From 32300751b4079cb5688453baa94711579d4285d5 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 12 May 2008 21:21:05 +0200 Subject: sched: 1Q08 RCU doc update, add call_rcu_sched() Long-delayed update to the RCU documentation, including adding the new call_rcu_sched() and rcu_barrier_sched() APIs. Signed-off-by: Paul E. McKenney Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- Documentation/RCU/NMI-RCU.txt | 3 ++ Documentation/RCU/RTFP.txt | 108 ++++++++++++++++++++++++++++++++++++++++ Documentation/RCU/checklist.txt | 89 ++++++++++++++++++++++----------- Documentation/RCU/whatisRCU.txt | 58 ++++++++++++++------- 4 files changed, 210 insertions(+), 48 deletions(-) (limited to 'Documentation') diff --git a/Documentation/RCU/NMI-RCU.txt b/Documentation/RCU/NMI-RCU.txt index c64158ecde43..a6d32e65d222 100644 --- a/Documentation/RCU/NMI-RCU.txt +++ b/Documentation/RCU/NMI-RCU.txt @@ -93,6 +93,9 @@ Since NMI handlers disable preemption, synchronize_sched() is guaranteed not to return until all ongoing NMI handlers exit. It is therefore safe to free up the handler's data as soon as synchronize_sched() returns. +Important note: for this to work, the architecture in question must +invoke irq_enter() and irq_exit() on NMI entry and exit, respectively. + Answer to Quick Quiz diff --git a/Documentation/RCU/RTFP.txt b/Documentation/RCU/RTFP.txt index 39ad8f56783a..9f711d2df91b 100644 --- a/Documentation/RCU/RTFP.txt +++ b/Documentation/RCU/RTFP.txt @@ -52,6 +52,10 @@ of each iteration. Unfortunately, chaotic relaxation requires highly structured data, such as the matrices used in scientific programs, and is thus inapplicable to most data structures in operating-system kernels. +In 1992, Henry (now Alexia) Massalin completed a dissertation advising +parallel programmers to defer processing when feasible to simplify +synchronization. RCU makes extremely heavy use of this advice. + In 1993, Jacobson [Jacobson93] verbally described what is perhaps the simplest deferred-free technique: simply waiting a fixed amount of time before freeing blocks awaiting deferred free. Jacobson did not describe @@ -138,6 +142,13 @@ blocking in read-side critical sections appeared [PaulEMcKenney2006c], Robert Olsson described an RCU-protected trie-hash combination [RobertOlsson2006a]. +2007 saw the journal version of the award-winning RCU paper from 2006 +[ThomasEHart2007a], as well as a paper demonstrating use of Promela +and Spin to mechanically verify an optimization to Oleg Nesterov's +QRCU [PaulEMcKenney2007QRCUspin], a design document describing +preemptible RCU [PaulEMcKenney2007PreemptibleRCU], and the three-part +LWN "What is RCU?" series [PaulEMcKenney2007WhatIsRCUFundamentally, +PaulEMcKenney2008WhatIsRCUUsage, and PaulEMcKenney2008WhatIsRCUAPI]. Bibtex Entries @@ -202,6 +213,20 @@ Bibtex Entries ,Year="1991" } +@phdthesis{HMassalinPhD +,author="H. Massalin" +,title="Synthesis: An Efficient Implementation of Fundamental Operating +System Services" +,school="Columbia University" +,address="New York, NY" +,year="1992" +,annotation=" + Mondo optimizing compiler. + Wait-free stuff. + Good advice: defer work to avoid synchronization. +" +} + @unpublished{Jacobson93 ,author="Van Jacobson" ,title="Avoid Read-Side Locking Via Delayed Free" @@ -635,3 +660,86 @@ Revised: " } +@unpublished{PaulEMcKenney2007PreemptibleRCU +,Author="Paul E. McKenney" +,Title="The design of preemptible read-copy-update" +,month="October" +,day="8" +,year="2007" +,note="Available: +\url{http://lwn.net/Articles/253651/} +[Viewed October 25, 2007]" +,annotation=" + LWN article describing the design of preemptible RCU. +" +} + +######################################################################## +# +# "What is RCU?" LWN series. +# + +@unpublished{PaulEMcKenney2007WhatIsRCUFundamentally +,Author="Paul E. McKenney and Jonathan Walpole" +,Title="What is {RCU}, Fundamentally?" +,month="December" +,day="17" +,year="2007" +,note="Available: +\url{http://lwn.net/Articles/262464/} +[Viewed December 27, 2007]" +,annotation=" + Lays out the three basic components of RCU: (1) publish-subscribe, + (2) wait for pre-existing readers to complete, and (2) maintain + multiple versions. +" +} + +@unpublished{PaulEMcKenney2008WhatIsRCUUsage +,Author="Paul E. McKenney" +,Title="What is {RCU}? Part 2: Usage" +,month="January" +,day="4" +,year="2008" +,note="Available: +\url{http://lwn.net/Articles/263130/} +[Viewed January 4, 2008]" +,annotation=" + Lays out six uses of RCU: + 1. RCU is a Reader-Writer Lock Replacement + 2. RCU is a Restricted Reference-Counting Mechanism + 3. RCU is a Bulk Reference-Counting Mechanism + 4. RCU is a Poor Man's Garbage Collector + 5. RCU is a Way of Providing Existence Guarantees + 6. RCU is a Way of Waiting for Things to Finish +" +} + +@unpublished{PaulEMcKenney2008WhatIsRCUAPI +,Author="Paul E. McKenney" +,Title="{RCU} part 3: the {RCU} {API}" +,month="January" +,day="17" +,year="2008" +,note="Available: +\url{http://lwn.net/Articles/264090/} +[Viewed January 10, 2008]" +,annotation=" + Gives an overview of the Linux-kernel RCU API and a brief annotated RCU + bibliography. +" +} + +@article{DinakarGuniguntala2008IBMSysJ +,author="D. Guniguntala and P. E. McKenney and J. Triplett and J. Walpole" +,title="The read-copy-update mechanism for supporting real-time applications on shared-memory multiprocessor systems with {Linux}" +,Year="2008" +,Month="April" +,journal="IBM Systems Journal" +,volume="47" +,number="2" +,pages="@@-@@" +,annotation=" + RCU, realtime RCU, sleepable RCU, performance. +" +} diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt index 42b01bc2e1b4..cf5562cbe356 100644 --- a/Documentation/RCU/checklist.txt +++ b/Documentation/RCU/checklist.txt @@ -13,10 +13,13 @@ over a rather long period of time, but improvements are always welcome! detailed performance measurements show that RCU is nonetheless the right tool for the job. - The other exception would be where performance is not an issue, - and RCU provides a simpler implementation. An example of this - situation is the dynamic NMI code in the Linux 2.6 kernel, - at least on architectures where NMIs are rare. + Another exception is where performance is not an issue, and RCU + provides a simpler implementation. An example of this situation + is the dynamic NMI code in the Linux 2.6 kernel, at least on + architectures where NMIs are rare. + + Yet another exception is where the low real-time latency of RCU's + read-side primitives is critically important. 1. Does the update code have proper mutual exclusion? @@ -39,9 +42,10 @@ over a rather long period of time, but improvements are always welcome! 2. Do the RCU read-side critical sections make proper use of rcu_read_lock() and friends? These primitives are needed - to suppress preemption (or bottom halves, in the case of - rcu_read_lock_bh()) in the read-side critical sections, - and are also an excellent aid to readability. + to prevent grace periods from ending prematurely, which + could result in data being unceremoniously freed out from + under your read-side code, which can greatly increase the + actuarial risk of your kernel. As a rough rule of thumb, any dereference of an RCU-protected pointer must be covered by rcu_read_lock() or rcu_read_lock_bh() @@ -54,15 +58,30 @@ over a rather long period of time, but improvements are always welcome! be running while updates are in progress. There are a number of ways to handle this concurrency, depending on the situation: - a. Make updates appear atomic to readers. For example, + a. Use the RCU variants of the list and hlist update + primitives to add, remove, and replace elements on an + RCU-protected list. Alternatively, use the RCU-protected + trees that have been added to the Linux kernel. + + This is almost always the best approach. + + b. Proceed as in (a) above, but also maintain per-element + locks (that are acquired by both readers and writers) + that guard per-element state. Of course, fields that + the readers refrain from accessing can be guarded by the + update-side lock. + + This works quite well, also. + + c. Make updates appear atomic to readers. For example, pointer updates to properly aligned fields will appear atomic, as will individual atomic primitives. Operations performed under a lock and sequences of multiple atomic primitives will -not- appear to be atomic. - This is almost always the best approach. + This can work, but is starting to get a bit tricky. - b. Carefully order the updates and the reads so that + d. Carefully order the updates and the reads so that readers see valid data at all phases of the update. This is often more difficult than it sounds, especially given modern CPUs' tendency to reorder memory references. @@ -123,18 +142,22 @@ over a rather long period of time, but improvements are always welcome! when publicizing a pointer to a structure that can be traversed by an RCU read-side critical section. -5. If call_rcu(), or a related primitive such as call_rcu_bh(), - is used, the callback function must be written to be called - from softirq context. In particular, it cannot block. +5. If call_rcu(), or a related primitive such as call_rcu_bh() or + call_rcu_sched(), is used, the callback function must be + written to be called from softirq context. In particular, + it cannot block. 6. Since synchronize_rcu() can block, it cannot be called from - any sort of irq context. + any sort of irq context. Ditto for synchronize_sched() and + synchronize_srcu(). 7. If the updater uses call_rcu(), then the corresponding readers must use rcu_read_lock() and rcu_read_unlock(). If the updater uses call_rcu_bh(), then the corresponding readers must use - rcu_read_lock_bh() and rcu_read_unlock_bh(). Mixing things up - will result in confusion and broken kernels. + rcu_read_lock_bh() and rcu_read_unlock_bh(). If the updater + uses call_rcu_sched(), then the corresponding readers must + disable preemption. Mixing things up will result in confusion + and broken kernels. One exception to this rule: rcu_read_lock() and rcu_read_unlock() may be substituted for rcu_read_lock_bh() and rcu_read_unlock_bh() @@ -143,9 +166,9 @@ over a rather long period of time, but improvements are always welcome! such cases is a must, of course! And the jury is still out on whether the increased speed is worth it. -8. Although synchronize_rcu() is a bit slower than is call_rcu(), - it usually results in simpler code. So, unless update - performance is critically important or the updaters cannot block, +8. Although synchronize_rcu() is slower than is call_rcu(), it + usually results in simpler code. So, unless update performance + is critically important or the updaters cannot block, synchronize_rcu() should be used in preference to call_rcu(). An especially important property of the synchronize_rcu() @@ -187,23 +210,23 @@ over a rather long period of time, but improvements are always welcome! number of updates per grace period. 9. All RCU list-traversal primitives, which include - list_for_each_rcu(), list_for_each_entry_rcu(), + rcu_dereference(), list_for_each_rcu(), list_for_each_entry_rcu(), list_for_each_continue_rcu(), and list_for_each_safe_rcu(), - must be within an RCU read-side critical section. RCU + must be either within an RCU read-side critical section or + must be protected by appropriate update-side locks. RCU read-side critical sections are delimited by rcu_read_lock() and rcu_read_unlock(), or by similar primitives such as rcu_read_lock_bh() and rcu_read_unlock_bh(). - Use of the _rcu() list-traversal primitives outside of an - RCU read-side critical section causes no harm other than - a slight performance degradation on Alpha CPUs. It can - also be quite helpful in reducing code bloat when common - code is shared between readers and updaters. + The reason that it is permissible to use RCU list-traversal + primitives when the update-side lock is held is that doing so + can be quite helpful in reducing code bloat when common code is + shared between readers and updaters. 10. Conversely, if you are in an RCU read-side critical section, - you -must- use the "_rcu()" variants of the list macros. - Failing to do so will break Alpha and confuse people reading - your code. + and you don't hold the appropriate update-side lock, you -must- + use the "_rcu()" variants of the list macros. Failing to do so + will break Alpha and confuse people reading your code. 11. Note that synchronize_rcu() -only- guarantees to wait until all currently executing rcu_read_lock()-protected RCU read-side @@ -230,6 +253,14 @@ over a rather long period of time, but improvements are always welcome! must use whatever locking or other synchronization is required to safely access and/or modify that data structure. + RCU callbacks are -usually- executed on the same CPU that executed + the corresponding call_rcu(), call_rcu_bh(), or call_rcu_sched(), + but are by -no- means guaranteed to be. For example, if a given + CPU goes offline while having an RCU callback pending, then that + RCU callback will execute on some surviving CPU. (If this was + not the case, a self-spawning RCU callback would prevent the + victim CPU from ever going offline.) + 14. SRCU (srcu_read_lock(), srcu_read_unlock(), and synchronize_srcu()) may only be invoked from process context. Unlike other forms of RCU, it -is- permissible to block in an SRCU read-side critical diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt index e0d6d99b8f9b..e04d643a9f57 100644 --- a/Documentation/RCU/whatisRCU.txt +++ b/Documentation/RCU/whatisRCU.txt @@ -1,3 +1,11 @@ +Please note that the "What is RCU?" LWN series is an excellent place +to start learning about RCU: + +1. What is RCU, Fundamentally? http://lwn.net/Articles/262464/ +2. What is RCU? Part 2: Usage http://lwn.net/Articles/263130/ +3. RCU part 3: the RCU API http://lwn.net/Articles/264090/ + + What is RCU? RCU is a synchronization mechanism that was added to the Linux kernel @@ -772,26 +780,18 @@ Linux-kernel source code, but it helps to have a full list of the APIs, since there does not appear to be a way to categorize them in docbook. Here is the list, by category. -Markers for RCU read-side critical sections: - - rcu_read_lock - rcu_read_unlock - rcu_read_lock_bh - rcu_read_unlock_bh - srcu_read_lock - srcu_read_unlock - RCU pointer/list traversal: rcu_dereference + list_for_each_entry_rcu + hlist_for_each_entry_rcu + list_for_each_rcu (to be deprecated in favor of list_for_each_entry_rcu) - list_for_each_entry_rcu list_for_each_continue_rcu (to be deprecated in favor of new list_for_each_entry_continue_rcu) - hlist_for_each_entry_rcu -RCU pointer update: +RCU pointer/list update: rcu_assign_pointer list_add_rcu @@ -799,16 +799,36 @@ RCU pointer update: list_del_rcu list_replace_rcu hlist_del_rcu + hlist_add_after_rcu + hlist_add_before_rcu hlist_add_head_rcu + hlist_replace_rcu + list_splice_init_rcu() -RCU grace period: +RCU: Critical sections Grace period Barrier + + rcu_read_lock synchronize_net rcu_barrier + rcu_read_unlock synchronize_rcu + call_rcu + + +bh: Critical sections Grace period Barrier + + rcu_read_lock_bh call_rcu_bh rcu_barrier_bh + rcu_read_unlock_bh + + +sched: Critical sections Grace period Barrier + + [preempt_disable] synchronize_sched rcu_barrier_sched + [and friends] call_rcu_sched + + +SRCU: Critical sections Grace period Barrier + + srcu_read_lock synchronize_srcu N/A + srcu_read_unlock - synchronize_net - synchronize_sched - synchronize_rcu - synchronize_srcu - call_rcu - call_rcu_bh See the comment headers in the source code (or the docbook generated from them) for more information. -- cgit v1.2.3 From 18404756765c713a0be4eb1082920c04822ce588 Mon Sep 17 00:00:00 2001 From: Max Krasnyansky Date: Thu, 29 May 2008 11:02:52 -0700 Subject: genirq: Expose default irq affinity mask (take 3) Current IRQ affinity interface does not provide a way to set affinity for the IRQs that will be allocated/activated in the future. This patch creates /proc/irq/default_smp_affinity that lets users set default affinity mask for the newly allocated IRQs. Changing the default does not affect affinity masks for the currently active IRQs, they have to be changed explicitly. Updated based on Paul J's comments and added some more documentation. Signed-off-by: Max Krasnyansky Cc: pj@sgi.com Cc: a.p.zijlstra@chello.nl Cc: tglx@linutronix.de Cc: rdunlap@xenotime.net Cc: mingo@elte.hu Signed-off-by: Thomas Gleixner --- Documentation/IRQ-affinity.txt | 37 ++++++++++++++++++------ Documentation/filesystems/proc.txt | 29 ++++++++++++------- arch/alpha/kernel/irq.c | 5 ++-- include/linux/interrupt.h | 5 ++++ include/linux/irq.h | 9 ------ kernel/irq/manage.c | 28 ++++++++++++++++-- kernel/irq/proc.c | 59 +++++++++++++++++++++++++++++++++++--- 7 files changed, 134 insertions(+), 38 deletions(-) (limited to 'Documentation') diff --git a/Documentation/IRQ-affinity.txt b/Documentation/IRQ-affinity.txt index 938d7dd05490..b4a615b78403 100644 --- a/Documentation/IRQ-affinity.txt +++ b/Documentation/IRQ-affinity.txt @@ -1,17 +1,26 @@ +ChangeLog: + Started by Ingo Molnar + Update by Max Krasnyansky -SMP IRQ affinity, started by Ingo Molnar - +SMP IRQ affinity /proc/irq/IRQ#/smp_affinity specifies which target CPUs are permitted for a given IRQ source. It's a bitmask of allowed CPUs. It's not allowed to turn off all CPUs, and if an IRQ controller does not support IRQ affinity then the value will not change from the default 0xffffffff. +/proc/irq/default_smp_affinity specifies default affinity mask that applies +to all non-active IRQs. Once IRQ is allocated/activated its affinity bitmask +will be set to the default mask. It can then be changed as described above. +Default mask is 0xffffffff. + Here is an example of restricting IRQ44 (eth1) to CPU0-3 then restricting -the IRQ to CPU4-7 (this is an 8-CPU SMP box): +it to CPU4-7 (this is an 8-CPU SMP box): +[root@moon 44]# cd /proc/irq/44 [root@moon 44]# cat smp_affinity ffffffff + [root@moon 44]# echo 0f > smp_affinity [root@moon 44]# cat smp_affinity 0000000f @@ -21,17 +30,27 @@ PING hell (195.4.7.3): 56 data bytes --- hell ping statistics --- 6029 packets transmitted, 6027 packets received, 0% packet loss round-trip min/avg/max = 0.1/0.1/0.4 ms -[root@moon 44]# cat /proc/interrupts | grep 44: - 44: 0 1785 1785 1783 1783 1 -1 0 IO-APIC-level eth1 +[root@moon 44]# cat /proc/interrupts | grep 'CPU\|44:' + CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 + 44: 1068 1785 1785 1783 0 0 0 0 IO-APIC-level eth1 + +As can be seen from the line above IRQ44 was delivered only to the first four +processors (0-3). +Now lets restrict that IRQ to CPU(4-7). + [root@moon 44]# echo f0 > smp_affinity +[root@moon 44]# cat smp_affinity +000000f0 [root@moon 44]# ping -f h PING hell (195.4.7.3): 56 data bytes .. --- hell ping statistics --- 2779 packets transmitted, 2777 packets received, 0% packet loss round-trip min/avg/max = 0.1/0.5/585.4 ms -[root@moon 44]# cat /proc/interrupts | grep 44: - 44: 1068 1785 1785 1784 1784 1069 1070 1069 IO-APIC-level eth1 -[root@moon 44]# +[root@moon 44]# cat /proc/interrupts | 'CPU\|44:' + CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 + 44: 1068 1785 1785 1783 1784 1069 1070 1069 IO-APIC-level eth1 + +This time around IRQ44 was delivered only to the last four processors. +i.e counters for the CPU0-3 did not change. diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index dbc3c6a3650f..7f268f327d75 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -380,28 +380,35 @@ i386 and x86_64 platforms support the new IRQ vector displays. Of some interest is the introduction of the /proc/irq directory to 2.4. It could be used to set IRQ to CPU affinity, this means that you can "hook" an IRQ to only one CPU, or to exclude a CPU of handling IRQs. The contents of the -irq subdir is one subdir for each IRQ, and one file; prof_cpu_mask +irq subdir is one subdir for each IRQ, and two files; default_smp_affinity and +prof_cpu_mask. For example > ls /proc/irq/ 0 10 12 14 16 18 2 4 6 8 prof_cpu_mask - 1 11 13 15 17 19 3 5 7 9 + 1 11 13 15 17 19 3 5 7 9 default_smp_affinity > ls /proc/irq/0/ smp_affinity -The contents of the prof_cpu_mask file and each smp_affinity file for each IRQ -is the same by default: +smp_affinity is a bitmask, in which you can specify which CPUs can handle the +IRQ, you can set it by doing: - > cat /proc/irq/0/smp_affinity - ffffffff + > echo 1 > /proc/irq/10/smp_affinity + +This means that only the first CPU will handle the IRQ, but you can also echo +5 which means that only the first and fourth CPU can handle the IRQ. -It's a bitmask, in which you can specify which CPUs can handle the IRQ, you can -set it by doing: +The contents of each smp_affinity file is the same by default: + + > cat /proc/irq/0/smp_affinity + ffffffff - > echo 1 > /proc/irq/prof_cpu_mask +The default_smp_affinity mask applies to all non-active IRQs, which are the +IRQs which have not yet been allocated/activated, and hence which lack a +/proc/irq/[0-9]* directory. -This means that only the first CPU will handle the IRQ, but you can also echo 5 -which means that only the first and fourth CPU can handle the IRQ. +prof_cpu_mask specifies which CPUs are to be profiled by the system wide +profiler. Default value is ffffffff (all cpus). The way IRQs are routed is handled by the IO-APIC, and it's Round Robin between all the CPUs which are allowed to handle it. As usual the kernel has diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c index facf82a5499a..c626a821cdcb 100644 --- a/arch/alpha/kernel/irq.c +++ b/arch/alpha/kernel/irq.c @@ -42,8 +42,7 @@ void ack_bad_irq(unsigned int irq) #ifdef CONFIG_SMP static char irq_user_affinity[NR_IRQS]; -int -select_smp_affinity(unsigned int irq) +int irq_select_affinity(unsigned int irq) { static int last_cpu; int cpu = last_cpu + 1; @@ -51,7 +50,7 @@ select_smp_affinity(unsigned int irq) if (!irq_desc[irq].chip->set_affinity || irq_user_affinity[irq]) return 1; - while (!cpu_possible(cpu)) + while (!cpu_possible(cpu) || !cpu_isset(cpu, irq_default_affinity)) cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0); last_cpu = cpu; diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index f1fc7470d26c..043400f3d458 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -104,8 +104,11 @@ extern void enable_irq(unsigned int irq); #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS) +extern cpumask_t irq_default_affinity; + extern int irq_set_affinity(unsigned int irq, cpumask_t cpumask); extern int irq_can_set_affinity(unsigned int irq); +extern int irq_select_affinity(unsigned int irq); #else /* CONFIG_SMP */ @@ -119,6 +122,8 @@ static inline int irq_can_set_affinity(unsigned int irq) return 0; } +static inline int irq_select_affinity(unsigned int irq) { return 0; } + #endif /* CONFIG_SMP && CONFIG_GENERIC_HARDIRQS */ #ifdef CONFIG_GENERIC_HARDIRQS diff --git a/include/linux/irq.h b/include/linux/irq.h index 552e0ec269c9..8ccb462ea42c 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -244,15 +244,6 @@ static inline void set_balance_irq_affinity(unsigned int irq, cpumask_t mask) } #endif -#ifdef CONFIG_AUTO_IRQ_AFFINITY -extern int select_smp_affinity(unsigned int irq); -#else -static inline int select_smp_affinity(unsigned int irq) -{ - return 1; -} -#endif - extern int no_irq_affinity; static inline int irq_balancing_disabled(unsigned int irq) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 46d6611a33bb..469814e9b9ee 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -17,6 +17,8 @@ #ifdef CONFIG_SMP +cpumask_t irq_default_affinity = CPU_MASK_ALL; + /** * synchronize_irq - wait for pending IRQ handlers (on other CPUs) * @irq: interrupt number to wait for @@ -95,6 +97,27 @@ int irq_set_affinity(unsigned int irq, cpumask_t cpumask) return 0; } +#ifndef CONFIG_AUTO_IRQ_AFFINITY +/* + * Generic version of the affinity autoselector. + */ +int irq_select_affinity(unsigned int irq) +{ + cpumask_t mask; + + if (!irq_can_set_affinity(irq)) + return 0; + + cpus_and(mask, cpu_online_map, irq_default_affinity); + + irq_desc[irq].affinity = mask; + irq_desc[irq].chip->set_affinity(irq, mask); + + set_balance_irq_affinity(irq, mask); + return 0; +} +#endif + #endif /** @@ -382,6 +405,9 @@ int setup_irq(unsigned int irq, struct irqaction *new) } else /* Undo nested disables: */ desc->depth = 1; + + /* Set default affinity mask once everything is setup */ + irq_select_affinity(irq); } /* Reset broken irq detection when installing new handler */ desc->irq_count = 0; @@ -571,8 +597,6 @@ int request_irq(unsigned int irq, irq_handler_t handler, action->next = NULL; action->dev_id = dev_id; - select_smp_affinity(irq); - #ifdef CONFIG_DEBUG_SHIRQ if (irqflags & IRQF_SHARED) { /* diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index c2f2ccb0549a..6c6d35d68ee9 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -44,7 +44,7 @@ static int irq_affinity_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data) { unsigned int irq = (int)(long)data, full_count = count, err; - cpumask_t new_value, tmp; + cpumask_t new_value; if (!irq_desc[irq].chip->set_affinity || no_irq_affinity || irq_balancing_disabled(irq)) @@ -62,17 +62,51 @@ static int irq_affinity_write_proc(struct file *file, const char __user *buffer, * way to make the system unusable accidentally :-) At least * one online CPU still has to be targeted. */ - cpus_and(tmp, new_value, cpu_online_map); - if (cpus_empty(tmp)) + if (!cpus_intersects(new_value, cpu_online_map)) /* Special case for empty set - allow the architecture code to set default SMP affinity. */ - return select_smp_affinity(irq) ? -EINVAL : full_count; + return irq_select_affinity(irq) ? -EINVAL : full_count; irq_set_affinity(irq, new_value); return full_count; } +static int default_affinity_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = cpumask_scnprintf(page, count, irq_default_affinity); + if (count - len < 2) + return -EINVAL; + len += sprintf(page + len, "\n"); + return len; +} + +static int default_affinity_write(struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + unsigned int full_count = count, err; + cpumask_t new_value; + + err = cpumask_parse_user(buffer, count, new_value); + if (err) + return err; + + if (!is_affinity_mask_valid(new_value)) + return -EINVAL; + + /* + * Do not allow disabling IRQs completely - it's a too easy + * way to make the system unusable accidentally :-) At least + * one online CPU still has to be targeted. + */ + if (!cpus_intersects(new_value, cpu_online_map)) + return -EINVAL; + + irq_default_affinity = new_value; + + return full_count; +} #endif static int irq_spurious_read(char *page, char **start, off_t off, @@ -171,6 +205,21 @@ void unregister_handler_proc(unsigned int irq, struct irqaction *action) remove_proc_entry(action->dir->name, irq_desc[irq].dir); } +void register_default_affinity_proc(void) +{ +#ifdef CONFIG_SMP + struct proc_dir_entry *entry; + + /* create /proc/irq/default_smp_affinity */ + entry = create_proc_entry("default_smp_affinity", 0600, root_irq_dir); + if (entry) { + entry->data = NULL; + entry->read_proc = default_affinity_read; + entry->write_proc = default_affinity_write; + } +#endif +} + void init_irq_proc(void) { int i; @@ -180,6 +229,8 @@ void init_irq_proc(void) if (!root_irq_dir) return; + register_default_affinity_proc(); + /* * Create entries for all existing IRQs. */ -- cgit v1.2.3 From c50cbb05a05cf1f9ca3592272eff053c847727d8 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 4 Jun 2008 21:47:29 -0700 Subject: cpu topology: always define CPU topology information This can result in an empty topology directory in sysfs, and requires in-kernel users to protect all uses with #ifdef - see . The documentation of CPU topology specifies what the defaults should be if only partial information is available from the hardware. So we can provide these defaults as a fallback. This patch: - Adds default definitions of the 4 topology macros to - Changes drivers/base/topology.c to use the topology macros unconditionally and to cope with definitions that aren't lvalues - Updates documentation accordingly [ From: Andrew Morton - fold now-duplicated code - fix layout ] Signed-off-by: Ben Hutchings Cc: Vegard Nossum Cc: Nick Piggin Cc: Chandra Seetharaman Cc: Suresh Siddha Cc: Mike Travis Cc: Christoph Lameter Cc: John Hawkes Cc: Zhang, Yanmin Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar --- Documentation/cputopology.txt | 26 +++++++++----------------- drivers/base/topology.c | 38 ++++++++++---------------------------- include/linux/topology.h | 13 +++++++++++++ 3 files changed, 32 insertions(+), 45 deletions(-) (limited to 'Documentation') diff --git a/Documentation/cputopology.txt b/Documentation/cputopology.txt index b61cb9564023..bd699da24666 100644 --- a/Documentation/cputopology.txt +++ b/Documentation/cputopology.txt @@ -14,9 +14,8 @@ represent the thread siblings to cpu X in the same physical package; To implement it in an architecture-neutral way, a new source file, drivers/base/topology.c, is to export the 4 attributes. -If one architecture wants to support this feature, it just needs to -implement 4 defines, typically in file include/asm-XXX/topology.h. -The 4 defines are: +For an architecture to support this feature, it must define some of +these macros in include/asm-XXX/topology.h: #define topology_physical_package_id(cpu) #define topology_core_id(cpu) #define topology_thread_siblings(cpu) @@ -25,17 +24,10 @@ The 4 defines are: The type of **_id is int. The type of siblings is cpumask_t. -To be consistent on all architectures, the 4 attributes should have -default values if their values are unavailable. Below is the rule. -1) physical_package_id: If cpu has no physical package id, -1 is the -default value. -2) core_id: If cpu doesn't support multi-core, its core id is 0. -3) thread_siblings: Just include itself, if the cpu doesn't support -HT/multi-thread. -4) core_siblings: Just include itself, if the cpu doesn't support -multi-core and HT/Multi-thread. - -So be careful when declaring the 4 defines in include/asm-XXX/topology.h. - -If an attribute isn't defined on an architecture, it won't be exported. - +To be consistent on all architectures, include/linux/topology.h +provides default definitions for any of the above macros that are +not defined by include/asm-XXX/topology.h: +1) physical_package_id: -1 +2) core_id: 0 +3) thread_siblings: just the given CPU +4) core_siblings: just the given CPU diff --git a/drivers/base/topology.c b/drivers/base/topology.c index fdf4044d2e74..24d29a9fc25b 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -59,60 +59,42 @@ static ssize_t show_cpumap(int type, cpumask_t *mask, char *buf) static inline ssize_t show_##name(struct sys_device *dev, char *buf) \ { \ unsigned int cpu = dev->id; \ - return show_cpumap(0, &(topology_##name(cpu)), buf); \ + cpumask_t siblings = topology_##name(cpu); \ + return show_cpumap(0, &siblings, buf); \ } #define define_siblings_show_list(name) \ static inline ssize_t show_##name##_list(struct sys_device *dev, char *buf) \ { \ unsigned int cpu = dev->id; \ - return show_cpumap(1, &(topology_##name(cpu)), buf); \ + cpumask_t siblings = topology_##name(cpu); \ + return show_cpumap(1, &siblings, buf); \ } #define define_siblings_show_func(name) \ define_siblings_show_map(name); define_siblings_show_list(name) -#ifdef topology_physical_package_id define_id_show_func(physical_package_id); define_one_ro(physical_package_id); -#define ref_physical_package_id_attr &attr_physical_package_id.attr, -#else -#define ref_physical_package_id_attr -#endif -#ifdef topology_core_id define_id_show_func(core_id); define_one_ro(core_id); -#define ref_core_id_attr &attr_core_id.attr, -#else -#define ref_core_id_attr -#endif -#ifdef topology_thread_siblings define_siblings_show_func(thread_siblings); define_one_ro(thread_siblings); define_one_ro(thread_siblings_list); -#define ref_thread_siblings_attr \ - &attr_thread_siblings.attr, &attr_thread_siblings_list.attr, -#else -#define ref_thread_siblings_attr -#endif -#ifdef topology_core_siblings define_siblings_show_func(core_siblings); define_one_ro(core_siblings); define_one_ro(core_siblings_list); -#define ref_core_siblings_attr \ - &attr_core_siblings.attr, &attr_core_siblings_list.attr, -#else -#define ref_core_siblings_attr -#endif static struct attribute *default_attrs[] = { - ref_physical_package_id_attr - ref_core_id_attr - ref_thread_siblings_attr - ref_core_siblings_attr + &attr_physical_package_id.attr, + &attr_core_id.attr, + &attr_thread_siblings.attr, + &attr_thread_siblings_list.attr, + &attr_core_siblings.attr, + &attr_core_siblings_list.attr, NULL }; diff --git a/include/linux/topology.h b/include/linux/topology.h index 24f3d2282e11..2158fc0d5a56 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -179,4 +179,17 @@ void arch_update_cpu_topology(void); #endif #endif /* CONFIG_NUMA */ +#ifndef topology_physical_package_id +#define topology_physical_package_id(cpu) ((void)(cpu), -1) +#endif +#ifndef topology_core_id +#define topology_core_id(cpu) ((void)(cpu), 0) +#endif +#ifndef topology_thread_siblings +#define topology_thread_siblings(cpu) cpumask_of_cpu(cpu) +#endif +#ifndef topology_core_siblings +#define topology_core_siblings(cpu) cpumask_of_cpu(cpu) +#endif + #endif /* _LINUX_TOPOLOGY_H */ -- cgit v1.2.3 From d120f65f3aaf306c957bc4c82e510f5b0f1e9b27 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 18 Jun 2008 05:21:44 -0700 Subject: rcu: make rcutorture more vicious: add stutter feature This patch takes a step towards making rcutorture more brutal by allowing the test to be automatically periodically paused, with the default being to run the test for five seconds then pause for five seconds and repeat. This behavior can be controlled using a new "stutter" module parameter, so that "stutter=0" gives the old default behavior of running continuously. Starting and stopping rcutorture more heavily stresses RCU's interaction with the scheduler, as well as exercising more paths through the grace-period detection code. Note that the default to "shuffle_interval" has also been adjusted from 5 seconds to 3 seconds to provide varying overlap with the "stutter" interval. I am still unable to provoke the failures that Alexey has been seeing, even with this patch, but will be doing a few additional things to beef up rcutorture. Suggested-by: Ingo Molnar Signed-off-by: Paul E. McKenney Signed-off-by: Ingo Molnar --- Documentation/RCU/torture.txt | 8 +++++- kernel/rcutorture.c | 59 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 63 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt index 2967a65269d8..02b3d14c0209 100644 --- a/Documentation/RCU/torture.txt +++ b/Documentation/RCU/torture.txt @@ -46,9 +46,15 @@ stat_interval The number of seconds between output of torture shuffle_interval The number of seconds to keep the test threads affinitied - to a particular subset of the CPUs, defaults to 5 seconds. + to a particular subset of the CPUs, defaults to 3 seconds. Used in conjunction with test_no_idle_hz. +stutter The length of time to run the test before pausing for this + same period of time. Defaults to "stutter=5", so as + to run and pause for (roughly) five-second intervals. + Specifying "stutter=0" causes the test to run continuously + without pausing, which is the old default behavior. + test_no_idle_hz Whether or not to test the ability of RCU to operate in a kernel that disables the scheduling-clock interrupt to idle CPUs. Boolean parameter, "1" to test, "0" otherwise. diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 0ca7e9b290b0..98ae7d168225 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -57,7 +57,8 @@ static int stat_interval; /* Interval between stats, in seconds. */ /* Defaults to "only at end of test". */ static int verbose; /* Print more debug info. */ static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */ -static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/ +static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/ +static int stutter = 5; /* Start/stop testing interval (in sec) */ static char *torture_type = "rcu"; /* What RCU implementation to torture. */ module_param(nreaders, int, 0444); @@ -72,6 +73,8 @@ module_param(test_no_idle_hz, bool, 0444); MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs"); module_param(shuffle_interval, int, 0444); MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles"); +module_param(stutter, int, 0444); +MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test"); module_param(torture_type, charp, 0444); MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)"); @@ -91,6 +94,7 @@ static struct task_struct **fakewriter_tasks; static struct task_struct **reader_tasks; static struct task_struct *stats_task; static struct task_struct *shuffler_task; +static struct task_struct *stutter_task; #define RCU_TORTURE_PIPE_LEN 10 @@ -119,6 +123,8 @@ static atomic_t n_rcu_torture_mberror; static atomic_t n_rcu_torture_error; static struct list_head rcu_torture_removed; +static int stutter_pause_test = 0; + /* * Allocate an element from the rcu_tortures pool. */ @@ -179,6 +185,13 @@ rcu_random(struct rcu_random_state *rrsp) return swahw32(rrsp->rrs_state); } +static void +rcu_stutter_wait(void) +{ + while (stutter_pause_test) + schedule_timeout_interruptible(1); +} + /* * Operations vector for selecting different types of tests. */ @@ -563,6 +576,7 @@ rcu_torture_writer(void *arg) } rcu_torture_current_version++; oldbatch = cur_ops->completed(); + rcu_stutter_wait(); } while (!kthread_should_stop() && !fullstop); VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping"); while (!kthread_should_stop()) @@ -586,6 +600,7 @@ rcu_torture_fakewriter(void *arg) schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10); udelay(rcu_random(&rand) & 0x3ff); cur_ops->sync(); + rcu_stutter_wait(); } while (!kthread_should_stop() && !fullstop); VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping"); @@ -641,6 +656,7 @@ rcu_torture_reader(void *arg) preempt_enable(); cur_ops->readunlock(idx); schedule(); + rcu_stutter_wait(); } while (!kthread_should_stop() && !fullstop); VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping"); while (!kthread_should_stop()) @@ -812,15 +828,34 @@ rcu_torture_shuffle(void *arg) return 0; } +/* Cause the rcutorture test to "stutter", starting and stopping all + * threads periodically. + */ +static int +rcu_torture_stutter(void *arg) +{ + VERBOSE_PRINTK_STRING("rcu_torture_stutter task started"); + do { + schedule_timeout_interruptible(stutter * HZ); + stutter_pause_test = 1; + if (!kthread_should_stop()) + schedule_timeout_interruptible(stutter * HZ); + stutter_pause_test = 0; + } while (!kthread_should_stop()); + VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping"); + return 0; +} + static inline void rcu_torture_print_module_parms(char *tag) { printk(KERN_ALERT "%s" TORTURE_FLAG "--- %s: nreaders=%d nfakewriters=%d " "stat_interval=%d verbose=%d test_no_idle_hz=%d " - "shuffle_interval = %d\n", + "shuffle_interval=%d stutter=%d\n", torture_type, tag, nrealreaders, nfakewriters, - stat_interval, verbose, test_no_idle_hz, shuffle_interval); + stat_interval, verbose, test_no_idle_hz, shuffle_interval, + stutter); } static void @@ -829,6 +864,11 @@ rcu_torture_cleanup(void) int i; fullstop = 1; + if (stutter_task) { + VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task"); + kthread_stop(stutter_task); + } + stutter_task = NULL; if (shuffler_task) { VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task"); kthread_stop(shuffler_task); @@ -1017,6 +1057,19 @@ rcu_torture_init(void) goto unwind; } } + if (stutter < 0) + stutter = 0; + if (stutter) { + /* Create the stutter thread */ + stutter_task = kthread_run(rcu_torture_stutter, NULL, + "rcu_torture_stutter"); + if (IS_ERR(stutter_task)) { + firsterr = PTR_ERR(stutter_task); + VERBOSE_PRINTK_ERRSTRING("Failed to create stutter"); + stutter_task = NULL; + goto unwind; + } + } return 0; unwind: -- cgit v1.2.3 From 31a72bce0bd6f3e0114009288bccbc96376eeeca Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 18 Jun 2008 09:26:49 -0700 Subject: rcu: make rcutorture more vicious: reinstate boot-time testing This patch re-institutes the ability to build rcutorture directly into the Linux kernel. The reason that this capability was removed was that this could result in your kernel being pretty much useless, as rcutorture would be running starting from early boot. This problem has been avoided by (1) making rcutorture run only three seconds of every six by default, (2) adding a CONFIG_RCU_TORTURE_TEST_RUNNABLE that permits rcutorture to be quiesced at boot time, and (3) adding a sysctl in /proc named /proc/sys/kernel/rcutorture_runnable that permits rcutorture to be quiesced and unquiesced when built into the kernel. Please note that this /proc file is -not- available when rcutorture is built as a module. Please also note that to get the earlier take-no-prisoners behavior, you must use the boot command line to set rcutorture's "stutter" parameter to zero. The rcutorture quiescing mechanism is currently quite crude: loops in each rcutorture process that poll a global variable once per tick. Suggestions for improvement are welcome. The default action will be to reduce the polling rate to a few times per second. Signed-off-by: Paul E. McKenney Suggested-by: Ingo Molnar Signed-off-by: Ingo Molnar --- Documentation/RCU/torture.txt | 21 ++++++++++++++------- kernel/rcutorture.c | 9 ++++++++- kernel/sysctl.c | 13 +++++++++++++ lib/Kconfig.debug | 21 +++++++++++++++++++-- 4 files changed, 54 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt index 02b3d14c0209..516527d4bc55 100644 --- a/Documentation/RCU/torture.txt +++ b/Documentation/RCU/torture.txt @@ -10,13 +10,20 @@ status messages via printk(), which can be examined via the dmesg command (perhaps grepping for "torture"). The test is started when the module is loaded, and stops when the module is unloaded. -However, actually setting this config option to "y" results in the system -running the test immediately upon boot, and ending only when the system -is taken down. Normally, one will instead want to build the system -with CONFIG_RCU_TORTURE_TEST=m and to use modprobe and rmmod to control -the test, perhaps using a script similar to the one shown at the end of -this document. Note that you will need CONFIG_MODULE_UNLOAD in order -to be able to end the test. +CONFIG_RCU_TORTURE_TEST_RUNNABLE + +It is also possible to specify CONFIG_RCU_TORTURE_TEST=y, which will +result in the tests being loaded into the base kernel. In this case, +the CONFIG_RCU_TORTURE_TEST_RUNNABLE config option is used to specify +whether the RCU torture tests are to be started immediately during +boot or whether the /proc/sys/kernel/rcutorture_runnable file is used +to enable them. This /proc file can be used to repeatedly pause and +restart the tests, regardless of the initial state specified by the +CONFIG_RCU_TORTURE_TEST_RUNNABLE config option. + +You will normally -not- want to start the RCU torture tests during boot +(and thus the default is CONFIG_RCU_TORTURE_TEST_RUNNABLE=n), but doing +this can sometimes be useful in finding boot-time bugs. MODULE PARAMETERS diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 98ae7d168225..27003e2421c7 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -125,6 +125,13 @@ static struct list_head rcu_torture_removed; static int stutter_pause_test = 0; +#if defined(MODULE) || defined(CONFIG_RCU_TORTURE_TEST_RUNNABLE) +#define RCUTORTURE_RUNNABLE_INIT 1 +#else +#define RCUTORTURE_RUNNABLE_INIT 0 +#endif +int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT; + /* * Allocate an element from the rcu_tortures pool. */ @@ -188,7 +195,7 @@ rcu_random(struct rcu_random_state *rrsp) static void rcu_stutter_wait(void) { - while (stutter_pause_test) + while (stutter_pause_test || !rcutorture_runnable) schedule_timeout_interruptible(1); } diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 29116652dca8..c6887cf135c8 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -82,6 +82,9 @@ extern int maps_protect; extern int sysctl_stat_interval; extern int latencytop_enabled; extern int sysctl_nr_open_min, sysctl_nr_open_max; +#ifdef CONFIG_RCU_TORTURE_TEST +extern int rcutorture_runnable; +#endif /* #ifdef CONFIG_RCU_TORTURE_TEST */ /* Constants used for minimum and maximum */ #if defined(CONFIG_DETECT_SOFTLOCKUP) || defined(CONFIG_HIGHMEM) @@ -813,6 +816,16 @@ static struct ctl_table kern_table[] = { .child = key_sysctls, }, #endif +#ifdef CONFIG_RCU_TORTURE_TEST + { + .ctl_name = CTL_UNNUMBERED, + .procname = "rcutorture_runnable", + .data = &rcutorture_runnable, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#endif /* * NOTE: do not add new entries to this table unless you have read * Documentation/sysctl/ctl_unnumbered.txt diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index f51ba2fa2662..c35a86a516a0 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -537,11 +537,28 @@ config RCU_TORTURE_TEST on the RCU infrastructure. The kernel module may be built after the fact on the running kernel to be tested, if desired. - Say Y here if you want RCU torture tests to start automatically - at boot time (you probably don't). + Say Y here if you want RCU torture tests to be built into + the kernel. Say M if you want the RCU torture tests to build as a module. Say N if you are unsure. +config RCU_TORTURE_TEST_RUNNABLE + bool "torture tests for RCU runnable by default" + depends on RCU_TORTURE_TEST = y + default n + help + This option provides a way to build the RCU torture tests + directly into the kernel without them starting up at boot + time. You can use /proc/sys/kernel/rcutorture_runnable + to manually override this setting. This /proc file is + available only when the RCU torture tests have been built + into the kernel. + + Say Y here if you want the RCU torture tests to start during + boot (you probably don't). + Say N here if you want the RCU torture tests to start only + after being manually enabled via /proc. + config KPROBES_SANITY_TEST bool "Kprobes sanity tests" depends on DEBUG_KERNEL -- cgit v1.2.3 From 0729fbf3bc70870370b4f43d652f05a468dc68b8 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 25 Jun 2008 12:24:52 -0700 Subject: rcu: make rcutorture even more vicious: invoke RCU readers from irq handlers (timers) This patch allows torturing RCU from irq handlers (timers, in this case). A new module parameter irqreader enables such additional torturing, and is enabled by default. Variants of RCU that do not tolerate readers being called from irq handlers (e.g., SRCU) ignore irqreader. Signed-off-by: Paul E. McKenney Cc: josh@freedesktop.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: dino@in.ibm.com Cc: akpm@linux-foundation.org Cc: torvalds@linux-foundation.org Cc: vegard.nossum@gmail.com Cc: adobriyan@gmail.com Cc: oleg@tv-sign.ru Cc: bunk@kernel.org Cc: rjw@sisk.pl Signed-off-by: Ingo Molnar --- Documentation/RCU/torture.txt | 23 ++++++++------ kernel/rcutorture.c | 74 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 84 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt index 516527d4bc55..a342b6e1cc10 100644 --- a/Documentation/RCU/torture.txt +++ b/Documentation/RCU/torture.txt @@ -30,10 +30,10 @@ MODULE PARAMETERS This module has the following parameters: -nreaders This is the number of RCU reading threads supported. - The default is twice the number of CPUs. Why twice? - To properly exercise RCU implementations with preemptible - read-side critical sections. +irqreaders Says to invoke RCU readers from irq level. This is currently + done via timers. Defaults to "1" for variants of RCU that + permit this. (Or, more accurately, variants of RCU that do + -not- permit this know to ignore this variable.) nfakewriters This is the number of RCU fake writer threads to run. Fake writer threads repeatedly use the synchronous "wait for @@ -44,6 +44,16 @@ nfakewriters This is the number of RCU fake writer threads to run. Fake to trigger special cases caused by multiple writers, such as the synchronize_srcu() early return optimization. +nreaders This is the number of RCU reading threads supported. + The default is twice the number of CPUs. Why twice? + To properly exercise RCU implementations with preemptible + read-side critical sections. + +shuffle_interval + The number of seconds to keep the test threads affinitied + to a particular subset of the CPUs, defaults to 3 seconds. + Used in conjunction with test_no_idle_hz. + stat_interval The number of seconds between output of torture statistics (via printk()). Regardless of the interval, statistics are printed when the module is unloaded. @@ -51,11 +61,6 @@ stat_interval The number of seconds between output of torture be printed -only- when the module is unloaded, and this is the default. -shuffle_interval - The number of seconds to keep the test threads affinitied - to a particular subset of the CPUs, defaults to 3 seconds. - Used in conjunction with test_no_idle_hz. - stutter The length of time to run the test before pausing for this same period of time. Defaults to "stutter=5", so as to run and pause for (roughly) five-second intervals. diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 5e954edf0ed5..90b5b123f7a1 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -59,6 +59,7 @@ static int verbose; /* Print more debug info. */ static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */ static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/ static int stutter = 5; /* Start/stop testing interval (in sec) */ +static int irqreader = 1; /* RCU readers from irq (timers). */ static char *torture_type = "rcu"; /* What RCU implementation to torture. */ module_param(nreaders, int, 0444); @@ -75,6 +76,8 @@ module_param(shuffle_interval, int, 0444); MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles"); module_param(stutter, int, 0444); MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test"); +module_param(irqreader, int, 0444); +MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers"); module_param(torture_type, charp, 0444); MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)"); @@ -121,6 +124,7 @@ static atomic_t n_rcu_torture_alloc_fail; static atomic_t n_rcu_torture_free; static atomic_t n_rcu_torture_mberror; static atomic_t n_rcu_torture_error; +static long n_rcu_torture_timers = 0; static struct list_head rcu_torture_removed; static int stutter_pause_test = 0; @@ -217,6 +221,7 @@ struct rcu_torture_ops { void (*sync)(void); void (*cb_barrier)(void); int (*stats)(char *page); + int irqcapable; char *name; }; static struct rcu_torture_ops *cur_ops = NULL; @@ -291,6 +296,7 @@ static struct rcu_torture_ops rcu_ops = { .sync = synchronize_rcu, .cb_barrier = rcu_barrier, .stats = NULL, + .irqcapable = 1, .name = "rcu" }; @@ -331,6 +337,7 @@ static struct rcu_torture_ops rcu_sync_ops = { .sync = synchronize_rcu, .cb_barrier = NULL, .stats = NULL, + .irqcapable = 1, .name = "rcu_sync" }; @@ -392,6 +399,7 @@ static struct rcu_torture_ops rcu_bh_ops = { .sync = rcu_bh_torture_synchronize, .cb_barrier = rcu_barrier_bh, .stats = NULL, + .irqcapable = 1, .name = "rcu_bh" }; @@ -406,6 +414,7 @@ static struct rcu_torture_ops rcu_bh_sync_ops = { .sync = rcu_bh_torture_synchronize, .cb_barrier = NULL, .stats = NULL, + .irqcapable = 1, .name = "rcu_bh_sync" }; @@ -532,6 +541,7 @@ static struct rcu_torture_ops sched_ops = { .sync = sched_torture_synchronize, .cb_barrier = rcu_barrier_sched, .stats = NULL, + .irqcapable = 1, .name = "sched" }; @@ -619,6 +629,52 @@ rcu_torture_fakewriter(void *arg) return 0; } +/* + * RCU torture reader from timer handler. Dereferences rcu_torture_current, + * incrementing the corresponding element of the pipeline array. The + * counter in the element should never be greater than 1, otherwise, the + * RCU implementation is broken. + */ +static void rcu_torture_timer(unsigned long unused) +{ + int idx; + int completed; + static DEFINE_RCU_RANDOM(rand); + static DEFINE_SPINLOCK(rand_lock); + struct rcu_torture *p; + int pipe_count; + + idx = cur_ops->readlock(); + completed = cur_ops->completed(); + p = rcu_dereference(rcu_torture_current); + if (p == NULL) { + /* Leave because rcu_torture_writer is not yet underway */ + cur_ops->readunlock(idx); + return; + } + if (p->rtort_mbtest == 0) + atomic_inc(&n_rcu_torture_mberror); + spin_lock(&rand_lock); + cur_ops->readdelay(&rand); + n_rcu_torture_timers++; + spin_unlock(&rand_lock); + preempt_disable(); + pipe_count = p->rtort_pipe_count; + if (pipe_count > RCU_TORTURE_PIPE_LEN) { + /* Should not happen, but... */ + pipe_count = RCU_TORTURE_PIPE_LEN; + } + ++__get_cpu_var(rcu_torture_count)[pipe_count]; + completed = cur_ops->completed() - completed; + if (completed > RCU_TORTURE_PIPE_LEN) { + /* Should not happen, but... */ + completed = RCU_TORTURE_PIPE_LEN; + } + ++__get_cpu_var(rcu_torture_batch)[completed]; + preempt_enable(); + cur_ops->readunlock(idx); +} + /* * RCU torture reader kthread. Repeatedly dereferences rcu_torture_current, * incrementing the corresponding element of the pipeline array. The @@ -633,11 +689,18 @@ rcu_torture_reader(void *arg) DEFINE_RCU_RANDOM(rand); struct rcu_torture *p; int pipe_count; + struct timer_list t; VERBOSE_PRINTK_STRING("rcu_torture_reader task started"); set_user_nice(current, 19); + if (irqreader && cur_ops->irqcapable) + setup_timer_on_stack(&t, rcu_torture_timer, 0); do { + if (irqreader && cur_ops->irqcapable) { + if (!timer_pending(&t)) + mod_timer(&t, 1); + } idx = cur_ops->readlock(); completed = cur_ops->completed(); p = rcu_dereference(rcu_torture_current); @@ -669,6 +732,8 @@ rcu_torture_reader(void *arg) rcu_stutter_wait(); } while (!kthread_should_stop() && !fullstop); VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping"); + if (irqreader && cur_ops->irqcapable) + del_timer_sync(&t); while (!kthread_should_stop()) schedule_timeout_uninterruptible(1); return 0; @@ -699,14 +764,15 @@ rcu_torture_printk(char *page) cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG); cnt += sprintf(&page[cnt], "rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d " - "rtmbe: %d", + "rtmbe: %d nt: %ld", rcu_torture_current, rcu_torture_current_version, list_empty(&rcu_torture_freelist), atomic_read(&n_rcu_torture_alloc), atomic_read(&n_rcu_torture_alloc_fail), atomic_read(&n_rcu_torture_free), - atomic_read(&n_rcu_torture_mberror)); + atomic_read(&n_rcu_torture_mberror), + n_rcu_torture_timers); if (atomic_read(&n_rcu_torture_mberror) != 0) cnt += sprintf(&page[cnt], " !!!"); cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG); @@ -862,10 +928,10 @@ rcu_torture_print_module_parms(char *tag) printk(KERN_ALERT "%s" TORTURE_FLAG "--- %s: nreaders=%d nfakewriters=%d " "stat_interval=%d verbose=%d test_no_idle_hz=%d " - "shuffle_interval=%d stutter=%d\n", + "shuffle_interval=%d stutter=%d irqreader=%d\n", torture_type, tag, nrealreaders, nfakewriters, stat_interval, verbose, test_no_idle_hz, shuffle_interval, - stutter); + stutter, irqreader); } static void -- cgit v1.2.3 From 9f1585cb03866452e0df61a83c88302181e50054 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 26 Jun 2008 08:25:57 +0100 Subject: [GFS2] Glock documentation This patch adds a file describing the internals of GFS2's glock abstraction. Signed-off-by: Steven Whitehouse --- Documentation/filesystems/gfs2-glocks.txt | 114 ++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 Documentation/filesystems/gfs2-glocks.txt (limited to 'Documentation') diff --git a/Documentation/filesystems/gfs2-glocks.txt b/Documentation/filesystems/gfs2-glocks.txt new file mode 100644 index 000000000000..4dae9a3840bf --- /dev/null +++ b/Documentation/filesystems/gfs2-glocks.txt @@ -0,0 +1,114 @@ + Glock internal locking rules + ------------------------------ + +This documents the basic principles of the glock state machine +internals. Each glock (struct gfs2_glock in fs/gfs2/incore.h) +has two main (internal) locks: + + 1. A spinlock (gl_spin) which protects the internal state such + as gl_state, gl_target and the list of holders (gl_holders) + 2. A non-blocking bit lock, GLF_LOCK, which is used to prevent other + threads from making calls to the DLM, etc. at the same time. If a + thread takes this lock, it must then call run_queue (usually via the + workqueue) when it releases it in order to ensure any pending tasks + are completed. + +The gl_holders list contains all the queued lock requests (not +just the holders) associated with the glock. If there are any +held locks, then they will be contiguous entries at the head +of the list. Locks are granted in strictly the order that they +are queued, except for those marked LM_FLAG_PRIORITY which are +used only during recovery, and even then only for journal locks. + +There are three lock states that users of the glock layer can request, +namely shared (SH), deferred (DF) and exclusive (EX). Those translate +to the following DLM lock modes: + +Glock mode | DLM lock mode +------------------------------ + UN | IV/NL Unlocked (no DLM lock associated with glock) or NL + SH | PR (Protected read) + DF | CW (Concurrent write) + EX | EX (Exclusive) + +Thus DF is basically a shared mode which is incompatible with the "normal" +shared lock mode, SH. In GFS2 the DF mode is used exclusively for direct I/O +operations. The glocks are basically a lock plus some routines which deal +with cache management. The following rules apply for the cache: + +Glock mode | Cache data | Cache Metadata | Dirty Data | Dirty Metadata +-------------------------------------------------------------------------- + UN | No | No | No | No + SH | Yes | Yes | No | No + DF | No | Yes | No | No + EX | Yes | Yes | Yes | Yes + +These rules are implemented using the various glock operations which +are defined for each type of glock. Not all types of glocks use +all the modes. Only inode glocks use the DF mode for example. + +Table of glock operations and per type constants: + +Field | Purpose +---------------------------------------------------------------------------- +go_xmote_th | Called before remote state change (e.g. to sync dirty data) +go_xmote_bh | Called after remote state change (e.g. to refill cache) +go_inval | Called if remote state change requires invalidating the cache +go_demote_ok | Returns boolean value of whether its ok to demote a glock + | (e.g. checks timeout, and that there is no cached data) +go_lock | Called for the first local holder of a lock +go_unlock | Called on the final local unlock of a lock +go_dump | Called to print content of object for debugfs file, or on + | error to dump glock to the log. +go_type; | The type of the glock, LM_TYPE_..... +go_min_hold_time | The minimum hold time + +The minimum hold time for each lock is the time after a remote lock +grant for which we ignore remote demote requests. This is in order to +prevent a situation where locks are being bounced around the cluster +from node to node with none of the nodes making any progress. This +tends to show up most with shared mmaped files which are being written +to by multiple nodes. By delaying the demotion in response to a +remote callback, that gives the userspace program time to make +some progress before the pages are unmapped. + +There is a plan to try and remove the go_lock and go_unlock callbacks +if possible, in order to try and speed up the fast path though the locking. +Also, eventually we hope to make the glock "EX" mode locally shared +such that any local locking will be done with the i_mutex as required +rather than via the glock. + +Locking rules for glock operations: + +Operation | GLF_LOCK bit lock held | gl_spin spinlock held +----------------------------------------------------------------- +go_xmote_th | Yes | No +go_xmote_bh | Yes | No +go_inval | Yes | No +go_demote_ok | Sometimes | Yes +go_lock | Yes | No +go_unlock | Yes | No +go_dump | Sometimes | Yes + +N.B. Operations must not drop either the bit lock or the spinlock +if its held on entry. go_dump and do_demote_ok must never block. +Note that go_dump will only be called if the glock's state +indicates that it is caching uptodate data. + +Glock locking order within GFS2: + + 1. i_mutex (if required) + 2. Rename glock (for rename only) + 3. Inode glock(s) + (Parents before children, inodes at "same level" with same parent in + lock number order) + 4. Rgrp glock(s) (for (de)allocation operations) + 5. Transaction glock (via gfs2_trans_begin) for non-read operations + 6. Page lock (always last, very important!) + +There are two glocks per inode. One deals with access to the inode +itself (locking order as above), and the other, known as the iopen +glock is used in conjunction with the i_nlink field in the inode to +determine the lifetime of the inode in question. Locking of inodes +is on a per-inode basis. Locking of rgrps is on a per rgrp basis. + -- cgit v1.2.3 From 93e3270c87549dc531a0b0e5d06362d998d810cb Mon Sep 17 00:00:00 2001 From: "Jose R. Santos" Date: Fri, 11 Jul 2008 19:27:31 -0400 Subject: ext4: Documentation updates. Some of the information in Documentation/filesystems/ext4.txt is out of date and in need of an update. Signed-off-by: Jose R. Santos Signed-off-by: "Theodore Ts'o" --- Documentation/filesystems/ext4.txt | 106 ++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 44 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt index 0c5086db8352..7e940c64be47 100644 --- a/Documentation/filesystems/ext4.txt +++ b/Documentation/filesystems/ext4.txt @@ -13,72 +13,89 @@ Mailing list: linux-ext4@vger.kernel.org 1. Quick usage instructions: =========================== - - Grab updated e2fsprogs from - ftp://ftp.kernel.org/pub/linux/kernel/people/tytso/e2fsprogs-interim/ - This is a patchset on top of e2fsprogs-1.39, which can be found at + - Compile and install the latest version of e2fsprogs (as of this + writing version 1.41) from: + + http://sourceforge.net/project/showfiles.php?group_id=2406 + + or + ftp://ftp.kernel.org/pub/linux/kernel/people/tytso/e2fsprogs/ - - It's still mke2fs -j /dev/hda1 + or grab the latest git repository from: + + git://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git + + - Create a new filesystem using the ext4dev filesystem type: + + # mke2fs -t ext4dev /dev/hda1 + + Or configure an existing ext3 filesystem to support extents and set + the test_fs flag to indicate that it's ok for an in-development + filesystem to touch this filesystem: - - mount /dev/hda1 /wherever -t ext4dev + # tune2fs -O extents -E test_fs /dev/hda1 - - To enable extents, + If the filesystem was created with 128 byte inodes, it can be + converted to use 256 byte for greater efficiency via: - mount /dev/hda1 /wherever -t ext4dev -o extents + # tune2fs -I 256 /dev/hda1 - - The filesystem is compatible with the ext3 driver until you add a file - which has extents (ie: `mount -o extents', then create a file). + (Note: we currently do not have tools to convert an ext4dev + filesystem back to ext3; so please do not do try this on production + filesystems.) - NOTE: The "extents" mount flag is temporary. It will soon go away and - extents will be enabled by the "-o extents" flag to mke2fs or tune2fs + - Mounting: + + # mount -t ext4dev /dev/hda1 /wherever - When comparing performance with other filesystems, remember that - ext3/4 by default offers higher data integrity guarantees than most. So - when comparing with a metadata-only journalling filesystem, use `mount -o - data=writeback'. And you might as well use `mount -o nobh' too along - with it. Making the journal larger than the mke2fs default often helps - performance with metadata-intensive workloads. + ext3/4 by default offers higher data integrity guarantees than most. + So when comparing with a metadata-only journalling filesystem, such + as ext3, use `mount -o data=writeback'. And you might as well use + `mount -o nobh' too along with it. Making the journal larger than + the mke2fs default often helps performance with metadata-intensive + workloads. 2. Features =========== 2.1 Currently available -* ability to use filesystems > 16TB +* ability to use filesystems > 16TB (e2fsprogs support not available yet) * extent format reduces metadata overhead (RAM, IO for access, transactions) * extent format more robust in face of on-disk corruption due to magics, * internal redunancy in tree - -2.1 Previously available, soon to be enabled by default by "mkefs.ext4": - -* dir_index and resize inode will be on by default -* large inodes will be used by default for fast EAs, nsec timestamps, etc +* improved file allocation (multi-block alloc, delayed alloc) +* fix 32000 subdirectory limit +* nsec timestamps for mtime, atime, ctime, create time +* inode version field on disk (NFSv4, Lustre) +* reduced e2fsck time via uninit_bg feature +* journal checksumming for robustness, performance +* persistent file preallocation (e.g for streaming media, databases) +* ability to pack bitmaps and inode tables into larger virtual groups via the + flex_bg feature +* large file support +* Inode allocation using large virtual block groups via flex_bg 2.2 Candidate features for future inclusion -There are several under discussion, whether they all make it in is -partly a function of how much time everyone has to work on them: +* Online defrag (patches available but not well tested) +* reduced mke2fs time via lazy itable initialization in conjuction with + the uninit_bg feature (capability to do this is available in e2fsprogs + but a kernel thread to do lazy zeroing of unused inode table blocks + after filesystem is first mounted is required for safety) -* improved file allocation (multi-block alloc, delayed alloc; basically done) -* fix 32000 subdirectory limit (patch exists, needs some e2fsck work) -* nsec timestamps for mtime, atime, ctime, create time (patch exists, - needs some e2fsck work) -* inode version field on disk (NFSv4, Lustre; prototype exists) -* reduced mke2fs/e2fsck time via uninitialized groups (prototype exists) -* journal checksumming for robustness, performance (prototype exists) -* persistent file preallocation (e.g for streaming media, databases) +There are several others under discussion, whether they all make it in is +partly a function of how much time everyone has to work on them. Features like +metadata checksumming have been discussed and planned for a bit but no patches +exist yet so I'm not sure they're in the near-term roadmap. -Features like metadata checksumming have been discussed and planned for -a bit but no patches exist yet so I'm not sure they're in the near-term -roadmap. +The big performance win will come with mballoc, delalloc and flex_bg +grouping of bitmaps and inode tables. Some test results available here: -The big performance win will come with mballoc and delalloc. CFS has -been using mballoc for a few years already with Lustre, and IBM + Bull -did a lot of benchmarking on it. The reason it isn't in the first set of -patches is partly a manageability issue, and partly because it doesn't -directly affect the on-disk format (outside of much better allocation) -so it isn't critical to get into the first round of changes. I believe -Alex is working on a new set of patches right now. + - http://www.bullopensource.org/ext4/20080530/ffsb-write-2.6.26-rc2.html + - http://www.bullopensource.org/ext4/20080530/ffsb-readwrite-2.6.26-rc2.html 3. Options ========== @@ -224,7 +241,7 @@ stripe=n Number of filesystem blocks that mballoc will try disks * RAID chunk size in file system blocks. Data Mode ---------- +========= There are 3 different data modes: * writeback mode @@ -256,7 +273,8 @@ kernel source: programs: http://e2fsprogs.sourceforge.net/ - http://ext2resize.sourceforge.net useful links: http://fedoraproject.org/wiki/ext3-devel http://www.bullopensource.org/ext4/ + http://ext4.wiki.kernel.org/index.php/Main_Page + http://fedoraproject.org/wiki/Features/Ext4 -- cgit v1.2.3 From 49f1487b2e41bd8439ea39a4f15b4064e823cc54 Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Fri, 11 Jul 2008 19:27:31 -0400 Subject: ext4: Documention update for new ordered mode and delayed allocation Adding some documentations for delayed allocation and new ordered mode. Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- Documentation/filesystems/ext4.txt | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt index 7e940c64be47..80e193d82e2e 100644 --- a/Documentation/filesystems/ext4.txt +++ b/Documentation/filesystems/ext4.txt @@ -66,7 +66,7 @@ Mailing list: linux-ext4@vger.kernel.org * extent format reduces metadata overhead (RAM, IO for access, transactions) * extent format more robust in face of on-disk corruption due to magics, * internal redunancy in tree -* improved file allocation (multi-block alloc, delayed alloc) +* improved file allocation (multi-block alloc) * fix 32000 subdirectory limit * nsec timestamps for mtime, atime, ctime, create time * inode version field on disk (NFSv4, Lustre) @@ -77,6 +77,10 @@ Mailing list: linux-ext4@vger.kernel.org flex_bg feature * large file support * Inode allocation using large virtual block groups via flex_bg +* delayed allocation +* large block (up to pagesize) support +* efficent new ordered mode in JBD2 and ext4(avoid using buffer head to force + the ordering) 2.2 Candidate features for future inclusion @@ -239,7 +243,9 @@ stripe=n Number of filesystem blocks that mballoc will try to use for allocation size and alignment. For RAID5/6 systems this should be the number of data disks * RAID chunk size in file system blocks. - +delalloc (*) Deferring block allocation until write-out time. +nodelalloc Disable delayed allocation. Blocks are allocation + when data is copied from user to page cache. Data Mode ========= There are 3 different data modes: @@ -253,10 +259,10 @@ typically provide the best ext4 performance. * ordered mode In data=ordered mode, ext4 only officially journals metadata, but it logically -groups metadata and data blocks into a single unit called a transaction. When -it's time to write the new metadata out to disk, the associated data blocks -are written first. In general, this mode performs slightly slower than -writeback but significantly faster than journal mode. +groups metadata information related to data changes with the data blocks into a +single unit called a transaction. When it's time to write the new metadata +out to disk, the associated data blocks are written first. In general, +this mode performs slightly slower than writeback but significantly faster than journal mode. * journal mode data=journal mode provides full data and metadata journaling. All new data is @@ -264,7 +270,8 @@ written to the journal first, and then to its final location. In the event of a crash, the journal can be replayed, bringing both data and metadata into a consistent state. This mode is the slowest except when data needs to be read from and written to disk at the same time where it -outperforms all others modes. +outperforms all others modes. Curently ext4 does not have delayed +allocation support if this data journalling mode is selected. References ========== -- cgit v1.2.3 From de32a2434f7ce4600da90ecb44abcdc365ada1d0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 12 Jul 2008 05:33:30 +0200 Subject: kernel-paramaters: document pmtmr= command line option Signed-off-by: Thomas Gleixner --- Documentation/kernel-parameters.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index e07c432c731f..356b64ba706a 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1571,6 +1571,10 @@ and is between 256 and 4096 characters. It is defined in the file Format: { parport | timid | 0 } See also Documentation/parport.txt. + pmtmr= [X86] Manual setup of pmtmr I/O Port. + Override pmtimer IOPort with a hex value. + e.g. pmtmr=0x508 + pnpacpi= [ACPI] { off } -- cgit v1.2.3 From 20a9b6e7c303f2a6f9afe17c0997bc9a3c734442 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 14 Jul 2008 22:38:22 +0200 Subject: i2c: Remove 3 deprecated bus drivers This patch contains the scheduled removal of i2c-i810, i2c-prosavage and i2c-savage4. Signed-off-by: Adrian Bunk Signed-off-by: Jean Delvare --- Documentation/feature-removal-schedule.txt | 7 - Documentation/i2c/busses/i2c-i810 | 47 ----- Documentation/i2c/busses/i2c-prosavage | 23 -- Documentation/i2c/busses/i2c-savage4 | 26 --- drivers/i2c/busses/Kconfig | 52 ----- drivers/i2c/busses/Makefile | 3 - drivers/i2c/busses/i2c-i810.c | 260 ----------------------- drivers/i2c/busses/i2c-prosavage.c | 325 ----------------------------- drivers/i2c/busses/i2c-savage4.c | 185 ---------------- include/linux/i2c-id.h | 1 - 10 files changed, 929 deletions(-) delete mode 100644 Documentation/i2c/busses/i2c-i810 delete mode 100644 Documentation/i2c/busses/i2c-prosavage delete mode 100644 Documentation/i2c/busses/i2c-savage4 delete mode 100644 drivers/i2c/busses/i2c-i810.c delete mode 100644 drivers/i2c/busses/i2c-prosavage.c delete mode 100644 drivers/i2c/busses/i2c-savage4.c (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 46ece3fba6f9..65a1482457a8 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -222,13 +222,6 @@ Who: Thomas Gleixner --------------------------- -What: i2c-i810, i2c-prosavage and i2c-savage4 -When: May 2008 -Why: These drivers are superseded by i810fb, intelfb and savagefb. -Who: Jean Delvare - ---------------------------- - What (Why): - include/linux/netfilter_ipv4/ipt_TOS.h ipt_tos.h header files (superseded by xt_TOS/xt_tos target & match) diff --git a/Documentation/i2c/busses/i2c-i810 b/Documentation/i2c/busses/i2c-i810 deleted file mode 100644 index 778210ee1583..000000000000 --- a/Documentation/i2c/busses/i2c-i810 +++ /dev/null @@ -1,47 +0,0 @@ -Kernel driver i2c-i810 - -Supported adapters: - * Intel 82810, 82810-DC100, 82810E, and 82815 (GMCH) - * Intel 82845G (GMCH) - -Authors: - Frodo Looijaard , - Philip Edelbrock , - Kyösti Mälkki , - Ralph Metzler , - Mark D. Studebaker - -Main contact: Mark Studebaker - -Description ------------ - -WARNING: If you have an '810' or '815' motherboard, your standard I2C -temperature sensors are most likely on the 801's I2C bus. You want the -i2c-i801 driver for those, not this driver. - -Now for the i2c-i810... - -The GMCH chip contains two I2C interfaces. - -The first interface is used for DDC (Data Display Channel) which is a -serial channel through the VGA monitor connector to a DDC-compliant -monitor. This interface is defined by the Video Electronics Standards -Association (VESA). The standards are available for purchase at -http://www.vesa.org . - -The second interface is a general-purpose I2C bus. It may be connected to a -TV-out chip such as the BT869 or possibly to a digital flat-panel display. - -Features --------- - -Both busses use the i2c-algo-bit driver for 'bit banging' -and support for specific transactions is provided by i2c-algo-bit. - -Issues ------- - -If you enable bus testing in i2c-algo-bit (insmod i2c-algo-bit bit_test=1), -the test may fail; if so, the i2c-i810 driver won't be inserted. However, -we think this has been fixed. diff --git a/Documentation/i2c/busses/i2c-prosavage b/Documentation/i2c/busses/i2c-prosavage deleted file mode 100644 index 703687902511..000000000000 --- a/Documentation/i2c/busses/i2c-prosavage +++ /dev/null @@ -1,23 +0,0 @@ -Kernel driver i2c-prosavage - -Supported adapters: - - S3/VIA KM266/VT8375 aka ProSavage8 - S3/VIA KM133/VT8365 aka Savage4 - -Author: Henk Vergonet - -Description ------------ - -The Savage4 chips contain two I2C interfaces (aka a I2C 'master' or -'host'). - -The first interface is used for DDC (Data Display Channel) which is a -serial channel through the VGA monitor connector to a DDC-compliant -monitor. This interface is defined by the Video Electronics Standards -Association (VESA). The standards are available for purchase at -http://www.vesa.org . The second interface is a general-purpose I2C bus. - -Usefull for gaining access to the TV Encoder chips. - diff --git a/Documentation/i2c/busses/i2c-savage4 b/Documentation/i2c/busses/i2c-savage4 deleted file mode 100644 index 6ecceab618d3..000000000000 --- a/Documentation/i2c/busses/i2c-savage4 +++ /dev/null @@ -1,26 +0,0 @@ -Kernel driver i2c-savage4 - -Supported adapters: - * Savage4 - * Savage2000 - -Authors: - Alexander Wold , - Mark D. Studebaker - -Description ------------ - -The Savage4 chips contain two I2C interfaces (aka a I2C 'master' -or 'host'). - -The first interface is used for DDC (Data Display Channel) which is a -serial channel through the VGA monitor connector to a DDC-compliant -monitor. This interface is defined by the Video Electronics Standards -Association (VESA). The standards are available for purchase at -http://www.vesa.org . The DDC bus is not yet supported because its register -is not directly memory-mapped. - -The second interface is a general-purpose I2C bus. This is the only -interface supported by the driver at the moment. - diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 00d76e13588f..b7cce9211838 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -186,26 +186,6 @@ config I2C_I801 This driver can also be built as a module. If so, the module will be called i2c-i801. -config I2C_I810 - tristate "Intel 810/815 (DEPRECATED)" - default n - depends on PCI - select I2C_ALGOBIT - help - If you say yes to this option, support will be included for the Intel - 810/815 family of mainboard I2C interfaces. Specifically, the - following versions of the chipset are supported: - i810AA - i810AB - i810E - i815 - i845G - - This driver is deprecated in favor of the i810fb and intelfb drivers. - - This driver can also be built as a module. If so, the module - will be called i2c-i810. - config I2C_PXA tristate "Intel PXA2XX I2C adapter (EXPERIMENTAL)" depends on EXPERIMENTAL && ARCH_PXA @@ -402,24 +382,6 @@ config I2C_PASEMI help Supports the PA Semi PWRficient on-chip SMBus interfaces. -config I2C_PROSAVAGE - tristate "S3/VIA (Pro)Savage (DEPRECATED)" - default n - depends on PCI - select I2C_ALGOBIT - help - If you say yes to this option, support will be included for the - I2C bus and DDC bus of the S3VIA embedded Savage4 and ProSavage8 - graphics processors. - chipsets supported: - S3/VIA KM266/VT8375 aka ProSavage8 - S3/VIA KM133/VT8365 aka Savage4 - - This driver is deprecated in favor of the savagefb driver. - - This support is also available as a module. If so, the module - will be called i2c-prosavage. - config I2C_S3C2410 tristate "S3C2410 I2C Driver" depends on ARCH_S3C2410 @@ -427,20 +389,6 @@ config I2C_S3C2410 Say Y here to include support for I2C controller in the Samsung S3C2410 based System-on-Chip devices. -config I2C_SAVAGE4 - tristate "S3 Savage 4 (DEPRECATED)" - default n - depends on PCI - select I2C_ALGOBIT - help - If you say yes to this option, support will be included for the - S3 Savage 4 I2C interface. - - This driver is deprecated in favor of the savagefb driver. - - This driver can also be built as a module. If so, the module - will be called i2c-savage4. - config I2C_SIBYTE tristate "SiByte SMBus interface" depends on SIBYTE_SB1xxx_SOC diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 8b0a8c257905..81bb407d24cc 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -16,7 +16,6 @@ obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o obj-$(CONFIG_I2C_I801) += i2c-i801.o -obj-$(CONFIG_I2C_I810) += i2c-i810.o obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o @@ -35,10 +34,8 @@ obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o obj-$(CONFIG_I2C_PNX) += i2c-pnx.o -obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o -obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c deleted file mode 100644 index 42e8d94c276f..000000000000 --- a/drivers/i2c/busses/i2c-i810.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - i2c-i810.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999, 2000 Frodo Looijaard , - Philip Edelbrock , - Ralph Metzler , and - Mark D. Studebaker - - Based on code written by Ralph Metzler and - Simon Vogl - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -/* - This interfaces to the I810/I815 to provide access to - the DDC Bus and the I2C Bus. - - SUPPORTED DEVICES PCI ID - i810AA 7121 - i810AB 7123 - i810E 7125 - i815 1132 - i845G 2562 -*/ - -#include -#include -#include -#include -#include -#include -#include - -/* GPIO register locations */ -#define I810_IOCONTROL_OFFSET 0x5000 -#define I810_HVSYNC 0x00 /* not used */ -#define I810_GPIOA 0x10 -#define I810_GPIOB 0x14 - -/* bit locations in the registers */ -#define SCL_DIR_MASK 0x0001 -#define SCL_DIR 0x0002 -#define SCL_VAL_MASK 0x0004 -#define SCL_VAL_OUT 0x0008 -#define SCL_VAL_IN 0x0010 -#define SDA_DIR_MASK 0x0100 -#define SDA_DIR 0x0200 -#define SDA_VAL_MASK 0x0400 -#define SDA_VAL_OUT 0x0800 -#define SDA_VAL_IN 0x1000 - -/* initialization states */ -#define INIT1 0x1 -#define INIT2 0x2 -#define INIT3 0x4 - -/* delays */ -#define CYCLE_DELAY 10 -#define TIMEOUT (HZ / 2) - -static void __iomem *ioaddr; - -/* The i810 GPIO registers have individual masks for each bit - so we never have to read before writing. Nice. */ - -static void bit_i810i2c_setscl(void *data, int val) -{ - writel((val ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK, - ioaddr + I810_GPIOB); - readl(ioaddr + I810_GPIOB); /* flush posted write */ -} - -static void bit_i810i2c_setsda(void *data, int val) -{ - writel((val ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK, - ioaddr + I810_GPIOB); - readl(ioaddr + I810_GPIOB); /* flush posted write */ -} - -/* The GPIO pins are open drain, so the pins could always remain outputs. - However, some chip versions don't latch the inputs unless they - are set as inputs. - We rely on the i2c-algo-bit routines to set the pins high before - reading the input from other chips. Following guidance in the 815 - prog. ref. guide, we do a "dummy write" of 0 to the register before - reading which forces the input value to be latched. We presume this - applies to the 810 as well; shouldn't hurt anyway. This is necessary to get - i2c_algo_bit bit_test=1 to pass. */ - -static int bit_i810i2c_getscl(void *data) -{ - writel(SCL_DIR_MASK, ioaddr + I810_GPIOB); - writel(0, ioaddr + I810_GPIOB); - return (0 != (readl(ioaddr + I810_GPIOB) & SCL_VAL_IN)); -} - -static int bit_i810i2c_getsda(void *data) -{ - writel(SDA_DIR_MASK, ioaddr + I810_GPIOB); - writel(0, ioaddr + I810_GPIOB); - return (0 != (readl(ioaddr + I810_GPIOB) & SDA_VAL_IN)); -} - -static void bit_i810ddc_setscl(void *data, int val) -{ - writel((val ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK, - ioaddr + I810_GPIOA); - readl(ioaddr + I810_GPIOA); /* flush posted write */ -} - -static void bit_i810ddc_setsda(void *data, int val) -{ - writel((val ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK, - ioaddr + I810_GPIOA); - readl(ioaddr + I810_GPIOA); /* flush posted write */ -} - -static int bit_i810ddc_getscl(void *data) -{ - writel(SCL_DIR_MASK, ioaddr + I810_GPIOA); - writel(0, ioaddr + I810_GPIOA); - return (0 != (readl(ioaddr + I810_GPIOA) & SCL_VAL_IN)); -} - -static int bit_i810ddc_getsda(void *data) -{ - writel(SDA_DIR_MASK, ioaddr + I810_GPIOA); - writel(0, ioaddr + I810_GPIOA); - return (0 != (readl(ioaddr + I810_GPIOA) & SDA_VAL_IN)); -} - -static int config_i810(struct pci_dev *dev) -{ - unsigned long cadr; - - /* map I810 memory */ - cadr = dev->resource[1].start; - cadr += I810_IOCONTROL_OFFSET; - cadr &= PCI_BASE_ADDRESS_MEM_MASK; - ioaddr = ioremap_nocache(cadr, 0x1000); - if (ioaddr) { - bit_i810i2c_setscl(NULL, 1); - bit_i810i2c_setsda(NULL, 1); - bit_i810ddc_setscl(NULL, 1); - bit_i810ddc_setsda(NULL, 1); - return 0; - } - return -ENODEV; -} - -static struct i2c_algo_bit_data i810_i2c_bit_data = { - .setsda = bit_i810i2c_setsda, - .setscl = bit_i810i2c_setscl, - .getsda = bit_i810i2c_getsda, - .getscl = bit_i810i2c_getscl, - .udelay = CYCLE_DELAY, - .timeout = TIMEOUT, -}; - -static struct i2c_adapter i810_i2c_adapter = { - .owner = THIS_MODULE, - .id = I2C_HW_B_I810, - .name = "I810/I815 I2C Adapter", - .algo_data = &i810_i2c_bit_data, -}; - -static struct i2c_algo_bit_data i810_ddc_bit_data = { - .setsda = bit_i810ddc_setsda, - .setscl = bit_i810ddc_setscl, - .getsda = bit_i810ddc_getsda, - .getscl = bit_i810ddc_getscl, - .udelay = CYCLE_DELAY, - .timeout = TIMEOUT, -}; - -static struct i2c_adapter i810_ddc_adapter = { - .owner = THIS_MODULE, - .id = I2C_HW_B_I810, - .name = "I810/I815 DDC Adapter", - .algo_data = &i810_ddc_bit_data, -}; - -static struct pci_device_id i810_ids[] __devinitdata = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG1) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810E_IG) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_CGC) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_IG) }, - { 0, }, -}; - -MODULE_DEVICE_TABLE (pci, i810_ids); - -static int __devinit i810_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - int retval; - - retval = config_i810(dev); - if (retval) - return retval; - dev_info(&dev->dev, "i810/i815 i2c device found.\n"); - - /* set up the sysfs linkage to our parent device */ - i810_i2c_adapter.dev.parent = &dev->dev; - i810_ddc_adapter.dev.parent = &dev->dev; - - retval = i2c_bit_add_bus(&i810_i2c_adapter); - if (retval) - return retval; - retval = i2c_bit_add_bus(&i810_ddc_adapter); - if (retval) - i2c_del_adapter(&i810_i2c_adapter); - return retval; -} - -static void __devexit i810_remove(struct pci_dev *dev) -{ - i2c_del_adapter(&i810_ddc_adapter); - i2c_del_adapter(&i810_i2c_adapter); - iounmap(ioaddr); -} - -static struct pci_driver i810_driver = { - .name = "i810_smbus", - .id_table = i810_ids, - .probe = i810_probe, - .remove = __devexit_p(i810_remove), -}; - -static int __init i2c_i810_init(void) -{ - return pci_register_driver(&i810_driver); -} - -static void __exit i2c_i810_exit(void) -{ - pci_unregister_driver(&i810_driver); -} - -MODULE_AUTHOR("Frodo Looijaard , " - "Philip Edelbrock , " - "Ralph Metzler , " - "and Mark D. Studebaker "); -MODULE_DESCRIPTION("I810/I815 I2C/DDC driver"); -MODULE_LICENSE("GPL"); - -module_init(i2c_i810_init); -module_exit(i2c_i810_exit); diff --git a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c deleted file mode 100644 index 07c1f1e27df1..000000000000 --- a/drivers/i2c/busses/i2c-prosavage.c +++ /dev/null @@ -1,325 +0,0 @@ -/* - * kernel/busses/i2c-prosavage.c - * - * i2c bus driver for S3/VIA 8365/8375 graphics processor. - * Copyright (c) 2003 Henk Vergonet - * Based on code written by: - * Frodo Looijaard , - * Philip Edelbrock , - * Ralph Metzler , and - * Mark D. Studebaker - * Simon Vogl - * and others - * - * Please read the lm_sensors documentation for details on use. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ -/* 18-05-2003 HVE - created - * 14-06-2003 HVE - adapted for lm_sensors2 - * 17-06-2003 HVE - linux 2.5.xx compatible - * 18-06-2003 HVE - codingstyle - * 21-06-2003 HVE - compatibility lm_sensors2 and linux 2.5.xx - * codingstyle, mmio enabled - * - * This driver interfaces to the I2C bus of the VIA north bridge embedded - * ProSavage4/8 devices. Usefull for gaining access to the TV Encoder chips. - * - * Graphics cores: - * S3/VIA KM266/VT8375 aka ProSavage8 - * S3/VIA KM133/VT8365 aka Savage4 - * - * Two serial busses are implemented: - * SERIAL1 - I2C serial communications interface - * SERIAL2 - DDC2 monitor communications interface - * - * Tested on a FX41 mainboard, see http://www.shuttle.com - * - * - * TODO: - * - integration with prosavage framebuffer device - * (Additional documentation needed :( - */ - -#include -#include -#include -#include -#include -#include - -/* - * driver configuration - */ -#define MAX_BUSSES 2 - -struct s_i2c_bus { - void __iomem *mmvga; - int i2c_reg; - int adap_ok; - struct i2c_adapter adap; - struct i2c_algo_bit_data algo; -}; - -struct s_i2c_chip { - void __iomem *mmio; - struct s_i2c_bus i2c_bus[MAX_BUSSES]; -}; - - -/* - * i2c configuration - */ -#define CYCLE_DELAY 10 -#define TIMEOUT (HZ / 2) - - -/* - * S3/VIA 8365/8375 registers - */ -#define VGA_CR_IX 0x3d4 -#define VGA_CR_DATA 0x3d5 - -#define CR_SERIAL1 0xa0 /* I2C serial communications interface */ -#define MM_SERIAL1 0xff20 -#define CR_SERIAL2 0xb1 /* DDC2 monitor communications interface */ - -/* based on vt8365 documentation */ -#define I2C_ENAB 0x10 -#define I2C_SCL_OUT 0x01 -#define I2C_SDA_OUT 0x02 -#define I2C_SCL_IN 0x04 -#define I2C_SDA_IN 0x08 - -#define SET_CR_IX(p, val) writeb((val), (p)->mmvga + VGA_CR_IX) -#define SET_CR_DATA(p, val) writeb((val), (p)->mmvga + VGA_CR_DATA) -#define GET_CR_DATA(p) readb((p)->mmvga + VGA_CR_DATA) - - -/* - * Serial bus line handling - * - * serial communications register as parameter in private data - * - * TODO: locks with other code sections accessing video registers? - */ -static void bit_s3via_setscl(void *bus, int val) -{ - struct s_i2c_bus *p = (struct s_i2c_bus *)bus; - unsigned int r; - - SET_CR_IX(p, p->i2c_reg); - r = GET_CR_DATA(p); - r |= I2C_ENAB; - if (val) { - r |= I2C_SCL_OUT; - } else { - r &= ~I2C_SCL_OUT; - } - SET_CR_DATA(p, r); -} - -static void bit_s3via_setsda(void *bus, int val) -{ - struct s_i2c_bus *p = (struct s_i2c_bus *)bus; - unsigned int r; - - SET_CR_IX(p, p->i2c_reg); - r = GET_CR_DATA(p); - r |= I2C_ENAB; - if (val) { - r |= I2C_SDA_OUT; - } else { - r &= ~I2C_SDA_OUT; - } - SET_CR_DATA(p, r); -} - -static int bit_s3via_getscl(void *bus) -{ - struct s_i2c_bus *p = (struct s_i2c_bus *)bus; - - SET_CR_IX(p, p->i2c_reg); - return (0 != (GET_CR_DATA(p) & I2C_SCL_IN)); -} - -static int bit_s3via_getsda(void *bus) -{ - struct s_i2c_bus *p = (struct s_i2c_bus *)bus; - - SET_CR_IX(p, p->i2c_reg); - return (0 != (GET_CR_DATA(p) & I2C_SDA_IN)); -} - - -/* - * adapter initialisation - */ -static int i2c_register_bus(struct pci_dev *dev, struct s_i2c_bus *p, void __iomem *mmvga, u32 i2c_reg) -{ - int ret; - p->adap.owner = THIS_MODULE; - p->adap.id = I2C_HW_B_S3VIA; - p->adap.algo_data = &p->algo; - p->adap.dev.parent = &dev->dev; - p->algo.setsda = bit_s3via_setsda; - p->algo.setscl = bit_s3via_setscl; - p->algo.getsda = bit_s3via_getsda; - p->algo.getscl = bit_s3via_getscl; - p->algo.udelay = CYCLE_DELAY; - p->algo.timeout = TIMEOUT; - p->algo.data = p; - p->mmvga = mmvga; - p->i2c_reg = i2c_reg; - - ret = i2c_bit_add_bus(&p->adap); - if (ret) { - return ret; - } - - p->adap_ok = 1; - return 0; -} - - -/* - * Cleanup stuff - */ -static void prosavage_remove(struct pci_dev *dev) -{ - struct s_i2c_chip *chip; - int i, ret; - - chip = (struct s_i2c_chip *)pci_get_drvdata(dev); - - if (!chip) { - return; - } - for (i = MAX_BUSSES - 1; i >= 0; i--) { - if (chip->i2c_bus[i].adap_ok == 0) - continue; - - ret = i2c_del_adapter(&chip->i2c_bus[i].adap); - if (ret) { - dev_err(&dev->dev, "%s not removed\n", - chip->i2c_bus[i].adap.name); - } - } - if (chip->mmio) { - iounmap(chip->mmio); - } - kfree(chip); -} - - -/* - * Detect chip and initialize it - */ -static int __devinit prosavage_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - int ret; - unsigned long base, len; - struct s_i2c_chip *chip; - struct s_i2c_bus *bus; - - pci_set_drvdata(dev, kzalloc(sizeof(struct s_i2c_chip), GFP_KERNEL)); - chip = (struct s_i2c_chip *)pci_get_drvdata(dev); - if (chip == NULL) { - return -ENOMEM; - } - - base = dev->resource[0].start & PCI_BASE_ADDRESS_MEM_MASK; - len = dev->resource[0].end - base + 1; - chip->mmio = ioremap_nocache(base, len); - - if (chip->mmio == NULL) { - dev_err(&dev->dev, "ioremap failed\n"); - prosavage_remove(dev); - return -ENODEV; - } - - - /* - * Chip initialisation - */ - /* Unlock Extended IO Space ??? */ - - - /* - * i2c bus registration - */ - bus = &chip->i2c_bus[0]; - snprintf(bus->adap.name, sizeof(bus->adap.name), - "ProSavage I2C bus at %02x:%02x.%x", - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - ret = i2c_register_bus(dev, bus, chip->mmio + 0x8000, CR_SERIAL1); - if (ret) { - goto err_adap; - } - /* - * ddc bus registration - */ - bus = &chip->i2c_bus[1]; - snprintf(bus->adap.name, sizeof(bus->adap.name), - "ProSavage DDC bus at %02x:%02x.%x", - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - ret = i2c_register_bus(dev, bus, chip->mmio + 0x8000, CR_SERIAL2); - if (ret) { - goto err_adap; - } - return 0; -err_adap: - dev_err(&dev->dev, "%s failed\n", bus->adap.name); - prosavage_remove(dev); - return ret; -} - - -/* - * Data for PCI driver interface - */ -static struct pci_device_id prosavage_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SAVAGE4) }, - { PCI_DEVICE(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_PROSAVAGE8) }, - { 0, }, -}; - -MODULE_DEVICE_TABLE (pci, prosavage_pci_tbl); - -static struct pci_driver prosavage_driver = { - .name = "prosavage_smbus", - .id_table = prosavage_pci_tbl, - .probe = prosavage_probe, - .remove = prosavage_remove, -}; - -static int __init i2c_prosavage_init(void) -{ - return pci_register_driver(&prosavage_driver); -} - -static void __exit i2c_prosavage_exit(void) -{ - pci_unregister_driver(&prosavage_driver); -} - -MODULE_DEVICE_TABLE(pci, prosavage_pci_tbl); -MODULE_AUTHOR("Henk Vergonet"); -MODULE_DESCRIPTION("ProSavage VIA 8365/8375 smbus driver"); -MODULE_LICENSE("GPL"); - -module_init (i2c_prosavage_init); -module_exit (i2c_prosavage_exit); diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c deleted file mode 100644 index 8adf4abaa035..000000000000 --- a/drivers/i2c/busses/i2c-savage4.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - i2c-savage4.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (C) 1998-2003 The LM Sensors Team - Alexander Wold - Mark D. Studebaker - - Based on i2c-voodoo3.c. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* This interfaces to the I2C bus of the Savage4 to gain access to - the BT869 and possibly other I2C devices. The DDC bus is not - yet supported because its register is not memory-mapped. -*/ - -#include -#include -#include -#include -#include -#include -#include - -/* device IDs */ -#define PCI_CHIP_SAVAGE4 0x8A22 -#define PCI_CHIP_SAVAGE2000 0x9102 - -#define REG 0xff20 /* Serial Port 1 Register */ - -/* bit locations in the register */ -#define I2C_ENAB 0x00000020 -#define I2C_SCL_OUT 0x00000001 -#define I2C_SDA_OUT 0x00000002 -#define I2C_SCL_IN 0x00000008 -#define I2C_SDA_IN 0x00000010 - -/* delays */ -#define CYCLE_DELAY 10 -#define TIMEOUT (HZ / 2) - - -static void __iomem *ioaddr; - -/* The sav GPIO registers don't have individual masks for each bit - so we always have to read before writing. */ - -static void bit_savi2c_setscl(void *data, int val) -{ - unsigned int r; - r = readl(ioaddr + REG); - if(val) - r |= I2C_SCL_OUT; - else - r &= ~I2C_SCL_OUT; - writel(r, ioaddr + REG); - readl(ioaddr + REG); /* flush posted write */ -} - -static void bit_savi2c_setsda(void *data, int val) -{ - unsigned int r; - r = readl(ioaddr + REG); - if(val) - r |= I2C_SDA_OUT; - else - r &= ~I2C_SDA_OUT; - writel(r, ioaddr + REG); - readl(ioaddr + REG); /* flush posted write */ -} - -/* The GPIO pins are open drain, so the pins always remain outputs. - We rely on the i2c-algo-bit routines to set the pins high before - reading the input from other chips. */ - -static int bit_savi2c_getscl(void *data) -{ - return (0 != (readl(ioaddr + REG) & I2C_SCL_IN)); -} - -static int bit_savi2c_getsda(void *data) -{ - return (0 != (readl(ioaddr + REG) & I2C_SDA_IN)); -} - -/* Configures the chip */ - -static int config_s4(struct pci_dev *dev) -{ - unsigned long cadr; - - /* map memory */ - cadr = dev->resource[0].start; - cadr &= PCI_BASE_ADDRESS_MEM_MASK; - ioaddr = ioremap_nocache(cadr, 0x0080000); - if (ioaddr) { - /* writel(0x8160, ioaddr + REG2); */ - writel(0x00000020, ioaddr + REG); - dev_info(&dev->dev, "Using Savage4 at %p\n", ioaddr); - return 0; - } - return -ENODEV; -} - -static struct i2c_algo_bit_data sav_i2c_bit_data = { - .setsda = bit_savi2c_setsda, - .setscl = bit_savi2c_setscl, - .getsda = bit_savi2c_getsda, - .getscl = bit_savi2c_getscl, - .udelay = CYCLE_DELAY, - .timeout = TIMEOUT -}; - -static struct i2c_adapter savage4_i2c_adapter = { - .owner = THIS_MODULE, - .id = I2C_HW_B_SAVAGE, - .name = "I2C Savage4 adapter", - .algo_data = &sav_i2c_bit_data, -}; - -static struct pci_device_id savage4_ids[] __devinitdata = { - { PCI_DEVICE(PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE4) }, - { PCI_DEVICE(PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE2000) }, - { 0, } -}; - -MODULE_DEVICE_TABLE (pci, savage4_ids); - -static int __devinit savage4_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - int retval; - - retval = config_s4(dev); - if (retval) - return retval; - - /* set up the sysfs linkage to our parent device */ - savage4_i2c_adapter.dev.parent = &dev->dev; - - return i2c_bit_add_bus(&savage4_i2c_adapter); -} - -static void __devexit savage4_remove(struct pci_dev *dev) -{ - i2c_del_adapter(&savage4_i2c_adapter); - iounmap(ioaddr); -} - -static struct pci_driver savage4_driver = { - .name = "savage4_smbus", - .id_table = savage4_ids, - .probe = savage4_probe, - .remove = __devexit_p(savage4_remove), -}; - -static int __init i2c_savage4_init(void) -{ - return pci_register_driver(&savage4_driver); -} - -static void __exit i2c_savage4_exit(void) -{ - pci_unregister_driver(&savage4_driver); -} - -MODULE_AUTHOR("Alexander Wold " - "and Mark D. Studebaker "); -MODULE_DESCRIPTION("Savage4 I2C/SMBus driver"); -MODULE_LICENSE("GPL"); - -module_init(i2c_savage4_init); -module_exit(i2c_savage4_exit); diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 580acc93903e..988e566d3ed5 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -111,7 +111,6 @@ #define I2C_HW_B_RIVA 0x010010 /* Riva based graphics cards */ #define I2C_HW_B_IOC 0x010011 /* IOC bit-wiggling */ #define I2C_HW_B_IXP2000 0x010016 /* GPIO on IXP2000 systems */ -#define I2C_HW_B_S3VIA 0x010018 /* S3Via ProSavage adapter */ #define I2C_HW_B_ZR36067 0x010019 /* Zoran-36057/36067 based boards */ #define I2C_HW_B_PCILYNX 0x01001a /* TI PCILynx I2C adapter */ #define I2C_HW_B_CX2388x 0x01001b /* connexant 2388x based tv cards */ -- cgit v1.2.3 From 81fded1f79771809059bdfa721ae5ab9114af545 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 14 Jul 2008 22:38:22 +0200 Subject: i2c: Document standard fault codes Create Documentation/i2c/fault-codes to help standardize fault/error code usage in the I2C stack. It turns out that returning -1 (-EPERM) for everything was not at all helpful. Signed-off-by: David Brownell Signed-off-by: Jean Delvare --- Documentation/i2c/fault-codes | 127 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 Documentation/i2c/fault-codes (limited to 'Documentation') diff --git a/Documentation/i2c/fault-codes b/Documentation/i2c/fault-codes new file mode 100644 index 000000000000..045765c0b9b5 --- /dev/null +++ b/Documentation/i2c/fault-codes @@ -0,0 +1,127 @@ +This is a summary of the most important conventions for use of fault +codes in the I2C/SMBus stack. + + +A "Fault" is not always an "Error" +---------------------------------- +Not all fault reports imply errors; "page faults" should be a familiar +example. Software often retries idempotent operations after transient +faults. There may be fancier recovery schemes that are appropriate in +some cases, such as re-initializing (and maybe resetting). After such +recovery, triggered by a fault report, there is no error. + +In a similar way, sometimes a "fault" code just reports one defined +result for an operation ... it doesn't indicate that anything is wrong +at all, just that the outcome wasn't on the "golden path". + +In short, your I2C driver code may need to know these codes in order +to respond correctly. Other code may need to rely on YOUR code reporting +the right fault code, so that it can (in turn) behave correctly. + + +I2C and SMBus fault codes +------------------------- +These are returned as negative numbers from most calls, with zero or +some positive number indicating a non-fault return. The specific +numbers associated with these symbols differ between architectures, +though most Linux systems use numbering. + +Note that the descriptions here are not exhaustive. There are other +codes that may be returned, and other cases where these codes should +be returned. However, drivers should not return other codes for these +cases (unless the hardware doesn't provide unique fault reports). + +Also, codes returned by adapter probe methods follow rules which are +specific to their host bus (such as PCI, or the platform bus). + + +EAGAIN + Returned by I2C adapters when they lose arbitration in master + transmit mode: some other master was transmitting different + data at the same time. + + Also returned when trying to invoke an I2C operation in an + atomic context, when some task is already using that I2C bus + to execute some other operation. + +EBADMSG + Returned by SMBus logic when an invalid Packet Error Code byte + is received. This code is a CRC covering all bytes in the + transaction, and is sent before the terminating STOP. This + fault is only reported on read transactions; the SMBus slave + may have a way to report PEC mismatches on writes from the + host. Note that even if PECs are in use, you should not rely + on these as the only way to detect incorrect data transfers. + +EBUSY + Returned by SMBus adapters when the bus was busy for longer + than allowed. This usually indicates some device (maybe the + SMBus adapter) needs some fault recovery (such as resetting), + or that the reset was attempted but failed. + +EINVAL + This rather vague error means an invalid parameter has been + detected before any I/O operation was started. Use a more + specific fault code when you can. + + One example would be a driver trying an SMBus Block Write + with block size outside the range of 1-32 bytes. + +EIO + This rather vague error means something went wrong when + performing an I/O operation. Use a more specific fault + code when you can. + +ENODEV + Returned by driver probe() methods. This is a bit more + specific than ENXIO, implying the problem isn't with the + address, but with the device found there. Driver probes + may verify the device returns *correct* responses, and + return this as appropriate. (The driver core will warn + about probe faults other than ENXIO and ENODEV.) + +ENOMEM + Returned by any component that can't allocate memory when + it needs to do so. + +ENXIO + Returned by I2C adapters to indicate that the address phase + of a transfer didn't get an ACK. While it might just mean + an I2C device was temporarily not responding, usually it + means there's nothing listening at that address. + + Returned by driver probe() methods to indicate that they + found no device to bind to. (ENODEV may also be used.) + +EOPNOTSUPP + Returned by an adapter when asked to perform an operation + that it doesn't, or can't, support. + + For example, this would be returned when an adapter that + doesn't support SMBus block transfers is asked to execute + one. In that case, the driver making that request should + have verified that functionality was supported before it + made that block transfer request. + + Similarly, if an I2C adapter can't execute all legal I2C + messages, it should return this when asked to perform a + transaction it can't. (These limitations can't be seen in + the adapter's functionality mask, since the assumption is + that if an adapter supports I2C it supports all of I2C.) + +EPROTO + Returned when slave does not conform to the relevant I2C + or SMBus (or chip-specific) protocol specifications. One + case is when the length of an SMBus block data response + (from the SMBus slave) is outside the range 1-32 bytes. + +ETIMEDOUT + This is returned by drivers when an operation took too much + time, and was aborted before it completed. + + SMBus adapters may return it when an operation took more + time than allowed by the SMBus specification; for example, + when a slave stretches clocks too far. I2C has no such + timeouts, but it's normal for I2C adapters to impose some + arbitrary limits (much longer than SMBus!) too. + -- cgit v1.2.3 From 24a5bb7b1838dc4524dd353224e2aa09c22cac3b Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 14 Jul 2008 22:38:23 +0200 Subject: i2c-core: Return -Errno, not -1 More updates to the I2C stack's fault reporting: make the core stop returning "-1" (usually "-EPERM") for all faults. Instead, pass lower level fault code up the stack, or return some appropriate errno. This patch happens to touch almost exclusively SMBus calls. Signed-off-by: David Brownell Signed-off-by: Jean Delvare --- Documentation/i2c/writing-clients | 8 ++-- drivers/i2c/i2c-core.c | 97 +++++++++++++++++++++------------------ 2 files changed, 57 insertions(+), 48 deletions(-) (limited to 'Documentation') diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index d4cd4126d1ad..ba5d1971f35f 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -598,10 +598,10 @@ be added back later if needed: u8 command, u8 length, u8 *values) -All these transactions return -1 on failure. The 'write' transactions -return 0 on success; the 'read' transactions return the read value, except -for read_block, which returns the number of values read. The block buffers -need not be longer than 32 bytes. +All these transactions return a negative errno value on failure. The 'write' +transactions return 0 on success; the 'read' transactions return the read +value, except for block transactions, which return the number of values +read. The block buffers need not be longer than 32 bytes. You can read the file `smbus-protocol' for more information about the actual SMBus protocol. diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index bb5c215a24e0..937f1dcbf3d7 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -974,7 +974,7 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num) return ret; } else { dev_dbg(&adap->dev, "I2C level transfers not supported\n"); - return -ENOSYS; + return -EOPNOTSUPP; } } EXPORT_SYMBOL(i2c_transfer); @@ -1106,7 +1106,7 @@ int i2c_probe(struct i2c_adapter *adapter, dev_warn(&adapter->dev, "SMBus Quick command not supported, " "can't probe for chips\n"); - return -1; + return -EOPNOTSUPP; } /* Probe entries are done second, and are not affected by ignore @@ -1298,7 +1298,7 @@ static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg) if (rpec != cpec) { pr_debug("i2c-core: Bad PEC 0x%02x vs. 0x%02x\n", rpec, cpec); - return -1; + return -EBADMSG; } return 0; } @@ -1313,11 +1313,12 @@ EXPORT_SYMBOL(i2c_smbus_write_quick); s32 i2c_smbus_read_byte(struct i2c_client *client) { union i2c_smbus_data data; - if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_READ,0,I2C_SMBUS_BYTE, &data)) - return -1; - else - return data.byte; + int status; + + status = i2c_smbus_xfer(client->adapter, client->addr, client->flags, + I2C_SMBUS_READ, 0, + I2C_SMBUS_BYTE, &data); + return (status < 0) ? status : data.byte; } EXPORT_SYMBOL(i2c_smbus_read_byte); @@ -1331,11 +1332,12 @@ EXPORT_SYMBOL(i2c_smbus_write_byte); s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command) { union i2c_smbus_data data; - if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data)) - return -1; - else - return data.byte; + int status; + + status = i2c_smbus_xfer(client->adapter, client->addr, client->flags, + I2C_SMBUS_READ, command, + I2C_SMBUS_BYTE_DATA, &data); + return (status < 0) ? status : data.byte; } EXPORT_SYMBOL(i2c_smbus_read_byte_data); @@ -1352,11 +1354,12 @@ EXPORT_SYMBOL(i2c_smbus_write_byte_data); s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command) { union i2c_smbus_data data; - if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA, &data)) - return -1; - else - return data.word; + int status; + + status = i2c_smbus_xfer(client->adapter, client->addr, client->flags, + I2C_SMBUS_READ, command, + I2C_SMBUS_WORD_DATA, &data); + return (status < 0) ? status : data.word; } EXPORT_SYMBOL(i2c_smbus_read_word_data); @@ -1390,11 +1393,13 @@ s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command, u8 *values) { union i2c_smbus_data data; + int status; - if (i2c_smbus_xfer(client->adapter, client->addr, client->flags, - I2C_SMBUS_READ, command, - I2C_SMBUS_BLOCK_DATA, &data)) - return -1; + status = i2c_smbus_xfer(client->adapter, client->addr, client->flags, + I2C_SMBUS_READ, command, + I2C_SMBUS_BLOCK_DATA, &data); + if (status) + return status; memcpy(values, &data.block[1], data.block[0]); return data.block[0]; @@ -1421,14 +1426,16 @@ s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 length, u8 *values) { union i2c_smbus_data data; + int status; if (length > I2C_SMBUS_BLOCK_MAX) length = I2C_SMBUS_BLOCK_MAX; data.block[0] = length; - if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_READ,command, - I2C_SMBUS_I2C_BLOCK_DATA,&data)) - return -1; + status = i2c_smbus_xfer(client->adapter, client->addr, client->flags, + I2C_SMBUS_READ, command, + I2C_SMBUS_I2C_BLOCK_DATA, &data); + if (status < 0) + return status; memcpy(values, &data.block[1], data.block[0]); return data.block[0]; @@ -1469,6 +1476,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, }; int i; u8 partial_pec = 0; + int status; msgbuf0[0] = command; switch(size) { @@ -1518,10 +1526,10 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, } else { msg[0].len = data->block[0] + 2; if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { - dev_err(&adapter->dev, "smbus_access called with " - "invalid block write size (%d)\n", - data->block[0]); - return -1; + dev_err(&adapter->dev, + "Invalid block write size %d\n", + data->block[0]); + return -EINVAL; } for (i = 1; i < msg[0].len; i++) msgbuf0[i] = data->block[i-1]; @@ -1531,10 +1539,10 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, num = 2; /* Another special case */ read_write = I2C_SMBUS_READ; if (data->block[0] > I2C_SMBUS_BLOCK_MAX) { - dev_err(&adapter->dev, "%s called with invalid " - "block proc call size (%d)\n", __func__, + dev_err(&adapter->dev, + "Invalid block write size %d\n", data->block[0]); - return -1; + return -EINVAL; } msg[0].len = data->block[0] + 2; for (i = 1; i < msg[0].len; i++) @@ -1549,19 +1557,18 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, } else { msg[0].len = data->block[0] + 1; if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) { - dev_err(&adapter->dev, "i2c_smbus_xfer_emulated called with " - "invalid block write size (%d)\n", - data->block[0]); - return -1; + dev_err(&adapter->dev, + "Invalid block write size %d\n", + data->block[0]); + return -EINVAL; } for (i = 1; i <= data->block[0]; i++) msgbuf0[i] = data->block[i]; } break; default: - dev_err(&adapter->dev, "smbus_access called with invalid size (%d)\n", - size); - return -1; + dev_err(&adapter->dev, "Unsupported transaction %d\n", size); + return -EOPNOTSUPP; } i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK @@ -1579,13 +1586,15 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, msg[num-1].len++; } - if (i2c_transfer(adapter, msg, num) < 0) - return -1; + status = i2c_transfer(adapter, msg, num); + if (status < 0) + return status; /* Check PEC if last message is a read */ if (i && (msg[num-1].flags & I2C_M_RD)) { - if (i2c_smbus_check_pec(partial_pec, &msg[num-1]) < 0) - return -1; + status = i2c_smbus_check_pec(partial_pec, &msg[num-1]); + if (status < 0) + return status; } if (read_write == I2C_SMBUS_READ) -- cgit v1.2.3 From 67c2e66571c383404a5acd08189194da660da942 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 14 Jul 2008 22:38:23 +0200 Subject: i2c: Delete unused function i2c_smbus_write_quick Function i2c_smbus_write_quick has no users left, so we can delete it. Also update the list of these helper functions which are gone but could be added back if needed. Signed-off-by: Jean Delvare --- Documentation/i2c/smbus-protocol | 4 ++-- Documentation/i2c/writing-clients | 14 +++++++------- drivers/i2c/i2c-core.c | 7 ------- include/linux/i2c.h | 1 - 4 files changed, 9 insertions(+), 17 deletions(-) (limited to 'Documentation') diff --git a/Documentation/i2c/smbus-protocol b/Documentation/i2c/smbus-protocol index 03f08fb491cc..24bfb65da17d 100644 --- a/Documentation/i2c/smbus-protocol +++ b/Documentation/i2c/smbus-protocol @@ -42,8 +42,8 @@ Count (8 bits): A data byte containing the length of a block operation. [..]: Data sent by I2C device, as opposed to data sent by the host adapter. -SMBus Quick Command: i2c_smbus_write_quick() -============================================= +SMBus Quick Command +=================== This sends a single bit to the device, at the place of the Rd/Wr bit. diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index ba5d1971f35f..63722d3c9cdf 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -569,7 +569,6 @@ SMBus communication in terms of it. Never use this function directly! - extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value); extern s32 i2c_smbus_read_byte(struct i2c_client * client); extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value); extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command); @@ -578,20 +577,21 @@ SMBus communication extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command); extern s32 i2c_smbus_write_word_data(struct i2c_client * client, u8 command, u16 value); + extern s32 i2c_smbus_read_block_data(struct i2c_client * client, + u8 command, u8 *values); extern s32 i2c_smbus_write_block_data(struct i2c_client * client, u8 command, u8 length, u8 *values); extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, u8 command, u8 length, u8 *values); - -These ones were removed in Linux 2.6.10 because they had no users, but could -be added back later if needed: - - extern s32 i2c_smbus_read_block_data(struct i2c_client * client, - u8 command, u8 *values); extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client, u8 command, u8 length, u8 *values); + +These ones were removed from i2c-core because they had no users, but could +be added back later if needed: + + extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value); extern s32 i2c_smbus_process_call(struct i2c_client * client, u8 command, u16 value); extern s32 i2c_smbus_block_process_call(struct i2c_client *client, diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 937f1dcbf3d7..3695a4a1ab77 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1303,13 +1303,6 @@ static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg) return 0; } -s32 i2c_smbus_write_quick(struct i2c_client *client, u8 value) -{ - return i2c_smbus_xfer(client->adapter,client->addr,client->flags, - value,0,I2C_SMBUS_QUICK,NULL); -} -EXPORT_SYMBOL(i2c_smbus_write_quick); - s32 i2c_smbus_read_byte(struct i2c_client *client) { union i2c_smbus_data data; diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 8dc730132192..b3695f353f79 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -71,7 +71,6 @@ extern s32 i2c_smbus_xfer (struct i2c_adapter * adapter, u16 addr, /* Now follow the 'nice' access routines. These also document the calling conventions of smbus_access. */ -extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value); extern s32 i2c_smbus_read_byte(struct i2c_client * client); extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value); extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command); -- cgit v1.2.3 From 4735c98f8447acb1c8977e2b8024640f7bf36dd6 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 14 Jul 2008 22:38:36 +0200 Subject: i2c: Add detection capability to new-style drivers Add a mechanism to let new-style i2c drivers optionally autodetect devices they would support on selected buses and ask i2c-core to instantiate them. This is a replacement for legacy i2c drivers, much cleaner. Where drivers had to implement both a legacy i2c_driver and a new-style i2c_driver so far, this mechanism makes it possible to get rid of the legacy i2c_driver and implement both enumerated and detected device support with just one (new-style) i2c_driver. Here is a quick conversion guide for these drivers, step by step: * Delete the legacy driver definition, registration and removal. Delete the attach_adapter and detach_client methods of the legacy driver. * Change the prototype of the legacy detect function from static int foo_detect(struct i2c_adapter *adapter, int address, int kind); to static int foo_detect(struct i2c_client *client, int kind, struct i2c_board_info *info); * Set the new-style driver detect callback to this new function, and set its address_data to &addr_data (addr_data is generally provided by I2C_CLIENT_INSMOD.) * Add the appropriate class to the new-style driver. This is typically the class the legacy attach_adapter method was checking for. Class checking is now mandatory (done by i2c-core.) See for the list of available classes. * Remove the i2c_client allocation and freeing from the detect function. A pre-allocated client is now handed to you by i2c-core, and is freed automatically. * Make the detect function fill the type field of the i2c_board_info structure it was passed as a parameter, and return 0, on success. If the detection fails, return -ENODEV. Signed-off-by: Jean Delvare --- Documentation/i2c/writing-clients | 29 +++++ drivers/i2c/i2c-core.c | 223 ++++++++++++++++++++++++++++++++++++-- include/linux/i2c.h | 36 +++++- 3 files changed, 272 insertions(+), 16 deletions(-) (limited to 'Documentation') diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index 63722d3c9cdf..6b61b3a2e90b 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -44,6 +44,10 @@ static struct i2c_driver foo_driver = { .id_table = foo_ids, .probe = foo_probe, .remove = foo_remove, + /* if device autodetection is needed: */ + .class = I2C_CLASS_SOMETHING, + .detect = foo_detect, + .address_data = &addr_data, /* else, driver uses "legacy" binding model: */ .attach_adapter = foo_attach_adapter, @@ -217,6 +221,31 @@ in the I2C bus driver. You may want to save the returned i2c_client reference for later use. +Device Detection (Standard driver model) +---------------------------------------- + +Sometimes you do not know in advance which I2C devices are connected to +a given I2C bus. This is for example the case of hardware monitoring +devices on a PC's SMBus. In that case, you may want to let your driver +detect supported devices automatically. This is how the legacy model +was working, and is now available as an extension to the standard +driver model (so that we can finally get rid of the legacy model.) + +You simply have to define a detect callback which will attempt to +identify supported devices (returning 0 for supported ones and -ENODEV +for unsupported ones), a list of addresses to probe, and a device type +(or class) so that only I2C buses which may have that type of device +connected (and not otherwise enumerated) will be probed. The i2c +core will then call you back as needed and will instantiate a device +for you for every successful detection. + +Note that this mechanism is purely optional and not suitable for all +devices. You need some reliable way to identify the supported devices +(typically using device-specific, dedicated identification registers), +otherwise misdetections are likely to occur and things can get wrong +quickly. + + Device Deletion (Standard driver model) --------------------------------------- diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 5e249d758828..0a79f7661017 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -42,7 +42,9 @@ static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); -#define is_newstyle_driver(d) ((d)->probe || (d)->remove) +#define is_newstyle_driver(d) ((d)->probe || (d)->remove || (d)->detect) + +static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); /* ------------------------------------------------------------------------- */ @@ -418,6 +420,10 @@ static int i2c_do_add_adapter(struct device_driver *d, void *data) struct i2c_driver *driver = to_i2c_driver(d); struct i2c_adapter *adap = data; + /* Detect supported devices on that bus, and instantiate them */ + i2c_detect(adap, driver); + + /* Let legacy drivers scan this bus for matching devices */ if (driver->attach_adapter) { /* We ignore the return code; if it fails, too bad */ driver->attach_adapter(adap); @@ -457,7 +463,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); - /* let legacy drivers scan this bus for matching devices */ + /* Notify drivers */ dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, i2c_do_add_adapter); @@ -563,8 +569,19 @@ static int i2c_do_del_adapter(struct device_driver *d, void *data) { struct i2c_driver *driver = to_i2c_driver(d); struct i2c_adapter *adapter = data; + struct i2c_client *client, *_n; int res; + /* Remove the devices we created ourselves */ + list_for_each_entry_safe(client, _n, &driver->clients, detected) { + if (client->adapter == adapter) { + dev_dbg(&adapter->dev, "Removing %s at 0x%x\n", + client->name, client->addr); + list_del(&client->detected); + i2c_unregister_device(client); + } + } + if (!driver->detach_adapter) return 0; res = driver->detach_adapter(adapter); @@ -651,7 +668,11 @@ static int __attach_adapter(struct device *dev, void *data) struct i2c_adapter *adapter = to_i2c_adapter(dev); struct i2c_driver *driver = data; - driver->attach_adapter(adapter); + i2c_detect(adapter, driver); + + /* Legacy drivers scan i2c busses directly */ + if (driver->attach_adapter) + driver->attach_adapter(adapter); return 0; } @@ -695,10 +716,9 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); - /* legacy drivers scan i2c busses directly */ - if (driver->attach_adapter) - class_for_each_device(&i2c_adapter_class, driver, - __attach_adapter); + INIT_LIST_HEAD(&driver->clients); + /* Walk the adapters that are already present */ + class_for_each_device(&i2c_adapter_class, driver, __attach_adapter); mutex_unlock(&core_lock); return 0; @@ -709,6 +729,17 @@ static int __detach_adapter(struct device *dev, void *data) { struct i2c_adapter *adapter = to_i2c_adapter(dev); struct i2c_driver *driver = data; + struct i2c_client *client, *_n; + + list_for_each_entry_safe(client, _n, &driver->clients, detected) { + dev_dbg(&adapter->dev, "Removing %s at 0x%x\n", + client->name, client->addr); + list_del(&client->detected); + i2c_unregister_device(client); + } + + if (is_newstyle_driver(driver)) + return 0; /* Have a look at each adapter, if clients of this driver are still * attached. If so, detach them to be able to kill the driver @@ -747,10 +778,7 @@ void i2c_del_driver(struct i2c_driver *driver) { mutex_lock(&core_lock); - /* legacy driver? */ - if (!is_newstyle_driver(driver)) - class_for_each_device(&i2c_adapter_class, driver, - __detach_adapter); + class_for_each_device(&i2c_adapter_class, driver, __detach_adapter); driver_unregister(&driver->driver); pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); @@ -1205,6 +1233,179 @@ int i2c_probe(struct i2c_adapter *adapter, } EXPORT_SYMBOL(i2c_probe); +/* Separate detection function for new-style drivers */ +static int i2c_detect_address(struct i2c_client *temp_client, int kind, + struct i2c_driver *driver) +{ + struct i2c_board_info info; + struct i2c_adapter *adapter = temp_client->adapter; + int addr = temp_client->addr; + int err; + + /* Make sure the address is valid */ + if (addr < 0x03 || addr > 0x77) { + dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n", + addr); + return -EINVAL; + } + + /* Skip if already in use */ + if (i2c_check_addr(adapter, addr)) + return 0; + + /* Make sure there is something at this address, unless forced */ + if (kind < 0) { + if (i2c_smbus_xfer(adapter, addr, 0, 0, 0, + I2C_SMBUS_QUICK, NULL) < 0) + return 0; + + /* prevent 24RF08 corruption */ + if ((addr & ~0x0f) == 0x50) + i2c_smbus_xfer(adapter, addr, 0, 0, 0, + I2C_SMBUS_QUICK, NULL); + } + + /* Finally call the custom detection function */ + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = addr; + err = driver->detect(temp_client, kind, &info); + if (err) { + /* -ENODEV is returned if the detection fails. We catch it + here as this isn't an error. */ + return err == -ENODEV ? 0 : err; + } + + /* Consistency check */ + if (info.type[0] == '\0') { + dev_err(&adapter->dev, "%s detection function provided " + "no name for 0x%x\n", driver->driver.name, + addr); + } else { + struct i2c_client *client; + + /* Detection succeeded, instantiate the device */ + dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n", + info.type, info.addr); + client = i2c_new_device(adapter, &info); + if (client) + list_add_tail(&client->detected, &driver->clients); + else + dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n", + info.type, info.addr); + } + return 0; +} + +static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) +{ + const struct i2c_client_address_data *address_data; + struct i2c_client *temp_client; + int i, err = 0; + int adap_id = i2c_adapter_id(adapter); + + address_data = driver->address_data; + if (!driver->detect || !address_data) + return 0; + + /* Set up a temporary client to help detect callback */ + temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!temp_client) + return -ENOMEM; + temp_client->adapter = adapter; + + /* Force entries are done first, and are not affected by ignore + entries */ + if (address_data->forces) { + const unsigned short * const *forces = address_data->forces; + int kind; + + for (kind = 0; forces[kind]; kind++) { + for (i = 0; forces[kind][i] != I2C_CLIENT_END; + i += 2) { + if (forces[kind][i] == adap_id + || forces[kind][i] == ANY_I2C_BUS) { + dev_dbg(&adapter->dev, "found force " + "parameter for adapter %d, " + "addr 0x%02x, kind %d\n", + adap_id, forces[kind][i + 1], + kind); + temp_client->addr = forces[kind][i + 1]; + err = i2c_detect_address(temp_client, + kind, driver); + if (err) + goto exit_free; + } + } + } + } + + /* Stop here if we can't use SMBUS_QUICK */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) { + if (address_data->probe[0] == I2C_CLIENT_END + && address_data->normal_i2c[0] == I2C_CLIENT_END) + goto exit_free; + + dev_warn(&adapter->dev, "SMBus Quick command not supported, " + "can't probe for chips\n"); + err = -EOPNOTSUPP; + goto exit_free; + } + + /* Stop here if the classes do not match */ + if (!(adapter->class & driver->class)) + goto exit_free; + + /* Probe entries are done second, and are not affected by ignore + entries either */ + for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) { + if (address_data->probe[i] == adap_id + || address_data->probe[i] == ANY_I2C_BUS) { + dev_dbg(&adapter->dev, "found probe parameter for " + "adapter %d, addr 0x%02x\n", adap_id, + address_data->probe[i + 1]); + temp_client->addr = address_data->probe[i + 1]; + err = i2c_detect_address(temp_client, -1, driver); + if (err) + goto exit_free; + } + } + + /* Normal entries are done last, unless shadowed by an ignore entry */ + for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) { + int j, ignore; + + ignore = 0; + for (j = 0; address_data->ignore[j] != I2C_CLIENT_END; + j += 2) { + if ((address_data->ignore[j] == adap_id || + address_data->ignore[j] == ANY_I2C_BUS) + && address_data->ignore[j + 1] + == address_data->normal_i2c[i]) { + dev_dbg(&adapter->dev, "found ignore " + "parameter for adapter %d, " + "addr 0x%02x\n", adap_id, + address_data->ignore[j + 1]); + ignore = 1; + break; + } + } + if (ignore) + continue; + + dev_dbg(&adapter->dev, "found normal entry for adapter %d, " + "addr 0x%02x\n", adap_id, + address_data->normal_i2c[i]); + temp_client->addr = address_data->normal_i2c[i]; + err = i2c_detect_address(temp_client, -1, driver); + if (err) + goto exit_free; + } + + exit_free: + kfree(temp_client); + return err; +} + struct i2c_client * i2c_new_probed_device(struct i2c_adapter *adap, struct i2c_board_info *info, diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 50cbab4b62b0..08be0d21864c 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -45,6 +45,7 @@ struct i2c_adapter; struct i2c_client; struct i2c_driver; union i2c_smbus_data; +struct i2c_board_info; /* * The master routines are the ones normally used to transmit data to devices @@ -94,15 +95,33 @@ extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client, u8 command, u8 length, const u8 *values); -/* - * A driver is capable of handling one or more physical devices present on - * I2C adapters. This information is used to inform the driver of adapter - * events. +/** + * struct i2c_driver - represent an I2C device driver + * @class: What kind of i2c device we instantiate (for detect) + * @detect: Callback for device detection + * @address_data: The I2C addresses to probe, ignore or force (for detect) + * @clients: List of detected clients we created (for i2c-core use only) * * The driver.owner field should be set to the module owner of this driver. * The driver.name field should be set to the name of this driver. + * + * For automatic device detection, both @detect and @address_data must + * be defined. @class should also be set, otherwise only devices forced + * with module parameters will be created. The detect function must + * fill at least the name field of the i2c_board_info structure it is + * handed upon successful detection, and possibly also the flags field. + * + * If @detect is missing, the driver will still work fine for enumerated + * devices. Detected devices simply won't be supported. This is expected + * for the many I2C/SMBus devices which can't be detected reliably, and + * the ones which can always be enumerated in practice. + * + * The i2c_client structure which is handed to the @detect callback is + * not a real i2c_client. It is initialized just enough so that you can + * call i2c_smbus_read_byte_data and friends on it. Don't do anything + * else with it. In particular, calling dev_dbg and friends on it is + * not allowed. */ - struct i2c_driver { int id; unsigned int class; @@ -142,6 +161,11 @@ struct i2c_driver { struct device_driver driver; const struct i2c_device_id *id_table; + + /* Device detection callback for automatic device creation */ + int (*detect)(struct i2c_client *, int kind, struct i2c_board_info *); + const struct i2c_client_address_data *address_data; + struct list_head clients; }; #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver) @@ -157,6 +181,7 @@ struct i2c_driver { * @dev: Driver model device node for the slave. * @irq: indicates the IRQ generated by this device (if any) * @list: list of active/busy clients (DEPRECATED) + * @detected: member of an i2c_driver.clients list * @released: used to synchronize client releases & detaches and references * * An i2c_client identifies a single device (i.e. chip) connected to an @@ -174,6 +199,7 @@ struct i2c_client { struct device dev; /* the device structure */ int irq; /* irq issued by device */ struct list_head list; /* DEPRECATED */ + struct list_head detected; struct completion released; }; #define to_i2c_client(d) container_of(d, struct i2c_client, dev) -- cgit v1.2.3 From d3af01f18bf18e9b2a95711894fc239daeab5e2e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 15 Jul 2008 15:04:56 +0200 Subject: Documentation: document debugpat commandline option Signed-off-by: Thomas Gleixner --- Documentation/kernel-parameters.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index b3a5aad7e629..681d6152e003 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -571,6 +571,8 @@ and is between 256 and 4096 characters. It is defined in the file debug_objects [KNL] Enable object debugging + debugpat [X86] Enable PAT debugging + decnet.addr= [HW,NET] Format: [,] See also Documentation/networking/decnet.txt. -- cgit v1.2.3 From 232595eaff951e96cabe5e85fed35f66b72ff51e Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 15 Jul 2008 21:21:46 +0200 Subject: ide: remove obsoleted "hdx=" kernel parameters * Remove obsoleted "hdx=" kernel parameters. * Remove no longer used stridx() and match_parm(). Signed-off-by: Bartlomiej Zolnierkiewicz --- Documentation/kernel-parameters.txt | 3 - drivers/ide/ide.c | 139 +----------------------------------- 2 files changed, 1 insertion(+), 141 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index b52f47d588b4..faeea507cdca 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -722,9 +722,6 @@ and is between 256 and 4096 characters. It is defined in the file hd= [EIDE] (E)IDE hard drive subsystem geometry Format: ,, - hd?= [HW] (E)IDE subsystem - hd?lun= See Documentation/ide/ide.txt. - highmem=nn[KMG] [KNL,BOOT] forces the highmem zone to have an exact size of . This works even on boxes that have no highmem otherwise. This also works to reduce highmem diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index f65be738b16a..6f600d81a972 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -721,90 +721,14 @@ set_val: EXPORT_SYMBOL(generic_ide_ioctl); -/* - * stridx() returns the offset of c within s, - * or -1 if c is '\0' or not found within s. - */ -static int __init stridx (const char *s, char c) -{ - char *i = strchr(s, c); - return (i && c) ? i - s : -1; -} - -/* - * match_parm() does parsing for ide_setup(): - * - * 1. the first char of s must be '='. - * 2. if the remainder matches one of the supplied keywords, - * the index (1 based) of the keyword is negated and returned. - * 3. if the remainder is a series of no more than max_vals numbers - * separated by commas, the numbers are saved in vals[] and a - * count of how many were saved is returned. Base10 is assumed, - * and base16 is allowed when prefixed with "0x". - * 4. otherwise, zero is returned. - */ -static int __init match_parm (char *s, const char *keywords[], int vals[], int max_vals) -{ - static const char *decimal = "0123456789"; - static const char *hex = "0123456789abcdef"; - int i, n; - - if (*s++ == '=') { - /* - * Try matching against the supplied keywords, - * and return -(index+1) if we match one - */ - if (keywords != NULL) { - for (i = 0; *keywords != NULL; ++i) { - if (!strcmp(s, *keywords++)) - return -(i+1); - } - } - /* - * Look for a series of no more than "max_vals" - * numeric values separated by commas, in base10, - * or base16 when prefixed with "0x". - * Return a count of how many were found. - */ - for (n = 0; (i = stridx(decimal, *s)) >= 0;) { - vals[n] = i; - while ((i = stridx(decimal, *++s)) >= 0) - vals[n] = (vals[n] * 10) + i; - if (*s == 'x' && !vals[n]) { - while ((i = stridx(hex, *++s)) >= 0) - vals[n] = (vals[n] * 0x10) + i; - } - if (++n == max_vals) - break; - if (*s == ',' || *s == ';') - ++s; - } - if (!*s) - return n; - } - return 0; /* zero = nothing matched */ -} - /* * ide_setup() gets called VERY EARLY during initialization, - * to handle kernel "command line" strings beginning with "hdx=" or "ide". + * to handle kernel "command line" strings beginning with "ide". * * Remember to update Documentation/ide/ide.txt if you change something here. */ static int __init ide_setup(char *s) { - ide_hwif_t *hwif; - ide_drive_t *drive; - unsigned int hw, unit; - int vals[3]; - const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1); - - if (strncmp(s,"hd",2) == 0 && s[2] == '=') /* hd= is for hd.c */ - return 0; /* driver and not us */ - - if (strncmp(s, "ide", 3) && strncmp(s, "hd", 2)) - return 0; - printk(KERN_INFO "ide_setup: %s", s); init_ide_data (); @@ -842,67 +766,6 @@ static int __init ide_setup(char *s) } #endif /* CONFIG_BLK_DEV_IDEACPI */ - /* - * Look for drive options: "hdx=" - */ - if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) { - const char *hd_words[] = { - "none", "noprobe", "nowerr", "cdrom", "nodma", - "-6", "-7", "-8", "-9", "-10", - "noflush", "remap", "remap63", "scsi", NULL }; - unit = s[2] - 'a'; - hw = unit / MAX_DRIVES; - unit = unit % MAX_DRIVES; - hwif = &ide_hwifs[hw]; - drive = &hwif->drives[unit]; - if (strncmp(s + 4, "ide-", 4) == 0) { - strlcpy(drive->driver_req, s + 4, sizeof(drive->driver_req)); - goto obsolete_option; - } - switch (match_parm(&s[3], hd_words, vals, 3)) { - case -1: /* "none" */ - case -2: /* "noprobe" */ - drive->noprobe = 1; - goto obsolete_option; - case -3: /* "nowerr" */ - drive->bad_wstat = BAD_R_STAT; - goto obsolete_option; - case -4: /* "cdrom" */ - drive->present = 1; - drive->media = ide_cdrom; - /* an ATAPI device ignores DRDY */ - drive->ready_stat = 0; - goto obsolete_option; - case -5: /* nodma */ - drive->nodma = 1; - goto obsolete_option; - case -11: /* noflush */ - drive->noflush = 1; - goto obsolete_option; - case -12: /* "remap" */ - drive->remap_0_to_1 = 1; - goto obsolete_option; - case -13: /* "remap63" */ - drive->sect0 = 63; - goto obsolete_option; - case -14: /* "scsi" */ - drive->scsi = 1; - goto obsolete_option; - case 3: /* cyl,head,sect */ - drive->media = ide_disk; - drive->ready_stat = READY_STAT; - drive->cyl = drive->bios_cyl = vals[0]; - drive->head = drive->bios_head = vals[1]; - drive->sect = drive->bios_sect = vals[2]; - drive->present = 1; - drive->forced_geom = 1; - goto obsolete_option; - default: - goto bad_option; - } - } - -bad_option: printk(" -- BAD OPTION\n"); return 1; obsolete_option: -- cgit v1.2.3