From 979f693def9084a452846365dfde5dcb28366333 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 22 Sep 2009 14:44:11 +0200 Subject: [PATCH 001/298] ratelimit: Use per ratelimit context locking I'd like to use printk_ratelimit() in atomic context, but that's not possible right now due to the spinlock usage this commit introduced more than a year ago: 717115e: printk ratelimiting rewrite As a first step push the lock into the ratelimit state structure. This allows us to deal with locking failures to be considered as an event related to that state being too busy. Also clean up the code a bit (without changing functionality): - tidy up the definitions - clean up the code flow This also shrinks the code a tiny bit: text data bss dec hex filename 264 0 4 268 10c ratelimit.o.before 255 0 0 255 ff ratelimit.o.after ( Whole-kernel data size got a bit larger, because we have two ratelimit-state data structures right now. ) Cc: Peter Zijlstra Cc: Andrew Morton Cc: Linus Torvalds Cc: David S. Miller LKML-Reference: Signed-off-by: Ingo Molnar --- include/linux/ratelimit.h | 32 +++++++++++++++++++++----------- lib/ratelimit.c | 29 +++++++++++++---------------- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/include/linux/ratelimit.h b/include/linux/ratelimit.h index 00044b85645..187bc16c1f1 100644 --- a/include/linux/ratelimit.h +++ b/include/linux/ratelimit.h @@ -1,20 +1,30 @@ #ifndef _LINUX_RATELIMIT_H #define _LINUX_RATELIMIT_H -#include -#define DEFAULT_RATELIMIT_INTERVAL (5 * HZ) -#define DEFAULT_RATELIMIT_BURST 10 +#include +#include + +#define DEFAULT_RATELIMIT_INTERVAL (5 * HZ) +#define DEFAULT_RATELIMIT_BURST 10 struct ratelimit_state { - int interval; - int burst; - int printed; - int missed; - unsigned long begin; + spinlock_t lock; /* protect the state */ + + int interval; + int burst; + int printed; + int missed; + unsigned long begin; }; -#define DEFINE_RATELIMIT_STATE(name, interval, burst) \ - struct ratelimit_state name = {interval, burst,} +#define DEFINE_RATELIMIT_STATE(name, interval_init, burst_init) \ + \ + struct ratelimit_state name = { \ + .lock = __SPIN_LOCK_UNLOCKED(name.lock), \ + .interval = interval_init, \ + .burst = burst_init, \ + } extern int __ratelimit(struct ratelimit_state *rs); -#endif + +#endif /* _LINUX_RATELIMIT_H */ diff --git a/lib/ratelimit.c b/lib/ratelimit.c index 26187edcc7e..0e2c28e8a0c 100644 --- a/lib/ratelimit.c +++ b/lib/ratelimit.c @@ -7,15 +7,12 @@ * parameter. Now every user can use their own standalone ratelimit_state. * * This file is released under the GPLv2. - * */ #include #include #include -static DEFINE_SPINLOCK(ratelimit_lock); - /* * __ratelimit - rate limiting * @rs: ratelimit_state data @@ -26,11 +23,12 @@ static DEFINE_SPINLOCK(ratelimit_lock); int __ratelimit(struct ratelimit_state *rs) { unsigned long flags; + int ret; if (!rs->interval) return 1; - spin_lock_irqsave(&ratelimit_lock, flags); + spin_lock_irqsave(&rs->lock, flags); if (!rs->begin) rs->begin = jiffies; @@ -38,20 +36,19 @@ int __ratelimit(struct ratelimit_state *rs) if (rs->missed) printk(KERN_WARNING "%s: %d callbacks suppressed\n", __func__, rs->missed); - rs->begin = 0; + rs->begin = 0; rs->printed = 0; - rs->missed = 0; + rs->missed = 0; } - if (rs->burst && rs->burst > rs->printed) - goto print; + if (rs->burst && rs->burst > rs->printed) { + rs->printed++; + ret = 1; + } else { + rs->missed++; + ret = 0; + } + spin_unlock_irqrestore(&rs->lock, flags); - rs->missed++; - spin_unlock_irqrestore(&ratelimit_lock, flags); - return 0; - -print: - rs->printed++; - spin_unlock_irqrestore(&ratelimit_lock, flags); - return 1; + return ret; } EXPORT_SYMBOL(__ratelimit); From edaac8e3167501cda336231d00611bf59c164346 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 22 Sep 2009 14:44:11 +0200 Subject: [PATCH 002/298] ratelimit: Fix/allow use in atomic contexts I'd like to use printk_ratelimit() in NMI context, but it's not robust right now due to spinlock usage in lib/ratelimit.c. If an NMI is unlucky enough to hit just that spot we might lock up trying to take the spinlock again. Fix that by using a trylock variant. If we contend on that lock we can genuinely skip the message because the state is just being accessed by another CPU (or by this CPU). ( We could use atomics for the suppressed messages field, but i doubt it matters in practice and it makes the code heavier. ) Cc: Peter Zijlstra Cc: Andrew Morton Cc: Linus Torvalds Cc: David S. Miller LKML-Reference: Signed-off-by: Ingo Molnar --- lib/ratelimit.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/ratelimit.c b/lib/ratelimit.c index 0e2c28e8a0c..69bfcacda16 100644 --- a/lib/ratelimit.c +++ b/lib/ratelimit.c @@ -28,7 +28,15 @@ int __ratelimit(struct ratelimit_state *rs) if (!rs->interval) return 1; - spin_lock_irqsave(&rs->lock, flags); + /* + * If we contend on this state's lock then almost + * by definition we are too busy to print a message, + * in addition to the one that will be printed by + * the entity that is holding the lock already: + */ + if (!spin_trylock_irqsave(&rs->lock, flags)) + return 1; + if (!rs->begin) rs->begin = jiffies; From 3fff4c42bd0a89869a0eb1e7874cc06ffa4aa0f5 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 22 Sep 2009 16:18:09 +0200 Subject: [PATCH 003/298] printk: Remove ratelimit.h from kernel.h Decouple kernel.h from ratelimit.h: the global declaration of printk's ratelimit_state is not needed, and it leads to messy circular dependencies due to ratelimit.h's (new) adding of a spinlock_types.h include. Cc: Peter Zijlstra Cc: Andrew Morton Cc: Linus Torvalds Cc: David S. Miller LKML-Reference: Signed-off-by: Ingo Molnar --- include/linux/kernel.h | 2 -- include/linux/net.h | 1 + kernel/printk.c | 1 + kernel/sysctl.c | 3 +++ lib/ratelimit.c | 2 +- net/core/sysctl_net_core.c | 2 ++ net/core/utils.c | 2 ++ 7 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 2b5b1e0899a..3305f33201b 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -241,7 +240,6 @@ asmlinkage int vprintk(const char *fmt, va_list args) asmlinkage int printk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))) __cold; -extern struct ratelimit_state printk_ratelimit_state; extern int printk_ratelimit(void); extern bool printk_timed_ratelimit(unsigned long *caller_jiffies, unsigned int interval_msec); diff --git a/include/linux/net.h b/include/linux/net.h index 9040a10584f..df20f680f45 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -358,6 +358,7 @@ static const struct proto_ops name##_ops = { \ #ifdef CONFIG_SYSCTL #include +#include extern struct ratelimit_state net_ratelimit_state; #endif diff --git a/kernel/printk.c b/kernel/printk.c index 602033acd6c..b997c893cdc 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -33,6 +33,7 @@ #include #include #include +#include #include diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 1a631ba684a..6c37048b9db 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -155,6 +156,8 @@ extern int no_unaligned_warning; extern int unaligned_dump_stack; #endif +extern struct ratelimit_state printk_ratelimit_state; + #ifdef CONFIG_RT_MUTEXES extern int max_lock_depth; #endif diff --git a/lib/ratelimit.c b/lib/ratelimit.c index 69bfcacda16..5551731ae1d 100644 --- a/lib/ratelimit.c +++ b/lib/ratelimit.c @@ -9,7 +9,7 @@ * This file is released under the GPLv2. */ -#include +#include #include #include diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 7db1de0497c..887c03c4e3c 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -10,7 +10,9 @@ #include #include #include +#include #include + #include #include diff --git a/net/core/utils.c b/net/core/utils.c index 83221aee708..838250241d2 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -24,6 +24,8 @@ #include #include #include +#include + #include #include From 96a2c464de07d7c72988db851c029b204fc59108 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 1 Aug 2009 01:34:24 +0200 Subject: [PATCH 004/298] tracing/bkl: Add bkl ftrace events Add two events lock_kernel and unlock_kernel() to trace the bkl uses. This opens the door for userspace tools to perform statistics about the callsites that use it, dependencies with other locks (by pairing the trace with lock events), use with recursivity and so on... The {__reacquire,release}_kernel_lock() events are not traced because these are called from schedule, thus the sched events are sufficient to trace them. Example of a trace: hald-addon-stor-4152 [000] 165.875501: unlock_kernel: depth: 0, fs/block_dev.c:1358 __blkdev_put() hald-addon-stor-4152 [000] 167.832974: lock_kernel: depth: 0, fs/block_dev.c:1167 __blkdev_get() How to get the callsites that acquire it recursively: cd /debug/tracing/events/bkl echo "lock_depth > 0" > filter firefox-4951 [001] 206.276967: unlock_kernel: depth: 1, fs/reiserfs/super.c:575 reiserfs_dirty_inode() You can also filter by file and/or line. v2: Use of FILTER_PTR_STRING attribute for files and lines fields to make them traceable. Signed-off-by: Frederic Weisbecker Cc: Steven Rostedt Cc: Li Zefan --- include/linux/smp_lock.h | 19 +++++++++--- include/trace/events/bkl.h | 61 ++++++++++++++++++++++++++++++++++++++ lib/kernel_lock.c | 11 +++---- 3 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 include/trace/events/bkl.h diff --git a/include/linux/smp_lock.h b/include/linux/smp_lock.h index 813be59bf34..d48cc77ba70 100644 --- a/include/linux/smp_lock.h +++ b/include/linux/smp_lock.h @@ -3,6 +3,7 @@ #ifdef CONFIG_LOCK_KERNEL #include +#include #define kernel_locked() (current->lock_depth >= 0) @@ -24,8 +25,18 @@ static inline int reacquire_kernel_lock(struct task_struct *task) return 0; } -extern void __lockfunc lock_kernel(void) __acquires(kernel_lock); -extern void __lockfunc unlock_kernel(void) __releases(kernel_lock); +extern void __lockfunc _lock_kernel(void) __acquires(kernel_lock); +extern void __lockfunc _unlock_kernel(void) __releases(kernel_lock); + +#define lock_kernel() { \ + trace_lock_kernel(__func__, __FILE__, __LINE__); \ + _lock_kernel(); \ +} + +#define unlock_kernel() { \ + trace_unlock_kernel(__func__, __FILE__, __LINE__); \ + _unlock_kernel(); \ +} /* * Various legacy drivers don't really need the BKL in a specific @@ -41,8 +52,8 @@ static inline void cycle_kernel_lock(void) #else -#define lock_kernel() do { } while(0) -#define unlock_kernel() do { } while(0) +#define lock_kernel() trace_lock_kernel(__func__, __FILE__, __LINE__); +#define unlock_kernel() trace_unlock_kernel(__func__, __FILE__, __LINE__); #define release_kernel_lock(task) do { } while(0) #define cycle_kernel_lock() do { } while(0) #define reacquire_kernel_lock(task) 0 diff --git a/include/trace/events/bkl.h b/include/trace/events/bkl.h new file mode 100644 index 00000000000..8abd620a490 --- /dev/null +++ b/include/trace/events/bkl.h @@ -0,0 +1,61 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM bkl + +#if !defined(_TRACE_BKL_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_BKL_H + +#include + +TRACE_EVENT(lock_kernel, + + TP_PROTO(const char *func, const char *file, int line), + + TP_ARGS(func, file, line), + + TP_STRUCT__entry( + __field( int, lock_depth ) + __field_ext( const char *, func, FILTER_PTR_STRING ) + __field_ext( const char *, file, FILTER_PTR_STRING ) + __field( int, line ) + ), + + TP_fast_assign( + /* We want to record the lock_depth after lock is acquired */ + __entry->lock_depth = current->lock_depth + 1; + __entry->func = func; + __entry->file = file; + __entry->line = line; + ), + + TP_printk("depth: %d, %s:%d %s()", __entry->lock_depth, + __entry->file, __entry->line, __entry->func) +); + +TRACE_EVENT(unlock_kernel, + + TP_PROTO(const char *func, const char *file, int line), + + TP_ARGS(func, file, line), + + TP_STRUCT__entry( + __field(int, lock_depth) + __field(const char *, func) + __field(const char *, file) + __field(int, line) + ), + + TP_fast_assign( + __entry->lock_depth = current->lock_depth; + __entry->func = func; + __entry->file = file; + __entry->line = line; + ), + + TP_printk("depth: %d, %s:%d %s()", __entry->lock_depth, + __entry->file, __entry->line, __entry->func) +); + +#endif /* _TRACE_BKL_H */ + +/* This part must be outside protection */ +#include diff --git a/lib/kernel_lock.c b/lib/kernel_lock.c index 39f1029e352..5c10b2e1fd0 100644 --- a/lib/kernel_lock.c +++ b/lib/kernel_lock.c @@ -5,10 +5,11 @@ * relegated to obsolescence, but used by various less * important (or lazy) subsystems. */ -#include #include #include #include +#define CREATE_TRACE_POINTS +#include /* * The 'big kernel lock' @@ -113,7 +114,7 @@ static inline void __unlock_kernel(void) * This cannot happen asynchronously, so we only need to * worry about other CPU's. */ -void __lockfunc lock_kernel(void) +void __lockfunc _lock_kernel(void) { int depth = current->lock_depth+1; if (likely(!depth)) @@ -121,13 +122,13 @@ void __lockfunc lock_kernel(void) current->lock_depth = depth; } -void __lockfunc unlock_kernel(void) +void __lockfunc _unlock_kernel(void) { BUG_ON(current->lock_depth < 0); if (likely(--current->lock_depth < 0)) __unlock_kernel(); } -EXPORT_SYMBOL(lock_kernel); -EXPORT_SYMBOL(unlock_kernel); +EXPORT_SYMBOL(_lock_kernel); +EXPORT_SYMBOL(_unlock_kernel); From 737f453fd115ea0c9642ed6b30e37e296a4e3ed7 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 1 Aug 2009 03:42:44 +0200 Subject: [PATCH 005/298] tracing/filters: Cleanup useless headers Cleanup remaining headers inclusion that were only useful when the filter framework and its tracing related filesystem user interface weren't yet separated. v2: Keep module.h, needed for EXPORT_SYMBOL_GPL Signed-off-by: Frederic Weisbecker Cc: Tom Zanussi Cc: Steven Rostedt Cc: Li Zefan --- kernel/trace/trace_events_filter.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 23245785927..189663d82aa 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -18,8 +18,6 @@ * Copyright (C) 2009 Tom Zanussi */ -#include -#include #include #include #include From f3f3f0092477d0165f3f1bf0fd518550b2abd097 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 24 Sep 2009 15:27:41 +0200 Subject: [PATCH 006/298] tracing/event: Cleanup the useless dentry variable Cleanup the useless dentry variable while creating a kernel event set of files. trace_create_file() warns if it fails to create the file anyway, and we don't store the dentry anywhere. v2: Fix a small conflict in kernel/trace/trace_events.c Signed-off-by: Frederic Weisbecker Cc: Steven Rostedt Cc: Li Zefan --- kernel/trace/trace_events.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 56c260b83a9..8c91b7c8f04 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -898,9 +898,9 @@ event_subsystem_dir(const char *name, struct dentry *d_events) "'%s/filter' entry\n", name); } - entry = trace_create_file("enable", 0644, system->entry, - (void *)system->name, - &ftrace_system_enable_fops); + trace_create_file("enable", 0644, system->entry, + (void *)system->name, + &ftrace_system_enable_fops); return system->entry; } @@ -912,7 +912,6 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, const struct file_operations *filter, const struct file_operations *format) { - struct dentry *entry; int ret; /* @@ -930,12 +929,12 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, } if (call->regfunc) - entry = trace_create_file("enable", 0644, call->dir, call, - enable); + trace_create_file("enable", 0644, call->dir, call, + enable); if (call->id && call->profile_enable) - entry = trace_create_file("id", 0444, call->dir, call, - id); + trace_create_file("id", 0444, call->dir, call, + id); if (call->define_fields) { ret = call->define_fields(call); @@ -944,16 +943,16 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, " events/%s\n", call->name); return ret; } - entry = trace_create_file("filter", 0644, call->dir, call, - filter); + trace_create_file("filter", 0644, call->dir, call, + filter); } /* A trace may not want to export its format */ if (!call->show_format) return 0; - entry = trace_create_file("format", 0444, call->dir, call, - format); + trace_create_file("format", 0444, call->dir, call, + format); return 0; } From 1889d20922d14a97b2099fa4d47587217c0ba48b Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 24 Sep 2009 21:10:44 +0200 Subject: [PATCH 007/298] tracing/filters: Provide basic regex support This patch provides basic support for regular expressions in filters. It supports the following types of regexp: - *match_beginning - *match_middle* - match_end* - !don't match Example: cd /debug/tracing/events/bkl/lock_kernel echo 'file == "*reiserfs*"' > filter echo 1 > enable gedit-4941 [000] 457.735437: lock_kernel: depth: 0, fs/reiserfs/namei.c:334 reiserfs_lookup() sync_supers-227 [001] 461.379985: lock_kernel: depth: 0, fs/reiserfs/super.c:69 reiserfs_sync_fs() sync_supers-227 [000] 461.383096: lock_kernel: depth: 0, fs/reiserfs/journal.c:1069 flush_commit_list() reiserfs/1-1369 [001] 461.479885: lock_kernel: depth: 0, fs/reiserfs/journal.c:3509 flush_async_commits() Every string is now handled as a regexp in the filter framework, which helps to factorize the code for handling both simple strings and regexp comparisons. (The regexp parsing code has been wildly cherry picked from ftrace.c written by Steve.) v2: Simplify the whole and drop the filter_regex file Signed-off-by: Frederic Weisbecker Cc: Steven Rostedt Cc: Tom Zanussi Cc: Li Zefan --- kernel/trace/trace.h | 27 +++-- kernel/trace/trace_events_filter.c | 155 ++++++++++++++++++++++++++--- 2 files changed, 157 insertions(+), 25 deletions(-) diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 86bcff94791..8d0db6018fe 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -702,20 +702,29 @@ struct event_subsystem { }; struct filter_pred; +struct regex; typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event, int val1, int val2); +typedef int (*regex_match_func)(char *str, struct regex *r, int len); + +struct regex { + char pattern[MAX_FILTER_STR_VAL]; + int len; + int field_len; + regex_match_func match; +}; + struct filter_pred { - filter_pred_fn_t fn; - u64 val; - char str_val[MAX_FILTER_STR_VAL]; - int str_len; - char *field_name; - int offset; - int not; - int op; - int pop_n; + filter_pred_fn_t fn; + u64 val; + struct regex regex; + char *field_name; + int offset; + int not; + int op; + int pop_n; }; extern void print_event_filter(struct ftrace_event_call *call, diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 189663d82aa..d3c94c13956 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -195,9 +195,9 @@ static int filter_pred_string(struct filter_pred *pred, void *event, char *addr = (char *)(event + pred->offset); int cmp, match; - cmp = strncmp(addr, pred->str_val, pred->str_len); + cmp = pred->regex.match(addr, &pred->regex, pred->regex.field_len); - match = (!cmp) ^ pred->not; + match = cmp ^ pred->not; return match; } @@ -209,9 +209,9 @@ static int filter_pred_pchar(struct filter_pred *pred, void *event, char **addr = (char **)(event + pred->offset); int cmp, match; - cmp = strncmp(*addr, pred->str_val, pred->str_len); + cmp = pred->regex.match(*addr, &pred->regex, pred->regex.field_len); - match = (!cmp) ^ pred->not; + match = cmp ^ pred->not; return match; } @@ -235,9 +235,9 @@ static int filter_pred_strloc(struct filter_pred *pred, void *event, char *addr = (char *)(event + str_loc); int cmp, match; - cmp = strncmp(addr, pred->str_val, str_len); + cmp = pred->regex.match(addr, &pred->regex, str_len); - match = (!cmp) ^ pred->not; + match = cmp ^ pred->not; return match; } @@ -248,6 +248,126 @@ static int filter_pred_none(struct filter_pred *pred, void *event, return 0; } +/* Basic regex callbacks */ +static int regex_match_full(char *str, struct regex *r, int len) +{ + if (strncmp(str, r->pattern, len) == 0) + return 1; + return 0; +} + +static int regex_match_front(char *str, struct regex *r, int len) +{ + if (strncmp(str, r->pattern, len) == 0) + return 1; + return 0; +} + +static int regex_match_middle(char *str, struct regex *r, int len) +{ + if (strstr(str, r->pattern)) + return 1; + return 0; +} + +static int regex_match_end(char *str, struct regex *r, int len) +{ + char *ptr = strstr(str, r->pattern); + + if (ptr && (ptr[r->len] == 0)) + return 1; + return 0; +} + +enum regex_type { + MATCH_FULL, + MATCH_FRONT_ONLY, + MATCH_MIDDLE_ONLY, + MATCH_END_ONLY, +}; + +/* + * Pass in a buffer containing a regex and this function will + * set search to point to the search part of the buffer and + * return the type of search it is (see enum above). + * This does modify buff. + * + * Returns enum type. + * search returns the pointer to use for comparison. + * not returns 1 if buff started with a '!' + * 0 otherwise. + */ +static enum regex_type +filter_parse_regex(char *buff, int len, char **search, int *not) +{ + int type = MATCH_FULL; + int i; + + if (buff[0] == '!') { + *not = 1; + buff++; + len--; + } else + *not = 0; + + *search = buff; + + for (i = 0; i < len; i++) { + if (buff[i] == '*') { + if (!i) { + *search = buff + 1; + type = MATCH_END_ONLY; + } else { + if (type == MATCH_END_ONLY) + type = MATCH_MIDDLE_ONLY; + else + type = MATCH_FRONT_ONLY; + buff[i] = 0; + break; + } + } + } + + return type; +} + +static int filter_build_regex(struct filter_pred *pred) +{ + struct regex *r = &pred->regex; + char *search, *dup; + enum regex_type type; + int not; + + type = filter_parse_regex(r->pattern, r->len, &search, ¬); + dup = kstrdup(search, GFP_KERNEL); + if (!dup) + return -ENOMEM; + + strcpy(r->pattern, dup); + kfree(dup); + + r->len = strlen(r->pattern); + + switch (type) { + case MATCH_FULL: + r->match = regex_match_full; + break; + case MATCH_FRONT_ONLY: + r->match = regex_match_front; + break; + case MATCH_MIDDLE_ONLY: + r->match = regex_match_middle; + break; + case MATCH_END_ONLY: + r->match = regex_match_end; + break; + } + + pred->not ^= not; + + return 0; +} + /* return 1 if event matches, 0 otherwise (discard) */ int filter_match_preds(struct ftrace_event_call *call, void *rec) { @@ -394,7 +514,7 @@ static void filter_clear_pred(struct filter_pred *pred) { kfree(pred->field_name); pred->field_name = NULL; - pred->str_len = 0; + pred->regex.len = 0; } static int filter_set_pred(struct filter_pred *dest, @@ -658,21 +778,24 @@ static int filter_add_pred(struct filter_parse_state *ps, } if (is_string_field(field)) { - pred->str_len = field->size; + ret = filter_build_regex(pred); + if (ret) + return ret; - if (field->filter_type == FILTER_STATIC_STRING) + if (field->filter_type == FILTER_STATIC_STRING) { fn = filter_pred_string; - else if (field->filter_type == FILTER_DYN_STRING) - fn = filter_pred_strloc; + pred->regex.field_len = field->size; + } else if (field->filter_type == FILTER_DYN_STRING) + fn = filter_pred_strloc; else { fn = filter_pred_pchar; - pred->str_len = strlen(pred->str_val); + pred->regex.field_len = strlen(pred->regex.pattern); } } else { if (field->is_signed) - ret = strict_strtoll(pred->str_val, 0, &val); + ret = strict_strtoll(pred->regex.pattern, 0, &val); else - ret = strict_strtoull(pred->str_val, 0, &val); + ret = strict_strtoull(pred->regex.pattern, 0, &val); if (ret) { parse_error(ps, FILT_ERR_ILLEGAL_INTVAL, 0); return -EINVAL; @@ -1042,8 +1165,8 @@ static struct filter_pred *create_pred(int op, char *operand1, char *operand2) return NULL; } - strcpy(pred->str_val, operand2); - pred->str_len = strlen(operand2); + strcpy(pred->regex.pattern, operand2); + pred->regex.len = strlen(pred->regex.pattern); pred->op = op; From 3f6fe06dbf67b46d36fedec502300e04dffeb67a Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 24 Sep 2009 21:31:51 +0200 Subject: [PATCH 008/298] tracing/filters: Unify the regex parsing helpers The filter code has stolen the regex parsing function from ftrace to get the regex support. We have duplicated this code, so factorize it in the filter area and make it generally available, as the filter code is the most suited to host this feature. Signed-off-by: Frederic Weisbecker Cc: Steven Rostedt Cc: Tom Zanussi Cc: Li Zefan --- kernel/trace/ftrace.c | 64 +++--------------------------- kernel/trace/trace.h | 9 +++++ kernel/trace/trace_events_filter.c | 20 +++++----- 3 files changed, 23 insertions(+), 70 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index cc615f84751..ddf23a225b5 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1655,60 +1655,6 @@ ftrace_regex_lseek(struct file *file, loff_t offset, int origin) return ret; } -enum { - MATCH_FULL, - MATCH_FRONT_ONLY, - MATCH_MIDDLE_ONLY, - MATCH_END_ONLY, -}; - -/* - * (static function - no need for kernel doc) - * - * Pass in a buffer containing a glob and this function will - * set search to point to the search part of the buffer and - * return the type of search it is (see enum above). - * This does modify buff. - * - * Returns enum type. - * search returns the pointer to use for comparison. - * not returns 1 if buff started with a '!' - * 0 otherwise. - */ -static int -ftrace_setup_glob(char *buff, int len, char **search, int *not) -{ - int type = MATCH_FULL; - int i; - - if (buff[0] == '!') { - *not = 1; - buff++; - len--; - } else - *not = 0; - - *search = buff; - - for (i = 0; i < len; i++) { - if (buff[i] == '*') { - if (!i) { - *search = buff + 1; - type = MATCH_END_ONLY; - } else { - if (type == MATCH_END_ONLY) - type = MATCH_MIDDLE_ONLY; - else - type = MATCH_FRONT_ONLY; - buff[i] = 0; - break; - } - } - } - - return type; -} - static int ftrace_match(char *str, char *regex, int len, int type) { int matched = 0; @@ -1757,7 +1703,7 @@ static void ftrace_match_records(char *buff, int len, int enable) int not; flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; - type = ftrace_setup_glob(buff, len, &search, ¬); + type = filter_parse_regex(buff, len, &search, ¬); search_len = strlen(search); @@ -1825,7 +1771,7 @@ static void ftrace_match_module_records(char *buff, char *mod, int enable) } if (strlen(buff)) { - type = ftrace_setup_glob(buff, strlen(buff), &search, ¬); + type = filter_parse_regex(buff, strlen(buff), &search, ¬); search_len = strlen(search); } @@ -1990,7 +1936,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, int count = 0; char *search; - type = ftrace_setup_glob(glob, strlen(glob), &search, ¬); + type = filter_parse_regex(glob, strlen(glob), &search, ¬); len = strlen(search); /* we do not support '!' for function probes */ @@ -2067,7 +2013,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, else if (glob) { int not; - type = ftrace_setup_glob(glob, strlen(glob), &search, ¬); + type = filter_parse_regex(glob, strlen(glob), &search, ¬); len = strlen(search); /* we do not support '!' for function probes */ @@ -2520,7 +2466,7 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) return -ENODEV; /* decode regex */ - type = ftrace_setup_glob(buffer, strlen(buffer), &search, ¬); + type = filter_parse_regex(buffer, strlen(buffer), &search, ¬); if (not) return -EINVAL; diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 8d0db6018fe..db6b83edd49 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -709,6 +709,13 @@ typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event, typedef int (*regex_match_func)(char *str, struct regex *r, int len); +enum regex_type { + MATCH_FULL, + MATCH_FRONT_ONLY, + MATCH_MIDDLE_ONLY, + MATCH_END_ONLY, +}; + struct regex { char pattern[MAX_FILTER_STR_VAL]; int len; @@ -727,6 +734,8 @@ struct filter_pred { int pop_n; }; +extern enum regex_type +filter_parse_regex(char *buff, int len, char **search, int *not); extern void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s); extern int apply_event_filter(struct ftrace_event_call *call, diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index d3c94c13956..8c194de675b 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -279,15 +279,14 @@ static int regex_match_end(char *str, struct regex *r, int len) return 0; } -enum regex_type { - MATCH_FULL, - MATCH_FRONT_ONLY, - MATCH_MIDDLE_ONLY, - MATCH_END_ONLY, -}; - -/* - * Pass in a buffer containing a regex and this function will +/** + * filter_parse_regex - parse a basic regex + * @buff: the raw regex + * @len: length of the regex + * @search: will point to the beginning of the string to compare + * @not: tell whether the match will have to be inverted + * + * This passes in a buffer containing a regex and this function will * set search to point to the search part of the buffer and * return the type of search it is (see enum above). * This does modify buff. @@ -297,8 +296,7 @@ enum regex_type { * not returns 1 if buff started with a '!' * 0 otherwise. */ -static enum regex_type -filter_parse_regex(char *buff, int len, char **search, int *not) +enum regex_type filter_parse_regex(char *buff, int len, char **search, int *not) { int type = MATCH_FULL; int i; From 7f366784f5c2b8fc0658b5b374f4c63ee42c789f Mon Sep 17 00:00:00 2001 From: Rajiv Andrade Date: Thu, 24 Sep 2009 16:27:46 -0300 Subject: [PATCH 009/298] TPM: increase default TPM buffer The TPM Working Group requested this communication buffer increase given that a particular TPM vendor can support a TPM_SHA1Start command input bigger than the current size. Signed-off-by: Rajiv Andrade Signed-off-by: James Morris --- drivers/char/tpm/tpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index b0603b2e568..f4c68abf2a1 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -31,7 +31,7 @@ enum tpm_const { TPM_MINOR = 224, /* officially assigned */ - TPM_BUFSIZE = 2048, + TPM_BUFSIZE = 4096, TPM_NUM_DEVICES = 256, }; From 925936ebf35a95c290e010b784c962164e6728f3 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Mon, 28 Sep 2009 17:12:49 +0200 Subject: [PATCH 010/298] tracing: Pushdown the bkl tracepoints calls Currently we are calling the bkl tracepoint callbacks just before the bkl lock/unlock operations, ie the tracepoint call is not inside a lock_kernel() function but inside a lock_kernel() macro. Hence the bkl trace event header must be included from smp_lock.h. This raises some nasty circular header dependencies: linux/smp_lock.h -> trace/events/bkl.h -> trace/define_trace.h -> trace/ftrace.h -> linux/ftrace_event.h -> linux/hardirq.h -> linux/smp_lock.h This results in incomplete event declarations, spurious event definitions and other kind of funny behaviours. This is hardly fixable without ugly workarounds. So instead, we push the file name, line number and function name as lock_kernel() parameters, so that we only deal with the trace event header from lib/kernel_lock.c This adds two parameters to lock_kernel() and unlock_kernel() but it should be fine wrt to performances because this pair dos not seem to be called in fast paths. Signed-off-by: Frederic Weisbecker Cc: Steven Rostedt Cc: Ingo Molnar Cc: Li Zefan --- include/linux/smp_lock.h | 28 +++++++++++++++------------- lib/kernel_lock.c | 15 +++++++++++---- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/include/linux/smp_lock.h b/include/linux/smp_lock.h index d48cc77ba70..2ea1dd1ba21 100644 --- a/include/linux/smp_lock.h +++ b/include/linux/smp_lock.h @@ -3,7 +3,6 @@ #ifdef CONFIG_LOCK_KERNEL #include -#include #define kernel_locked() (current->lock_depth >= 0) @@ -25,18 +24,21 @@ static inline int reacquire_kernel_lock(struct task_struct *task) return 0; } -extern void __lockfunc _lock_kernel(void) __acquires(kernel_lock); -extern void __lockfunc _unlock_kernel(void) __releases(kernel_lock); +extern void __lockfunc +_lock_kernel(const char *func, const char *file, int line) +__acquires(kernel_lock); -#define lock_kernel() { \ - trace_lock_kernel(__func__, __FILE__, __LINE__); \ - _lock_kernel(); \ -} +extern void __lockfunc +_unlock_kernel(const char *func, const char *file, int line) +__releases(kernel_lock); -#define unlock_kernel() { \ - trace_unlock_kernel(__func__, __FILE__, __LINE__); \ - _unlock_kernel(); \ -} +#define lock_kernel() do { \ + _lock_kernel(__func__, __FILE__, __LINE__); \ +} while (0) + +#define unlock_kernel() do { \ + _unlock_kernel(__func__, __FILE__, __LINE__); \ +} while (0) /* * Various legacy drivers don't really need the BKL in a specific @@ -52,8 +54,8 @@ static inline void cycle_kernel_lock(void) #else -#define lock_kernel() trace_lock_kernel(__func__, __FILE__, __LINE__); -#define unlock_kernel() trace_unlock_kernel(__func__, __FILE__, __LINE__); +#define lock_kernel() +#define unlock_kernel() #define release_kernel_lock(task) do { } while(0) #define cycle_kernel_lock() do { } while(0) #define reacquire_kernel_lock(task) 0 diff --git a/lib/kernel_lock.c b/lib/kernel_lock.c index 5c10b2e1fd0..4ebfa5a164d 100644 --- a/lib/kernel_lock.c +++ b/lib/kernel_lock.c @@ -8,9 +8,11 @@ #include #include #include -#define CREATE_TRACE_POINTS #include +#define CREATE_TRACE_POINTS +#include + /* * The 'big kernel lock' * @@ -114,19 +116,24 @@ static inline void __unlock_kernel(void) * This cannot happen asynchronously, so we only need to * worry about other CPU's. */ -void __lockfunc _lock_kernel(void) +void __lockfunc _lock_kernel(const char *func, const char *file, int line) { - int depth = current->lock_depth+1; + int depth = current->lock_depth + 1; + + trace_lock_kernel(func, file, line); + if (likely(!depth)) __lock_kernel(); current->lock_depth = depth; } -void __lockfunc _unlock_kernel(void) +void __lockfunc _unlock_kernel(const char *func, const char *file, int line) { BUG_ON(current->lock_depth < 0); if (likely(--current->lock_depth < 0)) __unlock_kernel(); + + trace_unlock_kernel(func, file, line); } EXPORT_SYMBOL(_lock_kernel); From af8ff04917169805b151280155bf772d3ca9bec0 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Sun, 20 Sep 2009 21:23:01 -0400 Subject: [PATCH 011/298] SELinux: reset the security_ops before flushing the avc cache This patch resets the security_ops to the secondary_ops before it flushes the avc. It's still possible that a task on another processor could have already passed the security_ops dereference and be executing an selinux hook function which would add a new avc entry. That entry would still not be freed. This should however help to reduce the number of needless avcs the kernel has when selinux is disabled at run time. There is no wasted memory if selinux is disabled on the command line or not compiled. Signed-off-by: Eric Paris Signed-off-by: James Morris --- security/selinux/hooks.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index bb230d5d708..a985d0bc59b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -5830,12 +5830,12 @@ int selinux_disable(void) selinux_disabled = 1; selinux_enabled = 0; - /* Try to destroy the avc node cache */ - avc_disable(); - /* Reset security_ops to the secondary module, dummy or capability. */ security_ops = secondary_ops; + /* Try to destroy the avc node cache */ + avc_disable(); + /* Unregister netfilter hooks. */ selinux_nf_ip_exit(); From 23acb98de5a4109a60b5fe3f0439389218b039d7 Mon Sep 17 00:00:00 2001 From: Rajiv Andrade Date: Wed, 30 Sep 2009 12:26:55 -0300 Subject: [PATCH 012/298] TPM: fix pcrread The previously sent patch: http://marc.info/?l=tpmdd-devel&m=125208945007834&w=2 Had its first hunk cropped when merged, submitting only this first hunk again. Signed-off-by: Jason Gunthorpe Cc: Debora Velarde Cc: Marcel Selhorst Cc: James Morris Signed-off-by: Andrew Morton Signed-off-by: Rajiv Andrade Acked-by: Mimi Zohar Tested-by: Mimi Zohar Signed-off-by: James Morris --- drivers/char/tpm/tpm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index aeafac5bde8..f06bb37defb 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -696,8 +696,7 @@ int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) cmd.header.in = pcrread_header; cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx); - BUG_ON(cmd.header.in.length > READ_PCR_RESULT_SIZE); - rc = transmit_cmd(chip, &cmd, cmd.header.in.length, + rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, "attempting to read a pcr value"); if (rc == 0) From c6d3aaa4e35c71a32a86ececacd4eea7ecfc316c Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Wed, 30 Sep 2009 13:37:50 -0400 Subject: [PATCH 013/298] selinux: dynamic class/perm discovery Modify SELinux to dynamically discover class and permission values upon policy load, based on the dynamic object class/perm discovery logic from libselinux. A mapping is created between kernel-private class and permission indices used outside the security server and the policy values used within the security server. The mappings are only applied upon kernel-internal computations; similar mappings for the private indices of userspace object managers is handled on a per-object manager basis by the userspace AVC. The interfaces for compute_av and transition_sid are split for kernel vs. userspace; the userspace functions are distinguished by a _user suffix. The kernel-private class indices are no longer tied to the policy values and thus do not need to skip indices for userspace classes; thus the kernel class index values are compressed. The flask.h definitions were regenerated by deleting the userspace classes from refpolicy's definitions and then regenerating the headers. Going forward, we can just maintain the flask.h, av_permissions.h, and classmap.h definitions separately from policy as they are no longer tied to the policy values. The next patch introduces a utility to automate generation of flask.h and av_permissions.h from the classmap.h definitions. The older kernel class and permission string tables are removed and replaced by a single security class mapping table that is walked at policy load to generate the mapping. The old kernel class validation logic is completely replaced by the mapping logic. The handle unknown logic is reworked. reject_unknown=1 is handled when the mappings are computed at policy load time, similar to the old handling by the class validation logic. allow_unknown=1 is handled when computing and mapping decisions - if the permission was not able to be mapped (i.e. undefined, mapped to zero), then it is automatically added to the allowed vector. If the class was not able to be mapped (i.e. undefined, mapped to zero), then all permissions are allowed for it if allow_unknown=1. avc_audit leverages the new security class mapping table to lookup the class and permission names from the kernel-private indices. The mdp program is updated to use the new table when generating the class definitions and allow rules for a minimal boot policy for the kernel. It should be noted that this policy will not include any userspace classes, nor will its policy index values for the kernel classes correspond with the ones in refpolicy (they will instead match the kernel-private indices). Signed-off-by: Stephen Smalley Signed-off-by: James Morris --- scripts/selinux/mdp/mdp.c | 151 +---- security/selinux/avc.c | 76 +-- security/selinux/include/av_inherit.h | 34 -- security/selinux/include/av_perm_to_string.h | 183 ------ security/selinux/include/av_permissions.h | 44 +- security/selinux/include/avc_ss.h | 21 +- security/selinux/include/class_to_string.h | 80 --- security/selinux/include/classmap.h | 150 +++++ .../selinux/include/common_perm_to_string.h | 58 -- security/selinux/include/flask.h | 40 +- security/selinux/include/security.h | 13 +- security/selinux/selinuxfs.c | 4 +- security/selinux/ss/mls.c | 2 +- security/selinux/ss/policydb.c | 47 +- security/selinux/ss/policydb.h | 7 +- security/selinux/ss/services.c | 540 ++++++++++-------- 16 files changed, 583 insertions(+), 867 deletions(-) delete mode 100644 security/selinux/include/av_inherit.h delete mode 100644 security/selinux/include/av_perm_to_string.h delete mode 100644 security/selinux/include/class_to_string.h create mode 100644 security/selinux/include/classmap.h delete mode 100644 security/selinux/include/common_perm_to_string.h diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c index b4ced856258..62b34ce1f50 100644 --- a/scripts/selinux/mdp/mdp.c +++ b/scripts/selinux/mdp/mdp.c @@ -29,86 +29,27 @@ #include #include -#include "flask.h" - static void usage(char *name) { printf("usage: %s [-m] policy_file context_file\n", name); exit(1); } -static void find_common_name(char *cname, char *dest, int len) -{ - char *start, *end; - - start = strchr(cname, '_')+1; - end = strchr(start, '_'); - if (!start || !end || start-cname > len || end-start > len) { - printf("Error with commons defines\n"); - exit(1); - } - strncpy(dest, start, end-start); - dest[end-start] = '\0'; -} - -#define S_(x) x, -static char *classlist[] = { -#include "class_to_string.h" - NULL +/* Class/perm mapping support */ +struct security_class_mapping { + const char *name; + const char *perms[sizeof(unsigned) * 8 + 1]; }; -#undef S_ +#include "classmap.h" #include "initial_sid_to_string.h" -#define TB_(x) char *x[] = { -#define TE_(x) NULL }; -#define S_(x) x, -#include "common_perm_to_string.h" -#undef TB_ -#undef TE_ -#undef S_ - -struct common { - char *cname; - char **perms; -}; -struct common common[] = { -#define TB_(x) { #x, x }, -#define S_(x) -#define TE_(x) -#include "common_perm_to_string.h" -#undef TB_ -#undef TE_ -#undef S_ -}; - -#define S_(x, y, z) {x, #y}, -struct av_inherit { - int class; - char *common; -}; -struct av_inherit av_inherit[] = { -#include "av_inherit.h" -}; -#undef S_ - -#include "av_permissions.h" -#define S_(x, y, z) {x, y, z}, -struct av_perms { - int class; - int perm_i; - char *perm_s; -}; -struct av_perms av_perms[] = { -#include "av_perm_to_string.h" -}; -#undef S_ - int main(int argc, char *argv[]) { int i, j, mls = 0; + int initial_sid_to_string_len; char **arg, *polout, *ctxout; - int classlist_len, initial_sid_to_string_len; + FILE *fout; if (argc < 3) @@ -127,64 +68,25 @@ int main(int argc, char *argv[]) usage(argv[0]); } - classlist_len = sizeof(classlist) / sizeof(char *); /* print out the classes */ - for (i=1; i < classlist_len; i++) { - if(classlist[i]) - fprintf(fout, "class %s\n", classlist[i]); - else - fprintf(fout, "class user%d\n", i); - } + for (i = 0; secclass_map[i].name; i++) + fprintf(fout, "class %s\n", secclass_map[i].name); fprintf(fout, "\n"); initial_sid_to_string_len = sizeof(initial_sid_to_string) / sizeof (char *); /* print out the sids */ - for (i=1; i < initial_sid_to_string_len; i++) + for (i = 1; i < initial_sid_to_string_len; i++) fprintf(fout, "sid %s\n", initial_sid_to_string[i]); fprintf(fout, "\n"); - /* print out the commons */ - for (i=0; i< sizeof(common)/sizeof(struct common); i++) { - char cname[101]; - find_common_name(common[i].cname, cname, 100); - cname[100] = '\0'; - fprintf(fout, "common %s\n{\n", cname); - for (j=0; common[i].perms[j]; j++) - fprintf(fout, "\t%s\n", common[i].perms[j]); - fprintf(fout, "}\n\n"); - } - fprintf(fout, "\n"); - /* print out the class permissions */ - for (i=1; i < classlist_len; i++) { - if (classlist[i]) { - int firstperm = -1, numperms = 0; - - fprintf(fout, "class %s\n", classlist[i]); - /* does it inherit from a common? */ - for (j=0; j < sizeof(av_inherit)/sizeof(struct av_inherit); j++) - if (av_inherit[j].class == i) - fprintf(fout, "inherits %s\n", av_inherit[j].common); - - for (j=0; j < sizeof(av_perms)/sizeof(struct av_perms); j++) { - if (av_perms[j].class == i) { - if (firstperm == -1) - firstperm = j; - numperms++; - } - } - if (!numperms) { - fprintf(fout, "\n"); - continue; - } - - fprintf(fout, "{\n"); - /* print out the av_perms */ - for (j=0; j < numperms; j++) { - fprintf(fout, "\t%s\n", av_perms[firstperm+j].perm_s); - } - fprintf(fout, "}\n\n"); - } + for (i = 0; secclass_map[i].name; i++) { + struct security_class_mapping *map = &secclass_map[i]; + fprintf(fout, "class %s\n", map->name); + fprintf(fout, "{\n"); + for (j = 0; map->perms[j]; j++) + fprintf(fout, "\t%s\n", map->perms[j]); + fprintf(fout, "}\n\n"); } fprintf(fout, "\n"); @@ -197,31 +99,34 @@ int main(int argc, char *argv[]) /* types, roles, and allows */ fprintf(fout, "type base_t;\n"); fprintf(fout, "role base_r types { base_t };\n"); - for (i=1; i < classlist_len; i++) { - if (classlist[i]) - fprintf(fout, "allow base_t base_t:%s *;\n", classlist[i]); - else - fprintf(fout, "allow base_t base_t:user%d *;\n", i); - } + for (i = 0; secclass_map[i].name; i++) + fprintf(fout, "allow base_t base_t:%s *;\n", + secclass_map[i].name); fprintf(fout, "user user_u roles { base_r };\n"); fprintf(fout, "\n"); /* default sids */ - for (i=1; i < initial_sid_to_string_len; i++) + for (i = 1; i < initial_sid_to_string_len; i++) fprintf(fout, "sid %s user_u:base_r:base_t\n", initial_sid_to_string[i]); fprintf(fout, "\n"); - fprintf(fout, "fs_use_xattr ext2 user_u:base_r:base_t;\n"); fprintf(fout, "fs_use_xattr ext3 user_u:base_r:base_t;\n"); + fprintf(fout, "fs_use_xattr ext4 user_u:base_r:base_t;\n"); fprintf(fout, "fs_use_xattr jfs user_u:base_r:base_t;\n"); fprintf(fout, "fs_use_xattr xfs user_u:base_r:base_t;\n"); fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n"); + fprintf(fout, "fs_use_xattr jffs2 user_u:base_r:base_t;\n"); + fprintf(fout, "fs_use_xattr gfs2 user_u:base_r:base_t;\n"); + fprintf(fout, "fs_use_xattr lustre user_u:base_r:base_t;\n"); + fprintf(fout, "fs_use_task eventpollfs user_u:base_r:base_t;\n"); fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n"); fprintf(fout, "fs_use_task sockfs user_u:base_r:base_t;\n"); + fprintf(fout, "fs_use_trans mqueue user_u:base_r:base_t;\n"); fprintf(fout, "fs_use_trans devpts user_u:base_r:base_t;\n"); + fprintf(fout, "fs_use_trans hugetlbfs user_u:base_r:base_t;\n"); fprintf(fout, "fs_use_trans tmpfs user_u:base_r:base_t;\n"); fprintf(fout, "fs_use_trans shm user_u:base_r:base_t;\n"); diff --git a/security/selinux/avc.c b/security/selinux/avc.c index b4b5da1c0a4..18f4103e02b 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -31,43 +31,7 @@ #include #include "avc.h" #include "avc_ss.h" - -static const struct av_perm_to_string av_perm_to_string[] = { -#define S_(c, v, s) { c, v, s }, -#include "av_perm_to_string.h" -#undef S_ -}; - -static const char *class_to_string[] = { -#define S_(s) s, -#include "class_to_string.h" -#undef S_ -}; - -#define TB_(s) static const char *s[] = { -#define TE_(s) }; -#define S_(s) s, -#include "common_perm_to_string.h" -#undef TB_ -#undef TE_ -#undef S_ - -static const struct av_inherit av_inherit[] = { -#define S_(c, i, b) { .tclass = c,\ - .common_pts = common_##i##_perm_to_string,\ - .common_base = b }, -#include "av_inherit.h" -#undef S_ -}; - -const struct selinux_class_perm selinux_class_perm = { - .av_perm_to_string = av_perm_to_string, - .av_pts_len = ARRAY_SIZE(av_perm_to_string), - .class_to_string = class_to_string, - .cts_len = ARRAY_SIZE(class_to_string), - .av_inherit = av_inherit, - .av_inherit_len = ARRAY_SIZE(av_inherit) -}; +#include "classmap.h" #define AVC_CACHE_SLOTS 512 #define AVC_DEF_CACHE_THRESHOLD 512 @@ -139,52 +103,28 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) */ static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) { - const char **common_pts = NULL; - u32 common_base = 0; - int i, i2, perm; + const char **perms; + int i, perm; if (av == 0) { audit_log_format(ab, " null"); return; } - for (i = 0; i < ARRAY_SIZE(av_inherit); i++) { - if (av_inherit[i].tclass == tclass) { - common_pts = av_inherit[i].common_pts; - common_base = av_inherit[i].common_base; - break; - } - } + perms = secclass_map[tclass-1].perms; audit_log_format(ab, " {"); i = 0; perm = 1; - while (perm < common_base) { + while (i < (sizeof(av) * 8)) { if (perm & av) { - audit_log_format(ab, " %s", common_pts[i]); + audit_log_format(ab, " %s", perms[i]); av &= ~perm; } i++; perm <<= 1; } - while (i < sizeof(av) * 8) { - if (perm & av) { - for (i2 = 0; i2 < ARRAY_SIZE(av_perm_to_string); i2++) { - if ((av_perm_to_string[i2].tclass == tclass) && - (av_perm_to_string[i2].value == perm)) - break; - } - if (i2 < ARRAY_SIZE(av_perm_to_string)) { - audit_log_format(ab, " %s", - av_perm_to_string[i2].name); - av &= ~perm; - } - } - i++; - perm <<= 1; - } - if (av) audit_log_format(ab, " 0x%x", av); @@ -219,8 +159,8 @@ static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tcla kfree(scontext); } - BUG_ON(tclass >= ARRAY_SIZE(class_to_string) || !class_to_string[tclass]); - audit_log_format(ab, " tclass=%s", class_to_string[tclass]); + BUG_ON(tclass >= ARRAY_SIZE(secclass_map)); + audit_log_format(ab, " tclass=%s", secclass_map[tclass-1].name); } /** diff --git a/security/selinux/include/av_inherit.h b/security/selinux/include/av_inherit.h deleted file mode 100644 index abedcd704da..00000000000 --- a/security/selinux/include/av_inherit.h +++ /dev/null @@ -1,34 +0,0 @@ -/* This file is automatically generated. Do not edit. */ - S_(SECCLASS_DIR, file, 0x00020000UL) - S_(SECCLASS_FILE, file, 0x00020000UL) - S_(SECCLASS_LNK_FILE, file, 0x00020000UL) - S_(SECCLASS_CHR_FILE, file, 0x00020000UL) - S_(SECCLASS_BLK_FILE, file, 0x00020000UL) - S_(SECCLASS_SOCK_FILE, file, 0x00020000UL) - S_(SECCLASS_FIFO_FILE, file, 0x00020000UL) - S_(SECCLASS_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_TCP_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_UDP_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_RAWIP_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_NETLINK_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_PACKET_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_KEY_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_UNIX_STREAM_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_UNIX_DGRAM_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_TUN_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_IPC, ipc, 0x00000200UL) - S_(SECCLASS_SEM, ipc, 0x00000200UL) - S_(SECCLASS_MSGQ, ipc, 0x00000200UL) - S_(SECCLASS_SHM, ipc, 0x00000200UL) - S_(SECCLASS_NETLINK_ROUTE_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_NETLINK_FIREWALL_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_NETLINK_TCPDIAG_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_NETLINK_NFLOG_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_NETLINK_XFRM_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_NETLINK_SELINUX_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_NETLINK_AUDIT_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_NETLINK_IP6FW_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_NETLINK_DNRT_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_APPLETALK_SOCKET, socket, 0x00400000UL) - S_(SECCLASS_DCCP_SOCKET, socket, 0x00400000UL) diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h deleted file mode 100644 index 2b683ad83d2..00000000000 --- a/security/selinux/include/av_perm_to_string.h +++ /dev/null @@ -1,183 +0,0 @@ -/* This file is automatically generated. Do not edit. */ - S_(SECCLASS_FILESYSTEM, FILESYSTEM__MOUNT, "mount") - S_(SECCLASS_FILESYSTEM, FILESYSTEM__REMOUNT, "remount") - S_(SECCLASS_FILESYSTEM, FILESYSTEM__UNMOUNT, "unmount") - S_(SECCLASS_FILESYSTEM, FILESYSTEM__GETATTR, "getattr") - S_(SECCLASS_FILESYSTEM, FILESYSTEM__RELABELFROM, "relabelfrom") - S_(SECCLASS_FILESYSTEM, FILESYSTEM__RELABELTO, "relabelto") - S_(SECCLASS_FILESYSTEM, FILESYSTEM__TRANSITION, "transition") - S_(SECCLASS_FILESYSTEM, FILESYSTEM__ASSOCIATE, "associate") - S_(SECCLASS_FILESYSTEM, FILESYSTEM__QUOTAMOD, "quotamod") - S_(SECCLASS_FILESYSTEM, FILESYSTEM__QUOTAGET, "quotaget") - S_(SECCLASS_DIR, DIR__ADD_NAME, "add_name") - S_(SECCLASS_DIR, DIR__REMOVE_NAME, "remove_name") - S_(SECCLASS_DIR, DIR__REPARENT, "reparent") - S_(SECCLASS_DIR, DIR__SEARCH, "search") - S_(SECCLASS_DIR, DIR__RMDIR, "rmdir") - S_(SECCLASS_DIR, DIR__OPEN, "open") - S_(SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, "execute_no_trans") - S_(SECCLASS_FILE, FILE__ENTRYPOINT, "entrypoint") - S_(SECCLASS_FILE, FILE__EXECMOD, "execmod") - S_(SECCLASS_FILE, FILE__OPEN, "open") - S_(SECCLASS_CHR_FILE, CHR_FILE__EXECUTE_NO_TRANS, "execute_no_trans") - S_(SECCLASS_CHR_FILE, CHR_FILE__ENTRYPOINT, "entrypoint") - S_(SECCLASS_CHR_FILE, CHR_FILE__EXECMOD, "execmod") - S_(SECCLASS_CHR_FILE, CHR_FILE__OPEN, "open") - S_(SECCLASS_BLK_FILE, BLK_FILE__OPEN, "open") - S_(SECCLASS_SOCK_FILE, SOCK_FILE__OPEN, "open") - S_(SECCLASS_FIFO_FILE, FIFO_FILE__OPEN, "open") - S_(SECCLASS_FD, FD__USE, "use") - S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__CONNECTTO, "connectto") - S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__NEWCONN, "newconn") - S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__ACCEPTFROM, "acceptfrom") - S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__NODE_BIND, "node_bind") - S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__NAME_CONNECT, "name_connect") - S_(SECCLASS_UDP_SOCKET, UDP_SOCKET__NODE_BIND, "node_bind") - S_(SECCLASS_RAWIP_SOCKET, RAWIP_SOCKET__NODE_BIND, "node_bind") - S_(SECCLASS_NODE, NODE__TCP_RECV, "tcp_recv") - S_(SECCLASS_NODE, NODE__TCP_SEND, "tcp_send") - S_(SECCLASS_NODE, NODE__UDP_RECV, "udp_recv") - S_(SECCLASS_NODE, NODE__UDP_SEND, "udp_send") - S_(SECCLASS_NODE, NODE__RAWIP_RECV, "rawip_recv") - S_(SECCLASS_NODE, NODE__RAWIP_SEND, "rawip_send") - S_(SECCLASS_NODE, NODE__ENFORCE_DEST, "enforce_dest") - S_(SECCLASS_NODE, NODE__DCCP_RECV, "dccp_recv") - S_(SECCLASS_NODE, NODE__DCCP_SEND, "dccp_send") - S_(SECCLASS_NODE, NODE__RECVFROM, "recvfrom") - S_(SECCLASS_NODE, NODE__SENDTO, "sendto") - S_(SECCLASS_NETIF, NETIF__TCP_RECV, "tcp_recv") - S_(SECCLASS_NETIF, NETIF__TCP_SEND, "tcp_send") - S_(SECCLASS_NETIF, NETIF__UDP_RECV, "udp_recv") - S_(SECCLASS_NETIF, NETIF__UDP_SEND, "udp_send") - S_(SECCLASS_NETIF, NETIF__RAWIP_RECV, "rawip_recv") - S_(SECCLASS_NETIF, NETIF__RAWIP_SEND, "rawip_send") - S_(SECCLASS_NETIF, NETIF__DCCP_RECV, "dccp_recv") - S_(SECCLASS_NETIF, NETIF__DCCP_SEND, "dccp_send") - S_(SECCLASS_NETIF, NETIF__INGRESS, "ingress") - S_(SECCLASS_NETIF, NETIF__EGRESS, "egress") - S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__CONNECTTO, "connectto") - S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__NEWCONN, "newconn") - S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__ACCEPTFROM, "acceptfrom") - S_(SECCLASS_PROCESS, PROCESS__FORK, "fork") - S_(SECCLASS_PROCESS, PROCESS__TRANSITION, "transition") - S_(SECCLASS_PROCESS, PROCESS__SIGCHLD, "sigchld") - S_(SECCLASS_PROCESS, PROCESS__SIGKILL, "sigkill") - S_(SECCLASS_PROCESS, PROCESS__SIGSTOP, "sigstop") - S_(SECCLASS_PROCESS, PROCESS__SIGNULL, "signull") - S_(SECCLASS_PROCESS, PROCESS__SIGNAL, "signal") - S_(SECCLASS_PROCESS, PROCESS__PTRACE, "ptrace") - S_(SECCLASS_PROCESS, PROCESS__GETSCHED, "getsched") - S_(SECCLASS_PROCESS, PROCESS__SETSCHED, "setsched") - S_(SECCLASS_PROCESS, PROCESS__GETSESSION, "getsession") - S_(SECCLASS_PROCESS, PROCESS__GETPGID, "getpgid") - S_(SECCLASS_PROCESS, PROCESS__SETPGID, "setpgid") - S_(SECCLASS_PROCESS, PROCESS__GETCAP, "getcap") - S_(SECCLASS_PROCESS, PROCESS__SETCAP, "setcap") - S_(SECCLASS_PROCESS, PROCESS__SHARE, "share") - S_(SECCLASS_PROCESS, PROCESS__GETATTR, "getattr") - S_(SECCLASS_PROCESS, PROCESS__SETEXEC, "setexec") - S_(SECCLASS_PROCESS, PROCESS__SETFSCREATE, "setfscreate") - S_(SECCLASS_PROCESS, PROCESS__NOATSECURE, "noatsecure") - S_(SECCLASS_PROCESS, PROCESS__SIGINH, "siginh") - S_(SECCLASS_PROCESS, PROCESS__SETRLIMIT, "setrlimit") - S_(SECCLASS_PROCESS, PROCESS__RLIMITINH, "rlimitinh") - S_(SECCLASS_PROCESS, PROCESS__DYNTRANSITION, "dyntransition") - S_(SECCLASS_PROCESS, PROCESS__SETCURRENT, "setcurrent") - S_(SECCLASS_PROCESS, PROCESS__EXECMEM, "execmem") - S_(SECCLASS_PROCESS, PROCESS__EXECSTACK, "execstack") - S_(SECCLASS_PROCESS, PROCESS__EXECHEAP, "execheap") - S_(SECCLASS_PROCESS, PROCESS__SETKEYCREATE, "setkeycreate") - S_(SECCLASS_PROCESS, PROCESS__SETSOCKCREATE, "setsockcreate") - S_(SECCLASS_MSGQ, MSGQ__ENQUEUE, "enqueue") - S_(SECCLASS_MSG, MSG__SEND, "send") - S_(SECCLASS_MSG, MSG__RECEIVE, "receive") - S_(SECCLASS_SHM, SHM__LOCK, "lock") - S_(SECCLASS_SECURITY, SECURITY__COMPUTE_AV, "compute_av") - S_(SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE, "compute_create") - S_(SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER, "compute_member") - S_(SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, "check_context") - S_(SECCLASS_SECURITY, SECURITY__LOAD_POLICY, "load_policy") - S_(SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL, "compute_relabel") - S_(SECCLASS_SECURITY, SECURITY__COMPUTE_USER, "compute_user") - S_(SECCLASS_SECURITY, SECURITY__SETENFORCE, "setenforce") - S_(SECCLASS_SECURITY, SECURITY__SETBOOL, "setbool") - S_(SECCLASS_SECURITY, SECURITY__SETSECPARAM, "setsecparam") - S_(SECCLASS_SECURITY, SECURITY__SETCHECKREQPROT, "setcheckreqprot") - S_(SECCLASS_SYSTEM, SYSTEM__IPC_INFO, "ipc_info") - S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, "syslog_read") - S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, "syslog_mod") - S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, "syslog_console") - S_(SECCLASS_SYSTEM, SYSTEM__MODULE_REQUEST, "module_request") - S_(SECCLASS_CAPABILITY, CAPABILITY__CHOWN, "chown") - S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_OVERRIDE, "dac_override") - S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_READ_SEARCH, "dac_read_search") - S_(SECCLASS_CAPABILITY, CAPABILITY__FOWNER, "fowner") - S_(SECCLASS_CAPABILITY, CAPABILITY__FSETID, "fsetid") - S_(SECCLASS_CAPABILITY, CAPABILITY__KILL, "kill") - S_(SECCLASS_CAPABILITY, CAPABILITY__SETGID, "setgid") - S_(SECCLASS_CAPABILITY, CAPABILITY__SETUID, "setuid") - S_(SECCLASS_CAPABILITY, CAPABILITY__SETPCAP, "setpcap") - S_(SECCLASS_CAPABILITY, CAPABILITY__LINUX_IMMUTABLE, "linux_immutable") - S_(SECCLASS_CAPABILITY, CAPABILITY__NET_BIND_SERVICE, "net_bind_service") - S_(SECCLASS_CAPABILITY, CAPABILITY__NET_BROADCAST, "net_broadcast") - S_(SECCLASS_CAPABILITY, CAPABILITY__NET_ADMIN, "net_admin") - S_(SECCLASS_CAPABILITY, CAPABILITY__NET_RAW, "net_raw") - S_(SECCLASS_CAPABILITY, CAPABILITY__IPC_LOCK, "ipc_lock") - S_(SECCLASS_CAPABILITY, CAPABILITY__IPC_OWNER, "ipc_owner") - S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_MODULE, "sys_module") - S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_RAWIO, "sys_rawio") - S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_CHROOT, "sys_chroot") - S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_PTRACE, "sys_ptrace") - S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_PACCT, "sys_pacct") - S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_ADMIN, "sys_admin") - S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_BOOT, "sys_boot") - S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_NICE, "sys_nice") - S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_RESOURCE, "sys_resource") - S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_TIME, "sys_time") - S_(SECCLASS_CAPABILITY, CAPABILITY__SYS_TTY_CONFIG, "sys_tty_config") - S_(SECCLASS_CAPABILITY, CAPABILITY__MKNOD, "mknod") - S_(SECCLASS_CAPABILITY, CAPABILITY__LEASE, "lease") - S_(SECCLASS_CAPABILITY, CAPABILITY__AUDIT_WRITE, "audit_write") - S_(SECCLASS_CAPABILITY, CAPABILITY__AUDIT_CONTROL, "audit_control") - S_(SECCLASS_CAPABILITY, CAPABILITY__SETFCAP, "setfcap") - S_(SECCLASS_CAPABILITY2, CAPABILITY2__MAC_OVERRIDE, "mac_override") - S_(SECCLASS_CAPABILITY2, CAPABILITY2__MAC_ADMIN, "mac_admin") - S_(SECCLASS_NETLINK_ROUTE_SOCKET, NETLINK_ROUTE_SOCKET__NLMSG_READ, "nlmsg_read") - S_(SECCLASS_NETLINK_ROUTE_SOCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE, "nlmsg_write") - S_(SECCLASS_NETLINK_FIREWALL_SOCKET, NETLINK_FIREWALL_SOCKET__NLMSG_READ, "nlmsg_read") - S_(SECCLASS_NETLINK_FIREWALL_SOCKET, NETLINK_FIREWALL_SOCKET__NLMSG_WRITE, "nlmsg_write") - S_(SECCLASS_NETLINK_TCPDIAG_SOCKET, NETLINK_TCPDIAG_SOCKET__NLMSG_READ, "nlmsg_read") - S_(SECCLASS_NETLINK_TCPDIAG_SOCKET, NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE, "nlmsg_write") - S_(SECCLASS_NETLINK_XFRM_SOCKET, NETLINK_XFRM_SOCKET__NLMSG_READ, "nlmsg_read") - S_(SECCLASS_NETLINK_XFRM_SOCKET, NETLINK_XFRM_SOCKET__NLMSG_WRITE, "nlmsg_write") - S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_READ, "nlmsg_read") - S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE, "nlmsg_write") - S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_RELAY, "nlmsg_relay") - S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV, "nlmsg_readpriv") - S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT, "nlmsg_tty_audit") - S_(SECCLASS_NETLINK_IP6FW_SOCKET, NETLINK_IP6FW_SOCKET__NLMSG_READ, "nlmsg_read") - S_(SECCLASS_NETLINK_IP6FW_SOCKET, NETLINK_IP6FW_SOCKET__NLMSG_WRITE, "nlmsg_write") - S_(SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, "sendto") - S_(SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, "recvfrom") - S_(SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, "setcontext") - S_(SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, "polmatch") - S_(SECCLASS_PACKET, PACKET__SEND, "send") - S_(SECCLASS_PACKET, PACKET__RECV, "recv") - S_(SECCLASS_PACKET, PACKET__RELABELTO, "relabelto") - S_(SECCLASS_PACKET, PACKET__FLOW_IN, "flow_in") - S_(SECCLASS_PACKET, PACKET__FLOW_OUT, "flow_out") - S_(SECCLASS_PACKET, PACKET__FORWARD_IN, "forward_in") - S_(SECCLASS_PACKET, PACKET__FORWARD_OUT, "forward_out") - S_(SECCLASS_KEY, KEY__VIEW, "view") - S_(SECCLASS_KEY, KEY__READ, "read") - S_(SECCLASS_KEY, KEY__WRITE, "write") - S_(SECCLASS_KEY, KEY__SEARCH, "search") - S_(SECCLASS_KEY, KEY__LINK, "link") - S_(SECCLASS_KEY, KEY__SETATTR, "setattr") - S_(SECCLASS_KEY, KEY__CREATE, "create") - S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NODE_BIND, "node_bind") - S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NAME_CONNECT, "name_connect") - S_(SECCLASS_MEMPROTECT, MEMPROTECT__MMAP_ZERO, "mmap_zero") - S_(SECCLASS_PEER, PEER__RECV, "recv") - S_(SECCLASS_KERNEL_SERVICE, KERNEL_SERVICE__USE_AS_OVERRIDE, "use_as_override") - S_(SECCLASS_KERNEL_SERVICE, KERNEL_SERVICE__CREATE_FILES_AS, "create_files_as") diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h index 0546d616cca..fef2582b734 100644 --- a/security/selinux/include/av_permissions.h +++ b/security/selinux/include/av_permissions.h @@ -423,28 +423,6 @@ #define UNIX_DGRAM_SOCKET__RECV_MSG 0x00080000UL #define UNIX_DGRAM_SOCKET__SEND_MSG 0x00100000UL #define UNIX_DGRAM_SOCKET__NAME_BIND 0x00200000UL -#define TUN_SOCKET__IOCTL 0x00000001UL -#define TUN_SOCKET__READ 0x00000002UL -#define TUN_SOCKET__WRITE 0x00000004UL -#define TUN_SOCKET__CREATE 0x00000008UL -#define TUN_SOCKET__GETATTR 0x00000010UL -#define TUN_SOCKET__SETATTR 0x00000020UL -#define TUN_SOCKET__LOCK 0x00000040UL -#define TUN_SOCKET__RELABELFROM 0x00000080UL -#define TUN_SOCKET__RELABELTO 0x00000100UL -#define TUN_SOCKET__APPEND 0x00000200UL -#define TUN_SOCKET__BIND 0x00000400UL -#define TUN_SOCKET__CONNECT 0x00000800UL -#define TUN_SOCKET__LISTEN 0x00001000UL -#define TUN_SOCKET__ACCEPT 0x00002000UL -#define TUN_SOCKET__GETOPT 0x00004000UL -#define TUN_SOCKET__SETOPT 0x00008000UL -#define TUN_SOCKET__SHUTDOWN 0x00010000UL -#define TUN_SOCKET__RECVFROM 0x00020000UL -#define TUN_SOCKET__SENDTO 0x00040000UL -#define TUN_SOCKET__RECV_MSG 0x00080000UL -#define TUN_SOCKET__SEND_MSG 0x00100000UL -#define TUN_SOCKET__NAME_BIND 0x00200000UL #define PROCESS__FORK 0x00000001UL #define PROCESS__TRANSITION 0x00000002UL #define PROCESS__SIGCHLD 0x00000004UL @@ -868,3 +846,25 @@ #define PEER__RECV 0x00000001UL #define KERNEL_SERVICE__USE_AS_OVERRIDE 0x00000001UL #define KERNEL_SERVICE__CREATE_FILES_AS 0x00000002UL +#define TUN_SOCKET__IOCTL 0x00000001UL +#define TUN_SOCKET__READ 0x00000002UL +#define TUN_SOCKET__WRITE 0x00000004UL +#define TUN_SOCKET__CREATE 0x00000008UL +#define TUN_SOCKET__GETATTR 0x00000010UL +#define TUN_SOCKET__SETATTR 0x00000020UL +#define TUN_SOCKET__LOCK 0x00000040UL +#define TUN_SOCKET__RELABELFROM 0x00000080UL +#define TUN_SOCKET__RELABELTO 0x00000100UL +#define TUN_SOCKET__APPEND 0x00000200UL +#define TUN_SOCKET__BIND 0x00000400UL +#define TUN_SOCKET__CONNECT 0x00000800UL +#define TUN_SOCKET__LISTEN 0x00001000UL +#define TUN_SOCKET__ACCEPT 0x00002000UL +#define TUN_SOCKET__GETOPT 0x00004000UL +#define TUN_SOCKET__SETOPT 0x00008000UL +#define TUN_SOCKET__SHUTDOWN 0x00010000UL +#define TUN_SOCKET__RECVFROM 0x00020000UL +#define TUN_SOCKET__SENDTO 0x00040000UL +#define TUN_SOCKET__RECV_MSG 0x00080000UL +#define TUN_SOCKET__SEND_MSG 0x00100000UL +#define TUN_SOCKET__NAME_BIND 0x00200000UL diff --git a/security/selinux/include/avc_ss.h b/security/selinux/include/avc_ss.h index bb1ec801bdf..4677aa519b0 100644 --- a/security/selinux/include/avc_ss.h +++ b/security/selinux/include/avc_ss.h @@ -10,26 +10,13 @@ int avc_ss_reset(u32 seqno); -struct av_perm_to_string { - u16 tclass; - u32 value; +/* Class/perm mapping support */ +struct security_class_mapping { const char *name; + const char *perms[sizeof(u32) * 8 + 1]; }; -struct av_inherit { - const char **common_pts; - u32 common_base; - u16 tclass; -}; - -struct selinux_class_perm { - const struct av_perm_to_string *av_perm_to_string; - u32 av_pts_len; - u32 cts_len; - const char **class_to_string; - const struct av_inherit *av_inherit; - u32 av_inherit_len; -}; +extern struct security_class_mapping secclass_map[]; #endif /* _SELINUX_AVC_SS_H_ */ diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h deleted file mode 100644 index 7ab9299bfb6..00000000000 --- a/security/selinux/include/class_to_string.h +++ /dev/null @@ -1,80 +0,0 @@ -/* This file is automatically generated. Do not edit. */ -/* - * Security object class definitions - */ - S_(NULL) - S_("security") - S_("process") - S_("system") - S_("capability") - S_("filesystem") - S_("file") - S_("dir") - S_("fd") - S_("lnk_file") - S_("chr_file") - S_("blk_file") - S_("sock_file") - S_("fifo_file") - S_("socket") - S_("tcp_socket") - S_("udp_socket") - S_("rawip_socket") - S_("node") - S_("netif") - S_("netlink_socket") - S_("packet_socket") - S_("key_socket") - S_("unix_stream_socket") - S_("unix_dgram_socket") - S_("sem") - S_("msg") - S_("msgq") - S_("shm") - S_("ipc") - S_(NULL) - S_(NULL) - S_(NULL) - S_(NULL) - S_(NULL) - S_(NULL) - S_(NULL) - S_(NULL) - S_(NULL) - S_(NULL) - S_(NULL) - S_(NULL) - S_(NULL) - S_("netlink_route_socket") - S_("netlink_firewall_socket") - S_("netlink_tcpdiag_socket") - S_("netlink_nflog_socket") - S_("netlink_xfrm_socket") - S_("netlink_selinux_socket") - S_("netlink_audit_socket") - S_("netlink_ip6fw_socket") - S_("netlink_dnrt_socket") - S_(NULL) - S_(NULL) - S_("association") - S_("netlink_kobject_uevent_socket") - S_("appletalk_socket") - S_("packet") - S_("key") - S_(NULL) - S_("dccp_socket") - S_("memprotect") - S_(NULL) - S_(NULL) - S_(NULL) - S_(NULL) - S_(NULL) - S_(NULL) - S_("peer") - S_("capability2") - S_(NULL) - S_(NULL) - S_(NULL) - S_(NULL) - S_("kernel_service") - S_("tun_socket") diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h new file mode 100644 index 00000000000..8b32e959bb2 --- /dev/null +++ b/security/selinux/include/classmap.h @@ -0,0 +1,150 @@ +#define COMMON_FILE_SOCK_PERMS "ioctl", "read", "write", "create", \ + "getattr", "setattr", "lock", "relabelfrom", "relabelto", "append" + +#define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \ + "rename", "execute", "swapon", "quotaon", "mounton" + +#define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \ + "listen", "accept", "getopt", "setopt", "shutdown", "recvfrom", \ + "sendto", "recv_msg", "send_msg", "name_bind" + +#define COMMON_IPC_PERMS "create", "destroy", "getattr", "setattr", "read", \ + "write", "associate", "unix_read", "unix_write" + +struct security_class_mapping secclass_map[] = { + { "security", + { "compute_av", "compute_create", "compute_member", + "check_context", "load_policy", "compute_relabel", + "compute_user", "setenforce", "setbool", "setsecparam", + "setcheckreqprot", NULL } }, + { "process", + { "fork", "transition", "sigchld", "sigkill", + "sigstop", "signull", "signal", "ptrace", "getsched", "setsched", + "getsession", "getpgid", "setpgid", "getcap", "setcap", "share", + "getattr", "setexec", "setfscreate", "noatsecure", "siginh", + "setrlimit", "rlimitinh", "dyntransition", "setcurrent", + "execmem", "execstack", "execheap", "setkeycreate", + "setsockcreate", NULL } }, + { "system", + { "ipc_info", "syslog_read", "syslog_mod", + "syslog_console", "module_request", NULL } }, + { "capability", + { "chown", "dac_override", "dac_read_search", + "fowner", "fsetid", "kill", "setgid", "setuid", "setpcap", + "linux_immutable", "net_bind_service", "net_broadcast", + "net_admin", "net_raw", "ipc_lock", "ipc_owner", "sys_module", + "sys_rawio", "sys_chroot", "sys_ptrace", "sys_pacct", "sys_admin", + "sys_boot", "sys_nice", "sys_resource", "sys_time", + "sys_tty_config", "mknod", "lease", "audit_write", + "audit_control", "setfcap", NULL } }, + { "filesystem", + { "mount", "remount", "unmount", "getattr", + "relabelfrom", "relabelto", "transition", "associate", "quotamod", + "quotaget", NULL } }, + { "file", + { COMMON_FILE_PERMS, + "execute_no_trans", "entrypoint", "execmod", "open", NULL } }, + { "dir", + { COMMON_FILE_PERMS, "add_name", "remove_name", + "reparent", "search", "rmdir", "open", NULL } }, + { "fd", { "use", NULL } }, + { "lnk_file", + { COMMON_FILE_PERMS, NULL } }, + { "chr_file", + { COMMON_FILE_PERMS, + "execute_no_trans", "entrypoint", "execmod", "open", NULL } }, + { "blk_file", + { COMMON_FILE_PERMS, "open", NULL } }, + { "sock_file", + { COMMON_FILE_PERMS, "open", NULL } }, + { "fifo_file", + { COMMON_FILE_PERMS, "open", NULL } }, + { "socket", + { COMMON_SOCK_PERMS, NULL } }, + { "tcp_socket", + { COMMON_SOCK_PERMS, + "connectto", "newconn", "acceptfrom", "node_bind", "name_connect", + NULL } }, + { "udp_socket", + { COMMON_SOCK_PERMS, + "node_bind", NULL } }, + { "rawip_socket", + { COMMON_SOCK_PERMS, + "node_bind", NULL } }, + { "node", + { "tcp_recv", "tcp_send", "udp_recv", "udp_send", + "rawip_recv", "rawip_send", "enforce_dest", + "dccp_recv", "dccp_send", "recvfrom", "sendto", NULL } }, + { "netif", + { "tcp_recv", "tcp_send", "udp_recv", "udp_send", + "rawip_recv", "rawip_send", "dccp_recv", "dccp_send", + "ingress", "egress", NULL } }, + { "netlink_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "packet_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "key_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "unix_stream_socket", + { COMMON_SOCK_PERMS, "connectto", "newconn", "acceptfrom", NULL + } }, + { "unix_dgram_socket", + { COMMON_SOCK_PERMS, NULL + } }, + { "sem", + { COMMON_IPC_PERMS, NULL } }, + { "msg", { "send", "receive", NULL } }, + { "msgq", + { COMMON_IPC_PERMS, "enqueue", NULL } }, + { "shm", + { COMMON_IPC_PERMS, "lock", NULL } }, + { "ipc", + { COMMON_IPC_PERMS, NULL } }, + { "netlink_route_socket", + { COMMON_SOCK_PERMS, + "nlmsg_read", "nlmsg_write", NULL } }, + { "netlink_firewall_socket", + { COMMON_SOCK_PERMS, + "nlmsg_read", "nlmsg_write", NULL } }, + { "netlink_tcpdiag_socket", + { COMMON_SOCK_PERMS, + "nlmsg_read", "nlmsg_write", NULL } }, + { "netlink_nflog_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "netlink_xfrm_socket", + { COMMON_SOCK_PERMS, + "nlmsg_read", "nlmsg_write", NULL } }, + { "netlink_selinux_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "netlink_audit_socket", + { COMMON_SOCK_PERMS, + "nlmsg_read", "nlmsg_write", "nlmsg_relay", "nlmsg_readpriv", + "nlmsg_tty_audit", NULL } }, + { "netlink_ip6fw_socket", + { COMMON_SOCK_PERMS, + "nlmsg_read", "nlmsg_write", NULL } }, + { "netlink_dnrt_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "association", + { "sendto", "recvfrom", "setcontext", "polmatch", NULL } }, + { "netlink_kobject_uevent_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "appletalk_socket", + { COMMON_SOCK_PERMS, NULL } }, + { "packet", + { "send", "recv", "relabelto", "flow_in", "flow_out", + "forward_in", "forward_out", NULL } }, + { "key", + { "view", "read", "write", "search", "link", "setattr", "create", + NULL } }, + { "dccp_socket", + { COMMON_SOCK_PERMS, + "node_bind", "name_connect", NULL } }, + { "memprotect", { "mmap_zero", NULL } }, + { "peer", { "recv", NULL } }, + { "capability2", { "mac_override", "mac_admin", NULL } }, + { "kernel_service", { "use_as_override", "create_files_as", NULL } }, + { "tun_socket", + { COMMON_SOCK_PERMS, NULL } }, + { NULL } + }; diff --git a/security/selinux/include/common_perm_to_string.h b/security/selinux/include/common_perm_to_string.h deleted file mode 100644 index ce5b6e2fe9d..00000000000 --- a/security/selinux/include/common_perm_to_string.h +++ /dev/null @@ -1,58 +0,0 @@ -/* This file is automatically generated. Do not edit. */ -TB_(common_file_perm_to_string) - S_("ioctl") - S_("read") - S_("write") - S_("create") - S_("getattr") - S_("setattr") - S_("lock") - S_("relabelfrom") - S_("relabelto") - S_("append") - S_("unlink") - S_("link") - S_("rename") - S_("execute") - S_("swapon") - S_("quotaon") - S_("mounton") -TE_(common_file_perm_to_string) - -TB_(common_socket_perm_to_string) - S_("ioctl") - S_("read") - S_("write") - S_("create") - S_("getattr") - S_("setattr") - S_("lock") - S_("relabelfrom") - S_("relabelto") - S_("append") - S_("bind") - S_("connect") - S_("listen") - S_("accept") - S_("getopt") - S_("setopt") - S_("shutdown") - S_("recvfrom") - S_("sendto") - S_("recv_msg") - S_("send_msg") - S_("name_bind") -TE_(common_socket_perm_to_string) - -TB_(common_ipc_perm_to_string) - S_("create") - S_("destroy") - S_("getattr") - S_("setattr") - S_("read") - S_("write") - S_("associate") - S_("unix_read") - S_("unix_write") -TE_(common_ipc_perm_to_string) - diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h index f248500a1e3..5359ca2abf2 100644 --- a/security/selinux/include/flask.h +++ b/security/selinux/include/flask.h @@ -34,26 +34,26 @@ #define SECCLASS_MSGQ 27 #define SECCLASS_SHM 28 #define SECCLASS_IPC 29 -#define SECCLASS_NETLINK_ROUTE_SOCKET 43 -#define SECCLASS_NETLINK_FIREWALL_SOCKET 44 -#define SECCLASS_NETLINK_TCPDIAG_SOCKET 45 -#define SECCLASS_NETLINK_NFLOG_SOCKET 46 -#define SECCLASS_NETLINK_XFRM_SOCKET 47 -#define SECCLASS_NETLINK_SELINUX_SOCKET 48 -#define SECCLASS_NETLINK_AUDIT_SOCKET 49 -#define SECCLASS_NETLINK_IP6FW_SOCKET 50 -#define SECCLASS_NETLINK_DNRT_SOCKET 51 -#define SECCLASS_ASSOCIATION 54 -#define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET 55 -#define SECCLASS_APPLETALK_SOCKET 56 -#define SECCLASS_PACKET 57 -#define SECCLASS_KEY 58 -#define SECCLASS_DCCP_SOCKET 60 -#define SECCLASS_MEMPROTECT 61 -#define SECCLASS_PEER 68 -#define SECCLASS_CAPABILITY2 69 -#define SECCLASS_KERNEL_SERVICE 74 -#define SECCLASS_TUN_SOCKET 75 +#define SECCLASS_NETLINK_ROUTE_SOCKET 30 +#define SECCLASS_NETLINK_FIREWALL_SOCKET 31 +#define SECCLASS_NETLINK_TCPDIAG_SOCKET 32 +#define SECCLASS_NETLINK_NFLOG_SOCKET 33 +#define SECCLASS_NETLINK_XFRM_SOCKET 34 +#define SECCLASS_NETLINK_SELINUX_SOCKET 35 +#define SECCLASS_NETLINK_AUDIT_SOCKET 36 +#define SECCLASS_NETLINK_IP6FW_SOCKET 37 +#define SECCLASS_NETLINK_DNRT_SOCKET 38 +#define SECCLASS_ASSOCIATION 39 +#define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET 40 +#define SECCLASS_APPLETALK_SOCKET 41 +#define SECCLASS_PACKET 42 +#define SECCLASS_KEY 43 +#define SECCLASS_DCCP_SOCKET 44 +#define SECCLASS_MEMPROTECT 45 +#define SECCLASS_PEER 46 +#define SECCLASS_CAPABILITY2 47 +#define SECCLASS_KERNEL_SERVICE 48 +#define SECCLASS_TUN_SOCKET 49 /* * Security identifier indices for initial entities diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index ca835795a8b..2553266ad79 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -97,11 +97,18 @@ struct av_decision { #define AVD_FLAGS_PERMISSIVE 0x0001 int security_compute_av(u32 ssid, u32 tsid, - u16 tclass, u32 requested, - struct av_decision *avd); + u16 tclass, u32 requested, + struct av_decision *avd); + +int security_compute_av_user(u32 ssid, u32 tsid, + u16 tclass, u32 requested, + struct av_decision *avd); int security_transition_sid(u32 ssid, u32 tsid, - u16 tclass, u32 *out_sid); + u16 tclass, u32 *out_sid); + +int security_transition_sid_user(u32 ssid, u32 tsid, + u16 tclass, u32 *out_sid); int security_member_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid); diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index b4fc506e7a8..fab36fdf276 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -522,7 +522,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) if (length < 0) goto out2; - length = security_compute_av(ssid, tsid, tclass, req, &avd); + length = security_compute_av_user(ssid, tsid, tclass, req, &avd); if (length < 0) goto out2; @@ -571,7 +571,7 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) if (length < 0) goto out2; - length = security_transition_sid(ssid, tsid, tclass, &newsid); + length = security_transition_sid_user(ssid, tsid, tclass, &newsid); if (length < 0) goto out2; diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index b5407f16c2a..3f2b2706b5b 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -532,7 +532,7 @@ int mls_compute_sid(struct context *scontext, } /* Fallthrough */ case AVTAB_CHANGE: - if (tclass == SECCLASS_PROCESS) + if (tclass == policydb.process_class) /* Use the process MLS attributes. */ return mls_context_cpy(newcontext, scontext); else diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 72e4a54973a..f03667213ea 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -713,7 +713,6 @@ void policydb_destroy(struct policydb *p) ebitmap_destroy(&p->type_attr_map[i]); } kfree(p->type_attr_map); - kfree(p->undefined_perms); ebitmap_destroy(&p->policycaps); ebitmap_destroy(&p->permissive_map); @@ -1640,6 +1639,40 @@ static int policydb_bounds_sanity_check(struct policydb *p) extern int ss_initialized; +u16 string_to_security_class(struct policydb *p, const char *name) +{ + struct class_datum *cladatum; + + cladatum = hashtab_search(p->p_classes.table, name); + if (!cladatum) + return 0; + + return cladatum->value; +} + +u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name) +{ + struct class_datum *cladatum; + struct perm_datum *perdatum = NULL; + struct common_datum *comdatum; + + if (!tclass || tclass > p->p_classes.nprim) + return 0; + + cladatum = p->class_val_to_struct[tclass-1]; + comdatum = cladatum->comdatum; + if (comdatum) + perdatum = hashtab_search(comdatum->permissions.table, + name); + if (!perdatum) + perdatum = hashtab_search(cladatum->permissions.table, + name); + if (!perdatum) + return 0; + + return 1U << (perdatum->value-1); +} + /* * Read the configuration data from a policy database binary * representation file into a policy database structure. @@ -1861,6 +1894,16 @@ int policydb_read(struct policydb *p, void *fp) if (rc) goto bad; + p->process_class = string_to_security_class(p, "process"); + if (!p->process_class) + goto bad; + p->process_trans_perms = string_to_av_perm(p, p->process_class, + "transition"); + p->process_trans_perms |= string_to_av_perm(p, p->process_class, + "dyntransition"); + if (!p->process_trans_perms) + goto bad; + for (i = 0; i < info->ocon_num; i++) { rc = next_entry(buf, fp, sizeof(u32)); if (rc < 0) @@ -2101,7 +2144,7 @@ int policydb_read(struct policydb *p, void *fp) goto bad; rt->target_class = le32_to_cpu(buf[0]); } else - rt->target_class = SECCLASS_PROCESS; + rt->target_class = p->process_class; if (!policydb_type_isvalid(p, rt->source_type) || !policydb_type_isvalid(p, rt->target_type) || !policydb_class_isvalid(p, rt->target_class)) { diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 55152d498b5..cdcc5700946 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -254,7 +254,9 @@ struct policydb { unsigned int reject_unknown : 1; unsigned int allow_unknown : 1; - u32 *undefined_perms; + + u16 process_class; + u32 process_trans_perms; }; extern void policydb_destroy(struct policydb *p); @@ -295,5 +297,8 @@ static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes) return 0; } +extern u16 string_to_security_class(struct policydb *p, const char *name); +extern u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name); + #endif /* _SS_POLICYDB_H_ */ diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index ff17820d35e..e19baa81fde 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -70,11 +70,6 @@ unsigned int policydb_loaded_version; int selinux_policycap_netpeer; int selinux_policycap_openperm; -/* - * This is declared in avc.c - */ -extern const struct selinux_class_perm selinux_class_perm; - static DEFINE_RWLOCK(policy_rwlock); static struct sidtab sidtab; @@ -98,6 +93,158 @@ static int context_struct_compute_av(struct context *scontext, u16 tclass, u32 requested, struct av_decision *avd); + +struct selinux_mapping { + u16 value; /* policy value */ + unsigned num_perms; + u32 perms[sizeof(u32) * 8]; +}; + +static struct selinux_mapping *current_mapping; +static u16 current_mapping_size; + +static int selinux_set_mapping(struct policydb *pol, + struct security_class_mapping *map, + struct selinux_mapping **out_map_p, + u16 *out_map_size) +{ + struct selinux_mapping *out_map = NULL; + size_t size = sizeof(struct selinux_mapping); + u16 i, j; + unsigned k; + bool print_unknown_handle = false; + + /* Find number of classes in the input mapping */ + if (!map) + return -EINVAL; + i = 0; + while (map[i].name) + i++; + + /* Allocate space for the class records, plus one for class zero */ + out_map = kcalloc(++i, size, GFP_ATOMIC); + if (!out_map) + return -ENOMEM; + + /* Store the raw class and permission values */ + j = 0; + while (map[j].name) { + struct security_class_mapping *p_in = map + (j++); + struct selinux_mapping *p_out = out_map + j; + + /* An empty class string skips ahead */ + if (!strcmp(p_in->name, "")) { + p_out->num_perms = 0; + continue; + } + + p_out->value = string_to_security_class(pol, p_in->name); + if (!p_out->value) { + printk(KERN_INFO + "SELinux: Class %s not defined in policy.\n", + p_in->name); + if (pol->reject_unknown) + goto err; + p_out->num_perms = 0; + print_unknown_handle = true; + continue; + } + + k = 0; + while (p_in->perms && p_in->perms[k]) { + /* An empty permission string skips ahead */ + if (!*p_in->perms[k]) { + k++; + continue; + } + p_out->perms[k] = string_to_av_perm(pol, p_out->value, + p_in->perms[k]); + if (!p_out->perms[k]) { + printk(KERN_INFO + "SELinux: Permission %s in class %s not defined in policy.\n", + p_in->perms[k], p_in->name); + if (pol->reject_unknown) + goto err; + print_unknown_handle = true; + } + + k++; + } + p_out->num_perms = k; + } + + if (print_unknown_handle) + printk(KERN_INFO "SELinux: the above unknown classes and permissions will be %s\n", + pol->allow_unknown ? "allowed" : "denied"); + + *out_map_p = out_map; + *out_map_size = i; + return 0; +err: + kfree(out_map); + return -EINVAL; +} + +/* + * Get real, policy values from mapped values + */ + +static u16 unmap_class(u16 tclass) +{ + if (tclass < current_mapping_size) + return current_mapping[tclass].value; + + return tclass; +} + +static u32 unmap_perm(u16 tclass, u32 tperm) +{ + if (tclass < current_mapping_size) { + unsigned i; + u32 kperm = 0; + + for (i = 0; i < current_mapping[tclass].num_perms; i++) + if (tperm & (1<allowed & current_mapping[tclass].perms[i]) + result |= 1<allowed = result; + + for (i = 0, result = 0; i < n; i++) + if (avd->auditallow & current_mapping[tclass].perms[i]) + result |= 1<auditallow = result; + + for (i = 0, result = 0; i < n; i++) { + if (avd->auditdeny & current_mapping[tclass].perms[i]) + result |= 1<auditdeny = result; + } +} + + /* * Return the boolean value of a constraint expression * when it is applied to the specified source and target @@ -467,7 +614,6 @@ static int context_struct_compute_av(struct context *scontext, struct class_datum *tclass_datum; struct ebitmap *sattr, *tattr; struct ebitmap_node *snode, *tnode; - const struct selinux_class_perm *kdefs = &selinux_class_perm; unsigned int i, j; /* @@ -477,9 +623,9 @@ static int context_struct_compute_av(struct context *scontext, * to remain in the correct class. */ if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS) - if (tclass >= SECCLASS_NETLINK_ROUTE_SOCKET && - tclass <= SECCLASS_NETLINK_DNRT_SOCKET) - tclass = SECCLASS_NETLINK_SOCKET; + if (tclass >= unmap_class(SECCLASS_NETLINK_ROUTE_SOCKET) && + tclass <= unmap_class(SECCLASS_NETLINK_DNRT_SOCKET)) + tclass = unmap_class(SECCLASS_NETLINK_SOCKET); /* * Initialize the access vectors to the default values. @@ -490,33 +636,11 @@ static int context_struct_compute_av(struct context *scontext, avd->seqno = latest_granting; avd->flags = 0; - /* - * Check for all the invalid cases. - * - tclass 0 - * - tclass > policy and > kernel - * - tclass > policy but is a userspace class - * - tclass > policy but we do not allow unknowns - */ - if (unlikely(!tclass)) - goto inval_class; - if (unlikely(tclass > policydb.p_classes.nprim)) - if (tclass > kdefs->cts_len || - !kdefs->class_to_string[tclass] || - !policydb.allow_unknown) - goto inval_class; - - /* - * Kernel class and we allow unknown so pad the allow decision - * the pad will be all 1 for unknown classes. - */ - if (tclass <= kdefs->cts_len && policydb.allow_unknown) - avd->allowed = policydb.undefined_perms[tclass - 1]; - - /* - * Not in policy. Since decision is completed (all 1 or all 0) return. - */ - if (unlikely(tclass > policydb.p_classes.nprim)) - return 0; + if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { + if (printk_ratelimit()) + printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass); + return -EINVAL; + } tclass_datum = policydb.class_val_to_struct[tclass - 1]; @@ -568,8 +692,8 @@ static int context_struct_compute_av(struct context *scontext, * role is changing, then check the (current_role, new_role) * pair. */ - if (tclass == SECCLASS_PROCESS && - (avd->allowed & (PROCESS__TRANSITION | PROCESS__DYNTRANSITION)) && + if (tclass == policydb.process_class && + (avd->allowed & policydb.process_trans_perms) && scontext->role != tcontext->role) { for (ra = policydb.role_allow; ra; ra = ra->next) { if (scontext->role == ra->role && @@ -577,8 +701,7 @@ static int context_struct_compute_av(struct context *scontext, break; } if (!ra) - avd->allowed &= ~(PROCESS__TRANSITION | - PROCESS__DYNTRANSITION); + avd->allowed &= ~policydb.process_trans_perms; } /* @@ -590,21 +713,6 @@ static int context_struct_compute_av(struct context *scontext, tclass, requested, avd); return 0; - -inval_class: - if (!tclass || tclass > kdefs->cts_len || - !kdefs->class_to_string[tclass]) { - if (printk_ratelimit()) - printk(KERN_ERR "SELinux: %s: unrecognized class %d\n", - __func__, tclass); - return -EINVAL; - } - - /* - * Known to the kernel, but not to the policy. - * Handle as a denial (allowed is 0). - */ - return 0; } static int security_validtrans_handle_fail(struct context *ocontext, @@ -636,13 +744,14 @@ out: } int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, - u16 tclass) + u16 orig_tclass) { struct context *ocontext; struct context *ncontext; struct context *tcontext; struct class_datum *tclass_datum; struct constraint_node *constraint; + u16 tclass; int rc = 0; if (!ss_initialized) @@ -650,6 +759,8 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, read_lock(&policy_rwlock); + tclass = unmap_class(orig_tclass); + /* * Remap extended Netlink classes for old policy versions. * Do this here rather than socket_type_to_security_class() @@ -657,9 +768,9 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, * to remain in the correct class. */ if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS) - if (tclass >= SECCLASS_NETLINK_ROUTE_SOCKET && - tclass <= SECCLASS_NETLINK_DNRT_SOCKET) - tclass = SECCLASS_NETLINK_SOCKET; + if (tclass >= unmap_class(SECCLASS_NETLINK_ROUTE_SOCKET) && + tclass <= unmap_class(SECCLASS_NETLINK_DNRT_SOCKET)) + tclass = unmap_class(SECCLASS_NETLINK_SOCKET); if (!tclass || tclass > policydb.p_classes.nprim) { printk(KERN_ERR "SELinux: %s: unrecognized class %d\n", @@ -792,6 +903,38 @@ out: } +static int security_compute_av_core(u32 ssid, + u32 tsid, + u16 tclass, + u32 requested, + struct av_decision *avd) +{ + struct context *scontext = NULL, *tcontext = NULL; + int rc = 0; + + scontext = sidtab_search(&sidtab, ssid); + if (!scontext) { + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, ssid); + return -EINVAL; + } + tcontext = sidtab_search(&sidtab, tsid); + if (!tcontext) { + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, tsid); + return -EINVAL; + } + + rc = context_struct_compute_av(scontext, tcontext, tclass, + requested, avd); + + /* permissive domain? */ + if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) + avd->flags |= AVD_FLAGS_PERMISSIVE; + + return rc; +} + /** * security_compute_av - Compute access vector decisions. * @ssid: source security identifier @@ -807,12 +950,45 @@ out: */ int security_compute_av(u32 ssid, u32 tsid, - u16 tclass, - u32 requested, + u16 orig_tclass, + u32 orig_requested, struct av_decision *avd) { - struct context *scontext = NULL, *tcontext = NULL; - int rc = 0; + u16 tclass; + u32 requested; + int rc; + + if (!ss_initialized) + goto allow; + + read_lock(&policy_rwlock); + requested = unmap_perm(orig_tclass, orig_requested); + tclass = unmap_class(orig_tclass); + if (unlikely(orig_tclass && !tclass)) { + if (policydb.allow_unknown) + goto allow; + return -EINVAL; + } + rc = security_compute_av_core(ssid, tsid, tclass, requested, avd); + map_decision(orig_tclass, avd, policydb.allow_unknown); + read_unlock(&policy_rwlock); + return rc; +allow: + avd->allowed = 0xffffffff; + avd->auditallow = 0; + avd->auditdeny = 0xffffffff; + avd->seqno = latest_granting; + avd->flags = 0; + return 0; +} + +int security_compute_av_user(u32 ssid, + u32 tsid, + u16 tclass, + u32 requested, + struct av_decision *avd) +{ + int rc; if (!ss_initialized) { avd->allowed = 0xffffffff; @@ -823,29 +999,7 @@ int security_compute_av(u32 ssid, } read_lock(&policy_rwlock); - - scontext = sidtab_search(&sidtab, ssid); - if (!scontext) { - printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", - __func__, ssid); - rc = -EINVAL; - goto out; - } - tcontext = sidtab_search(&sidtab, tsid); - if (!tcontext) { - printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", - __func__, tsid); - rc = -EINVAL; - goto out; - } - - rc = context_struct_compute_av(scontext, tcontext, tclass, - requested, avd); - - /* permissive domain? */ - if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) - avd->flags |= AVD_FLAGS_PERMISSIVE; -out: + rc = security_compute_av_core(ssid, tsid, tclass, requested, avd); read_unlock(&policy_rwlock); return rc; } @@ -1204,20 +1358,22 @@ out: static int security_compute_sid(u32 ssid, u32 tsid, - u16 tclass, + u16 orig_tclass, u32 specified, - u32 *out_sid) + u32 *out_sid, + bool kern) { struct context *scontext = NULL, *tcontext = NULL, newcontext; struct role_trans *roletr = NULL; struct avtab_key avkey; struct avtab_datum *avdatum; struct avtab_node *node; + u16 tclass; int rc = 0; if (!ss_initialized) { - switch (tclass) { - case SECCLASS_PROCESS: + switch (orig_tclass) { + case SECCLASS_PROCESS: /* kernel value */ *out_sid = ssid; break; default: @@ -1231,6 +1387,11 @@ static int security_compute_sid(u32 ssid, read_lock(&policy_rwlock); + if (kern) + tclass = unmap_class(orig_tclass); + else + tclass = orig_tclass; + scontext = sidtab_search(&sidtab, ssid); if (!scontext) { printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", @@ -1260,13 +1421,11 @@ static int security_compute_sid(u32 ssid, } /* Set the role and type to default values. */ - switch (tclass) { - case SECCLASS_PROCESS: + if (tclass == policydb.process_class) { /* Use the current role and type of process. */ newcontext.role = scontext->role; newcontext.type = scontext->type; - break; - default: + } else { /* Use the well-defined object role. */ newcontext.role = OBJECT_R_VAL; /* Use the type of the related object. */ @@ -1297,8 +1456,7 @@ static int security_compute_sid(u32 ssid, } /* Check for class-specific changes. */ - switch (tclass) { - case SECCLASS_PROCESS: + if (tclass == policydb.process_class) { if (specified & AVTAB_TRANSITION) { /* Look for a role transition rule. */ for (roletr = policydb.role_tr; roletr; @@ -1311,9 +1469,6 @@ static int security_compute_sid(u32 ssid, } } } - break; - default: - break; } /* Set the MLS attributes. @@ -1358,7 +1513,17 @@ int security_transition_sid(u32 ssid, u16 tclass, u32 *out_sid) { - return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid); + return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, + out_sid, true); +} + +int security_transition_sid_user(u32 ssid, + u32 tsid, + u16 tclass, + u32 *out_sid) +{ + return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, + out_sid, false); } /** @@ -1379,7 +1544,8 @@ int security_member_sid(u32 ssid, u16 tclass, u32 *out_sid) { - return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid); + return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid, + false); } /** @@ -1400,144 +1566,8 @@ int security_change_sid(u32 ssid, u16 tclass, u32 *out_sid) { - return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid); -} - -/* - * Verify that each kernel class that is defined in the - * policy is correct - */ -static int validate_classes(struct policydb *p) -{ - int i, j; - struct class_datum *cladatum; - struct perm_datum *perdatum; - u32 nprim, tmp, common_pts_len, perm_val, pol_val; - u16 class_val; - const struct selinux_class_perm *kdefs = &selinux_class_perm; - const char *def_class, *def_perm, *pol_class; - struct symtab *perms; - bool print_unknown_handle = 0; - - if (p->allow_unknown) { - u32 num_classes = kdefs->cts_len; - p->undefined_perms = kcalloc(num_classes, sizeof(u32), GFP_KERNEL); - if (!p->undefined_perms) - return -ENOMEM; - } - - for (i = 1; i < kdefs->cts_len; i++) { - def_class = kdefs->class_to_string[i]; - if (!def_class) - continue; - if (i > p->p_classes.nprim) { - printk(KERN_INFO - "SELinux: class %s not defined in policy\n", - def_class); - if (p->reject_unknown) - return -EINVAL; - if (p->allow_unknown) - p->undefined_perms[i-1] = ~0U; - print_unknown_handle = 1; - continue; - } - pol_class = p->p_class_val_to_name[i-1]; - if (strcmp(pol_class, def_class)) { - printk(KERN_ERR - "SELinux: class %d is incorrect, found %s but should be %s\n", - i, pol_class, def_class); - return -EINVAL; - } - } - for (i = 0; i < kdefs->av_pts_len; i++) { - class_val = kdefs->av_perm_to_string[i].tclass; - perm_val = kdefs->av_perm_to_string[i].value; - def_perm = kdefs->av_perm_to_string[i].name; - if (class_val > p->p_classes.nprim) - continue; - pol_class = p->p_class_val_to_name[class_val-1]; - cladatum = hashtab_search(p->p_classes.table, pol_class); - BUG_ON(!cladatum); - perms = &cladatum->permissions; - nprim = 1 << (perms->nprim - 1); - if (perm_val > nprim) { - printk(KERN_INFO - "SELinux: permission %s in class %s not defined in policy\n", - def_perm, pol_class); - if (p->reject_unknown) - return -EINVAL; - if (p->allow_unknown) - p->undefined_perms[class_val-1] |= perm_val; - print_unknown_handle = 1; - continue; - } - perdatum = hashtab_search(perms->table, def_perm); - if (perdatum == NULL) { - printk(KERN_ERR - "SELinux: permission %s in class %s not found in policy, bad policy\n", - def_perm, pol_class); - return -EINVAL; - } - pol_val = 1 << (perdatum->value - 1); - if (pol_val != perm_val) { - printk(KERN_ERR - "SELinux: permission %s in class %s has incorrect value\n", - def_perm, pol_class); - return -EINVAL; - } - } - for (i = 0; i < kdefs->av_inherit_len; i++) { - class_val = kdefs->av_inherit[i].tclass; - if (class_val > p->p_classes.nprim) - continue; - pol_class = p->p_class_val_to_name[class_val-1]; - cladatum = hashtab_search(p->p_classes.table, pol_class); - BUG_ON(!cladatum); - if (!cladatum->comdatum) { - printk(KERN_ERR - "SELinux: class %s should have an inherits clause but does not\n", - pol_class); - return -EINVAL; - } - tmp = kdefs->av_inherit[i].common_base; - common_pts_len = 0; - while (!(tmp & 0x01)) { - common_pts_len++; - tmp >>= 1; - } - perms = &cladatum->comdatum->permissions; - for (j = 0; j < common_pts_len; j++) { - def_perm = kdefs->av_inherit[i].common_pts[j]; - if (j >= perms->nprim) { - printk(KERN_INFO - "SELinux: permission %s in class %s not defined in policy\n", - def_perm, pol_class); - if (p->reject_unknown) - return -EINVAL; - if (p->allow_unknown) - p->undefined_perms[class_val-1] |= (1 << j); - print_unknown_handle = 1; - continue; - } - perdatum = hashtab_search(perms->table, def_perm); - if (perdatum == NULL) { - printk(KERN_ERR - "SELinux: permission %s in class %s not found in policy, bad policy\n", - def_perm, pol_class); - return -EINVAL; - } - if (perdatum->value != j + 1) { - printk(KERN_ERR - "SELinux: permission %s in class %s has incorrect value\n", - def_perm, pol_class); - return -EINVAL; - } - } - } - if (print_unknown_handle) - printk(KERN_INFO "SELinux: the above unknown classes and permissions will be %s\n", - (security_get_allow_unknown() ? "allowed" : "denied")); - return 0; + return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid, + false); } /* Clone the SID into the new SID table. */ @@ -1710,8 +1740,10 @@ int security_load_policy(void *data, size_t len) { struct policydb oldpolicydb, newpolicydb; struct sidtab oldsidtab, newsidtab; + struct selinux_mapping *oldmap, *map = NULL; struct convert_context_args args; u32 seqno; + u16 map_size; int rc = 0; struct policy_file file = { data, len }, *fp = &file; @@ -1721,16 +1753,14 @@ int security_load_policy(void *data, size_t len) avtab_cache_destroy(); return -EINVAL; } - if (policydb_load_isids(&policydb, &sidtab)) { + if (selinux_set_mapping(&policydb, secclass_map, + ¤t_mapping, + ¤t_mapping_size)) { policydb_destroy(&policydb); avtab_cache_destroy(); return -EINVAL; } - /* Verify that the kernel defined classes are correct. */ - if (validate_classes(&policydb)) { - printk(KERN_ERR - "SELinux: the definition of a class is incorrect\n"); - sidtab_destroy(&sidtab); + if (policydb_load_isids(&policydb, &sidtab)) { policydb_destroy(&policydb); avtab_cache_destroy(); return -EINVAL; @@ -1759,13 +1789,9 @@ int security_load_policy(void *data, size_t len) return -ENOMEM; } - /* Verify that the kernel defined classes are correct. */ - if (validate_classes(&newpolicydb)) { - printk(KERN_ERR - "SELinux: the definition of a class is incorrect\n"); - rc = -EINVAL; + if (selinux_set_mapping(&newpolicydb, secclass_map, + &map, &map_size)) goto err; - } rc = security_preserve_bools(&newpolicydb); if (rc) { @@ -1799,6 +1825,9 @@ int security_load_policy(void *data, size_t len) memcpy(&policydb, &newpolicydb, sizeof policydb); sidtab_set(&sidtab, &newsidtab); security_load_policycaps(); + oldmap = current_mapping; + current_mapping = map; + current_mapping_size = map_size; seqno = ++latest_granting; policydb_loaded_version = policydb.policyvers; write_unlock_irq(&policy_rwlock); @@ -1806,6 +1835,7 @@ int security_load_policy(void *data, size_t len) /* Free the old policydb and SID table. */ policydb_destroy(&oldpolicydb); sidtab_destroy(&oldsidtab); + kfree(oldmap); avc_ss_reset(seqno); selnl_notify_policyload(seqno); @@ -1815,6 +1845,7 @@ int security_load_policy(void *data, size_t len) return 0; err: + kfree(map); sidtab_destroy(&newsidtab); policydb_destroy(&newpolicydb); return rc; @@ -2091,7 +2122,7 @@ out_unlock: } for (i = 0, j = 0; i < mynel; i++) { rc = avc_has_perm_noaudit(fromsid, mysids[i], - SECCLASS_PROCESS, + SECCLASS_PROCESS, /* kernel value */ PROCESS__TRANSITION, AVC_STRICT, NULL); if (!rc) @@ -2119,10 +2150,11 @@ out: */ int security_genfs_sid(const char *fstype, char *path, - u16 sclass, + u16 orig_sclass, u32 *sid) { int len; + u16 sclass; struct genfs *genfs; struct ocontext *c; int rc = 0, cmp = 0; @@ -2132,6 +2164,8 @@ int security_genfs_sid(const char *fstype, read_lock(&policy_rwlock); + sclass = unmap_class(orig_sclass); + for (genfs = policydb.genfs; genfs; genfs = genfs->next) { cmp = strcmp(fstype, genfs->fstype); if (cmp <= 0) From 8753f6bec352392b52ed9b5e290afb34379f4612 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Wed, 30 Sep 2009 13:41:02 -0400 Subject: [PATCH 014/298] selinux: generate flask headers during kernel build Add a simple utility (scripts/selinux/genheaders) and invoke it to generate the kernel-private class and permission indices in flask.h and av_permissions.h automatically during the kernel build from the security class mapping definitions in classmap.h. Adding new kernel classes and permissions can then be done just by adding them to classmap.h. Signed-off-by: Stephen Smalley Signed-off-by: James Morris --- scripts/selinux/Makefile | 4 +- scripts/selinux/genheaders/Makefile | 5 + scripts/selinux/genheaders/genheaders.c | 118 +++ security/selinux/Makefile | 10 +- security/selinux/include/av_permissions.h | 870 ---------------------- security/selinux/include/flask.h | 91 --- security/selinux/ss/Makefile | 2 +- 7 files changed, 135 insertions(+), 965 deletions(-) create mode 100644 scripts/selinux/genheaders/Makefile create mode 100644 scripts/selinux/genheaders/genheaders.c delete mode 100644 security/selinux/include/av_permissions.h delete mode 100644 security/selinux/include/flask.h diff --git a/scripts/selinux/Makefile b/scripts/selinux/Makefile index ca4b1ec0182..e8049da1831 100644 --- a/scripts/selinux/Makefile +++ b/scripts/selinux/Makefile @@ -1,2 +1,2 @@ -subdir-y := mdp -subdir- += mdp +subdir-y := mdp genheaders +subdir- += mdp genheaders diff --git a/scripts/selinux/genheaders/Makefile b/scripts/selinux/genheaders/Makefile new file mode 100644 index 00000000000..417b165008e --- /dev/null +++ b/scripts/selinux/genheaders/Makefile @@ -0,0 +1,5 @@ +hostprogs-y := genheaders +HOST_EXTRACFLAGS += -Isecurity/selinux/include + +always := $(hostprogs-y) +clean-files := $(hostprogs-y) diff --git a/scripts/selinux/genheaders/genheaders.c b/scripts/selinux/genheaders/genheaders.c new file mode 100644 index 00000000000..3b16145dabe --- /dev/null +++ b/scripts/selinux/genheaders/genheaders.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include +#include +#include + +struct security_class_mapping { + const char *name; + const char *perms[sizeof(unsigned) * 8 + 1]; +}; + +#include "classmap.h" +#include "initial_sid_to_string.h" + +#define max(x, y) ((x > y) ? x : y) + +const char *progname; + +void usage(void) +{ + printf("usage: %s flask.h av_permissions.h\n", progname); + exit(1); +} + +char *stoupperx(const char *s) +{ + char *s2 = strdup(s); + char *p; + + if (!s2) { + fprintf(stderr, "%s: out of memory\n", progname); + exit(3); + } + + for (p = s2; *p; p++) + *p = toupper(*p); + return s2; +} + +int main(int argc, char *argv[]) +{ + int i, j, k; + int isids_len; + FILE *fout; + + progname = argv[0]; + + if (argc < 3) + usage(); + + fout = fopen(argv[1], "w"); + if (!fout) { + fprintf(stderr, "Could not open %s for writing: %s\n", + argv[1], strerror(errno)); + exit(2); + } + + for (i = 0; secclass_map[i].name; i++) { + struct security_class_mapping *map = &secclass_map[i]; + map->name = stoupperx(map->name); + for (j = 0; map->perms[j]; j++) + map->perms[j] = stoupperx(map->perms[j]); + } + + isids_len = sizeof(initial_sid_to_string) / sizeof (char *); + for (i = 1; i < isids_len; i++) + initial_sid_to_string[i] = stoupperx(initial_sid_to_string[i]); + + fprintf(fout, "/* This file is automatically generated. Do not edit. */\n"); + fprintf(fout, "#ifndef _SELINUX_FLASK_H_\n#define _SELINUX_FLASK_H_\n\n"); + + for (i = 0; secclass_map[i].name; i++) { + struct security_class_mapping *map = &secclass_map[i]; + fprintf(fout, "#define SECCLASS_%s", map->name); + for (j = 0; j < max(1, 40 - strlen(map->name)); j++) + fprintf(fout, " "); + fprintf(fout, "%2d\n", i+1); + } + + fprintf(fout, "\n"); + + for (i = 1; i < isids_len; i++) { + char *s = initial_sid_to_string[i]; + fprintf(fout, "#define SECINITSID_%s", s); + for (j = 0; j < max(1, 40 - strlen(s)); j++) + fprintf(fout, " "); + fprintf(fout, "%2d\n", i); + } + fprintf(fout, "\n#define SECINITSID_NUM %d\n", i-1); + fprintf(fout, "\n#endif\n"); + fclose(fout); + + fout = fopen(argv[2], "w"); + if (!fout) { + fprintf(stderr, "Could not open %s for writing: %s\n", + argv[2], strerror(errno)); + exit(4); + } + + fprintf(fout, "/* This file is automatically generated. Do not edit. */\n"); + fprintf(fout, "#ifndef _SELINUX_AV_PERMISSIONS_H_\n#define _SELINUX_AV_PERMISSIONS_H_\n\n"); + + for (i = 0; secclass_map[i].name; i++) { + struct security_class_mapping *map = &secclass_map[i]; + for (j = 0; map->perms[j]; j++) { + fprintf(fout, "#define %s__%s", map->name, + map->perms[j]); + for (k = 0; k < max(1, 40 - strlen(map->name) - strlen(map->perms[j])); k++) + fprintf(fout, " "); + fprintf(fout, "0x%08xUL\n", (1< Date: Thu, 1 Oct 2009 14:48:23 -0400 Subject: [PATCH 015/298] selinux: drop remapping of netlink classes Drop remapping of netlink classes and bypass of permission checking based on netlink message type for policy version < 18. This removes compatibility code introduced when the original single netlink security class used for all netlink sockets was split into finer-grained netlink classes based on netlink protocol and when permission checking was added based on netlink message type in Linux 2.6.8. The only known distribution that shipped with SELinux and policy < 18 was Fedora Core 2, which was EOL'd on 2005-04-11. Given that the remapping code was never updated to address the addition of newer netlink classes, that the corresponding userland support was dropped in 2005, and that the assumptions made by the remapping code about the fixed ordering among netlink classes in the policy may be violated in the future due to the dynamic class/perm discovery support, we should drop this compatibility code now. Signed-off-by: Stephen Smalley Signed-off-by: James Morris --- security/selinux/hooks.c | 6 +----- security/selinux/ss/services.c | 25 ------------------------- 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a985d0bc59b..a29d6612a32 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -91,7 +91,6 @@ #define NUM_SEL_MNT_OPTS 5 -extern unsigned int policydb_loaded_version; extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); extern struct security_operations *security_ops; @@ -4714,10 +4713,7 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) if (err) return err; - if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS) - err = selinux_nlmsg_perm(sk, skb); - - return err; + return selinux_nlmsg_perm(sk, skb); } static int selinux_netlink_recv(struct sk_buff *skb, int capability) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index e19baa81fde..f270e378c0e 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -65,7 +65,6 @@ #include "audit.h" extern void selnl_notify_policyload(u32 seqno); -unsigned int policydb_loaded_version; int selinux_policycap_netpeer; int selinux_policycap_openperm; @@ -616,17 +615,6 @@ static int context_struct_compute_av(struct context *scontext, struct ebitmap_node *snode, *tnode; unsigned int i, j; - /* - * Remap extended Netlink classes for old policy versions. - * Do this here rather than socket_type_to_security_class() - * in case a newer policy version is loaded, allowing sockets - * to remain in the correct class. - */ - if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS) - if (tclass >= unmap_class(SECCLASS_NETLINK_ROUTE_SOCKET) && - tclass <= unmap_class(SECCLASS_NETLINK_DNRT_SOCKET)) - tclass = unmap_class(SECCLASS_NETLINK_SOCKET); - /* * Initialize the access vectors to the default values. */ @@ -761,17 +749,6 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, tclass = unmap_class(orig_tclass); - /* - * Remap extended Netlink classes for old policy versions. - * Do this here rather than socket_type_to_security_class() - * in case a newer policy version is loaded, allowing sockets - * to remain in the correct class. - */ - if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS) - if (tclass >= unmap_class(SECCLASS_NETLINK_ROUTE_SOCKET) && - tclass <= unmap_class(SECCLASS_NETLINK_DNRT_SOCKET)) - tclass = unmap_class(SECCLASS_NETLINK_SOCKET); - if (!tclass || tclass > policydb.p_classes.nprim) { printk(KERN_ERR "SELinux: %s: unrecognized class %d\n", __func__, tclass); @@ -1766,7 +1743,6 @@ int security_load_policy(void *data, size_t len) return -EINVAL; } security_load_policycaps(); - policydb_loaded_version = policydb.policyvers; ss_initialized = 1; seqno = ++latest_granting; selinux_complete_init(); @@ -1829,7 +1805,6 @@ int security_load_policy(void *data, size_t len) current_mapping = map; current_mapping_size = map_size; seqno = ++latest_granting; - policydb_loaded_version = policydb.policyvers; write_unlock_irq(&policy_rwlock); /* Free the old policydb and SID table. */ From 89eda06837094ce9f34fae269b8773fcfd70f046 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sun, 4 Oct 2009 21:49:47 +0900 Subject: [PATCH 016/298] LSM: Add security_path_chmod() and security_path_chown(). This patch allows pathname based LSM modules to check chmod()/chown() operations. Since notify_change() does not receive "struct vfsmount *", we add security_path_chmod() and security_path_chown() to the caller of notify_change(). These hooks are used by TOMOYO. Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- fs/open.c | 24 ++++++++++++++++++++---- include/linux/security.h | 30 ++++++++++++++++++++++++++++++ security/capability.c | 13 +++++++++++++ security/security.c | 15 +++++++++++++++ 4 files changed, 78 insertions(+), 4 deletions(-) diff --git a/fs/open.c b/fs/open.c index 4f01e06227c..b5c294d35bd 100644 --- a/fs/open.c +++ b/fs/open.c @@ -616,6 +616,9 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode) err = mnt_want_write_file(file); if (err) goto out_putf; + err = security_path_chmod(dentry, file->f_vfsmnt, mode); + if (err) + goto out_drop_write; mutex_lock(&inode->i_mutex); if (mode == (mode_t) -1) mode = inode->i_mode; @@ -623,6 +626,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode) newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; err = notify_change(dentry, &newattrs); mutex_unlock(&inode->i_mutex); +out_drop_write: mnt_drop_write(file->f_path.mnt); out_putf: fput(file); @@ -645,6 +649,9 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode) error = mnt_want_write(path.mnt); if (error) goto dput_and_out; + error = security_path_chmod(path.dentry, path.mnt, mode); + if (error) + goto out_drop_write; mutex_lock(&inode->i_mutex); if (mode == (mode_t) -1) mode = inode->i_mode; @@ -652,6 +659,7 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode) newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; error = notify_change(path.dentry, &newattrs); mutex_unlock(&inode->i_mutex); +out_drop_write: mnt_drop_write(path.mnt); dput_and_out: path_put(&path); @@ -700,7 +708,9 @@ SYSCALL_DEFINE3(chown, const char __user *, filename, uid_t, user, gid_t, group) error = mnt_want_write(path.mnt); if (error) goto out_release; - error = chown_common(path.dentry, user, group); + error = security_path_chown(&path, user, group); + if (!error) + error = chown_common(path.dentry, user, group); mnt_drop_write(path.mnt); out_release: path_put(&path); @@ -725,7 +735,9 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user, error = mnt_want_write(path.mnt); if (error) goto out_release; - error = chown_common(path.dentry, user, group); + error = security_path_chown(&path, user, group); + if (!error) + error = chown_common(path.dentry, user, group); mnt_drop_write(path.mnt); out_release: path_put(&path); @@ -744,7 +756,9 @@ SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group error = mnt_want_write(path.mnt); if (error) goto out_release; - error = chown_common(path.dentry, user, group); + error = security_path_chown(&path, user, group); + if (!error) + error = chown_common(path.dentry, user, group); mnt_drop_write(path.mnt); out_release: path_put(&path); @@ -767,7 +781,9 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) goto out_fput; dentry = file->f_path.dentry; audit_inode(NULL, dentry); - error = chown_common(dentry, user, group); + error = security_path_chown(&file->f_path, user, group); + if (!error) + error = chown_common(dentry, user, group); mnt_drop_write(file->f_path.mnt); out_fput: fput(file); diff --git a/include/linux/security.h b/include/linux/security.h index 239e40d0450..c8a584c26f7 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -447,6 +447,18 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @new_dir contains the path structure for parent of the new link. * @new_dentry contains the dentry structure of the new link. * Return 0 if permission is granted. + * @path_chmod: + * Check for permission to change DAC's permission of a file or directory. + * @dentry contains the dentry structure. + * @mnt contains the vfsmnt structure. + * @mode contains DAC's mode. + * Return 0 if permission is granted. + * @path_chown: + * Check for permission to change owner/group of a file or directory. + * @path contains the path structure. + * @uid contains new owner's ID. + * @gid contains new group's ID. + * Return 0 if permission is granted. * @inode_readlink: * Check the permission to read the symbolic link. * @dentry contains the dentry structure for the file link. @@ -1488,6 +1500,9 @@ struct security_operations { struct dentry *new_dentry); int (*path_rename) (struct path *old_dir, struct dentry *old_dentry, struct path *new_dir, struct dentry *new_dentry); + int (*path_chmod) (struct dentry *dentry, struct vfsmount *mnt, + mode_t mode); + int (*path_chown) (struct path *path, uid_t uid, gid_t gid); #endif int (*inode_alloc_security) (struct inode *inode); @@ -2952,6 +2967,9 @@ int security_path_link(struct dentry *old_dentry, struct path *new_dir, struct dentry *new_dentry); int security_path_rename(struct path *old_dir, struct dentry *old_dentry, struct path *new_dir, struct dentry *new_dentry); +int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt, + mode_t mode); +int security_path_chown(struct path *path, uid_t uid, gid_t gid); #else /* CONFIG_SECURITY_PATH */ static inline int security_path_unlink(struct path *dir, struct dentry *dentry) { @@ -3001,6 +3019,18 @@ static inline int security_path_rename(struct path *old_dir, { return 0; } + +static inline int security_path_chmod(struct dentry *dentry, + struct vfsmount *mnt, + mode_t mode) +{ + return 0; +} + +static inline int security_path_chown(struct path *path, uid_t uid, gid_t gid) +{ + return 0; +} #endif /* CONFIG_SECURITY_PATH */ #ifdef CONFIG_KEYS diff --git a/security/capability.c b/security/capability.c index fce07a7bc82..09279a8d4a1 100644 --- a/security/capability.c +++ b/security/capability.c @@ -308,6 +308,17 @@ static int cap_path_truncate(struct path *path, loff_t length, { return 0; } + +static int cap_path_chmod(struct dentry *dentry, struct vfsmount *mnt, + mode_t mode) +{ + return 0; +} + +static int cap_path_chown(struct path *path, uid_t uid, gid_t gid) +{ + return 0; +} #endif static int cap_file_permission(struct file *file, int mask) @@ -977,6 +988,8 @@ void security_fixup_ops(struct security_operations *ops) set_to_cap_if_null(ops, path_link); set_to_cap_if_null(ops, path_rename); set_to_cap_if_null(ops, path_truncate); + set_to_cap_if_null(ops, path_chmod); + set_to_cap_if_null(ops, path_chown); #endif set_to_cap_if_null(ops, file_permission); set_to_cap_if_null(ops, file_alloc_security); diff --git a/security/security.c b/security/security.c index c4c673240c1..5259270e558 100644 --- a/security/security.c +++ b/security/security.c @@ -434,6 +434,21 @@ int security_path_truncate(struct path *path, loff_t length, return 0; return security_ops->path_truncate(path, length, time_attrs); } + +int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt, + mode_t mode) +{ + if (unlikely(IS_PRIVATE(dentry->d_inode))) + return 0; + return security_ops->path_chmod(dentry, mnt, mode); +} + +int security_path_chown(struct path *path, uid_t uid, gid_t gid) +{ + if (unlikely(IS_PRIVATE(path->dentry->d_inode))) + return 0; + return security_ops->path_chown(path, uid, gid); +} #endif int security_inode_create(struct inode *dir, struct dentry *dentry, int mode) From 8b8efb44033c7e86b3dc76f825c693ec92ae30e9 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sun, 4 Oct 2009 21:49:48 +0900 Subject: [PATCH 017/298] LSM: Add security_path_chroot(). This patch allows pathname based LSM modules to check chroot() operations. This hook is used by TOMOYO. Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- fs/open.c | 3 +++ include/linux/security.h | 11 +++++++++++ security/capability.c | 6 ++++++ security/security.c | 5 +++++ 4 files changed, 25 insertions(+) diff --git a/fs/open.c b/fs/open.c index b5c294d35bd..201041dfca5 100644 --- a/fs/open.c +++ b/fs/open.c @@ -587,6 +587,9 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename) error = -EPERM; if (!capable(CAP_SYS_CHROOT)) goto dput_and_out; + error = security_path_chroot(&path); + if (error) + goto dput_and_out; set_fs_root(current->fs, &path); error = 0; diff --git a/include/linux/security.h b/include/linux/security.h index c8a584c26f7..ed0faea60b8 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -459,6 +459,10 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @uid contains new owner's ID. * @gid contains new group's ID. * Return 0 if permission is granted. + * @path_chroot: + * Check for permission to change root directory. + * @path contains the path structure. + * Return 0 if permission is granted. * @inode_readlink: * Check the permission to read the symbolic link. * @dentry contains the dentry structure for the file link. @@ -1503,6 +1507,7 @@ struct security_operations { int (*path_chmod) (struct dentry *dentry, struct vfsmount *mnt, mode_t mode); int (*path_chown) (struct path *path, uid_t uid, gid_t gid); + int (*path_chroot) (struct path *path); #endif int (*inode_alloc_security) (struct inode *inode); @@ -2970,6 +2975,7 @@ int security_path_rename(struct path *old_dir, struct dentry *old_dentry, int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt, mode_t mode); int security_path_chown(struct path *path, uid_t uid, gid_t gid); +int security_path_chroot(struct path *path); #else /* CONFIG_SECURITY_PATH */ static inline int security_path_unlink(struct path *dir, struct dentry *dentry) { @@ -3031,6 +3037,11 @@ static inline int security_path_chown(struct path *path, uid_t uid, gid_t gid) { return 0; } + +static inline int security_path_chroot(struct path *path) +{ + return 0; +} #endif /* CONFIG_SECURITY_PATH */ #ifdef CONFIG_KEYS diff --git a/security/capability.c b/security/capability.c index 09279a8d4a1..4f3ab476937 100644 --- a/security/capability.c +++ b/security/capability.c @@ -319,6 +319,11 @@ static int cap_path_chown(struct path *path, uid_t uid, gid_t gid) { return 0; } + +static int cap_path_chroot(struct path *root) +{ + return 0; +} #endif static int cap_file_permission(struct file *file, int mask) @@ -990,6 +995,7 @@ void security_fixup_ops(struct security_operations *ops) set_to_cap_if_null(ops, path_truncate); set_to_cap_if_null(ops, path_chmod); set_to_cap_if_null(ops, path_chown); + set_to_cap_if_null(ops, path_chroot); #endif set_to_cap_if_null(ops, file_permission); set_to_cap_if_null(ops, file_alloc_security); diff --git a/security/security.c b/security/security.c index 5259270e558..279757314a0 100644 --- a/security/security.c +++ b/security/security.c @@ -449,6 +449,11 @@ int security_path_chown(struct path *path, uid_t uid, gid_t gid) return 0; return security_ops->path_chown(path, uid, gid); } + +int security_path_chroot(struct path *path) +{ + return security_ops->path_chroot(path); +} #endif int security_inode_create(struct inode *dir, struct dentry *dentry, int mode) From a27ab9f26b729326778271c1efd895aef4fda1c4 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sun, 4 Oct 2009 21:49:49 +0900 Subject: [PATCH 018/298] LSM: Pass original mount flags to security_sb_mount(). This patch allows LSM modules to determine based on original mount flags passed to mount(). A LSM module can get masked mount flags (if needed) by flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT | MS_STRICTATIME); Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- fs/namespace.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index bdc3cb4fd22..7d70d63ceb2 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1921,6 +1921,16 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, if (data_page) ((char *)data_page)[PAGE_SIZE - 1] = 0; + /* ... and get the mountpoint */ + retval = kern_path(dir_name, LOOKUP_FOLLOW, &path); + if (retval) + return retval; + + retval = security_sb_mount(dev_name, &path, + type_page, flags, data_page); + if (retval) + goto dput_out; + /* Default to relatime unless overriden */ if (!(flags & MS_NOATIME)) mnt_flags |= MNT_RELATIME; @@ -1945,16 +1955,6 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT | MS_STRICTATIME); - /* ... and get the mountpoint */ - retval = kern_path(dir_name, LOOKUP_FOLLOW, &path); - if (retval) - return retval; - - retval = security_sb_mount(dev_name, &path, - type_page, flags, data_page); - if (retval) - goto dput_out; - if (flags & MS_REMOUNT) retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags, data_page); From 3bb258bf430d29a24350fe4f44f8bf07b7b7a8f6 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 4 Oct 2009 17:53:29 -0700 Subject: [PATCH 019/298] ftrace.c: Add #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - Remove prefixes from pr_, use pr_fmt(fmt). No change in output. Signed-off-by: Joe Perches Acked-by: Steven Rostedt Cc: Frederic Weisbecker LKML-Reference: <9b377eefae9e28c599dd4a17bdc81172965e9931.1254701151.git.joe@perches.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/ftrace.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 9dbb527e165..25e6f5fc4b1 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -9,6 +9,8 @@ * the dangers of modifying code on the run. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -336,15 +338,15 @@ int __init ftrace_dyn_arch_init(void *data) switch (faulted) { case 0: - pr_info("ftrace: converting mcount calls to 0f 1f 44 00 00\n"); + pr_info("converting mcount calls to 0f 1f 44 00 00\n"); memcpy(ftrace_nop, ftrace_test_p6nop, MCOUNT_INSN_SIZE); break; case 1: - pr_info("ftrace: converting mcount calls to 66 66 66 66 90\n"); + pr_info("converting mcount calls to 66 66 66 66 90\n"); memcpy(ftrace_nop, ftrace_test_nop5, MCOUNT_INSN_SIZE); break; case 2: - pr_info("ftrace: converting mcount calls to jmp . + 5\n"); + pr_info("converting mcount calls to jmp . + 5\n"); memcpy(ftrace_nop, ftrace_test_jmp, MCOUNT_INSN_SIZE); break; } From 3c355863fb32070a2800f41106519c5c3038623a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 4 Oct 2009 17:53:40 -0700 Subject: [PATCH 020/298] testmmiotrace.c: Add and use pr_fmt(fmt) - Add #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt. - Strip MODULE_NAME from pr_s. - Remove MODULE_NAME definition. Signed-off-by: Joe Perches LKML-Reference: <3bb66cc7f85f77b9416902e1be7076f7e3f4ad48.1254701151.git.joe@perches.com> Signed-off-by: Ingo Molnar --- arch/x86/mm/testmmiotrace.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/arch/x86/mm/testmmiotrace.c b/arch/x86/mm/testmmiotrace.c index 427fd1b56df..8565d944f7c 100644 --- a/arch/x86/mm/testmmiotrace.c +++ b/arch/x86/mm/testmmiotrace.c @@ -1,12 +1,13 @@ /* * Written by Pekka Paalanen, 2008-2009 */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include -#define MODULE_NAME "testmmiotrace" - static unsigned long mmio_address; module_param(mmio_address, ulong, 0); MODULE_PARM_DESC(mmio_address, " Start address of the mapping of 16 kB " @@ -30,7 +31,7 @@ static unsigned v32(unsigned i) static void do_write_test(void __iomem *p) { unsigned int i; - pr_info(MODULE_NAME ": write test.\n"); + pr_info("write test.\n"); mmiotrace_printk("Write test.\n"); for (i = 0; i < 256; i++) @@ -47,7 +48,7 @@ static void do_read_test(void __iomem *p) { unsigned int i; unsigned errs[3] = { 0 }; - pr_info(MODULE_NAME ": read test.\n"); + pr_info("read test.\n"); mmiotrace_printk("Read test.\n"); for (i = 0; i < 256; i++) @@ -68,7 +69,7 @@ static void do_read_test(void __iomem *p) static void do_read_far_test(void __iomem *p) { - pr_info(MODULE_NAME ": read far test.\n"); + pr_info("read far test.\n"); mmiotrace_printk("Read far test.\n"); ioread32(p + read_far); @@ -78,7 +79,7 @@ static void do_test(unsigned long size) { void __iomem *p = ioremap_nocache(mmio_address, size); if (!p) { - pr_err(MODULE_NAME ": could not ioremap, aborting.\n"); + pr_err("could not ioremap, aborting.\n"); return; } mmiotrace_printk("ioremap returned %p.\n", p); @@ -94,24 +95,22 @@ static int __init init(void) unsigned long size = (read_far) ? (8 << 20) : (16 << 10); if (mmio_address == 0) { - pr_err(MODULE_NAME ": you have to use the module argument " - "mmio_address.\n"); - pr_err(MODULE_NAME ": DO NOT LOAD THIS MODULE UNLESS" - " YOU REALLY KNOW WHAT YOU ARE DOING!\n"); + pr_err("you have to use the module argument mmio_address.\n"); + pr_err("DO NOT LOAD THIS MODULE UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!\n"); return -ENXIO; } - pr_warning(MODULE_NAME ": WARNING: mapping %lu kB @ 0x%08lx in PCI " - "address space, and writing 16 kB of rubbish in there.\n", - size >> 10, mmio_address); + pr_warning("WARNING: mapping %lu kB @ 0x%08lx in PCI address space, " + "and writing 16 kB of rubbish in there.\n", + size >> 10, mmio_address); do_test(size); - pr_info(MODULE_NAME ": All done.\n"); + pr_info("All done.\n"); return 0; } static void __exit cleanup(void) { - pr_debug(MODULE_NAME ": unloaded.\n"); + pr_debug("unloaded.\n"); } module_init(init); From 369bc18f9a6c4e2686204c1d7476ab684a720968 Mon Sep 17 00:00:00 2001 From: Stefan Assmann Date: Mon, 12 Oct 2009 22:17:21 +0200 Subject: [PATCH 021/298] ftrace: add kernel command line graph function filtering Add a command line parameter to allow limiting the function graphs that are traced on boot up from the given top-level callers , when ftrace=function_graph is specified. This patch adds the following command line option: ftrace_graph_filter=function-list Where function-list is a comma separated list of functions to filter. [fweisbec@gmail.com: picked the documentation changes from the v2 patch] Signed-off-by: Stefan Assmann Acked-by: Steven Rostedt LKML-Reference: <4AD2DEB9.2@redhat.com> Signed-off-by: Frederic Weisbecker --- Documentation/kernel-parameters.txt | 7 ++++++ kernel/trace/ftrace.c | 34 +++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 6fa7292947e..1dc4b9cc20e 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -778,6 +778,13 @@ and is between 256 and 4096 characters. It is defined in the file by the set_ftrace_notrace file in the debugfs tracing directory. + ftrace_graph_filter=[function-list] + [FTRACE] Limit the top level callers functions traced + by the function graph tracer at boot up. + function-list is a comma separated list of functions + that can be changed at run time by the + set_graph_function file in the debugfs tracing directory. + gamecon.map[2|3]= [HW,JOY] Multisystem joystick and NES/SNES/PSX pad support via parallel port (up to 5 devices per port) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 9a72853a8f0..91283d40821 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -78,6 +78,10 @@ ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub; ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +static int ftrace_set_func(unsigned long *array, int *idx, char *buffer); +#endif + static void ftrace_list_func(unsigned long ip, unsigned long parent_ip) { struct ftrace_ops *op = ftrace_list; @@ -2248,6 +2252,7 @@ void ftrace_set_notrace(unsigned char *buf, int len, int reset) #define FTRACE_FILTER_SIZE COMMAND_LINE_SIZE static char ftrace_notrace_buf[FTRACE_FILTER_SIZE] __initdata; static char ftrace_filter_buf[FTRACE_FILTER_SIZE] __initdata; +static char ftrace_graph_buf[FTRACE_FILTER_SIZE] __initdata; static int __init set_ftrace_notrace(char *str) { @@ -2263,6 +2268,31 @@ static int __init set_ftrace_filter(char *str) } __setup("ftrace_filter=", set_ftrace_filter); +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +static int __init set_graph_function(char *str) +{ + strncpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE); + return 1; +} +__setup("ftrace_graph_filter=", set_graph_function); + +static void __init set_ftrace_early_graph(char *buf) +{ + int ret; + char *func; + + while (buf) { + func = strsep(&buf, ","); + /* we allow only one expression at a time */ + ret = ftrace_set_func(ftrace_graph_funcs, &ftrace_graph_count, + func); + if (ret) + printk(KERN_DEBUG "ftrace: function %s not " + "traceable\n", func); + } +} +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ + static void __init set_ftrace_early_filter(char *buf, int enable) { char *func; @@ -2279,6 +2309,10 @@ static void __init set_ftrace_early_filters(void) set_ftrace_early_filter(ftrace_filter_buf, 1); if (ftrace_notrace_buf[0]) set_ftrace_early_filter(ftrace_notrace_buf, 0); +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + if (ftrace_graph_buf[0]) + set_ftrace_early_graph(ftrace_graph_buf); +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ } static int From aef6f81b55f462082699c06e8e67e6eb5630ed45 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Mon, 12 Oct 2009 22:23:24 +0200 Subject: [PATCH 022/298] tracing: Rename set_ftrace to set_bootup_ftrace Do this rename because set_ftrace is too much generic and not enough self-explainable as a name. Signed-off-by: Frederic Weisbecker Cc: Steven Rostedt Cc: Li Zefan --- kernel/trace/trace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 45068269ebb..866daf8497f 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -129,7 +129,7 @@ static int tracing_set_tracer(const char *buf); static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata; static char *default_bootup_tracer; -static int __init set_ftrace(char *str) +static int __init set_bootup_ftrace(char *str) { strncpy(bootup_tracer_buf, str, MAX_TRACER_SIZE); default_bootup_tracer = bootup_tracer_buf; @@ -137,7 +137,7 @@ static int __init set_ftrace(char *str) ring_buffer_expanded = 1; return 1; } -__setup("ftrace=", set_ftrace); +__setup("ftrace=", set_bootup_ftrace); static int __init set_ftrace_dump_on_oops(char *str) { From bf7c5b43a12614847b83f507fb169ad30640e406 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Mon, 12 Oct 2009 22:31:32 +0200 Subject: [PATCH 023/298] tracing: Remove unused ftrace_trace_addr helper Remove the ftrace_trace_addr() function as only its off-case is implemented and there are no users of it currently. But we keep ftrace_graph_addr() off-case, in case someone come to use the function graph tracer to profit from top-level callers filtering. Signed-off-by: Frederic Weisbecker Cc: Steven Rostedt Cc: Li Zefan --- kernel/trace/trace.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 365fb19d9e1..f22a7ac3238 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -483,10 +483,6 @@ static inline int ftrace_graph_addr(unsigned long addr) return 0; } #else -static inline int ftrace_trace_addr(unsigned long addr) -{ - return 1; -} static inline int ftrace_graph_addr(unsigned long addr) { return 1; From 825332e4ff1373c55d931b49408df7ec2298f71e Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Wed, 14 Oct 2009 08:17:36 +1100 Subject: [PATCH 024/298] capabilities: simplify bound checks for copy_from_user() The capabilities syscall has a copy_from_user() call where gcc currently cannot prove to itself that the copy is always within bounds. This patch adds a very explicity bound check to prove to gcc that this copy_from_user cannot overflow its destination buffer. Signed-off-by: Arjan van de Ven Acked-by: James Morris Signed-off-by: Andrew Morton Signed-off-by: James Morris --- kernel/capability.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/kernel/capability.c b/kernel/capability.c index 4e17041963f..c2316d3fa09 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -238,7 +238,7 @@ SYSCALL_DEFINE2(capget, cap_user_header_t, header, cap_user_data_t, dataptr) SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data) { struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S]; - unsigned i, tocopy; + unsigned i, tocopy, copybytes; kernel_cap_t inheritable, permitted, effective; struct cred *new; int ret; @@ -255,8 +255,11 @@ SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data) if (pid != 0 && pid != task_pid_vnr(current)) return -EPERM; - if (copy_from_user(&kdata, data, - tocopy * sizeof(struct __user_cap_data_struct))) + copybytes = tocopy * sizeof(struct __user_cap_data_struct); + if (copybytes > sizeof(kdata)) + return -EFAULT; + + if (copy_from_user(&kdata, data, copybytes)) return -EFAULT; for (i = 0; i < tocopy; i++) { From 194ec34184869f0de1cf255c924fc5299e1b3d27 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 13 Oct 2009 16:33:50 -0400 Subject: [PATCH 025/298] function-graph/x86: Replace unbalanced ret with jmp The function graph tracer replaces the return address with a hook to trace the exit of the function call. This hook will finish by returning to the real location the function should return to. But the current implementation uses a ret to jump to the real return location. This causes a imbalance between calls and ret. That is the original function does a call, the ret goes to the handler and then the handler does a ret without a matching call. Although the function graph tracer itself still breaks the branch predictor by replacing the original ret, by using a second ret and causing an imbalance, it breaks the predictor even more. This patch replaces the ret with a jmp to keep the calls and ret balanced. I tested this on one box and it showed a 1.7% increase in performance. Another box only showed a small 0.3% increase. But no box that I tested this on showed a decrease in performance by making this change. Signed-off-by: Steven Rostedt Acked-by: Mathieu Desnoyers Cc: Frederic Weisbecker LKML-Reference: <20091013203425.042034383@goodmis.org> Signed-off-by: Ingo Molnar --- arch/x86/kernel/entry_32.S | 7 ++----- arch/x86/kernel/entry_64.S | 6 +++--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index c097e7d607c..7d52e9da5e0 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S @@ -1185,17 +1185,14 @@ END(ftrace_graph_caller) .globl return_to_handler return_to_handler: - pushl $0 pushl %eax - pushl %ecx pushl %edx movl %ebp, %eax call ftrace_return_to_handler - movl %eax, 0xc(%esp) + movl %eax, %ecx popl %edx - popl %ecx popl %eax - ret + jmp *%ecx #endif .section .rodata,"a" diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index b5c061f8f35..bd5bbddddf9 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -155,11 +155,11 @@ GLOBAL(return_to_handler) call ftrace_return_to_handler - movq %rax, 16(%rsp) + movq %rax, %rdi movq 8(%rsp), %rdx movq (%rsp), %rax - addq $16, %rsp - retq + addq $24, %rsp + jmp *%rdi #endif From 756d17ee7ee4fbc8238bdf97100af63e6ac441ef Mon Sep 17 00:00:00 2001 From: "jolsa@redhat.com" Date: Tue, 13 Oct 2009 16:33:52 -0400 Subject: [PATCH 026/298] tracing: Support multiple pids in set_pid_ftrace file Adding the possibility to set more than 1 pid in the set_pid_ftrace file, thus allowing to trace more than 1 independent processes. Usage: sh-4.0# echo 284 > ./set_ftrace_pid sh-4.0# cat ./set_ftrace_pid 284 sh-4.0# echo 1 >> ./set_ftrace_pid sh-4.0# echo 0 >> ./set_ftrace_pid sh-4.0# cat ./set_ftrace_pid swapper tasks 1 284 sh-4.0# echo 4 > ./set_ftrace_pid sh-4.0# cat ./set_ftrace_pid 4 sh-4.0# echo > ./set_ftrace_pid sh-4.0# cat ./set_ftrace_pid no pid sh-4.0# Signed-off-by: Jiri Olsa Cc: Frederic Weisbecker LKML-Reference: <20091013203425.565454612@goodmis.org> Signed-off-by: Steven Rostedt Signed-off-by: Ingo Molnar --- kernel/trace/ftrace.c | 234 +++++++++++++++++++++++++++++------------- kernel/trace/trace.h | 4 +- 2 files changed, 167 insertions(+), 71 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 45c965919cf..0c799d1af70 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -60,6 +60,13 @@ static int last_ftrace_enabled; /* Quick disabling of function tracer. */ int function_trace_stop; +/* List for set_ftrace_pid's pids. */ +LIST_HEAD(ftrace_pids); +struct ftrace_pid { + struct list_head list; + struct pid *pid; +}; + /* * ftrace_disabled is set when an anomaly is discovered. * ftrace_disabled is much stronger than ftrace_enabled. @@ -159,7 +166,7 @@ static int __register_ftrace_function(struct ftrace_ops *ops) else func = ftrace_list_func; - if (ftrace_pid_trace) { + if (!list_empty(&ftrace_pids)) { set_ftrace_pid_function(func); func = ftrace_pid_func; } @@ -207,7 +214,7 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) if (ftrace_list->next == &ftrace_list_end) { ftrace_func_t func = ftrace_list->func; - if (ftrace_pid_trace) { + if (!list_empty(&ftrace_pids)) { set_ftrace_pid_function(func); func = ftrace_pid_func; } @@ -235,7 +242,7 @@ static void ftrace_update_pid_func(void) func = __ftrace_trace_function; #endif - if (ftrace_pid_trace) { + if (!list_empty(&ftrace_pids)) { set_ftrace_pid_function(func); func = ftrace_pid_func; } else { @@ -825,8 +832,6 @@ static __init void ftrace_profile_debugfs(struct dentry *d_tracer) } #endif /* CONFIG_FUNCTION_PROFILER */ -/* set when tracing only a pid */ -struct pid *ftrace_pid_trace; static struct pid * const ftrace_swapper_pid = &init_struct_pid; #ifdef CONFIG_DYNAMIC_FTRACE @@ -2758,23 +2763,6 @@ static inline void ftrace_startup_enable(int command) { } # define ftrace_shutdown_sysctl() do { } while (0) #endif /* CONFIG_DYNAMIC_FTRACE */ -static ssize_t -ftrace_pid_read(struct file *file, char __user *ubuf, - size_t cnt, loff_t *ppos) -{ - char buf[64]; - int r; - - if (ftrace_pid_trace == ftrace_swapper_pid) - r = sprintf(buf, "swapper tasks\n"); - else if (ftrace_pid_trace) - r = sprintf(buf, "%u\n", pid_vnr(ftrace_pid_trace)); - else - r = sprintf(buf, "no pid\n"); - - return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); -} - static void clear_ftrace_swapper(void) { struct task_struct *p; @@ -2825,14 +2813,12 @@ static void set_ftrace_pid(struct pid *pid) rcu_read_unlock(); } -static void clear_ftrace_pid_task(struct pid **pid) +static void clear_ftrace_pid_task(struct pid *pid) { - if (*pid == ftrace_swapper_pid) + if (pid == ftrace_swapper_pid) clear_ftrace_swapper(); else - clear_ftrace_pid(*pid); - - *pid = NULL; + clear_ftrace_pid(pid); } static void set_ftrace_pid_task(struct pid *pid) @@ -2843,11 +2829,140 @@ static void set_ftrace_pid_task(struct pid *pid) set_ftrace_pid(pid); } +static int ftrace_pid_add(int p) +{ + struct pid *pid; + struct ftrace_pid *fpid; + int ret = -EINVAL; + + mutex_lock(&ftrace_lock); + + if (!p) + pid = ftrace_swapper_pid; + else + pid = find_get_pid(p); + + if (!pid) + goto out; + + ret = 0; + + list_for_each_entry(fpid, &ftrace_pids, list) + if (fpid->pid == pid) + goto out_put; + + ret = -ENOMEM; + + fpid = kmalloc(sizeof(*fpid), GFP_KERNEL); + if (!fpid) + goto out_put; + + list_add(&fpid->list, &ftrace_pids); + fpid->pid = pid; + + set_ftrace_pid_task(pid); + + ftrace_update_pid_func(); + ftrace_startup_enable(0); + + mutex_unlock(&ftrace_lock); + return 0; + +out_put: + if (pid != ftrace_swapper_pid) + put_pid(pid); + +out: + mutex_unlock(&ftrace_lock); + return ret; +} + +static void ftrace_pid_reset(void) +{ + struct ftrace_pid *fpid, *safe; + + mutex_lock(&ftrace_lock); + list_for_each_entry_safe(fpid, safe, &ftrace_pids, list) { + struct pid *pid = fpid->pid; + + clear_ftrace_pid_task(pid); + + list_del(&fpid->list); + kfree(fpid); + } + + ftrace_update_pid_func(); + ftrace_startup_enable(0); + + mutex_unlock(&ftrace_lock); +} + +static void *fpid_start(struct seq_file *m, loff_t *pos) +{ + mutex_lock(&ftrace_lock); + + if (list_empty(&ftrace_pids) && (!*pos)) + return (void *) 1; + + return seq_list_start(&ftrace_pids, *pos); +} + +static void *fpid_next(struct seq_file *m, void *v, loff_t *pos) +{ + if (v == (void *)1) + return NULL; + + return seq_list_next(v, &ftrace_pids, pos); +} + +static void fpid_stop(struct seq_file *m, void *p) +{ + mutex_unlock(&ftrace_lock); +} + +static int fpid_show(struct seq_file *m, void *v) +{ + const struct ftrace_pid *fpid = list_entry(v, struct ftrace_pid, list); + + if (v == (void *)1) { + seq_printf(m, "no pid\n"); + return 0; + } + + if (fpid->pid == ftrace_swapper_pid) + seq_printf(m, "swapper tasks\n"); + else + seq_printf(m, "%u\n", pid_vnr(fpid->pid)); + + return 0; +} + +static const struct seq_operations ftrace_pid_sops = { + .start = fpid_start, + .next = fpid_next, + .stop = fpid_stop, + .show = fpid_show, +}; + +static int +ftrace_pid_open(struct inode *inode, struct file *file) +{ + int ret = 0; + + if ((file->f_mode & FMODE_WRITE) && + (file->f_flags & O_TRUNC)) + ftrace_pid_reset(); + + if (file->f_mode & FMODE_READ) + ret = seq_open(file, &ftrace_pid_sops); + + return ret; +} + static ssize_t ftrace_pid_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { - struct pid *pid; char buf[64]; long val; int ret; @@ -2860,57 +2975,38 @@ ftrace_pid_write(struct file *filp, const char __user *ubuf, buf[cnt] = 0; + /* + * Allow "echo > set_ftrace_pid" or "echo -n '' > set_ftrace_pid" + * to clean the filter quietly. + */ + strstrip(buf); + if (strlen(buf) == 0) + return 1; + ret = strict_strtol(buf, 10, &val); if (ret < 0) return ret; - mutex_lock(&ftrace_lock); - if (val < 0) { - /* disable pid tracing */ - if (!ftrace_pid_trace) - goto out; + ret = ftrace_pid_add(val); - clear_ftrace_pid_task(&ftrace_pid_trace); + return ret ? ret : cnt; +} - } else { - /* swapper task is special */ - if (!val) { - pid = ftrace_swapper_pid; - if (pid == ftrace_pid_trace) - goto out; - } else { - pid = find_get_pid(val); +static int +ftrace_pid_release(struct inode *inode, struct file *file) +{ + if (file->f_mode & FMODE_READ) + seq_release(inode, file); - if (pid == ftrace_pid_trace) { - put_pid(pid); - goto out; - } - } - - if (ftrace_pid_trace) - clear_ftrace_pid_task(&ftrace_pid_trace); - - if (!pid) - goto out; - - ftrace_pid_trace = pid; - - set_ftrace_pid_task(ftrace_pid_trace); - } - - /* update the function call */ - ftrace_update_pid_func(); - ftrace_startup_enable(0); - - out: - mutex_unlock(&ftrace_lock); - - return cnt; + return 0; } static const struct file_operations ftrace_pid_fops = { - .read = ftrace_pid_read, - .write = ftrace_pid_write, + .open = ftrace_pid_open, + .write = ftrace_pid_write, + .read = seq_read, + .llseek = seq_lseek, + .release = ftrace_pid_release, }; static __init int ftrace_init_debugfs(void) diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index f22a7ac3238..acef8b4636f 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -496,12 +496,12 @@ print_graph_function(struct trace_iterator *iter) } #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ -extern struct pid *ftrace_pid_trace; +extern struct list_head ftrace_pids; #ifdef CONFIG_FUNCTION_TRACER static inline int ftrace_trace_task(struct task_struct *task) { - if (!ftrace_pid_trace) + if (list_empty(&ftrace_pids)) return 1; return test_tsk_trace_trace(task); From 5cb084bb1f3fd4dcdaf7e4cf564994346ec8f783 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 13 Oct 2009 16:33:53 -0400 Subject: [PATCH 027/298] tracing: Enable records during the module load I was debuging some module using "function" and "function_graph" tracers and noticed, that if you load module after you enabled tracing, the module's hooks will convert only to NOP instructions. The attached patch enables modules' hooks if there's function trace allready on, thus allowing to trace module functions. Signed-off-by: Jiri Olsa Cc: Frederic Weisbecker Signed-off-by: Steven Rostedt LKML-Reference: <20091013203425.896285120@goodmis.org> Signed-off-by: Ingo Molnar --- kernel/trace/ftrace.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 0c799d1af70..aaea9cda878 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1270,12 +1270,34 @@ static int ftrace_update_code(struct module *mod) ftrace_new_addrs = p->newlist; p->flags = 0L; - /* convert record (i.e, patch mcount-call with NOP) */ - if (ftrace_code_disable(mod, p)) { - p->flags |= FTRACE_FL_CONVERTED; - ftrace_update_cnt++; - } else + /* + * Do the initial record convertion from mcount jump + * to the NOP instructions. + */ + if (!ftrace_code_disable(mod, p)) { ftrace_free_rec(p); + continue; + } + + p->flags |= FTRACE_FL_CONVERTED; + ftrace_update_cnt++; + + /* + * If the tracing is enabled, go ahead and enable the record. + * + * The reason not to enable the record immediatelly is the + * inherent check of ftrace_make_nop/ftrace_make_call for + * correct previous instructions. Making first the NOP + * conversion puts the module to the correct state, thus + * passing the ftrace_make_call check. + */ + if (ftrace_start_up) { + int failed = __ftrace_replace_code(p, 1); + if (failed) { + ftrace_bug(failed, p->ip); + ftrace_free_rec(p); + } + } } stop = ftrace_now(raw_smp_processor_id()); @@ -2609,7 +2631,7 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer) return 0; } -static int ftrace_convert_nops(struct module *mod, +static int ftrace_process_locs(struct module *mod, unsigned long *start, unsigned long *end) { @@ -2669,7 +2691,7 @@ static void ftrace_init_module(struct module *mod, { if (ftrace_disabled || start == end) return; - ftrace_convert_nops(mod, start, end); + ftrace_process_locs(mod, start, end); } static int ftrace_module_notify(struct notifier_block *self, @@ -2730,7 +2752,7 @@ void __init ftrace_init(void) last_ftrace_enabled = ftrace_enabled = 1; - ret = ftrace_convert_nops(NULL, + ret = ftrace_process_locs(NULL, __start_mcount_loc, __stop_mcount_loc); From 4d8289494a37e19cd7f3beacea9c957ad3debad6 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 13 Oct 2009 16:33:54 -0400 Subject: [PATCH 028/298] tracing: Enable "__cold" functions Based on the commit: a586df06 "x86: Support __attribute__((__cold__)) in gcc 4.3" some of the functions goes to the ".text.unlikely" section. Looks like there's not many of them (I found printk, panic, __ssb_dma_not_implemented, fat_fs_error), but still worth to include I think. Signed-off-by: Jiri Olsa Cc: Frederic Weisbecker Signed-off-by: Steven Rostedt LKML-Reference: <20091013203426.175845614@goodmis.org> Signed-off-by: Ingo Molnar --- scripts/recordmcount.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 090d300d739..bfb8b2cdd92 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -119,6 +119,7 @@ my %text_sections = ( ".sched.text" => 1, ".spinlock.text" => 1, ".irqentry.text" => 1, + ".text.unlikely" => 1, ); $objdump = "objdump" if ((length $objdump) == 0); From c44fc770845163f8d9e573f37f92a7b7a7ade14e Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 19 Sep 2009 06:50:42 +0200 Subject: [PATCH 029/298] tracing: Move syscalls metadata handling from arch to core Most of the syscalls metadata processing is done from arch. But these operations are mostly generic accross archs. Especially now that we have a common variable name that expresses the number of syscalls supported by an arch: NR_syscalls, the only remaining bits that need to reside in arch is the syscall nr to addr translation. v2: Compare syscalls symbols only after the "sys" prefix so that we avoid spurious mismatches with archs that have syscalls wrappers, in which case syscalls symbols have "SyS" prefixed aliases. (Reported by: Heiko Carstens) Signed-off-by: Frederic Weisbecker Acked-by: Heiko Carstens Cc: Ingo Molnar Cc: Steven Rostedt Cc: Li Zefan Cc: Masami Hiramatsu Cc: Jason Baron Cc: Lai Jiangshan Cc: Martin Schwidefsky Cc: Paul Mundt --- arch/s390/kernel/ftrace.c | 67 +-------------------------- arch/x86/kernel/ftrace.c | 76 +------------------------------ include/trace/syscall.h | 2 +- kernel/trace/trace_syscalls.c | 86 +++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 140 deletions(-) diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index 57bdcb1e3cd..7c5752c3423 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c @@ -206,73 +206,10 @@ out: #ifdef CONFIG_FTRACE_SYSCALLS -extern unsigned long __start_syscalls_metadata[]; -extern unsigned long __stop_syscalls_metadata[]; extern unsigned int sys_call_table[]; -static struct syscall_metadata **syscalls_metadata; - -struct syscall_metadata *syscall_nr_to_meta(int nr) +unsigned long __init arch_syscall_addr(int nr) { - if (!syscalls_metadata || nr >= NR_syscalls || nr < 0) - return NULL; - - return syscalls_metadata[nr]; + return (unsigned long)sys_call_table[nr]; } - -int syscall_name_to_nr(char *name) -{ - int i; - - if (!syscalls_metadata) - return -1; - for (i = 0; i < NR_syscalls; i++) - if (syscalls_metadata[i]) - if (!strcmp(syscalls_metadata[i]->name, name)) - return i; - return -1; -} - -void set_syscall_enter_id(int num, int id) -{ - syscalls_metadata[num]->enter_id = id; -} - -void set_syscall_exit_id(int num, int id) -{ - syscalls_metadata[num]->exit_id = id; -} - -static struct syscall_metadata *find_syscall_meta(unsigned long syscall) -{ - struct syscall_metadata *start; - struct syscall_metadata *stop; - char str[KSYM_SYMBOL_LEN]; - - start = (struct syscall_metadata *)__start_syscalls_metadata; - stop = (struct syscall_metadata *)__stop_syscalls_metadata; - kallsyms_lookup(syscall, NULL, NULL, NULL, str); - - for ( ; start < stop; start++) { - if (start->name && !strcmp(start->name + 3, str + 3)) - return start; - } - return NULL; -} - -static int __init arch_init_ftrace_syscalls(void) -{ - struct syscall_metadata *meta; - int i; - syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * NR_syscalls, - GFP_KERNEL); - if (!syscalls_metadata) - return -ENOMEM; - for (i = 0; i < NR_syscalls; i++) { - meta = find_syscall_meta((unsigned long)sys_call_table[i]); - syscalls_metadata[i] = meta; - } - return 0; -} -arch_initcall(arch_init_ftrace_syscalls); #endif diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 25e6f5fc4b1..5a1b9758fd6 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -470,82 +470,10 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, #ifdef CONFIG_FTRACE_SYSCALLS -extern unsigned long __start_syscalls_metadata[]; -extern unsigned long __stop_syscalls_metadata[]; extern unsigned long *sys_call_table; -static struct syscall_metadata **syscalls_metadata; - -static struct syscall_metadata *find_syscall_meta(unsigned long *syscall) +unsigned long __init arch_syscall_addr(int nr) { - struct syscall_metadata *start; - struct syscall_metadata *stop; - char str[KSYM_SYMBOL_LEN]; - - - start = (struct syscall_metadata *)__start_syscalls_metadata; - stop = (struct syscall_metadata *)__stop_syscalls_metadata; - kallsyms_lookup((unsigned long) syscall, NULL, NULL, NULL, str); - - for ( ; start < stop; start++) { - if (start->name && !strcmp(start->name, str)) - return start; - } - return NULL; + return (unsigned long)(&sys_call_table)[nr]; } - -struct syscall_metadata *syscall_nr_to_meta(int nr) -{ - if (!syscalls_metadata || nr >= NR_syscalls || nr < 0) - return NULL; - - return syscalls_metadata[nr]; -} - -int syscall_name_to_nr(char *name) -{ - int i; - - if (!syscalls_metadata) - return -1; - - for (i = 0; i < NR_syscalls; i++) { - if (syscalls_metadata[i]) { - if (!strcmp(syscalls_metadata[i]->name, name)) - return i; - } - } - return -1; -} - -void set_syscall_enter_id(int num, int id) -{ - syscalls_metadata[num]->enter_id = id; -} - -void set_syscall_exit_id(int num, int id) -{ - syscalls_metadata[num]->exit_id = id; -} - -static int __init arch_init_ftrace_syscalls(void) -{ - int i; - struct syscall_metadata *meta; - unsigned long **psys_syscall_table = &sys_call_table; - - syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * - NR_syscalls, GFP_KERNEL); - if (!syscalls_metadata) { - WARN_ON(1); - return -ENOMEM; - } - - for (i = 0; i < NR_syscalls; i++) { - meta = find_syscall_meta(psys_syscall_table[i]); - syscalls_metadata[i] = meta; - } - return 0; -} -arch_initcall(arch_init_ftrace_syscalls); #endif diff --git a/include/trace/syscall.h b/include/trace/syscall.h index 5dc283ba5ae..e972f0a40f8 100644 --- a/include/trace/syscall.h +++ b/include/trace/syscall.h @@ -33,7 +33,7 @@ struct syscall_metadata { }; #ifdef CONFIG_FTRACE_SYSCALLS -extern struct syscall_metadata *syscall_nr_to_meta(int nr); +extern unsigned long arch_syscall_addr(int nr); extern int syscall_name_to_nr(char *name); void set_syscall_enter_id(int num, int id); void set_syscall_exit_id(int num, int id); diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 9fbce6c9d2e..8bda4bff228 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -14,6 +14,69 @@ static int sys_refcount_exit; static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); +extern unsigned long __start_syscalls_metadata[]; +extern unsigned long __stop_syscalls_metadata[]; + +static struct syscall_metadata **syscalls_metadata; + +static struct syscall_metadata *find_syscall_meta(unsigned long syscall) +{ + struct syscall_metadata *start; + struct syscall_metadata *stop; + char str[KSYM_SYMBOL_LEN]; + + + start = (struct syscall_metadata *)__start_syscalls_metadata; + stop = (struct syscall_metadata *)__stop_syscalls_metadata; + kallsyms_lookup(syscall, NULL, NULL, NULL, str); + + for ( ; start < stop; start++) { + /* + * Only compare after the "sys" prefix. Archs that use + * syscall wrappers may have syscalls symbols aliases prefixed + * with "SyS" instead of "sys", leading to an unwanted + * mismatch. + */ + if (start->name && !strcmp(start->name + 3, str + 3)) + return start; + } + return NULL; +} + +static struct syscall_metadata *syscall_nr_to_meta(int nr) +{ + if (!syscalls_metadata || nr >= NR_syscalls || nr < 0) + return NULL; + + return syscalls_metadata[nr]; +} + +int syscall_name_to_nr(char *name) +{ + int i; + + if (!syscalls_metadata) + return -1; + + for (i = 0; i < NR_syscalls; i++) { + if (syscalls_metadata[i]) { + if (!strcmp(syscalls_metadata[i]->name, name)) + return i; + } + } + return -1; +} + +void set_syscall_enter_id(int num, int id) +{ + syscalls_metadata[num]->enter_id = id; +} + +void set_syscall_exit_id(int num, int id) +{ + syscalls_metadata[num]->exit_id = id; +} + enum print_line_t print_syscall_enter(struct trace_iterator *iter, int flags) { @@ -375,6 +438,29 @@ struct trace_event event_syscall_exit = { .trace = print_syscall_exit, }; +int __init init_ftrace_syscalls(void) +{ + struct syscall_metadata *meta; + unsigned long addr; + int i; + + syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * + NR_syscalls, GFP_KERNEL); + if (!syscalls_metadata) { + WARN_ON(1); + return -ENOMEM; + } + + for (i = 0; i < NR_syscalls; i++) { + addr = arch_syscall_addr(i); + meta = find_syscall_meta(addr); + syscalls_metadata[i] = meta; + } + + return 0; +} +core_initcall(init_ftrace_syscalls); + #ifdef CONFIG_EVENT_PROFILE static DECLARE_BITMAP(enabled_prof_enter_syscalls, NR_syscalls); From 459c6d15a0c52bae43842ff2cd0dd41aa7de9b7f Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 19 Sep 2009 07:14:15 +0200 Subject: [PATCH 030/298] tracing: Document HAVE_SYSCALL_TRACEPOINTS needs Document the arch needed requirements to get the support for syscalls tracing. v2: HAVE_FTRACE_SYSCALLS have been changed to HAVE_SYSCALL_TRACEPOINTS recently. Update this config name in the documentation then. Signed-off-by: Frederic Weisbecker Acked-by: Heiko Carstens Cc: Ingo Molnar Cc: Steven Rostedt Cc: Li Zefan Cc: Masami Hiramatsu Cc: Jason Baron Cc: Lai Jiangshan Cc: Martin Schwidefsky Cc: Paul Mundt --- Documentation/trace/ftrace-design.txt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Documentation/trace/ftrace-design.txt b/Documentation/trace/ftrace-design.txt index 7003e10f10f..641a1ef2a7f 100644 --- a/Documentation/trace/ftrace-design.txt +++ b/Documentation/trace/ftrace-design.txt @@ -213,10 +213,19 @@ If you can't trace NMI functions, then skip this option.
-HAVE_FTRACE_SYSCALLS +HAVE_SYSCALL_TRACEPOINTS --------------------- -
+You need very few things to get the syscalls tracing in an arch. + +- Have a NR_syscalls variable in that provides the number + of syscalls supported by the arch. +- Implement arch_syscall_addr() that resolves a syscall address from a + syscall number. +- Support the TIF_SYSCALL_TRACEPOINT thread flags +- Put the trace_sys_enter() and trace_sys_exit() tracepoints calls from ptrace + in the ptrace syscalls tracing path. +- Tag this arch as HAVE_SYSCALL_TRACEPOINTS. HAVE_FTRACE_MCOUNT_RECORD From 06f43d66ec36388056f5c697bf1e67c0e0a1645c Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 14 Oct 2009 20:43:39 +0200 Subject: [PATCH 031/298] ftrace: Copy ftrace_graph_filter boot param using strlcpy We are using strncpy in the wrong way to copy the ftrace_graph_filter boot param because we pass the buffer size instead of the max string size it can contain (buffer size - 1). The end result might not be NULL terminated as we are abusing the max string size. Lets use strlcpy() instead. Reported-by: Li Zefan Signed-off-by: Frederic Weisbecker Cc: 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 aaea9cda878..b10c0d90a6f 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -2293,7 +2293,7 @@ __setup("ftrace_filter=", set_ftrace_filter); #ifdef CONFIG_FUNCTION_GRAPH_TRACER static int __init set_graph_function(char *str) { - strncpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE); + strlcpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE); return 1; } __setup("ftrace_graph_filter=", set_graph_function); From 1beee96bae0daf7f491356777c3080cc436950f5 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 14 Oct 2009 20:50:32 +0200 Subject: [PATCH 032/298] ftrace: Rename set_bootup_ftrace into set_cmdline_ftrace set_cmdline_ftrace is a better match against what does this function: apply a tracer name from the kernel command line. Reported-by: Steven Rostedt Signed-off-by: Frederic Weisbecker Cc: Li Zefan --- kernel/trace/trace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 4311ec3062f..026e715a0c7 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -129,7 +129,7 @@ static int tracing_set_tracer(const char *buf); static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata; static char *default_bootup_tracer; -static int __init set_bootup_ftrace(char *str) +static int __init set_cmdline_ftrace(char *str) { strncpy(bootup_tracer_buf, str, MAX_TRACER_SIZE); default_bootup_tracer = bootup_tracer_buf; @@ -137,7 +137,7 @@ static int __init set_bootup_ftrace(char *str) ring_buffer_expanded = 1; return 1; } -__setup("ftrace=", set_bootup_ftrace); +__setup("ftrace=", set_cmdline_ftrace); static int __init set_ftrace_dump_on_oops(char *str) { From 3397e040dfacbb303498ced1baa96be983dcea06 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 14 Oct 2009 16:36:38 -0700 Subject: [PATCH 033/298] rcu: Add rnp->blocked_tasks to tracing Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com Cc: npiggin@suse.de Cc: jens.axboe@oracle.com Cc: Josh Triplett LKML-Reference: <20091014233638.GE6763@linux.vnet.ibm.com> Signed-off-by: Ingo Molnar kernel/rcutree_trace.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) --- kernel/rcutree_trace.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index 4b31c779e62..1984cdc51e9 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c @@ -155,12 +155,14 @@ static const struct file_operations rcudata_csv_fops = { static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp) { + long gpnum; int level = 0; struct rcu_node *rnp; + gpnum = rsp->gpnum; seq_printf(m, "c=%ld g=%ld s=%d jfq=%ld j=%x " "nfqs=%lu/nfqsng=%lu(%lu) fqlh=%lu oqlen=%ld\n", - rsp->completed, rsp->gpnum, rsp->signaled, + rsp->completed, gpnum, rsp->signaled, (long)(rsp->jiffies_force_qs - jiffies), (int)(jiffies & 0xffff), rsp->n_force_qs, rsp->n_force_qs_ngp, @@ -171,8 +173,10 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp) seq_puts(m, "\n"); level = rnp->level; } - seq_printf(m, "%lx/%lx %d:%d ^%d ", + seq_printf(m, "%lx/%lx %c>%c %d:%d ^%d ", rnp->qsmask, rnp->qsmaskinit, + "T."[list_empty(&rnp->blocked_tasks[gpnum & 1])], + "T."[list_empty(&rnp->blocked_tasks[!(gpnum & 1)])], rnp->grplo, rnp->grphi, rnp->grpnum); } seq_puts(m, "\n"); From bd58b430039435e4c981cf802b5b11d511d73abd Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 14 Oct 2009 10:15:54 -0700 Subject: [PATCH 034/298] rcu: Update trace.txt documentation to reflect recent changes o Remove the CONFIG_PREEMPT_RCU documentation since this config option has now been removed. o Change the now-incorrect references to "rcu" labels to instead be "rcu_sched". o Add notes stating that CONFIG_TREE_PREEMPT_RCU kernels will have additional "rcu_preempt" output. o Note the new "oqlen" field in the rcuhier output (for RCU callbacks orphaned by an offlined CPU). Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com Cc: npiggin@suse.de Cc: jens.axboe@oracle.com LKML-Reference: <1255540559799-git-send-email-> Signed-off-by: Ingo Molnar --- Documentation/RCU/trace.txt | 231 ++++++------------------------------ 1 file changed, 33 insertions(+), 198 deletions(-) diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt index 187bbf10c92..c1a95507d10 100644 --- a/Documentation/RCU/trace.txt +++ b/Documentation/RCU/trace.txt @@ -1,185 +1,10 @@ CONFIG_RCU_TRACE debugfs Files and Formats -The rcupreempt and rcutree implementations of RCU provide debugfs trace -output that summarizes counters and state. This information is useful for -debugging RCU itself, and can sometimes also help to debug abuses of RCU. -Note that the rcuclassic implementation of RCU does not provide debugfs -trace output. - -The following sections describe the debugfs files and formats for -preemptable RCU (rcupreempt) and hierarchical RCU (rcutree). - - -Preemptable RCU debugfs Files and Formats - -This implementation of RCU provides three debugfs files under the -top-level directory RCU: rcu/rcuctrs (which displays the per-CPU -counters used by preemptable RCU) rcu/rcugp (which displays grace-period -counters), and rcu/rcustats (which internal counters for debugging RCU). - -The output of "cat rcu/rcuctrs" looks as follows: - -CPU last cur F M - 0 5 -5 0 0 - 1 -1 0 0 0 - 2 0 1 0 0 - 3 0 1 0 0 - 4 0 1 0 0 - 5 0 1 0 0 - 6 0 2 0 0 - 7 0 -1 0 0 - 8 0 1 0 0 -ggp = 26226, state = waitzero - -The per-CPU fields are as follows: - -o "CPU" gives the CPU number. Offline CPUs are not displayed. - -o "last" gives the value of the counter that is being decremented - for the current grace period phase. In the example above, - the counters sum to 4, indicating that there are still four - RCU read-side critical sections still running that started - before the last counter flip. - -o "cur" gives the value of the counter that is currently being - both incremented (by rcu_read_lock()) and decremented (by - rcu_read_unlock()). In the example above, the counters sum to - 1, indicating that there is only one RCU read-side critical section - still running that started after the last counter flip. - -o "F" indicates whether RCU is waiting for this CPU to acknowledge - a counter flip. In the above example, RCU is not waiting on any, - which is consistent with the state being "waitzero" rather than - "waitack". - -o "M" indicates whether RCU is waiting for this CPU to execute a - memory barrier. In the above example, RCU is not waiting on any, - which is consistent with the state being "waitzero" rather than - "waitmb". - -o "ggp" is the global grace-period counter. - -o "state" is the RCU state, which can be one of the following: - - o "idle": there is no grace period in progress. - - o "waitack": RCU just incremented the global grace-period - counter, which has the effect of reversing the roles of - the "last" and "cur" counters above, and is waiting for - all the CPUs to acknowledge the flip. Once the flip has - been acknowledged, CPUs will no longer be incrementing - what are now the "last" counters, so that their sum will - decrease monotonically down to zero. - - o "waitzero": RCU is waiting for the sum of the "last" counters - to decrease to zero. - - o "waitmb": RCU is waiting for each CPU to execute a memory - barrier, which ensures that instructions from a given CPU's - last RCU read-side critical section cannot be reordered - with instructions following the memory-barrier instruction. - -The output of "cat rcu/rcugp" looks as follows: - -oldggp=48870 newggp=48873 - -Note that reading from this file provokes a synchronize_rcu(). The -"oldggp" value is that of "ggp" from rcu/rcuctrs above, taken before -executing the synchronize_rcu(), and the "newggp" value is also the -"ggp" value, but taken after the synchronize_rcu() command returns. - - -The output of "cat rcu/rcugp" looks as follows: - -na=1337955 nl=40 wa=1337915 wl=44 da=1337871 dl=0 dr=1337871 di=1337871 -1=50989 e1=6138 i1=49722 ie1=82 g1=49640 a1=315203 ae1=265563 a2=49640 -z1=1401244 ze1=1351605 z2=49639 m1=5661253 me1=5611614 m2=49639 - -These are counters tracking internal preemptable-RCU events, however, -some of them may be useful for debugging algorithms using RCU. In -particular, the "nl", "wl", and "dl" values track the number of RCU -callbacks in various states. The fields are as follows: - -o "na" is the total number of RCU callbacks that have been enqueued - since boot. - -o "nl" is the number of RCU callbacks waiting for the previous - grace period to end so that they can start waiting on the next - grace period. - -o "wa" is the total number of RCU callbacks that have started waiting - for a grace period since boot. "na" should be roughly equal to - "nl" plus "wa". - -o "wl" is the number of RCU callbacks currently waiting for their - grace period to end. - -o "da" is the total number of RCU callbacks whose grace periods - have completed since boot. "wa" should be roughly equal to - "wl" plus "da". - -o "dr" is the total number of RCU callbacks that have been removed - from the list of callbacks ready to invoke. "dr" should be roughly - equal to "da". - -o "di" is the total number of RCU callbacks that have been invoked - since boot. "di" should be roughly equal to "da", though some - early versions of preemptable RCU had a bug so that only the - last CPU's count of invocations was displayed, rather than the - sum of all CPU's counts. - -o "1" is the number of calls to rcu_try_flip(). This should be - roughly equal to the sum of "e1", "i1", "a1", "z1", and "m1" - described below. In other words, the number of times that - the state machine is visited should be equal to the sum of the - number of times that each state is visited plus the number of - times that the state-machine lock acquisition failed. - -o "e1" is the number of times that rcu_try_flip() was unable to - acquire the fliplock. - -o "i1" is the number of calls to rcu_try_flip_idle(). - -o "ie1" is the number of times rcu_try_flip_idle() exited early - due to the calling CPU having no work for RCU. - -o "g1" is the number of times that rcu_try_flip_idle() decided - to start a new grace period. "i1" should be roughly equal to - "ie1" plus "g1". - -o "a1" is the number of calls to rcu_try_flip_waitack(). - -o "ae1" is the number of times that rcu_try_flip_waitack() found - that at least one CPU had not yet acknowledge the new grace period - (AKA "counter flip"). - -o "a2" is the number of time rcu_try_flip_waitack() found that - all CPUs had acknowledged. "a1" should be roughly equal to - "ae1" plus "a2". (This particular output was collected on - a 128-CPU machine, hence the smaller-than-usual fraction of - calls to rcu_try_flip_waitack() finding all CPUs having already - acknowledged.) - -o "z1" is the number of calls to rcu_try_flip_waitzero(). - -o "ze1" is the number of times that rcu_try_flip_waitzero() found - that not all of the old RCU read-side critical sections had - completed. - -o "z2" is the number of times that rcu_try_flip_waitzero() finds - the sum of the counters equal to zero, in other words, that - all of the old RCU read-side critical sections had completed. - The value of "z1" should be roughly equal to "ze1" plus - "z2". - -o "m1" is the number of calls to rcu_try_flip_waitmb(). - -o "me1" is the number of times that rcu_try_flip_waitmb() finds - that at least one CPU has not yet executed a memory barrier. - -o "m2" is the number of times that rcu_try_flip_waitmb() finds that - all CPUs have executed a memory barrier. +The rcutree implementation of RCU provides debugfs trace output that +summarizes counters and state. This information is useful for debugging +RCU itself, and can sometimes also help to debug abuses of RCU. +The following sections describe the debugfs files and formats. Hierarchical RCU debugfs Files and Formats @@ -210,9 +35,10 @@ rcu_bh: 6 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=859/1 dn=0 df=15 of=0 ri=0 ql=0 b=10 7 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3761/1 dn=0 df=15 of=0 ri=0 ql=0 b=10 -The first section lists the rcu_data structures for rcu, the second for -rcu_bh. Each section has one line per CPU, or eight for this 8-CPU system. -The fields are as follows: +The first section lists the rcu_data structures for rcu_sched, the second +for rcu_bh. Note that CONFIG_TREE_PREEMPT_RCU kernels will have an +additional section for rcu_preempt. Each section has one line per CPU, +or eight for this 8-CPU system. The fields are as follows: o The number at the beginning of each line is the CPU number. CPUs numbers followed by an exclamation mark are offline, @@ -223,9 +49,9 @@ o The number at the beginning of each line is the CPU number. o "c" is the count of grace periods that this CPU believes have completed. CPUs in dynticks idle mode may lag quite a ways - behind, for example, CPU 4 under "rcu" above, which has slept - through the past 25 RCU grace periods. It is not unusual to - see CPUs lagging by thousands of grace periods. + behind, for example, CPU 4 under "rcu_sched" above, which has + slept through the past 25 RCU grace periods. It is not unusual + to see CPUs lagging by thousands of grace periods. o "g" is the count of grace periods that this CPU believes have started. Again, CPUs in dynticks idle mode may lag behind. @@ -308,8 +134,10 @@ The output of "cat rcu/rcugp" looks as follows: rcu_sched: completed=33062 gpnum=33063 rcu_bh: completed=464 gpnum=464 -Again, this output is for both "rcu" and "rcu_bh". The fields are -taken from the rcu_state structure, and are as follows: +Again, this output is for both "rcu_sched" and "rcu_bh". Note that +kernels built with CONFIG_TREE_PREEMPT_RCU will have an additional +"rcu_preempt" line. The fields are taken from the rcu_state structure, +and are as follows: o "completed" is the number of grace periods that have completed. It is comparable to the "c" field from rcu/rcudata in that a @@ -324,23 +152,24 @@ o "gpnum" is the number of grace periods that have started. It is If these two fields are equal (as they are for "rcu_bh" above), then there is no grace period in progress, in other words, RCU is idle. On the other hand, if the two fields differ (as they - do for "rcu" above), then an RCU grace period is in progress. + do for "rcu_sched" above), then an RCU grace period is in progress. The output of "cat rcu/rcuhier" looks as follows, with very long lines: -c=6902 g=6903 s=2 jfq=3 j=72c7 nfqs=13142/nfqsng=0(13142) fqlh=6 +c=6902 g=6903 s=2 jfq=3 j=72c7 nfqs=13142/nfqsng=0(13142) fqlh=6 oqlen=0 1/1 0:127 ^0 3/3 0:35 ^0 0/0 36:71 ^1 0/0 72:107 ^2 0/0 108:127 ^3 3/3f 0:5 ^0 2/3 6:11 ^1 0/0 12:17 ^2 0/0 18:23 ^3 0/0 24:29 ^4 0/0 30:35 ^5 0/0 36:41 ^0 0/0 42:47 ^1 0/0 48:53 ^2 0/0 54:59 ^3 0/0 60:65 ^4 0/0 66:71 ^5 0/0 72:77 ^0 0/0 78:83 ^1 0/0 84:89 ^2 0/0 90:95 ^3 0/0 96:101 ^4 0/0 102:107 ^5 0/0 108:113 ^0 0/0 114:119 ^1 0/0 120:125 ^2 0/0 126:127 ^3 rcu_bh: -c=-226 g=-226 s=1 jfq=-5701 j=72c7 nfqs=88/nfqsng=0(88) fqlh=0 +c=-226 g=-226 s=1 jfq=-5701 j=72c7 nfqs=88/nfqsng=0(88) fqlh=0 oqlen=0 0/1 0:127 ^0 0/3 0:35 ^0 0/0 36:71 ^1 0/0 72:107 ^2 0/0 108:127 ^3 0/3f 0:5 ^0 0/3 6:11 ^1 0/0 12:17 ^2 0/0 18:23 ^3 0/0 24:29 ^4 0/0 30:35 ^5 0/0 36:41 ^0 0/0 42:47 ^1 0/0 48:53 ^2 0/0 54:59 ^3 0/0 60:65 ^4 0/0 66:71 ^5 0/0 72:77 ^0 0/0 78:83 ^1 0/0 84:89 ^2 0/0 90:95 ^3 0/0 96:101 ^4 0/0 102:107 ^5 0/0 108:113 ^0 0/0 114:119 ^1 0/0 120:125 ^2 0/0 126:127 ^3 -This is once again split into "rcu" and "rcu_bh" portions. The fields are -as follows: +This is once again split into "rcu_sched" and "rcu_bh" portions, +and CONFIG_TREE_PREEMPT_RCU kernels will again have an additional +"rcu_preempt" section. The fields are as follows: o "c" is exactly the same as "completed" under rcu/rcugp. @@ -372,6 +201,11 @@ o "fqlh" is the number of calls to force_quiescent_state() that exited immediately (without even being counted in nfqs above) due to contention on ->fqslock. +o "oqlen" is the number of callbacks on the "orphan" callback + list. RCU callbacks are placed on this list by CPUs going + offline, and are "adopted" either by the CPU helping the outgoing + CPU or by the next rcu_barrier*() call, whichever comes first. + o Each element of the form "1/1 0:127 ^0" represents one struct rcu_node. Each line represents one level of the hierarchy, from root to leaves. It is best to think of the rcu_data structures @@ -389,10 +223,10 @@ o Each element of the form "1/1 0:127 ^0" represents one struct The value of qsmaskinit is assigned to that of qsmask at the beginning of each grace period. - For example, for "rcu", the qsmask of the first entry - of the lowest level is 0x14, meaning that we are still - waiting for CPUs 2 and 4 to check in for the current - grace period. + For example, for "rcu_sched", the qsmask of the first + entry of the lowest level is 0x14, meaning that we + are still waiting for CPUs 2 and 4 to check in for the + current grace period. o The numbers separated by the ":" are the range of CPUs served by this struct rcu_node. This can be helpful @@ -431,8 +265,9 @@ rcu_bh: 6 np=120834 qsp=9902 cbr=0 cng=0 gpc=6 gps=3 nf=2 nn=110921 7 np=144888 qsp=26336 cbr=0 cng=0 gpc=8 gps=2 nf=0 nn=118542 -As always, this is once again split into "rcu" and "rcu_bh" portions. -The fields are as follows: +As always, this is once again split into "rcu_sched" and "rcu_bh" +portions, with CONFIG_TREE_PREEMPT_RCU kernels having an additional +"rcu_preempt" section. The fields are as follows: o "np" is the number of times that __rcu_pending() has been invoked for the corresponding flavor of RCU. From 0edf1a683e499191b27a067956ae9f5fa6e046c6 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 14 Oct 2009 10:15:59 -0700 Subject: [PATCH 035/298] rcu: Update trace.txt documentation for blocked-tasks lists Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com Cc: npiggin@suse.de Cc: jens.axboe@oracle.com LKML-Reference: <12555405592804-git-send-email-> Signed-off-by: Ingo Molnar --- Documentation/RCU/trace.txt | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt index c1a95507d10..8608fd85e92 100644 --- a/Documentation/RCU/trace.txt +++ b/Documentation/RCU/trace.txt @@ -158,14 +158,14 @@ o "gpnum" is the number of grace periods that have started. It is The output of "cat rcu/rcuhier" looks as follows, with very long lines: c=6902 g=6903 s=2 jfq=3 j=72c7 nfqs=13142/nfqsng=0(13142) fqlh=6 oqlen=0 -1/1 0:127 ^0 -3/3 0:35 ^0 0/0 36:71 ^1 0/0 72:107 ^2 0/0 108:127 ^3 -3/3f 0:5 ^0 2/3 6:11 ^1 0/0 12:17 ^2 0/0 18:23 ^3 0/0 24:29 ^4 0/0 30:35 ^5 0/0 36:41 ^0 0/0 42:47 ^1 0/0 48:53 ^2 0/0 54:59 ^3 0/0 60:65 ^4 0/0 66:71 ^5 0/0 72:77 ^0 0/0 78:83 ^1 0/0 84:89 ^2 0/0 90:95 ^3 0/0 96:101 ^4 0/0 102:107 ^5 0/0 108:113 ^0 0/0 114:119 ^1 0/0 120:125 ^2 0/0 126:127 ^3 +1/1 .>. 0:127 ^0 +3/3 .>. 0:35 ^0 0/0 .>. 36:71 ^1 0/0 .>. 72:107 ^2 0/0 .>. 108:127 ^3 +3/3f .>. 0:5 ^0 2/3 .>. 6:11 ^1 0/0 .>. 12:17 ^2 0/0 .>. 18:23 ^3 0/0 .>. 24:29 ^4 0/0 .>. 30:35 ^5 0/0 .>. 36:41 ^0 0/0 .>. 42:47 ^1 0/0 .>. 48:53 ^2 0/0 .>. 54:59 ^3 0/0 .>. 60:65 ^4 0/0 .>. 66:71 ^5 0/0 .>. 72:77 ^0 0/0 .>. 78:83 ^1 0/0 .>. 84:89 ^2 0/0 .>. 90:95 ^3 0/0 .>. 96:101 ^4 0/0 .>. 102:107 ^5 0/0 .>. 108:113 ^0 0/0 .>. 114:119 ^1 0/0 .>. 120:125 ^2 0/0 .>. 126:127 ^3 rcu_bh: c=-226 g=-226 s=1 jfq=-5701 j=72c7 nfqs=88/nfqsng=0(88) fqlh=0 oqlen=0 -0/1 0:127 ^0 -0/3 0:35 ^0 0/0 36:71 ^1 0/0 72:107 ^2 0/0 108:127 ^3 -0/3f 0:5 ^0 0/3 6:11 ^1 0/0 12:17 ^2 0/0 18:23 ^3 0/0 24:29 ^4 0/0 30:35 ^5 0/0 36:41 ^0 0/0 42:47 ^1 0/0 48:53 ^2 0/0 54:59 ^3 0/0 60:65 ^4 0/0 66:71 ^5 0/0 72:77 ^0 0/0 78:83 ^1 0/0 84:89 ^2 0/0 90:95 ^3 0/0 96:101 ^4 0/0 102:107 ^5 0/0 108:113 ^0 0/0 114:119 ^1 0/0 120:125 ^2 0/0 126:127 ^3 +0/1 .>. 0:127 ^0 +0/3 .>. 0:35 ^0 0/0 .>. 36:71 ^1 0/0 .>. 72:107 ^2 0/0 .>. 108:127 ^3 +0/3f .>. 0:5 ^0 0/3 .>. 6:11 ^1 0/0 .>. 12:17 ^2 0/0 .>. 18:23 ^3 0/0 .>. 24:29 ^4 0/0 .>. 30:35 ^5 0/0 .>. 36:41 ^0 0/0 .>. 42:47 ^1 0/0 .>. 48:53 ^2 0/0 .>. 54:59 ^3 0/0 .>. 60:65 ^4 0/0 .>. 66:71 ^5 0/0 .>. 72:77 ^0 0/0 .>. 78:83 ^1 0/0 .>. 84:89 ^2 0/0 .>. 90:95 ^3 0/0 .>. 96:101 ^4 0/0 .>. 102:107 ^5 0/0 .>. 108:113 ^0 0/0 .>. 114:119 ^1 0/0 .>. 120:125 ^2 0/0 .>. 126:127 ^3 This is once again split into "rcu_sched" and "rcu_bh" portions, and CONFIG_TREE_PREEMPT_RCU kernels will again have an additional @@ -213,7 +213,7 @@ o Each element of the form "1/1 0:127 ^0" represents one struct might be either one, two, or three levels of rcu_node structures, depending on the relationship between CONFIG_RCU_FANOUT and CONFIG_NR_CPUS. - + o The numbers separated by the "/" are the qsmask followed by the qsmaskinit. The qsmask will have one bit set for each entity in the next lower level that @@ -228,6 +228,15 @@ o Each element of the form "1/1 0:127 ^0" represents one struct are still waiting for CPUs 2 and 4 to check in for the current grace period. + o The characters separated by the ">" indicate the state + of the blocked-tasks lists. A "T" preceding the ">" + indicates that at least one task blocked in an RCU + read-side critical section blocks the current grace + period, while a "." preceding the ">" indicates otherwise. + The character following the ">" indicates similarly for + the next grace period. A "T" should appear in this + field only for rcu-preempt. + o The numbers separated by the ":" are the range of CPUs served by this struct rcu_node. This can be helpful in working out how the hierarchy is wired together. From b7f3008ad1d795935551e4dd810b0255a7bfa3c9 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Mon, 19 Oct 2009 10:08:50 -0400 Subject: [PATCH 036/298] SELinux: fix locking issue introduced with c6d3aaa4e35c71a3 Ensure that we release the policy read lock on all exit paths from security_compute_av. Signed-off-by: Stephen D. Smalley Signed-off-by: James Morris --- security/selinux/ss/services.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index f270e378c0e..77f6e54bb43 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -935,19 +935,22 @@ int security_compute_av(u32 ssid, u32 requested; int rc; + read_lock(&policy_rwlock); + if (!ss_initialized) goto allow; - read_lock(&policy_rwlock); requested = unmap_perm(orig_tclass, orig_requested); tclass = unmap_class(orig_tclass); if (unlikely(orig_tclass && !tclass)) { if (policydb.allow_unknown) goto allow; - return -EINVAL; + rc = -EINVAL; + goto out; } rc = security_compute_av_core(ssid, tsid, tclass, requested, avd); map_decision(orig_tclass, avd, policydb.allow_unknown); +out: read_unlock(&policy_rwlock); return rc; allow: @@ -956,7 +959,8 @@ allow: avd->auditdeny = 0xffffffff; avd->seqno = latest_granting; avd->flags = 0; - return 0; + rc = 0; + goto out; } int security_compute_av_user(u32 ssid, From 3e1c2515acf70448cad1ae3ab835ca80be043d33 Mon Sep 17 00:00:00 2001 From: James Morris Date: Tue, 20 Oct 2009 13:48:33 +0900 Subject: [PATCH 037/298] security: remove root_plug Remove the root_plug example LSM code. It's unmaintained and increasingly broken in various ways. Made at the 2009 Kernel Summit in Tokyo! Acked-by: Greg Kroah-Hartman Signed-off-by: James Morris --- Documentation/kernel-parameters.txt | 10 ---- security/Kconfig | 13 ----- security/Makefile | 1 - security/commoncap.c | 2 +- security/root_plug.c | 90 ----------------------------- 5 files changed, 1 insertion(+), 115 deletions(-) delete mode 100644 security/root_plug.c diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 6fa7292947e..5d386b4ff6a 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -85,7 +85,6 @@ parameter is applicable: PPT Parallel port support is enabled. PS2 Appropriate PS/2 support is enabled. RAM RAM disk support is enabled. - ROOTPLUG The example Root Plug LSM is enabled. S390 S390 architecture is enabled. SCSI Appropriate SCSI support is enabled. A lot of drivers has their options described inside of @@ -2163,15 +2162,6 @@ and is between 256 and 4096 characters. It is defined in the file Useful for devices that are detected asynchronously (e.g. USB and MMC devices). - root_plug.vendor_id= - [ROOTPLUG] Override the default vendor ID - - root_plug.product_id= - [ROOTPLUG] Override the default product ID - - root_plug.debug= - [ROOTPLUG] Enable debugging output - rw [KNL] Mount root device read-write on boot S [KNL] Run init in single mode diff --git a/security/Kconfig b/security/Kconfig index fb363cd81cf..aeea8c2bb59 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -100,19 +100,6 @@ config SECURITY_FILE_CAPABILITIES If in doubt, answer N. -config SECURITY_ROOTPLUG - bool "Root Plug Support" - depends on USB=y && SECURITY - help - This is a sample LSM module that should only be used as such. - It prevents any programs running with egid == 0 if a specific - USB device is not present in the system. - - See for - more information about this module. - - If you are unsure how to answer this question, answer N. - config INTEL_TXT bool "Enable Intel(R) Trusted Execution Technology (Intel(R) TXT)" depends on HAVE_INTEL_TXT diff --git a/security/Makefile b/security/Makefile index 95ecc06392d..bb44e350c61 100644 --- a/security/Makefile +++ b/security/Makefile @@ -18,7 +18,6 @@ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o obj-$(CONFIG_AUDIT) += lsm_audit.o obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o -obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o # Object integrity file lists diff --git a/security/commoncap.c b/security/commoncap.c index fe30751a6cd..45b87af4ae5 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -1,4 +1,4 @@ -/* Common capabilities, needed by capability.o and root_plug.o +/* Common capabilities, needed by capability.o. * * 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 diff --git a/security/root_plug.c b/security/root_plug.c deleted file mode 100644 index 2f7ffa67c4d..00000000000 --- a/security/root_plug.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Root Plug sample LSM module - * - * Originally written for a Linux Journal. - * - * Copyright (C) 2002 Greg Kroah-Hartman - * - * Prevents any programs running with egid == 0 if a specific USB device - * is not present in the system. Yes, it can be gotten around, but is a - * nice starting point for people to play with, and learn the LSM - * interface. - * - * If you want to turn this into something with a semblance of security, - * you need to hook the task_* functions also. - * - * See http://www.linuxjournal.com/article.php?sid=6279 for more information - * about this code. - * - * 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. - */ - -#include -#include -#include -#include -#include - -/* default is a generic type of usb to serial converter */ -static int vendor_id = 0x0557; -static int product_id = 0x2008; - -module_param(vendor_id, uint, 0400); -module_param(product_id, uint, 0400); - -/* should we print out debug messages */ -static int debug = 0; - -module_param(debug, bool, 0600); - -#define MY_NAME "root_plug" - -#define root_dbg(fmt, arg...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG "%s: %s: " fmt , \ - MY_NAME , __func__ , \ - ## arg); \ - } while (0) - -static int rootplug_bprm_check_security (struct linux_binprm *bprm) -{ - struct usb_device *dev; - - root_dbg("file %s, e_uid = %d, e_gid = %d\n", - bprm->filename, bprm->cred->euid, bprm->cred->egid); - - if (bprm->cred->egid == 0) { - dev = usb_find_device(vendor_id, product_id); - if (!dev) { - root_dbg("e_gid = 0, and device not found, " - "task not allowed to run...\n"); - return -EPERM; - } - usb_put_dev(dev); - } - - return 0; -} - -static struct security_operations rootplug_security_ops = { - .bprm_check_security = rootplug_bprm_check_security, -}; - -static int __init rootplug_init (void) -{ - /* register ourselves with the security framework */ - if (register_security (&rootplug_security_ops)) { - printk (KERN_INFO - "Failure registering Root Plug module with the kernel\n"); - return -EINVAL; - } - printk (KERN_INFO "Root Plug module initialized, " - "vendor_id = %4.4x, product id = %4.4x\n", vendor_id, product_id); - return 0; -} - -security_initcall (rootplug_init); From 40b1f4e5113eafc5e84f2ba86822df66087fcb25 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Thu, 22 Oct 2009 14:39:28 +1100 Subject: [PATCH 038/298] irq: trivial: Fix typo in comment for #endif The comment suggests this #endif is CONFIG_X86 but it's really CONFIG_TRACE_IRQFLAGS_SUPPORT Signed-off-by: Michael Neuling Cc: michael@ellerman.id.au LKML-Reference: <18191.1256182768@neuling.org> Signed-off-by: Ingo Molnar --- include/linux/irqflags.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/irqflags.h b/include/linux/irqflags.h index b02a3f1d46a..006bf45eae3 100644 --- a/include/linux/irqflags.h +++ b/include/linux/irqflags.h @@ -124,6 +124,6 @@ typecheck(unsigned long, flags); \ raw_irqs_disabled_flags(flags); \ }) -#endif /* CONFIG_X86 */ +#endif /* CONFIG_TRACE_IRQFLAGS_SUPPORT */ #endif From 72f279b256d520e321a850880d094bc0bcbf45d6 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Thu, 22 Oct 2009 19:19:34 +0800 Subject: [PATCH 039/298] generic-ipi: Fix misleading smp_call_function*() description After commit:8969a5ede0f9e17da4b943712429aef2c9bcd82b "generic-ipi: remove kmalloc()", wait = 0 can be guaranteed. Signed-off-by: Sheng Yang Cc: Peter Zijlstra Cc: Jens Axboe Cc: Nick Piggin LKML-Reference: <1256210374-25354-1-git-send-email-sheng@linux.intel.com> Signed-off-by: Ingo Molnar --- kernel/smp.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/kernel/smp.c b/kernel/smp.c index c9d1c7835c2..8bd618f0364 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -265,9 +265,7 @@ static DEFINE_PER_CPU(struct call_single_data, csd_data); * @info: An arbitrary pointer to pass to the function. * @wait: If true, wait until function has completed on other CPUs. * - * Returns 0 on success, else a negative status code. Note that @wait - * will be implicitly turned on in case of allocation failures, since - * we fall back to on-stack allocation. + * Returns 0 on success, else a negative status code. */ int smp_call_function_single(int cpu, void (*func) (void *info), void *info, int wait) @@ -355,9 +353,7 @@ void __smp_call_function_single(int cpu, struct call_single_data *data, * @wait: If true, wait (atomically) until function has completed * on other CPUs. * - * If @wait is true, then returns once @func has returned. Note that @wait - * will be implicitly turned on in case of allocation failures, since - * we fall back to on-stack allocation. + * If @wait is true, then returns once @func has returned. * * You must not call this function with disabled interrupts or from a * hardware interrupt handler or from a bottom half handler. Preemption @@ -443,8 +439,7 @@ EXPORT_SYMBOL(smp_call_function_many); * Returns 0. * * If @wait is true, then returns once @func has returned; otherwise - * it returns just before the target cpu calls @func. In case of allocation - * failure, @wait will be implicitly turned on. + * it returns just before the target cpu calls @func. * * You must not call this function with disabled interrupts or from a * hardware interrupt handler or from a bottom half handler. From 5c828713358cb9df8aa174371edcbbb62203a490 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 23 Oct 2009 14:58:11 +0200 Subject: [PATCH 040/298] ratelimit: Make suppressed output messages more useful Today I got: [39648.224782] Registered led device: iwl-phy0::TX [40676.545099] __ratelimit: 246 callbacks suppressed [40676.545103] abcdef[23675]: segfault at 0 ... as you can see the ratelimit message contains a function prefix. Since this is always __ratelimit, this wont help much. This patch changes __ratelimit and printk_ratelimit to print the function name that calls ratelimit. This will pinpoint the responsible function, as long as not several different places call ratelimit with the same ratelimit state at the same time. In that case we catch only one random function that calls ratelimit after the wait period. Signed-off-by: Christian Borntraeger Cc: Dave Young Cc: Linus Torvalds CC: Andrew Morton LKML-Reference: <200910231458.11832.borntraeger@de.ibm.com> Signed-off-by: Ingo Molnar --- include/linux/kernel.h | 3 ++- include/linux/ratelimit.h | 3 ++- kernel/printk.c | 6 +++--- lib/ratelimit.c | 6 +++--- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 3305f33201b..21d0d822c71 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -240,7 +240,8 @@ asmlinkage int vprintk(const char *fmt, va_list args) asmlinkage int printk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))) __cold; -extern int printk_ratelimit(void); +extern int __printk_ratelimit(const char *func); +#define printk_ratelimit() __printk_ratelimit(__func__) extern bool printk_timed_ratelimit(unsigned long *caller_jiffies, unsigned int interval_msec); diff --git a/include/linux/ratelimit.h b/include/linux/ratelimit.h index 187bc16c1f1..668cf1bef03 100644 --- a/include/linux/ratelimit.h +++ b/include/linux/ratelimit.h @@ -25,6 +25,7 @@ struct ratelimit_state { .burst = burst_init, \ } -extern int __ratelimit(struct ratelimit_state *rs); +extern int ___ratelimit(struct ratelimit_state *rs, const char *func); +#define __ratelimit(state) ___ratelimit(state, __func__) #endif /* _LINUX_RATELIMIT_H */ diff --git a/kernel/printk.c b/kernel/printk.c index b997c893cdc..8283dbe15af 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -1364,11 +1364,11 @@ late_initcall(disable_boot_consoles); */ DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10); -int printk_ratelimit(void) +int __printk_ratelimit(const char *func) { - return __ratelimit(&printk_ratelimit_state); + return ___ratelimit(&printk_ratelimit_state, func); } -EXPORT_SYMBOL(printk_ratelimit); +EXPORT_SYMBOL(__printk_ratelimit); /** * printk_timed_ratelimit - caller-controlled printk ratelimiting diff --git a/lib/ratelimit.c b/lib/ratelimit.c index 5551731ae1d..09f5ce1810d 100644 --- a/lib/ratelimit.c +++ b/lib/ratelimit.c @@ -20,7 +20,7 @@ * This enforces a rate limit: not more than @rs->ratelimit_burst callbacks * in every @rs->ratelimit_jiffies */ -int __ratelimit(struct ratelimit_state *rs) +int ___ratelimit(struct ratelimit_state *rs, const char *func) { unsigned long flags; int ret; @@ -43,7 +43,7 @@ int __ratelimit(struct ratelimit_state *rs) if (time_is_before_jiffies(rs->begin + rs->interval)) { if (rs->missed) printk(KERN_WARNING "%s: %d callbacks suppressed\n", - __func__, rs->missed); + func, rs->missed); rs->begin = 0; rs->printed = 0; rs->missed = 0; @@ -59,4 +59,4 @@ int __ratelimit(struct ratelimit_state *rs) return ret; } -EXPORT_SYMBOL(__ratelimit); +EXPORT_SYMBOL(___ratelimit); From 6e8e16c7bc298d7887584c3d027e05db3e86eed9 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Thu, 22 Oct 2009 15:38:26 -0400 Subject: [PATCH 041/298] SELinux: add .gitignore files for dynamic classes The SELinux dynamic class work in c6d3aaa4e35c71a32a86ececacd4eea7ecfc316c creates a number of dynamic header files and scripts. Add .gitignore files so git doesn't complain about these. Signed-off-by: Eric Paris Acked-by: Stephen D. Smalley Signed-off-by: James Morris --- Documentation/dontdiff | 3 +++ scripts/selinux/genheaders/.gitignore | 1 + security/selinux/.gitignore | 2 ++ 3 files changed, 6 insertions(+) create mode 100644 scripts/selinux/genheaders/.gitignore create mode 100644 security/selinux/.gitignore diff --git a/Documentation/dontdiff b/Documentation/dontdiff index e1efc400bed..e151b2a3626 100644 --- a/Documentation/dontdiff +++ b/Documentation/dontdiff @@ -65,6 +65,7 @@ aicdb.h* asm-offsets.h asm_offsets.h autoconf.h* +av_permissions.h bbootsect bin2c binkernel.spec @@ -95,12 +96,14 @@ docproc elf2ecoff elfconfig.h* fixdep +flask.h fore200e_mkfirm fore200e_pca_fw.c* gconf gen-devlist gen_crc32table gen_init_cpio +genheaders genksyms *_gray256.c ihex2fw diff --git a/scripts/selinux/genheaders/.gitignore b/scripts/selinux/genheaders/.gitignore new file mode 100644 index 00000000000..4c0b646ff8d --- /dev/null +++ b/scripts/selinux/genheaders/.gitignore @@ -0,0 +1 @@ +genheaders diff --git a/security/selinux/.gitignore b/security/selinux/.gitignore new file mode 100644 index 00000000000..2e5040a3d48 --- /dev/null +++ b/security/selinux/.gitignore @@ -0,0 +1,2 @@ +av_permissions.h +flask.h From bb015f0c85362aa767f8f00f50a40d85e489414f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 19 Oct 2009 11:43:32 +0200 Subject: [PATCH 042/298] pcmcia: drop already defined PCI_IDs Out of 10 PCI_IDs found in the PCMCIA subsystem, only two were not defined in pci_ids.h. Move them and drop the duplicates. Successfully build-tested. Signed-off-by: Wolfram Sang Cc: Jesse Barnes Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cirrus.h | 10 ---------- drivers/pcmcia/o2micro.h | 22 ---------------------- include/linux/pci_ids.h | 2 ++ 3 files changed, 2 insertions(+), 32 deletions(-) diff --git a/drivers/pcmcia/cirrus.h b/drivers/pcmcia/cirrus.h index ecd4fc7f666..446a4576e73 100644 --- a/drivers/pcmcia/cirrus.h +++ b/drivers/pcmcia/cirrus.h @@ -30,16 +30,6 @@ #ifndef _LINUX_CIRRUS_H #define _LINUX_CIRRUS_H -#ifndef PCI_VENDOR_ID_CIRRUS -#define PCI_VENDOR_ID_CIRRUS 0x1013 -#endif -#ifndef PCI_DEVICE_ID_CIRRUS_6729 -#define PCI_DEVICE_ID_CIRRUS_6729 0x1100 -#endif -#ifndef PCI_DEVICE_ID_CIRRUS_6832 -#define PCI_DEVICE_ID_CIRRUS_6832 0x1110 -#endif - #define PD67_MISC_CTL_1 0x16 /* Misc control 1 */ #define PD67_FIFO_CTL 0x17 /* FIFO control */ #define PD67_MISC_CTL_2 0x1E /* Misc control 2 */ diff --git a/drivers/pcmcia/o2micro.h b/drivers/pcmcia/o2micro.h index 72188c462c9..624442fc0d3 100644 --- a/drivers/pcmcia/o2micro.h +++ b/drivers/pcmcia/o2micro.h @@ -30,28 +30,6 @@ #ifndef _LINUX_O2MICRO_H #define _LINUX_O2MICRO_H -#ifndef PCI_VENDOR_ID_O2 -#define PCI_VENDOR_ID_O2 0x1217 -#endif -#ifndef PCI_DEVICE_ID_O2_6729 -#define PCI_DEVICE_ID_O2_6729 0x6729 -#endif -#ifndef PCI_DEVICE_ID_O2_6730 -#define PCI_DEVICE_ID_O2_6730 0x673a -#endif -#ifndef PCI_DEVICE_ID_O2_6832 -#define PCI_DEVICE_ID_O2_6832 0x6832 -#endif -#ifndef PCI_DEVICE_ID_O2_6836 -#define PCI_DEVICE_ID_O2_6836 0x6836 -#endif -#ifndef PCI_DEVICE_ID_O2_6812 -#define PCI_DEVICE_ID_O2_6812 0x6872 -#endif -#ifndef PCI_DEVICE_ID_O2_6933 -#define PCI_DEVICE_ID_O2_6933 0x6933 -#endif - /* Additional PCI configuration registers */ #define O2_MUX_CONTROL 0x90 /* 32 bit */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index f490e7a7307..857cc349bf7 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1632,6 +1632,8 @@ #define PCI_DEVICE_ID_O2_6730 0x673a #define PCI_DEVICE_ID_O2_6832 0x6832 #define PCI_DEVICE_ID_O2_6836 0x6836 +#define PCI_DEVICE_ID_O2_6812 0x6872 +#define PCI_DEVICE_ID_O2_6933 0x6933 #define PCI_VENDOR_ID_3DFX 0x121a #define PCI_DEVICE_ID_3DFX_VOODOO 0x0001 From 6ae3b84d979308671bf6f6a2123c258a8603d61c Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sun, 18 Oct 2009 18:14:32 +0200 Subject: [PATCH 043/298] serial_cs: use pcmcia_loop_config() and pre-determined values As the PCMCIA core already determines the multifunction count, the ConfigBase address and the Present value, we can use them directly instead of parsing the CIS again. By making use of pcmcia_loop_config(), we can further remove the remaining call to pcmcia_get_first_tuple() and friends. CC: linux-serial@vger.kernel.org CC: Russell King Signed-off-by: Dominik Brodowski --- drivers/serial/serial_cs.c | 87 ++++++++++---------------------------- 1 file changed, 23 insertions(+), 64 deletions(-) diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index ff4617e2142..7bf02cf3123 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -426,21 +426,6 @@ static int setup_serial(struct pcmcia_device *handle, struct serial_info * info, /*====================================================================*/ -static int -first_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse) -{ - int i; - i = pcmcia_get_first_tuple(handle, tuple); - if (i != 0) - return i; - i = pcmcia_get_tuple_data(handle, tuple); - if (i != 0) - return i; - return pcmcia_parse_tuple(tuple, parse); -} - -/*====================================================================*/ - static int simple_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cf, cistpl_cftable_entry_t *dflt, @@ -665,6 +650,25 @@ static int multi_config(struct pcmcia_device *link) return 0; } +static int serial_check_for_multi(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cf, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + struct serial_info *info = p_dev->priv; + + if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) + info->multi = cf->io.win[0].len >> 3; + + if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && + (cf->io.win[1].len == 8)) + info->multi = 2; + + return 0; /* break */ +} + + /*====================================================================== serial_config() is scheduled to run after a CARD_INSERTION event @@ -676,46 +680,14 @@ static int multi_config(struct pcmcia_device *link) static int serial_config(struct pcmcia_device * link) { struct serial_info *info = link->priv; - struct serial_cfg_mem *cfg_mem; - tuple_t *tuple; - u_char *buf; - cisparse_t *parse; - cistpl_cftable_entry_t *cf; - int i, last_ret, last_fn; + int i; DEBUG(0, "serial_config(0x%p)\n", link); - cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL); - if (!cfg_mem) - goto failed; - - tuple = &cfg_mem->tuple; - parse = &cfg_mem->parse; - cf = &parse->cftable_entry; - buf = cfg_mem->buf; - - tuple->TupleData = (cisdata_t *) buf; - tuple->TupleOffset = 0; - tuple->TupleDataMax = 255; - tuple->Attributes = 0; - - /* Get configuration register information */ - tuple->DesiredTuple = CISTPL_CONFIG; - last_ret = first_tuple(link, tuple, parse); - if (last_ret != 0) { - last_fn = ParseTuple; - goto cs_failed; - } - link->conf.ConfigBase = parse->config.base; - link->conf.Present = parse->config.rmask[0]; - /* Is this a compliant multifunction card? */ - tuple->DesiredTuple = CISTPL_LONGLINK_MFC; - tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; - info->multi = (first_tuple(link, tuple, parse) == 0); + info->multi = (link->socket->functions > 1); /* Is this a multiport card? */ - tuple->DesiredTuple = CISTPL_MANFID; info->manfid = link->manf_id; info->prodid = link->card_id; @@ -730,20 +702,11 @@ static int serial_config(struct pcmcia_device * link) /* Another check for dual-serial cards: look for either serial or multifunction cards that ask for appropriate IO port ranges */ - tuple->DesiredTuple = CISTPL_FUNCID; if ((info->multi == 0) && (link->has_func_id) && ((link->func_id == CISTPL_FUNCID_MULTI) || - (link->func_id == CISTPL_FUNCID_SERIAL))) { - tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; - if (first_tuple(link, tuple, parse) == 0) { - if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) - info->multi = cf->io.win[0].len >> 3; - if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && - (cf->io.win[1].len == 8)) - info->multi = 2; - } - } + (link->func_id == CISTPL_FUNCID_SERIAL))) + pcmcia_loop_config(link, serial_check_for_multi, info); /* * Apply any multi-port quirk. @@ -768,14 +731,10 @@ static int serial_config(struct pcmcia_device * link) goto failed; link->dev_node = &info->node[0]; - kfree(cfg_mem); return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: serial_remove(link); - kfree(cfg_mem); return -ENODEV; } From 6c21a7fb492bf7e2c4985937082ce58ddeca84bd Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Thu, 22 Oct 2009 17:30:13 -0400 Subject: [PATCH 044/298] LSM: imbed ima calls in the security hooks Based on discussions on LKML and LSM, where there are consecutive security_ and ima_ calls in the vfs layer, move the ima_ calls to the existing security_ hooks. Signed-off-by: Mimi Zohar Signed-off-by: James Morris --- fs/exec.c | 4 ---- fs/file_table.c | 2 -- fs/inode.c | 10 ---------- mm/mmap.c | 4 ---- security/integrity/ima/Kconfig | 1 + security/security.c | 28 +++++++++++++++++++++++++--- 6 files changed, 26 insertions(+), 23 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index d49be6bc179..d164342c2b6 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include @@ -1209,9 +1208,6 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) struct linux_binfmt *fmt; retval = security_bprm_check(bprm); - if (retval) - return retval; - retval = ima_bprm_check(bprm); if (retval) return retval; diff --git a/fs/file_table.c b/fs/file_table.c index 8eb44042e00..4bef4c01ec6 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -280,7 +279,6 @@ void __fput(struct file *file) if (file->f_op && file->f_op->release) file->f_op->release(inode, file); security_file_free(file); - ima_file_free(file); if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) cdev_put(inode->i_cdev); fops_put(file->f_op); diff --git a/fs/inode.c b/fs/inode.c index 4d8e3be5597..06c1f02de61 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -157,11 +156,6 @@ int inode_init_always(struct super_block *sb, struct inode *inode) if (security_inode_alloc(inode)) goto out; - - /* allocate and initialize an i_integrity */ - if (ima_inode_alloc(inode)) - goto out_free_security; - spin_lock_init(&inode->i_lock); lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key); @@ -201,9 +195,6 @@ int inode_init_always(struct super_block *sb, struct inode *inode) #endif return 0; - -out_free_security: - security_inode_free(inode); out: return -ENOMEM; } @@ -235,7 +226,6 @@ static struct inode *alloc_inode(struct super_block *sb) void __destroy_inode(struct inode *inode) { BUG_ON(inode_has_buffers(inode)); - ima_inode_free(inode); security_inode_free(inode); fsnotify_inode_delete(inode); #ifdef CONFIG_FS_POSIX_ACL diff --git a/mm/mmap.c b/mm/mmap.c index 73f5e4b6401..292ddc3cef9 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -1059,9 +1058,6 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, } error = security_file_mmap(file, reqprot, prot, flags, addr, 0); - if (error) - return error; - error = ima_file_mmap(file, prot); if (error) return error; diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 53d9764e8f0..3d7846de806 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -3,6 +3,7 @@ config IMA bool "Integrity Measurement Architecture(IMA)" depends on ACPI + depends on SECURITY select SECURITYFS select CRYPTO select CRYPTO_HMAC diff --git a/security/security.c b/security/security.c index 279757314a0..684d5ee655d 100644 --- a/security/security.c +++ b/security/security.c @@ -16,6 +16,7 @@ #include #include #include +#include /* Boot-time LSM user choice */ static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1]; @@ -235,7 +236,12 @@ int security_bprm_set_creds(struct linux_binprm *bprm) int security_bprm_check(struct linux_binprm *bprm) { - return security_ops->bprm_check_security(bprm); + int ret; + + ret = security_ops->bprm_check_security(bprm); + if (ret) + return ret; + return ima_bprm_check(bprm); } void security_bprm_committing_creds(struct linux_binprm *bprm) @@ -352,12 +358,21 @@ EXPORT_SYMBOL(security_sb_parse_opts_str); int security_inode_alloc(struct inode *inode) { + int ret; + inode->i_security = NULL; - return security_ops->inode_alloc_security(inode); + ret = security_ops->inode_alloc_security(inode); + if (ret) + return ret; + ret = ima_inode_alloc(inode); + if (ret) + security_inode_free(inode); + return ret; } void security_inode_free(struct inode *inode) { + ima_inode_free(inode); security_ops->inode_free_security(inode); } @@ -648,6 +663,8 @@ int security_file_alloc(struct file *file) void security_file_free(struct file *file) { security_ops->file_free_security(file); + if (file->f_dentry) + ima_file_free(file); } int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -659,7 +676,12 @@ int security_file_mmap(struct file *file, unsigned long reqprot, unsigned long prot, unsigned long flags, unsigned long addr, unsigned long addr_only) { - return security_ops->file_mmap(file, reqprot, prot, flags, addr, addr_only); + int ret; + + ret = security_ops->file_mmap(file, reqprot, prot, flags, addr, addr_only); + if (ret) + return ret; + return ima_file_mmap(file, prot); } int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, From 9b1d82fa1611706fa7ee1505f290160a18caf95d Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 25 Oct 2009 19:03:50 -0700 Subject: [PATCH 045/298] rcu: "Tiny RCU", The Bloatwatch Edition This patch is a version of RCU designed for !SMP provided for a small-footprint RCU implementation. In particular, the implementation of synchronize_rcu() is extremely lightweight and high performance. It passes rcutorture testing in each of the four relevant configurations (combinations of NO_HZ and PREEMPT) on x86. This saves about 1K bytes compared to old Classic RCU (which is no longer in mainline), and more than three kilobytes compared to Hierarchical RCU (updated to 2.6.30): CONFIG_TREE_RCU: text data bss dec filename 183 4 0 187 kernel/rcupdate.o 2783 520 36 3339 kernel/rcutree.o 3526 Total (vs 4565 for v7) CONFIG_TREE_PREEMPT_RCU: text data bss dec filename 263 4 0 267 kernel/rcupdate.o 4594 776 52 5422 kernel/rcutree.o 5689 Total (6155 for v7) CONFIG_TINY_RCU: text data bss dec filename 96 4 0 100 kernel/rcupdate.o 734 24 0 758 kernel/rcutiny.o 858 Total (vs 848 for v7) The above is for x86. Your mileage may vary on other platforms. Further compression is possible, but is being procrastinated. Changes from v7 (http://lkml.org/lkml/2009/10/9/388) o Apply Lai Jiangshan's review comments (aside from might_sleep() in synchronize_sched(), which is covered by SMP builds). o Fix up expedited primitives. Changes from v6 (http://lkml.org/lkml/2009/9/23/293). o Forward ported to put it into the 2.6.33 stream. o Added lockdep support. o Make lightweight rcu_barrier. Changes from v5 (http://lkml.org/lkml/2009/6/23/12). o Ported to latest pre-2.6.32 merge window kernel. - Renamed rcu_qsctr_inc() to rcu_sched_qs(). - Renamed rcu_bh_qsctr_inc() to rcu_bh_qs(). - Provided trivial rcu_cpu_notify(). - Provided trivial exit_rcu(). - Provided trivial rcu_needs_cpu(). - Fixed up the rcu_*_enter/exit() functions in linux/hardirq.h. o Removed the dependence on EMBEDDED, with a view to making TINY_RCU default for !SMP at some time in the future. o Added (trivial) support for expedited grace periods. Changes from v4 (http://lkml.org/lkml/2009/5/2/91) include: o Squeeze the size down a bit further by removing the ->completed field from struct rcu_ctrlblk. o This permits synchronize_rcu() to become the empty function. Previous concerns about rcutorture were unfounded, as rcutorture correctly handles a constant value from rcu_batches_completed() and rcu_batches_completed_bh(). Changes from v3 (http://lkml.org/lkml/2009/3/29/221) include: o Changed rcu_batches_completed(), rcu_batches_completed_bh() rcu_enter_nohz(), rcu_exit_nohz(), rcu_nmi_enter(), and rcu_nmi_exit(), to be static inlines, as suggested by David Howells. Doing this saves about 100 bytes from rcutiny.o. (The numbers between v3 and this v4 of the patch are not directly comparable, since they are against different versions of Linux.) Changes from v2 (http://lkml.org/lkml/2009/2/3/333) include: o Fix whitespace issues. o Change short-circuit "||" operator to instead be "+" in order to fix performance bug noted by "kraai" on LWN. (http://lwn.net/Articles/324348/) Changes from v1 (http://lkml.org/lkml/2009/1/13/440) include: o This version depends on EMBEDDED as well as !SMP, as suggested by Ingo. o Updated rcu_needs_cpu() to unconditionally return zero, permitting the CPU to enter dynticks-idle mode at any time. This works because callbacks can be invoked upon entry to dynticks-idle mode. o Paul is now OK with this being included, based on a poll at the Kernel Miniconf at linux.conf.au, where about ten people said that they cared about saving 900 bytes on single-CPU systems. o Applies to both mainline and tip/core/rcu. Signed-off-by: Paul E. McKenney Acked-by: David Howells Acked-by: Josh Triplett Reviewed-by: Lai Jiangshan Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: avi@redhat.com Cc: mtosatti@redhat.com LKML-Reference: <12565226351355-git-send-email-> Signed-off-by: Ingo Molnar --- include/linux/hardirq.h | 24 ++++ include/linux/rcupdate.h | 6 + include/linux/rcutiny.h | 97 +++++++++++++ init/Kconfig | 9 ++ kernel/Makefile | 1 + kernel/rcupdate.c | 4 + kernel/rcutiny.c | 294 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 435 insertions(+) create mode 100644 include/linux/rcutiny.h create mode 100644 kernel/rcutiny.c diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index 6d527ee82b2..d5b387669da 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -139,10 +139,34 @@ static inline void account_system_vtime(struct task_struct *tsk) #endif #if defined(CONFIG_NO_HZ) +#if defined(CONFIG_TINY_RCU) +extern void rcu_enter_nohz(void); +extern void rcu_exit_nohz(void); + +static inline void rcu_irq_enter(void) +{ + rcu_exit_nohz(); +} + +static inline void rcu_irq_exit(void) +{ + rcu_enter_nohz(); +} + +static inline void rcu_nmi_enter(void) +{ +} + +static inline void rcu_nmi_exit(void) +{ +} + +#else extern void rcu_irq_enter(void); extern void rcu_irq_exit(void); extern void rcu_nmi_enter(void); extern void rcu_nmi_exit(void); +#endif #else # define rcu_irq_enter() do { } while (0) # define rcu_irq_exit() do { } while (0) diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 3ebd0b7bcb0..6dd71fa4842 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -68,11 +68,17 @@ extern int sched_expedited_torture_stats(char *page); /* Internal to kernel */ extern void rcu_init(void); extern void rcu_scheduler_starting(void); +#ifndef CONFIG_TINY_RCU extern int rcu_needs_cpu(int cpu); +#else +static inline int rcu_needs_cpu(int cpu) { return 0; } +#endif extern int rcu_scheduler_active; #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) #include +#elif CONFIG_TINY_RCU +#include #else #error "Unknown RCU implementation specified to kernel configuration" #endif diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h new file mode 100644 index 00000000000..891073c264d --- /dev/null +++ b/include/linux/rcutiny.h @@ -0,0 +1,97 @@ +/* + * Read-Copy Update mechanism for mutual exclusion, the Bloatwatch edition. + * + * 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. + * + * Copyright IBM Corporation, 2008 + * + * Author: Paul E. McKenney + * + * For detailed explanation of Read-Copy Update mechanism see - + * Documentation/RCU + */ + +#ifndef __LINUX_TINY_H +#define __LINUX_TINY_H + +#include + +void rcu_sched_qs(int cpu); +void rcu_bh_qs(int cpu); + +#define __rcu_read_lock() preempt_disable() +#define __rcu_read_unlock() preempt_enable() +#define __rcu_read_lock_bh() local_bh_disable() +#define __rcu_read_unlock_bh() local_bh_enable() +#define call_rcu_sched call_rcu + +#define rcu_init_sched() do { } while (0) +extern void rcu_check_callbacks(int cpu, int user); +extern void __rcu_init(void); + +/* + * Return the number of grace periods. + */ +static inline long rcu_batches_completed(void) +{ + return 0; +} + +/* + * Return the number of bottom-half grace periods. + */ +static inline long rcu_batches_completed_bh(void) +{ + return 0; +} + +extern int rcu_expedited_torture_stats(char *page); + +static inline void synchronize_rcu_expedited(void) +{ + synchronize_sched(); +} + +static inline void synchronize_rcu_bh_expedited(void) +{ + synchronize_sched(); +} + +struct notifier_block; +extern int rcu_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu); + +#ifdef CONFIG_NO_HZ + +extern void rcu_enter_nohz(void); +extern void rcu_exit_nohz(void); + +#else /* #ifdef CONFIG_NO_HZ */ + +static inline void rcu_enter_nohz(void) +{ +} + +static inline void rcu_exit_nohz(void) +{ +} + +#endif /* #else #ifdef CONFIG_NO_HZ */ + +static inline void exit_rcu(void) +{ +} + +#endif /* __LINUX_RCUTINY_H */ diff --git a/init/Kconfig b/init/Kconfig index 09c5c6431f4..d367bf6bcc3 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -334,6 +334,15 @@ config TREE_PREEMPT_RCU is also required. It also scales down nicely to smaller systems. +config TINY_RCU + bool "UP-only small-memory-footprint RCU" + depends on !SMP + help + This option selects the RCU implementation that is + designed for UP systems from which real-time response + is not required. This option greatly reduces the + memory footprint of RCU. + endchoice config RCU_TRACE diff --git a/kernel/Makefile b/kernel/Makefile index b8d4cd8ac0b..e9a0e6ed25c 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o obj-$(CONFIG_TREE_RCU) += rcutree.o obj-$(CONFIG_TREE_PREEMPT_RCU) += rcutree.o obj-$(CONFIG_TREE_RCU_TRACE) += rcutree_trace.o +obj-$(CONFIG_TINY_RCU) += rcutiny.o obj-$(CONFIG_RELAY) += relay.o obj-$(CONFIG_SYSCTL) += utsname_sysctl.o obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index 400183346ad..7625f207f65 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -67,6 +67,8 @@ void wakeme_after_rcu(struct rcu_head *head) complete(&rcu->completion); } +#ifndef CONFIG_TINY_RCU + #ifdef CONFIG_TREE_PREEMPT_RCU /** @@ -157,6 +159,8 @@ void synchronize_rcu_bh(void) } EXPORT_SYMBOL_GPL(synchronize_rcu_bh); +#endif /* #ifndef CONFIG_TINY_RCU */ + static int __cpuinit rcu_barrier_cpu_hotplug(struct notifier_block *self, unsigned long action, void *hcpu) { diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c new file mode 100644 index 00000000000..0b54efde66a --- /dev/null +++ b/kernel/rcutiny.c @@ -0,0 +1,294 @@ +/* + * Read-Copy Update mechanism for mutual exclusion, the Bloatwatch edition. + * + * 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. + * + * Copyright IBM Corporation, 2008 + * + * Author: Paul E. McKenney + * + * For detailed explanation of Read-Copy Update mechanism see - + * Documentation/RCU + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Global control variables for rcupdate callback mechanism. */ +struct rcu_ctrlblk { + struct rcu_head *rcucblist; /* List of pending callbacks (CBs). */ + struct rcu_head **donetail; /* ->next pointer of last "done" CB. */ + struct rcu_head **curtail; /* ->next pointer of last CB. */ +}; + +/* Definition for rcupdate control block. */ +static struct rcu_ctrlblk rcu_ctrlblk = { + .rcucblist = NULL, + .donetail = &rcu_ctrlblk.rcucblist, + .curtail = &rcu_ctrlblk.rcucblist, +}; +static struct rcu_ctrlblk rcu_bh_ctrlblk = { + .rcucblist = NULL, + .donetail = &rcu_bh_ctrlblk.rcucblist, + .curtail = &rcu_bh_ctrlblk.rcucblist, +}; + +#ifdef CONFIG_NO_HZ + +static long rcu_dynticks_nesting = 1; + +/* + * Enter dynticks-idle mode, which is an extended quiescent state + * if we have fully entered that mode (i.e., if the new value of + * dynticks_nesting is zero). + */ +void rcu_enter_nohz(void) +{ + if (--rcu_dynticks_nesting == 0) + rcu_sched_qs(0); /* implies rcu_bh_qsctr_inc(0) */ +} + +/* + * Exit dynticks-idle mode, so that we are no longer in an extended + * quiescent state. + */ +void rcu_exit_nohz(void) +{ + rcu_dynticks_nesting++; +} + +#endif /* #ifdef CONFIG_NO_HZ */ + +/* + * Helper function for rcu_qsctr_inc() and rcu_bh_qsctr_inc(). + * Also disable irqs to avoid confusion due to interrupt handlers invoking + * call_rcu(). + */ +static int rcu_qsctr_help(struct rcu_ctrlblk *rcp) +{ + unsigned long flags; + + local_irq_save(flags); + if (rcp->rcucblist != NULL && + rcp->donetail != rcp->curtail) { + rcp->donetail = rcp->curtail; + local_irq_restore(flags); + return 1; + } + local_irq_restore(flags); + return 0; +} + +/* + * Record an rcu quiescent state. And an rcu_bh quiescent state while we + * are at it, given that any rcu quiescent state is also an rcu_bh + * quiescent state. Use "+" instead of "||" to defeat short circuiting. + */ +void rcu_sched_qs(int cpu) +{ + if (rcu_qsctr_help(&rcu_ctrlblk) + rcu_qsctr_help(&rcu_bh_ctrlblk)) + raise_softirq(RCU_SOFTIRQ); +} + +/* + * Record an rcu_bh quiescent state. + */ +void rcu_bh_qs(int cpu) +{ + if (rcu_qsctr_help(&rcu_bh_ctrlblk)) + raise_softirq(RCU_SOFTIRQ); +} + +/* + * Check to see if the scheduling-clock interrupt came from an extended + * quiescent state, and, if so, tell RCU about it. + */ +void rcu_check_callbacks(int cpu, int user) +{ + if (user || + (idle_cpu(cpu) && + !in_softirq() && + hardirq_count() <= (1 << HARDIRQ_SHIFT))) + rcu_sched_qs(cpu); + else if (!in_softirq()) + rcu_bh_qs(cpu); +} + +/* + * Helper function for rcu_process_callbacks() that operates on the + * specified rcu_ctrlkblk structure. + */ +static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) +{ + unsigned long flags; + struct rcu_head *next, *list; + + /* If no RCU callbacks ready to invoke, just return. */ + if (&rcp->rcucblist == rcp->donetail) + return; + + /* Move the ready-to-invoke callbacks to a local list. */ + local_irq_save(flags); + list = rcp->rcucblist; + rcp->rcucblist = *rcp->donetail; + *rcp->donetail = NULL; + if (rcp->curtail == rcp->donetail) + rcp->curtail = &rcp->rcucblist; + rcp->donetail = &rcp->rcucblist; + local_irq_restore(flags); + + /* Invoke the callbacks on the local list. */ + while (list) { + next = list->next; + prefetch(next); + list->func(list); + list = next; + } +} + +/* + * Invoke any callbacks whose grace period has completed. + */ +static void rcu_process_callbacks(struct softirq_action *unused) +{ + __rcu_process_callbacks(&rcu_ctrlblk); + __rcu_process_callbacks(&rcu_bh_ctrlblk); +} + +/* + * Null function to handle CPU being onlined. Longer term, we want to + * make TINY_RCU avoid using rcupdate.c, but later... + */ +int rcu_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + return NOTIFY_OK; +} + +/* + * Wait for a grace period to elapse. But it is illegal to invoke + * synchronize_sched() from within an RCU read-side critical section. + * Therefore, any legal call to synchronize_sched() is a quiescent + * state, and so on a UP system, synchronize_sched() need do nothing. + * Ditto for synchronize_rcu_bh(). (But Lai Jiangshan points out the + * benefits of doing might_sleep() to reduce latency.) + * + * Cool, huh? (Due to Josh Triplett.) + * + * But we want to make this a static inline later. + */ +void synchronize_sched(void) +{ + cond_resched(); +} +EXPORT_SYMBOL_GPL(synchronize_sched); + +void synchronize_rcu_bh(void) +{ + synchronize_sched(); +} +EXPORT_SYMBOL_GPL(synchronize_rcu_bh); + +/* + * Helper function for call_rcu() and call_rcu_bh(). + */ +static void __call_rcu(struct rcu_head *head, + void (*func)(struct rcu_head *rcu), + struct rcu_ctrlblk *rcp) +{ + unsigned long flags; + + head->func = func; + head->next = NULL; + local_irq_save(flags); + *rcp->curtail = head; + rcp->curtail = &head->next; + local_irq_restore(flags); +} + +/* + * Post an RCU callback to be invoked after the end of an RCU grace + * period. But since we have but one CPU, that would be after any + * quiescent state. + */ +void call_rcu(struct rcu_head *head, + void (*func)(struct rcu_head *rcu)) +{ + __call_rcu(head, func, &rcu_ctrlblk); +} +EXPORT_SYMBOL_GPL(call_rcu); + +/* + * Post an RCU bottom-half callback to be invoked after any subsequent + * quiescent state. + */ +void call_rcu_bh(struct rcu_head *head, + void (*func)(struct rcu_head *rcu)) +{ + __call_rcu(head, func, &rcu_bh_ctrlblk); +} +EXPORT_SYMBOL_GPL(call_rcu_bh); + +void rcu_barrier(void) +{ + struct rcu_synchronize rcu; + + init_completion(&rcu.completion); + /* Will wake me after RCU finished. */ + call_rcu(&rcu.head, wakeme_after_rcu); + /* Wait for it. */ + wait_for_completion(&rcu.completion); +} +EXPORT_SYMBOL_GPL(rcu_barrier); + +void rcu_barrier_bh(void) +{ + struct rcu_synchronize rcu; + + init_completion(&rcu.completion); + /* Will wake me after RCU finished. */ + call_rcu_bh(&rcu.head, wakeme_after_rcu); + /* Wait for it. */ + wait_for_completion(&rcu.completion); +} +EXPORT_SYMBOL_GPL(rcu_barrier_bh); + +void rcu_barrier_sched(void) +{ + struct rcu_synchronize rcu; + + init_completion(&rcu.completion); + /* Will wake me after RCU finished. */ + call_rcu_sched(&rcu.head, wakeme_after_rcu); + /* Wait for it. */ + wait_for_completion(&rcu.completion); +} +EXPORT_SYMBOL_GPL(rcu_barrier_sched); + +void __rcu_init(void) +{ + open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); +} From 0cd397d33608ae6c97d2ee6c8c43462b419b7e26 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 25 Oct 2009 19:03:51 -0700 Subject: [PATCH 046/298] rcu: Add synchronize_srcu_expedited() This patch creates a synchronize_srcu_expedited() that uses synchronize_sched_expedited() where synchronize_srcu() uses synchronize_sched(). The synchronize_srcu() and synchronize_srcu_expedited() functions become one-liners that pass synchronize_sched() or synchronize_sched_expedited(), repectively, to a new __synchronize_srcu() function. While in the file, move the EXPORT_SYMBOL_GPL()s to immediately follow the corresponding functions. Requested-by: Avi Kivity Tested-by: Marcelo Tosatti Signed-off-by: Paul E. McKenney Acked-by: Josh Triplett Reviewed-by: Lai Jiangshan Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com Cc: avi@redhat.com LKML-Reference: <12565226354038-git-send-email-> Signed-off-by: Ingo Molnar --- include/linux/srcu.h | 1 + kernel/srcu.c | 74 ++++++++++++++++++++++++++++++-------------- 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/include/linux/srcu.h b/include/linux/srcu.h index aca0eee5393..4765d97dcaf 100644 --- a/include/linux/srcu.h +++ b/include/linux/srcu.h @@ -48,6 +48,7 @@ void cleanup_srcu_struct(struct srcu_struct *sp); int srcu_read_lock(struct srcu_struct *sp) __acquires(sp); void srcu_read_unlock(struct srcu_struct *sp, int idx) __releases(sp); void synchronize_srcu(struct srcu_struct *sp); +void synchronize_srcu_expedited(struct srcu_struct *sp); long srcu_batches_completed(struct srcu_struct *sp); #endif diff --git a/kernel/srcu.c b/kernel/srcu.c index b0aeeaf22ce..818d7d9aa03 100644 --- a/kernel/srcu.c +++ b/kernel/srcu.c @@ -49,6 +49,7 @@ int init_srcu_struct(struct srcu_struct *sp) sp->per_cpu_ref = alloc_percpu(struct srcu_struct_array); return (sp->per_cpu_ref ? 0 : -ENOMEM); } +EXPORT_SYMBOL_GPL(init_srcu_struct); /* * srcu_readers_active_idx -- returns approximate number of readers @@ -97,6 +98,7 @@ void cleanup_srcu_struct(struct srcu_struct *sp) free_percpu(sp->per_cpu_ref); sp->per_cpu_ref = NULL; } +EXPORT_SYMBOL_GPL(cleanup_srcu_struct); /** * srcu_read_lock - register a new reader for an SRCU-protected structure. @@ -118,6 +120,7 @@ int srcu_read_lock(struct srcu_struct *sp) preempt_enable(); return idx; } +EXPORT_SYMBOL_GPL(srcu_read_lock); /** * srcu_read_unlock - unregister a old reader from an SRCU-protected structure. @@ -136,22 +139,12 @@ void srcu_read_unlock(struct srcu_struct *sp, int idx) per_cpu_ptr(sp->per_cpu_ref, smp_processor_id())->c[idx]--; preempt_enable(); } +EXPORT_SYMBOL_GPL(srcu_read_unlock); -/** - * synchronize_srcu - wait for prior SRCU read-side critical-section completion - * @sp: srcu_struct with which to synchronize. - * - * Flip the completed counter, and wait for the old count to drain to zero. - * As with classic RCU, the updater must use some separate means of - * synchronizing concurrent updates. Can block; must be called from - * process context. - * - * Note that it is illegal to call synchornize_srcu() from the corresponding - * SRCU read-side critical section; doing so will result in deadlock. - * However, it is perfectly legal to call synchronize_srcu() on one - * srcu_struct from some other srcu_struct's read-side critical section. +/* + * Helper function for synchronize_srcu() and synchronize_srcu_expedited(). */ -void synchronize_srcu(struct srcu_struct *sp) +void __synchronize_srcu(struct srcu_struct *sp, void (*sync_func)(void)) { int idx; @@ -173,7 +166,7 @@ void synchronize_srcu(struct srcu_struct *sp) return; } - synchronize_sched(); /* Force memory barrier on all CPUs. */ + sync_func(); /* Force memory barrier on all CPUs. */ /* * The preceding synchronize_sched() ensures that any CPU that @@ -190,7 +183,7 @@ void synchronize_srcu(struct srcu_struct *sp) idx = sp->completed & 0x1; sp->completed++; - synchronize_sched(); /* Force memory barrier on all CPUs. */ + sync_func(); /* Force memory barrier on all CPUs. */ /* * At this point, because of the preceding synchronize_sched(), @@ -203,7 +196,7 @@ void synchronize_srcu(struct srcu_struct *sp) while (srcu_readers_active_idx(sp, idx)) schedule_timeout_interruptible(1); - synchronize_sched(); /* Force memory barrier on all CPUs. */ + sync_func(); /* Force memory barrier on all CPUs. */ /* * The preceding synchronize_sched() forces all srcu_read_unlock() @@ -236,6 +229,47 @@ void synchronize_srcu(struct srcu_struct *sp) mutex_unlock(&sp->mutex); } +/** + * synchronize_srcu - wait for prior SRCU read-side critical-section completion + * @sp: srcu_struct with which to synchronize. + * + * Flip the completed counter, and wait for the old count to drain to zero. + * As with classic RCU, the updater must use some separate means of + * synchronizing concurrent updates. Can block; must be called from + * process context. + * + * Note that it is illegal to call synchronize_srcu() from the corresponding + * SRCU read-side critical section; doing so will result in deadlock. + * However, it is perfectly legal to call synchronize_srcu() on one + * srcu_struct from some other srcu_struct's read-side critical section. + */ +void synchronize_srcu(struct srcu_struct *sp) +{ + __synchronize_srcu(sp, synchronize_sched); +} +EXPORT_SYMBOL_GPL(synchronize_srcu); + +/** + * synchronize_srcu_expedited - like synchronize_srcu, but less patient + * @sp: srcu_struct with which to synchronize. + * + * Flip the completed counter, and wait for the old count to drain to zero. + * As with classic RCU, the updater must use some separate means of + * synchronizing concurrent updates. Can block; must be called from + * process context. + * + * Note that it is illegal to call synchronize_srcu_expedited() + * from the corresponding SRCU read-side critical section; doing so + * will result in deadlock. However, it is perfectly legal to call + * synchronize_srcu_expedited() on one srcu_struct from some other + * srcu_struct's read-side critical section. + */ +void synchronize_srcu_expedited(struct srcu_struct *sp) +{ + __synchronize_srcu(sp, synchronize_sched_expedited); +} +EXPORT_SYMBOL_GPL(synchronize_srcu_expedited); + /** * srcu_batches_completed - return batches completed. * @sp: srcu_struct on which to report batch completion. @@ -248,10 +282,4 @@ long srcu_batches_completed(struct srcu_struct *sp) { return sp->completed; } - -EXPORT_SYMBOL_GPL(init_srcu_struct); -EXPORT_SYMBOL_GPL(cleanup_srcu_struct); -EXPORT_SYMBOL_GPL(srcu_read_lock); -EXPORT_SYMBOL_GPL(srcu_read_unlock); -EXPORT_SYMBOL_GPL(synchronize_srcu); EXPORT_SYMBOL_GPL(srcu_batches_completed); From 804bb8370522a569bd3a732b9de5fbd55e26f155 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 25 Oct 2009 19:03:52 -0700 Subject: [PATCH 047/298] rcu: Add synchronize_srcu_expedited() to the rcutorture test suite Adds the "srcu_expedited" torture type, and also renames sched_ops_sync to sched_sync_ops for consistency while we are in this file. Signed-off-by: Paul E. McKenney Acked-by: Josh Triplett Reviewed-by: Lai Jiangshan Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com Cc: avi@redhat.com Cc: mtosatti@redhat.com LKML-Reference: <12565226353636-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutorture.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 697c0a0229d..14480e8b2a2 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -547,6 +547,25 @@ static struct rcu_torture_ops srcu_ops = { .name = "srcu" }; +static void srcu_torture_synchronize_expedited(void) +{ + synchronize_srcu_expedited(&srcu_ctl); +} + +static struct rcu_torture_ops srcu_expedited_ops = { + .init = srcu_torture_init, + .cleanup = srcu_torture_cleanup, + .readlock = srcu_torture_read_lock, + .read_delay = srcu_read_delay, + .readunlock = srcu_torture_read_unlock, + .completed = srcu_torture_completed, + .deferred_free = rcu_sync_torture_deferred_free, + .sync = srcu_torture_synchronize_expedited, + .cb_barrier = NULL, + .stats = srcu_torture_stats, + .name = "srcu_expedited" +}; + /* * Definitions for sched torture testing. */ @@ -592,7 +611,7 @@ static struct rcu_torture_ops sched_ops = { .name = "sched" }; -static struct rcu_torture_ops sched_ops_sync = { +static struct rcu_torture_ops sched_sync_ops = { .init = rcu_sync_torture_init, .cleanup = NULL, .readlock = sched_torture_read_lock, @@ -1098,8 +1117,8 @@ rcu_torture_init(void) int firsterr = 0; static struct rcu_torture_ops *torture_ops[] = { &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops, - &sched_expedited_ops, - &srcu_ops, &sched_ops, &sched_ops_sync, }; + &srcu_ops, &srcu_expedited_ops, + &sched_ops, &sched_sync_ops, &sched_expedited_ops, }; mutex_lock(&fullstop_mutex); From 64179861cb801eac4f00c79f39a29ea5ac9470d7 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 25 Oct 2009 19:03:53 -0700 Subject: [PATCH 048/298] rcu: Add synchronize_srcu_expedited() to the documentation Signed-off-by: Paul E. McKenney Acked-by: Josh Triplett Reviewed-by: Lai Jiangshan Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com Cc: avi@redhat.com Cc: mtosatti@redhat.com LKML-Reference: <12565226354176-git-send-email-> Signed-off-by: Ingo Molnar --- Documentation/RCU/whatisRCU.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt index e41a7fecf0d..d542ca243b8 100644 --- a/Documentation/RCU/whatisRCU.txt +++ b/Documentation/RCU/whatisRCU.txt @@ -830,7 +830,7 @@ sched: Critical sections Grace period Barrier SRCU: Critical sections Grace period Barrier srcu_read_lock synchronize_srcu N/A - srcu_read_unlock + srcu_read_unlock synchronize_srcu_expedited SRCU: Initialization/cleanup init_srcu_struct From cf886c44ec418a01b2c52493465accb81acbf930 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 25 Oct 2009 19:03:54 -0700 Subject: [PATCH 049/298] rcu: Improve rcutorture diagnostics when bad torture_type specified Make rcutorture list the available torture_type values when it doesn't like the one specified. Signed-off-by: Paul E. McKenney Acked-by: Josh Triplett Reviewed-by: Lai Jiangshan Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com Cc: avi@redhat.com Cc: mtosatti@redhat.com LKML-Reference: <12565226351868-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutorture.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 14480e8b2a2..3dd0ca23e19 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -1129,8 +1129,12 @@ rcu_torture_init(void) break; } if (i == ARRAY_SIZE(torture_ops)) { - printk(KERN_ALERT "rcutorture: invalid torture type: \"%s\"\n", + printk(KERN_ALERT "rcu-torture: invalid torture type: \"%s\"\n", torture_type); + printk(KERN_ALERT "rcu-torture types:"); + for (i = 0; i < ARRAY_SIZE(torture_ops); i++) + printk(KERN_ALERT " %s", torture_ops[i]->name); + printk(KERN_ALERT "\n"); mutex_unlock(&fullstop_mutex); return -EINVAL; } From 4ce5b90340879ce93d169b7b523c2cbbe7c45843 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 26 Oct 2009 07:55:55 +0100 Subject: [PATCH 050/298] rcu: Do tiny cleanups in rcutiny No change in functionality - just straighten out a few small stylistic details. Cc: Paul E. McKenney Cc: David Howells Cc: Josh Triplett Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: avi@redhat.com Cc: mtosatti@redhat.com LKML-Reference: <12565226351355-git-send-email-> Signed-off-by: Ingo Molnar --- include/linux/rcutiny.h | 6 ++--- kernel/rcutiny.c | 49 +++++++++++++++++++---------------------- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h index 891073c264d..2c1fe8373e7 100644 --- a/include/linux/rcutiny.h +++ b/include/linux/rcutiny.h @@ -20,9 +20,8 @@ * Author: Paul E. McKenney * * For detailed explanation of Read-Copy Update mechanism see - - * Documentation/RCU + * Documentation/RCU */ - #ifndef __LINUX_TINY_H #define __LINUX_TINY_H @@ -70,8 +69,7 @@ static inline void synchronize_rcu_bh_expedited(void) } struct notifier_block; -extern int rcu_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu); +extern int rcu_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu); #ifdef CONFIG_NO_HZ diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c index 0b54efde66a..b33ec3aa377 100644 --- a/kernel/rcutiny.c +++ b/kernel/rcutiny.c @@ -20,22 +20,21 @@ * Author: Paul E. McKenney * * For detailed explanation of Read-Copy Update mechanism see - - * Documentation/RCU + * Documentation/RCU */ - -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include #include -#include +#include +#include +#include #include +#include +#include +#include #include +#include /* Global control variables for rcupdate callback mechanism. */ struct rcu_ctrlblk { @@ -46,14 +45,13 @@ struct rcu_ctrlblk { /* Definition for rcupdate control block. */ static struct rcu_ctrlblk rcu_ctrlblk = { - .rcucblist = NULL, - .donetail = &rcu_ctrlblk.rcucblist, - .curtail = &rcu_ctrlblk.rcucblist, + .donetail = &rcu_ctrlblk.rcucblist, + .curtail = &rcu_ctrlblk.rcucblist, }; + static struct rcu_ctrlblk rcu_bh_ctrlblk = { - .rcucblist = NULL, - .donetail = &rcu_bh_ctrlblk.rcucblist, - .curtail = &rcu_bh_ctrlblk.rcucblist, + .donetail = &rcu_bh_ctrlblk.rcucblist, + .curtail = &rcu_bh_ctrlblk.rcucblist, }; #ifdef CONFIG_NO_HZ @@ -84,8 +82,8 @@ void rcu_exit_nohz(void) /* * Helper function for rcu_qsctr_inc() and rcu_bh_qsctr_inc(). - * Also disable irqs to avoid confusion due to interrupt handlers invoking - * call_rcu(). + * Also disable irqs to avoid confusion due to interrupt handlers + * invoking call_rcu(). */ static int rcu_qsctr_help(struct rcu_ctrlblk *rcp) { @@ -99,6 +97,7 @@ static int rcu_qsctr_help(struct rcu_ctrlblk *rcp) return 1; } local_irq_restore(flags); + return 0; } @@ -143,8 +142,8 @@ void rcu_check_callbacks(int cpu, int user) */ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) { - unsigned long flags; struct rcu_head *next, *list; + unsigned long flags; /* If no RCU callbacks ready to invoke, just return. */ if (&rcp->rcucblist == rcp->donetail) @@ -182,8 +181,7 @@ static void rcu_process_callbacks(struct softirq_action *unused) * Null function to handle CPU being onlined. Longer term, we want to * make TINY_RCU avoid using rcupdate.c, but later... */ -int rcu_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) +int rcu_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { return NOTIFY_OK; } @@ -223,6 +221,7 @@ static void __call_rcu(struct rcu_head *head, head->func = func; head->next = NULL; + local_irq_save(flags); *rcp->curtail = head; rcp->curtail = &head->next; @@ -234,8 +233,7 @@ static void __call_rcu(struct rcu_head *head, * period. But since we have but one CPU, that would be after any * quiescent state. */ -void call_rcu(struct rcu_head *head, - void (*func)(struct rcu_head *rcu)) +void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) { __call_rcu(head, func, &rcu_ctrlblk); } @@ -245,8 +243,7 @@ EXPORT_SYMBOL_GPL(call_rcu); * Post an RCU bottom-half callback to be invoked after any subsequent * quiescent state. */ -void call_rcu_bh(struct rcu_head *head, - void (*func)(struct rcu_head *rcu)) +void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) { __call_rcu(head, func, &rcu_bh_ctrlblk); } From 88b91c7ca49bc8600cf1106eb891d08c1965b9ce Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 26 Oct 2009 10:24:31 -0700 Subject: [PATCH 051/298] rcu: Simplify creating of lockdep class for root rcu_node Use lockdep_set_class() to simplify the code and to avoid any additional overhead in the !LOCKDEP case. Also move the definition of rcu_root_class into kernel/rcutree.c, as suggested by Lai Jiangshan. Signed-off-by: Peter Zijlstra Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <1256577871443-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index ddbf111e9e1..055f1a941a9 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -51,6 +51,8 @@ /* Data structures. */ +static struct lock_class_key rcu_root_class; + #define RCU_STATE_INITIALIZER(name) { \ .level = { &name.node[0] }, \ .levelcnt = { \ @@ -1666,8 +1668,7 @@ static void __init rcu_init_one(struct rcu_state *rsp) cpustride *= rsp->levelspread[i]; rnp = rsp->level[i]; for (j = 0; j < rsp->levelcnt[i]; j++, rnp++) { - if (rnp != rcu_get_root(rsp)) - spin_lock_init(&rnp->lock); + spin_lock_init(&rnp->lock); rnp->gpnum = 0; rnp->qsmask = 0; rnp->qsmaskinit = 0; @@ -1690,7 +1691,7 @@ static void __init rcu_init_one(struct rcu_state *rsp) INIT_LIST_HEAD(&rnp->blocked_tasks[1]); } } - spin_lock_init(&rcu_get_root(rsp)->lock); + lockdep_set_class(&rcu_get_root(rsp)->lock, &rcu_root_class); } /* From 2c28e2451dba2260e9f88811b29a7787db7e7616 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 26 Oct 2009 13:57:44 -0700 Subject: [PATCH 052/298] rcu: Fix TINY_RCU #elif condition Some compilers are happy with "#elif CONFIG_RCU_TINY", while others strongly prefer "#elif defined(CONFIG_RCU_TINY)". Change to the latter to make more compilers happy. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12565906642768-git-send-email-> Signed-off-by: Ingo Molnar --- include/linux/rcupdate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 6dd71fa4842..2f1bc42a3b8 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -77,7 +77,7 @@ extern int rcu_scheduler_active; #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) #include -#elif CONFIG_TINY_RCU +#elif defined(CONFIG_TINY_RCU) #include #else #error "Unknown RCU implementation specified to kernel configuration" From d6ba452128178091dab7a04d54f7e66fdc32fb39 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Mon, 26 Oct 2009 09:26:18 -0400 Subject: [PATCH 053/298] tpm add default function definitions Add default tpm_pcr_read/extend function definitions required by IMA/Kconfig changes. Signed-off-by: Mimi Zohar Reviewed-by: Eric Paris Signed-off-by: James Morris --- include/linux/tpm.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 3338b3f5c21..8eaa8f83eff 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -31,5 +31,12 @@ extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf); extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash); +#else +static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) { + return -ENODEV; +} +static inline int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) { + return -ENODEV; +} #endif #endif From 024e1a49411a1a7363e65db48edf1b09e9ee68ad Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 27 Oct 2009 19:24:46 -0700 Subject: [PATCH 054/298] tomoyo: improve hash bucket dispersion When examining the network device name hash, it was discovered that the low order bits of full_name_hash() are not very well dispersed across the possible values. When used by filesystem code, this is handled by folding with the function hash_long(). The only other non-filesystem usage of full_name_hash() at this time appears to be in TOMOYO. This patch should fix that. I do not use TOMOYO at this time, so this patch is build tested only. Signed-off-by: Stephen Hemminger Acked-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/realpath.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 5f2e3326337..917f564cdab 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c @@ -13,6 +13,8 @@ #include #include #include +#include + #include "common.h" #include "realpath.h" @@ -263,7 +265,8 @@ static unsigned int tomoyo_quota_for_savename; * table. Frequency of appending strings is very low. So we don't need * large (e.g. 64k) hash size. 256 will be sufficient. */ -#define TOMOYO_MAX_HASH 256 +#define TOMOYO_HASH_BITS 8 +#define TOMOYO_MAX_HASH (1u<entry.hash && !strcmp(name, ptr->entry.name)) goto out; } @@ -365,7 +370,7 @@ const struct tomoyo_path_info *tomoyo_save_name(const char *name) tomoyo_fill_path_info(&ptr->entry); fmb->ptr += len; fmb->len -= len; - list_add_tail(&ptr->list, &tomoyo_name_list[hash % TOMOYO_MAX_HASH]); + list_add_tail(&ptr->list, head); if (fmb->len == 0) { list_del(&fmb->list); kfree(fmb); From ff76ec18cabb12a6c8f3c65bd1d23f1a770fe908 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 28 Oct 2009 12:26:39 -0700 Subject: [PATCH 055/298] tpm: fix header for modular build Fix build for TCG_TPM=m. Header file doesn't handle this and incorrectly builds stubs. drivers/char/tpm/tpm.c:720: error: redefinition of 'tpm_pcr_read' include/linux/tpm.h:35: error:previous definition of 'tpm_pcr_read' was here drivers/char/tpm/tpm.c:752: error: redefinition of 'tpm_pcr_extend' include/linux/tpm.h:38: error:previous definition of 'tpm_pcr_extend' was here Repairs linux-next's commit d6ba452128178091dab7a04d54f7e66fdc32fb39 Author: Mimi Zohar Date: Mon Oct 26 09:26:18 2009 -0400 tpm add default function definitions Signed-off-by: Randy Dunlap Cc: Rajiv Andrade Cc: Mimi Zohar Cc: James Morris Cc: Eric Paris Signed-off-by: Andrew Morton Signed-off-by: James Morris --- include/linux/tpm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 8eaa8f83eff..ac5d1c1285d 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -27,7 +27,7 @@ */ #define TPM_ANY_NUM 0xFFFF -#if defined(CONFIG_TCG_TPM) +#if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE) extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf); extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash); From 4f65ae36f0291ef97b7d4de2f59b2e68f3c8420b Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 29 Oct 2009 17:16:00 +0100 Subject: [PATCH 056/298] agp/amd64: Remove GART dependency on AGP_AMD64 The GART IOMMU code has no strong dependency to the AMD64 AGP code. So the automatic selection of AGP_AMD64 for GART can be removed. Cc: Dave Jones Signed-off-by: Pavel Vasilyev Signed-off-by: Joerg Roedel --- drivers/char/agp/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index ccb1fa89de2..2fb3a480f6b 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig @@ -56,9 +56,8 @@ config AGP_AMD X on AMD Irongate, 761, and 762 chipsets. config AGP_AMD64 - tristate "AMD Opteron/Athlon64 on-CPU GART support" if !GART_IOMMU + tristate "AMD Opteron/Athlon64 on-CPU GART support" depends on AGP && X86 - default y if GART_IOMMU help This option gives you AGP support for the GLX component of X using the on-CPU northbridge of the AMD Athlon64/Opteron CPUs. From d49f6aa76d24c60a52530474cb662e8ad9f09471 Mon Sep 17 00:00:00 2001 From: Li Hong Date: Wed, 28 Oct 2009 13:01:38 +0800 Subject: [PATCH 057/298] tracing: Amend documentation in recordmcount.pl to reflect implementation The documentation currently says we will use the first function in a section as a reference. The actual algorithm is: choose the first global function we meet as a reference. If there is none, choose the first local one. Change the documentation to be consistent with the code. Also add several other clarifications. Signed-off-by: Li Hong LKML-Reference: <20091028050138.GA30758@uhli> Signed-off-by: Steven Rostedt --- scripts/recordmcount.pl | 84 ++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 35 deletions(-) diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index bfb8b2cdd92..a569be72f3b 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -6,73 +6,89 @@ # all the offsets to the calls to mcount. # # -# What we want to end up with is a section in vmlinux called -# __mcount_loc that contains a list of pointers to all the -# call sites in the kernel that call mcount. Later on boot up, the kernel -# will read this list, save the locations and turn them into nops. -# When tracing or profiling is later enabled, these locations will then -# be converted back to pointers to some function. +# What we want to end up with this is that each object file will have a +# section called __mcount_loc that will hold the list of pointers to mcount +# callers. After final linking, the vmlinux will have within .init.data the +# list of all callers to mcount between __start_mcount_loc and __stop_mcount_loc. +# Later on boot up, the kernel will read this list, save the locations and turn +# them into nops. When tracing or profiling is later enabled, these locations +# will then be converted back to pointers to some function. # # This is no easy feat. This script is called just after the original # object is compiled and before it is linked. # -# The references to the call sites are offsets from the section of text -# that the call site is in. Hence, all functions in a section that -# has a call site to mcount, will have the offset from the beginning of -# the section and not the beginning of the function. +# When parse this object file using 'objdump', the references to the call +# sites are offsets from the section that the call site is in. Hence, all +# functions in a section that has a call site to mcount, will have the +# offset from the beginning of the section and not the beginning of the +# function. +# +# But where this section will reside finally in vmlinx is undetermined at +# this point. So we can't use this kind of offsets to record the final +# address of this call site. +# +# The trick is to change the call offset referring the start of a section to +# referring a function symbol in this section. During the link step, 'ld' will +# compute the final address according to the information we record. # -# The trick is to find a way to record the beginning of the section. -# The way we do this is to look at the first function in the section -# which will also be the location of that section after final link. # e.g. # # .section ".sched.text", "ax" -# .globl my_func -# my_func: # [...] -# call mcount (offset: 0x5) +# func1: +# [...] +# call mcount (offset: 0x10) # [...] # ret -# other_func: +# .globl fun2 +# func2: (offset: 0x20) # [...] -# call mcount (offset: 0x1b) +# [...] +# ret +# func3: +# [...] +# call mcount (offset: 0x30) # [...] # # Both relocation offsets for the mcounts in the above example will be -# offset from .sched.text. If we make another file called tmp.s with: +# offset from .sched.text. If we choose global symbol func2 as a reference and +# make another file called tmp.s with the new offsets: # # .section __mcount_loc -# .quad my_func + 0x5 -# .quad my_func + 0x1b +# .quad func2 - 0x10 +# .quad func2 + 0x10 # -# We can then compile this tmp.s into tmp.o, and link it to the original +# We can then compile this tmp.s into tmp.o, and link it back to the original # object. # -# But this gets hard if my_func is not globl (a static function). -# In such a case we have: +# In our algorithm, we will choose the first global function we meet in this +# section as the reference. But this gets hard if there is no global functions +# in this section. In such a case we have to select a local one. E.g. func1: # # .section ".sched.text", "ax" -# my_func: +# func1: # [...] -# call mcount (offset: 0x5) +# call mcount (offset: 0x10) # [...] # ret -# other_func: +# func2: # [...] -# call mcount (offset: 0x1b) +# call mcount (offset: 0x20) # [...] +# .section "other.section" # # If we make the tmp.s the same as above, when we link together with -# the original object, we will end up with two symbols for my_func: +# the original object, we will end up with two symbols for func1: # one local, one global. After final compile, we will end up with -# an undefined reference to my_func. +# an undefined reference to func1 or a wrong reference to another global +# func1 in other files. # # Since local objects can reference local variables, we need to find # a way to make tmp.o reference the local objects of the original object -# file after it is linked together. To do this, we convert the my_func +# file after it is linked together. To do this, we convert func1 # into a global symbol before linking tmp.o. Then after we link tmp.o -# we will only have a single symbol for my_func that is global. -# We can convert my_func back into a local symbol and we are done. +# we will only have a single symbol for func1 that is global. +# We can convert func1 back into a local symbol and we are done. # # Here are the steps we take: # @@ -86,10 +102,8 @@ # 6) Link together this new object with the list object. # 7) Convert the local functions back to local symbols and rename # the result as the original object. -# End. # 8) Link the object with the list object. # 9) Move the result back to the original object. -# End. # use strict; From e2d753fac5b3954a3b6001f98479f0435fe7c868 Mon Sep 17 00:00:00 2001 From: Li Hong Date: Tue, 27 Oct 2009 14:57:33 +0800 Subject: [PATCH 058/298] tracing: Correct the check for number of arguments in recordmcount.pl The number of arguments passed into recordmcount.pl is 10, but the code checks if only 7 are passed in. Signed-off-by: Li Hong LKML-Reference: <20091027065733.GB22032@uhli> Signed-off-by: Steven Rostedt --- scripts/recordmcount.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index a569be72f3b..a512af1514b 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -113,7 +113,7 @@ $P =~ s@.*/@@g; my $V = '0.1'; -if ($#ARGV < 7) { +if ($#ARGV != 10) { print "usage: $P arch bits objdump objcopy cc ld nm rm mv is_module inputfile\n"; print "version: $V\n"; exit(1); From bdd3b052c63b2c19a0118937f500985c01a19956 Mon Sep 17 00:00:00 2001 From: Li Hong Date: Wed, 28 Oct 2009 13:03:32 +0800 Subject: [PATCH 059/298] tracing: Check absolute path of input file in recordmcount.pl The ftrace.c file may reference the mcount function and this may interfere with the recordmcount.pl processing. To avoid this, the code does not process the kernel/trace/ftrace.o. But currently the check is against a relative path. This patch modifies the check to succeed if the path is an absolute path. Signed-off-by: Li Hong LKML-Reference: <20091028050332.GC30758@uhli> Signed-off-by: Steven Rostedt --- scripts/recordmcount.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index a512af1514b..b80e5d04416 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -123,7 +123,7 @@ my ($arch, $bits, $objdump, $objcopy, $cc, $ld, $nm, $rm, $mv, $is_module, $inputfile) = @ARGV; # This file refers to mcount and shouldn't be ftraced, so lets' ignore it -if ($inputfile eq "kernel/trace/ftrace.o") { +if ($inputfile =~ m,kernel/trace/ftrace\.o$,) { exit(0); } From 7b7edc27683e20624f4daf17c76041719184201c Mon Sep 17 00:00:00 2001 From: Li Hong Date: Wed, 28 Oct 2009 13:04:21 +0800 Subject: [PATCH 060/298] tracing: Fix objcopy revision check in recordmcount.pl The current logic to check objcopy's version is incorrect. This patch fixes the algorithm and disables the use of local functions as a reference if the objcopy version does not support static to global conversions. Also remove some usused variables. Signed-off-by: Li Hong LKML-Reference: <20091028050421.GD30758@uhli> Signed-off-by: Steven Rostedt --- scripts/recordmcount.pl | 56 ++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index b80e5d04416..d6199fc4870 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -159,6 +159,31 @@ my $function_regex; # Find the name of a function my $mcount_regex; # Find the call site to mcount (return 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 + +## +# check_objcopy - whether objcopy supports --globalize-symbols +# +# --globalize-symbols came out in 2.17, we must test the version +# of objcopy, and if it is less than 2.17, then we can not +# record local functions. +sub check_objcopy +{ + open (IN, "$objcopy --version |") or die "error running $objcopy"; + while () { + if (/objcopy.*\s(\d+)\.(\d+)/) { + $can_use_local = 1 if ($1 > 2 || ($1 == 2 && $2 >= 17)); + last; + } + } + close (IN); + + if (!$can_use_local) { + print STDERR "WARNING: could not find objcopy version or version " . + "is less than 2.17.\n" . + "\tLocal function references is disabled.\n"; + } +} if ($arch eq "x86") { if ($bits == 64) { @@ -293,34 +318,7 @@ if ($filename =~ m,^(.*)(\.\S),) { my $mcount_s = $dirname . "/.tmp_mc_" . $prefix . ".s"; my $mcount_o = $dirname . "/.tmp_mc_" . $prefix . ".o"; -# -# --globalize-symbols came out in 2.17, we must test the version -# of objcopy, and if it is less than 2.17, then we can not -# record local functions. -my $use_locals = 01; -my $local_warn_once = 0; -my $found_version = 0; - -open (IN, "$objcopy --version |") || die "error running $objcopy"; -while () { - if (/objcopy.*\s(\d+)\.(\d+)/) { - my $major = $1; - my $minor = $2; - - $found_version = 1; - if ($major < 2 || - ($major == 2 && $minor < 17)) { - $use_locals = 0; - } - last; - } -} -close (IN); - -if (!$found_version) { - print STDERR "WARNING: could not find objcopy version.\n" . - "\tDisabling local function references.\n"; -} +check_objcopy(); # # Step 1: find all the local (static functions) and weak symbols. @@ -367,7 +365,7 @@ sub update_funcs if (defined $locals{$ref_func}) { # only use locals if objcopy supports globalize-symbols - if (!$use_locals) { + if (!$can_use_local) { return; } $convert{$ref_func} = 1; From db24c7dcf42f78629d89b34e5d5a98ed56ea2ff5 Mon Sep 17 00:00:00 2001 From: Li Hong Date: Wed, 28 Oct 2009 13:05:23 +0800 Subject: [PATCH 061/298] tracing: Move mcount section search to front of loop in recordmcount.pl Move the mcount section check to the beginning of the objdump read loop. This makes the code easier to follow since the search for the mcount section is performed first before the mcount callers are processed. Signed-off-by: Li Hong LKML-Reference: <20091028050523.GE30758@uhli> Signed-off-by: Steven Rostedt --- scripts/recordmcount.pl | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index d6199fc4870..02c80552b07 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -391,9 +391,27 @@ open(IN, "$objdump -hdr $inputfile|") || die "error running $objdump"; my $text; + +# read headers first my $read_headers = 1; while () { + + if ($read_headers && /$mcount_section/) { + # + # Somehow the make process can execute this script on an + # object twice. If it does, we would duplicate the mcount + # section and it will cause the function tracer self test + # to fail. Check if the mcount section exists, and if it does, + # warn and exit. + # + print STDERR "ERROR: $mcount_section already in $inputfile\n" . + "\tThis may be an indication that your build is corrupted.\n" . + "\tDelete $inputfile and try again. If the same object file\n" . + "\tstill causes an issue, then disable CONFIG_DYNAMIC_FTRACE.\n"; + exit(-1); + } + # is it a section? if (/$section_regex/) { $read_headers = 0; @@ -434,21 +452,7 @@ while () { $offset = hex $1; } } - } elsif ($read_headers && /$mcount_section/) { - # - # Somehow the make process can execute this script on an - # object twice. If it does, we would duplicate the mcount - # section and it will cause the function tracer self test - # to fail. Check if the mcount section exists, and if it does, - # warn and exit. - # - print STDERR "ERROR: $mcount_section already in $inputfile\n" . - "\tThis may be an indication that your build is corrupted.\n" . - "\tDelete $inputfile and try again. If the same object file\n" . - "\tstill causes an issue, then disable CONFIG_DYNAMIC_FTRACE.\n"; - exit(-1); } - # is this a call site to mcount? If so, record it to print later if ($text_found && /$mcount_regex/) { $offsets[$#offsets + 1] = hex $1; From 306dcf47d28aaf9aedfafb17a602768584cfc0f2 Mon Sep 17 00:00:00 2001 From: Li Hong Date: Wed, 28 Oct 2009 13:06:19 +0800 Subject: [PATCH 062/298] tracing: Add regex for weak functions in recordmcount.pl Add a variable to contain the regex needed to find weak functions in the 'nm' output. This will allow other archs to easily override it. Also rename the regex variable $nm_regex to $local_regex to be more descriptive. Signed-off-by: Li Hong LKML-Reference: <20091028050619.GF30758@uhli> Signed-off-by: Steven Rostedt --- scripts/recordmcount.pl | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 02c80552b07..7265a7dcac4 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -92,7 +92,7 @@ # # Here are the steps we take: # -# 1) Record all the local symbols by using 'nm' +# 1) Record all the local and weak symbols by using 'nm' # 2) Use objdump to find all the call site offsets and sections for # mcount. # 3) Compile the list into its own object. @@ -152,7 +152,8 @@ my %weak; # List of weak functions my %convert; # List of local functions used that needs conversion my $type; -my $nm_regex; # Find the local functions (return function) +my $local_regex; # Match a local function (return function) +my $weak_regex; # Match a weak function (return function) my $section_regex; # Find the start of a section my $function_regex; # Find the name of a function # (return offset and func name) @@ -197,7 +198,8 @@ if ($arch eq "x86") { # We base the defaults off of i386, the other archs may # feel free to change them in the below if statements. # -$nm_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\S+)"; +$local_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\S+)"; +$weak_regex = "^[0-9a-fA-F]+\\s+([wW])\\s+(\\S+)"; $section_regex = "Disassembly of section\\s+(\\S+):"; $function_regex = "^([0-9a-fA-F]+)\\s+<(.*?)>:"; $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount\$"; @@ -246,7 +248,7 @@ if ($arch eq "x86_64") { $cc .= " -m32"; } elsif ($arch eq "powerpc") { - $nm_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\.?\\S+)"; + $local_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\.?\\S+)"; $function_regex = "^([0-9a-fA-F]+)\\s+<(\\.?.*?)>:"; $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s\\.?_mcount\$"; @@ -322,13 +324,13 @@ check_objcopy(); # # Step 1: find all the local (static functions) and weak symbols. -# 't' is local, 'w/W' is weak (we never use a weak function) +# 't' is local, 'w/W' is weak # open (IN, "$nm $inputfile|") || die "error running $nm"; while () { - if (/$nm_regex/) { + if (/$local_regex/) { $locals{$1} = 1; - } elsif (/^[0-9a-fA-F]+\s+([wW])\s+(\S+)/) { + } elsif (/$weak_regex/) { $weak{$2} = $1; } } From 6092858c60f168c1950f8ad73880d54271696ec5 Mon Sep 17 00:00:00 2001 From: Li Hong Date: Wed, 28 Oct 2009 13:07:03 +0800 Subject: [PATCH 063/298] tracing: Move conditional into update_funcs() in recordmcount.pl Move all the condition validations into the function update_funcs(). Also update_funcs should not die if $ref_func is undefined for there may be more than one valid section in an object file. Signed-off-by: Li Hong LKML-Reference: <20091028050703.GG30758@uhli> Signed-off-by: Steven Rostedt --- scripts/recordmcount.pl | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 7265a7dcac4..884776a6e01 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -348,9 +348,7 @@ my $offset = 0; # offset of ref_func to section beginning # sub update_funcs { - return if ($#offsets < 0); - - defined($ref_func) || die "No function to reference"; + return unless ($ref_func and @offsets); # A section only had a weak function, to represent it. # Unfortunately, a weak function may be overwritten by another @@ -425,7 +423,7 @@ while () { $read_function = 0; } # print out any recorded offsets - update_funcs() if (defined($ref_func)); + update_funcs(); # reset all markers and arrays $text_found = 0; @@ -462,7 +460,7 @@ while () { } # dump out anymore offsets that may have been found -update_funcs() if (defined($ref_func)); +update_funcs(); # If we did not find any mcount callers, we are done (do nothing). if (!$opened) { From c4b8ac2c1aee1398b9378b8730bac56294b3410b Mon Sep 17 00:00:00 2001 From: Li Hong Date: Wed, 28 Oct 2009 13:07:43 +0800 Subject: [PATCH 064/298] tracing: Exit with error if a weak function is used in recordmcount.pl If a weak function is used as a relocation reference for mcount callers and that function is overridden, it will cause ftrace to fail at run time. The current code should prevent a weak function from being used, but if one is, the code should exit with an error to fail at compile time. Signed-off-by: Li Hong LKML-Reference: <20091028050743.GH30758@uhli> Signed-off-by: Steven Rostedt --- scripts/recordmcount.pl | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 884776a6e01..a4e2435d482 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -350,15 +350,11 @@ sub update_funcs { return unless ($ref_func and @offsets); - # A section only had a weak function, to represent it. - # Unfortunately, a weak function may be overwritten by another - # function of the same name, making all these offsets incorrect. - # To be safe, we simply print a warning and bail. + # Sanity check on weak function. A weak function may be overwritten by + # another function of the same name, making all these offsets incorrect. if (defined $weak{$ref_func}) { - print STDERR - "$inputfile: WARNING: referencing weak function" . + die "$inputfile: ERROR: referencing weak function" . " $ref_func for mcount\n"; - return; } # is this function static? If so, note this fact. From 5975c725dfd6f7d36f493ab1453fbdbd35c1f0e3 Mon Sep 17 00:00:00 2001 From: "Serge E. Hallyn" Date: Thu, 29 Oct 2009 11:40:17 -0500 Subject: [PATCH 065/298] define convenient securebits masks for prctl users (v2) Hi James, would you mind taking the following into security-testing? The securebits are used by passing them to prctl with the PR_{S,G}ET_SECUREBITS commands. But the defines must be shifted to be used in prctl, which begs to be confused and misused by userspace. So define some more convenient values for userspace to specify. This way userspace does prctl(PR_SET_SECUREBITS, SECBIT_NOROOT); instead of prctl(PR_SET_SECUREBITS, 1 << SECURE_NOROOT); (Thanks to Michael for the idea) This patch also adds include/linux/securebits to the installed headers. Then perhaps it can be included by glibc's sys/prctl.h. Changelog: Oct 29: Stephen Rothwell points out that issecure can be under __KERNEL__. Oct 14: (Suggestions by Michael Kerrisk): 1. spell out SETUID in SECBIT_NO_SETUID* 2. SECBIT_X_LOCKED does not imply SECBIT_X 3. add definitions for keepcaps Oct 14: As suggested by Michael Kerrisk, don't use SB_* as that convention is already in use. Use SECBIT_ prefix instead. Signed-off-by: Serge E. Hallyn Acked-by: Andrew G. Morgan Acked-by: Michael Kerrisk Cc: Ulrich Drepper Cc: James Morris Signed-off-by: James Morris --- include/linux/Kbuild | 1 + include/linux/securebits.h | 24 ++++++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/include/linux/Kbuild b/include/linux/Kbuild index cff4a101f26..ffcdb9b509d 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -329,6 +329,7 @@ unifdef-y += scc.h unifdef-y += sched.h unifdef-y += screen_info.h unifdef-y += sdla.h +unifdef-y += securebits.h unifdef-y += selinux_netlink.h unifdef-y += sem.h unifdef-y += serial_core.h diff --git a/include/linux/securebits.h b/include/linux/securebits.h index d2c5ed845bc..33406174cbe 100644 --- a/include/linux/securebits.h +++ b/include/linux/securebits.h @@ -1,6 +1,15 @@ #ifndef _LINUX_SECUREBITS_H #define _LINUX_SECUREBITS_H 1 +/* Each securesetting is implemented using two bits. One bit specifies + whether the setting is on or off. The other bit specify whether the + setting is locked or not. A setting which is locked cannot be + changed from user-level. */ +#define issecure_mask(X) (1 << (X)) +#ifdef __KERNEL__ +#define issecure(X) (issecure_mask(X) & current_cred_xxx(securebits)) +#endif + #define SECUREBITS_DEFAULT 0x00000000 /* When set UID 0 has no special privileges. When unset, we support @@ -12,6 +21,9 @@ #define SECURE_NOROOT 0 #define SECURE_NOROOT_LOCKED 1 /* make bit-0 immutable */ +#define SECBIT_NOROOT (issecure_mask(SECURE_NOROOT)) +#define SECBIT_NOROOT_LOCKED (issecure_mask(SECURE_NOROOT_LOCKED)) + /* When set, setuid to/from uid 0 does not trigger capability-"fixup". When unset, to provide compatiblility with old programs relying on set*uid to gain/lose privilege, transitions to/from uid 0 cause @@ -19,6 +31,10 @@ #define SECURE_NO_SETUID_FIXUP 2 #define SECURE_NO_SETUID_FIXUP_LOCKED 3 /* make bit-2 immutable */ +#define SECBIT_NO_SETUID_FIXUP (issecure_mask(SECURE_NO_SETUID_FIXUP)) +#define SECBIT_NO_SETUID_FIXUP_LOCKED \ + (issecure_mask(SECURE_NO_SETUID_FIXUP_LOCKED)) + /* When set, a process can retain its capabilities even after transitioning to a non-root user (the set-uid fixup suppressed by bit 2). Bit-4 is cleared when a process calls exec(); setting both @@ -27,12 +43,8 @@ #define SECURE_KEEP_CAPS 4 #define SECURE_KEEP_CAPS_LOCKED 5 /* make bit-4 immutable */ -/* Each securesetting is implemented using two bits. One bit specifies - whether the setting is on or off. The other bit specify whether the - setting is locked or not. A setting which is locked cannot be - changed from user-level. */ -#define issecure_mask(X) (1 << (X)) -#define issecure(X) (issecure_mask(X) & current_cred_xxx(securebits)) +#define SECBIT_KEEP_CAPS (issecure_mask(SECURE_KEEP_CAPS)) +#define SECBIT_KEEP_CAPS_LOCKED (issecure_mask(SECURE_KEEP_CAPS_LOCKED)) #define SECURE_ALL_BITS (issecure_mask(SECURE_NOROOT) | \ issecure_mask(SECURE_NO_SETUID_FIXUP) | \ From 3507d612366a4e81226295f646410130a1f62a5c Mon Sep 17 00:00:00 2001 From: Rajiv Andrade Date: Thu, 10 Sep 2009 17:09:35 -0300 Subject: [PATCH 066/298] tpm_tis: TPM_STS_DATA_EXPECT workaround Some newer Lenovo models are shipped with a TPM that doesn't seem to set the TPM_STS_DATA_EXPECT status bit when sending it a burst of data, so the code understands it as a failure and doesn't proceed sending the chip the intended data. In this patch we bypass this bit check in case the itpm module parameter was set. This patch is based on Andy Isaacson's one: http://marc.info/?l=linux-kernel&m=124650185023495&w=2 It was heavily discussed how should we deal with identifying the chip in kernel space, but the required patch to do so was NACK'd: http://marc.info/?l=linux-kernel&m=124650186423711&w=2 This way we let the user choose using this workaround or not based on his observations on this code behavior when trying to use the TPM. Fixed a checkpatch issue present on the previous patch, thanks to Daniel Walker. Signed-off-by: Rajiv Andrade Acked-by: Eric Paris Tested-by: Seiji Munetoh Signed-off-by: James Morris --- drivers/char/tpm/tpm_tis.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 0b73e4ec1ad..27e8de41530 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -257,6 +257,10 @@ out: return size; } +static int itpm; +module_param(itpm, bool, 0444); +MODULE_PARM_DESC(itpm, "Force iTPM workarounds (found on some Lenovo laptops)"); + /* * If interrupts are used (signaled by an irq set in the vendor structure) * tpm.c can skip polling for the data to be available as the interrupt is @@ -293,7 +297,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &chip->vendor.int_queue); status = tpm_tis_status(chip); - if ((status & TPM_STS_DATA_EXPECT) == 0) { + if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) { rc = -EIO; goto out_err; } @@ -467,6 +471,10 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, "1.2 TPM (device-id 0x%X, rev-id %d)\n", vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); + if (itpm) + dev_info(dev, "Intel iTPM workaround enabled\n"); + + /* Figure out the capabilities */ intfcaps = ioread32(chip->vendor.iobase + From 7b2a35132ad0a70902dcd2844c27ed64cda0ce9b Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 2 Nov 2009 08:50:52 +0800 Subject: [PATCH 067/298] compiler: Introduce __always_unused I wrote some code which is used as compile-time checker, and the code should be elided after compile. So I need to annotate the code as "always unused", compared to "maybe unused". Signed-off-by: Li Zefan Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Linus Torvalds LKML-Reference: <4AEE2CEC.8040206@cn.fujitsu.com> Signed-off-by: Ingo Molnar --- include/linux/compiler-gcc.h | 1 + include/linux/compiler.h | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index a3ed7cb8ca3..73dcf804bc9 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -79,6 +79,7 @@ #define noinline __attribute__((noinline)) #define __attribute_const__ __attribute__((__const__)) #define __maybe_unused __attribute__((unused)) +#define __always_unused __attribute__((unused)) #define __gcc_header(x) #x #define _gcc_header(x) __gcc_header(linux/compiler-gcc##x.h) diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 04fb5135b4e..7947f4f6fa5 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -213,6 +213,10 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); # define __maybe_unused /* unimplemented */ #endif +#ifndef __always_unused +# define __always_unused /* unimplemented */ +#endif + #ifndef noinline #define noinline #endif From 5e9b397292ca0b9409dced33e3a22ec993377064 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 2 Nov 2009 08:51:13 +0800 Subject: [PATCH 068/298] tracing: Fix to use __always_unused attribute ____ftrace_check_##name() is used for compile-time check on F_printk() only, so it should be marked as __unused instead of __used. Signed-off-by: Li Zefan Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Linus Torvalds LKML-Reference: <4AEE2D01.4010305@cn.fujitsu.com> Signed-off-by: Ingo Molnar --- kernel/trace/trace_export.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c index 9753fcc61bc..c74848ddb85 100644 --- a/kernel/trace/trace_export.c +++ b/kernel/trace/trace_export.c @@ -48,11 +48,11 @@ struct ____ftrace_##name { \ tstruct \ }; \ -static void __used ____ftrace_check_##name(void) \ +static void __always_unused ____ftrace_check_##name(void) \ { \ struct ____ftrace_##name *__entry = NULL; \ \ - /* force cmpile-time check on F_printk() */ \ + /* force compile-time check on F_printk() */ \ printk(print); \ } From c5e0cb3ddc5f14cedcfc50c0fb3b5fc6b56576da Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Wed, 28 Oct 2009 08:14:48 -0700 Subject: [PATCH 069/298] rcu: Cleanup: balance rcu_irq_enter()/rcu_irq_exit() calls Currently, rcu_irq_exit() is invoked only for CONFIG_NO_HZ, while rcu_irq_enter() is invoked unconditionally. This patch moves rcu_irq_exit() out from under CONFIG_NO_HZ so that the calls are balanced. This patch has no effect on the behavior of the kernel because both rcu_irq_enter() and rcu_irq_exit() are empty for !CONFIG_NO_HZ, but the code is easier to understand if the calls are obviously balanced in all cases. Signed-off-by: Lai Jiangshan Signed-off-by: Paul E. McKenney Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12567428891605-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/softirq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/softirq.c b/kernel/softirq.c index f8749e5216e..21939d9e830 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -302,9 +302,9 @@ void irq_exit(void) if (!in_interrupt() && local_softirq_pending()) invoke_softirq(); + rcu_irq_exit(); #ifdef CONFIG_NO_HZ /* Make sure that timer wheel updates are propagated */ - rcu_irq_exit(); if (idle_cpu(smp_processor_id()) && !in_interrupt() && !need_resched()) tick_nohz_stop_sched_tick(0); #endif From 4dae560f97fa438f373b53e14b30149c9e44a600 Mon Sep 17 00:00:00 2001 From: Ananth N Mavinakayanahalli Date: Fri, 30 Oct 2009 19:23:10 +0530 Subject: [PATCH 070/298] kprobes: Sanitize struct kretprobe_instance allocations For as long as kretprobes have existed, we've allocated NR_CPUS instances of kretprobe_instance structures. With the default value of CONFIG_NR_CPUS increasing on certain architectures, we are potentially wasting kernel memory. See http://sourceware.org/bugzilla/show_bug.cgi?id=10839#c3 for more details. Use a saner num_possible_cpus() instead of NR_CPUS for allocation. Signed-off-by: Ananth N Mavinakayanahalli Acked-by: Masami Hiramatsu Cc: Jim Keniston Cc: fweisbec@gmail.com LKML-Reference: <20091030135310.GA22230@in.ibm.com> Signed-off-by: Ingo Molnar --- kernel/kprobes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 5240d75f4c6..1494e85b35f 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1014,9 +1014,9 @@ int __kprobes register_kretprobe(struct kretprobe *rp) /* Pre-allocate memory for max kretprobe instances */ if (rp->maxactive <= 0) { #ifdef CONFIG_PREEMPT - rp->maxactive = max(10, 2 * NR_CPUS); + rp->maxactive = max(10, 2 * num_possible_cpus()); #else - rp->maxactive = NR_CPUS; + rp->maxactive = num_possible_cpus(); #endif } spin_lock_init(&rp->lock); From 31bde71c202722a76686c3cf69a254c8a912275a Mon Sep 17 00:00:00 2001 From: Matt Domsch Date: Tue, 3 Nov 2009 12:05:50 +1100 Subject: [PATCH 071/298] tpm: autoload tpm_tis based on system PnP IDs The tpm_tis driver already has a list of supported pnp_device_ids. This patch simply exports that list as a MODULE_DEVICE_TABLE() so that the module autoloader will discover and load the module at boottime. Signed-off-by: Matt Domsch Acked-by: Rajiv Andrade Signed-off-by: Andrew Morton Signed-off-by: James Morris --- drivers/char/tpm/tpm_tis.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 27e8de41530..2405f17b29d 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -637,6 +637,7 @@ static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = { {"", 0}, /* User Specified */ {"", 0} /* Terminator */ }; +MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl); static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev) { From 24b26d4211130b6455692804c14d537158855cd7 Mon Sep 17 00:00:00 2001 From: Liuweni Date: Wed, 4 Nov 2009 20:11:05 +0800 Subject: [PATCH 072/298] irq: Fix docbook comments Fix docbook comments to match the actual function names (set_irq_msi, handle_percpu_irq). Signed-off-by: Liuwenyi Signed-off-by: Thomas Gleixner --- kernel/irq/chip.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index c1660194d11..ba566c261ad 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -166,11 +166,11 @@ int set_irq_data(unsigned int irq, void *data) EXPORT_SYMBOL(set_irq_data); /** - * set_irq_data - set irq type data for an irq + * set_irq_msi - set MSI descriptor data for an irq * @irq: Interrupt number * @entry: Pointer to MSI descriptor data * - * Set the hardware irq controller data for an irq + * Set the MSI descriptor entry for an irq */ int set_irq_msi(unsigned int irq, struct msi_desc *entry) { @@ -590,7 +590,7 @@ out_unlock: } /** - * handle_percpu_IRQ - Per CPU local irq handler + * handle_percpu_irq - Per CPU local irq handler * @irq: the interrupt number * @desc: the interrupt description structure for this irq * From 663e69592856df53ef52969482ef413a96bc4e06 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 4 Nov 2009 14:22:21 +0100 Subject: [PATCH 073/298] irq: Remove unused debug_poll_all_shared_irqs() commit 74296a8ed added this function for debug purposes, but it was never used for anything. Remove it. Signed-off-by: Thomas Gleixner --- include/linux/interrupt.h | 6 ------ kernel/irq/spurious.c | 14 +------------- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 7ca72b74eec..75f3f00ac1e 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -603,12 +603,6 @@ static inline void init_irq_proc(void) } #endif -#if defined(CONFIG_GENERIC_HARDIRQS) && defined(CONFIG_DEBUG_SHIRQ) -extern void debug_poll_all_shared_irqs(void); -#else -static inline void debug_poll_all_shared_irqs(void) { } -#endif - struct seq_file; int show_interrupts(struct seq_file *p, void *v); diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index 114e704760f..8996b98f9eb 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -104,7 +104,7 @@ static int misrouted_irq(int irq) return ok; } -static void poll_all_shared_irqs(void) +static void poll_spurious_irqs(unsigned long dummy) { struct irq_desc *desc; int i; @@ -123,23 +123,11 @@ static void poll_all_shared_irqs(void) try_one_irq(i, desc); } -} - -static void poll_spurious_irqs(unsigned long dummy) -{ - poll_all_shared_irqs(); mod_timer(&poll_spurious_irq_timer, jiffies + POLL_SPURIOUS_IRQ_INTERVAL); } -#ifdef CONFIG_DEBUG_SHIRQ -void debug_poll_all_shared_irqs(void) -{ - poll_all_shared_irqs(); -} -#endif - /* * If 99,900 of the previous 100,000 interrupts have not been handled * then assume that the IRQ is stuck in some manner. Drop a diagnostic From 2a855dd01bc1539111adb7233f587c5c468732ac Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Sun, 25 Oct 2009 15:37:58 +0100 Subject: [PATCH 074/298] signal: Fix alternate signal stack check All architectures in the kernel increment/decrement the stack pointer before storing values on the stack. On architectures which have the stack grow down sas_ss_sp == sp is not on the alternate signal stack while sas_ss_sp + sas_ss_size == sp is on the alternate signal stack. On architectures which have the stack grow up sas_ss_sp == sp is on the alternate signal stack while sas_ss_sp + sas_ss_size == sp is not on the alternate signal stack. The current implementation fails for architectures which have the stack grow down on the corner case where sas_ss_sp == sp.This was reported as Debian bug #544905 on AMD64. Simplified test case: http://download.breakpoint.cc/tc-sig-stack.c The test case creates the following stack scenario: 0xn0300 stack top 0xn0200 alt stack pointer top (when switching to alt stack) 0xn01ff alt stack end 0xn0100 alt stack start == stack pointer If the signal is sent the stack pointer is pointing to the base address of the alt stack and the kernel erroneously decides that it has already switched to the alternate stack because of the current check for "sp - sas_ss_sp < sas_ss_size" On parisc (stack grows up) the scenario would be: 0xn0200 stack pointer 0xn01ff alt stack end 0xn0100 alt stack start = alt stack pointer base (when switching to alt stack) 0xn0000 stack base This is handled correctly by the current implementation. [ tglx: Modified for archs which have the stack grow up (parisc) which would fail with the correct implementation for stack grows down. Added a check for sp >= current->sas_ss_sp which is strictly not necessary but makes the code symetric for both variants ] Signed-off-by: Sebastian Andrzej Siewior Cc: Oleg Nesterov Cc: Roland McGrath Cc: Kyle McMartin Cc: stable@kernel.org LKML-Reference: <20091025143758.GA6653@Chamillionaire.breakpoint.cc> Signed-off-by: Thomas Gleixner --- include/linux/sched.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 75e6e60bf58..0f67914a43c 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2086,11 +2086,18 @@ static inline int is_si_special(const struct siginfo *info) return info <= SEND_SIG_FORCED; } -/* True if we are on the alternate signal stack. */ - +/* + * True if we are on the alternate signal stack. + */ static inline int on_sig_stack(unsigned long sp) { - return (sp - current->sas_ss_sp < current->sas_ss_size); +#ifdef CONFIG_STACK_GROWSUP + return sp >= current->sas_ss_sp && + sp - current->sas_ss_sp < current->sas_ss_size; +#else + return sp > current->sas_ss_sp && + sp - current->sas_ss_sp <= current->sas_ss_size; +#endif } static inline int sas_ss_flags(unsigned long sp) From 338bac527ed0e35b4cb50390972f15d3cbce92ca Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 27 Oct 2009 16:34:44 +0900 Subject: [PATCH 075/298] x86: Use x86_platform for iommu_shutdown This patch cleans up pci_iommu_shutdown() a bit to use x86_platform (similar to how IA64 initializes an IOMMU driver). This adds iommu_shutdown() to x86_platform to avoid calling every IOMMUs' shutdown functions in pci_iommu_shutdown() in order. The IOMMU shutdown functions are platform specific (we don't have multiple different IOMMU hardware) so the current way is pointless. An IOMMU driver sets x86_platform.iommu_shutdown to the shutdown function if necessary. Signed-off-by: FUJITA Tomonori Cc: joerg.roedel@amd.com LKML-Reference: <20091027163358F.fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/amd_iommu.h | 2 -- arch/x86/include/asm/gart.h | 4 ---- arch/x86/include/asm/iommu.h | 2 +- arch/x86/include/asm/x86_init.h | 1 + arch/x86/kernel/amd_iommu_init.c | 6 +----- arch/x86/kernel/crash.c | 5 ++--- arch/x86/kernel/pci-dma.c | 7 ------- arch/x86/kernel/pci-gart_64.c | 6 ++++-- arch/x86/kernel/reboot.c | 4 ++-- arch/x86/kernel/x86_init.c | 2 ++ 10 files changed, 13 insertions(+), 26 deletions(-) diff --git a/arch/x86/include/asm/amd_iommu.h b/arch/x86/include/asm/amd_iommu.h index 4b180897e6b..3604669f7b1 100644 --- a/arch/x86/include/asm/amd_iommu.h +++ b/arch/x86/include/asm/amd_iommu.h @@ -30,12 +30,10 @@ extern void amd_iommu_detect(void); extern irqreturn_t amd_iommu_int_handler(int irq, void *data); extern void amd_iommu_flush_all_domains(void); extern void amd_iommu_flush_all_devices(void); -extern void amd_iommu_shutdown(void); extern void amd_iommu_apply_erratum_63(u16 devid); #else static inline int amd_iommu_init(void) { return -ENODEV; } static inline void amd_iommu_detect(void) { } -static inline void amd_iommu_shutdown(void) { } #endif #endif /* _ASM_X86_AMD_IOMMU_H */ diff --git a/arch/x86/include/asm/gart.h b/arch/x86/include/asm/gart.h index 6cfdafa409d..4fdd5b3f87b 100644 --- a/arch/x86/include/asm/gart.h +++ b/arch/x86/include/asm/gart.h @@ -36,7 +36,6 @@ extern int gart_iommu_aperture_disabled; extern void early_gart_iommu_check(void); extern void gart_iommu_init(void); -extern void gart_iommu_shutdown(void); extern void __init gart_parse_options(char *); extern void gart_iommu_hole_init(void); @@ -51,9 +50,6 @@ static inline void early_gart_iommu_check(void) static inline void gart_iommu_init(void) { } -static inline void gart_iommu_shutdown(void) -{ -} static inline void gart_parse_options(char *options) { } diff --git a/arch/x86/include/asm/iommu.h b/arch/x86/include/asm/iommu.h index fd6d21bbee6..878b3071576 100644 --- a/arch/x86/include/asm/iommu.h +++ b/arch/x86/include/asm/iommu.h @@ -1,7 +1,7 @@ #ifndef _ASM_X86_IOMMU_H #define _ASM_X86_IOMMU_H -extern void pci_iommu_shutdown(void); +static inline void iommu_shutdown_noop(void) {} extern void no_iommu_init(void); extern struct dma_map_ops nommu_dma_ops; extern int force_iommu, no_iommu; diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index 2c756fd4ab0..66008ed80b7 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h @@ -121,6 +121,7 @@ struct x86_platform_ops { unsigned long (*calibrate_tsc)(void); unsigned long (*get_wallclock)(void); int (*set_wallclock)(unsigned long nowtime); + void (*iommu_shutdown)(void); }; extern struct x86_init_ops x86_init; diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index c20001e4f55..6acd43e9afd 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -1297,6 +1297,7 @@ int __init amd_iommu_init(void) else printk(KERN_INFO "AMD-Vi: Lazy IO/TLB flushing enabled\n"); + x86_platform.iommu_shutdown = disable_iommus; out: return ret; @@ -1323,11 +1324,6 @@ free: goto out; } -void amd_iommu_shutdown(void) -{ - disable_iommus(); -} - /**************************************************************************** * * Early detect code. This code runs at IOMMU detection time in the DMA diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index 5e409dc298a..a4849c10a77 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c @@ -27,8 +27,7 @@ #include #include #include -#include - +#include #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) @@ -106,7 +105,7 @@ void native_machine_crash_shutdown(struct pt_regs *regs) #endif #ifdef CONFIG_X86_64 - pci_iommu_shutdown(); + x86_platform.iommu_shutdown(); #endif crash_save_cpu(regs, safe_smp_processor_id()); diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index b2a71dca564..ce2fb91bbed 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -303,13 +303,6 @@ static int __init pci_iommu_init(void) no_iommu_init(); return 0; } - -void pci_iommu_shutdown(void) -{ - gart_iommu_shutdown(); - - amd_iommu_shutdown(); -} /* Must execute after PCI subsystem */ rootfs_initcall(pci_iommu_init); diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index a7f1b64f86e..a9bcdf7c880 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c @@ -39,6 +39,7 @@ #include #include #include +#include static unsigned long iommu_bus_base; /* GART remapping area (physical) */ static unsigned long iommu_size; /* size of remapping area bytes */ @@ -688,12 +689,12 @@ static struct dma_map_ops gart_dma_ops = { .free_coherent = gart_free_coherent, }; -void gart_iommu_shutdown(void) +static void gart_iommu_shutdown(void) { struct pci_dev *dev; int i; - if (no_agp && (dma_ops != &gart_dma_ops)) + if (no_agp) return; for (i = 0; i < num_k8_northbridges; i++) { @@ -838,6 +839,7 @@ void __init gart_iommu_init(void) flush_gart(); dma_ops = &gart_dma_ops; + x86_platform.iommu_shutdown = gart_iommu_shutdown; } void __init gart_parse_options(char *p) diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index f93078746e0..2b97fc5b124 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -23,7 +23,7 @@ # include # include #else -# include +# include #endif /* @@ -622,7 +622,7 @@ void native_machine_shutdown(void) #endif #ifdef CONFIG_X86_64 - pci_iommu_shutdown(); + x86_platform.iommu_shutdown(); #endif } diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index 4449a4a2c2e..bc9b230ef40 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c @@ -14,6 +14,7 @@ #include #include #include +#include void __cpuinit x86_init_noop(void) { } void __init x86_init_uint_noop(unsigned int unused) { } @@ -72,4 +73,5 @@ struct x86_platform_ops x86_platform = { .calibrate_tsc = native_calibrate_tsc, .get_wallclock = mach_get_cmos_time, .set_wallclock = mach_set_rtc_mmss, + .iommu_shutdown = iommu_shutdown_noop, }; From c82a43d40b93200a10a9fec0a489791e65e135ca Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 26 Oct 2009 23:28:11 +0300 Subject: [PATCH 076/298] irq: Do not attempt to create subdirectories if /proc/irq/ failed If a parent directory (ie /proc/irq/) could not be created we should not attempt to create subdirectories. Otherwise it would lead that "smp_affinity" and "spurious" entries are may be registered under /proc root instead of a proper place. Signed-off-by: Cyrill Gorcunov Cc: Rusty Russell Cc: Yinghai Lu LKML-Reference: <20091026202811.GD5321@lenovo> Signed-off-by: Ingo Molnar --- kernel/irq/proc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 692363dd591..dfef5b9f384 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -214,6 +214,8 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc) /* create /proc/irq/1234 */ desc->dir = proc_mkdir(name, root_irq_dir); + if (!desc->dir) + return; #ifdef CONFIG_SMP /* create /proc/irq//smp_affinity */ From 2ae8bb75db1f3de422eb5898f2a063c46c36dba8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 26 Oct 2009 15:41:46 +0100 Subject: [PATCH 077/298] x86: Fix iommu=nodac parameter handling iommu=nodac should forbid dac instead of enabling it. Fix it. Signed-off-by: Tejun Heo Acked-by: FUJITA Tomonori Cc: Matteo Frigo Cc: # .32.x and older LKML-Reference: <4AE5B52A.4050408@kernel.org> Signed-off-by: Ingo Molnar --- arch/x86/kernel/pci-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index ce2fb91bbed..839d49a669b 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -216,7 +216,7 @@ static __init int iommu_setup(char *p) if (!strncmp(p, "allowdac", 8)) forbid_dac = 0; if (!strncmp(p, "nodac", 5)) - forbid_dac = -1; + forbid_dac = 1; if (!strncmp(p, "usedac", 6)) { forbid_dac = -1; return 1; From 7d2e8d00b47b973c92db4df7444d5e6d3bb945f9 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sun, 18 Oct 2009 18:22:32 +0200 Subject: [PATCH 078/298] pcmcia: use pre-determined values A few PCMCIA network drivers can make use of values provided by the pcmcia core, instead of tedious, independent CIS parsing. xirc32ps_cs.c: manf_id hostap_cs.c: multifunction count b43/pcmcia.c: ConfigBase address and "Present" smc91c92_cs.c: By default, mhz_setup() can use VERS_1 as it is stored in struct pcmcia_device. Only some cards require workarounds, such as reading out VERS_1 twice. CC: David S. Miller CC: netdev@vger.kernel.org CC: linux-wireless@vger.kernel.org Acked-by: John W. Linville Signed-off-by: Dominik Brodowski --- drivers/net/pcmcia/smc91c92_cs.c | 11 +++++++++-- drivers/net/pcmcia/xirc2ps_cs.c | 12 +++++++++--- drivers/net/wireless/b43/pcmcia.c | 20 -------------------- drivers/net/wireless/hostap/hostap_cs.c | 21 +-------------------- 4 files changed, 19 insertions(+), 45 deletions(-) diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 7bde2cd34c7..af03759d186 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -545,6 +545,14 @@ static int mhz_setup(struct pcmcia_device *link) u_char *buf, *station_addr; int rc; + /* Read the station address from the CIS. It is stored as the last + (fourth) string in the Version 1 Version/ID tuple. */ + if ((link->prod_id[3]) && + (cvt_ascii_address(dev, link->prod_id[3]) == 0)) + return 0; + + /* Workarounds for broken cards start here. */ + cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL); if (!cfg_mem) return -1; @@ -557,8 +565,7 @@ static int mhz_setup(struct pcmcia_device *link) tuple->TupleData = (cisdata_t *)buf; tuple->TupleDataMax = 255; - /* Read the station address from the CIS. It is stored as the last - (fourth) string in the Version 1 Version/ID tuple. */ + /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */ tuple->DesiredTuple = CISTPL_VERS_1; if (first_tuple(link, tuple, parse) != 0) { rc = -1; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index cf842310253..5e203230144 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -792,13 +792,12 @@ xirc2ps_config(struct pcmcia_device * link) tuple.TupleOffset = 0; /* Is this a valid card */ - tuple.DesiredTuple = CISTPL_MANFID; - if ((err=first_tuple(link, &tuple, &parse))) { + if (link->has_manf_id == 0) { printk(KNOT_XIRC "manfid not found in CIS\n"); goto failure; } - switch(parse.manfid.manf) { + switch (link->manf_id) { case MANFID_XIRCOM: local->manf_str = "Xircom"; break; @@ -822,6 +821,13 @@ xirc2ps_config(struct pcmcia_device * link) } DEBUG(0, "found %s card\n", local->manf_str); + /* needed for the additional fields to be parsed by set_card_type() */ + tuple.DesiredTuple = CISTPL_MANFID; + err = first_tuple(link, &tuple, &parse) + if (err) { + printk(KNOT_XIRC "manfid not found in CIS\n"); + goto failure; + } if (!set_card_type(link, buf)) { printk(KNOT_XIRC "this card is not supported\n"); goto failure; diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c index 6c3a74964ab..cd14b7e8ba8 100644 --- a/drivers/net/wireless/b43/pcmcia.c +++ b/drivers/net/wireless/b43/pcmcia.c @@ -65,35 +65,15 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) struct ssb_bus *ssb; win_req_t win; memreq_t mem; - tuple_t tuple; - cisparse_t parse; int err = -ENOMEM; int res = 0; - unsigned char buf[64]; ssb = kzalloc(sizeof(*ssb), GFP_KERNEL); if (!ssb) goto out_error; err = -ENODEV; - tuple.DesiredTuple = CISTPL_CONFIG; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - res = pcmcia_get_first_tuple(dev, &tuple); - if (res != 0) - goto err_kfree_ssb; - res = pcmcia_get_tuple_data(dev, &tuple); - if (res != 0) - goto err_kfree_ssb; - res = pcmcia_parse_tuple(&tuple, &parse); - if (res != 0) - goto err_kfree_ssb; - - dev->conf.ConfigBase = parse.config.base; - dev->conf.Present = parse.config.rmask[0]; dev->conf.Attributes = CONF_ENABLE_IRQ; dev->conf.IntType = INT_MEMORY_AND_IO; diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index ad8eab4a639..31b60dd87bf 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -274,9 +274,6 @@ static int sandisk_enable_wireless(struct net_device *dev) conf_reg_t reg; struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; - tuple_t tuple; - cisparse_t *parse = NULL; - u_char buf[64]; struct hostap_cs_priv *hw_priv = local->hw_priv; if (hw_priv->link->io.NumPorts1 < 0x42) { @@ -285,28 +282,13 @@ static int sandisk_enable_wireless(struct net_device *dev) goto done; } - parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL); - if (parse == NULL) { - ret = -ENOMEM; - goto done; - } - - tuple.Attributes = TUPLE_RETURN_COMMON; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - if (hw_priv->link->manf_id != 0xd601 || hw_priv->link->card_id != 0x0101) { /* No SanDisk manfid found */ ret = -ENODEV; goto done; } - tuple.DesiredTuple = CISTPL_LONGLINK_MFC; - if (pcmcia_get_first_tuple(hw_priv->link, &tuple) || - pcmcia_get_tuple_data(hw_priv->link, &tuple) || - pcmcia_parse_tuple(&tuple, parse) || - parse->longlink_mfc.nfn < 2) { + if (hw_priv->link->socket->functions < 2) { /* No multi-function links found */ ret = -ENODEV; goto done; @@ -354,7 +336,6 @@ static int sandisk_enable_wireless(struct net_device *dev) udelay(10); done: - kfree(parse); return ret; } From aaa8cfdada648a6bae32f62df76cc60137a2b323 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sun, 18 Oct 2009 18:28:39 +0200 Subject: [PATCH 079/298] pcmcia: use pcmcia_loop_config in misc pcmcia drivers Use pcmcia_loop_config() in a few drivers missed during the first round. On fmvj18x_cs.c it -- strangely -- only requries us to set conf.ConfigIndex, which is done by the core, so include an empty loop function which returns 0 unconditionally. CC: David S. Miller CC: David Sterba CC: netdev@vger.kernel.org CC: linux-wireless@vger.kernel.org For the ipwireless part: Acked-by: Jiri Kosina Acked-by: John W. Linville Signed-off-by: Dominik Brodowski --- drivers/char/pcmcia/ipwireless/main.c | 103 ++++++-------------------- drivers/char/pcmcia/synclink_cs.c | 64 ++++++---------- drivers/net/pcmcia/fmvj18x_cs.c | 22 ++++-- drivers/net/wireless/libertas/if_cs.c | 67 +++++++---------- 4 files changed, 88 insertions(+), 168 deletions(-) diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c index 5216fce0c62..263a18f381b 100644 --- a/drivers/char/pcmcia/ipwireless/main.c +++ b/drivers/char/pcmcia/ipwireless/main.c @@ -79,14 +79,32 @@ static void signalled_reboot_callback(void *callback_data) schedule_work(&ipw->work_reboot); } +static int ipwireless_ioprobe(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + p_dev->io.BasePort1 = cfg->io.win[0].base; + p_dev->io.NumPorts1 = cfg->io.win[0].len; + p_dev->io.IOAddrLines = 16; + + p_dev->irq.IRQInfo1 = cfg->irq.IRQInfo1; + + /* 0x40 causes it to generate level mode interrupts. */ + /* 0x04 enables IREQ pin. */ + p_dev->conf.ConfigIndex = cfg->index | 0x44; + return pcmcia_request_io(p_dev, &p_dev->io); +} + static int config_ipwireless(struct ipw_dev *ipw) { struct pcmcia_device *link = ipw->link; - int ret; + int ret = 0; tuple_t tuple; unsigned short buf[64]; cisparse_t parse; - unsigned short cor_value; memreq_t memreq_attr_memory; memreq_t memreq_common_memory; @@ -97,103 +115,26 @@ static int config_ipwireless(struct ipw_dev *ipw) tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - tuple.DesiredTuple = RETURN_FIRST_TUPLE; - - ret = pcmcia_get_first_tuple(link, &tuple); - - while (ret == 0) { - ret = pcmcia_get_tuple_data(link, &tuple); - - if (ret != 0) { - cs_error(link, GetTupleData, ret); - goto exit0; - } - ret = pcmcia_get_next_tuple(link, &tuple); - } - - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - - ret = pcmcia_get_first_tuple(link, &tuple); - + ret = pcmcia_loop_config(link, ipwireless_ioprobe, NULL); if (ret != 0) { - cs_error(link, GetFirstTuple, ret); + cs_error(link, RequestIO, ret); goto exit0; } - ret = pcmcia_get_tuple_data(link, &tuple); - - if (ret != 0) { - cs_error(link, GetTupleData, ret); - goto exit0; - } - - ret = pcmcia_parse_tuple(&tuple, &parse); - - if (ret != 0) { - cs_error(link, ParseTuple, ret); - goto exit0; - } - - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - link->io.BasePort1 = parse.cftable_entry.io.win[0].base; - link->io.NumPorts1 = parse.cftable_entry.io.win[0].len; - link->io.IOAddrLines = 16; - - link->irq.IRQInfo1 = parse.cftable_entry.irq.IRQInfo1; - - /* 0x40 causes it to generate level mode interrupts. */ - /* 0x04 enables IREQ pin. */ - cor_value = parse.cftable_entry.index | 0x44; - link->conf.ConfigIndex = cor_value; - - /* IRQ and I/O settings */ - tuple.DesiredTuple = CISTPL_CONFIG; - - ret = pcmcia_get_first_tuple(link, &tuple); - - if (ret != 0) { - cs_error(link, GetFirstTuple, ret); - goto exit0; - } - - ret = pcmcia_get_tuple_data(link, &tuple); - - if (ret != 0) { - cs_error(link, GetTupleData, ret); - goto exit0; - } - - ret = pcmcia_parse_tuple(&tuple, &parse); - - if (ret != 0) { - cs_error(link, GetTupleData, ret); - goto exit0; - } link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; link->conf.IntType = INT_MEMORY_AND_IO; link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; link->irq.Handler = ipwireless_interrupt; link->irq.Instance = ipw->hardware; - ret = pcmcia_request_io(link, &link->io); - - if (ret != 0) { - cs_error(link, RequestIO, ret); - goto exit0; - } - request_region(link->io.BasePort1, link->io.NumPorts1, IPWIRELESS_PCCARD_NAME); /* memory settings */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; ret = pcmcia_get_first_tuple(link, &tuple); - if (ret != 0) { cs_error(link, GetFirstTuple, ret); goto exit1; diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index caf6e4d1946..429b7313119 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -575,55 +575,39 @@ static int mgslpc_probe(struct pcmcia_device *link) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) +static int mgslpc_ioprobe(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + if (cfg->io.nwin > 0) { + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(cfg->io.flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(cfg->io.flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK; + p_dev->io.BasePort1 = cfg->io.win[0].base; + p_dev->io.NumPorts1 = cfg->io.win[0].len; + return pcmcia_request_io(p_dev, &p_dev->io); + } + return -ENODEV; +} + static int mgslpc_config(struct pcmcia_device *link) { MGSLPC_INFO *info = link->priv; - tuple_t tuple; - cisparse_t parse; - int last_fn, last_ret; - u_char buf[64]; - cistpl_cftable_entry_t dflt = { 0 }; - cistpl_cftable_entry_t *cfg; + int last_fn = RequestIO; + int last_ret; if (debug_level >= DEBUG_LEVEL_INFO) printk("mgslpc_config(0x%p)\n", link); - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - - /* get CIS configuration entry */ - - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - - cfg = &(parse.cftable_entry); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(&tuple, &parse)); - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; - if (cfg->index == 0) + last_ret = pcmcia_loop_config(link, mgslpc_ioprobe, NULL); + if (last_ret != 0) goto cs_failed; - link->conf.ConfigIndex = cfg->index; - link->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - link->io.NumPorts1 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); - } - link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 8; diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 7e01fbdb87e..c7a2bbfaf82 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -341,14 +341,23 @@ static int ungermann_try_io_port(struct pcmcia_device *link) return ret; /* RequestIO failed */ } +static int fmvj18x_ioprobe(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + return 0; /* strange, but that's what the code did already before... */ +} + + static int fmvj18x_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; local_info_t *lp = netdev_priv(dev); tuple_t tuple; - cisparse_t parse; u_short buf[32]; - int i, last_fn = 0, last_ret = 0, ret; + int i, last_fn = RequestIO, last_ret = 0, ret; unsigned int ioaddr; cardtype_t cardtype; char *card_name = "unknown"; @@ -362,12 +371,11 @@ static int fmvj18x_config(struct pcmcia_device *link) tuple.DesiredTuple = CISTPL_FUNCE; tuple.TupleOffset = 0; if (pcmcia_get_first_tuple(link, &tuple) == 0) { + last_ret = pcmcia_loop_config(link, fmvj18x_ioprobe, NULL); + if (last_ret != 0) + goto cs_failed; + /* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(&tuple, &parse)); - link->conf.ConfigIndex = parse.cftable_entry.index; switch (link->manf_id) { case MANFID_TDK: cardtype = TDK; diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 62381768f2d..cb40c386fc7 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -793,18 +793,37 @@ static void if_cs_release(struct pcmcia_device *p_dev) * configure the card at this point -- we wait until we receive a card * insertion event. */ + +static int if_cs_ioprobe(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + p_dev->io.BasePort1 = cfg->io.win[0].base; + p_dev->io.NumPorts1 = cfg->io.win[0].len; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1) + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + if (cfg->io.nwin != 1) { + lbs_pr_err("wrong CIS (check number of IO windows)\n"); + return -ENODEV; + } + + /* This reserves IO space but doesn't actually enable it */ + return pcmcia_request_io(p_dev, &p_dev->io); +} + static int if_cs_probe(struct pcmcia_device *p_dev) { int ret = -ENOMEM; unsigned int prod_id; struct lbs_private *priv; struct if_cs_card *card; - /* CIS parsing */ - tuple_t tuple; - cisparse_t parse; - cistpl_cftable_entry_t *cfg = &parse.cftable_entry; - cistpl_io_t *io = &cfg->io; - u_char buf[64]; lbs_deb_enter(LBS_DEB_CS); @@ -823,43 +842,11 @@ static int if_cs_probe(struct pcmcia_device *p_dev) p_dev->conf.Attributes = 0; p_dev->conf.IntType = INT_MEMORY_AND_IO; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - if ((ret = pcmcia_get_first_tuple(p_dev, &tuple)) != 0 || - (ret = pcmcia_get_tuple_data(p_dev, &tuple)) != 0 || - (ret = pcmcia_parse_tuple(&tuple, &parse)) != 0) - { - lbs_pr_err("error in pcmcia_get_first_tuple etc\n"); + if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) { + lbs_pr_err("error in pcmcia_loop_config\n"); goto out1; } - p_dev->conf.ConfigIndex = cfg->index; - - /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1) { - p_dev->conf.Attributes |= CONF_ENABLE_IRQ; - } - - /* IO window settings */ - if (cfg->io.nwin != 1) { - lbs_pr_err("wrong CIS (check number of IO windows)\n"); - ret = -ENODEV; - goto out1; - } - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - p_dev->io.BasePort1 = io->win[0].base; - p_dev->io.NumPorts1 = io->win[0].len; - - /* This reserves IO space but doesn't actually enable it */ - ret = pcmcia_request_io(p_dev, &p_dev->io); - if (ret) { - lbs_pr_err("error in pcmcia_request_io\n"); - goto out1; - } /* * Allocate an interrupt line. Note that this does not assign From af757923a92e6e9dbfdb6b0264be14c564e1c466 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sun, 18 Oct 2009 19:48:39 +0200 Subject: [PATCH 080/298] ipwireless: make more use of pcmcia_loop_config() Within the pcmcia_loop_config() callback, we already have all tuple data available we need. Also add a fix to release the IO resource (at least within pcmcia_loop_config() error path). CC: Jiri Kosina CC: David Sterba Signed-off-by: Dominik Brodowski --- drivers/char/pcmcia/ipwireless/main.c | 233 ++++++++++++-------------- 1 file changed, 109 insertions(+), 124 deletions(-) diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c index 263a18f381b..0f467495991 100644 --- a/drivers/char/pcmcia/ipwireless/main.c +++ b/drivers/char/pcmcia/ipwireless/main.c @@ -79,12 +79,18 @@ static void signalled_reboot_callback(void *callback_data) schedule_work(&ipw->work_reboot); } -static int ipwireless_ioprobe(struct pcmcia_device *p_dev, - cistpl_cftable_entry_t *cfg, - cistpl_cftable_entry_t *dflt, - unsigned int vcc, - void *priv_data) +static int ipwireless_probe(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) { + struct ipw_dev *ipw = priv_data; + struct resource *io_resource; + memreq_t memreq_attr_memory; + memreq_t memreq_common_memory; + int ret; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; p_dev->io.BasePort1 = cfg->io.win[0].base; p_dev->io.NumPorts1 = cfg->io.win[0].len; @@ -95,30 +101,110 @@ static int ipwireless_ioprobe(struct pcmcia_device *p_dev, /* 0x40 causes it to generate level mode interrupts. */ /* 0x04 enables IREQ pin. */ p_dev->conf.ConfigIndex = cfg->index | 0x44; - return pcmcia_request_io(p_dev, &p_dev->io); + ret = pcmcia_request_io(p_dev, &p_dev->io); + if (ret) + return ret; + + io_resource = request_region(p_dev->io.BasePort1, p_dev->io.NumPorts1, + IPWIRELESS_PCCARD_NAME); + + if (cfg->mem.nwin == 0) + return 0; + + ipw->request_common_memory.Attributes = + WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE; + ipw->request_common_memory.Base = cfg->mem.win[0].host_addr; + ipw->request_common_memory.Size = cfg->mem.win[0].len; + if (ipw->request_common_memory.Size < 0x1000) + ipw->request_common_memory.Size = 0x1000; + ipw->request_common_memory.AccessSpeed = 0; + + ret = pcmcia_request_window(&p_dev, &ipw->request_common_memory, + &ipw->handle_common_memory); + + if (ret != 0) { + cs_error(p_dev, RequestWindow, ret); + goto exit1; + } + + memreq_common_memory.CardOffset = cfg->mem.win[0].card_addr; + memreq_common_memory.Page = 0; + + ret = pcmcia_map_mem_page(ipw->handle_common_memory, + &memreq_common_memory); + + if (ret != 0) { + cs_error(p_dev, MapMemPage, ret); + goto exit2; + } + + ipw->is_v2_card = cfg->mem.win[0].len == 0x100; + + ipw->common_memory = ioremap(ipw->request_common_memory.Base, + ipw->request_common_memory.Size); + request_mem_region(ipw->request_common_memory.Base, + ipw->request_common_memory.Size, + IPWIRELESS_PCCARD_NAME); + + ipw->request_attr_memory.Attributes = + WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE; + ipw->request_attr_memory.Base = 0; + ipw->request_attr_memory.Size = 0; /* this used to be 0x1000 */ + ipw->request_attr_memory.AccessSpeed = 0; + + ret = pcmcia_request_window(&p_dev, &ipw->request_attr_memory, + &ipw->handle_attr_memory); + + if (ret != 0) { + cs_error(p_dev, RequestWindow, ret); + goto exit2; + } + + memreq_attr_memory.CardOffset = 0; + memreq_attr_memory.Page = 0; + + ret = pcmcia_map_mem_page(ipw->handle_attr_memory, + &memreq_attr_memory); + + if (ret != 0) { + cs_error(p_dev, MapMemPage, ret); + goto exit3; + } + + ipw->attr_memory = ioremap(ipw->request_attr_memory.Base, + ipw->request_attr_memory.Size); + request_mem_region(ipw->request_attr_memory.Base, + ipw->request_attr_memory.Size, IPWIRELESS_PCCARD_NAME); + + return 0; + +exit3: + pcmcia_release_window(ipw->handle_attr_memory); +exit2: + if (ipw->common_memory) { + release_mem_region(ipw->request_common_memory.Base, + ipw->request_common_memory.Size); + iounmap(ipw->common_memory); + pcmcia_release_window(ipw->handle_common_memory); + } else + pcmcia_release_window(ipw->handle_common_memory); +exit1: + release_resource(io_resource); + pcmcia_disable_device(p_dev); + return -1; } static int config_ipwireless(struct ipw_dev *ipw) { struct pcmcia_device *link = ipw->link; int ret = 0; - tuple_t tuple; - unsigned short buf[64]; - cisparse_t parse; - memreq_t memreq_attr_memory; - memreq_t memreq_common_memory; ipw->is_v2_card = 0; - tuple.Attributes = 0; - tuple.TupleData = (cisdata_t *) buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - - ret = pcmcia_loop_config(link, ipwireless_ioprobe, NULL); + ret = pcmcia_loop_config(link, ipwireless_probe, ipw); if (ret != 0) { cs_error(link, RequestIO, ret); - goto exit0; + return ret; } link->conf.Attributes = CONF_ENABLE_IRQ; @@ -128,101 +214,6 @@ static int config_ipwireless(struct ipw_dev *ipw) link->irq.Handler = ipwireless_interrupt; link->irq.Instance = ipw->hardware; - request_region(link->io.BasePort1, link->io.NumPorts1, - IPWIRELESS_PCCARD_NAME); - - /* memory settings */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - - ret = pcmcia_get_first_tuple(link, &tuple); - if (ret != 0) { - cs_error(link, GetFirstTuple, ret); - goto exit1; - } - - ret = pcmcia_get_tuple_data(link, &tuple); - - if (ret != 0) { - cs_error(link, GetTupleData, ret); - goto exit1; - } - - ret = pcmcia_parse_tuple(&tuple, &parse); - - if (ret != 0) { - cs_error(link, ParseTuple, ret); - goto exit1; - } - - if (parse.cftable_entry.mem.nwin > 0) { - ipw->request_common_memory.Attributes = - WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE; - ipw->request_common_memory.Base = - parse.cftable_entry.mem.win[0].host_addr; - ipw->request_common_memory.Size = parse.cftable_entry.mem.win[0].len; - if (ipw->request_common_memory.Size < 0x1000) - ipw->request_common_memory.Size = 0x1000; - ipw->request_common_memory.AccessSpeed = 0; - - ret = pcmcia_request_window(&link, &ipw->request_common_memory, - &ipw->handle_common_memory); - - if (ret != 0) { - cs_error(link, RequestWindow, ret); - goto exit1; - } - - memreq_common_memory.CardOffset = - parse.cftable_entry.mem.win[0].card_addr; - memreq_common_memory.Page = 0; - - ret = pcmcia_map_mem_page(ipw->handle_common_memory, - &memreq_common_memory); - - if (ret != 0) { - cs_error(link, MapMemPage, ret); - goto exit1; - } - - ipw->is_v2_card = - parse.cftable_entry.mem.win[0].len == 0x100; - - ipw->common_memory = ioremap(ipw->request_common_memory.Base, - ipw->request_common_memory.Size); - request_mem_region(ipw->request_common_memory.Base, - ipw->request_common_memory.Size, IPWIRELESS_PCCARD_NAME); - - ipw->request_attr_memory.Attributes = - WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE; - ipw->request_attr_memory.Base = 0; - ipw->request_attr_memory.Size = 0; /* this used to be 0x1000 */ - ipw->request_attr_memory.AccessSpeed = 0; - - ret = pcmcia_request_window(&link, &ipw->request_attr_memory, - &ipw->handle_attr_memory); - - if (ret != 0) { - cs_error(link, RequestWindow, ret); - goto exit2; - } - - memreq_attr_memory.CardOffset = 0; - memreq_attr_memory.Page = 0; - - ret = pcmcia_map_mem_page(ipw->handle_attr_memory, - &memreq_attr_memory); - - if (ret != 0) { - cs_error(link, MapMemPage, ret); - goto exit2; - } - - ipw->attr_memory = ioremap(ipw->request_attr_memory.Base, - ipw->request_attr_memory.Size); - request_mem_region(ipw->request_attr_memory.Base, ipw->request_attr_memory.Size, - IPWIRELESS_PCCARD_NAME); - } - INIT_WORK(&ipw->work_reboot, signalled_reboot_work); ipwireless_init_hardware_v1(ipw->hardware, link->io.BasePort1, @@ -234,7 +225,7 @@ static int config_ipwireless(struct ipw_dev *ipw) if (ret != 0) { cs_error(link, RequestIRQ, ret); - goto exit3; + goto exit; } printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n", @@ -257,12 +248,12 @@ static int config_ipwireless(struct ipw_dev *ipw) ipw->network = ipwireless_network_create(ipw->hardware); if (!ipw->network) - goto exit3; + goto exit; ipw->tty = ipwireless_tty_create(ipw->hardware, ipw->network, ipw->nodes); if (!ipw->tty) - goto exit3; + goto exit; ipwireless_init_hardware_v2_v3(ipw->hardware); @@ -274,33 +265,27 @@ static int config_ipwireless(struct ipw_dev *ipw) if (ret != 0) { cs_error(link, RequestConfiguration, ret); - goto exit4; + goto exit; } link->dev_node = &ipw->nodes[0]; return 0; -exit4: - pcmcia_disable_device(link); -exit3: +exit: if (ipw->attr_memory) { release_mem_region(ipw->request_attr_memory.Base, ipw->request_attr_memory.Size); iounmap(ipw->attr_memory); pcmcia_release_window(ipw->handle_attr_memory); - pcmcia_disable_device(link); } -exit2: if (ipw->common_memory) { release_mem_region(ipw->request_common_memory.Base, ipw->request_common_memory.Size); iounmap(ipw->common_memory); pcmcia_release_window(ipw->handle_common_memory); } -exit1: pcmcia_disable_device(link); -exit0: return -1; } From 91284224da5b15ec6c2b45e10fa5eccd1c92a204 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sun, 18 Oct 2009 23:32:33 +0200 Subject: [PATCH 081/298] pcmcia: add new CIS access helpers As a replacement to pcmcia_get_{first,next}_tuple() and pcmcia_get_tuple_data(), three new -- and easier to use -- functions are added: - pcmcia_get_tuple() to get the very first CIS entry of one type. - pcmcia_loop_tuple() to loop over all CIS entries of one type. - pcmcia_get_mac_from_cis() to read out the hardware MAC address from CISTPL_FUNCE. Only a handful of drivers need these functions anyway, as most CIS access is already handled by pcmcia_loop_config(), which now shares the same backed (pccard_loop_tuple()) with pcmcia_loop_tuple(). A pcmcia_get_mac_from_cis() bug noted by Komuro has been fixed in this revision. Signed-off-by: Dominik Brodowski --- Documentation/pcmcia/driver-changes.txt | 7 + drivers/pcmcia/cistpl.c | 61 +++++++ drivers/pcmcia/cs_internal.h | 7 + drivers/pcmcia/pcmcia_resource.c | 225 ++++++++++++++++++++---- drivers/pcmcia/rsrc_mgr.c | 1 + include/pcmcia/ds.h | 63 +++++-- 6 files changed, 311 insertions(+), 53 deletions(-) diff --git a/Documentation/pcmcia/driver-changes.txt b/Documentation/pcmcia/driver-changes.txt index 059934363ca..adfb83e5867 100644 --- a/Documentation/pcmcia/driver-changes.txt +++ b/Documentation/pcmcia/driver-changes.txt @@ -1,5 +1,12 @@ This file details changes in 2.6 which affect PCMCIA card driver authors: +* New CIS tuple access (as of 2.6.33) + Instead of pcmcia_get_{first,next}_tuple(), pcmcia_get_tuple_data() and + pcmcia_parse_tuple(), a driver shall use "pcmcia_get_tuple()" if it is + only interested in one (raw) tuple, or "pcmcia_loop_tuple()" if it is + interested in all tuples of one type. To decode the MAC from CISTPL_FUNCE, + a new helper "pcmcia_get_mac_from_cis()" was added. + * New configuration loop helper (as of 2.6.28) By calling pcmcia_loop_config(), a driver can iterate over all available configuration options. During a driver's probe() phase, one doesn't need diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 6c4a4fc8363..24dd3c1eac0 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -1482,6 +1482,67 @@ done: } EXPORT_SYMBOL(pccard_read_tuple); + +/** + * pccard_loop_tuple() - loop over tuples in the CIS + * @s: the struct pcmcia_socket where the card is inserted + * @function: the device function we loop for + * @code: which CIS code shall we look for? + * @parse: buffer where the tuple shall be parsed (or NULL, if no parse) + * @priv_data: private data to be passed to the loop_tuple function. + * @loop_tuple: function to call for each CIS entry of type @function. IT + * gets passed the raw tuple, the paresed tuple (if @parse is + * set) and @priv_data. + * + * pccard_loop_tuple() loops over all CIS entries of type @function, and + * calls the @loop_tuple function for each entry. If the call to @loop_tuple + * returns 0, the loop exits. Returns 0 on success or errorcode otherwise. + */ +int pccard_loop_tuple(struct pcmcia_socket *s, unsigned int function, + cisdata_t code, cisparse_t *parse, void *priv_data, + int (*loop_tuple) (tuple_t *tuple, + cisparse_t *parse, + void *priv_data)) +{ + tuple_t tuple; + cisdata_t *buf; + int ret; + + buf = kzalloc(256, GFP_KERNEL); + if (buf == NULL) { + dev_printk(KERN_WARNING, &s->dev, "no memory to read tuple\n"); + return -ENOMEM; + } + + tuple.TupleData = buf; + tuple.TupleDataMax = 255; + tuple.TupleOffset = 0; + tuple.DesiredTuple = code; + tuple.Attributes = 0; + + ret = pccard_get_first_tuple(s, function, &tuple); + while (!ret) { + if (pccard_get_tuple_data(s, &tuple)) + goto next_entry; + + if (parse) + if (pcmcia_parse_tuple(&tuple, parse)) + goto next_entry; + + ret = loop_tuple(&tuple, parse, priv_data); + if (!ret) + break; + +next_entry: + ret = pccard_get_next_tuple(s, function, &tuple); + } + + kfree(buf); + return ret; +} +EXPORT_SYMBOL(pccard_loop_tuple); + + /*====================================================================== This tries to determine if a card has a sensible CIS. It returns diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 1f4098f1354..06a14c951e9 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -199,6 +199,13 @@ int pcmcia_replace_cis(struct pcmcia_socket *s, const u8 *data, const size_t len); int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *count); +/* loop over CIS entries */ +int pccard_loop_tuple(struct pcmcia_socket *s, unsigned int function, + cisdata_t code, cisparse_t *parse, void *priv_data, + int (*loop_tuple) (tuple_t *tuple, + cisparse_t *parse, + void *priv_data)); + /* rsrc_mgr.c */ int pcmcia_validate_mem(struct pcmcia_socket *s); struct resource *pcmcia_find_io_region(unsigned long base, diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index d919e96c0af..0bfb05aa8f8 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -885,12 +886,39 @@ EXPORT_SYMBOL(pcmcia_disable_device); struct pcmcia_cfg_mem { - tuple_t tuple; + struct pcmcia_device *p_dev; + void *priv_data; + int (*conf_check) (struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data); cisparse_t parse; - u8 buf[256]; cistpl_cftable_entry_t dflt; }; +/** + * pcmcia_do_loop_config() - internal helper for pcmcia_loop_config() + * + * pcmcia_do_loop_config() is the internal callback for the call from + * pcmcia_loop_config() to pccard_loop_tuple(). Data is transferred + * by a struct pcmcia_cfg_mem. + */ +static int pcmcia_do_loop_config(tuple_t *tuple, cisparse_t *parse, void *priv) +{ + cistpl_cftable_entry_t *cfg = &parse->cftable_entry; + struct pcmcia_cfg_mem *cfg_mem = priv; + + /* default values */ + cfg_mem->p_dev->conf.ConfigIndex = cfg->index; + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) + cfg_mem->dflt = *cfg; + + return cfg_mem->conf_check(cfg_mem->p_dev, cfg, &cfg_mem->dflt, + cfg_mem->p_dev->socket->socket.Vcc, + cfg_mem->priv_data); +} + /** * pcmcia_loop_config() - loop over configuration options * @p_dev: the struct pcmcia_device which we need to loop for. @@ -913,48 +941,173 @@ int pcmcia_loop_config(struct pcmcia_device *p_dev, void *priv_data) { struct pcmcia_cfg_mem *cfg_mem; - - tuple_t *tuple; int ret; - unsigned int vcc; cfg_mem = kzalloc(sizeof(struct pcmcia_cfg_mem), GFP_KERNEL); if (cfg_mem == NULL) return -ENOMEM; - /* get the current Vcc setting */ - vcc = p_dev->socket->socket.Vcc; + cfg_mem->p_dev = p_dev; + cfg_mem->conf_check = conf_check; + cfg_mem->priv_data = priv_data; - tuple = &cfg_mem->tuple; - tuple->TupleData = cfg_mem->buf; - tuple->TupleDataMax = 255; - tuple->TupleOffset = 0; - tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; - tuple->Attributes = 0; - - ret = pcmcia_get_first_tuple(p_dev, tuple); - while (!ret) { - cistpl_cftable_entry_t *cfg = &cfg_mem->parse.cftable_entry; - - if (pcmcia_get_tuple_data(p_dev, tuple)) - goto next_entry; - - if (pcmcia_parse_tuple(tuple, &cfg_mem->parse)) - goto next_entry; - - /* default values */ - p_dev->conf.ConfigIndex = cfg->index; - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - cfg_mem->dflt = *cfg; - - ret = conf_check(p_dev, cfg, &cfg_mem->dflt, vcc, priv_data); - if (!ret) - break; - -next_entry: - ret = pcmcia_get_next_tuple(p_dev, tuple); - } + ret = pccard_loop_tuple(p_dev->socket, p_dev->func, + CISTPL_CFTABLE_ENTRY, &cfg_mem->parse, + cfg_mem, pcmcia_do_loop_config); + kfree(cfg_mem); return ret; } EXPORT_SYMBOL(pcmcia_loop_config); + + +struct pcmcia_loop_mem { + struct pcmcia_device *p_dev; + void *priv_data; + int (*loop_tuple) (struct pcmcia_device *p_dev, + tuple_t *tuple, + void *priv_data); +}; + +/** + * pcmcia_do_loop_tuple() - internal helper for pcmcia_loop_config() + * + * pcmcia_do_loop_tuple() is the internal callback for the call from + * pcmcia_loop_tuple() to pccard_loop_tuple(). Data is transferred + * by a struct pcmcia_cfg_mem. + */ +static int pcmcia_do_loop_tuple(tuple_t *tuple, cisparse_t *parse, void *priv) +{ + struct pcmcia_loop_mem *loop = priv; + + return loop->loop_tuple(loop->p_dev, tuple, loop->priv_data); +}; + +/** + * pcmcia_loop_tuple() - loop over tuples in the CIS + * @p_dev: the struct pcmcia_device which we need to loop for. + * @code: which CIS code shall we look for? + * @priv_data: private data to be passed to the loop_tuple function. + * @loop_tuple: function to call for each CIS entry of type @function. IT + * gets passed the raw tuple and @priv_data. + * + * pcmcia_loop_tuple() loops over all CIS entries of type @function, and + * calls the @loop_tuple function for each entry. If the call to @loop_tuple + * returns 0, the loop exits. Returns 0 on success or errorcode otherwise. + */ +int pcmcia_loop_tuple(struct pcmcia_device *p_dev, cisdata_t code, + int (*loop_tuple) (struct pcmcia_device *p_dev, + tuple_t *tuple, + void *priv_data), + void *priv_data) +{ + struct pcmcia_loop_mem loop = { + .p_dev = p_dev, + .loop_tuple = loop_tuple, + .priv_data = priv_data}; + + return pccard_loop_tuple(p_dev->socket, p_dev->func, code, NULL, + &loop, pcmcia_do_loop_tuple); +}; +EXPORT_SYMBOL(pcmcia_loop_tuple); + + +struct pcmcia_loop_get { + size_t len; + cisdata_t **buf; +}; + +/** + * pcmcia_do_get_tuple() - internal helper for pcmcia_get_tuple() + * + * pcmcia_do_get_tuple() is the internal callback for the call from + * pcmcia_get_tuple() to pcmcia_loop_tuple(). As we're only interested in + * the first tuple, return 0 unconditionally. Create a memory buffer large + * enough to hold the content of the tuple, and fill it with the tuple data. + * The caller is responsible to free the buffer. + */ +static int pcmcia_do_get_tuple(struct pcmcia_device *p_dev, tuple_t *tuple, + void *priv) +{ + struct pcmcia_loop_get *get = priv; + + *get->buf = kzalloc(tuple->TupleDataLen, GFP_KERNEL); + if (*get->buf) { + get->len = tuple->TupleDataLen; + memcpy(*get->buf, tuple->TupleData, tuple->TupleDataLen); + } + return 0; +}; + +/** + * pcmcia_get_tuple() - get first tuple from CIS + * @p_dev: the struct pcmcia_device which we need to loop for. + * @code: which CIS code shall we look for? + * @buf: pointer to store the buffer to. + * + * pcmcia_get_tuple() gets the content of the first CIS entry of type @code. + * It returns the buffer length (or zero). The caller is responsible to free + * the buffer passed in @buf. + */ +size_t pcmcia_get_tuple(struct pcmcia_device *p_dev, cisdata_t code, + unsigned char **buf) +{ + struct pcmcia_loop_get get = { + .len = 0, + .buf = buf, + }; + + *get.buf = NULL; + pcmcia_loop_tuple(p_dev, code, pcmcia_do_get_tuple, &get); + + return get.len; +}; +EXPORT_SYMBOL(pcmcia_get_tuple); + + +/** + * pcmcia_do_get_mac() - internal helper for pcmcia_get_mac_from_cis() + * + * pcmcia_do_get_mac() is the internal callback for the call from + * pcmcia_get_mac_from_cis() to pcmcia_loop_tuple(). We check whether the + * tuple contains a proper LAN_NODE_ID of length 6, and copy the data + * to struct net_device->dev_addr[i]. + */ +static int pcmcia_do_get_mac(struct pcmcia_device *p_dev, tuple_t *tuple, + void *priv) +{ + struct net_device *dev = priv; + int i; + + if (tuple->TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID) + return -EINVAL; + if (tuple->TupleDataLen < ETH_ALEN + 2) { + dev_warn(&p_dev->dev, "Invalid CIS tuple length for " + "LAN_NODE_ID\n"); + return -EINVAL; + } + + if (tuple->TupleData[1] != ETH_ALEN) { + dev_warn(&p_dev->dev, "Invalid header for LAN_NODE_ID\n"); + return -EINVAL; + } + for (i = 0; i < 6; i++) + dev->dev_addr[i] = tuple->TupleData[i+2]; + return 0; +}; + +/** + * pcmcia_get_mac_from_cis() - read out MAC address from CISTPL_FUNCE + * @p_dev: the struct pcmcia_device for which we want the address. + * @dev: a properly prepared struct net_device to store the info to. + * + * pcmcia_get_mac_from_cis() reads out the hardware MAC address from + * CISTPL_FUNCE and stores it into struct net_device *dev->dev_addr which + * must be set up properly by the driver (see examples!). + */ +int pcmcia_get_mac_from_cis(struct pcmcia_device *p_dev, struct net_device *dev) +{ + return pcmcia_loop_tuple(p_dev, CISTPL_FUNCE, pcmcia_do_get_mac, dev); +}; +EXPORT_SYMBOL(pcmcia_get_mac_from_cis); + diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index e592e0e0d7e..de0e770ce6a 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "cs_internal.h" diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index a2be80b9a09..2eb6e24d1a6 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -34,6 +34,7 @@ struct pcmcia_socket; struct pcmcia_device; struct config_t; +struct net_device; /* dynamic device IDs for PCMCIA device drivers. See * Documentation/pcmcia/driver.txt for details. @@ -176,26 +177,39 @@ const char *pcmcia_error_ret(int ret); pcmcia_error_ret(ret)); \ } -/* CIS access. - * Use the pcmcia_* versions in PCMCIA drivers + +/* + * CIS access. + * + * Please use the following functions to access CIS tuples: + * - pcmcia_get_tuple() + * - pcmcia_loop_tuple() + * - pcmcia_get_mac_from_cis() + * + * To parse a tuple_t, pcmcia_parse_tuple() exists. Its interface + * might change in future. */ + +/* get the very first CIS entry of type @code. Note that buf is pointer + * to u8 *buf; and that you need to kfree(buf) afterwards. */ +size_t pcmcia_get_tuple(struct pcmcia_device *p_dev, cisdata_t code, + u8 **buf); + +/* loop over CIS entries */ +int pcmcia_loop_tuple(struct pcmcia_device *p_dev, cisdata_t code, + int (*loop_tuple) (struct pcmcia_device *p_dev, + tuple_t *tuple, + void *priv_data), + void *priv_data); + +/* get the MAC address from CISTPL_FUNCE */ +int pcmcia_get_mac_from_cis(struct pcmcia_device *p_dev, + struct net_device *dev); + + +/* parse a tuple_t */ int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse); -int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, - tuple_t *tuple); -#define pcmcia_get_first_tuple(p_dev, tuple) \ - pccard_get_first_tuple(p_dev->socket, p_dev->func, tuple) - -int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, - tuple_t *tuple); -#define pcmcia_get_next_tuple(p_dev, tuple) \ - pccard_get_next_tuple(p_dev->socket, p_dev->func, tuple) - -int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple); -#define pcmcia_get_tuple_data(p_dev, tuple) \ - pccard_get_tuple_data(p_dev->socket, tuple) - - /* loop CIS entries for valid configuration */ int pcmcia_loop_config(struct pcmcia_device *p_dev, int (*conf_check) (struct pcmcia_device *p_dev, @@ -215,6 +229,21 @@ int pcmcia_reset_card(struct pcmcia_socket *skt); int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, conf_reg_t *reg); +/* deprecated -- do not use in drivers. */ +int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, + tuple_t *tuple); +#define pcmcia_get_first_tuple(p_dev, tuple) \ + pccard_get_first_tuple(p_dev->socket, p_dev->func, tuple) + +int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, + tuple_t *tuple); +#define pcmcia_get_next_tuple(p_dev, tuple) \ + pccard_get_next_tuple(p_dev->socket, p_dev->func, tuple) + +int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple); +#define pcmcia_get_tuple_data(p_dev, tuple) \ + pccard_get_tuple_data(p_dev->socket, tuple) + /* device configuration */ int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req); int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req); From dddfbd824b96a25da0b2f1cf35c0be33ef2422fe Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sun, 18 Oct 2009 23:54:24 +0200 Subject: [PATCH 082/298] pcmcia: convert net pcmcia drivers to use new CIS helpers Use the new CIS helpers in net pcmcia drivers, which allows for a few code cleanups. This revision does not remove the phys_addr assignment in 3c589_cs.c -- a bug noted by Komuro CC: David S. Miller CC: netdev@vger.kernel.org Signed-off-by: Dominik Brodowski --- drivers/net/pcmcia/3c574_cs.c | 18 ++- drivers/net/pcmcia/3c589_cs.c | 21 ++- drivers/net/pcmcia/fmvj18x_cs.c | 50 +++---- drivers/net/pcmcia/nmclan_cs.c | 19 ++- drivers/net/pcmcia/smc91c92_cs.c | 240 +++++++++---------------------- drivers/net/pcmcia/xirc2ps_cs.c | 147 ++++++++----------- 6 files changed, 172 insertions(+), 323 deletions(-) diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index b58965a2b3a..6449290c62f 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -344,13 +344,13 @@ static int tc574_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct el3_private *lp = netdev_priv(dev); - tuple_t tuple; - __le16 buf[32]; int last_fn, last_ret, i, j; unsigned int ioaddr; __be16 *phys_addr; char *cardname; __u32 config; + u8 *buf; + size_t len; phys_addr = (__be16 *)dev->dev_addr; @@ -378,16 +378,14 @@ static int tc574_config(struct pcmcia_device *link) /* The 3c574 normally uses an EEPROM for configuration info, including the hardware address. The future products may include a modem chip and put the address in the CIS. */ - tuple.Attributes = 0; - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleDataMax = 64; - tuple.TupleOffset = 0; - tuple.DesiredTuple = 0x88; - if (pcmcia_get_first_tuple(link, &tuple) == 0) { - pcmcia_get_tuple_data(link, &tuple); + + len = pcmcia_get_tuple(link, 0x88, &buf); + if (buf && len >= 6) { for (i = 0; i < 3; i++) - phys_addr[i] = htons(le16_to_cpu(buf[i])); + phys_addr[i] = htons(le16_to_cpu(buf[i * 2])); + kfree(buf); } else { + kfree(buf); /* 0 < len < 6 */ EL3WINDOW(0); for (i = 0; i < 3; i++) phys_addr[i] = htons(read_eeprom(ioaddr, i + 10)); diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 569fb06793c..fc6123ea6fa 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -256,22 +256,16 @@ static int tc589_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct el3_private *lp = netdev_priv(dev); - tuple_t tuple; - __le16 buf[32]; __be16 *phys_addr; int last_fn, last_ret, i, j, multi = 0, fifo; unsigned int ioaddr; char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; + u8 *buf; + size_t len; DEBUG(0, "3c589_config(0x%p)\n", link); phys_addr = (__be16 *)dev->dev_addr; - tuple.Attributes = 0; - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - tuple.Attributes = TUPLE_RETURN_COMMON; - /* Is this a 3c562? */ if (link->manf_id != MANFID_3COM) printk(KERN_INFO "3c589_cs: hmmm, is this really a " @@ -301,12 +295,13 @@ static int tc589_config(struct pcmcia_device *link) /* The 3c589 has an extra EEPROM for configuration info, including the hardware address. The 3c562 puts the address in the CIS. */ - tuple.DesiredTuple = 0x88; - if (pcmcia_get_first_tuple(link, &tuple) == 0) { - pcmcia_get_tuple_data(link, &tuple); - for (i = 0; i < 3; i++) - phys_addr[i] = htons(le16_to_cpu(buf[i])); + len = pcmcia_get_tuple(link, 0x88, &buf); + if (buf && len >= 6) { + for (i = 0; i < 3; i++) + phys_addr[i] = htons(le16_to_cpu(buf[i*2])); + kfree(buf); } else { + kfree(buf); /* 0 < len < 6 */ for (i = 0; i < 3; i++) phys_addr[i] = htons(read_eeprom(ioaddr, i)); if (phys_addr[0] == htons(0x6060)) { diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index c7a2bbfaf82..5b73b11411c 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -350,32 +350,29 @@ static int fmvj18x_ioprobe(struct pcmcia_device *p_dev, return 0; /* strange, but that's what the code did already before... */ } - static int fmvj18x_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; local_info_t *lp = netdev_priv(dev); - tuple_t tuple; - u_short buf[32]; int i, last_fn = RequestIO, last_ret = 0, ret; unsigned int ioaddr; cardtype_t cardtype; char *card_name = "unknown"; - u_char *node_id; + u8 *buf; + size_t len; + u_char buggybuf[32]; DEBUG(0, "fmvj18x_config(0x%p)\n", link); - tuple.TupleData = (u_char *)buf; - tuple.TupleDataMax = 64; - tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_FUNCE; - tuple.TupleOffset = 0; - if (pcmcia_get_first_tuple(link, &tuple) == 0) { + len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf); + kfree(buf); + + if (len) { + /* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */ last_ret = pcmcia_loop_config(link, fmvj18x_ioprobe, NULL); if (last_ret != 0) goto cs_failed; - /* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */ switch (link->manf_id) { case MANFID_TDK: cardtype = TDK; @@ -482,21 +479,21 @@ static int fmvj18x_config(struct pcmcia_device *link) case CONTEC: case NEC: case KME: - tuple.DesiredTuple = CISTPL_FUNCE; - tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - tuple.TupleOffset = 0; - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); if (cardtype == MBH10304) { - /* MBH10304's CIS_FUNCE is corrupted */ - node_id = &(tuple.TupleData[5]); card_name = "FMV-J182"; - } else { - while (tuple.TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID ) { - CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + + len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf); + if (len < 11) { + kfree(buf); + goto failed; } - node_id = &(tuple.TupleData[2]); + /* Read MACID from CIS */ + for (i = 5; i < 11; i++) + dev->dev_addr[i] = buf[i]; + kfree(buf); + } else { + if (pcmcia_get_mac_from_cis(link, dev)) + goto failed; if( cardtype == TDK ) { card_name = "TDK LAK-CD021"; } else if( cardtype == LA501 ) { @@ -509,9 +506,6 @@ static int fmvj18x_config(struct pcmcia_device *link) card_name = "C-NET(PC)C"; } } - /* Read MACID from CIS */ - for (i = 0; i < 6; i++) - dev->dev_addr[i] = node_id[i]; break; case UNGERMANN: /* Read MACID from register */ @@ -521,12 +515,12 @@ static int fmvj18x_config(struct pcmcia_device *link) break; case XXX10304: /* Read MACID from Buggy CIS */ - if (fmvj18x_get_hwinfo(link, tuple.TupleData) == -1) { + if (fmvj18x_get_hwinfo(link, buggybuf) == -1) { printk(KERN_NOTICE "fmvj18x_cs: unable to read hardware net address.\n"); goto failed; } for (i = 0 ; i < 6; i++) { - dev->dev_addr[i] = tuple.TupleData[i]; + dev->dev_addr[i] = buggybuf[i]; } card_name = "FMV-J182"; break; diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 5ed6339c52b..4b96b356d97 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -661,8 +661,8 @@ static int nmclan_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; mace_private *lp = netdev_priv(dev); - tuple_t tuple; - u_char buf[64]; + u8 *buf; + size_t len; int i, last_ret, last_fn; unsigned int ioaddr; @@ -677,14 +677,13 @@ static int nmclan_config(struct pcmcia_device *link) ioaddr = dev->base_addr; /* Read the ethernet address from the CIS. */ - tuple.DesiredTuple = 0x80 /* CISTPL_CFTABLE_ENTRY_MISC */; - tuple.TupleData = buf; - tuple.TupleDataMax = 64; - tuple.TupleOffset = 0; - tuple.Attributes = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - memcpy(dev->dev_addr, tuple.TupleData, ETHER_ADDR_LEN); + len = pcmcia_get_tuple(link, 0x80, &buf); + if (!buf || len < ETHER_ADDR_LEN) { + kfree(buf); + goto failed; + } + memcpy(dev->dev_addr, buf, ETHER_ADDR_LEN); + kfree(buf); /* Verify configuration by reading the MACE ID. */ { diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index af03759d186..df92bcde9bc 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -126,12 +126,6 @@ struct smc_private { int rx_ovrn; }; -struct smc_cfg_mem { - tuple_t tuple; - cisparse_t parse; - u_char buf[255]; -}; - /* Special definitions for Megahertz multifunction cards */ #define MEGAHERTZ_ISR 0x0380 @@ -408,34 +402,7 @@ static int cvt_ascii_address(struct net_device *dev, char *s) return 0; } -/*====================================================================*/ - -static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, - cisparse_t *parse) -{ - int i; - - i = pcmcia_get_first_tuple(handle, tuple); - if (i != 0) - return i; - i = pcmcia_get_tuple_data(handle, tuple); - if (i != 0) - return i; - return pcmcia_parse_tuple(tuple, parse); -} - -static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, - cisparse_t *parse) -{ - int i; - - if ((i = pcmcia_get_next_tuple(handle, tuple)) != 0 || - (i = pcmcia_get_tuple_data(handle, tuple)) != 0) - return i; - return pcmcia_parse_tuple(tuple, parse); -} - -/*====================================================================== +/*==================================================================== Configuration stuff for Megahertz cards @@ -490,15 +457,10 @@ static int mhz_mfc_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct smc_private *smc = netdev_priv(dev); - struct smc_cfg_mem *cfg_mem; win_req_t req; memreq_t mem; int i; - cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL); - if (!cfg_mem) - return -ENOMEM; - link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; link->irq.Attributes = @@ -510,7 +472,8 @@ static int mhz_mfc_config(struct pcmcia_device *link) /* The Megahertz combo cards have modem-like CIS entries, so we have to explicitly try a bunch of port combinations. */ if (pcmcia_loop_config(link, mhz_mfc_config_check, NULL)) - goto free_cfg_mem; + return -ENODEV; + dev->base_addr = link->io.BasePort1; /* Allocate a memory window, for accessing the ISR */ @@ -519,7 +482,8 @@ static int mhz_mfc_config(struct pcmcia_device *link) req.AccessSpeed = 0; i = pcmcia_request_window(&link, &req, &link->win); if (i != 0) - goto free_cfg_mem; + return -ENODEV; + smc->base = ioremap(req.Base, req.Size); mem.CardOffset = mem.Page = 0; if (smc->manfid == MANFID_MOTOROLA) @@ -531,18 +495,32 @@ static int mhz_mfc_config(struct pcmcia_device *link) && (smc->cardid == PRODID_MEGAHERTZ_EM3288)) mhz_3288_power(link); -free_cfg_mem: - kfree(cfg_mem); - return -ENODEV; + return 0; } +static int pcmcia_get_versmac(struct pcmcia_device *p_dev, + tuple_t *tuple, + void *priv) +{ + struct net_device *dev = priv; + cisparse_t parse; + + if (pcmcia_parse_tuple(tuple, &parse)) + return -EINVAL; + + if ((parse.version_1.ns > 3) && + (cvt_ascii_address(dev, + (parse.version_1.str + parse.version_1.ofs[3])))) + return 0; + + return -EINVAL; +}; + static int mhz_setup(struct pcmcia_device *link) { struct net_device *dev = link->priv; - struct smc_cfg_mem *cfg_mem; - tuple_t *tuple; - cisparse_t *parse; - u_char *buf, *station_addr; + size_t len; + u8 *buf; int rc; /* Read the station address from the CIS. It is stored as the last @@ -552,56 +530,22 @@ static int mhz_setup(struct pcmcia_device *link) return 0; /* Workarounds for broken cards start here. */ - - cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL); - if (!cfg_mem) - return -1; - - tuple = &cfg_mem->tuple; - parse = &cfg_mem->parse; - buf = cfg_mem->buf; - - tuple->Attributes = tuple->TupleOffset = 0; - tuple->TupleData = (cisdata_t *)buf; - tuple->TupleDataMax = 255; - /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */ - tuple->DesiredTuple = CISTPL_VERS_1; - if (first_tuple(link, tuple, parse) != 0) { - rc = -1; - goto free_cfg_mem; - } - /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */ - if (next_tuple(link, tuple, parse) != 0) - first_tuple(link, tuple, parse); - if (parse->version_1.ns > 3) { - station_addr = parse->version_1.str + parse->version_1.ofs[3]; - if (cvt_ascii_address(dev, station_addr) == 0) { - rc = 0; - goto free_cfg_mem; - } - } + if (!pcmcia_loop_tuple(link, CISTPL_VERS_1, pcmcia_get_versmac, dev)) + return 0; /* Another possibility: for the EM3288, in a special tuple */ - tuple->DesiredTuple = 0x81; - if (pcmcia_get_first_tuple(link, tuple) != 0) { - rc = -1; - goto free_cfg_mem; - } - if (pcmcia_get_tuple_data(link, tuple) != 0) { - rc = -1; - goto free_cfg_mem; - } - buf[12] = '\0'; - if (cvt_ascii_address(dev, buf) == 0) { - rc = 0; - goto free_cfg_mem; - } rc = -1; -free_cfg_mem: - kfree(cfg_mem); - return rc; -} + len = pcmcia_get_tuple(link, 0x81, &buf); + if (buf && len >= 13) { + buf[12] = '\0'; + if (cvt_ascii_address(dev, buf)) + rc = 0; + } + kfree(buf); + + return rc; +}; /*====================================================================== @@ -691,58 +635,21 @@ static int smc_config(struct pcmcia_device *link) return i; } + static int smc_setup(struct pcmcia_device *link) { struct net_device *dev = link->priv; - struct smc_cfg_mem *cfg_mem; - tuple_t *tuple; - cisparse_t *parse; - cistpl_lan_node_id_t *node_id; - u_char *buf, *station_addr; - int i, rc; - - cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL); - if (!cfg_mem) - return -ENOMEM; - - tuple = &cfg_mem->tuple; - parse = &cfg_mem->parse; - buf = cfg_mem->buf; - - tuple->Attributes = tuple->TupleOffset = 0; - tuple->TupleData = (cisdata_t *)buf; - tuple->TupleDataMax = 255; /* Check for a LAN function extension tuple */ - tuple->DesiredTuple = CISTPL_FUNCE; - i = first_tuple(link, tuple, parse); - while (i == 0) { - if (parse->funce.type == CISTPL_FUNCE_LAN_NODE_ID) - break; - i = next_tuple(link, tuple, parse); - } - if (i == 0) { - node_id = (cistpl_lan_node_id_t *)parse->funce.data; - if (node_id->nb == 6) { - for (i = 0; i < 6; i++) - dev->dev_addr[i] = node_id->id[i]; - rc = 0; - goto free_cfg_mem; - } - } + if (!pcmcia_get_mac_from_cis(link, dev)) + return 0; + /* Try the third string in the Version 1 Version/ID tuple. */ if (link->prod_id[2]) { - station_addr = link->prod_id[2]; - if (cvt_ascii_address(dev, station_addr) == 0) { - rc = 0; - goto free_cfg_mem; - } + if (cvt_ascii_address(dev, link->prod_id[2]) == 0) + return 0; } - - rc = -1; -free_cfg_mem: - kfree(cfg_mem); - return rc; + return -1; } /*====================================================================*/ @@ -801,41 +708,31 @@ static int osi_load_firmware(struct pcmcia_device *link) return err; } +static int pcmcia_osi_mac(struct pcmcia_device *p_dev, + tuple_t *tuple, + void *priv) +{ + struct net_device *dev = priv; + int i; + + if (tuple->TupleDataLen < 8) + return -EINVAL; + if (tuple->TupleData[0] != 0x04) + return -EINVAL; + for (i = 0; i < 6; i++) + dev->dev_addr[i] = tuple->TupleData[i+2]; + return 0; +}; + + static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid) { struct net_device *dev = link->priv; - struct smc_cfg_mem *cfg_mem; - tuple_t *tuple; - u_char *buf; - int i, rc; - - cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL); - if (!cfg_mem) - return -1; - - tuple = &cfg_mem->tuple; - buf = cfg_mem->buf; - - tuple->Attributes = TUPLE_RETURN_COMMON; - tuple->TupleData = (cisdata_t *)buf; - tuple->TupleDataMax = 255; - tuple->TupleOffset = 0; + int rc; /* Read the station address from tuple 0x90, subtuple 0x04 */ - tuple->DesiredTuple = 0x90; - i = pcmcia_get_first_tuple(link, tuple); - while (i == 0) { - i = pcmcia_get_tuple_data(link, tuple); - if ((i != 0) || (buf[0] == 0x04)) - break; - i = pcmcia_get_next_tuple(link, tuple); - } - if (i != 0) { - rc = -1; - goto free_cfg_mem; - } - for (i = 0; i < 6; i++) - dev->dev_addr[i] = buf[i+2]; + if (pcmcia_loop_tuple(link, 0x90, pcmcia_osi_mac, dev)) + return -1; if (((manfid == MANFID_OSITECH) && (cardid == PRODID_OSITECH_SEVEN)) || @@ -843,7 +740,7 @@ static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid) (cardid == PRODID_PSION_NET100))) { rc = osi_load_firmware(link); if (rc) - goto free_cfg_mem; + return rc; } else if (manfid == MANFID_OSITECH) { /* Make sure both functions are powered up */ set_bits(0x300, link->io.BasePort1 + OSITECH_AUI_PWR); @@ -853,10 +750,7 @@ static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid) inw(link->io.BasePort1 + OSITECH_AUI_PWR), inw(link->io.BasePort1 + OSITECH_RESET_ISR)); } - rc = 0; -free_cfg_mem: - kfree(cfg_mem); - return rc; + return 0; } static int smc91c92_suspend(struct pcmcia_device *link) diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 5e203230144..925e8509662 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -359,7 +359,7 @@ static void xirc_tx_timeout(struct net_device *dev); static void xirc2ps_tx_timeout_task(struct work_struct *work); static void set_addresses(struct net_device *dev); static void set_multicast_list(struct net_device *dev); -static int set_card_type(struct pcmcia_device *link, const void *s); +static int set_card_type(struct pcmcia_device *link); static int do_config(struct net_device *dev, struct ifmap *map); static int do_open(struct net_device *dev); static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); @@ -371,28 +371,6 @@ static void do_powerdown(struct net_device *dev); static int do_stop(struct net_device *dev); /*=============== Helper functions =========================*/ -static int -first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) -{ - int err; - - if ((err = pcmcia_get_first_tuple(handle, tuple)) == 0 && - (err = pcmcia_get_tuple_data(handle, tuple)) == 0) - err = pcmcia_parse_tuple(tuple, parse); - return err; -} - -static int -next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) -{ - int err; - - if ((err = pcmcia_get_next_tuple(handle, tuple)) == 0 && - (err = pcmcia_get_tuple_data(handle, tuple)) == 0) - err = pcmcia_parse_tuple(tuple, parse); - return err; -} - #define SelectPage(pgnr) outb((pgnr), ioaddr + XIRCREG_PR) #define GetByte(reg) ((unsigned)inb(ioaddr + (reg))) #define GetWord(reg) ((unsigned)inw(ioaddr + (reg))) @@ -644,15 +622,23 @@ xirc2ps_detach(struct pcmcia_device *link) * */ static int -set_card_type(struct pcmcia_device *link, const void *s) +set_card_type(struct pcmcia_device *link) { struct net_device *dev = link->priv; local_info_t *local = netdev_priv(dev); - #ifdef PCMCIA_DEBUG - unsigned cisrev = ((const unsigned char *)s)[2]; - #endif - unsigned mediaid= ((const unsigned char *)s)[3]; - unsigned prodid = ((const unsigned char *)s)[4]; + u8 *buf; + unsigned int cisrev, mediaid, prodid; + size_t len; + + len = pcmcia_get_tuple(link, CISTPL_MANFID, &buf); + if (len < 5) { + dev_err(&link->dev, "invalid CIS -- sorry\n"); + return 0; + } + + cisrev = buf[2]; + mediaid = buf[3]; + prodid = buf[4]; DEBUG(0, "cisrev=%02x mediaid=%02x prodid=%02x\n", cisrev, mediaid, prodid); @@ -761,6 +747,26 @@ xirc2ps_config_check(struct pcmcia_device *p_dev, } + +static int pcmcia_get_mac_ce(struct pcmcia_device *p_dev, + tuple_t *tuple, + void *priv) +{ + struct net_device *dev = priv; + int i; + + if (tuple->TupleDataLen != 13) + return -EINVAL; + if ((tuple->TupleData[0] != 2) || (tuple->TupleData[1] != 1) || + (tuple->TupleData[2] != 6)) + return -EINVAL; + /* another try (James Lehmer's CE2 version 4.1)*/ + for (i = 2; i < 6; i++) + dev->dev_addr[i] = tuple->TupleData[i+2]; + return 0; +}; + + /**************** * xirc2ps_config() is scheduled to run after a CARD_INSERTION event * is received, to configure the PCMCIA socket, and to make the @@ -772,25 +778,14 @@ xirc2ps_config(struct pcmcia_device * link) struct net_device *dev = link->priv; local_info_t *local = netdev_priv(dev); unsigned int ioaddr; - tuple_t tuple; - cisparse_t parse; - int err, i; - u_char buf[64]; - cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data; + int err; + u8 *buf; + size_t len; local->dingo_ccr = NULL; DEBUG(0, "config(0x%p)\n", link); - /* - * This reads the card's CONFIG tuple to find its configuration - * registers. - */ - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = 64; - tuple.TupleOffset = 0; - /* Is this a valid card */ if (link->has_manf_id == 0) { printk(KNOT_XIRC "manfid not found in CIS\n"); @@ -816,67 +811,41 @@ xirc2ps_config(struct pcmcia_device * link) break; default: printk(KNOT_XIRC "Unknown Card Manufacturer ID: 0x%04x\n", - (unsigned)parse.manfid.manf); + (unsigned)link->manf_id); goto failure; } DEBUG(0, "found %s card\n", local->manf_str); - /* needed for the additional fields to be parsed by set_card_type() */ - tuple.DesiredTuple = CISTPL_MANFID; - err = first_tuple(link, &tuple, &parse) - if (err) { - printk(KNOT_XIRC "manfid not found in CIS\n"); - goto failure; - } - if (!set_card_type(link, buf)) { + if (!set_card_type(link)) { printk(KNOT_XIRC "this card is not supported\n"); goto failure; } /* get the ethernet address from the CIS */ - tuple.DesiredTuple = CISTPL_FUNCE; - for (err = first_tuple(link, &tuple, &parse); !err; - err = next_tuple(link, &tuple, &parse)) { - /* Once I saw two CISTPL_FUNCE_LAN_NODE_ID entries: - * the first one with a length of zero the second correct - - * so I skip all entries with length 0 */ - if (parse.funce.type == CISTPL_FUNCE_LAN_NODE_ID - && ((cistpl_lan_node_id_t *)parse.funce.data)->nb) - break; - } - if (err) { /* not found: try to get the node-id from tuple 0x89 */ - tuple.DesiredTuple = 0x89; /* data layout looks like tuple 0x22 */ - if ((err = pcmcia_get_first_tuple(link, &tuple)) == 0 && - (err = pcmcia_get_tuple_data(link, &tuple)) == 0) { - if (tuple.TupleDataLen == 8 && *buf == CISTPL_FUNCE_LAN_NODE_ID) - memcpy(&parse, buf, 8); - else - err = -1; - } - } - if (err) { /* another try (James Lehmer's CE2 version 4.1)*/ - tuple.DesiredTuple = CISTPL_FUNCE; - for (err = first_tuple(link, &tuple, &parse); !err; - err = next_tuple(link, &tuple, &parse)) { - if (parse.funce.type == 0x02 && parse.funce.data[0] == 1 - && parse.funce.data[1] == 6 && tuple.TupleDataLen == 13) { - buf[1] = 4; - memcpy(&parse, buf+1, 8); - break; + err = pcmcia_get_mac_from_cis(link, dev); + + /* not found: try to get the node-id from tuple 0x89 */ + if (err) { + len = pcmcia_get_tuple(link, 0x89, &buf); + /* data layout looks like tuple 0x22 */ + if (buf && len == 8) { + if (*buf == CISTPL_FUNCE_LAN_NODE_ID) { + int i; + for (i = 2; i < 6; i++) + dev->dev_addr[i] = buf[i+2]; + } else + err = -1; } - } + kfree(buf); } + + if (err) + err = pcmcia_loop_tuple(link, CISTPL_FUNCE, pcmcia_get_mac_ce, dev); + if (err) { printk(KNOT_XIRC "node-id not found in CIS\n"); goto failure; } - node_id = (cistpl_lan_node_id_t *)parse.funce.data; - if (node_id->nb != 6) { - printk(KNOT_XIRC "malformed node-id in CIS\n"); - goto failure; - } - for (i=0; i < 6; i++) - dev->dev_addr[i] = node_id->id[i]; link->io.IOAddrLines =10; link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; From 37ace3d4131ae80f370eb1230fa7db2b3eedf17c Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sun, 18 Oct 2009 23:56:41 +0200 Subject: [PATCH 083/298] pcmcia: convert ssb pcmcia driver to use new CIS helpers SSB is a prime example of how to make use of the new CIS helpers. CC: Michael Buesch Acked-by: John W. Linville Signed-off-by: Dominik Brodowski --- drivers/ssb/pcmcia.c | 232 ++++++++++++++++++++++--------------------- 1 file changed, 118 insertions(+), 114 deletions(-) diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c index 100e7a5c5ea..e72f4046a5e 100644 --- a/drivers/ssb/pcmcia.c +++ b/drivers/ssb/pcmcia.c @@ -617,136 +617,140 @@ static int ssb_pcmcia_sprom_check_crc(const u16 *sprom, size_t size) } \ } while (0) -int ssb_pcmcia_get_invariants(struct ssb_bus *bus, - struct ssb_init_invariants *iv) +static int ssb_pcmcia_get_mac(struct pcmcia_device *p_dev, + tuple_t *tuple, + void *priv) { - tuple_t tuple; - int res; - unsigned char buf[32]; + struct ssb_sprom *sprom = priv; + + if (tuple->TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID) + return -EINVAL; + if (tuple->TupleDataLen != ETH_ALEN + 2) + return -EINVAL; + if (tuple->TupleData[1] != ETH_ALEN) + return -EINVAL; + memcpy(sprom->il0mac, &tuple->TupleData[2], ETH_ALEN); + return 0; +}; + +static int ssb_pcmcia_do_get_invariants(struct pcmcia_device *p_dev, + tuple_t *tuple, + void *priv) +{ + struct ssb_init_invariants *iv = priv; struct ssb_sprom *sprom = &iv->sprom; struct ssb_boardinfo *bi = &iv->boardinfo; const char *error_description; + GOTO_ERROR_ON(tuple->TupleDataLen < 1, "VEN tpl < 1"); + switch (tuple->TupleData[0]) { + case SSB_PCMCIA_CIS_ID: + GOTO_ERROR_ON((tuple->TupleDataLen != 5) && + (tuple->TupleDataLen != 7), + "id tpl size"); + bi->vendor = tuple->TupleData[1] | + ((u16)tuple->TupleData[2] << 8); + break; + case SSB_PCMCIA_CIS_BOARDREV: + GOTO_ERROR_ON(tuple->TupleDataLen != 2, + "boardrev tpl size"); + sprom->board_rev = tuple->TupleData[1]; + break; + case SSB_PCMCIA_CIS_PA: + GOTO_ERROR_ON((tuple->TupleDataLen != 9) && + (tuple->TupleDataLen != 10), + "pa tpl size"); + sprom->pa0b0 = tuple->TupleData[1] | + ((u16)tuple->TupleData[2] << 8); + sprom->pa0b1 = tuple->TupleData[3] | + ((u16)tuple->TupleData[4] << 8); + sprom->pa0b2 = tuple->TupleData[5] | + ((u16)tuple->TupleData[6] << 8); + sprom->itssi_a = tuple->TupleData[7]; + sprom->itssi_bg = tuple->TupleData[7]; + sprom->maxpwr_a = tuple->TupleData[8]; + sprom->maxpwr_bg = tuple->TupleData[8]; + break; + case SSB_PCMCIA_CIS_OEMNAME: + /* We ignore this. */ + break; + case SSB_PCMCIA_CIS_CCODE: + GOTO_ERROR_ON(tuple->TupleDataLen != 2, + "ccode tpl size"); + sprom->country_code = tuple->TupleData[1]; + break; + case SSB_PCMCIA_CIS_ANTENNA: + GOTO_ERROR_ON(tuple->TupleDataLen != 2, + "ant tpl size"); + sprom->ant_available_a = tuple->TupleData[1]; + sprom->ant_available_bg = tuple->TupleData[1]; + break; + case SSB_PCMCIA_CIS_ANTGAIN: + GOTO_ERROR_ON(tuple->TupleDataLen != 2, + "antg tpl size"); + sprom->antenna_gain.ghz24.a0 = tuple->TupleData[1]; + sprom->antenna_gain.ghz24.a1 = tuple->TupleData[1]; + sprom->antenna_gain.ghz24.a2 = tuple->TupleData[1]; + sprom->antenna_gain.ghz24.a3 = tuple->TupleData[1]; + sprom->antenna_gain.ghz5.a0 = tuple->TupleData[1]; + sprom->antenna_gain.ghz5.a1 = tuple->TupleData[1]; + sprom->antenna_gain.ghz5.a2 = tuple->TupleData[1]; + sprom->antenna_gain.ghz5.a3 = tuple->TupleData[1]; + break; + case SSB_PCMCIA_CIS_BFLAGS: + GOTO_ERROR_ON((tuple->TupleDataLen != 3) && + (tuple->TupleDataLen != 5), + "bfl tpl size"); + sprom->boardflags_lo = tuple->TupleData[1] | + ((u16)tuple->TupleData[2] << 8); + break; + case SSB_PCMCIA_CIS_LEDS: + GOTO_ERROR_ON(tuple->TupleDataLen != 5, + "leds tpl size"); + sprom->gpio0 = tuple->TupleData[1]; + sprom->gpio1 = tuple->TupleData[2]; + sprom->gpio2 = tuple->TupleData[3]; + sprom->gpio3 = tuple->TupleData[4]; + break; + } + return -ENOSPC; /* continue with next entry */ + +error: + ssb_printk(KERN_ERR PFX + "PCMCIA: Failed to fetch device invariants: %s\n", + error_description); + return -ENODEV; +} + + +int ssb_pcmcia_get_invariants(struct ssb_bus *bus, + struct ssb_init_invariants *iv) +{ + struct ssb_sprom *sprom = &iv->sprom; + int res; + memset(sprom, 0xFF, sizeof(*sprom)); sprom->revision = 1; sprom->boardflags_lo = 0; sprom->boardflags_hi = 0; /* First fetch the MAC address. */ - memset(&tuple, 0, sizeof(tuple)); - tuple.DesiredTuple = CISTPL_FUNCE; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - res = pcmcia_get_first_tuple(bus->host_pcmcia, &tuple); - GOTO_ERROR_ON(res != 0, "MAC first tpl"); - res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple); - GOTO_ERROR_ON(res != 0, "MAC first tpl data"); - while (1) { - GOTO_ERROR_ON(tuple.TupleDataLen < 1, "MAC tpl < 1"); - if (tuple.TupleData[0] == CISTPL_FUNCE_LAN_NODE_ID) - break; - res = pcmcia_get_next_tuple(bus->host_pcmcia, &tuple); - GOTO_ERROR_ON(res != 0, "MAC next tpl"); - res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple); - GOTO_ERROR_ON(res != 0, "MAC next tpl data"); + res = pcmcia_loop_tuple(bus->host_pcmcia, CISTPL_FUNCE, + ssb_pcmcia_get_mac, sprom); + if (res != 0) { + ssb_printk(KERN_ERR PFX + "PCMCIA: Failed to fetch MAC address\n"); + return -ENODEV; } - GOTO_ERROR_ON(tuple.TupleDataLen != ETH_ALEN + 2, "MAC tpl size"); - memcpy(sprom->il0mac, &tuple.TupleData[2], ETH_ALEN); /* Fetch the vendor specific tuples. */ - memset(&tuple, 0, sizeof(tuple)); - tuple.DesiredTuple = SSB_PCMCIA_CIS; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - res = pcmcia_get_first_tuple(bus->host_pcmcia, &tuple); - GOTO_ERROR_ON(res != 0, "VEN first tpl"); - res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple); - GOTO_ERROR_ON(res != 0, "VEN first tpl data"); - while (1) { - GOTO_ERROR_ON(tuple.TupleDataLen < 1, "VEN tpl < 1"); - switch (tuple.TupleData[0]) { - case SSB_PCMCIA_CIS_ID: - GOTO_ERROR_ON((tuple.TupleDataLen != 5) && - (tuple.TupleDataLen != 7), - "id tpl size"); - bi->vendor = tuple.TupleData[1] | - ((u16)tuple.TupleData[2] << 8); - break; - case SSB_PCMCIA_CIS_BOARDREV: - GOTO_ERROR_ON(tuple.TupleDataLen != 2, - "boardrev tpl size"); - sprom->board_rev = tuple.TupleData[1]; - break; - case SSB_PCMCIA_CIS_PA: - GOTO_ERROR_ON((tuple.TupleDataLen != 9) && - (tuple.TupleDataLen != 10), - "pa tpl size"); - sprom->pa0b0 = tuple.TupleData[1] | - ((u16)tuple.TupleData[2] << 8); - sprom->pa0b1 = tuple.TupleData[3] | - ((u16)tuple.TupleData[4] << 8); - sprom->pa0b2 = tuple.TupleData[5] | - ((u16)tuple.TupleData[6] << 8); - sprom->itssi_a = tuple.TupleData[7]; - sprom->itssi_bg = tuple.TupleData[7]; - sprom->maxpwr_a = tuple.TupleData[8]; - sprom->maxpwr_bg = tuple.TupleData[8]; - break; - case SSB_PCMCIA_CIS_OEMNAME: - /* We ignore this. */ - break; - case SSB_PCMCIA_CIS_CCODE: - GOTO_ERROR_ON(tuple.TupleDataLen != 2, - "ccode tpl size"); - sprom->country_code = tuple.TupleData[1]; - break; - case SSB_PCMCIA_CIS_ANTENNA: - GOTO_ERROR_ON(tuple.TupleDataLen != 2, - "ant tpl size"); - sprom->ant_available_a = tuple.TupleData[1]; - sprom->ant_available_bg = tuple.TupleData[1]; - break; - case SSB_PCMCIA_CIS_ANTGAIN: - GOTO_ERROR_ON(tuple.TupleDataLen != 2, - "antg tpl size"); - sprom->antenna_gain.ghz24.a0 = tuple.TupleData[1]; - sprom->antenna_gain.ghz24.a1 = tuple.TupleData[1]; - sprom->antenna_gain.ghz24.a2 = tuple.TupleData[1]; - sprom->antenna_gain.ghz24.a3 = tuple.TupleData[1]; - sprom->antenna_gain.ghz5.a0 = tuple.TupleData[1]; - sprom->antenna_gain.ghz5.a1 = tuple.TupleData[1]; - sprom->antenna_gain.ghz5.a2 = tuple.TupleData[1]; - sprom->antenna_gain.ghz5.a3 = tuple.TupleData[1]; - break; - case SSB_PCMCIA_CIS_BFLAGS: - GOTO_ERROR_ON((tuple.TupleDataLen != 3) && - (tuple.TupleDataLen != 5), - "bfl tpl size"); - sprom->boardflags_lo = tuple.TupleData[1] | - ((u16)tuple.TupleData[2] << 8); - break; - case SSB_PCMCIA_CIS_LEDS: - GOTO_ERROR_ON(tuple.TupleDataLen != 5, - "leds tpl size"); - sprom->gpio0 = tuple.TupleData[1]; - sprom->gpio1 = tuple.TupleData[2]; - sprom->gpio2 = tuple.TupleData[3]; - sprom->gpio3 = tuple.TupleData[4]; - break; - } - res = pcmcia_get_next_tuple(bus->host_pcmcia, &tuple); - if (res == -ENOSPC) - break; - GOTO_ERROR_ON(res != 0, "VEN next tpl"); - res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple); - GOTO_ERROR_ON(res != 0, "VEN next tpl data"); - } + res = pcmcia_loop_tuple(bus->host_pcmcia, SSB_PCMCIA_CIS, + ssb_pcmcia_do_get_invariants, sprom); + if ((res == 0) || (res == -ENOSPC)) + return 0; - return 0; -error: ssb_printk(KERN_ERR PFX - "PCMCIA: Failed to fetch device invariants: %s\n", - error_description); + "PCMCIA: Failed to fetch device invariants\n"); return -ENODEV; } From 18b61b97294dad74dd00a1aa8efed0cfacb95aff Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sun, 18 Oct 2009 23:57:58 +0200 Subject: [PATCH 084/298] pcmcia: convert pcmciamtd driver to use new CIS helpers Convert the (broken) pcmciamtd driver to use the new CIS helpers. CC: David.Woodhouse@intel.com CC: linux-mtd@lists.infradead.org Signed-off-by: Dominik Brodowski --- drivers/mtd/maps/pcmciamtd.c | 189 ++++++++++++++++++----------------- 1 file changed, 99 insertions(+), 90 deletions(-) diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index d600c2deff7..5c3546ef29d 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -354,101 +354,110 @@ static void pcmciamtd_release(struct pcmcia_device *link) } +#ifdef CONFIG_MTD_DEBUG +static int pcmciamtd_cistpl_format(struct pcmcia_device *p_dev, + tuple_t *tuple, + void *priv_data) +{ + cisparse_t parse; + + if (!pcmcia_parse_tuple(tuple, &parse)) { + cistpl_format_t *t = &parse.format; + (void)t; /* Shut up, gcc */ + DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u", + t->type, t->edc, t->offset, t->length); + } + return -ENOSPC; +} + +static int pcmciamtd_cistpl_jedec(struct pcmcia_device *p_dev, + tuple_t *tuple, + void *priv_data) +{ + cisparse_t parse; + int i; + + if (!pcmcia_parse_tuple(tuple, &parse)) { + cistpl_jedec_t *t = &parse.jedec; + for (i = 0; i < t->nid; i++) + DEBUG(2, "JEDEC: 0x%02x 0x%02x", t->id[i].mfr, t->id[i].info); + } + return -ENOSPC; +} +#endif + +static int pcmciamtd_cistpl_device(struct pcmcia_device *p_dev, + tuple_t *tuple, + void *priv_data) +{ + struct pcmciamtd_dev *dev = priv_data; + cisparse_t parse; + cistpl_device_t *t = &parse.device; + int i; + + if (pcmcia_parse_tuple(tuple, &parse)) + return -EINVAL; + + DEBUG(2, "Common memory:"); + dev->pcmcia_map.size = t->dev[0].size; + /* from here on: DEBUG only */ + for (i = 0; i < t->ndev; i++) { + DEBUG(2, "Region %d, type = %u", i, t->dev[i].type); + DEBUG(2, "Region %d, wp = %u", i, t->dev[i].wp); + DEBUG(2, "Region %d, speed = %u ns", i, t->dev[i].speed); + DEBUG(2, "Region %d, size = %u bytes", i, t->dev[i].size); + } + return 0; +} + +static int pcmciamtd_cistpl_geo(struct pcmcia_device *p_dev, + tuple_t *tuple, + void *priv_data) +{ + struct pcmciamtd_dev *dev = priv_data; + cisparse_t parse; + cistpl_device_geo_t *t = &parse.device_geo; + int i; + + if (pcmcia_parse_tuple(tuple, &parse)) + return -EINVAL; + + dev->pcmcia_map.bankwidth = t->geo[0].buswidth; + /* from here on: DEBUG only */ + for (i = 0; i < t->ngeo; i++) { + DEBUG(2, "region: %d bankwidth = %u", i, t->geo[i].buswidth); + DEBUG(2, "region: %d erase_block = %u", i, t->geo[i].erase_block); + DEBUG(2, "region: %d read_block = %u", i, t->geo[i].read_block); + DEBUG(2, "region: %d write_block = %u", i, t->geo[i].write_block); + DEBUG(2, "region: %d partition = %u", i, t->geo[i].partition); + DEBUG(2, "region: %d interleave = %u", i, t->geo[i].interleave); + } + return 0; +} + + static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *link, int *new_name) { - int rc; - tuple_t tuple; - cisparse_t parse; - u_char buf[64]; + int i; - tuple.Attributes = 0; - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - tuple.DesiredTuple = RETURN_FIRST_TUPLE; - - rc = pcmcia_get_first_tuple(link, &tuple); - while (rc == 0) { - rc = pcmcia_get_tuple_data(link, &tuple); - if (rc != 0) { - cs_error(link, GetTupleData, rc); - break; + if (p_dev->prod_id[0]) { + dev->mtd_name[0] = '\0'; + for (i = 0; i < 4; i++) { + if (i) + strcat(dev->mtd_name, " "); + if (p_dev->prod_id[i]) + strcat(dev->mtd_name, p_dev->prod_id[i]); } - rc = pcmcia_parse_tuple(&tuple, &parse); - if (rc != 0) { - cs_error(link, ParseTuple, rc); - break; - } - - switch(tuple.TupleCode) { - case CISTPL_FORMAT: { - cistpl_format_t *t = &parse.format; - (void)t; /* Shut up, gcc */ - DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u", - t->type, t->edc, t->offset, t->length); - break; - - } - - case CISTPL_DEVICE: { - cistpl_device_t *t = &parse.device; - int i; - DEBUG(2, "Common memory:"); - dev->pcmcia_map.size = t->dev[0].size; - for(i = 0; i < t->ndev; i++) { - DEBUG(2, "Region %d, type = %u", i, t->dev[i].type); - DEBUG(2, "Region %d, wp = %u", i, t->dev[i].wp); - DEBUG(2, "Region %d, speed = %u ns", i, t->dev[i].speed); - DEBUG(2, "Region %d, size = %u bytes", i, t->dev[i].size); - } - break; - } - - case CISTPL_VERS_1: { - cistpl_vers_1_t *t = &parse.version_1; - int i; - if(t->ns) { - dev->mtd_name[0] = '\0'; - for(i = 0; i < t->ns; i++) { - if(i) - strcat(dev->mtd_name, " "); - strcat(dev->mtd_name, t->str+t->ofs[i]); - } - } - DEBUG(2, "Found name: %s", dev->mtd_name); - break; - } - - case CISTPL_JEDEC_C: { - cistpl_jedec_t *t = &parse.jedec; - int i; - for(i = 0; i < t->nid; i++) { - DEBUG(2, "JEDEC: 0x%02x 0x%02x", t->id[i].mfr, t->id[i].info); - } - break; - } - - case CISTPL_DEVICE_GEO: { - cistpl_device_geo_t *t = &parse.device_geo; - int i; - dev->pcmcia_map.bankwidth = t->geo[0].buswidth; - for(i = 0; i < t->ngeo; i++) { - DEBUG(2, "region: %d bankwidth = %u", i, t->geo[i].buswidth); - DEBUG(2, "region: %d erase_block = %u", i, t->geo[i].erase_block); - DEBUG(2, "region: %d read_block = %u", i, t->geo[i].read_block); - DEBUG(2, "region: %d write_block = %u", i, t->geo[i].write_block); - DEBUG(2, "region: %d partition = %u", i, t->geo[i].partition); - DEBUG(2, "region: %d interleave = %u", i, t->geo[i].interleave); - } - break; - } - - default: - DEBUG(2, "Unknown tuple code %d", tuple.TupleCode); - } - - rc = pcmcia_get_next_tuple(link, &tuple); + DEBUG(2, "Found name: %s", dev->mtd_name); } + +#ifdef CONFIG_MTD_DEBUG + pcmcia_loop_tuple(p_dev, CISTPL_FORMAT, pcmciamtd_cistpl_format, NULL); + pcmcia_loop_tuple(p_dev, CISTPL_JEDEC_C, pcmciamtd_cistpl_jedec, NULL); +#endif + pcmcia_loop_tuple(p_dev, CISTPL_DEVICE, pcmciamtd_cistpl_device, dev); + pcmcia_loop_tuple(p_dev, CISTPL_DEVICE_GEO, pcmciamtd_cistpl_geo, dev); + if(!dev->pcmcia_map.size) dev->pcmcia_map.size = MAX_PCMCIA_ADDR; From 18a7a19b37838789452e0bd2855a51475628b971 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Mon, 19 Oct 2009 00:07:39 +0200 Subject: [PATCH 085/298] pcmcia: remove pcmcia_get_{first,next}_tuple() Remove the pcmcia_get_{first,next}_tuple() calls no longer needed by (current) pcmcia device drivers. Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs_internal.h | 9 +++++++++ include/pcmcia/ds.h | 15 --------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 06a14c951e9..70432cae76e 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -206,6 +206,15 @@ int pccard_loop_tuple(struct pcmcia_socket *s, unsigned int function, cisparse_t *parse, void *priv_data)); +int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, + tuple_t *tuple); + +int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, + tuple_t *tuple); + +int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple); + + /* rsrc_mgr.c */ int pcmcia_validate_mem(struct pcmcia_socket *s); struct resource *pcmcia_find_io_region(unsigned long base, diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index 2eb6e24d1a6..6c37d4ed783 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -229,21 +229,6 @@ int pcmcia_reset_card(struct pcmcia_socket *skt); int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, conf_reg_t *reg); -/* deprecated -- do not use in drivers. */ -int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, - tuple_t *tuple); -#define pcmcia_get_first_tuple(p_dev, tuple) \ - pccard_get_first_tuple(p_dev->socket, p_dev->func, tuple) - -int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, - tuple_t *tuple); -#define pcmcia_get_next_tuple(p_dev, tuple) \ - pccard_get_next_tuple(p_dev->socket, p_dev->func, tuple) - -int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple); -#define pcmcia_get_tuple_data(p_dev, tuple) \ - pccard_get_tuple_data(p_dev->socket, tuple) - /* device configuration */ int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req); int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req); From d50dbec3ce52e1608636b8a624d087da9ced8cde Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Fri, 23 Oct 2009 12:51:28 +0200 Subject: [PATCH 086/298] pcmcia: use dynamic debug instead of custom infrastructure Use the generic "dynamic debug" infrastructure instead of CONIG_PCMCIA_DEBUG in the PCMCIA core (pcmcia.ko and pcmcia_core.ko). To enable debugging, enable CONFIG_DYNAMIC_DEBUG, mount debugfs and $ echo -n 'module pcmcia_core +p' > /sys/kernel/debug/dynamic_debug/control for the complete module "pcmcia_core", for example. For more detailled instructions, please see Documentation/dynamic-debug-howto.txt Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cardbus.c | 4 +- drivers/pcmcia/cistpl.c | 10 ++-- drivers/pcmcia/cs.c | 57 +++++++++------------ drivers/pcmcia/cs_internal.h | 22 -------- drivers/pcmcia/ds.c | 87 +++++++++++++------------------- drivers/pcmcia/pcmcia_ioctl.c | 31 ++++-------- drivers/pcmcia/pcmcia_resource.c | 63 +++++++++-------------- 7 files changed, 100 insertions(+), 174 deletions(-) diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c index db77e1f3309..4cd70d05681 100644 --- a/drivers/pcmcia/cardbus.c +++ b/drivers/pcmcia/cardbus.c @@ -91,7 +91,7 @@ static u_int xlate_rom_addr(void __iomem *b, u_int addr) static void cb_release_cis_mem(struct pcmcia_socket * s) { if (s->cb_cis_virt) { - cs_dbg(s, 1, "cb_release_cis_mem()\n"); + dev_dbg(&s->dev, "cb_release_cis_mem()\n"); iounmap(s->cb_cis_virt); s->cb_cis_virt = NULL; s->cb_cis_res = NULL; @@ -132,7 +132,7 @@ int read_cb_mem(struct pcmcia_socket * s, int space, u_int addr, u_int len, void struct pci_dev *dev; struct resource *res; - cs_dbg(s, 3, "read_cb_mem(%d, %#x, %u)\n", space, addr, len); + dev_dbg(&s->dev, "read_cb_mem(%d, %#x, %u)\n", space, addr, len); dev = pci_get_slot(s->cb_dev->subordinate, 0); if (!dev) diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 24dd3c1eac0..8c1b73cf021 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -138,7 +138,7 @@ int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, void __iomem *sys, *end; unsigned char *buf = ptr; - cs_dbg(s, 3, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len); + dev_dbg(&s->dev, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len); if (attr & IS_INDIRECT) { /* Indirect accesses use a bunch of special registers at fixed @@ -190,7 +190,7 @@ int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, addr = 0; } } - cs_dbg(s, 3, " %#2.2x %#2.2x %#2.2x %#2.2x ...\n", + dev_dbg(&s->dev, " %#2.2x %#2.2x %#2.2x %#2.2x ...\n", *(u_char *)(ptr+0), *(u_char *)(ptr+1), *(u_char *)(ptr+2), *(u_char *)(ptr+3)); return 0; @@ -204,7 +204,7 @@ void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, void __iomem *sys, *end; unsigned char *buf = ptr; - cs_dbg(s, 3, "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len); + dev_dbg(&s->dev, "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len); if (attr & IS_INDIRECT) { /* Indirect accesses use a bunch of special registers at fixed @@ -584,7 +584,7 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_ ofs += link[1] + 2; } if (i == MAX_TUPLES) { - cs_dbg(s, 1, "cs: overrun in pcmcia_get_next_tuple\n"); + dev_dbg(&s->dev, "cs: overrun in pcmcia_get_next_tuple\n"); return -ENOSPC; } @@ -1440,7 +1440,7 @@ int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse) break; } if (ret) - __cs_dbg(0, "parse_tuple failed %d\n", ret); + pr_debug("parse_tuple failed %d\n", ret); return ret; } EXPORT_SYMBOL(pcmcia_parse_tuple); diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 934d4bee39a..b0ec9c614ce 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -61,17 +61,6 @@ INT_MODULE_PARM(unreset_limit, 30); /* unreset_check's */ /* Access speed for attribute memory windows */ INT_MODULE_PARM(cis_speed, 300); /* ns */ -#ifdef CONFIG_PCMCIA_DEBUG -static int pc_debug; - -module_param(pc_debug, int, 0644); - -int cs_debug_level(int level) -{ - return pc_debug > level; -} -#endif - socket_state_t dead_socket = { .csc_mask = SS_DETECT, @@ -182,7 +171,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) if (!socket || !socket->ops || !socket->dev.parent || !socket->resource_ops) return -EINVAL; - cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops); + dev_dbg(&socket->dev, "pcmcia_register_socket(0x%p)\n", socket->ops); spin_lock_init(&socket->lock); @@ -274,7 +263,7 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket) if (!socket) return; - cs_dbg(socket, 0, "pcmcia_unregister_socket(0x%p)\n", socket->ops); + dev_dbg(&socket->dev, "pcmcia_unregister_socket(0x%p)\n", socket->ops); if (socket->thread) kthread_stop(socket->thread); @@ -327,7 +316,7 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority) if (s->state & SOCKET_CARDBUS) return 0; - cs_dbg(s, 1, "send_event(event %d, pri %d, callback 0x%p)\n", + dev_dbg(&s->dev, "send_event(event %d, pri %d, callback 0x%p)\n", event, priority, s->callback); if (!s->callback) @@ -344,7 +333,7 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority) static void socket_remove_drivers(struct pcmcia_socket *skt) { - cs_dbg(skt, 4, "remove_drivers\n"); + dev_dbg(&skt->dev, "remove_drivers\n"); send_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH); } @@ -353,7 +342,7 @@ static int socket_reset(struct pcmcia_socket *skt) { int status, i; - cs_dbg(skt, 4, "reset\n"); + dev_dbg(&skt->dev, "reset\n"); skt->socket.flags |= SS_OUTPUT_ENA | SS_RESET; skt->ops->set_socket(skt, &skt->socket); @@ -375,7 +364,7 @@ static int socket_reset(struct pcmcia_socket *skt) msleep(unreset_check * 10); } - cs_err(skt, "time out after reset.\n"); + dev_printk(KERN_ERR, &skt->dev, "time out after reset.\n"); return -ETIMEDOUT; } @@ -389,7 +378,7 @@ static void socket_shutdown(struct pcmcia_socket *s) { int status; - cs_dbg(s, 4, "shutdown\n"); + dev_dbg(&s->dev, "shutdown\n"); socket_remove_drivers(s); s->state &= SOCKET_INUSE | SOCKET_PRESENT; @@ -424,7 +413,7 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay) { int status, i; - cs_dbg(skt, 4, "setup\n"); + dev_dbg(&skt->dev, "setup\n"); skt->ops->get_status(skt, &status); if (!(status & SS_DETECT)) @@ -444,13 +433,15 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay) } if (status & SS_PENDING) { - cs_err(skt, "voltage interrogation timed out.\n"); + dev_printk(KERN_ERR, &skt->dev, + "voltage interrogation timed out.\n"); return -ETIMEDOUT; } if (status & SS_CARDBUS) { if (!(skt->features & SS_CAP_CARDBUS)) { - cs_err(skt, "cardbus cards are not supported.\n"); + dev_printk(KERN_ERR, &skt->dev, + "cardbus cards are not supported.\n"); return -EINVAL; } skt->state |= SOCKET_CARDBUS; @@ -464,7 +455,7 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay) else if (!(status & SS_XVCARD)) skt->socket.Vcc = skt->socket.Vpp = 50; else { - cs_err(skt, "unsupported voltage key.\n"); + dev_printk(KERN_ERR, &skt->dev, "unsupported voltage key.\n"); return -EIO; } @@ -481,7 +472,7 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay) skt->ops->get_status(skt, &status); if (!(status & SS_POWERON)) { - cs_err(skt, "unable to apply power.\n"); + dev_printk(KERN_ERR, &skt->dev, "unable to apply power.\n"); return -EIO; } @@ -501,7 +492,7 @@ static int socket_insert(struct pcmcia_socket *skt) { int ret; - cs_dbg(skt, 4, "insert\n"); + dev_dbg(&skt->dev, "insert\n"); if (!cs_socket_get(skt)) return -ENODEV; @@ -521,7 +512,7 @@ static int socket_insert(struct pcmcia_socket *skt) skt->state |= SOCKET_CARDBUS_CONFIG; } #endif - cs_dbg(skt, 4, "insert done\n"); + dev_dbg(&skt->dev, "insert done\n"); send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); } else { @@ -573,7 +564,7 @@ static int socket_resume(struct pcmcia_socket *skt) * FIXME: need a better check here for cardbus cards. */ if (verify_cis_cache(skt) != 0) { - cs_dbg(skt, 4, "cis mismatch - different card\n"); + dev_dbg(&skt->dev, "cis mismatch - different card\n"); socket_remove_drivers(skt); destroy_cis_cache(skt); /* @@ -584,7 +575,7 @@ static int socket_resume(struct pcmcia_socket *skt) msleep(200); send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); } else { - cs_dbg(skt, 4, "cis matches cache\n"); + dev_dbg(&skt->dev, "cis matches cache\n"); send_event(skt, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW); } } else { @@ -706,7 +697,7 @@ static int pccardd(void *__skt) void pcmcia_parse_events(struct pcmcia_socket *s, u_int events) { unsigned long flags; - cs_dbg(s, 4, "parse_events: events %08x\n", events); + dev_dbg(&s->dev, "parse_events: events %08x\n", events); if (s->thread) { spin_lock_irqsave(&s->thread_lock, flags); s->thread_events |= events; @@ -756,7 +747,7 @@ int pcmcia_reset_card(struct pcmcia_socket *skt) { int ret; - cs_dbg(skt, 1, "resetting socket\n"); + dev_dbg(&skt->dev, "resetting socket\n"); mutex_lock(&skt->skt_mutex); do { @@ -801,7 +792,7 @@ int pcmcia_suspend_card(struct pcmcia_socket *skt) { int ret; - cs_dbg(skt, 1, "suspending socket\n"); + dev_dbg(&skt->dev, "suspending socket\n"); mutex_lock(&skt->skt_mutex); do { @@ -831,7 +822,7 @@ int pcmcia_resume_card(struct pcmcia_socket *skt) { int ret; - cs_dbg(skt, 1, "waking up socket\n"); + dev_dbg(&skt->dev, "waking up socket\n"); mutex_lock(&skt->skt_mutex); do { @@ -859,7 +850,7 @@ int pcmcia_eject_card(struct pcmcia_socket *skt) { int ret; - cs_dbg(skt, 1, "user eject request\n"); + dev_dbg(&skt->dev, "user eject request\n"); mutex_lock(&skt->skt_mutex); do { @@ -888,7 +879,7 @@ int pcmcia_insert_card(struct pcmcia_socket *skt) { int ret; - cs_dbg(skt, 1, "user insert request\n"); + dev_dbg(&skt->dev, "user insert request\n"); mutex_lock(&skt->skt_mutex); do { diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 70432cae76e..0a3ada970bf 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -107,28 +107,6 @@ static inline void cs_socket_put(struct pcmcia_socket *skt) } } -#ifdef CONFIG_PCMCIA_DEBUG -extern int cs_debug_level(int); - -#define cs_dbg(skt, lvl, fmt, arg...) do { \ - if (cs_debug_level(lvl)) \ - dev_printk(KERN_DEBUG, &skt->dev, \ - "cs: " fmt, ## arg); \ -} while (0) -#define __cs_dbg(lvl, fmt, arg...) do { \ - if (cs_debug_level(lvl)) \ - printk(KERN_DEBUG \ - "cs: " fmt, ## arg); \ -} while (0) - -#else -#define cs_dbg(skt, lvl, fmt, arg...) do { } while (0) -#define __cs_dbg(lvl, fmt, arg...) do { } while (0) -#endif - -#define cs_err(skt, fmt, arg...) \ - dev_printk(KERN_ERR, &skt->dev, "cs: " fmt, ## arg) - /* * Stuff internal to module "pcmcia_core": diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index f5b7079f13d..5b069aeaf17 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -41,23 +41,6 @@ MODULE_AUTHOR("David Hinds "); MODULE_DESCRIPTION("PCMCIA Driver Services"); MODULE_LICENSE("GPL"); -#ifdef CONFIG_PCMCIA_DEBUG -int ds_pc_debug; - -module_param_named(pc_debug, ds_pc_debug, int, 0644); - -#define ds_dbg(lvl, fmt, arg...) do { \ - if (ds_pc_debug > (lvl)) \ - printk(KERN_DEBUG "ds: " fmt , ## arg); \ -} while (0) -#define ds_dev_dbg(lvl, dev, fmt, arg...) do { \ - if (ds_pc_debug > (lvl)) \ - dev_printk(KERN_DEBUG, dev, "ds: " fmt , ## arg); \ -} while (0) -#else -#define ds_dbg(lvl, fmt, arg...) do { } while (0) -#define ds_dev_dbg(lvl, dev, fmt, arg...) do { } while (0) -#endif spinlock_t pcmcia_dev_list_lock; @@ -303,7 +286,7 @@ int pcmcia_register_driver(struct pcmcia_driver *driver) spin_lock_init(&driver->dynids.lock); INIT_LIST_HEAD(&driver->dynids.list); - ds_dbg(3, "registering driver %s\n", driver->drv.name); + pr_debug("registering driver %s\n", driver->drv.name); error = driver_register(&driver->drv); if (error < 0) @@ -323,7 +306,7 @@ EXPORT_SYMBOL(pcmcia_register_driver); */ void pcmcia_unregister_driver(struct pcmcia_driver *driver) { - ds_dbg(3, "unregistering driver %s\n", driver->drv.name); + pr_debug("unregistering driver %s\n", driver->drv.name); driver_unregister(&driver->drv); pcmcia_free_dynids(driver); } @@ -350,14 +333,14 @@ void pcmcia_put_dev(struct pcmcia_device *p_dev) static void pcmcia_release_function(struct kref *ref) { struct config_t *c = container_of(ref, struct config_t, ref); - ds_dbg(1, "releasing config_t\n"); + pr_debug("releasing config_t\n"); kfree(c); } static void pcmcia_release_dev(struct device *dev) { struct pcmcia_device *p_dev = to_pcmcia_dev(dev); - ds_dev_dbg(1, dev, "releasing device\n"); + dev_dbg(dev, "releasing device\n"); pcmcia_put_socket(p_dev->socket); kfree(p_dev->devname); kref_put(&p_dev->function_config->ref, pcmcia_release_function); @@ -367,7 +350,7 @@ static void pcmcia_release_dev(struct device *dev) static void pcmcia_add_device_later(struct pcmcia_socket *s, int mfc) { if (!s->pcmcia_state.device_add_pending) { - ds_dev_dbg(1, &s->dev, "scheduling to add %s secondary" + dev_dbg(&s->dev, "scheduling to add %s secondary" " device to %d\n", mfc ? "mfc" : "pfc", s->sock); s->pcmcia_state.device_add_pending = 1; s->pcmcia_state.mfc_pfc = mfc; @@ -405,7 +388,7 @@ static int pcmcia_device_probe(struct device * dev) */ did = dev_get_drvdata(&p_dev->dev); - ds_dev_dbg(1, dev, "trying to bind to %s\n", p_drv->drv.name); + dev_dbg(dev, "trying to bind to %s\n", p_drv->drv.name); if ((!p_drv->probe) || (!p_dev->function_config) || (!try_module_get(p_drv->owner))) { @@ -428,7 +411,7 @@ static int pcmcia_device_probe(struct device * dev) ret = p_drv->probe(p_dev); if (ret) { - ds_dev_dbg(1, dev, "binding to %s failed with %d\n", + dev_dbg(dev, "binding to %s failed with %d\n", p_drv->drv.name, ret); goto put_module; } @@ -456,7 +439,7 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le struct pcmcia_device *tmp; unsigned long flags; - ds_dev_dbg(2, leftover ? &leftover->dev : &s->dev, + dev_dbg(leftover ? &leftover->dev : &s->dev, "pcmcia_card_remove(%d) %s\n", s->sock, leftover ? leftover->devname : ""); @@ -475,7 +458,7 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le p_dev->_removed=1; spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); - ds_dev_dbg(2, &p_dev->dev, "unregistering device\n"); + dev_dbg(&p_dev->dev, "unregistering device\n"); device_unregister(&p_dev->dev); } @@ -492,7 +475,7 @@ static int pcmcia_device_remove(struct device * dev) p_dev = to_pcmcia_dev(dev); p_drv = to_pcmcia_drv(dev->driver); - ds_dev_dbg(1, dev, "removing device\n"); + dev_dbg(dev, "removing device\n"); /* If we're removing the primary module driving a * pseudo multi-function card, we need to unbind @@ -572,7 +555,7 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev) } if (!pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_DEVICE_GEO, devgeo)) { - ds_dev_dbg(0, &p_dev->dev, + dev_dbg(&p_dev->dev, "mem device geometry probably means " "FUNCID_MEMORY\n"); p_dev->func_id = CISTPL_FUNCID_MEMORY; @@ -628,7 +611,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f mutex_lock(&device_add_lock); - ds_dbg(3, "adding device to %d, function %d\n", s->sock, function); + pr_debug("adding device to %d, function %d\n", s->sock, function); /* max of 4 devices per card */ if (s->device_count == 4) @@ -654,7 +637,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f p_dev->devname = kasprintf(GFP_KERNEL, "pcmcia%s", dev_name(&p_dev->dev)); if (!p_dev->devname) goto err_free; - ds_dev_dbg(3, &p_dev->dev, "devname is %s\n", p_dev->devname); + dev_dbg(&p_dev->dev, "devname is %s\n", p_dev->devname); spin_lock_irqsave(&pcmcia_dev_list_lock, flags); @@ -677,7 +660,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); if (!p_dev->function_config) { - ds_dev_dbg(3, &p_dev->dev, "creating config_t\n"); + dev_dbg(&p_dev->dev, "creating config_t\n"); p_dev->function_config = kzalloc(sizeof(struct config_t), GFP_KERNEL); if (!p_dev->function_config) @@ -722,20 +705,20 @@ static int pcmcia_card_add(struct pcmcia_socket *s) int ret = 0; if (!(s->resource_setup_done)) { - ds_dev_dbg(3, &s->dev, + dev_dbg(&s->dev, "no resources available, delaying card_add\n"); return -EAGAIN; /* try again, but later... */ } if (pcmcia_validate_mem(s)) { - ds_dev_dbg(3, &s->dev, "validating mem resources failed, " + dev_dbg(&s->dev, "validating mem resources failed, " "delaying card_add\n"); return -EAGAIN; /* try again, but later... */ } ret = pccard_validate_cis(s, &no_chains); if (ret || !no_chains) { - ds_dev_dbg(0, &s->dev, "invalid CIS or invalid resources\n"); + dev_dbg(&s->dev, "invalid CIS or invalid resources\n"); return -ENODEV; } @@ -756,7 +739,7 @@ static void pcmcia_delayed_add_device(struct work_struct *work) { struct pcmcia_socket *s = container_of(work, struct pcmcia_socket, device_add); - ds_dev_dbg(1, &s->dev, "adding additional device to %d\n", s->sock); + dev_dbg(&s->dev, "adding additional device to %d\n", s->sock); pcmcia_device_add(s, s->pcmcia_state.mfc_pfc); s->pcmcia_state.device_add_pending = 0; s->pcmcia_state.mfc_pfc = 0; @@ -766,7 +749,7 @@ static int pcmcia_requery(struct device *dev, void * _data) { struct pcmcia_device *p_dev = to_pcmcia_dev(dev); if (!p_dev->dev.driver) { - ds_dev_dbg(1, dev, "update device information\n"); + dev_dbg(dev, "update device information\n"); pcmcia_device_query(p_dev); } @@ -780,7 +763,7 @@ static void pcmcia_bus_rescan(struct pcmcia_socket *skt, int new_cis) unsigned long flags; /* must be called with skt_mutex held */ - ds_dev_dbg(0, &skt->dev, "re-scanning socket %d\n", skt->sock); + dev_dbg(&skt->dev, "re-scanning socket %d\n", skt->sock); spin_lock_irqsave(&pcmcia_dev_list_lock, flags); if (list_empty(&skt->devices_list)) @@ -835,7 +818,7 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) if (!filename) return -EINVAL; - ds_dev_dbg(1, &dev->dev, "trying to load CIS file %s\n", filename); + dev_dbg(&dev->dev, "trying to load CIS file %s\n", filename); if (request_firmware(&fw, filename, &dev->dev) == 0) { if (fw->size >= CISTPL_MAX_CIS_SIZE) { @@ -953,14 +936,14 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev, * after it has re-checked that there is no possible module * with a prod_id/manf_id/card_id match. */ - ds_dev_dbg(0, &dev->dev, + dev_dbg(&dev->dev, "skipping FUNC_ID match until userspace interaction\n"); if (!dev->allow_func_id_match) return 0; } if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) { - ds_dev_dbg(0, &dev->dev, "device needs a fake CIS\n"); + dev_dbg(&dev->dev, "device needs a fake CIS\n"); if (!dev->socket->fake_cis) pcmcia_load_firmware(dev, did->cisfile); @@ -992,9 +975,9 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) { /* match dynamic devices first */ spin_lock(&p_drv->dynids.lock); list_for_each_entry(dynid, &p_drv->dynids.list, node) { - ds_dev_dbg(3, dev, "trying to match to %s\n", drv->name); + dev_dbg(dev, "trying to match to %s\n", drv->name); if (pcmcia_devmatch(p_dev, &dynid->id)) { - ds_dev_dbg(0, dev, "matched to %s\n", drv->name); + dev_dbg(dev, "matched to %s\n", drv->name); spin_unlock(&p_drv->dynids.lock); return 1; } @@ -1004,15 +987,15 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) { #ifdef CONFIG_PCMCIA_IOCTL /* matching by cardmgr */ if (p_dev->cardmgr == p_drv) { - ds_dev_dbg(0, dev, "cardmgr matched to %s\n", drv->name); + dev_dbg(dev, "cardmgr matched to %s\n", drv->name); return 1; } #endif while (did && did->match_flags) { - ds_dev_dbg(3, dev, "trying to match to %s\n", drv->name); + dev_dbg(dev, "trying to match to %s\n", drv->name); if (pcmcia_devmatch(p_dev, did)) { - ds_dev_dbg(0, dev, "matched to %s\n", drv->name); + dev_dbg(dev, "matched to %s\n", drv->name); return 1; } did++; @@ -1218,7 +1201,7 @@ static int pcmcia_dev_suspend(struct device * dev, pm_message_t state) if (p_dev->suspended) return 0; - ds_dev_dbg(2, dev, "suspending\n"); + dev_dbg(dev, "suspending\n"); if (dev->driver) p_drv = to_pcmcia_drv(dev->driver); @@ -1238,7 +1221,7 @@ static int pcmcia_dev_suspend(struct device * dev, pm_message_t state) } if (p_dev->device_no == p_dev->func) { - ds_dev_dbg(2, dev, "releasing configuration\n"); + dev_dbg(dev, "releasing configuration\n"); pcmcia_release_configuration(p_dev); } @@ -1258,7 +1241,7 @@ static int pcmcia_dev_resume(struct device * dev) if (!p_dev->suspended) return 0; - ds_dev_dbg(2, dev, "resuming\n"); + dev_dbg(dev, "resuming\n"); if (dev->driver) p_drv = to_pcmcia_drv(dev->driver); @@ -1267,7 +1250,7 @@ static int pcmcia_dev_resume(struct device * dev) goto out; if (p_dev->device_no == p_dev->func) { - ds_dev_dbg(2, dev, "requesting configuration\n"); + dev_dbg(dev, "requesting configuration\n"); ret = pcmcia_request_configuration(p_dev, &p_dev->conf); if (ret) goto out; @@ -1309,14 +1292,14 @@ static int pcmcia_bus_resume_callback(struct device *dev, void * _data) static int pcmcia_bus_resume(struct pcmcia_socket *skt) { - ds_dev_dbg(2, &skt->dev, "resuming socket %d\n", skt->sock); + dev_dbg(&skt->dev, "resuming socket %d\n", skt->sock); bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback); return 0; } static int pcmcia_bus_suspend(struct pcmcia_socket *skt) { - ds_dev_dbg(2, &skt->dev, "suspending socket %d\n", skt->sock); + dev_dbg(&skt->dev, "suspending socket %d\n", skt->sock); if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_suspend_callback)) { pcmcia_bus_resume(skt); @@ -1348,7 +1331,7 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) return -ENODEV; } - ds_dev_dbg(1, &skt->dev, "ds_event(0x%06x, %d, 0x%p)\n", + dev_dbg(&skt->dev, "ds_event(0x%06x, %d, 0x%p)\n", event, priority, skt); switch (event) { diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 30cf71d2ee2..056fd131c89 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -58,17 +58,6 @@ typedef struct user_info_t { } user_info_t; -#ifdef CONFIG_PCMCIA_DEBUG -extern int ds_pc_debug; - -#define ds_dbg(lvl, fmt, arg...) do { \ - if (ds_pc_debug >= lvl) \ - printk(KERN_DEBUG "ds: " fmt , ## arg); \ -} while (0) -#else -#define ds_dbg(lvl, fmt, arg...) do { } while (0) -#endif - static struct pcmcia_device *get_pcmcia_device(struct pcmcia_socket *s, unsigned int function) { @@ -431,7 +420,7 @@ static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info) if (!s) return -EINVAL; - ds_dbg(2, "bind_request(%d, '%s')\n", s->sock, + pr_debug("bind_request(%d, '%s')\n", s->sock, (char *)bind_info->dev_info); p_drv = get_pcmcia_driver(&bind_info->dev_info); @@ -623,7 +612,7 @@ static int ds_open(struct inode *inode, struct file *file) static int warning_printed = 0; int ret = 0; - ds_dbg(0, "ds_open(socket %d)\n", i); + pr_debug("ds_open(socket %d)\n", i); lock_kernel(); s = pcmcia_get_socket_by_nr(i); @@ -685,7 +674,7 @@ static int ds_release(struct inode *inode, struct file *file) struct pcmcia_socket *s; user_info_t *user, **link; - ds_dbg(0, "ds_release(socket %d)\n", iminor(inode)); + pr_debug("ds_release(socket %d)\n", iminor(inode)); user = file->private_data; if (CHECK_USER(user)) @@ -719,7 +708,7 @@ static ssize_t ds_read(struct file *file, char __user *buf, user_info_t *user; int ret; - ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_path.dentry->d_inode)); + pr_debug("ds_read(socket %d)\n", iminor(file->f_path.dentry->d_inode)); if (count < 4) return -EINVAL; @@ -744,7 +733,7 @@ static ssize_t ds_read(struct file *file, char __user *buf, static ssize_t ds_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_path.dentry->d_inode)); + pr_debug("ds_write(socket %d)\n", iminor(file->f_path.dentry->d_inode)); if (count != 4) return -EINVAL; @@ -762,7 +751,7 @@ static u_int ds_poll(struct file *file, poll_table *wait) struct pcmcia_socket *s; user_info_t *user; - ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_path.dentry->d_inode)); + pr_debug("ds_poll(socket %d)\n", iminor(file->f_path.dentry->d_inode)); user = file->private_data; if (CHECK_USER(user)) @@ -790,7 +779,7 @@ static int ds_ioctl(struct inode * inode, struct file * file, ds_ioctl_arg_t *buf; user_info_t *user; - ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg); + pr_debug("ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg); user = file->private_data; if (CHECK_USER(user)) @@ -809,13 +798,13 @@ static int ds_ioctl(struct inode * inode, struct file * file, if (cmd & IOC_IN) { if (!access_ok(VERIFY_READ, uarg, size)) { - ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT); + pr_debug("ds_ioctl(): verify_read = %d\n", -EFAULT); return -EFAULT; } } if (cmd & IOC_OUT) { if (!access_ok(VERIFY_WRITE, uarg, size)) { - ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT); + pr_debug("ds_ioctl(): verify_write = %d\n", -EFAULT); return -EFAULT; } } @@ -962,7 +951,7 @@ static int ds_ioctl(struct inode * inode, struct file * file, } if ((err == 0) && (ret != 0)) { - ds_dbg(2, "ds_ioctl: ret = %d\n", ret); + pr_debug("ds_ioctl: ret = %d\n", ret); switch (ret) { case -ENODEV: case -EINVAL: diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 0bfb05aa8f8..349bc5662ff 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -44,21 +44,6 @@ static u8 pcmcia_used_irq[NR_IRQS]; #endif -#ifdef CONFIG_PCMCIA_DEBUG -extern int ds_pc_debug; - -#define ds_dbg(skt, lvl, fmt, arg...) do { \ - if (ds_pc_debug >= lvl) \ - dev_printk(KERN_DEBUG, &skt->dev, \ - "pcmcia_resource: " fmt, \ - ## arg); \ -} while (0) -#else -#define ds_dbg(skt, lvl, fmt, arg...) do { } while (0) -#endif - - - /** alloc_io_space * * Special stuff for managing IO windows, because they are scarce @@ -73,14 +58,14 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr, align = (*base) ? (lines ? 1<dev, "odd IO request: num %#x align %#x\n", num, align); align = 0; } else while (align && (align < num)) align <<= 1; } if (*base & ~(align-1)) { - ds_dbg(s, 0, "odd IO request: base %#x align %#x\n", + dev_dbg(&s->dev, "odd IO request: base %#x align %#x\n", *base, align); align = 0; } @@ -253,12 +238,12 @@ int pcmcia_map_mem_page(window_handle_t win, memreq_t *req) return -EINVAL; s = win->sock; if (req->Page != 0) { - ds_dbg(s, 0, "failure: requested page is zero\n"); + dev_dbg(&s->dev, "failure: requested page is zero\n"); return -EINVAL; } win->ctl.card_start = req->CardOffset; if (s->ops->set_mem_map(s, &win->ctl) != 0) { - ds_dbg(s, 0, "failed to set_mem_map\n"); + dev_dbg(&s->dev, "failed to set_mem_map\n"); return -EIO; } return 0; @@ -296,7 +281,7 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev, } if (mod->Attributes & CONF_VCC_CHANGE_VALID) { - ds_dbg(s, 0, "changing Vcc is not allowed at this time\n"); + dev_dbg(&s->dev, "changing Vcc is not allowed at this time\n"); return -EINVAL; } @@ -304,7 +289,7 @@ 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) { - ds_dbg(s, 0, "Vpp1 and Vpp2 must be the same\n"); + dev_dbg(&s->dev, "Vpp1 and Vpp2 must be the same\n"); return -EINVAL; } s->socket.Vpp = mod->Vpp1; @@ -315,7 +300,7 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev, } } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) || (mod->Attributes & CONF_VPP2_CHANGE_VALID)) { - ds_dbg(s, 0, "changing Vcc is not allowed at this time\n"); + dev_dbg(&s->dev, "changing Vcc is not allowed at this time\n"); return -EINVAL; } @@ -426,11 +411,11 @@ static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req) if (c->state & CONFIG_LOCKED) return -EACCES; if (c->irq.Attributes != req->Attributes) { - ds_dbg(s, 0, "IRQ attributes must match assigned ones\n"); + dev_dbg(&s->dev, "IRQ attributes must match assigned ones\n"); return -EINVAL; } if (s->irq.AssignedIRQ != req->AssignedIRQ) { - ds_dbg(s, 0, "IRQ must match assigned one\n"); + dev_dbg(&s->dev, "IRQ must match assigned one\n"); return -EINVAL; } if (--s->irq.Config == 0) { @@ -493,7 +478,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev, return -ENODEV; if (req->IntType & INT_CARDBUS) { - ds_dbg(p_dev->socket, 0, "IntType may not be INT_CARDBUS\n"); + dev_dbg(&s->dev, "IntType may not be INT_CARDBUS\n"); return -EINVAL; } c = p_dev->function_config; @@ -619,31 +604,31 @@ int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req) if (c->state & CONFIG_LOCKED) return -EACCES; if (c->state & CONFIG_IO_REQ) { - ds_dbg(s, 0, "IO already configured\n"); + dev_dbg(&s->dev, "IO already configured\n"); return -EBUSY; } if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)) { - ds_dbg(s, 0, "bad attribute setting for IO region 1\n"); + dev_dbg(&s->dev, "bad attribute setting for IO region 1\n"); return -EINVAL; } if ((req->NumPorts2 > 0) && (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))) { - ds_dbg(s, 0, "bad attribute setting for IO region 2\n"); + dev_dbg(&s->dev, "bad attribute setting for IO region 2\n"); return -EINVAL; } - ds_dbg(s, 1, "trying to allocate resource 1\n"); + dev_dbg(&s->dev, "trying to allocate resource 1\n"); if (alloc_io_space(s, req->Attributes1, &req->BasePort1, req->NumPorts1, req->IOAddrLines)) { - ds_dbg(s, 0, "allocation of resource 1 failed\n"); + dev_dbg(&s->dev, "allocation of resource 1 failed\n"); return -EBUSY; } if (req->NumPorts2) { - ds_dbg(s, 1, "trying to allocate resource 2\n"); + dev_dbg(&s->dev, "trying to allocate resource 2\n"); if (alloc_io_space(s, req->Attributes2, &req->BasePort2, req->NumPorts2, req->IOAddrLines)) { - ds_dbg(s, 0, "allocation of resource 2 failed\n"); + dev_dbg(&s->dev, "allocation of resource 2 failed\n"); release_io_space(s, req->BasePort1, req->NumPorts1); return -EBUSY; } @@ -687,7 +672,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) if (c->state & CONFIG_LOCKED) return -EACCES; if (c->state & CONFIG_IRQ_REQ) { - ds_dbg(s, 0, "IRQ already configured\n"); + dev_dbg(&s->dev, "IRQ already configured\n"); return -EBUSY; } @@ -798,7 +783,7 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h if (!(s->state & SOCKET_PRESENT)) return -ENODEV; if (req->Attributes & (WIN_PAGED | WIN_SHARED)) { - ds_dbg(s, 0, "bad attribute setting for iomem region\n"); + dev_dbg(&s->dev, "bad attribute setting for iomem region\n"); return -EINVAL; } @@ -809,12 +794,12 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h (req->Attributes & WIN_STRICT_ALIGN)) ? req->Size : s->map_size); if (req->Size & (s->map_size-1)) { - ds_dbg(s, 0, "invalid map size\n"); + dev_dbg(&s->dev, "invalid map size\n"); return -EINVAL; } if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) || (req->Base & (align-1))) { - ds_dbg(s, 0, "invalid base address\n"); + dev_dbg(&s->dev, "invalid base address\n"); return -EINVAL; } if (req->Base) @@ -824,7 +809,7 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h for (w = 0; w < MAX_WIN; w++) if (!(s->state & SOCKET_WIN_REQ(w))) break; if (w == MAX_WIN) { - ds_dbg(s, 0, "all windows are used already\n"); + dev_dbg(&s->dev, "all windows are used already\n"); return -EINVAL; } @@ -838,7 +823,7 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h win->ctl.res = pcmcia_find_mem_region(req->Base, req->Size, align, (req->Attributes & WIN_MAP_BELOW_1MB), s); if (!win->ctl.res) { - ds_dbg(s, 0, "allocating mem region failed\n"); + dev_dbg(&s->dev, "allocating mem region failed\n"); return -EINVAL; } } @@ -858,7 +843,7 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h win->ctl.flags |= MAP_USE_WAIT; win->ctl.card_start = 0; if (s->ops->set_mem_map(s, &win->ctl) != 0) { - ds_dbg(s, 0, "failed to set memory mapping\n"); + dev_dbg(&s->dev, "failed to set memory mapping\n"); return -EIO; } s->state |= SOCKET_WIN_REQ(w); From c9f50dddd184a020d64dab63fa795967f0f14aa4 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Fri, 23 Oct 2009 12:56:46 +0200 Subject: [PATCH 087/298] pcmcia: use dynamic debug in PCMCIA socket drivers Make use of the dynamic debug infrastructure in various PCMCIA socket drivers. By doing so, only the drivers relying on soc_common make use of CONFIG_PCMCIA_DEBUG. Therefore, update the Kconfig entry accordingly. Signed-off-by: Dominik Brodowski --- drivers/pcmcia/Kconfig | 36 ++++++------ drivers/pcmcia/i82365.c | 37 ++++-------- drivers/pcmcia/m32r_cfc.c | 105 +++++++++++++++-------------------- drivers/pcmcia/m32r_pcc.c | 51 +++++++---------- drivers/pcmcia/m8xx_pcmcia.c | 40 ++++++------- drivers/pcmcia/tcic.c | 29 +++------- 6 files changed, 118 insertions(+), 180 deletions(-) diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 17f38a781d4..0c44dddd9b7 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -17,24 +17,6 @@ menuconfig PCCARD if PCCARD -config PCMCIA_DEBUG - bool "Enable PCCARD debugging" - help - Say Y here to enable PCMCIA subsystem debugging. You - will need to choose the debugging level either via the - kernel command line, or module options depending whether - you build the PCMCIA as modules. - - The kernel command line options are: - pcmcia_core.pc_debug=N - pcmcia.pc_debug=N - sa11xx_core.pc_debug=N - - The module option is called pc_debug=N - - In all the above examples, N is the debugging verbosity - level. - config PCMCIA tristate "16-bit PCMCIA support" select CRC32 @@ -225,6 +207,24 @@ config PCMCIA_PXA2XX help Say Y here to include support for the PXA2xx PCMCIA controller +config PCMCIA_DEBUG + bool "Enable debugging" + depends on (PCMCIA_SA1111 || PCMCIA_SA1100 || PCMCIA_PXA2XX) + help + Say Y here to enable debugging for the SoC PCMCIA layer. + You will need to choose the debugging level either via the + kernel command line, or module options depending whether + you build the drivers as modules. + + The kernel command line options are: + sa11xx_core.pc_debug=N + pxa2xx_core.pc_debug=N + + The module option is called pc_debug=N + + In all the above examples, N is the debugging verbosity + level. + config PCMCIA_PROBE bool default y if ISA && !ARCH_SA1100 && !ARCH_CLPS711X && !PARISC diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index a4aacb830b8..c13fd936051 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -63,21 +63,6 @@ #include "vg468.h" #include "ricoh.h" -#ifdef CONFIG_PCMCIA_DEBUG -static const char version[] = -"i82365.c 1.265 1999/11/10 18:36:21 (David Hinds)"; - -static int pc_debug; - -module_param(pc_debug, int, 0644); - -#define debug(lvl, fmt, arg...) do { \ - if (pc_debug > (lvl)) \ - printk(KERN_DEBUG "i82365: " fmt , ## arg); \ -} while (0) -#else -#define debug(lvl, fmt, arg...) do { } while (0) -#endif static irqreturn_t i365_count_irq(int, void *); static inline int _check_irq(int irq, int flags) @@ -501,13 +486,13 @@ static irqreturn_t i365_count_irq(int irq, void *dev) { i365_get(irq_sock, I365_CSC); irq_hits++; - debug(2, "-> hit on irq %d\n", irq); + pr_debug("i82365: -> hit on irq %d\n", irq); return IRQ_HANDLED; } static u_int __init test_irq(u_short sock, int irq) { - debug(2, " testing ISA irq %d\n", irq); + pr_debug("i82365: testing ISA irq %d\n", irq); if (request_irq(irq, i365_count_irq, IRQF_PROBE_SHARED, "scan", i365_count_irq) != 0) return 1; @@ -515,7 +500,7 @@ static u_int __init test_irq(u_short sock, int irq) msleep(10); if (irq_hits) { free_irq(irq, i365_count_irq); - debug(2, " spurious hit!\n"); + pr_debug("i82365: spurious hit!\n"); return 1; } @@ -528,7 +513,7 @@ static u_int __init test_irq(u_short sock, int irq) /* mask all interrupts */ i365_set(sock, I365_CSCINT, 0); - debug(2, " hits = %d\n", irq_hits); + pr_debug("i82365: hits = %d\n", irq_hits); return (irq_hits != 1); } @@ -854,7 +839,7 @@ static irqreturn_t pcic_interrupt(int irq, void *dev) u_long flags = 0; int handled = 0; - debug(4, "pcic_interrupt(%d)\n", irq); + pr_debug("pcic_interrupt(%d)\n", irq); for (j = 0; j < 20; j++) { active = 0; @@ -878,7 +863,7 @@ static irqreturn_t pcic_interrupt(int irq, void *dev) events |= (csc & I365_CSC_READY) ? SS_READY : 0; } ISA_UNLOCK(i, flags); - debug(2, "socket %d event 0x%02x\n", i, events); + pr_debug("socket %d event 0x%02x\n", i, events); if (events) pcmcia_parse_events(&socket[i].socket, events); @@ -890,7 +875,7 @@ static irqreturn_t pcic_interrupt(int irq, void *dev) if (j == 20) printk(KERN_NOTICE "i82365: infinite loop in interrupt handler\n"); - debug(4, "interrupt done\n"); + pr_debug("pcic_interrupt done\n"); return IRQ_RETVAL(handled); } /* pcic_interrupt */ @@ -932,7 +917,7 @@ static int i365_get_status(u_short sock, u_int *value) } } - debug(1, "GetStatus(%d) = %#4.4x\n", sock, *value); + pr_debug("GetStatus(%d) = %#4.4x\n", sock, *value); return 0; } /* i365_get_status */ @@ -943,7 +928,7 @@ static int i365_set_socket(u_short sock, socket_state_t *state) struct i82365_socket *t = &socket[sock]; u_char reg; - debug(1, "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " + pr_debug("SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags, state->Vcc, state->Vpp, state->io_irq, state->csc_mask); @@ -1052,7 +1037,7 @@ static int i365_set_io_map(u_short sock, struct pccard_io_map *io) { u_char map, ioctl; - debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, " + pr_debug("SetIOMap(%d, %d, %#2.2x, %d ns, " "%#llx-%#llx)\n", sock, io->map, io->flags, io->speed, (unsigned long long)io->start, (unsigned long long)io->stop); map = io->map; @@ -1082,7 +1067,7 @@ static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem) u_short base, i; u_char map; - debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, %#llx-%#llx, " + pr_debug("SetMemMap(%d, %d, %#2.2x, %d ns, %#llx-%#llx, " "%#x)\n", sock, mem->map, mem->flags, mem->speed, (unsigned long long)mem->res->start, (unsigned long long)mem->res->end, mem->card_start); diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index 7dfbee1dcd7..26a621c9e2f 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -38,17 +38,6 @@ #include "m32r_cfc.h" -#ifdef CONFIG_PCMCIA_DEBUG -static int m32r_cfc_debug; -module_param(m32r_cfc_debug, int, 0644); -#define debug(lvl, fmt, arg...) do { \ - if (m32r_cfc_debug > (lvl)) \ - printk(KERN_DEBUG "m32r_cfc: " fmt , ## arg); \ -} while (0) -#else -#define debug(n, args...) do { } while (0) -#endif - /* Poll status interval -- 0 means default to interrupt */ static int poll_interval = 0; @@ -123,7 +112,7 @@ void pcc_ioread_byte(int sock, unsigned long port, void *buf, size_t size, unsigned char *bp = (unsigned char *)buf; unsigned long flags; - debug(3, "m32r_cfc: pcc_ioread_byte: sock=%d, port=%#lx, buf=%p, " + pr_debug("m32r_cfc: pcc_ioread_byte: sock=%d, port=%#lx, buf=%p, " "size=%u, nmemb=%d, flag=%d\n", sock, port, buf, size, nmemb, flag); @@ -132,7 +121,7 @@ void pcc_ioread_byte(int sock, unsigned long port, void *buf, size_t size, printk("m32r_cfc:ioread_byte null port :%#lx\n",port); return; } - debug(3, "m32r_cfc: pcc_ioread_byte: addr=%#lx\n", addr); + pr_debug("m32r_cfc: pcc_ioread_byte: addr=%#lx\n", addr); spin_lock_irqsave(&pcc_lock, flags); /* read Byte */ @@ -148,7 +137,7 @@ void pcc_ioread_word(int sock, unsigned long port, void *buf, size_t size, unsigned short *bp = (unsigned short *)buf; unsigned long flags; - debug(3, "m32r_cfc: pcc_ioread_word: sock=%d, port=%#lx, " + pr_debug("m32r_cfc: pcc_ioread_word: sock=%d, port=%#lx, " "buf=%p, size=%u, nmemb=%d, flag=%d\n", sock, port, buf, size, nmemb, flag); @@ -163,7 +152,7 @@ void pcc_ioread_word(int sock, unsigned long port, void *buf, size_t size, printk("m32r_cfc:ioread_word null port :%#lx\n",port); return; } - debug(3, "m32r_cfc: pcc_ioread_word: addr=%#lx\n", addr); + pr_debug("m32r_cfc: pcc_ioread_word: addr=%#lx\n", addr); spin_lock_irqsave(&pcc_lock, flags); /* read Word */ @@ -179,7 +168,7 @@ void pcc_iowrite_byte(int sock, unsigned long port, void *buf, size_t size, unsigned char *bp = (unsigned char *)buf; unsigned long flags; - debug(3, "m32r_cfc: pcc_iowrite_byte: sock=%d, port=%#lx, " + pr_debug("m32r_cfc: pcc_iowrite_byte: sock=%d, port=%#lx, " "buf=%p, size=%u, nmemb=%d, flag=%d\n", sock, port, buf, size, nmemb, flag); @@ -189,7 +178,7 @@ void pcc_iowrite_byte(int sock, unsigned long port, void *buf, size_t size, printk("m32r_cfc:iowrite_byte null port:%#lx\n",port); return; } - debug(3, "m32r_cfc: pcc_iowrite_byte: addr=%#lx\n", addr); + pr_debug("m32r_cfc: pcc_iowrite_byte: addr=%#lx\n", addr); spin_lock_irqsave(&pcc_lock, flags); while (nmemb--) @@ -204,7 +193,7 @@ void pcc_iowrite_word(int sock, unsigned long port, void *buf, size_t size, unsigned short *bp = (unsigned short *)buf; unsigned long flags; - debug(3, "m32r_cfc: pcc_iowrite_word: sock=%d, port=%#lx, " + pr_debug("m32r_cfc: pcc_iowrite_word: sock=%d, port=%#lx, " "buf=%p, size=%u, nmemb=%d, flag=%d\n", sock, port, buf, size, nmemb, flag); @@ -226,7 +215,7 @@ void pcc_iowrite_word(int sock, unsigned long port, void *buf, size_t size, return; } #endif - debug(3, "m32r_cfc: pcc_iowrite_word: addr=%#lx\n", addr); + pr_debug("m32r_cfc: pcc_iowrite_word: addr=%#lx\n", addr); spin_lock_irqsave(&pcc_lock, flags); while (nmemb--) @@ -262,7 +251,7 @@ static struct timer_list poll_timer; static unsigned int pcc_get(u_short sock, unsigned int reg) { unsigned int val = inw(reg); - debug(3, "m32r_cfc: pcc_get: reg(0x%08x)=0x%04x\n", reg, val); + pr_debug("m32r_cfc: pcc_get: reg(0x%08x)=0x%04x\n", reg, val); return val; } @@ -270,7 +259,7 @@ static unsigned int pcc_get(u_short sock, unsigned int reg) static void pcc_set(u_short sock, unsigned int reg, unsigned int data) { outw(data, reg); - debug(3, "m32r_cfc: pcc_set: reg(0x%08x)=0x%04x\n", reg, data); + pr_debug("m32r_cfc: pcc_set: reg(0x%08x)=0x%04x\n", reg, data); } /*====================================================================== @@ -286,14 +275,14 @@ static int __init is_alive(u_short sock) { unsigned int stat; - debug(3, "m32r_cfc: is_alive:\n"); + pr_debug("m32r_cfc: is_alive:\n"); printk("CF: "); stat = pcc_get(sock, (unsigned int)PLD_CFSTS); if (!stat) printk("No "); printk("Card is detected at socket %d : stat = 0x%08x\n", sock, stat); - debug(3, "m32r_cfc: is_alive: sock stat is 0x%04x\n", stat); + pr_debug("m32r_cfc: is_alive: sock stat is 0x%04x\n", stat); return 0; } @@ -303,7 +292,7 @@ static void add_pcc_socket(ulong base, int irq, ulong mapaddr, { pcc_socket_t *t = &socket[pcc_sockets]; - debug(3, "m32r_cfc: add_pcc_socket: base=%#lx, irq=%d, " + pr_debug("m32r_cfc: add_pcc_socket: base=%#lx, irq=%d, " "mapaddr=%#lx, ioaddr=%08x\n", base, irq, mapaddr, ioaddr); @@ -358,7 +347,7 @@ static void add_pcc_socket(ulong base, int irq, ulong mapaddr, /* eject interrupt */ request_irq(irq+1, pcc_interrupt, 0, "m32r_cfc", pcc_interrupt); #endif - debug(3, "m32r_cfc: enable CFMSK, RDYSEL\n"); + pr_debug("m32r_cfc: enable CFMSK, RDYSEL\n"); pcc_set(pcc_sockets, (unsigned int)PLD_CFIMASK, 0x01); #endif /* CONFIG_PLAT_USRV */ #if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT) @@ -378,26 +367,26 @@ static irqreturn_t pcc_interrupt(int irq, void *dev) u_int events = 0; int handled = 0; - debug(3, "m32r_cfc: pcc_interrupt: irq=%d, dev=%p\n", irq, dev); + pr_debug("m32r_cfc: pcc_interrupt: irq=%d, dev=%p\n", irq, dev); for (i = 0; i < pcc_sockets; i++) { if (socket[i].cs_irq1 != irq && socket[i].cs_irq2 != irq) continue; handled = 1; - debug(3, "m32r_cfc: pcc_interrupt: socket %d irq 0x%02x ", + pr_debug("m32r_cfc: pcc_interrupt: socket %d irq 0x%02x ", i, irq); events |= SS_DETECT; /* insert or eject */ if (events) pcmcia_parse_events(&socket[i].socket, events); } - debug(3, "m32r_cfc: pcc_interrupt: done\n"); + pr_debug("m32r_cfc: pcc_interrupt: done\n"); return IRQ_RETVAL(handled); } /* pcc_interrupt */ static void pcc_interrupt_wrapper(u_long data) { - debug(3, "m32r_cfc: pcc_interrupt_wrapper:\n"); + pr_debug("m32r_cfc: pcc_interrupt_wrapper:\n"); pcc_interrupt(0, NULL); init_timer(&poll_timer); poll_timer.expires = jiffies + poll_interval; @@ -410,17 +399,17 @@ static int _pcc_get_status(u_short sock, u_int *value) { u_int status; - debug(3, "m32r_cfc: _pcc_get_status:\n"); + pr_debug("m32r_cfc: _pcc_get_status:\n"); status = pcc_get(sock, (unsigned int)PLD_CFSTS); *value = (status) ? SS_DETECT : 0; - debug(3, "m32r_cfc: _pcc_get_status: status=0x%08x\n", status); + pr_debug("m32r_cfc: _pcc_get_status: status=0x%08x\n", status); #if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT) if ( status ) { /* enable CF power */ status = inw((unsigned int)PLD_CPCR); if (!(status & PLD_CPCR_CF)) { - debug(3, "m32r_cfc: _pcc_get_status: " + pr_debug("m32r_cfc: _pcc_get_status: " "power on (CPCR=0x%08x)\n", status); status |= PLD_CPCR_CF; outw(status, (unsigned int)PLD_CPCR); @@ -439,7 +428,7 @@ static int _pcc_get_status(u_short sock, u_int *value) status &= ~PLD_CPCR_CF; outw(status, (unsigned int)PLD_CPCR); udelay(100); - debug(3, "m32r_cfc: _pcc_get_status: " + pr_debug("m32r_cfc: _pcc_get_status: " "power off (CPCR=0x%08x)\n", status); } #elif defined(CONFIG_PLAT_MAPPI2) || defined(CONFIG_PLAT_MAPPI3) @@ -465,13 +454,13 @@ static int _pcc_get_status(u_short sock, u_int *value) /* disable CF power */ pcc_set(sock, (unsigned int)PLD_CPCR, 0); udelay(100); - debug(3, "m32r_cfc: _pcc_get_status: " + pr_debug("m32r_cfc: _pcc_get_status: " "power off (CPCR=0x%08x)\n", status); } #else #error no platform configuration #endif - debug(3, "m32r_cfc: _pcc_get_status: GetStatus(%d) = %#4.4x\n", + pr_debug("m32r_cfc: _pcc_get_status: GetStatus(%d) = %#4.4x\n", sock, *value); return 0; } /* _get_status */ @@ -480,7 +469,7 @@ static int _pcc_get_status(u_short sock, u_int *value) static int _pcc_set_socket(u_short sock, socket_state_t *state) { - debug(3, "m32r_cfc: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " + pr_debug("m32r_cfc: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags, state->Vcc, state->Vpp, state->io_irq, state->csc_mask); @@ -492,41 +481,39 @@ static int _pcc_set_socket(u_short sock, socket_state_t *state) } #endif if (state->flags & SS_RESET) { - debug(3, ":RESET\n"); + pr_debug(":RESET\n"); pcc_set(sock,(unsigned int)PLD_CFRSTCR,0x101); }else{ pcc_set(sock,(unsigned int)PLD_CFRSTCR,0x100); } if (state->flags & SS_OUTPUT_ENA){ - debug(3, ":OUTPUT_ENA\n"); + pr_debug(":OUTPUT_ENA\n"); /* bit clear */ pcc_set(sock,(unsigned int)PLD_CFBUFCR,0); } else { pcc_set(sock,(unsigned int)PLD_CFBUFCR,1); } -#ifdef CONFIG_PCMCIA_DEBUG if(state->flags & SS_IOCARD){ - debug(3, ":IOCARD"); + pr_debug(":IOCARD"); } if (state->flags & SS_PWR_AUTO) { - debug(3, ":PWR_AUTO"); + pr_debug(":PWR_AUTO"); } if (state->csc_mask & SS_DETECT) - debug(3, ":csc-SS_DETECT"); + pr_debug(":csc-SS_DETECT"); if (state->flags & SS_IOCARD) { if (state->csc_mask & SS_STSCHG) - debug(3, ":STSCHG"); + pr_debug(":STSCHG"); } else { if (state->csc_mask & SS_BATDEAD) - debug(3, ":BATDEAD"); + pr_debug(":BATDEAD"); if (state->csc_mask & SS_BATWARN) - debug(3, ":BATWARN"); + pr_debug(":BATWARN"); if (state->csc_mask & SS_READY) - debug(3, ":READY"); + pr_debug(":READY"); } - debug(3, "\n"); -#endif + pr_debug("\n"); return 0; } /* _set_socket */ @@ -536,7 +523,7 @@ static int _pcc_set_io_map(u_short sock, struct pccard_io_map *io) { u_char map; - debug(3, "m32r_cfc: SetIOMap(%d, %d, %#2.2x, %d ns, " + pr_debug("m32r_cfc: SetIOMap(%d, %d, %#2.2x, %d ns, " "%#llx-%#llx)\n", sock, io->map, io->flags, io->speed, (unsigned long long)io->start, (unsigned long long)io->stop); @@ -554,7 +541,7 @@ static int _pcc_set_mem_map(u_short sock, struct pccard_mem_map *mem) u_long addr; pcc_socket_t *t = &socket[sock]; - debug(3, "m32r_cfc: SetMemMap(%d, %d, %#2.2x, %d ns, " + pr_debug("m32r_cfc: SetMemMap(%d, %d, %#2.2x, %d ns, " "%#llx, %#x)\n", sock, map, mem->flags, mem->speed, (unsigned long long)mem->static_start, mem->card_start); @@ -640,11 +627,11 @@ static int pcc_get_status(struct pcmcia_socket *s, u_int *value) unsigned int sock = container_of(s, struct pcc_socket, socket)->number; if (socket[sock].flags & IS_ALIVE) { - debug(3, "m32r_cfc: pcc_get_status: sock(%d) -EINVAL\n", sock); + dev_dbg(&s->dev, "pcc_get_status: sock(%d) -EINVAL\n", sock); *value = 0; return -EINVAL; } - debug(3, "m32r_cfc: pcc_get_status: sock(%d)\n", sock); + dev_dbg(&s->dev, "pcc_get_status: sock(%d)\n", sock); LOCKED(_pcc_get_status(sock, value)); } @@ -653,10 +640,10 @@ static int pcc_set_socket(struct pcmcia_socket *s, socket_state_t *state) unsigned int sock = container_of(s, struct pcc_socket, socket)->number; if (socket[sock].flags & IS_ALIVE) { - debug(3, "m32r_cfc: pcc_set_socket: sock(%d) -EINVAL\n", sock); + dev_dbg(&s->dev, "pcc_set_socket: sock(%d) -EINVAL\n", sock); return -EINVAL; } - debug(3, "m32r_cfc: pcc_set_socket: sock(%d)\n", sock); + dev_dbg(&s->dev, "pcc_set_socket: sock(%d)\n", sock); LOCKED(_pcc_set_socket(sock, state)); } @@ -665,10 +652,10 @@ static int pcc_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io) unsigned int sock = container_of(s, struct pcc_socket, socket)->number; if (socket[sock].flags & IS_ALIVE) { - debug(3, "m32r_cfc: pcc_set_io_map: sock(%d) -EINVAL\n", sock); + dev_dbg(&s->dev, "pcc_set_io_map: sock(%d) -EINVAL\n", sock); return -EINVAL; } - debug(3, "m32r_cfc: pcc_set_io_map: sock(%d)\n", sock); + dev_dbg(&s->dev, "pcc_set_io_map: sock(%d)\n", sock); LOCKED(_pcc_set_io_map(sock, io)); } @@ -677,16 +664,16 @@ static int pcc_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem) unsigned int sock = container_of(s, struct pcc_socket, socket)->number; if (socket[sock].flags & IS_ALIVE) { - debug(3, "m32r_cfc: pcc_set_mem_map: sock(%d) -EINVAL\n", sock); + dev_dbg(&s->dev, "pcc_set_mem_map: sock(%d) -EINVAL\n", sock); return -EINVAL; } - debug(3, "m32r_cfc: pcc_set_mem_map: sock(%d)\n", sock); + dev_dbg(&s->dev, "pcc_set_mem_map: sock(%d)\n", sock); LOCKED(_pcc_set_mem_map(sock, mem)); } static int pcc_init(struct pcmcia_socket *s) { - debug(3, "m32r_cfc: pcc_init()\n"); + dev_dbg(&s->dev, "pcc_init()\n"); return 0; } diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index c6524f99ccc..72844c5a6d0 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c @@ -45,16 +45,6 @@ #define PCC_DEBUG_DBEX -#ifdef CONFIG_PCMCIA_DEBUG -static int m32r_pcc_debug; -module_param(m32r_pcc_debug, int, 0644); -#define debug(lvl, fmt, arg...) do { \ - if (m32r_pcc_debug > (lvl)) \ - printk(KERN_DEBUG "m32r_pcc: " fmt , ## arg); \ -} while (0) -#else -#define debug(n, args...) do { } while (0) -#endif /* Poll status interval -- 0 means default to interrupt */ static int poll_interval = 0; @@ -358,7 +348,7 @@ static irqreturn_t pcc_interrupt(int irq, void *dev) u_int events, active; int handled = 0; - debug(4, "m32r: pcc_interrupt(%d)\n", irq); + pr_debug("m32r_pcc: pcc_interrupt(%d)\n", irq); for (j = 0; j < 20; j++) { active = 0; @@ -369,13 +359,14 @@ static irqreturn_t pcc_interrupt(int irq, void *dev) handled = 1; irc = pcc_get(i, PCIRC); irc >>=16; - debug(2, "m32r-pcc:interrupt: socket %d pcirc 0x%02x ", i, irc); + pr_debug("m32r_pcc: interrupt: socket %d pcirc 0x%02x ", + i, irc); if (!irc) continue; events = (irc) ? SS_DETECT : 0; events |= (pcc_get(i,PCCR) & PCCR_PCEN) ? SS_READY : 0; - debug(2, " event 0x%02x\n", events); + pr_debug("m32r_pcc: event 0x%02x\n", events); if (events) pcmcia_parse_events(&socket[i].socket, events); @@ -388,7 +379,7 @@ static irqreturn_t pcc_interrupt(int irq, void *dev) if (j == 20) printk(KERN_NOTICE "m32r-pcc: infinite loop in interrupt handler\n"); - debug(4, "m32r-pcc: interrupt done\n"); + pr_debug("m32r_pcc: interrupt done\n"); return IRQ_RETVAL(handled); } /* pcc_interrupt */ @@ -422,7 +413,7 @@ static int _pcc_get_status(u_short sock, u_int *value) status = pcc_get(sock,PCCSIGCR); *value |= (status & PCCSIGCR_VEN) ? SS_POWERON : 0; - debug(3, "m32r-pcc: GetStatus(%d) = %#4.4x\n", sock, *value); + pr_debug("m32r_pcc: GetStatus(%d) = %#4.4x\n", sock, *value); return 0; } /* _get_status */ @@ -432,7 +423,7 @@ static int _pcc_set_socket(u_short sock, socket_state_t *state) { u_long reg = 0; - debug(3, "m32r-pcc: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " + pr_debug("m32r_pcc: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " "io_irq %d, csc_mask %#2.2x)", sock, state->flags, state->Vcc, state->Vpp, state->io_irq, state->csc_mask); @@ -448,11 +439,11 @@ static int _pcc_set_socket(u_short sock, socket_state_t *state) } if (state->flags & SS_RESET) { - debug(3, ":RESET\n"); + pr_debug("m32r_pcc: :RESET\n"); reg |= PCCSIGCR_CRST; } if (state->flags & SS_OUTPUT_ENA){ - debug(3, ":OUTPUT_ENA\n"); + pr_debug("m32r_pcc: :OUTPUT_ENA\n"); /* bit clear */ } else { reg |= PCCSIGCR_SEN; @@ -460,28 +451,26 @@ static int _pcc_set_socket(u_short sock, socket_state_t *state) pcc_set(sock,PCCSIGCR,reg); -#ifdef CONFIG_PCMCIA_DEBUG if(state->flags & SS_IOCARD){ - debug(3, ":IOCARD"); + pr_debug("m32r_pcc: :IOCARD"); } if (state->flags & SS_PWR_AUTO) { - debug(3, ":PWR_AUTO"); + pr_debug("m32r_pcc: :PWR_AUTO"); } if (state->csc_mask & SS_DETECT) - debug(3, ":csc-SS_DETECT"); + pr_debug("m32r_pcc: :csc-SS_DETECT"); if (state->flags & SS_IOCARD) { if (state->csc_mask & SS_STSCHG) - debug(3, ":STSCHG"); + pr_debug("m32r_pcc: :STSCHG"); } else { if (state->csc_mask & SS_BATDEAD) - debug(3, ":BATDEAD"); + pr_debug("m32r_pcc: :BATDEAD"); if (state->csc_mask & SS_BATWARN) - debug(3, ":BATWARN"); + pr_debug("m32r_pcc: :BATWARN"); if (state->csc_mask & SS_READY) - debug(3, ":READY"); + pr_debug("m32r_pcc: :READY"); } - debug(3, "\n"); -#endif + pr_debug("m32r_pcc: \n"); return 0; } /* _set_socket */ @@ -491,7 +480,7 @@ static int _pcc_set_io_map(u_short sock, struct pccard_io_map *io) { u_char map; - debug(3, "m32r-pcc: SetIOMap(%d, %d, %#2.2x, %d ns, " + pr_debug("m32r_pcc: SetIOMap(%d, %d, %#2.2x, %d ns, " "%#llx-%#llx)\n", sock, io->map, io->flags, io->speed, (unsigned long long)io->start, (unsigned long long)io->stop); @@ -515,7 +504,7 @@ static int _pcc_set_mem_map(u_short sock, struct pccard_mem_map *mem) #endif #endif - debug(3, "m32r-pcc: SetMemMap(%d, %d, %#2.2x, %d ns, " + pr_debug("m32r_pcc: SetMemMap(%d, %d, %#2.2x, %d ns, " "%#llx, %#x)\n", sock, map, mem->flags, mem->speed, (unsigned long long)mem->static_start, mem->card_start); @@ -662,7 +651,7 @@ static int pcc_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem) static int pcc_init(struct pcmcia_socket *s) { - debug(4, "m32r-pcc: init call\n"); + pr_debug("m32r_pcc: init call\n"); return 0; } diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index 403559ba49d..7f79c4e169a 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c @@ -64,14 +64,6 @@ #include #include -#ifdef CONFIG_PCMCIA_DEBUG -static int pc_debug; -module_param(pc_debug, int, 0); -#define dprintk(args...) printk(KERN_DEBUG "m8xx_pcmcia: " args); -#else -#define dprintk(args...) -#endif - #define pcmcia_info(args...) printk(KERN_INFO "m8xx_pcmcia: "args) #define pcmcia_error(args...) printk(KERN_ERR "m8xx_pcmcia: "args) @@ -565,7 +557,7 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev) unsigned int i, events, pscr, pipr, per; pcmconf8xx_t *pcmcia = socket[0].pcmcia; - dprintk("Interrupt!\n"); + pr_debug("m8xx_pcmcia: Interrupt!\n"); /* get interrupt sources */ pscr = in_be32(&pcmcia->pcmc_pscr); @@ -614,7 +606,7 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev) /* call the handler */ - dprintk("slot %u: events = 0x%02x, pscr = 0x%08x, " + pr_debug("m8xx_pcmcia: slot %u: events = 0x%02x, pscr = 0x%08x, " "pipr = 0x%08x\n", i, events, pscr, pipr); if (events) { @@ -641,7 +633,7 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev) /* clear the interrupt sources */ out_be32(&pcmcia->pcmc_pscr, pscr); - dprintk("Interrupt done.\n"); + pr_debug("m8xx_pcmcia: Interrupt done.\n"); return IRQ_HANDLED; } @@ -815,7 +807,7 @@ static int m8xx_get_status(struct pcmcia_socket *sock, unsigned int *value) }; } - dprintk("GetStatus(%d) = %#2.2x\n", lsock, *value); + pr_debug("m8xx_pcmcia: GetStatus(%d) = %#2.2x\n", lsock, *value); return 0; } @@ -828,7 +820,7 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t * state) unsigned long flags; pcmconf8xx_t *pcmcia = socket[0].pcmcia; - dprintk("SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " + pr_debug("m8xx_pcmcia: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags, state->Vcc, state->Vpp, state->io_irq, state->csc_mask); @@ -974,7 +966,7 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) #define M8XX_SIZE (io->stop - io->start + 1) #define M8XX_BASE (PCMCIA_IO_WIN_BASE + io->start) - dprintk("SetIOMap(%d, %d, %#2.2x, %d ns, " + pr_debug("m8xx_pcmcia: SetIOMap(%d, %d, %#2.2x, %d ns, " "%#4.4llx-%#4.4llx)\n", lsock, io->map, io->flags, io->speed, (unsigned long long)io->start, (unsigned long long)io->stop); @@ -988,7 +980,7 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) if (io->flags & MAP_ACTIVE) { - dprintk("io->flags & MAP_ACTIVE\n"); + pr_debug("m8xx_pcmcia: io->flags & MAP_ACTIVE\n"); winnr = (PCMCIA_MEM_WIN_NO * PCMCIA_SOCKETS_NO) + (lsock * PCMCIA_IO_WIN_NO) + io->map; @@ -1018,8 +1010,8 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) out_be32(&w->or, reg); - dprintk("Socket %u: Mapped io window %u at %#8.8x, " - "OR = %#8.8x.\n", lsock, io->map, w->br, w->or); + pr_debug("m8xx_pcmcia: Socket %u: Mapped io window %u at " + "%#8.8x, OR = %#8.8x.\n", lsock, io->map, w->br, w->or); } else { /* shutdown IO window */ winnr = (PCMCIA_MEM_WIN_NO * PCMCIA_SOCKETS_NO) @@ -1033,14 +1025,14 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) out_be32(&w->or, 0); /* turn off window */ out_be32(&w->br, 0); /* turn off base address */ - dprintk("Socket %u: Unmapped io window %u at %#8.8x, " - "OR = %#8.8x.\n", lsock, io->map, w->br, w->or); + pr_debug("m8xx_pcmcia: Socket %u: Unmapped io window %u at " + "%#8.8x, OR = %#8.8x.\n", lsock, io->map, w->br, w->or); } /* copy the struct and modify the copy */ s->io_win[io->map] = *io; s->io_win[io->map].flags &= (MAP_WRPROT | MAP_16BIT | MAP_ACTIVE); - dprintk("SetIOMap exit\n"); + pr_debug("m8xx_pcmcia: SetIOMap exit\n"); return 0; } @@ -1055,7 +1047,7 @@ static int m8xx_set_mem_map(struct pcmcia_socket *sock, unsigned int reg, winnr; pcmconf8xx_t *pcmcia = s->pcmcia; - dprintk("SetMemMap(%d, %d, %#2.2x, %d ns, " + pr_debug("m8xx_pcmcia: SetMemMap(%d, %d, %#2.2x, %d ns, " "%#5.5llx, %#5.5x)\n", lsock, mem->map, mem->flags, mem->speed, (unsigned long long)mem->static_start, mem->card_start); @@ -1098,7 +1090,7 @@ static int m8xx_set_mem_map(struct pcmcia_socket *sock, out_be32(&w->or, reg); - dprintk("Socket %u: Mapped memory window %u at %#8.8x, " + pr_debug("m8xx_pcmcia: Socket %u: Mapped memory window %u at %#8.8x, " "OR = %#8.8x.\n", lsock, mem->map, w->br, w->or); if (mem->flags & MAP_ACTIVE) { @@ -1108,7 +1100,7 @@ static int m8xx_set_mem_map(struct pcmcia_socket *sock, + mem->card_start; } - dprintk("SetMemMap(%d, %d, %#2.2x, %d ns, " + pr_debug("m8xx_pcmcia: SetMemMap(%d, %d, %#2.2x, %d ns, " "%#5.5llx, %#5.5x)\n", lsock, mem->map, mem->flags, mem->speed, (unsigned long long)mem->static_start, mem->card_start); @@ -1129,7 +1121,7 @@ static int m8xx_sock_init(struct pcmcia_socket *sock) pccard_io_map io = { 0, 0, 0, 0, 1 }; pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 }; - dprintk("sock_init(%d)\n", s); + pr_debug("m8xx_pcmcia: sock_init(%d)\n", s); m8xx_set_socket(sock, &dead_socket); for (i = 0; i < PCMCIA_IO_WIN_NO; i++) { diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index 6918849d511..12c49ee135e 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -55,21 +55,6 @@ #include #include "tcic.h" -#ifdef CONFIG_PCMCIA_DEBUG -static int pc_debug; - -module_param(pc_debug, int, 0644); -static const char version[] = -"tcic.c 1.111 2000/02/15 04:13:12 (David Hinds)"; - -#define debug(lvl, fmt, arg...) do { \ - if (pc_debug > (lvl)) \ - printk(KERN_DEBUG "tcic: " fmt , ## arg); \ -} while (0) -#else -#define debug(lvl, fmt, arg...) do { } while (0) -#endif - MODULE_AUTHOR("David Hinds "); MODULE_DESCRIPTION("Databook TCIC-2 PCMCIA socket driver"); MODULE_LICENSE("Dual MPL/GPL"); @@ -574,7 +559,7 @@ static irqreturn_t tcic_interrupt(int irq, void *dev) } else active = 1; - debug(2, "tcic_interrupt()\n"); + pr_debug("tcic_interrupt()\n"); for (i = 0; i < sockets; i++) { psock = socket_table[i].psock; @@ -611,13 +596,13 @@ static irqreturn_t tcic_interrupt(int irq, void *dev) } active = 0; - debug(2, "interrupt done\n"); + pr_debug("interrupt done\n"); return IRQ_HANDLED; } /* tcic_interrupt */ static void tcic_timer(u_long data) { - debug(2, "tcic_timer()\n"); + pr_debug("tcic_timer()\n"); tcic_timer_pending = 0; tcic_interrupt(0, NULL); } /* tcic_timer */ @@ -644,7 +629,7 @@ static int tcic_get_status(struct pcmcia_socket *sock, u_int *value) reg = tcic_getb(TCIC_PWR); if (reg & (TCIC_PWR_VCC(psock)|TCIC_PWR_VPP(psock))) *value |= SS_POWERON; - debug(1, "GetStatus(%d) = %#2.2x\n", psock, *value); + dev_dbg(&sock->dev, "GetStatus(%d) = %#2.2x\n", psock, *value); return 0; } /* tcic_get_status */ @@ -656,7 +641,7 @@ static int tcic_set_socket(struct pcmcia_socket *sock, socket_state_t *state) u_char reg; u_short scf1, scf2; - debug(1, "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " + dev_dbg(&sock->dev, "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " "io_irq %d, csc_mask %#2.2x)\n", psock, state->flags, state->Vcc, state->Vpp, state->io_irq, state->csc_mask); tcic_setw(TCIC_ADDR+2, (psock << TCIC_SS_SHFT) | TCIC_ADR2_INDREG); @@ -731,7 +716,7 @@ static int tcic_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) u_int addr; u_short base, len, ioctl; - debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, " + dev_dbg(&sock->dev, "SetIOMap(%d, %d, %#2.2x, %d ns, " "%#llx-%#llx)\n", psock, io->map, io->flags, io->speed, (unsigned long long)io->start, (unsigned long long)io->stop); if ((io->map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) || @@ -768,7 +753,7 @@ static int tcic_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m u_short addr, ctl; u_long base, len, mmap; - debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, " + dev_dbg(&sock->dev, "SetMemMap(%d, %d, %#2.2x, %d ns, " "%#llx-%#llx, %#x)\n", psock, mem->map, mem->flags, mem->speed, (unsigned long long)mem->res->start, (unsigned long long)mem->res->end, mem->card_start); From 6d9a299f675b176e2f81e1f6d5a361a1173971ea Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 24 Oct 2009 12:20:18 +0200 Subject: [PATCH 088/298] pcmcia: extend error reporting and debug messages in core Add a few more error and debug messages to the PCMCIA core. Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs.c | 3 ++ drivers/pcmcia/pcmcia_resource.c | 53 ++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index b0ec9c614ce..b229f6d9e44 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -752,14 +752,17 @@ int pcmcia_reset_card(struct pcmcia_socket *skt) mutex_lock(&skt->skt_mutex); do { if (!(skt->state & SOCKET_PRESENT)) { + dev_dbg(&skt->dev, "can't reset, not present\n"); ret = -ENODEV; break; } if (skt->state & SOCKET_SUSPEND) { + dev_dbg(&skt->dev, "can't reset, suspended\n"); ret = -EBUSY; break; } if (skt->state & SOCKET_CARDBUS) { + dev_dbg(&skt->dev, "can't reset, is cardbus\n"); ret = -EPERM; break; } diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 349bc5662ff..cda48ea9b6f 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -159,8 +159,10 @@ int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, s = p_dev->socket; c = p_dev->function_config; - if (!(c->state & CONFIG_LOCKED)) + if (!(c->state & CONFIG_LOCKED)) { + dev_dbg(&s->dev, "Configuration isnt't locked\n"); return -EACCES; + } addr = (c->ConfigBase + reg->Offset) >> 1; @@ -174,6 +176,7 @@ int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, pcmcia_write_cis_mem(s, 1, addr, 1, &val); break; default: + dev_dbg(&s->dev, "Invalid conf register request\n"); return -EINVAL; break; } @@ -264,10 +267,14 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev, s = p_dev->socket; c = p_dev->function_config; - if (!(s->state & SOCKET_PRESENT)) + if (!(s->state & SOCKET_PRESENT)) { + dev_dbg(&s->dev, "No card present\n"); return -ENODEV; - if (!(c->state & CONFIG_LOCKED)) + } + if (!(c->state & CONFIG_LOCKED)) { + dev_dbg(&s->dev, "Configuration isnt't locked\n"); return -EACCES; + } if (mod->Attributes & CONF_IRQ_CHANGE_VALID) { if (mod->Attributes & CONF_ENABLE_IRQ) { @@ -442,8 +449,10 @@ int pcmcia_release_window(window_handle_t win) if ((win == NULL) || (win->magic != WINDOW_MAGIC)) return -EINVAL; s = win->sock; - if (!(win->handle->_win & CLIENT_WIN_REQ(win->index))) + if (!(win->handle->_win & CLIENT_WIN_REQ(win->index))) { + dev_dbg(&s->dev, "not releasing unknown window\n"); return -EINVAL; + } /* Shut down memory window */ win->ctl.flags &= ~MAP_ACTIVE; @@ -482,8 +491,10 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev, return -EINVAL; } c = p_dev->function_config; - if (c->state & CONFIG_LOCKED) + if (c->state & CONFIG_LOCKED) { + dev_dbg(&s->dev, "Configuration is locked\n"); return -EACCES; + } /* Do power control. We don't allow changes in Vcc. */ s->socket.Vpp = req->Vpp; @@ -595,14 +606,18 @@ int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req) struct pcmcia_socket *s = p_dev->socket; config_t *c; - if (!(s->state & SOCKET_PRESENT)) + if (!(s->state & SOCKET_PRESENT)) { + dev_dbg(&s->dev, "No card present\n"); return -ENODEV; + } if (!req) return -EINVAL; c = p_dev->function_config; - if (c->state & CONFIG_LOCKED) + if (c->state & CONFIG_LOCKED) { + dev_dbg(&s->dev, "Configuration is locked\n"); return -EACCES; + } if (c->state & CONFIG_IO_REQ) { dev_dbg(&s->dev, "IO already configured\n"); return -EBUSY; @@ -666,11 +681,15 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) int ret = -EINVAL, irq = 0; int type; - if (!(s->state & SOCKET_PRESENT)) + if (!(s->state & SOCKET_PRESENT)) { + dev_dbg(&s->dev, "No card present\n"); return -ENODEV; + } c = p_dev->function_config; - if (c->state & CONFIG_LOCKED) + if (c->state & CONFIG_LOCKED) { + dev_dbg(&s->dev, "Configuration is locked\n"); return -EACCES; + } if (c->state & CONFIG_IRQ_REQ) { dev_dbg(&s->dev, "IRQ already configured\n"); return -EBUSY; @@ -731,8 +750,10 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) #endif /* only assign PCI irq if no IRQ already assigned */ if (ret && !s->irq.AssignedIRQ) { - if (!s->pci_irq) + if (!s->pci_irq) { + dev_printk(KERN_INFO, &s->dev, "no IRQ found\n"); return ret; + } type = IRQF_SHARED; irq = s->pci_irq; } @@ -740,8 +761,11 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) if (ret && (req->Attributes & IRQ_HANDLE_PRESENT)) { ret = request_irq(irq, req->Handler, type, p_dev->devname, req->Instance); - if (ret) + if (ret) { + dev_printk(KERN_INFO, &s->dev, + "request_irq() failed\n"); return ret; + } } /* Make sure the fact the request type was overridden is passed back */ @@ -780,8 +804,10 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h u_long align; int w; - if (!(s->state & SOCKET_PRESENT)) + if (!(s->state & SOCKET_PRESENT)) { + dev_dbg(&s->dev, "No card present\n"); return -ENODEV; + } if (req->Attributes & (WIN_PAGED | WIN_SHARED)) { dev_dbg(&s->dev, "bad attribute setting for iomem region\n"); return -EINVAL; @@ -1020,7 +1046,8 @@ static int pcmcia_do_get_tuple(struct pcmcia_device *p_dev, tuple_t *tuple, if (*get->buf) { get->len = tuple->TupleDataLen; memcpy(*get->buf, tuple->TupleData, tuple->TupleDataLen); - } + } else + dev_dbg(&p_dev->dev, "do_get_tuple: out of memory\n"); return 0; }; From 444486a5f9d2737b50e53dc140292899b9497808 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Fri, 23 Oct 2009 12:55:28 +0200 Subject: [PATCH 089/298] pcmcia: use dynamic debug infrastructure, deprecate CS_CHECK (ide) ide-cs.c is the only PCMCIA device driver making use of CONFIG_PCMCIA_DEBUG, so convert it to use the dynamic debug infrastructure. Also, remove all usages of the CS_CHECK macro and replace them with proper Linux style calling and return value checking. The extra error reporting may be dropped, as the PCMCIA core already complains about any (non-driver-author) errors. CC: linux-ide@vger.kernel.org Signed-off-by: Dominik Brodowski --- drivers/ata/pata_pcmcia.c | 16 ++++++++-------- drivers/ide/ide-cs.c | 32 +++++++++++--------------------- 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index dc99e26f8e5..5f94e214e17 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -177,9 +177,6 @@ static struct ata_port_operations pcmcia_8bit_port_ops = { .drain_fifo = pcmcia_8bit_drain_fifo, }; -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - struct pcmcia_config_check { unsigned long ctl_base; @@ -252,7 +249,7 @@ static int pcmcia_init_one(struct pcmcia_device *pdev) struct ata_port *ap; struct ata_pcmcia_info *info; struct pcmcia_config_check *stk = NULL; - int last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM, p; + int is_kme = 0, ret = -ENOMEM, p; unsigned long io_base, ctl_base; void __iomem *io_addr, *ctl_addr; int n_ports = 1; @@ -296,8 +293,13 @@ static int pcmcia_init_one(struct pcmcia_device *pdev) } io_base = pdev->io.BasePort1; ctl_base = stk->ctl_base; - CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &pdev->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &pdev->conf)); + ret = pcmcia_request_irq(pdev, &pdev->irq); + if (ret) + goto failed; + + ret = pcmcia_request_configuration(pdev, &pdev->conf); + if (ret) + goto failed; /* iomap */ ret = -ENOMEM; @@ -351,8 +353,6 @@ static int pcmcia_init_one(struct pcmcia_device *pdev) kfree(stk); return 0; -cs_failed: - cs_error(pdev, last_fn, last_ret); failed: kfree(stk); info->ndev = 0; diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c index 063b933d864..6cee6c8d078 100644 --- a/drivers/ide/ide-cs.c +++ b/drivers/ide/ide-cs.c @@ -60,15 +60,6 @@ MODULE_AUTHOR("David Hinds "); MODULE_DESCRIPTION("PCMCIA ATA/IDE card driver"); MODULE_LICENSE("Dual MPL/GPL"); -#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0) - -#ifdef CONFIG_PCMCIA_DEBUG -INT_MODULE_PARM(pc_debug, 0); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -#else -#define DEBUG(n, args...) -#endif - /*====================================================================*/ typedef struct ide_info_t { @@ -98,7 +89,7 @@ static int ide_probe(struct pcmcia_device *link) { ide_info_t *info; - DEBUG(0, "ide_attach()\n"); + dev_dbg(&link->dev, "ide_attach()\n"); /* Create new ide device */ info = kzalloc(sizeof(*info), GFP_KERNEL); @@ -134,7 +125,7 @@ static void ide_detach(struct pcmcia_device *link) ide_hwif_t *hwif = info->host->ports[0]; unsigned long data_addr, ctl_addr; - DEBUG(0, "ide_detach(0x%p)\n", link); + dev_dbg(&link->dev, "ide_detach(0x%p)\n", link); data_addr = hwif->io_ports.data_addr; ctl_addr = hwif->io_ports.ctl_addr; @@ -217,9 +208,6 @@ out_release: ======================================================================*/ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - struct pcmcia_config_check { unsigned long ctl_base; int skip_vcc; @@ -282,11 +270,11 @@ static int ide_config(struct pcmcia_device *link) { ide_info_t *info = link->priv; struct pcmcia_config_check *stk = NULL; - int last_ret = 0, last_fn = 0, is_kme = 0; + int ret = 0, is_kme = 0; unsigned long io_base, ctl_base; struct ide_host *host; - DEBUG(0, "ide_config(0x%p)\n", link); + dev_dbg(&link->dev, "ide_config(0x%p)\n", link); is_kme = ((link->manf_id == MANFID_KME) && ((link->card_id == PRODID_KME_KXLC005_A) || @@ -306,8 +294,12 @@ static int ide_config(struct pcmcia_device *link) io_base = link->io.BasePort1; ctl_base = stk->ctl_base; - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; /* disable drive interrupts during IDE probe */ outb(0x02, ctl_base); @@ -342,8 +334,6 @@ err_mem: printk(KERN_NOTICE "ide-cs: ide_config failed memory allocation\n"); goto failed; -cs_failed: - cs_error(link, last_fn, last_ret); failed: kfree(stk); ide_release(link); @@ -363,7 +353,7 @@ static void ide_release(struct pcmcia_device *link) ide_info_t *info = link->priv; struct ide_host *host = info->host; - DEBUG(0, "ide_release(0x%p)\n", link); + dev_dbg(&link->dev, "ide_release(0x%p)\n", link); if (info->ndev) /* FIXME: if this fails we need to queue the cleanup somehow From 9ac3e58ceff0b7b8b981c09c38a28742270eea12 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 24 Oct 2009 15:45:06 +0200 Subject: [PATCH 090/298] pcmcia: deprecate CS_CHECK (bluetooth) Remove all usages of the CS_CHECK macro and replace them with proper Linux style calling and return value checking. The extra error reporting may be dropped, as the PCMCIA core already complains about any (non-driver-author) errors. CC: linux-bluetooth@vger.kernel.org Signed-off-by: Dominik Brodowski --- drivers/bluetooth/bluecard_cs.c | 12 +++--------- drivers/bluetooth/bt3c_cs.c | 9 ++------- drivers/bluetooth/btuart_cs.c | 9 ++------- drivers/bluetooth/dtl1_cs.c | 8 ++------ 4 files changed, 9 insertions(+), 29 deletions(-) diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index b0e569ba730..1e0c4d82297 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -905,22 +905,16 @@ static int bluecard_config(struct pcmcia_device *link) break; } - if (i != 0) { - cs_error(link, RequestIO, i); + if (i != 0) goto failed; - } i = pcmcia_request_irq(link, &link->irq); - if (i != 0) { - cs_error(link, RequestIRQ, i); + if (i != 0) link->irq.AssignedIRQ = 0; - } i = pcmcia_request_configuration(link, &link->conf); - if (i != 0) { - cs_error(link, RequestConfiguration, i); + if (i != 0) goto failed; - } if (bluecard_open(info) != 0) goto failed; diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index d58e22b9f06..9787fda45d8 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -740,21 +740,16 @@ static int bt3c_config(struct pcmcia_device *link) goto found_port; BT_ERR("No usable port range found"); - cs_error(link, RequestIO, -ENODEV); goto failed; found_port: i = pcmcia_request_irq(link, &link->irq); - if (i != 0) { - cs_error(link, RequestIRQ, i); + if (i != 0) link->irq.AssignedIRQ = 0; - } i = pcmcia_request_configuration(link, &link->conf); - if (i != 0) { - cs_error(link, RequestConfiguration, i); + if (i != 0) goto failed; - } if (bt3c_open(info) != 0) goto failed; diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index efd689a062e..f44d75217b2 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -669,21 +669,16 @@ static int btuart_config(struct pcmcia_device *link) goto found_port; BT_ERR("No usable port range found"); - cs_error(link, RequestIO, -ENODEV); goto failed; found_port: i = pcmcia_request_irq(link, &link->irq); - if (i != 0) { - cs_error(link, RequestIRQ, i); + if (i != 0) link->irq.AssignedIRQ = 0; - } i = pcmcia_request_configuration(link, &link->conf); - if (i != 0) { - cs_error(link, RequestConfiguration, i); + if (i != 0) goto failed; - } if (btuart_open(info) != 0) goto failed; diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index b881a9cd874..7cd8614a8ea 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -622,16 +622,12 @@ static int dtl1_config(struct pcmcia_device *link) goto failed; i = pcmcia_request_irq(link, &link->irq); - if (i != 0) { - cs_error(link, RequestIRQ, i); + if (i != 0) link->irq.AssignedIRQ = 0; - } i = pcmcia_request_configuration(link, &link->conf); - if (i != 0) { - cs_error(link, RequestConfiguration, i); + if (i != 0) goto failed; - } if (dtl1_open(info) != 0) goto failed; From 0e1a6ef2dea88101b056b6d9984f3325c5efced3 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sun, 8 Nov 2009 09:37:00 -0800 Subject: [PATCH 091/298] sysctl: require CAP_SYS_RAWIO to set mmap_min_addr Currently the mmap_min_addr value can only be bypassed during mmap when the task has CAP_SYS_RAWIO. However, the mmap_min_addr sysctl value itself can be adjusted to 0 if euid == 0, allowing a bypass without CAP_SYS_RAWIO. This patch adds a check for the capability before allowing mmap_min_addr to be changed. Signed-off-by: Kees Cook Acked-by: Serge Hallyn Signed-off-by: James Morris --- security/min_addr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/security/min_addr.c b/security/min_addr.c index c844eed7915..fc43c9d3708 100644 --- a/security/min_addr.c +++ b/security/min_addr.c @@ -33,6 +33,9 @@ int mmap_min_addr_handler(struct ctl_table *table, int write, { int ret; + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + ret = proc_doulongvec_minmax(table, write, buffer, lenp, ppos); update_mmap_min_addr(); From 6e65f92ff0d6f18580737321718d09035085a3fb Mon Sep 17 00:00:00 2001 From: John Johansen Date: Thu, 5 Nov 2009 17:03:20 -0800 Subject: [PATCH 092/298] Config option to set a default LSM The LSM currently requires setting a kernel parameter at boot to select a specific LSM. This adds a config option that allows specifying a default LSM that is used unless overridden with the security= kernel parameter. If the the config option is not set the current behavior of first LSM to register is used. Signed-off-by: John Johansen Acked-by: Serge Hallyn Signed-off-by: James Morris --- security/Kconfig | 32 ++++++++++++++++++++++++++++++++ security/security.c | 9 ++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/security/Kconfig b/security/Kconfig index aeea8c2bb59..95cc08913ca 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -152,5 +152,37 @@ source security/tomoyo/Kconfig source security/integrity/ima/Kconfig +choice + prompt "Default security module" + default DEFAULT_SECURITY_SELINUX if SECURITY_SELINUX + default DEFAULT_SECURITY_SMACK if SECURITY_SMACK + default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO + default DEFAULT_SECURITY_DAC + + help + Select the security module that will be used by default if the + kernel parameter security= is not specified. + + config DEFAULT_SECURITY_SELINUX + bool "SELinux" if SECURITY_SELINUX=y + + config DEFAULT_SECURITY_SMACK + bool "Simplified Mandatory Access Control" if SECURITY_SMACK=y + + config DEFAULT_SECURITY_TOMOYO + bool "TOMOYO" if SECURITY_TOMOYO=y + + config DEFAULT_SECURITY_DAC + bool "Unix Discretionary Access Controls" + +endchoice + +config DEFAULT_SECURITY + string + default "selinux" if DEFAULT_SECURITY_SELINUX + default "smack" if DEFAULT_SECURITY_SMACK + default "tomoyo" if DEFAULT_SECURITY_TOMOYO + default "" if DEFAULT_SECURITY_DAC + endmenu diff --git a/security/security.c b/security/security.c index 684d5ee655d..aad71b2ca19 100644 --- a/security/security.c +++ b/security/security.c @@ -19,7 +19,8 @@ #include /* Boot-time LSM user choice */ -static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1]; +static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = + CONFIG_DEFAULT_SECURITY; /* things that live in capability.c */ extern struct security_operations default_security_ops; @@ -80,8 +81,10 @@ __setup("security=", choose_lsm); * * Return true if: * -The passed LSM is the one chosen by user at boot time, - * -or user didn't specify a specific LSM and we're the first to ask - * for registration permission, + * -or the passed LSM is configured as the default and the user did not + * choose an alternate LSM at boot time, + * -or there is no default LSM set and the user didn't specify a + * specific LSM and we're the first to ask for registration permission, * -or the passed LSM is currently loaded. * Otherwise, return false. */ From cbf624f0e18c4a05219855663a3e5f9fe8f2d876 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 24 Oct 2009 15:47:29 +0200 Subject: [PATCH 093/298] pcmcia: use dynamic debug infrastructure, deprecate CS_CHECK (char) Convert PCMCIA drivers to use the dynamic debug infrastructure, instead of requiring manual settings of PCMCIA_DEBUG. Only some rare extra debug checks in cm4000_cs.c cm4040_cs.c are now hidden behind a "#ifdef CM4000_DEBUG" or "#ifdef CM4040_DEBUG". Also, remove all usages of the CS_CHECK macro and replace them with proper Linux style calling and return value checking. The extra error reporting may be dropped, as the PCMCIA core already complains about any (non-driver-author) errors. CC: Harald Welte CC: Jiri Kosina CC: David Sterba Signed-off-by: Dominik Brodowski --- drivers/char/pcmcia/cm4000_cs.c | 71 ++++++++++----------------- drivers/char/pcmcia/cm4040_cs.c | 42 +++++++--------- drivers/char/pcmcia/ipwireless/main.c | 34 +++---------- drivers/char/pcmcia/synclink_cs.c | 23 +++++---- 4 files changed, 63 insertions(+), 107 deletions(-) diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index c250a31efa5..1611c4fe97f 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -23,8 +23,6 @@ * All rights reserved. Licensed under dual BSD/GPL license. */ -/* #define PCMCIA_DEBUG 6 */ - #include #include #include @@ -47,18 +45,17 @@ /* #define ATR_CSUM */ -#ifdef PCMCIA_DEBUG #define reader_to_dev(x) (&handle_to_dev(x->p_dev)) -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0600); -#define DEBUGP(n, rdr, x, args...) do { \ - if (pc_debug >= (n)) \ - dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, \ - __func__ , ## args); \ + +/* n (debug level) is ignored */ +/* additional debug output may be enabled by re-compiling with + * CM4000_DEBUG set */ +/* #define CM4000_DEBUG */ +#define DEBUGP(n, rdr, x, args...) do { \ + dev_dbg(reader_to_dev(rdr), "%s:" x, \ + __func__ , ## args); \ } while (0) -#else -#define DEBUGP(n, rdr, x, args...) -#endif + static char *version = "cm4000_cs.c v2.4.0gm6 - All bugs added by Harald Welte"; #define T_1SEC (HZ) @@ -174,14 +171,13 @@ static unsigned char fi_di_table[10][14] = { /* 9 */ {0x09,0x19,0x29,0x39,0x49,0x59,0x69,0x11,0x11,0x99,0xA9,0xB9,0xC9,0xD9} }; -#ifndef PCMCIA_DEBUG +#ifndef CM4000_DEBUG #define xoutb outb #define xinb inb #else static inline void xoutb(unsigned char val, unsigned short port) { - if (pc_debug >= 7) - printk(KERN_DEBUG "outb(val=%.2x,port=%.4x)\n", val, port); + pr_debug("outb(val=%.2x,port=%.4x)\n", val, port); outb(val, port); } static inline unsigned char xinb(unsigned short port) @@ -189,8 +185,7 @@ static inline unsigned char xinb(unsigned short port) unsigned char val; val = inb(port); - if (pc_debug >= 7) - printk(KERN_DEBUG "%.2x=inb(%.4x)\n", val, port); + pr_debug("%.2x=inb(%.4x)\n", val, port); return val; } @@ -514,12 +509,10 @@ static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq) for (i = 0; i < 4; i++) { xoutb(i, REG_BUF_ADDR(iobase)); xoutb(dev->pts[i], REG_BUF_DATA(iobase)); /* buf data */ -#ifdef PCMCIA_DEBUG - if (pc_debug >= 5) - printk("0x%.2x ", dev->pts[i]); +#ifdef CM4000_DEBUG + pr_debug("0x%.2x ", dev->pts[i]); } - if (pc_debug >= 5) - printk("\n"); + pr_debug("\n"); #else } #endif @@ -579,14 +572,13 @@ static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq) pts_reply[i] = inb(REG_BUF_DATA(iobase)); } -#ifdef PCMCIA_DEBUG +#ifdef CM4000_DEBUG DEBUGP(2, dev, "PTSreply: "); for (i = 0; i < num_bytes_read; i++) { - if (pc_debug >= 5) - printk("0x%.2x ", pts_reply[i]); + pr_debug("0x%.2x ", pts_reply[i]); } - printk("\n"); -#endif /* PCMCIA_DEBUG */ + pr_debug("\n"); +#endif /* CM4000_DEBUG */ DEBUGP(5, dev, "Clear Tactive in Flags1\n"); xoutb(0x20, REG_FLAGS1(iobase)); @@ -655,7 +647,7 @@ static void terminate_monitor(struct cm4000_dev *dev) DEBUGP(5, dev, "Delete timer\n"); del_timer_sync(&dev->timer); -#ifdef PCMCIA_DEBUG +#ifdef CM4000_DEBUG dev->monitor_running = 0; #endif @@ -898,7 +890,7 @@ static void monitor_card(unsigned long p) DEBUGP(4, dev, "ATR checksum (0x%.2x, should " "be zero) failed\n", dev->atr_csum); } -#ifdef PCMCIA_DEBUG +#ifdef CM4000_DEBUG else if (test_bit(IS_BAD_LENGTH, &dev->flags)) { DEBUGP(4, dev, "ATR length error\n"); } else { @@ -1415,7 +1407,7 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) int size; int rc; void __user *argp = (void __user *)arg; -#ifdef PCMCIA_DEBUG +#ifdef CM4000_DEBUG char *ioctl_names[CM_IOC_MAXNR + 1] = { [_IOC_NR(CM_IOCGSTATUS)] "CM_IOCGSTATUS", [_IOC_NR(CM_IOCGATR)] "CM_IOCGATR", @@ -1423,9 +1415,9 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) [_IOC_NR(CM_IOCSPTS)] "CM_IOCSPTS", [_IOC_NR(CM_IOSDBGLVL)] "CM4000_DBGLVL", }; -#endif DEBUGP(3, dev, "cmm_ioctl(device=%d.%d) %s\n", imajor(inode), iminor(inode), ioctl_names[_IOC_NR(cmd)]); +#endif lock_kernel(); rc = -ENODEV; @@ -1523,7 +1515,7 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } case CM_IOCARDOFF: -#ifdef PCMCIA_DEBUG +#ifdef CM4000_DEBUG DEBUGP(4, dev, "... in CM_IOCARDOFF\n"); if (dev->flags0 & 0x01) { DEBUGP(4, dev, " Card inserted\n"); @@ -1625,18 +1617,9 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; -#ifdef PCMCIA_DEBUG - case CM_IOSDBGLVL: /* set debug log level */ - { - int old_pc_debug = 0; - - old_pc_debug = pc_debug; - if (copy_from_user(&pc_debug, argp, sizeof(int))) - rc = -EFAULT; - else if (old_pc_debug != pc_debug) - DEBUGP(0, dev, "Changed debug log level " - "to %i\n", pc_debug); - } +#ifdef CM4000_DEBUG + case CM_IOSDBGLVL: + rc = -ENOTTY; break; #endif default: diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 4f0723b0797..0001ad2e58b 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -17,8 +17,6 @@ * All rights reserved, Dual BSD/GPL Licensed. */ -/* #define PCMCIA_DEBUG 6 */ - #include #include #include @@ -41,18 +39,16 @@ #include "cm4040_cs.h" -#ifdef PCMCIA_DEBUG #define reader_to_dev(x) (&handle_to_dev(x->p_dev)) -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0600); -#define DEBUGP(n, rdr, x, args...) do { \ - if (pc_debug >= (n)) \ - dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, \ - __func__ , ##args); \ + +/* n (debug level) is ignored */ +/* additional debug output may be enabled by re-compiling with + * CM4040_DEBUG set */ +/* #define CM4040_DEBUG */ +#define DEBUGP(n, rdr, x, args...) do { \ + dev_dbg(reader_to_dev(rdr), "%s:" x, \ + __func__ , ## args); \ } while (0) -#else -#define DEBUGP(n, rdr, x, args...) -#endif static char *version = "OMNIKEY CardMan 4040 v1.1.0gm5 - All bugs added by Harald Welte"; @@ -90,14 +86,13 @@ struct reader_dev { static struct pcmcia_device *dev_table[CM_MAX_DEV]; -#ifndef PCMCIA_DEBUG +#ifndef CM4040_DEBUG #define xoutb outb #define xinb inb #else static inline void xoutb(unsigned char val, unsigned short port) { - if (pc_debug >= 7) - printk(KERN_DEBUG "outb(val=%.2x,port=%.4x)\n", val, port); + pr_debug("outb(val=%.2x,port=%.4x)\n", val, port); outb(val, port); } @@ -106,8 +101,7 @@ static inline unsigned char xinb(unsigned short port) unsigned char val; val = inb(port); - if (pc_debug >= 7) - printk(KERN_DEBUG "%.2x=inb(%.4x)\n", val, port); + pr_debug("%.2x=inb(%.4x)\n", val, port); return val; } #endif @@ -260,11 +254,10 @@ static ssize_t cm4040_read(struct file *filp, char __user *buf, return -EIO; } dev->r_buf[i] = xinb(iobase + REG_OFFSET_BULK_IN); -#ifdef PCMCIA_DEBUG - if (pc_debug >= 6) - printk(KERN_DEBUG "%lu:%2x ", i, dev->r_buf[i]); +#ifdef CM4040_DEBUG + pr_debug("%lu:%2x ", i, dev->r_buf[i]); } - printk("\n"); + pr_debug("\n"); #else } #endif @@ -288,11 +281,10 @@ static ssize_t cm4040_read(struct file *filp, char __user *buf, return -EIO; } dev->r_buf[i+5] = xinb(iobase + REG_OFFSET_BULK_IN); -#ifdef PCMCIA_DEBUG - if (pc_debug >= 6) - printk(KERN_DEBUG "%lu:%2x ", i, dev->r_buf[i]); +#ifdef CM4040_DEBUG + pr_debug("%lu:%2x ", i, dev->r_buf[i]); } - printk("\n"); + pr_debug("\n"); #else } #endif diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c index 0f467495991..24bffa4ece4 100644 --- a/drivers/char/pcmcia/ipwireless/main.c +++ b/drivers/char/pcmcia/ipwireless/main.c @@ -65,10 +65,7 @@ static void signalled_reboot_work(struct work_struct *work_reboot) struct ipw_dev *ipw = container_of(work_reboot, struct ipw_dev, work_reboot); struct pcmcia_device *link = ipw->link; - int ret = pcmcia_reset_card(link->socket); - - if (ret != 0) - cs_error(link, ResetCard, ret); + pcmcia_reset_card(link->socket); } static void signalled_reboot_callback(void *callback_data) @@ -122,10 +119,8 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, ret = pcmcia_request_window(&p_dev, &ipw->request_common_memory, &ipw->handle_common_memory); - if (ret != 0) { - cs_error(p_dev, RequestWindow, ret); + if (ret != 0) goto exit1; - } memreq_common_memory.CardOffset = cfg->mem.win[0].card_addr; memreq_common_memory.Page = 0; @@ -133,10 +128,8 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, ret = pcmcia_map_mem_page(ipw->handle_common_memory, &memreq_common_memory); - if (ret != 0) { - cs_error(p_dev, MapMemPage, ret); + if (ret != 0) goto exit2; - } ipw->is_v2_card = cfg->mem.win[0].len == 0x100; @@ -155,10 +148,8 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, ret = pcmcia_request_window(&p_dev, &ipw->request_attr_memory, &ipw->handle_attr_memory); - if (ret != 0) { - cs_error(p_dev, RequestWindow, ret); + if (ret != 0) goto exit2; - } memreq_attr_memory.CardOffset = 0; memreq_attr_memory.Page = 0; @@ -166,10 +157,8 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, ret = pcmcia_map_mem_page(ipw->handle_attr_memory, &memreq_attr_memory); - if (ret != 0) { - cs_error(p_dev, MapMemPage, ret); + if (ret != 0) goto exit3; - } ipw->attr_memory = ioremap(ipw->request_attr_memory.Base, ipw->request_attr_memory.Size); @@ -202,10 +191,8 @@ static int config_ipwireless(struct ipw_dev *ipw) ipw->is_v2_card = 0; ret = pcmcia_loop_config(link, ipwireless_probe, ipw); - if (ret != 0) { - cs_error(link, RequestIO, ret); + if (ret != 0) return ret; - } link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; @@ -223,10 +210,8 @@ static int config_ipwireless(struct ipw_dev *ipw) ret = pcmcia_request_irq(link, &link->irq); - if (ret != 0) { - cs_error(link, RequestIRQ, ret); + if (ret != 0) goto exit; - } printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n", ipw->is_v2_card ? "V2/V3" : "V1"); @@ -263,10 +248,8 @@ static int config_ipwireless(struct ipw_dev *ipw) */ ret = pcmcia_request_configuration(link, &link->conf); - if (ret != 0) { - cs_error(link, RequestConfiguration, ret); + if (ret != 0) goto exit; - } link->dev_node = &ipw->nodes[0]; @@ -347,7 +330,6 @@ static int ipwireless_attach(struct pcmcia_device *link) ret = config_ipwireless(ipw); if (ret != 0) { - cs_error(link, RegisterClient, ret); ipwireless_detach(link); return ret; } diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 429b7313119..09b2590adb8 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -572,9 +572,6 @@ static int mgslpc_probe(struct pcmcia_device *link) /* Card has been inserted. */ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int mgslpc_ioprobe(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, cistpl_cftable_entry_t *dflt, @@ -598,15 +595,14 @@ static int mgslpc_ioprobe(struct pcmcia_device *p_dev, static int mgslpc_config(struct pcmcia_device *link) { MGSLPC_INFO *info = link->priv; - int last_fn = RequestIO; - int last_ret; + int ret; if (debug_level >= DEBUG_LEVEL_INFO) printk("mgslpc_config(0x%p)\n", link); - last_ret = pcmcia_loop_config(link, mgslpc_ioprobe, NULL); - if (last_ret != 0) - goto cs_failed; + ret = pcmcia_loop_config(link, mgslpc_ioprobe, NULL); + if (ret != 0) + goto failed; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; @@ -616,9 +612,13 @@ static int mgslpc_config(struct pcmcia_device *link) link->irq.Attributes |= IRQ_HANDLE_PRESENT; link->irq.Handler = mgslpc_isr; link->irq.Instance = info; - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; info->io_base = link->io.BasePort1; info->irq_level = link->irq.AssignedIRQ; @@ -638,8 +638,7 @@ static int mgslpc_config(struct pcmcia_device *link) printk("\n"); return 0; -cs_failed: - cs_error(link, last_fn, last_ret); +failed: mgslpc_release((u_long)link); return -ENODEV; } From e773cfe167c320d07b9423bc51fc4ab0221775a4 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 24 Oct 2009 15:50:13 +0200 Subject: [PATCH 094/298] pcmcia: use dynamic debug infrastructure, deprecate CS_CHECK (isdn) Convert PCMCIA drivers to use the dynamic debug infrastructure, instead of requiring manual settings of PCMCIA_DEBUG. Also, remove all usages of the CS_CHECK macro and replace them with proper Linux style calling and return value checking. The extra error reporting may be dropped, as the PCMCIA core already complains about any (non-driver-author) errors. CC: Karsten Keil Signed-off-by: Dominik Brodowski --- drivers/isdn/hardware/avm/avm_cs.c | 2 - drivers/isdn/hisax/avma1_cs.c | 26 ++----------- drivers/isdn/hisax/elsa_cs.c | 45 ++++++----------------- drivers/isdn/hisax/sedlbauer_cs.c | 59 +++++++++++------------------- drivers/isdn/hisax/teles_cs.c | 37 ++++--------------- 5 files changed, 43 insertions(+), 126 deletions(-) diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c index c72565520e4..d388eadb9fd 100644 --- a/drivers/isdn/hardware/avm/avm_cs.c +++ b/drivers/isdn/hardware/avm/avm_cs.c @@ -198,7 +198,6 @@ static int avmcs_config(struct pcmcia_device *link) */ i = pcmcia_request_irq(link, &link->irq); if (i != 0) { - cs_error(link, RequestIRQ, i); /* undo */ pcmcia_disable_device(link); break; @@ -209,7 +208,6 @@ static int avmcs_config(struct pcmcia_device *link) */ i = pcmcia_request_configuration(link, &link->conf); if (i != 0) { - cs_error(link, RequestConfiguration, i); pcmcia_disable_device(link); break; } diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c index 23560c897ec..6d963f9a09c 100644 --- a/drivers/isdn/hisax/avma1_cs.c +++ b/drivers/isdn/hisax/avma1_cs.c @@ -30,22 +30,6 @@ MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for AVM A1/Fritz!PCMCIA car MODULE_AUTHOR("Carsten Paeth"); MODULE_LICENSE("GPL"); -/* - All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If - you do not define PCMCIA_DEBUG at all, all the debug code will be - left out. If you compile with PCMCIA_DEBUG=0, the debug code will - be present but disabled -- but it can then be enabled for specific - modules at load time with a 'pc_debug=#' option to insmod. -*/ -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); -static char *version = -"avma1_cs.c 1.00 1998/01/23 10:00:00 (Carsten Paeth)"; -#else -#define DEBUG(n, args...) -#endif /*====================================================================*/ @@ -119,7 +103,7 @@ static int avma1cs_probe(struct pcmcia_device *p_dev) { local_info_t *local; - DEBUG(0, "avma1cs_attach()\n"); + dev_dbg(&p_dev->dev, "avma1cs_attach()\n"); /* Allocate space for private device-specific data */ local = kzalloc(sizeof(local_info_t), GFP_KERNEL); @@ -161,7 +145,7 @@ static int avma1cs_probe(struct pcmcia_device *p_dev) static void avma1cs_detach(struct pcmcia_device *link) { - DEBUG(0, "avma1cs_detach(0x%p)\n", link); + dev_dbg(&link->dev, "avma1cs_detach(0x%p)\n", link); avma1cs_release(link); kfree(link->priv); } /* avma1cs_detach */ @@ -203,7 +187,7 @@ static int avma1cs_config(struct pcmcia_device *link) dev = link->priv; - DEBUG(0, "avma1cs_config(0x%p)\n", link); + dev_dbg(&link->dev, "avma1cs_config(0x%p)\n", link); devname[0] = 0; if (link->prod_id[1]) @@ -218,7 +202,6 @@ static int avma1cs_config(struct pcmcia_device *link) */ i = pcmcia_request_irq(link, &link->irq); if (i != 0) { - cs_error(link, RequestIRQ, i); /* undo */ pcmcia_disable_device(link); break; @@ -229,7 +212,6 @@ static int avma1cs_config(struct pcmcia_device *link) */ i = pcmcia_request_configuration(link, &link->conf); if (i != 0) { - cs_error(link, RequestConfiguration, i); pcmcia_disable_device(link); break; } @@ -281,7 +263,7 @@ static void avma1cs_release(struct pcmcia_device *link) { local_info_t *local = link->priv; - DEBUG(0, "avma1cs_release(0x%p)\n", link); + dev_dbg(&link->dev, "avma1cs_release(0x%p)\n", link); /* now unregister function with hisax */ HiSax_closecard(local->node.minor); diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c index f4d0fe29bcf..cdcd2979fcd 100644 --- a/drivers/isdn/hisax/elsa_cs.c +++ b/drivers/isdn/hisax/elsa_cs.c @@ -57,23 +57,6 @@ MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Elsa PCM cards"); MODULE_AUTHOR("Klaus Lichtenwalder"); MODULE_LICENSE("Dual MPL/GPL"); -/* - All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If - you do not define PCMCIA_DEBUG at all, all the debug code will be - left out. If you compile with PCMCIA_DEBUG=0, the debug code will - be present but disabled -- but it can then be enabled for specific - modules at load time with a 'pc_debug=#' option to insmod. -*/ - -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); -static char *version = -"elsa_cs.c $Revision: 1.2.2.4 $ $Date: 2004/01/25 15:07:06 $ (K.Lichtenwalder)"; -#else -#define DEBUG(n, args...) -#endif /*====================================================================*/ @@ -142,7 +125,7 @@ static int elsa_cs_probe(struct pcmcia_device *link) { local_info_t *local; - DEBUG(0, "elsa_cs_attach()\n"); + dev_dbg(&link->dev, "elsa_cs_attach()\n"); /* Allocate space for private device-specific data */ local = kzalloc(sizeof(local_info_t), GFP_KERNEL); @@ -188,7 +171,7 @@ static void elsa_cs_detach(struct pcmcia_device *link) { local_info_t *info = link->priv; - DEBUG(0, "elsa_cs_detach(0x%p)\n", link); + dev_dbg(&link->dev, "elsa_cs_detach(0x%p)\n", link); info->busy = 1; elsa_cs_release(link); @@ -231,30 +214,25 @@ static int elsa_cs_configcheck(struct pcmcia_device *p_dev, static int elsa_cs_config(struct pcmcia_device *link) { local_info_t *dev; - int i, last_fn; + int i; IsdnCard_t icard; - DEBUG(0, "elsa_config(0x%p)\n", link); + dev_dbg(&link->dev, "elsa_config(0x%p)\n", link); dev = link->priv; i = pcmcia_loop_config(link, elsa_cs_configcheck, NULL); - if (i != 0) { - last_fn = RequestIO; - goto cs_failed; - } + if (i != 0) + goto failed; i = pcmcia_request_irq(link, &link->irq); if (i != 0) { link->irq.AssignedIRQ = 0; - last_fn = RequestIRQ; - goto cs_failed; + goto failed; } i = pcmcia_request_configuration(link, &link->conf); - if (i != 0) { - last_fn = RequestConfiguration; - goto cs_failed; - } + if (i != 0) + goto failed; /* At this point, the dev_node_t structure(s) should be initialized and arranged in a linked list at link->dev. *//* */ @@ -290,8 +268,7 @@ static int elsa_cs_config(struct pcmcia_device *link) ((local_info_t*)link->priv)->cardnr = i; return 0; -cs_failed: - cs_error(link, last_fn, i); +failed: elsa_cs_release(link); return -ENODEV; } /* elsa_cs_config */ @@ -308,7 +285,7 @@ static void elsa_cs_release(struct pcmcia_device *link) { local_info_t *local = link->priv; - DEBUG(0, "elsa_cs_release(0x%p)\n", link); + dev_dbg(&link->dev, "elsa_cs_release(0x%p)\n", link); if (local) { if (local->cardnr >= 0) { diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index 9a3c9f5e4fe..33d7530527c 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -57,24 +57,6 @@ MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Sedlbauer cards"); MODULE_AUTHOR("Marcus Niemann"); MODULE_LICENSE("Dual MPL/GPL"); -/* - All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If - you do not define PCMCIA_DEBUG at all, all the debug code will be - left out. If you compile with PCMCIA_DEBUG=0, the debug code will - be present but disabled -- but it can then be enabled for specific - modules at load time with a 'pc_debug=#' option to insmod. -*/ - -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); -static char *version = -"sedlbauer_cs.c 1.1a 2001/01/28 15:04:04 (M.Niemann)"; -#else -#define DEBUG(n, args...) -#endif - /*====================================================================*/ @@ -151,7 +133,7 @@ static int sedlbauer_probe(struct pcmcia_device *link) { local_info_t *local; - DEBUG(0, "sedlbauer_attach()\n"); + dev_dbg(&link->dev, "sedlbauer_attach()\n"); /* Allocate space for private device-specific data */ local = kzalloc(sizeof(local_info_t), GFP_KERNEL); @@ -198,7 +180,7 @@ static int sedlbauer_probe(struct pcmcia_device *link) static void sedlbauer_detach(struct pcmcia_device *link) { - DEBUG(0, "sedlbauer_detach(0x%p)\n", link); + dev_dbg(&link->dev, "sedlbauer_detach(0x%p)\n", link); ((local_info_t *)link->priv)->stop = 1; sedlbauer_release(link); @@ -214,9 +196,6 @@ static void sedlbauer_detach(struct pcmcia_device *link) device available to the system. ======================================================================*/ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int sedlbauer_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, cistpl_cftable_entry_t *dflt, @@ -309,10 +288,10 @@ static int sedlbauer_config(struct pcmcia_device *link) { local_info_t *dev = link->priv; win_req_t *req; - int last_fn, last_ret; + int ret; IsdnCard_t icard; - DEBUG(0, "sedlbauer_config(0x%p)\n", link); + dev_dbg(&link->dev, "sedlbauer_config(0x%p)\n", link); req = kzalloc(sizeof(win_req_t), GFP_KERNEL); if (!req) @@ -330,8 +309,8 @@ static int sedlbauer_config(struct pcmcia_device *link) these things without consulting the CIS, and most client drivers will only use the CIS to fill in implementation-defined details. */ - last_ret = pcmcia_loop_config(link, sedlbauer_config_check, req); - if (last_ret) + ret = pcmcia_loop_config(link, sedlbauer_config_check, req); + if (ret) goto failed; /* @@ -339,15 +318,20 @@ static int sedlbauer_config(struct pcmcia_device *link) handler to the interrupt, unless the 'Handler' member of the irq structure is initialized. */ - if (link->conf.Attributes & CONF_ENABLE_IRQ) - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + if (link->conf.Attributes & CONF_ENABLE_IRQ) { + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + } /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; /* At this point, the dev_node_t structure(s) need to be @@ -380,19 +364,18 @@ static int sedlbauer_config(struct pcmcia_device *link) icard.protocol = protocol; icard.typ = ISDN_CTYPE_SEDLBAUER_PCMCIA; - last_ret = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->stop), &icard); - if (last_ret < 0) { - printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d at i/o %#x\n", - last_ret, link->io.BasePort1); + ret = hisax_init_pcmcia(link, + &(((local_info_t *)link->priv)->stop), &icard); + if (ret < 0) { + printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d at i/o %#x\n", + ret, link->io.BasePort1); sedlbauer_release(link); return -ENODEV; } else - ((local_info_t*)link->priv)->cardnr = last_ret; + ((local_info_t *)link->priv)->cardnr = ret; return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: sedlbauer_release(link); return -ENODEV; @@ -410,7 +393,7 @@ failed: static void sedlbauer_release(struct pcmcia_device *link) { local_info_t *local = link->priv; - DEBUG(0, "sedlbauer_release(0x%p)\n", link); + dev_dbg(&link->dev, "sedlbauer_release(0x%p)\n", link); if (local) { if (local->cardnr >= 0) { diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index 623d111544d..7b11c15b3a9 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c @@ -38,23 +38,6 @@ MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Teles PCMCIA cards"); MODULE_AUTHOR("Christof Petig, christof.petig@wtal.de, Karsten Keil, kkeil@suse.de"); MODULE_LICENSE("GPL"); -/* - All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If - you do not define PCMCIA_DEBUG at all, all the debug code will be - left out. If you compile with PCMCIA_DEBUG=0, the debug code will - be present but disabled -- but it can then be enabled for specific - modules at load time with a 'pc_debug=#' option to insmod. -*/ - -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); -static char *version = -"teles_cs.c 2.10 2002/07/30 22:23:34 kkeil"; -#else -#define DEBUG(n, args...) -#endif /*====================================================================*/ @@ -133,7 +116,7 @@ static int teles_probe(struct pcmcia_device *link) { local_info_t *local; - DEBUG(0, "teles_attach()\n"); + dev_dbg(&link->dev, "teles_attach()\n"); /* Allocate space for private device-specific data */ local = kzalloc(sizeof(local_info_t), GFP_KERNEL); @@ -178,7 +161,7 @@ static void teles_detach(struct pcmcia_device *link) { local_info_t *info = link->priv; - DEBUG(0, "teles_detach(0x%p)\n", link); + dev_dbg(&link->dev, "teles_detach(0x%p)\n", link); info->busy = 1; teles_cs_release(link); @@ -221,30 +204,25 @@ static int teles_cs_configcheck(struct pcmcia_device *p_dev, static int teles_cs_config(struct pcmcia_device *link) { local_info_t *dev; - int i, last_fn; + int i; IsdnCard_t icard; - DEBUG(0, "teles_config(0x%p)\n", link); + dev_dbg(&link->dev, "teles_config(0x%p)\n", link); dev = link->priv; i = pcmcia_loop_config(link, teles_cs_configcheck, NULL); - if (i != 0) { - last_fn = RequestIO; + if (i != 0) goto cs_failed; - } i = pcmcia_request_irq(link, &link->irq); if (i != 0) { link->irq.AssignedIRQ = 0; - last_fn = RequestIRQ; goto cs_failed; } i = pcmcia_request_configuration(link, &link->conf); - if (i != 0) { - last_fn = RequestConfiguration; + if (i != 0) goto cs_failed; - } /* At this point, the dev_node_t structure(s) should be initialized and arranged in a linked list at link->dev. *//* */ @@ -283,7 +261,6 @@ static int teles_cs_config(struct pcmcia_device *link) return 0; cs_failed: - cs_error(link, last_fn, i); teles_cs_release(link); return -ENODEV; } /* teles_cs_config */ @@ -300,7 +277,7 @@ static void teles_cs_release(struct pcmcia_device *link) { local_info_t *local = link->priv; - DEBUG(0, "teles_cs_release(0x%p)\n", link); + dev_dbg(&link->dev, "teles_cs_release(0x%p)\n", link); if (local) { if (local->cardnr >= 0) { From dd0fab5b940c0b65f26ac5b01485bac1f690ace6 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 24 Oct 2009 15:51:05 +0200 Subject: [PATCH 095/298] pcmcia: use dynamic debug infrastructure, deprecate CS_CHECK (net) Convert PCMCIA drivers to use the dynamic debug infrastructure, instead of requiring manual settings of PCMCIA_DEBUG. Only some rare debug checks are now hidden behind "#ifdef DEBUG" or "#if 0". Also, remove all usages of the CS_CHECK macro and replace them with proper Linux style calling and return value checking. The extra error reporting may be dropped, as the PCMCIA core already complains about any (non-driver-author) errors. CC: netdev@vger.kernel.org Signed-off-by: Dominik Brodowski --- drivers/net/pcmcia/3c574_cs.c | 66 ++++++-------- drivers/net/pcmcia/3c589_cs.c | 75 ++++++---------- drivers/net/pcmcia/axnet_cs.c | 53 ++++------- drivers/net/pcmcia/com20020_cs.c | 55 +++++------- drivers/net/pcmcia/fmvj18x_cs.c | 109 ++++++++--------------- drivers/net/pcmcia/ibmtr_cs.c | 54 ++++++----- drivers/net/pcmcia/nmclan_cs.c | 148 +++++++++++++------------------ drivers/net/pcmcia/pcnet_cs.c | 67 ++++++-------- drivers/net/pcmcia/smc91c92_cs.c | 85 ++++++------------ drivers/net/pcmcia/xirc2ps_cs.c | 109 +++++++++-------------- 10 files changed, 315 insertions(+), 506 deletions(-) diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 6449290c62f..dbef5d9cc9d 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -118,14 +118,6 @@ INT_MODULE_PARM(full_duplex, 0); /* Autodetect link polarity reversal? */ INT_MODULE_PARM(auto_polarity, 1); -#ifdef PCMCIA_DEBUG -INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"3c574_cs.c 1.65ac1 2003/04/07 Donald Becker/David Hinds, becker@scyld.com.\n"; -#else -#define DEBUG(n, args...) -#endif /*====================================================================*/ @@ -278,7 +270,7 @@ static int tc574_probe(struct pcmcia_device *link) struct el3_private *lp; struct net_device *dev; - DEBUG(0, "3c574_attach()\n"); + dev_dbg(&link->dev, "3c574_attach()\n"); /* Create the PC card device object. */ dev = alloc_etherdev(sizeof(struct el3_private)); @@ -319,7 +311,7 @@ static void tc574_detach(struct pcmcia_device *link) { struct net_device *dev = link->priv; - DEBUG(0, "3c574_detach(0x%p)\n", link); + dev_dbg(&link->dev, "3c574_detach()\n"); if (link->dev_node) unregister_netdev(dev); @@ -335,16 +327,13 @@ static void tc574_detach(struct pcmcia_device *link) ethernet device available to the system. */ -#define CS_CHECK(fn, ret) \ - do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static const char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; static int tc574_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct el3_private *lp = netdev_priv(dev); - int last_fn, last_ret, i, j; + int ret, i, j; unsigned int ioaddr; __be16 *phys_addr; char *cardname; @@ -354,7 +343,7 @@ static int tc574_config(struct pcmcia_device *link) phys_addr = (__be16 *)dev->dev_addr; - DEBUG(0, "3c574_config(0x%p)\n", link); + dev_dbg(&link->dev, "3c574_config()\n"); link->io.IOAddrLines = 16; for (i = j = 0; j < 0x400; j += 0x20) { @@ -363,12 +352,16 @@ static int tc574_config(struct pcmcia_device *link) if (i == 0) break; } - if (i != 0) { - cs_error(link, RequestIO, i); + if (i != 0) + goto failed; + + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) goto failed; - } - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; @@ -433,7 +426,8 @@ static int tc574_config(struct pcmcia_device *link) mii_status = mdio_read(ioaddr, phy & 0x1f, 1); if (mii_status != 0xffff) { lp->phys = phy & 0x1f; - DEBUG(0, " MII transceiver at index %d, status %x.\n", + dev_dbg(&link->dev, " MII transceiver at " + "index %d, status %x.\n", phy, mii_status); if ((mii_status & 0x0040) == 0) mii_preamble_required = 1; @@ -476,8 +470,6 @@ static int tc574_config(struct pcmcia_device *link) return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: tc574_release(link); return -ENODEV; @@ -736,7 +728,7 @@ static int el3_open(struct net_device *dev) lp->media.expires = jiffies + HZ; add_timer(&lp->media); - DEBUG(2, "%s: opened, status %4.4x.\n", + dev_dbg(&link->dev, "%s: opened, status %4.4x.\n", dev->name, inw(dev->base_addr + EL3_STATUS)); return 0; @@ -770,7 +762,7 @@ static void pop_tx_status(struct net_device *dev) if (tx_status & 0x30) tc574_wait_for_completion(dev, TxReset); if (tx_status & 0x38) { - DEBUG(1, "%s: transmit error: status 0x%02x\n", + pr_debug("%s: transmit error: status 0x%02x\n", dev->name, tx_status); outw(TxEnable, ioaddr + EL3_CMD); dev->stats.tx_aborted_errors++; @@ -786,7 +778,7 @@ static netdev_tx_t el3_start_xmit(struct sk_buff *skb, struct el3_private *lp = netdev_priv(dev); unsigned long flags; - DEBUG(3, "%s: el3_start_xmit(length = %ld) called, " + pr_debug("%s: el3_start_xmit(length = %ld) called, " "status %4.4x.\n", dev->name, (long)skb->len, inw(ioaddr + EL3_STATUS)); @@ -825,7 +817,7 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id) return IRQ_NONE; ioaddr = dev->base_addr; - DEBUG(3, "%s: interrupt, status %4.4x.\n", + pr_debug("%s: interrupt, status %4.4x.\n", dev->name, inw(ioaddr + EL3_STATUS)); spin_lock(&lp->window_lock); @@ -834,7 +826,7 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id) (IntLatch | RxComplete | RxEarly | StatsFull)) { if (!netif_device_present(dev) || ((status & 0xe000) != 0x2000)) { - DEBUG(1, "%s: Interrupt from dead card\n", dev->name); + pr_debug("%s: Interrupt from dead card\n", dev->name); break; } @@ -844,7 +836,7 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id) work_budget = el3_rx(dev, work_budget); if (status & TxAvailable) { - DEBUG(3, " TX room bit was handled.\n"); + pr_debug(" TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); netif_wake_queue(dev); @@ -884,7 +876,7 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id) } if (--work_budget < 0) { - DEBUG(0, "%s: Too much work in interrupt, " + pr_debug("%s: Too much work in interrupt, " "status %4.4x.\n", dev->name, status); /* Clear all interrupts */ outw(AckIntr | 0xFF, ioaddr + EL3_CMD); @@ -894,7 +886,7 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id) outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); } - DEBUG(3, "%s: exiting interrupt, status %4.4x.\n", + pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, inw(ioaddr + EL3_STATUS)); spin_unlock(&lp->window_lock); @@ -1001,7 +993,7 @@ static void update_stats(struct net_device *dev) unsigned int ioaddr = dev->base_addr; u8 rx, tx, up; - DEBUG(2, "%s: updating the statistics.\n", dev->name); + pr_debug("%s: updating the statistics.\n", dev->name); if (inw(ioaddr+EL3_STATUS) == 0xffff) /* No card. */ return; @@ -1037,7 +1029,7 @@ static int el3_rx(struct net_device *dev, int worklimit) unsigned int ioaddr = dev->base_addr; short rx_status; - DEBUG(3, "%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n", + pr_debug("%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n", dev->name, inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus)); while (!((rx_status = inw(ioaddr + RxStatus)) & 0x8000) && worklimit > 0) { @@ -1059,7 +1051,7 @@ static int el3_rx(struct net_device *dev, int worklimit) skb = dev_alloc_skb(pkt_len+5); - DEBUG(3, " Receiving packet size %d status %4.4x.\n", + pr_debug(" Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); if (skb != NULL) { skb_reserve(skb, 2); @@ -1070,7 +1062,7 @@ static int el3_rx(struct net_device *dev, int worklimit) dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } else { - DEBUG(1, "%s: couldn't allocate a sk_buff of" + pr_debug("%s: couldn't allocate a sk_buff of" " size %d.\n", dev->name, pkt_len); dev->stats.rx_dropped++; } @@ -1099,7 +1091,7 @@ static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) struct mii_ioctl_data *data = if_mii(rq); int phy = lp->phys & 0x1f; - DEBUG(2, "%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n", + pr_debug("%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n", dev->name, rq->ifr_ifrn.ifrn_name, cmd, data->phy_id, data->reg_num, data->val_in, data->val_out); @@ -1176,7 +1168,7 @@ static int el3_close(struct net_device *dev) struct el3_private *lp = netdev_priv(dev); struct pcmcia_device *link = lp->p_dev; - DEBUG(2, "%s: shutting down ethercard.\n", dev->name); + dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name); if (pcmcia_dev_present(link)) { unsigned long flags; diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index fc6123ea6fa..6eac62b7143 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -130,14 +130,6 @@ MODULE_LICENSE("GPL"); /* Special hook for setting if_port when module is loaded */ INT_MODULE_PARM(if_port, 0); -#ifdef PCMCIA_DEBUG -INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -DRV_NAME ".c " DRV_VERSION " 2001/10/13 00:08:50 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif /*====================================================================*/ @@ -189,7 +181,7 @@ static int tc589_probe(struct pcmcia_device *link) struct el3_private *lp; struct net_device *dev; - DEBUG(0, "3c589_attach()\n"); + dev_dbg(&link->dev, "3c589_attach()\n"); /* Create new ethernet device */ dev = alloc_etherdev(sizeof(struct el3_private)); @@ -231,7 +223,7 @@ static void tc589_detach(struct pcmcia_device *link) { struct net_device *dev = link->priv; - DEBUG(0, "3c589_detach(0x%p)\n", link); + dev_dbg(&link->dev, "3c589_detach\n"); if (link->dev_node) unregister_netdev(dev); @@ -249,21 +241,18 @@ static void tc589_detach(struct pcmcia_device *link) ======================================================================*/ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int tc589_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct el3_private *lp = netdev_priv(dev); __be16 *phys_addr; - int last_fn, last_ret, i, j, multi = 0, fifo; + int ret, i, j, multi = 0, fifo; unsigned int ioaddr; char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; u8 *buf; size_t len; - DEBUG(0, "3c589_config(0x%p)\n", link); + dev_dbg(&link->dev, "3c589_config\n"); phys_addr = (__be16 *)dev->dev_addr; /* Is this a 3c562? */ @@ -281,12 +270,16 @@ static int tc589_config(struct pcmcia_device *link) if (i == 0) break; } - if (i != 0) { - cs_error(link, RequestIO, i); + if (i != 0) goto failed; - } - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; @@ -342,8 +335,6 @@ static int tc589_config(struct pcmcia_device *link) if_names[dev->if_port]); return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: tc589_release(link); return -ENODEV; @@ -506,24 +497,8 @@ static void netdev_get_drvinfo(struct net_device *dev, sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr); } -#ifdef PCMCIA_DEBUG -static u32 netdev_get_msglevel(struct net_device *dev) -{ - return pc_debug; -} - -static void netdev_set_msglevel(struct net_device *dev, u32 level) -{ - pc_debug = level; -} -#endif /* PCMCIA_DEBUG */ - static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, -#ifdef PCMCIA_DEBUG - .get_msglevel = netdev_get_msglevel, - .set_msglevel = netdev_set_msglevel, -#endif /* PCMCIA_DEBUG */ }; static int el3_config(struct net_device *dev, struct ifmap *map) @@ -558,7 +533,7 @@ static int el3_open(struct net_device *dev) lp->media.expires = jiffies + HZ; add_timer(&lp->media); - DEBUG(1, "%s: opened, status %4.4x.\n", + dev_dbg(&link->dev, "%s: opened, status %4.4x.\n", dev->name, inw(dev->base_addr + EL3_STATUS)); return 0; @@ -591,7 +566,7 @@ static void pop_tx_status(struct net_device *dev) if (tx_status & 0x30) tc589_wait_for_completion(dev, TxReset); if (tx_status & 0x38) { - DEBUG(1, "%s: transmit error: status 0x%02x\n", + pr_debug("%s: transmit error: status 0x%02x\n", dev->name, tx_status); outw(TxEnable, ioaddr + EL3_CMD); dev->stats.tx_aborted_errors++; @@ -607,7 +582,7 @@ static netdev_tx_t el3_start_xmit(struct sk_buff *skb, struct el3_private *priv = netdev_priv(dev); unsigned long flags; - DEBUG(3, "%s: el3_start_xmit(length = %ld) called, " + pr_debug("%s: el3_start_xmit(length = %ld) called, " "status %4.4x.\n", dev->name, (long)skb->len, inw(ioaddr + EL3_STATUS)); @@ -649,14 +624,14 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id) ioaddr = dev->base_addr; - DEBUG(3, "%s: interrupt, status %4.4x.\n", + pr_debug("%s: interrupt, status %4.4x.\n", dev->name, inw(ioaddr + EL3_STATUS)); spin_lock(&lp->lock); while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete | StatsFull)) { if ((status & 0xe000) != 0x2000) { - DEBUG(1, "%s: interrupt from dead card\n", dev->name); + pr_debug("%s: interrupt from dead card\n", dev->name); handled = 0; break; } @@ -665,7 +640,7 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id) el3_rx(dev); if (status & TxAvailable) { - DEBUG(3, " TX room bit was handled.\n"); + pr_debug(" TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); netif_wake_queue(dev); @@ -717,7 +692,7 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id) lp->last_irq = jiffies; spin_unlock(&lp->lock); - DEBUG(3, "%s: exiting interrupt, status %4.4x.\n", + pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, inw(ioaddr + EL3_STATUS)); return IRQ_RETVAL(handled); } @@ -828,7 +803,7 @@ static void update_stats(struct net_device *dev) { unsigned int ioaddr = dev->base_addr; - DEBUG(2, "%s: updating the statistics.\n", dev->name); + pr_debug("%s: updating the statistics.\n", dev->name); /* Turn off statistics updates while reading. */ outw(StatsDisable, ioaddr + EL3_CMD); /* Switch to the stats window, and read everything. */ @@ -856,7 +831,7 @@ static int el3_rx(struct net_device *dev) int worklimit = 32; short rx_status; - DEBUG(3, "%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n", + pr_debug("%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n", dev->name, inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS)); while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) && worklimit > 0) { @@ -878,7 +853,7 @@ static int el3_rx(struct net_device *dev) skb = dev_alloc_skb(pkt_len+5); - DEBUG(3, " Receiving packet size %d status %4.4x.\n", + pr_debug(" Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); if (skb != NULL) { skb_reserve(skb, 2); @@ -889,7 +864,7 @@ static int el3_rx(struct net_device *dev) dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } else { - DEBUG(1, "%s: couldn't allocate a sk_buff of" + pr_debug("%s: couldn't allocate a sk_buff of" " size %d.\n", dev->name, pkt_len); dev->stats.rx_dropped++; } @@ -930,7 +905,7 @@ static int el3_close(struct net_device *dev) struct pcmcia_device *link = lp->p_dev; unsigned int ioaddr = dev->base_addr; - DEBUG(1, "%s: shutting down ethercard.\n", dev->name); + dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name); if (pcmcia_dev_present(link)) { /* Turn off statistics ASAP. We update dev->stats below. */ diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 3131a59a8d3..5af2ccfdb52 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -75,16 +75,6 @@ MODULE_AUTHOR("David Hinds "); MODULE_DESCRIPTION("Asix AX88190 PCMCIA ethernet driver"); MODULE_LICENSE("GPL"); -#ifdef PCMCIA_DEBUG -#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0) - -INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"axnet_cs.c 1.28 2002/06/29 06:27:37 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif /*====================================================================*/ @@ -167,7 +157,7 @@ static int axnet_probe(struct pcmcia_device *link) struct net_device *dev; struct ei_device *ei_local; - DEBUG(0, "axnet_attach()\n"); + dev_dbg(&link->dev, "axnet_attach()\n"); dev = alloc_etherdev(sizeof(struct ei_device) + sizeof(axnet_dev_t)); if (!dev) @@ -205,7 +195,7 @@ static void axnet_detach(struct pcmcia_device *link) { struct net_device *dev = link->priv; - DEBUG(0, "axnet_detach(0x%p)\n", link); + dev_dbg(&link->dev, "axnet_detach(0x%p)\n", link); if (link->dev_node) unregister_netdev(dev); @@ -272,9 +262,6 @@ static int get_prom(struct pcmcia_device *link) ======================================================================*/ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int try_io_port(struct pcmcia_device *link) { int j, ret; @@ -341,26 +328,29 @@ static int axnet_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; axnet_dev_t *info = PRIV(dev); - int i, j, j2, last_ret, last_fn; + int i, j, j2, ret; - DEBUG(0, "axnet_config(0x%p)\n", link); + dev_dbg(&link->dev, "axnet_config(0x%p)\n", link); /* don't trust the CIS on this; Linksys got it wrong */ link->conf.Present = 0x63; - last_ret = pcmcia_loop_config(link, axnet_configcheck, NULL); - if (last_ret != 0) { - cs_error(link, RequestIO, last_ret); + ret = pcmcia_loop_config(link, axnet_configcheck, NULL); + if (ret != 0) goto failed; - } - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; if (link->io.NumPorts2 == 8) { link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; } - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; + dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; @@ -426,14 +416,12 @@ static int axnet_config(struct pcmcia_device *link) dev->base_addr, dev->irq, dev->dev_addr); if (info->phy_id != -1) { - DEBUG(0, " MII transceiver at index %d, status %x.\n", info->phy_id, j); + dev_dbg(&link->dev, " MII transceiver at index %d, status %x.\n", info->phy_id, j); } else { printk(KERN_NOTICE " No MII transceivers found!\n"); } return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: axnet_release(link); return -ENODEV; @@ -543,7 +531,7 @@ static int axnet_open(struct net_device *dev) struct pcmcia_device *link = info->p_dev; unsigned int nic_base = dev->base_addr; - DEBUG(2, "axnet_open('%s')\n", dev->name); + dev_dbg(&link->dev, "axnet_open('%s')\n", dev->name); if (!pcmcia_dev_present(link)) return -ENODEV; @@ -572,7 +560,7 @@ static int axnet_close(struct net_device *dev) axnet_dev_t *info = PRIV(dev); struct pcmcia_device *link = info->p_dev; - DEBUG(2, "axnet_close('%s')\n", dev->name); + dev_dbg(&link->dev, "axnet_close('%s')\n", dev->name); ax_close(dev); free_irq(dev->irq, dev); @@ -741,10 +729,8 @@ static void block_input(struct net_device *dev, int count, int xfer_count = count; char *buf = skb->data; -#ifdef PCMCIA_DEBUG if ((ei_debug > 4) && (count != 4)) - printk(KERN_DEBUG "%s: [bi=%d]\n", dev->name, count+4); -#endif + pr_debug("%s: [bi=%d]\n", dev->name, count+4); outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO); outb_p(ring_offset >> 8, nic_base + EN0_RSARHI); outb_p(E8390_RREAD+E8390_START, nic_base + AXNET_CMD); @@ -762,10 +748,7 @@ static void block_output(struct net_device *dev, int count, { unsigned int nic_base = dev->base_addr; -#ifdef PCMCIA_DEBUG - if (ei_debug > 4) - printk(KERN_DEBUG "%s: [bo=%d]\n", dev->name, count); -#endif + pr_debug("%s: [bo=%d]\n", dev->name, count); /* Round the count up for word writes. Do we need to do this? What effect will an odd byte count have on the 8390? diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index 7b5c77b7bd2..9a2e5006570 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -53,11 +53,7 @@ #define VERSION "arcnet: COM20020 PCMCIA support loaded.\n" -#ifdef PCMCIA_DEBUG - -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +#ifdef DEBUG static void regdump(struct net_device *dev) { @@ -92,7 +88,6 @@ static void regdump(struct net_device *dev) #else -#define DEBUG(n, args...) do { } while (0) static inline void regdump(struct net_device *dev) { } #endif @@ -144,7 +139,7 @@ static int com20020_probe(struct pcmcia_device *p_dev) struct net_device *dev; struct arcnet_local *lp; - DEBUG(0, "com20020_attach()\n"); + dev_dbg(&p_dev->dev, "com20020_attach()\n"); /* Create new network device */ info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL); @@ -198,12 +193,12 @@ static void com20020_detach(struct pcmcia_device *link) struct com20020_dev_t *info = link->priv; struct net_device *dev = info->dev; - DEBUG(1,"detach...\n"); + dev_dbg(&link->dev, "detach...\n"); - DEBUG(0, "com20020_detach(0x%p)\n", link); + dev_dbg(&link->dev, "com20020_detach\n"); if (link->dev_node) { - DEBUG(1,"unregister...\n"); + dev_dbg(&link->dev, "unregister...\n"); unregister_netdev(dev); @@ -218,16 +213,16 @@ static void com20020_detach(struct pcmcia_device *link) com20020_release(link); /* Unlink device structure, free bits */ - DEBUG(1,"unlinking...\n"); + dev_dbg(&link->dev, "unlinking...\n"); if (link->priv) { dev = info->dev; if (dev) { - DEBUG(1,"kfree...\n"); + dev_dbg(&link->dev, "kfree...\n"); free_netdev(dev); } - DEBUG(1,"kfree2...\n"); + dev_dbg(&link->dev, "kfree2...\n"); kfree(info); } @@ -241,25 +236,22 @@ static void com20020_detach(struct pcmcia_device *link) ======================================================================*/ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int com20020_config(struct pcmcia_device *link) { struct arcnet_local *lp; com20020_dev_t *info; struct net_device *dev; - int i, last_ret, last_fn; + int i, ret; int ioaddr; info = link->priv; dev = info->dev; - DEBUG(1,"config...\n"); + dev_dbg(&link->dev, "config...\n"); - DEBUG(0, "com20020_config(0x%p)\n", link); + dev_dbg(&link->dev, "com20020_config\n"); - DEBUG(1,"arcnet: baseport1 is %Xh\n", link->io.BasePort1); + dev_dbg(&link->dev, "baseport1 is %Xh\n", link->io.BasePort1); i = -ENODEV; if (!link->io.BasePort1) { @@ -276,26 +268,28 @@ static int com20020_config(struct pcmcia_device *link) if (i != 0) { - DEBUG(1,"arcnet: requestIO failed totally!\n"); + dev_dbg(&link->dev, "requestIO failed totally!\n"); goto failed; } ioaddr = dev->base_addr = link->io.BasePort1; - DEBUG(1,"arcnet: got ioaddr %Xh\n", ioaddr); + dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr); - DEBUG(1,"arcnet: request IRQ %d (%Xh/%Xh)\n", + dev_dbg(&link->dev, "request IRQ %d (%Xh/%Xh)\n", link->irq.AssignedIRQ, link->irq.IRQInfo1, link->irq.IRQInfo2); i = pcmcia_request_irq(link, &link->irq); if (i != 0) { - DEBUG(1,"arcnet: requestIRQ failed totally!\n"); + dev_dbg(&link->dev, "requestIRQ failed totally!\n"); goto failed; } dev->irq = link->irq.AssignedIRQ; - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; if (com20020_check(dev)) { @@ -313,21 +307,20 @@ static int com20020_config(struct pcmcia_device *link) i = com20020_found(dev, 0); /* calls register_netdev */ if (i != 0) { - DEBUG(1,KERN_NOTICE "com20020_cs: com20020_found() failed\n"); + dev_printk(KERN_NOTICE, &link->dev, + "com20020_cs: com20020_found() failed\n"); link->dev_node = NULL; goto failed; } strcpy(info->node.dev_name, dev->name); - DEBUG(1,KERN_INFO "%s: port %#3lx, irq %d\n", + dev_dbg(&link->dev,KERN_INFO "%s: port %#3lx, irq %d\n", dev->name, dev->base_addr, dev->irq); return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: - DEBUG(1,"com20020_config failed...\n"); + dev_dbg(&link->dev, "com20020_config failed...\n"); com20020_release(link); return -ENODEV; } /* com20020_config */ @@ -342,7 +335,7 @@ failed: static void com20020_release(struct pcmcia_device *link) { - DEBUG(0, "com20020_release(0x%p)\n", link); + dev_dbg(&link->dev, "com20020_release\n"); pcmcia_disable_device(link); } diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 5b73b11411c..fdec5c333a2 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -72,13 +72,6 @@ MODULE_LICENSE("GPL"); /* 0:4KB*2 TX buffer else:8KB*2 TX buffer */ INT_MODULE_PARM(sram_config, 0); -#ifdef PCMCIA_DEBUG -INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = DRV_NAME ".c " DRV_VERSION " 2002/03/23"; -#else -#define DEBUG(n, args...) -#endif /*====================================================================*/ /* @@ -245,7 +238,7 @@ static int fmvj18x_probe(struct pcmcia_device *link) local_info_t *lp; struct net_device *dev; - DEBUG(0, "fmvj18x_attach()\n"); + dev_dbg(&link->dev, "fmvj18x_attach()\n"); /* Make up a FMVJ18x specific data structure */ dev = alloc_etherdev(sizeof(local_info_t)); @@ -285,7 +278,7 @@ static void fmvj18x_detach(struct pcmcia_device *link) { struct net_device *dev = link->priv; - DEBUG(0, "fmvj18x_detach(0x%p)\n", link); + dev_dbg(&link->dev, "fmvj18x_detach\n"); if (link->dev_node) unregister_netdev(dev); @@ -297,9 +290,6 @@ static void fmvj18x_detach(struct pcmcia_device *link) /*====================================================================*/ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int mfc_try_io_port(struct pcmcia_device *link) { int i, ret; @@ -354,7 +344,7 @@ static int fmvj18x_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; local_info_t *lp = netdev_priv(dev); - int i, last_fn = RequestIO, last_ret = 0, ret; + int i, ret; unsigned int ioaddr; cardtype_t cardtype; char *card_name = "unknown"; @@ -362,16 +352,16 @@ static int fmvj18x_config(struct pcmcia_device *link) size_t len; u_char buggybuf[32]; - DEBUG(0, "fmvj18x_config(0x%p)\n", link); + dev_dbg(&link->dev, "fmvj18x_config\n"); len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf); kfree(buf); if (len) { /* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */ - last_ret = pcmcia_loop_config(link, fmvj18x_ioprobe, NULL); - if (last_ret != 0) - goto cs_failed; + ret = pcmcia_loop_config(link, fmvj18x_ioprobe, NULL); + if (ret != 0) + goto failed; switch (link->manf_id) { case MANFID_TDK: @@ -440,15 +430,22 @@ static int fmvj18x_config(struct pcmcia_device *link) link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT; ret = mfc_try_io_port(link); - if (ret != 0) goto cs_failed; + if (ret != 0) goto failed; } else if (cardtype == UNGERMANN) { ret = ungermann_try_io_port(link); - if (ret != 0) goto cs_failed; + if (ret != 0) goto failed; } else { - CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); + ret = pcmcia_request_io(link, &link->io); + if (ret) + goto failed; } - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; + dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; @@ -553,9 +550,6 @@ static int fmvj18x_config(struct pcmcia_device *link) return 0; -cs_failed: - /* All Card Services errors end up here */ - cs_error(link, last_fn, last_ret); failed: fmvj18x_release(link); return -ENODEV; @@ -574,10 +568,8 @@ static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id) req.Base = 0; req.Size = 0; req.AccessSpeed = 0; i = pcmcia_request_window(&link, &req, &link->win); - if (i != 0) { - cs_error(link, RequestWindow, i); + if (i != 0) return -1; - } base = ioremap(req.Base, req.Size); mem.Page = 0; @@ -608,8 +600,6 @@ static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id) iounmap(base); j = pcmcia_release_window(link->win); - if (j != 0) - cs_error(link, ReleaseWindow, j); return (i != 0x200) ? 0 : -1; } /* fmvj18x_get_hwinfo */ @@ -629,10 +619,8 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link) req.Base = 0; req.Size = 0; req.AccessSpeed = 0; i = pcmcia_request_window(&link, &req, &link->win); - if (i != 0) { - cs_error(link, RequestWindow, i); + if (i != 0) return -1; - } lp->base = ioremap(req.Base, req.Size); if (lp->base == NULL) { @@ -646,7 +634,6 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link) if (i != 0) { iounmap(lp->base); lp->base = NULL; - cs_error(link, MapMemPage, i); return -1; } @@ -673,15 +660,13 @@ static void fmvj18x_release(struct pcmcia_device *link) u_char __iomem *tmp; int j; - DEBUG(0, "fmvj18x_release(0x%p)\n", link); + dev_dbg(&link->dev, "fmvj18x_release\n"); if (lp->base != NULL) { tmp = lp->base; lp->base = NULL; /* set NULL before iounmap */ iounmap(tmp); j = pcmcia_release_window(link->win); - if (j != 0) - cs_error(link, ReleaseWindow, j); } pcmcia_disable_device(link); @@ -790,8 +775,8 @@ static irqreturn_t fjn_interrupt(int dummy, void *dev_id) outb(tx_stat, ioaddr + TX_STATUS); outb(rx_stat, ioaddr + RX_STATUS); - DEBUG(4, "%s: interrupt, rx_status %02x.\n", dev->name, rx_stat); - DEBUG(4, " tx_status %02x.\n", tx_stat); + pr_debug("%s: interrupt, rx_status %02x.\n", dev->name, rx_stat); + pr_debug(" tx_status %02x.\n", tx_stat); if (rx_stat || (inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) { /* there is packet(s) in rx buffer */ @@ -811,8 +796,8 @@ static irqreturn_t fjn_interrupt(int dummy, void *dev_id) } netif_wake_queue(dev); } - DEBUG(4, "%s: exiting interrupt,\n", dev->name); - DEBUG(4, " tx_status %02x, rx_status %02x.\n", tx_stat, rx_stat); + pr_debug("%s: exiting interrupt,\n", dev->name); + pr_debug(" tx_status %02x, rx_status %02x.\n", tx_stat, rx_stat); outb(D_TX_INTR, ioaddr + TX_INTR); outb(D_RX_INTR, ioaddr + RX_INTR); @@ -884,7 +869,7 @@ static netdev_tx_t fjn_start_xmit(struct sk_buff *skb, return NETDEV_TX_BUSY; } - DEBUG(4, "%s: Transmitting a packet of length %lu.\n", + pr_debug("%s: Transmitting a packet of length %lu.\n", dev->name, (unsigned long)skb->len); dev->stats.tx_bytes += skb->len; @@ -939,7 +924,7 @@ static void fjn_reset(struct net_device *dev) unsigned int ioaddr = dev->base_addr; int i; - DEBUG(4, "fjn_reset(%s) called.\n",dev->name); + pr_debug("fjn_reset(%s) called.\n",dev->name); /* Reset controller */ if( sram_config == 0 ) @@ -1017,13 +1002,13 @@ static void fjn_rx(struct net_device *dev) unsigned int ioaddr = dev->base_addr; int boguscount = 10; /* 5 -> 10: by agy 19940922 */ - DEBUG(4, "%s: in rx_packet(), rx_status %02x.\n", + pr_debug("%s: in rx_packet(), rx_status %02x.\n", dev->name, inb(ioaddr + RX_STATUS)); while ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) { u_short status = inw(ioaddr + DATAPORT); - DEBUG(4, "%s: Rxing packet mode %02x status %04x.\n", + pr_debug("%s: Rxing packet mode %02x status %04x.\n", dev->name, inb(ioaddr + RX_MODE), status); #ifndef final_version if (status == 0) { @@ -1063,16 +1048,14 @@ static void fjn_rx(struct net_device *dev) (pkt_len + 1) >> 1); skb->protocol = eth_type_trans(skb, dev); -#ifdef PCMCIA_DEBUG - if (pc_debug > 5) { + { int i; - printk(KERN_DEBUG "%s: Rxed packet of length %d: ", - dev->name, pkt_len); + pr_debug("%s: Rxed packet of length %d: ", + dev->name, pkt_len); for (i = 0; i < 14; i++) - printk(" %02x", skb->data[i]); - printk(".\n"); + pr_debug(" %02x", skb->data[i]); + pr_debug(".\n"); } -#endif netif_rx(skb); dev->stats.rx_packets++; @@ -1096,7 +1079,7 @@ static void fjn_rx(struct net_device *dev) } if (i > 0) - DEBUG(5, "%s: Exint Rx packet with mode %02x after " + pr_debug("%s: Exint Rx packet with mode %02x after " "%d ticks.\n", dev->name, inb(ioaddr + RX_MODE), i); } */ @@ -1114,24 +1097,8 @@ static void netdev_get_drvinfo(struct net_device *dev, sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr); } -#ifdef PCMCIA_DEBUG -static u32 netdev_get_msglevel(struct net_device *dev) -{ - return pc_debug; -} - -static void netdev_set_msglevel(struct net_device *dev, u32 level) -{ - pc_debug = level; -} -#endif /* PCMCIA_DEBUG */ - static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, -#ifdef PCMCIA_DEBUG - .get_msglevel = netdev_get_msglevel, - .set_msglevel = netdev_set_msglevel, -#endif /* PCMCIA_DEBUG */ }; static int fjn_config(struct net_device *dev, struct ifmap *map){ @@ -1143,7 +1110,7 @@ static int fjn_open(struct net_device *dev) struct local_info_t *lp = netdev_priv(dev); struct pcmcia_device *link = lp->p_dev; - DEBUG(4, "fjn_open('%s').\n", dev->name); + pr_debug("fjn_open('%s').\n", dev->name); if (!pcmcia_dev_present(link)) return -ENODEV; @@ -1169,7 +1136,7 @@ static int fjn_close(struct net_device *dev) struct pcmcia_device *link = lp->p_dev; unsigned int ioaddr = dev->base_addr; - DEBUG(4, "fjn_close('%s').\n", dev->name); + pr_debug("fjn_close('%s').\n", dev->name); lp->open_time = 0; netif_stop_queue(dev); diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index 06618af1a46..0d914f3b294 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -69,17 +69,6 @@ #define PCMCIA #include "../tokenring/ibmtr.c" -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"ibmtr_cs.c 1.10 1996/01/06 05:19:00 (Steve Kipisz)\n" -" 2.2.7 1999/05/03 12:00:00 (Mike Phillips)\n" -" 2.4.2 2001/30/28 Midnight (Burt Silverman)\n"; -#else -#define DEBUG(n, args...) -#endif /*====================================================================*/ @@ -143,7 +132,7 @@ static int __devinit ibmtr_attach(struct pcmcia_device *link) ibmtr_dev_t *info; struct net_device *dev; - DEBUG(0, "ibmtr_attach()\n"); + dev_dbg(&link->dev, "ibmtr_attach()\n"); /* Create new token-ring device */ info = kzalloc(sizeof(*info), GFP_KERNEL); @@ -190,7 +179,7 @@ static void ibmtr_detach(struct pcmcia_device *link) struct net_device *dev = info->dev; struct tok_info *ti = netdev_priv(dev); - DEBUG(0, "ibmtr_detach(0x%p)\n", link); + dev_dbg(&link->dev, "ibmtr_detach\n"); /* * When the card removal interrupt hits tok_interrupt(), @@ -217,9 +206,6 @@ static void ibmtr_detach(struct pcmcia_device *link) ======================================================================*/ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int __devinit ibmtr_config(struct pcmcia_device *link) { ibmtr_dev_t *info = link->priv; @@ -227,9 +213,9 @@ static int __devinit ibmtr_config(struct pcmcia_device *link) struct tok_info *ti = netdev_priv(dev); win_req_t req; memreq_t mem; - int i, last_ret, last_fn; + int i, ret; - DEBUG(0, "ibmtr_config(0x%p)\n", link); + dev_dbg(&link->dev, "ibmtr_config\n"); link->conf.ConfigIndex = 0x61; @@ -241,11 +227,15 @@ static int __devinit ibmtr_config(struct pcmcia_device *link) if (i != 0) { /* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */ link->io.BasePort1 = 0xA24; - CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); + ret = pcmcia_request_io(link, &link->io); + if (ret) + goto failed; } dev->base_addr = link->io.BasePort1; - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; dev->irq = link->irq.AssignedIRQ; ti->irq = link->irq.AssignedIRQ; ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq); @@ -256,11 +246,15 @@ static int __devinit ibmtr_config(struct pcmcia_device *link) req.Base = 0; req.Size = 0x2000; req.AccessSpeed = 250; - CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &link->win)); + ret = pcmcia_request_window(&link, &req, &link->win); + if (ret) + goto failed; mem.CardOffset = mmiobase; mem.Page = 0; - CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); + ret = pcmcia_map_mem_page(link->win, &mem); + if (ret) + goto failed; ti->mmio = ioremap(req.Base, req.Size); /* Allocate the SRAM memory window */ @@ -269,17 +263,23 @@ static int __devinit ibmtr_config(struct pcmcia_device *link) req.Base = 0; req.Size = sramsize * 1024; req.AccessSpeed = 250; - CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &info->sram_win_handle)); + ret = pcmcia_request_window(&link, &req, &info->sram_win_handle); + if (ret) + goto failed; mem.CardOffset = srambase; mem.Page = 0; - CS_CHECK(MapMemPage, pcmcia_map_mem_page(info->sram_win_handle, &mem)); + ret = pcmcia_map_mem_page(info->sram_win_handle, &mem); + if (ret) + goto failed; ti->sram_base = mem.CardOffset >> 12; ti->sram_virt = ioremap(req.Base, req.Size); ti->sram_phys = req.Base; - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; /* Set up the Token-Ring Controller Configuration Register and turn on the card. Check the "Local Area Network Credit Card @@ -305,8 +305,6 @@ static int __devinit ibmtr_config(struct pcmcia_device *link) dev->dev_addr); return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: ibmtr_release(link); return -ENODEV; @@ -325,7 +323,7 @@ static void ibmtr_release(struct pcmcia_device *link) ibmtr_dev_t *info = link->priv; struct net_device *dev = info->dev; - DEBUG(0, "ibmtr_release(0x%p)\n", link); + dev_dbg(&link->dev, "ibmtr_release\n"); if (link->win) { struct tok_info *ti = netdev_priv(dev); diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 4b96b356d97..a5363483ec6 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -381,13 +381,6 @@ typedef struct _mace_private { Private Global Variables ---------------------------------------------------------------------------- */ -#ifdef PCMCIA_DEBUG -static char rcsid[] = -"nmclan_cs.c,v 0.16 1995/07/01 06:42:17 rpao Exp rpao"; -static char *version = -DRV_NAME " " DRV_VERSION " (Roger C. Pao)"; -#endif - static const char *if_names[]={ "Auto", "10baseT", "BNC", }; @@ -406,12 +399,6 @@ MODULE_LICENSE("GPL"); /* 0=auto, 1=10baseT, 2 = 10base2, default=auto */ INT_MODULE_PARM(if_port, 0); -#ifdef PCMCIA_DEBUG -INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -#else -#define DEBUG(n, args...) -#endif /* ---------------------------------------------------------------------------- Function Prototypes @@ -462,8 +449,7 @@ static int nmclan_probe(struct pcmcia_device *link) mace_private *lp; struct net_device *dev; - DEBUG(0, "nmclan_attach()\n"); - DEBUG(1, "%s\n", rcsid); + dev_dbg(&link->dev, "nmclan_attach()\n"); /* Create new ethernet device */ dev = alloc_etherdev(sizeof(mace_private)); @@ -507,7 +493,7 @@ static void nmclan_detach(struct pcmcia_device *link) { struct net_device *dev = link->priv; - DEBUG(0, "nmclan_detach(0x%p)\n", link); + dev_dbg(&link->dev, "nmclan_detach\n"); if (link->dev_node) unregister_netdev(dev); @@ -654,23 +640,27 @@ nmclan_config ethernet device available to the system. ---------------------------------------------------------------------------- */ -#define CS_CHECK(fn, ret) \ - do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int nmclan_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; mace_private *lp = netdev_priv(dev); u8 *buf; size_t len; - int i, last_ret, last_fn; + int i, ret; unsigned int ioaddr; - DEBUG(0, "nmclan_config(0x%p)\n", link); + dev_dbg(&link->dev, "nmclan_config\n"); + + ret = pcmcia_request_io(link, &link->io); + if (ret) + goto failed; + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; - CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; @@ -692,7 +682,7 @@ static int nmclan_config(struct pcmcia_device *link) sig[0] = mace_read(lp, ioaddr, MACE_CHIPIDL); sig[1] = mace_read(lp, ioaddr, MACE_CHIPIDH); if ((sig[0] == 0x40) && ((sig[1] & 0x0F) == 0x09)) { - DEBUG(0, "nmclan_cs configured: mace id=%x %x\n", + dev_dbg(&link->dev, "nmclan_cs configured: mace id=%x %x\n", sig[0], sig[1]); } else { printk(KERN_NOTICE "nmclan_cs: mace id not found: %x %x should" @@ -728,8 +718,6 @@ static int nmclan_config(struct pcmcia_device *link) dev->dev_addr); return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: nmclan_release(link); return -ENODEV; @@ -743,7 +731,7 @@ nmclan_release ---------------------------------------------------------------------------- */ static void nmclan_release(struct pcmcia_device *link) { - DEBUG(0, "nmclan_release(0x%p)\n", link); + dev_dbg(&link->dev, "nmclan_release\n"); pcmcia_disable_device(link); } @@ -794,7 +782,7 @@ static void nmclan_reset(struct net_device *dev) /* Reset Xilinx */ reg.Action = CS_WRITE; reg.Offset = CISREG_COR; - DEBUG(1, "nmclan_reset: OrigCorValue=0x%lX, resetting...\n", + dev_dbg(&link->dev, "nmclan_reset: OrigCorValue=0x%lX, resetting...\n", OrigCorValue); reg.Value = COR_SOFT_RESET; pcmcia_access_configuration_register(link, ®); @@ -871,7 +859,7 @@ static int mace_close(struct net_device *dev) mace_private *lp = netdev_priv(dev); struct pcmcia_device *link = lp->p_dev; - DEBUG(2, "%s: shutting down ethercard.\n", dev->name); + dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name); /* Mask off all interrupts from the MACE chip. */ outb(0xFF, ioaddr + AM2150_MACE_BASE + MACE_IMR); @@ -890,24 +878,8 @@ static void netdev_get_drvinfo(struct net_device *dev, sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr); } -#ifdef PCMCIA_DEBUG -static u32 netdev_get_msglevel(struct net_device *dev) -{ - return pc_debug; -} - -static void netdev_set_msglevel(struct net_device *dev, u32 level) -{ - pc_debug = level; -} -#endif /* PCMCIA_DEBUG */ - static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, -#ifdef PCMCIA_DEBUG - .get_msglevel = netdev_get_msglevel, - .set_msglevel = netdev_set_msglevel, -#endif /* PCMCIA_DEBUG */ }; /* ---------------------------------------------------------------------------- @@ -945,7 +917,7 @@ static netdev_tx_t mace_start_xmit(struct sk_buff *skb, netif_stop_queue(dev); - DEBUG(3, "%s: mace_start_xmit(length = %ld) called.\n", + pr_debug("%s: mace_start_xmit(length = %ld) called.\n", dev->name, (long)skb->len); #if (!TX_INTERRUPTABLE) @@ -1007,7 +979,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id) int IntrCnt = MACE_MAX_IR_ITERATIONS; if (dev == NULL) { - DEBUG(2, "mace_interrupt(): irq 0x%X for unknown device.\n", + pr_debug("mace_interrupt(): irq 0x%X for unknown device.\n", irq); return IRQ_NONE; } @@ -1030,7 +1002,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id) } if (!netif_device_present(dev)) { - DEBUG(2, "%s: interrupt from dead card\n", dev->name); + pr_debug("%s: interrupt from dead card\n", dev->name); return IRQ_NONE; } @@ -1038,7 +1010,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id) /* WARNING: MACE_IR is a READ/CLEAR port! */ status = inb(ioaddr + AM2150_MACE_BASE + MACE_IR); - DEBUG(3, "mace_interrupt: irq 0x%X status 0x%X.\n", irq, status); + pr_debug("mace_interrupt: irq 0x%X status 0x%X.\n", irq, status); if (status & MACE_IR_RCVINT) { mace_rx(dev, MACE_MAX_RX_ITERATIONS); @@ -1157,7 +1129,7 @@ static int mace_rx(struct net_device *dev, unsigned char RxCnt) ) { rx_status = inw(ioaddr + AM2150_RCV); - DEBUG(3, "%s: in mace_rx(), framecnt 0x%X, rx_status" + pr_debug("%s: in mace_rx(), framecnt 0x%X, rx_status" " 0x%X.\n", dev->name, rx_framecnt, rx_status); if (rx_status & MACE_RCVFS_RCVSTS) { /* Error, update stats. */ @@ -1184,7 +1156,7 @@ static int mace_rx(struct net_device *dev, unsigned char RxCnt) lp->mace_stats.rfs_rcvcc += inb(ioaddr + AM2150_RCV); /* rcv collision count */ - DEBUG(3, " receiving packet size 0x%X rx_status" + pr_debug(" receiving packet size 0x%X rx_status" " 0x%X.\n", pkt_len, rx_status); skb = dev_alloc_skb(pkt_len+2); @@ -1203,7 +1175,7 @@ static int mace_rx(struct net_device *dev, unsigned char RxCnt) outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */ continue; } else { - DEBUG(1, "%s: couldn't allocate a sk_buff of size" + pr_debug("%s: couldn't allocate a sk_buff of size" " %d.\n", dev->name, pkt_len); lp->linux_stats.rx_dropped++; } @@ -1219,28 +1191,28 @@ pr_linux_stats ---------------------------------------------------------------------------- */ static void pr_linux_stats(struct net_device_stats *pstats) { - DEBUG(2, "pr_linux_stats\n"); - DEBUG(2, " rx_packets=%-7ld tx_packets=%ld\n", + pr_debug("pr_linux_stats\n"); + pr_debug(" rx_packets=%-7ld tx_packets=%ld\n", (long)pstats->rx_packets, (long)pstats->tx_packets); - DEBUG(2, " rx_errors=%-7ld tx_errors=%ld\n", + pr_debug(" rx_errors=%-7ld tx_errors=%ld\n", (long)pstats->rx_errors, (long)pstats->tx_errors); - DEBUG(2, " rx_dropped=%-7ld tx_dropped=%ld\n", + pr_debug(" rx_dropped=%-7ld tx_dropped=%ld\n", (long)pstats->rx_dropped, (long)pstats->tx_dropped); - DEBUG(2, " multicast=%-7ld collisions=%ld\n", + pr_debug(" multicast=%-7ld collisions=%ld\n", (long)pstats->multicast, (long)pstats->collisions); - DEBUG(2, " rx_length_errors=%-7ld rx_over_errors=%ld\n", + pr_debug(" rx_length_errors=%-7ld rx_over_errors=%ld\n", (long)pstats->rx_length_errors, (long)pstats->rx_over_errors); - DEBUG(2, " rx_crc_errors=%-7ld rx_frame_errors=%ld\n", + pr_debug(" rx_crc_errors=%-7ld rx_frame_errors=%ld\n", (long)pstats->rx_crc_errors, (long)pstats->rx_frame_errors); - DEBUG(2, " rx_fifo_errors=%-7ld rx_missed_errors=%ld\n", + pr_debug(" rx_fifo_errors=%-7ld rx_missed_errors=%ld\n", (long)pstats->rx_fifo_errors, (long)pstats->rx_missed_errors); - DEBUG(2, " tx_aborted_errors=%-7ld tx_carrier_errors=%ld\n", + pr_debug(" tx_aborted_errors=%-7ld tx_carrier_errors=%ld\n", (long)pstats->tx_aborted_errors, (long)pstats->tx_carrier_errors); - DEBUG(2, " tx_fifo_errors=%-7ld tx_heartbeat_errors=%ld\n", + pr_debug(" tx_fifo_errors=%-7ld tx_heartbeat_errors=%ld\n", (long)pstats->tx_fifo_errors, (long)pstats->tx_heartbeat_errors); - DEBUG(2, " tx_window_errors=%ld\n", + pr_debug(" tx_window_errors=%ld\n", (long)pstats->tx_window_errors); } /* pr_linux_stats */ @@ -1249,48 +1221,48 @@ pr_mace_stats ---------------------------------------------------------------------------- */ static void pr_mace_stats(mace_statistics *pstats) { - DEBUG(2, "pr_mace_stats\n"); + pr_debug("pr_mace_stats\n"); - DEBUG(2, " xmtsv=%-7d uflo=%d\n", + pr_debug(" xmtsv=%-7d uflo=%d\n", pstats->xmtsv, pstats->uflo); - DEBUG(2, " lcol=%-7d more=%d\n", + pr_debug(" lcol=%-7d more=%d\n", pstats->lcol, pstats->more); - DEBUG(2, " one=%-7d defer=%d\n", + pr_debug(" one=%-7d defer=%d\n", pstats->one, pstats->defer); - DEBUG(2, " lcar=%-7d rtry=%d\n", + pr_debug(" lcar=%-7d rtry=%d\n", pstats->lcar, pstats->rtry); /* MACE_XMTRC */ - DEBUG(2, " exdef=%-7d xmtrc=%d\n", + pr_debug(" exdef=%-7d xmtrc=%d\n", pstats->exdef, pstats->xmtrc); /* RFS1--Receive Status (RCVSTS) */ - DEBUG(2, " oflo=%-7d clsn=%d\n", + pr_debug(" oflo=%-7d clsn=%d\n", pstats->oflo, pstats->clsn); - DEBUG(2, " fram=%-7d fcs=%d\n", + pr_debug(" fram=%-7d fcs=%d\n", pstats->fram, pstats->fcs); /* RFS2--Runt Packet Count (RNTPC) */ /* RFS3--Receive Collision Count (RCVCC) */ - DEBUG(2, " rfs_rntpc=%-7d rfs_rcvcc=%d\n", + pr_debug(" rfs_rntpc=%-7d rfs_rcvcc=%d\n", pstats->rfs_rntpc, pstats->rfs_rcvcc); /* MACE_IR */ - DEBUG(2, " jab=%-7d babl=%d\n", + pr_debug(" jab=%-7d babl=%d\n", pstats->jab, pstats->babl); - DEBUG(2, " cerr=%-7d rcvcco=%d\n", + pr_debug(" cerr=%-7d rcvcco=%d\n", pstats->cerr, pstats->rcvcco); - DEBUG(2, " rntpco=%-7d mpco=%d\n", + pr_debug(" rntpco=%-7d mpco=%d\n", pstats->rntpco, pstats->mpco); /* MACE_MPC */ - DEBUG(2, " mpc=%d\n", pstats->mpc); + pr_debug(" mpc=%d\n", pstats->mpc); /* MACE_RNTPC */ - DEBUG(2, " rntpc=%d\n", pstats->rntpc); + pr_debug(" rntpc=%d\n", pstats->rntpc); /* MACE_RCVCC */ - DEBUG(2, " rcvcc=%d\n", pstats->rcvcc); + pr_debug(" rcvcc=%d\n", pstats->rcvcc); } /* pr_mace_stats */ @@ -1359,7 +1331,7 @@ static struct net_device_stats *mace_get_stats(struct net_device *dev) update_stats(dev->base_addr, dev); - DEBUG(1, "%s: updating the statistics.\n", dev->name); + pr_debug("%s: updating the statistics.\n", dev->name); pr_linux_stats(&lp->linux_stats); pr_mace_stats(&lp->mace_stats); @@ -1426,7 +1398,7 @@ static void BuildLAF(int *ladrf, int *adr) ladrf[byte] |= (1 << (hashcode & 7)); #ifdef PCMCIA_DEBUG - if (pc_debug > 2) + if (0) printk(KERN_DEBUG " adr =%pM\n", adr); printk(KERN_DEBUG " hashcode = %d(decimal), ladrf[0:63] =", hashcode); for (i = 0; i < 8; i++) @@ -1453,12 +1425,12 @@ static void restore_multicast_list(struct net_device *dev) unsigned int ioaddr = dev->base_addr; int i; - DEBUG(2, "%s: restoring Rx mode to %d addresses.\n", + pr_debug("%s: restoring Rx mode to %d addresses.\n", dev->name, num_addrs); if (num_addrs > 0) { - DEBUG(1, "Attempt to restore multicast list detected.\n"); + pr_debug("Attempt to restore multicast list detected.\n"); mace_write(lp, ioaddr, MACE_IAC, MACE_IAC_ADDRCHG | MACE_IAC_LOGADDR); /* Poll ADDRCHG bit */ @@ -1510,11 +1482,11 @@ static void set_multicast_list(struct net_device *dev) struct dev_mc_list *dmi = dev->mc_list; #ifdef PCMCIA_DEBUG - if (pc_debug > 1) { + { static int old; if (dev->mc_count != old) { old = dev->mc_count; - DEBUG(0, "%s: setting Rx mode to %d addresses.\n", + pr_debug("%s: setting Rx mode to %d addresses.\n", dev->name, old); } } @@ -1545,7 +1517,7 @@ static void restore_multicast_list(struct net_device *dev) unsigned int ioaddr = dev->base_addr; mace_private *lp = netdev_priv(dev); - DEBUG(2, "%s: restoring Rx mode to %d addresses.\n", dev->name, + pr_debug("%s: restoring Rx mode to %d addresses.\n", dev->name, lp->multicast_num_addrs); if (dev->flags & IFF_PROMISC) { @@ -1566,11 +1538,11 @@ static void set_multicast_list(struct net_device *dev) mace_private *lp = netdev_priv(dev); #ifdef PCMCIA_DEBUG - if (pc_debug > 1) { + { static int old; if (dev->mc_count != old) { old = dev->mc_count; - DEBUG(0, "%s: setting Rx mode to %d addresses.\n", + pr_debug("%s: setting Rx mode to %d addresses.\n", dev->name, old); } } diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index bd3447f0490..80ab9de1c4d 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -71,15 +71,6 @@ static const char *if_names[] = { "auto", "10baseT", "10base2"}; -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"pcnet_cs.c 1.153 2003/11/09 18:53:09 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif /*====================================================================*/ @@ -265,7 +256,7 @@ static int pcnet_probe(struct pcmcia_device *link) pcnet_dev_t *info; struct net_device *dev; - DEBUG(0, "pcnet_attach()\n"); + dev_dbg(&link->dev, "pcnet_attach()\n"); /* Create new ethernet device */ dev = __alloc_ei_netdev(sizeof(pcnet_dev_t)); @@ -297,7 +288,7 @@ static void pcnet_detach(struct pcmcia_device *link) { struct net_device *dev = link->priv; - DEBUG(0, "pcnet_detach(0x%p)\n", link); + dev_dbg(&link->dev, "pcnet_detach\n"); if (link->dev_node) unregister_netdev(dev); @@ -327,10 +318,8 @@ static hw_info_t *get_hwinfo(struct pcmcia_device *link) req.Base = 0; req.Size = 0; req.AccessSpeed = 0; i = pcmcia_request_window(&link, &req, &link->win); - if (i != 0) { - cs_error(link, RequestWindow, i); + if (i != 0) return NULL; - } virt = ioremap(req.Base, req.Size); mem.Page = 0; @@ -349,8 +338,6 @@ static hw_info_t *get_hwinfo(struct pcmcia_device *link) iounmap(virt); j = pcmcia_release_window(link->win); - if (j != 0) - cs_error(link, ReleaseWindow, j); return (i < NR_INFO) ? hw_info+i : NULL; } /* get_hwinfo */ @@ -495,9 +482,6 @@ static hw_info_t *get_hwired(struct pcmcia_device *link) ======================================================================*/ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int try_io_port(struct pcmcia_device *link) { int j, ret; @@ -567,19 +551,19 @@ static int pcnet_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; pcnet_dev_t *info = PRIV(dev); - int last_ret, last_fn, start_pg, stop_pg, cm_offset; + int ret, start_pg, stop_pg, cm_offset; int has_shmem = 0; hw_info_t *local_hw_info; - DEBUG(0, "pcnet_config(0x%p)\n", link); + dev_dbg(&link->dev, "pcnet_config\n"); - last_ret = pcmcia_loop_config(link, pcnet_confcheck, &has_shmem); - if (last_ret) { - cs_error(link, RequestIO, last_ret); + ret = pcmcia_loop_config(link, pcnet_confcheck, &has_shmem); + if (ret) goto failed; - } - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; if (link->io.NumPorts2 == 8) { link->conf.Attributes |= CONF_ENABLE_SPKR; @@ -589,7 +573,9 @@ static int pcnet_config(struct pcmcia_device *link) (link->card_id == PRODID_IBM_HOME_AND_AWAY)) link->conf.ConfigIndex |= 0x10; - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; if (info->flags & HAS_MISC_REG) { @@ -687,8 +673,6 @@ static int pcnet_config(struct pcmcia_device *link) printk(" hw_addr %pM\n", dev->dev_addr); return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: pcnet_release(link); return -ENODEV; @@ -706,7 +690,7 @@ static void pcnet_release(struct pcmcia_device *link) { pcnet_dev_t *info = PRIV(link->priv); - DEBUG(0, "pcnet_release(0x%p)\n", link); + dev_dbg(&link->dev, "pcnet_release\n"); if (info->flags & USE_SHMEM) iounmap(info->base); @@ -960,7 +944,7 @@ static void mii_phy_probe(struct net_device *dev) phyid = tmp << 16; phyid |= mdio_read(mii_addr, i, MII_PHYID_REG2); phyid &= MII_PHYID_REV_MASK; - DEBUG(0, "%s: MII at %d is 0x%08x\n", dev->name, i, phyid); + pr_debug("%s: MII at %d is 0x%08x\n", dev->name, i, phyid); if (phyid == AM79C9XX_HOME_PHY) { info->pna_phy = i; } else if (phyid != AM79C9XX_ETH_PHY) { @@ -976,7 +960,7 @@ static int pcnet_open(struct net_device *dev) struct pcmcia_device *link = info->p_dev; unsigned int nic_base = dev->base_addr; - DEBUG(2, "pcnet_open('%s')\n", dev->name); + dev_dbg(&link->dev, "pcnet_open('%s')\n", dev->name); if (!pcmcia_dev_present(link)) return -ENODEV; @@ -1008,7 +992,7 @@ static int pcnet_close(struct net_device *dev) pcnet_dev_t *info = PRIV(dev); struct pcmcia_device *link = info->p_dev; - DEBUG(2, "pcnet_close('%s')\n", dev->name); + dev_dbg(&link->dev, "pcnet_close('%s')\n", dev->name); ei_close(dev); free_irq(dev->irq, dev); @@ -1251,10 +1235,8 @@ static void dma_block_input(struct net_device *dev, int count, int xfer_count = count; char *buf = skb->data; -#ifdef PCMCIA_DEBUG if ((ei_debug > 4) && (count != 4)) - printk(KERN_DEBUG "%s: [bi=%d]\n", dev->name, count+4); -#endif + pr_debug("%s: [bi=%d]\n", dev->name, count+4); if (ei_status.dmaing) { printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input." "[DMAstat:%1x][irqlock:%1x]\n", @@ -1495,7 +1477,7 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg, pcnet_dev_t *info = PRIV(dev); win_req_t req; memreq_t mem; - int i, window_size, offset, last_ret, last_fn; + int i, window_size, offset, ret; window_size = (stop_pg - start_pg) << 8; if (window_size > 32 * 1024) @@ -1509,13 +1491,17 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg, req.Attributes |= WIN_USE_WAIT; req.Base = 0; req.Size = window_size; req.AccessSpeed = mem_speed; - CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &link->win)); + ret = pcmcia_request_window(&link, &req, &link->win); + if (ret) + goto failed; mem.CardOffset = (start_pg << 8) + cm_offset; offset = mem.CardOffset % window_size; mem.CardOffset -= offset; mem.Page = 0; - CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); + ret = pcmcia_map_mem_page(link->win, &mem); + if (ret) + goto failed; /* Try scribbling on the buffer */ info->base = ioremap(req.Base, window_size); @@ -1549,8 +1535,6 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg, info->flags |= USE_SHMEM; return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: return 1; } @@ -1788,7 +1772,6 @@ static int __init init_pcnet_cs(void) static void __exit exit_pcnet_cs(void) { - DEBUG(0, "pcnet_cs: unloading\n"); pcmcia_unregister_driver(&pcnet_driver); } diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index df92bcde9bc..580ec444a65 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -79,14 +79,6 @@ MODULE_FIRMWARE(FIRMWARE_NAME); */ INT_MODULE_PARM(if_port, 0); -#ifdef PCMCIA_DEBUG -INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); -static const char *version = -"smc91c92_cs.c 1.123 2006/11/09 Donald Becker, becker@scyld.com.\n"; -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -#else -#define DEBUG(n, args...) -#endif #define DRV_NAME "smc91c92_cs" #define DRV_VERSION "1.123" @@ -323,7 +315,7 @@ static int smc91c92_probe(struct pcmcia_device *link) struct smc_private *smc; struct net_device *dev; - DEBUG(0, "smc91c92_attach()\n"); + dev_dbg(&link->dev, "smc91c92_attach()\n"); /* Create new ethernet device */ dev = alloc_etherdev(sizeof(struct smc_private)); @@ -371,7 +363,7 @@ static void smc91c92_detach(struct pcmcia_device *link) { struct net_device *dev = link->priv; - DEBUG(0, "smc91c92_detach(0x%p)\n", link); + dev_dbg(&link->dev, "smc91c92_detach\n"); if (link->dev_node) unregister_netdev(dev); @@ -746,7 +738,7 @@ static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid) set_bits(0x300, link->io.BasePort1 + OSITECH_AUI_PWR); /* Now, turn on the interrupt for both card functions */ set_bits(0x300, link->io.BasePort1 + OSITECH_RESET_ISR); - DEBUG(2, "AUI/PWR: %4.4x RESET/ISR: %4.4x\n", + dev_dbg(&link->dev, "AUI/PWR: %4.4x RESET/ISR: %4.4x\n", inw(link->io.BasePort1 + OSITECH_AUI_PWR), inw(link->io.BasePort1 + OSITECH_RESET_ISR)); } @@ -860,12 +852,6 @@ static int check_sig(struct pcmcia_device *link) ======================================================================*/ -#define CS_EXIT_TEST(ret, svc, label) \ -if (ret != 0) { \ - cs_error(link, svc, ret); \ - goto label; \ -} - static int smc91c92_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; @@ -875,7 +861,7 @@ static int smc91c92_config(struct pcmcia_device *link) unsigned int ioaddr; u_long mir; - DEBUG(0, "smc91c92_config(0x%p)\n", link); + dev_dbg(&link->dev, "smc91c92_config\n"); smc->manfid = link->manf_id; smc->cardid = link->card_id; @@ -891,12 +877,15 @@ static int smc91c92_config(struct pcmcia_device *link) } else { i = smc_config(link); } - CS_EXIT_TEST(i, RequestIO, config_failed); + if (i) + goto config_failed; i = pcmcia_request_irq(link, &link->irq); - CS_EXIT_TEST(i, RequestIRQ, config_failed); + if (i) + goto config_failed; i = pcmcia_request_configuration(link, &link->conf); - CS_EXIT_TEST(i, RequestConfiguration, config_failed); + if (i) + goto config_failed; if (smc->manfid == MANFID_MOTOROLA) mot_config(link); @@ -1001,7 +990,7 @@ static int smc91c92_config(struct pcmcia_device *link) if (smc->cfg & CFG_MII_SELECT) { if (smc->mii_if.phy_id != -1) { - DEBUG(0, " MII transceiver at index %d, status %x.\n", + dev_dbg(&link->dev, " MII transceiver at index %d, status %x.\n", smc->mii_if.phy_id, j); } else { printk(KERN_NOTICE " No MII transceivers found!\n"); @@ -1011,7 +1000,7 @@ static int smc91c92_config(struct pcmcia_device *link) config_undo: unregister_netdev(dev); -config_failed: /* CS_EXIT_TEST() calls jump to here... */ +config_failed: smc91c92_release(link); return -ENODEV; } /* smc91c92_config */ @@ -1026,7 +1015,7 @@ config_failed: /* CS_EXIT_TEST() calls jump to here... */ static void smc91c92_release(struct pcmcia_device *link) { - DEBUG(0, "smc91c92_release(0x%p)\n", link); + dev_dbg(&link->dev, "smc91c92_release\n"); if (link->win) { struct net_device *dev = link->priv; struct smc_private *smc = netdev_priv(dev); @@ -1123,10 +1112,10 @@ static int smc_open(struct net_device *dev) struct smc_private *smc = netdev_priv(dev); struct pcmcia_device *link = smc->p_dev; -#ifdef PCMCIA_DEBUG - DEBUG(0, "%s: smc_open(%p), ID/Window %4.4x.\n", + dev_dbg(&link->dev, "%s: smc_open(%p), ID/Window %4.4x.\n", dev->name, dev, inw(dev->base_addr + BANK_SELECT)); - if (pc_debug > 1) smc_dump(dev); +#ifdef PCMCIA_DEBUG + smc_dump(dev); #endif /* Check that the PCMCIA card is still here. */ @@ -1161,7 +1150,7 @@ static int smc_close(struct net_device *dev) struct pcmcia_device *link = smc->p_dev; unsigned int ioaddr = dev->base_addr; - DEBUG(0, "%s: smc_close(), status %4.4x.\n", + dev_dbg(&link->dev, "%s: smc_close(), status %4.4x.\n", dev->name, inw(ioaddr + BANK_SELECT)); netif_stop_queue(dev); @@ -1228,7 +1217,7 @@ static void smc_hardware_send_packet(struct net_device * dev) u_char *buf = skb->data; u_int length = skb->len; /* The chip will pad to ethernet min. */ - DEBUG(2, "%s: Trying to xmit packet of length %d.\n", + pr_debug("%s: Trying to xmit packet of length %d.\n", dev->name, length); /* send the packet length: +6 for status word, length, and ctl */ @@ -1283,7 +1272,7 @@ static netdev_tx_t smc_start_xmit(struct sk_buff *skb, netif_stop_queue(dev); - DEBUG(2, "%s: smc_start_xmit(length = %d) called," + pr_debug("%s: smc_start_xmit(length = %d) called," " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2)); if (smc->saved_skb) { @@ -1330,7 +1319,7 @@ static netdev_tx_t smc_start_xmit(struct sk_buff *skb, } /* Otherwise defer until the Tx-space-allocated interrupt. */ - DEBUG(2, "%s: memory allocation deferred.\n", dev->name); + pr_debug("%s: memory allocation deferred.\n", dev->name); outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT); spin_unlock_irqrestore(&smc->lock, flags); @@ -1395,7 +1384,7 @@ static void smc_eph_irq(struct net_device *dev) SMC_SELECT_BANK(0); ephs = inw(ioaddr + EPH); - DEBUG(2, "%s: Ethernet protocol handler interrupt, status" + pr_debug("%s: Ethernet protocol handler interrupt, status" " %4.4x.\n", dev->name, ephs); /* Could be a counter roll-over warning: update stats. */ card_stats = inw(ioaddr + COUNTER); @@ -1435,7 +1424,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id) ioaddr = dev->base_addr; - DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name, + pr_debug("%s: SMC91c92 interrupt %d at %#x.\n", dev->name, irq, ioaddr); spin_lock(&smc->lock); @@ -1444,7 +1433,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id) if ((saved_bank & 0xff00) != 0x3300) { /* The device does not exist -- the card could be off-line, or maybe it has been ejected. */ - DEBUG(1, "%s: SMC91c92 interrupt %d for non-existent" + pr_debug("%s: SMC91c92 interrupt %d for non-existent" "/ejected device.\n", dev->name, irq); handled = 0; goto irq_done; @@ -1458,7 +1447,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id) do { /* read the status flag, and mask it */ status = inw(ioaddr + INTERRUPT) & 0xff; - DEBUG(3, "%s: Status is %#2.2x (mask %#2.2x).\n", dev->name, + pr_debug("%s: Status is %#2.2x (mask %#2.2x).\n", dev->name, status, mask); if ((status & mask) == 0) { if (bogus_cnt == INTR_WORK) @@ -1503,7 +1492,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id) smc_eph_irq(dev); } while (--bogus_cnt); - DEBUG(3, " Restoring saved registers mask %2.2x bank %4.4x" + pr_debug(" Restoring saved registers mask %2.2x bank %4.4x" " pointer %4.4x.\n", mask, saved_bank, saved_pointer); /* restore state register */ @@ -1511,7 +1500,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id) outw(saved_pointer, ioaddr + POINTER); SMC_SELECT_BANK(saved_bank); - DEBUG(3, "%s: Exiting interrupt IRQ%d.\n", dev->name, irq); + pr_debug("%s: Exiting interrupt IRQ%d.\n", dev->name, irq); irq_done: @@ -1562,7 +1551,7 @@ static void smc_rx(struct net_device *dev) rx_status = inw(ioaddr + DATA_1); packet_length = inw(ioaddr + DATA_1) & 0x07ff; - DEBUG(2, "%s: Receive status %4.4x length %d.\n", + pr_debug("%s: Receive status %4.4x length %d.\n", dev->name, rx_status, packet_length); if (!(rx_status & RS_ERRORS)) { @@ -1573,7 +1562,7 @@ static void smc_rx(struct net_device *dev) skb = dev_alloc_skb(packet_length+2); if (skb == NULL) { - DEBUG(1, "%s: Low memory, packet dropped.\n", dev->name); + pr_debug("%s: Low memory, packet dropped.\n", dev->name); dev->stats.rx_dropped++; outw(MC_RELEASE, ioaddr + MMU_CMD); return; @@ -1733,7 +1722,7 @@ static void smc_reset(struct net_device *dev) struct smc_private *smc = netdev_priv(dev); int i; - DEBUG(0, "%s: smc91c92 reset called.\n", dev->name); + pr_debug("%s: smc91c92 reset called.\n", dev->name); /* The first interaction must be a write to bring the chip out of sleep mode. */ @@ -2050,18 +2039,6 @@ static u32 smc_get_link(struct net_device *dev) return ret; } -#ifdef PCMCIA_DEBUG -static u32 smc_get_msglevel(struct net_device *dev) -{ - return pc_debug; -} - -static void smc_set_msglevel(struct net_device *dev, u32 val) -{ - pc_debug = val; -} -#endif - static int smc_nway_reset(struct net_device *dev) { struct smc_private *smc = netdev_priv(dev); @@ -2085,10 +2062,6 @@ static const struct ethtool_ops ethtool_ops = { .get_settings = smc_get_settings, .set_settings = smc_set_settings, .get_link = smc_get_link, -#ifdef PCMCIA_DEBUG - .get_msglevel = smc_get_msglevel, - .set_msglevel = smc_set_msglevel, -#endif .nway_reset = smc_nway_reset, }; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 925e8509662..fbf92653928 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -211,20 +211,6 @@ enum xirc_cmd { /* Commands */ static const char *if_names[] = { "Auto", "10BaseT", "10Base2", "AUI", "100BaseT" }; -/**************** - * All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If - * you do not define PCMCIA_DEBUG at all, all the debug code will be - * left out. If you compile with PCMCIA_DEBUG=0, the debug code will - * be present but disabled -- but it can then be enabled for specific - * modules at load time with a 'pc_debug=#' option to insmod. - */ -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KDBG_XIRC args) -#else -#define DEBUG(n, args...) -#endif #define KDBG_XIRC KERN_DEBUG "xirc2ps_cs: " #define KERR_XIRC KERN_ERR "xirc2ps_cs: " @@ -378,7 +364,7 @@ static int do_stop(struct net_device *dev); #define PutWord(reg,value) outw((value), ioaddr+(reg)) /*====== Functions used for debugging =================================*/ -#if defined(PCMCIA_DEBUG) && 0 /* reading regs may change system status */ +#if 0 /* reading regs may change system status */ static void PrintRegisters(struct net_device *dev) { @@ -410,7 +396,7 @@ PrintRegisters(struct net_device *dev) } } } -#endif /* PCMCIA_DEBUG */ +#endif /* 0 */ /*============== MII Management functions ===============*/ @@ -554,7 +540,7 @@ xirc2ps_probe(struct pcmcia_device *link) struct net_device *dev; local_info_t *local; - DEBUG(0, "attach()\n"); + dev_dbg(&link->dev, "attach()\n"); /* Allocate the device structure */ dev = alloc_etherdev(sizeof(local_info_t)); @@ -593,7 +579,7 @@ xirc2ps_detach(struct pcmcia_device *link) { struct net_device *dev = link->priv; - DEBUG(0, "detach(0x%p)\n", link); + dev_dbg(&link->dev, "detach\n"); if (link->dev_node) unregister_netdev(dev); @@ -640,7 +626,7 @@ set_card_type(struct pcmcia_device *link) mediaid = buf[3]; prodid = buf[4]; - DEBUG(0, "cisrev=%02x mediaid=%02x prodid=%02x\n", + dev_dbg(&link->dev, "cisrev=%02x mediaid=%02x prodid=%02x\n", cisrev, mediaid, prodid); local->mohawk = 0; @@ -784,7 +770,7 @@ xirc2ps_config(struct pcmcia_device * link) local->dingo_ccr = NULL; - DEBUG(0, "config(0x%p)\n", link); + dev_dbg(&link->dev, "config\n"); /* Is this a valid card */ if (link->has_manf_id == 0) { @@ -814,7 +800,7 @@ xirc2ps_config(struct pcmcia_device * link) (unsigned)link->manf_id); goto failure; } - DEBUG(0, "found %s card\n", local->manf_str); + dev_dbg(&link->dev, "found %s card\n", local->manf_str); if (!set_card_type(link)) { printk(KNOT_XIRC "this card is not supported\n"); @@ -891,10 +877,8 @@ xirc2ps_config(struct pcmcia_device * link) goto port_found; } link->io.BasePort1 = 0; /* let CS decide */ - if ((err=pcmcia_request_io(link, &link->io))) { - cs_error(link, RequestIO, err); + if ((err=pcmcia_request_io(link, &link->io))) goto config_error; - } } port_found: if (err) @@ -904,19 +888,15 @@ xirc2ps_config(struct pcmcia_device * link) * Now allocate an interrupt line. Note that this does not * actually assign a handler to the interrupt. */ - if ((err=pcmcia_request_irq(link, &link->irq))) { - cs_error(link, RequestIRQ, err); + if ((err=pcmcia_request_irq(link, &link->irq))) goto config_error; - } /**************** * This actually configures the PCMCIA socket -- setting up * the I/O windows and the interrupt mapping. */ - if ((err=pcmcia_request_configuration(link, &link->conf))) { - cs_error(link, RequestConfiguration, err); + if ((err=pcmcia_request_configuration(link, &link->conf))) goto config_error; - } if (local->dingo) { conf_reg_t reg; @@ -931,17 +911,13 @@ xirc2ps_config(struct pcmcia_device * link) reg.Action = CS_WRITE; reg.Offset = CISREG_IOBASE_0; reg.Value = link->io.BasePort2 & 0xff; - if ((err = pcmcia_access_configuration_register(link, ®))) { - cs_error(link, AccessConfigurationRegister, err); + if ((err = pcmcia_access_configuration_register(link, ®))) goto config_error; - } reg.Action = CS_WRITE; reg.Offset = CISREG_IOBASE_1; reg.Value = (link->io.BasePort2 >> 8) & 0xff; - if ((err = pcmcia_access_configuration_register(link, ®))) { - cs_error(link, AccessConfigurationRegister, err); + if ((err = pcmcia_access_configuration_register(link, ®))) goto config_error; - } /* There is no config entry for the Ethernet part which * is at 0x0800. So we allocate a window into the attribute @@ -950,17 +926,14 @@ xirc2ps_config(struct pcmcia_device * link) req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = req.Size = 0; req.AccessSpeed = 0; - if ((err = pcmcia_request_window(&link, &req, &link->win))) { - cs_error(link, RequestWindow, err); + if ((err = pcmcia_request_window(&link, &req, &link->win))) goto config_error; - } + local->dingo_ccr = ioremap(req.Base,0x1000) + 0x0800; mem.CardOffset = 0x0; mem.Page = 0; - if ((err = pcmcia_map_mem_page(link->win, &mem))) { - cs_error(link, MapMemPage, err); + if ((err = pcmcia_map_mem_page(link->win, &mem))) goto config_error; - } /* Setup the CCRs; there are no infos in the CIS about the Ethernet * part. @@ -1052,7 +1025,7 @@ xirc2ps_config(struct pcmcia_device * link) static void xirc2ps_release(struct pcmcia_device *link) { - DEBUG(0, "release(0x%p)\n", link); + dev_dbg(&link->dev, "release\n"); if (link->win) { struct net_device *dev = link->priv; @@ -1119,7 +1092,7 @@ xirc2ps_interrupt(int irq, void *dev_id) PutByte(XIRCREG_CR, 0); } - DEBUG(6, "%s: interrupt %d at %#x.\n", dev->name, irq, ioaddr); + pr_debug("%s: interrupt %d at %#x.\n", dev->name, irq, ioaddr); saved_page = GetByte(XIRCREG_PR); /* Read the ISR to see whats the cause for the interrupt. @@ -1129,7 +1102,7 @@ xirc2ps_interrupt(int irq, void *dev_id) bytes_rcvd = 0; loop_entry: if (int_status == 0xff) { /* card may be ejected */ - DEBUG(3, "%s: interrupt %d for dead card\n", dev->name, irq); + pr_debug("%s: interrupt %d for dead card\n", dev->name, irq); goto leave; } eth_status = GetByte(XIRCREG_ESR); @@ -1142,7 +1115,7 @@ xirc2ps_interrupt(int irq, void *dev_id) PutByte(XIRCREG40_TXST0, 0); PutByte(XIRCREG40_TXST1, 0); - DEBUG(3, "%s: ISR=%#2.2x ESR=%#2.2x RSR=%#2.2x TSR=%#4.4x\n", + pr_debug("%s: ISR=%#2.2x ESR=%#2.2x RSR=%#2.2x TSR=%#4.4x\n", dev->name, int_status, eth_status, rx_status, tx_status); /***** receive section ******/ @@ -1153,14 +1126,14 @@ xirc2ps_interrupt(int irq, void *dev_id) /* too many bytes received during this int, drop the rest of the * packets */ dev->stats.rx_dropped++; - DEBUG(2, "%s: RX drop, too much done\n", dev->name); + pr_debug("%s: RX drop, too much done\n", dev->name); } else if (rsr & PktRxOk) { struct sk_buff *skb; pktlen = GetWord(XIRCREG0_RBC); bytes_rcvd += pktlen; - DEBUG(5, "rsr=%#02x packet_length=%u\n", rsr, pktlen); + pr_debug("rsr=%#02x packet_length=%u\n", rsr, pktlen); skb = dev_alloc_skb(pktlen+3); /* 1 extra so we can use insw */ if (!skb) { @@ -1228,19 +1201,19 @@ xirc2ps_interrupt(int irq, void *dev_id) dev->stats.multicast++; } } else { /* bad packet */ - DEBUG(5, "rsr=%#02x\n", rsr); + pr_debug("rsr=%#02x\n", rsr); } if (rsr & PktTooLong) { dev->stats.rx_frame_errors++; - DEBUG(3, "%s: Packet too long\n", dev->name); + pr_debug("%s: Packet too long\n", dev->name); } if (rsr & CRCErr) { dev->stats.rx_crc_errors++; - DEBUG(3, "%s: CRC error\n", dev->name); + pr_debug("%s: CRC error\n", dev->name); } if (rsr & AlignErr) { dev->stats.rx_fifo_errors++; /* okay ? */ - DEBUG(3, "%s: Alignment error\n", dev->name); + pr_debug("%s: Alignment error\n", dev->name); } /* clear the received/dropped/error packet */ @@ -1252,7 +1225,7 @@ xirc2ps_interrupt(int irq, void *dev_id) if (rx_status & 0x10) { /* Receive overrun */ dev->stats.rx_over_errors++; PutByte(XIRCREG_CR, ClearRxOvrun); - DEBUG(3, "receive overrun cleared\n"); + pr_debug("receive overrun cleared\n"); } /***** transmit section ******/ @@ -1265,13 +1238,13 @@ xirc2ps_interrupt(int irq, void *dev_id) if (nn < n) /* rollover */ dev->stats.tx_packets += 256 - n; else if (n == nn) { /* happens sometimes - don't know why */ - DEBUG(0, "PTR not changed?\n"); + pr_debug("PTR not changed?\n"); } else dev->stats.tx_packets += lp->last_ptr_value - n; netif_wake_queue(dev); } if (tx_status & 0x0002) { /* Execessive collissions */ - DEBUG(0, "tx restarted due to execssive collissions\n"); + pr_debug("tx restarted due to execssive collissions\n"); PutByte(XIRCREG_CR, RestartTx); /* restart transmitter process */ } if (tx_status & 0x0040) @@ -1290,14 +1263,14 @@ xirc2ps_interrupt(int irq, void *dev_id) maxrx_bytes = 2000; else if (maxrx_bytes > 22000) maxrx_bytes = 22000; - DEBUG(1, "set maxrx=%u (rcvd=%u ticks=%lu)\n", + pr_debug("set maxrx=%u (rcvd=%u ticks=%lu)\n", maxrx_bytes, bytes_rcvd, duration); } else if (!duration && maxrx_bytes < 22000) { /* now much faster */ maxrx_bytes += 2000; if (maxrx_bytes > 22000) maxrx_bytes = 22000; - DEBUG(1, "set maxrx=%u\n", maxrx_bytes); + pr_debug("set maxrx=%u\n", maxrx_bytes); } } @@ -1347,7 +1320,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned freespace; unsigned pktlen = skb->len; - DEBUG(1, "do_start_xmit(skb=%p, dev=%p) len=%u\n", + pr_debug("do_start_xmit(skb=%p, dev=%p) len=%u\n", skb, dev, pktlen); @@ -1373,7 +1346,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev) freespace &= 0x7fff; /* TRS doesn't work - (indeed it is eliminated with sil-rev 1) */ okay = pktlen +2 < freespace; - DEBUG(2 + (okay ? 2 : 0), "%s: avail. tx space=%u%s\n", + pr_debug("%s: avail. tx space=%u%s\n", dev->name, freespace, okay ? " (okay)":" (not enough)"); if (!okay) { /* not enough space */ return NETDEV_TX_BUSY; /* upper layer may decide to requeue this packet */ @@ -1475,7 +1448,7 @@ do_config(struct net_device *dev, struct ifmap *map) { local_info_t *local = netdev_priv(dev); - DEBUG(0, "do_config(%p)\n", dev); + pr_debug("do_config(%p)\n", dev); if (map->port != 255 && map->port != dev->if_port) { if (map->port > 4) return -EINVAL; @@ -1502,7 +1475,7 @@ do_open(struct net_device *dev) local_info_t *lp = netdev_priv(dev); struct pcmcia_device *link = lp->p_dev; - DEBUG(0, "do_open(%p)\n", dev); + dev_dbg(&link->dev, "do_open(%p)\n", dev); /* Check that the PCMCIA card is still here. */ /* Physical device present signature. */ @@ -1536,7 +1509,7 @@ do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) unsigned int ioaddr = dev->base_addr; struct mii_ioctl_data *data = if_mii(rq); - DEBUG(1, "%s: ioctl(%-.6s, %#04x) %04x %04x %04x %04x\n", + pr_debug("%s: ioctl(%-.6s, %#04x) %04x %04x %04x %04x\n", dev->name, rq->ifr_ifrn.ifrn_name, cmd, data->phy_id, data->reg_num, data->val_in, data->val_out); @@ -1585,7 +1558,7 @@ do_reset(struct net_device *dev, int full) unsigned int ioaddr = dev->base_addr; unsigned value; - DEBUG(0, "%s: do_reset(%p,%d)\n", dev? dev->name:"eth?", dev, full); + pr_debug("%s: do_reset(%p,%d)\n", dev? dev->name:"eth?", dev, full); hardreset(dev); PutByte(XIRCREG_CR, SoftReset); /* set */ @@ -1623,8 +1596,8 @@ do_reset(struct net_device *dev, int full) } msleep(40); /* wait 40 msec to let it complete */ - #ifdef PCMCIA_DEBUG - if (pc_debug) { + #if 0 + { SelectPage(0); value = GetByte(XIRCREG_ESR); /* read the ESR */ printk(KERN_DEBUG "%s: ESR is: %#02x\n", dev->name, value); @@ -1641,7 +1614,7 @@ do_reset(struct net_device *dev, int full) value |= DisableLinkPulse; PutByte(XIRCREG1_ECR, value); #endif - DEBUG(0, "%s: ECR is: %#02x\n", dev->name, value); + pr_debug("%s: ECR is: %#02x\n", dev->name, value); SelectPage(0x42); PutByte(XIRCREG42_SWC0, 0x20); /* disable source insertion */ @@ -1819,7 +1792,7 @@ do_powerdown(struct net_device *dev) unsigned int ioaddr = dev->base_addr; - DEBUG(0, "do_powerdown(%p)\n", dev); + pr_debug("do_powerdown(%p)\n", dev); SelectPage(4); PutByte(XIRCREG4_GPR1, 0); /* clear bit 0: power down */ @@ -1833,7 +1806,7 @@ do_stop(struct net_device *dev) local_info_t *lp = netdev_priv(dev); struct pcmcia_device *link = lp->p_dev; - DEBUG(0, "do_stop(%p)\n", dev); + dev_dbg(&link->dev, "do_stop(%p)\n", dev); if (!link) return -ENODEV; From 624dd66957e53e15cf40e937b50597c4d41f0e99 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 24 Oct 2009 15:52:44 +0200 Subject: [PATCH 096/298] pcmcia: use dynamic debug infrastructure, deprecate CS_CHECK (ray-cs.c) Convert PCMCIA drivers to use the dynamic debug infrastructure, instead of requiring manual settings of PCMCIA_DEBUG. Also, remove all usages of the CS_CHECK macro and replace them with proper Linux style calling and return value checking. The extra error reporting may be dropped, as the PCMCIA core already complains about any (non-driver-author) errors. CC: linux-wireless@vger.kernel.org CC: netdev@vger.kernel.org Signed-off-by: Dominik Brodowski --- drivers/net/wireless/ray_cs.c | 347 +++++++++++++++++----------------- 1 file changed, 169 insertions(+), 178 deletions(-) diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 88cd58eb3b9..28db7914a5d 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -71,25 +71,7 @@ typedef u_char mac_addr[ETH_ALEN]; /* Hardware address */ #include "rayctl.h" #include "ray_cs.h" -/* All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If - you do not define PCMCIA_DEBUG at all, all the debug code will be - left out. If you compile with PCMCIA_DEBUG=0, the debug code will - be present but disabled -- but it can then be enabled for specific - modules at load time with a 'pc_debug=#' option to insmod. -*/ -#ifdef RAYLINK_DEBUG -#define PCMCIA_DEBUG RAYLINK_DEBUG -#endif -#ifdef PCMCIA_DEBUG -static int ray_debug; -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0); -/* #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); */ -#define DEBUG(n, args...) if (pc_debug > (n)) printk(args); -#else -#define DEBUG(n, args...) -#endif /** Prototypes based on PCMCIA skeleton driver *******************************/ static int ray_config(struct pcmcia_device *link); static void ray_release(struct pcmcia_device *link); @@ -325,7 +307,7 @@ static int ray_probe(struct pcmcia_device *p_dev) ray_dev_t *local; struct net_device *dev; - DEBUG(1, "ray_attach()\n"); + dev_dbg(&p_dev->dev, "ray_attach()\n"); /* Allocate space for private device-specific data */ dev = alloc_etherdev(sizeof(ray_dev_t)); @@ -357,7 +339,7 @@ static int ray_probe(struct pcmcia_device *p_dev) local->card_status = CARD_INSERTED; local->authentication_state = UNAUTHENTICATED; local->num_multi = 0; - DEBUG(2, "ray_attach p_dev = %p, dev = %p, local = %p, intr = %p\n", + dev_dbg(&p_dev->dev, "ray_attach p_dev = %p, dev = %p, local = %p, intr = %p\n", p_dev, dev, local, &ray_interrupt); /* Raylink entries in the device structure */ @@ -370,7 +352,7 @@ static int ray_probe(struct pcmcia_device *p_dev) #endif /* WIRELESS_SPY */ - DEBUG(2, "ray_cs ray_attach calling ether_setup.)\n"); + dev_dbg(&p_dev->dev, "ray_cs ray_attach calling ether_setup.)\n"); netif_stop_queue(dev); init_timer(&local->timer); @@ -393,7 +375,7 @@ static void ray_detach(struct pcmcia_device *link) struct net_device *dev; ray_dev_t *local; - DEBUG(1, "ray_detach(0x%p)\n", link); + dev_dbg(&link->dev, "ray_detach\n"); this_device = NULL; dev = link->priv; @@ -408,7 +390,7 @@ static void ray_detach(struct pcmcia_device *link) unregister_netdev(dev); free_netdev(dev); } - DEBUG(2, "ray_cs ray_detach ending\n"); + dev_dbg(&link->dev, "ray_cs ray_detach ending\n"); } /* ray_detach */ /*============================================================================= @@ -416,19 +398,17 @@ static void ray_detach(struct pcmcia_device *link) is received, to configure the PCMCIA socket, and to make the ethernet device available to the system. =============================================================================*/ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) #define MAX_TUPLE_SIZE 128 static int ray_config(struct pcmcia_device *link) { - int last_fn = 0, last_ret = 0; + int ret = 0; int i; win_req_t req; memreq_t mem; struct net_device *dev = (struct net_device *)link->priv; ray_dev_t *local = netdev_priv(dev); - DEBUG(1, "ray_config(0x%p)\n", link); + dev_dbg(&link->dev, "ray_config\n"); /* Determine card type and firmware version */ printk(KERN_INFO "ray_cs Detected: %s%s%s%s\n", @@ -440,14 +420,17 @@ static int ray_config(struct pcmcia_device *link) /* Now allocate an interrupt line. Note that this does not actually assign a handler to the interrupt. */ - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; dev->irq = link->irq.AssignedIRQ; /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping. */ - CS_CHECK(RequestConfiguration, - pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; /*** Set up 32k window for shared memory (transmit and control) ************/ req.Attributes = @@ -455,10 +438,14 @@ static int ray_config(struct pcmcia_device *link) req.Base = 0; req.Size = 0x8000; req.AccessSpeed = ray_mem_speed; - CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &link->win)); + ret = pcmcia_request_window(&link, &req, &link->win); + if (ret) + goto failed; mem.CardOffset = 0x0000; mem.Page = 0; - CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); + ret = pcmcia_map_mem_page(link->win, &mem); + if (ret) + goto failed; local->sram = ioremap(req.Base, req.Size); /*** Set up 16k window for shared memory (receive buffer) ***************/ @@ -467,11 +454,14 @@ static int ray_config(struct pcmcia_device *link) req.Base = 0; req.Size = 0x4000; req.AccessSpeed = ray_mem_speed; - CS_CHECK(RequestWindow, - pcmcia_request_window(&link, &req, &local->rmem_handle)); + ret = pcmcia_request_window(&link, &req, &local->rmem_handle); + if (ret) + goto failed; mem.CardOffset = 0x8000; mem.Page = 0; - CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->rmem_handle, &mem)); + ret = pcmcia_map_mem_page(local->rmem_handle, &mem); + if (ret) + goto failed; local->rmem = ioremap(req.Base, req.Size); /*** Set up window for attribute memory ***********************************/ @@ -480,16 +470,19 @@ static int ray_config(struct pcmcia_device *link) req.Base = 0; req.Size = 0x1000; req.AccessSpeed = ray_mem_speed; - CS_CHECK(RequestWindow, - pcmcia_request_window(&link, &req, &local->amem_handle)); + ret = pcmcia_request_window(&link, &req, &local->amem_handle); + if (ret) + goto failed; mem.CardOffset = 0x0000; mem.Page = 0; - CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->amem_handle, &mem)); + ret = pcmcia_map_mem_page(local->amem_handle, &mem); + if (ret) + goto failed; local->amem = ioremap(req.Base, req.Size); - DEBUG(3, "ray_config sram=%p\n", local->sram); - DEBUG(3, "ray_config rmem=%p\n", local->rmem); - DEBUG(3, "ray_config amem=%p\n", local->amem); + dev_dbg(&link->dev, "ray_config sram=%p\n", local->sram); + dev_dbg(&link->dev, "ray_config rmem=%p\n", local->rmem); + dev_dbg(&link->dev, "ray_config amem=%p\n", local->amem); if (ray_init(dev) < 0) { ray_release(link); return -ENODEV; @@ -511,9 +504,7 @@ static int ray_config(struct pcmcia_device *link) return 0; -cs_failed: - cs_error(link, last_fn, last_ret); - +failed: ray_release(link); return -ENODEV; } /* ray_config */ @@ -543,9 +534,9 @@ static int ray_init(struct net_device *dev) struct ccs __iomem *pccs; ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; - DEBUG(1, "ray_init(0x%p)\n", dev); + dev_dbg(&link->dev, "ray_init(0x%p)\n", dev); if (!(pcmcia_dev_present(link))) { - DEBUG(0, "ray_init - device not present\n"); + dev_dbg(&link->dev, "ray_init - device not present\n"); return -1; } @@ -567,13 +558,13 @@ static int ray_init(struct net_device *dev) local->fw_ver = local->startup_res.firmware_version[0]; local->fw_bld = local->startup_res.firmware_version[1]; local->fw_var = local->startup_res.firmware_version[2]; - DEBUG(1, "ray_init firmware version %d.%d \n", local->fw_ver, + dev_dbg(&link->dev, "ray_init firmware version %d.%d \n", local->fw_ver, local->fw_bld); local->tib_length = 0x20; if ((local->fw_ver == 5) && (local->fw_bld >= 30)) local->tib_length = local->startup_res.tib_length; - DEBUG(2, "ray_init tib_length = 0x%02x\n", local->tib_length); + dev_dbg(&link->dev, "ray_init tib_length = 0x%02x\n", local->tib_length); /* Initialize CCS's to buffer free state */ pccs = ccs_base(local); for (i = 0; i < NUMBER_OF_CCS; i++) { @@ -592,7 +583,7 @@ static int ray_init(struct net_device *dev) clear_interrupt(local); /* Clear any interrupt from the card */ local->card_status = CARD_AWAITING_PARAM; - DEBUG(2, "ray_init ending\n"); + dev_dbg(&link->dev, "ray_init ending\n"); return 0; } /* ray_init */ @@ -605,9 +596,9 @@ static int dl_startup_params(struct net_device *dev) struct ccs __iomem *pccs; struct pcmcia_device *link = local->finder; - DEBUG(1, "dl_startup_params entered\n"); + dev_dbg(&link->dev, "dl_startup_params entered\n"); if (!(pcmcia_dev_present(link))) { - DEBUG(2, "ray_cs dl_startup_params - device not present\n"); + dev_dbg(&link->dev, "ray_cs dl_startup_params - device not present\n"); return -1; } @@ -625,7 +616,7 @@ static int dl_startup_params(struct net_device *dev) local->dl_param_ccs = ccsindex; pccs = ccs_base(local) + ccsindex; writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd); - DEBUG(2, "dl_startup_params start ccsindex = %d\n", + dev_dbg(&link->dev, "dl_startup_params start ccsindex = %d\n", local->dl_param_ccs); /* Interrupt the firmware to process the command */ if (interrupt_ecf(local, ccsindex)) { @@ -641,7 +632,7 @@ static int dl_startup_params(struct net_device *dev) local->timer.data = (long)local; local->timer.function = &verify_dl_startup; add_timer(&local->timer); - DEBUG(2, + dev_dbg(&link->dev, "ray_cs dl_startup_params started timer for verify_dl_startup\n"); return 0; } /* dl_startup_params */ @@ -717,11 +708,11 @@ static void verify_dl_startup(u_long data) struct pcmcia_device *link = local->finder; if (!(pcmcia_dev_present(link))) { - DEBUG(2, "ray_cs verify_dl_startup - device not present\n"); + dev_dbg(&link->dev, "ray_cs verify_dl_startup - device not present\n"); return; } -#ifdef PCMCIA_DEBUG - if (pc_debug > 2) { +#if 0 + { int i; printk(KERN_DEBUG "verify_dl_startup parameters sent via ccs %d:\n", @@ -760,7 +751,7 @@ static void start_net(u_long data) int ccsindex; struct pcmcia_device *link = local->finder; if (!(pcmcia_dev_present(link))) { - DEBUG(2, "ray_cs start_net - device not present\n"); + dev_dbg(&link->dev, "ray_cs start_net - device not present\n"); return; } /* Fill in the CCS fields for the ECF */ @@ -771,7 +762,7 @@ static void start_net(u_long data) writeb(0, &pccs->var.start_network.update_param); /* Interrupt the firmware to process the command */ if (interrupt_ecf(local, ccsindex)) { - DEBUG(1, "ray start net failed - card not ready for intr\n"); + dev_dbg(&link->dev, "ray start net failed - card not ready for intr\n"); writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); return; } @@ -790,7 +781,7 @@ static void join_net(u_long data) struct pcmcia_device *link = local->finder; if (!(pcmcia_dev_present(link))) { - DEBUG(2, "ray_cs join_net - device not present\n"); + dev_dbg(&link->dev, "ray_cs join_net - device not present\n"); return; } /* Fill in the CCS fields for the ECF */ @@ -802,7 +793,7 @@ static void join_net(u_long data) writeb(0, &pccs->var.join_network.net_initiated); /* Interrupt the firmware to process the command */ if (interrupt_ecf(local, ccsindex)) { - DEBUG(1, "ray join net failed - card not ready for intr\n"); + dev_dbg(&link->dev, "ray join net failed - card not ready for intr\n"); writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); return; } @@ -821,7 +812,7 @@ static void ray_release(struct pcmcia_device *link) ray_dev_t *local = netdev_priv(dev); int i; - DEBUG(1, "ray_release(0x%p)\n", link); + dev_dbg(&link->dev, "ray_release\n"); del_timer(&local->timer); @@ -831,13 +822,13 @@ static void ray_release(struct pcmcia_device *link) /* Do bother checking to see if these succeed or not */ i = pcmcia_release_window(local->amem_handle); if (i != 0) - DEBUG(0, "ReleaseWindow(local->amem) ret = %x\n", i); + dev_dbg(&link->dev, "ReleaseWindow(local->amem) ret = %x\n", i); i = pcmcia_release_window(local->rmem_handle); if (i != 0) - DEBUG(0, "ReleaseWindow(local->rmem) ret = %x\n", i); + dev_dbg(&link->dev, "ReleaseWindow(local->rmem) ret = %x\n", i); pcmcia_disable_device(link); - DEBUG(2, "ray_release ending\n"); + dev_dbg(&link->dev, "ray_release ending\n"); } static int ray_suspend(struct pcmcia_device *link) @@ -871,9 +862,9 @@ static int ray_dev_init(struct net_device *dev) ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; - DEBUG(1, "ray_dev_init(dev=%p)\n", dev); + dev_dbg(&link->dev, "ray_dev_init(dev=%p)\n", dev); if (!(pcmcia_dev_present(link))) { - DEBUG(2, "ray_dev_init - device not present\n"); + dev_dbg(&link->dev, "ray_dev_init - device not present\n"); return -1; } #ifdef RAY_IMMEDIATE_INIT @@ -887,7 +878,7 @@ static int ray_dev_init(struct net_device *dev) /* Postpone the card init so that we can still configure the card, * for example using the Wireless Extensions. The init will happen * in ray_open() - Jean II */ - DEBUG(1, + dev_dbg(&link->dev, "ray_dev_init: postponing card init to ray_open() ; Status = %d\n", local->card_status); #endif /* RAY_IMMEDIATE_INIT */ @@ -896,7 +887,7 @@ static int ray_dev_init(struct net_device *dev) memcpy(dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN); memset(dev->broadcast, 0xff, ETH_ALEN); - DEBUG(2, "ray_dev_init ending\n"); + dev_dbg(&link->dev, "ray_dev_init ending\n"); return 0; } @@ -906,9 +897,9 @@ static int ray_dev_config(struct net_device *dev, struct ifmap *map) ray_dev_t *local = netdev_priv(dev); struct pcmcia_device *link = local->finder; /* Dummy routine to satisfy device structure */ - DEBUG(1, "ray_dev_config(dev=%p,ifmap=%p)\n", dev, map); + dev_dbg(&link->dev, "ray_dev_config(dev=%p,ifmap=%p)\n", dev, map); if (!(pcmcia_dev_present(link))) { - DEBUG(2, "ray_dev_config - device not present\n"); + dev_dbg(&link->dev, "ray_dev_config - device not present\n"); return -1; } @@ -924,14 +915,14 @@ static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb, short length = skb->len; if (!pcmcia_dev_present(link)) { - DEBUG(2, "ray_dev_start_xmit - device not present\n"); + dev_dbg(&link->dev, "ray_dev_start_xmit - device not present\n"); dev_kfree_skb(skb); return NETDEV_TX_OK; } - DEBUG(3, "ray_dev_start_xmit(skb=%p, dev=%p)\n", skb, dev); + dev_dbg(&link->dev, "ray_dev_start_xmit(skb=%p, dev=%p)\n", skb, dev); if (local->authentication_state == NEED_TO_AUTH) { - DEBUG(0, "ray_cs Sending authentication request.\n"); + dev_dbg(&link->dev, "ray_cs Sending authentication request.\n"); if (!build_auth_frame(local, local->auth_id, OPEN_AUTH_REQUEST)) { local->authentication_state = AUTHENTICATED; netif_stop_queue(dev); @@ -971,7 +962,7 @@ static int ray_hw_xmit(unsigned char *data, int len, struct net_device *dev, struct tx_msg __iomem *ptx; /* Address of xmit buffer in PC space */ short int addr; /* Address of xmit buffer in card space */ - DEBUG(3, "ray_hw_xmit(data=%p, len=%d, dev=%p)\n", data, len, dev); + pr_debug("ray_hw_xmit(data=%p, len=%d, dev=%p)\n", data, len, dev); if (len + TX_HEADER_LENGTH > TX_BUF_SIZE) { printk(KERN_INFO "ray_hw_xmit packet too large: %d bytes\n", len); @@ -979,9 +970,9 @@ static int ray_hw_xmit(unsigned char *data, int len, struct net_device *dev, } switch (ccsindex = get_free_tx_ccs(local)) { case ECCSBUSY: - DEBUG(2, "ray_hw_xmit tx_ccs table busy\n"); + pr_debug("ray_hw_xmit tx_ccs table busy\n"); case ECCSFULL: - DEBUG(2, "ray_hw_xmit No free tx ccs\n"); + pr_debug("ray_hw_xmit No free tx ccs\n"); case ECARDGONE: netif_stop_queue(dev); return XMIT_NO_CCS; @@ -1018,12 +1009,12 @@ static int ray_hw_xmit(unsigned char *data, int len, struct net_device *dev, writeb(PSM_CAM, &pccs->var.tx_request.pow_sav_mode); writeb(local->net_default_tx_rate, &pccs->var.tx_request.tx_rate); writeb(0, &pccs->var.tx_request.antenna); - DEBUG(3, "ray_hw_xmit default_tx_rate = 0x%x\n", + pr_debug("ray_hw_xmit default_tx_rate = 0x%x\n", local->net_default_tx_rate); /* Interrupt the firmware to process the command */ if (interrupt_ecf(local, ccsindex)) { - DEBUG(2, "ray_hw_xmit failed - ECF not ready for intr\n"); + pr_debug("ray_hw_xmit failed - ECF not ready for intr\n"); /* TBD very inefficient to copy packet to buffer, and then not send it, but the alternative is to queue the messages and that won't be done for a while. Maybe set tbusy until a CCS is free? @@ -1040,7 +1031,7 @@ static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, { __be16 proto = ((struct ethhdr *)data)->h_proto; if (ntohs(proto) >= 1536) { /* DIX II ethernet frame */ - DEBUG(3, "ray_cs translate_frame DIX II\n"); + pr_debug("ray_cs translate_frame DIX II\n"); /* Copy LLC header to card buffer */ memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc)); memcpy_toio(((void __iomem *)&ptx->var) + sizeof(eth2_llc), @@ -1056,9 +1047,9 @@ static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, len - ETH_HLEN); return (int)sizeof(struct snaphdr_t) - ETH_HLEN; } else { /* already 802 type, and proto is length */ - DEBUG(3, "ray_cs translate_frame 802\n"); + pr_debug("ray_cs translate_frame 802\n"); if (proto == htons(0xffff)) { /* evil netware IPX 802.3 without LLC */ - DEBUG(3, "ray_cs translate_frame evil IPX\n"); + pr_debug("ray_cs translate_frame evil IPX\n"); memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); return 0 - ETH_HLEN; } @@ -1603,7 +1594,7 @@ static int ray_open(struct net_device *dev) struct pcmcia_device *link; link = local->finder; - DEBUG(1, "ray_open('%s')\n", dev->name); + dev_dbg(&link->dev, "ray_open('%s')\n", dev->name); if (link->open == 0) local->num_multi = 0; @@ -1613,7 +1604,7 @@ static int ray_open(struct net_device *dev) if (local->card_status == CARD_AWAITING_PARAM) { int i; - DEBUG(1, "ray_open: doing init now !\n"); + dev_dbg(&link->dev, "ray_open: doing init now !\n"); /* Download startup parameters */ if ((i = dl_startup_params(dev)) < 0) { @@ -1629,7 +1620,7 @@ static int ray_open(struct net_device *dev) else netif_start_queue(dev); - DEBUG(2, "ray_open ending\n"); + dev_dbg(&link->dev, "ray_open ending\n"); return 0; } /* end ray_open */ @@ -1640,7 +1631,7 @@ static int ray_dev_close(struct net_device *dev) struct pcmcia_device *link; link = local->finder; - DEBUG(1, "ray_dev_close('%s')\n", dev->name); + dev_dbg(&link->dev, "ray_dev_close('%s')\n", dev->name); link->open--; netif_stop_queue(dev); @@ -1656,7 +1647,7 @@ static int ray_dev_close(struct net_device *dev) /*===========================================================================*/ static void ray_reset(struct net_device *dev) { - DEBUG(1, "ray_reset entered\n"); + pr_debug("ray_reset entered\n"); return; } @@ -1669,17 +1660,17 @@ static int interrupt_ecf(ray_dev_t *local, int ccs) struct pcmcia_device *link = local->finder; if (!(pcmcia_dev_present(link))) { - DEBUG(2, "ray_cs interrupt_ecf - device not present\n"); + dev_dbg(&link->dev, "ray_cs interrupt_ecf - device not present\n"); return -1; } - DEBUG(2, "interrupt_ecf(local=%p, ccs = 0x%x\n", local, ccs); + dev_dbg(&link->dev, "interrupt_ecf(local=%p, ccs = 0x%x\n", local, ccs); while (i && (readb(local->amem + CIS_OFFSET + ECF_INTR_OFFSET) & ECF_INTR_SET)) i--; if (i == 0) { - DEBUG(2, "ray_cs interrupt_ecf card not ready for interrupt\n"); + dev_dbg(&link->dev, "ray_cs interrupt_ecf card not ready for interrupt\n"); return -1; } /* Fill the mailbox, then kick the card */ @@ -1698,12 +1689,12 @@ static int get_free_tx_ccs(ray_dev_t *local) struct pcmcia_device *link = local->finder; if (!(pcmcia_dev_present(link))) { - DEBUG(2, "ray_cs get_free_tx_ccs - device not present\n"); + dev_dbg(&link->dev, "ray_cs get_free_tx_ccs - device not present\n"); return ECARDGONE; } if (test_and_set_bit(0, &local->tx_ccs_lock)) { - DEBUG(1, "ray_cs tx_ccs_lock busy\n"); + dev_dbg(&link->dev, "ray_cs tx_ccs_lock busy\n"); return ECCSBUSY; } @@ -1716,7 +1707,7 @@ static int get_free_tx_ccs(ray_dev_t *local) } } local->tx_ccs_lock = 0; - DEBUG(2, "ray_cs ERROR no free tx CCS for raylink card\n"); + dev_dbg(&link->dev, "ray_cs ERROR no free tx CCS for raylink card\n"); return ECCSFULL; } /* get_free_tx_ccs */ @@ -1730,11 +1721,11 @@ static int get_free_ccs(ray_dev_t *local) struct pcmcia_device *link = local->finder; if (!(pcmcia_dev_present(link))) { - DEBUG(2, "ray_cs get_free_ccs - device not present\n"); + dev_dbg(&link->dev, "ray_cs get_free_ccs - device not present\n"); return ECARDGONE; } if (test_and_set_bit(0, &local->ccs_lock)) { - DEBUG(1, "ray_cs ccs_lock busy\n"); + dev_dbg(&link->dev, "ray_cs ccs_lock busy\n"); return ECCSBUSY; } @@ -1747,7 +1738,7 @@ static int get_free_ccs(ray_dev_t *local) } } local->ccs_lock = 0; - DEBUG(1, "ray_cs ERROR no free CCS for raylink card\n"); + dev_dbg(&link->dev, "ray_cs ERROR no free CCS for raylink card\n"); return ECCSFULL; } /* get_free_ccs */ @@ -1823,7 +1814,7 @@ static struct net_device_stats *ray_get_stats(struct net_device *dev) struct pcmcia_device *link = local->finder; struct status __iomem *p = local->sram + STATUS_BASE; if (!(pcmcia_dev_present(link))) { - DEBUG(2, "ray_cs net_device_stats - device not present\n"); + dev_dbg(&link->dev, "ray_cs net_device_stats - device not present\n"); return &local->stats; } if (readb(&p->mrx_overflow_for_host)) { @@ -1856,12 +1847,12 @@ static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, struct ccs __iomem *pccs; if (!(pcmcia_dev_present(link))) { - DEBUG(2, "ray_update_parm - device not present\n"); + dev_dbg(&link->dev, "ray_update_parm - device not present\n"); return; } if ((ccsindex = get_free_ccs(local)) < 0) { - DEBUG(0, "ray_update_parm - No free ccs\n"); + dev_dbg(&link->dev, "ray_update_parm - No free ccs\n"); return; } pccs = ccs_base(local) + ccsindex; @@ -1874,7 +1865,7 @@ static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, } /* Interrupt the firmware to process the command */ if (interrupt_ecf(local, ccsindex)) { - DEBUG(0, "ray_cs associate failed - ECF not ready for intr\n"); + dev_dbg(&link->dev, "ray_cs associate failed - ECF not ready for intr\n"); writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); } } @@ -1891,12 +1882,12 @@ static void ray_update_multi_list(struct net_device *dev, int all) void __iomem *p = local->sram + HOST_TO_ECF_BASE; if (!(pcmcia_dev_present(link))) { - DEBUG(2, "ray_update_multi_list - device not present\n"); + dev_dbg(&link->dev, "ray_update_multi_list - device not present\n"); return; } else - DEBUG(2, "ray_update_multi_list(%p)\n", dev); + dev_dbg(&link->dev, "ray_update_multi_list(%p)\n", dev); if ((ccsindex = get_free_ccs(local)) < 0) { - DEBUG(1, "ray_update_multi - No free ccs\n"); + dev_dbg(&link->dev, "ray_update_multi - No free ccs\n"); return; } pccs = ccs_base(local) + ccsindex; @@ -1910,7 +1901,7 @@ static void ray_update_multi_list(struct net_device *dev, int all) for (dmip = &dev->mc_list; (dmi = *dmip) != NULL; dmip = &dmi->next) { memcpy_toio(p, dmi->dmi_addr, ETH_ALEN); - DEBUG(1, + dev_dbg(&link->dev, "ray_update_multi add addr %02x%02x%02x%02x%02x%02x\n", dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], dmi->dmi_addr[3], @@ -1921,12 +1912,12 @@ static void ray_update_multi_list(struct net_device *dev, int all) if (i > 256 / ADDRLEN) i = 256 / ADDRLEN; writeb((UCHAR) i, &pccs->var); - DEBUG(1, "ray_cs update_multi %d addresses in list\n", i); + dev_dbg(&link->dev, "ray_cs update_multi %d addresses in list\n", i); /* Interrupt the firmware to process the command */ local->num_multi = i; } if (interrupt_ecf(local, ccsindex)) { - DEBUG(1, + dev_dbg(&link->dev, "ray_cs update_multi failed - ECF not ready for intr\n"); writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); } @@ -1938,11 +1929,11 @@ static void set_multicast_list(struct net_device *dev) ray_dev_t *local = netdev_priv(dev); UCHAR promisc; - DEBUG(2, "ray_cs set_multicast_list(%p)\n", dev); + pr_debug("ray_cs set_multicast_list(%p)\n", dev); if (dev->flags & IFF_PROMISC) { if (local->sparm.b5.a_promiscuous_mode == 0) { - DEBUG(1, "ray_cs set_multicast_list promisc on\n"); + pr_debug("ray_cs set_multicast_list promisc on\n"); local->sparm.b5.a_promiscuous_mode = 1; promisc = 1; ray_update_parm(dev, OBJID_promiscuous_mode, @@ -1950,7 +1941,7 @@ static void set_multicast_list(struct net_device *dev) } } else { if (local->sparm.b5.a_promiscuous_mode == 1) { - DEBUG(1, "ray_cs set_multicast_list promisc off\n"); + pr_debug("ray_cs set_multicast_list promisc off\n"); local->sparm.b5.a_promiscuous_mode = 0; promisc = 0; ray_update_parm(dev, OBJID_promiscuous_mode, @@ -1984,19 +1975,19 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id) if (dev == NULL) /* Note that we want interrupts with dev->start == 0 */ return IRQ_NONE; - DEBUG(4, "ray_cs: interrupt for *dev=%p\n", dev); + pr_debug("ray_cs: interrupt for *dev=%p\n", dev); local = netdev_priv(dev); link = (struct pcmcia_device *)local->finder; if (!pcmcia_dev_present(link)) { - DEBUG(2, - "ray_cs interrupt from device not present or suspended.\n"); + pr_debug( + "ray_cs interrupt from device not present or suspended.\n"); return IRQ_NONE; } rcsindex = readb(&((struct scb __iomem *)(local->sram))->rcs_index); if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) { - DEBUG(1, "ray_cs interrupt bad rcsindex = 0x%x\n", rcsindex); + dev_dbg(&link->dev, "ray_cs interrupt bad rcsindex = 0x%x\n", rcsindex); clear_interrupt(local); return IRQ_HANDLED; } @@ -2008,33 +1999,33 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id) case CCS_DOWNLOAD_STARTUP_PARAMS: /* Happens in firmware someday */ del_timer(&local->timer); if (status == CCS_COMMAND_COMPLETE) { - DEBUG(1, + dev_dbg(&link->dev, "ray_cs interrupt download_startup_parameters OK\n"); } else { - DEBUG(1, + dev_dbg(&link->dev, "ray_cs interrupt download_startup_parameters fail\n"); } break; case CCS_UPDATE_PARAMS: - DEBUG(1, "ray_cs interrupt update params done\n"); + dev_dbg(&link->dev, "ray_cs interrupt update params done\n"); if (status != CCS_COMMAND_COMPLETE) { tmp = readb(&pccs->var.update_param. failure_cause); - DEBUG(0, + dev_dbg(&link->dev, "ray_cs interrupt update params failed - reason %d\n", tmp); } break; case CCS_REPORT_PARAMS: - DEBUG(1, "ray_cs interrupt report params done\n"); + dev_dbg(&link->dev, "ray_cs interrupt report params done\n"); break; case CCS_UPDATE_MULTICAST_LIST: /* Note that this CCS isn't returned */ - DEBUG(1, + dev_dbg(&link->dev, "ray_cs interrupt CCS Update Multicast List done\n"); break; case CCS_UPDATE_POWER_SAVINGS_MODE: - DEBUG(1, + dev_dbg(&link->dev, "ray_cs interrupt update power save mode done\n"); break; case CCS_START_NETWORK: @@ -2043,11 +2034,11 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id) if (readb (&pccs->var.start_network.net_initiated) == 1) { - DEBUG(0, + dev_dbg(&link->dev, "ray_cs interrupt network \"%s\" started\n", local->sparm.b4.a_current_ess_id); } else { - DEBUG(0, + dev_dbg(&link->dev, "ray_cs interrupt network \"%s\" joined\n", local->sparm.b4.a_current_ess_id); } @@ -2075,12 +2066,12 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id) local->timer.expires = jiffies + HZ * 5; local->timer.data = (long)local; if (status == CCS_START_NETWORK) { - DEBUG(0, + dev_dbg(&link->dev, "ray_cs interrupt network \"%s\" start failed\n", local->sparm.b4.a_current_ess_id); local->timer.function = &start_net; } else { - DEBUG(0, + dev_dbg(&link->dev, "ray_cs interrupt network \"%s\" join failed\n", local->sparm.b4.a_current_ess_id); local->timer.function = &join_net; @@ -2091,19 +2082,19 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id) case CCS_START_ASSOCIATION: if (status == CCS_COMMAND_COMPLETE) { local->card_status = CARD_ASSOC_COMPLETE; - DEBUG(0, "ray_cs association successful\n"); + dev_dbg(&link->dev, "ray_cs association successful\n"); } else { - DEBUG(0, "ray_cs association failed,\n"); + dev_dbg(&link->dev, "ray_cs association failed,\n"); local->card_status = CARD_ASSOC_FAILED; join_net((u_long) local); } break; case CCS_TX_REQUEST: if (status == CCS_COMMAND_COMPLETE) { - DEBUG(3, + dev_dbg(&link->dev, "ray_cs interrupt tx request complete\n"); } else { - DEBUG(1, + dev_dbg(&link->dev, "ray_cs interrupt tx request failed\n"); } if (!sniffer) @@ -2111,21 +2102,21 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id) netif_wake_queue(dev); break; case CCS_TEST_MEMORY: - DEBUG(1, "ray_cs interrupt mem test done\n"); + dev_dbg(&link->dev, "ray_cs interrupt mem test done\n"); break; case CCS_SHUTDOWN: - DEBUG(1, + dev_dbg(&link->dev, "ray_cs interrupt Unexpected CCS returned - Shutdown\n"); break; case CCS_DUMP_MEMORY: - DEBUG(1, "ray_cs interrupt dump memory done\n"); + dev_dbg(&link->dev, "ray_cs interrupt dump memory done\n"); break; case CCS_START_TIMER: - DEBUG(2, + dev_dbg(&link->dev, "ray_cs interrupt DING - raylink timer expired\n"); break; default: - DEBUG(1, + dev_dbg(&link->dev, "ray_cs interrupt Unexpected CCS 0x%x returned 0x%x\n", rcsindex, cmd); } @@ -2139,7 +2130,7 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id) ray_rx(dev, local, prcs); break; case REJOIN_NET_COMPLETE: - DEBUG(1, "ray_cs interrupt rejoin net complete\n"); + dev_dbg(&link->dev, "ray_cs interrupt rejoin net complete\n"); local->card_status = CARD_ACQ_COMPLETE; /* do we need to clear tx buffers CCS's? */ if (local->sparm.b4.a_network_type == ADHOC) { @@ -2149,7 +2140,7 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id) memcpy_fromio(&local->bss_id, prcs->var.rejoin_net_complete. bssid, ADDRLEN); - DEBUG(1, + dev_dbg(&link->dev, "ray_cs new BSSID = %02x%02x%02x%02x%02x%02x\n", local->bss_id[0], local->bss_id[1], local->bss_id[2], local->bss_id[3], @@ -2159,15 +2150,15 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id) } break; case ROAMING_INITIATED: - DEBUG(1, "ray_cs interrupt roaming initiated\n"); + dev_dbg(&link->dev, "ray_cs interrupt roaming initiated\n"); netif_stop_queue(dev); local->card_status = CARD_DOING_ACQ; break; case JAPAN_CALL_SIGN_RXD: - DEBUG(1, "ray_cs interrupt japan call sign rx\n"); + dev_dbg(&link->dev, "ray_cs interrupt japan call sign rx\n"); break; default: - DEBUG(1, + dev_dbg(&link->dev, "ray_cs Unexpected interrupt for RCS 0x%x cmd = 0x%x\n", rcsindex, (unsigned int)readb(&prcs->interrupt_id)); @@ -2186,7 +2177,7 @@ static void ray_rx(struct net_device *dev, ray_dev_t *local, int rx_len; unsigned int pkt_addr; void __iomem *pmsg; - DEBUG(4, "ray_rx process rx packet\n"); + pr_debug("ray_rx process rx packet\n"); /* Calculate address of packet within Rx buffer */ pkt_addr = ((readb(&prcs->var.rx_packet.rx_data_ptr[0]) << 8) @@ -2199,28 +2190,28 @@ static void ray_rx(struct net_device *dev, ray_dev_t *local, pmsg = local->rmem + pkt_addr; switch (readb(pmsg)) { case DATA_TYPE: - DEBUG(4, "ray_rx data type\n"); + pr_debug("ray_rx data type\n"); rx_data(dev, prcs, pkt_addr, rx_len); break; case AUTHENTIC_TYPE: - DEBUG(4, "ray_rx authentic type\n"); + pr_debug("ray_rx authentic type\n"); if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len); else rx_authenticate(local, prcs, pkt_addr, rx_len); break; case DEAUTHENTIC_TYPE: - DEBUG(4, "ray_rx deauth type\n"); + pr_debug("ray_rx deauth type\n"); if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len); else rx_deauthenticate(local, prcs, pkt_addr, rx_len); break; case NULL_MSG_TYPE: - DEBUG(3, "ray_cs rx NULL msg\n"); + pr_debug("ray_cs rx NULL msg\n"); break; case BEACON_TYPE: - DEBUG(4, "ray_rx beacon type\n"); + pr_debug("ray_rx beacon type\n"); if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len); @@ -2233,7 +2224,7 @@ static void ray_rx(struct net_device *dev, ray_dev_t *local, ray_get_stats(dev); break; default: - DEBUG(0, "ray_cs unknown pkt type %2x\n", + pr_debug("ray_cs unknown pkt type %2x\n", (unsigned int)readb(pmsg)); break; } @@ -2262,7 +2253,7 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, rx_len > (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + FCS_LEN)) { - DEBUG(0, + pr_debug( "ray_cs invalid packet length %d received \n", rx_len); return; @@ -2273,17 +2264,17 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, rx_len > (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + FCS_LEN)) { - DEBUG(0, + pr_debug( "ray_cs invalid packet length %d received \n", rx_len); return; } } } - DEBUG(4, "ray_cs rx_data packet\n"); + pr_debug("ray_cs rx_data packet\n"); /* If fragmented packet, verify sizes of fragments add up */ if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) { - DEBUG(1, "ray_cs rx'ed fragment\n"); + pr_debug("ray_cs rx'ed fragment\n"); tmp = (readb(&prcs->var.rx_packet.totalpacketlength[0]) << 8) + readb(&prcs->var.rx_packet.totalpacketlength[1]); total_len = tmp; @@ -2301,7 +2292,7 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, } while (1); if (tmp < 0) { - DEBUG(0, + pr_debug( "ray_cs rx_data fragment lengths don't add up\n"); local->stats.rx_dropped++; release_frag_chain(local, prcs); @@ -2313,7 +2304,7 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, skb = dev_alloc_skb(total_len + 5); if (skb == NULL) { - DEBUG(0, "ray_cs rx_data could not allocate skb\n"); + pr_debug("ray_cs rx_data could not allocate skb\n"); local->stats.rx_dropped++; if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) release_frag_chain(local, prcs); @@ -2321,7 +2312,7 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, } skb_reserve(skb, 2); /* Align IP on 16 byte (TBD check this) */ - DEBUG(4, "ray_cs rx_data total_len = %x, rx_len = %x\n", total_len, + pr_debug("ray_cs rx_data total_len = %x, rx_len = %x\n", total_len, rx_len); /************************/ @@ -2354,7 +2345,7 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, tmp = 17; if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) { prcslink = prcs; - DEBUG(1, "ray_cs rx_data in fragment loop\n"); + pr_debug("ray_cs rx_data in fragment loop\n"); do { prcslink = rcs_base(local) + @@ -2426,8 +2417,8 @@ static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) memcpy(destaddr, ieee80211_get_DA(pmac), ADDRLEN); memcpy(srcaddr, ieee80211_get_SA(pmac), ADDRLEN); -#ifdef PCMCIA_DEBUG - if (pc_debug > 3) { +#if 0 + if { print_hex_dump(KERN_DEBUG, "skb->data before untranslate: ", DUMP_PREFIX_NONE, 16, 1, skb->data, 64, true); @@ -2441,7 +2432,7 @@ static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) if (psnap->dsap != 0xaa || psnap->ssap != 0xaa || psnap->ctrl != 3) { /* not a snap type so leave it alone */ - DEBUG(3, "ray_cs untranslate NOT SNAP %02x %02x %02x\n", + pr_debug("ray_cs untranslate NOT SNAP %02x %02x %02x\n", psnap->dsap, psnap->ssap, psnap->ctrl); delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; @@ -2450,7 +2441,7 @@ static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) } else { /* Its a SNAP */ if (memcmp(psnap->org, org_bridge, 3) == 0) { /* EtherII and nuke the LLC */ - DEBUG(3, "ray_cs untranslate Bridge encap\n"); + pr_debug("ray_cs untranslate Bridge encap\n"); delta = RX_MAC_HEADER_LENGTH + sizeof(struct snaphdr_t) - ETH_HLEN; peth = (struct ethhdr *)(skb->data + delta); @@ -2459,14 +2450,14 @@ static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) switch (ntohs(type)) { case ETH_P_IPX: case ETH_P_AARP: - DEBUG(3, "ray_cs untranslate RFC IPX/AARP\n"); + pr_debug("ray_cs untranslate RFC IPX/AARP\n"); delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; peth = (struct ethhdr *)(skb->data + delta); peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH); break; default: - DEBUG(3, "ray_cs untranslate RFC default\n"); + pr_debug("ray_cs untranslate RFC default\n"); delta = RX_MAC_HEADER_LENGTH + sizeof(struct snaphdr_t) - ETH_HLEN; peth = (struct ethhdr *)(skb->data + delta); @@ -2482,12 +2473,12 @@ static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) } /* TBD reserve skb_reserve(skb, delta); */ skb_pull(skb, delta); - DEBUG(3, "untranslate after skb_pull(%d), skb->data = %p\n", delta, + pr_debug("untranslate after skb_pull(%d), skb->data = %p\n", delta, skb->data); memcpy(peth->h_dest, destaddr, ADDRLEN); memcpy(peth->h_source, srcaddr, ADDRLEN); -#ifdef PCMCIA_DEBUG - if (pc_debug > 3) { +#if 0 + { int i; printk(KERN_DEBUG "skb->data after untranslate:"); for (i = 0; i < 64; i++) @@ -2529,7 +2520,7 @@ static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs) while (tmp--) { writeb(CCS_BUFFER_FREE, &prcslink->buffer_status); if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) { - DEBUG(1, "ray_cs interrupt bad rcsindex = 0x%x\n", + pr_debug("ray_cs interrupt bad rcsindex = 0x%x\n", rcsindex); break; } @@ -2543,9 +2534,9 @@ static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs) static void authenticate(ray_dev_t *local) { struct pcmcia_device *link = local->finder; - DEBUG(0, "ray_cs Starting authentication.\n"); + dev_dbg(&link->dev, "ray_cs Starting authentication.\n"); if (!(pcmcia_dev_present(link))) { - DEBUG(2, "ray_cs authenticate - device not present\n"); + dev_dbg(&link->dev, "ray_cs authenticate - device not present\n"); return; } @@ -2573,11 +2564,11 @@ static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs, copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff); /* if we are trying to get authenticated */ if (local->sparm.b4.a_network_type == ADHOC) { - DEBUG(1, "ray_cs rx_auth var= %02x %02x %02x %02x %02x %02x\n", + pr_debug("ray_cs rx_auth var= %02x %02x %02x %02x %02x %02x\n", msg->var[0], msg->var[1], msg->var[2], msg->var[3], msg->var[4], msg->var[5]); if (msg->var[2] == 1) { - DEBUG(0, "ray_cs Sending authentication response.\n"); + pr_debug("ray_cs Sending authentication response.\n"); if (!build_auth_frame (local, msg->mac.addr_2, OPEN_AUTH_RESPONSE)) { local->authentication_state = NEED_TO_AUTH; @@ -2591,13 +2582,13 @@ static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs, /* Verify authentication sequence #2 and success */ if (msg->var[2] == 2) { if ((msg->var[3] | msg->var[4]) == 0) { - DEBUG(1, "Authentication successful\n"); + pr_debug("Authentication successful\n"); local->card_status = CARD_AUTH_COMPLETE; associate(local); local->authentication_state = AUTHENTICATED; } else { - DEBUG(0, "Authentication refused\n"); + pr_debug("Authentication refused\n"); local->card_status = CARD_AUTH_REFUSED; join_net((u_long) local); local->authentication_state = @@ -2617,22 +2608,22 @@ static void associate(ray_dev_t *local) struct net_device *dev = link->priv; int ccsindex; if (!(pcmcia_dev_present(link))) { - DEBUG(2, "ray_cs associate - device not present\n"); + dev_dbg(&link->dev, "ray_cs associate - device not present\n"); return; } /* If no tx buffers available, return */ if ((ccsindex = get_free_ccs(local)) < 0) { /* TBD should never be here but... what if we are? */ - DEBUG(1, "ray_cs associate - No free ccs\n"); + dev_dbg(&link->dev, "ray_cs associate - No free ccs\n"); return; } - DEBUG(1, "ray_cs Starting association with access point\n"); + dev_dbg(&link->dev, "ray_cs Starting association with access point\n"); pccs = ccs_base(local) + ccsindex; /* fill in the CCS */ writeb(CCS_START_ASSOCIATION, &pccs->cmd); /* Interrupt the firmware to process the command */ if (interrupt_ecf(local, ccsindex)) { - DEBUG(1, "ray_cs associate failed - ECF not ready for intr\n"); + dev_dbg(&link->dev, "ray_cs associate failed - ECF not ready for intr\n"); writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); del_timer(&local->timer); @@ -2655,7 +2646,7 @@ static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs, /* UCHAR buff[256]; struct rx_msg *msg = (struct rx_msg *)buff; */ - DEBUG(0, "Deauthentication frame received\n"); + pr_debug("Deauthentication frame received\n"); local->authentication_state = UNAUTHENTICATED; /* Need to reauthenticate or rejoin depending on reason code */ /* copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff); @@ -2823,7 +2814,7 @@ static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type) /* If no tx buffers available, return */ if ((ccsindex = get_free_tx_ccs(local)) < 0) { - DEBUG(1, "ray_cs send authenticate - No free tx ccs\n"); + pr_debug("ray_cs send authenticate - No free tx ccs\n"); return -1; } @@ -2855,7 +2846,7 @@ static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type) /* Interrupt the firmware to process the command */ if (interrupt_ecf(local, ccsindex)) { - DEBUG(1, + pr_debug( "ray_cs send authentication request failed - ECF not ready for intr\n"); writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); return -1; @@ -2942,9 +2933,9 @@ static int __init init_ray_cs(void) { int rc; - DEBUG(1, "%s\n", rcsid); + pr_debug("%s\n", rcsid); rc = pcmcia_register_driver(&ray_driver); - DEBUG(1, "raylink init_module register_pcmcia_driver returns 0x%x\n", + pr_debug("raylink init_module register_pcmcia_driver returns 0x%x\n", rc); #ifdef CONFIG_PROC_FS @@ -2964,7 +2955,7 @@ static int __init init_ray_cs(void) static void __exit exit_ray_cs(void) { - DEBUG(0, "ray_cs: cleanup_module\n"); + pr_debug("ray_cs: cleanup_module\n"); #ifdef CONFIG_PROC_FS remove_proc_entry("driver/ray_cs/ray_cs", NULL); From 2caff14713d53abba273e6095495788e2720f756 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 24 Oct 2009 15:53:36 +0200 Subject: [PATCH 097/298] pcmcia: use dynamic debug infrastructure, deprecate CS_CHECK (wireless) Convert PCMCIA drivers to use the dynamic debug infrastructure, instead of requiring manual settings of PCMCIA_DEBUG. Also, remove all usages of the CS_CHECK macro and replace them with proper Linux style calling and return value checking. The extra error reporting may be dropped, as the PCMCIA core already complains about any (non-driver-author) errors. CC: linux-wireless@vger.kernel.org CC: netdev@vger.kernel.org Signed-off-by: Dominik Brodowski --- drivers/net/wireless/airo_cs.c | 48 ++++-------- drivers/net/wireless/atmel_cs.c | 46 ++++------- drivers/net/wireless/hostap/hostap_cs.c | 23 ++---- drivers/net/wireless/netwave_cs.c | 88 +++++++++------------- drivers/net/wireless/orinoco/orinoco_cs.c | 27 +++---- drivers/net/wireless/orinoco/spectrum_cs.c | 54 ++++++------- drivers/net/wireless/wavelan_cs.c | 24 ------ drivers/net/wireless/wl3501_cs.c | 67 ++++++---------- 8 files changed, 136 insertions(+), 241 deletions(-) diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index d0593ed9170..a1b84fc48af 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -43,21 +43,6 @@ #include "airo.h" -/* - All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If - you do not define PCMCIA_DEBUG at all, all the debug code will be - left out. If you compile with PCMCIA_DEBUG=0, the debug code will - be present but disabled -- but it can then be enabled for specific - modules at load time with a 'pc_debug=#' option to insmod. -*/ -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0); -static char *version = "$Revision: 1.2 $"; -#define DEBUG(n, args...) if (pc_debug > (n)) printk(KERN_DEBUG args); -#else -#define DEBUG(n, args...) -#endif /*====================================================================*/ @@ -145,7 +130,7 @@ static int airo_probe(struct pcmcia_device *p_dev) { local_info_t *local; - DEBUG(0, "airo_attach()\n"); + dev_dbg(&p_dev->dev, "airo_attach()\n"); /* Interrupt setup */ p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; @@ -184,7 +169,7 @@ static int airo_probe(struct pcmcia_device *p_dev) static void airo_detach(struct pcmcia_device *link) { - DEBUG(0, "airo_detach(0x%p)\n", link); + dev_dbg(&link->dev, "airo_detach\n"); airo_release(link); @@ -204,9 +189,6 @@ static void airo_detach(struct pcmcia_device *link) ======================================================================*/ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int airo_cs_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, cistpl_cftable_entry_t *dflt, @@ -291,11 +273,11 @@ static int airo_config(struct pcmcia_device *link) { local_info_t *dev; win_req_t *req; - int last_fn, last_ret; + int ret; dev = link->priv; - DEBUG(0, "airo_config(0x%p)\n", link); + dev_dbg(&link->dev, "airo_config\n"); req = kzalloc(sizeof(win_req_t), GFP_KERNEL); if (!req) @@ -315,8 +297,8 @@ static int airo_config(struct pcmcia_device *link) * and most client drivers will only use the CIS to fill in * implementation-defined details. */ - last_ret = pcmcia_loop_config(link, airo_cs_config_check, req); - if (last_ret) + ret = pcmcia_loop_config(link, airo_cs_config_check, req); + if (ret) goto failed; /* @@ -324,21 +306,25 @@ static int airo_config(struct pcmcia_device *link) handler to the interrupt, unless the 'Handler' member of the irq structure is initialized. */ - if (link->conf.Attributes & CONF_ENABLE_IRQ) - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + if (link->conf.Attributes & CONF_ENABLE_IRQ) { + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + } /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - CS_CHECK(RequestConfiguration, - pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; ((local_info_t *)link->priv)->eth_dev = init_airo_card(link->irq.AssignedIRQ, link->io.BasePort1, 1, &handle_to_dev(link)); if (!((local_info_t *)link->priv)->eth_dev) - goto cs_failed; + goto failed; /* At this point, the dev_node_t structure(s) need to be @@ -368,8 +354,6 @@ static int airo_config(struct pcmcia_device *link) kfree(req); return 0; - cs_failed: - cs_error(link, last_fn, last_ret); failed: airo_release(link); kfree(req); @@ -386,7 +370,7 @@ static int airo_config(struct pcmcia_device *link) static void airo_release(struct pcmcia_device *link) { - DEBUG(0, "airo_release(0x%p)\n", link); + dev_dbg(&link->dev, "airo_release\n"); pcmcia_disable_device(link); } diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index ddaa859c349..78385722a76 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -55,22 +55,6 @@ #include "atmel.h" -/* - All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If - you do not define PCMCIA_DEBUG at all, all the debug code will be - left out. If you compile with PCMCIA_DEBUG=0, the debug code will - be present but disabled -- but it can then be enabled for specific - modules at load time with a 'pc_debug=#' option to insmod. -*/ - -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0); -static char *version = "$Revision: 1.2 $"; -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); -#else -#define DEBUG(n, args...) -#endif /*====================================================================*/ @@ -155,7 +139,7 @@ static int atmel_probe(struct pcmcia_device *p_dev) { local_info_t *local; - DEBUG(0, "atmel_attach()\n"); + dev_dbg(&p_dev->dev, "atmel_attach()\n"); /* Interrupt setup */ p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; @@ -194,7 +178,7 @@ static int atmel_probe(struct pcmcia_device *p_dev) static void atmel_detach(struct pcmcia_device *link) { - DEBUG(0, "atmel_detach(0x%p)\n", link); + dev_dbg(&link->dev, "atmel_detach\n"); atmel_release(link); @@ -209,9 +193,6 @@ static void atmel_detach(struct pcmcia_device *link) ======================================================================*/ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - /* Call-back function to interrogate PCMCIA-specific information about the current existance of the card */ static int card_present(void *arg) @@ -275,13 +256,13 @@ static int atmel_config_check(struct pcmcia_device *p_dev, static int atmel_config(struct pcmcia_device *link) { local_info_t *dev; - int last_fn, last_ret; + int ret; struct pcmcia_device_id *did; dev = link->priv; did = dev_get_drvdata(&handle_to_dev(link)); - DEBUG(0, "atmel_config(0x%p)\n", link); + dev_dbg(&link->dev, "atmel_config\n"); /* In this loop, we scan the CIS for configuration table entries, @@ -303,20 +284,25 @@ static int atmel_config(struct pcmcia_device *link) handler to the interrupt, unless the 'Handler' member of the irq structure is initialized. */ - if (link->conf.Attributes & CONF_ENABLE_IRQ) - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + if (link->conf.Attributes & CONF_ENABLE_IRQ) { + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + } /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; if (link->irq.AssignedIRQ == 0) { printk(KERN_ALERT "atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config."); - goto cs_failed; + goto failed; } ((local_info_t*)link->priv)->eth_dev = @@ -327,7 +313,7 @@ static int atmel_config(struct pcmcia_device *link) card_present, link); if (!((local_info_t*)link->priv)->eth_dev) - goto cs_failed; + goto failed; /* @@ -340,8 +326,6 @@ static int atmel_config(struct pcmcia_device *link) return 0; - cs_failed: - cs_error(link, last_fn, last_ret); failed: atmel_release(link); return -ENODEV; @@ -359,7 +343,7 @@ static void atmel_release(struct pcmcia_device *link) { struct net_device *dev = ((local_info_t*)link->priv)->eth_dev; - DEBUG(0, "atmel_release(0x%p)\n", link); + dev_dbg(&link->dev, "atmel_release\n"); if (dev) stop_atmel_card(dev); diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 31b60dd87bf..ca3ab849ac0 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -510,10 +510,6 @@ static void prism2_detach(struct pcmcia_device *link) } -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - - /* run after a CARD_INSERTION event is received to configure the PCMCIA * socket and make the device available to the system */ @@ -605,7 +601,6 @@ static int prism2_config(struct pcmcia_device *link) struct hostap_interface *iface; local_info_t *local; int ret = 1; - int last_fn, last_ret; struct hostap_cs_priv *hw_priv; PDEBUG(DEBUG_FLOW, "prism2_config()\n"); @@ -617,13 +612,12 @@ static int prism2_config(struct pcmcia_device *link) } /* Look for an appropriate configuration table entry in the CIS */ - last_ret = pcmcia_loop_config(link, prism2_config_check, NULL); - if (last_ret) { + ret = pcmcia_loop_config(link, prism2_config_check, NULL); + if (ret) { if (!ignore_cis_vcc) printk(KERN_ERR "GetNextTuple(): No matching " "CIS configuration. Maybe you need the " "ignore_cis_vcc=1 parameter.\n"); - cs_error(link, RequestIO, last_ret); goto failed; } @@ -652,8 +646,9 @@ static int prism2_config(struct pcmcia_device *link) link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = prism2_interrupt; link->irq.Instance = dev; - CS_CHECK(RequestIRQ, - pcmcia_request_irq(link, &link->irq)); + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; } /* @@ -661,8 +656,9 @@ static int prism2_config(struct pcmcia_device *link) * the I/O windows and the interrupt mapping, and putting the * card and host interface into "Memory and IO" mode. */ - CS_CHECK(RequestConfiguration, - pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; @@ -695,9 +691,6 @@ static int prism2_config(struct pcmcia_device *link) } return ret; - cs_failed: - cs_error(link, last_fn, last_ret); - failed: kfree(hw_priv); prism2_release((u_long)link); diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index 9498b46c99a..cbd85de0c60 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -145,23 +145,6 @@ static const unsigned int txConfEUD = 0x10; /* Enable Uni-Data packets */ static const unsigned int txConfKey = 0x02; /* Scramble data packets */ static const unsigned int txConfLoop = 0x01; /* Loopback mode */ -/* - All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If - you do not define PCMCIA_DEBUG at all, all the debug code will be - left out. If you compile with PCMCIA_DEBUG=0, the debug code will - be present but disabled -- but it can then be enabled for specific - modules at load time with a 'pc_debug=#' option to insmod. -*/ - -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"netwave_cs.c 0.3.0 Thu Jul 17 14:36:02 1997 (John Markus Bjørndalen)\n"; -#else -#define DEBUG(n, args...) -#endif /*====================================================================*/ @@ -383,7 +366,7 @@ static int netwave_probe(struct pcmcia_device *link) struct net_device *dev; netwave_private *priv; - DEBUG(0, "netwave_attach()\n"); + dev_dbg(&link->dev, "netwave_attach()\n"); /* Initialize the struct pcmcia_device structure */ dev = alloc_etherdev(sizeof(netwave_private)); @@ -438,7 +421,7 @@ static void netwave_detach(struct pcmcia_device *link) { struct net_device *dev = link->priv; - DEBUG(0, "netwave_detach(0x%p)\n", link); + dev_dbg(&link->dev, "netwave_detach\n"); netwave_release(link); @@ -725,18 +708,15 @@ static const struct iw_handler_def netwave_handler_def = * */ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int netwave_pcmcia_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; netwave_private *priv = netdev_priv(dev); - int i, j, last_ret, last_fn; + int i, j, ret; win_req_t req; memreq_t mem; u_char __iomem *ramBase = NULL; - DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link); + dev_dbg(&link->dev, "netwave_pcmcia_config\n"); /* * Try allocating IO ports. This tries a few fixed addresses. @@ -749,22 +729,24 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { if (i == 0) break; } - if (i != 0) { - cs_error(link, RequestIO, i); + if (i != 0) goto failed; - } /* * Now allocate an interrupt line. Note that this does not * actually assign a handler to the interrupt. */ - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; /* * This actually configures the PCMCIA socket -- setting up * the I/O windows and the interrupt mapping. */ - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; /* * Allocate a 32K memory window. Note that the struct pcmcia_device @@ -772,14 +754,18 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { * device needs several windows, you'll need to keep track of * the handles in your private data structure, dev->priv. */ - DEBUG(1, "Setting mem speed of %d\n", mem_speed); + dev_dbg(&link->dev, "Setting mem speed of %d\n", mem_speed); req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_CM|WIN_ENABLE; req.Base = 0; req.Size = 0x8000; req.AccessSpeed = mem_speed; - CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &link->win)); + ret = pcmcia_request_window(&link, &req, &link->win); + if (ret) + goto failed; mem.CardOffset = 0x20000; mem.Page = 0; - CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); + ret = pcmcia_map_mem_page(link->win, &mem); + if (ret) + goto failed; /* Store base address of the common window frame */ ramBase = ioremap(req.Base, 0x8000); @@ -818,8 +804,6 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { get_uint16(ramBase + NETWAVE_EREG_ARW+2)); return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: netwave_release(link); return -ENODEV; @@ -837,7 +821,7 @@ static void netwave_release(struct pcmcia_device *link) struct net_device *dev = link->priv; netwave_private *priv = netdev_priv(dev); - DEBUG(0, "netwave_release(0x%p)\n", link); + dev_dbg(&link->dev, "netwave_release\n"); pcmcia_disable_device(link); if (link->win) @@ -892,7 +876,7 @@ static void netwave_reset(struct net_device *dev) { u_char __iomem *ramBase = priv->ramBase; unsigned int iobase = dev->base_addr; - DEBUG(0, "netwave_reset: Done with hardware reset\n"); + pr_debug("netwave_reset: Done with hardware reset\n"); priv->timeoutCounter = 0; @@ -988,7 +972,7 @@ static int netwave_hw_xmit(unsigned char* data, int len, dev->stats.tx_bytes += len; - DEBUG(3, "Transmitting with SPCQ %x SPU %x LIF %x ISPLQ %x\n", + pr_debug("Transmitting with SPCQ %x SPU %x LIF %x ISPLQ %x\n", readb(ramBase + NETWAVE_EREG_SPCQ), readb(ramBase + NETWAVE_EREG_SPU), readb(ramBase + NETWAVE_EREG_LIF), @@ -1000,7 +984,7 @@ static int netwave_hw_xmit(unsigned char* data, int len, MaxData = get_uint16(ramBase + NETWAVE_EREG_TDP+2); DataOffset = get_uint16(ramBase + NETWAVE_EREG_TDP+4); - DEBUG(3, "TxFreeList %x, MaxData %x, DataOffset %x\n", + pr_debug("TxFreeList %x, MaxData %x, DataOffset %x\n", TxFreeList, MaxData, DataOffset); /* Copy packet to the adapter fragment buffers */ @@ -1088,7 +1072,7 @@ static irqreturn_t netwave_interrupt(int irq, void* dev_id) status = inb(iobase + NETWAVE_REG_ASR); if (!pcmcia_dev_present(link)) { - DEBUG(1, "netwave_interrupt: Interrupt with status 0x%x " + pr_debug("netwave_interrupt: Interrupt with status 0x%x " "from removed or suspended card!\n", status); break; } @@ -1132,7 +1116,7 @@ static irqreturn_t netwave_interrupt(int irq, void* dev_id) int txStatus; txStatus = readb(ramBase + NETWAVE_EREG_TSER); - DEBUG(3, "Transmit done. TSER = %x id %x\n", + pr_debug("Transmit done. TSER = %x id %x\n", txStatus, readb(ramBase + NETWAVE_EREG_TSER + 1)); if (txStatus & 0x20) { @@ -1156,7 +1140,7 @@ static irqreturn_t netwave_interrupt(int irq, void* dev_id) * TxGU and TxNOAP is set. (Those are the only ones * to set TxErr). */ - DEBUG(3, "netwave_interrupt: TxDN with error status %x\n", + pr_debug("netwave_interrupt: TxDN with error status %x\n", txStatus); /* Clear out TxGU, TxNOAP, TxErr and TxTrys */ @@ -1164,7 +1148,7 @@ static irqreturn_t netwave_interrupt(int irq, void* dev_id) writeb(0xdf & txStatus, ramBase+NETWAVE_EREG_TSER+4); ++dev->stats.tx_errors; } - DEBUG(3, "New status is TSER %x ASR %x\n", + pr_debug("New status is TSER %x ASR %x\n", readb(ramBase + NETWAVE_EREG_TSER), inb(iobase + NETWAVE_REG_ASR)); @@ -1172,7 +1156,7 @@ static irqreturn_t netwave_interrupt(int irq, void* dev_id) } /* TxBA, this would trigger on all error packets received */ /* if (status & 0x01) { - DEBUG(4, "Transmit buffers available, %x\n", status); + pr_debug("Transmit buffers available, %x\n", status); } */ } @@ -1190,7 +1174,7 @@ static irqreturn_t netwave_interrupt(int irq, void* dev_id) */ static void netwave_watchdog(struct net_device *dev) { - DEBUG(1, "%s: netwave_watchdog: watchdog timer expired\n", dev->name); + pr_debug("%s: netwave_watchdog: watchdog timer expired\n", dev->name); netwave_reset(dev); dev->trans_start = jiffies; netif_wake_queue(dev); @@ -1211,7 +1195,7 @@ static int netwave_rx(struct net_device *dev) int i; u_char *ptr; - DEBUG(3, "xinw_rx: Receiving ... \n"); + pr_debug("xinw_rx: Receiving ... \n"); /* Receive max 10 packets for now. */ for (i = 0; i < 10; i++) { @@ -1237,7 +1221,7 @@ static int netwave_rx(struct net_device *dev) skb = dev_alloc_skb(rcvLen+5); if (skb == NULL) { - DEBUG(1, "netwave_rx: Could not allocate an sk_buff of " + pr_debug("netwave_rx: Could not allocate an sk_buff of " "length %d\n", rcvLen); ++dev->stats.rx_dropped; /* Tell the adapter to skip the packet */ @@ -1279,7 +1263,7 @@ static int netwave_rx(struct net_device *dev) wait_WOC(iobase); writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0); writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); - DEBUG(3, "Packet reception ok\n"); + pr_debug("Packet reception ok\n"); } return 0; } @@ -1288,7 +1272,7 @@ static int netwave_open(struct net_device *dev) { netwave_private *priv = netdev_priv(dev); struct pcmcia_device *link = priv->p_dev; - DEBUG(1, "netwave_open: starting.\n"); + dev_dbg(&link->dev, "netwave_open: starting.\n"); if (!pcmcia_dev_present(link)) return -ENODEV; @@ -1305,7 +1289,7 @@ static int netwave_close(struct net_device *dev) { netwave_private *priv = netdev_priv(dev); struct pcmcia_device *link = priv->p_dev; - DEBUG(1, "netwave_close: finishing.\n"); + dev_dbg(&link->dev, "netwave_close: finishing.\n"); link->open--; netif_stop_queue(dev); @@ -1358,11 +1342,11 @@ static void set_multicast_list(struct net_device *dev) u_char rcvMode = 0; #ifdef PCMCIA_DEBUG - if (pc_debug > 2) { - static int old; + { + xstatic int old; if (old != dev->mc_count) { old = dev->mc_count; - DEBUG(0, "%s: setting Rx mode to %d addresses.\n", + pr_debug("%s: setting Rx mode to %d addresses.\n", dev->name, dev->mc_count); } } diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index 38c1c9d2abb..da626ec663d 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -160,12 +160,6 @@ static void orinoco_cs_detach(struct pcmcia_device *link) * device available to the system. */ -#define CS_CHECK(fn, ret) do { \ - last_fn = (fn); \ - if ((last_ret = (ret)) != 0) \ - goto cs_failed; \ -} while (0) - static int orinoco_cs_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, cistpl_cftable_entry_t *dflt, @@ -240,7 +234,7 @@ orinoco_cs_config(struct pcmcia_device *link) struct orinoco_private *priv = link->priv; struct orinoco_pccard *card = priv->card; hermes_t *hw = &priv->hw; - int last_fn, last_ret; + int ret; void __iomem *mem; /* @@ -257,13 +251,12 @@ orinoco_cs_config(struct pcmcia_device *link) * and most client drivers will only use the CIS to fill in * implementation-defined details. */ - last_ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL); - if (last_ret) { + ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL); + if (ret) { if (!ignore_cis_vcc) printk(KERN_ERR PFX "GetNextTuple(): No matching " "CIS configuration. Maybe you need the " "ignore_cis_vcc=1 parameter.\n"); - cs_error(link, RequestIO, last_ret); goto failed; } @@ -272,14 +265,16 @@ orinoco_cs_config(struct pcmcia_device *link) * a handler to the interrupt, unless the 'Handler' member of * the irq structure is initialized. */ - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; /* We initialize the hermes structure before completing PCMCIA * configuration just in case the interrupt handler gets * called. */ mem = ioport_map(link->io.BasePort1, link->io.NumPorts1); if (!mem) - goto cs_failed; + goto failed; hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); @@ -288,8 +283,9 @@ orinoco_cs_config(struct pcmcia_device *link) * the I/O windows and the interrupt mapping, and putting the * card and host interface into "Memory and IO" mode. */ - CS_CHECK(RequestConfiguration, - pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; /* Ok, we have the configuration, prepare to register the netdev */ card->node.major = card->node.minor = 0; @@ -315,9 +311,6 @@ orinoco_cs_config(struct pcmcia_device *link) * net_device has been registered */ return 0; - cs_failed: - cs_error(link, last_fn, last_ret); - failed: orinoco_cs_release(link); return -ENODEV; diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index c361310b885..700010e9e34 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -73,9 +73,6 @@ static void spectrum_cs_release(struct pcmcia_device *link); #define HCR_MEM16 0x10 /* memory width bit, should be preserved */ -#define CS_CHECK(fn, ret) \ - do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - /* * Reset the card using configuration registers COR and CCSR. * If IDLE is 1, stop the firmware, so that it can be safely rewritten. @@ -83,7 +80,7 @@ static void spectrum_cs_release(struct pcmcia_device *link); static int spectrum_reset(struct pcmcia_device *link, int idle) { - int last_ret, last_fn; + int ret; conf_reg_t reg; u_int save_cor; @@ -95,23 +92,26 @@ spectrum_reset(struct pcmcia_device *link, int idle) reg.Function = 0; reg.Action = CS_READ; reg.Offset = CISREG_COR; - CS_CHECK(AccessConfigurationRegister, - pcmcia_access_configuration_register(link, ®)); + ret = pcmcia_access_configuration_register(link, ®); + if (ret) + goto failed; save_cor = reg.Value; /* Soft-Reset card */ reg.Action = CS_WRITE; reg.Offset = CISREG_COR; reg.Value = (save_cor | COR_SOFT_RESET); - CS_CHECK(AccessConfigurationRegister, - pcmcia_access_configuration_register(link, ®)); + ret = pcmcia_access_configuration_register(link, ®); + if (ret) + goto failed; udelay(1000); /* Read CCSR */ reg.Action = CS_READ; reg.Offset = CISREG_CCSR; - CS_CHECK(AccessConfigurationRegister, - pcmcia_access_configuration_register(link, ®)); + ret = pcmcia_access_configuration_register(link, ®); + if (ret) + goto failed; /* * Start or stop the firmware. Memory width bit should be @@ -120,21 +120,22 @@ spectrum_reset(struct pcmcia_device *link, int idle) reg.Action = CS_WRITE; reg.Offset = CISREG_CCSR; reg.Value = (idle ? HCR_IDLE : HCR_RUN) | (reg.Value & HCR_MEM16); - CS_CHECK(AccessConfigurationRegister, - pcmcia_access_configuration_register(link, ®)); + ret = pcmcia_access_configuration_register(link, ®); + if (ret) + goto failed; udelay(1000); /* Restore original COR configuration index */ reg.Action = CS_WRITE; reg.Offset = CISREG_COR; reg.Value = (save_cor & ~COR_SOFT_RESET); - CS_CHECK(AccessConfigurationRegister, - pcmcia_access_configuration_register(link, ®)); + ret = pcmcia_access_configuration_register(link, ®); + if (ret) + goto failed; udelay(1000); return 0; -cs_failed: - cs_error(link, last_fn, last_ret); +failed: return -ENODEV; } @@ -307,7 +308,7 @@ spectrum_cs_config(struct pcmcia_device *link) struct orinoco_private *priv = link->priv; struct orinoco_pccard *card = priv->card; hermes_t *hw = &priv->hw; - int last_fn, last_ret; + int ret; void __iomem *mem; /* @@ -324,13 +325,12 @@ spectrum_cs_config(struct pcmcia_device *link) * and most client drivers will only use the CIS to fill in * implementation-defined details. */ - last_ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL); - if (last_ret) { + ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL); + if (ret) { if (!ignore_cis_vcc) printk(KERN_ERR PFX "GetNextTuple(): No matching " "CIS configuration. Maybe you need the " "ignore_cis_vcc=1 parameter.\n"); - cs_error(link, RequestIO, last_ret); goto failed; } @@ -339,14 +339,16 @@ spectrum_cs_config(struct pcmcia_device *link) * a handler to the interrupt, unless the 'Handler' member of * the irq structure is initialized. */ - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; /* We initialize the hermes structure before completing PCMCIA * configuration just in case the interrupt handler gets * called. */ mem = ioport_map(link->io.BasePort1, link->io.NumPorts1); if (!mem) - goto cs_failed; + goto failed; hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); @@ -355,8 +357,9 @@ spectrum_cs_config(struct pcmcia_device *link) * the I/O windows and the interrupt mapping, and putting the * card and host interface into "Memory and IO" mode. */ - CS_CHECK(RequestConfiguration, - pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; /* Ok, we have the configuration, prepare to register the netdev */ card->node.major = card->node.minor = 0; @@ -386,9 +389,6 @@ spectrum_cs_config(struct pcmcia_device *link) * net_device has been registered */ return 0; - cs_failed: - cs_error(link, last_fn, last_ret); - failed: spectrum_cs_release(link); return -ENODEV; diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 431a20ec6db..2fad4ac8982 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -3656,10 +3656,7 @@ wv_pcmcia_reset(struct net_device * dev) i = pcmcia_access_configuration_register(link, ®); if (i != 0) - { - cs_error(link, AccessConfigurationRegister, i); return FALSE; - } #ifdef DEBUG_CONFIG_INFO printk(KERN_DEBUG "%s: wavelan_pcmcia_reset(): Config reg is 0x%x\n", @@ -3670,19 +3667,13 @@ wv_pcmcia_reset(struct net_device * dev) reg.Value = reg.Value | COR_SW_RESET; i = pcmcia_access_configuration_register(link, ®); if (i != 0) - { - cs_error(link, AccessConfigurationRegister, i); return FALSE; - } reg.Action = CS_WRITE; reg.Value = COR_LEVEL_IRQ | COR_CONFIG; i = pcmcia_access_configuration_register(link, ®); if (i != 0) - { - cs_error(link, AccessConfigurationRegister, i); return FALSE; - } #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <-wv_pcmcia_reset()\n", dev->name); @@ -3857,10 +3848,7 @@ wv_pcmcia_config(struct pcmcia_device * link) { i = pcmcia_request_io(link, &link->io); if (i != 0) - { - cs_error(link, RequestIO, i); break; - } /* * Now allocate an interrupt line. Note that this does not @@ -3868,10 +3856,7 @@ wv_pcmcia_config(struct pcmcia_device * link) */ i = pcmcia_request_irq(link, &link->irq); if (i != 0) - { - cs_error(link, RequestIRQ, i); break; - } /* * This actually configures the PCMCIA socket -- setting up @@ -3880,10 +3865,7 @@ wv_pcmcia_config(struct pcmcia_device * link) link->conf.ConfigIndex = 1; i = pcmcia_request_configuration(link, &link->conf); if (i != 0) - { - cs_error(link, RequestConfiguration, i); break; - } /* * Allocate a small memory window. Note that the struct pcmcia_device @@ -3896,10 +3878,7 @@ wv_pcmcia_config(struct pcmcia_device * link) req.AccessSpeed = mem_speed; i = pcmcia_request_window(&link, &req, &link->win); if (i != 0) - { - cs_error(link, RequestWindow, i); break; - } lp->mem = ioremap(req.Base, req.Size); dev->mem_start = (u_long)lp->mem; @@ -3908,10 +3887,7 @@ wv_pcmcia_config(struct pcmcia_device * link) mem.CardOffset = 0; mem.Page = 0; i = pcmcia_map_mem_page(link->win, &mem); if (i != 0) - { - cs_error(link, MapMemPage, i); break; - } /* Feed device with this info... */ dev->irq = link->irq.AssignedIRQ; diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 4f1e0cfe609..7e8e269b4cb 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -67,23 +67,7 @@ /* For rough constant delay */ #define WL3501_NOPLOOP(n) { int x = 0; while (x++ < n) slow_down_io(); } -/* - * All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If you do not - * define PCMCIA_DEBUG at all, all the debug code will be left out. If you - * compile with PCMCIA_DEBUG=0, the debug code will be present but disabled -- - * but it can then be enabled for specific modules at load time with a - * 'pc_debug=#' option to insmod. - */ -#define PCMCIA_DEBUG 0 -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0); -#define dprintk(n, format, args...) \ - { if (pc_debug > (n)) \ - printk(KERN_INFO "%s: " format "\n", __func__ , ##args); } -#else -#define dprintk(n, format, args...) -#endif + #define wl3501_outb(a, b) { outb(a, b); slow_down_io(); } #define wl3501_outb_p(a, b) { outb_p(a, b); slow_down_io(); } @@ -684,10 +668,10 @@ static void wl3501_mgmt_scan_confirm(struct wl3501_card *this, u16 addr) int matchflag = 0; struct wl3501_scan_confirm sig; - dprintk(3, "entry"); + pr_debug("entry"); wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); if (sig.status == WL3501_STATUS_SUCCESS) { - dprintk(3, "success"); + pr_debug("success"); if ((this->net_type == IW_MODE_INFRA && (sig.cap_info & WL3501_MGMT_CAPABILITY_ESS)) || (this->net_type == IW_MODE_ADHOC && @@ -722,7 +706,7 @@ static void wl3501_mgmt_scan_confirm(struct wl3501_card *this, u16 addr) } } } else if (sig.status == WL3501_STATUS_TIMEOUT) { - dprintk(3, "timeout"); + pr_debug("timeout"); this->join_sta_bss = 0; for (i = this->join_sta_bss; i < this->bss_cnt; i++) if (!wl3501_mgmt_join(this, i)) @@ -879,7 +863,7 @@ static int wl3501_mgmt_auth(struct wl3501_card *this) .timeout = 1000, }; - dprintk(3, "entry"); + pr_debug("entry"); memcpy(sig.mac_addr, this->bssid, ETH_ALEN); return wl3501_esbq_exec(this, &sig, sizeof(sig)); } @@ -893,7 +877,7 @@ static int wl3501_mgmt_association(struct wl3501_card *this) .cap_info = this->cap_info, }; - dprintk(3, "entry"); + pr_debug("entry"); memcpy(sig.mac_addr, this->bssid, ETH_ALEN); return wl3501_esbq_exec(this, &sig, sizeof(sig)); } @@ -903,7 +887,7 @@ static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr) struct wl3501_card *this = netdev_priv(dev); struct wl3501_join_confirm sig; - dprintk(3, "entry"); + pr_debug("entry"); wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); if (sig.status == WL3501_STATUS_SUCCESS) { if (this->net_type == IW_MODE_INFRA) { @@ -962,7 +946,7 @@ static inline void wl3501_md_confirm_interrupt(struct net_device *dev, { struct wl3501_md_confirm sig; - dprintk(3, "entry"); + pr_debug("entry"); wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); wl3501_free_tx_buffer(this, sig.data); if (netif_queue_stopped(dev)) @@ -1017,7 +1001,7 @@ static inline void wl3501_md_ind_interrupt(struct net_device *dev, static inline void wl3501_get_confirm_interrupt(struct wl3501_card *this, u16 addr, void *sig, int size) { - dprintk(3, "entry"); + pr_debug("entry"); wl3501_get_from_wla(this, addr, &this->sig_get_confirm, sizeof(this->sig_get_confirm)); wake_up(&this->wait); @@ -1029,7 +1013,7 @@ static inline void wl3501_start_confirm_interrupt(struct net_device *dev, { struct wl3501_start_confirm sig; - dprintk(3, "entry"); + pr_debug("entry"); wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); if (sig.status == WL3501_STATUS_SUCCESS) netif_wake_queue(dev); @@ -1041,7 +1025,7 @@ static inline void wl3501_assoc_confirm_interrupt(struct net_device *dev, struct wl3501_card *this = netdev_priv(dev); struct wl3501_assoc_confirm sig; - dprintk(3, "entry"); + pr_debug("entry"); wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); if (sig.status == WL3501_STATUS_SUCCESS) @@ -1053,7 +1037,7 @@ static inline void wl3501_auth_confirm_interrupt(struct wl3501_card *this, { struct wl3501_auth_confirm sig; - dprintk(3, "entry"); + pr_debug("entry"); wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); if (sig.status == WL3501_STATUS_SUCCESS) @@ -1069,7 +1053,7 @@ static inline void wl3501_rx_interrupt(struct net_device *dev) u8 sig_id; struct wl3501_card *this = netdev_priv(dev); - dprintk(3, "entry"); + pr_debug("entry"); loop: morepkts = 0; if (!wl3501_esbq_confirm(this)) @@ -1302,7 +1286,7 @@ static int wl3501_reset(struct net_device *dev) wl3501_ack_interrupt(this); wl3501_unblock_interrupt(this); wl3501_mgmt_scan(this, 100); - dprintk(1, "%s: device reset", dev->name); + pr_debug("%s: device reset", dev->name); rc = 0; out: return rc; @@ -1376,7 +1360,7 @@ static int wl3501_open(struct net_device *dev) link->open++; /* Initial WL3501 firmware */ - dprintk(1, "%s: Initialize WL3501 firmware...", dev->name); + pr_debug("%s: Initialize WL3501 firmware...", dev->name); if (wl3501_init_firmware(this)) goto fail; /* Initial device variables */ @@ -1388,7 +1372,7 @@ static int wl3501_open(struct net_device *dev) wl3501_unblock_interrupt(this); wl3501_mgmt_scan(this, 100); rc = 0; - dprintk(1, "%s: WL3501 opened", dev->name); + pr_debug("%s: WL3501 opened", dev->name); printk(KERN_INFO "%s: Card Name: %s\n" "%s: Firmware Date: %s\n", dev->name, this->card_name, @@ -1945,9 +1929,6 @@ out_link: return -ENOMEM; } -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - /** * wl3501_config - configure the PCMCIA socket and make eth device available * @link - FILL_IN @@ -1959,7 +1940,7 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static int wl3501_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; - int i = 0, j, last_fn, last_ret; + int i = 0, j, ret; struct wl3501_card *this; /* Try allocating IO ports. This tries a few fixed addresses. If you @@ -1975,20 +1956,22 @@ static int wl3501_config(struct pcmcia_device *link) if (i == 0) break; } - if (i != 0) { - cs_error(link, RequestIO, i); + if (i != 0) goto failed; - } /* Now allocate an interrupt line. Note that this does not actually * assign a handler to the interrupt. */ - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; /* This actually configures the PCMCIA socket -- setting up the I/O * windows and the interrupt mapping. */ - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; @@ -2041,8 +2024,6 @@ static int wl3501_config(struct pcmcia_device *link) netif_start_queue(dev); return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: wl3501_release(link); return -ENODEV; From 3e7166178a83fef690dcbfcdaeda192f7282a9a4 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 24 Oct 2009 15:54:14 +0200 Subject: [PATCH 098/298] pcmcia: use dynamic debug infrastructure, deprecate CS_CHECK (scsi) Convert PCMCIA drivers to use the dynamic debug infrastructure, instead of requiring manual settings of PCMCIA_DEBUG. Also, remove all usages of the CS_CHECK macro and replace them with proper Linux style calling and return value checking. The extra error reporting may be dropped, as the PCMCIA core already complains about any (non-driver-author) errors. CC: linux-scsi@vger.kernel.org Signed-off-by: Dominik Brodowski --- drivers/scsi/pcmcia/aha152x_stub.c | 41 ++++++++++------------------ drivers/scsi/pcmcia/fdomain_stub.c | 43 ++++++++++------------------- drivers/scsi/pcmcia/qlogic_stub.c | 44 +++++++++++------------------- drivers/scsi/pcmcia/sym53c500_cs.c | 41 ++++++++++------------------ 4 files changed, 60 insertions(+), 109 deletions(-) diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index 67cde013806..4329e4e5043 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c @@ -54,15 +54,6 @@ #include #include -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0644); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"aha152x_cs.c 1.54 2000/06/12 21:27:25 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif /*====================================================================*/ @@ -103,7 +94,7 @@ static int aha152x_probe(struct pcmcia_device *link) { scsi_info_t *info; - DEBUG(0, "aha152x_attach()\n"); + dev_dbg(&link->dev, "aha152x_attach()\n"); /* Create new SCSI device */ info = kzalloc(sizeof(*info), GFP_KERNEL); @@ -127,7 +118,7 @@ static int aha152x_probe(struct pcmcia_device *link) static void aha152x_detach(struct pcmcia_device *link) { - DEBUG(0, "aha152x_detach(0x%p)\n", link); + dev_dbg(&link->dev, "aha152x_detach\n"); aha152x_release_cs(link); @@ -137,9 +128,6 @@ static void aha152x_detach(struct pcmcia_device *link) /*====================================================================*/ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int aha152x_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, cistpl_cftable_entry_t *dflt, @@ -164,19 +152,22 @@ static int aha152x_config_cs(struct pcmcia_device *link) { scsi_info_t *info = link->priv; struct aha152x_setup s; - int last_ret, last_fn; + int ret; struct Scsi_Host *host; - DEBUG(0, "aha152x_config(0x%p)\n", link); + dev_dbg(&link->dev, "aha152x_config\n"); - last_ret = pcmcia_loop_config(link, aha152x_config_check, NULL); - if (last_ret) { - cs_error(link, RequestIO, last_ret); - goto failed; - } + ret = pcmcia_loop_config(link, aha152x_config_check, NULL); + if (ret) + goto failed; - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; /* Set configuration options for the aha152x driver */ memset(&s, 0, sizeof(s)); @@ -194,7 +185,7 @@ static int aha152x_config_cs(struct pcmcia_device *link) host = aha152x_probe_one(&s); if (host == NULL) { printk(KERN_INFO "aha152x_cs: no SCSI devices found\n"); - goto cs_failed; + goto failed; } sprintf(info->node.dev_name, "scsi%d", host->host_no); @@ -203,8 +194,6 @@ static int aha152x_config_cs(struct pcmcia_device *link) return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: aha152x_release_cs(link); return -ENODEV; diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c index 06254f46a0d..5792b55c9d3 100644 --- a/drivers/scsi/pcmcia/fdomain_stub.c +++ b/drivers/scsi/pcmcia/fdomain_stub.c @@ -59,16 +59,6 @@ MODULE_AUTHOR("David Hinds "); MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver"); MODULE_LICENSE("Dual MPL/GPL"); -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"fdomain_cs.c 1.47 2001/10/13 00:08:52 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - /*====================================================================*/ typedef struct scsi_info_t { @@ -86,7 +76,7 @@ static int fdomain_probe(struct pcmcia_device *link) { scsi_info_t *info; - DEBUG(0, "fdomain_attach()\n"); + dev_dbg(&link->dev, "fdomain_attach()\n"); /* Create new SCSI device */ info = kzalloc(sizeof(*info), GFP_KERNEL); @@ -111,7 +101,7 @@ static int fdomain_probe(struct pcmcia_device *link) static void fdomain_detach(struct pcmcia_device *link) { - DEBUG(0, "fdomain_detach(0x%p)\n", link); + dev_dbg(&link->dev, "fdomain_detach\n"); fdomain_release(link); @@ -120,9 +110,6 @@ static void fdomain_detach(struct pcmcia_device *link) /*====================================================================*/ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int fdomain_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, cistpl_cftable_entry_t *dflt, @@ -137,20 +124,22 @@ static int fdomain_config_check(struct pcmcia_device *p_dev, static int fdomain_config(struct pcmcia_device *link) { scsi_info_t *info = link->priv; - int last_ret, last_fn; + int ret; char str[22]; struct Scsi_Host *host; - DEBUG(0, "fdomain_config(0x%p)\n", link); + dev_dbg(&link->dev, "fdomain_config\n"); - last_ret = pcmcia_loop_config(link, fdomain_config_check, NULL); - if (last_ret) { - cs_error(link, RequestIO, last_ret); + ret = pcmcia_loop_config(link, fdomain_config_check, NULL); + if (ret) goto failed; - } - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; /* A bad hack... */ release_region(link->io.BasePort1, link->io.NumPorts1); @@ -162,11 +151,11 @@ static int fdomain_config(struct pcmcia_device *link) host = __fdomain_16x0_detect(&fdomain_driver_template); if (!host) { printk(KERN_INFO "fdomain_cs: no SCSI devices found\n"); - goto cs_failed; + goto failed; } if (scsi_add_host(host, NULL)) - goto cs_failed; + goto failed; scsi_scan_host(host); sprintf(info->node.dev_name, "scsi%d", host->host_no); @@ -175,8 +164,6 @@ static int fdomain_config(struct pcmcia_device *link) return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: fdomain_release(link); return -ENODEV; @@ -188,7 +175,7 @@ static void fdomain_release(struct pcmcia_device *link) { scsi_info_t *info = link->priv; - DEBUG(0, "fdomain_release(0x%p)\n", link); + dev_dbg(&link->dev, "fdomain_release\n"); scsi_remove_host(info->host); pcmcia_disable_device(link); diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c index 20c3e5e6d88..65d7ad58433 100644 --- a/drivers/scsi/pcmcia/qlogic_stub.c +++ b/drivers/scsi/pcmcia/qlogic_stub.c @@ -62,15 +62,6 @@ static char qlogic_name[] = "qlogic_cs"; -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0644); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = "qlogic_cs.c 1.79-ac 2002/10/26 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - static struct scsi_host_template qlogicfas_driver_template = { .module = THIS_MODULE, .name = qlogic_name, @@ -159,7 +150,7 @@ static int qlogic_probe(struct pcmcia_device *link) { scsi_info_t *info; - DEBUG(0, "qlogic_attach()\n"); + dev_dbg(&link->dev, "qlogic_attach()\n"); /* Create new SCSI device */ info = kzalloc(sizeof(*info), GFP_KERNEL); @@ -183,7 +174,7 @@ static int qlogic_probe(struct pcmcia_device *link) static void qlogic_detach(struct pcmcia_device *link) { - DEBUG(0, "qlogic_detach(0x%p)\n", link); + dev_dbg(&link->dev, "qlogic_detach\n"); qlogic_release(link); kfree(link->priv); @@ -192,9 +183,6 @@ static void qlogic_detach(struct pcmcia_device *link) /*====================================================================*/ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int qlogic_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, cistpl_cftable_entry_t *dflt, @@ -213,19 +201,22 @@ static int qlogic_config_check(struct pcmcia_device *p_dev, static int qlogic_config(struct pcmcia_device * link) { scsi_info_t *info = link->priv; - int last_ret, last_fn; + int ret; struct Scsi_Host *host; - DEBUG(0, "qlogic_config(0x%p)\n", link); + dev_dbg(&link->dev, "qlogic_config\n"); - last_ret = pcmcia_loop_config(link, qlogic_config_check, NULL); - if (last_ret) { - cs_error(link, RequestIO, last_ret); + ret = pcmcia_loop_config(link, qlogic_config_check, NULL); + if (ret) goto failed; - } - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) { /* set ATAcmd */ @@ -244,7 +235,7 @@ static int qlogic_config(struct pcmcia_device * link) if (!host) { printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name); - goto cs_failed; + goto failed; } sprintf(info->node.dev_name, "scsi%d", host->host_no); @@ -253,12 +244,9 @@ static int qlogic_config(struct pcmcia_device * link) return 0; -cs_failed: - cs_error(link, last_fn, last_ret); - pcmcia_disable_device(link); failed: + pcmcia_disable_device(link); return -ENODEV; - } /* qlogic_config */ /*====================================================================*/ @@ -267,7 +255,7 @@ static void qlogic_release(struct pcmcia_device *link) { scsi_info_t *info = link->priv; - DEBUG(0, "qlogic_release(0x%p)\n", link); + dev_dbg(&link->dev, "qlogic_release\n"); scsi_remove_host(info->host); diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index b330c11a175..851a41ce4f0 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -77,17 +77,6 @@ #include #include -/* ================================================================== */ - -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"sym53c500_cs.c 0.9c 2004/10/27 (Bob Tracy)"; -#else -#define DEBUG(n, args...) -#endif /* ================================================================== */ @@ -525,7 +514,7 @@ SYM53C500_release(struct pcmcia_device *link) struct scsi_info_t *info = link->priv; struct Scsi_Host *shost = info->host; - DEBUG(0, "SYM53C500_release(0x%p)\n", link); + dev_dbg(&link->dev, "SYM53C500_release\n"); /* * Do this before releasing/freeing resources. @@ -697,9 +686,6 @@ static struct scsi_host_template sym53c500_driver_template = { .shost_attrs = SYM53C500_shost_attrs }; -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int SYM53C500_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, cistpl_cftable_entry_t *dflt, @@ -719,24 +705,27 @@ static int SYM53C500_config(struct pcmcia_device *link) { struct scsi_info_t *info = link->priv; - int last_ret, last_fn; + int ret; int irq_level, port_base; struct Scsi_Host *host; struct scsi_host_template *tpnt = &sym53c500_driver_template; struct sym53c500_data *data; - DEBUG(0, "SYM53C500_config(0x%p)\n", link); + dev_dbg(&link->dev, "SYM53C500_config\n"); info->manf_id = link->manf_id; - last_ret = pcmcia_loop_config(link, SYM53C500_config_check, NULL); - if (last_ret) { - cs_error(link, RequestIO, last_ret); + ret = pcmcia_loop_config(link, SYM53C500_config_check, NULL); + if (ret) goto failed; - } - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; /* * That's the trouble with copying liberally from another driver. @@ -824,8 +813,6 @@ err_release: printk(KERN_INFO "sym53c500_cs: no SCSI devices found\n"); return -ENODEV; -cs_failed: - cs_error(link, last_fn, last_ret); failed: SYM53C500_release(link); return -ENODEV; @@ -855,7 +842,7 @@ static int sym53c500_resume(struct pcmcia_device *link) static void SYM53C500_detach(struct pcmcia_device *link) { - DEBUG(0, "SYM53C500_detach(0x%p)\n", link); + dev_dbg(&link->dev, "SYM53C500_detach\n"); SYM53C500_release(link); @@ -868,7 +855,7 @@ SYM53C500_probe(struct pcmcia_device *link) { struct scsi_info_t *info; - DEBUG(0, "SYM53C500_attach()\n"); + dev_dbg(&link->dev, "SYM53C500_attach()\n"); /* Create new SCSI device */ info = kzalloc(sizeof(*info), GFP_KERNEL); From 9ec0bf41b5030ccc691049754ed1398cad5e953e Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 24 Oct 2009 15:54:46 +0200 Subject: [PATCH 099/298] pcmcia: use dynamic debug infrastructure, deprecate CS_CHECK (serial_cs) Convert PCMCIA drivers to use the dynamic debug infrastructure, instead of requiring manual settings of PCMCIA_DEBUG. Also, remove all usages of the CS_CHECK macro and replace them with proper Linux style calling and return value checking. The extra error reporting may be dropped, as the PCMCIA core already complains about any (non-driver-author) errors. CC: linux-serial@vger.kernel.org CC: Russell King Signed-off-by: Dominik Brodowski --- drivers/serial/serial_cs.c | 53 ++++++++++++-------------------------- 1 file changed, 17 insertions(+), 36 deletions(-) diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 7bf02cf3123..3b31bee8576 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -54,14 +54,6 @@ #include "8250.h" -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0644); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = "serial_cs.c 1.134 2002/05/04 05:48:53 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif /*====================================================================*/ @@ -121,24 +113,20 @@ static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_ static int quirk_post_ibm(struct pcmcia_device *link) { conf_reg_t reg = { 0, CS_READ, 0x800, 0 }; - int last_ret, last_fn; + int ret; + + ret = pcmcia_access_configuration_register(link, ®); + if (ret) + goto failed; - last_ret = pcmcia_access_configuration_register(link, ®); - if (last_ret) { - last_fn = AccessConfigurationRegister; - goto cs_failed; - } reg.Action = CS_WRITE; reg.Value = reg.Value | 1; - last_ret = pcmcia_access_configuration_register(link, ®); - if (last_ret) { - last_fn = AccessConfigurationRegister; - goto cs_failed; - } + ret = pcmcia_access_configuration_register(link, ®); + if (ret) + goto failed; return 0; - cs_failed: - cs_error(link, last_fn, last_ret); + failed: return -ENODEV; } @@ -283,7 +271,7 @@ static void serial_remove(struct pcmcia_device *link) struct serial_info *info = link->priv; int i; - DEBUG(0, "serial_release(0x%p)\n", link); + dev_dbg(&link->dev, "serial_release\n"); /* * Recheck to see if the device is still configured. @@ -334,7 +322,7 @@ static int serial_probe(struct pcmcia_device *link) { struct serial_info *info; - DEBUG(0, "serial_attach()\n"); + dev_dbg(&link->dev, "serial_attach()\n"); /* Create new serial device */ info = kzalloc(sizeof (*info), GFP_KERNEL); @@ -370,7 +358,7 @@ static void serial_detach(struct pcmcia_device *link) { struct serial_info *info = link->priv; - DEBUG(0, "serial_detach(0x%p)\n", link); + dev_dbg(&link->dev, "serial_detach\n"); /* * Ensure any outstanding scheduled tasks are completed. @@ -507,15 +495,13 @@ static int simple_config(struct pcmcia_device *link) printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n"); - cs_error(link, RequestIO, i); return -1; found_port: i = pcmcia_request_irq(link, &link->irq); - if (i != 0) { - cs_error(link, RequestIRQ, i); + if (i != 0) link->irq.AssignedIRQ = 0; - } + if (info->multi && (info->manfid == MANFID_3COM)) link->conf.ConfigIndex &= ~(0x08); @@ -526,10 +512,8 @@ found_port: info->quirk->config(link); i = pcmcia_request_configuration(link, &link->conf); - if (i != 0) { - cs_error(link, RequestConfiguration, i); + if (i != 0) return -1; - } return setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ); } @@ -598,7 +582,6 @@ static int multi_config(struct pcmcia_device *link) /* FIXME: comment does not fit, error handling does not fit */ printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n"); - cs_error(link, RequestIRQ, i); link->irq.AssignedIRQ = 0; } @@ -609,10 +592,8 @@ static int multi_config(struct pcmcia_device *link) info->quirk->config(link); i = pcmcia_request_configuration(link, &link->conf); - if (i != 0) { - cs_error(link, RequestConfiguration, i); + if (i != 0) return -ENODEV; - } /* The Oxford Semiconductor OXCF950 cards are in fact single-port: * 8 registers are for the UART, the others are extra registers. @@ -682,7 +663,7 @@ static int serial_config(struct pcmcia_device * link) struct serial_info *info = link->priv; int i; - DEBUG(0, "serial_config(0x%p)\n", link); + dev_dbg(&link->dev, "serial_config\n"); /* Is this a compliant multifunction card? */ info->multi = (link->socket->functions > 1); From 7c5af6ffd69bb2bb3c86b374153627529d67598c Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 24 Oct 2009 15:55:12 +0200 Subject: [PATCH 100/298] pcmcia: use dynamic debug infrastructure, deprecate CS_CHECK (sound) Convert PCMCIA drivers to use the dynamic debug infrastructure, instead of requiring manual settings of PCMCIA_DEBUG. Also, remove all usages of the CS_CHECK macro and replace them with proper Linux style calling and return value checking. The extra error reporting may be dropped, as the PCMCIA core already complains about any (non-driver-author) errors. CC: Jaroslav Kysela CC: alsa-devel@alsa-project.org Signed-off-by: Dominik Brodowski --- sound/pcmcia/pdaudiocf/pdaudiocf.c | 21 ++++++++++++--------- sound/pcmcia/vx/vxpocket.c | 21 ++++++++++++--------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 7dea74b71cf..64b859925c0 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -217,20 +217,25 @@ static void snd_pdacf_detach(struct pcmcia_device *link) * configuration callback */ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int pdacf_config(struct pcmcia_device *link) { struct snd_pdacf *pdacf = link->priv; - int last_fn, last_ret; + int ret; snd_printdd(KERN_DEBUG "pdacf_config called\n"); link->conf.ConfigIndex = 0x5; - CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_io(link, &link->io); + if (ret) + goto failed; + + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; if (snd_pdacf_assign_resources(pdacf, link->io.BasePort1, link->irq.AssignedIRQ) < 0) goto failed; @@ -238,8 +243,6 @@ static int pdacf_config(struct pcmcia_device *link) link->dev_node = &pdacf->node; return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: pcmcia_disable_device(link); return -ENODEV; diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 7445cc8a47d..1492744ad67 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -213,14 +213,11 @@ static int snd_vxpocket_assign_resources(struct vx_core *chip, int port, int irq * configuration callback */ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int vxpocket_config(struct pcmcia_device *link) { struct vx_core *chip = link->priv; struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; - int last_fn, last_ret; + int ret; snd_printdd(KERN_DEBUG "vxpocket_config called\n"); @@ -235,9 +232,17 @@ static int vxpocket_config(struct pcmcia_device *link) strcpy(chip->card->driver, vxp440_hw.name); } - CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_io(link, &link->io); + if (ret) + goto failed; + + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; chip->dev = &handle_to_dev(link); snd_card_set_dev(chip->card, chip->dev); @@ -248,8 +253,6 @@ static int vxpocket_config(struct pcmcia_device *link) link->dev_node = &vxp->node; return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: pcmcia_disable_device(link); return -ENODEV; From 9b44de2015ff4a2ed1d56efedfcc72b917d356a6 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 24 Oct 2009 15:55:39 +0200 Subject: [PATCH 101/298] pcmcia: use dynamic debug infrastructure, deprecate CS_CHECK (misc drivers) Convert PCMCIA drivers to use the dynamic debug infrastructure, instead of requiring manual settings of PCMCIA_DEBUG. Also, remove all usages of the CS_CHECK macro and replace them with proper Linux style calling and return value checking. The extra error reporting may be dropped, as the PCMCIA core already complains about any (non-driver-author) errors. CC: linux-mtd@lists.infradead.org CC: linux-usb@vger.kernel.org Signed-off-by: Dominik Brodowski --- drivers/mtd/maps/pcmciamtd.c | 14 ++--------- drivers/parport/parport_cs.c | 37 ++++++++++----------------- drivers/telephony/ixj_pcmcia.c | 36 ++++++++++---------------- drivers/usb/host/sl811_cs.c | 46 ++++++++++------------------------ 4 files changed, 41 insertions(+), 92 deletions(-) diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index 5c3546ef29d..b698dbaaf9e 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -119,10 +119,8 @@ static caddr_t remap_window(struct map_info *map, unsigned long to) dev->offset, mrq.CardOffset); mrq.Page = 0; ret = pcmcia_map_mem_page(win, &mrq); - if (ret != 0) { - cs_error(dev->p_dev, MapMemPage, ret); + if (ret != 0) return NULL; - } dev->offset = mrq.CardOffset; } return dev->win_base + (to & (dev->win_size-1)); @@ -327,8 +325,6 @@ static void pcmciamtd_set_vpp(struct map_info *map, int on) DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp); ret = pcmcia_modify_configuration(link, &mod); - if (ret != 0) - cs_error(link, ModifyConfiguration, ret); } @@ -490,16 +486,12 @@ static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *link, * MTD device available to the system. */ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int pcmciamtd_config(struct pcmcia_device *link) { struct pcmciamtd_dev *dev = link->priv; struct mtd_info *mtd = NULL; cs_status_t status; win_req_t req; - int last_ret = 0, last_fn = 0; int ret; int i; static char *probes[] = { "jedec_probe", "cfi_probe" }; @@ -586,7 +578,6 @@ static int pcmciamtd_config(struct pcmcia_device *link) DEBUG(2, "Setting Configuration"); ret = pcmcia_request_configuration(link, &link->conf); if (ret != 0) { - cs_error(link, RequestConfiguration, ret); if (dev->win_base) { iounmap(dev->win_base); dev->win_base = NULL; @@ -661,8 +652,7 @@ static int pcmciamtd_config(struct pcmcia_device *link) link->dev_node = &dev->node; return 0; - cs_failed: - cs_error(link, last_fn, last_ret); + failed: err("CS Error, exiting"); pcmciamtd_release(link); return -ENODEV; diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c index 8fdfa4f537a..e56a4dea671 100644 --- a/drivers/parport/parport_cs.c +++ b/drivers/parport/parport_cs.c @@ -67,14 +67,6 @@ MODULE_LICENSE("Dual MPL/GPL"); INT_MODULE_PARM(epp_mode, 1); -#ifdef PCMCIA_DEBUG -INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"parport_cs.c 1.29 2002/10/11 06:57:41 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif /*====================================================================*/ @@ -103,7 +95,7 @@ static int parport_probe(struct pcmcia_device *link) { parport_info_t *info; - DEBUG(0, "parport_attach()\n"); + dev_dbg(&link->dev, "parport_attach()\n"); /* Create new parport device */ info = kzalloc(sizeof(*info), GFP_KERNEL); @@ -132,7 +124,7 @@ static int parport_probe(struct pcmcia_device *link) static void parport_detach(struct pcmcia_device *link) { - DEBUG(0, "parport_detach(0x%p)\n", link); + dev_dbg(&link->dev, "parport_detach\n"); parport_cs_release(link); @@ -147,9 +139,6 @@ static void parport_detach(struct pcmcia_device *link) ======================================================================*/ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int parport_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cfg, cistpl_cftable_entry_t *dflt, @@ -178,18 +167,20 @@ static int parport_config(struct pcmcia_device *link) { parport_info_t *info = link->priv; struct parport *p; - int last_ret, last_fn; + int ret; - DEBUG(0, "parport_config(0x%p)\n", link); + dev_dbg(&link->dev, "parport_config\n"); - last_ret = pcmcia_loop_config(link, parport_config_check, NULL); - if (last_ret) { - cs_error(link, RequestIO, last_ret); + ret = pcmcia_loop_config(link, parport_config_check, NULL); + if (ret) goto failed; - } - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2, link->irq.AssignedIRQ, PARPORT_DMA_NONE, @@ -213,8 +204,6 @@ static int parport_config(struct pcmcia_device *link) return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: parport_cs_release(link); return -ENODEV; @@ -232,7 +221,7 @@ static void parport_cs_release(struct pcmcia_device *link) { parport_info_t *info = link->priv; - DEBUG(0, "parport_release(0x%p)\n", link); + dev_dbg(&link->dev, "parport_release\n"); if (info->ndev) { struct parport *p = info->port; diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c index 347c3ed1d9f..d442fd35620 100644 --- a/drivers/telephony/ixj_pcmcia.c +++ b/drivers/telephony/ixj_pcmcia.c @@ -19,13 +19,6 @@ * PCMCIA service support for Quicknet cards */ -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0644); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -#else -#define DEBUG(n, args...) -#endif typedef struct ixj_info_t { int ndev; @@ -39,7 +32,7 @@ static void ixj_cs_release(struct pcmcia_device * link); static int ixj_probe(struct pcmcia_device *p_dev) { - DEBUG(0, "ixj_attach()\n"); + dev_dbg(&p_dev->dev, "ixj_attach()\n"); /* Create new ixj device */ p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_8; @@ -55,33 +48,30 @@ static int ixj_probe(struct pcmcia_device *p_dev) static void ixj_detach(struct pcmcia_device *link) { - DEBUG(0, "ixj_detach(0x%p)\n", link); + dev_dbg(&link->dev, "ixj_detach\n"); ixj_cs_release(link); kfree(link->priv); } -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static void ixj_get_serial(struct pcmcia_device * link, IXJ * j) { char *str; int i, place; - DEBUG(0, "ixj_get_serial(0x%p)\n", link); + dev_dbg(&link->dev, "ixj_get_serial\n"); str = link->prod_id[0]; if (!str) - goto cs_failed; + goto failed; printk("%s", str); str = link->prod_id[1]; if (!str) - goto cs_failed; + goto failed; printk(" %s", str); str = link->prod_id[2]; if (!str) - goto cs_failed; + goto failed; place = 1; for (i = strlen(str) - 1; i >= 0; i--) { switch (str[i]) { @@ -118,9 +108,9 @@ static void ixj_get_serial(struct pcmcia_device * link, IXJ * j) } str = link->prod_id[3]; if (!str) - goto cs_failed; + goto failed; printk(" version %s\n", str); - cs_failed: +failed: return; } @@ -151,13 +141,13 @@ static int ixj_config(struct pcmcia_device * link) cistpl_cftable_entry_t dflt = { 0 }; info = link->priv; - DEBUG(0, "ixj_config(0x%p)\n", link); + dev_dbg(&link->dev, "ixj_config\n"); if (pcmcia_loop_config(link, ixj_config_check, &dflt)) - goto cs_failed; + goto failed; if (pcmcia_request_configuration(link, &link->conf)) - goto cs_failed; + goto failed; /* * Register the card with the core. @@ -170,7 +160,7 @@ static int ixj_config(struct pcmcia_device * link) ixj_get_serial(link, j); return 0; - cs_failed: +failed: ixj_cs_release(link); return -ENODEV; } @@ -178,7 +168,7 @@ static int ixj_config(struct pcmcia_device * link) static void ixj_cs_release(struct pcmcia_device *link) { ixj_info_t *info = link->priv; - DEBUG(0, "ixj_cs_release(0x%p)\n", link); + dev_dbg(&link->dev, "ixj_cs_release\n"); info->ndev = 0; pcmcia_disable_device(link); } diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 516848dd9b4..46077420dea 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c @@ -37,28 +37,8 @@ MODULE_LICENSE("GPL"); /* MACROS */ /*====================================================================*/ -#if defined(DEBUG) || defined(PCMCIA_DEBUG) - -static int pc_debug = 0; -module_param(pc_debug, int, 0644); - -#define DBG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG "sl811_cs: " args) - -#else -#define DBG(n, args...) do{}while(0) -#endif /* no debugging */ - #define INFO(args...) printk(KERN_INFO "sl811_cs: " args) -#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444) - -#define CS_CHECK(fn, ret) \ - do { \ - last_fn = (fn); \ - if ((last_ret = (ret)) != 0) \ - goto cs_failed; \ - } while (0) - /*====================================================================*/ /* VARIABLES */ /*====================================================================*/ @@ -76,7 +56,7 @@ static void sl811_cs_release(struct pcmcia_device * link); static void release_platform_dev(struct device * dev) { - DBG(0, "sl811_cs platform_dev release\n"); + dev_dbg(dev, "sl811_cs platform_dev release\n"); dev->parent = NULL; } @@ -140,7 +120,7 @@ static int sl811_hc_init(struct device *parent, resource_size_t base_addr, static void sl811_cs_detach(struct pcmcia_device *link) { - DBG(0, "sl811_cs_detach(0x%p)\n", link); + dev_dbg(&link->dev, "sl811_cs_detach\n"); sl811_cs_release(link); @@ -150,7 +130,7 @@ static void sl811_cs_detach(struct pcmcia_device *link) static void sl811_cs_release(struct pcmcia_device * link) { - DBG(0, "sl811_cs_release(0x%p)\n", link); + dev_dbg(&link->dev, "sl811_cs_release\n"); pcmcia_disable_device(link); platform_device_unregister(&platform_dev); @@ -207,9 +187,9 @@ static int sl811_cs_config(struct pcmcia_device *link) { struct device *parent = &handle_to_dev(link); local_info_t *dev = link->priv; - int last_fn, last_ret; + int ret; - DBG(0, "sl811_cs_config(0x%p)\n", link); + dev_dbg(&link->dev, "sl811_cs_config\n"); if (pcmcia_loop_config(link, sl811_cs_config_check, NULL)) goto failed; @@ -217,14 +197,16 @@ static int sl811_cs_config(struct pcmcia_device *link) /* require an IRQ and two registers */ if (!link->io.NumPorts1 || link->io.NumPorts1 < 2) goto failed; - if (link->conf.Attributes & CONF_ENABLE_IRQ) - CS_CHECK(RequestIRQ, - pcmcia_request_irq(link, &link->irq)); - else + if (link->conf.Attributes & CONF_ENABLE_IRQ) { + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + } else goto failed; - CS_CHECK(RequestConfiguration, - pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; sprintf(dev->node.dev_name, driver_name); dev->node.major = dev->node.minor = 0; @@ -241,8 +223,6 @@ static int sl811_cs_config(struct pcmcia_device *link) if (sl811_hc_init(parent, link->io.BasePort1, link->irq.AssignedIRQ) < 0) { -cs_failed: - cs_error(link, last_fn, last_ret); failed: printk(KERN_WARNING "sl811_cs_config failed\n"); sl811_cs_release(link); From 9cb495bb41f07a3ebfc60d3b9d26017a1fd7050c Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 24 Oct 2009 15:57:22 +0200 Subject: [PATCH 102/298] pcmcia: remove now-defunct cs_error, pcmcia_error_{func,ret} As all in-tree drivers have been converted to not use cs_error() any more, drop these functions and definitions, and update the Documentation. Signed-off-by: Dominik Brodowski --- Documentation/pcmcia/driver-changes.txt | 5 ++ drivers/pcmcia/ds.c | 101 ------------------------ include/pcmcia/ds.h | 36 --------- 3 files changed, 5 insertions(+), 137 deletions(-) diff --git a/Documentation/pcmcia/driver-changes.txt b/Documentation/pcmcia/driver-changes.txt index adfb83e5867..446f43b309d 100644 --- a/Documentation/pcmcia/driver-changes.txt +++ b/Documentation/pcmcia/driver-changes.txt @@ -1,5 +1,10 @@ This file details changes in 2.6 which affect PCMCIA card driver authors: +* no cs_error / CS_CHECK / CONFIG_PCMCIA_DEBUG (as of 2.6.33) + Instead of the cs_error() callback or the CS_CHECK() macro, please use + Linux-style checking of return values, and -- if necessary -- debug + messages using "dev_dbg()" or "pr_debug()". + * New CIS tuple access (as of 2.6.33) Instead of pcmcia_get_{first,next}_tuple(), pcmcia_get_tuple_data() and pcmcia_parse_tuple(), a driver shall use "pcmcia_get_tuple()" if it is diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 5b069aeaf17..05893d41dd4 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -46,107 +46,6 @@ spinlock_t pcmcia_dev_list_lock; /*====================================================================*/ -/* code which was in cs.c before */ - -/* String tables for error messages */ - -typedef struct lookup_t { - const int key; - const char *msg; -} lookup_t; - -static const lookup_t error_table[] = { - { 0, "Operation succeeded" }, - { -EIO, "Input/Output error" }, - { -ENODEV, "No card present" }, - { -EINVAL, "Bad parameter" }, - { -EACCES, "Configuration locked" }, - { -EBUSY, "Resource in use" }, - { -ENOSPC, "No more items" }, - { -ENOMEM, "Out of resource" }, -}; - - -static const lookup_t service_table[] = { - { AccessConfigurationRegister, "AccessConfigurationRegister" }, - { AddSocketServices, "AddSocketServices" }, - { AdjustResourceInfo, "AdjustResourceInfo" }, - { CheckEraseQueue, "CheckEraseQueue" }, - { CloseMemory, "CloseMemory" }, - { DeregisterClient, "DeregisterClient" }, - { DeregisterEraseQueue, "DeregisterEraseQueue" }, - { GetCardServicesInfo, "GetCardServicesInfo" }, - { GetClientInfo, "GetClientInfo" }, - { GetConfigurationInfo, "GetConfigurationInfo" }, - { GetEventMask, "GetEventMask" }, - { GetFirstClient, "GetFirstClient" }, - { GetFirstRegion, "GetFirstRegion" }, - { GetFirstTuple, "GetFirstTuple" }, - { GetNextClient, "GetNextClient" }, - { GetNextRegion, "GetNextRegion" }, - { GetNextTuple, "GetNextTuple" }, - { GetStatus, "GetStatus" }, - { GetTupleData, "GetTupleData" }, - { MapMemPage, "MapMemPage" }, - { ModifyConfiguration, "ModifyConfiguration" }, - { ModifyWindow, "ModifyWindow" }, - { OpenMemory, "OpenMemory" }, - { ParseTuple, "ParseTuple" }, - { ReadMemory, "ReadMemory" }, - { RegisterClient, "RegisterClient" }, - { RegisterEraseQueue, "RegisterEraseQueue" }, - { RegisterMTD, "RegisterMTD" }, - { ReleaseConfiguration, "ReleaseConfiguration" }, - { ReleaseIO, "ReleaseIO" }, - { ReleaseIRQ, "ReleaseIRQ" }, - { ReleaseWindow, "ReleaseWindow" }, - { RequestConfiguration, "RequestConfiguration" }, - { RequestIO, "RequestIO" }, - { RequestIRQ, "RequestIRQ" }, - { RequestSocketMask, "RequestSocketMask" }, - { RequestWindow, "RequestWindow" }, - { ResetCard, "ResetCard" }, - { SetEventMask, "SetEventMask" }, - { ValidateCIS, "ValidateCIS" }, - { WriteMemory, "WriteMemory" }, - { BindDevice, "BindDevice" }, - { BindMTD, "BindMTD" }, - { ReportError, "ReportError" }, - { SuspendCard, "SuspendCard" }, - { ResumeCard, "ResumeCard" }, - { EjectCard, "EjectCard" }, - { InsertCard, "InsertCard" }, - { ReplaceCIS, "ReplaceCIS" } -}; - -const char *pcmcia_error_func(int func) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(service_table); i++) - if (service_table[i].key == func) - return service_table[i].msg; - - return "Unknown service number"; -} -EXPORT_SYMBOL(pcmcia_error_func); - -const char *pcmcia_error_ret(int ret) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(error_table); i++) - if (error_table[i].key == ret) - return error_table[i].msg; - - return "unknown"; -} -EXPORT_SYMBOL(pcmcia_error_ret); - -/*======================================================================*/ - - - static void pcmcia_check_driver(struct pcmcia_driver *p_drv) { struct pcmcia_device_id *did = p_drv->id_table; diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index 6c37d4ed783..d82392de4e9 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -142,42 +142,6 @@ struct pcmcia_device { #define handle_to_dev(handle) (handle->dev) -/* (deprecated) error reporting by PCMCIA devices. Use dev_printk() - * or dev_dbg() directly in the driver, without referring to pcmcia_error_func() - * and/or pcmcia_error_ret() for those functions will go away soon. - */ -enum service { - AccessConfigurationRegister, AddSocketServices, - AdjustResourceInfo, CheckEraseQueue, CloseMemory, CopyMemory, - DeregisterClient, DeregisterEraseQueue, GetCardServicesInfo, - GetClientInfo, GetConfigurationInfo, GetEventMask, - GetFirstClient, GetFirstPartion, GetFirstRegion, GetFirstTuple, - GetNextClient, GetNextPartition, GetNextRegion, GetNextTuple, - GetStatus, GetTupleData, MapLogSocket, MapLogWindow, MapMemPage, - MapPhySocket, MapPhyWindow, ModifyConfiguration, ModifyWindow, - OpenMemory, ParseTuple, ReadMemory, RegisterClient, - RegisterEraseQueue, RegisterMTD, RegisterTimer, - ReleaseConfiguration, ReleaseExclusive, ReleaseIO, ReleaseIRQ, - ReleaseSocketMask, ReleaseWindow, ReplaceSocketServices, - RequestConfiguration, RequestExclusive, RequestIO, RequestIRQ, - RequestSocketMask, RequestWindow, ResetCard, ReturnSSEntry, - SetEventMask, SetRegion, ValidateCIS, VendorSpecific, - WriteMemory, BindDevice, BindMTD, ReportError, - SuspendCard, ResumeCard, EjectCard, InsertCard, ReplaceCIS, - GetFirstWindow, GetNextWindow, GetMemPage -}; -const char *pcmcia_error_func(int func); -const char *pcmcia_error_ret(int ret); - -#define cs_error(p_dev, func, ret) \ - { \ - dev_printk(KERN_NOTICE, &p_dev->dev, \ - "%s : %s\n", \ - pcmcia_error_func(func), \ - pcmcia_error_ret(ret)); \ - } - - /* * CIS access. * From a7149f9a26eb44a5658d56335c23104ba529e9f6 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 24 Oct 2009 18:07:16 +0200 Subject: [PATCH 103/298] pcmcia: use dev_dbg and dev_print in pd6729.c As suggested by Wolfram Sang , use dev_dbg(), and dev_{err,warn,info}() in pd6729.c, and add some "\n" suggested by Komuro . In the ISR, use pr_devel() and dev_vdbg() as they are only compiled if DEBUG (or, for dev_vdbg(), VERBOSE_DEBUG) are set explicitly. CC: Komuro Acked-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/pd6729.c | 70 ++++++++++++++++++++++------------------- drivers/pcmcia/pd6729.h | 7 ----- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index 70a33468bcd..e1741cd875a 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -213,7 +213,8 @@ static irqreturn_t pd6729_interrupt(int irq, void *dev) if (csc & I365_CSC_DETECT) { events |= SS_DETECT; - dprintk("Card detected in socket %i!\n", i); + dev_vdbg(&socket[i].socket.dev, + "Card detected in socket %i!\n", i); } if (indirect_read(&socket[i], I365_INTCTL) @@ -331,11 +332,11 @@ static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state) reg = I365_PWR_NORESET; /* default: disable resetdrv on resume */ if (state->flags & SS_PWR_AUTO) { - dprintk("Auto power\n"); + dev_dbg(&sock->dev, "Auto power\n"); reg |= I365_PWR_AUTO; /* automatic power mngmnt */ } if (state->flags & SS_OUTPUT_ENA) { - dprintk("Power Enabled\n"); + dev_dbg(&sock->dev, "Power Enabled\n"); reg |= I365_PWR_OUT; /* enable power */ } @@ -343,40 +344,44 @@ static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state) case 0: break; case 33: - dprintk("setting voltage to Vcc to 3.3V on socket %i\n", + dev_dbg(&sock->dev, + "setting voltage to Vcc to 3.3V on socket %i\n", socket->number); reg |= I365_VCC_5V; indirect_setbit(socket, PD67_MISC_CTL_1, PD67_MC1_VCC_3V); break; case 50: - dprintk("setting voltage to Vcc to 5V on socket %i\n", + dev_dbg(&sock->dev, + "setting voltage to Vcc to 5V on socket %i\n", socket->number); reg |= I365_VCC_5V; indirect_resetbit(socket, PD67_MISC_CTL_1, PD67_MC1_VCC_3V); break; default: - dprintk("pd6729: pd6729_set_socket called with " - "invalid VCC power value: %i\n", - state->Vcc); + dev_dbg(&sock->dev, + "pd6729_set_socket called with invalid VCC power " + "value: %i\n", state->Vcc); return -EINVAL; } switch (state->Vpp) { case 0: - dprintk("not setting Vpp on socket %i\n", socket->number); + dev_dbg(&sock->dev, "not setting Vpp on socket %i\n", + socket->number); break; case 33: case 50: - dprintk("setting Vpp to Vcc for socket %i\n", socket->number); + dev_dbg(&sock->dev, "setting Vpp to Vcc for socket %i\n", + socket->number); reg |= I365_VPP1_5V; break; case 120: - dprintk("setting Vpp to 12.0\n"); + dev_dbg(&sock->dev, "setting Vpp to 12.0\n"); reg |= I365_VPP1_12V; break; default: - dprintk("pd6729: pd6729_set_socket called with invalid VPP power value: %i\n", - state->Vpp); + dev_dbg(&sock->dev, "pd6729: pd6729_set_socket called with " + "invalid VPP power value: %i\n", state->Vpp); return -EINVAL; } @@ -438,7 +443,7 @@ static int pd6729_set_io_map(struct pcmcia_socket *sock, /* Check error conditions */ if (map > 1) { - dprintk("pd6729_set_io_map with invalid map"); + dev_dbg(&sock->dev, "pd6729_set_io_map with invalid map\n"); return -EINVAL; } @@ -446,7 +451,7 @@ static int pd6729_set_io_map(struct pcmcia_socket *sock, if (indirect_read(socket, I365_ADDRWIN) & I365_ENA_IO(map)) indirect_resetbit(socket, I365_ADDRWIN, I365_ENA_IO(map)); - /* dprintk("set_io_map: Setting range to %x - %x\n", + /* dev_dbg(&sock->dev, "set_io_map: Setting range to %x - %x\n", io->start, io->stop);*/ /* write the new values */ @@ -478,12 +483,12 @@ static int pd6729_set_mem_map(struct pcmcia_socket *sock, map = mem->map; if (map > 4) { - printk("pd6729_set_mem_map: invalid map"); + dev_warn(&sock->dev, "invalid map requested\n"); return -EINVAL; } if ((mem->res->start > mem->res->end) || (mem->speed > 1000)) { - printk("pd6729_set_mem_map: invalid address / speed"); + dev_warn(&sock->dev, "invalid invalid address / speed\n"); return -EINVAL; } @@ -529,12 +534,12 @@ static int pd6729_set_mem_map(struct pcmcia_socket *sock, if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT; if (mem->flags & MAP_ATTRIB) { - /* dprintk("requesting attribute memory for socket %i\n", - socket->number);*/ + /* dev_dbg(&sock->dev, "requesting attribute memory for " + "socket %i\n", socket->number);*/ i |= I365_MEM_REG; } else { - /* dprintk("requesting normal memory for socket %i\n", - socket->number);*/ + /* dev_dbg(&sock->dev, "requesting normal memory for " + "socket %i\n", socket->number);*/ } indirect_write16(socket, base + I365_W_OFF, i); @@ -577,7 +582,7 @@ static struct pccard_operations pd6729_operations = { static irqreturn_t pd6729_test(int irq, void *dev) { - dprintk("-> hit on irq %d\n", irq); + pr_devel("-> hit on irq %d\n", irq); return IRQ_HANDLED; } @@ -642,13 +647,13 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev, goto err_out_free_mem; if (!pci_resource_start(dev, 0)) { - printk(KERN_INFO "pd6729: refusing to load the driver " - "as the io_base is 0.\n"); + dev_warn(&dev->dev, "refusing to load the driver as the " + "io_base is NULL.\n"); goto err_out_free_mem; } - printk(KERN_INFO "pd6729: Cirrus PD6729 PCI to PCMCIA Bridge " - "at 0x%llx on irq %d\n", + dev_info(&dev->dev, "Cirrus PD6729 PCI to PCMCIA Bridge at 0x%llx " + "on irq %d\n", (unsigned long long)pci_resource_start(dev, 0), dev->irq); /* * Since we have no memory BARs some firmware may not @@ -656,14 +661,14 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev, */ pci_read_config_byte(dev, PCI_COMMAND, &configbyte); if (!(configbyte & PCI_COMMAND_MEMORY)) { - printk(KERN_DEBUG "pd6729: Enabling PCI_COMMAND_MEMORY.\n"); + dev_dbg(&dev->dev, "pd6729: Enabling PCI_COMMAND_MEMORY.\n"); configbyte |= PCI_COMMAND_MEMORY; pci_write_config_byte(dev, PCI_COMMAND, configbyte); } ret = pci_request_regions(dev, "pd6729"); if (ret) { - printk(KERN_INFO "pd6729: pci request region failed.\n"); + dev_warn(&dev->dev, "pci request region failed.\n"); goto err_out_disable; } @@ -672,7 +677,7 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev, mask = pd6729_isa_scan(); if (irq_mode == 0 && mask == 0) { - printk(KERN_INFO "pd6729: no ISA interrupt is available.\n"); + dev_warn(&dev->dev, "no ISA interrupt is available.\n"); goto err_out_free_res; } @@ -697,8 +702,8 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev, /* Register the interrupt handler */ if ((ret = request_irq(dev->irq, pd6729_interrupt, IRQF_SHARED, "pd6729", socket))) { - printk(KERN_ERR "pd6729: Failed to register irq %d, " - "aborting\n", dev->irq); + dev_err(&dev->dev, "Failed to register irq %d\n", + dev->irq); goto err_out_free_res; } } else { @@ -713,8 +718,7 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev, for (i = 0; i < MAX_SOCKETS; i++) { ret = pcmcia_register_socket(&socket[i].socket); if (ret) { - printk(KERN_INFO "pd6729: pcmcia_register_socket " - "failed.\n"); + dev_warn(&dev->dev, "pcmcia_register_socket failed.\n"); for (j = 0; j < i ; j++) pcmcia_unregister_socket(&socket[j].socket); goto err_out_free_res2; diff --git a/drivers/pcmcia/pd6729.h b/drivers/pcmcia/pd6729.h index f392e458cdf..41418d394c5 100644 --- a/drivers/pcmcia/pd6729.h +++ b/drivers/pcmcia/pd6729.h @@ -1,13 +1,6 @@ #ifndef _INCLUDE_GUARD_PD6729_H_ #define _INCLUDE_GUARD_PD6729_H_ -/* Debuging defines */ -#ifdef NOTRACE -#define dprintk(fmt, args...) printk(fmt , ## args) -#else -#define dprintk(fmt, args...) do {} while (0) -#endif - /* Flags for I365_GENCTL */ #define I365_DF_VS1 0x40 /* DF-step Voltage Sense */ #define I365_DF_VS2 0x80 From 0f767de6a26a07f7d58394512b6f6c96322f047f Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Thu, 26 Mar 2009 21:14:19 +0000 Subject: [PATCH 104/298] PCMCIA: soc_common: convert to a stand alone module Convert soc_common.c to be a stand alone module, rather than wrapping it up into the individual SoC specific base modules. In doing this, we need to add init/exit functions for soc_common to register/remove the cpufreq notifier. Signed-off-by: Russell King Signed-off-by: Dominik Brodowski --- drivers/pcmcia/Kconfig | 6 ++++++ drivers/pcmcia/Makefile | 10 ++++------ drivers/pcmcia/soc_common.c | 16 +++++++--------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 0c44dddd9b7..f3ccbccf5f2 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -178,9 +178,13 @@ config PCMCIA_BCM63XX tristate "bcm63xx pcmcia support" depends on BCM63XX && PCMCIA +config PCMCIA_SOC_COMMON + bool + config PCMCIA_SA1100 tristate "SA1100 support" depends on ARM && ARCH_SA1100 && PCMCIA + select PCMCIA_SOC_COMMON help Say Y here to include support for SA11x0-based PCMCIA or CF sockets, found on HP iPAQs, Yopy, and other StrongARM(R)/ @@ -191,6 +195,7 @@ config PCMCIA_SA1100 config PCMCIA_SA1111 tristate "SA1111 support" depends on ARM && ARCH_SA1100 && SA1111 && PCMCIA + select PCMCIA_SOC_COMMON help Say Y here to include support for SA1111-based PCMCIA or CF sockets, found on the Jornada 720, Graphicsmaster and other @@ -204,6 +209,7 @@ config PCMCIA_PXA2XX depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \ || MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \ || ARCH_VIPER || ARCH_PXA_ESERIES || MACH_STARGATE2) + select PCMCIA_SOC_COMMON help Say Y here to include support for the PXA2xx PCMCIA controller diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index a03a38acd77..38293831399 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -22,8 +22,9 @@ obj-$(CONFIG_I82365) += i82365.o obj-$(CONFIG_I82092) += i82092.o obj-$(CONFIG_TCIC) += tcic.o obj-$(CONFIG_PCMCIA_M8XX) += m8xx_pcmcia.o -obj-$(CONFIG_PCMCIA_SA1100) += sa11xx_core.o sa1100_cs.o -obj-$(CONFIG_PCMCIA_SA1111) += sa11xx_core.o sa1111_cs.o +obj-$(CONFIG_PCMCIA_SOC_COMMON) += soc_common.o +obj-$(CONFIG_PCMCIA_SA1100) += sa11xx_base.o sa1100_cs.o +obj-$(CONFIG_PCMCIA_SA1111) += sa11xx_base.o sa1111_cs.o obj-$(CONFIG_M32R_PCC) += m32r_pcc.o obj-$(CONFIG_M32R_CFC) += m32r_cfc.o obj-$(CONFIG_PCMCIA_AU1X00) += au1x00_ss.o @@ -35,9 +36,6 @@ obj-$(CONFIG_BFIN_CFPCMCIA) += bfin_cf_pcmcia.o obj-$(CONFIG_AT91_CF) += at91_cf.o obj-$(CONFIG_ELECTRA_CF) += electra_cf.o -sa11xx_core-y += soc_common.o sa11xx_base.o -pxa2xx_core-y += soc_common.o pxa2xx_base.o - au1x00_ss-y += au1000_generic.o au1x00_ss-$(CONFIG_MIPS_PB1000) += au1000_pb1x00.o au1x00_ss-$(CONFIG_MIPS_PB1100) += au1000_pb1x00.o @@ -77,4 +75,4 @@ pxa2xx-obj-$(CONFIG_MACH_PALMLD) += pxa2xx_palmld.o pxa2xx-obj-$(CONFIG_MACH_E740) += pxa2xx_e740.o pxa2xx-obj-$(CONFIG_MACH_STARGATE2) += pxa2xx_stargate2.o -obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_core.o $(pxa2xx-obj-y) +obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_base.o $(pxa2xx-obj-y) diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index ef7e9e58782..a2d448f20b0 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -609,15 +609,14 @@ static int soc_pcmcia_cpufreq_register(void) "notifier for PCMCIA (%d)\n", ret); return ret; } +fs_initcall(soc_pcmcia_cpufreq_register); static void soc_pcmcia_cpufreq_unregister(void) { cpufreq_unregister_notifier(&soc_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); } +module_exit(soc_pcmcia_cpufreq_unregister); -#else -static int soc_pcmcia_cpufreq_register(void) { return 0; } -static void soc_pcmcia_cpufreq_unregister(void) {} #endif int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, @@ -668,9 +667,6 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops goto out_err_5; } - if (list_empty(&soc_pcmcia_sockets)) - soc_pcmcia_cpufreq_register(); - list_add(&skt->node, &soc_pcmcia_sockets); /* @@ -743,6 +739,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops mutex_unlock(&soc_pcmcia_sockets_lock); return ret; } +EXPORT_SYMBOL(soc_common_drv_pcmcia_probe); int soc_common_drv_pcmcia_remove(struct device *dev) { @@ -773,9 +770,6 @@ int soc_common_drv_pcmcia_remove(struct device *dev) release_resource(&skt->res_io); release_resource(&skt->res_skt); } - if (list_empty(&soc_pcmcia_sockets)) - soc_pcmcia_cpufreq_unregister(); - mutex_unlock(&soc_pcmcia_sockets_lock); kfree(sinfo); @@ -783,3 +777,7 @@ int soc_common_drv_pcmcia_remove(struct device *dev) return 0; } EXPORT_SYMBOL(soc_common_drv_pcmcia_remove); + +MODULE_AUTHOR("John Dorsey "); +MODULE_DESCRIPTION("Linux PCMCIA Card Services: Common SoC support"); +MODULE_LICENSE("Dual MPL/GPL"); From 097e296d6175881eba7244de7222de61e9569911 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Thu, 26 Mar 2009 21:45:05 +0000 Subject: [PATCH 105/298] PCMCIA: soc_common: provide single socket add/remove functionality Factor out the functionality for adding and removing a single socket, thereby allowing SoCs to individually register each socket. The advantage of this approach is that SoCs can then extend soc_pcmcia_socket as they wish. Signed-off-by: Russell King Signed-off-by: Dominik Brodowski --- drivers/pcmcia/soc_common.c | 254 +++++++++++++++++++----------------- drivers/pcmcia/soc_common.h | 3 +- 2 files changed, 137 insertions(+), 120 deletions(-) diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index a2d448f20b0..9bfa74a6d8f 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -574,7 +574,7 @@ void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt, EXPORT_SYMBOL(soc_pcmcia_enable_irqs); -LIST_HEAD(soc_pcmcia_sockets); +static LIST_HEAD(soc_pcmcia_sockets); static DEFINE_MUTEX(soc_pcmcia_sockets_lock); #ifdef CONFIG_CPU_FREQ @@ -619,124 +619,161 @@ module_exit(soc_pcmcia_cpufreq_unregister); #endif +void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt) +{ + mutex_lock(&soc_pcmcia_sockets_lock); + del_timer_sync(&skt->poll_timer); + + pcmcia_unregister_socket(&skt->socket); + + flush_scheduled_work(); + + skt->ops->hw_shutdown(skt); + + soc_common_pcmcia_config_skt(skt, &dead_socket); + + list_del(&skt->node); + mutex_unlock(&soc_pcmcia_sockets_lock); + + iounmap(skt->virt_io); + skt->virt_io = NULL; + release_resource(&skt->res_attr); + release_resource(&skt->res_mem); + release_resource(&skt->res_io); + release_resource(&skt->res_skt); +} +EXPORT_SYMBOL(soc_pcmcia_remove_one); + +int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt) +{ + int ret; + + init_timer(&skt->poll_timer); + skt->poll_timer.function = soc_common_pcmcia_poll_event; + skt->poll_timer.data = (unsigned long)skt; + skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD; + + ret = request_resource(&iomem_resource, &skt->res_skt); + if (ret) + goto out_err_1; + + ret = request_resource(&skt->res_skt, &skt->res_io); + if (ret) + goto out_err_2; + + ret = request_resource(&skt->res_skt, &skt->res_mem); + if (ret) + goto out_err_3; + + ret = request_resource(&skt->res_skt, &skt->res_attr); + if (ret) + goto out_err_4; + + skt->virt_io = ioremap(skt->res_io.start, 0x10000); + if (skt->virt_io == NULL) { + ret = -ENOMEM; + goto out_err_5; + } + + mutex_lock(&soc_pcmcia_sockets_lock); + + list_add(&skt->node, &soc_pcmcia_sockets); + + /* + * We initialize default socket timing here, because + * we are not guaranteed to see a SetIOMap operation at + * runtime. + */ + skt->ops->set_timing(skt); + + ret = skt->ops->hw_init(skt); + if (ret) + goto out_err_6; + + skt->socket.ops = &soc_common_pcmcia_operations; + skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD; + skt->socket.resource_ops = &pccard_static_ops; + skt->socket.irq_mask = 0; + skt->socket.map_size = PAGE_SIZE; + skt->socket.pci_irq = skt->irq; + skt->socket.io_offset = (unsigned long)skt->virt_io; + + skt->status = soc_common_pcmcia_skt_state(skt); + + ret = pcmcia_register_socket(&skt->socket); + if (ret) + goto out_err_7; + + add_timer(&skt->poll_timer); + + mutex_unlock(&soc_pcmcia_sockets_lock); + + ret = device_create_file(&skt->socket.dev, &dev_attr_status); + if (ret) + goto out_err_8; + + return ret; + + out_err_8: + mutex_lock(&soc_pcmcia_sockets_lock); + del_timer_sync(&skt->poll_timer); + pcmcia_unregister_socket(&skt->socket); + + out_err_7: + flush_scheduled_work(); + + skt->ops->hw_shutdown(skt); + out_err_6: + list_del(&skt->node); + mutex_unlock(&soc_pcmcia_sockets_lock); + iounmap(skt->virt_io); + out_err_5: + release_resource(&skt->res_attr); + out_err_4: + release_resource(&skt->res_mem); + out_err_3: + release_resource(&skt->res_io); + out_err_2: + release_resource(&skt->res_skt); + out_err_1: + + return ret; +} +EXPORT_SYMBOL(soc_pcmcia_add_one); + int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, struct skt_dev_info *sinfo) { struct soc_pcmcia_socket *skt; int ret, i; - mutex_lock(&soc_pcmcia_sockets_lock); - /* * Initialise the per-socket structure. */ - for (i = 0; i < sinfo->nskt; i++) { + for (i = ret = 0; i < sinfo->nskt; i++) { skt = &sinfo->skt[i]; - skt->socket.ops = &soc_common_pcmcia_operations; skt->socket.owner = ops->owner; skt->socket.dev.parent = dev; - init_timer(&skt->poll_timer); - skt->poll_timer.function = soc_common_pcmcia_poll_event; - skt->poll_timer.data = (unsigned long)skt; - skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD; - skt->dev = dev; skt->ops = ops; - ret = request_resource(&iomem_resource, &skt->res_skt); + ret = soc_pcmcia_add_one(skt); if (ret) - goto out_err_1; - - ret = request_resource(&skt->res_skt, &skt->res_io); - if (ret) - goto out_err_2; - - ret = request_resource(&skt->res_skt, &skt->res_mem); - if (ret) - goto out_err_3; - - ret = request_resource(&skt->res_skt, &skt->res_attr); - if (ret) - goto out_err_4; - - skt->virt_io = ioremap(skt->res_io.start, 0x10000); - if (skt->virt_io == NULL) { - ret = -ENOMEM; - goto out_err_5; - } - - list_add(&skt->node, &soc_pcmcia_sockets); - - /* - * We initialize default socket timing here, because - * we are not guaranteed to see a SetIOMap operation at - * runtime. - */ - ops->set_timing(skt); - - ret = ops->hw_init(skt); - if (ret) - goto out_err_6; - - skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD; - skt->socket.resource_ops = &pccard_static_ops; - skt->socket.irq_mask = 0; - skt->socket.map_size = PAGE_SIZE; - skt->socket.pci_irq = skt->irq; - skt->socket.io_offset = (unsigned long)skt->virt_io; - - skt->status = soc_common_pcmcia_skt_state(skt); - - ret = pcmcia_register_socket(&skt->socket); - if (ret) - goto out_err_7; + break; WARN_ON(skt->socket.sock != i); - - add_timer(&skt->poll_timer); - - ret = device_create_file(&skt->socket.dev, &dev_attr_status); - if (ret) - goto out_err_8; } - dev_set_drvdata(dev, sinfo); - ret = 0; - goto out; + if (ret) { + while (--i >= 0) + soc_pcmcia_remove_one(&sinfo->skt[i]); + kfree(sinfo); + } else { + dev_set_drvdata(dev, sinfo); + } - do { - skt = &sinfo->skt[i]; - - device_remove_file(&skt->socket.dev, &dev_attr_status); - out_err_8: - del_timer_sync(&skt->poll_timer); - pcmcia_unregister_socket(&skt->socket); - - out_err_7: - flush_scheduled_work(); - - ops->hw_shutdown(skt); - out_err_6: - list_del(&skt->node); - iounmap(skt->virt_io); - out_err_5: - release_resource(&skt->res_attr); - out_err_4: - release_resource(&skt->res_mem); - out_err_3: - release_resource(&skt->res_io); - out_err_2: - release_resource(&skt->res_skt); - out_err_1: - i--; - } while (i > 0); - - kfree(sinfo); - - out: - mutex_unlock(&soc_pcmcia_sockets_lock); return ret; } EXPORT_SYMBOL(soc_common_drv_pcmcia_probe); @@ -748,29 +785,8 @@ int soc_common_drv_pcmcia_remove(struct device *dev) dev_set_drvdata(dev, NULL); - mutex_lock(&soc_pcmcia_sockets_lock); - for (i = 0; i < sinfo->nskt; i++) { - struct soc_pcmcia_socket *skt = &sinfo->skt[i]; - - del_timer_sync(&skt->poll_timer); - - pcmcia_unregister_socket(&skt->socket); - - flush_scheduled_work(); - - skt->ops->hw_shutdown(skt); - - soc_common_pcmcia_config_skt(skt, &dead_socket); - - list_del(&skt->node); - iounmap(skt->virt_io); - skt->virt_io = NULL; - release_resource(&skt->res_attr); - release_resource(&skt->res_mem); - release_resource(&skt->res_io); - release_resource(&skt->res_skt); - } - mutex_unlock(&soc_pcmcia_sockets_lock); + for (i = 0; i < sinfo->nskt; i++) + soc_pcmcia_remove_one(&sinfo->skt[i]); kfree(sinfo); diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index 290e143839e..51c72bae018 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -135,7 +135,8 @@ extern void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_ extern void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *, struct soc_pcmcia_timing *); -extern struct list_head soc_pcmcia_sockets; +void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt); +int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt); extern int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, struct skt_dev_info *sinfo); extern int soc_common_drv_pcmcia_remove(struct device *dev); From be85458edce0f165cff62622f5e73b1d17b1e228 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Thu, 26 Mar 2009 22:21:18 +0000 Subject: [PATCH 106/298] PCMCIA: soc_common: push socket removal down to SoC specific support Mechanically transplant the removal code from soc_common into each SoC specific base support file, thereby allowing soc_common_drv_pcmcia_remove to be removed. No other changes. Signed-off-by: Russell King Signed-off-by: Dominik Brodowski --- drivers/pcmcia/pxa2xx_base.c | 11 ++++++++++- drivers/pcmcia/sa1100_generic.c | 11 ++++++++++- drivers/pcmcia/sa1111_generic.c | 10 +++++++++- drivers/pcmcia/soc_common.c | 16 ---------------- drivers/pcmcia/soc_common.h | 1 - 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 0e35acb1366..8a91106056f 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -297,7 +297,16 @@ static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev) static int pxa2xx_drv_pcmcia_remove(struct platform_device *dev) { - return soc_common_drv_pcmcia_remove(&dev->dev); + struct skt_dev_info *sinfo = platform_get_drvdata(dev); + int i; + + platform_set_drvdata(dev, NULL); + + for (i = 0; i < sinfo->nskt; i++) + soc_pcmcia_remove_one(&sinfo->skt[i]); + + kfree(sinfo); + return 0; } static int pxa2xx_drv_pcmcia_suspend(struct device *dev) diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index 2d0e9975153..11cc3ba1260 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -83,7 +83,16 @@ static int sa11x0_drv_pcmcia_probe(struct platform_device *dev) static int sa11x0_drv_pcmcia_remove(struct platform_device *dev) { - return soc_common_drv_pcmcia_remove(&dev->dev); + struct skt_dev_info *sinfo = platform_get_drvdata(dev); + int i; + + platform_set_drvdata(dev, NULL); + + for (i = 0; i < sinfo->nskt; i++) + soc_pcmcia_remove_one(&sinfo->skt[i]); + + kfree(sinfo); + return 0; } static int sa11x0_drv_pcmcia_suspend(struct platform_device *dev, diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index 4be4e172ffa..a6793e30cf7 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -152,7 +152,15 @@ static int pcmcia_probe(struct sa1111_dev *dev) static int __devexit pcmcia_remove(struct sa1111_dev *dev) { - soc_common_drv_pcmcia_remove(&dev->dev); + struct skt_dev_info *sinfo = dev_get_drvdata(&dev->dev); + int i; + + dev_set_drvdata(&dev->dev, NULL); + + for (i = 0; i < sinfo->nskt; i++) + soc_pcmcia_remove_one(&sinfo->skt[i]); + + kfree(sinfo); release_mem_region(dev->res.start, 512); return 0; } diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 9bfa74a6d8f..fb5377d17af 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -778,22 +778,6 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops } EXPORT_SYMBOL(soc_common_drv_pcmcia_probe); -int soc_common_drv_pcmcia_remove(struct device *dev) -{ - struct skt_dev_info *sinfo = dev_get_drvdata(dev); - int i; - - dev_set_drvdata(dev, NULL); - - for (i = 0; i < sinfo->nskt; i++) - soc_pcmcia_remove_one(&sinfo->skt[i]); - - kfree(sinfo); - - return 0; -} -EXPORT_SYMBOL(soc_common_drv_pcmcia_remove); - MODULE_AUTHOR("John Dorsey "); MODULE_DESCRIPTION("Linux PCMCIA Card Services: Common SoC support"); MODULE_LICENSE("Dual MPL/GPL"); diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index 51c72bae018..c33b8c314fb 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -139,7 +139,6 @@ void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt); int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt); extern int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, struct skt_dev_info *sinfo); -extern int soc_common_drv_pcmcia_remove(struct device *dev); #ifdef CONFIG_PCMCIA_DEBUG From da4f007375197d6683461b995d404b01a7fdf2f5 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Sun, 29 Mar 2009 19:23:42 +0100 Subject: [PATCH 107/298] PCMCIA: soc_common: push socket probe down into SoC specific support Move the individual socket probing and initialization down into the SoC specific support files, thereby allowing soc_common_drv_pcmcia_probe to be eliminated. soc_common.c now no longer deals with distinct groups of sockets. Signed-off-by: Russell King Signed-off-by: Dominik Brodowski --- drivers/pcmcia/pxa2xx_base.c | 77 ++++++++++++++++++------------ drivers/pcmcia/sa11xx_base.c | 91 ++++++++++++++++++++++-------------- drivers/pcmcia/soc_common.c | 37 --------------- drivers/pcmcia/soc_common.h | 2 - 4 files changed, 103 insertions(+), 104 deletions(-) diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 8a91106056f..3cb4fd21cc2 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -228,6 +228,31 @@ static const char *skt_names[] = { #define SKT_DEV_INFO_SIZE(n) \ (sizeof(struct skt_dev_info) + (n)*sizeof(struct soc_pcmcia_socket)) +static int pxa2xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt) +{ + skt->res_skt.start = _PCMCIA(skt->nr); + skt->res_skt.end = _PCMCIA(skt->nr) + PCMCIASp - 1; + skt->res_skt.name = skt_names[skt->nr]; + skt->res_skt.flags = IORESOURCE_MEM; + + skt->res_io.start = _PCMCIAIO(skt->nr); + skt->res_io.end = _PCMCIAIO(skt->nr) + PCMCIAIOSp - 1; + skt->res_io.name = "io"; + skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + + skt->res_mem.start = _PCMCIAMem(skt->nr); + skt->res_mem.end = _PCMCIAMem(skt->nr) + PCMCIAMemSp - 1; + skt->res_mem.name = "memory"; + skt->res_mem.flags = IORESOURCE_MEM; + + skt->res_attr.start = _PCMCIAAttr(skt->nr); + skt->res_attr.end = _PCMCIAAttr(skt->nr) + PCMCIAAttrSp - 1; + skt->res_attr.name = "attribute"; + skt->res_attr.flags = IORESOURCE_MEM; + + return soc_pcmcia_add_one(skt); +} + int __pxa2xx_drv_pcmcia_probe(struct device *dev) { int i, ret; @@ -240,6 +265,12 @@ int __pxa2xx_drv_pcmcia_probe(struct device *dev) ops = (struct pcmcia_low_level *)dev->platform_data; + /* Provide our PXA2xx specific timing routines. */ + ops->set_timing = pxa2xx_pcmcia_set_timing; +#ifdef CONFIG_CPU_FREQ + ops->frequency_change = pxa2xx_pcmcia_frequency_change; +#endif + sinfo = kzalloc(SKT_DEV_INFO_SIZE(ops->nr), GFP_KERNEL); if (!sinfo) return -ENOMEM; @@ -250,40 +281,26 @@ int __pxa2xx_drv_pcmcia_probe(struct device *dev) for (i = 0; i < ops->nr; i++) { skt = &sinfo->skt[i]; - skt->nr = ops->first + i; - skt->irq = NO_IRQ; + skt->nr = ops->first + i; + skt->irq = NO_IRQ; + skt->dev = dev; + skt->ops = ops; + skt->socket.owner = ops->owner; + skt->socket.dev.parent = dev; - skt->res_skt.start = _PCMCIA(skt->nr); - skt->res_skt.end = _PCMCIA(skt->nr) + PCMCIASp - 1; - skt->res_skt.name = skt_names[skt->nr]; - skt->res_skt.flags = IORESOURCE_MEM; - - skt->res_io.start = _PCMCIAIO(skt->nr); - skt->res_io.end = _PCMCIAIO(skt->nr) + PCMCIAIOSp - 1; - skt->res_io.name = "io"; - skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY; - - skt->res_mem.start = _PCMCIAMem(skt->nr); - skt->res_mem.end = _PCMCIAMem(skt->nr) + PCMCIAMemSp - 1; - skt->res_mem.name = "memory"; - skt->res_mem.flags = IORESOURCE_MEM; - - skt->res_attr.start = _PCMCIAAttr(skt->nr); - skt->res_attr.end = _PCMCIAAttr(skt->nr) + PCMCIAAttrSp - 1; - skt->res_attr.name = "attribute"; - skt->res_attr.flags = IORESOURCE_MEM; + ret = pxa2xx_drv_pcmcia_add_one(skt); + if (ret) + break; } - /* Provide our PXA2xx specific timing routines. */ - ops->set_timing = pxa2xx_pcmcia_set_timing; -#ifdef CONFIG_CPU_FREQ - ops->frequency_change = pxa2xx_pcmcia_frequency_change; -#endif - - ret = soc_common_drv_pcmcia_probe(dev, ops, sinfo); - - if (!ret) + if (ret) { + while (--i >= 0) + soc_pcmcia_remove_one(&sinfo->skt[i]); + kfree(sinfo); + } else { pxa2xx_configure_sockets(dev); + dev_set_drvdata(dev, sinfo); + } return ret; } diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c index e15d59f2d8a..92a43486adc 100644 --- a/drivers/pcmcia/sa11xx_base.c +++ b/drivers/pcmcia/sa11xx_base.c @@ -171,6 +171,31 @@ static const char *skt_names[] = { #define SKT_DEV_INFO_SIZE(n) \ (sizeof(struct skt_dev_info) + (n)*sizeof(struct soc_pcmcia_socket)) +static int sa11xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt) +{ + skt->res_skt.start = _PCMCIA(skt->nr); + skt->res_skt.end = _PCMCIA(skt->nr) + PCMCIASp - 1; + skt->res_skt.name = skt_names[skt->nr]; + skt->res_skt.flags = IORESOURCE_MEM; + + skt->res_io.start = _PCMCIAIO(skt->nr); + skt->res_io.end = _PCMCIAIO(skt->nr) + PCMCIAIOSp - 1; + skt->res_io.name = "io"; + skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + + skt->res_mem.start = _PCMCIAMem(skt->nr); + skt->res_mem.end = _PCMCIAMem(skt->nr) + PCMCIAMemSp - 1; + skt->res_mem.name = "memory"; + skt->res_mem.flags = IORESOURCE_MEM; + + skt->res_attr.start = _PCMCIAAttr(skt->nr); + skt->res_attr.end = _PCMCIAAttr(skt->nr) + PCMCIAAttrSp - 1; + skt->res_attr.name = "attribute"; + skt->res_attr.flags = IORESOURCE_MEM; + + return soc_pcmcia_add_one(skt); +} + int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr) { @@ -178,40 +203,6 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, struct soc_pcmcia_socket *skt; int i; - sinfo = kzalloc(SKT_DEV_INFO_SIZE(nr), GFP_KERNEL); - if (!sinfo) - return -ENOMEM; - - sinfo->nskt = nr; - - /* Initiliaze processor specific parameters */ - for (i = 0; i < nr; i++) { - skt = &sinfo->skt[i]; - - skt->nr = first + i; - skt->irq = NO_IRQ; - - skt->res_skt.start = _PCMCIA(skt->nr); - skt->res_skt.end = _PCMCIA(skt->nr) + PCMCIASp - 1; - skt->res_skt.name = skt_names[skt->nr]; - skt->res_skt.flags = IORESOURCE_MEM; - - skt->res_io.start = _PCMCIAIO(skt->nr); - skt->res_io.end = _PCMCIAIO(skt->nr) + PCMCIAIOSp - 1; - skt->res_io.name = "io"; - skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY; - - skt->res_mem.start = _PCMCIAMem(skt->nr); - skt->res_mem.end = _PCMCIAMem(skt->nr) + PCMCIAMemSp - 1; - skt->res_mem.name = "memory"; - skt->res_mem.flags = IORESOURCE_MEM; - - skt->res_attr.start = _PCMCIAAttr(skt->nr); - skt->res_attr.end = _PCMCIAAttr(skt->nr) + PCMCIAAttrSp - 1; - skt->res_attr.name = "attribute"; - skt->res_attr.flags = IORESOURCE_MEM; - } - /* * set default MECR calculation if the board specific * code did not specify one... @@ -226,7 +217,37 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, ops->frequency_change = sa1100_pcmcia_frequency_change; #endif - return soc_common_drv_pcmcia_probe(dev, ops, sinfo); + sinfo = kzalloc(SKT_DEV_INFO_SIZE(nr), GFP_KERNEL); + if (!sinfo) + return -ENOMEM; + + sinfo->nskt = nr; + + /* Initiliaze processor specific parameters */ + for (i = 0; i < nr; i++) { + skt = &sinfo->skt[i]; + + skt->nr = first + i; + skt->irq = NO_IRQ; + skt->dev = dev; + skt->ops = ops; + skt->socket.owner = ops->owner; + skt->socket.dev.parent = dev; + + ret = sa11xx_drv_pcmcia_add_one(skt); + if (ret) + break; + } + + if (ret) { + while (--i >= 0) + soc_pcmcia_remove_one(&sinfo->skt[i]); + kfree(sinfo); + } else { + dev_set_drvdata(dev, sinfo); + } + + return ret; } EXPORT_SYMBOL(sa11xx_drv_pcmcia_probe); diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index fb5377d17af..6bc60f84a44 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -741,43 +741,6 @@ int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt) } EXPORT_SYMBOL(soc_pcmcia_add_one); -int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, - struct skt_dev_info *sinfo) -{ - struct soc_pcmcia_socket *skt; - int ret, i; - - /* - * Initialise the per-socket structure. - */ - for (i = ret = 0; i < sinfo->nskt; i++) { - skt = &sinfo->skt[i]; - - skt->socket.owner = ops->owner; - skt->socket.dev.parent = dev; - - skt->dev = dev; - skt->ops = ops; - - ret = soc_pcmcia_add_one(skt); - if (ret) - break; - - WARN_ON(skt->socket.sock != i); - } - - if (ret) { - while (--i >= 0) - soc_pcmcia_remove_one(&sinfo->skt[i]); - kfree(sinfo); - } else { - dev_set_drvdata(dev, sinfo); - } - - return ret; -} -EXPORT_SYMBOL(soc_common_drv_pcmcia_probe); - MODULE_AUTHOR("John Dorsey "); MODULE_DESCRIPTION("Linux PCMCIA Card Services: Common SoC support"); MODULE_LICENSE("Dual MPL/GPL"); diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index c33b8c314fb..8a755c1a949 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -138,8 +138,6 @@ extern void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *, struct soc_ void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt); int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt); -extern int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, struct skt_dev_info *sinfo); - #ifdef CONFIG_PCMCIA_DEBUG From 701a5dc05ad99a06958b3f97cb69d99b47cebee3 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Sun, 29 Mar 2009 19:42:44 +0100 Subject: [PATCH 108/298] PCMCIA: sa1111: wrap soc_pcmcia_socket to contain sa1111 specific data Signed-off-by: Russell King Signed-off-by: Dominik Brodowski --- drivers/pcmcia/pxa2xx_base.c | 19 ++++++---- drivers/pcmcia/pxa2xx_base.h | 3 ++ drivers/pcmcia/pxa2xx_lubbock.c | 10 +++--- drivers/pcmcia/sa1100_badge4.c | 7 +++- drivers/pcmcia/sa1100_jornada720.c | 20 +++++++---- drivers/pcmcia/sa1100_neponset.c | 9 +++-- drivers/pcmcia/sa1111_generic.c | 58 +++++++++++++++++++++++------- drivers/pcmcia/sa1111_generic.h | 14 ++++++++ drivers/pcmcia/sa11xx_base.c | 21 +++++++---- drivers/pcmcia/sa11xx_base.h | 2 ++ 10 files changed, 123 insertions(+), 40 deletions(-) diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 3cb4fd21cc2..c9c104b57c5 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -228,7 +228,7 @@ static const char *skt_names[] = { #define SKT_DEV_INFO_SIZE(n) \ (sizeof(struct skt_dev_info) + (n)*sizeof(struct soc_pcmcia_socket)) -static int pxa2xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt) +int pxa2xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt) { skt->res_skt.start = _PCMCIA(skt->nr); skt->res_skt.end = _PCMCIA(skt->nr) + PCMCIASp - 1; @@ -253,9 +253,18 @@ static int pxa2xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt) return soc_pcmcia_add_one(skt); } +void pxa2xx_drv_pcmcia_ops(struct pcmcia_low_level *ops) +{ + /* Provide our PXA2xx specific timing routines. */ + ops->set_timing = pxa2xx_pcmcia_set_timing; +#ifdef CONFIG_CPU_FREQ + ops->frequency_change = pxa2xx_pcmcia_frequency_change; +#endif +} + int __pxa2xx_drv_pcmcia_probe(struct device *dev) { - int i, ret; + int i, ret = 0; struct pcmcia_low_level *ops; struct skt_dev_info *sinfo; struct soc_pcmcia_socket *skt; @@ -265,11 +274,7 @@ int __pxa2xx_drv_pcmcia_probe(struct device *dev) ops = (struct pcmcia_low_level *)dev->platform_data; - /* Provide our PXA2xx specific timing routines. */ - ops->set_timing = pxa2xx_pcmcia_set_timing; -#ifdef CONFIG_CPU_FREQ - ops->frequency_change = pxa2xx_pcmcia_frequency_change; -#endif + pxa2xx_drv_pcmcia_ops(ops); sinfo = kzalloc(SKT_DEV_INFO_SIZE(ops->nr), GFP_KERNEL); if (!sinfo) diff --git a/drivers/pcmcia/pxa2xx_base.h b/drivers/pcmcia/pxa2xx_base.h index 235d681652c..cb5efaec886 100644 --- a/drivers/pcmcia/pxa2xx_base.h +++ b/drivers/pcmcia/pxa2xx_base.h @@ -1,3 +1,6 @@ /* temporary measure */ extern int __pxa2xx_drv_pcmcia_probe(struct device *); +int pxa2xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt); +void pxa2xx_drv_pcmcia_ops(struct pcmcia_low_level *ops); + diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c index 6cbb1b1f7cf..35d52809a8c 100644 --- a/drivers/pcmcia/pxa2xx_lubbock.c +++ b/drivers/pcmcia/pxa2xx_lubbock.c @@ -32,6 +32,7 @@ static int lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) { + struct sa1111_pcmcia_socket *s = to_skt(skt); unsigned int pa_dwr_mask, pa_dwr_set, misc_mask, misc_set; int ret = 0; @@ -149,7 +150,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, if (ret == 0) { lubbock_set_misc_wr(misc_mask, misc_set); - sa1111_set_io(SA1111_DEV(skt->dev), pa_dwr_mask, pa_dwr_set); + sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set); } #if 1 @@ -175,7 +176,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, * Switch to 5V, Configure socket with 5V voltage */ lubbock_set_misc_wr(misc_mask, 0); - sa1111_set_io(SA1111_DEV(skt->dev), pa_dwr_mask, 0); + sa1111_set_io(s->dev, pa_dwr_mask, 0); /* * It takes about 100ms to turn off Vcc. @@ -228,8 +229,9 @@ int pcmcia_lubbock_init(struct sa1111_dev *sadev) /* Set CF Socket 1 power to standby mode. */ lubbock_set_misc_wr((1 << 15) | (1 << 14), 0); - sadev->dev.platform_data = &lubbock_pcmcia_ops; - ret = __pxa2xx_drv_pcmcia_probe(&sadev->dev); + pxa2xx_drv_pcmcia_ops(&lubbock_pcmcia_ops); + ret = sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops, + pxa2xx_drv_pcmcia_add_one); } return ret; diff --git a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c index 1ca9737ea79..6399314e244 100644 --- a/drivers/pcmcia/sa1100_badge4.c +++ b/drivers/pcmcia/sa1100_badge4.c @@ -134,6 +134,9 @@ static struct pcmcia_low_level badge4_pcmcia_ops = { .socket_init = sa1111_pcmcia_socket_init, .socket_suspend = sa1111_pcmcia_socket_suspend, + + .first = 0, + .nr = 2, }; int pcmcia_badge4_init(struct device *dev) @@ -146,7 +149,9 @@ int pcmcia_badge4_init(struct device *dev) __func__, badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc); - ret = sa11xx_drv_pcmcia_probe(dev, &badge4_pcmcia_ops, 0, 2); + sa11xx_drv_pcmcia_ops(&badge4_pcmcia_ops); + ret = sa1111_pcmcia_add(dev, &badge4_pcmcia_ops, + sa11xx_drv_pcmcia_add_one); } return ret; diff --git a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c index 7eedb42f800..4a32f4f1a71 100644 --- a/drivers/pcmcia/sa1100_jornada720.c +++ b/drivers/pcmcia/sa1100_jornada720.c @@ -24,6 +24,7 @@ static int jornada720_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { + struct sa1111_pcmcia_socket *s = to_skt(skt); unsigned int pin = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3; /* @@ -31,9 +32,9 @@ static int jornada720_pcmcia_hw_init(struct soc_pcmcia_socket *skt) */ GRER |= 0x00000002; /* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */ - sa1111_set_io_dir(SA1111_DEV(skt->dev), pin, 0, 0); - sa1111_set_io(SA1111_DEV(skt->dev), pin, 0); - sa1111_set_sleep_io(SA1111_DEV(skt->dev), pin, 0); + sa1111_set_io_dir(s->dev, pin, 0, 0); + sa1111_set_io(s->dev, pin, 0); + sa1111_set_sleep_io(s->dev, pin, 0); return sa1111_pcmcia_hw_init(skt); } @@ -41,6 +42,7 @@ static int jornada720_pcmcia_hw_init(struct soc_pcmcia_socket *skt) static int jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) { + struct sa1111_pcmcia_socket *s = to_skt(skt); unsigned int pa_dwr_mask, pa_dwr_set; int ret; @@ -97,7 +99,7 @@ jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s unsigned long flags; local_irq_save(flags); - sa1111_set_io(SA1111_DEV(skt->dev), pa_dwr_mask, pa_dwr_set); + sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set); local_irq_restore(flags); } @@ -113,14 +115,20 @@ static struct pcmcia_low_level jornada720_pcmcia_ops = { .socket_init = sa1111_pcmcia_socket_init, .socket_suspend = sa1111_pcmcia_socket_suspend, + + .first = 0, + .nr = 2, }; int __devinit pcmcia_jornada720_init(struct device *dev) { int ret = -ENODEV; - if (machine_is_jornada720()) - ret = sa11xx_drv_pcmcia_probe(dev, &jornada720_pcmcia_ops, 0, 2); + if (machine_is_jornada720()) { + sa11xx_drv_pcmcia_ops(&jornada720_pcmcia_ops); + ret = sa1111_pcmcia_add(dev, &jornada720_pcmcia_ops, + sa11xx_drv_pcmcia_add_one); + } return ret; } diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c index 0c76d337815..e39c65a06fe 100644 --- a/drivers/pcmcia/sa1100_neponset.c +++ b/drivers/pcmcia/sa1100_neponset.c @@ -43,6 +43,7 @@ static int neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) { + struct sa1111_pcmcia_socket *s = to_skt(skt); unsigned int ncr_mask, ncr_set, pa_dwr_mask, pa_dwr_set; int ret; @@ -99,7 +100,7 @@ neponset_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_sta NCR_0 = (NCR_0 & ~ncr_mask) | ncr_set; local_irq_restore(flags); - sa1111_set_io(SA1111_DEV(skt->dev), pa_dwr_mask, pa_dwr_set); + sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set); } return 0; @@ -121,6 +122,8 @@ static struct pcmcia_low_level neponset_pcmcia_ops = { .configure_socket = neponset_pcmcia_configure_socket, .socket_init = neponset_pcmcia_socket_init, .socket_suspend = sa1111_pcmcia_socket_suspend, + .first = 0, + .nr = 2, }; int pcmcia_neponset_init(struct sa1111_dev *sadev) @@ -135,7 +138,9 @@ int pcmcia_neponset_init(struct sa1111_dev *sadev) sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0); sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0); sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0); - ret = sa11xx_drv_pcmcia_probe(&sadev->dev, &neponset_pcmcia_ops, 0, 2); + sa11xx_drv_pcmcia_ops(&neponset_pcmcia_ops); + ret = sa1111_pcmcia_add(sadev, &neponset_pcmcia_ops, + sa11xx_drv_pcmcia_add_one); } return ret; diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index a6793e30cf7..98c791537ca 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -30,9 +30,6 @@ static struct pcmcia_irqs irqs[] = { int sa1111_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { - if (skt->irq == NO_IRQ) - skt->irq = skt->nr ? IRQ_S1_READY_NINT : IRQ_S0_READY_NINT; - return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } @@ -43,8 +40,8 @@ void sa1111_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) { - struct sa1111_dev *sadev = SA1111_DEV(skt->dev); - unsigned long status = sa1111_readl(sadev->mapbase + SA1111_PCSR); + struct sa1111_pcmcia_socket *s = to_skt(skt); + unsigned long status = sa1111_readl(s->dev->mapbase + SA1111_PCSR); switch (skt->nr) { case 0: @@ -71,7 +68,7 @@ void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_sta int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) { - struct sa1111_dev *sadev = SA1111_DEV(skt->dev); + struct sa1111_pcmcia_socket *s = to_skt(skt); unsigned int pccr_skt_mask, pccr_set_mask, val; unsigned long flags; @@ -100,10 +97,10 @@ int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s pccr_set_mask |= PCCR_S0_FLT|PCCR_S1_FLT; local_irq_save(flags); - val = sa1111_readl(sadev->mapbase + SA1111_PCCR); + val = sa1111_readl(s->dev->mapbase + SA1111_PCCR); val &= ~pccr_skt_mask; val |= pccr_set_mask & pccr_skt_mask; - sa1111_writel(val, sadev->mapbase + SA1111_PCCR); + sa1111_writel(val, s->dev->mapbase + SA1111_PCCR); local_irq_restore(flags); return 0; @@ -119,10 +116,45 @@ void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } +int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops, + int (*add)(struct soc_pcmcia_socket *)) +{ + struct sa1111_pcmcia_socket *s; + int i, ret = 0; + + s = kzalloc(sizeof(*s) * ops->nr, GFP_KERNEL); + if (!s) + return -ENODEV; + + for (i = 0; i < ops->nr; i++) { + s = kzalloc(sizeof(*s), GFP_KERNEL); + if (!s) + return -ENOMEM; + + s->soc.nr = ops->first + i; + s->soc.irq = s->soc.nr ? IRQ_S1_READY_NINT : IRQ_S0_READY_NINT; + s->soc.ops = ops; + s->soc.socket.owner = ops->owner; + s->soc.socket.dev.parent = &dev->dev; + s->dev = dev; + + ret = add(&s->soc); + if (ret == 0) { + s->next = dev_get_drvdata(&dev->dev); + dev_set_drvdata(&dev->dev, s); + } else + kfree(s); + } + + return ret; +} + static int pcmcia_probe(struct sa1111_dev *dev) { void __iomem *base; + dev_set_drvdata(&dev->dev, NULL); + if (!request_mem_region(dev->res.start, 512, SA1111_DRIVER_NAME(dev))) return -EBUSY; @@ -152,15 +184,15 @@ static int pcmcia_probe(struct sa1111_dev *dev) static int __devexit pcmcia_remove(struct sa1111_dev *dev) { - struct skt_dev_info *sinfo = dev_get_drvdata(&dev->dev); - int i; + struct sa1111_pcmcia_socket *next, *s = dev_get_drvdata(&dev->dev); dev_set_drvdata(&dev->dev, NULL); - for (i = 0; i < sinfo->nskt; i++) - soc_pcmcia_remove_one(&sinfo->skt[i]); + for (; next = s->next, s; s = next) { + soc_pcmcia_remove_one(&s->soc); + kfree(s); + } - kfree(sinfo); release_mem_region(dev->res.start, 512); return 0; } diff --git a/drivers/pcmcia/sa1111_generic.h b/drivers/pcmcia/sa1111_generic.h index 10ced4a210d..536fe15818b 100644 --- a/drivers/pcmcia/sa1111_generic.h +++ b/drivers/pcmcia/sa1111_generic.h @@ -1,6 +1,20 @@ #include "soc_common.h" #include "sa11xx_base.h" +struct sa1111_pcmcia_socket { + struct soc_pcmcia_socket soc; + struct sa1111_dev *dev; + struct sa1111_pcmcia_socket *next; +}; + +static inline struct sa1111_pcmcia_socket *to_skt(struct soc_pcmcia_socket *s) +{ + return container_of(s, struct sa1111_pcmcia_socket, soc); +} + +int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops, + int (*add)(struct soc_pcmcia_socket *)); + extern int sa1111_pcmcia_hw_init(struct soc_pcmcia_socket *); extern void sa1111_pcmcia_hw_shutdown(struct soc_pcmcia_socket *); extern void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *, struct pcmcia_state *); diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c index 92a43486adc..4db81490e5c 100644 --- a/drivers/pcmcia/sa11xx_base.c +++ b/drivers/pcmcia/sa11xx_base.c @@ -171,7 +171,7 @@ static const char *skt_names[] = { #define SKT_DEV_INFO_SIZE(n) \ (sizeof(struct skt_dev_info) + (n)*sizeof(struct soc_pcmcia_socket)) -static int sa11xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt) +int sa11xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt) { skt->res_skt.start = _PCMCIA(skt->nr); skt->res_skt.end = _PCMCIA(skt->nr) + PCMCIASp - 1; @@ -195,14 +195,10 @@ static int sa11xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt) return soc_pcmcia_add_one(skt); } +EXPORT_SYMBOL(sa11xx_drv_pcmcia_add_one); -int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, - int first, int nr) +void sa11xx_drv_pcmcia_ops(struct pcmcia_low_level *ops) { - struct skt_dev_info *sinfo; - struct soc_pcmcia_socket *skt; - int i; - /* * set default MECR calculation if the board specific * code did not specify one... @@ -216,6 +212,17 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, #ifdef CONFIG_CPU_FREQ ops->frequency_change = sa1100_pcmcia_frequency_change; #endif +} +EXPORT_SYMBOL(sa11xx_drv_pcmcia_ops); + +int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, + int first, int nr) +{ + struct skt_dev_info *sinfo; + struct soc_pcmcia_socket *skt; + int i, ret = 0; + + sa11xx_drv_pcmcia_ops(ops); sinfo = kzalloc(SKT_DEV_INFO_SIZE(nr), GFP_KERNEL); if (!sinfo) diff --git a/drivers/pcmcia/sa11xx_base.h b/drivers/pcmcia/sa11xx_base.h index 7bc20828052..3d76d720f46 100644 --- a/drivers/pcmcia/sa11xx_base.h +++ b/drivers/pcmcia/sa11xx_base.h @@ -118,6 +118,8 @@ static inline unsigned int sa1100_pcmcia_cmd_time(unsigned int cpu_clock_khz, } +int sa11xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt); +void sa11xx_drv_pcmcia_ops(struct pcmcia_low_level *ops); extern int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr); #endif /* !defined(_PCMCIA_SA1100_H) */ From dabd14684bc2375bf69f227f04993a4dc2fd3a16 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Sun, 29 Mar 2009 22:35:11 +0100 Subject: [PATCH 109/298] PCMCIA: sa1111: remove duplicated initializers Signed-off-by: Russell King Signed-off-by: Dominik Brodowski --- drivers/pcmcia/pxa2xx_lubbock.c | 4 ---- drivers/pcmcia/sa1100_badge4.c | 6 ------ drivers/pcmcia/sa1100_jornada720.c | 32 +++++++++--------------------- drivers/pcmcia/sa1100_neponset.c | 4 ---- drivers/pcmcia/sa1111_generic.c | 11 +++++++--- drivers/pcmcia/sa1111_generic.h | 3 --- 6 files changed, 17 insertions(+), 43 deletions(-) diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c index 35d52809a8c..b9f8c8fb42b 100644 --- a/drivers/pcmcia/pxa2xx_lubbock.c +++ b/drivers/pcmcia/pxa2xx_lubbock.c @@ -201,12 +201,8 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, static struct pcmcia_low_level lubbock_pcmcia_ops = { .owner = THIS_MODULE, - .hw_init = sa1111_pcmcia_hw_init, - .hw_shutdown = sa1111_pcmcia_hw_shutdown, - .socket_state = sa1111_pcmcia_socket_state, .configure_socket = lubbock_pcmcia_configure_socket, .socket_init = sa1111_pcmcia_socket_init, - .socket_suspend = sa1111_pcmcia_socket_suspend, .first = 0, .nr = 2, }; diff --git a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c index 6399314e244..1ce53f493be 100644 --- a/drivers/pcmcia/sa1100_badge4.c +++ b/drivers/pcmcia/sa1100_badge4.c @@ -127,14 +127,8 @@ badge4_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state static struct pcmcia_low_level badge4_pcmcia_ops = { .owner = THIS_MODULE, - .hw_init = sa1111_pcmcia_hw_init, - .hw_shutdown = sa1111_pcmcia_hw_shutdown, - .socket_state = sa1111_pcmcia_socket_state, .configure_socket = badge4_pcmcia_configure_socket, - .socket_init = sa1111_pcmcia_socket_init, - .socket_suspend = sa1111_pcmcia_socket_suspend, - .first = 0, .nr = 2, }; diff --git a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c index 4a32f4f1a71..6bcabee6bde 100644 --- a/drivers/pcmcia/sa1100_jornada720.c +++ b/drivers/pcmcia/sa1100_jornada720.c @@ -22,23 +22,6 @@ #define SOCKET1_POWER (GPIO_GPIO1 | GPIO_GPIO3) #define SOCKET1_3V GPIO_GPIO3 -static int jornada720_pcmcia_hw_init(struct soc_pcmcia_socket *skt) -{ - struct sa1111_pcmcia_socket *s = to_skt(skt); - unsigned int pin = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3; - - /* - * What is all this crap for? - */ - GRER |= 0x00000002; - /* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */ - sa1111_set_io_dir(s->dev, pin, 0, 0); - sa1111_set_io(s->dev, pin, 0); - sa1111_set_sleep_io(s->dev, pin, 0); - - return sa1111_pcmcia_hw_init(skt); -} - static int jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) { @@ -108,14 +91,8 @@ jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s static struct pcmcia_low_level jornada720_pcmcia_ops = { .owner = THIS_MODULE, - .hw_init = jornada720_pcmcia_hw_init, - .hw_shutdown = sa1111_pcmcia_hw_shutdown, - .socket_state = sa1111_pcmcia_socket_state, .configure_socket = jornada720_pcmcia_configure_socket, - .socket_init = sa1111_pcmcia_socket_init, - .socket_suspend = sa1111_pcmcia_socket_suspend, - .first = 0, .nr = 2, }; @@ -125,6 +102,15 @@ int __devinit pcmcia_jornada720_init(struct device *dev) int ret = -ENODEV; if (machine_is_jornada720()) { + unsigned int pin = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3; + + GRER |= 0x00000002; + + /* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */ + sa1111_set_io_dir(dev, pin, 0, 0); + sa1111_set_io(dev, pin, 0); + sa1111_set_sleep_io(dev, pin, 0); + sa11xx_drv_pcmcia_ops(&jornada720_pcmcia_ops); ret = sa1111_pcmcia_add(dev, &jornada720_pcmcia_ops, sa11xx_drv_pcmcia_add_one); diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c index e39c65a06fe..c95639b5f2a 100644 --- a/drivers/pcmcia/sa1100_neponset.c +++ b/drivers/pcmcia/sa1100_neponset.c @@ -116,12 +116,8 @@ static void neponset_pcmcia_socket_init(struct soc_pcmcia_socket *skt) static struct pcmcia_low_level neponset_pcmcia_ops = { .owner = THIS_MODULE, - .hw_init = sa1111_pcmcia_hw_init, - .hw_shutdown = sa1111_pcmcia_hw_shutdown, - .socket_state = sa1111_pcmcia_socket_state, .configure_socket = neponset_pcmcia_configure_socket, .socket_init = neponset_pcmcia_socket_init, - .socket_suspend = sa1111_pcmcia_socket_suspend, .first = 0, .nr = 2, }; diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index 98c791537ca..219860aba81 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -28,12 +28,12 @@ static struct pcmcia_irqs irqs[] = { { 1, IRQ_S1_BVD1_STSCHG, "SA1111 CF BVD1" }, }; -int sa1111_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +static int sa1111_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -void sa1111_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) +static void sa1111_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) { soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); } @@ -111,7 +111,7 @@ void sa1111_pcmcia_socket_init(struct soc_pcmcia_socket *skt) soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) +static void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) { soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } @@ -122,6 +122,11 @@ int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops, struct sa1111_pcmcia_socket *s; int i, ret = 0; + ops->hw_init = sa1111_pcmcia_hw_init; + ops->hw_shutdown = sa1111_pcmcia_hw_shutdown; + ops->socket_state = sa1111_pcmcia_socket_state; + ops->socket_suspend = sa1111_pcmcia_socket_suspend; + s = kzalloc(sizeof(*s) * ops->nr, GFP_KERNEL); if (!s) return -ENODEV; diff --git a/drivers/pcmcia/sa1111_generic.h b/drivers/pcmcia/sa1111_generic.h index 536fe15818b..02dc8577cda 100644 --- a/drivers/pcmcia/sa1111_generic.h +++ b/drivers/pcmcia/sa1111_generic.h @@ -15,12 +15,9 @@ static inline struct sa1111_pcmcia_socket *to_skt(struct soc_pcmcia_socket *s) int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops, int (*add)(struct soc_pcmcia_socket *)); -extern int sa1111_pcmcia_hw_init(struct soc_pcmcia_socket *); -extern void sa1111_pcmcia_hw_shutdown(struct soc_pcmcia_socket *); extern void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *, struct pcmcia_state *); extern int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *, const socket_state_t *); extern void sa1111_pcmcia_socket_init(struct soc_pcmcia_socket *); -extern void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *); extern int pcmcia_badge4_init(struct device *); extern int pcmcia_jornada720_init(struct device *); From b62d99b5028b6df1c32b864fd9dd32ad6b42d396 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Sun, 29 Mar 2009 22:14:32 +0100 Subject: [PATCH 110/298] PCMCIA: soc_common: constify soc_pcmcia_socket ops member No one should modify the ops structure supplied to soc_pcmcia_socket so make it const. Signed-off-by: Russell King Signed-off-by: Dominik Brodowski --- drivers/pcmcia/soc_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index 8a755c1a949..f7533dcba67 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -37,7 +37,7 @@ struct soc_pcmcia_socket { /* * Core PCMCIA state */ - struct pcmcia_low_level *ops; + const struct pcmcia_low_level *ops; unsigned int status; socket_state_t cs_state; From f397b9c5dcc30a575973b2e4f0a602fc85b38853 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Sun, 29 Mar 2009 22:12:34 +0100 Subject: [PATCH 111/298] PCMCIA: soc_common: remove 'dev' member from soc_pcmcia_socket The 'dev' member is now only ever written, so we can safely remove it. Signed-off-by: Russell King Signed-off-by: Dominik Brodowski --- drivers/pcmcia/pxa2xx_base.c | 1 - drivers/pcmcia/sa11xx_base.c | 1 - drivers/pcmcia/soc_common.h | 1 - 3 files changed, 3 deletions(-) diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index c9c104b57c5..7f61b62a1de 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -288,7 +288,6 @@ int __pxa2xx_drv_pcmcia_probe(struct device *dev) skt->nr = ops->first + i; skt->irq = NO_IRQ; - skt->dev = dev; skt->ops = ops; skt->socket.owner = ops->owner; skt->socket.dev.parent = dev; diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c index 4db81490e5c..ac998724313 100644 --- a/drivers/pcmcia/sa11xx_base.c +++ b/drivers/pcmcia/sa11xx_base.c @@ -236,7 +236,6 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, skt->nr = first + i; skt->irq = NO_IRQ; - skt->dev = dev; skt->ops = ops; skt->socket.owner = ops->owner; skt->socket.dev.parent = dev; diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index f7533dcba67..4fb06f797ad 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -30,7 +30,6 @@ struct soc_pcmcia_socket { /* * Info from low level handler */ - struct device *dev; unsigned int nr; unsigned int irq; From 1689164a272a962572a1f31af715dfe462cf7910 Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Sun, 29 Mar 2009 22:43:43 +0100 Subject: [PATCH 112/298] PCMCIA: ss: allow PCI IRQs > 255 Signed-off-by: Russell King Signed-off-by: Dominik Brodowski --- include/pcmcia/ss.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index d696a692d94..753da9b087d 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -172,7 +172,7 @@ struct pcmcia_socket { u_int irq_mask; u_int map_size; u_int io_offset; - u_char pci_irq; + u_int pci_irq; struct pci_dev * cb_dev; From 66024db57d5b9011e274b314affad68f370c0d6f Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Sun, 29 Mar 2009 22:45:26 +0100 Subject: [PATCH 113/298] PCMCIA: stop duplicating pci_irq in soc_pcmcia_socket skt->irq is a mere duplication of pcmcia_socket's pci_irq member. Get rid of it. Signed-off-by: Russell King Signed-off-by: Dominik Brodowski --- drivers/pcmcia/pxa2xx_base.c | 2 +- drivers/pcmcia/pxa2xx_cm_x255.c | 2 +- drivers/pcmcia/pxa2xx_cm_x270.c | 2 +- drivers/pcmcia/pxa2xx_e740.c | 2 +- drivers/pcmcia/pxa2xx_mainstone.c | 2 +- drivers/pcmcia/pxa2xx_palmld.c | 2 +- drivers/pcmcia/pxa2xx_palmtx.c | 2 +- drivers/pcmcia/pxa2xx_sharpsl.c | 2 +- drivers/pcmcia/pxa2xx_trizeps4.c | 4 ++-- drivers/pcmcia/pxa2xx_viper.c | 2 +- drivers/pcmcia/sa1100_assabet.c | 2 +- drivers/pcmcia/sa1100_cerf.c | 2 +- drivers/pcmcia/sa1100_h3600.c | 4 ++-- drivers/pcmcia/sa1100_shannon.c | 2 +- drivers/pcmcia/sa1100_simpad.c | 2 +- drivers/pcmcia/sa1111_generic.c | 2 +- drivers/pcmcia/sa11xx_base.c | 2 +- drivers/pcmcia/soc_common.c | 8 ++++---- drivers/pcmcia/soc_common.h | 1 - 19 files changed, 23 insertions(+), 24 deletions(-) diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 7f61b62a1de..84dde7768ad 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -287,10 +287,10 @@ int __pxa2xx_drv_pcmcia_probe(struct device *dev) skt = &sinfo->skt[i]; skt->nr = ops->first + i; - skt->irq = NO_IRQ; skt->ops = ops; skt->socket.owner = ops->owner; skt->socket.dev.parent = dev; + skt->socket.pci_irq = NO_IRQ; ret = pxa2xx_drv_pcmcia_add_one(skt); if (ret) diff --git a/drivers/pcmcia/pxa2xx_cm_x255.c b/drivers/pcmcia/pxa2xx_cm_x255.c index 5143a760153..05913d0bbdb 100644 --- a/drivers/pcmcia/pxa2xx_cm_x255.c +++ b/drivers/pcmcia/pxa2xx_cm_x255.c @@ -44,7 +44,7 @@ static int cmx255_pcmcia_hw_init(struct soc_pcmcia_socket *skt) return ret; gpio_direction_output(GPIO_PCMCIA_RESET, 0); - skt->irq = skt->nr == 0 ? PCMCIA_S0_RDYINT : PCMCIA_S1_RDYINT; + skt->socket.pci_irq = skt->nr == 0 ? PCMCIA_S0_RDYINT : PCMCIA_S1_RDYINT; ret = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); if (!ret) gpio_free(GPIO_PCMCIA_RESET); diff --git a/drivers/pcmcia/pxa2xx_cm_x270.c b/drivers/pcmcia/pxa2xx_cm_x270.c index a7b943d01e3..5662646b84d 100644 --- a/drivers/pcmcia/pxa2xx_cm_x270.c +++ b/drivers/pcmcia/pxa2xx_cm_x270.c @@ -38,7 +38,7 @@ static int cmx270_pcmcia_hw_init(struct soc_pcmcia_socket *skt) return ret; gpio_direction_output(GPIO_PCMCIA_RESET, 0); - skt->irq = PCMCIA_S0_RDYINT; + skt->socket.pci_irq = PCMCIA_S0_RDYINT; ret = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); if (!ret) gpio_free(GPIO_PCMCIA_RESET); diff --git a/drivers/pcmcia/pxa2xx_e740.c b/drivers/pcmcia/pxa2xx_e740.c index d09c0dc4a31..8bfbd4dca13 100644 --- a/drivers/pcmcia/pxa2xx_e740.c +++ b/drivers/pcmcia/pxa2xx_e740.c @@ -38,7 +38,7 @@ static struct pcmcia_irqs cd_irqs[] = { static int e740_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { - skt->irq = skt->nr == 0 ? IRQ_GPIO(GPIO_E740_PCMCIA_RDY0) : + skt->socket.pci_irq = skt->nr == 0 ? IRQ_GPIO(GPIO_E740_PCMCIA_RDY0) : IRQ_GPIO(GPIO_E740_PCMCIA_RDY1); return soc_pcmcia_request_irqs(skt, &cd_irqs[skt->nr], 1); diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c index 1138551ba8f..92016fe932b 100644 --- a/drivers/pcmcia/pxa2xx_mainstone.c +++ b/drivers/pcmcia/pxa2xx_mainstone.c @@ -44,7 +44,7 @@ static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt) * before we enable them as outputs. */ - skt->irq = (skt->nr == 0) ? MAINSTONE_S0_IRQ : MAINSTONE_S1_IRQ; + skt->socket.pci_irq = (skt->nr == 0) ? MAINSTONE_S0_IRQ : MAINSTONE_S1_IRQ; return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } diff --git a/drivers/pcmcia/pxa2xx_palmld.c b/drivers/pcmcia/pxa2xx_palmld.c index 5ba9b3664a0..6fb6f7f0672 100644 --- a/drivers/pcmcia/pxa2xx_palmld.c +++ b/drivers/pcmcia/pxa2xx_palmld.c @@ -45,7 +45,7 @@ static int palmld_pcmcia_hw_init(struct soc_pcmcia_socket *skt) if (ret) goto err4; - skt->irq = IRQ_GPIO(GPIO_NR_PALMLD_PCMCIA_READY); + skt->socket.pci_irq = IRQ_GPIO(GPIO_NR_PALMLD_PCMCIA_READY); return 0; err4: diff --git a/drivers/pcmcia/pxa2xx_palmtx.c b/drivers/pcmcia/pxa2xx_palmtx.c index e07b5c51ec5..b07b247a399 100644 --- a/drivers/pcmcia/pxa2xx_palmtx.c +++ b/drivers/pcmcia/pxa2xx_palmtx.c @@ -53,7 +53,7 @@ static int palmtx_pcmcia_hw_init(struct soc_pcmcia_socket *skt) if (ret) goto err5; - skt->irq = gpio_to_irq(GPIO_NR_PALMTX_PCMCIA_READY); + skt->socket.pci_irq = gpio_to_irq(GPIO_NR_PALMTX_PCMCIA_READY); return 0; err5: diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index bc43f78f6f0..0ea3b29440e 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c @@ -66,7 +66,7 @@ static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt) } } - skt->irq = SCOOP_DEV[skt->nr].irq; + skt->socket.pci_irq = SCOOP_DEV[skt->nr].irq; return 0; } diff --git a/drivers/pcmcia/pxa2xx_trizeps4.c b/drivers/pcmcia/pxa2xx_trizeps4.c index e0e5cb339b4..b7e596620db 100644 --- a/drivers/pcmcia/pxa2xx_trizeps4.c +++ b/drivers/pcmcia/pxa2xx_trizeps4.c @@ -53,7 +53,7 @@ static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt) gpio_free(GPIO_PRDY); return -EINVAL; } - skt->irq = IRQ_GPIO(GPIO_PRDY); + skt->socket.pci_irq = IRQ_GPIO(GPIO_PRDY); break; #ifndef CONFIG_MACH_TRIZEPS_CONXS @@ -63,7 +63,7 @@ static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt) break; } /* release the reset of this card */ - pr_debug("%s: sock %d irq %d\n", __func__, skt->nr, skt->irq); + pr_debug("%s: sock %d irq %d\n", __func__, skt->nr, skt->socket.pci_irq); /* supplementory irqs for the socket */ for (i = 0; i < ARRAY_SIZE(irqs); i++) { diff --git a/drivers/pcmcia/pxa2xx_viper.c b/drivers/pcmcia/pxa2xx_viper.c index 17871360fe9..27be2e154df 100644 --- a/drivers/pcmcia/pxa2xx_viper.c +++ b/drivers/pcmcia/pxa2xx_viper.c @@ -40,7 +40,7 @@ static int viper_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { unsigned long flags; - skt->irq = gpio_to_irq(VIPER_CF_RDY_GPIO); + skt->socket.pci_irq = gpio_to_irq(VIPER_CF_RDY_GPIO); if (gpio_request(VIPER_CF_CD_GPIO, "CF detect")) goto err_request_cd; diff --git a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c index ac8aa09ba0d..fd013a1ef47 100644 --- a/drivers/pcmcia/sa1100_assabet.c +++ b/drivers/pcmcia/sa1100_assabet.c @@ -27,7 +27,7 @@ static struct pcmcia_irqs irqs[] = { static int assabet_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { - skt->irq = ASSABET_IRQ_GPIO_CF_IRQ; + skt->socket.pci_irq = ASSABET_IRQ_GPIO_CF_IRQ; return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } diff --git a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c index 63e6bc431a0..9bf088b1727 100644 --- a/drivers/pcmcia/sa1100_cerf.c +++ b/drivers/pcmcia/sa1100_cerf.c @@ -27,7 +27,7 @@ static struct pcmcia_irqs irqs[] = { static int cerf_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { - skt->irq = CERF_IRQ_GPIO_CF_IRQ; + skt->socket.pci_irq = CERF_IRQ_GPIO_CF_IRQ; return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } diff --git a/drivers/pcmcia/sa1100_h3600.c b/drivers/pcmcia/sa1100_h3600.c index 0cc3748f375..3a121ac697d 100644 --- a/drivers/pcmcia/sa1100_h3600.c +++ b/drivers/pcmcia/sa1100_h3600.c @@ -25,8 +25,8 @@ static struct pcmcia_irqs irqs[] = { static int h3600_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { - skt->irq = skt->nr ? IRQ_GPIO_H3600_PCMCIA_IRQ1 - : IRQ_GPIO_H3600_PCMCIA_IRQ0; + skt->socket.pci_irq = skt->nr ? IRQ_GPIO_H3600_PCMCIA_IRQ1 + : IRQ_GPIO_H3600_PCMCIA_IRQ0; return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); diff --git a/drivers/pcmcia/sa1100_shannon.c b/drivers/pcmcia/sa1100_shannon.c index 46d8c1977c2..c4d51867a05 100644 --- a/drivers/pcmcia/sa1100_shannon.c +++ b/drivers/pcmcia/sa1100_shannon.c @@ -28,7 +28,7 @@ static int shannon_pcmcia_hw_init(struct soc_pcmcia_socket *skt) GAFR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1); - skt->irq = skt->nr ? SHANNON_IRQ_GPIO_RDY_1 : SHANNON_IRQ_GPIO_RDY_0; + skt->socket.pci_irq = skt->nr ? SHANNON_IRQ_GPIO_RDY_1 : SHANNON_IRQ_GPIO_RDY_0; return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } diff --git a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c index 33a08ae09fd..05bd504e6f1 100644 --- a/drivers/pcmcia/sa1100_simpad.c +++ b/drivers/pcmcia/sa1100_simpad.c @@ -28,7 +28,7 @@ static int simpad_pcmcia_hw_init(struct soc_pcmcia_socket *skt) clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); - skt->irq = IRQ_GPIO_CF_IRQ; + skt->socket.pci_irq = IRQ_GPIO_CF_IRQ; return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index 219860aba81..deb5036ee5f 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -137,10 +137,10 @@ int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops, return -ENOMEM; s->soc.nr = ops->first + i; - s->soc.irq = s->soc.nr ? IRQ_S1_READY_NINT : IRQ_S0_READY_NINT; s->soc.ops = ops; s->soc.socket.owner = ops->owner; s->soc.socket.dev.parent = &dev->dev; + s->soc.socket.pci_irq = s->soc.nr ? IRQ_S1_READY_NINT : IRQ_S0_READY_NINT; s->dev = dev; ret = add(&s->soc); diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c index ac998724313..fc9a6527019 100644 --- a/drivers/pcmcia/sa11xx_base.c +++ b/drivers/pcmcia/sa11xx_base.c @@ -235,10 +235,10 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, skt = &sinfo->skt[i]; skt->nr = first + i; - skt->irq = NO_IRQ; skt->ops = ops; skt->socket.owner = ops->owner; skt->socket.dev.parent = dev; + skt->socket.pci_irq = NO_IRQ; ret = sa11xx_drv_pcmcia_add_one(skt); if (ret) diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 6bc60f84a44..6f1a86b43c6 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -144,10 +144,10 @@ soc_common_pcmcia_config_skt(struct soc_pcmcia_socket *skt, socket_state_t *stat */ if (skt->irq_state != 1 && state->io_irq) { skt->irq_state = 1; - set_irq_type(skt->irq, IRQ_TYPE_EDGE_FALLING); + set_irq_type(skt->socket.pci_irq, IRQ_TYPE_EDGE_FALLING); } else if (skt->irq_state == 1 && state->io_irq == 0) { skt->irq_state = 0; - set_irq_type(skt->irq, IRQ_TYPE_NONE); + set_irq_type(skt->socket.pci_irq, IRQ_TYPE_NONE); } skt->cs_state = *state; @@ -492,7 +492,8 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr, ch p+=sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc); p+=sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp); - p+=sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq, skt->irq); + p+=sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq, + skt->socket.pci_irq); if (skt->ops->show_timing) p+=skt->ops->show_timing(skt, p); @@ -695,7 +696,6 @@ int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt) skt->socket.resource_ops = &pccard_static_ops; skt->socket.irq_mask = 0; skt->socket.map_size = PAGE_SIZE; - skt->socket.pci_irq = skt->irq; skt->socket.io_offset = (unsigned long)skt->virt_io; skt->status = soc_common_pcmcia_skt_state(skt); diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index 4fb06f797ad..e40824ce6b0 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -31,7 +31,6 @@ struct soc_pcmcia_socket { * Info from low level handler */ unsigned int nr; - unsigned int irq; /* * Core PCMCIA state From 55a19b39acb8888af8e9cfe5b762d03c52fdb48c Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Thu, 29 Oct 2009 00:54:49 +0100 Subject: [PATCH 114/298] pcmcia/staging: update comedi drivers Update comedi PCMCIA drivers to work with recent PCMCIA changes documented in Documentation/pcmcia/driver-changes.txt: - use pcmcia_config_loop() - don't use PCMCIA_DEBUG, but use dev_dbg() - don't use cs_error() - re-use prod_id and card_id values already stored Acked-by: Greg Kroah-Hartman Signed-off-by: Dominik Brodowski --- drivers/staging/comedi/drivers/cb_das16_cs.c | 222 ++++------------ drivers/staging/comedi/drivers/das08_cs.c | 202 ++++---------- drivers/staging/comedi/drivers/ni_daq_700.c | 246 ++++++------------ drivers/staging/comedi/drivers/ni_daq_dio24.c | 245 ++++++----------- drivers/staging/comedi/drivers/ni_labpc_cs.c | 238 ++++++----------- drivers/staging/comedi/drivers/ni_mio_cs.c | 133 +++------- .../staging/comedi/drivers/quatech_daqp_cs.c | 219 ++++------------ 7 files changed, 447 insertions(+), 1058 deletions(-) diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index 80c0df8656f..9e758027efe 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -141,37 +141,14 @@ static int das16cs_timer_insn_config(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data); -static int get_prodid(struct comedi_device *dev, struct pcmcia_device *link) -{ - tuple_t tuple; - u_short buf[128]; - int prodid = 0; - - tuple.TupleData = (cisdata_t *) buf; - tuple.TupleOffset = 0; - tuple.TupleDataMax = 255; - tuple.DesiredTuple = CISTPL_MANFID; - tuple.Attributes = TUPLE_RETURN_COMMON; - if ((pcmcia_get_first_tuple(link, &tuple) == 0) && - (pcmcia_get_tuple_data(link, &tuple) == 0)) { - prodid = le16_to_cpu(buf[1]); - } - - return prodid; -} - static const struct das16cs_board *das16cs_probe(struct comedi_device *dev, struct pcmcia_device *link) { - int id; int i; - id = get_prodid(dev, link); - for (i = 0; i < n_boards; i++) { - if (das16cs_boards[i].device_id == id) { + if (das16cs_boards[i].device_id == link->card_id) return das16cs_boards + i; - } } printk("unknown board!\n"); @@ -660,27 +637,8 @@ static int das16cs_timer_insn_config(struct comedi_device *dev, ======================================================================*/ -/* - All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If - you do not define PCMCIA_DEBUG at all, all the debug code will be - left out. If you compile with PCMCIA_DEBUG=0, the debug code will - be present but disabled -- but it can then be enabled for specific - modules at load time with a 'pc_debug=#' option to insmod. -*/ #if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE) -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0644); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = - "cb_das16_cs.c pcmcia code (David Schleef), modified from dummy_cs.c 1.31 2001/08/24 12:13:13 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - -/*====================================================================*/ - static void das16cs_pcmcia_config(struct pcmcia_device *link); static void das16cs_pcmcia_release(struct pcmcia_device *link); static int das16cs_pcmcia_suspend(struct pcmcia_device *p_dev); @@ -733,7 +691,7 @@ static int das16cs_pcmcia_attach(struct pcmcia_device *link) { struct local_info_t *local; - DEBUG(0, "das16cs_pcmcia_attach()\n"); + dev_dbg(&link->dev, "das16cs_pcmcia_attach()\n"); /* Allocate space for private device-specific data */ local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); @@ -760,7 +718,7 @@ static int das16cs_pcmcia_attach(struct pcmcia_device *link) static void das16cs_pcmcia_detach(struct pcmcia_device *link) { - DEBUG(0, "das16cs_pcmcia_detach(0x%p)\n", link); + dev_dbg(&link->dev, "das16cs_pcmcia_detach\n"); if (link->dev_node) { ((struct local_info_t *)link->priv)->stop = 1; @@ -771,118 +729,55 @@ static void das16cs_pcmcia_detach(struct pcmcia_device *link) kfree(link->priv); } /* das16cs_pcmcia_detach */ + +static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + if (cfg->index == 0) + return -EINVAL; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1) + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + p_dev->io.Attributes2 = p_dev->io.Attributes1; + p_dev->io.BasePort2 = io->win[1].base; + p_dev->io.NumPorts2 = io->win[1].len; + } + /* This reserves IO space but doesn't actually enable it */ + return pcmcia_request_io(p_dev, &p_dev->io); + } + + return 0; +} + static void das16cs_pcmcia_config(struct pcmcia_device *link) { struct local_info_t *dev = link->priv; - tuple_t tuple; - cisparse_t parse; - int last_fn, last_ret; - u_char buf[64]; - cistpl_cftable_entry_t dflt = { 0 }; + int ret; - DEBUG(0, "das16cs_pcmcia_config(0x%p)\n", link); + dev_dbg(&link->dev, "das16cs_pcmcia_config\n"); - /* - This reads the card's CONFIG tuple to find its configuration - registers. - */ - tuple.DesiredTuple = CISTPL_CONFIG; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - - last_fn = GetFirstTuple; - last_ret = pcmcia_get_first_tuple(link, &tuple); - if (last_ret != 0) - goto cs_failed; - - last_fn = GetTupleData; - last_ret = pcmcia_get_tuple_data(link, &tuple); - if (last_ret != 0) - goto cs_failed; - - last_fn = ParseTuple; - last_ret = pcmcia_parse_tuple(&tuple, &parse); - if (last_ret != 0) - goto cs_failed; - - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - - /* - In this loop, we scan the CIS for configuration table entries, - each of which describes a valid card configuration, including - voltage, IO window, memory window, and interrupt settings. - - We make no assumptions about the card to be configured: we use - just the information available in the CIS. In an ideal world, - this would work for any PCMCIA card, but it requires a complete - and accurate CIS. In practice, a driver usually "knows" most of - these things without consulting the CIS, and most client drivers - will only use the CIS to fill in implementation-defined details. - */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - last_fn = GetFirstTuple; - - last_ret = pcmcia_get_first_tuple(link, &tuple); - if (last_ret) - goto cs_failed; - - while (1) { - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - if (pcmcia_get_tuple_data(link, &tuple)) - goto next_entry; - if (pcmcia_parse_tuple(&tuple, &parse)) - goto next_entry; - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - dflt = *cfg; - if (cfg->index == 0) - goto next_entry; - link->conf.ConfigIndex = cfg->index; - - /* Does this card need audio output? */ -/* if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } -*/ - /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) - link->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link, &link->io)) - goto next_entry; - } - - /* If we got this far, we're cool! */ - break; - -next_entry: - last_fn = GetNextTuple; - - last_ret = pcmcia_get_next_tuple(link, &tuple); - if (last_ret) - goto cs_failed; + ret = pcmcia_loop_config(link, das16cs_pcmcia_config_loop, NULL); + if (ret) { + dev_warn(&link->dev, "no configuration found\n"); + goto failed; } /* @@ -891,21 +786,18 @@ next_entry: irq structure is initialized. */ if (link->conf.Attributes & CONF_ENABLE_IRQ) { - last_fn = RequestIRQ; - - last_ret = pcmcia_request_irq(link, &link->irq); - if (last_ret) - goto cs_failed; + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; } /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - last_fn = RequestConfiguration; - last_ret = pcmcia_request_configuration(link, &link->conf); - if (last_ret) - goto cs_failed; + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; /* At this point, the dev_node_t structure(s) need to be @@ -930,14 +822,13 @@ next_entry: return; -cs_failed: - cs_error(link, last_fn, last_ret); +failed: das16cs_pcmcia_release(link); } /* das16cs_pcmcia_config */ static void das16cs_pcmcia_release(struct pcmcia_device *link) { - DEBUG(0, "das16cs_pcmcia_release(0x%p)\n", link); + dev_dbg(&link->dev, "das16cs_pcmcia_release\n"); pcmcia_disable_device(link); } /* das16cs_pcmcia_release */ @@ -983,14 +874,13 @@ struct pcmcia_driver das16cs_driver = { static int __init init_das16cs_pcmcia_cs(void) { - DEBUG(0, "%s\n", version); pcmcia_register_driver(&das16cs_driver); return 0; } static void __exit exit_das16cs_pcmcia_cs(void) { - DEBUG(0, "das16cs_pcmcia_cs: unloading\n"); + pr_debug("das16cs_pcmcia_cs: unloading\n"); pcmcia_unregister_driver(&das16cs_driver); } diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c index 9cab21eaaa1..384a77a37c2 100644 --- a/drivers/staging/comedi/drivers/das08_cs.c +++ b/drivers/staging/comedi/drivers/das08_cs.c @@ -110,25 +110,6 @@ static int das08_cs_attach(struct comedi_device *dev, ======================================================================*/ -/* - All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If - you do not define PCMCIA_DEBUG at all, all the debug code will be - left out. If you compile with PCMCIA_DEBUG=0, the debug code will - be present but disabled -- but it can then be enabled for specific - modules at load time with a 'pc_debug=#' option to insmod. -*/ - -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0644); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static const char *version = - "das08.c pcmcia code (Frank Hess), modified from dummy_cs.c 1.31 2001/08/24 12:13:13 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - -/*====================================================================*/ static void das08_pcmcia_config(struct pcmcia_device *link); static void das08_pcmcia_release(struct pcmcia_device *link); static int das08_pcmcia_suspend(struct pcmcia_device *p_dev); @@ -181,7 +162,7 @@ static int das08_pcmcia_attach(struct pcmcia_device *link) { struct local_info_t *local; - DEBUG(0, "das08_pcmcia_attach()\n"); + dev_dbg(&link->dev, "das08_pcmcia_attach()\n"); /* Allocate space for private device-specific data */ local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); @@ -224,7 +205,7 @@ static int das08_pcmcia_attach(struct pcmcia_device *link) static void das08_pcmcia_detach(struct pcmcia_device *link) { - DEBUG(0, "das08_pcmcia_detach(0x%p)\n", link); + dev_dbg(&link->dev, "das08_pcmcia_detach\n"); if (link->dev_node) { ((struct local_info_t *)link->priv)->stop = 1; @@ -237,6 +218,44 @@ static void das08_pcmcia_detach(struct pcmcia_device *link) } /* das08_pcmcia_detach */ + +static int das08_pcmcia_config_loop(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + if (cfg->index == 0) + return -ENODEV; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1) + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + p_dev->io.Attributes2 = p_dev->io.Attributes1; + p_dev->io.BasePort2 = io->win[1].base; + p_dev->io.NumPorts2 = io->win[1].len; + } + /* This reserves IO space but doesn't actually enable it */ + return pcmcia_request_io(p_dev, &p_dev->io); + } + return 0; +} + + /*====================================================================== das08_pcmcia_config() is scheduled to run after a CARD_INSERTION event @@ -248,128 +267,20 @@ static void das08_pcmcia_detach(struct pcmcia_device *link) static void das08_pcmcia_config(struct pcmcia_device *link) { struct local_info_t *dev = link->priv; - tuple_t tuple; - cisparse_t parse; - int last_fn, last_ret; - u_char buf[64]; - cistpl_cftable_entry_t dflt = { 0 }; + int ret; - DEBUG(0, "das08_pcmcia_config(0x%p)\n", link); + dev_dbg(&link->dev, "das08_pcmcia_config\n"); - /* - This reads the card's CONFIG tuple to find its configuration - registers. - */ - tuple.DesiredTuple = CISTPL_CONFIG; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - last_fn = GetFirstTuple; - - last_ret = pcmcia_get_first_tuple(link, &tuple); - if (last_ret) - goto cs_failed; - - last_fn = GetTupleData; - - last_ret = pcmcia_get_tuple_data(link, &tuple); - if (last_ret) - goto cs_failed; - - last_fn = ParseTuple; - - last_ret = pcmcia_parse_tuple(&tuple, &parse); - if (last_ret) - goto cs_failed; - - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - - /* - In this loop, we scan the CIS for configuration table entries, - each of which describes a valid card configuration, including - voltage, IO window, memory window, and interrupt settings. - - We make no assumptions about the card to be configured: we use - just the information available in the CIS. In an ideal world, - this would work for any PCMCIA card, but it requires a complete - and accurate CIS. In practice, a driver usually "knows" most of - these things without consulting the CIS, and most client drivers - will only use the CIS to fill in implementation-defined details. - */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - last_fn = GetFirstTuple; - - last_ret = pcmcia_get_first_tuple(link, &tuple); - if (last_ret) - goto cs_failed; - - while (1) { - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - - last_ret = pcmcia_get_tuple_data(link, &tuple); - if (last_ret) - goto next_entry; - - last_ret = pcmcia_parse_tuple(&tuple, &parse); - if (last_ret) - goto next_entry; - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - dflt = *cfg; - if (cfg->index == 0) - goto next_entry; - link->conf.ConfigIndex = cfg->index; - - /* Does this card need audio output? */ -/* if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } -*/ - /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) - link->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link, &link->io) != 0) - goto next_entry; - } - - /* If we got this far, we're cool! */ - break; - -next_entry: - last_fn = GetNextTuple; - - last_ret = pcmcia_get_next_tuple(link, &tuple); - if (last_ret) - goto cs_failed; + ret = pcmcia_loop_config(link, das08_pcmcia_config_loop, NULL); + if (ret) { + dev_warn(&link->dev, "no configuration found\n"); + goto failed; } if (link->conf.Attributes & CONF_ENABLE_IRQ) { - last_fn = RequestIRQ; - last_ret = pcmcia_request_irq(link, &link->irq); - if (last_ret) - goto cs_failed; + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; } /* @@ -377,10 +288,9 @@ next_entry: the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - last_fn = RequestConfiguration; - last_ret = pcmcia_request_configuration(link, &link->conf); - if (last_ret) - goto cs_failed; + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; /* At this point, the dev_node_t structure(s) need to be @@ -405,8 +315,7 @@ next_entry: return; -cs_failed: - cs_error(link, last_fn, last_ret); +failed: das08_pcmcia_release(link); } /* das08_pcmcia_config */ @@ -421,7 +330,7 @@ cs_failed: static void das08_pcmcia_release(struct pcmcia_device *link) { - DEBUG(0, "das08_pcmcia_release(0x%p)\n", link); + dev_dbg(&link->dev, "das08_pcmcia_release\n"); pcmcia_disable_device(link); } /* das08_pcmcia_release */ @@ -477,14 +386,13 @@ struct pcmcia_driver das08_cs_driver = { static int __init init_das08_pcmcia_cs(void) { - DEBUG(0, "%s\n", version); pcmcia_register_driver(&das08_cs_driver); return 0; } static void __exit exit_das08_pcmcia_cs(void) { - DEBUG(0, "das08_pcmcia_cs: unloading\n"); + pr_debug("das08_pcmcia_cs: unloading\n"); pcmcia_unregister_driver(&das08_cs_driver); } diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c index ec31a397066..e06d5b2bc33 100644 --- a/drivers/staging/comedi/drivers/ni_daq_700.c +++ b/drivers/staging/comedi/drivers/ni_daq_700.c @@ -436,25 +436,7 @@ static int dio700_detach(struct comedi_device *dev) return 0; }; -/* PCMCIA crap */ - -/* - All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If - you do not define PCMCIA_DEBUG at all, all the debug code will be - left out. If you compile with PCMCIA_DEBUG=0, the debug code will - be present but disabled -- but it can then be enabled for specific - modules at load time with a 'pc_debug=#' option to insmod. -*/ -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0644); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = "ni_daq_700.c, based on dummy_cs.c"; -#else -#define DEBUG(n, args...) -#endif - -/*====================================================================*/ +/* PCMCIA crap -- watch your words, please! */ static void dio700_config(struct pcmcia_device *link); static void dio700_release(struct pcmcia_device *link); @@ -510,7 +492,7 @@ static int dio700_cs_attach(struct pcmcia_device *link) printk(KERN_INFO "ni_daq_700: cs-attach\n"); - DEBUG(0, "dio700_cs_attach()\n"); + dev_dbg(&link->dev, "dio700_cs_attach()\n"); /* Allocate space for private device-specific data */ local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); @@ -555,7 +537,7 @@ static void dio700_cs_detach(struct pcmcia_device *link) printk(KERN_INFO "ni_daq_700: cs-detach!\n"); - DEBUG(0, "dio700_cs_detach(0x%p)\n", link); + dev_dbg(&link->dev, "dio700_cs_detach\n"); if (link->dev_node) { ((struct local_info_t *)link->priv)->stop = 1; @@ -576,141 +558,85 @@ static void dio700_cs_detach(struct pcmcia_device *link) ======================================================================*/ +static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + win_req_t *req = priv_data; + memreq_t map; + + if (cfg->index == 0) + return -ENODEV; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + p_dev->conf.Attributes |= CONF_ENABLE_SPKR; + p_dev->conf.Status = CCSR_AUDIO_ENA; + } + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1) + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + p_dev->io.Attributes2 = p_dev->io.Attributes1; + p_dev->io.BasePort2 = io->win[1].base; + p_dev->io.NumPorts2 = io->win[1].len; + } + /* This reserves IO space but doesn't actually enable it */ + if (pcmcia_request_io(p_dev, &p_dev->io) != 0) + return -ENODEV; + } + + if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) { + cistpl_mem_t *mem = + (cfg->mem.nwin) ? &cfg->mem : &dflt->mem; + req->Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM; + req->Attributes |= WIN_ENABLE; + req->Base = mem->win[0].host_addr; + req->Size = mem->win[0].len; + if (req->Size < 0x1000) + req->Size = 0x1000; + req->AccessSpeed = 0; + if (pcmcia_request_window(&p_dev, req, &p_dev->win)) + return -ENODEV; + map.Page = 0; + map.CardOffset = mem->win[0].card_addr; + if (pcmcia_map_mem_page(p_dev->win, &map)) + return -ENODEV; + } + /* If we got this far, we're cool! */ + return 0; +} + static void dio700_config(struct pcmcia_device *link) { struct local_info_t *dev = link->priv; - tuple_t tuple; - cisparse_t parse; - int last_ret; - u_char buf[64]; win_req_t req; - memreq_t map; - cistpl_cftable_entry_t dflt = { 0 }; + int ret; printk(KERN_INFO "ni_daq_700: cs-config\n"); - DEBUG(0, "dio700_config(0x%p)\n", link); + dev_dbg(&link->dev, "dio700_config\n"); - /* - This reads the card's CONFIG tuple to find its configuration - registers. - */ - tuple.DesiredTuple = CISTPL_CONFIG; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - - last_ret = pcmcia_get_first_tuple(link, &tuple); - if (last_ret) { - cs_error(link, GetFirstTuple, last_ret); - goto cs_failed; - } - - last_ret = pcmcia_get_tuple_data(link, &tuple); - if (last_ret) { - cs_error(link, GetTupleData, last_ret); - goto cs_failed; - } - - last_ret = pcmcia_parse_tuple(&tuple, &parse); - if (last_ret) { - cs_error(link, ParseTuple, last_ret); - goto cs_failed; - } - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - - /* - In this loop, we scan the CIS for configuration table entries, - each of which describes a valid card configuration, including - voltage, IO window, memory window, and interrupt settings. - - We make no assumptions about the card to be configured: we use - just the information available in the CIS. In an ideal world, - this would work for any PCMCIA card, but it requires a complete - and accurate CIS. In practice, a driver usually "knows" most of - these things without consulting the CIS, and most client drivers - will only use the CIS to fill in implementation-defined details. - */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - last_ret = pcmcia_get_first_tuple(link, &tuple); - if (last_ret != 0) { - cs_error(link, GetFirstTuple, last_ret); - goto cs_failed; - } - while (1) { - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - if (pcmcia_get_tuple_data(link, &tuple) != 0) - goto next_entry; - if (pcmcia_parse_tuple(&tuple, &parse) != 0) - goto next_entry; - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - dflt = *cfg; - if (cfg->index == 0) - goto next_entry; - link->conf.ConfigIndex = cfg->index; - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } - - /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) - link->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link, &link->io) != 0) - goto next_entry; - } - - if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { - cistpl_mem_t *mem = - (cfg->mem.nwin) ? &cfg->mem : &dflt.mem; - req.Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM; - req.Attributes |= WIN_ENABLE; - req.Base = mem->win[0].host_addr; - req.Size = mem->win[0].len; - if (req.Size < 0x1000) - req.Size = 0x1000; - req.AccessSpeed = 0; - if (pcmcia_request_window(&link, &req, &link->win)) - goto next_entry; - map.Page = 0; - map.CardOffset = mem->win[0].card_addr; - if (pcmcia_map_mem_page(link->win, &map)) - goto next_entry; - } - /* If we got this far, we're cool! */ - break; - -next_entry: - - last_ret = pcmcia_get_next_tuple(link, &tuple); - if (last_ret) { - cs_error(link, GetNextTuple, last_ret); - goto cs_failed; - } + ret = pcmcia_loop_config(link, dio700_pcmcia_config_loop, &req); + if (ret) { + dev_warn(&link->dev, "no configuration found\n"); + goto failed; } /* @@ -719,11 +645,9 @@ next_entry: irq structure is initialized. */ if (link->conf.Attributes & CONF_ENABLE_IRQ) { - last_ret = pcmcia_request_irq(link, &link->irq); - if (last_ret) { - cs_error(link, RequestIRQ, last_ret); - goto cs_failed; - } + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; } /* @@ -731,11 +655,9 @@ next_entry: the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - last_ret = pcmcia_request_configuration(link, &link->conf); - if (last_ret != 0) { - cs_error(link, RequestConfiguration, last_ret); - goto cs_failed; - } + ret = pcmcia_request_configuration(link, &link->conf); + if (ret != 0) + goto failed; /* At this point, the dev_node_t structure(s) need to be @@ -763,7 +685,7 @@ next_entry: return; -cs_failed: +failed: printk(KERN_INFO "ni_daq_700 cs failed"); dio700_release(link); @@ -771,7 +693,7 @@ cs_failed: static void dio700_release(struct pcmcia_device *link) { - DEBUG(0, "dio700_release(0x%p)\n", link); + dev_dbg(&link->dev, "dio700_release\n"); pcmcia_disable_device(link); } /* dio700_release */ @@ -830,15 +752,13 @@ struct pcmcia_driver dio700_cs_driver = { static int __init init_dio700_cs(void) { - printk("ni_daq_700: cs-init \n"); - DEBUG(0, "%s\n", version); pcmcia_register_driver(&dio700_cs_driver); return 0; } static void __exit exit_dio700_cs(void) { - DEBUG(0, "ni_daq_700: unloading\n"); + pr_debug("ni_daq_700: unloading\n"); pcmcia_unregister_driver(&dio700_cs_driver); } diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c index 0700a8bddd1..9257a4224ea 100644 --- a/drivers/staging/comedi/drivers/ni_daq_dio24.c +++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c @@ -187,25 +187,7 @@ static int dio24_detach(struct comedi_device *dev) return 0; }; -/* PCMCIA crap */ - -/* - All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If - you do not define PCMCIA_DEBUG at all, all the debug code will be - left out. If you compile with PCMCIA_DEBUG=0, the debug code will - be present but disabled -- but it can then be enabled for specific - modules at load time with a 'pc_debug=#' option to insmod. -*/ -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0644); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = "ni_daq_dio24.c, based on dummy_cs.c"; -#else -#define DEBUG(n, args...) -#endif - -/*====================================================================*/ +/* PCMCIA crap -- watch your words! */ static void dio24_config(struct pcmcia_device *link); static void dio24_release(struct pcmcia_device *link); @@ -261,7 +243,7 @@ static int dio24_cs_attach(struct pcmcia_device *link) printk(KERN_INFO "ni_daq_dio24: HOLA SOY YO - CS-attach!\n"); - DEBUG(0, "dio24_cs_attach()\n"); + dev_dbg(&link->dev, "dio24_cs_attach()\n"); /* Allocate space for private device-specific data */ local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); @@ -306,7 +288,7 @@ static void dio24_cs_detach(struct pcmcia_device *link) printk(KERN_INFO "ni_daq_dio24: HOLA SOY YO - cs-detach!\n"); - DEBUG(0, "dio24_cs_detach(0x%p)\n", link); + dev_dbg(&link->dev, "dio24_cs_detach\n"); if (link->dev_node) { ((struct local_info_t *)link->priv)->stop = 1; @@ -327,142 +309,85 @@ static void dio24_cs_detach(struct pcmcia_device *link) ======================================================================*/ +static int dio24_pcmcia_config_loop(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + win_req_t *req = priv_data; + memreq_t map; + + if (cfg->index == 0) + return -ENODEV; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + p_dev->conf.Attributes |= CONF_ENABLE_SPKR; + p_dev->conf.Status = CCSR_AUDIO_ENA; + } + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1) + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + p_dev->io.Attributes2 = p_dev->io.Attributes1; + p_dev->io.BasePort2 = io->win[1].base; + p_dev->io.NumPorts2 = io->win[1].len; + } + /* This reserves IO space but doesn't actually enable it */ + if (pcmcia_request_io(p_dev, &p_dev->io) != 0) + return -ENODEV; + } + + if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) { + cistpl_mem_t *mem = + (cfg->mem.nwin) ? &cfg->mem : &dflt->mem; + req->Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM; + req->Attributes |= WIN_ENABLE; + req->Base = mem->win[0].host_addr; + req->Size = mem->win[0].len; + if (req->Size < 0x1000) + req->Size = 0x1000; + req->AccessSpeed = 0; + if (pcmcia_request_window(&p_dev, req, &p_dev->win)) + return -ENODEV; + map.Page = 0; + map.CardOffset = mem->win[0].card_addr; + if (pcmcia_map_mem_page(p_dev->win, &map)) + return -ENODEV; + } + /* If we got this far, we're cool! */ + return 0; +} + static void dio24_config(struct pcmcia_device *link) { struct local_info_t *dev = link->priv; - tuple_t tuple; - cisparse_t parse; - int last_ret; - u_char buf[64]; + int ret; win_req_t req; - memreq_t map; - cistpl_cftable_entry_t dflt = { 0 }; printk(KERN_INFO "ni_daq_dio24: HOLA SOY YO! - config\n"); - DEBUG(0, "dio24_config(0x%p)\n", link); + dev_dbg(&link->dev, "dio24_config\n"); - /* - This reads the card's CONFIG tuple to find its configuration - registers. - */ - tuple.DesiredTuple = CISTPL_CONFIG; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - - last_ret = pcmcia_get_first_tuple(link, &tuple); - if (last_ret) { - cs_error(link, GetFirstTuple, last_ret); - goto cs_failed; - } - - last_ret = pcmcia_get_tuple_data(link, &tuple); - if (last_ret) { - cs_error(link, GetTupleData, last_ret); - goto cs_failed; - } - - last_ret = pcmcia_parse_tuple(&tuple, &parse); - if (last_ret) { - cs_error(link, ParseTuple, last_ret); - goto cs_failed; - } - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - - /* - In this loop, we scan the CIS for configuration table entries, - each of which describes a valid card configuration, including - voltage, IO window, memory window, and interrupt settings. - - We make no assumptions about the card to be configured: we use - just the information available in the CIS. In an ideal world, - this would work for any PCMCIA card, but it requires a complete - and accurate CIS. In practice, a driver usually "knows" most of - these things without consulting the CIS, and most client drivers - will only use the CIS to fill in implementation-defined details. - */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - - last_ret = pcmcia_get_first_tuple(link, &tuple); - if (last_ret) { - cs_error(link, GetFirstTuple, last_ret); - goto cs_failed; - } - while (1) { - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - if (pcmcia_get_tuple_data(link, &tuple) != 0) - goto next_entry; - if (pcmcia_parse_tuple(&tuple, &parse) != 0) - goto next_entry; - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - dflt = *cfg; - if (cfg->index == 0) - goto next_entry; - link->conf.ConfigIndex = cfg->index; - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } - - /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) - link->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link, &link->io) != 0) - goto next_entry; - } - - if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { - cistpl_mem_t *mem = - (cfg->mem.nwin) ? &cfg->mem : &dflt.mem; - req.Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM; - req.Attributes |= WIN_ENABLE; - req.Base = mem->win[0].host_addr; - req.Size = mem->win[0].len; - if (req.Size < 0x1000) - req.Size = 0x1000; - req.AccessSpeed = 0; - if (pcmcia_request_window(&link, &req, &link->win)) - goto next_entry; - map.Page = 0; - map.CardOffset = mem->win[0].card_addr; - if (pcmcia_map_mem_page(link->win, &map)) - goto next_entry; - } - /* If we got this far, we're cool! */ - break; - -next_entry: - - last_ret = pcmcia_get_next_tuple(link, &tuple); - if (last_ret) { - cs_error(link, GetNextTuple, last_ret); - goto cs_failed; - } + ret = pcmcia_loop_config(link, dio24_pcmcia_config_loop, &req); + if (ret) { + dev_warn(&link->dev, "no configuration found\n"); + goto failed; } /* @@ -471,11 +396,9 @@ next_entry: irq structure is initialized. */ if (link->conf.Attributes & CONF_ENABLE_IRQ) { - last_ret = pcmcia_request_irq(link, &link->irq); - if (last_ret) { - cs_error(link, RequestIRQ, last_ret); - goto cs_failed; - } + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; } /* @@ -483,11 +406,9 @@ next_entry: the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - last_ret = pcmcia_request_configuration(link, &link->conf); - if (last_ret) { - cs_error(link, RequestConfiguration, last_ret); - goto cs_failed; - } + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; /* At this point, the dev_node_t structure(s) need to be @@ -515,7 +436,7 @@ next_entry: return; -cs_failed: +failed: printk(KERN_INFO "Fallo"); dio24_release(link); @@ -523,7 +444,7 @@ cs_failed: static void dio24_release(struct pcmcia_device *link) { - DEBUG(0, "dio24_release(0x%p)\n", link); + dev_dbg(&link->dev, "dio24_release\n"); pcmcia_disable_device(link); } /* dio24_release */ @@ -582,14 +503,12 @@ struct pcmcia_driver dio24_cs_driver = { static int __init init_dio24_cs(void) { printk("ni_daq_dio24: HOLA SOY YO!\n"); - DEBUG(0, "%s\n", version); pcmcia_register_driver(&dio24_cs_driver); return 0; } static void __exit exit_dio24_cs(void) { - DEBUG(0, "ni_dio24: unloading\n"); pcmcia_unregister_driver(&dio24_cs_driver); } diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c index a3053b8da1c..28ff4a68cab 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_cs.c +++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c @@ -153,23 +153,6 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) return labpc_common_attach(dev, iobase, irq, 0); } -/* - All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If - you do not define PCMCIA_DEBUG at all, all the debug code will be - left out. If you compile with PCMCIA_DEBUG=0, the debug code will - be present but disabled -- but it can then be enabled for specific - modules at load time with a 'pc_debug=#' option to insmod. -*/ -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0644); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static const char *version = - "ni_labpc.c, based on dummy_cs.c 1.31 2001/08/24 12:13:13"; -#else -#define DEBUG(n, args...) -#endif - /*====================================================================*/ /* @@ -236,7 +219,7 @@ static int labpc_cs_attach(struct pcmcia_device *link) { struct local_info_t *local; - DEBUG(0, "labpc_cs_attach()\n"); + dev_dbg(&link->dev, "labpc_cs_attach()\n"); /* Allocate space for private device-specific data */ local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); @@ -278,7 +261,7 @@ static int labpc_cs_attach(struct pcmcia_device *link) static void labpc_cs_detach(struct pcmcia_device *link) { - DEBUG(0, "labpc_cs_detach(0x%p)\n", link); + dev_dbg(&link->dev, "labpc_cs_detach\n"); /* If the device is currently configured and active, we won't @@ -305,135 +288,84 @@ static void labpc_cs_detach(struct pcmcia_device *link) ======================================================================*/ +static int labpc_pcmcia_config_loop(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + win_req_t *req = priv_data; + memreq_t map; + + if (cfg->index == 0) + return -ENODEV; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + p_dev->conf.Attributes |= CONF_ENABLE_SPKR; + p_dev->conf.Status = CCSR_AUDIO_ENA; + } + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1) + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + p_dev->io.Attributes2 = p_dev->io.Attributes1; + p_dev->io.BasePort2 = io->win[1].base; + p_dev->io.NumPorts2 = io->win[1].len; + } + /* This reserves IO space but doesn't actually enable it */ + if (pcmcia_request_io(p_dev, &p_dev->io) != 0) + return -ENODEV; + } + + if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) { + cistpl_mem_t *mem = + (cfg->mem.nwin) ? &cfg->mem : &dflt->mem; + req->Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM; + req->Attributes |= WIN_ENABLE; + req->Base = mem->win[0].host_addr; + req->Size = mem->win[0].len; + if (req->Size < 0x1000) + req->Size = 0x1000; + req->AccessSpeed = 0; + if (pcmcia_request_window(&p_dev, req, &p_dev->win)) + return -ENODEV; + map.Page = 0; + map.CardOffset = mem->win[0].card_addr; + if (pcmcia_map_mem_page(p_dev->win, &map)) + return -ENODEV; + } + /* If we got this far, we're cool! */ + return 0; +} + + static void labpc_config(struct pcmcia_device *link) { struct local_info_t *dev = link->priv; - tuple_t tuple; - cisparse_t parse; - int last_ret; - u_char buf[64]; + int ret; win_req_t req; - memreq_t map; - cistpl_cftable_entry_t dflt = { 0 }; - DEBUG(0, "labpc_config(0x%p)\n", link); + dev_dbg(&link->dev, "labpc_config\n"); - /* - This reads the card's CONFIG tuple to find its configuration - registers. - */ - tuple.DesiredTuple = CISTPL_CONFIG; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - - last_ret = pcmcia_get_first_tuple(link, &tuple); - if (last_ret) { - cs_error(link, GetFirstTuple, last_ret); - goto cs_failed; - } - - last_ret = pcmcia_get_tuple_data(link, &tuple); - if (last_ret) { - cs_error(link, GetTupleData, last_ret); - goto cs_failed; - } - - last_ret = pcmcia_parse_tuple(&tuple, &parse); - if (last_ret) { - cs_error(link, ParseTuple, last_ret); - goto cs_failed; - } - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - - /* - In this loop, we scan the CIS for configuration table entries, - each of which describes a valid card configuration, including - voltage, IO window, memory window, and interrupt settings. - - We make no assumptions about the card to be configured: we use - just the information available in the CIS. In an ideal world, - this would work for any PCMCIA card, but it requires a complete - and accurate CIS. In practice, a driver usually "knows" most of - these things without consulting the CIS, and most client drivers - will only use the CIS to fill in implementation-defined details. - */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - last_ret = pcmcia_get_first_tuple(link, &tuple); - if (last_ret) { - cs_error(link, GetFirstTuple, last_ret); - goto cs_failed; - } - while (1) { - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - if (pcmcia_get_tuple_data(link, &tuple)) - goto next_entry; - if (pcmcia_parse_tuple(&tuple, &parse)) - goto next_entry; - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - dflt = *cfg; - if (cfg->index == 0) - goto next_entry; - link->conf.ConfigIndex = cfg->index; - - /* Does this card need audio output? */ - if (cfg->flags & CISTPL_CFTABLE_AUDIO) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } - - /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) - link->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link, &link->io)) - goto next_entry; - } - - if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { - cistpl_mem_t *mem = - (cfg->mem.nwin) ? &cfg->mem : &dflt.mem; - req.Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM; - req.Attributes |= WIN_ENABLE; - req.Base = mem->win[0].host_addr; - req.Size = mem->win[0].len; - if (req.Size < 0x1000) - req.Size = 0x1000; - req.AccessSpeed = 0; - link->win = (window_handle_t) link; - if (pcmcia_request_window(&link, &req, &link->win)) - goto next_entry; - map.Page = 0; - map.CardOffset = mem->win[0].card_addr; - if (pcmcia_map_mem_page(link->win, &map)) - goto next_entry; - } - /* If we got this far, we're cool! */ - break; - -next_entry: - last_ret = pcmcia_get_next_tuple(link, &tuple); - if (last_ret) { - cs_error(link, GetNextTuple, last_ret); - goto cs_failed; - } + ret = pcmcia_loop_config(link, labpc_pcmcia_config_loop, &req); + if (ret) { + dev_warn(&link->dev, "no configuration found\n"); + goto failed; } /* @@ -442,11 +374,9 @@ next_entry: irq structure is initialized. */ if (link->conf.Attributes & CONF_ENABLE_IRQ) { - last_ret = pcmcia_request_irq(link, &link->irq); - if (last_ret) { - cs_error(link, RequestIRQ, last_ret); - goto cs_failed; - } + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; } /* @@ -454,11 +384,9 @@ next_entry: the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - last_ret = pcmcia_request_configuration(link, &link->conf); - if (last_ret) { - cs_error(link, RequestConfiguration, last_ret); - goto cs_failed; - } + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; /* At this point, the dev_node_t structure(s) need to be @@ -486,14 +414,14 @@ next_entry: return; -cs_failed: +failed: labpc_release(link); } /* labpc_config */ static void labpc_release(struct pcmcia_device *link) { - DEBUG(0, "labpc_release(0x%p)\n", link); + dev_dbg(&link->dev, "labpc_release\n"); pcmcia_disable_device(link); } /* labpc_release */ @@ -551,14 +479,12 @@ struct pcmcia_driver labpc_cs_driver = { static int __init init_labpc_cs(void) { - DEBUG(0, "%s\n", version); pcmcia_register_driver(&labpc_cs_driver); return 0; } static void __exit exit_labpc_cs(void) { - DEBUG(0, "ni_labpc: unloading\n"); pcmcia_unregister_driver(&labpc_cs_driver); } diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c index 9aef87fc81d..ca7ab4abdc2 100644 --- a/drivers/staging/comedi/drivers/ni_mio_cs.c +++ b/drivers/staging/comedi/drivers/ni_mio_cs.c @@ -312,96 +312,50 @@ static int mio_cs_resume(struct pcmcia_device *link) return 0; } + +static int mio_pcmcia_config_loop(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + int base, ret; + + p_dev->io.NumPorts1 = cfg->io.win[0].len; + p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK; + p_dev->io.NumPorts2 = 0; + + p_dev->irq.IRQInfo1 = cfg->irq.IRQInfo1; + p_dev->irq.IRQInfo2 = cfg->irq.IRQInfo2; + + for (base = 0x000; base < 0x400; base += 0x20) { + p_dev->io.BasePort1 = base; + ret = pcmcia_request_io(p_dev, &p_dev->io); + if (!ret) + return 0; + } + return -ENODEV; +} + + static void mio_cs_config(struct pcmcia_device *link) { - tuple_t tuple; - u_short buf[128]; - cisparse_t parse; - int manfid = 0, prodid = 0; int ret; DPRINTK("mio_cs_config(link=%p)\n", link); - tuple.TupleData = (cisdata_t *) buf; - tuple.TupleOffset = 0; - tuple.TupleDataMax = 255; - tuple.Attributes = 0; - - tuple.DesiredTuple = CISTPL_CONFIG; - ret = pcmcia_get_first_tuple(link, &tuple); - ret = pcmcia_get_tuple_data(link, &tuple); - ret = pcmcia_parse_tuple(&tuple, &parse); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - -#if 0 - tuple.DesiredTuple = CISTPL_LONGLINK_MFC; - tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; - info->multi(first_tuple(link, &tuple, &parse) == 0); -#endif - - tuple.DesiredTuple = CISTPL_MANFID; - tuple.Attributes = TUPLE_RETURN_COMMON; - if ((pcmcia_get_first_tuple(link, &tuple) == 0) && - (pcmcia_get_tuple_data(link, &tuple) == 0)) { - manfid = le16_to_cpu(buf[0]); - prodid = le16_to_cpu(buf[1]); - } - /* printk("manfid = 0x%04x, 0x%04x\n",manfid,prodid); */ - - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - tuple.Attributes = 0; - ret = pcmcia_get_first_tuple(link, &tuple); - ret = pcmcia_get_tuple_data(link, &tuple); - ret = pcmcia_parse_tuple(&tuple, &parse); - -#if 0 - printk(" index: 0x%x\n", parse.cftable_entry.index); - printk(" flags: 0x%x\n", parse.cftable_entry.flags); - printk(" io flags: 0x%x\n", parse.cftable_entry.io.flags); - printk(" io nwin: 0x%x\n", parse.cftable_entry.io.nwin); - printk(" io base: 0x%x\n", parse.cftable_entry.io.win[0].base); - printk(" io len: 0x%x\n", parse.cftable_entry.io.win[0].len); - printk(" irq1: 0x%x\n", parse.cftable_entry.irq.IRQInfo1); - printk(" irq2: 0x%x\n", parse.cftable_entry.irq.IRQInfo2); - printk(" mem flags: 0x%x\n", parse.cftable_entry.mem.flags); - printk(" mem nwin: 0x%x\n", parse.cftable_entry.mem.nwin); - printk(" subtuples: 0x%x\n", parse.cftable_entry.subtuples); -#endif - -#if 0 - link->io.NumPorts1 = 0x20; - link->io.IOAddrLines = 5; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; -#endif - link->io.NumPorts1 = parse.cftable_entry.io.win[0].len; - link->io.IOAddrLines = - parse.cftable_entry.io.flags & CISTPL_IO_LINES_MASK; - link->io.NumPorts2 = 0; - - { - int base; - for (base = 0x000; base < 0x400; base += 0x20) { - link->io.BasePort1 = base; - ret = pcmcia_request_io(link, &link->io); - /* printk("RequestIO 0x%02x\n",ret); */ - if (!ret) - break; - } + ret = pcmcia_loop_config(link, mio_pcmcia_config_loop, NULL); + if (ret) { + dev_warn(&link->dev, "no configuration found\n"); + return; } - link->irq.IRQInfo1 = parse.cftable_entry.irq.IRQInfo1; - link->irq.IRQInfo2 = parse.cftable_entry.irq.IRQInfo2; ret = pcmcia_request_irq(link, &link->irq); if (ret) { printk("pcmcia_request_irq() returned error: %i\n", ret); } - /* printk("RequestIRQ 0x%02x\n",ret); */ - - link->conf.ConfigIndex = 1; ret = pcmcia_request_configuration(link, &link->conf); - /* printk("RequestConfiguration %d\n",ret); */ link->dev_node = &dev_node; } @@ -475,40 +429,17 @@ static int mio_cs_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static int get_prodid(struct comedi_device *dev, struct pcmcia_device *link) -{ - tuple_t tuple; - u_short buf[128]; - int prodid = 0; - - tuple.TupleData = (cisdata_t *) buf; - tuple.TupleOffset = 0; - tuple.TupleDataMax = 255; - tuple.DesiredTuple = CISTPL_MANFID; - tuple.Attributes = TUPLE_RETURN_COMMON; - if ((pcmcia_get_first_tuple(link, &tuple) == 0) && - (pcmcia_get_tuple_data(link, &tuple) == 0)) { - prodid = le16_to_cpu(buf[1]); - } - - return prodid; -} - static int ni_getboardtype(struct comedi_device *dev, struct pcmcia_device *link) { - int id; int i; - id = get_prodid(dev, link); - for (i = 0; i < n_ni_boards; i++) { - if (ni_boards[i].device_id == id) { + if (ni_boards[i].device_id == link->card_id) return i; - } } - printk("unknown board 0x%04x -- pretend it is a ", id); + printk("unknown board 0x%04x -- pretend it is a ", link->card_id); return 0; } diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index 344b82353e0..48e7c27ed87 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -55,23 +55,6 @@ Devices: [Quatech] DAQP-208 (daqp), DAQP-308 #include #include -/* - All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If - you do not define PCMCIA_DEBUG at all, all the debug code will be - left out. If you compile with PCMCIA_DEBUG=0, the debug code will - be present but disabled -- but it can then be enabled for specific - modules at load time with a 'pc_debug=#' option to insmod. -*/ - -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -module_param(pc_debug, int, 0644); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = "quatech_daqp_cs.c 1.10 2003/04/21 (Brent Baccala)"; -#else -#define DEBUG(n, args...) -#endif - /* Maximum number of separate DAQP devices we'll allow */ #define MAX_DEV 4 @@ -863,8 +846,6 @@ static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret; struct local_info_t *local = dev_table[it->options[0]]; - tuple_t tuple; - int i; struct comedi_subdevice *s; if (it->options[0] < 0 || it->options[0] >= MAX_DEV || !local) { @@ -883,29 +864,10 @@ static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it) strcpy(local->board_name, "DAQP"); dev->board_name = local->board_name; - - tuple.DesiredTuple = CISTPL_VERS_1; - if (pcmcia_get_first_tuple(local->link, &tuple) == 0) { - u_char buf[128]; - - buf[0] = buf[sizeof(buf) - 1] = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 2; - if (pcmcia_get_tuple_data(local->link, &tuple) == 0) { - - for (i = 0; i < tuple.TupleDataLen - 4; i++) - if (buf[i] == 0) - break; - for (i++; i < tuple.TupleDataLen - 4; i++) - if (buf[i] == 0) - break; - i++; - if ((i < tuple.TupleDataLen - 4) - && (strncmp(buf + i, "DAQP", 4) == 0)) { - strncpy(local->board_name, buf + i, - sizeof(local->board_name)); - } + if (local->link->prod_id[2]) { + if (strncmp(local->link->prod_id[2], "DAQP", 4) == 0) { + strncpy(local->board_name, local->link->prod_id[2], + sizeof(local->board_name)); } } @@ -1058,7 +1020,7 @@ static int daqp_cs_attach(struct pcmcia_device *link) struct local_info_t *local; int i; - DEBUG(0, "daqp_cs_attach()\n"); + dev_dbg(&link->dev, "daqp_cs_attach()\n"); for (i = 0; i < MAX_DEV; i++) if (dev_table[i] == NULL) @@ -1112,7 +1074,7 @@ static void daqp_cs_detach(struct pcmcia_device *link) { struct local_info_t *dev = link->priv; - DEBUG(0, "daqp_cs_detach(0x%p)\n", link); + dev_dbg(&link->dev, "daqp_cs_detach\n"); if (link->dev_node) { dev->stop = 1; @@ -1134,115 +1096,54 @@ static void daqp_cs_detach(struct pcmcia_device *link) ======================================================================*/ + +static int daqp_pcmcia_config_loop(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cfg, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + if (cfg->index == 0) + return -ENODEV; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1) + p_dev->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + p_dev->io.BasePort1 = io->win[0].base; + p_dev->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + p_dev->io.Attributes2 = p_dev->io.Attributes1; + p_dev->io.BasePort2 = io->win[1].base; + p_dev->io.NumPorts2 = io->win[1].len; + } + } + + /* This reserves IO space but doesn't actually enable it */ + return pcmcia_request_io(p_dev, &p_dev->io); +} + static void daqp_cs_config(struct pcmcia_device *link) { struct local_info_t *dev = link->priv; - tuple_t tuple; - cisparse_t parse; - int last_ret; - u_char buf[64]; + int ret; - DEBUG(0, "daqp_cs_config(0x%p)\n", link); + dev_dbg(&link->dev, "daqp_cs_config\n"); - /* - This reads the card's CONFIG tuple to find its configuration - registers. - */ - tuple.DesiredTuple = CISTPL_CONFIG; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - - last_ret = pcmcia_get_first_tuple(link, &tuple); - if (last_ret) { - cs_error(link, GetFirstTuple, last_ret); - goto cs_failed; - } - - last_ret = pcmcia_get_tuple_data(link, &tuple); - if (last_ret) { - cs_error(link, GetTupleData, last_ret); - goto cs_failed; - } - - last_ret = pcmcia_parse_tuple(&tuple, &parse); - if (last_ret) { - cs_error(link, ParseTuple, last_ret); - goto cs_failed; - } - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - - /* - In this loop, we scan the CIS for configuration table entries, - each of which describes a valid card configuration, including - voltage, IO window, memory window, and interrupt settings. - - We make no assumptions about the card to be configured: we use - just the information available in the CIS. In an ideal world, - this would work for any PCMCIA card, but it requires a complete - and accurate CIS. In practice, a driver usually "knows" most of - these things without consulting the CIS, and most client drivers - will only use the CIS to fill in implementation-defined details. - */ - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - last_ret = pcmcia_get_first_tuple(link, &tuple); - if (last_ret) { - cs_error(link, GetFirstTuple, last_ret); - goto cs_failed; - } - - while (1) { - cistpl_cftable_entry_t dflt = { 0 }; - cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - if (pcmcia_get_tuple_data(link, &tuple)) - goto next_entry; - if (pcmcia_parse_tuple(&tuple, &parse)) - goto next_entry; - - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - dflt = *cfg; - if (cfg->index == 0) - goto next_entry; - link->conf.ConfigIndex = cfg->index; - - /* Do we need to allocate an interrupt? */ - if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) - link->conf.Attributes |= CONF_ENABLE_IRQ; - - /* IO window settings */ - link->io.NumPorts1 = link->io.NumPorts2 = 0; - if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(io->flags & CISTPL_IO_8BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; - link->io.BasePort1 = io->win[0].base; - link->io.NumPorts1 = io->win[0].len; - if (io->nwin > 1) { - link->io.Attributes2 = link->io.Attributes1; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = io->win[1].len; - } - } - - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link, &link->io)) - goto next_entry; - - /* If we got this far, we're cool! */ - break; - -next_entry: - last_ret = pcmcia_get_next_tuple(link, &tuple); - if (last_ret) { - cs_error(link, GetNextTuple, last_ret); - goto cs_failed; - } + ret = pcmcia_loop_config(link, daqp_pcmcia_config_loop, NULL); + if (ret) { + dev_warn(&link->dev, "no configuration found\n"); + goto failed; } /* @@ -1251,11 +1152,9 @@ next_entry: irq structure is initialized. */ if (link->conf.Attributes & CONF_ENABLE_IRQ) { - last_ret = pcmcia_request_irq(link, &link->irq); - if (last_ret) { - cs_error(link, RequestIRQ, last_ret); - goto cs_failed; - } + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; } /* @@ -1263,11 +1162,9 @@ next_entry: the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - last_ret = pcmcia_request_configuration(link, &link->conf); - if (last_ret) { - cs_error(link, RequestConfiguration, last_ret); - goto cs_failed; - } + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; /* At this point, the dev_node_t structure(s) need to be @@ -1296,14 +1193,14 @@ next_entry: return; -cs_failed: +failed: daqp_cs_release(link); } /* daqp_cs_config */ static void daqp_cs_release(struct pcmcia_device *link) { - DEBUG(0, "daqp_cs_release(0x%p)\n", link); + dev_dbg(&link->dev, "daqp_cs_release\n"); pcmcia_disable_device(link); } /* daqp_cs_release */ @@ -1363,7 +1260,6 @@ struct pcmcia_driver daqp_cs_driver = { int __init init_module(void) { - DEBUG(0, "%s\n", version); pcmcia_register_driver(&daqp_cs_driver); comedi_driver_register(&driver_daqp); return 0; @@ -1371,7 +1267,6 @@ int __init init_module(void) void __exit cleanup_module(void) { - DEBUG(0, "daqp_cs: unloading\n"); comedi_driver_unregister(&driver_daqp); pcmcia_unregister_driver(&daqp_cs_driver); } From 638bba55fe6440439005f02fcd6b0c1f908d0d11 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 7 Nov 2009 12:26:17 +0100 Subject: [PATCH 115/298] pcmcia: autoload module pcmcia Attempt to load the "pcmcia" module for 16-bit PCMCIA cards, so that PCMCIA support becomes available without pcmciautils/udev userspace interaction. Based on a suggestion and a patch Signed-off-by: Komuro but converted it to request_module_nowait() and move it to a later stage. Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index b229f6d9e44..fc1c0c6baae 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -243,6 +243,13 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) pcmcia_parse_events(socket, SS_DETECT); + /* + * Let's try to get the PCMCIA module for 16-bit PCMCIA support. + * If it fails, it doesn't matter -- we still have 32-bit CardBus + * support to offer, so this is not a failure mode. + */ + request_module_nowait("pcmcia"); + return 0; err: From f84d49b218b7d4c6cba2e0b41f24bd4045403962 Mon Sep 17 00:00:00 2001 From: Naohiro Ooiwa Date: Mon, 9 Nov 2009 00:46:42 +0900 Subject: [PATCH 116/298] signal: Print warning message when dropping signals When the system has too many timers or too many aggregate queued signals, the EAGAIN error is returned to application from kernel, including timer_create() [POSIX.1b]. It means that the app exceeded the limit of pending signals, but in general application writers do not expect this outcome and the current silent failure can cause rare app failures under very high load. This patch adds a new message when we reach the limit and if print_fatal_signals is enabled: task/1234: reached RLIMIT_SIGPENDING, dropping signal If you see this message and your system behaved unexpectedly, you can run following command to lift the limit: # ulimit -i unlimited With help from Hiroshi Shimamoto . Signed-off-by: Naohiro Ooiwa Cc: Andrew Morton Cc: Hiroshi Shimamoto Cc: Roland McGrath Cc: Peter Zijlstra Cc: oleg@redhat.com LKML-Reference: <4AF6E7E2.9080406@miraclelinux.com> [ Modified a few small details, gave surrounding code some love. ] Signed-off-by: Ingo Molnar --- Documentation/kernel-parameters.txt | 11 +++++-- kernel/signal.c | 46 +++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 9107b387e91..3bbd92f805a 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2032,8 +2032,15 @@ and is between 256 and 4096 characters. It is defined in the file print-fatal-signals= [KNL] debug: print fatal signals - print-fatal-signals=1: print segfault info to - the kernel console. + + If enabled, warn about various signal handling + related application anomalies: too many signals, + too many POSIX.1 timers, fatal signals causing a + coredump - etc. + + If you hit the warning due to signal overflow, + you might want to try "ulimit -i unlimited". + default: off. printk.time= Show timing data prefixed to each printk message line diff --git a/kernel/signal.c b/kernel/signal.c index 6705320784f..fe08008133d 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,8 @@ static struct kmem_cache *sigqueue_cachep; +int print_fatal_signals __read_mostly; + static void __user *sig_handler(struct task_struct *t, int sig) { return t->sighand->action[sig - 1].sa.sa_handler; @@ -159,7 +162,7 @@ int next_signal(struct sigpending *pending, sigset_t *mask) { unsigned long i, *s, *m, x; int sig = 0; - + s = pending->signal.sig; m = mask->sig; switch (_NSIG_WORDS) { @@ -184,17 +187,31 @@ int next_signal(struct sigpending *pending, sigset_t *mask) sig = ffz(~x) + 1; break; } - + return sig; } +static inline void print_dropped_signal(int sig) +{ + static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 10); + + if (!print_fatal_signals) + return; + + if (!__ratelimit(&ratelimit_state)) + return; + + printk(KERN_INFO "%s/%d: reached RLIMIT_SIGPENDING, dropped signal %d\n", + current->comm, current->pid, sig); +} + /* * allocate a new signal queue record * - this may be called without locks if and only if t == current, otherwise an * appopriate lock must be held to stop the target task from exiting */ -static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags, - int override_rlimit) +static struct sigqueue * +__sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimit) { struct sigqueue *q = NULL; struct user_struct *user; @@ -207,10 +224,15 @@ static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags, */ user = get_uid(__task_cred(t)->user); atomic_inc(&user->sigpending); + if (override_rlimit || atomic_read(&user->sigpending) <= - t->signal->rlim[RLIMIT_SIGPENDING].rlim_cur) + t->signal->rlim[RLIMIT_SIGPENDING].rlim_cur) { q = kmem_cache_alloc(sigqueue_cachep, flags); + } else { + print_dropped_signal(sig); + } + if (unlikely(q == NULL)) { atomic_dec(&user->sigpending); free_uid(user); @@ -869,7 +891,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, else override_rlimit = 0; - q = __sigqueue_alloc(t, GFP_ATOMIC | __GFP_NOTRACK_FALSE_POSITIVE, + q = __sigqueue_alloc(sig, t, GFP_ATOMIC | __GFP_NOTRACK_FALSE_POSITIVE, override_rlimit); if (q) { list_add_tail(&q->list, &pending->list); @@ -925,8 +947,6 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t, return __send_signal(sig, info, t, group, from_ancestor_ns); } -int print_fatal_signals; - static void print_fatal_signal(struct pt_regs *regs, int signr) { printk("%s/%d: potentially unexpected fatal signal %d.\n", @@ -1293,19 +1313,19 @@ EXPORT_SYMBOL(kill_pid); * These functions support sending signals using preallocated sigqueue * structures. This is needed "because realtime applications cannot * afford to lose notifications of asynchronous events, like timer - * expirations or I/O completions". In the case of Posix Timers + * expirations or I/O completions". In the case of Posix Timers * we allocate the sigqueue structure from the timer_create. If this * allocation fails we are able to report the failure to the application * with an EAGAIN error. */ - struct sigqueue *sigqueue_alloc(void) { - struct sigqueue *q; + struct sigqueue *q = __sigqueue_alloc(-1, current, GFP_KERNEL, 0); - if ((q = __sigqueue_alloc(current, GFP_KERNEL, 0))) + if (q) q->flags |= SIGQUEUE_PREALLOC; - return(q); + + return q; } void sigqueue_free(struct sigqueue *q) From dd8dbf2e6880e30c00b18600c962d0cb5a03c555 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Tue, 3 Nov 2009 16:35:32 +1100 Subject: [PATCH 117/298] security: report the module name to security_module_request For SELinux to do better filtering in userspace we send the name of the module along with the AVC denial when a program is denied module_request. Example output: type=SYSCALL msg=audit(11/03/2009 10:59:43.510:9) : arch=x86_64 syscall=write success=yes exit=2 a0=3 a1=7fc28c0d56c0 a2=2 a3=7fffca0d7440 items=0 ppid=1727 pid=1729 auid=unset uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=(none) ses=unset comm=rpc.nfsd exe=/usr/sbin/rpc.nfsd subj=system_u:system_r:nfsd_t:s0 key=(null) type=AVC msg=audit(11/03/2009 10:59:43.510:9) : avc: denied { module_request } for pid=1729 comm=rpc.nfsd kmod="net-pf-10" scontext=system_u:system_r:nfsd_t:s0 tcontext=system_u:system_r:kernel_t:s0 tclass=system Signed-off-by: Eric Paris Signed-off-by: James Morris --- include/linux/lsm_audit.h | 18 ++++++++++-------- include/linux/security.h | 7 ++++--- kernel/kmod.c | 8 ++++---- security/capability.c | 2 +- security/lsm_audit.c | 4 ++++ security/security.c | 4 ++-- security/selinux/hooks.c | 13 +++++++++++-- 7 files changed, 36 insertions(+), 20 deletions(-) diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h index 190c3785487..f78f83d7663 100644 --- a/include/linux/lsm_audit.h +++ b/include/linux/lsm_audit.h @@ -26,14 +26,15 @@ /* Auxiliary data to use in generating the audit record. */ struct common_audit_data { - char type; -#define LSM_AUDIT_DATA_FS 1 -#define LSM_AUDIT_DATA_NET 2 -#define LSM_AUDIT_DATA_CAP 3 -#define LSM_AUDIT_DATA_IPC 4 -#define LSM_AUDIT_DATA_TASK 5 -#define LSM_AUDIT_DATA_KEY 6 -#define LSM_AUDIT_NO_AUDIT 7 + char type; +#define LSM_AUDIT_DATA_FS 1 +#define LSM_AUDIT_DATA_NET 2 +#define LSM_AUDIT_DATA_CAP 3 +#define LSM_AUDIT_DATA_IPC 4 +#define LSM_AUDIT_DATA_TASK 5 +#define LSM_AUDIT_DATA_KEY 6 +#define LSM_AUDIT_NO_AUDIT 7 +#define LSM_AUDIT_DATA_KMOD 8 struct task_struct *tsk; union { struct { @@ -66,6 +67,7 @@ struct common_audit_data { char *key_desc; } key_struct; #endif + char *kmod_name; } u; /* this union contains LSM specific data */ union { diff --git a/include/linux/security.h b/include/linux/security.h index ed0faea60b8..466cbadbd1e 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -706,6 +706,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @kernel_module_request: * Ability to trigger the kernel to automatically upcall to userspace for * userspace to load a kernel module with the given name. + * @kmod_name name of the module requested by the kernel * Return 0 if successful. * @task_setuid: * Check permission before setting one or more of the user identity @@ -1577,7 +1578,7 @@ struct security_operations { void (*cred_transfer)(struct cred *new, const struct cred *old); int (*kernel_act_as)(struct cred *new, u32 secid); int (*kernel_create_files_as)(struct cred *new, struct inode *inode); - int (*kernel_module_request)(void); + int (*kernel_module_request)(char *kmod_name); int (*task_setuid) (uid_t id0, uid_t id1, uid_t id2, int flags); int (*task_fix_setuid) (struct cred *new, const struct cred *old, int flags); @@ -1842,7 +1843,7 @@ void security_commit_creds(struct cred *new, const struct cred *old); void security_transfer_creds(struct cred *new, const struct cred *old); int security_kernel_act_as(struct cred *new, u32 secid); int security_kernel_create_files_as(struct cred *new, struct inode *inode); -int security_kernel_module_request(void); +int security_kernel_module_request(char *kmod_name); int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags); int security_task_fix_setuid(struct cred *new, const struct cred *old, int flags); @@ -2407,7 +2408,7 @@ static inline int security_kernel_create_files_as(struct cred *cred, return 0; } -static inline int security_kernel_module_request(void) +static inline int security_kernel_module_request(char *kmod_name) { return 0; } diff --git a/kernel/kmod.c b/kernel/kmod.c index 9fcb53a11f8..25b10319036 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -80,16 +80,16 @@ int __request_module(bool wait, const char *fmt, ...) #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */ static int kmod_loop_msg; - ret = security_kernel_module_request(); - if (ret) - return ret; - va_start(args, fmt); ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); va_end(args); if (ret >= MODULE_NAME_LEN) return -ENAMETOOLONG; + ret = security_kernel_module_request(module_name); + if (ret) + return ret; + /* If modprobe needs a service that is in a module, we get a recursive * loop. Limit the number of running kmod threads to max_threads/2 or * MAX_KMOD_CONCURRENT, whichever is the smaller. A cleaner method diff --git a/security/capability.c b/security/capability.c index 4f3ab476937..5c700e1a4fd 100644 --- a/security/capability.c +++ b/security/capability.c @@ -421,7 +421,7 @@ static int cap_kernel_create_files_as(struct cred *new, struct inode *inode) return 0; } -static int cap_kernel_module_request(void) +static int cap_kernel_module_request(char *kmod_name) { return 0; } diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 3bb90b6f1dd..51bd0fd9c9f 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -354,6 +354,10 @@ static void dump_common_audit_data(struct audit_buffer *ab, } break; #endif + case LSM_AUDIT_DATA_KMOD: + audit_log_format(ab, " kmod="); + audit_log_untrustedstring(ab, a->u.kmod_name); + break; } /* switch (a->type) */ } diff --git a/security/security.c b/security/security.c index aad71b2ca19..24e060be9fa 100644 --- a/security/security.c +++ b/security/security.c @@ -764,9 +764,9 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode) return security_ops->kernel_create_files_as(new, inode); } -int security_kernel_module_request(void) +int security_kernel_module_request(char *kmod_name) { - return security_ops->kernel_module_request(); + return security_ops->kernel_module_request(kmod_name); } int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a29d6612a32..c96d63ec475 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3337,9 +3337,18 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) return 0; } -static int selinux_kernel_module_request(void) +static int selinux_kernel_module_request(char *kmod_name) { - return task_has_system(current, SYSTEM__MODULE_REQUEST); + u32 sid; + struct common_audit_data ad; + + sid = task_sid(current); + + COMMON_AUDIT_DATA_INIT(&ad, KMOD); + ad.u.kmod_name = kmod_name; + + return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM, + SYSTEM__MODULE_REQUEST, &ad); } static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) From 281d150c5f8892f158747594ab49ce2823fd8b8c Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 2 Nov 2009 13:52:27 -0800 Subject: [PATCH 118/298] rcu: Prepare for synchronization fixes: clean up for non-NO_HZ handling of ->completed counter Impose a clear locking design on non-NO_HZ handling of the ->completed counter. This increases the distance between the RCU and the CPU-hotplug mechanisms. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com Cc: # .32.x LKML-Reference: <12571987491353-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 67 ++++++++++++++++++++++-------------------------- kernel/rcutree.h | 8 +++--- 2 files changed, 34 insertions(+), 41 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 69f4efec344..26249abf24d 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -178,8 +178,28 @@ static struct rcu_node *rcu_get_root(struct rcu_state *rsp) return &rsp->node[0]; } +/* + * Record the specified "completed" value, which is later used to validate + * dynticks counter manipulations and CPU-offline checks. Specify + * "rsp->completed - 1" to unconditionally invalidate any future dynticks + * manipulations and CPU-offline checks. Such invalidation is useful at + * the beginning of a grace period. + */ +static void dyntick_record_completed(struct rcu_state *rsp, long comp) +{ + rsp->dynticks_completed = comp; +} + #ifdef CONFIG_SMP +/* + * Recall the previously recorded value of the completion for dynticks. + */ +static long dyntick_recall_completed(struct rcu_state *rsp) +{ + return rsp->dynticks_completed; +} + /* * If the specified CPU is offline, tell the caller that it is in * a quiescent state. Otherwise, whack it with a reschedule IPI. @@ -337,27 +357,8 @@ void rcu_irq_exit(void) set_need_resched(); } -/* - * Record the specified "completed" value, which is later used to validate - * dynticks counter manipulations. Specify "rsp->completed - 1" to - * unconditionally invalidate any future dynticks manipulations (which is - * useful at the beginning of a grace period). - */ -static void dyntick_record_completed(struct rcu_state *rsp, long comp) -{ - rsp->dynticks_completed = comp; -} - #ifdef CONFIG_SMP -/* - * Recall the previously recorded value of the completion for dynticks. - */ -static long dyntick_recall_completed(struct rcu_state *rsp) -{ - return rsp->dynticks_completed; -} - /* * Snapshot the specified CPU's dynticks counter so that we can later * credit them with an implicit quiescent state. Return 1 if this CPU @@ -421,24 +422,8 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) #else /* #ifdef CONFIG_NO_HZ */ -static void dyntick_record_completed(struct rcu_state *rsp, long comp) -{ -} - #ifdef CONFIG_SMP -/* - * If there are no dynticks, then the only way that a CPU can passively - * be in a quiescent state is to be offline. Unlike dynticks idle, which - * is a point in time during the prior (already finished) grace period, - * an offline CPU is always in a quiescent state, and thus can be - * unconditionally applied. So just return the current value of completed. - */ -static long dyntick_recall_completed(struct rcu_state *rsp) -{ - return rsp->completed; -} - static int dyntick_save_progress_counter(struct rcu_data *rdp) { return 0; @@ -1146,6 +1131,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) long lastcomp; struct rcu_node *rnp = rcu_get_root(rsp); u8 signaled; + u8 forcenow; if (!rcu_gp_in_progress(rsp)) return; /* No grace period in progress, nothing to force. */ @@ -1182,16 +1168,23 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) if (rcu_process_dyntick(rsp, lastcomp, dyntick_save_progress_counter)) goto unlock_ret; + /* fall into next case. */ + + case RCU_SAVE_COMPLETED: /* Update state, record completion counter. */ + forcenow = 0; spin_lock(&rnp->lock); if (lastcomp == rsp->completed && - rsp->signaled == RCU_SAVE_DYNTICK) { + rsp->signaled == signaled) { rsp->signaled = RCU_FORCE_QS; dyntick_record_completed(rsp, lastcomp); + forcenow = signaled == RCU_SAVE_COMPLETED; } spin_unlock(&rnp->lock); - break; + if (!forcenow) + break; + /* fall into next case. */ case RCU_FORCE_QS: diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 1899023b096..8a4c1650ad8 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -204,11 +204,12 @@ struct rcu_data { #define RCU_GP_IDLE 0 /* No grace period in progress. */ #define RCU_GP_INIT 1 /* Grace period being initialized. */ #define RCU_SAVE_DYNTICK 2 /* Need to scan dyntick state. */ -#define RCU_FORCE_QS 3 /* Need to force quiescent state. */ +#define RCU_SAVE_COMPLETED 3 /* Need to save rsp->completed. */ +#define RCU_FORCE_QS 4 /* Need to force quiescent state. */ #ifdef CONFIG_NO_HZ #define RCU_SIGNAL_INIT RCU_SAVE_DYNTICK #else /* #ifdef CONFIG_NO_HZ */ -#define RCU_SIGNAL_INIT RCU_FORCE_QS +#define RCU_SIGNAL_INIT RCU_SAVE_COMPLETED #endif /* #else #ifdef CONFIG_NO_HZ */ #define RCU_JIFFIES_TILL_FORCE_QS 3 /* for rsp->jiffies_force_qs */ @@ -274,9 +275,8 @@ struct rcu_state { unsigned long jiffies_stall; /* Time at which to check */ /* for CPU stalls. */ #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ -#ifdef CONFIG_NO_HZ long dynticks_completed; /* Value of completed @ snap. */ -#endif /* #ifdef CONFIG_NO_HZ */ + /* Protected by fqslock. */ }; #ifdef RCU_TREE_NONCORE From d09b62dfa336447c52a5ec9bb88adbc479b0f3b8 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 2 Nov 2009 13:52:28 -0800 Subject: [PATCH 119/298] rcu: Fix synchronization for rcu_process_gp_end() uses of ->completed counter Impose a clear locking design on the rcu_process_gp_end() function's use of the ->completed counter. This is done by creating a ->completed field in the rcu_node structure, which can safely be accessed under the protection of that structure's lock. Performance and scalability are maintained by using a form of double-checked locking, so that rcu_process_gp_end() only acquires the leaf rcu_node structure's ->lock if a grace period has recently ended. This fix reduces rcutorture failure rate by at least two orders of magnitude under heavy stress with force_quiescent_state() being invoked artificially often. Without this fix, unsynchronized access to the ->completed field can cause rcu_process_gp_end() to advance callbacks whose grace period has not yet expired. (Bad idea!) Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com Cc: # .32.x LKML-Reference: <12571987494069-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 128 +++++++++++++++++++++++++++++------------------ kernel/rcutree.h | 3 ++ 2 files changed, 83 insertions(+), 48 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 26249abf24d..9e068d11215 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -569,6 +569,76 @@ check_for_new_grace_period(struct rcu_state *rsp, struct rcu_data *rdp) return ret; } +/* + * Advance this CPU's callbacks, but only if the current grace period + * has ended. This may be called only from the CPU to whom the rdp + * belongs. In addition, the corresponding leaf rcu_node structure's + * ->lock must be held by the caller, with irqs disabled. + */ +static void +__rcu_process_gp_end(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp) +{ + /* Did another grace period end? */ + if (rdp->completed != rnp->completed) { + + /* Advance callbacks. No harm if list empty. */ + rdp->nxttail[RCU_DONE_TAIL] = rdp->nxttail[RCU_WAIT_TAIL]; + rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_READY_TAIL]; + rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; + + /* Remember that we saw this grace-period completion. */ + rdp->completed = rnp->completed; + } +} + +/* + * Advance this CPU's callbacks, but only if the current grace period + * has ended. This may be called only from the CPU to whom the rdp + * belongs. + */ +static void +rcu_process_gp_end(struct rcu_state *rsp, struct rcu_data *rdp) +{ + unsigned long flags; + struct rcu_node *rnp; + + local_irq_save(flags); + rnp = rdp->mynode; + if (rdp->completed == ACCESS_ONCE(rnp->completed) || /* outside lock. */ + !spin_trylock(&rnp->lock)) { /* irqs already off, retry later. */ + local_irq_restore(flags); + return; + } + __rcu_process_gp_end(rsp, rnp, rdp); + spin_unlock_irqrestore(&rnp->lock, flags); +} + +/* + * Do per-CPU grace-period initialization for running CPU. The caller + * must hold the lock of the leaf rcu_node structure corresponding to + * this CPU. + */ +static void +rcu_start_gp_per_cpu(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp) +{ + /* Prior grace period ended, so advance callbacks for current CPU. */ + __rcu_process_gp_end(rsp, rnp, rdp); + + /* + * Because this CPU just now started the new grace period, we know + * that all of its callbacks will be covered by this upcoming grace + * period, even the ones that were registered arbitrarily recently. + * Therefore, advance all outstanding callbacks to RCU_WAIT_TAIL. + * + * Other CPUs cannot be sure exactly when the grace period started. + * Therefore, their recently registered callbacks must pass through + * an additional RCU_NEXT_READY stage, so that they will be handled + * by the next RCU grace period. + */ + rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; + rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; +} + /* * Start a new RCU grace period if warranted, re-initializing the hierarchy * in preparation for detecting the next grace period. The caller must hold @@ -596,26 +666,14 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) dyntick_record_completed(rsp, rsp->completed - 1); note_new_gpnum(rsp, rdp); - /* - * Because this CPU just now started the new grace period, we know - * that all of its callbacks will be covered by this upcoming grace - * period, even the ones that were registered arbitrarily recently. - * Therefore, advance all outstanding callbacks to RCU_WAIT_TAIL. - * - * Other CPUs cannot be sure exactly when the grace period started. - * Therefore, their recently registered callbacks must pass through - * an additional RCU_NEXT_READY stage, so that they will be handled - * by the next RCU grace period. - */ - rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; - rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; - /* Special-case the common single-level case. */ if (NUM_RCU_NODES == 1) { rcu_preempt_check_blocked_tasks(rnp); rnp->qsmask = rnp->qsmaskinit; rnp->gpnum = rsp->gpnum; + rnp->completed = rsp->completed; rsp->signaled = RCU_SIGNAL_INIT; /* force_quiescent_state OK. */ + rcu_start_gp_per_cpu(rsp, rnp, rdp); spin_unlock_irqrestore(&rnp->lock, flags); return; } @@ -648,6 +706,9 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) rcu_preempt_check_blocked_tasks(rnp); rnp->qsmask = rnp->qsmaskinit; rnp->gpnum = rsp->gpnum; + rnp->completed = rsp->completed; + if (rnp == rdp->mynode) + rcu_start_gp_per_cpu(rsp, rnp, rdp); spin_unlock(&rnp->lock); /* irqs remain disabled. */ } @@ -658,34 +719,6 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) spin_unlock_irqrestore(&rsp->onofflock, flags); } -/* - * Advance this CPU's callbacks, but only if the current grace period - * has ended. This may be called only from the CPU to whom the rdp - * belongs. - */ -static void -rcu_process_gp_end(struct rcu_state *rsp, struct rcu_data *rdp) -{ - long completed_snap; - unsigned long flags; - - local_irq_save(flags); - completed_snap = ACCESS_ONCE(rsp->completed); /* outside of lock. */ - - /* Did another grace period end? */ - if (rdp->completed != completed_snap) { - - /* Advance callbacks. No harm if list empty. */ - rdp->nxttail[RCU_DONE_TAIL] = rdp->nxttail[RCU_WAIT_TAIL]; - rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_READY_TAIL]; - rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; - - /* Remember that we saw this grace-period completion. */ - rdp->completed = completed_snap; - } - local_irq_restore(flags); -} - /* * Clean up after the prior grace period and let rcu_start_gp() start up * the next grace period if one is needed. Note that the caller must @@ -697,7 +730,6 @@ static void cpu_quiet_msk_finish(struct rcu_state *rsp, unsigned long flags) WARN_ON_ONCE(!rcu_gp_in_progress(rsp)); rsp->completed = rsp->gpnum; rsp->signaled = RCU_GP_IDLE; - rcu_process_gp_end(rsp, rsp->rda[smp_processor_id()]); rcu_start_gp(rsp, flags); /* releases root node's rnp->lock. */ } @@ -1539,21 +1571,16 @@ static void __cpuinit rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptable) { unsigned long flags; - long lastcomp; unsigned long mask; struct rcu_data *rdp = rsp->rda[cpu]; struct rcu_node *rnp = rcu_get_root(rsp); /* Set up local state, ensuring consistent view of global state. */ spin_lock_irqsave(&rnp->lock, flags); - lastcomp = rsp->completed; - rdp->completed = lastcomp; - rdp->gpnum = lastcomp; rdp->passed_quiesc = 0; /* We could be racing with new GP, */ rdp->qs_pending = 1; /* so set up to respond to current GP. */ rdp->beenonline = 1; /* We have now been online. */ rdp->preemptable = preemptable; - rdp->passed_quiesc_completed = lastcomp - 1; rdp->qlen_last_fqs_check = 0; rdp->n_force_qs_snap = rsp->n_force_qs; rdp->blimit = blimit; @@ -1575,6 +1602,11 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptable) spin_lock(&rnp->lock); /* irqs already disabled. */ rnp->qsmaskinit |= mask; mask = rnp->grpmask; + if (rnp == rdp->mynode) { + rdp->gpnum = rnp->completed; /* if GP in progress... */ + rdp->completed = rnp->completed; + rdp->passed_quiesc_completed = rnp->completed - 1; + } spin_unlock(&rnp->lock); /* irqs already disabled. */ rnp = rnp->parent; } while (rnp != NULL && !(rnp->qsmaskinit & mask)); diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 8a4c1650ad8..c1891c3cae6 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -84,6 +84,9 @@ struct rcu_node { long gpnum; /* Current grace period for this node. */ /* This will either be equal to or one */ /* behind the root rcu_node's gpnum. */ + long completed; /* Last grace period completed for this node. */ + /* This will either be equal to or one */ + /* behind the root rcu_node's gpnum. */ unsigned long qsmask; /* CPUs or groups that need to switch in */ /* order for current grace period to proceed.*/ /* In leaf rcu_node, each bit corresponds to */ From 9160306e6f5b68bb64630c9031c517ca1cf463db Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 2 Nov 2009 13:52:29 -0800 Subject: [PATCH 120/298] rcu: Fix note_new_gpnum() uses of ->gpnum Impose a clear locking design on the note_new_gpnum() function's use of the ->gpnum counter. This is done by updating rdp->gpnum only from the corresponding leaf rcu_node structure's rnp->gpnum field, and even then only under the protection of that same rcu_node structure's ->lock field. Performance and scalability are maintained using a form of double-checked locking, and excessive spinning is avoided by use of the spin_trylock() function. The use of spin_trylock() is safe due to the fact that CPUs who fail to acquire this lock will try again later. The hierarchical nature of the rcu_node data structure limits contention (which could be limited further if need be using the RCU_FANOUT kernel parameter). Without this patch, obscure but quite possible races could result in a quiescent state that occurred during one grace period to be accounted to the following grace period, causing this following grace period to end prematurely. Not good! Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com Cc: # .32.x LKML-Reference: <12571987492350-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 9e068d11215..ec007dd2263 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -540,13 +540,33 @@ static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp) /* * Update CPU-local rcu_data state to record the newly noticed grace period. * This is used both when we started the grace period and when we notice - * that someone else started the grace period. + * that someone else started the grace period. The caller must hold the + * ->lock of the leaf rcu_node structure corresponding to the current CPU, + * and must have irqs disabled. */ +static void __note_new_gpnum(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp) +{ + if (rdp->gpnum != rnp->gpnum) { + rdp->qs_pending = 1; + rdp->passed_quiesc = 0; + rdp->gpnum = rnp->gpnum; + } +} + static void note_new_gpnum(struct rcu_state *rsp, struct rcu_data *rdp) { - rdp->qs_pending = 1; - rdp->passed_quiesc = 0; - rdp->gpnum = rsp->gpnum; + unsigned long flags; + struct rcu_node *rnp; + + local_irq_save(flags); + rnp = rdp->mynode; + if (rdp->gpnum == ACCESS_ONCE(rnp->gpnum) || /* outside lock. */ + !spin_trylock(&rnp->lock)) { /* irqs already off, retry later. */ + local_irq_restore(flags); + return; + } + __note_new_gpnum(rsp, rnp, rdp); + spin_unlock_irqrestore(&rnp->lock, flags); } /* @@ -637,6 +657,9 @@ rcu_start_gp_per_cpu(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_dat */ rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; + + /* Set state so that this CPU will detect the next quiescent state. */ + __note_new_gpnum(rsp, rnp, rdp); } /* @@ -664,7 +687,6 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS; record_gp_stall_check_time(rsp); dyntick_record_completed(rsp, rsp->completed - 1); - note_new_gpnum(rsp, rdp); /* Special-case the common single-level case. */ if (NUM_RCU_NODES == 1) { From 41855b77547fa18d90ed6a5d322983d3fdab1959 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 9 Nov 2009 17:58:50 -0800 Subject: [PATCH 121/298] x86: GART: pci-gart_64.c: Use correct length in strncmp Signed-off-by: Joe Perches Cc: # .3x.x LKML-Reference: <1257818330.12852.72.camel@Joe-Laptop.home> Signed-off-by: Ingo Molnar --- arch/x86/kernel/pci-gart_64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index a9bcdf7c880..eb46ab3f52b 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c @@ -858,7 +858,7 @@ void __init gart_parse_options(char *p) #endif if (isdigit(*p) && get_option(&p, &arg)) iommu_size = arg; - if (!strncmp(p, "fullflush", 8)) + if (!strncmp(p, "fullflush", 9)) iommu_fullflush = 1; if (!strncmp(p, "nofullflush", 11)) iommu_fullflush = 0; From d07c1be0693e0902d743160b8b638585b808f8ac Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 10 Nov 2009 19:46:12 +0900 Subject: [PATCH 122/298] x86: Add iommu_init to x86_init_ops We call the detections functions of all the IOMMUs then all their initialization functions. The latter is pointless since we don't detect multiple different IOMMUs. What we need to do is calling the initialization function of the detected IOMMU. This adds iommu_init hook to x86_init_ops so if an IOMMU detection function can set its initialization function to the hook. Signed-off-by: FUJITA Tomonori Cc: chrisw@sous-sol.org Cc: dwmw2@infradead.org Cc: joerg.roedel@amd.com Cc: muli@il.ibm.com LKML-Reference: <1257849980-22640-2-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/x86_init.h | 9 +++++++++ arch/x86/kernel/pci-dma.c | 2 ++ arch/x86/kernel/x86_init.c | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index 66008ed80b7..d8e71459f02 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h @@ -90,6 +90,14 @@ struct x86_init_timers { void (*timer_init)(void); }; +/** + * struct x86_init_iommu - platform specific iommu setup + * @iommu_init: platform specific iommu setup + */ +struct x86_init_iommu { + int (*iommu_init)(void); +}; + /** * struct x86_init_ops - functions for platform specific setup * @@ -101,6 +109,7 @@ struct x86_init_ops { struct x86_init_oem oem; struct x86_init_paging paging; struct x86_init_timers timers; + struct x86_init_iommu iommu; }; /** diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 839d49a669b..a13478da533 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -292,6 +292,8 @@ static int __init pci_iommu_init(void) dma_debug_add_bus(&pci_bus_type); #endif + x86_init.iommu.iommu_init(); + calgary_iommu_init(); intel_iommu_init(); diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index bc9b230ef40..c46984d122d 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c @@ -19,6 +19,7 @@ void __cpuinit x86_init_noop(void) { } void __init x86_init_uint_noop(unsigned int unused) { } void __init x86_init_pgd_noop(pgd_t *unused) { } +int __init iommu_init_noop(void) { return 0; } /* * The platform setup functions are preset with the default functions @@ -63,6 +64,10 @@ struct x86_init_ops x86_init __initdata = { .tsc_pre_init = x86_init_noop, .timer_init = hpet_time_init, }, + + .iommu = { + .iommu_init = iommu_init_noop, + }, }; struct x86_cpuinit_ops x86_cpuinit __cpuinitdata = { From d7b9f7be216b04ff9d108f856bc03d96e7b3439c Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 10 Nov 2009 19:46:13 +0900 Subject: [PATCH 123/298] x86: Calgary: Convert detect_calgary() to use iommu_init hook This changes detect_calgary() to set init_calgary() to iommu_init hook if detect_calgary() finds the Calgary IOMMU. We can kill the code to check if we found the IOMMU in init_calgary() since detect_calgary() sets init_calgary() only when it found the IOMMU. Signed-off-by: FUJITA Tomonori Acked-by: Muli Ben-Yehuda Cc: chrisw@sous-sol.org Cc: dwmw2@infradead.org Cc: joerg.roedel@amd.com LKML-Reference: <1257849980-22640-3-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/calgary.h | 2 -- arch/x86/kernel/pci-calgary_64.c | 11 +++++------ arch/x86/kernel/pci-dma.c | 2 -- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/arch/x86/include/asm/calgary.h b/arch/x86/include/asm/calgary.h index b03bedb62aa..0918654305a 100644 --- a/arch/x86/include/asm/calgary.h +++ b/arch/x86/include/asm/calgary.h @@ -62,10 +62,8 @@ struct cal_chipset_ops { extern int use_calgary; #ifdef CONFIG_CALGARY_IOMMU -extern int calgary_iommu_init(void); extern void detect_calgary(void); #else -static inline int calgary_iommu_init(void) { return 1; } static inline void detect_calgary(void) { return; } #endif diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index 971a3bec47a..47bd419ea4d 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c @@ -46,6 +46,7 @@ #include #include #include +#include #ifdef CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT int use_calgary __read_mostly = 1; @@ -1344,6 +1345,8 @@ static void __init get_tce_space_from_tar(void) return; } +int __init calgary_iommu_init(void); + void __init detect_calgary(void) { int bus; @@ -1445,6 +1448,8 @@ void __init detect_calgary(void) /* swiotlb for devices that aren't behind the Calgary. */ if (max_pfn > MAX_DMA32_PFN) swiotlb = 1; + + x86_init.iommu.iommu_init = calgary_iommu_init; } return; @@ -1461,12 +1466,6 @@ int __init calgary_iommu_init(void) { int ret; - if (no_iommu || (swiotlb && !calgary_detected)) - return -ENODEV; - - if (!calgary_detected) - return -ENODEV; - /* ok, we're trying to use Calgary - let's roll */ printk(KERN_INFO "PCI-DMA: Using Calgary IOMMU\n"); diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index a13478da533..0224da88256 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -294,8 +294,6 @@ static int __init pci_iommu_init(void) x86_init.iommu.iommu_init(); - calgary_iommu_init(); - intel_iommu_init(); amd_iommu_init(); From de957628ce7c84764ff41331111036b3ae5bad0f Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 10 Nov 2009 19:46:14 +0900 Subject: [PATCH 124/298] x86: GART: Convert gart_iommu_hole_init() to use iommu_init hook This changes gart_iommu_hole_init() to set gart_iommu_init() to iommu_init hook if gart_iommu_hole_init() finds the GART IOMMU. We can kill the code to check if we found the IOMMU in gart_iommu_init() since gart_iommu_hole_init() sets gart_iommu_init() only when it found the IOMMU. Signed-off-by: FUJITA Tomonori Cc: chrisw@sous-sol.org Cc: dwmw2@infradead.org Cc: joerg.roedel@amd.com Cc: muli@il.ibm.com LKML-Reference: <1257849980-22640-4-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/gart.h | 5 +---- arch/x86/kernel/aperture_64.c | 2 ++ arch/x86/kernel/pci-dma.c | 2 -- arch/x86/kernel/pci-gart_64.c | 15 +++++---------- 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/arch/x86/include/asm/gart.h b/arch/x86/include/asm/gart.h index 4fdd5b3f87b..4ac5b0f33fc 100644 --- a/arch/x86/include/asm/gart.h +++ b/arch/x86/include/asm/gart.h @@ -35,7 +35,7 @@ extern int gart_iommu_aperture_allowed; extern int gart_iommu_aperture_disabled; extern void early_gart_iommu_check(void); -extern void gart_iommu_init(void); +extern int gart_iommu_init(void); extern void __init gart_parse_options(char *); extern void gart_iommu_hole_init(void); @@ -47,9 +47,6 @@ extern void gart_iommu_hole_init(void); static inline void early_gart_iommu_check(void) { } -static inline void gart_iommu_init(void) -{ -} static inline void gart_parse_options(char *options) { } diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c index 128111d8ffe..03933cf0b63 100644 --- a/arch/x86/kernel/aperture_64.c +++ b/arch/x86/kernel/aperture_64.c @@ -28,6 +28,7 @@ #include #include #include +#include int gart_iommu_aperture; int gart_iommu_aperture_disabled __initdata; @@ -400,6 +401,7 @@ void __init gart_iommu_hole_init(void) iommu_detected = 1; gart_iommu_aperture = 1; + x86_init.iommu.iommu_init = gart_iommu_init; aper_order = (read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL) >> 1) & 7; aper_size = (32 * 1024 * 1024) << aper_order; diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 0224da88256..ecde8543537 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -298,8 +298,6 @@ static int __init pci_iommu_init(void) amd_iommu_init(); - gart_iommu_init(); - no_iommu_init(); return 0; } diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index eb46ab3f52b..0410bd30060 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c @@ -709,7 +709,7 @@ static void gart_iommu_shutdown(void) } } -void __init gart_iommu_init(void) +int __init gart_iommu_init(void) { struct agp_kern_info info; unsigned long iommu_start; @@ -719,7 +719,7 @@ void __init gart_iommu_init(void) long i; if (cache_k8_northbridges() < 0 || num_k8_northbridges == 0) - return; + return 0; #ifndef CONFIG_AGP_AMD64 no_agp = 1; @@ -731,13 +731,6 @@ void __init gart_iommu_init(void) (agp_copy_info(agp_bridge, &info) < 0); #endif - if (swiotlb) - return; - - /* Did we detect a different HW IOMMU? */ - if (iommu_detected && !gart_iommu_aperture) - return; - if (no_iommu || (!force_iommu && max_pfn <= MAX_DMA32_PFN) || !gart_iommu_aperture || @@ -747,7 +740,7 @@ void __init gart_iommu_init(void) "but GART IOMMU not available.\n"); printk(KERN_WARNING "falling back to iommu=soft.\n"); } - return; + return 0; } /* need to map that range */ @@ -840,6 +833,8 @@ void __init gart_iommu_init(void) flush_gart(); dma_ops = &gart_dma_ops; x86_platform.iommu_shutdown = gart_iommu_shutdown; + + return 0; } void __init gart_parse_options(char *p) From ea1b0d3945c7374849235b6ecaea1191ee1d9d50 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 10 Nov 2009 19:46:15 +0900 Subject: [PATCH 125/298] x86: amd_iommu: Convert amd_iommu_detect() to use iommu_init hook This changes amd_iommu_detect() to set amd_iommu_init to iommu_init hook if amd_iommu_detect() finds the AMD IOMMU. We can kill the code to check if we found the IOMMU in amd_iommu_init() since amd_iommu_detect() sets amd_iommu_init() only when it found the IOMMU. Signed-off-by: FUJITA Tomonori Cc: chrisw@sous-sol.org Cc: dwmw2@infradead.org Cc: joerg.roedel@amd.com Cc: muli@il.ibm.com LKML-Reference: <1257849980-22640-5-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/amd_iommu.h | 2 -- arch/x86/kernel/amd_iommu_init.c | 17 +++-------------- arch/x86/kernel/pci-dma.c | 2 -- 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/arch/x86/include/asm/amd_iommu.h b/arch/x86/include/asm/amd_iommu.h index 3604669f7b1..b8ef2ee9364 100644 --- a/arch/x86/include/asm/amd_iommu.h +++ b/arch/x86/include/asm/amd_iommu.h @@ -23,7 +23,6 @@ #include #ifdef CONFIG_AMD_IOMMU -extern int amd_iommu_init(void); extern int amd_iommu_init_dma_ops(void); extern int amd_iommu_init_passthrough(void); extern void amd_iommu_detect(void); @@ -32,7 +31,6 @@ extern void amd_iommu_flush_all_domains(void); extern void amd_iommu_flush_all_devices(void); extern void amd_iommu_apply_erratum_63(u16 devid); #else -static inline int amd_iommu_init(void) { return -ENODEV; } static inline void amd_iommu_detect(void) { } #endif diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 6acd43e9afd..c41aabddaa2 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -29,6 +29,7 @@ #include #include #include +#include /* * definitions for the ACPI scanning code @@ -1176,19 +1177,10 @@ static struct sys_device device_amd_iommu = { * functions. Finally it prints some information about AMD IOMMUs and * the driver state and enables the hardware. */ -int __init amd_iommu_init(void) +static int __init amd_iommu_init(void) { int i, ret = 0; - - if (no_iommu) { - printk(KERN_INFO "AMD-Vi disabled by kernel command line\n"); - return 0; - } - - if (!amd_iommu_detected) - return -ENODEV; - /* * First parse ACPI tables to find the largest Bus/Dev/Func * we need to handle. Upon this information the shared data @@ -1344,10 +1336,7 @@ void __init amd_iommu_detect(void) if (acpi_table_parse("IVRS", early_amd_iommu_detect) == 0) { iommu_detected = 1; amd_iommu_detected = 1; -#ifdef CONFIG_GART_IOMMU - gart_iommu_aperture_disabled = 1; - gart_iommu_aperture = 0; -#endif + x86_init.iommu.iommu_init = amd_iommu_init; } } diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index ecde8543537..5ca44a9301a 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -296,8 +296,6 @@ static int __init pci_iommu_init(void) intel_iommu_init(); - amd_iommu_init(); - no_iommu_init(); return 0; } From 9d5ce73a64be2be8112147a3e0b551ad9cd1247b Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 10 Nov 2009 19:46:16 +0900 Subject: [PATCH 126/298] x86: intel-iommu: Convert detect_intel_iommu to use iommu_init hook This changes detect_intel_iommu() to set intel_iommu_init() to iommu_init hook if detect_intel_iommu() finds the IOMMU. Signed-off-by: FUJITA Tomonori Cc: chrisw@sous-sol.org Cc: dwmw2@infradead.org Cc: joerg.roedel@amd.com Cc: muli@il.ibm.com LKML-Reference: <1257849980-22640-6-git-send-email-fujita.tomonori@lab.ntt.co.jp> [ -v2: build fix for the !CONFIG_DMAR case ] Signed-off-by: Ingo Molnar --- arch/x86/kernel/pci-dma.c | 2 -- drivers/pci/dmar.c | 4 ++++ include/linux/dmar.h | 15 ++++----------- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 5ca44a9301a..bed05e2e589 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -294,8 +294,6 @@ static int __init pci_iommu_init(void) x86_init.iommu.iommu_init(); - intel_iommu_init(); - no_iommu_init(); return 0; } diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 22b02c6df85..bce9cd7c755 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -616,6 +616,10 @@ void __init detect_intel_iommu(void) if (ret && !no_iommu && !iommu_detected && !swiotlb && !dmar_disabled) iommu_detected = 1; +#endif +#ifdef CONFIG_X86 + if (ret) + x86_init.iommu.iommu_init = intel_iommu_init; #endif } early_acpi_os_unmap_memory(dmar_tbl, dmar_tbl_size); diff --git a/include/linux/dmar.h b/include/linux/dmar.h index 4a2b162c256..5de4c9e5856 100644 --- a/include/linux/dmar.h +++ b/include/linux/dmar.h @@ -208,16 +208,9 @@ struct dmar_atsr_unit { u8 include_all:1; /* include all ports */ }; -/* Intel DMAR initialization functions */ extern int intel_iommu_init(void); -#else -static inline int intel_iommu_init(void) -{ -#ifdef CONFIG_INTR_REMAP - return dmar_dev_scope_init(); -#else - return -ENODEV; -#endif -} -#endif /* !CONFIG_DMAR */ +#else /* !CONFIG_DMAR: */ +static inline int intel_iommu_init(void) { return -ENODEV; } +#endif /* CONFIG_DMAR */ + #endif /* __DMAR_H__ */ From 9f993ac3f708b661207ed7de521f245586217a68 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 10 Nov 2009 19:46:17 +0900 Subject: [PATCH 127/298] bootmem: Add free_bootmem_late() Add a new function for freeing bootmem after the bootmem allocator has been released and the unreserved pages given to the page allocator. This allows us to reserve bootmem and then release it if we later discover it was not needed. ( This new API will be used by the swiotlb code to recover a significant amount of RAM (64MB). ) Signed-off-by: FUJITA Tomonori Acked-by: Pekka Enberg Cc: chrisw@sous-sol.org Cc: dwmw2@infradead.org Cc: joerg.roedel@amd.com Cc: muli@il.ibm.com Cc: hannes@cmpxchg.org Cc: tj@kernel.org Cc: akpm@linux-foundation.org Cc: Linus Torvalds LKML-Reference: <1257849980-22640-7-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar --- include/linux/bootmem.h | 1 + mm/bootmem.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h index dd97fb8408a..b10ec49ee2d 100644 --- a/include/linux/bootmem.h +++ b/include/linux/bootmem.h @@ -53,6 +53,7 @@ extern void free_bootmem_node(pg_data_t *pgdat, unsigned long addr, unsigned long size); extern void free_bootmem(unsigned long addr, unsigned long size); +extern void free_bootmem_late(unsigned long addr, unsigned long size); /* * Flags for reserve_bootmem (also if CONFIG_HAVE_ARCH_BOOTMEM_NODE, diff --git a/mm/bootmem.c b/mm/bootmem.c index 555d5d2731c..d1dc23cc7f1 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -143,6 +143,30 @@ unsigned long __init init_bootmem(unsigned long start, unsigned long pages) return init_bootmem_core(NODE_DATA(0)->bdata, start, 0, pages); } +/* + * free_bootmem_late - free bootmem pages directly to page allocator + * @addr: starting address of the range + * @size: size of the range in bytes + * + * This is only useful when the bootmem allocator has already been torn + * down, but we are still initializing the system. Pages are given directly + * to the page allocator, no bootmem metadata is updated because it is gone. + */ +void __init free_bootmem_late(unsigned long addr, unsigned long size) +{ + unsigned long cursor, end; + + kmemleak_free_part(__va(addr), size); + + cursor = PFN_UP(addr); + end = PFN_DOWN(addr + size); + + for (; cursor < end; cursor++) { + __free_pages_bootmem(pfn_to_page(cursor), 0); + totalram_pages++; + } +} + static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata) { int aligned; From 5740afdb68abadc473fd5392df733558a58c1254 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 10 Nov 2009 19:46:18 +0900 Subject: [PATCH 128/298] swiotlb: Add swiotlb_free() function swiotlb_free() function frees all allocated memory for swiotlb. We need to initialize swiotlb before IOMMU initialization (x86 and powerpc needs to allocate memory from bootmem allocator). If IOMMU initialization is successful, we need to free swiotlb resource (don't want to waste 64MB). Signed-off-by: FUJITA Tomonori Cc: chrisw@sous-sol.org Cc: dwmw2@infradead.org Cc: joerg.roedel@amd.com Cc: muli@il.ibm.com LKML-Reference: <1257849980-22640-8-git-send-email-fujita.tomonori@lab.ntt.co.jp> [ -v2: build fix for the !CONFIG_SWIOTLB case ] Signed-off-by: Ingo Molnar --- include/linux/swiotlb.h | 6 ++++++ lib/swiotlb.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index 73b1f1cec42..59bafa69029 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -88,4 +88,10 @@ swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr); extern int swiotlb_dma_supported(struct device *hwdev, u64 mask); +#ifdef CONFIG_SWIOTLB +extern void __init swiotlb_free(void); +#else +static inline void swiotlb_free(void) { } +#endif + #endif /* __LINUX_SWIOTLB_H */ diff --git a/lib/swiotlb.c b/lib/swiotlb.c index ac25cd28e80..eee512b63f1 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -97,6 +97,8 @@ static phys_addr_t *io_tlb_orig_addr; */ static DEFINE_SPINLOCK(io_tlb_lock); +static int late_alloc; + static int __init setup_io_tlb_npages(char *str) { @@ -262,6 +264,8 @@ swiotlb_late_init_with_default_size(size_t default_size) swiotlb_print_info(bytes); + late_alloc = 1; + return 0; cleanup4: @@ -281,6 +285,32 @@ cleanup1: return -ENOMEM; } +void __init swiotlb_free(void) +{ + if (!io_tlb_overflow_buffer) + return; + + if (late_alloc) { + free_pages((unsigned long)io_tlb_overflow_buffer, + get_order(io_tlb_overflow)); + free_pages((unsigned long)io_tlb_orig_addr, + get_order(io_tlb_nslabs * sizeof(phys_addr_t))); + free_pages((unsigned long)io_tlb_list, get_order(io_tlb_nslabs * + sizeof(int))); + free_pages((unsigned long)io_tlb_start, + get_order(io_tlb_nslabs << IO_TLB_SHIFT)); + } else { + free_bootmem_late(__pa(io_tlb_overflow_buffer), + io_tlb_overflow); + free_bootmem_late(__pa(io_tlb_orig_addr), + io_tlb_nslabs * sizeof(phys_addr_t)); + free_bootmem_late(__pa(io_tlb_list), + io_tlb_nslabs * sizeof(int)); + free_bootmem_late(__pa(io_tlb_start), + io_tlb_nslabs << IO_TLB_SHIFT); + } +} + static int is_swiotlb_buffer(phys_addr_t paddr) { return paddr >= virt_to_phys(io_tlb_start) && From ad32e8cb86e7894aac51c8963eaa9f36bb8a4e14 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 10 Nov 2009 19:46:19 +0900 Subject: [PATCH 129/298] swiotlb: Defer swiotlb init printing, export swiotlb_print_info() This enables us to avoid printing swiotlb memory info when we initialize swiotlb. After swiotlb initialization, we could find that we don't need swiotlb. This patch removes the code to print swiotlb memory info in swiotlb_init() and exports the function to do that. Signed-off-by: FUJITA Tomonori Cc: chrisw@sous-sol.org Cc: dwmw2@infradead.org Cc: joerg.roedel@amd.com Cc: muli@il.ibm.com Cc: tony.luck@intel.com Cc: benh@kernel.crashing.org LKML-Reference: <1257849980-22640-9-git-send-email-fujita.tomonori@lab.ntt.co.jp> [ -v2: merge up conflict ] Signed-off-by: Ingo Molnar --- arch/ia64/kernel/pci-swiotlb.c | 4 ++-- arch/powerpc/kernel/setup_32.c | 2 +- arch/powerpc/kernel/setup_64.c | 2 +- arch/x86/kernel/pci-swiotlb.c | 3 +-- include/linux/swiotlb.h | 4 ++-- lib/swiotlb.c | 15 ++++++++------- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/arch/ia64/kernel/pci-swiotlb.c b/arch/ia64/kernel/pci-swiotlb.c index 285aae8431c..53292abf846 100644 --- a/arch/ia64/kernel/pci-swiotlb.c +++ b/arch/ia64/kernel/pci-swiotlb.c @@ -41,7 +41,7 @@ struct dma_map_ops swiotlb_dma_ops = { void __init swiotlb_dma_init(void) { dma_ops = &swiotlb_dma_ops; - swiotlb_init(); + swiotlb_init(1); } void __init pci_swiotlb_init(void) @@ -51,7 +51,7 @@ void __init pci_swiotlb_init(void) swiotlb = 1; printk(KERN_INFO "PCI-DMA: Re-initialize machine vector.\n"); machvec_init("dig"); - swiotlb_init(); + swiotlb_init(1); dma_ops = &swiotlb_dma_ops; #else panic("Unable to find Intel IOMMU"); diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 53bcf3d792d..b152de3e64d 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -345,7 +345,7 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_SWIOTLB if (ppc_swiotlb_enable) - swiotlb_init(); + swiotlb_init(1); #endif paging_init(); diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 04f638d82fb..df2c9e932b3 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -550,7 +550,7 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_SWIOTLB if (ppc_swiotlb_enable) - swiotlb_init(); + swiotlb_init(1); #endif paging_init(); diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c index aaa6b7839f1..ea20ef7ca52 100644 --- a/arch/x86/kernel/pci-swiotlb.c +++ b/arch/x86/kernel/pci-swiotlb.c @@ -52,8 +52,7 @@ void __init pci_swiotlb_init(void) if (swiotlb_force) swiotlb = 1; if (swiotlb) { - printk(KERN_INFO "PCI-DMA: Using software bounce buffering for IO (SWIOTLB)\n"); - swiotlb_init(); + swiotlb_init(0); dma_ops = &swiotlb_dma_ops; } } diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index 59bafa69029..eb9bdb4d485 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -20,8 +20,7 @@ struct scatterlist; */ #define IO_TLB_SHIFT 11 -extern void -swiotlb_init(void); +extern void swiotlb_init(int verbose); extern void *swiotlb_alloc_coherent(struct device *hwdev, size_t size, @@ -94,4 +93,5 @@ extern void __init swiotlb_free(void); static inline void swiotlb_free(void) { } #endif +extern void swiotlb_print_info(void); #endif /* __LINUX_SWIOTLB_H */ diff --git a/lib/swiotlb.c b/lib/swiotlb.c index eee512b63f1..0c12d7cce30 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -123,8 +123,9 @@ static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev, return phys_to_dma(hwdev, virt_to_phys(address)); } -static void swiotlb_print_info(unsigned long bytes) +void swiotlb_print_info(void) { + unsigned long bytes = io_tlb_nslabs << IO_TLB_SHIFT; phys_addr_t pstart, pend; pstart = virt_to_phys(io_tlb_start); @@ -142,7 +143,7 @@ static void swiotlb_print_info(unsigned long bytes) * structures for the software IO TLB used to implement the DMA API. */ void __init -swiotlb_init_with_default_size(size_t default_size) +swiotlb_init_with_default_size(size_t default_size, int verbose) { unsigned long i, bytes; @@ -178,14 +179,14 @@ swiotlb_init_with_default_size(size_t default_size) io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow); if (!io_tlb_overflow_buffer) panic("Cannot allocate SWIOTLB overflow buffer!\n"); - - swiotlb_print_info(bytes); + if (verbose) + swiotlb_print_info(); } void __init -swiotlb_init(void) +swiotlb_init(int verbose) { - swiotlb_init_with_default_size(64 * (1<<20)); /* default to 64MB */ + swiotlb_init_with_default_size(64 * (1<<20), verbose); /* default to 64MB */ } /* @@ -262,7 +263,7 @@ swiotlb_late_init_with_default_size(size_t default_size) if (!io_tlb_overflow_buffer) goto cleanup4; - swiotlb_print_info(bytes); + swiotlb_print_info(); late_alloc = 1; From 75f1cdf1dda92cae037ec848ae63690d91913eac Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 10 Nov 2009 19:46:20 +0900 Subject: [PATCH 130/298] x86: Handle HW IOMMU initialization failure gracefully If HW IOMMU initialization fails (Intel VT-d often does this, typically due to BIOS bugs), we fall back to nommu. It doesn't work for the majority since nowadays we have more than 4GB memory so we must use swiotlb instead of nommu. The problem is that it's too late to initialize swiotlb when HW IOMMU initialization fails. We need to allocate swiotlb memory earlier from bootmem allocator. Chris explained the issue in detail: http://marc.info/?l=linux-kernel&m=125657444317079&w=2 The current x86 IOMMU initialization sequence is too complicated and handling the above issue makes it more hacky. This patch changes x86 IOMMU initialization sequence to handle the above issue cleanly. The new x86 IOMMU initialization sequence are: 1. we initialize the swiotlb (and setting swiotlb to 1) in the case of (max_pfn > MAX_DMA32_PFN && !no_iommu). dma_ops is set to swiotlb_dma_ops or nommu_dma_ops. if swiotlb usage is forced by the boot option, we finish here. 2. we call the detection functions of all the IOMMUs 3. the detection function sets x86_init.iommu.iommu_init to the IOMMU initialization function (so we can avoid calling the initialization functions of all the IOMMUs needlessly). 4. if the IOMMU initialization function doesn't need to swiotlb then sets swiotlb to zero (e.g. the initialization is sucessful). 5. if we find that swiotlb is set to zero, we free swiotlb resource. Signed-off-by: FUJITA Tomonori Cc: chrisw@sous-sol.org Cc: dwmw2@infradead.org Cc: joerg.roedel@amd.com Cc: muli@il.ibm.com LKML-Reference: <1257849980-22640-10-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/iommu.h | 1 - arch/x86/kernel/amd_iommu.c | 2 +- arch/x86/kernel/amd_iommu_init.c | 2 +- arch/x86/kernel/aperture_64.c | 2 +- arch/x86/kernel/pci-calgary_64.c | 10 +--------- arch/x86/kernel/pci-dma.c | 21 +++++++++++++-------- arch/x86/kernel/pci-gart_64.c | 1 + arch/x86/kernel/pci-nommu.c | 9 --------- arch/x86/kernel/pci-swiotlb.c | 7 +++---- drivers/pci/dmar.c | 3 +-- drivers/pci/intel-iommu.c | 6 ++++-- lib/swiotlb.c | 4 +++- 12 files changed, 29 insertions(+), 39 deletions(-) diff --git a/arch/x86/include/asm/iommu.h b/arch/x86/include/asm/iommu.h index 878b3071576..df42a712361 100644 --- a/arch/x86/include/asm/iommu.h +++ b/arch/x86/include/asm/iommu.h @@ -2,7 +2,6 @@ #define _ASM_X86_IOMMU_H static inline void iommu_shutdown_noop(void) {} -extern void no_iommu_init(void); extern struct dma_map_ops nommu_dma_ops; extern int force_iommu, no_iommu; extern int iommu_detected; diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 0285521e0a9..66237fde758 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -2110,8 +2110,8 @@ int __init amd_iommu_init_dma_ops(void) prealloc_protection_domains(); iommu_detected = 1; - force_iommu = 1; bad_dma_address = 0; + swiotlb = 0; #ifdef CONFIG_GART_IOMMU gart_iommu_aperture_disabled = 1; gart_iommu_aperture = 0; diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index c41aabddaa2..0d4581e602a 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -1330,7 +1330,7 @@ static int __init early_amd_iommu_detect(struct acpi_table_header *table) void __init amd_iommu_detect(void) { - if (swiotlb || no_iommu || (iommu_detected && !gart_iommu_aperture)) + if (no_iommu || (iommu_detected && !gart_iommu_aperture)) return; if (acpi_table_parse("IVRS", early_amd_iommu_detect) == 0) { diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c index 03933cf0b63..e0dfb6856aa 100644 --- a/arch/x86/kernel/aperture_64.c +++ b/arch/x86/kernel/aperture_64.c @@ -458,7 +458,7 @@ out: if (aper_alloc) { /* Got the aperture from the AGP bridge */ - } else if (swiotlb && !valid_agp) { + } else if (!valid_agp) { /* Do nothing */ } else if ((!no_iommu && max_pfn > MAX_DMA32_PFN) || force_iommu || diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index 47bd419ea4d..833f491440b 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c @@ -1360,7 +1360,7 @@ void __init detect_calgary(void) * if the user specified iommu=off or iommu=soft or we found * another HW IOMMU already, bail out. */ - if (swiotlb || no_iommu || iommu_detected) + if (no_iommu || iommu_detected) return; if (!use_calgary) @@ -1445,10 +1445,6 @@ void __init detect_calgary(void) printk(KERN_INFO "PCI-DMA: Calgary TCE table spec is %d\n", specified_table_size); - /* swiotlb for devices that aren't behind the Calgary. */ - if (max_pfn > MAX_DMA32_PFN) - swiotlb = 1; - x86_init.iommu.iommu_init = calgary_iommu_init; } return; @@ -1476,11 +1472,7 @@ int __init calgary_iommu_init(void) return ret; } - force_iommu = 1; bad_dma_address = 0x0; - /* dma_ops is set to swiotlb or nommu */ - if (!dma_ops) - dma_ops = &nommu_dma_ops; return 0; } diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index bed05e2e589..a234e63c265 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -124,24 +124,24 @@ static void __init dma32_free_bootmem(void) void __init pci_iommu_alloc(void) { + /* swiotlb is forced by the boot option */ + int use_swiotlb = swiotlb; #ifdef CONFIG_X86_64 /* free the range so iommu could get some range less than 4G */ dma32_free_bootmem(); #endif + pci_swiotlb_init(); + if (use_swiotlb) + return; - /* - * The order of these functions is important for - * fall-back/fail-over reasons - */ gart_iommu_hole_init(); detect_calgary(); detect_intel_iommu(); + /* needs to be called after gart_iommu_hole_init */ amd_iommu_detect(); - - pci_swiotlb_init(); } void *dma_generic_alloc_coherent(struct device *dev, size_t size, @@ -291,10 +291,15 @@ static int __init pci_iommu_init(void) #ifdef CONFIG_PCI dma_debug_add_bus(&pci_bus_type); #endif - x86_init.iommu.iommu_init(); - no_iommu_init(); + if (swiotlb) { + printk(KERN_INFO "PCI-DMA: " + "Using software bounce buffering for IO (SWIOTLB)\n"); + swiotlb_print_info(); + } else + swiotlb_free(); + return 0; } /* Must execute after PCI subsystem */ diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index 0410bd30060..919182e15d1 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c @@ -833,6 +833,7 @@ int __init gart_iommu_init(void) flush_gart(); dma_ops = &gart_dma_ops; x86_platform.iommu_shutdown = gart_iommu_shutdown; + swiotlb = 0; return 0; } diff --git a/arch/x86/kernel/pci-nommu.c b/arch/x86/kernel/pci-nommu.c index a3933d4330c..875e3822ae6 100644 --- a/arch/x86/kernel/pci-nommu.c +++ b/arch/x86/kernel/pci-nommu.c @@ -103,12 +103,3 @@ struct dma_map_ops nommu_dma_ops = { .sync_sg_for_device = nommu_sync_sg_for_device, .is_phys = 1, }; - -void __init no_iommu_init(void) -{ - if (dma_ops) - return; - - force_iommu = 0; /* no HW IOMMU */ - dma_ops = &nommu_dma_ops; -} diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c index ea20ef7ca52..17ce4221bd0 100644 --- a/arch/x86/kernel/pci-swiotlb.c +++ b/arch/x86/kernel/pci-swiotlb.c @@ -46,13 +46,12 @@ void __init pci_swiotlb_init(void) { /* don't initialize swiotlb if iommu=off (no_iommu=1) */ #ifdef CONFIG_X86_64 - if ((!iommu_detected && !no_iommu && max_pfn > MAX_DMA32_PFN)) + if (!no_iommu && max_pfn > MAX_DMA32_PFN) swiotlb = 1; #endif - if (swiotlb_force) - swiotlb = 1; if (swiotlb) { swiotlb_init(0); dma_ops = &swiotlb_dma_ops; - } + } else + dma_ops = &nommu_dma_ops; } diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index bce9cd7c755..437399667e5 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -613,8 +613,7 @@ void __init detect_intel_iommu(void) "x2apic and Intr-remapping.\n"); #endif #ifdef CONFIG_DMAR - if (ret && !no_iommu && !iommu_detected && !swiotlb && - !dmar_disabled) + if (ret && !no_iommu && !iommu_detected && !dmar_disabled) iommu_detected = 1; #endif #ifdef CONFIG_X86 diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index b1e97e68250..43d755a2e14 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -3231,7 +3231,7 @@ int __init intel_iommu_init(void) * Check the need for DMA-remapping initialization now. * Above initialization will also be used by Interrupt-remapping. */ - if (no_iommu || swiotlb || dmar_disabled) + if (no_iommu || dmar_disabled) return -ENODEV; iommu_init_mempool(); @@ -3252,7 +3252,9 @@ int __init intel_iommu_init(void) "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n"); init_timer(&unmap_timer); - force_iommu = 1; +#ifdef CONFIG_SWIOTLB + swiotlb = 0; +#endif dma_ops = &intel_dma_ops; init_iommu_sysfs(); diff --git a/lib/swiotlb.c b/lib/swiotlb.c index 0c12d7cce30..e6755a0574f 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -109,8 +109,10 @@ setup_io_tlb_npages(char *str) } if (*str == ',') ++str; - if (!strcmp(str, "force")) + if (!strcmp(str, "force")) { swiotlb_force = 1; + swiotlb = 1; + } return 1; } __setup("swiotlb=", setup_io_tlb_npages); From 72d03802b8b5c841ab1da82bff0652628cbadf60 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 10 Nov 2009 21:35:17 +0900 Subject: [PATCH 131/298] x86, 32-bit: Fix swiotlb boot crash Ingo Molnar reported this boot crash: [ 8.655620] pata_amd 0000:00:06.0: version 0.4.1 [ 8.660286] BUG: unable to handle kernel NULL pointer dereference at 00000034 [ 8.663572] IP: [] dma_supported+0x3b/0xa4 [ 8.663572] *pde = 00000000 Initialize dma_ops properly in the 32-bit case. Signed-off-by: Ingo Molnar --- arch/x86/kernel/pci-dma.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index a234e63c265..63eebee80e7 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -129,6 +129,8 @@ void __init pci_iommu_alloc(void) #ifdef CONFIG_X86_64 /* free the range so iommu could get some range less than 4G */ dma32_free_bootmem(); +#else + dma_ops = &nommu_dma_ops; #endif pci_swiotlb_init(); if (use_swiotlb) From b4941a9a606f0131559cc040b64e8437ac7b32c5 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 10 Nov 2009 14:37:58 +0100 Subject: [PATCH 132/298] x86: Add iommu_init to x86_init_ops, fix build Most of the time x86_init.h is included in pci-dma.c - but not always, leading to this rare build failure: arch/x86/kernel/pci-dma.c:296: error: 'x86_init' undeclared (first use in this function) So include asm/x86_init.h explicitly. Cc: FUJITA Tomonori Cc: chrisw@sous-sol.org Cc: dwmw2@infradead.org Cc: joerg.roedel@amd.com Cc: muli@il.ibm.com LKML-Reference: <1257849980-22640-2-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar --- arch/x86/kernel/pci-dma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 63eebee80e7..f79870e8926 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -11,6 +11,7 @@ #include #include #include +#include static int forbid_dac __read_mostly; From dbe01350fa8ce0c11948ab7d6be71a4d901be151 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 10 Nov 2009 13:37:19 -0800 Subject: [PATCH 133/298] rcu: Remove inline from forward-referenced functions Some variants of gcc are reputed to dislike forward references to functions declared "inline". Remove the "inline" keyword from such functions. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12578890422402-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.h | 2 +- kernel/rcutree_plugin.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/rcutree.h b/kernel/rcutree.h index c1891c3cae6..ddb79ece05e 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -301,7 +301,7 @@ DECLARE_PER_CPU(struct rcu_data, rcu_preempt_data); #else /* #ifdef RCU_TREE_NONCORE */ /* Forward declarations for rcutree_plugin.h */ -static inline void rcu_bootup_announce(void); +static void rcu_bootup_announce(void); long rcu_batches_completed(void); static void rcu_preempt_note_context_switch(int cpu); static int rcu_preempted_readers(struct rcu_node *rnp); diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index ef2a58c2b9d..c03edf76635 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -33,7 +33,7 @@ DEFINE_PER_CPU(struct rcu_data, rcu_preempt_data); /* * Tell them what RCU they are running. */ -static inline void rcu_bootup_announce(void) +static void rcu_bootup_announce(void) { printk(KERN_INFO "Experimental preemptable hierarchical RCU implementation.\n"); @@ -481,7 +481,7 @@ void exit_rcu(void) /* * Tell them what RCU they are running. */ -static inline void rcu_bootup_announce(void) +static void rcu_bootup_announce(void) { printk(KERN_INFO "Hierarchical RCU implementation.\n"); } From 956539b75921f561c0956c22d37320780e8b4ba1 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 10 Nov 2009 13:37:20 -0800 Subject: [PATCH 134/298] rcu: Enable synchronize_sched_expedited() fastpath This patch adds a counter increment to enable tasks to actually take the synchronize_sched_expedited() function's fastpath. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <1257889042435-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/sched.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/sched.c b/kernel/sched.c index 76c0e9691fc..e69fee4544b 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -10865,6 +10865,7 @@ void synchronize_sched_expedited(void) spin_unlock_irqrestore(&rq->lock, flags); } rcu_expedited_state = RCU_EXPEDITED_STATE_IDLE; + synchronize_sched_expedited_count++; mutex_unlock(&rcu_sched_expedited_mutex); put_online_cpus(); if (need_full_sync) From 4bcfe055030d9e953945def3864f7e6997b27782 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 10 Nov 2009 13:37:21 -0800 Subject: [PATCH 135/298] rcu: Rename dynticks_completed to completed_fqs This field is used whether or not CONFIG_NO_HZ is set, so the old name of ->dynticks_completed is quite misleading. Change to ->completed_fqs, given that it the value that force_quiescent_state() is trying to drive the ->completed field away from. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12578890423298-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 4 ++-- kernel/rcutree.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index ec007dd2263..26fc7807761 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -187,7 +187,7 @@ static struct rcu_node *rcu_get_root(struct rcu_state *rsp) */ static void dyntick_record_completed(struct rcu_state *rsp, long comp) { - rsp->dynticks_completed = comp; + rsp->completed_fqs = comp; } #ifdef CONFIG_SMP @@ -197,7 +197,7 @@ static void dyntick_record_completed(struct rcu_state *rsp, long comp) */ static long dyntick_recall_completed(struct rcu_state *rsp) { - return rsp->dynticks_completed; + return rsp->completed_fqs; } /* diff --git a/kernel/rcutree.h b/kernel/rcutree.h index ddb79ece05e..17a28a08b55 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -264,6 +264,8 @@ struct rcu_state { long orphan_qlen; /* Number of orphaned cbs. */ spinlock_t fqslock; /* Only one task forcing */ /* quiescent states. */ + long completed_fqs; /* Value of completed @ snap. */ + /* Protected by fqslock. */ unsigned long jiffies_force_qs; /* Time at which to invoke */ /* force_quiescent_state(). */ unsigned long n_force_qs; /* Number of calls to */ @@ -278,8 +280,6 @@ struct rcu_state { unsigned long jiffies_stall; /* Time at which to check */ /* for CPU stalls. */ #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ - long dynticks_completed; /* Value of completed @ snap. */ - /* Protected by fqslock. */ }; #ifdef RCU_TREE_NONCORE From c64ac3ce06558e534aec62b1fadeb0a3f111dac1 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 10 Nov 2009 13:37:22 -0800 Subject: [PATCH 136/298] rcu: Simplify association of quiescent states with grace periods The rdp->passed_quiesc_completed fields are used to properly associate the recorded quiescent state with a grace period. It is OK to wrongly associate a given quiescent state with a preceding grace period, but it is fatal to associate a given quiescent state with a grace period that begins after the quiescent state occurred. Grace periods are numbered, and the following fields track them: o ->gpnum is the number of the grace period currently in progress, or the number of the last grace period to complete if no grace period is currently in progress. o ->completed is the number of the last grace period to have completed. These two fields are equal if there is no grace period in progress, otherwise ->gpnum is one greater than ->completed. But the rdp->passed_quiesc_completed field compared against ->completed, and if equal, the quiescent state is presumed to count against the current grace period. The earlier code copied rdp->completed to rdp->passed_quiesc_completed, which has been made to work, but is error-prone. In contrast, copying one less than rdp->gpnum is guaranteed safe, because rdp->gpnum is not incremented until after the start of the corresponding grace period. At the end of the grace period, when ->completed has incremented, then any quiescent periods recorded previously will be discarded. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12578890421011-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 4 ++-- kernel/rcutree_plugin.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 26fc7807761..d8024192c73 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -100,7 +100,7 @@ void rcu_sched_qs(int cpu) struct rcu_data *rdp; rdp = &per_cpu(rcu_sched_data, cpu); - rdp->passed_quiesc_completed = rdp->completed; + rdp->passed_quiesc_completed = rdp->gpnum - 1; barrier(); rdp->passed_quiesc = 1; rcu_preempt_note_context_switch(cpu); @@ -111,7 +111,7 @@ void rcu_bh_qs(int cpu) struct rcu_data *rdp; rdp = &per_cpu(rcu_bh_data, cpu); - rdp->passed_quiesc_completed = rdp->completed; + rdp->passed_quiesc_completed = rdp->gpnum - 1; barrier(); rdp->passed_quiesc = 1; } diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index c03edf76635..52075da7054 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -67,7 +67,7 @@ EXPORT_SYMBOL_GPL(rcu_batches_completed); static void rcu_preempt_qs(int cpu) { struct rcu_data *rdp = &per_cpu(rcu_preempt_data, cpu); - rdp->passed_quiesc_completed = rdp->completed; + rdp->passed_quiesc_completed = rdp->gpnum - 1; barrier(); rdp->passed_quiesc = 1; } From b18485e7acfe1a634615d1c628ef644c0d58d472 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 12 Nov 2009 00:03:28 +0900 Subject: [PATCH 137/298] swiotlb: Remove the swiotlb variable usage POWERPC doesn't expect it to be used. This fixes the linux-next build failure reported by Stephen Rothwell: lib/swiotlb.c: In function 'setup_io_tlb_npages': lib/swiotlb.c:114: error: 'swiotlb' undeclared (first use in this function) Reported-by: Stephen Rothwell Signed-off-by: FUJITA Tomonori Cc: peterz@infradead.org LKML-Reference: <20091112000258F.fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/swiotlb.h | 5 +++-- arch/x86/kernel/pci-dma.c | 5 +---- arch/x86/kernel/pci-swiotlb.c | 13 ++++++++++++- lib/swiotlb.c | 5 ++--- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/arch/x86/include/asm/swiotlb.h b/arch/x86/include/asm/swiotlb.h index b9e4e20174f..940f13a213f 100644 --- a/arch/x86/include/asm/swiotlb.h +++ b/arch/x86/include/asm/swiotlb.h @@ -9,11 +9,12 @@ extern int swiotlb_force; #ifdef CONFIG_SWIOTLB extern int swiotlb; -extern void pci_swiotlb_init(void); +extern int pci_swiotlb_init(void); #else #define swiotlb 0 -static inline void pci_swiotlb_init(void) +static inline int pci_swiotlb_init(void) { + return 0; } #endif diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index f79870e8926..0b11bf18f54 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -125,16 +125,13 @@ static void __init dma32_free_bootmem(void) void __init pci_iommu_alloc(void) { - /* swiotlb is forced by the boot option */ - int use_swiotlb = swiotlb; #ifdef CONFIG_X86_64 /* free the range so iommu could get some range less than 4G */ dma32_free_bootmem(); #else dma_ops = &nommu_dma_ops; #endif - pci_swiotlb_init(); - if (use_swiotlb) + if (pci_swiotlb_init()) return; gart_iommu_hole_init(); diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c index 17ce4221bd0..a6e5d0ffa3a 100644 --- a/arch/x86/kernel/pci-swiotlb.c +++ b/arch/x86/kernel/pci-swiotlb.c @@ -42,16 +42,27 @@ static struct dma_map_ops swiotlb_dma_ops = { .dma_supported = NULL, }; -void __init pci_swiotlb_init(void) +/* + * pci_swiotlb_init - initialize swiotlb if necessary + * + * This returns non-zero if we are forced to use swiotlb (by the boot + * option). + */ +int __init pci_swiotlb_init(void) { /* don't initialize swiotlb if iommu=off (no_iommu=1) */ #ifdef CONFIG_X86_64 if (!no_iommu && max_pfn > MAX_DMA32_PFN) swiotlb = 1; #endif + if (swiotlb_force) + swiotlb = 1; + if (swiotlb) { swiotlb_init(0); dma_ops = &swiotlb_dma_ops; } else dma_ops = &nommu_dma_ops; + + return swiotlb_force; } diff --git a/lib/swiotlb.c b/lib/swiotlb.c index e6755a0574f..795472d8ae2 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -109,10 +109,9 @@ setup_io_tlb_npages(char *str) } if (*str == ',') ++str; - if (!strcmp(str, "force")) { + if (!strcmp(str, "force")) swiotlb_force = 1; - swiotlb = 1; - } + return 1; } __setup("swiotlb=", setup_io_tlb_npages); From e657ea17ef2d7f364e5c2625157f6cc0584ac7ad Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 11 Nov 2009 09:31:07 -0800 Subject: [PATCH 138/298] pcmcia: fix printk formats Fix printk format warnings on sizeof() [size_t] arguments. drivers/char/pcmcia/cm4040_cs.c:267: warning: format '%lu' expects type 'long unsigned int', but argument 5 has type 'size_t' drivers/char/pcmcia/cm4040_cs.c:272: warning: format '%lu' expects type 'long unsigned int', but argument 5 has type 'size_t' CC: Harald Welte Signed-off-by: Randy Dunlap Signed-off-by: Dominik Brodowski --- drivers/char/pcmcia/cm4040_cs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 0001ad2e58b..38790db561a 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -264,12 +264,12 @@ static ssize_t cm4040_read(struct file *filp, char __user *buf, bytes_to_read = 5 + le32_to_cpu(*(__le32 *)&dev->r_buf[1]); - DEBUGP(6, dev, "BytesToRead=%lu\n", bytes_to_read); + DEBUGP(6, dev, "BytesToRead=%zu\n", bytes_to_read); min_bytes_to_read = min(count, bytes_to_read + 5); min_bytes_to_read = min_t(size_t, min_bytes_to_read, READ_WRITE_BUFFER_SIZE); - DEBUGP(6, dev, "Min=%lu\n", min_bytes_to_read); + DEBUGP(6, dev, "Min=%zu\n", min_bytes_to_read); for (i = 0; i < (min_bytes_to_read-5); i++) { rc = wait_for_bulk_in_ready(dev); From b285fab4185a9b3db953726f0dd9d343a6e389db Mon Sep 17 00:00:00 2001 From: Avi Cohen Stuart Date: Tue, 10 Nov 2009 22:43:46 +0100 Subject: [PATCH 139/298] pcmcia: correct handling for Zoomed Video registers in topic.h Fix handling of Zoomed Video Registers in the Topic pcmcia controller ( http://bugzilla.kernel.org/show_bug.cgi?id=14581 ). The information has been retrieved from the Topic manual which can be obtained from Toshiba. The Zoomed Video is used with PCMCIA Cards like the Margi DVD-to-Go. [linux@dominikbrodowski.net: whitespace & commit message fix] Signed-off-by: Avi Cohen Stuart Signed-off-by: Dominik Brodowski --- drivers/pcmcia/topic.h | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/pcmcia/topic.h b/drivers/pcmcia/topic.h index edccfa5bb40..615a45a8fe8 100644 --- a/drivers/pcmcia/topic.h +++ b/drivers/pcmcia/topic.h @@ -114,22 +114,17 @@ static void topic97_zoom_video(struct pcmcia_socket *sock, int onoff) reg_zv |= TOPIC97_ZV_CONTROL_ENABLE; config_writeb(socket, TOPIC97_ZOOM_VIDEO_CONTROL, reg_zv); - reg = config_readb(socket, TOPIC97_MISC2); - reg |= TOPIC97_MISC2_ZV_ENABLE; - config_writeb(socket, TOPIC97_MISC2, reg); - - /* not sure this is needed, doc is unclear */ -#if 0 reg = config_readb(socket, TOPIC97_AUDIO_VIDEO_SWITCH); reg |= TOPIC97_AVS_AUDIO_CONTROL | TOPIC97_AVS_VIDEO_CONTROL; config_writeb(socket, TOPIC97_AUDIO_VIDEO_SWITCH, reg); -#endif - } - else { + } else { reg_zv &= ~TOPIC97_ZV_CONTROL_ENABLE; config_writeb(socket, TOPIC97_ZOOM_VIDEO_CONTROL, reg_zv); - } + reg = config_readb(socket, TOPIC97_AUDIO_VIDEO_SWITCH); + reg &= ~(TOPIC97_AVS_AUDIO_CONTROL | TOPIC97_AVS_VIDEO_CONTROL); + config_writeb(socket, TOPIC97_AUDIO_VIDEO_SWITCH, reg); + } } static int topic97_override(struct yenta_socket *socket) From 0e0fc1c23e04c15e814763f2b366e92d87d8b95d Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 11 Nov 2009 11:28:06 -0800 Subject: [PATCH 140/298] rcu: Mark init-time-only rcu_bootup_announce() as __init Because rcu_bootup_announce() is used only at boot time, mark it as __init, presumably so that its memory can be reclaimed. Suggested-by: Joe Perches Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <20091111192806.GA10073@linux.vnet.ibm.com> Signed-off-by: Ingo Molnar --- kernel/rcutree_plugin.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 52075da7054..5ca2d26c597 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -33,7 +33,7 @@ DEFINE_PER_CPU(struct rcu_data, rcu_preempt_data); /* * Tell them what RCU they are running. */ -static void rcu_bootup_announce(void) +static void __init rcu_bootup_announce(void) { printk(KERN_INFO "Experimental preemptable hierarchical RCU implementation.\n"); @@ -481,7 +481,7 @@ void exit_rcu(void) /* * Tell them what RCU they are running. */ -static void rcu_bootup_announce(void) +static void __init rcu_bootup_announce(void) { printk(KERN_INFO "Hierarchical RCU implementation.\n"); } From a646365cc330b5aaf4452c91f61b1e0d1acf68d0 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Wed, 11 Nov 2009 22:26:35 +0100 Subject: [PATCH 141/298] tracing: Fix return value of tracing_stats_read() The function tracing_stats_read() mistakenly returns ENOMEM instead of the negative value -ENOMEM. Signed-off-by: Roel Kluin LKML-Reference: <4AFB2C0B.50605@gmail.com> Signed-off-by: Steven Rostedt --- kernel/trace/trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index b20d3ec75de..03c7fd55c5f 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -3730,7 +3730,7 @@ tracing_stats_read(struct file *filp, char __user *ubuf, s = kmalloc(sizeof(*s), GFP_KERNEL); if (!s) - return ENOMEM; + return -ENOMEM; trace_seq_init(s); From a6f0eb6adc42e5eed3f35af99c61c0e411b16f8e Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 11 Nov 2009 17:14:07 -0500 Subject: [PATCH 142/298] ring-buffer: Add multiple iterations between benchmark timestamps The ring_buffer_benchmark does a gettimeofday after every write to the ring buffer in its measurements. This adds the overhead of the call to gettimeofday to the measurements and does not give an accurate picture of the length of time it takes to record a trace. This was first noticed with perf top: ------------------------------------------------------------------------------ PerfTop: 679 irqs/sec kernel:99.9% [1000Hz cpu-clock-msecs], (all, 4 CPUs) ------------------------------------------------------------------------------ samples pcnt kernel function _______ _____ _______________ 1673.00 - 27.8% : trace_clock_local 806.00 - 13.4% : do_gettimeofday 590.00 - 9.8% : rb_reserve_next_event 554.00 - 9.2% : native_read_tsc 431.00 - 7.2% : ring_buffer_lock_reserve 365.00 - 6.1% : __rb_reserve_next 355.00 - 5.9% : rb_end_commit 322.00 - 5.4% : getnstimeofday 268.00 - 4.5% : ring_buffer_unlock_commit 262.00 - 4.4% : ring_buffer_producer_thread [ring_buffer_benchmark] 113.00 - 1.9% : read_tsc 91.00 - 1.5% : debug_smp_processor_id 69.00 - 1.1% : trace_recursive_unlock 66.00 - 1.1% : ring_buffer_event_data 25.00 - 0.4% : _spin_unlock_irq And the length of each write to the ring buffer measured at 310ns. This patch adds a new module parameter called "write_interval" which is defaulted to 50. This is the number of writes performed between timestamps. After this patch perf top shows: ------------------------------------------------------------------------------ PerfTop: 244 irqs/sec kernel:100.0% [1000Hz cpu-clock-msecs], (all, 4 CPUs) ------------------------------------------------------------------------------ samples pcnt kernel function _______ _____ _______________ 2842.00 - 40.4% : trace_clock_local 1043.00 - 14.8% : rb_reserve_next_event 784.00 - 11.1% : ring_buffer_lock_reserve 600.00 - 8.5% : __rb_reserve_next 579.00 - 8.2% : rb_end_commit 440.00 - 6.3% : ring_buffer_unlock_commit 290.00 - 4.1% : ring_buffer_producer_thread [ring_buffer_benchmark] 155.00 - 2.2% : debug_smp_processor_id 117.00 - 1.7% : trace_recursive_unlock 103.00 - 1.5% : ring_buffer_event_data 28.00 - 0.4% : do_gettimeofday 22.00 - 0.3% : _spin_unlock_irq 14.00 - 0.2% : native_read_tsc 11.00 - 0.2% : getnstimeofday do_gettimeofday dropped from 13% usage to a mere 0.4%! (using the default 50 interval) The measurement for each timestamp went from 310ns to 210ns. That's 100ns (1/3rd) overhead that the gettimeofday call was introducing. Signed-off-by: Steven Rostedt --- kernel/trace/ring_buffer_benchmark.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/kernel/trace/ring_buffer_benchmark.c b/kernel/trace/ring_buffer_benchmark.c index 573d3cc762c..70df73e4ff2 100644 --- a/kernel/trace/ring_buffer_benchmark.c +++ b/kernel/trace/ring_buffer_benchmark.c @@ -35,6 +35,10 @@ static int disable_reader; module_param(disable_reader, uint, 0644); MODULE_PARM_DESC(disable_reader, "only run producer"); +static int write_iteration = 50; +module_param(write_iteration, uint, 0644); +MODULE_PARM_DESC(write_iteration, "# of writes between timestamp readings"); + static int read_events; static int kill_test; @@ -208,15 +212,18 @@ static void ring_buffer_producer(void) do { struct ring_buffer_event *event; int *entry; + int i; - event = ring_buffer_lock_reserve(buffer, 10); - if (!event) { - missed++; - } else { - hit++; - entry = ring_buffer_event_data(event); - *entry = smp_processor_id(); - ring_buffer_unlock_commit(buffer, event); + for (i = 0; i < write_iteration; i++) { + event = ring_buffer_lock_reserve(buffer, 10); + if (!event) { + missed++; + } else { + hit++; + entry = ring_buffer_event_data(event); + *entry = smp_processor_id(); + ring_buffer_unlock_commit(buffer, event); + } } do_gettimeofday(&end_tv); From 8b2a5dac7859dd1954095fce8b6445c3ceb36ef6 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 11 Nov 2009 19:36:03 -0500 Subject: [PATCH 143/298] tracing: do not disable interrupts for trace_clock_local Disabling interrupts in trace_clock_local takes quite a performance hit to the recording of traces. Using perf top we see: ------------------------------------------------------------------------------ PerfTop: 244 irqs/sec kernel:100.0% [1000Hz cpu-clock-msecs], (all, 4 CPUs) ------------------------------------------------------------------------------ samples pcnt kernel function _______ _____ _______________ 2842.00 - 40.4% : trace_clock_local 1043.00 - 14.8% : rb_reserve_next_event 784.00 - 11.1% : ring_buffer_lock_reserve 600.00 - 8.5% : __rb_reserve_next 579.00 - 8.2% : rb_end_commit 440.00 - 6.3% : ring_buffer_unlock_commit 290.00 - 4.1% : ring_buffer_producer_thread [ring_buffer_benchmark] 155.00 - 2.2% : debug_smp_processor_id 117.00 - 1.7% : trace_recursive_unlock 103.00 - 1.5% : ring_buffer_event_data 28.00 - 0.4% : do_gettimeofday 22.00 - 0.3% : _spin_unlock_irq 14.00 - 0.2% : native_read_tsc 11.00 - 0.2% : getnstimeofday Where trace_clock_local is 40% of the tracing, and the time for recording a trace according to ring_buffer_benchmark is 210ns. After converting the interrupts to preemption disabling we have from perf top: ------------------------------------------------------------------------------ PerfTop: 1084 irqs/sec kernel:99.9% [1000Hz cpu-clock-msecs], (all, 4 CPUs) ------------------------------------------------------------------------------ samples pcnt kernel function _______ _____ _______________ 1277.00 - 16.8% : native_read_tsc 1148.00 - 15.1% : rb_reserve_next_event 896.00 - 11.8% : ring_buffer_lock_reserve 688.00 - 9.1% : __rb_reserve_next 664.00 - 8.8% : rb_end_commit 563.00 - 7.4% : ring_buffer_unlock_commit 508.00 - 6.7% : _spin_unlock_irq 365.00 - 4.8% : debug_smp_processor_id 321.00 - 4.2% : trace_clock_local 303.00 - 4.0% : ring_buffer_producer_thread [ring_buffer_benchmark] 273.00 - 3.6% : native_sched_clock 122.00 - 1.6% : trace_recursive_unlock 113.00 - 1.5% : sched_clock 101.00 - 1.3% : ring_buffer_event_data 53.00 - 0.7% : tick_nohz_stop_sched_tick Where trace_clock_local drops from 40% to only taking 4% of the total time. The trace time also goes from 210ns down to 179ns (31ns). I talked with Peter Zijlstra about the impact that sched_clock may have without having interrupts disabled, and he told me that if a timer interrupt comes in, sched_clock may report a wrong time. Balancing a seldom incorrect timestamp with a 15% performance boost, I'll take the performance boost. Acked-by: Peter Zijlstra Signed-off-by: Steven Rostedt --- kernel/trace/trace_clock.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/kernel/trace/trace_clock.c b/kernel/trace/trace_clock.c index 20c5f92e28a..878c03f386b 100644 --- a/kernel/trace/trace_clock.c +++ b/kernel/trace/trace_clock.c @@ -20,6 +20,8 @@ #include #include +#include "trace.h" + /* * trace_clock_local(): the simplest and least coherent tracing clock. * @@ -28,17 +30,17 @@ */ u64 notrace trace_clock_local(void) { - unsigned long flags; u64 clock; + int resched; /* * sched_clock() is an architecture implemented, fast, scalable, * lockless clock. It is not guaranteed to be coherent across * CPUs, nor across CPU idle events. */ - raw_local_irq_save(flags); + resched = ftrace_preempt_disable(); clock = sched_clock(); - raw_local_irq_restore(flags); + ftrace_preempt_enable(resched); return clock; } From b32e9eb6ad29572b4451847d0e8227c9be2b6d69 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 12 Nov 2009 22:35:03 -0800 Subject: [PATCH 144/298] rcu: Accelerate callback processing on CPUs not detecting GP end An earlier fix for a race resulted in a situation where the CPUs other than the CPU that detected the end of the grace period would not process their callbacks until the next grace period started. This means that these other CPUs would unnecessarily demand that an extra grace period be started. This patch eliminates this extra grace period and speeds callback processing by propagating rsp->completed to the rcu_node structures in the case where the CPU detecting the end of the grace period sees no reason to start a new grace period. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <1258094104417-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index d8024192c73..b4efb9e3668 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -676,7 +676,23 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) struct rcu_node *rnp = rcu_get_root(rsp); if (!cpu_needs_another_gp(rsp, rdp)) { - spin_unlock_irqrestore(&rnp->lock, flags); + if (rnp->completed == rsp->completed) { + spin_unlock_irqrestore(&rnp->lock, flags); + return; + } + spin_unlock(&rnp->lock); /* irqs remain disabled. */ + + /* + * Propagate new ->completed value to rcu_node structures + * so that other CPUs don't have to wait until the start + * of the next grace period to process their callbacks. + */ + rcu_for_each_node_breadth_first(rsp, rnp) { + spin_lock(&rnp->lock); /* irqs already disabled. */ + rnp->completed = rsp->completed; + spin_unlock(&rnp->lock); /* irqs remain disabled. */ + } + local_irq_restore(flags); return; } From 8e9aa8f067d2dcd9457980ced618e1cffbcfba46 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 12 Nov 2009 22:35:04 -0800 Subject: [PATCH 145/298] rcu: Simplify association of forced quiescent states with grace periods The force_quiescent_state() function also took a snapshot of the ->completed field, which was as obnoxious as it was in rcu_sched_qs() and friends. So snapshot ->gpnum-1. Also, since the dyntick_record_completed() and dyntick_recall_completed() functions are now simple assignments that are independent of CONFIG_NO_HZ, and since their names are now misleading, get rid of them. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12580941042308-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index b4efb9e3668..3df04381ea3 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -178,28 +178,8 @@ static struct rcu_node *rcu_get_root(struct rcu_state *rsp) return &rsp->node[0]; } -/* - * Record the specified "completed" value, which is later used to validate - * dynticks counter manipulations and CPU-offline checks. Specify - * "rsp->completed - 1" to unconditionally invalidate any future dynticks - * manipulations and CPU-offline checks. Such invalidation is useful at - * the beginning of a grace period. - */ -static void dyntick_record_completed(struct rcu_state *rsp, long comp) -{ - rsp->completed_fqs = comp; -} - #ifdef CONFIG_SMP -/* - * Recall the previously recorded value of the completion for dynticks. - */ -static long dyntick_recall_completed(struct rcu_state *rsp) -{ - return rsp->completed_fqs; -} - /* * If the specified CPU is offline, tell the caller that it is in * a quiescent state. Otherwise, whack it with a reschedule IPI. @@ -702,7 +682,6 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) rsp->signaled = RCU_GP_INIT; /* Hold off force_quiescent_state. */ rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS; record_gp_stall_check_time(rsp); - dyntick_record_completed(rsp, rsp->completed - 1); /* Special-case the common single-level case. */ if (NUM_RCU_NODES == 1) { @@ -1214,7 +1193,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) goto unlock_ret; /* no emergency and done recently. */ rsp->n_force_qs++; spin_lock(&rnp->lock); - lastcomp = rsp->completed; + lastcomp = rsp->gpnum - 1; signaled = rsp->signaled; rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS; if (lastcomp == rsp->gpnum) { @@ -1248,7 +1227,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) if (lastcomp == rsp->completed && rsp->signaled == signaled) { rsp->signaled = RCU_FORCE_QS; - dyntick_record_completed(rsp, lastcomp); + rsp->completed_fqs = lastcomp; forcenow = signaled == RCU_SAVE_COMPLETED; } spin_unlock(&rnp->lock); @@ -1259,7 +1238,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) case RCU_FORCE_QS: /* Check dyntick-idle state, send IPI to laggarts. */ - if (rcu_process_dyntick(rsp, dyntick_recall_completed(rsp), + if (rcu_process_dyntick(rsp, rsp->completed_fqs, rcu_implicit_dynticks_qs)) goto unlock_ret; From 6beb000923882f6204ea2cfcd932e568e900803f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 9 Nov 2009 15:21:34 +0000 Subject: [PATCH 146/298] locking: Make inlining decision Kconfig based commit 892a7c67 (locking: Allow arch-inlined spinlocks) implements the selection of which lock functions are inlined based on defines in arch/.../spinlock.h: #define __always_inline__LOCK_FUNCTION Despite of the name __always_inline__* the lock functions can be built out of line depending on config options. Also if the arch does not set some inline defines the generic code might set them; again depending on config options. This makes it unnecessary hard to figure out when and which lock functions are inlined. Aside of that it makes it way harder and messier for -rt to manipulate the lock functions. Convert the inlining decision to CONFIG switches. Each lock function is inlined depending on CONFIG_INLINE_*. The configs implement the existing dependencies. The architecture code can select ARCH_INLINE_* to signal that it wants the corresponding lock function inlined. ARCH_INLINE_* is necessary as Kconfig ignores "depends on" restrictions when a config element is selected. No functional change. Signed-off-by: Thomas Gleixner LKML-Reference: <20091109151428.504477141@linutronix.de> Acked-by: Heiko Carstens Reviewed-by: Ingo Molnar Acked-by: Peter Zijlstra --- arch/s390/Kconfig | 28 +++++ arch/s390/include/asm/spinlock.h | 29 ----- include/linux/spinlock_api_smp.h | 75 +++++------- init/Kconfig | 1 + kernel/Kconfig.locks | 199 +++++++++++++++++++++++++++++++ kernel/spinlock.c | 56 ++++----- 6 files changed, 284 insertions(+), 104 deletions(-) create mode 100644 kernel/Kconfig.locks diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 43c0acad716..16c673096a2 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -95,6 +95,34 @@ config S390 select HAVE_ARCH_TRACEHOOK select INIT_ALL_POSSIBLE select HAVE_PERF_EVENTS + select ARCH_INLINE_SPIN_TRYLOCK + select ARCH_INLINE_SPIN_TRYLOCK_BH + select ARCH_INLINE_SPIN_LOCK + select ARCH_INLINE_SPIN_LOCK_BH + select ARCH_INLINE_SPIN_LOCK_IRQ + select ARCH_INLINE_SPIN_LOCK_IRQSAVE + select ARCH_INLINE_SPIN_UNLOCK + select ARCH_INLINE_SPIN_UNLOCK_BH + select ARCH_INLINE_SPIN_UNLOCK_IRQ + select ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE + select ARCH_INLINE_READ_TRYLOCK + select ARCH_INLINE_READ_LOCK + select ARCH_INLINE_READ_LOCK_BH + select ARCH_INLINE_READ_LOCK_IRQ + select ARCH_INLINE_READ_LOCK_IRQSAVE + select ARCH_INLINE_READ_UNLOCK + select ARCH_INLINE_READ_UNLOCK_BH + select ARCH_INLINE_READ_UNLOCK_IRQ + select ARCH_INLINE_READ_UNLOCK_IRQRESTORE + select ARCH_INLINE_WRITE_TRYLOCK + select ARCH_INLINE_WRITE_LOCK + select ARCH_INLINE_WRITE_LOCK_BH + select ARCH_INLINE_WRITE_LOCK_IRQ + select ARCH_INLINE_WRITE_LOCK_IRQSAVE + select ARCH_INLINE_WRITE_UNLOCK + select ARCH_INLINE_WRITE_UNLOCK_BH + select ARCH_INLINE_WRITE_UNLOCK_IRQ + select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE config SCHED_OMIT_FRAME_POINTER bool diff --git a/arch/s390/include/asm/spinlock.h b/arch/s390/include/asm/spinlock.h index 41ce6861174..c9af0d19c7a 100644 --- a/arch/s390/include/asm/spinlock.h +++ b/arch/s390/include/asm/spinlock.h @@ -191,33 +191,4 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw) #define _raw_read_relax(lock) cpu_relax() #define _raw_write_relax(lock) cpu_relax() -#define __always_inline__spin_lock -#define __always_inline__read_lock -#define __always_inline__write_lock -#define __always_inline__spin_lock_bh -#define __always_inline__read_lock_bh -#define __always_inline__write_lock_bh -#define __always_inline__spin_lock_irq -#define __always_inline__read_lock_irq -#define __always_inline__write_lock_irq -#define __always_inline__spin_lock_irqsave -#define __always_inline__read_lock_irqsave -#define __always_inline__write_lock_irqsave -#define __always_inline__spin_trylock -#define __always_inline__read_trylock -#define __always_inline__write_trylock -#define __always_inline__spin_trylock_bh -#define __always_inline__spin_unlock -#define __always_inline__read_unlock -#define __always_inline__write_unlock -#define __always_inline__spin_unlock_bh -#define __always_inline__read_unlock_bh -#define __always_inline__write_unlock_bh -#define __always_inline__spin_unlock_irq -#define __always_inline__read_unlock_irq -#define __always_inline__write_unlock_irq -#define __always_inline__spin_unlock_irqrestore -#define __always_inline__read_unlock_irqrestore -#define __always_inline__write_unlock_irqrestore - #endif /* __ASM_SPINLOCK_H */ diff --git a/include/linux/spinlock_api_smp.h b/include/linux/spinlock_api_smp.h index 7a7e18fc241..8264a7f459b 100644 --- a/include/linux/spinlock_api_smp.h +++ b/include/linux/spinlock_api_smp.h @@ -60,137 +60,118 @@ void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) __releases(lock); -/* - * We inline the unlock functions in the nondebug case: - */ -#if !defined(CONFIG_DEBUG_SPINLOCK) && !defined(CONFIG_PREEMPT) -#define __always_inline__spin_unlock -#define __always_inline__read_unlock -#define __always_inline__write_unlock -#define __always_inline__spin_unlock_irq -#define __always_inline__read_unlock_irq -#define __always_inline__write_unlock_irq -#endif - -#ifndef CONFIG_DEBUG_SPINLOCK -#ifndef CONFIG_GENERIC_LOCKBREAK - -#ifdef __always_inline__spin_lock +#ifdef CONFIG_INLINE_SPIN_LOCK #define _spin_lock(lock) __spin_lock(lock) #endif -#ifdef __always_inline__read_lock +#ifdef CONFIG_INLINE_READ_LOCK #define _read_lock(lock) __read_lock(lock) #endif -#ifdef __always_inline__write_lock +#ifdef CONFIG_INLINE_WRITE_LOCK #define _write_lock(lock) __write_lock(lock) #endif -#ifdef __always_inline__spin_lock_bh +#ifdef CONFIG_INLINE_SPIN_LOCK_BH #define _spin_lock_bh(lock) __spin_lock_bh(lock) #endif -#ifdef __always_inline__read_lock_bh +#ifdef CONFIG_INLINE_READ_LOCK_BH #define _read_lock_bh(lock) __read_lock_bh(lock) #endif -#ifdef __always_inline__write_lock_bh +#ifdef CONFIG_INLINE_WRITE_LOCK_BH #define _write_lock_bh(lock) __write_lock_bh(lock) #endif -#ifdef __always_inline__spin_lock_irq +#ifdef CONFIG_INLINE_SPIN_LOCK_IRQ #define _spin_lock_irq(lock) __spin_lock_irq(lock) #endif -#ifdef __always_inline__read_lock_irq +#ifdef CONFIG_INLINE_READ_LOCK_IRQ #define _read_lock_irq(lock) __read_lock_irq(lock) #endif -#ifdef __always_inline__write_lock_irq +#ifdef CONFIG_INLINE_WRITE_LOCK_IRQ #define _write_lock_irq(lock) __write_lock_irq(lock) #endif -#ifdef __always_inline__spin_lock_irqsave +#ifdef CONFIG_INLINE_SPIN_LOCK_IRQSAVE #define _spin_lock_irqsave(lock) __spin_lock_irqsave(lock) #endif -#ifdef __always_inline__read_lock_irqsave +#ifdef CONFIG_INLINE_READ_LOCK_IRQSAVE #define _read_lock_irqsave(lock) __read_lock_irqsave(lock) #endif -#ifdef __always_inline__write_lock_irqsave +#ifdef CONFIG_INLINE_WRITE_LOCK_IRQSAVE #define _write_lock_irqsave(lock) __write_lock_irqsave(lock) #endif -#endif /* !CONFIG_GENERIC_LOCKBREAK */ - -#ifdef __always_inline__spin_trylock +#ifdef CONFIG_INLINE_SPIN_TRYLOCK #define _spin_trylock(lock) __spin_trylock(lock) #endif -#ifdef __always_inline__read_trylock +#ifdef CONFIG_INLINE_READ_TRYLOCK #define _read_trylock(lock) __read_trylock(lock) #endif -#ifdef __always_inline__write_trylock +#ifdef CONFIG_INLINE_WRITE_TRYLOCK #define _write_trylock(lock) __write_trylock(lock) #endif -#ifdef __always_inline__spin_trylock_bh +#ifdef CONFIG_INLINE_SPIN_TRYLOCK_BH #define _spin_trylock_bh(lock) __spin_trylock_bh(lock) #endif -#ifdef __always_inline__spin_unlock +#ifdef CONFIG_INLINE_SPIN_UNLOCK #define _spin_unlock(lock) __spin_unlock(lock) #endif -#ifdef __always_inline__read_unlock +#ifdef CONFIG_INLINE_READ_UNLOCK #define _read_unlock(lock) __read_unlock(lock) #endif -#ifdef __always_inline__write_unlock +#ifdef CONFIG_INLINE_WRITE_UNLOCK #define _write_unlock(lock) __write_unlock(lock) #endif -#ifdef __always_inline__spin_unlock_bh +#ifdef CONFIG_INLINE_SPIN_UNLOCK_BH #define _spin_unlock_bh(lock) __spin_unlock_bh(lock) #endif -#ifdef __always_inline__read_unlock_bh +#ifdef CONFIG_INLINE_READ_UNLOCK_BH #define _read_unlock_bh(lock) __read_unlock_bh(lock) #endif -#ifdef __always_inline__write_unlock_bh +#ifdef CONFIG_INLINE_WRITE_UNLOCK_BH #define _write_unlock_bh(lock) __write_unlock_bh(lock) #endif -#ifdef __always_inline__spin_unlock_irq +#ifdef CONFIG_INLINE_SPIN_UNLOCK_IRQ #define _spin_unlock_irq(lock) __spin_unlock_irq(lock) #endif -#ifdef __always_inline__read_unlock_irq +#ifdef CONFIG_INLINE_READ_UNLOCK_IRQ #define _read_unlock_irq(lock) __read_unlock_irq(lock) #endif -#ifdef __always_inline__write_unlock_irq +#ifdef CONFIG_INLINE_WRITE_UNLOCK_IRQ #define _write_unlock_irq(lock) __write_unlock_irq(lock) #endif -#ifdef __always_inline__spin_unlock_irqrestore +#ifdef CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE #define _spin_unlock_irqrestore(lock, flags) __spin_unlock_irqrestore(lock, flags) #endif -#ifdef __always_inline__read_unlock_irqrestore +#ifdef CONFIG_INLINE_READ_UNLOCK_IRQRESTORE #define _read_unlock_irqrestore(lock, flags) __read_unlock_irqrestore(lock, flags) #endif -#ifdef __always_inline__write_unlock_irqrestore +#ifdef CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE #define _write_unlock_irqrestore(lock, flags) __write_unlock_irqrestore(lock, flags) #endif -#endif /* CONFIG_DEBUG_SPINLOCK */ - static inline int __spin_trylock(spinlock_t *lock) { preempt_disable(); diff --git a/init/Kconfig b/init/Kconfig index 9e03ef8b311..06863dd7bf4 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1210,3 +1210,4 @@ source "block/Kconfig" config PREEMPT_NOTIFIERS bool +source "kernel/Kconfig.locks" diff --git a/kernel/Kconfig.locks b/kernel/Kconfig.locks new file mode 100644 index 00000000000..d1f86db7145 --- /dev/null +++ b/kernel/Kconfig.locks @@ -0,0 +1,199 @@ +# +# The ARCH_INLINE foo is necessary because select ignores "depends on" +# +config ARCH_INLINE_SPIN_TRYLOCK + bool + +config ARCH_INLINE_SPIN_TRYLOCK_BH + bool + +config ARCH_INLINE_SPIN_LOCK + bool + +config ARCH_INLINE_SPIN_LOCK_BH + bool + +config ARCH_INLINE_SPIN_LOCK_IRQ + bool + +config ARCH_INLINE_SPIN_LOCK_IRQSAVE + bool + +config ARCH_INLINE_SPIN_UNLOCK + bool + +config ARCH_INLINE_SPIN_UNLOCK_BH + bool + +config ARCH_INLINE_SPIN_UNLOCK_IRQ + bool + +config ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE + bool + + +config ARCH_INLINE_READ_TRYLOCK + bool + +config ARCH_INLINE_READ_LOCK + bool + +config ARCH_INLINE_READ_LOCK_BH + bool + +config ARCH_INLINE_READ_LOCK_IRQ + bool + +config ARCH_INLINE_READ_LOCK_IRQSAVE + bool + +config ARCH_INLINE_READ_UNLOCK + bool + +config ARCH_INLINE_READ_UNLOCK_BH + bool + +config ARCH_INLINE_READ_UNLOCK_IRQ + bool + +config ARCH_INLINE_READ_UNLOCK_IRQRESTORE + bool + + +config ARCH_INLINE_WRITE_TRYLOCK + bool + +config ARCH_INLINE_WRITE_LOCK + bool + +config ARCH_INLINE_WRITE_LOCK_BH + bool + +config ARCH_INLINE_WRITE_LOCK_IRQ + bool + +config ARCH_INLINE_WRITE_LOCK_IRQSAVE + bool + +config ARCH_INLINE_WRITE_UNLOCK + bool + +config ARCH_INLINE_WRITE_UNLOCK_BH + bool + +config ARCH_INLINE_WRITE_UNLOCK_IRQ + bool + +config ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE + bool + +# +# lock_* functions are inlined when: +# - DEBUG_SPINLOCK=n and GENERIC_LOCKBREAK=n and ARCH_INLINE_*LOCK=y +# +# trylock_* functions are inlined when: +# - DEBUG_SPINLOCK=n and ARCH_INLINE_*LOCK=y +# +# unlock and unlock_irq functions are inlined when: +# - DEBUG_SPINLOCK=n and ARCH_INLINE_*LOCK=y +# or +# - DEBUG_SPINLOCK=n and PREEMPT=n +# +# unlock_bh and unlock_irqrestore functions are inlined when: +# - DEBUG_SPINLOCK=n and ARCH_INLINE_*LOCK=y +# + +config INLINE_SPIN_TRYLOCK + def_bool !DEBUG_SPINLOCK && ARCH_INLINE_SPIN_TRYLOCK + +config INLINE_SPIN_TRYLOCK_BH + def_bool !DEBUG_SPINLOCK && ARCH_INLINE_SPIN_TRYLOCK_BH + +config INLINE_SPIN_LOCK + def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && ARCH_INLINE_SPIN_LOCK + +config INLINE_SPIN_LOCK_BH + def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \ + ARCH_INLINE_SPIN_LOCK_BH + +config INLINE_SPIN_LOCK_IRQ + def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \ + ARCH_INLINE_SPIN_LOCK_IRQ + +config INLINE_SPIN_LOCK_IRQSAVE + def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \ + ARCH_INLINE_SPIN_LOCK_IRQSAVE + +config INLINE_SPIN_UNLOCK + def_bool !DEBUG_SPINLOCK && (!PREEMPT || ARCH_INLINE_SPIN_UNLOCK) + +config INLINE_SPIN_UNLOCK_BH + def_bool !DEBUG_SPINLOCK && ARCH_INLINE_SPIN_UNLOCK_BH + +config INLINE_SPIN_UNLOCK_IRQ + def_bool !DEBUG_SPINLOCK && (!PREEMPT || ARCH_INLINE_SPIN_UNLOCK_BH) + +config INLINE_SPIN_UNLOCK_IRQRESTORE + def_bool !DEBUG_SPINLOCK && ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE + + +config INLINE_READ_TRYLOCK + def_bool !DEBUG_SPINLOCK && ARCH_INLINE_READ_TRYLOCK + +config INLINE_READ_LOCK + def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && ARCH_INLINE_READ_LOCK + +config INLINE_READ_LOCK_BH + def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \ + ARCH_INLINE_READ_LOCK_BH + +config INLINE_READ_LOCK_IRQ + def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \ + ARCH_INLINE_READ_LOCK_IRQ + +config INLINE_READ_LOCK_IRQSAVE + def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \ + ARCH_INLINE_READ_LOCK_IRQSAVE + +config INLINE_READ_UNLOCK + def_bool !DEBUG_SPINLOCK && (!PREEMPT || ARCH_INLINE_READ_UNLOCK) + +config INLINE_READ_UNLOCK_BH + def_bool !DEBUG_SPINLOCK && ARCH_INLINE_READ_UNLOCK_BH + +config INLINE_READ_UNLOCK_IRQ + def_bool !DEBUG_SPINLOCK && (!PREEMPT || ARCH_INLINE_READ_UNLOCK_BH) + +config INLINE_READ_UNLOCK_IRQRESTORE + def_bool !DEBUG_SPINLOCK && ARCH_INLINE_READ_UNLOCK_IRQRESTORE + + +config INLINE_WRITE_TRYLOCK + def_bool !DEBUG_SPINLOCK && ARCH_INLINE_WRITE_TRYLOCK + +config INLINE_WRITE_LOCK + def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && ARCH_INLINE_WRITE_LOCK + +config INLINE_WRITE_LOCK_BH + def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \ + ARCH_INLINE_WRITE_LOCK_BH + +config INLINE_WRITE_LOCK_IRQ + def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \ + ARCH_INLINE_WRITE_LOCK_IRQ + +config INLINE_WRITE_LOCK_IRQSAVE + def_bool !DEBUG_SPINLOCK && !GENERIC_LOCKBREAK && \ + ARCH_INLINE_WRITE_LOCK_IRQSAVE + +config INLINE_WRITE_UNLOCK + def_bool !DEBUG_SPINLOCK && (!PREEMPT || ARCH_INLINE_WRITE_UNLOCK) + +config INLINE_WRITE_UNLOCK_BH + def_bool !DEBUG_SPINLOCK && ARCH_INLINE_WRITE_UNLOCK_BH + +config INLINE_WRITE_UNLOCK_IRQ + def_bool !DEBUG_SPINLOCK && (!PREEMPT || ARCH_INLINE_WRITE_UNLOCK_BH) + +config INLINE_WRITE_UNLOCK_IRQRESTORE + def_bool !DEBUG_SPINLOCK && ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE diff --git a/kernel/spinlock.c b/kernel/spinlock.c index 5ddab730cb2..235a9579a87 100644 --- a/kernel/spinlock.c +++ b/kernel/spinlock.c @@ -21,7 +21,7 @@ #include #include -#ifndef _spin_trylock +#ifndef CONFIG_INLINE_SPIN_TRYLOCK int __lockfunc _spin_trylock(spinlock_t *lock) { return __spin_trylock(lock); @@ -29,7 +29,7 @@ int __lockfunc _spin_trylock(spinlock_t *lock) EXPORT_SYMBOL(_spin_trylock); #endif -#ifndef _read_trylock +#ifndef CONFIG_INLINE_READ_TRYLOCK int __lockfunc _read_trylock(rwlock_t *lock) { return __read_trylock(lock); @@ -37,7 +37,7 @@ int __lockfunc _read_trylock(rwlock_t *lock) EXPORT_SYMBOL(_read_trylock); #endif -#ifndef _write_trylock +#ifndef CONFIG_INLINE_WRITE_TRYLOCK int __lockfunc _write_trylock(rwlock_t *lock) { return __write_trylock(lock); @@ -52,7 +52,7 @@ EXPORT_SYMBOL(_write_trylock); */ #if !defined(CONFIG_GENERIC_LOCKBREAK) || defined(CONFIG_DEBUG_LOCK_ALLOC) -#ifndef _read_lock +#ifndef CONFIG_INLINE_READ_LOCK void __lockfunc _read_lock(rwlock_t *lock) { __read_lock(lock); @@ -60,7 +60,7 @@ void __lockfunc _read_lock(rwlock_t *lock) EXPORT_SYMBOL(_read_lock); #endif -#ifndef _spin_lock_irqsave +#ifndef CONFIG_INLINE_SPIN_LOCK_IRQSAVE unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) { return __spin_lock_irqsave(lock); @@ -68,7 +68,7 @@ unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) EXPORT_SYMBOL(_spin_lock_irqsave); #endif -#ifndef _spin_lock_irq +#ifndef CONFIG_INLINE_SPIN_LOCK_IRQ void __lockfunc _spin_lock_irq(spinlock_t *lock) { __spin_lock_irq(lock); @@ -76,7 +76,7 @@ void __lockfunc _spin_lock_irq(spinlock_t *lock) EXPORT_SYMBOL(_spin_lock_irq); #endif -#ifndef _spin_lock_bh +#ifndef CONFIG_INLINE_SPIN_LOCK_BH void __lockfunc _spin_lock_bh(spinlock_t *lock) { __spin_lock_bh(lock); @@ -84,7 +84,7 @@ void __lockfunc _spin_lock_bh(spinlock_t *lock) EXPORT_SYMBOL(_spin_lock_bh); #endif -#ifndef _read_lock_irqsave +#ifndef CONFIG_INLINE_READ_LOCK_IRQSAVE unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock) { return __read_lock_irqsave(lock); @@ -92,7 +92,7 @@ unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock) EXPORT_SYMBOL(_read_lock_irqsave); #endif -#ifndef _read_lock_irq +#ifndef CONFIG_INLINE_READ_LOCK_IRQ void __lockfunc _read_lock_irq(rwlock_t *lock) { __read_lock_irq(lock); @@ -100,7 +100,7 @@ void __lockfunc _read_lock_irq(rwlock_t *lock) EXPORT_SYMBOL(_read_lock_irq); #endif -#ifndef _read_lock_bh +#ifndef CONFIG_INLINE_READ_LOCK_BH void __lockfunc _read_lock_bh(rwlock_t *lock) { __read_lock_bh(lock); @@ -108,7 +108,7 @@ void __lockfunc _read_lock_bh(rwlock_t *lock) EXPORT_SYMBOL(_read_lock_bh); #endif -#ifndef _write_lock_irqsave +#ifndef CONFIG_INLINE_WRITE_LOCK_IRQSAVE unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock) { return __write_lock_irqsave(lock); @@ -116,7 +116,7 @@ unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock) EXPORT_SYMBOL(_write_lock_irqsave); #endif -#ifndef _write_lock_irq +#ifndef CONFIG_INLINE_WRITE_LOCK_IRQ void __lockfunc _write_lock_irq(rwlock_t *lock) { __write_lock_irq(lock); @@ -124,7 +124,7 @@ void __lockfunc _write_lock_irq(rwlock_t *lock) EXPORT_SYMBOL(_write_lock_irq); #endif -#ifndef _write_lock_bh +#ifndef CONFIG_INLINE_WRITE_LOCK_BH void __lockfunc _write_lock_bh(rwlock_t *lock) { __write_lock_bh(lock); @@ -132,7 +132,7 @@ void __lockfunc _write_lock_bh(rwlock_t *lock) EXPORT_SYMBOL(_write_lock_bh); #endif -#ifndef _spin_lock +#ifndef CONFIG_INLINE_SPIN_LOCK void __lockfunc _spin_lock(spinlock_t *lock) { __spin_lock(lock); @@ -140,7 +140,7 @@ void __lockfunc _spin_lock(spinlock_t *lock) EXPORT_SYMBOL(_spin_lock); #endif -#ifndef _write_lock +#ifndef CONFIG_INLINE_WRITE_LOCK void __lockfunc _write_lock(rwlock_t *lock) { __write_lock(lock); @@ -272,7 +272,7 @@ EXPORT_SYMBOL(_spin_lock_nest_lock); #endif -#ifndef _spin_unlock +#ifndef CONFIG_INLINE_SPIN_UNLOCK void __lockfunc _spin_unlock(spinlock_t *lock) { __spin_unlock(lock); @@ -280,7 +280,7 @@ void __lockfunc _spin_unlock(spinlock_t *lock) EXPORT_SYMBOL(_spin_unlock); #endif -#ifndef _write_unlock +#ifndef CONFIG_INLINE_WRITE_UNLOCK void __lockfunc _write_unlock(rwlock_t *lock) { __write_unlock(lock); @@ -288,7 +288,7 @@ void __lockfunc _write_unlock(rwlock_t *lock) EXPORT_SYMBOL(_write_unlock); #endif -#ifndef _read_unlock +#ifndef CONFIG_INLINE_READ_UNLOCK void __lockfunc _read_unlock(rwlock_t *lock) { __read_unlock(lock); @@ -296,7 +296,7 @@ void __lockfunc _read_unlock(rwlock_t *lock) EXPORT_SYMBOL(_read_unlock); #endif -#ifndef _spin_unlock_irqrestore +#ifndef CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) { __spin_unlock_irqrestore(lock, flags); @@ -304,7 +304,7 @@ void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) EXPORT_SYMBOL(_spin_unlock_irqrestore); #endif -#ifndef _spin_unlock_irq +#ifndef CONFIG_INLINE_SPIN_UNLOCK_IRQ void __lockfunc _spin_unlock_irq(spinlock_t *lock) { __spin_unlock_irq(lock); @@ -312,7 +312,7 @@ void __lockfunc _spin_unlock_irq(spinlock_t *lock) EXPORT_SYMBOL(_spin_unlock_irq); #endif -#ifndef _spin_unlock_bh +#ifndef CONFIG_INLINE_SPIN_UNLOCK_BH void __lockfunc _spin_unlock_bh(spinlock_t *lock) { __spin_unlock_bh(lock); @@ -320,7 +320,7 @@ void __lockfunc _spin_unlock_bh(spinlock_t *lock) EXPORT_SYMBOL(_spin_unlock_bh); #endif -#ifndef _read_unlock_irqrestore +#ifndef CONFIG_INLINE_READ_UNLOCK_IRQRESTORE void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) { __read_unlock_irqrestore(lock, flags); @@ -328,7 +328,7 @@ void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) EXPORT_SYMBOL(_read_unlock_irqrestore); #endif -#ifndef _read_unlock_irq +#ifndef CONFIG_INLINE_READ_UNLOCK_IRQ void __lockfunc _read_unlock_irq(rwlock_t *lock) { __read_unlock_irq(lock); @@ -336,7 +336,7 @@ void __lockfunc _read_unlock_irq(rwlock_t *lock) EXPORT_SYMBOL(_read_unlock_irq); #endif -#ifndef _read_unlock_bh +#ifndef CONFIG_INLINE_READ_UNLOCK_BH void __lockfunc _read_unlock_bh(rwlock_t *lock) { __read_unlock_bh(lock); @@ -344,7 +344,7 @@ void __lockfunc _read_unlock_bh(rwlock_t *lock) EXPORT_SYMBOL(_read_unlock_bh); #endif -#ifndef _write_unlock_irqrestore +#ifndef CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) { __write_unlock_irqrestore(lock, flags); @@ -352,7 +352,7 @@ void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) EXPORT_SYMBOL(_write_unlock_irqrestore); #endif -#ifndef _write_unlock_irq +#ifndef CONFIG_INLINE_WRITE_UNLOCK_IRQ void __lockfunc _write_unlock_irq(rwlock_t *lock) { __write_unlock_irq(lock); @@ -360,7 +360,7 @@ void __lockfunc _write_unlock_irq(rwlock_t *lock) EXPORT_SYMBOL(_write_unlock_irq); #endif -#ifndef _write_unlock_bh +#ifndef CONFIG_INLINE_WRITE_UNLOCK_BH void __lockfunc _write_unlock_bh(rwlock_t *lock) { __write_unlock_bh(lock); @@ -368,7 +368,7 @@ void __lockfunc _write_unlock_bh(rwlock_t *lock) EXPORT_SYMBOL(_write_unlock_bh); #endif -#ifndef _spin_trylock_bh +#ifndef CONFIG_INLINE_SPIN_TRYLOCK_BH int __lockfunc _spin_trylock_bh(spinlock_t *lock) { return __spin_trylock_bh(lock); From 8e13c7b772387f55dc05c6a0e5b30010c3c46ff9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 9 Nov 2009 15:21:41 +0000 Subject: [PATCH 147/298] locking: Reduce ifdefs in kernel/spinlock.c With the Kconfig based inline decisions we can remove extra ifdefs in kernel/spinlock.c by creating the complex lockbreak functions as inlines which are inserted into the non inlined lock functions. No functional change. Signed-off-by: Thomas Gleixner LKML-Reference: <20091109151428.548614772@linutronix.de> Acked-by: Heiko Carstens Reviewed-by: Ingo Molnar Acked-by: Peter Zijlstra --- kernel/spinlock.c | 258 +++++++++++++++++++++++----------------------- 1 file changed, 127 insertions(+), 131 deletions(-) diff --git a/kernel/spinlock.c b/kernel/spinlock.c index 235a9579a87..41e042219ff 100644 --- a/kernel/spinlock.c +++ b/kernel/spinlock.c @@ -21,6 +21,133 @@ #include #include +/* + * If lockdep is enabled then we use the non-preemption spin-ops + * even on CONFIG_PREEMPT, because lockdep assumes that interrupts are + * not re-enabled during lock-acquire (which the preempt-spin-ops do): + */ +#if !defined(CONFIG_GENERIC_LOCKBREAK) || defined(CONFIG_DEBUG_LOCK_ALLOC) +/* + * The __lock_function inlines are taken from + * include/linux/spinlock_api_smp.h + */ +#else +/* + * We build the __lock_function inlines here. They are too large for + * inlining all over the place, but here is only one user per function + * which embedds them into the calling _lock_function below. + * + * This could be a long-held lock. We both prepare to spin for a long + * time (making _this_ CPU preemptable if possible), and we also signal + * towards that other CPU that it should break the lock ASAP. + */ +#define BUILD_LOCK_OPS(op, locktype) \ +void __lockfunc __##op##_lock(locktype##_t *lock) \ +{ \ + for (;;) { \ + preempt_disable(); \ + if (likely(_raw_##op##_trylock(lock))) \ + break; \ + preempt_enable(); \ + \ + if (!(lock)->break_lock) \ + (lock)->break_lock = 1; \ + while (!op##_can_lock(lock) && (lock)->break_lock) \ + _raw_##op##_relax(&lock->raw_lock); \ + } \ + (lock)->break_lock = 0; \ +} \ + \ +unsigned long __lockfunc __##op##_lock_irqsave(locktype##_t *lock) \ +{ \ + unsigned long flags; \ + \ + for (;;) { \ + preempt_disable(); \ + local_irq_save(flags); \ + if (likely(_raw_##op##_trylock(lock))) \ + break; \ + local_irq_restore(flags); \ + preempt_enable(); \ + \ + if (!(lock)->break_lock) \ + (lock)->break_lock = 1; \ + while (!op##_can_lock(lock) && (lock)->break_lock) \ + _raw_##op##_relax(&lock->raw_lock); \ + } \ + (lock)->break_lock = 0; \ + return flags; \ +} \ + \ +void __lockfunc __##op##_lock_irq(locktype##_t *lock) \ +{ \ + _##op##_lock_irqsave(lock); \ +} \ + \ +void __lockfunc __##op##_lock_bh(locktype##_t *lock) \ +{ \ + unsigned long flags; \ + \ + /* */ \ + /* Careful: we must exclude softirqs too, hence the */ \ + /* irq-disabling. We use the generic preemption-aware */ \ + /* function: */ \ + /**/ \ + flags = _##op##_lock_irqsave(lock); \ + local_bh_disable(); \ + local_irq_restore(flags); \ +} \ + +/* + * Build preemption-friendly versions of the following + * lock-spinning functions: + * + * __[spin|read|write]_lock() + * __[spin|read|write]_lock_irq() + * __[spin|read|write]_lock_irqsave() + * __[spin|read|write]_lock_bh() + */ +BUILD_LOCK_OPS(spin, spinlock); +BUILD_LOCK_OPS(read, rwlock); +BUILD_LOCK_OPS(write, rwlock); + +#endif + +#ifdef CONFIG_DEBUG_LOCK_ALLOC + +void __lockfunc _spin_lock_nested(spinlock_t *lock, int subclass) +{ + preempt_disable(); + spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_); + LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); +} +EXPORT_SYMBOL(_spin_lock_nested); + +unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock, + int subclass) +{ + unsigned long flags; + + local_irq_save(flags); + preempt_disable(); + spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_); + LOCK_CONTENDED_FLAGS(lock, _raw_spin_trylock, _raw_spin_lock, + _raw_spin_lock_flags, &flags); + return flags; +} +EXPORT_SYMBOL(_spin_lock_irqsave_nested); + +void __lockfunc _spin_lock_nest_lock(spinlock_t *lock, + struct lockdep_map *nest_lock) +{ + preempt_disable(); + spin_acquire_nest(&lock->dep_map, 0, 0, nest_lock, _RET_IP_); + LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); +} +EXPORT_SYMBOL(_spin_lock_nest_lock); + +#endif + #ifndef CONFIG_INLINE_SPIN_TRYLOCK int __lockfunc _spin_trylock(spinlock_t *lock) { @@ -45,13 +172,6 @@ int __lockfunc _write_trylock(rwlock_t *lock) EXPORT_SYMBOL(_write_trylock); #endif -/* - * If lockdep is enabled then we use the non-preemption spin-ops - * even on CONFIG_PREEMPT, because lockdep assumes that interrupts are - * not re-enabled during lock-acquire (which the preempt-spin-ops do): - */ -#if !defined(CONFIG_GENERIC_LOCKBREAK) || defined(CONFIG_DEBUG_LOCK_ALLOC) - #ifndef CONFIG_INLINE_READ_LOCK void __lockfunc _read_lock(rwlock_t *lock) { @@ -148,130 +268,6 @@ void __lockfunc _write_lock(rwlock_t *lock) EXPORT_SYMBOL(_write_lock); #endif -#else /* CONFIG_PREEMPT: */ - -/* - * This could be a long-held lock. We both prepare to spin for a long - * time (making _this_ CPU preemptable if possible), and we also signal - * towards that other CPU that it should break the lock ASAP. - * - * (We do this in a function because inlining it would be excessive.) - */ - -#define BUILD_LOCK_OPS(op, locktype) \ -void __lockfunc _##op##_lock(locktype##_t *lock) \ -{ \ - for (;;) { \ - preempt_disable(); \ - if (likely(_raw_##op##_trylock(lock))) \ - break; \ - preempt_enable(); \ - \ - if (!(lock)->break_lock) \ - (lock)->break_lock = 1; \ - while (!op##_can_lock(lock) && (lock)->break_lock) \ - _raw_##op##_relax(&lock->raw_lock); \ - } \ - (lock)->break_lock = 0; \ -} \ - \ -EXPORT_SYMBOL(_##op##_lock); \ - \ -unsigned long __lockfunc _##op##_lock_irqsave(locktype##_t *lock) \ -{ \ - unsigned long flags; \ - \ - for (;;) { \ - preempt_disable(); \ - local_irq_save(flags); \ - if (likely(_raw_##op##_trylock(lock))) \ - break; \ - local_irq_restore(flags); \ - preempt_enable(); \ - \ - if (!(lock)->break_lock) \ - (lock)->break_lock = 1; \ - while (!op##_can_lock(lock) && (lock)->break_lock) \ - _raw_##op##_relax(&lock->raw_lock); \ - } \ - (lock)->break_lock = 0; \ - return flags; \ -} \ - \ -EXPORT_SYMBOL(_##op##_lock_irqsave); \ - \ -void __lockfunc _##op##_lock_irq(locktype##_t *lock) \ -{ \ - _##op##_lock_irqsave(lock); \ -} \ - \ -EXPORT_SYMBOL(_##op##_lock_irq); \ - \ -void __lockfunc _##op##_lock_bh(locktype##_t *lock) \ -{ \ - unsigned long flags; \ - \ - /* */ \ - /* Careful: we must exclude softirqs too, hence the */ \ - /* irq-disabling. We use the generic preemption-aware */ \ - /* function: */ \ - /**/ \ - flags = _##op##_lock_irqsave(lock); \ - local_bh_disable(); \ - local_irq_restore(flags); \ -} \ - \ -EXPORT_SYMBOL(_##op##_lock_bh) - -/* - * Build preemption-friendly versions of the following - * lock-spinning functions: - * - * _[spin|read|write]_lock() - * _[spin|read|write]_lock_irq() - * _[spin|read|write]_lock_irqsave() - * _[spin|read|write]_lock_bh() - */ -BUILD_LOCK_OPS(spin, spinlock); -BUILD_LOCK_OPS(read, rwlock); -BUILD_LOCK_OPS(write, rwlock); - -#endif /* CONFIG_PREEMPT */ - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - -void __lockfunc _spin_lock_nested(spinlock_t *lock, int subclass) -{ - preempt_disable(); - spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_); - LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); -} -EXPORT_SYMBOL(_spin_lock_nested); - -unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock, int subclass) -{ - unsigned long flags; - - local_irq_save(flags); - preempt_disable(); - spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_); - LOCK_CONTENDED_FLAGS(lock, _raw_spin_trylock, _raw_spin_lock, - _raw_spin_lock_flags, &flags); - return flags; -} -EXPORT_SYMBOL(_spin_lock_irqsave_nested); - -void __lockfunc _spin_lock_nest_lock(spinlock_t *lock, - struct lockdep_map *nest_lock) -{ - preempt_disable(); - spin_acquire_nest(&lock->dep_map, 0, 0, nest_lock, _RET_IP_); - LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); -} -EXPORT_SYMBOL(_spin_lock_nest_lock); - -#endif - #ifndef CONFIG_INLINE_SPIN_UNLOCK void __lockfunc _spin_unlock(spinlock_t *lock) { From 811cb50baf63461ce0bdb234927046131fc7fa8b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 13 Nov 2009 23:40:09 +0100 Subject: [PATCH 148/298] tracing: Fix event format export For some reason the export of the event print format to userspace uses '#fmt' which breaks if the format string is anything but a plain string, for example if it is built with macros then the macro names are exported instead of their contents. Use "\"%s\"", fmt instead of "%s", #fmt to export the string and not the way it is built. For example, in net/mac80211/driver-trace.h for the trace event drv_start there is: TP_printk( LOCAL_PR_FMT, LOCAL_PR_ARG ) Which use to produce: print fmt: LOCAL_PR_FMT, REC->wiphy_name Now produces: print fmt: "%s", REC->wiphy_name Signed-off-by: Johannes Berg LKML-Reference: <20091113224009.GB23942@elte.hu> Signed-off-by: Steven Rostedt --- include/trace/ftrace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index cc0d9667e18..dacb8ef6700 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h @@ -159,7 +159,7 @@ #undef __get_str #undef TP_printk -#define TP_printk(fmt, args...) "%s, %s\n", #fmt, __stringify(args) +#define TP_printk(fmt, args...) "\"%s\", %s\n", fmt, __stringify(args) #undef TP_fast_assign #define TP_fast_assign(args...) args From 560d4bc0df9a5e63b980432282d8c2bd3559ec74 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 13 Nov 2009 19:51:38 -0800 Subject: [PATCH 149/298] rcu: Further cleanups of use of lastcomp Now that a copy of the rsp->completed flag is available in all rcu_node structures, make full use of it. It is still legitimate to access rsp->completed while holding the root rcu_node structure's lock, however. Also, tighten up force_quiescent_state()'s checks for end of current grace period. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <1258170699933-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 3df04381ea3..24bbf2ce060 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -817,7 +817,7 @@ cpu_quiet(int cpu, struct rcu_state *rsp, struct rcu_data *rdp, long lastcomp) rnp = rdp->mynode; spin_lock_irqsave(&rnp->lock, flags); - if (lastcomp != ACCESS_ONCE(rsp->completed)) { + if (lastcomp != rnp->completed) { /* * Someone beat us to it for this grace period, so leave. @@ -935,7 +935,6 @@ static void rcu_adopt_orphan_cbs(struct rcu_state *rsp) static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) { unsigned long flags; - long lastcomp; unsigned long mask; struct rcu_data *rdp = rsp->rda[cpu]; struct rcu_node *rnp; @@ -971,7 +970,6 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) spin_unlock(&rnp->lock); /* irqs remain disabled. */ rnp = rnp->parent; } while (rnp != NULL); - lastcomp = rsp->completed; spin_unlock_irqrestore(&rsp->onofflock, flags); @@ -1145,7 +1143,7 @@ static int rcu_process_dyntick(struct rcu_state *rsp, long lastcomp, rcu_for_each_leaf_node(rsp, rnp) { mask = 0; spin_lock_irqsave(&rnp->lock, flags); - if (rsp->completed != lastcomp) { + if (rnp->completed != lastcomp) { spin_unlock_irqrestore(&rnp->lock, flags); return 1; } @@ -1159,7 +1157,7 @@ static int rcu_process_dyntick(struct rcu_state *rsp, long lastcomp, if ((rnp->qsmask & bit) != 0 && f(rsp->rda[cpu])) mask |= bit; } - if (mask != 0 && rsp->completed == lastcomp) { + if (mask != 0 && rnp->completed == lastcomp) { /* cpu_quiet_msk() releases rnp->lock. */ cpu_quiet_msk(mask, rsp, rnp, flags); @@ -1196,7 +1194,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) lastcomp = rsp->gpnum - 1; signaled = rsp->signaled; rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS; - if (lastcomp == rsp->gpnum) { + if(!rcu_gp_in_progress(rsp)) { rsp->n_force_qs_ngp++; spin_unlock(&rnp->lock); goto unlock_ret; /* no GP in progress, time updated. */ @@ -1224,7 +1222,8 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) /* Update state, record completion counter. */ forcenow = 0; spin_lock(&rnp->lock); - if (lastcomp == rsp->completed && + if (lastcomp + 1 == rsp->gpnum && + lastcomp == rsp->completed && rsp->signaled == signaled) { rsp->signaled = RCU_FORCE_QS; rsp->completed_fqs = lastcomp; From 2f51f9884f6a36b0fe9636d5a1937e5cbd25723b Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 13 Nov 2009 19:51:39 -0800 Subject: [PATCH 150/298] rcu: Eliminate __rcu_pending() false positives Now that there are both ->gpnum and ->completed fields in the rcu_node structure, __rcu_pending() should check rdp->gpnum and rdp->completed against rnp->gpnum and rdp->completed, respectively, instead of the prior comparison against the rcu_state fields rsp->gpnum and rsp->completed. Given the old comparison, __rcu_pending() could return 1, resulting in a needless raise_softirq(RCU_SOFTIRQ). This useless work would happen if RCU responded to a scheduling-clock interrupt after the rcu_state fields had been updated, but before the rcu_node fields had been updated. Changing the comparison from the rcu_state fields to the rcu_node fields prevents this useless work from happening. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12581706991966-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 24bbf2ce060..9b36d6d7fb9 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1403,6 +1403,8 @@ EXPORT_SYMBOL_GPL(call_rcu_bh); */ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp) { + struct rcu_node *rnp = rdp->mynode; + rdp->n_rcu_pending++; /* Check for CPU stalls, if enabled. */ @@ -1427,13 +1429,13 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp) } /* Has another RCU grace period completed? */ - if (ACCESS_ONCE(rsp->completed) != rdp->completed) { /* outside lock */ + if (ACCESS_ONCE(rnp->completed) != rdp->completed) { /* outside lock */ rdp->n_rp_gp_completed++; return 1; } /* Has a new RCU grace period started? */ - if (ACCESS_ONCE(rsp->gpnum) != rdp->gpnum) { /* outside lock */ + if (ACCESS_ONCE(rnp->gpnum) != rdp->gpnum) { /* outside lock */ rdp->n_rp_gp_started++; return 1; } From a3b28ee1090072092e2be043c24df94230e725b2 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Sat, 14 Nov 2009 20:46:36 +0900 Subject: [PATCH 151/298] x86: Set dma_ops to nommu_dma_ops by default We set dma_ops to nommu_dma_ops at two different places for x86_32 and x86_64. This unifies them by setting dma_ops to nommu_dma_ops by default. Signed-off-by: FUJITA Tomonori LKML-Reference: <1258199198-16657-2-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar --- arch/x86/kernel/pci-dma.c | 4 +--- arch/x86/kernel/pci-swiotlb.c | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 0b11bf18f54..f170b5364b4 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -15,7 +15,7 @@ static int forbid_dac __read_mostly; -struct dma_map_ops *dma_ops; +struct dma_map_ops *dma_ops = &nommu_dma_ops; EXPORT_SYMBOL(dma_ops); static int iommu_sac_force __read_mostly; @@ -128,8 +128,6 @@ void __init pci_iommu_alloc(void) #ifdef CONFIG_X86_64 /* free the range so iommu could get some range less than 4G */ dma32_free_bootmem(); -#else - dma_ops = &nommu_dma_ops; #endif if (pci_swiotlb_init()) return; diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c index a6e5d0ffa3a..e36e71daa44 100644 --- a/arch/x86/kernel/pci-swiotlb.c +++ b/arch/x86/kernel/pci-swiotlb.c @@ -61,8 +61,7 @@ int __init pci_swiotlb_init(void) if (swiotlb) { swiotlb_init(0); dma_ops = &swiotlb_dma_ops; - } else - dma_ops = &nommu_dma_ops; + } return swiotlb_force; } From 94a15564ac63af6bb2ff8d4d04f86d5e7ee0278a Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Sat, 14 Nov 2009 20:46:37 +0900 Subject: [PATCH 152/298] x86: Move iommu_shutdown_noop to x86_init.c iommu_init_noop() is in arch/x86/kernel/x86_init.c but iommu_shutdown_noop() in arch/x86/include/asm/iommu.h. This moves iommu_shutdown_noop() to x86_init.c for consistency. Signed-off-by: FUJITA Tomonori LKML-Reference: <1258199198-16657-3-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/iommu.h | 1 - arch/x86/kernel/x86_init.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/include/asm/iommu.h b/arch/x86/include/asm/iommu.h index df42a712361..345c99cef15 100644 --- a/arch/x86/include/asm/iommu.h +++ b/arch/x86/include/asm/iommu.h @@ -1,7 +1,6 @@ #ifndef _ASM_X86_IOMMU_H #define _ASM_X86_IOMMU_H -static inline void iommu_shutdown_noop(void) {} extern struct dma_map_ops nommu_dma_ops; extern int force_iommu, no_iommu; extern int iommu_detected; diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index c46984d122d..80f3ae24b97 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c @@ -20,6 +20,7 @@ void __cpuinit x86_init_noop(void) { } void __init x86_init_uint_noop(unsigned int unused) { } void __init x86_init_pgd_noop(pgd_t *unused) { } int __init iommu_init_noop(void) { return 0; } +void __init iommu_shutdown_noop(void) { } /* * The platform setup functions are preset with the default functions From 6959450e567c1f17d3ce8489099fc56c3721d577 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Sat, 14 Nov 2009 20:46:38 +0900 Subject: [PATCH 153/298] swiotlb: Remove duplicate swiotlb_force extern declarations Signed-off-by: FUJITA Tomonori Cc: tony.luck@intel.com LKML-Reference: <1258199198-16657-4-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar --- arch/ia64/include/asm/swiotlb.h | 2 -- arch/x86/include/asm/swiotlb.h | 4 ---- include/linux/swiotlb.h | 2 ++ 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/ia64/include/asm/swiotlb.h b/arch/ia64/include/asm/swiotlb.h index dcbaea7ce12..f0acde68aae 100644 --- a/arch/ia64/include/asm/swiotlb.h +++ b/arch/ia64/include/asm/swiotlb.h @@ -4,8 +4,6 @@ #include #include -extern int swiotlb_force; - #ifdef CONFIG_SWIOTLB extern int swiotlb; extern void pci_swiotlb_init(void); diff --git a/arch/x86/include/asm/swiotlb.h b/arch/x86/include/asm/swiotlb.h index 940f13a213f..87ffcb12a1b 100644 --- a/arch/x86/include/asm/swiotlb.h +++ b/arch/x86/include/asm/swiotlb.h @@ -3,10 +3,6 @@ #include -/* SWIOTLB interface */ - -extern int swiotlb_force; - #ifdef CONFIG_SWIOTLB extern int swiotlb; extern int pci_swiotlb_init(void); diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index eb9bdb4d485..febedcf67c7 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -7,6 +7,8 @@ struct device; struct dma_attrs; struct scatterlist; +extern int swiotlb_force; + /* * Maximum allowable number of contiguous slabs to map, * must be a power of 2. What is the appropriate value ? From f4131c6259b46bd84dcfcd3bb9ed08e99e2875a4 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Sat, 14 Nov 2009 21:26:50 +0900 Subject: [PATCH 154/298] x86: Make calgary_iommu_init() static This makes calgary_iommu_init() static and moves it to remove the forward declaration. Signed-off-by: FUJITA Tomonori Cc: muli@il.ibm.com LKML-Reference: <20091114212603U.fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar --- arch/x86/kernel/pci-calgary_64.c | 38 +++++++++++++++----------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index 833f491440b..c84ad037f58 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c @@ -1345,7 +1345,24 @@ static void __init get_tce_space_from_tar(void) return; } -int __init calgary_iommu_init(void); +static int __init calgary_iommu_init(void) +{ + int ret; + + /* ok, we're trying to use Calgary - let's roll */ + printk(KERN_INFO "PCI-DMA: Using Calgary IOMMU\n"); + + ret = calgary_init(); + if (ret) { + printk(KERN_ERR "PCI-DMA: Calgary init failed %d, " + "falling back to no_iommu\n", ret); + return ret; + } + + bad_dma_address = 0x0; + + return 0; +} void __init detect_calgary(void) { @@ -1458,25 +1475,6 @@ cleanup: } } -int __init calgary_iommu_init(void) -{ - int ret; - - /* ok, we're trying to use Calgary - let's roll */ - printk(KERN_INFO "PCI-DMA: Using Calgary IOMMU\n"); - - ret = calgary_init(); - if (ret) { - printk(KERN_ERR "PCI-DMA: Calgary init failed %d, " - "falling back to no_iommu\n", ret); - return ret; - } - - bad_dma_address = 0x0; - - return 0; -} - static int __init calgary_parse_options(char *p) { unsigned int bridge; From 62ad33f67003b9a7b6013f0511579b9805e11626 Mon Sep 17 00:00:00 2001 From: Hiroshi Shimamoto Date: Mon, 16 Nov 2009 11:44:30 +0900 Subject: [PATCH 155/298] x86: Don't put iommu_shutdown_noop() in init section It causes kernel panic on shutdown or reboot. Signed-off-by: Hiroshi Shimamoto Acked-by: FUJITA Tomonori LKML-Reference: <4B00BC8E.50801@ct.jp.nec.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/x86_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index 80f3ae24b97..d11c5ff7c65 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c @@ -20,7 +20,7 @@ void __cpuinit x86_init_noop(void) { } void __init x86_init_uint_noop(unsigned int unused) { } void __init x86_init_pgd_noop(pgd_t *unused) { } int __init iommu_init_noop(void) { return 0; } -void __init iommu_shutdown_noop(void) { } +void iommu_shutdown_noop(void) { } /* * The platform setup functions are preset with the default functions From 42109197eb7c01080eea6d9cd48ca23cbc3c566c Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Sun, 15 Nov 2009 21:19:52 +0900 Subject: [PATCH 156/298] x86: gart: Add own dma_mapping_error function GART IOMMU is the only user of bad_dma_address variable. This patch converts GART to use the newer mechanism, fill in ->mapping_error() in struct dma_map_ops, to make dma_mapping_error() work in IOMMU specific way. Signed-off-by: FUJITA Tomonori Acked-by: Jesse Barnes Cc: muli@il.ibm.com Cc: joerg.roedel@amd.com LKML-Reference: <1258287594-8777-2-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar --- arch/x86/kernel/pci-gart_64.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index 919182e15d1..61c4d1e41a6 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c @@ -47,6 +47,8 @@ static unsigned long iommu_pages; /* .. and in pages */ static u32 *iommu_gatt_base; /* Remapping table */ +static dma_addr_t bad_dma_addr; + /* * If this is disabled the IOMMU will use an optimized flushing strategy * of only flushing when an mapping is reused. With it true the GART is @@ -217,7 +219,7 @@ static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem, if (panic_on_overflow) panic("dma_map_area overflow %lu bytes\n", size); iommu_full(dev, size, dir); - return bad_dma_address; + return bad_dma_addr; } for (i = 0; i < npages; i++) { @@ -303,7 +305,7 @@ static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg, if (nonforced_iommu(dev, addr, s->length)) { addr = dma_map_area(dev, addr, s->length, dir, 0); - if (addr == bad_dma_address) { + if (addr == bad_dma_addr) { if (i > 0) gart_unmap_sg(dev, sg, i, dir, NULL); nents = 0; @@ -456,7 +458,7 @@ error: iommu_full(dev, pages << PAGE_SHIFT, dir); for_each_sg(sg, s, nents, i) - s->dma_address = bad_dma_address; + s->dma_address = bad_dma_addr; return 0; } @@ -480,7 +482,7 @@ gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr, DMA_BIDIRECTIONAL, align_mask); flush_gart(); - if (paddr != bad_dma_address) { + if (paddr != bad_dma_addr) { *dma_addr = paddr; return page_address(page); } @@ -500,6 +502,11 @@ gart_free_coherent(struct device *dev, size_t size, void *vaddr, free_pages((unsigned long)vaddr, get_order(size)); } +static int gart_mapping_error(struct device *dev, dma_addr_t dma_addr) +{ + return (dma_addr == bad_dma_addr); +} + static int no_agp; static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size) @@ -687,6 +694,7 @@ static struct dma_map_ops gart_dma_ops = { .unmap_page = gart_unmap_page, .alloc_coherent = gart_alloc_coherent, .free_coherent = gart_free_coherent, + .mapping_error = gart_mapping_error, }; static void gart_iommu_shutdown(void) @@ -785,7 +793,7 @@ int __init gart_iommu_init(void) iommu_start = aper_size - iommu_size; iommu_bus_base = info.aper_base + iommu_start; - bad_dma_address = iommu_bus_base; + bad_dma_addr = iommu_bus_base; iommu_gatt_base = agp_gatt_table + (iommu_start>>PAGE_SHIFT); /* From 8fd524b355daef0945692227e726fb444cebcd4f Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Sun, 15 Nov 2009 21:19:53 +0900 Subject: [PATCH 157/298] x86: Kill bad_dma_address variable This kills bad_dma_address variable, the old mechanism to enable IOMMU drivers to make dma_mapping_error() work in IOMMU's specific way. bad_dma_address variable was introduced to enable IOMMU drivers to make dma_mapping_error() work in IOMMU's specific way. However, it can't handle systems that use both swiotlb and HW IOMMU. SO we introduced dma_map_ops->mapping_error to solve that case. Intel VT-d, GART, and swiotlb already use dma_map_ops->mapping_error. Calgary, AMD IOMMU, and nommu use zero for an error dma address. This adds DMA_ERROR_CODE and converts them to use it (as SPARC and POWER does). Signed-off-by: FUJITA Tomonori Acked-by: Jesse Barnes Cc: muli@il.ibm.com Cc: joerg.roedel@amd.com LKML-Reference: <1258287594-8777-3-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/dma-mapping.h | 5 +++-- arch/x86/kernel/amd_iommu.c | 21 ++++++++++----------- arch/x86/kernel/pci-calgary_64.c | 22 ++++++++++------------ arch/x86/kernel/pci-dma.c | 3 --- arch/x86/kernel/pci-nommu.c | 2 +- 5 files changed, 24 insertions(+), 29 deletions(-) diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index 6a25d5d4283..0f6c02f3b7d 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -20,7 +20,8 @@ # define ISA_DMA_BIT_MASK DMA_BIT_MASK(32) #endif -extern dma_addr_t bad_dma_address; +#define DMA_ERROR_CODE 0 + extern int iommu_merge; extern struct device x86_dma_fallback_dev; extern int panic_on_overflow; @@ -48,7 +49,7 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) if (ops->mapping_error) return ops->mapping_error(dev, dma_addr); - return (dma_addr == bad_dma_address); + return (dma_addr == DMA_ERROR_CODE); } #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 66237fde758..093bd526c94 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -928,7 +928,7 @@ static unsigned long dma_ops_alloc_addresses(struct device *dev, } if (unlikely(address == -1)) - address = bad_dma_address; + address = DMA_ERROR_CODE; WARN_ON((address + (PAGE_SIZE*pages)) > dom->aperture_size); @@ -1544,7 +1544,7 @@ static dma_addr_t dma_ops_domain_map(struct amd_iommu *iommu, pte = dma_ops_get_pte(dom, address); if (!pte) - return bad_dma_address; + return DMA_ERROR_CODE; __pte = paddr | IOMMU_PTE_P | IOMMU_PTE_FC; @@ -1625,7 +1625,7 @@ static dma_addr_t __map_single(struct device *dev, retry: address = dma_ops_alloc_addresses(dev, dma_dom, pages, align_mask, dma_mask); - if (unlikely(address == bad_dma_address)) { + if (unlikely(address == DMA_ERROR_CODE)) { /* * setting next_address here will let the address * allocator only scan the new allocated range in the @@ -1646,7 +1646,7 @@ retry: start = address; for (i = 0; i < pages; ++i) { ret = dma_ops_domain_map(iommu, dma_dom, start, paddr, dir); - if (ret == bad_dma_address) + if (ret == DMA_ERROR_CODE) goto out_unmap; paddr += PAGE_SIZE; @@ -1674,7 +1674,7 @@ out_unmap: dma_ops_free_addresses(dma_dom, address, pages); - return bad_dma_address; + return DMA_ERROR_CODE; } /* @@ -1690,7 +1690,7 @@ static void __unmap_single(struct amd_iommu *iommu, dma_addr_t i, start; unsigned int pages; - if ((dma_addr == bad_dma_address) || + if ((dma_addr == DMA_ERROR_CODE) || (dma_addr + size > dma_dom->aperture_size)) return; @@ -1732,7 +1732,7 @@ static dma_addr_t map_page(struct device *dev, struct page *page, INC_STATS_COUNTER(cnt_map_single); if (!check_device(dev)) - return bad_dma_address; + return DMA_ERROR_CODE; dma_mask = *dev->dma_mask; @@ -1743,12 +1743,12 @@ static dma_addr_t map_page(struct device *dev, struct page *page, return (dma_addr_t)paddr; if (!dma_ops_domain(domain)) - return bad_dma_address; + return DMA_ERROR_CODE; spin_lock_irqsave(&domain->lock, flags); addr = __map_single(dev, iommu, domain->priv, paddr, size, dir, false, dma_mask); - if (addr == bad_dma_address) + if (addr == DMA_ERROR_CODE) goto out; iommu_completion_wait(iommu); @@ -1957,7 +1957,7 @@ static void *alloc_coherent(struct device *dev, size_t size, *dma_addr = __map_single(dev, iommu, domain->priv, paddr, size, DMA_BIDIRECTIONAL, true, dma_mask); - if (*dma_addr == bad_dma_address) { + if (*dma_addr == DMA_ERROR_CODE) { spin_unlock_irqrestore(&domain->lock, flags); goto out_free; } @@ -2110,7 +2110,6 @@ int __init amd_iommu_init_dma_ops(void) prealloc_protection_domains(); iommu_detected = 1; - bad_dma_address = 0; swiotlb = 0; #ifdef CONFIG_GART_IOMMU gart_iommu_aperture_disabled = 1; diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index c84ad037f58..af9f436096a 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c @@ -245,7 +245,7 @@ static unsigned long iommu_range_alloc(struct device *dev, if (panic_on_overflow) panic("Calgary: fix the allocator.\n"); else - return bad_dma_address; + return DMA_ERROR_CODE; } } @@ -261,11 +261,11 @@ static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl, void *vaddr, unsigned int npages, int direction) { unsigned long entry; - dma_addr_t ret = bad_dma_address; + dma_addr_t ret = DMA_ERROR_CODE; entry = iommu_range_alloc(dev, tbl, npages); - if (unlikely(entry == bad_dma_address)) + if (unlikely(entry == DMA_ERROR_CODE)) goto error; /* set the return dma address */ @@ -280,7 +280,7 @@ static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl, error: printk(KERN_WARNING "Calgary: failed to allocate %u pages in " "iommu %p\n", npages, tbl); - return bad_dma_address; + return DMA_ERROR_CODE; } static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, @@ -291,8 +291,8 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, unsigned long flags; /* were we called with bad_dma_address? */ - badend = bad_dma_address + (EMERGENCY_PAGES * PAGE_SIZE); - if (unlikely((dma_addr >= bad_dma_address) && (dma_addr < badend))) { + badend = DMA_ERROR_CODE + (EMERGENCY_PAGES * PAGE_SIZE); + if (unlikely((dma_addr >= DMA_ERROR_CODE) && (dma_addr < badend))) { WARN(1, KERN_ERR "Calgary: driver tried unmapping bad DMA " "address 0x%Lx\n", dma_addr); return; @@ -374,7 +374,7 @@ static int calgary_map_sg(struct device *dev, struct scatterlist *sg, npages = iommu_num_pages(vaddr, s->length, PAGE_SIZE); entry = iommu_range_alloc(dev, tbl, npages); - if (entry == bad_dma_address) { + if (entry == DMA_ERROR_CODE) { /* makes sure unmap knows to stop */ s->dma_length = 0; goto error; @@ -392,7 +392,7 @@ static int calgary_map_sg(struct device *dev, struct scatterlist *sg, error: calgary_unmap_sg(dev, sg, nelems, dir, NULL); for_each_sg(sg, s, nelems, i) { - sg->dma_address = bad_dma_address; + sg->dma_address = DMA_ERROR_CODE; sg->dma_length = 0; } return 0; @@ -447,7 +447,7 @@ static void* calgary_alloc_coherent(struct device *dev, size_t size, /* set up tces to cover the allocated range */ mapping = iommu_alloc(dev, tbl, ret, npages, DMA_BIDIRECTIONAL); - if (mapping == bad_dma_address) + if (mapping == DMA_ERROR_CODE) goto free; *dma_handle = mapping; return ret; @@ -728,7 +728,7 @@ static void __init calgary_reserve_regions(struct pci_dev *dev) struct iommu_table *tbl = pci_iommu(dev->bus); /* reserve EMERGENCY_PAGES from bad_dma_address and up */ - iommu_range_reserve(tbl, bad_dma_address, EMERGENCY_PAGES); + iommu_range_reserve(tbl, DMA_ERROR_CODE, EMERGENCY_PAGES); /* avoid the BIOS/VGA first 640KB-1MB region */ /* for CalIOC2 - avoid the entire first MB */ @@ -1359,8 +1359,6 @@ static int __init calgary_iommu_init(void) return ret; } - bad_dma_address = 0x0; - return 0; } diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index bf621b9ee26..afcc58b69c7 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -43,9 +43,6 @@ int iommu_detected __read_mostly = 0; */ int iommu_pass_through __read_mostly; -dma_addr_t bad_dma_address __read_mostly = 0; -EXPORT_SYMBOL(bad_dma_address); - /* Dummy device used for NULL arguments (normally ISA). */ struct device x86_dma_fallback_dev = { .init_name = "fallback device", diff --git a/arch/x86/kernel/pci-nommu.c b/arch/x86/kernel/pci-nommu.c index 875e3822ae6..22be12b60a8 100644 --- a/arch/x86/kernel/pci-nommu.c +++ b/arch/x86/kernel/pci-nommu.c @@ -33,7 +33,7 @@ static dma_addr_t nommu_map_page(struct device *dev, struct page *page, dma_addr_t bus = page_to_phys(page) + offset; WARN_ON(size == 0); if (!check_addr("map_single", dev, bus, size)) - return bad_dma_address; + return DMA_ERROR_CODE; flush_write_buffers(); return bus; } From 1f7564ca831a00b21bb493ef174c845b2ba9e64d Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Sun, 15 Nov 2009 21:19:54 +0900 Subject: [PATCH 158/298] x86: Calgary: Remove unnecessary DMA_ERROR_CODE usage This cleans up iommu_alloc() a bit and removes unnecessary DMA_ERROR_CODE usage. Signed-off-by: FUJITA Tomonori Acked-by: Jesse Barnes Cc: muli@il.ibm.com Cc: joerg.roedel@amd.com LKML-Reference: <1258287594-8777-4-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar --- arch/x86/kernel/pci-calgary_64.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index af9f436096a..849a0995d97 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c @@ -261,12 +261,15 @@ static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl, void *vaddr, unsigned int npages, int direction) { unsigned long entry; - dma_addr_t ret = DMA_ERROR_CODE; + dma_addr_t ret; entry = iommu_range_alloc(dev, tbl, npages); - if (unlikely(entry == DMA_ERROR_CODE)) - goto error; + if (unlikely(entry == DMA_ERROR_CODE)) { + printk(KERN_WARNING "Calgary: failed to allocate %u pages in " + "iommu %p\n", npages, tbl); + return DMA_ERROR_CODE; + } /* set the return dma address */ ret = (entry << PAGE_SHIFT) | ((unsigned long)vaddr & ~PAGE_MASK); @@ -274,13 +277,7 @@ static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl, /* put the TCEs in the HW table */ tce_build(tbl, entry, npages, (unsigned long)vaddr & PAGE_MASK, direction); - return ret; - -error: - printk(KERN_WARNING "Calgary: failed to allocate %u pages in " - "iommu %p\n", npages, tbl); - return DMA_ERROR_CODE; } static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, From 123bf0e2eddcda36a33bdfc87aa1fb07229f07b5 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 15 Nov 2009 21:19:52 +0900 Subject: [PATCH 159/298] x86: gart: Clean up the code a bit Clean up various small stylistic details in the GART code. No functionality changed. Cc: FUJITA Tomonori Cc: Jesse Barnes Cc: muli@il.ibm.com Cc: joerg.roedel@amd.com LKML-Reference: <1258287594-8777-2-git-send-email-fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar --- arch/x86/kernel/pci-gart_64.c | 122 ++++++++++++++++++---------------- 1 file changed, 64 insertions(+), 58 deletions(-) diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index 61c4d1e41a6..e6a0d402f17 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c @@ -95,7 +95,7 @@ static unsigned long alloc_iommu(struct device *dev, int size, base_index = ALIGN(iommu_bus_base & dma_get_seg_boundary(dev), PAGE_SIZE) >> PAGE_SHIFT; - boundary_size = ALIGN((unsigned long long)dma_get_seg_boundary(dev) + 1, + boundary_size = ALIGN((u64)dma_get_seg_boundary(dev) + 1, PAGE_SIZE) >> PAGE_SHIFT; spin_lock_irqsave(&iommu_bitmap_lock, flags); @@ -297,7 +297,7 @@ static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg, int i; #ifdef CONFIG_IOMMU_DEBUG - printk(KERN_DEBUG "dma_map_sg overflow\n"); + pr_debug("dma_map_sg overflow\n"); #endif for_each_sg(sg, s, nents, i) { @@ -392,12 +392,14 @@ static int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, if (!dev) dev = &x86_dma_fallback_dev; - out = 0; - start = 0; - start_sg = sgmap = sg; - seg_size = 0; - max_seg_size = dma_get_max_seg_size(dev); - ps = NULL; /* shut up gcc */ + out = 0; + start = 0; + start_sg = sg; + sgmap = sg; + seg_size = 0; + max_seg_size = dma_get_max_seg_size(dev); + ps = NULL; /* shut up gcc */ + for_each_sg(sg, s, nents, i) { dma_addr_t addr = sg_phys(s); @@ -420,11 +422,12 @@ static int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, sgmap, pages, need) < 0) goto error; out++; - seg_size = 0; - sgmap = sg_next(sgmap); - pages = 0; - start = i; - start_sg = s; + + seg_size = 0; + sgmap = sg_next(sgmap); + pages = 0; + start = i; + start_sg = s; } } @@ -523,7 +526,7 @@ static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size) iommu_size -= round_up(a, PMD_PAGE_SIZE) - a; if (iommu_size < 64*1024*1024) { - printk(KERN_WARNING + pr_warning( "PCI-DMA: Warning: Small IOMMU %luMB." " Consider increasing the AGP aperture in BIOS\n", iommu_size >> 20); @@ -578,28 +581,32 @@ void set_up_gart_resume(u32 aper_order, u32 aper_alloc) aperture_alloc = aper_alloc; } +static void gart_fixup_northbridges(struct sys_device *dev) +{ + int i; + + if (!fix_up_north_bridges) + return; + + pr_info("PCI-DMA: Restoring GART aperture settings\n"); + + for (i = 0; i < num_k8_northbridges; i++) { + struct pci_dev *dev = k8_northbridges[i]; + + /* + * Don't enable translations just yet. That is the next + * step. Restore the pre-suspend aperture settings. + */ + pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, aperture_order << 1); + pci_write_config_dword(dev, AMD64_GARTAPERTUREBASE, aperture_alloc >> 25); + } +} + static int gart_resume(struct sys_device *dev) { - printk(KERN_INFO "PCI-DMA: Resuming GART IOMMU\n"); + pr_info("PCI-DMA: Resuming GART IOMMU\n"); - if (fix_up_north_bridges) { - int i; - - printk(KERN_INFO "PCI-DMA: Restoring GART aperture settings\n"); - - for (i = 0; i < num_k8_northbridges; i++) { - struct pci_dev *dev = k8_northbridges[i]; - - /* - * Don't enable translations just yet. That is the next - * step. Restore the pre-suspend aperture settings. - */ - pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, - aperture_order << 1); - pci_write_config_dword(dev, AMD64_GARTAPERTUREBASE, - aperture_alloc >> 25); - } - } + gart_fixup_northbridges(dev); enable_gart_translations(); @@ -612,15 +619,14 @@ static int gart_suspend(struct sys_device *dev, pm_message_t state) } static struct sysdev_class gart_sysdev_class = { - .name = "gart", - .suspend = gart_suspend, - .resume = gart_resume, + .name = "gart", + .suspend = gart_suspend, + .resume = gart_resume, }; static struct sys_device device_gart = { - .id = 0, - .cls = &gart_sysdev_class, + .cls = &gart_sysdev_class, }; /* @@ -635,7 +641,8 @@ static __init int init_k8_gatt(struct agp_kern_info *info) void *gatt; int i, error; - printk(KERN_INFO "PCI-DMA: Disabling AGP.\n"); + pr_info("PCI-DMA: Disabling AGP.\n"); + aper_size = aper_base = info->aper_size = 0; dev = NULL; for (i = 0; i < num_k8_northbridges; i++) { @@ -653,6 +660,7 @@ static __init int init_k8_gatt(struct agp_kern_info *info) } if (!aper_base) goto nommu; + info->aper_base = aper_base; info->aper_size = aper_size >> 20; @@ -675,14 +683,14 @@ static __init int init_k8_gatt(struct agp_kern_info *info) flush_gart(); - printk(KERN_INFO "PCI-DMA: aperture base @ %x size %u KB\n", + pr_info("PCI-DMA: aperture base @ %x size %u KB\n", aper_base, aper_size>>10); return 0; nommu: /* Should not happen anymore */ - printk(KERN_WARNING "PCI-DMA: More than 4GB of RAM and no IOMMU\n" + pr_warning("PCI-DMA: More than 4GB of RAM and no IOMMU\n" "falling back to iommu=soft.\n"); return -1; } @@ -744,23 +752,23 @@ int __init gart_iommu_init(void) !gart_iommu_aperture || (no_agp && init_k8_gatt(&info) < 0)) { if (max_pfn > MAX_DMA32_PFN) { - printk(KERN_WARNING "More than 4GB of memory " - "but GART IOMMU not available.\n"); - printk(KERN_WARNING "falling back to iommu=soft.\n"); + pr_warning("More than 4GB of memory but GART IOMMU not available.\n"); + pr_warning("falling back to iommu=soft.\n"); } return 0; } /* need to map that range */ - aper_size = info.aper_size << 20; - aper_base = info.aper_base; - end_pfn = (aper_base>>PAGE_SHIFT) + (aper_size>>PAGE_SHIFT); + aper_size = info.aper_size << 20; + aper_base = info.aper_base; + end_pfn = (aper_base>>PAGE_SHIFT) + (aper_size>>PAGE_SHIFT); + if (end_pfn > max_low_pfn_mapped) { start_pfn = (aper_base>>PAGE_SHIFT); init_memory_mapping(start_pfn<> PAGE_SHIFT; @@ -775,8 +783,7 @@ int __init gart_iommu_init(void) ret = dma_debug_resize_entries(iommu_pages); if (ret) - printk(KERN_DEBUG - "PCI-DMA: Cannot trace all the entries\n"); + pr_debug("PCI-DMA: Cannot trace all the entries\n"); } #endif @@ -786,15 +793,14 @@ int __init gart_iommu_init(void) */ iommu_area_reserve(iommu_gart_bitmap, 0, EMERGENCY_PAGES); - agp_memory_reserved = iommu_size; - printk(KERN_INFO - "PCI-DMA: Reserving %luMB of IOMMU area in the AGP aperture\n", + pr_info("PCI-DMA: Reserving %luMB of IOMMU area in the AGP aperture\n", iommu_size >> 20); - iommu_start = aper_size - iommu_size; - iommu_bus_base = info.aper_base + iommu_start; - bad_dma_addr = iommu_bus_base; - iommu_gatt_base = agp_gatt_table + (iommu_start>>PAGE_SHIFT); + agp_memory_reserved = iommu_size; + iommu_start = aper_size - iommu_size; + iommu_bus_base = info.aper_base + iommu_start; + bad_dma_addr = iommu_bus_base; + iommu_gatt_base = agp_gatt_table + (iommu_start>>PAGE_SHIFT); /* * Unmap the IOMMU part of the GART. The alias of the page is @@ -816,7 +822,7 @@ int __init gart_iommu_init(void) * the pages as Not-Present: */ wbinvd(); - + /* * Now all caches are flushed and we can safely enable * GART hardware. Doing it early leaves the possibility From 5a50e33cc916f6a81cb96f0f24f6a88c9ab78b79 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 17 Nov 2009 08:43:01 -0500 Subject: [PATCH 160/298] ring-buffer: Move access to commit_page up into function used With the change of the way we process commits. Where a commit only happens at the outer most level, and that we don't need to worry about a commit ending after the rb_start_commit() has been called, the code use to grab the commit page before the tail page to prevent a possible race. But this race no longer exists with the rb_start_commit() rb_end_commit() interface. Signed-off-by: Steven Rostedt --- kernel/trace/ring_buffer.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 3ffa502fb24..4b8293fa545 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -1785,9 +1785,9 @@ rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer, static struct ring_buffer_event * rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer, unsigned long length, unsigned long tail, - struct buffer_page *commit_page, struct buffer_page *tail_page, u64 *ts) { + struct buffer_page *commit_page = cpu_buffer->commit_page; struct ring_buffer *buffer = cpu_buffer->buffer; struct buffer_page *next_page; int ret; @@ -1890,13 +1890,10 @@ static struct ring_buffer_event * __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, unsigned type, unsigned long length, u64 *ts) { - struct buffer_page *tail_page, *commit_page; + struct buffer_page *tail_page; struct ring_buffer_event *event; unsigned long tail, write; - commit_page = cpu_buffer->commit_page; - /* we just need to protect against interrupts */ - barrier(); tail_page = cpu_buffer->tail_page; write = local_add_return(length, &tail_page->write); @@ -1907,7 +1904,7 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, /* See if we shot pass the end of this buffer page */ if (write > BUF_PAGE_SIZE) return rb_move_tail(cpu_buffer, length, tail, - commit_page, tail_page, ts); + tail_page, ts); /* We reserved something on the buffer */ From c13d2f7c3231e873f30db92b96c8caa48f100f33 Mon Sep 17 00:00:00 2001 From: Carsten Emde Date: Mon, 16 Nov 2009 20:56:13 +0100 Subject: [PATCH 161/298] tracing: Fix trace_marker output When a string was written to /tracing/trace_marker, some strange characters appeared in the trace output instead of the string, since a vprint function erroneously called a vararg print function with a va_list argument. This patch fixes the problem and simplifies the related code. Signed-off-by: Carsten Emde LKML-Reference: <4B01AE5D.1010801@osadl.org> Signed-off-by: Steven Rostedt --- kernel/trace/trace.c | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 03c7fd55c5f..12b49caedf8 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -1361,10 +1361,11 @@ int trace_array_vprintk(struct trace_array *tr, pause_graph_tracing(); raw_local_irq_save(irq_flags); __raw_spin_lock(&trace_buf_lock); - len = vsnprintf(trace_buf, TRACE_BUF_SIZE, fmt, args); - - len = min(len, TRACE_BUF_SIZE-1); - trace_buf[len] = 0; + if (args == NULL) { + strncpy(trace_buf, fmt, TRACE_BUF_SIZE); + len = strlen(trace_buf); + } else + len = vsnprintf(trace_buf, TRACE_BUF_SIZE, fmt, args); size = sizeof(*entry) + len + 1; buffer = tr->buffer; @@ -1373,10 +1374,10 @@ int trace_array_vprintk(struct trace_array *tr, if (!event) goto out_unlock; entry = ring_buffer_event_data(event); - entry->ip = ip; + entry->ip = ip; memcpy(&entry->buf, trace_buf, len); - entry->buf[len] = 0; + entry->buf[len] = '\0'; if (!filter_check_discard(call, entry, buffer, event)) ring_buffer_unlock_commit(buffer, event); @@ -3319,22 +3320,11 @@ tracing_entries_write(struct file *filp, const char __user *ubuf, return cnt; } -static int mark_printk(const char *fmt, ...) -{ - int ret; - va_list args; - va_start(args, fmt); - ret = trace_vprintk(0, fmt, args); - va_end(args); - return ret; -} - static ssize_t tracing_mark_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *fpos) { char *buf; - char *end; if (tracing_disabled) return -EINVAL; @@ -3342,7 +3332,7 @@ tracing_mark_write(struct file *filp, const char __user *ubuf, if (cnt > TRACE_BUF_SIZE) cnt = TRACE_BUF_SIZE; - buf = kmalloc(cnt + 1, GFP_KERNEL); + buf = kmalloc(cnt + 2, GFP_KERNEL); if (buf == NULL) return -ENOMEM; @@ -3350,14 +3340,13 @@ tracing_mark_write(struct file *filp, const char __user *ubuf, kfree(buf); return -EFAULT; } + if (buf[cnt-1] != '\n') { + buf[cnt] = '\n'; + buf[cnt+1] = '\0'; + } else + buf[cnt] = '\0'; - /* Cut from the first nil or newline. */ - buf[cnt] = '\0'; - end = strchr(buf, '\n'); - if (end) - *end = '\0'; - - cnt = mark_printk("%s\n", buf); + cnt = trace_vprintk(0, buf, NULL); kfree(buf); *fpos += cnt; From f6060f46819f313d34a8c8151390cda509c23389 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Thu, 5 Nov 2009 11:16:17 +0800 Subject: [PATCH 162/298] tracing: Prevent build warning: 'ftrace_graph_buf' defined but not used Prevent build warning when CONFIG_FUNCTION_GRAPH_TRACER is not set. Signed-off-by: Lai Jiangshan LKML-Reference: <4AF24381.5060307@cn.fujitsu.com> 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 1ed514fe3a3..7f9b51e8184 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -2274,7 +2274,6 @@ void ftrace_set_notrace(unsigned char *buf, int len, int reset) #define FTRACE_FILTER_SIZE COMMAND_LINE_SIZE static char ftrace_notrace_buf[FTRACE_FILTER_SIZE] __initdata; static char ftrace_filter_buf[FTRACE_FILTER_SIZE] __initdata; -static char ftrace_graph_buf[FTRACE_FILTER_SIZE] __initdata; static int __init set_ftrace_notrace(char *str) { @@ -2291,6 +2290,7 @@ static int __init set_ftrace_filter(char *str) __setup("ftrace_filter=", set_ftrace_filter); #ifdef CONFIG_FUNCTION_GRAPH_TRACER +static char ftrace_graph_buf[FTRACE_FILTER_SIZE] __initdata; static int __init set_graph_function(char *str) { strlcpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE); From 638adb0561264a3360a53e93def62288c85d8373 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 17 Nov 2009 10:48:25 -0500 Subject: [PATCH 163/298] tracing: Only print objcopy version warning once from recordmcount If the user has an older version of objcopy, that can not handle converting local symbols to global and vice versa, then some functions will not be part of the dynamic function tracer. The current code in recordmcount.pl will print a warning in this case. Unfortunately, there exists lots of files that may have this issue with older objcopys and this will cause a warning for every file compiled with this issue. This patch solves this overwhelming output by creating a .tmp_quiet_recordmcount file on the first instance the warning is encountered. The warning will not print if this file exists. The temp file is deleted at the beginning of the compile to ensure that the warning will happen once again on new compiles (because the issue is still present). Reported-by: Andrew Morton Cc: Sam Ravnborg Signed-off-by: Steven Rostedt --- Makefile | 1 + scripts/recordmcount.pl | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 9425d1de54c..1c949ac8ce6 100644 --- a/Makefile +++ b/Makefile @@ -379,6 +379,7 @@ export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exc PHONY += scripts_basic scripts_basic: $(Q)$(MAKE) $(build)=scripts/basic + $(Q)rm -f .tmp_quiet_recordmcount # To avoid any implicit rule to kick in, define an empty command. scripts/basic/%: scripts_basic ; diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index a4e2435d482..f0d14452632 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -162,6 +162,11 @@ 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 +# Shut up recordmcount if user has older objcopy +my $quiet_recordmcount = ".tmp_quiet_recordmcount"; +my $print_warning = 1; +$print_warning = 0 if ( -f $quiet_recordmcount); + ## # check_objcopy - whether objcopy supports --globalize-symbols # @@ -179,10 +184,13 @@ sub check_objcopy } close (IN); - if (!$can_use_local) { + if (!$can_use_local && $print_warning) { print STDERR "WARNING: could not find objcopy version or version " . "is less than 2.17.\n" . - "\tLocal function references is disabled.\n"; + "\tLocal function references are disabled.\n"; + open (QUIET, ">$quiet_recordmcount"); + printf QUIET "Disables the warning from recordmcount.pl\n"; + close QUIET; } } From a1afb6371bb5341057056194d1168753f6d77242 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 28 Aug 2009 22:19:33 +0400 Subject: [PATCH 164/298] genirq: switch /proc/irq/*/spurious to seq_file [ tglx: compacted it a bit ] Signed-off-by: Alexey Dobriyan LKML-Reference: <20090828181743.GA14050@x200.localdomain> Signed-off-by: Andrew Morton Signed-off-by: Thomas Gleixner --- kernel/irq/proc.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index dfef5b9f384..4e47f11da6a 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -148,18 +148,28 @@ static const struct file_operations default_affinity_proc_fops = { }; #endif -static int irq_spurious_read(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int irq_spurious_proc_show(struct seq_file *m, void *v) { - struct irq_desc *desc = irq_to_desc((long) data); - return sprintf(page, "count %u\n" - "unhandled %u\n" - "last_unhandled %u ms\n", - desc->irq_count, - desc->irqs_unhandled, - jiffies_to_msecs(desc->last_unhandled)); + struct irq_desc *desc = irq_to_desc((long) m->private); + + seq_printf(m, "count %u\n" "unhandled %u\n" "last_unhandled %u ms\n", + desc->irq_count, desc->irqs_unhandled, + jiffies_to_msecs(desc->last_unhandled)); + return 0; } +static int irq_spurious_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, irq_spurious_proc_show, NULL); +} + +static const struct file_operations irq_spurious_proc_fops = { + .open = irq_spurious_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + #define MAX_NAMELEN 128 static int name_unique(unsigned int irq, struct irqaction *new_action) @@ -204,7 +214,6 @@ void register_handler_proc(unsigned int irq, struct irqaction *action) void register_irq_proc(unsigned int irq, struct irq_desc *desc) { char name [MAX_NAMELEN]; - struct proc_dir_entry *entry; if (!root_irq_dir || (desc->chip == &no_irq_chip) || desc->dir) return; @@ -223,11 +232,8 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc) &irq_affinity_proc_fops, (void *)(long)irq); #endif - entry = create_proc_entry("spurious", 0444, desc->dir); - if (entry) { - entry->data = (void *)(long)irq; - entry->read_proc = irq_spurious_read; - } + proc_create_data("spurious", 0444, desc->dir, + &irq_spurious_proc_fops, (void *)(long)irq); } #undef MAX_NAMELEN From 2ea6dec4a22a6f66f6633876212fd4d195cf8277 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 17 Nov 2009 14:27:27 -0800 Subject: [PATCH 165/298] generic-ipi: Add smp_call_function_any() Andrew points out that acpi-cpufreq uses cpumask_any, when it really would prefer to use the same CPU if possible (to avoid an IPI). In general, this seems a good idea to offer. [ tglx: Documented selection preference and Inlined the UP case to avoid the copy of smp_call_function_single() and the extra EXPORT ] Signed-off-by: Rusty Russell Cc: Ingo Molnar Cc: Venkatesh Pallipadi Cc: Len Brown Cc: Zhao Yakui Cc: Dave Jones Cc: Thomas Gleixner Cc: Mike Galbraith Cc: "Zhang, Yanmin" Signed-off-by: Andrew Morton Signed-off-by: Thomas Gleixner --- include/linux/smp.h | 11 ++++++++++- kernel/smp.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/include/linux/smp.h b/include/linux/smp.h index 39c64bae776..7a0570e6a59 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -76,6 +76,9 @@ void smp_call_function_many(const struct cpumask *mask, void __smp_call_function_single(int cpuid, struct call_single_data *data, int wait); +int smp_call_function_any(const struct cpumask *mask, + void (*func)(void *info), void *info, int wait); + /* * Generic and arch helpers */ @@ -137,9 +140,15 @@ static inline void smp_send_reschedule(int cpu) { } #define smp_prepare_boot_cpu() do {} while (0) #define smp_call_function_many(mask, func, info, wait) \ (up_smp_call_function(func, info)) -static inline void init_call_single_data(void) +static inline void init_call_single_data(void) { } + +static inline int +smp_call_function_any(const struct cpumask *mask, void (*func)(void *info), + void *info, int wait) { + return smp_call_function_single(0, func, info, wait); } + #endif /* !SMP */ /* diff --git a/kernel/smp.c b/kernel/smp.c index 8bd618f0364..a8c76069cf5 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -319,6 +319,51 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info, } EXPORT_SYMBOL(smp_call_function_single); +/* + * smp_call_function_any - Run a function on any of the given cpus + * @mask: The mask of cpus it can run on. + * @func: The function to run. This must be fast and non-blocking. + * @info: An arbitrary pointer to pass to the function. + * @wait: If true, wait until function has completed. + * + * Returns 0 on success, else a negative status code (if no cpus were online). + * Note that @wait will be implicitly turned on in case of allocation failures, + * since we fall back to on-stack allocation. + * + * Selection preference: + * 1) current cpu if in @mask + * 2) any cpu of current node if in @mask + * 3) any other online cpu in @mask + */ +int smp_call_function_any(const struct cpumask *mask, + void (*func)(void *info), void *info, int wait) +{ + unsigned int cpu; + const struct cpumask *nodemask; + int ret; + + /* Try for same CPU (cheapest) */ + cpu = get_cpu(); + if (cpumask_test_cpu(cpu, mask)) + goto call; + + /* Try for same node. */ + nodemask = cpumask_of_node(cpu); + for (cpu = cpumask_first_and(nodemask, mask); cpu < nr_cpu_ids; + cpu = cpumask_next_and(cpu, nodemask, mask)) { + if (cpu_online(cpu)) + goto call; + } + + /* Any online will do: smp_call_function_single handles nr_cpu_ids. */ + cpu = cpumask_any_and(mask, cpu_online_mask); +call: + ret = smp_call_function_single(cpu, func, info, wait); + put_cpu(); + return ret; +} +EXPORT_SYMBOL_GPL(smp_call_function_any); + /** * __smp_call_function_single(): Run a function on another CPU * @cpu: The CPU to run on. From 821d35a56044e522e811f6a1e8632cc230360280 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 18 Nov 2009 14:39:51 +0000 Subject: [PATCH 166/298] selinux: Fix warnings scripts/selinux/genheaders/genheaders.c:20: warning: no previous prototype for ?usage? scripts/selinux/genheaders/genheaders.c:26: warning: no previous prototype for ?stoupperx? Signed-off-by: Alan Cox Acked-by: WANG Cong Signed-off-by: James Morris --- scripts/selinux/genheaders/genheaders.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/selinux/genheaders/genheaders.c b/scripts/selinux/genheaders/genheaders.c index 3b16145dabe..771b86f4619 100644 --- a/scripts/selinux/genheaders/genheaders.c +++ b/scripts/selinux/genheaders/genheaders.c @@ -17,13 +17,13 @@ struct security_class_mapping { const char *progname; -void usage(void) +static void usage(void) { printf("usage: %s flask.h av_permissions.h\n", progname); exit(1); } -char *stoupperx(const char *s) +static char *stoupperx(const char *s) { char *s2 = strdup(s); char *p; From 192dcf1d1775736627280a5dd4cb0f605b21857a Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 18 Nov 2009 13:06:55 -0800 Subject: [PATCH 167/298] tracing: Remove the stale include/trace/power.h Commit 6161352 moved the power tracing to include/trace/events/, but left the old header behind. No one is using the old header, and its declarations are now incorrect, so it should be removed. Signed-off-by: Josh Stone Acked-by: Arjan van de Ven Cc: Frank Ch. Eigler Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Frederic Weisbecker LKML-Reference: <1258578415-14752-1-git-send-email-jistone@redhat.com> Signed-off-by: Ingo Molnar --- include/trace/power.h | 32 -------------------------------- 1 file changed, 32 deletions(-) delete mode 100644 include/trace/power.h diff --git a/include/trace/power.h b/include/trace/power.h deleted file mode 100644 index ef204666e98..00000000000 --- a/include/trace/power.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _TRACE_POWER_H -#define _TRACE_POWER_H - -#include -#include - -enum { - POWER_NONE = 0, - POWER_CSTATE = 1, - POWER_PSTATE = 2, -}; - -struct power_trace { - ktime_t stamp; - ktime_t end; - int type; - int state; -}; - -DECLARE_TRACE(power_start, - TP_PROTO(struct power_trace *it, unsigned int type, unsigned int state), - TP_ARGS(it, type, state)); - -DECLARE_TRACE(power_mark, - TP_PROTO(struct power_trace *it, unsigned int type, unsigned int state), - TP_ARGS(it, type, state)); - -DECLARE_TRACE(power_end, - TP_PROTO(struct power_trace *it), - TP_ARGS(it)); - -#endif /* _TRACE_POWER_H */ From 34769945f7cd9ab470413ffe64426e3ad069f49e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 20 Nov 2009 11:46:21 +0100 Subject: [PATCH 168/298] genirq: Fix spurious irq seqfile conversion single_open data argument must be PDE(inode)->data instead of NULL otherwise seq_file->private is always NULL and we always read the spurious data of irq 0. Reported-by: Alexey Dobriyan Signed-off-by: Thomas Gleixner --- kernel/irq/proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 4e47f11da6a..0832145fea9 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -136,7 +136,7 @@ out: static int default_affinity_open(struct inode *inode, struct file *file) { - return single_open(file, default_affinity_show, NULL); + return single_open(file, default_affinity_show, PDE(inode)->data); } static const struct file_operations default_affinity_proc_fops = { From 78a14e273d93dfbea9673f9b10398c538096302d Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 21 Nov 2009 12:50:34 +0100 Subject: [PATCH 169/298] drivers/pcmcia: remove unnecessary kzalloc The result of calling kzalloc is never used or freed. The semantic match that finds this problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; statement S; expression E; identifier f,f1,l; position p1,p2; expression *ptr != NULL; @@ x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...); ... if (x == NULL) S <... when != x when != if (...) { <+...x...+> } ( x->f1 = E | (x->f1 == NULL || ...) | f(...,x->f1,...) ) ...> ( return \(0\|<+...x...+>\|ptr\); | return@p2 ...; ) @script:python@ p1 << r.p1; p2 << r.p2; @@ print "* file: %s kmalloc %s return %s" % (p1[0].file,p1[0].line,p2[0].line) // Signed-off-by: Julia Lawall Signed-off-by: Dominik Brodowski --- drivers/pcmcia/sa1111_generic.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index deb5036ee5f..de6bc333d29 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -127,10 +127,6 @@ int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops, ops->socket_state = sa1111_pcmcia_socket_state; ops->socket_suspend = sa1111_pcmcia_socket_suspend; - s = kzalloc(sizeof(*s) * ops->nr, GFP_KERNEL); - if (!s) - return -ENODEV; - for (i = 0; i < ops->nr; i++) { s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) From b668c9cf3e58739dac54a1d6f42f2b4bdd980b3e Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 22 Nov 2009 08:53:48 -0800 Subject: [PATCH 170/298] rcu: Fix grace-period-stall bug on large systems with CPU hotplug When the last CPU of a given leaf rcu_node structure goes offline, all of the tasks queued on that leaf rcu_node structure (due to having blocked in their current RCU read-side critical sections) are requeued onto the root rcu_node structure. This requeuing is carried out by rcu_preempt_offline_tasks(). However, it is possible that these queued tasks are the only thing preventing the leaf rcu_node structure from reporting a quiescent state up the rcu_node hierarchy. Unfortunately, the old code would fail to do this reporting, resulting in a grace-period stall given the following sequence of events: 1. Kernel built for more than 32 CPUs on 32-bit systems or for more than 64 CPUs on 64-bit systems, so that there is more than one rcu_node structure. (Or CONFIG_RCU_FANOUT is artificially set to a number smaller than CONFIG_NR_CPUS.) 2. The kernel is built with CONFIG_TREE_PREEMPT_RCU. 3. A task running on a CPU associated with a given leaf rcu_node structure blocks while in an RCU read-side critical section -and- that CPU has not yet passed through a quiescent state for the current RCU grace period. This will cause the task to be queued on the leaf rcu_node's blocked_tasks[] array, in particular, on the element of this array corresponding to the current grace period. 4. Each of the remaining CPUs corresponding to this same leaf rcu_node structure pass through a quiescent state. However, the task is still in its RCU read-side critical section, so these quiescent states cannot be reported further up the rcu_node hierarchy. Nevertheless, all bits in the leaf rcu_node structure's ->qsmask field are now zero. 5. Each of the remaining CPUs go offline. (The events in step #4 and #5 can happen in any order as long as each CPU passes through a quiescent state before going offline.) 6. When the last CPU goes offline, __rcu_offline_cpu() will invoke rcu_preempt_offline_tasks(), which will move the task to the root rcu_node structure, but without reporting a quiescent state up the rcu_node hierarchy (and this failure to report a quiescent state is the bug). But because this leaf rcu_node structure's ->qsmask field is already zero and its ->block_tasks[] entries are all empty, force_quiescent_state() will skip this rcu_node structure. Therefore, grace periods are now hung. This patch abstracts some code out of rcu_read_unlock_special(), calling the result task_quiet() by analogy with cpu_quiet(), and invokes task_quiet() from both rcu_read_lock_special() and __rcu_offline_cpu(). Invoking task_quiet() from __rcu_offline_cpu() reports the quiescent state up the rcu_node hierarchy, fixing the bug. This ends up requiring a separate lock_class_key per level of the rcu_node hierarchy, which this patch also provides. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12589088301770-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 40 ++++++++++--------- kernel/rcutree.h | 3 ++ kernel/rcutree_plugin.h | 85 +++++++++++++++++++++++++++++------------ 3 files changed, 85 insertions(+), 43 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 9b36d6d7fb9..b79bfcd28e9 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -51,7 +51,7 @@ /* Data structures. */ -static struct lock_class_key rcu_root_class; +static struct lock_class_key rcu_node_class[NUM_RCU_LVLS]; #define RCU_STATE_INITIALIZER(name) { \ .level = { &name.node[0] }, \ @@ -936,6 +936,7 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) { unsigned long flags; unsigned long mask; + int need_quiet = 0; struct rcu_data *rdp = rsp->rda[cpu]; struct rcu_node *rnp; @@ -949,29 +950,30 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) spin_lock(&rnp->lock); /* irqs already disabled. */ rnp->qsmaskinit &= ~mask; if (rnp->qsmaskinit != 0) { - spin_unlock(&rnp->lock); /* irqs remain disabled. */ + if (rnp != rdp->mynode) + spin_unlock(&rnp->lock); /* irqs remain disabled. */ break; } - - /* - * If there was a task blocking the current grace period, - * and if all CPUs have checked in, we need to propagate - * the quiescent state up the rcu_node hierarchy. But that - * is inconvenient at the moment due to deadlock issues if - * this should end the current grace period. So set the - * offlined CPU's bit in ->qsmask in order to force the - * next force_quiescent_state() invocation to clean up this - * mess in a deadlock-free manner. - */ - if (rcu_preempt_offline_tasks(rsp, rnp, rdp) && !rnp->qsmask) - rnp->qsmask |= mask; - + if (rnp == rdp->mynode) + need_quiet = rcu_preempt_offline_tasks(rsp, rnp, rdp); + else + spin_unlock(&rnp->lock); /* irqs remain disabled. */ mask = rnp->grpmask; - spin_unlock(&rnp->lock); /* irqs remain disabled. */ rnp = rnp->parent; } while (rnp != NULL); - spin_unlock_irqrestore(&rsp->onofflock, flags); + /* + * We still hold the leaf rcu_node structure lock here, and + * irqs are still disabled. The reason for this subterfuge is + * because invoking task_quiet() with ->onofflock held leads + * to deadlock. + */ + spin_unlock(&rsp->onofflock); /* irqs remain disabled. */ + rnp = rdp->mynode; + if (need_quiet) + task_quiet(rnp, flags); + else + spin_unlock_irqrestore(&rnp->lock, flags); rcu_adopt_orphan_cbs(rsp); } @@ -1731,6 +1733,7 @@ static void __init rcu_init_one(struct rcu_state *rsp) rnp = rsp->level[i]; for (j = 0; j < rsp->levelcnt[i]; j++, rnp++) { spin_lock_init(&rnp->lock); + lockdep_set_class(&rnp->lock, &rcu_node_class[i]); rnp->gpnum = 0; rnp->qsmask = 0; rnp->qsmaskinit = 0; @@ -1753,7 +1756,6 @@ static void __init rcu_init_one(struct rcu_state *rsp) INIT_LIST_HEAD(&rnp->blocked_tasks[1]); } } - lockdep_set_class(&rcu_get_root(rsp)->lock, &rcu_root_class); } /* diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 17a28a08b55..a81188c4292 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -305,6 +305,9 @@ static void rcu_bootup_announce(void); long rcu_batches_completed(void); static void rcu_preempt_note_context_switch(int cpu); static int rcu_preempted_readers(struct rcu_node *rnp); +#ifdef CONFIG_HOTPLUG_CPU +static void task_quiet(struct rcu_node *rnp, unsigned long flags); +#endif /* #ifdef CONFIG_HOTPLUG_CPU */ #ifdef CONFIG_RCU_CPU_STALL_DETECTOR static void rcu_print_task_stall(struct rcu_node *rnp); #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 5ca2d26c597..0bdb592eee6 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -160,11 +160,51 @@ static int rcu_preempted_readers(struct rcu_node *rnp) return !list_empty(&rnp->blocked_tasks[rnp->gpnum & 0x1]); } +/* + * Record a quiescent state for all tasks that were previously queued + * on the specified rcu_node structure and that were blocking the current + * RCU grace period. The caller must hold the specified rnp->lock with + * irqs disabled, and this lock is released upon return, but irqs remain + * disabled. + */ +static void task_quiet(struct rcu_node *rnp, unsigned long flags) + __releases(rnp->lock) +{ + unsigned long mask; + struct rcu_node *rnp_p; + + if (rnp->qsmask != 0 || rcu_preempted_readers(rnp)) { + spin_unlock_irqrestore(&rnp->lock, flags); + return; /* Still need more quiescent states! */ + } + + rnp_p = rnp->parent; + if (rnp_p == NULL) { + /* + * Either there is only one rcu_node in the tree, + * or tasks were kicked up to root rcu_node due to + * CPUs going offline. + */ + cpu_quiet_msk_finish(&rcu_preempt_state, flags); + return; + } + + /* Report up the rest of the hierarchy. */ + mask = rnp->grpmask; + spin_unlock(&rnp->lock); /* irqs remain disabled. */ + spin_lock(&rnp_p->lock); /* irqs already disabled. */ + cpu_quiet_msk(mask, &rcu_preempt_state, rnp_p, flags); +} + +/* + * Handle special cases during rcu_read_unlock(), such as needing to + * notify RCU core processing or task having blocked during the RCU + * read-side critical section. + */ static void rcu_read_unlock_special(struct task_struct *t) { int empty; unsigned long flags; - unsigned long mask; struct rcu_node *rnp; int special; @@ -213,30 +253,15 @@ static void rcu_read_unlock_special(struct task_struct *t) /* * If this was the last task on the current list, and if * we aren't waiting on any CPUs, report the quiescent state. - * Note that both cpu_quiet_msk_finish() and cpu_quiet_msk() - * drop rnp->lock and restore irq. + * Note that task_quiet() releases rnp->lock. */ - if (!empty && rnp->qsmask == 0 && - !rcu_preempted_readers(rnp)) { - struct rcu_node *rnp_p; - - if (rnp->parent == NULL) { - /* Only one rcu_node in the tree. */ - cpu_quiet_msk_finish(&rcu_preempt_state, flags); - return; - } - /* Report up the rest of the hierarchy. */ - mask = rnp->grpmask; + if (empty) spin_unlock_irqrestore(&rnp->lock, flags); - rnp_p = rnp->parent; - spin_lock_irqsave(&rnp_p->lock, flags); - WARN_ON_ONCE(rnp->qsmask); - cpu_quiet_msk(mask, &rcu_preempt_state, rnp_p, flags); - return; - } - spin_unlock(&rnp->lock); + else + task_quiet(rnp, flags); + } else { + local_irq_restore(flags); } - local_irq_restore(flags); } /* @@ -303,6 +328,8 @@ static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp) * rcu_node. The reason for not just moving them to the immediate * parent is to remove the need for rcu_read_unlock_special() to * make more than two attempts to acquire the target rcu_node's lock. + * Returns true if there were tasks blocking the current RCU grace + * period. * * Returns 1 if there was previously a task blocking the current grace * period on the specified rcu_node structure. @@ -316,7 +343,7 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp, int i; struct list_head *lp; struct list_head *lp_root; - int retval = rcu_preempted_readers(rnp); + int retval; struct rcu_node *rnp_root = rcu_get_root(rsp); struct task_struct *tp; @@ -334,6 +361,7 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp, * rcu_nodes in terms of gp_num value. This fact allows us to * move the blocked_tasks[] array directly, element by element. */ + retval = rcu_preempted_readers(rnp); for (i = 0; i < 2; i++) { lp = &rnp->blocked_tasks[i]; lp_root = &rnp_root->blocked_tasks[i]; @@ -346,7 +374,6 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp, spin_unlock(&rnp_root->lock); /* irqs remain disabled */ } } - return retval; } @@ -512,6 +539,16 @@ static int rcu_preempted_readers(struct rcu_node *rnp) return 0; } +#ifdef CONFIG_HOTPLUG_CPU + +/* Because preemptible RCU does not exist, no quieting of tasks. */ +static void task_quiet(struct rcu_node *rnp, unsigned long flags) +{ + spin_unlock_irqrestore(&rnp->lock, flags); +} + +#endif /* #ifdef CONFIG_HOTPLUG_CPU */ + #ifdef CONFIG_RCU_CPU_STALL_DETECTOR /* From 9f680ab41485edfdc96331b70afa7513aa0a7720 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 22 Nov 2009 08:53:49 -0800 Subject: [PATCH 171/298] rcu: Eliminate unneeded function wrapping The functions rcu_init() is a wrapper for __rcu_init(), and also sets up the CPU-hotplug notifier for rcu_barrier_cpu_hotplug(). But TINY_RCU doesn't need CPU-hotplug notification, and the rcu_barrier_cpu_hotplug() is a simple wrapper for rcu_cpu_notify(). So push rcu_init() out to kernel/rcutree.c and kernel/rcutiny.c and get rid of the wrapper function rcu_barrier_cpu_hotplug(). Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12589088302320-git-send-email-> Signed-off-by: Ingo Molnar --- include/linux/rcutiny.h | 2 -- include/linux/rcutree.h | 3 --- kernel/rcupdate.c | 22 ---------------------- kernel/rcutiny.c | 11 +---------- kernel/rcutree.c | 17 ++++++++++++++--- 5 files changed, 15 insertions(+), 40 deletions(-) diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h index 2c1fe8373e7..a3b6272af2d 100644 --- a/include/linux/rcutiny.h +++ b/include/linux/rcutiny.h @@ -38,7 +38,6 @@ void rcu_bh_qs(int cpu); #define rcu_init_sched() do { } while (0) extern void rcu_check_callbacks(int cpu, int user); -extern void __rcu_init(void); /* * Return the number of grace periods. @@ -69,7 +68,6 @@ static inline void synchronize_rcu_bh_expedited(void) } struct notifier_block; -extern int rcu_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu); #ifdef CONFIG_NO_HZ diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 9642c6bcb39..111a6525735 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -34,8 +34,6 @@ struct notifier_block; extern void rcu_sched_qs(int cpu); extern void rcu_bh_qs(int cpu); -extern int rcu_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu); extern int rcu_needs_cpu(int cpu); extern int rcu_expedited_torture_stats(char *page); @@ -83,7 +81,6 @@ static inline void synchronize_rcu_bh_expedited(void) synchronize_sched_expedited(); } -extern void __rcu_init(void); extern void rcu_check_callbacks(int cpu, int user); extern long rcu_batches_completed(void); diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index 7625f207f65..eb6b534db31 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -161,28 +161,6 @@ EXPORT_SYMBOL_GPL(synchronize_rcu_bh); #endif /* #ifndef CONFIG_TINY_RCU */ -static int __cpuinit rcu_barrier_cpu_hotplug(struct notifier_block *self, - unsigned long action, void *hcpu) -{ - return rcu_cpu_notify(self, action, hcpu); -} - -void __init rcu_init(void) -{ - int i; - - __rcu_init(); - cpu_notifier(rcu_barrier_cpu_hotplug, 0); - - /* - * We don't need protection against CPU-hotplug here because - * this is called early in boot, before either interrupts - * or the scheduler are operational. - */ - for_each_online_cpu(i) - rcu_barrier_cpu_hotplug(NULL, CPU_UP_PREPARE, (void *)(long)i); -} - void rcu_scheduler_starting(void) { WARN_ON(num_online_cpus() != 1); diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c index b33ec3aa377..9f6d9ff2572 100644 --- a/kernel/rcutiny.c +++ b/kernel/rcutiny.c @@ -177,15 +177,6 @@ static void rcu_process_callbacks(struct softirq_action *unused) __rcu_process_callbacks(&rcu_bh_ctrlblk); } -/* - * Null function to handle CPU being onlined. Longer term, we want to - * make TINY_RCU avoid using rcupdate.c, but later... - */ -int rcu_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) -{ - return NOTIFY_OK; -} - /* * Wait for a grace period to elapse. But it is illegal to invoke * synchronize_sched() from within an RCU read-side critical section. @@ -285,7 +276,7 @@ void rcu_barrier_sched(void) } EXPORT_SYMBOL_GPL(rcu_barrier_sched); -void __rcu_init(void) +void __init rcu_init(void) { open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); } diff --git a/kernel/rcutree.c b/kernel/rcutree.c index b79bfcd28e9..e3d3bbddbcd 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -1644,8 +1644,8 @@ static void __cpuinit rcu_online_cpu(int cpu) /* * Handle CPU online/offline notification events. */ -int __cpuinit rcu_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) +static int __cpuinit rcu_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) { long cpu = (long)hcpu; @@ -1781,8 +1781,10 @@ do { \ } \ } while (0) -void __init __rcu_init(void) +void __init rcu_init(void) { + int i; + rcu_bootup_announce(); #ifdef CONFIG_RCU_CPU_STALL_DETECTOR printk(KERN_INFO "RCU-based detection of stalled CPUs is enabled.\n"); @@ -1791,6 +1793,15 @@ void __init __rcu_init(void) RCU_INIT_FLAVOR(&rcu_bh_state, rcu_bh_data); __rcu_init_preempt(); open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); + + /* + * We don't need protection against CPU-hotplug here because + * this is called early in boot, before either interrupts + * or the scheduler are operational. + */ + cpu_notifier(rcu_cpu_notify, 0); + for_each_online_cpu(i) + rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)i); } #include "rcutree_plugin.h" From 6ebb237bece23275d1da149b61a342f0d4d06a08 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 22 Nov 2009 08:53:50 -0800 Subject: [PATCH 172/298] rcu: Re-arrange code to reduce #ifdef pain Remove #ifdefs from kernel/rcupdate.c and include/linux/rcupdate.h by moving code to include/linux/rcutiny.h, include/linux/rcutree.h, and kernel/rcutree.c. Also remove some definitions that are no longer used. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <1258908830885-git-send-email-> Signed-off-by: Ingo Molnar --- include/linux/rcupdate.h | 12 ----- include/linux/rcutiny.h | 11 +++++ include/linux/rcutree.h | 4 +- kernel/rcupdate.c | 104 --------------------------------------- kernel/rcutree.c | 80 ++++++++++++++++++++++++++++++ kernel/rcutree_plugin.h | 24 +++++++++ 6 files changed, 118 insertions(+), 117 deletions(-) diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 2f1bc42a3b8..24440f4bf47 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -52,11 +52,6 @@ struct rcu_head { }; /* Exported common interfaces */ -#ifdef CONFIG_TREE_PREEMPT_RCU -extern void synchronize_rcu(void); -#else /* #ifdef CONFIG_TREE_PREEMPT_RCU */ -#define synchronize_rcu synchronize_sched -#endif /* #else #ifdef CONFIG_TREE_PREEMPT_RCU */ extern void synchronize_rcu_bh(void); extern void synchronize_sched(void); extern void rcu_barrier(void); @@ -67,13 +62,6 @@ extern int sched_expedited_torture_stats(char *page); /* Internal to kernel */ extern void rcu_init(void); -extern void rcu_scheduler_starting(void); -#ifndef CONFIG_TINY_RCU -extern int rcu_needs_cpu(int cpu); -#else -static inline int rcu_needs_cpu(int cpu) { return 0; } -#endif -extern int rcu_scheduler_active; #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) #include diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h index a3b6272af2d..c4ba9a78721 100644 --- a/include/linux/rcutiny.h +++ b/include/linux/rcutiny.h @@ -39,6 +39,11 @@ void rcu_bh_qs(int cpu); #define rcu_init_sched() do { } while (0) extern void rcu_check_callbacks(int cpu, int user); +static inline int rcu_needs_cpu(int cpu) +{ + return 0; +} + /* * Return the number of grace periods. */ @@ -57,6 +62,8 @@ static inline long rcu_batches_completed_bh(void) extern int rcu_expedited_torture_stats(char *page); +#define synchronize_rcu synchronize_sched + static inline void synchronize_rcu_expedited(void) { synchronize_sched(); @@ -86,6 +93,10 @@ static inline void rcu_exit_nohz(void) #endif /* #else #ifdef CONFIG_NO_HZ */ +static inline void rcu_scheduler_starting(void) +{ +} + static inline void exit_rcu(void) { } diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 111a6525735..c93eee5911b 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -35,12 +35,14 @@ struct notifier_block; extern void rcu_sched_qs(int cpu); extern void rcu_bh_qs(int cpu); extern int rcu_needs_cpu(int cpu); +extern void rcu_scheduler_starting(void); extern int rcu_expedited_torture_stats(char *page); #ifdef CONFIG_TREE_PREEMPT_RCU extern void __rcu_read_lock(void); extern void __rcu_read_unlock(void); +extern void synchronize_rcu(void); extern void exit_rcu(void); #else /* #ifdef CONFIG_TREE_PREEMPT_RCU */ @@ -55,7 +57,7 @@ static inline void __rcu_read_unlock(void) preempt_enable(); } -#define __synchronize_sched() synchronize_rcu() +#define synchronize_rcu synchronize_sched static inline void exit_rcu(void) { diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index eb6b534db31..9b7fd472387 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -44,7 +44,6 @@ #include #include #include -#include #ifdef CONFIG_DEBUG_LOCK_ALLOC static struct lock_class_key rcu_lock_key; @@ -53,8 +52,6 @@ struct lockdep_map rcu_lock_map = EXPORT_SYMBOL_GPL(rcu_lock_map); #endif -int rcu_scheduler_active __read_mostly; - /* * Awaken the corresponding synchronize_rcu() instance now that a * grace period has elapsed. @@ -66,104 +63,3 @@ void wakeme_after_rcu(struct rcu_head *head) rcu = container_of(head, struct rcu_synchronize, head); complete(&rcu->completion); } - -#ifndef CONFIG_TINY_RCU - -#ifdef CONFIG_TREE_PREEMPT_RCU - -/** - * synchronize_rcu - wait until a grace period has elapsed. - * - * Control will return to the caller some time after a full grace - * period has elapsed, in other words after all currently executing RCU - * read-side critical sections have completed. RCU read-side critical - * sections are delimited by rcu_read_lock() and rcu_read_unlock(), - * and may be nested. - */ -void synchronize_rcu(void) -{ - struct rcu_synchronize rcu; - - if (!rcu_scheduler_active) - return; - - init_completion(&rcu.completion); - /* Will wake me after RCU finished. */ - call_rcu(&rcu.head, wakeme_after_rcu); - /* Wait for it. */ - wait_for_completion(&rcu.completion); -} -EXPORT_SYMBOL_GPL(synchronize_rcu); - -#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ - -/** - * synchronize_sched - wait until an rcu-sched grace period has elapsed. - * - * Control will return to the caller some time after a full rcu-sched - * grace period has elapsed, in other words after all currently executing - * rcu-sched read-side critical sections have completed. These read-side - * critical sections are delimited by rcu_read_lock_sched() and - * rcu_read_unlock_sched(), and may be nested. Note that preempt_disable(), - * local_irq_disable(), and so on may be used in place of - * rcu_read_lock_sched(). - * - * This means that all preempt_disable code sequences, including NMI and - * hardware-interrupt handlers, in progress on entry will have completed - * before this primitive returns. However, this does not guarantee that - * softirq handlers will have completed, since in some kernels, these - * handlers can run in process context, and can block. - * - * This primitive provides the guarantees made by the (now removed) - * synchronize_kernel() API. In contrast, synchronize_rcu() only - * guarantees that rcu_read_lock() sections will have completed. - * In "classic RCU", these two guarantees happen to be one and - * the same, but can differ in realtime RCU implementations. - */ -void synchronize_sched(void) -{ - struct rcu_synchronize rcu; - - if (rcu_blocking_is_gp()) - return; - - init_completion(&rcu.completion); - /* Will wake me after RCU finished. */ - call_rcu_sched(&rcu.head, wakeme_after_rcu); - /* Wait for it. */ - wait_for_completion(&rcu.completion); -} -EXPORT_SYMBOL_GPL(synchronize_sched); - -/** - * synchronize_rcu_bh - wait until an rcu_bh grace period has elapsed. - * - * Control will return to the caller some time after a full rcu_bh grace - * period has elapsed, in other words after all currently executing rcu_bh - * read-side critical sections have completed. RCU read-side critical - * sections are delimited by rcu_read_lock_bh() and rcu_read_unlock_bh(), - * and may be nested. - */ -void synchronize_rcu_bh(void) -{ - struct rcu_synchronize rcu; - - if (rcu_blocking_is_gp()) - return; - - init_completion(&rcu.completion); - /* Will wake me after RCU finished. */ - call_rcu_bh(&rcu.head, wakeme_after_rcu); - /* Wait for it. */ - wait_for_completion(&rcu.completion); -} -EXPORT_SYMBOL_GPL(synchronize_rcu_bh); - -#endif /* #ifndef CONFIG_TINY_RCU */ - -void rcu_scheduler_starting(void) -{ - WARN_ON(num_online_cpus() != 1); - WARN_ON(nr_context_switches() > 0); - rcu_scheduler_active = 1; -} diff --git a/kernel/rcutree.c b/kernel/rcutree.c index e3d3bbddbcd..4ca7e0292fd 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -46,6 +46,7 @@ #include #include #include +#include #include "rcutree.h" @@ -79,6 +80,8 @@ DEFINE_PER_CPU(struct rcu_data, rcu_sched_data); struct rcu_state rcu_bh_state = RCU_STATE_INITIALIZER(rcu_bh_state); DEFINE_PER_CPU(struct rcu_data, rcu_bh_data); +static int rcu_scheduler_active __read_mostly; + /* * Return true if an RCU grace period is in progress. The ACCESS_ONCE()s @@ -1396,6 +1399,68 @@ void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) } EXPORT_SYMBOL_GPL(call_rcu_bh); +/** + * synchronize_sched - wait until an rcu-sched grace period has elapsed. + * + * Control will return to the caller some time after a full rcu-sched + * grace period has elapsed, in other words after all currently executing + * rcu-sched read-side critical sections have completed. These read-side + * critical sections are delimited by rcu_read_lock_sched() and + * rcu_read_unlock_sched(), and may be nested. Note that preempt_disable(), + * local_irq_disable(), and so on may be used in place of + * rcu_read_lock_sched(). + * + * This means that all preempt_disable code sequences, including NMI and + * hardware-interrupt handlers, in progress on entry will have completed + * before this primitive returns. However, this does not guarantee that + * softirq handlers will have completed, since in some kernels, these + * handlers can run in process context, and can block. + * + * This primitive provides the guarantees made by the (now removed) + * synchronize_kernel() API. In contrast, synchronize_rcu() only + * guarantees that rcu_read_lock() sections will have completed. + * In "classic RCU", these two guarantees happen to be one and + * the same, but can differ in realtime RCU implementations. + */ +void synchronize_sched(void) +{ + struct rcu_synchronize rcu; + + if (rcu_blocking_is_gp()) + return; + + init_completion(&rcu.completion); + /* Will wake me after RCU finished. */ + call_rcu_sched(&rcu.head, wakeme_after_rcu); + /* Wait for it. */ + wait_for_completion(&rcu.completion); +} +EXPORT_SYMBOL_GPL(synchronize_sched); + +/** + * synchronize_rcu_bh - wait until an rcu_bh grace period has elapsed. + * + * Control will return to the caller some time after a full rcu_bh grace + * period has elapsed, in other words after all currently executing rcu_bh + * read-side critical sections have completed. RCU read-side critical + * sections are delimited by rcu_read_lock_bh() and rcu_read_unlock_bh(), + * and may be nested. + */ +void synchronize_rcu_bh(void) +{ + struct rcu_synchronize rcu; + + if (rcu_blocking_is_gp()) + return; + + init_completion(&rcu.completion); + /* Will wake me after RCU finished. */ + call_rcu_bh(&rcu.head, wakeme_after_rcu); + /* Wait for it. */ + wait_for_completion(&rcu.completion); +} +EXPORT_SYMBOL_GPL(synchronize_rcu_bh); + /* * Check to see if there is any immediate RCU-related work to be done * by the current CPU, for the specified type of RCU, returning 1 if so. @@ -1480,6 +1545,21 @@ int rcu_needs_cpu(int cpu) rcu_preempt_needs_cpu(cpu); } +/* + * This function is invoked towards the end of the scheduler's initialization + * process. Before this is called, the idle task might contain + * RCU read-side critical sections (during which time, this idle + * task is booting the system). After this function is called, the + * idle tasks are prohibited from containing RCU read-side critical + * sections. + */ +void rcu_scheduler_starting(void) +{ + WARN_ON(num_online_cpus() != 1); + WARN_ON(nr_context_switches() > 0); + rcu_scheduler_active = 1; +} + static DEFINE_PER_CPU(struct rcu_head, rcu_barrier_head) = {NULL}; static atomic_t rcu_barrier_cpu_count; static DEFINE_MUTEX(rcu_barrier_mutex); diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 0bdb592eee6..1d295c789d3 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -425,6 +425,30 @@ void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) } EXPORT_SYMBOL_GPL(call_rcu); +/** + * synchronize_rcu - wait until a grace period has elapsed. + * + * Control will return to the caller some time after a full grace + * period has elapsed, in other words after all currently executing RCU + * read-side critical sections have completed. RCU read-side critical + * sections are delimited by rcu_read_lock() and rcu_read_unlock(), + * and may be nested. + */ +void synchronize_rcu(void) +{ + struct rcu_synchronize rcu; + + if (!rcu_scheduler_active) + return; + + init_completion(&rcu.completion); + /* Will wake me after RCU finished. */ + call_rcu(&rcu.head, wakeme_after_rcu); + /* Wait for it. */ + wait_for_completion(&rcu.completion); +} +EXPORT_SYMBOL_GPL(synchronize_rcu); + /* * Wait for an rcu-preempt grace period. We are supposed to expedite the * grace period, but this is the crude slow compatability hack, so just From 85c3b529f8ad4d65ba86b982ef050212ae7dd976 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Fri, 20 Nov 2009 11:00:12 -0500 Subject: [PATCH 173/298] SELinux: header generation may hit infinite loop If a permission name is long enough the selinux class definition generation tool will go into a infinite loop. This is because it's macro max() is fooled into thinking it is dealing with unsigned numbers. This patch makes sure the macro always uses signed number so 1 > -1. Signed-off-by: Eric Paris Signed-off-by: James Morris --- scripts/selinux/genheaders/genheaders.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/selinux/genheaders/genheaders.c b/scripts/selinux/genheaders/genheaders.c index 771b86f4619..24626968055 100644 --- a/scripts/selinux/genheaders/genheaders.c +++ b/scripts/selinux/genheaders/genheaders.c @@ -13,7 +13,7 @@ struct security_class_mapping { #include "classmap.h" #include "initial_sid_to_string.h" -#define max(x, y) ((x > y) ? x : y) +#define max(x, y) (((int)(x) > (int)(y)) ? x : y) const char *progname; From 98e4833ba3c314c99dc364012fba6ac894230ad0 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 23 Nov 2009 08:03:09 +0100 Subject: [PATCH 174/298] ring-buffer benchmark: Run producer/consumer threads at nice +19 The ring-buffer benchmark threads run on nice 0 by default, using up a lot of CPU time and slowing down the system: PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1024 root 20 0 0 0 0 D 95.3 0.0 4:01.67 rb_producer 1023 root 20 0 0 0 0 R 93.5 0.0 2:54.33 rb_consumer 21569 mingo 40 0 14852 1048 772 R 3.6 0.1 0:00.05 top 1 root 40 0 4080 928 668 S 0.0 0.0 0:23.98 init Renice them to +19 to make them less intrusive. Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Mike Galbraith LKML-Reference: Signed-off-by: Ingo Molnar --- kernel/trace/ring_buffer_benchmark.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/trace/ring_buffer_benchmark.c b/kernel/trace/ring_buffer_benchmark.c index 70df73e4ff2..3875d49da99 100644 --- a/kernel/trace/ring_buffer_benchmark.c +++ b/kernel/trace/ring_buffer_benchmark.c @@ -399,6 +399,12 @@ static int __init ring_buffer_benchmark_init(void) if (IS_ERR(producer)) goto out_kill; + /* + * Run them as low-prio background tasks by default: + */ + set_user_nice(consumer, 19); + set_user_nice(producer, 19); + return 0; out_kill: From 457dc928f586f3f4b930206965e6db270034e97e Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 23 Nov 2009 11:03:28 +0100 Subject: [PATCH 175/298] tracing, function tracer: Clean up strstrip() usage Clean up strstrip() usage - which also addresses this build warning: kernel/trace/ftrace.c: In function 'ftrace_pid_write': kernel/trace/ftrace.c:3004: warning: ignoring return value of 'strstrip', declared with attribute warn_unused_result Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo LKML-Reference: Signed-off-by: Ingo Molnar --- kernel/trace/ftrace.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 7f9b51e8184..1dc101d0976 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -2985,7 +2985,7 @@ static ssize_t ftrace_pid_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { - char buf[64]; + char buf[64], *tmp; long val; int ret; @@ -3001,11 +3001,11 @@ ftrace_pid_write(struct file *filp, const char __user *ubuf, * Allow "echo > set_ftrace_pid" or "echo -n '' > set_ftrace_pid" * to clean the filter quietly. */ - strstrip(buf); - if (strlen(buf) == 0) + tmp = strstrip(buf); + if (strlen(tmp) == 0) return 1; - ret = strict_strtol(buf, 10, &val); + ret = strict_strtol(tmp, 10, &val); if (ret < 0) return ret; @@ -3391,4 +3391,3 @@ void ftrace_graph_stop(void) ftrace_stop(); } #endif - From 9f800de38b05d84809e89f16671d636a140eede7 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 23 Nov 2009 12:45:25 +0100 Subject: [PATCH 176/298] x86/amd-iommu: un__init iommu_setup_msi This function may be called on the resume path and can not be dropped after booting. Cc: stable@kernel.org Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 0d4581e602a..72bdbdac9b4 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -926,7 +926,7 @@ static int __init init_iommu_all(struct acpi_table_header *table) * ****************************************************************************/ -static int __init iommu_setup_msi(struct amd_iommu *iommu) +static int iommu_setup_msi(struct amd_iommu *iommu) { int r; From be831297716036de5b24308447ecb69f1706a846 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 23 Nov 2009 12:50:00 +0100 Subject: [PATCH 177/298] x86/amd-iommu: attach devices to pre-allocated domains early For some devices the ACPI table may define unity map requirements which must me met when the IOMMU is enabled. So we need to attach devices to their domains as early as possible so that these mappings are in place when needed. This patch assigns the domains right after they are allocated. Otherwise this can result in I/O page faults before a driver binds to a device and BIOS is still using it. Cc: stable@kernel.org Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 093bd526c94..b74b2124758 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -2047,10 +2047,10 @@ static void prealloc_protection_domains(void) struct pci_dev *dev = NULL; struct dma_ops_domain *dma_dom; struct amd_iommu *iommu; - u16 devid; + u16 devid, __devid; while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - devid = calc_devid(dev->bus->number, dev->devfn); + __devid = devid = calc_devid(dev->bus->number, dev->devfn); if (devid > amd_iommu_last_bdf) continue; devid = amd_iommu_alias_table[devid]; @@ -2065,6 +2065,10 @@ static void prealloc_protection_domains(void) init_unity_mappings_for_device(dma_dom, devid); dma_dom->target_dev = devid; + attach_device(iommu, &dma_dom->domain, devid); + if (__devid != devid) + attach_device(iommu, &dma_dom->domain, __devid); + list_add_tail(&dma_dom->list, &iommu_pd_list); } } From fe542cf59bf0b31afe72b9e9749c0f6645419fa0 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sun, 22 Nov 2009 11:49:55 +0900 Subject: [PATCH 178/298] LSM: Move security_path_chmod()/security_path_chown() to after mutex_lock(). We should call security_path_chmod()/security_path_chown() after mutex_lock() in order to avoid races. Signed-off-by: Tetsuo Handa Acked-by: John Johansen Signed-off-by: James Morris --- fs/open.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/fs/open.c b/fs/open.c index 201041dfca5..b4b31d277f3 100644 --- a/fs/open.c +++ b/fs/open.c @@ -619,17 +619,17 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode) err = mnt_want_write_file(file); if (err) goto out_putf; + mutex_lock(&inode->i_mutex); err = security_path_chmod(dentry, file->f_vfsmnt, mode); if (err) - goto out_drop_write; - mutex_lock(&inode->i_mutex); + goto out_unlock; if (mode == (mode_t) -1) mode = inode->i_mode; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; err = notify_change(dentry, &newattrs); +out_unlock: mutex_unlock(&inode->i_mutex); -out_drop_write: mnt_drop_write(file->f_path.mnt); out_putf: fput(file); @@ -652,17 +652,17 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode) error = mnt_want_write(path.mnt); if (error) goto dput_and_out; + mutex_lock(&inode->i_mutex); error = security_path_chmod(path.dentry, path.mnt, mode); if (error) - goto out_drop_write; - mutex_lock(&inode->i_mutex); + goto out_unlock; if (mode == (mode_t) -1) mode = inode->i_mode; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; error = notify_change(path.dentry, &newattrs); +out_unlock: mutex_unlock(&inode->i_mutex); -out_drop_write: mnt_drop_write(path.mnt); dput_and_out: path_put(&path); @@ -675,9 +675,9 @@ SYSCALL_DEFINE2(chmod, const char __user *, filename, mode_t, mode) return sys_fchmodat(AT_FDCWD, filename, mode); } -static int chown_common(struct dentry * dentry, uid_t user, gid_t group) +static int chown_common(struct path *path, uid_t user, gid_t group) { - struct inode *inode = dentry->d_inode; + struct inode *inode = path->dentry->d_inode; int error; struct iattr newattrs; @@ -694,7 +694,9 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group) newattrs.ia_valid |= ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; mutex_lock(&inode->i_mutex); - error = notify_change(dentry, &newattrs); + error = security_path_chown(path, user, group); + if (!error) + error = notify_change(path->dentry, &newattrs); mutex_unlock(&inode->i_mutex); return error; @@ -711,9 +713,7 @@ SYSCALL_DEFINE3(chown, const char __user *, filename, uid_t, user, gid_t, group) error = mnt_want_write(path.mnt); if (error) goto out_release; - error = security_path_chown(&path, user, group); - if (!error) - error = chown_common(path.dentry, user, group); + error = chown_common(&path, user, group); mnt_drop_write(path.mnt); out_release: path_put(&path); @@ -738,9 +738,7 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user, error = mnt_want_write(path.mnt); if (error) goto out_release; - error = security_path_chown(&path, user, group); - if (!error) - error = chown_common(path.dentry, user, group); + error = chown_common(&path, user, group); mnt_drop_write(path.mnt); out_release: path_put(&path); @@ -759,9 +757,7 @@ SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group error = mnt_want_write(path.mnt); if (error) goto out_release; - error = security_path_chown(&path, user, group); - if (!error) - error = chown_common(path.dentry, user, group); + error = chown_common(&path, user, group); mnt_drop_write(path.mnt); out_release: path_put(&path); @@ -784,9 +780,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) goto out_fput; dentry = file->f_path.dentry; audit_inode(NULL, dentry); - error = security_path_chown(&file->f_path, user, group); - if (!error) - error = chown_common(dentry, user, group); + error = chown_common(&file->f_path, user, group); mnt_drop_write(file->f_path.mnt); out_fput: fput(file); From c4a5af54c8ef277a59189fc9358e190f3c1b8206 Mon Sep 17 00:00:00 2001 From: "Andrew G. Morgan" Date: Mon, 23 Nov 2009 04:57:52 +0000 Subject: [PATCH 179/298] Silence the existing API for capability version compatibility check. When libcap, or other libraries attempt to confirm/determine the supported capability version magic, they generally supply a NULL dataptr to capget(). In this case, while returning the supported/preferred magic (via a modified header content), the return code of this system call may be 0, -EINVAL, or -EFAULT. No libcap code depends on the previous -EINVAL etc. return code, and all of the above three return codes can accompany a valid (successful) attempt to determine the requested magic value. This patch cleans up the system call to return 0, if the call is successfully being used to determine the supported/preferred capability magic value. Signed-off-by: Andrew G. Morgan Acked-by: Steve Grubb Acked-by: Serge Hallyn Signed-off-by: James Morris --- kernel/capability.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/capability.c b/kernel/capability.c index c2316d3fa09..c450375e855 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -169,8 +169,8 @@ SYSCALL_DEFINE2(capget, cap_user_header_t, header, cap_user_data_t, dataptr) kernel_cap_t pE, pI, pP; ret = cap_validate_magic(header, &tocopy); - if (ret != 0) - return ret; + if ((dataptr == NULL) || (ret != 0)) + return ((dataptr == NULL) && (ret == -EINVAL)) ? 0 : ret; if (get_user(pid, &header->pid)) return -EFAULT; From 0bce95279909aa4cc401a2e3140b4295ca22e72a Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Mon, 23 Nov 2009 16:47:23 -0500 Subject: [PATCH 180/298] SELinux: print denials for buggy kernel with unknown perms Historically we've seen cases where permissions are requested for classes where they do not exist. In particular we have seen CIFS forget to set i_mode to indicate it is a directory so when we later check something like remove_name we have problems since it wasn't defined in tclass file. This used to result in a avc which included the permission 0x2000 or something. Currently the kernel will deny the operations (good thing) but will not print ANY information (bad thing). First the auditdeny field is no extended to include unknown permissions. After that is fixed the logic in avc_dump_query to output this information isn't right since it will remove the permission from the av and print the phrase "". This takes us back to the behavior before the classmap rewrite. Signed-off-by: Eric Paris Signed-off-by: James Morris --- security/selinux/avc.c | 2 +- security/selinux/ss/services.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 18f4103e02b..f2dde268165 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -117,7 +117,7 @@ static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) i = 0; perm = 1; while (i < (sizeof(av) * 8)) { - if (perm & av) { + if ((perm & av) && perms[i]) { audit_log_format(ab, " %s", perms[i]); av &= ~perm; } diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 77f6e54bb43..d6bb20cbad6 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -239,6 +239,13 @@ static void map_decision(u16 tclass, struct av_decision *avd, if (!allow_unknown && !current_mapping[tclass].perms[i]) result |= 1<auditdeny = result; } } From b3a222e52e4d4be77cc4520a57af1a4a0d8222d1 Mon Sep 17 00:00:00 2001 From: "Serge E. Hallyn" Date: Mon, 23 Nov 2009 16:21:30 -0600 Subject: [PATCH 181/298] remove CONFIG_SECURITY_FILE_CAPABILITIES compile option As far as I know, all distros currently ship kernels with default CONFIG_SECURITY_FILE_CAPABILITIES=y. Since having the option on leaves a 'no_file_caps' option to boot without file capabilities, the main reason to keep the option is that turning it off saves you (on my s390x partition) 5k. In particular, vmlinux sizes came to: without patch fscaps=n: 53598392 without patch fscaps=y: 53603406 with this patch applied: 53603342 with the security-next tree. Against this we must weigh the fact that there is no simple way for userspace to figure out whether file capabilities are supported, while things like per-process securebits, capability bounding sets, and adding bits to pI if CAP_SETPCAP is in pE are not supported with SECURITY_FILE_CAPABILITIES=n, leaving a bit of a problem for applications wanting to know whether they can use them and/or why something failed. It also adds another subtly different set of semantics which we must maintain at the risk of severe security regressions. So this patch removes the SECURITY_FILE_CAPABILITIES compile option. It drops the kernel size by about 50k over the stock SECURITY_FILE_CAPABILITIES=y kernel, by removing the cap_limit_ptraced_target() function. Changelog: Nov 20: remove cap_limit_ptraced_target() as it's logic was ifndef'ed. Signed-off-by: Serge E. Hallyn Acked-by: Andrew G. Morgan" Signed-off-by: James Morris --- include/linux/capability.h | 2 -- include/linux/init_task.h | 4 --- kernel/capability.c | 2 -- security/Kconfig | 9 ----- security/commoncap.c | 72 ++------------------------------------ 5 files changed, 2 insertions(+), 87 deletions(-) diff --git a/include/linux/capability.h b/include/linux/capability.h index c8f2a5f70ed..39e5ff512fb 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -92,9 +92,7 @@ struct vfs_cap_data { #define _KERNEL_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_3 #define _KERNEL_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_3 -#ifdef CONFIG_SECURITY_FILE_CAPABILITIES extern int file_caps_enabled; -#endif typedef struct kernel_cap_struct { __u32 cap[_KERNEL_CAPABILITY_U32S]; diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 21a6f5d9af2..8d10aa7fd4c 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -83,16 +83,12 @@ extern struct group_info init_groups; #define INIT_IDS #endif -#ifdef CONFIG_SECURITY_FILE_CAPABILITIES /* * Because of the reduced scope of CAP_SETPCAP when filesystem * capabilities are in effect, it is safe to allow CAP_SETPCAP to * be available in the default configuration. */ # define CAP_INIT_BSET CAP_FULL_SET -#else -# define CAP_INIT_BSET CAP_INIT_EFF_SET -#endif #ifdef CONFIG_TREE_PREEMPT_RCU #define INIT_TASK_RCU_PREEMPT(tsk) \ diff --git a/kernel/capability.c b/kernel/capability.c index c450375e855..7f876e60521 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -29,7 +29,6 @@ EXPORT_SYMBOL(__cap_empty_set); EXPORT_SYMBOL(__cap_full_set); EXPORT_SYMBOL(__cap_init_eff_set); -#ifdef CONFIG_SECURITY_FILE_CAPABILITIES int file_caps_enabled = 1; static int __init file_caps_disable(char *str) @@ -38,7 +37,6 @@ static int __init file_caps_disable(char *str) return 1; } __setup("no_file_caps", file_caps_disable); -#endif /* * More recent versions of libcap are available from: diff --git a/security/Kconfig b/security/Kconfig index 95cc08913ca..226b9556b25 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -91,15 +91,6 @@ config SECURITY_PATH implement pathname based access controls. If you are unsure how to answer this question, answer N. -config SECURITY_FILE_CAPABILITIES - bool "File POSIX Capabilities" - default n - help - This enables filesystem capabilities, allowing you to give - binaries a subset of root's powers without using setuid 0. - - If in doubt, answer N. - config INTEL_TXT bool "Enable Intel(R) Trusted Execution Technology (Intel(R) TXT)" depends on HAVE_INTEL_TXT diff --git a/security/commoncap.c b/security/commoncap.c index 45b87af4ae5..f800fdb3de9 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -173,7 +173,6 @@ int cap_capget(struct task_struct *target, kernel_cap_t *effective, */ static inline int cap_inh_is_capped(void) { -#ifdef CONFIG_SECURITY_FILE_CAPABILITIES /* they are so limited unless the current task has the CAP_SETPCAP * capability @@ -181,7 +180,6 @@ static inline int cap_inh_is_capped(void) if (cap_capable(current, current_cred(), CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0) return 0; -#endif return 1; } @@ -239,8 +237,6 @@ static inline void bprm_clear_caps(struct linux_binprm *bprm) bprm->cap_effective = false; } -#ifdef CONFIG_SECURITY_FILE_CAPABILITIES - /** * cap_inode_need_killpriv - Determine if inode change affects privileges * @dentry: The inode/dentry in being changed with change marked ATTR_KILL_PRIV @@ -421,49 +417,6 @@ out: return rc; } -#else -int cap_inode_need_killpriv(struct dentry *dentry) -{ - return 0; -} - -int cap_inode_killpriv(struct dentry *dentry) -{ - return 0; -} - -int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps) -{ - memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data)); - return -ENODATA; -} - -static inline int get_file_caps(struct linux_binprm *bprm, bool *effective) -{ - bprm_clear_caps(bprm); - return 0; -} -#endif - -/* - * Determine whether a exec'ing process's new permitted capabilities should be - * limited to just what it already has. - * - * This prevents processes that are being ptraced from gaining access to - * CAP_SETPCAP, unless the process they're tracing already has it, and the - * binary they're executing has filecaps that elevate it. - * - * Returns 1 if they should be limited, 0 if they are not. - */ -static inline int cap_limit_ptraced_target(void) -{ -#ifndef CONFIG_SECURITY_FILE_CAPABILITIES - if (capable(CAP_SETPCAP)) - return 0; -#endif - return 1; -} - /** * cap_bprm_set_creds - Set up the proposed credentials for execve(). * @bprm: The execution parameters, including the proposed creds @@ -523,9 +476,8 @@ skip: new->euid = new->uid; new->egid = new->gid; } - if (cap_limit_ptraced_target()) - new->cap_permitted = cap_intersect(new->cap_permitted, - old->cap_permitted); + new->cap_permitted = cap_intersect(new->cap_permitted, + old->cap_permitted); } new->suid = new->fsuid = new->euid; @@ -739,7 +691,6 @@ int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags) return 0; } -#ifdef CONFIG_SECURITY_FILE_CAPABILITIES /* * Rationale: code calling task_setscheduler, task_setioprio, and * task_setnice, assumes that @@ -820,22 +771,6 @@ static long cap_prctl_drop(struct cred *new, unsigned long cap) return 0; } -#else -int cap_task_setscheduler (struct task_struct *p, int policy, - struct sched_param *lp) -{ - return 0; -} -int cap_task_setioprio (struct task_struct *p, int ioprio) -{ - return 0; -} -int cap_task_setnice (struct task_struct *p, int nice) -{ - return 0; -} -#endif - /** * cap_task_prctl - Implement process control functions for this security module * @option: The process control function requested @@ -866,7 +801,6 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, error = !!cap_raised(new->cap_bset, arg2); goto no_change; -#ifdef CONFIG_SECURITY_FILE_CAPABILITIES case PR_CAPBSET_DROP: error = cap_prctl_drop(new, arg2); if (error < 0) @@ -917,8 +851,6 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, error = new->securebits; goto no_change; -#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ - case PR_GET_KEEPCAPS: if (issecure(SECURE_KEEP_CAPS)) error = 1; From c9286b7e293a1ea054e857ff3f5a23d0ad8d4f36 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 16 Nov 2009 19:50:38 +0100 Subject: [PATCH 182/298] locking: Remove unused prototype commit 910067d1(remove generic__raw_read_trylock()) removed the implementation but left the prototype around. Remove it. Signed-off-by: Thomas Gleixner --- include/linux/spinlock.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index f0ca7a7a175..faf1482028d 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -79,8 +79,6 @@ */ #include -extern int __lockfunc generic__raw_read_trylock(raw_rwlock_t *lock); - /* * Pull the __raw*() functions/declarations (UP-nondebug doesnt need them): */ From a49ed0bf427a8328a3296eebedc7697fe5098dbf Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 16 Nov 2009 19:57:50 +0100 Subject: [PATCH 183/298] locking: Use __[SPIN|RW]_LOCK_UNLOCKED in [spin|rw]_lock_init() SPIN_LOCK_UNLOCKED and RW_LOCK_UNLOCKED are deprecated. Replace them with the __*_LOCK_UNLOCKED variants. Signed-off-by: Thomas Gleixner --- include/linux/spinlock.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index faf1482028d..71dccfeb0d8 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -100,7 +100,7 @@ do { \ #else # define spin_lock_init(lock) \ - do { *(lock) = SPIN_LOCK_UNLOCKED; } while (0) + do { *(lock) = __SPIN_LOCK_UNLOCKED(lock); } while (0) #endif #ifdef CONFIG_DEBUG_SPINLOCK @@ -114,7 +114,7 @@ do { \ } while (0) #else # define rwlock_init(lock) \ - do { *(lock) = RW_LOCK_UNLOCKED; } while (0) + do { *(lock) = __RW_LOCK_UNLOCKED(lock); } while (0) #endif #define spin_is_locked(lock) __raw_spin_is_locked(&(lock)->raw_lock) From 7539cf4b92be4aecc573ea962135f246a7a33401 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 24 Nov 2009 22:00:05 +0900 Subject: [PATCH 184/298] TOMOYO: Add recursive directory matching operator support. TOMOYO 1.7.1 has recursive directory matching operator support. I want to add it to TOMOYO for Linux 2.6.33 . ---------- [PATCH] TOMOYO: Add recursive directory matching operator support. This patch introduces new operator /\{dir\}/ which matches '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/ /dir/dir/dir/ ). Signed-off-by: Tetsuo Handa Acked-by: John Johansen Signed-off-by: James Morris --- security/tomoyo/common.c | 216 +++++++++++++++++++++++---------------- security/tomoyo/common.h | 4 - 2 files changed, 129 insertions(+), 91 deletions(-) diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 3c8bd8ee0b9..e0d0354008b 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -187,6 +187,8 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, const s8 pattern_type, const s8 end_type, const char *function) { + const char *const start = filename; + bool in_repetition = false; bool contains_pattern = false; unsigned char c; unsigned char d; @@ -212,9 +214,13 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, if (c == '/') goto out; } - while ((c = *filename++) != '\0') { + while (1) { + c = *filename++; + if (!c) + break; if (c == '\\') { - switch ((c = *filename++)) { + c = *filename++; + switch (c) { case '\\': /* "\\" */ continue; case '$': /* "\$" */ @@ -231,6 +237,22 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, break; /* Must not contain pattern */ contains_pattern = true; continue; + case '{': /* "/\{" */ + if (filename - 3 < start || + *(filename - 3) != '/') + break; + if (pattern_type == -1) + break; /* Must not contain pattern */ + contains_pattern = true; + in_repetition = true; + continue; + case '}': /* "\}/" */ + if (*filename != '/') + break; + if (!in_repetition) + break; + in_repetition = false; + continue; case '0': /* "\ooo" */ case '1': case '2': @@ -246,6 +268,8 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, continue; /* pattern is not \000 */ } goto out; + } else if (in_repetition && c == '/') { + goto out; } else if (tomoyo_is_invalid(c)) { goto out; } @@ -254,6 +278,8 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, if (!contains_pattern) goto out; } + if (in_repetition) + goto out; return true; out: printk(KERN_DEBUG "%s: Invalid pathname '%s'\n", function, @@ -359,33 +385,6 @@ struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) return NULL; } -/** - * tomoyo_path_depth - Evaluate the number of '/' in a string. - * - * @pathname: The string to evaluate. - * - * Returns path depth of the string. - * - * I score 2 for each of the '/' in the @pathname - * and score 1 if the @pathname ends with '/'. - */ -static int tomoyo_path_depth(const char *pathname) -{ - int i = 0; - - if (pathname) { - const char *ep = pathname + strlen(pathname); - if (pathname < ep--) { - if (*ep != '/') - i++; - while (pathname <= ep) - if (*ep-- == '/') - i += 2; - } - } - return i; -} - /** * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token. * @@ -444,11 +443,10 @@ void tomoyo_fill_path_info(struct tomoyo_path_info *ptr) ptr->is_dir = len && (name[len - 1] == '/'); ptr->is_patterned = (ptr->const_len < len); ptr->hash = full_name_hash(name, len); - ptr->depth = tomoyo_path_depth(name); } /** - * tomoyo_file_matches_to_pattern2 - Pattern matching without '/' character + * tomoyo_file_matches_pattern2 - Pattern matching without '/' character * and "\-" pattern. * * @filename: The start of string to check. @@ -458,10 +456,10 @@ void tomoyo_fill_path_info(struct tomoyo_path_info *ptr) * * Returns true if @filename matches @pattern, false otherwise. */ -static bool tomoyo_file_matches_to_pattern2(const char *filename, - const char *filename_end, - const char *pattern, - const char *pattern_end) +static bool tomoyo_file_matches_pattern2(const char *filename, + const char *filename_end, + const char *pattern, + const char *pattern_end) { while (filename < filename_end && pattern < pattern_end) { char c; @@ -519,7 +517,7 @@ static bool tomoyo_file_matches_to_pattern2(const char *filename, case '*': case '@': for (i = 0; i <= filename_end - filename; i++) { - if (tomoyo_file_matches_to_pattern2( + if (tomoyo_file_matches_pattern2( filename + i, filename_end, pattern + 1, pattern_end)) return true; @@ -550,7 +548,7 @@ static bool tomoyo_file_matches_to_pattern2(const char *filename, j++; } for (i = 1; i <= j; i++) { - if (tomoyo_file_matches_to_pattern2( + if (tomoyo_file_matches_pattern2( filename + i, filename_end, pattern + 1, pattern_end)) return true; @@ -567,7 +565,7 @@ static bool tomoyo_file_matches_to_pattern2(const char *filename, } /** - * tomoyo_file_matches_to_pattern - Pattern matching without without '/' character. + * tomoyo_file_matches_pattern - Pattern matching without without '/' character. * * @filename: The start of string to check. * @filename_end: The end of string to check. @@ -576,7 +574,7 @@ static bool tomoyo_file_matches_to_pattern2(const char *filename, * * Returns true if @filename matches @pattern, false otherwise. */ -static bool tomoyo_file_matches_to_pattern(const char *filename, +static bool tomoyo_file_matches_pattern(const char *filename, const char *filename_end, const char *pattern, const char *pattern_end) @@ -589,10 +587,10 @@ static bool tomoyo_file_matches_to_pattern(const char *filename, /* Split at "\-" pattern. */ if (*pattern++ != '\\' || *pattern++ != '-') continue; - result = tomoyo_file_matches_to_pattern2(filename, - filename_end, - pattern_start, - pattern - 2); + result = tomoyo_file_matches_pattern2(filename, + filename_end, + pattern_start, + pattern - 2); if (first) result = !result; if (result) @@ -600,64 +598,35 @@ static bool tomoyo_file_matches_to_pattern(const char *filename, first = false; pattern_start = pattern; } - result = tomoyo_file_matches_to_pattern2(filename, filename_end, - pattern_start, pattern_end); + result = tomoyo_file_matches_pattern2(filename, filename_end, + pattern_start, pattern_end); return first ? result : !result; } /** - * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern. - * @filename: The filename to check. - * @pattern: The pattern to compare. + * tomoyo_path_matches_pattern2 - Do pathname pattern matching. * - * Returns true if matches, false otherwise. + * @f: The start of string to check. + * @p: The start of pattern to compare. * - * The following patterns are available. - * \\ \ itself. - * \ooo Octal representation of a byte. - * \* More than or equals to 0 character other than '/'. - * \@ More than or equals to 0 character other than '/' or '.'. - * \? 1 byte character other than '/'. - * \$ More than or equals to 1 decimal digit. - * \+ 1 decimal digit. - * \X More than or equals to 1 hexadecimal digit. - * \x 1 hexadecimal digit. - * \A More than or equals to 1 alphabet character. - * \a 1 alphabet character. - * \- Subtraction operator. + * Returns true if @f matches @p, false otherwise. */ -bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, - const struct tomoyo_path_info *pattern) +static bool tomoyo_path_matches_pattern2(const char *f, const char *p) { - /* - if (!filename || !pattern) - return false; - */ - const char *f = filename->name; - const char *p = pattern->name; - const int len = pattern->const_len; + const char *f_delimiter; + const char *p_delimiter; - /* If @pattern doesn't contain pattern, I can use strcmp(). */ - if (!pattern->is_patterned) - return !tomoyo_pathcmp(filename, pattern); - /* Dont compare if the number of '/' differs. */ - if (filename->depth != pattern->depth) - return false; - /* Compare the initial length without patterns. */ - if (strncmp(f, p, len)) - return false; - f += len; - p += len; - /* Main loop. Compare each directory component. */ while (*f && *p) { - const char *f_delimiter = strchr(f, '/'); - const char *p_delimiter = strchr(p, '/'); + f_delimiter = strchr(f, '/'); if (!f_delimiter) f_delimiter = f + strlen(f); + p_delimiter = strchr(p, '/'); if (!p_delimiter) p_delimiter = p + strlen(p); - if (!tomoyo_file_matches_to_pattern(f, f_delimiter, - p, p_delimiter)) + if (*p == '\\' && *(p + 1) == '{') + goto recursive; + if (!tomoyo_file_matches_pattern(f, f_delimiter, p, + p_delimiter)) return false; f = f_delimiter; if (*f) @@ -671,6 +640,79 @@ bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, (*(p + 1) == '*' || *(p + 1) == '@')) p += 2; return !*f && !*p; + recursive: + /* + * The "\{" pattern is permitted only after '/' character. + * This guarantees that below "*(p - 1)" is safe. + * Also, the "\}" pattern is permitted only before '/' character + * so that "\{" + "\}" pair will not break the "\-" operator. + */ + if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' || + *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\') + return false; /* Bad pattern. */ + do { + /* Compare current component with pattern. */ + if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2, + p_delimiter - 2)) + break; + /* Proceed to next component. */ + f = f_delimiter; + if (!*f) + break; + f++; + /* Continue comparison. */ + if (tomoyo_path_matches_pattern2(f, p_delimiter + 1)) + return true; + f_delimiter = strchr(f, '/'); + } while (f_delimiter); + return false; /* Not matched. */ +} + +/** + * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern. + * + * @filename: The filename to check. + * @pattern: The pattern to compare. + * + * Returns true if matches, false otherwise. + * + * The following patterns are available. + * \\ \ itself. + * \ooo Octal representation of a byte. + * \* Zero or more repetitions of characters other than '/'. + * \@ Zero or more repetitions of characters other than '/' or '.'. + * \? 1 byte character other than '/'. + * \$ One or more repetitions of decimal digits. + * \+ 1 decimal digit. + * \X One or more repetitions of hexadecimal digits. + * \x 1 hexadecimal digit. + * \A One or more repetitions of alphabet characters. + * \a 1 alphabet character. + * + * \- Subtraction operator. + * + * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/ + * /dir/dir/dir/ ). + */ +bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, + const struct tomoyo_path_info *pattern) +{ + const char *f = filename->name; + const char *p = pattern->name; + const int len = pattern->const_len; + + /* If @pattern doesn't contain pattern, I can use strcmp(). */ + if (!pattern->is_patterned) + return !tomoyo_pathcmp(filename, pattern); + /* Don't compare directory and non-directory. */ + if (filename->is_dir != pattern->is_dir) + return false; + /* Compare the initial length without patterns. */ + if (strncmp(f, p, len)) + return false; + f += len; + p += len; + return tomoyo_path_matches_pattern2(f, p); } /** diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 31df541911f..92169d29b2d 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -56,9 +56,6 @@ struct tomoyo_page_buffer { * (5) "is_patterned" is a bool which is true if "name" contains wildcard * characters, false otherwise. This allows TOMOYO to use "hash" and * strcmp() for string comparison if "is_patterned" is false. - * (6) "depth" is calculated using the number of "/" characters in "name". - * This allows TOMOYO to avoid comparing two pathnames which never match - * (e.g. whether "/var/www/html/index.html" matches "/tmp/sh-thd-\$"). */ struct tomoyo_path_info { const char *name; @@ -66,7 +63,6 @@ struct tomoyo_path_info { u16 const_len; /* = tomoyo_const_part_length(name) */ bool is_dir; /* = tomoyo_strendswith(name, "/") */ bool is_patterned; /* = tomoyo_path_contains_pattern(name) */ - u16 depth; /* = tomoyo_path_depth(name) */ }; /* From 273bee27fa9f79d94b78c83506016f2e41e78983 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Wed, 25 Nov 2009 08:46:28 +0900 Subject: [PATCH 185/298] x86: Fix iommu=soft boot option iommu=soft boot option forces the kernel to use swiotlb. ( This has the side-effect of enabling the swiotlb over the GART if this boot option is provided. This is the desired behavior of the swiotlb boot option and works like that for all other hw-IOMMU drivers. ) Signed-off-by: FUJITA Tomonori Cc: yinghai@kernel.org LKML-Reference: <20091125084611O.fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Ingo Molnar --- arch/x86/kernel/pci-swiotlb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c index e36e71daa44..e3c0a66b9e7 100644 --- a/arch/x86/kernel/pci-swiotlb.c +++ b/arch/x86/kernel/pci-swiotlb.c @@ -50,6 +50,8 @@ static struct dma_map_ops swiotlb_dma_ops = { */ int __init pci_swiotlb_init(void) { + int use_swiotlb = swiotlb | swiotlb_force; + /* don't initialize swiotlb if iommu=off (no_iommu=1) */ #ifdef CONFIG_X86_64 if (!no_iommu && max_pfn > MAX_DMA32_PFN) @@ -63,5 +65,5 @@ int __init pci_swiotlb_init(void) dma_ops = &swiotlb_dma_ops; } - return swiotlb_force; + return use_swiotlb; } From 7ac074340480018681a0d72b324d4487543bdc0e Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 25 Nov 2009 13:22:21 -0500 Subject: [PATCH 186/298] ring-buffer-benchmark: Add parameters to set produce/consumer priorities Running the ring-buffer-benchmark's threads at the lowest priority may work well for keeping it in the background, but it is not appropriate for the benchmarks. This patch adds 4 parameters to the module: consumer_fifo consumer_nice producer_fifo producer_nice By default the consumer and producer still run at nice +19. If the *_fifo options are set, they will override the *_nice values. modprobe ring_buffer_benchmark consumer_nice=0 producer_fifo=10 The above will set the consumer thread to a nice value of 0, and the producer thread to a RT SCHED_FIFO priority of 10. Note, this patch also fixes a bug where calling set_user_nice on the consumer thread would oops the kernel when the parameter "disable_reader" is set. Signed-off-by: Steven Rostedt --- kernel/trace/ring_buffer_benchmark.c | 58 +++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/kernel/trace/ring_buffer_benchmark.c b/kernel/trace/ring_buffer_benchmark.c index 3875d49da99..b2477caf09c 100644 --- a/kernel/trace/ring_buffer_benchmark.c +++ b/kernel/trace/ring_buffer_benchmark.c @@ -39,6 +39,24 @@ static int write_iteration = 50; module_param(write_iteration, uint, 0644); MODULE_PARM_DESC(write_iteration, "# of writes between timestamp readings"); +static int producer_nice = 19; +static int consumer_nice = 19; + +static int producer_fifo = -1; +static int consumer_fifo = -1; + +module_param(producer_nice, uint, 0644); +MODULE_PARM_DESC(producer_nice, "nice prio for producer"); + +module_param(consumer_nice, uint, 0644); +MODULE_PARM_DESC(consumer_nice, "nice prio for consumer"); + +module_param(producer_fifo, uint, 0644); +MODULE_PARM_DESC(producer_fifo, "fifo prio for producer"); + +module_param(consumer_fifo, uint, 0644); +MODULE_PARM_DESC(consumer_fifo, "fifo prio for consumer"); + static int read_events; static int kill_test; @@ -270,6 +288,27 @@ static void ring_buffer_producer(void) if (kill_test) trace_printk("ERROR!\n"); + + if (!disable_reader) { + if (consumer_fifo < 0) + trace_printk("Running Consumer at nice: %d\n", + consumer_nice); + else + trace_printk("Running Consumer at SCHED_FIFO %d\n", + consumer_fifo); + } + if (producer_fifo < 0) + trace_printk("Running Producer at nice: %d\n", + producer_nice); + else + trace_printk("Running Producer at SCHED_FIFO %d\n", + producer_fifo); + + /* Let the user know that the test is running at low priority */ + if (producer_fifo < 0 && consumer_fifo < 0 && + producer_nice == 19 && consumer_nice == 19) + trace_printk("WARNING!!! This test is running at lowest priority.\n"); + trace_printk("Time: %lld (usecs)\n", time); trace_printk("Overruns: %lld\n", overruns); if (disable_reader) @@ -402,8 +441,23 @@ static int __init ring_buffer_benchmark_init(void) /* * Run them as low-prio background tasks by default: */ - set_user_nice(consumer, 19); - set_user_nice(producer, 19); + if (!disable_reader) { + if (consumer_fifo >= 0) { + struct sched_param param = { + .sched_priority = consumer_fifo + }; + sched_setscheduler(consumer, SCHED_FIFO, ¶m); + } else + set_user_nice(consumer, consumer_nice); + } + + if (producer_fifo >= 0) { + struct sched_param param = { + .sched_priority = consumer_fifo + }; + sched_setscheduler(producer, SCHED_FIFO, ¶m); + } else + set_user_nice(producer, producer_nice); return 0; From b8007ef7422270864eae523cb38d7522a53a94d3 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 3 Nov 2009 13:45:32 +0800 Subject: [PATCH 187/298] tracing: Separate raw syscall from syscall tracer The current syscall tracer mixes raw syscalls and real syscalls. echo 1 > events/syscalls/enable And we get these from the output: (XXXX insteads " grep-20914 [001] 588211.446347" .. etc) XXXX: sys_read(fd: 3, buf: 80609a8, count: 7000) XXXX: sys_enter: NR 3 (3, 80609a8, 7000, a, 1000, bfce8ef8) XXXX: sys_read -> 0x138 XXXX: sys_exit: NR 3 = 312 XXXX: sys_read(fd: 3, buf: 8060ae0, count: 7000) XXXX: sys_enter: NR 3 (3, 8060ae0, 7000, a, 1000, bfce8ef8) XXXX: sys_read -> 0x138 XXXX: sys_exit: NR 3 = 312 There are 2 drawbacks here. A) two almost identical records are saved in ringbuffer when a syscall enters or exits. (4 records for every syscall) This wastes precious space in the ring buffer. B) the lines including "sys_enter/sys_exit" produces hardly any useful information for the output (no labels). The user can use this method to prevent these drawbacks: echo 1 > events/syscalls/enable echo 0 > events/syscalls/sys_enter/enable echo 0 > events/syscalls/sys_exit/enable But this is not user friendly. So we separate raw syscall from syscall tracer. After this fix applied: syscall tracer's output (echo 1 > events/syscalls/enable): XXXX: sys_read(fd: 3, buf: bfe87d88, count: 200) XXXX: sys_read -> 0x200 XXXX: sys_fstat64(fd: 3, statbuf: bfe87c98) XXXX: sys_fstat64 -> 0x0 XXXX: sys_close(fd: 3) raw syscall tracer's output (echo 1 > events/raw_syscalls/enable): XXXX: sys_enter: NR 175 (0, bf92bf18, bf92bf98, 8, b748cff4, bf92bef8) XXXX: sys_exit: NR 175 = 0 XXXX: sys_enter: NR 175 (2, bf92bf98, 0, 8, b748cff4, bf92bef8) XXXX: sys_exit: NR 175 = 0 XXXX: sys_enter: NR 3 (9, bf927f9c, 4000, b77e2518, b77dce60, bf92bff8) Signed-off-by: Lai Jiangshan LKML-Reference: <4AEFC37C.5080609@cn.fujitsu.com> Signed-off-by: Steven Rostedt --- include/trace/events/syscalls.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/trace/events/syscalls.h b/include/trace/events/syscalls.h index 397dff2dbd5..fb726ac7cae 100644 --- a/include/trace/events/syscalls.h +++ b/include/trace/events/syscalls.h @@ -1,5 +1,6 @@ #undef TRACE_SYSTEM -#define TRACE_SYSTEM syscalls +#define TRACE_SYSTEM raw_syscalls +#define TRACE_INCLUDE_FILE syscalls #if !defined(_TRACE_EVENTS_SYSCALLS_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_EVENTS_SYSCALLS_H From e5af02261668350b43eb7381648930bde8e872f7 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Fri, 27 Nov 2009 13:28:20 +1100 Subject: [PATCH 188/298] softlockup: Fix hung_task_check_count sysctl I'm seeing spikes of up to 0.5ms in khungtaskd on a large machine. To reduce this source of jitter I tried setting hung_task_check_count to 0: # echo 0 > /proc/sys/kernel/hung_task_check_count which didn't have the intended response. Change to a post increment of max_count, so a value of 0 means check 0 tasks. Signed-off-by: Anton Blanchard Acked-by: Frederic Weisbecker Cc: msb@google.com LKML-Reference: <20091127022820.GU32182@kryten> Signed-off-by: Ingo Molnar --- kernel/hung_task.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/hung_task.c b/kernel/hung_task.c index d4e84174740..0c642d51aac 100644 --- a/kernel/hung_task.c +++ b/kernel/hung_task.c @@ -144,7 +144,7 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) rcu_read_lock(); do_each_thread(g, t) { - if (!--max_count) + if (!max_count--) goto unlock; if (!--batch_count) { batch_count = HUNG_TASK_BATCHING; From 6a9401a7ac13e62ef2baf4d46e022d303edc3050 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 20 Nov 2009 13:22:21 +0100 Subject: [PATCH 189/298] x86/amd-iommu: Separate internal interface definitions This patch moves all function declarations which are only used inside the driver code to a seperate header file. Signed-off-by: Joerg Roedel --- arch/x86/include/asm/amd_iommu.h | 10 +++---- arch/x86/include/asm/amd_iommu_proto.h | 38 ++++++++++++++++++++++++++ arch/x86/include/asm/amd_iommu_types.h | 5 ---- arch/x86/kernel/amd_iommu.c | 1 + arch/x86/kernel/amd_iommu_init.c | 1 + 5 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 arch/x86/include/asm/amd_iommu_proto.h diff --git a/arch/x86/include/asm/amd_iommu.h b/arch/x86/include/asm/amd_iommu.h index b8ef2ee9364..089133899b3 100644 --- a/arch/x86/include/asm/amd_iommu.h +++ b/arch/x86/include/asm/amd_iommu.h @@ -23,15 +23,13 @@ #include #ifdef CONFIG_AMD_IOMMU -extern int amd_iommu_init_dma_ops(void); -extern int amd_iommu_init_passthrough(void); + extern void amd_iommu_detect(void); -extern irqreturn_t amd_iommu_int_handler(int irq, void *data); -extern void amd_iommu_flush_all_domains(void); -extern void amd_iommu_flush_all_devices(void); -extern void amd_iommu_apply_erratum_63(u16 devid); + #else + static inline void amd_iommu_detect(void) { } + #endif #endif /* _ASM_X86_AMD_IOMMU_H */ diff --git a/arch/x86/include/asm/amd_iommu_proto.h b/arch/x86/include/asm/amd_iommu_proto.h new file mode 100644 index 00000000000..84786fb9a23 --- /dev/null +++ b/arch/x86/include/asm/amd_iommu_proto.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009 Advanced Micro Devices, Inc. + * Author: Joerg Roedel + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * 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 + */ + +#ifndef _ASM_X86_AMD_IOMMU_PROTO_H +#define _ASM_X86_AMD_IOMMU_PROTO_H + +struct amd_iommu; + +extern int amd_iommu_init_dma_ops(void); +extern int amd_iommu_init_passthrough(void); +extern irqreturn_t amd_iommu_int_handler(int irq, void *data); +extern void amd_iommu_flush_all_domains(void); +extern void amd_iommu_flush_all_devices(void); +extern void amd_iommu_apply_erratum_63(u16 devid); +extern void amd_iommu_reset_cmd_buffer(struct amd_iommu *iommu); + +#ifndef CONFIG_AMD_IOMMU_STATS + +static inline void amd_iommu_stats_init(void) { } + +#endif /* !CONFIG_AMD_IOMMU_STATS */ + +#endif /* _ASM_X86_AMD_IOMMU_PROTO_H */ diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 2a2cc7a78a8..27db7f9c7ae 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -462,11 +462,6 @@ struct __iommu_counter { #define ADD_STATS_COUNTER(name, x) #define SUB_STATS_COUNTER(name, x) -static inline void amd_iommu_stats_init(void) { } - #endif /* CONFIG_AMD_IOMMU_STATS */ -/* some function prototypes */ -extern void amd_iommu_reset_cmd_buffer(struct amd_iommu *iommu); - #endif /* _ASM_X86_AMD_IOMMU_TYPES_H */ diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index b74b2124758..50d2b05a458 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 72bdbdac9b4..db30cfe86fc 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include From bf3118c1276d27fe9e84aa42382da25ee0750777 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 20 Nov 2009 13:39:19 +0100 Subject: [PATCH 190/298] x86/amd-iommu: Update copyright headers This patch updates the copyright headers in the relevant AMD IOMMU driver files to match the date of the latest changes. Signed-off-by: Joerg Roedel --- arch/x86/include/asm/amd_iommu.h | 2 +- arch/x86/include/asm/amd_iommu_types.h | 2 +- arch/x86/kernel/amd_iommu.c | 2 +- arch/x86/kernel/amd_iommu_init.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/amd_iommu.h b/arch/x86/include/asm/amd_iommu.h index 089133899b3..5af2982133b 100644 --- a/arch/x86/include/asm/amd_iommu.h +++ b/arch/x86/include/asm/amd_iommu.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2008 Advanced Micro Devices, Inc. + * Copyright (C) 2007-2009 Advanced Micro Devices, Inc. * Author: Joerg Roedel * Leo Duran * diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 27db7f9c7ae..df5e9c8a856 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2008 Advanced Micro Devices, Inc. + * Copyright (C) 2007-2009 Advanced Micro Devices, Inc. * Author: Joerg Roedel * Leo Duran * diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 50d2b05a458..7fe28be3b54 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2008 Advanced Micro Devices, Inc. + * Copyright (C) 2007-2009 Advanced Micro Devices, Inc. * Author: Joerg Roedel * Leo Duran * diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index db30cfe86fc..cee11424d41 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2008 Advanced Micro Devices, Inc. + * Copyright (C) 2007-2009 Advanced Micro Devices, Inc. * Author: Joerg Roedel * Leo Duran * From bb52777ec4d736c2d7c4f037b32d4eeeb172ed89 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 20 Nov 2009 14:31:51 +0100 Subject: [PATCH 191/298] x86/amd-iommu: Add an index field to struct amd_iommu This patch adds an index field to struct amd_iommu which can be used to lookup it up in an array. This index will be used in struct protection_domain to keep track which protection domain has devices behind which IOMMU. Signed-off-by: Joerg Roedel --- arch/x86/include/asm/amd_iommu_types.h | 17 +++++++++++++++++ arch/x86/kernel/amd_iommu_init.c | 15 +++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index df5e9c8a856..ab3e7bf1af7 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -24,6 +24,11 @@ #include #include +/* + * Maximum number of IOMMUs supported + */ +#define MAX_IOMMUS 32 + /* * some size calculation constants */ @@ -291,6 +296,9 @@ struct dma_ops_domain { struct amd_iommu { struct list_head list; + /* Index within the IOMMU array */ + int index; + /* locks the accesses to the hardware */ spinlock_t lock; @@ -356,6 +364,15 @@ struct amd_iommu { */ extern struct list_head amd_iommu_list; +/* + * Array with pointers to each IOMMU struct + * The indices are referenced in the protection domains + */ +extern struct amd_iommu *amd_iommus[MAX_IOMMUS]; + +/* Number of IOMMUs present in the system */ +extern int amd_iommus_present; + /* * Structure defining one entry in the device table */ diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index cee11424d41..8567d169802 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -137,6 +137,10 @@ bool amd_iommu_unmap_flush; /* if true, flush on every unmap */ LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the system */ +/* Array to assign indices to IOMMUs*/ +struct amd_iommu *amd_iommus[MAX_IOMMUS]; +int amd_iommus_present; + /* * Pointer to the device table which is shared by all AMD IOMMUs * it is indexed by the PCI device id or the HT unit id and contains @@ -840,7 +844,18 @@ static void __init free_iommu_all(void) static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) { spin_lock_init(&iommu->lock); + + /* Add IOMMU to internal data structures */ list_add_tail(&iommu->list, &amd_iommu_list); + iommu->index = amd_iommus_present++; + + if (unlikely(iommu->index >= MAX_IOMMUS)) { + WARN(1, "AMD-Vi: System has more IOMMUs than supported by this driver\n"); + return -ENOSYS; + } + + /* Index is fine - add IOMMU to the array */ + amd_iommus[iommu->index] = iommu; /* * Copy data from ACPI table entry to the iommu struct From c459611424d8b8396060eb766e23bd0c70c993bc Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 20 Nov 2009 14:57:32 +0100 Subject: [PATCH 192/298] x86/amd-iommu: Add per IOMMU reference counting This patch adds reference counting for protection domains per IOMMU. This allows a smarter TLB flushing strategy. Signed-off-by: Joerg Roedel --- arch/x86/include/asm/amd_iommu_types.h | 2 ++ arch/x86/kernel/amd_iommu.c | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index ab3e7bf1af7..e68b1481138 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -238,7 +238,9 @@ struct protection_domain { unsigned long flags; /* flags to find out type of domain */ bool updated; /* complete domain flush required */ unsigned dev_cnt; /* devices assigned to this domain */ + unsigned dev_iommu[MAX_IOMMUS]; /* per-IOMMU reference count */ void *priv; /* private data */ + }; /* diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 7fe28be3b54..8c38f008540 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1175,7 +1175,9 @@ static void __attach_device(struct amd_iommu *iommu, /* update DTE entry */ set_dte_entry(devid, domain); - domain->dev_cnt += 1; + /* Do reference counting */ + domain->dev_iommu[iommu->index] += 1; + domain->dev_cnt += 1; /* ready */ spin_unlock(&domain->lock); @@ -1209,6 +1211,9 @@ static void attach_device(struct amd_iommu *iommu, */ static void __detach_device(struct protection_domain *domain, u16 devid) { + struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; + + BUG_ON(!iommu); /* lock domain */ spin_lock(&domain->lock); @@ -1223,8 +1228,9 @@ static void __detach_device(struct protection_domain *domain, u16 devid) amd_iommu_apply_erratum_63(devid); - /* decrease reference counter */ - domain->dev_cnt -= 1; + /* decrease reference counters */ + domain->dev_iommu[iommu->index] -= 1; + domain->dev_cnt -= 1; /* ready */ spin_unlock(&domain->lock); From 0518a3a4585cb3eeeaf14ca57131f11d252130c6 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 20 Nov 2009 16:00:05 +0100 Subject: [PATCH 193/298] x86/amd-iommu: Add function to complete a tlb flush This patch adds a function to the AMD IOMMU driver which completes all queued commands an all IOMMUs a specific domain has devices attached on. This is required in a later patch when per-domain flushing is implemented. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 8c38f008540..8fa5cc3e02d 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -376,6 +376,22 @@ out: return 0; } +static void iommu_flush_complete(struct protection_domain *domain) +{ + int i; + + for (i = 0; i < amd_iommus_present; ++i) { + if (!domain->dev_iommu[i]) + continue; + + /* + * Devices of this domain are behind this IOMMU + * We need to wait for completion of all commands. + */ + iommu_completion_wait(amd_iommus[i]); + } +} + /* * Command send function for invalidating a device table entry */ @@ -1758,7 +1774,7 @@ static dma_addr_t map_page(struct device *dev, struct page *page, if (addr == DMA_ERROR_CODE) goto out; - iommu_completion_wait(iommu); + iommu_flush_complete(domain); out: spin_unlock_irqrestore(&domain->lock, flags); @@ -1791,7 +1807,7 @@ static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, __unmap_single(iommu, domain->priv, dma_addr, size, dir); - iommu_completion_wait(iommu); + iommu_flush_complete(domain); spin_unlock_irqrestore(&domain->lock, flags); } @@ -1863,7 +1879,7 @@ static int map_sg(struct device *dev, struct scatterlist *sglist, goto unmap; } - iommu_completion_wait(iommu); + iommu_flush_complete(domain); out: spin_unlock_irqrestore(&domain->lock, flags); @@ -1914,7 +1930,7 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist, s->dma_address = s->dma_length = 0; } - iommu_completion_wait(iommu); + iommu_flush_complete(domain); spin_unlock_irqrestore(&domain->lock, flags); } @@ -1969,7 +1985,7 @@ static void *alloc_coherent(struct device *dev, size_t size, goto out_free; } - iommu_completion_wait(iommu); + iommu_flush_complete(domain); spin_unlock_irqrestore(&domain->lock, flags); @@ -2010,7 +2026,7 @@ static void free_coherent(struct device *dev, size_t size, __unmap_single(iommu, domain->priv, dma_addr, size, DMA_BIDIRECTIONAL); - iommu_completion_wait(iommu); + iommu_flush_complete(domain); spin_unlock_irqrestore(&domain->lock, flags); From 6de8ad9b9ee0ec5b52ec8ec41401833e5e89186f Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 23 Nov 2009 18:30:32 +0100 Subject: [PATCH 194/298] x86/amd-iommu: Make iommu_flush_pages aware of multiple IOMMUs This patch extends the iommu_flush_pages function to flush the TLB entries on all IOMMUs the domain has devices on. This basically gives up the former assumption that dma_ops domains are only bound to one IOMMU in the system. For dma_ops domains this is still true but not for IOMMU-API managed domains. Giving this assumption up for dma_ops domains too allows code simplification. Further it splits out the main logic into a generic function which can be used by iommu_flush_tlb too. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 8fa5cc3e02d..7c06e574008 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -447,10 +447,10 @@ static int iommu_queue_inv_iommu_pages(struct amd_iommu *iommu, * It invalidates a single PTE if the range to flush is within a single * page. Otherwise it flushes the whole TLB of the IOMMU. */ -static int iommu_flush_pages(struct amd_iommu *iommu, u16 domid, - u64 address, size_t size) +static void __iommu_flush_pages(struct protection_domain *domain, + u64 address, size_t size, int pde) { - int s = 0; + int s = 0, i; unsigned pages = iommu_num_pages(address, size, PAGE_SIZE); address &= PAGE_MASK; @@ -464,9 +464,26 @@ static int iommu_flush_pages(struct amd_iommu *iommu, u16 domid, s = 1; } - iommu_queue_inv_iommu_pages(iommu, address, domid, 0, s); - return 0; + for (i = 0; i < amd_iommus_present; ++i) { + if (!domain->dev_iommu[i]) + continue; + + /* + * Devices of this domain are behind this IOMMU + * We need a TLB flush + */ + iommu_queue_inv_iommu_pages(amd_iommus[i], address, + domain->id, pde, s); + } + + return; +} + +static void iommu_flush_pages(struct protection_domain *domain, + u64 address, size_t size) +{ + __iommu_flush_pages(domain, address, size, 0); } /* Flush the whole IO/TLB for a given protection domain */ @@ -1683,7 +1700,7 @@ retry: iommu_flush_tlb(iommu, dma_dom->domain.id); dma_dom->need_flush = false; } else if (unlikely(iommu_has_npcache(iommu))) - iommu_flush_pages(iommu, dma_dom->domain.id, address, size); + iommu_flush_pages(&dma_dom->domain, address, size); out: return address; @@ -1731,7 +1748,7 @@ static void __unmap_single(struct amd_iommu *iommu, dma_ops_free_addresses(dma_dom, dma_addr, pages); if (amd_iommu_unmap_flush || dma_dom->need_flush) { - iommu_flush_pages(iommu, dma_dom->domain.id, dma_addr, size); + iommu_flush_pages(&dma_dom->domain, dma_addr, size); dma_dom->need_flush = false; } } From dcd1e92e405449ecc5e8bd8fcfebf3b2a13d3d37 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 20 Nov 2009 15:30:58 +0100 Subject: [PATCH 195/298] x86/amd-iommu: Use __iommu_flush_pages for tlb flushes This patch re-implements iommu_flush_tlb functions to use the __iommu_flush_pages logic. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 7c06e574008..c55aa079ded 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -451,7 +451,7 @@ static void __iommu_flush_pages(struct protection_domain *domain, u64 address, size_t size, int pde) { int s = 0, i; - unsigned pages = iommu_num_pages(address, size, PAGE_SIZE); + unsigned long pages = iommu_num_pages(address, size, PAGE_SIZE); address &= PAGE_MASK; @@ -487,23 +487,15 @@ static void iommu_flush_pages(struct protection_domain *domain, } /* Flush the whole IO/TLB for a given protection domain */ -static void iommu_flush_tlb(struct amd_iommu *iommu, u16 domid) +static void iommu_flush_tlb(struct protection_domain *domain) { - u64 address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS; - - INC_STATS_COUNTER(domain_flush_single); - - iommu_queue_inv_iommu_pages(iommu, address, domid, 0, 1); + __iommu_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 0); } /* Flush the whole IO/TLB for a given protection domain - including PDE */ -static void iommu_flush_tlb_pde(struct amd_iommu *iommu, u16 domid) +static void iommu_flush_tlb_pde(struct protection_domain *domain) { - u64 address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS; - - INC_STATS_COUNTER(domain_flush_single); - - iommu_queue_inv_iommu_pages(iommu, address, domid, 1, 1); + __iommu_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 1); } /* @@ -1236,7 +1228,7 @@ static void attach_device(struct amd_iommu *iommu, * here to evict all dirty stuff. */ iommu_queue_inv_dev_entry(iommu, devid); - iommu_flush_tlb_pde(iommu, domain->id); + iommu_flush_tlb_pde(domain); } /* @@ -1697,7 +1689,7 @@ retry: ADD_STATS_COUNTER(alloced_io_mem, size); if (unlikely(dma_dom->need_flush && !amd_iommu_unmap_flush)) { - iommu_flush_tlb(iommu, dma_dom->domain.id); + iommu_flush_tlb(&dma_dom->domain); dma_dom->need_flush = false; } else if (unlikely(iommu_has_npcache(iommu))) iommu_flush_pages(&dma_dom->domain, address, size); From 601367d76bd19b7eea2286ae99e5b1cb5d74f38d Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 20 Nov 2009 16:08:55 +0100 Subject: [PATCH 196/298] x86/amd-iommu: Remove iommu_flush_domain function This iommu_flush_tlb_pde function does essentially the same. So the iommu_flush_domain function is redundant and can be removed. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index c55aa079ded..b2c19f41f23 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -528,20 +528,6 @@ static void flush_all_domains_on_iommu(struct amd_iommu *iommu) } -/* - * This function is used to flush the IO/TLB for a given protection domain - * on every IOMMU in the system - */ -static void iommu_flush_domain(u16 domid) -{ - struct amd_iommu *iommu; - - INC_STATS_COUNTER(domain_flush_all); - - for_each_iommu(iommu) - flush_domain_on_iommu(iommu, domid); -} - void amd_iommu_flush_all_domains(void) { struct amd_iommu *iommu; @@ -1464,7 +1450,7 @@ static void update_domain(struct protection_domain *domain) update_device_table(domain); flush_devices_by_domain(domain); - iommu_flush_domain(domain->id); + iommu_flush_tlb_pde(domain); domain->updated = false; } @@ -2377,7 +2363,7 @@ static void amd_iommu_unmap_range(struct iommu_domain *dom, iova += PAGE_SIZE; } - iommu_flush_domain(domain->id); + iommu_flush_tlb_pde(domain); } static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom, From aeb26f55337d4310840c8adc3ec7d6aebb714472 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 20 Nov 2009 16:44:01 +0100 Subject: [PATCH 197/298] x86/amd-iommu: Implement protection domain list This patch adds code to keep a global list of all protection domains. This allows to simplify the resume code. Signed-off-by: Joerg Roedel --- arch/x86/include/asm/amd_iommu_types.h | 7 ++++++ arch/x86/kernel/amd_iommu.c | 33 ++++++++++++++++++++++++++ arch/x86/kernel/amd_iommu_init.c | 8 +++++++ 3 files changed, 48 insertions(+) diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index e68b1481138..b332b7f7d8d 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -231,6 +231,7 @@ extern bool amd_iommu_dump; * independent of their use. */ struct protection_domain { + struct list_head list; /* for list of all protection domains */ spinlock_t lock; /* mostly used to lock the page table*/ u16 id; /* the domain id written to the device table */ int mode; /* paging mode (0-6 levels) */ @@ -375,6 +376,12 @@ extern struct amd_iommu *amd_iommus[MAX_IOMMUS]; /* Number of IOMMUs present in the system */ extern int amd_iommus_present; +/* + * Declarations for the global list of all protection domains + */ +extern spinlock_t amd_iommu_pd_lock; +extern struct list_head amd_iommu_pd_list; + /* * Structure defining one entry in the device table */ diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index b2c19f41f23..0c4319b1301 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -985,6 +985,31 @@ static void dma_ops_free_addresses(struct dma_ops_domain *dom, * ****************************************************************************/ +/* + * This function adds a protection domain to the global protection domain list + */ +static void add_domain_to_list(struct protection_domain *domain) +{ + unsigned long flags; + + spin_lock_irqsave(&amd_iommu_pd_lock, flags); + list_add(&domain->list, &amd_iommu_pd_list); + spin_unlock_irqrestore(&amd_iommu_pd_lock, flags); +} + +/* + * This function removes a protection domain to the global + * protection domain list + */ +static void del_domain_from_list(struct protection_domain *domain) +{ + unsigned long flags; + + spin_lock_irqsave(&amd_iommu_pd_lock, flags); + list_del(&domain->list); + spin_unlock_irqrestore(&amd_iommu_pd_lock, flags); +} + static u16 domain_id_alloc(void) { unsigned long flags; @@ -1073,6 +1098,8 @@ static void dma_ops_domain_free(struct dma_ops_domain *dom) if (!dom) return; + del_domain_from_list(&dom->domain); + free_pagetable(&dom->domain); for (i = 0; i < APERTURE_MAX_RANGES; ++i) { @@ -1113,6 +1140,8 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu) dma_dom->need_flush = false; dma_dom->target_dev = 0xffff; + add_domain_to_list(&dma_dom->domain); + if (alloc_new_range(iommu, dma_dom, true, GFP_KERNEL)) goto free_dma_dom; @@ -2188,6 +2217,8 @@ static void protection_domain_free(struct protection_domain *domain) if (!domain) return; + del_domain_from_list(domain); + if (domain->id) domain_id_free(domain->id); @@ -2207,6 +2238,8 @@ static struct protection_domain *protection_domain_alloc(void) if (!domain->id) goto out_err; + add_domain_to_list(domain); + return domain; out_err: diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 8567d169802..73d5173765d 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -141,6 +141,12 @@ LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the struct amd_iommu *amd_iommus[MAX_IOMMUS]; int amd_iommus_present; +/* + * List of protection domains - used during resume + */ +LIST_HEAD(amd_iommu_pd_list); +spinlock_t amd_iommu_pd_lock; + /* * Pointer to the device table which is shared by all AMD IOMMUs * it is indexed by the PCI device id or the HT unit id and contains @@ -1263,6 +1269,8 @@ static int __init amd_iommu_init(void) */ amd_iommu_pd_alloc_bitmap[0] = 1; + spin_lock_init(&amd_iommu_pd_lock); + /* * now the data structures are allocated and basically initialized * start the real acpi table scan From e3306664eb307ae4cc93211cd9f12d0dbd49de65 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 20 Nov 2009 16:48:58 +0100 Subject: [PATCH 198/298] x86/amd-iommu: Reimplement amd_iommu_flush_all_domains() This patch reimplementes the amd_iommu_flush_all_domains function to use the global protection domain list instead of flushing every domain on every IOMMU. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 0c4319b1301..5141f5608c5 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -530,10 +530,12 @@ static void flush_all_domains_on_iommu(struct amd_iommu *iommu) void amd_iommu_flush_all_domains(void) { - struct amd_iommu *iommu; + struct protection_domain *domain; - for_each_iommu(iommu) - flush_all_domains_on_iommu(iommu); + list_for_each_entry(domain, &amd_iommu_pd_list, list) { + iommu_flush_tlb_pde(domain); + iommu_flush_complete(domain); + } } static void flush_all_devices_for_iommu(struct amd_iommu *iommu) From 09b4280439ef6fdc55f1353a9135034336eb5d26 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 20 Nov 2009 17:02:44 +0100 Subject: [PATCH 199/298] x86/amd-iommu: Reimplement flush_all_domains_on_iommu() This patch reimplements the function flush_all_domains_on_iommu to use the global protection domain list. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 45 ++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 5141f5608c5..a1bd99d390a 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -499,43 +499,48 @@ static void iommu_flush_tlb_pde(struct protection_domain *domain) } /* - * This function flushes one domain on one IOMMU + * This function flushes all domains that have devices on the given IOMMU */ -static void flush_domain_on_iommu(struct amd_iommu *iommu, u16 domid) -{ - struct iommu_cmd cmd; - unsigned long flags; - - __iommu_build_inv_iommu_pages(&cmd, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, - domid, 1, 1); - - spin_lock_irqsave(&iommu->lock, flags); - __iommu_queue_command(iommu, &cmd); - __iommu_completion_wait(iommu); - __iommu_wait_for_completion(iommu); - spin_unlock_irqrestore(&iommu->lock, flags); -} - static void flush_all_domains_on_iommu(struct amd_iommu *iommu) { - int i; + u64 address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS; + struct protection_domain *domain; + unsigned long flags; - for (i = 1; i < MAX_DOMAIN_ID; ++i) { - if (!test_bit(i, amd_iommu_pd_alloc_bitmap)) + spin_lock_irqsave(&amd_iommu_pd_lock, flags); + + list_for_each_entry(domain, &amd_iommu_pd_list, list) { + if (domain->dev_iommu[iommu->index] == 0) continue; - flush_domain_on_iommu(iommu, i); + + spin_lock(&domain->lock); + iommu_queue_inv_iommu_pages(iommu, address, domain->id, 1, 1); + iommu_flush_complete(domain); + spin_unlock(&domain->lock); } + spin_unlock_irqrestore(&amd_iommu_pd_lock, flags); } +/* + * This function uses heavy locking and may disable irqs for some time. But + * this is no issue because it is only called during resume. + */ void amd_iommu_flush_all_domains(void) { struct protection_domain *domain; + unsigned long flags; + + spin_lock_irqsave(&amd_iommu_pd_lock, flags); list_for_each_entry(domain, &amd_iommu_pd_list, list) { + spin_lock(&domain->lock); iommu_flush_tlb_pde(domain); iommu_flush_complete(domain); + spin_unlock(&domain->lock); } + + spin_unlock_irqrestore(&amd_iommu_pd_lock, flags); } static void flush_all_devices_for_iommu(struct amd_iommu *iommu) From 318afd41d2eca3224de3fd85a3b9a27a3010a98d Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 23 Nov 2009 18:32:38 +0100 Subject: [PATCH 200/298] x86/amd-iommu: Make np-cache a global flag The non-present cache flag was IOMMU local until now which doesn't make sense. Make this a global flag so we can remove the lase user of 'struct iommu' in the map/unmap path. Signed-off-by: Joerg Roedel --- arch/x86/include/asm/amd_iommu_types.h | 3 +++ arch/x86/kernel/amd_iommu.c | 8 +------- arch/x86/kernel/amd_iommu_init.c | 6 ++++++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index b332b7f7d8d..4899f783df6 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -211,6 +211,9 @@ extern bool amd_iommu_dump; printk(KERN_INFO "AMD-Vi: " format, ## arg); \ } while(0); +/* global flag if IOMMUs cache non-present entries */ +extern bool amd_iommu_np_cache; + /* * Make iterating over all IOMMUs easier */ diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index a1bd99d390a..5ebd24e4fc5 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -131,12 +131,6 @@ static void amd_iommu_stats_init(void) #endif -/* returns !0 if the IOMMU is caching non-present entries in its TLB */ -static int iommu_has_npcache(struct amd_iommu *iommu) -{ - return iommu->cap & (1UL << IOMMU_CAP_NPCACHE); -} - /**************************************************************************** * * Interrupt handling functions @@ -1713,7 +1707,7 @@ retry: if (unlikely(dma_dom->need_flush && !amd_iommu_unmap_flush)) { iommu_flush_tlb(&dma_dom->domain); dma_dom->need_flush = false; - } else if (unlikely(iommu_has_npcache(iommu))) + } else if (unlikely(amd_iommu_np_cache)) iommu_flush_pages(&dma_dom->domain, address, size); out: diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 73d5173765d..fbe4c3c02a9 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -141,6 +141,9 @@ LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the struct amd_iommu *amd_iommus[MAX_IOMMUS]; int amd_iommus_present; +/* IOMMUs have a non-present cache? */ +bool amd_iommu_np_cache __read_mostly; + /* * List of protection domains - used during resume */ @@ -891,6 +894,9 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) init_iommu_from_acpi(iommu, h); init_iommu_devices(iommu); + if (iommu->cap & (1UL << IOMMU_CAP_NPCACHE)) + amd_iommu_np_cache = true; + return pci_enable_device(iommu->dev); } From 420aef8a3acfc3e75427107e23d5a9bafd17c477 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 23 Nov 2009 16:14:57 +0100 Subject: [PATCH 201/298] x86/amd-iommu: Use check_device for amd_iommu_dma_supported The check_device logic needs to include the dma_supported checks to be really sure. Merge the dma_supported logic into check_device and use it to implement dma_supported. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 5ebd24e4fc5..ac27b1d6bd1 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1375,9 +1375,27 @@ static struct notifier_block device_nb = { */ static bool check_device(struct device *dev) { + u16 bdf; + struct pci_dev *pcidev; + if (!dev || !dev->dma_mask) return false; + /* No device or no PCI device */ + if (!dev || dev->bus != &pci_bus_type) + return false; + + pcidev = to_pci_dev(dev); + + bdf = calc_devid(pcidev->bus->number, pcidev->devfn); + + /* Out of our scope? */ + if (bdf > amd_iommu_last_bdf) + return false; + + if (amd_iommu_rlookup_table[bdf] == NULL) + return false; + return true; } @@ -2065,22 +2083,7 @@ free_mem: */ static int amd_iommu_dma_supported(struct device *dev, u64 mask) { - u16 bdf; - struct pci_dev *pcidev; - - /* No device or no PCI device */ - if (!dev || dev->bus != &pci_bus_type) - return 0; - - pcidev = to_pci_dev(dev); - - bdf = calc_devid(pcidev->bus->number, pcidev->devfn); - - /* Out of our scope? */ - if (bdf > amd_iommu_last_bdf) - return 0; - - return 1; + return check_device(dev); } /* From f99c0f1c75f75924a6f19cb40a21ccefc6e8754d Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 23 Nov 2009 16:52:56 +0100 Subject: [PATCH 202/298] x86/amd-iommu: Use check_device in get_device_resources Every call-place of get_device_resources calls check_device before it. So call it from get_device_resources directly and simplify the code. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 86 ++++++++++++------------------------- 1 file changed, 28 insertions(+), 58 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index ac27b1d6bd1..c5102ebdcbd 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1432,35 +1432,24 @@ static struct dma_ops_domain *find_protection_domain(u16 devid) * If the device is not yet associated with a domain this is also done * in this function. */ -static int get_device_resources(struct device *dev, - struct amd_iommu **iommu, - struct protection_domain **domain, - u16 *bdf) +static bool get_device_resources(struct device *dev, + struct amd_iommu **iommu, + struct protection_domain **domain, + u16 *bdf) { struct dma_ops_domain *dma_dom; struct pci_dev *pcidev; u16 _bdf; - *iommu = NULL; - *domain = NULL; - *bdf = 0xffff; + if (!check_device(dev)) + return false; - if (dev->bus != &pci_bus_type) - return 0; - - pcidev = to_pci_dev(dev); - _bdf = calc_devid(pcidev->bus->number, pcidev->devfn); - - /* device not translated by any IOMMU in the system? */ - if (_bdf > amd_iommu_last_bdf) - return 0; - - *bdf = amd_iommu_alias_table[_bdf]; - - *iommu = amd_iommu_rlookup_table[*bdf]; - if (*iommu == NULL) - return 0; + pcidev = to_pci_dev(dev); + _bdf = calc_devid(pcidev->bus->number, pcidev->devfn); + *bdf = amd_iommu_alias_table[_bdf]; + *iommu = amd_iommu_rlookup_table[*bdf]; *domain = domain_for_device(*bdf); + if (*domain == NULL) { dma_dom = find_protection_domain(*bdf); if (!dma_dom) @@ -1474,7 +1463,7 @@ static int get_device_resources(struct device *dev, if (domain_for_device(_bdf) == NULL) attach_device(*iommu, *domain, _bdf); - return 1; + return true; } static void update_device_table(struct protection_domain *domain) @@ -1797,17 +1786,12 @@ static dma_addr_t map_page(struct device *dev, struct page *page, INC_STATS_COUNTER(cnt_map_single); - if (!check_device(dev)) - return DMA_ERROR_CODE; - - dma_mask = *dev->dma_mask; - - get_device_resources(dev, &iommu, &domain, &devid); - - if (iommu == NULL || domain == NULL) + if (!get_device_resources(dev, &iommu, &domain, &devid)) /* device not handled by any AMD IOMMU */ return (dma_addr_t)paddr; + dma_mask = *dev->dma_mask; + if (!dma_ops_domain(domain)) return DMA_ERROR_CODE; @@ -1838,8 +1822,7 @@ static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, INC_STATS_COUNTER(cnt_unmap_single); - if (!check_device(dev) || - !get_device_resources(dev, &iommu, &domain, &devid)) + if (!get_device_resources(dev, &iommu, &domain, &devid)) /* device not handled by any AMD IOMMU */ return; @@ -1893,16 +1876,11 @@ static int map_sg(struct device *dev, struct scatterlist *sglist, INC_STATS_COUNTER(cnt_map_sg); - if (!check_device(dev)) - return 0; + if (!get_device_resources(dev, &iommu, &domain, &devid)) + return map_sg_no_iommu(dev, sglist, nelems, dir); dma_mask = *dev->dma_mask; - get_device_resources(dev, &iommu, &domain, &devid); - - if (!iommu || !domain) - return map_sg_no_iommu(dev, sglist, nelems, dir); - if (!dma_ops_domain(domain)) return 0; @@ -1958,8 +1936,7 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist, INC_STATS_COUNTER(cnt_unmap_sg); - if (!check_device(dev) || - !get_device_resources(dev, &iommu, &domain, &devid)) + if (!get_device_resources(dev, &iommu, &domain, &devid)) return; if (!dma_ops_domain(domain)) @@ -1994,24 +1971,22 @@ static void *alloc_coherent(struct device *dev, size_t size, INC_STATS_COUNTER(cnt_alloc_coherent); - if (!check_device(dev)) - return NULL; + if (!get_device_resources(dev, &iommu, &domain, &devid)) { + virt_addr = (void *)__get_free_pages(flag, get_order(size)); + *dma_addr = __pa(virt_addr); + return virt_addr; + } - if (!get_device_resources(dev, &iommu, &domain, &devid)) - flag &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); + dma_mask = dev->coherent_dma_mask; + flag &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); + flag |= __GFP_ZERO; - flag |= __GFP_ZERO; virt_addr = (void *)__get_free_pages(flag, get_order(size)); if (!virt_addr) return NULL; paddr = virt_to_phys(virt_addr); - if (!iommu || !domain) { - *dma_addr = (dma_addr_t)paddr; - return virt_addr; - } - if (!dma_ops_domain(domain)) goto out_free; @@ -2054,12 +2029,7 @@ static void free_coherent(struct device *dev, size_t size, INC_STATS_COUNTER(cnt_free_coherent); - if (!check_device(dev)) - return; - - get_device_resources(dev, &iommu, &domain, &devid); - - if (!iommu || !domain) + if (!get_device_resources(dev, &iommu, &domain, &devid)) goto free_mem; if (!dma_ops_domain(domain)) From 680525e06ddccda8c51bdddf532cd5b7d950c411 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 23 Nov 2009 18:44:42 +0100 Subject: [PATCH 203/298] x86/amd-iommu: Remove iommu parameter from dma_ops_domain_(un)map The parameter is unused in these function so remove it from the parameter list. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index c5102ebdcbd..da3f9d8ee39 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1585,8 +1585,7 @@ static u64* dma_ops_get_pte(struct dma_ops_domain *dom, * This is the generic map function. It maps one 4kb page at paddr to * the given address in the DMA address space for the domain. */ -static dma_addr_t dma_ops_domain_map(struct amd_iommu *iommu, - struct dma_ops_domain *dom, +static dma_addr_t dma_ops_domain_map(struct dma_ops_domain *dom, unsigned long address, phys_addr_t paddr, int direction) @@ -1620,8 +1619,7 @@ static dma_addr_t dma_ops_domain_map(struct amd_iommu *iommu, /* * The generic unmapping function for on page in the DMA address space. */ -static void dma_ops_domain_unmap(struct amd_iommu *iommu, - struct dma_ops_domain *dom, +static void dma_ops_domain_unmap(struct dma_ops_domain *dom, unsigned long address) { struct aperture_range *aperture; @@ -1700,7 +1698,7 @@ retry: start = address; for (i = 0; i < pages; ++i) { - ret = dma_ops_domain_map(iommu, dma_dom, start, paddr, dir); + ret = dma_ops_domain_map(dma_dom, start, paddr, dir); if (ret == DMA_ERROR_CODE) goto out_unmap; @@ -1724,7 +1722,7 @@ out_unmap: for (--i; i >= 0; --i) { start -= PAGE_SIZE; - dma_ops_domain_unmap(iommu, dma_dom, start); + dma_ops_domain_unmap(dma_dom, start); } dma_ops_free_addresses(dma_dom, address, pages); @@ -1754,7 +1752,7 @@ static void __unmap_single(struct amd_iommu *iommu, start = dma_addr; for (i = 0; i < pages; ++i) { - dma_ops_domain_unmap(iommu, dma_dom, start); + dma_ops_domain_unmap(dma_dom, start); start += PAGE_SIZE; } From 576175c2503ae9b0f930ee9a6a0abaf7ef8956ad Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 23 Nov 2009 19:08:46 +0100 Subject: [PATCH 204/298] x86/amd-iommu: Make alloc_new_range aware of multiple IOMMUs Since the assumption that an dma_ops domain is only bound to one IOMMU was given up we need to make alloc_new_range aware of it. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index da3f9d8ee39..687f617b95d 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -788,11 +788,11 @@ static u64 *fetch_pte(struct protection_domain *domain, * aperture in case of dma_ops domain allocation or address allocation * failure. */ -static int alloc_new_range(struct amd_iommu *iommu, - struct dma_ops_domain *dma_dom, +static int alloc_new_range(struct dma_ops_domain *dma_dom, bool populate, gfp_t gfp) { int index = dma_dom->aperture_size >> APERTURE_RANGE_SHIFT; + struct amd_iommu *iommu; int i; #ifdef CONFIG_IOMMU_STRESS @@ -832,14 +832,17 @@ static int alloc_new_range(struct amd_iommu *iommu, dma_dom->aperture_size += APERTURE_RANGE_SIZE; /* Intialize the exclusion range if necessary */ - if (iommu->exclusion_start && - iommu->exclusion_start >= dma_dom->aperture[index]->offset && - iommu->exclusion_start < dma_dom->aperture_size) { - unsigned long startpage = iommu->exclusion_start >> PAGE_SHIFT; - int pages = iommu_num_pages(iommu->exclusion_start, - iommu->exclusion_length, - PAGE_SIZE); - dma_ops_reserve_addresses(dma_dom, startpage, pages); + for_each_iommu(iommu) { + if (iommu->exclusion_start && + iommu->exclusion_start >= dma_dom->aperture[index]->offset + && iommu->exclusion_start < dma_dom->aperture_size) { + unsigned long startpage; + int pages = iommu_num_pages(iommu->exclusion_start, + iommu->exclusion_length, + PAGE_SIZE); + startpage = iommu->exclusion_start >> PAGE_SHIFT; + dma_ops_reserve_addresses(dma_dom, startpage, pages); + } } /* @@ -1143,7 +1146,7 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu) add_domain_to_list(&dma_dom->domain); - if (alloc_new_range(iommu, dma_dom, true, GFP_KERNEL)) + if (alloc_new_range(dma_dom, true, GFP_KERNEL)) goto free_dma_dom; /* @@ -1686,7 +1689,7 @@ retry: */ dma_dom->next_address = dma_dom->aperture_size; - if (alloc_new_range(iommu, dma_dom, false, GFP_ATOMIC)) + if (alloc_new_range(dma_dom, false, GFP_ATOMIC)) goto out; /* From cd8c82e875c27ee0d8b59fb76bc12aa9db6a70c2 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 23 Nov 2009 19:33:56 +0100 Subject: [PATCH 205/298] x86/amd-iommu: Remove iommu parameter from __(un)map_single With the prior changes this parameter is not longer required. This patch removes it from the function and all callers. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 687f617b95d..c04dcb7f40b 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1653,7 +1653,6 @@ static void dma_ops_domain_unmap(struct dma_ops_domain *dom, * Must be called with the domain lock held. */ static dma_addr_t __map_single(struct device *dev, - struct amd_iommu *iommu, struct dma_ops_domain *dma_dom, phys_addr_t paddr, size_t size, @@ -1737,8 +1736,7 @@ out_unmap: * Does the reverse of the __map_single function. Must be called with * the domain lock held too */ -static void __unmap_single(struct amd_iommu *iommu, - struct dma_ops_domain *dma_dom, +static void __unmap_single(struct dma_ops_domain *dma_dom, dma_addr_t dma_addr, size_t size, int dir) @@ -1797,7 +1795,7 @@ static dma_addr_t map_page(struct device *dev, struct page *page, return DMA_ERROR_CODE; spin_lock_irqsave(&domain->lock, flags); - addr = __map_single(dev, iommu, domain->priv, paddr, size, dir, false, + addr = __map_single(dev, domain->priv, paddr, size, dir, false, dma_mask); if (addr == DMA_ERROR_CODE) goto out; @@ -1832,7 +1830,7 @@ static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, spin_lock_irqsave(&domain->lock, flags); - __unmap_single(iommu, domain->priv, dma_addr, size, dir); + __unmap_single(domain->priv, dma_addr, size, dir); iommu_flush_complete(domain); @@ -1890,7 +1888,7 @@ static int map_sg(struct device *dev, struct scatterlist *sglist, for_each_sg(sglist, s, nelems, i) { paddr = sg_phys(s); - s->dma_address = __map_single(dev, iommu, domain->priv, + s->dma_address = __map_single(dev, domain->priv, paddr, s->length, dir, false, dma_mask); @@ -1910,7 +1908,7 @@ out: unmap: for_each_sg(sglist, s, mapped_elems, i) { if (s->dma_address) - __unmap_single(iommu, domain->priv, s->dma_address, + __unmap_single(domain->priv, s->dma_address, s->dma_length, dir); s->dma_address = s->dma_length = 0; } @@ -1946,7 +1944,7 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist, spin_lock_irqsave(&domain->lock, flags); for_each_sg(sglist, s, nelems, i) { - __unmap_single(iommu, domain->priv, s->dma_address, + __unmap_single(domain->priv, s->dma_address, s->dma_length, dir); s->dma_address = s->dma_length = 0; } @@ -1996,7 +1994,7 @@ static void *alloc_coherent(struct device *dev, size_t size, spin_lock_irqsave(&domain->lock, flags); - *dma_addr = __map_single(dev, iommu, domain->priv, paddr, + *dma_addr = __map_single(dev, domain->priv, paddr, size, DMA_BIDIRECTIONAL, true, dma_mask); if (*dma_addr == DMA_ERROR_CODE) { @@ -2038,7 +2036,7 @@ static void free_coherent(struct device *dev, size_t size, spin_lock_irqsave(&domain->lock, flags); - __unmap_single(iommu, domain->priv, dma_addr, size, DMA_BIDIRECTIONAL); + __unmap_single(domain->priv, dma_addr, size, DMA_BIDIRECTIONAL); iommu_flush_complete(domain); From f3be07da531ceef1b51295e5becc9bc07670b671 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 23 Nov 2009 19:43:14 +0100 Subject: [PATCH 206/298] x86/amd-iommu: Remove iommu specific handling from dma_ops path This patch finishes the removal of all iommu specific handling code in the dma_ops path. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index c04dcb7f40b..2cd5800e688 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1436,11 +1436,11 @@ static struct dma_ops_domain *find_protection_domain(u16 devid) * in this function. */ static bool get_device_resources(struct device *dev, - struct amd_iommu **iommu, struct protection_domain **domain, u16 *bdf) { struct dma_ops_domain *dma_dom; + struct amd_iommu *iommu; struct pci_dev *pcidev; u16 _bdf; @@ -1450,21 +1450,21 @@ static bool get_device_resources(struct device *dev, pcidev = to_pci_dev(dev); _bdf = calc_devid(pcidev->bus->number, pcidev->devfn); *bdf = amd_iommu_alias_table[_bdf]; - *iommu = amd_iommu_rlookup_table[*bdf]; + iommu = amd_iommu_rlookup_table[*bdf]; *domain = domain_for_device(*bdf); if (*domain == NULL) { dma_dom = find_protection_domain(*bdf); if (!dma_dom) - dma_dom = (*iommu)->default_dom; + dma_dom = iommu->default_dom; *domain = &dma_dom->domain; - attach_device(*iommu, *domain, *bdf); + attach_device(iommu, *domain, *bdf); DUMP_printk("Using protection domain %d for device %s\n", (*domain)->id, dev_name(dev)); } if (domain_for_device(_bdf) == NULL) - attach_device(*iommu, *domain, _bdf); + attach_device(iommu, *domain, _bdf); return true; } @@ -1776,7 +1776,6 @@ static dma_addr_t map_page(struct device *dev, struct page *page, struct dma_attrs *attrs) { unsigned long flags; - struct amd_iommu *iommu; struct protection_domain *domain; u16 devid; dma_addr_t addr; @@ -1785,7 +1784,7 @@ static dma_addr_t map_page(struct device *dev, struct page *page, INC_STATS_COUNTER(cnt_map_single); - if (!get_device_resources(dev, &iommu, &domain, &devid)) + if (!get_device_resources(dev, &domain, &devid)) /* device not handled by any AMD IOMMU */ return (dma_addr_t)paddr; @@ -1815,13 +1814,12 @@ static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction dir, struct dma_attrs *attrs) { unsigned long flags; - struct amd_iommu *iommu; struct protection_domain *domain; u16 devid; INC_STATS_COUNTER(cnt_unmap_single); - if (!get_device_resources(dev, &iommu, &domain, &devid)) + if (!get_device_resources(dev, &domain, &devid)) /* device not handled by any AMD IOMMU */ return; @@ -1864,7 +1862,6 @@ static int map_sg(struct device *dev, struct scatterlist *sglist, struct dma_attrs *attrs) { unsigned long flags; - struct amd_iommu *iommu; struct protection_domain *domain; u16 devid; int i; @@ -1875,7 +1872,7 @@ static int map_sg(struct device *dev, struct scatterlist *sglist, INC_STATS_COUNTER(cnt_map_sg); - if (!get_device_resources(dev, &iommu, &domain, &devid)) + if (!get_device_resources(dev, &domain, &devid)) return map_sg_no_iommu(dev, sglist, nelems, dir); dma_mask = *dev->dma_mask; @@ -1927,7 +1924,6 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist, struct dma_attrs *attrs) { unsigned long flags; - struct amd_iommu *iommu; struct protection_domain *domain; struct scatterlist *s; u16 devid; @@ -1935,7 +1931,7 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist, INC_STATS_COUNTER(cnt_unmap_sg); - if (!get_device_resources(dev, &iommu, &domain, &devid)) + if (!get_device_resources(dev, &domain, &devid)) return; if (!dma_ops_domain(domain)) @@ -1962,7 +1958,6 @@ static void *alloc_coherent(struct device *dev, size_t size, { unsigned long flags; void *virt_addr; - struct amd_iommu *iommu; struct protection_domain *domain; u16 devid; phys_addr_t paddr; @@ -1970,7 +1965,7 @@ static void *alloc_coherent(struct device *dev, size_t size, INC_STATS_COUNTER(cnt_alloc_coherent); - if (!get_device_resources(dev, &iommu, &domain, &devid)) { + if (!get_device_resources(dev, &domain, &devid)) { virt_addr = (void *)__get_free_pages(flag, get_order(size)); *dma_addr = __pa(virt_addr); return virt_addr; @@ -2022,13 +2017,12 @@ static void free_coherent(struct device *dev, size_t size, void *virt_addr, dma_addr_t dma_addr) { unsigned long flags; - struct amd_iommu *iommu; struct protection_domain *domain; u16 devid; INC_STATS_COUNTER(cnt_free_coherent); - if (!get_device_resources(dev, &iommu, &domain, &devid)) + if (!get_device_resources(dev, &domain, &devid)) goto free_mem; if (!dma_ops_domain(domain)) From 15898bbcb48fc86c2baff156163df0941ecb6a15 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 24 Nov 2009 15:39:42 +0100 Subject: [PATCH 207/298] x86/amd-iommu: Let domain_for_device handle aliases If there is no domain associated to a device yet and the device has an alias device which already has a domain, the original device needs to have the same domain as the alias device. This patch changes domain_for_device to handle this situation and directly assigns the alias device domain to the device in this situation. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 255 +++++++++++++++++++++--------------- 1 file changed, 149 insertions(+), 106 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 2cd5800e688..75470ffee35 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -71,6 +71,19 @@ static u64 *fetch_pte(struct protection_domain *domain, unsigned long address, int map_size); static void update_domain(struct protection_domain *domain); +/**************************************************************************** + * + * Helper functions + * + ****************************************************************************/ + +static inline u16 get_device_id(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + + return calc_devid(pdev->bus->number, pdev->devfn); +} + #ifdef CONFIG_AMD_IOMMU_STATS /* @@ -1174,26 +1187,13 @@ static bool dma_ops_domain(struct protection_domain *domain) return domain->flags & PD_DMA_OPS_MASK; } -/* - * Find out the protection domain structure for a given PCI device. This - * will give us the pointer to the page table root for example. - */ -static struct protection_domain *domain_for_device(u16 devid) -{ - struct protection_domain *dom; - unsigned long flags; - - read_lock_irqsave(&amd_iommu_devtable_lock, flags); - dom = amd_iommu_pd_table[devid]; - read_unlock_irqrestore(&amd_iommu_devtable_lock, flags); - - return dom; -} - static void set_dte_entry(u16 devid, struct protection_domain *domain) { + struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; u64 pte_root = virt_to_phys(domain->pt_root); + BUG_ON(amd_iommu_pd_table[devid] != NULL); + pte_root |= (domain->mode & DEV_ENTRY_MODE_MASK) << DEV_ENTRY_MODE_SHIFT; pte_root |= IOMMU_PTE_IR | IOMMU_PTE_IW | IOMMU_PTE_P | IOMMU_PTE_TV; @@ -1203,64 +1203,21 @@ static void set_dte_entry(u16 devid, struct protection_domain *domain) amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root); amd_iommu_pd_table[devid] = domain; -} - -/* - * If a device is not yet associated with a domain, this function does - * assigns it visible for the hardware - */ -static void __attach_device(struct amd_iommu *iommu, - struct protection_domain *domain, - u16 devid) -{ - /* lock domain */ - spin_lock(&domain->lock); - - /* update DTE entry */ - set_dte_entry(devid, domain); /* Do reference counting */ domain->dev_iommu[iommu->index] += 1; domain->dev_cnt += 1; - /* ready */ - spin_unlock(&domain->lock); -} - -/* - * If a device is not yet associated with a domain, this function does - * assigns it visible for the hardware - */ -static void attach_device(struct amd_iommu *iommu, - struct protection_domain *domain, - u16 devid) -{ - unsigned long flags; - - write_lock_irqsave(&amd_iommu_devtable_lock, flags); - __attach_device(iommu, domain, devid); - write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); - - /* - * We might boot into a crash-kernel here. The crashed kernel - * left the caches in the IOMMU dirty. So we have to flush - * here to evict all dirty stuff. - */ + /* Flush the changes DTE entry */ iommu_queue_inv_dev_entry(iommu, devid); - iommu_flush_tlb_pde(domain); } -/* - * Removes a device from a protection domain (unlocked) - */ -static void __detach_device(struct protection_domain *domain, u16 devid) +static void clear_dte_entry(u16 devid) { + struct protection_domain *domain = amd_iommu_pd_table[devid]; struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; - BUG_ON(!iommu); - - /* lock domain */ - spin_lock(&domain->lock); + BUG_ON(domain == NULL); /* remove domain from the lookup table */ amd_iommu_pd_table[devid] = NULL; @@ -1276,32 +1233,128 @@ static void __detach_device(struct protection_domain *domain, u16 devid) domain->dev_iommu[iommu->index] -= 1; domain->dev_cnt -= 1; + iommu_queue_inv_dev_entry(iommu, devid); +} + +/* + * If a device is not yet associated with a domain, this function does + * assigns it visible for the hardware + */ +static int __attach_device(struct device *dev, + struct protection_domain *domain) +{ + u16 devid = get_device_id(dev); + u16 alias = amd_iommu_alias_table[devid]; + + /* lock domain */ + spin_lock(&domain->lock); + + /* Some sanity checks */ + if (amd_iommu_pd_table[alias] != NULL && + amd_iommu_pd_table[alias] != domain) + return -EBUSY; + + if (amd_iommu_pd_table[devid] != NULL && + amd_iommu_pd_table[devid] != domain) + return -EBUSY; + + /* Do real assignment */ + if (alias != devid && + amd_iommu_pd_table[alias] == NULL) + set_dte_entry(alias, domain); + + if (amd_iommu_pd_table[devid] == NULL) + set_dte_entry(devid, domain); + /* ready */ spin_unlock(&domain->lock); + return 0; +} + +/* + * If a device is not yet associated with a domain, this function does + * assigns it visible for the hardware + */ +static int attach_device(struct device *dev, + struct protection_domain *domain) +{ + unsigned long flags; + int ret; + + write_lock_irqsave(&amd_iommu_devtable_lock, flags); + ret = __attach_device(dev, domain); + write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); + + /* + * We might boot into a crash-kernel here. The crashed kernel + * left the caches in the IOMMU dirty. So we have to flush + * here to evict all dirty stuff. + */ + iommu_flush_tlb_pde(domain); + + return ret; +} + +/* + * Removes a device from a protection domain (unlocked) + */ +static void __detach_device(struct device *dev) +{ + u16 devid = get_device_id(dev); + struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; + + BUG_ON(!iommu); + + clear_dte_entry(devid); + /* * If we run in passthrough mode the device must be assigned to the * passthrough domain if it is detached from any other domain */ - if (iommu_pass_through) { - struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; - __attach_device(iommu, pt_domain, devid); - } + if (iommu_pass_through) + __attach_device(dev, pt_domain); } /* * Removes a device from a protection domain (with devtable_lock held) */ -static void detach_device(struct protection_domain *domain, u16 devid) +static void detach_device(struct device *dev) { unsigned long flags; /* lock device table */ write_lock_irqsave(&amd_iommu_devtable_lock, flags); - __detach_device(domain, devid); + __detach_device(dev); write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); } +/* + * Find out the protection domain structure for a given PCI device. This + * will give us the pointer to the page table root for example. + */ +static struct protection_domain *domain_for_device(struct device *dev) +{ + struct protection_domain *dom; + unsigned long flags; + u16 devid, alias; + + devid = get_device_id(dev); + alias = amd_iommu_alias_table[devid]; + + read_lock_irqsave(&amd_iommu_devtable_lock, flags); + dom = amd_iommu_pd_table[devid]; + if (dom == NULL && + amd_iommu_pd_table[alias] != NULL) { + __attach_device(dev, amd_iommu_pd_table[alias]); + dom = amd_iommu_pd_table[devid]; + } + + read_unlock_irqrestore(&amd_iommu_devtable_lock, flags); + + return dom; +} + static int device_change_notifier(struct notifier_block *nb, unsigned long action, void *data) { @@ -1322,7 +1375,7 @@ static int device_change_notifier(struct notifier_block *nb, if (iommu == NULL) goto out; - domain = domain_for_device(devid); + domain = domain_for_device(dev); if (domain && !dma_ops_domain(domain)) WARN_ONCE(1, "AMD IOMMU WARNING: device %s already bound " @@ -1334,7 +1387,7 @@ static int device_change_notifier(struct notifier_block *nb, goto out; if (iommu_pass_through) break; - detach_device(domain, devid); + detach_device(dev); break; case BUS_NOTIFY_ADD_DEVICE: /* allocate a protection domain if a device is added */ @@ -1441,30 +1494,25 @@ static bool get_device_resources(struct device *dev, { struct dma_ops_domain *dma_dom; struct amd_iommu *iommu; - struct pci_dev *pcidev; - u16 _bdf; if (!check_device(dev)) return false; - pcidev = to_pci_dev(dev); - _bdf = calc_devid(pcidev->bus->number, pcidev->devfn); - *bdf = amd_iommu_alias_table[_bdf]; + *bdf = get_device_id(dev); + *domain = domain_for_device(dev); iommu = amd_iommu_rlookup_table[*bdf]; - *domain = domain_for_device(*bdf); - if (*domain == NULL) { - dma_dom = find_protection_domain(*bdf); - if (!dma_dom) - dma_dom = iommu->default_dom; - *domain = &dma_dom->domain; - attach_device(iommu, *domain, *bdf); - DUMP_printk("Using protection domain %d for device %s\n", - (*domain)->id, dev_name(dev)); - } + if (*domain != NULL) + return true; - if (domain_for_device(_bdf) == NULL) - attach_device(iommu, *domain, _bdf); + /* Device not bount yet - bind it */ + dma_dom = find_protection_domain(*bdf); + if (!dma_dom) + dma_dom = iommu->default_dom; + *domain = &dma_dom->domain; + attach_device(dev, *domain); + DUMP_printk("Using protection domain %d for device %s\n", + (*domain)->id, dev_name(dev)); return true; } @@ -2068,7 +2116,7 @@ static void prealloc_protection_domains(void) if (devid > amd_iommu_last_bdf) continue; devid = amd_iommu_alias_table[devid]; - if (domain_for_device(devid)) + if (domain_for_device(&dev->dev)) continue; iommu = amd_iommu_rlookup_table[devid]; if (!iommu) @@ -2079,9 +2127,7 @@ static void prealloc_protection_domains(void) init_unity_mappings_for_device(dma_dom, devid); dma_dom->target_dev = devid; - attach_device(iommu, &dma_dom->domain, devid); - if (__devid != devid) - attach_device(iommu, &dma_dom->domain, __devid); + attach_device(&dev->dev, &dma_dom->domain); list_add_tail(&dma_dom->list, &iommu_pd_list); } @@ -2174,7 +2220,7 @@ static void cleanup_domain(struct protection_domain *domain) for (devid = 0; devid <= amd_iommu_last_bdf; ++devid) if (amd_iommu_pd_table[devid] == domain) - __detach_device(domain, devid); + clear_dte_entry(devid); write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); } @@ -2262,7 +2308,6 @@ static void amd_iommu_domain_destroy(struct iommu_domain *dom) static void amd_iommu_detach_device(struct iommu_domain *dom, struct device *dev) { - struct protection_domain *domain = dom->priv; struct amd_iommu *iommu; struct pci_dev *pdev; u16 devid; @@ -2275,7 +2320,7 @@ static void amd_iommu_detach_device(struct iommu_domain *dom, devid = calc_devid(pdev->bus->number, pdev->devfn); if (devid > 0) - detach_device(domain, devid); + detach_device(dev); iommu = amd_iommu_rlookup_table[devid]; if (!iommu) @@ -2292,6 +2337,7 @@ static int amd_iommu_attach_device(struct iommu_domain *dom, struct protection_domain *old_domain; struct amd_iommu *iommu; struct pci_dev *pdev; + int ret; u16 devid; if (dev->bus != &pci_bus_type) @@ -2309,15 +2355,15 @@ static int amd_iommu_attach_device(struct iommu_domain *dom, if (!iommu) return -EINVAL; - old_domain = domain_for_device(devid); + old_domain = amd_iommu_pd_table[devid]; if (old_domain) - detach_device(old_domain, devid); + detach_device(dev); - attach_device(iommu, domain, devid); + ret = attach_device(dev, domain); iommu_completion_wait(iommu); - return 0; + return ret; } static int amd_iommu_map_range(struct iommu_domain *dom, @@ -2414,8 +2460,9 @@ static struct iommu_ops amd_iommu_ops = { int __init amd_iommu_init_passthrough(void) { + struct amd_iommu *iommu; struct pci_dev *dev = NULL; - u16 devid, devid2; + u16 devid; /* allocate passthroug domain */ pt_domain = protection_domain_alloc(); @@ -2425,20 +2472,16 @@ int __init amd_iommu_init_passthrough(void) pt_domain->mode |= PAGE_MODE_NONE; while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - struct amd_iommu *iommu; devid = calc_devid(dev->bus->number, dev->devfn); if (devid > amd_iommu_last_bdf) continue; - devid2 = amd_iommu_alias_table[devid]; - - iommu = amd_iommu_rlookup_table[devid2]; + iommu = amd_iommu_rlookup_table[devid]; if (!iommu) continue; - __attach_device(iommu, pt_domain, devid); - __attach_device(iommu, pt_domain, devid2); + attach_device(&dev->dev, pt_domain); } pr_info("AMD-Vi: Initialized for Passthrough Mode\n"); From 94f6d190eeed91cb2bb901aa7816edd1e2405347 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 24 Nov 2009 16:40:02 +0100 Subject: [PATCH 208/298] x86/amd-iommu: Simplify get_device_resources() With the previous changes the get_device_resources function can be simplified even more. The only important information for the callers is the protection domain. This patch renames the function to get_domain() and let it only return the protection domain for a device. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 86 ++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 50 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 75470ffee35..e5bbe9a0c19 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1463,6 +1463,7 @@ static struct dma_ops_domain *find_protection_domain(u16 devid) { struct dma_ops_domain *entry, *ret = NULL; unsigned long flags; + u16 alias = amd_iommu_alias_table[devid]; if (list_empty(&iommu_pd_list)) return NULL; @@ -1470,7 +1471,8 @@ static struct dma_ops_domain *find_protection_domain(u16 devid) spin_lock_irqsave(&iommu_pd_list_lock, flags); list_for_each_entry(entry, &iommu_pd_list, list) { - if (entry->target_dev == devid) { + if (entry->target_dev == devid || + entry->target_dev == alias) { ret = entry; break; } @@ -1488,33 +1490,31 @@ static struct dma_ops_domain *find_protection_domain(u16 devid) * If the device is not yet associated with a domain this is also done * in this function. */ -static bool get_device_resources(struct device *dev, - struct protection_domain **domain, - u16 *bdf) +static struct protection_domain *get_domain(struct device *dev) { + struct protection_domain *domain; struct dma_ops_domain *dma_dom; - struct amd_iommu *iommu; + u16 devid = get_device_id(dev); if (!check_device(dev)) - return false; + return ERR_PTR(-EINVAL); - *bdf = get_device_id(dev); - *domain = domain_for_device(dev); - iommu = amd_iommu_rlookup_table[*bdf]; + domain = domain_for_device(dev); + if (domain != NULL && !dma_ops_domain(domain)) + return ERR_PTR(-EBUSY); - if (*domain != NULL) - return true; + if (domain != NULL) + return domain; /* Device not bount yet - bind it */ - dma_dom = find_protection_domain(*bdf); + dma_dom = find_protection_domain(devid); if (!dma_dom) - dma_dom = iommu->default_dom; - *domain = &dma_dom->domain; - attach_device(dev, *domain); + dma_dom = amd_iommu_rlookup_table[devid]->default_dom; + attach_device(dev, &dma_dom->domain); DUMP_printk("Using protection domain %d for device %s\n", - (*domain)->id, dev_name(dev)); + dma_dom->domain.id, dev_name(dev)); - return true; + return &dma_dom->domain; } static void update_device_table(struct protection_domain *domain) @@ -1825,23 +1825,22 @@ static dma_addr_t map_page(struct device *dev, struct page *page, { unsigned long flags; struct protection_domain *domain; - u16 devid; dma_addr_t addr; u64 dma_mask; phys_addr_t paddr = page_to_phys(page) + offset; INC_STATS_COUNTER(cnt_map_single); - if (!get_device_resources(dev, &domain, &devid)) - /* device not handled by any AMD IOMMU */ + domain = get_domain(dev); + if (PTR_ERR(domain) == -EINVAL) return (dma_addr_t)paddr; + else if (IS_ERR(domain)) + return DMA_ERROR_CODE; dma_mask = *dev->dma_mask; - if (!dma_ops_domain(domain)) - return DMA_ERROR_CODE; - spin_lock_irqsave(&domain->lock, flags); + addr = __map_single(dev, domain->priv, paddr, size, dir, false, dma_mask); if (addr == DMA_ERROR_CODE) @@ -1863,15 +1862,11 @@ static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, { unsigned long flags; struct protection_domain *domain; - u16 devid; INC_STATS_COUNTER(cnt_unmap_single); - if (!get_device_resources(dev, &domain, &devid)) - /* device not handled by any AMD IOMMU */ - return; - - if (!dma_ops_domain(domain)) + domain = get_domain(dev); + if (IS_ERR(domain)) return; spin_lock_irqsave(&domain->lock, flags); @@ -1911,7 +1906,6 @@ static int map_sg(struct device *dev, struct scatterlist *sglist, { unsigned long flags; struct protection_domain *domain; - u16 devid; int i; struct scatterlist *s; phys_addr_t paddr; @@ -1920,14 +1914,14 @@ static int map_sg(struct device *dev, struct scatterlist *sglist, INC_STATS_COUNTER(cnt_map_sg); - if (!get_device_resources(dev, &domain, &devid)) + domain = get_domain(dev); + if (PTR_ERR(domain) == -EINVAL) return map_sg_no_iommu(dev, sglist, nelems, dir); + else if (IS_ERR(domain)) + return 0; dma_mask = *dev->dma_mask; - if (!dma_ops_domain(domain)) - return 0; - spin_lock_irqsave(&domain->lock, flags); for_each_sg(sglist, s, nelems, i) { @@ -1974,15 +1968,12 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist, unsigned long flags; struct protection_domain *domain; struct scatterlist *s; - u16 devid; int i; INC_STATS_COUNTER(cnt_unmap_sg); - if (!get_device_resources(dev, &domain, &devid)) - return; - - if (!dma_ops_domain(domain)) + domain = get_domain(dev); + if (IS_ERR(domain)) return; spin_lock_irqsave(&domain->lock, flags); @@ -2007,17 +1998,18 @@ static void *alloc_coherent(struct device *dev, size_t size, unsigned long flags; void *virt_addr; struct protection_domain *domain; - u16 devid; phys_addr_t paddr; u64 dma_mask = dev->coherent_dma_mask; INC_STATS_COUNTER(cnt_alloc_coherent); - if (!get_device_resources(dev, &domain, &devid)) { + domain = get_domain(dev); + if (PTR_ERR(domain) == -EINVAL) { virt_addr = (void *)__get_free_pages(flag, get_order(size)); *dma_addr = __pa(virt_addr); return virt_addr; - } + } else if (IS_ERR(domain)) + return NULL; dma_mask = dev->coherent_dma_mask; flag &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); @@ -2029,9 +2021,6 @@ static void *alloc_coherent(struct device *dev, size_t size, paddr = virt_to_phys(virt_addr); - if (!dma_ops_domain(domain)) - goto out_free; - if (!dma_mask) dma_mask = *dev->dma_mask; @@ -2066,14 +2055,11 @@ static void free_coherent(struct device *dev, size_t size, { unsigned long flags; struct protection_domain *domain; - u16 devid; INC_STATS_COUNTER(cnt_free_coherent); - if (!get_device_resources(dev, &domain, &devid)) - goto free_mem; - - if (!dma_ops_domain(domain)) + domain = get_domain(dev); + if (IS_ERR(domain)) goto free_mem; spin_lock_irqsave(&domain->lock, flags); From 71c70984e5afc20d304fbb523f1c8bb42c4ceb36 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 24 Nov 2009 16:43:06 +0100 Subject: [PATCH 209/298] x86/amd-iommu: Move find_protection_domain to helper functions This is a helper function and when its placed in the helper function section we can remove its forward declaration. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 57 ++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index e5bbe9a0c19..405f8dad7c7 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -59,7 +59,6 @@ struct iommu_cmd { static int dma_ops_unity_map(struct dma_ops_domain *dma_dom, struct unity_map_entry *e); -static struct dma_ops_domain *find_protection_domain(u16 devid); static u64 *alloc_pte(struct protection_domain *domain, unsigned long address, int end_lvl, u64 **pte_page, gfp_t gfp); @@ -84,6 +83,34 @@ static inline u16 get_device_id(struct device *dev) return calc_devid(pdev->bus->number, pdev->devfn); } +/* + * In this function the list of preallocated protection domains is traversed to + * find the domain for a specific device + */ +static struct dma_ops_domain *find_protection_domain(u16 devid) +{ + struct dma_ops_domain *entry, *ret = NULL; + unsigned long flags; + u16 alias = amd_iommu_alias_table[devid]; + + if (list_empty(&iommu_pd_list)) + return NULL; + + spin_lock_irqsave(&iommu_pd_list_lock, flags); + + list_for_each_entry(entry, &iommu_pd_list, list) { + if (entry->target_dev == devid || + entry->target_dev == alias) { + ret = entry; + break; + } + } + + spin_unlock_irqrestore(&iommu_pd_list_lock, flags); + + return ret; +} + #ifdef CONFIG_AMD_IOMMU_STATS /* @@ -1455,34 +1482,6 @@ static bool check_device(struct device *dev) return true; } -/* - * In this function the list of preallocated protection domains is traversed to - * find the domain for a specific device - */ -static struct dma_ops_domain *find_protection_domain(u16 devid) -{ - struct dma_ops_domain *entry, *ret = NULL; - unsigned long flags; - u16 alias = amd_iommu_alias_table[devid]; - - if (list_empty(&iommu_pd_list)) - return NULL; - - spin_lock_irqsave(&iommu_pd_list_lock, flags); - - list_for_each_entry(entry, &iommu_pd_list, list) { - if (entry->target_dev == devid || - entry->target_dev == alias) { - ret = entry; - break; - } - } - - spin_unlock_irqrestore(&iommu_pd_list_lock, flags); - - return ret; -} - /* * In the dma_ops path we only have the struct device. This function * finds the corresponding IOMMU, the protection domain and the From 98fc5a693bbdda498a556654c70d1e31a186c988 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 24 Nov 2009 17:19:23 +0100 Subject: [PATCH 210/298] x86/amd-iommu: Use get_device_id and check_device where appropriate The logic of these two functions is reimplemented (at least in parts) in places in the code. This patch removes these code duplications and uses the functions instead. As a side effect it moves check_device() to the helper function code section. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 110 ++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 61 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 405f8dad7c7..d10195b685a 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -111,6 +111,33 @@ static struct dma_ops_domain *find_protection_domain(u16 devid) return ret; } +/* + * This function checks if the driver got a valid device from the caller to + * avoid dereferencing invalid pointers. + */ +static bool check_device(struct device *dev) +{ + u16 devid; + + if (!dev || !dev->dma_mask) + return false; + + /* No device or no PCI device */ + if (!dev || dev->bus != &pci_bus_type) + return false; + + devid = get_device_id(dev); + + /* Out of our scope? */ + if (devid > amd_iommu_last_bdf) + return false; + + if (amd_iommu_rlookup_table[devid] == NULL) + return false; + + return true; +} + #ifdef CONFIG_AMD_IOMMU_STATS /* @@ -1386,22 +1413,17 @@ static int device_change_notifier(struct notifier_block *nb, unsigned long action, void *data) { struct device *dev = data; - struct pci_dev *pdev = to_pci_dev(dev); - u16 devid = calc_devid(pdev->bus->number, pdev->devfn); + u16 devid; struct protection_domain *domain; struct dma_ops_domain *dma_domain; struct amd_iommu *iommu; unsigned long flags; - if (devid > amd_iommu_last_bdf) - goto out; - - devid = amd_iommu_alias_table[devid]; - - iommu = amd_iommu_rlookup_table[devid]; - if (iommu == NULL) - goto out; + if (!check_device(dev)) + return 0; + devid = get_device_id(dev); + iommu = amd_iommu_rlookup_table[devid]; domain = domain_for_device(dev); if (domain && !dma_ops_domain(domain)) @@ -1452,36 +1474,6 @@ static struct notifier_block device_nb = { * *****************************************************************************/ -/* - * This function checks if the driver got a valid device from the caller to - * avoid dereferencing invalid pointers. - */ -static bool check_device(struct device *dev) -{ - u16 bdf; - struct pci_dev *pcidev; - - if (!dev || !dev->dma_mask) - return false; - - /* No device or no PCI device */ - if (!dev || dev->bus != &pci_bus_type) - return false; - - pcidev = to_pci_dev(dev); - - bdf = calc_devid(pcidev->bus->number, pcidev->devfn); - - /* Out of our scope? */ - if (bdf > amd_iommu_last_bdf) - return false; - - if (amd_iommu_rlookup_table[bdf] == NULL) - return false; - - return true; -} - /* * In the dma_ops path we only have the struct device. This function * finds the corresponding IOMMU, the protection domain and the @@ -2094,15 +2086,20 @@ static void prealloc_protection_domains(void) struct pci_dev *dev = NULL; struct dma_ops_domain *dma_dom; struct amd_iommu *iommu; - u16 devid, __devid; + u16 devid; while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - __devid = devid = calc_devid(dev->bus->number, dev->devfn); - if (devid > amd_iommu_last_bdf) + + /* Do we handle this device? */ + if (!check_device(&dev->dev)) continue; - devid = amd_iommu_alias_table[devid]; + + /* Is there already any domain for it? */ if (domain_for_device(&dev->dev)) continue; + + devid = get_device_id(&dev->dev); + iommu = amd_iommu_rlookup_table[devid]; if (!iommu) continue; @@ -2294,17 +2291,14 @@ static void amd_iommu_detach_device(struct iommu_domain *dom, struct device *dev) { struct amd_iommu *iommu; - struct pci_dev *pdev; u16 devid; - if (dev->bus != &pci_bus_type) + if (!check_device(dev)) return; - pdev = to_pci_dev(dev); + devid = get_device_id(dev); - devid = calc_devid(pdev->bus->number, pdev->devfn); - - if (devid > 0) + if (amd_iommu_pd_table[devid] != NULL) detach_device(dev); iommu = amd_iommu_rlookup_table[devid]; @@ -2321,20 +2315,13 @@ static int amd_iommu_attach_device(struct iommu_domain *dom, struct protection_domain *domain = dom->priv; struct protection_domain *old_domain; struct amd_iommu *iommu; - struct pci_dev *pdev; int ret; u16 devid; - if (dev->bus != &pci_bus_type) + if (!check_device(dev)) return -EINVAL; - pdev = to_pci_dev(dev); - - devid = calc_devid(pdev->bus->number, pdev->devfn); - - if (devid >= amd_iommu_last_bdf || - devid != amd_iommu_alias_table[devid]) - return -EINVAL; + devid = get_device_id(dev); iommu = amd_iommu_rlookup_table[devid]; if (!iommu) @@ -2458,10 +2445,11 @@ int __init amd_iommu_init_passthrough(void) while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - devid = calc_devid(dev->bus->number, dev->devfn); - if (devid > amd_iommu_last_bdf) + if (!check_device(&dev->dev)) continue; + devid = get_device_id(&dev->dev); + iommu = amd_iommu_rlookup_table[devid]; if (!iommu) continue; From 87a64d523825351a23743e69949c2a8c2077cecf Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 24 Nov 2009 17:26:43 +0100 Subject: [PATCH 211/298] x86/amd-iommu: Remove iommu parameter from dma_ops_domain_alloc This function doesn't use the parameter anymore so it can be removed. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index d10195b685a..17e83ecb8b2 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1188,7 +1188,7 @@ static void dma_ops_domain_free(struct dma_ops_domain *dom) * It also intializes the page table and the address allocator data * structures required for the dma_ops interface */ -static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu) +static struct dma_ops_domain *dma_ops_domain_alloc(void) { struct dma_ops_domain *dma_dom; @@ -1443,7 +1443,7 @@ static int device_change_notifier(struct notifier_block *nb, dma_domain = find_protection_domain(devid); if (dma_domain) goto out; - dma_domain = dma_ops_domain_alloc(iommu); + dma_domain = dma_ops_domain_alloc(); if (!dma_domain) goto out; dma_domain->target_dev = devid; @@ -2085,7 +2085,6 @@ static void prealloc_protection_domains(void) { struct pci_dev *dev = NULL; struct dma_ops_domain *dma_dom; - struct amd_iommu *iommu; u16 devid; while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { @@ -2100,10 +2099,7 @@ static void prealloc_protection_domains(void) devid = get_device_id(&dev->dev); - iommu = amd_iommu_rlookup_table[devid]; - if (!iommu) - continue; - dma_dom = dma_ops_domain_alloc(iommu); + dma_dom = dma_ops_domain_alloc(); if (!dma_dom) continue; init_unity_mappings_for_device(dma_dom, devid); @@ -2139,7 +2135,7 @@ int __init amd_iommu_init_dma_ops(void) * protection domain will be assigned to the default one. */ for_each_iommu(iommu) { - iommu->default_dom = dma_ops_domain_alloc(iommu); + iommu->default_dom = dma_ops_domain_alloc(); if (iommu->default_dom == NULL) return -ENOMEM; iommu->default_dom->domain.flags |= PD_DEFAULT_MASK; From 308973d3b958b9328a1051642c81ee6dbc5021a4 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 24 Nov 2009 17:43:32 +0100 Subject: [PATCH 212/298] x86/amd-iommu: Move some pte allocation functions in the right section This patch moves alloc_pte() and fetch_pte() into the page table handling code section so that the forward declarations for them could be removed. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 193 ++++++++++++++++++------------------ 1 file changed, 94 insertions(+), 99 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 17e83ecb8b2..90b365024c2 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -59,15 +59,10 @@ struct iommu_cmd { static int dma_ops_unity_map(struct dma_ops_domain *dma_dom, struct unity_map_entry *e); -static u64 *alloc_pte(struct protection_domain *domain, - unsigned long address, int end_lvl, - u64 **pte_page, gfp_t gfp); static void dma_ops_reserve_addresses(struct dma_ops_domain *dom, unsigned long start_page, unsigned int pages); static void reset_iommu_command_buffer(struct amd_iommu *iommu); -static u64 *fetch_pte(struct protection_domain *domain, - unsigned long address, int map_size); static void update_domain(struct protection_domain *domain); /**************************************************************************** @@ -664,6 +659,100 @@ void amd_iommu_flush_all_devices(void) * ****************************************************************************/ +/* + * This function is used to add another level to an IO page table. Adding + * another level increases the size of the address space by 9 bits to a size up + * to 64 bits. + */ +static bool increase_address_space(struct protection_domain *domain, + gfp_t gfp) +{ + u64 *pte; + + if (domain->mode == PAGE_MODE_6_LEVEL) + /* address space already 64 bit large */ + return false; + + pte = (void *)get_zeroed_page(gfp); + if (!pte) + return false; + + *pte = PM_LEVEL_PDE(domain->mode, + virt_to_phys(domain->pt_root)); + domain->pt_root = pte; + domain->mode += 1; + domain->updated = true; + + return true; +} + +static u64 *alloc_pte(struct protection_domain *domain, + unsigned long address, + int end_lvl, + u64 **pte_page, + gfp_t gfp) +{ + u64 *pte, *page; + int level; + + while (address > PM_LEVEL_SIZE(domain->mode)) + increase_address_space(domain, gfp); + + level = domain->mode - 1; + pte = &domain->pt_root[PM_LEVEL_INDEX(level, address)]; + + while (level > end_lvl) { + if (!IOMMU_PTE_PRESENT(*pte)) { + page = (u64 *)get_zeroed_page(gfp); + if (!page) + return NULL; + *pte = PM_LEVEL_PDE(level, virt_to_phys(page)); + } + + level -= 1; + + pte = IOMMU_PTE_PAGE(*pte); + + if (pte_page && level == end_lvl) + *pte_page = pte; + + pte = &pte[PM_LEVEL_INDEX(level, address)]; + } + + return pte; +} + +/* + * This function checks if there is a PTE for a given dma address. If + * there is one, it returns the pointer to it. + */ +static u64 *fetch_pte(struct protection_domain *domain, + unsigned long address, int map_size) +{ + int level; + u64 *pte; + + level = domain->mode - 1; + pte = &domain->pt_root[PM_LEVEL_INDEX(level, address)]; + + while (level > map_size) { + if (!IOMMU_PTE_PRESENT(*pte)) + return NULL; + + level -= 1; + + pte = IOMMU_PTE_PAGE(*pte); + pte = &pte[PM_LEVEL_INDEX(level, address)]; + + if ((PM_PTE_LEVEL(*pte) == 0) && level != map_size) { + pte = NULL; + break; + } + } + + return pte; +} + /* * Generic mapping functions. It maps a physical address into a DMA * address space. It allocates the page table pages if necessary. @@ -819,37 +908,6 @@ static int init_unity_mappings_for_device(struct dma_ops_domain *dma_dom, * called with domain->lock held */ -/* - * This function checks if there is a PTE for a given dma address. If - * there is one, it returns the pointer to it. - */ -static u64 *fetch_pte(struct protection_domain *domain, - unsigned long address, int map_size) -{ - int level; - u64 *pte; - - level = domain->mode - 1; - pte = &domain->pt_root[PM_LEVEL_INDEX(level, address)]; - - while (level > map_size) { - if (!IOMMU_PTE_PRESENT(*pte)) - return NULL; - - level -= 1; - - pte = IOMMU_PTE_PAGE(*pte); - pte = &pte[PM_LEVEL_INDEX(level, address)]; - - if ((PM_PTE_LEVEL(*pte) == 0) && level != map_size) { - pte = NULL; - break; - } - } - - return pte; -} - /* * This function is used to add a new aperture range to an existing * aperture in case of dma_ops domain allocation or address allocation @@ -1534,69 +1592,6 @@ static void update_domain(struct protection_domain *domain) domain->updated = false; } -/* - * This function is used to add another level to an IO page table. Adding - * another level increases the size of the address space by 9 bits to a size up - * to 64 bits. - */ -static bool increase_address_space(struct protection_domain *domain, - gfp_t gfp) -{ - u64 *pte; - - if (domain->mode == PAGE_MODE_6_LEVEL) - /* address space already 64 bit large */ - return false; - - pte = (void *)get_zeroed_page(gfp); - if (!pte) - return false; - - *pte = PM_LEVEL_PDE(domain->mode, - virt_to_phys(domain->pt_root)); - domain->pt_root = pte; - domain->mode += 1; - domain->updated = true; - - return true; -} - -static u64 *alloc_pte(struct protection_domain *domain, - unsigned long address, - int end_lvl, - u64 **pte_page, - gfp_t gfp) -{ - u64 *pte, *page; - int level; - - while (address > PM_LEVEL_SIZE(domain->mode)) - increase_address_space(domain, gfp); - - level = domain->mode - 1; - pte = &domain->pt_root[PM_LEVEL_INDEX(level, address)]; - - while (level > end_lvl) { - if (!IOMMU_PTE_PRESENT(*pte)) { - page = (u64 *)get_zeroed_page(gfp); - if (!page) - return NULL; - *pte = PM_LEVEL_PDE(level, virt_to_phys(page)); - } - - level -= 1; - - pte = IOMMU_PTE_PAGE(*pte); - - if (pte_page && level == end_lvl) - *pte_page = pte; - - pte = &pte[PM_LEVEL_INDEX(level, address)]; - } - - return pte; -} - /* * This function fetches the PTE for a given address in the aperture */ From 171e7b3739e175eea7b32eca9dbe189589e14a28 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 24 Nov 2009 17:47:56 +0100 Subject: [PATCH 213/298] x86/amd-iommu: Rearrange dma_ops related functions This patch rearranges two dma_ops related functions so that their forward declarations are not longer necessary. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 89 +++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 47 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 90b365024c2..14b60c0cdc7 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -57,11 +57,6 @@ struct iommu_cmd { u32 data[4]; }; -static int dma_ops_unity_map(struct dma_ops_domain *dma_dom, - struct unity_map_entry *e); -static void dma_ops_reserve_addresses(struct dma_ops_domain *dom, - unsigned long start_page, - unsigned int pages); static void reset_iommu_command_buffer(struct amd_iommu *iommu); static void update_domain(struct protection_domain *domain); @@ -822,28 +817,6 @@ static int iommu_for_unity_map(struct amd_iommu *iommu, return 0; } -/* - * Init the unity mappings for a specific IOMMU in the system - * - * Basically iterates over all unity mapping entries and applies them to - * the default domain DMA of that IOMMU if necessary. - */ -static int iommu_init_unity_mappings(struct amd_iommu *iommu) -{ - struct unity_map_entry *entry; - int ret; - - list_for_each_entry(entry, &amd_iommu_unity_map, list) { - if (!iommu_for_unity_map(iommu, entry)) - continue; - ret = dma_ops_unity_map(iommu->default_dom, entry); - if (ret) - return ret; - } - - return 0; -} - /* * This function actually applies the mapping to the page table of the * dma_ops domain. @@ -872,6 +845,28 @@ static int dma_ops_unity_map(struct dma_ops_domain *dma_dom, return 0; } +/* + * Init the unity mappings for a specific IOMMU in the system + * + * Basically iterates over all unity mapping entries and applies them to + * the default domain DMA of that IOMMU if necessary. + */ +static int iommu_init_unity_mappings(struct amd_iommu *iommu) +{ + struct unity_map_entry *entry; + int ret; + + list_for_each_entry(entry, &amd_iommu_unity_map, list) { + if (!iommu_for_unity_map(iommu, entry)) + continue; + ret = dma_ops_unity_map(iommu->default_dom, entry); + if (ret) + return ret; + } + + return 0; +} + /* * Inits the unity mappings required for a specific device */ @@ -908,6 +903,26 @@ static int init_unity_mappings_for_device(struct dma_ops_domain *dma_dom, * called with domain->lock held */ +/* + * Used to reserve address ranges in the aperture (e.g. for exclusion + * ranges. + */ +static void dma_ops_reserve_addresses(struct dma_ops_domain *dom, + unsigned long start_page, + unsigned int pages) +{ + unsigned int i, last_page = dom->aperture_size >> PAGE_SHIFT; + + if (start_page + pages > last_page) + pages = last_page - start_page; + + for (i = start_page; i < start_page + pages; ++i) { + int index = i / APERTURE_RANGE_PAGES; + int page = i % APERTURE_RANGE_PAGES; + __set_bit(page, dom->aperture[index]->bitmap); + } +} + /* * This function is used to add a new aperture range to an existing * aperture in case of dma_ops domain allocation or address allocation @@ -1166,26 +1181,6 @@ static void domain_id_free(int id) write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); } -/* - * Used to reserve address ranges in the aperture (e.g. for exclusion - * ranges. - */ -static void dma_ops_reserve_addresses(struct dma_ops_domain *dom, - unsigned long start_page, - unsigned int pages) -{ - unsigned int i, last_page = dom->aperture_size >> PAGE_SHIFT; - - if (start_page + pages > last_page) - pages = last_page - start_page; - - for (i = start_page; i < start_page + pages; ++i) { - int index = i / APERTURE_RANGE_PAGES; - int page = i % APERTURE_RANGE_PAGES; - __set_bit(page, dom->aperture[index]->bitmap); - } -} - static void free_pagetable(struct protection_domain *domain) { int i, j; From 8793abeb783c12cc37f92f6133fd6468152b98df Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 27 Nov 2009 11:40:33 +0100 Subject: [PATCH 214/298] x86/amd-iommu: Remove support for domain sharing This patch makes device isolation mandatory and removes support for the amd_iommu=share option. This simplifies the code in several places. Signed-off-by: Joerg Roedel --- arch/x86/include/asm/amd_iommu_types.h | 3 --- arch/x86/kernel/amd_iommu.c | 10 ++-------- arch/x86/kernel/amd_iommu_init.c | 17 ----------------- 3 files changed, 2 insertions(+), 28 deletions(-) diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 4899f783df6..02b6a0fd863 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -451,9 +451,6 @@ extern struct protection_domain **amd_iommu_pd_table; /* allocation bitmap for domain ids */ extern unsigned long *amd_iommu_pd_alloc_bitmap; -/* will be 1 if device isolation is enabled */ -extern bool amd_iommu_isolate; - /* * If true, the addresses will be flushed on unmap time, not when * they are reused diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 14b60c0cdc7..ed58a168839 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -148,7 +148,6 @@ DECLARE_STATS_COUNTER(alloced_io_mem); DECLARE_STATS_COUNTER(total_map_requests); static struct dentry *stats_dir; -static struct dentry *de_isolate; static struct dentry *de_fflush; static void amd_iommu_stats_add(struct __iommu_counter *cnt) @@ -166,9 +165,6 @@ static void amd_iommu_stats_init(void) if (stats_dir == NULL) return; - de_isolate = debugfs_create_bool("isolation", 0444, stats_dir, - (u32 *)&amd_iommu_isolate); - de_fflush = debugfs_create_bool("fullflush", 0444, stats_dir, (u32 *)&amd_iommu_unmap_flush); @@ -2135,11 +2131,9 @@ int __init amd_iommu_init_dma_ops(void) } /* - * If device isolation is enabled, pre-allocate the protection - * domains for each device. + * Pre-allocate the protection domains for each device. */ - if (amd_iommu_isolate) - prealloc_protection_domains(); + prealloc_protection_domains(); iommu_detected = 1; swiotlb = 0; diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index fbe4c3c02a9..fe1686f6f91 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -125,13 +125,6 @@ u16 amd_iommu_last_bdf; /* largest PCI device id we have to handle */ LIST_HEAD(amd_iommu_unity_map); /* a list of required unity mappings we find in ACPI */ -#ifdef CONFIG_IOMMU_STRESS -bool amd_iommu_isolate = false; -#else -bool amd_iommu_isolate = true; /* if true, device isolation is - enabled */ -#endif - bool amd_iommu_unmap_flush; /* if true, flush on every unmap */ LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the @@ -1308,12 +1301,6 @@ static int __init amd_iommu_init(void) if (iommu_pass_through) goto out; - printk(KERN_INFO "AMD-Vi: device isolation "); - if (amd_iommu_isolate) - printk("enabled\n"); - else - printk("disabled\n"); - if (amd_iommu_unmap_flush) printk(KERN_INFO "AMD-Vi: IO/TLB flush on unmap enabled\n"); else @@ -1387,10 +1374,6 @@ static int __init parse_amd_iommu_dump(char *str) static int __init parse_amd_iommu_options(char *str) { for (; *str; ++str) { - if (strncmp(str, "isolate", 7) == 0) - amd_iommu_isolate = true; - if (strncmp(str, "share", 5) == 0) - amd_iommu_isolate = false; if (strncmp(str, "fullflush", 9) == 0) amd_iommu_unmap_flush = true; } From 657cbb6b6cba0f9c98c5299e0c803b2c0e67ea0a Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 23 Nov 2009 15:26:46 +0100 Subject: [PATCH 215/298] x86/amd-iommu: Use dev->arch->iommu to store iommu related information This patch changes IOMMU code to use dev->archdata->iommu to store information about the alias device and the domain the device is attached to. This allows the driver to get rid of the amd_iommu_pd_table in the future. Signed-off-by: Joerg Roedel --- arch/x86/include/asm/amd_iommu_types.h | 8 ++ arch/x86/include/asm/device.h | 2 +- arch/x86/kernel/amd_iommu.c | 109 +++++++++++++++++++------ 3 files changed, 95 insertions(+), 24 deletions(-) diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 02b6a0fd863..9eaa27b4686 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -247,6 +247,14 @@ struct protection_domain { }; +/* + * This struct contains device specific data for the IOMMU + */ +struct iommu_dev_data { + struct device *alias; /* The Alias Device */ + struct protection_domain *domain; /* Domain the device is bound to */ +}; + /* * For dynamic growth the aperture size is split into ranges of 128MB of * DMA address space each. This struct represents one such range. diff --git a/arch/x86/include/asm/device.h b/arch/x86/include/asm/device.h index cee34e9ca45..029f230ab63 100644 --- a/arch/x86/include/asm/device.h +++ b/arch/x86/include/asm/device.h @@ -8,7 +8,7 @@ struct dev_archdata { #ifdef CONFIG_X86_64 struct dma_map_ops *dma_ops; #endif -#ifdef CONFIG_DMAR +#if defined(CONFIG_DMAR) || defined(CONFIG_AMD_IOMMU) void *iommu; /* hook for IOMMU specific extension */ #endif }; diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index ed58a168839..3214e8806f9 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -73,6 +73,11 @@ static inline u16 get_device_id(struct device *dev) return calc_devid(pdev->bus->number, pdev->devfn); } +static struct iommu_dev_data *get_dev_data(struct device *dev) +{ + return dev->archdata.iommu; +} + /* * In this function the list of preallocated protection domains is traversed to * find the domain for a specific device @@ -128,6 +133,35 @@ static bool check_device(struct device *dev) return true; } +static int iommu_init_device(struct device *dev) +{ + struct iommu_dev_data *dev_data; + struct pci_dev *pdev; + u16 devid, alias; + + if (dev->archdata.iommu) + return 0; + + dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL); + if (!dev_data) + return -ENOMEM; + + devid = get_device_id(dev); + alias = amd_iommu_alias_table[devid]; + pdev = pci_get_bus_and_slot(PCI_BUS(alias), alias & 0xff); + if (pdev) + dev_data->alias = &pdev->dev; + + dev->archdata.iommu = dev_data; + + + return 0; +} + +static void iommu_uninit_device(struct device *dev) +{ + kfree(dev->archdata.iommu); +} #ifdef CONFIG_AMD_IOMMU_STATS /* @@ -1346,28 +1380,39 @@ static void clear_dte_entry(u16 devid) static int __attach_device(struct device *dev, struct protection_domain *domain) { - u16 devid = get_device_id(dev); - u16 alias = amd_iommu_alias_table[devid]; + struct iommu_dev_data *dev_data, *alias_data; + u16 devid, alias; + + devid = get_device_id(dev); + alias = amd_iommu_alias_table[devid]; + dev_data = get_dev_data(dev); + alias_data = get_dev_data(dev_data->alias); + if (!alias_data) + return -EINVAL; /* lock domain */ spin_lock(&domain->lock); /* Some sanity checks */ - if (amd_iommu_pd_table[alias] != NULL && - amd_iommu_pd_table[alias] != domain) + if (alias_data->domain != NULL && + alias_data->domain != domain) return -EBUSY; - if (amd_iommu_pd_table[devid] != NULL && - amd_iommu_pd_table[devid] != domain) + if (dev_data->domain != NULL && + dev_data->domain != domain) return -EBUSY; /* Do real assignment */ if (alias != devid && - amd_iommu_pd_table[alias] == NULL) + alias_data->domain == NULL) { + alias_data->domain = domain; set_dte_entry(alias, domain); + } - if (amd_iommu_pd_table[devid] == NULL) + if (dev_data->domain == NULL) { + dev_data->domain = domain; set_dte_entry(devid, domain); + } /* ready */ spin_unlock(&domain->lock); @@ -1406,10 +1451,12 @@ static void __detach_device(struct device *dev) { u16 devid = get_device_id(dev); struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; + struct iommu_dev_data *dev_data = get_dev_data(dev); BUG_ON(!iommu); clear_dte_entry(devid); + dev_data->domain = NULL; /* * If we run in passthrough mode the device must be assigned to the @@ -1439,18 +1486,23 @@ static void detach_device(struct device *dev) static struct protection_domain *domain_for_device(struct device *dev) { struct protection_domain *dom; + struct iommu_dev_data *dev_data, *alias_data; unsigned long flags; u16 devid, alias; - devid = get_device_id(dev); - alias = amd_iommu_alias_table[devid]; + devid = get_device_id(dev); + alias = amd_iommu_alias_table[devid]; + dev_data = get_dev_data(dev); + alias_data = get_dev_data(dev_data->alias); + if (!alias_data) + return NULL; read_lock_irqsave(&amd_iommu_devtable_lock, flags); - dom = amd_iommu_pd_table[devid]; + dom = dev_data->domain; if (dom == NULL && - amd_iommu_pd_table[alias] != NULL) { - __attach_device(dev, amd_iommu_pd_table[alias]); - dom = amd_iommu_pd_table[devid]; + alias_data->domain != NULL) { + __attach_device(dev, alias_data->domain); + dom = alias_data->domain; } read_unlock_irqrestore(&amd_iommu_devtable_lock, flags); @@ -1473,14 +1525,12 @@ static int device_change_notifier(struct notifier_block *nb, devid = get_device_id(dev); iommu = amd_iommu_rlookup_table[devid]; - domain = domain_for_device(dev); - - if (domain && !dma_ops_domain(domain)) - WARN_ONCE(1, "AMD IOMMU WARNING: device %s already bound " - "to a non-dma-ops domain\n", dev_name(dev)); switch (action) { case BUS_NOTIFY_UNBOUND_DRIVER: + + domain = domain_for_device(dev); + if (!domain) goto out; if (iommu_pass_through) @@ -1488,6 +1538,11 @@ static int device_change_notifier(struct notifier_block *nb, detach_device(dev); break; case BUS_NOTIFY_ADD_DEVICE: + + iommu_init_device(dev); + + domain = domain_for_device(dev); + /* allocate a protection domain if a device is added */ dma_domain = find_protection_domain(devid); if (dma_domain) @@ -1502,6 +1557,10 @@ static int device_change_notifier(struct notifier_block *nb, spin_unlock_irqrestore(&iommu_pd_list_lock, flags); break; + case BUS_NOTIFY_DEL_DEVICE: + + iommu_uninit_device(dev); + default: goto out; } @@ -2079,6 +2138,8 @@ static void prealloc_protection_domains(void) if (!check_device(&dev->dev)) continue; + iommu_init_device(&dev->dev); + /* Is there already any domain for it? */ if (domain_for_device(&dev->dev)) continue; @@ -2270,6 +2331,7 @@ static void amd_iommu_domain_destroy(struct iommu_domain *dom) static void amd_iommu_detach_device(struct iommu_domain *dom, struct device *dev) { + struct iommu_dev_data *dev_data = dev->archdata.iommu; struct amd_iommu *iommu; u16 devid; @@ -2278,7 +2340,7 @@ static void amd_iommu_detach_device(struct iommu_domain *dom, devid = get_device_id(dev); - if (amd_iommu_pd_table[devid] != NULL) + if (dev_data->domain != NULL) detach_device(dev); iommu = amd_iommu_rlookup_table[devid]; @@ -2293,7 +2355,7 @@ static int amd_iommu_attach_device(struct iommu_domain *dom, struct device *dev) { struct protection_domain *domain = dom->priv; - struct protection_domain *old_domain; + struct iommu_dev_data *dev_data; struct amd_iommu *iommu; int ret; u16 devid; @@ -2301,14 +2363,15 @@ static int amd_iommu_attach_device(struct iommu_domain *dom, if (!check_device(dev)) return -EINVAL; + dev_data = dev->archdata.iommu; + devid = get_device_id(dev); iommu = amd_iommu_rlookup_table[devid]; if (!iommu) return -EINVAL; - old_domain = amd_iommu_pd_table[devid]; - if (old_domain) + if (dev_data->domain) detach_device(dev); ret = attach_device(dev, domain); From 241000556f751dacd332df6ab2e903a23746e51e Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 25 Nov 2009 15:59:57 +0100 Subject: [PATCH 216/298] x86/amd-iommu: Add device bind reference counting This patch adds a reference count to each device to count how often the device was bound to that domain. This is important for single devices that act as an alias for a number of others. These devices must stay bound to their domains until all devices that alias to it are unbound from the same domain. Signed-off-by: Joerg Roedel --- arch/x86/include/asm/amd_iommu_types.h | 1 + arch/x86/kernel/amd_iommu.c | 37 ++++++++++++++++++++------ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 9eaa27b4686..434e90ed89c 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -253,6 +253,7 @@ struct protection_domain { struct iommu_dev_data { struct device *alias; /* The Alias Device */ struct protection_domain *domain; /* Domain the device is bound to */ + atomic_t bind; /* Domain attach reverent count */ }; /* diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 3214e8806f9..f5db7d5e444 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -152,6 +152,8 @@ static int iommu_init_device(struct device *dev) if (pdev) dev_data->alias = &pdev->dev; + atomic_set(&dev_data->bind, 0); + dev->archdata.iommu = dev_data; @@ -1403,10 +1405,13 @@ static int __attach_device(struct device *dev, return -EBUSY; /* Do real assignment */ - if (alias != devid && - alias_data->domain == NULL) { - alias_data->domain = domain; - set_dte_entry(alias, domain); + if (alias != devid) { + if (alias_data->domain == NULL) { + alias_data->domain = domain; + set_dte_entry(alias, domain); + } + + atomic_inc(&alias_data->bind); } if (dev_data->domain == NULL) { @@ -1414,6 +1419,8 @@ static int __attach_device(struct device *dev, set_dte_entry(devid, domain); } + atomic_inc(&dev_data->bind); + /* ready */ spin_unlock(&domain->lock); @@ -1449,20 +1456,34 @@ static int attach_device(struct device *dev, */ static void __detach_device(struct device *dev) { - u16 devid = get_device_id(dev); + u16 devid = get_device_id(dev), alias; struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; struct iommu_dev_data *dev_data = get_dev_data(dev); + struct iommu_dev_data *alias_data; BUG_ON(!iommu); - clear_dte_entry(devid); - dev_data->domain = NULL; + devid = get_device_id(dev); + alias = get_device_id(dev_data->alias); + + if (devid != alias) { + alias_data = get_dev_data(dev_data->alias); + if (atomic_dec_and_test(&alias_data->bind)) { + clear_dte_entry(alias); + alias_data->domain = NULL; + } + } + + if (atomic_dec_and_test(&dev_data->bind)) { + clear_dte_entry(devid); + dev_data->domain = NULL; + } /* * If we run in passthrough mode the device must be assigned to the * passthrough domain if it is detached from any other domain */ - if (iommu_pass_through) + if (iommu_pass_through && dev_data->domain == NULL) __attach_device(dev, pt_domain); } From 7c392cbe984d904f7c89a6a75b2ac245254e8da5 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 26 Nov 2009 11:13:32 +0100 Subject: [PATCH 217/298] x86/amd-iommu: Keep devices per domain in a list This patch introduces a list to each protection domain which keeps all devices associated with the domain. This can be used later to optimize certain functions and to completly remove the amd_iommu_pd_table. Signed-off-by: Joerg Roedel --- arch/x86/include/asm/amd_iommu_types.h | 2 ++ arch/x86/kernel/amd_iommu.c | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 434e90ed89c..93953d1922c 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -235,6 +235,7 @@ extern bool amd_iommu_np_cache; */ struct protection_domain { struct list_head list; /* for list of all protection domains */ + struct list_head dev_list; /* List of all devices in this domain */ spinlock_t lock; /* mostly used to lock the page table*/ u16 id; /* the domain id written to the device table */ int mode; /* paging mode (0-6 levels) */ @@ -251,6 +252,7 @@ struct protection_domain { * This struct contains device specific data for the IOMMU */ struct iommu_dev_data { + struct list_head list; /* For domain->dev_list */ struct device *alias; /* The Alias Device */ struct protection_domain *domain; /* Domain the device is bound to */ atomic_t bind; /* Domain attach reverent count */ diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index f5db7d5e444..530d6080940 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1286,6 +1286,7 @@ static struct dma_ops_domain *dma_ops_domain_alloc(void) dma_dom->domain.id = domain_id_alloc(); if (dma_dom->domain.id == 0) goto free_dma_dom; + INIT_LIST_HEAD(&dma_dom->domain.dev_list); dma_dom->domain.mode = PAGE_MODE_2_LEVEL; dma_dom->domain.pt_root = (void *)get_zeroed_page(GFP_KERNEL); dma_dom->domain.flags = PD_DMA_OPS_MASK; @@ -1408,6 +1409,7 @@ static int __attach_device(struct device *dev, if (alias != devid) { if (alias_data->domain == NULL) { alias_data->domain = domain; + list_add(&alias_data->list, &domain->dev_list); set_dte_entry(alias, domain); } @@ -1416,6 +1418,7 @@ static int __attach_device(struct device *dev, if (dev_data->domain == NULL) { dev_data->domain = domain; + list_add(&dev_data->list, &domain->dev_list); set_dte_entry(devid, domain); } @@ -1460,6 +1463,7 @@ static void __detach_device(struct device *dev) struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; struct iommu_dev_data *dev_data = get_dev_data(dev); struct iommu_dev_data *alias_data; + unsigned long flags; BUG_ON(!iommu); @@ -1469,13 +1473,19 @@ static void __detach_device(struct device *dev) if (devid != alias) { alias_data = get_dev_data(dev_data->alias); if (atomic_dec_and_test(&alias_data->bind)) { + spin_lock_irqsave(&alias_data->domain->lock, flags); clear_dte_entry(alias); + list_del(&alias_data->list); + spin_unlock_irqrestore(&alias_data->domain->lock, flags); alias_data->domain = NULL; } } if (atomic_dec_and_test(&dev_data->bind)) { + spin_lock_irqsave(&dev_data->domain->lock, flags); clear_dte_entry(devid); + list_del(&dev_data->list); + spin_unlock_irqrestore(&dev_data->domain->lock, flags); dev_data->domain = NULL; } @@ -2294,6 +2304,7 @@ static struct protection_domain *protection_domain_alloc(void) domain->id = domain_id_alloc(); if (!domain->id) goto out_err; + INIT_LIST_HEAD(&domain->dev_list); add_domain_to_list(domain); From 7f760ddd702d162d693bc79f62c3bdd7fe55bd9d Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 26 Nov 2009 14:49:59 +0100 Subject: [PATCH 218/298] x86/amd-iommu: Cleanup attach/detach_device code This patch cleans up the attach_device and detach_device paths and fixes reference counting while at it. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 102 ++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 44 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 530d6080940..e3363fd5eef 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1329,7 +1329,6 @@ static bool dma_ops_domain(struct protection_domain *domain) static void set_dte_entry(u16 devid, struct protection_domain *domain) { - struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; u64 pte_root = virt_to_phys(domain->pt_root); BUG_ON(amd_iommu_pd_table[devid] != NULL); @@ -1344,18 +1343,11 @@ static void set_dte_entry(u16 devid, struct protection_domain *domain) amd_iommu_pd_table[devid] = domain; - /* Do reference counting */ - domain->dev_iommu[iommu->index] += 1; - domain->dev_cnt += 1; - - /* Flush the changes DTE entry */ - iommu_queue_inv_dev_entry(iommu, devid); } static void clear_dte_entry(u16 devid) { struct protection_domain *domain = amd_iommu_pd_table[devid]; - struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; BUG_ON(domain == NULL); @@ -1368,11 +1360,51 @@ static void clear_dte_entry(u16 devid) amd_iommu_dev_table[devid].data[2] = 0; amd_iommu_apply_erratum_63(devid); +} + +static void do_attach(struct device *dev, struct protection_domain *domain) +{ + struct iommu_dev_data *dev_data; + struct amd_iommu *iommu; + u16 devid; + + devid = get_device_id(dev); + iommu = amd_iommu_rlookup_table[devid]; + dev_data = get_dev_data(dev); + + /* Update data structures */ + dev_data->domain = domain; + list_add(&dev_data->list, &domain->dev_list); + set_dte_entry(devid, domain); + + /* Do reference counting */ + domain->dev_iommu[iommu->index] += 1; + domain->dev_cnt += 1; + + /* Flush the DTE entry */ + iommu_queue_inv_dev_entry(iommu, devid); +} + +static void do_detach(struct device *dev) +{ + struct iommu_dev_data *dev_data; + struct amd_iommu *iommu; + u16 devid; + + devid = get_device_id(dev); + iommu = amd_iommu_rlookup_table[devid]; + dev_data = get_dev_data(dev); /* decrease reference counters */ - domain->dev_iommu[iommu->index] -= 1; - domain->dev_cnt -= 1; + dev_data->domain->dev_iommu[iommu->index] -= 1; + dev_data->domain->dev_cnt -= 1; + /* Update data structures */ + dev_data->domain = NULL; + list_del(&dev_data->list); + clear_dte_entry(devid); + + /* Flush the DTE entry */ iommu_queue_inv_dev_entry(iommu, devid); } @@ -1384,12 +1416,10 @@ static int __attach_device(struct device *dev, struct protection_domain *domain) { struct iommu_dev_data *dev_data, *alias_data; - u16 devid, alias; - devid = get_device_id(dev); - alias = amd_iommu_alias_table[devid]; dev_data = get_dev_data(dev); alias_data = get_dev_data(dev_data->alias); + if (!alias_data) return -EINVAL; @@ -1406,21 +1436,16 @@ static int __attach_device(struct device *dev, return -EBUSY; /* Do real assignment */ - if (alias != devid) { - if (alias_data->domain == NULL) { - alias_data->domain = domain; - list_add(&alias_data->list, &domain->dev_list); - set_dte_entry(alias, domain); - } + if (dev_data->alias != dev) { + alias_data = get_dev_data(dev_data->alias); + if (alias_data->domain == NULL) + do_attach(dev_data->alias, domain); atomic_inc(&alias_data->bind); } - if (dev_data->domain == NULL) { - dev_data->domain = domain; - list_add(&dev_data->list, &domain->dev_list); - set_dte_entry(devid, domain); - } + if (dev_data->domain == NULL) + do_attach(dev, domain); atomic_inc(&dev_data->bind); @@ -1459,35 +1484,24 @@ static int attach_device(struct device *dev, */ static void __detach_device(struct device *dev) { - u16 devid = get_device_id(dev), alias; - struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; struct iommu_dev_data *dev_data = get_dev_data(dev); struct iommu_dev_data *alias_data; unsigned long flags; - BUG_ON(!iommu); + BUG_ON(!dev_data->domain); - devid = get_device_id(dev); - alias = get_device_id(dev_data->alias); + spin_lock_irqsave(&dev_data->domain->lock, flags); - if (devid != alias) { + if (dev_data->alias != dev) { alias_data = get_dev_data(dev_data->alias); - if (atomic_dec_and_test(&alias_data->bind)) { - spin_lock_irqsave(&alias_data->domain->lock, flags); - clear_dte_entry(alias); - list_del(&alias_data->list); - spin_unlock_irqrestore(&alias_data->domain->lock, flags); - alias_data->domain = NULL; - } + if (atomic_dec_and_test(&alias_data->bind)) + do_detach(dev_data->alias); } - if (atomic_dec_and_test(&dev_data->bind)) { - spin_lock_irqsave(&dev_data->domain->lock, flags); - clear_dte_entry(devid); - list_del(&dev_data->list); - spin_unlock_irqrestore(&dev_data->domain->lock, flags); - dev_data->domain = NULL; - } + if (atomic_dec_and_test(&dev_data->bind)) + do_detach(dev); + + spin_unlock_irqrestore(&dev_data->domain->lock, flags); /* * If we run in passthrough mode the device must be assigned to the From 3fa43655d81d471d47c44b0db4e2be1f8af32207 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 26 Nov 2009 15:04:38 +0100 Subject: [PATCH 219/298] x86/amd-iommu: Introduce iommu_flush_device() function This patch adds a function to flush a DTE entry for a given struct device and replaces iommu_queue_inv_dev_entry calls with this function where appropriate. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index e3363fd5eef..41c4ebecced 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -494,6 +494,17 @@ static int iommu_queue_inv_dev_entry(struct amd_iommu *iommu, u16 devid) return ret; } +static int iommu_flush_device(struct device *dev) +{ + struct amd_iommu *iommu; + u16 devid; + + devid = get_device_id(dev); + iommu = amd_iommu_rlookup_table[devid]; + + return iommu_queue_inv_dev_entry(iommu, devid); +} + static void __iommu_build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address, u16 domid, int pde, int s) { @@ -1382,7 +1393,7 @@ static void do_attach(struct device *dev, struct protection_domain *domain) domain->dev_cnt += 1; /* Flush the DTE entry */ - iommu_queue_inv_dev_entry(iommu, devid); + iommu_flush_device(dev); } static void do_detach(struct device *dev) @@ -1405,7 +1416,7 @@ static void do_detach(struct device *dev) clear_dte_entry(devid); /* Flush the DTE entry */ - iommu_queue_inv_dev_entry(iommu, devid); + iommu_flush_device(dev); } /* @@ -1610,7 +1621,7 @@ static int device_change_notifier(struct notifier_block *nb, goto out; } - iommu_queue_inv_dev_entry(iommu, devid); + iommu_flush_device(dev); iommu_completion_wait(iommu); out: @@ -2393,7 +2404,7 @@ static void amd_iommu_detach_device(struct iommu_domain *dom, if (!iommu) return; - iommu_queue_inv_dev_entry(iommu, devid); + iommu_flush_device(dev); iommu_completion_wait(iommu); } From b00d3bcff4d996f65e337d404b0df5dc201a01ab Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 26 Nov 2009 15:35:33 +0100 Subject: [PATCH 220/298] x86/amd-iommu: Cleanup DTE flushing code This patch cleans up the code to flush device table entries in the IOMMU. With this chance the driver can get rid of the iommu_queue_inv_dev_entry() function. Signed-off-by: Joerg Roedel --- arch/x86/include/asm/amd_iommu_types.h | 1 + arch/x86/kernel/amd_iommu.c | 100 +++++++++---------------- 2 files changed, 35 insertions(+), 66 deletions(-) diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 93953d1922c..f92d1b37b87 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -253,6 +253,7 @@ struct protection_domain { */ struct iommu_dev_data { struct list_head list; /* For domain->dev_list */ + struct device *dev; /* Device this data belong to */ struct device *alias; /* The Alias Device */ struct protection_domain *domain; /* Domain the device is bound to */ atomic_t bind; /* Domain attach reverent count */ diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 41c4ebecced..0eafca58926 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -146,6 +146,8 @@ static int iommu_init_device(struct device *dev) if (!dev_data) return -ENOMEM; + dev_data->dev = dev; + devid = get_device_id(dev); alias = amd_iommu_alias_table[devid]; pdev = pci_get_bus_and_slot(PCI_BUS(alias), alias & 0xff); @@ -478,31 +480,21 @@ static void iommu_flush_complete(struct protection_domain *domain) /* * Command send function for invalidating a device table entry */ -static int iommu_queue_inv_dev_entry(struct amd_iommu *iommu, u16 devid) -{ - struct iommu_cmd cmd; - int ret; - - BUG_ON(iommu == NULL); - - memset(&cmd, 0, sizeof(cmd)); - CMD_SET_TYPE(&cmd, CMD_INV_DEV_ENTRY); - cmd.data[0] = devid; - - ret = iommu_queue_command(iommu, &cmd); - - return ret; -} - static int iommu_flush_device(struct device *dev) { struct amd_iommu *iommu; + struct iommu_cmd cmd; u16 devid; devid = get_device_id(dev); iommu = amd_iommu_rlookup_table[devid]; - return iommu_queue_inv_dev_entry(iommu, devid); + /* Build command */ + memset(&cmd, 0, sizeof(cmd)); + CMD_SET_TYPE(&cmd, CMD_INV_DEV_ENTRY); + cmd.data[0] = devid; + + return iommu_queue_command(iommu, &cmd); } static void __iommu_build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address, @@ -592,30 +584,43 @@ static void iommu_flush_tlb_pde(struct protection_domain *domain) __iommu_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 1); } + /* - * This function flushes all domains that have devices on the given IOMMU + * This function flushes the DTEs for all devices in domain */ -static void flush_all_domains_on_iommu(struct amd_iommu *iommu) +static void iommu_flush_domain_devices(struct protection_domain *domain) +{ + struct iommu_dev_data *dev_data; + unsigned long flags; + + spin_lock_irqsave(&domain->lock, flags); + + list_for_each_entry(dev_data, &domain->dev_list, list) + iommu_flush_device(dev_data->dev); + + spin_unlock_irqrestore(&domain->lock, flags); +} + +static void iommu_flush_all_domain_devices(void) { - u64 address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS; struct protection_domain *domain; unsigned long flags; spin_lock_irqsave(&amd_iommu_pd_lock, flags); list_for_each_entry(domain, &amd_iommu_pd_list, list) { - if (domain->dev_iommu[iommu->index] == 0) - continue; - - spin_lock(&domain->lock); - iommu_queue_inv_iommu_pages(iommu, address, domain->id, 1, 1); + iommu_flush_domain_devices(domain); iommu_flush_complete(domain); - spin_unlock(&domain->lock); } spin_unlock_irqrestore(&amd_iommu_pd_lock, flags); } +void amd_iommu_flush_all_devices(void) +{ + iommu_flush_all_domain_devices(); +} + /* * This function uses heavy locking and may disable irqs for some time. But * this is no issue because it is only called during resume. @@ -637,38 +642,6 @@ void amd_iommu_flush_all_domains(void) spin_unlock_irqrestore(&amd_iommu_pd_lock, flags); } -static void flush_all_devices_for_iommu(struct amd_iommu *iommu) -{ - int i; - - for (i = 0; i <= amd_iommu_last_bdf; ++i) { - if (iommu != amd_iommu_rlookup_table[i]) - continue; - - iommu_queue_inv_dev_entry(iommu, i); - iommu_completion_wait(iommu); - } -} - -static void flush_devices_by_domain(struct protection_domain *domain) -{ - struct amd_iommu *iommu; - int i; - - for (i = 0; i <= amd_iommu_last_bdf; ++i) { - if ((domain == NULL && amd_iommu_pd_table[i] == NULL) || - (amd_iommu_pd_table[i] != domain)) - continue; - - iommu = amd_iommu_rlookup_table[i]; - if (!iommu) - continue; - - iommu_queue_inv_dev_entry(iommu, i); - iommu_completion_wait(iommu); - } -} - static void reset_iommu_command_buffer(struct amd_iommu *iommu) { pr_err("AMD-Vi: Resetting IOMMU command buffer\n"); @@ -679,17 +652,12 @@ static void reset_iommu_command_buffer(struct amd_iommu *iommu) iommu->reset_in_progress = true; amd_iommu_reset_cmd_buffer(iommu); - flush_all_devices_for_iommu(iommu); - flush_all_domains_on_iommu(iommu); + amd_iommu_flush_all_devices(); + amd_iommu_flush_all_domains(); iommu->reset_in_progress = false; } -void amd_iommu_flush_all_devices(void) -{ - flush_devices_by_domain(NULL); -} - /**************************************************************************** * * The functions below are used the create the page table mappings for @@ -1692,7 +1660,7 @@ static void update_domain(struct protection_domain *domain) return; update_device_table(domain); - flush_devices_by_domain(domain); + iommu_flush_domain_devices(domain); iommu_flush_tlb_pde(domain); domain->updated = false; From 8eed9833346781dd15e3bef35a91b0a40787ea3c Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 26 Nov 2009 15:45:41 +0100 Subject: [PATCH 221/298] x86/amd-iommu: Move reset_iommu_command_buffer out of locked code This patch removes the ugly contruct where the iommu->lock must be released while before calling the reset_iommu_command_buffer function. Signed-off-by: Joerg Roedel --- arch/x86/kernel/amd_iommu.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 0eafca58926..b75fcd9b6a0 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -285,6 +285,7 @@ static void iommu_print_event(struct amd_iommu *iommu, void *__evt) break; case EVENT_TYPE_ILL_CMD: printk("ILLEGAL_COMMAND_ERROR address=0x%016llx]\n", address); + iommu->reset_in_progress = true; reset_iommu_command_buffer(iommu); dump_command(address); break; @@ -407,11 +408,8 @@ static void __iommu_wait_for_completion(struct amd_iommu *iommu) status &= ~MMIO_STATUS_COM_WAIT_INT_MASK; writel(status, iommu->mmio_base + MMIO_STATUS_OFFSET); - if (unlikely(i == EXIT_LOOP_COUNT)) { - spin_unlock(&iommu->lock); - reset_iommu_command_buffer(iommu); - spin_lock(&iommu->lock); - } + if (unlikely(i == EXIT_LOOP_COUNT)) + iommu->reset_in_progress = true; } /* @@ -458,6 +456,9 @@ static int iommu_completion_wait(struct amd_iommu *iommu) out: spin_unlock_irqrestore(&iommu->lock, flags); + if (iommu->reset_in_progress) + reset_iommu_command_buffer(iommu); + return 0; } @@ -649,8 +650,6 @@ static void reset_iommu_command_buffer(struct amd_iommu *iommu) if (iommu->reset_in_progress) panic("AMD-Vi: ILLEGAL_COMMAND_ERROR while resetting command buffer\n"); - iommu->reset_in_progress = true; - amd_iommu_reset_cmd_buffer(iommu); amd_iommu_flush_all_devices(); amd_iommu_flush_all_domains(); From 492667dacc0ac9763969155482b1261b34ccf450 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 27 Nov 2009 13:25:47 +0100 Subject: [PATCH 222/298] x86/amd-iommu: Remove amd_iommu_pd_table The data that was stored in this table is now available in dev->archdata.iommu. So this table is not longer necessary. This patch removes the remaining uses of that variable and removes it from the code. Signed-off-by: Joerg Roedel --- arch/x86/include/asm/amd_iommu_types.h | 3 --- arch/x86/kernel/amd_iommu.c | 35 ++++++++------------------ arch/x86/kernel/amd_iommu_init.c | 18 ------------- 3 files changed, 11 insertions(+), 45 deletions(-) diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index f92d1b37b87..ba19ad4c47d 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h @@ -457,9 +457,6 @@ extern unsigned amd_iommu_aperture_order; /* largest PCI device id we expect translation requests for */ extern u16 amd_iommu_last_bdf; -/* data structures for protection domain handling */ -extern struct protection_domain **amd_iommu_pd_table; - /* allocation bitmap for domain ids */ extern unsigned long *amd_iommu_pd_alloc_bitmap; diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index b75fcd9b6a0..32fb09102a1 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1309,8 +1309,6 @@ static void set_dte_entry(u16 devid, struct protection_domain *domain) { u64 pte_root = virt_to_phys(domain->pt_root); - BUG_ON(amd_iommu_pd_table[devid] != NULL); - pte_root |= (domain->mode & DEV_ENTRY_MODE_MASK) << DEV_ENTRY_MODE_SHIFT; pte_root |= IOMMU_PTE_IR | IOMMU_PTE_IW | IOMMU_PTE_P | IOMMU_PTE_TV; @@ -1318,20 +1316,10 @@ static void set_dte_entry(u16 devid, struct protection_domain *domain) amd_iommu_dev_table[devid].data[2] = domain->id; amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root); amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root); - - amd_iommu_pd_table[devid] = domain; - } static void clear_dte_entry(u16 devid) { - struct protection_domain *domain = amd_iommu_pd_table[devid]; - - BUG_ON(domain == NULL); - - /* remove domain from the lookup table */ - amd_iommu_pd_table[devid] = NULL; - /* remove entry from the device table seen by the hardware */ amd_iommu_dev_table[devid].data[0] = IOMMU_PTE_P | IOMMU_PTE_TV; amd_iommu_dev_table[devid].data[1] = 0; @@ -1641,15 +1629,11 @@ static struct protection_domain *get_domain(struct device *dev) static void update_device_table(struct protection_domain *domain) { - unsigned long flags; - int i; + struct iommu_dev_data *dev_data; - for (i = 0; i <= amd_iommu_last_bdf; ++i) { - if (amd_iommu_pd_table[i] != domain) - continue; - write_lock_irqsave(&amd_iommu_devtable_lock, flags); - set_dte_entry(i, domain); - write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); + list_for_each_entry(dev_data, &domain->dev_list, list) { + u16 devid = get_device_id(dev_data->dev); + set_dte_entry(devid, domain); } } @@ -2259,14 +2243,17 @@ free_domains: static void cleanup_domain(struct protection_domain *domain) { + struct iommu_dev_data *dev_data, *next; unsigned long flags; - u16 devid; write_lock_irqsave(&amd_iommu_devtable_lock, flags); - for (devid = 0; devid <= amd_iommu_last_bdf; ++devid) - if (amd_iommu_pd_table[devid] == domain) - clear_dte_entry(devid); + list_for_each_entry_safe(dev_data, next, &domain->dev_list, list) { + struct device *dev = dev_data->dev; + + do_detach(dev); + atomic_set(&dev_data->bind, 0); + } write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); } diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index fe1686f6f91..7ffc3996523 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c @@ -164,12 +164,6 @@ u16 *amd_iommu_alias_table; */ struct amd_iommu **amd_iommu_rlookup_table; -/* - * The pd table (protection domain table) is used to find the protection domain - * data structure a device belongs to. Indexed with the PCI device id too. - */ -struct protection_domain **amd_iommu_pd_table; - /* * AMD IOMMU allows up to 2^16 differend protection domains. This is a bitmap * to know which ones are already in use. @@ -1238,15 +1232,6 @@ static int __init amd_iommu_init(void) if (amd_iommu_rlookup_table == NULL) goto free; - /* - * Protection Domain table - maps devices to protection domains - * This table has the same size as the rlookup_table - */ - amd_iommu_pd_table = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, - get_order(rlookup_table_size)); - if (amd_iommu_pd_table == NULL) - goto free; - amd_iommu_pd_alloc_bitmap = (void *)__get_free_pages( GFP_KERNEL | __GFP_ZERO, get_order(MAX_DOMAIN_ID/8)); @@ -1314,9 +1299,6 @@ free: free_pages((unsigned long)amd_iommu_pd_alloc_bitmap, get_order(MAX_DOMAIN_ID/8)); - free_pages((unsigned long)amd_iommu_pd_table, - get_order(rlookup_table_size)); - free_pages((unsigned long)amd_iommu_rlookup_table, get_order(rlookup_table_size)); From f5560da549ea2e32dd41e36548c0e7dee3d4aabb Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 13 Dec 2006 19:46:38 +0900 Subject: [PATCH 223/298] pcmcia: Pass struct pcmcia_device to pcmcia_release_window() No logic changes, just pass struct pcmcia_device to pcmcia_release_window(). [linux@dominikbrodowski.net: update to 2.6.31] CC: netdev@vger.kernel.org CC: Jiri Kosina Signed-off-by: Magnus Damm Signed-off-by: Dominik Brodowski --- drivers/char/pcmcia/ipwireless/main.c | 14 +++++++------- drivers/mtd/maps/pcmciamtd.c | 2 +- drivers/net/pcmcia/fmvj18x_cs.c | 4 ++-- drivers/net/pcmcia/ibmtr_cs.c | 2 +- drivers/net/pcmcia/pcnet_cs.c | 4 ++-- drivers/net/wireless/ray_cs.c | 4 ++-- drivers/pcmcia/pcmcia_resource.c | 5 +++-- include/pcmcia/ds.h | 2 +- 8 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c index 24bffa4ece4..91ca23d2b04 100644 --- a/drivers/char/pcmcia/ipwireless/main.c +++ b/drivers/char/pcmcia/ipwireless/main.c @@ -168,15 +168,15 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, return 0; exit3: - pcmcia_release_window(ipw->handle_attr_memory); + pcmcia_release_window(p_dev, ipw->handle_attr_memory); exit2: if (ipw->common_memory) { release_mem_region(ipw->request_common_memory.Base, ipw->request_common_memory.Size); iounmap(ipw->common_memory); - pcmcia_release_window(ipw->handle_common_memory); + pcmcia_release_window(p_dev, ipw->handle_common_memory); } else - pcmcia_release_window(ipw->handle_common_memory); + pcmcia_release_window(p_dev, ipw->handle_common_memory); exit1: release_resource(io_resource); pcmcia_disable_device(p_dev); @@ -260,13 +260,13 @@ exit: release_mem_region(ipw->request_attr_memory.Base, ipw->request_attr_memory.Size); iounmap(ipw->attr_memory); - pcmcia_release_window(ipw->handle_attr_memory); + pcmcia_release_window(link, ipw->handle_attr_memory); } if (ipw->common_memory) { release_mem_region(ipw->request_common_memory.Base, ipw->request_common_memory.Size); iounmap(ipw->common_memory); - pcmcia_release_window(ipw->handle_common_memory); + pcmcia_release_window(link, ipw->handle_common_memory); } pcmcia_disable_device(link); return -1; @@ -287,9 +287,9 @@ static void release_ipwireless(struct ipw_dev *ipw) iounmap(ipw->attr_memory); } if (ipw->common_memory) - pcmcia_release_window(ipw->handle_common_memory); + pcmcia_release_window(ipw->link, ipw->handle_common_memory); if (ipw->attr_memory) - pcmcia_release_window(ipw->handle_attr_memory); + pcmcia_release_window(ipw->link, ipw->handle_attr_memory); /* Break the link with Card Services */ pcmcia_disable_device(ipw->link); diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index b698dbaaf9e..16d9985aadc 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -344,7 +344,7 @@ static void pcmciamtd_release(struct pcmcia_device *link) iounmap(dev->win_base); dev->win_base = NULL; } - pcmcia_release_window(link->win); + pcmcia_release_window(link, link->win); } pcmcia_disable_device(link); } diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index fdec5c333a2..61726c82be4 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -599,7 +599,7 @@ static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id) } iounmap(base); - j = pcmcia_release_window(link->win); + j = pcmcia_release_window(link, link->win); return (i != 0x200) ? 0 : -1; } /* fmvj18x_get_hwinfo */ @@ -666,7 +666,7 @@ static void fmvj18x_release(struct pcmcia_device *link) tmp = lp->base; lp->base = NULL; /* set NULL before iounmap */ iounmap(tmp); - j = pcmcia_release_window(link->win); + j = pcmcia_release_window(link, link->win); } pcmcia_disable_device(link); diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index 0d914f3b294..7a985ca079d 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -328,7 +328,7 @@ static void ibmtr_release(struct pcmcia_device *link) if (link->win) { struct tok_info *ti = netdev_priv(dev); iounmap(ti->mmio); - pcmcia_release_window(info->sram_win_handle); + pcmcia_release_window(link, info->sram_win_handle); } pcmcia_disable_device(link); } diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 80ab9de1c4d..4156a6c5811 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -337,7 +337,7 @@ static hw_info_t *get_hwinfo(struct pcmcia_device *link) } iounmap(virt); - j = pcmcia_release_window(link->win); + j = pcmcia_release_window(link, link->win); return (i < NR_INFO) ? hw_info+i : NULL; } /* get_hwinfo */ @@ -1513,7 +1513,7 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg, pcnet_reset_8390(dev); if (i != (TX_PAGES<<8)) { iounmap(info->base); - pcmcia_release_window(link->win); + pcmcia_release_window(link, link->win); info->base = NULL; link->win = NULL; goto failed; } diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 28db7914a5d..ed328750de4 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -820,10 +820,10 @@ static void ray_release(struct pcmcia_device *link) iounmap(local->rmem); iounmap(local->amem); /* Do bother checking to see if these succeed or not */ - i = pcmcia_release_window(local->amem_handle); + i = pcmcia_release_window(link, local->amem_handle); if (i != 0) dev_dbg(&link->dev, "ReleaseWindow(local->amem) ret = %x\n", i); - i = pcmcia_release_window(local->rmem_handle); + i = pcmcia_release_window(link, local->rmem_handle); if (i != 0) dev_dbg(&link->dev, "ReleaseWindow(local->rmem) ret = %x\n", i); pcmcia_disable_device(link); diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index cda48ea9b6f..820a6e5868e 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -442,9 +442,10 @@ static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req) } /* pcmcia_release_irq */ -int pcmcia_release_window(window_handle_t win) +int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh) { struct pcmcia_socket *s; + window_handle_t win = wh; if ((win == NULL) || (win->magic != WINDOW_MAGIC)) return -EINVAL; @@ -891,7 +892,7 @@ void pcmcia_disable_device(struct pcmcia_device *p_dev) { pcmcia_release_io(p_dev, &p_dev->io); pcmcia_release_irq(p_dev, &p_dev->irq); if (p_dev->win) - pcmcia_release_window(p_dev->win); + pcmcia_release_window(p_dev, p_dev->win); } EXPORT_SYMBOL(pcmcia_disable_device); diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index d82392de4e9..40b098d7aa4 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -201,7 +201,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev, int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_handle_t *wh); -int pcmcia_release_window(window_handle_t win); +int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t win); int pcmcia_get_mem_page(window_handle_t win, memreq_t *req); int pcmcia_map_mem_page(window_handle_t win, memreq_t *req); From 868575d1e87ff2091800aea816972ddb46de60d5 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 13 Dec 2006 19:46:43 +0900 Subject: [PATCH 224/298] pcmcia: Pass struct pcmcia_device to pcmcia_map_mem_page() No logic changes, just pass struct pcmcia_device to pcmcia_map_mem_page() [linux@dominikbrodowski.net: update to 2.6.31] CC: netdev@vger.kernel.org CC: linux-wireless@vger.kernel.org CC: linux-scsi@vger.kernel.org CC: Jiri Kosina Acked-by: Karsten Keil (for ISDN) Signed-off-by: Magnus Damm Signed-off-by: Dominik Brodowski --- drivers/char/pcmcia/ipwireless/main.c | 4 ++-- drivers/isdn/hisax/sedlbauer_cs.c | 2 +- drivers/mtd/maps/pcmciamtd.c | 2 +- drivers/net/pcmcia/fmvj18x_cs.c | 4 ++-- drivers/net/pcmcia/ibmtr_cs.c | 4 ++-- drivers/net/pcmcia/pcnet_cs.c | 4 ++-- drivers/net/pcmcia/smc91c92_cs.c | 2 +- drivers/net/pcmcia/xirc2ps_cs.c | 2 +- drivers/net/wireless/airo_cs.c | 2 +- drivers/net/wireless/b43/pcmcia.c | 2 +- drivers/net/wireless/netwave_cs.c | 2 +- drivers/net/wireless/ray_cs.c | 6 +++--- drivers/net/wireless/wavelan_cs.c | 2 +- drivers/pcmcia/pcmcia_resource.c | 5 ++++- drivers/scsi/pcmcia/nsp_cs.c | 2 +- drivers/staging/comedi/drivers/ni_daq_700.c | 2 +- drivers/staging/comedi/drivers/ni_daq_dio24.c | 2 +- drivers/staging/comedi/drivers/ni_labpc_cs.c | 2 +- include/pcmcia/ds.h | 3 ++- 19 files changed, 29 insertions(+), 25 deletions(-) diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c index 91ca23d2b04..10af1c0dc36 100644 --- a/drivers/char/pcmcia/ipwireless/main.c +++ b/drivers/char/pcmcia/ipwireless/main.c @@ -125,7 +125,7 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, memreq_common_memory.CardOffset = cfg->mem.win[0].card_addr; memreq_common_memory.Page = 0; - ret = pcmcia_map_mem_page(ipw->handle_common_memory, + ret = pcmcia_map_mem_page(p_dev, ipw->handle_common_memory, &memreq_common_memory); if (ret != 0) @@ -154,7 +154,7 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, memreq_attr_memory.CardOffset = 0; memreq_attr_memory.Page = 0; - ret = pcmcia_map_mem_page(ipw->handle_attr_memory, + ret = pcmcia_map_mem_page(p_dev, ipw->handle_attr_memory, &memreq_attr_memory); if (ret != 0) diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index 33d7530527c..598e17a551b 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -276,7 +276,7 @@ static int sedlbauer_config_check(struct pcmcia_device *p_dev, return -ENODEV; map.Page = 0; map.CardOffset = mem->win[0].card_addr; - if (pcmcia_map_mem_page(p_dev->win, &map) != 0) + if (pcmcia_map_mem_page(p_dev, p_dev->win, &map) != 0) return -ENODEV; } return 0; diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index 16d9985aadc..80b9005c373 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -118,7 +118,7 @@ static caddr_t remap_window(struct map_info *map, unsigned long to) DEBUG(2, "Remapping window from 0x%8.8x to 0x%8.8x", dev->offset, mrq.CardOffset); mrq.Page = 0; - ret = pcmcia_map_mem_page(win, &mrq); + ret = pcmcia_map_mem_page(dev->p_dev, win, &mrq); if (ret != 0) return NULL; dev->offset = mrq.CardOffset; diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 61726c82be4..6b9c79e4a2c 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -574,7 +574,7 @@ static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id) base = ioremap(req.Base, req.Size); mem.Page = 0; mem.CardOffset = 0; - pcmcia_map_mem_page(link->win, &mem); + pcmcia_map_mem_page(link, link->win, &mem); /* * MBH10304 CISTPL_FUNCE_LAN_NODE_ID format @@ -630,7 +630,7 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link) mem.Page = 0; mem.CardOffset = 0; - i = pcmcia_map_mem_page(link->win, &mem); + i = pcmcia_map_mem_page(link, link->win, &mem); if (i != 0) { iounmap(lp->base); lp->base = NULL; diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index 7a985ca079d..6fc89eba9c8 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -252,7 +252,7 @@ static int __devinit ibmtr_config(struct pcmcia_device *link) mem.CardOffset = mmiobase; mem.Page = 0; - ret = pcmcia_map_mem_page(link->win, &mem); + ret = pcmcia_map_mem_page(link, link->win, &mem); if (ret) goto failed; ti->mmio = ioremap(req.Base, req.Size); @@ -269,7 +269,7 @@ static int __devinit ibmtr_config(struct pcmcia_device *link) mem.CardOffset = srambase; mem.Page = 0; - ret = pcmcia_map_mem_page(info->sram_win_handle, &mem); + ret = pcmcia_map_mem_page(link, info->sram_win_handle, &mem); if (ret) goto failed; diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 4156a6c5811..75e68946455 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -325,7 +325,7 @@ static hw_info_t *get_hwinfo(struct pcmcia_device *link) mem.Page = 0; for (i = 0; i < NR_INFO; i++) { mem.CardOffset = hw_info[i].offset & ~(req.Size-1); - pcmcia_map_mem_page(link->win, &mem); + pcmcia_map_mem_page(link, link->win, &mem); base = &virt[hw_info[i].offset & (req.Size-1)]; if ((readb(base+0) == hw_info[i].a0) && (readb(base+2) == hw_info[i].a1) && @@ -1499,7 +1499,7 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg, offset = mem.CardOffset % window_size; mem.CardOffset -= offset; mem.Page = 0; - ret = pcmcia_map_mem_page(link->win, &mem); + ret = pcmcia_map_mem_page(link, link->win, &mem); if (ret) goto failed; diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 580ec444a65..4ceaa45d7d8 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -480,7 +480,7 @@ static int mhz_mfc_config(struct pcmcia_device *link) mem.CardOffset = mem.Page = 0; if (smc->manfid == MANFID_MOTOROLA) mem.CardOffset = link->conf.ConfigBase; - i = pcmcia_map_mem_page(link->win, &mem); + i = pcmcia_map_mem_page(link, link->win, &mem); if ((i == 0) && (smc->manfid == MANFID_MEGAHERTZ) diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index fbf92653928..9bc4d6002ae 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -932,7 +932,7 @@ xirc2ps_config(struct pcmcia_device * link) local->dingo_ccr = ioremap(req.Base,0x1000) + 0x0800; mem.CardOffset = 0x0; mem.Page = 0; - if ((err = pcmcia_map_mem_page(link->win, &mem))) + if ((err = pcmcia_map_mem_page(link, link->win, &mem))) goto config_error; /* Setup the CCRs; there are no infos in the CIS about the Ethernet diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index a1b84fc48af..2aa6978d76c 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -261,7 +261,7 @@ static int airo_cs_config_check(struct pcmcia_device *p_dev, return -ENODEV; map.Page = 0; map.CardOffset = mem->win[0].card_addr; - if (pcmcia_map_mem_page(p_dev->win, &map) != 0) + if (pcmcia_map_mem_page(p_dev, p_dev->win, &map) != 0) return -ENODEV; } /* If we got this far, we're cool! */ diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c index cd14b7e8ba8..c0a34bbcb8d 100644 --- a/drivers/net/wireless/b43/pcmcia.c +++ b/drivers/net/wireless/b43/pcmcia.c @@ -93,7 +93,7 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) mem.CardOffset = 0; mem.Page = 0; - res = pcmcia_map_mem_page(dev->win, &mem); + res = pcmcia_map_mem_page(dev, dev->win, &mem); if (res != 0) goto err_disable; diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index cbd85de0c60..4a8c62126c5 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -763,7 +763,7 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { if (ret) goto failed; mem.CardOffset = 0x20000; mem.Page = 0; - ret = pcmcia_map_mem_page(link->win, &mem); + ret = pcmcia_map_mem_page(link, link->win, &mem); if (ret) goto failed; diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index ed328750de4..f719ffcb3c7 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -443,7 +443,7 @@ static int ray_config(struct pcmcia_device *link) goto failed; mem.CardOffset = 0x0000; mem.Page = 0; - ret = pcmcia_map_mem_page(link->win, &mem); + ret = pcmcia_map_mem_page(link, link->win, &mem); if (ret) goto failed; local->sram = ioremap(req.Base, req.Size); @@ -459,7 +459,7 @@ static int ray_config(struct pcmcia_device *link) goto failed; mem.CardOffset = 0x8000; mem.Page = 0; - ret = pcmcia_map_mem_page(local->rmem_handle, &mem); + ret = pcmcia_map_mem_page(link, local->rmem_handle, &mem); if (ret) goto failed; local->rmem = ioremap(req.Base, req.Size); @@ -475,7 +475,7 @@ static int ray_config(struct pcmcia_device *link) goto failed; mem.CardOffset = 0x0000; mem.Page = 0; - ret = pcmcia_map_mem_page(local->amem_handle, &mem); + ret = pcmcia_map_mem_page(link, local->amem_handle, &mem); if (ret) goto failed; local->amem = ioremap(req.Base, req.Size); diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 2fad4ac8982..d4df25d329d 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -3885,7 +3885,7 @@ wv_pcmcia_config(struct pcmcia_device * link) dev->mem_end = dev->mem_start + req.Size; mem.CardOffset = 0; mem.Page = 0; - i = pcmcia_map_mem_page(link->win, &mem); + i = pcmcia_map_mem_page(link, link->win, &mem); if (i != 0) break; diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 820a6e5868e..b60952a3df9 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -234,9 +234,12 @@ int pcmcia_get_mem_page(window_handle_t win, memreq_t *req) EXPORT_SYMBOL(pcmcia_get_mem_page); -int pcmcia_map_mem_page(window_handle_t win, memreq_t *req) +int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh, + memreq_t *req) { struct pcmcia_socket *s; + window_handle_t win = wh; + if ((win == NULL) || (win->magic != WINDOW_MAGIC)) return -EINVAL; s = win->sock; diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index e32c344d7ad..c54108fc89a 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1687,7 +1687,7 @@ static int nsp_cs_config_check(struct pcmcia_device *p_dev, if (pcmcia_request_window(&p_dev, &cfg_mem->req, &p_dev->win) != 0) goto next_entry; map.Page = 0; map.CardOffset = mem->win[0].card_addr; - if (pcmcia_map_mem_page(p_dev->win, &map) != 0) + if (pcmcia_map_mem_page(p_dev, p_dev->win, &map) != 0) goto next_entry; cfg_mem->data->MmioAddress = (unsigned long) ioremap_nocache(cfg_mem->req.Base, cfg_mem->req.Size); diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c index e06d5b2bc33..aeb85b3ec7a 100644 --- a/drivers/staging/comedi/drivers/ni_daq_700.c +++ b/drivers/staging/comedi/drivers/ni_daq_700.c @@ -616,7 +616,7 @@ static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev, return -ENODEV; map.Page = 0; map.CardOffset = mem->win[0].card_addr; - if (pcmcia_map_mem_page(p_dev->win, &map)) + if (pcmcia_map_mem_page(p_dev, p_dev->win, &map)) return -ENODEV; } /* If we got this far, we're cool! */ diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c index 9257a4224ea..0968a67b97c 100644 --- a/drivers/staging/comedi/drivers/ni_daq_dio24.c +++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c @@ -367,7 +367,7 @@ static int dio24_pcmcia_config_loop(struct pcmcia_device *p_dev, return -ENODEV; map.Page = 0; map.CardOffset = mem->win[0].card_addr; - if (pcmcia_map_mem_page(p_dev->win, &map)) + if (pcmcia_map_mem_page(p_dev, p_dev->win, &map)) return -ENODEV; } /* If we got this far, we're cool! */ diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c index 28ff4a68cab..b4c7dfa5463 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_cs.c +++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c @@ -346,7 +346,7 @@ static int labpc_pcmcia_config_loop(struct pcmcia_device *p_dev, return -ENODEV; map.Page = 0; map.CardOffset = mem->win[0].card_addr; - if (pcmcia_map_mem_page(p_dev->win, &map)) + if (pcmcia_map_mem_page(p_dev, p_dev->win, &map)) return -ENODEV; } /* If we got this far, we're cool! */ diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index 40b098d7aa4..f240bfa454f 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -204,7 +204,8 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t win); int pcmcia_get_mem_page(window_handle_t win, memreq_t *req); -int pcmcia_map_mem_page(window_handle_t win, memreq_t *req); +int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t win, + memreq_t *req); int pcmcia_modify_configuration(struct pcmcia_device *p_dev, modconf_t *mod); void pcmcia_disable_device(struct pcmcia_device *p_dev); From 16456ebabfec3f8f509fc18b45f256d066a1b360 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 13 Dec 2006 19:46:48 +0900 Subject: [PATCH 225/298] pcmcia: Pass struct pcmcia_socket to pcmcia_get_mem_page() No logic changes, just pass struct pcmcia_socket to pcmcia_get_mem_page() [linux@dominikbrodowski.net: update to 2.6.31] Signed-off-by: Magnus Damm Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs_internal.h | 2 ++ drivers/pcmcia/pcmcia_ioctl.c | 2 +- drivers/pcmcia/pcmcia_resource.c | 5 ++++- include/pcmcia/ds.h | 2 -- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 0a3ada970bf..8e09a4998c8 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -227,6 +227,8 @@ extern void pcmcia_put_dev(struct pcmcia_device *p_dev); struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int function); +int pcmcia_get_mem_page(struct pcmcia_socket *skt, window_handle_t win, + memreq_t *req); /* pcmcia_ioctl.c */ extern void __init pcmcia_setup_ioctl(void); diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 056fd131c89..c829ead5cdb 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -924,7 +924,7 @@ static int ds_ioctl(struct inode * inode, struct file * file, buf->win_info.handle->index + 1, &buf->win_info.window); break; case DS_GET_MEM_PAGE: - ret = pcmcia_get_mem_page(buf->win_info.handle, + ret = pcmcia_get_mem_page(s, buf->win_info.handle, &buf->win_info.map); break; case DS_REPLACE_CIS: diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index b60952a3df9..a092749f79c 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -223,8 +223,11 @@ EXPORT_SYMBOL(pcmcia_get_window); * * Change the card address of an already open memory window. */ -int pcmcia_get_mem_page(window_handle_t win, memreq_t *req) +int pcmcia_get_mem_page(struct pcmcia_socket *skt, window_handle_t wh, + memreq_t *req) { + window_handle_t win = wh; + if ((win == NULL) || (win->magic != WINDOW_MAGIC)) return -EINVAL; req->Page = 0; diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index f240bfa454f..cbf5f05745f 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -202,8 +202,6 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev, int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_handle_t *wh); int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t win); - -int pcmcia_get_mem_page(window_handle_t win, memreq_t *req); int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t win, memreq_t *req); From 0bdf9b3dd3cfa5cbd5d55172c19f5dd166208e17 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 13 Dec 2006 19:46:53 +0900 Subject: [PATCH 226/298] pcmcia: Change window_handle_t logic to unsigned long Logic changes based on top of the other patches: This set of patches changed window_handle_t from being a pointer to an unsigned long. The unsigned long is now a simple index into socket->win[]. Going from a pointer to unsigned long should leave the user space interface unchanged unless I'm mistaken. This change results in code that is less error prone and a user space interface which is much cleaner and safer. A nice side effect is that we are also are able to remove all members except one from window_t. [ linux@dominikbrodowski.net: Update to 2.6.31. Also, a plain "index" to socket->win[] does not work, as several codepaths rely on "window_handle_t" being non-zero if used. Therefore, set the window_handle_t to the socket->win[] index + 1. ] CC: netdev@vger.kernel.org Signed-off-by: Magnus Damm Signed-off-by: Dominik Brodowski --- drivers/net/pcmcia/pcnet_cs.c | 2 +- drivers/pcmcia/cs_internal.h | 4 +-- drivers/pcmcia/pcmcia_ioctl.c | 4 +-- drivers/pcmcia/pcmcia_resource.c | 59 ++++++++++++++++---------------- include/pcmcia/cs_types.h | 3 +- include/pcmcia/ss.h | 5 --- 6 files changed, 36 insertions(+), 41 deletions(-) diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 75e68946455..518b094c9f6 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1514,7 +1514,7 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg, if (i != (TX_PAGES<<8)) { iounmap(info->base); pcmcia_release_window(link, link->win); - info->base = NULL; link->win = NULL; + info->base = NULL; link->win = 0; goto failed; } diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 8e09a4998c8..6df41de39d1 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -149,8 +149,8 @@ extern struct list_head pcmcia_socket_list; extern struct class pcmcia_socket_class; int pcmcia_get_window(struct pcmcia_socket *s, - window_handle_t *handle, - int idx, + window_handle_t *wh_out, + window_handle_t wh, win_req_t *req); int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c); struct pcmcia_socket *pcmcia_get_socket_by_nr(unsigned int nr); diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index c829ead5cdb..6245fde02b7 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -916,12 +916,12 @@ static int ds_ioctl(struct inode * inode, struct file * file, goto free_out; break; case DS_GET_FIRST_WINDOW: - ret = pcmcia_get_window(s, &buf->win_info.handle, 0, + ret = pcmcia_get_window(s, &buf->win_info.handle, 1, &buf->win_info.window); break; case DS_GET_NEXT_WINDOW: ret = pcmcia_get_window(s, &buf->win_info.handle, - buf->win_info.handle->index + 1, &buf->win_info.window); + buf->win_info.handle + 1, &buf->win_info.window); break; case DS_GET_MEM_PAGE: ret = pcmcia_get_mem_page(s, buf->win_info.handle, diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index a092749f79c..ae6abc7833d 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -187,15 +187,19 @@ EXPORT_SYMBOL(pcmcia_access_configuration_register); /** pcmcia_get_window */ -int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, - int idx, win_req_t *req) +int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *wh_out, + window_handle_t wh, win_req_t *req) { window_t *win; - int w; + window_handle_t w; if (!s || !(s->state & SOCKET_PRESENT)) return -ENODEV; - for (w = idx; w < MAX_WIN; w++) + + wh--; + if (wh >= MAX_WIN) + return -EINVAL; + for (w = wh; w < MAX_WIN; w++) if (s->state & SOCKET_WIN_REQ(w)) break; if (w == MAX_WIN) @@ -213,7 +217,8 @@ int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, req->Attributes |= WIN_DATA_WIDTH_16; if (win->ctl.flags & MAP_USE_WAIT) req->Attributes |= WIN_USE_WAIT; - *handle = win; + + *wh_out = w++; return 0; } /* pcmcia_get_window */ EXPORT_SYMBOL(pcmcia_get_window); @@ -226,12 +231,12 @@ EXPORT_SYMBOL(pcmcia_get_window); int pcmcia_get_mem_page(struct pcmcia_socket *skt, window_handle_t wh, memreq_t *req) { - window_handle_t win = wh; - - if ((win == NULL) || (win->magic != WINDOW_MAGIC)) + wh--; + if (wh >= MAX_WIN) return -EINVAL; + req->Page = 0; - req->CardOffset = win->ctl.card_start; + req->CardOffset = skt->win[wh].ctl.card_start; return 0; } /* pcmcia_get_mem_page */ EXPORT_SYMBOL(pcmcia_get_mem_page); @@ -240,18 +245,17 @@ EXPORT_SYMBOL(pcmcia_get_mem_page); int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh, memreq_t *req) { - struct pcmcia_socket *s; - window_handle_t win = wh; + struct pcmcia_socket *s = p_dev->socket; - if ((win == NULL) || (win->magic != WINDOW_MAGIC)) + wh--; + if (wh >= MAX_WIN) return -EINVAL; - s = win->sock; if (req->Page != 0) { dev_dbg(&s->dev, "failure: requested page is zero\n"); return -EINVAL; } - win->ctl.card_start = req->CardOffset; - if (s->ops->set_mem_map(s, &win->ctl) != 0) { + s->win[wh].ctl.card_start = req->CardOffset; + if (s->ops->set_mem_map(s, &s->win[wh].ctl) != 0) { dev_dbg(&s->dev, "failed to set_mem_map\n"); return -EIO; } @@ -450,13 +454,16 @@ static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req) int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh) { - struct pcmcia_socket *s; - window_handle_t win = wh; + struct pcmcia_socket *s = p_dev->socket; + window_t *win; - if ((win == NULL) || (win->magic != WINDOW_MAGIC)) + wh--; + if (wh >= MAX_WIN) return -EINVAL; - s = win->sock; - if (!(win->handle->_win & CLIENT_WIN_REQ(win->index))) { + + win = &s->win[wh]; + + if (!(p_dev->_win & CLIENT_WIN_REQ(wh))) { dev_dbg(&s->dev, "not releasing unknown window\n"); return -EINVAL; } @@ -464,7 +471,7 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh) /* Shut down memory window */ win->ctl.flags &= ~MAP_ACTIVE; s->ops->set_mem_map(s, &win->ctl); - s->state &= ~SOCKET_WIN_REQ(win->index); + s->state &= ~SOCKET_WIN_REQ(wh); /* Release system memory */ if (win->ctl.res) { @@ -472,9 +479,7 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh) kfree(win->ctl.res); win->ctl.res = NULL; } - win->handle->_win &= ~CLIENT_WIN_REQ(win->index); - - win->magic = 0; + p_dev->_win &= ~CLIENT_WIN_REQ(wh); return 0; } /* pcmcia_release_window */ @@ -847,10 +852,6 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h } win = &s->win[w]; - win->magic = WINDOW_MAGIC; - win->index = w; - win->handle = *p_dev; - win->sock = s; if (!(s->features & SS_CAP_STATIC_MAP)) { win->ctl.res = pcmcia_find_mem_region(req->Base, req->Size, align, @@ -887,7 +888,7 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h } else { req->Base = win->ctl.res->start; } - *wh = win; + *wh = w + 1; return 0; } /* pcmcia_request_window */ diff --git a/include/pcmcia/cs_types.h b/include/pcmcia/cs_types.h index 315965a3793..f5e3b8386c8 100644 --- a/include/pcmcia/cs_types.h +++ b/include/pcmcia/cs_types.h @@ -26,8 +26,7 @@ typedef u_int event_t; typedef u_char cisdata_t; typedef u_short page_t; -struct window_t; -typedef struct window_t *window_handle_t; +typedef unsigned long window_handle_t; struct region_t; typedef struct region_t *memory_handle_t; diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index 753da9b087d..6301c3f4f19 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -107,12 +107,7 @@ typedef struct io_window_t { struct resource *res; } io_window_t; -#define WINDOW_MAGIC 0xB35C typedef struct window_t { - u_short magic; - u_short index; - struct pcmcia_device *handle; - struct pcmcia_socket *sock; pccard_mem_map ctl; } window_t; From d7b0364bfc71c4abc97dfc47f85bb32363266e4e Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 3 Nov 2009 01:05:33 +0100 Subject: [PATCH 227/298] pcmcia: move some window-related code to pcmcia_ioctl.c pcmcia_get_window() and pcmcia_get_mem_page() were only called from pcmcia_ioctl.c. Therefore, move these functions to that file, and remove the useless EXPORTs. Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs_internal.h | 6 ---- drivers/pcmcia/pcmcia_ioctl.c | 55 ++++++++++++++++++++++++++++++ drivers/pcmcia/pcmcia_resource.c | 57 -------------------------------- 3 files changed, 55 insertions(+), 63 deletions(-) diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 6df41de39d1..3bc02d53a3a 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -148,10 +148,6 @@ extern struct rw_semaphore pcmcia_socket_list_rwsem; extern struct list_head pcmcia_socket_list; extern struct class pcmcia_socket_class; -int pcmcia_get_window(struct pcmcia_socket *s, - window_handle_t *wh_out, - window_handle_t wh, - win_req_t *req); int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c); struct pcmcia_socket *pcmcia_get_socket_by_nr(unsigned int nr); @@ -227,8 +223,6 @@ extern void pcmcia_put_dev(struct pcmcia_device *p_dev); struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int function); -int pcmcia_get_mem_page(struct pcmcia_socket *skt, window_handle_t win, - memreq_t *req); /* pcmcia_ioctl.c */ extern void __init pcmcia_setup_ioctl(void); diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 6245fde02b7..38b3a26a3ff 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -218,6 +218,61 @@ static int pcmcia_adjust_resource_info(adjust_t *adj) return (ret); } + +/** pcmcia_get_window + */ +static int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *wh_out, + window_handle_t wh, win_req_t *req) +{ + window_t *win; + window_handle_t w; + + wh--; + if (!s || !(s->state & SOCKET_PRESENT)) + return -ENODEV; + if (wh >= MAX_WIN) + return -EINVAL; + for (w = wh; w < MAX_WIN; w++) + if (s->state & SOCKET_WIN_REQ(w)) + break; + if (w == MAX_WIN) + return -EINVAL; + win = &s->win[w]; + req->Base = win->ctl.res->start; + req->Size = win->ctl.res->end - win->ctl.res->start + 1; + req->AccessSpeed = win->ctl.speed; + req->Attributes = 0; + if (win->ctl.flags & MAP_ATTRIB) + req->Attributes |= WIN_MEMORY_TYPE_AM; + if (win->ctl.flags & MAP_ACTIVE) + req->Attributes |= WIN_ENABLE; + if (win->ctl.flags & MAP_16BIT) + req->Attributes |= WIN_DATA_WIDTH_16; + if (win->ctl.flags & MAP_USE_WAIT) + req->Attributes |= WIN_USE_WAIT; + + *wh_out = w + 1; + return 0; +} /* pcmcia_get_window */ + + +/** pcmcia_get_mem_page + * + * Change the card address of an already open memory window. + */ +static int pcmcia_get_mem_page(struct pcmcia_socket *skt, window_handle_t wh, + memreq_t *req) +{ + wh--; + if (wh >= MAX_WIN) + return -EINVAL; + + req->Page = 0; + req->CardOffset = skt->win[wh].ctl.card_start; + return 0; +} /* pcmcia_get_mem_page */ + + /** pccard_get_status * * Get the current socket state bits. We don't support the latched diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index ae6abc7833d..ae68b26a705 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -185,63 +185,6 @@ int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, EXPORT_SYMBOL(pcmcia_access_configuration_register); -/** pcmcia_get_window - */ -int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *wh_out, - window_handle_t wh, win_req_t *req) -{ - window_t *win; - window_handle_t w; - - if (!s || !(s->state & SOCKET_PRESENT)) - return -ENODEV; - - wh--; - if (wh >= MAX_WIN) - return -EINVAL; - for (w = wh; w < MAX_WIN; w++) - if (s->state & SOCKET_WIN_REQ(w)) - break; - if (w == MAX_WIN) - return -EINVAL; - win = &s->win[w]; - req->Base = win->ctl.res->start; - req->Size = win->ctl.res->end - win->ctl.res->start + 1; - req->AccessSpeed = win->ctl.speed; - req->Attributes = 0; - if (win->ctl.flags & MAP_ATTRIB) - req->Attributes |= WIN_MEMORY_TYPE_AM; - if (win->ctl.flags & MAP_ACTIVE) - req->Attributes |= WIN_ENABLE; - if (win->ctl.flags & MAP_16BIT) - req->Attributes |= WIN_DATA_WIDTH_16; - if (win->ctl.flags & MAP_USE_WAIT) - req->Attributes |= WIN_USE_WAIT; - - *wh_out = w++; - return 0; -} /* pcmcia_get_window */ -EXPORT_SYMBOL(pcmcia_get_window); - - -/** pcmcia_get_mem_page - * - * Change the card address of an already open memory window. - */ -int pcmcia_get_mem_page(struct pcmcia_socket *skt, window_handle_t wh, - memreq_t *req) -{ - wh--; - if (wh >= MAX_WIN) - return -EINVAL; - - req->Page = 0; - req->CardOffset = skt->win[wh].ctl.card_start; - return 0; -} /* pcmcia_get_mem_page */ -EXPORT_SYMBOL(pcmcia_get_mem_page); - - int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh, memreq_t *req) { From 82f88e36004162f49a9340ffbbaebe89016e4835 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 3 Nov 2009 01:16:12 +0100 Subject: [PATCH 228/298] pcmcia: remove unused "window_t" typedef Signed-off-by: Dominik Brodowski --- drivers/pcmcia/pcmcia_ioctl.c | 18 ++++++------- drivers/pcmcia/pcmcia_resource.c | 46 ++++++++++++++++---------------- include/pcmcia/ss.h | 6 +---- 3 files changed, 33 insertions(+), 37 deletions(-) diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 38b3a26a3ff..c4d7908fa37 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -224,7 +224,7 @@ static int pcmcia_adjust_resource_info(adjust_t *adj) static int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *wh_out, window_handle_t wh, win_req_t *req) { - window_t *win; + pccard_mem_map *win; window_handle_t w; wh--; @@ -238,17 +238,17 @@ static int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *wh_out, if (w == MAX_WIN) return -EINVAL; win = &s->win[w]; - req->Base = win->ctl.res->start; - req->Size = win->ctl.res->end - win->ctl.res->start + 1; - req->AccessSpeed = win->ctl.speed; + req->Base = win->res->start; + req->Size = win->res->end - win->res->start + 1; + req->AccessSpeed = win->speed; req->Attributes = 0; - if (win->ctl.flags & MAP_ATTRIB) + if (win->flags & MAP_ATTRIB) req->Attributes |= WIN_MEMORY_TYPE_AM; - if (win->ctl.flags & MAP_ACTIVE) + if (win->flags & MAP_ACTIVE) req->Attributes |= WIN_ENABLE; - if (win->ctl.flags & MAP_16BIT) + if (win->flags & MAP_16BIT) req->Attributes |= WIN_DATA_WIDTH_16; - if (win->ctl.flags & MAP_USE_WAIT) + if (win->flags & MAP_USE_WAIT) req->Attributes |= WIN_USE_WAIT; *wh_out = w + 1; @@ -268,7 +268,7 @@ static int pcmcia_get_mem_page(struct pcmcia_socket *skt, window_handle_t wh, return -EINVAL; req->Page = 0; - req->CardOffset = skt->win[wh].ctl.card_start; + req->CardOffset = skt->win[wh].card_start; return 0; } /* pcmcia_get_mem_page */ diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index ae68b26a705..50468543d60 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -197,8 +197,8 @@ int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh, dev_dbg(&s->dev, "failure: requested page is zero\n"); return -EINVAL; } - s->win[wh].ctl.card_start = req->CardOffset; - if (s->ops->set_mem_map(s, &s->win[wh].ctl) != 0) { + s->win[wh].card_start = req->CardOffset; + if (s->ops->set_mem_map(s, &s->win[wh]) != 0) { dev_dbg(&s->dev, "failed to set_mem_map\n"); return -EIO; } @@ -398,7 +398,7 @@ static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req) int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh) { struct pcmcia_socket *s = p_dev->socket; - window_t *win; + pccard_mem_map *win; wh--; if (wh >= MAX_WIN) @@ -412,15 +412,15 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh) } /* Shut down memory window */ - win->ctl.flags &= ~MAP_ACTIVE; - s->ops->set_mem_map(s, &win->ctl); + win->flags &= ~MAP_ACTIVE; + s->ops->set_mem_map(s, win); s->state &= ~SOCKET_WIN_REQ(wh); /* Release system memory */ - if (win->ctl.res) { - release_resource(win->ctl.res); - kfree(win->ctl.res); - win->ctl.res = NULL; + if (win->res) { + release_resource(win->res); + kfree(win->res); + win->res = NULL; } p_dev->_win &= ~CLIENT_WIN_REQ(wh); @@ -755,7 +755,7 @@ EXPORT_SYMBOL(pcmcia_request_irq); int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_handle_t *wh) { struct pcmcia_socket *s = (*p_dev)->socket; - window_t *win; + pccard_mem_map *win; u_long align; int w; @@ -797,9 +797,9 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h win = &s->win[w]; if (!(s->features & SS_CAP_STATIC_MAP)) { - win->ctl.res = pcmcia_find_mem_region(req->Base, req->Size, align, + win->res = pcmcia_find_mem_region(req->Base, req->Size, align, (req->Attributes & WIN_MAP_BELOW_1MB), s); - if (!win->ctl.res) { + if (!win->res) { dev_dbg(&s->dev, "allocating mem region failed\n"); return -EINVAL; } @@ -807,19 +807,19 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h (*p_dev)->_win |= CLIENT_WIN_REQ(w); /* Configure the socket controller */ - win->ctl.map = w+1; - win->ctl.flags = 0; - win->ctl.speed = req->AccessSpeed; + win->map = w+1; + win->flags = 0; + win->speed = req->AccessSpeed; if (req->Attributes & WIN_MEMORY_TYPE) - win->ctl.flags |= MAP_ATTRIB; + win->flags |= MAP_ATTRIB; if (req->Attributes & WIN_ENABLE) - win->ctl.flags |= MAP_ACTIVE; + win->flags |= MAP_ACTIVE; if (req->Attributes & WIN_DATA_WIDTH_16) - win->ctl.flags |= MAP_16BIT; + win->flags |= MAP_16BIT; if (req->Attributes & WIN_USE_WAIT) - win->ctl.flags |= MAP_USE_WAIT; - win->ctl.card_start = 0; - if (s->ops->set_mem_map(s, &win->ctl) != 0) { + win->flags |= MAP_USE_WAIT; + win->card_start = 0; + if (s->ops->set_mem_map(s, win) != 0) { dev_dbg(&s->dev, "failed to set memory mapping\n"); return -EIO; } @@ -827,9 +827,9 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h /* Return window handle */ if (s->features & SS_CAP_STATIC_MAP) { - req->Base = win->ctl.static_start; + req->Base = win->static_start; } else { - req->Base = win->ctl.res->start; + req->Base = win->res->start; } *wh = w + 1; diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index 6301c3f4f19..d85f725be7e 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -107,10 +107,6 @@ typedef struct io_window_t { struct resource *res; } io_window_t; -typedef struct window_t { - pccard_mem_map ctl; -} window_t; - /* Maximum number of IO windows per socket */ #define MAX_IO_WIN 2 @@ -150,7 +146,7 @@ struct pcmcia_socket { u_int Config; } irq; io_window_t io[MAX_IO_WIN]; - window_t win[MAX_WIN]; + pccard_mem_map win[MAX_WIN]; struct list_head cis_cache; size_t fake_cis_len; u8 *fake_cis; From 6838b03fc6564ea07d0cd87ea6e198d90ab1fc3e Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 3 Nov 2009 01:31:52 +0100 Subject: [PATCH 229/298] pcmcia: pcmcia_request_window() doesn't need a pointer to a pointer pcmcia_request_window() only needs a pointer to struct pcmcia_device, not a pointer to a pointer. CC: netdev@vger.kernel.org CC: linux-wireless@vger.kernel.org CC: linux-scsi@vger.kernel.org CC: Jiri Kosina Acked-by: Karsten Keil (for ISDN) Signed-off-by: Dominik Brodowski --- drivers/char/pcmcia/ipwireless/main.c | 4 ++-- drivers/isdn/hisax/sedlbauer_cs.c | 2 +- drivers/mtd/maps/pcmciamtd.c | 2 +- drivers/net/pcmcia/fmvj18x_cs.c | 4 ++-- drivers/net/pcmcia/ibmtr_cs.c | 4 ++-- drivers/net/pcmcia/pcnet_cs.c | 4 ++-- drivers/net/pcmcia/smc91c92_cs.c | 2 +- drivers/net/pcmcia/xirc2ps_cs.c | 2 +- drivers/net/wireless/airo_cs.c | 2 +- drivers/net/wireless/b43/pcmcia.c | 2 +- drivers/net/wireless/netwave_cs.c | 2 +- drivers/net/wireless/ray_cs.c | 6 +++--- drivers/net/wireless/wavelan_cs.c | 2 +- drivers/pcmcia/pcmcia_resource.c | 6 +++--- drivers/scsi/pcmcia/nsp_cs.c | 2 +- drivers/staging/comedi/drivers/ni_daq_700.c | 2 +- drivers/staging/comedi/drivers/ni_daq_dio24.c | 2 +- drivers/staging/comedi/drivers/ni_labpc_cs.c | 2 +- include/pcmcia/ds.h | 2 +- 19 files changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c index 10af1c0dc36..082146a26c8 100644 --- a/drivers/char/pcmcia/ipwireless/main.c +++ b/drivers/char/pcmcia/ipwireless/main.c @@ -116,7 +116,7 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, ipw->request_common_memory.Size = 0x1000; ipw->request_common_memory.AccessSpeed = 0; - ret = pcmcia_request_window(&p_dev, &ipw->request_common_memory, + ret = pcmcia_request_window(p_dev, &ipw->request_common_memory, &ipw->handle_common_memory); if (ret != 0) @@ -145,7 +145,7 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, ipw->request_attr_memory.Size = 0; /* this used to be 0x1000 */ ipw->request_attr_memory.AccessSpeed = 0; - ret = pcmcia_request_window(&p_dev, &ipw->request_attr_memory, + ret = pcmcia_request_window(p_dev, &ipw->request_attr_memory, &ipw->handle_attr_memory); if (ret != 0) diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index 598e17a551b..331716fc6b3 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -272,7 +272,7 @@ static int sedlbauer_config_check(struct pcmcia_device *p_dev, req->Base = mem->win[0].host_addr; req->Size = mem->win[0].len; req->AccessSpeed = 0; - if (pcmcia_request_window(&p_dev, req, &p_dev->win) != 0) + if (pcmcia_request_window(p_dev, req, &p_dev->win) != 0) return -ENODEV; map.Page = 0; map.CardOffset = mem->win[0].card_addr; diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index 80b9005c373..689d6a79ffc 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -530,7 +530,7 @@ static int pcmciamtd_config(struct pcmcia_device *link) int ret; DEBUG(2, "requesting window with size = %dKiB memspeed = %d", req.Size >> 10, req.AccessSpeed); - ret = pcmcia_request_window(&link, &req, &link->win); + ret = pcmcia_request_window(link, &req, &link->win); DEBUG(2, "ret = %d dev->win_size = %d", ret, dev->win_size); if(ret) { req.Size >>= 1; diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 6b9c79e4a2c..85f7c456270 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -567,7 +567,7 @@ static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id) req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = 0; req.Size = 0; req.AccessSpeed = 0; - i = pcmcia_request_window(&link, &req, &link->win); + i = pcmcia_request_window(link, &req, &link->win); if (i != 0) return -1; @@ -618,7 +618,7 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link) req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = 0; req.Size = 0; req.AccessSpeed = 0; - i = pcmcia_request_window(&link, &req, &link->win); + i = pcmcia_request_window(link, &req, &link->win); if (i != 0) return -1; diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index 6fc89eba9c8..14fe5fa35d8 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -246,7 +246,7 @@ static int __devinit ibmtr_config(struct pcmcia_device *link) req.Base = 0; req.Size = 0x2000; req.AccessSpeed = 250; - ret = pcmcia_request_window(&link, &req, &link->win); + ret = pcmcia_request_window(link, &req, &link->win); if (ret) goto failed; @@ -263,7 +263,7 @@ static int __devinit ibmtr_config(struct pcmcia_device *link) req.Base = 0; req.Size = sramsize * 1024; req.AccessSpeed = 250; - ret = pcmcia_request_window(&link, &req, &info->sram_win_handle); + ret = pcmcia_request_window(link, &req, &info->sram_win_handle); if (ret) goto failed; diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 518b094c9f6..d06a0ce7cb8 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -317,7 +317,7 @@ static hw_info_t *get_hwinfo(struct pcmcia_device *link) req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = 0; req.Size = 0; req.AccessSpeed = 0; - i = pcmcia_request_window(&link, &req, &link->win); + i = pcmcia_request_window(link, &req, &link->win); if (i != 0) return NULL; @@ -1491,7 +1491,7 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg, req.Attributes |= WIN_USE_WAIT; req.Base = 0; req.Size = window_size; req.AccessSpeed = mem_speed; - ret = pcmcia_request_window(&link, &req, &link->win); + ret = pcmcia_request_window(link, &req, &link->win); if (ret) goto failed; diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 4ceaa45d7d8..c6ca3764ab6 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -472,7 +472,7 @@ static int mhz_mfc_config(struct pcmcia_device *link) req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = req.Size = 0; req.AccessSpeed = 0; - i = pcmcia_request_window(&link, &req, &link->win); + i = pcmcia_request_window(link, &req, &link->win); if (i != 0) return -ENODEV; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 9bc4d6002ae..265852ab1a2 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -926,7 +926,7 @@ xirc2ps_config(struct pcmcia_device * link) req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = req.Size = 0; req.AccessSpeed = 0; - if ((err = pcmcia_request_window(&link, &req, &link->win))) + if ((err = pcmcia_request_window(link, &req, &link->win))) goto config_error; local->dingo_ccr = ioremap(req.Base,0x1000) + 0x0800; diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index 2aa6978d76c..34d775c18a3 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -257,7 +257,7 @@ static int airo_cs_config_check(struct pcmcia_device *p_dev, req->Base = mem->win[0].host_addr; req->Size = mem->win[0].len; req->AccessSpeed = 0; - if (pcmcia_request_window(&p_dev, req, &p_dev->win) != 0) + if (pcmcia_request_window(p_dev, req, &p_dev->win) != 0) return -ENODEV; map.Page = 0; map.CardOffset = mem->win[0].card_addr; diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c index c0a34bbcb8d..2588358294b 100644 --- a/drivers/net/wireless/b43/pcmcia.c +++ b/drivers/net/wireless/b43/pcmcia.c @@ -87,7 +87,7 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) win.Base = 0; win.Size = SSB_CORE_SIZE; win.AccessSpeed = 250; - res = pcmcia_request_window(&dev, &win, &dev->win); + res = pcmcia_request_window(dev, &win, &dev->win); if (res != 0) goto err_kfree_ssb; diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index 4a8c62126c5..bd4eff79bd1 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -759,7 +759,7 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_CM|WIN_ENABLE; req.Base = 0; req.Size = 0x8000; req.AccessSpeed = mem_speed; - ret = pcmcia_request_window(&link, &req, &link->win); + ret = pcmcia_request_window(link, &req, &link->win); if (ret) goto failed; mem.CardOffset = 0x20000; mem.Page = 0; diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index f719ffcb3c7..66e2d10cd75 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -438,7 +438,7 @@ static int ray_config(struct pcmcia_device *link) req.Base = 0; req.Size = 0x8000; req.AccessSpeed = ray_mem_speed; - ret = pcmcia_request_window(&link, &req, &link->win); + ret = pcmcia_request_window(link, &req, &link->win); if (ret) goto failed; mem.CardOffset = 0x0000; @@ -454,7 +454,7 @@ static int ray_config(struct pcmcia_device *link) req.Base = 0; req.Size = 0x4000; req.AccessSpeed = ray_mem_speed; - ret = pcmcia_request_window(&link, &req, &local->rmem_handle); + ret = pcmcia_request_window(link, &req, &local->rmem_handle); if (ret) goto failed; mem.CardOffset = 0x8000; @@ -470,7 +470,7 @@ static int ray_config(struct pcmcia_device *link) req.Base = 0; req.Size = 0x1000; req.AccessSpeed = ray_mem_speed; - ret = pcmcia_request_window(&link, &req, &local->amem_handle); + ret = pcmcia_request_window(link, &req, &local->amem_handle); if (ret) goto failed; mem.CardOffset = 0x0000; diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index d4df25d329d..f8c5166fffe 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -3876,7 +3876,7 @@ wv_pcmcia_config(struct pcmcia_device * link) req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = req.Size = 0; req.AccessSpeed = mem_speed; - i = pcmcia_request_window(&link, &req, &link->win); + i = pcmcia_request_window(link, &req, &link->win); if (i != 0) break; diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 50468543d60..1cf7d54fb7e 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -752,9 +752,9 @@ EXPORT_SYMBOL(pcmcia_request_irq); * Request_window() establishes a mapping between card memory space * and system memory space. */ -int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_handle_t *wh) +int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_handle_t *wh) { - struct pcmcia_socket *s = (*p_dev)->socket; + struct pcmcia_socket *s = p_dev->socket; pccard_mem_map *win; u_long align; int w; @@ -804,7 +804,7 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h return -EINVAL; } } - (*p_dev)->_win |= CLIENT_WIN_REQ(w); + p_dev->_win |= CLIENT_WIN_REQ(w); /* Configure the socket controller */ win->map = w+1; diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index c54108fc89a..9dfd6f510b6 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1684,7 +1684,7 @@ static int nsp_cs_config_check(struct pcmcia_device *p_dev, if (cfg_mem->req.Size < 0x1000) cfg_mem->req.Size = 0x1000; cfg_mem->req.AccessSpeed = 0; - if (pcmcia_request_window(&p_dev, &cfg_mem->req, &p_dev->win) != 0) + if (pcmcia_request_window(p_dev, &cfg_mem->req, &p_dev->win) != 0) goto next_entry; map.Page = 0; map.CardOffset = mem->win[0].card_addr; if (pcmcia_map_mem_page(p_dev, p_dev->win, &map) != 0) diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c index aeb85b3ec7a..7328a84ac50 100644 --- a/drivers/staging/comedi/drivers/ni_daq_700.c +++ b/drivers/staging/comedi/drivers/ni_daq_700.c @@ -612,7 +612,7 @@ static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev, if (req->Size < 0x1000) req->Size = 0x1000; req->AccessSpeed = 0; - if (pcmcia_request_window(&p_dev, req, &p_dev->win)) + if (pcmcia_request_window(p_dev, req, &p_dev->win)) return -ENODEV; map.Page = 0; map.CardOffset = mem->win[0].card_addr; diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c index 0968a67b97c..505631553ef 100644 --- a/drivers/staging/comedi/drivers/ni_daq_dio24.c +++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c @@ -363,7 +363,7 @@ static int dio24_pcmcia_config_loop(struct pcmcia_device *p_dev, if (req->Size < 0x1000) req->Size = 0x1000; req->AccessSpeed = 0; - if (pcmcia_request_window(&p_dev, req, &p_dev->win)) + if (pcmcia_request_window(p_dev, req, &p_dev->win)) return -ENODEV; map.Page = 0; map.CardOffset = mem->win[0].card_addr; diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c index b4c7dfa5463..7fb5058ad43 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_cs.c +++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c @@ -342,7 +342,7 @@ static int labpc_pcmcia_config_loop(struct pcmcia_device *p_dev, if (req->Size < 0x1000) req->Size = 0x1000; req->AccessSpeed = 0; - if (pcmcia_request_window(&p_dev, req, &p_dev->win)) + if (pcmcia_request_window(p_dev, req, &p_dev->win)) return -ENODEV; map.Page = 0; map.CardOffset = mem->win[0].card_addr; diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index cbf5f05745f..d6c55fdf8d0 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -199,7 +199,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req); int pcmcia_request_configuration(struct pcmcia_device *p_dev, config_req_t *req); -int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, +int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_handle_t *wh); int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t win); int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t win, From dd2e5a156525f11754d9b1e0583f6bb49c253d62 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 3 Nov 2009 10:27:34 +0100 Subject: [PATCH 230/298] pcmcia: remove deprecated handle_to_dev() macro Update remaining users and remove deprecated handle_to_dev() macro CC: Harald Welte CC: netdev@vger.kernel.org CC: linux-wireless@vger.kernel.org CC: linux-serial@vger.kernel.org Signed-off-by: Dominik Brodowski --- drivers/char/pcmcia/cm4000_cs.c | 2 +- drivers/char/pcmcia/cm4040_cs.c | 6 +++--- drivers/net/pcmcia/3c574_cs.c | 2 +- drivers/net/pcmcia/3c589_cs.c | 2 +- drivers/net/pcmcia/axnet_cs.c | 2 +- drivers/net/pcmcia/com20020_cs.c | 2 +- drivers/net/pcmcia/fmvj18x_cs.c | 2 +- drivers/net/pcmcia/ibmtr_cs.c | 2 +- drivers/net/pcmcia/nmclan_cs.c | 2 +- drivers/net/pcmcia/pcnet_cs.c | 2 +- drivers/net/pcmcia/smc91c92_cs.c | 2 +- drivers/net/pcmcia/xirc2ps_cs.c | 2 +- drivers/net/wireless/airo_cs.c | 2 +- drivers/net/wireless/atmel_cs.c | 4 ++-- drivers/net/wireless/hostap/hostap_cs.c | 2 +- drivers/net/wireless/libertas/if_cs.c | 4 ++-- drivers/net/wireless/netwave_cs.c | 2 +- drivers/net/wireless/orinoco/orinoco_cs.c | 2 +- drivers/net/wireless/orinoco/spectrum_cs.c | 2 +- drivers/net/wireless/ray_cs.c | 2 +- drivers/net/wireless/wavelan_cs.c | 2 +- drivers/net/wireless/wl3501_cs.c | 2 +- drivers/serial/serial_cs.c | 2 +- drivers/usb/host/sl811_cs.c | 2 +- include/pcmcia/ds.h | 3 --- sound/pcmcia/pdaudiocf/pdaudiocf.c | 2 +- sound/pcmcia/vx/vxpocket.c | 2 +- 27 files changed, 30 insertions(+), 33 deletions(-) diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 1611c4fe97f..2db4c0a29b0 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -45,7 +45,7 @@ /* #define ATR_CSUM */ -#define reader_to_dev(x) (&handle_to_dev(x->p_dev)) +#define reader_to_dev(x) (&x->p_dev->dev) /* n (debug level) is ignored */ /* additional debug output may be enabled by re-compiling with diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 38790db561a..a6a70e476be 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -39,7 +39,7 @@ #include "cm4040_cs.h" -#define reader_to_dev(x) (&handle_to_dev(x->p_dev)) +#define reader_to_dev(x) (&x->p_dev->dev) /* n (debug level) is ignored */ /* additional debug output may be enabled by re-compiling with @@ -539,7 +539,7 @@ static int cm4040_config_check(struct pcmcia_device *p_dev, p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK; rc = pcmcia_request_io(p_dev, &p_dev->io); - dev_printk(KERN_INFO, &handle_to_dev(p_dev), + dev_printk(KERN_INFO, &p_dev->dev, "pcmcia_request_io returned 0x%x\n", rc); return rc; } @@ -561,7 +561,7 @@ static int reader_config(struct pcmcia_device *link, int devno) fail_rc = pcmcia_request_configuration(link, &link->conf); if (fail_rc != 0) { - dev_printk(KERN_INFO, &handle_to_dev(link), + dev_printk(KERN_INFO, &link->dev, "pcmcia_request_configuration failed 0x%x\n", fail_rc); goto cs_release; diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index dbef5d9cc9d..8b65e18ab23 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -449,7 +449,7 @@ static int tc574_config(struct pcmcia_device *link) } link->dev_node = &lp->node; - SET_NETDEV_DEV(dev, &handle_to_dev(link)); + SET_NETDEV_DEV(dev, &link->dev); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n"); diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 6eac62b7143..c43c21ddb2d 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -316,7 +316,7 @@ static int tc589_config(struct pcmcia_device *link) printk(KERN_ERR "3c589_cs: invalid if_port requested\n"); link->dev_node = &lp->node; - SET_NETDEV_DEV(dev, &handle_to_dev(link)); + SET_NETDEV_DEV(dev, &link->dev); if (register_netdev(dev) != 0) { printk(KERN_ERR "3c589_cs: register_netdev() failed\n"); diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 5af2ccfdb52..0552dddd587 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -400,7 +400,7 @@ static int axnet_config(struct pcmcia_device *link) info->phy_id = (i < 32) ? i : -1; link->dev_node = &info->node; - SET_NETDEV_DEV(dev, &handle_to_dev(link)); + SET_NETDEV_DEV(dev, &link->dev); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n"); diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index 9a2e5006570..51e9cb0a6d1 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -302,7 +302,7 @@ static int com20020_config(struct pcmcia_device *link) lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */ link->dev_node = &info->node; - SET_NETDEV_DEV(dev, &handle_to_dev(link)); + SET_NETDEV_DEV(dev, &link->dev); i = com20020_found(dev, 0); /* calls register_netdev */ diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 85f7c456270..9b5ca37c668 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -532,7 +532,7 @@ static int fmvj18x_config(struct pcmcia_device *link) lp->cardtype = cardtype; link->dev_node = &lp->node; - SET_NETDEV_DEV(dev, &handle_to_dev(link)); + SET_NETDEV_DEV(dev, &link->dev); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n"); diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index 14fe5fa35d8..76706e12d73 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -287,7 +287,7 @@ static int __devinit ibmtr_config(struct pcmcia_device *link) ibmtr_hw_setup(dev, mmiobase); link->dev_node = &info->node; - SET_NETDEV_DEV(dev, &handle_to_dev(link)); + SET_NETDEV_DEV(dev, &link->dev); i = ibmtr_probe_card(dev); if (i != 0) { diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index a5363483ec6..2d0c6f93ed8 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -701,7 +701,7 @@ static int nmclan_config(struct pcmcia_device *link) printk(KERN_NOTICE "nmclan_cs: invalid if_port requested\n"); link->dev_node = &lp->node; - SET_NETDEV_DEV(dev, &handle_to_dev(link)); + SET_NETDEV_DEV(dev, &link->dev); i = register_netdev(dev); if (i != 0) { diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index d06a0ce7cb8..30baee7b86a 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -646,7 +646,7 @@ static int pcnet_config(struct pcmcia_device *link) mii_phy_probe(dev); link->dev_node = &info->node; - SET_NETDEV_DEV(dev, &handle_to_dev(link)); + SET_NETDEV_DEV(dev, &link->dev); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "pcnet_cs: register_netdev() failed\n"); diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index c6ca3764ab6..2e795de06cb 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -964,7 +964,7 @@ static int smc91c92_config(struct pcmcia_device *link) } link->dev_node = &smc->node; - SET_NETDEV_DEV(dev, &handle_to_dev(link)); + SET_NETDEV_DEV(dev, &link->dev); if (register_netdev(dev) != 0) { printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n"); diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 265852ab1a2..f75ac716390 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -992,7 +992,7 @@ xirc2ps_config(struct pcmcia_device * link) do_reset(dev, 1); /* a kludge to make the cem56 work */ link->dev_node = &local->node; - SET_NETDEV_DEV(dev, &handle_to_dev(link)); + SET_NETDEV_DEV(dev, &link->dev); if ((err=register_netdev(dev))) { printk(KNOT_XIRC "register_netdev() failed\n"); diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index 34d775c18a3..7d3a96fdf5a 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -322,7 +322,7 @@ static int airo_config(struct pcmcia_device *link) goto failed; ((local_info_t *)link->priv)->eth_dev = init_airo_card(link->irq.AssignedIRQ, - link->io.BasePort1, 1, &handle_to_dev(link)); + link->io.BasePort1, 1, &link->dev); if (!((local_info_t *)link->priv)->eth_dev) goto failed; diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 78385722a76..18a58b85922 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -260,7 +260,7 @@ static int atmel_config(struct pcmcia_device *link) struct pcmcia_device_id *did; dev = link->priv; - did = dev_get_drvdata(&handle_to_dev(link)); + did = dev_get_drvdata(&link->dev); dev_dbg(&link->dev, "atmel_config\n"); @@ -309,7 +309,7 @@ static int atmel_config(struct pcmcia_device *link) init_atmel_card(link->irq.AssignedIRQ, link->io.BasePort1, did ? did->driver_info : ATMEL_FW_TYPE_NONE, - &handle_to_dev(link), + &link->dev, card_present, link); if (!((local_info_t*)link->priv)->eth_dev) diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index ca3ab849ac0..243e912729b 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -623,7 +623,7 @@ static int prism2_config(struct pcmcia_device *link) /* Need to allocate net_device before requesting IRQ handler */ dev = prism2_init_local_data(&prism2_pccard_funcs, 0, - &handle_to_dev(link)); + &link->dev); if (dev == NULL) goto failed; link->priv = dev; diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index cb40c386fc7..f2b16559b68 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -590,7 +590,7 @@ static int if_cs_prog_helper(struct if_cs_card *card) /* TODO: make firmware file configurable */ ret = request_firmware(&fw, "libertas_cs_helper.fw", - &handle_to_dev(card->p_dev)); + &card->p_dev->dev); if (ret) { lbs_pr_err("can't load helper firmware\n"); ret = -ENODEV; @@ -663,7 +663,7 @@ static int if_cs_prog_real(struct if_cs_card *card) /* TODO: make firmware file configurable */ ret = request_firmware(&fw, "libertas_cs.fw", - &handle_to_dev(card->p_dev)); + &card->p_dev->dev); if (ret) { lbs_pr_err("can't load firmware\n"); ret = -ENODEV; diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index bd4eff79bd1..f5333b7d222 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -773,7 +773,7 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - SET_NETDEV_DEV(dev, &handle_to_dev(link)); + SET_NETDEV_DEV(dev, &link->dev); if (register_netdev(dev) != 0) { printk(KERN_DEBUG "netwave_cs: register_netdev() failed\n"); diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index da626ec663d..688b3982345 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -109,7 +109,7 @@ orinoco_cs_probe(struct pcmcia_device *link) struct orinoco_private *priv; struct orinoco_pccard *card; - priv = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), + priv = alloc_orinocodev(sizeof(*card), &link->dev, orinoco_cs_hard_reset, NULL); if (!priv) return -ENOMEM; diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index 700010e9e34..c609371d152 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -182,7 +182,7 @@ spectrum_cs_probe(struct pcmcia_device *link) struct orinoco_private *priv; struct orinoco_pccard *card; - priv = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), + priv = alloc_orinocodev(sizeof(*card), &link->dev, spectrum_cs_hard_reset, spectrum_cs_stop_firmware); if (!priv) diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 66e2d10cd75..5e0f4c3eac3 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -488,7 +488,7 @@ static int ray_config(struct pcmcia_device *link) return -ENODEV; } - SET_NETDEV_DEV(dev, &handle_to_dev(link)); + SET_NETDEV_DEV(dev, &link->dev); i = register_netdev(dev); if (i != 0) { printk("ray_config register_netdev() failed\n"); diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index f8c5166fffe..df3579aef50 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -3899,7 +3899,7 @@ wv_pcmcia_config(struct pcmcia_device * link) lp->mem, dev->irq, (u_int) dev->base_addr); #endif - SET_NETDEV_DEV(dev, &handle_to_dev(link)); + SET_NETDEV_DEV(dev, &link->dev); i = register_netdev(dev); if(i != 0) { diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 7e8e269b4cb..9a956c78673 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1975,7 +1975,7 @@ static int wl3501_config(struct pcmcia_device *link) dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - SET_NETDEV_DEV(dev, &handle_to_dev(link)); + SET_NETDEV_DEV(dev, &link->dev); if (register_netdev(dev)) { printk(KERN_NOTICE "wl3501_cs: register_netdev() failed\n"); goto failed; diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 3b31bee8576..8d651a61845 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -387,7 +387,7 @@ static int setup_serial(struct pcmcia_device *handle, struct serial_info * info, port.irq = irq; port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ; port.uartclk = 1843200; - port.dev = &handle_to_dev(handle); + port.dev = &handle->dev; if (buggy_uart) port.flags |= UPF_BUGGY_UART; diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 46077420dea..f87aba6db4e 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c @@ -185,7 +185,7 @@ static int sl811_cs_config_check(struct pcmcia_device *p_dev, static int sl811_cs_config(struct pcmcia_device *link) { - struct device *parent = &handle_to_dev(link); + struct device *parent = &link->dev; local_info_t *dev = link->priv; int ret; diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index d6c55fdf8d0..d403c12f797 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -138,9 +138,6 @@ struct pcmcia_device { #define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev) #define to_pcmcia_drv(n) container_of(n, struct pcmcia_driver, drv) -/* deprecated -- don't use! */ -#define handle_to_dev(handle) (handle->dev) - /* * CIS access. diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 64b859925c0..447aaaee3be 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -131,7 +131,7 @@ static int snd_pdacf_probe(struct pcmcia_device *link) return err; } - snd_card_set_dev(card, &handle_to_dev(link)); + snd_card_set_dev(card, &link->dev); pdacf->index = i; card_list[i] = card; diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 1492744ad67..5a5db48a91a 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -244,7 +244,7 @@ static int vxpocket_config(struct pcmcia_device *link) if (ret) goto failed; - chip->dev = &handle_to_dev(link); + chip->dev = &link->dev; snd_card_set_dev(chip->card, chip->dev); if (snd_vxpocket_assign_resources(chip, link->io.BasePort1, link->irq.AssignedIRQ) < 0) From 5fa9167a1bf5f5a4b7282f5e7ac56a4a5a1fa044 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sun, 8 Nov 2009 17:24:46 +0100 Subject: [PATCH 231/298] pcmcia: rework the irq_req_t typedef Most of the irq_req_t typedef'd struct can be re-worked quite easily: (1) IRQInfo2 was unused in any case, so drop it. (2) IRQInfo1 was used write-only, so drop it. (3) Instance (private data to be passed to the IRQ handler): Most PCMCIA drivers using pcmcia_request_irq() to actually register an IRQ handler set the "dev_id" to the same pointer as the "priv" pointer in struct pcmcia_device. Modify the two exceptions (ipwireless, ibmtr_cs) to also work this waym and set the IRQ handler's "dev_id" to p_dev->priv unconditionally. (4) Handler is to be of type irq_handler_t. (5) Handler != NULL already tells whether an IRQ handler is present. Therefore, we do not need the IRQ_HANDLER_PRESENT flag in irq_req_t.Attributes. CC: netdev@vger.kernel.org CC: linux-bluetooth@vger.kernel.org CC: linux-ide@vger.kernel.org CC: linux-wireless@vger.kernel.org CC: linux-scsi@vger.kernel.org CC: alsa-devel@alsa-project.org CC: Jaroslav Kysela CC: Jiri Kosina CC: Karsten Keil for the Bluetooth parts: Acked-by: Marcel Holtmann Signed-off-by: Dominik Brodowski --- drivers/ata/pata_pcmcia.c | 1 - drivers/bluetooth/bluecard_cs.c | 4 +--- drivers/bluetooth/bt3c_cs.c | 4 +--- drivers/bluetooth/btuart_cs.c | 4 +--- drivers/bluetooth/dtl1_cs.c | 4 +--- drivers/char/pcmcia/ipwireless/hardware.c | 8 ++++---- drivers/char/pcmcia/ipwireless/main.c | 6 +----- drivers/char/pcmcia/synclink_cs.c | 3 --- drivers/ide/ide-cs.c | 1 - drivers/isdn/hardware/avm/avm_cs.c | 2 -- drivers/isdn/hisax/avma1_cs.c | 2 -- drivers/isdn/hisax/elsa_cs.c | 1 - drivers/isdn/hisax/sedlbauer_cs.c | 1 - drivers/isdn/hisax/teles_cs.c | 1 - drivers/net/pcmcia/3c574_cs.c | 4 +--- drivers/net/pcmcia/3c589_cs.c | 4 +--- drivers/net/pcmcia/axnet_cs.c | 1 - drivers/net/pcmcia/com20020_cs.c | 8 +++----- drivers/net/pcmcia/fmvj18x_cs.c | 6 ++---- drivers/net/pcmcia/ibmtr_cs.c | 13 +++++++++---- drivers/net/pcmcia/nmclan_cs.c | 4 +--- drivers/net/pcmcia/pcnet_cs.c | 1 - drivers/net/pcmcia/smc91c92_cs.c | 8 +++----- drivers/net/pcmcia/xirc2ps_cs.c | 3 --- drivers/net/wireless/airo_cs.c | 1 - drivers/net/wireless/atmel_cs.c | 1 - drivers/net/wireless/b43/pcmcia.c | 2 -- drivers/net/wireless/hostap/hostap_cs.c | 5 +---- drivers/net/wireless/libertas/if_cs.c | 1 - drivers/net/wireless/netwave_cs.c | 5 +---- drivers/net/wireless/orinoco/orinoco_cs.c | 4 +--- drivers/net/wireless/orinoco/spectrum_cs.c | 4 +--- drivers/net/wireless/ray_cs.c | 4 +--- drivers/net/wireless/wavelan_cs.c | 5 ++--- drivers/net/wireless/wl3501_cs.c | 5 ++--- drivers/parport/parport_cs.c | 1 - drivers/pcmcia/pcmcia_resource.c | 18 +++++++++--------- drivers/scsi/pcmcia/aha152x_stub.c | 1 - drivers/scsi/pcmcia/fdomain_stub.c | 1 - drivers/scsi/pcmcia/nsp_cs.c | 4 +--- drivers/scsi/pcmcia/qlogic_stub.c | 1 - drivers/scsi/pcmcia/sym53c500_cs.c | 1 - drivers/serial/serial_cs.c | 1 - drivers/staging/comedi/drivers/cb_das16_cs.c | 1 - drivers/staging/comedi/drivers/das08_cs.c | 1 - drivers/staging/comedi/drivers/ni_daq_700.c | 1 - drivers/staging/comedi/drivers/ni_daq_dio24.c | 1 - drivers/staging/comedi/drivers/ni_labpc_cs.c | 1 - drivers/staging/comedi/drivers/ni_mio_cs.c | 4 ---- .../staging/comedi/drivers/quatech_daqp_cs.c | 4 +--- drivers/usb/host/sl811_cs.c | 1 - include/pcmcia/cs.h | 14 ++++++++------ sound/pcmcia/pdaudiocf/pdaudiocf.c | 4 +--- sound/pcmcia/vx/vxpocket.c | 4 +--- 54 files changed, 59 insertions(+), 136 deletions(-) diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 5f94e214e17..1b392c9e853 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -268,7 +268,6 @@ static int pcmcia_init_one(struct pcmcia_device *pdev) pdev->io.Attributes2 = IO_DATA_PATH_WIDTH_8; pdev->io.IOAddrLines = 3; pdev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; - pdev->irq.IRQInfo1 = IRQ_LEVEL_ID; pdev->conf.Attributes = CONF_ENABLE_IRQ; pdev->conf.IntType = INT_MEMORY_AND_IO; diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 1e0c4d82297..2acdc605cb4 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -867,11 +867,9 @@ static int bluecard_probe(struct pcmcia_device *link) link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts1 = 8; - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->irq.Handler = bluecard_interrupt; - link->irq.Instance = info; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 9787fda45d8..d814a2755cc 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -659,11 +659,9 @@ static int bt3c_probe(struct pcmcia_device *link) link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts1 = 8; - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->irq.Handler = bt3c_interrupt; - link->irq.Instance = info; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index f44d75217b2..d339464dc15 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -588,11 +588,9 @@ static int btuart_probe(struct pcmcia_device *link) link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts1 = 8; - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->irq.Handler = btuart_interrupt; - link->irq.Instance = info; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 7cd8614a8ea..4f02a6f3c98 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -573,11 +573,9 @@ static int dtl1_probe(struct pcmcia_device *link) link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts1 = 8; - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->irq.Handler = dtl1_interrupt; - link->irq.Instance = info; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c index 4c1820cad71..99cffdab105 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.c +++ b/drivers/char/pcmcia/ipwireless/hardware.c @@ -1213,12 +1213,12 @@ static irqreturn_t ipwireless_handle_v2_v3_interrupt(int irq, irqreturn_t ipwireless_interrupt(int irq, void *dev_id) { - struct ipw_hardware *hw = dev_id; + struct ipw_dev *ipw = dev_id; - if (hw->hw_version == HW_VERSION_1) - return ipwireless_handle_v1_interrupt(irq, hw); + if (ipw->hardware->hw_version == HW_VERSION_1) + return ipwireless_handle_v1_interrupt(irq, ipw->hardware); else - return ipwireless_handle_v2_v3_interrupt(irq, hw); + return ipwireless_handle_v2_v3_interrupt(irq, ipw->hardware); } static void flush_packets_to_hw(struct ipw_hardware *hw) diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c index 082146a26c8..dff24dae148 100644 --- a/drivers/char/pcmcia/ipwireless/main.c +++ b/drivers/char/pcmcia/ipwireless/main.c @@ -93,8 +93,6 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, p_dev->io.NumPorts1 = cfg->io.win[0].len; p_dev->io.IOAddrLines = 16; - p_dev->irq.IRQInfo1 = cfg->irq.IRQInfo1; - /* 0x40 causes it to generate level mode interrupts. */ /* 0x04 enables IREQ pin. */ p_dev->conf.ConfigIndex = cfg->index | 0x44; @@ -197,9 +195,8 @@ static int config_ipwireless(struct ipw_dev *ipw) link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->irq.Handler = ipwireless_interrupt; - link->irq.Instance = ipw->hardware; INIT_WORK(&ipw->work_reboot, signalled_reboot_work); @@ -315,7 +312,6 @@ static int ipwireless_attach(struct pcmcia_device *link) ipw->link = link; link->priv = ipw; - link->irq.Instance = ipw; /* Link this device into our device list. */ link->dev_node = &ipw->nodes[0]; diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 09b2590adb8..c31a0d913d3 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -554,7 +554,6 @@ static int mgslpc_probe(struct pcmcia_device *link) /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = NULL; link->conf.Attributes = 0; @@ -609,9 +608,7 @@ static int mgslpc_config(struct pcmcia_device *link) link->conf.ConfigIndex = 8; link->conf.Present = PRESENT_OPTION; - link->irq.Attributes |= IRQ_HANDLE_PRESENT; link->irq.Handler = mgslpc_isr; - link->irq.Instance = info; ret = pcmcia_request_irq(link, &link->irq); if (ret) diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c index 6cee6c8d078..dd6396384c2 100644 --- a/drivers/ide/ide-cs.c +++ b/drivers/ide/ide-cs.c @@ -103,7 +103,6 @@ static int ide_probe(struct pcmcia_device *link) link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; link->io.IOAddrLines = 3; link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c index d388eadb9fd..5a6ae646a63 100644 --- a/drivers/isdn/hardware/avm/avm_cs.c +++ b/drivers/isdn/hardware/avm/avm_cs.c @@ -111,8 +111,6 @@ static int avmcs_probe(struct pcmcia_device *p_dev) p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE; p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; - p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; - /* General socket configuration */ p_dev->conf.Attributes = CONF_ENABLE_IRQ; p_dev->conf.IntType = INT_MEMORY_AND_IO; diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c index 6d963f9a09c..f9bdff39cf4 100644 --- a/drivers/isdn/hisax/avma1_cs.c +++ b/drivers/isdn/hisax/avma1_cs.c @@ -123,8 +123,6 @@ static int avma1cs_probe(struct pcmcia_device *p_dev) p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE; p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; - p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; - /* General socket configuration */ p_dev->conf.Attributes = CONF_ENABLE_IRQ; p_dev->conf.IntType = INT_MEMORY_AND_IO; diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c index cdcd2979fcd..a2f709f5397 100644 --- a/drivers/isdn/hisax/elsa_cs.c +++ b/drivers/isdn/hisax/elsa_cs.c @@ -138,7 +138,6 @@ static int elsa_cs_probe(struct pcmcia_device *link) /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; - link->irq.IRQInfo1 = IRQ_LEVEL_ID|IRQ_SHARE_ID; link->irq.Handler = NULL; /* diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index 331716fc6b3..af5d393cc2d 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -145,7 +145,6 @@ static int sedlbauer_probe(struct pcmcia_device *link) /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = NULL; /* diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index 7b11c15b3a9..ea705394ce2 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c @@ -128,7 +128,6 @@ static int teles_probe(struct pcmcia_device *link) /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; - link->irq.IRQInfo1 = IRQ_LEVEL_ID|IRQ_SHARE_ID; link->irq.Handler = NULL; /* diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 8b65e18ab23..17a27225cc9 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -283,10 +283,8 @@ static int tc574_probe(struct pcmcia_device *link) spin_lock_init(&lp->window_lock); link->io.NumPorts1 = 32; link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->irq.Handler = &el3_interrupt; - link->irq.Instance = dev; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index c43c21ddb2d..6f8d7e2e592 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -194,10 +194,8 @@ static int tc589_probe(struct pcmcia_device *link) spin_lock_init(&lp->lock); link->io.NumPorts1 = 16; link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->irq.Handler = &el3_interrupt; - link->irq.Instance = dev; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 0552dddd587..800597b82d1 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -170,7 +170,6 @@ static int axnet_probe(struct pcmcia_device *link) info->p_dev = link; link->priv = dev; link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index 51e9cb0a6d1..21d9c9d815d 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -164,11 +164,10 @@ static int com20020_probe(struct pcmcia_device *p_dev) p_dev->io.NumPorts1 = 16; p_dev->io.IOAddrLines = 16; p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->conf.Attributes = CONF_ENABLE_IRQ; p_dev->conf.IntType = INT_MEMORY_AND_IO; - p_dev->irq.Instance = info->dev = dev; + info->dev = dev; p_dev->priv = info; return com20020_config(p_dev); @@ -275,9 +274,8 @@ static int com20020_config(struct pcmcia_device *link) ioaddr = dev->base_addr = link->io.BasePort1; dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr); - dev_dbg(&link->dev, "request IRQ %d (%Xh/%Xh)\n", - link->irq.AssignedIRQ, - link->irq.IRQInfo1, link->irq.IRQInfo2); + dev_dbg(&link->dev, "request IRQ %d\n", + link->irq.AssignedIRQ); i = pcmcia_request_irq(link, &link->irq); if (i != 0) { diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 9b5ca37c668..6e3e1ced6db 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -255,10 +255,8 @@ static int fmvj18x_probe(struct pcmcia_device *link) link->io.IOAddrLines = 5; /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->irq.Handler = &fjn_interrupt; - link->irq.Instance = dev; /* General socket configuration */ link->conf.Attributes = CONF_ENABLE_IRQ; @@ -428,7 +426,7 @@ static int fmvj18x_config(struct pcmcia_device *link) if (link->io.NumPorts2 != 0) { link->irq.Attributes = - IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT; + IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; ret = mfc_try_io_port(link); if (ret != 0) goto failed; } else if (cardtype == UNGERMANN) { diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index 76706e12d73..37f4a6fdc3e 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -119,6 +119,12 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, }; +static irqreturn_t ibmtr_interrupt(int irq, void *dev_id) { + ibmtr_dev_t *info = dev_id; + struct net_device *dev = info->dev; + return tok_interrupt(irq, dev); +}; + /*====================================================================== ibmtr_attach() creates an "instance" of the driver, allocating @@ -150,14 +156,13 @@ static int __devinit ibmtr_attach(struct pcmcia_device *link) link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts1 = 4; link->io.IOAddrLines = 16; - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; - link->irq.Handler = &tok_interrupt; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.Handler = ibmtr_interrupt; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.Present = PRESENT_OPTION; - link->irq.Instance = info->dev = dev; + info->dev = dev; SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 2d0c6f93ed8..dae5ef6b260 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -463,10 +463,8 @@ static int nmclan_probe(struct pcmcia_device *link) link->io.NumPorts1 = 32; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.IOAddrLines = 5; - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.Handler = &mace_interrupt; - link->irq.Instance = dev; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 30baee7b86a..de2d1008563 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -266,7 +266,6 @@ static int pcnet_probe(struct pcmcia_device *link) link->priv = dev; link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 2e795de06cb..9e0da370912 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -329,10 +329,8 @@ static int smc91c92_probe(struct pcmcia_device *link) link->io.NumPorts1 = 16; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.IOAddrLines = 4; - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->irq.Handler = &smc_interrupt; - link->irq.Instance = dev; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; @@ -456,7 +454,7 @@ static int mhz_mfc_config(struct pcmcia_device *link) link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; link->irq.Attributes = - IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT; + IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; link->io.IOAddrLines = 16; link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts2 = 8; @@ -655,7 +653,7 @@ static int osi_config(struct pcmcia_device *link) link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; link->irq.Attributes = - IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT; + IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; link->io.NumPorts1 = 64; link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts2 = 8; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index f75ac716390..fe504b7f369 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -556,7 +556,6 @@ xirc2ps_probe(struct pcmcia_device *link) link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; link->irq.Handler = xirc2ps_interrupt; - link->irq.Instance = dev; /* Fill in card specific entries */ dev->netdev_ops = &netdev_ops; @@ -835,8 +834,6 @@ xirc2ps_config(struct pcmcia_device * link) link->io.IOAddrLines =10; link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - link->irq.Attributes = IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; if (local->modem) { int pass; diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index 7d3a96fdf5a..f6036fb4231 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -134,7 +134,6 @@ static int airo_probe(struct pcmcia_device *p_dev) /* Interrupt setup */ p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; - p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->irq.Handler = NULL; /* diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 18a58b85922..32407911842 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -143,7 +143,6 @@ static int atmel_probe(struct pcmcia_device *p_dev) /* Interrupt setup */ p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; - p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; p_dev->irq.Handler = NULL; /* diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c index 2588358294b..984174bc7b0 100644 --- a/drivers/net/wireless/b43/pcmcia.c +++ b/drivers/net/wireless/b43/pcmcia.c @@ -98,9 +98,7 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev) goto err_disable; dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; - dev->irq.IRQInfo1 = IRQ_LEVEL_ID; dev->irq.Handler = NULL; /* The handler is registered later. */ - dev->irq.Instance = NULL; res = pcmcia_request_irq(dev, &dev->irq); if (res != 0) goto err_disable; diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 243e912729b..c9640a3e02c 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -641,11 +641,8 @@ static int prism2_config(struct pcmcia_device *link) * irq structure is initialized. */ if (link->conf.Attributes & CONF_ENABLE_IRQ) { - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | - IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->irq.Handler = prism2_interrupt; - link->irq.Instance = dev; ret = pcmcia_request_irq(link, &link->irq); if (ret) goto failed; diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index f2b16559b68..b1d84592b95 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -837,7 +837,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev) p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; p_dev->irq.Handler = NULL; - p_dev->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; p_dev->conf.Attributes = 0; p_dev->conf.IntType = INT_MEMORY_AND_IO; diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index f5333b7d222..e61e6b9440a 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -384,8 +384,7 @@ static int netwave_probe(struct pcmcia_device *link) link->io.IOAddrLines = 5; /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->irq.Handler = &netwave_interrupt; /* General socket configuration */ @@ -404,8 +403,6 @@ static int netwave_probe(struct pcmcia_device *link) dev->watchdog_timeo = TX_TIMEOUT; - link->irq.Instance = dev; - return netwave_pcmcia_config( link); } /* netwave_attach */ diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index 688b3982345..f27bb8367c9 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -120,10 +120,8 @@ orinoco_cs_probe(struct pcmcia_device *link) link->priv = priv; /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->irq.Handler = orinoco_interrupt; - link->irq.Instance = priv; /* General socket configuration defaults can go here. In this * client, we assume very little, and rely on the CIS for diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index c609371d152..59bda240fdc 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -194,10 +194,8 @@ spectrum_cs_probe(struct pcmcia_device *link) link->priv = priv; /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->irq.Handler = orinoco_interrupt; - link->irq.Instance = priv; /* General socket configuration defaults can go here. In this * client, we assume very little, and rely on the CIS for diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 5e0f4c3eac3..91213f9e2c4 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -323,8 +323,7 @@ static int ray_probe(struct pcmcia_device *p_dev) p_dev->io.IOAddrLines = 5; /* Interrupt setup. For PCMCIA, driver takes what's given */ - p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; - p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; + p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; p_dev->irq.Handler = &ray_interrupt; /* General socket configuration */ @@ -333,7 +332,6 @@ static int ray_probe(struct pcmcia_device *p_dev) p_dev->conf.ConfigIndex = 1; p_dev->priv = dev; - p_dev->irq.Instance = dev; local->finder = p_dev; local->card_status = CARD_INSERTED; diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index df3579aef50..33918fd5b23 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -4438,8 +4438,7 @@ wavelan_probe(struct pcmcia_device *p_dev) p_dev->io.IOAddrLines = 3; /* Interrupt setup */ - p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; - p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; + p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; p_dev->irq.Handler = wavelan_interrupt; /* General socket configuration */ @@ -4451,7 +4450,7 @@ wavelan_probe(struct pcmcia_device *p_dev) if (!dev) return -ENOMEM; - p_dev->priv = p_dev->irq.Instance = dev; + p_dev->priv = dev; lp = netdev_priv(dev); diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 9a956c78673..5f0401a52cf 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1898,8 +1898,7 @@ static int wl3501_probe(struct pcmcia_device *p_dev) p_dev->io.IOAddrLines = 5; /* Interrupt setup */ - p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; - p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; + p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; p_dev->irq.Handler = wl3501_interrupt; /* General socket configuration */ @@ -1922,7 +1921,7 @@ static int wl3501_probe(struct pcmcia_device *p_dev) dev->wireless_handlers = &wl3501_handler_def; SET_ETHTOOL_OPS(dev, &ops); netif_stop_queue(dev); - p_dev->priv = p_dev->irq.Instance = dev; + p_dev->priv = dev; return wl3501_config(p_dev); out_link: diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c index e56a4dea671..7dd370fa343 100644 --- a/drivers/parport/parport_cs.c +++ b/drivers/parport/parport_cs.c @@ -106,7 +106,6 @@ static int parport_probe(struct pcmcia_device *link) link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 1cf7d54fb7e..a8bf8c1b45e 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -383,8 +383,8 @@ static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req) s->irq.AssignedIRQ = 0; } - if (req->Attributes & IRQ_HANDLE_PRESENT) { - free_irq(req->AssignedIRQ, req->Instance); + if (req->Handler) { + free_irq(req->AssignedIRQ, p_dev->priv); } #ifdef CONFIG_PCMCIA_PROBE @@ -664,7 +664,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) /* if the underlying IRQ infrastructure allows for it, only allocate * the IRQ, but do not enable it */ - if (!(req->Attributes & IRQ_HANDLE_PRESENT)) + if (!(req->Handler)) type |= IRQ_NOAUTOEN; #endif /* IRQ_NOAUTOEN */ @@ -674,7 +674,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) } else { int try; u32 mask = s->irq_mask; - void *data = &p_dev->dev.driver; /* something unique to this device */ + void *data = p_dev; /* something unique to this device */ for (try = 0; try < 64; try++) { irq = try % 32; @@ -691,12 +691,12 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) * registering a dummy handle works, i.e. if the IRQ isn't * marked as used by the kernel resource management core */ ret = request_irq(irq, - (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Handler : test_action, + (req->Handler) ? req->Handler : test_action, type, p_dev->devname, - (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Instance : data); + (req->Handler) ? p_dev->priv : data); if (!ret) { - if (!(req->Attributes & IRQ_HANDLE_PRESENT)) + if (!req->Handler) free_irq(irq, data); break; } @@ -713,9 +713,9 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) irq = s->pci_irq; } - if (ret && (req->Attributes & IRQ_HANDLE_PRESENT)) { + if (ret && req->Handler) { ret = request_irq(irq, req->Handler, type, - p_dev->devname, req->Instance); + p_dev->devname, p_dev->priv); if (ret) { dev_printk(KERN_INFO, &s->dev, "request_irq() failed\n"); diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index 4329e4e5043..528733b4a39 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c @@ -106,7 +106,6 @@ static int aha152x_probe(struct pcmcia_device *link) link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.IOAddrLines = 10; link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.Present = PRESENT_OPTION; diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c index 5792b55c9d3..91404068407 100644 --- a/drivers/scsi/pcmcia/fdomain_stub.c +++ b/drivers/scsi/pcmcia/fdomain_stub.c @@ -89,7 +89,6 @@ static int fdomain_probe(struct pcmcia_device *link) link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.IOAddrLines = 10; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.Present = PRESENT_OPTION; diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 9dfd6f510b6..c2341af587a 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1564,12 +1564,10 @@ static int nsp_cs_probe(struct pcmcia_device *link) link->io.IOAddrLines = 10; /* not used */ /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; /* Interrupt handler */ link->irq.Handler = &nspintr; - link->irq.Instance = info; link->irq.Attributes |= IRQF_SHARED; /* General socket configuration */ diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c index 65d7ad58433..f85f094870b 100644 --- a/drivers/scsi/pcmcia/qlogic_stub.c +++ b/drivers/scsi/pcmcia/qlogic_stub.c @@ -162,7 +162,6 @@ static int qlogic_probe(struct pcmcia_device *link) link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.IOAddrLines = 10; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.Present = PRESENT_OPTION; diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index 851a41ce4f0..e7564d8f0cb 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -867,7 +867,6 @@ SYM53C500_probe(struct pcmcia_device *link) link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.IOAddrLines = 10; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 8d651a61845..5d6f947ef7f 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -334,7 +334,6 @@ static int serial_probe(struct pcmcia_device *link) link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts1 = 8; link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; if (do_sound) { link->conf.Attributes |= CONF_ENABLE_SPKR; diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index 9e758027efe..39923cb388b 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -703,7 +703,6 @@ static int das16cs_pcmcia_attach(struct pcmcia_device *link) /* Initialize the pcmcia_device structure */ /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = NULL; link->conf.Attributes = 0; diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c index 384a77a37c2..9b945e5fdd3 100644 --- a/drivers/staging/comedi/drivers/das08_cs.c +++ b/drivers/staging/comedi/drivers/das08_cs.c @@ -173,7 +173,6 @@ static int das08_pcmcia_attach(struct pcmcia_device *link) /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = NULL; /* diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c index 7328a84ac50..ef5e1183d47 100644 --- a/drivers/staging/comedi/drivers/ni_daq_700.c +++ b/drivers/staging/comedi/drivers/ni_daq_700.c @@ -503,7 +503,6 @@ static int dio700_cs_attach(struct pcmcia_device *link) /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = NULL; /* diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c index 505631553ef..9017be3a92f 100644 --- a/drivers/staging/comedi/drivers/ni_daq_dio24.c +++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c @@ -254,7 +254,6 @@ static int dio24_cs_attach(struct pcmcia_device *link) /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = NULL; /* diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c index 7fb5058ad43..7d514b3ee75 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_cs.c +++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c @@ -230,7 +230,6 @@ static int labpc_cs_attach(struct pcmcia_device *link) /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_FORCED_PULSE; - link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_PULSE_ID; link->irq.Handler = NULL; /* diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c index ca7ab4abdc2..d692f4bb47e 100644 --- a/drivers/staging/comedi/drivers/ni_mio_cs.c +++ b/drivers/staging/comedi/drivers/ni_mio_cs.c @@ -274,7 +274,6 @@ static int cs_attach(struct pcmcia_device *link) link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; link->io.NumPorts1 = 16; link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; @@ -325,9 +324,6 @@ static int mio_pcmcia_config_loop(struct pcmcia_device *p_dev, p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK; p_dev->io.NumPorts2 = 0; - p_dev->irq.IRQInfo1 = cfg->irq.IRQInfo1; - p_dev->irq.IRQInfo2 = cfg->irq.IRQInfo2; - for (base = 0x000; base < 0x400; base += 0x20) { p_dev->io.BasePort1 = base; ret = pcmcia_request_io(p_dev, &p_dev->io); diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index 48e7c27ed87..5256fd93316 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -1041,10 +1041,8 @@ static int daqp_cs_attach(struct pcmcia_device *link) link->priv = local; /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->irq.Handler = daqp_interrupt; - link->irq.Instance = local; /* General socket configuration defaults can go here. In this diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index f87aba6db4e..39d253e841f 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c @@ -243,7 +243,6 @@ static int sl811_cs_probe(struct pcmcia_device *link) /* Initialize */ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; link->irq.Handler = NULL; link->conf.Attributes = 0; diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h index 904468a191e..afc2bfb9e91 100644 --- a/include/pcmcia/cs.h +++ b/include/pcmcia/cs.h @@ -15,6 +15,10 @@ #ifndef _LINUX_CS_H #define _LINUX_CS_H +#ifdef __KERNEL__ +#include +#endif + /* For AccessConfigurationRegister */ typedef struct conf_reg_t { u_char Function; @@ -111,11 +115,9 @@ typedef struct io_req_t { /* For RequestIRQ and ReleaseIRQ */ typedef struct irq_req_t { - u_int Attributes; - u_int AssignedIRQ; - u_int IRQInfo1, IRQInfo2; /* IRQInfo2 is ignored */ - void *Handler; - void *Instance; + u_int Attributes; + u_int AssignedIRQ; + irq_handler_t Handler; } irq_req_t; /* Attributes for RequestIRQ and ReleaseIRQ */ @@ -125,7 +127,7 @@ typedef struct irq_req_t { #define IRQ_TYPE_DYNAMIC_SHARING 0x02 #define IRQ_FORCED_PULSE 0x04 #define IRQ_FIRST_SHARED 0x08 -#define IRQ_HANDLE_PRESENT 0x10 +//#define IRQ_HANDLE_PRESENT 0x10 #define IRQ_PULSE_ALLOCATED 0x100 /* Bits in IRQInfo1 field */ diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 447aaaee3be..7717e01fc07 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -142,12 +142,10 @@ static int snd_pdacf_probe(struct pcmcia_device *link) link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.NumPorts1 = 16; - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT | IRQ_FORCED_PULSE; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_FORCED_PULSE; // link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; - link->irq.IRQInfo1 = 0 /* | IRQ_LEVEL_ID */; link->irq.Handler = pdacf_interrupt; - link->irq.Instance = pdacf; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 5a5db48a91a..7be3b335704 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -161,11 +161,9 @@ static int snd_vxpocket_new(struct snd_card *card, int ibl, link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.NumPorts1 = 16; - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = &snd_vx_irq_handler; - link->irq.Instance = chip; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; From d0e260782c3702a009645c3caa02e381dab8798b Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 1 Dec 2009 17:30:59 +1100 Subject: [PATCH 232/298] md: revert incorrect fix for read error handling in raid1. commit 4706b349f was a forward port of a fix that was needed for SLES10. But in fact it is not needed in mainline because the earlier commit dd00a99e7a fixes the same problem in a better way. Further, this commit introduces a bug in the way it interacts with the automatic read-error-correction. If, after a read error is successfully corrected, the same disk is chosen to re-read - the re-read won't be attempted but an error will be returned instead. After reverting that commit, there is the possibility that a read error on a read-only array (where read errors cannot be corrected as that requires a write) will repeatedly read the same device and continue to get an error. So in the "Array is readonly" case, fail the drive immediately on a read error. Signed-off-by: NeilBrown Cc: stable@kernel.org --- drivers/md/raid1.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index a053423785c..e07ce2e033a 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1650,11 +1650,12 @@ static void raid1d(mddev_t *mddev) r1_bio->sector, r1_bio->sectors); unfreeze_array(conf); - } + } else + md_error(mddev, + conf->mirrors[r1_bio->read_disk].rdev); bio = r1_bio->bios[r1_bio->read_disk]; - if ((disk=read_balance(conf, r1_bio)) == -1 || - disk == r1_bio->read_disk) { + if ((disk=read_balance(conf, r1_bio)) == -1) { printk(KERN_ALERT "raid1: %s: unrecoverable I/O" " read error for block %llu\n", bdevname(bio->bi_bdev,b), From 7716977b6ae5a0cdd0afab5c6035c4d0ce53f599 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 30 Nov 2009 13:24:18 +0000 Subject: [PATCH 233/298] mfd: Correct WM831X_MAX_ISEL_VALUE There was confusion between the array size and the highest ISEL value possible. Reported-by: Dan Carpenter Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-core.c | 2 +- include/linux/mfd/wm831x/regulator.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 49b7885c270..7f27576ca04 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -29,7 +29,7 @@ /* Current settings - values are 2*2^(reg_val/4) microamps. These are * exported since they are used by multiple drivers. */ -int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL] = { +int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL + 1] = { 2, 2, 3, diff --git a/include/linux/mfd/wm831x/regulator.h b/include/linux/mfd/wm831x/regulator.h index f95466343fb..955d30fc6a2 100644 --- a/include/linux/mfd/wm831x/regulator.h +++ b/include/linux/mfd/wm831x/regulator.h @@ -1212,7 +1212,7 @@ #define WM831X_LDO1_OK_SHIFT 0 /* LDO1_OK */ #define WM831X_LDO1_OK_WIDTH 1 /* LDO1_OK */ -#define WM831X_ISINK_MAX_ISEL 56 -extern int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL]; +#define WM831X_ISINK_MAX_ISEL 55 +extern int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL + 1]; #endif From 4c4cb1b1605e50983afd7924980c9434b214599f Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 1 Dec 2009 13:17:41 -0800 Subject: [PATCH 234/298] drivers/media/dvb/dvb-core/dvb_frontend.c: needs semaphore.h Fixes: v4l/dvb_frontend.c: In function 'dvb_frontend_stop': v4l/dvb_frontend.c:707: error: implicit declaration of function 'init_MUTEX' Addresses http://bugzilla.kernel.org/show_bug.cgi?id=14609 Reported-by: Cc: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-core/dvb_frontend.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index ddf639ed2fd..98082416aa5 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include From fa00e106eb6f082654d822a0946c0c86297ede2c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 1 Dec 2009 13:17:41 -0800 Subject: [PATCH 235/298] drivers/rtc/rtc-pcf50633.c: fix use after free in pcf50633_rtc_probe() "rtc" is freed and then dereferenced on the next line. This patch fixes that. Signed-off-by: Dan Carpenter Acked-by: Alessandro Zummo Cc: David Brownell Cc: Paul Gortmaker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-pcf50633.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c index 33a10c47260..4c5d5d0c4cf 100644 --- a/drivers/rtc/rtc-pcf50633.c +++ b/drivers/rtc/rtc-pcf50633.c @@ -292,8 +292,9 @@ static int __devinit pcf50633_rtc_probe(struct platform_device *pdev) &pcf50633_rtc_ops, THIS_MODULE); if (IS_ERR(rtc->rtc_dev)) { + int ret = PTR_ERR(rtc->rtc_dev); kfree(rtc); - return PTR_ERR(rtc->rtc_dev); + return ret; } pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_ALARM, From 3510b8f7f53bf0ded13888724734bba87d22ecc3 Mon Sep 17 00:00:00 2001 From: Sudhakar Rajashekhara Date: Tue, 1 Dec 2009 13:17:43 -0800 Subject: [PATCH 236/298] davinci: fb: fix frame buffer driver issues Following issues have been addressed on DA8XX/OMAP-L1XX: a. Screen misalignment during booting when frame buffer console is enabled. b. Driver was configured always in PSEUDOCOLOR mode. This patch dynamically configures the driver either in PSEUDOCOLOUR or TRUECOLOR mode depending on bpp. c. The RED and BLUE offsets were interchanged resulting in wrong bootup logo colour. This patch has been tested on DA830/OMAP-L137 and DA850/OMAP-L138 EVMs. Signed-off-by: Sudhakar Rajashekhara Cc: Steve Chen Cc: Pavel Kiryukhin Cc: Krzysztof Helt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/da8xx-fb.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 035d56835b7..ea1fd3f4751 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -554,11 +554,11 @@ static int fb_check_var(struct fb_var_screeninfo *var, var->transp.length = 0; break; case 16: /* RGB 565 */ - var->red.offset = 0; + var->red.offset = 11; var->red.length = 5; var->green.offset = 5; var->green.length = 6; - var->blue.offset = 11; + var->blue.offset = 0; var->blue.length = 5; var->transp.offset = 0; var->transp.length = 0; @@ -591,7 +591,7 @@ static int __devexit fb_remove(struct platform_device *dev) unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE, - info->screen_base, + info->screen_base - PAGE_SIZE, info->fix.smem_start); free_irq(par->irq, par); clk_disable(par->lcdc_clk); @@ -749,6 +749,7 @@ static int __init fb_probe(struct platform_device *device) (PAGE_SIZE - par->palette_sz); /* the rest of the frame buffer is pixel data */ + da8xx_fb_info->screen_base = par->v_palette_base + par->palette_sz; da8xx_fb_fix.smem_start = par->p_palette_base + par->palette_sz; da8xx_fb_fix.smem_len = par->databuf_sz - par->palette_sz; da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8; @@ -787,6 +788,8 @@ static int __init fb_probe(struct platform_device *device) da8xx_fb_info->var = da8xx_fb_var; da8xx_fb_info->fbops = &da8xx_fb_ops; da8xx_fb_info->pseudo_palette = par->pseudo_palette; + da8xx_fb_info->fix.visual = (da8xx_fb_info->var.bits_per_pixel <= 8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0); if (ret) @@ -825,7 +828,7 @@ err_free_irq: err_release_fb_mem: dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE, - da8xx_fb_info->screen_base, + da8xx_fb_info->screen_base - PAGE_SIZE, da8xx_fb_info->fix.smem_start); err_release_fb: From 974348435c6d7b65fd6d8857b4809b0ff208d323 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Tue, 1 Dec 2009 13:17:44 -0800 Subject: [PATCH 237/298] kbuild: stepping down as maintainer It has been fun but the last year or more it has been a duty and a burden. So I leave it open for others to take over. Signed-off-by: Sam Ravnborg Cc: Anibal Monsalve Salazar Cc: Steven Rostedt Cc: Michal Marek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 16129e67678..4f96ac81089 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3015,11 +3015,8 @@ S: Maintained F: fs/autofs4/ KERNEL BUILD -M: Sam Ravnborg -T: git git://git.kernel.org/pub/scm/linux/kernel/git/sam/kbuild-next.git -T: git git://git.kernel.org/pub/scm/linux/kernel/git/sam/kbuild-fixes.git L: linux-kbuild@vger.kernel.org -S: Maintained +S: Orphan F: Documentation/kbuild/ F: Makefile F: scripts/Makefile.* From ca0297015d4f117005718e01aa368875abcccbc5 Mon Sep 17 00:00:00 2001 From: Alek Du Date: Tue, 1 Dec 2009 13:17:45 -0800 Subject: [PATCH 238/298] gpio: Langwell GPIO driver bugfixes - Remove wrong and unnecessary unmask operation - Remove extra GEDR reading This fixes the loss of interrupts which occurs when two or more pins are triggered in close succession. Signed-off-by: Alek Du Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/langwell_gpio.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/gpio/langwell_gpio.c b/drivers/gpio/langwell_gpio.c index 5711ce5353c..4baf3d7d0f8 100644 --- a/drivers/gpio/langwell_gpio.c +++ b/drivers/gpio/langwell_gpio.c @@ -144,13 +144,6 @@ static int lnw_irq_type(unsigned irq, unsigned type) static void lnw_irq_unmask(unsigned irq) { - struct lnw_gpio *lnw = get_irq_chip_data(irq); - u32 gpio = irq - lnw->irq_base; - u8 reg = gpio / 32; - void __iomem *gedr; - - gedr = (void __iomem *)(&lnw->reg_base->GEDR[reg]); - writel(BIT(gpio % 32), gedr); }; static void lnw_irq_mask(unsigned irq) @@ -183,13 +176,11 @@ static void lnw_irq_handler(unsigned irq, struct irq_desc *desc) gedr_v = readl(gedr); if (!gedr_v) continue; - for (gpio = reg*32; gpio < reg*32+32; gpio++) { - gedr_v = readl(gedr); + for (gpio = reg*32; gpio < reg*32+32; gpio++) if (gedr_v & BIT(gpio % 32)) { pr_debug("pin %d triggered\n", gpio); generic_handle_irq(lnw->irq_base + gpio); } - } /* clear the edge detect status bit */ writel(gedr_v, gedr); } From 0a1f127a0594d62cb23c26732686d0e2b097b264 Mon Sep 17 00:00:00 2001 From: Peter Horton Date: Tue, 1 Dec 2009 13:17:46 -0800 Subject: [PATCH 239/298] aoe: prevent cache aliases Prevent the AoE block driver from creating cache aliases of page cache pages on machines with virtually indexed caches. Building kernels on an AT91SAM9G20 board without this patch fails with segmentation faults after a couple of passes. Signed-off-by: Peter Horton Cc: "Ed L. Cashin" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/aoe/aoecmd.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 965ece2c7e4..13bb69d2abb 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -735,6 +735,21 @@ diskstats(struct gendisk *disk, struct bio *bio, ulong duration, sector_t sector part_stat_unlock(); } +/* + * Ensure we don't create aliases in VI caches + */ +static inline void +killalias(struct bio *bio) +{ + struct bio_vec *bv; + int i; + + if (bio_data_dir(bio) == READ) + __bio_for_each_segment(bv, bio, i, 0) { + flush_dcache_page(bv->bv_page); + } +} + void aoecmd_ata_rsp(struct sk_buff *skb) { @@ -853,8 +868,12 @@ aoecmd_ata_rsp(struct sk_buff *skb) if (buf && --buf->nframesout == 0 && buf->resid == 0) { diskstats(d->gd, buf->bio, jiffies - buf->stime, buf->sector); - n = (buf->flags & BUFFL_FAIL) ? -EIO : 0; - bio_endio(buf->bio, n); + if (buf->flags & BUFFL_FAIL) + bio_endio(buf->bio, -EIO); + else { + killalias(buf->bio); + bio_endio(buf->bio, 0); + } mempool_free(buf, d->bufpool); } From 48a7f7746875425797aea31ed2910088635c1c7a Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Tue, 1 Dec 2009 13:17:48 -0800 Subject: [PATCH 240/298] rtc-x1205: fix rtc_time to y2k register value conversion The possible CCR_Y2K register values are 19 or 20 and struct rtc_time's tm_year is in years since 1900. The function translating rtc_time to register values assumes tm_year to be years since first christmas, though, and we end up storing 0 or 1 in the CCR_Y2K register, which the hardware does not refuse to do. A subsequent probing of the clock fails due to the invalid value range in the register, though. [ And if it didn't, reading the clock would yield a bogus year because the function translating registers to tm_year is assuming a register value of 19 or 20. ] This fixes the conversion from years since 1900 in tm_year to the corresponding CCR_Y2K value of 19 or 20. Signed-off-by: Johannes Weiner Cc: Alessandro Zummo Cc: Paul Gortmaker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-x1205.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index 310c10795e9..cc9ba47b215 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -195,7 +195,7 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, /* year, since the rtc epoch*/ buf[CCR_YEAR] = bin2bcd(tm->tm_year % 100); buf[CCR_WDAY] = tm->tm_wday & 0x07; - buf[CCR_Y2K] = bin2bcd(tm->tm_year / 100); + buf[CCR_Y2K] = bin2bcd((tm->tm_year + 1900) / 100); } /* If writing alarm registers, set compare bits on registers 0-4 */ From cb8799eeddd542abd504c62c11014dfbaec7f3a1 Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Tue, 1 Dec 2009 13:17:49 -0800 Subject: [PATCH 241/298] rtc-x1205: reset clock to sane state after power failure When detecting power failure, the probe function would reset the clock time to defined state. However, the clock's _date_ might still be bogus and a subsequent probe fails when sanity-checking these values. Change the power-failure fixup code to do a full setting of rtc_time, including a valid date. Signed-off-by: Johannes Weiner Cc: Alessandro Zummo Cc: Paul Gortmaker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-x1205.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index cc9ba47b215..6583c1a8b07 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -280,9 +280,9 @@ static int x1205_fix_osc(struct i2c_client *client) int err; struct rtc_time tm; - tm.tm_hour = tm.tm_min = tm.tm_sec = 0; + memset(&tm, 0, sizeof(tm)); - err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE, 0); + err = x1205_set_datetime(client, &tm, 1, X1205_CCR_BASE, 0); if (err < 0) dev_err(&client->dev, "unable to restart the oscillator\n"); From e9438e3193a0d1430b70fafe46855c1a56202f7c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 1 Dec 2009 13:17:50 -0800 Subject: [PATCH 242/298] sysfs: fix SYSFS_DEPRECATED_V2 prompt The SYSFS_DEPRECATED_V2 says "remove" older, deprecated features, but it actually enables them, so correct this confusing, backwards text. Signed-off-by: Randy Dunlap Cc: Kay Sievers Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- init/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/init/Kconfig b/init/Kconfig index 39923ccc287..eb4b33725db 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -606,7 +606,7 @@ config SYSFS_DEPRECATED bool config SYSFS_DEPRECATED_V2 - bool "remove sysfs features which may confuse old userspace tools" + bool "enable deprecated sysfs features which may confuse old userspace tools" depends on SYSFS default n select SYSFS_DEPRECATED From fa1452e808732ae10e8b1267fd75fc2d028d634b Mon Sep 17 00:00:00 2001 From: Hiroshi Shimamoto Date: Mon, 30 Nov 2009 14:59:44 +0900 Subject: [PATCH 243/298] locking, task_struct: Reduce size on TRACE_IRQFLAGS and 64bit Reorder task_struct field for TRACE_IRQFLAGS to remove padding on 64-bit. Signed-off-by: Hiroshi Shimamoto Cc: Peter Zijlstra LKML-Reference: <4B135F50.8070302@ct.jp.nec.com> Signed-off-by: Ingo Molnar --- include/linux/sched.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 75e6e60bf58..49be8f7c05f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1421,17 +1421,17 @@ struct task_struct { #endif #ifdef CONFIG_TRACE_IRQFLAGS unsigned int irq_events; - int hardirqs_enabled; unsigned long hardirq_enable_ip; - unsigned int hardirq_enable_event; unsigned long hardirq_disable_ip; + unsigned int hardirq_enable_event; unsigned int hardirq_disable_event; - int softirqs_enabled; - unsigned long softirq_disable_ip; - unsigned int softirq_disable_event; - unsigned long softirq_enable_ip; - unsigned int softirq_enable_event; + int hardirqs_enabled; int hardirq_context; + unsigned long softirq_disable_ip; + unsigned long softirq_enable_ip; + unsigned int softirq_disable_event; + unsigned int softirq_enable_event; + int softirqs_enabled; int softirq_context; #endif #ifdef CONFIG_LOCKDEP From be088b139f5244b23ee931afb195eee236b7ff33 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 24 Nov 2009 21:06:26 -0500 Subject: [PATCH 244/298] [WATCHDOG] rc32434_wdt.c: use resource_size() The size value passed to ioremap_nocache() is not correct. Use resource_size() to get the correct value. Signed-off-by: H Hartley Sweeten Cc: Phil Sutter Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/rc32434_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/rc32434_wdt.c b/drivers/watchdog/rc32434_wdt.c index f6cccc9df02..3764af11065 100644 --- a/drivers/watchdog/rc32434_wdt.c +++ b/drivers/watchdog/rc32434_wdt.c @@ -276,7 +276,7 @@ static int __devinit rc32434_wdt_probe(struct platform_device *pdev) return -ENODEV; } - wdt_reg = ioremap_nocache(r->start, r->end - r->start); + wdt_reg = ioremap_nocache(r->start, resource_size(r)); if (!wdt_reg) { printk(KERN_ERR PFX "failed to remap I/O resources\n"); return -ENXIO; From 810a90ae4d2a9f6d9ff80424accbd6f91947e981 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 2 Dec 2009 13:21:23 +0100 Subject: [PATCH 245/298] [PATCH] rc32434_wdt: fix compilation failure This patch fixes the compilation failure of rc32434 due to a bad module parameter description. Signed-off-by: Florian Fainelli Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/rc32434_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/rc32434_wdt.c b/drivers/watchdog/rc32434_wdt.c index 3764af11065..bf12d06b587 100644 --- a/drivers/watchdog/rc32434_wdt.c +++ b/drivers/watchdog/rc32434_wdt.c @@ -62,7 +62,7 @@ extern unsigned int idt_cpu_freq; static int timeout = WATCHDOG_TIMEOUT; module_param(timeout, int, 0); MODULE_PARM_DESC(timeout, "Watchdog timeout value, in seconds (default=" - WATCHDOG_TIMEOUT ")"); + __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); static int nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, int, 0); From 5d6b1edf8ccc4b7e4e77dff3fc80882833d6186e Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 1 Dec 2009 18:17:18 +0100 Subject: [PATCH 246/298] [ARM] pxamci: call mmc_remove_host() before freeing resources mmc_remove_host() will cause the mmc core to switch off the bus power by eventually calling pxamci_set_ios(). This function uses the regulator or the GPIO which have been freed already. This causes the following Oops on module unload. [ 49.519649] Unable to handle kernel paging request at virtual address 30303a70 [ 49.526878] pgd = c7084000 [ 49.529563] [30303a70] *pgd=00000000 [ 49.533136] Internal error: Oops: 5 [#1] [ 49.537025] last sysfs file: /sys/devices/platform/pxa27x-ohci/usb1/1-1/1-1:1.0/host0/target0:0:0/0:0:0:0/scsi_level [ 49.547471] Modules linked in: pxamci(-) eeti_ts [ 49.552061] CPU: 0 Not tainted (2.6.32-rc8 #322) [ 49.557001] PC is at regulator_is_enabled+0x3c/0xbc [ 49.561846] LR is at regulator_is_enabled+0x30/0xbc [ 49.566691] pc : [] lr : [] psr: 60000013 [ 49.566702] sp : c7083e70 ip : 30303a30 fp : 00000000 [ 49.578093] r10: c705e200 r9 : c7082000 r8 : c705e2e0 [ 49.583280] r7 : c7061340 r6 : c7061340 r5 : c7083e70 r4 : 00000000 [ 49.589759] r3 : c04dc434 r2 : c04dc434 r1 : c03eecea r0 : 00000047 [ 49.596241] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user [ 49.603329] Control: 0000397f Table: a7084018 DAC: 00000015 [ 49.609031] Process rmmod (pid: 1101, stack limit = 0xc7082278) [ 49.614908] Stack: (0xc7083e70 to 0xc7084000) [ 49.619238] 3e60: c7082000 c703c4f8 c705ea00 c04f4074 [ 49.627366] 3e80: 00000000 c705e3a0 ffffffff c0247ddc c70361a0 00000000 c705e3a0 ffffffff [ 49.635499] 3ea0: c705e200 bf006400 c78c4f00 c705e200 c705e3a0 ffffffff c705e200 ffffffff [ 49.643633] 3ec0: c04d8ac8 c02476d0 ffffffff c0247c60 c705e200 c0248678 c705e200 c0249064 [ 49.651765] 3ee0: ffffffff bf006204 c04d8ad0 c04d8ad0 c04d8ac8 bf007490 00000880 c00440c4 [ 49.659898] 3f00: 0000b748 c01c5708 bf007490 c01c44c8 c04d8ac8 c04d8afc bf007490 c01c4570 [ 49.668031] 3f20: bf007490 bf00750c c04f4258 c01c37a4 00000000 bf00750c c7083f44 c007b014 [ 49.676162] 3f40: 4000d000 6d617870 08006963 00000001 00000000 c7085000 00000001 00000000 [ 49.684287] 3f60: 4000d000 c7083f8c 00000001 bea01a54 00005401 c7ab1400 c00440c4 00082000 [ 49.692420] 3f80: bf00750c 00000880 c7083f8c 00000000 4000cfa8 00000000 00000880 bea01cc8 [ 49.700552] 3fa0: 00000081 c0043f40 00000000 00000880 bea01cc8 00000880 00000006 00000000 [ 49.708677] 3fc0: 00000000 00000880 bea01cc8 00000081 00000097 0000cca4 0000b748 00000000 [ 49.716802] 3fe0: 4001a4f0 bea01cc0 00018bf4 4001a4fc 20000010 bea01cc8 a063e021 a063e421 [ 49.724958] [] (regulator_is_enabled+0x3c/0xbc) from [] (mmc_regulator_set_ocr+0x14/0xd8) [ 49.734836] [] (mmc_regulator_set_ocr+0x14/0xd8) from [] (pxamci_set_ios+0xd8/0x17c [pxamci]) [ 49.745044] [] (pxamci_set_ios+0xd8/0x17c [pxamci]) from [] (mmc_power_off+0x50/0x58) [ 49.754555] [] (mmc_power_off+0x50/0x58) from [] (mmc_detach_bus+0x68/0xc4) [ 49.763207] [] (mmc_detach_bus+0x68/0xc4) from [] (mmc_stop_host+0xd4/0x1bc) [ 49.771944] [] (mmc_stop_host+0xd4/0x1bc) from [] (mmc_remove_host+0xc/0x20) [ 49.780681] [] (mmc_remove_host+0xc/0x20) from [] (pxamci_remove+0xc8/0x174 [pxamci]) [ 49.790211] [] (pxamci_remove+0xc8/0x174 [pxamci]) from [] (platform_drv_remove+0x1c/0x24) [ 49.800164] [] (platform_drv_remove+0x1c/0x24) from [] (__device_release_driver+0x7c/0xc4) [ 49.810110] [] (__device_release_driver+0x7c/0xc4) from [] (driver_detach+0x60/0x8c) [ 49.819535] [] (driver_detach+0x60/0x8c) from [] (bus_remove_driver+0x90/0xcc) [ 49.828452] [] (bus_remove_driver+0x90/0xcc) from [] (sys_delete_module+0x1d8/0x254) [ 49.837891] [] (sys_delete_module+0x1d8/0x254) from [] (ret_fast_syscall+0x0/0x28) [ 49.847145] Code: eb06c53a e596c030 e1a0500d e59f106c (e59c0040) [ 49.853566] ---[ end trace b5fa66a00cea142f ]--- Signed-off-by: Daniel Mack Reported-by: Sven Neumann Cc: Pierre Ossman Cc: linux-mmc@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: stable@kernel.org Signed-off-by: Eric Miao --- drivers/mmc/host/pxamci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index b00d6731905..9fb480bb0e0 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -760,6 +760,8 @@ static int pxamci_remove(struct platform_device *pdev) if (mmc) { struct pxamci_host *host = mmc_priv(mmc); + mmc_remove_host(mmc); + if (host->pdata) { gpio_cd = host->pdata->gpio_card_detect; gpio_ro = host->pdata->gpio_card_ro; @@ -779,8 +781,6 @@ static int pxamci_remove(struct platform_device *pdev) if (host->pdata && host->pdata->exit) host->pdata->exit(&pdev->dev, mmc); - mmc_remove_host(mmc); - pxamci_stop_clock(host); writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD| END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, From a91be9ee69b09cdaa02afd5d7056bc2e6d382cfe Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 2 Dec 2009 11:33:03 +0000 Subject: [PATCH 247/298] MIPS: Fix MIPS I build. Broken by d63c63e889bbeeaa461a8addf1245f89f3ce4ece (lmo) rsp. f1e39a4a616cd9981a9decfd5332fd07a01abb8b (kernel.org). Signed-off-by: Ralf Baechle Patchwork: http://patchwork.linux-mips.org/patch/746/ --- arch/mips/kernel/syscall.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 3fe1fcfa2e7..fe0d7980560 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -306,6 +306,7 @@ static inline int mips_atomic_set(struct pt_regs *regs, if (cpu_has_llsc && R10000_LLSC_WAR) { __asm__ __volatile__ ( + " .set mips3 \n" " li %[err], 0 \n" "1: ll %[old], (%[addr]) \n" " move %[tmp], %[new] \n" @@ -320,6 +321,7 @@ static inline int mips_atomic_set(struct pt_regs *regs, " "STR(PTR)" 1b, 4b \n" " "STR(PTR)" 2b, 4b \n" " .previous \n" + " .set mips0 \n" : [old] "=&r" (old), [err] "=&r" (err), [tmp] "=&r" (tmp) @@ -329,6 +331,7 @@ static inline int mips_atomic_set(struct pt_regs *regs, : "memory"); } else if (cpu_has_llsc) { __asm__ __volatile__ ( + " .set mips3 \n" " li %[err], 0 \n" "1: ll %[old], (%[addr]) \n" " move %[tmp], %[new] \n" @@ -347,6 +350,7 @@ static inline int mips_atomic_set(struct pt_regs *regs, " "STR(PTR)" 1b, 5b \n" " "STR(PTR)" 2b, 5b \n" " .previous \n" + " .set mips0 \n" : [old] "=&r" (old), [err] "=&r" (err), [tmp] "=&r" (tmp) From 4e7c81af3fa076e2d1534cc665ea2f623e631f5d Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 2 Dec 2009 13:07:01 +0100 Subject: [PATCH 248/298] MIPS: RB532: Fix devices.c compilation. We should now use dev_set_drvdata to set the driver driver_data field. Signed-off-by: Florian Fainelli Patchwork: http://patchwork.linux-mips.org/patch/747/ Signed-off-by: Ralf Baechle --- arch/mips/rb532/devices.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c index 9f40e1ff9b4..041fc1afc3f 100644 --- a/arch/mips/rb532/devices.c +++ b/arch/mips/rb532/devices.c @@ -110,7 +110,6 @@ static struct korina_device korina_dev0_data = { static struct platform_device korina_dev0 = { .id = -1, .name = "korina", - .dev.driver_data = &korina_dev0_data, .resource = korina_dev0_res, .num_resources = ARRAY_SIZE(korina_dev0_res), }; @@ -332,6 +331,8 @@ static int __init plat_setup_devices(void) /* set the uart clock to the current cpu frequency */ rb532_uart_res[0].uartclk = idt_cpu_freq; + dev_set_drvdata(&korina_dev0.dev, &korina_dev0_data); + return platform_add_devices(rb532_devs, ARRAY_SIZE(rb532_devs)); } From e8092da92e1fd38dc7c38a4eeae93eaa21764584 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 30 Nov 2009 14:01:56 +0000 Subject: [PATCH 249/298] regulator: Initialise wm831x structure pointor for ISINK driver The version that made it into mainline missed the initialisation of the chip handle. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/wm831x-isink.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c index 1d8d9879d3a..48857008758 100644 --- a/drivers/regulator/wm831x-isink.c +++ b/drivers/regulator/wm831x-isink.c @@ -167,6 +167,8 @@ static __devinit int wm831x_isink_probe(struct platform_device *pdev) return -ENOMEM; } + isink->wm831x = wm831x; + res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (res == NULL) { dev_err(&pdev->dev, "No I/O resource\n"); From 35dead4235e2b67da7275b4122fed37099c2f462 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 3 Dec 2009 00:29:15 +0100 Subject: [PATCH 250/298] modules: don't export section names of empty sections via sysfs On the parisc architecture we face for each and every loaded kernel module this kernel "badness warning": sysfs: cannot create duplicate filename '/module/ac97_bus/sections/.text' Badness at fs/sysfs/dir.c:487 Reason for that is, that on parisc all kernel modules do have multiple .text sections due to the usage of the -ffunction-sections compiler flag which is needed to reach all jump targets on this platform. An objdump on such a kernel module gives: Sections: Idx Name Size VMA LMA File off Algn 0 .note.gnu.build-id 00000024 00000000 00000000 00000034 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 1 .text 00000000 00000000 00000000 00000058 2**0 CONTENTS, ALLOC, LOAD, READONLY, CODE 2 .text.ac97_bus_match 0000001c 00000000 00000000 00000058 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 3 .text 00000000 00000000 00000000 000000d4 2**0 CONTENTS, ALLOC, LOAD, READONLY, CODE ... Since the .text sections are empty (size of 0 bytes) and won't be loaded by the kernel module loader anyway, I don't see a reason why such sections need to be listed under /sys/module//sections/ either. The attached patch does solve this issue by not exporting section names which are empty. This fixes bugzilla http://bugzilla.kernel.org/show_bug.cgi?id=14703 Signed-off-by: Helge Deller CC: rusty@rustcorp.com.au CC: akpm@linux-foundation.org CC: James.Bottomley@HansenPartnership.com CC: roland@redhat.com CC: dave@hiauly1.hia.nrc.ca Signed-off-by: Linus Torvalds --- kernel/module.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/module.c b/kernel/module.c index 8b7d8805819..5842a71cf05 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1187,7 +1187,8 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect, /* Count loaded sections and allocate structures */ for (i = 0; i < nsect; i++) - if (sechdrs[i].sh_flags & SHF_ALLOC) + if (sechdrs[i].sh_flags & SHF_ALLOC + && sechdrs[i].sh_size) nloaded++; size[0] = ALIGN(sizeof(*sect_attrs) + nloaded * sizeof(sect_attrs->attrs[0]), @@ -1207,6 +1208,8 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect, for (i = 0; i < nsect; i++) { if (! (sechdrs[i].sh_flags & SHF_ALLOC)) continue; + if (!sechdrs[i].sh_size) + continue; sattr->address = sechdrs[i].sh_addr; sattr->name = kstrdup(secstrings + sechdrs[i].sh_name, GFP_KERNEL); From f066a4f6df68f03b565dfe867dde54dfeb26576e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 1 Dec 2009 14:56:44 +1030 Subject: [PATCH 251/298] param: don't complain about unused module parameters. Jon confirms that recent modprobe will look in /proc/cmdline, so these cmdline options can still be used. See http://bugzilla.kernel.org/show_bug.cgi?id=14164 Reported-by: Adam Williamson Cc: stable@kernel.org Signed-off-by: Rusty Russell Signed-off-by: Linus Torvalds --- init/main.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/init/main.c b/init/main.c index 5988debfc50..4051d75dd2d 100644 --- a/init/main.c +++ b/init/main.c @@ -251,7 +251,7 @@ early_param("loglevel", loglevel); /* * Unknown boot options get handed to init, unless they look like - * failed parameters + * unused parameters (modprobe will find them in /proc/cmdline). */ static int __init unknown_bootoption(char *param, char *val) { @@ -272,14 +272,9 @@ static int __init unknown_bootoption(char *param, char *val) if (obsolete_checksetup(param)) return 0; - /* - * Preemptive maintenance for "why didn't my misspelled command - * line work?" - */ - if (strchr(param, '.') && (!val || strchr(param, '.') < val)) { - printk(KERN_ERR "Unknown boot option `%s': ignoring\n", param); + /* Unused module parameter. */ + if (strchr(param, '.') && (!val || strchr(param, '.') < val)) return 0; - } if (panic_later) return 0; From 049e2d13b8e8a6d8be43e675a5ed9d4613819f65 Mon Sep 17 00:00:00 2001 From: Anisse Astier Date: Tue, 1 Dec 2009 01:14:25 -0800 Subject: [PATCH 252/298] Input: i8042 - add Dell Vostro 1320, 1520 and 1720 to the reset list These laptops often leave i8042 in a wierd state resulting in non- operational touchpad and keyboard. Signed-off-by: Anisse Astier Signed-off-by: Dmitry Torokhov Signed-off-by: Linus Torvalds --- drivers/input/serio/i8042-x86ia64io.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index a537925f765..2bcf1ace27c 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -447,6 +447,27 @@ static struct dmi_system_id __initdata i8042_dmi_reset_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "N10"), }, }, + { + .ident = "Dell Vostro 1320", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1320"), + }, + }, + { + .ident = "Dell Vostro 1520", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1520"), + }, + }, + { + .ident = "Dell Vostro 1720", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1720"), + }, + }, { } }; From dbf763a2f1c117cfe45bbbd2c874a150f0e0900b Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Thu, 3 Sep 2009 22:59:01 +0900 Subject: [PATCH 253/298] SPI: spi_txx9: Fix bit rate calculation TXx9 SPI bit rate is calculated by: fBR = (spi-baseclk) / (n + 1) Fix calculation of min_speed_hz, max_speed_hz and n. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- drivers/spi/spi_txx9.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi_txx9.c b/drivers/spi/spi_txx9.c index 96057de133a..19f75627c3d 100644 --- a/drivers/spi/spi_txx9.c +++ b/drivers/spi/spi_txx9.c @@ -29,6 +29,8 @@ #define SPI_FIFO_SIZE 4 +#define SPI_MAX_DIVIDER 0xff /* Max. value for SPCR1.SER */ +#define SPI_MIN_DIVIDER 1 /* Min. value for SPCR1.SER */ #define TXx9_SPMCR 0x00 #define TXx9_SPCR0 0x04 @@ -193,11 +195,8 @@ static void txx9spi_work_one(struct txx9spi *c, struct spi_message *m) if (prev_speed_hz != speed_hz || prev_bits_per_word != bits_per_word) { - u32 n = (c->baseclk + speed_hz - 1) / speed_hz; - if (n < 1) - n = 1; - else if (n > 0xff) - n = 0xff; + int n = DIV_ROUND_UP(c->baseclk, speed_hz) - 1; + n = clamp(n, SPI_MIN_DIVIDER, SPI_MAX_DIVIDER); /* enter config mode */ txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR, TXx9_SPMCR); @@ -370,8 +369,8 @@ static int __init txx9spi_probe(struct platform_device *dev) goto exit; } c->baseclk = clk_get_rate(c->clk); - c->min_speed_hz = (c->baseclk + 0xff - 1) / 0xff; - c->max_speed_hz = c->baseclk; + c->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1); + c->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1); res = platform_get_resource(dev, IORESOURCE_MEM, 0); if (!res) From 0fdd07f77fd9cc6a7d49076793daef06ea5d8f13 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 9 Aug 2009 11:42:32 +0200 Subject: [PATCH 254/298] VIDEO: Correct use of request_region/request_mem_region request_region should be used with release_region, not request_mem_region. Geert Uytterhoeven pointed out that in the case of drivers/video/gbefb.c, the problem is actually the other way around; request_mem_region should be used instead of request_region. The semantic patch that finds/fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @r1@ expression start; @@ request_region(start,...) @b1@ expression r1.start; @@ request_mem_region(start,...) @depends on !b1@ expression r1.start; expression E; @@ - release_mem_region + release_region (start,E) // Signed-off-by: Julia Lawall Signed-off-by: Ralf Baechle --- drivers/video/gbefb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index 1a83709f961..f67db426837 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c @@ -1147,7 +1147,7 @@ static int __init gbefb_probe(struct platform_device *p_dev) gbefb_setup(options); #endif - if (!request_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) { + if (!request_mem_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) { printk(KERN_ERR "gbefb: couldn't reserve mmio region\n"); ret = -EBUSY; goto out_release_framebuffer; From 22763c5cf3690a681551162c15d34d935308c8d7 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 2 Dec 2009 19:51:21 -0800 Subject: [PATCH 255/298] Linux 2.6.32 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ad8260102f6..f5cdb72ba2c 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 32 -EXTRAVERSION = -rc8 +EXTRAVERSION = NAME = Man-Eating Seals of Antiquity # *DOCUMENTATION* From d3f6bad3911736e44ba11f3f3f6ac4e8c837fdfc Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 2 Dec 2009 12:10:13 -0800 Subject: [PATCH 256/298] rcu: Rename "quiet" functions The number of "quiet" functions has grown recently, and the names are no longer very descriptive. The point of all of these functions is to do some portion of the task of reporting a quiescent state, so rename them accordingly: o cpu_quiet() becomes rcu_report_qs_rdp(), which reports a quiescent state to the per-CPU rcu_data structure. If this turns out to be a new quiescent state for this grace period, then rcu_report_qs_rnp() will be invoked to propagate the quiescent state up the rcu_node hierarchy. o cpu_quiet_msk() becomes rcu_report_qs_rnp(), which reports a quiescent state for a given CPU (or possibly a set of CPUs) up the rcu_node hierarchy. o cpu_quiet_msk_finish() becomes rcu_report_qs_rsp(), which reports a full set of quiescent states to the global rcu_state structure. o task_quiet() becomes rcu_report_unblock_qs_rnp(), which reports a quiescent state due to a task exiting an RCU read-side critical section that had previously blocked in that same critical section. As indicated by the new name, this type of quiescent state is reported up the rcu_node hierarchy (using rcu_report_qs_rnp() to do so). Signed-off-by: Paul E. McKenney Acked-by: Josh Triplett Acked-by: Lai Jiangshan Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12597846163698-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 66 +++++++++++++++++++++++------------------ kernel/rcutree.h | 3 +- kernel/rcutree_plugin.h | 12 ++++---- 3 files changed, 45 insertions(+), 36 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 4ca7e0292fd..a9f51031d3e 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -740,11 +740,13 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) } /* - * Clean up after the prior grace period and let rcu_start_gp() start up - * the next grace period if one is needed. Note that the caller must - * hold rnp->lock, as required by rcu_start_gp(), which will release it. + * Report a full set of quiescent states to the specified rcu_state + * data structure. This involves cleaning up after the prior grace + * period and letting rcu_start_gp() start up the next grace period + * if one is needed. Note that the caller must hold rnp->lock, as + * required by rcu_start_gp(), which will release it. */ -static void cpu_quiet_msk_finish(struct rcu_state *rsp, unsigned long flags) +static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags) __releases(rcu_get_root(rsp)->lock) { WARN_ON_ONCE(!rcu_gp_in_progress(rsp)); @@ -754,15 +756,16 @@ static void cpu_quiet_msk_finish(struct rcu_state *rsp, unsigned long flags) } /* - * Similar to cpu_quiet(), for which it is a helper function. Allows - * a group of CPUs to be quieted at one go, though all the CPUs in the - * group must be represented by the same leaf rcu_node structure. - * That structure's lock must be held upon entry, and it is released - * before return. + * Similar to rcu_report_qs_rdp(), for which it is a helper function. + * Allows quiescent states for a group of CPUs to be reported at one go + * to the specified rcu_node structure, though all the CPUs in the group + * must be represented by the same rcu_node structure (which need not be + * a leaf rcu_node structure, though it often will be). That structure's + * lock must be held upon entry, and it is released before return. */ static void -cpu_quiet_msk(unsigned long mask, struct rcu_state *rsp, struct rcu_node *rnp, - unsigned long flags) +rcu_report_qs_rnp(unsigned long mask, struct rcu_state *rsp, + struct rcu_node *rnp, unsigned long flags) __releases(rnp->lock) { struct rcu_node *rnp_c; @@ -798,21 +801,23 @@ cpu_quiet_msk(unsigned long mask, struct rcu_state *rsp, struct rcu_node *rnp, /* * Get here if we are the last CPU to pass through a quiescent - * state for this grace period. Invoke cpu_quiet_msk_finish() + * state for this grace period. Invoke rcu_report_qs_rsp() * to clean up and start the next grace period if one is needed. */ - cpu_quiet_msk_finish(rsp, flags); /* releases rnp->lock. */ + rcu_report_qs_rsp(rsp, flags); /* releases rnp->lock. */ } /* - * Record a quiescent state for the specified CPU, which must either be - * the current CPU. The lastcomp argument is used to make sure we are - * still in the grace period of interest. We don't want to end the current - * grace period based on quiescent states detected in an earlier grace - * period! + * Record a quiescent state for the specified CPU to that CPU's rcu_data + * structure. This must be either called from the specified CPU, or + * called when the specified CPU is known to be offline (and when it is + * also known that no other CPU is concurrently trying to help the offline + * CPU). The lastcomp argument is used to make sure we are still in the + * grace period of interest. We don't want to end the current grace period + * based on quiescent states detected in an earlier grace period! */ static void -cpu_quiet(int cpu, struct rcu_state *rsp, struct rcu_data *rdp, long lastcomp) +rcu_report_qs_rdp(int cpu, struct rcu_state *rsp, struct rcu_data *rdp, long lastcomp) { unsigned long flags; unsigned long mask; @@ -827,8 +832,8 @@ cpu_quiet(int cpu, struct rcu_state *rsp, struct rcu_data *rdp, long lastcomp) * The race with GP start is resolved by the fact that we * hold the leaf rcu_node lock, so that the per-CPU bits * cannot yet be initialized -- so we would simply find our - * CPU's bit already cleared in cpu_quiet_msk() if this race - * occurred. + * CPU's bit already cleared in rcu_report_qs_rnp() if this + * race occurred. */ rdp->passed_quiesc = 0; /* try again later! */ spin_unlock_irqrestore(&rnp->lock, flags); @@ -846,7 +851,7 @@ cpu_quiet(int cpu, struct rcu_state *rsp, struct rcu_data *rdp, long lastcomp) */ rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; - cpu_quiet_msk(mask, rsp, rnp, flags); /* releases rnp->lock */ + rcu_report_qs_rnp(mask, rsp, rnp, flags); /* rlses rnp->lock */ } } @@ -877,8 +882,11 @@ rcu_check_quiescent_state(struct rcu_state *rsp, struct rcu_data *rdp) if (!rdp->passed_quiesc) return; - /* Tell RCU we are done (but cpu_quiet() will be the judge of that). */ - cpu_quiet(rdp->cpu, rsp, rdp, rdp->passed_quiesc_completed); + /* + * Tell RCU we are done (but rcu_report_qs_rdp() will be the + * judge of that). + */ + rcu_report_qs_rdp(rdp->cpu, rsp, rdp, rdp->passed_quiesc_completed); } #ifdef CONFIG_HOTPLUG_CPU @@ -968,13 +976,13 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) /* * We still hold the leaf rcu_node structure lock here, and * irqs are still disabled. The reason for this subterfuge is - * because invoking task_quiet() with ->onofflock held leads - * to deadlock. + * because invoking rcu_report_unblock_qs_rnp() with ->onofflock + * held leads to deadlock. */ spin_unlock(&rsp->onofflock); /* irqs remain disabled. */ rnp = rdp->mynode; if (need_quiet) - task_quiet(rnp, flags); + rcu_report_unblock_qs_rnp(rnp, flags); else spin_unlock_irqrestore(&rnp->lock, flags); @@ -1164,8 +1172,8 @@ static int rcu_process_dyntick(struct rcu_state *rsp, long lastcomp, } if (mask != 0 && rnp->completed == lastcomp) { - /* cpu_quiet_msk() releases rnp->lock. */ - cpu_quiet_msk(mask, rsp, rnp, flags); + /* rcu_report_qs_rnp() releases rnp->lock. */ + rcu_report_qs_rnp(mask, rsp, rnp, flags); continue; } spin_unlock_irqrestore(&rnp->lock, flags); diff --git a/kernel/rcutree.h b/kernel/rcutree.h index a81188c4292..8bb03cb0744 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -306,7 +306,8 @@ long rcu_batches_completed(void); static void rcu_preempt_note_context_switch(int cpu); static int rcu_preempted_readers(struct rcu_node *rnp); #ifdef CONFIG_HOTPLUG_CPU -static void task_quiet(struct rcu_node *rnp, unsigned long flags); +static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, + unsigned long flags); #endif /* #ifdef CONFIG_HOTPLUG_CPU */ #ifdef CONFIG_RCU_CPU_STALL_DETECTOR static void rcu_print_task_stall(struct rcu_node *rnp); diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 1d295c789d3..c9f0c975c00 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -167,7 +167,7 @@ static int rcu_preempted_readers(struct rcu_node *rnp) * irqs disabled, and this lock is released upon return, but irqs remain * disabled. */ -static void task_quiet(struct rcu_node *rnp, unsigned long flags) +static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, unsigned long flags) __releases(rnp->lock) { unsigned long mask; @@ -185,7 +185,7 @@ static void task_quiet(struct rcu_node *rnp, unsigned long flags) * or tasks were kicked up to root rcu_node due to * CPUs going offline. */ - cpu_quiet_msk_finish(&rcu_preempt_state, flags); + rcu_report_qs_rsp(&rcu_preempt_state, flags); return; } @@ -193,7 +193,7 @@ static void task_quiet(struct rcu_node *rnp, unsigned long flags) mask = rnp->grpmask; spin_unlock(&rnp->lock); /* irqs remain disabled. */ spin_lock(&rnp_p->lock); /* irqs already disabled. */ - cpu_quiet_msk(mask, &rcu_preempt_state, rnp_p, flags); + rcu_report_qs_rnp(mask, &rcu_preempt_state, rnp_p, flags); } /* @@ -253,12 +253,12 @@ static void rcu_read_unlock_special(struct task_struct *t) /* * If this was the last task on the current list, and if * we aren't waiting on any CPUs, report the quiescent state. - * Note that task_quiet() releases rnp->lock. + * Note that rcu_report_unblock_qs_rnp() releases rnp->lock. */ if (empty) spin_unlock_irqrestore(&rnp->lock, flags); else - task_quiet(rnp, flags); + rcu_report_unblock_qs_rnp(rnp, flags); } else { local_irq_restore(flags); } @@ -566,7 +566,7 @@ static int rcu_preempted_readers(struct rcu_node *rnp) #ifdef CONFIG_HOTPLUG_CPU /* Because preemptible RCU does not exist, no quieting of tasks. */ -static void task_quiet(struct rcu_node *rnp, unsigned long flags) +static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, unsigned long flags) { spin_unlock_irqrestore(&rnp->lock, flags); } From cf244dc01bf68e1ad338b82447f8686d24ea4435 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 2 Dec 2009 12:10:14 -0800 Subject: [PATCH 257/298] rcu: Enable fourth level of TREE_RCU hierarchy Enable a fourth level of rcu_node hierarchy for TREE_RCU and TREE_PREEMPT_RCU. This is for stress-testing and experiemental purposes only, although in theory this would enable 16,777,216 CPUs on 64-bit systems, though only 1,048,576 CPUs on 32-bit systems. Normal experimental use of this fourth level will normally set CONFIG_RCU_FANOUT=2, requiring a 16-CPU system, though the more adventurous (and more fortunate) experimenters may wish to chose CONFIG_RCU_FANOUT=3 for 81-CPU systems or even CONFIG_RCU_FANOUT=4 for 256-CPU systems. Signed-off-by: Paul E. McKenney Acked-by: Josh Triplett Acked-by: Lai Jiangshan Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12597846161257-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutree.c | 6 +++++- kernel/rcutree.h | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/kernel/rcutree.c b/kernel/rcutree.c index a9f51031d3e..d47e03e5792 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -60,7 +60,8 @@ static struct lock_class_key rcu_node_class[NUM_RCU_LVLS]; NUM_RCU_LVL_0, /* root of hierarchy. */ \ NUM_RCU_LVL_1, \ NUM_RCU_LVL_2, \ - NUM_RCU_LVL_3, /* == MAX_RCU_LVLS */ \ + NUM_RCU_LVL_3, \ + NUM_RCU_LVL_4, /* == MAX_RCU_LVLS */ \ }, \ .signaled = RCU_GP_IDLE, \ .gpnum = -300, \ @@ -1877,6 +1878,9 @@ void __init rcu_init(void) #ifdef CONFIG_RCU_CPU_STALL_DETECTOR printk(KERN_INFO "RCU-based detection of stalled CPUs is enabled.\n"); #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ +#if NUM_RCU_LVL_4 != 0 + printk(KERN_INFO "Experimental four-level hierarchy is enabled.\n"); +#endif /* #if NUM_RCU_LVL_4 != 0 */ RCU_INIT_FLAVOR(&rcu_sched_state, rcu_sched_data); RCU_INIT_FLAVOR(&rcu_bh_state, rcu_bh_data); __rcu_init_preempt(); diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 8bb03cb0744..df2e0b69474 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -34,10 +34,11 @@ * In practice, this has not been tested, so there is probably some * bug somewhere. */ -#define MAX_RCU_LVLS 3 +#define MAX_RCU_LVLS 4 #define RCU_FANOUT (CONFIG_RCU_FANOUT) #define RCU_FANOUT_SQ (RCU_FANOUT * RCU_FANOUT) #define RCU_FANOUT_CUBE (RCU_FANOUT_SQ * RCU_FANOUT) +#define RCU_FANOUT_FOURTH (RCU_FANOUT_CUBE * RCU_FANOUT) #if NR_CPUS <= RCU_FANOUT # define NUM_RCU_LVLS 1 @@ -45,23 +46,33 @@ # define NUM_RCU_LVL_1 (NR_CPUS) # define NUM_RCU_LVL_2 0 # define NUM_RCU_LVL_3 0 +# define NUM_RCU_LVL_4 0 #elif NR_CPUS <= RCU_FANOUT_SQ # define NUM_RCU_LVLS 2 # define NUM_RCU_LVL_0 1 # define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT) # define NUM_RCU_LVL_2 (NR_CPUS) # define NUM_RCU_LVL_3 0 +# define NUM_RCU_LVL_4 0 #elif NR_CPUS <= RCU_FANOUT_CUBE # define NUM_RCU_LVLS 3 # define NUM_RCU_LVL_0 1 # define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_SQ) # define NUM_RCU_LVL_2 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT) # define NUM_RCU_LVL_3 NR_CPUS +# define NUM_RCU_LVL_4 0 +#elif NR_CPUS <= RCU_FANOUT_FOURTH +# define NUM_RCU_LVLS 4 +# define NUM_RCU_LVL_0 1 +# define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_CUBE) +# define NUM_RCU_LVL_2 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_SQ) +# define NUM_RCU_LVL_3 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT) +# define NUM_RCU_LVL_4 NR_CPUS #else # error "CONFIG_RCU_FANOUT insufficient for NR_CPUS" #endif /* #if (NR_CPUS) <= RCU_FANOUT */ -#define RCU_SUM (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2 + NUM_RCU_LVL_3) +#define RCU_SUM (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2 + NUM_RCU_LVL_3 + NUM_RCU_LVL_4) #define NUM_RCU_NODES (RCU_SUM - NR_CPUS) /* From d9a3da0699b24a589b27a61e1a5b5bd30d9db669 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 2 Dec 2009 12:10:15 -0800 Subject: [PATCH 258/298] rcu: Add expedited grace-period support for preemptible RCU Implement an synchronize_rcu_expedited() for preemptible RCU that actually is expedited. This uses synchronize_sched_expedited() to force all threads currently running in a preemptible-RCU read-side critical section onto the appropriate ->blocked_tasks[] list, then takes a snapshot of all of these lists and waits for them to drain. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <1259784616158-git-send-email-> Signed-off-by: Ingo Molnar --- kernel/rcutorture.c | 34 +++++-- kernel/rcutree.c | 10 +- kernel/rcutree.h | 35 ++++++- kernel/rcutree_plugin.h | 198 ++++++++++++++++++++++++++++++++++++++-- kernel/rcutree_trace.c | 10 +- 5 files changed, 260 insertions(+), 27 deletions(-) diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 3dd0ca23e19..a621a67ef4e 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -327,6 +327,11 @@ rcu_torture_cb(struct rcu_head *p) cur_ops->deferred_free(rp); } +static int rcu_no_completed(void) +{ + return 0; +} + static void rcu_torture_deferred_free(struct rcu_torture *p) { call_rcu(&p->rtort_rcu, rcu_torture_cb); @@ -388,6 +393,21 @@ static struct rcu_torture_ops rcu_sync_ops = { .name = "rcu_sync" }; +static struct rcu_torture_ops rcu_expedited_ops = { + .init = rcu_sync_torture_init, + .cleanup = NULL, + .readlock = rcu_torture_read_lock, + .read_delay = rcu_read_delay, /* just reuse rcu's version. */ + .readunlock = rcu_torture_read_unlock, + .completed = rcu_no_completed, + .deferred_free = rcu_sync_torture_deferred_free, + .sync = synchronize_rcu_expedited, + .cb_barrier = NULL, + .stats = NULL, + .irq_capable = 1, + .name = "rcu_expedited" +}; + /* * Definitions for rcu_bh torture testing. */ @@ -581,11 +601,6 @@ static void sched_torture_read_unlock(int idx) preempt_enable(); } -static int sched_torture_completed(void) -{ - return 0; -} - static void rcu_sched_torture_deferred_free(struct rcu_torture *p) { call_rcu_sched(&p->rtort_rcu, rcu_torture_cb); @@ -602,7 +617,7 @@ static struct rcu_torture_ops sched_ops = { .readlock = sched_torture_read_lock, .read_delay = rcu_read_delay, /* just reuse rcu's version. */ .readunlock = sched_torture_read_unlock, - .completed = sched_torture_completed, + .completed = rcu_no_completed, .deferred_free = rcu_sched_torture_deferred_free, .sync = sched_torture_synchronize, .cb_barrier = rcu_barrier_sched, @@ -617,7 +632,7 @@ static struct rcu_torture_ops sched_sync_ops = { .readlock = sched_torture_read_lock, .read_delay = rcu_read_delay, /* just reuse rcu's version. */ .readunlock = sched_torture_read_unlock, - .completed = sched_torture_completed, + .completed = rcu_no_completed, .deferred_free = rcu_sync_torture_deferred_free, .sync = sched_torture_synchronize, .cb_barrier = NULL, @@ -631,7 +646,7 @@ static struct rcu_torture_ops sched_expedited_ops = { .readlock = sched_torture_read_lock, .read_delay = rcu_read_delay, /* just reuse rcu's version. */ .readunlock = sched_torture_read_unlock, - .completed = sched_torture_completed, + .completed = rcu_no_completed, .deferred_free = rcu_sync_torture_deferred_free, .sync = synchronize_sched_expedited, .cb_barrier = NULL, @@ -1116,7 +1131,8 @@ rcu_torture_init(void) int cpu; int firsterr = 0; static struct rcu_torture_ops *torture_ops[] = - { &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops, + { &rcu_ops, &rcu_sync_ops, &rcu_expedited_ops, + &rcu_bh_ops, &rcu_bh_sync_ops, &srcu_ops, &srcu_expedited_ops, &sched_ops, &sched_sync_ops, &sched_expedited_ops, }; diff --git a/kernel/rcutree.c b/kernel/rcutree.c index d47e03e5792..53ae9598f79 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -948,7 +948,7 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) { unsigned long flags; unsigned long mask; - int need_quiet = 0; + int need_report = 0; struct rcu_data *rdp = rsp->rda[cpu]; struct rcu_node *rnp; @@ -967,7 +967,7 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) break; } if (rnp == rdp->mynode) - need_quiet = rcu_preempt_offline_tasks(rsp, rnp, rdp); + need_report = rcu_preempt_offline_tasks(rsp, rnp, rdp); else spin_unlock(&rnp->lock); /* irqs remain disabled. */ mask = rnp->grpmask; @@ -982,10 +982,12 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) */ spin_unlock(&rsp->onofflock); /* irqs remain disabled. */ rnp = rdp->mynode; - if (need_quiet) + if (need_report & RCU_OFL_TASKS_NORM_GP) rcu_report_unblock_qs_rnp(rnp, flags); else spin_unlock_irqrestore(&rnp->lock, flags); + if (need_report & RCU_OFL_TASKS_EXP_GP) + rcu_report_exp_rnp(rsp, rnp); rcu_adopt_orphan_cbs(rsp); } @@ -1843,6 +1845,8 @@ static void __init rcu_init_one(struct rcu_state *rsp) rnp->level = i; INIT_LIST_HEAD(&rnp->blocked_tasks[0]); INIT_LIST_HEAD(&rnp->blocked_tasks[1]); + INIT_LIST_HEAD(&rnp->blocked_tasks[2]); + INIT_LIST_HEAD(&rnp->blocked_tasks[3]); } } } diff --git a/kernel/rcutree.h b/kernel/rcutree.h index df2e0b69474..d2a0046f63b 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -104,8 +104,12 @@ struct rcu_node { /* an rcu_data structure, otherwise, each */ /* bit corresponds to a child rcu_node */ /* structure. */ + unsigned long expmask; /* Groups that have ->blocked_tasks[] */ + /* elements that need to drain to allow the */ + /* current expedited grace period to */ + /* complete (only for TREE_PREEMPT_RCU). */ unsigned long qsmaskinit; - /* Per-GP initialization for qsmask. */ + /* Per-GP initial value for qsmask & expmask. */ unsigned long grpmask; /* Mask to apply to parent qsmask. */ /* Only one bit will be set in this mask. */ int grplo; /* lowest-numbered CPU or group here. */ @@ -113,7 +117,7 @@ struct rcu_node { u8 grpnum; /* CPU/group number for next level up. */ u8 level; /* root is at level 0. */ struct rcu_node *parent; - struct list_head blocked_tasks[2]; + struct list_head blocked_tasks[4]; /* Tasks blocked in RCU read-side critsect. */ /* Grace period number (->gpnum) x blocked */ /* by tasks on the (x & 0x1) element of the */ @@ -128,6 +132,21 @@ struct rcu_node { for ((rnp) = &(rsp)->node[0]; \ (rnp) < &(rsp)->node[NUM_RCU_NODES]; (rnp)++) +/* + * Do a breadth-first scan of the non-leaf rcu_node structures for the + * specified rcu_state structure. Note that if there is a singleton + * rcu_node tree with but one rcu_node structure, this loop is a no-op. + */ +#define rcu_for_each_nonleaf_node_breadth_first(rsp, rnp) \ + for ((rnp) = &(rsp)->node[0]; \ + (rnp) < (rsp)->level[NUM_RCU_LVLS - 1]; (rnp)++) + +/* + * Scan the leaves of the rcu_node hierarchy for the specified rcu_state + * structure. Note that if there is a singleton rcu_node tree with but + * one rcu_node structure, this loop -will- visit the rcu_node structure. + * It is still a leaf node, even if it is also the root node. + */ #define rcu_for_each_leaf_node(rsp, rnp) \ for ((rnp) = (rsp)->level[NUM_RCU_LVLS - 1]; \ (rnp) < &(rsp)->node[NUM_RCU_NODES]; (rnp)++) @@ -261,7 +280,7 @@ struct rcu_state { long gpnum; /* Current gp number. */ long completed; /* # of last completed gp. */ - /* End of fields guarded by root rcu_node's lock. */ + /* End of fields guarded by root rcu_node's lock. */ spinlock_t onofflock; /* exclude on/offline and */ /* starting new GP. Also */ @@ -293,6 +312,13 @@ struct rcu_state { #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ }; +/* Return values for rcu_preempt_offline_tasks(). */ + +#define RCU_OFL_TASKS_NORM_GP 0x1 /* Tasks blocking normal */ + /* GP were moved to root. */ +#define RCU_OFL_TASKS_EXP_GP 0x2 /* Tasks blocking expedited */ + /* GP were moved to root. */ + #ifdef RCU_TREE_NONCORE /* @@ -333,6 +359,9 @@ static void rcu_preempt_offline_cpu(int cpu); static void rcu_preempt_check_callbacks(int cpu); static void rcu_preempt_process_callbacks(void); void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)); +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_TREE_PREEMPT_RCU) +static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp); +#endif /* #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_TREE_PREEMPT_RCU) */ static int rcu_preempt_pending(int cpu); static int rcu_preempt_needs_cpu(int cpu); static void __cpuinit rcu_preempt_init_percpu_data(int cpu); diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index c9f0c975c00..37fbccdf41d 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h @@ -24,12 +24,15 @@ * Paul E. McKenney */ +#include #ifdef CONFIG_TREE_PREEMPT_RCU struct rcu_state rcu_preempt_state = RCU_STATE_INITIALIZER(rcu_preempt_state); DEFINE_PER_CPU(struct rcu_data, rcu_preempt_data); +static int rcu_preempted_readers_exp(struct rcu_node *rnp); + /* * Tell them what RCU they are running. */ @@ -157,7 +160,10 @@ EXPORT_SYMBOL_GPL(__rcu_read_lock); */ static int rcu_preempted_readers(struct rcu_node *rnp) { - return !list_empty(&rnp->blocked_tasks[rnp->gpnum & 0x1]); + int phase = rnp->gpnum & 0x1; + + return !list_empty(&rnp->blocked_tasks[phase]) || + !list_empty(&rnp->blocked_tasks[phase + 2]); } /* @@ -204,6 +210,7 @@ static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, unsigned long flags) static void rcu_read_unlock_special(struct task_struct *t) { int empty; + int empty_exp; unsigned long flags; struct rcu_node *rnp; int special; @@ -247,6 +254,8 @@ static void rcu_read_unlock_special(struct task_struct *t) spin_unlock(&rnp->lock); /* irqs remain disabled. */ } empty = !rcu_preempted_readers(rnp); + empty_exp = !rcu_preempted_readers_exp(rnp); + smp_mb(); /* ensure expedited fastpath sees end of RCU c-s. */ list_del_init(&t->rcu_node_entry); t->rcu_blocked_node = NULL; @@ -259,6 +268,13 @@ static void rcu_read_unlock_special(struct task_struct *t) spin_unlock_irqrestore(&rnp->lock, flags); else rcu_report_unblock_qs_rnp(rnp, flags); + + /* + * If this was the last task on the expedited lists, + * then we need to report up the rcu_node hierarchy. + */ + if (!empty_exp && !rcu_preempted_readers_exp(rnp)) + rcu_report_exp_rnp(&rcu_preempt_state, rnp); } else { local_irq_restore(flags); } @@ -343,7 +359,7 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp, int i; struct list_head *lp; struct list_head *lp_root; - int retval; + int retval = 0; struct rcu_node *rnp_root = rcu_get_root(rsp); struct task_struct *tp; @@ -353,7 +369,9 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp, } WARN_ON_ONCE(rnp != rdp->mynode && (!list_empty(&rnp->blocked_tasks[0]) || - !list_empty(&rnp->blocked_tasks[1]))); + !list_empty(&rnp->blocked_tasks[1]) || + !list_empty(&rnp->blocked_tasks[2]) || + !list_empty(&rnp->blocked_tasks[3]))); /* * Move tasks up to root rcu_node. Rely on the fact that the @@ -361,8 +379,11 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp, * rcu_nodes in terms of gp_num value. This fact allows us to * move the blocked_tasks[] array directly, element by element. */ - retval = rcu_preempted_readers(rnp); - for (i = 0; i < 2; i++) { + if (rcu_preempted_readers(rnp)) + retval |= RCU_OFL_TASKS_NORM_GP; + if (rcu_preempted_readers_exp(rnp)) + retval |= RCU_OFL_TASKS_EXP_GP; + for (i = 0; i < 4; i++) { lp = &rnp->blocked_tasks[i]; lp_root = &rnp_root->blocked_tasks[i]; while (!list_empty(lp)) { @@ -449,14 +470,159 @@ void synchronize_rcu(void) } EXPORT_SYMBOL_GPL(synchronize_rcu); +static DECLARE_WAIT_QUEUE_HEAD(sync_rcu_preempt_exp_wq); +static long sync_rcu_preempt_exp_count; +static DEFINE_MUTEX(sync_rcu_preempt_exp_mutex); + /* - * Wait for an rcu-preempt grace period. We are supposed to expedite the - * grace period, but this is the crude slow compatability hack, so just - * invoke synchronize_rcu(). + * Return non-zero if there are any tasks in RCU read-side critical + * sections blocking the current preemptible-RCU expedited grace period. + * If there is no preemptible-RCU expedited grace period currently in + * progress, returns zero unconditionally. + */ +static int rcu_preempted_readers_exp(struct rcu_node *rnp) +{ + return !list_empty(&rnp->blocked_tasks[2]) || + !list_empty(&rnp->blocked_tasks[3]); +} + +/* + * return non-zero if there is no RCU expedited grace period in progress + * for the specified rcu_node structure, in other words, if all CPUs and + * tasks covered by the specified rcu_node structure have done their bit + * for the current expedited grace period. Works only for preemptible + * RCU -- other RCU implementation use other means. + * + * Caller must hold sync_rcu_preempt_exp_mutex. + */ +static int sync_rcu_preempt_exp_done(struct rcu_node *rnp) +{ + return !rcu_preempted_readers_exp(rnp) && + ACCESS_ONCE(rnp->expmask) == 0; +} + +/* + * Report the exit from RCU read-side critical section for the last task + * that queued itself during or before the current expedited preemptible-RCU + * grace period. This event is reported either to the rcu_node structure on + * which the task was queued or to one of that rcu_node structure's ancestors, + * recursively up the tree. (Calm down, calm down, we do the recursion + * iteratively!) + * + * Caller must hold sync_rcu_preempt_exp_mutex. + */ +static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp) +{ + unsigned long flags; + unsigned long mask; + + spin_lock_irqsave(&rnp->lock, flags); + for (;;) { + if (!sync_rcu_preempt_exp_done(rnp)) + break; + if (rnp->parent == NULL) { + wake_up(&sync_rcu_preempt_exp_wq); + break; + } + mask = rnp->grpmask; + spin_unlock(&rnp->lock); /* irqs remain disabled */ + rnp = rnp->parent; + spin_lock(&rnp->lock); /* irqs already disabled */ + rnp->expmask &= ~mask; + } + spin_unlock_irqrestore(&rnp->lock, flags); +} + +/* + * Snapshot the tasks blocking the newly started preemptible-RCU expedited + * grace period for the specified rcu_node structure. If there are no such + * tasks, report it up the rcu_node hierarchy. + * + * Caller must hold sync_rcu_preempt_exp_mutex and rsp->onofflock. + */ +static void +sync_rcu_preempt_exp_init(struct rcu_state *rsp, struct rcu_node *rnp) +{ + int must_wait; + + spin_lock(&rnp->lock); /* irqs already disabled */ + list_splice_init(&rnp->blocked_tasks[0], &rnp->blocked_tasks[2]); + list_splice_init(&rnp->blocked_tasks[1], &rnp->blocked_tasks[3]); + must_wait = rcu_preempted_readers_exp(rnp); + spin_unlock(&rnp->lock); /* irqs remain disabled */ + if (!must_wait) + rcu_report_exp_rnp(rsp, rnp); +} + +/* + * Wait for an rcu-preempt grace period, but expedite it. The basic idea + * is to invoke synchronize_sched_expedited() to push all the tasks to + * the ->blocked_tasks[] lists, move all entries from the first set of + * ->blocked_tasks[] lists to the second set, and finally wait for this + * second set to drain. */ void synchronize_rcu_expedited(void) { - synchronize_rcu(); + unsigned long flags; + struct rcu_node *rnp; + struct rcu_state *rsp = &rcu_preempt_state; + long snap; + int trycount = 0; + + smp_mb(); /* Caller's modifications seen first by other CPUs. */ + snap = ACCESS_ONCE(sync_rcu_preempt_exp_count) + 1; + smp_mb(); /* Above access cannot bleed into critical section. */ + + /* + * Acquire lock, falling back to synchronize_rcu() if too many + * lock-acquisition failures. Of course, if someone does the + * expedited grace period for us, just leave. + */ + while (!mutex_trylock(&sync_rcu_preempt_exp_mutex)) { + if (trycount++ < 10) + udelay(trycount * num_online_cpus()); + else { + synchronize_rcu(); + return; + } + if ((ACCESS_ONCE(sync_rcu_preempt_exp_count) - snap) > 0) + goto mb_ret; /* Others did our work for us. */ + } + if ((ACCESS_ONCE(sync_rcu_preempt_exp_count) - snap) > 0) + goto unlock_mb_ret; /* Others did our work for us. */ + + /* force all RCU readers onto blocked_tasks[]. */ + synchronize_sched_expedited(); + + spin_lock_irqsave(&rsp->onofflock, flags); + + /* Initialize ->expmask for all non-leaf rcu_node structures. */ + rcu_for_each_nonleaf_node_breadth_first(rsp, rnp) { + spin_lock(&rnp->lock); /* irqs already disabled. */ + rnp->expmask = rnp->qsmaskinit; + spin_unlock(&rnp->lock); /* irqs remain disabled. */ + } + + /* Snapshot current state of ->blocked_tasks[] lists. */ + rcu_for_each_leaf_node(rsp, rnp) + sync_rcu_preempt_exp_init(rsp, rnp); + if (NUM_RCU_NODES > 1) + sync_rcu_preempt_exp_init(rsp, rcu_get_root(rsp)); + + spin_unlock_irqrestore(&rsp->onofflock, flags); + + /* Wait for snapshotted ->blocked_tasks[] lists to drain. */ + rnp = rcu_get_root(rsp); + wait_event(sync_rcu_preempt_exp_wq, + sync_rcu_preempt_exp_done(rnp)); + + /* Clean up and exit. */ + smp_mb(); /* ensure expedited GP seen before counter increment. */ + ACCESS_ONCE(sync_rcu_preempt_exp_count)++; +unlock_mb_ret: + mutex_unlock(&sync_rcu_preempt_exp_mutex); +mb_ret: + smp_mb(); /* ensure subsequent action seen after grace period. */ } EXPORT_SYMBOL_GPL(synchronize_rcu_expedited); @@ -655,6 +821,20 @@ void synchronize_rcu_expedited(void) } EXPORT_SYMBOL_GPL(synchronize_rcu_expedited); +#ifdef CONFIG_HOTPLUG_CPU + +/* + * Because preemptable RCU does not exist, there is never any need to + * report on tasks preempted in RCU read-side critical sections during + * expedited RCU grace periods. + */ +static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp) +{ + return; +} + +#endif /* #ifdef CONFIG_HOTPLUG_CPU */ + /* * Because preemptable RCU does not exist, it never has any work to do. */ diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index 1984cdc51e9..9d2c88423b3 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c @@ -157,6 +157,7 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp) { long gpnum; int level = 0; + int phase; struct rcu_node *rnp; gpnum = rsp->gpnum; @@ -173,10 +174,13 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp) seq_puts(m, "\n"); level = rnp->level; } - seq_printf(m, "%lx/%lx %c>%c %d:%d ^%d ", + phase = gpnum & 0x1; + seq_printf(m, "%lx/%lx %c%c>%c%c %d:%d ^%d ", rnp->qsmask, rnp->qsmaskinit, - "T."[list_empty(&rnp->blocked_tasks[gpnum & 1])], - "T."[list_empty(&rnp->blocked_tasks[!(gpnum & 1)])], + "T."[list_empty(&rnp->blocked_tasks[phase])], + "E."[list_empty(&rnp->blocked_tasks[phase + 2])], + "T."[list_empty(&rnp->blocked_tasks[!phase])], + "E."[list_empty(&rnp->blocked_tasks[!phase + 2])], rnp->grplo, rnp->grphi, rnp->grpnum); } seq_puts(m, "\n"); From 8bfb2f8e655b9d0c45fde679fcd5fd97e34513db Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 2 Dec 2009 12:10:16 -0800 Subject: [PATCH 259/298] rcu: Make RCU's CPU-stall detector be default The RCU_CPU_STALL_DETECTOR costs almost nothing and has located some bugs that might otherwise have been difficult to track down. Make it be default for the TREE RCU implementations. The vmlinux size impact is limited (on 64-bit x86 defconfig): text data bss dec hex filename 8440248 1260076 995588 10695912 a334e8 vmlinux.before 8440774 1260060 995588 10696422 a336e6 vmlinux.after +526 bytes - acceptable default cost. For RAM starved systems, TINY_RCU does not support CPU-stall detection and is much smaller, but then again it is a uniprocessor... Signed-off-by: Paul E. McKenney Acked-by: Lai Jiangshan Cc: dipankar@in.ibm.com Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12597846162906-git-send-email-> [ v2: added image size calculations to the changelog ] Signed-off-by: Ingo Molnar --- lib/Kconfig.debug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 891155817bc..50e0e78259e 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -749,7 +749,7 @@ config RCU_TORTURE_TEST_RUNNABLE config RCU_CPU_STALL_DETECTOR bool "Check for stalled CPUs delaying RCU grace periods" depends on TREE_RCU || TREE_PREEMPT_RCU - default n + default y help This option causes RCU to printk information on which CPUs are delaying the current grace period, but only when From 4528752f49c1f4025473d12bc5fa9181085c3f22 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 2 Dec 2009 15:05:56 -0800 Subject: [PATCH 260/298] x86, Calgary IOMMU quirk: Find nearest matching Calgary while walking up the PCI tree On a multi-node x3950M2 system, there's a slight oddity in the PCI device tree for all secondary nodes: 30:1e.0 PCI bridge: Intel Corporation 82801 PCI Bridge (rev e1) \-33:00.0 PCI bridge: IBM CalIOC2 PCI-E Root Port (rev 01) \-34:00.0 RAID bus controller: LSI Logic / Symbios Logic MegaRAID SAS 1078 (rev 04) ...as compared to the primary node: 00:1e.0 PCI bridge: Intel Corporation 82801 PCI Bridge (rev e1) \-01:00.0 VGA compatible controller: ATI Technologies Inc ES1000 (rev 02) 03:00.0 PCI bridge: IBM CalIOC2 PCI-E Root Port (rev 01) \-04:00.0 RAID bus controller: LSI Logic / Symbios Logic MegaRAID SAS 1078 (rev 04) In both nodes, the LSI RAID controller hangs off a CalIOC2 device, but on the secondary nodes, the BIOS hides the VGA device and substitutes the device tree ending with the disk controller. It would seem that Calgary devices don't necessarily appear at the top of the PCI tree, which means that the current code to find the Calgary IOMMU that goes with a particular device is buggy. Rather than walk all the way to the top of the PCI device tree and try to match bus number with Calgary descriptor, the code needs to examine each parent of the particular device; if it encounters a Calgary with a matching bus number, simply use that. Otherwise, we BUG() when the bus number of the Calgary doesn't match the bus number of whatever's at the top of the device tree. Extra note: This patch appears to work correctly for the x3950 that came before the x3950 M2. Signed-off-by: Darrick J. Wong Acked-by: Muli Ben-Yehuda Cc: FUJITA Tomonori Cc: Joerg Roedel Cc: Yinghai Lu Cc: Jon D. Mason Cc: Corinna Schultz Cc: LKML-Reference: <20091202230556.GG10295@tux1.beaverton.ibm.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/pci-calgary_64.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index 849a0995d97..c563e4c8ff3 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c @@ -316,13 +316,15 @@ static inline struct iommu_table *find_iommu_table(struct device *dev) pdev = to_pci_dev(dev); + /* search up the device tree for an iommu */ pbus = pdev->bus; - - /* is the device behind a bridge? Look for the root bus */ - while (pbus->parent) + do { + tbl = pci_iommu(pbus); + if (tbl && tbl->it_busno == pbus->number) + break; + tbl = NULL; pbus = pbus->parent; - - tbl = pci_iommu(pbus); + } while (pbus); BUG_ON(tbl && (tbl->it_busno != pbus->number)); From c02260277e472095ffb3ad893be5eeab9dcefde3 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 2 Dec 2009 20:49:16 +0100 Subject: [PATCH 261/298] mutex: Better control mutex adaptive spinning config Introduce CONFIG_MUTEX_SPIN_ON_OWNER so that we can centralize in a single place the conditions that determine its definition and use. Signed-off-by: Frederic Weisbecker Acked-by: Peter Zijlstra LKML-Reference: <1259783357-8542-1-git-send-regression-fweisbec@gmail.com> Signed-off-by: Ingo Molnar Cc: Peter Zijlstra --- kernel/Kconfig.locks | 3 +++ kernel/mutex.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/kernel/Kconfig.locks b/kernel/Kconfig.locks index d1f86db7145..88c92fb4461 100644 --- a/kernel/Kconfig.locks +++ b/kernel/Kconfig.locks @@ -197,3 +197,6 @@ config INLINE_WRITE_UNLOCK_IRQ config INLINE_WRITE_UNLOCK_IRQRESTORE def_bool !DEBUG_SPINLOCK && ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE + +config MUTEX_SPIN_ON_OWNER + def_bool SMP && !DEBUG_MUTEXES && !HAVE_DEFAULT_NO_SPIN_MUTEXES diff --git a/kernel/mutex.c b/kernel/mutex.c index 947b3ad551f..632f04c57d8 100644 --- a/kernel/mutex.c +++ b/kernel/mutex.c @@ -148,8 +148,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, preempt_disable(); mutex_acquire(&lock->dep_map, subclass, 0, ip); -#if defined(CONFIG_SMP) && !defined(CONFIG_DEBUG_MUTEXES) && \ - !defined(CONFIG_HAVE_DEFAULT_NO_SPIN_MUTEXES) + +#ifdef CONFIG_MUTEX_SPIN_ON_OWNER /* * Optimistic spinning. * From c08f782985eed9959438368e84ce1d7f2ed03d95 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 2 Dec 2009 20:49:17 +0100 Subject: [PATCH 262/298] mutex: Fix missing conditions to build mutex_spin_on_owner() We don't need to build mutex_spin_on_owner() if we have CONFIG_DEBUG_MUTEXES or CONFIG_HAVE_DEFAULT_NO_SPIN_MUTEXES as it won't be used under such configs. Use CONFIG_MUTEX_SPIN_ON_OWNER as it gathers all the necessary checks before building it. Signed-off-by: Frederic Weisbecker Acked-by: Peter Zijlstra LKML-Reference: <1259783357-8542-2-git-send-regression-fweisbec@gmail.com> Signed-off-by: Ingo Molnar Cc: Peter Zijlstra --- kernel/sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched.c b/kernel/sched.c index 3c11ae0a948..ec0af1fcb19 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -5481,7 +5481,7 @@ need_resched_nonpreemptible: } EXPORT_SYMBOL(schedule); -#ifdef CONFIG_SMP +#ifdef CONFIG_MUTEX_SPIN_ON_OWNER /* * Look out! "owner" is an entirely speculative pointer * access and not reliable. From 7e71c55ee73988d0cb61045660b899eaac23bf8f Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 22 Sep 2009 10:56:16 +0100 Subject: [PATCH 263/298] GFS2: Fix potential race in glock code We need to be careful of the ordering between clearing the GLF_LOCK bit and scheduling the workqueue. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 8b674b1f3a5..a3f90ad2af8 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -672,12 +672,17 @@ out: return; out_sched: + clear_bit(GLF_LOCK, &gl->gl_flags); + smp_mb__after_clear_bit(); gfs2_glock_hold(gl); if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) gfs2_glock_put_nolock(gl); + return; + out_unlock: clear_bit(GLF_LOCK, &gl->gl_flags); - goto out; + smp_mb__after_clear_bit(); + return; } static void delete_work_func(struct work_struct *work) @@ -1375,10 +1380,11 @@ static int gfs2_shrink_glock_memory(int nr, gfp_t gfp_mask) handle_callback(gl, LM_ST_UNLOCKED, 0); nr--; } + clear_bit(GLF_LOCK, &gl->gl_flags); + smp_mb__after_clear_bit(); if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) gfs2_glock_put_nolock(gl); spin_unlock(&gl->gl_spin); - clear_bit(GLF_LOCK, &gl->gl_flags); spin_lock(&lru_lock); continue; } From f55073ff1eaf99f6b3bc62134a456638bca043a3 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 28 Sep 2009 10:30:49 +0100 Subject: [PATCH 264/298] GFS2: Fix -o meta mounts for subsequent mounts (i.e. all but the first one) We have a long term plan to use the "-o meta" flag to GFS2 mounts to access the alternate root which is used to store metadata for a GFS2 filesystem. This will allow us to eventually remove support for the gfs2meta filesystem type (which is in any case just a "front end" to the gfs2 filesystem type with the meta/master root). Currently the "-o meta" option is only taken into account on the initial mount of the filesystem. Subsequent mounts of the same filesystem (i.e. on the same device) result in basically the same as bind mounting the root of the original mount. This patch changes that by using what is more or less a copy of get_sb_bdev() and extending it so that it will take into account the alternate root in all cases. The main difference is that we have to parse the mount options a bit earlier. We can then use them to select the appropriate root towards the end of the function. In addition this also fixes a bug where it was possible (but certainly not desirable) to set different ro/rw options for the meta root when mounted via the gfs2meta fs compared with the original mount. Signed-off-by: Steven Whitehouse Cc: Alexander Viro --- fs/gfs2/ops_fstype.c | 135 +++++++++++++++++++++++++++++++++++++------ fs/gfs2/super.c | 16 ++--- fs/gfs2/super.h | 2 +- 3 files changed, 127 insertions(+), 26 deletions(-) diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 52fb6c04898..e5ee06231ae 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -1114,7 +1114,7 @@ void gfs2_online_uevent(struct gfs2_sbd *sdp) * Returns: errno */ -static int fill_super(struct super_block *sb, void *data, int silent) +static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent) { struct gfs2_sbd *sdp; struct gfs2_holder mount_gh; @@ -1125,17 +1125,7 @@ static int fill_super(struct super_block *sb, void *data, int silent) printk(KERN_WARNING "GFS2: can't alloc struct gfs2_sbd\n"); return -ENOMEM; } - - sdp->sd_args.ar_quota = GFS2_QUOTA_DEFAULT; - sdp->sd_args.ar_data = GFS2_DATA_DEFAULT; - sdp->sd_args.ar_commit = 60; - sdp->sd_args.ar_errors = GFS2_ERRORS_DEFAULT; - - error = gfs2_mount_args(sdp, &sdp->sd_args, data); - if (error) { - printk(KERN_WARNING "GFS2: can't parse mount arguments\n"); - goto fail; - } + sdp->sd_args = *args; if (sdp->sd_args.ar_spectator) { sb->s_flags |= MS_RDONLY; @@ -1243,18 +1233,125 @@ fail: return error; } -static int gfs2_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, struct vfsmount *mnt) +static int set_gfs2_super(struct super_block *s, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, fill_super, mnt); + s->s_bdev = data; + s->s_dev = s->s_bdev->bd_dev; + + /* + * We set the bdi here to the queue backing, file systems can + * overwrite this in ->fill_super() + */ + s->s_bdi = &bdev_get_queue(s->s_bdev)->backing_dev_info; + return 0; } -static int test_meta_super(struct super_block *s, void *ptr) +static int test_gfs2_super(struct super_block *s, void *ptr) { struct block_device *bdev = ptr; return (bdev == s->s_bdev); } +/** + * gfs2_get_sb - Get the GFS2 superblock + * @fs_type: The GFS2 filesystem type + * @flags: Mount flags + * @dev_name: The name of the device + * @data: The mount arguments + * @mnt: The vfsmnt for this mount + * + * Q. Why not use get_sb_bdev() ? + * A. We need to select one of two root directories to mount, independent + * of whether this is the initial, or subsequent, mount of this sb + * + * Returns: 0 or -ve on error + */ + +static int gfs2_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, struct vfsmount *mnt) +{ + struct block_device *bdev; + struct super_block *s; + fmode_t mode = FMODE_READ; + int error; + struct gfs2_args args; + struct gfs2_sbd *sdp; + + if (!(flags & MS_RDONLY)) + mode |= FMODE_WRITE; + + bdev = open_bdev_exclusive(dev_name, mode, fs_type); + if (IS_ERR(bdev)) + return PTR_ERR(bdev); + + /* + * once the super is inserted into the list by sget, s_umount + * will protect the lockfs code from trying to start a snapshot + * while we are mounting + */ + mutex_lock(&bdev->bd_fsfreeze_mutex); + if (bdev->bd_fsfreeze_count > 0) { + mutex_unlock(&bdev->bd_fsfreeze_mutex); + error = -EBUSY; + goto error_bdev; + } + s = sget(fs_type, test_gfs2_super, set_gfs2_super, bdev); + mutex_unlock(&bdev->bd_fsfreeze_mutex); + error = PTR_ERR(s); + if (IS_ERR(s)) + goto error_bdev; + + memset(&args, 0, sizeof(args)); + args.ar_quota = GFS2_QUOTA_DEFAULT; + args.ar_data = GFS2_DATA_DEFAULT; + args.ar_commit = 60; + args.ar_errors = GFS2_ERRORS_DEFAULT; + + error = gfs2_mount_args(&args, data); + if (error) { + printk(KERN_WARNING "GFS2: can't parse mount arguments\n"); + if (s->s_root) + goto error_super; + deactivate_locked_super(s); + return error; + } + + if (s->s_root) { + error = -EBUSY; + if ((flags ^ s->s_flags) & MS_RDONLY) + goto error_super; + close_bdev_exclusive(bdev, mode); + } else { + char b[BDEVNAME_SIZE]; + + s->s_flags = flags; + s->s_mode = mode; + strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id)); + sb_set_blocksize(s, block_size(bdev)); + error = fill_super(s, &args, flags & MS_SILENT ? 1 : 0); + if (error) { + deactivate_locked_super(s); + return error; + } + s->s_flags |= MS_ACTIVE; + bdev->bd_super = s; + } + + sdp = s->s_fs_info; + mnt->mnt_sb = s; + if (args.ar_meta) + mnt->mnt_root = dget(sdp->sd_master_dir); + else + mnt->mnt_root = dget(sdp->sd_root_dir); + return 0; + +error_super: + deactivate_locked_super(s); +error_bdev: + close_bdev_exclusive(bdev, mode); + return error; +} + static int set_meta_super(struct super_block *s, void *ptr) { return -EINVAL; @@ -1274,13 +1371,17 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags, dev_name, error); return error; } - s = sget(&gfs2_fs_type, test_meta_super, set_meta_super, + s = sget(&gfs2_fs_type, test_gfs2_super, set_meta_super, path.dentry->d_inode->i_sb->s_bdev); path_put(&path); if (IS_ERR(s)) { printk(KERN_WARNING "GFS2: gfs2 mount does not exist\n"); return PTR_ERR(s); } + if ((flags ^ s->s_flags) & MS_RDONLY) { + deactivate_locked_super(s); + return -EBUSY; + } sdp = s->s_fs_info; mnt->mnt_sb = s; mnt->mnt_root = dget(sdp->sd_master_dir); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 0ec3ec672de..42e5458703f 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -106,13 +106,13 @@ static const match_table_t tokens = { /** * gfs2_mount_args - Parse mount options - * @sdp: - * @data: + * @args: The structure into which the parsed options will be written + * @options: The options to parse * * Return: errno */ -int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options) +int gfs2_mount_args(struct gfs2_args *args, char *options) { char *o; int token; @@ -157,7 +157,7 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options) break; case Opt_debug: if (args->ar_errors == GFS2_ERRORS_PANIC) { - fs_info(sdp, "-o debug and -o errors=panic " + printk(KERN_WARNING "GFS2: -o debug and -o errors=panic " "are mutually exclusive.\n"); return -EINVAL; } @@ -210,7 +210,7 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options) case Opt_commit: rv = match_int(&tmp[0], &args->ar_commit); if (rv || args->ar_commit <= 0) { - fs_info(sdp, "commit mount option requires a positive numeric argument\n"); + printk(KERN_WARNING "GFS2: commit mount option requires a positive numeric argument\n"); return rv ? rv : -EINVAL; } break; @@ -219,7 +219,7 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options) break; case Opt_err_panic: if (args->ar_debug) { - fs_info(sdp, "-o debug and -o errors=panic " + printk(KERN_WARNING "GFS2: -o debug and -o errors=panic " "are mutually exclusive.\n"); return -EINVAL; } @@ -227,7 +227,7 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options) break; case Opt_error: default: - fs_info(sdp, "invalid mount option: %s\n", o); + printk(KERN_WARNING "GFS2: invalid mount option: %s\n", o); return -EINVAL; } } @@ -1062,7 +1062,7 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) spin_lock(>->gt_spin); args.ar_commit = gt->gt_log_flush_secs; spin_unlock(>->gt_spin); - error = gfs2_mount_args(sdp, &args, data); + error = gfs2_mount_args(&args, data); if (error) return error; diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index 235db368288..ed962ea68c3 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h @@ -27,7 +27,7 @@ static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp) extern void gfs2_jindex_free(struct gfs2_sbd *sdp); -extern int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *data); +extern int gfs2_mount_args(struct gfs2_args *args, char *data); extern struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid); extern int gfs2_jdesc_check(struct gfs2_jdesc *jd); From 2646a1f61a3b5525914757f10fa12b5b94713648 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 2 Oct 2009 11:50:54 +0100 Subject: [PATCH 265/298] GFS2: Fix up system xattrs This code has been shamelessly stolen from XFS at the suggestion of Christoph Hellwig. I've not added support for cached ACLs so far... watch for that in a later patch, although this is designed in such a way that they should be easy to add. Signed-off-by: Steven Whitehouse Cc: Christoph Hellwig --- fs/gfs2/acl.c | 170 ++++++++++++++++++++++++++++++++---------------- fs/gfs2/acl.h | 24 ++----- fs/gfs2/xattr.c | 18 ----- 3 files changed, 120 insertions(+), 92 deletions(-) diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 3fc4e3ac7d8..2168da12164 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -26,61 +27,6 @@ #include "trans.h" #include "util.h" -#define ACL_ACCESS 1 -#define ACL_DEFAULT 0 - -int gfs2_acl_validate_set(struct gfs2_inode *ip, int access, - struct gfs2_ea_request *er, int *remove, mode_t *mode) -{ - struct posix_acl *acl; - int error; - - error = gfs2_acl_validate_remove(ip, access); - if (error) - return error; - - if (!er->er_data) - return -EINVAL; - - acl = posix_acl_from_xattr(er->er_data, er->er_data_len); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (!acl) { - *remove = 1; - return 0; - } - - error = posix_acl_valid(acl); - if (error) - goto out; - - if (access) { - error = posix_acl_equiv_mode(acl, mode); - if (!error) - *remove = 1; - else if (error > 0) - error = 0; - } - -out: - posix_acl_release(acl); - return error; -} - -int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access) -{ - if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl) - return -EOPNOTSUPP; - if (!is_owner_or_cap(&ip->i_inode)) - return -EPERM; - if (S_ISLNK(ip->i_inode.i_mode)) - return -EOPNOTSUPP; - if (!access && !S_ISDIR(ip->i_inode.i_mode)) - return -EACCES; - - return 0; -} - static int acl_get(struct gfs2_inode *ip, const char *name, struct posix_acl **acl, struct gfs2_ea_location *el, char **datap, unsigned int *lenp) @@ -277,3 +223,117 @@ out_brelse: return error; } +static int gfs2_acl_type(const char *name) +{ + if (strcmp(name, GFS2_POSIX_ACL_ACCESS) == 0) + return ACL_TYPE_ACCESS; + if (strcmp(name, GFS2_POSIX_ACL_DEFAULT) == 0) + return ACL_TYPE_DEFAULT; + return -EINVAL; +} + +static int gfs2_xattr_system_get(struct inode *inode, const char *name, + void *buffer, size_t size) +{ + int type; + + type = gfs2_acl_type(name); + if (type < 0) + return type; + + return gfs2_xattr_get(inode, GFS2_EATYPE_SYS, name, buffer, size); +} + +static int gfs2_set_mode(struct inode *inode, mode_t mode) +{ + int error = 0; + + if (mode != inode->i_mode) { + struct iattr iattr; + + iattr.ia_valid = ATTR_MODE; + iattr.ia_mode = mode; + + error = gfs2_setattr_simple(GFS2_I(inode), &iattr); + } + + return error; +} + +static int gfs2_xattr_system_set(struct inode *inode, const char *name, + const void *value, size_t size, int flags) +{ + struct gfs2_sbd *sdp = GFS2_SB(inode); + struct posix_acl *acl = NULL; + int error = 0, type; + + if (!sdp->sd_args.ar_posix_acl) + return -EOPNOTSUPP; + + type = gfs2_acl_type(name); + if (type < 0) + return type; + if (flags & XATTR_CREATE) + return -EINVAL; + if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) + return value ? -EACCES : 0; + if ((current_fsuid() != inode->i_uid) && !capable(CAP_FOWNER)) + return -EPERM; + if (S_ISLNK(inode->i_mode)) + return -EOPNOTSUPP; + + if (!value) + goto set_acl; + + acl = posix_acl_from_xattr(value, size); + if (!acl) { + /* + * acl_set_file(3) may request that we set default ACLs with + * zero length -- defend (gracefully) against that here. + */ + goto out; + } + if (IS_ERR(acl)) { + error = PTR_ERR(acl); + goto out; + } + + error = posix_acl_valid(acl); + if (error) + goto out_release; + + error = -EINVAL; + if (acl->a_count > GFS2_ACL_MAX_ENTRIES) + goto out_release; + + if (type == ACL_TYPE_ACCESS) { + mode_t mode = inode->i_mode; + error = posix_acl_equiv_mode(acl, &mode); + + if (error <= 0) { + posix_acl_release(acl); + acl = NULL; + + if (error < 0) + return error; + } + + error = gfs2_set_mode(inode, mode); + if (error) + goto out_release; + } + +set_acl: + error = gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, value, size, 0); +out_release: + posix_acl_release(acl); +out: + return error; +} + +struct xattr_handler gfs2_xattr_system_handler = { + .prefix = XATTR_SYSTEM_PREFIX, + .get = gfs2_xattr_system_get, + .set = gfs2_xattr_system_set, +}; + diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h index 6751930bfb6..cc954390b6d 100644 --- a/fs/gfs2/acl.h +++ b/fs/gfs2/acl.h @@ -13,26 +13,12 @@ #include "incore.h" #define GFS2_POSIX_ACL_ACCESS "posix_acl_access" -#define GFS2_POSIX_ACL_ACCESS_LEN 16 #define GFS2_POSIX_ACL_DEFAULT "posix_acl_default" -#define GFS2_POSIX_ACL_DEFAULT_LEN 17 +#define GFS2_ACL_MAX_ENTRIES 25 -#define GFS2_ACL_IS_ACCESS(name, len) \ - ((len) == GFS2_POSIX_ACL_ACCESS_LEN && \ - !memcmp(GFS2_POSIX_ACL_ACCESS, (name), (len))) - -#define GFS2_ACL_IS_DEFAULT(name, len) \ - ((len) == GFS2_POSIX_ACL_DEFAULT_LEN && \ - !memcmp(GFS2_POSIX_ACL_DEFAULT, (name), (len))) - -struct gfs2_ea_request; - -int gfs2_acl_validate_set(struct gfs2_inode *ip, int access, - struct gfs2_ea_request *er, - int *remove, mode_t *mode); -int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access); -int gfs2_check_acl(struct inode *inode, int mask); -int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip); -int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr); +extern int gfs2_check_acl(struct inode *inode, int mask); +extern int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip); +extern int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr); +extern struct xattr_handler gfs2_xattr_system_handler; #endif /* __ACL_DOT_H__ */ diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c index 8a0f8ef6ee2..6b803540951 100644 --- a/fs/gfs2/xattr.c +++ b/fs/gfs2/xattr.c @@ -1507,18 +1507,6 @@ static int gfs2_xattr_user_set(struct inode *inode, const char *name, return gfs2_xattr_set(inode, GFS2_EATYPE_USR, name, value, size, flags); } -static int gfs2_xattr_system_get(struct inode *inode, const char *name, - void *buffer, size_t size) -{ - return gfs2_xattr_get(inode, GFS2_EATYPE_SYS, name, buffer, size); -} - -static int gfs2_xattr_system_set(struct inode *inode, const char *name, - const void *value, size_t size, int flags) -{ - return gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, value, size, flags); -} - static int gfs2_xattr_security_get(struct inode *inode, const char *name, void *buffer, size_t size) { @@ -1543,12 +1531,6 @@ static struct xattr_handler gfs2_xattr_security_handler = { .set = gfs2_xattr_security_set, }; -static struct xattr_handler gfs2_xattr_system_handler = { - .prefix = XATTR_SYSTEM_PREFIX, - .get = gfs2_xattr_system_get, - .set = gfs2_xattr_system_set, -}; - struct xattr_handler *gfs2_xattr_handlers[] = { &gfs2_xattr_user_handler, &gfs2_xattr_security_handler, From 796bd9524731850967d437b7f47a86acc776ea89 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 29 Sep 2009 12:27:23 +0100 Subject: [PATCH 266/298] VFS: Add forget_all_cached_acls() This is required for cluster filesystems which want to use cached ACLs so that they can invalidate the cache when required. Signed-off-by: Steven Whitehouse Cc: Alexander Viro Cc: Christoph Hellwig --- include/linux/posix_acl.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h index 065a3652a3e..67608161df6 100644 --- a/include/linux/posix_acl.h +++ b/include/linux/posix_acl.h @@ -147,6 +147,20 @@ static inline void forget_cached_acl(struct inode *inode, int type) if (old != ACL_NOT_CACHED) posix_acl_release(old); } + +static inline void forget_all_cached_acls(struct inode *inode) +{ + struct posix_acl *old_access, *old_default; + spin_lock(&inode->i_lock); + old_access = inode->i_acl; + old_default = inode->i_default_acl; + inode->i_acl = inode->i_default_acl = ACL_NOT_CACHED; + spin_unlock(&inode->i_lock); + if (old_access != ACL_NOT_CACHED) + posix_acl_release(old_access); + if (old_default != ACL_NOT_CACHED) + posix_acl_release(old_default); +} #endif static inline void cache_no_acl(struct inode *inode) From c65f7fb5342ecb8cb85e9b676327b3a43a5a4735 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 2 Oct 2009 11:54:39 +0100 Subject: [PATCH 267/298] GFS2: Use forget_all_cached_acls() Invalidate all the cached ACLs when we drop the glock. Signed-off-by: Steven Whitehouse --- fs/gfs2/glops.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 6985eef06c3..78554acc060 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "gfs2.h" #include "incore.h" @@ -184,8 +185,10 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags) if (flags & DIO_METADATA) { struct address_space *mapping = gl->gl_aspace->i_mapping; truncate_inode_pages(mapping, 0); - if (ip) + if (ip) { set_bit(GIF_INVALID, &ip->i_flags); + forget_all_cached_acls(&ip->i_inode); + } } if (ip == GFS2_I(gl->gl_sbd->sd_rindex)) From 69dca42464962d8d0989b7e09877ba644c9cba66 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 29 Sep 2009 12:40:19 +0100 Subject: [PATCH 268/298] GFS2: Use gfs2_set_mode() instead of munge_mode() These two functions do the same thing, so lets only use one of them. Signed-off-by: Steven Whitehouse --- fs/gfs2/acl.c | 46 +++++++++++----------------------------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 2168da12164..1be314837d3 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -104,29 +104,20 @@ int gfs2_check_acl(struct inode *inode, int mask) return -EAGAIN; } -static int munge_mode(struct gfs2_inode *ip, mode_t mode) +static int gfs2_set_mode(struct inode *inode, mode_t mode) { - struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - struct buffer_head *dibh; - int error; + int error = 0; - error = gfs2_trans_begin(sdp, RES_DINODE, 0); - if (error) - return error; + if (mode != inode->i_mode) { + struct iattr iattr; - error = gfs2_meta_inode_buffer(ip, &dibh); - if (!error) { - gfs2_assert_withdraw(sdp, - (ip->i_inode.i_mode & S_IFMT) == (mode & S_IFMT)); - ip->i_inode.i_mode = mode; - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - gfs2_dinode_out(ip, dibh->b_data); - brelse(dibh); + iattr.ia_valid = ATTR_MODE; + iattr.ia_mode = mode; + + error = gfs2_setattr_simple(GFS2_I(inode), &iattr); } - gfs2_trans_end(sdp); - - return 0; + return error; } int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) @@ -151,7 +142,7 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) if (!acl) { mode &= ~current_umask(); if (mode != ip->i_inode.i_mode) - error = munge_mode(ip, mode); + error = gfs2_set_mode(&ip->i_inode, mode); return error; } @@ -181,7 +172,7 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) if (error) goto out; munge: - error = munge_mode(ip, mode); + error = gfs2_set_mode(&ip->i_inode, mode); out: posix_acl_release(acl); kfree(data); @@ -244,21 +235,6 @@ static int gfs2_xattr_system_get(struct inode *inode, const char *name, return gfs2_xattr_get(inode, GFS2_EATYPE_SYS, name, buffer, size); } -static int gfs2_set_mode(struct inode *inode, mode_t mode) -{ - int error = 0; - - if (mode != inode->i_mode) { - struct iattr iattr; - - iattr.ia_valid = ATTR_MODE; - iattr.ia_mode = mode; - - error = gfs2_setattr_simple(GFS2_I(inode), &iattr); - } - - return error; -} static int gfs2_xattr_system_set(struct inode *inode, const char *name, const void *value, size_t size, int flags) From 479c427dd60fe1aadbbf2e6cbf2f84942baeb210 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 2 Oct 2009 12:00:00 +0100 Subject: [PATCH 269/298] GFS2: Clean up ACLs To prepare for support for caching of ACLs, this cleans up the GFS2 ACL support by pushing the xattr code back into xattr.c and changing the acl_get function into one which only returns ACLs so that we can drop the caching function into it shortly. Signed-off-by: Steven Whitehouse --- fs/gfs2/acl.c | 164 ++++++++++++++++++++++++------------------------ fs/gfs2/acl.h | 2 +- fs/gfs2/inode.c | 2 +- fs/gfs2/xattr.c | 56 +++++++++++++---- fs/gfs2/xattr.h | 8 +-- 5 files changed, 132 insertions(+), 100 deletions(-) diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 1be314837d3..bd0fce964c4 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -27,53 +27,40 @@ #include "trans.h" #include "util.h" -static int acl_get(struct gfs2_inode *ip, const char *name, - struct posix_acl **acl, struct gfs2_ea_location *el, - char **datap, unsigned int *lenp) +static const char *gfs2_acl_name(int type) { - char *data; - unsigned int len; - int error; + switch (type) { + case ACL_TYPE_ACCESS: + return GFS2_POSIX_ACL_ACCESS; + case ACL_TYPE_DEFAULT: + return GFS2_POSIX_ACL_DEFAULT; + } + return NULL; +} - el->el_bh = NULL; +static struct posix_acl *gfs2_acl_get(struct gfs2_inode *ip, int type) +{ + struct posix_acl *acl; + const char *name; + char *data; + int len; if (!ip->i_eattr) - return 0; + return NULL; - error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, name, el); - if (error) - return error; - if (!el->el_ea) - return 0; - if (!GFS2_EA_DATA_LEN(el->el_ea)) - goto out; + name = gfs2_acl_name(type); + if (name == NULL) + return ERR_PTR(-EINVAL); - len = GFS2_EA_DATA_LEN(el->el_ea); - data = kmalloc(len, GFP_NOFS); - error = -ENOMEM; - if (!data) - goto out; + len = gfs2_xattr_acl_get(ip, name, &data); + if (len < 0) + return ERR_PTR(len); + if (len == 0) + return NULL; - error = gfs2_ea_get_copy(ip, el, data, len); - if (error < 0) - goto out_kfree; - error = 0; - - if (acl) { - *acl = posix_acl_from_xattr(data, len); - if (IS_ERR(*acl)) - error = PTR_ERR(*acl); - } - -out_kfree: - if (error || !datap) { - kfree(data); - } else { - *datap = data; - *lenp = len; - } -out: - return error; + acl = posix_acl_from_xattr(data, len); + kfree(data); + return acl; } /** @@ -86,14 +73,12 @@ out: int gfs2_check_acl(struct inode *inode, int mask) { - struct gfs2_ea_location el; - struct posix_acl *acl = NULL; + struct posix_acl *acl; int error; - error = acl_get(GFS2_I(inode), GFS2_POSIX_ACL_ACCESS, &acl, &el, NULL, NULL); - brelse(el.el_bh); - if (error) - return error; + acl = gfs2_acl_get(GFS2_I(inode), ACL_TYPE_ACCESS); + if (IS_ERR(acl)) + return PTR_ERR(acl); if (acl) { error = posix_acl_permission(inode, acl, mask); @@ -120,32 +105,57 @@ static int gfs2_set_mode(struct inode *inode, mode_t mode) return error; } -int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) +static int gfs2_acl_set(struct inode *inode, int type, struct posix_acl *acl) { - struct gfs2_ea_location el; - struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - struct posix_acl *acl = NULL, *clone; - mode_t mode = ip->i_inode.i_mode; - char *data = NULL; - unsigned int len; int error; + int len; + char *data; + const char *name = gfs2_acl_name(type); + + BUG_ON(name == NULL); + len = posix_acl_to_xattr(acl, NULL, 0); + if (len == 0) + return 0; + data = kmalloc(len, GFP_NOFS); + if (data == NULL) + return -ENOMEM; + error = posix_acl_to_xattr(acl, data, len); + if (error < 0) + goto out; + error = gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, data, len, 0); +out: + kfree(data); + return error; +} + +int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode) +{ + struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); + struct posix_acl *acl, *clone; + mode_t mode = inode->i_mode; + int error = 0; if (!sdp->sd_args.ar_posix_acl) return 0; - if (S_ISLNK(ip->i_inode.i_mode)) + if (S_ISLNK(inode->i_mode)) return 0; - error = acl_get(dip, GFS2_POSIX_ACL_DEFAULT, &acl, &el, &data, &len); - brelse(el.el_bh); - if (error) - return error; + acl = gfs2_acl_get(dip, ACL_TYPE_DEFAULT); + if (IS_ERR(acl)) + return PTR_ERR(acl); if (!acl) { mode &= ~current_umask(); - if (mode != ip->i_inode.i_mode) - error = gfs2_set_mode(&ip->i_inode, mode); + if (mode != inode->i_mode) + error = gfs2_set_mode(inode, mode); return error; } + if (S_ISDIR(inode->i_mode)) { + error = gfs2_acl_set(inode, ACL_TYPE_DEFAULT, acl); + if (error) + goto out; + } + clone = posix_acl_clone(acl, GFP_NOFS); error = -ENOMEM; if (!clone) @@ -153,43 +163,32 @@ int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip) posix_acl_release(acl); acl = clone; - if (S_ISDIR(ip->i_inode.i_mode)) { - error = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SYS, - GFS2_POSIX_ACL_DEFAULT, data, len, 0); - if (error) - goto out; - } - error = posix_acl_create_masq(acl, &mode); if (error < 0) goto out; if (error == 0) goto munge; - posix_acl_to_xattr(acl, data, len); - error = gfs2_xattr_set(&ip->i_inode, GFS2_EATYPE_SYS, - GFS2_POSIX_ACL_ACCESS, data, len, 0); + error = gfs2_acl_set(inode, ACL_TYPE_ACCESS, acl); if (error) goto out; munge: - error = gfs2_set_mode(&ip->i_inode, mode); + error = gfs2_set_mode(inode, mode); out: posix_acl_release(acl); - kfree(data); return error; } int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) { - struct posix_acl *acl = NULL, *clone; - struct gfs2_ea_location el; + struct posix_acl *acl, *clone; char *data; unsigned int len; int error; - error = acl_get(ip, GFS2_POSIX_ACL_ACCESS, &acl, &el, &data, &len); - if (error) - goto out_brelse; + acl = gfs2_acl_get(ip, ACL_TYPE_ACCESS); + if (IS_ERR(acl)) + return PTR_ERR(acl); if (!acl) return gfs2_setattr_simple(ip, attr); @@ -202,15 +201,18 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) error = posix_acl_chmod_masq(acl, attr->ia_mode); if (!error) { + len = posix_acl_to_xattr(acl, NULL, 0); + data = kmalloc(len, GFP_NOFS); + error = -ENOMEM; + if (data == NULL) + goto out; posix_acl_to_xattr(acl, data, len); - error = gfs2_ea_acl_chmod(ip, &el, attr, data); + error = gfs2_xattr_acl_chmod(ip, attr, data); + kfree(data); } out: posix_acl_release(acl); - kfree(data); -out_brelse: - brelse(el.el_bh); return error; } diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h index cc954390b6d..9306a2e6620 100644 --- a/fs/gfs2/acl.h +++ b/fs/gfs2/acl.h @@ -17,7 +17,7 @@ #define GFS2_ACL_MAX_ENTRIES 25 extern int gfs2_check_acl(struct inode *inode, int mask); -extern int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip); +extern int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode); extern int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr); extern struct xattr_handler gfs2_xattr_system_handler; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index fb15d3b1f40..6380cd9314b 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -871,7 +871,7 @@ struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, if (error) goto fail_gunlock2; - error = gfs2_acl_create(dip, GFS2_I(inode)); + error = gfs2_acl_create(dip, inode); if (error) goto fail_gunlock2; diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c index 6b803540951..912f5cbc474 100644 --- a/fs/gfs2/xattr.c +++ b/fs/gfs2/xattr.c @@ -186,8 +186,8 @@ static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh, return 0; } -int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name, - struct gfs2_ea_location *el) +static int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name, + struct gfs2_ea_location *el) { struct ea_find ef; int error; @@ -516,8 +516,8 @@ out: return error; } -int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, - char *data, size_t size) +static int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, + char *data, size_t size) { int ret; size_t len = GFS2_EA_DATA_LEN(el->el_ea); @@ -534,6 +534,36 @@ int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, return len; } +int gfs2_xattr_acl_get(struct gfs2_inode *ip, const char *name, char **ppdata) +{ + struct gfs2_ea_location el; + int error; + int len; + char *data; + + error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, name, &el); + if (error) + return error; + if (!el.el_ea) + goto out; + if (!GFS2_EA_DATA_LEN(el.el_ea)) + goto out; + + len = GFS2_EA_DATA_LEN(el.el_ea); + data = kmalloc(len, GFP_NOFS); + error = -ENOMEM; + if (data == NULL) + goto out; + + error = gfs2_ea_get_copy(ip, &el, data, len); + if (error == 0) + error = len; + *ppdata = data; +out: + brelse(el.el_bh); + return error; +} + /** * gfs2_xattr_get - Get a GFS2 extended attribute * @inode: The inode @@ -1259,22 +1289,26 @@ fail: return error; } -int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, - struct iattr *attr, char *data) +int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data) { + struct gfs2_ea_location el; struct buffer_head *dibh; int error; - if (GFS2_EA_IS_STUFFED(el->el_ea)) { + error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, GFS2_POSIX_ACL_ACCESS, &el); + if (error) + return error; + + if (GFS2_EA_IS_STUFFED(el.el_ea)) { error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0); if (error) return error; - gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1); - memcpy(GFS2_EA2DATA(el->el_ea), data, - GFS2_EA_DATA_LEN(el->el_ea)); + gfs2_trans_add_bh(ip->i_gl, el.el_bh, 1); + memcpy(GFS2_EA2DATA(el.el_ea), data, + GFS2_EA_DATA_LEN(el.el_ea)); } else - error = ea_acl_chmod_unstuffed(ip, el->el_ea, data); + error = ea_acl_chmod_unstuffed(ip, el.el_ea, data); if (error) return error; diff --git a/fs/gfs2/xattr.h b/fs/gfs2/xattr.h index cbdfd774373..8d6ae5813c4 100644 --- a/fs/gfs2/xattr.h +++ b/fs/gfs2/xattr.h @@ -62,11 +62,7 @@ extern int gfs2_ea_dealloc(struct gfs2_inode *ip); /* Exported to acl.c */ -extern int gfs2_ea_find(struct gfs2_inode *ip, int type, const char *name, - struct gfs2_ea_location *el); -extern int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el, - char *data, size_t size); -extern int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, - struct iattr *attr, char *data); +extern int gfs2_xattr_acl_get(struct gfs2_inode *ip, const char *name, char **data); +extern int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data); #endif /* __EATTR_DOT_H__ */ From 106381bfba997b83b64f68f2210e154162fc38e6 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 29 Sep 2009 16:26:23 +0100 Subject: [PATCH 270/298] GFS2: Add cached ACLs support The other patches in this series have been building towards being able to support cached ACLs like other filesystems. The only real difference with GFS2 is that we have to invalidate the cache when we drop a glock, but that is dealt with in earlier patches. Signed-off-by: Steven Whitehouse --- fs/gfs2/acl.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index bd0fce964c4..3eb1ea84617 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -48,6 +48,10 @@ static struct posix_acl *gfs2_acl_get(struct gfs2_inode *ip, int type) if (!ip->i_eattr) return NULL; + acl = get_cached_acl(&ip->i_inode, type); + if (acl != ACL_NOT_CACHED) + return acl; + name = gfs2_acl_name(type); if (name == NULL) return ERR_PTR(-EINVAL); @@ -123,6 +127,8 @@ static int gfs2_acl_set(struct inode *inode, int type, struct posix_acl *acl) if (error < 0) goto out; error = gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, data, len, 0); + if (!error) + set_cached_acl(inode, type, acl); out: kfree(data); return error; @@ -209,6 +215,7 @@ int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr) posix_acl_to_xattr(acl, data, len); error = gfs2_xattr_acl_chmod(ip, attr, data); kfree(data); + set_cached_acl(&ip->i_inode, ACL_TYPE_ACCESS, acl); } out: @@ -228,15 +235,25 @@ static int gfs2_acl_type(const char *name) static int gfs2_xattr_system_get(struct inode *inode, const char *name, void *buffer, size_t size) { + struct posix_acl *acl; int type; + int error; type = gfs2_acl_type(name); if (type < 0) return type; - return gfs2_xattr_get(inode, GFS2_EATYPE_SYS, name, buffer, size); -} + acl = gfs2_acl_get(GFS2_I(inode), type); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl == NULL) + return -ENODATA; + error = posix_acl_to_xattr(acl, buffer, size); + posix_acl_release(acl); + + return error; +} static int gfs2_xattr_system_set(struct inode *inode, const char *name, const void *value, size_t size, int flags) @@ -303,6 +320,12 @@ static int gfs2_xattr_system_set(struct inode *inode, const char *name, set_acl: error = gfs2_xattr_set(inode, GFS2_EATYPE_SYS, name, value, size, 0); + if (!error) { + if (acl) + set_cached_acl(inode, type, acl); + else + forget_cached_acl(inode, type); + } out_release: posix_acl_release(acl); out: From ab201832f75f58c8f5093436363f80ffa4a4c9a8 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 29 Sep 2009 16:31:03 +0100 Subject: [PATCH 271/298] VFS: Use GFP_NOFS in posix_acl_from_xattr() GFS2 needs to call this from under a glock, so we need GFP_NOFS and I suspect that other filesystems might require this too. Signed-off-by: Steven Whitehouse --- fs/xattr_acl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xattr_acl.c b/fs/xattr_acl.c index c6ad7c7e3ee..05ac0fe9c4d 100644 --- a/fs/xattr_acl.c +++ b/fs/xattr_acl.c @@ -36,7 +36,7 @@ posix_acl_from_xattr(const void *value, size_t size) if (count == 0) return NULL; - acl = posix_acl_alloc(count, GFP_KERNEL); + acl = posix_acl_alloc(count, GFP_NOFS); if (!acl) return ERR_PTR(-ENOMEM); acl_e = acl->a_entries; From 8c42d637f6f2859e0fb28b78d5add7f0dc6d0973 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 11 Sep 2009 14:36:44 +0100 Subject: [PATCH 272/298] GFS2: Alter arguments of gfs2_quota/statfs_sync These two functions are altered so that gfs2_quota_sync may in future be called directly from the VFS. The GFS2 superblock changes to a VFS super block and there is an addition of an int argument which is currently ignored. Signed-off-by: Steven Whitehouse --- fs/gfs2/quota.c | 7 ++++--- fs/gfs2/quota.h | 2 +- fs/gfs2/super.c | 7 ++++--- fs/gfs2/super.h | 2 +- fs/gfs2/sys.c | 4 ++-- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 2e9b9326bfc..ed9e1971b2c 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -1069,8 +1069,9 @@ void gfs2_quota_change(struct gfs2_inode *ip, s64 change, } } -int gfs2_quota_sync(struct gfs2_sbd *sdp) +int gfs2_quota_sync(struct super_block *sb, int type) { + struct gfs2_sbd *sdp = sb->s_fs_info; struct gfs2_quota_data **qda; unsigned int max_qd = gfs2_tune_get(sdp, gt_quota_simul_sync); unsigned int num_qd; @@ -1298,12 +1299,12 @@ static void quotad_error(struct gfs2_sbd *sdp, const char *msg, int error) } static void quotad_check_timeo(struct gfs2_sbd *sdp, const char *msg, - int (*fxn)(struct gfs2_sbd *sdp), + int (*fxn)(struct super_block *sb, int type), unsigned long t, unsigned long *timeo, unsigned int *new_timeo) { if (t >= *timeo) { - int error = fxn(sdp); + int error = fxn(sdp->sd_vfs, 0); quotad_error(sdp, msg, error); *timeo = gfs2_tune_get_i(&sdp->sd_tune, new_timeo) * HZ; } else { diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h index 0fa5fa63d0e..437afa77663 100644 --- a/fs/gfs2/quota.h +++ b/fs/gfs2/quota.h @@ -25,7 +25,7 @@ extern int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid); extern void gfs2_quota_change(struct gfs2_inode *ip, s64 change, u32 uid, u32 gid); -extern int gfs2_quota_sync(struct gfs2_sbd *sdp); +extern int gfs2_quota_sync(struct super_block *sb, int type); extern int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id); extern int gfs2_quota_init(struct gfs2_sbd *sdp); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 42e5458703f..e7b24d59d4f 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -484,8 +484,9 @@ void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh, gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode)); } -int gfs2_statfs_sync(struct gfs2_sbd *sdp) +int gfs2_statfs_sync(struct super_block *sb, int type) { + struct gfs2_sbd *sdp = sb->s_fs_info; struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master; @@ -712,8 +713,8 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp) int error; flush_workqueue(gfs2_delete_workqueue); - gfs2_quota_sync(sdp); - gfs2_statfs_sync(sdp); + gfs2_quota_sync(sdp->sd_vfs, 0); + gfs2_statfs_sync(sdp->sd_vfs, 0); error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, GL_NOCACHE, &t_gh); diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index ed962ea68c3..3df60f2d84e 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h @@ -44,7 +44,7 @@ extern void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, const void *buf); extern void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh, struct buffer_head *l_bh); -extern int gfs2_statfs_sync(struct gfs2_sbd *sdp); +extern int gfs2_statfs_sync(struct super_block *sb, int type); extern int gfs2_freeze_fs(struct gfs2_sbd *sdp); extern void gfs2_unfreeze_fs(struct gfs2_sbd *sdp); diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 446329728d5..be1b8aca590 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -158,7 +158,7 @@ static ssize_t statfs_sync_store(struct gfs2_sbd *sdp, const char *buf, if (simple_strtol(buf, NULL, 0) != 1) return -EINVAL; - gfs2_statfs_sync(sdp); + gfs2_statfs_sync(sdp->sd_vfs, 0); return len; } @@ -171,7 +171,7 @@ static ssize_t quota_sync_store(struct gfs2_sbd *sdp, const char *buf, if (simple_strtol(buf, NULL, 0) != 1) return -EINVAL; - gfs2_quota_sync(sdp); + gfs2_quota_sync(sdp->sd_vfs, 0); return len; } From cc632e7f93465597896862cf9e50baefb1999215 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 15 Sep 2009 09:59:02 +0100 Subject: [PATCH 273/298] GFS2: Hook gfs2_quota_sync into VFS via gfs2_quotactl_ops The plan is to add further operations to the gfs2_quotactl_ops in future patches. The sync operation is easy, so we start with that one. We plan to use the XFS quota control functions because they more closely match the GFS2 ones. Signed-off-by: Steven Whitehouse --- fs/gfs2/Kconfig | 2 ++ fs/gfs2/ops_fstype.c | 3 +++ fs/gfs2/quota.c | 4 ++++ fs/gfs2/quota.h | 1 + 4 files changed, 10 insertions(+) diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig index 5971359d209..4dcddf83326 100644 --- a/fs/gfs2/Kconfig +++ b/fs/gfs2/Kconfig @@ -8,6 +8,8 @@ config GFS2_FS select FS_POSIX_ACL select CRC32 select SLOW_WORK + select QUOTA + select QUOTACTL help A cluster filesystem. diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index e5ee06231ae..36b11cba57e 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "gfs2.h" #include "incore.h" @@ -1138,6 +1139,8 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent sb->s_op = &gfs2_super_ops; sb->s_export_op = &gfs2_export_ops; sb->s_xattr = gfs2_xattr_handlers; + sb->s_qcop = &gfs2_quotactl_ops; + sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE; sb->s_time_gran = 1; sb->s_maxbytes = MAX_LFS_FILESIZE; diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index ed9e1971b2c..73a43cee0ea 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -1378,3 +1378,7 @@ int gfs2_quotad(void *data) return 0; } +const struct quotactl_ops gfs2_quotactl_ops = { + .quota_sync = gfs2_quota_sync, +}; + diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h index 437afa77663..025d15ba24c 100644 --- a/fs/gfs2/quota.h +++ b/fs/gfs2/quota.h @@ -50,5 +50,6 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip) } extern int gfs2_shrink_qd_memory(int nr, gfp_t gfp_mask); +extern const struct quotactl_ops gfs2_quotactl_ops; #endif /* __QUOTA_DOT_H__ */ From 91094d0fb650decd8bf48b85d86c892d7ca913ee Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 11 Sep 2009 15:21:56 +0100 Subject: [PATCH 274/298] GFS2: Remove obsolete code in quota.c There is no point in testing for GLF_DEMOTE here, we might as well always release the glock at that point. Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.h | 9 --------- fs/gfs2/quota.c | 13 +++++-------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index c609894ec0d..13f0bd22813 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -180,15 +180,6 @@ static inline int gfs2_glock_is_held_shrd(struct gfs2_glock *gl) return gl->gl_state == LM_ST_SHARED; } -static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl) -{ - int ret; - spin_lock(&gl->gl_spin); - ret = test_bit(GLF_DEMOTE, &gl->gl_flags); - spin_unlock(&gl->gl_spin); - return ret; -} - int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, const struct gfs2_glock_operations *glops, int create, struct gfs2_glock **glp); diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 73a43cee0ea..6aaa6c5e21b 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -843,9 +843,8 @@ restart: if (force_refresh || qd->qd_qb.qb_magic != cpu_to_be32(GFS2_MAGIC)) { loff_t pos; gfs2_glock_dq_uninit(q_gh); - error = gfs2_glock_nq_init(qd->qd_gl, - LM_ST_EXCLUSIVE, GL_NOCACHE, - q_gh); + error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_EXCLUSIVE, + GL_NOCACHE, q_gh); if (error) return error; @@ -871,11 +870,9 @@ restart: qlvb->qb_value = cpu_to_be64(q.qu_value); qd->qd_qb = *qlvb; - if (gfs2_glock_is_blocking(qd->qd_gl)) { - gfs2_glock_dq_uninit(q_gh); - force_refresh = 0; - goto restart; - } + gfs2_glock_dq_uninit(q_gh); + force_refresh = 0; + goto restart; } return 0; From 1d371b5e179d943491a5fddad211cb317f38a142 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 11 Sep 2009 15:57:27 +0100 Subject: [PATCH 275/298] GFS2: Add get_xstate quota function This allows querying of the quota state via the XFS quota API. Signed-off-by: Steven Whitehouse --- fs/gfs2/quota.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 6aaa6c5e21b..e7114be7b44 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -47,6 +47,7 @@ #include #include #include +#include #include "gfs2.h" #include "incore.h" @@ -1375,7 +1376,29 @@ int gfs2_quotad(void *data) return 0; } +static int gfs2_quota_get_xstate(struct super_block *sb, + struct fs_quota_stat *fqs) +{ + struct gfs2_sbd *sdp = sb->s_fs_info; + + memset(fqs, 0, sizeof(struct fs_quota_stat)); + fqs->qs_version = FS_QSTAT_VERSION; + if (sdp->sd_args.ar_quota == GFS2_QUOTA_ON) + fqs->qs_flags = (XFS_QUOTA_UDQ_ENFD | XFS_QUOTA_GDQ_ENFD); + else if (sdp->sd_args.ar_quota == GFS2_QUOTA_ACCOUNT) + fqs->qs_flags = (XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_GDQ_ACCT); + if (sdp->sd_quota_inode) { + fqs->qs_uquota.qfs_ino = GFS2_I(sdp->sd_quota_inode)->i_no_addr; + fqs->qs_uquota.qfs_nblks = sdp->sd_quota_inode->i_blocks; + } + fqs->qs_uquota.qfs_nextents = 1; /* unsupported */ + fqs->qs_gquota = fqs->qs_uquota; /* its the same inode in both cases */ + fqs->qs_incoredqs = atomic_read(&qd_lru_count); + return 0; +} + const struct quotactl_ops gfs2_quotactl_ops = { .quota_sync = gfs2_quota_sync, + .get_xstate = gfs2_quota_get_xstate, }; From ea7623385930c63e2a35749cff9db72094cd06ad Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 15 Sep 2009 16:20:30 +0100 Subject: [PATCH 276/298] GFS2: Add proper error reporting to quota sync via sysfs For some reason, the errors were not making it to userspace. Signed-off-by: Steven Whitehouse --- fs/gfs2/sys.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index be1b8aca590..c5dad1eb7b9 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -178,6 +178,7 @@ static ssize_t quota_sync_store(struct gfs2_sbd *sdp, const char *buf, static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf, size_t len) { + int error; u32 id; if (!capable(CAP_SYS_ADMIN)) @@ -185,13 +186,14 @@ static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf, id = simple_strtoul(buf, NULL, 0); - gfs2_quota_refresh(sdp, 1, id); - return len; + error = gfs2_quota_refresh(sdp, 1, id); + return error ? error : len; } static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf, size_t len) { + int error; u32 id; if (!capable(CAP_SYS_ADMIN)) @@ -199,8 +201,8 @@ static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf, id = simple_strtoul(buf, NULL, 0); - gfs2_quota_refresh(sdp, 0, id); - return len; + error = gfs2_quota_refresh(sdp, 0, id); + return error ? error : len; } static ssize_t demote_rq_store(struct gfs2_sbd *sdp, const char *buf, size_t len) From 33a82529e7007ed7beceebc6b3f3cddadb5b67f0 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 15 Sep 2009 16:25:40 +0100 Subject: [PATCH 277/298] GFS2: Remove constant argument from qdsb_get() The "create" argument to qdsb_get() was only ever set to true, so this patch removes that argument. Signed-off-by: Steven Whitehouse --- fs/gfs2/quota.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index e7114be7b44..f790f5af74e 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -462,12 +462,12 @@ static void qd_unlock(struct gfs2_quota_data *qd) qd_put(qd); } -static int qdsb_get(struct gfs2_sbd *sdp, int user, u32 id, int create, +static int qdsb_get(struct gfs2_sbd *sdp, int user, u32 id, struct gfs2_quota_data **qdp) { int error; - error = qd_get(sdp, user, id, create, qdp); + error = qd_get(sdp, user, id, CREATE, qdp); if (error) return error; @@ -509,20 +509,20 @@ int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid) if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF) return 0; - error = qdsb_get(sdp, QUOTA_USER, ip->i_inode.i_uid, CREATE, qd); + error = qdsb_get(sdp, QUOTA_USER, ip->i_inode.i_uid, qd); if (error) goto out; al->al_qd_num++; qd++; - error = qdsb_get(sdp, QUOTA_GROUP, ip->i_inode.i_gid, CREATE, qd); + error = qdsb_get(sdp, QUOTA_GROUP, ip->i_inode.i_gid, qd); if (error) goto out; al->al_qd_num++; qd++; if (uid != NO_QUOTA_CHANGE && uid != ip->i_inode.i_uid) { - error = qdsb_get(sdp, QUOTA_USER, uid, CREATE, qd); + error = qdsb_get(sdp, QUOTA_USER, uid, qd); if (error) goto out; al->al_qd_num++; @@ -530,7 +530,7 @@ int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid) } if (gid != NO_QUOTA_CHANGE && gid != ip->i_inode.i_gid) { - error = qdsb_get(sdp, QUOTA_GROUP, gid, CREATE, qd); + error = qdsb_get(sdp, QUOTA_GROUP, gid, qd); if (error) goto out; al->al_qd_num++; From 6a6ada81e4ffc222bf7e54ea7503c7cc98b4f0d8 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 15 Sep 2009 16:30:38 +0100 Subject: [PATCH 278/298] GFS2: Remove constant argument from qd_get() This function was only ever called with the "create" argument set to true, so we can remove it. Signed-off-by: Steven Whitehouse --- fs/gfs2/quota.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index f790f5af74e..db124af8998 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -165,7 +165,7 @@ fail: return error; } -static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, int create, +static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, struct gfs2_quota_data **qdp) { struct gfs2_quota_data *qd = NULL, *new_qd = NULL; @@ -203,7 +203,7 @@ static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, int create, spin_unlock(&qd_lru_lock); - if (qd || !create) { + if (qd) { if (new_qd) { gfs2_glock_put(new_qd->qd_gl); kmem_cache_free(gfs2_quotad_cachep, new_qd); @@ -467,7 +467,7 @@ static int qdsb_get(struct gfs2_sbd *sdp, int user, u32 id, { int error; - error = qd_get(sdp, user, id, CREATE, qdp); + error = qd_get(sdp, user, id, qdp); if (error) return error; @@ -1117,7 +1117,7 @@ int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id) struct gfs2_holder q_gh; int error; - error = qd_get(sdp, user, id, CREATE, &qd); + error = qd_get(sdp, user, id, &qd); if (error) return error; From 1e72c0f7c40e665d2ed40014750fdd2fa9968bcf Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Tue, 15 Sep 2009 20:42:56 +0100 Subject: [PATCH 279/298] GFS2: Clean up gfs2_adjust_quota() and do_glock() Both of these functions contained confusing and in one case duplicate code. This patch adds a new check in do_glock() so that we report -ENOENT if we are asked to sync a quota entry which doesn't exist. Due to the previous patch this is now reported correctly to userspace. Also there are a few new comments, and I hope that the code is easier to understand now. Signed-off-by: Steven Whitehouse --- fs/gfs2/quota.c | 82 ++++++++++++++++--------------------------------- 1 file changed, 26 insertions(+), 56 deletions(-) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index db124af8998..33e369f108b 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -15,7 +15,7 @@ * fuzziness in the current usage value of IDs that are being used on different * nodes in the cluster simultaneously. So, it is possible for a user on * multiple nodes to overrun their quota, but that overrun is controlable. - * Since quota tags are part of transactions, there is no need to a quota check + * Since quota tags are part of transactions, there is no need for a quota check * program to be run on node crashes or anything like that. * * There are couple of knobs that let the administrator manage the quota @@ -66,13 +66,6 @@ #define QUOTA_USER 1 #define QUOTA_GROUP 0 -struct gfs2_quota_host { - u64 qu_limit; - u64 qu_warn; - s64 qu_value; - u32 qu_ll_next; -}; - struct gfs2_quota_change_host { u64 qc_change; u32 qc_flags; /* GFS2_QCF_... */ @@ -618,33 +611,19 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change) mutex_unlock(&sdp->sd_quota_mutex); } -static void gfs2_quota_in(struct gfs2_quota_host *qu, const void *buf) -{ - const struct gfs2_quota *str = buf; - - qu->qu_limit = be64_to_cpu(str->qu_limit); - qu->qu_warn = be64_to_cpu(str->qu_warn); - qu->qu_value = be64_to_cpu(str->qu_value); - qu->qu_ll_next = be32_to_cpu(str->qu_ll_next); -} - -static void gfs2_quota_out(const struct gfs2_quota_host *qu, void *buf) -{ - struct gfs2_quota *str = buf; - - str->qu_limit = cpu_to_be64(qu->qu_limit); - str->qu_warn = cpu_to_be64(qu->qu_warn); - str->qu_value = cpu_to_be64(qu->qu_value); - str->qu_ll_next = cpu_to_be32(qu->qu_ll_next); - memset(&str->qu_reserved, 0, sizeof(str->qu_reserved)); -} - /** - * gfs2_adjust_quota + * gfs2_adjust_quota - adjust record of current block usage + * @ip: The quota inode + * @loc: Offset of the entry in the quota file + * @change: The amount of change to record + * @qd: The quota data * * This function was mostly borrowed from gfs2_block_truncate_page which was * in turn mostly borrowed from ext3 + * + * Returns: 0 or -ve on error */ + static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, s64 change, struct gfs2_quota_data *qd) { @@ -656,8 +635,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, struct buffer_head *bh; struct page *page; void *kaddr; - char *ptr; - struct gfs2_quota_host qp; + struct gfs2_quota *qp; s64 value; int err = -EIO; @@ -701,18 +679,13 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, gfs2_trans_add_bh(ip->i_gl, bh, 0); kaddr = kmap_atomic(page, KM_USER0); - ptr = kaddr + offset; - gfs2_quota_in(&qp, ptr); - qp.qu_value += change; - value = qp.qu_value; - gfs2_quota_out(&qp, ptr); + qp = kaddr + offset; + value = (s64)be64_to_cpu(qp->qu_value) + change; + qp->qu_value = cpu_to_be64(value); + qd->qd_qb.qb_value = qp->qu_value; flush_dcache_page(page); kunmap_atomic(kaddr, KM_USER0); err = 0; - qd->qd_qb.qb_magic = cpu_to_be32(GFS2_MAGIC); - qd->qd_qb.qb_value = cpu_to_be64(value); - ((struct gfs2_quota_lvb*)(qd->qd_gl->gl_lvb))->qb_magic = cpu_to_be32(GFS2_MAGIC); - ((struct gfs2_quota_lvb*)(qd->qd_gl->gl_lvb))->qb_value = cpu_to_be64(value); unlock: unlock_page(page); page_cache_release(page); @@ -741,8 +714,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) sort(qda, num_qd, sizeof(struct gfs2_quota_data *), sort_qd, NULL); for (qx = 0; qx < num_qd; qx++) { - error = gfs2_glock_nq_init(qda[qx]->qd_gl, - LM_ST_EXCLUSIVE, + error = gfs2_glock_nq_init(qda[qx]->qd_gl, LM_ST_EXCLUSIVE, GL_NOCACHE, &ghs[qx]); if (error) goto out; @@ -797,8 +769,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) qd = qda[x]; offset = qd2offset(qd); error = gfs2_adjust_quota(ip, offset, qd->qd_change_sync, - (struct gfs2_quota_data *) - qd); + (struct gfs2_quota_data *)qd); if (error) goto out_end_trans; @@ -829,8 +800,7 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh, struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode); struct gfs2_holder i_gh; - struct gfs2_quota_host q; - char buf[sizeof(struct gfs2_quota)]; + struct gfs2_quota q; int error; struct gfs2_quota_lvb *qlvb; @@ -853,22 +823,23 @@ restart: if (error) goto fail; - memset(buf, 0, sizeof(struct gfs2_quota)); + memset(&q, 0, sizeof(struct gfs2_quota)); pos = qd2offset(qd); - error = gfs2_internal_read(ip, NULL, buf, &pos, - sizeof(struct gfs2_quota)); + error = gfs2_internal_read(ip, NULL, (char *)&q, &pos, sizeof(q)); if (error < 0) goto fail_gunlock; - + if ((error < sizeof(q)) && force_refresh) { + error = -ENOENT; + goto fail_gunlock; + } gfs2_glock_dq_uninit(&i_gh); - gfs2_quota_in(&q, buf); qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb; qlvb->qb_magic = cpu_to_be32(GFS2_MAGIC); qlvb->__pad = 0; - qlvb->qb_limit = cpu_to_be64(q.qu_limit); - qlvb->qb_warn = cpu_to_be64(q.qu_warn); - qlvb->qb_value = cpu_to_be64(q.qu_value); + qlvb->qb_limit = q.qu_limit; + qlvb->qb_warn = q.qu_warn; + qlvb->qb_value = q.qu_value; qd->qd_qb = *qlvb; gfs2_glock_dq_uninit(q_gh); @@ -1126,7 +1097,6 @@ int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id) gfs2_glock_dq_uninit(&q_gh); qd_put(qd); - return error; } From 113d6b3c99bf30d8083068d00e3c7304d91d4845 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 28 Sep 2009 11:52:16 +0100 Subject: [PATCH 280/298] GFS2: Add get_xquota support This adds support for viewing the current GFS2 quota settings via the XFS quota API. The setting of quotas will be addressed in a later patch. Fields which are not supported here are left set to zero. Signed-off-by: Steven Whitehouse Reviewed-by: Bob Peterson --- fs/gfs2/quota.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 33e369f108b..6c5d6aa7d53 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -1367,8 +1367,51 @@ static int gfs2_quota_get_xstate(struct super_block *sb, return 0; } +static int gfs2_xquota_get(struct super_block *sb, int type, qid_t id, + struct fs_disk_quota *fdq) +{ + struct gfs2_sbd *sdp = sb->s_fs_info; + struct gfs2_quota_lvb *qlvb; + struct gfs2_quota_data *qd; + struct gfs2_holder q_gh; + int error; + + memset(fdq, 0, sizeof(struct fs_disk_quota)); + + if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF) + return -ESRCH; /* Crazy XFS error code */ + + if (type == USRQUOTA) + type = QUOTA_USER; + else if (type == GRPQUOTA) + type = QUOTA_GROUP; + else + return -EINVAL; + + error = qd_get(sdp, type, id, &qd); + if (error) + return error; + error = do_glock(qd, FORCE, &q_gh); + if (error) + goto out; + + qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb; + fdq->d_version = FS_DQUOT_VERSION; + fdq->d_flags = (type == QUOTA_USER) ? XFS_USER_QUOTA : XFS_GROUP_QUOTA; + fdq->d_id = id; + fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit); + fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn); + fdq->d_bcount = be64_to_cpu(qlvb->qb_value); + + gfs2_glock_dq_uninit(&q_gh); +out: + qd_put(qd); + return error; +} + const struct quotactl_ops gfs2_quotactl_ops = { .quota_sync = gfs2_quota_sync, .get_xstate = gfs2_quota_get_xstate, + .get_xquota = gfs2_xquota_get, }; From e285c100362762f7440643be637dd332460fdc75 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Wed, 23 Sep 2009 13:50:49 +0100 Subject: [PATCH 281/298] GFS2: Add set_xquota support This patch adds the ability to set GFS2 quota limit and warning levels via the XFS quota API. Signed-off-by: Steven Whitehouse --- fs/gfs2/quota.c | 198 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 172 insertions(+), 26 deletions(-) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 6c5d6aa7d53..e8db5346a94 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -615,8 +615,9 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change) * gfs2_adjust_quota - adjust record of current block usage * @ip: The quota inode * @loc: Offset of the entry in the quota file - * @change: The amount of change to record + * @change: The amount of usage change to record * @qd: The quota data + * @fdq: The updated limits to record * * This function was mostly borrowed from gfs2_block_truncate_page which was * in turn mostly borrowed from ext3 @@ -625,19 +626,21 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change) */ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, - s64 change, struct gfs2_quota_data *qd) + s64 change, struct gfs2_quota_data *qd, + struct fs_disk_quota *fdq) { struct inode *inode = &ip->i_inode; struct address_space *mapping = inode->i_mapping; unsigned long index = loc >> PAGE_CACHE_SHIFT; unsigned offset = loc & (PAGE_CACHE_SIZE - 1); unsigned blocksize, iblock, pos; - struct buffer_head *bh; + struct buffer_head *bh, *dibh; struct page *page; void *kaddr; struct gfs2_quota *qp; s64 value; int err = -EIO; + u64 size; if (gfs2_is_stuffed(ip)) gfs2_unstuff_dinode(ip, NULL); @@ -683,9 +686,34 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, value = (s64)be64_to_cpu(qp->qu_value) + change; qp->qu_value = cpu_to_be64(value); qd->qd_qb.qb_value = qp->qu_value; + if (fdq) { + if (fdq->d_fieldmask & FS_DQ_BSOFT) { + qp->qu_warn = cpu_to_be64(fdq->d_blk_softlimit); + qd->qd_qb.qb_warn = qp->qu_warn; + } + if (fdq->d_fieldmask & FS_DQ_BHARD) { + qp->qu_limit = cpu_to_be64(fdq->d_blk_hardlimit); + qd->qd_qb.qb_limit = qp->qu_limit; + } + } flush_dcache_page(page); kunmap_atomic(kaddr, KM_USER0); - err = 0; + + err = gfs2_meta_inode_buffer(ip, &dibh); + if (err) + goto unlock; + + size = loc + sizeof(struct gfs2_quota); + if (size > inode->i_size) { + ip->i_disksize = size; + i_size_write(inode, size); + } + inode->i_mtime = inode->i_atime = CURRENT_TIME; + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + gfs2_dinode_out(ip, dibh->b_data); + brelse(dibh); + mark_inode_dirty(inode); + unlock: unlock_page(page); page_cache_release(page); @@ -713,6 +741,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) return -ENOMEM; sort(qda, num_qd, sizeof(struct gfs2_quota_data *), sort_qd, NULL); + mutex_lock_nested(&ip->i_inode.i_mutex, I_MUTEX_QUOTA); for (qx = 0; qx < num_qd; qx++) { error = gfs2_glock_nq_init(qda[qx]->qd_gl, LM_ST_EXCLUSIVE, GL_NOCACHE, &ghs[qx]); @@ -768,8 +797,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) for (x = 0; x < num_qd; x++) { qd = qda[x]; offset = qd2offset(qd); - error = gfs2_adjust_quota(ip, offset, qd->qd_change_sync, - (struct gfs2_quota_data *)qd); + error = gfs2_adjust_quota(ip, offset, qd->qd_change_sync, qd, NULL); if (error) goto out_end_trans; @@ -789,20 +817,44 @@ out_gunlock: out: while (qx--) gfs2_glock_dq_uninit(&ghs[qx]); + mutex_unlock(&ip->i_inode.i_mutex); kfree(ghs); gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl); return error; } +static int update_qd(struct gfs2_sbd *sdp, struct gfs2_quota_data *qd) +{ + struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode); + struct gfs2_quota q; + struct gfs2_quota_lvb *qlvb; + loff_t pos; + int error; + + memset(&q, 0, sizeof(struct gfs2_quota)); + pos = qd2offset(qd); + error = gfs2_internal_read(ip, NULL, (char *)&q, &pos, sizeof(q)); + if (error < 0) + return error; + + qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb; + qlvb->qb_magic = cpu_to_be32(GFS2_MAGIC); + qlvb->__pad = 0; + qlvb->qb_limit = q.qu_limit; + qlvb->qb_warn = q.qu_warn; + qlvb->qb_value = q.qu_value; + qd->qd_qb = *qlvb; + + return 0; +} + static int do_glock(struct gfs2_quota_data *qd, int force_refresh, struct gfs2_holder *q_gh) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode); struct gfs2_holder i_gh; - struct gfs2_quota q; int error; - struct gfs2_quota_lvb *qlvb; restart: error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_SHARED, 0, q_gh); @@ -812,7 +864,6 @@ restart: qd->qd_qb = *(struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb; if (force_refresh || qd->qd_qb.qb_magic != cpu_to_be32(GFS2_MAGIC)) { - loff_t pos; gfs2_glock_dq_uninit(q_gh); error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_EXCLUSIVE, GL_NOCACHE, q_gh); @@ -823,25 +874,11 @@ restart: if (error) goto fail; - memset(&q, 0, sizeof(struct gfs2_quota)); - pos = qd2offset(qd); - error = gfs2_internal_read(ip, NULL, (char *)&q, &pos, sizeof(q)); - if (error < 0) + error = update_qd(sdp, qd); + if (error) goto fail_gunlock; - if ((error < sizeof(q)) && force_refresh) { - error = -ENOENT; - goto fail_gunlock; - } + gfs2_glock_dq_uninit(&i_gh); - - qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb; - qlvb->qb_magic = cpu_to_be32(GFS2_MAGIC); - qlvb->__pad = 0; - qlvb->qb_limit = q.qu_limit; - qlvb->qb_warn = q.qu_warn; - qlvb->qb_value = q.qu_value; - qd->qd_qb = *qlvb; - gfs2_glock_dq_uninit(q_gh); force_refresh = 0; goto restart; @@ -1409,9 +1446,118 @@ out: return error; } +/* GFS2 only supports a subset of the XFS fields */ +#define GFS2_FIELDMASK (FS_DQ_BSOFT|FS_DQ_BHARD) + +static int gfs2_xquota_set(struct super_block *sb, int type, qid_t id, + struct fs_disk_quota *fdq) +{ + struct gfs2_sbd *sdp = sb->s_fs_info; + struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode); + struct gfs2_quota_data *qd; + struct gfs2_holder q_gh, i_gh; + unsigned int data_blocks, ind_blocks; + unsigned int blocks = 0; + int alloc_required; + struct gfs2_alloc *al; + loff_t offset; + int error; + + if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF) + return -ESRCH; /* Crazy XFS error code */ + + switch(type) { + case USRQUOTA: + type = QUOTA_USER; + if (fdq->d_flags != XFS_USER_QUOTA) + return -EINVAL; + break; + case GRPQUOTA: + type = QUOTA_GROUP; + if (fdq->d_flags != XFS_GROUP_QUOTA) + return -EINVAL; + break; + default: + return -EINVAL; + } + + if (fdq->d_fieldmask & ~GFS2_FIELDMASK) + return -EINVAL; + if (fdq->d_id != id) + return -EINVAL; + + error = qd_get(sdp, type, id, &qd); + if (error) + return error; + + mutex_lock(&ip->i_inode.i_mutex); + error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_EXCLUSIVE, 0, &q_gh); + if (error) + goto out_put; + error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); + if (error) + goto out_q; + + /* Check for existing entry, if none then alloc new blocks */ + error = update_qd(sdp, qd); + if (error) + goto out_i; + + /* If nothing has changed, this is a no-op */ + if ((fdq->d_fieldmask & FS_DQ_BSOFT) && + (fdq->d_blk_softlimit == be64_to_cpu(qd->qd_qb.qb_warn))) + fdq->d_fieldmask ^= FS_DQ_BSOFT; + if ((fdq->d_fieldmask & FS_DQ_BHARD) && + (fdq->d_blk_hardlimit == be64_to_cpu(qd->qd_qb.qb_limit))) + fdq->d_fieldmask ^= FS_DQ_BHARD; + if (fdq->d_fieldmask == 0) + goto out_i; + + offset = qd2offset(qd); + error = gfs2_write_alloc_required(ip, offset, sizeof(struct gfs2_quota), + &alloc_required); + if (error) + goto out_i; + if (alloc_required) { + al = gfs2_alloc_get(ip); + if (al == NULL) + goto out_i; + gfs2_write_calc_reserv(ip, sizeof(struct gfs2_quota), + &data_blocks, &ind_blocks); + blocks = al->al_requested = 1 + data_blocks + ind_blocks; + error = gfs2_inplace_reserve(ip); + if (error) + goto out_alloc; + } + + error = gfs2_trans_begin(sdp, blocks + RES_DINODE + 1, 0); + if (error) + goto out_release; + + /* Apply changes */ + error = gfs2_adjust_quota(ip, offset, 0, qd, fdq); + + gfs2_trans_end(sdp); +out_release: + if (alloc_required) { + gfs2_inplace_release(ip); +out_alloc: + gfs2_alloc_put(ip); + } +out_i: + gfs2_glock_dq_uninit(&i_gh); +out_q: + gfs2_glock_dq_uninit(&q_gh); +out_put: + mutex_unlock(&ip->i_inode.i_mutex); + qd_put(qd); + return error; +} + const struct quotactl_ops gfs2_quotactl_ops = { .quota_sync = gfs2_quota_sync, .get_xstate = gfs2_quota_get_xstate, .get_xquota = gfs2_xquota_get, + .set_xquota = gfs2_xquota_set, }; From 86e931a35e93d94e6e91b57cc76456e16d188ea9 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 28 Sep 2009 12:35:17 +0100 Subject: [PATCH 282/298] VFS: Export dquot_send_warning Sending a message to userspace in a generic format to warn of events (e.g. quota exceeded) in the quota subsystem is a generically useful feature. This patch makes some minor changes to the send_message function from dquot.c renaming it quota_send_message, moving it to quota.c and exporting it for use by filesystems which do not use the dquot code. Signed-off-by: Steven Whitehouse --- fs/quota/Kconfig | 2 +- fs/quota/dquot.c | 93 +++++-------------------------------------- fs/quota/quota.c | 93 +++++++++++++++++++++++++++++++++++++++++++ include/linux/quota.h | 11 +++++ 4 files changed, 114 insertions(+), 85 deletions(-) diff --git a/fs/quota/Kconfig b/fs/quota/Kconfig index 8047e01ef46..353e78a9ebe 100644 --- a/fs/quota/Kconfig +++ b/fs/quota/Kconfig @@ -17,7 +17,7 @@ config QUOTA config QUOTA_NETLINK_INTERFACE bool "Report quota messages through netlink interface" - depends on QUOTA && NET + depends on QUOTACTL && NET help If you say Y here, quota warnings (about exceeding softlimit, reaching hardlimit, etc.) will be reported through netlink interface. If unsure, diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 39b49c42a7e..9b6ad908dcb 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -77,10 +77,6 @@ #include #include #include /* for inode_lock, oddly enough.. */ -#ifdef CONFIG_QUOTA_NETLINK_INTERFACE -#include -#include -#endif #include @@ -1071,73 +1067,6 @@ static void print_warning(struct dquot *dquot, const int warntype) } #endif -#ifdef CONFIG_QUOTA_NETLINK_INTERFACE - -/* Netlink family structure for quota */ -static struct genl_family quota_genl_family = { - .id = GENL_ID_GENERATE, - .hdrsize = 0, - .name = "VFS_DQUOT", - .version = 1, - .maxattr = QUOTA_NL_A_MAX, -}; - -/* Send warning to userspace about user which exceeded quota */ -static void send_warning(const struct dquot *dquot, const char warntype) -{ - static atomic_t seq; - struct sk_buff *skb; - void *msg_head; - int ret; - int msg_size = 4 * nla_total_size(sizeof(u32)) + - 2 * nla_total_size(sizeof(u64)); - - /* We have to allocate using GFP_NOFS as we are called from a - * filesystem performing write and thus further recursion into - * the fs to free some data could cause deadlocks. */ - skb = genlmsg_new(msg_size, GFP_NOFS); - if (!skb) { - printk(KERN_ERR - "VFS: Not enough memory to send quota warning.\n"); - return; - } - msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq), - "a_genl_family, 0, QUOTA_NL_C_WARNING); - if (!msg_head) { - printk(KERN_ERR - "VFS: Cannot store netlink header in quota warning.\n"); - goto err_out; - } - ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, dquot->dq_type); - if (ret) - goto attr_err_out; - ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, dquot->dq_id); - if (ret) - goto attr_err_out; - ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype); - if (ret) - goto attr_err_out; - ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MAJOR, - MAJOR(dquot->dq_sb->s_dev)); - if (ret) - goto attr_err_out; - ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, - MINOR(dquot->dq_sb->s_dev)); - if (ret) - goto attr_err_out; - ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid()); - if (ret) - goto attr_err_out; - genlmsg_end(skb, msg_head); - - genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS); - return; -attr_err_out: - printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); -err_out: - kfree_skb(skb); -} -#endif /* * Write warnings to the console and send warning messages over netlink. * @@ -1145,18 +1074,20 @@ err_out: */ static void flush_warnings(struct dquot *const *dquots, char *warntype) { + struct dquot *dq; int i; - for (i = 0; i < MAXQUOTAS; i++) - if (dquots[i] && warntype[i] != QUOTA_NL_NOWARN && - !warning_issued(dquots[i], warntype[i])) { + for (i = 0; i < MAXQUOTAS; i++) { + dq = dquots[i]; + if (dq && warntype[i] != QUOTA_NL_NOWARN && + !warning_issued(dq, warntype[i])) { #ifdef CONFIG_PRINT_QUOTA_WARNING - print_warning(dquots[i], warntype[i]); -#endif -#ifdef CONFIG_QUOTA_NETLINK_INTERFACE - send_warning(dquots[i], warntype[i]); + print_warning(dq, warntype[i]); #endif + quota_send_warning(dq->dq_type, dq->dq_id, + dq->dq_sb->s_dev, warntype[i]); } + } } static int ignore_hardlimit(struct dquot *dquot) @@ -2607,12 +2538,6 @@ static int __init dquot_init(void) register_shrinker(&dqcache_shrinker); -#ifdef CONFIG_QUOTA_NETLINK_INTERFACE - if (genl_register_family("a_genl_family) != 0) - printk(KERN_ERR - "VFS: Failed to create quota netlink interface.\n"); -#endif - return 0; } module_init(dquot_init); diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 95c5b42384b..ee91e275695 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include /* Check validity of generic quotactl commands */ static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, @@ -525,3 +527,94 @@ asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special, return ret; } #endif + + +#ifdef CONFIG_QUOTA_NETLINK_INTERFACE + +/* Netlink family structure for quota */ +static struct genl_family quota_genl_family = { + .id = GENL_ID_GENERATE, + .hdrsize = 0, + .name = "VFS_DQUOT", + .version = 1, + .maxattr = QUOTA_NL_A_MAX, +}; + +/** + * quota_send_warning - Send warning to userspace about exceeded quota + * @type: The quota type: USRQQUOTA, GRPQUOTA,... + * @id: The user or group id of the quota that was exceeded + * @dev: The device on which the fs is mounted (sb->s_dev) + * @warntype: The type of the warning: QUOTA_NL_... + * + * This can be used by filesystems (including those which don't use + * dquot) to send a message to userspace relating to quota limits. + * + */ + +void quota_send_warning(short type, unsigned int id, dev_t dev, + const char warntype) +{ + static atomic_t seq; + struct sk_buff *skb; + void *msg_head; + int ret; + int msg_size = 4 * nla_total_size(sizeof(u32)) + + 2 * nla_total_size(sizeof(u64)); + + /* We have to allocate using GFP_NOFS as we are called from a + * filesystem performing write and thus further recursion into + * the fs to free some data could cause deadlocks. */ + skb = genlmsg_new(msg_size, GFP_NOFS); + if (!skb) { + printk(KERN_ERR + "VFS: Not enough memory to send quota warning.\n"); + return; + } + msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq), + "a_genl_family, 0, QUOTA_NL_C_WARNING); + if (!msg_head) { + printk(KERN_ERR + "VFS: Cannot store netlink header in quota warning.\n"); + goto err_out; + } + ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, type); + if (ret) + goto attr_err_out; + ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, id); + if (ret) + goto attr_err_out; + ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype); + if (ret) + goto attr_err_out; + ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MAJOR, MAJOR(dev)); + if (ret) + goto attr_err_out; + ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, MINOR(dev)); + if (ret) + goto attr_err_out; + ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid()); + if (ret) + goto attr_err_out; + genlmsg_end(skb, msg_head); + + genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS); + return; +attr_err_out: + printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); +err_out: + kfree_skb(skb); +} +EXPORT_SYMBOL(quota_send_warning); + +static int __init quota_init(void) +{ + if (genl_register_family("a_genl_family) != 0) + printk(KERN_ERR + "VFS: Failed to create quota netlink interface.\n"); + return 0; +}; + +module_init(quota_init); +#endif + diff --git a/include/linux/quota.h b/include/linux/quota.h index 78c48895b12..ce9a9b2e5cd 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -376,6 +376,17 @@ static inline unsigned int dquot_generic_flag(unsigned int flags, int type) return flags >> _DQUOT_STATE_FLAGS; } +#ifdef CONFIG_QUOTA_NETLINK_INTERFACE +extern void quota_send_warning(short type, unsigned int id, dev_t dev, + const char warntype); +#else +static inline void quota_send_warning(short type, unsigned int id, dev_t dev, + const char warntype) +{ + return; +} +#endif /* CONFIG_QUOTA_NETLINK_INTERFACE */ + struct quota_info { unsigned int flags; /* Flags for diskquotas on this device */ struct mutex dqio_mutex; /* lock device while I/O in progress */ From 2ec4650526c5a94d96bb760001fe0685b15988de Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Mon, 28 Sep 2009 12:49:15 +0100 Subject: [PATCH 283/298] GFS2: Use dquot_send_warning() This adds support to GFS2 to send quota warnings via netlink. Also it removes a stray \r which was left over from when the code used to print warnings on the console. Signed-off-by: Steven Whitehouse --- fs/gfs2/quota.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index e8db5346a94..1d4fc0413a3 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include "gfs2.h" @@ -1001,7 +1002,7 @@ static int print_message(struct gfs2_quota_data *qd, char *type) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; - printk(KERN_INFO "GFS2: fsid=%s: quota %s for %s %u\r\n", + printk(KERN_INFO "GFS2: fsid=%s: quota %s for %s %u\n", sdp->sd_fsname, type, (test_bit(QDF_USER, &qd->qd_flags)) ? "user" : "group", qd->qd_id); @@ -1038,6 +1039,10 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid) if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) { print_message(qd, "exceeded"); + quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ? + USRQUOTA : GRPQUOTA, qd->qd_id, + sdp->sd_vfs->s_dev, QUOTA_NL_BHARDWARN); + error = -EDQUOT; break; } else if (be64_to_cpu(qd->qd_qb.qb_warn) && @@ -1045,6 +1050,9 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid) time_after_eq(jiffies, qd->qd_last_warn + gfs2_tune_get(sdp, gt_quota_warn_period) * HZ)) { + quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ? + USRQUOTA : GRPQUOTA, qd->qd_id, + sdp->sd_vfs->s_dev, QUOTA_NL_BSOFTWARN); error = print_message(qd, "warning"); qd->qd_last_warn = jiffies; } From 3d3c10f2ce80d2a19e5e02023c2b7ab7086c36d5 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Tue, 20 Oct 2009 02:39:44 -0500 Subject: [PATCH 284/298] GFS2: Improve statfs and quota usability GFS2 now has three new mount options, statfs_quantum, quota_quantum and statfs_percent. statfs_quantum and quota_quantum simply allow you to set the tunables of the same name. Setting setting statfs_quantum to 0 will also turn on the statfs_slow tunable. statfs_percent accepts an integer between 0 and 100. Numbers between 1 and 100 will cause GFS2 to do any early sync when the local number of blocks free changes by at least statfs_percent from the totoal number of blocks free. Setting statfs_percent to 0 disables this. Signed-off-by: Benjamin Marzinski Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 4 +++ fs/gfs2/ops_fstype.c | 14 +++++++-- fs/gfs2/quota.c | 21 ++++++++++++-- fs/gfs2/quota.h | 2 ++ fs/gfs2/super.c | 69 +++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 100 insertions(+), 10 deletions(-) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 6edb423f90b..c239b0f969c 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -430,6 +430,9 @@ struct gfs2_args { unsigned int ar_discard:1; /* discard requests */ unsigned int ar_errors:2; /* errors=withdraw | panic */ int ar_commit; /* Commit interval */ + int ar_statfs_quantum; /* The fast statfs interval */ + int ar_quota_quantum; /* The quota interval */ + int ar_statfs_percent; /* The % change to force sync */ }; struct gfs2_tune { @@ -558,6 +561,7 @@ struct gfs2_sbd { spinlock_t sd_statfs_spin; struct gfs2_statfs_change_host sd_statfs_master; struct gfs2_statfs_change_host sd_statfs_local; + int sd_statfs_force_sync; /* Resource group stuff */ diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 36b11cba57e..9744ee92047 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -63,13 +63,10 @@ static void gfs2_tune_init(struct gfs2_tune *gt) gt->gt_quota_warn_period = 10; gt->gt_quota_scale_num = 1; gt->gt_quota_scale_den = 1; - gt->gt_quota_quantum = 60; gt->gt_new_files_jdata = 0; gt->gt_max_readahead = 1 << 18; gt->gt_stall_secs = 600; gt->gt_complain_secs = 10; - gt->gt_statfs_quantum = 30; - gt->gt_statfs_slow = 0; } static struct gfs2_sbd *init_sbd(struct super_block *sb) @@ -1153,6 +1150,15 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift; sdp->sd_tune.gt_log_flush_secs = sdp->sd_args.ar_commit; + sdp->sd_tune.gt_quota_quantum = sdp->sd_args.ar_quota_quantum; + if (sdp->sd_args.ar_statfs_quantum) { + sdp->sd_tune.gt_statfs_slow = 0; + sdp->sd_tune.gt_statfs_quantum = sdp->sd_args.ar_statfs_quantum; + } + else { + sdp->sd_tune.gt_statfs_slow = 1; + sdp->sd_tune.gt_statfs_quantum = 30; + } error = init_names(sdp, silent); if (error) @@ -1308,6 +1314,8 @@ static int gfs2_get_sb(struct file_system_type *fs_type, int flags, args.ar_quota = GFS2_QUOTA_DEFAULT; args.ar_data = GFS2_DATA_DEFAULT; args.ar_commit = 60; + args.ar_statfs_quantum = 30; + args.ar_quota_quantum = 60; args.ar_errors = GFS2_ERRORS_DEFAULT; error = gfs2_mount_args(&args, data); diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 1d4fc0413a3..e3bf6eab875 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -1344,6 +1344,14 @@ static void quotad_check_trunc_list(struct gfs2_sbd *sdp) } } +void gfs2_wake_up_statfs(struct gfs2_sbd *sdp) { + if (!sdp->sd_statfs_force_sync) { + sdp->sd_statfs_force_sync = 1; + wake_up(&sdp->sd_quota_wait); + } +} + + /** * gfs2_quotad - Write cached quota changes into the quota file * @sdp: Pointer to GFS2 superblock @@ -1363,8 +1371,15 @@ int gfs2_quotad(void *data) while (!kthread_should_stop()) { /* Update the master statfs file */ - quotad_check_timeo(sdp, "statfs", gfs2_statfs_sync, t, - &statfs_timeo, &tune->gt_statfs_quantum); + if (sdp->sd_statfs_force_sync) { + int error = gfs2_statfs_sync(sdp->sd_vfs, 0); + quotad_error(sdp, "statfs", error); + statfs_timeo = gfs2_tune_get(sdp, gt_statfs_quantum) * HZ; + } + else + quotad_check_timeo(sdp, "statfs", gfs2_statfs_sync, t, + &statfs_timeo, + &tune->gt_statfs_quantum); /* Update quota file */ quotad_check_timeo(sdp, "sync", gfs2_quota_sync, t, @@ -1381,7 +1396,7 @@ int gfs2_quotad(void *data) spin_lock(&sdp->sd_trunc_lock); empty = list_empty(&sdp->sd_trunc_list); spin_unlock(&sdp->sd_trunc_lock); - if (empty) + if (empty && !sdp->sd_statfs_force_sync) t -= schedule_timeout(t); else t = 0; diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h index 025d15ba24c..e271fa07ad0 100644 --- a/fs/gfs2/quota.h +++ b/fs/gfs2/quota.h @@ -32,6 +32,8 @@ extern int gfs2_quota_init(struct gfs2_sbd *sdp); extern void gfs2_quota_cleanup(struct gfs2_sbd *sdp); extern int gfs2_quotad(void *data); +extern void gfs2_wake_up_statfs(struct gfs2_sbd *sdp); + static inline int gfs2_quota_lock_check(struct gfs2_inode *ip) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index e7b24d59d4f..3fee2fd3ae4 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -70,6 +70,9 @@ enum { Opt_commit, Opt_err_withdraw, Opt_err_panic, + Opt_statfs_quantum, + Opt_statfs_percent, + Opt_quota_quantum, Opt_error, }; @@ -101,6 +104,9 @@ static const match_table_t tokens = { {Opt_commit, "commit=%d"}, {Opt_err_withdraw, "errors=withdraw"}, {Opt_err_panic, "errors=panic"}, + {Opt_statfs_quantum, "statfs_quantum=%d"}, + {Opt_statfs_percent, "statfs_percent=%d"}, + {Opt_quota_quantum, "quota_quantum=%d"}, {Opt_error, NULL} }; @@ -214,6 +220,28 @@ int gfs2_mount_args(struct gfs2_args *args, char *options) return rv ? rv : -EINVAL; } break; + case Opt_statfs_quantum: + rv = match_int(&tmp[0], &args->ar_statfs_quantum); + if (rv || args->ar_statfs_quantum < 0) { + printk(KERN_WARNING "GFS2: statfs_quantum mount option requires a non-negative numeric argument\n"); + return rv ? rv : -EINVAL; + } + break; + case Opt_quota_quantum: + rv = match_int(&tmp[0], &args->ar_quota_quantum); + if (rv || args->ar_quota_quantum <= 0) { + printk(KERN_WARNING "GFS2: quota_quantum mount option requires a positive numeric argument\n"); + return rv ? rv : -EINVAL; + } + break; + case Opt_statfs_percent: + rv = match_int(&tmp[0], &args->ar_statfs_percent); + if (rv || args->ar_statfs_percent < 0 || + args->ar_statfs_percent > 100) { + printk(KERN_WARNING "statfs_percent mount option requires a numeric argument between 0 and 100\n"); + return rv ? rv : -EINVAL; + } + break; case Opt_err_withdraw: args->ar_errors = GFS2_ERRORS_WITHDRAW; break; @@ -442,7 +470,9 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, { struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; + struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master; struct buffer_head *l_bh; + int percent, sync_percent; int error; error = gfs2_meta_inode_buffer(l_ip, &l_bh); @@ -456,9 +486,17 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, l_sc->sc_free += free; l_sc->sc_dinodes += dinodes; gfs2_statfs_change_out(l_sc, l_bh->b_data + sizeof(struct gfs2_dinode)); + if (m_sc->sc_free) + percent = (100 * l_sc->sc_free) / m_sc->sc_free; + else + percent = 100; spin_unlock(&sdp->sd_statfs_spin); brelse(l_bh); + sync_percent = sdp->sd_args.ar_statfs_percent; + if (sync_percent && (percent >= sync_percent || + percent <= -sync_percent)) + gfs2_wake_up_statfs(sdp); } void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh, @@ -522,6 +560,7 @@ int gfs2_statfs_sync(struct super_block *sb, int type) goto out_bh2; update_statfs(sdp, m_bh, l_bh); + sdp->sd_statfs_force_sync = 0; gfs2_trans_end(sdp); @@ -1062,6 +1101,11 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) spin_lock(>->gt_spin); args.ar_commit = gt->gt_log_flush_secs; + args.ar_quota_quantum = gt->gt_quota_quantum; + if (gt->gt_statfs_slow) + args.ar_statfs_quantum = 0; + else + args.ar_statfs_quantum = gt->gt_statfs_quantum; spin_unlock(>->gt_spin); error = gfs2_mount_args(&args, data); if (error) @@ -1100,6 +1144,15 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) sb->s_flags &= ~MS_POSIXACL; spin_lock(>->gt_spin); gt->gt_log_flush_secs = args.ar_commit; + gt->gt_quota_quantum = args.ar_quota_quantum; + if (args.ar_statfs_quantum) { + gt->gt_statfs_slow = 0; + gt->gt_statfs_quantum = args.ar_statfs_quantum; + } + else { + gt->gt_statfs_slow = 1; + gt->gt_statfs_quantum = 30; + } spin_unlock(>->gt_spin); gfs2_online_uevent(sdp); @@ -1180,7 +1233,7 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) { struct gfs2_sbd *sdp = mnt->mnt_sb->s_fs_info; struct gfs2_args *args = &sdp->sd_args; - int lfsecs; + int val; if (is_ancestor(mnt->mnt_root, sdp->sd_master_dir)) seq_printf(s, ",meta"); @@ -1241,9 +1294,17 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) } if (args->ar_discard) seq_printf(s, ",discard"); - lfsecs = sdp->sd_tune.gt_log_flush_secs; - if (lfsecs != 60) - seq_printf(s, ",commit=%d", lfsecs); + val = sdp->sd_tune.gt_log_flush_secs; + if (val != 60) + seq_printf(s, ",commit=%d", val); + val = sdp->sd_tune.gt_statfs_quantum; + if (val != 30) + seq_printf(s, ",statfs_quantum=%d", val); + val = sdp->sd_tune.gt_quota_quantum; + if (val != 60) + seq_printf(s, ",quota_quantum=%d", val); + if (args->ar_statfs_percent) + seq_printf(s, ",statfs_percent=%d", args->ar_statfs_percent); if (args->ar_errors != GFS2_ERRORS_DEFAULT) { const char *state; From c14f5735e724cb5338ca8298d42b1658008a10d7 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Mon, 26 Oct 2009 13:29:47 -0500 Subject: [PATCH 285/298] GFS2: remove division from new statfs code It's not necessary to do any 64bit division for the statfs sync code, so remove it. Signed-off-by: Benjamin Marzinski Signed-off-by: Steven Whitehouse --- fs/gfs2/super.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 3fee2fd3ae4..b1dcfab3646 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -472,7 +472,8 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master; struct buffer_head *l_bh; - int percent, sync_percent; + s64 x, y; + int need_sync = 0; int error; error = gfs2_meta_inode_buffer(l_ip, &l_bh); @@ -486,16 +487,16 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, l_sc->sc_free += free; l_sc->sc_dinodes += dinodes; gfs2_statfs_change_out(l_sc, l_bh->b_data + sizeof(struct gfs2_dinode)); - if (m_sc->sc_free) - percent = (100 * l_sc->sc_free) / m_sc->sc_free; - else - percent = 100; + if (sdp->sd_args.ar_statfs_percent) { + x = 100 * l_sc->sc_free; + y = m_sc->sc_free * sdp->sd_args.ar_statfs_percent; + if (x >= y || x <= -y) + need_sync = 1; + } spin_unlock(&sdp->sd_statfs_spin); brelse(l_bh); - sync_percent = sdp->sd_args.ar_statfs_percent; - if (sync_percent && (percent >= sync_percent || - percent <= -sync_percent)) + if (need_sync) gfs2_wake_up_statfs(sdp); } From f25934c5f88655a8d5c3c40a540daed1f0e6dedc Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 30 Oct 2009 08:03:27 +0100 Subject: [PATCH 286/298] GFS2: add barrier/nobarrier mount options Currently gfs2 issues barrier unconditionally. There are various reasons to disable them, be that just for testing or for stupid devices flushing large battert backed caches. Add a nobarrier option that matches xfs and btrfs for this. Also add a symmetric barrier option to turn it back on at remount time. Signed-off-by: Christoph Hellwig Signed-off-by: Steven Whitehouse --- fs/gfs2/incore.h | 1 + fs/gfs2/ops_fstype.c | 2 ++ fs/gfs2/super.c | 14 ++++++++++++++ 3 files changed, 17 insertions(+) diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index c239b0f969c..4792200978c 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -429,6 +429,7 @@ struct gfs2_args { unsigned int ar_meta:1; /* mount metafs */ unsigned int ar_discard:1; /* discard requests */ unsigned int ar_errors:2; /* errors=withdraw | panic */ + unsigned int ar_nobarrier:1; /* do not send barriers */ int ar_commit; /* Commit interval */ int ar_statfs_quantum; /* The fast statfs interval */ int ar_quota_quantum; /* The quota interval */ diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 9744ee92047..edfee24f363 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -1131,6 +1131,8 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent } if (sdp->sd_args.ar_posix_acl) sb->s_flags |= MS_POSIXACL; + if (sdp->sd_args.ar_nobarrier) + set_bit(SDF_NOBARRIERS, &sdp->sd_flags); sb->s_magic = GFS2_MAGIC; sb->s_op = &gfs2_super_ops; diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index b1dcfab3646..5e4b31441a9 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -73,6 +73,8 @@ enum { Opt_statfs_quantum, Opt_statfs_percent, Opt_quota_quantum, + Opt_barrier, + Opt_nobarrier, Opt_error, }; @@ -107,6 +109,8 @@ static const match_table_t tokens = { {Opt_statfs_quantum, "statfs_quantum=%d"}, {Opt_statfs_percent, "statfs_percent=%d"}, {Opt_quota_quantum, "quota_quantum=%d"}, + {Opt_barrier, "barrier"}, + {Opt_nobarrier, "nobarrier"}, {Opt_error, NULL} }; @@ -253,6 +257,12 @@ int gfs2_mount_args(struct gfs2_args *args, char *options) } args->ar_errors = GFS2_ERRORS_PANIC; break; + case Opt_barrier: + args->ar_nobarrier = 0; + break; + case Opt_nobarrier: + args->ar_nobarrier = 1; + break; case Opt_error: default: printk(KERN_WARNING "GFS2: invalid mount option: %s\n", o); @@ -1143,6 +1153,10 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) sb->s_flags |= MS_POSIXACL; else sb->s_flags &= ~MS_POSIXACL; + if (sdp->sd_args.ar_nobarrier) + set_bit(SDF_NOBARRIERS, &sdp->sd_flags); + else + clear_bit(SDF_NOBARRIERS, &sdp->sd_flags); spin_lock(>->gt_spin); gt->gt_log_flush_secs = args.ar_commit; gt->gt_quota_quantum = args.ar_quota_quantum; From cdcfde62dac64c86ff34e483c595d568a252c433 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 30 Oct 2009 10:48:53 +0000 Subject: [PATCH 287/298] GFS2: Display nobarrier option in /proc/mounts Since the default is barriers on, this only displays the nobarrier option when that is active. Signed-off-by: Steven Whitehouse --- fs/gfs2/super.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 5e4b31441a9..c282ad41f3d 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1336,6 +1336,9 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) } seq_printf(s, ",errors=%s", state); } + if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) + seq_printf(s, ",nobarrier"); + return 0; } From 1579343a73e32b5886e186e8f3e4db85e420ed3f Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 6 Nov 2009 11:06:37 +0000 Subject: [PATCH 288/298] GFS2: Remove dirent_first() function This function only had one caller left, and that caller only called it for leaf blocks, hence one branch of the "if" was never taken. In addition the call to get_left had already verified the metadata type, so the function can be reduced to a single line of code in its caller. Signed-off-by: Steven Whitehouse --- fs/gfs2/dir.c | 34 +--------------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 297d7e5ceba..25fddc100f1 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -525,38 +525,6 @@ consist_inode: return ERR_PTR(-EIO); } - -/** - * dirent_first - Return the first dirent - * @dip: the directory - * @bh: The buffer - * @dent: Pointer to list of dirents - * - * return first dirent whether bh points to leaf or stuffed dinode - * - * Returns: IS_LEAF, IS_DINODE, or -errno - */ - -static int dirent_first(struct gfs2_inode *dip, struct buffer_head *bh, - struct gfs2_dirent **dent) -{ - struct gfs2_meta_header *h = (struct gfs2_meta_header *)bh->b_data; - - if (be32_to_cpu(h->mh_type) == GFS2_METATYPE_LF) { - if (gfs2_meta_check(GFS2_SB(&dip->i_inode), bh)) - return -EIO; - *dent = (struct gfs2_dirent *)(bh->b_data + - sizeof(struct gfs2_leaf)); - return IS_LEAF; - } else { - if (gfs2_metatype_check(GFS2_SB(&dip->i_inode), bh, GFS2_METATYPE_DI)) - return -EIO; - *dent = (struct gfs2_dirent *)(bh->b_data + - sizeof(struct gfs2_dinode)); - return IS_DINODE; - } -} - static int dirent_check_reclen(struct gfs2_inode *dip, const struct gfs2_dirent *d, const void *end_p) { @@ -1006,7 +974,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) divider = (start + half_len) << (32 - dip->i_depth); /* Copy the entries */ - dirent_first(dip, obh, &dent); + dent = (struct gfs2_dirent *)(obh->b_data + sizeof(struct gfs2_leaf)); do { next = dent; From 2c77634965ee28c8b4790ffb5e83dd5ff7ac8988 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 6 Nov 2009 11:10:51 +0000 Subject: [PATCH 289/298] GFS2: Locking order fix in gfs2_check_blk_state In some cases we already have the rindex lock when we enter this function. Signed-off-by: Steven Whitehouse --- fs/gfs2/rgrp.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 8f1cfb02a6c..0608f490c29 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1710,11 +1710,16 @@ int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type) { struct gfs2_rgrpd *rgd; struct gfs2_holder ri_gh, rgd_gh; + struct gfs2_inode *ip = GFS2_I(sdp->sd_rindex); + int ri_locked = 0; int error; - error = gfs2_rindex_hold(sdp, &ri_gh); - if (error) - goto fail; + if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { + error = gfs2_rindex_hold(sdp, &ri_gh); + if (error) + goto fail; + ri_locked = 1; + } error = -EINVAL; rgd = gfs2_blk2rgrpd(sdp, no_addr); @@ -1730,7 +1735,8 @@ int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type) gfs2_glock_dq_uninit(&rgd_gh); fail_rindex: - gfs2_glock_dq_uninit(&ri_gh); + if (ri_locked) + gfs2_glock_dq_uninit(&ri_gh); fail: return error; } From 0ab7d13fcbd7ce1658c563e345990ba453719deb Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 6 Nov 2009 16:20:51 +0000 Subject: [PATCH 290/298] GFS2: Tag all metadata with jid There are two spare field in the header common to all GFS2 metadata. One is just the right size to fit a journal id in it, and this patch updates the journal code so that each time a metadata block is modified, we tag it with the journal id of the node which is performing the modification. The reason for this is that it should make it much easier to debug issues which arise if we can tell which node was the last to modify a particular metadata block. Since the field is updated before the block is written into the journal, each journal should only contain metadata which is tagged with its own journal id. The one exception to this is the journal header block, which might have a different node's id in it, if that journal was recovered by another node in the cluster. Thus each journal will contain a record of which nodes recovered it, via the journal header. The other field in the metadata header could potentially be used to hold information about what kind of operation was performed, but for the time being we just zero it on each transaction so that if we use it for that in future, we'll know that the information (where it exists) is reliable. I did consider using the other field to hold the journal sequence number, however since in GFS2's journaling we write the modified data into the journal and not the original data, this gives no information as to what action caused the modification, so I think we can probably come up with a better use for those 64 bits in the future. Signed-off-by: Steven Whitehouse --- fs/gfs2/inode.c | 2 -- fs/gfs2/log.c | 2 ++ fs/gfs2/lops.c | 4 ++++ fs/gfs2/recovery.c | 2 ++ include/linux/gfs2_ondisk.h | 6 +++++- 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 6380cd9314b..26ba2a4c4a2 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -947,9 +947,7 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf) str->di_header.mh_magic = cpu_to_be32(GFS2_MAGIC); str->di_header.mh_type = cpu_to_be32(GFS2_METATYPE_DI); - str->di_header.__pad0 = 0; str->di_header.mh_format = cpu_to_be32(GFS2_FORMAT_DI); - str->di_header.__pad1 = 0; str->di_num.no_addr = cpu_to_be64(ip->i_no_addr); str->di_num.no_formal_ino = cpu_to_be64(ip->i_no_formal_ino); str->di_mode = cpu_to_be32(ip->i_inode.i_mode); diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 13c6237c5f6..4511b08fc45 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -596,7 +596,9 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) memset(lh, 0, sizeof(struct gfs2_log_header)); lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC); lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH); + lh->lh_header.__pad0 = cpu_to_be64(0); lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH); + lh->lh_header.mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid); lh->lh_sequence = cpu_to_be64(sdp->sd_log_sequence++); lh->lh_flags = cpu_to_be32(flags); lh->lh_tail = cpu_to_be32(tail); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 9969ff062c5..de97632ba32 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -132,6 +132,7 @@ static struct buffer_head *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type) static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) { struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); + struct gfs2_meta_header *mh; struct gfs2_trans *tr; lock_buffer(bd->bd_bh); @@ -148,6 +149,9 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags); gfs2_meta_check(sdp, bd->bd_bh); gfs2_pin(sdp, bd->bd_bh); + mh = (struct gfs2_meta_header *)bd->bd_bh->b_data; + mh->__pad0 = cpu_to_be64(0); + mh->mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid); sdp->sd_log_num_buf++; list_add(&le->le_list, &sdp->sd_log_le_buf); tr->tr_num_buf_new++; diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index 09fa3196557..4b9bece3d43 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -410,7 +410,9 @@ static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header_host *hea memset(lh, 0, sizeof(struct gfs2_log_header)); lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC); lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH); + lh->lh_header.__pad0 = cpu_to_be64(0); lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH); + lh->lh_header.mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid); lh->lh_sequence = cpu_to_be64(head->lh_sequence + 1); lh->lh_flags = cpu_to_be32(GFS2_LOG_HEAD_UNMOUNT); lh->lh_blkno = cpu_to_be32(lblock); diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index b80c88dedbb..81f90a59cda 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -81,7 +81,11 @@ struct gfs2_meta_header { __be32 mh_type; __be64 __pad0; /* Was generation number in gfs1 */ __be32 mh_format; - __be32 __pad1; /* Was incarnation number in gfs1 */ + /* This union is to keep userspace happy */ + union { + __be32 mh_jid; /* Was incarnation number in gfs1 */ + __be32 __pad1; + }; }; /* From 9ae3c6de6981a1e8765b5d029f94555fc0f0fea0 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Tue, 10 Nov 2009 12:54:56 -0600 Subject: [PATCH 291/298] GFS2: drop rindex glock to refresh rindex list When a gfs2 filesystem is grown, it needs to rebuild the rindex list to be able to use the new space. gfs2 does this when the rindex is marked not uptodate, which happens when the rindex glock is dropped. However, on a single node setup, there is never any reason to drop the rindex glock, so gfs2 never invalidates the the rindex. This patch makes gfs2 automatically drop the rindex glock after filesystem grows, so it can refresh the rindex list. Signed-off-by: Benjamin Marzinski Signed-off-by: Steven Whitehouse --- fs/gfs2/aops.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 694b5d48f03..dce062a0b02 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -819,8 +819,10 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh, mark_inode_dirty(inode); } - if (inode == sdp->sd_rindex) + if (inode == sdp->sd_rindex) { adjust_fs_space(inode); + ip->i_gh.gh_flags |= GL_NOCACHE; + } brelse(dibh); gfs2_trans_end(sdp); @@ -889,8 +891,10 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping, mark_inode_dirty(inode); } - if (inode == sdp->sd_rindex) + if (inode == sdp->sd_rindex) { adjust_fs_space(inode); + ip->i_gh.gh_flags |= GL_NOCACHE; + } brelse(dibh); gfs2_trans_end(sdp); From c29cd9004e72acb5a6cb8caf08508f1c5edee686 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 18 Nov 2009 18:09:41 +0800 Subject: [PATCH 292/298] writeback: remove unused nonblocking and congestion checks (gfs2) No one is calling wb_writeback and write_cache_pages with wbc.nonblocking=1 any more. And lumpy pageout will want to do nonblocking writeback without the congestion wait. Signed-off-by: Wu Fengguang Signed-off-by: Steven Whitehouse --- fs/gfs2/aops.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index dce062a0b02..7b8da941526 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -269,7 +269,6 @@ static int gfs2_write_jdata_pagevec(struct address_space *mapping, pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; unsigned offset = i_size & (PAGE_CACHE_SIZE-1); unsigned nrblocks = nr_pages * (PAGE_CACHE_SIZE/inode->i_sb->s_blocksize); - struct backing_dev_info *bdi = mapping->backing_dev_info; int i; int ret; @@ -313,11 +312,6 @@ static int gfs2_write_jdata_pagevec(struct address_space *mapping, if (ret || (--(wbc->nr_to_write) <= 0)) ret = 1; - if (wbc->nonblocking && bdi_write_congested(bdi)) { - wbc->encountered_congestion = 1; - ret = 1; - } - } gfs2_trans_end(sdp); return ret; @@ -338,7 +332,6 @@ static int gfs2_write_jdata_pagevec(struct address_space *mapping, static int gfs2_write_cache_jdata(struct address_space *mapping, struct writeback_control *wbc) { - struct backing_dev_info *bdi = mapping->backing_dev_info; int ret = 0; int done = 0; struct pagevec pvec; @@ -348,11 +341,6 @@ static int gfs2_write_cache_jdata(struct address_space *mapping, int scanned = 0; int range_whole = 0; - if (wbc->nonblocking && bdi_write_congested(bdi)) { - wbc->encountered_congestion = 1; - return 0; - } - pagevec_init(&pvec, 0); if (wbc->range_cyclic) { index = mapping->writeback_index; /* Start from prev offset */ From 26bb7505cf7db3560286be9f6384b6d3911f78b5 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 27 Nov 2009 10:31:11 +0000 Subject: [PATCH 293/298] GFS2: Fix glock refcount issues This patch fixes some ref counting issues. Firstly by moving the point at which we drop the ref count after a dlm lock operation has completed we ensure that we never call gfs2_glock_hold() on a lock with a zero ref count. Secondly, by using atomic_dec_and_lock() in gfs2_glock_put() we ensure that at no time will a glock with zero ref count appear on the lru_list. That means that we can remove the check for this in our shrinker (which was racy). Signed-off-by: Steven Whitehouse --- fs/gfs2/glock.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index a3f90ad2af8..f455a03a09e 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -241,15 +241,14 @@ int gfs2_glock_put(struct gfs2_glock *gl) int rv = 0; write_lock(gl_lock_addr(gl->gl_hash)); - if (atomic_dec_and_test(&gl->gl_ref)) { + if (atomic_dec_and_lock(&gl->gl_ref, &lru_lock)) { hlist_del(&gl->gl_list); - write_unlock(gl_lock_addr(gl->gl_hash)); - spin_lock(&lru_lock); if (!list_empty(&gl->gl_lru)) { list_del_init(&gl->gl_lru); atomic_dec(&lru_count); } spin_unlock(&lru_lock); + write_unlock(gl_lock_addr(gl->gl_hash)); GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders)); glock_free(gl); rv = 1; @@ -513,7 +512,6 @@ retry: GLOCK_BUG_ON(gl, 1); } spin_unlock(&gl->gl_spin); - gfs2_glock_put(gl); return; } @@ -524,8 +522,6 @@ retry: if (glops->go_xmote_bh) { spin_unlock(&gl->gl_spin); rv = glops->go_xmote_bh(gl, gh); - if (rv == -EAGAIN) - return; spin_lock(&gl->gl_spin); if (rv) { do_error(gl, rv); @@ -540,7 +536,6 @@ out: clear_bit(GLF_LOCK, &gl->gl_flags); out_locked: spin_unlock(&gl->gl_spin); - gfs2_glock_put(gl); } static unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock, @@ -600,7 +595,6 @@ __acquires(&gl->gl_spin) if (!(ret & LM_OUT_ASYNC)) { finish_xmote(gl, ret); - gfs2_glock_hold(gl); if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) gfs2_glock_put(gl); } else { @@ -712,9 +706,12 @@ static void glock_work_func(struct work_struct *work) { unsigned long delay = 0; struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_work.work); + int drop_ref = 0; - if (test_and_clear_bit(GLF_REPLY_PENDING, &gl->gl_flags)) + if (test_and_clear_bit(GLF_REPLY_PENDING, &gl->gl_flags)) { finish_xmote(gl, gl->gl_reply); + drop_ref = 1; + } down_read(&gfs2_umount_flush_sem); spin_lock(&gl->gl_spin); if (test_and_clear_bit(GLF_PENDING_DEMOTE, &gl->gl_flags) && @@ -732,6 +729,8 @@ static void glock_work_func(struct work_struct *work) if (!delay || queue_delayed_work(glock_workqueue, &gl->gl_work, delay) == 0) gfs2_glock_put(gl); + if (drop_ref) + gfs2_glock_put(gl); } /** @@ -1366,10 +1365,6 @@ static int gfs2_shrink_glock_memory(int nr, gfp_t gfp_mask) list_del_init(&gl->gl_lru); atomic_dec(&lru_count); - /* Check if glock is about to be freed */ - if (atomic_read(&gl->gl_ref) == 0) - continue; - /* Test for being demotable */ if (!test_and_set_bit(GLF_LOCK, &gl->gl_flags)) { gfs2_glock_hold(gl); From 38938c879eb0c39edf85d5164aa0cffe2874304c Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 4 Dec 2009 17:44:50 -0800 Subject: [PATCH 294/298] Add support for GCC-4.5's __builtin_unreachable() to compiler.h (v2) Starting with version 4.5, GCC has a new built-in function __builtin_unreachable() that can be used in places like the kernel's BUG() where inline assembly is used to transfer control flow. This eliminated the need for an endless loop in these places. The patch adds a new macro 'unreachable()' that will expand to either __builtin_unreachable() or an endless loop depending on the compiler version. Change from v1: Simplify unreachable() for non-GCC 4.5 case. Signed-off-by: David Daney Acked-by: Ralf Baechle Signed-off-by: Linus Torvalds --- include/linux/compiler-gcc4.h | 14 ++++++++++++++ include/linux/compiler.h | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h index 450fa597c94..ab3af40a53c 100644 --- a/include/linux/compiler-gcc4.h +++ b/include/linux/compiler-gcc4.h @@ -36,4 +36,18 @@ the kernel context */ #define __cold __attribute__((__cold__)) + +#if __GNUC_MINOR__ >= 5 +/* + * Mark a position in code as unreachable. This can be used to + * suppress control flow warnings after asm blocks that transfer + * control elsewhere. + * + * Early snapshots of gcc 4.5 don't support this and we can't detect + * this in the preprocessor, but we can live with this because they're + * unreleased. Really, we need to have autoconf for the kernel. + */ +#define unreachable() __builtin_unreachable() +#endif + #endif diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 04fb5135b4e..59f208926d1 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -144,6 +144,11 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); # define barrier() __memory_barrier() #endif +/* Unreachable code */ +#ifndef unreachable +# define unreachable() do { } while (1) +#endif + #ifndef RELOC_HIDE # define RELOC_HIDE(ptr, off) \ ({ unsigned long __ptr; \ From a5fc5eba4dfcc284e6adcd7fdcd5b43182230d2b Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 4 Dec 2009 17:44:51 -0800 Subject: [PATCH 295/298] x86: Convert BUG() to use unreachable() Use the new unreachable() macro instead of for(;;);. When allyesconfig is built with a GCC-4.5 snapshot on i686 the size of the text segment is reduced by 3987 bytes (from 6827019 to 6823032). Signed-off-by: David Daney Acked-by: "H. Peter Anvin" CC: Thomas Gleixner CC: Ingo Molnar CC: x86@kernel.org Signed-off-by: Linus Torvalds --- arch/x86/include/asm/bug.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h index d9cf1cd156d..f654d1bb17f 100644 --- a/arch/x86/include/asm/bug.h +++ b/arch/x86/include/asm/bug.h @@ -22,14 +22,14 @@ do { \ ".popsection" \ : : "i" (__FILE__), "i" (__LINE__), \ "i" (sizeof(struct bug_entry))); \ - for (;;) ; \ + unreachable(); \ } while (0) #else #define BUG() \ do { \ asm volatile("ud2"); \ - for (;;) ; \ + unreachable(); \ } while (0) #endif From 4ef5651e85589e3aaca704c6d2d7ae7e794e5d25 Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 4 Dec 2009 17:44:52 -0800 Subject: [PATCH 296/298] MIPS: Convert BUG() to use unreachable() Use the new unreachable() macro instead of while(1); Signed-off-by: David Daney Acked-by: Ralf Baechle CC: linux-mips@linux-mips.org Signed-off-by: Linus Torvalds --- arch/mips/include/asm/bug.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/mips/include/asm/bug.h b/arch/mips/include/asm/bug.h index 6cf29c26e87..540c98a810d 100644 --- a/arch/mips/include/asm/bug.h +++ b/arch/mips/include/asm/bug.h @@ -11,9 +11,7 @@ static inline void __noreturn BUG(void) { __asm__ __volatile__("break %0" : : "i" (BRK_BUG)); - /* Fool GCC into thinking the function doesn't return. */ - while (1) - ; + unreachable(); } #define HAVE_ARCH_BUG From 5506e68975c346e55f786b554e28e368cdede444 Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 4 Dec 2009 17:44:53 -0800 Subject: [PATCH 297/298] s390: Convert BUG() to use unreachable() Use the new unreachable() macro instead of for(;;); Signed-off-by: David Daney Acked-by: Martin Schwidefsky CC: Heiko Carstens CC: linux390@de.ibm.com CC: linux-s390@vger.kernel.org Signed-off-by: Linus Torvalds --- arch/s390/include/asm/bug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/include/asm/bug.h b/arch/s390/include/asm/bug.h index 7efd0abe888..efb74fd5156 100644 --- a/arch/s390/include/asm/bug.h +++ b/arch/s390/include/asm/bug.h @@ -49,7 +49,7 @@ #define BUG() do { \ __EMIT_BUG(0); \ - for (;;); \ + unreachable(); \ } while (0) #define WARN_ON(x) ({ \ From 27d16d08717faeaa8afd1b736a096dbaab90f08e Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 4 Dec 2009 17:44:54 -0800 Subject: [PATCH 298/298] avr32: Convert BUG() to use unreachable() Use the new unreachable() macro instead of for(;;); Signed-off-by: David Daney Acked-by: Haavard Skinnemoen Signed-off-by: Linus Torvalds --- arch/avr32/include/asm/bug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/avr32/include/asm/bug.h b/arch/avr32/include/asm/bug.h index 331d45bab18..2aa373cc61b 100644 --- a/arch/avr32/include/asm/bug.h +++ b/arch/avr32/include/asm/bug.h @@ -52,7 +52,7 @@ #define BUG() \ do { \ _BUG_OR_WARN(0); \ - for (;;); \ + unreachable(); \ } while (0) #define WARN_ON(condition) \