diff options
370 files changed, 16414 insertions, 4334 deletions
@@ -3741,10 +3741,11 @@ D: Mylex DAC960 PCI RAID driver | |||
3741 | D: Miscellaneous kernel fixes | 3741 | D: Miscellaneous kernel fixes |
3742 | 3742 | ||
3743 | N: Alessandro Zummo | 3743 | N: Alessandro Zummo |
3744 | E: azummo@ita.flashnet.it | 3744 | E: a.zummo@towertech.it |
3745 | W: http://freepage.logicom.it/azummo/ | ||
3746 | D: CMI8330 support is sb_card.c | 3745 | D: CMI8330 support is sb_card.c |
3747 | D: ISAPnP fixes in sb_card.c | 3746 | D: ISAPnP fixes in sb_card.c |
3747 | D: ZyXEL omni.net lcd plus driver | ||
3748 | D: RTC subsystem | ||
3748 | S: Italy | 3749 | S: Italy |
3749 | 3750 | ||
3750 | N: Marc Zyngier | 3751 | N: Marc Zyngier |
diff --git a/Documentation/pnp.txt b/Documentation/pnp.txt index af0f6eabfa1c..9529c9c9fd59 100644 --- a/Documentation/pnp.txt +++ b/Documentation/pnp.txt | |||
@@ -115,6 +115,9 @@ pnp_unregister_protocol | |||
115 | pnp_register_driver | 115 | pnp_register_driver |
116 | - adds a PnP driver to the Plug and Play Layer | 116 | - adds a PnP driver to the Plug and Play Layer |
117 | - this includes driver model integration | 117 | - this includes driver model integration |
118 | - returns zero for success or a negative error number for failure; count | ||
119 | calls to the .add() method if you need to know how many devices bind to | ||
120 | the driver | ||
118 | 121 | ||
119 | pnp_unregister_driver | 122 | pnp_unregister_driver |
120 | - removes a PnP driver from the Plug and Play Layer | 123 | - removes a PnP driver from the Plug and Play Layer |
diff --git a/Documentation/robust-futex-ABI.txt b/Documentation/robust-futex-ABI.txt new file mode 100644 index 000000000000..8529a17ffaa1 --- /dev/null +++ b/Documentation/robust-futex-ABI.txt | |||
@@ -0,0 +1,182 @@ | |||
1 | Started by Paul Jackson <pj@sgi.com> | ||
2 | |||
3 | The robust futex ABI | ||
4 | -------------------- | ||
5 | |||
6 | Robust_futexes provide a mechanism that is used in addition to normal | ||
7 | futexes, for kernel assist of cleanup of held locks on task exit. | ||
8 | |||
9 | The interesting data as to what futexes a thread is holding is kept on a | ||
10 | linked list in user space, where it can be updated efficiently as locks | ||
11 | are taken and dropped, without kernel intervention. The only additional | ||
12 | kernel intervention required for robust_futexes above and beyond what is | ||
13 | required for futexes is: | ||
14 | |||
15 | 1) a one time call, per thread, to tell the kernel where its list of | ||
16 | held robust_futexes begins, and | ||
17 | 2) internal kernel code at exit, to handle any listed locks held | ||
18 | by the exiting thread. | ||
19 | |||
20 | The existing normal futexes already provide a "Fast Userspace Locking" | ||
21 | mechanism, which handles uncontested locking without needing a system | ||
22 | call, and handles contested locking by maintaining a list of waiting | ||
23 | threads in the kernel. Options on the sys_futex(2) system call support | ||
24 | waiting on a particular futex, and waking up the next waiter on a | ||
25 | particular futex. | ||
26 | |||
27 | For robust_futexes to work, the user code (typically in a library such | ||
28 | as glibc linked with the application) has to manage and place the | ||
29 | necessary list elements exactly as the kernel expects them. If it fails | ||
30 | to do so, then improperly listed locks will not be cleaned up on exit, | ||
31 | probably causing deadlock or other such failure of the other threads | ||
32 | waiting on the same locks. | ||
33 | |||
34 | A thread that anticipates possibly using robust_futexes should first | ||
35 | issue the system call: | ||
36 | |||
37 | asmlinkage long | ||
38 | sys_set_robust_list(struct robust_list_head __user *head, size_t len); | ||
39 | |||
40 | The pointer 'head' points to a structure in the threads address space | ||
41 | consisting of three words. Each word is 32 bits on 32 bit arch's, or 64 | ||
42 | bits on 64 bit arch's, and local byte order. Each thread should have | ||
43 | its own thread private 'head'. | ||
44 | |||
45 | If a thread is running in 32 bit compatibility mode on a 64 native arch | ||
46 | kernel, then it can actually have two such structures - one using 32 bit | ||
47 | words for 32 bit compatibility mode, and one using 64 bit words for 64 | ||
48 | bit native mode. The kernel, if it is a 64 bit kernel supporting 32 bit | ||
49 | compatibility mode, will attempt to process both lists on each task | ||
50 | exit, if the corresponding sys_set_robust_list() call has been made to | ||
51 | setup that list. | ||
52 | |||
53 | The first word in the memory structure at 'head' contains a | ||
54 | pointer to a single linked list of 'lock entries', one per lock, | ||
55 | as described below. If the list is empty, the pointer will point | ||
56 | to itself, 'head'. The last 'lock entry' points back to the 'head'. | ||
57 | |||
58 | The second word, called 'offset', specifies the offset from the | ||
59 | address of the associated 'lock entry', plus or minus, of what will | ||
60 | be called the 'lock word', from that 'lock entry'. The 'lock word' | ||
61 | is always a 32 bit word, unlike the other words above. The 'lock | ||
62 | word' holds 3 flag bits in the upper 3 bits, and the thread id (TID) | ||
63 | of the thread holding the lock in the bottom 29 bits. See further | ||
64 | below for a description of the flag bits. | ||
65 | |||
66 | The third word, called 'list_op_pending', contains transient copy of | ||
67 | the address of the 'lock entry', during list insertion and removal, | ||
68 | and is needed to correctly resolve races should a thread exit while | ||
69 | in the middle of a locking or unlocking operation. | ||
70 | |||
71 | Each 'lock entry' on the single linked list starting at 'head' consists | ||
72 | of just a single word, pointing to the next 'lock entry', or back to | ||
73 | 'head' if there are no more entries. In addition, nearby to each 'lock | ||
74 | entry', at an offset from the 'lock entry' specified by the 'offset' | ||
75 | word, is one 'lock word'. | ||
76 | |||
77 | The 'lock word' is always 32 bits, and is intended to be the same 32 bit | ||
78 | lock variable used by the futex mechanism, in conjunction with | ||
79 | robust_futexes. The kernel will only be able to wakeup the next thread | ||
80 | waiting for a lock on a threads exit if that next thread used the futex | ||
81 | mechanism to register the address of that 'lock word' with the kernel. | ||
82 | |||
83 | For each futex lock currently held by a thread, if it wants this | ||
84 | robust_futex support for exit cleanup of that lock, it should have one | ||
85 | 'lock entry' on this list, with its associated 'lock word' at the | ||
86 | specified 'offset'. Should a thread die while holding any such locks, | ||
87 | the kernel will walk this list, mark any such locks with a bit | ||
88 | indicating their holder died, and wakeup the next thread waiting for | ||
89 | that lock using the futex mechanism. | ||
90 | |||
91 | When a thread has invoked the above system call to indicate it | ||
92 | anticipates using robust_futexes, the kernel stores the passed in 'head' | ||
93 | pointer for that task. The task may retrieve that value later on by | ||
94 | using the system call: | ||
95 | |||
96 | asmlinkage long | ||
97 | sys_get_robust_list(int pid, struct robust_list_head __user **head_ptr, | ||
98 | size_t __user *len_ptr); | ||
99 | |||
100 | It is anticipated that threads will use robust_futexes embedded in | ||
101 | larger, user level locking structures, one per lock. The kernel | ||
102 | robust_futex mechanism doesn't care what else is in that structure, so | ||
103 | long as the 'offset' to the 'lock word' is the same for all | ||
104 | robust_futexes used by that thread. The thread should link those locks | ||
105 | it currently holds using the 'lock entry' pointers. It may also have | ||
106 | other links between the locks, such as the reverse side of a double | ||
107 | linked list, but that doesn't matter to the kernel. | ||
108 | |||
109 | By keeping its locks linked this way, on a list starting with a 'head' | ||
110 | pointer known to the kernel, the kernel can provide to a thread the | ||
111 | essential service available for robust_futexes, which is to help clean | ||
112 | up locks held at the time of (a perhaps unexpectedly) exit. | ||
113 | |||
114 | Actual locking and unlocking, during normal operations, is handled | ||
115 | entirely by user level code in the contending threads, and by the | ||
116 | existing futex mechanism to wait for, and wakeup, locks. The kernels | ||
117 | only essential involvement in robust_futexes is to remember where the | ||
118 | list 'head' is, and to walk the list on thread exit, handling locks | ||
119 | still held by the departing thread, as described below. | ||
120 | |||
121 | There may exist thousands of futex lock structures in a threads shared | ||
122 | memory, on various data structures, at a given point in time. Only those | ||
123 | lock structures for locks currently held by that thread should be on | ||
124 | that thread's robust_futex linked lock list a given time. | ||
125 | |||
126 | A given futex lock structure in a user shared memory region may be held | ||
127 | at different times by any of the threads with access to that region. The | ||
128 | thread currently holding such a lock, if any, is marked with the threads | ||
129 | TID in the lower 29 bits of the 'lock word'. | ||
130 | |||
131 | When adding or removing a lock from its list of held locks, in order for | ||
132 | the kernel to correctly handle lock cleanup regardless of when the task | ||
133 | exits (perhaps it gets an unexpected signal 9 in the middle of | ||
134 | manipulating this list), the user code must observe the following | ||
135 | protocol on 'lock entry' insertion and removal: | ||
136 | |||
137 | On insertion: | ||
138 | 1) set the 'list_op_pending' word to the address of the 'lock word' | ||
139 | to be inserted, | ||
140 | 2) acquire the futex lock, | ||
141 | 3) add the lock entry, with its thread id (TID) in the bottom 29 bits | ||
142 | of the 'lock word', to the linked list starting at 'head', and | ||
143 | 4) clear the 'list_op_pending' word. | ||
144 | |||
145 | On removal: | ||
146 | 1) set the 'list_op_pending' word to the address of the 'lock word' | ||
147 | to be removed, | ||
148 | 2) remove the lock entry for this lock from the 'head' list, | ||
149 | 2) release the futex lock, and | ||
150 | 2) clear the 'lock_op_pending' word. | ||
151 | |||
152 | On exit, the kernel will consider the address stored in | ||
153 | 'list_op_pending' and the address of each 'lock word' found by walking | ||
154 | the list starting at 'head'. For each such address, if the bottom 29 | ||
155 | bits of the 'lock word' at offset 'offset' from that address equals the | ||
156 | exiting threads TID, then the kernel will do two things: | ||
157 | |||
158 | 1) if bit 31 (0x80000000) is set in that word, then attempt a futex | ||
159 | wakeup on that address, which will waken the next thread that has | ||
160 | used to the futex mechanism to wait on that address, and | ||
161 | 2) atomically set bit 30 (0x40000000) in the 'lock word'. | ||
162 | |||
163 | In the above, bit 31 was set by futex waiters on that lock to indicate | ||
164 | they were waiting, and bit 30 is set by the kernel to indicate that the | ||
165 | lock owner died holding the lock. | ||
166 | |||
167 | The kernel exit code will silently stop scanning the list further if at | ||
168 | any point: | ||
169 | |||
170 | 1) the 'head' pointer or an subsequent linked list pointer | ||
171 | is not a valid address of a user space word | ||
172 | 2) the calculated location of the 'lock word' (address plus | ||
173 | 'offset') is not the valud address of a 32 bit user space | ||
174 | word | ||
175 | 3) if the list contains more than 1 million (subject to | ||
176 | future kernel configuration changes) elements. | ||
177 | |||
178 | When the kernel sees a list entry whose 'lock word' doesn't have the | ||
179 | current threads TID in the lower 29 bits, it does nothing with that | ||
180 | entry, and goes on to the next entry. | ||
181 | |||
182 | Bit 29 (0x20000000) of the 'lock word' is reserved for future use. | ||
diff --git a/Documentation/robust-futexes.txt b/Documentation/robust-futexes.txt new file mode 100644 index 000000000000..df82d75245a0 --- /dev/null +++ b/Documentation/robust-futexes.txt | |||
@@ -0,0 +1,218 @@ | |||
1 | Started by: Ingo Molnar <mingo@redhat.com> | ||
2 | |||
3 | Background | ||
4 | ---------- | ||
5 | |||
6 | what are robust futexes? To answer that, we first need to understand | ||
7 | what futexes are: normal futexes are special types of locks that in the | ||
8 | noncontended case can be acquired/released from userspace without having | ||
9 | to enter the kernel. | ||
10 | |||
11 | A futex is in essence a user-space address, e.g. a 32-bit lock variable | ||
12 | field. If userspace notices contention (the lock is already owned and | ||
13 | someone else wants to grab it too) then the lock is marked with a value | ||
14 | that says "there's a waiter pending", and the sys_futex(FUTEX_WAIT) | ||
15 | syscall is used to wait for the other guy to release it. The kernel | ||
16 | creates a 'futex queue' internally, so that it can later on match up the | ||
17 | waiter with the waker - without them having to know about each other. | ||
18 | When the owner thread releases the futex, it notices (via the variable | ||
19 | value) that there were waiter(s) pending, and does the | ||
20 | sys_futex(FUTEX_WAKE) syscall to wake them up. Once all waiters have | ||
21 | taken and released the lock, the futex is again back to 'uncontended' | ||
22 | state, and there's no in-kernel state associated with it. The kernel | ||
23 | completely forgets that there ever was a futex at that address. This | ||
24 | method makes futexes very lightweight and scalable. | ||
25 | |||
26 | "Robustness" is about dealing with crashes while holding a lock: if a | ||
27 | process exits prematurely while holding a pthread_mutex_t lock that is | ||
28 | also shared with some other process (e.g. yum segfaults while holding a | ||
29 | pthread_mutex_t, or yum is kill -9-ed), then waiters for that lock need | ||
30 | to be notified that the last owner of the lock exited in some irregular | ||
31 | way. | ||
32 | |||
33 | To solve such types of problems, "robust mutex" userspace APIs were | ||
34 | created: pthread_mutex_lock() returns an error value if the owner exits | ||
35 | prematurely - and the new owner can decide whether the data protected by | ||
36 | the lock can be recovered safely. | ||
37 | |||
38 | There is a big conceptual problem with futex based mutexes though: it is | ||
39 | the kernel that destroys the owner task (e.g. due to a SEGFAULT), but | ||
40 | the kernel cannot help with the cleanup: if there is no 'futex queue' | ||
41 | (and in most cases there is none, futexes being fast lightweight locks) | ||
42 | then the kernel has no information to clean up after the held lock! | ||
43 | Userspace has no chance to clean up after the lock either - userspace is | ||
44 | the one that crashes, so it has no opportunity to clean up. Catch-22. | ||
45 | |||
46 | In practice, when e.g. yum is kill -9-ed (or segfaults), a system reboot | ||
47 | is needed to release that futex based lock. This is one of the leading | ||
48 | bugreports against yum. | ||
49 | |||
50 | To solve this problem, the traditional approach was to extend the vma | ||
51 | (virtual memory area descriptor) concept to have a notion of 'pending | ||
52 | robust futexes attached to this area'. This approach requires 3 new | ||
53 | syscall variants to sys_futex(): FUTEX_REGISTER, FUTEX_DEREGISTER and | ||
54 | FUTEX_RECOVER. At do_exit() time, all vmas are searched to see whether | ||
55 | they have a robust_head set. This approach has two fundamental problems | ||
56 | left: | ||
57 | |||
58 | - it has quite complex locking and race scenarios. The vma-based | ||
59 | approach had been pending for years, but they are still not completely | ||
60 | reliable. | ||
61 | |||
62 | - they have to scan _every_ vma at sys_exit() time, per thread! | ||
63 | |||
64 | The second disadvantage is a real killer: pthread_exit() takes around 1 | ||
65 | microsecond on Linux, but with thousands (or tens of thousands) of vmas | ||
66 | every pthread_exit() takes a millisecond or more, also totally | ||
67 | destroying the CPU's L1 and L2 caches! | ||
68 | |||
69 | This is very much noticeable even for normal process sys_exit_group() | ||
70 | calls: the kernel has to do the vma scanning unconditionally! (this is | ||
71 | because the kernel has no knowledge about how many robust futexes there | ||
72 | are to be cleaned up, because a robust futex might have been registered | ||
73 | in another task, and the futex variable might have been simply mmap()-ed | ||
74 | into this process's address space). | ||
75 | |||
76 | This huge overhead forced the creation of CONFIG_FUTEX_ROBUST so that | ||
77 | normal kernels can turn it off, but worse than that: the overhead makes | ||
78 | robust futexes impractical for any type of generic Linux distribution. | ||
79 | |||
80 | So something had to be done. | ||
81 | |||
82 | New approach to robust futexes | ||
83 | ------------------------------ | ||
84 | |||
85 | At the heart of this new approach there is a per-thread private list of | ||
86 | robust locks that userspace is holding (maintained by glibc) - which | ||
87 | userspace list is registered with the kernel via a new syscall [this | ||
88 | registration happens at most once per thread lifetime]. At do_exit() | ||
89 | time, the kernel checks this user-space list: are there any robust futex | ||
90 | locks to be cleaned up? | ||
91 | |||
92 | In the common case, at do_exit() time, there is no list registered, so | ||
93 | the cost of robust futexes is just a simple current->robust_list != NULL | ||
94 | comparison. If the thread has registered a list, then normally the list | ||
95 | is empty. If the thread/process crashed or terminated in some incorrect | ||
96 | way then the list might be non-empty: in this case the kernel carefully | ||
97 | walks the list [not trusting it], and marks all locks that are owned by | ||
98 | this thread with the FUTEX_OWNER_DEAD bit, and wakes up one waiter (if | ||
99 | any). | ||
100 | |||
101 | The list is guaranteed to be private and per-thread at do_exit() time, | ||
102 | so it can be accessed by the kernel in a lockless way. | ||
103 | |||
104 | There is one race possible though: since adding to and removing from the | ||
105 | list is done after the futex is acquired by glibc, there is a few | ||
106 | instructions window for the thread (or process) to die there, leaving | ||
107 | the futex hung. To protect against this possibility, userspace (glibc) | ||
108 | also maintains a simple per-thread 'list_op_pending' field, to allow the | ||
109 | kernel to clean up if the thread dies after acquiring the lock, but just | ||
110 | before it could have added itself to the list. Glibc sets this | ||
111 | list_op_pending field before it tries to acquire the futex, and clears | ||
112 | it after the list-add (or list-remove) has finished. | ||
113 | |||
114 | That's all that is needed - all the rest of robust-futex cleanup is done | ||
115 | in userspace [just like with the previous patches]. | ||
116 | |||
117 | Ulrich Drepper has implemented the necessary glibc support for this new | ||
118 | mechanism, which fully enables robust mutexes. | ||
119 | |||
120 | Key differences of this userspace-list based approach, compared to the | ||
121 | vma based method: | ||
122 | |||
123 | - it's much, much faster: at thread exit time, there's no need to loop | ||
124 | over every vma (!), which the VM-based method has to do. Only a very | ||
125 | simple 'is the list empty' op is done. | ||
126 | |||
127 | - no VM changes are needed - 'struct address_space' is left alone. | ||
128 | |||
129 | - no registration of individual locks is needed: robust mutexes dont | ||
130 | need any extra per-lock syscalls. Robust mutexes thus become a very | ||
131 | lightweight primitive - so they dont force the application designer | ||
132 | to do a hard choice between performance and robustness - robust | ||
133 | mutexes are just as fast. | ||
134 | |||
135 | - no per-lock kernel allocation happens. | ||
136 | |||
137 | - no resource limits are needed. | ||
138 | |||
139 | - no kernel-space recovery call (FUTEX_RECOVER) is needed. | ||
140 | |||
141 | - the implementation and the locking is "obvious", and there are no | ||
142 | interactions with the VM. | ||
143 | |||
144 | Performance | ||
145 | ----------- | ||
146 | |||
147 | I have benchmarked the time needed for the kernel to process a list of 1 | ||
148 | million (!) held locks, using the new method [on a 2GHz CPU]: | ||
149 | |||
150 | - with FUTEX_WAIT set [contended mutex]: 130 msecs | ||
151 | - without FUTEX_WAIT set [uncontended mutex]: 30 msecs | ||
152 | |||
153 | I have also measured an approach where glibc does the lock notification | ||
154 | [which it currently does for !pshared robust mutexes], and that took 256 | ||
155 | msecs - clearly slower, due to the 1 million FUTEX_WAKE syscalls | ||
156 | userspace had to do. | ||
157 | |||
158 | (1 million held locks are unheard of - we expect at most a handful of | ||
159 | locks to be held at a time. Nevertheless it's nice to know that this | ||
160 | approach scales nicely.) | ||
161 | |||
162 | Implementation details | ||
163 | ---------------------- | ||
164 | |||
165 | The patch adds two new syscalls: one to register the userspace list, and | ||
166 | one to query the registered list pointer: | ||
167 | |||
168 | asmlinkage long | ||
169 | sys_set_robust_list(struct robust_list_head __user *head, | ||
170 | size_t len); | ||
171 | |||
172 | asmlinkage long | ||
173 | sys_get_robust_list(int pid, struct robust_list_head __user **head_ptr, | ||
174 | size_t __user *len_ptr); | ||
175 | |||
176 | List registration is very fast: the pointer is simply stored in | ||
177 | current->robust_list. [Note that in the future, if robust futexes become | ||
178 | widespread, we could extend sys_clone() to register a robust-list head | ||
179 | for new threads, without the need of another syscall.] | ||
180 | |||
181 | So there is virtually zero overhead for tasks not using robust futexes, | ||
182 | and even for robust futex users, there is only one extra syscall per | ||
183 | thread lifetime, and the cleanup operation, if it happens, is fast and | ||
184 | straightforward. The kernel doesnt have any internal distinction between | ||
185 | robust and normal futexes. | ||
186 | |||
187 | If a futex is found to be held at exit time, the kernel sets the | ||
188 | following bit of the futex word: | ||
189 | |||
190 | #define FUTEX_OWNER_DIED 0x40000000 | ||
191 | |||
192 | and wakes up the next futex waiter (if any). User-space does the rest of | ||
193 | the cleanup. | ||
194 | |||
195 | Otherwise, robust futexes are acquired by glibc by putting the TID into | ||
196 | the futex field atomically. Waiters set the FUTEX_WAITERS bit: | ||
197 | |||
198 | #define FUTEX_WAITERS 0x80000000 | ||
199 | |||
200 | and the remaining bits are for the TID. | ||
201 | |||
202 | Testing, architecture support | ||
203 | ----------------------------- | ||
204 | |||
205 | i've tested the new syscalls on x86 and x86_64, and have made sure the | ||
206 | parsing of the userspace list is robust [ ;-) ] even if the list is | ||
207 | deliberately corrupted. | ||
208 | |||
209 | i386 and x86_64 syscalls are wired up at the moment, and Ulrich has | ||
210 | tested the new glibc code (on x86_64 and i386), and it works for his | ||
211 | robust-mutex testcases. | ||
212 | |||
213 | All other architectures should build just fine too - but they wont have | ||
214 | the new syscalls yet. | ||
215 | |||
216 | Architectures need to implement the new futex_atomic_cmpxchg_inatomic() | ||
217 | inline function before writing up the syscalls (that function returns | ||
218 | -ENOSYS right now). | ||
diff --git a/Documentation/rpc-cache.txt b/Documentation/rpc-cache.txt index 2b5d4434fa5a..5f757c8cf979 100644 --- a/Documentation/rpc-cache.txt +++ b/Documentation/rpc-cache.txt | |||
@@ -1,4 +1,4 @@ | |||
1 | This document gives a brief introduction to the caching | 1 | This document gives a brief introduction to the caching |
2 | mechanisms in the sunrpc layer that is used, in particular, | 2 | mechanisms in the sunrpc layer that is used, in particular, |
3 | for NFS authentication. | 3 | for NFS authentication. |
4 | 4 | ||
@@ -25,25 +25,17 @@ The common code handles such things as: | |||
25 | - supporting 'NEGATIVE' as well as positive entries | 25 | - supporting 'NEGATIVE' as well as positive entries |
26 | - allowing an EXPIRED time on cache items, and removing | 26 | - allowing an EXPIRED time on cache items, and removing |
27 | items after they expire, and are no longe in-use. | 27 | items after they expire, and are no longe in-use. |
28 | |||
29 | Future code extensions are expect to handle | ||
30 | - making requests to user-space to fill in cache entries | 28 | - making requests to user-space to fill in cache entries |
31 | - allowing user-space to directly set entries in the cache | 29 | - allowing user-space to directly set entries in the cache |
32 | - delaying RPC requests that depend on as-yet incomplete | 30 | - delaying RPC requests that depend on as-yet incomplete |
33 | cache entries, and replaying those requests when the cache entry | 31 | cache entries, and replaying those requests when the cache entry |
34 | is complete. | 32 | is complete. |
35 | - maintaining last-access times on cache entries | 33 | - clean out old entries as they expire. |
36 | - clean out old entries when the caches become full | ||
37 | |||
38 | The code for performing a cache lookup is also common, but in the form | ||
39 | of a template. i.e. a #define. | ||
40 | Each cache defines a lookup function by using the DefineCacheLookup | ||
41 | macro, or the simpler DefineSimpleCacheLookup macro | ||
42 | 34 | ||
43 | Creating a Cache | 35 | Creating a Cache |
44 | ---------------- | 36 | ---------------- |
45 | 37 | ||
46 | 1/ A cache needs a datum to cache. This is in the form of a | 38 | 1/ A cache needs a datum to store. This is in the form of a |
47 | structure definition that must contain a | 39 | structure definition that must contain a |
48 | struct cache_head | 40 | struct cache_head |
49 | as an element, usually the first. | 41 | as an element, usually the first. |
@@ -51,35 +43,69 @@ Creating a Cache | |||
51 | Each cache element is reference counted and contains | 43 | Each cache element is reference counted and contains |
52 | expiry and update times for use in cache management. | 44 | expiry and update times for use in cache management. |
53 | 2/ A cache needs a "cache_detail" structure that | 45 | 2/ A cache needs a "cache_detail" structure that |
54 | describes the cache. This stores the hash table, and some | 46 | describes the cache. This stores the hash table, some |
55 | parameters for cache management. | 47 | parameters for cache management, and some operations detailing how |
56 | 3/ A cache needs a lookup function. This is created using | 48 | to work with particular cache items. |
57 | the DefineCacheLookup macro. This lookup function is used both | 49 | The operations requires are: |
58 | to find entries and to update entries. The normal mode for | 50 | struct cache_head *alloc(void) |
59 | updating an entry is to replace the old entry with a new | 51 | This simply allocates appropriate memory and returns |
60 | entry. However it is possible to allow update-in-place | 52 | a pointer to the cache_detail embedded within the |
61 | for those caches where it makes sense (no atomicity issues | 53 | structure |
62 | or indirect reference counting issue) | 54 | void cache_put(struct kref *) |
63 | 4/ A cache needs to be registered using cache_register(). This | 55 | This is called when the last reference to an item is |
64 | includes in on a list of caches that will be regularly | 56 | is dropped. The pointer passed is to the 'ref' field |
65 | cleaned to discard old data. For this to work, some | 57 | in the cache_head. cache_put should release any |
66 | thread must periodically call cache_clean | 58 | references create by 'cache_init' and, if CACHE_VALID |
67 | 59 | is set, any references created by cache_update. | |
60 | It should then release the memory allocated by | ||
61 | 'alloc'. | ||
62 | int match(struct cache_head *orig, struct cache_head *new) | ||
63 | test if the keys in the two structures match. Return | ||
64 | 1 if they do, 0 if they don't. | ||
65 | void init(struct cache_head *orig, struct cache_head *new) | ||
66 | Set the 'key' fields in 'new' from 'orig'. This may | ||
67 | include taking references to shared objects. | ||
68 | void update(struct cache_head *orig, struct cache_head *new) | ||
69 | Set the 'content' fileds in 'new' from 'orig'. | ||
70 | int cache_show(struct seq_file *m, struct cache_detail *cd, | ||
71 | struct cache_head *h) | ||
72 | Optional. Used to provide a /proc file that lists the | ||
73 | contents of a cache. This should show one item, | ||
74 | usually on just one line. | ||
75 | int cache_request(struct cache_detail *cd, struct cache_head *h, | ||
76 | char **bpp, int *blen) | ||
77 | Format a request to be send to user-space for an item | ||
78 | to be instantiated. *bpp is a buffer of size *blen. | ||
79 | bpp should be moved forward over the encoded message, | ||
80 | and *blen should be reduced to show how much free | ||
81 | space remains. Return 0 on success or <0 if not | ||
82 | enough room or other problem. | ||
83 | int cache_parse(struct cache_detail *cd, char *buf, int len) | ||
84 | A message from user space has arrived to fill out a | ||
85 | cache entry. It is in 'buf' of length 'len'. | ||
86 | cache_parse should parse this, find the item in the | ||
87 | cache with sunrpc_cache_lookup, and update the item | ||
88 | with sunrpc_cache_update. | ||
89 | |||
90 | |||
91 | 3/ A cache needs to be registered using cache_register(). This | ||
92 | includes it on a list of caches that will be regularly | ||
93 | cleaned to discard old data. | ||
94 | |||
68 | Using a cache | 95 | Using a cache |
69 | ------------- | 96 | ------------- |
70 | 97 | ||
71 | To find a value in a cache, call the lookup function passing it a the | 98 | To find a value in a cache, call sunrpc_cache_lookup passing a pointer |
72 | datum which contains key, and possibly content, and a flag saying | 99 | to the cache_head in a sample item with the 'key' fields filled in. |
73 | whether to update the cache with new data from the datum. Depending | 100 | This will be passed to ->match to identify the target entry. If no |
74 | on how the cache lookup function was defined, it may take an extra | 101 | entry is found, a new entry will be create, added to the cache, and |
75 | argument to identify the particular cache in question. | 102 | marked as not containing valid data. |
76 | 103 | ||
77 | Except in cases of kmalloc failure, the lookup function | 104 | The item returned is typically passed to cache_check which will check |
78 | will return a new datum which will store the key and | 105 | if the data is valid, and may initiate an up-call to get fresh data. |
79 | may contain valid content, or may not. | 106 | cache_check will return -ENOENT in the entry is negative or if an up |
80 | This datum is typically passed to cache_check which determines the | 107 | call is needed but not possible, -EAGAIN if an upcall is pending, |
81 | validity of the datum and may later initiate an upcall to fill | 108 | or 0 if the data is valid; |
82 | in the data. | ||
83 | 109 | ||
84 | cache_check can be passed a "struct cache_req *". This structure is | 110 | cache_check can be passed a "struct cache_req *". This structure is |
85 | typically embedded in the actual request and can be used to create a | 111 | typically embedded in the actual request and can be used to create a |
@@ -90,6 +116,13 @@ item does become valid, the deferred copy of the request will be | |||
90 | revisited (->revisit). It is expected that this method will | 116 | revisited (->revisit). It is expected that this method will |
91 | reschedule the request for processing. | 117 | reschedule the request for processing. |
92 | 118 | ||
119 | The value returned by sunrpc_cache_lookup can also be passed to | ||
120 | sunrpc_cache_update to set the content for the item. A second item is | ||
121 | passed which should hold the content. If the item found by _lookup | ||
122 | has valid data, then it is discarded and a new item is created. This | ||
123 | saves any user of an item from worrying about content changing while | ||
124 | it is being inspected. If the item found by _lookup does not contain | ||
125 | valid data, then the content is copied across and CACHE_VALID is set. | ||
93 | 126 | ||
94 | Populating a cache | 127 | Populating a cache |
95 | ------------------ | 128 | ------------------ |
@@ -114,8 +147,8 @@ should be create or updated to have the given content, and the | |||
114 | expiry time should be set on that item. | 147 | expiry time should be set on that item. |
115 | 148 | ||
116 | Reading from a channel is a bit more interesting. When a cache | 149 | Reading from a channel is a bit more interesting. When a cache |
117 | lookup fail, or when it suceeds but finds an entry that may soon | 150 | lookup fails, or when it succeeds but finds an entry that may soon |
118 | expiry, a request is lodged for that cache item to be updated by | 151 | expire, a request is lodged for that cache item to be updated by |
119 | user-space. These requests appear in the channel file. | 152 | user-space. These requests appear in the channel file. |
120 | 153 | ||
121 | Successive reads will return successive requests. | 154 | Successive reads will return successive requests. |
@@ -130,7 +163,7 @@ Thus a user-space helper is likely to: | |||
130 | write a response | 163 | write a response |
131 | loop. | 164 | loop. |
132 | 165 | ||
133 | If it dies and needs to be restarted, any requests that have not be | 166 | If it dies and needs to be restarted, any requests that have not been |
134 | answered will still appear in the file and will be read by the new | 167 | answered will still appear in the file and will be read by the new |
135 | instance of the helper. | 168 | instance of the helper. |
136 | 169 | ||
@@ -142,10 +175,9 @@ Each cache should also define a "cache_request" method which | |||
142 | takes a cache item and encodes a request into the buffer | 175 | takes a cache item and encodes a request into the buffer |
143 | provided. | 176 | provided. |
144 | 177 | ||
145 | |||
146 | Note: If a cache has no active readers on the channel, and has had not | 178 | Note: If a cache has no active readers on the channel, and has had not |
147 | active readers for more than 60 seconds, further requests will not be | 179 | active readers for more than 60 seconds, further requests will not be |
148 | added to the channel but instead all looks that do not find a valid | 180 | added to the channel but instead all lookups that do not find a valid |
149 | entry will fail. This is partly for backward compatibility: The | 181 | entry will fail. This is partly for backward compatibility: The |
150 | previous nfs exports table was deemed to be authoritative and a | 182 | previous nfs exports table was deemed to be authoritative and a |
151 | failed lookup meant a definite 'no'. | 183 | failed lookup meant a definite 'no'. |
@@ -154,18 +186,17 @@ request/response format | |||
154 | ----------------------- | 186 | ----------------------- |
155 | 187 | ||
156 | While each cache is free to use it's own format for requests | 188 | While each cache is free to use it's own format for requests |
157 | and responses over channel, the following is recommended are | 189 | and responses over channel, the following is recommended as |
158 | appropriate and support routines are available to help: | 190 | appropriate and support routines are available to help: |
159 | Each request or response record should be printable ASCII | 191 | Each request or response record should be printable ASCII |
160 | with precisely one newline character which should be at the end. | 192 | with precisely one newline character which should be at the end. |
161 | Fields within the record should be separated by spaces, normally one. | 193 | Fields within the record should be separated by spaces, normally one. |
162 | If spaces, newlines, or nul characters are needed in a field they | 194 | If spaces, newlines, or nul characters are needed in a field they |
163 | much be quotes. two mechanisms are available: | 195 | much be quoted. two mechanisms are available: |
164 | 1/ If a field begins '\x' then it must contain an even number of | 196 | 1/ If a field begins '\x' then it must contain an even number of |
165 | hex digits, and pairs of these digits provide the bytes in the | 197 | hex digits, and pairs of these digits provide the bytes in the |
166 | field. | 198 | field. |
167 | 2/ otherwise a \ in the field must be followed by 3 octal digits | 199 | 2/ otherwise a \ in the field must be followed by 3 octal digits |
168 | which give the code for a byte. Other characters are treated | 200 | which give the code for a byte. Other characters are treated |
169 | as them selves. At the very least, space, newlines nul, and | 201 | as them selves. At the very least, space, newline, nul, and |
170 | '\' must be quoted in this way. | 202 | '\' must be quoted in this way. |
171 | |||
diff --git a/MAINTAINERS b/MAINTAINERS index f27846734b06..e5b051f0e27e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -2233,6 +2233,12 @@ M: p_gortmaker@yahoo.com | |||
2233 | L: linux-kernel@vger.kernel.org | 2233 | L: linux-kernel@vger.kernel.org |
2234 | S: Maintained | 2234 | S: Maintained |
2235 | 2235 | ||
2236 | REAL TIME CLOCK (RTC) SUBSYSTEM | ||
2237 | P: Alessandro Zummo | ||
2238 | M: a.zummo@towertech.it | ||
2239 | L: linux-kernel@vger.kernel.org | ||
2240 | S: Maintained | ||
2241 | |||
2236 | REISERFS FILE SYSTEM | 2242 | REISERFS FILE SYSTEM |
2237 | P: Hans Reiser | 2243 | P: Hans Reiser |
2238 | M: reiserfs-dev@namesys.com | 2244 | M: reiserfs-dev@namesys.com |
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index b4e5f8ff2b25..dd8769670596 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/root_dev.h> | 34 | #include <linux/root_dev.h> |
35 | #include <linux/initrd.h> | 35 | #include <linux/initrd.h> |
36 | #include <linux/eisa.h> | 36 | #include <linux/eisa.h> |
37 | #include <linux/pfn.h> | ||
37 | #ifdef CONFIG_MAGIC_SYSRQ | 38 | #ifdef CONFIG_MAGIC_SYSRQ |
38 | #include <linux/sysrq.h> | 39 | #include <linux/sysrq.h> |
39 | #include <linux/reboot.h> | 40 | #include <linux/reboot.h> |
@@ -42,7 +43,7 @@ | |||
42 | #include <asm/setup.h> | 43 | #include <asm/setup.h> |
43 | #include <asm/io.h> | 44 | #include <asm/io.h> |
44 | 45 | ||
45 | extern struct notifier_block *panic_notifier_list; | 46 | extern struct atomic_notifier_head panic_notifier_list; |
46 | static int alpha_panic_event(struct notifier_block *, unsigned long, void *); | 47 | static int alpha_panic_event(struct notifier_block *, unsigned long, void *); |
47 | static struct notifier_block alpha_panic_block = { | 48 | static struct notifier_block alpha_panic_block = { |
48 | alpha_panic_event, | 49 | alpha_panic_event, |
@@ -241,9 +242,6 @@ reserve_std_resources(void) | |||
241 | request_resource(io, standard_io_resources+i); | 242 | request_resource(io, standard_io_resources+i); |
242 | } | 243 | } |
243 | 244 | ||
244 | #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) | ||
245 | #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) | ||
246 | #define PFN_PHYS(x) ((x) << PAGE_SHIFT) | ||
247 | #define PFN_MAX PFN_DOWN(0x80000000) | 245 | #define PFN_MAX PFN_DOWN(0x80000000) |
248 | #define for_each_mem_cluster(memdesc, cluster, i) \ | 246 | #define for_each_mem_cluster(memdesc, cluster, i) \ |
249 | for ((cluster) = (memdesc)->cluster, (i) = 0; \ | 247 | for ((cluster) = (memdesc)->cluster, (i) = 0; \ |
@@ -472,11 +470,6 @@ page_is_ram(unsigned long pfn) | |||
472 | return 0; | 470 | return 0; |
473 | } | 471 | } |
474 | 472 | ||
475 | #undef PFN_UP | ||
476 | #undef PFN_DOWN | ||
477 | #undef PFN_PHYS | ||
478 | #undef PFN_MAX | ||
479 | |||
480 | void __init | 473 | void __init |
481 | setup_arch(char **cmdline_p) | 474 | setup_arch(char **cmdline_p) |
482 | { | 475 | { |
@@ -507,7 +500,8 @@ setup_arch(char **cmdline_p) | |||
507 | } | 500 | } |
508 | 501 | ||
509 | /* Register a call for panic conditions. */ | 502 | /* Register a call for panic conditions. */ |
510 | notifier_chain_register(&panic_notifier_list, &alpha_panic_block); | 503 | atomic_notifier_chain_register(&panic_notifier_list, |
504 | &alpha_panic_block); | ||
511 | 505 | ||
512 | #ifdef CONFIG_ALPHA_GENERIC | 506 | #ifdef CONFIG_ALPHA_GENERIC |
513 | /* Assume that we've booted from SRM if we haven't booted from MILO. | 507 | /* Assume that we've booted from SRM if we haven't booted from MILO. |
diff --git a/arch/alpha/mm/numa.c b/arch/alpha/mm/numa.c index 6d5251254f68..bf6b65c81bef 100644 --- a/arch/alpha/mm/numa.c +++ b/arch/alpha/mm/numa.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/bootmem.h> | 13 | #include <linux/bootmem.h> |
14 | #include <linux/swap.h> | 14 | #include <linux/swap.h> |
15 | #include <linux/initrd.h> | 15 | #include <linux/initrd.h> |
16 | #include <linux/pfn.h> | ||
16 | 17 | ||
17 | #include <asm/hwrpb.h> | 18 | #include <asm/hwrpb.h> |
18 | #include <asm/pgalloc.h> | 19 | #include <asm/pgalloc.h> |
@@ -27,9 +28,6 @@ bootmem_data_t node_bdata[MAX_NUMNODES]; | |||
27 | #define DBGDCONT(args...) | 28 | #define DBGDCONT(args...) |
28 | #endif | 29 | #endif |
29 | 30 | ||
30 | #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) | ||
31 | #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) | ||
32 | #define PFN_PHYS(x) ((x) << PAGE_SHIFT) | ||
33 | #define for_each_mem_cluster(memdesc, cluster, i) \ | 31 | #define for_each_mem_cluster(memdesc, cluster, i) \ |
34 | for ((cluster) = (memdesc)->cluster, (i) = 0; \ | 32 | for ((cluster) = (memdesc)->cluster, (i) = 0; \ |
35 | (i) < (memdesc)->numclusters; (i)++, (cluster)++) | 33 | (i) < (memdesc)->numclusters; (i)++, (cluster)++) |
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index bf2e72698d02..9731b3f826ab 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -8,6 +8,7 @@ mainmenu "Linux Kernel Configuration" | |||
8 | config ARM | 8 | config ARM |
9 | bool | 9 | bool |
10 | default y | 10 | default y |
11 | select RTC_LIB | ||
11 | help | 12 | help |
12 | The ARM series is a line of low-power-consumption RISC chip designs | 13 | The ARM series is a line of low-power-consumption RISC chip designs |
13 | licensed by ARM Ltd and targeted at embedded applications and | 14 | licensed by ARM Ltd and targeted at embedded applications and |
@@ -839,6 +840,8 @@ source "drivers/usb/Kconfig" | |||
839 | 840 | ||
840 | source "drivers/mmc/Kconfig" | 841 | source "drivers/mmc/Kconfig" |
841 | 842 | ||
843 | source "drivers/rtc/Kconfig" | ||
844 | |||
842 | endmenu | 845 | endmenu |
843 | 846 | ||
844 | source "fs/Kconfig" | 847 | source "fs/Kconfig" |
diff --git a/arch/arm/common/rtctime.c b/arch/arm/common/rtctime.c index e851d86c212c..35c9a64ac14c 100644 --- a/arch/arm/common/rtctime.c +++ b/arch/arm/common/rtctime.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/capability.h> | 20 | #include <linux/capability.h> |
21 | #include <linux/device.h> | 21 | #include <linux/device.h> |
22 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
23 | #include <linux/rtc.h> | ||
23 | 24 | ||
24 | #include <asm/rtc.h> | 25 | #include <asm/rtc.h> |
25 | #include <asm/semaphore.h> | 26 | #include <asm/semaphore.h> |
@@ -42,89 +43,6 @@ static struct rtc_ops *rtc_ops; | |||
42 | 43 | ||
43 | #define rtc_epoch 1900UL | 44 | #define rtc_epoch 1900UL |
44 | 45 | ||
45 | static const unsigned char days_in_month[] = { | ||
46 | 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 | ||
47 | }; | ||
48 | |||
49 | #define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) | ||
50 | #define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400)) | ||
51 | |||
52 | static int month_days(unsigned int month, unsigned int year) | ||
53 | { | ||
54 | return days_in_month[month] + (LEAP_YEAR(year) && month == 1); | ||
55 | } | ||
56 | |||
57 | /* | ||
58 | * Convert seconds since 01-01-1970 00:00:00 to Gregorian date. | ||
59 | */ | ||
60 | void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) | ||
61 | { | ||
62 | int days, month, year; | ||
63 | |||
64 | days = time / 86400; | ||
65 | time -= days * 86400; | ||
66 | |||
67 | tm->tm_wday = (days + 4) % 7; | ||
68 | |||
69 | year = 1970 + days / 365; | ||
70 | days -= (year - 1970) * 365 | ||
71 | + LEAPS_THRU_END_OF(year - 1) | ||
72 | - LEAPS_THRU_END_OF(1970 - 1); | ||
73 | if (days < 0) { | ||
74 | year -= 1; | ||
75 | days += 365 + LEAP_YEAR(year); | ||
76 | } | ||
77 | tm->tm_year = year - 1900; | ||
78 | tm->tm_yday = days + 1; | ||
79 | |||
80 | for (month = 0; month < 11; month++) { | ||
81 | int newdays; | ||
82 | |||
83 | newdays = days - month_days(month, year); | ||
84 | if (newdays < 0) | ||
85 | break; | ||
86 | days = newdays; | ||
87 | } | ||
88 | tm->tm_mon = month; | ||
89 | tm->tm_mday = days + 1; | ||
90 | |||
91 | tm->tm_hour = time / 3600; | ||
92 | time -= tm->tm_hour * 3600; | ||
93 | tm->tm_min = time / 60; | ||
94 | tm->tm_sec = time - tm->tm_min * 60; | ||
95 | } | ||
96 | EXPORT_SYMBOL(rtc_time_to_tm); | ||
97 | |||
98 | /* | ||
99 | * Does the rtc_time represent a valid date/time? | ||
100 | */ | ||
101 | int rtc_valid_tm(struct rtc_time *tm) | ||
102 | { | ||
103 | if (tm->tm_year < 70 || | ||
104 | tm->tm_mon >= 12 || | ||
105 | tm->tm_mday < 1 || | ||
106 | tm->tm_mday > month_days(tm->tm_mon, tm->tm_year + 1900) || | ||
107 | tm->tm_hour >= 24 || | ||
108 | tm->tm_min >= 60 || | ||
109 | tm->tm_sec >= 60) | ||
110 | return -EINVAL; | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | EXPORT_SYMBOL(rtc_valid_tm); | ||
115 | |||
116 | /* | ||
117 | * Convert Gregorian date to seconds since 01-01-1970 00:00:00. | ||
118 | */ | ||
119 | int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) | ||
120 | { | ||
121 | *time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, | ||
122 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | EXPORT_SYMBOL(rtc_tm_to_time); | ||
127 | |||
128 | /* | 46 | /* |
129 | * Calculate the next alarm time given the requested alarm time mask | 47 | * Calculate the next alarm time given the requested alarm time mask |
130 | * and the current time. | 48 | * and the current time. |
@@ -151,13 +69,13 @@ void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, struct rtc | |||
151 | } | 69 | } |
152 | } | 70 | } |
153 | 71 | ||
154 | static inline int rtc_read_time(struct rtc_ops *ops, struct rtc_time *tm) | 72 | static inline int rtc_arm_read_time(struct rtc_ops *ops, struct rtc_time *tm) |
155 | { | 73 | { |
156 | memset(tm, 0, sizeof(struct rtc_time)); | 74 | memset(tm, 0, sizeof(struct rtc_time)); |
157 | return ops->read_time(tm); | 75 | return ops->read_time(tm); |
158 | } | 76 | } |
159 | 77 | ||
160 | static inline int rtc_set_time(struct rtc_ops *ops, struct rtc_time *tm) | 78 | static inline int rtc_arm_set_time(struct rtc_ops *ops, struct rtc_time *tm) |
161 | { | 79 | { |
162 | int ret; | 80 | int ret; |
163 | 81 | ||
@@ -168,7 +86,7 @@ static inline int rtc_set_time(struct rtc_ops *ops, struct rtc_time *tm) | |||
168 | return ret; | 86 | return ret; |
169 | } | 87 | } |
170 | 88 | ||
171 | static inline int rtc_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) | 89 | static inline int rtc_arm_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) |
172 | { | 90 | { |
173 | int ret = -EINVAL; | 91 | int ret = -EINVAL; |
174 | if (ops->read_alarm) { | 92 | if (ops->read_alarm) { |
@@ -178,7 +96,7 @@ static inline int rtc_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) | |||
178 | return ret; | 96 | return ret; |
179 | } | 97 | } |
180 | 98 | ||
181 | static inline int rtc_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) | 99 | static inline int rtc_arm_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) |
182 | { | 100 | { |
183 | int ret = -EINVAL; | 101 | int ret = -EINVAL; |
184 | if (ops->set_alarm) | 102 | if (ops->set_alarm) |
@@ -266,7 +184,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
266 | 184 | ||
267 | switch (cmd) { | 185 | switch (cmd) { |
268 | case RTC_ALM_READ: | 186 | case RTC_ALM_READ: |
269 | ret = rtc_read_alarm(ops, &alrm); | 187 | ret = rtc_arm_read_alarm(ops, &alrm); |
270 | if (ret) | 188 | if (ret) |
271 | break; | 189 | break; |
272 | ret = copy_to_user(uarg, &alrm.time, sizeof(tm)); | 190 | ret = copy_to_user(uarg, &alrm.time, sizeof(tm)); |
@@ -288,11 +206,11 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
288 | alrm.time.tm_wday = -1; | 206 | alrm.time.tm_wday = -1; |
289 | alrm.time.tm_yday = -1; | 207 | alrm.time.tm_yday = -1; |
290 | alrm.time.tm_isdst = -1; | 208 | alrm.time.tm_isdst = -1; |
291 | ret = rtc_set_alarm(ops, &alrm); | 209 | ret = rtc_arm_set_alarm(ops, &alrm); |
292 | break; | 210 | break; |
293 | 211 | ||
294 | case RTC_RD_TIME: | 212 | case RTC_RD_TIME: |
295 | ret = rtc_read_time(ops, &tm); | 213 | ret = rtc_arm_read_time(ops, &tm); |
296 | if (ret) | 214 | if (ret) |
297 | break; | 215 | break; |
298 | ret = copy_to_user(uarg, &tm, sizeof(tm)); | 216 | ret = copy_to_user(uarg, &tm, sizeof(tm)); |
@@ -310,7 +228,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
310 | ret = -EFAULT; | 228 | ret = -EFAULT; |
311 | break; | 229 | break; |
312 | } | 230 | } |
313 | ret = rtc_set_time(ops, &tm); | 231 | ret = rtc_arm_set_time(ops, &tm); |
314 | break; | 232 | break; |
315 | 233 | ||
316 | case RTC_EPOCH_SET: | 234 | case RTC_EPOCH_SET: |
@@ -341,11 +259,11 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
341 | ret = -EFAULT; | 259 | ret = -EFAULT; |
342 | break; | 260 | break; |
343 | } | 261 | } |
344 | ret = rtc_set_alarm(ops, &alrm); | 262 | ret = rtc_arm_set_alarm(ops, &alrm); |
345 | break; | 263 | break; |
346 | 264 | ||
347 | case RTC_WKALM_RD: | 265 | case RTC_WKALM_RD: |
348 | ret = rtc_read_alarm(ops, &alrm); | 266 | ret = rtc_arm_read_alarm(ops, &alrm); |
349 | if (ret) | 267 | if (ret) |
350 | break; | 268 | break; |
351 | ret = copy_to_user(uarg, &alrm, sizeof(alrm)); | 269 | ret = copy_to_user(uarg, &alrm, sizeof(alrm)); |
@@ -435,7 +353,7 @@ static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eo | |||
435 | struct rtc_time tm; | 353 | struct rtc_time tm; |
436 | char *p = page; | 354 | char *p = page; |
437 | 355 | ||
438 | if (rtc_read_time(ops, &tm) == 0) { | 356 | if (rtc_arm_read_time(ops, &tm) == 0) { |
439 | p += sprintf(p, | 357 | p += sprintf(p, |
440 | "rtc_time\t: %02d:%02d:%02d\n" | 358 | "rtc_time\t: %02d:%02d:%02d\n" |
441 | "rtc_date\t: %04d-%02d-%02d\n" | 359 | "rtc_date\t: %04d-%02d-%02d\n" |
@@ -445,7 +363,7 @@ static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eo | |||
445 | rtc_epoch); | 363 | rtc_epoch); |
446 | } | 364 | } |
447 | 365 | ||
448 | if (rtc_read_alarm(ops, &alrm) == 0) { | 366 | if (rtc_arm_read_alarm(ops, &alrm) == 0) { |
449 | p += sprintf(p, "alrm_time\t: "); | 367 | p += sprintf(p, "alrm_time\t: "); |
450 | if ((unsigned int)alrm.time.tm_hour <= 24) | 368 | if ((unsigned int)alrm.time.tm_hour <= 24) |
451 | p += sprintf(p, "%02d:", alrm.time.tm_hour); | 369 | p += sprintf(p, "%02d:", alrm.time.tm_hour); |
diff --git a/arch/arm/mach-integrator/time.c b/arch/arm/mach-integrator/time.c index 3c22c16b38bf..bc07f52a6fd7 100644 --- a/arch/arm/mach-integrator/time.c +++ b/arch/arm/mach-integrator/time.c | |||
@@ -40,13 +40,13 @@ static int integrator_set_rtc(void) | |||
40 | return 1; | 40 | return 1; |
41 | } | 41 | } |
42 | 42 | ||
43 | static int rtc_read_alarm(struct rtc_wkalrm *alrm) | 43 | static int integrator_rtc_read_alarm(struct rtc_wkalrm *alrm) |
44 | { | 44 | { |
45 | rtc_time_to_tm(readl(rtc_base + RTC_MR), &alrm->time); | 45 | rtc_time_to_tm(readl(rtc_base + RTC_MR), &alrm->time); |
46 | return 0; | 46 | return 0; |
47 | } | 47 | } |
48 | 48 | ||
49 | static inline int rtc_set_alarm(struct rtc_wkalrm *alrm) | 49 | static inline int integrator_rtc_set_alarm(struct rtc_wkalrm *alrm) |
50 | { | 50 | { |
51 | unsigned long time; | 51 | unsigned long time; |
52 | int ret; | 52 | int ret; |
@@ -62,7 +62,7 @@ static inline int rtc_set_alarm(struct rtc_wkalrm *alrm) | |||
62 | return ret; | 62 | return ret; |
63 | } | 63 | } |
64 | 64 | ||
65 | static int rtc_read_time(struct rtc_time *tm) | 65 | static int integrator_rtc_read_time(struct rtc_time *tm) |
66 | { | 66 | { |
67 | rtc_time_to_tm(readl(rtc_base + RTC_DR), tm); | 67 | rtc_time_to_tm(readl(rtc_base + RTC_DR), tm); |
68 | return 0; | 68 | return 0; |
@@ -76,7 +76,7 @@ static int rtc_read_time(struct rtc_time *tm) | |||
76 | * edge of the 1Hz clock, we must write the time one second | 76 | * edge of the 1Hz clock, we must write the time one second |
77 | * in advance. | 77 | * in advance. |
78 | */ | 78 | */ |
79 | static inline int rtc_set_time(struct rtc_time *tm) | 79 | static inline int integrator_rtc_set_time(struct rtc_time *tm) |
80 | { | 80 | { |
81 | unsigned long time; | 81 | unsigned long time; |
82 | int ret; | 82 | int ret; |
@@ -90,10 +90,10 @@ static inline int rtc_set_time(struct rtc_time *tm) | |||
90 | 90 | ||
91 | static struct rtc_ops rtc_ops = { | 91 | static struct rtc_ops rtc_ops = { |
92 | .owner = THIS_MODULE, | 92 | .owner = THIS_MODULE, |
93 | .read_time = rtc_read_time, | 93 | .read_time = integrator_rtc_read_time, |
94 | .set_time = rtc_set_time, | 94 | .set_time = integrator_rtc_set_time, |
95 | .read_alarm = rtc_read_alarm, | 95 | .read_alarm = integrator_rtc_read_alarm, |
96 | .set_alarm = rtc_set_alarm, | 96 | .set_alarm = integrator_rtc_set_alarm, |
97 | }; | 97 | }; |
98 | 98 | ||
99 | static irqreturn_t arm_rtc_interrupt(int irq, void *dev_id, | 99 | static irqreturn_t arm_rtc_interrupt(int irq, void *dev_id, |
diff --git a/arch/arm/mach-omap1/board-netstar.c b/arch/arm/mach-omap1/board-netstar.c index 60d5f8a3339c..7520e602d7a2 100644 --- a/arch/arm/mach-omap1/board-netstar.c +++ b/arch/arm/mach-omap1/board-netstar.c | |||
@@ -141,7 +141,7 @@ static int __init netstar_late_init(void) | |||
141 | /* TODO: Setup front panel switch here */ | 141 | /* TODO: Setup front panel switch here */ |
142 | 142 | ||
143 | /* Setup panic notifier */ | 143 | /* Setup panic notifier */ |
144 | notifier_chain_register(&panic_notifier_list, &panic_block); | 144 | atomic_notifier_chain_register(&panic_notifier_list, &panic_block); |
145 | 145 | ||
146 | return 0; | 146 | return 0; |
147 | } | 147 | } |
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c index bfd5fdd1a875..52e4a9d69642 100644 --- a/arch/arm/mach-omap1/board-voiceblue.c +++ b/arch/arm/mach-omap1/board-voiceblue.c | |||
@@ -235,7 +235,7 @@ static struct notifier_block panic_block = { | |||
235 | static int __init voiceblue_setup(void) | 235 | static int __init voiceblue_setup(void) |
236 | { | 236 | { |
237 | /* Setup panic notifier */ | 237 | /* Setup panic notifier */ |
238 | notifier_chain_register(&panic_notifier_list, &panic_block); | 238 | atomic_notifier_chain_register(&panic_notifier_list, &panic_block); |
239 | 239 | ||
240 | return 0; | 240 | return 0; |
241 | } | 241 | } |
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 9b48a90aefce..5efa84749f37 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c | |||
@@ -319,6 +319,11 @@ void __init pxa_set_ficp_info(struct pxaficp_platform_data *info) | |||
319 | pxaficp_device.dev.platform_data = info; | 319 | pxaficp_device.dev.platform_data = info; |
320 | } | 320 | } |
321 | 321 | ||
322 | static struct platform_device pxartc_device = { | ||
323 | .name = "sa1100-rtc", | ||
324 | .id = -1, | ||
325 | }; | ||
326 | |||
322 | static struct platform_device *devices[] __initdata = { | 327 | static struct platform_device *devices[] __initdata = { |
323 | &pxamci_device, | 328 | &pxamci_device, |
324 | &udc_device, | 329 | &udc_device, |
@@ -329,6 +334,7 @@ static struct platform_device *devices[] __initdata = { | |||
329 | &pxaficp_device, | 334 | &pxaficp_device, |
330 | &i2c_device, | 335 | &i2c_device, |
331 | &i2s_device, | 336 | &i2s_device, |
337 | &pxartc_device, | ||
332 | }; | 338 | }; |
333 | 339 | ||
334 | static int __init pxa_init(void) | 340 | static int __init pxa_init(void) |
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 2abdc419e984..9ea71551fc04 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c | |||
@@ -324,6 +324,11 @@ void sa11x0_set_irda_data(struct irda_platform_data *irda) | |||
324 | sa11x0ir_device.dev.platform_data = irda; | 324 | sa11x0ir_device.dev.platform_data = irda; |
325 | } | 325 | } |
326 | 326 | ||
327 | static struct platform_device sa11x0rtc_device = { | ||
328 | .name = "sa1100-rtc", | ||
329 | .id = -1, | ||
330 | }; | ||
331 | |||
327 | static struct platform_device *sa11x0_devices[] __initdata = { | 332 | static struct platform_device *sa11x0_devices[] __initdata = { |
328 | &sa11x0udc_device, | 333 | &sa11x0udc_device, |
329 | &sa11x0uart1_device, | 334 | &sa11x0uart1_device, |
@@ -333,6 +338,7 @@ static struct platform_device *sa11x0_devices[] __initdata = { | |||
333 | &sa11x0pcmcia_device, | 338 | &sa11x0pcmcia_device, |
334 | &sa11x0fb_device, | 339 | &sa11x0fb_device, |
335 | &sa11x0mtd_device, | 340 | &sa11x0mtd_device, |
341 | &sa11x0rtc_device, | ||
336 | }; | 342 | }; |
337 | 343 | ||
338 | static int __init sa1100_init(void) | 344 | static int __init sa1100_init(void) |
diff --git a/arch/arm26/mm/init.c b/arch/arm26/mm/init.c index e3ecaa453747..7da8a5205678 100644 --- a/arch/arm26/mm/init.c +++ b/arch/arm26/mm/init.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/initrd.h> | 23 | #include <linux/initrd.h> |
24 | #include <linux/bootmem.h> | 24 | #include <linux/bootmem.h> |
25 | #include <linux/blkdev.h> | 25 | #include <linux/blkdev.h> |
26 | #include <linux/pfn.h> | ||
26 | 27 | ||
27 | #include <asm/segment.h> | 28 | #include <asm/segment.h> |
28 | #include <asm/mach-types.h> | 29 | #include <asm/mach-types.h> |
@@ -101,12 +102,6 @@ struct node_info { | |||
101 | int bootmap_pages; | 102 | int bootmap_pages; |
102 | }; | 103 | }; |
103 | 104 | ||
104 | #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) | ||
105 | #define PFN_UP(x) (PAGE_ALIGN(x) >> PAGE_SHIFT) | ||
106 | #define PFN_SIZE(x) ((x) >> PAGE_SHIFT) | ||
107 | #define PFN_RANGE(s,e) PFN_SIZE(PAGE_ALIGN((unsigned long)(e)) - \ | ||
108 | (((unsigned long)(s)) & PAGE_MASK)) | ||
109 | |||
110 | /* | 105 | /* |
111 | * FIXME: We really want to avoid allocating the bootmap bitmap | 106 | * FIXME: We really want to avoid allocating the bootmap bitmap |
112 | * over the top of the initrd. Hopefully, this is located towards | 107 | * over the top of the initrd. Hopefully, this is located towards |
diff --git a/arch/cris/kernel/setup.c b/arch/cris/kernel/setup.c index 1ba57efff60d..619a6eefd893 100644 --- a/arch/cris/kernel/setup.c +++ b/arch/cris/kernel/setup.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/seq_file.h> | 18 | #include <linux/seq_file.h> |
19 | #include <linux/tty.h> | 19 | #include <linux/tty.h> |
20 | #include <linux/utsname.h> | 20 | #include <linux/utsname.h> |
21 | #include <linux/pfn.h> | ||
21 | 22 | ||
22 | #include <asm/setup.h> | 23 | #include <asm/setup.h> |
23 | 24 | ||
@@ -88,10 +89,6 @@ setup_arch(char **cmdline_p) | |||
88 | init_mm.end_data = (unsigned long) &_edata; | 89 | init_mm.end_data = (unsigned long) &_edata; |
89 | init_mm.brk = (unsigned long) &_end; | 90 | init_mm.brk = (unsigned long) &_end; |
90 | 91 | ||
91 | #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) | ||
92 | #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) | ||
93 | #define PFN_PHYS(x) ((x) << PAGE_SHIFT) | ||
94 | |||
95 | /* min_low_pfn points to the start of DRAM, start_pfn points | 92 | /* min_low_pfn points to the start of DRAM, start_pfn points |
96 | * to the first DRAM pages after the kernel, and max_low_pfn | 93 | * to the first DRAM pages after the kernel, and max_low_pfn |
97 | * to the end of DRAM. | 94 | * to the end of DRAM. |
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index f7db71d0b913..f17bd1d2707e 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig | |||
@@ -231,6 +231,15 @@ config SCHED_SMT | |||
231 | cost of slightly increased overhead in some places. If unsure say | 231 | cost of slightly increased overhead in some places. If unsure say |
232 | N here. | 232 | N here. |
233 | 233 | ||
234 | config SCHED_MC | ||
235 | bool "Multi-core scheduler support" | ||
236 | depends on SMP | ||
237 | default y | ||
238 | help | ||
239 | Multi-core scheduler support improves the CPU scheduler's decision | ||
240 | making when dealing with multi-core CPU chips at a cost of slightly | ||
241 | increased overhead in some places. If unsure say N here. | ||
242 | |||
234 | source "kernel/Kconfig.preempt" | 243 | source "kernel/Kconfig.preempt" |
235 | 244 | ||
236 | config X86_UP_APIC | 245 | config X86_UP_APIC |
diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S index 2ac40c8244c4..0000a2674537 100644 --- a/arch/i386/boot/video.S +++ b/arch/i386/boot/video.S | |||
@@ -1924,6 +1924,7 @@ skip10: movb %ah, %al | |||
1924 | ret | 1924 | ret |
1925 | 1925 | ||
1926 | store_edid: | 1926 | store_edid: |
1927 | #ifdef CONFIG_FB_FIRMWARE_EDID | ||
1927 | pushw %es # just save all registers | 1928 | pushw %es # just save all registers |
1928 | pushw %ax | 1929 | pushw %ax |
1929 | pushw %bx | 1930 | pushw %bx |
@@ -1954,6 +1955,7 @@ store_edid: | |||
1954 | popw %bx | 1955 | popw %bx |
1955 | popw %ax | 1956 | popw %ax |
1956 | popw %es | 1957 | popw %es |
1958 | #endif | ||
1957 | ret | 1959 | ret |
1958 | 1960 | ||
1959 | # VIDEO_SELECT-only variables | 1961 | # VIDEO_SELECT-only variables |
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index 7e3d6b6a4e96..a06a49075f10 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c | |||
@@ -266,7 +266,7 @@ static void __init early_cpu_detect(void) | |||
266 | void __cpuinit generic_identify(struct cpuinfo_x86 * c) | 266 | void __cpuinit generic_identify(struct cpuinfo_x86 * c) |
267 | { | 267 | { |
268 | u32 tfms, xlvl; | 268 | u32 tfms, xlvl; |
269 | int junk; | 269 | int ebx; |
270 | 270 | ||
271 | if (have_cpuid_p()) { | 271 | if (have_cpuid_p()) { |
272 | /* Get vendor name */ | 272 | /* Get vendor name */ |
@@ -282,7 +282,7 @@ void __cpuinit generic_identify(struct cpuinfo_x86 * c) | |||
282 | /* Intel-defined flags: level 0x00000001 */ | 282 | /* Intel-defined flags: level 0x00000001 */ |
283 | if ( c->cpuid_level >= 0x00000001 ) { | 283 | if ( c->cpuid_level >= 0x00000001 ) { |
284 | u32 capability, excap; | 284 | u32 capability, excap; |
285 | cpuid(0x00000001, &tfms, &junk, &excap, &capability); | 285 | cpuid(0x00000001, &tfms, &ebx, &excap, &capability); |
286 | c->x86_capability[0] = capability; | 286 | c->x86_capability[0] = capability; |
287 | c->x86_capability[4] = excap; | 287 | c->x86_capability[4] = excap; |
288 | c->x86 = (tfms >> 8) & 15; | 288 | c->x86 = (tfms >> 8) & 15; |
@@ -292,6 +292,11 @@ void __cpuinit generic_identify(struct cpuinfo_x86 * c) | |||
292 | if (c->x86 >= 0x6) | 292 | if (c->x86 >= 0x6) |
293 | c->x86_model += ((tfms >> 16) & 0xF) << 4; | 293 | c->x86_model += ((tfms >> 16) & 0xF) << 4; |
294 | c->x86_mask = tfms & 15; | 294 | c->x86_mask = tfms & 15; |
295 | #ifdef CONFIG_SMP | ||
296 | c->apicid = phys_pkg_id((ebx >> 24) & 0xFF, 0); | ||
297 | #else | ||
298 | c->apicid = (ebx >> 24) & 0xFF; | ||
299 | #endif | ||
295 | } else { | 300 | } else { |
296 | /* Have CPUID level 0 only - unheard of */ | 301 | /* Have CPUID level 0 only - unheard of */ |
297 | c->x86 = 4; | 302 | c->x86 = 4; |
@@ -474,7 +479,6 @@ void __cpuinit detect_ht(struct cpuinfo_x86 *c) | |||
474 | 479 | ||
475 | cpuid(1, &eax, &ebx, &ecx, &edx); | 480 | cpuid(1, &eax, &ebx, &ecx, &edx); |
476 | 481 | ||
477 | c->apicid = phys_pkg_id((ebx >> 24) & 0xFF, 0); | ||
478 | 482 | ||
479 | if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY)) | 483 | if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY)) |
480 | return; | 484 | return; |
diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c index ce61921369e5..9df87b03612c 100644 --- a/arch/i386/kernel/cpu/intel_cacheinfo.c +++ b/arch/i386/kernel/cpu/intel_cacheinfo.c | |||
@@ -173,6 +173,10 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c) | |||
173 | unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */ | 173 | unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */ |
174 | unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */ | 174 | unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */ |
175 | unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */ | 175 | unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */ |
176 | unsigned int l2_id = 0, l3_id = 0, num_threads_sharing, index_msb; | ||
177 | #ifdef CONFIG_SMP | ||
178 | unsigned int cpu = (c == &boot_cpu_data) ? 0 : (c - cpu_data); | ||
179 | #endif | ||
176 | 180 | ||
177 | if (c->cpuid_level > 3) { | 181 | if (c->cpuid_level > 3) { |
178 | static int is_initialized; | 182 | static int is_initialized; |
@@ -205,9 +209,15 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c) | |||
205 | break; | 209 | break; |
206 | case 2: | 210 | case 2: |
207 | new_l2 = this_leaf.size/1024; | 211 | new_l2 = this_leaf.size/1024; |
212 | num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing; | ||
213 | index_msb = get_count_order(num_threads_sharing); | ||
214 | l2_id = c->apicid >> index_msb; | ||
208 | break; | 215 | break; |
209 | case 3: | 216 | case 3: |
210 | new_l3 = this_leaf.size/1024; | 217 | new_l3 = this_leaf.size/1024; |
218 | num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing; | ||
219 | index_msb = get_count_order(num_threads_sharing); | ||
220 | l3_id = c->apicid >> index_msb; | ||
211 | break; | 221 | break; |
212 | default: | 222 | default: |
213 | break; | 223 | break; |
@@ -215,11 +225,19 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c) | |||
215 | } | 225 | } |
216 | } | 226 | } |
217 | } | 227 | } |
218 | if (c->cpuid_level > 1) { | 228 | /* |
229 | * Don't use cpuid2 if cpuid4 is supported. For P4, we use cpuid2 for | ||
230 | * trace cache | ||
231 | */ | ||
232 | if ((num_cache_leaves == 0 || c->x86 == 15) && c->cpuid_level > 1) { | ||
219 | /* supports eax=2 call */ | 233 | /* supports eax=2 call */ |
220 | int i, j, n; | 234 | int i, j, n; |
221 | int regs[4]; | 235 | int regs[4]; |
222 | unsigned char *dp = (unsigned char *)regs; | 236 | unsigned char *dp = (unsigned char *)regs; |
237 | int only_trace = 0; | ||
238 | |||
239 | if (num_cache_leaves != 0 && c->x86 == 15) | ||
240 | only_trace = 1; | ||
223 | 241 | ||
224 | /* Number of times to iterate */ | 242 | /* Number of times to iterate */ |
225 | n = cpuid_eax(2) & 0xFF; | 243 | n = cpuid_eax(2) & 0xFF; |
@@ -241,6 +259,8 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c) | |||
241 | while (cache_table[k].descriptor != 0) | 259 | while (cache_table[k].descriptor != 0) |
242 | { | 260 | { |
243 | if (cache_table[k].descriptor == des) { | 261 | if (cache_table[k].descriptor == des) { |
262 | if (only_trace && cache_table[k].cache_type != LVL_TRACE) | ||
263 | break; | ||
244 | switch (cache_table[k].cache_type) { | 264 | switch (cache_table[k].cache_type) { |
245 | case LVL_1_INST: | 265 | case LVL_1_INST: |
246 | l1i += cache_table[k].size; | 266 | l1i += cache_table[k].size; |
@@ -266,34 +286,45 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c) | |||
266 | } | 286 | } |
267 | } | 287 | } |
268 | } | 288 | } |
289 | } | ||
269 | 290 | ||
270 | if (new_l1d) | 291 | if (new_l1d) |
271 | l1d = new_l1d; | 292 | l1d = new_l1d; |
272 | 293 | ||
273 | if (new_l1i) | 294 | if (new_l1i) |
274 | l1i = new_l1i; | 295 | l1i = new_l1i; |
275 | 296 | ||
276 | if (new_l2) | 297 | if (new_l2) { |
277 | l2 = new_l2; | 298 | l2 = new_l2; |
299 | #ifdef CONFIG_SMP | ||
300 | cpu_llc_id[cpu] = l2_id; | ||
301 | #endif | ||
302 | } | ||
278 | 303 | ||
279 | if (new_l3) | 304 | if (new_l3) { |
280 | l3 = new_l3; | 305 | l3 = new_l3; |
306 | #ifdef CONFIG_SMP | ||
307 | cpu_llc_id[cpu] = l3_id; | ||
308 | #endif | ||
309 | } | ||
281 | 310 | ||
282 | if ( trace ) | 311 | if (trace) |
283 | printk (KERN_INFO "CPU: Trace cache: %dK uops", trace); | 312 | printk (KERN_INFO "CPU: Trace cache: %dK uops", trace); |
284 | else if ( l1i ) | 313 | else if ( l1i ) |
285 | printk (KERN_INFO "CPU: L1 I cache: %dK", l1i); | 314 | printk (KERN_INFO "CPU: L1 I cache: %dK", l1i); |
286 | if ( l1d ) | ||
287 | printk(", L1 D cache: %dK\n", l1d); | ||
288 | else | ||
289 | printk("\n"); | ||
290 | if ( l2 ) | ||
291 | printk(KERN_INFO "CPU: L2 cache: %dK\n", l2); | ||
292 | if ( l3 ) | ||
293 | printk(KERN_INFO "CPU: L3 cache: %dK\n", l3); | ||
294 | 315 | ||
295 | c->x86_cache_size = l3 ? l3 : (l2 ? l2 : (l1i+l1d)); | 316 | if (l1d) |
296 | } | 317 | printk(", L1 D cache: %dK\n", l1d); |
318 | else | ||
319 | printk("\n"); | ||
320 | |||
321 | if (l2) | ||
322 | printk(KERN_INFO "CPU: L2 cache: %dK\n", l2); | ||
323 | |||
324 | if (l3) | ||
325 | printk(KERN_INFO "CPU: L3 cache: %dK\n", l3); | ||
326 | |||
327 | c->x86_cache_size = l3 ? l3 : (l2 ? l2 : (l1i+l1d)); | ||
297 | 328 | ||
298 | return l2; | 329 | return l2; |
299 | } | 330 | } |
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 6917daa159ab..8c08660b4e5d 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/kexec.h> | 46 | #include <linux/kexec.h> |
47 | #include <linux/crash_dump.h> | 47 | #include <linux/crash_dump.h> |
48 | #include <linux/dmi.h> | 48 | #include <linux/dmi.h> |
49 | #include <linux/pfn.h> | ||
49 | 50 | ||
50 | #include <video/edid.h> | 51 | #include <video/edid.h> |
51 | 52 | ||
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 82371d83bfa9..a6969903f2d6 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c | |||
@@ -72,6 +72,9 @@ int phys_proc_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID}; | |||
72 | /* Core ID of each logical CPU */ | 72 | /* Core ID of each logical CPU */ |
73 | int cpu_core_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID}; | 73 | int cpu_core_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID}; |
74 | 74 | ||
75 | /* Last level cache ID of each logical CPU */ | ||
76 | int cpu_llc_id[NR_CPUS] __cpuinitdata = {[0 ... NR_CPUS-1] = BAD_APICID}; | ||
77 | |||
75 | /* representing HT siblings of each logical CPU */ | 78 | /* representing HT siblings of each logical CPU */ |
76 | cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly; | 79 | cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly; |
77 | EXPORT_SYMBOL(cpu_sibling_map); | 80 | EXPORT_SYMBOL(cpu_sibling_map); |
@@ -440,6 +443,18 @@ static void __devinit smp_callin(void) | |||
440 | 443 | ||
441 | static int cpucount; | 444 | static int cpucount; |
442 | 445 | ||
446 | /* maps the cpu to the sched domain representing multi-core */ | ||
447 | cpumask_t cpu_coregroup_map(int cpu) | ||
448 | { | ||
449 | struct cpuinfo_x86 *c = cpu_data + cpu; | ||
450 | /* | ||
451 | * For perf, we return last level cache shared map. | ||
452 | * TBD: when power saving sched policy is added, we will return | ||
453 | * cpu_core_map when power saving policy is enabled | ||
454 | */ | ||
455 | return c->llc_shared_map; | ||
456 | } | ||
457 | |||
443 | /* representing cpus for which sibling maps can be computed */ | 458 | /* representing cpus for which sibling maps can be computed */ |
444 | static cpumask_t cpu_sibling_setup_map; | 459 | static cpumask_t cpu_sibling_setup_map; |
445 | 460 | ||
@@ -459,12 +474,16 @@ set_cpu_sibling_map(int cpu) | |||
459 | cpu_set(cpu, cpu_sibling_map[i]); | 474 | cpu_set(cpu, cpu_sibling_map[i]); |
460 | cpu_set(i, cpu_core_map[cpu]); | 475 | cpu_set(i, cpu_core_map[cpu]); |
461 | cpu_set(cpu, cpu_core_map[i]); | 476 | cpu_set(cpu, cpu_core_map[i]); |
477 | cpu_set(i, c[cpu].llc_shared_map); | ||
478 | cpu_set(cpu, c[i].llc_shared_map); | ||
462 | } | 479 | } |
463 | } | 480 | } |
464 | } else { | 481 | } else { |
465 | cpu_set(cpu, cpu_sibling_map[cpu]); | 482 | cpu_set(cpu, cpu_sibling_map[cpu]); |
466 | } | 483 | } |
467 | 484 | ||
485 | cpu_set(cpu, c[cpu].llc_shared_map); | ||
486 | |||
468 | if (current_cpu_data.x86_max_cores == 1) { | 487 | if (current_cpu_data.x86_max_cores == 1) { |
469 | cpu_core_map[cpu] = cpu_sibling_map[cpu]; | 488 | cpu_core_map[cpu] = cpu_sibling_map[cpu]; |
470 | c[cpu].booted_cores = 1; | 489 | c[cpu].booted_cores = 1; |
@@ -472,6 +491,11 @@ set_cpu_sibling_map(int cpu) | |||
472 | } | 491 | } |
473 | 492 | ||
474 | for_each_cpu_mask(i, cpu_sibling_setup_map) { | 493 | for_each_cpu_mask(i, cpu_sibling_setup_map) { |
494 | if (cpu_llc_id[cpu] != BAD_APICID && | ||
495 | cpu_llc_id[cpu] == cpu_llc_id[i]) { | ||
496 | cpu_set(i, c[cpu].llc_shared_map); | ||
497 | cpu_set(cpu, c[i].llc_shared_map); | ||
498 | } | ||
475 | if (phys_proc_id[cpu] == phys_proc_id[i]) { | 499 | if (phys_proc_id[cpu] == phys_proc_id[i]) { |
476 | cpu_set(i, cpu_core_map[cpu]); | 500 | cpu_set(i, cpu_core_map[cpu]); |
477 | cpu_set(cpu, cpu_core_map[i]); | 501 | cpu_set(cpu, cpu_core_map[i]); |
diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S index ac687d00a1ce..326595f3fa4d 100644 --- a/arch/i386/kernel/syscall_table.S +++ b/arch/i386/kernel/syscall_table.S | |||
@@ -310,3 +310,5 @@ ENTRY(sys_call_table) | |||
310 | .long sys_pselect6 | 310 | .long sys_pselect6 |
311 | .long sys_ppoll | 311 | .long sys_ppoll |
312 | .long sys_unshare /* 310 */ | 312 | .long sys_unshare /* 310 */ |
313 | .long sys_set_robust_list | ||
314 | .long sys_get_robust_list | ||
diff --git a/arch/i386/kernel/timers/timer_pm.c b/arch/i386/kernel/timers/timer_pm.c index 264edaaac315..144e94a04933 100644 --- a/arch/i386/kernel/timers/timer_pm.c +++ b/arch/i386/kernel/timers/timer_pm.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/device.h> | 16 | #include <linux/device.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/pci.h> | ||
18 | #include <asm/types.h> | 19 | #include <asm/types.h> |
19 | #include <asm/timer.h> | 20 | #include <asm/timer.h> |
20 | #include <asm/smp.h> | 21 | #include <asm/smp.h> |
@@ -45,24 +46,31 @@ static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED; | |||
45 | 46 | ||
46 | #define ACPI_PM_MASK 0xFFFFFF /* limit it to 24 bits */ | 47 | #define ACPI_PM_MASK 0xFFFFFF /* limit it to 24 bits */ |
47 | 48 | ||
49 | static int pmtmr_need_workaround __read_mostly = 1; | ||
50 | |||
48 | /*helper function to safely read acpi pm timesource*/ | 51 | /*helper function to safely read acpi pm timesource*/ |
49 | static inline u32 read_pmtmr(void) | 52 | static inline u32 read_pmtmr(void) |
50 | { | 53 | { |
51 | u32 v1=0,v2=0,v3=0; | 54 | if (pmtmr_need_workaround) { |
52 | /* It has been reported that because of various broken | 55 | u32 v1, v2, v3; |
53 | * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM time | 56 | |
54 | * source is not latched, so you must read it multiple | 57 | /* It has been reported that because of various broken |
55 | * times to insure a safe value is read. | 58 | * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM time |
56 | */ | 59 | * source is not latched, so you must read it multiple |
57 | do { | 60 | * times to insure a safe value is read. |
58 | v1 = inl(pmtmr_ioport); | 61 | */ |
59 | v2 = inl(pmtmr_ioport); | 62 | do { |
60 | v3 = inl(pmtmr_ioport); | 63 | v1 = inl(pmtmr_ioport); |
61 | } while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) | 64 | v2 = inl(pmtmr_ioport); |
62 | || (v3 > v1 && v3 < v2)); | 65 | v3 = inl(pmtmr_ioport); |
63 | 66 | } while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) | |
64 | /* mask the output to 24 bits */ | 67 | || (v3 > v1 && v3 < v2)); |
65 | return v2 & ACPI_PM_MASK; | 68 | |
69 | /* mask the output to 24 bits */ | ||
70 | return v2 & ACPI_PM_MASK; | ||
71 | } | ||
72 | |||
73 | return inl(pmtmr_ioport) & ACPI_PM_MASK; | ||
66 | } | 74 | } |
67 | 75 | ||
68 | 76 | ||
@@ -263,6 +271,72 @@ struct init_timer_opts __initdata timer_pmtmr_init = { | |||
263 | .opts = &timer_pmtmr, | 271 | .opts = &timer_pmtmr, |
264 | }; | 272 | }; |
265 | 273 | ||
274 | #ifdef CONFIG_PCI | ||
275 | /* | ||
276 | * PIIX4 Errata: | ||
277 | * | ||
278 | * The power management timer may return improper results when read. | ||
279 | * Although the timer value settles properly after incrementing, | ||
280 | * while incrementing there is a 3 ns window every 69.8 ns where the | ||
281 | * timer value is indeterminate (a 4.2% chance that the data will be | ||
282 | * incorrect when read). As a result, the ACPI free running count up | ||
283 | * timer specification is violated due to erroneous reads. | ||
284 | */ | ||
285 | static int __init pmtmr_bug_check(void) | ||
286 | { | ||
287 | static struct pci_device_id gray_list[] __initdata = { | ||
288 | /* these chipsets may have bug. */ | ||
289 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, | ||
290 | PCI_DEVICE_ID_INTEL_82801DB_0) }, | ||
291 | { }, | ||
292 | }; | ||
293 | struct pci_dev *dev; | ||
294 | int pmtmr_has_bug = 0; | ||
295 | u8 rev; | ||
296 | |||
297 | if (cur_timer != &timer_pmtmr || !pmtmr_need_workaround) | ||
298 | return 0; | ||
299 | |||
300 | dev = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
301 | PCI_DEVICE_ID_INTEL_82371AB_3, NULL); | ||
302 | if (dev) { | ||
303 | pci_read_config_byte(dev, PCI_REVISION_ID, &rev); | ||
304 | /* the bug has been fixed in PIIX4M */ | ||
305 | if (rev < 3) { | ||
306 | printk(KERN_WARNING "* Found PM-Timer Bug on this " | ||
307 | "chipset. Due to workarounds for a bug,\n" | ||
308 | "* this time source is slow. Consider trying " | ||
309 | "other time sources (clock=)\n"); | ||
310 | pmtmr_has_bug = 1; | ||
311 | } | ||
312 | pci_dev_put(dev); | ||
313 | } | ||
314 | |||
315 | if (pci_dev_present(gray_list)) { | ||
316 | printk(KERN_WARNING "* This chipset may have PM-Timer Bug. Due" | ||
317 | " to workarounds for a bug,\n" | ||
318 | "* this time source is slow. If you are sure your timer" | ||
319 | " does not have\n" | ||
320 | "* this bug, please use \"pmtmr_good\" to disable the " | ||
321 | "workaround\n"); | ||
322 | pmtmr_has_bug = 1; | ||
323 | } | ||
324 | |||
325 | if (!pmtmr_has_bug) | ||
326 | pmtmr_need_workaround = 0; | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | device_initcall(pmtmr_bug_check); | ||
331 | #endif | ||
332 | |||
333 | static int __init pmtr_good_setup(char *__str) | ||
334 | { | ||
335 | pmtmr_need_workaround = 0; | ||
336 | return 1; | ||
337 | } | ||
338 | __setup("pmtmr_good", pmtr_good_setup); | ||
339 | |||
266 | MODULE_LICENSE("GPL"); | 340 | MODULE_LICENSE("GPL"); |
267 | MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>"); | 341 | MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>"); |
268 | MODULE_DESCRIPTION("Power Management Timer (PMTMR) as primary timing source for x86"); | 342 | MODULE_DESCRIPTION("Power Management Timer (PMTMR) as primary timing source for x86"); |
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 4624f8ca2459..6b63a5aa1e46 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c | |||
@@ -92,22 +92,21 @@ asmlinkage void spurious_interrupt_bug(void); | |||
92 | asmlinkage void machine_check(void); | 92 | asmlinkage void machine_check(void); |
93 | 93 | ||
94 | static int kstack_depth_to_print = 24; | 94 | static int kstack_depth_to_print = 24; |
95 | struct notifier_block *i386die_chain; | 95 | ATOMIC_NOTIFIER_HEAD(i386die_chain); |
96 | static DEFINE_SPINLOCK(die_notifier_lock); | ||
97 | 96 | ||
98 | int register_die_notifier(struct notifier_block *nb) | 97 | int register_die_notifier(struct notifier_block *nb) |
99 | { | 98 | { |
100 | int err = 0; | ||
101 | unsigned long flags; | ||
102 | |||
103 | vmalloc_sync_all(); | 99 | vmalloc_sync_all(); |
104 | spin_lock_irqsave(&die_notifier_lock, flags); | 100 | return atomic_notifier_chain_register(&i386die_chain, nb); |
105 | err = notifier_chain_register(&i386die_chain, nb); | ||
106 | spin_unlock_irqrestore(&die_notifier_lock, flags); | ||
107 | return err; | ||
108 | } | 101 | } |
109 | EXPORT_SYMBOL(register_die_notifier); | 102 | EXPORT_SYMBOL(register_die_notifier); |
110 | 103 | ||
104 | int unregister_die_notifier(struct notifier_block *nb) | ||
105 | { | ||
106 | return atomic_notifier_chain_unregister(&i386die_chain, nb); | ||
107 | } | ||
108 | EXPORT_SYMBOL(unregister_die_notifier); | ||
109 | |||
111 | static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) | 110 | static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) |
112 | { | 111 | { |
113 | return p > (void *)tinfo && | 112 | return p > (void *)tinfo && |
diff --git a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c index c4af9638dbfa..fe6eb901326e 100644 --- a/arch/i386/mm/discontig.c +++ b/arch/i386/mm/discontig.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/nodemask.h> | 31 | #include <linux/nodemask.h> |
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <linux/kexec.h> | 33 | #include <linux/kexec.h> |
34 | #include <linux/pfn.h> | ||
34 | 35 | ||
35 | #include <asm/e820.h> | 36 | #include <asm/e820.h> |
36 | #include <asm/setup.h> | 37 | #include <asm/setup.h> |
@@ -352,17 +353,6 @@ void __init zone_sizes_init(void) | |||
352 | { | 353 | { |
353 | int nid; | 354 | int nid; |
354 | 355 | ||
355 | /* | ||
356 | * Insert nodes into pgdat_list backward so they appear in order. | ||
357 | * Clobber node 0's links and NULL out pgdat_list before starting. | ||
358 | */ | ||
359 | pgdat_list = NULL; | ||
360 | for (nid = MAX_NUMNODES - 1; nid >= 0; nid--) { | ||
361 | if (!node_online(nid)) | ||
362 | continue; | ||
363 | NODE_DATA(nid)->pgdat_next = pgdat_list; | ||
364 | pgdat_list = NODE_DATA(nid); | ||
365 | } | ||
366 | 356 | ||
367 | for_each_online_node(nid) { | 357 | for_each_online_node(nid) { |
368 | unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; | 358 | unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; |
diff --git a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c index 9db3242103be..2889567e21a1 100644 --- a/arch/i386/mm/pgtable.c +++ b/arch/i386/mm/pgtable.c | |||
@@ -36,7 +36,7 @@ void show_mem(void) | |||
36 | printk(KERN_INFO "Mem-info:\n"); | 36 | printk(KERN_INFO "Mem-info:\n"); |
37 | show_free_areas(); | 37 | show_free_areas(); |
38 | printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); | 38 | printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); |
39 | for_each_pgdat(pgdat) { | 39 | for_each_online_pgdat(pgdat) { |
40 | pgdat_resize_lock(pgdat, &flags); | 40 | pgdat_resize_lock(pgdat, &flags); |
41 | for (i = 0; i < pgdat->node_spanned_pages; ++i) { | 41 | for (i = 0; i < pgdat->node_spanned_pages; ++i) { |
42 | page = pgdat_page_nr(pgdat, i); | 42 | page = pgdat_page_nr(pgdat, i); |
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index dabd6c32641e..7c1ddc8ac443 100644 --- a/arch/ia64/kernel/traps.c +++ b/arch/ia64/kernel/traps.c | |||
@@ -30,19 +30,19 @@ extern spinlock_t timerlist_lock; | |||
30 | fpswa_interface_t *fpswa_interface; | 30 | fpswa_interface_t *fpswa_interface; |
31 | EXPORT_SYMBOL(fpswa_interface); | 31 | EXPORT_SYMBOL(fpswa_interface); |
32 | 32 | ||
33 | struct notifier_block *ia64die_chain; | 33 | ATOMIC_NOTIFIER_HEAD(ia64die_chain); |
34 | 34 | ||
35 | int | 35 | int |
36 | register_die_notifier(struct notifier_block *nb) | 36 | register_die_notifier(struct notifier_block *nb) |
37 | { | 37 | { |
38 | return notifier_chain_register(&ia64die_chain, nb); | 38 | return atomic_notifier_chain_register(&ia64die_chain, nb); |
39 | } | 39 | } |
40 | EXPORT_SYMBOL_GPL(register_die_notifier); | 40 | EXPORT_SYMBOL_GPL(register_die_notifier); |
41 | 41 | ||
42 | int | 42 | int |
43 | unregister_die_notifier(struct notifier_block *nb) | 43 | unregister_die_notifier(struct notifier_block *nb) |
44 | { | 44 | { |
45 | return notifier_chain_unregister(&ia64die_chain, nb); | 45 | return atomic_notifier_chain_unregister(&ia64die_chain, nb); |
46 | } | 46 | } |
47 | EXPORT_SYMBOL_GPL(unregister_die_notifier); | 47 | EXPORT_SYMBOL_GPL(unregister_die_notifier); |
48 | 48 | ||
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c index 2f5e44862e91..ec9eeb89975d 100644 --- a/arch/ia64/mm/discontig.c +++ b/arch/ia64/mm/discontig.c | |||
@@ -379,31 +379,6 @@ static void __init *memory_less_node_alloc(int nid, unsigned long pernodesize) | |||
379 | } | 379 | } |
380 | 380 | ||
381 | /** | 381 | /** |
382 | * pgdat_insert - insert the pgdat into global pgdat_list | ||
383 | * @pgdat: the pgdat for a node. | ||
384 | */ | ||
385 | static void __init pgdat_insert(pg_data_t *pgdat) | ||
386 | { | ||
387 | pg_data_t *prev = NULL, *next; | ||
388 | |||
389 | for_each_pgdat(next) | ||
390 | if (pgdat->node_id < next->node_id) | ||
391 | break; | ||
392 | else | ||
393 | prev = next; | ||
394 | |||
395 | if (prev) { | ||
396 | prev->pgdat_next = pgdat; | ||
397 | pgdat->pgdat_next = next; | ||
398 | } else { | ||
399 | pgdat->pgdat_next = pgdat_list; | ||
400 | pgdat_list = pgdat; | ||
401 | } | ||
402 | |||
403 | return; | ||
404 | } | ||
405 | |||
406 | /** | ||
407 | * memory_less_nodes - allocate and initialize CPU only nodes pernode | 382 | * memory_less_nodes - allocate and initialize CPU only nodes pernode |
408 | * information. | 383 | * information. |
409 | */ | 384 | */ |
@@ -560,7 +535,7 @@ void show_mem(void) | |||
560 | printk("Mem-info:\n"); | 535 | printk("Mem-info:\n"); |
561 | show_free_areas(); | 536 | show_free_areas(); |
562 | printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); | 537 | printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); |
563 | for_each_pgdat(pgdat) { | 538 | for_each_online_pgdat(pgdat) { |
564 | unsigned long present; | 539 | unsigned long present; |
565 | unsigned long flags; | 540 | unsigned long flags; |
566 | int shared = 0, cached = 0, reserved = 0; | 541 | int shared = 0, cached = 0, reserved = 0; |
@@ -745,11 +720,5 @@ void __init paging_init(void) | |||
745 | pfn_offset, zholes_size); | 720 | pfn_offset, zholes_size); |
746 | } | 721 | } |
747 | 722 | ||
748 | /* | ||
749 | * Make memory less nodes become a member of the known nodes. | ||
750 | */ | ||
751 | for_each_node_mask(node, memory_less_mask) | ||
752 | pgdat_insert(mem_data[node].pgdat); | ||
753 | |||
754 | zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page)); | 723 | zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page)); |
755 | } | 724 | } |
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index ff4f31fcd330..2ef1151cde90 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c | |||
@@ -600,7 +600,7 @@ mem_init (void) | |||
600 | kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START); | 600 | kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START); |
601 | kclist_add(&kcore_kernel, _stext, _end - _stext); | 601 | kclist_add(&kcore_kernel, _stext, _end - _stext); |
602 | 602 | ||
603 | for_each_pgdat(pgdat) | 603 | for_each_online_pgdat(pgdat) |
604 | if (pgdat->bdata->node_bootmem_map) | 604 | if (pgdat->bdata->node_bootmem_map) |
605 | totalram_pages += free_all_bootmem_node(pgdat); | 605 | totalram_pages += free_all_bootmem_node(pgdat); |
606 | 606 | ||
diff --git a/arch/m32r/kernel/setup.c b/arch/m32r/kernel/setup.c index d742037a7ccb..0d78942b4c76 100644 --- a/arch/m32r/kernel/setup.c +++ b/arch/m32r/kernel/setup.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/tty.h> | 24 | #include <linux/tty.h> |
25 | #include <linux/cpu.h> | 25 | #include <linux/cpu.h> |
26 | #include <linux/nodemask.h> | 26 | #include <linux/nodemask.h> |
27 | #include <linux/pfn.h> | ||
27 | 28 | ||
28 | #include <asm/processor.h> | 29 | #include <asm/processor.h> |
29 | #include <asm/pgtable.h> | 30 | #include <asm/pgtable.h> |
diff --git a/arch/m32r/mm/discontig.c b/arch/m32r/mm/discontig.c index 08e727955555..cf610a7c5ff0 100644 --- a/arch/m32r/mm/discontig.c +++ b/arch/m32r/mm/discontig.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/initrd.h> | 13 | #include <linux/initrd.h> |
14 | #include <linux/nodemask.h> | 14 | #include <linux/nodemask.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/pfn.h> | ||
16 | 17 | ||
17 | #include <asm/setup.h> | 18 | #include <asm/setup.h> |
18 | 19 | ||
@@ -137,12 +138,6 @@ unsigned long __init zone_sizes_init(void) | |||
137 | int nid, i; | 138 | int nid, i; |
138 | mem_prof_t *mp; | 139 | mem_prof_t *mp; |
139 | 140 | ||
140 | pgdat_list = NULL; | ||
141 | for (nid = num_online_nodes() - 1 ; nid >= 0 ; nid--) { | ||
142 | NODE_DATA(nid)->pgdat_next = pgdat_list; | ||
143 | pgdat_list = NODE_DATA(nid); | ||
144 | } | ||
145 | |||
146 | for_each_online_node(nid) { | 141 | for_each_online_node(nid) { |
147 | mp = &mem_prof[nid]; | 142 | mp = &mem_prof[nid]; |
148 | for (i = 0 ; i < MAX_NR_ZONES ; i++) { | 143 | for (i = 0 ; i < MAX_NR_ZONES ; i++) { |
diff --git a/arch/m32r/mm/init.c b/arch/m32r/mm/init.c index c9e7dad860b7..b71348fec1f4 100644 --- a/arch/m32r/mm/init.c +++ b/arch/m32r/mm/init.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/highmem.h> | 18 | #include <linux/highmem.h> |
19 | #include <linux/bitops.h> | 19 | #include <linux/bitops.h> |
20 | #include <linux/nodemask.h> | 20 | #include <linux/nodemask.h> |
21 | #include <linux/pfn.h> | ||
21 | #include <asm/types.h> | 22 | #include <asm/types.h> |
22 | #include <asm/processor.h> | 23 | #include <asm/processor.h> |
23 | #include <asm/page.h> | 24 | #include <asm/page.h> |
@@ -47,7 +48,7 @@ void show_mem(void) | |||
47 | printk("Mem-info:\n"); | 48 | printk("Mem-info:\n"); |
48 | show_free_areas(); | 49 | show_free_areas(); |
49 | printk("Free swap: %6ldkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); | 50 | printk("Free swap: %6ldkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); |
50 | for_each_pgdat(pgdat) { | 51 | for_each_online_pgdat(pgdat) { |
51 | unsigned long flags; | 52 | unsigned long flags; |
52 | pgdat_resize_lock(pgdat, &flags); | 53 | pgdat_resize_lock(pgdat, &flags); |
53 | for (i = 0; i < pgdat->node_spanned_pages; ++i) { | 54 | for (i = 0; i < pgdat->node_spanned_pages; ++i) { |
diff --git a/arch/mips/ddb5xxx/common/rtc_ds1386.c b/arch/mips/ddb5xxx/common/rtc_ds1386.c index 995896ac0e39..5dc34daa7150 100644 --- a/arch/mips/ddb5xxx/common/rtc_ds1386.c +++ b/arch/mips/ddb5xxx/common/rtc_ds1386.c | |||
@@ -165,6 +165,6 @@ rtc_ds1386_init(unsigned long base) | |||
165 | WRITE_RTC(0xB, byte); | 165 | WRITE_RTC(0xB, byte); |
166 | 166 | ||
167 | /* set the function pointers */ | 167 | /* set the function pointers */ |
168 | rtc_get_time = rtc_ds1386_get_time; | 168 | rtc_mips_get_time = rtc_ds1386_get_time; |
169 | rtc_set_time = rtc_ds1386_set_time; | 169 | rtc_mips_set_time = rtc_ds1386_set_time; |
170 | } | 170 | } |
diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c index 174822344131..f17d3378e9a6 100644 --- a/arch/mips/dec/time.c +++ b/arch/mips/dec/time.c | |||
@@ -193,8 +193,8 @@ static void dec_ioasic_hpt_init(unsigned int count) | |||
193 | 193 | ||
194 | void __init dec_time_init(void) | 194 | void __init dec_time_init(void) |
195 | { | 195 | { |
196 | rtc_get_time = dec_rtc_get_time; | 196 | rtc_mips_get_time = dec_rtc_get_time; |
197 | rtc_set_mmss = dec_rtc_set_mmss; | 197 | rtc_mips_set_mmss = dec_rtc_set_mmss; |
198 | 198 | ||
199 | mips_timer_state = dec_timer_state; | 199 | mips_timer_state = dec_timer_state; |
200 | mips_timer_ack = dec_timer_ack; | 200 | mips_timer_ack = dec_timer_ack; |
diff --git a/arch/mips/ite-boards/generic/time.c b/arch/mips/ite-boards/generic/time.c index f5d67ee21ac6..b79817bb6cce 100644 --- a/arch/mips/ite-boards/generic/time.c +++ b/arch/mips/ite-boards/generic/time.c | |||
@@ -227,8 +227,8 @@ void __init it8172_time_init(void) | |||
227 | 227 | ||
228 | local_irq_restore(flags); | 228 | local_irq_restore(flags); |
229 | 229 | ||
230 | rtc_get_time = it8172_rtc_get_time; | 230 | rtc_mips_get_time = it8172_rtc_get_time; |
231 | rtc_set_time = it8172_rtc_set_time; | 231 | rtc_mips_set_time = it8172_rtc_set_time; |
232 | } | 232 | } |
233 | 233 | ||
234 | #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) | 234 | #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) |
diff --git a/arch/mips/ite-boards/ivr/init.c b/arch/mips/ite-boards/ivr/init.c index ea4e1935fec5..b774db035b31 100644 --- a/arch/mips/ite-boards/ivr/init.c +++ b/arch/mips/ite-boards/ivr/init.c | |||
@@ -45,9 +45,6 @@ extern void __init prom_init_cmdline(void); | |||
45 | extern unsigned long __init prom_get_memsize(void); | 45 | extern unsigned long __init prom_get_memsize(void); |
46 | extern void __init it8172_init_ram_resource(unsigned long memsize); | 46 | extern void __init it8172_init_ram_resource(unsigned long memsize); |
47 | 47 | ||
48 | #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) | ||
49 | #define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) | ||
50 | |||
51 | const char *get_system_type(void) | 48 | const char *get_system_type(void) |
52 | { | 49 | { |
53 | return "Globespan IVR"; | 50 | return "Globespan IVR"; |
diff --git a/arch/mips/ite-boards/qed-4n-s01b/init.c b/arch/mips/ite-boards/qed-4n-s01b/init.c index 56dca7e0c21d..e8ec8be66a80 100644 --- a/arch/mips/ite-boards/qed-4n-s01b/init.c +++ b/arch/mips/ite-boards/qed-4n-s01b/init.c | |||
@@ -45,9 +45,6 @@ extern void __init prom_init_cmdline(void); | |||
45 | extern unsigned long __init prom_get_memsize(void); | 45 | extern unsigned long __init prom_get_memsize(void); |
46 | extern void __init it8172_init_ram_resource(unsigned long memsize); | 46 | extern void __init it8172_init_ram_resource(unsigned long memsize); |
47 | 47 | ||
48 | #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) | ||
49 | #define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) | ||
50 | |||
51 | const char *get_system_type(void) | 48 | const char *get_system_type(void) |
52 | { | 49 | { |
53 | return "ITE QED-4N-S01B"; | 50 | return "ITE QED-4N-S01B"; |
diff --git a/arch/mips/jmr3927/common/rtc_ds1742.c b/arch/mips/jmr3927/common/rtc_ds1742.c index 9a8bff153d80..a6bd3f4d3049 100644 --- a/arch/mips/jmr3927/common/rtc_ds1742.c +++ b/arch/mips/jmr3927/common/rtc_ds1742.c | |||
@@ -159,8 +159,8 @@ rtc_ds1742_init(unsigned long base) | |||
159 | db_assert((rtc_base & 0xe0000000) == KSEG1); | 159 | db_assert((rtc_base & 0xe0000000) == KSEG1); |
160 | 160 | ||
161 | /* set the function pointers */ | 161 | /* set the function pointers */ |
162 | rtc_get_time = rtc_ds1742_get_time; | 162 | rtc_mips_get_time = rtc_ds1742_get_time; |
163 | rtc_set_time = rtc_ds1742_set_time; | 163 | rtc_mips_set_time = rtc_ds1742_set_time; |
164 | 164 | ||
165 | /* clear oscillator stop bit */ | 165 | /* clear oscillator stop bit */ |
166 | CMOS_WRITE(RTC_READ, RTC_CONTROL); | 166 | CMOS_WRITE(RTC_READ, RTC_CONTROL); |
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 0cb3b6097e0e..dcbfd27071f0 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/highmem.h> | 34 | #include <linux/highmem.h> |
35 | #include <linux/console.h> | 35 | #include <linux/console.h> |
36 | #include <linux/mmzone.h> | 36 | #include <linux/mmzone.h> |
37 | #include <linux/pfn.h> | ||
37 | 38 | ||
38 | #include <asm/addrspace.h> | 39 | #include <asm/addrspace.h> |
39 | #include <asm/bootinfo.h> | 40 | #include <asm/bootinfo.h> |
@@ -257,10 +258,6 @@ static inline int parse_rd_cmdline(unsigned long* rd_start, unsigned long* rd_en | |||
257 | return 0; | 258 | return 0; |
258 | } | 259 | } |
259 | 260 | ||
260 | #define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT) | ||
261 | #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) | ||
262 | #define PFN_PHYS(x) ((x) << PAGE_SHIFT) | ||
263 | |||
264 | #define MAXMEM HIGHMEM_START | 261 | #define MAXMEM HIGHMEM_START |
265 | #define MAXMEM_PFN PFN_DOWN(MAXMEM) | 262 | #define MAXMEM_PFN PFN_DOWN(MAXMEM) |
266 | 263 | ||
@@ -493,10 +490,6 @@ static inline void resource_init(void) | |||
493 | } | 490 | } |
494 | } | 491 | } |
495 | 492 | ||
496 | #undef PFN_UP | ||
497 | #undef PFN_DOWN | ||
498 | #undef PFN_PHYS | ||
499 | |||
500 | #undef MAXMEM | 493 | #undef MAXMEM |
501 | #undef MAXMEM_PFN | 494 | #undef MAXMEM_PFN |
502 | 495 | ||
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index 51273b7297a7..5e51a2d8f3f0 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c | |||
@@ -65,9 +65,9 @@ static int null_rtc_set_time(unsigned long sec) | |||
65 | return 0; | 65 | return 0; |
66 | } | 66 | } |
67 | 67 | ||
68 | unsigned long (*rtc_get_time)(void) = null_rtc_get_time; | 68 | unsigned long (*rtc_mips_get_time)(void) = null_rtc_get_time; |
69 | int (*rtc_set_time)(unsigned long) = null_rtc_set_time; | 69 | int (*rtc_mips_set_time)(unsigned long) = null_rtc_set_time; |
70 | int (*rtc_set_mmss)(unsigned long); | 70 | int (*rtc_mips_set_mmss)(unsigned long); |
71 | 71 | ||
72 | 72 | ||
73 | /* usecs per counter cycle, shifted to left by 32 bits */ | 73 | /* usecs per counter cycle, shifted to left by 32 bits */ |
@@ -440,14 +440,14 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
440 | 440 | ||
441 | /* | 441 | /* |
442 | * If we have an externally synchronized Linux clock, then update | 442 | * If we have an externally synchronized Linux clock, then update |
443 | * CMOS clock accordingly every ~11 minutes. rtc_set_time() has to be | 443 | * CMOS clock accordingly every ~11 minutes. rtc_mips_set_time() has to be |
444 | * called as close as possible to 500 ms before the new second starts. | 444 | * called as close as possible to 500 ms before the new second starts. |
445 | */ | 445 | */ |
446 | if (ntp_synced() && | 446 | if (ntp_synced() && |
447 | xtime.tv_sec > last_rtc_update + 660 && | 447 | xtime.tv_sec > last_rtc_update + 660 && |
448 | (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && | 448 | (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && |
449 | (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { | 449 | (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { |
450 | if (rtc_set_mmss(xtime.tv_sec) == 0) { | 450 | if (rtc_mips_set_mmss(xtime.tv_sec) == 0) { |
451 | last_rtc_update = xtime.tv_sec; | 451 | last_rtc_update = xtime.tv_sec; |
452 | } else { | 452 | } else { |
453 | /* do it again in 60 s */ | 453 | /* do it again in 60 s */ |
@@ -565,7 +565,7 @@ asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs) | |||
565 | * b) (optional) calibrate and set the mips_hpt_frequency | 565 | * b) (optional) calibrate and set the mips_hpt_frequency |
566 | * (only needed if you intended to use fixed_rate_gettimeoffset | 566 | * (only needed if you intended to use fixed_rate_gettimeoffset |
567 | * or use cpu counter as timer interrupt source) | 567 | * or use cpu counter as timer interrupt source) |
568 | * 2) setup xtime based on rtc_get_time(). | 568 | * 2) setup xtime based on rtc_mips_get_time(). |
569 | * 3) choose a appropriate gettimeoffset routine. | 569 | * 3) choose a appropriate gettimeoffset routine. |
570 | * 4) calculate a couple of cached variables for later usage | 570 | * 4) calculate a couple of cached variables for later usage |
571 | * 5) board_timer_setup() - | 571 | * 5) board_timer_setup() - |
@@ -633,10 +633,10 @@ void __init time_init(void) | |||
633 | if (board_time_init) | 633 | if (board_time_init) |
634 | board_time_init(); | 634 | board_time_init(); |
635 | 635 | ||
636 | if (!rtc_set_mmss) | 636 | if (!rtc_mips_set_mmss) |
637 | rtc_set_mmss = rtc_set_time; | 637 | rtc_mips_set_mmss = rtc_mips_set_time; |
638 | 638 | ||
639 | xtime.tv_sec = rtc_get_time(); | 639 | xtime.tv_sec = rtc_mips_get_time(); |
640 | xtime.tv_nsec = 0; | 640 | xtime.tv_nsec = 0; |
641 | 641 | ||
642 | set_normalized_timespec(&wall_to_monotonic, | 642 | set_normalized_timespec(&wall_to_monotonic, |
@@ -772,8 +772,8 @@ void to_tm(unsigned long tim, struct rtc_time *tm) | |||
772 | 772 | ||
773 | EXPORT_SYMBOL(rtc_lock); | 773 | EXPORT_SYMBOL(rtc_lock); |
774 | EXPORT_SYMBOL(to_tm); | 774 | EXPORT_SYMBOL(to_tm); |
775 | EXPORT_SYMBOL(rtc_set_time); | 775 | EXPORT_SYMBOL(rtc_mips_set_time); |
776 | EXPORT_SYMBOL(rtc_get_time); | 776 | EXPORT_SYMBOL(rtc_mips_get_time); |
777 | 777 | ||
778 | unsigned long long sched_clock(void) | 778 | unsigned long long sched_clock(void) |
779 | { | 779 | { |
diff --git a/arch/mips/lasat/setup.c b/arch/mips/lasat/setup.c index 83eb08b7a072..bb70a8240e61 100644 --- a/arch/mips/lasat/setup.c +++ b/arch/mips/lasat/setup.c | |||
@@ -165,7 +165,8 @@ void __init plat_setup(void) | |||
165 | 165 | ||
166 | /* Set up panic notifier */ | 166 | /* Set up panic notifier */ |
167 | for (i = 0; i < sizeof(lasat_panic_block) / sizeof(struct notifier_block); i++) | 167 | for (i = 0; i < sizeof(lasat_panic_block) / sizeof(struct notifier_block); i++) |
168 | notifier_chain_register(&panic_notifier_list, &lasat_panic_block[i]); | 168 | atomic_notifier_chain_register(&panic_notifier_list, |
169 | &lasat_panic_block[i]); | ||
169 | 170 | ||
170 | lasat_reboot_setup(); | 171 | lasat_reboot_setup(); |
171 | 172 | ||
@@ -174,8 +175,8 @@ void __init plat_setup(void) | |||
174 | 175 | ||
175 | #ifdef CONFIG_DS1603 | 176 | #ifdef CONFIG_DS1603 |
176 | ds1603 = &ds_defs[mips_machtype]; | 177 | ds1603 = &ds_defs[mips_machtype]; |
177 | rtc_get_time = ds1603_read; | 178 | rtc_mips_get_time = ds1603_read; |
178 | rtc_set_time = ds1603_set; | 179 | rtc_mips_set_time = ds1603_set; |
179 | #endif | 180 | #endif |
180 | 181 | ||
181 | #ifdef DYNAMIC_SERIAL_INIT | 182 | #ifdef DYNAMIC_SERIAL_INIT |
diff --git a/arch/mips/mips-boards/atlas/atlas_setup.c b/arch/mips/mips-boards/atlas/atlas_setup.c index 873cf3141a31..c20d401ecf80 100644 --- a/arch/mips/mips-boards/atlas/atlas_setup.c +++ b/arch/mips/mips-boards/atlas/atlas_setup.c | |||
@@ -65,7 +65,7 @@ void __init plat_setup(void) | |||
65 | 65 | ||
66 | board_time_init = mips_time_init; | 66 | board_time_init = mips_time_init; |
67 | board_timer_setup = mips_timer_setup; | 67 | board_timer_setup = mips_timer_setup; |
68 | rtc_get_time = mips_rtc_get_time; | 68 | rtc_mips_get_time = mips_rtc_get_time; |
69 | } | 69 | } |
70 | 70 | ||
71 | static void __init serial_init(void) | 71 | static void __init serial_init(void) |
diff --git a/arch/mips/mips-boards/generic/memory.c b/arch/mips/mips-boards/generic/memory.c index ee5e70c95cf3..32c9210373ac 100644 --- a/arch/mips/mips-boards/generic/memory.c +++ b/arch/mips/mips-boards/generic/memory.c | |||
@@ -49,9 +49,6 @@ static char *mtypes[3] = { | |||
49 | /* References to section boundaries */ | 49 | /* References to section boundaries */ |
50 | extern char _end; | 50 | extern char _end; |
51 | 51 | ||
52 | #define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) | ||
53 | |||
54 | |||
55 | struct prom_pmemblock * __init prom_getmdesc(void) | 52 | struct prom_pmemblock * __init prom_getmdesc(void) |
56 | { | 53 | { |
57 | char *memsize_str; | 54 | char *memsize_str; |
@@ -109,10 +106,10 @@ struct prom_pmemblock * __init prom_getmdesc(void) | |||
109 | 106 | ||
110 | mdesc[3].type = yamon_dontuse; | 107 | mdesc[3].type = yamon_dontuse; |
111 | mdesc[3].base = 0x00100000; | 108 | mdesc[3].base = 0x00100000; |
112 | mdesc[3].size = CPHYSADDR(PFN_ALIGN(&_end)) - mdesc[3].base; | 109 | mdesc[3].size = CPHYSADDR(PAGE_ALIGN(&_end)) - mdesc[3].base; |
113 | 110 | ||
114 | mdesc[4].type = yamon_free; | 111 | mdesc[4].type = yamon_free; |
115 | mdesc[4].base = CPHYSADDR(PFN_ALIGN(&_end)); | 112 | mdesc[4].base = CPHYSADDR(PAGE_ALIGN(&_end)); |
116 | mdesc[4].size = memsize - mdesc[4].base; | 113 | mdesc[4].size = memsize - mdesc[4].base; |
117 | 114 | ||
118 | return &mdesc[0]; | 115 | return &mdesc[0]; |
diff --git a/arch/mips/mips-boards/malta/malta_setup.c b/arch/mips/mips-boards/malta/malta_setup.c index 2209e8a9de34..b8488aab6df1 100644 --- a/arch/mips/mips-boards/malta/malta_setup.c +++ b/arch/mips/mips-boards/malta/malta_setup.c | |||
@@ -225,5 +225,5 @@ void __init plat_setup(void) | |||
225 | 225 | ||
226 | board_time_init = mips_time_init; | 226 | board_time_init = mips_time_init; |
227 | board_timer_setup = mips_timer_setup; | 227 | board_timer_setup = mips_timer_setup; |
228 | rtc_get_time = mips_rtc_get_time; | 228 | rtc_mips_get_time = mips_rtc_get_time; |
229 | } | 229 | } |
diff --git a/arch/mips/mips-boards/sim/sim_mem.c b/arch/mips/mips-boards/sim/sim_mem.c index 1ec4e75656bd..e57f737bab10 100644 --- a/arch/mips/mips-boards/sim/sim_mem.c +++ b/arch/mips/mips-boards/sim/sim_mem.c | |||
@@ -42,9 +42,6 @@ static char *mtypes[3] = { | |||
42 | /* References to section boundaries */ | 42 | /* References to section boundaries */ |
43 | extern char _end; | 43 | extern char _end; |
44 | 44 | ||
45 | #define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) | ||
46 | |||
47 | |||
48 | struct prom_pmemblock * __init prom_getmdesc(void) | 45 | struct prom_pmemblock * __init prom_getmdesc(void) |
49 | { | 46 | { |
50 | unsigned int memsize; | 47 | unsigned int memsize; |
@@ -64,10 +61,10 @@ struct prom_pmemblock * __init prom_getmdesc(void) | |||
64 | 61 | ||
65 | mdesc[2].type = simmem_reserved; | 62 | mdesc[2].type = simmem_reserved; |
66 | mdesc[2].base = 0x00100000; | 63 | mdesc[2].base = 0x00100000; |
67 | mdesc[2].size = CPHYSADDR(PFN_ALIGN(&_end)) - mdesc[2].base; | 64 | mdesc[2].size = CPHYSADDR(PAGE_ALIGN(&_end)) - mdesc[2].base; |
68 | 65 | ||
69 | mdesc[3].type = simmem_free; | 66 | mdesc[3].type = simmem_free; |
70 | mdesc[3].base = CPHYSADDR(PFN_ALIGN(&_end)); | 67 | mdesc[3].base = CPHYSADDR(PAGE_ALIGN(&_end)); |
71 | mdesc[3].size = memsize - mdesc[3].base; | 68 | mdesc[3].size = memsize - mdesc[3].base; |
72 | 69 | ||
73 | return &mdesc[0]; | 70 | return &mdesc[0]; |
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 52f7d59fe612..ad89c442f299 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/highmem.h> | 25 | #include <linux/highmem.h> |
26 | #include <linux/swap.h> | 26 | #include <linux/swap.h> |
27 | #include <linux/proc_fs.h> | 27 | #include <linux/proc_fs.h> |
28 | #include <linux/pfn.h> | ||
28 | 29 | ||
29 | #include <asm/bootinfo.h> | 30 | #include <asm/bootinfo.h> |
30 | #include <asm/cachectl.h> | 31 | #include <asm/cachectl.h> |
@@ -177,9 +178,6 @@ void __init paging_init(void) | |||
177 | free_area_init(zones_size); | 178 | free_area_init(zones_size); |
178 | } | 179 | } |
179 | 180 | ||
180 | #define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT) | ||
181 | #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) | ||
182 | |||
183 | static inline int page_is_ram(unsigned long pagenr) | 181 | static inline int page_is_ram(unsigned long pagenr) |
184 | { | 182 | { |
185 | int i; | 183 | int i; |
diff --git a/arch/mips/momentum/jaguar_atx/setup.c b/arch/mips/momentum/jaguar_atx/setup.c index 3784c898db1a..91d9637143d7 100644 --- a/arch/mips/momentum/jaguar_atx/setup.c +++ b/arch/mips/momentum/jaguar_atx/setup.c | |||
@@ -229,8 +229,8 @@ void momenco_time_init(void) | |||
229 | mips_hpt_frequency = cpu_clock / 2; | 229 | mips_hpt_frequency = cpu_clock / 2; |
230 | board_timer_setup = momenco_timer_setup; | 230 | board_timer_setup = momenco_timer_setup; |
231 | 231 | ||
232 | rtc_get_time = m48t37y_get_time; | 232 | rtc_mips_get_time = m48t37y_get_time; |
233 | rtc_set_time = m48t37y_set_time; | 233 | rtc_mips_set_time = m48t37y_set_time; |
234 | } | 234 | } |
235 | 235 | ||
236 | static struct resource mv_pci_io_mem0_resource = { | 236 | static struct resource mv_pci_io_mem0_resource = { |
diff --git a/arch/mips/momentum/ocelot_3/setup.c b/arch/mips/momentum/ocelot_3/setup.c index f95677f4f06f..969612eab8a6 100644 --- a/arch/mips/momentum/ocelot_3/setup.c +++ b/arch/mips/momentum/ocelot_3/setup.c | |||
@@ -215,8 +215,8 @@ void momenco_time_init(void) | |||
215 | mips_hpt_frequency = cpu_clock / 2; | 215 | mips_hpt_frequency = cpu_clock / 2; |
216 | board_timer_setup = momenco_timer_setup; | 216 | board_timer_setup = momenco_timer_setup; |
217 | 217 | ||
218 | rtc_get_time = m48t37y_get_time; | 218 | rtc_mips_get_time = m48t37y_get_time; |
219 | rtc_set_time = m48t37y_set_time; | 219 | rtc_mips_set_time = m48t37y_set_time; |
220 | } | 220 | } |
221 | 221 | ||
222 | /* | 222 | /* |
diff --git a/arch/mips/momentum/ocelot_c/setup.c b/arch/mips/momentum/ocelot_c/setup.c index bd02e60d037a..a3e6f5575592 100644 --- a/arch/mips/momentum/ocelot_c/setup.c +++ b/arch/mips/momentum/ocelot_c/setup.c | |||
@@ -227,8 +227,8 @@ void momenco_time_init(void) | |||
227 | printk("momenco_time_init cpu_clock=%d\n", cpu_clock); | 227 | printk("momenco_time_init cpu_clock=%d\n", cpu_clock); |
228 | board_timer_setup = momenco_timer_setup; | 228 | board_timer_setup = momenco_timer_setup; |
229 | 229 | ||
230 | rtc_get_time = m48t37y_get_time; | 230 | rtc_mips_get_time = m48t37y_get_time; |
231 | rtc_set_time = m48t37y_set_time; | 231 | rtc_mips_set_time = m48t37y_set_time; |
232 | } | 232 | } |
233 | 233 | ||
234 | void __init plat_setup(void) | 234 | void __init plat_setup(void) |
diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c index 8bce711575de..3f724d661bdb 100644 --- a/arch/mips/pmc-sierra/yosemite/setup.c +++ b/arch/mips/pmc-sierra/yosemite/setup.c | |||
@@ -198,8 +198,8 @@ static void __init py_rtc_setup(void) | |||
198 | if (!m48t37_base) | 198 | if (!m48t37_base) |
199 | printk(KERN_ERR "Mapping the RTC failed\n"); | 199 | printk(KERN_ERR "Mapping the RTC failed\n"); |
200 | 200 | ||
201 | rtc_get_time = m48t37y_get_time; | 201 | rtc_mips_get_time = m48t37y_get_time; |
202 | rtc_set_time = m48t37y_set_time; | 202 | rtc_mips_set_time = m48t37y_set_time; |
203 | 203 | ||
204 | write_seqlock(&xtime_lock); | 204 | write_seqlock(&xtime_lock); |
205 | xtime.tv_sec = m48t37y_get_time(); | 205 | xtime.tv_sec = m48t37y_get_time(); |
diff --git a/arch/mips/sgi-ip22/ip22-reset.c b/arch/mips/sgi-ip22/ip22-reset.c index 92a3b3c15ed3..a9c58e067b53 100644 --- a/arch/mips/sgi-ip22/ip22-reset.c +++ b/arch/mips/sgi-ip22/ip22-reset.c | |||
@@ -238,7 +238,7 @@ static int __init reboot_setup(void) | |||
238 | request_irq(SGI_PANEL_IRQ, panel_int, 0, "Front Panel", NULL); | 238 | request_irq(SGI_PANEL_IRQ, panel_int, 0, "Front Panel", NULL); |
239 | init_timer(&blink_timer); | 239 | init_timer(&blink_timer); |
240 | blink_timer.function = blink_timeout; | 240 | blink_timer.function = blink_timeout; |
241 | notifier_chain_register(&panic_notifier_list, &panic_block); | 241 | atomic_notifier_chain_register(&panic_notifier_list, &panic_block); |
242 | 242 | ||
243 | return 0; | 243 | return 0; |
244 | } | 244 | } |
diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c index b7300cc5c5ad..cca688ad64ad 100644 --- a/arch/mips/sgi-ip22/ip22-time.c +++ b/arch/mips/sgi-ip22/ip22-time.c | |||
@@ -212,8 +212,8 @@ static void indy_timer_setup(struct irqaction *irq) | |||
212 | void __init ip22_time_init(void) | 212 | void __init ip22_time_init(void) |
213 | { | 213 | { |
214 | /* setup hookup functions */ | 214 | /* setup hookup functions */ |
215 | rtc_get_time = indy_rtc_get_time; | 215 | rtc_mips_get_time = indy_rtc_get_time; |
216 | rtc_set_time = indy_rtc_set_time; | 216 | rtc_mips_set_time = indy_rtc_set_time; |
217 | 217 | ||
218 | board_time_init = indy_time_init; | 218 | board_time_init = indy_time_init; |
219 | board_timer_setup = indy_timer_setup; | 219 | board_timer_setup = indy_timer_setup; |
diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c index e0d095daa5ed..6c00dce9f73f 100644 --- a/arch/mips/sgi-ip27/ip27-memory.c +++ b/arch/mips/sgi-ip27/ip27-memory.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/nodemask.h> | 19 | #include <linux/nodemask.h> |
20 | #include <linux/swap.h> | 20 | #include <linux/swap.h> |
21 | #include <linux/bootmem.h> | 21 | #include <linux/bootmem.h> |
22 | #include <linux/pfn.h> | ||
22 | #include <asm/page.h> | 23 | #include <asm/page.h> |
23 | #include <asm/sections.h> | 24 | #include <asm/sections.h> |
24 | 25 | ||
@@ -28,8 +29,6 @@ | |||
28 | #include <asm/sn/sn_private.h> | 29 | #include <asm/sn/sn_private.h> |
29 | 30 | ||
30 | 31 | ||
31 | #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) | ||
32 | |||
33 | #define SLOT_PFNSHIFT (SLOT_SHIFT - PAGE_SHIFT) | 32 | #define SLOT_PFNSHIFT (SLOT_SHIFT - PAGE_SHIFT) |
34 | #define PFN_NASIDSHFT (NASID_SHFT - PAGE_SHIFT) | 33 | #define PFN_NASIDSHFT (NASID_SHFT - PAGE_SHIFT) |
35 | 34 | ||
diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c index 0c948008b023..ab9d9cef089e 100644 --- a/arch/mips/sgi-ip32/ip32-reset.c +++ b/arch/mips/sgi-ip32/ip32-reset.c | |||
@@ -193,7 +193,7 @@ static __init int ip32_reboot_setup(void) | |||
193 | 193 | ||
194 | init_timer(&blink_timer); | 194 | init_timer(&blink_timer); |
195 | blink_timer.function = blink_timeout; | 195 | blink_timer.function = blink_timeout; |
196 | notifier_chain_register(&panic_notifier_list, &panic_block); | 196 | atomic_notifier_chain_register(&panic_notifier_list, &panic_block); |
197 | 197 | ||
198 | request_irq(MACEISA_RTC_IRQ, ip32_rtc_int, 0, "rtc", NULL); | 198 | request_irq(MACEISA_RTC_IRQ, ip32_rtc_int, 0, "rtc", NULL); |
199 | 199 | ||
diff --git a/arch/mips/sgi-ip32/ip32-setup.c b/arch/mips/sgi-ip32/ip32-setup.c index 2f50c79b7887..a2dd8ae1ea8f 100644 --- a/arch/mips/sgi-ip32/ip32-setup.c +++ b/arch/mips/sgi-ip32/ip32-setup.c | |||
@@ -91,8 +91,8 @@ void __init plat_setup(void) | |||
91 | { | 91 | { |
92 | board_be_init = ip32_be_init; | 92 | board_be_init = ip32_be_init; |
93 | 93 | ||
94 | rtc_get_time = mc146818_get_cmos_time; | 94 | rtc_mips_get_time = mc146818_get_cmos_time; |
95 | rtc_set_mmss = mc146818_set_rtc_mmss; | 95 | rtc_mips_set_mmss = mc146818_set_rtc_mmss; |
96 | 96 | ||
97 | board_time_init = ip32_time_init; | 97 | board_time_init = ip32_time_init; |
98 | board_timer_setup = ip32_timer_setup; | 98 | board_timer_setup = ip32_timer_setup; |
diff --git a/arch/mips/sibyte/swarm/setup.c b/arch/mips/sibyte/swarm/setup.c index b661d2425a36..4b5f74ff3edd 100644 --- a/arch/mips/sibyte/swarm/setup.c +++ b/arch/mips/sibyte/swarm/setup.c | |||
@@ -121,14 +121,14 @@ void __init plat_setup(void) | |||
121 | 121 | ||
122 | if (xicor_probe()) { | 122 | if (xicor_probe()) { |
123 | printk("swarm setup: Xicor 1241 RTC detected.\n"); | 123 | printk("swarm setup: Xicor 1241 RTC detected.\n"); |
124 | rtc_get_time = xicor_get_time; | 124 | rtc_mips_get_time = xicor_get_time; |
125 | rtc_set_time = xicor_set_time; | 125 | rtc_mips_set_time = xicor_set_time; |
126 | } | 126 | } |
127 | 127 | ||
128 | if (m41t81_probe()) { | 128 | if (m41t81_probe()) { |
129 | printk("swarm setup: M41T81 RTC detected.\n"); | 129 | printk("swarm setup: M41T81 RTC detected.\n"); |
130 | rtc_get_time = m41t81_get_time; | 130 | rtc_mips_get_time = m41t81_get_time; |
131 | rtc_set_time = m41t81_set_time; | 131 | rtc_mips_set_time = m41t81_set_time; |
132 | } | 132 | } |
133 | 133 | ||
134 | printk("This kernel optimized for " | 134 | printk("This kernel optimized for " |
diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c index 1141fcd13a59..01ba6c581e3d 100644 --- a/arch/mips/sni/setup.c +++ b/arch/mips/sni/setup.c | |||
@@ -164,8 +164,8 @@ static struct pci_controller sni_controller = { | |||
164 | 164 | ||
165 | static inline void sni_pcimt_time_init(void) | 165 | static inline void sni_pcimt_time_init(void) |
166 | { | 166 | { |
167 | rtc_get_time = mc146818_get_cmos_time; | 167 | rtc_mips_get_time = mc146818_get_cmos_time; |
168 | rtc_set_time = mc146818_set_rtc_mmss; | 168 | rtc_mips_set_time = mc146818_set_rtc_mmss; |
169 | } | 169 | } |
170 | 170 | ||
171 | void __init plat_setup(void) | 171 | void __init plat_setup(void) |
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c index 2ad6401d2af4..6dcf077f61a0 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c | |||
@@ -1036,8 +1036,8 @@ toshiba_rbtx4927_time_init(void) | |||
1036 | 1036 | ||
1037 | #ifdef CONFIG_RTC_DS1742 | 1037 | #ifdef CONFIG_RTC_DS1742 |
1038 | 1038 | ||
1039 | rtc_get_time = rtc_ds1742_get_time; | 1039 | rtc_mips_get_time = rtc_ds1742_get_time; |
1040 | rtc_set_time = rtc_ds1742_set_time; | 1040 | rtc_mips_set_time = rtc_ds1742_set_time; |
1041 | 1041 | ||
1042 | TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_TIME_INIT, | 1042 | TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_TIME_INIT, |
1043 | ":rtc_ds1742_init()-\n"); | 1043 | ":rtc_ds1742_init()-\n"); |
diff --git a/arch/mips/tx4938/common/rtc_rx5c348.c b/arch/mips/tx4938/common/rtc_rx5c348.c index d249edbb6af4..f74295f28527 100644 --- a/arch/mips/tx4938/common/rtc_rx5c348.c +++ b/arch/mips/tx4938/common/rtc_rx5c348.c | |||
@@ -197,6 +197,6 @@ rtc_rx5c348_init(int chipid) | |||
197 | srtc_24h = 1; | 197 | srtc_24h = 1; |
198 | 198 | ||
199 | /* set the function pointers */ | 199 | /* set the function pointers */ |
200 | rtc_get_time = rtc_rx5c348_get_time; | 200 | rtc_mips_get_time = rtc_rx5c348_get_time; |
201 | rtc_set_time = rtc_rx5c348_set_time; | 201 | rtc_mips_set_time = rtc_rx5c348_set_time; |
202 | } | 202 | } |
diff --git a/arch/parisc/kernel/pdc_chassis.c b/arch/parisc/kernel/pdc_chassis.c index 2a01fe1bdc98..0cea6958f427 100644 --- a/arch/parisc/kernel/pdc_chassis.c +++ b/arch/parisc/kernel/pdc_chassis.c | |||
@@ -150,7 +150,8 @@ void __init parisc_pdc_chassis_init(void) | |||
150 | 150 | ||
151 | if (handle) { | 151 | if (handle) { |
152 | /* initialize panic notifier chain */ | 152 | /* initialize panic notifier chain */ |
153 | notifier_chain_register(&panic_notifier_list, &pdc_chassis_panic_block); | 153 | atomic_notifier_chain_register(&panic_notifier_list, |
154 | &pdc_chassis_panic_block); | ||
154 | 155 | ||
155 | /* initialize reboot notifier chain */ | 156 | /* initialize reboot notifier chain */ |
156 | register_reboot_notifier(&pdc_chassis_reboot_block); | 157 | register_reboot_notifier(&pdc_chassis_reboot_block); |
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 2f3fdad35594..e20c1fae3423 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
@@ -579,7 +579,8 @@ void __init setup_arch(char **cmdline_p) | |||
579 | panic_timeout = 180; | 579 | panic_timeout = 180; |
580 | 580 | ||
581 | if (ppc_md.panic) | 581 | if (ppc_md.panic) |
582 | notifier_chain_register(&panic_notifier_list, &ppc64_panic_block); | 582 | atomic_notifier_chain_register(&panic_notifier_list, |
583 | &ppc64_panic_block); | ||
583 | 584 | ||
584 | init_mm.start_code = PAGE_OFFSET; | 585 | init_mm.start_code = PAGE_OFFSET; |
585 | init_mm.end_code = (unsigned long) _etext; | 586 | init_mm.end_code = (unsigned long) _etext; |
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 98660aedeeb7..9763faab6739 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -74,19 +74,19 @@ EXPORT_SYMBOL(__debugger_dabr_match); | |||
74 | EXPORT_SYMBOL(__debugger_fault_handler); | 74 | EXPORT_SYMBOL(__debugger_fault_handler); |
75 | #endif | 75 | #endif |
76 | 76 | ||
77 | struct notifier_block *powerpc_die_chain; | 77 | ATOMIC_NOTIFIER_HEAD(powerpc_die_chain); |
78 | static DEFINE_SPINLOCK(die_notifier_lock); | ||
79 | 78 | ||
80 | int register_die_notifier(struct notifier_block *nb) | 79 | int register_die_notifier(struct notifier_block *nb) |
81 | { | 80 | { |
82 | int err = 0; | 81 | return atomic_notifier_chain_register(&powerpc_die_chain, nb); |
83 | unsigned long flags; | 82 | } |
83 | EXPORT_SYMBOL(register_die_notifier); | ||
84 | 84 | ||
85 | spin_lock_irqsave(&die_notifier_lock, flags); | 85 | int unregister_die_notifier(struct notifier_block *nb) |
86 | err = notifier_chain_register(&powerpc_die_chain, nb); | 86 | { |
87 | spin_unlock_irqrestore(&die_notifier_lock, flags); | 87 | return atomic_notifier_chain_unregister(&powerpc_die_chain, nb); |
88 | return err; | ||
89 | } | 88 | } |
89 | EXPORT_SYMBOL(unregister_die_notifier); | ||
90 | 90 | ||
91 | /* | 91 | /* |
92 | * Trap & Exception support | 92 | * Trap & Exception support |
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index badac10d700c..5e435a9c3431 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c | |||
@@ -195,7 +195,7 @@ void show_mem(void) | |||
195 | printk("Mem-info:\n"); | 195 | printk("Mem-info:\n"); |
196 | show_free_areas(); | 196 | show_free_areas(); |
197 | printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); | 197 | printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); |
198 | for_each_pgdat(pgdat) { | 198 | for_each_online_pgdat(pgdat) { |
199 | unsigned long flags; | 199 | unsigned long flags; |
200 | pgdat_resize_lock(pgdat, &flags); | 200 | pgdat_resize_lock(pgdat, &flags); |
201 | for (i = 0; i < pgdat->node_spanned_pages; i++) { | 201 | for (i = 0; i < pgdat->node_spanned_pages; i++) { |
@@ -351,7 +351,7 @@ void __init mem_init(void) | |||
351 | max_mapnr = max_pfn; | 351 | max_mapnr = max_pfn; |
352 | totalram_pages += free_all_bootmem(); | 352 | totalram_pages += free_all_bootmem(); |
353 | #endif | 353 | #endif |
354 | for_each_pgdat(pgdat) { | 354 | for_each_online_pgdat(pgdat) { |
355 | for (i = 0; i < pgdat->node_spanned_pages; i++) { | 355 | for (i = 0; i < pgdat->node_spanned_pages; i++) { |
356 | if (!pfn_valid(pgdat->node_start_pfn + i)) | 356 | if (!pfn_valid(pgdat->node_start_pfn + i)) |
357 | continue; | 357 | continue; |
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 86cfa6ecdcf3..5ad90676567a 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c | |||
@@ -94,16 +94,16 @@ static struct device_node *derive_parent(const char *path) | |||
94 | return parent; | 94 | return parent; |
95 | } | 95 | } |
96 | 96 | ||
97 | static struct notifier_block *pSeries_reconfig_chain; | 97 | static BLOCKING_NOTIFIER_HEAD(pSeries_reconfig_chain); |
98 | 98 | ||
99 | int pSeries_reconfig_notifier_register(struct notifier_block *nb) | 99 | int pSeries_reconfig_notifier_register(struct notifier_block *nb) |
100 | { | 100 | { |
101 | return notifier_chain_register(&pSeries_reconfig_chain, nb); | 101 | return blocking_notifier_chain_register(&pSeries_reconfig_chain, nb); |
102 | } | 102 | } |
103 | 103 | ||
104 | void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) | 104 | void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) |
105 | { | 105 | { |
106 | notifier_chain_unregister(&pSeries_reconfig_chain, nb); | 106 | blocking_notifier_chain_unregister(&pSeries_reconfig_chain, nb); |
107 | } | 107 | } |
108 | 108 | ||
109 | static int pSeries_reconfig_add_node(const char *path, struct property *proplist) | 109 | static int pSeries_reconfig_add_node(const char *path, struct property *proplist) |
@@ -131,7 +131,7 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist | |||
131 | goto out_err; | 131 | goto out_err; |
132 | } | 132 | } |
133 | 133 | ||
134 | err = notifier_call_chain(&pSeries_reconfig_chain, | 134 | err = blocking_notifier_call_chain(&pSeries_reconfig_chain, |
135 | PSERIES_RECONFIG_ADD, np); | 135 | PSERIES_RECONFIG_ADD, np); |
136 | if (err == NOTIFY_BAD) { | 136 | if (err == NOTIFY_BAD) { |
137 | printk(KERN_ERR "Failed to add device node %s\n", path); | 137 | printk(KERN_ERR "Failed to add device node %s\n", path); |
@@ -171,7 +171,7 @@ static int pSeries_reconfig_remove_node(struct device_node *np) | |||
171 | 171 | ||
172 | remove_node_proc_entries(np); | 172 | remove_node_proc_entries(np); |
173 | 173 | ||
174 | notifier_call_chain(&pSeries_reconfig_chain, | 174 | blocking_notifier_call_chain(&pSeries_reconfig_chain, |
175 | PSERIES_RECONFIG_REMOVE, np); | 175 | PSERIES_RECONFIG_REMOVE, np); |
176 | of_detach_node(np); | 176 | of_detach_node(np); |
177 | 177 | ||
diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c index a0fc628ffb1e..d95c05d9824d 100644 --- a/arch/ppc/platforms/prep_setup.c +++ b/arch/ppc/platforms/prep_setup.c | |||
@@ -736,7 +736,7 @@ ibm_statusled_progress(char *s, unsigned short hex) | |||
736 | hex = 0xfff; | 736 | hex = 0xfff; |
737 | if (!notifier_installed) { | 737 | if (!notifier_installed) { |
738 | ++notifier_installed; | 738 | ++notifier_installed; |
739 | notifier_chain_register(&panic_notifier_list, | 739 | atomic_notifier_chain_register(&panic_notifier_list, |
740 | &ibm_statusled_block); | 740 | &ibm_statusled_block); |
741 | } | 741 | } |
742 | } | 742 | } |
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 99182a415fe7..4a0f5a1551ea 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c | |||
@@ -76,17 +76,17 @@ unsigned long thread_saved_pc(struct task_struct *tsk) | |||
76 | /* | 76 | /* |
77 | * Need to know about CPUs going idle? | 77 | * Need to know about CPUs going idle? |
78 | */ | 78 | */ |
79 | static struct notifier_block *idle_chain; | 79 | static ATOMIC_NOTIFIER_HEAD(idle_chain); |
80 | 80 | ||
81 | int register_idle_notifier(struct notifier_block *nb) | 81 | int register_idle_notifier(struct notifier_block *nb) |
82 | { | 82 | { |
83 | return notifier_chain_register(&idle_chain, nb); | 83 | return atomic_notifier_chain_register(&idle_chain, nb); |
84 | } | 84 | } |
85 | EXPORT_SYMBOL(register_idle_notifier); | 85 | EXPORT_SYMBOL(register_idle_notifier); |
86 | 86 | ||
87 | int unregister_idle_notifier(struct notifier_block *nb) | 87 | int unregister_idle_notifier(struct notifier_block *nb) |
88 | { | 88 | { |
89 | return notifier_chain_unregister(&idle_chain, nb); | 89 | return atomic_notifier_chain_unregister(&idle_chain, nb); |
90 | } | 90 | } |
91 | EXPORT_SYMBOL(unregister_idle_notifier); | 91 | EXPORT_SYMBOL(unregister_idle_notifier); |
92 | 92 | ||
@@ -95,7 +95,7 @@ void do_monitor_call(struct pt_regs *regs, long interruption_code) | |||
95 | /* disable monitor call class 0 */ | 95 | /* disable monitor call class 0 */ |
96 | __ctl_clear_bit(8, 15); | 96 | __ctl_clear_bit(8, 15); |
97 | 97 | ||
98 | notifier_call_chain(&idle_chain, CPU_NOT_IDLE, | 98 | atomic_notifier_call_chain(&idle_chain, CPU_NOT_IDLE, |
99 | (void *)(long) smp_processor_id()); | 99 | (void *)(long) smp_processor_id()); |
100 | } | 100 | } |
101 | 101 | ||
@@ -116,7 +116,8 @@ static void default_idle(void) | |||
116 | return; | 116 | return; |
117 | } | 117 | } |
118 | 118 | ||
119 | rc = notifier_call_chain(&idle_chain, CPU_IDLE, (void *)(long) cpu); | 119 | rc = atomic_notifier_call_chain(&idle_chain, |
120 | CPU_IDLE, (void *)(long) cpu); | ||
120 | if (rc != NOTIFY_OK && rc != NOTIFY_DONE) | 121 | if (rc != NOTIFY_OK && rc != NOTIFY_DONE) |
121 | BUG(); | 122 | BUG(); |
122 | if (rc != NOTIFY_OK) { | 123 | if (rc != NOTIFY_OK) { |
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index c0e79843f580..7ee4ca203616 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/root_dev.h> | 20 | #include <linux/root_dev.h> |
21 | #include <linux/utsname.h> | 21 | #include <linux/utsname.h> |
22 | #include <linux/cpu.h> | 22 | #include <linux/cpu.h> |
23 | #include <linux/pfn.h> | ||
23 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
24 | #include <asm/io.h> | 25 | #include <asm/io.h> |
25 | #include <asm/sections.h> | 26 | #include <asm/sections.h> |
@@ -275,10 +276,6 @@ void __init setup_arch(char **cmdline_p) | |||
275 | 276 | ||
276 | sh_mv_setup(cmdline_p); | 277 | sh_mv_setup(cmdline_p); |
277 | 278 | ||
278 | #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) | ||
279 | #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) | ||
280 | #define PFN_PHYS(x) ((x) << PAGE_SHIFT) | ||
281 | |||
282 | /* | 279 | /* |
283 | * Find the highest page frame number we have available | 280 | * Find the highest page frame number we have available |
284 | */ | 281 | */ |
diff --git a/arch/sh64/kernel/setup.c b/arch/sh64/kernel/setup.c index c7a7b816a30f..d2711c9c9d13 100644 --- a/arch/sh64/kernel/setup.c +++ b/arch/sh64/kernel/setup.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <linux/root_dev.h> | 48 | #include <linux/root_dev.h> |
49 | #include <linux/cpu.h> | 49 | #include <linux/cpu.h> |
50 | #include <linux/initrd.h> | 50 | #include <linux/initrd.h> |
51 | #include <linux/pfn.h> | ||
51 | #include <asm/processor.h> | 52 | #include <asm/processor.h> |
52 | #include <asm/page.h> | 53 | #include <asm/page.h> |
53 | #include <asm/pgtable.h> | 54 | #include <asm/pgtable.h> |
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index df612e4f75f9..ff090bb9734b 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c | |||
@@ -43,18 +43,19 @@ | |||
43 | #include <linux/kmod.h> | 43 | #include <linux/kmod.h> |
44 | #endif | 44 | #endif |
45 | 45 | ||
46 | struct notifier_block *sparc64die_chain; | 46 | ATOMIC_NOTIFIER_HEAD(sparc64die_chain); |
47 | static DEFINE_SPINLOCK(die_notifier_lock); | ||
48 | 47 | ||
49 | int register_die_notifier(struct notifier_block *nb) | 48 | int register_die_notifier(struct notifier_block *nb) |
50 | { | 49 | { |
51 | int err = 0; | 50 | return atomic_notifier_chain_register(&sparc64die_chain, nb); |
52 | unsigned long flags; | ||
53 | spin_lock_irqsave(&die_notifier_lock, flags); | ||
54 | err = notifier_chain_register(&sparc64die_chain, nb); | ||
55 | spin_unlock_irqrestore(&die_notifier_lock, flags); | ||
56 | return err; | ||
57 | } | 51 | } |
52 | EXPORT_SYMBOL(register_die_notifier); | ||
53 | |||
54 | int unregister_die_notifier(struct notifier_block *nb) | ||
55 | { | ||
56 | return atomic_notifier_chain_unregister(&sparc64die_chain, nb); | ||
57 | } | ||
58 | EXPORT_SYMBOL(unregister_die_notifier); | ||
58 | 59 | ||
59 | /* When an irrecoverable trap occurs at tl > 0, the trap entry | 60 | /* When an irrecoverable trap occurs at tl > 0, the trap entry |
60 | * code logs the trap state registers at every level in the trap | 61 | * code logs the trap state registers at every level in the trap |
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 54388d10bcf9..1488816588ea 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c | |||
@@ -762,7 +762,8 @@ static struct notifier_block panic_exit_notifier = { | |||
762 | 762 | ||
763 | static int add_notifier(void) | 763 | static int add_notifier(void) |
764 | { | 764 | { |
765 | notifier_chain_register(&panic_notifier_list, &panic_exit_notifier); | 765 | atomic_notifier_chain_register(&panic_notifier_list, |
766 | &panic_exit_notifier); | ||
766 | return(0); | 767 | return(0); |
767 | } | 768 | } |
768 | 769 | ||
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index fa617e0719ab..0336575d2448 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
@@ -71,7 +71,7 @@ struct io_thread_req { | |||
71 | int error; | 71 | int error; |
72 | }; | 72 | }; |
73 | 73 | ||
74 | extern int open_ubd_file(char *file, struct openflags *openflags, | 74 | extern int open_ubd_file(char *file, struct openflags *openflags, int shared, |
75 | char **backing_file_out, int *bitmap_offset_out, | 75 | char **backing_file_out, int *bitmap_offset_out, |
76 | unsigned long *bitmap_len_out, int *data_offset_out, | 76 | unsigned long *bitmap_len_out, int *data_offset_out, |
77 | int *create_cow_out); | 77 | int *create_cow_out); |
@@ -137,7 +137,7 @@ static int fake_major = MAJOR_NR; | |||
137 | 137 | ||
138 | static struct gendisk *ubd_gendisk[MAX_DEV]; | 138 | static struct gendisk *ubd_gendisk[MAX_DEV]; |
139 | static struct gendisk *fake_gendisk[MAX_DEV]; | 139 | static struct gendisk *fake_gendisk[MAX_DEV]; |
140 | 140 | ||
141 | #ifdef CONFIG_BLK_DEV_UBD_SYNC | 141 | #ifdef CONFIG_BLK_DEV_UBD_SYNC |
142 | #define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \ | 142 | #define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \ |
143 | .cl = 1 }) | 143 | .cl = 1 }) |
@@ -168,6 +168,7 @@ struct ubd { | |||
168 | __u64 size; | 168 | __u64 size; |
169 | struct openflags boot_openflags; | 169 | struct openflags boot_openflags; |
170 | struct openflags openflags; | 170 | struct openflags openflags; |
171 | int shared; | ||
171 | int no_cow; | 172 | int no_cow; |
172 | struct cow cow; | 173 | struct cow cow; |
173 | struct platform_device pdev; | 174 | struct platform_device pdev; |
@@ -189,6 +190,7 @@ struct ubd { | |||
189 | .boot_openflags = OPEN_FLAGS, \ | 190 | .boot_openflags = OPEN_FLAGS, \ |
190 | .openflags = OPEN_FLAGS, \ | 191 | .openflags = OPEN_FLAGS, \ |
191 | .no_cow = 0, \ | 192 | .no_cow = 0, \ |
193 | .shared = 0, \ | ||
192 | .cow = DEFAULT_COW, \ | 194 | .cow = DEFAULT_COW, \ |
193 | } | 195 | } |
194 | 196 | ||
@@ -305,7 +307,7 @@ static int ubd_setup_common(char *str, int *index_out) | |||
305 | } | 307 | } |
306 | major = simple_strtoul(str, &end, 0); | 308 | major = simple_strtoul(str, &end, 0); |
307 | if((*end != '\0') || (end == str)){ | 309 | if((*end != '\0') || (end == str)){ |
308 | printk(KERN_ERR | 310 | printk(KERN_ERR |
309 | "ubd_setup : didn't parse major number\n"); | 311 | "ubd_setup : didn't parse major number\n"); |
310 | return(1); | 312 | return(1); |
311 | } | 313 | } |
@@ -316,7 +318,7 @@ static int ubd_setup_common(char *str, int *index_out) | |||
316 | printk(KERN_ERR "Can't assign a fake major twice\n"); | 318 | printk(KERN_ERR "Can't assign a fake major twice\n"); |
317 | goto out1; | 319 | goto out1; |
318 | } | 320 | } |
319 | 321 | ||
320 | fake_major = major; | 322 | fake_major = major; |
321 | 323 | ||
322 | printk(KERN_INFO "Setting extra ubd major number to %d\n", | 324 | printk(KERN_INFO "Setting extra ubd major number to %d\n", |
@@ -351,7 +353,7 @@ static int ubd_setup_common(char *str, int *index_out) | |||
351 | if (index_out) | 353 | if (index_out) |
352 | *index_out = n; | 354 | *index_out = n; |
353 | 355 | ||
354 | for (i = 0; i < 4; i++) { | 356 | for (i = 0; i < sizeof("rscd="); i++) { |
355 | switch (*str) { | 357 | switch (*str) { |
356 | case 'r': | 358 | case 'r': |
357 | flags.w = 0; | 359 | flags.w = 0; |
@@ -362,11 +364,14 @@ static int ubd_setup_common(char *str, int *index_out) | |||
362 | case 'd': | 364 | case 'd': |
363 | dev->no_cow = 1; | 365 | dev->no_cow = 1; |
364 | break; | 366 | break; |
367 | case 'c': | ||
368 | dev->shared = 1; | ||
369 | break; | ||
365 | case '=': | 370 | case '=': |
366 | str++; | 371 | str++; |
367 | goto break_loop; | 372 | goto break_loop; |
368 | default: | 373 | default: |
369 | printk(KERN_ERR "ubd_setup : Expected '=' or flag letter (r,s or d)\n"); | 374 | printk(KERN_ERR "ubd_setup : Expected '=' or flag letter (r, s, c, or d)\n"); |
370 | goto out; | 375 | goto out; |
371 | } | 376 | } |
372 | str++; | 377 | str++; |
@@ -515,7 +520,7 @@ static void ubd_handler(void) | |||
515 | spin_unlock(&ubd_io_lock); | 520 | spin_unlock(&ubd_io_lock); |
516 | return; | 521 | return; |
517 | } | 522 | } |
518 | 523 | ||
519 | ubd_finish(rq, req.error); | 524 | ubd_finish(rq, req.error); |
520 | reactivate_fd(thread_fd, UBD_IRQ); | 525 | reactivate_fd(thread_fd, UBD_IRQ); |
521 | do_ubd_request(ubd_queue); | 526 | do_ubd_request(ubd_queue); |
@@ -532,7 +537,7 @@ static int io_pid = -1; | |||
532 | 537 | ||
533 | void kill_io_thread(void) | 538 | void kill_io_thread(void) |
534 | { | 539 | { |
535 | if(io_pid != -1) | 540 | if(io_pid != -1) |
536 | os_kill_process(io_pid, 1); | 541 | os_kill_process(io_pid, 1); |
537 | } | 542 | } |
538 | 543 | ||
@@ -567,14 +572,15 @@ static int ubd_open_dev(struct ubd *dev) | |||
567 | create_cow = 0; | 572 | create_cow = 0; |
568 | create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL; | 573 | create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL; |
569 | back_ptr = dev->no_cow ? NULL : &dev->cow.file; | 574 | back_ptr = dev->no_cow ? NULL : &dev->cow.file; |
570 | dev->fd = open_ubd_file(dev->file, &dev->openflags, back_ptr, | 575 | dev->fd = open_ubd_file(dev->file, &dev->openflags, dev->shared, |
571 | &dev->cow.bitmap_offset, &dev->cow.bitmap_len, | 576 | back_ptr, &dev->cow.bitmap_offset, |
572 | &dev->cow.data_offset, create_ptr); | 577 | &dev->cow.bitmap_len, &dev->cow.data_offset, |
578 | create_ptr); | ||
573 | 579 | ||
574 | if((dev->fd == -ENOENT) && create_cow){ | 580 | if((dev->fd == -ENOENT) && create_cow){ |
575 | dev->fd = create_cow_file(dev->file, dev->cow.file, | 581 | dev->fd = create_cow_file(dev->file, dev->cow.file, |
576 | dev->openflags, 1 << 9, PAGE_SIZE, | 582 | dev->openflags, 1 << 9, PAGE_SIZE, |
577 | &dev->cow.bitmap_offset, | 583 | &dev->cow.bitmap_offset, |
578 | &dev->cow.bitmap_len, | 584 | &dev->cow.bitmap_len, |
579 | &dev->cow.data_offset); | 585 | &dev->cow.data_offset); |
580 | if(dev->fd >= 0){ | 586 | if(dev->fd >= 0){ |
@@ -598,16 +604,16 @@ static int ubd_open_dev(struct ubd *dev) | |||
598 | } | 604 | } |
599 | flush_tlb_kernel_vm(); | 605 | flush_tlb_kernel_vm(); |
600 | 606 | ||
601 | err = read_cow_bitmap(dev->fd, dev->cow.bitmap, | 607 | err = read_cow_bitmap(dev->fd, dev->cow.bitmap, |
602 | dev->cow.bitmap_offset, | 608 | dev->cow.bitmap_offset, |
603 | dev->cow.bitmap_len); | 609 | dev->cow.bitmap_len); |
604 | if(err < 0) | 610 | if(err < 0) |
605 | goto error; | 611 | goto error; |
606 | 612 | ||
607 | flags = dev->openflags; | 613 | flags = dev->openflags; |
608 | flags.w = 0; | 614 | flags.w = 0; |
609 | err = open_ubd_file(dev->cow.file, &flags, NULL, NULL, NULL, | 615 | err = open_ubd_file(dev->cow.file, &flags, dev->shared, NULL, |
610 | NULL, NULL); | 616 | NULL, NULL, NULL, NULL); |
611 | if(err < 0) goto error; | 617 | if(err < 0) goto error; |
612 | dev->cow.fd = err; | 618 | dev->cow.fd = err; |
613 | } | 619 | } |
@@ -685,11 +691,11 @@ static int ubd_add(int n) | |||
685 | dev->size = ROUND_BLOCK(dev->size); | 691 | dev->size = ROUND_BLOCK(dev->size); |
686 | 692 | ||
687 | err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]); | 693 | err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]); |
688 | if(err) | 694 | if(err) |
689 | goto out_close; | 695 | goto out_close; |
690 | 696 | ||
691 | if(fake_major != MAJOR_NR) | 697 | if(fake_major != MAJOR_NR) |
692 | ubd_new_disk(fake_major, dev->size, n, | 698 | ubd_new_disk(fake_major, dev->size, n, |
693 | &fake_gendisk[n]); | 699 | &fake_gendisk[n]); |
694 | 700 | ||
695 | /* perhaps this should also be under the "if (fake_major)" above */ | 701 | /* perhaps this should also be under the "if (fake_major)" above */ |
@@ -854,7 +860,7 @@ int ubd_init(void) | |||
854 | return -1; | 860 | return -1; |
855 | } | 861 | } |
856 | platform_driver_register(&ubd_driver); | 862 | platform_driver_register(&ubd_driver); |
857 | for (i = 0; i < MAX_DEV; i++) | 863 | for (i = 0; i < MAX_DEV; i++) |
858 | ubd_add(i); | 864 | ubd_add(i); |
859 | return 0; | 865 | return 0; |
860 | } | 866 | } |
@@ -872,16 +878,16 @@ int ubd_driver_init(void){ | |||
872 | * enough. So use anyway the io thread. */ | 878 | * enough. So use anyway the io thread. */ |
873 | } | 879 | } |
874 | stack = alloc_stack(0, 0); | 880 | stack = alloc_stack(0, 0); |
875 | io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), | 881 | io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), |
876 | &thread_fd); | 882 | &thread_fd); |
877 | if(io_pid < 0){ | 883 | if(io_pid < 0){ |
878 | printk(KERN_ERR | 884 | printk(KERN_ERR |
879 | "ubd : Failed to start I/O thread (errno = %d) - " | 885 | "ubd : Failed to start I/O thread (errno = %d) - " |
880 | "falling back to synchronous I/O\n", -io_pid); | 886 | "falling back to synchronous I/O\n", -io_pid); |
881 | io_pid = -1; | 887 | io_pid = -1; |
882 | return(0); | 888 | return(0); |
883 | } | 889 | } |
884 | err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, | 890 | err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, |
885 | SA_INTERRUPT, "ubd", ubd_dev); | 891 | SA_INTERRUPT, "ubd", ubd_dev); |
886 | if(err != 0) | 892 | if(err != 0) |
887 | printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); | 893 | printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); |
@@ -978,7 +984,7 @@ static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, | |||
978 | if(req->op == UBD_READ) { | 984 | if(req->op == UBD_READ) { |
979 | for(i = 0; i < req->length >> 9; i++){ | 985 | for(i = 0; i < req->length >> 9; i++){ |
980 | if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) | 986 | if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) |
981 | ubd_set_bit(i, (unsigned char *) | 987 | ubd_set_bit(i, (unsigned char *) |
982 | &req->sector_mask); | 988 | &req->sector_mask); |
983 | } | 989 | } |
984 | } | 990 | } |
@@ -999,7 +1005,7 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req) | |||
999 | 1005 | ||
1000 | /* This should be impossible now */ | 1006 | /* This should be impossible now */ |
1001 | if((rq_data_dir(req) == WRITE) && !dev->openflags.w){ | 1007 | if((rq_data_dir(req) == WRITE) && !dev->openflags.w){ |
1002 | printk("Write attempted on readonly ubd device %s\n", | 1008 | printk("Write attempted on readonly ubd device %s\n", |
1003 | disk->disk_name); | 1009 | disk->disk_name); |
1004 | end_request(req, 0); | 1010 | end_request(req, 0); |
1005 | return(1); | 1011 | return(1); |
@@ -1182,7 +1188,7 @@ int read_cow_bitmap(int fd, void *buf, int offset, int len) | |||
1182 | return(0); | 1188 | return(0); |
1183 | } | 1189 | } |
1184 | 1190 | ||
1185 | int open_ubd_file(char *file, struct openflags *openflags, | 1191 | int open_ubd_file(char *file, struct openflags *openflags, int shared, |
1186 | char **backing_file_out, int *bitmap_offset_out, | 1192 | char **backing_file_out, int *bitmap_offset_out, |
1187 | unsigned long *bitmap_len_out, int *data_offset_out, | 1193 | unsigned long *bitmap_len_out, int *data_offset_out, |
1188 | int *create_cow_out) | 1194 | int *create_cow_out) |
@@ -1206,10 +1212,14 @@ int open_ubd_file(char *file, struct openflags *openflags, | |||
1206 | return fd; | 1212 | return fd; |
1207 | } | 1213 | } |
1208 | 1214 | ||
1209 | err = os_lock_file(fd, openflags->w); | 1215 | if(shared) |
1210 | if(err < 0){ | 1216 | printk("Not locking \"%s\" on the host\n", file); |
1211 | printk("Failed to lock '%s', err = %d\n", file, -err); | 1217 | else { |
1212 | goto out_close; | 1218 | err = os_lock_file(fd, openflags->w); |
1219 | if(err < 0){ | ||
1220 | printk("Failed to lock '%s', err = %d\n", file, -err); | ||
1221 | goto out_close; | ||
1222 | } | ||
1213 | } | 1223 | } |
1214 | 1224 | ||
1215 | /* Succesful return case! */ | 1225 | /* Succesful return case! */ |
@@ -1260,7 +1270,7 @@ int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, | |||
1260 | int err, fd; | 1270 | int err, fd; |
1261 | 1271 | ||
1262 | flags.c = 1; | 1272 | flags.c = 1; |
1263 | fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL); | 1273 | fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL); |
1264 | if(fd < 0){ | 1274 | if(fd < 0){ |
1265 | err = fd; | 1275 | err = fd; |
1266 | printk("Open of COW file '%s' failed, errno = %d\n", cow_file, | 1276 | printk("Open of COW file '%s' failed, errno = %d\n", cow_file, |
diff --git a/arch/um/include/irq_user.h b/arch/um/include/irq_user.h index b61deb8b362a..69a93c804f0e 100644 --- a/arch/um/include/irq_user.h +++ b/arch/um/include/irq_user.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
@@ -6,6 +6,17 @@ | |||
6 | #ifndef __IRQ_USER_H__ | 6 | #ifndef __IRQ_USER_H__ |
7 | #define __IRQ_USER_H__ | 7 | #define __IRQ_USER_H__ |
8 | 8 | ||
9 | struct irq_fd { | ||
10 | struct irq_fd *next; | ||
11 | void *id; | ||
12 | int fd; | ||
13 | int type; | ||
14 | int irq; | ||
15 | int pid; | ||
16 | int events; | ||
17 | int current_events; | ||
18 | }; | ||
19 | |||
9 | enum { IRQ_READ, IRQ_WRITE }; | 20 | enum { IRQ_READ, IRQ_WRITE }; |
10 | 21 | ||
11 | extern void sigio_handler(int sig, union uml_pt_regs *regs); | 22 | extern void sigio_handler(int sig, union uml_pt_regs *regs); |
@@ -16,8 +27,6 @@ extern void reactivate_fd(int fd, int irqnum); | |||
16 | extern void deactivate_fd(int fd, int irqnum); | 27 | extern void deactivate_fd(int fd, int irqnum); |
17 | extern int deactivate_all_fds(void); | 28 | extern int deactivate_all_fds(void); |
18 | extern void forward_interrupts(int pid); | 29 | extern void forward_interrupts(int pid); |
19 | extern void init_irq_signals(int on_sigstack); | ||
20 | extern void forward_ipi(int fd, int pid); | ||
21 | extern int activate_ipi(int fd, int pid); | 30 | extern int activate_ipi(int fd, int pid); |
22 | extern unsigned long irq_lock(void); | 31 | extern unsigned long irq_lock(void); |
23 | extern void irq_unlock(unsigned long flags); | 32 | extern void irq_unlock(unsigned long flags); |
diff --git a/arch/um/include/kern.h b/arch/um/include/kern.h index 7d223beccbc0..4ce3fc650e57 100644 --- a/arch/um/include/kern.h +++ b/arch/um/include/kern.h | |||
@@ -29,7 +29,7 @@ extern int getuid(void); | |||
29 | extern int getgid(void); | 29 | extern int getgid(void); |
30 | extern int pause(void); | 30 | extern int pause(void); |
31 | extern int write(int, const void *, int); | 31 | extern int write(int, const void *, int); |
32 | extern int exit(int); | 32 | extern void exit(int); |
33 | extern int close(int); | 33 | extern int close(int); |
34 | extern int read(unsigned int, char *, int); | 34 | extern int read(unsigned int, char *, int); |
35 | extern int pipe(int *); | 35 | extern int pipe(int *); |
diff --git a/arch/um/include/misc_constants.h b/arch/um/include/misc_constants.h new file mode 100644 index 000000000000..989bc08de36e --- /dev/null +++ b/arch/um/include/misc_constants.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef __MISC_CONSTANT_H_ | ||
2 | #define __MISC_CONSTANT_H_ | ||
3 | |||
4 | #include <user_constants.h> | ||
5 | |||
6 | #endif | ||
diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 2a1c64d8d0bf..d3d1bc6074ef 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h | |||
@@ -12,6 +12,7 @@ | |||
12 | #include "sysdep/ptrace.h" | 12 | #include "sysdep/ptrace.h" |
13 | #include "kern_util.h" | 13 | #include "kern_util.h" |
14 | #include "skas/mm_id.h" | 14 | #include "skas/mm_id.h" |
15 | #include "irq_user.h" | ||
15 | 16 | ||
16 | #define OS_TYPE_FILE 1 | 17 | #define OS_TYPE_FILE 1 |
17 | #define OS_TYPE_DIR 2 | 18 | #define OS_TYPE_DIR 2 |
@@ -121,6 +122,7 @@ static inline struct openflags of_cloexec(struct openflags flags) | |||
121 | return(flags); | 122 | return(flags); |
122 | } | 123 | } |
123 | 124 | ||
125 | /* file.c */ | ||
124 | extern int os_stat_file(const char *file_name, struct uml_stat *buf); | 126 | extern int os_stat_file(const char *file_name, struct uml_stat *buf); |
125 | extern int os_stat_fd(const int fd, struct uml_stat *buf); | 127 | extern int os_stat_fd(const int fd, struct uml_stat *buf); |
126 | extern int os_access(const char *file, int mode); | 128 | extern int os_access(const char *file, int mode); |
@@ -156,10 +158,20 @@ extern int os_connect_socket(char *name); | |||
156 | extern int os_file_type(char *file); | 158 | extern int os_file_type(char *file); |
157 | extern int os_file_mode(char *file, struct openflags *mode_out); | 159 | extern int os_file_mode(char *file, struct openflags *mode_out); |
158 | extern int os_lock_file(int fd, int excl); | 160 | extern int os_lock_file(int fd, int excl); |
161 | extern void os_flush_stdout(void); | ||
162 | extern int os_stat_filesystem(char *path, long *bsize_out, | ||
163 | long long *blocks_out, long long *bfree_out, | ||
164 | long long *bavail_out, long long *files_out, | ||
165 | long long *ffree_out, void *fsid_out, | ||
166 | int fsid_size, long *namelen_out, | ||
167 | long *spare_out); | ||
168 | extern int os_change_dir(char *dir); | ||
169 | extern int os_fchange_dir(int fd); | ||
159 | 170 | ||
160 | /* start_up.c */ | 171 | /* start_up.c */ |
161 | extern void os_early_checks(void); | 172 | extern void os_early_checks(void); |
162 | extern int can_do_skas(void); | 173 | extern int can_do_skas(void); |
174 | extern void os_check_bugs(void); | ||
163 | 175 | ||
164 | /* Make sure they are clear when running in TT mode. Required by | 176 | /* Make sure they are clear when running in TT mode. Required by |
165 | * SEGV_MAYBE_FIXABLE */ | 177 | * SEGV_MAYBE_FIXABLE */ |
@@ -198,6 +210,8 @@ extern void os_flush_stdout(void); | |||
198 | /* tt.c | 210 | /* tt.c |
199 | * for tt mode only (will be deleted in future...) | 211 | * for tt mode only (will be deleted in future...) |
200 | */ | 212 | */ |
213 | extern void forward_ipi(int fd, int pid); | ||
214 | extern void kill_child_dead(int pid); | ||
201 | extern void stop(void); | 215 | extern void stop(void); |
202 | extern int wait_for_stop(int pid, int sig, int cont_type, void *relay); | 216 | extern int wait_for_stop(int pid, int sig, int cont_type, void *relay); |
203 | extern int protect_memory(unsigned long addr, unsigned long len, | 217 | extern int protect_memory(unsigned long addr, unsigned long len, |
@@ -294,4 +308,26 @@ extern void initial_thread_cb_skas(void (*proc)(void *), | |||
294 | extern void halt_skas(void); | 308 | extern void halt_skas(void); |
295 | extern void reboot_skas(void); | 309 | extern void reboot_skas(void); |
296 | 310 | ||
311 | /* irq.c */ | ||
312 | extern int os_waiting_for_events(struct irq_fd *active_fds); | ||
313 | extern int os_isatty(int fd); | ||
314 | extern int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds); | ||
315 | extern void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg, | ||
316 | struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2); | ||
317 | extern void os_free_irq_later(struct irq_fd *active_fds, | ||
318 | int irq, void *dev_id); | ||
319 | extern int os_get_pollfd(int i); | ||
320 | extern void os_set_pollfd(int i, int fd); | ||
321 | extern void os_set_ioignore(void); | ||
322 | extern void init_irq_signals(int on_sigstack); | ||
323 | |||
324 | /* sigio.c */ | ||
325 | extern void write_sigio_workaround(void); | ||
326 | extern int add_sigio_fd(int fd, int read); | ||
327 | extern int ignore_sigio_fd(int fd); | ||
328 | |||
329 | /* skas/trap */ | ||
330 | extern void sig_handler_common_skas(int sig, void *sc_ptr); | ||
331 | extern void user_signal(int sig, union uml_pt_regs *regs, int pid); | ||
332 | |||
297 | #endif | 333 | #endif |
diff --git a/arch/um/include/sigio.h b/arch/um/include/sigio.h index 37d76e29a147..fe99ea163c2e 100644 --- a/arch/um/include/sigio.h +++ b/arch/um/include/sigio.h | |||
@@ -8,9 +8,6 @@ | |||
8 | 8 | ||
9 | extern int write_sigio_irq(int fd); | 9 | extern int write_sigio_irq(int fd); |
10 | extern int register_sigio_fd(int fd); | 10 | extern int register_sigio_fd(int fd); |
11 | extern int read_sigio_fd(int fd); | ||
12 | extern int add_sigio_fd(int fd, int read); | ||
13 | extern int ignore_sigio_fd(int fd); | ||
14 | extern void sigio_lock(void); | 11 | extern void sigio_lock(void); |
15 | extern void sigio_unlock(void); | 12 | extern void sigio_unlock(void); |
16 | 13 | ||
diff --git a/arch/um/include/skas/mode-skas.h b/arch/um/include/skas/mode-skas.h index 260065cfeef1..8bc6916bbbb1 100644 --- a/arch/um/include/skas/mode-skas.h +++ b/arch/um/include/skas/mode-skas.h | |||
@@ -13,7 +13,6 @@ extern unsigned long exec_fp_regs[]; | |||
13 | extern unsigned long exec_fpx_regs[]; | 13 | extern unsigned long exec_fpx_regs[]; |
14 | extern int have_fpx_regs; | 14 | extern int have_fpx_regs; |
15 | 15 | ||
16 | extern void sig_handler_common_skas(int sig, void *sc_ptr); | ||
17 | extern void kill_off_processes_skas(void); | 16 | extern void kill_off_processes_skas(void); |
18 | 17 | ||
19 | #endif | 18 | #endif |
diff --git a/arch/um/include/skas/skas.h b/arch/um/include/skas/skas.h index 86357282d681..853b26f148c5 100644 --- a/arch/um/include/skas/skas.h +++ b/arch/um/include/skas/skas.h | |||
@@ -17,7 +17,6 @@ extern int user_thread(unsigned long stack, int flags); | |||
17 | extern void new_thread_proc(void *stack, void (*handler)(int sig)); | 17 | extern void new_thread_proc(void *stack, void (*handler)(int sig)); |
18 | extern void new_thread_handler(int sig); | 18 | extern void new_thread_handler(int sig); |
19 | extern void handle_syscall(union uml_pt_regs *regs); | 19 | extern void handle_syscall(union uml_pt_regs *regs); |
20 | extern void user_signal(int sig, union uml_pt_regs *regs, int pid); | ||
21 | extern int new_mm(unsigned long stack); | 20 | extern int new_mm(unsigned long stack); |
22 | extern void get_skas_faultinfo(int pid, struct faultinfo * fi); | 21 | extern void get_skas_faultinfo(int pid, struct faultinfo * fi); |
23 | extern long execute_syscall_skas(void *r); | 22 | extern long execute_syscall_skas(void *r); |
diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h index a6f1f176cf84..992a7e1e0fca 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h | |||
@@ -58,7 +58,6 @@ extern int attach(int pid); | |||
58 | extern void kill_child_dead(int pid); | 58 | extern void kill_child_dead(int pid); |
59 | extern int cont(int pid); | 59 | extern int cont(int pid); |
60 | extern void check_sigio(void); | 60 | extern void check_sigio(void); |
61 | extern void write_sigio_workaround(void); | ||
62 | extern void arch_check_bugs(void); | 61 | extern void arch_check_bugs(void); |
63 | extern int cpu_feature(char *what, char *buf, int len); | 62 | extern int cpu_feature(char *what, char *buf, int len); |
64 | extern int arch_handle_signal(int sig, union uml_pt_regs *regs); | 63 | extern int arch_handle_signal(int sig, union uml_pt_regs *regs); |
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 693018ba80f1..fe08971b64cf 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile | |||
@@ -7,23 +7,20 @@ extra-y := vmlinux.lds | |||
7 | clean-files := | 7 | clean-files := |
8 | 8 | ||
9 | obj-y = config.o exec_kern.o exitcode.o \ | 9 | obj-y = config.o exec_kern.o exitcode.o \ |
10 | init_task.o irq.o irq_user.o ksyms.o mem.o physmem.o \ | 10 | init_task.o irq.o ksyms.o mem.o physmem.o \ |
11 | process_kern.o ptrace.o reboot.o resource.o sigio_user.o sigio_kern.o \ | 11 | process_kern.o ptrace.o reboot.o resource.o sigio_kern.o \ |
12 | signal_kern.o smp.o syscall_kern.o sysrq.o \ | 12 | signal_kern.o smp.o syscall_kern.o sysrq.o \ |
13 | time_kern.o tlb.o trap_kern.o uaccess.o um_arch.o umid.o | 13 | time_kern.o tlb.o trap_kern.o uaccess.o um_arch.o umid.o |
14 | 14 | ||
15 | obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o | 15 | obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o |
16 | obj-$(CONFIG_GPROF) += gprof_syms.o | 16 | obj-$(CONFIG_GPROF) += gprof_syms.o |
17 | obj-$(CONFIG_GCOV) += gmon_syms.o | 17 | obj-$(CONFIG_GCOV) += gmon_syms.o |
18 | obj-$(CONFIG_TTY_LOG) += tty_log.o | ||
19 | obj-$(CONFIG_SYSCALL_DEBUG) += syscall.o | 18 | obj-$(CONFIG_SYSCALL_DEBUG) += syscall.o |
20 | 19 | ||
21 | obj-$(CONFIG_MODE_TT) += tt/ | 20 | obj-$(CONFIG_MODE_TT) += tt/ |
22 | obj-$(CONFIG_MODE_SKAS) += skas/ | 21 | obj-$(CONFIG_MODE_SKAS) += skas/ |
23 | 22 | ||
24 | user-objs-$(CONFIG_TTY_LOG) += tty_log.o | 23 | USER_OBJS := config.o |
25 | |||
26 | USER_OBJS := $(user-objs-y) config.o tty_log.o | ||
27 | 24 | ||
28 | include arch/um/scripts/Makefile.rules | 25 | include arch/um/scripts/Makefile.rules |
29 | 26 | ||
diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c index c264e1c05ab3..1ca84319317d 100644 --- a/arch/um/kernel/exec_kern.c +++ b/arch/um/kernel/exec_kern.c | |||
@@ -30,8 +30,6 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) | |||
30 | CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp); | 30 | CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp); |
31 | } | 31 | } |
32 | 32 | ||
33 | extern void log_exec(char **argv, void *tty); | ||
34 | |||
35 | static long execve1(char *file, char __user * __user *argv, | 33 | static long execve1(char *file, char __user * __user *argv, |
36 | char __user *__user *env) | 34 | char __user *__user *env) |
37 | { | 35 | { |
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index bbf94bf2921e..c39ea3abeda4 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c | |||
@@ -31,6 +31,8 @@ | |||
31 | #include "irq_user.h" | 31 | #include "irq_user.h" |
32 | #include "irq_kern.h" | 32 | #include "irq_kern.h" |
33 | #include "os.h" | 33 | #include "os.h" |
34 | #include "sigio.h" | ||
35 | #include "misc_constants.h" | ||
34 | 36 | ||
35 | /* | 37 | /* |
36 | * Generic, controller-independent functions: | 38 | * Generic, controller-independent functions: |
@@ -77,6 +79,298 @@ skip: | |||
77 | return 0; | 79 | return 0; |
78 | } | 80 | } |
79 | 81 | ||
82 | struct irq_fd *active_fds = NULL; | ||
83 | static struct irq_fd **last_irq_ptr = &active_fds; | ||
84 | |||
85 | extern void free_irqs(void); | ||
86 | |||
87 | void sigio_handler(int sig, union uml_pt_regs *regs) | ||
88 | { | ||
89 | struct irq_fd *irq_fd; | ||
90 | int n; | ||
91 | |||
92 | if(smp_sigio_handler()) return; | ||
93 | while(1){ | ||
94 | n = os_waiting_for_events(active_fds); | ||
95 | if (n <= 0) { | ||
96 | if(n == -EINTR) continue; | ||
97 | else break; | ||
98 | } | ||
99 | |||
100 | for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ | ||
101 | if(irq_fd->current_events != 0){ | ||
102 | irq_fd->current_events = 0; | ||
103 | do_IRQ(irq_fd->irq, regs); | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | |||
108 | free_irqs(); | ||
109 | } | ||
110 | |||
111 | static void maybe_sigio_broken(int fd, int type) | ||
112 | { | ||
113 | if(os_isatty(fd)){ | ||
114 | if((type == IRQ_WRITE) && !pty_output_sigio){ | ||
115 | write_sigio_workaround(); | ||
116 | add_sigio_fd(fd, 0); | ||
117 | } | ||
118 | else if((type == IRQ_READ) && !pty_close_sigio){ | ||
119 | write_sigio_workaround(); | ||
120 | add_sigio_fd(fd, 1); | ||
121 | } | ||
122 | } | ||
123 | } | ||
124 | |||
125 | |||
126 | int activate_fd(int irq, int fd, int type, void *dev_id) | ||
127 | { | ||
128 | struct pollfd *tmp_pfd; | ||
129 | struct irq_fd *new_fd, *irq_fd; | ||
130 | unsigned long flags; | ||
131 | int pid, events, err, n; | ||
132 | |||
133 | pid = os_getpid(); | ||
134 | err = os_set_fd_async(fd, pid); | ||
135 | if(err < 0) | ||
136 | goto out; | ||
137 | |||
138 | new_fd = um_kmalloc(sizeof(*new_fd)); | ||
139 | err = -ENOMEM; | ||
140 | if(new_fd == NULL) | ||
141 | goto out; | ||
142 | |||
143 | if(type == IRQ_READ) events = UM_POLLIN | UM_POLLPRI; | ||
144 | else events = UM_POLLOUT; | ||
145 | *new_fd = ((struct irq_fd) { .next = NULL, | ||
146 | .id = dev_id, | ||
147 | .fd = fd, | ||
148 | .type = type, | ||
149 | .irq = irq, | ||
150 | .pid = pid, | ||
151 | .events = events, | ||
152 | .current_events = 0 } ); | ||
153 | |||
154 | /* Critical section - locked by a spinlock because this stuff can | ||
155 | * be changed from interrupt handlers. The stuff above is done | ||
156 | * outside the lock because it allocates memory. | ||
157 | */ | ||
158 | |||
159 | /* Actually, it only looks like it can be called from interrupt | ||
160 | * context. The culprit is reactivate_fd, which calls | ||
161 | * maybe_sigio_broken, which calls write_sigio_workaround, | ||
162 | * which calls activate_fd. However, write_sigio_workaround should | ||
163 | * only be called once, at boot time. That would make it clear that | ||
164 | * this is called only from process context, and can be locked with | ||
165 | * a semaphore. | ||
166 | */ | ||
167 | flags = irq_lock(); | ||
168 | for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ | ||
169 | if((irq_fd->fd == fd) && (irq_fd->type == type)){ | ||
170 | printk("Registering fd %d twice\n", fd); | ||
171 | printk("Irqs : %d, %d\n", irq_fd->irq, irq); | ||
172 | printk("Ids : 0x%p, 0x%p\n", irq_fd->id, dev_id); | ||
173 | goto out_unlock; | ||
174 | } | ||
175 | } | ||
176 | |||
177 | /*-------------*/ | ||
178 | if(type == IRQ_WRITE) | ||
179 | fd = -1; | ||
180 | |||
181 | tmp_pfd = NULL; | ||
182 | n = 0; | ||
183 | |||
184 | while(1){ | ||
185 | n = os_create_pollfd(fd, events, tmp_pfd, n); | ||
186 | if (n == 0) | ||
187 | break; | ||
188 | |||
189 | /* n > 0 | ||
190 | * It means we couldn't put new pollfd to current pollfds | ||
191 | * and tmp_fds is NULL or too small for new pollfds array. | ||
192 | * Needed size is equal to n as minimum. | ||
193 | * | ||
194 | * Here we have to drop the lock in order to call | ||
195 | * kmalloc, which might sleep. | ||
196 | * If something else came in and changed the pollfds array | ||
197 | * so we will not be able to put new pollfd struct to pollfds | ||
198 | * then we free the buffer tmp_fds and try again. | ||
199 | */ | ||
200 | irq_unlock(flags); | ||
201 | if (tmp_pfd != NULL) { | ||
202 | kfree(tmp_pfd); | ||
203 | tmp_pfd = NULL; | ||
204 | } | ||
205 | |||
206 | tmp_pfd = um_kmalloc(n); | ||
207 | if (tmp_pfd == NULL) | ||
208 | goto out_kfree; | ||
209 | |||
210 | flags = irq_lock(); | ||
211 | } | ||
212 | /*-------------*/ | ||
213 | |||
214 | *last_irq_ptr = new_fd; | ||
215 | last_irq_ptr = &new_fd->next; | ||
216 | |||
217 | irq_unlock(flags); | ||
218 | |||
219 | /* This calls activate_fd, so it has to be outside the critical | ||
220 | * section. | ||
221 | */ | ||
222 | maybe_sigio_broken(fd, type); | ||
223 | |||
224 | return(0); | ||
225 | |||
226 | out_unlock: | ||
227 | irq_unlock(flags); | ||
228 | out_kfree: | ||
229 | kfree(new_fd); | ||
230 | out: | ||
231 | return(err); | ||
232 | } | ||
233 | |||
234 | static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg) | ||
235 | { | ||
236 | unsigned long flags; | ||
237 | |||
238 | flags = irq_lock(); | ||
239 | os_free_irq_by_cb(test, arg, active_fds, &last_irq_ptr); | ||
240 | irq_unlock(flags); | ||
241 | } | ||
242 | |||
243 | struct irq_and_dev { | ||
244 | int irq; | ||
245 | void *dev; | ||
246 | }; | ||
247 | |||
248 | static int same_irq_and_dev(struct irq_fd *irq, void *d) | ||
249 | { | ||
250 | struct irq_and_dev *data = d; | ||
251 | |||
252 | return((irq->irq == data->irq) && (irq->id == data->dev)); | ||
253 | } | ||
254 | |||
255 | void free_irq_by_irq_and_dev(unsigned int irq, void *dev) | ||
256 | { | ||
257 | struct irq_and_dev data = ((struct irq_and_dev) { .irq = irq, | ||
258 | .dev = dev }); | ||
259 | |||
260 | free_irq_by_cb(same_irq_and_dev, &data); | ||
261 | } | ||
262 | |||
263 | static int same_fd(struct irq_fd *irq, void *fd) | ||
264 | { | ||
265 | return(irq->fd == *((int *) fd)); | ||
266 | } | ||
267 | |||
268 | void free_irq_by_fd(int fd) | ||
269 | { | ||
270 | free_irq_by_cb(same_fd, &fd); | ||
271 | } | ||
272 | |||
273 | static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out) | ||
274 | { | ||
275 | struct irq_fd *irq; | ||
276 | int i = 0; | ||
277 | int fdi; | ||
278 | |||
279 | for(irq=active_fds; irq != NULL; irq = irq->next){ | ||
280 | if((irq->fd == fd) && (irq->irq == irqnum)) break; | ||
281 | i++; | ||
282 | } | ||
283 | if(irq == NULL){ | ||
284 | printk("find_irq_by_fd doesn't have descriptor %d\n", fd); | ||
285 | goto out; | ||
286 | } | ||
287 | fdi = os_get_pollfd(i); | ||
288 | if((fdi != -1) && (fdi != fd)){ | ||
289 | printk("find_irq_by_fd - mismatch between active_fds and " | ||
290 | "pollfds, fd %d vs %d, need %d\n", irq->fd, | ||
291 | fdi, fd); | ||
292 | irq = NULL; | ||
293 | goto out; | ||
294 | } | ||
295 | *index_out = i; | ||
296 | out: | ||
297 | return(irq); | ||
298 | } | ||
299 | |||
300 | void reactivate_fd(int fd, int irqnum) | ||
301 | { | ||
302 | struct irq_fd *irq; | ||
303 | unsigned long flags; | ||
304 | int i; | ||
305 | |||
306 | flags = irq_lock(); | ||
307 | irq = find_irq_by_fd(fd, irqnum, &i); | ||
308 | if(irq == NULL){ | ||
309 | irq_unlock(flags); | ||
310 | return; | ||
311 | } | ||
312 | os_set_pollfd(i, irq->fd); | ||
313 | irq_unlock(flags); | ||
314 | |||
315 | /* This calls activate_fd, so it has to be outside the critical | ||
316 | * section. | ||
317 | */ | ||
318 | maybe_sigio_broken(fd, irq->type); | ||
319 | } | ||
320 | |||
321 | void deactivate_fd(int fd, int irqnum) | ||
322 | { | ||
323 | struct irq_fd *irq; | ||
324 | unsigned long flags; | ||
325 | int i; | ||
326 | |||
327 | flags = irq_lock(); | ||
328 | irq = find_irq_by_fd(fd, irqnum, &i); | ||
329 | if(irq == NULL) | ||
330 | goto out; | ||
331 | os_set_pollfd(i, -1); | ||
332 | out: | ||
333 | irq_unlock(flags); | ||
334 | } | ||
335 | |||
336 | int deactivate_all_fds(void) | ||
337 | { | ||
338 | struct irq_fd *irq; | ||
339 | int err; | ||
340 | |||
341 | for(irq=active_fds;irq != NULL;irq = irq->next){ | ||
342 | err = os_clear_fd_async(irq->fd); | ||
343 | if(err) | ||
344 | return(err); | ||
345 | } | ||
346 | /* If there is a signal already queued, after unblocking ignore it */ | ||
347 | os_set_ioignore(); | ||
348 | |||
349 | return(0); | ||
350 | } | ||
351 | |||
352 | void forward_interrupts(int pid) | ||
353 | { | ||
354 | struct irq_fd *irq; | ||
355 | unsigned long flags; | ||
356 | int err; | ||
357 | |||
358 | flags = irq_lock(); | ||
359 | for(irq=active_fds;irq != NULL;irq = irq->next){ | ||
360 | err = os_set_owner(irq->fd, pid); | ||
361 | if(err < 0){ | ||
362 | /* XXX Just remove the irq rather than | ||
363 | * print out an infinite stream of these | ||
364 | */ | ||
365 | printk("Failed to forward %d to pid %d, err = %d\n", | ||
366 | irq->fd, pid, -err); | ||
367 | } | ||
368 | |||
369 | irq->pid = pid; | ||
370 | } | ||
371 | irq_unlock(flags); | ||
372 | } | ||
373 | |||
80 | /* | 374 | /* |
81 | * do_IRQ handles all normal device IRQ's (the special | 375 | * do_IRQ handles all normal device IRQ's (the special |
82 | * SMP cross-CPU interrupts have their own specific | 376 | * SMP cross-CPU interrupts have their own specific |
diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c deleted file mode 100644 index 0e32f5f4a887..000000000000 --- a/arch/um/kernel/irq_user.c +++ /dev/null | |||
@@ -1,412 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include <stdlib.h> | ||
7 | #include <unistd.h> | ||
8 | #include <errno.h> | ||
9 | #include <signal.h> | ||
10 | #include <string.h> | ||
11 | #include <sys/poll.h> | ||
12 | #include <sys/types.h> | ||
13 | #include <sys/time.h> | ||
14 | #include "user_util.h" | ||
15 | #include "kern_util.h" | ||
16 | #include "user.h" | ||
17 | #include "process.h" | ||
18 | #include "sigio.h" | ||
19 | #include "irq_user.h" | ||
20 | #include "os.h" | ||
21 | |||
22 | struct irq_fd { | ||
23 | struct irq_fd *next; | ||
24 | void *id; | ||
25 | int fd; | ||
26 | int type; | ||
27 | int irq; | ||
28 | int pid; | ||
29 | int events; | ||
30 | int current_events; | ||
31 | }; | ||
32 | |||
33 | static struct irq_fd *active_fds = NULL; | ||
34 | static struct irq_fd **last_irq_ptr = &active_fds; | ||
35 | |||
36 | static struct pollfd *pollfds = NULL; | ||
37 | static int pollfds_num = 0; | ||
38 | static int pollfds_size = 0; | ||
39 | |||
40 | extern int io_count, intr_count; | ||
41 | |||
42 | extern void free_irqs(void); | ||
43 | |||
44 | void sigio_handler(int sig, union uml_pt_regs *regs) | ||
45 | { | ||
46 | struct irq_fd *irq_fd; | ||
47 | int i, n; | ||
48 | |||
49 | if(smp_sigio_handler()) return; | ||
50 | while(1){ | ||
51 | n = poll(pollfds, pollfds_num, 0); | ||
52 | if(n < 0){ | ||
53 | if(errno == EINTR) continue; | ||
54 | printk("sigio_handler : poll returned %d, " | ||
55 | "errno = %d\n", n, errno); | ||
56 | break; | ||
57 | } | ||
58 | if(n == 0) break; | ||
59 | |||
60 | irq_fd = active_fds; | ||
61 | for(i = 0; i < pollfds_num; i++){ | ||
62 | if(pollfds[i].revents != 0){ | ||
63 | irq_fd->current_events = pollfds[i].revents; | ||
64 | pollfds[i].fd = -1; | ||
65 | } | ||
66 | irq_fd = irq_fd->next; | ||
67 | } | ||
68 | |||
69 | for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ | ||
70 | if(irq_fd->current_events != 0){ | ||
71 | irq_fd->current_events = 0; | ||
72 | do_IRQ(irq_fd->irq, regs); | ||
73 | } | ||
74 | } | ||
75 | } | ||
76 | |||
77 | free_irqs(); | ||
78 | } | ||
79 | |||
80 | int activate_ipi(int fd, int pid) | ||
81 | { | ||
82 | return(os_set_fd_async(fd, pid)); | ||
83 | } | ||
84 | |||
85 | static void maybe_sigio_broken(int fd, int type) | ||
86 | { | ||
87 | if(isatty(fd)){ | ||
88 | if((type == IRQ_WRITE) && !pty_output_sigio){ | ||
89 | write_sigio_workaround(); | ||
90 | add_sigio_fd(fd, 0); | ||
91 | } | ||
92 | else if((type == IRQ_READ) && !pty_close_sigio){ | ||
93 | write_sigio_workaround(); | ||
94 | add_sigio_fd(fd, 1); | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | |||
99 | int activate_fd(int irq, int fd, int type, void *dev_id) | ||
100 | { | ||
101 | struct pollfd *tmp_pfd; | ||
102 | struct irq_fd *new_fd, *irq_fd; | ||
103 | unsigned long flags; | ||
104 | int pid, events, err, n, size; | ||
105 | |||
106 | pid = os_getpid(); | ||
107 | err = os_set_fd_async(fd, pid); | ||
108 | if(err < 0) | ||
109 | goto out; | ||
110 | |||
111 | new_fd = um_kmalloc(sizeof(*new_fd)); | ||
112 | err = -ENOMEM; | ||
113 | if(new_fd == NULL) | ||
114 | goto out; | ||
115 | |||
116 | if(type == IRQ_READ) events = POLLIN | POLLPRI; | ||
117 | else events = POLLOUT; | ||
118 | *new_fd = ((struct irq_fd) { .next = NULL, | ||
119 | .id = dev_id, | ||
120 | .fd = fd, | ||
121 | .type = type, | ||
122 | .irq = irq, | ||
123 | .pid = pid, | ||
124 | .events = events, | ||
125 | .current_events = 0 } ); | ||
126 | |||
127 | /* Critical section - locked by a spinlock because this stuff can | ||
128 | * be changed from interrupt handlers. The stuff above is done | ||
129 | * outside the lock because it allocates memory. | ||
130 | */ | ||
131 | |||
132 | /* Actually, it only looks like it can be called from interrupt | ||
133 | * context. The culprit is reactivate_fd, which calls | ||
134 | * maybe_sigio_broken, which calls write_sigio_workaround, | ||
135 | * which calls activate_fd. However, write_sigio_workaround should | ||
136 | * only be called once, at boot time. That would make it clear that | ||
137 | * this is called only from process context, and can be locked with | ||
138 | * a semaphore. | ||
139 | */ | ||
140 | flags = irq_lock(); | ||
141 | for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ | ||
142 | if((irq_fd->fd == fd) && (irq_fd->type == type)){ | ||
143 | printk("Registering fd %d twice\n", fd); | ||
144 | printk("Irqs : %d, %d\n", irq_fd->irq, irq); | ||
145 | printk("Ids : 0x%x, 0x%x\n", irq_fd->id, dev_id); | ||
146 | goto out_unlock; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | n = pollfds_num; | ||
151 | if(n == pollfds_size){ | ||
152 | while(1){ | ||
153 | /* Here we have to drop the lock in order to call | ||
154 | * kmalloc, which might sleep. If something else | ||
155 | * came in and changed the pollfds array, we free | ||
156 | * the buffer and try again. | ||
157 | */ | ||
158 | irq_unlock(flags); | ||
159 | size = (pollfds_num + 1) * sizeof(pollfds[0]); | ||
160 | tmp_pfd = um_kmalloc(size); | ||
161 | flags = irq_lock(); | ||
162 | if(tmp_pfd == NULL) | ||
163 | goto out_unlock; | ||
164 | if(n == pollfds_size) | ||
165 | break; | ||
166 | kfree(tmp_pfd); | ||
167 | } | ||
168 | if(pollfds != NULL){ | ||
169 | memcpy(tmp_pfd, pollfds, | ||
170 | sizeof(pollfds[0]) * pollfds_size); | ||
171 | kfree(pollfds); | ||
172 | } | ||
173 | pollfds = tmp_pfd; | ||
174 | pollfds_size++; | ||
175 | } | ||
176 | |||
177 | if(type == IRQ_WRITE) | ||
178 | fd = -1; | ||
179 | |||
180 | pollfds[pollfds_num] = ((struct pollfd) { .fd = fd, | ||
181 | .events = events, | ||
182 | .revents = 0 }); | ||
183 | pollfds_num++; | ||
184 | |||
185 | *last_irq_ptr = new_fd; | ||
186 | last_irq_ptr = &new_fd->next; | ||
187 | |||
188 | irq_unlock(flags); | ||
189 | |||
190 | /* This calls activate_fd, so it has to be outside the critical | ||
191 | * section. | ||
192 | */ | ||
193 | maybe_sigio_broken(fd, type); | ||
194 | |||
195 | return(0); | ||
196 | |||
197 | out_unlock: | ||
198 | irq_unlock(flags); | ||
199 | kfree(new_fd); | ||
200 | out: | ||
201 | return(err); | ||
202 | } | ||
203 | |||
204 | static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg) | ||
205 | { | ||
206 | struct irq_fd **prev; | ||
207 | unsigned long flags; | ||
208 | int i = 0; | ||
209 | |||
210 | flags = irq_lock(); | ||
211 | prev = &active_fds; | ||
212 | while(*prev != NULL){ | ||
213 | if((*test)(*prev, arg)){ | ||
214 | struct irq_fd *old_fd = *prev; | ||
215 | if((pollfds[i].fd != -1) && | ||
216 | (pollfds[i].fd != (*prev)->fd)){ | ||
217 | printk("free_irq_by_cb - mismatch between " | ||
218 | "active_fds and pollfds, fd %d vs %d\n", | ||
219 | (*prev)->fd, pollfds[i].fd); | ||
220 | goto out; | ||
221 | } | ||
222 | |||
223 | pollfds_num--; | ||
224 | |||
225 | /* This moves the *whole* array after pollfds[i] (though | ||
226 | * it doesn't spot as such)! */ | ||
227 | |||
228 | memmove(&pollfds[i], &pollfds[i + 1], | ||
229 | (pollfds_num - i) * sizeof(pollfds[0])); | ||
230 | |||
231 | if(last_irq_ptr == &old_fd->next) | ||
232 | last_irq_ptr = prev; | ||
233 | *prev = (*prev)->next; | ||
234 | if(old_fd->type == IRQ_WRITE) | ||
235 | ignore_sigio_fd(old_fd->fd); | ||
236 | kfree(old_fd); | ||
237 | continue; | ||
238 | } | ||
239 | prev = &(*prev)->next; | ||
240 | i++; | ||
241 | } | ||
242 | out: | ||
243 | irq_unlock(flags); | ||
244 | } | ||
245 | |||
246 | struct irq_and_dev { | ||
247 | int irq; | ||
248 | void *dev; | ||
249 | }; | ||
250 | |||
251 | static int same_irq_and_dev(struct irq_fd *irq, void *d) | ||
252 | { | ||
253 | struct irq_and_dev *data = d; | ||
254 | |||
255 | return((irq->irq == data->irq) && (irq->id == data->dev)); | ||
256 | } | ||
257 | |||
258 | void free_irq_by_irq_and_dev(unsigned int irq, void *dev) | ||
259 | { | ||
260 | struct irq_and_dev data = ((struct irq_and_dev) { .irq = irq, | ||
261 | .dev = dev }); | ||
262 | |||
263 | free_irq_by_cb(same_irq_and_dev, &data); | ||
264 | } | ||
265 | |||
266 | static int same_fd(struct irq_fd *irq, void *fd) | ||
267 | { | ||
268 | return(irq->fd == *((int *) fd)); | ||
269 | } | ||
270 | |||
271 | void free_irq_by_fd(int fd) | ||
272 | { | ||
273 | free_irq_by_cb(same_fd, &fd); | ||
274 | } | ||
275 | |||
276 | static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out) | ||
277 | { | ||
278 | struct irq_fd *irq; | ||
279 | int i = 0; | ||
280 | |||
281 | for(irq=active_fds; irq != NULL; irq = irq->next){ | ||
282 | if((irq->fd == fd) && (irq->irq == irqnum)) break; | ||
283 | i++; | ||
284 | } | ||
285 | if(irq == NULL){ | ||
286 | printk("find_irq_by_fd doesn't have descriptor %d\n", fd); | ||
287 | goto out; | ||
288 | } | ||
289 | if((pollfds[i].fd != -1) && (pollfds[i].fd != fd)){ | ||
290 | printk("find_irq_by_fd - mismatch between active_fds and " | ||
291 | "pollfds, fd %d vs %d, need %d\n", irq->fd, | ||
292 | pollfds[i].fd, fd); | ||
293 | irq = NULL; | ||
294 | goto out; | ||
295 | } | ||
296 | *index_out = i; | ||
297 | out: | ||
298 | return(irq); | ||
299 | } | ||
300 | |||
301 | void reactivate_fd(int fd, int irqnum) | ||
302 | { | ||
303 | struct irq_fd *irq; | ||
304 | unsigned long flags; | ||
305 | int i; | ||
306 | |||
307 | flags = irq_lock(); | ||
308 | irq = find_irq_by_fd(fd, irqnum, &i); | ||
309 | if(irq == NULL){ | ||
310 | irq_unlock(flags); | ||
311 | return; | ||
312 | } | ||
313 | |||
314 | pollfds[i].fd = irq->fd; | ||
315 | |||
316 | irq_unlock(flags); | ||
317 | |||
318 | /* This calls activate_fd, so it has to be outside the critical | ||
319 | * section. | ||
320 | */ | ||
321 | maybe_sigio_broken(fd, irq->type); | ||
322 | } | ||
323 | |||
324 | void deactivate_fd(int fd, int irqnum) | ||
325 | { | ||
326 | struct irq_fd *irq; | ||
327 | unsigned long flags; | ||
328 | int i; | ||
329 | |||
330 | flags = irq_lock(); | ||
331 | irq = find_irq_by_fd(fd, irqnum, &i); | ||
332 | if(irq == NULL) | ||
333 | goto out; | ||
334 | pollfds[i].fd = -1; | ||
335 | out: | ||
336 | irq_unlock(flags); | ||
337 | } | ||
338 | |||
339 | int deactivate_all_fds(void) | ||
340 | { | ||
341 | struct irq_fd *irq; | ||
342 | int err; | ||
343 | |||
344 | for(irq=active_fds;irq != NULL;irq = irq->next){ | ||
345 | err = os_clear_fd_async(irq->fd); | ||
346 | if(err) | ||
347 | return(err); | ||
348 | } | ||
349 | /* If there is a signal already queued, after unblocking ignore it */ | ||
350 | set_handler(SIGIO, SIG_IGN, 0, -1); | ||
351 | |||
352 | return(0); | ||
353 | } | ||
354 | |||
355 | void forward_ipi(int fd, int pid) | ||
356 | { | ||
357 | int err; | ||
358 | |||
359 | err = os_set_owner(fd, pid); | ||
360 | if(err < 0) | ||
361 | printk("forward_ipi: set_owner failed, fd = %d, me = %d, " | ||
362 | "target = %d, err = %d\n", fd, os_getpid(), pid, -err); | ||
363 | } | ||
364 | |||
365 | void forward_interrupts(int pid) | ||
366 | { | ||
367 | struct irq_fd *irq; | ||
368 | unsigned long flags; | ||
369 | int err; | ||
370 | |||
371 | flags = irq_lock(); | ||
372 | for(irq=active_fds;irq != NULL;irq = irq->next){ | ||
373 | err = os_set_owner(irq->fd, pid); | ||
374 | if(err < 0){ | ||
375 | /* XXX Just remove the irq rather than | ||
376 | * print out an infinite stream of these | ||
377 | */ | ||
378 | printk("Failed to forward %d to pid %d, err = %d\n", | ||
379 | irq->fd, pid, -err); | ||
380 | } | ||
381 | |||
382 | irq->pid = pid; | ||
383 | } | ||
384 | irq_unlock(flags); | ||
385 | } | ||
386 | |||
387 | void init_irq_signals(int on_sigstack) | ||
388 | { | ||
389 | __sighandler_t h; | ||
390 | int flags; | ||
391 | |||
392 | flags = on_sigstack ? SA_ONSTACK : 0; | ||
393 | if(timer_irq_inited) h = (__sighandler_t) alarm_handler; | ||
394 | else h = boot_timer_handler; | ||
395 | |||
396 | set_handler(SIGVTALRM, h, flags | SA_RESTART, | ||
397 | SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1); | ||
398 | set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART, | ||
399 | SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); | ||
400 | signal(SIGWINCH, SIG_IGN); | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
405 | * Emacs will notice this stuff at the end of the file and automatically | ||
406 | * adjust the settings for this buffer only. This must remain at the end | ||
407 | * of the file. | ||
408 | * --------------------------------------------------------------------------- | ||
409 | * Local variables: | ||
410 | * c-file-style: "linux" | ||
411 | * End: | ||
412 | */ | ||
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index 0e65340eee33..0500800df1c1 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include "linux/vmalloc.h" | 9 | #include "linux/vmalloc.h" |
10 | #include "linux/bootmem.h" | 10 | #include "linux/bootmem.h" |
11 | #include "linux/module.h" | 11 | #include "linux/module.h" |
12 | #include "linux/pfn.h" | ||
12 | #include "asm/types.h" | 13 | #include "asm/types.h" |
13 | #include "asm/pgtable.h" | 14 | #include "asm/pgtable.h" |
14 | #include "kern_util.h" | 15 | #include "kern_util.h" |
@@ -316,8 +317,6 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len, | |||
316 | } | 317 | } |
317 | } | 318 | } |
318 | 319 | ||
319 | #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) | ||
320 | |||
321 | extern int __syscall_stub_start, __binary_start; | 320 | extern int __syscall_stub_start, __binary_start; |
322 | 321 | ||
323 | void setup_physmem(unsigned long start, unsigned long reserve_end, | 322 | void setup_physmem(unsigned long start, unsigned long reserve_end, |
diff --git a/arch/um/kernel/sigio_kern.c b/arch/um/kernel/sigio_kern.c index 229988463c4c..1c1300fb1e95 100644 --- a/arch/um/kernel/sigio_kern.c +++ b/arch/um/kernel/sigio_kern.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) | 2 | * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
@@ -12,13 +12,16 @@ | |||
12 | #include "sigio.h" | 12 | #include "sigio.h" |
13 | #include "irq_user.h" | 13 | #include "irq_user.h" |
14 | #include "irq_kern.h" | 14 | #include "irq_kern.h" |
15 | #include "os.h" | ||
15 | 16 | ||
16 | /* Protected by sigio_lock() called from write_sigio_workaround */ | 17 | /* Protected by sigio_lock() called from write_sigio_workaround */ |
17 | static int sigio_irq_fd = -1; | 18 | static int sigio_irq_fd = -1; |
18 | 19 | ||
19 | static irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused) | 20 | static irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused) |
20 | { | 21 | { |
21 | read_sigio_fd(sigio_irq_fd); | 22 | char c; |
23 | |||
24 | os_read_file(sigio_irq_fd, &c, sizeof(c)); | ||
22 | reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ); | 25 | reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ); |
23 | return(IRQ_HANDLED); | 26 | return(IRQ_HANDLED); |
24 | } | 27 | } |
@@ -51,6 +54,9 @@ void sigio_unlock(void) | |||
51 | spin_unlock(&sigio_spinlock); | 54 | spin_unlock(&sigio_spinlock); |
52 | } | 55 | } |
53 | 56 | ||
57 | extern void sigio_cleanup(void); | ||
58 | __uml_exitcall(sigio_cleanup); | ||
59 | |||
54 | /* | 60 | /* |
55 | * Overrides for Emacs so that we follow Linus's tabbing style. | 61 | * Overrides for Emacs so that we follow Linus's tabbing style. |
56 | * Emacs will notice this stuff at the end of the file and automatically | 62 | * Emacs will notice this stuff at the end of the file and automatically |
diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c index 72113b0a96e7..c8d8d0ac1a7f 100644 --- a/arch/um/kernel/smp.c +++ b/arch/um/kernel/smp.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) | 2 | * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
@@ -77,9 +77,9 @@ static int idle_proc(void *cpup) | |||
77 | if(err < 0) | 77 | if(err < 0) |
78 | panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err); | 78 | panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err); |
79 | 79 | ||
80 | activate_ipi(cpu_data[cpu].ipi_pipe[0], | 80 | os_set_fd_async(cpu_data[cpu].ipi_pipe[0], |
81 | current->thread.mode.tt.extern_pid); | 81 | current->thread.mode.tt.extern_pid); |
82 | 82 | ||
83 | wmb(); | 83 | wmb(); |
84 | if (cpu_test_and_set(cpu, cpu_callin_map)) { | 84 | if (cpu_test_and_set(cpu, cpu_callin_map)) { |
85 | printk("huh, CPU#%d already present??\n", cpu); | 85 | printk("huh, CPU#%d already present??\n", cpu); |
@@ -106,7 +106,7 @@ static struct task_struct *idle_thread(int cpu) | |||
106 | panic("copy_process failed in idle_thread, error = %ld", | 106 | panic("copy_process failed in idle_thread, error = %ld", |
107 | PTR_ERR(new_task)); | 107 | PTR_ERR(new_task)); |
108 | 108 | ||
109 | cpu_tasks[cpu] = ((struct cpu_task) | 109 | cpu_tasks[cpu] = ((struct cpu_task) |
110 | { .pid = new_task->thread.mode.tt.extern_pid, | 110 | { .pid = new_task->thread.mode.tt.extern_pid, |
111 | .task = new_task } ); | 111 | .task = new_task } ); |
112 | idle_threads[cpu] = new_task; | 112 | idle_threads[cpu] = new_task; |
@@ -134,12 +134,12 @@ void smp_prepare_cpus(unsigned int maxcpus) | |||
134 | if(err < 0) | 134 | if(err < 0) |
135 | panic("CPU#0 failed to create IPI pipe, errno = %d", -err); | 135 | panic("CPU#0 failed to create IPI pipe, errno = %d", -err); |
136 | 136 | ||
137 | activate_ipi(cpu_data[me].ipi_pipe[0], | 137 | os_set_fd_async(cpu_data[me].ipi_pipe[0], |
138 | current->thread.mode.tt.extern_pid); | 138 | current->thread.mode.tt.extern_pid); |
139 | 139 | ||
140 | for(cpu = 1; cpu < ncpus; cpu++){ | 140 | for(cpu = 1; cpu < ncpus; cpu++){ |
141 | printk("Booting processor %d...\n", cpu); | 141 | printk("Booting processor %d...\n", cpu); |
142 | 142 | ||
143 | idle = idle_thread(cpu); | 143 | idle = idle_thread(cpu); |
144 | 144 | ||
145 | init_idle(idle, cpu); | 145 | init_idle(idle, cpu); |
@@ -223,7 +223,7 @@ void smp_call_function_slave(int cpu) | |||
223 | atomic_inc(&scf_finished); | 223 | atomic_inc(&scf_finished); |
224 | } | 224 | } |
225 | 225 | ||
226 | int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, | 226 | int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, |
227 | int wait) | 227 | int wait) |
228 | { | 228 | { |
229 | int cpus = num_online_cpus() - 1; | 229 | int cpus = num_online_cpus() - 1; |
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 80c9c18aae94..7d51dd7201c3 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c | |||
@@ -421,7 +421,7 @@ int linux_main(int argc, char **argv) | |||
421 | #ifndef CONFIG_HIGHMEM | 421 | #ifndef CONFIG_HIGHMEM |
422 | highmem = 0; | 422 | highmem = 0; |
423 | printf("CONFIG_HIGHMEM not enabled - physical memory shrunk " | 423 | printf("CONFIG_HIGHMEM not enabled - physical memory shrunk " |
424 | "to %lu bytes\n", physmem_size); | 424 | "to %Lu bytes\n", physmem_size); |
425 | #endif | 425 | #endif |
426 | } | 426 | } |
427 | 427 | ||
@@ -433,8 +433,8 @@ int linux_main(int argc, char **argv) | |||
433 | 433 | ||
434 | setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); | 434 | setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); |
435 | if(init_maps(physmem_size, iomem_size, highmem)){ | 435 | if(init_maps(physmem_size, iomem_size, highmem)){ |
436 | printf("Failed to allocate mem_map for %lu bytes of physical " | 436 | printf("Failed to allocate mem_map for %Lu bytes of physical " |
437 | "memory and %lu bytes of highmem\n", physmem_size, | 437 | "memory and %Lu bytes of highmem\n", physmem_size, |
438 | highmem); | 438 | highmem); |
439 | exit(1); | 439 | exit(1); |
440 | } | 440 | } |
@@ -477,7 +477,8 @@ static struct notifier_block panic_exit_notifier = { | |||
477 | 477 | ||
478 | void __init setup_arch(char **cmdline_p) | 478 | void __init setup_arch(char **cmdline_p) |
479 | { | 479 | { |
480 | notifier_chain_register(&panic_notifier_list, &panic_exit_notifier); | 480 | atomic_notifier_chain_register(&panic_notifier_list, |
481 | &panic_exit_notifier); | ||
481 | paging_init(); | 482 | paging_init(); |
482 | strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); | 483 | strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); |
483 | *cmdline_p = command_line; | 484 | *cmdline_p = command_line; |
@@ -487,8 +488,7 @@ void __init setup_arch(char **cmdline_p) | |||
487 | void __init check_bugs(void) | 488 | void __init check_bugs(void) |
488 | { | 489 | { |
489 | arch_check_bugs(); | 490 | arch_check_bugs(); |
490 | check_sigio(); | 491 | os_check_bugs(); |
491 | check_devanon(); | ||
492 | } | 492 | } |
493 | 493 | ||
494 | void apply_alternatives(struct alt_instr *start, struct alt_instr *end) | 494 | void apply_alternatives(struct alt_instr *start, struct alt_instr *end) |
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index 08a4e628b24c..1659386b42bb 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile | |||
@@ -3,14 +3,17 @@ | |||
3 | # Licensed under the GPL | 3 | # Licensed under the GPL |
4 | # | 4 | # |
5 | 5 | ||
6 | obj-y = aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ | 6 | obj-y = aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o sigio.o \ |
7 | start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o user_syms.o \ | 7 | signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o \ |
8 | util.o drivers/ sys-$(SUBARCH)/ | 8 | user_syms.o util.o drivers/ sys-$(SUBARCH)/ |
9 | 9 | ||
10 | obj-$(CONFIG_MODE_SKAS) += skas/ | 10 | obj-$(CONFIG_MODE_SKAS) += skas/ |
11 | obj-$(CONFIG_TTY_LOG) += tty_log.o | ||
12 | user-objs-$(CONFIG_TTY_LOG) += tty_log.o | ||
11 | 13 | ||
12 | USER_OBJS := aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ | 14 | USER_OBJS := $(user-objs-y) aio.o elf_aux.o file.o helper.o irq.o main.o mem.o \ |
13 | start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o util.o | 15 | process.o sigio.o signal.o start_up.o time.o trap.o tt.o tty.o \ |
16 | uaccess.o umid.o util.o | ||
14 | 17 | ||
15 | elf_aux.o: $(ARCH_DIR)/kernel-offsets.h | 18 | elf_aux.o: $(ARCH_DIR)/kernel-offsets.h |
16 | CFLAGS_elf_aux.o += -I$(objtree)/arch/um | 19 | CFLAGS_elf_aux.o += -I$(objtree)/arch/um |
diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c new file mode 100644 index 000000000000..e599be423da1 --- /dev/null +++ b/arch/um/os-Linux/irq.c | |||
@@ -0,0 +1,162 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include <stdlib.h> | ||
7 | #include <unistd.h> | ||
8 | #include <errno.h> | ||
9 | #include <signal.h> | ||
10 | #include <string.h> | ||
11 | #include <sys/poll.h> | ||
12 | #include <sys/types.h> | ||
13 | #include <sys/time.h> | ||
14 | #include "user_util.h" | ||
15 | #include "kern_util.h" | ||
16 | #include "user.h" | ||
17 | #include "process.h" | ||
18 | #include "sigio.h" | ||
19 | #include "irq_user.h" | ||
20 | #include "os.h" | ||
21 | |||
22 | static struct pollfd *pollfds = NULL; | ||
23 | static int pollfds_num = 0; | ||
24 | static int pollfds_size = 0; | ||
25 | |||
26 | int os_waiting_for_events(struct irq_fd *active_fds) | ||
27 | { | ||
28 | struct irq_fd *irq_fd; | ||
29 | int i, n, err; | ||
30 | |||
31 | n = poll(pollfds, pollfds_num, 0); | ||
32 | if(n < 0){ | ||
33 | err = -errno; | ||
34 | if(errno != EINTR) | ||
35 | printk("sigio_handler: os_waiting_for_events:" | ||
36 | " poll returned %d, errno = %d\n", n, errno); | ||
37 | return err; | ||
38 | } | ||
39 | |||
40 | if(n == 0) | ||
41 | return 0; | ||
42 | |||
43 | irq_fd = active_fds; | ||
44 | |||
45 | for(i = 0; i < pollfds_num; i++){ | ||
46 | if(pollfds[i].revents != 0){ | ||
47 | irq_fd->current_events = pollfds[i].revents; | ||
48 | pollfds[i].fd = -1; | ||
49 | } | ||
50 | irq_fd = irq_fd->next; | ||
51 | } | ||
52 | return n; | ||
53 | } | ||
54 | |||
55 | int os_isatty(int fd) | ||
56 | { | ||
57 | return(isatty(fd)); | ||
58 | } | ||
59 | |||
60 | int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds) | ||
61 | { | ||
62 | if (pollfds_num == pollfds_size) { | ||
63 | if (size_tmpfds <= pollfds_size * sizeof(pollfds[0])) { | ||
64 | /* return min size needed for new pollfds area */ | ||
65 | return((pollfds_size + 1) * sizeof(pollfds[0])); | ||
66 | } | ||
67 | |||
68 | if(pollfds != NULL){ | ||
69 | memcpy(tmp_pfd, pollfds, | ||
70 | sizeof(pollfds[0]) * pollfds_size); | ||
71 | /* remove old pollfds */ | ||
72 | kfree(pollfds); | ||
73 | } | ||
74 | pollfds = tmp_pfd; | ||
75 | pollfds_size++; | ||
76 | } else { | ||
77 | /* remove not used tmp_pfd */ | ||
78 | if (tmp_pfd != NULL) | ||
79 | kfree(tmp_pfd); | ||
80 | } | ||
81 | |||
82 | pollfds[pollfds_num] = ((struct pollfd) { .fd = fd, | ||
83 | .events = events, | ||
84 | .revents = 0 }); | ||
85 | pollfds_num++; | ||
86 | |||
87 | return(0); | ||
88 | } | ||
89 | |||
90 | void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg, | ||
91 | struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2) | ||
92 | { | ||
93 | struct irq_fd **prev; | ||
94 | int i = 0; | ||
95 | |||
96 | prev = &active_fds; | ||
97 | while(*prev != NULL){ | ||
98 | if((*test)(*prev, arg)){ | ||
99 | struct irq_fd *old_fd = *prev; | ||
100 | if((pollfds[i].fd != -1) && | ||
101 | (pollfds[i].fd != (*prev)->fd)){ | ||
102 | printk("os_free_irq_by_cb - mismatch between " | ||
103 | "active_fds and pollfds, fd %d vs %d\n", | ||
104 | (*prev)->fd, pollfds[i].fd); | ||
105 | goto out; | ||
106 | } | ||
107 | |||
108 | pollfds_num--; | ||
109 | |||
110 | /* This moves the *whole* array after pollfds[i] | ||
111 | * (though it doesn't spot as such)! | ||
112 | */ | ||
113 | |||
114 | memmove(&pollfds[i], &pollfds[i + 1], | ||
115 | (pollfds_num - i) * sizeof(pollfds[0])); | ||
116 | if(*last_irq_ptr2 == &old_fd->next) | ||
117 | *last_irq_ptr2 = prev; | ||
118 | |||
119 | *prev = (*prev)->next; | ||
120 | if(old_fd->type == IRQ_WRITE) | ||
121 | ignore_sigio_fd(old_fd->fd); | ||
122 | kfree(old_fd); | ||
123 | continue; | ||
124 | } | ||
125 | prev = &(*prev)->next; | ||
126 | i++; | ||
127 | } | ||
128 | out: | ||
129 | return; | ||
130 | } | ||
131 | |||
132 | |||
133 | int os_get_pollfd(int i) | ||
134 | { | ||
135 | return(pollfds[i].fd); | ||
136 | } | ||
137 | |||
138 | void os_set_pollfd(int i, int fd) | ||
139 | { | ||
140 | pollfds[i].fd = fd; | ||
141 | } | ||
142 | |||
143 | void os_set_ioignore(void) | ||
144 | { | ||
145 | set_handler(SIGIO, SIG_IGN, 0, -1); | ||
146 | } | ||
147 | |||
148 | void init_irq_signals(int on_sigstack) | ||
149 | { | ||
150 | __sighandler_t h; | ||
151 | int flags; | ||
152 | |||
153 | flags = on_sigstack ? SA_ONSTACK : 0; | ||
154 | if(timer_irq_inited) h = (__sighandler_t) alarm_handler; | ||
155 | else h = boot_timer_handler; | ||
156 | |||
157 | set_handler(SIGVTALRM, h, flags | SA_RESTART, | ||
158 | SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1); | ||
159 | set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART, | ||
160 | SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); | ||
161 | signal(SIGWINCH, SIG_IGN); | ||
162 | } | ||
diff --git a/arch/um/kernel/sigio_user.c b/arch/um/os-Linux/sigio.c index f7b18e157d35..9ba942947146 100644 --- a/arch/um/kernel/sigio_user.c +++ b/arch/um/os-Linux/sigio.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
@@ -20,128 +20,7 @@ | |||
20 | #include "sigio.h" | 20 | #include "sigio.h" |
21 | #include "os.h" | 21 | #include "os.h" |
22 | 22 | ||
23 | /* Changed during early boot */ | 23 | /* Protected by sigio_lock(), also used by sigio_cleanup, which is an |
24 | int pty_output_sigio = 0; | ||
25 | int pty_close_sigio = 0; | ||
26 | |||
27 | /* Used as a flag during SIGIO testing early in boot */ | ||
28 | static volatile int got_sigio = 0; | ||
29 | |||
30 | void __init handler(int sig) | ||
31 | { | ||
32 | got_sigio = 1; | ||
33 | } | ||
34 | |||
35 | struct openpty_arg { | ||
36 | int master; | ||
37 | int slave; | ||
38 | int err; | ||
39 | }; | ||
40 | |||
41 | static void openpty_cb(void *arg) | ||
42 | { | ||
43 | struct openpty_arg *info = arg; | ||
44 | |||
45 | info->err = 0; | ||
46 | if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) | ||
47 | info->err = -errno; | ||
48 | } | ||
49 | |||
50 | void __init check_one_sigio(void (*proc)(int, int)) | ||
51 | { | ||
52 | struct sigaction old, new; | ||
53 | struct openpty_arg pty = { .master = -1, .slave = -1 }; | ||
54 | int master, slave, err; | ||
55 | |||
56 | initial_thread_cb(openpty_cb, &pty); | ||
57 | if(pty.err){ | ||
58 | printk("openpty failed, errno = %d\n", -pty.err); | ||
59 | return; | ||
60 | } | ||
61 | |||
62 | master = pty.master; | ||
63 | slave = pty.slave; | ||
64 | |||
65 | if((master == -1) || (slave == -1)){ | ||
66 | printk("openpty failed to allocate a pty\n"); | ||
67 | return; | ||
68 | } | ||
69 | |||
70 | /* Not now, but complain so we now where we failed. */ | ||
71 | err = raw(master); | ||
72 | if (err < 0) | ||
73 | panic("check_sigio : __raw failed, errno = %d\n", -err); | ||
74 | |||
75 | err = os_sigio_async(master, slave); | ||
76 | if(err < 0) | ||
77 | panic("tty_fds : sigio_async failed, err = %d\n", -err); | ||
78 | |||
79 | if(sigaction(SIGIO, NULL, &old) < 0) | ||
80 | panic("check_sigio : sigaction 1 failed, errno = %d\n", errno); | ||
81 | new = old; | ||
82 | new.sa_handler = handler; | ||
83 | if(sigaction(SIGIO, &new, NULL) < 0) | ||
84 | panic("check_sigio : sigaction 2 failed, errno = %d\n", errno); | ||
85 | |||
86 | got_sigio = 0; | ||
87 | (*proc)(master, slave); | ||
88 | |||
89 | os_close_file(master); | ||
90 | os_close_file(slave); | ||
91 | |||
92 | if(sigaction(SIGIO, &old, NULL) < 0) | ||
93 | panic("check_sigio : sigaction 3 failed, errno = %d\n", errno); | ||
94 | } | ||
95 | |||
96 | static void tty_output(int master, int slave) | ||
97 | { | ||
98 | int n; | ||
99 | char buf[512]; | ||
100 | |||
101 | printk("Checking that host ptys support output SIGIO..."); | ||
102 | |||
103 | memset(buf, 0, sizeof(buf)); | ||
104 | |||
105 | while(os_write_file(master, buf, sizeof(buf)) > 0) ; | ||
106 | if(errno != EAGAIN) | ||
107 | panic("check_sigio : write failed, errno = %d\n", errno); | ||
108 | while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; | ||
109 | |||
110 | if (got_sigio) { | ||
111 | printk("Yes\n"); | ||
112 | pty_output_sigio = 1; | ||
113 | } else if (n == -EAGAIN) { | ||
114 | printk("No, enabling workaround\n"); | ||
115 | } else { | ||
116 | panic("check_sigio : read failed, err = %d\n", n); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | static void tty_close(int master, int slave) | ||
121 | { | ||
122 | printk("Checking that host ptys support SIGIO on close..."); | ||
123 | |||
124 | os_close_file(slave); | ||
125 | if(got_sigio){ | ||
126 | printk("Yes\n"); | ||
127 | pty_close_sigio = 1; | ||
128 | } | ||
129 | else printk("No, enabling workaround\n"); | ||
130 | } | ||
131 | |||
132 | void __init check_sigio(void) | ||
133 | { | ||
134 | if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) && | ||
135 | (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){ | ||
136 | printk("No pseudo-terminals available - skipping pty SIGIO " | ||
137 | "check\n"); | ||
138 | return; | ||
139 | } | ||
140 | check_one_sigio(tty_output); | ||
141 | check_one_sigio(tty_close); | ||
142 | } | ||
143 | |||
144 | /* Protected by sigio_lock(), also used by sigio_cleanup, which is an | ||
145 | * exitcall. | 24 | * exitcall. |
146 | */ | 25 | */ |
147 | static int write_sigio_pid = -1; | 26 | static int write_sigio_pid = -1; |
@@ -150,8 +29,10 @@ static int write_sigio_pid = -1; | |||
150 | * the descriptors closed after it is killed. So, it can't see them change. | 29 | * the descriptors closed after it is killed. So, it can't see them change. |
151 | * On the UML side, they are changed under the sigio_lock. | 30 | * On the UML side, they are changed under the sigio_lock. |
152 | */ | 31 | */ |
153 | static int write_sigio_fds[2] = { -1, -1 }; | 32 | #define SIGIO_FDS_INIT {-1, -1} |
154 | static int sigio_private[2] = { -1, -1 }; | 33 | |
34 | static int write_sigio_fds[2] = SIGIO_FDS_INIT; | ||
35 | static int sigio_private[2] = SIGIO_FDS_INIT; | ||
155 | 36 | ||
156 | struct pollfds { | 37 | struct pollfds { |
157 | struct pollfd *poll; | 38 | struct pollfd *poll; |
@@ -264,13 +145,13 @@ static void update_thread(void) | |||
264 | return; | 145 | return; |
265 | fail: | 146 | fail: |
266 | /* Critical section start */ | 147 | /* Critical section start */ |
267 | if(write_sigio_pid != -1) | 148 | if(write_sigio_pid != -1) |
268 | os_kill_process(write_sigio_pid, 1); | 149 | os_kill_process(write_sigio_pid, 1); |
269 | write_sigio_pid = -1; | 150 | write_sigio_pid = -1; |
270 | os_close_file(sigio_private[0]); | 151 | close(sigio_private[0]); |
271 | os_close_file(sigio_private[1]); | 152 | close(sigio_private[1]); |
272 | os_close_file(write_sigio_fds[0]); | 153 | close(write_sigio_fds[0]); |
273 | os_close_file(write_sigio_fds[1]); | 154 | close(write_sigio_fds[1]); |
274 | /* Critical section end */ | 155 | /* Critical section end */ |
275 | set_signals(flags); | 156 | set_signals(flags); |
276 | } | 157 | } |
@@ -281,13 +162,13 @@ int add_sigio_fd(int fd, int read) | |||
281 | 162 | ||
282 | sigio_lock(); | 163 | sigio_lock(); |
283 | for(i = 0; i < current_poll.used; i++){ | 164 | for(i = 0; i < current_poll.used; i++){ |
284 | if(current_poll.poll[i].fd == fd) | 165 | if(current_poll.poll[i].fd == fd) |
285 | goto out; | 166 | goto out; |
286 | } | 167 | } |
287 | 168 | ||
288 | n = current_poll.used + 1; | 169 | n = current_poll.used + 1; |
289 | err = need_poll(n); | 170 | err = need_poll(n); |
290 | if(err) | 171 | if(err) |
291 | goto out; | 172 | goto out; |
292 | 173 | ||
293 | for(i = 0; i < current_poll.used; i++) | 174 | for(i = 0; i < current_poll.used; i++) |
@@ -316,7 +197,7 @@ int ignore_sigio_fd(int fd) | |||
316 | } | 197 | } |
317 | if(i == current_poll.used) | 198 | if(i == current_poll.used) |
318 | goto out; | 199 | goto out; |
319 | 200 | ||
320 | err = need_poll(current_poll.used - 1); | 201 | err = need_poll(current_poll.used - 1); |
321 | if(err) | 202 | if(err) |
322 | goto out; | 203 | goto out; |
@@ -337,7 +218,7 @@ int ignore_sigio_fd(int fd) | |||
337 | return(err); | 218 | return(err); |
338 | } | 219 | } |
339 | 220 | ||
340 | static struct pollfd* setup_initial_poll(int fd) | 221 | static struct pollfd *setup_initial_poll(int fd) |
341 | { | 222 | { |
342 | struct pollfd *p; | 223 | struct pollfd *p; |
343 | 224 | ||
@@ -377,7 +258,7 @@ void write_sigio_workaround(void) | |||
377 | } | 258 | } |
378 | err = os_pipe(l_sigio_private, 1, 1); | 259 | err = os_pipe(l_sigio_private, 1, 1); |
379 | if(err < 0){ | 260 | if(err < 0){ |
380 | printk("write_sigio_workaround - os_pipe 1 failed, " | 261 | printk("write_sigio_workaround - os_pipe 2 failed, " |
381 | "err = %d\n", -err); | 262 | "err = %d\n", -err); |
382 | goto out_close1; | 263 | goto out_close1; |
383 | } | 264 | } |
@@ -391,76 +272,52 @@ void write_sigio_workaround(void) | |||
391 | /* Did we race? Don't try to optimize this, please, it's not so likely | 272 | /* Did we race? Don't try to optimize this, please, it's not so likely |
392 | * to happen, and no more than once at the boot. */ | 273 | * to happen, and no more than once at the boot. */ |
393 | if(write_sigio_pid != -1) | 274 | if(write_sigio_pid != -1) |
394 | goto out_unlock; | 275 | goto out_free; |
395 | 276 | ||
396 | write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, | 277 | current_poll = ((struct pollfds) { .poll = p, |
397 | CLONE_FILES | CLONE_VM, &stack, 0); | 278 | .used = 1, |
398 | 279 | .size = 1 }); | |
399 | if (write_sigio_pid < 0) | ||
400 | goto out_clear; | ||
401 | 280 | ||
402 | if (write_sigio_irq(l_write_sigio_fds[0])) | 281 | if (write_sigio_irq(l_write_sigio_fds[0])) |
403 | goto out_kill; | 282 | goto out_clear_poll; |
404 | 283 | ||
405 | /* Success, finally. */ | ||
406 | memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); | 284 | memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); |
407 | memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); | 285 | memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); |
408 | 286 | ||
409 | current_poll = ((struct pollfds) { .poll = p, | 287 | write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, |
410 | .used = 1, | 288 | CLONE_FILES | CLONE_VM, &stack, 0); |
411 | .size = 1 }); | ||
412 | 289 | ||
413 | sigio_unlock(); | 290 | if (write_sigio_pid < 0) |
414 | return; | 291 | goto out_clear; |
415 | 292 | ||
416 | out_kill: | ||
417 | l_write_sigio_pid = write_sigio_pid; | ||
418 | write_sigio_pid = -1; | ||
419 | sigio_unlock(); | 293 | sigio_unlock(); |
420 | /* Going to call waitpid, avoid holding the lock. */ | 294 | return; |
421 | os_kill_process(l_write_sigio_pid, 1); | ||
422 | goto out_free; | ||
423 | 295 | ||
424 | out_clear: | 296 | out_clear: |
425 | write_sigio_pid = -1; | 297 | write_sigio_pid = -1; |
426 | out_unlock: | 298 | write_sigio_fds[0] = -1; |
427 | sigio_unlock(); | 299 | write_sigio_fds[1] = -1; |
428 | out_free: | 300 | sigio_private[0] = -1; |
301 | sigio_private[1] = -1; | ||
302 | out_clear_poll: | ||
303 | current_poll = ((struct pollfds) { .poll = NULL, | ||
304 | .size = 0, | ||
305 | .used = 0 }); | ||
306 | out_free: | ||
429 | kfree(p); | 307 | kfree(p); |
430 | out_close2: | 308 | sigio_unlock(); |
431 | os_close_file(l_sigio_private[0]); | 309 | out_close2: |
432 | os_close_file(l_sigio_private[1]); | 310 | close(l_sigio_private[0]); |
433 | out_close1: | 311 | close(l_sigio_private[1]); |
434 | os_close_file(l_write_sigio_fds[0]); | 312 | out_close1: |
435 | os_close_file(l_write_sigio_fds[1]); | 313 | close(l_write_sigio_fds[0]); |
436 | return; | 314 | close(l_write_sigio_fds[1]); |
437 | } | ||
438 | |||
439 | int read_sigio_fd(int fd) | ||
440 | { | ||
441 | int n; | ||
442 | char c; | ||
443 | |||
444 | n = os_read_file(fd, &c, sizeof(c)); | ||
445 | if(n != sizeof(c)){ | ||
446 | if(n < 0) { | ||
447 | printk("read_sigio_fd - read failed, err = %d\n", -n); | ||
448 | return(n); | ||
449 | } | ||
450 | else { | ||
451 | printk("read_sigio_fd - short read, bytes = %d\n", n); | ||
452 | return(-EIO); | ||
453 | } | ||
454 | } | ||
455 | return(n); | ||
456 | } | 315 | } |
457 | 316 | ||
458 | static void sigio_cleanup(void) | 317 | void sigio_cleanup(void) |
459 | { | 318 | { |
460 | if (write_sigio_pid != -1) { | 319 | if(write_sigio_pid != -1){ |
461 | os_kill_process(write_sigio_pid, 1); | 320 | os_kill_process(write_sigio_pid, 1); |
462 | write_sigio_pid = -1; | 321 | write_sigio_pid = -1; |
463 | } | 322 | } |
464 | } | 323 | } |
465 | |||
466 | __uml_exitcall(sigio_cleanup); | ||
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 829d6b0d8b02..32753131f8d8 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <pty.h> | ||
6 | #include <stdio.h> | 7 | #include <stdio.h> |
7 | #include <stddef.h> | 8 | #include <stddef.h> |
8 | #include <stdarg.h> | 9 | #include <stdarg.h> |
@@ -539,3 +540,130 @@ int __init parse_iomem(char *str, int *add) | |||
539 | return(1); | 540 | return(1); |
540 | } | 541 | } |
541 | 542 | ||
543 | |||
544 | /* Changed during early boot */ | ||
545 | int pty_output_sigio = 0; | ||
546 | int pty_close_sigio = 0; | ||
547 | |||
548 | /* Used as a flag during SIGIO testing early in boot */ | ||
549 | static volatile int got_sigio = 0; | ||
550 | |||
551 | static void __init handler(int sig) | ||
552 | { | ||
553 | got_sigio = 1; | ||
554 | } | ||
555 | |||
556 | struct openpty_arg { | ||
557 | int master; | ||
558 | int slave; | ||
559 | int err; | ||
560 | }; | ||
561 | |||
562 | static void openpty_cb(void *arg) | ||
563 | { | ||
564 | struct openpty_arg *info = arg; | ||
565 | |||
566 | info->err = 0; | ||
567 | if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) | ||
568 | info->err = -errno; | ||
569 | } | ||
570 | |||
571 | static void __init check_one_sigio(void (*proc)(int, int)) | ||
572 | { | ||
573 | struct sigaction old, new; | ||
574 | struct openpty_arg pty = { .master = -1, .slave = -1 }; | ||
575 | int master, slave, err; | ||
576 | |||
577 | initial_thread_cb(openpty_cb, &pty); | ||
578 | if(pty.err){ | ||
579 | printk("openpty failed, errno = %d\n", -pty.err); | ||
580 | return; | ||
581 | } | ||
582 | |||
583 | master = pty.master; | ||
584 | slave = pty.slave; | ||
585 | |||
586 | if((master == -1) || (slave == -1)){ | ||
587 | printk("openpty failed to allocate a pty\n"); | ||
588 | return; | ||
589 | } | ||
590 | |||
591 | /* Not now, but complain so we now where we failed. */ | ||
592 | err = raw(master); | ||
593 | if (err < 0) | ||
594 | panic("check_sigio : __raw failed, errno = %d\n", -err); | ||
595 | |||
596 | err = os_sigio_async(master, slave); | ||
597 | if(err < 0) | ||
598 | panic("tty_fds : sigio_async failed, err = %d\n", -err); | ||
599 | |||
600 | if(sigaction(SIGIO, NULL, &old) < 0) | ||
601 | panic("check_sigio : sigaction 1 failed, errno = %d\n", errno); | ||
602 | new = old; | ||
603 | new.sa_handler = handler; | ||
604 | if(sigaction(SIGIO, &new, NULL) < 0) | ||
605 | panic("check_sigio : sigaction 2 failed, errno = %d\n", errno); | ||
606 | |||
607 | got_sigio = 0; | ||
608 | (*proc)(master, slave); | ||
609 | |||
610 | close(master); | ||
611 | close(slave); | ||
612 | |||
613 | if(sigaction(SIGIO, &old, NULL) < 0) | ||
614 | panic("check_sigio : sigaction 3 failed, errno = %d\n", errno); | ||
615 | } | ||
616 | |||
617 | static void tty_output(int master, int slave) | ||
618 | { | ||
619 | int n; | ||
620 | char buf[512]; | ||
621 | |||
622 | printk("Checking that host ptys support output SIGIO..."); | ||
623 | |||
624 | memset(buf, 0, sizeof(buf)); | ||
625 | |||
626 | while(os_write_file(master, buf, sizeof(buf)) > 0) ; | ||
627 | if(errno != EAGAIN) | ||
628 | panic("check_sigio : write failed, errno = %d\n", errno); | ||
629 | while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; | ||
630 | |||
631 | if(got_sigio){ | ||
632 | printk("Yes\n"); | ||
633 | pty_output_sigio = 1; | ||
634 | } | ||
635 | else if(n == -EAGAIN) printk("No, enabling workaround\n"); | ||
636 | else panic("check_sigio : read failed, err = %d\n", n); | ||
637 | } | ||
638 | |||
639 | static void tty_close(int master, int slave) | ||
640 | { | ||
641 | printk("Checking that host ptys support SIGIO on close..."); | ||
642 | |||
643 | close(slave); | ||
644 | if(got_sigio){ | ||
645 | printk("Yes\n"); | ||
646 | pty_close_sigio = 1; | ||
647 | } | ||
648 | else printk("No, enabling workaround\n"); | ||
649 | } | ||
650 | |||
651 | void __init check_sigio(void) | ||
652 | { | ||
653 | if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) && | ||
654 | (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){ | ||
655 | printk("No pseudo-terminals available - skipping pty SIGIO " | ||
656 | "check\n"); | ||
657 | return; | ||
658 | } | ||
659 | check_one_sigio(tty_output); | ||
660 | check_one_sigio(tty_close); | ||
661 | } | ||
662 | |||
663 | void os_check_bugs(void) | ||
664 | { | ||
665 | check_ptrace(); | ||
666 | check_sigio(); | ||
667 | check_devanon(); | ||
668 | } | ||
669 | |||
diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c index 919d19f11537..5461a065bbb9 100644 --- a/arch/um/os-Linux/tt.c +++ b/arch/um/os-Linux/tt.c | |||
@@ -110,6 +110,16 @@ int wait_for_stop(int pid, int sig, int cont_type, void *relay) | |||
110 | } | 110 | } |
111 | } | 111 | } |
112 | 112 | ||
113 | void forward_ipi(int fd, int pid) | ||
114 | { | ||
115 | int err; | ||
116 | |||
117 | err = os_set_owner(fd, pid); | ||
118 | if(err < 0) | ||
119 | printk("forward_ipi: set_owner failed, fd = %d, me = %d, " | ||
120 | "target = %d, err = %d\n", fd, os_getpid(), pid, -err); | ||
121 | } | ||
122 | |||
113 | /* | 123 | /* |
114 | *------------------------- | 124 | *------------------------- |
115 | * only for tt mode (will be deleted in future...) | 125 | * only for tt mode (will be deleted in future...) |
diff --git a/arch/um/kernel/tty_log.c b/arch/um/os-Linux/tty_log.c index 9ada656f68ce..c6ba56c1560f 100644 --- a/arch/um/kernel/tty_log.c +++ b/arch/um/os-Linux/tty_log.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and | 2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and |
3 | * geoffrey hing <ghing@net.ohio-state.edu> | 3 | * geoffrey hing <ghing@net.ohio-state.edu> |
4 | * Licensed under the GPL | 4 | * Licensed under the GPL |
5 | */ | 5 | */ |
@@ -58,7 +58,7 @@ int open_tty_log(void *tty, void *current_tty) | |||
58 | return(tty_log_fd); | 58 | return(tty_log_fd); |
59 | } | 59 | } |
60 | 60 | ||
61 | sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, | 61 | sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, |
62 | (unsigned int) tv.tv_usec); | 62 | (unsigned int) tv.tv_usec); |
63 | 63 | ||
64 | fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))), | 64 | fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))), |
@@ -216,15 +216,3 @@ __uml_setup("tty_log_fd=", set_tty_log_fd, | |||
216 | " tty data will be written. Preconfigure the descriptor with something\n" | 216 | " tty data will be written. Preconfigure the descriptor with something\n" |
217 | " like '10>tty_log tty_log_fd=10'.\n\n" | 217 | " like '10>tty_log tty_log_fd=10'.\n\n" |
218 | ); | 218 | ); |
219 | |||
220 | |||
221 | /* | ||
222 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
223 | * Emacs will notice this stuff at the end of the file and automatically | ||
224 | * adjust the settings for this buffer only. This must remain at the end | ||
225 | * of the file. | ||
226 | * --------------------------------------------------------------------------- | ||
227 | * Local variables: | ||
228 | * c-file-style: "linux" | ||
229 | * End: | ||
230 | */ | ||
diff --git a/arch/um/os-Linux/umid.c b/arch/um/os-Linux/umid.c index ecf107ae5ac8..198e59163288 100644 --- a/arch/um/os-Linux/umid.c +++ b/arch/um/os-Linux/umid.c | |||
@@ -143,8 +143,10 @@ static int not_dead_yet(char *dir) | |||
143 | goto out_close; | 143 | goto out_close; |
144 | } | 144 | } |
145 | 145 | ||
146 | if((kill(p, 0) == 0) || (errno != ESRCH)) | 146 | if((kill(p, 0) == 0) || (errno != ESRCH)){ |
147 | printk("umid \"%s\" is already in use by pid %d\n", umid, p); | ||
147 | return 1; | 148 | return 1; |
149 | } | ||
148 | 150 | ||
149 | err = actually_do_remove(dir); | 151 | err = actually_do_remove(dir); |
150 | if(err) | 152 | if(err) |
@@ -234,33 +236,44 @@ int __init make_umid(void) | |||
234 | err = mkdir(tmp, 0777); | 236 | err = mkdir(tmp, 0777); |
235 | if(err < 0){ | 237 | if(err < 0){ |
236 | err = -errno; | 238 | err = -errno; |
237 | if(errno != EEXIST) | 239 | if(err != -EEXIST) |
238 | goto err; | 240 | goto err; |
239 | 241 | ||
240 | if(not_dead_yet(tmp) < 0) | 242 | /* 1 -> this umid is already in use |
243 | * < 0 -> we couldn't remove the umid directory | ||
244 | * In either case, we can't use this umid, so return -EEXIST. | ||
245 | */ | ||
246 | if(not_dead_yet(tmp) != 0) | ||
241 | goto err; | 247 | goto err; |
242 | 248 | ||
243 | err = mkdir(tmp, 0777); | 249 | err = mkdir(tmp, 0777); |
244 | } | 250 | } |
245 | if(err < 0){ | 251 | if(err){ |
246 | printk("Failed to create '%s' - err = %d\n", umid, err); | 252 | err = -errno; |
247 | goto err_rmdir; | 253 | printk("Failed to create '%s' - err = %d\n", umid, -errno); |
254 | goto err; | ||
248 | } | 255 | } |
249 | 256 | ||
250 | umid_setup = 1; | 257 | umid_setup = 1; |
251 | 258 | ||
252 | create_pid_file(); | 259 | create_pid_file(); |
253 | 260 | ||
254 | return 0; | 261 | err = 0; |
255 | |||
256 | err_rmdir: | ||
257 | rmdir(tmp); | ||
258 | err: | 262 | err: |
259 | return err; | 263 | return err; |
260 | } | 264 | } |
261 | 265 | ||
262 | static int __init make_umid_init(void) | 266 | static int __init make_umid_init(void) |
263 | { | 267 | { |
268 | if(!make_umid()) | ||
269 | return 0; | ||
270 | |||
271 | /* If initializing with the given umid failed, then try again with | ||
272 | * a random one. | ||
273 | */ | ||
274 | printk("Failed to initialize umid \"%s\", trying with a random umid\n", | ||
275 | umid); | ||
276 | *umid = '\0'; | ||
264 | make_umid(); | 277 | make_umid(); |
265 | 278 | ||
266 | return 0; | 279 | return 0; |
diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c index e839ce65ad28..8032a105949a 100644 --- a/arch/um/sys-i386/ptrace.c +++ b/arch/um/sys-i386/ptrace.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <linux/config.h> | 6 | #include <linux/config.h> |
7 | #include <linux/compiler.h> | 7 | #include <linux/compiler.h> |
8 | #include "linux/sched.h" | 8 | #include "linux/sched.h" |
9 | #include "linux/mm.h" | ||
9 | #include "asm/elf.h" | 10 | #include "asm/elf.h" |
10 | #include "asm/ptrace.h" | 11 | #include "asm/ptrace.h" |
11 | #include "asm/uaccess.h" | 12 | #include "asm/uaccess.h" |
@@ -26,9 +27,17 @@ int is_syscall(unsigned long addr) | |||
26 | 27 | ||
27 | n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); | 28 | n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); |
28 | if(n){ | 29 | if(n){ |
29 | printk("is_syscall : failed to read instruction from 0x%lx\n", | 30 | /* access_process_vm() grants access to vsyscall and stub, |
30 | addr); | 31 | * while copy_from_user doesn't. Maybe access_process_vm is |
31 | return(0); | 32 | * slow, but that doesn't matter, since it will be called only |
33 | * in case of singlestepping, if copy_from_user failed. | ||
34 | */ | ||
35 | n = access_process_vm(current, addr, &instr, sizeof(instr), 0); | ||
36 | if(n != sizeof(instr)) { | ||
37 | printk("is_syscall : failed to read instruction from " | ||
38 | "0x%lx\n", addr); | ||
39 | return(1); | ||
40 | } | ||
32 | } | 41 | } |
33 | /* int 0x80 or sysenter */ | 42 | /* int 0x80 or sysenter */ |
34 | return((instr == 0x80cd) || (instr == 0x340f)); | 43 | return((instr == 0x80cd) || (instr == 0x340f)); |
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c index 7cd1a82dc8c2..33a40f5ef0d2 100644 --- a/arch/um/sys-i386/signal.c +++ b/arch/um/sys-i386/signal.c | |||
@@ -58,7 +58,7 @@ static int copy_sc_from_user_skas(struct pt_regs *regs, | |||
58 | } | 58 | } |
59 | 59 | ||
60 | int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | 60 | int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, |
61 | struct pt_regs *regs) | 61 | struct pt_regs *regs, unsigned long sp) |
62 | { | 62 | { |
63 | struct sigcontext sc; | 63 | struct sigcontext sc; |
64 | unsigned long fpregs[HOST_FP_SIZE]; | 64 | unsigned long fpregs[HOST_FP_SIZE]; |
@@ -72,7 +72,7 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | |||
72 | sc.edi = REGS_EDI(regs->regs.skas.regs); | 72 | sc.edi = REGS_EDI(regs->regs.skas.regs); |
73 | sc.esi = REGS_ESI(regs->regs.skas.regs); | 73 | sc.esi = REGS_ESI(regs->regs.skas.regs); |
74 | sc.ebp = REGS_EBP(regs->regs.skas.regs); | 74 | sc.ebp = REGS_EBP(regs->regs.skas.regs); |
75 | sc.esp = REGS_SP(regs->regs.skas.regs); | 75 | sc.esp = sp; |
76 | sc.ebx = REGS_EBX(regs->regs.skas.regs); | 76 | sc.ebx = REGS_EBX(regs->regs.skas.regs); |
77 | sc.edx = REGS_EDX(regs->regs.skas.regs); | 77 | sc.edx = REGS_EDX(regs->regs.skas.regs); |
78 | sc.ecx = REGS_ECX(regs->regs.skas.regs); | 78 | sc.ecx = REGS_ECX(regs->regs.skas.regs); |
@@ -132,7 +132,7 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, | |||
132 | } | 132 | } |
133 | 133 | ||
134 | int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, | 134 | int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, |
135 | struct sigcontext *from, int fpsize) | 135 | struct sigcontext *from, int fpsize, unsigned long sp) |
136 | { | 136 | { |
137 | struct _fpstate *to_fp, *from_fp; | 137 | struct _fpstate *to_fp, *from_fp; |
138 | int err; | 138 | int err; |
@@ -140,11 +140,18 @@ int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, | |||
140 | to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); | 140 | to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); |
141 | from_fp = from->fpstate; | 141 | from_fp = from->fpstate; |
142 | err = copy_to_user(to, from, sizeof(*to)); | 142 | err = copy_to_user(to, from, sizeof(*to)); |
143 | |||
144 | /* The SP in the sigcontext is the updated one for the signal | ||
145 | * delivery. The sp passed in is the original, and this needs | ||
146 | * to be restored, so we stick it in separately. | ||
147 | */ | ||
148 | err |= copy_to_user(&SC_SP(to), sp, sizeof(sp)); | ||
149 | |||
143 | if(from_fp != NULL){ | 150 | if(from_fp != NULL){ |
144 | err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); | 151 | err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); |
145 | err |= copy_to_user(to_fp, from_fp, fpsize); | 152 | err |= copy_to_user(to_fp, from_fp, fpsize); |
146 | } | 153 | } |
147 | return(err); | 154 | return err; |
148 | } | 155 | } |
149 | #endif | 156 | #endif |
150 | 157 | ||
@@ -159,11 +166,11 @@ static int copy_sc_from_user(struct pt_regs *to, void __user *from) | |||
159 | } | 166 | } |
160 | 167 | ||
161 | static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, | 168 | static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, |
162 | struct pt_regs *from) | 169 | struct pt_regs *from, unsigned long sp) |
163 | { | 170 | { |
164 | return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), | 171 | return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), |
165 | sizeof(*fp)), | 172 | sizeof(*fp), sp), |
166 | copy_sc_to_user_skas(to, fp, from))); | 173 | copy_sc_to_user_skas(to, fp, from, sp))); |
167 | } | 174 | } |
168 | 175 | ||
169 | static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp, | 176 | static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp, |
@@ -174,7 +181,7 @@ static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp, | |||
174 | err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp); | 181 | err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp); |
175 | err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags); | 182 | err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags); |
176 | err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size); | 183 | err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size); |
177 | err |= copy_sc_to_user(&uc->uc_mcontext, fp, ¤t->thread.regs); | 184 | err |= copy_sc_to_user(&uc->uc_mcontext, fp, ¤t->thread.regs, sp); |
178 | err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set)); | 185 | err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set)); |
179 | return(err); | 186 | return(err); |
180 | } | 187 | } |
@@ -207,6 +214,7 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, | |||
207 | { | 214 | { |
208 | struct sigframe __user *frame; | 215 | struct sigframe __user *frame; |
209 | void *restorer; | 216 | void *restorer; |
217 | unsigned long save_sp = PT_REGS_SP(regs); | ||
210 | int err = 0; | 218 | int err = 0; |
211 | 219 | ||
212 | stack_top &= -8UL; | 220 | stack_top &= -8UL; |
@@ -218,9 +226,19 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, | |||
218 | if(ka->sa.sa_flags & SA_RESTORER) | 226 | if(ka->sa.sa_flags & SA_RESTORER) |
219 | restorer = ka->sa.sa_restorer; | 227 | restorer = ka->sa.sa_restorer; |
220 | 228 | ||
229 | /* Update SP now because the page fault handler refuses to extend | ||
230 | * the stack if the faulting address is too far below the current | ||
231 | * SP, which frame now certainly is. If there's an error, the original | ||
232 | * value is restored on the way out. | ||
233 | * When writing the sigcontext to the stack, we have to write the | ||
234 | * original value, so that's passed to copy_sc_to_user, which does | ||
235 | * the right thing with it. | ||
236 | */ | ||
237 | PT_REGS_SP(regs) = (unsigned long) frame; | ||
238 | |||
221 | err |= __put_user(restorer, &frame->pretcode); | 239 | err |= __put_user(restorer, &frame->pretcode); |
222 | err |= __put_user(sig, &frame->sig); | 240 | err |= __put_user(sig, &frame->sig); |
223 | err |= copy_sc_to_user(&frame->sc, NULL, regs); | 241 | err |= copy_sc_to_user(&frame->sc, NULL, regs, save_sp); |
224 | err |= __put_user(mask->sig[0], &frame->sc.oldmask); | 242 | err |= __put_user(mask->sig[0], &frame->sc.oldmask); |
225 | if (_NSIG_WORDS > 1) | 243 | if (_NSIG_WORDS > 1) |
226 | err |= __copy_to_user(&frame->extramask, &mask->sig[1], | 244 | err |= __copy_to_user(&frame->extramask, &mask->sig[1], |
@@ -238,7 +256,7 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, | |||
238 | err |= __put_user(0x80cd, (short __user *)(frame->retcode+6)); | 256 | err |= __put_user(0x80cd, (short __user *)(frame->retcode+6)); |
239 | 257 | ||
240 | if(err) | 258 | if(err) |
241 | return(err); | 259 | goto err; |
242 | 260 | ||
243 | PT_REGS_SP(regs) = (unsigned long) frame; | 261 | PT_REGS_SP(regs) = (unsigned long) frame; |
244 | PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; | 262 | PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; |
@@ -248,7 +266,11 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, | |||
248 | 266 | ||
249 | if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) | 267 | if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) |
250 | ptrace_notify(SIGTRAP); | 268 | ptrace_notify(SIGTRAP); |
251 | return(0); | 269 | return 0; |
270 | |||
271 | err: | ||
272 | PT_REGS_SP(regs) = save_sp; | ||
273 | return err; | ||
252 | } | 274 | } |
253 | 275 | ||
254 | int setup_signal_stack_si(unsigned long stack_top, int sig, | 276 | int setup_signal_stack_si(unsigned long stack_top, int sig, |
@@ -257,6 +279,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, | |||
257 | { | 279 | { |
258 | struct rt_sigframe __user *frame; | 280 | struct rt_sigframe __user *frame; |
259 | void *restorer; | 281 | void *restorer; |
282 | unsigned long save_sp = PT_REGS_SP(regs); | ||
260 | int err = 0; | 283 | int err = 0; |
261 | 284 | ||
262 | stack_top &= -8UL; | 285 | stack_top &= -8UL; |
@@ -268,13 +291,16 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, | |||
268 | if(ka->sa.sa_flags & SA_RESTORER) | 291 | if(ka->sa.sa_flags & SA_RESTORER) |
269 | restorer = ka->sa.sa_restorer; | 292 | restorer = ka->sa.sa_restorer; |
270 | 293 | ||
294 | /* See comment above about why this is here */ | ||
295 | PT_REGS_SP(regs) = (unsigned long) frame; | ||
296 | |||
271 | err |= __put_user(restorer, &frame->pretcode); | 297 | err |= __put_user(restorer, &frame->pretcode); |
272 | err |= __put_user(sig, &frame->sig); | 298 | err |= __put_user(sig, &frame->sig); |
273 | err |= __put_user(&frame->info, &frame->pinfo); | 299 | err |= __put_user(&frame->info, &frame->pinfo); |
274 | err |= __put_user(&frame->uc, &frame->puc); | 300 | err |= __put_user(&frame->uc, &frame->puc); |
275 | err |= copy_siginfo_to_user(&frame->info, info); | 301 | err |= copy_siginfo_to_user(&frame->info, info); |
276 | err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask, | 302 | err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask, |
277 | PT_REGS_SP(regs)); | 303 | save_sp); |
278 | 304 | ||
279 | /* | 305 | /* |
280 | * This is movl $,%eax ; int $0x80 | 306 | * This is movl $,%eax ; int $0x80 |
@@ -288,9 +314,8 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, | |||
288 | err |= __put_user(0x80cd, (short __user *)(frame->retcode+5)); | 314 | err |= __put_user(0x80cd, (short __user *)(frame->retcode+5)); |
289 | 315 | ||
290 | if(err) | 316 | if(err) |
291 | return(err); | 317 | goto err; |
292 | 318 | ||
293 | PT_REGS_SP(regs) = (unsigned long) frame; | ||
294 | PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; | 319 | PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; |
295 | PT_REGS_EAX(regs) = (unsigned long) sig; | 320 | PT_REGS_EAX(regs) = (unsigned long) sig; |
296 | PT_REGS_EDX(regs) = (unsigned long) &frame->info; | 321 | PT_REGS_EDX(regs) = (unsigned long) &frame->info; |
@@ -298,7 +323,11 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, | |||
298 | 323 | ||
299 | if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) | 324 | if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) |
300 | ptrace_notify(SIGTRAP); | 325 | ptrace_notify(SIGTRAP); |
301 | return(0); | 326 | return 0; |
327 | |||
328 | err: | ||
329 | PT_REGS_SP(regs) = save_sp; | ||
330 | return err; | ||
302 | } | 331 | } |
303 | 332 | ||
304 | long sys_sigreturn(struct pt_regs regs) | 333 | long sys_sigreturn(struct pt_regs regs) |
diff --git a/arch/um/sys-i386/user-offsets.c b/arch/um/sys-i386/user-offsets.c index 26b68675053d..6f4ef2b7fa4a 100644 --- a/arch/um/sys-i386/user-offsets.c +++ b/arch/um/sys-i386/user-offsets.c | |||
@@ -3,12 +3,13 @@ | |||
3 | #include <asm/ptrace.h> | 3 | #include <asm/ptrace.h> |
4 | #include <asm/user.h> | 4 | #include <asm/user.h> |
5 | #include <linux/stddef.h> | 5 | #include <linux/stddef.h> |
6 | #include <sys/poll.h> | ||
6 | 7 | ||
7 | #define DEFINE(sym, val) \ | 8 | #define DEFINE(sym, val) \ |
8 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | 9 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) |
9 | 10 | ||
10 | #define DEFINE_LONGS(sym, val) \ | 11 | #define DEFINE_LONGS(sym, val) \ |
11 | asm volatile("\n->" #sym " %0 " #val : : "i" (val/sizeof(unsigned long))) | 12 | asm volatile("\n->" #sym " %0 " #val : : "i" (val/sizeof(unsigned long))) |
12 | 13 | ||
13 | #define OFFSET(sym, str, mem) \ | 14 | #define OFFSET(sym, str, mem) \ |
14 | DEFINE(sym, offsetof(struct str, mem)); | 15 | DEFINE(sym, offsetof(struct str, mem)); |
@@ -67,4 +68,9 @@ void foo(void) | |||
67 | DEFINE(HOST_ES, ES); | 68 | DEFINE(HOST_ES, ES); |
68 | DEFINE(HOST_GS, GS); | 69 | DEFINE(HOST_GS, GS); |
69 | DEFINE(UM_FRAME_SIZE, sizeof(struct user_regs_struct)); | 70 | DEFINE(UM_FRAME_SIZE, sizeof(struct user_regs_struct)); |
71 | |||
72 | /* XXX Duplicated between i386 and x86_64 */ | ||
73 | DEFINE(UM_POLLIN, POLLIN); | ||
74 | DEFINE(UM_POLLPRI, POLLPRI); | ||
75 | DEFINE(UM_POLLOUT, POLLOUT); | ||
70 | } | 76 | } |
diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c index 74eee5c7c6dd..147bbf05cbc2 100644 --- a/arch/um/sys-x86_64/ptrace.c +++ b/arch/um/sys-x86_64/ptrace.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <asm/ptrace.h> | 8 | #include <asm/ptrace.h> |
9 | #include <linux/sched.h> | 9 | #include <linux/sched.h> |
10 | #include <linux/errno.h> | 10 | #include <linux/errno.h> |
11 | #include <linux/mm.h> | ||
11 | #include <asm/uaccess.h> | 12 | #include <asm/uaccess.h> |
12 | #include <asm/elf.h> | 13 | #include <asm/elf.h> |
13 | 14 | ||
@@ -136,9 +137,28 @@ void arch_switch(void) | |||
136 | */ | 137 | */ |
137 | } | 138 | } |
138 | 139 | ||
140 | /* XXX Mostly copied from sys-i386 */ | ||
139 | int is_syscall(unsigned long addr) | 141 | int is_syscall(unsigned long addr) |
140 | { | 142 | { |
141 | panic("is_syscall"); | 143 | unsigned short instr; |
144 | int n; | ||
145 | |||
146 | n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); | ||
147 | if(n){ | ||
148 | /* access_process_vm() grants access to vsyscall and stub, | ||
149 | * while copy_from_user doesn't. Maybe access_process_vm is | ||
150 | * slow, but that doesn't matter, since it will be called only | ||
151 | * in case of singlestepping, if copy_from_user failed. | ||
152 | */ | ||
153 | n = access_process_vm(current, addr, &instr, sizeof(instr), 0); | ||
154 | if(n != sizeof(instr)) { | ||
155 | printk("is_syscall : failed to read instruction from " | ||
156 | "0x%lx\n", addr); | ||
157 | return(1); | ||
158 | } | ||
159 | } | ||
160 | /* sysenter */ | ||
161 | return(instr == 0x050f); | ||
142 | } | 162 | } |
143 | 163 | ||
144 | int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu ) | 164 | int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu ) |
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c index fe1d065332b1..e75c4e1838b0 100644 --- a/arch/um/sys-x86_64/signal.c +++ b/arch/um/sys-x86_64/signal.c | |||
@@ -55,7 +55,8 @@ static int copy_sc_from_user_skas(struct pt_regs *regs, | |||
55 | } | 55 | } |
56 | 56 | ||
57 | int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | 57 | int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, |
58 | struct pt_regs *regs, unsigned long mask) | 58 | struct pt_regs *regs, unsigned long mask, |
59 | unsigned long sp) | ||
59 | { | 60 | { |
60 | struct faultinfo * fi = ¤t->thread.arch.faultinfo; | 61 | struct faultinfo * fi = ¤t->thread.arch.faultinfo; |
61 | int err = 0; | 62 | int err = 0; |
@@ -70,7 +71,11 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | |||
70 | err |= PUTREG(regs, RDI, to, rdi); | 71 | err |= PUTREG(regs, RDI, to, rdi); |
71 | err |= PUTREG(regs, RSI, to, rsi); | 72 | err |= PUTREG(regs, RSI, to, rsi); |
72 | err |= PUTREG(regs, RBP, to, rbp); | 73 | err |= PUTREG(regs, RBP, to, rbp); |
73 | err |= PUTREG(regs, RSP, to, rsp); | 74 | /* Must use orignal RSP, which is passed in, rather than what's in |
75 | * the pt_regs, because that's already been updated to point at the | ||
76 | * signal frame. | ||
77 | */ | ||
78 | err |= __put_user(sp, &to->rsp); | ||
74 | err |= PUTREG(regs, RBX, to, rbx); | 79 | err |= PUTREG(regs, RBX, to, rbx); |
75 | err |= PUTREG(regs, RDX, to, rdx); | 80 | err |= PUTREG(regs, RDX, to, rdx); |
76 | err |= PUTREG(regs, RCX, to, rcx); | 81 | err |= PUTREG(regs, RCX, to, rcx); |
@@ -102,7 +107,7 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | |||
102 | 107 | ||
103 | #ifdef CONFIG_MODE_TT | 108 | #ifdef CONFIG_MODE_TT |
104 | int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, | 109 | int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, |
105 | int fpsize) | 110 | int fpsize) |
106 | { | 111 | { |
107 | struct _fpstate *to_fp, *from_fp; | 112 | struct _fpstate *to_fp, *from_fp; |
108 | unsigned long sigs; | 113 | unsigned long sigs; |
@@ -120,7 +125,7 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, | |||
120 | } | 125 | } |
121 | 126 | ||
122 | int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, | 127 | int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, |
123 | struct sigcontext *from, int fpsize) | 128 | struct sigcontext *from, int fpsize, unsigned long sp) |
124 | { | 129 | { |
125 | struct _fpstate *to_fp, *from_fp; | 130 | struct _fpstate *to_fp, *from_fp; |
126 | int err; | 131 | int err; |
@@ -128,11 +133,17 @@ int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, | |||
128 | to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); | 133 | to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); |
129 | from_fp = from->fpstate; | 134 | from_fp = from->fpstate; |
130 | err = copy_to_user(to, from, sizeof(*to)); | 135 | err = copy_to_user(to, from, sizeof(*to)); |
136 | /* The SP in the sigcontext is the updated one for the signal | ||
137 | * delivery. The sp passed in is the original, and this needs | ||
138 | * to be restored, so we stick it in separately. | ||
139 | */ | ||
140 | err |= copy_to_user(&SC_SP(to), sp, sizeof(sp)); | ||
141 | |||
131 | if(from_fp != NULL){ | 142 | if(from_fp != NULL){ |
132 | err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); | 143 | err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); |
133 | err |= copy_to_user(to_fp, from_fp, fpsize); | 144 | err |= copy_to_user(to_fp, from_fp, fpsize); |
134 | } | 145 | } |
135 | return(err); | 146 | return err; |
136 | } | 147 | } |
137 | 148 | ||
138 | #endif | 149 | #endif |
@@ -148,11 +159,12 @@ static int copy_sc_from_user(struct pt_regs *to, void __user *from) | |||
148 | } | 159 | } |
149 | 160 | ||
150 | static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, | 161 | static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, |
151 | struct pt_regs *from, unsigned long mask) | 162 | struct pt_regs *from, unsigned long mask, |
163 | unsigned long sp) | ||
152 | { | 164 | { |
153 | return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), | 165 | return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), |
154 | sizeof(*fp)), | 166 | sizeof(*fp), sp), |
155 | copy_sc_to_user_skas(to, fp, from, mask))); | 167 | copy_sc_to_user_skas(to, fp, from, mask, sp))); |
156 | } | 168 | } |
157 | 169 | ||
158 | struct rt_sigframe | 170 | struct rt_sigframe |
@@ -170,6 +182,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, | |||
170 | { | 182 | { |
171 | struct rt_sigframe __user *frame; | 183 | struct rt_sigframe __user *frame; |
172 | struct _fpstate __user *fp = NULL; | 184 | struct _fpstate __user *fp = NULL; |
185 | unsigned long save_sp = PT_REGS_RSP(regs); | ||
173 | int err = 0; | 186 | int err = 0; |
174 | struct task_struct *me = current; | 187 | struct task_struct *me = current; |
175 | 188 | ||
@@ -193,14 +206,25 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, | |||
193 | goto out; | 206 | goto out; |
194 | } | 207 | } |
195 | 208 | ||
209 | /* Update SP now because the page fault handler refuses to extend | ||
210 | * the stack if the faulting address is too far below the current | ||
211 | * SP, which frame now certainly is. If there's an error, the original | ||
212 | * value is restored on the way out. | ||
213 | * When writing the sigcontext to the stack, we have to write the | ||
214 | * original value, so that's passed to copy_sc_to_user, which does | ||
215 | * the right thing with it. | ||
216 | */ | ||
217 | PT_REGS_RSP(regs) = (unsigned long) frame; | ||
218 | |||
196 | /* Create the ucontext. */ | 219 | /* Create the ucontext. */ |
197 | err |= __put_user(0, &frame->uc.uc_flags); | 220 | err |= __put_user(0, &frame->uc.uc_flags); |
198 | err |= __put_user(0, &frame->uc.uc_link); | 221 | err |= __put_user(0, &frame->uc.uc_link); |
199 | err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 222 | err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
200 | err |= __put_user(sas_ss_flags(PT_REGS_SP(regs)), | 223 | err |= __put_user(sas_ss_flags(save_sp), |
201 | &frame->uc.uc_stack.ss_flags); | 224 | &frame->uc.uc_stack.ss_flags); |
202 | err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); | 225 | err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); |
203 | err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); | 226 | err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0], |
227 | save_sp); | ||
204 | err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); | 228 | err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); |
205 | if (sizeof(*set) == 16) { | 229 | if (sizeof(*set) == 16) { |
206 | __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); | 230 | __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); |
@@ -217,10 +241,10 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, | |||
217 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); | 241 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); |
218 | else | 242 | else |
219 | /* could use a vstub here */ | 243 | /* could use a vstub here */ |
220 | goto out; | 244 | goto restore_sp; |
221 | 245 | ||
222 | if (err) | 246 | if (err) |
223 | goto out; | 247 | goto restore_sp; |
224 | 248 | ||
225 | /* Set up registers for signal handler */ | 249 | /* Set up registers for signal handler */ |
226 | { | 250 | { |
@@ -238,10 +262,12 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, | |||
238 | PT_REGS_RSI(regs) = (unsigned long) &frame->info; | 262 | PT_REGS_RSI(regs) = (unsigned long) &frame->info; |
239 | PT_REGS_RDX(regs) = (unsigned long) &frame->uc; | 263 | PT_REGS_RDX(regs) = (unsigned long) &frame->uc; |
240 | PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler; | 264 | PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler; |
241 | |||
242 | PT_REGS_RSP(regs) = (unsigned long) frame; | ||
243 | out: | 265 | out: |
244 | return(err); | 266 | return err; |
267 | |||
268 | restore_sp: | ||
269 | PT_REGS_RSP(regs) = save_sp; | ||
270 | return err; | ||
245 | } | 271 | } |
246 | 272 | ||
247 | long sys_rt_sigreturn(struct pt_regs *regs) | 273 | long sys_rt_sigreturn(struct pt_regs *regs) |
diff --git a/arch/um/sys-x86_64/user-offsets.c b/arch/um/sys-x86_64/user-offsets.c index 7bd54a921cf7..899cebb57c3f 100644 --- a/arch/um/sys-x86_64/user-offsets.c +++ b/arch/um/sys-x86_64/user-offsets.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include <stdio.h> | 1 | #include <stdio.h> |
2 | #include <stddef.h> | 2 | #include <stddef.h> |
3 | #include <signal.h> | 3 | #include <signal.h> |
4 | #include <sys/poll.h> | ||
4 | #define __FRAME_OFFSETS | 5 | #define __FRAME_OFFSETS |
5 | #include <asm/ptrace.h> | 6 | #include <asm/ptrace.h> |
6 | #include <asm/types.h> | 7 | #include <asm/types.h> |
@@ -88,4 +89,9 @@ void foo(void) | |||
88 | DEFINE_LONGS(HOST_IP, RIP); | 89 | DEFINE_LONGS(HOST_IP, RIP); |
89 | DEFINE_LONGS(HOST_SP, RSP); | 90 | DEFINE_LONGS(HOST_SP, RSP); |
90 | DEFINE(UM_FRAME_SIZE, sizeof(struct user_regs_struct)); | 91 | DEFINE(UM_FRAME_SIZE, sizeof(struct user_regs_struct)); |
92 | |||
93 | /* XXX Duplicated between i386 and x86_64 */ | ||
94 | DEFINE(UM_POLLIN, POLLIN); | ||
95 | DEFINE(UM_POLLPRI, POLLPRI); | ||
96 | DEFINE(UM_POLLOUT, POLLOUT); | ||
91 | } | 97 | } |
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index 45efe0ca88f8..4310b4a311a5 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig | |||
@@ -250,6 +250,15 @@ config SCHED_SMT | |||
250 | cost of slightly increased overhead in some places. If unsure say | 250 | cost of slightly increased overhead in some places. If unsure say |
251 | N here. | 251 | N here. |
252 | 252 | ||
253 | config SCHED_MC | ||
254 | bool "Multi-core scheduler support" | ||
255 | depends on SMP | ||
256 | default y | ||
257 | help | ||
258 | Multi-core scheduler support improves the CPU scheduler's decision | ||
259 | making when dealing with multi-core CPU chips at a cost of slightly | ||
260 | increased overhead in some places. If unsure say N here. | ||
261 | |||
253 | source "kernel/Kconfig.preempt" | 262 | source "kernel/Kconfig.preempt" |
254 | 263 | ||
255 | config NUMA | 264 | config NUMA |
@@ -325,6 +334,10 @@ config HAVE_ARCH_EARLY_PFN_TO_NID | |||
325 | def_bool y | 334 | def_bool y |
326 | depends on NUMA | 335 | depends on NUMA |
327 | 336 | ||
337 | config OUT_OF_LINE_PFN_TO_PAGE | ||
338 | def_bool y | ||
339 | depends on DISCONTIGMEM | ||
340 | |||
328 | config NR_CPUS | 341 | config NR_CPUS |
329 | int "Maximum number of CPUs (2-256)" | 342 | int "Maximum number of CPUs (2-256)" |
330 | range 2 255 | 343 | range 2 255 |
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S index 7549a4389fbf..35b2faccdc6c 100644 --- a/arch/x86_64/ia32/ia32entry.S +++ b/arch/x86_64/ia32/ia32entry.S | |||
@@ -688,6 +688,8 @@ ia32_sys_call_table: | |||
688 | .quad sys_ni_syscall /* pselect6 for now */ | 688 | .quad sys_ni_syscall /* pselect6 for now */ |
689 | .quad sys_ni_syscall /* ppoll for now */ | 689 | .quad sys_ni_syscall /* ppoll for now */ |
690 | .quad sys_unshare /* 310 */ | 690 | .quad sys_unshare /* 310 */ |
691 | .quad compat_sys_set_robust_list | ||
692 | .quad compat_sys_get_robust_list | ||
691 | ia32_syscall_end: | 693 | ia32_syscall_end: |
692 | .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8 | 694 | .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8 |
693 | .quad ni_syscall | 695 | .quad ni_syscall |
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index 0370720515f1..70dd8e5c6889 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c | |||
@@ -66,24 +66,17 @@ EXPORT_SYMBOL(boot_option_idle_override); | |||
66 | void (*pm_idle)(void); | 66 | void (*pm_idle)(void); |
67 | static DEFINE_PER_CPU(unsigned int, cpu_idle_state); | 67 | static DEFINE_PER_CPU(unsigned int, cpu_idle_state); |
68 | 68 | ||
69 | static struct notifier_block *idle_notifier; | 69 | static ATOMIC_NOTIFIER_HEAD(idle_notifier); |
70 | static DEFINE_SPINLOCK(idle_notifier_lock); | ||
71 | 70 | ||
72 | void idle_notifier_register(struct notifier_block *n) | 71 | void idle_notifier_register(struct notifier_block *n) |
73 | { | 72 | { |
74 | unsigned long flags; | 73 | atomic_notifier_chain_register(&idle_notifier, n); |
75 | spin_lock_irqsave(&idle_notifier_lock, flags); | ||
76 | notifier_chain_register(&idle_notifier, n); | ||
77 | spin_unlock_irqrestore(&idle_notifier_lock, flags); | ||
78 | } | 74 | } |
79 | EXPORT_SYMBOL_GPL(idle_notifier_register); | 75 | EXPORT_SYMBOL_GPL(idle_notifier_register); |
80 | 76 | ||
81 | void idle_notifier_unregister(struct notifier_block *n) | 77 | void idle_notifier_unregister(struct notifier_block *n) |
82 | { | 78 | { |
83 | unsigned long flags; | 79 | atomic_notifier_chain_unregister(&idle_notifier, n); |
84 | spin_lock_irqsave(&idle_notifier_lock, flags); | ||
85 | notifier_chain_unregister(&idle_notifier, n); | ||
86 | spin_unlock_irqrestore(&idle_notifier_lock, flags); | ||
87 | } | 80 | } |
88 | EXPORT_SYMBOL(idle_notifier_unregister); | 81 | EXPORT_SYMBOL(idle_notifier_unregister); |
89 | 82 | ||
@@ -93,13 +86,13 @@ static DEFINE_PER_CPU(enum idle_state, idle_state) = CPU_NOT_IDLE; | |||
93 | void enter_idle(void) | 86 | void enter_idle(void) |
94 | { | 87 | { |
95 | __get_cpu_var(idle_state) = CPU_IDLE; | 88 | __get_cpu_var(idle_state) = CPU_IDLE; |
96 | notifier_call_chain(&idle_notifier, IDLE_START, NULL); | 89 | atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL); |
97 | } | 90 | } |
98 | 91 | ||
99 | static void __exit_idle(void) | 92 | static void __exit_idle(void) |
100 | { | 93 | { |
101 | __get_cpu_var(idle_state) = CPU_NOT_IDLE; | 94 | __get_cpu_var(idle_state) = CPU_NOT_IDLE; |
102 | notifier_call_chain(&idle_notifier, IDLE_END, NULL); | 95 | atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL); |
103 | } | 96 | } |
104 | 97 | ||
105 | /* Called from interrupts to signify idle end */ | 98 | /* Called from interrupts to signify idle end */ |
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index a57eec8311a7..d1f3e9272c05 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c | |||
@@ -962,7 +962,6 @@ static void __cpuinit detect_ht(struct cpuinfo_x86 *c) | |||
962 | 962 | ||
963 | cpuid(1, &eax, &ebx, &ecx, &edx); | 963 | cpuid(1, &eax, &ebx, &ecx, &edx); |
964 | 964 | ||
965 | c->apicid = phys_pkg_id(0); | ||
966 | 965 | ||
967 | if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY)) | 966 | if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY)) |
968 | return; | 967 | return; |
@@ -1171,6 +1170,8 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c) | |||
1171 | c->x86_capability[2] = cpuid_edx(0x80860001); | 1170 | c->x86_capability[2] = cpuid_edx(0x80860001); |
1172 | } | 1171 | } |
1173 | 1172 | ||
1173 | c->apicid = phys_pkg_id(0); | ||
1174 | |||
1174 | /* | 1175 | /* |
1175 | * Vendor-specific initialization. In this section we | 1176 | * Vendor-specific initialization. In this section we |
1176 | * canonicalize the feature flags, meaning if there are | 1177 | * canonicalize the feature flags, meaning if there are |
diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index 66e98659d077..ea48fa638070 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c | |||
@@ -68,6 +68,9 @@ u8 phys_proc_id[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID }; | |||
68 | /* core ID of each logical CPU */ | 68 | /* core ID of each logical CPU */ |
69 | u8 cpu_core_id[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID }; | 69 | u8 cpu_core_id[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID }; |
70 | 70 | ||
71 | /* Last level cache ID of each logical CPU */ | ||
72 | u8 cpu_llc_id[NR_CPUS] __cpuinitdata = {[0 ... NR_CPUS-1] = BAD_APICID}; | ||
73 | |||
71 | /* Bitmask of currently online CPUs */ | 74 | /* Bitmask of currently online CPUs */ |
72 | cpumask_t cpu_online_map __read_mostly; | 75 | cpumask_t cpu_online_map __read_mostly; |
73 | 76 | ||
@@ -445,6 +448,18 @@ void __cpuinit smp_callin(void) | |||
445 | cpu_set(cpuid, cpu_callin_map); | 448 | cpu_set(cpuid, cpu_callin_map); |
446 | } | 449 | } |
447 | 450 | ||
451 | /* maps the cpu to the sched domain representing multi-core */ | ||
452 | cpumask_t cpu_coregroup_map(int cpu) | ||
453 | { | ||
454 | struct cpuinfo_x86 *c = cpu_data + cpu; | ||
455 | /* | ||
456 | * For perf, we return last level cache shared map. | ||
457 | * TBD: when power saving sched policy is added, we will return | ||
458 | * cpu_core_map when power saving policy is enabled | ||
459 | */ | ||
460 | return c->llc_shared_map; | ||
461 | } | ||
462 | |||
448 | /* representing cpus for which sibling maps can be computed */ | 463 | /* representing cpus for which sibling maps can be computed */ |
449 | static cpumask_t cpu_sibling_setup_map; | 464 | static cpumask_t cpu_sibling_setup_map; |
450 | 465 | ||
@@ -463,12 +478,16 @@ static inline void set_cpu_sibling_map(int cpu) | |||
463 | cpu_set(cpu, cpu_sibling_map[i]); | 478 | cpu_set(cpu, cpu_sibling_map[i]); |
464 | cpu_set(i, cpu_core_map[cpu]); | 479 | cpu_set(i, cpu_core_map[cpu]); |
465 | cpu_set(cpu, cpu_core_map[i]); | 480 | cpu_set(cpu, cpu_core_map[i]); |
481 | cpu_set(i, c[cpu].llc_shared_map); | ||
482 | cpu_set(cpu, c[i].llc_shared_map); | ||
466 | } | 483 | } |
467 | } | 484 | } |
468 | } else { | 485 | } else { |
469 | cpu_set(cpu, cpu_sibling_map[cpu]); | 486 | cpu_set(cpu, cpu_sibling_map[cpu]); |
470 | } | 487 | } |
471 | 488 | ||
489 | cpu_set(cpu, c[cpu].llc_shared_map); | ||
490 | |||
472 | if (current_cpu_data.x86_max_cores == 1) { | 491 | if (current_cpu_data.x86_max_cores == 1) { |
473 | cpu_core_map[cpu] = cpu_sibling_map[cpu]; | 492 | cpu_core_map[cpu] = cpu_sibling_map[cpu]; |
474 | c[cpu].booted_cores = 1; | 493 | c[cpu].booted_cores = 1; |
@@ -476,6 +495,11 @@ static inline void set_cpu_sibling_map(int cpu) | |||
476 | } | 495 | } |
477 | 496 | ||
478 | for_each_cpu_mask(i, cpu_sibling_setup_map) { | 497 | for_each_cpu_mask(i, cpu_sibling_setup_map) { |
498 | if (cpu_llc_id[cpu] != BAD_APICID && | ||
499 | cpu_llc_id[cpu] == cpu_llc_id[i]) { | ||
500 | cpu_set(i, c[cpu].llc_shared_map); | ||
501 | cpu_set(cpu, c[i].llc_shared_map); | ||
502 | } | ||
479 | if (phys_proc_id[cpu] == phys_proc_id[i]) { | 503 | if (phys_proc_id[cpu] == phys_proc_id[i]) { |
480 | cpu_set(i, cpu_core_map[cpu]); | 504 | cpu_set(i, cpu_core_map[cpu]); |
481 | cpu_set(cpu, cpu_core_map[i]); | 505 | cpu_set(cpu, cpu_core_map[i]); |
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 7b148309c529..edaa9fe654dc 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c | |||
@@ -69,20 +69,20 @@ asmlinkage void alignment_check(void); | |||
69 | asmlinkage void machine_check(void); | 69 | asmlinkage void machine_check(void); |
70 | asmlinkage void spurious_interrupt_bug(void); | 70 | asmlinkage void spurious_interrupt_bug(void); |
71 | 71 | ||
72 | struct notifier_block *die_chain; | 72 | ATOMIC_NOTIFIER_HEAD(die_chain); |
73 | static DEFINE_SPINLOCK(die_notifier_lock); | ||
74 | 73 | ||
75 | int register_die_notifier(struct notifier_block *nb) | 74 | int register_die_notifier(struct notifier_block *nb) |
76 | { | 75 | { |
77 | int err = 0; | ||
78 | unsigned long flags; | ||
79 | |||
80 | vmalloc_sync_all(); | 76 | vmalloc_sync_all(); |
81 | spin_lock_irqsave(&die_notifier_lock, flags); | 77 | return atomic_notifier_chain_register(&die_chain, nb); |
82 | err = notifier_chain_register(&die_chain, nb); | 78 | } |
83 | spin_unlock_irqrestore(&die_notifier_lock, flags); | 79 | EXPORT_SYMBOL(register_die_notifier); |
84 | return err; | 80 | |
81 | int unregister_die_notifier(struct notifier_block *nb) | ||
82 | { | ||
83 | return atomic_notifier_chain_unregister(&die_chain, nb); | ||
85 | } | 84 | } |
85 | EXPORT_SYMBOL(unregister_die_notifier); | ||
86 | 86 | ||
87 | static inline void conditional_sti(struct pt_regs *regs) | 87 | static inline void conditional_sti(struct pt_regs *regs) |
88 | { | 88 | { |
diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index b04415625442..e5f7f1c34462 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c | |||
@@ -72,7 +72,7 @@ void show_mem(void) | |||
72 | show_free_areas(); | 72 | show_free_areas(); |
73 | printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); | 73 | printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); |
74 | 74 | ||
75 | for_each_pgdat(pgdat) { | 75 | for_each_online_pgdat(pgdat) { |
76 | for (i = 0; i < pgdat->node_spanned_pages; ++i) { | 76 | for (i = 0; i < pgdat->node_spanned_pages; ++i) { |
77 | page = pfn_to_page(pgdat->node_start_pfn + i); | 77 | page = pfn_to_page(pgdat->node_start_pfn + i); |
78 | total++; | 78 | total++; |
diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c index 63c72641b737..4be82d6e2b48 100644 --- a/arch/x86_64/mm/numa.c +++ b/arch/x86_64/mm/numa.c | |||
@@ -377,21 +377,6 @@ EXPORT_SYMBOL(node_data); | |||
377 | * Should do that. | 377 | * Should do that. |
378 | */ | 378 | */ |
379 | 379 | ||
380 | /* Requires pfn_valid(pfn) to be true */ | ||
381 | struct page *pfn_to_page(unsigned long pfn) | ||
382 | { | ||
383 | int nid = phys_to_nid(((unsigned long)(pfn)) << PAGE_SHIFT); | ||
384 | return (pfn - node_start_pfn(nid)) + NODE_DATA(nid)->node_mem_map; | ||
385 | } | ||
386 | EXPORT_SYMBOL(pfn_to_page); | ||
387 | |||
388 | unsigned long page_to_pfn(struct page *page) | ||
389 | { | ||
390 | return (long)(((page) - page_zone(page)->zone_mem_map) + | ||
391 | page_zone(page)->zone_start_pfn); | ||
392 | } | ||
393 | EXPORT_SYMBOL(page_to_pfn); | ||
394 | |||
395 | int pfn_valid(unsigned long pfn) | 380 | int pfn_valid(unsigned long pfn) |
396 | { | 381 | { |
397 | unsigned nid; | 382 | unsigned nid; |
diff --git a/arch/xtensa/platform-iss/setup.c b/arch/xtensa/platform-iss/setup.c index 2e6dcbf0cc04..23790a5610e2 100644 --- a/arch/xtensa/platform-iss/setup.c +++ b/arch/xtensa/platform-iss/setup.c | |||
@@ -108,5 +108,5 @@ static struct notifier_block iss_panic_block = { | |||
108 | 108 | ||
109 | void __init platform_setup(char **p_cmdline) | 109 | void __init platform_setup(char **p_cmdline) |
110 | { | 110 | { |
111 | notifier_chain_register(&panic_notifier_list, &iss_panic_block); | 111 | atomic_notifier_chain_register(&panic_notifier_list, &iss_panic_block); |
112 | } | 112 | } |
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 7fc903b5f3cd..82469db25100 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c | |||
@@ -785,6 +785,8 @@ void blk_queue_stack_limits(request_queue_t *t, request_queue_t *b) | |||
785 | t->max_hw_segments = min(t->max_hw_segments,b->max_hw_segments); | 785 | t->max_hw_segments = min(t->max_hw_segments,b->max_hw_segments); |
786 | t->max_segment_size = min(t->max_segment_size,b->max_segment_size); | 786 | t->max_segment_size = min(t->max_segment_size,b->max_segment_size); |
787 | t->hardsect_size = max(t->hardsect_size,b->hardsect_size); | 787 | t->hardsect_size = max(t->hardsect_size,b->hardsect_size); |
788 | if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags)) | ||
789 | clear_bit(QUEUE_FLAG_CLUSTER, &t->queue_flags); | ||
788 | } | 790 | } |
789 | 791 | ||
790 | EXPORT_SYMBOL(blk_queue_stack_limits); | 792 | EXPORT_SYMBOL(blk_queue_stack_limits); |
diff --git a/drivers/Kconfig b/drivers/Kconfig index bddf431bbb72..9f5c0da57c90 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig | |||
@@ -70,4 +70,6 @@ source "drivers/sn/Kconfig" | |||
70 | 70 | ||
71 | source "drivers/edac/Kconfig" | 71 | source "drivers/edac/Kconfig" |
72 | 72 | ||
73 | source "drivers/rtc/Kconfig" | ||
74 | |||
73 | endmenu | 75 | endmenu |
diff --git a/drivers/Makefile b/drivers/Makefile index 5c69b86db624..424955274e60 100644 --- a/drivers/Makefile +++ b/drivers/Makefile | |||
@@ -56,6 +56,7 @@ obj-$(CONFIG_USB_GADGET) += usb/gadget/ | |||
56 | obj-$(CONFIG_GAMEPORT) += input/gameport/ | 56 | obj-$(CONFIG_GAMEPORT) += input/gameport/ |
57 | obj-$(CONFIG_INPUT) += input/ | 57 | obj-$(CONFIG_INPUT) += input/ |
58 | obj-$(CONFIG_I2O) += message/ | 58 | obj-$(CONFIG_I2O) += message/ |
59 | obj-$(CONFIG_RTC_LIB) += rtc/ | ||
59 | obj-$(CONFIG_I2C) += i2c/ | 60 | obj-$(CONFIG_I2C) += i2c/ |
60 | obj-$(CONFIG_W1) += w1/ | 61 | obj-$(CONFIG_W1) += w1/ |
61 | obj-$(CONFIG_HWMON) += hwmon/ | 62 | obj-$(CONFIG_HWMON) += hwmon/ |
diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 105a0d61eb1f..dd547af4681a 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c | |||
@@ -47,16 +47,16 @@ static struct kset_uevent_ops memory_uevent_ops = { | |||
47 | .uevent = memory_uevent, | 47 | .uevent = memory_uevent, |
48 | }; | 48 | }; |
49 | 49 | ||
50 | static struct notifier_block *memory_chain; | 50 | static BLOCKING_NOTIFIER_HEAD(memory_chain); |
51 | 51 | ||
52 | int register_memory_notifier(struct notifier_block *nb) | 52 | int register_memory_notifier(struct notifier_block *nb) |
53 | { | 53 | { |
54 | return notifier_chain_register(&memory_chain, nb); | 54 | return blocking_notifier_chain_register(&memory_chain, nb); |
55 | } | 55 | } |
56 | 56 | ||
57 | void unregister_memory_notifier(struct notifier_block *nb) | 57 | void unregister_memory_notifier(struct notifier_block *nb) |
58 | { | 58 | { |
59 | notifier_chain_unregister(&memory_chain, nb); | 59 | blocking_notifier_chain_unregister(&memory_chain, nb); |
60 | } | 60 | } |
61 | 61 | ||
62 | /* | 62 | /* |
@@ -140,7 +140,7 @@ static ssize_t show_mem_state(struct sys_device *dev, char *buf) | |||
140 | 140 | ||
141 | static inline int memory_notify(unsigned long val, void *v) | 141 | static inline int memory_notify(unsigned long val, void *v) |
142 | { | 142 | { |
143 | return notifier_call_chain(&memory_chain, val, v); | 143 | return blocking_notifier_call_chain(&memory_chain, val, v); |
144 | } | 144 | } |
145 | 145 | ||
146 | /* | 146 | /* |
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index facc3f1d9e37..73d30bf01582 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig | |||
@@ -696,7 +696,7 @@ config NVRAM | |||
696 | 696 | ||
697 | config RTC | 697 | config RTC |
698 | tristate "Enhanced Real Time Clock Support" | 698 | tristate "Enhanced Real Time Clock Support" |
699 | depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV | 699 | depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM |
700 | ---help--- | 700 | ---help--- |
701 | If you say Y here and create a character special file /dev/rtc with | 701 | If you say Y here and create a character special file /dev/rtc with |
702 | major number 10 and minor number 135 using mknod ("man mknod"), you | 702 | major number 10 and minor number 135 using mknod ("man mknod"), you |
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index b8fb87c6c29f..40eb005b9d77 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c | |||
@@ -3744,7 +3744,7 @@ static int ipmi_init_msghandler(void) | |||
3744 | ipmi_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES; | 3744 | ipmi_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES; |
3745 | add_timer(&ipmi_timer); | 3745 | add_timer(&ipmi_timer); |
3746 | 3746 | ||
3747 | notifier_chain_register(&panic_notifier_list, &panic_block); | 3747 | atomic_notifier_chain_register(&panic_notifier_list, &panic_block); |
3748 | 3748 | ||
3749 | initialized = 1; | 3749 | initialized = 1; |
3750 | 3750 | ||
@@ -3764,7 +3764,7 @@ static __exit void cleanup_ipmi(void) | |||
3764 | if (!initialized) | 3764 | if (!initialized) |
3765 | return; | 3765 | return; |
3766 | 3766 | ||
3767 | notifier_chain_unregister(&panic_notifier_list, &panic_block); | 3767 | atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block); |
3768 | 3768 | ||
3769 | /* This can't be called if any interfaces exist, so no worry about | 3769 | /* This can't be called if any interfaces exist, so no worry about |
3770 | shutting down the interfaces. */ | 3770 | shutting down the interfaces. */ |
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 12f858dc9994..35fbd4d8ed4b 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
@@ -237,10 +237,10 @@ struct smi_info | |||
237 | 237 | ||
238 | static int try_smi_init(struct smi_info *smi); | 238 | static int try_smi_init(struct smi_info *smi); |
239 | 239 | ||
240 | static struct notifier_block *xaction_notifier_list; | 240 | static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list); |
241 | static int register_xaction_notifier(struct notifier_block * nb) | 241 | static int register_xaction_notifier(struct notifier_block * nb) |
242 | { | 242 | { |
243 | return notifier_chain_register(&xaction_notifier_list, nb); | 243 | return atomic_notifier_chain_register(&xaction_notifier_list, nb); |
244 | } | 244 | } |
245 | 245 | ||
246 | static void si_restart_short_timer(struct smi_info *smi_info); | 246 | static void si_restart_short_timer(struct smi_info *smi_info); |
@@ -302,7 +302,8 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) | |||
302 | do_gettimeofday(&t); | 302 | do_gettimeofday(&t); |
303 | printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec); | 303 | printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec); |
304 | #endif | 304 | #endif |
305 | err = notifier_call_chain(&xaction_notifier_list, 0, smi_info); | 305 | err = atomic_notifier_call_chain(&xaction_notifier_list, |
306 | 0, smi_info); | ||
306 | if (err & NOTIFY_STOP_MASK) { | 307 | if (err & NOTIFY_STOP_MASK) { |
307 | rv = SI_SM_CALL_WITHOUT_DELAY; | 308 | rv = SI_SM_CALL_WITHOUT_DELAY; |
308 | goto out; | 309 | goto out; |
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 616539310d9a..7ece9f3c8f70 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c | |||
@@ -1158,7 +1158,8 @@ static int __init ipmi_wdog_init(void) | |||
1158 | } | 1158 | } |
1159 | 1159 | ||
1160 | register_reboot_notifier(&wdog_reboot_notifier); | 1160 | register_reboot_notifier(&wdog_reboot_notifier); |
1161 | notifier_chain_register(&panic_notifier_list, &wdog_panic_notifier); | 1161 | atomic_notifier_chain_register(&panic_notifier_list, |
1162 | &wdog_panic_notifier); | ||
1162 | 1163 | ||
1163 | printk(KERN_INFO PFX "driver initialized\n"); | 1164 | printk(KERN_INFO PFX "driver initialized\n"); |
1164 | 1165 | ||
@@ -1176,7 +1177,8 @@ static __exit void ipmi_unregister_watchdog(void) | |||
1176 | release_nmi(&ipmi_nmi_handler); | 1177 | release_nmi(&ipmi_nmi_handler); |
1177 | #endif | 1178 | #endif |
1178 | 1179 | ||
1179 | notifier_chain_unregister(&panic_notifier_list, &wdog_panic_notifier); | 1180 | atomic_notifier_chain_unregister(&panic_notifier_list, |
1181 | &wdog_panic_notifier); | ||
1180 | unregister_reboot_notifier(&wdog_reboot_notifier); | 1182 | unregister_reboot_notifier(&wdog_reboot_notifier); |
1181 | 1183 | ||
1182 | if (! watchdog_user) | 1184 | if (! watchdog_user) |
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index aed80e6aec6d..9b6ae7dc8b8a 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -52,9 +52,8 @@ static void handle_update(void *data); | |||
52 | * changes to devices when the CPU clock speed changes. | 52 | * changes to devices when the CPU clock speed changes. |
53 | * The mutex locks both lists. | 53 | * The mutex locks both lists. |
54 | */ | 54 | */ |
55 | static struct notifier_block *cpufreq_policy_notifier_list; | 55 | static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list); |
56 | static struct notifier_block *cpufreq_transition_notifier_list; | 56 | static BLOCKING_NOTIFIER_HEAD(cpufreq_transition_notifier_list); |
57 | static DECLARE_RWSEM (cpufreq_notifier_rwsem); | ||
58 | 57 | ||
59 | 58 | ||
60 | static LIST_HEAD(cpufreq_governor_list); | 59 | static LIST_HEAD(cpufreq_governor_list); |
@@ -247,8 +246,6 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) | |||
247 | dprintk("notification %u of frequency transition to %u kHz\n", | 246 | dprintk("notification %u of frequency transition to %u kHz\n", |
248 | state, freqs->new); | 247 | state, freqs->new); |
249 | 248 | ||
250 | down_read(&cpufreq_notifier_rwsem); | ||
251 | |||
252 | policy = cpufreq_cpu_data[freqs->cpu]; | 249 | policy = cpufreq_cpu_data[freqs->cpu]; |
253 | switch (state) { | 250 | switch (state) { |
254 | 251 | ||
@@ -266,20 +263,19 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) | |||
266 | freqs->old = policy->cur; | 263 | freqs->old = policy->cur; |
267 | } | 264 | } |
268 | } | 265 | } |
269 | notifier_call_chain(&cpufreq_transition_notifier_list, | 266 | blocking_notifier_call_chain(&cpufreq_transition_notifier_list, |
270 | CPUFREQ_PRECHANGE, freqs); | 267 | CPUFREQ_PRECHANGE, freqs); |
271 | adjust_jiffies(CPUFREQ_PRECHANGE, freqs); | 268 | adjust_jiffies(CPUFREQ_PRECHANGE, freqs); |
272 | break; | 269 | break; |
273 | 270 | ||
274 | case CPUFREQ_POSTCHANGE: | 271 | case CPUFREQ_POSTCHANGE: |
275 | adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); | 272 | adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); |
276 | notifier_call_chain(&cpufreq_transition_notifier_list, | 273 | blocking_notifier_call_chain(&cpufreq_transition_notifier_list, |
277 | CPUFREQ_POSTCHANGE, freqs); | 274 | CPUFREQ_POSTCHANGE, freqs); |
278 | if (likely(policy) && likely(policy->cpu == freqs->cpu)) | 275 | if (likely(policy) && likely(policy->cpu == freqs->cpu)) |
279 | policy->cur = freqs->new; | 276 | policy->cur = freqs->new; |
280 | break; | 277 | break; |
281 | } | 278 | } |
282 | up_read(&cpufreq_notifier_rwsem); | ||
283 | } | 279 | } |
284 | EXPORT_SYMBOL_GPL(cpufreq_notify_transition); | 280 | EXPORT_SYMBOL_GPL(cpufreq_notify_transition); |
285 | 281 | ||
@@ -1007,7 +1003,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg) | |||
1007 | freqs.old = cpu_policy->cur; | 1003 | freqs.old = cpu_policy->cur; |
1008 | freqs.new = cur_freq; | 1004 | freqs.new = cur_freq; |
1009 | 1005 | ||
1010 | notifier_call_chain(&cpufreq_transition_notifier_list, | 1006 | blocking_notifier_call_chain(&cpufreq_transition_notifier_list, |
1011 | CPUFREQ_SUSPENDCHANGE, &freqs); | 1007 | CPUFREQ_SUSPENDCHANGE, &freqs); |
1012 | adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs); | 1008 | adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs); |
1013 | 1009 | ||
@@ -1088,7 +1084,8 @@ static int cpufreq_resume(struct sys_device * sysdev) | |||
1088 | freqs.old = cpu_policy->cur; | 1084 | freqs.old = cpu_policy->cur; |
1089 | freqs.new = cur_freq; | 1085 | freqs.new = cur_freq; |
1090 | 1086 | ||
1091 | notifier_call_chain(&cpufreq_transition_notifier_list, | 1087 | blocking_notifier_call_chain( |
1088 | &cpufreq_transition_notifier_list, | ||
1092 | CPUFREQ_RESUMECHANGE, &freqs); | 1089 | CPUFREQ_RESUMECHANGE, &freqs); |
1093 | adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs); | 1090 | adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs); |
1094 | 1091 | ||
@@ -1125,24 +1122,24 @@ static struct sysdev_driver cpufreq_sysdev_driver = { | |||
1125 | * changes in cpufreq policy. | 1122 | * changes in cpufreq policy. |
1126 | * | 1123 | * |
1127 | * This function may sleep, and has the same return conditions as | 1124 | * This function may sleep, and has the same return conditions as |
1128 | * notifier_chain_register. | 1125 | * blocking_notifier_chain_register. |
1129 | */ | 1126 | */ |
1130 | int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list) | 1127 | int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list) |
1131 | { | 1128 | { |
1132 | int ret; | 1129 | int ret; |
1133 | 1130 | ||
1134 | down_write(&cpufreq_notifier_rwsem); | ||
1135 | switch (list) { | 1131 | switch (list) { |
1136 | case CPUFREQ_TRANSITION_NOTIFIER: | 1132 | case CPUFREQ_TRANSITION_NOTIFIER: |
1137 | ret = notifier_chain_register(&cpufreq_transition_notifier_list, nb); | 1133 | ret = blocking_notifier_chain_register( |
1134 | &cpufreq_transition_notifier_list, nb); | ||
1138 | break; | 1135 | break; |
1139 | case CPUFREQ_POLICY_NOTIFIER: | 1136 | case CPUFREQ_POLICY_NOTIFIER: |
1140 | ret = notifier_chain_register(&cpufreq_policy_notifier_list, nb); | 1137 | ret = blocking_notifier_chain_register( |
1138 | &cpufreq_policy_notifier_list, nb); | ||
1141 | break; | 1139 | break; |
1142 | default: | 1140 | default: |
1143 | ret = -EINVAL; | 1141 | ret = -EINVAL; |
1144 | } | 1142 | } |
1145 | up_write(&cpufreq_notifier_rwsem); | ||
1146 | 1143 | ||
1147 | return ret; | 1144 | return ret; |
1148 | } | 1145 | } |
@@ -1157,24 +1154,24 @@ EXPORT_SYMBOL(cpufreq_register_notifier); | |||
1157 | * Remove a driver from the CPU frequency notifier list. | 1154 | * Remove a driver from the CPU frequency notifier list. |
1158 | * | 1155 | * |
1159 | * This function may sleep, and has the same return conditions as | 1156 | * This function may sleep, and has the same return conditions as |
1160 | * notifier_chain_unregister. | 1157 | * blocking_notifier_chain_unregister. |
1161 | */ | 1158 | */ |
1162 | int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list) | 1159 | int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list) |
1163 | { | 1160 | { |
1164 | int ret; | 1161 | int ret; |
1165 | 1162 | ||
1166 | down_write(&cpufreq_notifier_rwsem); | ||
1167 | switch (list) { | 1163 | switch (list) { |
1168 | case CPUFREQ_TRANSITION_NOTIFIER: | 1164 | case CPUFREQ_TRANSITION_NOTIFIER: |
1169 | ret = notifier_chain_unregister(&cpufreq_transition_notifier_list, nb); | 1165 | ret = blocking_notifier_chain_unregister( |
1166 | &cpufreq_transition_notifier_list, nb); | ||
1170 | break; | 1167 | break; |
1171 | case CPUFREQ_POLICY_NOTIFIER: | 1168 | case CPUFREQ_POLICY_NOTIFIER: |
1172 | ret = notifier_chain_unregister(&cpufreq_policy_notifier_list, nb); | 1169 | ret = blocking_notifier_chain_unregister( |
1170 | &cpufreq_policy_notifier_list, nb); | ||
1173 | break; | 1171 | break; |
1174 | default: | 1172 | default: |
1175 | ret = -EINVAL; | 1173 | ret = -EINVAL; |
1176 | } | 1174 | } |
1177 | up_write(&cpufreq_notifier_rwsem); | ||
1178 | 1175 | ||
1179 | return ret; | 1176 | return ret; |
1180 | } | 1177 | } |
@@ -1346,29 +1343,23 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_poli | |||
1346 | if (ret) | 1343 | if (ret) |
1347 | goto error_out; | 1344 | goto error_out; |
1348 | 1345 | ||
1349 | down_read(&cpufreq_notifier_rwsem); | ||
1350 | |||
1351 | /* adjust if necessary - all reasons */ | 1346 | /* adjust if necessary - all reasons */ |
1352 | notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_ADJUST, | 1347 | blocking_notifier_call_chain(&cpufreq_policy_notifier_list, |
1353 | policy); | 1348 | CPUFREQ_ADJUST, policy); |
1354 | 1349 | ||
1355 | /* adjust if necessary - hardware incompatibility*/ | 1350 | /* adjust if necessary - hardware incompatibility*/ |
1356 | notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_INCOMPATIBLE, | 1351 | blocking_notifier_call_chain(&cpufreq_policy_notifier_list, |
1357 | policy); | 1352 | CPUFREQ_INCOMPATIBLE, policy); |
1358 | 1353 | ||
1359 | /* verify the cpu speed can be set within this limit, | 1354 | /* verify the cpu speed can be set within this limit, |
1360 | which might be different to the first one */ | 1355 | which might be different to the first one */ |
1361 | ret = cpufreq_driver->verify(policy); | 1356 | ret = cpufreq_driver->verify(policy); |
1362 | if (ret) { | 1357 | if (ret) |
1363 | up_read(&cpufreq_notifier_rwsem); | ||
1364 | goto error_out; | 1358 | goto error_out; |
1365 | } | ||
1366 | 1359 | ||
1367 | /* notification of the new policy */ | 1360 | /* notification of the new policy */ |
1368 | notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_NOTIFY, | 1361 | blocking_notifier_call_chain(&cpufreq_policy_notifier_list, |
1369 | policy); | 1362 | CPUFREQ_NOTIFY, policy); |
1370 | |||
1371 | up_read(&cpufreq_notifier_rwsem); | ||
1372 | 1363 | ||
1373 | data->min = policy->min; | 1364 | data->min = policy->min; |
1374 | data->max = policy->max; | 1365 | data->max = policy->max; |
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c index d6543fc4a923..339f405ff708 100644 --- a/drivers/firmware/dcdbas.c +++ b/drivers/firmware/dcdbas.c | |||
@@ -484,26 +484,15 @@ static void dcdbas_host_control(void) | |||
484 | static int dcdbas_reboot_notify(struct notifier_block *nb, unsigned long code, | 484 | static int dcdbas_reboot_notify(struct notifier_block *nb, unsigned long code, |
485 | void *unused) | 485 | void *unused) |
486 | { | 486 | { |
487 | static unsigned int notify_cnt = 0; | ||
488 | |||
489 | switch (code) { | 487 | switch (code) { |
490 | case SYS_DOWN: | 488 | case SYS_DOWN: |
491 | case SYS_HALT: | 489 | case SYS_HALT: |
492 | case SYS_POWER_OFF: | 490 | case SYS_POWER_OFF: |
493 | if (host_control_on_shutdown) { | 491 | if (host_control_on_shutdown) { |
494 | /* firmware is going to perform host control action */ | 492 | /* firmware is going to perform host control action */ |
495 | if (++notify_cnt == 2) { | 493 | printk(KERN_WARNING "Please wait for shutdown " |
496 | printk(KERN_WARNING | 494 | "action to complete...\n"); |
497 | "Please wait for shutdown " | 495 | dcdbas_host_control(); |
498 | "action to complete...\n"); | ||
499 | dcdbas_host_control(); | ||
500 | } | ||
501 | /* | ||
502 | * register again and initiate the host control | ||
503 | * action on the second notification to allow | ||
504 | * everyone that registered to be notified | ||
505 | */ | ||
506 | register_reboot_notifier(nb); | ||
507 | } | 496 | } |
508 | break; | 497 | break; |
509 | } | 498 | } |
@@ -514,7 +503,7 @@ static int dcdbas_reboot_notify(struct notifier_block *nb, unsigned long code, | |||
514 | static struct notifier_block dcdbas_reboot_nb = { | 503 | static struct notifier_block dcdbas_reboot_nb = { |
515 | .notifier_call = dcdbas_reboot_notify, | 504 | .notifier_call = dcdbas_reboot_notify, |
516 | .next = NULL, | 505 | .next = NULL, |
517 | .priority = 0 | 506 | .priority = INT_MIN |
518 | }; | 507 | }; |
519 | 508 | ||
520 | static DCDBAS_BIN_ATTR_RW(smi_data); | 509 | static DCDBAS_BIN_ATTR_RW(smi_data); |
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index f9fae28f5612..7aa5c38f0855 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig | |||
@@ -65,15 +65,6 @@ config SENSORS_PCF8591 | |||
65 | This driver can also be built as a module. If so, the module | 65 | This driver can also be built as a module. If so, the module |
66 | will be called pcf8591. | 66 | will be called pcf8591. |
67 | 67 | ||
68 | config SENSORS_RTC8564 | ||
69 | tristate "Epson 8564 RTC chip" | ||
70 | depends on I2C && EXPERIMENTAL | ||
71 | help | ||
72 | If you say yes here you get support for the Epson 8564 RTC chip. | ||
73 | |||
74 | This driver can also be built as a module. If so, the module | ||
75 | will be called i2c-rtc8564. | ||
76 | |||
77 | config ISP1301_OMAP | 68 | config ISP1301_OMAP |
78 | tristate "Philips ISP1301 with OMAP OTG" | 69 | tristate "Philips ISP1301 with OMAP OTG" |
79 | depends on I2C && ARCH_OMAP_OTG | 70 | depends on I2C && ARCH_OMAP_OTG |
@@ -126,13 +117,4 @@ config SENSORS_MAX6875 | |||
126 | This driver can also be built as a module. If so, the module | 117 | This driver can also be built as a module. If so, the module |
127 | will be called max6875. | 118 | will be called max6875. |
128 | 119 | ||
129 | config RTC_X1205_I2C | ||
130 | tristate "Xicor X1205 RTC chip" | ||
131 | depends on I2C && EXPERIMENTAL | ||
132 | help | ||
133 | If you say yes here you get support for the Xicor X1205 RTC chip. | ||
134 | |||
135 | This driver can also be built as a module. If so, the module | ||
136 | will be called x1205. | ||
137 | |||
138 | endmenu | 120 | endmenu |
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 46178b57b1f1..779868ef2e26 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile | |||
@@ -10,10 +10,8 @@ obj-$(CONFIG_SENSORS_M41T00) += m41t00.o | |||
10 | obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o | 10 | obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o |
11 | obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o | 11 | obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o |
12 | obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o | 12 | obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o |
13 | obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o | ||
14 | obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o | 13 | obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o |
15 | obj-$(CONFIG_TPS65010) += tps65010.o | 14 | obj-$(CONFIG_TPS65010) += tps65010.o |
16 | obj-$(CONFIG_RTC_X1205_I2C) += x1205.o | ||
17 | 15 | ||
18 | ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) | 16 | ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) |
19 | EXTRA_CFLAGS += -DDEBUG | 17 | EXTRA_CFLAGS += -DDEBUG |
diff --git a/drivers/i2c/chips/rtc8564.c b/drivers/i2c/chips/rtc8564.c deleted file mode 100644 index 0d8699b3f488..000000000000 --- a/drivers/i2c/chips/rtc8564.c +++ /dev/null | |||
@@ -1,385 +0,0 @@ | |||
1 | /* | ||
2 | * linux/drivers/i2c/chips/rtc8564.c | ||
3 | * | ||
4 | * Copyright (C) 2002-2004 Stefan Eletzhofer | ||
5 | * | ||
6 | * based on linux/drivers/acron/char/pcf8583.c | ||
7 | * Copyright (C) 2000 Russell King | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * Driver for system3's EPSON RTC 8564 chip | ||
14 | */ | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/bcd.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/rtc.h> /* get the user-level API */ | ||
22 | #include <linux/init.h> | ||
23 | |||
24 | #include "rtc8564.h" | ||
25 | |||
26 | #ifdef DEBUG | ||
27 | # define _DBG(x, fmt, args...) do{ if (debug>=x) printk(KERN_DEBUG"%s: " fmt "\n", __FUNCTION__, ##args); } while(0); | ||
28 | #else | ||
29 | # define _DBG(x, fmt, args...) do { } while(0); | ||
30 | #endif | ||
31 | |||
32 | #define _DBGRTCTM(x, rtctm) if (debug>=x) printk("%s: secs=%d, mins=%d, hours=%d, mday=%d, " \ | ||
33 | "mon=%d, year=%d, wday=%d VL=%d\n", __FUNCTION__, \ | ||
34 | (rtctm).secs, (rtctm).mins, (rtctm).hours, (rtctm).mday, \ | ||
35 | (rtctm).mon, (rtctm).year, (rtctm).wday, (rtctm).vl); | ||
36 | |||
37 | struct rtc8564_data { | ||
38 | struct i2c_client client; | ||
39 | u16 ctrl; | ||
40 | }; | ||
41 | |||
42 | static inline u8 _rtc8564_ctrl1(struct i2c_client *client) | ||
43 | { | ||
44 | struct rtc8564_data *data = i2c_get_clientdata(client); | ||
45 | return data->ctrl & 0xff; | ||
46 | } | ||
47 | static inline u8 _rtc8564_ctrl2(struct i2c_client *client) | ||
48 | { | ||
49 | struct rtc8564_data *data = i2c_get_clientdata(client); | ||
50 | return (data->ctrl & 0xff00) >> 8; | ||
51 | } | ||
52 | |||
53 | #define CTRL1(c) _rtc8564_ctrl1(c) | ||
54 | #define CTRL2(c) _rtc8564_ctrl2(c) | ||
55 | |||
56 | static int debug; | ||
57 | module_param(debug, int, S_IRUGO | S_IWUSR); | ||
58 | |||
59 | static struct i2c_driver rtc8564_driver; | ||
60 | |||
61 | static unsigned short ignore[] = { I2C_CLIENT_END }; | ||
62 | static unsigned short normal_addr[] = { 0x51, I2C_CLIENT_END }; | ||
63 | |||
64 | static struct i2c_client_address_data addr_data = { | ||
65 | .normal_i2c = normal_addr, | ||
66 | .probe = ignore, | ||
67 | .ignore = ignore, | ||
68 | }; | ||
69 | |||
70 | static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem); | ||
71 | static int rtc8564_write_mem(struct i2c_client *client, struct mem *mem); | ||
72 | |||
73 | static int rtc8564_read(struct i2c_client *client, unsigned char adr, | ||
74 | unsigned char *buf, unsigned char len) | ||
75 | { | ||
76 | int ret = -EIO; | ||
77 | unsigned char addr[1] = { adr }; | ||
78 | struct i2c_msg msgs[2] = { | ||
79 | {client->addr, 0, 1, addr}, | ||
80 | {client->addr, I2C_M_RD, len, buf} | ||
81 | }; | ||
82 | |||
83 | _DBG(1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, buf, len); | ||
84 | |||
85 | if (!buf) { | ||
86 | ret = -EINVAL; | ||
87 | goto done; | ||
88 | } | ||
89 | |||
90 | ret = i2c_transfer(client->adapter, msgs, 2); | ||
91 | if (ret == 2) { | ||
92 | ret = 0; | ||
93 | } | ||
94 | |||
95 | done: | ||
96 | return ret; | ||
97 | } | ||
98 | |||
99 | static int rtc8564_write(struct i2c_client *client, unsigned char adr, | ||
100 | unsigned char *data, unsigned char len) | ||
101 | { | ||
102 | int ret = 0; | ||
103 | unsigned char _data[16]; | ||
104 | struct i2c_msg wr; | ||
105 | int i; | ||
106 | |||
107 | if (!data || len > 15) { | ||
108 | ret = -EINVAL; | ||
109 | goto done; | ||
110 | } | ||
111 | |||
112 | _DBG(1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, data, len); | ||
113 | |||
114 | _data[0] = adr; | ||
115 | for (i = 0; i < len; i++) { | ||
116 | _data[i + 1] = data[i]; | ||
117 | _DBG(5, "data[%d] = 0x%02x (%d)", i, data[i], data[i]); | ||
118 | } | ||
119 | |||
120 | wr.addr = client->addr; | ||
121 | wr.flags = 0; | ||
122 | wr.len = len + 1; | ||
123 | wr.buf = _data; | ||
124 | |||
125 | ret = i2c_transfer(client->adapter, &wr, 1); | ||
126 | if (ret == 1) { | ||
127 | ret = 0; | ||
128 | } | ||
129 | |||
130 | done: | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | static int rtc8564_attach(struct i2c_adapter *adap, int addr, int kind) | ||
135 | { | ||
136 | int ret; | ||
137 | struct i2c_client *new_client; | ||
138 | struct rtc8564_data *d; | ||
139 | unsigned char data[10]; | ||
140 | unsigned char ad[1] = { 0 }; | ||
141 | struct i2c_msg ctrl_wr[1] = { | ||
142 | {addr, 0, 2, data} | ||
143 | }; | ||
144 | struct i2c_msg ctrl_rd[2] = { | ||
145 | {addr, 0, 1, ad}, | ||
146 | {addr, I2C_M_RD, 2, data} | ||
147 | }; | ||
148 | |||
149 | d = kzalloc(sizeof(struct rtc8564_data), GFP_KERNEL); | ||
150 | if (!d) { | ||
151 | ret = -ENOMEM; | ||
152 | goto done; | ||
153 | } | ||
154 | new_client = &d->client; | ||
155 | |||
156 | strlcpy(new_client->name, "RTC8564", I2C_NAME_SIZE); | ||
157 | i2c_set_clientdata(new_client, d); | ||
158 | new_client->addr = addr; | ||
159 | new_client->adapter = adap; | ||
160 | new_client->driver = &rtc8564_driver; | ||
161 | |||
162 | _DBG(1, "client=%p", new_client); | ||
163 | |||
164 | /* init ctrl1 reg */ | ||
165 | data[0] = 0; | ||
166 | data[1] = 0; | ||
167 | ret = i2c_transfer(new_client->adapter, ctrl_wr, 1); | ||
168 | if (ret != 1) { | ||
169 | printk(KERN_INFO "rtc8564: cant init ctrl1\n"); | ||
170 | ret = -ENODEV; | ||
171 | goto done; | ||
172 | } | ||
173 | |||
174 | /* read back ctrl1 and ctrl2 */ | ||
175 | ret = i2c_transfer(new_client->adapter, ctrl_rd, 2); | ||
176 | if (ret != 2) { | ||
177 | printk(KERN_INFO "rtc8564: cant read ctrl\n"); | ||
178 | ret = -ENODEV; | ||
179 | goto done; | ||
180 | } | ||
181 | |||
182 | d->ctrl = data[0] | (data[1] << 8); | ||
183 | |||
184 | _DBG(1, "RTC8564_REG_CTRL1=%02x, RTC8564_REG_CTRL2=%02x", | ||
185 | data[0], data[1]); | ||
186 | |||
187 | ret = i2c_attach_client(new_client); | ||
188 | done: | ||
189 | if (ret) { | ||
190 | kfree(d); | ||
191 | } | ||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | static int rtc8564_probe(struct i2c_adapter *adap) | ||
196 | { | ||
197 | return i2c_probe(adap, &addr_data, rtc8564_attach); | ||
198 | } | ||
199 | |||
200 | static int rtc8564_detach(struct i2c_client *client) | ||
201 | { | ||
202 | i2c_detach_client(client); | ||
203 | kfree(i2c_get_clientdata(client)); | ||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static int rtc8564_get_datetime(struct i2c_client *client, struct rtc_tm *dt) | ||
208 | { | ||
209 | int ret = -EIO; | ||
210 | unsigned char buf[15]; | ||
211 | |||
212 | _DBG(1, "client=%p, dt=%p", client, dt); | ||
213 | |||
214 | if (!dt) | ||
215 | return -EINVAL; | ||
216 | |||
217 | memset(buf, 0, sizeof(buf)); | ||
218 | |||
219 | ret = rtc8564_read(client, 0, buf, 15); | ||
220 | if (ret) | ||
221 | return ret; | ||
222 | |||
223 | /* century stored in minute alarm reg */ | ||
224 | dt->year = BCD2BIN(buf[RTC8564_REG_YEAR]); | ||
225 | dt->year += 100 * BCD2BIN(buf[RTC8564_REG_AL_MIN] & 0x3f); | ||
226 | dt->mday = BCD2BIN(buf[RTC8564_REG_DAY] & 0x3f); | ||
227 | dt->wday = BCD2BIN(buf[RTC8564_REG_WDAY] & 7); | ||
228 | dt->mon = BCD2BIN(buf[RTC8564_REG_MON_CENT] & 0x1f); | ||
229 | |||
230 | dt->secs = BCD2BIN(buf[RTC8564_REG_SEC] & 0x7f); | ||
231 | dt->vl = (buf[RTC8564_REG_SEC] & 0x80) == 0x80; | ||
232 | dt->mins = BCD2BIN(buf[RTC8564_REG_MIN] & 0x7f); | ||
233 | dt->hours = BCD2BIN(buf[RTC8564_REG_HR] & 0x3f); | ||
234 | |||
235 | _DBGRTCTM(2, *dt); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static int | ||
241 | rtc8564_set_datetime(struct i2c_client *client, struct rtc_tm *dt, int datetoo) | ||
242 | { | ||
243 | int ret, len = 5; | ||
244 | unsigned char buf[15]; | ||
245 | |||
246 | _DBG(1, "client=%p, dt=%p", client, dt); | ||
247 | |||
248 | if (!dt) | ||
249 | return -EINVAL; | ||
250 | |||
251 | _DBGRTCTM(2, *dt); | ||
252 | |||
253 | buf[RTC8564_REG_CTRL1] = CTRL1(client) | RTC8564_CTRL1_STOP; | ||
254 | buf[RTC8564_REG_CTRL2] = CTRL2(client); | ||
255 | buf[RTC8564_REG_SEC] = BIN2BCD(dt->secs); | ||
256 | buf[RTC8564_REG_MIN] = BIN2BCD(dt->mins); | ||
257 | buf[RTC8564_REG_HR] = BIN2BCD(dt->hours); | ||
258 | |||
259 | if (datetoo) { | ||
260 | len += 5; | ||
261 | buf[RTC8564_REG_DAY] = BIN2BCD(dt->mday); | ||
262 | buf[RTC8564_REG_WDAY] = BIN2BCD(dt->wday); | ||
263 | buf[RTC8564_REG_MON_CENT] = BIN2BCD(dt->mon) & 0x1f; | ||
264 | /* century stored in minute alarm reg */ | ||
265 | buf[RTC8564_REG_YEAR] = BIN2BCD(dt->year % 100); | ||
266 | buf[RTC8564_REG_AL_MIN] = BIN2BCD(dt->year / 100); | ||
267 | } | ||
268 | |||
269 | ret = rtc8564_write(client, 0, buf, len); | ||
270 | if (ret) { | ||
271 | _DBG(1, "error writing data! %d", ret); | ||
272 | } | ||
273 | |||
274 | buf[RTC8564_REG_CTRL1] = CTRL1(client); | ||
275 | ret = rtc8564_write(client, 0, buf, 1); | ||
276 | if (ret) { | ||
277 | _DBG(1, "error writing data! %d", ret); | ||
278 | } | ||
279 | |||
280 | return ret; | ||
281 | } | ||
282 | |||
283 | static int rtc8564_get_ctrl(struct i2c_client *client, unsigned int *ctrl) | ||
284 | { | ||
285 | struct rtc8564_data *data = i2c_get_clientdata(client); | ||
286 | |||
287 | if (!ctrl) | ||
288 | return -1; | ||
289 | |||
290 | *ctrl = data->ctrl; | ||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static int rtc8564_set_ctrl(struct i2c_client *client, unsigned int *ctrl) | ||
295 | { | ||
296 | struct rtc8564_data *data = i2c_get_clientdata(client); | ||
297 | unsigned char buf[2]; | ||
298 | |||
299 | if (!ctrl) | ||
300 | return -1; | ||
301 | |||
302 | buf[0] = *ctrl & 0xff; | ||
303 | buf[1] = (*ctrl & 0xff00) >> 8; | ||
304 | data->ctrl = *ctrl; | ||
305 | |||
306 | return rtc8564_write(client, 0, buf, 2); | ||
307 | } | ||
308 | |||
309 | static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem) | ||
310 | { | ||
311 | |||
312 | if (!mem) | ||
313 | return -EINVAL; | ||
314 | |||
315 | return rtc8564_read(client, mem->loc, mem->data, mem->nr); | ||
316 | } | ||
317 | |||
318 | static int rtc8564_write_mem(struct i2c_client *client, struct mem *mem) | ||
319 | { | ||
320 | |||
321 | if (!mem) | ||
322 | return -EINVAL; | ||
323 | |||
324 | return rtc8564_write(client, mem->loc, mem->data, mem->nr); | ||
325 | } | ||
326 | |||
327 | static int | ||
328 | rtc8564_command(struct i2c_client *client, unsigned int cmd, void *arg) | ||
329 | { | ||
330 | |||
331 | _DBG(1, "cmd=%d", cmd); | ||
332 | |||
333 | switch (cmd) { | ||
334 | case RTC_GETDATETIME: | ||
335 | return rtc8564_get_datetime(client, arg); | ||
336 | |||
337 | case RTC_SETTIME: | ||
338 | return rtc8564_set_datetime(client, arg, 0); | ||
339 | |||
340 | case RTC_SETDATETIME: | ||
341 | return rtc8564_set_datetime(client, arg, 1); | ||
342 | |||
343 | case RTC_GETCTRL: | ||
344 | return rtc8564_get_ctrl(client, arg); | ||
345 | |||
346 | case RTC_SETCTRL: | ||
347 | return rtc8564_set_ctrl(client, arg); | ||
348 | |||
349 | case MEM_READ: | ||
350 | return rtc8564_read_mem(client, arg); | ||
351 | |||
352 | case MEM_WRITE: | ||
353 | return rtc8564_write_mem(client, arg); | ||
354 | |||
355 | default: | ||
356 | return -EINVAL; | ||
357 | } | ||
358 | } | ||
359 | |||
360 | static struct i2c_driver rtc8564_driver = { | ||
361 | .driver = { | ||
362 | .name = "RTC8564", | ||
363 | }, | ||
364 | .id = I2C_DRIVERID_RTC8564, | ||
365 | .attach_adapter = rtc8564_probe, | ||
366 | .detach_client = rtc8564_detach, | ||
367 | .command = rtc8564_command | ||
368 | }; | ||
369 | |||
370 | static __init int rtc8564_init(void) | ||
371 | { | ||
372 | return i2c_add_driver(&rtc8564_driver); | ||
373 | } | ||
374 | |||
375 | static __exit void rtc8564_exit(void) | ||
376 | { | ||
377 | i2c_del_driver(&rtc8564_driver); | ||
378 | } | ||
379 | |||
380 | MODULE_AUTHOR("Stefan Eletzhofer <Stefan.Eletzhofer@eletztrick.de>"); | ||
381 | MODULE_DESCRIPTION("EPSON RTC8564 Driver"); | ||
382 | MODULE_LICENSE("GPL"); | ||
383 | |||
384 | module_init(rtc8564_init); | ||
385 | module_exit(rtc8564_exit); | ||
diff --git a/drivers/i2c/chips/rtc8564.h b/drivers/i2c/chips/rtc8564.h deleted file mode 100644 index e5342d10b8fa..000000000000 --- a/drivers/i2c/chips/rtc8564.h +++ /dev/null | |||
@@ -1,78 +0,0 @@ | |||
1 | /* | ||
2 | * linux/drivers/i2c/chips/rtc8564.h | ||
3 | * | ||
4 | * Copyright (C) 2002-2004 Stefan Eletzhofer | ||
5 | * | ||
6 | * based on linux/drivers/acron/char/pcf8583.h | ||
7 | * Copyright (C) 2000 Russell King | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | struct rtc_tm { | ||
14 | unsigned char secs; | ||
15 | unsigned char mins; | ||
16 | unsigned char hours; | ||
17 | unsigned char mday; | ||
18 | unsigned char mon; | ||
19 | unsigned short year; /* xxxx 4 digits :) */ | ||
20 | unsigned char wday; | ||
21 | unsigned char vl; | ||
22 | }; | ||
23 | |||
24 | struct mem { | ||
25 | unsigned int loc; | ||
26 | unsigned int nr; | ||
27 | unsigned char *data; | ||
28 | }; | ||
29 | |||
30 | #define RTC_GETDATETIME 0 | ||
31 | #define RTC_SETTIME 1 | ||
32 | #define RTC_SETDATETIME 2 | ||
33 | #define RTC_GETCTRL 3 | ||
34 | #define RTC_SETCTRL 4 | ||
35 | #define MEM_READ 5 | ||
36 | #define MEM_WRITE 6 | ||
37 | |||
38 | #define RTC8564_REG_CTRL1 0x0 /* T 0 S 0 | T 0 0 0 */ | ||
39 | #define RTC8564_REG_CTRL2 0x1 /* 0 0 0 TI/TP | AF TF AIE TIE */ | ||
40 | #define RTC8564_REG_SEC 0x2 /* VL 4 2 1 | 8 4 2 1 */ | ||
41 | #define RTC8564_REG_MIN 0x3 /* x 4 2 1 | 8 4 2 1 */ | ||
42 | #define RTC8564_REG_HR 0x4 /* x x 2 1 | 8 4 2 1 */ | ||
43 | #define RTC8564_REG_DAY 0x5 /* x x 2 1 | 8 4 2 1 */ | ||
44 | #define RTC8564_REG_WDAY 0x6 /* x x x x | x 4 2 1 */ | ||
45 | #define RTC8564_REG_MON_CENT 0x7 /* C x x 1 | 8 4 2 1 */ | ||
46 | #define RTC8564_REG_YEAR 0x8 /* 8 4 2 1 | 8 4 2 1 */ | ||
47 | #define RTC8564_REG_AL_MIN 0x9 /* AE 4 2 1 | 8 4 2 1 */ | ||
48 | #define RTC8564_REG_AL_HR 0xa /* AE 4 2 1 | 8 4 2 1 */ | ||
49 | #define RTC8564_REG_AL_DAY 0xb /* AE x 2 1 | 8 4 2 1 */ | ||
50 | #define RTC8564_REG_AL_WDAY 0xc /* AE x x x | x 4 2 1 */ | ||
51 | #define RTC8564_REG_CLKOUT 0xd /* FE x x x | x x FD1 FD0 */ | ||
52 | #define RTC8564_REG_TCTL 0xe /* TE x x x | x x FD1 FD0 */ | ||
53 | #define RTC8564_REG_TIMER 0xf /* 8 bit binary */ | ||
54 | |||
55 | /* Control reg */ | ||
56 | #define RTC8564_CTRL1_TEST1 (1<<3) | ||
57 | #define RTC8564_CTRL1_STOP (1<<5) | ||
58 | #define RTC8564_CTRL1_TEST2 (1<<7) | ||
59 | |||
60 | #define RTC8564_CTRL2_TIE (1<<0) | ||
61 | #define RTC8564_CTRL2_AIE (1<<1) | ||
62 | #define RTC8564_CTRL2_TF (1<<2) | ||
63 | #define RTC8564_CTRL2_AF (1<<3) | ||
64 | #define RTC8564_CTRL2_TI_TP (1<<4) | ||
65 | |||
66 | /* CLKOUT frequencies */ | ||
67 | #define RTC8564_FD_32768HZ (0x0) | ||
68 | #define RTC8564_FD_1024HZ (0x1) | ||
69 | #define RTC8564_FD_32 (0x2) | ||
70 | #define RTC8564_FD_1HZ (0x3) | ||
71 | |||
72 | /* Timer CTRL */ | ||
73 | #define RTC8564_TD_4096HZ (0x0) | ||
74 | #define RTC8564_TD_64HZ (0x1) | ||
75 | #define RTC8564_TD_1HZ (0x2) | ||
76 | #define RTC8564_TD_1_60HZ (0x3) | ||
77 | |||
78 | #define I2C_DRIVERID_RTC8564 0xf000 | ||
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index d2ead1776c16..34fcabac5fdb 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c | |||
@@ -80,7 +80,7 @@ static struct adb_driver *adb_driver_list[] = { | |||
80 | static struct class *adb_dev_class; | 80 | static struct class *adb_dev_class; |
81 | 81 | ||
82 | struct adb_driver *adb_controller; | 82 | struct adb_driver *adb_controller; |
83 | struct notifier_block *adb_client_list = NULL; | 83 | BLOCKING_NOTIFIER_HEAD(adb_client_list); |
84 | static int adb_got_sleep; | 84 | static int adb_got_sleep; |
85 | static int adb_inited; | 85 | static int adb_inited; |
86 | static pid_t adb_probe_task_pid; | 86 | static pid_t adb_probe_task_pid; |
@@ -354,7 +354,8 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when) | |||
354 | /* Stop autopoll */ | 354 | /* Stop autopoll */ |
355 | if (adb_controller->autopoll) | 355 | if (adb_controller->autopoll) |
356 | adb_controller->autopoll(0); | 356 | adb_controller->autopoll(0); |
357 | ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL); | 357 | ret = blocking_notifier_call_chain(&adb_client_list, |
358 | ADB_MSG_POWERDOWN, NULL); | ||
358 | if (ret & NOTIFY_STOP_MASK) { | 359 | if (ret & NOTIFY_STOP_MASK) { |
359 | up(&adb_probe_mutex); | 360 | up(&adb_probe_mutex); |
360 | return PBOOK_SLEEP_REFUSE; | 361 | return PBOOK_SLEEP_REFUSE; |
@@ -391,7 +392,8 @@ do_adb_reset_bus(void) | |||
391 | if (adb_controller->autopoll) | 392 | if (adb_controller->autopoll) |
392 | adb_controller->autopoll(0); | 393 | adb_controller->autopoll(0); |
393 | 394 | ||
394 | nret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL); | 395 | nret = blocking_notifier_call_chain(&adb_client_list, |
396 | ADB_MSG_PRE_RESET, NULL); | ||
395 | if (nret & NOTIFY_STOP_MASK) { | 397 | if (nret & NOTIFY_STOP_MASK) { |
396 | if (adb_controller->autopoll) | 398 | if (adb_controller->autopoll) |
397 | adb_controller->autopoll(autopoll_devs); | 399 | adb_controller->autopoll(autopoll_devs); |
@@ -426,7 +428,8 @@ do_adb_reset_bus(void) | |||
426 | } | 428 | } |
427 | up(&adb_handler_sem); | 429 | up(&adb_handler_sem); |
428 | 430 | ||
429 | nret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL); | 431 | nret = blocking_notifier_call_chain(&adb_client_list, |
432 | ADB_MSG_POST_RESET, NULL); | ||
430 | if (nret & NOTIFY_STOP_MASK) | 433 | if (nret & NOTIFY_STOP_MASK) |
431 | return -EBUSY; | 434 | return -EBUSY; |
432 | 435 | ||
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index c0b46bceb5df..f5779a73184d 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c | |||
@@ -1214,7 +1214,8 @@ static int __init adbhid_init(void) | |||
1214 | 1214 | ||
1215 | adbhid_probe(); | 1215 | adbhid_probe(); |
1216 | 1216 | ||
1217 | notifier_chain_register(&adb_client_list, &adbhid_adb_notifier); | 1217 | blocking_notifier_chain_register(&adb_client_list, |
1218 | &adbhid_adb_notifier); | ||
1218 | 1219 | ||
1219 | return 0; | 1220 | return 0; |
1220 | } | 1221 | } |
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 4f5f3abc9cb3..0b5ff553e39a 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c | |||
@@ -187,7 +187,7 @@ extern int disable_kernel_backlight; | |||
187 | 187 | ||
188 | int __fake_sleep; | 188 | int __fake_sleep; |
189 | int asleep; | 189 | int asleep; |
190 | struct notifier_block *sleep_notifier_list; | 190 | BLOCKING_NOTIFIER_HEAD(sleep_notifier_list); |
191 | 191 | ||
192 | #ifdef CONFIG_ADB | 192 | #ifdef CONFIG_ADB |
193 | static int adb_dev_map = 0; | 193 | static int adb_dev_map = 0; |
diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c index f08e52f2107b..35b70323e7e3 100644 --- a/drivers/macintosh/via-pmu68k.c +++ b/drivers/macintosh/via-pmu68k.c | |||
@@ -102,7 +102,7 @@ static int pmu_kind = PMU_UNKNOWN; | |||
102 | static int pmu_fully_inited = 0; | 102 | static int pmu_fully_inited = 0; |
103 | 103 | ||
104 | int asleep; | 104 | int asleep; |
105 | struct notifier_block *sleep_notifier_list; | 105 | BLOCKING_NOTIFIER_HEAD(sleep_notifier_list); |
106 | 106 | ||
107 | static int pmu_probe(void); | 107 | static int pmu_probe(void); |
108 | static int pmu_init(void); | 108 | static int pmu_init(void); |
@@ -913,7 +913,8 @@ int powerbook_sleep(void) | |||
913 | struct adb_request sleep_req; | 913 | struct adb_request sleep_req; |
914 | 914 | ||
915 | /* Notify device drivers */ | 915 | /* Notify device drivers */ |
916 | ret = notifier_call_chain(&sleep_notifier_list, PBOOK_SLEEP, NULL); | 916 | ret = blocking_notifier_call_chain(&sleep_notifier_list, |
917 | PBOOK_SLEEP, NULL); | ||
917 | if (ret & NOTIFY_STOP_MASK) | 918 | if (ret & NOTIFY_STOP_MASK) |
918 | return -EBUSY; | 919 | return -EBUSY; |
919 | 920 | ||
@@ -984,7 +985,7 @@ int powerbook_sleep(void) | |||
984 | enable_irq(i); | 985 | enable_irq(i); |
985 | 986 | ||
986 | /* Notify drivers */ | 987 | /* Notify drivers */ |
987 | notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL); | 988 | blocking_notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL); |
988 | 989 | ||
989 | /* reenable ADB autopoll */ | 990 | /* reenable ADB autopoll */ |
990 | pmu_adb_autopoll(adb_dev_map); | 991 | pmu_adb_autopoll(adb_dev_map); |
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c index 6c0ba04bc57a..ab3faa702d58 100644 --- a/drivers/macintosh/windfarm_core.c +++ b/drivers/macintosh/windfarm_core.c | |||
@@ -52,7 +52,7 @@ | |||
52 | static LIST_HEAD(wf_controls); | 52 | static LIST_HEAD(wf_controls); |
53 | static LIST_HEAD(wf_sensors); | 53 | static LIST_HEAD(wf_sensors); |
54 | static DEFINE_MUTEX(wf_lock); | 54 | static DEFINE_MUTEX(wf_lock); |
55 | static struct notifier_block *wf_client_list; | 55 | static BLOCKING_NOTIFIER_HEAD(wf_client_list); |
56 | static int wf_client_count; | 56 | static int wf_client_count; |
57 | static unsigned int wf_overtemp; | 57 | static unsigned int wf_overtemp; |
58 | static unsigned int wf_overtemp_counter; | 58 | static unsigned int wf_overtemp_counter; |
@@ -68,7 +68,7 @@ static struct platform_device wf_platform_device = { | |||
68 | 68 | ||
69 | static inline void wf_notify(int event, void *param) | 69 | static inline void wf_notify(int event, void *param) |
70 | { | 70 | { |
71 | notifier_call_chain(&wf_client_list, event, param); | 71 | blocking_notifier_call_chain(&wf_client_list, event, param); |
72 | } | 72 | } |
73 | 73 | ||
74 | int wf_critical_overtemp(void) | 74 | int wf_critical_overtemp(void) |
@@ -398,7 +398,7 @@ int wf_register_client(struct notifier_block *nb) | |||
398 | struct wf_sensor *sr; | 398 | struct wf_sensor *sr; |
399 | 399 | ||
400 | mutex_lock(&wf_lock); | 400 | mutex_lock(&wf_lock); |
401 | rc = notifier_chain_register(&wf_client_list, nb); | 401 | rc = blocking_notifier_chain_register(&wf_client_list, nb); |
402 | if (rc != 0) | 402 | if (rc != 0) |
403 | goto bail; | 403 | goto bail; |
404 | wf_client_count++; | 404 | wf_client_count++; |
@@ -417,7 +417,7 @@ EXPORT_SYMBOL_GPL(wf_register_client); | |||
417 | int wf_unregister_client(struct notifier_block *nb) | 417 | int wf_unregister_client(struct notifier_block *nb) |
418 | { | 418 | { |
419 | mutex_lock(&wf_lock); | 419 | mutex_lock(&wf_lock); |
420 | notifier_chain_unregister(&wf_client_list, nb); | 420 | blocking_notifier_chain_unregister(&wf_client_list, nb); |
421 | wf_client_count++; | 421 | wf_client_count++; |
422 | if (wf_client_count == 0) | 422 | if (wf_client_count == 0) |
423 | wf_stop_thread(); | 423 | wf_stop_thread(); |
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index ac43f98062fd..fd2aae150ccc 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig | |||
@@ -127,6 +127,32 @@ config MD_RAID5 | |||
127 | 127 | ||
128 | If unsure, say Y. | 128 | If unsure, say Y. |
129 | 129 | ||
130 | config MD_RAID5_RESHAPE | ||
131 | bool "Support adding drives to a raid-5 array (experimental)" | ||
132 | depends on MD_RAID5 && EXPERIMENTAL | ||
133 | ---help--- | ||
134 | A RAID-5 set can be expanded by adding extra drives. This | ||
135 | requires "restriping" the array which means (almost) every | ||
136 | block must be written to a different place. | ||
137 | |||
138 | This option allows such restriping to be done while the array | ||
139 | is online. However it is still EXPERIMENTAL code. It should | ||
140 | work, but please be sure that you have backups. | ||
141 | |||
142 | You will need a version of mdadm newer than 2.3.1. During the | ||
143 | early stage of reshape there is a critical section where live data | ||
144 | is being over-written. A crash during this time needs extra care | ||
145 | for recovery. The newer mdadm takes a copy of the data in the | ||
146 | critical section and will restore it, if necessary, after a crash. | ||
147 | |||
148 | The mdadm usage is e.g. | ||
149 | mdadm --grow /dev/md1 --raid-disks=6 | ||
150 | to grow '/dev/md1' to having 6 disks. | ||
151 | |||
152 | Note: The array can only be expanded, not contracted. | ||
153 | There should be enough spares already present to make the new | ||
154 | array workable. | ||
155 | |||
130 | config MD_RAID6 | 156 | config MD_RAID6 |
131 | tristate "RAID-6 mode" | 157 | tristate "RAID-6 mode" |
132 | depends on BLK_DEV_MD | 158 | depends on BLK_DEV_MD |
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 259e86f26549..61a590bb6241 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c | |||
@@ -518,6 +518,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
518 | char *ivopts; | 518 | char *ivopts; |
519 | unsigned int crypto_flags; | 519 | unsigned int crypto_flags; |
520 | unsigned int key_size; | 520 | unsigned int key_size; |
521 | unsigned long long tmpll; | ||
521 | 522 | ||
522 | if (argc != 5) { | 523 | if (argc != 5) { |
523 | ti->error = PFX "Not enough arguments"; | 524 | ti->error = PFX "Not enough arguments"; |
@@ -633,15 +634,17 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
633 | goto bad5; | 634 | goto bad5; |
634 | } | 635 | } |
635 | 636 | ||
636 | if (sscanf(argv[2], SECTOR_FORMAT, &cc->iv_offset) != 1) { | 637 | if (sscanf(argv[2], "%llu", &tmpll) != 1) { |
637 | ti->error = PFX "Invalid iv_offset sector"; | 638 | ti->error = PFX "Invalid iv_offset sector"; |
638 | goto bad5; | 639 | goto bad5; |
639 | } | 640 | } |
641 | cc->iv_offset = tmpll; | ||
640 | 642 | ||
641 | if (sscanf(argv[4], SECTOR_FORMAT, &cc->start) != 1) { | 643 | if (sscanf(argv[4], "%llu", &tmpll) != 1) { |
642 | ti->error = PFX "Invalid device sector"; | 644 | ti->error = PFX "Invalid device sector"; |
643 | goto bad5; | 645 | goto bad5; |
644 | } | 646 | } |
647 | cc->start = tmpll; | ||
645 | 648 | ||
646 | if (dm_get_device(ti, argv[3], cc->start, ti->len, | 649 | if (dm_get_device(ti, argv[3], cc->start, ti->len, |
647 | dm_table_get_mode(ti->table), &cc->dev)) { | 650 | dm_table_get_mode(ti->table), &cc->dev)) { |
@@ -885,8 +888,8 @@ static int crypt_status(struct dm_target *ti, status_type_t type, | |||
885 | result[sz++] = '-'; | 888 | result[sz++] = '-'; |
886 | } | 889 | } |
887 | 890 | ||
888 | DMEMIT(" " SECTOR_FORMAT " %s " SECTOR_FORMAT, | 891 | DMEMIT(" %llu %s %llu", (unsigned long long)cc->iv_offset, |
889 | cc->iv_offset, cc->dev->name, cc->start); | 892 | cc->dev->name, (unsigned long long)cc->start); |
890 | break; | 893 | break; |
891 | } | 894 | } |
892 | return 0; | 895 | return 0; |
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 442e2be6052e..8edd6435414d 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/devfs_fs_kernel.h> | 16 | #include <linux/devfs_fs_kernel.h> |
17 | #include <linux/dm-ioctl.h> | 17 | #include <linux/dm-ioctl.h> |
18 | #include <linux/hdreg.h> | ||
18 | 19 | ||
19 | #include <asm/uaccess.h> | 20 | #include <asm/uaccess.h> |
20 | 21 | ||
@@ -244,9 +245,9 @@ static void __hash_remove(struct hash_cell *hc) | |||
244 | dm_table_put(table); | 245 | dm_table_put(table); |
245 | } | 246 | } |
246 | 247 | ||
247 | dm_put(hc->md); | ||
248 | if (hc->new_map) | 248 | if (hc->new_map) |
249 | dm_table_put(hc->new_map); | 249 | dm_table_put(hc->new_map); |
250 | dm_put(hc->md); | ||
250 | free_cell(hc); | 251 | free_cell(hc); |
251 | } | 252 | } |
252 | 253 | ||
@@ -600,12 +601,22 @@ static int dev_create(struct dm_ioctl *param, size_t param_size) | |||
600 | */ | 601 | */ |
601 | static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param) | 602 | static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param) |
602 | { | 603 | { |
604 | struct mapped_device *md; | ||
605 | void *mdptr = NULL; | ||
606 | |||
603 | if (*param->uuid) | 607 | if (*param->uuid) |
604 | return __get_uuid_cell(param->uuid); | 608 | return __get_uuid_cell(param->uuid); |
605 | else if (*param->name) | 609 | |
610 | if (*param->name) | ||
606 | return __get_name_cell(param->name); | 611 | return __get_name_cell(param->name); |
607 | else | 612 | |
608 | return dm_get_mdptr(huge_decode_dev(param->dev)); | 613 | md = dm_get_md(huge_decode_dev(param->dev)); |
614 | if (md) { | ||
615 | mdptr = dm_get_mdptr(md); | ||
616 | dm_put(md); | ||
617 | } | ||
618 | |||
619 | return mdptr; | ||
609 | } | 620 | } |
610 | 621 | ||
611 | static struct mapped_device *find_device(struct dm_ioctl *param) | 622 | static struct mapped_device *find_device(struct dm_ioctl *param) |
@@ -690,6 +701,54 @@ static int dev_rename(struct dm_ioctl *param, size_t param_size) | |||
690 | return dm_hash_rename(param->name, new_name); | 701 | return dm_hash_rename(param->name, new_name); |
691 | } | 702 | } |
692 | 703 | ||
704 | static int dev_set_geometry(struct dm_ioctl *param, size_t param_size) | ||
705 | { | ||
706 | int r = -EINVAL, x; | ||
707 | struct mapped_device *md; | ||
708 | struct hd_geometry geometry; | ||
709 | unsigned long indata[4]; | ||
710 | char *geostr = (char *) param + param->data_start; | ||
711 | |||
712 | md = find_device(param); | ||
713 | if (!md) | ||
714 | return -ENXIO; | ||
715 | |||
716 | if (geostr < (char *) (param + 1) || | ||
717 | invalid_str(geostr, (void *) param + param_size)) { | ||
718 | DMWARN("Invalid geometry supplied."); | ||
719 | goto out; | ||
720 | } | ||
721 | |||
722 | x = sscanf(geostr, "%lu %lu %lu %lu", indata, | ||
723 | indata + 1, indata + 2, indata + 3); | ||
724 | |||
725 | if (x != 4) { | ||
726 | DMWARN("Unable to interpret geometry settings."); | ||
727 | goto out; | ||
728 | } | ||
729 | |||
730 | if (indata[0] > 65535 || indata[1] > 255 || | ||
731 | indata[2] > 255 || indata[3] > ULONG_MAX) { | ||
732 | DMWARN("Geometry exceeds range limits."); | ||
733 | goto out; | ||
734 | } | ||
735 | |||
736 | geometry.cylinders = indata[0]; | ||
737 | geometry.heads = indata[1]; | ||
738 | geometry.sectors = indata[2]; | ||
739 | geometry.start = indata[3]; | ||
740 | |||
741 | r = dm_set_geometry(md, &geometry); | ||
742 | if (!r) | ||
743 | r = __dev_status(md, param); | ||
744 | |||
745 | param->data_size = 0; | ||
746 | |||
747 | out: | ||
748 | dm_put(md); | ||
749 | return r; | ||
750 | } | ||
751 | |||
693 | static int do_suspend(struct dm_ioctl *param) | 752 | static int do_suspend(struct dm_ioctl *param) |
694 | { | 753 | { |
695 | int r = 0; | 754 | int r = 0; |
@@ -975,33 +1034,43 @@ static int table_load(struct dm_ioctl *param, size_t param_size) | |||
975 | int r; | 1034 | int r; |
976 | struct hash_cell *hc; | 1035 | struct hash_cell *hc; |
977 | struct dm_table *t; | 1036 | struct dm_table *t; |
1037 | struct mapped_device *md; | ||
978 | 1038 | ||
979 | r = dm_table_create(&t, get_mode(param), param->target_count); | 1039 | md = find_device(param); |
1040 | if (!md) | ||
1041 | return -ENXIO; | ||
1042 | |||
1043 | r = dm_table_create(&t, get_mode(param), param->target_count, md); | ||
980 | if (r) | 1044 | if (r) |
981 | return r; | 1045 | goto out; |
982 | 1046 | ||
983 | r = populate_table(t, param, param_size); | 1047 | r = populate_table(t, param, param_size); |
984 | if (r) { | 1048 | if (r) { |
985 | dm_table_put(t); | 1049 | dm_table_put(t); |
986 | return r; | 1050 | goto out; |
987 | } | 1051 | } |
988 | 1052 | ||
989 | down_write(&_hash_lock); | 1053 | down_write(&_hash_lock); |
990 | hc = __find_device_hash_cell(param); | 1054 | hc = dm_get_mdptr(md); |
991 | if (!hc) { | 1055 | if (!hc || hc->md != md) { |
992 | DMWARN("device doesn't appear to be in the dev hash table."); | 1056 | DMWARN("device has been removed from the dev hash table."); |
993 | up_write(&_hash_lock); | ||
994 | dm_table_put(t); | 1057 | dm_table_put(t); |
995 | return -ENXIO; | 1058 | up_write(&_hash_lock); |
1059 | r = -ENXIO; | ||
1060 | goto out; | ||
996 | } | 1061 | } |
997 | 1062 | ||
998 | if (hc->new_map) | 1063 | if (hc->new_map) |
999 | dm_table_put(hc->new_map); | 1064 | dm_table_put(hc->new_map); |
1000 | hc->new_map = t; | 1065 | hc->new_map = t; |
1066 | up_write(&_hash_lock); | ||
1067 | |||
1001 | param->flags |= DM_INACTIVE_PRESENT_FLAG; | 1068 | param->flags |= DM_INACTIVE_PRESENT_FLAG; |
1069 | r = __dev_status(md, param); | ||
1070 | |||
1071 | out: | ||
1072 | dm_put(md); | ||
1002 | 1073 | ||
1003 | r = __dev_status(hc->md, param); | ||
1004 | up_write(&_hash_lock); | ||
1005 | return r; | 1074 | return r; |
1006 | } | 1075 | } |
1007 | 1076 | ||
@@ -1214,7 +1283,8 @@ static ioctl_fn lookup_ioctl(unsigned int cmd) | |||
1214 | 1283 | ||
1215 | {DM_LIST_VERSIONS_CMD, list_versions}, | 1284 | {DM_LIST_VERSIONS_CMD, list_versions}, |
1216 | 1285 | ||
1217 | {DM_TARGET_MSG_CMD, target_message} | 1286 | {DM_TARGET_MSG_CMD, target_message}, |
1287 | {DM_DEV_SET_GEOMETRY_CMD, dev_set_geometry} | ||
1218 | }; | 1288 | }; |
1219 | 1289 | ||
1220 | return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn; | 1290 | return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn; |
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index 6a2cd5dc8a63..daf586c0898d 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c | |||
@@ -26,6 +26,7 @@ struct linear_c { | |||
26 | static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) | 26 | static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) |
27 | { | 27 | { |
28 | struct linear_c *lc; | 28 | struct linear_c *lc; |
29 | unsigned long long tmp; | ||
29 | 30 | ||
30 | if (argc != 2) { | 31 | if (argc != 2) { |
31 | ti->error = "dm-linear: Invalid argument count"; | 32 | ti->error = "dm-linear: Invalid argument count"; |
@@ -38,10 +39,11 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
38 | return -ENOMEM; | 39 | return -ENOMEM; |
39 | } | 40 | } |
40 | 41 | ||
41 | if (sscanf(argv[1], SECTOR_FORMAT, &lc->start) != 1) { | 42 | if (sscanf(argv[1], "%llu", &tmp) != 1) { |
42 | ti->error = "dm-linear: Invalid device sector"; | 43 | ti->error = "dm-linear: Invalid device sector"; |
43 | goto bad; | 44 | goto bad; |
44 | } | 45 | } |
46 | lc->start = tmp; | ||
45 | 47 | ||
46 | if (dm_get_device(ti, argv[0], lc->start, ti->len, | 48 | if (dm_get_device(ti, argv[0], lc->start, ti->len, |
47 | dm_table_get_mode(ti->table), &lc->dev)) { | 49 | dm_table_get_mode(ti->table), &lc->dev)) { |
@@ -87,8 +89,8 @@ static int linear_status(struct dm_target *ti, status_type_t type, | |||
87 | break; | 89 | break; |
88 | 90 | ||
89 | case STATUSTYPE_TABLE: | 91 | case STATUSTYPE_TABLE: |
90 | snprintf(result, maxlen, "%s " SECTOR_FORMAT, lc->dev->name, | 92 | snprintf(result, maxlen, "%s %llu", lc->dev->name, |
91 | lc->start); | 93 | (unsigned long long)lc->start); |
92 | break; | 94 | break; |
93 | } | 95 | } |
94 | return 0; | 96 | return 0; |
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 4e90f231fbfb..d12cf3e5e076 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c | |||
@@ -402,9 +402,21 @@ static void rh_dec(struct region_hash *rh, region_t region) | |||
402 | 402 | ||
403 | spin_lock_irqsave(&rh->region_lock, flags); | 403 | spin_lock_irqsave(&rh->region_lock, flags); |
404 | if (atomic_dec_and_test(®->pending)) { | 404 | if (atomic_dec_and_test(®->pending)) { |
405 | /* | ||
406 | * There is no pending I/O for this region. | ||
407 | * We can move the region to corresponding list for next action. | ||
408 | * At this point, the region is not yet connected to any list. | ||
409 | * | ||
410 | * If the state is RH_NOSYNC, the region should be kept off | ||
411 | * from clean list. | ||
412 | * The hash entry for RH_NOSYNC will remain in memory | ||
413 | * until the region is recovered or the map is reloaded. | ||
414 | */ | ||
415 | |||
416 | /* do nothing for RH_NOSYNC */ | ||
405 | if (reg->state == RH_RECOVERING) { | 417 | if (reg->state == RH_RECOVERING) { |
406 | list_add_tail(®->list, &rh->quiesced_regions); | 418 | list_add_tail(®->list, &rh->quiesced_regions); |
407 | } else { | 419 | } else if (reg->state == RH_DIRTY) { |
408 | reg->state = RH_CLEAN; | 420 | reg->state = RH_CLEAN; |
409 | list_add(®->list, &rh->clean_regions); | 421 | list_add(®->list, &rh->clean_regions); |
410 | } | 422 | } |
@@ -922,9 +934,9 @@ static inline int _check_region_size(struct dm_target *ti, uint32_t size) | |||
922 | static int get_mirror(struct mirror_set *ms, struct dm_target *ti, | 934 | static int get_mirror(struct mirror_set *ms, struct dm_target *ti, |
923 | unsigned int mirror, char **argv) | 935 | unsigned int mirror, char **argv) |
924 | { | 936 | { |
925 | sector_t offset; | 937 | unsigned long long offset; |
926 | 938 | ||
927 | if (sscanf(argv[1], SECTOR_FORMAT, &offset) != 1) { | 939 | if (sscanf(argv[1], "%llu", &offset) != 1) { |
928 | ti->error = "dm-mirror: Invalid offset"; | 940 | ti->error = "dm-mirror: Invalid offset"; |
929 | return -EINVAL; | 941 | return -EINVAL; |
930 | } | 942 | } |
@@ -1191,16 +1203,17 @@ static int mirror_status(struct dm_target *ti, status_type_t type, | |||
1191 | for (m = 0; m < ms->nr_mirrors; m++) | 1203 | for (m = 0; m < ms->nr_mirrors; m++) |
1192 | DMEMIT("%s ", ms->mirror[m].dev->name); | 1204 | DMEMIT("%s ", ms->mirror[m].dev->name); |
1193 | 1205 | ||
1194 | DMEMIT(SECTOR_FORMAT "/" SECTOR_FORMAT, | 1206 | DMEMIT("%llu/%llu", |
1195 | ms->rh.log->type->get_sync_count(ms->rh.log), | 1207 | (unsigned long long)ms->rh.log->type-> |
1196 | ms->nr_regions); | 1208 | get_sync_count(ms->rh.log), |
1209 | (unsigned long long)ms->nr_regions); | ||
1197 | break; | 1210 | break; |
1198 | 1211 | ||
1199 | case STATUSTYPE_TABLE: | 1212 | case STATUSTYPE_TABLE: |
1200 | DMEMIT("%d ", ms->nr_mirrors); | 1213 | DMEMIT("%d ", ms->nr_mirrors); |
1201 | for (m = 0; m < ms->nr_mirrors; m++) | 1214 | for (m = 0; m < ms->nr_mirrors; m++) |
1202 | DMEMIT("%s " SECTOR_FORMAT " ", | 1215 | DMEMIT("%s %llu ", ms->mirror[m].dev->name, |
1203 | ms->mirror[m].dev->name, ms->mirror[m].offset); | 1216 | (unsigned long long)ms->mirror[m].offset); |
1204 | } | 1217 | } |
1205 | 1218 | ||
1206 | return 0; | 1219 | return 0; |
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 7401540086df..08312b46463a 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -49,11 +49,26 @@ struct pending_exception { | |||
49 | struct bio_list snapshot_bios; | 49 | struct bio_list snapshot_bios; |
50 | 50 | ||
51 | /* | 51 | /* |
52 | * Other pending_exceptions that are processing this | 52 | * Short-term queue of pending exceptions prior to submission. |
53 | * chunk. When this list is empty, we know we can | ||
54 | * complete the origins. | ||
55 | */ | 53 | */ |
56 | struct list_head siblings; | 54 | struct list_head list; |
55 | |||
56 | /* | ||
57 | * The primary pending_exception is the one that holds | ||
58 | * the sibling_count and the list of origin_bios for a | ||
59 | * group of pending_exceptions. It is always last to get freed. | ||
60 | * These fields get set up when writing to the origin. | ||
61 | */ | ||
62 | struct pending_exception *primary_pe; | ||
63 | |||
64 | /* | ||
65 | * Number of pending_exceptions processing this chunk. | ||
66 | * When this drops to zero we must complete the origin bios. | ||
67 | * If incrementing or decrementing this, hold pe->snap->lock for | ||
68 | * the sibling concerned and not pe->primary_pe->snap->lock unless | ||
69 | * they are the same. | ||
70 | */ | ||
71 | atomic_t sibling_count; | ||
57 | 72 | ||
58 | /* Pointer back to snapshot context */ | 73 | /* Pointer back to snapshot context */ |
59 | struct dm_snapshot *snap; | 74 | struct dm_snapshot *snap; |
@@ -377,6 +392,8 @@ static void read_snapshot_metadata(struct dm_snapshot *s) | |||
377 | down_write(&s->lock); | 392 | down_write(&s->lock); |
378 | s->valid = 0; | 393 | s->valid = 0; |
379 | up_write(&s->lock); | 394 | up_write(&s->lock); |
395 | |||
396 | dm_table_event(s->table); | ||
380 | } | 397 | } |
381 | } | 398 | } |
382 | 399 | ||
@@ -542,8 +559,12 @@ static void snapshot_dtr(struct dm_target *ti) | |||
542 | { | 559 | { |
543 | struct dm_snapshot *s = (struct dm_snapshot *) ti->private; | 560 | struct dm_snapshot *s = (struct dm_snapshot *) ti->private; |
544 | 561 | ||
562 | /* Prevent further origin writes from using this snapshot. */ | ||
563 | /* After this returns there can be no new kcopyd jobs. */ | ||
545 | unregister_snapshot(s); | 564 | unregister_snapshot(s); |
546 | 565 | ||
566 | kcopyd_client_destroy(s->kcopyd_client); | ||
567 | |||
547 | exit_exception_table(&s->pending, pending_cache); | 568 | exit_exception_table(&s->pending, pending_cache); |
548 | exit_exception_table(&s->complete, exception_cache); | 569 | exit_exception_table(&s->complete, exception_cache); |
549 | 570 | ||
@@ -552,7 +573,7 @@ static void snapshot_dtr(struct dm_target *ti) | |||
552 | 573 | ||
553 | dm_put_device(ti, s->origin); | 574 | dm_put_device(ti, s->origin); |
554 | dm_put_device(ti, s->cow); | 575 | dm_put_device(ti, s->cow); |
555 | kcopyd_client_destroy(s->kcopyd_client); | 576 | |
556 | kfree(s); | 577 | kfree(s); |
557 | } | 578 | } |
558 | 579 | ||
@@ -586,78 +607,117 @@ static void error_bios(struct bio *bio) | |||
586 | } | 607 | } |
587 | } | 608 | } |
588 | 609 | ||
610 | static inline void error_snapshot_bios(struct pending_exception *pe) | ||
611 | { | ||
612 | error_bios(bio_list_get(&pe->snapshot_bios)); | ||
613 | } | ||
614 | |||
589 | static struct bio *__flush_bios(struct pending_exception *pe) | 615 | static struct bio *__flush_bios(struct pending_exception *pe) |
590 | { | 616 | { |
591 | struct pending_exception *sibling; | 617 | /* |
618 | * If this pe is involved in a write to the origin and | ||
619 | * it is the last sibling to complete then release | ||
620 | * the bios for the original write to the origin. | ||
621 | */ | ||
622 | |||
623 | if (pe->primary_pe && | ||
624 | atomic_dec_and_test(&pe->primary_pe->sibling_count)) | ||
625 | return bio_list_get(&pe->primary_pe->origin_bios); | ||
626 | |||
627 | return NULL; | ||
628 | } | ||
629 | |||
630 | static void __invalidate_snapshot(struct dm_snapshot *s, | ||
631 | struct pending_exception *pe, int err) | ||
632 | { | ||
633 | if (!s->valid) | ||
634 | return; | ||
592 | 635 | ||
593 | if (list_empty(&pe->siblings)) | 636 | if (err == -EIO) |
594 | return bio_list_get(&pe->origin_bios); | 637 | DMERR("Invalidating snapshot: Error reading/writing."); |
638 | else if (err == -ENOMEM) | ||
639 | DMERR("Invalidating snapshot: Unable to allocate exception."); | ||
595 | 640 | ||
596 | sibling = list_entry(pe->siblings.next, | 641 | if (pe) |
597 | struct pending_exception, siblings); | 642 | remove_exception(&pe->e); |
598 | 643 | ||
599 | list_del(&pe->siblings); | 644 | if (s->store.drop_snapshot) |
645 | s->store.drop_snapshot(&s->store); | ||
600 | 646 | ||
601 | /* This is fine as long as kcopyd is single-threaded. If kcopyd | 647 | s->valid = 0; |
602 | * becomes multi-threaded, we'll need some locking here. | ||
603 | */ | ||
604 | bio_list_merge(&sibling->origin_bios, &pe->origin_bios); | ||
605 | 648 | ||
606 | return NULL; | 649 | dm_table_event(s->table); |
607 | } | 650 | } |
608 | 651 | ||
609 | static void pending_complete(struct pending_exception *pe, int success) | 652 | static void pending_complete(struct pending_exception *pe, int success) |
610 | { | 653 | { |
611 | struct exception *e; | 654 | struct exception *e; |
655 | struct pending_exception *primary_pe; | ||
612 | struct dm_snapshot *s = pe->snap; | 656 | struct dm_snapshot *s = pe->snap; |
613 | struct bio *flush = NULL; | 657 | struct bio *flush = NULL; |
614 | 658 | ||
615 | if (success) { | 659 | if (!success) { |
616 | e = alloc_exception(); | 660 | /* Read/write error - snapshot is unusable */ |
617 | if (!e) { | ||
618 | DMWARN("Unable to allocate exception."); | ||
619 | down_write(&s->lock); | ||
620 | s->store.drop_snapshot(&s->store); | ||
621 | s->valid = 0; | ||
622 | flush = __flush_bios(pe); | ||
623 | up_write(&s->lock); | ||
624 | |||
625 | error_bios(bio_list_get(&pe->snapshot_bios)); | ||
626 | goto out; | ||
627 | } | ||
628 | *e = pe->e; | ||
629 | |||
630 | /* | ||
631 | * Add a proper exception, and remove the | ||
632 | * in-flight exception from the list. | ||
633 | */ | ||
634 | down_write(&s->lock); | 661 | down_write(&s->lock); |
635 | insert_exception(&s->complete, e); | 662 | __invalidate_snapshot(s, pe, -EIO); |
636 | remove_exception(&pe->e); | ||
637 | flush = __flush_bios(pe); | 663 | flush = __flush_bios(pe); |
638 | |||
639 | /* Submit any pending write bios */ | ||
640 | up_write(&s->lock); | 664 | up_write(&s->lock); |
641 | 665 | ||
642 | flush_bios(bio_list_get(&pe->snapshot_bios)); | 666 | error_snapshot_bios(pe); |
643 | } else { | 667 | goto out; |
644 | /* Read/write error - snapshot is unusable */ | 668 | } |
669 | |||
670 | e = alloc_exception(); | ||
671 | if (!e) { | ||
645 | down_write(&s->lock); | 672 | down_write(&s->lock); |
646 | if (s->valid) | 673 | __invalidate_snapshot(s, pe, -ENOMEM); |
647 | DMERR("Error reading/writing snapshot"); | ||
648 | s->store.drop_snapshot(&s->store); | ||
649 | s->valid = 0; | ||
650 | remove_exception(&pe->e); | ||
651 | flush = __flush_bios(pe); | 674 | flush = __flush_bios(pe); |
652 | up_write(&s->lock); | 675 | up_write(&s->lock); |
653 | 676 | ||
654 | error_bios(bio_list_get(&pe->snapshot_bios)); | 677 | error_snapshot_bios(pe); |
678 | goto out; | ||
679 | } | ||
680 | *e = pe->e; | ||
655 | 681 | ||
656 | dm_table_event(s->table); | 682 | /* |
683 | * Add a proper exception, and remove the | ||
684 | * in-flight exception from the list. | ||
685 | */ | ||
686 | down_write(&s->lock); | ||
687 | if (!s->valid) { | ||
688 | flush = __flush_bios(pe); | ||
689 | up_write(&s->lock); | ||
690 | |||
691 | free_exception(e); | ||
692 | |||
693 | error_snapshot_bios(pe); | ||
694 | goto out; | ||
657 | } | 695 | } |
658 | 696 | ||
697 | insert_exception(&s->complete, e); | ||
698 | remove_exception(&pe->e); | ||
699 | flush = __flush_bios(pe); | ||
700 | |||
701 | up_write(&s->lock); | ||
702 | |||
703 | /* Submit any pending write bios */ | ||
704 | flush_bios(bio_list_get(&pe->snapshot_bios)); | ||
705 | |||
659 | out: | 706 | out: |
660 | free_pending_exception(pe); | 707 | primary_pe = pe->primary_pe; |
708 | |||
709 | /* | ||
710 | * Free the pe if it's not linked to an origin write or if | ||
711 | * it's not itself a primary pe. | ||
712 | */ | ||
713 | if (!primary_pe || primary_pe != pe) | ||
714 | free_pending_exception(pe); | ||
715 | |||
716 | /* | ||
717 | * Free the primary pe if nothing references it. | ||
718 | */ | ||
719 | if (primary_pe && !atomic_read(&primary_pe->sibling_count)) | ||
720 | free_pending_exception(primary_pe); | ||
661 | 721 | ||
662 | if (flush) | 722 | if (flush) |
663 | flush_bios(flush); | 723 | flush_bios(flush); |
@@ -734,38 +794,45 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio) | |||
734 | if (e) { | 794 | if (e) { |
735 | /* cast the exception to a pending exception */ | 795 | /* cast the exception to a pending exception */ |
736 | pe = container_of(e, struct pending_exception, e); | 796 | pe = container_of(e, struct pending_exception, e); |
797 | goto out; | ||
798 | } | ||
737 | 799 | ||
738 | } else { | 800 | /* |
739 | /* | 801 | * Create a new pending exception, we don't want |
740 | * Create a new pending exception, we don't want | 802 | * to hold the lock while we do this. |
741 | * to hold the lock while we do this. | 803 | */ |
742 | */ | 804 | up_write(&s->lock); |
743 | up_write(&s->lock); | 805 | pe = alloc_pending_exception(); |
744 | pe = alloc_pending_exception(); | 806 | down_write(&s->lock); |
745 | down_write(&s->lock); | ||
746 | 807 | ||
747 | e = lookup_exception(&s->pending, chunk); | 808 | if (!s->valid) { |
748 | if (e) { | 809 | free_pending_exception(pe); |
749 | free_pending_exception(pe); | 810 | return NULL; |
750 | pe = container_of(e, struct pending_exception, e); | 811 | } |
751 | } else { | ||
752 | pe->e.old_chunk = chunk; | ||
753 | bio_list_init(&pe->origin_bios); | ||
754 | bio_list_init(&pe->snapshot_bios); | ||
755 | INIT_LIST_HEAD(&pe->siblings); | ||
756 | pe->snap = s; | ||
757 | pe->started = 0; | ||
758 | |||
759 | if (s->store.prepare_exception(&s->store, &pe->e)) { | ||
760 | free_pending_exception(pe); | ||
761 | s->valid = 0; | ||
762 | return NULL; | ||
763 | } | ||
764 | 812 | ||
765 | insert_exception(&s->pending, &pe->e); | 813 | e = lookup_exception(&s->pending, chunk); |
766 | } | 814 | if (e) { |
815 | free_pending_exception(pe); | ||
816 | pe = container_of(e, struct pending_exception, e); | ||
817 | goto out; | ||
818 | } | ||
819 | |||
820 | pe->e.old_chunk = chunk; | ||
821 | bio_list_init(&pe->origin_bios); | ||
822 | bio_list_init(&pe->snapshot_bios); | ||
823 | pe->primary_pe = NULL; | ||
824 | atomic_set(&pe->sibling_count, 1); | ||
825 | pe->snap = s; | ||
826 | pe->started = 0; | ||
827 | |||
828 | if (s->store.prepare_exception(&s->store, &pe->e)) { | ||
829 | free_pending_exception(pe); | ||
830 | return NULL; | ||
767 | } | 831 | } |
768 | 832 | ||
833 | insert_exception(&s->pending, &pe->e); | ||
834 | |||
835 | out: | ||
769 | return pe; | 836 | return pe; |
770 | } | 837 | } |
771 | 838 | ||
@@ -782,13 +849,15 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio, | |||
782 | { | 849 | { |
783 | struct exception *e; | 850 | struct exception *e; |
784 | struct dm_snapshot *s = (struct dm_snapshot *) ti->private; | 851 | struct dm_snapshot *s = (struct dm_snapshot *) ti->private; |
852 | int copy_needed = 0; | ||
785 | int r = 1; | 853 | int r = 1; |
786 | chunk_t chunk; | 854 | chunk_t chunk; |
787 | struct pending_exception *pe; | 855 | struct pending_exception *pe = NULL; |
788 | 856 | ||
789 | chunk = sector_to_chunk(s, bio->bi_sector); | 857 | chunk = sector_to_chunk(s, bio->bi_sector); |
790 | 858 | ||
791 | /* Full snapshots are not usable */ | 859 | /* Full snapshots are not usable */ |
860 | /* To get here the table must be live so s->active is always set. */ | ||
792 | if (!s->valid) | 861 | if (!s->valid) |
793 | return -EIO; | 862 | return -EIO; |
794 | 863 | ||
@@ -806,36 +875,41 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio, | |||
806 | * to copy an exception */ | 875 | * to copy an exception */ |
807 | down_write(&s->lock); | 876 | down_write(&s->lock); |
808 | 877 | ||
878 | if (!s->valid) { | ||
879 | r = -EIO; | ||
880 | goto out_unlock; | ||
881 | } | ||
882 | |||
809 | /* If the block is already remapped - use that, else remap it */ | 883 | /* If the block is already remapped - use that, else remap it */ |
810 | e = lookup_exception(&s->complete, chunk); | 884 | e = lookup_exception(&s->complete, chunk); |
811 | if (e) { | 885 | if (e) { |
812 | remap_exception(s, e, bio); | 886 | remap_exception(s, e, bio); |
813 | up_write(&s->lock); | 887 | goto out_unlock; |
814 | 888 | } | |
815 | } else { | 889 | |
816 | pe = __find_pending_exception(s, bio); | 890 | pe = __find_pending_exception(s, bio); |
817 | 891 | if (!pe) { | |
818 | if (!pe) { | 892 | __invalidate_snapshot(s, pe, -ENOMEM); |
819 | if (s->store.drop_snapshot) | 893 | r = -EIO; |
820 | s->store.drop_snapshot(&s->store); | 894 | goto out_unlock; |
821 | s->valid = 0; | 895 | } |
822 | r = -EIO; | 896 | |
823 | up_write(&s->lock); | 897 | remap_exception(s, &pe->e, bio); |
824 | } else { | 898 | bio_list_add(&pe->snapshot_bios, bio); |
825 | remap_exception(s, &pe->e, bio); | 899 | |
826 | bio_list_add(&pe->snapshot_bios, bio); | 900 | if (!pe->started) { |
827 | 901 | /* this is protected by snap->lock */ | |
828 | if (!pe->started) { | 902 | pe->started = 1; |
829 | /* this is protected by snap->lock */ | 903 | copy_needed = 1; |
830 | pe->started = 1; | ||
831 | up_write(&s->lock); | ||
832 | start_copy(pe); | ||
833 | } else | ||
834 | up_write(&s->lock); | ||
835 | r = 0; | ||
836 | } | ||
837 | } | 904 | } |
838 | 905 | ||
906 | r = 0; | ||
907 | |||
908 | out_unlock: | ||
909 | up_write(&s->lock); | ||
910 | |||
911 | if (copy_needed) | ||
912 | start_copy(pe); | ||
839 | } else { | 913 | } else { |
840 | /* | 914 | /* |
841 | * FIXME: this read path scares me because we | 915 | * FIXME: this read path scares me because we |
@@ -847,6 +921,11 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio, | |||
847 | /* Do reads */ | 921 | /* Do reads */ |
848 | down_read(&s->lock); | 922 | down_read(&s->lock); |
849 | 923 | ||
924 | if (!s->valid) { | ||
925 | up_read(&s->lock); | ||
926 | return -EIO; | ||
927 | } | ||
928 | |||
850 | /* See if it it has been remapped */ | 929 | /* See if it it has been remapped */ |
851 | e = lookup_exception(&s->complete, chunk); | 930 | e = lookup_exception(&s->complete, chunk); |
852 | if (e) | 931 | if (e) |
@@ -884,9 +963,9 @@ static int snapshot_status(struct dm_target *ti, status_type_t type, | |||
884 | snap->store.fraction_full(&snap->store, | 963 | snap->store.fraction_full(&snap->store, |
885 | &numerator, | 964 | &numerator, |
886 | &denominator); | 965 | &denominator); |
887 | snprintf(result, maxlen, | 966 | snprintf(result, maxlen, "%llu/%llu", |
888 | SECTOR_FORMAT "/" SECTOR_FORMAT, | 967 | (unsigned long long)numerator, |
889 | numerator, denominator); | 968 | (unsigned long long)denominator); |
890 | } | 969 | } |
891 | else | 970 | else |
892 | snprintf(result, maxlen, "Unknown"); | 971 | snprintf(result, maxlen, "Unknown"); |
@@ -899,9 +978,10 @@ static int snapshot_status(struct dm_target *ti, status_type_t type, | |||
899 | * to make private copies if the output is to | 978 | * to make private copies if the output is to |
900 | * make sense. | 979 | * make sense. |
901 | */ | 980 | */ |
902 | snprintf(result, maxlen, "%s %s %c " SECTOR_FORMAT, | 981 | snprintf(result, maxlen, "%s %s %c %llu", |
903 | snap->origin->name, snap->cow->name, | 982 | snap->origin->name, snap->cow->name, |
904 | snap->type, snap->chunk_size); | 983 | snap->type, |
984 | (unsigned long long)snap->chunk_size); | ||
905 | break; | 985 | break; |
906 | } | 986 | } |
907 | 987 | ||
@@ -911,40 +991,27 @@ static int snapshot_status(struct dm_target *ti, status_type_t type, | |||
911 | /*----------------------------------------------------------------- | 991 | /*----------------------------------------------------------------- |
912 | * Origin methods | 992 | * Origin methods |
913 | *---------------------------------------------------------------*/ | 993 | *---------------------------------------------------------------*/ |
914 | static void list_merge(struct list_head *l1, struct list_head *l2) | ||
915 | { | ||
916 | struct list_head *l1_n, *l2_p; | ||
917 | |||
918 | l1_n = l1->next; | ||
919 | l2_p = l2->prev; | ||
920 | |||
921 | l1->next = l2; | ||
922 | l2->prev = l1; | ||
923 | |||
924 | l2_p->next = l1_n; | ||
925 | l1_n->prev = l2_p; | ||
926 | } | ||
927 | |||
928 | static int __origin_write(struct list_head *snapshots, struct bio *bio) | 994 | static int __origin_write(struct list_head *snapshots, struct bio *bio) |
929 | { | 995 | { |
930 | int r = 1, first = 1; | 996 | int r = 1, first = 0; |
931 | struct dm_snapshot *snap; | 997 | struct dm_snapshot *snap; |
932 | struct exception *e; | 998 | struct exception *e; |
933 | struct pending_exception *pe, *last = NULL; | 999 | struct pending_exception *pe, *next_pe, *primary_pe = NULL; |
934 | chunk_t chunk; | 1000 | chunk_t chunk; |
1001 | LIST_HEAD(pe_queue); | ||
935 | 1002 | ||
936 | /* Do all the snapshots on this origin */ | 1003 | /* Do all the snapshots on this origin */ |
937 | list_for_each_entry (snap, snapshots, list) { | 1004 | list_for_each_entry (snap, snapshots, list) { |
938 | 1005 | ||
1006 | down_write(&snap->lock); | ||
1007 | |||
939 | /* Only deal with valid and active snapshots */ | 1008 | /* Only deal with valid and active snapshots */ |
940 | if (!snap->valid || !snap->active) | 1009 | if (!snap->valid || !snap->active) |
941 | continue; | 1010 | goto next_snapshot; |
942 | 1011 | ||
943 | /* Nothing to do if writing beyond end of snapshot */ | 1012 | /* Nothing to do if writing beyond end of snapshot */ |
944 | if (bio->bi_sector >= dm_table_get_size(snap->table)) | 1013 | if (bio->bi_sector >= dm_table_get_size(snap->table)) |
945 | continue; | 1014 | goto next_snapshot; |
946 | |||
947 | down_write(&snap->lock); | ||
948 | 1015 | ||
949 | /* | 1016 | /* |
950 | * Remember, different snapshots can have | 1017 | * Remember, different snapshots can have |
@@ -956,49 +1023,75 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) | |||
956 | * Check exception table to see if block | 1023 | * Check exception table to see if block |
957 | * is already remapped in this snapshot | 1024 | * is already remapped in this snapshot |
958 | * and trigger an exception if not. | 1025 | * and trigger an exception if not. |
1026 | * | ||
1027 | * sibling_count is initialised to 1 so pending_complete() | ||
1028 | * won't destroy the primary_pe while we're inside this loop. | ||
959 | */ | 1029 | */ |
960 | e = lookup_exception(&snap->complete, chunk); | 1030 | e = lookup_exception(&snap->complete, chunk); |
961 | if (!e) { | 1031 | if (e) |
962 | pe = __find_pending_exception(snap, bio); | 1032 | goto next_snapshot; |
963 | if (!pe) { | 1033 | |
964 | snap->store.drop_snapshot(&snap->store); | 1034 | pe = __find_pending_exception(snap, bio); |
965 | snap->valid = 0; | 1035 | if (!pe) { |
966 | 1036 | __invalidate_snapshot(snap, pe, ENOMEM); | |
967 | } else { | 1037 | goto next_snapshot; |
968 | if (last) | 1038 | } |
969 | list_merge(&pe->siblings, | 1039 | |
970 | &last->siblings); | 1040 | if (!primary_pe) { |
971 | 1041 | /* | |
972 | last = pe; | 1042 | * Either every pe here has same |
973 | r = 0; | 1043 | * primary_pe or none has one yet. |
1044 | */ | ||
1045 | if (pe->primary_pe) | ||
1046 | primary_pe = pe->primary_pe; | ||
1047 | else { | ||
1048 | primary_pe = pe; | ||
1049 | first = 1; | ||
974 | } | 1050 | } |
1051 | |||
1052 | bio_list_add(&primary_pe->origin_bios, bio); | ||
1053 | |||
1054 | r = 0; | ||
1055 | } | ||
1056 | |||
1057 | if (!pe->primary_pe) { | ||
1058 | atomic_inc(&primary_pe->sibling_count); | ||
1059 | pe->primary_pe = primary_pe; | ||
1060 | } | ||
1061 | |||
1062 | if (!pe->started) { | ||
1063 | pe->started = 1; | ||
1064 | list_add_tail(&pe->list, &pe_queue); | ||
975 | } | 1065 | } |
976 | 1066 | ||
1067 | next_snapshot: | ||
977 | up_write(&snap->lock); | 1068 | up_write(&snap->lock); |
978 | } | 1069 | } |
979 | 1070 | ||
1071 | if (!primary_pe) | ||
1072 | goto out; | ||
1073 | |||
980 | /* | 1074 | /* |
981 | * Now that we have a complete pe list we can start the copying. | 1075 | * If this is the first time we're processing this chunk and |
1076 | * sibling_count is now 1 it means all the pending exceptions | ||
1077 | * got completed while we were in the loop above, so it falls to | ||
1078 | * us here to remove the primary_pe and submit any origin_bios. | ||
982 | */ | 1079 | */ |
983 | if (last) { | 1080 | |
984 | pe = last; | 1081 | if (first && atomic_dec_and_test(&primary_pe->sibling_count)) { |
985 | do { | 1082 | flush_bios(bio_list_get(&primary_pe->origin_bios)); |
986 | down_write(&pe->snap->lock); | 1083 | free_pending_exception(primary_pe); |
987 | if (first) | 1084 | /* If we got here, pe_queue is necessarily empty. */ |
988 | bio_list_add(&pe->origin_bios, bio); | 1085 | goto out; |
989 | if (!pe->started) { | ||
990 | pe->started = 1; | ||
991 | up_write(&pe->snap->lock); | ||
992 | start_copy(pe); | ||
993 | } else | ||
994 | up_write(&pe->snap->lock); | ||
995 | first = 0; | ||
996 | pe = list_entry(pe->siblings.next, | ||
997 | struct pending_exception, siblings); | ||
998 | |||
999 | } while (pe != last); | ||
1000 | } | 1086 | } |
1001 | 1087 | ||
1088 | /* | ||
1089 | * Now that we have a complete pe list we can start the copying. | ||
1090 | */ | ||
1091 | list_for_each_entry_safe(pe, next_pe, &pe_queue, list) | ||
1092 | start_copy(pe); | ||
1093 | |||
1094 | out: | ||
1002 | return r; | 1095 | return r; |
1003 | } | 1096 | } |
1004 | 1097 | ||
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index 697aacafb02a..08328a8f5a3c 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c | |||
@@ -49,9 +49,9 @@ static inline struct stripe_c *alloc_context(unsigned int stripes) | |||
49 | static int get_stripe(struct dm_target *ti, struct stripe_c *sc, | 49 | static int get_stripe(struct dm_target *ti, struct stripe_c *sc, |
50 | unsigned int stripe, char **argv) | 50 | unsigned int stripe, char **argv) |
51 | { | 51 | { |
52 | sector_t start; | 52 | unsigned long long start; |
53 | 53 | ||
54 | if (sscanf(argv[1], SECTOR_FORMAT, &start) != 1) | 54 | if (sscanf(argv[1], "%llu", &start) != 1) |
55 | return -EINVAL; | 55 | return -EINVAL; |
56 | 56 | ||
57 | if (dm_get_device(ti, argv[0], start, sc->stripe_width, | 57 | if (dm_get_device(ti, argv[0], start, sc->stripe_width, |
@@ -103,7 +103,7 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
103 | return -EINVAL; | 103 | return -EINVAL; |
104 | } | 104 | } |
105 | 105 | ||
106 | if (((uint32_t)ti->len) & (chunk_size - 1)) { | 106 | if (ti->len & (chunk_size - 1)) { |
107 | ti->error = "dm-stripe: Target length not divisible by " | 107 | ti->error = "dm-stripe: Target length not divisible by " |
108 | "chunk size"; | 108 | "chunk size"; |
109 | return -EINVAL; | 109 | return -EINVAL; |
@@ -201,10 +201,11 @@ static int stripe_status(struct dm_target *ti, | |||
201 | break; | 201 | break; |
202 | 202 | ||
203 | case STATUSTYPE_TABLE: | 203 | case STATUSTYPE_TABLE: |
204 | DMEMIT("%d " SECTOR_FORMAT, sc->stripes, sc->chunk_mask + 1); | 204 | DMEMIT("%d %llu", sc->stripes, |
205 | (unsigned long long)sc->chunk_mask + 1); | ||
205 | for (i = 0; i < sc->stripes; i++) | 206 | for (i = 0; i < sc->stripes; i++) |
206 | DMEMIT(" %s " SECTOR_FORMAT, sc->stripe[i].dev->name, | 207 | DMEMIT(" %s %llu", sc->stripe[i].dev->name, |
207 | sc->stripe[i].physical_start); | 208 | (unsigned long long)sc->stripe[i].physical_start); |
208 | break; | 209 | break; |
209 | } | 210 | } |
210 | return 0; | 211 | return 0; |
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 907b08ddb783..8f56a54cf0ce 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/ctype.h> | 14 | #include <linux/ctype.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/mutex.h> | ||
17 | #include <asm/atomic.h> | 18 | #include <asm/atomic.h> |
18 | 19 | ||
19 | #define MAX_DEPTH 16 | 20 | #define MAX_DEPTH 16 |
@@ -22,6 +23,7 @@ | |||
22 | #define CHILDREN_PER_NODE (KEYS_PER_NODE + 1) | 23 | #define CHILDREN_PER_NODE (KEYS_PER_NODE + 1) |
23 | 24 | ||
24 | struct dm_table { | 25 | struct dm_table { |
26 | struct mapped_device *md; | ||
25 | atomic_t holders; | 27 | atomic_t holders; |
26 | 28 | ||
27 | /* btree table */ | 29 | /* btree table */ |
@@ -97,6 +99,8 @@ static void combine_restrictions_low(struct io_restrictions *lhs, | |||
97 | 99 | ||
98 | lhs->seg_boundary_mask = | 100 | lhs->seg_boundary_mask = |
99 | min_not_zero(lhs->seg_boundary_mask, rhs->seg_boundary_mask); | 101 | min_not_zero(lhs->seg_boundary_mask, rhs->seg_boundary_mask); |
102 | |||
103 | lhs->no_cluster |= rhs->no_cluster; | ||
100 | } | 104 | } |
101 | 105 | ||
102 | /* | 106 | /* |
@@ -204,7 +208,8 @@ static int alloc_targets(struct dm_table *t, unsigned int num) | |||
204 | return 0; | 208 | return 0; |
205 | } | 209 | } |
206 | 210 | ||
207 | int dm_table_create(struct dm_table **result, int mode, unsigned num_targets) | 211 | int dm_table_create(struct dm_table **result, int mode, |
212 | unsigned num_targets, struct mapped_device *md) | ||
208 | { | 213 | { |
209 | struct dm_table *t = kmalloc(sizeof(*t), GFP_KERNEL); | 214 | struct dm_table *t = kmalloc(sizeof(*t), GFP_KERNEL); |
210 | 215 | ||
@@ -227,6 +232,7 @@ int dm_table_create(struct dm_table **result, int mode, unsigned num_targets) | |||
227 | } | 232 | } |
228 | 233 | ||
229 | t->mode = mode; | 234 | t->mode = mode; |
235 | t->md = md; | ||
230 | *result = t; | 236 | *result = t; |
231 | return 0; | 237 | return 0; |
232 | } | 238 | } |
@@ -345,7 +351,7 @@ static struct dm_dev *find_device(struct list_head *l, dev_t dev) | |||
345 | /* | 351 | /* |
346 | * Open a device so we can use it as a map destination. | 352 | * Open a device so we can use it as a map destination. |
347 | */ | 353 | */ |
348 | static int open_dev(struct dm_dev *d, dev_t dev) | 354 | static int open_dev(struct dm_dev *d, dev_t dev, struct mapped_device *md) |
349 | { | 355 | { |
350 | static char *_claim_ptr = "I belong to device-mapper"; | 356 | static char *_claim_ptr = "I belong to device-mapper"; |
351 | struct block_device *bdev; | 357 | struct block_device *bdev; |
@@ -357,7 +363,7 @@ static int open_dev(struct dm_dev *d, dev_t dev) | |||
357 | bdev = open_by_devnum(dev, d->mode); | 363 | bdev = open_by_devnum(dev, d->mode); |
358 | if (IS_ERR(bdev)) | 364 | if (IS_ERR(bdev)) |
359 | return PTR_ERR(bdev); | 365 | return PTR_ERR(bdev); |
360 | r = bd_claim(bdev, _claim_ptr); | 366 | r = bd_claim_by_disk(bdev, _claim_ptr, dm_disk(md)); |
361 | if (r) | 367 | if (r) |
362 | blkdev_put(bdev); | 368 | blkdev_put(bdev); |
363 | else | 369 | else |
@@ -368,12 +374,12 @@ static int open_dev(struct dm_dev *d, dev_t dev) | |||
368 | /* | 374 | /* |
369 | * Close a device that we've been using. | 375 | * Close a device that we've been using. |
370 | */ | 376 | */ |
371 | static void close_dev(struct dm_dev *d) | 377 | static void close_dev(struct dm_dev *d, struct mapped_device *md) |
372 | { | 378 | { |
373 | if (!d->bdev) | 379 | if (!d->bdev) |
374 | return; | 380 | return; |
375 | 381 | ||
376 | bd_release(d->bdev); | 382 | bd_release_from_disk(d->bdev, dm_disk(md)); |
377 | blkdev_put(d->bdev); | 383 | blkdev_put(d->bdev); |
378 | d->bdev = NULL; | 384 | d->bdev = NULL; |
379 | } | 385 | } |
@@ -394,7 +400,7 @@ static int check_device_area(struct dm_dev *dd, sector_t start, sector_t len) | |||
394 | * careful to leave things as they were if we fail to reopen the | 400 | * careful to leave things as they were if we fail to reopen the |
395 | * device. | 401 | * device. |
396 | */ | 402 | */ |
397 | static int upgrade_mode(struct dm_dev *dd, int new_mode) | 403 | static int upgrade_mode(struct dm_dev *dd, int new_mode, struct mapped_device *md) |
398 | { | 404 | { |
399 | int r; | 405 | int r; |
400 | struct dm_dev dd_copy; | 406 | struct dm_dev dd_copy; |
@@ -404,9 +410,9 @@ static int upgrade_mode(struct dm_dev *dd, int new_mode) | |||
404 | 410 | ||
405 | dd->mode |= new_mode; | 411 | dd->mode |= new_mode; |
406 | dd->bdev = NULL; | 412 | dd->bdev = NULL; |
407 | r = open_dev(dd, dev); | 413 | r = open_dev(dd, dev, md); |
408 | if (!r) | 414 | if (!r) |
409 | close_dev(&dd_copy); | 415 | close_dev(&dd_copy, md); |
410 | else | 416 | else |
411 | *dd = dd_copy; | 417 | *dd = dd_copy; |
412 | 418 | ||
@@ -448,7 +454,7 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti, | |||
448 | dd->mode = mode; | 454 | dd->mode = mode; |
449 | dd->bdev = NULL; | 455 | dd->bdev = NULL; |
450 | 456 | ||
451 | if ((r = open_dev(dd, dev))) { | 457 | if ((r = open_dev(dd, dev, t->md))) { |
452 | kfree(dd); | 458 | kfree(dd); |
453 | return r; | 459 | return r; |
454 | } | 460 | } |
@@ -459,7 +465,7 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti, | |||
459 | list_add(&dd->list, &t->devices); | 465 | list_add(&dd->list, &t->devices); |
460 | 466 | ||
461 | } else if (dd->mode != (mode | dd->mode)) { | 467 | } else if (dd->mode != (mode | dd->mode)) { |
462 | r = upgrade_mode(dd, mode); | 468 | r = upgrade_mode(dd, mode, t->md); |
463 | if (r) | 469 | if (r) |
464 | return r; | 470 | return r; |
465 | } | 471 | } |
@@ -523,6 +529,8 @@ int dm_get_device(struct dm_target *ti, const char *path, sector_t start, | |||
523 | rs->seg_boundary_mask = | 529 | rs->seg_boundary_mask = |
524 | min_not_zero(rs->seg_boundary_mask, | 530 | min_not_zero(rs->seg_boundary_mask, |
525 | q->seg_boundary_mask); | 531 | q->seg_boundary_mask); |
532 | |||
533 | rs->no_cluster |= !test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); | ||
526 | } | 534 | } |
527 | 535 | ||
528 | return r; | 536 | return r; |
@@ -534,7 +542,7 @@ int dm_get_device(struct dm_target *ti, const char *path, sector_t start, | |||
534 | void dm_put_device(struct dm_target *ti, struct dm_dev *dd) | 542 | void dm_put_device(struct dm_target *ti, struct dm_dev *dd) |
535 | { | 543 | { |
536 | if (atomic_dec_and_test(&dd->count)) { | 544 | if (atomic_dec_and_test(&dd->count)) { |
537 | close_dev(dd); | 545 | close_dev(dd, ti->table->md); |
538 | list_del(&dd->list); | 546 | list_del(&dd->list); |
539 | kfree(dd); | 547 | kfree(dd); |
540 | } | 548 | } |
@@ -763,14 +771,14 @@ int dm_table_complete(struct dm_table *t) | |||
763 | return r; | 771 | return r; |
764 | } | 772 | } |
765 | 773 | ||
766 | static DECLARE_MUTEX(_event_lock); | 774 | static DEFINE_MUTEX(_event_lock); |
767 | void dm_table_event_callback(struct dm_table *t, | 775 | void dm_table_event_callback(struct dm_table *t, |
768 | void (*fn)(void *), void *context) | 776 | void (*fn)(void *), void *context) |
769 | { | 777 | { |
770 | down(&_event_lock); | 778 | mutex_lock(&_event_lock); |
771 | t->event_fn = fn; | 779 | t->event_fn = fn; |
772 | t->event_context = context; | 780 | t->event_context = context; |
773 | up(&_event_lock); | 781 | mutex_unlock(&_event_lock); |
774 | } | 782 | } |
775 | 783 | ||
776 | void dm_table_event(struct dm_table *t) | 784 | void dm_table_event(struct dm_table *t) |
@@ -781,10 +789,10 @@ void dm_table_event(struct dm_table *t) | |||
781 | */ | 789 | */ |
782 | BUG_ON(in_interrupt()); | 790 | BUG_ON(in_interrupt()); |
783 | 791 | ||
784 | down(&_event_lock); | 792 | mutex_lock(&_event_lock); |
785 | if (t->event_fn) | 793 | if (t->event_fn) |
786 | t->event_fn(t->event_context); | 794 | t->event_fn(t->event_context); |
787 | up(&_event_lock); | 795 | mutex_unlock(&_event_lock); |
788 | } | 796 | } |
789 | 797 | ||
790 | sector_t dm_table_get_size(struct dm_table *t) | 798 | sector_t dm_table_get_size(struct dm_table *t) |
@@ -832,6 +840,11 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q) | |||
832 | q->hardsect_size = t->limits.hardsect_size; | 840 | q->hardsect_size = t->limits.hardsect_size; |
833 | q->max_segment_size = t->limits.max_segment_size; | 841 | q->max_segment_size = t->limits.max_segment_size; |
834 | q->seg_boundary_mask = t->limits.seg_boundary_mask; | 842 | q->seg_boundary_mask = t->limits.seg_boundary_mask; |
843 | if (t->limits.no_cluster) | ||
844 | q->queue_flags &= ~(1 << QUEUE_FLAG_CLUSTER); | ||
845 | else | ||
846 | q->queue_flags |= (1 << QUEUE_FLAG_CLUSTER); | ||
847 | |||
835 | } | 848 | } |
836 | 849 | ||
837 | unsigned int dm_table_get_num_targets(struct dm_table *t) | 850 | unsigned int dm_table_get_num_targets(struct dm_table *t) |
@@ -943,12 +956,20 @@ int dm_table_flush_all(struct dm_table *t) | |||
943 | return ret; | 956 | return ret; |
944 | } | 957 | } |
945 | 958 | ||
959 | struct mapped_device *dm_table_get_md(struct dm_table *t) | ||
960 | { | ||
961 | dm_get(t->md); | ||
962 | |||
963 | return t->md; | ||
964 | } | ||
965 | |||
946 | EXPORT_SYMBOL(dm_vcalloc); | 966 | EXPORT_SYMBOL(dm_vcalloc); |
947 | EXPORT_SYMBOL(dm_get_device); | 967 | EXPORT_SYMBOL(dm_get_device); |
948 | EXPORT_SYMBOL(dm_put_device); | 968 | EXPORT_SYMBOL(dm_put_device); |
949 | EXPORT_SYMBOL(dm_table_event); | 969 | EXPORT_SYMBOL(dm_table_event); |
950 | EXPORT_SYMBOL(dm_table_get_size); | 970 | EXPORT_SYMBOL(dm_table_get_size); |
951 | EXPORT_SYMBOL(dm_table_get_mode); | 971 | EXPORT_SYMBOL(dm_table_get_mode); |
972 | EXPORT_SYMBOL(dm_table_get_md); | ||
952 | EXPORT_SYMBOL(dm_table_put); | 973 | EXPORT_SYMBOL(dm_table_put); |
953 | EXPORT_SYMBOL(dm_table_get); | 974 | EXPORT_SYMBOL(dm_table_get); |
954 | EXPORT_SYMBOL(dm_table_unplug_all); | 975 | EXPORT_SYMBOL(dm_table_unplug_all); |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index a64798ef481e..4d710b7a133b 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -10,6 +10,7 @@ | |||
10 | 10 | ||
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/mutex.h> | ||
13 | #include <linux/moduleparam.h> | 14 | #include <linux/moduleparam.h> |
14 | #include <linux/blkpg.h> | 15 | #include <linux/blkpg.h> |
15 | #include <linux/bio.h> | 16 | #include <linux/bio.h> |
@@ -17,6 +18,7 @@ | |||
17 | #include <linux/mempool.h> | 18 | #include <linux/mempool.h> |
18 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
19 | #include <linux/idr.h> | 20 | #include <linux/idr.h> |
21 | #include <linux/hdreg.h> | ||
20 | #include <linux/blktrace_api.h> | 22 | #include <linux/blktrace_api.h> |
21 | 23 | ||
22 | static const char *_name = DM_NAME; | 24 | static const char *_name = DM_NAME; |
@@ -69,6 +71,7 @@ struct mapped_device { | |||
69 | 71 | ||
70 | request_queue_t *queue; | 72 | request_queue_t *queue; |
71 | struct gendisk *disk; | 73 | struct gendisk *disk; |
74 | char name[16]; | ||
72 | 75 | ||
73 | void *interface_ptr; | 76 | void *interface_ptr; |
74 | 77 | ||
@@ -101,6 +104,9 @@ struct mapped_device { | |||
101 | */ | 104 | */ |
102 | struct super_block *frozen_sb; | 105 | struct super_block *frozen_sb; |
103 | struct block_device *suspended_bdev; | 106 | struct block_device *suspended_bdev; |
107 | |||
108 | /* forced geometry settings */ | ||
109 | struct hd_geometry geometry; | ||
104 | }; | 110 | }; |
105 | 111 | ||
106 | #define MIN_IOS 256 | 112 | #define MIN_IOS 256 |
@@ -226,6 +232,13 @@ static int dm_blk_close(struct inode *inode, struct file *file) | |||
226 | return 0; | 232 | return 0; |
227 | } | 233 | } |
228 | 234 | ||
235 | static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) | ||
236 | { | ||
237 | struct mapped_device *md = bdev->bd_disk->private_data; | ||
238 | |||
239 | return dm_get_geometry(md, geo); | ||
240 | } | ||
241 | |||
229 | static inline struct dm_io *alloc_io(struct mapped_device *md) | 242 | static inline struct dm_io *alloc_io(struct mapped_device *md) |
230 | { | 243 | { |
231 | return mempool_alloc(md->io_pool, GFP_NOIO); | 244 | return mempool_alloc(md->io_pool, GFP_NOIO); |
@@ -312,6 +325,33 @@ struct dm_table *dm_get_table(struct mapped_device *md) | |||
312 | return t; | 325 | return t; |
313 | } | 326 | } |
314 | 327 | ||
328 | /* | ||
329 | * Get the geometry associated with a dm device | ||
330 | */ | ||
331 | int dm_get_geometry(struct mapped_device *md, struct hd_geometry *geo) | ||
332 | { | ||
333 | *geo = md->geometry; | ||
334 | |||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | /* | ||
339 | * Set the geometry of a device. | ||
340 | */ | ||
341 | int dm_set_geometry(struct mapped_device *md, struct hd_geometry *geo) | ||
342 | { | ||
343 | sector_t sz = (sector_t)geo->cylinders * geo->heads * geo->sectors; | ||
344 | |||
345 | if (geo->start > sz) { | ||
346 | DMWARN("Start sector is beyond the geometry limits."); | ||
347 | return -EINVAL; | ||
348 | } | ||
349 | |||
350 | md->geometry = *geo; | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
315 | /*----------------------------------------------------------------- | 355 | /*----------------------------------------------------------------- |
316 | * CRUD START: | 356 | * CRUD START: |
317 | * A more elegant soln is in the works that uses the queue | 357 | * A more elegant soln is in the works that uses the queue |
@@ -704,14 +744,14 @@ static int dm_any_congested(void *congested_data, int bdi_bits) | |||
704 | /*----------------------------------------------------------------- | 744 | /*----------------------------------------------------------------- |
705 | * An IDR is used to keep track of allocated minor numbers. | 745 | * An IDR is used to keep track of allocated minor numbers. |
706 | *---------------------------------------------------------------*/ | 746 | *---------------------------------------------------------------*/ |
707 | static DECLARE_MUTEX(_minor_lock); | 747 | static DEFINE_MUTEX(_minor_lock); |
708 | static DEFINE_IDR(_minor_idr); | 748 | static DEFINE_IDR(_minor_idr); |
709 | 749 | ||
710 | static void free_minor(unsigned int minor) | 750 | static void free_minor(unsigned int minor) |
711 | { | 751 | { |
712 | down(&_minor_lock); | 752 | mutex_lock(&_minor_lock); |
713 | idr_remove(&_minor_idr, minor); | 753 | idr_remove(&_minor_idr, minor); |
714 | up(&_minor_lock); | 754 | mutex_unlock(&_minor_lock); |
715 | } | 755 | } |
716 | 756 | ||
717 | /* | 757 | /* |
@@ -724,7 +764,7 @@ static int specific_minor(struct mapped_device *md, unsigned int minor) | |||
724 | if (minor >= (1 << MINORBITS)) | 764 | if (minor >= (1 << MINORBITS)) |
725 | return -EINVAL; | 765 | return -EINVAL; |
726 | 766 | ||
727 | down(&_minor_lock); | 767 | mutex_lock(&_minor_lock); |
728 | 768 | ||
729 | if (idr_find(&_minor_idr, minor)) { | 769 | if (idr_find(&_minor_idr, minor)) { |
730 | r = -EBUSY; | 770 | r = -EBUSY; |
@@ -749,7 +789,7 @@ static int specific_minor(struct mapped_device *md, unsigned int minor) | |||
749 | } | 789 | } |
750 | 790 | ||
751 | out: | 791 | out: |
752 | up(&_minor_lock); | 792 | mutex_unlock(&_minor_lock); |
753 | return r; | 793 | return r; |
754 | } | 794 | } |
755 | 795 | ||
@@ -758,7 +798,7 @@ static int next_free_minor(struct mapped_device *md, unsigned int *minor) | |||
758 | int r; | 798 | int r; |
759 | unsigned int m; | 799 | unsigned int m; |
760 | 800 | ||
761 | down(&_minor_lock); | 801 | mutex_lock(&_minor_lock); |
762 | 802 | ||
763 | r = idr_pre_get(&_minor_idr, GFP_KERNEL); | 803 | r = idr_pre_get(&_minor_idr, GFP_KERNEL); |
764 | if (!r) { | 804 | if (!r) { |
@@ -780,7 +820,7 @@ static int next_free_minor(struct mapped_device *md, unsigned int *minor) | |||
780 | *minor = m; | 820 | *minor = m; |
781 | 821 | ||
782 | out: | 822 | out: |
783 | up(&_minor_lock); | 823 | mutex_unlock(&_minor_lock); |
784 | return r; | 824 | return r; |
785 | } | 825 | } |
786 | 826 | ||
@@ -842,6 +882,7 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent) | |||
842 | md->disk->private_data = md; | 882 | md->disk->private_data = md; |
843 | sprintf(md->disk->disk_name, "dm-%d", minor); | 883 | sprintf(md->disk->disk_name, "dm-%d", minor); |
844 | add_disk(md->disk); | 884 | add_disk(md->disk); |
885 | format_dev_t(md->name, MKDEV(_major, minor)); | ||
845 | 886 | ||
846 | atomic_set(&md->pending, 0); | 887 | atomic_set(&md->pending, 0); |
847 | init_waitqueue_head(&md->wait); | 888 | init_waitqueue_head(&md->wait); |
@@ -904,6 +945,13 @@ static int __bind(struct mapped_device *md, struct dm_table *t) | |||
904 | sector_t size; | 945 | sector_t size; |
905 | 946 | ||
906 | size = dm_table_get_size(t); | 947 | size = dm_table_get_size(t); |
948 | |||
949 | /* | ||
950 | * Wipe any geometry if the size of the table changed. | ||
951 | */ | ||
952 | if (size != get_capacity(md->disk)) | ||
953 | memset(&md->geometry, 0, sizeof(md->geometry)); | ||
954 | |||
907 | __set_size(md, size); | 955 | __set_size(md, size); |
908 | if (size == 0) | 956 | if (size == 0) |
909 | return 0; | 957 | return 0; |
@@ -967,13 +1015,13 @@ static struct mapped_device *dm_find_md(dev_t dev) | |||
967 | if (MAJOR(dev) != _major || minor >= (1 << MINORBITS)) | 1015 | if (MAJOR(dev) != _major || minor >= (1 << MINORBITS)) |
968 | return NULL; | 1016 | return NULL; |
969 | 1017 | ||
970 | down(&_minor_lock); | 1018 | mutex_lock(&_minor_lock); |
971 | 1019 | ||
972 | md = idr_find(&_minor_idr, minor); | 1020 | md = idr_find(&_minor_idr, minor); |
973 | if (!md || (dm_disk(md)->first_minor != minor)) | 1021 | if (!md || (dm_disk(md)->first_minor != minor)) |
974 | md = NULL; | 1022 | md = NULL; |
975 | 1023 | ||
976 | up(&_minor_lock); | 1024 | mutex_unlock(&_minor_lock); |
977 | 1025 | ||
978 | return md; | 1026 | return md; |
979 | } | 1027 | } |
@@ -988,15 +1036,9 @@ struct mapped_device *dm_get_md(dev_t dev) | |||
988 | return md; | 1036 | return md; |
989 | } | 1037 | } |
990 | 1038 | ||
991 | void *dm_get_mdptr(dev_t dev) | 1039 | void *dm_get_mdptr(struct mapped_device *md) |
992 | { | 1040 | { |
993 | struct mapped_device *md; | 1041 | return md->interface_ptr; |
994 | void *mdptr = NULL; | ||
995 | |||
996 | md = dm_find_md(dev); | ||
997 | if (md) | ||
998 | mdptr = md->interface_ptr; | ||
999 | return mdptr; | ||
1000 | } | 1042 | } |
1001 | 1043 | ||
1002 | void dm_set_mdptr(struct mapped_device *md, void *ptr) | 1044 | void dm_set_mdptr(struct mapped_device *md, void *ptr) |
@@ -1011,18 +1053,18 @@ void dm_get(struct mapped_device *md) | |||
1011 | 1053 | ||
1012 | void dm_put(struct mapped_device *md) | 1054 | void dm_put(struct mapped_device *md) |
1013 | { | 1055 | { |
1014 | struct dm_table *map = dm_get_table(md); | 1056 | struct dm_table *map; |
1015 | 1057 | ||
1016 | if (atomic_dec_and_test(&md->holders)) { | 1058 | if (atomic_dec_and_test(&md->holders)) { |
1059 | map = dm_get_table(md); | ||
1017 | if (!dm_suspended(md)) { | 1060 | if (!dm_suspended(md)) { |
1018 | dm_table_presuspend_targets(map); | 1061 | dm_table_presuspend_targets(map); |
1019 | dm_table_postsuspend_targets(map); | 1062 | dm_table_postsuspend_targets(map); |
1020 | } | 1063 | } |
1021 | __unbind(md); | 1064 | __unbind(md); |
1065 | dm_table_put(map); | ||
1022 | free_dev(md); | 1066 | free_dev(md); |
1023 | } | 1067 | } |
1024 | |||
1025 | dm_table_put(map); | ||
1026 | } | 1068 | } |
1027 | 1069 | ||
1028 | /* | 1070 | /* |
@@ -1107,6 +1149,7 @@ int dm_suspend(struct mapped_device *md, int do_lockfs) | |||
1107 | { | 1149 | { |
1108 | struct dm_table *map = NULL; | 1150 | struct dm_table *map = NULL; |
1109 | DECLARE_WAITQUEUE(wait, current); | 1151 | DECLARE_WAITQUEUE(wait, current); |
1152 | struct bio *def; | ||
1110 | int r = -EINVAL; | 1153 | int r = -EINVAL; |
1111 | 1154 | ||
1112 | down(&md->suspend_lock); | 1155 | down(&md->suspend_lock); |
@@ -1166,9 +1209,11 @@ int dm_suspend(struct mapped_device *md, int do_lockfs) | |||
1166 | /* were we interrupted ? */ | 1209 | /* were we interrupted ? */ |
1167 | r = -EINTR; | 1210 | r = -EINTR; |
1168 | if (atomic_read(&md->pending)) { | 1211 | if (atomic_read(&md->pending)) { |
1212 | clear_bit(DMF_BLOCK_IO, &md->flags); | ||
1213 | def = bio_list_get(&md->deferred); | ||
1214 | __flush_deferred_io(md, def); | ||
1169 | up_write(&md->io_lock); | 1215 | up_write(&md->io_lock); |
1170 | unlock_fs(md); | 1216 | unlock_fs(md); |
1171 | clear_bit(DMF_BLOCK_IO, &md->flags); | ||
1172 | goto out; | 1217 | goto out; |
1173 | } | 1218 | } |
1174 | up_write(&md->io_lock); | 1219 | up_write(&md->io_lock); |
@@ -1262,6 +1307,7 @@ int dm_suspended(struct mapped_device *md) | |||
1262 | static struct block_device_operations dm_blk_dops = { | 1307 | static struct block_device_operations dm_blk_dops = { |
1263 | .open = dm_blk_open, | 1308 | .open = dm_blk_open, |
1264 | .release = dm_blk_close, | 1309 | .release = dm_blk_close, |
1310 | .getgeo = dm_blk_getgeo, | ||
1265 | .owner = THIS_MODULE | 1311 | .owner = THIS_MODULE |
1266 | }; | 1312 | }; |
1267 | 1313 | ||
diff --git a/drivers/md/dm.h b/drivers/md/dm.h index 4eaf075da217..fd90bc8f9e45 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/device-mapper.h> | 14 | #include <linux/device-mapper.h> |
15 | #include <linux/list.h> | 15 | #include <linux/list.h> |
16 | #include <linux/blkdev.h> | 16 | #include <linux/blkdev.h> |
17 | #include <linux/hdreg.h> | ||
17 | 18 | ||
18 | #define DM_NAME "device-mapper" | 19 | #define DM_NAME "device-mapper" |
19 | #define DMWARN(f, x...) printk(KERN_WARNING DM_NAME ": " f "\n" , ## x) | 20 | #define DMWARN(f, x...) printk(KERN_WARNING DM_NAME ": " f "\n" , ## x) |
@@ -23,16 +24,6 @@ | |||
23 | #define DMEMIT(x...) sz += ((sz >= maxlen) ? \ | 24 | #define DMEMIT(x...) sz += ((sz >= maxlen) ? \ |
24 | 0 : scnprintf(result + sz, maxlen - sz, x)) | 25 | 0 : scnprintf(result + sz, maxlen - sz, x)) |
25 | 26 | ||
26 | /* | ||
27 | * FIXME: I think this should be with the definition of sector_t | ||
28 | * in types.h. | ||
29 | */ | ||
30 | #ifdef CONFIG_LBD | ||
31 | #define SECTOR_FORMAT "%llu" | ||
32 | #else | ||
33 | #define SECTOR_FORMAT "%lu" | ||
34 | #endif | ||
35 | |||
36 | #define SECTOR_SHIFT 9 | 27 | #define SECTOR_SHIFT 9 |
37 | 28 | ||
38 | /* | 29 | /* |
@@ -57,7 +48,7 @@ struct mapped_device; | |||
57 | int dm_create(struct mapped_device **md); | 48 | int dm_create(struct mapped_device **md); |
58 | int dm_create_with_minor(unsigned int minor, struct mapped_device **md); | 49 | int dm_create_with_minor(unsigned int minor, struct mapped_device **md); |
59 | void dm_set_mdptr(struct mapped_device *md, void *ptr); | 50 | void dm_set_mdptr(struct mapped_device *md, void *ptr); |
60 | void *dm_get_mdptr(dev_t dev); | 51 | void *dm_get_mdptr(struct mapped_device *md); |
61 | struct mapped_device *dm_get_md(dev_t dev); | 52 | struct mapped_device *dm_get_md(dev_t dev); |
62 | 53 | ||
63 | /* | 54 | /* |
@@ -95,11 +86,18 @@ int dm_wait_event(struct mapped_device *md, int event_nr); | |||
95 | struct gendisk *dm_disk(struct mapped_device *md); | 86 | struct gendisk *dm_disk(struct mapped_device *md); |
96 | int dm_suspended(struct mapped_device *md); | 87 | int dm_suspended(struct mapped_device *md); |
97 | 88 | ||
89 | /* | ||
90 | * Geometry functions. | ||
91 | */ | ||
92 | int dm_get_geometry(struct mapped_device *md, struct hd_geometry *geo); | ||
93 | int dm_set_geometry(struct mapped_device *md, struct hd_geometry *geo); | ||
94 | |||
98 | /*----------------------------------------------------------------- | 95 | /*----------------------------------------------------------------- |
99 | * Functions for manipulating a table. Tables are also reference | 96 | * Functions for manipulating a table. Tables are also reference |
100 | * counted. | 97 | * counted. |
101 | *---------------------------------------------------------------*/ | 98 | *---------------------------------------------------------------*/ |
102 | int dm_table_create(struct dm_table **result, int mode, unsigned num_targets); | 99 | int dm_table_create(struct dm_table **result, int mode, |
100 | unsigned num_targets, struct mapped_device *md); | ||
103 | 101 | ||
104 | void dm_table_get(struct dm_table *t); | 102 | void dm_table_get(struct dm_table *t); |
105 | void dm_table_put(struct dm_table *t); | 103 | void dm_table_put(struct dm_table *t); |
@@ -117,6 +115,7 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q); | |||
117 | unsigned int dm_table_get_num_targets(struct dm_table *t); | 115 | unsigned int dm_table_get_num_targets(struct dm_table *t); |
118 | struct list_head *dm_table_get_devices(struct dm_table *t); | 116 | struct list_head *dm_table_get_devices(struct dm_table *t); |
119 | int dm_table_get_mode(struct dm_table *t); | 117 | int dm_table_get_mode(struct dm_table *t); |
118 | struct mapped_device *dm_table_get_md(struct dm_table *t); | ||
120 | void dm_table_presuspend_targets(struct dm_table *t); | 119 | void dm_table_presuspend_targets(struct dm_table *t); |
121 | void dm_table_postsuspend_targets(struct dm_table *t); | 120 | void dm_table_postsuspend_targets(struct dm_table *t); |
122 | void dm_table_resume_targets(struct dm_table *t); | 121 | void dm_table_resume_targets(struct dm_table *t); |
diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c index 9dcb2c8a3853..72480a48d88b 100644 --- a/drivers/md/kcopyd.c +++ b/drivers/md/kcopyd.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/vmalloc.h> | 23 | #include <linux/vmalloc.h> |
24 | #include <linux/workqueue.h> | 24 | #include <linux/workqueue.h> |
25 | #include <linux/mutex.h> | ||
25 | 26 | ||
26 | #include "kcopyd.h" | 27 | #include "kcopyd.h" |
27 | 28 | ||
@@ -44,6 +45,9 @@ struct kcopyd_client { | |||
44 | struct page_list *pages; | 45 | struct page_list *pages; |
45 | unsigned int nr_pages; | 46 | unsigned int nr_pages; |
46 | unsigned int nr_free_pages; | 47 | unsigned int nr_free_pages; |
48 | |||
49 | wait_queue_head_t destroyq; | ||
50 | atomic_t nr_jobs; | ||
47 | }; | 51 | }; |
48 | 52 | ||
49 | static struct page_list *alloc_pl(void) | 53 | static struct page_list *alloc_pl(void) |
@@ -292,10 +296,15 @@ static int run_complete_job(struct kcopyd_job *job) | |||
292 | int read_err = job->read_err; | 296 | int read_err = job->read_err; |
293 | unsigned int write_err = job->write_err; | 297 | unsigned int write_err = job->write_err; |
294 | kcopyd_notify_fn fn = job->fn; | 298 | kcopyd_notify_fn fn = job->fn; |
299 | struct kcopyd_client *kc = job->kc; | ||
295 | 300 | ||
296 | kcopyd_put_pages(job->kc, job->pages); | 301 | kcopyd_put_pages(kc, job->pages); |
297 | mempool_free(job, _job_pool); | 302 | mempool_free(job, _job_pool); |
298 | fn(read_err, write_err, context); | 303 | fn(read_err, write_err, context); |
304 | |||
305 | if (atomic_dec_and_test(&kc->nr_jobs)) | ||
306 | wake_up(&kc->destroyq); | ||
307 | |||
299 | return 0; | 308 | return 0; |
300 | } | 309 | } |
301 | 310 | ||
@@ -430,6 +439,7 @@ static void do_work(void *ignored) | |||
430 | */ | 439 | */ |
431 | static void dispatch_job(struct kcopyd_job *job) | 440 | static void dispatch_job(struct kcopyd_job *job) |
432 | { | 441 | { |
442 | atomic_inc(&job->kc->nr_jobs); | ||
433 | push(&_pages_jobs, job); | 443 | push(&_pages_jobs, job); |
434 | wake(); | 444 | wake(); |
435 | } | 445 | } |
@@ -572,21 +582,21 @@ int kcopyd_cancel(struct kcopyd_job *job, int block) | |||
572 | /*----------------------------------------------------------------- | 582 | /*----------------------------------------------------------------- |
573 | * Unit setup | 583 | * Unit setup |
574 | *---------------------------------------------------------------*/ | 584 | *---------------------------------------------------------------*/ |
575 | static DECLARE_MUTEX(_client_lock); | 585 | static DEFINE_MUTEX(_client_lock); |
576 | static LIST_HEAD(_clients); | 586 | static LIST_HEAD(_clients); |
577 | 587 | ||
578 | static void client_add(struct kcopyd_client *kc) | 588 | static void client_add(struct kcopyd_client *kc) |
579 | { | 589 | { |
580 | down(&_client_lock); | 590 | mutex_lock(&_client_lock); |
581 | list_add(&kc->list, &_clients); | 591 | list_add(&kc->list, &_clients); |
582 | up(&_client_lock); | 592 | mutex_unlock(&_client_lock); |
583 | } | 593 | } |
584 | 594 | ||
585 | static void client_del(struct kcopyd_client *kc) | 595 | static void client_del(struct kcopyd_client *kc) |
586 | { | 596 | { |
587 | down(&_client_lock); | 597 | mutex_lock(&_client_lock); |
588 | list_del(&kc->list); | 598 | list_del(&kc->list); |
589 | up(&_client_lock); | 599 | mutex_unlock(&_client_lock); |
590 | } | 600 | } |
591 | 601 | ||
592 | static DEFINE_MUTEX(kcopyd_init_lock); | 602 | static DEFINE_MUTEX(kcopyd_init_lock); |
@@ -669,6 +679,9 @@ int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result) | |||
669 | return r; | 679 | return r; |
670 | } | 680 | } |
671 | 681 | ||
682 | init_waitqueue_head(&kc->destroyq); | ||
683 | atomic_set(&kc->nr_jobs, 0); | ||
684 | |||
672 | client_add(kc); | 685 | client_add(kc); |
673 | *result = kc; | 686 | *result = kc; |
674 | return 0; | 687 | return 0; |
@@ -676,6 +689,9 @@ int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result) | |||
676 | 689 | ||
677 | void kcopyd_client_destroy(struct kcopyd_client *kc) | 690 | void kcopyd_client_destroy(struct kcopyd_client *kc) |
678 | { | 691 | { |
692 | /* Wait for completion of all jobs submitted by this client. */ | ||
693 | wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs)); | ||
694 | |||
679 | dm_io_put(kc->nr_pages); | 695 | dm_io_put(kc->nr_pages); |
680 | client_free_pages(kc); | 696 | client_free_pages(kc); |
681 | client_del(kc); | 697 | client_del(kc); |
diff --git a/drivers/md/md.c b/drivers/md/md.c index 5ed2228745cb..039e071c1007 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <linux/buffer_head.h> /* for invalidate_bdev */ | 43 | #include <linux/buffer_head.h> /* for invalidate_bdev */ |
44 | #include <linux/suspend.h> | 44 | #include <linux/suspend.h> |
45 | #include <linux/poll.h> | 45 | #include <linux/poll.h> |
46 | #include <linux/mutex.h> | ||
46 | 47 | ||
47 | #include <linux/init.h> | 48 | #include <linux/init.h> |
48 | 49 | ||
@@ -158,11 +159,12 @@ static int start_readonly; | |||
158 | */ | 159 | */ |
159 | static DECLARE_WAIT_QUEUE_HEAD(md_event_waiters); | 160 | static DECLARE_WAIT_QUEUE_HEAD(md_event_waiters); |
160 | static atomic_t md_event_count; | 161 | static atomic_t md_event_count; |
161 | static void md_new_event(mddev_t *mddev) | 162 | void md_new_event(mddev_t *mddev) |
162 | { | 163 | { |
163 | atomic_inc(&md_event_count); | 164 | atomic_inc(&md_event_count); |
164 | wake_up(&md_event_waiters); | 165 | wake_up(&md_event_waiters); |
165 | } | 166 | } |
167 | EXPORT_SYMBOL_GPL(md_new_event); | ||
166 | 168 | ||
167 | /* | 169 | /* |
168 | * Enables to iterate over all existing md arrays | 170 | * Enables to iterate over all existing md arrays |
@@ -253,7 +255,7 @@ static mddev_t * mddev_find(dev_t unit) | |||
253 | else | 255 | else |
254 | new->md_minor = MINOR(unit) >> MdpMinorShift; | 256 | new->md_minor = MINOR(unit) >> MdpMinorShift; |
255 | 257 | ||
256 | init_MUTEX(&new->reconfig_sem); | 258 | mutex_init(&new->reconfig_mutex); |
257 | INIT_LIST_HEAD(&new->disks); | 259 | INIT_LIST_HEAD(&new->disks); |
258 | INIT_LIST_HEAD(&new->all_mddevs); | 260 | INIT_LIST_HEAD(&new->all_mddevs); |
259 | init_timer(&new->safemode_timer); | 261 | init_timer(&new->safemode_timer); |
@@ -266,6 +268,7 @@ static mddev_t * mddev_find(dev_t unit) | |||
266 | kfree(new); | 268 | kfree(new); |
267 | return NULL; | 269 | return NULL; |
268 | } | 270 | } |
271 | set_bit(QUEUE_FLAG_CLUSTER, &new->queue->queue_flags); | ||
269 | 272 | ||
270 | blk_queue_make_request(new->queue, md_fail_request); | 273 | blk_queue_make_request(new->queue, md_fail_request); |
271 | 274 | ||
@@ -274,22 +277,22 @@ static mddev_t * mddev_find(dev_t unit) | |||
274 | 277 | ||
275 | static inline int mddev_lock(mddev_t * mddev) | 278 | static inline int mddev_lock(mddev_t * mddev) |
276 | { | 279 | { |
277 | return down_interruptible(&mddev->reconfig_sem); | 280 | return mutex_lock_interruptible(&mddev->reconfig_mutex); |
278 | } | 281 | } |
279 | 282 | ||
280 | static inline void mddev_lock_uninterruptible(mddev_t * mddev) | 283 | static inline void mddev_lock_uninterruptible(mddev_t * mddev) |
281 | { | 284 | { |
282 | down(&mddev->reconfig_sem); | 285 | mutex_lock(&mddev->reconfig_mutex); |
283 | } | 286 | } |
284 | 287 | ||
285 | static inline int mddev_trylock(mddev_t * mddev) | 288 | static inline int mddev_trylock(mddev_t * mddev) |
286 | { | 289 | { |
287 | return down_trylock(&mddev->reconfig_sem); | 290 | return mutex_trylock(&mddev->reconfig_mutex); |
288 | } | 291 | } |
289 | 292 | ||
290 | static inline void mddev_unlock(mddev_t * mddev) | 293 | static inline void mddev_unlock(mddev_t * mddev) |
291 | { | 294 | { |
292 | up(&mddev->reconfig_sem); | 295 | mutex_unlock(&mddev->reconfig_mutex); |
293 | 296 | ||
294 | md_wakeup_thread(mddev->thread); | 297 | md_wakeup_thread(mddev->thread); |
295 | } | 298 | } |
@@ -660,7 +663,8 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version | |||
660 | } | 663 | } |
661 | 664 | ||
662 | if (sb->major_version != 0 || | 665 | if (sb->major_version != 0 || |
663 | sb->minor_version != 90) { | 666 | sb->minor_version < 90 || |
667 | sb->minor_version > 91) { | ||
664 | printk(KERN_WARNING "Bad version number %d.%d on %s\n", | 668 | printk(KERN_WARNING "Bad version number %d.%d on %s\n", |
665 | sb->major_version, sb->minor_version, | 669 | sb->major_version, sb->minor_version, |
666 | b); | 670 | b); |
@@ -745,6 +749,20 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
745 | mddev->bitmap_offset = 0; | 749 | mddev->bitmap_offset = 0; |
746 | mddev->default_bitmap_offset = MD_SB_BYTES >> 9; | 750 | mddev->default_bitmap_offset = MD_SB_BYTES >> 9; |
747 | 751 | ||
752 | if (mddev->minor_version >= 91) { | ||
753 | mddev->reshape_position = sb->reshape_position; | ||
754 | mddev->delta_disks = sb->delta_disks; | ||
755 | mddev->new_level = sb->new_level; | ||
756 | mddev->new_layout = sb->new_layout; | ||
757 | mddev->new_chunk = sb->new_chunk; | ||
758 | } else { | ||
759 | mddev->reshape_position = MaxSector; | ||
760 | mddev->delta_disks = 0; | ||
761 | mddev->new_level = mddev->level; | ||
762 | mddev->new_layout = mddev->layout; | ||
763 | mddev->new_chunk = mddev->chunk_size; | ||
764 | } | ||
765 | |||
748 | if (sb->state & (1<<MD_SB_CLEAN)) | 766 | if (sb->state & (1<<MD_SB_CLEAN)) |
749 | mddev->recovery_cp = MaxSector; | 767 | mddev->recovery_cp = MaxSector; |
750 | else { | 768 | else { |
@@ -764,7 +782,8 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
764 | 782 | ||
765 | if (sb->state & (1<<MD_SB_BITMAP_PRESENT) && | 783 | if (sb->state & (1<<MD_SB_BITMAP_PRESENT) && |
766 | mddev->bitmap_file == NULL) { | 784 | mddev->bitmap_file == NULL) { |
767 | if (mddev->level != 1 && mddev->level != 5 && mddev->level != 6 | 785 | if (mddev->level != 1 && mddev->level != 4 |
786 | && mddev->level != 5 && mddev->level != 6 | ||
768 | && mddev->level != 10) { | 787 | && mddev->level != 10) { |
769 | /* FIXME use a better test */ | 788 | /* FIXME use a better test */ |
770 | printk(KERN_WARNING "md: bitmaps not supported for this level.\n"); | 789 | printk(KERN_WARNING "md: bitmaps not supported for this level.\n"); |
@@ -838,7 +857,6 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) | |||
838 | 857 | ||
839 | sb->md_magic = MD_SB_MAGIC; | 858 | sb->md_magic = MD_SB_MAGIC; |
840 | sb->major_version = mddev->major_version; | 859 | sb->major_version = mddev->major_version; |
841 | sb->minor_version = mddev->minor_version; | ||
842 | sb->patch_version = mddev->patch_version; | 860 | sb->patch_version = mddev->patch_version; |
843 | sb->gvalid_words = 0; /* ignored */ | 861 | sb->gvalid_words = 0; /* ignored */ |
844 | memcpy(&sb->set_uuid0, mddev->uuid+0, 4); | 862 | memcpy(&sb->set_uuid0, mddev->uuid+0, 4); |
@@ -857,6 +875,17 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) | |||
857 | sb->events_hi = (mddev->events>>32); | 875 | sb->events_hi = (mddev->events>>32); |
858 | sb->events_lo = (u32)mddev->events; | 876 | sb->events_lo = (u32)mddev->events; |
859 | 877 | ||
878 | if (mddev->reshape_position == MaxSector) | ||
879 | sb->minor_version = 90; | ||
880 | else { | ||
881 | sb->minor_version = 91; | ||
882 | sb->reshape_position = mddev->reshape_position; | ||
883 | sb->new_level = mddev->new_level; | ||
884 | sb->delta_disks = mddev->delta_disks; | ||
885 | sb->new_layout = mddev->new_layout; | ||
886 | sb->new_chunk = mddev->new_chunk; | ||
887 | } | ||
888 | mddev->minor_version = sb->minor_version; | ||
860 | if (mddev->in_sync) | 889 | if (mddev->in_sync) |
861 | { | 890 | { |
862 | sb->recovery_cp = mddev->recovery_cp; | 891 | sb->recovery_cp = mddev->recovery_cp; |
@@ -893,10 +922,9 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) | |||
893 | d->raid_disk = rdev2->raid_disk; | 922 | d->raid_disk = rdev2->raid_disk; |
894 | else | 923 | else |
895 | d->raid_disk = rdev2->desc_nr; /* compatibility */ | 924 | d->raid_disk = rdev2->desc_nr; /* compatibility */ |
896 | if (test_bit(Faulty, &rdev2->flags)) { | 925 | if (test_bit(Faulty, &rdev2->flags)) |
897 | d->state = (1<<MD_DISK_FAULTY); | 926 | d->state = (1<<MD_DISK_FAULTY); |
898 | failed++; | 927 | else if (test_bit(In_sync, &rdev2->flags)) { |
899 | } else if (test_bit(In_sync, &rdev2->flags)) { | ||
900 | d->state = (1<<MD_DISK_ACTIVE); | 928 | d->state = (1<<MD_DISK_ACTIVE); |
901 | d->state |= (1<<MD_DISK_SYNC); | 929 | d->state |= (1<<MD_DISK_SYNC); |
902 | active++; | 930 | active++; |
@@ -1102,6 +1130,20 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) | |||
1102 | } | 1130 | } |
1103 | mddev->bitmap_offset = (__s32)le32_to_cpu(sb->bitmap_offset); | 1131 | mddev->bitmap_offset = (__s32)le32_to_cpu(sb->bitmap_offset); |
1104 | } | 1132 | } |
1133 | if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) { | ||
1134 | mddev->reshape_position = le64_to_cpu(sb->reshape_position); | ||
1135 | mddev->delta_disks = le32_to_cpu(sb->delta_disks); | ||
1136 | mddev->new_level = le32_to_cpu(sb->new_level); | ||
1137 | mddev->new_layout = le32_to_cpu(sb->new_layout); | ||
1138 | mddev->new_chunk = le32_to_cpu(sb->new_chunk)<<9; | ||
1139 | } else { | ||
1140 | mddev->reshape_position = MaxSector; | ||
1141 | mddev->delta_disks = 0; | ||
1142 | mddev->new_level = mddev->level; | ||
1143 | mddev->new_layout = mddev->layout; | ||
1144 | mddev->new_chunk = mddev->chunk_size; | ||
1145 | } | ||
1146 | |||
1105 | } else if (mddev->pers == NULL) { | 1147 | } else if (mddev->pers == NULL) { |
1106 | /* Insist of good event counter while assembling */ | 1148 | /* Insist of good event counter while assembling */ |
1107 | __u64 ev1 = le64_to_cpu(sb->events); | 1149 | __u64 ev1 = le64_to_cpu(sb->events); |
@@ -1173,6 +1215,14 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) | |||
1173 | sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset); | 1215 | sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset); |
1174 | sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET); | 1216 | sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET); |
1175 | } | 1217 | } |
1218 | if (mddev->reshape_position != MaxSector) { | ||
1219 | sb->feature_map |= cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE); | ||
1220 | sb->reshape_position = cpu_to_le64(mddev->reshape_position); | ||
1221 | sb->new_layout = cpu_to_le32(mddev->new_layout); | ||
1222 | sb->delta_disks = cpu_to_le32(mddev->delta_disks); | ||
1223 | sb->new_level = cpu_to_le32(mddev->new_level); | ||
1224 | sb->new_chunk = cpu_to_le32(mddev->new_chunk>>9); | ||
1225 | } | ||
1176 | 1226 | ||
1177 | max_dev = 0; | 1227 | max_dev = 0; |
1178 | ITERATE_RDEV(mddev,rdev2,tmp) | 1228 | ITERATE_RDEV(mddev,rdev2,tmp) |
@@ -1301,6 +1351,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) | |||
1301 | else | 1351 | else |
1302 | ko = &rdev->bdev->bd_disk->kobj; | 1352 | ko = &rdev->bdev->bd_disk->kobj; |
1303 | sysfs_create_link(&rdev->kobj, ko, "block"); | 1353 | sysfs_create_link(&rdev->kobj, ko, "block"); |
1354 | bd_claim_by_disk(rdev->bdev, rdev, mddev->gendisk); | ||
1304 | return 0; | 1355 | return 0; |
1305 | } | 1356 | } |
1306 | 1357 | ||
@@ -1311,6 +1362,7 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev) | |||
1311 | MD_BUG(); | 1362 | MD_BUG(); |
1312 | return; | 1363 | return; |
1313 | } | 1364 | } |
1365 | bd_release_from_disk(rdev->bdev, rdev->mddev->gendisk); | ||
1314 | list_del_init(&rdev->same_set); | 1366 | list_del_init(&rdev->same_set); |
1315 | printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b)); | 1367 | printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b)); |
1316 | rdev->mddev = NULL; | 1368 | rdev->mddev = NULL; |
@@ -1493,7 +1545,7 @@ static void sync_sbs(mddev_t * mddev) | |||
1493 | } | 1545 | } |
1494 | } | 1546 | } |
1495 | 1547 | ||
1496 | static void md_update_sb(mddev_t * mddev) | 1548 | void md_update_sb(mddev_t * mddev) |
1497 | { | 1549 | { |
1498 | int err; | 1550 | int err; |
1499 | struct list_head *tmp; | 1551 | struct list_head *tmp; |
@@ -1570,6 +1622,7 @@ repeat: | |||
1570 | wake_up(&mddev->sb_wait); | 1622 | wake_up(&mddev->sb_wait); |
1571 | 1623 | ||
1572 | } | 1624 | } |
1625 | EXPORT_SYMBOL_GPL(md_update_sb); | ||
1573 | 1626 | ||
1574 | /* words written to sysfs files may, or my not, be \n terminated. | 1627 | /* words written to sysfs files may, or my not, be \n terminated. |
1575 | * We want to accept with case. For this we use cmd_match. | 1628 | * We want to accept with case. For this we use cmd_match. |
@@ -2162,7 +2215,9 @@ action_show(mddev_t *mddev, char *page) | |||
2162 | char *type = "idle"; | 2215 | char *type = "idle"; |
2163 | if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) || | 2216 | if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) || |
2164 | test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) { | 2217 | test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) { |
2165 | if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { | 2218 | if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) |
2219 | type = "reshape"; | ||
2220 | else if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { | ||
2166 | if (!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) | 2221 | if (!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) |
2167 | type = "resync"; | 2222 | type = "resync"; |
2168 | else if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)) | 2223 | else if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)) |
@@ -2193,7 +2248,14 @@ action_store(mddev_t *mddev, const char *page, size_t len) | |||
2193 | return -EBUSY; | 2248 | return -EBUSY; |
2194 | else if (cmd_match(page, "resync") || cmd_match(page, "recover")) | 2249 | else if (cmd_match(page, "resync") || cmd_match(page, "recover")) |
2195 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); | 2250 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); |
2196 | else { | 2251 | else if (cmd_match(page, "reshape")) { |
2252 | int err; | ||
2253 | if (mddev->pers->start_reshape == NULL) | ||
2254 | return -EINVAL; | ||
2255 | err = mddev->pers->start_reshape(mddev); | ||
2256 | if (err) | ||
2257 | return err; | ||
2258 | } else { | ||
2197 | if (cmd_match(page, "check")) | 2259 | if (cmd_match(page, "check")) |
2198 | set_bit(MD_RECOVERY_CHECK, &mddev->recovery); | 2260 | set_bit(MD_RECOVERY_CHECK, &mddev->recovery); |
2199 | else if (cmd_match(page, "repair")) | 2261 | else if (cmd_match(page, "repair")) |
@@ -2304,6 +2366,63 @@ sync_completed_show(mddev_t *mddev, char *page) | |||
2304 | static struct md_sysfs_entry | 2366 | static struct md_sysfs_entry |
2305 | md_sync_completed = __ATTR_RO(sync_completed); | 2367 | md_sync_completed = __ATTR_RO(sync_completed); |
2306 | 2368 | ||
2369 | static ssize_t | ||
2370 | suspend_lo_show(mddev_t *mddev, char *page) | ||
2371 | { | ||
2372 | return sprintf(page, "%llu\n", (unsigned long long)mddev->suspend_lo); | ||
2373 | } | ||
2374 | |||
2375 | static ssize_t | ||
2376 | suspend_lo_store(mddev_t *mddev, const char *buf, size_t len) | ||
2377 | { | ||
2378 | char *e; | ||
2379 | unsigned long long new = simple_strtoull(buf, &e, 10); | ||
2380 | |||
2381 | if (mddev->pers->quiesce == NULL) | ||
2382 | return -EINVAL; | ||
2383 | if (buf == e || (*e && *e != '\n')) | ||
2384 | return -EINVAL; | ||
2385 | if (new >= mddev->suspend_hi || | ||
2386 | (new > mddev->suspend_lo && new < mddev->suspend_hi)) { | ||
2387 | mddev->suspend_lo = new; | ||
2388 | mddev->pers->quiesce(mddev, 2); | ||
2389 | return len; | ||
2390 | } else | ||
2391 | return -EINVAL; | ||
2392 | } | ||
2393 | static struct md_sysfs_entry md_suspend_lo = | ||
2394 | __ATTR(suspend_lo, S_IRUGO|S_IWUSR, suspend_lo_show, suspend_lo_store); | ||
2395 | |||
2396 | |||
2397 | static ssize_t | ||
2398 | suspend_hi_show(mddev_t *mddev, char *page) | ||
2399 | { | ||
2400 | return sprintf(page, "%llu\n", (unsigned long long)mddev->suspend_hi); | ||
2401 | } | ||
2402 | |||
2403 | static ssize_t | ||
2404 | suspend_hi_store(mddev_t *mddev, const char *buf, size_t len) | ||
2405 | { | ||
2406 | char *e; | ||
2407 | unsigned long long new = simple_strtoull(buf, &e, 10); | ||
2408 | |||
2409 | if (mddev->pers->quiesce == NULL) | ||
2410 | return -EINVAL; | ||
2411 | if (buf == e || (*e && *e != '\n')) | ||
2412 | return -EINVAL; | ||
2413 | if ((new <= mddev->suspend_lo && mddev->suspend_lo >= mddev->suspend_hi) || | ||
2414 | (new > mddev->suspend_lo && new > mddev->suspend_hi)) { | ||
2415 | mddev->suspend_hi = new; | ||
2416 | mddev->pers->quiesce(mddev, 1); | ||
2417 | mddev->pers->quiesce(mddev, 0); | ||
2418 | return len; | ||
2419 | } else | ||
2420 | return -EINVAL; | ||
2421 | } | ||
2422 | static struct md_sysfs_entry md_suspend_hi = | ||
2423 | __ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store); | ||
2424 | |||
2425 | |||
2307 | static struct attribute *md_default_attrs[] = { | 2426 | static struct attribute *md_default_attrs[] = { |
2308 | &md_level.attr, | 2427 | &md_level.attr, |
2309 | &md_raid_disks.attr, | 2428 | &md_raid_disks.attr, |
@@ -2321,6 +2440,8 @@ static struct attribute *md_redundancy_attrs[] = { | |||
2321 | &md_sync_max.attr, | 2440 | &md_sync_max.attr, |
2322 | &md_sync_speed.attr, | 2441 | &md_sync_speed.attr, |
2323 | &md_sync_completed.attr, | 2442 | &md_sync_completed.attr, |
2443 | &md_suspend_lo.attr, | ||
2444 | &md_suspend_hi.attr, | ||
2324 | NULL, | 2445 | NULL, |
2325 | }; | 2446 | }; |
2326 | static struct attribute_group md_redundancy_group = { | 2447 | static struct attribute_group md_redundancy_group = { |
@@ -2380,7 +2501,7 @@ int mdp_major = 0; | |||
2380 | 2501 | ||
2381 | static struct kobject *md_probe(dev_t dev, int *part, void *data) | 2502 | static struct kobject *md_probe(dev_t dev, int *part, void *data) |
2382 | { | 2503 | { |
2383 | static DECLARE_MUTEX(disks_sem); | 2504 | static DEFINE_MUTEX(disks_mutex); |
2384 | mddev_t *mddev = mddev_find(dev); | 2505 | mddev_t *mddev = mddev_find(dev); |
2385 | struct gendisk *disk; | 2506 | struct gendisk *disk; |
2386 | int partitioned = (MAJOR(dev) != MD_MAJOR); | 2507 | int partitioned = (MAJOR(dev) != MD_MAJOR); |
@@ -2390,15 +2511,15 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) | |||
2390 | if (!mddev) | 2511 | if (!mddev) |
2391 | return NULL; | 2512 | return NULL; |
2392 | 2513 | ||
2393 | down(&disks_sem); | 2514 | mutex_lock(&disks_mutex); |
2394 | if (mddev->gendisk) { | 2515 | if (mddev->gendisk) { |
2395 | up(&disks_sem); | 2516 | mutex_unlock(&disks_mutex); |
2396 | mddev_put(mddev); | 2517 | mddev_put(mddev); |
2397 | return NULL; | 2518 | return NULL; |
2398 | } | 2519 | } |
2399 | disk = alloc_disk(1 << shift); | 2520 | disk = alloc_disk(1 << shift); |
2400 | if (!disk) { | 2521 | if (!disk) { |
2401 | up(&disks_sem); | 2522 | mutex_unlock(&disks_mutex); |
2402 | mddev_put(mddev); | 2523 | mddev_put(mddev); |
2403 | return NULL; | 2524 | return NULL; |
2404 | } | 2525 | } |
@@ -2416,7 +2537,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) | |||
2416 | disk->queue = mddev->queue; | 2537 | disk->queue = mddev->queue; |
2417 | add_disk(disk); | 2538 | add_disk(disk); |
2418 | mddev->gendisk = disk; | 2539 | mddev->gendisk = disk; |
2419 | up(&disks_sem); | 2540 | mutex_unlock(&disks_mutex); |
2420 | mddev->kobj.parent = &disk->kobj; | 2541 | mddev->kobj.parent = &disk->kobj; |
2421 | mddev->kobj.k_name = NULL; | 2542 | mddev->kobj.k_name = NULL; |
2422 | snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md"); | 2543 | snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md"); |
@@ -2539,6 +2660,14 @@ static int do_md_run(mddev_t * mddev) | |||
2539 | mddev->level = pers->level; | 2660 | mddev->level = pers->level; |
2540 | strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel)); | 2661 | strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel)); |
2541 | 2662 | ||
2663 | if (mddev->reshape_position != MaxSector && | ||
2664 | pers->start_reshape == NULL) { | ||
2665 | /* This personality cannot handle reshaping... */ | ||
2666 | mddev->pers = NULL; | ||
2667 | module_put(pers->owner); | ||
2668 | return -EINVAL; | ||
2669 | } | ||
2670 | |||
2542 | mddev->recovery = 0; | 2671 | mddev->recovery = 0; |
2543 | mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */ | 2672 | mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */ |
2544 | mddev->barriers_work = 1; | 2673 | mddev->barriers_work = 1; |
@@ -2772,7 +2901,6 @@ static void autorun_array(mddev_t *mddev) | |||
2772 | */ | 2901 | */ |
2773 | static void autorun_devices(int part) | 2902 | static void autorun_devices(int part) |
2774 | { | 2903 | { |
2775 | struct list_head candidates; | ||
2776 | struct list_head *tmp; | 2904 | struct list_head *tmp; |
2777 | mdk_rdev_t *rdev0, *rdev; | 2905 | mdk_rdev_t *rdev0, *rdev; |
2778 | mddev_t *mddev; | 2906 | mddev_t *mddev; |
@@ -2781,6 +2909,7 @@ static void autorun_devices(int part) | |||
2781 | printk(KERN_INFO "md: autorun ...\n"); | 2909 | printk(KERN_INFO "md: autorun ...\n"); |
2782 | while (!list_empty(&pending_raid_disks)) { | 2910 | while (!list_empty(&pending_raid_disks)) { |
2783 | dev_t dev; | 2911 | dev_t dev; |
2912 | LIST_HEAD(candidates); | ||
2784 | rdev0 = list_entry(pending_raid_disks.next, | 2913 | rdev0 = list_entry(pending_raid_disks.next, |
2785 | mdk_rdev_t, same_set); | 2914 | mdk_rdev_t, same_set); |
2786 | 2915 | ||
@@ -3427,11 +3556,18 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) | |||
3427 | mddev->default_bitmap_offset = MD_SB_BYTES >> 9; | 3556 | mddev->default_bitmap_offset = MD_SB_BYTES >> 9; |
3428 | mddev->bitmap_offset = 0; | 3557 | mddev->bitmap_offset = 0; |
3429 | 3558 | ||
3559 | mddev->reshape_position = MaxSector; | ||
3560 | |||
3430 | /* | 3561 | /* |
3431 | * Generate a 128 bit UUID | 3562 | * Generate a 128 bit UUID |
3432 | */ | 3563 | */ |
3433 | get_random_bytes(mddev->uuid, 16); | 3564 | get_random_bytes(mddev->uuid, 16); |
3434 | 3565 | ||
3566 | mddev->new_level = mddev->level; | ||
3567 | mddev->new_chunk = mddev->chunk_size; | ||
3568 | mddev->new_layout = mddev->layout; | ||
3569 | mddev->delta_disks = 0; | ||
3570 | |||
3435 | return 0; | 3571 | return 0; |
3436 | } | 3572 | } |
3437 | 3573 | ||
@@ -3440,6 +3576,7 @@ static int update_size(mddev_t *mddev, unsigned long size) | |||
3440 | mdk_rdev_t * rdev; | 3576 | mdk_rdev_t * rdev; |
3441 | int rv; | 3577 | int rv; |
3442 | struct list_head *tmp; | 3578 | struct list_head *tmp; |
3579 | int fit = (size == 0); | ||
3443 | 3580 | ||
3444 | if (mddev->pers->resize == NULL) | 3581 | if (mddev->pers->resize == NULL) |
3445 | return -EINVAL; | 3582 | return -EINVAL; |
@@ -3457,7 +3594,6 @@ static int update_size(mddev_t *mddev, unsigned long size) | |||
3457 | return -EBUSY; | 3594 | return -EBUSY; |
3458 | ITERATE_RDEV(mddev,rdev,tmp) { | 3595 | ITERATE_RDEV(mddev,rdev,tmp) { |
3459 | sector_t avail; | 3596 | sector_t avail; |
3460 | int fit = (size == 0); | ||
3461 | if (rdev->sb_offset > rdev->data_offset) | 3597 | if (rdev->sb_offset > rdev->data_offset) |
3462 | avail = (rdev->sb_offset*2) - rdev->data_offset; | 3598 | avail = (rdev->sb_offset*2) - rdev->data_offset; |
3463 | else | 3599 | else |
@@ -3487,14 +3623,16 @@ static int update_raid_disks(mddev_t *mddev, int raid_disks) | |||
3487 | { | 3623 | { |
3488 | int rv; | 3624 | int rv; |
3489 | /* change the number of raid disks */ | 3625 | /* change the number of raid disks */ |
3490 | if (mddev->pers->reshape == NULL) | 3626 | if (mddev->pers->check_reshape == NULL) |
3491 | return -EINVAL; | 3627 | return -EINVAL; |
3492 | if (raid_disks <= 0 || | 3628 | if (raid_disks <= 0 || |
3493 | raid_disks >= mddev->max_disks) | 3629 | raid_disks >= mddev->max_disks) |
3494 | return -EINVAL; | 3630 | return -EINVAL; |
3495 | if (mddev->sync_thread) | 3631 | if (mddev->sync_thread || mddev->reshape_position != MaxSector) |
3496 | return -EBUSY; | 3632 | return -EBUSY; |
3497 | rv = mddev->pers->reshape(mddev, raid_disks); | 3633 | mddev->delta_disks = raid_disks - mddev->raid_disks; |
3634 | |||
3635 | rv = mddev->pers->check_reshape(mddev); | ||
3498 | return rv; | 3636 | return rv; |
3499 | } | 3637 | } |
3500 | 3638 | ||
@@ -4041,7 +4179,10 @@ static void status_unused(struct seq_file *seq) | |||
4041 | 4179 | ||
4042 | static void status_resync(struct seq_file *seq, mddev_t * mddev) | 4180 | static void status_resync(struct seq_file *seq, mddev_t * mddev) |
4043 | { | 4181 | { |
4044 | unsigned long max_blocks, resync, res, dt, db, rt; | 4182 | sector_t max_blocks, resync, res; |
4183 | unsigned long dt, db, rt; | ||
4184 | int scale; | ||
4185 | unsigned int per_milli; | ||
4045 | 4186 | ||
4046 | resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active))/2; | 4187 | resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active))/2; |
4047 | 4188 | ||
@@ -4057,9 +4198,22 @@ static void status_resync(struct seq_file *seq, mddev_t * mddev) | |||
4057 | MD_BUG(); | 4198 | MD_BUG(); |
4058 | return; | 4199 | return; |
4059 | } | 4200 | } |
4060 | res = (resync/1024)*1000/(max_blocks/1024 + 1); | 4201 | /* Pick 'scale' such that (resync>>scale)*1000 will fit |
4202 | * in a sector_t, and (max_blocks>>scale) will fit in a | ||
4203 | * u32, as those are the requirements for sector_div. | ||
4204 | * Thus 'scale' must be at least 10 | ||
4205 | */ | ||
4206 | scale = 10; | ||
4207 | if (sizeof(sector_t) > sizeof(unsigned long)) { | ||
4208 | while ( max_blocks/2 > (1ULL<<(scale+32))) | ||
4209 | scale++; | ||
4210 | } | ||
4211 | res = (resync>>scale)*1000; | ||
4212 | sector_div(res, (u32)((max_blocks>>scale)+1)); | ||
4213 | |||
4214 | per_milli = res; | ||
4061 | { | 4215 | { |
4062 | int i, x = res/50, y = 20-x; | 4216 | int i, x = per_milli/50, y = 20-x; |
4063 | seq_printf(seq, "["); | 4217 | seq_printf(seq, "["); |
4064 | for (i = 0; i < x; i++) | 4218 | for (i = 0; i < x; i++) |
4065 | seq_printf(seq, "="); | 4219 | seq_printf(seq, "="); |
@@ -4068,10 +4222,14 @@ static void status_resync(struct seq_file *seq, mddev_t * mddev) | |||
4068 | seq_printf(seq, "."); | 4222 | seq_printf(seq, "."); |
4069 | seq_printf(seq, "] "); | 4223 | seq_printf(seq, "] "); |
4070 | } | 4224 | } |
4071 | seq_printf(seq, " %s =%3lu.%lu%% (%lu/%lu)", | 4225 | seq_printf(seq, " %s =%3u.%u%% (%llu/%llu)", |
4226 | (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)? | ||
4227 | "reshape" : | ||
4072 | (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ? | 4228 | (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ? |
4073 | "resync" : "recovery"), | 4229 | "resync" : "recovery")), |
4074 | res/10, res % 10, resync, max_blocks); | 4230 | per_milli/10, per_milli % 10, |
4231 | (unsigned long long) resync, | ||
4232 | (unsigned long long) max_blocks); | ||
4075 | 4233 | ||
4076 | /* | 4234 | /* |
4077 | * We do not want to overflow, so the order of operands and | 4235 | * We do not want to overflow, so the order of operands and |
@@ -4085,7 +4243,7 @@ static void status_resync(struct seq_file *seq, mddev_t * mddev) | |||
4085 | dt = ((jiffies - mddev->resync_mark) / HZ); | 4243 | dt = ((jiffies - mddev->resync_mark) / HZ); |
4086 | if (!dt) dt++; | 4244 | if (!dt) dt++; |
4087 | db = resync - (mddev->resync_mark_cnt/2); | 4245 | db = resync - (mddev->resync_mark_cnt/2); |
4088 | rt = (dt * ((max_blocks-resync) / (db/100+1)))/100; | 4246 | rt = (dt * ((unsigned long)(max_blocks-resync) / (db/100+1)))/100; |
4089 | 4247 | ||
4090 | seq_printf(seq, " finish=%lu.%lumin", rt / 60, (rt % 60)/6); | 4248 | seq_printf(seq, " finish=%lu.%lumin", rt / 60, (rt % 60)/6); |
4091 | 4249 | ||
@@ -4442,7 +4600,7 @@ static DECLARE_WAIT_QUEUE_HEAD(resync_wait); | |||
4442 | 4600 | ||
4443 | #define SYNC_MARKS 10 | 4601 | #define SYNC_MARKS 10 |
4444 | #define SYNC_MARK_STEP (3*HZ) | 4602 | #define SYNC_MARK_STEP (3*HZ) |
4445 | static void md_do_sync(mddev_t *mddev) | 4603 | void md_do_sync(mddev_t *mddev) |
4446 | { | 4604 | { |
4447 | mddev_t *mddev2; | 4605 | mddev_t *mddev2; |
4448 | unsigned int currspeed = 0, | 4606 | unsigned int currspeed = 0, |
@@ -4522,7 +4680,9 @@ static void md_do_sync(mddev_t *mddev) | |||
4522 | */ | 4680 | */ |
4523 | max_sectors = mddev->resync_max_sectors; | 4681 | max_sectors = mddev->resync_max_sectors; |
4524 | mddev->resync_mismatches = 0; | 4682 | mddev->resync_mismatches = 0; |
4525 | } else | 4683 | } else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) |
4684 | max_sectors = mddev->size << 1; | ||
4685 | else | ||
4526 | /* recovery follows the physical size of devices */ | 4686 | /* recovery follows the physical size of devices */ |
4527 | max_sectors = mddev->size << 1; | 4687 | max_sectors = mddev->size << 1; |
4528 | 4688 | ||
@@ -4658,6 +4818,8 @@ static void md_do_sync(mddev_t *mddev) | |||
4658 | mddev->pers->sync_request(mddev, max_sectors, &skipped, 1); | 4818 | mddev->pers->sync_request(mddev, max_sectors, &skipped, 1); |
4659 | 4819 | ||
4660 | if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) && | 4820 | if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) && |
4821 | test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && | ||
4822 | !test_bit(MD_RECOVERY_CHECK, &mddev->recovery) && | ||
4661 | mddev->curr_resync > 2 && | 4823 | mddev->curr_resync > 2 && |
4662 | mddev->curr_resync >= mddev->recovery_cp) { | 4824 | mddev->curr_resync >= mddev->recovery_cp) { |
4663 | if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { | 4825 | if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { |
@@ -4675,6 +4837,7 @@ static void md_do_sync(mddev_t *mddev) | |||
4675 | set_bit(MD_RECOVERY_DONE, &mddev->recovery); | 4837 | set_bit(MD_RECOVERY_DONE, &mddev->recovery); |
4676 | md_wakeup_thread(mddev->thread); | 4838 | md_wakeup_thread(mddev->thread); |
4677 | } | 4839 | } |
4840 | EXPORT_SYMBOL_GPL(md_do_sync); | ||
4678 | 4841 | ||
4679 | 4842 | ||
4680 | /* | 4843 | /* |
@@ -4730,7 +4893,7 @@ void md_check_recovery(mddev_t *mddev) | |||
4730 | )) | 4893 | )) |
4731 | return; | 4894 | return; |
4732 | 4895 | ||
4733 | if (mddev_trylock(mddev)==0) { | 4896 | if (mddev_trylock(mddev)) { |
4734 | int spares =0; | 4897 | int spares =0; |
4735 | 4898 | ||
4736 | spin_lock_irq(&mddev->write_lock); | 4899 | spin_lock_irq(&mddev->write_lock); |
@@ -4866,7 +5029,7 @@ static int md_notify_reboot(struct notifier_block *this, | |||
4866 | printk(KERN_INFO "md: stopping all md devices.\n"); | 5029 | printk(KERN_INFO "md: stopping all md devices.\n"); |
4867 | 5030 | ||
4868 | ITERATE_MDDEV(mddev,tmp) | 5031 | ITERATE_MDDEV(mddev,tmp) |
4869 | if (mddev_trylock(mddev)==0) | 5032 | if (mddev_trylock(mddev)) |
4870 | do_md_stop (mddev, 1); | 5033 | do_md_stop (mddev, 1); |
4871 | /* | 5034 | /* |
4872 | * certain more exotic SCSI devices are known to be | 5035 | * certain more exotic SCSI devices are known to be |
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 5d88329e3c7a..3cb0872a845d 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c | |||
@@ -1402,6 +1402,9 @@ static void raid1d(mddev_t *mddev) | |||
1402 | clear_bit(R1BIO_BarrierRetry, &r1_bio->state); | 1402 | clear_bit(R1BIO_BarrierRetry, &r1_bio->state); |
1403 | clear_bit(R1BIO_Barrier, &r1_bio->state); | 1403 | clear_bit(R1BIO_Barrier, &r1_bio->state); |
1404 | for (i=0; i < conf->raid_disks; i++) | 1404 | for (i=0; i < conf->raid_disks; i++) |
1405 | if (r1_bio->bios[i]) | ||
1406 | atomic_inc(&r1_bio->remaining); | ||
1407 | for (i=0; i < conf->raid_disks; i++) | ||
1405 | if (r1_bio->bios[i]) { | 1408 | if (r1_bio->bios[i]) { |
1406 | struct bio_vec *bvec; | 1409 | struct bio_vec *bvec; |
1407 | int j; | 1410 | int j; |
@@ -1789,6 +1792,11 @@ static int run(mddev_t *mddev) | |||
1789 | mdname(mddev), mddev->level); | 1792 | mdname(mddev), mddev->level); |
1790 | goto out; | 1793 | goto out; |
1791 | } | 1794 | } |
1795 | if (mddev->reshape_position != MaxSector) { | ||
1796 | printk("raid1: %s: reshape_position set but not supported\n", | ||
1797 | mdname(mddev)); | ||
1798 | goto out; | ||
1799 | } | ||
1792 | /* | 1800 | /* |
1793 | * copy the already verified devices into our private RAID1 | 1801 | * copy the already verified devices into our private RAID1 |
1794 | * bookkeeping area. [whatever we allocate in run(), | 1802 | * bookkeeping area. [whatever we allocate in run(), |
@@ -1971,7 +1979,7 @@ static int raid1_resize(mddev_t *mddev, sector_t sectors) | |||
1971 | return 0; | 1979 | return 0; |
1972 | } | 1980 | } |
1973 | 1981 | ||
1974 | static int raid1_reshape(mddev_t *mddev, int raid_disks) | 1982 | static int raid1_reshape(mddev_t *mddev) |
1975 | { | 1983 | { |
1976 | /* We need to: | 1984 | /* We need to: |
1977 | * 1/ resize the r1bio_pool | 1985 | * 1/ resize the r1bio_pool |
@@ -1988,10 +1996,22 @@ static int raid1_reshape(mddev_t *mddev, int raid_disks) | |||
1988 | struct pool_info *newpoolinfo; | 1996 | struct pool_info *newpoolinfo; |
1989 | mirror_info_t *newmirrors; | 1997 | mirror_info_t *newmirrors; |
1990 | conf_t *conf = mddev_to_conf(mddev); | 1998 | conf_t *conf = mddev_to_conf(mddev); |
1991 | int cnt; | 1999 | int cnt, raid_disks; |
1992 | 2000 | ||
1993 | int d, d2; | 2001 | int d, d2; |
1994 | 2002 | ||
2003 | /* Cannot change chunk_size, layout, or level */ | ||
2004 | if (mddev->chunk_size != mddev->new_chunk || | ||
2005 | mddev->layout != mddev->new_layout || | ||
2006 | mddev->level != mddev->new_level) { | ||
2007 | mddev->new_chunk = mddev->chunk_size; | ||
2008 | mddev->new_layout = mddev->layout; | ||
2009 | mddev->new_level = mddev->level; | ||
2010 | return -EINVAL; | ||
2011 | } | ||
2012 | |||
2013 | raid_disks = mddev->raid_disks + mddev->delta_disks; | ||
2014 | |||
1995 | if (raid_disks < conf->raid_disks) { | 2015 | if (raid_disks < conf->raid_disks) { |
1996 | cnt=0; | 2016 | cnt=0; |
1997 | for (d= 0; d < conf->raid_disks; d++) | 2017 | for (d= 0; d < conf->raid_disks; d++) |
@@ -2038,6 +2058,7 @@ static int raid1_reshape(mddev_t *mddev, int raid_disks) | |||
2038 | 2058 | ||
2039 | mddev->degraded += (raid_disks - conf->raid_disks); | 2059 | mddev->degraded += (raid_disks - conf->raid_disks); |
2040 | conf->raid_disks = mddev->raid_disks = raid_disks; | 2060 | conf->raid_disks = mddev->raid_disks = raid_disks; |
2061 | mddev->delta_disks = 0; | ||
2041 | 2062 | ||
2042 | conf->last_used = 0; /* just make sure it is in-range */ | 2063 | conf->last_used = 0; /* just make sure it is in-range */ |
2043 | lower_barrier(conf); | 2064 | lower_barrier(conf); |
@@ -2079,7 +2100,7 @@ static struct mdk_personality raid1_personality = | |||
2079 | .spare_active = raid1_spare_active, | 2100 | .spare_active = raid1_spare_active, |
2080 | .sync_request = sync_request, | 2101 | .sync_request = sync_request, |
2081 | .resize = raid1_resize, | 2102 | .resize = raid1_resize, |
2082 | .reshape = raid1_reshape, | 2103 | .check_reshape = raid1_reshape, |
2083 | .quiesce = raid1_quiesce, | 2104 | .quiesce = raid1_quiesce, |
2084 | }; | 2105 | }; |
2085 | 2106 | ||
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 2dba305daf3c..dae740adaf65 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/raid/raid5.h> | 22 | #include <linux/raid/raid5.h> |
23 | #include <linux/highmem.h> | 23 | #include <linux/highmem.h> |
24 | #include <linux/bitops.h> | 24 | #include <linux/bitops.h> |
25 | #include <linux/kthread.h> | ||
25 | #include <asm/atomic.h> | 26 | #include <asm/atomic.h> |
26 | 27 | ||
27 | #include <linux/raid/bitmap.h> | 28 | #include <linux/raid/bitmap.h> |
@@ -93,11 +94,11 @@ static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh) | |||
93 | if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) | 94 | if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) |
94 | md_wakeup_thread(conf->mddev->thread); | 95 | md_wakeup_thread(conf->mddev->thread); |
95 | } | 96 | } |
96 | list_add_tail(&sh->lru, &conf->inactive_list); | ||
97 | atomic_dec(&conf->active_stripes); | 97 | atomic_dec(&conf->active_stripes); |
98 | if (!conf->inactive_blocked || | 98 | if (!test_bit(STRIPE_EXPANDING, &sh->state)) { |
99 | atomic_read(&conf->active_stripes) < (conf->max_nr_stripes*3/4)) | 99 | list_add_tail(&sh->lru, &conf->inactive_list); |
100 | wake_up(&conf->wait_for_stripe); | 100 | wake_up(&conf->wait_for_stripe); |
101 | } | ||
101 | } | 102 | } |
102 | } | 103 | } |
103 | } | 104 | } |
@@ -178,10 +179,10 @@ static int grow_buffers(struct stripe_head *sh, int num) | |||
178 | 179 | ||
179 | static void raid5_build_block (struct stripe_head *sh, int i); | 180 | static void raid5_build_block (struct stripe_head *sh, int i); |
180 | 181 | ||
181 | static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx) | 182 | static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx, int disks) |
182 | { | 183 | { |
183 | raid5_conf_t *conf = sh->raid_conf; | 184 | raid5_conf_t *conf = sh->raid_conf; |
184 | int disks = conf->raid_disks, i; | 185 | int i; |
185 | 186 | ||
186 | if (atomic_read(&sh->count) != 0) | 187 | if (atomic_read(&sh->count) != 0) |
187 | BUG(); | 188 | BUG(); |
@@ -198,7 +199,9 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx) | |||
198 | sh->pd_idx = pd_idx; | 199 | sh->pd_idx = pd_idx; |
199 | sh->state = 0; | 200 | sh->state = 0; |
200 | 201 | ||
201 | for (i=disks; i--; ) { | 202 | sh->disks = disks; |
203 | |||
204 | for (i = sh->disks; i--; ) { | ||
202 | struct r5dev *dev = &sh->dev[i]; | 205 | struct r5dev *dev = &sh->dev[i]; |
203 | 206 | ||
204 | if (dev->toread || dev->towrite || dev->written || | 207 | if (dev->toread || dev->towrite || dev->written || |
@@ -215,7 +218,7 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx) | |||
215 | insert_hash(conf, sh); | 218 | insert_hash(conf, sh); |
216 | } | 219 | } |
217 | 220 | ||
218 | static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector) | 221 | static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector, int disks) |
219 | { | 222 | { |
220 | struct stripe_head *sh; | 223 | struct stripe_head *sh; |
221 | struct hlist_node *hn; | 224 | struct hlist_node *hn; |
@@ -223,7 +226,7 @@ static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector) | |||
223 | CHECK_DEVLOCK(); | 226 | CHECK_DEVLOCK(); |
224 | PRINTK("__find_stripe, sector %llu\n", (unsigned long long)sector); | 227 | PRINTK("__find_stripe, sector %llu\n", (unsigned long long)sector); |
225 | hlist_for_each_entry(sh, hn, stripe_hash(conf, sector), hash) | 228 | hlist_for_each_entry(sh, hn, stripe_hash(conf, sector), hash) |
226 | if (sh->sector == sector) | 229 | if (sh->sector == sector && sh->disks == disks) |
227 | return sh; | 230 | return sh; |
228 | PRINTK("__stripe %llu not in cache\n", (unsigned long long)sector); | 231 | PRINTK("__stripe %llu not in cache\n", (unsigned long long)sector); |
229 | return NULL; | 232 | return NULL; |
@@ -232,8 +235,8 @@ static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector) | |||
232 | static void unplug_slaves(mddev_t *mddev); | 235 | static void unplug_slaves(mddev_t *mddev); |
233 | static void raid5_unplug_device(request_queue_t *q); | 236 | static void raid5_unplug_device(request_queue_t *q); |
234 | 237 | ||
235 | static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector, | 238 | static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector, int disks, |
236 | int pd_idx, int noblock) | 239 | int pd_idx, int noblock) |
237 | { | 240 | { |
238 | struct stripe_head *sh; | 241 | struct stripe_head *sh; |
239 | 242 | ||
@@ -245,7 +248,7 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector | |||
245 | wait_event_lock_irq(conf->wait_for_stripe, | 248 | wait_event_lock_irq(conf->wait_for_stripe, |
246 | conf->quiesce == 0, | 249 | conf->quiesce == 0, |
247 | conf->device_lock, /* nothing */); | 250 | conf->device_lock, /* nothing */); |
248 | sh = __find_stripe(conf, sector); | 251 | sh = __find_stripe(conf, sector, disks); |
249 | if (!sh) { | 252 | if (!sh) { |
250 | if (!conf->inactive_blocked) | 253 | if (!conf->inactive_blocked) |
251 | sh = get_free_stripe(conf); | 254 | sh = get_free_stripe(conf); |
@@ -259,11 +262,11 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector | |||
259 | < (conf->max_nr_stripes *3/4) | 262 | < (conf->max_nr_stripes *3/4) |
260 | || !conf->inactive_blocked), | 263 | || !conf->inactive_blocked), |
261 | conf->device_lock, | 264 | conf->device_lock, |
262 | unplug_slaves(conf->mddev); | 265 | unplug_slaves(conf->mddev) |
263 | ); | 266 | ); |
264 | conf->inactive_blocked = 0; | 267 | conf->inactive_blocked = 0; |
265 | } else | 268 | } else |
266 | init_stripe(sh, sector, pd_idx); | 269 | init_stripe(sh, sector, pd_idx, disks); |
267 | } else { | 270 | } else { |
268 | if (atomic_read(&sh->count)) { | 271 | if (atomic_read(&sh->count)) { |
269 | if (!list_empty(&sh->lru)) | 272 | if (!list_empty(&sh->lru)) |
@@ -271,9 +274,8 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector | |||
271 | } else { | 274 | } else { |
272 | if (!test_bit(STRIPE_HANDLE, &sh->state)) | 275 | if (!test_bit(STRIPE_HANDLE, &sh->state)) |
273 | atomic_inc(&conf->active_stripes); | 276 | atomic_inc(&conf->active_stripes); |
274 | if (list_empty(&sh->lru)) | 277 | if (!list_empty(&sh->lru)) |
275 | BUG(); | 278 | list_del_init(&sh->lru); |
276 | list_del_init(&sh->lru); | ||
277 | } | 279 | } |
278 | } | 280 | } |
279 | } while (sh == NULL); | 281 | } while (sh == NULL); |
@@ -300,6 +302,7 @@ static int grow_one_stripe(raid5_conf_t *conf) | |||
300 | kmem_cache_free(conf->slab_cache, sh); | 302 | kmem_cache_free(conf->slab_cache, sh); |
301 | return 0; | 303 | return 0; |
302 | } | 304 | } |
305 | sh->disks = conf->raid_disks; | ||
303 | /* we just created an active stripe so... */ | 306 | /* we just created an active stripe so... */ |
304 | atomic_set(&sh->count, 1); | 307 | atomic_set(&sh->count, 1); |
305 | atomic_inc(&conf->active_stripes); | 308 | atomic_inc(&conf->active_stripes); |
@@ -313,14 +316,16 @@ static int grow_stripes(raid5_conf_t *conf, int num) | |||
313 | kmem_cache_t *sc; | 316 | kmem_cache_t *sc; |
314 | int devs = conf->raid_disks; | 317 | int devs = conf->raid_disks; |
315 | 318 | ||
316 | sprintf(conf->cache_name, "raid5/%s", mdname(conf->mddev)); | 319 | sprintf(conf->cache_name[0], "raid5/%s", mdname(conf->mddev)); |
317 | 320 | sprintf(conf->cache_name[1], "raid5/%s-alt", mdname(conf->mddev)); | |
318 | sc = kmem_cache_create(conf->cache_name, | 321 | conf->active_name = 0; |
322 | sc = kmem_cache_create(conf->cache_name[conf->active_name], | ||
319 | sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev), | 323 | sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev), |
320 | 0, 0, NULL, NULL); | 324 | 0, 0, NULL, NULL); |
321 | if (!sc) | 325 | if (!sc) |
322 | return 1; | 326 | return 1; |
323 | conf->slab_cache = sc; | 327 | conf->slab_cache = sc; |
328 | conf->pool_size = devs; | ||
324 | while (num--) { | 329 | while (num--) { |
325 | if (!grow_one_stripe(conf)) | 330 | if (!grow_one_stripe(conf)) |
326 | return 1; | 331 | return 1; |
@@ -328,6 +333,129 @@ static int grow_stripes(raid5_conf_t *conf, int num) | |||
328 | return 0; | 333 | return 0; |
329 | } | 334 | } |
330 | 335 | ||
336 | #ifdef CONFIG_MD_RAID5_RESHAPE | ||
337 | static int resize_stripes(raid5_conf_t *conf, int newsize) | ||
338 | { | ||
339 | /* Make all the stripes able to hold 'newsize' devices. | ||
340 | * New slots in each stripe get 'page' set to a new page. | ||
341 | * | ||
342 | * This happens in stages: | ||
343 | * 1/ create a new kmem_cache and allocate the required number of | ||
344 | * stripe_heads. | ||
345 | * 2/ gather all the old stripe_heads and tranfer the pages across | ||
346 | * to the new stripe_heads. This will have the side effect of | ||
347 | * freezing the array as once all stripe_heads have been collected, | ||
348 | * no IO will be possible. Old stripe heads are freed once their | ||
349 | * pages have been transferred over, and the old kmem_cache is | ||
350 | * freed when all stripes are done. | ||
351 | * 3/ reallocate conf->disks to be suitable bigger. If this fails, | ||
352 | * we simple return a failre status - no need to clean anything up. | ||
353 | * 4/ allocate new pages for the new slots in the new stripe_heads. | ||
354 | * If this fails, we don't bother trying the shrink the | ||
355 | * stripe_heads down again, we just leave them as they are. | ||
356 | * As each stripe_head is processed the new one is released into | ||
357 | * active service. | ||
358 | * | ||
359 | * Once step2 is started, we cannot afford to wait for a write, | ||
360 | * so we use GFP_NOIO allocations. | ||
361 | */ | ||
362 | struct stripe_head *osh, *nsh; | ||
363 | LIST_HEAD(newstripes); | ||
364 | struct disk_info *ndisks; | ||
365 | int err = 0; | ||
366 | kmem_cache_t *sc; | ||
367 | int i; | ||
368 | |||
369 | if (newsize <= conf->pool_size) | ||
370 | return 0; /* never bother to shrink */ | ||
371 | |||
372 | /* Step 1 */ | ||
373 | sc = kmem_cache_create(conf->cache_name[1-conf->active_name], | ||
374 | sizeof(struct stripe_head)+(newsize-1)*sizeof(struct r5dev), | ||
375 | 0, 0, NULL, NULL); | ||
376 | if (!sc) | ||
377 | return -ENOMEM; | ||
378 | |||
379 | for (i = conf->max_nr_stripes; i; i--) { | ||
380 | nsh = kmem_cache_alloc(sc, GFP_KERNEL); | ||
381 | if (!nsh) | ||
382 | break; | ||
383 | |||
384 | memset(nsh, 0, sizeof(*nsh) + (newsize-1)*sizeof(struct r5dev)); | ||
385 | |||
386 | nsh->raid_conf = conf; | ||
387 | spin_lock_init(&nsh->lock); | ||
388 | |||
389 | list_add(&nsh->lru, &newstripes); | ||
390 | } | ||
391 | if (i) { | ||
392 | /* didn't get enough, give up */ | ||
393 | while (!list_empty(&newstripes)) { | ||
394 | nsh = list_entry(newstripes.next, struct stripe_head, lru); | ||
395 | list_del(&nsh->lru); | ||
396 | kmem_cache_free(sc, nsh); | ||
397 | } | ||
398 | kmem_cache_destroy(sc); | ||
399 | return -ENOMEM; | ||
400 | } | ||
401 | /* Step 2 - Must use GFP_NOIO now. | ||
402 | * OK, we have enough stripes, start collecting inactive | ||
403 | * stripes and copying them over | ||
404 | */ | ||
405 | list_for_each_entry(nsh, &newstripes, lru) { | ||
406 | spin_lock_irq(&conf->device_lock); | ||
407 | wait_event_lock_irq(conf->wait_for_stripe, | ||
408 | !list_empty(&conf->inactive_list), | ||
409 | conf->device_lock, | ||
410 | unplug_slaves(conf->mddev) | ||
411 | ); | ||
412 | osh = get_free_stripe(conf); | ||
413 | spin_unlock_irq(&conf->device_lock); | ||
414 | atomic_set(&nsh->count, 1); | ||
415 | for(i=0; i<conf->pool_size; i++) | ||
416 | nsh->dev[i].page = osh->dev[i].page; | ||
417 | for( ; i<newsize; i++) | ||
418 | nsh->dev[i].page = NULL; | ||
419 | kmem_cache_free(conf->slab_cache, osh); | ||
420 | } | ||
421 | kmem_cache_destroy(conf->slab_cache); | ||
422 | |||
423 | /* Step 3. | ||
424 | * At this point, we are holding all the stripes so the array | ||
425 | * is completely stalled, so now is a good time to resize | ||
426 | * conf->disks. | ||
427 | */ | ||
428 | ndisks = kzalloc(newsize * sizeof(struct disk_info), GFP_NOIO); | ||
429 | if (ndisks) { | ||
430 | for (i=0; i<conf->raid_disks; i++) | ||
431 | ndisks[i] = conf->disks[i]; | ||
432 | kfree(conf->disks); | ||
433 | conf->disks = ndisks; | ||
434 | } else | ||
435 | err = -ENOMEM; | ||
436 | |||
437 | /* Step 4, return new stripes to service */ | ||
438 | while(!list_empty(&newstripes)) { | ||
439 | nsh = list_entry(newstripes.next, struct stripe_head, lru); | ||
440 | list_del_init(&nsh->lru); | ||
441 | for (i=conf->raid_disks; i < newsize; i++) | ||
442 | if (nsh->dev[i].page == NULL) { | ||
443 | struct page *p = alloc_page(GFP_NOIO); | ||
444 | nsh->dev[i].page = p; | ||
445 | if (!p) | ||
446 | err = -ENOMEM; | ||
447 | } | ||
448 | release_stripe(nsh); | ||
449 | } | ||
450 | /* critical section pass, GFP_NOIO no longer needed */ | ||
451 | |||
452 | conf->slab_cache = sc; | ||
453 | conf->active_name = 1-conf->active_name; | ||
454 | conf->pool_size = newsize; | ||
455 | return err; | ||
456 | } | ||
457 | #endif | ||
458 | |||
331 | static int drop_one_stripe(raid5_conf_t *conf) | 459 | static int drop_one_stripe(raid5_conf_t *conf) |
332 | { | 460 | { |
333 | struct stripe_head *sh; | 461 | struct stripe_head *sh; |
@@ -339,7 +467,7 @@ static int drop_one_stripe(raid5_conf_t *conf) | |||
339 | return 0; | 467 | return 0; |
340 | if (atomic_read(&sh->count)) | 468 | if (atomic_read(&sh->count)) |
341 | BUG(); | 469 | BUG(); |
342 | shrink_buffers(sh, conf->raid_disks); | 470 | shrink_buffers(sh, conf->pool_size); |
343 | kmem_cache_free(conf->slab_cache, sh); | 471 | kmem_cache_free(conf->slab_cache, sh); |
344 | atomic_dec(&conf->active_stripes); | 472 | atomic_dec(&conf->active_stripes); |
345 | return 1; | 473 | return 1; |
@@ -360,7 +488,7 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done, | |||
360 | { | 488 | { |
361 | struct stripe_head *sh = bi->bi_private; | 489 | struct stripe_head *sh = bi->bi_private; |
362 | raid5_conf_t *conf = sh->raid_conf; | 490 | raid5_conf_t *conf = sh->raid_conf; |
363 | int disks = conf->raid_disks, i; | 491 | int disks = sh->disks, i; |
364 | int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); | 492 | int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); |
365 | 493 | ||
366 | if (bi->bi_size) | 494 | if (bi->bi_size) |
@@ -458,7 +586,7 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done, | |||
458 | { | 586 | { |
459 | struct stripe_head *sh = bi->bi_private; | 587 | struct stripe_head *sh = bi->bi_private; |
460 | raid5_conf_t *conf = sh->raid_conf; | 588 | raid5_conf_t *conf = sh->raid_conf; |
461 | int disks = conf->raid_disks, i; | 589 | int disks = sh->disks, i; |
462 | unsigned long flags; | 590 | unsigned long flags; |
463 | int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); | 591 | int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); |
464 | 592 | ||
@@ -612,7 +740,7 @@ static sector_t raid5_compute_sector(sector_t r_sector, unsigned int raid_disks, | |||
612 | static sector_t compute_blocknr(struct stripe_head *sh, int i) | 740 | static sector_t compute_blocknr(struct stripe_head *sh, int i) |
613 | { | 741 | { |
614 | raid5_conf_t *conf = sh->raid_conf; | 742 | raid5_conf_t *conf = sh->raid_conf; |
615 | int raid_disks = conf->raid_disks, data_disks = raid_disks - 1; | 743 | int raid_disks = sh->disks, data_disks = raid_disks - 1; |
616 | sector_t new_sector = sh->sector, check; | 744 | sector_t new_sector = sh->sector, check; |
617 | int sectors_per_chunk = conf->chunk_size >> 9; | 745 | int sectors_per_chunk = conf->chunk_size >> 9; |
618 | sector_t stripe; | 746 | sector_t stripe; |
@@ -713,8 +841,7 @@ static void copy_data(int frombio, struct bio *bio, | |||
713 | 841 | ||
714 | static void compute_block(struct stripe_head *sh, int dd_idx) | 842 | static void compute_block(struct stripe_head *sh, int dd_idx) |
715 | { | 843 | { |
716 | raid5_conf_t *conf = sh->raid_conf; | 844 | int i, count, disks = sh->disks; |
717 | int i, count, disks = conf->raid_disks; | ||
718 | void *ptr[MAX_XOR_BLOCKS], *p; | 845 | void *ptr[MAX_XOR_BLOCKS], *p; |
719 | 846 | ||
720 | PRINTK("compute_block, stripe %llu, idx %d\n", | 847 | PRINTK("compute_block, stripe %llu, idx %d\n", |
@@ -744,7 +871,7 @@ static void compute_block(struct stripe_head *sh, int dd_idx) | |||
744 | static void compute_parity(struct stripe_head *sh, int method) | 871 | static void compute_parity(struct stripe_head *sh, int method) |
745 | { | 872 | { |
746 | raid5_conf_t *conf = sh->raid_conf; | 873 | raid5_conf_t *conf = sh->raid_conf; |
747 | int i, pd_idx = sh->pd_idx, disks = conf->raid_disks, count; | 874 | int i, pd_idx = sh->pd_idx, disks = sh->disks, count; |
748 | void *ptr[MAX_XOR_BLOCKS]; | 875 | void *ptr[MAX_XOR_BLOCKS]; |
749 | struct bio *chosen; | 876 | struct bio *chosen; |
750 | 877 | ||
@@ -910,6 +1037,20 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in | |||
910 | return 0; | 1037 | return 0; |
911 | } | 1038 | } |
912 | 1039 | ||
1040 | static void end_reshape(raid5_conf_t *conf); | ||
1041 | |||
1042 | static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks) | ||
1043 | { | ||
1044 | int sectors_per_chunk = conf->chunk_size >> 9; | ||
1045 | sector_t x = stripe; | ||
1046 | int pd_idx, dd_idx; | ||
1047 | int chunk_offset = sector_div(x, sectors_per_chunk); | ||
1048 | stripe = x; | ||
1049 | raid5_compute_sector(stripe*(disks-1)*sectors_per_chunk | ||
1050 | + chunk_offset, disks, disks-1, &dd_idx, &pd_idx, conf); | ||
1051 | return pd_idx; | ||
1052 | } | ||
1053 | |||
913 | 1054 | ||
914 | /* | 1055 | /* |
915 | * handle_stripe - do things to a stripe. | 1056 | * handle_stripe - do things to a stripe. |
@@ -932,11 +1073,11 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in | |||
932 | static void handle_stripe(struct stripe_head *sh) | 1073 | static void handle_stripe(struct stripe_head *sh) |
933 | { | 1074 | { |
934 | raid5_conf_t *conf = sh->raid_conf; | 1075 | raid5_conf_t *conf = sh->raid_conf; |
935 | int disks = conf->raid_disks; | 1076 | int disks = sh->disks; |
936 | struct bio *return_bi= NULL; | 1077 | struct bio *return_bi= NULL; |
937 | struct bio *bi; | 1078 | struct bio *bi; |
938 | int i; | 1079 | int i; |
939 | int syncing; | 1080 | int syncing, expanding, expanded; |
940 | int locked=0, uptodate=0, to_read=0, to_write=0, failed=0, written=0; | 1081 | int locked=0, uptodate=0, to_read=0, to_write=0, failed=0, written=0; |
941 | int non_overwrite = 0; | 1082 | int non_overwrite = 0; |
942 | int failed_num=0; | 1083 | int failed_num=0; |
@@ -951,6 +1092,8 @@ static void handle_stripe(struct stripe_head *sh) | |||
951 | clear_bit(STRIPE_DELAYED, &sh->state); | 1092 | clear_bit(STRIPE_DELAYED, &sh->state); |
952 | 1093 | ||
953 | syncing = test_bit(STRIPE_SYNCING, &sh->state); | 1094 | syncing = test_bit(STRIPE_SYNCING, &sh->state); |
1095 | expanding = test_bit(STRIPE_EXPAND_SOURCE, &sh->state); | ||
1096 | expanded = test_bit(STRIPE_EXPAND_READY, &sh->state); | ||
954 | /* Now to look around and see what can be done */ | 1097 | /* Now to look around and see what can be done */ |
955 | 1098 | ||
956 | rcu_read_lock(); | 1099 | rcu_read_lock(); |
@@ -1143,13 +1286,14 @@ static void handle_stripe(struct stripe_head *sh) | |||
1143 | * parity, or to satisfy requests | 1286 | * parity, or to satisfy requests |
1144 | * or to load a block that is being partially written. | 1287 | * or to load a block that is being partially written. |
1145 | */ | 1288 | */ |
1146 | if (to_read || non_overwrite || (syncing && (uptodate < disks))) { | 1289 | if (to_read || non_overwrite || (syncing && (uptodate < disks)) || expanding) { |
1147 | for (i=disks; i--;) { | 1290 | for (i=disks; i--;) { |
1148 | dev = &sh->dev[i]; | 1291 | dev = &sh->dev[i]; |
1149 | if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) && | 1292 | if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) && |
1150 | (dev->toread || | 1293 | (dev->toread || |
1151 | (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) || | 1294 | (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) || |
1152 | syncing || | 1295 | syncing || |
1296 | expanding || | ||
1153 | (failed && (sh->dev[failed_num].toread || | 1297 | (failed && (sh->dev[failed_num].toread || |
1154 | (sh->dev[failed_num].towrite && !test_bit(R5_OVERWRITE, &sh->dev[failed_num].flags)))) | 1298 | (sh->dev[failed_num].towrite && !test_bit(R5_OVERWRITE, &sh->dev[failed_num].flags)))) |
1155 | ) | 1299 | ) |
@@ -1339,13 +1483,77 @@ static void handle_stripe(struct stripe_head *sh) | |||
1339 | set_bit(R5_Wantwrite, &dev->flags); | 1483 | set_bit(R5_Wantwrite, &dev->flags); |
1340 | set_bit(R5_ReWrite, &dev->flags); | 1484 | set_bit(R5_ReWrite, &dev->flags); |
1341 | set_bit(R5_LOCKED, &dev->flags); | 1485 | set_bit(R5_LOCKED, &dev->flags); |
1486 | locked++; | ||
1342 | } else { | 1487 | } else { |
1343 | /* let's read it back */ | 1488 | /* let's read it back */ |
1344 | set_bit(R5_Wantread, &dev->flags); | 1489 | set_bit(R5_Wantread, &dev->flags); |
1345 | set_bit(R5_LOCKED, &dev->flags); | 1490 | set_bit(R5_LOCKED, &dev->flags); |
1491 | locked++; | ||
1346 | } | 1492 | } |
1347 | } | 1493 | } |
1348 | 1494 | ||
1495 | if (expanded && test_bit(STRIPE_EXPANDING, &sh->state)) { | ||
1496 | /* Need to write out all blocks after computing parity */ | ||
1497 | sh->disks = conf->raid_disks; | ||
1498 | sh->pd_idx = stripe_to_pdidx(sh->sector, conf, conf->raid_disks); | ||
1499 | compute_parity(sh, RECONSTRUCT_WRITE); | ||
1500 | for (i= conf->raid_disks; i--;) { | ||
1501 | set_bit(R5_LOCKED, &sh->dev[i].flags); | ||
1502 | locked++; | ||
1503 | set_bit(R5_Wantwrite, &sh->dev[i].flags); | ||
1504 | } | ||
1505 | clear_bit(STRIPE_EXPANDING, &sh->state); | ||
1506 | } else if (expanded) { | ||
1507 | clear_bit(STRIPE_EXPAND_READY, &sh->state); | ||
1508 | atomic_dec(&conf->reshape_stripes); | ||
1509 | wake_up(&conf->wait_for_overlap); | ||
1510 | md_done_sync(conf->mddev, STRIPE_SECTORS, 1); | ||
1511 | } | ||
1512 | |||
1513 | if (expanding && locked == 0) { | ||
1514 | /* We have read all the blocks in this stripe and now we need to | ||
1515 | * copy some of them into a target stripe for expand. | ||
1516 | */ | ||
1517 | clear_bit(STRIPE_EXPAND_SOURCE, &sh->state); | ||
1518 | for (i=0; i< sh->disks; i++) | ||
1519 | if (i != sh->pd_idx) { | ||
1520 | int dd_idx, pd_idx, j; | ||
1521 | struct stripe_head *sh2; | ||
1522 | |||
1523 | sector_t bn = compute_blocknr(sh, i); | ||
1524 | sector_t s = raid5_compute_sector(bn, conf->raid_disks, | ||
1525 | conf->raid_disks-1, | ||
1526 | &dd_idx, &pd_idx, conf); | ||
1527 | sh2 = get_active_stripe(conf, s, conf->raid_disks, pd_idx, 1); | ||
1528 | if (sh2 == NULL) | ||
1529 | /* so far only the early blocks of this stripe | ||
1530 | * have been requested. When later blocks | ||
1531 | * get requested, we will try again | ||
1532 | */ | ||
1533 | continue; | ||
1534 | if(!test_bit(STRIPE_EXPANDING, &sh2->state) || | ||
1535 | test_bit(R5_Expanded, &sh2->dev[dd_idx].flags)) { | ||
1536 | /* must have already done this block */ | ||
1537 | release_stripe(sh2); | ||
1538 | continue; | ||
1539 | } | ||
1540 | memcpy(page_address(sh2->dev[dd_idx].page), | ||
1541 | page_address(sh->dev[i].page), | ||
1542 | STRIPE_SIZE); | ||
1543 | set_bit(R5_Expanded, &sh2->dev[dd_idx].flags); | ||
1544 | set_bit(R5_UPTODATE, &sh2->dev[dd_idx].flags); | ||
1545 | for (j=0; j<conf->raid_disks; j++) | ||
1546 | if (j != sh2->pd_idx && | ||
1547 | !test_bit(R5_Expanded, &sh2->dev[j].flags)) | ||
1548 | break; | ||
1549 | if (j == conf->raid_disks) { | ||
1550 | set_bit(STRIPE_EXPAND_READY, &sh2->state); | ||
1551 | set_bit(STRIPE_HANDLE, &sh2->state); | ||
1552 | } | ||
1553 | release_stripe(sh2); | ||
1554 | } | ||
1555 | } | ||
1556 | |||
1349 | spin_unlock(&sh->lock); | 1557 | spin_unlock(&sh->lock); |
1350 | 1558 | ||
1351 | while ((bi=return_bi)) { | 1559 | while ((bi=return_bi)) { |
@@ -1384,7 +1592,7 @@ static void handle_stripe(struct stripe_head *sh) | |||
1384 | rcu_read_unlock(); | 1592 | rcu_read_unlock(); |
1385 | 1593 | ||
1386 | if (rdev) { | 1594 | if (rdev) { |
1387 | if (syncing) | 1595 | if (syncing || expanding || expanded) |
1388 | md_sync_acct(rdev->bdev, STRIPE_SECTORS); | 1596 | md_sync_acct(rdev->bdev, STRIPE_SECTORS); |
1389 | 1597 | ||
1390 | bi->bi_bdev = rdev->bdev; | 1598 | bi->bi_bdev = rdev->bdev; |
@@ -1526,17 +1734,16 @@ static inline void raid5_plug_device(raid5_conf_t *conf) | |||
1526 | spin_unlock_irq(&conf->device_lock); | 1734 | spin_unlock_irq(&conf->device_lock); |
1527 | } | 1735 | } |
1528 | 1736 | ||
1529 | static int make_request (request_queue_t *q, struct bio * bi) | 1737 | static int make_request(request_queue_t *q, struct bio * bi) |
1530 | { | 1738 | { |
1531 | mddev_t *mddev = q->queuedata; | 1739 | mddev_t *mddev = q->queuedata; |
1532 | raid5_conf_t *conf = mddev_to_conf(mddev); | 1740 | raid5_conf_t *conf = mddev_to_conf(mddev); |
1533 | const unsigned int raid_disks = conf->raid_disks; | ||
1534 | const unsigned int data_disks = raid_disks - 1; | ||
1535 | unsigned int dd_idx, pd_idx; | 1741 | unsigned int dd_idx, pd_idx; |
1536 | sector_t new_sector; | 1742 | sector_t new_sector; |
1537 | sector_t logical_sector, last_sector; | 1743 | sector_t logical_sector, last_sector; |
1538 | struct stripe_head *sh; | 1744 | struct stripe_head *sh; |
1539 | const int rw = bio_data_dir(bi); | 1745 | const int rw = bio_data_dir(bi); |
1746 | int remaining; | ||
1540 | 1747 | ||
1541 | if (unlikely(bio_barrier(bi))) { | 1748 | if (unlikely(bio_barrier(bi))) { |
1542 | bio_endio(bi, bi->bi_size, -EOPNOTSUPP); | 1749 | bio_endio(bi, bi->bi_size, -EOPNOTSUPP); |
@@ -1555,20 +1762,77 @@ static int make_request (request_queue_t *q, struct bio * bi) | |||
1555 | 1762 | ||
1556 | for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { | 1763 | for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { |
1557 | DEFINE_WAIT(w); | 1764 | DEFINE_WAIT(w); |
1558 | 1765 | int disks; | |
1559 | new_sector = raid5_compute_sector(logical_sector, | ||
1560 | raid_disks, data_disks, &dd_idx, &pd_idx, conf); | ||
1561 | 1766 | ||
1767 | retry: | ||
1768 | prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE); | ||
1769 | if (likely(conf->expand_progress == MaxSector)) | ||
1770 | disks = conf->raid_disks; | ||
1771 | else { | ||
1772 | /* spinlock is needed as expand_progress may be | ||
1773 | * 64bit on a 32bit platform, and so it might be | ||
1774 | * possible to see a half-updated value | ||
1775 | * Ofcourse expand_progress could change after | ||
1776 | * the lock is dropped, so once we get a reference | ||
1777 | * to the stripe that we think it is, we will have | ||
1778 | * to check again. | ||
1779 | */ | ||
1780 | spin_lock_irq(&conf->device_lock); | ||
1781 | disks = conf->raid_disks; | ||
1782 | if (logical_sector >= conf->expand_progress) | ||
1783 | disks = conf->previous_raid_disks; | ||
1784 | else { | ||
1785 | if (logical_sector >= conf->expand_lo) { | ||
1786 | spin_unlock_irq(&conf->device_lock); | ||
1787 | schedule(); | ||
1788 | goto retry; | ||
1789 | } | ||
1790 | } | ||
1791 | spin_unlock_irq(&conf->device_lock); | ||
1792 | } | ||
1793 | new_sector = raid5_compute_sector(logical_sector, disks, disks - 1, | ||
1794 | &dd_idx, &pd_idx, conf); | ||
1562 | PRINTK("raid5: make_request, sector %llu logical %llu\n", | 1795 | PRINTK("raid5: make_request, sector %llu logical %llu\n", |
1563 | (unsigned long long)new_sector, | 1796 | (unsigned long long)new_sector, |
1564 | (unsigned long long)logical_sector); | 1797 | (unsigned long long)logical_sector); |
1565 | 1798 | ||
1566 | retry: | 1799 | sh = get_active_stripe(conf, new_sector, disks, pd_idx, (bi->bi_rw&RWA_MASK)); |
1567 | prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE); | ||
1568 | sh = get_active_stripe(conf, new_sector, pd_idx, (bi->bi_rw&RWA_MASK)); | ||
1569 | if (sh) { | 1800 | if (sh) { |
1570 | if (!add_stripe_bio(sh, bi, dd_idx, (bi->bi_rw&RW_MASK))) { | 1801 | if (unlikely(conf->expand_progress != MaxSector)) { |
1571 | /* Add failed due to overlap. Flush everything | 1802 | /* expansion might have moved on while waiting for a |
1803 | * stripe, so we must do the range check again. | ||
1804 | * Expansion could still move past after this | ||
1805 | * test, but as we are holding a reference to | ||
1806 | * 'sh', we know that if that happens, | ||
1807 | * STRIPE_EXPANDING will get set and the expansion | ||
1808 | * won't proceed until we finish with the stripe. | ||
1809 | */ | ||
1810 | int must_retry = 0; | ||
1811 | spin_lock_irq(&conf->device_lock); | ||
1812 | if (logical_sector < conf->expand_progress && | ||
1813 | disks == conf->previous_raid_disks) | ||
1814 | /* mismatch, need to try again */ | ||
1815 | must_retry = 1; | ||
1816 | spin_unlock_irq(&conf->device_lock); | ||
1817 | if (must_retry) { | ||
1818 | release_stripe(sh); | ||
1819 | goto retry; | ||
1820 | } | ||
1821 | } | ||
1822 | /* FIXME what if we get a false positive because these | ||
1823 | * are being updated. | ||
1824 | */ | ||
1825 | if (logical_sector >= mddev->suspend_lo && | ||
1826 | logical_sector < mddev->suspend_hi) { | ||
1827 | release_stripe(sh); | ||
1828 | schedule(); | ||
1829 | goto retry; | ||
1830 | } | ||
1831 | |||
1832 | if (test_bit(STRIPE_EXPANDING, &sh->state) || | ||
1833 | !add_stripe_bio(sh, bi, dd_idx, (bi->bi_rw&RW_MASK))) { | ||
1834 | /* Stripe is busy expanding or | ||
1835 | * add failed due to overlap. Flush everything | ||
1572 | * and wait a while | 1836 | * and wait a while |
1573 | */ | 1837 | */ |
1574 | raid5_unplug_device(mddev->queue); | 1838 | raid5_unplug_device(mddev->queue); |
@@ -1580,7 +1844,6 @@ static int make_request (request_queue_t *q, struct bio * bi) | |||
1580 | raid5_plug_device(conf); | 1844 | raid5_plug_device(conf); |
1581 | handle_stripe(sh); | 1845 | handle_stripe(sh); |
1582 | release_stripe(sh); | 1846 | release_stripe(sh); |
1583 | |||
1584 | } else { | 1847 | } else { |
1585 | /* cannot get stripe for read-ahead, just give-up */ | 1848 | /* cannot get stripe for read-ahead, just give-up */ |
1586 | clear_bit(BIO_UPTODATE, &bi->bi_flags); | 1849 | clear_bit(BIO_UPTODATE, &bi->bi_flags); |
@@ -1590,7 +1853,9 @@ static int make_request (request_queue_t *q, struct bio * bi) | |||
1590 | 1853 | ||
1591 | } | 1854 | } |
1592 | spin_lock_irq(&conf->device_lock); | 1855 | spin_lock_irq(&conf->device_lock); |
1593 | if (--bi->bi_phys_segments == 0) { | 1856 | remaining = --bi->bi_phys_segments; |
1857 | spin_unlock_irq(&conf->device_lock); | ||
1858 | if (remaining == 0) { | ||
1594 | int bytes = bi->bi_size; | 1859 | int bytes = bi->bi_size; |
1595 | 1860 | ||
1596 | if ( bio_data_dir(bi) == WRITE ) | 1861 | if ( bio_data_dir(bi) == WRITE ) |
@@ -1598,7 +1863,6 @@ static int make_request (request_queue_t *q, struct bio * bi) | |||
1598 | bi->bi_size = 0; | 1863 | bi->bi_size = 0; |
1599 | bi->bi_end_io(bi, bytes, 0); | 1864 | bi->bi_end_io(bi, bytes, 0); |
1600 | } | 1865 | } |
1601 | spin_unlock_irq(&conf->device_lock); | ||
1602 | return 0; | 1866 | return 0; |
1603 | } | 1867 | } |
1604 | 1868 | ||
@@ -1607,12 +1871,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i | |||
1607 | { | 1871 | { |
1608 | raid5_conf_t *conf = (raid5_conf_t *) mddev->private; | 1872 | raid5_conf_t *conf = (raid5_conf_t *) mddev->private; |
1609 | struct stripe_head *sh; | 1873 | struct stripe_head *sh; |
1610 | int sectors_per_chunk = conf->chunk_size >> 9; | 1874 | int pd_idx; |
1611 | sector_t x; | 1875 | sector_t first_sector, last_sector; |
1612 | unsigned long stripe; | ||
1613 | int chunk_offset; | ||
1614 | int dd_idx, pd_idx; | ||
1615 | sector_t first_sector; | ||
1616 | int raid_disks = conf->raid_disks; | 1876 | int raid_disks = conf->raid_disks; |
1617 | int data_disks = raid_disks-1; | 1877 | int data_disks = raid_disks-1; |
1618 | sector_t max_sector = mddev->size << 1; | 1878 | sector_t max_sector = mddev->size << 1; |
@@ -1621,6 +1881,10 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i | |||
1621 | if (sector_nr >= max_sector) { | 1881 | if (sector_nr >= max_sector) { |
1622 | /* just being told to finish up .. nothing much to do */ | 1882 | /* just being told to finish up .. nothing much to do */ |
1623 | unplug_slaves(mddev); | 1883 | unplug_slaves(mddev); |
1884 | if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) { | ||
1885 | end_reshape(conf); | ||
1886 | return 0; | ||
1887 | } | ||
1624 | 1888 | ||
1625 | if (mddev->curr_resync < max_sector) /* aborted */ | 1889 | if (mddev->curr_resync < max_sector) /* aborted */ |
1626 | bitmap_end_sync(mddev->bitmap, mddev->curr_resync, | 1890 | bitmap_end_sync(mddev->bitmap, mddev->curr_resync, |
@@ -1631,6 +1895,123 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i | |||
1631 | 1895 | ||
1632 | return 0; | 1896 | return 0; |
1633 | } | 1897 | } |
1898 | |||
1899 | if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) { | ||
1900 | /* reshaping is quite different to recovery/resync so it is | ||
1901 | * handled quite separately ... here. | ||
1902 | * | ||
1903 | * On each call to sync_request, we gather one chunk worth of | ||
1904 | * destination stripes and flag them as expanding. | ||
1905 | * Then we find all the source stripes and request reads. | ||
1906 | * As the reads complete, handle_stripe will copy the data | ||
1907 | * into the destination stripe and release that stripe. | ||
1908 | */ | ||
1909 | int i; | ||
1910 | int dd_idx; | ||
1911 | sector_t writepos, safepos, gap; | ||
1912 | |||
1913 | if (sector_nr == 0 && | ||
1914 | conf->expand_progress != 0) { | ||
1915 | /* restarting in the middle, skip the initial sectors */ | ||
1916 | sector_nr = conf->expand_progress; | ||
1917 | sector_div(sector_nr, conf->raid_disks-1); | ||
1918 | *skipped = 1; | ||
1919 | return sector_nr; | ||
1920 | } | ||
1921 | |||
1922 | /* we update the metadata when there is more than 3Meg | ||
1923 | * in the block range (that is rather arbitrary, should | ||
1924 | * probably be time based) or when the data about to be | ||
1925 | * copied would over-write the source of the data at | ||
1926 | * the front of the range. | ||
1927 | * i.e. one new_stripe forward from expand_progress new_maps | ||
1928 | * to after where expand_lo old_maps to | ||
1929 | */ | ||
1930 | writepos = conf->expand_progress + | ||
1931 | conf->chunk_size/512*(conf->raid_disks-1); | ||
1932 | sector_div(writepos, conf->raid_disks-1); | ||
1933 | safepos = conf->expand_lo; | ||
1934 | sector_div(safepos, conf->previous_raid_disks-1); | ||
1935 | gap = conf->expand_progress - conf->expand_lo; | ||
1936 | |||
1937 | if (writepos >= safepos || | ||
1938 | gap > (conf->raid_disks-1)*3000*2 /*3Meg*/) { | ||
1939 | /* Cannot proceed until we've updated the superblock... */ | ||
1940 | wait_event(conf->wait_for_overlap, | ||
1941 | atomic_read(&conf->reshape_stripes)==0); | ||
1942 | mddev->reshape_position = conf->expand_progress; | ||
1943 | mddev->sb_dirty = 1; | ||
1944 | md_wakeup_thread(mddev->thread); | ||
1945 | wait_event(mddev->sb_wait, mddev->sb_dirty == 0 || | ||
1946 | kthread_should_stop()); | ||
1947 | spin_lock_irq(&conf->device_lock); | ||
1948 | conf->expand_lo = mddev->reshape_position; | ||
1949 | spin_unlock_irq(&conf->device_lock); | ||
1950 | wake_up(&conf->wait_for_overlap); | ||
1951 | } | ||
1952 | |||
1953 | for (i=0; i < conf->chunk_size/512; i+= STRIPE_SECTORS) { | ||
1954 | int j; | ||
1955 | int skipped = 0; | ||
1956 | pd_idx = stripe_to_pdidx(sector_nr+i, conf, conf->raid_disks); | ||
1957 | sh = get_active_stripe(conf, sector_nr+i, | ||
1958 | conf->raid_disks, pd_idx, 0); | ||
1959 | set_bit(STRIPE_EXPANDING, &sh->state); | ||
1960 | atomic_inc(&conf->reshape_stripes); | ||
1961 | /* If any of this stripe is beyond the end of the old | ||
1962 | * array, then we need to zero those blocks | ||
1963 | */ | ||
1964 | for (j=sh->disks; j--;) { | ||
1965 | sector_t s; | ||
1966 | if (j == sh->pd_idx) | ||
1967 | continue; | ||
1968 | s = compute_blocknr(sh, j); | ||
1969 | if (s < (mddev->array_size<<1)) { | ||
1970 | skipped = 1; | ||
1971 | continue; | ||
1972 | } | ||
1973 | memset(page_address(sh->dev[j].page), 0, STRIPE_SIZE); | ||
1974 | set_bit(R5_Expanded, &sh->dev[j].flags); | ||
1975 | set_bit(R5_UPTODATE, &sh->dev[j].flags); | ||
1976 | } | ||
1977 | if (!skipped) { | ||
1978 | set_bit(STRIPE_EXPAND_READY, &sh->state); | ||
1979 | set_bit(STRIPE_HANDLE, &sh->state); | ||
1980 | } | ||
1981 | release_stripe(sh); | ||
1982 | } | ||
1983 | spin_lock_irq(&conf->device_lock); | ||
1984 | conf->expand_progress = (sector_nr + i)*(conf->raid_disks-1); | ||
1985 | spin_unlock_irq(&conf->device_lock); | ||
1986 | /* Ok, those stripe are ready. We can start scheduling | ||
1987 | * reads on the source stripes. | ||
1988 | * The source stripes are determined by mapping the first and last | ||
1989 | * block on the destination stripes. | ||
1990 | */ | ||
1991 | raid_disks = conf->previous_raid_disks; | ||
1992 | data_disks = raid_disks - 1; | ||
1993 | first_sector = | ||
1994 | raid5_compute_sector(sector_nr*(conf->raid_disks-1), | ||
1995 | raid_disks, data_disks, | ||
1996 | &dd_idx, &pd_idx, conf); | ||
1997 | last_sector = | ||
1998 | raid5_compute_sector((sector_nr+conf->chunk_size/512) | ||
1999 | *(conf->raid_disks-1) -1, | ||
2000 | raid_disks, data_disks, | ||
2001 | &dd_idx, &pd_idx, conf); | ||
2002 | if (last_sector >= (mddev->size<<1)) | ||
2003 | last_sector = (mddev->size<<1)-1; | ||
2004 | while (first_sector <= last_sector) { | ||
2005 | pd_idx = stripe_to_pdidx(first_sector, conf, conf->previous_raid_disks); | ||
2006 | sh = get_active_stripe(conf, first_sector, | ||
2007 | conf->previous_raid_disks, pd_idx, 0); | ||
2008 | set_bit(STRIPE_EXPAND_SOURCE, &sh->state); | ||
2009 | set_bit(STRIPE_HANDLE, &sh->state); | ||
2010 | release_stripe(sh); | ||
2011 | first_sector += STRIPE_SECTORS; | ||
2012 | } | ||
2013 | return conf->chunk_size>>9; | ||
2014 | } | ||
1634 | /* if there is 1 or more failed drives and we are trying | 2015 | /* if there is 1 or more failed drives and we are trying |
1635 | * to resync, then assert that we are finished, because there is | 2016 | * to resync, then assert that we are finished, because there is |
1636 | * nothing we can do. | 2017 | * nothing we can do. |
@@ -1649,16 +2030,10 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i | |||
1649 | return sync_blocks * STRIPE_SECTORS; /* keep things rounded to whole stripes */ | 2030 | return sync_blocks * STRIPE_SECTORS; /* keep things rounded to whole stripes */ |
1650 | } | 2031 | } |
1651 | 2032 | ||
1652 | x = sector_nr; | 2033 | pd_idx = stripe_to_pdidx(sector_nr, conf, raid_disks); |
1653 | chunk_offset = sector_div(x, sectors_per_chunk); | 2034 | sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 1); |
1654 | stripe = x; | ||
1655 | BUG_ON(x != stripe); | ||
1656 | |||
1657 | first_sector = raid5_compute_sector((sector_t)stripe*data_disks*sectors_per_chunk | ||
1658 | + chunk_offset, raid_disks, data_disks, &dd_idx, &pd_idx, conf); | ||
1659 | sh = get_active_stripe(conf, sector_nr, pd_idx, 1); | ||
1660 | if (sh == NULL) { | 2035 | if (sh == NULL) { |
1661 | sh = get_active_stripe(conf, sector_nr, pd_idx, 0); | 2036 | sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 0); |
1662 | /* make sure we don't swamp the stripe cache if someone else | 2037 | /* make sure we don't swamp the stripe cache if someone else |
1663 | * is trying to get access | 2038 | * is trying to get access |
1664 | */ | 2039 | */ |
@@ -1822,11 +2197,64 @@ static int run(mddev_t *mddev) | |||
1822 | return -EIO; | 2197 | return -EIO; |
1823 | } | 2198 | } |
1824 | 2199 | ||
1825 | mddev->private = kzalloc(sizeof (raid5_conf_t) | 2200 | if (mddev->reshape_position != MaxSector) { |
1826 | + mddev->raid_disks * sizeof(struct disk_info), | 2201 | /* Check that we can continue the reshape. |
1827 | GFP_KERNEL); | 2202 | * Currently only disks can change, it must |
2203 | * increase, and we must be past the point where | ||
2204 | * a stripe over-writes itself | ||
2205 | */ | ||
2206 | sector_t here_new, here_old; | ||
2207 | int old_disks; | ||
2208 | |||
2209 | if (mddev->new_level != mddev->level || | ||
2210 | mddev->new_layout != mddev->layout || | ||
2211 | mddev->new_chunk != mddev->chunk_size) { | ||
2212 | printk(KERN_ERR "raid5: %s: unsupported reshape required - aborting.\n", | ||
2213 | mdname(mddev)); | ||
2214 | return -EINVAL; | ||
2215 | } | ||
2216 | if (mddev->delta_disks <= 0) { | ||
2217 | printk(KERN_ERR "raid5: %s: unsupported reshape (reduce disks) required - aborting.\n", | ||
2218 | mdname(mddev)); | ||
2219 | return -EINVAL; | ||
2220 | } | ||
2221 | old_disks = mddev->raid_disks - mddev->delta_disks; | ||
2222 | /* reshape_position must be on a new-stripe boundary, and one | ||
2223 | * further up in new geometry must map after here in old geometry. | ||
2224 | */ | ||
2225 | here_new = mddev->reshape_position; | ||
2226 | if (sector_div(here_new, (mddev->chunk_size>>9)*(mddev->raid_disks-1))) { | ||
2227 | printk(KERN_ERR "raid5: reshape_position not on a stripe boundary\n"); | ||
2228 | return -EINVAL; | ||
2229 | } | ||
2230 | /* here_new is the stripe we will write to */ | ||
2231 | here_old = mddev->reshape_position; | ||
2232 | sector_div(here_old, (mddev->chunk_size>>9)*(old_disks-1)); | ||
2233 | /* here_old is the first stripe that we might need to read from */ | ||
2234 | if (here_new >= here_old) { | ||
2235 | /* Reading from the same stripe as writing to - bad */ | ||
2236 | printk(KERN_ERR "raid5: reshape_position too early for auto-recovery - aborting.\n"); | ||
2237 | return -EINVAL; | ||
2238 | } | ||
2239 | printk(KERN_INFO "raid5: reshape will continue\n"); | ||
2240 | /* OK, we should be able to continue; */ | ||
2241 | } | ||
2242 | |||
2243 | |||
2244 | mddev->private = kzalloc(sizeof (raid5_conf_t), GFP_KERNEL); | ||
1828 | if ((conf = mddev->private) == NULL) | 2245 | if ((conf = mddev->private) == NULL) |
1829 | goto abort; | 2246 | goto abort; |
2247 | if (mddev->reshape_position == MaxSector) { | ||
2248 | conf->previous_raid_disks = conf->raid_disks = mddev->raid_disks; | ||
2249 | } else { | ||
2250 | conf->raid_disks = mddev->raid_disks; | ||
2251 | conf->previous_raid_disks = mddev->raid_disks - mddev->delta_disks; | ||
2252 | } | ||
2253 | |||
2254 | conf->disks = kzalloc(conf->raid_disks * sizeof(struct disk_info), | ||
2255 | GFP_KERNEL); | ||
2256 | if (!conf->disks) | ||
2257 | goto abort; | ||
1830 | 2258 | ||
1831 | conf->mddev = mddev; | 2259 | conf->mddev = mddev; |
1832 | 2260 | ||
@@ -1847,7 +2275,7 @@ static int run(mddev_t *mddev) | |||
1847 | 2275 | ||
1848 | ITERATE_RDEV(mddev,rdev,tmp) { | 2276 | ITERATE_RDEV(mddev,rdev,tmp) { |
1849 | raid_disk = rdev->raid_disk; | 2277 | raid_disk = rdev->raid_disk; |
1850 | if (raid_disk >= mddev->raid_disks | 2278 | if (raid_disk >= conf->raid_disks |
1851 | || raid_disk < 0) | 2279 | || raid_disk < 0) |
1852 | continue; | 2280 | continue; |
1853 | disk = conf->disks + raid_disk; | 2281 | disk = conf->disks + raid_disk; |
@@ -1863,7 +2291,6 @@ static int run(mddev_t *mddev) | |||
1863 | } | 2291 | } |
1864 | } | 2292 | } |
1865 | 2293 | ||
1866 | conf->raid_disks = mddev->raid_disks; | ||
1867 | /* | 2294 | /* |
1868 | * 0 for a fully functional array, 1 for a degraded array. | 2295 | * 0 for a fully functional array, 1 for a degraded array. |
1869 | */ | 2296 | */ |
@@ -1873,6 +2300,7 @@ static int run(mddev_t *mddev) | |||
1873 | conf->level = mddev->level; | 2300 | conf->level = mddev->level; |
1874 | conf->algorithm = mddev->layout; | 2301 | conf->algorithm = mddev->layout; |
1875 | conf->max_nr_stripes = NR_STRIPES; | 2302 | conf->max_nr_stripes = NR_STRIPES; |
2303 | conf->expand_progress = mddev->reshape_position; | ||
1876 | 2304 | ||
1877 | /* device size must be a multiple of chunk size */ | 2305 | /* device size must be a multiple of chunk size */ |
1878 | mddev->size &= ~(mddev->chunk_size/1024 -1); | 2306 | mddev->size &= ~(mddev->chunk_size/1024 -1); |
@@ -1945,6 +2373,21 @@ static int run(mddev_t *mddev) | |||
1945 | 2373 | ||
1946 | print_raid5_conf(conf); | 2374 | print_raid5_conf(conf); |
1947 | 2375 | ||
2376 | if (conf->expand_progress != MaxSector) { | ||
2377 | printk("...ok start reshape thread\n"); | ||
2378 | conf->expand_lo = conf->expand_progress; | ||
2379 | atomic_set(&conf->reshape_stripes, 0); | ||
2380 | clear_bit(MD_RECOVERY_SYNC, &mddev->recovery); | ||
2381 | clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); | ||
2382 | set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery); | ||
2383 | set_bit(MD_RECOVERY_RUNNING, &mddev->recovery); | ||
2384 | mddev->sync_thread = md_register_thread(md_do_sync, mddev, | ||
2385 | "%s_reshape"); | ||
2386 | /* FIXME if md_register_thread fails?? */ | ||
2387 | md_wakeup_thread(mddev->sync_thread); | ||
2388 | |||
2389 | } | ||
2390 | |||
1948 | /* read-ahead size must cover two whole stripes, which is | 2391 | /* read-ahead size must cover two whole stripes, which is |
1949 | * 2 * (n-1) * chunksize where 'n' is the number of raid devices | 2392 | * 2 * (n-1) * chunksize where 'n' is the number of raid devices |
1950 | */ | 2393 | */ |
@@ -1960,12 +2403,13 @@ static int run(mddev_t *mddev) | |||
1960 | 2403 | ||
1961 | mddev->queue->unplug_fn = raid5_unplug_device; | 2404 | mddev->queue->unplug_fn = raid5_unplug_device; |
1962 | mddev->queue->issue_flush_fn = raid5_issue_flush; | 2405 | mddev->queue->issue_flush_fn = raid5_issue_flush; |
2406 | mddev->array_size = mddev->size * (conf->previous_raid_disks - 1); | ||
1963 | 2407 | ||
1964 | mddev->array_size = mddev->size * (mddev->raid_disks - 1); | ||
1965 | return 0; | 2408 | return 0; |
1966 | abort: | 2409 | abort: |
1967 | if (conf) { | 2410 | if (conf) { |
1968 | print_raid5_conf(conf); | 2411 | print_raid5_conf(conf); |
2412 | kfree(conf->disks); | ||
1969 | kfree(conf->stripe_hashtbl); | 2413 | kfree(conf->stripe_hashtbl); |
1970 | kfree(conf); | 2414 | kfree(conf); |
1971 | } | 2415 | } |
@@ -1986,6 +2430,7 @@ static int stop(mddev_t *mddev) | |||
1986 | kfree(conf->stripe_hashtbl); | 2430 | kfree(conf->stripe_hashtbl); |
1987 | blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ | 2431 | blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ |
1988 | sysfs_remove_group(&mddev->kobj, &raid5_attrs_group); | 2432 | sysfs_remove_group(&mddev->kobj, &raid5_attrs_group); |
2433 | kfree(conf->disks); | ||
1989 | kfree(conf); | 2434 | kfree(conf); |
1990 | mddev->private = NULL; | 2435 | mddev->private = NULL; |
1991 | return 0; | 2436 | return 0; |
@@ -2001,7 +2446,7 @@ static void print_sh (struct stripe_head *sh) | |||
2001 | printk("sh %llu, count %d.\n", | 2446 | printk("sh %llu, count %d.\n", |
2002 | (unsigned long long)sh->sector, atomic_read(&sh->count)); | 2447 | (unsigned long long)sh->sector, atomic_read(&sh->count)); |
2003 | printk("sh %llu, ", (unsigned long long)sh->sector); | 2448 | printk("sh %llu, ", (unsigned long long)sh->sector); |
2004 | for (i = 0; i < sh->raid_conf->raid_disks; i++) { | 2449 | for (i = 0; i < sh->disks; i++) { |
2005 | printk("(cache%d: %p %ld) ", | 2450 | printk("(cache%d: %p %ld) ", |
2006 | i, sh->dev[i].page, sh->dev[i].flags); | 2451 | i, sh->dev[i].page, sh->dev[i].flags); |
2007 | } | 2452 | } |
@@ -2132,7 +2577,7 @@ static int raid5_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) | |||
2132 | /* | 2577 | /* |
2133 | * find the disk ... | 2578 | * find the disk ... |
2134 | */ | 2579 | */ |
2135 | for (disk=0; disk < mddev->raid_disks; disk++) | 2580 | for (disk=0; disk < conf->raid_disks; disk++) |
2136 | if ((p=conf->disks + disk)->rdev == NULL) { | 2581 | if ((p=conf->disks + disk)->rdev == NULL) { |
2137 | clear_bit(In_sync, &rdev->flags); | 2582 | clear_bit(In_sync, &rdev->flags); |
2138 | rdev->raid_disk = disk; | 2583 | rdev->raid_disk = disk; |
@@ -2168,11 +2613,146 @@ static int raid5_resize(mddev_t *mddev, sector_t sectors) | |||
2168 | return 0; | 2613 | return 0; |
2169 | } | 2614 | } |
2170 | 2615 | ||
2616 | #ifdef CONFIG_MD_RAID5_RESHAPE | ||
2617 | static int raid5_check_reshape(mddev_t *mddev) | ||
2618 | { | ||
2619 | raid5_conf_t *conf = mddev_to_conf(mddev); | ||
2620 | int err; | ||
2621 | |||
2622 | if (mddev->delta_disks < 0 || | ||
2623 | mddev->new_level != mddev->level) | ||
2624 | return -EINVAL; /* Cannot shrink array or change level yet */ | ||
2625 | if (mddev->delta_disks == 0) | ||
2626 | return 0; /* nothing to do */ | ||
2627 | |||
2628 | /* Can only proceed if there are plenty of stripe_heads. | ||
2629 | * We need a minimum of one full stripe,, and for sensible progress | ||
2630 | * it is best to have about 4 times that. | ||
2631 | * If we require 4 times, then the default 256 4K stripe_heads will | ||
2632 | * allow for chunk sizes up to 256K, which is probably OK. | ||
2633 | * If the chunk size is greater, user-space should request more | ||
2634 | * stripe_heads first. | ||
2635 | */ | ||
2636 | if ((mddev->chunk_size / STRIPE_SIZE) * 4 > conf->max_nr_stripes || | ||
2637 | (mddev->new_chunk / STRIPE_SIZE) * 4 > conf->max_nr_stripes) { | ||
2638 | printk(KERN_WARNING "raid5: reshape: not enough stripes. Needed %lu\n", | ||
2639 | (mddev->chunk_size / STRIPE_SIZE)*4); | ||
2640 | return -ENOSPC; | ||
2641 | } | ||
2642 | |||
2643 | err = resize_stripes(conf, conf->raid_disks + mddev->delta_disks); | ||
2644 | if (err) | ||
2645 | return err; | ||
2646 | |||
2647 | /* looks like we might be able to manage this */ | ||
2648 | return 0; | ||
2649 | } | ||
2650 | |||
2651 | static int raid5_start_reshape(mddev_t *mddev) | ||
2652 | { | ||
2653 | raid5_conf_t *conf = mddev_to_conf(mddev); | ||
2654 | mdk_rdev_t *rdev; | ||
2655 | struct list_head *rtmp; | ||
2656 | int spares = 0; | ||
2657 | int added_devices = 0; | ||
2658 | |||
2659 | if (mddev->degraded || | ||
2660 | test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) | ||
2661 | return -EBUSY; | ||
2662 | |||
2663 | ITERATE_RDEV(mddev, rdev, rtmp) | ||
2664 | if (rdev->raid_disk < 0 && | ||
2665 | !test_bit(Faulty, &rdev->flags)) | ||
2666 | spares++; | ||
2667 | |||
2668 | if (spares < mddev->delta_disks-1) | ||
2669 | /* Not enough devices even to make a degraded array | ||
2670 | * of that size | ||
2671 | */ | ||
2672 | return -EINVAL; | ||
2673 | |||
2674 | atomic_set(&conf->reshape_stripes, 0); | ||
2675 | spin_lock_irq(&conf->device_lock); | ||
2676 | conf->previous_raid_disks = conf->raid_disks; | ||
2677 | conf->raid_disks += mddev->delta_disks; | ||
2678 | conf->expand_progress = 0; | ||
2679 | conf->expand_lo = 0; | ||
2680 | spin_unlock_irq(&conf->device_lock); | ||
2681 | |||
2682 | /* Add some new drives, as many as will fit. | ||
2683 | * We know there are enough to make the newly sized array work. | ||
2684 | */ | ||
2685 | ITERATE_RDEV(mddev, rdev, rtmp) | ||
2686 | if (rdev->raid_disk < 0 && | ||
2687 | !test_bit(Faulty, &rdev->flags)) { | ||
2688 | if (raid5_add_disk(mddev, rdev)) { | ||
2689 | char nm[20]; | ||
2690 | set_bit(In_sync, &rdev->flags); | ||
2691 | conf->working_disks++; | ||
2692 | added_devices++; | ||
2693 | sprintf(nm, "rd%d", rdev->raid_disk); | ||
2694 | sysfs_create_link(&mddev->kobj, &rdev->kobj, nm); | ||
2695 | } else | ||
2696 | break; | ||
2697 | } | ||
2698 | |||
2699 | mddev->degraded = (conf->raid_disks - conf->previous_raid_disks) - added_devices; | ||
2700 | mddev->raid_disks = conf->raid_disks; | ||
2701 | mddev->reshape_position = 0; | ||
2702 | mddev->sb_dirty = 1; | ||
2703 | |||
2704 | clear_bit(MD_RECOVERY_SYNC, &mddev->recovery); | ||
2705 | clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); | ||
2706 | set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery); | ||
2707 | set_bit(MD_RECOVERY_RUNNING, &mddev->recovery); | ||
2708 | mddev->sync_thread = md_register_thread(md_do_sync, mddev, | ||
2709 | "%s_reshape"); | ||
2710 | if (!mddev->sync_thread) { | ||
2711 | mddev->recovery = 0; | ||
2712 | spin_lock_irq(&conf->device_lock); | ||
2713 | mddev->raid_disks = conf->raid_disks = conf->previous_raid_disks; | ||
2714 | conf->expand_progress = MaxSector; | ||
2715 | spin_unlock_irq(&conf->device_lock); | ||
2716 | return -EAGAIN; | ||
2717 | } | ||
2718 | md_wakeup_thread(mddev->sync_thread); | ||
2719 | md_new_event(mddev); | ||
2720 | return 0; | ||
2721 | } | ||
2722 | #endif | ||
2723 | |||
2724 | static void end_reshape(raid5_conf_t *conf) | ||
2725 | { | ||
2726 | struct block_device *bdev; | ||
2727 | |||
2728 | if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) { | ||
2729 | conf->mddev->array_size = conf->mddev->size * (conf->raid_disks-1); | ||
2730 | set_capacity(conf->mddev->gendisk, conf->mddev->array_size << 1); | ||
2731 | conf->mddev->changed = 1; | ||
2732 | |||
2733 | bdev = bdget_disk(conf->mddev->gendisk, 0); | ||
2734 | if (bdev) { | ||
2735 | mutex_lock(&bdev->bd_inode->i_mutex); | ||
2736 | i_size_write(bdev->bd_inode, conf->mddev->array_size << 10); | ||
2737 | mutex_unlock(&bdev->bd_inode->i_mutex); | ||
2738 | bdput(bdev); | ||
2739 | } | ||
2740 | spin_lock_irq(&conf->device_lock); | ||
2741 | conf->expand_progress = MaxSector; | ||
2742 | spin_unlock_irq(&conf->device_lock); | ||
2743 | conf->mddev->reshape_position = MaxSector; | ||
2744 | } | ||
2745 | } | ||
2746 | |||
2171 | static void raid5_quiesce(mddev_t *mddev, int state) | 2747 | static void raid5_quiesce(mddev_t *mddev, int state) |
2172 | { | 2748 | { |
2173 | raid5_conf_t *conf = mddev_to_conf(mddev); | 2749 | raid5_conf_t *conf = mddev_to_conf(mddev); |
2174 | 2750 | ||
2175 | switch(state) { | 2751 | switch(state) { |
2752 | case 2: /* resume for a suspend */ | ||
2753 | wake_up(&conf->wait_for_overlap); | ||
2754 | break; | ||
2755 | |||
2176 | case 1: /* stop all writes */ | 2756 | case 1: /* stop all writes */ |
2177 | spin_lock_irq(&conf->device_lock); | 2757 | spin_lock_irq(&conf->device_lock); |
2178 | conf->quiesce = 1; | 2758 | conf->quiesce = 1; |
@@ -2186,6 +2766,7 @@ static void raid5_quiesce(mddev_t *mddev, int state) | |||
2186 | spin_lock_irq(&conf->device_lock); | 2766 | spin_lock_irq(&conf->device_lock); |
2187 | conf->quiesce = 0; | 2767 | conf->quiesce = 0; |
2188 | wake_up(&conf->wait_for_stripe); | 2768 | wake_up(&conf->wait_for_stripe); |
2769 | wake_up(&conf->wait_for_overlap); | ||
2189 | spin_unlock_irq(&conf->device_lock); | 2770 | spin_unlock_irq(&conf->device_lock); |
2190 | break; | 2771 | break; |
2191 | } | 2772 | } |
@@ -2206,6 +2787,10 @@ static struct mdk_personality raid5_personality = | |||
2206 | .spare_active = raid5_spare_active, | 2787 | .spare_active = raid5_spare_active, |
2207 | .sync_request = sync_request, | 2788 | .sync_request = sync_request, |
2208 | .resize = raid5_resize, | 2789 | .resize = raid5_resize, |
2790 | #ifdef CONFIG_MD_RAID5_RESHAPE | ||
2791 | .check_reshape = raid5_check_reshape, | ||
2792 | .start_reshape = raid5_start_reshape, | ||
2793 | #endif | ||
2209 | .quiesce = raid5_quiesce, | 2794 | .quiesce = raid5_quiesce, |
2210 | }; | 2795 | }; |
2211 | 2796 | ||
diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index cd477ebf2ee4..6df4930fddec 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c | |||
@@ -331,9 +331,9 @@ static int grow_stripes(raid6_conf_t *conf, int num) | |||
331 | kmem_cache_t *sc; | 331 | kmem_cache_t *sc; |
332 | int devs = conf->raid_disks; | 332 | int devs = conf->raid_disks; |
333 | 333 | ||
334 | sprintf(conf->cache_name, "raid6/%s", mdname(conf->mddev)); | 334 | sprintf(conf->cache_name[0], "raid6/%s", mdname(conf->mddev)); |
335 | 335 | ||
336 | sc = kmem_cache_create(conf->cache_name, | 336 | sc = kmem_cache_create(conf->cache_name[0], |
337 | sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev), | 337 | sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev), |
338 | 0, 0, NULL, NULL); | 338 | 0, 0, NULL, NULL); |
339 | if (!sc) | 339 | if (!sc) |
@@ -2006,11 +2006,14 @@ static int run(mddev_t *mddev) | |||
2006 | return -EIO; | 2006 | return -EIO; |
2007 | } | 2007 | } |
2008 | 2008 | ||
2009 | mddev->private = kzalloc(sizeof (raid6_conf_t) | 2009 | mddev->private = kzalloc(sizeof (raid6_conf_t), GFP_KERNEL); |
2010 | + mddev->raid_disks * sizeof(struct disk_info), | ||
2011 | GFP_KERNEL); | ||
2012 | if ((conf = mddev->private) == NULL) | 2010 | if ((conf = mddev->private) == NULL) |
2013 | goto abort; | 2011 | goto abort; |
2012 | conf->disks = kzalloc(mddev->raid_disks * sizeof(struct disk_info), | ||
2013 | GFP_KERNEL); | ||
2014 | if (!conf->disks) | ||
2015 | goto abort; | ||
2016 | |||
2014 | conf->mddev = mddev; | 2017 | conf->mddev = mddev; |
2015 | 2018 | ||
2016 | if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL) | 2019 | if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL) |
@@ -2158,6 +2161,7 @@ abort: | |||
2158 | print_raid6_conf(conf); | 2161 | print_raid6_conf(conf); |
2159 | safe_put_page(conf->spare_page); | 2162 | safe_put_page(conf->spare_page); |
2160 | kfree(conf->stripe_hashtbl); | 2163 | kfree(conf->stripe_hashtbl); |
2164 | kfree(conf->disks); | ||
2161 | kfree(conf); | 2165 | kfree(conf); |
2162 | } | 2166 | } |
2163 | mddev->private = NULL; | 2167 | mddev->private = NULL; |
diff --git a/drivers/misc/ibmasm/heartbeat.c b/drivers/misc/ibmasm/heartbeat.c index f295401fac21..7fd7a43e38de 100644 --- a/drivers/misc/ibmasm/heartbeat.c +++ b/drivers/misc/ibmasm/heartbeat.c | |||
@@ -52,12 +52,13 @@ static struct notifier_block panic_notifier = { panic_happened, NULL, 1 }; | |||
52 | 52 | ||
53 | void ibmasm_register_panic_notifier(void) | 53 | void ibmasm_register_panic_notifier(void) |
54 | { | 54 | { |
55 | notifier_chain_register(&panic_notifier_list, &panic_notifier); | 55 | atomic_notifier_chain_register(&panic_notifier_list, &panic_notifier); |
56 | } | 56 | } |
57 | 57 | ||
58 | void ibmasm_unregister_panic_notifier(void) | 58 | void ibmasm_unregister_panic_notifier(void) |
59 | { | 59 | { |
60 | notifier_chain_unregister(&panic_notifier_list, &panic_notifier); | 60 | atomic_notifier_chain_unregister(&panic_notifier_list, |
61 | &panic_notifier); | ||
61 | } | 62 | } |
62 | 63 | ||
63 | 64 | ||
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 2d0ac169a86c..f13a539dc169 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -3159,7 +3159,7 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave | |||
3159 | * bond_netdev_event: handle netdev notifier chain events. | 3159 | * bond_netdev_event: handle netdev notifier chain events. |
3160 | * | 3160 | * |
3161 | * This function receives events for the netdev chain. The caller (an | 3161 | * This function receives events for the netdev chain. The caller (an |
3162 | * ioctl handler calling notifier_call_chain) holds the necessary | 3162 | * ioctl handler calling blocking_notifier_call_chain) holds the necessary |
3163 | * locks for us to safely manipulate the slave devices (RTNL lock, | 3163 | * locks for us to safely manipulate the slave devices (RTNL lock, |
3164 | * dev_probe_lock). | 3164 | * dev_probe_lock). |
3165 | */ | 3165 | */ |
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 83141a3ff546..9aa074b44dd3 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c | |||
@@ -207,7 +207,7 @@ static int __init nsc_ircc_init(void) | |||
207 | /* Register with PnP subsystem to detect disable ports */ | 207 | /* Register with PnP subsystem to detect disable ports */ |
208 | ret = pnp_register_driver(&nsc_ircc_pnp_driver); | 208 | ret = pnp_register_driver(&nsc_ircc_pnp_driver); |
209 | 209 | ||
210 | if (ret >= 0) | 210 | if (!ret) |
211 | pnp_registered = 1; | 211 | pnp_registered = 1; |
212 | 212 | ||
213 | ret = -ENODEV; | 213 | ret = -ENODEV; |
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index 3627a2d7f79f..298f2ddb2c17 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c | |||
@@ -499,11 +499,16 @@ static int led_halt(struct notifier_block *, unsigned long, void *); | |||
499 | static struct notifier_block led_notifier = { | 499 | static struct notifier_block led_notifier = { |
500 | .notifier_call = led_halt, | 500 | .notifier_call = led_halt, |
501 | }; | 501 | }; |
502 | static int notifier_disabled = 0; | ||
502 | 503 | ||
503 | static int led_halt(struct notifier_block *nb, unsigned long event, void *buf) | 504 | static int led_halt(struct notifier_block *nb, unsigned long event, void *buf) |
504 | { | 505 | { |
505 | char *txt; | 506 | char *txt; |
506 | 507 | ||
508 | if (notifier_disabled) | ||
509 | return NOTIFY_OK; | ||
510 | |||
511 | notifier_disabled = 1; | ||
507 | switch (event) { | 512 | switch (event) { |
508 | case SYS_RESTART: txt = "SYSTEM RESTART"; | 513 | case SYS_RESTART: txt = "SYSTEM RESTART"; |
509 | break; | 514 | break; |
@@ -527,7 +532,6 @@ static int led_halt(struct notifier_block *nb, unsigned long event, void *buf) | |||
527 | if (led_func_ptr) | 532 | if (led_func_ptr) |
528 | led_func_ptr(0xff); /* turn all LEDs ON */ | 533 | led_func_ptr(0xff); /* turn all LEDs ON */ |
529 | 534 | ||
530 | unregister_reboot_notifier(&led_notifier); | ||
531 | return NOTIFY_OK; | 535 | return NOTIFY_OK; |
532 | } | 536 | } |
533 | 537 | ||
@@ -758,6 +762,12 @@ not_found: | |||
758 | return 1; | 762 | return 1; |
759 | } | 763 | } |
760 | 764 | ||
765 | static void __exit led_exit(void) | ||
766 | { | ||
767 | unregister_reboot_notifier(&led_notifier); | ||
768 | return; | ||
769 | } | ||
770 | |||
761 | #ifdef CONFIG_PROC_FS | 771 | #ifdef CONFIG_PROC_FS |
762 | module_init(led_create_procfs) | 772 | module_init(led_create_procfs) |
763 | #endif | 773 | #endif |
diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c index 54b2b7f20b96..0bcab83b4080 100644 --- a/drivers/parisc/power.c +++ b/drivers/parisc/power.c | |||
@@ -251,7 +251,8 @@ static int __init power_init(void) | |||
251 | } | 251 | } |
252 | 252 | ||
253 | /* Register a call for panic conditions. */ | 253 | /* Register a call for panic conditions. */ |
254 | notifier_chain_register(&panic_notifier_list, &parisc_panic_block); | 254 | atomic_notifier_chain_register(&panic_notifier_list, |
255 | &parisc_panic_block); | ||
255 | 256 | ||
256 | tasklet_enable(&power_tasklet); | 257 | tasklet_enable(&power_tasklet); |
257 | 258 | ||
@@ -264,7 +265,8 @@ static void __exit power_exit(void) | |||
264 | return; | 265 | return; |
265 | 266 | ||
266 | tasklet_disable(&power_tasklet); | 267 | tasklet_disable(&power_tasklet); |
267 | notifier_chain_unregister(&panic_notifier_list, &parisc_panic_block); | 268 | atomic_notifier_chain_unregister(&panic_notifier_list, |
269 | &parisc_panic_block); | ||
268 | power_tasklet.func = NULL; | 270 | power_tasklet.func = NULL; |
269 | pdc_soft_power_button(0); | 271 | pdc_soft_power_button(0); |
270 | } | 272 | } |
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 9302b8fd7461..d5890027f8af 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c | |||
@@ -3126,9 +3126,9 @@ parport_pc_find_isa_ports (int autoirq, int autodma) | |||
3126 | * autoirq is PARPORT_IRQ_NONE, PARPORT_IRQ_AUTO, or PARPORT_IRQ_PROBEONLY | 3126 | * autoirq is PARPORT_IRQ_NONE, PARPORT_IRQ_AUTO, or PARPORT_IRQ_PROBEONLY |
3127 | * autodma is PARPORT_DMA_NONE or PARPORT_DMA_AUTO | 3127 | * autodma is PARPORT_DMA_NONE or PARPORT_DMA_AUTO |
3128 | */ | 3128 | */ |
3129 | static int __init parport_pc_find_ports (int autoirq, int autodma) | 3129 | static void __init parport_pc_find_ports (int autoirq, int autodma) |
3130 | { | 3130 | { |
3131 | int count = 0, r; | 3131 | int count = 0, err; |
3132 | 3132 | ||
3133 | #ifdef CONFIG_PARPORT_PC_SUPERIO | 3133 | #ifdef CONFIG_PARPORT_PC_SUPERIO |
3134 | detect_and_report_winbond (); | 3134 | detect_and_report_winbond (); |
@@ -3140,23 +3140,17 @@ static int __init parport_pc_find_ports (int autoirq, int autodma) | |||
3140 | 3140 | ||
3141 | /* PnP ports, skip detection if SuperIO already found them */ | 3141 | /* PnP ports, skip detection if SuperIO already found them */ |
3142 | if (!count) { | 3142 | if (!count) { |
3143 | r = pnp_register_driver (&parport_pc_pnp_driver); | 3143 | err = pnp_register_driver (&parport_pc_pnp_driver); |
3144 | if (r >= 0) { | 3144 | if (!err) |
3145 | pnp_registered_parport = 1; | 3145 | pnp_registered_parport = 1; |
3146 | count += r; | ||
3147 | } | ||
3148 | } | 3146 | } |
3149 | 3147 | ||
3150 | /* ISA ports and whatever (see asm/parport.h). */ | 3148 | /* ISA ports and whatever (see asm/parport.h). */ |
3151 | count += parport_pc_find_nonpci_ports (autoirq, autodma); | 3149 | parport_pc_find_nonpci_ports (autoirq, autodma); |
3152 | |||
3153 | r = pci_register_driver (&parport_pc_pci_driver); | ||
3154 | if (r) | ||
3155 | return r; | ||
3156 | pci_registered_parport = 1; | ||
3157 | count += 1; | ||
3158 | 3150 | ||
3159 | return count; | 3151 | err = pci_register_driver (&parport_pc_pci_driver); |
3152 | if (!err) | ||
3153 | pci_registered_parport = 1; | ||
3160 | } | 3154 | } |
3161 | 3155 | ||
3162 | /* | 3156 | /* |
@@ -3381,8 +3375,6 @@ __setup("parport_init_mode=",parport_init_mode_setup); | |||
3381 | 3375 | ||
3382 | static int __init parport_pc_init(void) | 3376 | static int __init parport_pc_init(void) |
3383 | { | 3377 | { |
3384 | int count = 0; | ||
3385 | |||
3386 | if (parse_parport_params()) | 3378 | if (parse_parport_params()) |
3387 | return -EINVAL; | 3379 | return -EINVAL; |
3388 | 3380 | ||
@@ -3395,12 +3387,11 @@ static int __init parport_pc_init(void) | |||
3395 | break; | 3387 | break; |
3396 | if ((io_hi[i]) == PARPORT_IOHI_AUTO) | 3388 | if ((io_hi[i]) == PARPORT_IOHI_AUTO) |
3397 | io_hi[i] = 0x400 + io[i]; | 3389 | io_hi[i] = 0x400 + io[i]; |
3398 | if (parport_pc_probe_port(io[i], io_hi[i], | 3390 | parport_pc_probe_port(io[i], io_hi[i], |
3399 | irqval[i], dmaval[i], NULL)) | 3391 | irqval[i], dmaval[i], NULL); |
3400 | count++; | ||
3401 | } | 3392 | } |
3402 | } else | 3393 | } else |
3403 | count += parport_pc_find_ports (irqval[0], dmaval[0]); | 3394 | parport_pc_find_ports (irqval[0], dmaval[0]); |
3404 | 3395 | ||
3405 | return 0; | 3396 | return 0; |
3406 | } | 3397 | } |
diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c index b68eef251614..bb19c64073c6 100644 --- a/drivers/pnp/card.c +++ b/drivers/pnp/card.c | |||
@@ -47,7 +47,7 @@ static void card_remove(struct pnp_dev * dev) | |||
47 | { | 47 | { |
48 | dev->card_link = NULL; | 48 | dev->card_link = NULL; |
49 | } | 49 | } |
50 | 50 | ||
51 | static void card_remove_first(struct pnp_dev * dev) | 51 | static void card_remove_first(struct pnp_dev * dev) |
52 | { | 52 | { |
53 | struct pnp_card_driver * drv = to_pnp_card_driver(dev->driver); | 53 | struct pnp_card_driver * drv = to_pnp_card_driver(dev->driver); |
@@ -361,7 +361,7 @@ static int card_resume(struct pnp_dev *dev) | |||
361 | 361 | ||
362 | int pnp_register_card_driver(struct pnp_card_driver * drv) | 362 | int pnp_register_card_driver(struct pnp_card_driver * drv) |
363 | { | 363 | { |
364 | int count; | 364 | int error; |
365 | struct list_head *pos, *temp; | 365 | struct list_head *pos, *temp; |
366 | 366 | ||
367 | drv->link.name = drv->name; | 367 | drv->link.name = drv->name; |
@@ -372,21 +372,19 @@ int pnp_register_card_driver(struct pnp_card_driver * drv) | |||
372 | drv->link.suspend = drv->suspend ? card_suspend : NULL; | 372 | drv->link.suspend = drv->suspend ? card_suspend : NULL; |
373 | drv->link.resume = drv->resume ? card_resume : NULL; | 373 | drv->link.resume = drv->resume ? card_resume : NULL; |
374 | 374 | ||
375 | count = pnp_register_driver(&drv->link); | 375 | error = pnp_register_driver(&drv->link); |
376 | if (count < 0) | 376 | if (error < 0) |
377 | return count; | 377 | return error; |
378 | 378 | ||
379 | spin_lock(&pnp_lock); | 379 | spin_lock(&pnp_lock); |
380 | list_add_tail(&drv->global_list, &pnp_card_drivers); | 380 | list_add_tail(&drv->global_list, &pnp_card_drivers); |
381 | spin_unlock(&pnp_lock); | 381 | spin_unlock(&pnp_lock); |
382 | 382 | ||
383 | count = 0; | ||
384 | |||
385 | list_for_each_safe(pos,temp,&pnp_cards){ | 383 | list_for_each_safe(pos,temp,&pnp_cards){ |
386 | struct pnp_card *card = list_entry(pos, struct pnp_card, global_list); | 384 | struct pnp_card *card = list_entry(pos, struct pnp_card, global_list); |
387 | count += card_probe(card,drv); | 385 | card_probe(card,drv); |
388 | } | 386 | } |
389 | return count; | 387 | return 0; |
390 | } | 388 | } |
391 | 389 | ||
392 | /** | 390 | /** |
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c index 7cafacdd12b0..e54c15383193 100644 --- a/drivers/pnp/driver.c +++ b/drivers/pnp/driver.c | |||
@@ -201,31 +201,14 @@ struct bus_type pnp_bus_type = { | |||
201 | .resume = pnp_bus_resume, | 201 | .resume = pnp_bus_resume, |
202 | }; | 202 | }; |
203 | 203 | ||
204 | |||
205 | static int count_devices(struct device * dev, void * c) | ||
206 | { | ||
207 | int * count = c; | ||
208 | (*count)++; | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | int pnp_register_driver(struct pnp_driver *drv) | 204 | int pnp_register_driver(struct pnp_driver *drv) |
213 | { | 205 | { |
214 | int count; | ||
215 | |||
216 | pnp_dbg("the driver '%s' has been registered", drv->name); | 206 | pnp_dbg("the driver '%s' has been registered", drv->name); |
217 | 207 | ||
218 | drv->driver.name = drv->name; | 208 | drv->driver.name = drv->name; |
219 | drv->driver.bus = &pnp_bus_type; | 209 | drv->driver.bus = &pnp_bus_type; |
220 | 210 | ||
221 | count = driver_register(&drv->driver); | 211 | return driver_register(&drv->driver); |
222 | |||
223 | /* get the number of initial matches */ | ||
224 | if (count >= 0){ | ||
225 | count = 0; | ||
226 | driver_for_each_device(&drv->driver, NULL, &count, count_devices); | ||
227 | } | ||
228 | return count; | ||
229 | } | 212 | } |
230 | 213 | ||
231 | void pnp_unregister_driver(struct pnp_driver *drv) | 214 | void pnp_unregister_driver(struct pnp_driver *drv) |
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig new file mode 100644 index 000000000000..929dd8090578 --- /dev/null +++ b/drivers/rtc/Kconfig | |||
@@ -0,0 +1,165 @@ | |||
1 | \# | ||
2 | # RTC class/drivers configuration | ||
3 | # | ||
4 | |||
5 | menu "Real Time Clock" | ||
6 | |||
7 | config RTC_LIB | ||
8 | tristate | ||
9 | |||
10 | config RTC_CLASS | ||
11 | tristate "RTC class" | ||
12 | depends on EXPERIMENTAL | ||
13 | default n | ||
14 | select RTC_LIB | ||
15 | help | ||
16 | Generic RTC class support. If you say yes here, you will | ||
17 | be allowed to plug one or more RTCs to your system. You will | ||
18 | probably want to enable one of more of the interfaces below. | ||
19 | |||
20 | This driver can also be built as a module. If so, the module | ||
21 | will be called rtc-class. | ||
22 | |||
23 | config RTC_HCTOSYS | ||
24 | bool "Set system time from RTC on startup" | ||
25 | depends on RTC_CLASS = y | ||
26 | default y | ||
27 | help | ||
28 | If you say yes here, the system time will be set using | ||
29 | the value read from the specified RTC device. This is useful | ||
30 | in order to avoid unnecessary fschk runs. | ||
31 | |||
32 | config RTC_HCTOSYS_DEVICE | ||
33 | string "The RTC to read the time from" | ||
34 | depends on RTC_HCTOSYS = y | ||
35 | default "rtc0" | ||
36 | help | ||
37 | The RTC device that will be used as the source for | ||
38 | the system time, usually rtc0. | ||
39 | |||
40 | comment "RTC interfaces" | ||
41 | depends on RTC_CLASS | ||
42 | |||
43 | config RTC_INTF_SYSFS | ||
44 | tristate "sysfs" | ||
45 | depends on RTC_CLASS && SYSFS | ||
46 | default RTC_CLASS | ||
47 | help | ||
48 | Say yes here if you want to use your RTC using the sysfs | ||
49 | interface, /sys/class/rtc/rtcX . | ||
50 | |||
51 | This driver can also be built as a module. If so, the module | ||
52 | will be called rtc-sysfs. | ||
53 | |||
54 | config RTC_INTF_PROC | ||
55 | tristate "proc" | ||
56 | depends on RTC_CLASS && PROC_FS | ||
57 | default RTC_CLASS | ||
58 | help | ||
59 | Say yes here if you want to use your RTC using the proc | ||
60 | interface, /proc/driver/rtc . | ||
61 | |||
62 | This driver can also be built as a module. If so, the module | ||
63 | will be called rtc-proc. | ||
64 | |||
65 | config RTC_INTF_DEV | ||
66 | tristate "dev" | ||
67 | depends on RTC_CLASS | ||
68 | default RTC_CLASS | ||
69 | help | ||
70 | Say yes here if you want to use your RTC using the dev | ||
71 | interface, /dev/rtc . | ||
72 | |||
73 | This driver can also be built as a module. If so, the module | ||
74 | will be called rtc-dev. | ||
75 | |||
76 | comment "RTC drivers" | ||
77 | depends on RTC_CLASS | ||
78 | |||
79 | config RTC_DRV_X1205 | ||
80 | tristate "Xicor/Intersil X1205" | ||
81 | depends on RTC_CLASS && I2C | ||
82 | help | ||
83 | If you say yes here you get support for the | ||
84 | Xicor/Intersil X1205 RTC chip. | ||
85 | |||
86 | This driver can also be built as a module. If so, the module | ||
87 | will be called rtc-x1205. | ||
88 | |||
89 | config RTC_DRV_DS1672 | ||
90 | tristate "Dallas/Maxim DS1672" | ||
91 | depends on RTC_CLASS && I2C | ||
92 | help | ||
93 | If you say yes here you get support for the | ||
94 | Dallas/Maxim DS1672 timekeeping chip. | ||
95 | |||
96 | This driver can also be built as a module. If so, the module | ||
97 | will be called rtc-ds1672. | ||
98 | |||
99 | config RTC_DRV_PCF8563 | ||
100 | tristate "Philips PCF8563/Epson RTC8564" | ||
101 | depends on RTC_CLASS && I2C | ||
102 | help | ||
103 | If you say yes here you get support for the | ||
104 | Philips PCF8563 RTC chip. The Epson RTC8564 | ||
105 | should work as well. | ||
106 | |||
107 | This driver can also be built as a module. If so, the module | ||
108 | will be called rtc-pcf8563. | ||
109 | |||
110 | config RTC_DRV_RS5C372 | ||
111 | tristate "Ricoh RS5C372A/B" | ||
112 | depends on RTC_CLASS && I2C | ||
113 | help | ||
114 | If you say yes here you get support for the | ||
115 | Ricoh RS5C372A and RS5C372B RTC chips. | ||
116 | |||
117 | This driver can also be built as a module. If so, the module | ||
118 | will be called rtc-rs5c372. | ||
119 | |||
120 | config RTC_DRV_M48T86 | ||
121 | tristate "ST M48T86/Dallas DS12887" | ||
122 | depends on RTC_CLASS | ||
123 | help | ||
124 | If you say Y here you will get support for the | ||
125 | ST M48T86 and Dallas DS12887 RTC chips. | ||
126 | |||
127 | This driver can also be built as a module. If so, the module | ||
128 | will be called rtc-m48t86. | ||
129 | |||
130 | config RTC_DRV_EP93XX | ||
131 | tristate "Cirrus Logic EP93XX" | ||
132 | depends on RTC_CLASS && ARCH_EP93XX | ||
133 | help | ||
134 | If you say yes here you get support for the | ||
135 | RTC embedded in the Cirrus Logic EP93XX processors. | ||
136 | |||
137 | This driver can also be built as a module. If so, the module | ||
138 | will be called rtc-ep93xx. | ||
139 | |||
140 | config RTC_DRV_SA1100 | ||
141 | tristate "SA11x0/PXA2xx" | ||
142 | depends on RTC_CLASS && (ARCH_SA1100 || ARCH_PXA) | ||
143 | help | ||
144 | If you say Y here you will get access to the real time clock | ||
145 | built into your SA11x0 or PXA2xx CPU. | ||
146 | |||
147 | To compile this driver as a module, choose M here: the | ||
148 | module will be called rtc-sa1100. | ||
149 | |||
150 | config RTC_DRV_TEST | ||
151 | tristate "Test driver/device" | ||
152 | depends on RTC_CLASS | ||
153 | help | ||
154 | If you say yes here you get support for the | ||
155 | RTC test driver. It's a software RTC which can be | ||
156 | used to test the RTC subsystem APIs. It gets | ||
157 | the time from the system clock. | ||
158 | You want this driver only if you are doing development | ||
159 | on the RTC subsystem. Please read the source code | ||
160 | for further details. | ||
161 | |||
162 | This driver can also be built as a module. If so, the module | ||
163 | will be called rtc-test. | ||
164 | |||
165 | endmenu | ||
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile new file mode 100644 index 000000000000..8d4c7fe88d58 --- /dev/null +++ b/drivers/rtc/Makefile | |||
@@ -0,0 +1,21 @@ | |||
1 | # | ||
2 | # Makefile for RTC class/drivers. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_RTC_LIB) += rtc-lib.o | ||
6 | obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o | ||
7 | obj-$(CONFIG_RTC_CLASS) += rtc-core.o | ||
8 | rtc-core-y := class.o interface.o | ||
9 | |||
10 | obj-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o | ||
11 | obj-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o | ||
12 | obj-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o | ||
13 | |||
14 | obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o | ||
15 | obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o | ||
16 | obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o | ||
17 | obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o | ||
18 | obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o | ||
19 | obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o | ||
20 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o | ||
21 | obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o | ||
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c new file mode 100644 index 000000000000..8533936d50d8 --- /dev/null +++ b/drivers/rtc/class.c | |||
@@ -0,0 +1,145 @@ | |||
1 | /* | ||
2 | * RTC subsystem, base class | ||
3 | * | ||
4 | * Copyright (C) 2005 Tower Technologies | ||
5 | * Author: Alessandro Zummo <a.zummo@towertech.it> | ||
6 | * | ||
7 | * class skeleton from drivers/hwmon/hwmon.c | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/rtc.h> | ||
16 | #include <linux/kdev_t.h> | ||
17 | #include <linux/idr.h> | ||
18 | |||
19 | static DEFINE_IDR(rtc_idr); | ||
20 | static DEFINE_MUTEX(idr_lock); | ||
21 | struct class *rtc_class; | ||
22 | |||
23 | static void rtc_device_release(struct class_device *class_dev) | ||
24 | { | ||
25 | struct rtc_device *rtc = to_rtc_device(class_dev); | ||
26 | mutex_lock(&idr_lock); | ||
27 | idr_remove(&rtc_idr, rtc->id); | ||
28 | mutex_unlock(&idr_lock); | ||
29 | kfree(rtc); | ||
30 | } | ||
31 | |||
32 | /** | ||
33 | * rtc_device_register - register w/ RTC class | ||
34 | * @dev: the device to register | ||
35 | * | ||
36 | * rtc_device_unregister() must be called when the class device is no | ||
37 | * longer needed. | ||
38 | * | ||
39 | * Returns the pointer to the new struct class device. | ||
40 | */ | ||
41 | struct rtc_device *rtc_device_register(const char *name, struct device *dev, | ||
42 | struct rtc_class_ops *ops, | ||
43 | struct module *owner) | ||
44 | { | ||
45 | struct rtc_device *rtc; | ||
46 | int id, err; | ||
47 | |||
48 | if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) { | ||
49 | err = -ENOMEM; | ||
50 | goto exit; | ||
51 | } | ||
52 | |||
53 | |||
54 | mutex_lock(&idr_lock); | ||
55 | err = idr_get_new(&rtc_idr, NULL, &id); | ||
56 | mutex_unlock(&idr_lock); | ||
57 | |||
58 | if (err < 0) | ||
59 | goto exit; | ||
60 | |||
61 | id = id & MAX_ID_MASK; | ||
62 | |||
63 | rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL); | ||
64 | if (rtc == NULL) { | ||
65 | err = -ENOMEM; | ||
66 | goto exit_idr; | ||
67 | } | ||
68 | |||
69 | rtc->id = id; | ||
70 | rtc->ops = ops; | ||
71 | rtc->owner = owner; | ||
72 | rtc->class_dev.dev = dev; | ||
73 | rtc->class_dev.class = rtc_class; | ||
74 | rtc->class_dev.release = rtc_device_release; | ||
75 | |||
76 | mutex_init(&rtc->ops_lock); | ||
77 | spin_lock_init(&rtc->irq_lock); | ||
78 | spin_lock_init(&rtc->irq_task_lock); | ||
79 | |||
80 | strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); | ||
81 | snprintf(rtc->class_dev.class_id, BUS_ID_SIZE, "rtc%d", id); | ||
82 | |||
83 | err = class_device_register(&rtc->class_dev); | ||
84 | if (err) | ||
85 | goto exit_kfree; | ||
86 | |||
87 | dev_info(dev, "rtc core: registered %s as %s\n", | ||
88 | rtc->name, rtc->class_dev.class_id); | ||
89 | |||
90 | return rtc; | ||
91 | |||
92 | exit_kfree: | ||
93 | kfree(rtc); | ||
94 | |||
95 | exit_idr: | ||
96 | idr_remove(&rtc_idr, id); | ||
97 | |||
98 | exit: | ||
99 | return ERR_PTR(err); | ||
100 | } | ||
101 | EXPORT_SYMBOL_GPL(rtc_device_register); | ||
102 | |||
103 | |||
104 | /** | ||
105 | * rtc_device_unregister - removes the previously registered RTC class device | ||
106 | * | ||
107 | * @rtc: the RTC class device to destroy | ||
108 | */ | ||
109 | void rtc_device_unregister(struct rtc_device *rtc) | ||
110 | { | ||
111 | mutex_lock(&rtc->ops_lock); | ||
112 | rtc->ops = NULL; | ||
113 | mutex_unlock(&rtc->ops_lock); | ||
114 | class_device_unregister(&rtc->class_dev); | ||
115 | } | ||
116 | EXPORT_SYMBOL_GPL(rtc_device_unregister); | ||
117 | |||
118 | int rtc_interface_register(struct class_interface *intf) | ||
119 | { | ||
120 | intf->class = rtc_class; | ||
121 | return class_interface_register(intf); | ||
122 | } | ||
123 | EXPORT_SYMBOL_GPL(rtc_interface_register); | ||
124 | |||
125 | static int __init rtc_init(void) | ||
126 | { | ||
127 | rtc_class = class_create(THIS_MODULE, "rtc"); | ||
128 | if (IS_ERR(rtc_class)) { | ||
129 | printk(KERN_ERR "%s: couldn't create class\n", __FILE__); | ||
130 | return PTR_ERR(rtc_class); | ||
131 | } | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static void __exit rtc_exit(void) | ||
136 | { | ||
137 | class_destroy(rtc_class); | ||
138 | } | ||
139 | |||
140 | module_init(rtc_init); | ||
141 | module_exit(rtc_exit); | ||
142 | |||
143 | MODULE_AUTHOR("Alessandro Zummo <a.zummo@towerteh.it>"); | ||
144 | MODULE_DESCRIPTION("RTC class support"); | ||
145 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c new file mode 100644 index 000000000000..d02fe9a0001f --- /dev/null +++ b/drivers/rtc/hctosys.c | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * RTC subsystem, initialize system time on startup | ||
3 | * | ||
4 | * Copyright (C) 2005 Tower Technologies | ||
5 | * Author: Alessandro Zummo <a.zummo@towertech.it> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/rtc.h> | ||
13 | |||
14 | /* IMPORTANT: the RTC only stores whole seconds. It is arbitrary | ||
15 | * whether it stores the most close value or the value with partial | ||
16 | * seconds truncated. However, it is important that we use it to store | ||
17 | * the truncated value. This is because otherwise it is necessary, | ||
18 | * in an rtc sync function, to read both xtime.tv_sec and | ||
19 | * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read | ||
20 | * of >32bits is not possible. So storing the most close value would | ||
21 | * slow down the sync API. So here we have the truncated value and | ||
22 | * the best guess is to add 0.5s. | ||
23 | */ | ||
24 | |||
25 | static int __init rtc_hctosys(void) | ||
26 | { | ||
27 | int err; | ||
28 | struct rtc_time tm; | ||
29 | struct class_device *class_dev = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); | ||
30 | |||
31 | if (class_dev == NULL) { | ||
32 | printk("%s: unable to open rtc device (%s)\n", | ||
33 | __FILE__, CONFIG_RTC_HCTOSYS_DEVICE); | ||
34 | return -ENODEV; | ||
35 | } | ||
36 | |||
37 | err = rtc_read_time(class_dev, &tm); | ||
38 | if (err == 0) { | ||
39 | err = rtc_valid_tm(&tm); | ||
40 | if (err == 0) { | ||
41 | struct timespec tv; | ||
42 | |||
43 | tv.tv_nsec = NSEC_PER_SEC >> 1; | ||
44 | |||
45 | rtc_tm_to_time(&tm, &tv.tv_sec); | ||
46 | |||
47 | do_settimeofday(&tv); | ||
48 | |||
49 | dev_info(class_dev->dev, | ||
50 | "setting the system clock to " | ||
51 | "%d-%02d-%02d %02d:%02d:%02d (%u)\n", | ||
52 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, | ||
53 | tm.tm_hour, tm.tm_min, tm.tm_sec, | ||
54 | (unsigned int) tv.tv_sec); | ||
55 | } | ||
56 | else | ||
57 | dev_err(class_dev->dev, | ||
58 | "hctosys: invalid date/time\n"); | ||
59 | } | ||
60 | else | ||
61 | dev_err(class_dev->dev, | ||
62 | "hctosys: unable to read the hardware clock\n"); | ||
63 | |||
64 | rtc_class_close(class_dev); | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | late_initcall(rtc_hctosys); | ||
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c new file mode 100644 index 000000000000..56e490709b87 --- /dev/null +++ b/drivers/rtc/interface.c | |||
@@ -0,0 +1,277 @@ | |||
1 | /* | ||
2 | * RTC subsystem, interface functions | ||
3 | * | ||
4 | * Copyright (C) 2005 Tower Technologies | ||
5 | * Author: Alessandro Zummo <a.zummo@towertech.it> | ||
6 | * | ||
7 | * based on arch/arm/common/rtctime.c | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/rtc.h> | ||
15 | |||
16 | int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm) | ||
17 | { | ||
18 | int err; | ||
19 | struct rtc_device *rtc = to_rtc_device(class_dev); | ||
20 | |||
21 | err = mutex_lock_interruptible(&rtc->ops_lock); | ||
22 | if (err) | ||
23 | return -EBUSY; | ||
24 | |||
25 | if (!rtc->ops) | ||
26 | err = -ENODEV; | ||
27 | else if (!rtc->ops->read_time) | ||
28 | err = -EINVAL; | ||
29 | else { | ||
30 | memset(tm, 0, sizeof(struct rtc_time)); | ||
31 | err = rtc->ops->read_time(class_dev->dev, tm); | ||
32 | } | ||
33 | |||
34 | mutex_unlock(&rtc->ops_lock); | ||
35 | return err; | ||
36 | } | ||
37 | EXPORT_SYMBOL_GPL(rtc_read_time); | ||
38 | |||
39 | int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm) | ||
40 | { | ||
41 | int err; | ||
42 | struct rtc_device *rtc = to_rtc_device(class_dev); | ||
43 | |||
44 | err = rtc_valid_tm(tm); | ||
45 | if (err != 0) | ||
46 | return err; | ||
47 | |||
48 | err = mutex_lock_interruptible(&rtc->ops_lock); | ||
49 | if (err) | ||
50 | return -EBUSY; | ||
51 | |||
52 | if (!rtc->ops) | ||
53 | err = -ENODEV; | ||
54 | else if (!rtc->ops->set_time) | ||
55 | err = -EINVAL; | ||
56 | else | ||
57 | err = rtc->ops->set_time(class_dev->dev, tm); | ||
58 | |||
59 | mutex_unlock(&rtc->ops_lock); | ||
60 | return err; | ||
61 | } | ||
62 | EXPORT_SYMBOL_GPL(rtc_set_time); | ||
63 | |||
64 | int rtc_set_mmss(struct class_device *class_dev, unsigned long secs) | ||
65 | { | ||
66 | int err; | ||
67 | struct rtc_device *rtc = to_rtc_device(class_dev); | ||
68 | |||
69 | err = mutex_lock_interruptible(&rtc->ops_lock); | ||
70 | if (err) | ||
71 | return -EBUSY; | ||
72 | |||
73 | if (!rtc->ops) | ||
74 | err = -ENODEV; | ||
75 | else if (rtc->ops->set_mmss) | ||
76 | err = rtc->ops->set_mmss(class_dev->dev, secs); | ||
77 | else if (rtc->ops->read_time && rtc->ops->set_time) { | ||
78 | struct rtc_time new, old; | ||
79 | |||
80 | err = rtc->ops->read_time(class_dev->dev, &old); | ||
81 | if (err == 0) { | ||
82 | rtc_time_to_tm(secs, &new); | ||
83 | |||
84 | /* | ||
85 | * avoid writing when we're going to change the day of | ||
86 | * the month. We will retry in the next minute. This | ||
87 | * basically means that if the RTC must not drift | ||
88 | * by more than 1 minute in 11 minutes. | ||
89 | */ | ||
90 | if (!((old.tm_hour == 23 && old.tm_min == 59) || | ||
91 | (new.tm_hour == 23 && new.tm_min == 59))) | ||
92 | err = rtc->ops->set_time(class_dev->dev, &new); | ||
93 | } | ||
94 | } | ||
95 | else | ||
96 | err = -EINVAL; | ||
97 | |||
98 | mutex_unlock(&rtc->ops_lock); | ||
99 | |||
100 | return err; | ||
101 | } | ||
102 | EXPORT_SYMBOL_GPL(rtc_set_mmss); | ||
103 | |||
104 | int rtc_read_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm) | ||
105 | { | ||
106 | int err; | ||
107 | struct rtc_device *rtc = to_rtc_device(class_dev); | ||
108 | |||
109 | err = mutex_lock_interruptible(&rtc->ops_lock); | ||
110 | if (err) | ||
111 | return -EBUSY; | ||
112 | |||
113 | if (rtc->ops == NULL) | ||
114 | err = -ENODEV; | ||
115 | else if (!rtc->ops->read_alarm) | ||
116 | err = -EINVAL; | ||
117 | else { | ||
118 | memset(alarm, 0, sizeof(struct rtc_wkalrm)); | ||
119 | err = rtc->ops->read_alarm(class_dev->dev, alarm); | ||
120 | } | ||
121 | |||
122 | mutex_unlock(&rtc->ops_lock); | ||
123 | return err; | ||
124 | } | ||
125 | EXPORT_SYMBOL_GPL(rtc_read_alarm); | ||
126 | |||
127 | int rtc_set_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm) | ||
128 | { | ||
129 | int err; | ||
130 | struct rtc_device *rtc = to_rtc_device(class_dev); | ||
131 | |||
132 | err = mutex_lock_interruptible(&rtc->ops_lock); | ||
133 | if (err) | ||
134 | return -EBUSY; | ||
135 | |||
136 | if (!rtc->ops) | ||
137 | err = -ENODEV; | ||
138 | else if (!rtc->ops->set_alarm) | ||
139 | err = -EINVAL; | ||
140 | else | ||
141 | err = rtc->ops->set_alarm(class_dev->dev, alarm); | ||
142 | |||
143 | mutex_unlock(&rtc->ops_lock); | ||
144 | return err; | ||
145 | } | ||
146 | EXPORT_SYMBOL_GPL(rtc_set_alarm); | ||
147 | |||
148 | void rtc_update_irq(struct class_device *class_dev, | ||
149 | unsigned long num, unsigned long events) | ||
150 | { | ||
151 | struct rtc_device *rtc = to_rtc_device(class_dev); | ||
152 | |||
153 | spin_lock(&rtc->irq_lock); | ||
154 | rtc->irq_data = (rtc->irq_data + (num << 8)) | events; | ||
155 | spin_unlock(&rtc->irq_lock); | ||
156 | |||
157 | spin_lock(&rtc->irq_task_lock); | ||
158 | if (rtc->irq_task) | ||
159 | rtc->irq_task->func(rtc->irq_task->private_data); | ||
160 | spin_unlock(&rtc->irq_task_lock); | ||
161 | |||
162 | wake_up_interruptible(&rtc->irq_queue); | ||
163 | kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); | ||
164 | } | ||
165 | EXPORT_SYMBOL_GPL(rtc_update_irq); | ||
166 | |||
167 | struct class_device *rtc_class_open(char *name) | ||
168 | { | ||
169 | struct class_device *class_dev = NULL, | ||
170 | *class_dev_tmp; | ||
171 | |||
172 | down(&rtc_class->sem); | ||
173 | list_for_each_entry(class_dev_tmp, &rtc_class->children, node) { | ||
174 | if (strncmp(class_dev_tmp->class_id, name, BUS_ID_SIZE) == 0) { | ||
175 | class_dev = class_dev_tmp; | ||
176 | break; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | if (class_dev) { | ||
181 | if (!try_module_get(to_rtc_device(class_dev)->owner)) | ||
182 | class_dev = NULL; | ||
183 | } | ||
184 | up(&rtc_class->sem); | ||
185 | |||
186 | return class_dev; | ||
187 | } | ||
188 | EXPORT_SYMBOL_GPL(rtc_class_open); | ||
189 | |||
190 | void rtc_class_close(struct class_device *class_dev) | ||
191 | { | ||
192 | module_put(to_rtc_device(class_dev)->owner); | ||
193 | } | ||
194 | EXPORT_SYMBOL_GPL(rtc_class_close); | ||
195 | |||
196 | int rtc_irq_register(struct class_device *class_dev, struct rtc_task *task) | ||
197 | { | ||
198 | int retval = -EBUSY; | ||
199 | struct rtc_device *rtc = to_rtc_device(class_dev); | ||
200 | |||
201 | if (task == NULL || task->func == NULL) | ||
202 | return -EINVAL; | ||
203 | |||
204 | spin_lock(&rtc->irq_task_lock); | ||
205 | if (rtc->irq_task == NULL) { | ||
206 | rtc->irq_task = task; | ||
207 | retval = 0; | ||
208 | } | ||
209 | spin_unlock(&rtc->irq_task_lock); | ||
210 | |||
211 | return retval; | ||
212 | } | ||
213 | EXPORT_SYMBOL_GPL(rtc_irq_register); | ||
214 | |||
215 | void rtc_irq_unregister(struct class_device *class_dev, struct rtc_task *task) | ||
216 | { | ||
217 | struct rtc_device *rtc = to_rtc_device(class_dev); | ||
218 | |||
219 | spin_lock(&rtc->irq_task_lock); | ||
220 | if (rtc->irq_task == task) | ||
221 | rtc->irq_task = NULL; | ||
222 | spin_unlock(&rtc->irq_task_lock); | ||
223 | } | ||
224 | EXPORT_SYMBOL_GPL(rtc_irq_unregister); | ||
225 | |||
226 | int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int enabled) | ||
227 | { | ||
228 | int err = 0; | ||
229 | unsigned long flags; | ||
230 | struct rtc_device *rtc = to_rtc_device(class_dev); | ||
231 | |||
232 | spin_lock_irqsave(&rtc->irq_task_lock, flags); | ||
233 | if (rtc->irq_task != task) | ||
234 | err = -ENXIO; | ||
235 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); | ||
236 | |||
237 | if (err == 0) | ||
238 | err = rtc->ops->irq_set_state(class_dev->dev, enabled); | ||
239 | |||
240 | return err; | ||
241 | } | ||
242 | EXPORT_SYMBOL_GPL(rtc_irq_set_state); | ||
243 | |||
244 | int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq) | ||
245 | { | ||
246 | int err = 0, tmp = 0; | ||
247 | unsigned long flags; | ||
248 | struct rtc_device *rtc = to_rtc_device(class_dev); | ||
249 | |||
250 | /* allowed range is 2-8192 */ | ||
251 | if (freq < 2 || freq > 8192) | ||
252 | return -EINVAL; | ||
253 | /* | ||
254 | FIXME: this does not belong here, will move where appropriate | ||
255 | at a later stage. It cannot hurt right now, trust me :) | ||
256 | if ((freq > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE))) | ||
257 | return -EACCES; | ||
258 | */ | ||
259 | /* check if freq is a power of 2 */ | ||
260 | while (freq > (1 << tmp)) | ||
261 | tmp++; | ||
262 | |||
263 | if (freq != (1 << tmp)) | ||
264 | return -EINVAL; | ||
265 | |||
266 | spin_lock_irqsave(&rtc->irq_task_lock, flags); | ||
267 | if (rtc->irq_task != task) | ||
268 | err = -ENXIO; | ||
269 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); | ||
270 | |||
271 | if (err == 0) { | ||
272 | err = rtc->ops->irq_set_freq(class_dev->dev, freq); | ||
273 | if (err == 0) | ||
274 | rtc->irq_freq = freq; | ||
275 | } | ||
276 | return err; | ||
277 | } | ||
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c new file mode 100644 index 000000000000..b1e3e6179e56 --- /dev/null +++ b/drivers/rtc/rtc-dev.c | |||
@@ -0,0 +1,382 @@ | |||
1 | /* | ||
2 | * RTC subsystem, dev interface | ||
3 | * | ||
4 | * Copyright (C) 2005 Tower Technologies | ||
5 | * Author: Alessandro Zummo <a.zummo@towertech.it> | ||
6 | * | ||
7 | * based on arch/arm/common/rtctime.c | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/rtc.h> | ||
16 | |||
17 | static struct class *rtc_dev_class; | ||
18 | static dev_t rtc_devt; | ||
19 | |||
20 | #define RTC_DEV_MAX 16 /* 16 RTCs should be enough for everyone... */ | ||
21 | |||
22 | static int rtc_dev_open(struct inode *inode, struct file *file) | ||
23 | { | ||
24 | int err; | ||
25 | struct rtc_device *rtc = container_of(inode->i_cdev, | ||
26 | struct rtc_device, char_dev); | ||
27 | struct rtc_class_ops *ops = rtc->ops; | ||
28 | |||
29 | /* We keep the lock as long as the device is in use | ||
30 | * and return immediately if busy | ||
31 | */ | ||
32 | if (!(mutex_trylock(&rtc->char_lock))) | ||
33 | return -EBUSY; | ||
34 | |||
35 | file->private_data = &rtc->class_dev; | ||
36 | |||
37 | err = ops->open ? ops->open(rtc->class_dev.dev) : 0; | ||
38 | if (err == 0) { | ||
39 | spin_lock_irq(&rtc->irq_lock); | ||
40 | rtc->irq_data = 0; | ||
41 | spin_unlock_irq(&rtc->irq_lock); | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | /* something has gone wrong, release the lock */ | ||
47 | mutex_unlock(&rtc->char_lock); | ||
48 | return err; | ||
49 | } | ||
50 | |||
51 | |||
52 | static ssize_t | ||
53 | rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | ||
54 | { | ||
55 | struct rtc_device *rtc = to_rtc_device(file->private_data); | ||
56 | |||
57 | DECLARE_WAITQUEUE(wait, current); | ||
58 | unsigned long data; | ||
59 | ssize_t ret; | ||
60 | |||
61 | if (count < sizeof(unsigned long)) | ||
62 | return -EINVAL; | ||
63 | |||
64 | add_wait_queue(&rtc->irq_queue, &wait); | ||
65 | do { | ||
66 | __set_current_state(TASK_INTERRUPTIBLE); | ||
67 | |||
68 | spin_lock_irq(&rtc->irq_lock); | ||
69 | data = rtc->irq_data; | ||
70 | rtc->irq_data = 0; | ||
71 | spin_unlock_irq(&rtc->irq_lock); | ||
72 | |||
73 | if (data != 0) { | ||
74 | ret = 0; | ||
75 | break; | ||
76 | } | ||
77 | if (file->f_flags & O_NONBLOCK) { | ||
78 | ret = -EAGAIN; | ||
79 | break; | ||
80 | } | ||
81 | if (signal_pending(current)) { | ||
82 | ret = -ERESTARTSYS; | ||
83 | break; | ||
84 | } | ||
85 | schedule(); | ||
86 | } while (1); | ||
87 | set_current_state(TASK_RUNNING); | ||
88 | remove_wait_queue(&rtc->irq_queue, &wait); | ||
89 | |||
90 | if (ret == 0) { | ||
91 | /* Check for any data updates */ | ||
92 | if (rtc->ops->read_callback) | ||
93 | data = rtc->ops->read_callback(rtc->class_dev.dev, data); | ||
94 | |||
95 | ret = put_user(data, (unsigned long __user *)buf); | ||
96 | if (ret == 0) | ||
97 | ret = sizeof(unsigned long); | ||
98 | } | ||
99 | return ret; | ||
100 | } | ||
101 | |||
102 | static unsigned int rtc_dev_poll(struct file *file, poll_table *wait) | ||
103 | { | ||
104 | struct rtc_device *rtc = to_rtc_device(file->private_data); | ||
105 | unsigned long data; | ||
106 | |||
107 | poll_wait(file, &rtc->irq_queue, wait); | ||
108 | |||
109 | data = rtc->irq_data; | ||
110 | |||
111 | return (data != 0) ? (POLLIN | POLLRDNORM) : 0; | ||
112 | } | ||
113 | |||
114 | static int rtc_dev_ioctl(struct inode *inode, struct file *file, | ||
115 | unsigned int cmd, unsigned long arg) | ||
116 | { | ||
117 | int err = 0; | ||
118 | struct class_device *class_dev = file->private_data; | ||
119 | struct rtc_device *rtc = to_rtc_device(class_dev); | ||
120 | struct rtc_class_ops *ops = rtc->ops; | ||
121 | struct rtc_time tm; | ||
122 | struct rtc_wkalrm alarm; | ||
123 | void __user *uarg = (void __user *) arg; | ||
124 | |||
125 | /* avoid conflicting IRQ users */ | ||
126 | if (cmd == RTC_PIE_ON || cmd == RTC_PIE_OFF || cmd == RTC_IRQP_SET) { | ||
127 | spin_lock(&rtc->irq_task_lock); | ||
128 | if (rtc->irq_task) | ||
129 | err = -EBUSY; | ||
130 | spin_unlock(&rtc->irq_task_lock); | ||
131 | |||
132 | if (err < 0) | ||
133 | return err; | ||
134 | } | ||
135 | |||
136 | /* try the driver's ioctl interface */ | ||
137 | if (ops->ioctl) { | ||
138 | err = ops->ioctl(class_dev->dev, cmd, arg); | ||
139 | if (err != -EINVAL) | ||
140 | return err; | ||
141 | } | ||
142 | |||
143 | /* if the driver does not provide the ioctl interface | ||
144 | * or if that particular ioctl was not implemented | ||
145 | * (-EINVAL), we will try to emulate here. | ||
146 | */ | ||
147 | |||
148 | switch (cmd) { | ||
149 | case RTC_ALM_READ: | ||
150 | err = rtc_read_alarm(class_dev, &alarm); | ||
151 | if (err < 0) | ||
152 | return err; | ||
153 | |||
154 | if (copy_to_user(uarg, &alarm.time, sizeof(tm))) | ||
155 | return -EFAULT; | ||
156 | break; | ||
157 | |||
158 | case RTC_ALM_SET: | ||
159 | if (copy_from_user(&alarm.time, uarg, sizeof(tm))) | ||
160 | return -EFAULT; | ||
161 | |||
162 | alarm.enabled = 0; | ||
163 | alarm.pending = 0; | ||
164 | alarm.time.tm_mday = -1; | ||
165 | alarm.time.tm_mon = -1; | ||
166 | alarm.time.tm_year = -1; | ||
167 | alarm.time.tm_wday = -1; | ||
168 | alarm.time.tm_yday = -1; | ||
169 | alarm.time.tm_isdst = -1; | ||
170 | err = rtc_set_alarm(class_dev, &alarm); | ||
171 | break; | ||
172 | |||
173 | case RTC_RD_TIME: | ||
174 | err = rtc_read_time(class_dev, &tm); | ||
175 | if (err < 0) | ||
176 | return err; | ||
177 | |||
178 | if (copy_to_user(uarg, &tm, sizeof(tm))) | ||
179 | return -EFAULT; | ||
180 | break; | ||
181 | |||
182 | case RTC_SET_TIME: | ||
183 | if (!capable(CAP_SYS_TIME)) | ||
184 | return -EACCES; | ||
185 | |||
186 | if (copy_from_user(&tm, uarg, sizeof(tm))) | ||
187 | return -EFAULT; | ||
188 | |||
189 | err = rtc_set_time(class_dev, &tm); | ||
190 | break; | ||
191 | #if 0 | ||
192 | case RTC_EPOCH_SET: | ||
193 | #ifndef rtc_epoch | ||
194 | /* | ||
195 | * There were no RTC clocks before 1900. | ||
196 | */ | ||
197 | if (arg < 1900) { | ||
198 | err = -EINVAL; | ||
199 | break; | ||
200 | } | ||
201 | if (!capable(CAP_SYS_TIME)) { | ||
202 | err = -EACCES; | ||
203 | break; | ||
204 | } | ||
205 | rtc_epoch = arg; | ||
206 | err = 0; | ||
207 | #endif | ||
208 | break; | ||
209 | |||
210 | case RTC_EPOCH_READ: | ||
211 | err = put_user(rtc_epoch, (unsigned long __user *)uarg); | ||
212 | break; | ||
213 | #endif | ||
214 | case RTC_WKALM_SET: | ||
215 | if (copy_from_user(&alarm, uarg, sizeof(alarm))) | ||
216 | return -EFAULT; | ||
217 | |||
218 | err = rtc_set_alarm(class_dev, &alarm); | ||
219 | break; | ||
220 | |||
221 | case RTC_WKALM_RD: | ||
222 | err = rtc_read_alarm(class_dev, &alarm); | ||
223 | if (err < 0) | ||
224 | return err; | ||
225 | |||
226 | if (copy_to_user(uarg, &alarm, sizeof(alarm))) | ||
227 | return -EFAULT; | ||
228 | break; | ||
229 | |||
230 | default: | ||
231 | err = -EINVAL; | ||
232 | break; | ||
233 | } | ||
234 | |||
235 | return err; | ||
236 | } | ||
237 | |||
238 | static int rtc_dev_release(struct inode *inode, struct file *file) | ||
239 | { | ||
240 | struct rtc_device *rtc = to_rtc_device(file->private_data); | ||
241 | |||
242 | if (rtc->ops->release) | ||
243 | rtc->ops->release(rtc->class_dev.dev); | ||
244 | |||
245 | mutex_unlock(&rtc->char_lock); | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static int rtc_dev_fasync(int fd, struct file *file, int on) | ||
250 | { | ||
251 | struct rtc_device *rtc = to_rtc_device(file->private_data); | ||
252 | return fasync_helper(fd, file, on, &rtc->async_queue); | ||
253 | } | ||
254 | |||
255 | static struct file_operations rtc_dev_fops = { | ||
256 | .owner = THIS_MODULE, | ||
257 | .llseek = no_llseek, | ||
258 | .read = rtc_dev_read, | ||
259 | .poll = rtc_dev_poll, | ||
260 | .ioctl = rtc_dev_ioctl, | ||
261 | .open = rtc_dev_open, | ||
262 | .release = rtc_dev_release, | ||
263 | .fasync = rtc_dev_fasync, | ||
264 | }; | ||
265 | |||
266 | /* insertion/removal hooks */ | ||
267 | |||
268 | static int rtc_dev_add_device(struct class_device *class_dev, | ||
269 | struct class_interface *class_intf) | ||
270 | { | ||
271 | int err = 0; | ||
272 | struct rtc_device *rtc = to_rtc_device(class_dev); | ||
273 | |||
274 | if (rtc->id >= RTC_DEV_MAX) { | ||
275 | dev_err(class_dev->dev, "too many RTCs\n"); | ||
276 | return -EINVAL; | ||
277 | } | ||
278 | |||
279 | mutex_init(&rtc->char_lock); | ||
280 | spin_lock_init(&rtc->irq_lock); | ||
281 | init_waitqueue_head(&rtc->irq_queue); | ||
282 | |||
283 | cdev_init(&rtc->char_dev, &rtc_dev_fops); | ||
284 | rtc->char_dev.owner = rtc->owner; | ||
285 | |||
286 | if (cdev_add(&rtc->char_dev, MKDEV(MAJOR(rtc_devt), rtc->id), 1)) { | ||
287 | cdev_del(&rtc->char_dev); | ||
288 | dev_err(class_dev->dev, | ||
289 | "failed to add char device %d:%d\n", | ||
290 | MAJOR(rtc_devt), rtc->id); | ||
291 | return -ENODEV; | ||
292 | } | ||
293 | |||
294 | rtc->rtc_dev = class_device_create(rtc_dev_class, NULL, | ||
295 | MKDEV(MAJOR(rtc_devt), rtc->id), | ||
296 | class_dev->dev, "rtc%d", rtc->id); | ||
297 | if (IS_ERR(rtc->rtc_dev)) { | ||
298 | dev_err(class_dev->dev, "cannot create rtc_dev device\n"); | ||
299 | err = PTR_ERR(rtc->rtc_dev); | ||
300 | goto err_cdev_del; | ||
301 | } | ||
302 | |||
303 | dev_info(class_dev->dev, "rtc intf: dev (%d:%d)\n", | ||
304 | MAJOR(rtc->rtc_dev->devt), | ||
305 | MINOR(rtc->rtc_dev->devt)); | ||
306 | |||
307 | return 0; | ||
308 | |||
309 | err_cdev_del: | ||
310 | |||
311 | cdev_del(&rtc->char_dev); | ||
312 | return err; | ||
313 | } | ||
314 | |||
315 | static void rtc_dev_remove_device(struct class_device *class_dev, | ||
316 | struct class_interface *class_intf) | ||
317 | { | ||
318 | struct rtc_device *rtc = to_rtc_device(class_dev); | ||
319 | |||
320 | if (rtc->rtc_dev) { | ||
321 | dev_dbg(class_dev->dev, "removing char %d:%d\n", | ||
322 | MAJOR(rtc->rtc_dev->devt), | ||
323 | MINOR(rtc->rtc_dev->devt)); | ||
324 | |||
325 | class_device_unregister(rtc->rtc_dev); | ||
326 | cdev_del(&rtc->char_dev); | ||
327 | } | ||
328 | } | ||
329 | |||
330 | /* interface registration */ | ||
331 | |||
332 | static struct class_interface rtc_dev_interface = { | ||
333 | .add = &rtc_dev_add_device, | ||
334 | .remove = &rtc_dev_remove_device, | ||
335 | }; | ||
336 | |||
337 | static int __init rtc_dev_init(void) | ||
338 | { | ||
339 | int err; | ||
340 | |||
341 | rtc_dev_class = class_create(THIS_MODULE, "rtc-dev"); | ||
342 | if (IS_ERR(rtc_dev_class)) | ||
343 | return PTR_ERR(rtc_dev_class); | ||
344 | |||
345 | err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc"); | ||
346 | if (err < 0) { | ||
347 | printk(KERN_ERR "%s: failed to allocate char dev region\n", | ||
348 | __FILE__); | ||
349 | goto err_destroy_class; | ||
350 | } | ||
351 | |||
352 | err = rtc_interface_register(&rtc_dev_interface); | ||
353 | if (err < 0) { | ||
354 | printk(KERN_ERR "%s: failed to register the interface\n", | ||
355 | __FILE__); | ||
356 | goto err_unregister_chrdev; | ||
357 | } | ||
358 | |||
359 | return 0; | ||
360 | |||
361 | err_unregister_chrdev: | ||
362 | unregister_chrdev_region(rtc_devt, RTC_DEV_MAX); | ||
363 | |||
364 | err_destroy_class: | ||
365 | class_destroy(rtc_dev_class); | ||
366 | |||
367 | return err; | ||
368 | } | ||
369 | |||
370 | static void __exit rtc_dev_exit(void) | ||
371 | { | ||
372 | class_interface_unregister(&rtc_dev_interface); | ||
373 | class_destroy(rtc_dev_class); | ||
374 | unregister_chrdev_region(rtc_devt, RTC_DEV_MAX); | ||
375 | } | ||
376 | |||
377 | module_init(rtc_dev_init); | ||
378 | module_exit(rtc_dev_exit); | ||
379 | |||
380 | MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); | ||
381 | MODULE_DESCRIPTION("RTC class dev interface"); | ||
382 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c new file mode 100644 index 000000000000..358695a416f3 --- /dev/null +++ b/drivers/rtc/rtc-ds1672.c | |||
@@ -0,0 +1,233 @@ | |||
1 | /* | ||
2 | * An rtc/i2c driver for the Dallas DS1672 | ||
3 | * Copyright 2005 Alessandro Zummo | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/i2c.h> | ||
12 | #include <linux/rtc.h> | ||
13 | |||
14 | #define DRV_VERSION "0.2" | ||
15 | |||
16 | /* Addresses to scan: none. This chip cannot be detected. */ | ||
17 | static unsigned short normal_i2c[] = { I2C_CLIENT_END }; | ||
18 | |||
19 | /* Insmod parameters */ | ||
20 | I2C_CLIENT_INSMOD; | ||
21 | |||
22 | /* Registers */ | ||
23 | |||
24 | #define DS1672_REG_CNT_BASE 0 | ||
25 | #define DS1672_REG_CONTROL 4 | ||
26 | #define DS1672_REG_TRICKLE 5 | ||
27 | |||
28 | |||
29 | /* Prototypes */ | ||
30 | static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind); | ||
31 | |||
32 | /* | ||
33 | * In the routines that deal directly with the ds1672 hardware, we use | ||
34 | * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch | ||
35 | * Epoch is initialized as 2000. Time is set to UTC. | ||
36 | */ | ||
37 | static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) | ||
38 | { | ||
39 | unsigned long time; | ||
40 | unsigned char addr = DS1672_REG_CNT_BASE; | ||
41 | unsigned char buf[4]; | ||
42 | |||
43 | struct i2c_msg msgs[] = { | ||
44 | { client->addr, 0, 1, &addr }, /* setup read ptr */ | ||
45 | { client->addr, I2C_M_RD, 4, buf }, /* read date */ | ||
46 | }; | ||
47 | |||
48 | /* read date registers */ | ||
49 | if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { | ||
50 | dev_err(&client->dev, "%s: read error\n", __FUNCTION__); | ||
51 | return -EIO; | ||
52 | } | ||
53 | |||
54 | dev_dbg(&client->dev, | ||
55 | "%s: raw read data - counters=%02x,%02x,%02x,%02x\n" | ||
56 | __FUNCTION__, | ||
57 | buf[0], buf[1], buf[2], buf[3]); | ||
58 | |||
59 | time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; | ||
60 | |||
61 | rtc_time_to_tm(time, tm); | ||
62 | |||
63 | dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " | ||
64 | "mday=%d, mon=%d, year=%d, wday=%d\n", | ||
65 | __FUNCTION__, | ||
66 | tm->tm_sec, tm->tm_min, tm->tm_hour, | ||
67 | tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs) | ||
73 | { | ||
74 | int xfer; | ||
75 | unsigned char buf[5]; | ||
76 | |||
77 | buf[0] = DS1672_REG_CNT_BASE; | ||
78 | buf[1] = secs & 0x000000FF; | ||
79 | buf[2] = (secs & 0x0000FF00) >> 8; | ||
80 | buf[3] = (secs & 0x00FF0000) >> 16; | ||
81 | buf[4] = (secs & 0xFF000000) >> 24; | ||
82 | |||
83 | xfer = i2c_master_send(client, buf, 5); | ||
84 | if (xfer != 5) { | ||
85 | dev_err(&client->dev, "%s: send: %d\n", __FUNCTION__, xfer); | ||
86 | return -EIO; | ||
87 | } | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static int ds1672_set_datetime(struct i2c_client *client, struct rtc_time *tm) | ||
93 | { | ||
94 | unsigned long secs; | ||
95 | |||
96 | dev_dbg(&client->dev, | ||
97 | "%s: secs=%d, mins=%d, hours=%d, ", | ||
98 | "mday=%d, mon=%d, year=%d, wday=%d\n", | ||
99 | __FUNCTION__, | ||
100 | tm->tm_sec, tm->tm_min, tm->tm_hour, | ||
101 | tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); | ||
102 | |||
103 | rtc_tm_to_time(tm, &secs); | ||
104 | |||
105 | return ds1672_set_mmss(client, secs); | ||
106 | } | ||
107 | |||
108 | static int ds1672_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
109 | { | ||
110 | return ds1672_get_datetime(to_i2c_client(dev), tm); | ||
111 | } | ||
112 | |||
113 | static int ds1672_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
114 | { | ||
115 | return ds1672_set_datetime(to_i2c_client(dev), tm); | ||
116 | } | ||
117 | |||
118 | static int ds1672_rtc_set_mmss(struct device *dev, unsigned long secs) | ||
119 | { | ||
120 | return ds1672_set_mmss(to_i2c_client(dev), secs); | ||
121 | } | ||
122 | |||
123 | static struct rtc_class_ops ds1672_rtc_ops = { | ||
124 | .read_time = ds1672_rtc_read_time, | ||
125 | .set_time = ds1672_rtc_set_time, | ||
126 | .set_mmss = ds1672_rtc_set_mmss, | ||
127 | }; | ||
128 | |||
129 | static int ds1672_attach(struct i2c_adapter *adapter) | ||
130 | { | ||
131 | dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); | ||
132 | return i2c_probe(adapter, &addr_data, ds1672_probe); | ||
133 | } | ||
134 | |||
135 | static int ds1672_detach(struct i2c_client *client) | ||
136 | { | ||
137 | int err; | ||
138 | struct rtc_device *rtc = i2c_get_clientdata(client); | ||
139 | |||
140 | dev_dbg(&client->dev, "%s\n", __FUNCTION__); | ||
141 | |||
142 | if (rtc) | ||
143 | rtc_device_unregister(rtc); | ||
144 | |||
145 | if ((err = i2c_detach_client(client))) | ||
146 | return err; | ||
147 | |||
148 | kfree(client); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static struct i2c_driver ds1672_driver = { | ||
154 | .driver = { | ||
155 | .name = "ds1672", | ||
156 | }, | ||
157 | .id = I2C_DRIVERID_DS1672, | ||
158 | .attach_adapter = &ds1672_attach, | ||
159 | .detach_client = &ds1672_detach, | ||
160 | }; | ||
161 | |||
162 | static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind) | ||
163 | { | ||
164 | int err = 0; | ||
165 | struct i2c_client *client; | ||
166 | struct rtc_device *rtc; | ||
167 | |||
168 | dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); | ||
169 | |||
170 | if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { | ||
171 | err = -ENODEV; | ||
172 | goto exit; | ||
173 | } | ||
174 | |||
175 | if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) { | ||
176 | err = -ENOMEM; | ||
177 | goto exit; | ||
178 | } | ||
179 | |||
180 | /* I2C client */ | ||
181 | client->addr = address; | ||
182 | client->driver = &ds1672_driver; | ||
183 | client->adapter = adapter; | ||
184 | |||
185 | strlcpy(client->name, ds1672_driver.driver.name, I2C_NAME_SIZE); | ||
186 | |||
187 | /* Inform the i2c layer */ | ||
188 | if ((err = i2c_attach_client(client))) | ||
189 | goto exit_kfree; | ||
190 | |||
191 | dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); | ||
192 | |||
193 | rtc = rtc_device_register(ds1672_driver.driver.name, &client->dev, | ||
194 | &ds1672_rtc_ops, THIS_MODULE); | ||
195 | |||
196 | if (IS_ERR(rtc)) { | ||
197 | err = PTR_ERR(rtc); | ||
198 | dev_err(&client->dev, | ||
199 | "unable to register the class device\n"); | ||
200 | goto exit_detach; | ||
201 | } | ||
202 | |||
203 | i2c_set_clientdata(client, rtc); | ||
204 | |||
205 | return 0; | ||
206 | |||
207 | exit_detach: | ||
208 | i2c_detach_client(client); | ||
209 | |||
210 | exit_kfree: | ||
211 | kfree(client); | ||
212 | |||
213 | exit: | ||
214 | return err; | ||
215 | } | ||
216 | |||
217 | static int __init ds1672_init(void) | ||
218 | { | ||
219 | return i2c_add_driver(&ds1672_driver); | ||
220 | } | ||
221 | |||
222 | static void __exit ds1672_exit(void) | ||
223 | { | ||
224 | i2c_del_driver(&ds1672_driver); | ||
225 | } | ||
226 | |||
227 | MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); | ||
228 | MODULE_DESCRIPTION("Dallas/Maxim DS1672 timekeeper driver"); | ||
229 | MODULE_LICENSE("GPL"); | ||
230 | MODULE_VERSION(DRV_VERSION); | ||
231 | |||
232 | module_init(ds1672_init); | ||
233 | module_exit(ds1672_exit); | ||
diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c new file mode 100644 index 000000000000..0dd80ea686a9 --- /dev/null +++ b/drivers/rtc/rtc-ep93xx.c | |||
@@ -0,0 +1,162 @@ | |||
1 | /* | ||
2 | * A driver for the RTC embedded in the Cirrus Logic EP93XX processors | ||
3 | * Copyright (c) 2006 Tower Technologies | ||
4 | * | ||
5 | * Author: Alessandro Zummo <a.zummo@towertech.it> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/rtc.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <asm/hardware.h> | ||
16 | |||
17 | #define EP93XX_RTC_REG(x) (EP93XX_RTC_BASE + (x)) | ||
18 | #define EP93XX_RTC_DATA EP93XX_RTC_REG(0x0000) | ||
19 | #define EP93XX_RTC_LOAD EP93XX_RTC_REG(0x000C) | ||
20 | #define EP93XX_RTC_SWCOMP EP93XX_RTC_REG(0x0108) | ||
21 | |||
22 | #define DRV_VERSION "0.2" | ||
23 | |||
24 | static int ep93xx_get_swcomp(struct device *dev, unsigned short *preload, | ||
25 | unsigned short *delete) | ||
26 | { | ||
27 | unsigned short comp = __raw_readl(EP93XX_RTC_SWCOMP); | ||
28 | |||
29 | if (preload) | ||
30 | *preload = comp & 0xffff; | ||
31 | |||
32 | if (delete) | ||
33 | *delete = (comp >> 16) & 0x1f; | ||
34 | |||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
39 | { | ||
40 | unsigned long time = __raw_readl(EP93XX_RTC_DATA); | ||
41 | |||
42 | rtc_time_to_tm(time, tm); | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs) | ||
47 | { | ||
48 | __raw_writel(secs + 1, EP93XX_RTC_LOAD); | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static int ep93xx_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
53 | { | ||
54 | int err; | ||
55 | unsigned long secs; | ||
56 | |||
57 | err = rtc_tm_to_time(tm, &secs); | ||
58 | if (err != 0) | ||
59 | return err; | ||
60 | |||
61 | return ep93xx_rtc_set_mmss(dev, secs); | ||
62 | } | ||
63 | |||
64 | static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq) | ||
65 | { | ||
66 | unsigned short preload, delete; | ||
67 | |||
68 | ep93xx_get_swcomp(dev, &preload, &delete); | ||
69 | |||
70 | seq_printf(seq, "24hr\t\t: yes\n"); | ||
71 | seq_printf(seq, "preload\t\t: %d\n", preload); | ||
72 | seq_printf(seq, "delete\t\t: %d\n", delete); | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static struct rtc_class_ops ep93xx_rtc_ops = { | ||
78 | .read_time = ep93xx_rtc_read_time, | ||
79 | .set_time = ep93xx_rtc_set_time, | ||
80 | .set_mmss = ep93xx_rtc_set_mmss, | ||
81 | .proc = ep93xx_rtc_proc, | ||
82 | }; | ||
83 | |||
84 | static ssize_t ep93xx_sysfs_show_comp_preload(struct device *dev, | ||
85 | struct device_attribute *attr, char *buf) | ||
86 | { | ||
87 | unsigned short preload; | ||
88 | |||
89 | ep93xx_get_swcomp(dev, &preload, NULL); | ||
90 | |||
91 | return sprintf(buf, "%d\n", preload); | ||
92 | } | ||
93 | static DEVICE_ATTR(comp_preload, S_IRUGO, ep93xx_sysfs_show_comp_preload, NULL); | ||
94 | |||
95 | static ssize_t ep93xx_sysfs_show_comp_delete(struct device *dev, | ||
96 | struct device_attribute *attr, char *buf) | ||
97 | { | ||
98 | unsigned short delete; | ||
99 | |||
100 | ep93xx_get_swcomp(dev, NULL, &delete); | ||
101 | |||
102 | return sprintf(buf, "%d\n", delete); | ||
103 | } | ||
104 | static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_sysfs_show_comp_delete, NULL); | ||
105 | |||
106 | |||
107 | static int __devinit ep93xx_rtc_probe(struct platform_device *dev) | ||
108 | { | ||
109 | struct rtc_device *rtc = rtc_device_register("ep93xx", | ||
110 | &dev->dev, &ep93xx_rtc_ops, THIS_MODULE); | ||
111 | |||
112 | if (IS_ERR(rtc)) { | ||
113 | dev_err(&dev->dev, "unable to register\n"); | ||
114 | return PTR_ERR(rtc); | ||
115 | } | ||
116 | |||
117 | platform_set_drvdata(dev, rtc); | ||
118 | |||
119 | device_create_file(&dev->dev, &dev_attr_comp_preload); | ||
120 | device_create_file(&dev->dev, &dev_attr_comp_delete); | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static int __devexit ep93xx_rtc_remove(struct platform_device *dev) | ||
126 | { | ||
127 | struct rtc_device *rtc = platform_get_drvdata(dev); | ||
128 | |||
129 | if (rtc) | ||
130 | rtc_device_unregister(rtc); | ||
131 | |||
132 | platform_set_drvdata(dev, NULL); | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static struct platform_driver ep93xx_rtc_platform_driver = { | ||
138 | .driver = { | ||
139 | .name = "ep93xx-rtc", | ||
140 | .owner = THIS_MODULE, | ||
141 | }, | ||
142 | .probe = ep93xx_rtc_probe, | ||
143 | .remove = __devexit_p(ep93xx_rtc_remove), | ||
144 | }; | ||
145 | |||
146 | static int __init ep93xx_rtc_init(void) | ||
147 | { | ||
148 | return platform_driver_register(&ep93xx_rtc_platform_driver); | ||
149 | } | ||
150 | |||
151 | static void __exit ep93xx_rtc_exit(void) | ||
152 | { | ||
153 | platform_driver_unregister(&ep93xx_rtc_platform_driver); | ||
154 | } | ||
155 | |||
156 | MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); | ||
157 | MODULE_DESCRIPTION("EP93XX RTC driver"); | ||
158 | MODULE_LICENSE("GPL"); | ||
159 | MODULE_VERSION(DRV_VERSION); | ||
160 | |||
161 | module_init(ep93xx_rtc_init); | ||
162 | module_exit(ep93xx_rtc_exit); | ||
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c new file mode 100644 index 000000000000..cfedc1d28ee1 --- /dev/null +++ b/drivers/rtc/rtc-lib.c | |||
@@ -0,0 +1,101 @@ | |||
1 | /* | ||
2 | * rtc and date/time utility functions | ||
3 | * | ||
4 | * Copyright (C) 2005-06 Tower Technologies | ||
5 | * Author: Alessandro Zummo <a.zummo@towertech.it> | ||
6 | * | ||
7 | * based on arch/arm/common/rtctime.c and other bits | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/rtc.h> | ||
16 | |||
17 | static const unsigned char rtc_days_in_month[] = { | ||
18 | 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 | ||
19 | }; | ||
20 | |||
21 | #define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) | ||
22 | #define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400)) | ||
23 | |||
24 | int rtc_month_days(unsigned int month, unsigned int year) | ||
25 | { | ||
26 | return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1); | ||
27 | } | ||
28 | EXPORT_SYMBOL(rtc_month_days); | ||
29 | |||
30 | /* | ||
31 | * Convert seconds since 01-01-1970 00:00:00 to Gregorian date. | ||
32 | */ | ||
33 | void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) | ||
34 | { | ||
35 | register int days, month, year; | ||
36 | |||
37 | days = time / 86400; | ||
38 | time -= days * 86400; | ||
39 | |||
40 | /* day of the week, 1970-01-01 was a Thursday */ | ||
41 | tm->tm_wday = (days + 4) % 7; | ||
42 | |||
43 | year = 1970 + days / 365; | ||
44 | days -= (year - 1970) * 365 | ||
45 | + LEAPS_THRU_END_OF(year - 1) | ||
46 | - LEAPS_THRU_END_OF(1970 - 1); | ||
47 | if (days < 0) { | ||
48 | year -= 1; | ||
49 | days += 365 + LEAP_YEAR(year); | ||
50 | } | ||
51 | tm->tm_year = year - 1900; | ||
52 | tm->tm_yday = days + 1; | ||
53 | |||
54 | for (month = 0; month < 11; month++) { | ||
55 | int newdays; | ||
56 | |||
57 | newdays = days - rtc_month_days(month, year); | ||
58 | if (newdays < 0) | ||
59 | break; | ||
60 | days = newdays; | ||
61 | } | ||
62 | tm->tm_mon = month; | ||
63 | tm->tm_mday = days + 1; | ||
64 | |||
65 | tm->tm_hour = time / 3600; | ||
66 | time -= tm->tm_hour * 3600; | ||
67 | tm->tm_min = time / 60; | ||
68 | tm->tm_sec = time - tm->tm_min * 60; | ||
69 | } | ||
70 | EXPORT_SYMBOL(rtc_time_to_tm); | ||
71 | |||
72 | /* | ||
73 | * Does the rtc_time represent a valid date/time? | ||
74 | */ | ||
75 | int rtc_valid_tm(struct rtc_time *tm) | ||
76 | { | ||
77 | if (tm->tm_year < 70 | ||
78 | || tm->tm_mon >= 12 | ||
79 | || tm->tm_mday < 1 | ||
80 | || tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + 1900) | ||
81 | || tm->tm_hour >= 24 | ||
82 | || tm->tm_min >= 60 | ||
83 | || tm->tm_sec >= 60) | ||
84 | return -EINVAL; | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | EXPORT_SYMBOL(rtc_valid_tm); | ||
89 | |||
90 | /* | ||
91 | * Convert Gregorian date to seconds since 01-01-1970 00:00:00. | ||
92 | */ | ||
93 | int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) | ||
94 | { | ||
95 | *time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, | ||
96 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
97 | return 0; | ||
98 | } | ||
99 | EXPORT_SYMBOL(rtc_tm_to_time); | ||
100 | |||
101 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c new file mode 100644 index 000000000000..db445c872b1b --- /dev/null +++ b/drivers/rtc/rtc-m48t86.c | |||
@@ -0,0 +1,209 @@ | |||
1 | /* | ||
2 | * ST M48T86 / Dallas DS12887 RTC driver | ||
3 | * Copyright (c) 2006 Tower Technologies | ||
4 | * | ||
5 | * Author: Alessandro Zummo <a.zummo@towertech.it> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This drivers only supports the clock running in BCD and 24H mode. | ||
12 | * If it will be ever adapted to binary and 12H mode, care must be taken | ||
13 | * to not introduce bugs. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/rtc.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/m48t86.h> | ||
20 | #include <linux/bcd.h> | ||
21 | |||
22 | #define M48T86_REG_SEC 0x00 | ||
23 | #define M48T86_REG_SECALRM 0x01 | ||
24 | #define M48T86_REG_MIN 0x02 | ||
25 | #define M48T86_REG_MINALRM 0x03 | ||
26 | #define M48T86_REG_HOUR 0x04 | ||
27 | #define M48T86_REG_HOURALRM 0x05 | ||
28 | #define M48T86_REG_DOW 0x06 /* 1 = sunday */ | ||
29 | #define M48T86_REG_DOM 0x07 | ||
30 | #define M48T86_REG_MONTH 0x08 /* 1 - 12 */ | ||
31 | #define M48T86_REG_YEAR 0x09 /* 0 - 99 */ | ||
32 | #define M48T86_REG_A 0x0A | ||
33 | #define M48T86_REG_B 0x0B | ||
34 | #define M48T86_REG_C 0x0C | ||
35 | #define M48T86_REG_D 0x0D | ||
36 | |||
37 | #define M48T86_REG_B_H24 (1 << 1) | ||
38 | #define M48T86_REG_B_DM (1 << 2) | ||
39 | #define M48T86_REG_B_SET (1 << 7) | ||
40 | #define M48T86_REG_D_VRT (1 << 7) | ||
41 | |||
42 | #define DRV_VERSION "0.1" | ||
43 | |||
44 | |||
45 | static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
46 | { | ||
47 | unsigned char reg; | ||
48 | struct platform_device *pdev = to_platform_device(dev); | ||
49 | struct m48t86_ops *ops = pdev->dev.platform_data; | ||
50 | |||
51 | reg = ops->readb(M48T86_REG_B); | ||
52 | |||
53 | if (reg & M48T86_REG_B_DM) { | ||
54 | /* data (binary) mode */ | ||
55 | tm->tm_sec = ops->readb(M48T86_REG_SEC); | ||
56 | tm->tm_min = ops->readb(M48T86_REG_MIN); | ||
57 | tm->tm_hour = ops->readb(M48T86_REG_HOUR) & 0x3F; | ||
58 | tm->tm_mday = ops->readb(M48T86_REG_DOM); | ||
59 | /* tm_mon is 0-11 */ | ||
60 | tm->tm_mon = ops->readb(M48T86_REG_MONTH) - 1; | ||
61 | tm->tm_year = ops->readb(M48T86_REG_YEAR) + 100; | ||
62 | tm->tm_wday = ops->readb(M48T86_REG_DOW); | ||
63 | } else { | ||
64 | /* bcd mode */ | ||
65 | tm->tm_sec = BCD2BIN(ops->readb(M48T86_REG_SEC)); | ||
66 | tm->tm_min = BCD2BIN(ops->readb(M48T86_REG_MIN)); | ||
67 | tm->tm_hour = BCD2BIN(ops->readb(M48T86_REG_HOUR) & 0x3F); | ||
68 | tm->tm_mday = BCD2BIN(ops->readb(M48T86_REG_DOM)); | ||
69 | /* tm_mon is 0-11 */ | ||
70 | tm->tm_mon = BCD2BIN(ops->readb(M48T86_REG_MONTH)) - 1; | ||
71 | tm->tm_year = BCD2BIN(ops->readb(M48T86_REG_YEAR)) + 100; | ||
72 | tm->tm_wday = BCD2BIN(ops->readb(M48T86_REG_DOW)); | ||
73 | } | ||
74 | |||
75 | /* correct the hour if the clock is in 12h mode */ | ||
76 | if (!(reg & M48T86_REG_B_H24)) | ||
77 | if (ops->readb(M48T86_REG_HOUR) & 0x80) | ||
78 | tm->tm_hour += 12; | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
84 | { | ||
85 | unsigned char reg; | ||
86 | struct platform_device *pdev = to_platform_device(dev); | ||
87 | struct m48t86_ops *ops = pdev->dev.platform_data; | ||
88 | |||
89 | reg = ops->readb(M48T86_REG_B); | ||
90 | |||
91 | /* update flag and 24h mode */ | ||
92 | reg |= M48T86_REG_B_SET | M48T86_REG_B_H24; | ||
93 | ops->writeb(reg, M48T86_REG_B); | ||
94 | |||
95 | if (reg & M48T86_REG_B_DM) { | ||
96 | /* data (binary) mode */ | ||
97 | ops->writeb(tm->tm_sec, M48T86_REG_SEC); | ||
98 | ops->writeb(tm->tm_min, M48T86_REG_MIN); | ||
99 | ops->writeb(tm->tm_hour, M48T86_REG_HOUR); | ||
100 | ops->writeb(tm->tm_mday, M48T86_REG_DOM); | ||
101 | ops->writeb(tm->tm_mon + 1, M48T86_REG_MONTH); | ||
102 | ops->writeb(tm->tm_year % 100, M48T86_REG_YEAR); | ||
103 | ops->writeb(tm->tm_wday, M48T86_REG_DOW); | ||
104 | } else { | ||
105 | /* bcd mode */ | ||
106 | ops->writeb(BIN2BCD(tm->tm_sec), M48T86_REG_SEC); | ||
107 | ops->writeb(BIN2BCD(tm->tm_min), M48T86_REG_MIN); | ||
108 | ops->writeb(BIN2BCD(tm->tm_hour), M48T86_REG_HOUR); | ||
109 | ops->writeb(BIN2BCD(tm->tm_mday), M48T86_REG_DOM); | ||
110 | ops->writeb(BIN2BCD(tm->tm_mon + 1), M48T86_REG_MONTH); | ||
111 | ops->writeb(BIN2BCD(tm->tm_year % 100), M48T86_REG_YEAR); | ||
112 | ops->writeb(BIN2BCD(tm->tm_wday), M48T86_REG_DOW); | ||
113 | } | ||
114 | |||
115 | /* update ended */ | ||
116 | reg &= ~M48T86_REG_B_SET; | ||
117 | ops->writeb(reg, M48T86_REG_B); | ||
118 | |||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq) | ||
123 | { | ||
124 | unsigned char reg; | ||
125 | struct platform_device *pdev = to_platform_device(dev); | ||
126 | struct m48t86_ops *ops = pdev->dev.platform_data; | ||
127 | |||
128 | reg = ops->readb(M48T86_REG_B); | ||
129 | |||
130 | seq_printf(seq, "24hr\t\t: %s\n", | ||
131 | (reg & M48T86_REG_B_H24) ? "yes" : "no"); | ||
132 | |||
133 | seq_printf(seq, "mode\t\t: %s\n", | ||
134 | (reg & M48T86_REG_B_DM) ? "binary" : "bcd"); | ||
135 | |||
136 | reg = ops->readb(M48T86_REG_D); | ||
137 | |||
138 | seq_printf(seq, "battery\t\t: %s\n", | ||
139 | (reg & M48T86_REG_D_VRT) ? "ok" : "exhausted"); | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static struct rtc_class_ops m48t86_rtc_ops = { | ||
145 | .read_time = m48t86_rtc_read_time, | ||
146 | .set_time = m48t86_rtc_set_time, | ||
147 | .proc = m48t86_rtc_proc, | ||
148 | }; | ||
149 | |||
150 | static int __devinit m48t86_rtc_probe(struct platform_device *dev) | ||
151 | { | ||
152 | unsigned char reg; | ||
153 | struct m48t86_ops *ops = dev->dev.platform_data; | ||
154 | struct rtc_device *rtc = rtc_device_register("m48t86", | ||
155 | &dev->dev, &m48t86_rtc_ops, THIS_MODULE); | ||
156 | |||
157 | if (IS_ERR(rtc)) { | ||
158 | dev_err(&dev->dev, "unable to register\n"); | ||
159 | return PTR_ERR(rtc); | ||
160 | } | ||
161 | |||
162 | platform_set_drvdata(dev, rtc); | ||
163 | |||
164 | /* read battery status */ | ||
165 | reg = ops->readb(M48T86_REG_D); | ||
166 | dev_info(&dev->dev, "battery %s\n", | ||
167 | (reg & M48T86_REG_D_VRT) ? "ok" : "exhausted"); | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int __devexit m48t86_rtc_remove(struct platform_device *dev) | ||
173 | { | ||
174 | struct rtc_device *rtc = platform_get_drvdata(dev); | ||
175 | |||
176 | if (rtc) | ||
177 | rtc_device_unregister(rtc); | ||
178 | |||
179 | platform_set_drvdata(dev, NULL); | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static struct platform_driver m48t86_rtc_platform_driver = { | ||
185 | .driver = { | ||
186 | .name = "rtc-m48t86", | ||
187 | .owner = THIS_MODULE, | ||
188 | }, | ||
189 | .probe = m48t86_rtc_probe, | ||
190 | .remove = __devexit_p(m48t86_rtc_remove), | ||
191 | }; | ||
192 | |||
193 | static int __init m48t86_rtc_init(void) | ||
194 | { | ||
195 | return platform_driver_register(&m48t86_rtc_platform_driver); | ||
196 | } | ||
197 | |||
198 | static void __exit m48t86_rtc_exit(void) | ||
199 | { | ||
200 | platform_driver_unregister(&m48t86_rtc_platform_driver); | ||
201 | } | ||
202 | |||
203 | MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); | ||
204 | MODULE_DESCRIPTION("M48T86 RTC driver"); | ||
205 | MODULE_LICENSE("GPL"); | ||
206 | MODULE_VERSION(DRV_VERSION); | ||
207 | |||
208 | module_init(m48t86_rtc_init); | ||
209 | module_exit(m48t86_rtc_exit); | ||
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c new file mode 100644 index 000000000000..d857d45bdbe8 --- /dev/null +++ b/drivers/rtc/rtc-pcf8563.c | |||
@@ -0,0 +1,353 @@ | |||
1 | /* | ||
2 | * An I2C driver for the Philips PCF8563 RTC | ||
3 | * Copyright 2005-06 Tower Technologies | ||
4 | * | ||
5 | * Author: Alessandro Zummo <a.zummo@towertech.it> | ||
6 | * Maintainers: http://www.nslu2-linux.org/ | ||
7 | * | ||
8 | * based on the other drivers in this same directory. | ||
9 | * | ||
10 | * http://www.semiconductors.philips.com/acrobat/datasheets/PCF8563-04.pdf | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/bcd.h> | ||
19 | #include <linux/rtc.h> | ||
20 | |||
21 | #define DRV_VERSION "0.4.2" | ||
22 | |||
23 | /* Addresses to scan: none | ||
24 | * This chip cannot be reliably autodetected. An empty eeprom | ||
25 | * located at 0x51 will pass the validation routine due to | ||
26 | * the way the registers are implemented. | ||
27 | */ | ||
28 | static unsigned short normal_i2c[] = { I2C_CLIENT_END }; | ||
29 | |||
30 | /* Module parameters */ | ||
31 | I2C_CLIENT_INSMOD; | ||
32 | |||
33 | #define PCF8563_REG_ST1 0x00 /* status */ | ||
34 | #define PCF8563_REG_ST2 0x01 | ||
35 | |||
36 | #define PCF8563_REG_SC 0x02 /* datetime */ | ||
37 | #define PCF8563_REG_MN 0x03 | ||
38 | #define PCF8563_REG_HR 0x04 | ||
39 | #define PCF8563_REG_DM 0x05 | ||
40 | #define PCF8563_REG_DW 0x06 | ||
41 | #define PCF8563_REG_MO 0x07 | ||
42 | #define PCF8563_REG_YR 0x08 | ||
43 | |||
44 | #define PCF8563_REG_AMN 0x09 /* alarm */ | ||
45 | #define PCF8563_REG_AHR 0x0A | ||
46 | #define PCF8563_REG_ADM 0x0B | ||
47 | #define PCF8563_REG_ADW 0x0C | ||
48 | |||
49 | #define PCF8563_REG_CLKO 0x0D /* clock out */ | ||
50 | #define PCF8563_REG_TMRC 0x0E /* timer control */ | ||
51 | #define PCF8563_REG_TMR 0x0F /* timer */ | ||
52 | |||
53 | #define PCF8563_SC_LV 0x80 /* low voltage */ | ||
54 | #define PCF8563_MO_C 0x80 /* century */ | ||
55 | |||
56 | static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind); | ||
57 | static int pcf8563_detach(struct i2c_client *client); | ||
58 | |||
59 | /* | ||
60 | * In the routines that deal directly with the pcf8563 hardware, we use | ||
61 | * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. | ||
62 | */ | ||
63 | static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) | ||
64 | { | ||
65 | unsigned char buf[13] = { PCF8563_REG_ST1 }; | ||
66 | |||
67 | struct i2c_msg msgs[] = { | ||
68 | { client->addr, 0, 1, buf }, /* setup read ptr */ | ||
69 | { client->addr, I2C_M_RD, 13, buf }, /* read status + date */ | ||
70 | }; | ||
71 | |||
72 | /* read registers */ | ||
73 | if ((i2c_transfer(client->adapter, msgs, 2)) != 2) { | ||
74 | dev_err(&client->dev, "%s: read error\n", __FUNCTION__); | ||
75 | return -EIO; | ||
76 | } | ||
77 | |||
78 | if (buf[PCF8563_REG_SC] & PCF8563_SC_LV) | ||
79 | dev_info(&client->dev, | ||
80 | "low voltage detected, date/time is not reliable.\n"); | ||
81 | |||
82 | dev_dbg(&client->dev, | ||
83 | "%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, " | ||
84 | "mday=%02x, wday=%02x, mon=%02x, year=%02x\n", | ||
85 | __FUNCTION__, | ||
86 | buf[0], buf[1], buf[2], buf[3], | ||
87 | buf[4], buf[5], buf[6], buf[7], | ||
88 | buf[8]); | ||
89 | |||
90 | |||
91 | tm->tm_sec = BCD2BIN(buf[PCF8563_REG_SC] & 0x7F); | ||
92 | tm->tm_min = BCD2BIN(buf[PCF8563_REG_MN] & 0x7F); | ||
93 | tm->tm_hour = BCD2BIN(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */ | ||
94 | tm->tm_mday = BCD2BIN(buf[PCF8563_REG_DM] & 0x3F); | ||
95 | tm->tm_wday = buf[PCF8563_REG_DW] & 0x07; | ||
96 | tm->tm_mon = BCD2BIN(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */ | ||
97 | tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR]) | ||
98 | + (buf[PCF8563_REG_MO] & PCF8563_MO_C ? 100 : 0); | ||
99 | |||
100 | dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " | ||
101 | "mday=%d, mon=%d, year=%d, wday=%d\n", | ||
102 | __FUNCTION__, | ||
103 | tm->tm_sec, tm->tm_min, tm->tm_hour, | ||
104 | tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); | ||
105 | |||
106 | /* the clock can give out invalid datetime, but we cannot return | ||
107 | * -EINVAL otherwise hwclock will refuse to set the time on bootup. | ||
108 | */ | ||
109 | if (rtc_valid_tm(tm) < 0) | ||
110 | dev_err(&client->dev, "retrieved date/time is not valid.\n"); | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) | ||
116 | { | ||
117 | int i, err; | ||
118 | unsigned char buf[9]; | ||
119 | |||
120 | dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " | ||
121 | "mday=%d, mon=%d, year=%d, wday=%d\n", | ||
122 | __FUNCTION__, | ||
123 | tm->tm_sec, tm->tm_min, tm->tm_hour, | ||
124 | tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); | ||
125 | |||
126 | /* hours, minutes and seconds */ | ||
127 | buf[PCF8563_REG_SC] = BIN2BCD(tm->tm_sec); | ||
128 | buf[PCF8563_REG_MN] = BIN2BCD(tm->tm_min); | ||
129 | buf[PCF8563_REG_HR] = BIN2BCD(tm->tm_hour); | ||
130 | |||
131 | buf[PCF8563_REG_DM] = BIN2BCD(tm->tm_mday); | ||
132 | |||
133 | /* month, 1 - 12 */ | ||
134 | buf[PCF8563_REG_MO] = BIN2BCD(tm->tm_mon + 1); | ||
135 | |||
136 | /* year and century */ | ||
137 | buf[PCF8563_REG_YR] = BIN2BCD(tm->tm_year % 100); | ||
138 | if (tm->tm_year / 100) | ||
139 | buf[PCF8563_REG_MO] |= PCF8563_MO_C; | ||
140 | |||
141 | buf[PCF8563_REG_DW] = tm->tm_wday & 0x07; | ||
142 | |||
143 | /* write register's data */ | ||
144 | for (i = 0; i < 7; i++) { | ||
145 | unsigned char data[2] = { PCF8563_REG_SC + i, | ||
146 | buf[PCF8563_REG_SC + i] }; | ||
147 | |||
148 | err = i2c_master_send(client, data, sizeof(data)); | ||
149 | if (err != sizeof(data)) { | ||
150 | dev_err(&client->dev, | ||
151 | "%s: err=%d addr=%02x, data=%02x\n", | ||
152 | __FUNCTION__, err, data[0], data[1]); | ||
153 | return -EIO; | ||
154 | } | ||
155 | }; | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | struct pcf8563_limit | ||
161 | { | ||
162 | unsigned char reg; | ||
163 | unsigned char mask; | ||
164 | unsigned char min; | ||
165 | unsigned char max; | ||
166 | }; | ||
167 | |||
168 | static int pcf8563_validate_client(struct i2c_client *client) | ||
169 | { | ||
170 | int i; | ||
171 | |||
172 | static const struct pcf8563_limit pattern[] = { | ||
173 | /* register, mask, min, max */ | ||
174 | { PCF8563_REG_SC, 0x7F, 0, 59 }, | ||
175 | { PCF8563_REG_MN, 0x7F, 0, 59 }, | ||
176 | { PCF8563_REG_HR, 0x3F, 0, 23 }, | ||
177 | { PCF8563_REG_DM, 0x3F, 0, 31 }, | ||
178 | { PCF8563_REG_MO, 0x1F, 0, 12 }, | ||
179 | }; | ||
180 | |||
181 | /* check limits (only registers with bcd values) */ | ||
182 | for (i = 0; i < ARRAY_SIZE(pattern); i++) { | ||
183 | int xfer; | ||
184 | unsigned char value; | ||
185 | unsigned char buf = pattern[i].reg; | ||
186 | |||
187 | struct i2c_msg msgs[] = { | ||
188 | { client->addr, 0, 1, &buf }, | ||
189 | { client->addr, I2C_M_RD, 1, &buf }, | ||
190 | }; | ||
191 | |||
192 | xfer = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | ||
193 | |||
194 | if (xfer != ARRAY_SIZE(msgs)) { | ||
195 | dev_err(&client->adapter->dev, | ||
196 | "%s: could not read register 0x%02X\n", | ||
197 | __FUNCTION__, pattern[i].reg); | ||
198 | |||
199 | return -EIO; | ||
200 | } | ||
201 | |||
202 | value = BCD2BIN(buf & pattern[i].mask); | ||
203 | |||
204 | if (value > pattern[i].max || | ||
205 | value < pattern[i].min) { | ||
206 | dev_dbg(&client->adapter->dev, | ||
207 | "%s: pattern=%d, reg=%x, mask=0x%02x, min=%d, " | ||
208 | "max=%d, value=%d, raw=0x%02X\n", | ||
209 | __FUNCTION__, i, pattern[i].reg, pattern[i].mask, | ||
210 | pattern[i].min, pattern[i].max, | ||
211 | value, buf); | ||
212 | |||
213 | return -ENODEV; | ||
214 | } | ||
215 | } | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
221 | { | ||
222 | return pcf8563_get_datetime(to_i2c_client(dev), tm); | ||
223 | } | ||
224 | |||
225 | static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
226 | { | ||
227 | return pcf8563_set_datetime(to_i2c_client(dev), tm); | ||
228 | } | ||
229 | |||
230 | static int pcf8563_rtc_proc(struct device *dev, struct seq_file *seq) | ||
231 | { | ||
232 | seq_printf(seq, "24hr\t\t: yes\n"); | ||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static struct rtc_class_ops pcf8563_rtc_ops = { | ||
237 | .proc = pcf8563_rtc_proc, | ||
238 | .read_time = pcf8563_rtc_read_time, | ||
239 | .set_time = pcf8563_rtc_set_time, | ||
240 | }; | ||
241 | |||
242 | static int pcf8563_attach(struct i2c_adapter *adapter) | ||
243 | { | ||
244 | return i2c_probe(adapter, &addr_data, pcf8563_probe); | ||
245 | } | ||
246 | |||
247 | static struct i2c_driver pcf8563_driver = { | ||
248 | .driver = { | ||
249 | .name = "pcf8563", | ||
250 | }, | ||
251 | .id = I2C_DRIVERID_PCF8563, | ||
252 | .attach_adapter = &pcf8563_attach, | ||
253 | .detach_client = &pcf8563_detach, | ||
254 | }; | ||
255 | |||
256 | static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind) | ||
257 | { | ||
258 | struct i2c_client *client; | ||
259 | struct rtc_device *rtc; | ||
260 | |||
261 | int err = 0; | ||
262 | |||
263 | dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); | ||
264 | |||
265 | if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { | ||
266 | err = -ENODEV; | ||
267 | goto exit; | ||
268 | } | ||
269 | |||
270 | if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) { | ||
271 | err = -ENOMEM; | ||
272 | goto exit; | ||
273 | } | ||
274 | |||
275 | client->addr = address; | ||
276 | client->driver = &pcf8563_driver; | ||
277 | client->adapter = adapter; | ||
278 | |||
279 | strlcpy(client->name, pcf8563_driver.driver.name, I2C_NAME_SIZE); | ||
280 | |||
281 | /* Verify the chip is really an PCF8563 */ | ||
282 | if (kind < 0) { | ||
283 | if (pcf8563_validate_client(client) < 0) { | ||
284 | err = -ENODEV; | ||
285 | goto exit_kfree; | ||
286 | } | ||
287 | } | ||
288 | |||
289 | /* Inform the i2c layer */ | ||
290 | if ((err = i2c_attach_client(client))) | ||
291 | goto exit_kfree; | ||
292 | |||
293 | dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); | ||
294 | |||
295 | rtc = rtc_device_register(pcf8563_driver.driver.name, &client->dev, | ||
296 | &pcf8563_rtc_ops, THIS_MODULE); | ||
297 | |||
298 | if (IS_ERR(rtc)) { | ||
299 | err = PTR_ERR(rtc); | ||
300 | dev_err(&client->dev, | ||
301 | "unable to register the class device\n"); | ||
302 | goto exit_detach; | ||
303 | } | ||
304 | |||
305 | i2c_set_clientdata(client, rtc); | ||
306 | |||
307 | return 0; | ||
308 | |||
309 | exit_detach: | ||
310 | i2c_detach_client(client); | ||
311 | |||
312 | exit_kfree: | ||
313 | kfree(client); | ||
314 | |||
315 | exit: | ||
316 | return err; | ||
317 | } | ||
318 | |||
319 | static int pcf8563_detach(struct i2c_client *client) | ||
320 | { | ||
321 | int err; | ||
322 | struct rtc_device *rtc = i2c_get_clientdata(client); | ||
323 | |||
324 | dev_dbg(&client->dev, "%s\n", __FUNCTION__); | ||
325 | |||
326 | if (rtc) | ||
327 | rtc_device_unregister(rtc); | ||
328 | |||
329 | if ((err = i2c_detach_client(client))) | ||
330 | return err; | ||
331 | |||
332 | kfree(client); | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static int __init pcf8563_init(void) | ||
338 | { | ||
339 | return i2c_add_driver(&pcf8563_driver); | ||
340 | } | ||
341 | |||
342 | static void __exit pcf8563_exit(void) | ||
343 | { | ||
344 | i2c_del_driver(&pcf8563_driver); | ||
345 | } | ||
346 | |||
347 | MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); | ||
348 | MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver"); | ||
349 | MODULE_LICENSE("GPL"); | ||
350 | MODULE_VERSION(DRV_VERSION); | ||
351 | |||
352 | module_init(pcf8563_init); | ||
353 | module_exit(pcf8563_exit); | ||
diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c new file mode 100644 index 000000000000..90b8a97a0919 --- /dev/null +++ b/drivers/rtc/rtc-proc.c | |||
@@ -0,0 +1,162 @@ | |||
1 | /* | ||
2 | * RTC subsystem, proc interface | ||
3 | * | ||
4 | * Copyright (C) 2005-06 Tower Technologies | ||
5 | * Author: Alessandro Zummo <a.zummo@towertech.it> | ||
6 | * | ||
7 | * based on arch/arm/common/rtctime.c | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/rtc.h> | ||
16 | #include <linux/proc_fs.h> | ||
17 | #include <linux/seq_file.h> | ||
18 | |||
19 | static struct class_device *rtc_dev = NULL; | ||
20 | static DEFINE_MUTEX(rtc_lock); | ||
21 | |||
22 | static int rtc_proc_show(struct seq_file *seq, void *offset) | ||
23 | { | ||
24 | int err; | ||
25 | struct class_device *class_dev = seq->private; | ||
26 | struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops; | ||
27 | struct rtc_wkalrm alrm; | ||
28 | struct rtc_time tm; | ||
29 | |||
30 | err = rtc_read_time(class_dev, &tm); | ||
31 | if (err == 0) { | ||
32 | seq_printf(seq, | ||
33 | "rtc_time\t: %02d:%02d:%02d\n" | ||
34 | "rtc_date\t: %04d-%02d-%02d\n", | ||
35 | tm.tm_hour, tm.tm_min, tm.tm_sec, | ||
36 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); | ||
37 | } | ||
38 | |||
39 | err = rtc_read_alarm(class_dev, &alrm); | ||
40 | if (err == 0) { | ||
41 | seq_printf(seq, "alrm_time\t: "); | ||
42 | if ((unsigned int)alrm.time.tm_hour <= 24) | ||
43 | seq_printf(seq, "%02d:", alrm.time.tm_hour); | ||
44 | else | ||
45 | seq_printf(seq, "**:"); | ||
46 | if ((unsigned int)alrm.time.tm_min <= 59) | ||
47 | seq_printf(seq, "%02d:", alrm.time.tm_min); | ||
48 | else | ||
49 | seq_printf(seq, "**:"); | ||
50 | if ((unsigned int)alrm.time.tm_sec <= 59) | ||
51 | seq_printf(seq, "%02d\n", alrm.time.tm_sec); | ||
52 | else | ||
53 | seq_printf(seq, "**\n"); | ||
54 | |||
55 | seq_printf(seq, "alrm_date\t: "); | ||
56 | if ((unsigned int)alrm.time.tm_year <= 200) | ||
57 | seq_printf(seq, "%04d-", alrm.time.tm_year + 1900); | ||
58 | else | ||
59 | seq_printf(seq, "****-"); | ||
60 | if ((unsigned int)alrm.time.tm_mon <= 11) | ||
61 | seq_printf(seq, "%02d-", alrm.time.tm_mon + 1); | ||
62 | else | ||
63 | seq_printf(seq, "**-"); | ||
64 | if ((unsigned int)alrm.time.tm_mday <= 31) | ||
65 | seq_printf(seq, "%02d\n", alrm.time.tm_mday); | ||
66 | else | ||
67 | seq_printf(seq, "**\n"); | ||
68 | seq_printf(seq, "alrm_wakeup\t: %s\n", | ||
69 | alrm.enabled ? "yes" : "no"); | ||
70 | seq_printf(seq, "alrm_pending\t: %s\n", | ||
71 | alrm.pending ? "yes" : "no"); | ||
72 | } | ||
73 | |||
74 | if (ops->proc) | ||
75 | ops->proc(class_dev->dev, seq); | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static int rtc_proc_open(struct inode *inode, struct file *file) | ||
81 | { | ||
82 | struct class_device *class_dev = PDE(inode)->data; | ||
83 | |||
84 | if (!try_module_get(THIS_MODULE)) | ||
85 | return -ENODEV; | ||
86 | |||
87 | return single_open(file, rtc_proc_show, class_dev); | ||
88 | } | ||
89 | |||
90 | static int rtc_proc_release(struct inode *inode, struct file *file) | ||
91 | { | ||
92 | int res = single_release(inode, file); | ||
93 | module_put(THIS_MODULE); | ||
94 | return res; | ||
95 | } | ||
96 | |||
97 | static struct file_operations rtc_proc_fops = { | ||
98 | .open = rtc_proc_open, | ||
99 | .read = seq_read, | ||
100 | .llseek = seq_lseek, | ||
101 | .release = rtc_proc_release, | ||
102 | }; | ||
103 | |||
104 | static int rtc_proc_add_device(struct class_device *class_dev, | ||
105 | struct class_interface *class_intf) | ||
106 | { | ||
107 | mutex_lock(&rtc_lock); | ||
108 | if (rtc_dev == NULL) { | ||
109 | struct proc_dir_entry *ent; | ||
110 | |||
111 | rtc_dev = class_dev; | ||
112 | |||
113 | ent = create_proc_entry("driver/rtc", 0, NULL); | ||
114 | if (ent) { | ||
115 | struct rtc_device *rtc = to_rtc_device(class_dev); | ||
116 | |||
117 | ent->proc_fops = &rtc_proc_fops; | ||
118 | ent->owner = rtc->owner; | ||
119 | ent->data = class_dev; | ||
120 | |||
121 | dev_info(class_dev->dev, "rtc intf: proc\n"); | ||
122 | } | ||
123 | else | ||
124 | rtc_dev = NULL; | ||
125 | } | ||
126 | mutex_unlock(&rtc_lock); | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static void rtc_proc_remove_device(struct class_device *class_dev, | ||
132 | struct class_interface *class_intf) | ||
133 | { | ||
134 | mutex_lock(&rtc_lock); | ||
135 | if (rtc_dev == class_dev) { | ||
136 | remove_proc_entry("driver/rtc", NULL); | ||
137 | rtc_dev = NULL; | ||
138 | } | ||
139 | mutex_unlock(&rtc_lock); | ||
140 | } | ||
141 | |||
142 | static struct class_interface rtc_proc_interface = { | ||
143 | .add = &rtc_proc_add_device, | ||
144 | .remove = &rtc_proc_remove_device, | ||
145 | }; | ||
146 | |||
147 | static int __init rtc_proc_init(void) | ||
148 | { | ||
149 | return rtc_interface_register(&rtc_proc_interface); | ||
150 | } | ||
151 | |||
152 | static void __exit rtc_proc_exit(void) | ||
153 | { | ||
154 | class_interface_unregister(&rtc_proc_interface); | ||
155 | } | ||
156 | |||
157 | module_init(rtc_proc_init); | ||
158 | module_exit(rtc_proc_exit); | ||
159 | |||
160 | MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); | ||
161 | MODULE_DESCRIPTION("RTC class proc interface"); | ||
162 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c new file mode 100644 index 000000000000..396c8681f66c --- /dev/null +++ b/drivers/rtc/rtc-rs5c372.c | |||
@@ -0,0 +1,294 @@ | |||
1 | /* | ||
2 | * An I2C driver for the Ricoh RS5C372 RTC | ||
3 | * | ||
4 | * Copyright (C) 2005 Pavel Mironchik <pmironchik@optifacio.net> | ||
5 | * Copyright (C) 2006 Tower Technologies | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/i2c.h> | ||
13 | #include <linux/rtc.h> | ||
14 | #include <linux/bcd.h> | ||
15 | |||
16 | #define DRV_VERSION "0.2" | ||
17 | |||
18 | /* Addresses to scan */ | ||
19 | static unsigned short normal_i2c[] = { /* 0x32,*/ I2C_CLIENT_END }; | ||
20 | |||
21 | /* Insmod parameters */ | ||
22 | I2C_CLIENT_INSMOD; | ||
23 | |||
24 | #define RS5C372_REG_SECS 0 | ||
25 | #define RS5C372_REG_MINS 1 | ||
26 | #define RS5C372_REG_HOURS 2 | ||
27 | #define RS5C372_REG_WDAY 3 | ||
28 | #define RS5C372_REG_DAY 4 | ||
29 | #define RS5C372_REG_MONTH 5 | ||
30 | #define RS5C372_REG_YEAR 6 | ||
31 | #define RS5C372_REG_TRIM 7 | ||
32 | |||
33 | #define RS5C372_TRIM_XSL 0x80 | ||
34 | #define RS5C372_TRIM_MASK 0x7F | ||
35 | |||
36 | #define RS5C372_REG_BASE 0 | ||
37 | |||
38 | static int rs5c372_attach(struct i2c_adapter *adapter); | ||
39 | static int rs5c372_detach(struct i2c_client *client); | ||
40 | static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind); | ||
41 | |||
42 | static struct i2c_driver rs5c372_driver = { | ||
43 | .driver = { | ||
44 | .name = "rs5c372", | ||
45 | }, | ||
46 | .attach_adapter = &rs5c372_attach, | ||
47 | .detach_client = &rs5c372_detach, | ||
48 | }; | ||
49 | |||
50 | static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm) | ||
51 | { | ||
52 | unsigned char buf[7] = { RS5C372_REG_BASE }; | ||
53 | |||
54 | /* this implements the 1st reading method, according | ||
55 | * to the datasheet. buf[0] is initialized with | ||
56 | * address ptr and transmission format register. | ||
57 | */ | ||
58 | struct i2c_msg msgs[] = { | ||
59 | { client->addr, 0, 1, buf }, | ||
60 | { client->addr, I2C_M_RD, 7, buf }, | ||
61 | }; | ||
62 | |||
63 | if ((i2c_transfer(client->adapter, msgs, 2)) != 2) { | ||
64 | dev_err(&client->dev, "%s: read error\n", __FUNCTION__); | ||
65 | return -EIO; | ||
66 | } | ||
67 | |||
68 | tm->tm_sec = BCD2BIN(buf[RS5C372_REG_SECS] & 0x7f); | ||
69 | tm->tm_min = BCD2BIN(buf[RS5C372_REG_MINS] & 0x7f); | ||
70 | tm->tm_hour = BCD2BIN(buf[RS5C372_REG_HOURS] & 0x3f); | ||
71 | tm->tm_wday = BCD2BIN(buf[RS5C372_REG_WDAY] & 0x07); | ||
72 | tm->tm_mday = BCD2BIN(buf[RS5C372_REG_DAY] & 0x3f); | ||
73 | |||
74 | /* tm->tm_mon is zero-based */ | ||
75 | tm->tm_mon = BCD2BIN(buf[RS5C372_REG_MONTH] & 0x1f) - 1; | ||
76 | |||
77 | /* year is 1900 + tm->tm_year */ | ||
78 | tm->tm_year = BCD2BIN(buf[RS5C372_REG_YEAR]) + 100; | ||
79 | |||
80 | dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " | ||
81 | "mday=%d, mon=%d, year=%d, wday=%d\n", | ||
82 | __FUNCTION__, | ||
83 | tm->tm_sec, tm->tm_min, tm->tm_hour, | ||
84 | tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm) | ||
90 | { | ||
91 | unsigned char buf[8] = { RS5C372_REG_BASE }; | ||
92 | |||
93 | dev_dbg(&client->dev, | ||
94 | "%s: secs=%d, mins=%d, hours=%d ", | ||
95 | "mday=%d, mon=%d, year=%d, wday=%d\n", | ||
96 | __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour, | ||
97 | tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); | ||
98 | |||
99 | buf[1] = BIN2BCD(tm->tm_sec); | ||
100 | buf[2] = BIN2BCD(tm->tm_min); | ||
101 | buf[3] = BIN2BCD(tm->tm_hour); | ||
102 | buf[4] = BIN2BCD(tm->tm_wday); | ||
103 | buf[5] = BIN2BCD(tm->tm_mday); | ||
104 | buf[6] = BIN2BCD(tm->tm_mon + 1); | ||
105 | buf[7] = BIN2BCD(tm->tm_year - 100); | ||
106 | |||
107 | if ((i2c_master_send(client, buf, 8)) != 8) { | ||
108 | dev_err(&client->dev, "%s: write error\n", __FUNCTION__); | ||
109 | return -EIO; | ||
110 | } | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim) | ||
116 | { | ||
117 | unsigned char buf = RS5C372_REG_TRIM; | ||
118 | |||
119 | struct i2c_msg msgs[] = { | ||
120 | { client->addr, 0, 1, &buf }, | ||
121 | { client->addr, I2C_M_RD, 1, &buf }, | ||
122 | }; | ||
123 | |||
124 | if ((i2c_transfer(client->adapter, msgs, 2)) != 2) { | ||
125 | dev_err(&client->dev, "%s: read error\n", __FUNCTION__); | ||
126 | return -EIO; | ||
127 | } | ||
128 | |||
129 | dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, trim); | ||
130 | |||
131 | if (osc) | ||
132 | *osc = (buf & RS5C372_TRIM_XSL) ? 32000 : 32768; | ||
133 | |||
134 | if (trim) | ||
135 | *trim = buf & RS5C372_TRIM_MASK; | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int rs5c372_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
141 | { | ||
142 | return rs5c372_get_datetime(to_i2c_client(dev), tm); | ||
143 | } | ||
144 | |||
145 | static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
146 | { | ||
147 | return rs5c372_set_datetime(to_i2c_client(dev), tm); | ||
148 | } | ||
149 | |||
150 | static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq) | ||
151 | { | ||
152 | int err, osc, trim; | ||
153 | |||
154 | seq_printf(seq, "24hr\t\t: yes\n"); | ||
155 | |||
156 | if ((err = rs5c372_get_trim(to_i2c_client(dev), &osc, &trim)) == 0) { | ||
157 | seq_printf(seq, "%d.%03d KHz\n", osc / 1000, osc % 1000); | ||
158 | seq_printf(seq, "trim\t: %d\n", trim); | ||
159 | } | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static struct rtc_class_ops rs5c372_rtc_ops = { | ||
165 | .proc = rs5c372_rtc_proc, | ||
166 | .read_time = rs5c372_rtc_read_time, | ||
167 | .set_time = rs5c372_rtc_set_time, | ||
168 | }; | ||
169 | |||
170 | static ssize_t rs5c372_sysfs_show_trim(struct device *dev, | ||
171 | struct device_attribute *attr, char *buf) | ||
172 | { | ||
173 | int trim; | ||
174 | |||
175 | if (rs5c372_get_trim(to_i2c_client(dev), NULL, &trim) == 0) | ||
176 | return sprintf(buf, "0x%2x\n", trim); | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | static DEVICE_ATTR(trim, S_IRUGO, rs5c372_sysfs_show_trim, NULL); | ||
181 | |||
182 | static ssize_t rs5c372_sysfs_show_osc(struct device *dev, | ||
183 | struct device_attribute *attr, char *buf) | ||
184 | { | ||
185 | int osc; | ||
186 | |||
187 | if (rs5c372_get_trim(to_i2c_client(dev), &osc, NULL) == 0) | ||
188 | return sprintf(buf, "%d.%03d KHz\n", osc / 1000, osc % 1000); | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | static DEVICE_ATTR(osc, S_IRUGO, rs5c372_sysfs_show_osc, NULL); | ||
193 | |||
194 | static int rs5c372_attach(struct i2c_adapter *adapter) | ||
195 | { | ||
196 | dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); | ||
197 | return i2c_probe(adapter, &addr_data, rs5c372_probe); | ||
198 | } | ||
199 | |||
200 | static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) | ||
201 | { | ||
202 | int err = 0; | ||
203 | struct i2c_client *client; | ||
204 | struct rtc_device *rtc; | ||
205 | |||
206 | dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); | ||
207 | |||
208 | if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { | ||
209 | err = -ENODEV; | ||
210 | goto exit; | ||
211 | } | ||
212 | |||
213 | if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) { | ||
214 | err = -ENOMEM; | ||
215 | goto exit; | ||
216 | } | ||
217 | |||
218 | /* I2C client */ | ||
219 | client->addr = address; | ||
220 | client->driver = &rs5c372_driver; | ||
221 | client->adapter = adapter; | ||
222 | |||
223 | strlcpy(client->name, rs5c372_driver.driver.name, I2C_NAME_SIZE); | ||
224 | |||
225 | /* Inform the i2c layer */ | ||
226 | if ((err = i2c_attach_client(client))) | ||
227 | goto exit_kfree; | ||
228 | |||
229 | dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); | ||
230 | |||
231 | rtc = rtc_device_register(rs5c372_driver.driver.name, &client->dev, | ||
232 | &rs5c372_rtc_ops, THIS_MODULE); | ||
233 | |||
234 | if (IS_ERR(rtc)) { | ||
235 | err = PTR_ERR(rtc); | ||
236 | dev_err(&client->dev, | ||
237 | "unable to register the class device\n"); | ||
238 | goto exit_detach; | ||
239 | } | ||
240 | |||
241 | i2c_set_clientdata(client, rtc); | ||
242 | |||
243 | device_create_file(&client->dev, &dev_attr_trim); | ||
244 | device_create_file(&client->dev, &dev_attr_osc); | ||
245 | |||
246 | return 0; | ||
247 | |||
248 | exit_detach: | ||
249 | i2c_detach_client(client); | ||
250 | |||
251 | exit_kfree: | ||
252 | kfree(client); | ||
253 | |||
254 | exit: | ||
255 | return err; | ||
256 | } | ||
257 | |||
258 | static int rs5c372_detach(struct i2c_client *client) | ||
259 | { | ||
260 | int err; | ||
261 | struct rtc_device *rtc = i2c_get_clientdata(client); | ||
262 | |||
263 | dev_dbg(&client->dev, "%s\n", __FUNCTION__); | ||
264 | |||
265 | if (rtc) | ||
266 | rtc_device_unregister(rtc); | ||
267 | |||
268 | if ((err = i2c_detach_client(client))) | ||
269 | return err; | ||
270 | |||
271 | kfree(client); | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static __init int rs5c372_init(void) | ||
277 | { | ||
278 | return i2c_add_driver(&rs5c372_driver); | ||
279 | } | ||
280 | |||
281 | static __exit void rs5c372_exit(void) | ||
282 | { | ||
283 | i2c_del_driver(&rs5c372_driver); | ||
284 | } | ||
285 | |||
286 | module_init(rs5c372_init); | ||
287 | module_exit(rs5c372_exit); | ||
288 | |||
289 | MODULE_AUTHOR( | ||
290 | "Pavel Mironchik <pmironchik@optifacio.net>, " | ||
291 | "Alessandro Zummo <a.zummo@towertech.it>"); | ||
292 | MODULE_DESCRIPTION("Ricoh RS5C372 RTC driver"); | ||
293 | MODULE_LICENSE("GPL"); | ||
294 | MODULE_VERSION(DRV_VERSION); | ||
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c new file mode 100644 index 000000000000..83b2bb480a16 --- /dev/null +++ b/drivers/rtc/rtc-sa1100.c | |||
@@ -0,0 +1,388 @@ | |||
1 | /* | ||
2 | * Real Time Clock interface for StrongARM SA1x00 and XScale PXA2xx | ||
3 | * | ||
4 | * Copyright (c) 2000 Nils Faerber | ||
5 | * | ||
6 | * Based on rtc.c by Paul Gortmaker | ||
7 | * | ||
8 | * Original Driver by Nils Faerber <nils@kernelconcepts.de> | ||
9 | * | ||
10 | * Modifications from: | ||
11 | * CIH <cih@coventive.com> | ||
12 | * Nicolas Pitre <nico@cam.org> | ||
13 | * Andrew Christian <andrew.christian@hp.com> | ||
14 | * | ||
15 | * Converted to the RTC subsystem and Driver Model | ||
16 | * by Richard Purdie <rpurdie@rpsys.net> | ||
17 | * | ||
18 | * This program is free software; you can redistribute it and/or | ||
19 | * modify it under the terms of the GNU General Public License | ||
20 | * as published by the Free Software Foundation; either version | ||
21 | * 2 of the License, or (at your option) any later version. | ||
22 | */ | ||
23 | |||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/rtc.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/fs.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/string.h> | ||
31 | #include <linux/pm.h> | ||
32 | |||
33 | #include <asm/bitops.h> | ||
34 | #include <asm/hardware.h> | ||
35 | #include <asm/irq.h> | ||
36 | #include <asm/rtc.h> | ||
37 | |||
38 | #ifdef CONFIG_ARCH_PXA | ||
39 | #include <asm/arch/pxa-regs.h> | ||
40 | #endif | ||
41 | |||
42 | #define TIMER_FREQ CLOCK_TICK_RATE | ||
43 | #define RTC_DEF_DIVIDER 32768 - 1 | ||
44 | #define RTC_DEF_TRIM 0 | ||
45 | |||
46 | static unsigned long rtc_freq = 1024; | ||
47 | static struct rtc_time rtc_alarm; | ||
48 | static spinlock_t sa1100_rtc_lock = SPIN_LOCK_UNLOCKED; | ||
49 | |||
50 | static int rtc_update_alarm(struct rtc_time *alrm) | ||
51 | { | ||
52 | struct rtc_time alarm_tm, now_tm; | ||
53 | unsigned long now, time; | ||
54 | int ret; | ||
55 | |||
56 | do { | ||
57 | now = RCNR; | ||
58 | rtc_time_to_tm(now, &now_tm); | ||
59 | rtc_next_alarm_time(&alarm_tm, &now_tm, alrm); | ||
60 | ret = rtc_tm_to_time(&alarm_tm, &time); | ||
61 | if (ret != 0) | ||
62 | break; | ||
63 | |||
64 | RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL); | ||
65 | RTAR = time; | ||
66 | } while (now != RCNR); | ||
67 | |||
68 | return ret; | ||
69 | } | ||
70 | |||
71 | static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id, | ||
72 | struct pt_regs *regs) | ||
73 | { | ||
74 | struct platform_device *pdev = to_platform_device(dev_id); | ||
75 | struct rtc_device *rtc = platform_get_drvdata(pdev); | ||
76 | unsigned int rtsr; | ||
77 | unsigned long events = 0; | ||
78 | |||
79 | spin_lock(&sa1100_rtc_lock); | ||
80 | |||
81 | rtsr = RTSR; | ||
82 | /* clear interrupt sources */ | ||
83 | RTSR = 0; | ||
84 | RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2); | ||
85 | |||
86 | /* clear alarm interrupt if it has occurred */ | ||
87 | if (rtsr & RTSR_AL) | ||
88 | rtsr &= ~RTSR_ALE; | ||
89 | RTSR = rtsr & (RTSR_ALE | RTSR_HZE); | ||
90 | |||
91 | /* update irq data & counter */ | ||
92 | if (rtsr & RTSR_AL) | ||
93 | events |= RTC_AF | RTC_IRQF; | ||
94 | if (rtsr & RTSR_HZ) | ||
95 | events |= RTC_UF | RTC_IRQF; | ||
96 | |||
97 | rtc_update_irq(&rtc->class_dev, 1, events); | ||
98 | |||
99 | if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm)) | ||
100 | rtc_update_alarm(&rtc_alarm); | ||
101 | |||
102 | spin_unlock(&sa1100_rtc_lock); | ||
103 | |||
104 | return IRQ_HANDLED; | ||
105 | } | ||
106 | |||
107 | static int rtc_timer1_count; | ||
108 | |||
109 | static irqreturn_t timer1_interrupt(int irq, void *dev_id, | ||
110 | struct pt_regs *regs) | ||
111 | { | ||
112 | struct platform_device *pdev = to_platform_device(dev_id); | ||
113 | struct rtc_device *rtc = platform_get_drvdata(pdev); | ||
114 | |||
115 | /* | ||
116 | * If we match for the first time, rtc_timer1_count will be 1. | ||
117 | * Otherwise, we wrapped around (very unlikely but | ||
118 | * still possible) so compute the amount of missed periods. | ||
119 | * The match reg is updated only when the data is actually retrieved | ||
120 | * to avoid unnecessary interrupts. | ||
121 | */ | ||
122 | OSSR = OSSR_M1; /* clear match on timer1 */ | ||
123 | |||
124 | rtc_update_irq(&rtc->class_dev, rtc_timer1_count, RTC_PF | RTC_IRQF); | ||
125 | |||
126 | if (rtc_timer1_count == 1) | ||
127 | rtc_timer1_count = (rtc_freq * ((1<<30)/(TIMER_FREQ>>2))); | ||
128 | |||
129 | return IRQ_HANDLED; | ||
130 | } | ||
131 | |||
132 | static int sa1100_rtc_read_callback(struct device *dev, int data) | ||
133 | { | ||
134 | if (data & RTC_PF) { | ||
135 | /* interpolate missed periods and set match for the next */ | ||
136 | unsigned long period = TIMER_FREQ/rtc_freq; | ||
137 | unsigned long oscr = OSCR; | ||
138 | unsigned long osmr1 = OSMR1; | ||
139 | unsigned long missed = (oscr - osmr1)/period; | ||
140 | data += missed << 8; | ||
141 | OSSR = OSSR_M1; /* clear match on timer 1 */ | ||
142 | OSMR1 = osmr1 + (missed + 1)*period; | ||
143 | /* Ensure we didn't miss another match in the mean time. | ||
144 | * Here we compare (match - OSCR) 8 instead of 0 -- | ||
145 | * see comment in pxa_timer_interrupt() for explanation. | ||
146 | */ | ||
147 | while( (signed long)((osmr1 = OSMR1) - OSCR) <= 8 ) { | ||
148 | data += 0x100; | ||
149 | OSSR = OSSR_M1; /* clear match on timer 1 */ | ||
150 | OSMR1 = osmr1 + period; | ||
151 | } | ||
152 | } | ||
153 | return data; | ||
154 | } | ||
155 | |||
156 | static int sa1100_rtc_open(struct device *dev) | ||
157 | { | ||
158 | int ret; | ||
159 | |||
160 | ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, SA_INTERRUPT, | ||
161 | "rtc 1Hz", dev); | ||
162 | if (ret) { | ||
163 | printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTC1Hz); | ||
164 | goto fail_ui; | ||
165 | } | ||
166 | ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, SA_INTERRUPT, | ||
167 | "rtc Alrm", dev); | ||
168 | if (ret) { | ||
169 | printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTCAlrm); | ||
170 | goto fail_ai; | ||
171 | } | ||
172 | ret = request_irq(IRQ_OST1, timer1_interrupt, SA_INTERRUPT, | ||
173 | "rtc timer", dev); | ||
174 | if (ret) { | ||
175 | printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_OST1); | ||
176 | goto fail_pi; | ||
177 | } | ||
178 | return 0; | ||
179 | |||
180 | fail_pi: | ||
181 | free_irq(IRQ_RTCAlrm, NULL); | ||
182 | fail_ai: | ||
183 | free_irq(IRQ_RTC1Hz, NULL); | ||
184 | fail_ui: | ||
185 | return ret; | ||
186 | } | ||
187 | |||
188 | static void sa1100_rtc_release(struct device *dev) | ||
189 | { | ||
190 | spin_lock_irq(&sa1100_rtc_lock); | ||
191 | RTSR = 0; | ||
192 | OIER &= ~OIER_E1; | ||
193 | OSSR = OSSR_M1; | ||
194 | spin_unlock_irq(&sa1100_rtc_lock); | ||
195 | |||
196 | free_irq(IRQ_OST1, dev); | ||
197 | free_irq(IRQ_RTCAlrm, dev); | ||
198 | free_irq(IRQ_RTC1Hz, dev); | ||
199 | } | ||
200 | |||
201 | |||
202 | static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, | ||
203 | unsigned long arg) | ||
204 | { | ||
205 | switch(cmd) { | ||
206 | case RTC_AIE_OFF: | ||
207 | spin_lock_irq(&sa1100_rtc_lock); | ||
208 | RTSR &= ~RTSR_ALE; | ||
209 | spin_unlock_irq(&sa1100_rtc_lock); | ||
210 | return 0; | ||
211 | case RTC_AIE_ON: | ||
212 | spin_lock_irq(&sa1100_rtc_lock); | ||
213 | RTSR |= RTSR_ALE; | ||
214 | spin_unlock_irq(&sa1100_rtc_lock); | ||
215 | return 0; | ||
216 | case RTC_UIE_OFF: | ||
217 | spin_lock_irq(&sa1100_rtc_lock); | ||
218 | RTSR &= ~RTSR_HZE; | ||
219 | spin_unlock_irq(&sa1100_rtc_lock); | ||
220 | return 0; | ||
221 | case RTC_UIE_ON: | ||
222 | spin_lock_irq(&sa1100_rtc_lock); | ||
223 | RTSR |= RTSR_HZE; | ||
224 | spin_unlock_irq(&sa1100_rtc_lock); | ||
225 | return 0; | ||
226 | case RTC_PIE_OFF: | ||
227 | spin_lock_irq(&sa1100_rtc_lock); | ||
228 | OIER &= ~OIER_E1; | ||
229 | spin_unlock_irq(&sa1100_rtc_lock); | ||
230 | return 0; | ||
231 | case RTC_PIE_ON: | ||
232 | if ((rtc_freq > 64) && !capable(CAP_SYS_RESOURCE)) | ||
233 | return -EACCES; | ||
234 | spin_lock_irq(&sa1100_rtc_lock); | ||
235 | OSMR1 = TIMER_FREQ/rtc_freq + OSCR; | ||
236 | OIER |= OIER_E1; | ||
237 | rtc_timer1_count = 1; | ||
238 | spin_unlock_irq(&sa1100_rtc_lock); | ||
239 | return 0; | ||
240 | case RTC_IRQP_READ: | ||
241 | return put_user(rtc_freq, (unsigned long *)arg); | ||
242 | case RTC_IRQP_SET: | ||
243 | if (arg < 1 || arg > TIMER_FREQ) | ||
244 | return -EINVAL; | ||
245 | if ((arg > 64) && (!capable(CAP_SYS_RESOURCE))) | ||
246 | return -EACCES; | ||
247 | rtc_freq = arg; | ||
248 | return 0; | ||
249 | } | ||
250 | return -EINVAL; | ||
251 | } | ||
252 | |||
253 | static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
254 | { | ||
255 | rtc_time_to_tm(RCNR, tm); | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
260 | { | ||
261 | unsigned long time; | ||
262 | int ret; | ||
263 | |||
264 | ret = rtc_tm_to_time(tm, &time); | ||
265 | if (ret == 0) | ||
266 | RCNR = time; | ||
267 | return ret; | ||
268 | } | ||
269 | |||
270 | static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
271 | { | ||
272 | memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time)); | ||
273 | alrm->pending = RTSR & RTSR_AL ? 1 : 0; | ||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
278 | { | ||
279 | int ret; | ||
280 | |||
281 | spin_lock_irq(&sa1100_rtc_lock); | ||
282 | ret = rtc_update_alarm(&alrm->time); | ||
283 | if (ret == 0) { | ||
284 | memcpy(&rtc_alarm, &alrm->time, sizeof(struct rtc_time)); | ||
285 | |||
286 | if (alrm->enabled) | ||
287 | enable_irq_wake(IRQ_RTCAlrm); | ||
288 | else | ||
289 | disable_irq_wake(IRQ_RTCAlrm); | ||
290 | } | ||
291 | spin_unlock_irq(&sa1100_rtc_lock); | ||
292 | |||
293 | return ret; | ||
294 | } | ||
295 | |||
296 | static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) | ||
297 | { | ||
298 | seq_printf(seq, "trim/divider\t: 0x%08x\n", RTTR); | ||
299 | seq_printf(seq, "alarm_IRQ\t: %s\n", | ||
300 | (RTSR & RTSR_ALE) ? "yes" : "no" ); | ||
301 | seq_printf(seq, "update_IRQ\t: %s\n", | ||
302 | (RTSR & RTSR_HZE) ? "yes" : "no"); | ||
303 | seq_printf(seq, "periodic_IRQ\t: %s\n", | ||
304 | (OIER & OIER_E1) ? "yes" : "no"); | ||
305 | seq_printf(seq, "periodic_freq\t: %ld\n", rtc_freq); | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static struct rtc_class_ops sa1100_rtc_ops = { | ||
311 | .open = sa1100_rtc_open, | ||
312 | .read_callback = sa1100_rtc_read_callback, | ||
313 | .release = sa1100_rtc_release, | ||
314 | .ioctl = sa1100_rtc_ioctl, | ||
315 | .read_time = sa1100_rtc_read_time, | ||
316 | .set_time = sa1100_rtc_set_time, | ||
317 | .read_alarm = sa1100_rtc_read_alarm, | ||
318 | .set_alarm = sa1100_rtc_set_alarm, | ||
319 | .proc = sa1100_rtc_proc, | ||
320 | }; | ||
321 | |||
322 | static int sa1100_rtc_probe(struct platform_device *pdev) | ||
323 | { | ||
324 | struct rtc_device *rtc; | ||
325 | |||
326 | /* | ||
327 | * According to the manual we should be able to let RTTR be zero | ||
328 | * and then a default diviser for a 32.768KHz clock is used. | ||
329 | * Apparently this doesn't work, at least for my SA1110 rev 5. | ||
330 | * If the clock divider is uninitialized then reset it to the | ||
331 | * default value to get the 1Hz clock. | ||
332 | */ | ||
333 | if (RTTR == 0) { | ||
334 | RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); | ||
335 | printk(KERN_WARNING "rtc: warning: initializing default clock divider/trim value\n"); | ||
336 | /* The current RTC value probably doesn't make sense either */ | ||
337 | RCNR = 0; | ||
338 | } | ||
339 | |||
340 | rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops, | ||
341 | THIS_MODULE); | ||
342 | |||
343 | if (IS_ERR(rtc)) { | ||
344 | dev_err(&pdev->dev, "Unable to register the RTC device\n"); | ||
345 | return PTR_ERR(rtc); | ||
346 | } | ||
347 | |||
348 | platform_set_drvdata(pdev, rtc); | ||
349 | |||
350 | dev_info(&pdev->dev, "SA11xx/PXA2xx RTC Registered\n"); | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | static int sa1100_rtc_remove(struct platform_device *pdev) | ||
356 | { | ||
357 | struct rtc_device *rtc = platform_get_drvdata(pdev); | ||
358 | |||
359 | if (rtc) | ||
360 | rtc_device_unregister(rtc); | ||
361 | |||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | static struct platform_driver sa1100_rtc_driver = { | ||
366 | .probe = sa1100_rtc_probe, | ||
367 | .remove = sa1100_rtc_remove, | ||
368 | .driver = { | ||
369 | .name = "sa1100-rtc", | ||
370 | }, | ||
371 | }; | ||
372 | |||
373 | static int __init sa1100_rtc_init(void) | ||
374 | { | ||
375 | return platform_driver_register(&sa1100_rtc_driver); | ||
376 | } | ||
377 | |||
378 | static void __exit sa1100_rtc_exit(void) | ||
379 | { | ||
380 | platform_driver_unregister(&sa1100_rtc_driver); | ||
381 | } | ||
382 | |||
383 | module_init(sa1100_rtc_init); | ||
384 | module_exit(sa1100_rtc_exit); | ||
385 | |||
386 | MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); | ||
387 | MODULE_DESCRIPTION("SA11x0/PXA2xx Realtime Clock Driver (RTC)"); | ||
388 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c new file mode 100644 index 000000000000..7c1f3d2e53c4 --- /dev/null +++ b/drivers/rtc/rtc-sysfs.c | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | * RTC subsystem, sysfs interface | ||
3 | * | ||
4 | * Copyright (C) 2005 Tower Technologies | ||
5 | * Author: Alessandro Zummo <a.zummo@towertech.it> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/rtc.h> | ||
14 | |||
15 | /* device attributes */ | ||
16 | |||
17 | static ssize_t rtc_sysfs_show_name(struct class_device *dev, char *buf) | ||
18 | { | ||
19 | return sprintf(buf, "%s\n", to_rtc_device(dev)->name); | ||
20 | } | ||
21 | static CLASS_DEVICE_ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL); | ||
22 | |||
23 | static ssize_t rtc_sysfs_show_date(struct class_device *dev, char *buf) | ||
24 | { | ||
25 | ssize_t retval; | ||
26 | struct rtc_time tm; | ||
27 | |||
28 | retval = rtc_read_time(dev, &tm); | ||
29 | if (retval == 0) { | ||
30 | retval = sprintf(buf, "%04d-%02d-%02d\n", | ||
31 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); | ||
32 | } | ||
33 | |||
34 | return retval; | ||
35 | } | ||
36 | static CLASS_DEVICE_ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL); | ||
37 | |||
38 | static ssize_t rtc_sysfs_show_time(struct class_device *dev, char *buf) | ||
39 | { | ||
40 | ssize_t retval; | ||
41 | struct rtc_time tm; | ||
42 | |||
43 | retval = rtc_read_time(dev, &tm); | ||
44 | if (retval == 0) { | ||
45 | retval = sprintf(buf, "%02d:%02d:%02d\n", | ||
46 | tm.tm_hour, tm.tm_min, tm.tm_sec); | ||
47 | } | ||
48 | |||
49 | return retval; | ||
50 | } | ||
51 | static CLASS_DEVICE_ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL); | ||
52 | |||
53 | static ssize_t rtc_sysfs_show_since_epoch(struct class_device *dev, char *buf) | ||
54 | { | ||
55 | ssize_t retval; | ||
56 | struct rtc_time tm; | ||
57 | |||
58 | retval = rtc_read_time(dev, &tm); | ||
59 | if (retval == 0) { | ||
60 | unsigned long time; | ||
61 | rtc_tm_to_time(&tm, &time); | ||
62 | retval = sprintf(buf, "%lu\n", time); | ||
63 | } | ||
64 | |||
65 | return retval; | ||
66 | } | ||
67 | static CLASS_DEVICE_ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL); | ||
68 | |||
69 | static struct attribute *rtc_attrs[] = { | ||
70 | &class_device_attr_name.attr, | ||
71 | &class_device_attr_date.attr, | ||
72 | &class_device_attr_time.attr, | ||
73 | &class_device_attr_since_epoch.attr, | ||
74 | NULL, | ||
75 | }; | ||
76 | |||
77 | static struct attribute_group rtc_attr_group = { | ||
78 | .attrs = rtc_attrs, | ||
79 | }; | ||
80 | |||
81 | static int __devinit rtc_sysfs_add_device(struct class_device *class_dev, | ||
82 | struct class_interface *class_intf) | ||
83 | { | ||
84 | int err; | ||
85 | |||
86 | dev_info(class_dev->dev, "rtc intf: sysfs\n"); | ||
87 | |||
88 | err = sysfs_create_group(&class_dev->kobj, &rtc_attr_group); | ||
89 | if (err) | ||
90 | dev_err(class_dev->dev, | ||
91 | "failed to create sysfs attributes\n"); | ||
92 | |||
93 | return err; | ||
94 | } | ||
95 | |||
96 | static void rtc_sysfs_remove_device(struct class_device *class_dev, | ||
97 | struct class_interface *class_intf) | ||
98 | { | ||
99 | sysfs_remove_group(&class_dev->kobj, &rtc_attr_group); | ||
100 | } | ||
101 | |||
102 | /* interface registration */ | ||
103 | |||
104 | static struct class_interface rtc_sysfs_interface = { | ||
105 | .add = &rtc_sysfs_add_device, | ||
106 | .remove = &rtc_sysfs_remove_device, | ||
107 | }; | ||
108 | |||
109 | static int __init rtc_sysfs_init(void) | ||
110 | { | ||
111 | return rtc_interface_register(&rtc_sysfs_interface); | ||
112 | } | ||
113 | |||
114 | static void __exit rtc_sysfs_exit(void) | ||
115 | { | ||
116 | class_interface_unregister(&rtc_sysfs_interface); | ||
117 | } | ||
118 | |||
119 | module_init(rtc_sysfs_init); | ||
120 | module_exit(rtc_sysfs_exit); | ||
121 | |||
122 | MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); | ||
123 | MODULE_DESCRIPTION("RTC class sysfs interface"); | ||
124 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c new file mode 100644 index 000000000000..43d107487820 --- /dev/null +++ b/drivers/rtc/rtc-test.c | |||
@@ -0,0 +1,204 @@ | |||
1 | /* | ||
2 | * An RTC test device/driver | ||
3 | * Copyright (C) 2005 Tower Technologies | ||
4 | * Author: Alessandro Zummo <a.zummo@towertech.it> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/err.h> | ||
13 | #include <linux/rtc.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | |||
16 | static struct platform_device *test0 = NULL, *test1 = NULL; | ||
17 | |||
18 | static int test_rtc_read_alarm(struct device *dev, | ||
19 | struct rtc_wkalrm *alrm) | ||
20 | { | ||
21 | return 0; | ||
22 | } | ||
23 | |||
24 | static int test_rtc_set_alarm(struct device *dev, | ||
25 | struct rtc_wkalrm *alrm) | ||
26 | { | ||
27 | return 0; | ||
28 | } | ||
29 | |||
30 | static int test_rtc_read_time(struct device *dev, | ||
31 | struct rtc_time *tm) | ||
32 | { | ||
33 | rtc_time_to_tm(get_seconds(), tm); | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | static int test_rtc_set_time(struct device *dev, | ||
38 | struct rtc_time *tm) | ||
39 | { | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static int test_rtc_set_mmss(struct device *dev, unsigned long secs) | ||
44 | { | ||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | static int test_rtc_proc(struct device *dev, struct seq_file *seq) | ||
49 | { | ||
50 | struct platform_device *plat_dev = to_platform_device(dev); | ||
51 | |||
52 | seq_printf(seq, "24hr\t\t: yes\n"); | ||
53 | seq_printf(seq, "test\t\t: yes\n"); | ||
54 | seq_printf(seq, "id\t\t: %d\n", plat_dev->id); | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static int test_rtc_ioctl(struct device *dev, unsigned int cmd, | ||
60 | unsigned long arg) | ||
61 | { | ||
62 | /* We do support interrupts, they're generated | ||
63 | * using the sysfs interface. | ||
64 | */ | ||
65 | switch (cmd) { | ||
66 | case RTC_PIE_ON: | ||
67 | case RTC_PIE_OFF: | ||
68 | case RTC_UIE_ON: | ||
69 | case RTC_UIE_OFF: | ||
70 | case RTC_AIE_ON: | ||
71 | case RTC_AIE_OFF: | ||
72 | return 0; | ||
73 | |||
74 | default: | ||
75 | return -EINVAL; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | static struct rtc_class_ops test_rtc_ops = { | ||
80 | .proc = test_rtc_proc, | ||
81 | .read_time = test_rtc_read_time, | ||
82 | .set_time = test_rtc_set_time, | ||
83 | .read_alarm = test_rtc_read_alarm, | ||
84 | .set_alarm = test_rtc_set_alarm, | ||
85 | .set_mmss = test_rtc_set_mmss, | ||
86 | .ioctl = test_rtc_ioctl, | ||
87 | }; | ||
88 | |||
89 | static ssize_t test_irq_show(struct device *dev, | ||
90 | struct device_attribute *attr, char *buf) | ||
91 | { | ||
92 | return sprintf(buf, "%d\n", 42); | ||
93 | } | ||
94 | static ssize_t test_irq_store(struct device *dev, | ||
95 | struct device_attribute *attr, | ||
96 | const char *buf, size_t count) | ||
97 | { | ||
98 | int retval; | ||
99 | struct platform_device *plat_dev = to_platform_device(dev); | ||
100 | struct rtc_device *rtc = platform_get_drvdata(plat_dev); | ||
101 | |||
102 | retval = count; | ||
103 | if (strncmp(buf, "tick", 4) == 0) | ||
104 | rtc_update_irq(&rtc->class_dev, 1, RTC_PF | RTC_IRQF); | ||
105 | else if (strncmp(buf, "alarm", 5) == 0) | ||
106 | rtc_update_irq(&rtc->class_dev, 1, RTC_AF | RTC_IRQF); | ||
107 | else if (strncmp(buf, "update", 6) == 0) | ||
108 | rtc_update_irq(&rtc->class_dev, 1, RTC_UF | RTC_IRQF); | ||
109 | else | ||
110 | retval = -EINVAL; | ||
111 | |||
112 | return retval; | ||
113 | } | ||
114 | static DEVICE_ATTR(irq, S_IRUGO | S_IWUSR, test_irq_show, test_irq_store); | ||
115 | |||
116 | static int test_probe(struct platform_device *plat_dev) | ||
117 | { | ||
118 | int err; | ||
119 | struct rtc_device *rtc = rtc_device_register("test", &plat_dev->dev, | ||
120 | &test_rtc_ops, THIS_MODULE); | ||
121 | if (IS_ERR(rtc)) { | ||
122 | err = PTR_ERR(rtc); | ||
123 | dev_err(&plat_dev->dev, | ||
124 | "unable to register the class device\n"); | ||
125 | return err; | ||
126 | } | ||
127 | device_create_file(&plat_dev->dev, &dev_attr_irq); | ||
128 | |||
129 | platform_set_drvdata(plat_dev, rtc); | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static int __devexit test_remove(struct platform_device *plat_dev) | ||
135 | { | ||
136 | struct rtc_device *rtc = platform_get_drvdata(plat_dev); | ||
137 | |||
138 | rtc_device_unregister(rtc); | ||
139 | device_remove_file(&plat_dev->dev, &dev_attr_irq); | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static struct platform_driver test_drv = { | ||
145 | .probe = test_probe, | ||
146 | .remove = __devexit_p(test_remove), | ||
147 | .driver = { | ||
148 | .name = "rtc-test", | ||
149 | .owner = THIS_MODULE, | ||
150 | }, | ||
151 | }; | ||
152 | |||
153 | static int __init test_init(void) | ||
154 | { | ||
155 | int err; | ||
156 | |||
157 | if ((err = platform_driver_register(&test_drv))) | ||
158 | return err; | ||
159 | |||
160 | if ((test0 = platform_device_alloc("rtc-test", 0)) == NULL) { | ||
161 | err = -ENOMEM; | ||
162 | goto exit_driver_unregister; | ||
163 | } | ||
164 | |||
165 | if ((test1 = platform_device_alloc("rtc-test", 1)) == NULL) { | ||
166 | err = -ENOMEM; | ||
167 | goto exit_free_test0; | ||
168 | } | ||
169 | |||
170 | if ((err = platform_device_add(test0))) | ||
171 | goto exit_free_test1; | ||
172 | |||
173 | if ((err = platform_device_add(test1))) | ||
174 | goto exit_device_unregister; | ||
175 | |||
176 | return 0; | ||
177 | |||
178 | exit_device_unregister: | ||
179 | platform_device_unregister(test0); | ||
180 | |||
181 | exit_free_test1: | ||
182 | platform_device_put(test1); | ||
183 | |||
184 | exit_free_test0: | ||
185 | platform_device_put(test0); | ||
186 | |||
187 | exit_driver_unregister: | ||
188 | platform_driver_unregister(&test_drv); | ||
189 | return err; | ||
190 | } | ||
191 | |||
192 | static void __exit test_exit(void) | ||
193 | { | ||
194 | platform_device_unregister(test0); | ||
195 | platform_device_unregister(test1); | ||
196 | platform_driver_unregister(&test_drv); | ||
197 | } | ||
198 | |||
199 | MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); | ||
200 | MODULE_DESCRIPTION("RTC test driver/device"); | ||
201 | MODULE_LICENSE("GPL"); | ||
202 | |||
203 | module_init(test_init); | ||
204 | module_exit(test_exit); | ||
diff --git a/drivers/i2c/chips/x1205.c b/drivers/rtc/rtc-x1205.c index 245fffa92dbd..621d17afc0d9 100644 --- a/drivers/i2c/chips/x1205.c +++ b/drivers/rtc/rtc-x1205.c | |||
@@ -1,32 +1,25 @@ | |||
1 | /* | 1 | /* |
2 | * x1205.c - An i2c driver for the Xicor X1205 RTC | 2 | * An i2c driver for the Xicor/Intersil X1205 RTC |
3 | * Copyright 2004 Karen Spearel | 3 | * Copyright 2004 Karen Spearel |
4 | * Copyright 2005 Alessandro Zummo | 4 | * Copyright 2005 Alessandro Zummo |
5 | * | 5 | * |
6 | * please send all reports to: | 6 | * please send all reports to: |
7 | * kas11 at tampabay dot rr dot com | 7 | * Karen Spearel <kas111 at gmail dot com> |
8 | * a dot zummo at towertech dot it | 8 | * Alessandro Zummo <a.zummo@towertech.it> |
9 | * | 9 | * |
10 | * based on the other drivers in this same directory. | 10 | * based on a lot of other RTC drivers. |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License as published by | 13 | * it under the terms of the GNU General Public License version 2 as |
14 | * the Free Software Foundation; either version 2 of the License, or | 14 | * published by the Free Software Foundation. |
15 | * (at your option) any later version. | ||
16 | */ | 15 | */ |
17 | 16 | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
22 | #include <linux/string.h> | ||
23 | #include <linux/bcd.h> | 18 | #include <linux/bcd.h> |
24 | #include <linux/rtc.h> | 19 | #include <linux/rtc.h> |
25 | #include <linux/list.h> | 20 | #include <linux/delay.h> |
26 | 21 | ||
27 | #include <linux/x1205.h> | 22 | #define DRV_VERSION "1.0.6" |
28 | |||
29 | #define DRV_VERSION "0.9.9" | ||
30 | 23 | ||
31 | /* Addresses to scan: none. This chip is located at | 24 | /* Addresses to scan: none. This chip is located at |
32 | * 0x6f and uses a two bytes register addressing. | 25 | * 0x6f and uses a two bytes register addressing. |
@@ -40,8 +33,6 @@ static unsigned short normal_i2c[] = { I2C_CLIENT_END }; | |||
40 | 33 | ||
41 | /* Insmod parameters */ | 34 | /* Insmod parameters */ |
42 | I2C_CLIENT_INSMOD; | 35 | I2C_CLIENT_INSMOD; |
43 | I2C_CLIENT_MODULE_PARM(hctosys, | ||
44 | "Set the system time from the hardware clock upon initialization"); | ||
45 | 36 | ||
46 | /* offsets into CCR area */ | 37 | /* offsets into CCR area */ |
47 | 38 | ||
@@ -101,107 +92,35 @@ I2C_CLIENT_MODULE_PARM(hctosys, | |||
101 | static int x1205_attach(struct i2c_adapter *adapter); | 92 | static int x1205_attach(struct i2c_adapter *adapter); |
102 | static int x1205_detach(struct i2c_client *client); | 93 | static int x1205_detach(struct i2c_client *client); |
103 | static int x1205_probe(struct i2c_adapter *adapter, int address, int kind); | 94 | static int x1205_probe(struct i2c_adapter *adapter, int address, int kind); |
104 | static int x1205_command(struct i2c_client *client, unsigned int cmd, | ||
105 | void *arg); | ||
106 | 95 | ||
107 | static struct i2c_driver x1205_driver = { | 96 | static struct i2c_driver x1205_driver = { |
108 | .driver = { | 97 | .driver = { |
109 | .name = "x1205", | 98 | .name = "x1205", |
110 | }, | 99 | }, |
100 | .id = I2C_DRIVERID_X1205, | ||
111 | .attach_adapter = &x1205_attach, | 101 | .attach_adapter = &x1205_attach, |
112 | .detach_client = &x1205_detach, | 102 | .detach_client = &x1205_detach, |
113 | }; | 103 | }; |
114 | 104 | ||
115 | struct x1205_data { | ||
116 | struct i2c_client client; | ||
117 | struct list_head list; | ||
118 | unsigned int epoch; | ||
119 | }; | ||
120 | |||
121 | static const unsigned char days_in_mo[] = | ||
122 | { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; | ||
123 | |||
124 | static LIST_HEAD(x1205_clients); | ||
125 | |||
126 | /* Workaround until the I2C subsytem will allow to send | ||
127 | * commands to a specific client. This function will send the command | ||
128 | * to the first client. | ||
129 | */ | ||
130 | int x1205_do_command(unsigned int cmd, void *arg) | ||
131 | { | ||
132 | struct list_head *walk; | ||
133 | struct list_head *tmp; | ||
134 | struct x1205_data *data; | ||
135 | |||
136 | list_for_each_safe(walk, tmp, &x1205_clients) { | ||
137 | data = list_entry(walk, struct x1205_data, list); | ||
138 | return x1205_command(&data->client, cmd, arg); | ||
139 | } | ||
140 | |||
141 | return -ENODEV; | ||
142 | } | ||
143 | |||
144 | #define is_leap(year) \ | ||
145 | ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) | ||
146 | |||
147 | /* make sure the rtc_time values are in bounds */ | ||
148 | static int x1205_validate_tm(struct rtc_time *tm) | ||
149 | { | ||
150 | int year = tm->tm_year + 1900; | ||
151 | |||
152 | if ((tm->tm_year < 70) || (tm->tm_year > 255)) | ||
153 | return -EINVAL; | ||
154 | |||
155 | if ((tm->tm_mon > 11) || (tm->tm_mday == 0)) | ||
156 | return -EINVAL; | ||
157 | |||
158 | if (tm->tm_mday > days_in_mo[tm->tm_mon] | ||
159 | + ((tm->tm_mon == 1) && is_leap(year))) | ||
160 | return -EINVAL; | ||
161 | |||
162 | if ((tm->tm_hour >= 24) || (tm->tm_min >= 60) || (tm->tm_sec >= 60)) | ||
163 | return -EINVAL; | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | /* | 105 | /* |
169 | * In the routines that deal directly with the x1205 hardware, we use | 106 | * In the routines that deal directly with the x1205 hardware, we use |
170 | * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch | 107 | * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch |
171 | * Epoch is initialized as 2000. Time is set to UTC. | 108 | * Epoch is initialized as 2000. Time is set to UTC. |
172 | */ | 109 | */ |
173 | static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm, | 110 | static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm, |
174 | u8 reg_base) | 111 | unsigned char reg_base) |
175 | { | 112 | { |
176 | unsigned char dt_addr[2] = { 0, reg_base }; | 113 | unsigned char dt_addr[2] = { 0, reg_base }; |
177 | static unsigned char sr_addr[2] = { 0, X1205_REG_SR }; | ||
178 | 114 | ||
179 | unsigned char buf[8], sr; | 115 | unsigned char buf[8]; |
180 | 116 | ||
181 | struct i2c_msg msgs[] = { | 117 | struct i2c_msg msgs[] = { |
182 | { client->addr, 0, 2, sr_addr }, /* setup read ptr */ | ||
183 | { client->addr, I2C_M_RD, 1, &sr }, /* read status */ | ||
184 | { client->addr, 0, 2, dt_addr }, /* setup read ptr */ | 118 | { client->addr, 0, 2, dt_addr }, /* setup read ptr */ |
185 | { client->addr, I2C_M_RD, 8, buf }, /* read date */ | 119 | { client->addr, I2C_M_RD, 8, buf }, /* read date */ |
186 | }; | 120 | }; |
187 | 121 | ||
188 | struct x1205_data *data = i2c_get_clientdata(client); | ||
189 | |||
190 | /* read status register */ | ||
191 | if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { | ||
192 | dev_err(&client->dev, "%s: read error\n", __FUNCTION__); | ||
193 | return -EIO; | ||
194 | } | ||
195 | |||
196 | /* check for battery failure */ | ||
197 | if (sr & X1205_SR_RTCF) { | ||
198 | dev_warn(&client->dev, | ||
199 | "Clock had a power failure, you must set the date.\n"); | ||
200 | return -EINVAL; | ||
201 | } | ||
202 | |||
203 | /* read date registers */ | 122 | /* read date registers */ |
204 | if ((i2c_transfer(client->adapter, &msgs[2], 2)) != 2) { | 123 | if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { |
205 | dev_err(&client->dev, "%s: read error\n", __FUNCTION__); | 124 | dev_err(&client->dev, "%s: read error\n", __FUNCTION__); |
206 | return -EIO; | 125 | return -EIO; |
207 | } | 126 | } |
@@ -217,9 +136,9 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm, | |||
217 | tm->tm_min = BCD2BIN(buf[CCR_MIN]); | 136 | tm->tm_min = BCD2BIN(buf[CCR_MIN]); |
218 | tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */ | 137 | tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */ |
219 | tm->tm_mday = BCD2BIN(buf[CCR_MDAY]); | 138 | tm->tm_mday = BCD2BIN(buf[CCR_MDAY]); |
220 | tm->tm_mon = BCD2BIN(buf[CCR_MONTH]); | 139 | tm->tm_mon = BCD2BIN(buf[CCR_MONTH]) - 1; /* mon is 0-11 */ |
221 | data->epoch = BCD2BIN(buf[CCR_Y2K]) * 100; | 140 | tm->tm_year = BCD2BIN(buf[CCR_YEAR]) |
222 | tm->tm_year = BCD2BIN(buf[CCR_YEAR]) + data->epoch - 1900; | 141 | + (BCD2BIN(buf[CCR_Y2K]) * 100) - 1900; |
223 | tm->tm_wday = buf[CCR_WDAY]; | 142 | tm->tm_wday = buf[CCR_WDAY]; |
224 | 143 | ||
225 | dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " | 144 | dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " |
@@ -231,11 +150,28 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm, | |||
231 | return 0; | 150 | return 0; |
232 | } | 151 | } |
233 | 152 | ||
153 | static int x1205_get_status(struct i2c_client *client, unsigned char *sr) | ||
154 | { | ||
155 | static unsigned char sr_addr[2] = { 0, X1205_REG_SR }; | ||
156 | |||
157 | struct i2c_msg msgs[] = { | ||
158 | { client->addr, 0, 2, sr_addr }, /* setup read ptr */ | ||
159 | { client->addr, I2C_M_RD, 1, sr }, /* read status */ | ||
160 | }; | ||
161 | |||
162 | /* read status register */ | ||
163 | if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { | ||
164 | dev_err(&client->dev, "%s: read error\n", __FUNCTION__); | ||
165 | return -EIO; | ||
166 | } | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
234 | static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, | 171 | static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, |
235 | int datetoo, u8 reg_base) | 172 | int datetoo, u8 reg_base) |
236 | { | 173 | { |
237 | int i, err, xfer; | 174 | int i, xfer; |
238 | |||
239 | unsigned char buf[8]; | 175 | unsigned char buf[8]; |
240 | 176 | ||
241 | static const unsigned char wel[3] = { 0, X1205_REG_SR, | 177 | static const unsigned char wel[3] = { 0, X1205_REG_SR, |
@@ -246,17 +182,10 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, | |||
246 | 182 | ||
247 | static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 }; | 183 | static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 }; |
248 | 184 | ||
249 | struct x1205_data *data = i2c_get_clientdata(client); | 185 | dev_dbg(&client->dev, |
250 | 186 | "%s: secs=%d, mins=%d, hours=%d\n", | |
251 | /* check if all values in the tm struct are correct */ | ||
252 | if ((err = x1205_validate_tm(tm)) < 0) | ||
253 | return err; | ||
254 | |||
255 | dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " | ||
256 | "mday=%d, mon=%d, year=%d, wday=%d\n", | ||
257 | __FUNCTION__, | 187 | __FUNCTION__, |
258 | tm->tm_sec, tm->tm_min, tm->tm_hour, | 188 | tm->tm_sec, tm->tm_min, tm->tm_hour); |
259 | tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); | ||
260 | 189 | ||
261 | buf[CCR_SEC] = BIN2BCD(tm->tm_sec); | 190 | buf[CCR_SEC] = BIN2BCD(tm->tm_sec); |
262 | buf[CCR_MIN] = BIN2BCD(tm->tm_min); | 191 | buf[CCR_MIN] = BIN2BCD(tm->tm_min); |
@@ -266,26 +195,29 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, | |||
266 | 195 | ||
267 | /* should we also set the date? */ | 196 | /* should we also set the date? */ |
268 | if (datetoo) { | 197 | if (datetoo) { |
198 | dev_dbg(&client->dev, | ||
199 | "%s: mday=%d, mon=%d, year=%d, wday=%d\n", | ||
200 | __FUNCTION__, | ||
201 | tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); | ||
202 | |||
269 | buf[CCR_MDAY] = BIN2BCD(tm->tm_mday); | 203 | buf[CCR_MDAY] = BIN2BCD(tm->tm_mday); |
270 | 204 | ||
271 | /* month, 0 - 11 */ | 205 | /* month, 1 - 12 */ |
272 | buf[CCR_MONTH] = BIN2BCD(tm->tm_mon); | 206 | buf[CCR_MONTH] = BIN2BCD(tm->tm_mon + 1); |
273 | 207 | ||
274 | /* year, since 1900 */ | 208 | /* year, since the rtc epoch*/ |
275 | buf[CCR_YEAR] = BIN2BCD(tm->tm_year + 1900 - data->epoch); | 209 | buf[CCR_YEAR] = BIN2BCD(tm->tm_year % 100); |
276 | buf[CCR_WDAY] = tm->tm_wday & 0x07; | 210 | buf[CCR_WDAY] = tm->tm_wday & 0x07; |
277 | buf[CCR_Y2K] = BIN2BCD(data->epoch / 100); | 211 | buf[CCR_Y2K] = BIN2BCD(tm->tm_year / 100); |
278 | } | 212 | } |
279 | 213 | ||
280 | /* this sequence is required to unlock the chip */ | 214 | /* this sequence is required to unlock the chip */ |
281 | xfer = i2c_master_send(client, wel, 3); | 215 | if ((xfer = i2c_master_send(client, wel, 3)) != 3) { |
282 | if (xfer != 3) { | ||
283 | dev_err(&client->dev, "%s: wel - %d\n", __FUNCTION__, xfer); | 216 | dev_err(&client->dev, "%s: wel - %d\n", __FUNCTION__, xfer); |
284 | return -EIO; | 217 | return -EIO; |
285 | } | 218 | } |
286 | 219 | ||
287 | xfer = i2c_master_send(client, rwel, 3); | 220 | if ((xfer = i2c_master_send(client, rwel, 3)) != 3) { |
288 | if (xfer != 3) { | ||
289 | dev_err(&client->dev, "%s: rwel - %d\n", __FUNCTION__, xfer); | 221 | dev_err(&client->dev, "%s: rwel - %d\n", __FUNCTION__, xfer); |
290 | return -EIO; | 222 | return -EIO; |
291 | } | 223 | } |
@@ -305,8 +237,7 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, | |||
305 | }; | 237 | }; |
306 | 238 | ||
307 | /* disable further writes */ | 239 | /* disable further writes */ |
308 | xfer = i2c_master_send(client, diswe, 3); | 240 | if ((xfer = i2c_master_send(client, diswe, 3)) != 3) { |
309 | if (xfer != 3) { | ||
310 | dev_err(&client->dev, "%s: diswe - %d\n", __FUNCTION__, xfer); | 241 | dev_err(&client->dev, "%s: diswe - %d\n", __FUNCTION__, xfer); |
311 | return -EIO; | 242 | return -EIO; |
312 | } | 243 | } |
@@ -314,6 +245,20 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, | |||
314 | return 0; | 245 | return 0; |
315 | } | 246 | } |
316 | 247 | ||
248 | static int x1205_fix_osc(struct i2c_client *client) | ||
249 | { | ||
250 | int err; | ||
251 | struct rtc_time tm; | ||
252 | |||
253 | tm.tm_hour = tm.tm_min = tm.tm_sec = 0; | ||
254 | |||
255 | if ((err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE)) < 0) | ||
256 | dev_err(&client->dev, | ||
257 | "unable to restart the oscillator\n"); | ||
258 | |||
259 | return err; | ||
260 | } | ||
261 | |||
317 | static int x1205_get_dtrim(struct i2c_client *client, int *trim) | 262 | static int x1205_get_dtrim(struct i2c_client *client, int *trim) |
318 | { | 263 | { |
319 | unsigned char dtr; | 264 | unsigned char dtr; |
@@ -380,60 +325,9 @@ static int x1205_get_atrim(struct i2c_client *client, int *trim) | |||
380 | return 0; | 325 | return 0; |
381 | } | 326 | } |
382 | 327 | ||
383 | static int x1205_hctosys(struct i2c_client *client) | ||
384 | { | ||
385 | int err; | ||
386 | |||
387 | struct rtc_time tm; | ||
388 | struct timespec tv; | ||
389 | |||
390 | err = x1205_command(client, X1205_CMD_GETDATETIME, &tm); | ||
391 | |||
392 | if (err) { | ||
393 | dev_err(&client->dev, | ||
394 | "Unable to set the system clock\n"); | ||
395 | return err; | ||
396 | } | ||
397 | |||
398 | /* IMPORTANT: the RTC only stores whole seconds. It is arbitrary | ||
399 | * whether it stores the most close value or the value with partial | ||
400 | * seconds truncated. However, it is important that we use it to store | ||
401 | * the truncated value. This is because otherwise it is necessary, | ||
402 | * in an rtc sync function, to read both xtime.tv_sec and | ||
403 | * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read | ||
404 | * of >32bits is not possible. So storing the most close value would | ||
405 | * slow down the sync API. So here we have the truncated value and | ||
406 | * the best guess is to add 0.5s. | ||
407 | */ | ||
408 | |||
409 | tv.tv_nsec = NSEC_PER_SEC >> 1; | ||
410 | |||
411 | /* WARNING: this is not the C library 'mktime' call, it is a built in | ||
412 | * inline function from include/linux/time.h. It expects (requires) | ||
413 | * the month to be in the range 1-12 | ||
414 | */ | ||
415 | |||
416 | tv.tv_sec = mktime(tm.tm_year + 1900, tm.tm_mon + 1, | ||
417 | tm.tm_mday, tm.tm_hour, | ||
418 | tm.tm_min, tm.tm_sec); | ||
419 | |||
420 | do_settimeofday(&tv); | ||
421 | |||
422 | dev_info(&client->dev, | ||
423 | "setting the system clock to %d-%d-%d %d:%d:%d\n", | ||
424 | tm.tm_year + 1900, tm.tm_mon + 1, | ||
425 | tm.tm_mday, tm.tm_hour, tm.tm_min, | ||
426 | tm.tm_sec); | ||
427 | |||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | struct x1205_limit | 328 | struct x1205_limit |
432 | { | 329 | { |
433 | unsigned char reg; | 330 | unsigned char reg, mask, min, max; |
434 | unsigned char mask; | ||
435 | unsigned char min; | ||
436 | unsigned char max; | ||
437 | }; | 331 | }; |
438 | 332 | ||
439 | static int x1205_validate_client(struct i2c_client *client) | 333 | static int x1205_validate_client(struct i2c_client *client) |
@@ -477,11 +371,10 @@ static int x1205_validate_client(struct i2c_client *client) | |||
477 | { client->addr, I2C_M_RD, 1, &buf }, | 371 | { client->addr, I2C_M_RD, 1, &buf }, |
478 | }; | 372 | }; |
479 | 373 | ||
480 | xfer = i2c_transfer(client->adapter, msgs, 2); | 374 | if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) { |
481 | if (xfer != 2) { | ||
482 | dev_err(&client->adapter->dev, | 375 | dev_err(&client->adapter->dev, |
483 | "%s: could not read register %x\n", | 376 | "%s: could not read register %x\n", |
484 | __FUNCTION__, addr[1]); | 377 | __FUNCTION__, probe_zero_pattern[i]); |
485 | 378 | ||
486 | return -EIO; | 379 | return -EIO; |
487 | } | 380 | } |
@@ -489,7 +382,7 @@ static int x1205_validate_client(struct i2c_client *client) | |||
489 | if ((buf & probe_zero_pattern[i+1]) != 0) { | 382 | if ((buf & probe_zero_pattern[i+1]) != 0) { |
490 | dev_err(&client->adapter->dev, | 383 | dev_err(&client->adapter->dev, |
491 | "%s: register=%02x, zero pattern=%d, value=%x\n", | 384 | "%s: register=%02x, zero pattern=%d, value=%x\n", |
492 | __FUNCTION__, addr[1], i, buf); | 385 | __FUNCTION__, probe_zero_pattern[i], i, buf); |
493 | 386 | ||
494 | return -ENODEV; | 387 | return -ENODEV; |
495 | } | 388 | } |
@@ -506,12 +399,10 @@ static int x1205_validate_client(struct i2c_client *client) | |||
506 | { client->addr, I2C_M_RD, 1, ® }, | 399 | { client->addr, I2C_M_RD, 1, ® }, |
507 | }; | 400 | }; |
508 | 401 | ||
509 | xfer = i2c_transfer(client->adapter, msgs, 2); | 402 | if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) { |
510 | |||
511 | if (xfer != 2) { | ||
512 | dev_err(&client->adapter->dev, | 403 | dev_err(&client->adapter->dev, |
513 | "%s: could not read register %x\n", | 404 | "%s: could not read register %x\n", |
514 | __FUNCTION__, addr[1]); | 405 | __FUNCTION__, probe_limits_pattern[i].reg); |
515 | 406 | ||
516 | return -EIO; | 407 | return -EIO; |
517 | } | 408 | } |
@@ -522,7 +413,8 @@ static int x1205_validate_client(struct i2c_client *client) | |||
522 | value < probe_limits_pattern[i].min) { | 413 | value < probe_limits_pattern[i].min) { |
523 | dev_dbg(&client->adapter->dev, | 414 | dev_dbg(&client->adapter->dev, |
524 | "%s: register=%x, lim pattern=%d, value=%d\n", | 415 | "%s: register=%x, lim pattern=%d, value=%d\n", |
525 | __FUNCTION__, addr[1], i, value); | 416 | __FUNCTION__, probe_limits_pattern[i].reg, |
417 | i, value); | ||
526 | 418 | ||
527 | return -ENODEV; | 419 | return -ENODEV; |
528 | } | 420 | } |
@@ -531,37 +423,89 @@ static int x1205_validate_client(struct i2c_client *client) | |||
531 | return 0; | 423 | return 0; |
532 | } | 424 | } |
533 | 425 | ||
534 | static int x1205_attach(struct i2c_adapter *adapter) | 426 | static int x1205_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
535 | { | 427 | { |
536 | dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); | 428 | return x1205_get_datetime(to_i2c_client(dev), |
429 | &alrm->time, X1205_ALM0_BASE); | ||
430 | } | ||
537 | 431 | ||
538 | return i2c_probe(adapter, &addr_data, x1205_probe); | 432 | static int x1205_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
433 | { | ||
434 | return x1205_set_datetime(to_i2c_client(dev), | ||
435 | &alrm->time, 1, X1205_ALM0_BASE); | ||
539 | } | 436 | } |
540 | 437 | ||
541 | int x1205_direct_attach(int adapter_id, | 438 | static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm) |
542 | struct i2c_client_address_data *address_data) | ||
543 | { | 439 | { |
544 | int err; | 440 | return x1205_get_datetime(to_i2c_client(dev), |
545 | struct i2c_adapter *adapter = i2c_get_adapter(adapter_id); | 441 | tm, X1205_CCR_BASE); |
442 | } | ||
546 | 443 | ||
547 | if (adapter) { | 444 | static int x1205_rtc_set_time(struct device *dev, struct rtc_time *tm) |
548 | err = i2c_probe(adapter, | 445 | { |
549 | address_data, x1205_probe); | 446 | return x1205_set_datetime(to_i2c_client(dev), |
447 | tm, 1, X1205_CCR_BASE); | ||
448 | } | ||
550 | 449 | ||
551 | i2c_put_adapter(adapter); | 450 | static int x1205_rtc_proc(struct device *dev, struct seq_file *seq) |
451 | { | ||
452 | int err, dtrim, atrim; | ||
552 | 453 | ||
553 | return err; | 454 | seq_printf(seq, "24hr\t\t: yes\n"); |
554 | } | ||
555 | 455 | ||
556 | return -ENODEV; | 456 | if ((err = x1205_get_dtrim(to_i2c_client(dev), &dtrim)) == 0) |
457 | seq_printf(seq, "digital_trim\t: %d ppm\n", dtrim); | ||
458 | |||
459 | if ((err = x1205_get_atrim(to_i2c_client(dev), &atrim)) == 0) | ||
460 | seq_printf(seq, "analog_trim\t: %d.%02d pF\n", | ||
461 | atrim / 1000, atrim % 1000); | ||
462 | return 0; | ||
557 | } | 463 | } |
558 | 464 | ||
559 | static int x1205_probe(struct i2c_adapter *adapter, int address, int kind) | 465 | static struct rtc_class_ops x1205_rtc_ops = { |
466 | .proc = x1205_rtc_proc, | ||
467 | .read_time = x1205_rtc_read_time, | ||
468 | .set_time = x1205_rtc_set_time, | ||
469 | .read_alarm = x1205_rtc_read_alarm, | ||
470 | .set_alarm = x1205_rtc_set_alarm, | ||
471 | }; | ||
472 | |||
473 | static ssize_t x1205_sysfs_show_atrim(struct device *dev, | ||
474 | struct device_attribute *attr, char *buf) | ||
560 | { | 475 | { |
561 | struct i2c_client *client; | 476 | int atrim; |
562 | struct x1205_data *data; | 477 | |
478 | if (x1205_get_atrim(to_i2c_client(dev), &atrim) == 0) | ||
479 | return sprintf(buf, "%d.%02d pF\n", | ||
480 | atrim / 1000, atrim % 1000); | ||
481 | return 0; | ||
482 | } | ||
483 | static DEVICE_ATTR(atrim, S_IRUGO, x1205_sysfs_show_atrim, NULL); | ||
484 | |||
485 | static ssize_t x1205_sysfs_show_dtrim(struct device *dev, | ||
486 | struct device_attribute *attr, char *buf) | ||
487 | { | ||
488 | int dtrim; | ||
489 | |||
490 | if (x1205_get_dtrim(to_i2c_client(dev), &dtrim) == 0) | ||
491 | return sprintf(buf, "%d ppm\n", dtrim); | ||
492 | |||
493 | return 0; | ||
494 | } | ||
495 | static DEVICE_ATTR(dtrim, S_IRUGO, x1205_sysfs_show_dtrim, NULL); | ||
563 | 496 | ||
497 | static int x1205_attach(struct i2c_adapter *adapter) | ||
498 | { | ||
499 | dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); | ||
500 | return i2c_probe(adapter, &addr_data, x1205_probe); | ||
501 | } | ||
502 | |||
503 | static int x1205_probe(struct i2c_adapter *adapter, int address, int kind) | ||
504 | { | ||
564 | int err = 0; | 505 | int err = 0; |
506 | unsigned char sr; | ||
507 | struct i2c_client *client; | ||
508 | struct rtc_device *rtc; | ||
565 | 509 | ||
566 | dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); | 510 | dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); |
567 | 511 | ||
@@ -570,22 +514,17 @@ static int x1205_probe(struct i2c_adapter *adapter, int address, int kind) | |||
570 | goto exit; | 514 | goto exit; |
571 | } | 515 | } |
572 | 516 | ||
573 | if (!(data = kzalloc(sizeof(struct x1205_data), GFP_KERNEL))) { | 517 | if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) { |
574 | err = -ENOMEM; | 518 | err = -ENOMEM; |
575 | goto exit; | 519 | goto exit; |
576 | } | 520 | } |
577 | 521 | ||
578 | /* Initialize our structures */ | 522 | /* I2C client */ |
579 | data->epoch = 2000; | ||
580 | |||
581 | client = &data->client; | ||
582 | client->addr = address; | 523 | client->addr = address; |
583 | client->driver = &x1205_driver; | 524 | client->driver = &x1205_driver; |
584 | client->adapter = adapter; | 525 | client->adapter = adapter; |
585 | 526 | ||
586 | strlcpy(client->name, "x1205", I2C_NAME_SIZE); | 527 | strlcpy(client->name, x1205_driver.driver.name, I2C_NAME_SIZE); |
587 | |||
588 | i2c_set_clientdata(client, data); | ||
589 | 528 | ||
590 | /* Verify the chip is really an X1205 */ | 529 | /* Verify the chip is really an X1205 */ |
591 | if (kind < 0) { | 530 | if (kind < 0) { |
@@ -599,18 +538,43 @@ static int x1205_probe(struct i2c_adapter *adapter, int address, int kind) | |||
599 | if ((err = i2c_attach_client(client))) | 538 | if ((err = i2c_attach_client(client))) |
600 | goto exit_kfree; | 539 | goto exit_kfree; |
601 | 540 | ||
602 | list_add(&data->list, &x1205_clients); | ||
603 | |||
604 | dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); | 541 | dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); |
605 | 542 | ||
606 | /* If requested, set the system time */ | 543 | rtc = rtc_device_register(x1205_driver.driver.name, &client->dev, |
607 | if (hctosys) | 544 | &x1205_rtc_ops, THIS_MODULE); |
608 | x1205_hctosys(client); | 545 | |
546 | if (IS_ERR(rtc)) { | ||
547 | err = PTR_ERR(rtc); | ||
548 | dev_err(&client->dev, | ||
549 | "unable to register the class device\n"); | ||
550 | goto exit_detach; | ||
551 | } | ||
552 | |||
553 | i2c_set_clientdata(client, rtc); | ||
554 | |||
555 | /* Check for power failures and eventualy enable the osc */ | ||
556 | if ((err = x1205_get_status(client, &sr)) == 0) { | ||
557 | if (sr & X1205_SR_RTCF) { | ||
558 | dev_err(&client->dev, | ||
559 | "power failure detected, " | ||
560 | "please set the clock\n"); | ||
561 | udelay(50); | ||
562 | x1205_fix_osc(client); | ||
563 | } | ||
564 | } | ||
565 | else | ||
566 | dev_err(&client->dev, "couldn't read status\n"); | ||
567 | |||
568 | device_create_file(&client->dev, &dev_attr_atrim); | ||
569 | device_create_file(&client->dev, &dev_attr_dtrim); | ||
609 | 570 | ||
610 | return 0; | 571 | return 0; |
611 | 572 | ||
573 | exit_detach: | ||
574 | i2c_detach_client(client); | ||
575 | |||
612 | exit_kfree: | 576 | exit_kfree: |
613 | kfree(data); | 577 | kfree(client); |
614 | 578 | ||
615 | exit: | 579 | exit: |
616 | return err; | 580 | return err; |
@@ -619,61 +583,21 @@ exit: | |||
619 | static int x1205_detach(struct i2c_client *client) | 583 | static int x1205_detach(struct i2c_client *client) |
620 | { | 584 | { |
621 | int err; | 585 | int err; |
622 | struct x1205_data *data = i2c_get_clientdata(client); | 586 | struct rtc_device *rtc = i2c_get_clientdata(client); |
623 | 587 | ||
624 | dev_dbg(&client->dev, "%s\n", __FUNCTION__); | 588 | dev_dbg(&client->dev, "%s\n", __FUNCTION__); |
625 | 589 | ||
590 | if (rtc) | ||
591 | rtc_device_unregister(rtc); | ||
592 | |||
626 | if ((err = i2c_detach_client(client))) | 593 | if ((err = i2c_detach_client(client))) |
627 | return err; | 594 | return err; |
628 | 595 | ||
629 | list_del(&data->list); | 596 | kfree(client); |
630 | |||
631 | kfree(data); | ||
632 | 597 | ||
633 | return 0; | 598 | return 0; |
634 | } | 599 | } |
635 | 600 | ||
636 | static int x1205_command(struct i2c_client *client, unsigned int cmd, | ||
637 | void *param) | ||
638 | { | ||
639 | if (param == NULL) | ||
640 | return -EINVAL; | ||
641 | |||
642 | if (!capable(CAP_SYS_TIME)) | ||
643 | return -EACCES; | ||
644 | |||
645 | dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd); | ||
646 | |||
647 | switch (cmd) { | ||
648 | case X1205_CMD_GETDATETIME: | ||
649 | return x1205_get_datetime(client, param, X1205_CCR_BASE); | ||
650 | |||
651 | case X1205_CMD_SETTIME: | ||
652 | return x1205_set_datetime(client, param, 0, | ||
653 | X1205_CCR_BASE); | ||
654 | |||
655 | case X1205_CMD_SETDATETIME: | ||
656 | return x1205_set_datetime(client, param, 1, | ||
657 | X1205_CCR_BASE); | ||
658 | |||
659 | case X1205_CMD_GETALARM: | ||
660 | return x1205_get_datetime(client, param, X1205_ALM0_BASE); | ||
661 | |||
662 | case X1205_CMD_SETALARM: | ||
663 | return x1205_set_datetime(client, param, 1, | ||
664 | X1205_ALM0_BASE); | ||
665 | |||
666 | case X1205_CMD_GETDTRIM: | ||
667 | return x1205_get_dtrim(client, param); | ||
668 | |||
669 | case X1205_CMD_GETATRIM: | ||
670 | return x1205_get_atrim(client, param); | ||
671 | |||
672 | default: | ||
673 | return -EINVAL; | ||
674 | } | ||
675 | } | ||
676 | |||
677 | static int __init x1205_init(void) | 601 | static int __init x1205_init(void) |
678 | { | 602 | { |
679 | return i2c_add_driver(&x1205_driver); | 603 | return i2c_add_driver(&x1205_driver); |
@@ -685,14 +609,11 @@ static void __exit x1205_exit(void) | |||
685 | } | 609 | } |
686 | 610 | ||
687 | MODULE_AUTHOR( | 611 | MODULE_AUTHOR( |
688 | "Karen Spearel <kas11@tampabay.rr.com>, " | 612 | "Karen Spearel <kas111 at gmail dot com>, " |
689 | "Alessandro Zummo <a.zummo@towertech.it>"); | 613 | "Alessandro Zummo <a.zummo@towertech.it>"); |
690 | MODULE_DESCRIPTION("Xicor X1205 RTC driver"); | 614 | MODULE_DESCRIPTION("Xicor/Intersil X1205 RTC driver"); |
691 | MODULE_LICENSE("GPL"); | 615 | MODULE_LICENSE("GPL"); |
692 | MODULE_VERSION(DRV_VERSION); | 616 | MODULE_VERSION(DRV_VERSION); |
693 | 617 | ||
694 | EXPORT_SYMBOL_GPL(x1205_do_command); | ||
695 | EXPORT_SYMBOL_GPL(x1205_direct_attach); | ||
696 | |||
697 | module_init(x1205_init); | 618 | module_init(x1205_init); |
698 | module_exit(x1205_exit); | 619 | module_exit(x1205_exit); |
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 62e3cda859af..7f7013e80a88 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c | |||
@@ -671,7 +671,7 @@ static struct file_operations gdth_fops = { | |||
671 | static struct notifier_block gdth_notifier = { | 671 | static struct notifier_block gdth_notifier = { |
672 | gdth_halt, NULL, 0 | 672 | gdth_halt, NULL, 0 |
673 | }; | 673 | }; |
674 | 674 | static int notifier_disabled = 0; | |
675 | 675 | ||
676 | static void gdth_delay(int milliseconds) | 676 | static void gdth_delay(int milliseconds) |
677 | { | 677 | { |
@@ -4595,13 +4595,13 @@ static int __init gdth_detect(struct scsi_host_template *shtp) | |||
4595 | add_timer(&gdth_timer); | 4595 | add_timer(&gdth_timer); |
4596 | #endif | 4596 | #endif |
4597 | major = register_chrdev(0,"gdth",&gdth_fops); | 4597 | major = register_chrdev(0,"gdth",&gdth_fops); |
4598 | notifier_disabled = 0; | ||
4598 | register_reboot_notifier(&gdth_notifier); | 4599 | register_reboot_notifier(&gdth_notifier); |
4599 | } | 4600 | } |
4600 | gdth_polling = FALSE; | 4601 | gdth_polling = FALSE; |
4601 | return gdth_ctr_vcount; | 4602 | return gdth_ctr_vcount; |
4602 | } | 4603 | } |
4603 | 4604 | ||
4604 | |||
4605 | static int gdth_release(struct Scsi_Host *shp) | 4605 | static int gdth_release(struct Scsi_Host *shp) |
4606 | { | 4606 | { |
4607 | int hanum; | 4607 | int hanum; |
@@ -5632,10 +5632,14 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) | |||
5632 | char cmnd[MAX_COMMAND_SIZE]; | 5632 | char cmnd[MAX_COMMAND_SIZE]; |
5633 | #endif | 5633 | #endif |
5634 | 5634 | ||
5635 | if (notifier_disabled) | ||
5636 | return NOTIFY_OK; | ||
5637 | |||
5635 | TRACE2(("gdth_halt() event %d\n",(int)event)); | 5638 | TRACE2(("gdth_halt() event %d\n",(int)event)); |
5636 | if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF) | 5639 | if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF) |
5637 | return NOTIFY_DONE; | 5640 | return NOTIFY_DONE; |
5638 | 5641 | ||
5642 | notifier_disabled = 1; | ||
5639 | printk("GDT-HA: Flushing all host drives .. "); | 5643 | printk("GDT-HA: Flushing all host drives .. "); |
5640 | for (hanum = 0; hanum < gdth_ctr_count; ++hanum) { | 5644 | for (hanum = 0; hanum < gdth_ctr_count; ++hanum) { |
5641 | gdth_flush(hanum); | 5645 | gdth_flush(hanum); |
@@ -5679,7 +5683,6 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf) | |||
5679 | #ifdef GDTH_STATISTICS | 5683 | #ifdef GDTH_STATISTICS |
5680 | del_timer(&gdth_timer); | 5684 | del_timer(&gdth_timer); |
5681 | #endif | 5685 | #endif |
5682 | unregister_reboot_notifier(&gdth_notifier); | ||
5683 | return NOTIFY_OK; | 5686 | return NOTIFY_OK; |
5684 | } | 5687 | } |
5685 | 5688 | ||
diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c index 4b55285de9a0..fe0ed54fa0ae 100644 --- a/drivers/usb/core/notify.c +++ b/drivers/usb/core/notify.c | |||
@@ -16,57 +16,7 @@ | |||
16 | #include <linux/mutex.h> | 16 | #include <linux/mutex.h> |
17 | #include "usb.h" | 17 | #include "usb.h" |
18 | 18 | ||
19 | 19 | static BLOCKING_NOTIFIER_HEAD(usb_notifier_list); | |
20 | static struct notifier_block *usb_notifier_list; | ||
21 | static DEFINE_MUTEX(usb_notifier_lock); | ||
22 | |||
23 | static void usb_notifier_chain_register(struct notifier_block **list, | ||
24 | struct notifier_block *n) | ||
25 | { | ||
26 | mutex_lock(&usb_notifier_lock); | ||
27 | while (*list) { | ||
28 | if (n->priority > (*list)->priority) | ||
29 | break; | ||
30 | list = &((*list)->next); | ||
31 | } | ||
32 | n->next = *list; | ||
33 | *list = n; | ||
34 | mutex_unlock(&usb_notifier_lock); | ||
35 | } | ||
36 | |||
37 | static void usb_notifier_chain_unregister(struct notifier_block **nl, | ||
38 | struct notifier_block *n) | ||
39 | { | ||
40 | mutex_lock(&usb_notifier_lock); | ||
41 | while ((*nl)!=NULL) { | ||
42 | if ((*nl)==n) { | ||
43 | *nl = n->next; | ||
44 | goto exit; | ||
45 | } | ||
46 | nl=&((*nl)->next); | ||
47 | } | ||
48 | exit: | ||
49 | mutex_unlock(&usb_notifier_lock); | ||
50 | } | ||
51 | |||
52 | static int usb_notifier_call_chain(struct notifier_block **n, | ||
53 | unsigned long val, void *v) | ||
54 | { | ||
55 | int ret=NOTIFY_DONE; | ||
56 | struct notifier_block *nb = *n; | ||
57 | |||
58 | mutex_lock(&usb_notifier_lock); | ||
59 | while (nb) { | ||
60 | ret = nb->notifier_call(nb,val,v); | ||
61 | if (ret&NOTIFY_STOP_MASK) { | ||
62 | goto exit; | ||
63 | } | ||
64 | nb = nb->next; | ||
65 | } | ||
66 | exit: | ||
67 | mutex_unlock(&usb_notifier_lock); | ||
68 | return ret; | ||
69 | } | ||
70 | 20 | ||
71 | /** | 21 | /** |
72 | * usb_register_notify - register a notifier callback whenever a usb change happens | 22 | * usb_register_notify - register a notifier callback whenever a usb change happens |
@@ -76,7 +26,7 @@ exit: | |||
76 | */ | 26 | */ |
77 | void usb_register_notify(struct notifier_block *nb) | 27 | void usb_register_notify(struct notifier_block *nb) |
78 | { | 28 | { |
79 | usb_notifier_chain_register(&usb_notifier_list, nb); | 29 | blocking_notifier_chain_register(&usb_notifier_list, nb); |
80 | } | 30 | } |
81 | EXPORT_SYMBOL_GPL(usb_register_notify); | 31 | EXPORT_SYMBOL_GPL(usb_register_notify); |
82 | 32 | ||
@@ -89,27 +39,28 @@ EXPORT_SYMBOL_GPL(usb_register_notify); | |||
89 | */ | 39 | */ |
90 | void usb_unregister_notify(struct notifier_block *nb) | 40 | void usb_unregister_notify(struct notifier_block *nb) |
91 | { | 41 | { |
92 | usb_notifier_chain_unregister(&usb_notifier_list, nb); | 42 | blocking_notifier_chain_unregister(&usb_notifier_list, nb); |
93 | } | 43 | } |
94 | EXPORT_SYMBOL_GPL(usb_unregister_notify); | 44 | EXPORT_SYMBOL_GPL(usb_unregister_notify); |
95 | 45 | ||
96 | 46 | ||
97 | void usb_notify_add_device(struct usb_device *udev) | 47 | void usb_notify_add_device(struct usb_device *udev) |
98 | { | 48 | { |
99 | usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev); | 49 | blocking_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev); |
100 | } | 50 | } |
101 | 51 | ||
102 | void usb_notify_remove_device(struct usb_device *udev) | 52 | void usb_notify_remove_device(struct usb_device *udev) |
103 | { | 53 | { |
104 | usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_REMOVE, udev); | 54 | blocking_notifier_call_chain(&usb_notifier_list, |
55 | USB_DEVICE_REMOVE, udev); | ||
105 | } | 56 | } |
106 | 57 | ||
107 | void usb_notify_add_bus(struct usb_bus *ubus) | 58 | void usb_notify_add_bus(struct usb_bus *ubus) |
108 | { | 59 | { |
109 | usb_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus); | 60 | blocking_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus); |
110 | } | 61 | } |
111 | 62 | ||
112 | void usb_notify_remove_bus(struct usb_bus *ubus) | 63 | void usb_notify_remove_bus(struct usb_bus *ubus) |
113 | { | 64 | { |
114 | usb_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus); | 65 | blocking_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus); |
115 | } | 66 | } |
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index fdebd60a3250..22e9d696fdd2 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -70,6 +70,22 @@ config FB_MACMODES | |||
70 | depends on FB | 70 | depends on FB |
71 | default n | 71 | default n |
72 | 72 | ||
73 | config FB_FIRMWARE_EDID | ||
74 | bool "Enable firmware EDID" | ||
75 | depends on FB | ||
76 | default y | ||
77 | ---help--- | ||
78 | This enables access to the EDID transferred from the firmware. | ||
79 | On the i386, this is from the Video BIOS. Enable this if DDC/I2C | ||
80 | transfers do not work for your driver and if you are using | ||
81 | nvidiafb, i810fb or savagefb. | ||
82 | |||
83 | In general, choosing Y for this option is safe. If you | ||
84 | experience extremely long delays while booting before you get | ||
85 | something on your display, try setting this to N. Matrox cards in | ||
86 | combination with certain motherboards and monitors are known to | ||
87 | suffer from this problem. | ||
88 | |||
73 | config FB_MODE_HELPERS | 89 | config FB_MODE_HELPERS |
74 | bool "Enable Video Mode Handling Helpers" | 90 | bool "Enable Video Mode Handling Helpers" |
75 | depends on FB | 91 | depends on FB |
@@ -1202,6 +1218,17 @@ config FB_AU1100 | |||
1202 | bool "Au1100 LCD Driver" | 1218 | bool "Au1100 LCD Driver" |
1203 | depends on (FB = y) && EXPERIMENTAL && PCI && MIPS && MIPS_PB1100=y | 1219 | depends on (FB = y) && EXPERIMENTAL && PCI && MIPS && MIPS_PB1100=y |
1204 | 1220 | ||
1221 | config FB_AU1200 | ||
1222 | bool "Au1200 LCD Driver" | ||
1223 | depends on FB && MIPS && SOC_AU1200 | ||
1224 | select FB_CFB_FILLRECT | ||
1225 | select FB_CFB_COPYAREA | ||
1226 | select FB_CFB_IMAGEBLIT | ||
1227 | help | ||
1228 | This is the framebuffer driver for the AMD Au1200 SOC. It can drive | ||
1229 | various panels and CRTs by passing in kernel cmd line option | ||
1230 | au1200fb:panel=<name>. | ||
1231 | |||
1205 | source "drivers/video/geode/Kconfig" | 1232 | source "drivers/video/geode/Kconfig" |
1206 | 1233 | ||
1207 | config FB_FFB | 1234 | config FB_FFB |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index aa434e725c0d..cb90218515ac 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -86,6 +86,7 @@ obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o | |||
86 | obj-$(CONFIG_FB_PXA) += pxafb.o | 86 | obj-$(CONFIG_FB_PXA) += pxafb.o |
87 | obj-$(CONFIG_FB_W100) += w100fb.o | 87 | obj-$(CONFIG_FB_W100) += w100fb.o |
88 | obj-$(CONFIG_FB_AU1100) += au1100fb.o | 88 | obj-$(CONFIG_FB_AU1100) += au1100fb.o |
89 | obj-$(CONFIG_FB_AU1200) += au1200fb.o | ||
89 | obj-$(CONFIG_FB_PMAG_AA) += pmag-aa-fb.o | 90 | obj-$(CONFIG_FB_PMAG_AA) += pmag-aa-fb.o |
90 | obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o | 91 | obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o |
91 | obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o | 92 | obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o |
diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index 76448d6ae896..98baecccb3fd 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c | |||
@@ -1308,7 +1308,7 @@ static int __init acornfb_probe(struct platform_device *dev) | |||
1308 | /* | 1308 | /* |
1309 | * Try to select a suitable default mode | 1309 | * Try to select a suitable default mode |
1310 | */ | 1310 | */ |
1311 | for (i = 0; i < sizeof(modedb) / sizeof(*modedb); i++) { | 1311 | for (i = 0; i < ARRAY_SIZE(modedb); i++) { |
1312 | unsigned long hs; | 1312 | unsigned long hs; |
1313 | 1313 | ||
1314 | hs = modedb[i].refresh * | 1314 | hs = modedb[i].refresh * |
@@ -1380,7 +1380,7 @@ static int __init acornfb_probe(struct platform_device *dev) | |||
1380 | */ | 1380 | */ |
1381 | free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE); | 1381 | free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE); |
1382 | #endif | 1382 | #endif |
1383 | 1383 | ||
1384 | fb_info.fix.smem_len = size; | 1384 | fb_info.fix.smem_len = size; |
1385 | current_par.palette_size = VIDC_PALETTE_SIZE; | 1385 | current_par.palette_size = VIDC_PALETTE_SIZE; |
1386 | 1386 | ||
@@ -1391,7 +1391,7 @@ static int __init acornfb_probe(struct platform_device *dev) | |||
1391 | */ | 1391 | */ |
1392 | do { | 1392 | do { |
1393 | rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb, | 1393 | rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb, |
1394 | sizeof(modedb) / sizeof(*modedb), | 1394 | ARRAY_SIZE(modedb), |
1395 | &acornfb_default_mode, DEFAULT_BPP); | 1395 | &acornfb_default_mode, DEFAULT_BPP); |
1396 | /* | 1396 | /* |
1397 | * If we found an exact match, all ok. | 1397 | * If we found an exact match, all ok. |
@@ -1408,7 +1408,7 @@ static int __init acornfb_probe(struct platform_device *dev) | |||
1408 | break; | 1408 | break; |
1409 | 1409 | ||
1410 | rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb, | 1410 | rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb, |
1411 | sizeof(modedb) / sizeof(*modedb), | 1411 | ARRAY_SIZE(modedb), |
1412 | &acornfb_default_mode, DEFAULT_BPP); | 1412 | &acornfb_default_mode, DEFAULT_BPP); |
1413 | if (rc) | 1413 | if (rc) |
1414 | break; | 1414 | break; |
diff --git a/drivers/video/asiliantfb.c b/drivers/video/asiliantfb.c index c924d81f7978..29f9f0dfe3b4 100644 --- a/drivers/video/asiliantfb.c +++ b/drivers/video/asiliantfb.c | |||
@@ -353,8 +353,6 @@ struct chips_init_reg { | |||
353 | unsigned char data; | 353 | unsigned char data; |
354 | }; | 354 | }; |
355 | 355 | ||
356 | #define N_ELTS(x) (sizeof(x) / sizeof(x[0])) | ||
357 | |||
358 | static struct chips_init_reg chips_init_sr[] = | 356 | static struct chips_init_reg chips_init_sr[] = |
359 | { | 357 | { |
360 | {0x00, 0x03}, /* Reset register */ | 358 | {0x00, 0x03}, /* Reset register */ |
@@ -460,22 +458,22 @@ static void __devinit chips_hw_init(struct fb_info *p) | |||
460 | { | 458 | { |
461 | int i; | 459 | int i; |
462 | 460 | ||
463 | for (i = 0; i < N_ELTS(chips_init_xr); ++i) | 461 | for (i = 0; i < ARRAY_SIZE(chips_init_xr); ++i) |
464 | write_xr(chips_init_xr[i].addr, chips_init_xr[i].data); | 462 | write_xr(chips_init_xr[i].addr, chips_init_xr[i].data); |
465 | write_xr(0x81, 0x12); | 463 | write_xr(0x81, 0x12); |
466 | write_xr(0x82, 0x08); | 464 | write_xr(0x82, 0x08); |
467 | write_xr(0x20, 0x00); | 465 | write_xr(0x20, 0x00); |
468 | for (i = 0; i < N_ELTS(chips_init_sr); ++i) | 466 | for (i = 0; i < ARRAY_SIZE(chips_init_sr); ++i) |
469 | write_sr(chips_init_sr[i].addr, chips_init_sr[i].data); | 467 | write_sr(chips_init_sr[i].addr, chips_init_sr[i].data); |
470 | for (i = 0; i < N_ELTS(chips_init_gr); ++i) | 468 | for (i = 0; i < ARRAY_SIZE(chips_init_gr); ++i) |
471 | write_gr(chips_init_gr[i].addr, chips_init_gr[i].data); | 469 | write_gr(chips_init_gr[i].addr, chips_init_gr[i].data); |
472 | for (i = 0; i < N_ELTS(chips_init_ar); ++i) | 470 | for (i = 0; i < ARRAY_SIZE(chips_init_ar); ++i) |
473 | write_ar(chips_init_ar[i].addr, chips_init_ar[i].data); | 471 | write_ar(chips_init_ar[i].addr, chips_init_ar[i].data); |
474 | /* Enable video output in attribute index register */ | 472 | /* Enable video output in attribute index register */ |
475 | writeb(0x20, mmio_base + 0x780); | 473 | writeb(0x20, mmio_base + 0x780); |
476 | for (i = 0; i < N_ELTS(chips_init_cr); ++i) | 474 | for (i = 0; i < ARRAY_SIZE(chips_init_cr); ++i) |
477 | write_cr(chips_init_cr[i].addr, chips_init_cr[i].data); | 475 | write_cr(chips_init_cr[i].addr, chips_init_cr[i].data); |
478 | for (i = 0; i < N_ELTS(chips_init_fr); ++i) | 476 | for (i = 0; i < ARRAY_SIZE(chips_init_fr); ++i) |
479 | write_fr(chips_init_fr[i].addr, chips_init_fr[i].data); | 477 | write_fr(chips_init_fr[i].addr, chips_init_fr[i].data); |
480 | } | 478 | } |
481 | 479 | ||
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 620c9a934e0e..821c6da8e42c 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c | |||
@@ -1725,9 +1725,9 @@ static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id * | |||
1725 | strcpy(video_card, "Rage128 XX "); | 1725 | strcpy(video_card, "Rage128 XX "); |
1726 | video_card[8] = ent->device >> 8; | 1726 | video_card[8] = ent->device >> 8; |
1727 | video_card[9] = ent->device & 0xFF; | 1727 | video_card[9] = ent->device & 0xFF; |
1728 | 1728 | ||
1729 | /* range check to make sure */ | 1729 | /* range check to make sure */ |
1730 | if (ent->driver_data < (sizeof(r128_family)/sizeof(char *))) | 1730 | if (ent->driver_data < ARRAY_SIZE(r128_family)) |
1731 | strncat(video_card, r128_family[ent->driver_data], sizeof(video_card)); | 1731 | strncat(video_card, r128_family[ent->driver_data], sizeof(video_card)); |
1732 | 1732 | ||
1733 | printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev); | 1733 | printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev); |
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 485be386a8ff..e799fcca365a 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c | |||
@@ -434,7 +434,7 @@ static int __devinit correct_chipset(struct atyfb_par *par) | |||
434 | const char *name; | 434 | const char *name; |
435 | int i; | 435 | int i; |
436 | 436 | ||
437 | for (i = sizeof(aty_chips) / sizeof(*aty_chips) - 1; i >= 0; i--) | 437 | for (i = ARRAY_SIZE(aty_chips) - 1; i >= 0; i--) |
438 | if (par->pci_id == aty_chips[i].pci_id) | 438 | if (par->pci_id == aty_chips[i].pci_id) |
439 | break; | 439 | break; |
440 | 440 | ||
@@ -2168,10 +2168,10 @@ static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk) | |||
2168 | 2168 | ||
2169 | if (IS_XL(par->pci_id) || IS_MOBILITY(par->pci_id)) { | 2169 | if (IS_XL(par->pci_id) || IS_MOBILITY(par->pci_id)) { |
2170 | refresh_tbl = ragexl_tbl; | 2170 | refresh_tbl = ragexl_tbl; |
2171 | size = sizeof(ragexl_tbl)/sizeof(int); | 2171 | size = ARRAY_SIZE(ragexl_tbl); |
2172 | } else { | 2172 | } else { |
2173 | refresh_tbl = ragepro_tbl; | 2173 | refresh_tbl = ragepro_tbl; |
2174 | size = sizeof(ragepro_tbl)/sizeof(int); | 2174 | size = ARRAY_SIZE(ragepro_tbl); |
2175 | } | 2175 | } |
2176 | 2176 | ||
2177 | for (i=0; i < size; i++) { | 2177 | for (i=0; i < size; i++) { |
@@ -2298,6 +2298,10 @@ static int __init aty_init(struct fb_info *info, const char *name) | |||
2298 | case CLK_ATI18818_1: | 2298 | case CLK_ATI18818_1: |
2299 | par->pll_ops = &aty_pll_ati18818_1; | 2299 | par->pll_ops = &aty_pll_ati18818_1; |
2300 | break; | 2300 | break; |
2301 | case CLK_IBMRGB514: | ||
2302 | par->pll_ops = &aty_pll_ibm514; | ||
2303 | break; | ||
2304 | #if 0 /* dead code */ | ||
2301 | case CLK_STG1703: | 2305 | case CLK_STG1703: |
2302 | par->pll_ops = &aty_pll_stg1703; | 2306 | par->pll_ops = &aty_pll_stg1703; |
2303 | break; | 2307 | break; |
@@ -2307,9 +2311,7 @@ static int __init aty_init(struct fb_info *info, const char *name) | |||
2307 | case CLK_ATT20C408: | 2311 | case CLK_ATT20C408: |
2308 | par->pll_ops = &aty_pll_att20c408; | 2312 | par->pll_ops = &aty_pll_att20c408; |
2309 | break; | 2313 | break; |
2310 | case CLK_IBMRGB514: | 2314 | #endif |
2311 | par->pll_ops = &aty_pll_ibm514; | ||
2312 | break; | ||
2313 | default: | 2315 | default: |
2314 | PRINTKI("aty_init: CLK type not implemented yet!"); | 2316 | PRINTKI("aty_init: CLK type not implemented yet!"); |
2315 | par->pll_ops = &aty_pll_unsupported; | 2317 | par->pll_ops = &aty_pll_unsupported; |
@@ -3397,7 +3399,7 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi | |||
3397 | struct atyfb_par *par; | 3399 | struct atyfb_par *par; |
3398 | int i, rc = -ENOMEM; | 3400 | int i, rc = -ENOMEM; |
3399 | 3401 | ||
3400 | for (i = sizeof(aty_chips) / sizeof(*aty_chips) - 1; i >= 0; i--) | 3402 | for (i = ARRAY_SIZE(aty_chips); i >= 0; i--) |
3401 | if (pdev->device == aty_chips[i].pci_id) | 3403 | if (pdev->device == aty_chips[i].pci_id) |
3402 | break; | 3404 | break; |
3403 | 3405 | ||
diff --git a/drivers/video/aty/mach64_gx.c b/drivers/video/aty/mach64_gx.c index 01fdff79483b..2045639cb671 100644 --- a/drivers/video/aty/mach64_gx.c +++ b/drivers/video/aty/mach64_gx.c | |||
@@ -149,8 +149,7 @@ static int aty_var_to_pll_514(const struct fb_info *info, u32 vclk_per, | |||
149 | }; | 149 | }; |
150 | int i; | 150 | int i; |
151 | 151 | ||
152 | for (i = 0; i < sizeof(RGB514_clocks) / sizeof(*RGB514_clocks); | 152 | for (i = 0; i < ARRAY_SIZE(RGB514_clocks); i++) |
153 | i++) | ||
154 | if (vclk_per <= RGB514_clocks[i].limit) { | 153 | if (vclk_per <= RGB514_clocks[i].limit) { |
155 | pll->ibm514.m = RGB514_clocks[i].m; | 154 | pll->ibm514.m = RGB514_clocks[i].m; |
156 | pll->ibm514.n = RGB514_clocks[i].n; | 155 | pll->ibm514.n = RGB514_clocks[i].n; |
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index c9f0c5a07e6e..9a6b5b39b88e 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c | |||
@@ -1067,7 +1067,7 @@ static int radeon_setcolreg (unsigned regno, unsigned red, unsigned green, | |||
1067 | 1067 | ||
1068 | 1068 | ||
1069 | if (regno > 255) | 1069 | if (regno > 255) |
1070 | return 1; | 1070 | return -EINVAL; |
1071 | 1071 | ||
1072 | red >>= 8; | 1072 | red >>= 8; |
1073 | green >>= 8; | 1073 | green >>= 8; |
@@ -1086,9 +1086,9 @@ static int radeon_setcolreg (unsigned regno, unsigned red, unsigned green, | |||
1086 | pindex = regno * 8; | 1086 | pindex = regno * 8; |
1087 | 1087 | ||
1088 | if (rinfo->depth == 16 && regno > 63) | 1088 | if (rinfo->depth == 16 && regno > 63) |
1089 | return 1; | 1089 | return -EINVAL; |
1090 | if (rinfo->depth == 15 && regno > 31) | 1090 | if (rinfo->depth == 15 && regno > 31) |
1091 | return 1; | 1091 | return -EINVAL; |
1092 | 1092 | ||
1093 | /* For 565, the green component is mixed one order | 1093 | /* For 565, the green component is mixed one order |
1094 | * below | 1094 | * below |
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c new file mode 100644 index 000000000000..b367de30b98c --- /dev/null +++ b/drivers/video/au1200fb.c | |||
@@ -0,0 +1,3844 @@ | |||
1 | /* | ||
2 | * BRIEF MODULE DESCRIPTION | ||
3 | * Au1200 LCD Driver. | ||
4 | * | ||
5 | * Copyright 2004-2005 AMD | ||
6 | * Author: AMD | ||
7 | * | ||
8 | * Based on: | ||
9 | * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device | ||
10 | * Created 28 Dec 1997 by Geert Uytterhoeven | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | * | ||
17 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
19 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
20 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
23 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
24 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
27 | * | ||
28 | * You should have received a copy of the GNU General Public License along | ||
29 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
30 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
31 | */ | ||
32 | |||
33 | #include <linux/module.h> | ||
34 | #include <linux/platform_device.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/errno.h> | ||
37 | #include <linux/string.h> | ||
38 | #include <linux/mm.h> | ||
39 | #include <linux/fb.h> | ||
40 | #include <linux/init.h> | ||
41 | #include <linux/interrupt.h> | ||
42 | #include <linux/ctype.h> | ||
43 | #include <linux/dma-mapping.h> | ||
44 | |||
45 | #include <asm/mach-au1x00/au1000.h> | ||
46 | #include "au1200fb.h" | ||
47 | |||
48 | #ifdef CONFIG_PM | ||
49 | #include <asm/mach-au1x00/au1xxx_pm.h> | ||
50 | #endif | ||
51 | |||
52 | #ifndef CONFIG_FB_AU1200_DEVS | ||
53 | #define CONFIG_FB_AU1200_DEVS 4 | ||
54 | #endif | ||
55 | |||
56 | #define DRIVER_NAME "au1200fb" | ||
57 | #define DRIVER_DESC "LCD controller driver for AU1200 processors" | ||
58 | |||
59 | #define DEBUG 1 | ||
60 | |||
61 | #define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg) | ||
62 | #define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg) | ||
63 | #define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg) | ||
64 | |||
65 | #if DEBUG | ||
66 | #define print_dbg(f, arg...) printk(KERN_DEBUG __FILE__ ": " f "\n", ## arg) | ||
67 | #else | ||
68 | #define print_dbg(f, arg...) do {} while (0) | ||
69 | #endif | ||
70 | |||
71 | |||
72 | #define AU1200_LCD_FB_IOCTL 0x46FF | ||
73 | |||
74 | #define AU1200_LCD_SET_SCREEN 1 | ||
75 | #define AU1200_LCD_GET_SCREEN 2 | ||
76 | #define AU1200_LCD_SET_WINDOW 3 | ||
77 | #define AU1200_LCD_GET_WINDOW 4 | ||
78 | #define AU1200_LCD_SET_PANEL 5 | ||
79 | #define AU1200_LCD_GET_PANEL 6 | ||
80 | |||
81 | #define SCREEN_SIZE (1<< 1) | ||
82 | #define SCREEN_BACKCOLOR (1<< 2) | ||
83 | #define SCREEN_BRIGHTNESS (1<< 3) | ||
84 | #define SCREEN_COLORKEY (1<< 4) | ||
85 | #define SCREEN_MASK (1<< 5) | ||
86 | |||
87 | struct au1200_lcd_global_regs_t { | ||
88 | unsigned int flags; | ||
89 | unsigned int xsize; | ||
90 | unsigned int ysize; | ||
91 | unsigned int backcolor; | ||
92 | unsigned int brightness; | ||
93 | unsigned int colorkey; | ||
94 | unsigned int mask; | ||
95 | unsigned int panel_choice; | ||
96 | char panel_desc[80]; | ||
97 | |||
98 | }; | ||
99 | |||
100 | #define WIN_POSITION (1<< 0) | ||
101 | #define WIN_ALPHA_COLOR (1<< 1) | ||
102 | #define WIN_ALPHA_MODE (1<< 2) | ||
103 | #define WIN_PRIORITY (1<< 3) | ||
104 | #define WIN_CHANNEL (1<< 4) | ||
105 | #define WIN_BUFFER_FORMAT (1<< 5) | ||
106 | #define WIN_COLOR_ORDER (1<< 6) | ||
107 | #define WIN_PIXEL_ORDER (1<< 7) | ||
108 | #define WIN_SIZE (1<< 8) | ||
109 | #define WIN_COLORKEY_MODE (1<< 9) | ||
110 | #define WIN_DOUBLE_BUFFER_MODE (1<< 10) | ||
111 | #define WIN_RAM_ARRAY_MODE (1<< 11) | ||
112 | #define WIN_BUFFER_SCALE (1<< 12) | ||
113 | #define WIN_ENABLE (1<< 13) | ||
114 | |||
115 | struct au1200_lcd_window_regs_t { | ||
116 | unsigned int flags; | ||
117 | unsigned int xpos; | ||
118 | unsigned int ypos; | ||
119 | unsigned int alpha_color; | ||
120 | unsigned int alpha_mode; | ||
121 | unsigned int priority; | ||
122 | unsigned int channel; | ||
123 | unsigned int buffer_format; | ||
124 | unsigned int color_order; | ||
125 | unsigned int pixel_order; | ||
126 | unsigned int xsize; | ||
127 | unsigned int ysize; | ||
128 | unsigned int colorkey_mode; | ||
129 | unsigned int double_buffer_mode; | ||
130 | unsigned int ram_array_mode; | ||
131 | unsigned int xscale; | ||
132 | unsigned int yscale; | ||
133 | unsigned int enable; | ||
134 | }; | ||
135 | |||
136 | |||
137 | struct au1200_lcd_iodata_t { | ||
138 | unsigned int subcmd; | ||
139 | struct au1200_lcd_global_regs_t global; | ||
140 | struct au1200_lcd_window_regs_t window; | ||
141 | }; | ||
142 | |||
143 | #if defined(__BIG_ENDIAN) | ||
144 | #define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_11 | ||
145 | #else | ||
146 | #define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_00 | ||
147 | #endif | ||
148 | #define LCD_CONTROL_DEFAULT_SBPPF LCD_CONTROL_SBPPF_565 | ||
149 | |||
150 | /* Private, per-framebuffer management information (independent of the panel itself) */ | ||
151 | struct au1200fb_device { | ||
152 | struct fb_info fb_info; /* FB driver info record */ | ||
153 | |||
154 | int plane; | ||
155 | unsigned char* fb_mem; /* FrameBuffer memory map */ | ||
156 | unsigned int fb_len; | ||
157 | dma_addr_t fb_phys; | ||
158 | }; | ||
159 | |||
160 | static struct au1200fb_device _au1200fb_devices[CONFIG_FB_AU1200_DEVS]; | ||
161 | /********************************************************************/ | ||
162 | |||
163 | /* LCD controller restrictions */ | ||
164 | #define AU1200_LCD_MAX_XRES 1280 | ||
165 | #define AU1200_LCD_MAX_YRES 1024 | ||
166 | #define AU1200_LCD_MAX_BPP 32 | ||
167 | #define AU1200_LCD_MAX_CLK 96000000 /* fixme: this needs to go away ? */ | ||
168 | #define AU1200_LCD_NBR_PALETTE_ENTRIES 256 | ||
169 | |||
170 | /* Default number of visible screen buffer to allocate */ | ||
171 | #define AU1200FB_NBR_VIDEO_BUFFERS 1 | ||
172 | |||
173 | /********************************************************************/ | ||
174 | |||
175 | static struct au1200_lcd *lcd = (struct au1200_lcd *) AU1200_LCD_ADDR; | ||
176 | static int window_index = 2; /* default is zero */ | ||
177 | static int panel_index = 2; /* default is zero */ | ||
178 | static struct window_settings *win; | ||
179 | static struct panel_settings *panel; | ||
180 | static int noblanking = 1; | ||
181 | static int nohwcursor = 0; | ||
182 | |||
183 | struct window_settings { | ||
184 | unsigned char name[64]; | ||
185 | uint32 mode_backcolor; | ||
186 | uint32 mode_colorkey; | ||
187 | uint32 mode_colorkeymsk; | ||
188 | struct { | ||
189 | int xres; | ||
190 | int yres; | ||
191 | int xpos; | ||
192 | int ypos; | ||
193 | uint32 mode_winctrl1; /* winctrl1[FRM,CCO,PO,PIPE] */ | ||
194 | uint32 mode_winenable; | ||
195 | } w[4]; | ||
196 | }; | ||
197 | |||
198 | #if defined(__BIG_ENDIAN) | ||
199 | #define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_00 | ||
200 | #else | ||
201 | #define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01 | ||
202 | #endif | ||
203 | |||
204 | extern int board_au1200fb_panel_init (void); | ||
205 | extern int board_au1200fb_panel_shutdown (void); | ||
206 | |||
207 | #ifdef CONFIG_PM | ||
208 | int au1200fb_pm_callback(au1xxx_power_dev_t *dev, | ||
209 | au1xxx_request_t request, void *data); | ||
210 | au1xxx_power_dev_t *LCD_pm_dev; | ||
211 | #endif | ||
212 | |||
213 | /* | ||
214 | * Default window configurations | ||
215 | */ | ||
216 | static struct window_settings windows[] = { | ||
217 | { /* Index 0 */ | ||
218 | "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx", | ||
219 | /* mode_backcolor */ 0x006600ff, | ||
220 | /* mode_colorkey,msk*/ 0, 0, | ||
221 | { | ||
222 | { | ||
223 | /* xres, yres, xpos, ypos */ 0, 0, 0, 0, | ||
224 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | | ||
225 | LCD_WINCTRL1_PO_16BPP, | ||
226 | /* mode_winenable*/ LCD_WINENABLE_WEN0, | ||
227 | }, | ||
228 | { | ||
229 | /* xres, yres, xpos, ypos */ 100, 100, 100, 100, | ||
230 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | | ||
231 | LCD_WINCTRL1_PO_16BPP | | ||
232 | LCD_WINCTRL1_PIPE, | ||
233 | /* mode_winenable*/ LCD_WINENABLE_WEN1, | ||
234 | }, | ||
235 | { | ||
236 | /* xres, yres, xpos, ypos */ 0, 0, 0, 0, | ||
237 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | | ||
238 | LCD_WINCTRL1_PO_16BPP, | ||
239 | /* mode_winenable*/ 0, | ||
240 | }, | ||
241 | { | ||
242 | /* xres, yres, xpos, ypos */ 0, 0, 0, 0, | ||
243 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | | ||
244 | LCD_WINCTRL1_PO_16BPP | | ||
245 | LCD_WINCTRL1_PIPE, | ||
246 | /* mode_winenable*/ 0, | ||
247 | }, | ||
248 | }, | ||
249 | }, | ||
250 | |||
251 | { /* Index 1 */ | ||
252 | "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx", | ||
253 | /* mode_backcolor */ 0x006600ff, | ||
254 | /* mode_colorkey,msk*/ 0, 0, | ||
255 | { | ||
256 | { | ||
257 | /* xres, yres, xpos, ypos */ 320, 240, 5, 5, | ||
258 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_24BPP | | ||
259 | LCD_WINCTRL1_PO_00, | ||
260 | /* mode_winenable*/ LCD_WINENABLE_WEN0, | ||
261 | }, | ||
262 | { | ||
263 | /* xres, yres, xpos, ypos */ 0, 0, 0, 0, | ||
264 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | ||
265 | | LCD_WINCTRL1_PO_16BPP, | ||
266 | /* mode_winenable*/ 0, | ||
267 | }, | ||
268 | { | ||
269 | /* xres, yres, xpos, ypos */ 100, 100, 0, 0, | ||
270 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | | ||
271 | LCD_WINCTRL1_PO_16BPP | | ||
272 | LCD_WINCTRL1_PIPE, | ||
273 | /* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/, | ||
274 | }, | ||
275 | { | ||
276 | /* xres, yres, xpos, ypos */ 200, 25, 0, 0, | ||
277 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | | ||
278 | LCD_WINCTRL1_PO_16BPP | | ||
279 | LCD_WINCTRL1_PIPE, | ||
280 | /* mode_winenable*/ 0, | ||
281 | }, | ||
282 | }, | ||
283 | }, | ||
284 | { /* Index 2 */ | ||
285 | "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx", | ||
286 | /* mode_backcolor */ 0x006600ff, | ||
287 | /* mode_colorkey,msk*/ 0, 0, | ||
288 | { | ||
289 | { | ||
290 | /* xres, yres, xpos, ypos */ 0, 0, 0, 0, | ||
291 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | | ||
292 | LCD_WINCTRL1_PO_16BPP, | ||
293 | /* mode_winenable*/ LCD_WINENABLE_WEN0, | ||
294 | }, | ||
295 | { | ||
296 | /* xres, yres, xpos, ypos */ 0, 0, 0, 0, | ||
297 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | | ||
298 | LCD_WINCTRL1_PO_16BPP, | ||
299 | /* mode_winenable*/ 0, | ||
300 | }, | ||
301 | { | ||
302 | /* xres, yres, xpos, ypos */ 0, 0, 0, 0, | ||
303 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_32BPP | | ||
304 | LCD_WINCTRL1_PO_00|LCD_WINCTRL1_PIPE, | ||
305 | /* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/, | ||
306 | }, | ||
307 | { | ||
308 | /* xres, yres, xpos, ypos */ 0, 0, 0, 0, | ||
309 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | | ||
310 | LCD_WINCTRL1_PO_16BPP | | ||
311 | LCD_WINCTRL1_PIPE, | ||
312 | /* mode_winenable*/ 0, | ||
313 | }, | ||
314 | }, | ||
315 | }, | ||
316 | /* Need VGA 640 @ 24bpp, @ 32bpp */ | ||
317 | /* Need VGA 800 @ 24bpp, @ 32bpp */ | ||
318 | /* Need VGA 1024 @ 24bpp, @ 32bpp */ | ||
319 | }; | ||
320 | |||
321 | /* | ||
322 | * Controller configurations for various panels. | ||
323 | */ | ||
324 | |||
325 | struct panel_settings | ||
326 | { | ||
327 | const char name[25]; /* Full name <vendor>_<model> */ | ||
328 | |||
329 | struct fb_monspecs monspecs; /* FB monitor specs */ | ||
330 | |||
331 | /* panel timings */ | ||
332 | uint32 mode_screen; | ||
333 | uint32 mode_horztiming; | ||
334 | uint32 mode_verttiming; | ||
335 | uint32 mode_clkcontrol; | ||
336 | uint32 mode_pwmdiv; | ||
337 | uint32 mode_pwmhi; | ||
338 | uint32 mode_outmask; | ||
339 | uint32 mode_fifoctrl; | ||
340 | uint32 mode_toyclksrc; | ||
341 | uint32 mode_backlight; | ||
342 | uint32 mode_auxpll; | ||
343 | int (*device_init)(void); | ||
344 | int (*device_shutdown)(void); | ||
345 | #define Xres min_xres | ||
346 | #define Yres min_yres | ||
347 | u32 min_xres; /* Minimum horizontal resolution */ | ||
348 | u32 max_xres; /* Maximum horizontal resolution */ | ||
349 | u32 min_yres; /* Minimum vertical resolution */ | ||
350 | u32 max_yres; /* Maximum vertical resolution */ | ||
351 | }; | ||
352 | |||
353 | /********************************************************************/ | ||
354 | /* fixme: Maybe a modedb for the CRT ? otherwise panels should be as-is */ | ||
355 | |||
356 | /* List of panels known to work with the AU1200 LCD controller. | ||
357 | * To add a new panel, enter the same specifications as the | ||
358 | * Generic_TFT one, and MAKE SURE that it doesn't conflicts | ||
359 | * with the controller restrictions. Restrictions are: | ||
360 | * | ||
361 | * STN color panels: max_bpp <= 12 | ||
362 | * STN mono panels: max_bpp <= 4 | ||
363 | * TFT panels: max_bpp <= 16 | ||
364 | * max_xres <= 800 | ||
365 | * max_yres <= 600 | ||
366 | */ | ||
367 | static struct panel_settings known_lcd_panels[] = | ||
368 | { | ||
369 | [0] = { /* QVGA 320x240 H:33.3kHz V:110Hz */ | ||
370 | .name = "QVGA_320x240", | ||
371 | .monspecs = { | ||
372 | .modedb = NULL, | ||
373 | .modedb_len = 0, | ||
374 | .hfmin = 30000, | ||
375 | .hfmax = 70000, | ||
376 | .vfmin = 60, | ||
377 | .vfmax = 60, | ||
378 | .dclkmin = 6000000, | ||
379 | .dclkmax = 28000000, | ||
380 | .input = FB_DISP_RGB, | ||
381 | }, | ||
382 | .mode_screen = LCD_SCREEN_SX_N(320) | | ||
383 | LCD_SCREEN_SY_N(240), | ||
384 | .mode_horztiming = 0x00c4623b, | ||
385 | .mode_verttiming = 0x00502814, | ||
386 | .mode_clkcontrol = 0x00020002, /* /4=24Mhz */ | ||
387 | .mode_pwmdiv = 0x00000000, | ||
388 | .mode_pwmhi = 0x00000000, | ||
389 | .mode_outmask = 0x00FFFFFF, | ||
390 | .mode_fifoctrl = 0x2f2f2f2f, | ||
391 | .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ | ||
392 | .mode_backlight = 0x00000000, | ||
393 | .mode_auxpll = 8, /* 96MHz AUXPLL */ | ||
394 | .device_init = NULL, | ||
395 | .device_shutdown = NULL, | ||
396 | 320, 320, | ||
397 | 240, 240, | ||
398 | }, | ||
399 | |||
400 | [1] = { /* VGA 640x480 H:30.3kHz V:58Hz */ | ||
401 | .name = "VGA_640x480", | ||
402 | .monspecs = { | ||
403 | .modedb = NULL, | ||
404 | .modedb_len = 0, | ||
405 | .hfmin = 30000, | ||
406 | .hfmax = 70000, | ||
407 | .vfmin = 60, | ||
408 | .vfmax = 60, | ||
409 | .dclkmin = 6000000, | ||
410 | .dclkmax = 28000000, | ||
411 | .input = FB_DISP_RGB, | ||
412 | }, | ||
413 | .mode_screen = 0x13f9df80, | ||
414 | .mode_horztiming = 0x003c5859, | ||
415 | .mode_verttiming = 0x00741201, | ||
416 | .mode_clkcontrol = 0x00020001, /* /4=24Mhz */ | ||
417 | .mode_pwmdiv = 0x00000000, | ||
418 | .mode_pwmhi = 0x00000000, | ||
419 | .mode_outmask = 0x00FFFFFF, | ||
420 | .mode_fifoctrl = 0x2f2f2f2f, | ||
421 | .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ | ||
422 | .mode_backlight = 0x00000000, | ||
423 | .mode_auxpll = 8, /* 96MHz AUXPLL */ | ||
424 | .device_init = NULL, | ||
425 | .device_shutdown = NULL, | ||
426 | 640, 480, | ||
427 | 640, 480, | ||
428 | }, | ||
429 | |||
430 | [2] = { /* SVGA 800x600 H:46.1kHz V:69Hz */ | ||
431 | .name = "SVGA_800x600", | ||
432 | .monspecs = { | ||
433 | .modedb = NULL, | ||
434 | .modedb_len = 0, | ||
435 | .hfmin = 30000, | ||
436 | .hfmax = 70000, | ||
437 | .vfmin = 60, | ||
438 | .vfmax = 60, | ||
439 | .dclkmin = 6000000, | ||
440 | .dclkmax = 28000000, | ||
441 | .input = FB_DISP_RGB, | ||
442 | }, | ||
443 | .mode_screen = 0x18fa5780, | ||
444 | .mode_horztiming = 0x00dc7e77, | ||
445 | .mode_verttiming = 0x00584805, | ||
446 | .mode_clkcontrol = 0x00020000, /* /2=48Mhz */ | ||
447 | .mode_pwmdiv = 0x00000000, | ||
448 | .mode_pwmhi = 0x00000000, | ||
449 | .mode_outmask = 0x00FFFFFF, | ||
450 | .mode_fifoctrl = 0x2f2f2f2f, | ||
451 | .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ | ||
452 | .mode_backlight = 0x00000000, | ||
453 | .mode_auxpll = 8, /* 96MHz AUXPLL */ | ||
454 | .device_init = NULL, | ||
455 | .device_shutdown = NULL, | ||
456 | 800, 800, | ||
457 | 600, 600, | ||
458 | }, | ||
459 | |||
460 | [3] = { /* XVGA 1024x768 H:56.2kHz V:70Hz */ | ||
461 | .name = "XVGA_1024x768", | ||
462 | .monspecs = { | ||
463 | .modedb = NULL, | ||
464 | .modedb_len = 0, | ||
465 | .hfmin = 30000, | ||
466 | .hfmax = 70000, | ||
467 | .vfmin = 60, | ||
468 | .vfmax = 60, | ||
469 | .dclkmin = 6000000, | ||
470 | .dclkmax = 28000000, | ||
471 | .input = FB_DISP_RGB, | ||
472 | }, | ||
473 | .mode_screen = 0x1ffaff80, | ||
474 | .mode_horztiming = 0x007d0e57, | ||
475 | .mode_verttiming = 0x00740a01, | ||
476 | .mode_clkcontrol = 0x000A0000, /* /1 */ | ||
477 | .mode_pwmdiv = 0x00000000, | ||
478 | .mode_pwmhi = 0x00000000, | ||
479 | .mode_outmask = 0x00FFFFFF, | ||
480 | .mode_fifoctrl = 0x2f2f2f2f, | ||
481 | .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ | ||
482 | .mode_backlight = 0x00000000, | ||
483 | .mode_auxpll = 6, /* 72MHz AUXPLL */ | ||
484 | .device_init = NULL, | ||
485 | .device_shutdown = NULL, | ||
486 | 1024, 1024, | ||
487 | 768, 768, | ||
488 | }, | ||
489 | |||
490 | [4] = { /* XVGA XVGA 1280x1024 H:68.5kHz V:65Hz */ | ||
491 | .name = "XVGA_1280x1024", | ||
492 | .monspecs = { | ||
493 | .modedb = NULL, | ||
494 | .modedb_len = 0, | ||
495 | .hfmin = 30000, | ||
496 | .hfmax = 70000, | ||
497 | .vfmin = 60, | ||
498 | .vfmax = 60, | ||
499 | .dclkmin = 6000000, | ||
500 | .dclkmax = 28000000, | ||
501 | .input = FB_DISP_RGB, | ||
502 | }, | ||
503 | .mode_screen = 0x27fbff80, | ||
504 | .mode_horztiming = 0x00cdb2c7, | ||
505 | .mode_verttiming = 0x00600002, | ||
506 | .mode_clkcontrol = 0x000A0000, /* /1 */ | ||
507 | .mode_pwmdiv = 0x00000000, | ||
508 | .mode_pwmhi = 0x00000000, | ||
509 | .mode_outmask = 0x00FFFFFF, | ||
510 | .mode_fifoctrl = 0x2f2f2f2f, | ||
511 | .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ | ||
512 | .mode_backlight = 0x00000000, | ||
513 | .mode_auxpll = 10, /* 120MHz AUXPLL */ | ||
514 | .device_init = NULL, | ||
515 | .device_shutdown = NULL, | ||
516 | 1280, 1280, | ||
517 | 1024, 1024, | ||
518 | }, | ||
519 | |||
520 | [5] = { /* Samsung 1024x768 TFT */ | ||
521 | .name = "Samsung_1024x768_TFT", | ||
522 | .monspecs = { | ||
523 | .modedb = NULL, | ||
524 | .modedb_len = 0, | ||
525 | .hfmin = 30000, | ||
526 | .hfmax = 70000, | ||
527 | .vfmin = 60, | ||
528 | .vfmax = 60, | ||
529 | .dclkmin = 6000000, | ||
530 | .dclkmax = 28000000, | ||
531 | .input = FB_DISP_RGB, | ||
532 | }, | ||
533 | .mode_screen = 0x1ffaff80, | ||
534 | .mode_horztiming = 0x018cc677, | ||
535 | .mode_verttiming = 0x00241217, | ||
536 | .mode_clkcontrol = 0x00000000, /* SCB 0x1 /4=24Mhz */ | ||
537 | .mode_pwmdiv = 0x8000063f, /* SCB 0x0 */ | ||
538 | .mode_pwmhi = 0x03400000, /* SCB 0x0 */ | ||
539 | .mode_outmask = 0x00FFFFFF, | ||
540 | .mode_fifoctrl = 0x2f2f2f2f, | ||
541 | .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ | ||
542 | .mode_backlight = 0x00000000, | ||
543 | .mode_auxpll = 8, /* 96MHz AUXPLL */ | ||
544 | .device_init = board_au1200fb_panel_init, | ||
545 | .device_shutdown = board_au1200fb_panel_shutdown, | ||
546 | 1024, 1024, | ||
547 | 768, 768, | ||
548 | }, | ||
549 | |||
550 | [6] = { /* Toshiba 640x480 TFT */ | ||
551 | .name = "Toshiba_640x480_TFT", | ||
552 | .monspecs = { | ||
553 | .modedb = NULL, | ||
554 | .modedb_len = 0, | ||
555 | .hfmin = 30000, | ||
556 | .hfmax = 70000, | ||
557 | .vfmin = 60, | ||
558 | .vfmax = 60, | ||
559 | .dclkmin = 6000000, | ||
560 | .dclkmax = 28000000, | ||
561 | .input = FB_DISP_RGB, | ||
562 | }, | ||
563 | .mode_screen = LCD_SCREEN_SX_N(640) | | ||
564 | LCD_SCREEN_SY_N(480), | ||
565 | .mode_horztiming = LCD_HORZTIMING_HPW_N(96) | | ||
566 | LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(51), | ||
567 | .mode_verttiming = LCD_VERTTIMING_VPW_N(2) | | ||
568 | LCD_VERTTIMING_VND1_N(11) | LCD_VERTTIMING_VND2_N(32), | ||
569 | .mode_clkcontrol = 0x00000000, /* /4=24Mhz */ | ||
570 | .mode_pwmdiv = 0x8000063f, | ||
571 | .mode_pwmhi = 0x03400000, | ||
572 | .mode_outmask = 0x00fcfcfc, | ||
573 | .mode_fifoctrl = 0x2f2f2f2f, | ||
574 | .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ | ||
575 | .mode_backlight = 0x00000000, | ||
576 | .mode_auxpll = 8, /* 96MHz AUXPLL */ | ||
577 | .device_init = board_au1200fb_panel_init, | ||
578 | .device_shutdown = board_au1200fb_panel_shutdown, | ||
579 | 640, 480, | ||
580 | 640, 480, | ||
581 | }, | ||
582 | |||
583 | [7] = { /* Sharp 320x240 TFT */ | ||
584 | .name = "Sharp_320x240_TFT", | ||
585 | .monspecs = { | ||
586 | .modedb = NULL, | ||
587 | .modedb_len = 0, | ||
588 | .hfmin = 12500, | ||
589 | .hfmax = 20000, | ||
590 | .vfmin = 38, | ||
591 | .vfmax = 81, | ||
592 | .dclkmin = 4500000, | ||
593 | .dclkmax = 6800000, | ||
594 | .input = FB_DISP_RGB, | ||
595 | }, | ||
596 | .mode_screen = LCD_SCREEN_SX_N(320) | | ||
597 | LCD_SCREEN_SY_N(240), | ||
598 | .mode_horztiming = LCD_HORZTIMING_HPW_N(60) | | ||
599 | LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(2), | ||
600 | .mode_verttiming = LCD_VERTTIMING_VPW_N(2) | | ||
601 | LCD_VERTTIMING_VND1_N(2) | LCD_VERTTIMING_VND2_N(5), | ||
602 | .mode_clkcontrol = LCD_CLKCONTROL_PCD_N(7), /*16=6Mhz*/ | ||
603 | .mode_pwmdiv = 0x8000063f, | ||
604 | .mode_pwmhi = 0x03400000, | ||
605 | .mode_outmask = 0x00fcfcfc, | ||
606 | .mode_fifoctrl = 0x2f2f2f2f, | ||
607 | .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ | ||
608 | .mode_backlight = 0x00000000, | ||
609 | .mode_auxpll = 8, /* 96MHz AUXPLL */ | ||
610 | .device_init = board_au1200fb_panel_init, | ||
611 | .device_shutdown = board_au1200fb_panel_shutdown, | ||
612 | 320, 320, | ||
613 | 240, 240, | ||
614 | }, | ||
615 | |||
616 | [8] = { /* Toppoly TD070WGCB2 7" 856x480 TFT */ | ||
617 | .name = "Toppoly_TD070WGCB2", | ||
618 | .monspecs = { | ||
619 | .modedb = NULL, | ||
620 | .modedb_len = 0, | ||
621 | .hfmin = 30000, | ||
622 | .hfmax = 70000, | ||
623 | .vfmin = 60, | ||
624 | .vfmax = 60, | ||
625 | .dclkmin = 6000000, | ||
626 | .dclkmax = 28000000, | ||
627 | .input = FB_DISP_RGB, | ||
628 | }, | ||
629 | .mode_screen = LCD_SCREEN_SX_N(856) | | ||
630 | LCD_SCREEN_SY_N(480), | ||
631 | .mode_horztiming = LCD_HORZTIMING_HND2_N(43) | | ||
632 | LCD_HORZTIMING_HND1_N(43) | LCD_HORZTIMING_HPW_N(114), | ||
633 | .mode_verttiming = LCD_VERTTIMING_VND2_N(20) | | ||
634 | LCD_VERTTIMING_VND1_N(21) | LCD_VERTTIMING_VPW_N(4), | ||
635 | .mode_clkcontrol = 0x00020001, /* /4=24Mhz */ | ||
636 | .mode_pwmdiv = 0x8000063f, | ||
637 | .mode_pwmhi = 0x03400000, | ||
638 | .mode_outmask = 0x00fcfcfc, | ||
639 | .mode_fifoctrl = 0x2f2f2f2f, | ||
640 | .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ | ||
641 | .mode_backlight = 0x00000000, | ||
642 | .mode_auxpll = 8, /* 96MHz AUXPLL */ | ||
643 | .device_init = board_au1200fb_panel_init, | ||
644 | .device_shutdown = board_au1200fb_panel_shutdown, | ||
645 | 856, 856, | ||
646 | 480, 480, | ||
647 | }, | ||
648 | }; | ||
649 | |||
650 | #define NUM_PANELS (ARRAY_SIZE(known_lcd_panels)) | ||
651 | |||
652 | /********************************************************************/ | ||
653 | |||
654 | #ifdef CONFIG_PM | ||
655 | static int set_brightness(unsigned int brightness) | ||
656 | { | ||
657 | unsigned int hi1, divider; | ||
658 | |||
659 | /* limit brightness pwm duty to >= 30/1600 */ | ||
660 | if (brightness < 30) { | ||
661 | brightness = 30; | ||
662 | } | ||
663 | divider = (lcd->pwmdiv & 0x3FFFF) + 1; | ||
664 | hi1 = (lcd->pwmhi >> 16) + 1; | ||
665 | hi1 = (((brightness & 0xFF) + 1) * divider >> 8); | ||
666 | lcd->pwmhi &= 0xFFFF; | ||
667 | lcd->pwmhi |= (hi1 << 16); | ||
668 | |||
669 | return brightness; | ||
670 | } | ||
671 | #endif /* CONFIG_PM */ | ||
672 | |||
673 | static int winbpp (unsigned int winctrl1) | ||
674 | { | ||
675 | int bits = 0; | ||
676 | |||
677 | /* how many bits are needed for each pixel format */ | ||
678 | switch (winctrl1 & LCD_WINCTRL1_FRM) { | ||
679 | case LCD_WINCTRL1_FRM_1BPP: | ||
680 | bits = 1; | ||
681 | break; | ||
682 | case LCD_WINCTRL1_FRM_2BPP: | ||
683 | bits = 2; | ||
684 | break; | ||
685 | case LCD_WINCTRL1_FRM_4BPP: | ||
686 | bits = 4; | ||
687 | break; | ||
688 | case LCD_WINCTRL1_FRM_8BPP: | ||
689 | bits = 8; | ||
690 | break; | ||
691 | case LCD_WINCTRL1_FRM_12BPP: | ||
692 | case LCD_WINCTRL1_FRM_16BPP655: | ||
693 | case LCD_WINCTRL1_FRM_16BPP565: | ||
694 | case LCD_WINCTRL1_FRM_16BPP556: | ||
695 | case LCD_WINCTRL1_FRM_16BPPI1555: | ||
696 | case LCD_WINCTRL1_FRM_16BPPI5551: | ||
697 | case LCD_WINCTRL1_FRM_16BPPA1555: | ||
698 | case LCD_WINCTRL1_FRM_16BPPA5551: | ||
699 | bits = 16; | ||
700 | break; | ||
701 | case LCD_WINCTRL1_FRM_24BPP: | ||
702 | case LCD_WINCTRL1_FRM_32BPP: | ||
703 | bits = 32; | ||
704 | break; | ||
705 | } | ||
706 | |||
707 | return bits; | ||
708 | } | ||
709 | |||
710 | static int fbinfo2index (struct fb_info *fb_info) | ||
711 | { | ||
712 | int i; | ||
713 | |||
714 | for (i = 0; i < CONFIG_FB_AU1200_DEVS; ++i) { | ||
715 | if (fb_info == (struct fb_info *)(&_au1200fb_devices[i].fb_info)) | ||
716 | return i; | ||
717 | } | ||
718 | printk("au1200fb: ERROR: fbinfo2index failed!\n"); | ||
719 | return -1; | ||
720 | } | ||
721 | |||
722 | static int au1200_setlocation (struct au1200fb_device *fbdev, int plane, | ||
723 | int xpos, int ypos) | ||
724 | { | ||
725 | uint32 winctrl0, winctrl1, winenable, fb_offset = 0; | ||
726 | int xsz, ysz; | ||
727 | |||
728 | /* FIX!!! NOT CHECKING FOR COMPLETE OFFSCREEN YET */ | ||
729 | |||
730 | winctrl0 = lcd->window[plane].winctrl0; | ||
731 | winctrl1 = lcd->window[plane].winctrl1; | ||
732 | winctrl0 &= (LCD_WINCTRL0_A | LCD_WINCTRL0_AEN); | ||
733 | winctrl1 &= ~(LCD_WINCTRL1_SZX | LCD_WINCTRL1_SZY); | ||
734 | |||
735 | /* Check for off-screen adjustments */ | ||
736 | xsz = win->w[plane].xres; | ||
737 | ysz = win->w[plane].yres; | ||
738 | if ((xpos + win->w[plane].xres) > panel->Xres) { | ||
739 | /* Off-screen to the right */ | ||
740 | xsz = panel->Xres - xpos; /* off by 1 ??? */ | ||
741 | /*printk("off screen right\n");*/ | ||
742 | } | ||
743 | |||
744 | if ((ypos + win->w[plane].yres) > panel->Yres) { | ||
745 | /* Off-screen to the bottom */ | ||
746 | ysz = panel->Yres - ypos; /* off by 1 ??? */ | ||
747 | /*printk("off screen bottom\n");*/ | ||
748 | } | ||
749 | |||
750 | if (xpos < 0) { | ||
751 | /* Off-screen to the left */ | ||
752 | xsz = win->w[plane].xres + xpos; | ||
753 | fb_offset += (((0 - xpos) * winbpp(lcd->window[plane].winctrl1))/8); | ||
754 | xpos = 0; | ||
755 | /*printk("off screen left\n");*/ | ||
756 | } | ||
757 | |||
758 | if (ypos < 0) { | ||
759 | /* Off-screen to the top */ | ||
760 | ysz = win->w[plane].yres + ypos; | ||
761 | /* fixme: fb_offset += ((0-ypos)*fb_pars[plane].line_length); */ | ||
762 | ypos = 0; | ||
763 | /*printk("off screen top\n");*/ | ||
764 | } | ||
765 | |||
766 | /* record settings */ | ||
767 | win->w[plane].xpos = xpos; | ||
768 | win->w[plane].ypos = ypos; | ||
769 | |||
770 | xsz -= 1; | ||
771 | ysz -= 1; | ||
772 | winctrl0 |= (xpos << 21); | ||
773 | winctrl0 |= (ypos << 10); | ||
774 | winctrl1 |= (xsz << 11); | ||
775 | winctrl1 |= (ysz << 0); | ||
776 | |||
777 | /* Disable the window while making changes, then restore WINEN */ | ||
778 | winenable = lcd->winenable & (1 << plane); | ||
779 | au_sync(); | ||
780 | lcd->winenable &= ~(1 << plane); | ||
781 | lcd->window[plane].winctrl0 = winctrl0; | ||
782 | lcd->window[plane].winctrl1 = winctrl1; | ||
783 | lcd->window[plane].winbuf0 = | ||
784 | lcd->window[plane].winbuf1 = fbdev->fb_phys; | ||
785 | lcd->window[plane].winbufctrl = 0; /* select winbuf0 */ | ||
786 | lcd->winenable |= winenable; | ||
787 | au_sync(); | ||
788 | |||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | static void au1200_setpanel (struct panel_settings *newpanel) | ||
793 | { | ||
794 | /* | ||
795 | * Perform global setup/init of LCD controller | ||
796 | */ | ||
797 | uint32 winenable; | ||
798 | |||
799 | /* Make sure all windows disabled */ | ||
800 | winenable = lcd->winenable; | ||
801 | lcd->winenable = 0; | ||
802 | au_sync(); | ||
803 | /* | ||
804 | * Ensure everything is disabled before reconfiguring | ||
805 | */ | ||
806 | if (lcd->screen & LCD_SCREEN_SEN) { | ||
807 | /* Wait for vertical sync period */ | ||
808 | lcd->intstatus = LCD_INT_SS; | ||
809 | while ((lcd->intstatus & LCD_INT_SS) == 0) { | ||
810 | au_sync(); | ||
811 | } | ||
812 | |||
813 | lcd->screen &= ~LCD_SCREEN_SEN; /*disable the controller*/ | ||
814 | |||
815 | do { | ||
816 | lcd->intstatus = lcd->intstatus; /*clear interrupts*/ | ||
817 | au_sync(); | ||
818 | /*wait for controller to shut down*/ | ||
819 | } while ((lcd->intstatus & LCD_INT_SD) == 0); | ||
820 | |||
821 | /* Call shutdown of current panel (if up) */ | ||
822 | /* this must occur last, because if an external clock is driving | ||
823 | the controller, the clock cannot be turned off before first | ||
824 | shutting down the controller. | ||
825 | */ | ||
826 | if (panel->device_shutdown != NULL) | ||
827 | panel->device_shutdown(); | ||
828 | } | ||
829 | |||
830 | /* Newpanel == NULL indicates a shutdown operation only */ | ||
831 | if (newpanel == NULL) | ||
832 | return; | ||
833 | |||
834 | panel = newpanel; | ||
835 | |||
836 | printk("Panel(%s), %dx%d\n", panel->name, panel->Xres, panel->Yres); | ||
837 | |||
838 | /* | ||
839 | * Setup clocking if internal LCD clock source (assumes sys_auxpll valid) | ||
840 | */ | ||
841 | if (!(panel->mode_clkcontrol & LCD_CLKCONTROL_EXT)) | ||
842 | { | ||
843 | uint32 sys_clksrc; | ||
844 | au_writel(panel->mode_auxpll, SYS_AUXPLL); | ||
845 | sys_clksrc = au_readl(SYS_CLKSRC) & ~0x0000001f; | ||
846 | sys_clksrc |= panel->mode_toyclksrc; | ||
847 | au_writel(sys_clksrc, SYS_CLKSRC); | ||
848 | } | ||
849 | |||
850 | /* | ||
851 | * Configure panel timings | ||
852 | */ | ||
853 | lcd->screen = panel->mode_screen; | ||
854 | lcd->horztiming = panel->mode_horztiming; | ||
855 | lcd->verttiming = panel->mode_verttiming; | ||
856 | lcd->clkcontrol = panel->mode_clkcontrol; | ||
857 | lcd->pwmdiv = panel->mode_pwmdiv; | ||
858 | lcd->pwmhi = panel->mode_pwmhi; | ||
859 | lcd->outmask = panel->mode_outmask; | ||
860 | lcd->fifoctrl = panel->mode_fifoctrl; | ||
861 | au_sync(); | ||
862 | |||
863 | /* fixme: Check window settings to make sure still valid | ||
864 | * for new geometry */ | ||
865 | #if 0 | ||
866 | au1200_setlocation(fbdev, 0, win->w[0].xpos, win->w[0].ypos); | ||
867 | au1200_setlocation(fbdev, 1, win->w[1].xpos, win->w[1].ypos); | ||
868 | au1200_setlocation(fbdev, 2, win->w[2].xpos, win->w[2].ypos); | ||
869 | au1200_setlocation(fbdev, 3, win->w[3].xpos, win->w[3].ypos); | ||
870 | #endif | ||
871 | lcd->winenable = winenable; | ||
872 | |||
873 | /* | ||
874 | * Re-enable screen now that it is configured | ||
875 | */ | ||
876 | lcd->screen |= LCD_SCREEN_SEN; | ||
877 | au_sync(); | ||
878 | |||
879 | /* Call init of panel */ | ||
880 | if (panel->device_init != NULL) panel->device_init(); | ||
881 | |||
882 | /* FIX!!!! not appropriate on panel change!!! Global setup/init */ | ||
883 | lcd->intenable = 0; | ||
884 | lcd->intstatus = ~0; | ||
885 | lcd->backcolor = win->mode_backcolor; | ||
886 | |||
887 | /* Setup Color Key - FIX!!! */ | ||
888 | lcd->colorkey = win->mode_colorkey; | ||
889 | lcd->colorkeymsk = win->mode_colorkeymsk; | ||
890 | |||
891 | /* Setup HWCursor - FIX!!! Need to support this eventually */ | ||
892 | lcd->hwc.cursorctrl = 0; | ||
893 | lcd->hwc.cursorpos = 0; | ||
894 | lcd->hwc.cursorcolor0 = 0; | ||
895 | lcd->hwc.cursorcolor1 = 0; | ||
896 | lcd->hwc.cursorcolor2 = 0; | ||
897 | lcd->hwc.cursorcolor3 = 0; | ||
898 | |||
899 | |||
900 | #if 0 | ||
901 | #define D(X) printk("%25s: %08X\n", #X, X) | ||
902 | D(lcd->screen); | ||
903 | D(lcd->horztiming); | ||
904 | D(lcd->verttiming); | ||
905 | D(lcd->clkcontrol); | ||
906 | D(lcd->pwmdiv); | ||
907 | D(lcd->pwmhi); | ||
908 | D(lcd->outmask); | ||
909 | D(lcd->fifoctrl); | ||
910 | D(lcd->window[0].winctrl0); | ||
911 | D(lcd->window[0].winctrl1); | ||
912 | D(lcd->window[0].winctrl2); | ||
913 | D(lcd->window[0].winbuf0); | ||
914 | D(lcd->window[0].winbuf1); | ||
915 | D(lcd->window[0].winbufctrl); | ||
916 | D(lcd->window[1].winctrl0); | ||
917 | D(lcd->window[1].winctrl1); | ||
918 | D(lcd->window[1].winctrl2); | ||
919 | D(lcd->window[1].winbuf0); | ||
920 | D(lcd->window[1].winbuf1); | ||
921 | D(lcd->window[1].winbufctrl); | ||
922 | D(lcd->window[2].winctrl0); | ||
923 | D(lcd->window[2].winctrl1); | ||
924 | D(lcd->window[2].winctrl2); | ||
925 | D(lcd->window[2].winbuf0); | ||
926 | D(lcd->window[2].winbuf1); | ||
927 | D(lcd->window[2].winbufctrl); | ||
928 | D(lcd->window[3].winctrl0); | ||
929 | D(lcd->window[3].winctrl1); | ||
930 | D(lcd->window[3].winctrl2); | ||
931 | D(lcd->window[3].winbuf0); | ||
932 | D(lcd->window[3].winbuf1); | ||
933 | D(lcd->window[3].winbufctrl); | ||
934 | D(lcd->winenable); | ||
935 | D(lcd->intenable); | ||
936 | D(lcd->intstatus); | ||
937 | D(lcd->backcolor); | ||
938 | D(lcd->winenable); | ||
939 | D(lcd->colorkey); | ||
940 | D(lcd->colorkeymsk); | ||
941 | D(lcd->hwc.cursorctrl); | ||
942 | D(lcd->hwc.cursorpos); | ||
943 | D(lcd->hwc.cursorcolor0); | ||
944 | D(lcd->hwc.cursorcolor1); | ||
945 | D(lcd->hwc.cursorcolor2); | ||
946 | D(lcd->hwc.cursorcolor3); | ||
947 | #endif | ||
948 | } | ||
949 | |||
950 | static void au1200_setmode(struct au1200fb_device *fbdev) | ||
951 | { | ||
952 | int plane = fbdev->plane; | ||
953 | /* Window/plane setup */ | ||
954 | lcd->window[plane].winctrl1 = ( 0 | ||
955 | | LCD_WINCTRL1_PRI_N(plane) | ||
956 | | win->w[plane].mode_winctrl1 /* FRM,CCO,PO,PIPE */ | ||
957 | ) ; | ||
958 | |||
959 | au1200_setlocation(fbdev, plane, win->w[plane].xpos, win->w[plane].ypos); | ||
960 | |||
961 | lcd->window[plane].winctrl2 = ( 0 | ||
962 | | LCD_WINCTRL2_CKMODE_00 | ||
963 | | LCD_WINCTRL2_DBM | ||
964 | | LCD_WINCTRL2_BX_N( fbdev->fb_info.fix.line_length) | ||
965 | | LCD_WINCTRL2_SCX_1 | ||
966 | | LCD_WINCTRL2_SCY_1 | ||
967 | ) ; | ||
968 | lcd->winenable |= win->w[plane].mode_winenable; | ||
969 | au_sync(); | ||
970 | } | ||
971 | |||
972 | |||
973 | /* Inline helpers */ | ||
974 | |||
975 | /*#define panel_is_dual(panel) ((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/ | ||
976 | /*#define panel_is_active(panel)((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/ | ||
977 | |||
978 | #define panel_is_color(panel) ((panel->mode_screen & LCD_SCREEN_PT) <= LCD_SCREEN_PT_CDSTN) | ||
979 | |||
980 | /* Bitfields format supported by the controller. */ | ||
981 | static struct fb_bitfield rgb_bitfields[][4] = { | ||
982 | /* Red, Green, Blue, Transp */ | ||
983 | [LCD_WINCTRL1_FRM_16BPP655 >> 25] = | ||
984 | { { 10, 6, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } }, | ||
985 | |||
986 | [LCD_WINCTRL1_FRM_16BPP565 >> 25] = | ||
987 | { { 11, 5, 0 }, { 5, 6, 0 }, { 0, 5, 0 }, { 0, 0, 0 } }, | ||
988 | |||
989 | [LCD_WINCTRL1_FRM_16BPP556 >> 25] = | ||
990 | { { 11, 5, 0 }, { 6, 5, 0 }, { 0, 6, 0 }, { 0, 0, 0 } }, | ||
991 | |||
992 | [LCD_WINCTRL1_FRM_16BPPI1555 >> 25] = | ||
993 | { { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } }, | ||
994 | |||
995 | [LCD_WINCTRL1_FRM_16BPPI5551 >> 25] = | ||
996 | { { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 0, 0 } }, | ||
997 | |||
998 | [LCD_WINCTRL1_FRM_16BPPA1555 >> 25] = | ||
999 | { { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 15, 1, 0 } }, | ||
1000 | |||
1001 | [LCD_WINCTRL1_FRM_16BPPA5551 >> 25] = | ||
1002 | { { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 1, 0 } }, | ||
1003 | |||
1004 | [LCD_WINCTRL1_FRM_24BPP >> 25] = | ||
1005 | { { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 0, 0, 0 } }, | ||
1006 | |||
1007 | [LCD_WINCTRL1_FRM_32BPP >> 25] = | ||
1008 | { { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 0, 0 } }, | ||
1009 | }; | ||
1010 | |||
1011 | /*-------------------------------------------------------------------------*/ | ||
1012 | |||
1013 | /* Helpers */ | ||
1014 | |||
1015 | static void au1200fb_update_fbinfo(struct fb_info *fbi) | ||
1016 | { | ||
1017 | /* FIX!!!! This also needs to take the window pixel format into account!!! */ | ||
1018 | |||
1019 | /* Update var-dependent FB info */ | ||
1020 | if (panel_is_color(panel)) { | ||
1021 | if (fbi->var.bits_per_pixel <= 8) { | ||
1022 | /* palettized */ | ||
1023 | fbi->fix.visual = FB_VISUAL_PSEUDOCOLOR; | ||
1024 | fbi->fix.line_length = fbi->var.xres_virtual / | ||
1025 | (8/fbi->var.bits_per_pixel); | ||
1026 | } else { | ||
1027 | /* non-palettized */ | ||
1028 | fbi->fix.visual = FB_VISUAL_TRUECOLOR; | ||
1029 | fbi->fix.line_length = fbi->var.xres_virtual * (fbi->var.bits_per_pixel / 8); | ||
1030 | } | ||
1031 | } else { | ||
1032 | /* mono FIX!!! mono 8 and 4 bits */ | ||
1033 | fbi->fix.visual = FB_VISUAL_MONO10; | ||
1034 | fbi->fix.line_length = fbi->var.xres_virtual / 8; | ||
1035 | } | ||
1036 | |||
1037 | fbi->screen_size = fbi->fix.line_length * fbi->var.yres_virtual; | ||
1038 | print_dbg("line length: %d\n", fbi->fix.line_length); | ||
1039 | print_dbg("bits_per_pixel: %d\n", fbi->var.bits_per_pixel); | ||
1040 | } | ||
1041 | |||
1042 | /*-------------------------------------------------------------------------*/ | ||
1043 | |||
1044 | /* AU1200 framebuffer driver */ | ||
1045 | |||
1046 | /* fb_check_var | ||
1047 | * Validate var settings with hardware restrictions and modify it if necessary | ||
1048 | */ | ||
1049 | static int au1200fb_fb_check_var(struct fb_var_screeninfo *var, | ||
1050 | struct fb_info *fbi) | ||
1051 | { | ||
1052 | struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi; | ||
1053 | u32 pixclock; | ||
1054 | int screen_size, plane; | ||
1055 | |||
1056 | plane = fbdev->plane; | ||
1057 | |||
1058 | /* Make sure that the mode respect all LCD controller and | ||
1059 | * panel restrictions. */ | ||
1060 | var->xres = win->w[plane].xres; | ||
1061 | var->yres = win->w[plane].yres; | ||
1062 | |||
1063 | /* No need for virtual resolution support */ | ||
1064 | var->xres_virtual = var->xres; | ||
1065 | var->yres_virtual = var->yres; | ||
1066 | |||
1067 | var->bits_per_pixel = winbpp(win->w[plane].mode_winctrl1); | ||
1068 | |||
1069 | screen_size = var->xres_virtual * var->yres_virtual; | ||
1070 | if (var->bits_per_pixel > 8) screen_size *= (var->bits_per_pixel / 8); | ||
1071 | else screen_size /= (8/var->bits_per_pixel); | ||
1072 | |||
1073 | if (fbdev->fb_len < screen_size) | ||
1074 | return -EINVAL; /* Virtual screen is to big, abort */ | ||
1075 | |||
1076 | /* FIX!!!! what are the implicaitons of ignoring this for windows ??? */ | ||
1077 | /* The max LCD clock is fixed to 48MHz (value of AUX_CLK). The pixel | ||
1078 | * clock can only be obtain by dividing this value by an even integer. | ||
1079 | * Fallback to a slower pixel clock if necessary. */ | ||
1080 | pixclock = max((u32)(PICOS2KHZ(var->pixclock) * 1000), fbi->monspecs.dclkmin); | ||
1081 | pixclock = min(pixclock, min(fbi->monspecs.dclkmax, (u32)AU1200_LCD_MAX_CLK/2)); | ||
1082 | |||
1083 | if (AU1200_LCD_MAX_CLK % pixclock) { | ||
1084 | int diff = AU1200_LCD_MAX_CLK % pixclock; | ||
1085 | pixclock -= diff; | ||
1086 | } | ||
1087 | |||
1088 | var->pixclock = KHZ2PICOS(pixclock/1000); | ||
1089 | #if 0 | ||
1090 | if (!panel_is_active(panel)) { | ||
1091 | int pcd = AU1200_LCD_MAX_CLK / (pixclock * 2) - 1; | ||
1092 | |||
1093 | if (!panel_is_color(panel) | ||
1094 | && (panel->control_base & LCD_CONTROL_MPI) && (pcd < 3)) { | ||
1095 | /* STN 8bit mono panel support is up to 6MHz pixclock */ | ||
1096 | var->pixclock = KHZ2PICOS(6000); | ||
1097 | } else if (!pcd) { | ||
1098 | /* Other STN panel support is up to 12MHz */ | ||
1099 | var->pixclock = KHZ2PICOS(12000); | ||
1100 | } | ||
1101 | } | ||
1102 | #endif | ||
1103 | /* Set bitfield accordingly */ | ||
1104 | switch (var->bits_per_pixel) { | ||
1105 | case 16: | ||
1106 | { | ||
1107 | /* 16bpp True color. | ||
1108 | * These must be set to MATCH WINCTRL[FORM] */ | ||
1109 | int idx; | ||
1110 | idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25; | ||
1111 | var->red = rgb_bitfields[idx][0]; | ||
1112 | var->green = rgb_bitfields[idx][1]; | ||
1113 | var->blue = rgb_bitfields[idx][2]; | ||
1114 | var->transp = rgb_bitfields[idx][3]; | ||
1115 | break; | ||
1116 | } | ||
1117 | |||
1118 | case 32: | ||
1119 | { | ||
1120 | /* 32bpp True color. | ||
1121 | * These must be set to MATCH WINCTRL[FORM] */ | ||
1122 | int idx; | ||
1123 | idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25; | ||
1124 | var->red = rgb_bitfields[idx][0]; | ||
1125 | var->green = rgb_bitfields[idx][1]; | ||
1126 | var->blue = rgb_bitfields[idx][2]; | ||
1127 | var->transp = rgb_bitfields[idx][3]; | ||
1128 | break; | ||
1129 | } | ||
1130 | default: | ||
1131 | print_dbg("Unsupported depth %dbpp", var->bits_per_pixel); | ||
1132 | return -EINVAL; | ||
1133 | } | ||
1134 | |||
1135 | return 0; | ||
1136 | } | ||
1137 | |||
1138 | /* fb_set_par | ||
1139 | * Set hardware with var settings. This will enable the controller with a | ||
1140 | * specific mode, normally validated with the fb_check_var method | ||
1141 | */ | ||
1142 | static int au1200fb_fb_set_par(struct fb_info *fbi) | ||
1143 | { | ||
1144 | struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi; | ||
1145 | |||
1146 | au1200fb_update_fbinfo(fbi); | ||
1147 | au1200_setmode(fbdev); | ||
1148 | |||
1149 | return 0; | ||
1150 | } | ||
1151 | |||
1152 | /* fb_setcolreg | ||
1153 | * Set color in LCD palette. | ||
1154 | */ | ||
1155 | static int au1200fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green, | ||
1156 | unsigned blue, unsigned transp, struct fb_info *fbi) | ||
1157 | { | ||
1158 | volatile u32 *palette = lcd->palette; | ||
1159 | u32 value; | ||
1160 | |||
1161 | if (regno > (AU1200_LCD_NBR_PALETTE_ENTRIES - 1)) | ||
1162 | return -EINVAL; | ||
1163 | |||
1164 | if (fbi->var.grayscale) { | ||
1165 | /* Convert color to grayscale */ | ||
1166 | red = green = blue = | ||
1167 | (19595 * red + 38470 * green + 7471 * blue) >> 16; | ||
1168 | } | ||
1169 | |||
1170 | if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) { | ||
1171 | /* Place color in the pseudopalette */ | ||
1172 | if (regno > 16) | ||
1173 | return -EINVAL; | ||
1174 | |||
1175 | palette = (u32*) fbi->pseudo_palette; | ||
1176 | |||
1177 | red >>= (16 - fbi->var.red.length); | ||
1178 | green >>= (16 - fbi->var.green.length); | ||
1179 | blue >>= (16 - fbi->var.blue.length); | ||
1180 | |||
1181 | value = (red << fbi->var.red.offset) | | ||
1182 | (green << fbi->var.green.offset)| | ||
1183 | (blue << fbi->var.blue.offset); | ||
1184 | value &= 0xFFFF; | ||
1185 | |||
1186 | } else if (1 /*FIX!!! panel_is_active(fbdev->panel)*/) { | ||
1187 | /* COLOR TFT PALLETTIZED (use RGB 565) */ | ||
1188 | value = (red & 0xF800)|((green >> 5) & | ||
1189 | 0x07E0)|((blue >> 11) & 0x001F); | ||
1190 | value &= 0xFFFF; | ||
1191 | |||
1192 | } else if (0 /*panel_is_color(fbdev->panel)*/) { | ||
1193 | /* COLOR STN MODE */ | ||
1194 | value = 0x1234; | ||
1195 | value &= 0xFFF; | ||
1196 | } else { | ||
1197 | /* MONOCHROME MODE */ | ||
1198 | value = (green >> 12) & 0x000F; | ||
1199 | value &= 0xF; | ||
1200 | } | ||
1201 | |||
1202 | palette[regno] = value; | ||
1203 | |||
1204 | return 0; | ||
1205 | } | ||
1206 | |||
1207 | /* fb_blank | ||
1208 | * Blank the screen. Depending on the mode, the screen will be | ||
1209 | * activated with the backlight color, or desactivated | ||
1210 | */ | ||
1211 | static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi) | ||
1212 | { | ||
1213 | /* Short-circuit screen blanking */ | ||
1214 | if (noblanking) | ||
1215 | return 0; | ||
1216 | |||
1217 | switch (blank_mode) { | ||
1218 | |||
1219 | case FB_BLANK_UNBLANK: | ||
1220 | case FB_BLANK_NORMAL: | ||
1221 | /* printk("turn on panel\n"); */ | ||
1222 | au1200_setpanel(panel); | ||
1223 | break; | ||
1224 | case FB_BLANK_VSYNC_SUSPEND: | ||
1225 | case FB_BLANK_HSYNC_SUSPEND: | ||
1226 | case FB_BLANK_POWERDOWN: | ||
1227 | /* printk("turn off panel\n"); */ | ||
1228 | au1200_setpanel(NULL); | ||
1229 | break; | ||
1230 | default: | ||
1231 | break; | ||
1232 | |||
1233 | } | ||
1234 | |||
1235 | /* FB_BLANK_NORMAL is a soft blank */ | ||
1236 | return (blank_mode == FB_BLANK_NORMAL) ? -EINVAL : 0; | ||
1237 | } | ||
1238 | |||
1239 | /* fb_mmap | ||
1240 | * Map video memory in user space. We don't use the generic fb_mmap | ||
1241 | * method mainly to allow the use of the TLB streaming flag (CCA=6) | ||
1242 | */ | ||
1243 | static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) | ||
1244 | |||
1245 | { | ||
1246 | unsigned int len; | ||
1247 | unsigned long start=0, off; | ||
1248 | struct au1200fb_device *fbdev = (struct au1200fb_device *) info; | ||
1249 | |||
1250 | #ifdef CONFIG_PM | ||
1251 | au1xxx_pm_access(LCD_pm_dev); | ||
1252 | #endif | ||
1253 | |||
1254 | if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) { | ||
1255 | return -EINVAL; | ||
1256 | } | ||
1257 | |||
1258 | start = fbdev->fb_phys & PAGE_MASK; | ||
1259 | len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len); | ||
1260 | |||
1261 | off = vma->vm_pgoff << PAGE_SHIFT; | ||
1262 | |||
1263 | if ((vma->vm_end - vma->vm_start + off) > len) { | ||
1264 | return -EINVAL; | ||
1265 | } | ||
1266 | |||
1267 | off += start; | ||
1268 | vma->vm_pgoff = off >> PAGE_SHIFT; | ||
1269 | |||
1270 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
1271 | pgprot_val(vma->vm_page_prot) |= _CACHE_MASK; /* CCA=7 */ | ||
1272 | |||
1273 | vma->vm_flags |= VM_IO; | ||
1274 | |||
1275 | return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, | ||
1276 | vma->vm_end - vma->vm_start, | ||
1277 | vma->vm_page_prot); | ||
1278 | |||
1279 | return 0; | ||
1280 | } | ||
1281 | |||
1282 | static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata) | ||
1283 | { | ||
1284 | |||
1285 | unsigned int hi1, divider; | ||
1286 | |||
1287 | /* SCREEN_SIZE: user cannot reset size, must switch panel choice */ | ||
1288 | |||
1289 | if (pdata->flags & SCREEN_BACKCOLOR) | ||
1290 | lcd->backcolor = pdata->backcolor; | ||
1291 | |||
1292 | if (pdata->flags & SCREEN_BRIGHTNESS) { | ||
1293 | |||
1294 | // limit brightness pwm duty to >= 30/1600 | ||
1295 | if (pdata->brightness < 30) { | ||
1296 | pdata->brightness = 30; | ||
1297 | } | ||
1298 | divider = (lcd->pwmdiv & 0x3FFFF) + 1; | ||
1299 | hi1 = (lcd->pwmhi >> 16) + 1; | ||
1300 | hi1 = (((pdata->brightness & 0xFF)+1) * divider >> 8); | ||
1301 | lcd->pwmhi &= 0xFFFF; | ||
1302 | lcd->pwmhi |= (hi1 << 16); | ||
1303 | } | ||
1304 | |||
1305 | if (pdata->flags & SCREEN_COLORKEY) | ||
1306 | lcd->colorkey = pdata->colorkey; | ||
1307 | |||
1308 | if (pdata->flags & SCREEN_MASK) | ||
1309 | lcd->colorkeymsk = pdata->mask; | ||
1310 | au_sync(); | ||
1311 | } | ||
1312 | |||
1313 | static void get_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata) | ||
1314 | { | ||
1315 | unsigned int hi1, divider; | ||
1316 | |||
1317 | pdata->xsize = ((lcd->screen & LCD_SCREEN_SX) >> 19) + 1; | ||
1318 | pdata->ysize = ((lcd->screen & LCD_SCREEN_SY) >> 8) + 1; | ||
1319 | |||
1320 | pdata->backcolor = lcd->backcolor; | ||
1321 | pdata->colorkey = lcd->colorkey; | ||
1322 | pdata->mask = lcd->colorkeymsk; | ||
1323 | |||
1324 | // brightness | ||
1325 | hi1 = (lcd->pwmhi >> 16) + 1; | ||
1326 | divider = (lcd->pwmdiv & 0x3FFFF) + 1; | ||
1327 | pdata->brightness = ((hi1 << 8) / divider) - 1; | ||
1328 | au_sync(); | ||
1329 | } | ||
1330 | |||
1331 | static void set_window(unsigned int plane, | ||
1332 | struct au1200_lcd_window_regs_t *pdata) | ||
1333 | { | ||
1334 | unsigned int val, bpp; | ||
1335 | |||
1336 | /* Window control register 0 */ | ||
1337 | if (pdata->flags & WIN_POSITION) { | ||
1338 | val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_OX | | ||
1339 | LCD_WINCTRL0_OY); | ||
1340 | val |= ((pdata->xpos << 21) & LCD_WINCTRL0_OX); | ||
1341 | val |= ((pdata->ypos << 10) & LCD_WINCTRL0_OY); | ||
1342 | lcd->window[plane].winctrl0 = val; | ||
1343 | } | ||
1344 | if (pdata->flags & WIN_ALPHA_COLOR) { | ||
1345 | val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_A); | ||
1346 | val |= ((pdata->alpha_color << 2) & LCD_WINCTRL0_A); | ||
1347 | lcd->window[plane].winctrl0 = val; | ||
1348 | } | ||
1349 | if (pdata->flags & WIN_ALPHA_MODE) { | ||
1350 | val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_AEN); | ||
1351 | val |= ((pdata->alpha_mode << 1) & LCD_WINCTRL0_AEN); | ||
1352 | lcd->window[plane].winctrl0 = val; | ||
1353 | } | ||
1354 | |||
1355 | /* Window control register 1 */ | ||
1356 | if (pdata->flags & WIN_PRIORITY) { | ||
1357 | val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PRI); | ||
1358 | val |= ((pdata->priority << 30) & LCD_WINCTRL1_PRI); | ||
1359 | lcd->window[plane].winctrl1 = val; | ||
1360 | } | ||
1361 | if (pdata->flags & WIN_CHANNEL) { | ||
1362 | val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PIPE); | ||
1363 | val |= ((pdata->channel << 29) & LCD_WINCTRL1_PIPE); | ||
1364 | lcd->window[plane].winctrl1 = val; | ||
1365 | } | ||
1366 | if (pdata->flags & WIN_BUFFER_FORMAT) { | ||
1367 | val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_FRM); | ||
1368 | val |= ((pdata->buffer_format << 25) & LCD_WINCTRL1_FRM); | ||
1369 | lcd->window[plane].winctrl1 = val; | ||
1370 | } | ||
1371 | if (pdata->flags & WIN_COLOR_ORDER) { | ||
1372 | val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_CCO); | ||
1373 | val |= ((pdata->color_order << 24) & LCD_WINCTRL1_CCO); | ||
1374 | lcd->window[plane].winctrl1 = val; | ||
1375 | } | ||
1376 | if (pdata->flags & WIN_PIXEL_ORDER) { | ||
1377 | val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PO); | ||
1378 | val |= ((pdata->pixel_order << 22) & LCD_WINCTRL1_PO); | ||
1379 | lcd->window[plane].winctrl1 = val; | ||
1380 | } | ||
1381 | if (pdata->flags & WIN_SIZE) { | ||
1382 | val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_SZX | | ||
1383 | LCD_WINCTRL1_SZY); | ||
1384 | val |= (((pdata->xsize << 11) - 1) & LCD_WINCTRL1_SZX); | ||
1385 | val |= (((pdata->ysize) - 1) & LCD_WINCTRL1_SZY); | ||
1386 | lcd->window[plane].winctrl1 = val; | ||
1387 | /* program buffer line width */ | ||
1388 | bpp = winbpp(val) / 8; | ||
1389 | val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_BX); | ||
1390 | val |= (((pdata->xsize * bpp) << 8) & LCD_WINCTRL2_BX); | ||
1391 | lcd->window[plane].winctrl2 = val; | ||
1392 | } | ||
1393 | |||
1394 | /* Window control register 2 */ | ||
1395 | if (pdata->flags & WIN_COLORKEY_MODE) { | ||
1396 | val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_CKMODE); | ||
1397 | val |= ((pdata->colorkey_mode << 24) & LCD_WINCTRL2_CKMODE); | ||
1398 | lcd->window[plane].winctrl2 = val; | ||
1399 | } | ||
1400 | if (pdata->flags & WIN_DOUBLE_BUFFER_MODE) { | ||
1401 | val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_DBM); | ||
1402 | val |= ((pdata->double_buffer_mode << 23) & LCD_WINCTRL2_DBM); | ||
1403 | lcd->window[plane].winctrl2 = val; | ||
1404 | } | ||
1405 | if (pdata->flags & WIN_RAM_ARRAY_MODE) { | ||
1406 | val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_RAM); | ||
1407 | val |= ((pdata->ram_array_mode << 21) & LCD_WINCTRL2_RAM); | ||
1408 | lcd->window[plane].winctrl2 = val; | ||
1409 | } | ||
1410 | |||
1411 | /* Buffer line width programmed with WIN_SIZE */ | ||
1412 | |||
1413 | if (pdata->flags & WIN_BUFFER_SCALE) { | ||
1414 | val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_SCX | | ||
1415 | LCD_WINCTRL2_SCY); | ||
1416 | val |= ((pdata->xsize << 11) & LCD_WINCTRL2_SCX); | ||
1417 | val |= ((pdata->ysize) & LCD_WINCTRL2_SCY); | ||
1418 | lcd->window[plane].winctrl2 = val; | ||
1419 | } | ||
1420 | |||
1421 | if (pdata->flags & WIN_ENABLE) { | ||
1422 | val = lcd->winenable; | ||
1423 | val &= ~(1<<plane); | ||
1424 | val |= (pdata->enable & 1) << plane; | ||
1425 | lcd->winenable = val; | ||
1426 | } | ||
1427 | au_sync(); | ||
1428 | } | ||
1429 | |||
1430 | static void get_window(unsigned int plane, | ||
1431 | struct au1200_lcd_window_regs_t *pdata) | ||
1432 | { | ||
1433 | /* Window control register 0 */ | ||
1434 | pdata->xpos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OX) >> 21; | ||
1435 | pdata->ypos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OY) >> 10; | ||
1436 | pdata->alpha_color = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_A) >> 2; | ||
1437 | pdata->alpha_mode = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_AEN) >> 1; | ||
1438 | |||
1439 | /* Window control register 1 */ | ||
1440 | pdata->priority = (lcd->window[plane].winctrl1& LCD_WINCTRL1_PRI) >> 30; | ||
1441 | pdata->channel = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PIPE) >> 29; | ||
1442 | pdata->buffer_format = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_FRM) >> 25; | ||
1443 | pdata->color_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_CCO) >> 24; | ||
1444 | pdata->pixel_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PO) >> 22; | ||
1445 | pdata->xsize = ((lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZX) >> 11) + 1; | ||
1446 | pdata->ysize = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZY) + 1; | ||
1447 | |||
1448 | /* Window control register 2 */ | ||
1449 | pdata->colorkey_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_CKMODE) >> 24; | ||
1450 | pdata->double_buffer_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_DBM) >> 23; | ||
1451 | pdata->ram_array_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_RAM) >> 21; | ||
1452 | |||
1453 | pdata->enable = (lcd->winenable >> plane) & 1; | ||
1454 | au_sync(); | ||
1455 | } | ||
1456 | |||
1457 | static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd, | ||
1458 | unsigned long arg) | ||
1459 | { | ||
1460 | int plane; | ||
1461 | int val; | ||
1462 | |||
1463 | #ifdef CONFIG_PM | ||
1464 | au1xxx_pm_access(LCD_pm_dev); | ||
1465 | #endif | ||
1466 | |||
1467 | plane = fbinfo2index(info); | ||
1468 | print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane); | ||
1469 | |||
1470 | if (cmd == AU1200_LCD_FB_IOCTL) { | ||
1471 | struct au1200_lcd_iodata_t iodata; | ||
1472 | |||
1473 | if (copy_from_user(&iodata, (void __user *) arg, sizeof(iodata))) | ||
1474 | return -EFAULT; | ||
1475 | |||
1476 | print_dbg("FB IOCTL called\n"); | ||
1477 | |||
1478 | switch (iodata.subcmd) { | ||
1479 | case AU1200_LCD_SET_SCREEN: | ||
1480 | print_dbg("AU1200_LCD_SET_SCREEN\n"); | ||
1481 | set_global(cmd, &iodata.global); | ||
1482 | break; | ||
1483 | |||
1484 | case AU1200_LCD_GET_SCREEN: | ||
1485 | print_dbg("AU1200_LCD_GET_SCREEN\n"); | ||
1486 | get_global(cmd, &iodata.global); | ||
1487 | break; | ||
1488 | |||
1489 | case AU1200_LCD_SET_WINDOW: | ||
1490 | print_dbg("AU1200_LCD_SET_WINDOW\n"); | ||
1491 | set_window(plane, &iodata.window); | ||
1492 | break; | ||
1493 | |||
1494 | case AU1200_LCD_GET_WINDOW: | ||
1495 | print_dbg("AU1200_LCD_GET_WINDOW\n"); | ||
1496 | get_window(plane, &iodata.window); | ||
1497 | break; | ||
1498 | |||
1499 | case AU1200_LCD_SET_PANEL: | ||
1500 | print_dbg("AU1200_LCD_SET_PANEL\n"); | ||
1501 | if ((iodata.global.panel_choice >= 0) && | ||
1502 | (iodata.global.panel_choice < | ||
1503 | NUM_PANELS)) | ||
1504 | { | ||
1505 | struct panel_settings *newpanel; | ||
1506 | panel_index = iodata.global.panel_choice; | ||
1507 | newpanel = &known_lcd_panels[panel_index]; | ||
1508 | au1200_setpanel(newpanel); | ||
1509 | } | ||
1510 | break; | ||
1511 | |||
1512 | case AU1200_LCD_GET_PANEL: | ||
1513 | print_dbg("AU1200_LCD_GET_PANEL\n"); | ||
1514 | iodata.global.panel_choice = panel_index; | ||
1515 | break; | ||
1516 | |||
1517 | default: | ||
1518 | return -EINVAL; | ||
1519 | } | ||
1520 | |||
1521 | val = copy_to_user((void __user *) arg, &iodata, sizeof(iodata)); | ||
1522 | if (val) { | ||
1523 | print_dbg("error: could not copy %d bytes\n", val); | ||
1524 | return -EFAULT; | ||
1525 | } | ||
1526 | } | ||
1527 | |||
1528 | return 0; | ||
1529 | } | ||
1530 | |||
1531 | |||
1532 | static struct fb_ops au1200fb_fb_ops = { | ||
1533 | .owner = THIS_MODULE, | ||
1534 | .fb_check_var = au1200fb_fb_check_var, | ||
1535 | .fb_set_par = au1200fb_fb_set_par, | ||
1536 | .fb_setcolreg = au1200fb_fb_setcolreg, | ||
1537 | .fb_blank = au1200fb_fb_blank, | ||
1538 | .fb_fillrect = cfb_fillrect, | ||
1539 | .fb_copyarea = cfb_copyarea, | ||
1540 | .fb_imageblit = cfb_imageblit, | ||
1541 | .fb_sync = NULL, | ||
1542 | .fb_ioctl = au1200fb_ioctl, | ||
1543 | .fb_mmap = au1200fb_fb_mmap, | ||
1544 | }; | ||
1545 | |||
1546 | /*-------------------------------------------------------------------------*/ | ||
1547 | |||
1548 | static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id, struct pt_regs *regs) | ||
1549 | { | ||
1550 | /* Nothing to do for now, just clear any pending interrupt */ | ||
1551 | lcd->intstatus = lcd->intstatus; | ||
1552 | au_sync(); | ||
1553 | |||
1554 | return IRQ_HANDLED; | ||
1555 | } | ||
1556 | |||
1557 | /*-------------------------------------------------------------------------*/ | ||
1558 | |||
1559 | /* AU1200 LCD device probe helpers */ | ||
1560 | |||
1561 | static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev) | ||
1562 | { | ||
1563 | struct fb_info *fbi = &fbdev->fb_info; | ||
1564 | int bpp; | ||
1565 | |||
1566 | memset(fbi, 0, sizeof(struct fb_info)); | ||
1567 | fbi->fbops = &au1200fb_fb_ops; | ||
1568 | |||
1569 | bpp = winbpp(win->w[fbdev->plane].mode_winctrl1); | ||
1570 | |||
1571 | /* Copy monitor specs from panel data */ | ||
1572 | /* fixme: we're setting up LCD controller windows, so these dont give a | ||
1573 | damn as to what the monitor specs are (the panel itself does, but that | ||
1574 | isnt done here...so maybe need a generic catchall monitor setting??? */ | ||
1575 | memcpy(&fbi->monspecs, &panel->monspecs, sizeof(struct fb_monspecs)); | ||
1576 | |||
1577 | /* We first try the user mode passed in argument. If that failed, | ||
1578 | * or if no one has been specified, we default to the first mode of the | ||
1579 | * panel list. Note that after this call, var data will be set */ | ||
1580 | if (!fb_find_mode(&fbi->var, | ||
1581 | fbi, | ||
1582 | NULL, /* drv_info.opt_mode, */ | ||
1583 | fbi->monspecs.modedb, | ||
1584 | fbi->monspecs.modedb_len, | ||
1585 | fbi->monspecs.modedb, | ||
1586 | bpp)) { | ||
1587 | |||
1588 | print_err("Cannot find valid mode for panel %s", panel->name); | ||
1589 | return -EFAULT; | ||
1590 | } | ||
1591 | |||
1592 | fbi->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); | ||
1593 | if (!fbi->pseudo_palette) { | ||
1594 | return -ENOMEM; | ||
1595 | } | ||
1596 | memset(fbi->pseudo_palette, 0, sizeof(u32) * 16); | ||
1597 | |||
1598 | if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { | ||
1599 | print_err("Fail to allocate colormap (%d entries)", | ||
1600 | AU1200_LCD_NBR_PALETTE_ENTRIES); | ||
1601 | kfree(fbi->pseudo_palette); | ||
1602 | return -EFAULT; | ||
1603 | } | ||
1604 | |||
1605 | strncpy(fbi->fix.id, "AU1200", sizeof(fbi->fix.id)); | ||
1606 | fbi->fix.smem_start = fbdev->fb_phys; | ||
1607 | fbi->fix.smem_len = fbdev->fb_len; | ||
1608 | fbi->fix.type = FB_TYPE_PACKED_PIXELS; | ||
1609 | fbi->fix.xpanstep = 0; | ||
1610 | fbi->fix.ypanstep = 0; | ||
1611 | fbi->fix.mmio_start = 0; | ||
1612 | fbi->fix.mmio_len = 0; | ||
1613 | fbi->fix.accel = FB_ACCEL_NONE; | ||
1614 | |||
1615 | fbi->screen_base = (char __iomem *) fbdev->fb_mem; | ||
1616 | |||
1617 | au1200fb_update_fbinfo(fbi); | ||
1618 | |||
1619 | return 0; | ||
1620 | } | ||
1621 | |||
1622 | /*-------------------------------------------------------------------------*/ | ||
1623 | |||
1624 | /* AU1200 LCD controller device driver */ | ||
1625 | |||
1626 | static int au1200fb_drv_probe(struct device *dev) | ||
1627 | { | ||
1628 | struct au1200fb_device *fbdev; | ||
1629 | unsigned long page; | ||
1630 | int bpp, plane, ret; | ||
1631 | |||
1632 | if (!dev) | ||
1633 | return -EINVAL; | ||
1634 | |||
1635 | for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) { | ||
1636 | bpp = winbpp(win->w[plane].mode_winctrl1); | ||
1637 | if (win->w[plane].xres == 0) | ||
1638 | win->w[plane].xres = panel->Xres; | ||
1639 | if (win->w[plane].yres == 0) | ||
1640 | win->w[plane].yres = panel->Yres; | ||
1641 | |||
1642 | fbdev = &_au1200fb_devices[plane]; | ||
1643 | memset(fbdev, 0, sizeof(struct au1200fb_device)); | ||
1644 | fbdev->plane = plane; | ||
1645 | |||
1646 | /* Allocate the framebuffer to the maximum screen size */ | ||
1647 | fbdev->fb_len = (win->w[plane].xres * win->w[plane].yres * bpp) / 8; | ||
1648 | |||
1649 | fbdev->fb_mem = dma_alloc_noncoherent(dev, | ||
1650 | PAGE_ALIGN(fbdev->fb_len), | ||
1651 | &fbdev->fb_phys, GFP_KERNEL); | ||
1652 | if (!fbdev->fb_mem) { | ||
1653 | print_err("fail to allocate frambuffer (size: %dK))", | ||
1654 | fbdev->fb_len / 1024); | ||
1655 | return -ENOMEM; | ||
1656 | } | ||
1657 | |||
1658 | /* | ||
1659 | * Set page reserved so that mmap will work. This is necessary | ||
1660 | * since we'll be remapping normal memory. | ||
1661 | */ | ||
1662 | for (page = (unsigned long)fbdev->fb_phys; | ||
1663 | page < PAGE_ALIGN((unsigned long)fbdev->fb_phys + | ||
1664 | fbdev->fb_len); | ||
1665 | page += PAGE_SIZE) { | ||
1666 | SetPageReserved(pfn_to_page(page >> PAGE_SHIFT)); /* LCD DMA is NOT coherent on Au1200 */ | ||
1667 | } | ||
1668 | print_dbg("Framebuffer memory map at %p", fbdev->fb_mem); | ||
1669 | print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024); | ||
1670 | |||
1671 | /* Init FB data */ | ||
1672 | if ((ret = au1200fb_init_fbinfo(fbdev)) < 0) | ||
1673 | goto failed; | ||
1674 | |||
1675 | /* Register new framebuffer */ | ||
1676 | if ((ret = register_framebuffer(&fbdev->fb_info)) < 0) { | ||
1677 | print_err("cannot register new framebuffer"); | ||
1678 | goto failed; | ||
1679 | } | ||
1680 | |||
1681 | au1200fb_fb_set_par(&fbdev->fb_info); | ||
1682 | |||
1683 | #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) | ||
1684 | if (plane == 0) | ||
1685 | if (fb_prepare_logo(&fbdev->fb_info, FB_ROTATE_UR)) { | ||
1686 | /* Start display and show logo on boot */ | ||
1687 | fb_set_cmap(&fbdev->fb_info.cmap, | ||
1688 | &fbdev->fb_info); | ||
1689 | |||
1690 | fb_show_logo(&fbdev->fb_info, FB_ROTATE_UR); | ||
1691 | } | ||
1692 | #endif | ||
1693 | } | ||
1694 | |||
1695 | /* Now hook interrupt too */ | ||
1696 | if ((ret = request_irq(AU1200_LCD_INT, au1200fb_handle_irq, | ||
1697 | SA_INTERRUPT | SA_SHIRQ, "lcd", (void *)dev)) < 0) { | ||
1698 | print_err("fail to request interrupt line %d (err: %d)", | ||
1699 | AU1200_LCD_INT, ret); | ||
1700 | goto failed; | ||
1701 | } | ||
1702 | |||
1703 | return 0; | ||
1704 | |||
1705 | failed: | ||
1706 | /* NOTE: This only does the current plane/window that failed; others are still active */ | ||
1707 | if (fbdev->fb_mem) | ||
1708 | dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len), | ||
1709 | fbdev->fb_mem, fbdev->fb_phys); | ||
1710 | if (fbdev->fb_info.cmap.len != 0) | ||
1711 | fb_dealloc_cmap(&fbdev->fb_info.cmap); | ||
1712 | if (fbdev->fb_info.pseudo_palette) | ||
1713 | kfree(fbdev->fb_info.pseudo_palette); | ||
1714 | if (plane == 0) | ||
1715 | free_irq(AU1200_LCD_INT, (void*)dev); | ||
1716 | return ret; | ||
1717 | } | ||
1718 | |||
1719 | static int au1200fb_drv_remove(struct device *dev) | ||
1720 | { | ||
1721 | struct au1200fb_device *fbdev; | ||
1722 | int plane; | ||
1723 | |||
1724 | if (!dev) | ||
1725 | return -ENODEV; | ||
1726 | |||
1727 | /* Turn off the panel */ | ||
1728 | au1200_setpanel(NULL); | ||
1729 | |||
1730 | for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) | ||
1731 | { | ||
1732 | fbdev = &_au1200fb_devices[plane]; | ||
1733 | |||
1734 | /* Clean up all probe data */ | ||
1735 | unregister_framebuffer(&fbdev->fb_info); | ||
1736 | if (fbdev->fb_mem) | ||
1737 | dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len), | ||
1738 | fbdev->fb_mem, fbdev->fb_phys); | ||
1739 | if (fbdev->fb_info.cmap.len != 0) | ||
1740 | fb_dealloc_cmap(&fbdev->fb_info.cmap); | ||
1741 | if (fbdev->fb_info.pseudo_palette) | ||
1742 | kfree(fbdev->fb_info.pseudo_palette); | ||
1743 | } | ||
1744 | |||
1745 | free_irq(AU1200_LCD_INT, (void *)dev); | ||
1746 | |||
1747 | return 0; | ||
1748 | } | ||
1749 | |||
1750 | #ifdef CONFIG_PM | ||
1751 | static int au1200fb_drv_suspend(struct device *dev, u32 state, u32 level) | ||
1752 | { | ||
1753 | /* TODO */ | ||
1754 | return 0; | ||
1755 | } | ||
1756 | |||
1757 | static int au1200fb_drv_resume(struct device *dev, u32 level) | ||
1758 | { | ||
1759 | /* TODO */ | ||
1760 | return 0; | ||
1761 | } | ||
1762 | #endif /* CONFIG_PM */ | ||
1763 | |||
1764 | static struct device_driver au1200fb_driver = { | ||
1765 | .name = "au1200-lcd", | ||
1766 | .bus = &platform_bus_type, | ||
1767 | .probe = au1200fb_drv_probe, | ||
1768 | .remove = au1200fb_drv_remove, | ||
1769 | #ifdef CONFIG_PM | ||
1770 | .suspend = au1200fb_drv_suspend, | ||
1771 | .resume = au1200fb_drv_resume, | ||
1772 | #endif | ||
1773 | }; | ||
1774 | |||
1775 | /*-------------------------------------------------------------------------*/ | ||
1776 | |||
1777 | /* Kernel driver */ | ||
1778 | |||
1779 | static void au1200fb_setup(void) | ||
1780 | { | ||
1781 | char* options = NULL; | ||
1782 | char* this_opt; | ||
1783 | int num_panels = ARRAY_SIZE(known_lcd_panels); | ||
1784 | int panel_idx = -1; | ||
1785 | |||
1786 | fb_get_options(DRIVER_NAME, &options); | ||
1787 | |||
1788 | if (options) { | ||
1789 | while ((this_opt = strsep(&options,",")) != NULL) { | ||
1790 | /* Panel option - can be panel name, | ||
1791 | * "bs" for board-switch, or number/index */ | ||
1792 | if (!strncmp(this_opt, "panel:", 6)) { | ||
1793 | int i; | ||
1794 | long int li; | ||
1795 | char *endptr; | ||
1796 | this_opt += 6; | ||
1797 | /* First check for index, which allows | ||
1798 | * to short circuit this mess */ | ||
1799 | li = simple_strtol(this_opt, &endptr, 0); | ||
1800 | if (*endptr == '\0') { | ||
1801 | panel_idx = (int)li; | ||
1802 | } | ||
1803 | else if (strcmp(this_opt, "bs") == 0) { | ||
1804 | extern int board_au1200fb_panel(void); | ||
1805 | panel_idx = board_au1200fb_panel(); | ||
1806 | } | ||
1807 | |||
1808 | else | ||
1809 | for (i = 0; i < num_panels; i++) { | ||
1810 | if (!strcmp(this_opt, known_lcd_panels[i].name)) { | ||
1811 | panel_idx = i; | ||
1812 | break; | ||
1813 | } | ||
1814 | } | ||
1815 | |||
1816 | if ((panel_idx < 0) || (panel_idx >= num_panels)) { | ||
1817 | print_warn("Panel %s not supported!", this_opt); | ||
1818 | } | ||
1819 | else | ||
1820 | panel_index = panel_idx; | ||
1821 | } | ||
1822 | |||
1823 | else if (strncmp(this_opt, "nohwcursor", 10) == 0) { | ||
1824 | nohwcursor = 1; | ||
1825 | } | ||
1826 | |||
1827 | /* Unsupported option */ | ||
1828 | else { | ||
1829 | print_warn("Unsupported option \"%s\"", this_opt); | ||
1830 | } | ||
1831 | } | ||
1832 | } | ||
1833 | } | ||
1834 | |||
1835 | #ifdef CONFIG_PM | ||
1836 | static int au1200fb_pm_callback(au1xxx_power_dev_t *dev, | ||
1837 | au1xxx_request_t request, void *data) { | ||
1838 | int retval = -1; | ||
1839 | unsigned int d = 0; | ||
1840 | unsigned int brightness = 0; | ||
1841 | |||
1842 | if (request == AU1XXX_PM_SLEEP) { | ||
1843 | board_au1200fb_panel_shutdown(); | ||
1844 | } | ||
1845 | else if (request == AU1XXX_PM_WAKEUP) { | ||
1846 | if(dev->prev_state == SLEEP_STATE) | ||
1847 | { | ||
1848 | int plane; | ||
1849 | au1200_setpanel(panel); | ||
1850 | for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) { | ||
1851 | struct au1200fb_device *fbdev; | ||
1852 | fbdev = &_au1200fb_devices[plane]; | ||
1853 | au1200fb_fb_set_par(&fbdev->fb_info); | ||
1854 | } | ||
1855 | } | ||
1856 | |||
1857 | d = *((unsigned int*)data); | ||
1858 | if(d <=10) brightness = 26; | ||
1859 | else if(d<=20) brightness = 51; | ||
1860 | else if(d<=30) brightness = 77; | ||
1861 | else if(d<=40) brightness = 102; | ||
1862 | else if(d<=50) brightness = 128; | ||
1863 | else if(d<=60) brightness = 153; | ||
1864 | else if(d<=70) brightness = 179; | ||
1865 | else if(d<=80) brightness = 204; | ||
1866 | else if(d<=90) brightness = 230; | ||
1867 | else brightness = 255; | ||
1868 | set_brightness(brightness); | ||
1869 | } else if (request == AU1XXX_PM_GETSTATUS) { | ||
1870 | return dev->cur_state; | ||
1871 | } else if (request == AU1XXX_PM_ACCESS) { | ||
1872 | if (dev->cur_state != SLEEP_STATE) | ||
1873 | return retval; | ||
1874 | else { | ||
1875 | au1200_setpanel(panel); | ||
1876 | } | ||
1877 | } else if (request == AU1XXX_PM_IDLE) { | ||
1878 | } else if (request == AU1XXX_PM_CLEANUP) { | ||
1879 | } | ||
1880 | |||
1881 | return retval; | ||
1882 | } | ||
1883 | #endif | ||
1884 | |||
1885 | static int __init au1200fb_init(void) | ||
1886 | { | ||
1887 | print_info("" DRIVER_DESC ""); | ||
1888 | |||
1889 | /* Setup driver with options */ | ||
1890 | au1200fb_setup(); | ||
1891 | |||
1892 | /* Point to the panel selected */ | ||
1893 | panel = &known_lcd_panels[panel_index]; | ||
1894 | win = &windows[window_index]; | ||
1895 | |||
1896 | printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name); | ||
1897 | printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name); | ||
1898 | |||
1899 | /* Kickstart the panel, the framebuffers/windows come soon enough */ | ||
1900 | au1200_setpanel(panel); | ||
1901 | |||
1902 | #ifdef CONFIG_PM | ||
1903 | LCD_pm_dev = new_au1xxx_power_device("LCD", &au1200fb_pm_callback, NULL); | ||
1904 | if ( LCD_pm_dev == NULL) | ||
1905 | printk(KERN_INFO "Unable to create a power management device entry for the au1200fb.\n"); | ||
1906 | else | ||
1907 | printk(KERN_INFO "Power management device entry for the au1200fb loaded.\n"); | ||
1908 | #endif | ||
1909 | |||
1910 | return driver_register(&au1200fb_driver); | ||
1911 | } | ||
1912 | |||
1913 | static void __exit au1200fb_cleanup(void) | ||
1914 | { | ||
1915 | driver_unregister(&au1200fb_driver); | ||
1916 | } | ||
1917 | |||
1918 | module_init(au1200fb_init); | ||
1919 | module_exit(au1200fb_cleanup); | ||
1920 | |||
1921 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
1922 | MODULE_LICENSE("GPL"); | ||
1923 | /* | ||
1924 | * BRIEF MODULE DESCRIPTION | ||
1925 | * Au1200 LCD Driver. | ||
1926 | * | ||
1927 | * Copyright 2004-2005 AMD | ||
1928 | * Author: AMD | ||
1929 | * | ||
1930 | * Based on: | ||
1931 | * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device | ||
1932 | * Created 28 Dec 1997 by Geert Uytterhoeven | ||
1933 | * | ||
1934 | * This program is free software; you can redistribute it and/or modify it | ||
1935 | * under the terms of the GNU General Public License as published by the | ||
1936 | * Free Software Foundation; either version 2 of the License, or (at your | ||
1937 | * option) any later version. | ||
1938 | * | ||
1939 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
1940 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
1941 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
1942 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
1943 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
1944 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
1945 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
1946 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
1947 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
1948 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
1949 | * | ||
1950 | * You should have received a copy of the GNU General Public License along | ||
1951 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
1952 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
1953 | */ | ||
1954 | |||
1955 | #include <linux/module.h> | ||
1956 | #include <linux/platform_device.h> | ||
1957 | #include <linux/kernel.h> | ||
1958 | #include <linux/errno.h> | ||
1959 | #include <linux/string.h> | ||
1960 | #include <linux/mm.h> | ||
1961 | #include <linux/fb.h> | ||
1962 | #include <linux/init.h> | ||
1963 | #include <linux/interrupt.h> | ||
1964 | #include <linux/ctype.h> | ||
1965 | #include <linux/dma-mapping.h> | ||
1966 | |||
1967 | #include <asm/mach-au1x00/au1000.h> | ||
1968 | #include "au1200fb.h" | ||
1969 | |||
1970 | #ifdef CONFIG_PM | ||
1971 | #include <asm/mach-au1x00/au1xxx_pm.h> | ||
1972 | #endif | ||
1973 | |||
1974 | #ifndef CONFIG_FB_AU1200_DEVS | ||
1975 | #define CONFIG_FB_AU1200_DEVS 4 | ||
1976 | #endif | ||
1977 | |||
1978 | #define DRIVER_NAME "au1200fb" | ||
1979 | #define DRIVER_DESC "LCD controller driver for AU1200 processors" | ||
1980 | |||
1981 | #define DEBUG 1 | ||
1982 | |||
1983 | #define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg) | ||
1984 | #define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg) | ||
1985 | #define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg) | ||
1986 | |||
1987 | #if DEBUG | ||
1988 | #define print_dbg(f, arg...) printk(KERN_DEBUG __FILE__ ": " f "\n", ## arg) | ||
1989 | #else | ||
1990 | #define print_dbg(f, arg...) do {} while (0) | ||
1991 | #endif | ||
1992 | |||
1993 | |||
1994 | #define AU1200_LCD_FB_IOCTL 0x46FF | ||
1995 | |||
1996 | #define AU1200_LCD_SET_SCREEN 1 | ||
1997 | #define AU1200_LCD_GET_SCREEN 2 | ||
1998 | #define AU1200_LCD_SET_WINDOW 3 | ||
1999 | #define AU1200_LCD_GET_WINDOW 4 | ||
2000 | #define AU1200_LCD_SET_PANEL 5 | ||
2001 | #define AU1200_LCD_GET_PANEL 6 | ||
2002 | |||
2003 | #define SCREEN_SIZE (1<< 1) | ||
2004 | #define SCREEN_BACKCOLOR (1<< 2) | ||
2005 | #define SCREEN_BRIGHTNESS (1<< 3) | ||
2006 | #define SCREEN_COLORKEY (1<< 4) | ||
2007 | #define SCREEN_MASK (1<< 5) | ||
2008 | |||
2009 | struct au1200_lcd_global_regs_t { | ||
2010 | unsigned int flags; | ||
2011 | unsigned int xsize; | ||
2012 | unsigned int ysize; | ||
2013 | unsigned int backcolor; | ||
2014 | unsigned int brightness; | ||
2015 | unsigned int colorkey; | ||
2016 | unsigned int mask; | ||
2017 | unsigned int panel_choice; | ||
2018 | char panel_desc[80]; | ||
2019 | |||
2020 | }; | ||
2021 | |||
2022 | #define WIN_POSITION (1<< 0) | ||
2023 | #define WIN_ALPHA_COLOR (1<< 1) | ||
2024 | #define WIN_ALPHA_MODE (1<< 2) | ||
2025 | #define WIN_PRIORITY (1<< 3) | ||
2026 | #define WIN_CHANNEL (1<< 4) | ||
2027 | #define WIN_BUFFER_FORMAT (1<< 5) | ||
2028 | #define WIN_COLOR_ORDER (1<< 6) | ||
2029 | #define WIN_PIXEL_ORDER (1<< 7) | ||
2030 | #define WIN_SIZE (1<< 8) | ||
2031 | #define WIN_COLORKEY_MODE (1<< 9) | ||
2032 | #define WIN_DOUBLE_BUFFER_MODE (1<< 10) | ||
2033 | #define WIN_RAM_ARRAY_MODE (1<< 11) | ||
2034 | #define WIN_BUFFER_SCALE (1<< 12) | ||
2035 | #define WIN_ENABLE (1<< 13) | ||
2036 | |||
2037 | struct au1200_lcd_window_regs_t { | ||
2038 | unsigned int flags; | ||
2039 | unsigned int xpos; | ||
2040 | unsigned int ypos; | ||
2041 | unsigned int alpha_color; | ||
2042 | unsigned int alpha_mode; | ||
2043 | unsigned int priority; | ||
2044 | unsigned int channel; | ||
2045 | unsigned int buffer_format; | ||
2046 | unsigned int color_order; | ||
2047 | unsigned int pixel_order; | ||
2048 | unsigned int xsize; | ||
2049 | unsigned int ysize; | ||
2050 | unsigned int colorkey_mode; | ||
2051 | unsigned int double_buffer_mode; | ||
2052 | unsigned int ram_array_mode; | ||
2053 | unsigned int xscale; | ||
2054 | unsigned int yscale; | ||
2055 | unsigned int enable; | ||
2056 | }; | ||
2057 | |||
2058 | |||
2059 | struct au1200_lcd_iodata_t { | ||
2060 | unsigned int subcmd; | ||
2061 | struct au1200_lcd_global_regs_t global; | ||
2062 | struct au1200_lcd_window_regs_t window; | ||
2063 | }; | ||
2064 | |||
2065 | #if defined(__BIG_ENDIAN) | ||
2066 | #define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_11 | ||
2067 | #else | ||
2068 | #define LCD_CONTROL_DEFAULT_PO LCD_CONTROL_PO_00 | ||
2069 | #endif | ||
2070 | #define LCD_CONTROL_DEFAULT_SBPPF LCD_CONTROL_SBPPF_565 | ||
2071 | |||
2072 | /* Private, per-framebuffer management information (independent of the panel itself) */ | ||
2073 | struct au1200fb_device { | ||
2074 | struct fb_info fb_info; /* FB driver info record */ | ||
2075 | |||
2076 | int plane; | ||
2077 | unsigned char* fb_mem; /* FrameBuffer memory map */ | ||
2078 | unsigned int fb_len; | ||
2079 | dma_addr_t fb_phys; | ||
2080 | }; | ||
2081 | |||
2082 | static struct au1200fb_device _au1200fb_devices[CONFIG_FB_AU1200_DEVS]; | ||
2083 | /********************************************************************/ | ||
2084 | |||
2085 | /* LCD controller restrictions */ | ||
2086 | #define AU1200_LCD_MAX_XRES 1280 | ||
2087 | #define AU1200_LCD_MAX_YRES 1024 | ||
2088 | #define AU1200_LCD_MAX_BPP 32 | ||
2089 | #define AU1200_LCD_MAX_CLK 96000000 /* fixme: this needs to go away ? */ | ||
2090 | #define AU1200_LCD_NBR_PALETTE_ENTRIES 256 | ||
2091 | |||
2092 | /* Default number of visible screen buffer to allocate */ | ||
2093 | #define AU1200FB_NBR_VIDEO_BUFFERS 1 | ||
2094 | |||
2095 | /********************************************************************/ | ||
2096 | |||
2097 | static struct au1200_lcd *lcd = (struct au1200_lcd *) AU1200_LCD_ADDR; | ||
2098 | static int window_index = 2; /* default is zero */ | ||
2099 | static int panel_index = 2; /* default is zero */ | ||
2100 | static struct window_settings *win; | ||
2101 | static struct panel_settings *panel; | ||
2102 | static int noblanking = 1; | ||
2103 | static int nohwcursor = 0; | ||
2104 | |||
2105 | struct window_settings { | ||
2106 | unsigned char name[64]; | ||
2107 | uint32 mode_backcolor; | ||
2108 | uint32 mode_colorkey; | ||
2109 | uint32 mode_colorkeymsk; | ||
2110 | struct { | ||
2111 | int xres; | ||
2112 | int yres; | ||
2113 | int xpos; | ||
2114 | int ypos; | ||
2115 | uint32 mode_winctrl1; /* winctrl1[FRM,CCO,PO,PIPE] */ | ||
2116 | uint32 mode_winenable; | ||
2117 | } w[4]; | ||
2118 | }; | ||
2119 | |||
2120 | #if defined(__BIG_ENDIAN) | ||
2121 | #define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_00 | ||
2122 | #else | ||
2123 | #define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01 | ||
2124 | #endif | ||
2125 | |||
2126 | extern int board_au1200fb_panel_init (void); | ||
2127 | extern int board_au1200fb_panel_shutdown (void); | ||
2128 | |||
2129 | #ifdef CONFIG_PM | ||
2130 | int au1200fb_pm_callback(au1xxx_power_dev_t *dev, | ||
2131 | au1xxx_request_t request, void *data); | ||
2132 | au1xxx_power_dev_t *LCD_pm_dev; | ||
2133 | #endif | ||
2134 | |||
2135 | /* | ||
2136 | * Default window configurations | ||
2137 | */ | ||
2138 | static struct window_settings windows[] = { | ||
2139 | { /* Index 0 */ | ||
2140 | "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx", | ||
2141 | /* mode_backcolor */ 0x006600ff, | ||
2142 | /* mode_colorkey,msk*/ 0, 0, | ||
2143 | { | ||
2144 | { | ||
2145 | /* xres, yres, xpos, ypos */ 0, 0, 0, 0, | ||
2146 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | | ||
2147 | LCD_WINCTRL1_PO_16BPP, | ||
2148 | /* mode_winenable*/ LCD_WINENABLE_WEN0, | ||
2149 | }, | ||
2150 | { | ||
2151 | /* xres, yres, xpos, ypos */ 100, 100, 100, 100, | ||
2152 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | | ||
2153 | LCD_WINCTRL1_PO_16BPP | | ||
2154 | LCD_WINCTRL1_PIPE, | ||
2155 | /* mode_winenable*/ LCD_WINENABLE_WEN1, | ||
2156 | }, | ||
2157 | { | ||
2158 | /* xres, yres, xpos, ypos */ 0, 0, 0, 0, | ||
2159 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | | ||
2160 | LCD_WINCTRL1_PO_16BPP, | ||
2161 | /* mode_winenable*/ 0, | ||
2162 | }, | ||
2163 | { | ||
2164 | /* xres, yres, xpos, ypos */ 0, 0, 0, 0, | ||
2165 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | | ||
2166 | LCD_WINCTRL1_PO_16BPP | | ||
2167 | LCD_WINCTRL1_PIPE, | ||
2168 | /* mode_winenable*/ 0, | ||
2169 | }, | ||
2170 | }, | ||
2171 | }, | ||
2172 | |||
2173 | { /* Index 1 */ | ||
2174 | "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx", | ||
2175 | /* mode_backcolor */ 0x006600ff, | ||
2176 | /* mode_colorkey,msk*/ 0, 0, | ||
2177 | { | ||
2178 | { | ||
2179 | /* xres, yres, xpos, ypos */ 320, 240, 5, 5, | ||
2180 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_24BPP | | ||
2181 | LCD_WINCTRL1_PO_00, | ||
2182 | /* mode_winenable*/ LCD_WINENABLE_WEN0, | ||
2183 | }, | ||
2184 | { | ||
2185 | /* xres, yres, xpos, ypos */ 0, 0, 0, 0, | ||
2186 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | ||
2187 | | LCD_WINCTRL1_PO_16BPP, | ||
2188 | /* mode_winenable*/ 0, | ||
2189 | }, | ||
2190 | { | ||
2191 | /* xres, yres, xpos, ypos */ 100, 100, 0, 0, | ||
2192 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | | ||
2193 | LCD_WINCTRL1_PO_16BPP | | ||
2194 | LCD_WINCTRL1_PIPE, | ||
2195 | /* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/, | ||
2196 | }, | ||
2197 | { | ||
2198 | /* xres, yres, xpos, ypos */ 200, 25, 0, 0, | ||
2199 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | | ||
2200 | LCD_WINCTRL1_PO_16BPP | | ||
2201 | LCD_WINCTRL1_PIPE, | ||
2202 | /* mode_winenable*/ 0, | ||
2203 | }, | ||
2204 | }, | ||
2205 | }, | ||
2206 | { /* Index 2 */ | ||
2207 | "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx", | ||
2208 | /* mode_backcolor */ 0x006600ff, | ||
2209 | /* mode_colorkey,msk*/ 0, 0, | ||
2210 | { | ||
2211 | { | ||
2212 | /* xres, yres, xpos, ypos */ 0, 0, 0, 0, | ||
2213 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | | ||
2214 | LCD_WINCTRL1_PO_16BPP, | ||
2215 | /* mode_winenable*/ LCD_WINENABLE_WEN0, | ||
2216 | }, | ||
2217 | { | ||
2218 | /* xres, yres, xpos, ypos */ 0, 0, 0, 0, | ||
2219 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | | ||
2220 | LCD_WINCTRL1_PO_16BPP, | ||
2221 | /* mode_winenable*/ 0, | ||
2222 | }, | ||
2223 | { | ||
2224 | /* xres, yres, xpos, ypos */ 0, 0, 0, 0, | ||
2225 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_32BPP | | ||
2226 | LCD_WINCTRL1_PO_00|LCD_WINCTRL1_PIPE, | ||
2227 | /* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/, | ||
2228 | }, | ||
2229 | { | ||
2230 | /* xres, yres, xpos, ypos */ 0, 0, 0, 0, | ||
2231 | /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565 | | ||
2232 | LCD_WINCTRL1_PO_16BPP | | ||
2233 | LCD_WINCTRL1_PIPE, | ||
2234 | /* mode_winenable*/ 0, | ||
2235 | }, | ||
2236 | }, | ||
2237 | }, | ||
2238 | /* Need VGA 640 @ 24bpp, @ 32bpp */ | ||
2239 | /* Need VGA 800 @ 24bpp, @ 32bpp */ | ||
2240 | /* Need VGA 1024 @ 24bpp, @ 32bpp */ | ||
2241 | }; | ||
2242 | |||
2243 | /* | ||
2244 | * Controller configurations for various panels. | ||
2245 | */ | ||
2246 | |||
2247 | struct panel_settings | ||
2248 | { | ||
2249 | const char name[25]; /* Full name <vendor>_<model> */ | ||
2250 | |||
2251 | struct fb_monspecs monspecs; /* FB monitor specs */ | ||
2252 | |||
2253 | /* panel timings */ | ||
2254 | uint32 mode_screen; | ||
2255 | uint32 mode_horztiming; | ||
2256 | uint32 mode_verttiming; | ||
2257 | uint32 mode_clkcontrol; | ||
2258 | uint32 mode_pwmdiv; | ||
2259 | uint32 mode_pwmhi; | ||
2260 | uint32 mode_outmask; | ||
2261 | uint32 mode_fifoctrl; | ||
2262 | uint32 mode_toyclksrc; | ||
2263 | uint32 mode_backlight; | ||
2264 | uint32 mode_auxpll; | ||
2265 | int (*device_init)(void); | ||
2266 | int (*device_shutdown)(void); | ||
2267 | #define Xres min_xres | ||
2268 | #define Yres min_yres | ||
2269 | u32 min_xres; /* Minimum horizontal resolution */ | ||
2270 | u32 max_xres; /* Maximum horizontal resolution */ | ||
2271 | u32 min_yres; /* Minimum vertical resolution */ | ||
2272 | u32 max_yres; /* Maximum vertical resolution */ | ||
2273 | }; | ||
2274 | |||
2275 | /********************************************************************/ | ||
2276 | /* fixme: Maybe a modedb for the CRT ? otherwise panels should be as-is */ | ||
2277 | |||
2278 | /* List of panels known to work with the AU1200 LCD controller. | ||
2279 | * To add a new panel, enter the same specifications as the | ||
2280 | * Generic_TFT one, and MAKE SURE that it doesn't conflicts | ||
2281 | * with the controller restrictions. Restrictions are: | ||
2282 | * | ||
2283 | * STN color panels: max_bpp <= 12 | ||
2284 | * STN mono panels: max_bpp <= 4 | ||
2285 | * TFT panels: max_bpp <= 16 | ||
2286 | * max_xres <= 800 | ||
2287 | * max_yres <= 600 | ||
2288 | */ | ||
2289 | static struct panel_settings known_lcd_panels[] = | ||
2290 | { | ||
2291 | [0] = { /* QVGA 320x240 H:33.3kHz V:110Hz */ | ||
2292 | .name = "QVGA_320x240", | ||
2293 | .monspecs = { | ||
2294 | .modedb = NULL, | ||
2295 | .modedb_len = 0, | ||
2296 | .hfmin = 30000, | ||
2297 | .hfmax = 70000, | ||
2298 | .vfmin = 60, | ||
2299 | .vfmax = 60, | ||
2300 | .dclkmin = 6000000, | ||
2301 | .dclkmax = 28000000, | ||
2302 | .input = FB_DISP_RGB, | ||
2303 | }, | ||
2304 | .mode_screen = LCD_SCREEN_SX_N(320) | | ||
2305 | LCD_SCREEN_SY_N(240), | ||
2306 | .mode_horztiming = 0x00c4623b, | ||
2307 | .mode_verttiming = 0x00502814, | ||
2308 | .mode_clkcontrol = 0x00020002, /* /4=24Mhz */ | ||
2309 | .mode_pwmdiv = 0x00000000, | ||
2310 | .mode_pwmhi = 0x00000000, | ||
2311 | .mode_outmask = 0x00FFFFFF, | ||
2312 | .mode_fifoctrl = 0x2f2f2f2f, | ||
2313 | .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ | ||
2314 | .mode_backlight = 0x00000000, | ||
2315 | .mode_auxpll = 8, /* 96MHz AUXPLL */ | ||
2316 | .device_init = NULL, | ||
2317 | .device_shutdown = NULL, | ||
2318 | 320, 320, | ||
2319 | 240, 240, | ||
2320 | }, | ||
2321 | |||
2322 | [1] = { /* VGA 640x480 H:30.3kHz V:58Hz */ | ||
2323 | .name = "VGA_640x480", | ||
2324 | .monspecs = { | ||
2325 | .modedb = NULL, | ||
2326 | .modedb_len = 0, | ||
2327 | .hfmin = 30000, | ||
2328 | .hfmax = 70000, | ||
2329 | .vfmin = 60, | ||
2330 | .vfmax = 60, | ||
2331 | .dclkmin = 6000000, | ||
2332 | .dclkmax = 28000000, | ||
2333 | .input = FB_DISP_RGB, | ||
2334 | }, | ||
2335 | .mode_screen = 0x13f9df80, | ||
2336 | .mode_horztiming = 0x003c5859, | ||
2337 | .mode_verttiming = 0x00741201, | ||
2338 | .mode_clkcontrol = 0x00020001, /* /4=24Mhz */ | ||
2339 | .mode_pwmdiv = 0x00000000, | ||
2340 | .mode_pwmhi = 0x00000000, | ||
2341 | .mode_outmask = 0x00FFFFFF, | ||
2342 | .mode_fifoctrl = 0x2f2f2f2f, | ||
2343 | .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ | ||
2344 | .mode_backlight = 0x00000000, | ||
2345 | .mode_auxpll = 8, /* 96MHz AUXPLL */ | ||
2346 | .device_init = NULL, | ||
2347 | .device_shutdown = NULL, | ||
2348 | 640, 480, | ||
2349 | 640, 480, | ||
2350 | }, | ||
2351 | |||
2352 | [2] = { /* SVGA 800x600 H:46.1kHz V:69Hz */ | ||
2353 | .name = "SVGA_800x600", | ||
2354 | .monspecs = { | ||
2355 | .modedb = NULL, | ||
2356 | .modedb_len = 0, | ||
2357 | .hfmin = 30000, | ||
2358 | .hfmax = 70000, | ||
2359 | .vfmin = 60, | ||
2360 | .vfmax = 60, | ||
2361 | .dclkmin = 6000000, | ||
2362 | .dclkmax = 28000000, | ||
2363 | .input = FB_DISP_RGB, | ||
2364 | }, | ||
2365 | .mode_screen = 0x18fa5780, | ||
2366 | .mode_horztiming = 0x00dc7e77, | ||
2367 | .mode_verttiming = 0x00584805, | ||
2368 | .mode_clkcontrol = 0x00020000, /* /2=48Mhz */ | ||
2369 | .mode_pwmdiv = 0x00000000, | ||
2370 | .mode_pwmhi = 0x00000000, | ||
2371 | .mode_outmask = 0x00FFFFFF, | ||
2372 | .mode_fifoctrl = 0x2f2f2f2f, | ||
2373 | .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ | ||
2374 | .mode_backlight = 0x00000000, | ||
2375 | .mode_auxpll = 8, /* 96MHz AUXPLL */ | ||
2376 | .device_init = NULL, | ||
2377 | .device_shutdown = NULL, | ||
2378 | 800, 800, | ||
2379 | 600, 600, | ||
2380 | }, | ||
2381 | |||
2382 | [3] = { /* XVGA 1024x768 H:56.2kHz V:70Hz */ | ||
2383 | .name = "XVGA_1024x768", | ||
2384 | .monspecs = { | ||
2385 | .modedb = NULL, | ||
2386 | .modedb_len = 0, | ||
2387 | .hfmin = 30000, | ||
2388 | .hfmax = 70000, | ||
2389 | .vfmin = 60, | ||
2390 | .vfmax = 60, | ||
2391 | .dclkmin = 6000000, | ||
2392 | .dclkmax = 28000000, | ||
2393 | .input = FB_DISP_RGB, | ||
2394 | }, | ||
2395 | .mode_screen = 0x1ffaff80, | ||
2396 | .mode_horztiming = 0x007d0e57, | ||
2397 | .mode_verttiming = 0x00740a01, | ||
2398 | .mode_clkcontrol = 0x000A0000, /* /1 */ | ||
2399 | .mode_pwmdiv = 0x00000000, | ||
2400 | .mode_pwmhi = 0x00000000, | ||
2401 | .mode_outmask = 0x00FFFFFF, | ||
2402 | .mode_fifoctrl = 0x2f2f2f2f, | ||
2403 | .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ | ||
2404 | .mode_backlight = 0x00000000, | ||
2405 | .mode_auxpll = 6, /* 72MHz AUXPLL */ | ||
2406 | .device_init = NULL, | ||
2407 | .device_shutdown = NULL, | ||
2408 | 1024, 1024, | ||
2409 | 768, 768, | ||
2410 | }, | ||
2411 | |||
2412 | [4] = { /* XVGA XVGA 1280x1024 H:68.5kHz V:65Hz */ | ||
2413 | .name = "XVGA_1280x1024", | ||
2414 | .monspecs = { | ||
2415 | .modedb = NULL, | ||
2416 | .modedb_len = 0, | ||
2417 | .hfmin = 30000, | ||
2418 | .hfmax = 70000, | ||
2419 | .vfmin = 60, | ||
2420 | .vfmax = 60, | ||
2421 | .dclkmin = 6000000, | ||
2422 | .dclkmax = 28000000, | ||
2423 | .input = FB_DISP_RGB, | ||
2424 | }, | ||
2425 | .mode_screen = 0x27fbff80, | ||
2426 | .mode_horztiming = 0x00cdb2c7, | ||
2427 | .mode_verttiming = 0x00600002, | ||
2428 | .mode_clkcontrol = 0x000A0000, /* /1 */ | ||
2429 | .mode_pwmdiv = 0x00000000, | ||
2430 | .mode_pwmhi = 0x00000000, | ||
2431 | .mode_outmask = 0x00FFFFFF, | ||
2432 | .mode_fifoctrl = 0x2f2f2f2f, | ||
2433 | .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ | ||
2434 | .mode_backlight = 0x00000000, | ||
2435 | .mode_auxpll = 10, /* 120MHz AUXPLL */ | ||
2436 | .device_init = NULL, | ||
2437 | .device_shutdown = NULL, | ||
2438 | 1280, 1280, | ||
2439 | 1024, 1024, | ||
2440 | }, | ||
2441 | |||
2442 | [5] = { /* Samsung 1024x768 TFT */ | ||
2443 | .name = "Samsung_1024x768_TFT", | ||
2444 | .monspecs = { | ||
2445 | .modedb = NULL, | ||
2446 | .modedb_len = 0, | ||
2447 | .hfmin = 30000, | ||
2448 | .hfmax = 70000, | ||
2449 | .vfmin = 60, | ||
2450 | .vfmax = 60, | ||
2451 | .dclkmin = 6000000, | ||
2452 | .dclkmax = 28000000, | ||
2453 | .input = FB_DISP_RGB, | ||
2454 | }, | ||
2455 | .mode_screen = 0x1ffaff80, | ||
2456 | .mode_horztiming = 0x018cc677, | ||
2457 | .mode_verttiming = 0x00241217, | ||
2458 | .mode_clkcontrol = 0x00000000, /* SCB 0x1 /4=24Mhz */ | ||
2459 | .mode_pwmdiv = 0x8000063f, /* SCB 0x0 */ | ||
2460 | .mode_pwmhi = 0x03400000, /* SCB 0x0 */ | ||
2461 | .mode_outmask = 0x00FFFFFF, | ||
2462 | .mode_fifoctrl = 0x2f2f2f2f, | ||
2463 | .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ | ||
2464 | .mode_backlight = 0x00000000, | ||
2465 | .mode_auxpll = 8, /* 96MHz AUXPLL */ | ||
2466 | .device_init = board_au1200fb_panel_init, | ||
2467 | .device_shutdown = board_au1200fb_panel_shutdown, | ||
2468 | 1024, 1024, | ||
2469 | 768, 768, | ||
2470 | }, | ||
2471 | |||
2472 | [6] = { /* Toshiba 640x480 TFT */ | ||
2473 | .name = "Toshiba_640x480_TFT", | ||
2474 | .monspecs = { | ||
2475 | .modedb = NULL, | ||
2476 | .modedb_len = 0, | ||
2477 | .hfmin = 30000, | ||
2478 | .hfmax = 70000, | ||
2479 | .vfmin = 60, | ||
2480 | .vfmax = 60, | ||
2481 | .dclkmin = 6000000, | ||
2482 | .dclkmax = 28000000, | ||
2483 | .input = FB_DISP_RGB, | ||
2484 | }, | ||
2485 | .mode_screen = LCD_SCREEN_SX_N(640) | | ||
2486 | LCD_SCREEN_SY_N(480), | ||
2487 | .mode_horztiming = LCD_HORZTIMING_HPW_N(96) | | ||
2488 | LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(51), | ||
2489 | .mode_verttiming = LCD_VERTTIMING_VPW_N(2) | | ||
2490 | LCD_VERTTIMING_VND1_N(11) | LCD_VERTTIMING_VND2_N(32), | ||
2491 | .mode_clkcontrol = 0x00000000, /* /4=24Mhz */ | ||
2492 | .mode_pwmdiv = 0x8000063f, | ||
2493 | .mode_pwmhi = 0x03400000, | ||
2494 | .mode_outmask = 0x00fcfcfc, | ||
2495 | .mode_fifoctrl = 0x2f2f2f2f, | ||
2496 | .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ | ||
2497 | .mode_backlight = 0x00000000, | ||
2498 | .mode_auxpll = 8, /* 96MHz AUXPLL */ | ||
2499 | .device_init = board_au1200fb_panel_init, | ||
2500 | .device_shutdown = board_au1200fb_panel_shutdown, | ||
2501 | 640, 480, | ||
2502 | 640, 480, | ||
2503 | }, | ||
2504 | |||
2505 | [7] = { /* Sharp 320x240 TFT */ | ||
2506 | .name = "Sharp_320x240_TFT", | ||
2507 | .monspecs = { | ||
2508 | .modedb = NULL, | ||
2509 | .modedb_len = 0, | ||
2510 | .hfmin = 12500, | ||
2511 | .hfmax = 20000, | ||
2512 | .vfmin = 38, | ||
2513 | .vfmax = 81, | ||
2514 | .dclkmin = 4500000, | ||
2515 | .dclkmax = 6800000, | ||
2516 | .input = FB_DISP_RGB, | ||
2517 | }, | ||
2518 | .mode_screen = LCD_SCREEN_SX_N(320) | | ||
2519 | LCD_SCREEN_SY_N(240), | ||
2520 | .mode_horztiming = LCD_HORZTIMING_HPW_N(60) | | ||
2521 | LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(2), | ||
2522 | .mode_verttiming = LCD_VERTTIMING_VPW_N(2) | | ||
2523 | LCD_VERTTIMING_VND1_N(2) | LCD_VERTTIMING_VND2_N(5), | ||
2524 | .mode_clkcontrol = LCD_CLKCONTROL_PCD_N(7), /*16=6Mhz*/ | ||
2525 | .mode_pwmdiv = 0x8000063f, | ||
2526 | .mode_pwmhi = 0x03400000, | ||
2527 | .mode_outmask = 0x00fcfcfc, | ||
2528 | .mode_fifoctrl = 0x2f2f2f2f, | ||
2529 | .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ | ||
2530 | .mode_backlight = 0x00000000, | ||
2531 | .mode_auxpll = 8, /* 96MHz AUXPLL */ | ||
2532 | .device_init = board_au1200fb_panel_init, | ||
2533 | .device_shutdown = board_au1200fb_panel_shutdown, | ||
2534 | 320, 320, | ||
2535 | 240, 240, | ||
2536 | }, | ||
2537 | |||
2538 | [8] = { /* Toppoly TD070WGCB2 7" 856x480 TFT */ | ||
2539 | .name = "Toppoly_TD070WGCB2", | ||
2540 | .monspecs = { | ||
2541 | .modedb = NULL, | ||
2542 | .modedb_len = 0, | ||
2543 | .hfmin = 30000, | ||
2544 | .hfmax = 70000, | ||
2545 | .vfmin = 60, | ||
2546 | .vfmax = 60, | ||
2547 | .dclkmin = 6000000, | ||
2548 | .dclkmax = 28000000, | ||
2549 | .input = FB_DISP_RGB, | ||
2550 | }, | ||
2551 | .mode_screen = LCD_SCREEN_SX_N(856) | | ||
2552 | LCD_SCREEN_SY_N(480), | ||
2553 | .mode_horztiming = LCD_HORZTIMING_HND2_N(43) | | ||
2554 | LCD_HORZTIMING_HND1_N(43) | LCD_HORZTIMING_HPW_N(114), | ||
2555 | .mode_verttiming = LCD_VERTTIMING_VND2_N(20) | | ||
2556 | LCD_VERTTIMING_VND1_N(21) | LCD_VERTTIMING_VPW_N(4), | ||
2557 | .mode_clkcontrol = 0x00020001, /* /4=24Mhz */ | ||
2558 | .mode_pwmdiv = 0x8000063f, | ||
2559 | .mode_pwmhi = 0x03400000, | ||
2560 | .mode_outmask = 0x00fcfcfc, | ||
2561 | .mode_fifoctrl = 0x2f2f2f2f, | ||
2562 | .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ | ||
2563 | .mode_backlight = 0x00000000, | ||
2564 | .mode_auxpll = 8, /* 96MHz AUXPLL */ | ||
2565 | .device_init = board_au1200fb_panel_init, | ||
2566 | .device_shutdown = board_au1200fb_panel_shutdown, | ||
2567 | 856, 856, | ||
2568 | 480, 480, | ||
2569 | }, | ||
2570 | }; | ||
2571 | |||
2572 | #define NUM_PANELS (ARRAY_SIZE(known_lcd_panels)) | ||
2573 | |||
2574 | /********************************************************************/ | ||
2575 | |||
2576 | #ifdef CONFIG_PM | ||
2577 | static int set_brightness(unsigned int brightness) | ||
2578 | { | ||
2579 | unsigned int hi1, divider; | ||
2580 | |||
2581 | /* limit brightness pwm duty to >= 30/1600 */ | ||
2582 | if (brightness < 30) { | ||
2583 | brightness = 30; | ||
2584 | } | ||
2585 | divider = (lcd->pwmdiv & 0x3FFFF) + 1; | ||
2586 | hi1 = (lcd->pwmhi >> 16) + 1; | ||
2587 | hi1 = (((brightness & 0xFF) + 1) * divider >> 8); | ||
2588 | lcd->pwmhi &= 0xFFFF; | ||
2589 | lcd->pwmhi |= (hi1 << 16); | ||
2590 | |||
2591 | return brightness; | ||
2592 | } | ||
2593 | #endif /* CONFIG_PM */ | ||
2594 | |||
2595 | static int winbpp (unsigned int winctrl1) | ||
2596 | { | ||
2597 | int bits = 0; | ||
2598 | |||
2599 | /* how many bits are needed for each pixel format */ | ||
2600 | switch (winctrl1 & LCD_WINCTRL1_FRM) { | ||
2601 | case LCD_WINCTRL1_FRM_1BPP: | ||
2602 | bits = 1; | ||
2603 | break; | ||
2604 | case LCD_WINCTRL1_FRM_2BPP: | ||
2605 | bits = 2; | ||
2606 | break; | ||
2607 | case LCD_WINCTRL1_FRM_4BPP: | ||
2608 | bits = 4; | ||
2609 | break; | ||
2610 | case LCD_WINCTRL1_FRM_8BPP: | ||
2611 | bits = 8; | ||
2612 | break; | ||
2613 | case LCD_WINCTRL1_FRM_12BPP: | ||
2614 | case LCD_WINCTRL1_FRM_16BPP655: | ||
2615 | case LCD_WINCTRL1_FRM_16BPP565: | ||
2616 | case LCD_WINCTRL1_FRM_16BPP556: | ||
2617 | case LCD_WINCTRL1_FRM_16BPPI1555: | ||
2618 | case LCD_WINCTRL1_FRM_16BPPI5551: | ||
2619 | case LCD_WINCTRL1_FRM_16BPPA1555: | ||
2620 | case LCD_WINCTRL1_FRM_16BPPA5551: | ||
2621 | bits = 16; | ||
2622 | break; | ||
2623 | case LCD_WINCTRL1_FRM_24BPP: | ||
2624 | case LCD_WINCTRL1_FRM_32BPP: | ||
2625 | bits = 32; | ||
2626 | break; | ||
2627 | } | ||
2628 | |||
2629 | return bits; | ||
2630 | } | ||
2631 | |||
2632 | static int fbinfo2index (struct fb_info *fb_info) | ||
2633 | { | ||
2634 | int i; | ||
2635 | |||
2636 | for (i = 0; i < CONFIG_FB_AU1200_DEVS; ++i) { | ||
2637 | if (fb_info == (struct fb_info *)(&_au1200fb_devices[i].fb_info)) | ||
2638 | return i; | ||
2639 | } | ||
2640 | printk("au1200fb: ERROR: fbinfo2index failed!\n"); | ||
2641 | return -1; | ||
2642 | } | ||
2643 | |||
2644 | static int au1200_setlocation (struct au1200fb_device *fbdev, int plane, | ||
2645 | int xpos, int ypos) | ||
2646 | { | ||
2647 | uint32 winctrl0, winctrl1, winenable, fb_offset = 0; | ||
2648 | int xsz, ysz; | ||
2649 | |||
2650 | /* FIX!!! NOT CHECKING FOR COMPLETE OFFSCREEN YET */ | ||
2651 | |||
2652 | winctrl0 = lcd->window[plane].winctrl0; | ||
2653 | winctrl1 = lcd->window[plane].winctrl1; | ||
2654 | winctrl0 &= (LCD_WINCTRL0_A | LCD_WINCTRL0_AEN); | ||
2655 | winctrl1 &= ~(LCD_WINCTRL1_SZX | LCD_WINCTRL1_SZY); | ||
2656 | |||
2657 | /* Check for off-screen adjustments */ | ||
2658 | xsz = win->w[plane].xres; | ||
2659 | ysz = win->w[plane].yres; | ||
2660 | if ((xpos + win->w[plane].xres) > panel->Xres) { | ||
2661 | /* Off-screen to the right */ | ||
2662 | xsz = panel->Xres - xpos; /* off by 1 ??? */ | ||
2663 | /*printk("off screen right\n");*/ | ||
2664 | } | ||
2665 | |||
2666 | if ((ypos + win->w[plane].yres) > panel->Yres) { | ||
2667 | /* Off-screen to the bottom */ | ||
2668 | ysz = panel->Yres - ypos; /* off by 1 ??? */ | ||
2669 | /*printk("off screen bottom\n");*/ | ||
2670 | } | ||
2671 | |||
2672 | if (xpos < 0) { | ||
2673 | /* Off-screen to the left */ | ||
2674 | xsz = win->w[plane].xres + xpos; | ||
2675 | fb_offset += (((0 - xpos) * winbpp(lcd->window[plane].winctrl1))/8); | ||
2676 | xpos = 0; | ||
2677 | /*printk("off screen left\n");*/ | ||
2678 | } | ||
2679 | |||
2680 | if (ypos < 0) { | ||
2681 | /* Off-screen to the top */ | ||
2682 | ysz = win->w[plane].yres + ypos; | ||
2683 | /* fixme: fb_offset += ((0-ypos)*fb_pars[plane].line_length); */ | ||
2684 | ypos = 0; | ||
2685 | /*printk("off screen top\n");*/ | ||
2686 | } | ||
2687 | |||
2688 | /* record settings */ | ||
2689 | win->w[plane].xpos = xpos; | ||
2690 | win->w[plane].ypos = ypos; | ||
2691 | |||
2692 | xsz -= 1; | ||
2693 | ysz -= 1; | ||
2694 | winctrl0 |= (xpos << 21); | ||
2695 | winctrl0 |= (ypos << 10); | ||
2696 | winctrl1 |= (xsz << 11); | ||
2697 | winctrl1 |= (ysz << 0); | ||
2698 | |||
2699 | /* Disable the window while making changes, then restore WINEN */ | ||
2700 | winenable = lcd->winenable & (1 << plane); | ||
2701 | au_sync(); | ||
2702 | lcd->winenable &= ~(1 << plane); | ||
2703 | lcd->window[plane].winctrl0 = winctrl0; | ||
2704 | lcd->window[plane].winctrl1 = winctrl1; | ||
2705 | lcd->window[plane].winbuf0 = | ||
2706 | lcd->window[plane].winbuf1 = fbdev->fb_phys; | ||
2707 | lcd->window[plane].winbufctrl = 0; /* select winbuf0 */ | ||
2708 | lcd->winenable |= winenable; | ||
2709 | au_sync(); | ||
2710 | |||
2711 | return 0; | ||
2712 | } | ||
2713 | |||
2714 | static void au1200_setpanel (struct panel_settings *newpanel) | ||
2715 | { | ||
2716 | /* | ||
2717 | * Perform global setup/init of LCD controller | ||
2718 | */ | ||
2719 | uint32 winenable; | ||
2720 | |||
2721 | /* Make sure all windows disabled */ | ||
2722 | winenable = lcd->winenable; | ||
2723 | lcd->winenable = 0; | ||
2724 | au_sync(); | ||
2725 | /* | ||
2726 | * Ensure everything is disabled before reconfiguring | ||
2727 | */ | ||
2728 | if (lcd->screen & LCD_SCREEN_SEN) { | ||
2729 | /* Wait for vertical sync period */ | ||
2730 | lcd->intstatus = LCD_INT_SS; | ||
2731 | while ((lcd->intstatus & LCD_INT_SS) == 0) { | ||
2732 | au_sync(); | ||
2733 | } | ||
2734 | |||
2735 | lcd->screen &= ~LCD_SCREEN_SEN; /*disable the controller*/ | ||
2736 | |||
2737 | do { | ||
2738 | lcd->intstatus = lcd->intstatus; /*clear interrupts*/ | ||
2739 | au_sync(); | ||
2740 | /*wait for controller to shut down*/ | ||
2741 | } while ((lcd->intstatus & LCD_INT_SD) == 0); | ||
2742 | |||
2743 | /* Call shutdown of current panel (if up) */ | ||
2744 | /* this must occur last, because if an external clock is driving | ||
2745 | the controller, the clock cannot be turned off before first | ||
2746 | shutting down the controller. | ||
2747 | */ | ||
2748 | if (panel->device_shutdown != NULL) | ||
2749 | panel->device_shutdown(); | ||
2750 | } | ||
2751 | |||
2752 | /* Newpanel == NULL indicates a shutdown operation only */ | ||
2753 | if (newpanel == NULL) | ||
2754 | return; | ||
2755 | |||
2756 | panel = newpanel; | ||
2757 | |||
2758 | printk("Panel(%s), %dx%d\n", panel->name, panel->Xres, panel->Yres); | ||
2759 | |||
2760 | /* | ||
2761 | * Setup clocking if internal LCD clock source (assumes sys_auxpll valid) | ||
2762 | */ | ||
2763 | if (!(panel->mode_clkcontrol & LCD_CLKCONTROL_EXT)) | ||
2764 | { | ||
2765 | uint32 sys_clksrc; | ||
2766 | au_writel(panel->mode_auxpll, SYS_AUXPLL); | ||
2767 | sys_clksrc = au_readl(SYS_CLKSRC) & ~0x0000001f; | ||
2768 | sys_clksrc |= panel->mode_toyclksrc; | ||
2769 | au_writel(sys_clksrc, SYS_CLKSRC); | ||
2770 | } | ||
2771 | |||
2772 | /* | ||
2773 | * Configure panel timings | ||
2774 | */ | ||
2775 | lcd->screen = panel->mode_screen; | ||
2776 | lcd->horztiming = panel->mode_horztiming; | ||
2777 | lcd->verttiming = panel->mode_verttiming; | ||
2778 | lcd->clkcontrol = panel->mode_clkcontrol; | ||
2779 | lcd->pwmdiv = panel->mode_pwmdiv; | ||
2780 | lcd->pwmhi = panel->mode_pwmhi; | ||
2781 | lcd->outmask = panel->mode_outmask; | ||
2782 | lcd->fifoctrl = panel->mode_fifoctrl; | ||
2783 | au_sync(); | ||
2784 | |||
2785 | /* fixme: Check window settings to make sure still valid | ||
2786 | * for new geometry */ | ||
2787 | #if 0 | ||
2788 | au1200_setlocation(fbdev, 0, win->w[0].xpos, win->w[0].ypos); | ||
2789 | au1200_setlocation(fbdev, 1, win->w[1].xpos, win->w[1].ypos); | ||
2790 | au1200_setlocation(fbdev, 2, win->w[2].xpos, win->w[2].ypos); | ||
2791 | au1200_setlocation(fbdev, 3, win->w[3].xpos, win->w[3].ypos); | ||
2792 | #endif | ||
2793 | lcd->winenable = winenable; | ||
2794 | |||
2795 | /* | ||
2796 | * Re-enable screen now that it is configured | ||
2797 | */ | ||
2798 | lcd->screen |= LCD_SCREEN_SEN; | ||
2799 | au_sync(); | ||
2800 | |||
2801 | /* Call init of panel */ | ||
2802 | if (panel->device_init != NULL) panel->device_init(); | ||
2803 | |||
2804 | /* FIX!!!! not appropriate on panel change!!! Global setup/init */ | ||
2805 | lcd->intenable = 0; | ||
2806 | lcd->intstatus = ~0; | ||
2807 | lcd->backcolor = win->mode_backcolor; | ||
2808 | |||
2809 | /* Setup Color Key - FIX!!! */ | ||
2810 | lcd->colorkey = win->mode_colorkey; | ||
2811 | lcd->colorkeymsk = win->mode_colorkeymsk; | ||
2812 | |||
2813 | /* Setup HWCursor - FIX!!! Need to support this eventually */ | ||
2814 | lcd->hwc.cursorctrl = 0; | ||
2815 | lcd->hwc.cursorpos = 0; | ||
2816 | lcd->hwc.cursorcolor0 = 0; | ||
2817 | lcd->hwc.cursorcolor1 = 0; | ||
2818 | lcd->hwc.cursorcolor2 = 0; | ||
2819 | lcd->hwc.cursorcolor3 = 0; | ||
2820 | |||
2821 | |||
2822 | #if 0 | ||
2823 | #define D(X) printk("%25s: %08X\n", #X, X) | ||
2824 | D(lcd->screen); | ||
2825 | D(lcd->horztiming); | ||
2826 | D(lcd->verttiming); | ||
2827 | D(lcd->clkcontrol); | ||
2828 | D(lcd->pwmdiv); | ||
2829 | D(lcd->pwmhi); | ||
2830 | D(lcd->outmask); | ||
2831 | D(lcd->fifoctrl); | ||
2832 | D(lcd->window[0].winctrl0); | ||
2833 | D(lcd->window[0].winctrl1); | ||
2834 | D(lcd->window[0].winctrl2); | ||
2835 | D(lcd->window[0].winbuf0); | ||
2836 | D(lcd->window[0].winbuf1); | ||
2837 | D(lcd->window[0].winbufctrl); | ||
2838 | D(lcd->window[1].winctrl0); | ||
2839 | D(lcd->window[1].winctrl1); | ||
2840 | D(lcd->window[1].winctrl2); | ||
2841 | D(lcd->window[1].winbuf0); | ||
2842 | D(lcd->window[1].winbuf1); | ||
2843 | D(lcd->window[1].winbufctrl); | ||
2844 | D(lcd->window[2].winctrl0); | ||
2845 | D(lcd->window[2].winctrl1); | ||
2846 | D(lcd->window[2].winctrl2); | ||
2847 | D(lcd->window[2].winbuf0); | ||
2848 | D(lcd->window[2].winbuf1); | ||
2849 | D(lcd->window[2].winbufctrl); | ||
2850 | D(lcd->window[3].winctrl0); | ||
2851 | D(lcd->window[3].winctrl1); | ||
2852 | D(lcd->window[3].winctrl2); | ||
2853 | D(lcd->window[3].winbuf0); | ||
2854 | D(lcd->window[3].winbuf1); | ||
2855 | D(lcd->window[3].winbufctrl); | ||
2856 | D(lcd->winenable); | ||
2857 | D(lcd->intenable); | ||
2858 | D(lcd->intstatus); | ||
2859 | D(lcd->backcolor); | ||
2860 | D(lcd->winenable); | ||
2861 | D(lcd->colorkey); | ||
2862 | D(lcd->colorkeymsk); | ||
2863 | D(lcd->hwc.cursorctrl); | ||
2864 | D(lcd->hwc.cursorpos); | ||
2865 | D(lcd->hwc.cursorcolor0); | ||
2866 | D(lcd->hwc.cursorcolor1); | ||
2867 | D(lcd->hwc.cursorcolor2); | ||
2868 | D(lcd->hwc.cursorcolor3); | ||
2869 | #endif | ||
2870 | } | ||
2871 | |||
2872 | static void au1200_setmode(struct au1200fb_device *fbdev) | ||
2873 | { | ||
2874 | int plane = fbdev->plane; | ||
2875 | /* Window/plane setup */ | ||
2876 | lcd->window[plane].winctrl1 = ( 0 | ||
2877 | | LCD_WINCTRL1_PRI_N(plane) | ||
2878 | | win->w[plane].mode_winctrl1 /* FRM,CCO,PO,PIPE */ | ||
2879 | ) ; | ||
2880 | |||
2881 | au1200_setlocation(fbdev, plane, win->w[plane].xpos, win->w[plane].ypos); | ||
2882 | |||
2883 | lcd->window[plane].winctrl2 = ( 0 | ||
2884 | | LCD_WINCTRL2_CKMODE_00 | ||
2885 | | LCD_WINCTRL2_DBM | ||
2886 | | LCD_WINCTRL2_BX_N( fbdev->fb_info.fix.line_length) | ||
2887 | | LCD_WINCTRL2_SCX_1 | ||
2888 | | LCD_WINCTRL2_SCY_1 | ||
2889 | ) ; | ||
2890 | lcd->winenable |= win->w[plane].mode_winenable; | ||
2891 | au_sync(); | ||
2892 | } | ||
2893 | |||
2894 | |||
2895 | /* Inline helpers */ | ||
2896 | |||
2897 | /*#define panel_is_dual(panel) ((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/ | ||
2898 | /*#define panel_is_active(panel)((panel->mode_screen & LCD_SCREEN_PT) == LCD_SCREEN_PT_010)*/ | ||
2899 | |||
2900 | #define panel_is_color(panel) ((panel->mode_screen & LCD_SCREEN_PT) <= LCD_SCREEN_PT_CDSTN) | ||
2901 | |||
2902 | /* Bitfields format supported by the controller. */ | ||
2903 | static struct fb_bitfield rgb_bitfields[][4] = { | ||
2904 | /* Red, Green, Blue, Transp */ | ||
2905 | [LCD_WINCTRL1_FRM_16BPP655 >> 25] = | ||
2906 | { { 10, 6, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } }, | ||
2907 | |||
2908 | [LCD_WINCTRL1_FRM_16BPP565 >> 25] = | ||
2909 | { { 11, 5, 0 }, { 5, 6, 0 }, { 0, 5, 0 }, { 0, 0, 0 } }, | ||
2910 | |||
2911 | [LCD_WINCTRL1_FRM_16BPP556 >> 25] = | ||
2912 | { { 11, 5, 0 }, { 6, 5, 0 }, { 0, 6, 0 }, { 0, 0, 0 } }, | ||
2913 | |||
2914 | [LCD_WINCTRL1_FRM_16BPPI1555 >> 25] = | ||
2915 | { { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } }, | ||
2916 | |||
2917 | [LCD_WINCTRL1_FRM_16BPPI5551 >> 25] = | ||
2918 | { { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 0, 0 } }, | ||
2919 | |||
2920 | [LCD_WINCTRL1_FRM_16BPPA1555 >> 25] = | ||
2921 | { { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 15, 1, 0 } }, | ||
2922 | |||
2923 | [LCD_WINCTRL1_FRM_16BPPA5551 >> 25] = | ||
2924 | { { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 1, 0 } }, | ||
2925 | |||
2926 | [LCD_WINCTRL1_FRM_24BPP >> 25] = | ||
2927 | { { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 0, 0, 0 } }, | ||
2928 | |||
2929 | [LCD_WINCTRL1_FRM_32BPP >> 25] = | ||
2930 | { { 16, 8, 0 }, { 8, 8, 0 }, { 0, 8, 0 }, { 24, 0, 0 } }, | ||
2931 | }; | ||
2932 | |||
2933 | /*-------------------------------------------------------------------------*/ | ||
2934 | |||
2935 | /* Helpers */ | ||
2936 | |||
2937 | static void au1200fb_update_fbinfo(struct fb_info *fbi) | ||
2938 | { | ||
2939 | /* FIX!!!! This also needs to take the window pixel format into account!!! */ | ||
2940 | |||
2941 | /* Update var-dependent FB info */ | ||
2942 | if (panel_is_color(panel)) { | ||
2943 | if (fbi->var.bits_per_pixel <= 8) { | ||
2944 | /* palettized */ | ||
2945 | fbi->fix.visual = FB_VISUAL_PSEUDOCOLOR; | ||
2946 | fbi->fix.line_length = fbi->var.xres_virtual / | ||
2947 | (8/fbi->var.bits_per_pixel); | ||
2948 | } else { | ||
2949 | /* non-palettized */ | ||
2950 | fbi->fix.visual = FB_VISUAL_TRUECOLOR; | ||
2951 | fbi->fix.line_length = fbi->var.xres_virtual * (fbi->var.bits_per_pixel / 8); | ||
2952 | } | ||
2953 | } else { | ||
2954 | /* mono FIX!!! mono 8 and 4 bits */ | ||
2955 | fbi->fix.visual = FB_VISUAL_MONO10; | ||
2956 | fbi->fix.line_length = fbi->var.xres_virtual / 8; | ||
2957 | } | ||
2958 | |||
2959 | fbi->screen_size = fbi->fix.line_length * fbi->var.yres_virtual; | ||
2960 | print_dbg("line length: %d\n", fbi->fix.line_length); | ||
2961 | print_dbg("bits_per_pixel: %d\n", fbi->var.bits_per_pixel); | ||
2962 | } | ||
2963 | |||
2964 | /*-------------------------------------------------------------------------*/ | ||
2965 | |||
2966 | /* AU1200 framebuffer driver */ | ||
2967 | |||
2968 | /* fb_check_var | ||
2969 | * Validate var settings with hardware restrictions and modify it if necessary | ||
2970 | */ | ||
2971 | static int au1200fb_fb_check_var(struct fb_var_screeninfo *var, | ||
2972 | struct fb_info *fbi) | ||
2973 | { | ||
2974 | struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi; | ||
2975 | u32 pixclock; | ||
2976 | int screen_size, plane; | ||
2977 | |||
2978 | plane = fbdev->plane; | ||
2979 | |||
2980 | /* Make sure that the mode respect all LCD controller and | ||
2981 | * panel restrictions. */ | ||
2982 | var->xres = win->w[plane].xres; | ||
2983 | var->yres = win->w[plane].yres; | ||
2984 | |||
2985 | /* No need for virtual resolution support */ | ||
2986 | var->xres_virtual = var->xres; | ||
2987 | var->yres_virtual = var->yres; | ||
2988 | |||
2989 | var->bits_per_pixel = winbpp(win->w[plane].mode_winctrl1); | ||
2990 | |||
2991 | screen_size = var->xres_virtual * var->yres_virtual; | ||
2992 | if (var->bits_per_pixel > 8) screen_size *= (var->bits_per_pixel / 8); | ||
2993 | else screen_size /= (8/var->bits_per_pixel); | ||
2994 | |||
2995 | if (fbdev->fb_len < screen_size) | ||
2996 | return -EINVAL; /* Virtual screen is to big, abort */ | ||
2997 | |||
2998 | /* FIX!!!! what are the implicaitons of ignoring this for windows ??? */ | ||
2999 | /* The max LCD clock is fixed to 48MHz (value of AUX_CLK). The pixel | ||
3000 | * clock can only be obtain by dividing this value by an even integer. | ||
3001 | * Fallback to a slower pixel clock if necessary. */ | ||
3002 | pixclock = max((u32)(PICOS2KHZ(var->pixclock) * 1000), fbi->monspecs.dclkmin); | ||
3003 | pixclock = min(pixclock, min(fbi->monspecs.dclkmax, (u32)AU1200_LCD_MAX_CLK/2)); | ||
3004 | |||
3005 | if (AU1200_LCD_MAX_CLK % pixclock) { | ||
3006 | int diff = AU1200_LCD_MAX_CLK % pixclock; | ||
3007 | pixclock -= diff; | ||
3008 | } | ||
3009 | |||
3010 | var->pixclock = KHZ2PICOS(pixclock/1000); | ||
3011 | #if 0 | ||
3012 | if (!panel_is_active(panel)) { | ||
3013 | int pcd = AU1200_LCD_MAX_CLK / (pixclock * 2) - 1; | ||
3014 | |||
3015 | if (!panel_is_color(panel) | ||
3016 | && (panel->control_base & LCD_CONTROL_MPI) && (pcd < 3)) { | ||
3017 | /* STN 8bit mono panel support is up to 6MHz pixclock */ | ||
3018 | var->pixclock = KHZ2PICOS(6000); | ||
3019 | } else if (!pcd) { | ||
3020 | /* Other STN panel support is up to 12MHz */ | ||
3021 | var->pixclock = KHZ2PICOS(12000); | ||
3022 | } | ||
3023 | } | ||
3024 | #endif | ||
3025 | /* Set bitfield accordingly */ | ||
3026 | switch (var->bits_per_pixel) { | ||
3027 | case 16: | ||
3028 | { | ||
3029 | /* 16bpp True color. | ||
3030 | * These must be set to MATCH WINCTRL[FORM] */ | ||
3031 | int idx; | ||
3032 | idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25; | ||
3033 | var->red = rgb_bitfields[idx][0]; | ||
3034 | var->green = rgb_bitfields[idx][1]; | ||
3035 | var->blue = rgb_bitfields[idx][2]; | ||
3036 | var->transp = rgb_bitfields[idx][3]; | ||
3037 | break; | ||
3038 | } | ||
3039 | |||
3040 | case 32: | ||
3041 | { | ||
3042 | /* 32bpp True color. | ||
3043 | * These must be set to MATCH WINCTRL[FORM] */ | ||
3044 | int idx; | ||
3045 | idx = (win->w[0].mode_winctrl1 & LCD_WINCTRL1_FRM) >> 25; | ||
3046 | var->red = rgb_bitfields[idx][0]; | ||
3047 | var->green = rgb_bitfields[idx][1]; | ||
3048 | var->blue = rgb_bitfields[idx][2]; | ||
3049 | var->transp = rgb_bitfields[idx][3]; | ||
3050 | break; | ||
3051 | } | ||
3052 | default: | ||
3053 | print_dbg("Unsupported depth %dbpp", var->bits_per_pixel); | ||
3054 | return -EINVAL; | ||
3055 | } | ||
3056 | |||
3057 | return 0; | ||
3058 | } | ||
3059 | |||
3060 | /* fb_set_par | ||
3061 | * Set hardware with var settings. This will enable the controller with a | ||
3062 | * specific mode, normally validated with the fb_check_var method | ||
3063 | */ | ||
3064 | static int au1200fb_fb_set_par(struct fb_info *fbi) | ||
3065 | { | ||
3066 | struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi; | ||
3067 | |||
3068 | au1200fb_update_fbinfo(fbi); | ||
3069 | au1200_setmode(fbdev); | ||
3070 | |||
3071 | return 0; | ||
3072 | } | ||
3073 | |||
3074 | /* fb_setcolreg | ||
3075 | * Set color in LCD palette. | ||
3076 | */ | ||
3077 | static int au1200fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green, | ||
3078 | unsigned blue, unsigned transp, struct fb_info *fbi) | ||
3079 | { | ||
3080 | volatile u32 *palette = lcd->palette; | ||
3081 | u32 value; | ||
3082 | |||
3083 | if (regno > (AU1200_LCD_NBR_PALETTE_ENTRIES - 1)) | ||
3084 | return -EINVAL; | ||
3085 | |||
3086 | if (fbi->var.grayscale) { | ||
3087 | /* Convert color to grayscale */ | ||
3088 | red = green = blue = | ||
3089 | (19595 * red + 38470 * green + 7471 * blue) >> 16; | ||
3090 | } | ||
3091 | |||
3092 | if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) { | ||
3093 | /* Place color in the pseudopalette */ | ||
3094 | if (regno > 16) | ||
3095 | return -EINVAL; | ||
3096 | |||
3097 | palette = (u32*) fbi->pseudo_palette; | ||
3098 | |||
3099 | red >>= (16 - fbi->var.red.length); | ||
3100 | green >>= (16 - fbi->var.green.length); | ||
3101 | blue >>= (16 - fbi->var.blue.length); | ||
3102 | |||
3103 | value = (red << fbi->var.red.offset) | | ||
3104 | (green << fbi->var.green.offset)| | ||
3105 | (blue << fbi->var.blue.offset); | ||
3106 | value &= 0xFFFF; | ||
3107 | |||
3108 | } else if (1 /*FIX!!! panel_is_active(fbdev->panel)*/) { | ||
3109 | /* COLOR TFT PALLETTIZED (use RGB 565) */ | ||
3110 | value = (red & 0xF800)|((green >> 5) & | ||
3111 | 0x07E0)|((blue >> 11) & 0x001F); | ||
3112 | value &= 0xFFFF; | ||
3113 | |||
3114 | } else if (0 /*panel_is_color(fbdev->panel)*/) { | ||
3115 | /* COLOR STN MODE */ | ||
3116 | value = 0x1234; | ||
3117 | value &= 0xFFF; | ||
3118 | } else { | ||
3119 | /* MONOCHROME MODE */ | ||
3120 | value = (green >> 12) & 0x000F; | ||
3121 | value &= 0xF; | ||
3122 | } | ||
3123 | |||
3124 | palette[regno] = value; | ||
3125 | |||
3126 | return 0; | ||
3127 | } | ||
3128 | |||
3129 | /* fb_blank | ||
3130 | * Blank the screen. Depending on the mode, the screen will be | ||
3131 | * activated with the backlight color, or desactivated | ||
3132 | */ | ||
3133 | static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi) | ||
3134 | { | ||
3135 | /* Short-circuit screen blanking */ | ||
3136 | if (noblanking) | ||
3137 | return 0; | ||
3138 | |||
3139 | switch (blank_mode) { | ||
3140 | |||
3141 | case FB_BLANK_UNBLANK: | ||
3142 | case FB_BLANK_NORMAL: | ||
3143 | /* printk("turn on panel\n"); */ | ||
3144 | au1200_setpanel(panel); | ||
3145 | break; | ||
3146 | case FB_BLANK_VSYNC_SUSPEND: | ||
3147 | case FB_BLANK_HSYNC_SUSPEND: | ||
3148 | case FB_BLANK_POWERDOWN: | ||
3149 | /* printk("turn off panel\n"); */ | ||
3150 | au1200_setpanel(NULL); | ||
3151 | break; | ||
3152 | default: | ||
3153 | break; | ||
3154 | |||
3155 | } | ||
3156 | |||
3157 | /* FB_BLANK_NORMAL is a soft blank */ | ||
3158 | return (blank_mode == FB_BLANK_NORMAL) ? -EINVAL : 0; | ||
3159 | } | ||
3160 | |||
3161 | /* fb_mmap | ||
3162 | * Map video memory in user space. We don't use the generic fb_mmap | ||
3163 | * method mainly to allow the use of the TLB streaming flag (CCA=6) | ||
3164 | */ | ||
3165 | static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) | ||
3166 | |||
3167 | { | ||
3168 | unsigned int len; | ||
3169 | unsigned long start=0, off; | ||
3170 | struct au1200fb_device *fbdev = (struct au1200fb_device *) info; | ||
3171 | |||
3172 | #ifdef CONFIG_PM | ||
3173 | au1xxx_pm_access(LCD_pm_dev); | ||
3174 | #endif | ||
3175 | |||
3176 | if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) { | ||
3177 | return -EINVAL; | ||
3178 | } | ||
3179 | |||
3180 | start = fbdev->fb_phys & PAGE_MASK; | ||
3181 | len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len); | ||
3182 | |||
3183 | off = vma->vm_pgoff << PAGE_SHIFT; | ||
3184 | |||
3185 | if ((vma->vm_end - vma->vm_start + off) > len) { | ||
3186 | return -EINVAL; | ||
3187 | } | ||
3188 | |||
3189 | off += start; | ||
3190 | vma->vm_pgoff = off >> PAGE_SHIFT; | ||
3191 | |||
3192 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
3193 | pgprot_val(vma->vm_page_prot) |= _CACHE_MASK; /* CCA=7 */ | ||
3194 | |||
3195 | vma->vm_flags |= VM_IO; | ||
3196 | |||
3197 | return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, | ||
3198 | vma->vm_end - vma->vm_start, | ||
3199 | vma->vm_page_prot); | ||
3200 | |||
3201 | return 0; | ||
3202 | } | ||
3203 | |||
3204 | static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata) | ||
3205 | { | ||
3206 | |||
3207 | unsigned int hi1, divider; | ||
3208 | |||
3209 | /* SCREEN_SIZE: user cannot reset size, must switch panel choice */ | ||
3210 | |||
3211 | if (pdata->flags & SCREEN_BACKCOLOR) | ||
3212 | lcd->backcolor = pdata->backcolor; | ||
3213 | |||
3214 | if (pdata->flags & SCREEN_BRIGHTNESS) { | ||
3215 | |||
3216 | // limit brightness pwm duty to >= 30/1600 | ||
3217 | if (pdata->brightness < 30) { | ||
3218 | pdata->brightness = 30; | ||
3219 | } | ||
3220 | divider = (lcd->pwmdiv & 0x3FFFF) + 1; | ||
3221 | hi1 = (lcd->pwmhi >> 16) + 1; | ||
3222 | hi1 = (((pdata->brightness & 0xFF)+1) * divider >> 8); | ||
3223 | lcd->pwmhi &= 0xFFFF; | ||
3224 | lcd->pwmhi |= (hi1 << 16); | ||
3225 | } | ||
3226 | |||
3227 | if (pdata->flags & SCREEN_COLORKEY) | ||
3228 | lcd->colorkey = pdata->colorkey; | ||
3229 | |||
3230 | if (pdata->flags & SCREEN_MASK) | ||
3231 | lcd->colorkeymsk = pdata->mask; | ||
3232 | au_sync(); | ||
3233 | } | ||
3234 | |||
3235 | static void get_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata) | ||
3236 | { | ||
3237 | unsigned int hi1, divider; | ||
3238 | |||
3239 | pdata->xsize = ((lcd->screen & LCD_SCREEN_SX) >> 19) + 1; | ||
3240 | pdata->ysize = ((lcd->screen & LCD_SCREEN_SY) >> 8) + 1; | ||
3241 | |||
3242 | pdata->backcolor = lcd->backcolor; | ||
3243 | pdata->colorkey = lcd->colorkey; | ||
3244 | pdata->mask = lcd->colorkeymsk; | ||
3245 | |||
3246 | // brightness | ||
3247 | hi1 = (lcd->pwmhi >> 16) + 1; | ||
3248 | divider = (lcd->pwmdiv & 0x3FFFF) + 1; | ||
3249 | pdata->brightness = ((hi1 << 8) / divider) - 1; | ||
3250 | au_sync(); | ||
3251 | } | ||
3252 | |||
3253 | static void set_window(unsigned int plane, | ||
3254 | struct au1200_lcd_window_regs_t *pdata) | ||
3255 | { | ||
3256 | unsigned int val, bpp; | ||
3257 | |||
3258 | /* Window control register 0 */ | ||
3259 | if (pdata->flags & WIN_POSITION) { | ||
3260 | val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_OX | | ||
3261 | LCD_WINCTRL0_OY); | ||
3262 | val |= ((pdata->xpos << 21) & LCD_WINCTRL0_OX); | ||
3263 | val |= ((pdata->ypos << 10) & LCD_WINCTRL0_OY); | ||
3264 | lcd->window[plane].winctrl0 = val; | ||
3265 | } | ||
3266 | if (pdata->flags & WIN_ALPHA_COLOR) { | ||
3267 | val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_A); | ||
3268 | val |= ((pdata->alpha_color << 2) & LCD_WINCTRL0_A); | ||
3269 | lcd->window[plane].winctrl0 = val; | ||
3270 | } | ||
3271 | if (pdata->flags & WIN_ALPHA_MODE) { | ||
3272 | val = lcd->window[plane].winctrl0 & ~(LCD_WINCTRL0_AEN); | ||
3273 | val |= ((pdata->alpha_mode << 1) & LCD_WINCTRL0_AEN); | ||
3274 | lcd->window[plane].winctrl0 = val; | ||
3275 | } | ||
3276 | |||
3277 | /* Window control register 1 */ | ||
3278 | if (pdata->flags & WIN_PRIORITY) { | ||
3279 | val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PRI); | ||
3280 | val |= ((pdata->priority << 30) & LCD_WINCTRL1_PRI); | ||
3281 | lcd->window[plane].winctrl1 = val; | ||
3282 | } | ||
3283 | if (pdata->flags & WIN_CHANNEL) { | ||
3284 | val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PIPE); | ||
3285 | val |= ((pdata->channel << 29) & LCD_WINCTRL1_PIPE); | ||
3286 | lcd->window[plane].winctrl1 = val; | ||
3287 | } | ||
3288 | if (pdata->flags & WIN_BUFFER_FORMAT) { | ||
3289 | val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_FRM); | ||
3290 | val |= ((pdata->buffer_format << 25) & LCD_WINCTRL1_FRM); | ||
3291 | lcd->window[plane].winctrl1 = val; | ||
3292 | } | ||
3293 | if (pdata->flags & WIN_COLOR_ORDER) { | ||
3294 | val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_CCO); | ||
3295 | val |= ((pdata->color_order << 24) & LCD_WINCTRL1_CCO); | ||
3296 | lcd->window[plane].winctrl1 = val; | ||
3297 | } | ||
3298 | if (pdata->flags & WIN_PIXEL_ORDER) { | ||
3299 | val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_PO); | ||
3300 | val |= ((pdata->pixel_order << 22) & LCD_WINCTRL1_PO); | ||
3301 | lcd->window[plane].winctrl1 = val; | ||
3302 | } | ||
3303 | if (pdata->flags & WIN_SIZE) { | ||
3304 | val = lcd->window[plane].winctrl1 & ~(LCD_WINCTRL1_SZX | | ||
3305 | LCD_WINCTRL1_SZY); | ||
3306 | val |= (((pdata->xsize << 11) - 1) & LCD_WINCTRL1_SZX); | ||
3307 | val |= (((pdata->ysize) - 1) & LCD_WINCTRL1_SZY); | ||
3308 | lcd->window[plane].winctrl1 = val; | ||
3309 | /* program buffer line width */ | ||
3310 | bpp = winbpp(val) / 8; | ||
3311 | val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_BX); | ||
3312 | val |= (((pdata->xsize * bpp) << 8) & LCD_WINCTRL2_BX); | ||
3313 | lcd->window[plane].winctrl2 = val; | ||
3314 | } | ||
3315 | |||
3316 | /* Window control register 2 */ | ||
3317 | if (pdata->flags & WIN_COLORKEY_MODE) { | ||
3318 | val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_CKMODE); | ||
3319 | val |= ((pdata->colorkey_mode << 24) & LCD_WINCTRL2_CKMODE); | ||
3320 | lcd->window[plane].winctrl2 = val; | ||
3321 | } | ||
3322 | if (pdata->flags & WIN_DOUBLE_BUFFER_MODE) { | ||
3323 | val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_DBM); | ||
3324 | val |= ((pdata->double_buffer_mode << 23) & LCD_WINCTRL2_DBM); | ||
3325 | lcd->window[plane].winctrl2 = val; | ||
3326 | } | ||
3327 | if (pdata->flags & WIN_RAM_ARRAY_MODE) { | ||
3328 | val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_RAM); | ||
3329 | val |= ((pdata->ram_array_mode << 21) & LCD_WINCTRL2_RAM); | ||
3330 | lcd->window[plane].winctrl2 = val; | ||
3331 | } | ||
3332 | |||
3333 | /* Buffer line width programmed with WIN_SIZE */ | ||
3334 | |||
3335 | if (pdata->flags & WIN_BUFFER_SCALE) { | ||
3336 | val = lcd->window[plane].winctrl2 & ~(LCD_WINCTRL2_SCX | | ||
3337 | LCD_WINCTRL2_SCY); | ||
3338 | val |= ((pdata->xsize << 11) & LCD_WINCTRL2_SCX); | ||
3339 | val |= ((pdata->ysize) & LCD_WINCTRL2_SCY); | ||
3340 | lcd->window[plane].winctrl2 = val; | ||
3341 | } | ||
3342 | |||
3343 | if (pdata->flags & WIN_ENABLE) { | ||
3344 | val = lcd->winenable; | ||
3345 | val &= ~(1<<plane); | ||
3346 | val |= (pdata->enable & 1) << plane; | ||
3347 | lcd->winenable = val; | ||
3348 | } | ||
3349 | au_sync(); | ||
3350 | } | ||
3351 | |||
3352 | static void get_window(unsigned int plane, | ||
3353 | struct au1200_lcd_window_regs_t *pdata) | ||
3354 | { | ||
3355 | /* Window control register 0 */ | ||
3356 | pdata->xpos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OX) >> 21; | ||
3357 | pdata->ypos = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OY) >> 10; | ||
3358 | pdata->alpha_color = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_A) >> 2; | ||
3359 | pdata->alpha_mode = (lcd->window[plane].winctrl0 & LCD_WINCTRL0_AEN) >> 1; | ||
3360 | |||
3361 | /* Window control register 1 */ | ||
3362 | pdata->priority = (lcd->window[plane].winctrl1& LCD_WINCTRL1_PRI) >> 30; | ||
3363 | pdata->channel = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PIPE) >> 29; | ||
3364 | pdata->buffer_format = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_FRM) >> 25; | ||
3365 | pdata->color_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_CCO) >> 24; | ||
3366 | pdata->pixel_order = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_PO) >> 22; | ||
3367 | pdata->xsize = ((lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZX) >> 11) + 1; | ||
3368 | pdata->ysize = (lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZY) + 1; | ||
3369 | |||
3370 | /* Window control register 2 */ | ||
3371 | pdata->colorkey_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_CKMODE) >> 24; | ||
3372 | pdata->double_buffer_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_DBM) >> 23; | ||
3373 | pdata->ram_array_mode = (lcd->window[plane].winctrl2 & LCD_WINCTRL2_RAM) >> 21; | ||
3374 | |||
3375 | pdata->enable = (lcd->winenable >> plane) & 1; | ||
3376 | au_sync(); | ||
3377 | } | ||
3378 | |||
3379 | static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd, | ||
3380 | unsigned long arg) | ||
3381 | { | ||
3382 | int plane; | ||
3383 | int val; | ||
3384 | |||
3385 | #ifdef CONFIG_PM | ||
3386 | au1xxx_pm_access(LCD_pm_dev); | ||
3387 | #endif | ||
3388 | |||
3389 | plane = fbinfo2index(info); | ||
3390 | print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane); | ||
3391 | |||
3392 | if (cmd == AU1200_LCD_FB_IOCTL) { | ||
3393 | struct au1200_lcd_iodata_t iodata; | ||
3394 | |||
3395 | if (copy_from_user(&iodata, (void __user *) arg, sizeof(iodata))) | ||
3396 | return -EFAULT; | ||
3397 | |||
3398 | print_dbg("FB IOCTL called\n"); | ||
3399 | |||
3400 | switch (iodata.subcmd) { | ||
3401 | case AU1200_LCD_SET_SCREEN: | ||
3402 | print_dbg("AU1200_LCD_SET_SCREEN\n"); | ||
3403 | set_global(cmd, &iodata.global); | ||
3404 | break; | ||
3405 | |||
3406 | case AU1200_LCD_GET_SCREEN: | ||
3407 | print_dbg("AU1200_LCD_GET_SCREEN\n"); | ||
3408 | get_global(cmd, &iodata.global); | ||
3409 | break; | ||
3410 | |||
3411 | case AU1200_LCD_SET_WINDOW: | ||
3412 | print_dbg("AU1200_LCD_SET_WINDOW\n"); | ||
3413 | set_window(plane, &iodata.window); | ||
3414 | break; | ||
3415 | |||
3416 | case AU1200_LCD_GET_WINDOW: | ||
3417 | print_dbg("AU1200_LCD_GET_WINDOW\n"); | ||
3418 | get_window(plane, &iodata.window); | ||
3419 | break; | ||
3420 | |||
3421 | case AU1200_LCD_SET_PANEL: | ||
3422 | print_dbg("AU1200_LCD_SET_PANEL\n"); | ||
3423 | if ((iodata.global.panel_choice >= 0) && | ||
3424 | (iodata.global.panel_choice < | ||
3425 | NUM_PANELS)) | ||
3426 | { | ||
3427 | struct panel_settings *newpanel; | ||
3428 | panel_index = iodata.global.panel_choice; | ||
3429 | newpanel = &known_lcd_panels[panel_index]; | ||
3430 | au1200_setpanel(newpanel); | ||
3431 | } | ||
3432 | break; | ||
3433 | |||
3434 | case AU1200_LCD_GET_PANEL: | ||
3435 | print_dbg("AU1200_LCD_GET_PANEL\n"); | ||
3436 | iodata.global.panel_choice = panel_index; | ||
3437 | break; | ||
3438 | |||
3439 | default: | ||
3440 | return -EINVAL; | ||
3441 | } | ||
3442 | |||
3443 | val = copy_to_user((void __user *) arg, &iodata, sizeof(iodata)); | ||
3444 | if (val) { | ||
3445 | print_dbg("error: could not copy %d bytes\n", val); | ||
3446 | return -EFAULT; | ||
3447 | } | ||
3448 | } | ||
3449 | |||
3450 | return 0; | ||
3451 | } | ||
3452 | |||
3453 | |||
3454 | static struct fb_ops au1200fb_fb_ops = { | ||
3455 | .owner = THIS_MODULE, | ||
3456 | .fb_check_var = au1200fb_fb_check_var, | ||
3457 | .fb_set_par = au1200fb_fb_set_par, | ||
3458 | .fb_setcolreg = au1200fb_fb_setcolreg, | ||
3459 | .fb_blank = au1200fb_fb_blank, | ||
3460 | .fb_fillrect = cfb_fillrect, | ||
3461 | .fb_copyarea = cfb_copyarea, | ||
3462 | .fb_imageblit = cfb_imageblit, | ||
3463 | .fb_sync = NULL, | ||
3464 | .fb_ioctl = au1200fb_ioctl, | ||
3465 | .fb_mmap = au1200fb_fb_mmap, | ||
3466 | }; | ||
3467 | |||
3468 | /*-------------------------------------------------------------------------*/ | ||
3469 | |||
3470 | static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id, struct pt_regs *regs) | ||
3471 | { | ||
3472 | /* Nothing to do for now, just clear any pending interrupt */ | ||
3473 | lcd->intstatus = lcd->intstatus; | ||
3474 | au_sync(); | ||
3475 | |||
3476 | return IRQ_HANDLED; | ||
3477 | } | ||
3478 | |||
3479 | /*-------------------------------------------------------------------------*/ | ||
3480 | |||
3481 | /* AU1200 LCD device probe helpers */ | ||
3482 | |||
3483 | static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev) | ||
3484 | { | ||
3485 | struct fb_info *fbi = &fbdev->fb_info; | ||
3486 | int bpp; | ||
3487 | |||
3488 | memset(fbi, 0, sizeof(struct fb_info)); | ||
3489 | fbi->fbops = &au1200fb_fb_ops; | ||
3490 | |||
3491 | bpp = winbpp(win->w[fbdev->plane].mode_winctrl1); | ||
3492 | |||
3493 | /* Copy monitor specs from panel data */ | ||
3494 | /* fixme: we're setting up LCD controller windows, so these dont give a | ||
3495 | damn as to what the monitor specs are (the panel itself does, but that | ||
3496 | isnt done here...so maybe need a generic catchall monitor setting??? */ | ||
3497 | memcpy(&fbi->monspecs, &panel->monspecs, sizeof(struct fb_monspecs)); | ||
3498 | |||
3499 | /* We first try the user mode passed in argument. If that failed, | ||
3500 | * or if no one has been specified, we default to the first mode of the | ||
3501 | * panel list. Note that after this call, var data will be set */ | ||
3502 | if (!fb_find_mode(&fbi->var, | ||
3503 | fbi, | ||
3504 | NULL, /* drv_info.opt_mode, */ | ||
3505 | fbi->monspecs.modedb, | ||
3506 | fbi->monspecs.modedb_len, | ||
3507 | fbi->monspecs.modedb, | ||
3508 | bpp)) { | ||
3509 | |||
3510 | print_err("Cannot find valid mode for panel %s", panel->name); | ||
3511 | return -EFAULT; | ||
3512 | } | ||
3513 | |||
3514 | fbi->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); | ||
3515 | if (!fbi->pseudo_palette) { | ||
3516 | return -ENOMEM; | ||
3517 | } | ||
3518 | memset(fbi->pseudo_palette, 0, sizeof(u32) * 16); | ||
3519 | |||
3520 | if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { | ||
3521 | print_err("Fail to allocate colormap (%d entries)", | ||
3522 | AU1200_LCD_NBR_PALETTE_ENTRIES); | ||
3523 | kfree(fbi->pseudo_palette); | ||
3524 | return -EFAULT; | ||
3525 | } | ||
3526 | |||
3527 | strncpy(fbi->fix.id, "AU1200", sizeof(fbi->fix.id)); | ||
3528 | fbi->fix.smem_start = fbdev->fb_phys; | ||
3529 | fbi->fix.smem_len = fbdev->fb_len; | ||
3530 | fbi->fix.type = FB_TYPE_PACKED_PIXELS; | ||
3531 | fbi->fix.xpanstep = 0; | ||
3532 | fbi->fix.ypanstep = 0; | ||
3533 | fbi->fix.mmio_start = 0; | ||
3534 | fbi->fix.mmio_len = 0; | ||
3535 | fbi->fix.accel = FB_ACCEL_NONE; | ||
3536 | |||
3537 | fbi->screen_base = (char __iomem *) fbdev->fb_mem; | ||
3538 | |||
3539 | au1200fb_update_fbinfo(fbi); | ||
3540 | |||
3541 | return 0; | ||
3542 | } | ||
3543 | |||
3544 | /*-------------------------------------------------------------------------*/ | ||
3545 | |||
3546 | /* AU1200 LCD controller device driver */ | ||
3547 | |||
3548 | static int au1200fb_drv_probe(struct device *dev) | ||
3549 | { | ||
3550 | struct au1200fb_device *fbdev; | ||
3551 | unsigned long page; | ||
3552 | int bpp, plane, ret; | ||
3553 | |||
3554 | if (!dev) | ||
3555 | return -EINVAL; | ||
3556 | |||
3557 | for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) { | ||
3558 | bpp = winbpp(win->w[plane].mode_winctrl1); | ||
3559 | if (win->w[plane].xres == 0) | ||
3560 | win->w[plane].xres = panel->Xres; | ||
3561 | if (win->w[plane].yres == 0) | ||
3562 | win->w[plane].yres = panel->Yres; | ||
3563 | |||
3564 | fbdev = &_au1200fb_devices[plane]; | ||
3565 | memset(fbdev, 0, sizeof(struct au1200fb_device)); | ||
3566 | fbdev->plane = plane; | ||
3567 | |||
3568 | /* Allocate the framebuffer to the maximum screen size */ | ||
3569 | fbdev->fb_len = (win->w[plane].xres * win->w[plane].yres * bpp) / 8; | ||
3570 | |||
3571 | fbdev->fb_mem = dma_alloc_noncoherent(dev, | ||
3572 | PAGE_ALIGN(fbdev->fb_len), | ||
3573 | &fbdev->fb_phys, GFP_KERNEL); | ||
3574 | if (!fbdev->fb_mem) { | ||
3575 | print_err("fail to allocate frambuffer (size: %dK))", | ||
3576 | fbdev->fb_len / 1024); | ||
3577 | return -ENOMEM; | ||
3578 | } | ||
3579 | |||
3580 | /* | ||
3581 | * Set page reserved so that mmap will work. This is necessary | ||
3582 | * since we'll be remapping normal memory. | ||
3583 | */ | ||
3584 | for (page = (unsigned long)fbdev->fb_phys; | ||
3585 | page < PAGE_ALIGN((unsigned long)fbdev->fb_phys + | ||
3586 | fbdev->fb_len); | ||
3587 | page += PAGE_SIZE) { | ||
3588 | SetPageReserved(pfn_to_page(page >> PAGE_SHIFT)); /* LCD DMA is NOT coherent on Au1200 */ | ||
3589 | } | ||
3590 | print_dbg("Framebuffer memory map at %p", fbdev->fb_mem); | ||
3591 | print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024); | ||
3592 | |||
3593 | /* Init FB data */ | ||
3594 | if ((ret = au1200fb_init_fbinfo(fbdev)) < 0) | ||
3595 | goto failed; | ||
3596 | |||
3597 | /* Register new framebuffer */ | ||
3598 | if ((ret = register_framebuffer(&fbdev->fb_info)) < 0) { | ||
3599 | print_err("cannot register new framebuffer"); | ||
3600 | goto failed; | ||
3601 | } | ||
3602 | |||
3603 | au1200fb_fb_set_par(&fbdev->fb_info); | ||
3604 | |||
3605 | #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) | ||
3606 | if (plane == 0) | ||
3607 | if (fb_prepare_logo(&fbdev->fb_info, FB_ROTATE_UR)) { | ||
3608 | /* Start display and show logo on boot */ | ||
3609 | fb_set_cmap(&fbdev->fb_info.cmap, | ||
3610 | &fbdev->fb_info); | ||
3611 | |||
3612 | fb_show_logo(&fbdev->fb_info, FB_ROTATE_UR); | ||
3613 | } | ||
3614 | #endif | ||
3615 | } | ||
3616 | |||
3617 | /* Now hook interrupt too */ | ||
3618 | if ((ret = request_irq(AU1200_LCD_INT, au1200fb_handle_irq, | ||
3619 | SA_INTERRUPT | SA_SHIRQ, "lcd", (void *)dev)) < 0) { | ||
3620 | print_err("fail to request interrupt line %d (err: %d)", | ||
3621 | AU1200_LCD_INT, ret); | ||
3622 | goto failed; | ||
3623 | } | ||
3624 | |||
3625 | return 0; | ||
3626 | |||
3627 | failed: | ||
3628 | /* NOTE: This only does the current plane/window that failed; others are still active */ | ||
3629 | if (fbdev->fb_mem) | ||
3630 | dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len), | ||
3631 | fbdev->fb_mem, fbdev->fb_phys); | ||
3632 | if (fbdev->fb_info.cmap.len != 0) | ||
3633 | fb_dealloc_cmap(&fbdev->fb_info.cmap); | ||
3634 | if (fbdev->fb_info.pseudo_palette) | ||
3635 | kfree(fbdev->fb_info.pseudo_palette); | ||
3636 | if (plane == 0) | ||
3637 | free_irq(AU1200_LCD_INT, (void*)dev); | ||
3638 | return ret; | ||
3639 | } | ||
3640 | |||
3641 | static int au1200fb_drv_remove(struct device *dev) | ||
3642 | { | ||
3643 | struct au1200fb_device *fbdev; | ||
3644 | int plane; | ||
3645 | |||
3646 | if (!dev) | ||
3647 | return -ENODEV; | ||
3648 | |||
3649 | /* Turn off the panel */ | ||
3650 | au1200_setpanel(NULL); | ||
3651 | |||
3652 | for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) | ||
3653 | { | ||
3654 | fbdev = &_au1200fb_devices[plane]; | ||
3655 | |||
3656 | /* Clean up all probe data */ | ||
3657 | unregister_framebuffer(&fbdev->fb_info); | ||
3658 | if (fbdev->fb_mem) | ||
3659 | dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len), | ||
3660 | fbdev->fb_mem, fbdev->fb_phys); | ||
3661 | if (fbdev->fb_info.cmap.len != 0) | ||
3662 | fb_dealloc_cmap(&fbdev->fb_info.cmap); | ||
3663 | if (fbdev->fb_info.pseudo_palette) | ||
3664 | kfree(fbdev->fb_info.pseudo_palette); | ||
3665 | } | ||
3666 | |||
3667 | free_irq(AU1200_LCD_INT, (void *)dev); | ||
3668 | |||
3669 | return 0; | ||
3670 | } | ||
3671 | |||
3672 | #ifdef CONFIG_PM | ||
3673 | static int au1200fb_drv_suspend(struct device *dev, u32 state, u32 level) | ||
3674 | { | ||
3675 | /* TODO */ | ||
3676 | return 0; | ||
3677 | } | ||
3678 | |||
3679 | static int au1200fb_drv_resume(struct device *dev, u32 level) | ||
3680 | { | ||
3681 | /* TODO */ | ||
3682 | return 0; | ||
3683 | } | ||
3684 | #endif /* CONFIG_PM */ | ||
3685 | |||
3686 | static struct device_driver au1200fb_driver = { | ||
3687 | .name = "au1200-lcd", | ||
3688 | .bus = &platform_bus_type, | ||
3689 | .probe = au1200fb_drv_probe, | ||
3690 | .remove = au1200fb_drv_remove, | ||
3691 | #ifdef CONFIG_PM | ||
3692 | .suspend = au1200fb_drv_suspend, | ||
3693 | .resume = au1200fb_drv_resume, | ||
3694 | #endif | ||
3695 | }; | ||
3696 | |||
3697 | /*-------------------------------------------------------------------------*/ | ||
3698 | |||
3699 | /* Kernel driver */ | ||
3700 | |||
3701 | static void au1200fb_setup(void) | ||
3702 | { | ||
3703 | char* options = NULL; | ||
3704 | char* this_opt; | ||
3705 | int num_panels = ARRAY_SIZE(known_lcd_panels); | ||
3706 | int panel_idx = -1; | ||
3707 | |||
3708 | fb_get_options(DRIVER_NAME, &options); | ||
3709 | |||
3710 | if (options) { | ||
3711 | while ((this_opt = strsep(&options,",")) != NULL) { | ||
3712 | /* Panel option - can be panel name, | ||
3713 | * "bs" for board-switch, or number/index */ | ||
3714 | if (!strncmp(this_opt, "panel:", 6)) { | ||
3715 | int i; | ||
3716 | long int li; | ||
3717 | char *endptr; | ||
3718 | this_opt += 6; | ||
3719 | /* First check for index, which allows | ||
3720 | * to short circuit this mess */ | ||
3721 | li = simple_strtol(this_opt, &endptr, 0); | ||
3722 | if (*endptr == '\0') { | ||
3723 | panel_idx = (int)li; | ||
3724 | } | ||
3725 | else if (strcmp(this_opt, "bs") == 0) { | ||
3726 | extern int board_au1200fb_panel(void); | ||
3727 | panel_idx = board_au1200fb_panel(); | ||
3728 | } | ||
3729 | |||
3730 | else | ||
3731 | for (i = 0; i < num_panels; i++) { | ||
3732 | if (!strcmp(this_opt, known_lcd_panels[i].name)) { | ||
3733 | panel_idx = i; | ||
3734 | break; | ||
3735 | } | ||
3736 | } | ||
3737 | |||
3738 | if ((panel_idx < 0) || (panel_idx >= num_panels)) { | ||
3739 | print_warn("Panel %s not supported!", this_opt); | ||
3740 | } | ||
3741 | else | ||
3742 | panel_index = panel_idx; | ||
3743 | } | ||
3744 | |||
3745 | else if (strncmp(this_opt, "nohwcursor", 10) == 0) { | ||
3746 | nohwcursor = 1; | ||
3747 | } | ||
3748 | |||
3749 | /* Unsupported option */ | ||
3750 | else { | ||
3751 | print_warn("Unsupported option \"%s\"", this_opt); | ||
3752 | } | ||
3753 | } | ||
3754 | } | ||
3755 | } | ||
3756 | |||
3757 | #ifdef CONFIG_PM | ||
3758 | static int au1200fb_pm_callback(au1xxx_power_dev_t *dev, | ||
3759 | au1xxx_request_t request, void *data) { | ||
3760 | int retval = -1; | ||
3761 | unsigned int d = 0; | ||
3762 | unsigned int brightness = 0; | ||
3763 | |||
3764 | if (request == AU1XXX_PM_SLEEP) { | ||
3765 | board_au1200fb_panel_shutdown(); | ||
3766 | } | ||
3767 | else if (request == AU1XXX_PM_WAKEUP) { | ||
3768 | if(dev->prev_state == SLEEP_STATE) | ||
3769 | { | ||
3770 | int plane; | ||
3771 | au1200_setpanel(panel); | ||
3772 | for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) { | ||
3773 | struct au1200fb_device *fbdev; | ||
3774 | fbdev = &_au1200fb_devices[plane]; | ||
3775 | au1200fb_fb_set_par(&fbdev->fb_info); | ||
3776 | } | ||
3777 | } | ||
3778 | |||
3779 | d = *((unsigned int*)data); | ||
3780 | if(d <=10) brightness = 26; | ||
3781 | else if(d<=20) brightness = 51; | ||
3782 | else if(d<=30) brightness = 77; | ||
3783 | else if(d<=40) brightness = 102; | ||
3784 | else if(d<=50) brightness = 128; | ||
3785 | else if(d<=60) brightness = 153; | ||
3786 | else if(d<=70) brightness = 179; | ||
3787 | else if(d<=80) brightness = 204; | ||
3788 | else if(d<=90) brightness = 230; | ||
3789 | else brightness = 255; | ||
3790 | set_brightness(brightness); | ||
3791 | } else if (request == AU1XXX_PM_GETSTATUS) { | ||
3792 | return dev->cur_state; | ||
3793 | } else if (request == AU1XXX_PM_ACCESS) { | ||
3794 | if (dev->cur_state != SLEEP_STATE) | ||
3795 | return retval; | ||
3796 | else { | ||
3797 | au1200_setpanel(panel); | ||
3798 | } | ||
3799 | } else if (request == AU1XXX_PM_IDLE) { | ||
3800 | } else if (request == AU1XXX_PM_CLEANUP) { | ||
3801 | } | ||
3802 | |||
3803 | return retval; | ||
3804 | } | ||
3805 | #endif | ||
3806 | |||
3807 | static int __init au1200fb_init(void) | ||
3808 | { | ||
3809 | print_info("" DRIVER_DESC ""); | ||
3810 | |||
3811 | /* Setup driver with options */ | ||
3812 | au1200fb_setup(); | ||
3813 | |||
3814 | /* Point to the panel selected */ | ||
3815 | panel = &known_lcd_panels[panel_index]; | ||
3816 | win = &windows[window_index]; | ||
3817 | |||
3818 | printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name); | ||
3819 | printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name); | ||
3820 | |||
3821 | /* Kickstart the panel, the framebuffers/windows come soon enough */ | ||
3822 | au1200_setpanel(panel); | ||
3823 | |||
3824 | #ifdef CONFIG_PM | ||
3825 | LCD_pm_dev = new_au1xxx_power_device("LCD", &au1200fb_pm_callback, NULL); | ||
3826 | if ( LCD_pm_dev == NULL) | ||
3827 | printk(KERN_INFO "Unable to create a power management device entry for the au1200fb.\n"); | ||
3828 | else | ||
3829 | printk(KERN_INFO "Power management device entry for the au1200fb loaded.\n"); | ||
3830 | #endif | ||
3831 | |||
3832 | return driver_register(&au1200fb_driver); | ||
3833 | } | ||
3834 | |||
3835 | static void __exit au1200fb_cleanup(void) | ||
3836 | { | ||
3837 | driver_unregister(&au1200fb_driver); | ||
3838 | } | ||
3839 | |||
3840 | module_init(au1200fb_init); | ||
3841 | module_exit(au1200fb_cleanup); | ||
3842 | |||
3843 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
3844 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/au1200fb.h b/drivers/video/au1200fb.h new file mode 100644 index 000000000000..e2672714d8d4 --- /dev/null +++ b/drivers/video/au1200fb.h | |||
@@ -0,0 +1,572 @@ | |||
1 | /* | ||
2 | * BRIEF MODULE DESCRIPTION | ||
3 | * Hardware definitions for the Au1200 LCD controller | ||
4 | * | ||
5 | * Copyright 2004 AMD | ||
6 | * Author: AMD | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
14 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
15 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
16 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
17 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
18 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
19 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License along | ||
25 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
26 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
27 | */ | ||
28 | |||
29 | #ifndef _AU1200LCD_H | ||
30 | #define _AU1200LCD_H | ||
31 | |||
32 | /********************************************************************/ | ||
33 | #define AU1200_LCD_ADDR 0xB5000000 | ||
34 | |||
35 | #define uint8 unsigned char | ||
36 | #define uint32 unsigned int | ||
37 | |||
38 | struct au1200_lcd { | ||
39 | volatile uint32 reserved0; | ||
40 | volatile uint32 screen; | ||
41 | volatile uint32 backcolor; | ||
42 | volatile uint32 horztiming; | ||
43 | volatile uint32 verttiming; | ||
44 | volatile uint32 clkcontrol; | ||
45 | volatile uint32 pwmdiv; | ||
46 | volatile uint32 pwmhi; | ||
47 | volatile uint32 reserved1; | ||
48 | volatile uint32 winenable; | ||
49 | volatile uint32 colorkey; | ||
50 | volatile uint32 colorkeymsk; | ||
51 | struct | ||
52 | { | ||
53 | volatile uint32 cursorctrl; | ||
54 | volatile uint32 cursorpos; | ||
55 | volatile uint32 cursorcolor0; | ||
56 | volatile uint32 cursorcolor1; | ||
57 | volatile uint32 cursorcolor2; | ||
58 | uint32 cursorcolor3; | ||
59 | } hwc; | ||
60 | volatile uint32 intstatus; | ||
61 | volatile uint32 intenable; | ||
62 | volatile uint32 outmask; | ||
63 | volatile uint32 fifoctrl; | ||
64 | uint32 reserved2[(0x0100-0x0058)/4]; | ||
65 | struct | ||
66 | { | ||
67 | volatile uint32 winctrl0; | ||
68 | volatile uint32 winctrl1; | ||
69 | volatile uint32 winctrl2; | ||
70 | volatile uint32 winbuf0; | ||
71 | volatile uint32 winbuf1; | ||
72 | volatile uint32 winbufctrl; | ||
73 | uint32 winreserved0; | ||
74 | uint32 winreserved1; | ||
75 | } window[4]; | ||
76 | |||
77 | uint32 reserved3[(0x0400-0x0180)/4]; | ||
78 | |||
79 | volatile uint32 palette[(0x0800-0x0400)/4]; | ||
80 | |||
81 | volatile uint8 cursorpattern[256]; | ||
82 | }; | ||
83 | |||
84 | /* lcd_screen */ | ||
85 | #define LCD_SCREEN_SEN (1<<31) | ||
86 | #define LCD_SCREEN_SX (0x07FF<<19) | ||
87 | #define LCD_SCREEN_SY (0x07FF<< 8) | ||
88 | #define LCD_SCREEN_SWP (1<<7) | ||
89 | #define LCD_SCREEN_SWD (1<<6) | ||
90 | #define LCD_SCREEN_PT (7<<0) | ||
91 | #define LCD_SCREEN_PT_TFT (0<<0) | ||
92 | #define LCD_SCREEN_SX_N(WIDTH) ((WIDTH-1)<<19) | ||
93 | #define LCD_SCREEN_SY_N(HEIGHT) ((HEIGHT-1)<<8) | ||
94 | #define LCD_SCREEN_PT_CSTN (1<<0) | ||
95 | #define LCD_SCREEN_PT_CDSTN (2<<0) | ||
96 | #define LCD_SCREEN_PT_M8STN (3<<0) | ||
97 | #define LCD_SCREEN_PT_M4STN (4<<0) | ||
98 | |||
99 | /* lcd_backcolor */ | ||
100 | #define LCD_BACKCOLOR_SBGR (0xFF<<16) | ||
101 | #define LCD_BACKCOLOR_SBGG (0xFF<<8) | ||
102 | #define LCD_BACKCOLOR_SBGB (0xFF<<0) | ||
103 | #define LCD_BACKCOLOR_SBGR_N(N) ((N)<<16) | ||
104 | #define LCD_BACKCOLOR_SBGG_N(N) ((N)<<8) | ||
105 | #define LCD_BACKCOLOR_SBGB_N(N) ((N)<<0) | ||
106 | |||
107 | /* lcd_winenable */ | ||
108 | #define LCD_WINENABLE_WEN3 (1<<3) | ||
109 | #define LCD_WINENABLE_WEN2 (1<<2) | ||
110 | #define LCD_WINENABLE_WEN1 (1<<1) | ||
111 | #define LCD_WINENABLE_WEN0 (1<<0) | ||
112 | |||
113 | /* lcd_colorkey */ | ||
114 | #define LCD_COLORKEY_CKR (0xFF<<16) | ||
115 | #define LCD_COLORKEY_CKG (0xFF<<8) | ||
116 | #define LCD_COLORKEY_CKB (0xFF<<0) | ||
117 | #define LCD_COLORKEY_CKR_N(N) ((N)<<16) | ||
118 | #define LCD_COLORKEY_CKG_N(N) ((N)<<8) | ||
119 | #define LCD_COLORKEY_CKB_N(N) ((N)<<0) | ||
120 | |||
121 | /* lcd_colorkeymsk */ | ||
122 | #define LCD_COLORKEYMSK_CKMR (0xFF<<16) | ||
123 | #define LCD_COLORKEYMSK_CKMG (0xFF<<8) | ||
124 | #define LCD_COLORKEYMSK_CKMB (0xFF<<0) | ||
125 | #define LCD_COLORKEYMSK_CKMR_N(N) ((N)<<16) | ||
126 | #define LCD_COLORKEYMSK_CKMG_N(N) ((N)<<8) | ||
127 | #define LCD_COLORKEYMSK_CKMB_N(N) ((N)<<0) | ||
128 | |||
129 | /* lcd windows control 0 */ | ||
130 | #define LCD_WINCTRL0_OX (0x07FF<<21) | ||
131 | #define LCD_WINCTRL0_OY (0x07FF<<10) | ||
132 | #define LCD_WINCTRL0_A (0x00FF<<2) | ||
133 | #define LCD_WINCTRL0_AEN (1<<1) | ||
134 | #define LCD_WINCTRL0_OX_N(N) ((N)<<21) | ||
135 | #define LCD_WINCTRL0_OY_N(N) ((N)<<10) | ||
136 | #define LCD_WINCTRL0_A_N(N) ((N)<<2) | ||
137 | |||
138 | /* lcd windows control 1 */ | ||
139 | #define LCD_WINCTRL1_PRI (3<<30) | ||
140 | #define LCD_WINCTRL1_PIPE (1<<29) | ||
141 | #define LCD_WINCTRL1_FRM (0xF<<25) | ||
142 | #define LCD_WINCTRL1_CCO (1<<24) | ||
143 | #define LCD_WINCTRL1_PO (3<<22) | ||
144 | #define LCD_WINCTRL1_SZX (0x07FF<<11) | ||
145 | #define LCD_WINCTRL1_SZY (0x07FF<<0) | ||
146 | #define LCD_WINCTRL1_FRM_1BPP (0<<25) | ||
147 | #define LCD_WINCTRL1_FRM_2BPP (1<<25) | ||
148 | #define LCD_WINCTRL1_FRM_4BPP (2<<25) | ||
149 | #define LCD_WINCTRL1_FRM_8BPP (3<<25) | ||
150 | #define LCD_WINCTRL1_FRM_12BPP (4<<25) | ||
151 | #define LCD_WINCTRL1_FRM_16BPP655 (5<<25) | ||
152 | #define LCD_WINCTRL1_FRM_16BPP565 (6<<25) | ||
153 | #define LCD_WINCTRL1_FRM_16BPP556 (7<<25) | ||
154 | #define LCD_WINCTRL1_FRM_16BPPI1555 (8<<25) | ||
155 | #define LCD_WINCTRL1_FRM_16BPPI5551 (9<<25) | ||
156 | #define LCD_WINCTRL1_FRM_16BPPA1555 (10<<25) | ||
157 | #define LCD_WINCTRL1_FRM_16BPPA5551 (11<<25) | ||
158 | #define LCD_WINCTRL1_FRM_24BPP (12<<25) | ||
159 | #define LCD_WINCTRL1_FRM_32BPP (13<<25) | ||
160 | #define LCD_WINCTRL1_PRI_N(N) ((N)<<30) | ||
161 | #define LCD_WINCTRL1_PO_00 (0<<22) | ||
162 | #define LCD_WINCTRL1_PO_01 (1<<22) | ||
163 | #define LCD_WINCTRL1_PO_10 (2<<22) | ||
164 | #define LCD_WINCTRL1_PO_11 (3<<22) | ||
165 | #define LCD_WINCTRL1_SZX_N(N) ((N-1)<<11) | ||
166 | #define LCD_WINCTRL1_SZY_N(N) ((N-1)<<0) | ||
167 | |||
168 | /* lcd windows control 2 */ | ||
169 | #define LCD_WINCTRL2_CKMODE (3<<24) | ||
170 | #define LCD_WINCTRL2_DBM (1<<23) | ||
171 | #define LCD_WINCTRL2_RAM (3<<21) | ||
172 | #define LCD_WINCTRL2_BX (0x1FFF<<8) | ||
173 | #define LCD_WINCTRL2_SCX (0xF<<4) | ||
174 | #define LCD_WINCTRL2_SCY (0xF<<0) | ||
175 | #define LCD_WINCTRL2_CKMODE_00 (0<<24) | ||
176 | #define LCD_WINCTRL2_CKMODE_01 (1<<24) | ||
177 | #define LCD_WINCTRL2_CKMODE_10 (2<<24) | ||
178 | #define LCD_WINCTRL2_CKMODE_11 (3<<24) | ||
179 | #define LCD_WINCTRL2_RAM_NONE (0<<21) | ||
180 | #define LCD_WINCTRL2_RAM_PALETTE (1<<21) | ||
181 | #define LCD_WINCTRL2_RAM_GAMMA (2<<21) | ||
182 | #define LCD_WINCTRL2_RAM_BUFFER (3<<21) | ||
183 | #define LCD_WINCTRL2_BX_N(N) ((N)<<8) | ||
184 | #define LCD_WINCTRL2_SCX_1 (0<<4) | ||
185 | #define LCD_WINCTRL2_SCX_2 (1<<4) | ||
186 | #define LCD_WINCTRL2_SCX_4 (2<<4) | ||
187 | #define LCD_WINCTRL2_SCY_1 (0<<0) | ||
188 | #define LCD_WINCTRL2_SCY_2 (1<<0) | ||
189 | #define LCD_WINCTRL2_SCY_4 (2<<0) | ||
190 | |||
191 | /* lcd windows buffer control */ | ||
192 | #define LCD_WINBUFCTRL_DB (1<<1) | ||
193 | #define LCD_WINBUFCTRL_DBN (1<<0) | ||
194 | |||
195 | /* lcd_intstatus, lcd_intenable */ | ||
196 | #define LCD_INT_IFO (0xF<<14) | ||
197 | #define LCD_INT_IFU (0xF<<10) | ||
198 | #define LCD_INT_OFO (1<<9) | ||
199 | #define LCD_INT_OFU (1<<8) | ||
200 | #define LCD_INT_WAIT (1<<3) | ||
201 | #define LCD_INT_SD (1<<2) | ||
202 | #define LCD_INT_SA (1<<1) | ||
203 | #define LCD_INT_SS (1<<0) | ||
204 | |||
205 | /* lcd_horztiming */ | ||
206 | #define LCD_HORZTIMING_HND2 (0x1FF<<18) | ||
207 | #define LCD_HORZTIMING_HND1 (0x1FF<<9) | ||
208 | #define LCD_HORZTIMING_HPW (0x1FF<<0) | ||
209 | #define LCD_HORZTIMING_HND2_N(N)(((N)-1)<<18) | ||
210 | #define LCD_HORZTIMING_HND1_N(N)(((N)-1)<<9) | ||
211 | #define LCD_HORZTIMING_HPW_N(N) (((N)-1)<<0) | ||
212 | |||
213 | /* lcd_verttiming */ | ||
214 | #define LCD_VERTTIMING_VND2 (0x1FF<<18) | ||
215 | #define LCD_VERTTIMING_VND1 (0x1FF<<9) | ||
216 | #define LCD_VERTTIMING_VPW (0x1FF<<0) | ||
217 | #define LCD_VERTTIMING_VND2_N(N)(((N)-1)<<18) | ||
218 | #define LCD_VERTTIMING_VND1_N(N)(((N)-1)<<9) | ||
219 | #define LCD_VERTTIMING_VPW_N(N) (((N)-1)<<0) | ||
220 | |||
221 | /* lcd_clkcontrol */ | ||
222 | #define LCD_CLKCONTROL_EXT (1<<22) | ||
223 | #define LCD_CLKCONTROL_DELAY (3<<20) | ||
224 | #define LCD_CLKCONTROL_CDD (1<<19) | ||
225 | #define LCD_CLKCONTROL_IB (1<<18) | ||
226 | #define LCD_CLKCONTROL_IC (1<<17) | ||
227 | #define LCD_CLKCONTROL_IH (1<<16) | ||
228 | #define LCD_CLKCONTROL_IV (1<<15) | ||
229 | #define LCD_CLKCONTROL_BF (0x1F<<10) | ||
230 | #define LCD_CLKCONTROL_PCD (0x3FF<<0) | ||
231 | #define LCD_CLKCONTROL_BF_N(N) (((N)-1)<<10) | ||
232 | #define LCD_CLKCONTROL_PCD_N(N) ((N)<<0) | ||
233 | |||
234 | /* lcd_pwmdiv */ | ||
235 | #define LCD_PWMDIV_EN (1<<31) | ||
236 | #define LCD_PWMDIV_PWMDIV (0x1FFFF<<0) | ||
237 | #define LCD_PWMDIV_PWMDIV_N(N) ((N)<<0) | ||
238 | |||
239 | /* lcd_pwmhi */ | ||
240 | #define LCD_PWMHI_PWMHI1 (0xFFFF<<16) | ||
241 | #define LCD_PWMHI_PWMHI0 (0xFFFF<<0) | ||
242 | #define LCD_PWMHI_PWMHI1_N(N) ((N)<<16) | ||
243 | #define LCD_PWMHI_PWMHI0_N(N) ((N)<<0) | ||
244 | |||
245 | /* lcd_hwccon */ | ||
246 | #define LCD_HWCCON_EN (1<<0) | ||
247 | |||
248 | /* lcd_cursorpos */ | ||
249 | #define LCD_CURSORPOS_HWCXOFF (0x1F<<27) | ||
250 | #define LCD_CURSORPOS_HWCXPOS (0x07FF<<16) | ||
251 | #define LCD_CURSORPOS_HWCYOFF (0x1F<<11) | ||
252 | #define LCD_CURSORPOS_HWCYPOS (0x07FF<<0) | ||
253 | #define LCD_CURSORPOS_HWCXOFF_N(N) ((N)<<27) | ||
254 | #define LCD_CURSORPOS_HWCXPOS_N(N) ((N)<<16) | ||
255 | #define LCD_CURSORPOS_HWCYOFF_N(N) ((N)<<11) | ||
256 | #define LCD_CURSORPOS_HWCYPOS_N(N) ((N)<<0) | ||
257 | |||
258 | /* lcd_cursorcolor */ | ||
259 | #define LCD_CURSORCOLOR_HWCA (0xFF<<24) | ||
260 | #define LCD_CURSORCOLOR_HWCR (0xFF<<16) | ||
261 | #define LCD_CURSORCOLOR_HWCG (0xFF<<8) | ||
262 | #define LCD_CURSORCOLOR_HWCB (0xFF<<0) | ||
263 | #define LCD_CURSORCOLOR_HWCA_N(N) ((N)<<24) | ||
264 | #define LCD_CURSORCOLOR_HWCR_N(N) ((N)<<16) | ||
265 | #define LCD_CURSORCOLOR_HWCG_N(N) ((N)<<8) | ||
266 | #define LCD_CURSORCOLOR_HWCB_N(N) ((N)<<0) | ||
267 | |||
268 | /* lcd_fifoctrl */ | ||
269 | #define LCD_FIFOCTRL_F3IF (1<<29) | ||
270 | #define LCD_FIFOCTRL_F3REQ (0x1F<<24) | ||
271 | #define LCD_FIFOCTRL_F2IF (1<<29) | ||
272 | #define LCD_FIFOCTRL_F2REQ (0x1F<<16) | ||
273 | #define LCD_FIFOCTRL_F1IF (1<<29) | ||
274 | #define LCD_FIFOCTRL_F1REQ (0x1F<<8) | ||
275 | #define LCD_FIFOCTRL_F0IF (1<<29) | ||
276 | #define LCD_FIFOCTRL_F0REQ (0x1F<<0) | ||
277 | #define LCD_FIFOCTRL_F3REQ_N(N) ((N-1)<<24) | ||
278 | #define LCD_FIFOCTRL_F2REQ_N(N) ((N-1)<<16) | ||
279 | #define LCD_FIFOCTRL_F1REQ_N(N) ((N-1)<<8) | ||
280 | #define LCD_FIFOCTRL_F0REQ_N(N) ((N-1)<<0) | ||
281 | |||
282 | /* lcd_outmask */ | ||
283 | #define LCD_OUTMASK_MASK (0x00FFFFFF) | ||
284 | |||
285 | /********************************************************************/ | ||
286 | #endif /* _AU1200LCD_H */ | ||
287 | /* | ||
288 | * BRIEF MODULE DESCRIPTION | ||
289 | * Hardware definitions for the Au1200 LCD controller | ||
290 | * | ||
291 | * Copyright 2004 AMD | ||
292 | * Author: AMD | ||
293 | * | ||
294 | * This program is free software; you can redistribute it and/or modify it | ||
295 | * under the terms of the GNU General Public License as published by the | ||
296 | * Free Software Foundation; either version 2 of the License, or (at your | ||
297 | * option) any later version. | ||
298 | * | ||
299 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
300 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
301 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
302 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
303 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
304 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
305 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
306 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
307 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
308 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
309 | * | ||
310 | * You should have received a copy of the GNU General Public License along | ||
311 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
312 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
313 | */ | ||
314 | |||
315 | #ifndef _AU1200LCD_H | ||
316 | #define _AU1200LCD_H | ||
317 | |||
318 | /********************************************************************/ | ||
319 | #define AU1200_LCD_ADDR 0xB5000000 | ||
320 | |||
321 | #define uint8 unsigned char | ||
322 | #define uint32 unsigned int | ||
323 | |||
324 | struct au1200_lcd { | ||
325 | volatile uint32 reserved0; | ||
326 | volatile uint32 screen; | ||
327 | volatile uint32 backcolor; | ||
328 | volatile uint32 horztiming; | ||
329 | volatile uint32 verttiming; | ||
330 | volatile uint32 clkcontrol; | ||
331 | volatile uint32 pwmdiv; | ||
332 | volatile uint32 pwmhi; | ||
333 | volatile uint32 reserved1; | ||
334 | volatile uint32 winenable; | ||
335 | volatile uint32 colorkey; | ||
336 | volatile uint32 colorkeymsk; | ||
337 | struct | ||
338 | { | ||
339 | volatile uint32 cursorctrl; | ||
340 | volatile uint32 cursorpos; | ||
341 | volatile uint32 cursorcolor0; | ||
342 | volatile uint32 cursorcolor1; | ||
343 | volatile uint32 cursorcolor2; | ||
344 | uint32 cursorcolor3; | ||
345 | } hwc; | ||
346 | volatile uint32 intstatus; | ||
347 | volatile uint32 intenable; | ||
348 | volatile uint32 outmask; | ||
349 | volatile uint32 fifoctrl; | ||
350 | uint32 reserved2[(0x0100-0x0058)/4]; | ||
351 | struct | ||
352 | { | ||
353 | volatile uint32 winctrl0; | ||
354 | volatile uint32 winctrl1; | ||
355 | volatile uint32 winctrl2; | ||
356 | volatile uint32 winbuf0; | ||
357 | volatile uint32 winbuf1; | ||
358 | volatile uint32 winbufctrl; | ||
359 | uint32 winreserved0; | ||
360 | uint32 winreserved1; | ||
361 | } window[4]; | ||
362 | |||
363 | uint32 reserved3[(0x0400-0x0180)/4]; | ||
364 | |||
365 | volatile uint32 palette[(0x0800-0x0400)/4]; | ||
366 | |||
367 | volatile uint8 cursorpattern[256]; | ||
368 | }; | ||
369 | |||
370 | /* lcd_screen */ | ||
371 | #define LCD_SCREEN_SEN (1<<31) | ||
372 | #define LCD_SCREEN_SX (0x07FF<<19) | ||
373 | #define LCD_SCREEN_SY (0x07FF<< 8) | ||
374 | #define LCD_SCREEN_SWP (1<<7) | ||
375 | #define LCD_SCREEN_SWD (1<<6) | ||
376 | #define LCD_SCREEN_PT (7<<0) | ||
377 | #define LCD_SCREEN_PT_TFT (0<<0) | ||
378 | #define LCD_SCREEN_SX_N(WIDTH) ((WIDTH-1)<<19) | ||
379 | #define LCD_SCREEN_SY_N(HEIGHT) ((HEIGHT-1)<<8) | ||
380 | #define LCD_SCREEN_PT_CSTN (1<<0) | ||
381 | #define LCD_SCREEN_PT_CDSTN (2<<0) | ||
382 | #define LCD_SCREEN_PT_M8STN (3<<0) | ||
383 | #define LCD_SCREEN_PT_M4STN (4<<0) | ||
384 | |||
385 | /* lcd_backcolor */ | ||
386 | #define LCD_BACKCOLOR_SBGR (0xFF<<16) | ||
387 | #define LCD_BACKCOLOR_SBGG (0xFF<<8) | ||
388 | #define LCD_BACKCOLOR_SBGB (0xFF<<0) | ||
389 | #define LCD_BACKCOLOR_SBGR_N(N) ((N)<<16) | ||
390 | #define LCD_BACKCOLOR_SBGG_N(N) ((N)<<8) | ||
391 | #define LCD_BACKCOLOR_SBGB_N(N) ((N)<<0) | ||
392 | |||
393 | /* lcd_winenable */ | ||
394 | #define LCD_WINENABLE_WEN3 (1<<3) | ||
395 | #define LCD_WINENABLE_WEN2 (1<<2) | ||
396 | #define LCD_WINENABLE_WEN1 (1<<1) | ||
397 | #define LCD_WINENABLE_WEN0 (1<<0) | ||
398 | |||
399 | /* lcd_colorkey */ | ||
400 | #define LCD_COLORKEY_CKR (0xFF<<16) | ||
401 | #define LCD_COLORKEY_CKG (0xFF<<8) | ||
402 | #define LCD_COLORKEY_CKB (0xFF<<0) | ||
403 | #define LCD_COLORKEY_CKR_N(N) ((N)<<16) | ||
404 | #define LCD_COLORKEY_CKG_N(N) ((N)<<8) | ||
405 | #define LCD_COLORKEY_CKB_N(N) ((N)<<0) | ||
406 | |||
407 | /* lcd_colorkeymsk */ | ||
408 | #define LCD_COLORKEYMSK_CKMR (0xFF<<16) | ||
409 | #define LCD_COLORKEYMSK_CKMG (0xFF<<8) | ||
410 | #define LCD_COLORKEYMSK_CKMB (0xFF<<0) | ||
411 | #define LCD_COLORKEYMSK_CKMR_N(N) ((N)<<16) | ||
412 | #define LCD_COLORKEYMSK_CKMG_N(N) ((N)<<8) | ||
413 | #define LCD_COLORKEYMSK_CKMB_N(N) ((N)<<0) | ||
414 | |||
415 | /* lcd windows control 0 */ | ||
416 | #define LCD_WINCTRL0_OX (0x07FF<<21) | ||
417 | #define LCD_WINCTRL0_OY (0x07FF<<10) | ||
418 | #define LCD_WINCTRL0_A (0x00FF<<2) | ||
419 | #define LCD_WINCTRL0_AEN (1<<1) | ||
420 | #define LCD_WINCTRL0_OX_N(N) ((N)<<21) | ||
421 | #define LCD_WINCTRL0_OY_N(N) ((N)<<10) | ||
422 | #define LCD_WINCTRL0_A_N(N) ((N)<<2) | ||
423 | |||
424 | /* lcd windows control 1 */ | ||
425 | #define LCD_WINCTRL1_PRI (3<<30) | ||
426 | #define LCD_WINCTRL1_PIPE (1<<29) | ||
427 | #define LCD_WINCTRL1_FRM (0xF<<25) | ||
428 | #define LCD_WINCTRL1_CCO (1<<24) | ||
429 | #define LCD_WINCTRL1_PO (3<<22) | ||
430 | #define LCD_WINCTRL1_SZX (0x07FF<<11) | ||
431 | #define LCD_WINCTRL1_SZY (0x07FF<<0) | ||
432 | #define LCD_WINCTRL1_FRM_1BPP (0<<25) | ||
433 | #define LCD_WINCTRL1_FRM_2BPP (1<<25) | ||
434 | #define LCD_WINCTRL1_FRM_4BPP (2<<25) | ||
435 | #define LCD_WINCTRL1_FRM_8BPP (3<<25) | ||
436 | #define LCD_WINCTRL1_FRM_12BPP (4<<25) | ||
437 | #define LCD_WINCTRL1_FRM_16BPP655 (5<<25) | ||
438 | #define LCD_WINCTRL1_FRM_16BPP565 (6<<25) | ||
439 | #define LCD_WINCTRL1_FRM_16BPP556 (7<<25) | ||
440 | #define LCD_WINCTRL1_FRM_16BPPI1555 (8<<25) | ||
441 | #define LCD_WINCTRL1_FRM_16BPPI5551 (9<<25) | ||
442 | #define LCD_WINCTRL1_FRM_16BPPA1555 (10<<25) | ||
443 | #define LCD_WINCTRL1_FRM_16BPPA5551 (11<<25) | ||
444 | #define LCD_WINCTRL1_FRM_24BPP (12<<25) | ||
445 | #define LCD_WINCTRL1_FRM_32BPP (13<<25) | ||
446 | #define LCD_WINCTRL1_PRI_N(N) ((N)<<30) | ||
447 | #define LCD_WINCTRL1_PO_00 (0<<22) | ||
448 | #define LCD_WINCTRL1_PO_01 (1<<22) | ||
449 | #define LCD_WINCTRL1_PO_10 (2<<22) | ||
450 | #define LCD_WINCTRL1_PO_11 (3<<22) | ||
451 | #define LCD_WINCTRL1_SZX_N(N) ((N-1)<<11) | ||
452 | #define LCD_WINCTRL1_SZY_N(N) ((N-1)<<0) | ||
453 | |||
454 | /* lcd windows control 2 */ | ||
455 | #define LCD_WINCTRL2_CKMODE (3<<24) | ||
456 | #define LCD_WINCTRL2_DBM (1<<23) | ||
457 | #define LCD_WINCTRL2_RAM (3<<21) | ||
458 | #define LCD_WINCTRL2_BX (0x1FFF<<8) | ||
459 | #define LCD_WINCTRL2_SCX (0xF<<4) | ||
460 | #define LCD_WINCTRL2_SCY (0xF<<0) | ||
461 | #define LCD_WINCTRL2_CKMODE_00 (0<<24) | ||
462 | #define LCD_WINCTRL2_CKMODE_01 (1<<24) | ||
463 | #define LCD_WINCTRL2_CKMODE_10 (2<<24) | ||
464 | #define LCD_WINCTRL2_CKMODE_11 (3<<24) | ||
465 | #define LCD_WINCTRL2_RAM_NONE (0<<21) | ||
466 | #define LCD_WINCTRL2_RAM_PALETTE (1<<21) | ||
467 | #define LCD_WINCTRL2_RAM_GAMMA (2<<21) | ||
468 | #define LCD_WINCTRL2_RAM_BUFFER (3<<21) | ||
469 | #define LCD_WINCTRL2_BX_N(N) ((N)<<8) | ||
470 | #define LCD_WINCTRL2_SCX_1 (0<<4) | ||
471 | #define LCD_WINCTRL2_SCX_2 (1<<4) | ||
472 | #define LCD_WINCTRL2_SCX_4 (2<<4) | ||
473 | #define LCD_WINCTRL2_SCY_1 (0<<0) | ||
474 | #define LCD_WINCTRL2_SCY_2 (1<<0) | ||
475 | #define LCD_WINCTRL2_SCY_4 (2<<0) | ||
476 | |||
477 | /* lcd windows buffer control */ | ||
478 | #define LCD_WINBUFCTRL_DB (1<<1) | ||
479 | #define LCD_WINBUFCTRL_DBN (1<<0) | ||
480 | |||
481 | /* lcd_intstatus, lcd_intenable */ | ||
482 | #define LCD_INT_IFO (0xF<<14) | ||
483 | #define LCD_INT_IFU (0xF<<10) | ||
484 | #define LCD_INT_OFO (1<<9) | ||
485 | #define LCD_INT_OFU (1<<8) | ||
486 | #define LCD_INT_WAIT (1<<3) | ||
487 | #define LCD_INT_SD (1<<2) | ||
488 | #define LCD_INT_SA (1<<1) | ||
489 | #define LCD_INT_SS (1<<0) | ||
490 | |||
491 | /* lcd_horztiming */ | ||
492 | #define LCD_HORZTIMING_HND2 (0x1FF<<18) | ||
493 | #define LCD_HORZTIMING_HND1 (0x1FF<<9) | ||
494 | #define LCD_HORZTIMING_HPW (0x1FF<<0) | ||
495 | #define LCD_HORZTIMING_HND2_N(N)(((N)-1)<<18) | ||
496 | #define LCD_HORZTIMING_HND1_N(N)(((N)-1)<<9) | ||
497 | #define LCD_HORZTIMING_HPW_N(N) (((N)-1)<<0) | ||
498 | |||
499 | /* lcd_verttiming */ | ||
500 | #define LCD_VERTTIMING_VND2 (0x1FF<<18) | ||
501 | #define LCD_VERTTIMING_VND1 (0x1FF<<9) | ||
502 | #define LCD_VERTTIMING_VPW (0x1FF<<0) | ||
503 | #define LCD_VERTTIMING_VND2_N(N)(((N)-1)<<18) | ||
504 | #define LCD_VERTTIMING_VND1_N(N)(((N)-1)<<9) | ||
505 | #define LCD_VERTTIMING_VPW_N(N) (((N)-1)<<0) | ||
506 | |||
507 | /* lcd_clkcontrol */ | ||
508 | #define LCD_CLKCONTROL_EXT (1<<22) | ||
509 | #define LCD_CLKCONTROL_DELAY (3<<20) | ||
510 | #define LCD_CLKCONTROL_CDD (1<<19) | ||
511 | #define LCD_CLKCONTROL_IB (1<<18) | ||
512 | #define LCD_CLKCONTROL_IC (1<<17) | ||
513 | #define LCD_CLKCONTROL_IH (1<<16) | ||
514 | #define LCD_CLKCONTROL_IV (1<<15) | ||
515 | #define LCD_CLKCONTROL_BF (0x1F<<10) | ||
516 | #define LCD_CLKCONTROL_PCD (0x3FF<<0) | ||
517 | #define LCD_CLKCONTROL_BF_N(N) (((N)-1)<<10) | ||
518 | #define LCD_CLKCONTROL_PCD_N(N) ((N)<<0) | ||
519 | |||
520 | /* lcd_pwmdiv */ | ||
521 | #define LCD_PWMDIV_EN (1<<31) | ||
522 | #define LCD_PWMDIV_PWMDIV (0x1FFFF<<0) | ||
523 | #define LCD_PWMDIV_PWMDIV_N(N) ((N)<<0) | ||
524 | |||
525 | /* lcd_pwmhi */ | ||
526 | #define LCD_PWMHI_PWMHI1 (0xFFFF<<16) | ||
527 | #define LCD_PWMHI_PWMHI0 (0xFFFF<<0) | ||
528 | #define LCD_PWMHI_PWMHI1_N(N) ((N)<<16) | ||
529 | #define LCD_PWMHI_PWMHI0_N(N) ((N)<<0) | ||
530 | |||
531 | /* lcd_hwccon */ | ||
532 | #define LCD_HWCCON_EN (1<<0) | ||
533 | |||
534 | /* lcd_cursorpos */ | ||
535 | #define LCD_CURSORPOS_HWCXOFF (0x1F<<27) | ||
536 | #define LCD_CURSORPOS_HWCXPOS (0x07FF<<16) | ||
537 | #define LCD_CURSORPOS_HWCYOFF (0x1F<<11) | ||
538 | #define LCD_CURSORPOS_HWCYPOS (0x07FF<<0) | ||
539 | #define LCD_CURSORPOS_HWCXOFF_N(N) ((N)<<27) | ||
540 | #define LCD_CURSORPOS_HWCXPOS_N(N) ((N)<<16) | ||
541 | #define LCD_CURSORPOS_HWCYOFF_N(N) ((N)<<11) | ||
542 | #define LCD_CURSORPOS_HWCYPOS_N(N) ((N)<<0) | ||
543 | |||
544 | /* lcd_cursorcolor */ | ||
545 | #define LCD_CURSORCOLOR_HWCA (0xFF<<24) | ||
546 | #define LCD_CURSORCOLOR_HWCR (0xFF<<16) | ||
547 | #define LCD_CURSORCOLOR_HWCG (0xFF<<8) | ||
548 | #define LCD_CURSORCOLOR_HWCB (0xFF<<0) | ||
549 | #define LCD_CURSORCOLOR_HWCA_N(N) ((N)<<24) | ||
550 | #define LCD_CURSORCOLOR_HWCR_N(N) ((N)<<16) | ||
551 | #define LCD_CURSORCOLOR_HWCG_N(N) ((N)<<8) | ||
552 | #define LCD_CURSORCOLOR_HWCB_N(N) ((N)<<0) | ||
553 | |||
554 | /* lcd_fifoctrl */ | ||
555 | #define LCD_FIFOCTRL_F3IF (1<<29) | ||
556 | #define LCD_FIFOCTRL_F3REQ (0x1F<<24) | ||
557 | #define LCD_FIFOCTRL_F2IF (1<<29) | ||
558 | #define LCD_FIFOCTRL_F2REQ (0x1F<<16) | ||
559 | #define LCD_FIFOCTRL_F1IF (1<<29) | ||
560 | #define LCD_FIFOCTRL_F1REQ (0x1F<<8) | ||
561 | #define LCD_FIFOCTRL_F0IF (1<<29) | ||
562 | #define LCD_FIFOCTRL_F0REQ (0x1F<<0) | ||
563 | #define LCD_FIFOCTRL_F3REQ_N(N) ((N-1)<<24) | ||
564 | #define LCD_FIFOCTRL_F2REQ_N(N) ((N-1)<<16) | ||
565 | #define LCD_FIFOCTRL_F1REQ_N(N) ((N-1)<<8) | ||
566 | #define LCD_FIFOCTRL_F0REQ_N(N) ((N-1)<<0) | ||
567 | |||
568 | /* lcd_outmask */ | ||
569 | #define LCD_OUTMASK_MASK (0x00FFFFFF) | ||
570 | |||
571 | /********************************************************************/ | ||
572 | #endif /* _AU1200LCD_H */ | ||
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index bc061d4ec786..72ff6bf75e5e 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c | |||
@@ -178,8 +178,6 @@ struct chips_init_reg { | |||
178 | unsigned char data; | 178 | unsigned char data; |
179 | }; | 179 | }; |
180 | 180 | ||
181 | #define N_ELTS(x) (sizeof(x) / sizeof(x[0])) | ||
182 | |||
183 | static struct chips_init_reg chips_init_sr[] = { | 181 | static struct chips_init_reg chips_init_sr[] = { |
184 | { 0x00, 0x03 }, | 182 | { 0x00, 0x03 }, |
185 | { 0x01, 0x01 }, | 183 | { 0x01, 0x01 }, |
@@ -287,18 +285,18 @@ static void __init chips_hw_init(void) | |||
287 | { | 285 | { |
288 | int i; | 286 | int i; |
289 | 287 | ||
290 | for (i = 0; i < N_ELTS(chips_init_xr); ++i) | 288 | for (i = 0; i < ARRAY_SIZE(chips_init_xr); ++i) |
291 | write_xr(chips_init_xr[i].addr, chips_init_xr[i].data); | 289 | write_xr(chips_init_xr[i].addr, chips_init_xr[i].data); |
292 | outb(0x29, 0x3c2); /* set misc output reg */ | 290 | outb(0x29, 0x3c2); /* set misc output reg */ |
293 | for (i = 0; i < N_ELTS(chips_init_sr); ++i) | 291 | for (i = 0; i < ARRAY_SIZE(chips_init_sr); ++i) |
294 | write_sr(chips_init_sr[i].addr, chips_init_sr[i].data); | 292 | write_sr(chips_init_sr[i].addr, chips_init_sr[i].data); |
295 | for (i = 0; i < N_ELTS(chips_init_gr); ++i) | 293 | for (i = 0; i < ARRAY_SIZE(chips_init_gr); ++i) |
296 | write_gr(chips_init_gr[i].addr, chips_init_gr[i].data); | 294 | write_gr(chips_init_gr[i].addr, chips_init_gr[i].data); |
297 | for (i = 0; i < N_ELTS(chips_init_ar); ++i) | 295 | for (i = 0; i < ARRAY_SIZE(chips_init_ar); ++i) |
298 | write_ar(chips_init_ar[i].addr, chips_init_ar[i].data); | 296 | write_ar(chips_init_ar[i].addr, chips_init_ar[i].data); |
299 | for (i = 0; i < N_ELTS(chips_init_cr); ++i) | 297 | for (i = 0; i < ARRAY_SIZE(chips_init_cr); ++i) |
300 | write_cr(chips_init_cr[i].addr, chips_init_cr[i].data); | 298 | write_cr(chips_init_cr[i].addr, chips_init_cr[i].data); |
301 | for (i = 0; i < N_ELTS(chips_init_fr); ++i) | 299 | for (i = 0; i < ARRAY_SIZE(chips_init_fr); ++i) |
302 | write_fr(chips_init_fr[i].addr, chips_init_fr[i].data); | 300 | write_fr(chips_init_fr[i].addr, chips_init_fr[i].data); |
303 | } | 301 | } |
304 | 302 | ||
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index 6ee449858a5c..4444bef68fba 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig | |||
@@ -26,6 +26,30 @@ config VGA_CONSOLE | |||
26 | # fi | 26 | # fi |
27 | # fi | 27 | # fi |
28 | 28 | ||
29 | config VGACON_SOFT_SCROLLBACK | ||
30 | bool "Enable Scrollback Buffer in System RAM" | ||
31 | depends on VGA_CONSOLE | ||
32 | default n | ||
33 | help | ||
34 | The scrollback buffer of the standard VGA console is located in | ||
35 | the VGA RAM. The size of this RAM is fixed and is quite small. | ||
36 | If you require a larger scrollback buffer, this can be placed in | ||
37 | System RAM which is dynamically allocated during intialization. | ||
38 | Placing the scrollback buffer in System RAM will slightly slow | ||
39 | down the console. | ||
40 | |||
41 | If you want this feature, say 'Y' here and enter the amount of | ||
42 | RAM to allocate for this buffer. If unsure, say 'N'. | ||
43 | |||
44 | config VGACON_SOFT_SCROLLBACK_SIZE | ||
45 | int "Scrollback Buffer Size (in KB)" | ||
46 | depends on VGACON_SOFT_SCROLLBACK | ||
47 | default "64" | ||
48 | help | ||
49 | Enter the amount of System RAM to allocate for the scrollback | ||
50 | buffer. Each 64KB will give you approximately 16 80x25 | ||
51 | screenfuls of scrollback buffer | ||
52 | |||
29 | config VIDEO_SELECT | 53 | config VIDEO_SELECT |
30 | bool "Video mode selection support" | 54 | bool "Video mode selection support" |
31 | depends on X86 && VGA_CONSOLE | 55 | depends on X86 && VGA_CONSOLE |
diff --git a/drivers/video/console/fonts.c b/drivers/video/console/fonts.c index 4fd07d9eca03..0cc1bfda76a6 100644 --- a/drivers/video/console/fonts.c +++ b/drivers/video/console/fonts.c | |||
@@ -66,7 +66,7 @@ static const struct font_desc *fonts[] = { | |||
66 | #endif | 66 | #endif |
67 | }; | 67 | }; |
68 | 68 | ||
69 | #define num_fonts (sizeof(fonts)/sizeof(*fonts)) | 69 | #define num_fonts ARRAY_SIZE(fonts) |
70 | 70 | ||
71 | #ifdef NO_FONTS | 71 | #ifdef NO_FONTS |
72 | #error No fonts configured. | 72 | #error No fonts configured. |
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index 762c7a593141..e99fe30e568c 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c | |||
@@ -149,7 +149,7 @@ static inline void newport_clear_lines(int ystart, int yend, int ci) | |||
149 | newport_clear_screen(0, ystart, 1280 + 63, yend, ci); | 149 | newport_clear_screen(0, ystart, 1280 + 63, yend, ci); |
150 | } | 150 | } |
151 | 151 | ||
152 | void newport_reset(void) | 152 | static void newport_reset(void) |
153 | { | 153 | { |
154 | unsigned short treg; | 154 | unsigned short treg; |
155 | int i; | 155 | int i; |
@@ -193,7 +193,7 @@ void newport_reset(void) | |||
193 | * calculate the actual screen size by reading | 193 | * calculate the actual screen size by reading |
194 | * the video timing out of the VC2 | 194 | * the video timing out of the VC2 |
195 | */ | 195 | */ |
196 | void newport_get_screensize(void) | 196 | static void newport_get_screensize(void) |
197 | { | 197 | { |
198 | int i, cols; | 198 | int i, cols; |
199 | unsigned short ventry, treg; | 199 | unsigned short ventry, treg; |
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 5a86978537d2..d5a04b68c4d4 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c | |||
@@ -93,7 +93,6 @@ static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, | |||
93 | static void vgacon_invert_region(struct vc_data *c, u16 * p, int count); | 93 | static void vgacon_invert_region(struct vc_data *c, u16 * p, int count); |
94 | static unsigned long vgacon_uni_pagedir[2]; | 94 | static unsigned long vgacon_uni_pagedir[2]; |
95 | 95 | ||
96 | |||
97 | /* Description of the hardware situation */ | 96 | /* Description of the hardware situation */ |
98 | static unsigned long vga_vram_base; /* Base of video memory */ | 97 | static unsigned long vga_vram_base; /* Base of video memory */ |
99 | static unsigned long vga_vram_end; /* End of video memory */ | 98 | static unsigned long vga_vram_end; /* End of video memory */ |
@@ -161,6 +160,201 @@ static inline void write_vga(unsigned char reg, unsigned int val) | |||
161 | spin_unlock_irqrestore(&vga_lock, flags); | 160 | spin_unlock_irqrestore(&vga_lock, flags); |
162 | } | 161 | } |
163 | 162 | ||
163 | static inline void vga_set_mem_top(struct vc_data *c) | ||
164 | { | ||
165 | write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2); | ||
166 | } | ||
167 | |||
168 | #ifdef CONFIG_VGACON_SOFT_SCROLLBACK | ||
169 | #include <linux/bootmem.h> | ||
170 | /* software scrollback */ | ||
171 | static void *vgacon_scrollback; | ||
172 | static int vgacon_scrollback_tail; | ||
173 | static int vgacon_scrollback_size; | ||
174 | static int vgacon_scrollback_rows; | ||
175 | static int vgacon_scrollback_cnt; | ||
176 | static int vgacon_scrollback_cur; | ||
177 | static int vgacon_scrollback_save; | ||
178 | static int vgacon_scrollback_restore; | ||
179 | |||
180 | static void vgacon_scrollback_init(int pitch) | ||
181 | { | ||
182 | int rows = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024/pitch; | ||
183 | |||
184 | if (vgacon_scrollback) { | ||
185 | vgacon_scrollback_cnt = 0; | ||
186 | vgacon_scrollback_tail = 0; | ||
187 | vgacon_scrollback_cur = 0; | ||
188 | vgacon_scrollback_rows = rows - 1; | ||
189 | vgacon_scrollback_size = rows * pitch; | ||
190 | } | ||
191 | } | ||
192 | |||
193 | static void __init vgacon_scrollback_startup(void) | ||
194 | { | ||
195 | vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE | ||
196 | * 1024); | ||
197 | vgacon_scrollback_init(vga_video_num_columns * 2); | ||
198 | } | ||
199 | |||
200 | static void vgacon_scrollback_update(struct vc_data *c, int t, int count) | ||
201 | { | ||
202 | void *p; | ||
203 | |||
204 | if (!vgacon_scrollback_size || c->vc_num != fg_console) | ||
205 | return; | ||
206 | |||
207 | p = (void *) (c->vc_origin + t * c->vc_size_row); | ||
208 | |||
209 | while (count--) { | ||
210 | scr_memcpyw(vgacon_scrollback + vgacon_scrollback_tail, | ||
211 | p, c->vc_size_row); | ||
212 | vgacon_scrollback_cnt++; | ||
213 | p += c->vc_size_row; | ||
214 | vgacon_scrollback_tail += c->vc_size_row; | ||
215 | |||
216 | if (vgacon_scrollback_tail >= vgacon_scrollback_size) | ||
217 | vgacon_scrollback_tail = 0; | ||
218 | |||
219 | if (vgacon_scrollback_cnt > vgacon_scrollback_rows) | ||
220 | vgacon_scrollback_cnt = vgacon_scrollback_rows; | ||
221 | |||
222 | vgacon_scrollback_cur = vgacon_scrollback_cnt; | ||
223 | } | ||
224 | } | ||
225 | |||
226 | static void vgacon_restore_screen(struct vc_data *c) | ||
227 | { | ||
228 | vgacon_scrollback_save = 0; | ||
229 | |||
230 | if (!vga_is_gfx && !vgacon_scrollback_restore) { | ||
231 | scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, | ||
232 | c->vc_screenbuf_size > vga_vram_size ? | ||
233 | vga_vram_size : c->vc_screenbuf_size); | ||
234 | vgacon_scrollback_restore = 1; | ||
235 | vgacon_scrollback_cur = vgacon_scrollback_cnt; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | static int vgacon_scrolldelta(struct vc_data *c, int lines) | ||
240 | { | ||
241 | int start, end, count, soff, diff; | ||
242 | void *d, *s; | ||
243 | |||
244 | if (!lines) { | ||
245 | c->vc_visible_origin = c->vc_origin; | ||
246 | vga_set_mem_top(c); | ||
247 | return 1; | ||
248 | } | ||
249 | |||
250 | if (!vgacon_scrollback) | ||
251 | return 1; | ||
252 | |||
253 | if (!vgacon_scrollback_save) { | ||
254 | vgacon_cursor(c, CM_ERASE); | ||
255 | vgacon_save_screen(c); | ||
256 | vgacon_scrollback_save = 1; | ||
257 | } | ||
258 | |||
259 | vgacon_scrollback_restore = 0; | ||
260 | start = vgacon_scrollback_cur + lines; | ||
261 | end = start + abs(lines); | ||
262 | |||
263 | if (start < 0) | ||
264 | start = 0; | ||
265 | |||
266 | if (start > vgacon_scrollback_cnt) | ||
267 | start = vgacon_scrollback_cnt; | ||
268 | |||
269 | if (end < 0) | ||
270 | end = 0; | ||
271 | |||
272 | if (end > vgacon_scrollback_cnt) | ||
273 | end = vgacon_scrollback_cnt; | ||
274 | |||
275 | vgacon_scrollback_cur = start; | ||
276 | count = end - start; | ||
277 | soff = vgacon_scrollback_tail - ((vgacon_scrollback_cnt - end) * | ||
278 | c->vc_size_row); | ||
279 | soff -= count * c->vc_size_row; | ||
280 | |||
281 | if (soff < 0) | ||
282 | soff += vgacon_scrollback_size; | ||
283 | |||
284 | count = vgacon_scrollback_cnt - start; | ||
285 | |||
286 | if (count > c->vc_rows) | ||
287 | count = c->vc_rows; | ||
288 | |||
289 | diff = c->vc_rows - count; | ||
290 | |||
291 | d = (void *) c->vc_origin; | ||
292 | s = (void *) c->vc_screenbuf; | ||
293 | |||
294 | while (count--) { | ||
295 | scr_memcpyw(d, vgacon_scrollback + soff, c->vc_size_row); | ||
296 | d += c->vc_size_row; | ||
297 | soff += c->vc_size_row; | ||
298 | |||
299 | if (soff >= vgacon_scrollback_size) | ||
300 | soff = 0; | ||
301 | } | ||
302 | |||
303 | if (diff == c->vc_rows) { | ||
304 | vgacon_cursor(c, CM_MOVE); | ||
305 | } else { | ||
306 | while (diff--) { | ||
307 | scr_memcpyw(d, s, c->vc_size_row); | ||
308 | d += c->vc_size_row; | ||
309 | s += c->vc_size_row; | ||
310 | } | ||
311 | } | ||
312 | |||
313 | return 1; | ||
314 | } | ||
315 | #else | ||
316 | #define vgacon_scrollback_startup(...) do { } while (0) | ||
317 | #define vgacon_scrollback_init(...) do { } while (0) | ||
318 | #define vgacon_scrollback_update(...) do { } while (0) | ||
319 | |||
320 | static void vgacon_restore_screen(struct vc_data *c) | ||
321 | { | ||
322 | if (c->vc_origin != c->vc_visible_origin) | ||
323 | vgacon_scrolldelta(c, 0); | ||
324 | } | ||
325 | |||
326 | static int vgacon_scrolldelta(struct vc_data *c, int lines) | ||
327 | { | ||
328 | if (!lines) /* Turn scrollback off */ | ||
329 | c->vc_visible_origin = c->vc_origin; | ||
330 | else { | ||
331 | int margin = c->vc_size_row * 4; | ||
332 | int ul, we, p, st; | ||
333 | |||
334 | if (vga_rolled_over > | ||
335 | (c->vc_scr_end - vga_vram_base) + margin) { | ||
336 | ul = c->vc_scr_end - vga_vram_base; | ||
337 | we = vga_rolled_over + c->vc_size_row; | ||
338 | } else { | ||
339 | ul = 0; | ||
340 | we = vga_vram_size; | ||
341 | } | ||
342 | p = (c->vc_visible_origin - vga_vram_base - ul + we) % we + | ||
343 | lines * c->vc_size_row; | ||
344 | st = (c->vc_origin - vga_vram_base - ul + we) % we; | ||
345 | if (st < 2 * margin) | ||
346 | margin = 0; | ||
347 | if (p < margin) | ||
348 | p = 0; | ||
349 | if (p > st - margin) | ||
350 | p = st; | ||
351 | c->vc_visible_origin = vga_vram_base + (p + ul) % we; | ||
352 | } | ||
353 | vga_set_mem_top(c); | ||
354 | return 1; | ||
355 | } | ||
356 | #endif /* CONFIG_VGACON_SOFT_SCROLLBACK */ | ||
357 | |||
164 | static const char __init *vgacon_startup(void) | 358 | static const char __init *vgacon_startup(void) |
165 | { | 359 | { |
166 | const char *display_desc = NULL; | 360 | const char *display_desc = NULL; |
@@ -330,7 +524,7 @@ static const char __init *vgacon_startup(void) | |||
330 | 524 | ||
331 | vgacon_xres = ORIG_VIDEO_COLS * VGA_FONTWIDTH; | 525 | vgacon_xres = ORIG_VIDEO_COLS * VGA_FONTWIDTH; |
332 | vgacon_yres = vga_scan_lines; | 526 | vgacon_yres = vga_scan_lines; |
333 | 527 | vgacon_scrollback_startup(); | |
334 | return display_desc; | 528 | return display_desc; |
335 | } | 529 | } |
336 | 530 | ||
@@ -357,11 +551,6 @@ static void vgacon_init(struct vc_data *c, int init) | |||
357 | con_set_default_unimap(c); | 551 | con_set_default_unimap(c); |
358 | } | 552 | } |
359 | 553 | ||
360 | static inline void vga_set_mem_top(struct vc_data *c) | ||
361 | { | ||
362 | write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2); | ||
363 | } | ||
364 | |||
365 | static void vgacon_deinit(struct vc_data *c) | 554 | static void vgacon_deinit(struct vc_data *c) |
366 | { | 555 | { |
367 | /* When closing the last console, reset video origin */ | 556 | /* When closing the last console, reset video origin */ |
@@ -433,29 +622,37 @@ static void vgacon_set_cursor_size(int xpos, int from, int to) | |||
433 | cursor_size_lastto = to; | 622 | cursor_size_lastto = to; |
434 | 623 | ||
435 | spin_lock_irqsave(&vga_lock, flags); | 624 | spin_lock_irqsave(&vga_lock, flags); |
436 | outb_p(0x0a, vga_video_port_reg); /* Cursor start */ | 625 | if (vga_video_type >= VIDEO_TYPE_VGAC) { |
437 | curs = inb_p(vga_video_port_val); | 626 | outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg); |
438 | outb_p(0x0b, vga_video_port_reg); /* Cursor end */ | 627 | curs = inb_p(vga_video_port_val); |
439 | cure = inb_p(vga_video_port_val); | 628 | outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg); |
629 | cure = inb_p(vga_video_port_val); | ||
630 | } else { | ||
631 | curs = 0; | ||
632 | cure = 0; | ||
633 | } | ||
440 | 634 | ||
441 | curs = (curs & 0xc0) | from; | 635 | curs = (curs & 0xc0) | from; |
442 | cure = (cure & 0xe0) | to; | 636 | cure = (cure & 0xe0) | to; |
443 | 637 | ||
444 | outb_p(0x0a, vga_video_port_reg); /* Cursor start */ | 638 | outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg); |
445 | outb_p(curs, vga_video_port_val); | 639 | outb_p(curs, vga_video_port_val); |
446 | outb_p(0x0b, vga_video_port_reg); /* Cursor end */ | 640 | outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg); |
447 | outb_p(cure, vga_video_port_val); | 641 | outb_p(cure, vga_video_port_val); |
448 | spin_unlock_irqrestore(&vga_lock, flags); | 642 | spin_unlock_irqrestore(&vga_lock, flags); |
449 | } | 643 | } |
450 | 644 | ||
451 | static void vgacon_cursor(struct vc_data *c, int mode) | 645 | static void vgacon_cursor(struct vc_data *c, int mode) |
452 | { | 646 | { |
453 | if (c->vc_origin != c->vc_visible_origin) | 647 | vgacon_restore_screen(c); |
454 | vgacon_scrolldelta(c, 0); | 648 | |
455 | switch (mode) { | 649 | switch (mode) { |
456 | case CM_ERASE: | 650 | case CM_ERASE: |
457 | write_vga(14, (c->vc_pos - vga_vram_base) / 2); | 651 | write_vga(14, (c->vc_pos - vga_vram_base) / 2); |
458 | vgacon_set_cursor_size(c->vc_x, 31, 30); | 652 | if (vga_video_type >= VIDEO_TYPE_VGAC) |
653 | vgacon_set_cursor_size(c->vc_x, 31, 30); | ||
654 | else | ||
655 | vgacon_set_cursor_size(c->vc_x, 31, 31); | ||
459 | break; | 656 | break; |
460 | 657 | ||
461 | case CM_MOVE: | 658 | case CM_MOVE: |
@@ -493,7 +690,10 @@ static void vgacon_cursor(struct vc_data *c, int mode) | |||
493 | 10 ? 1 : 2)); | 690 | 10 ? 1 : 2)); |
494 | break; | 691 | break; |
495 | case CUR_NONE: | 692 | case CUR_NONE: |
496 | vgacon_set_cursor_size(c->vc_x, 31, 30); | 693 | if (vga_video_type >= VIDEO_TYPE_VGAC) |
694 | vgacon_set_cursor_size(c->vc_x, 31, 30); | ||
695 | else | ||
696 | vgacon_set_cursor_size(c->vc_x, 31, 31); | ||
497 | break; | 697 | break; |
498 | default: | 698 | default: |
499 | vgacon_set_cursor_size(c->vc_x, 1, | 699 | vgacon_set_cursor_size(c->vc_x, 1, |
@@ -595,6 +795,7 @@ static int vgacon_switch(struct vc_data *c) | |||
595 | vgacon_doresize(c, c->vc_cols, c->vc_rows); | 795 | vgacon_doresize(c, c->vc_cols, c->vc_rows); |
596 | } | 796 | } |
597 | 797 | ||
798 | vgacon_scrollback_init(c->vc_size_row); | ||
598 | return 0; /* Redrawing not needed */ | 799 | return 0; /* Redrawing not needed */ |
599 | } | 800 | } |
600 | 801 | ||
@@ -1062,37 +1263,6 @@ static int vgacon_resize(struct vc_data *c, unsigned int width, | |||
1062 | return 0; | 1263 | return 0; |
1063 | } | 1264 | } |
1064 | 1265 | ||
1065 | static int vgacon_scrolldelta(struct vc_data *c, int lines) | ||
1066 | { | ||
1067 | if (!lines) /* Turn scrollback off */ | ||
1068 | c->vc_visible_origin = c->vc_origin; | ||
1069 | else { | ||
1070 | int margin = c->vc_size_row * 4; | ||
1071 | int ul, we, p, st; | ||
1072 | |||
1073 | if (vga_rolled_over > | ||
1074 | (c->vc_scr_end - vga_vram_base) + margin) { | ||
1075 | ul = c->vc_scr_end - vga_vram_base; | ||
1076 | we = vga_rolled_over + c->vc_size_row; | ||
1077 | } else { | ||
1078 | ul = 0; | ||
1079 | we = vga_vram_size; | ||
1080 | } | ||
1081 | p = (c->vc_visible_origin - vga_vram_base - ul + we) % we + | ||
1082 | lines * c->vc_size_row; | ||
1083 | st = (c->vc_origin - vga_vram_base - ul + we) % we; | ||
1084 | if (st < 2 * margin) | ||
1085 | margin = 0; | ||
1086 | if (p < margin) | ||
1087 | p = 0; | ||
1088 | if (p > st - margin) | ||
1089 | p = st; | ||
1090 | c->vc_visible_origin = vga_vram_base + (p + ul) % we; | ||
1091 | } | ||
1092 | vga_set_mem_top(c); | ||
1093 | return 1; | ||
1094 | } | ||
1095 | |||
1096 | static int vgacon_set_origin(struct vc_data *c) | 1266 | static int vgacon_set_origin(struct vc_data *c) |
1097 | { | 1267 | { |
1098 | if (vga_is_gfx || /* We don't play origin tricks in graphic modes */ | 1268 | if (vga_is_gfx || /* We don't play origin tricks in graphic modes */ |
@@ -1135,15 +1305,14 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, | |||
1135 | if (t || b != c->vc_rows || vga_is_gfx) | 1305 | if (t || b != c->vc_rows || vga_is_gfx) |
1136 | return 0; | 1306 | return 0; |
1137 | 1307 | ||
1138 | if (c->vc_origin != c->vc_visible_origin) | ||
1139 | vgacon_scrolldelta(c, 0); | ||
1140 | |||
1141 | if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2) | 1308 | if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2) |
1142 | return 0; | 1309 | return 0; |
1143 | 1310 | ||
1311 | vgacon_restore_screen(c); | ||
1144 | oldo = c->vc_origin; | 1312 | oldo = c->vc_origin; |
1145 | delta = lines * c->vc_size_row; | 1313 | delta = lines * c->vc_size_row; |
1146 | if (dir == SM_UP) { | 1314 | if (dir == SM_UP) { |
1315 | vgacon_scrollback_update(c, t, lines); | ||
1147 | if (c->vc_scr_end + delta >= vga_vram_end) { | 1316 | if (c->vc_scr_end + delta >= vga_vram_end) { |
1148 | scr_memcpyw((u16 *) vga_vram_base, | 1317 | scr_memcpyw((u16 *) vga_vram_base, |
1149 | (u16 *) (oldo + delta), | 1318 | (u16 *) (oldo + delta), |
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c index c32a2a50bfa2..1f98392a43b3 100644 --- a/drivers/video/fbcmap.c +++ b/drivers/video/fbcmap.c | |||
@@ -85,7 +85,7 @@ static struct fb_cmap default_16_colors = { | |||
85 | * Allocates memory for a colormap @cmap. @len is the | 85 | * Allocates memory for a colormap @cmap. @len is the |
86 | * number of entries in the palette. | 86 | * number of entries in the palette. |
87 | * | 87 | * |
88 | * Returns -1 errno on error, or zero on success. | 88 | * Returns negative errno on error, or zero on success. |
89 | * | 89 | * |
90 | */ | 90 | */ |
91 | 91 | ||
@@ -116,7 +116,7 @@ int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp) | |||
116 | 116 | ||
117 | fail: | 117 | fail: |
118 | fb_dealloc_cmap(cmap); | 118 | fb_dealloc_cmap(cmap); |
119 | return -1; | 119 | return -ENOMEM; |
120 | } | 120 | } |
121 | 121 | ||
122 | /** | 122 | /** |
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 07d882b14396..b1a8dca76430 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c | |||
@@ -55,7 +55,7 @@ | |||
55 | 55 | ||
56 | #define FBPIXMAPSIZE (1024 * 8) | 56 | #define FBPIXMAPSIZE (1024 * 8) |
57 | 57 | ||
58 | static struct notifier_block *fb_notifier_list; | 58 | static BLOCKING_NOTIFIER_HEAD(fb_notifier_list); |
59 | struct fb_info *registered_fb[FB_MAX]; | 59 | struct fb_info *registered_fb[FB_MAX]; |
60 | int num_registered_fb; | 60 | int num_registered_fb; |
61 | 61 | ||
@@ -784,7 +784,7 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) | |||
784 | 784 | ||
785 | event.info = info; | 785 | event.info = info; |
786 | event.data = &mode1; | 786 | event.data = &mode1; |
787 | ret = notifier_call_chain(&fb_notifier_list, | 787 | ret = blocking_notifier_call_chain(&fb_notifier_list, |
788 | FB_EVENT_MODE_DELETE, &event); | 788 | FB_EVENT_MODE_DELETE, &event); |
789 | } | 789 | } |
790 | 790 | ||
@@ -830,8 +830,8 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) | |||
830 | 830 | ||
831 | info->flags &= ~FBINFO_MISC_USEREVENT; | 831 | info->flags &= ~FBINFO_MISC_USEREVENT; |
832 | event.info = info; | 832 | event.info = info; |
833 | notifier_call_chain(&fb_notifier_list, evnt, | 833 | blocking_notifier_call_chain(&fb_notifier_list, |
834 | &event); | 834 | evnt, &event); |
835 | } | 835 | } |
836 | } | 836 | } |
837 | } | 837 | } |
@@ -854,7 +854,8 @@ fb_blank(struct fb_info *info, int blank) | |||
854 | 854 | ||
855 | event.info = info; | 855 | event.info = info; |
856 | event.data = ␣ | 856 | event.data = ␣ |
857 | notifier_call_chain(&fb_notifier_list, FB_EVENT_BLANK, &event); | 857 | blocking_notifier_call_chain(&fb_notifier_list, |
858 | FB_EVENT_BLANK, &event); | ||
858 | } | 859 | } |
859 | 860 | ||
860 | return ret; | 861 | return ret; |
@@ -925,7 +926,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
925 | con2fb.framebuffer = -1; | 926 | con2fb.framebuffer = -1; |
926 | event.info = info; | 927 | event.info = info; |
927 | event.data = &con2fb; | 928 | event.data = &con2fb; |
928 | notifier_call_chain(&fb_notifier_list, | 929 | blocking_notifier_call_chain(&fb_notifier_list, |
929 | FB_EVENT_GET_CONSOLE_MAP, &event); | 930 | FB_EVENT_GET_CONSOLE_MAP, &event); |
930 | return copy_to_user(argp, &con2fb, | 931 | return copy_to_user(argp, &con2fb, |
931 | sizeof(con2fb)) ? -EFAULT : 0; | 932 | sizeof(con2fb)) ? -EFAULT : 0; |
@@ -944,7 +945,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
944 | return -EINVAL; | 945 | return -EINVAL; |
945 | event.info = info; | 946 | event.info = info; |
946 | event.data = &con2fb; | 947 | event.data = &con2fb; |
947 | return notifier_call_chain(&fb_notifier_list, | 948 | return blocking_notifier_call_chain(&fb_notifier_list, |
948 | FB_EVENT_SET_CONSOLE_MAP, | 949 | FB_EVENT_SET_CONSOLE_MAP, |
949 | &event); | 950 | &event); |
950 | case FBIOBLANK: | 951 | case FBIOBLANK: |
@@ -1324,7 +1325,7 @@ register_framebuffer(struct fb_info *fb_info) | |||
1324 | devfs_mk_cdev(MKDEV(FB_MAJOR, i), | 1325 | devfs_mk_cdev(MKDEV(FB_MAJOR, i), |
1325 | S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i); | 1326 | S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i); |
1326 | event.info = fb_info; | 1327 | event.info = fb_info; |
1327 | notifier_call_chain(&fb_notifier_list, | 1328 | blocking_notifier_call_chain(&fb_notifier_list, |
1328 | FB_EVENT_FB_REGISTERED, &event); | 1329 | FB_EVENT_FB_REGISTERED, &event); |
1329 | return 0; | 1330 | return 0; |
1330 | } | 1331 | } |
@@ -1366,7 +1367,7 @@ unregister_framebuffer(struct fb_info *fb_info) | |||
1366 | */ | 1367 | */ |
1367 | int fb_register_client(struct notifier_block *nb) | 1368 | int fb_register_client(struct notifier_block *nb) |
1368 | { | 1369 | { |
1369 | return notifier_chain_register(&fb_notifier_list, nb); | 1370 | return blocking_notifier_chain_register(&fb_notifier_list, nb); |
1370 | } | 1371 | } |
1371 | 1372 | ||
1372 | /** | 1373 | /** |
@@ -1375,7 +1376,7 @@ int fb_register_client(struct notifier_block *nb) | |||
1375 | */ | 1376 | */ |
1376 | int fb_unregister_client(struct notifier_block *nb) | 1377 | int fb_unregister_client(struct notifier_block *nb) |
1377 | { | 1378 | { |
1378 | return notifier_chain_unregister(&fb_notifier_list, nb); | 1379 | return blocking_notifier_chain_unregister(&fb_notifier_list, nb); |
1379 | } | 1380 | } |
1380 | 1381 | ||
1381 | /** | 1382 | /** |
@@ -1393,11 +1394,13 @@ void fb_set_suspend(struct fb_info *info, int state) | |||
1393 | 1394 | ||
1394 | event.info = info; | 1395 | event.info = info; |
1395 | if (state) { | 1396 | if (state) { |
1396 | notifier_call_chain(&fb_notifier_list, FB_EVENT_SUSPEND, &event); | 1397 | blocking_notifier_call_chain(&fb_notifier_list, |
1398 | FB_EVENT_SUSPEND, &event); | ||
1397 | info->state = FBINFO_STATE_SUSPENDED; | 1399 | info->state = FBINFO_STATE_SUSPENDED; |
1398 | } else { | 1400 | } else { |
1399 | info->state = FBINFO_STATE_RUNNING; | 1401 | info->state = FBINFO_STATE_RUNNING; |
1400 | notifier_call_chain(&fb_notifier_list, FB_EVENT_RESUME, &event); | 1402 | blocking_notifier_call_chain(&fb_notifier_list, |
1403 | FB_EVENT_RESUME, &event); | ||
1401 | } | 1404 | } |
1402 | } | 1405 | } |
1403 | 1406 | ||
@@ -1469,7 +1472,7 @@ int fb_new_modelist(struct fb_info *info) | |||
1469 | 1472 | ||
1470 | if (!list_empty(&info->modelist)) { | 1473 | if (!list_empty(&info->modelist)) { |
1471 | event.info = info; | 1474 | event.info = info; |
1472 | err = notifier_call_chain(&fb_notifier_list, | 1475 | err = blocking_notifier_call_chain(&fb_notifier_list, |
1473 | FB_EVENT_NEW_MODELIST, | 1476 | FB_EVENT_NEW_MODELIST, |
1474 | &event); | 1477 | &event); |
1475 | } | 1478 | } |
@@ -1495,7 +1498,7 @@ int fb_con_duit(struct fb_info *info, int event, void *data) | |||
1495 | evnt.info = info; | 1498 | evnt.info = info; |
1496 | evnt.data = data; | 1499 | evnt.data = data; |
1497 | 1500 | ||
1498 | return notifier_call_chain(&fb_notifier_list, event, &evnt); | 1501 | return blocking_notifier_call_chain(&fb_notifier_list, event, &evnt); |
1499 | } | 1502 | } |
1500 | EXPORT_SYMBOL(fb_con_duit); | 1503 | EXPORT_SYMBOL(fb_con_duit); |
1501 | 1504 | ||
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 7c74e7325d95..53beeb4a9998 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c | |||
@@ -1281,7 +1281,7 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info) | |||
1281 | -EINVAL : 0; | 1281 | -EINVAL : 0; |
1282 | } | 1282 | } |
1283 | 1283 | ||
1284 | #if defined(__i386__) | 1284 | #if defined(CONFIG_FB_FIRMWARE_EDID) && defined(__i386__) |
1285 | #include <linux/pci.h> | 1285 | #include <linux/pci.h> |
1286 | 1286 | ||
1287 | /* | 1287 | /* |
@@ -1311,11 +1311,11 @@ const unsigned char *fb_firmware_edid(struct device *device) | |||
1311 | { | 1311 | { |
1312 | return NULL; | 1312 | return NULL; |
1313 | } | 1313 | } |
1314 | #endif /* _i386_ */ | 1314 | #endif |
1315 | EXPORT_SYMBOL(fb_firmware_edid); | ||
1315 | 1316 | ||
1316 | EXPORT_SYMBOL(fb_parse_edid); | 1317 | EXPORT_SYMBOL(fb_parse_edid); |
1317 | EXPORT_SYMBOL(fb_edid_to_monspecs); | 1318 | EXPORT_SYMBOL(fb_edid_to_monspecs); |
1318 | EXPORT_SYMBOL(fb_firmware_edid); | ||
1319 | EXPORT_SYMBOL(fb_get_mode); | 1319 | EXPORT_SYMBOL(fb_get_mode); |
1320 | EXPORT_SYMBOL(fb_validate_mode); | 1320 | EXPORT_SYMBOL(fb_validate_mode); |
1321 | EXPORT_SYMBOL(fb_destroy_modedb); | 1321 | EXPORT_SYMBOL(fb_destroy_modedb); |
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index 6d26057337e2..b72b05250a9d 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c | |||
@@ -348,7 +348,7 @@ static ssize_t store_cmap(struct class_device *class_device, const char *buf, | |||
348 | fb_copy_cmap(&umap, &fb_info->cmap); | 348 | fb_copy_cmap(&umap, &fb_info->cmap); |
349 | fb_dealloc_cmap(&umap); | 349 | fb_dealloc_cmap(&umap); |
350 | 350 | ||
351 | return rc; | 351 | return rc ?: count; |
352 | } | 352 | } |
353 | for (i = 0; i < length; i++) { | 353 | for (i = 0; i < length; i++) { |
354 | u16 red, blue, green, tsp; | 354 | u16 red, blue, green, tsp; |
@@ -367,7 +367,7 @@ static ssize_t store_cmap(struct class_device *class_device, const char *buf, | |||
367 | if (transp) | 367 | if (transp) |
368 | fb_info->cmap.transp[i] = tsp; | 368 | fb_info->cmap.transp[i] = tsp; |
369 | } | 369 | } |
370 | return 0; | 370 | return count; |
371 | } | 371 | } |
372 | 372 | ||
373 | static ssize_t show_cmap(struct class_device *class_device, char *buf) | 373 | static ssize_t show_cmap(struct class_device *class_device, char *buf) |
diff --git a/drivers/video/geode/Kconfig b/drivers/video/geode/Kconfig index 42fb9a89a792..4e173ef20a7d 100644 --- a/drivers/video/geode/Kconfig +++ b/drivers/video/geode/Kconfig | |||
@@ -8,9 +8,24 @@ config FB_GEODE | |||
8 | Say 'Y' here to allow you to select framebuffer drivers for | 8 | Say 'Y' here to allow you to select framebuffer drivers for |
9 | the AMD Geode family of processors. | 9 | the AMD Geode family of processors. |
10 | 10 | ||
11 | config FB_GEODE_GX | ||
12 | tristate "AMD Geode GX framebuffer support (EXPERIMENTAL)" | ||
13 | depends on FB && FB_GEODE && EXPERIMENTAL | ||
14 | select FB_CFB_FILLRECT | ||
15 | select FB_CFB_COPYAREA | ||
16 | select FB_CFB_IMAGEBLIT | ||
17 | ---help--- | ||
18 | Framebuffer driver for the display controller integrated into the | ||
19 | AMD Geode GX processors. | ||
20 | |||
21 | To compile this driver as a module, choose M here: the module will be | ||
22 | called gxfb. | ||
23 | |||
24 | If unsure, say N. | ||
25 | |||
11 | config FB_GEODE_GX1 | 26 | config FB_GEODE_GX1 |
12 | tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)" | 27 | tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)" |
13 | depends on FB_GEODE && EXPERIMENTAL | 28 | depends on FB && FB_GEODE && EXPERIMENTAL |
14 | select FB_CFB_FILLRECT | 29 | select FB_CFB_FILLRECT |
15 | select FB_CFB_COPYAREA | 30 | select FB_CFB_COPYAREA |
16 | select FB_CFB_IMAGEBLIT | 31 | select FB_CFB_IMAGEBLIT |
diff --git a/drivers/video/geode/Makefile b/drivers/video/geode/Makefile index 13ad501ea990..f896565bc312 100644 --- a/drivers/video/geode/Makefile +++ b/drivers/video/geode/Makefile | |||
@@ -1,5 +1,7 @@ | |||
1 | # Makefile for the Geode family framebuffer drivers | 1 | # Makefile for the Geode family framebuffer drivers |
2 | 2 | ||
3 | obj-$(CONFIG_FB_GEODE_GX1) += gx1fb.o | 3 | obj-$(CONFIG_FB_GEODE_GX1) += gx1fb.o |
4 | obj-$(CONFIG_FB_GEODE_GX) += gxfb.o | ||
4 | 5 | ||
5 | gx1fb-objs := gx1fb_core.o display_gx1.o video_cs5530.o | 6 | gx1fb-objs := gx1fb_core.o display_gx1.o video_cs5530.o |
7 | gxfb-objs := gxfb_core.o display_gx.o video_gx.o | ||
diff --git a/drivers/video/geode/display_gx.c b/drivers/video/geode/display_gx.c new file mode 100644 index 000000000000..825c3405f5c2 --- /dev/null +++ b/drivers/video/geode/display_gx.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * Geode GX display controller. | ||
3 | * | ||
4 | * Copyright (C) 2005 Arcom Control Systems Ltd. | ||
5 | * | ||
6 | * Portions from AMD's original 2.4 driver: | ||
7 | * Copyright (C) 2004 Advanced Micro Devices, Inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by * the | ||
11 | * Free Software Foundation; either version 2 of the License, or * (at your | ||
12 | * option) any later version. | ||
13 | */ | ||
14 | #include <linux/spinlock.h> | ||
15 | #include <linux/fb.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <asm/io.h> | ||
18 | #include <asm/div64.h> | ||
19 | #include <asm/delay.h> | ||
20 | |||
21 | #include "geodefb.h" | ||
22 | #include "display_gx.h" | ||
23 | |||
24 | int gx_frame_buffer_size(void) | ||
25 | { | ||
26 | /* Assuming 16 MiB. */ | ||
27 | return 16*1024*1024; | ||
28 | } | ||
29 | |||
30 | int gx_line_delta(int xres, int bpp) | ||
31 | { | ||
32 | /* Must be a multiple of 8 bytes. */ | ||
33 | return (xres * (bpp >> 3) + 7) & ~0x7; | ||
34 | } | ||
35 | |||
36 | static void gx_set_mode(struct fb_info *info) | ||
37 | { | ||
38 | struct geodefb_par *par = info->par; | ||
39 | u32 gcfg, dcfg; | ||
40 | int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal; | ||
41 | int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal; | ||
42 | |||
43 | /* Unlock the display controller registers. */ | ||
44 | readl(par->dc_regs + DC_UNLOCK); | ||
45 | writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); | ||
46 | |||
47 | gcfg = readl(par->dc_regs + DC_GENERAL_CFG); | ||
48 | dcfg = readl(par->dc_regs + DC_DISPLAY_CFG); | ||
49 | |||
50 | /* Disable the timing generator. */ | ||
51 | dcfg &= ~(DC_DCFG_TGEN); | ||
52 | writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); | ||
53 | |||
54 | /* Wait for pending memory requests before disabling the FIFO load. */ | ||
55 | udelay(100); | ||
56 | |||
57 | /* Disable FIFO load and compression. */ | ||
58 | gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE); | ||
59 | writel(gcfg, par->dc_regs + DC_GENERAL_CFG); | ||
60 | |||
61 | /* Setup DCLK and its divisor. */ | ||
62 | par->vid_ops->set_dclk(info); | ||
63 | |||
64 | /* | ||
65 | * Setup new mode. | ||
66 | */ | ||
67 | |||
68 | /* Clear all unused feature bits. */ | ||
69 | gcfg &= DC_GCFG_YUVM | DC_GCFG_VDSE; | ||
70 | dcfg = 0; | ||
71 | |||
72 | /* Set FIFO priority (default 6/5) and enable. */ | ||
73 | /* FIXME: increase fifo priority for 1280x1024 and higher modes? */ | ||
74 | gcfg |= (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE; | ||
75 | |||
76 | /* Framebuffer start offset. */ | ||
77 | writel(0, par->dc_regs + DC_FB_ST_OFFSET); | ||
78 | |||
79 | /* Line delta and line buffer length. */ | ||
80 | writel(info->fix.line_length >> 3, par->dc_regs + DC_GFX_PITCH); | ||
81 | writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2, | ||
82 | par->dc_regs + DC_LINE_SIZE); | ||
83 | |||
84 | /* Enable graphics and video data and unmask address lines. */ | ||
85 | dcfg |= DC_DCFG_GDEN | DC_DCFG_VDEN | DC_DCFG_A20M | DC_DCFG_A18M; | ||
86 | |||
87 | /* Set pixel format. */ | ||
88 | switch (info->var.bits_per_pixel) { | ||
89 | case 8: | ||
90 | dcfg |= DC_DCFG_DISP_MODE_8BPP; | ||
91 | break; | ||
92 | case 16: | ||
93 | dcfg |= DC_DCFG_DISP_MODE_16BPP; | ||
94 | dcfg |= DC_DCFG_16BPP_MODE_565; | ||
95 | break; | ||
96 | case 32: | ||
97 | dcfg |= DC_DCFG_DISP_MODE_24BPP; | ||
98 | dcfg |= DC_DCFG_PALB; | ||
99 | break; | ||
100 | } | ||
101 | |||
102 | /* Enable timing generator. */ | ||
103 | dcfg |= DC_DCFG_TGEN; | ||
104 | |||
105 | /* Horizontal and vertical timings. */ | ||
106 | hactive = info->var.xres; | ||
107 | hblankstart = hactive; | ||
108 | hsyncstart = hblankstart + info->var.right_margin; | ||
109 | hsyncend = hsyncstart + info->var.hsync_len; | ||
110 | hblankend = hsyncend + info->var.left_margin; | ||
111 | htotal = hblankend; | ||
112 | |||
113 | vactive = info->var.yres; | ||
114 | vblankstart = vactive; | ||
115 | vsyncstart = vblankstart + info->var.lower_margin; | ||
116 | vsyncend = vsyncstart + info->var.vsync_len; | ||
117 | vblankend = vsyncend + info->var.upper_margin; | ||
118 | vtotal = vblankend; | ||
119 | |||
120 | writel((hactive - 1) | ((htotal - 1) << 16), par->dc_regs + DC_H_ACTIVE_TIMING); | ||
121 | writel((hblankstart - 1) | ((hblankend - 1) << 16), par->dc_regs + DC_H_BLANK_TIMING); | ||
122 | writel((hsyncstart - 1) | ((hsyncend - 1) << 16), par->dc_regs + DC_H_SYNC_TIMING); | ||
123 | |||
124 | writel((vactive - 1) | ((vtotal - 1) << 16), par->dc_regs + DC_V_ACTIVE_TIMING); | ||
125 | writel((vblankstart - 1) | ((vblankend - 1) << 16), par->dc_regs + DC_V_BLANK_TIMING); | ||
126 | writel((vsyncstart - 1) | ((vsyncend - 1) << 16), par->dc_regs + DC_V_SYNC_TIMING); | ||
127 | |||
128 | /* Write final register values. */ | ||
129 | writel(dcfg, par->dc_regs + DC_DISPLAY_CFG); | ||
130 | writel(gcfg, par->dc_regs + DC_GENERAL_CFG); | ||
131 | |||
132 | par->vid_ops->configure_display(info); | ||
133 | |||
134 | /* Relock display controller registers */ | ||
135 | writel(0, par->dc_regs + DC_UNLOCK); | ||
136 | } | ||
137 | |||
138 | static void gx_set_hw_palette_reg(struct fb_info *info, unsigned regno, | ||
139 | unsigned red, unsigned green, unsigned blue) | ||
140 | { | ||
141 | struct geodefb_par *par = info->par; | ||
142 | int val; | ||
143 | |||
144 | /* Hardware palette is in RGB 8-8-8 format. */ | ||
145 | val = (red << 8) & 0xff0000; | ||
146 | val |= (green) & 0x00ff00; | ||
147 | val |= (blue >> 8) & 0x0000ff; | ||
148 | |||
149 | writel(regno, par->dc_regs + DC_PAL_ADDRESS); | ||
150 | writel(val, par->dc_regs + DC_PAL_DATA); | ||
151 | } | ||
152 | |||
153 | struct geode_dc_ops gx_dc_ops = { | ||
154 | .set_mode = gx_set_mode, | ||
155 | .set_palette_reg = gx_set_hw_palette_reg, | ||
156 | }; | ||
diff --git a/drivers/video/geode/display_gx.h b/drivers/video/geode/display_gx.h new file mode 100644 index 000000000000..86c623361305 --- /dev/null +++ b/drivers/video/geode/display_gx.h | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * Geode GX display controller | ||
3 | * | ||
4 | * Copyright (C) 2006 Arcom Control Systems Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | #ifndef __DISPLAY_GX_H__ | ||
12 | #define __DISPLAY_GX_H__ | ||
13 | |||
14 | int gx_frame_buffer_size(void); | ||
15 | int gx_line_delta(int xres, int bpp); | ||
16 | |||
17 | extern struct geode_dc_ops gx_dc_ops; | ||
18 | |||
19 | /* Display controller registers */ | ||
20 | |||
21 | #define DC_UNLOCK 0x00 | ||
22 | # define DC_UNLOCK_CODE 0x00004758 | ||
23 | |||
24 | #define DC_GENERAL_CFG 0x04 | ||
25 | # define DC_GCFG_DFLE 0x00000001 | ||
26 | # define DC_GCFG_CURE 0x00000002 | ||
27 | # define DC_GCFG_ICNE 0x00000004 | ||
28 | # define DC_GCFG_VIDE 0x00000008 | ||
29 | # define DC_GCFG_CMPE 0x00000020 | ||
30 | # define DC_GCFG_DECE 0x00000040 | ||
31 | # define DC_GCFG_VGAE 0x00000080 | ||
32 | # define DC_GCFG_DFHPSL_MASK 0x00000F00 | ||
33 | # define DC_GCFG_DFHPSL_POS 8 | ||
34 | # define DC_GCFG_DFHPEL_MASK 0x0000F000 | ||
35 | # define DC_GCFG_DFHPEL_POS 12 | ||
36 | # define DC_GCFG_STFM 0x00010000 | ||
37 | # define DC_GCFG_FDTY 0x00020000 | ||
38 | # define DC_GCFG_VGAFT 0x00040000 | ||
39 | # define DC_GCFG_VDSE 0x00080000 | ||
40 | # define DC_GCFG_YUVM 0x00100000 | ||
41 | # define DC_GCFG_VFSL 0x00800000 | ||
42 | # define DC_GCFG_SIGE 0x01000000 | ||
43 | # define DC_GCFG_SGRE 0x02000000 | ||
44 | # define DC_GCFG_SGFR 0x04000000 | ||
45 | # define DC_GCFG_CRC_MODE 0x08000000 | ||
46 | # define DC_GCFG_DIAG 0x10000000 | ||
47 | # define DC_GCFG_CFRW 0x20000000 | ||
48 | |||
49 | #define DC_DISPLAY_CFG 0x08 | ||
50 | # define DC_DCFG_TGEN 0x00000001 | ||
51 | # define DC_DCFG_GDEN 0x00000008 | ||
52 | # define DC_DCFG_VDEN 0x00000010 | ||
53 | # define DC_DCFG_TRUP 0x00000040 | ||
54 | # define DC_DCFG_DISP_MODE_MASK 0x00000300 | ||
55 | # define DC_DCFG_DISP_MODE_8BPP 0x00000000 | ||
56 | # define DC_DCFG_DISP_MODE_16BPP 0x00000100 | ||
57 | # define DC_DCFG_DISP_MODE_24BPP 0x00000200 | ||
58 | # define DC_DCFG_16BPP_MODE_MASK 0x00000c00 | ||
59 | # define DC_DCFG_16BPP_MODE_565 0x00000000 | ||
60 | # define DC_DCFG_16BPP_MODE_555 0x00000100 | ||
61 | # define DC_DCFG_16BPP_MODE_444 0x00000200 | ||
62 | # define DC_DCFG_DCEN 0x00080000 | ||
63 | # define DC_DCFG_PALB 0x02000000 | ||
64 | # define DC_DCFG_FRLK 0x04000000 | ||
65 | # define DC_DCFG_VISL 0x08000000 | ||
66 | # define DC_DCFG_FRSL 0x20000000 | ||
67 | # define DC_DCFG_A18M 0x40000000 | ||
68 | # define DC_DCFG_A20M 0x80000000 | ||
69 | |||
70 | #define DC_FB_ST_OFFSET 0x10 | ||
71 | |||
72 | #define DC_LINE_SIZE 0x30 | ||
73 | # define DC_LINE_SIZE_FB_LINE_SIZE_MASK 0x000007ff | ||
74 | # define DC_LINE_SIZE_FB_LINE_SIZE_POS 0 | ||
75 | # define DC_LINE_SIZE_CB_LINE_SIZE_MASK 0x007f0000 | ||
76 | # define DC_LINE_SIZE_CB_LINE_SIZE_POS 16 | ||
77 | # define DC_LINE_SIZE_VID_LINE_SIZE_MASK 0xff000000 | ||
78 | # define DC_LINE_SIZE_VID_LINE_SIZE_POS 24 | ||
79 | |||
80 | #define DC_GFX_PITCH 0x34 | ||
81 | # define DC_GFX_PITCH_FB_PITCH_MASK 0x0000ffff | ||
82 | # define DC_GFX_PITCH_FB_PITCH_POS 0 | ||
83 | # define DC_GFX_PITCH_CB_PITCH_MASK 0xffff0000 | ||
84 | # define DC_GFX_PITCH_CB_PITCH_POS 16 | ||
85 | |||
86 | #define DC_H_ACTIVE_TIMING 0x40 | ||
87 | #define DC_H_BLANK_TIMING 0x44 | ||
88 | #define DC_H_SYNC_TIMING 0x48 | ||
89 | #define DC_V_ACTIVE_TIMING 0x50 | ||
90 | #define DC_V_BLANK_TIMING 0x54 | ||
91 | #define DC_V_SYNC_TIMING 0x58 | ||
92 | |||
93 | #define DC_PAL_ADDRESS 0x70 | ||
94 | #define DC_PAL_DATA 0x74 | ||
95 | |||
96 | #endif /* !__DISPLAY_GX1_H__ */ | ||
diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c new file mode 100644 index 000000000000..89c34b15f5d4 --- /dev/null +++ b/drivers/video/geode/gxfb_core.c | |||
@@ -0,0 +1,423 @@ | |||
1 | /* | ||
2 | * Geode GX framebuffer driver. | ||
3 | * | ||
4 | * Copyright (C) 2006 Arcom Control Systems Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | * | ||
11 | * | ||
12 | * This driver assumes that the BIOS has created a virtual PCI device header | ||
13 | * for the video device. The PCI header is assumed to contain the following | ||
14 | * BARs: | ||
15 | * | ||
16 | * BAR0 - framebuffer memory | ||
17 | * BAR1 - graphics processor registers | ||
18 | * BAR2 - display controller registers | ||
19 | * BAR3 - video processor and flat panel control registers. | ||
20 | * | ||
21 | * 16 MiB of framebuffer memory is assumed to be available. | ||
22 | */ | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/errno.h> | ||
26 | #include <linux/string.h> | ||
27 | #include <linux/mm.h> | ||
28 | #include <linux/tty.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/fb.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/pci.h> | ||
34 | |||
35 | #include "geodefb.h" | ||
36 | #include "display_gx.h" | ||
37 | #include "video_gx.h" | ||
38 | |||
39 | static char mode_option[32] = "640x480-16@60"; | ||
40 | |||
41 | /* Modes relevant to the GX (taken from modedb.c) */ | ||
42 | static const struct fb_videomode __initdata gx_modedb[] = { | ||
43 | /* 640x480-60 VESA */ | ||
44 | { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, | ||
45 | 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
46 | /* 640x480-75 VESA */ | ||
47 | { NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3, | ||
48 | 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
49 | /* 640x480-85 VESA */ | ||
50 | { NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3, | ||
51 | 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
52 | /* 800x600-60 VESA */ | ||
53 | { NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4, | ||
54 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
55 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
56 | /* 800x600-75 VESA */ | ||
57 | { NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3, | ||
58 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
59 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
60 | /* 800x600-85 VESA */ | ||
61 | { NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3, | ||
62 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
63 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
64 | /* 1024x768-60 VESA */ | ||
65 | { NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6, | ||
66 | 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
67 | /* 1024x768-75 VESA */ | ||
68 | { NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3, | ||
69 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
70 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
71 | /* 1024x768-85 VESA */ | ||
72 | { NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3, | ||
73 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
74 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
75 | /* 1280x960-60 VESA */ | ||
76 | { NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3, | ||
77 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
78 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
79 | /* 1280x960-85 VESA */ | ||
80 | { NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3, | ||
81 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
82 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
83 | /* 1280x1024-60 VESA */ | ||
84 | { NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3, | ||
85 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
86 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
87 | /* 1280x1024-75 VESA */ | ||
88 | { NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3, | ||
89 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
90 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
91 | /* 1280x1024-85 VESA */ | ||
92 | { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3, | ||
93 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
94 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
95 | /* 1600x1200-60 VESA */ | ||
96 | { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, | ||
97 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
98 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
99 | /* 1600x1200-75 VESA */ | ||
100 | { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, | ||
101 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
102 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
103 | /* 1600x1200-85 VESA */ | ||
104 | { NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3, | ||
105 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
106 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
107 | }; | ||
108 | |||
109 | static int gxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | ||
110 | { | ||
111 | if (var->xres > 1600 || var->yres > 1200) | ||
112 | return -EINVAL; | ||
113 | if ((var->xres > 1280 || var->yres > 1024) && var->bits_per_pixel > 16) | ||
114 | return -EINVAL; | ||
115 | |||
116 | if (var->bits_per_pixel == 32) { | ||
117 | var->red.offset = 16; var->red.length = 8; | ||
118 | var->green.offset = 8; var->green.length = 8; | ||
119 | var->blue.offset = 0; var->blue.length = 8; | ||
120 | } else if (var->bits_per_pixel == 16) { | ||
121 | var->red.offset = 11; var->red.length = 5; | ||
122 | var->green.offset = 5; var->green.length = 6; | ||
123 | var->blue.offset = 0; var->blue.length = 5; | ||
124 | } else if (var->bits_per_pixel == 8) { | ||
125 | var->red.offset = 0; var->red.length = 8; | ||
126 | var->green.offset = 0; var->green.length = 8; | ||
127 | var->blue.offset = 0; var->blue.length = 8; | ||
128 | } else | ||
129 | return -EINVAL; | ||
130 | var->transp.offset = 0; var->transp.length = 0; | ||
131 | |||
132 | /* Enough video memory? */ | ||
133 | if (gx_line_delta(var->xres, var->bits_per_pixel) * var->yres > info->fix.smem_len) | ||
134 | return -EINVAL; | ||
135 | |||
136 | /* FIXME: Check timing parameters here? */ | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static int gxfb_set_par(struct fb_info *info) | ||
142 | { | ||
143 | struct geodefb_par *par = info->par; | ||
144 | |||
145 | if (info->var.bits_per_pixel > 8) { | ||
146 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
147 | fb_dealloc_cmap(&info->cmap); | ||
148 | } else { | ||
149 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | ||
150 | fb_alloc_cmap(&info->cmap, 1<<info->var.bits_per_pixel, 0); | ||
151 | } | ||
152 | |||
153 | info->fix.line_length = gx_line_delta(info->var.xres, info->var.bits_per_pixel); | ||
154 | |||
155 | par->dc_ops->set_mode(info); | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) | ||
161 | { | ||
162 | chan &= 0xffff; | ||
163 | chan >>= 16 - bf->length; | ||
164 | return chan << bf->offset; | ||
165 | } | ||
166 | |||
167 | static int gxfb_setcolreg(unsigned regno, unsigned red, unsigned green, | ||
168 | unsigned blue, unsigned transp, | ||
169 | struct fb_info *info) | ||
170 | { | ||
171 | struct geodefb_par *par = info->par; | ||
172 | |||
173 | if (info->var.grayscale) { | ||
174 | /* grayscale = 0.30*R + 0.59*G + 0.11*B */ | ||
175 | red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; | ||
176 | } | ||
177 | |||
178 | /* Truecolor has hardware independent palette */ | ||
179 | if (info->fix.visual == FB_VISUAL_TRUECOLOR) { | ||
180 | u32 *pal = info->pseudo_palette; | ||
181 | u32 v; | ||
182 | |||
183 | if (regno >= 16) | ||
184 | return -EINVAL; | ||
185 | |||
186 | v = chan_to_field(red, &info->var.red); | ||
187 | v |= chan_to_field(green, &info->var.green); | ||
188 | v |= chan_to_field(blue, &info->var.blue); | ||
189 | |||
190 | pal[regno] = v; | ||
191 | } else { | ||
192 | if (regno >= 256) | ||
193 | return -EINVAL; | ||
194 | |||
195 | par->dc_ops->set_palette_reg(info, regno, red, green, blue); | ||
196 | } | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static int gxfb_blank(int blank_mode, struct fb_info *info) | ||
202 | { | ||
203 | struct geodefb_par *par = info->par; | ||
204 | |||
205 | return par->vid_ops->blank_display(info, blank_mode); | ||
206 | } | ||
207 | |||
208 | static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *dev) | ||
209 | { | ||
210 | struct geodefb_par *par = info->par; | ||
211 | int fb_len; | ||
212 | int ret; | ||
213 | |||
214 | ret = pci_enable_device(dev); | ||
215 | if (ret < 0) | ||
216 | return ret; | ||
217 | |||
218 | ret = pci_request_region(dev, 3, "gxfb (video processor)"); | ||
219 | if (ret < 0) | ||
220 | return ret; | ||
221 | par->vid_regs = ioremap(pci_resource_start(dev, 3), | ||
222 | pci_resource_len(dev, 3)); | ||
223 | if (!par->vid_regs) | ||
224 | return -ENOMEM; | ||
225 | |||
226 | ret = pci_request_region(dev, 2, "gxfb (display controller)"); | ||
227 | if (ret < 0) | ||
228 | return ret; | ||
229 | par->dc_regs = ioremap(pci_resource_start(dev, 2), pci_resource_len(dev, 2)); | ||
230 | if (!par->dc_regs) | ||
231 | return -ENOMEM; | ||
232 | |||
233 | ret = pci_request_region(dev, 0, "gxfb (framebuffer)"); | ||
234 | if (ret < 0) | ||
235 | return ret; | ||
236 | if ((fb_len = gx_frame_buffer_size()) < 0) | ||
237 | return -ENOMEM; | ||
238 | info->fix.smem_start = pci_resource_start(dev, 0); | ||
239 | info->fix.smem_len = fb_len; | ||
240 | info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); | ||
241 | if (!info->screen_base) | ||
242 | return -ENOMEM; | ||
243 | |||
244 | dev_info(&dev->dev, "%d Kibyte of video memory at 0x%lx\n", | ||
245 | info->fix.smem_len / 1024, info->fix.smem_start); | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | static struct fb_ops gxfb_ops = { | ||
251 | .owner = THIS_MODULE, | ||
252 | .fb_check_var = gxfb_check_var, | ||
253 | .fb_set_par = gxfb_set_par, | ||
254 | .fb_setcolreg = gxfb_setcolreg, | ||
255 | .fb_blank = gxfb_blank, | ||
256 | /* No HW acceleration for now. */ | ||
257 | .fb_fillrect = cfb_fillrect, | ||
258 | .fb_copyarea = cfb_copyarea, | ||
259 | .fb_imageblit = cfb_imageblit, | ||
260 | }; | ||
261 | |||
262 | static struct fb_info * __init gxfb_init_fbinfo(struct device *dev) | ||
263 | { | ||
264 | struct geodefb_par *par; | ||
265 | struct fb_info *info; | ||
266 | |||
267 | /* Alloc enough space for the pseudo palette. */ | ||
268 | info = framebuffer_alloc(sizeof(struct geodefb_par) + sizeof(u32) * 16, dev); | ||
269 | if (!info) | ||
270 | return NULL; | ||
271 | |||
272 | par = info->par; | ||
273 | |||
274 | strcpy(info->fix.id, "Geode GX"); | ||
275 | |||
276 | info->fix.type = FB_TYPE_PACKED_PIXELS; | ||
277 | info->fix.type_aux = 0; | ||
278 | info->fix.xpanstep = 0; | ||
279 | info->fix.ypanstep = 0; | ||
280 | info->fix.ywrapstep = 0; | ||
281 | info->fix.accel = FB_ACCEL_NONE; | ||
282 | |||
283 | info->var.nonstd = 0; | ||
284 | info->var.activate = FB_ACTIVATE_NOW; | ||
285 | info->var.height = -1; | ||
286 | info->var.width = -1; | ||
287 | info->var.accel_flags = 0; | ||
288 | info->var.vmode = FB_VMODE_NONINTERLACED; | ||
289 | |||
290 | info->fbops = &gxfb_ops; | ||
291 | info->flags = FBINFO_DEFAULT; | ||
292 | info->node = -1; | ||
293 | |||
294 | info->pseudo_palette = (void *)par + sizeof(struct geodefb_par); | ||
295 | |||
296 | info->var.grayscale = 0; | ||
297 | |||
298 | return info; | ||
299 | } | ||
300 | |||
301 | static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||
302 | { | ||
303 | struct geodefb_par *par; | ||
304 | struct fb_info *info; | ||
305 | int ret; | ||
306 | |||
307 | info = gxfb_init_fbinfo(&pdev->dev); | ||
308 | if (!info) | ||
309 | return -ENOMEM; | ||
310 | par = info->par; | ||
311 | |||
312 | /* GX display controller and GX video device. */ | ||
313 | par->dc_ops = &gx_dc_ops; | ||
314 | par->vid_ops = &gx_vid_ops; | ||
315 | |||
316 | if ((ret = gxfb_map_video_memory(info, pdev)) < 0) { | ||
317 | dev_err(&pdev->dev, "failed to map frame buffer or controller registers\n"); | ||
318 | goto err; | ||
319 | } | ||
320 | |||
321 | ret = fb_find_mode(&info->var, info, mode_option, | ||
322 | gx_modedb, ARRAY_SIZE(gx_modedb), NULL, 16); | ||
323 | if (ret == 0 || ret == 4) { | ||
324 | dev_err(&pdev->dev, "could not find valid video mode\n"); | ||
325 | ret = -EINVAL; | ||
326 | goto err; | ||
327 | } | ||
328 | |||
329 | /* Clear the frame buffer of garbage. */ | ||
330 | memset_io(info->screen_base, 0, info->fix.smem_len); | ||
331 | |||
332 | gxfb_check_var(&info->var, info); | ||
333 | gxfb_set_par(info); | ||
334 | |||
335 | if (register_framebuffer(info) < 0) { | ||
336 | ret = -EINVAL; | ||
337 | goto err; | ||
338 | } | ||
339 | pci_set_drvdata(pdev, info); | ||
340 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); | ||
341 | return 0; | ||
342 | |||
343 | err: | ||
344 | if (info->screen_base) { | ||
345 | iounmap(info->screen_base); | ||
346 | pci_release_region(pdev, 0); | ||
347 | } | ||
348 | if (par->vid_regs) { | ||
349 | iounmap(par->vid_regs); | ||
350 | pci_release_region(pdev, 3); | ||
351 | } | ||
352 | if (par->dc_regs) { | ||
353 | iounmap(par->dc_regs); | ||
354 | pci_release_region(pdev, 2); | ||
355 | } | ||
356 | |||
357 | pci_disable_device(pdev); | ||
358 | |||
359 | if (info) | ||
360 | framebuffer_release(info); | ||
361 | return ret; | ||
362 | } | ||
363 | |||
364 | static void gxfb_remove(struct pci_dev *pdev) | ||
365 | { | ||
366 | struct fb_info *info = pci_get_drvdata(pdev); | ||
367 | struct geodefb_par *par = info->par; | ||
368 | |||
369 | unregister_framebuffer(info); | ||
370 | |||
371 | iounmap((void __iomem *)info->screen_base); | ||
372 | pci_release_region(pdev, 0); | ||
373 | |||
374 | iounmap(par->vid_regs); | ||
375 | pci_release_region(pdev, 3); | ||
376 | |||
377 | iounmap(par->dc_regs); | ||
378 | pci_release_region(pdev, 2); | ||
379 | |||
380 | pci_disable_device(pdev); | ||
381 | pci_set_drvdata(pdev, NULL); | ||
382 | |||
383 | framebuffer_release(info); | ||
384 | } | ||
385 | |||
386 | static struct pci_device_id gxfb_id_table[] = { | ||
387 | { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_VIDEO, | ||
388 | PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, | ||
389 | 0xff0000, 0 }, | ||
390 | { 0, } | ||
391 | }; | ||
392 | |||
393 | MODULE_DEVICE_TABLE(pci, gxfb_id_table); | ||
394 | |||
395 | static struct pci_driver gxfb_driver = { | ||
396 | .name = "gxfb", | ||
397 | .id_table = gxfb_id_table, | ||
398 | .probe = gxfb_probe, | ||
399 | .remove = gxfb_remove, | ||
400 | }; | ||
401 | |||
402 | static int __init gxfb_init(void) | ||
403 | { | ||
404 | #ifndef MODULE | ||
405 | if (fb_get_options("gxfb", NULL)) | ||
406 | return -ENODEV; | ||
407 | #endif | ||
408 | return pci_register_driver(&gxfb_driver); | ||
409 | } | ||
410 | |||
411 | static void __exit gxfb_cleanup(void) | ||
412 | { | ||
413 | pci_unregister_driver(&gxfb_driver); | ||
414 | } | ||
415 | |||
416 | module_init(gxfb_init); | ||
417 | module_exit(gxfb_cleanup); | ||
418 | |||
419 | module_param_string(mode, mode_option, sizeof(mode_option), 0444); | ||
420 | MODULE_PARM_DESC(mode, "video mode (<x>x<y>[-<bpp>][@<refr>])"); | ||
421 | |||
422 | MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode GX"); | ||
423 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/geode/video_gx.c b/drivers/video/geode/video_gx.c new file mode 100644 index 000000000000..2b2a7880ea75 --- /dev/null +++ b/drivers/video/geode/video_gx.c | |||
@@ -0,0 +1,262 @@ | |||
1 | /* | ||
2 | * Geode GX video processor device. | ||
3 | * | ||
4 | * Copyright (C) 2006 Arcom Control Systems Ltd. | ||
5 | * | ||
6 | * Portions from AMD's original 2.4 driver: | ||
7 | * Copyright (C) 2004 Advanced Micro Devices, Inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | */ | ||
14 | #include <linux/fb.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <asm/io.h> | ||
17 | #include <asm/delay.h> | ||
18 | #include <asm/msr.h> | ||
19 | |||
20 | #include "geodefb.h" | ||
21 | #include "video_gx.h" | ||
22 | |||
23 | |||
24 | /* | ||
25 | * Tables of register settings for various DOTCLKs. | ||
26 | */ | ||
27 | struct gx_pll_entry { | ||
28 | long pixclock; /* ps */ | ||
29 | u32 sys_rstpll_bits; | ||
30 | u32 dotpll_value; | ||
31 | }; | ||
32 | |||
33 | #define POSTDIV3 ((u32)MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3) | ||
34 | #define PREMULT2 ((u32)MSR_GLCP_SYS_RSTPLL_DOTPREMULT2) | ||
35 | #define PREDIV2 ((u32)MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3) | ||
36 | |||
37 | static const struct gx_pll_entry gx_pll_table_48MHz[] = { | ||
38 | { 40123, POSTDIV3, 0x00000BF2 }, /* 24.9230 */ | ||
39 | { 39721, 0, 0x00000037 }, /* 25.1750 */ | ||
40 | { 35308, POSTDIV3|PREMULT2, 0x00000B1A }, /* 28.3220 */ | ||
41 | { 31746, POSTDIV3, 0x000002D2 }, /* 31.5000 */ | ||
42 | { 27777, POSTDIV3|PREMULT2, 0x00000FE2 }, /* 36.0000 */ | ||
43 | { 26666, POSTDIV3, 0x0000057A }, /* 37.5000 */ | ||
44 | { 25000, POSTDIV3, 0x0000030A }, /* 40.0000 */ | ||
45 | { 22271, 0, 0x00000063 }, /* 44.9000 */ | ||
46 | { 20202, 0, 0x0000054B }, /* 49.5000 */ | ||
47 | { 20000, 0, 0x0000026E }, /* 50.0000 */ | ||
48 | { 19860, PREMULT2, 0x00000037 }, /* 50.3500 */ | ||
49 | { 18518, POSTDIV3|PREMULT2, 0x00000B0D }, /* 54.0000 */ | ||
50 | { 17777, 0, 0x00000577 }, /* 56.2500 */ | ||
51 | { 17733, 0, 0x000007F7 }, /* 56.3916 */ | ||
52 | { 17653, 0, 0x0000057B }, /* 56.6444 */ | ||
53 | { 16949, PREMULT2, 0x00000707 }, /* 59.0000 */ | ||
54 | { 15873, POSTDIV3|PREMULT2, 0x00000B39 }, /* 63.0000 */ | ||
55 | { 15384, POSTDIV3|PREMULT2, 0x00000B45 }, /* 65.0000 */ | ||
56 | { 14814, POSTDIV3|PREMULT2, 0x00000FC1 }, /* 67.5000 */ | ||
57 | { 14124, POSTDIV3, 0x00000561 }, /* 70.8000 */ | ||
58 | { 13888, POSTDIV3, 0x000007E1 }, /* 72.0000 */ | ||
59 | { 13426, PREMULT2, 0x00000F4A }, /* 74.4810 */ | ||
60 | { 13333, 0, 0x00000052 }, /* 75.0000 */ | ||
61 | { 12698, 0, 0x00000056 }, /* 78.7500 */ | ||
62 | { 12500, POSTDIV3|PREMULT2, 0x00000709 }, /* 80.0000 */ | ||
63 | { 11135, PREMULT2, 0x00000262 }, /* 89.8000 */ | ||
64 | { 10582, 0, 0x000002D2 }, /* 94.5000 */ | ||
65 | { 10101, PREMULT2, 0x00000B4A }, /* 99.0000 */ | ||
66 | { 10000, PREMULT2, 0x00000036 }, /* 100.0000 */ | ||
67 | { 9259, 0, 0x000007E2 }, /* 108.0000 */ | ||
68 | { 8888, 0, 0x000007F6 }, /* 112.5000 */ | ||
69 | { 7692, POSTDIV3|PREMULT2, 0x00000FB0 }, /* 130.0000 */ | ||
70 | { 7407, POSTDIV3|PREMULT2, 0x00000B50 }, /* 135.0000 */ | ||
71 | { 6349, 0, 0x00000055 }, /* 157.5000 */ | ||
72 | { 6172, 0, 0x000009C1 }, /* 162.0000 */ | ||
73 | { 5787, PREMULT2, 0x0000002D }, /* 172.798 */ | ||
74 | { 5698, 0, 0x000002C1 }, /* 175.5000 */ | ||
75 | { 5291, 0, 0x000002D1 }, /* 189.0000 */ | ||
76 | { 4938, 0, 0x00000551 }, /* 202.5000 */ | ||
77 | { 4357, 0, 0x0000057D }, /* 229.5000 */ | ||
78 | }; | ||
79 | |||
80 | static const struct gx_pll_entry gx_pll_table_14MHz[] = { | ||
81 | { 39721, 0, 0x00000037 }, /* 25.1750 */ | ||
82 | { 35308, 0, 0x00000B7B }, /* 28.3220 */ | ||
83 | { 31746, 0, 0x000004D3 }, /* 31.5000 */ | ||
84 | { 27777, 0, 0x00000BE3 }, /* 36.0000 */ | ||
85 | { 26666, 0, 0x0000074F }, /* 37.5000 */ | ||
86 | { 25000, 0, 0x0000050B }, /* 40.0000 */ | ||
87 | { 22271, 0, 0x00000063 }, /* 44.9000 */ | ||
88 | { 20202, 0, 0x0000054B }, /* 49.5000 */ | ||
89 | { 20000, 0, 0x0000026E }, /* 50.0000 */ | ||
90 | { 19860, 0, 0x000007C3 }, /* 50.3500 */ | ||
91 | { 18518, 0, 0x000007E3 }, /* 54.0000 */ | ||
92 | { 17777, 0, 0x00000577 }, /* 56.2500 */ | ||
93 | { 17733, 0, 0x000002FB }, /* 56.3916 */ | ||
94 | { 17653, 0, 0x0000057B }, /* 56.6444 */ | ||
95 | { 16949, 0, 0x0000058B }, /* 59.0000 */ | ||
96 | { 15873, 0, 0x0000095E }, /* 63.0000 */ | ||
97 | { 15384, 0, 0x0000096A }, /* 65.0000 */ | ||
98 | { 14814, 0, 0x00000BC2 }, /* 67.5000 */ | ||
99 | { 14124, 0, 0x0000098A }, /* 70.8000 */ | ||
100 | { 13888, 0, 0x00000BE2 }, /* 72.0000 */ | ||
101 | { 13333, 0, 0x00000052 }, /* 75.0000 */ | ||
102 | { 12698, 0, 0x00000056 }, /* 78.7500 */ | ||
103 | { 12500, 0, 0x0000050A }, /* 80.0000 */ | ||
104 | { 11135, 0, 0x0000078E }, /* 89.8000 */ | ||
105 | { 10582, 0, 0x000002D2 }, /* 94.5000 */ | ||
106 | { 10101, 0, 0x000011F6 }, /* 99.0000 */ | ||
107 | { 10000, 0, 0x0000054E }, /* 100.0000 */ | ||
108 | { 9259, 0, 0x000007E2 }, /* 108.0000 */ | ||
109 | { 8888, 0, 0x000002FA }, /* 112.5000 */ | ||
110 | { 7692, 0, 0x00000BB1 }, /* 130.0000 */ | ||
111 | { 7407, 0, 0x00000975 }, /* 135.0000 */ | ||
112 | { 6349, 0, 0x00000055 }, /* 157.5000 */ | ||
113 | { 6172, 0, 0x000009C1 }, /* 162.0000 */ | ||
114 | { 5698, 0, 0x000002C1 }, /* 175.5000 */ | ||
115 | { 5291, 0, 0x00000539 }, /* 189.0000 */ | ||
116 | { 4938, 0, 0x00000551 }, /* 202.5000 */ | ||
117 | { 4357, 0, 0x0000057D }, /* 229.5000 */ | ||
118 | }; | ||
119 | |||
120 | static void gx_set_dclk_frequency(struct fb_info *info) | ||
121 | { | ||
122 | const struct gx_pll_entry *pll_table; | ||
123 | int pll_table_len; | ||
124 | int i, best_i; | ||
125 | long min, diff; | ||
126 | u64 dotpll, sys_rstpll; | ||
127 | int timeout = 1000; | ||
128 | |||
129 | /* Rev. 1 Geode GXs use a 14 MHz reference clock instead of 48 MHz. */ | ||
130 | if (cpu_data->x86_mask == 1) { | ||
131 | pll_table = gx_pll_table_14MHz; | ||
132 | pll_table_len = ARRAY_SIZE(gx_pll_table_14MHz); | ||
133 | } else { | ||
134 | pll_table = gx_pll_table_48MHz; | ||
135 | pll_table_len = ARRAY_SIZE(gx_pll_table_48MHz); | ||
136 | } | ||
137 | |||
138 | /* Search the table for the closest pixclock. */ | ||
139 | best_i = 0; | ||
140 | min = abs(pll_table[0].pixclock - info->var.pixclock); | ||
141 | for (i = 1; i < pll_table_len; i++) { | ||
142 | diff = abs(pll_table[i].pixclock - info->var.pixclock); | ||
143 | if (diff < min) { | ||
144 | min = diff; | ||
145 | best_i = i; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | rdmsrl(MSR_GLCP_SYS_RSTPLL, sys_rstpll); | ||
150 | rdmsrl(MSR_GLCP_DOTPLL, dotpll); | ||
151 | |||
152 | /* Program new M, N and P. */ | ||
153 | dotpll &= 0x00000000ffffffffull; | ||
154 | dotpll |= (u64)pll_table[best_i].dotpll_value << 32; | ||
155 | dotpll |= MSR_GLCP_DOTPLL_DOTRESET; | ||
156 | dotpll &= ~MSR_GLCP_DOTPLL_BYPASS; | ||
157 | |||
158 | wrmsrl(MSR_GLCP_DOTPLL, dotpll); | ||
159 | |||
160 | /* Program dividers. */ | ||
161 | sys_rstpll &= ~( MSR_GLCP_SYS_RSTPLL_DOTPREDIV2 | ||
162 | | MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 | ||
163 | | MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 ); | ||
164 | sys_rstpll |= pll_table[best_i].sys_rstpll_bits; | ||
165 | |||
166 | wrmsrl(MSR_GLCP_SYS_RSTPLL, sys_rstpll); | ||
167 | |||
168 | /* Clear reset bit to start PLL. */ | ||
169 | dotpll &= ~(MSR_GLCP_DOTPLL_DOTRESET); | ||
170 | wrmsrl(MSR_GLCP_DOTPLL, dotpll); | ||
171 | |||
172 | /* Wait for LOCK bit. */ | ||
173 | do { | ||
174 | rdmsrl(MSR_GLCP_DOTPLL, dotpll); | ||
175 | } while (timeout-- && !(dotpll & MSR_GLCP_DOTPLL_LOCK)); | ||
176 | } | ||
177 | |||
178 | static void gx_configure_display(struct fb_info *info) | ||
179 | { | ||
180 | struct geodefb_par *par = info->par; | ||
181 | u32 dcfg, fp_pm; | ||
182 | |||
183 | dcfg = readl(par->vid_regs + GX_DCFG); | ||
184 | |||
185 | /* Clear bits from existing mode. */ | ||
186 | dcfg &= ~(GX_DCFG_CRT_SYNC_SKW_MASK | ||
187 | | GX_DCFG_CRT_HSYNC_POL | GX_DCFG_CRT_VSYNC_POL | ||
188 | | GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN); | ||
189 | |||
190 | /* Set default sync skew. */ | ||
191 | dcfg |= GX_DCFG_CRT_SYNC_SKW_DFLT; | ||
192 | |||
193 | /* Enable hsync and vsync. */ | ||
194 | dcfg |= GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN; | ||
195 | |||
196 | /* Sync polarities. */ | ||
197 | if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) | ||
198 | dcfg |= GX_DCFG_CRT_HSYNC_POL; | ||
199 | if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) | ||
200 | dcfg |= GX_DCFG_CRT_VSYNC_POL; | ||
201 | |||
202 | writel(dcfg, par->vid_regs + GX_DCFG); | ||
203 | |||
204 | /* Power on flat panel. */ | ||
205 | fp_pm = readl(par->vid_regs + GX_FP_PM); | ||
206 | fp_pm |= GX_FP_PM_P; | ||
207 | writel(fp_pm, par->vid_regs + GX_FP_PM); | ||
208 | } | ||
209 | |||
210 | static int gx_blank_display(struct fb_info *info, int blank_mode) | ||
211 | { | ||
212 | struct geodefb_par *par = info->par; | ||
213 | u32 dcfg, fp_pm; | ||
214 | int blank, hsync, vsync; | ||
215 | |||
216 | /* CRT power saving modes. */ | ||
217 | switch (blank_mode) { | ||
218 | case FB_BLANK_UNBLANK: | ||
219 | blank = 0; hsync = 1; vsync = 1; | ||
220 | break; | ||
221 | case FB_BLANK_NORMAL: | ||
222 | blank = 1; hsync = 1; vsync = 1; | ||
223 | break; | ||
224 | case FB_BLANK_VSYNC_SUSPEND: | ||
225 | blank = 1; hsync = 1; vsync = 0; | ||
226 | break; | ||
227 | case FB_BLANK_HSYNC_SUSPEND: | ||
228 | blank = 1; hsync = 0; vsync = 1; | ||
229 | break; | ||
230 | case FB_BLANK_POWERDOWN: | ||
231 | blank = 1; hsync = 0; vsync = 0; | ||
232 | break; | ||
233 | default: | ||
234 | return -EINVAL; | ||
235 | } | ||
236 | dcfg = readl(par->vid_regs + GX_DCFG); | ||
237 | dcfg &= ~(GX_DCFG_DAC_BL_EN | ||
238 | | GX_DCFG_HSYNC_EN | GX_DCFG_VSYNC_EN); | ||
239 | if (!blank) | ||
240 | dcfg |= GX_DCFG_DAC_BL_EN; | ||
241 | if (hsync) | ||
242 | dcfg |= GX_DCFG_HSYNC_EN; | ||
243 | if (vsync) | ||
244 | dcfg |= GX_DCFG_VSYNC_EN; | ||
245 | writel(dcfg, par->vid_regs + GX_DCFG); | ||
246 | |||
247 | /* Power on/off flat panel. */ | ||
248 | fp_pm = readl(par->vid_regs + GX_FP_PM); | ||
249 | if (blank_mode == FB_BLANK_POWERDOWN) | ||
250 | fp_pm &= ~GX_FP_PM_P; | ||
251 | else | ||
252 | fp_pm |= GX_FP_PM_P; | ||
253 | writel(fp_pm, par->vid_regs + GX_FP_PM); | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | struct geode_vid_ops gx_vid_ops = { | ||
259 | .set_dclk = gx_set_dclk_frequency, | ||
260 | .configure_display = gx_configure_display, | ||
261 | .blank_display = gx_blank_display, | ||
262 | }; | ||
diff --git a/drivers/video/geode/video_gx.h b/drivers/video/geode/video_gx.h new file mode 100644 index 000000000000..2d9211f3ed84 --- /dev/null +++ b/drivers/video/geode/video_gx.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * Geode GX video device | ||
3 | * | ||
4 | * Copyright (C) 2006 Arcom Control Systems Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | #ifndef __VIDEO_GX_H__ | ||
12 | #define __VIDEO_GX_H__ | ||
13 | |||
14 | extern struct geode_vid_ops gx_vid_ops; | ||
15 | |||
16 | /* Geode GX video processor registers */ | ||
17 | |||
18 | #define GX_DCFG 0x0008 | ||
19 | # define GX_DCFG_CRT_EN 0x00000001 | ||
20 | # define GX_DCFG_HSYNC_EN 0x00000002 | ||
21 | # define GX_DCFG_VSYNC_EN 0x00000004 | ||
22 | # define GX_DCFG_DAC_BL_EN 0x00000008 | ||
23 | # define GX_DCFG_CRT_HSYNC_POL 0x00000100 | ||
24 | # define GX_DCFG_CRT_VSYNC_POL 0x00000200 | ||
25 | # define GX_DCFG_CRT_SYNC_SKW_MASK 0x0001C000 | ||
26 | # define GX_DCFG_CRT_SYNC_SKW_DFLT 0x00010000 | ||
27 | # define GX_DCFG_VG_CK 0x00100000 | ||
28 | # define GX_DCFG_GV_GAM 0x00200000 | ||
29 | # define GX_DCFG_DAC_VREF 0x04000000 | ||
30 | |||
31 | /* Geode GX flat panel display control registers */ | ||
32 | #define GX_FP_PM 0x410 | ||
33 | # define GX_FP_PM_P 0x01000000 | ||
34 | |||
35 | /* Geode GX clock control MSRs */ | ||
36 | |||
37 | #define MSR_GLCP_SYS_RSTPLL 0x4c000014 | ||
38 | # define MSR_GLCP_SYS_RSTPLL_DOTPREDIV2 (0x0000000000000002ull) | ||
39 | # define MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 (0x0000000000000004ull) | ||
40 | # define MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 (0x0000000000000008ull) | ||
41 | |||
42 | #define MSR_GLCP_DOTPLL 0x4c000015 | ||
43 | # define MSR_GLCP_DOTPLL_DOTRESET (0x0000000000000001ull) | ||
44 | # define MSR_GLCP_DOTPLL_BYPASS (0x0000000000008000ull) | ||
45 | # define MSR_GLCP_DOTPLL_LOCK (0x0000000002000000ull) | ||
46 | |||
47 | #endif /* !__VIDEO_GX_H__ */ | ||
diff --git a/drivers/video/i810/i810-i2c.c b/drivers/video/i810/i810-i2c.c index e3c8b5f1ca76..3fe3ae1aff12 100644 --- a/drivers/video/i810/i810-i2c.c +++ b/drivers/video/i810/i810-i2c.c | |||
@@ -210,8 +210,7 @@ int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn) | |||
210 | } | 210 | } |
211 | } | 211 | } |
212 | 212 | ||
213 | if (out_edid) | 213 | *out_edid = edid; |
214 | *out_edid = edid; | ||
215 | 214 | ||
216 | return (edid) ? 0 : 1; | 215 | return (edid) ? 0 : 1; |
217 | } | 216 | } |
diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c index 7db42542eb19..f73c642b50c2 100644 --- a/drivers/video/imsttfb.c +++ b/drivers/video/imsttfb.c | |||
@@ -440,9 +440,9 @@ getclkMHz(struct imstt_par *par) | |||
440 | static void | 440 | static void |
441 | setclkMHz(struct imstt_par *par, __u32 MHz) | 441 | setclkMHz(struct imstt_par *par, __u32 MHz) |
442 | { | 442 | { |
443 | __u32 clk_m, clk_n, clk_p, x, stage, spilled; | 443 | __u32 clk_m, clk_n, x, stage, spilled; |
444 | 444 | ||
445 | clk_m = clk_n = clk_p = 0; | 445 | clk_m = clk_n = 0; |
446 | stage = spilled = 0; | 446 | stage = spilled = 0; |
447 | for (;;) { | 447 | for (;;) { |
448 | switch (stage) { | 448 | switch (stage) { |
@@ -453,7 +453,7 @@ setclkMHz(struct imstt_par *par, __u32 MHz) | |||
453 | clk_n++; | 453 | clk_n++; |
454 | break; | 454 | break; |
455 | } | 455 | } |
456 | x = 20 * (clk_m + 1) / ((clk_n + 1) * (clk_p ? 2 * clk_p : 1)); | 456 | x = 20 * (clk_m + 1) / (clk_n + 1); |
457 | if (x == MHz) | 457 | if (x == MHz) |
458 | break; | 458 | break; |
459 | if (x > MHz) { | 459 | if (x > MHz) { |
@@ -466,7 +466,7 @@ setclkMHz(struct imstt_par *par, __u32 MHz) | |||
466 | 466 | ||
467 | par->init.pclk_m = clk_m; | 467 | par->init.pclk_m = clk_m; |
468 | par->init.pclk_n = clk_n; | 468 | par->init.pclk_n = clk_n; |
469 | par->init.pclk_p = clk_p; | 469 | par->init.pclk_p = 0; |
470 | } | 470 | } |
471 | 471 | ||
472 | static struct imstt_regvals * | 472 | static struct imstt_regvals * |
@@ -1372,18 +1372,24 @@ init_imstt(struct fb_info *info) | |||
1372 | write_reg_le32(par->dc_regs, STGCTL, tmp & ~0x1); | 1372 | write_reg_le32(par->dc_regs, STGCTL, tmp & ~0x1); |
1373 | write_reg_le32(par->dc_regs, SSR, 0); | 1373 | write_reg_le32(par->dc_regs, SSR, 0); |
1374 | 1374 | ||
1375 | /* set default values for DAC registers */ | 1375 | /* set default values for DAC registers */ |
1376 | if (par->ramdac == IBM) { | 1376 | if (par->ramdac == IBM) { |
1377 | par->cmap_regs[PPMASK] = 0xff; eieio(); | 1377 | par->cmap_regs[PPMASK] = 0xff; |
1378 | par->cmap_regs[PIDXHI] = 0; eieio(); | 1378 | eieio(); |
1379 | for (i = 0; i < sizeof(ibm_initregs) / sizeof(*ibm_initregs); i++) { | 1379 | par->cmap_regs[PIDXHI] = 0; |
1380 | par->cmap_regs[PIDXLO] = ibm_initregs[i].addr; eieio(); | 1380 | eieio(); |
1381 | par->cmap_regs[PIDXDATA] = ibm_initregs[i].value; eieio(); | 1381 | for (i = 0; i < ARRAY_SIZE(ibm_initregs); i++) { |
1382 | par->cmap_regs[PIDXLO] = ibm_initregs[i].addr; | ||
1383 | eieio(); | ||
1384 | par->cmap_regs[PIDXDATA] = ibm_initregs[i].value; | ||
1385 | eieio(); | ||
1382 | } | 1386 | } |
1383 | } else { | 1387 | } else { |
1384 | for (i = 0; i < sizeof(tvp_initregs) / sizeof(*tvp_initregs); i++) { | 1388 | for (i = 0; i < ARRAY_SIZE(tvp_initregs); i++) { |
1385 | par->cmap_regs[TVPADDRW] = tvp_initregs[i].addr; eieio(); | 1389 | par->cmap_regs[TVPADDRW] = tvp_initregs[i].addr; |
1386 | par->cmap_regs[TVPIDATA] = tvp_initregs[i].value; eieio(); | 1390 | eieio(); |
1391 | par->cmap_regs[TVPIDATA] = tvp_initregs[i].value; | ||
1392 | eieio(); | ||
1387 | } | 1393 | } |
1388 | } | 1394 | } |
1389 | 1395 | ||
diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c index 2fc71081f7e7..c0385c6f7db5 100644 --- a/drivers/video/macmodes.c +++ b/drivers/video/macmodes.c | |||
@@ -380,7 +380,7 @@ int __init mac_find_mode(struct fb_var_screeninfo *var, struct fb_info *info, | |||
380 | if (mode_option && !strncmp(mode_option, "mac", 3)) { | 380 | if (mode_option && !strncmp(mode_option, "mac", 3)) { |
381 | mode_option += 3; | 381 | mode_option += 3; |
382 | db = mac_modedb; | 382 | db = mac_modedb; |
383 | dbsize = sizeof(mac_modedb)/sizeof(*mac_modedb); | 383 | dbsize = ARRAY_SIZE(mac_modedb); |
384 | } | 384 | } |
385 | return fb_find_mode(var, info, mode_option, db, dbsize, | 385 | return fb_find_mode(var, info, mode_option, db, dbsize, |
386 | &mac_modedb[DEFAULT_MODEDB_INDEX], default_bpp); | 386 | &mac_modedb[DEFAULT_MODEDB_INDEX], default_bpp); |
diff --git a/drivers/video/matrox/matroxfb_g450.c b/drivers/video/matrox/matroxfb_g450.c index c122d8743dd2..4d610b405d45 100644 --- a/drivers/video/matrox/matroxfb_g450.c +++ b/drivers/video/matrox/matroxfb_g450.c | |||
@@ -59,7 +59,7 @@ static const struct mctl g450_controls[] = | |||
59 | }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) }, | 59 | }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) }, |
60 | }; | 60 | }; |
61 | 61 | ||
62 | #define G450CTRLS (sizeof(g450_controls)/sizeof(g450_controls[0])) | 62 | #define G450CTRLS ARRAY_SIZE(g450_controls) |
63 | 63 | ||
64 | /* Return: positive number: id found | 64 | /* Return: positive number: id found |
65 | -EINVAL: id not found, return failure | 65 | -EINVAL: id not found, return failure |
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c index 6019710dc298..5d29a26b8cdf 100644 --- a/drivers/video/matrox/matroxfb_maven.c +++ b/drivers/video/matrox/matroxfb_maven.c | |||
@@ -89,12 +89,12 @@ static const struct mctl maven_controls[] = | |||
89 | }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) }, | 89 | }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) }, |
90 | { { V4L2_CID_GAMMA, V4L2_CTRL_TYPE_INTEGER, | 90 | { { V4L2_CID_GAMMA, V4L2_CTRL_TYPE_INTEGER, |
91 | "gamma", | 91 | "gamma", |
92 | 0, sizeof(maven_gamma)/sizeof(maven_gamma[0])-1, 1, 3, | 92 | 0, ARRAY_SIZE(maven_gamma) - 1, 1, 3, |
93 | 0, | 93 | 0, |
94 | }, offsetof(struct matrox_fb_info, altout.tvo_params.gamma) }, | 94 | }, offsetof(struct matrox_fb_info, altout.tvo_params.gamma) }, |
95 | { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN, | 95 | { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN, |
96 | "test output", | 96 | "test output", |
97 | 0, 1, 1, 0, | 97 | 0, 1, 1, 0, |
98 | 0, | 98 | 0, |
99 | }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) }, | 99 | }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) }, |
100 | { { MATROXFB_CID_DEFLICKER, V4L2_CTRL_TYPE_INTEGER, | 100 | { { MATROXFB_CID_DEFLICKER, V4L2_CTRL_TYPE_INTEGER, |
@@ -105,7 +105,7 @@ static const struct mctl maven_controls[] = | |||
105 | 105 | ||
106 | }; | 106 | }; |
107 | 107 | ||
108 | #define MAVCTRLS (sizeof(maven_controls)/sizeof(maven_controls[0])) | 108 | #define MAVCTRLS ARRAY_SIZE(maven_controls) |
109 | 109 | ||
110 | /* Return: positive number: id found | 110 | /* Return: positive number: id found |
111 | -EINVAL: id not found, return failure | 111 | -EINVAL: id not found, return failure |
@@ -129,7 +129,7 @@ static int get_ctrl_id(__u32 v4l2_id) { | |||
129 | 129 | ||
130 | struct maven_data { | 130 | struct maven_data { |
131 | struct matrox_fb_info* primary_head; | 131 | struct matrox_fb_info* primary_head; |
132 | struct i2c_client* client; | 132 | struct i2c_client client; |
133 | int version; | 133 | int version; |
134 | }; | 134 | }; |
135 | 135 | ||
@@ -970,7 +970,7 @@ static inline int maven_compute_timming(struct maven_data* md, | |||
970 | 970 | ||
971 | static int maven_program_timming(struct maven_data* md, | 971 | static int maven_program_timming(struct maven_data* md, |
972 | const struct mavenregs* m) { | 972 | const struct mavenregs* m) { |
973 | struct i2c_client* c = md->client; | 973 | struct i2c_client* c = &md->client; |
974 | 974 | ||
975 | if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) { | 975 | if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) { |
976 | LR(0x80); | 976 | LR(0x80); |
@@ -1007,7 +1007,7 @@ static int maven_program_timming(struct maven_data* md, | |||
1007 | } | 1007 | } |
1008 | 1008 | ||
1009 | static inline int maven_resync(struct maven_data* md) { | 1009 | static inline int maven_resync(struct maven_data* md) { |
1010 | struct i2c_client* c = md->client; | 1010 | struct i2c_client* c = &md->client; |
1011 | maven_set_reg(c, 0x95, 0x20); /* start whole thing */ | 1011 | maven_set_reg(c, 0x95, 0x20); /* start whole thing */ |
1012 | return 0; | 1012 | return 0; |
1013 | } | 1013 | } |
@@ -1065,48 +1065,48 @@ static int maven_set_control (struct maven_data* md, | |||
1065 | maven_compute_bwlevel(md, &blacklevel, &whitelevel); | 1065 | maven_compute_bwlevel(md, &blacklevel, &whitelevel); |
1066 | blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8); | 1066 | blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8); |
1067 | whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8); | 1067 | whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8); |
1068 | maven_set_reg_pair(md->client, 0x0e, blacklevel); | 1068 | maven_set_reg_pair(&md->client, 0x0e, blacklevel); |
1069 | maven_set_reg_pair(md->client, 0x1e, whitelevel); | 1069 | maven_set_reg_pair(&md->client, 0x1e, whitelevel); |
1070 | } | 1070 | } |
1071 | break; | 1071 | break; |
1072 | case V4L2_CID_SATURATION: | 1072 | case V4L2_CID_SATURATION: |
1073 | { | 1073 | { |
1074 | maven_set_reg(md->client, 0x20, p->value); | 1074 | maven_set_reg(&md->client, 0x20, p->value); |
1075 | maven_set_reg(md->client, 0x22, p->value); | 1075 | maven_set_reg(&md->client, 0x22, p->value); |
1076 | } | 1076 | } |
1077 | break; | 1077 | break; |
1078 | case V4L2_CID_HUE: | 1078 | case V4L2_CID_HUE: |
1079 | { | 1079 | { |
1080 | maven_set_reg(md->client, 0x25, p->value); | 1080 | maven_set_reg(&md->client, 0x25, p->value); |
1081 | } | 1081 | } |
1082 | break; | 1082 | break; |
1083 | case V4L2_CID_GAMMA: | 1083 | case V4L2_CID_GAMMA: |
1084 | { | 1084 | { |
1085 | const struct maven_gamma* g; | 1085 | const struct maven_gamma* g; |
1086 | g = maven_compute_gamma(md); | 1086 | g = maven_compute_gamma(md); |
1087 | maven_set_reg(md->client, 0x83, g->reg83); | 1087 | maven_set_reg(&md->client, 0x83, g->reg83); |
1088 | maven_set_reg(md->client, 0x84, g->reg84); | 1088 | maven_set_reg(&md->client, 0x84, g->reg84); |
1089 | maven_set_reg(md->client, 0x85, g->reg85); | 1089 | maven_set_reg(&md->client, 0x85, g->reg85); |
1090 | maven_set_reg(md->client, 0x86, g->reg86); | 1090 | maven_set_reg(&md->client, 0x86, g->reg86); |
1091 | maven_set_reg(md->client, 0x87, g->reg87); | 1091 | maven_set_reg(&md->client, 0x87, g->reg87); |
1092 | maven_set_reg(md->client, 0x88, g->reg88); | 1092 | maven_set_reg(&md->client, 0x88, g->reg88); |
1093 | maven_set_reg(md->client, 0x89, g->reg89); | 1093 | maven_set_reg(&md->client, 0x89, g->reg89); |
1094 | maven_set_reg(md->client, 0x8a, g->reg8a); | 1094 | maven_set_reg(&md->client, 0x8a, g->reg8a); |
1095 | maven_set_reg(md->client, 0x8b, g->reg8b); | 1095 | maven_set_reg(&md->client, 0x8b, g->reg8b); |
1096 | } | 1096 | } |
1097 | break; | 1097 | break; |
1098 | case MATROXFB_CID_TESTOUT: | 1098 | case MATROXFB_CID_TESTOUT: |
1099 | { | 1099 | { |
1100 | unsigned char val | 1100 | unsigned char val |
1101 | = maven_get_reg (md->client,0x8d); | 1101 | = maven_get_reg(&md->client,0x8d); |
1102 | if (p->value) val |= 0x10; | 1102 | if (p->value) val |= 0x10; |
1103 | else val &= ~0x10; | 1103 | else val &= ~0x10; |
1104 | maven_set_reg (md->client, 0x8d, val); | 1104 | maven_set_reg(&md->client, 0x8d, val); |
1105 | } | 1105 | } |
1106 | break; | 1106 | break; |
1107 | case MATROXFB_CID_DEFLICKER: | 1107 | case MATROXFB_CID_DEFLICKER: |
1108 | { | 1108 | { |
1109 | maven_set_reg(md->client, 0x93, maven_compute_deflicker(md)); | 1109 | maven_set_reg(&md->client, 0x93, maven_compute_deflicker(md)); |
1110 | } | 1110 | } |
1111 | break; | 1111 | break; |
1112 | } | 1112 | } |
@@ -1185,7 +1185,6 @@ static int maven_init_client(struct i2c_client* clnt) { | |||
1185 | MINFO_FROM(container_of(clnt->adapter, struct i2c_bit_adapter, adapter)->minfo); | 1185 | MINFO_FROM(container_of(clnt->adapter, struct i2c_bit_adapter, adapter)->minfo); |
1186 | 1186 | ||
1187 | md->primary_head = MINFO; | 1187 | md->primary_head = MINFO; |
1188 | md->client = clnt; | ||
1189 | down_write(&ACCESS_FBINFO(altout.lock)); | 1188 | down_write(&ACCESS_FBINFO(altout.lock)); |
1190 | ACCESS_FBINFO(outputs[1]).output = &maven_altout; | 1189 | ACCESS_FBINFO(outputs[1]).output = &maven_altout; |
1191 | ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src; | 1190 | ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src; |
@@ -1243,19 +1242,17 @@ static int maven_detect_client(struct i2c_adapter* adapter, int address, int kin | |||
1243 | I2C_FUNC_SMBUS_BYTE_DATA | | 1242 | I2C_FUNC_SMBUS_BYTE_DATA | |
1244 | I2C_FUNC_PROTOCOL_MANGLING)) | 1243 | I2C_FUNC_PROTOCOL_MANGLING)) |
1245 | goto ERROR0; | 1244 | goto ERROR0; |
1246 | if (!(new_client = (struct i2c_client*)kmalloc(sizeof(*new_client) + sizeof(*data), | 1245 | if (!(data = kzalloc(sizeof(*data), GFP_KERNEL))) { |
1247 | GFP_KERNEL))) { | ||
1248 | err = -ENOMEM; | 1246 | err = -ENOMEM; |
1249 | goto ERROR0; | 1247 | goto ERROR0; |
1250 | } | 1248 | } |
1251 | memset(new_client, 0, sizeof(*new_client) + sizeof(*data)); | 1249 | new_client = &data->client; |
1252 | data = (struct maven_data*)(new_client + 1); | ||
1253 | i2c_set_clientdata(new_client, data); | 1250 | i2c_set_clientdata(new_client, data); |
1254 | new_client->addr = address; | 1251 | new_client->addr = address; |
1255 | new_client->adapter = adapter; | 1252 | new_client->adapter = adapter; |
1256 | new_client->driver = &maven_driver; | 1253 | new_client->driver = &maven_driver; |
1257 | new_client->flags = 0; | 1254 | new_client->flags = 0; |
1258 | strcpy(new_client->name, "maven client"); | 1255 | strlcpy(new_client->name, "maven", I2C_NAME_SIZE); |
1259 | if ((err = i2c_attach_client(new_client))) | 1256 | if ((err = i2c_attach_client(new_client))) |
1260 | goto ERROR3; | 1257 | goto ERROR3; |
1261 | err = maven_init_client(new_client); | 1258 | err = maven_init_client(new_client); |
@@ -1279,12 +1276,10 @@ static int maven_attach_adapter(struct i2c_adapter* adapter) { | |||
1279 | static int maven_detach_client(struct i2c_client* client) { | 1276 | static int maven_detach_client(struct i2c_client* client) { |
1280 | int err; | 1277 | int err; |
1281 | 1278 | ||
1282 | if ((err = i2c_detach_client(client))) { | 1279 | if ((err = i2c_detach_client(client))) |
1283 | printk(KERN_ERR "maven: Cannot deregister client\n"); | ||
1284 | return err; | 1280 | return err; |
1285 | } | ||
1286 | maven_shutdown_client(client); | 1281 | maven_shutdown_client(client); |
1287 | kfree(client); | 1282 | kfree(i2c_get_clientdata(client)); |
1288 | return 0; | 1283 | return 0; |
1289 | } | 1284 | } |
1290 | 1285 | ||
@@ -1297,20 +1292,13 @@ static struct i2c_driver maven_driver={ | |||
1297 | .detach_client = maven_detach_client, | 1292 | .detach_client = maven_detach_client, |
1298 | }; | 1293 | }; |
1299 | 1294 | ||
1300 | /* ************************** */ | 1295 | static int __init matroxfb_maven_init(void) |
1301 | 1296 | { | |
1302 | static int matroxfb_maven_init(void) { | 1297 | return i2c_add_driver(&maven_driver); |
1303 | int err; | ||
1304 | |||
1305 | err = i2c_add_driver(&maven_driver); | ||
1306 | if (err) { | ||
1307 | printk(KERN_ERR "maven: Maven driver failed to register (%d).\n", err); | ||
1308 | return err; | ||
1309 | } | ||
1310 | return 0; | ||
1311 | } | 1298 | } |
1312 | 1299 | ||
1313 | static void matroxfb_maven_exit(void) { | 1300 | static void __exit matroxfb_maven_exit(void) |
1301 | { | ||
1314 | i2c_del_driver(&maven_driver); | 1302 | i2c_del_driver(&maven_driver); |
1315 | } | 1303 | } |
1316 | 1304 | ||
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 1da2f84bdc25..26a1c618a205 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c | |||
@@ -183,6 +183,10 @@ static const struct fb_videomode modedb[] = { | |||
183 | NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, | 183 | NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, |
184 | FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | 184 | FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED |
185 | }, { | 185 | }, { |
186 | /* 1680x1050 @ 60 Hz, 65.191 kHz hsync */ | ||
187 | NULL, 60, 1680, 1050, 6848, 280, 104, 30, 3, 176, 6, | ||
188 | FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
189 | }, { | ||
186 | /* 1600x1200 @ 85 Hz, 105.77 kHz hsync */ | 190 | /* 1600x1200 @ 85 Hz, 105.77 kHz hsync */ |
187 | NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3, | 191 | NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3, |
188 | FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | 192 | FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED |
@@ -496,7 +500,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, | |||
496 | /* Set up defaults */ | 500 | /* Set up defaults */ |
497 | if (!db) { | 501 | if (!db) { |
498 | db = modedb; | 502 | db = modedb; |
499 | dbsize = sizeof(modedb)/sizeof(*modedb); | 503 | dbsize = ARRAY_SIZE(modedb); |
500 | } | 504 | } |
501 | if (!default_mode) | 505 | if (!default_mode) |
502 | default_mode = &modedb[DEFAULT_MODEDB_INDEX]; | 506 | default_mode = &modedb[DEFAULT_MODEDB_INDEX]; |
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c index b961d5601bd9..24b12f71d5a8 100644 --- a/drivers/video/neofb.c +++ b/drivers/video/neofb.c | |||
@@ -165,20 +165,20 @@ static int neoFindMode(int xres, int yres, int depth) | |||
165 | 165 | ||
166 | switch (depth) { | 166 | switch (depth) { |
167 | case 8: | 167 | case 8: |
168 | size = sizeof(bios8) / sizeof(biosMode); | 168 | size = ARRAY_SIZE(bios8); |
169 | mode = bios8; | 169 | mode = bios8; |
170 | break; | 170 | break; |
171 | case 16: | 171 | case 16: |
172 | size = sizeof(bios16) / sizeof(biosMode); | 172 | size = ARRAY_SIZE(bios16); |
173 | mode = bios16; | 173 | mode = bios16; |
174 | break; | 174 | break; |
175 | case 24: | 175 | case 24: |
176 | size = sizeof(bios24) / sizeof(biosMode); | 176 | size = ARRAY_SIZE(bios24); |
177 | mode = bios24; | 177 | mode = bios24; |
178 | break; | 178 | break; |
179 | #ifdef NO_32BIT_SUPPORT_YET | 179 | #ifdef NO_32BIT_SUPPORT_YET |
180 | case 32: | 180 | case 32: |
181 | size = sizeof(bios32) / sizeof(biosMode); | 181 | size = ARRAY_SIZE(bios32); |
182 | mode = bios32; | 182 | mode = bios32; |
183 | break; | 183 | break; |
184 | #endif | 184 | #endif |
diff --git a/drivers/video/nvidia/nv_accel.c b/drivers/video/nvidia/nv_accel.c index f377a29ec97a..4aefb8f41637 100644 --- a/drivers/video/nvidia/nv_accel.c +++ b/drivers/video/nvidia/nv_accel.c | |||
@@ -300,6 +300,9 @@ int nvidiafb_sync(struct fb_info *info) | |||
300 | { | 300 | { |
301 | struct nvidia_par *par = info->par; | 301 | struct nvidia_par *par = info->par; |
302 | 302 | ||
303 | if (info->state != FBINFO_STATE_RUNNING) | ||
304 | return 0; | ||
305 | |||
303 | if (!par->lockup) | 306 | if (!par->lockup) |
304 | NVFlush(par); | 307 | NVFlush(par); |
305 | 308 | ||
@@ -313,6 +316,9 @@ void nvidiafb_copyarea(struct fb_info *info, const struct fb_copyarea *region) | |||
313 | { | 316 | { |
314 | struct nvidia_par *par = info->par; | 317 | struct nvidia_par *par = info->par; |
315 | 318 | ||
319 | if (info->state != FBINFO_STATE_RUNNING) | ||
320 | return; | ||
321 | |||
316 | if (par->lockup) | 322 | if (par->lockup) |
317 | return cfb_copyarea(info, region); | 323 | return cfb_copyarea(info, region); |
318 | 324 | ||
@@ -329,6 +335,9 @@ void nvidiafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) | |||
329 | struct nvidia_par *par = info->par; | 335 | struct nvidia_par *par = info->par; |
330 | u32 color; | 336 | u32 color; |
331 | 337 | ||
338 | if (info->state != FBINFO_STATE_RUNNING) | ||
339 | return; | ||
340 | |||
332 | if (par->lockup) | 341 | if (par->lockup) |
333 | return cfb_fillrect(info, rect); | 342 | return cfb_fillrect(info, rect); |
334 | 343 | ||
@@ -412,6 +421,9 @@ void nvidiafb_imageblit(struct fb_info *info, const struct fb_image *image) | |||
412 | { | 421 | { |
413 | struct nvidia_par *par = info->par; | 422 | struct nvidia_par *par = info->par; |
414 | 423 | ||
424 | if (info->state != FBINFO_STATE_RUNNING) | ||
425 | return; | ||
426 | |||
415 | if (image->depth == 1 && !par->lockup) | 427 | if (image->depth == 1 && !par->lockup) |
416 | nvidiafb_mono_color_expand(info, image); | 428 | nvidiafb_mono_color_expand(info, image); |
417 | else | 429 | else |
diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c index bd9eca05e146..1edb1c432b75 100644 --- a/drivers/video/nvidia/nv_i2c.c +++ b/drivers/video/nvidia/nv_i2c.c | |||
@@ -218,8 +218,7 @@ int nvidia_probe_i2c_connector(struct fb_info *info, int conn, u8 **out_edid) | |||
218 | } | 218 | } |
219 | } | 219 | } |
220 | 220 | ||
221 | if (out_edid) | 221 | *out_edid = edid; |
222 | *out_edid = edid; | ||
223 | 222 | ||
224 | return (edid) ? 0 : 1; | 223 | return (edid) ? 0 : 1; |
225 | } | 224 | } |
diff --git a/drivers/video/nvidia/nv_type.h b/drivers/video/nvidia/nv_type.h index e4a5b1da71c4..acdc26693402 100644 --- a/drivers/video/nvidia/nv_type.h +++ b/drivers/video/nvidia/nv_type.h | |||
@@ -129,6 +129,7 @@ struct nvidia_par { | |||
129 | int fpHeight; | 129 | int fpHeight; |
130 | int PanelTweak; | 130 | int PanelTweak; |
131 | int paneltweak; | 131 | int paneltweak; |
132 | int pm_state; | ||
132 | u32 crtcSync_read; | 133 | u32 crtcSync_read; |
133 | u32 fpSyncs; | 134 | u32 fpSyncs; |
134 | u32 dmaPut; | 135 | u32 dmaPut; |
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index a7c4e5e8ead6..6d3e4890cb43 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/fb.h> | 21 | #include <linux/fb.h> |
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
24 | #include <linux/console.h> | ||
24 | #ifdef CONFIG_MTRR | 25 | #ifdef CONFIG_MTRR |
25 | #include <asm/mtrr.h> | 26 | #include <asm/mtrr.h> |
26 | #endif | 27 | #endif |
@@ -296,6 +297,8 @@ static struct pci_device_id nvidiafb_pci_tbl[] = { | |||
296 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | 297 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
297 | {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_GT, | 298 | {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_GT, |
298 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | 299 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
300 | {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_QUADRO_NVS280, | ||
301 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
299 | {PCI_VENDOR_ID_NVIDIA, 0x0252, | 302 | {PCI_VENDOR_ID_NVIDIA, 0x0252, |
300 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | 303 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
301 | {PCI_VENDOR_ID_NVIDIA, 0x0313, | 304 | {PCI_VENDOR_ID_NVIDIA, 0x0313, |
@@ -615,6 +618,30 @@ static int nvidia_panel_tweak(struct nvidia_par *par, | |||
615 | return tweak; | 618 | return tweak; |
616 | } | 619 | } |
617 | 620 | ||
621 | static void nvidia_vga_protect(struct nvidia_par *par, int on) | ||
622 | { | ||
623 | unsigned char tmp; | ||
624 | |||
625 | if (on) { | ||
626 | /* | ||
627 | * Turn off screen and disable sequencer. | ||
628 | */ | ||
629 | tmp = NVReadSeq(par, 0x01); | ||
630 | |||
631 | NVWriteSeq(par, 0x00, 0x01); /* Synchronous Reset */ | ||
632 | NVWriteSeq(par, 0x01, tmp | 0x20); /* disable the display */ | ||
633 | } else { | ||
634 | /* | ||
635 | * Reenable sequencer, then turn on screen. | ||
636 | */ | ||
637 | |||
638 | tmp = NVReadSeq(par, 0x01); | ||
639 | |||
640 | NVWriteSeq(par, 0x01, tmp & ~0x20); /* reenable display */ | ||
641 | NVWriteSeq(par, 0x00, 0x03); /* End Reset */ | ||
642 | } | ||
643 | } | ||
644 | |||
618 | static void nvidia_save_vga(struct nvidia_par *par, | 645 | static void nvidia_save_vga(struct nvidia_par *par, |
619 | struct _riva_hw_state *state) | 646 | struct _riva_hw_state *state) |
620 | { | 647 | { |
@@ -643,9 +670,9 @@ static void nvidia_save_vga(struct nvidia_par *par, | |||
643 | 670 | ||
644 | #undef DUMP_REG | 671 | #undef DUMP_REG |
645 | 672 | ||
646 | static void nvidia_write_regs(struct nvidia_par *par) | 673 | static void nvidia_write_regs(struct nvidia_par *par, |
674 | struct _riva_hw_state *state) | ||
647 | { | 675 | { |
648 | struct _riva_hw_state *state = &par->ModeReg; | ||
649 | int i; | 676 | int i; |
650 | 677 | ||
651 | NVTRACE_ENTER(); | 678 | NVTRACE_ENTER(); |
@@ -694,32 +721,6 @@ static void nvidia_write_regs(struct nvidia_par *par) | |||
694 | NVTRACE_LEAVE(); | 721 | NVTRACE_LEAVE(); |
695 | } | 722 | } |
696 | 723 | ||
697 | static void nvidia_vga_protect(struct nvidia_par *par, int on) | ||
698 | { | ||
699 | unsigned char tmp; | ||
700 | |||
701 | if (on) { | ||
702 | /* | ||
703 | * Turn off screen and disable sequencer. | ||
704 | */ | ||
705 | tmp = NVReadSeq(par, 0x01); | ||
706 | |||
707 | NVWriteSeq(par, 0x00, 0x01); /* Synchronous Reset */ | ||
708 | NVWriteSeq(par, 0x01, tmp | 0x20); /* disable the display */ | ||
709 | } else { | ||
710 | /* | ||
711 | * Reenable sequencer, then turn on screen. | ||
712 | */ | ||
713 | |||
714 | tmp = NVReadSeq(par, 0x01); | ||
715 | |||
716 | NVWriteSeq(par, 0x01, tmp & ~0x20); /* reenable display */ | ||
717 | NVWriteSeq(par, 0x00, 0x03); /* End Reset */ | ||
718 | } | ||
719 | } | ||
720 | |||
721 | |||
722 | |||
723 | static int nvidia_calc_regs(struct fb_info *info) | 724 | static int nvidia_calc_regs(struct fb_info *info) |
724 | { | 725 | { |
725 | struct nvidia_par *par = info->par; | 726 | struct nvidia_par *par = info->par; |
@@ -1068,7 +1069,8 @@ static int nvidiafb_set_par(struct fb_info *info) | |||
1068 | 1069 | ||
1069 | nvidia_vga_protect(par, 1); | 1070 | nvidia_vga_protect(par, 1); |
1070 | 1071 | ||
1071 | nvidia_write_regs(par); | 1072 | nvidia_write_regs(par, &par->ModeReg); |
1073 | NVSetStartAddress(par, 0); | ||
1072 | 1074 | ||
1073 | #if defined (__BIG_ENDIAN) | 1075 | #if defined (__BIG_ENDIAN) |
1074 | /* turn on LFB swapping */ | 1076 | /* turn on LFB swapping */ |
@@ -1377,6 +1379,57 @@ static struct fb_ops nvidia_fb_ops = { | |||
1377 | .fb_sync = nvidiafb_sync, | 1379 | .fb_sync = nvidiafb_sync, |
1378 | }; | 1380 | }; |
1379 | 1381 | ||
1382 | #ifdef CONFIG_PM | ||
1383 | static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t state) | ||
1384 | { | ||
1385 | struct fb_info *info = pci_get_drvdata(dev); | ||
1386 | struct nvidia_par *par = info->par; | ||
1387 | |||
1388 | acquire_console_sem(); | ||
1389 | par->pm_state = state.event; | ||
1390 | |||
1391 | if (state.event == PM_EVENT_FREEZE) { | ||
1392 | dev->dev.power.power_state = state; | ||
1393 | } else { | ||
1394 | fb_set_suspend(info, 1); | ||
1395 | nvidiafb_blank(FB_BLANK_POWERDOWN, info); | ||
1396 | nvidia_write_regs(par, &par->SavedReg); | ||
1397 | pci_save_state(dev); | ||
1398 | pci_disable_device(dev); | ||
1399 | pci_set_power_state(dev, pci_choose_state(dev, state)); | ||
1400 | } | ||
1401 | |||
1402 | release_console_sem(); | ||
1403 | return 0; | ||
1404 | } | ||
1405 | |||
1406 | static int nvidiafb_resume(struct pci_dev *dev) | ||
1407 | { | ||
1408 | struct fb_info *info = pci_get_drvdata(dev); | ||
1409 | struct nvidia_par *par = info->par; | ||
1410 | |||
1411 | acquire_console_sem(); | ||
1412 | pci_set_power_state(dev, PCI_D0); | ||
1413 | |||
1414 | if (par->pm_state != PM_EVENT_FREEZE) { | ||
1415 | pci_restore_state(dev); | ||
1416 | pci_enable_device(dev); | ||
1417 | pci_set_master(dev); | ||
1418 | } | ||
1419 | |||
1420 | par->pm_state = PM_EVENT_ON; | ||
1421 | nvidiafb_set_par(info); | ||
1422 | fb_set_suspend (info, 0); | ||
1423 | nvidiafb_blank(FB_BLANK_UNBLANK, info); | ||
1424 | |||
1425 | release_console_sem(); | ||
1426 | return 0; | ||
1427 | } | ||
1428 | #else | ||
1429 | #define nvidiafb_suspend NULL | ||
1430 | #define nvidiafb_resume NULL | ||
1431 | #endif | ||
1432 | |||
1380 | static int __devinit nvidia_set_fbinfo(struct fb_info *info) | 1433 | static int __devinit nvidia_set_fbinfo(struct fb_info *info) |
1381 | { | 1434 | { |
1382 | struct fb_monspecs *specs = &info->monspecs; | 1435 | struct fb_monspecs *specs = &info->monspecs; |
@@ -1720,8 +1773,6 @@ static void __exit nvidiafb_remove(struct pci_dev *pd) | |||
1720 | struct nvidia_par *par = info->par; | 1773 | struct nvidia_par *par = info->par; |
1721 | 1774 | ||
1722 | NVTRACE_ENTER(); | 1775 | NVTRACE_ENTER(); |
1723 | if (!info) | ||
1724 | return; | ||
1725 | 1776 | ||
1726 | unregister_framebuffer(info); | 1777 | unregister_framebuffer(info); |
1727 | #ifdef CONFIG_MTRR | 1778 | #ifdef CONFIG_MTRR |
@@ -1798,8 +1849,10 @@ static int __devinit nvidiafb_setup(char *options) | |||
1798 | static struct pci_driver nvidiafb_driver = { | 1849 | static struct pci_driver nvidiafb_driver = { |
1799 | .name = "nvidiafb", | 1850 | .name = "nvidiafb", |
1800 | .id_table = nvidiafb_pci_tbl, | 1851 | .id_table = nvidiafb_pci_tbl, |
1801 | .probe = nvidiafb_probe, | 1852 | .probe = nvidiafb_probe, |
1802 | .remove = __exit_p(nvidiafb_remove), | 1853 | .suspend = nvidiafb_suspend, |
1854 | .resume = nvidiafb_resume, | ||
1855 | .remove = __exit_p(nvidiafb_remove), | ||
1803 | }; | 1856 | }; |
1804 | 1857 | ||
1805 | /* ------------------------------------------------------------------------- * | 1858 | /* ------------------------------------------------------------------------- * |
diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c index eeeac924b500..73e2d7d16608 100644 --- a/drivers/video/pmagb-b-fb.c +++ b/drivers/video/pmagb-b-fb.c | |||
@@ -228,7 +228,7 @@ static void __init pmagbbfb_osc_setup(struct fb_info *info) | |||
228 | 228 | ||
229 | freq1 = (par->osc0 * count1 + count0 / 2) / count0; | 229 | freq1 = (par->osc0 * count1 + count0 / 2) / count0; |
230 | par->osc1 = freq1; | 230 | par->osc1 = freq1; |
231 | for (i = 0; i < sizeof(pmagbbfb_freqs) / sizeof(*pmagbbfb_freqs); i++) | 231 | for (i = 0; i < ARRAY_SIZE(pmagbbfb_freqs); i++) |
232 | if (freq1 >= pmagbbfb_freqs[i] - | 232 | if (freq1 >= pmagbbfb_freqs[i] - |
233 | (pmagbbfb_freqs[i] + 128) / 256 && | 233 | (pmagbbfb_freqs[i] + 128) / 256 && |
234 | freq1 <= pmagbbfb_freqs[i] + | 234 | freq1 <= pmagbbfb_freqs[i] + |
diff --git a/drivers/video/radeonfb.c b/drivers/video/radeonfb.c index db9fb9074dbc..24982adb3aa2 100644 --- a/drivers/video/radeonfb.c +++ b/drivers/video/radeonfb.c | |||
@@ -759,7 +759,7 @@ static void __iomem *radeon_find_rom(struct radeonfb_info *rinfo) | |||
759 | rom = rom_base; | 759 | rom = rom_base; |
760 | 760 | ||
761 | for (i = 0; (i < 512) && (stage != 4); i++) { | 761 | for (i = 0; (i < 512) && (stage != 4); i++) { |
762 | for(j = 0;j < sizeof(radeon_sig)/sizeof(char *);j++) { | 762 | for (j = 0; j < ARRAY_SIZE(radeon_sig); j++) { |
763 | if (radeon_sig[j][0] == *rom) | 763 | if (radeon_sig[j][0] == *rom) |
764 | if (strncmp(radeon_sig[j], rom, | 764 | if (strncmp(radeon_sig[j], rom, |
765 | strlen(radeon_sig[j])) == 0) { | 765 | strlen(radeon_sig[j])) == 0) { |
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 6c19ab6afb01..f841f013b96f 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c | |||
@@ -2072,8 +2072,6 @@ static void __exit rivafb_remove(struct pci_dev *pd) | |||
2072 | struct riva_par *par = info->par; | 2072 | struct riva_par *par = info->par; |
2073 | 2073 | ||
2074 | NVTRACE_ENTER(); | 2074 | NVTRACE_ENTER(); |
2075 | if (!info) | ||
2076 | return; | ||
2077 | 2075 | ||
2078 | #ifdef CONFIG_FB_RIVA_I2C | 2076 | #ifdef CONFIG_FB_RIVA_I2C |
2079 | riva_delete_i2c_busses(par); | 2077 | riva_delete_i2c_busses(par); |
diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c index 00719a91479f..21debed863ac 100644 --- a/drivers/video/savage/savagefb-i2c.c +++ b/drivers/video/savage/savagefb-i2c.c | |||
@@ -273,8 +273,7 @@ int savagefb_probe_i2c_connector(struct fb_info *info, u8 **out_edid) | |||
273 | } | 273 | } |
274 | } | 274 | } |
275 | 275 | ||
276 | if (out_edid) | 276 | *out_edid = edid; |
277 | *out_edid = edid; | ||
278 | 277 | ||
279 | return (edid) ? 0 : 1; | 278 | return (edid) ? 0 : 1; |
280 | } | 279 | } |
diff --git a/drivers/video/sis/init301.c b/drivers/video/sis/init301.c index 2d88f908170a..c3e070a6effd 100644 --- a/drivers/video/sis/init301.c +++ b/drivers/video/sis/init301.c | |||
@@ -8564,11 +8564,9 @@ SiS_ChrontelDoSomething3(struct SiS_Private *SiS_Pr, unsigned short ModeNo) | |||
8564 | static void | 8564 | static void |
8565 | SiS_ChrontelDoSomething2(struct SiS_Private *SiS_Pr) | 8565 | SiS_ChrontelDoSomething2(struct SiS_Private *SiS_Pr) |
8566 | { | 8566 | { |
8567 | unsigned short temp,tempcl,tempch; | 8567 | unsigned short temp; |
8568 | 8568 | ||
8569 | SiS_LongDelay(SiS_Pr, 1); | 8569 | SiS_LongDelay(SiS_Pr, 1); |
8570 | tempcl = 3; | ||
8571 | tempch = 0; | ||
8572 | 8570 | ||
8573 | do { | 8571 | do { |
8574 | temp = SiS_GetCH701x(SiS_Pr,0x66); | 8572 | temp = SiS_GetCH701x(SiS_Pr,0x66); |
@@ -8582,13 +8580,6 @@ SiS_ChrontelDoSomething2(struct SiS_Private *SiS_Pr) | |||
8582 | 8580 | ||
8583 | SiS_SetCH701xForLCD(SiS_Pr); | 8581 | SiS_SetCH701xForLCD(SiS_Pr); |
8584 | 8582 | ||
8585 | if(tempcl == 0) { | ||
8586 | if(tempch == 3) break; | ||
8587 | SiS_ChrontelResetDB(SiS_Pr); | ||
8588 | tempcl = 3; | ||
8589 | tempch++; | ||
8590 | } | ||
8591 | tempcl--; | ||
8592 | temp = SiS_GetCH701x(SiS_Pr,0x76); | 8583 | temp = SiS_GetCH701x(SiS_Pr,0x76); |
8593 | temp &= 0xfb; /* Reset PLL */ | 8584 | temp &= 0xfb; /* Reset PLL */ |
8594 | SiS_SetCH701x(SiS_Pr,0x76,temp); | 8585 | SiS_SetCH701x(SiS_Pr,0x76,temp); |
diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c index 8c1a8b5135c6..c44de90ca12e 100644 --- a/drivers/video/sstfb.c +++ b/drivers/video/sstfb.c | |||
@@ -1194,10 +1194,11 @@ static struct dac_switch dacs[] __devinitdata = { | |||
1194 | static int __devinit sst_detect_dactype(struct fb_info *info, struct sstfb_par *par) | 1194 | static int __devinit sst_detect_dactype(struct fb_info *info, struct sstfb_par *par) |
1195 | { | 1195 | { |
1196 | int i, ret = 0; | 1196 | int i, ret = 0; |
1197 | 1197 | ||
1198 | for (i=0; i<sizeof(dacs)/sizeof(dacs[0]); i++) { | 1198 | for (i = 0; i < ARRAY_SIZE(dacs); i++) { |
1199 | ret = dacs[i].detect(info); | 1199 | ret = dacs[i].detect(info); |
1200 | if (ret) break; | 1200 | if (ret) |
1201 | break; | ||
1201 | } | 1202 | } |
1202 | if (!ret) | 1203 | if (!ret) |
1203 | return 0; | 1204 | return 0; |
@@ -1604,8 +1605,8 @@ static int sstfb_dump_regs(struct fb_info *info) | |||
1604 | {FBZMODE,"fbzmode"}, | 1605 | {FBZMODE,"fbzmode"}, |
1605 | }; | 1606 | }; |
1606 | 1607 | ||
1607 | const int pci_s = sizeof(pci_regs)/sizeof(pci_regs[0]); | 1608 | const int pci_s = ARRAY_SIZE(pci_regs); |
1608 | const int sst_s = sizeof(sst_regs)/sizeof(sst_regs[0]); | 1609 | const int sst_s = ARRAY_SIZE(sst_regs); |
1609 | struct sstfb_par *par = info->par; | 1610 | struct sstfb_par *par = info->par; |
1610 | struct pci_dev *dev = par->dev; | 1611 | struct pci_dev *dev = par->dev; |
1611 | u32 pci_res[pci_s]; | 1612 | u32 pci_res[pci_s]; |
diff --git a/drivers/video/virgefb.c b/drivers/video/virgefb.c index ed78747487e2..5ea2345dab99 100644 --- a/drivers/video/virgefb.c +++ b/drivers/video/virgefb.c | |||
@@ -616,8 +616,7 @@ static struct { | |||
616 | #endif | 616 | #endif |
617 | }; | 617 | }; |
618 | 618 | ||
619 | #define arraysize(x) (sizeof(x)/sizeof(*(x))) | 619 | #define NUM_TOTAL_MODES ARRAY_SIZE(virgefb_predefined) |
620 | #define NUM_TOTAL_MODES arraysize(virgefb_predefined) | ||
621 | 620 | ||
622 | /* | 621 | /* |
623 | * Default to 800x600 for video=virge8:, virge16: or virge32: | 622 | * Default to 800x600 for video=virge8:, virge16: or virge32: |
diff --git a/fs/autofs/dirhash.c b/fs/autofs/dirhash.c index 5ccfcf26310d..3fded389d06b 100644 --- a/fs/autofs/dirhash.c +++ b/fs/autofs/dirhash.c | |||
@@ -92,7 +92,7 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb, | |||
92 | ; | 92 | ; |
93 | dput(dentry); | 93 | dput(dentry); |
94 | 94 | ||
95 | if ( may_umount(mnt) == 0 ) { | 95 | if ( may_umount(mnt) ) { |
96 | mntput(mnt); | 96 | mntput(mnt); |
97 | DPRINTK(("autofs: signaling expire on %s\n", ent->name)); | 97 | DPRINTK(("autofs: signaling expire on %s\n", ent->name)); |
98 | return ent; /* Expirable! */ | 98 | return ent; /* Expirable! */ |
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index f54c5b21f876..617fd7b37447 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h | |||
@@ -3,6 +3,7 @@ | |||
3 | * linux/fs/autofs/autofs_i.h | 3 | * linux/fs/autofs/autofs_i.h |
4 | * | 4 | * |
5 | * Copyright 1997-1998 Transmeta Corporation - All Rights Reserved | 5 | * Copyright 1997-1998 Transmeta Corporation - All Rights Reserved |
6 | * Copyright 2005-2006 Ian Kent <raven@themaw.net> | ||
6 | * | 7 | * |
7 | * This file is part of the Linux kernel and is made available under | 8 | * This file is part of the Linux kernel and is made available under |
8 | * the terms of the GNU General Public License, version 2, or at your | 9 | * the terms of the GNU General Public License, version 2, or at your |
@@ -41,14 +42,6 @@ | |||
41 | 42 | ||
42 | #define AUTOFS_SUPER_MAGIC 0x0187 | 43 | #define AUTOFS_SUPER_MAGIC 0x0187 |
43 | 44 | ||
44 | /* | ||
45 | * If the daemon returns a negative response (AUTOFS_IOC_FAIL) then the | ||
46 | * kernel will keep the negative response cached for up to the time given | ||
47 | * here, although the time can be shorter if the kernel throws the dcache | ||
48 | * entry away. This probably should be settable from user space. | ||
49 | */ | ||
50 | #define AUTOFS_NEGATIVE_TIMEOUT (60*HZ) /* 1 minute */ | ||
51 | |||
52 | /* Unified info structure. This is pointed to by both the dentry and | 45 | /* Unified info structure. This is pointed to by both the dentry and |
53 | inode structures. Each file in the filesystem has an instance of this | 46 | inode structures. Each file in the filesystem has an instance of this |
54 | structure. It holds a reference to the dentry, so dentries are never | 47 | structure. It holds a reference to the dentry, so dentries are never |
@@ -63,6 +56,7 @@ struct autofs_info { | |||
63 | 56 | ||
64 | struct autofs_sb_info *sbi; | 57 | struct autofs_sb_info *sbi; |
65 | unsigned long last_used; | 58 | unsigned long last_used; |
59 | atomic_t count; | ||
66 | 60 | ||
67 | mode_t mode; | 61 | mode_t mode; |
68 | size_t size; | 62 | size_t size; |
@@ -83,23 +77,37 @@ struct autofs_wait_queue { | |||
83 | int hash; | 77 | int hash; |
84 | int len; | 78 | int len; |
85 | char *name; | 79 | char *name; |
80 | u32 dev; | ||
81 | u64 ino; | ||
82 | uid_t uid; | ||
83 | gid_t gid; | ||
84 | pid_t pid; | ||
85 | pid_t tgid; | ||
86 | /* This is for status reporting upon return */ | 86 | /* This is for status reporting upon return */ |
87 | int status; | 87 | int status; |
88 | atomic_t notified; | 88 | atomic_t notify; |
89 | atomic_t wait_ctr; | 89 | atomic_t wait_ctr; |
90 | }; | 90 | }; |
91 | 91 | ||
92 | #define AUTOFS_SBI_MAGIC 0x6d4a556d | 92 | #define AUTOFS_SBI_MAGIC 0x6d4a556d |
93 | 93 | ||
94 | #define AUTOFS_TYPE_INDIRECT 0x0001 | ||
95 | #define AUTOFS_TYPE_DIRECT 0x0002 | ||
96 | #define AUTOFS_TYPE_OFFSET 0x0004 | ||
97 | |||
94 | struct autofs_sb_info { | 98 | struct autofs_sb_info { |
95 | u32 magic; | 99 | u32 magic; |
96 | struct dentry *root; | 100 | struct dentry *root; |
101 | int pipefd; | ||
97 | struct file *pipe; | 102 | struct file *pipe; |
98 | pid_t oz_pgrp; | 103 | pid_t oz_pgrp; |
99 | int catatonic; | 104 | int catatonic; |
100 | int version; | 105 | int version; |
101 | int sub_version; | 106 | int sub_version; |
107 | int min_proto; | ||
108 | int max_proto; | ||
102 | unsigned long exp_timeout; | 109 | unsigned long exp_timeout; |
110 | unsigned int type; | ||
103 | int reghost_enabled; | 111 | int reghost_enabled; |
104 | int needs_reghost; | 112 | int needs_reghost; |
105 | struct super_block *sb; | 113 | struct super_block *sb; |
@@ -166,6 +174,8 @@ int autofs4_expire_multi(struct super_block *, struct vfsmount *, | |||
166 | extern struct inode_operations autofs4_symlink_inode_operations; | 174 | extern struct inode_operations autofs4_symlink_inode_operations; |
167 | extern struct inode_operations autofs4_dir_inode_operations; | 175 | extern struct inode_operations autofs4_dir_inode_operations; |
168 | extern struct inode_operations autofs4_root_inode_operations; | 176 | extern struct inode_operations autofs4_root_inode_operations; |
177 | extern struct inode_operations autofs4_indirect_root_inode_operations; | ||
178 | extern struct inode_operations autofs4_direct_root_inode_operations; | ||
169 | extern struct file_operations autofs4_dir_operations; | 179 | extern struct file_operations autofs4_dir_operations; |
170 | extern struct file_operations autofs4_root_operations; | 180 | extern struct file_operations autofs4_root_operations; |
171 | 181 | ||
@@ -176,13 +186,6 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *, struct autofs_sb_info | |||
176 | 186 | ||
177 | /* Queue management functions */ | 187 | /* Queue management functions */ |
178 | 188 | ||
179 | enum autofs_notify | ||
180 | { | ||
181 | NFY_NONE, | ||
182 | NFY_MOUNT, | ||
183 | NFY_EXPIRE | ||
184 | }; | ||
185 | |||
186 | int autofs4_wait(struct autofs_sb_info *,struct dentry *, enum autofs_notify); | 189 | int autofs4_wait(struct autofs_sb_info *,struct dentry *, enum autofs_notify); |
187 | int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int); | 190 | int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int); |
188 | void autofs4_catatonic_mode(struct autofs_sb_info *); | 191 | void autofs4_catatonic_mode(struct autofs_sb_info *); |
@@ -200,12 +203,22 @@ static inline int autofs4_follow_mount(struct vfsmount **mnt, struct dentry **de | |||
200 | return res; | 203 | return res; |
201 | } | 204 | } |
202 | 205 | ||
206 | static inline u32 autofs4_get_dev(struct autofs_sb_info *sbi) | ||
207 | { | ||
208 | return new_encode_dev(sbi->sb->s_dev); | ||
209 | } | ||
210 | |||
211 | static inline u64 autofs4_get_ino(struct autofs_sb_info *sbi) | ||
212 | { | ||
213 | return sbi->sb->s_root->d_inode->i_ino; | ||
214 | } | ||
215 | |||
203 | static inline int simple_positive(struct dentry *dentry) | 216 | static inline int simple_positive(struct dentry *dentry) |
204 | { | 217 | { |
205 | return dentry->d_inode && !d_unhashed(dentry); | 218 | return dentry->d_inode && !d_unhashed(dentry); |
206 | } | 219 | } |
207 | 220 | ||
208 | static inline int simple_empty_nolock(struct dentry *dentry) | 221 | static inline int __simple_empty(struct dentry *dentry) |
209 | { | 222 | { |
210 | struct dentry *child; | 223 | struct dentry *child; |
211 | int ret = 0; | 224 | int ret = 0; |
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index dc39589df165..b8ce02607d66 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * | 4 | * |
5 | * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved | 5 | * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved |
6 | * Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org> | 6 | * Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org> |
7 | * Copyright 2001-2003 Ian Kent <raven@themaw.net> | 7 | * Copyright 2001-2006 Ian Kent <raven@themaw.net> |
8 | * | 8 | * |
9 | * This file is part of the Linux kernel and is made available under | 9 | * This file is part of the Linux kernel and is made available under |
10 | * the terms of the GNU General Public License, version 2, or at your | 10 | * the terms of the GNU General Public License, version 2, or at your |
@@ -16,7 +16,7 @@ | |||
16 | 16 | ||
17 | static unsigned long now; | 17 | static unsigned long now; |
18 | 18 | ||
19 | /* Check if a dentry can be expired return 1 if it can else return 0 */ | 19 | /* Check if a dentry can be expired */ |
20 | static inline int autofs4_can_expire(struct dentry *dentry, | 20 | static inline int autofs4_can_expire(struct dentry *dentry, |
21 | unsigned long timeout, int do_now) | 21 | unsigned long timeout, int do_now) |
22 | { | 22 | { |
@@ -41,14 +41,14 @@ static inline int autofs4_can_expire(struct dentry *dentry, | |||
41 | attempts if expire fails the first time */ | 41 | attempts if expire fails the first time */ |
42 | ino->last_used = now; | 42 | ino->last_used = now; |
43 | } | 43 | } |
44 | |||
45 | return 1; | 44 | return 1; |
46 | } | 45 | } |
47 | 46 | ||
48 | /* Check a mount point for busyness return 1 if not busy, otherwise */ | 47 | /* Check a mount point for busyness */ |
49 | static int autofs4_check_mount(struct vfsmount *mnt, struct dentry *dentry) | 48 | static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry) |
50 | { | 49 | { |
51 | int status = 0; | 50 | struct dentry *top = dentry; |
51 | int status = 1; | ||
52 | 52 | ||
53 | DPRINTK("dentry %p %.*s", | 53 | DPRINTK("dentry %p %.*s", |
54 | dentry, (int)dentry->d_name.len, dentry->d_name.name); | 54 | dentry, (int)dentry->d_name.len, dentry->d_name.name); |
@@ -63,9 +63,14 @@ static int autofs4_check_mount(struct vfsmount *mnt, struct dentry *dentry) | |||
63 | if (is_autofs4_dentry(dentry)) | 63 | if (is_autofs4_dentry(dentry)) |
64 | goto done; | 64 | goto done; |
65 | 65 | ||
66 | /* The big question */ | 66 | /* Update the expiry counter if fs is busy */ |
67 | if (may_umount_tree(mnt) == 0) | 67 | if (!may_umount_tree(mnt)) { |
68 | status = 1; | 68 | struct autofs_info *ino = autofs4_dentry_ino(top); |
69 | ino->last_used = jiffies; | ||
70 | goto done; | ||
71 | } | ||
72 | |||
73 | status = 0; | ||
69 | done: | 74 | done: |
70 | DPRINTK("returning = %d", status); | 75 | DPRINTK("returning = %d", status); |
71 | mntput(mnt); | 76 | mntput(mnt); |
@@ -73,78 +78,124 @@ done: | |||
73 | return status; | 78 | return status; |
74 | } | 79 | } |
75 | 80 | ||
81 | /* | ||
82 | * Calculate next entry in top down tree traversal. | ||
83 | * From next_mnt in namespace.c - elegant. | ||
84 | */ | ||
85 | static struct dentry *next_dentry(struct dentry *p, struct dentry *root) | ||
86 | { | ||
87 | struct list_head *next = p->d_subdirs.next; | ||
88 | |||
89 | if (next == &p->d_subdirs) { | ||
90 | while (1) { | ||
91 | if (p == root) | ||
92 | return NULL; | ||
93 | next = p->d_u.d_child.next; | ||
94 | if (next != &p->d_parent->d_subdirs) | ||
95 | break; | ||
96 | p = p->d_parent; | ||
97 | } | ||
98 | } | ||
99 | return list_entry(next, struct dentry, d_u.d_child); | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * Check a direct mount point for busyness. | ||
104 | * Direct mounts have similar expiry semantics to tree mounts. | ||
105 | * The tree is not busy iff no mountpoints are busy and there are no | ||
106 | * autofs submounts. | ||
107 | */ | ||
108 | static int autofs4_direct_busy(struct vfsmount *mnt, | ||
109 | struct dentry *top, | ||
110 | unsigned long timeout, | ||
111 | int do_now) | ||
112 | { | ||
113 | DPRINTK("top %p %.*s", | ||
114 | top, (int) top->d_name.len, top->d_name.name); | ||
115 | |||
116 | /* If it's busy update the expiry counters */ | ||
117 | if (!may_umount_tree(mnt)) { | ||
118 | struct autofs_info *ino = autofs4_dentry_ino(top); | ||
119 | if (ino) | ||
120 | ino->last_used = jiffies; | ||
121 | return 1; | ||
122 | } | ||
123 | |||
124 | /* Timeout of a direct mount is determined by its top dentry */ | ||
125 | if (!autofs4_can_expire(top, timeout, do_now)) | ||
126 | return 1; | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
76 | /* Check a directory tree of mount points for busyness | 131 | /* Check a directory tree of mount points for busyness |
77 | * The tree is not busy iff no mountpoints are busy | 132 | * The tree is not busy iff no mountpoints are busy |
78 | * Return 1 if the tree is busy or 0 otherwise | ||
79 | */ | 133 | */ |
80 | static int autofs4_check_tree(struct vfsmount *mnt, | 134 | static int autofs4_tree_busy(struct vfsmount *mnt, |
81 | struct dentry *top, | 135 | struct dentry *top, |
82 | unsigned long timeout, | 136 | unsigned long timeout, |
83 | int do_now) | 137 | int do_now) |
84 | { | 138 | { |
85 | struct dentry *this_parent = top; | 139 | struct autofs_info *top_ino = autofs4_dentry_ino(top); |
86 | struct list_head *next; | 140 | struct dentry *p; |
87 | 141 | ||
88 | DPRINTK("parent %p %.*s", | 142 | DPRINTK("top %p %.*s", |
89 | top, (int)top->d_name.len, top->d_name.name); | 143 | top, (int)top->d_name.len, top->d_name.name); |
90 | 144 | ||
91 | /* Negative dentry - give up */ | 145 | /* Negative dentry - give up */ |
92 | if (!simple_positive(top)) | 146 | if (!simple_positive(top)) |
93 | return 0; | 147 | return 1; |
94 | |||
95 | /* Timeout of a tree mount is determined by its top dentry */ | ||
96 | if (!autofs4_can_expire(top, timeout, do_now)) | ||
97 | return 0; | ||
98 | |||
99 | /* Is someone visiting anywhere in the tree ? */ | ||
100 | if (may_umount_tree(mnt)) | ||
101 | return 0; | ||
102 | 148 | ||
103 | spin_lock(&dcache_lock); | 149 | spin_lock(&dcache_lock); |
104 | repeat: | 150 | for (p = top; p; p = next_dentry(p, top)) { |
105 | next = this_parent->d_subdirs.next; | ||
106 | resume: | ||
107 | while (next != &this_parent->d_subdirs) { | ||
108 | struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); | ||
109 | |||
110 | /* Negative dentry - give up */ | 151 | /* Negative dentry - give up */ |
111 | if (!simple_positive(dentry)) { | 152 | if (!simple_positive(p)) |
112 | next = next->next; | ||
113 | continue; | 153 | continue; |
114 | } | ||
115 | 154 | ||
116 | DPRINTK("dentry %p %.*s", | 155 | DPRINTK("dentry %p %.*s", |
117 | dentry, (int)dentry->d_name.len, dentry->d_name.name); | 156 | p, (int) p->d_name.len, p->d_name.name); |
118 | |||
119 | if (!simple_empty_nolock(dentry)) { | ||
120 | this_parent = dentry; | ||
121 | goto repeat; | ||
122 | } | ||
123 | 157 | ||
124 | dentry = dget(dentry); | 158 | p = dget(p); |
125 | spin_unlock(&dcache_lock); | 159 | spin_unlock(&dcache_lock); |
126 | 160 | ||
127 | if (d_mountpoint(dentry)) { | 161 | /* |
128 | /* First busy => tree busy */ | 162 | * Is someone visiting anywhere in the subtree ? |
129 | if (!autofs4_check_mount(mnt, dentry)) { | 163 | * If there's no mount we need to check the usage |
130 | dput(dentry); | 164 | * count for the autofs dentry. |
131 | return 0; | 165 | * If the fs is busy update the expiry counter. |
166 | */ | ||
167 | if (d_mountpoint(p)) { | ||
168 | if (autofs4_mount_busy(mnt, p)) { | ||
169 | top_ino->last_used = jiffies; | ||
170 | dput(p); | ||
171 | return 1; | ||
172 | } | ||
173 | } else { | ||
174 | struct autofs_info *ino = autofs4_dentry_ino(p); | ||
175 | unsigned int ino_count = atomic_read(&ino->count); | ||
176 | |||
177 | /* allow for dget above and top is already dgot */ | ||
178 | if (p == top) | ||
179 | ino_count += 2; | ||
180 | else | ||
181 | ino_count++; | ||
182 | |||
183 | if (atomic_read(&p->d_count) > ino_count) { | ||
184 | top_ino->last_used = jiffies; | ||
185 | dput(p); | ||
186 | return 1; | ||
132 | } | 187 | } |
133 | } | 188 | } |
134 | 189 | dput(p); | |
135 | dput(dentry); | ||
136 | spin_lock(&dcache_lock); | 190 | spin_lock(&dcache_lock); |
137 | next = next->next; | ||
138 | } | ||
139 | |||
140 | if (this_parent != top) { | ||
141 | next = this_parent->d_u.d_child.next; | ||
142 | this_parent = this_parent->d_parent; | ||
143 | goto resume; | ||
144 | } | 191 | } |
145 | spin_unlock(&dcache_lock); | 192 | spin_unlock(&dcache_lock); |
146 | 193 | ||
147 | return 1; | 194 | /* Timeout of a tree mount is ultimately determined by its top dentry */ |
195 | if (!autofs4_can_expire(top, timeout, do_now)) | ||
196 | return 1; | ||
197 | |||
198 | return 0; | ||
148 | } | 199 | } |
149 | 200 | ||
150 | static struct dentry *autofs4_check_leaves(struct vfsmount *mnt, | 201 | static struct dentry *autofs4_check_leaves(struct vfsmount *mnt, |
@@ -152,58 +203,68 @@ static struct dentry *autofs4_check_leaves(struct vfsmount *mnt, | |||
152 | unsigned long timeout, | 203 | unsigned long timeout, |
153 | int do_now) | 204 | int do_now) |
154 | { | 205 | { |
155 | struct dentry *this_parent = parent; | 206 | struct dentry *p; |
156 | struct list_head *next; | ||
157 | 207 | ||
158 | DPRINTK("parent %p %.*s", | 208 | DPRINTK("parent %p %.*s", |
159 | parent, (int)parent->d_name.len, parent->d_name.name); | 209 | parent, (int)parent->d_name.len, parent->d_name.name); |
160 | 210 | ||
161 | spin_lock(&dcache_lock); | 211 | spin_lock(&dcache_lock); |
162 | repeat: | 212 | for (p = parent; p; p = next_dentry(p, parent)) { |
163 | next = this_parent->d_subdirs.next; | ||
164 | resume: | ||
165 | while (next != &this_parent->d_subdirs) { | ||
166 | struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); | ||
167 | |||
168 | /* Negative dentry - give up */ | 213 | /* Negative dentry - give up */ |
169 | if (!simple_positive(dentry)) { | 214 | if (!simple_positive(p)) |
170 | next = next->next; | ||
171 | continue; | 215 | continue; |
172 | } | ||
173 | 216 | ||
174 | DPRINTK("dentry %p %.*s", | 217 | DPRINTK("dentry %p %.*s", |
175 | dentry, (int)dentry->d_name.len, dentry->d_name.name); | 218 | p, (int) p->d_name.len, p->d_name.name); |
176 | |||
177 | if (!list_empty(&dentry->d_subdirs)) { | ||
178 | this_parent = dentry; | ||
179 | goto repeat; | ||
180 | } | ||
181 | 219 | ||
182 | dentry = dget(dentry); | 220 | p = dget(p); |
183 | spin_unlock(&dcache_lock); | 221 | spin_unlock(&dcache_lock); |
184 | 222 | ||
185 | if (d_mountpoint(dentry)) { | 223 | if (d_mountpoint(p)) { |
186 | /* Can we expire this guy */ | ||
187 | if (!autofs4_can_expire(dentry, timeout, do_now)) | ||
188 | goto cont; | ||
189 | |||
190 | /* Can we umount this guy */ | 224 | /* Can we umount this guy */ |
191 | if (autofs4_check_mount(mnt, dentry)) | 225 | if (autofs4_mount_busy(mnt, p)) |
192 | return dentry; | 226 | goto cont; |
193 | 227 | ||
228 | /* Can we expire this guy */ | ||
229 | if (autofs4_can_expire(p, timeout, do_now)) | ||
230 | return p; | ||
194 | } | 231 | } |
195 | cont: | 232 | cont: |
196 | dput(dentry); | 233 | dput(p); |
197 | spin_lock(&dcache_lock); | 234 | spin_lock(&dcache_lock); |
198 | next = next->next; | ||
199 | } | 235 | } |
236 | spin_unlock(&dcache_lock); | ||
237 | return NULL; | ||
238 | } | ||
239 | |||
240 | /* Check if we can expire a direct mount (possibly a tree) */ | ||
241 | static struct dentry *autofs4_expire_direct(struct super_block *sb, | ||
242 | struct vfsmount *mnt, | ||
243 | struct autofs_sb_info *sbi, | ||
244 | int how) | ||
245 | { | ||
246 | unsigned long timeout; | ||
247 | struct dentry *root = dget(sb->s_root); | ||
248 | int do_now = how & AUTOFS_EXP_IMMEDIATE; | ||
249 | |||
250 | if (!sbi->exp_timeout || !root) | ||
251 | return NULL; | ||
252 | |||
253 | now = jiffies; | ||
254 | timeout = sbi->exp_timeout; | ||
255 | |||
256 | /* Lock the tree as we must expire as a whole */ | ||
257 | spin_lock(&sbi->fs_lock); | ||
258 | if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { | ||
259 | struct autofs_info *ino = autofs4_dentry_ino(root); | ||
200 | 260 | ||
201 | if (this_parent != parent) { | 261 | /* Set this flag early to catch sys_chdir and the like */ |
202 | next = this_parent->d_u.d_child.next; | 262 | ino->flags |= AUTOFS_INF_EXPIRING; |
203 | this_parent = this_parent->d_parent; | 263 | spin_unlock(&sbi->fs_lock); |
204 | goto resume; | 264 | return root; |
205 | } | 265 | } |
206 | spin_unlock(&dcache_lock); | 266 | spin_unlock(&sbi->fs_lock); |
267 | dput(root); | ||
207 | 268 | ||
208 | return NULL; | 269 | return NULL; |
209 | } | 270 | } |
@@ -214,10 +275,10 @@ cont: | |||
214 | * - it is unused by any user process | 275 | * - it is unused by any user process |
215 | * - it has been unused for exp_timeout time | 276 | * - it has been unused for exp_timeout time |
216 | */ | 277 | */ |
217 | static struct dentry *autofs4_expire(struct super_block *sb, | 278 | static struct dentry *autofs4_expire_indirect(struct super_block *sb, |
218 | struct vfsmount *mnt, | 279 | struct vfsmount *mnt, |
219 | struct autofs_sb_info *sbi, | 280 | struct autofs_sb_info *sbi, |
220 | int how) | 281 | int how) |
221 | { | 282 | { |
222 | unsigned long timeout; | 283 | unsigned long timeout; |
223 | struct dentry *root = sb->s_root; | 284 | struct dentry *root = sb->s_root; |
@@ -241,7 +302,7 @@ static struct dentry *autofs4_expire(struct super_block *sb, | |||
241 | struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); | 302 | struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); |
242 | 303 | ||
243 | /* Negative dentry - give up */ | 304 | /* Negative dentry - give up */ |
244 | if ( !simple_positive(dentry) ) { | 305 | if (!simple_positive(dentry)) { |
245 | next = next->next; | 306 | next = next->next; |
246 | continue; | 307 | continue; |
247 | } | 308 | } |
@@ -249,31 +310,36 @@ static struct dentry *autofs4_expire(struct super_block *sb, | |||
249 | dentry = dget(dentry); | 310 | dentry = dget(dentry); |
250 | spin_unlock(&dcache_lock); | 311 | spin_unlock(&dcache_lock); |
251 | 312 | ||
252 | /* Case 1: indirect mount or top level direct mount */ | 313 | /* |
314 | * Case 1: (i) indirect mount or top level pseudo direct mount | ||
315 | * (autofs-4.1). | ||
316 | * (ii) indirect mount with offset mount, check the "/" | ||
317 | * offset (autofs-5.0+). | ||
318 | */ | ||
253 | if (d_mountpoint(dentry)) { | 319 | if (d_mountpoint(dentry)) { |
254 | DPRINTK("checking mountpoint %p %.*s", | 320 | DPRINTK("checking mountpoint %p %.*s", |
255 | dentry, (int)dentry->d_name.len, dentry->d_name.name); | 321 | dentry, (int)dentry->d_name.len, dentry->d_name.name); |
256 | 322 | ||
257 | /* Can we expire this guy */ | 323 | /* Can we umount this guy */ |
258 | if (!autofs4_can_expire(dentry, timeout, do_now)) | 324 | if (autofs4_mount_busy(mnt, dentry)) |
259 | goto next; | 325 | goto next; |
260 | 326 | ||
261 | /* Can we umount this guy */ | 327 | /* Can we expire this guy */ |
262 | if (autofs4_check_mount(mnt, dentry)) { | 328 | if (autofs4_can_expire(dentry, timeout, do_now)) { |
263 | expired = dentry; | 329 | expired = dentry; |
264 | break; | 330 | break; |
265 | } | 331 | } |
266 | goto next; | 332 | goto next; |
267 | } | 333 | } |
268 | 334 | ||
269 | if ( simple_empty(dentry) ) | 335 | if (simple_empty(dentry)) |
270 | goto next; | 336 | goto next; |
271 | 337 | ||
272 | /* Case 2: tree mount, expire iff entire tree is not busy */ | 338 | /* Case 2: tree mount, expire iff entire tree is not busy */ |
273 | if (!exp_leaves) { | 339 | if (!exp_leaves) { |
274 | /* Lock the tree as we must expire as a whole */ | 340 | /* Lock the tree as we must expire as a whole */ |
275 | spin_lock(&sbi->fs_lock); | 341 | spin_lock(&sbi->fs_lock); |
276 | if (autofs4_check_tree(mnt, dentry, timeout, do_now)) { | 342 | if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { |
277 | struct autofs_info *inf = autofs4_dentry_ino(dentry); | 343 | struct autofs_info *inf = autofs4_dentry_ino(dentry); |
278 | 344 | ||
279 | /* Set this flag early to catch sys_chdir and the like */ | 345 | /* Set this flag early to catch sys_chdir and the like */ |
@@ -283,7 +349,10 @@ static struct dentry *autofs4_expire(struct super_block *sb, | |||
283 | break; | 349 | break; |
284 | } | 350 | } |
285 | spin_unlock(&sbi->fs_lock); | 351 | spin_unlock(&sbi->fs_lock); |
286 | /* Case 3: direct mount, expire individual leaves */ | 352 | /* |
353 | * Case 3: pseudo direct mount, expire individual leaves | ||
354 | * (autofs-4.1). | ||
355 | */ | ||
287 | } else { | 356 | } else { |
288 | expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); | 357 | expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); |
289 | if (expired) { | 358 | if (expired) { |
@@ -297,7 +366,7 @@ next: | |||
297 | next = next->next; | 366 | next = next->next; |
298 | } | 367 | } |
299 | 368 | ||
300 | if ( expired ) { | 369 | if (expired) { |
301 | DPRINTK("returning %p %.*s", | 370 | DPRINTK("returning %p %.*s", |
302 | expired, (int)expired->d_name.len, expired->d_name.name); | 371 | expired, (int)expired->d_name.len, expired->d_name.name); |
303 | spin_lock(&dcache_lock); | 372 | spin_lock(&dcache_lock); |
@@ -325,7 +394,7 @@ int autofs4_expire_run(struct super_block *sb, | |||
325 | pkt.hdr.proto_version = sbi->version; | 394 | pkt.hdr.proto_version = sbi->version; |
326 | pkt.hdr.type = autofs_ptype_expire; | 395 | pkt.hdr.type = autofs_ptype_expire; |
327 | 396 | ||
328 | if ((dentry = autofs4_expire(sb, mnt, sbi, 0)) == NULL) | 397 | if ((dentry = autofs4_expire_indirect(sb, mnt, sbi, 0)) == NULL) |
329 | return -EAGAIN; | 398 | return -EAGAIN; |
330 | 399 | ||
331 | pkt.len = dentry->d_name.len; | 400 | pkt.len = dentry->d_name.len; |
@@ -351,17 +420,22 @@ int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt, | |||
351 | if (arg && get_user(do_now, arg)) | 420 | if (arg && get_user(do_now, arg)) |
352 | return -EFAULT; | 421 | return -EFAULT; |
353 | 422 | ||
354 | if ((dentry = autofs4_expire(sb, mnt, sbi, do_now)) != NULL) { | 423 | if (sbi->type & AUTOFS_TYPE_DIRECT) |
355 | struct autofs_info *de_info = autofs4_dentry_ino(dentry); | 424 | dentry = autofs4_expire_direct(sb, mnt, sbi, do_now); |
425 | else | ||
426 | dentry = autofs4_expire_indirect(sb, mnt, sbi, do_now); | ||
427 | |||
428 | if (dentry) { | ||
429 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
356 | 430 | ||
357 | /* This is synchronous because it makes the daemon a | 431 | /* This is synchronous because it makes the daemon a |
358 | little easier */ | 432 | little easier */ |
359 | de_info->flags |= AUTOFS_INF_EXPIRING; | 433 | ino->flags |= AUTOFS_INF_EXPIRING; |
360 | ret = autofs4_wait(sbi, dentry, NFY_EXPIRE); | 434 | ret = autofs4_wait(sbi, dentry, NFY_EXPIRE); |
361 | de_info->flags &= ~AUTOFS_INF_EXPIRING; | 435 | ino->flags &= ~AUTOFS_INF_EXPIRING; |
362 | dput(dentry); | 436 | dput(dentry); |
363 | } | 437 | } |
364 | 438 | ||
365 | return ret; | 439 | return ret; |
366 | } | 440 | } |
367 | 441 | ||
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 1ad98d48e550..4eddee4e76fc 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * linux/fs/autofs/inode.c | 3 | * linux/fs/autofs/inode.c |
4 | * | 4 | * |
5 | * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved | 5 | * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved |
6 | * Copyright 2005-2006 Ian Kent <raven@themaw.net> | ||
6 | * | 7 | * |
7 | * This file is part of the Linux kernel and is made available under | 8 | * This file is part of the Linux kernel and is made available under |
8 | * the terms of the GNU General Public License, version 2, or at your | 9 | * the terms of the GNU General Public License, version 2, or at your |
@@ -13,6 +14,7 @@ | |||
13 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
14 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
15 | #include <linux/file.h> | 16 | #include <linux/file.h> |
17 | #include <linux/seq_file.h> | ||
16 | #include <linux/pagemap.h> | 18 | #include <linux/pagemap.h> |
17 | #include <linux/parser.h> | 19 | #include <linux/parser.h> |
18 | #include <linux/bitops.h> | 20 | #include <linux/bitops.h> |
@@ -46,6 +48,7 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino, | |||
46 | ino->size = 0; | 48 | ino->size = 0; |
47 | 49 | ||
48 | ino->last_used = jiffies; | 50 | ino->last_used = jiffies; |
51 | atomic_set(&ino->count, 0); | ||
49 | 52 | ||
50 | ino->sbi = sbi; | 53 | ino->sbi = sbi; |
51 | 54 | ||
@@ -64,10 +67,19 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino, | |||
64 | 67 | ||
65 | void autofs4_free_ino(struct autofs_info *ino) | 68 | void autofs4_free_ino(struct autofs_info *ino) |
66 | { | 69 | { |
70 | struct autofs_info *p_ino; | ||
71 | |||
67 | if (ino->dentry) { | 72 | if (ino->dentry) { |
68 | ino->dentry->d_fsdata = NULL; | 73 | ino->dentry->d_fsdata = NULL; |
69 | if (ino->dentry->d_inode) | 74 | if (ino->dentry->d_inode) { |
75 | struct dentry *parent = ino->dentry->d_parent; | ||
76 | if (atomic_dec_and_test(&ino->count)) { | ||
77 | p_ino = autofs4_dentry_ino(parent); | ||
78 | if (p_ino && parent != ino->dentry) | ||
79 | atomic_dec(&p_ino->count); | ||
80 | } | ||
70 | dput(ino->dentry); | 81 | dput(ino->dentry); |
82 | } | ||
71 | ino->dentry = NULL; | 83 | ino->dentry = NULL; |
72 | } | 84 | } |
73 | if (ino->free) | 85 | if (ino->free) |
@@ -145,20 +157,44 @@ static void autofs4_put_super(struct super_block *sb) | |||
145 | autofs4_catatonic_mode(sbi); /* Free wait queues, close pipe */ | 157 | autofs4_catatonic_mode(sbi); /* Free wait queues, close pipe */ |
146 | 158 | ||
147 | /* Clean up and release dangling references */ | 159 | /* Clean up and release dangling references */ |
148 | if (sbi) | 160 | autofs4_force_release(sbi); |
149 | autofs4_force_release(sbi); | ||
150 | 161 | ||
151 | kfree(sbi); | 162 | kfree(sbi); |
152 | 163 | ||
153 | DPRINTK("shutting down"); | 164 | DPRINTK("shutting down"); |
154 | } | 165 | } |
155 | 166 | ||
167 | static int autofs4_show_options(struct seq_file *m, struct vfsmount *mnt) | ||
168 | { | ||
169 | struct autofs_sb_info *sbi = autofs4_sbi(mnt->mnt_sb); | ||
170 | |||
171 | if (!sbi) | ||
172 | return 0; | ||
173 | |||
174 | seq_printf(m, ",fd=%d", sbi->pipefd); | ||
175 | seq_printf(m, ",pgrp=%d", sbi->oz_pgrp); | ||
176 | seq_printf(m, ",timeout=%lu", sbi->exp_timeout/HZ); | ||
177 | seq_printf(m, ",minproto=%d", sbi->min_proto); | ||
178 | seq_printf(m, ",maxproto=%d", sbi->max_proto); | ||
179 | |||
180 | if (sbi->type & AUTOFS_TYPE_OFFSET) | ||
181 | seq_printf(m, ",offset"); | ||
182 | else if (sbi->type & AUTOFS_TYPE_DIRECT) | ||
183 | seq_printf(m, ",direct"); | ||
184 | else | ||
185 | seq_printf(m, ",indirect"); | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
156 | static struct super_operations autofs4_sops = { | 190 | static struct super_operations autofs4_sops = { |
157 | .put_super = autofs4_put_super, | 191 | .put_super = autofs4_put_super, |
158 | .statfs = simple_statfs, | 192 | .statfs = simple_statfs, |
193 | .show_options = autofs4_show_options, | ||
159 | }; | 194 | }; |
160 | 195 | ||
161 | enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto}; | 196 | enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto, |
197 | Opt_indirect, Opt_direct, Opt_offset}; | ||
162 | 198 | ||
163 | static match_table_t tokens = { | 199 | static match_table_t tokens = { |
164 | {Opt_fd, "fd=%u"}, | 200 | {Opt_fd, "fd=%u"}, |
@@ -167,11 +203,15 @@ static match_table_t tokens = { | |||
167 | {Opt_pgrp, "pgrp=%u"}, | 203 | {Opt_pgrp, "pgrp=%u"}, |
168 | {Opt_minproto, "minproto=%u"}, | 204 | {Opt_minproto, "minproto=%u"}, |
169 | {Opt_maxproto, "maxproto=%u"}, | 205 | {Opt_maxproto, "maxproto=%u"}, |
206 | {Opt_indirect, "indirect"}, | ||
207 | {Opt_direct, "direct"}, | ||
208 | {Opt_offset, "offset"}, | ||
170 | {Opt_err, NULL} | 209 | {Opt_err, NULL} |
171 | }; | 210 | }; |
172 | 211 | ||
173 | static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, | 212 | static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, |
174 | pid_t *pgrp, int *minproto, int *maxproto) | 213 | pid_t *pgrp, unsigned int *type, |
214 | int *minproto, int *maxproto) | ||
175 | { | 215 | { |
176 | char *p; | 216 | char *p; |
177 | substring_t args[MAX_OPT_ARGS]; | 217 | substring_t args[MAX_OPT_ARGS]; |
@@ -225,6 +265,15 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, | |||
225 | return 1; | 265 | return 1; |
226 | *maxproto = option; | 266 | *maxproto = option; |
227 | break; | 267 | break; |
268 | case Opt_indirect: | ||
269 | *type = AUTOFS_TYPE_INDIRECT; | ||
270 | break; | ||
271 | case Opt_direct: | ||
272 | *type = AUTOFS_TYPE_DIRECT; | ||
273 | break; | ||
274 | case Opt_offset: | ||
275 | *type = AUTOFS_TYPE_DIRECT | AUTOFS_TYPE_OFFSET; | ||
276 | break; | ||
228 | default: | 277 | default: |
229 | return 1; | 278 | return 1; |
230 | } | 279 | } |
@@ -243,6 +292,11 @@ static struct autofs_info *autofs4_mkroot(struct autofs_sb_info *sbi) | |||
243 | return ino; | 292 | return ino; |
244 | } | 293 | } |
245 | 294 | ||
295 | void autofs4_dentry_release(struct dentry *); | ||
296 | static struct dentry_operations autofs4_sb_dentry_operations = { | ||
297 | .d_release = autofs4_dentry_release, | ||
298 | }; | ||
299 | |||
246 | int autofs4_fill_super(struct super_block *s, void *data, int silent) | 300 | int autofs4_fill_super(struct super_block *s, void *data, int silent) |
247 | { | 301 | { |
248 | struct inode * root_inode; | 302 | struct inode * root_inode; |
@@ -251,7 +305,6 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) | |||
251 | int pipefd; | 305 | int pipefd; |
252 | struct autofs_sb_info *sbi; | 306 | struct autofs_sb_info *sbi; |
253 | struct autofs_info *ino; | 307 | struct autofs_info *ino; |
254 | int minproto, maxproto; | ||
255 | 308 | ||
256 | sbi = (struct autofs_sb_info *) kmalloc(sizeof(*sbi), GFP_KERNEL); | 309 | sbi = (struct autofs_sb_info *) kmalloc(sizeof(*sbi), GFP_KERNEL); |
257 | if ( !sbi ) | 310 | if ( !sbi ) |
@@ -263,12 +316,16 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) | |||
263 | s->s_fs_info = sbi; | 316 | s->s_fs_info = sbi; |
264 | sbi->magic = AUTOFS_SBI_MAGIC; | 317 | sbi->magic = AUTOFS_SBI_MAGIC; |
265 | sbi->root = NULL; | 318 | sbi->root = NULL; |
319 | sbi->pipefd = -1; | ||
266 | sbi->catatonic = 0; | 320 | sbi->catatonic = 0; |
267 | sbi->exp_timeout = 0; | 321 | sbi->exp_timeout = 0; |
268 | sbi->oz_pgrp = process_group(current); | 322 | sbi->oz_pgrp = process_group(current); |
269 | sbi->sb = s; | 323 | sbi->sb = s; |
270 | sbi->version = 0; | 324 | sbi->version = 0; |
271 | sbi->sub_version = 0; | 325 | sbi->sub_version = 0; |
326 | sbi->type = 0; | ||
327 | sbi->min_proto = 0; | ||
328 | sbi->max_proto = 0; | ||
272 | mutex_init(&sbi->wq_mutex); | 329 | mutex_init(&sbi->wq_mutex); |
273 | spin_lock_init(&sbi->fs_lock); | 330 | spin_lock_init(&sbi->fs_lock); |
274 | sbi->queues = NULL; | 331 | sbi->queues = NULL; |
@@ -285,38 +342,46 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) | |||
285 | if (!ino) | 342 | if (!ino) |
286 | goto fail_free; | 343 | goto fail_free; |
287 | root_inode = autofs4_get_inode(s, ino); | 344 | root_inode = autofs4_get_inode(s, ino); |
288 | kfree(ino); | ||
289 | if (!root_inode) | 345 | if (!root_inode) |
290 | goto fail_free; | 346 | goto fail_ino; |
291 | 347 | ||
292 | root_inode->i_op = &autofs4_root_inode_operations; | ||
293 | root_inode->i_fop = &autofs4_root_operations; | ||
294 | root = d_alloc_root(root_inode); | 348 | root = d_alloc_root(root_inode); |
295 | pipe = NULL; | ||
296 | |||
297 | if (!root) | 349 | if (!root) |
298 | goto fail_iput; | 350 | goto fail_iput; |
351 | pipe = NULL; | ||
352 | |||
353 | root->d_op = &autofs4_sb_dentry_operations; | ||
354 | root->d_fsdata = ino; | ||
299 | 355 | ||
300 | /* Can this call block? */ | 356 | /* Can this call block? */ |
301 | if (parse_options(data, &pipefd, | 357 | if (parse_options(data, &pipefd, |
302 | &root_inode->i_uid, &root_inode->i_gid, | 358 | &root_inode->i_uid, &root_inode->i_gid, |
303 | &sbi->oz_pgrp, | 359 | &sbi->oz_pgrp, &sbi->type, |
304 | &minproto, &maxproto)) { | 360 | &sbi->min_proto, &sbi->max_proto)) { |
305 | printk("autofs: called with bogus options\n"); | 361 | printk("autofs: called with bogus options\n"); |
306 | goto fail_dput; | 362 | goto fail_dput; |
307 | } | 363 | } |
308 | 364 | ||
365 | root_inode->i_fop = &autofs4_root_operations; | ||
366 | root_inode->i_op = sbi->type & AUTOFS_TYPE_DIRECT ? | ||
367 | &autofs4_direct_root_inode_operations : | ||
368 | &autofs4_indirect_root_inode_operations; | ||
369 | |||
309 | /* Couldn't this be tested earlier? */ | 370 | /* Couldn't this be tested earlier? */ |
310 | if (maxproto < AUTOFS_MIN_PROTO_VERSION || | 371 | if (sbi->max_proto < AUTOFS_MIN_PROTO_VERSION || |
311 | minproto > AUTOFS_MAX_PROTO_VERSION) { | 372 | sbi->min_proto > AUTOFS_MAX_PROTO_VERSION) { |
312 | printk("autofs: kernel does not match daemon version " | 373 | printk("autofs: kernel does not match daemon version " |
313 | "daemon (%d, %d) kernel (%d, %d)\n", | 374 | "daemon (%d, %d) kernel (%d, %d)\n", |
314 | minproto, maxproto, | 375 | sbi->min_proto, sbi->max_proto, |
315 | AUTOFS_MIN_PROTO_VERSION, AUTOFS_MAX_PROTO_VERSION); | 376 | AUTOFS_MIN_PROTO_VERSION, AUTOFS_MAX_PROTO_VERSION); |
316 | goto fail_dput; | 377 | goto fail_dput; |
317 | } | 378 | } |
318 | 379 | ||
319 | sbi->version = maxproto > AUTOFS_MAX_PROTO_VERSION ? AUTOFS_MAX_PROTO_VERSION : maxproto; | 380 | /* Establish highest kernel protocol version */ |
381 | if (sbi->max_proto > AUTOFS_MAX_PROTO_VERSION) | ||
382 | sbi->version = AUTOFS_MAX_PROTO_VERSION; | ||
383 | else | ||
384 | sbi->version = sbi->max_proto; | ||
320 | sbi->sub_version = AUTOFS_PROTO_SUBVERSION; | 385 | sbi->sub_version = AUTOFS_PROTO_SUBVERSION; |
321 | 386 | ||
322 | DPRINTK("pipe fd = %d, pgrp = %u", pipefd, sbi->oz_pgrp); | 387 | DPRINTK("pipe fd = %d, pgrp = %u", pipefd, sbi->oz_pgrp); |
@@ -329,6 +394,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) | |||
329 | if ( !pipe->f_op || !pipe->f_op->write ) | 394 | if ( !pipe->f_op || !pipe->f_op->write ) |
330 | goto fail_fput; | 395 | goto fail_fput; |
331 | sbi->pipe = pipe; | 396 | sbi->pipe = pipe; |
397 | sbi->pipefd = pipefd; | ||
332 | 398 | ||
333 | /* | 399 | /* |
334 | * Take a reference to the root dentry so we get a chance to | 400 | * Take a reference to the root dentry so we get a chance to |
@@ -356,6 +422,8 @@ fail_dput: | |||
356 | fail_iput: | 422 | fail_iput: |
357 | printk("autofs: get root dentry failed\n"); | 423 | printk("autofs: get root dentry failed\n"); |
358 | iput(root_inode); | 424 | iput(root_inode); |
425 | fail_ino: | ||
426 | kfree(ino); | ||
359 | fail_free: | 427 | fail_free: |
360 | kfree(sbi); | 428 | kfree(sbi); |
361 | fail_unlock: | 429 | fail_unlock: |
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 62d8d4acb8bb..c8fe43a475e2 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * | 4 | * |
5 | * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved | 5 | * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved |
6 | * Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org> | 6 | * Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org> |
7 | * Copyright 2001-2003 Ian Kent <raven@themaw.net> | 7 | * Copyright 2001-2006 Ian Kent <raven@themaw.net> |
8 | * | 8 | * |
9 | * This file is part of the Linux kernel and is made available under | 9 | * This file is part of the Linux kernel and is made available under |
10 | * the terms of the GNU General Public License, version 2, or at your | 10 | * the terms of the GNU General Public License, version 2, or at your |
@@ -30,7 +30,7 @@ static int autofs4_dir_close(struct inode *inode, struct file *file); | |||
30 | static int autofs4_dir_readdir(struct file * filp, void * dirent, filldir_t filldir); | 30 | static int autofs4_dir_readdir(struct file * filp, void * dirent, filldir_t filldir); |
31 | static int autofs4_root_readdir(struct file * filp, void * dirent, filldir_t filldir); | 31 | static int autofs4_root_readdir(struct file * filp, void * dirent, filldir_t filldir); |
32 | static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *); | 32 | static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *); |
33 | static int autofs4_dcache_readdir(struct file *, void *, filldir_t); | 33 | static void *autofs4_follow_link(struct dentry *, struct nameidata *); |
34 | 34 | ||
35 | struct file_operations autofs4_root_operations = { | 35 | struct file_operations autofs4_root_operations = { |
36 | .open = dcache_dir_open, | 36 | .open = dcache_dir_open, |
@@ -47,7 +47,7 @@ struct file_operations autofs4_dir_operations = { | |||
47 | .readdir = autofs4_dir_readdir, | 47 | .readdir = autofs4_dir_readdir, |
48 | }; | 48 | }; |
49 | 49 | ||
50 | struct inode_operations autofs4_root_inode_operations = { | 50 | struct inode_operations autofs4_indirect_root_inode_operations = { |
51 | .lookup = autofs4_lookup, | 51 | .lookup = autofs4_lookup, |
52 | .unlink = autofs4_dir_unlink, | 52 | .unlink = autofs4_dir_unlink, |
53 | .symlink = autofs4_dir_symlink, | 53 | .symlink = autofs4_dir_symlink, |
@@ -55,6 +55,14 @@ struct inode_operations autofs4_root_inode_operations = { | |||
55 | .rmdir = autofs4_dir_rmdir, | 55 | .rmdir = autofs4_dir_rmdir, |
56 | }; | 56 | }; |
57 | 57 | ||
58 | struct inode_operations autofs4_direct_root_inode_operations = { | ||
59 | .lookup = autofs4_lookup, | ||
60 | .unlink = autofs4_dir_unlink, | ||
61 | .mkdir = autofs4_dir_mkdir, | ||
62 | .rmdir = autofs4_dir_rmdir, | ||
63 | .follow_link = autofs4_follow_link, | ||
64 | }; | ||
65 | |||
58 | struct inode_operations autofs4_dir_inode_operations = { | 66 | struct inode_operations autofs4_dir_inode_operations = { |
59 | .lookup = autofs4_lookup, | 67 | .lookup = autofs4_lookup, |
60 | .unlink = autofs4_dir_unlink, | 68 | .unlink = autofs4_dir_unlink, |
@@ -82,87 +90,7 @@ static int autofs4_root_readdir(struct file *file, void *dirent, | |||
82 | 90 | ||
83 | DPRINTK("needs_reghost = %d", sbi->needs_reghost); | 91 | DPRINTK("needs_reghost = %d", sbi->needs_reghost); |
84 | 92 | ||
85 | return autofs4_dcache_readdir(file, dirent, filldir); | 93 | return dcache_readdir(file, dirent, filldir); |
86 | } | ||
87 | |||
88 | /* Update usage from here to top of tree, so that scan of | ||
89 | top-level directories will give a useful result */ | ||
90 | static void autofs4_update_usage(struct vfsmount *mnt, struct dentry *dentry) | ||
91 | { | ||
92 | struct dentry *top = dentry->d_sb->s_root; | ||
93 | |||
94 | spin_lock(&dcache_lock); | ||
95 | for(; dentry != top; dentry = dentry->d_parent) { | ||
96 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
97 | |||
98 | if (ino) { | ||
99 | touch_atime(mnt, dentry); | ||
100 | ino->last_used = jiffies; | ||
101 | } | ||
102 | } | ||
103 | spin_unlock(&dcache_lock); | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * From 2.4 kernel readdir.c | ||
108 | */ | ||
109 | static int autofs4_dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) | ||
110 | { | ||
111 | int i; | ||
112 | struct dentry *dentry = filp->f_dentry; | ||
113 | |||
114 | i = filp->f_pos; | ||
115 | switch (i) { | ||
116 | case 0: | ||
117 | if (filldir(dirent, ".", 1, i, dentry->d_inode->i_ino, DT_DIR) < 0) | ||
118 | break; | ||
119 | i++; | ||
120 | filp->f_pos++; | ||
121 | /* fallthrough */ | ||
122 | case 1: | ||
123 | if (filldir(dirent, "..", 2, i, dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) | ||
124 | break; | ||
125 | i++; | ||
126 | filp->f_pos++; | ||
127 | /* fallthrough */ | ||
128 | default: { | ||
129 | struct list_head *list; | ||
130 | int j = i-2; | ||
131 | |||
132 | spin_lock(&dcache_lock); | ||
133 | list = dentry->d_subdirs.next; | ||
134 | |||
135 | for (;;) { | ||
136 | if (list == &dentry->d_subdirs) { | ||
137 | spin_unlock(&dcache_lock); | ||
138 | return 0; | ||
139 | } | ||
140 | if (!j) | ||
141 | break; | ||
142 | j--; | ||
143 | list = list->next; | ||
144 | } | ||
145 | |||
146 | while(1) { | ||
147 | struct dentry *de = list_entry(list, | ||
148 | struct dentry, d_u.d_child); | ||
149 | |||
150 | if (!d_unhashed(de) && de->d_inode) { | ||
151 | spin_unlock(&dcache_lock); | ||
152 | if (filldir(dirent, de->d_name.name, de->d_name.len, filp->f_pos, de->d_inode->i_ino, DT_UNKNOWN) < 0) | ||
153 | break; | ||
154 | spin_lock(&dcache_lock); | ||
155 | } | ||
156 | filp->f_pos++; | ||
157 | list = list->next; | ||
158 | if (list != &dentry->d_subdirs) | ||
159 | continue; | ||
160 | spin_unlock(&dcache_lock); | ||
161 | break; | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | return 0; | ||
166 | } | 94 | } |
167 | 95 | ||
168 | static int autofs4_dir_open(struct inode *inode, struct file *file) | 96 | static int autofs4_dir_open(struct inode *inode, struct file *file) |
@@ -170,8 +98,16 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) | |||
170 | struct dentry *dentry = file->f_dentry; | 98 | struct dentry *dentry = file->f_dentry; |
171 | struct vfsmount *mnt = file->f_vfsmnt; | 99 | struct vfsmount *mnt = file->f_vfsmnt; |
172 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | 100 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); |
101 | struct dentry *cursor; | ||
173 | int status; | 102 | int status; |
174 | 103 | ||
104 | status = dcache_dir_open(inode, file); | ||
105 | if (status) | ||
106 | goto out; | ||
107 | |||
108 | cursor = file->private_data; | ||
109 | cursor->d_fsdata = NULL; | ||
110 | |||
175 | DPRINTK("file=%p dentry=%p %.*s", | 111 | DPRINTK("file=%p dentry=%p %.*s", |
176 | file, dentry, dentry->d_name.len, dentry->d_name.name); | 112 | file, dentry, dentry->d_name.len, dentry->d_name.name); |
177 | 113 | ||
@@ -180,12 +116,15 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) | |||
180 | 116 | ||
181 | if (autofs4_ispending(dentry)) { | 117 | if (autofs4_ispending(dentry)) { |
182 | DPRINTK("dentry busy"); | 118 | DPRINTK("dentry busy"); |
183 | return -EBUSY; | 119 | dcache_dir_close(inode, file); |
120 | status = -EBUSY; | ||
121 | goto out; | ||
184 | } | 122 | } |
185 | 123 | ||
124 | status = -ENOENT; | ||
186 | if (!d_mountpoint(dentry) && dentry->d_op && dentry->d_op->d_revalidate) { | 125 | if (!d_mountpoint(dentry) && dentry->d_op && dentry->d_op->d_revalidate) { |
187 | struct nameidata nd; | 126 | struct nameidata nd; |
188 | int empty; | 127 | int empty, ret; |
189 | 128 | ||
190 | /* In case there are stale directory dentrys from a failed mount */ | 129 | /* In case there are stale directory dentrys from a failed mount */ |
191 | spin_lock(&dcache_lock); | 130 | spin_lock(&dcache_lock); |
@@ -195,13 +134,13 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) | |||
195 | if (!empty) | 134 | if (!empty) |
196 | d_invalidate(dentry); | 135 | d_invalidate(dentry); |
197 | 136 | ||
198 | nd.dentry = dentry; | ||
199 | nd.mnt = mnt; | ||
200 | nd.flags = LOOKUP_DIRECTORY; | 137 | nd.flags = LOOKUP_DIRECTORY; |
201 | status = (dentry->d_op->d_revalidate)(dentry, &nd); | 138 | ret = (dentry->d_op->d_revalidate)(dentry, &nd); |
202 | 139 | ||
203 | if (!status) | 140 | if (!ret) { |
204 | return -ENOENT; | 141 | dcache_dir_close(inode, file); |
142 | goto out; | ||
143 | } | ||
205 | } | 144 | } |
206 | 145 | ||
207 | if (d_mountpoint(dentry)) { | 146 | if (d_mountpoint(dentry)) { |
@@ -212,25 +151,29 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) | |||
212 | if (!autofs4_follow_mount(&fp_mnt, &fp_dentry)) { | 151 | if (!autofs4_follow_mount(&fp_mnt, &fp_dentry)) { |
213 | dput(fp_dentry); | 152 | dput(fp_dentry); |
214 | mntput(fp_mnt); | 153 | mntput(fp_mnt); |
215 | return -ENOENT; | 154 | dcache_dir_close(inode, file); |
155 | goto out; | ||
216 | } | 156 | } |
217 | 157 | ||
218 | fp = dentry_open(fp_dentry, fp_mnt, file->f_flags); | 158 | fp = dentry_open(fp_dentry, fp_mnt, file->f_flags); |
219 | status = PTR_ERR(fp); | 159 | status = PTR_ERR(fp); |
220 | if (IS_ERR(fp)) { | 160 | if (IS_ERR(fp)) { |
221 | file->private_data = NULL; | 161 | dcache_dir_close(inode, file); |
222 | return status; | 162 | goto out; |
223 | } | 163 | } |
224 | file->private_data = fp; | 164 | cursor->d_fsdata = fp; |
225 | } | 165 | } |
226 | out: | ||
227 | return 0; | 166 | return 0; |
167 | out: | ||
168 | return status; | ||
228 | } | 169 | } |
229 | 170 | ||
230 | static int autofs4_dir_close(struct inode *inode, struct file *file) | 171 | static int autofs4_dir_close(struct inode *inode, struct file *file) |
231 | { | 172 | { |
232 | struct dentry *dentry = file->f_dentry; | 173 | struct dentry *dentry = file->f_dentry; |
233 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | 174 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); |
175 | struct dentry *cursor = file->private_data; | ||
176 | int status = 0; | ||
234 | 177 | ||
235 | DPRINTK("file=%p dentry=%p %.*s", | 178 | DPRINTK("file=%p dentry=%p %.*s", |
236 | file, dentry, dentry->d_name.len, dentry->d_name.name); | 179 | file, dentry, dentry->d_name.len, dentry->d_name.name); |
@@ -240,26 +183,28 @@ static int autofs4_dir_close(struct inode *inode, struct file *file) | |||
240 | 183 | ||
241 | if (autofs4_ispending(dentry)) { | 184 | if (autofs4_ispending(dentry)) { |
242 | DPRINTK("dentry busy"); | 185 | DPRINTK("dentry busy"); |
243 | return -EBUSY; | 186 | status = -EBUSY; |
187 | goto out; | ||
244 | } | 188 | } |
245 | 189 | ||
246 | if (d_mountpoint(dentry)) { | 190 | if (d_mountpoint(dentry)) { |
247 | struct file *fp = file->private_data; | 191 | struct file *fp = cursor->d_fsdata; |
248 | 192 | if (!fp) { | |
249 | if (!fp) | 193 | status = -ENOENT; |
250 | return -ENOENT; | 194 | goto out; |
251 | 195 | } | |
252 | filp_close(fp, current->files); | 196 | filp_close(fp, current->files); |
253 | file->private_data = NULL; | ||
254 | } | 197 | } |
255 | out: | 198 | out: |
256 | return 0; | 199 | dcache_dir_close(inode, file); |
200 | return status; | ||
257 | } | 201 | } |
258 | 202 | ||
259 | static int autofs4_dir_readdir(struct file *file, void *dirent, filldir_t filldir) | 203 | static int autofs4_dir_readdir(struct file *file, void *dirent, filldir_t filldir) |
260 | { | 204 | { |
261 | struct dentry *dentry = file->f_dentry; | 205 | struct dentry *dentry = file->f_dentry; |
262 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | 206 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); |
207 | struct dentry *cursor = file->private_data; | ||
263 | int status; | 208 | int status; |
264 | 209 | ||
265 | DPRINTK("file=%p dentry=%p %.*s", | 210 | DPRINTK("file=%p dentry=%p %.*s", |
@@ -274,7 +219,7 @@ static int autofs4_dir_readdir(struct file *file, void *dirent, filldir_t filldi | |||
274 | } | 219 | } |
275 | 220 | ||
276 | if (d_mountpoint(dentry)) { | 221 | if (d_mountpoint(dentry)) { |
277 | struct file *fp = file->private_data; | 222 | struct file *fp = cursor->d_fsdata; |
278 | 223 | ||
279 | if (!fp) | 224 | if (!fp) |
280 | return -ENOENT; | 225 | return -ENOENT; |
@@ -289,27 +234,26 @@ static int autofs4_dir_readdir(struct file *file, void *dirent, filldir_t filldi | |||
289 | return status; | 234 | return status; |
290 | } | 235 | } |
291 | out: | 236 | out: |
292 | return autofs4_dcache_readdir(file, dirent, filldir); | 237 | return dcache_readdir(file, dirent, filldir); |
293 | } | 238 | } |
294 | 239 | ||
295 | static int try_to_fill_dentry(struct vfsmount *mnt, struct dentry *dentry, int flags) | 240 | static int try_to_fill_dentry(struct dentry *dentry, int flags) |
296 | { | 241 | { |
297 | struct super_block *sb = mnt->mnt_sb; | 242 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); |
298 | struct autofs_sb_info *sbi = autofs4_sbi(sb); | 243 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
299 | struct autofs_info *de_info = autofs4_dentry_ino(dentry); | ||
300 | int status = 0; | 244 | int status = 0; |
301 | 245 | ||
302 | /* Block on any pending expiry here; invalidate the dentry | 246 | /* Block on any pending expiry here; invalidate the dentry |
303 | when expiration is done to trigger mount request with a new | 247 | when expiration is done to trigger mount request with a new |
304 | dentry */ | 248 | dentry */ |
305 | if (de_info && (de_info->flags & AUTOFS_INF_EXPIRING)) { | 249 | if (ino && (ino->flags & AUTOFS_INF_EXPIRING)) { |
306 | DPRINTK("waiting for expire %p name=%.*s", | 250 | DPRINTK("waiting for expire %p name=%.*s", |
307 | dentry, dentry->d_name.len, dentry->d_name.name); | 251 | dentry, dentry->d_name.len, dentry->d_name.name); |
308 | 252 | ||
309 | status = autofs4_wait(sbi, dentry, NFY_NONE); | 253 | status = autofs4_wait(sbi, dentry, NFY_NONE); |
310 | 254 | ||
311 | DPRINTK("expire done status=%d", status); | 255 | DPRINTK("expire done status=%d", status); |
312 | 256 | ||
313 | /* | 257 | /* |
314 | * If the directory still exists the mount request must | 258 | * If the directory still exists the mount request must |
315 | * continue otherwise it can't be followed at the right | 259 | * continue otherwise it can't be followed at the right |
@@ -317,34 +261,36 @@ static int try_to_fill_dentry(struct vfsmount *mnt, struct dentry *dentry, int f | |||
317 | */ | 261 | */ |
318 | status = d_invalidate(dentry); | 262 | status = d_invalidate(dentry); |
319 | if (status != -EBUSY) | 263 | if (status != -EBUSY) |
320 | return 0; | 264 | return -ENOENT; |
321 | } | 265 | } |
322 | 266 | ||
323 | DPRINTK("dentry=%p %.*s ino=%p", | 267 | DPRINTK("dentry=%p %.*s ino=%p", |
324 | dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); | 268 | dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); |
325 | 269 | ||
326 | /* Wait for a pending mount, triggering one if there isn't one already */ | 270 | /* |
271 | * Wait for a pending mount, triggering one if there | ||
272 | * isn't one already | ||
273 | */ | ||
327 | if (dentry->d_inode == NULL) { | 274 | if (dentry->d_inode == NULL) { |
328 | DPRINTK("waiting for mount name=%.*s", | 275 | DPRINTK("waiting for mount name=%.*s", |
329 | dentry->d_name.len, dentry->d_name.name); | 276 | dentry->d_name.len, dentry->d_name.name); |
330 | 277 | ||
331 | status = autofs4_wait(sbi, dentry, NFY_MOUNT); | 278 | status = autofs4_wait(sbi, dentry, NFY_MOUNT); |
332 | 279 | ||
333 | DPRINTK("mount done status=%d", status); | 280 | DPRINTK("mount done status=%d", status); |
334 | 281 | ||
335 | if (status && dentry->d_inode) | 282 | if (status && dentry->d_inode) |
336 | return 0; /* Try to get the kernel to invalidate this dentry */ | 283 | return status; /* Try to get the kernel to invalidate this dentry */ |
337 | 284 | ||
338 | /* Turn this into a real negative dentry? */ | 285 | /* Turn this into a real negative dentry? */ |
339 | if (status == -ENOENT) { | 286 | if (status == -ENOENT) { |
340 | dentry->d_time = jiffies + AUTOFS_NEGATIVE_TIMEOUT; | ||
341 | spin_lock(&dentry->d_lock); | 287 | spin_lock(&dentry->d_lock); |
342 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; | 288 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; |
343 | spin_unlock(&dentry->d_lock); | 289 | spin_unlock(&dentry->d_lock); |
344 | return 1; | 290 | return status; |
345 | } else if (status) { | 291 | } else if (status) { |
346 | /* Return a negative dentry, but leave it "pending" */ | 292 | /* Return a negative dentry, but leave it "pending" */ |
347 | return 1; | 293 | return status; |
348 | } | 294 | } |
349 | /* Trigger mount for path component or follow link */ | 295 | /* Trigger mount for path component or follow link */ |
350 | } else if (flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY) || | 296 | } else if (flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY) || |
@@ -363,19 +309,87 @@ static int try_to_fill_dentry(struct vfsmount *mnt, struct dentry *dentry, int f | |||
363 | spin_lock(&dentry->d_lock); | 309 | spin_lock(&dentry->d_lock); |
364 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; | 310 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; |
365 | spin_unlock(&dentry->d_lock); | 311 | spin_unlock(&dentry->d_lock); |
366 | return 0; | 312 | return status; |
367 | } | 313 | } |
368 | } | 314 | } |
369 | 315 | ||
370 | /* We don't update the usages for the autofs daemon itself, this | 316 | /* Initialize expiry counter after successful mount */ |
371 | is necessary for recursive autofs mounts */ | 317 | if (ino) |
372 | if (!autofs4_oz_mode(sbi)) | 318 | ino->last_used = jiffies; |
373 | autofs4_update_usage(mnt, dentry); | ||
374 | 319 | ||
375 | spin_lock(&dentry->d_lock); | 320 | spin_lock(&dentry->d_lock); |
376 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; | 321 | dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; |
377 | spin_unlock(&dentry->d_lock); | 322 | spin_unlock(&dentry->d_lock); |
378 | return 1; | 323 | return status; |
324 | } | ||
325 | |||
326 | /* For autofs direct mounts the follow link triggers the mount */ | ||
327 | static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | ||
328 | { | ||
329 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
330 | int oz_mode = autofs4_oz_mode(sbi); | ||
331 | unsigned int lookup_type; | ||
332 | int status; | ||
333 | |||
334 | DPRINTK("dentry=%p %.*s oz_mode=%d nd->flags=%d", | ||
335 | dentry, dentry->d_name.len, dentry->d_name.name, oz_mode, | ||
336 | nd->flags); | ||
337 | |||
338 | /* If it's our master or we shouldn't trigger a mount we're done */ | ||
339 | lookup_type = nd->flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY); | ||
340 | if (oz_mode || !lookup_type) | ||
341 | goto done; | ||
342 | |||
343 | /* | ||
344 | * If a request is pending wait for it. | ||
345 | * If it's a mount then it won't be expired till at least | ||
346 | * a liitle later and if it's an expire then we might need | ||
347 | * to mount it again. | ||
348 | */ | ||
349 | if (autofs4_ispending(dentry)) { | ||
350 | DPRINTK("waiting for active request %p name=%.*s", | ||
351 | dentry, dentry->d_name.len, dentry->d_name.name); | ||
352 | |||
353 | status = autofs4_wait(sbi, dentry, NFY_NONE); | ||
354 | |||
355 | DPRINTK("request done status=%d", status); | ||
356 | } | ||
357 | |||
358 | /* | ||
359 | * If the dentry contains directories then it is an | ||
360 | * autofs multi-mount with no root mount offset. So | ||
361 | * don't try to mount it again. | ||
362 | */ | ||
363 | spin_lock(&dcache_lock); | ||
364 | if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { | ||
365 | spin_unlock(&dcache_lock); | ||
366 | |||
367 | status = try_to_fill_dentry(dentry, 0); | ||
368 | if (status) | ||
369 | goto out_error; | ||
370 | |||
371 | /* | ||
372 | * The mount succeeded but if there is no root mount | ||
373 | * it must be an autofs multi-mount with no root offset | ||
374 | * so we don't need to follow the mount. | ||
375 | */ | ||
376 | if (d_mountpoint(dentry)) { | ||
377 | if (!autofs4_follow_mount(&nd->mnt, &nd->dentry)) { | ||
378 | status = -ENOENT; | ||
379 | goto out_error; | ||
380 | } | ||
381 | } | ||
382 | |||
383 | goto done; | ||
384 | } | ||
385 | spin_unlock(&dcache_lock); | ||
386 | |||
387 | done: | ||
388 | return NULL; | ||
389 | |||
390 | out_error: | ||
391 | path_release(nd); | ||
392 | return ERR_PTR(status); | ||
379 | } | 393 | } |
380 | 394 | ||
381 | /* | 395 | /* |
@@ -384,47 +398,43 @@ static int try_to_fill_dentry(struct vfsmount *mnt, struct dentry *dentry, int f | |||
384 | * yet completely filled in, and revalidate has to delay such | 398 | * yet completely filled in, and revalidate has to delay such |
385 | * lookups.. | 399 | * lookups.. |
386 | */ | 400 | */ |
387 | static int autofs4_revalidate(struct dentry * dentry, struct nameidata *nd) | 401 | static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) |
388 | { | 402 | { |
389 | struct inode * dir = dentry->d_parent->d_inode; | 403 | struct inode *dir = dentry->d_parent->d_inode; |
390 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 404 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); |
391 | int oz_mode = autofs4_oz_mode(sbi); | 405 | int oz_mode = autofs4_oz_mode(sbi); |
392 | int flags = nd ? nd->flags : 0; | 406 | int flags = nd ? nd->flags : 0; |
393 | int status = 1; | 407 | int status = 0; |
394 | 408 | ||
395 | /* Pending dentry */ | 409 | /* Pending dentry */ |
396 | if (autofs4_ispending(dentry)) { | 410 | if (autofs4_ispending(dentry)) { |
397 | if (!oz_mode) | 411 | if (!oz_mode) |
398 | status = try_to_fill_dentry(nd->mnt, dentry, flags); | 412 | status = try_to_fill_dentry(dentry, flags); |
399 | return status; | 413 | return !status; |
400 | } | 414 | } |
401 | 415 | ||
402 | /* Negative dentry.. invalidate if "old" */ | 416 | /* Negative dentry.. invalidate if "old" */ |
403 | if (dentry->d_inode == NULL) | 417 | if (dentry->d_inode == NULL) |
404 | return (dentry->d_time - jiffies <= AUTOFS_NEGATIVE_TIMEOUT); | 418 | return 0; |
405 | 419 | ||
406 | /* Check for a non-mountpoint directory with no contents */ | 420 | /* Check for a non-mountpoint directory with no contents */ |
407 | spin_lock(&dcache_lock); | 421 | spin_lock(&dcache_lock); |
408 | if (S_ISDIR(dentry->d_inode->i_mode) && | 422 | if (S_ISDIR(dentry->d_inode->i_mode) && |
409 | !d_mountpoint(dentry) && | 423 | !d_mountpoint(dentry) && |
410 | list_empty(&dentry->d_subdirs)) { | 424 | __simple_empty(dentry)) { |
411 | DPRINTK("dentry=%p %.*s, emptydir", | 425 | DPRINTK("dentry=%p %.*s, emptydir", |
412 | dentry, dentry->d_name.len, dentry->d_name.name); | 426 | dentry, dentry->d_name.len, dentry->d_name.name); |
413 | spin_unlock(&dcache_lock); | 427 | spin_unlock(&dcache_lock); |
414 | if (!oz_mode) | 428 | if (!oz_mode) |
415 | status = try_to_fill_dentry(nd->mnt, dentry, flags); | 429 | status = try_to_fill_dentry(dentry, flags); |
416 | return status; | 430 | return !status; |
417 | } | 431 | } |
418 | spin_unlock(&dcache_lock); | 432 | spin_unlock(&dcache_lock); |
419 | 433 | ||
420 | /* Update the usage list */ | ||
421 | if (!oz_mode) | ||
422 | autofs4_update_usage(nd->mnt, dentry); | ||
423 | |||
424 | return 1; | 434 | return 1; |
425 | } | 435 | } |
426 | 436 | ||
427 | static void autofs4_dentry_release(struct dentry *de) | 437 | void autofs4_dentry_release(struct dentry *de) |
428 | { | 438 | { |
429 | struct autofs_info *inf; | 439 | struct autofs_info *inf; |
430 | 440 | ||
@@ -462,12 +472,13 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s | |||
462 | DPRINTK("name = %.*s", | 472 | DPRINTK("name = %.*s", |
463 | dentry->d_name.len, dentry->d_name.name); | 473 | dentry->d_name.len, dentry->d_name.name); |
464 | 474 | ||
475 | /* File name too long to exist */ | ||
465 | if (dentry->d_name.len > NAME_MAX) | 476 | if (dentry->d_name.len > NAME_MAX) |
466 | return ERR_PTR(-ENAMETOOLONG);/* File name too long to exist */ | 477 | return ERR_PTR(-ENAMETOOLONG); |
467 | 478 | ||
468 | sbi = autofs4_sbi(dir->i_sb); | 479 | sbi = autofs4_sbi(dir->i_sb); |
469 | |||
470 | oz_mode = autofs4_oz_mode(sbi); | 480 | oz_mode = autofs4_oz_mode(sbi); |
481 | |||
471 | DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", | 482 | DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", |
472 | current->pid, process_group(current), sbi->catatonic, oz_mode); | 483 | current->pid, process_group(current), sbi->catatonic, oz_mode); |
473 | 484 | ||
@@ -519,7 +530,7 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s | |||
519 | * doesn't do the right thing for all system calls, but it should | 530 | * doesn't do the right thing for all system calls, but it should |
520 | * be OK for the operations we permit from an autofs. | 531 | * be OK for the operations we permit from an autofs. |
521 | */ | 532 | */ |
522 | if ( dentry->d_inode && d_unhashed(dentry) ) | 533 | if (dentry->d_inode && d_unhashed(dentry)) |
523 | return ERR_PTR(-ENOENT); | 534 | return ERR_PTR(-ENOENT); |
524 | 535 | ||
525 | return NULL; | 536 | return NULL; |
@@ -531,6 +542,7 @@ static int autofs4_dir_symlink(struct inode *dir, | |||
531 | { | 542 | { |
532 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 543 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); |
533 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | 544 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
545 | struct autofs_info *p_ino; | ||
534 | struct inode *inode; | 546 | struct inode *inode; |
535 | char *cp; | 547 | char *cp; |
536 | 548 | ||
@@ -564,6 +576,10 @@ static int autofs4_dir_symlink(struct inode *dir, | |||
564 | 576 | ||
565 | dentry->d_fsdata = ino; | 577 | dentry->d_fsdata = ino; |
566 | ino->dentry = dget(dentry); | 578 | ino->dentry = dget(dentry); |
579 | atomic_inc(&ino->count); | ||
580 | p_ino = autofs4_dentry_ino(dentry->d_parent); | ||
581 | if (p_ino && dentry->d_parent != dentry) | ||
582 | atomic_inc(&p_ino->count); | ||
567 | ino->inode = inode; | 583 | ino->inode = inode; |
568 | 584 | ||
569 | dir->i_mtime = CURRENT_TIME; | 585 | dir->i_mtime = CURRENT_TIME; |
@@ -590,11 +606,17 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) | |||
590 | { | 606 | { |
591 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 607 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); |
592 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | 608 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
609 | struct autofs_info *p_ino; | ||
593 | 610 | ||
594 | /* This allows root to remove symlinks */ | 611 | /* This allows root to remove symlinks */ |
595 | if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) | 612 | if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) |
596 | return -EACCES; | 613 | return -EACCES; |
597 | 614 | ||
615 | if (atomic_dec_and_test(&ino->count)) { | ||
616 | p_ino = autofs4_dentry_ino(dentry->d_parent); | ||
617 | if (p_ino && dentry->d_parent != dentry) | ||
618 | atomic_dec(&p_ino->count); | ||
619 | } | ||
598 | dput(ino->dentry); | 620 | dput(ino->dentry); |
599 | 621 | ||
600 | dentry->d_inode->i_size = 0; | 622 | dentry->d_inode->i_size = 0; |
@@ -611,6 +633,7 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | |||
611 | { | 633 | { |
612 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 634 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); |
613 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | 635 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
636 | struct autofs_info *p_ino; | ||
614 | 637 | ||
615 | if (!autofs4_oz_mode(sbi)) | 638 | if (!autofs4_oz_mode(sbi)) |
616 | return -EACCES; | 639 | return -EACCES; |
@@ -625,8 +648,12 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | |||
625 | spin_unlock(&dentry->d_lock); | 648 | spin_unlock(&dentry->d_lock); |
626 | spin_unlock(&dcache_lock); | 649 | spin_unlock(&dcache_lock); |
627 | 650 | ||
651 | if (atomic_dec_and_test(&ino->count)) { | ||
652 | p_ino = autofs4_dentry_ino(dentry->d_parent); | ||
653 | if (p_ino && dentry->d_parent != dentry) | ||
654 | atomic_dec(&p_ino->count); | ||
655 | } | ||
628 | dput(ino->dentry); | 656 | dput(ino->dentry); |
629 | |||
630 | dentry->d_inode->i_size = 0; | 657 | dentry->d_inode->i_size = 0; |
631 | dentry->d_inode->i_nlink = 0; | 658 | dentry->d_inode->i_nlink = 0; |
632 | 659 | ||
@@ -640,6 +667,7 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
640 | { | 667 | { |
641 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 668 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); |
642 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | 669 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
670 | struct autofs_info *p_ino; | ||
643 | struct inode *inode; | 671 | struct inode *inode; |
644 | 672 | ||
645 | if ( !autofs4_oz_mode(sbi) ) | 673 | if ( !autofs4_oz_mode(sbi) ) |
@@ -662,6 +690,10 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
662 | 690 | ||
663 | dentry->d_fsdata = ino; | 691 | dentry->d_fsdata = ino; |
664 | ino->dentry = dget(dentry); | 692 | ino->dentry = dget(dentry); |
693 | atomic_inc(&ino->count); | ||
694 | p_ino = autofs4_dentry_ino(dentry->d_parent); | ||
695 | if (p_ino && dentry->d_parent != dentry) | ||
696 | atomic_inc(&p_ino->count); | ||
665 | ino->inode = inode; | 697 | ino->inode = inode; |
666 | dir->i_nlink++; | 698 | dir->i_nlink++; |
667 | dir->i_mtime = CURRENT_TIME; | 699 | dir->i_mtime = CURRENT_TIME; |
@@ -745,7 +777,7 @@ static inline int autofs4_ask_umount(struct vfsmount *mnt, int __user *p) | |||
745 | { | 777 | { |
746 | int status = 0; | 778 | int status = 0; |
747 | 779 | ||
748 | if (may_umount(mnt) == 0) | 780 | if (may_umount(mnt)) |
749 | status = 1; | 781 | status = 1; |
750 | 782 | ||
751 | DPRINTK("returning %d", status); | 783 | DPRINTK("returning %d", status); |
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index be78e9378c03..142ab6aa2aa1 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * linux/fs/autofs/waitq.c | 3 | * linux/fs/autofs/waitq.c |
4 | * | 4 | * |
5 | * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved | 5 | * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved |
6 | * Copyright 2001-2003 Ian Kent <raven@themaw.net> | 6 | * Copyright 2001-2006 Ian Kent <raven@themaw.net> |
7 | * | 7 | * |
8 | * This file is part of the Linux kernel and is made available under | 8 | * This file is part of the Linux kernel and is made available under |
9 | * the terms of the GNU General Public License, version 2, or at your | 9 | * the terms of the GNU General Public License, version 2, or at your |
@@ -33,7 +33,7 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi) | |||
33 | sbi->catatonic = 1; | 33 | sbi->catatonic = 1; |
34 | wq = sbi->queues; | 34 | wq = sbi->queues; |
35 | sbi->queues = NULL; /* Erase all wait queues */ | 35 | sbi->queues = NULL; /* Erase all wait queues */ |
36 | while ( wq ) { | 36 | while (wq) { |
37 | nwq = wq->next; | 37 | nwq = wq->next; |
38 | wq->status = -ENOENT; /* Magic is gone - report failure */ | 38 | wq->status = -ENOENT; /* Magic is gone - report failure */ |
39 | kfree(wq->name); | 39 | kfree(wq->name); |
@@ -45,7 +45,6 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi) | |||
45 | fput(sbi->pipe); /* Close the pipe */ | 45 | fput(sbi->pipe); /* Close the pipe */ |
46 | sbi->pipe = NULL; | 46 | sbi->pipe = NULL; |
47 | } | 47 | } |
48 | |||
49 | shrink_dcache_sb(sbi->sb); | 48 | shrink_dcache_sb(sbi->sb); |
50 | } | 49 | } |
51 | 50 | ||
@@ -98,7 +97,10 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, | |||
98 | 97 | ||
99 | pkt.hdr.proto_version = sbi->version; | 98 | pkt.hdr.proto_version = sbi->version; |
100 | pkt.hdr.type = type; | 99 | pkt.hdr.type = type; |
101 | if (type == autofs_ptype_missing) { | 100 | switch (type) { |
101 | /* Kernel protocol v4 missing and expire packets */ | ||
102 | case autofs_ptype_missing: | ||
103 | { | ||
102 | struct autofs_packet_missing *mp = &pkt.missing; | 104 | struct autofs_packet_missing *mp = &pkt.missing; |
103 | 105 | ||
104 | pktsz = sizeof(*mp); | 106 | pktsz = sizeof(*mp); |
@@ -107,7 +109,10 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, | |||
107 | mp->len = wq->len; | 109 | mp->len = wq->len; |
108 | memcpy(mp->name, wq->name, wq->len); | 110 | memcpy(mp->name, wq->name, wq->len); |
109 | mp->name[wq->len] = '\0'; | 111 | mp->name[wq->len] = '\0'; |
110 | } else if (type == autofs_ptype_expire_multi) { | 112 | break; |
113 | } | ||
114 | case autofs_ptype_expire_multi: | ||
115 | { | ||
111 | struct autofs_packet_expire_multi *ep = &pkt.expire_multi; | 116 | struct autofs_packet_expire_multi *ep = &pkt.expire_multi; |
112 | 117 | ||
113 | pktsz = sizeof(*ep); | 118 | pktsz = sizeof(*ep); |
@@ -116,7 +121,34 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, | |||
116 | ep->len = wq->len; | 121 | ep->len = wq->len; |
117 | memcpy(ep->name, wq->name, wq->len); | 122 | memcpy(ep->name, wq->name, wq->len); |
118 | ep->name[wq->len] = '\0'; | 123 | ep->name[wq->len] = '\0'; |
119 | } else { | 124 | break; |
125 | } | ||
126 | /* | ||
127 | * Kernel protocol v5 packet for handling indirect and direct | ||
128 | * mount missing and expire requests | ||
129 | */ | ||
130 | case autofs_ptype_missing_indirect: | ||
131 | case autofs_ptype_expire_indirect: | ||
132 | case autofs_ptype_missing_direct: | ||
133 | case autofs_ptype_expire_direct: | ||
134 | { | ||
135 | struct autofs_v5_packet *packet = &pkt.v5_packet; | ||
136 | |||
137 | pktsz = sizeof(*packet); | ||
138 | |||
139 | packet->wait_queue_token = wq->wait_queue_token; | ||
140 | packet->len = wq->len; | ||
141 | memcpy(packet->name, wq->name, wq->len); | ||
142 | packet->name[wq->len] = '\0'; | ||
143 | packet->dev = wq->dev; | ||
144 | packet->ino = wq->ino; | ||
145 | packet->uid = wq->uid; | ||
146 | packet->gid = wq->gid; | ||
147 | packet->pid = wq->pid; | ||
148 | packet->tgid = wq->tgid; | ||
149 | break; | ||
150 | } | ||
151 | default: | ||
120 | printk("autofs4_notify_daemon: bad type %d!\n", type); | 152 | printk("autofs4_notify_daemon: bad type %d!\n", type); |
121 | return; | 153 | return; |
122 | } | 154 | } |
@@ -162,21 +194,29 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
162 | { | 194 | { |
163 | struct autofs_wait_queue *wq; | 195 | struct autofs_wait_queue *wq; |
164 | char *name; | 196 | char *name; |
165 | int len, status; | 197 | unsigned int len = 0; |
198 | unsigned int hash = 0; | ||
199 | int status; | ||
166 | 200 | ||
167 | /* In catatonic mode, we don't wait for nobody */ | 201 | /* In catatonic mode, we don't wait for nobody */ |
168 | if ( sbi->catatonic ) | 202 | if (sbi->catatonic) |
169 | return -ENOENT; | 203 | return -ENOENT; |
170 | 204 | ||
171 | name = kmalloc(NAME_MAX + 1, GFP_KERNEL); | 205 | name = kmalloc(NAME_MAX + 1, GFP_KERNEL); |
172 | if (!name) | 206 | if (!name) |
173 | return -ENOMEM; | 207 | return -ENOMEM; |
174 | 208 | ||
175 | len = autofs4_getpath(sbi, dentry, &name); | 209 | /* If this is a direct mount request create a dummy name */ |
176 | if (!len) { | 210 | if (IS_ROOT(dentry) && (sbi->type & AUTOFS_TYPE_DIRECT)) |
177 | kfree(name); | 211 | len = sprintf(name, "%p", dentry); |
178 | return -ENOENT; | 212 | else { |
213 | len = autofs4_getpath(sbi, dentry, &name); | ||
214 | if (!len) { | ||
215 | kfree(name); | ||
216 | return -ENOENT; | ||
217 | } | ||
179 | } | 218 | } |
219 | hash = full_name_hash(name, len); | ||
180 | 220 | ||
181 | if (mutex_lock_interruptible(&sbi->wq_mutex)) { | 221 | if (mutex_lock_interruptible(&sbi->wq_mutex)) { |
182 | kfree(name); | 222 | kfree(name); |
@@ -190,7 +230,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
190 | break; | 230 | break; |
191 | } | 231 | } |
192 | 232 | ||
193 | if ( !wq ) { | 233 | if (!wq) { |
194 | /* Can't wait for an expire if there's no mount */ | 234 | /* Can't wait for an expire if there's no mount */ |
195 | if (notify == NFY_NONE && !d_mountpoint(dentry)) { | 235 | if (notify == NFY_NONE && !d_mountpoint(dentry)) { |
196 | kfree(name); | 236 | kfree(name); |
@@ -200,7 +240,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
200 | 240 | ||
201 | /* Create a new wait queue */ | 241 | /* Create a new wait queue */ |
202 | wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL); | 242 | wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL); |
203 | if ( !wq ) { | 243 | if (!wq) { |
204 | kfree(name); | 244 | kfree(name); |
205 | mutex_unlock(&sbi->wq_mutex); | 245 | mutex_unlock(&sbi->wq_mutex); |
206 | return -ENOMEM; | 246 | return -ENOMEM; |
@@ -212,12 +252,18 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
212 | wq->next = sbi->queues; | 252 | wq->next = sbi->queues; |
213 | sbi->queues = wq; | 253 | sbi->queues = wq; |
214 | init_waitqueue_head(&wq->queue); | 254 | init_waitqueue_head(&wq->queue); |
215 | wq->hash = dentry->d_name.hash; | 255 | wq->hash = hash; |
216 | wq->name = name; | 256 | wq->name = name; |
217 | wq->len = len; | 257 | wq->len = len; |
258 | wq->dev = autofs4_get_dev(sbi); | ||
259 | wq->ino = autofs4_get_ino(sbi); | ||
260 | wq->uid = current->uid; | ||
261 | wq->gid = current->gid; | ||
262 | wq->pid = current->pid; | ||
263 | wq->tgid = current->tgid; | ||
218 | wq->status = -EINTR; /* Status return if interrupted */ | 264 | wq->status = -EINTR; /* Status return if interrupted */ |
219 | atomic_set(&wq->wait_ctr, 2); | 265 | atomic_set(&wq->wait_ctr, 2); |
220 | atomic_set(&wq->notified, 1); | 266 | atomic_set(&wq->notify, 1); |
221 | mutex_unlock(&sbi->wq_mutex); | 267 | mutex_unlock(&sbi->wq_mutex); |
222 | } else { | 268 | } else { |
223 | atomic_inc(&wq->wait_ctr); | 269 | atomic_inc(&wq->wait_ctr); |
@@ -227,9 +273,26 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
227 | (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); | 273 | (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); |
228 | } | 274 | } |
229 | 275 | ||
230 | if (notify != NFY_NONE && atomic_dec_and_test(&wq->notified)) { | 276 | if (notify != NFY_NONE && atomic_read(&wq->notify)) { |
231 | int type = (notify == NFY_MOUNT ? | 277 | int type; |
232 | autofs_ptype_missing : autofs_ptype_expire_multi); | 278 | |
279 | atomic_dec(&wq->notify); | ||
280 | |||
281 | if (sbi->version < 5) { | ||
282 | if (notify == NFY_MOUNT) | ||
283 | type = autofs_ptype_missing; | ||
284 | else | ||
285 | type = autofs_ptype_expire_multi; | ||
286 | } else { | ||
287 | if (notify == NFY_MOUNT) | ||
288 | type = (sbi->type & AUTOFS_TYPE_DIRECT) ? | ||
289 | autofs_ptype_missing_direct : | ||
290 | autofs_ptype_missing_indirect; | ||
291 | else | ||
292 | type = (sbi->type & AUTOFS_TYPE_DIRECT) ? | ||
293 | autofs_ptype_expire_direct : | ||
294 | autofs_ptype_expire_indirect; | ||
295 | } | ||
233 | 296 | ||
234 | DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d\n", | 297 | DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d\n", |
235 | (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); | 298 | (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); |
@@ -240,14 +303,14 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, | |||
240 | 303 | ||
241 | /* wq->name is NULL if and only if the lock is already released */ | 304 | /* wq->name is NULL if and only if the lock is already released */ |
242 | 305 | ||
243 | if ( sbi->catatonic ) { | 306 | if (sbi->catatonic) { |
244 | /* We might have slept, so check again for catatonic mode */ | 307 | /* We might have slept, so check again for catatonic mode */ |
245 | wq->status = -ENOENT; | 308 | wq->status = -ENOENT; |
246 | kfree(wq->name); | 309 | kfree(wq->name); |
247 | wq->name = NULL; | 310 | wq->name = NULL; |
248 | } | 311 | } |
249 | 312 | ||
250 | if ( wq->name ) { | 313 | if (wq->name) { |
251 | /* Block all but "shutdown" signals while waiting */ | 314 | /* Block all but "shutdown" signals while waiting */ |
252 | sigset_t oldset; | 315 | sigset_t oldset; |
253 | unsigned long irqflags; | 316 | unsigned long irqflags; |
@@ -283,12 +346,12 @@ int autofs4_wait_release(struct autofs_sb_info *sbi, autofs_wqt_t wait_queue_tok | |||
283 | struct autofs_wait_queue *wq, **wql; | 346 | struct autofs_wait_queue *wq, **wql; |
284 | 347 | ||
285 | mutex_lock(&sbi->wq_mutex); | 348 | mutex_lock(&sbi->wq_mutex); |
286 | for ( wql = &sbi->queues ; (wq = *wql) != 0 ; wql = &wq->next ) { | 349 | for (wql = &sbi->queues ; (wq = *wql) != 0 ; wql = &wq->next) { |
287 | if ( wq->wait_queue_token == wait_queue_token ) | 350 | if (wq->wait_queue_token == wait_queue_token) |
288 | break; | 351 | break; |
289 | } | 352 | } |
290 | 353 | ||
291 | if ( !wq ) { | 354 | if (!wq) { |
292 | mutex_unlock(&sbi->wq_mutex); | 355 | mutex_unlock(&sbi->wq_mutex); |
293 | return -EINVAL; | 356 | return -EINVAL; |
294 | } | 357 | } |
diff --git a/fs/block_dev.c b/fs/block_dev.c index 5983d42df015..17c76182f389 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -266,6 +266,9 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) | |||
266 | mutex_init(&bdev->bd_mount_mutex); | 266 | mutex_init(&bdev->bd_mount_mutex); |
267 | INIT_LIST_HEAD(&bdev->bd_inodes); | 267 | INIT_LIST_HEAD(&bdev->bd_inodes); |
268 | INIT_LIST_HEAD(&bdev->bd_list); | 268 | INIT_LIST_HEAD(&bdev->bd_list); |
269 | #ifdef CONFIG_SYSFS | ||
270 | INIT_LIST_HEAD(&bdev->bd_holder_list); | ||
271 | #endif | ||
269 | inode_init_once(&ei->vfs_inode); | 272 | inode_init_once(&ei->vfs_inode); |
270 | } | 273 | } |
271 | } | 274 | } |
@@ -490,6 +493,300 @@ void bd_release(struct block_device *bdev) | |||
490 | 493 | ||
491 | EXPORT_SYMBOL(bd_release); | 494 | EXPORT_SYMBOL(bd_release); |
492 | 495 | ||
496 | #ifdef CONFIG_SYSFS | ||
497 | /* | ||
498 | * Functions for bd_claim_by_kobject / bd_release_from_kobject | ||
499 | * | ||
500 | * If a kobject is passed to bd_claim_by_kobject() | ||
501 | * and the kobject has a parent directory, | ||
502 | * following symlinks are created: | ||
503 | * o from the kobject to the claimed bdev | ||
504 | * o from "holders" directory of the bdev to the parent of the kobject | ||
505 | * bd_release_from_kobject() removes these symlinks. | ||
506 | * | ||
507 | * Example: | ||
508 | * If /dev/dm-0 maps to /dev/sda, kobject corresponding to | ||
509 | * /sys/block/dm-0/slaves is passed to bd_claim_by_kobject(), then: | ||
510 | * /sys/block/dm-0/slaves/sda --> /sys/block/sda | ||
511 | * /sys/block/sda/holders/dm-0 --> /sys/block/dm-0 | ||
512 | */ | ||
513 | |||
514 | static struct kobject *bdev_get_kobj(struct block_device *bdev) | ||
515 | { | ||
516 | if (bdev->bd_contains != bdev) | ||
517 | return kobject_get(&bdev->bd_part->kobj); | ||
518 | else | ||
519 | return kobject_get(&bdev->bd_disk->kobj); | ||
520 | } | ||
521 | |||
522 | static struct kobject *bdev_get_holder(struct block_device *bdev) | ||
523 | { | ||
524 | if (bdev->bd_contains != bdev) | ||
525 | return kobject_get(bdev->bd_part->holder_dir); | ||
526 | else | ||
527 | return kobject_get(bdev->bd_disk->holder_dir); | ||
528 | } | ||
529 | |||
530 | static void add_symlink(struct kobject *from, struct kobject *to) | ||
531 | { | ||
532 | if (!from || !to) | ||
533 | return; | ||
534 | sysfs_create_link(from, to, kobject_name(to)); | ||
535 | } | ||
536 | |||
537 | static void del_symlink(struct kobject *from, struct kobject *to) | ||
538 | { | ||
539 | if (!from || !to) | ||
540 | return; | ||
541 | sysfs_remove_link(from, kobject_name(to)); | ||
542 | } | ||
543 | |||
544 | /* | ||
545 | * 'struct bd_holder' contains pointers to kobjects symlinked by | ||
546 | * bd_claim_by_kobject. | ||
547 | * It's connected to bd_holder_list which is protected by bdev->bd_sem. | ||
548 | */ | ||
549 | struct bd_holder { | ||
550 | struct list_head list; /* chain of holders of the bdev */ | ||
551 | int count; /* references from the holder */ | ||
552 | struct kobject *sdir; /* holder object, e.g. "/block/dm-0/slaves" */ | ||
553 | struct kobject *hdev; /* e.g. "/block/dm-0" */ | ||
554 | struct kobject *hdir; /* e.g. "/block/sda/holders" */ | ||
555 | struct kobject *sdev; /* e.g. "/block/sda" */ | ||
556 | }; | ||
557 | |||
558 | /* | ||
559 | * Get references of related kobjects at once. | ||
560 | * Returns 1 on success. 0 on failure. | ||
561 | * | ||
562 | * Should call bd_holder_release_dirs() after successful use. | ||
563 | */ | ||
564 | static int bd_holder_grab_dirs(struct block_device *bdev, | ||
565 | struct bd_holder *bo) | ||
566 | { | ||
567 | if (!bdev || !bo) | ||
568 | return 0; | ||
569 | |||
570 | bo->sdir = kobject_get(bo->sdir); | ||
571 | if (!bo->sdir) | ||
572 | return 0; | ||
573 | |||
574 | bo->hdev = kobject_get(bo->sdir->parent); | ||
575 | if (!bo->hdev) | ||
576 | goto fail_put_sdir; | ||
577 | |||
578 | bo->sdev = bdev_get_kobj(bdev); | ||
579 | if (!bo->sdev) | ||
580 | goto fail_put_hdev; | ||
581 | |||
582 | bo->hdir = bdev_get_holder(bdev); | ||
583 | if (!bo->hdir) | ||
584 | goto fail_put_sdev; | ||
585 | |||
586 | return 1; | ||
587 | |||
588 | fail_put_sdev: | ||
589 | kobject_put(bo->sdev); | ||
590 | fail_put_hdev: | ||
591 | kobject_put(bo->hdev); | ||
592 | fail_put_sdir: | ||
593 | kobject_put(bo->sdir); | ||
594 | |||
595 | return 0; | ||
596 | } | ||
597 | |||
598 | /* Put references of related kobjects at once. */ | ||
599 | static void bd_holder_release_dirs(struct bd_holder *bo) | ||
600 | { | ||
601 | kobject_put(bo->hdir); | ||
602 | kobject_put(bo->sdev); | ||
603 | kobject_put(bo->hdev); | ||
604 | kobject_put(bo->sdir); | ||
605 | } | ||
606 | |||
607 | static struct bd_holder *alloc_bd_holder(struct kobject *kobj) | ||
608 | { | ||
609 | struct bd_holder *bo; | ||
610 | |||
611 | bo = kzalloc(sizeof(*bo), GFP_KERNEL); | ||
612 | if (!bo) | ||
613 | return NULL; | ||
614 | |||
615 | bo->count = 1; | ||
616 | bo->sdir = kobj; | ||
617 | |||
618 | return bo; | ||
619 | } | ||
620 | |||
621 | static void free_bd_holder(struct bd_holder *bo) | ||
622 | { | ||
623 | kfree(bo); | ||
624 | } | ||
625 | |||
626 | /** | ||
627 | * add_bd_holder - create sysfs symlinks for bd_claim() relationship | ||
628 | * | ||
629 | * @bdev: block device to be bd_claimed | ||
630 | * @bo: preallocated and initialized by alloc_bd_holder() | ||
631 | * | ||
632 | * If there is no matching entry with @bo in @bdev->bd_holder_list, | ||
633 | * add @bo to the list, create symlinks. | ||
634 | * | ||
635 | * Returns 1 if @bo was added to the list. | ||
636 | * Returns 0 if @bo wasn't used by any reason and should be freed. | ||
637 | */ | ||
638 | static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo) | ||
639 | { | ||
640 | struct bd_holder *tmp; | ||
641 | |||
642 | if (!bo) | ||
643 | return 0; | ||
644 | |||
645 | list_for_each_entry(tmp, &bdev->bd_holder_list, list) { | ||
646 | if (tmp->sdir == bo->sdir) { | ||
647 | tmp->count++; | ||
648 | return 0; | ||
649 | } | ||
650 | } | ||
651 | |||
652 | if (!bd_holder_grab_dirs(bdev, bo)) | ||
653 | return 0; | ||
654 | |||
655 | add_symlink(bo->sdir, bo->sdev); | ||
656 | add_symlink(bo->hdir, bo->hdev); | ||
657 | list_add_tail(&bo->list, &bdev->bd_holder_list); | ||
658 | return 1; | ||
659 | } | ||
660 | |||
661 | /** | ||
662 | * del_bd_holder - delete sysfs symlinks for bd_claim() relationship | ||
663 | * | ||
664 | * @bdev: block device to be bd_claimed | ||
665 | * @kobj: holder's kobject | ||
666 | * | ||
667 | * If there is matching entry with @kobj in @bdev->bd_holder_list | ||
668 | * and no other bd_claim() from the same kobject, | ||
669 | * remove the struct bd_holder from the list, delete symlinks for it. | ||
670 | * | ||
671 | * Returns a pointer to the struct bd_holder when it's removed from the list | ||
672 | * and ready to be freed. | ||
673 | * Returns NULL if matching claim isn't found or there is other bd_claim() | ||
674 | * by the same kobject. | ||
675 | */ | ||
676 | static struct bd_holder *del_bd_holder(struct block_device *bdev, | ||
677 | struct kobject *kobj) | ||
678 | { | ||
679 | struct bd_holder *bo; | ||
680 | |||
681 | list_for_each_entry(bo, &bdev->bd_holder_list, list) { | ||
682 | if (bo->sdir == kobj) { | ||
683 | bo->count--; | ||
684 | BUG_ON(bo->count < 0); | ||
685 | if (!bo->count) { | ||
686 | list_del(&bo->list); | ||
687 | del_symlink(bo->sdir, bo->sdev); | ||
688 | del_symlink(bo->hdir, bo->hdev); | ||
689 | bd_holder_release_dirs(bo); | ||
690 | return bo; | ||
691 | } | ||
692 | break; | ||
693 | } | ||
694 | } | ||
695 | |||
696 | return NULL; | ||
697 | } | ||
698 | |||
699 | /** | ||
700 | * bd_claim_by_kobject - bd_claim() with additional kobject signature | ||
701 | * | ||
702 | * @bdev: block device to be claimed | ||
703 | * @holder: holder's signature | ||
704 | * @kobj: holder's kobject | ||
705 | * | ||
706 | * Do bd_claim() and if it succeeds, create sysfs symlinks between | ||
707 | * the bdev and the holder's kobject. | ||
708 | * Use bd_release_from_kobject() when relesing the claimed bdev. | ||
709 | * | ||
710 | * Returns 0 on success. (same as bd_claim()) | ||
711 | * Returns errno on failure. | ||
712 | */ | ||
713 | static int bd_claim_by_kobject(struct block_device *bdev, void *holder, | ||
714 | struct kobject *kobj) | ||
715 | { | ||
716 | int res; | ||
717 | struct bd_holder *bo; | ||
718 | |||
719 | if (!kobj) | ||
720 | return -EINVAL; | ||
721 | |||
722 | bo = alloc_bd_holder(kobj); | ||
723 | if (!bo) | ||
724 | return -ENOMEM; | ||
725 | |||
726 | mutex_lock(&bdev->bd_mutex); | ||
727 | res = bd_claim(bdev, holder); | ||
728 | if (res || !add_bd_holder(bdev, bo)) | ||
729 | free_bd_holder(bo); | ||
730 | mutex_unlock(&bdev->bd_mutex); | ||
731 | |||
732 | return res; | ||
733 | } | ||
734 | |||
735 | /** | ||
736 | * bd_release_from_kobject - bd_release() with additional kobject signature | ||
737 | * | ||
738 | * @bdev: block device to be released | ||
739 | * @kobj: holder's kobject | ||
740 | * | ||
741 | * Do bd_release() and remove sysfs symlinks created by bd_claim_by_kobject(). | ||
742 | */ | ||
743 | static void bd_release_from_kobject(struct block_device *bdev, | ||
744 | struct kobject *kobj) | ||
745 | { | ||
746 | struct bd_holder *bo; | ||
747 | |||
748 | if (!kobj) | ||
749 | return; | ||
750 | |||
751 | mutex_lock(&bdev->bd_mutex); | ||
752 | bd_release(bdev); | ||
753 | if ((bo = del_bd_holder(bdev, kobj))) | ||
754 | free_bd_holder(bo); | ||
755 | mutex_unlock(&bdev->bd_mutex); | ||
756 | } | ||
757 | |||
758 | /** | ||
759 | * bd_claim_by_disk - wrapper function for bd_claim_by_kobject() | ||
760 | * | ||
761 | * @bdev: block device to be claimed | ||
762 | * @holder: holder's signature | ||
763 | * @disk: holder's gendisk | ||
764 | * | ||
765 | * Call bd_claim_by_kobject() with getting @disk->slave_dir. | ||
766 | */ | ||
767 | int bd_claim_by_disk(struct block_device *bdev, void *holder, | ||
768 | struct gendisk *disk) | ||
769 | { | ||
770 | return bd_claim_by_kobject(bdev, holder, kobject_get(disk->slave_dir)); | ||
771 | } | ||
772 | EXPORT_SYMBOL_GPL(bd_claim_by_disk); | ||
773 | |||
774 | /** | ||
775 | * bd_release_from_disk - wrapper function for bd_release_from_kobject() | ||
776 | * | ||
777 | * @bdev: block device to be claimed | ||
778 | * @disk: holder's gendisk | ||
779 | * | ||
780 | * Call bd_release_from_kobject() and put @disk->slave_dir. | ||
781 | */ | ||
782 | void bd_release_from_disk(struct block_device *bdev, struct gendisk *disk) | ||
783 | { | ||
784 | bd_release_from_kobject(bdev, disk->slave_dir); | ||
785 | kobject_put(disk->slave_dir); | ||
786 | } | ||
787 | EXPORT_SYMBOL_GPL(bd_release_from_disk); | ||
788 | #endif | ||
789 | |||
493 | /* | 790 | /* |
494 | * Tries to open block device by device number. Use it ONLY if you | 791 | * Tries to open block device by device number. Use it ONLY if you |
495 | * really do not have anything better - i.e. when you are behind a | 792 | * really do not have anything better - i.e. when you are behind a |
diff --git a/fs/buffer.c b/fs/buffer.c index d597758dd129..23f1f3a68077 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -493,7 +493,7 @@ static void free_more_memory(void) | |||
493 | wakeup_pdflush(1024); | 493 | wakeup_pdflush(1024); |
494 | yield(); | 494 | yield(); |
495 | 495 | ||
496 | for_each_pgdat(pgdat) { | 496 | for_each_online_pgdat(pgdat) { |
497 | zones = pgdat->node_zonelists[gfp_zone(GFP_NOFS)].zones; | 497 | zones = pgdat->node_zonelists[gfp_zone(GFP_NOFS)].zones; |
498 | if (*zones) | 498 | if (*zones) |
499 | try_to_free_pages(zones, GFP_NOFS); | 499 | try_to_free_pages(zones, GFP_NOFS); |
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c index b97809deba66..23b7cee72123 100644 --- a/fs/hostfs/hostfs_user.c +++ b/fs/hostfs/hostfs_user.c | |||
@@ -360,7 +360,6 @@ int do_statfs(char *root, long *bsize_out, long long *blocks_out, | |||
360 | spare_out[2] = buf.f_spare[2]; | 360 | spare_out[2] = buf.f_spare[2]; |
361 | spare_out[3] = buf.f_spare[3]; | 361 | spare_out[3] = buf.f_spare[3]; |
362 | spare_out[4] = buf.f_spare[4]; | 362 | spare_out[4] = buf.f_spare[4]; |
363 | spare_out[5] = buf.f_spare[5]; | ||
364 | return(0); | 363 | return(0); |
365 | } | 364 | } |
366 | 365 | ||
diff --git a/fs/namei.c b/fs/namei.c index 98dc2e134362..22f6e8d16aa8 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -546,6 +546,22 @@ struct path { | |||
546 | struct dentry *dentry; | 546 | struct dentry *dentry; |
547 | }; | 547 | }; |
548 | 548 | ||
549 | static inline void dput_path(struct path *path, struct nameidata *nd) | ||
550 | { | ||
551 | dput(path->dentry); | ||
552 | if (path->mnt != nd->mnt) | ||
553 | mntput(path->mnt); | ||
554 | } | ||
555 | |||
556 | static inline void path_to_nameidata(struct path *path, struct nameidata *nd) | ||
557 | { | ||
558 | dput(nd->dentry); | ||
559 | if (nd->mnt != path->mnt) | ||
560 | mntput(nd->mnt); | ||
561 | nd->mnt = path->mnt; | ||
562 | nd->dentry = path->dentry; | ||
563 | } | ||
564 | |||
549 | static __always_inline int __do_follow_link(struct path *path, struct nameidata *nd) | 565 | static __always_inline int __do_follow_link(struct path *path, struct nameidata *nd) |
550 | { | 566 | { |
551 | int error; | 567 | int error; |
@@ -555,8 +571,11 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata | |||
555 | touch_atime(path->mnt, dentry); | 571 | touch_atime(path->mnt, dentry); |
556 | nd_set_link(nd, NULL); | 572 | nd_set_link(nd, NULL); |
557 | 573 | ||
558 | if (path->mnt == nd->mnt) | 574 | if (path->mnt != nd->mnt) { |
559 | mntget(path->mnt); | 575 | path_to_nameidata(path, nd); |
576 | dget(dentry); | ||
577 | } | ||
578 | mntget(path->mnt); | ||
560 | cookie = dentry->d_inode->i_op->follow_link(dentry, nd); | 579 | cookie = dentry->d_inode->i_op->follow_link(dentry, nd); |
561 | error = PTR_ERR(cookie); | 580 | error = PTR_ERR(cookie); |
562 | if (!IS_ERR(cookie)) { | 581 | if (!IS_ERR(cookie)) { |
@@ -573,22 +592,6 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata | |||
573 | return error; | 592 | return error; |
574 | } | 593 | } |
575 | 594 | ||
576 | static inline void dput_path(struct path *path, struct nameidata *nd) | ||
577 | { | ||
578 | dput(path->dentry); | ||
579 | if (path->mnt != nd->mnt) | ||
580 | mntput(path->mnt); | ||
581 | } | ||
582 | |||
583 | static inline void path_to_nameidata(struct path *path, struct nameidata *nd) | ||
584 | { | ||
585 | dput(nd->dentry); | ||
586 | if (nd->mnt != path->mnt) | ||
587 | mntput(nd->mnt); | ||
588 | nd->mnt = path->mnt; | ||
589 | nd->dentry = path->dentry; | ||
590 | } | ||
591 | |||
592 | /* | 595 | /* |
593 | * This limits recursive symlink follows to 8, while | 596 | * This limits recursive symlink follows to 8, while |
594 | * limiting consecutive symlinks to 40. | 597 | * limiting consecutive symlinks to 40. |
diff --git a/fs/namespace.c b/fs/namespace.c index e069a4c5e389..bf478addb852 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -459,9 +459,9 @@ int may_umount_tree(struct vfsmount *mnt) | |||
459 | spin_unlock(&vfsmount_lock); | 459 | spin_unlock(&vfsmount_lock); |
460 | 460 | ||
461 | if (actual_refs > minimum_refs) | 461 | if (actual_refs > minimum_refs) |
462 | return -EBUSY; | 462 | return 0; |
463 | 463 | ||
464 | return 0; | 464 | return 1; |
465 | } | 465 | } |
466 | 466 | ||
467 | EXPORT_SYMBOL(may_umount_tree); | 467 | EXPORT_SYMBOL(may_umount_tree); |
@@ -481,10 +481,10 @@ EXPORT_SYMBOL(may_umount_tree); | |||
481 | */ | 481 | */ |
482 | int may_umount(struct vfsmount *mnt) | 482 | int may_umount(struct vfsmount *mnt) |
483 | { | 483 | { |
484 | int ret = 0; | 484 | int ret = 1; |
485 | spin_lock(&vfsmount_lock); | 485 | spin_lock(&vfsmount_lock); |
486 | if (propagate_mount_busy(mnt, 2)) | 486 | if (propagate_mount_busy(mnt, 2)) |
487 | ret = -EBUSY; | 487 | ret = 0; |
488 | spin_unlock(&vfsmount_lock); | 488 | spin_unlock(&vfsmount_lock); |
489 | return ret; | 489 | return ret; |
490 | } | 490 | } |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 417ec02df44f..c340be0a3f59 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -57,27 +57,17 @@ static int exp_verify_string(char *cp, int max); | |||
57 | #define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1) | 57 | #define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1) |
58 | static struct cache_head *expkey_table[EXPKEY_HASHMAX]; | 58 | static struct cache_head *expkey_table[EXPKEY_HASHMAX]; |
59 | 59 | ||
60 | static inline int svc_expkey_hash(struct svc_expkey *item) | 60 | static void expkey_put(struct kref *ref) |
61 | { | 61 | { |
62 | int hash = item->ek_fsidtype; | 62 | struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref); |
63 | char * cp = (char*)item->ek_fsid; | ||
64 | int len = key_len(item->ek_fsidtype); | ||
65 | 63 | ||
66 | hash ^= hash_mem(cp, len, EXPKEY_HASHBITS); | 64 | if (test_bit(CACHE_VALID, &key->h.flags) && |
67 | hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS); | 65 | !test_bit(CACHE_NEGATIVE, &key->h.flags)) { |
68 | return hash & EXPKEY_HASHMASK; | 66 | dput(key->ek_dentry); |
69 | } | 67 | mntput(key->ek_mnt); |
70 | |||
71 | void expkey_put(struct cache_head *item, struct cache_detail *cd) | ||
72 | { | ||
73 | if (cache_put(item, cd)) { | ||
74 | struct svc_expkey *key = container_of(item, struct svc_expkey, h); | ||
75 | if (test_bit(CACHE_VALID, &item->flags) && | ||
76 | !test_bit(CACHE_NEGATIVE, &item->flags)) | ||
77 | exp_put(key->ek_export); | ||
78 | auth_domain_put(key->ek_client); | ||
79 | kfree(key); | ||
80 | } | 68 | } |
69 | auth_domain_put(key->ek_client); | ||
70 | kfree(key); | ||
81 | } | 71 | } |
82 | 72 | ||
83 | static void expkey_request(struct cache_detail *cd, | 73 | static void expkey_request(struct cache_detail *cd, |
@@ -95,7 +85,10 @@ static void expkey_request(struct cache_detail *cd, | |||
95 | (*bpp)[-1] = '\n'; | 85 | (*bpp)[-1] = '\n'; |
96 | } | 86 | } |
97 | 87 | ||
98 | static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *, int); | 88 | static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old); |
89 | static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *); | ||
90 | static struct cache_detail svc_expkey_cache; | ||
91 | |||
99 | static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) | 92 | static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) |
100 | { | 93 | { |
101 | /* client fsidtype fsid [path] */ | 94 | /* client fsidtype fsid [path] */ |
@@ -106,6 +99,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
106 | int fsidtype; | 99 | int fsidtype; |
107 | char *ep; | 100 | char *ep; |
108 | struct svc_expkey key; | 101 | struct svc_expkey key; |
102 | struct svc_expkey *ek; | ||
109 | 103 | ||
110 | if (mesg[mlen-1] != '\n') | 104 | if (mesg[mlen-1] != '\n') |
111 | return -EINVAL; | 105 | return -EINVAL; |
@@ -150,40 +144,38 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
150 | key.ek_fsidtype = fsidtype; | 144 | key.ek_fsidtype = fsidtype; |
151 | memcpy(key.ek_fsid, buf, len); | 145 | memcpy(key.ek_fsid, buf, len); |
152 | 146 | ||
147 | ek = svc_expkey_lookup(&key); | ||
148 | err = -ENOMEM; | ||
149 | if (!ek) | ||
150 | goto out; | ||
151 | |||
153 | /* now we want a pathname, or empty meaning NEGATIVE */ | 152 | /* now we want a pathname, or empty meaning NEGATIVE */ |
153 | err = -EINVAL; | ||
154 | if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0) | 154 | if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0) |
155 | goto out; | 155 | goto out; |
156 | dprintk("Path seems to be <%s>\n", buf); | 156 | dprintk("Path seems to be <%s>\n", buf); |
157 | err = 0; | 157 | err = 0; |
158 | if (len == 0) { | 158 | if (len == 0) { |
159 | struct svc_expkey *ek; | ||
160 | set_bit(CACHE_NEGATIVE, &key.h.flags); | 159 | set_bit(CACHE_NEGATIVE, &key.h.flags); |
161 | ek = svc_expkey_lookup(&key, 1); | 160 | ek = svc_expkey_update(&key, ek); |
162 | if (ek) | 161 | if (ek) |
163 | expkey_put(&ek->h, &svc_expkey_cache); | 162 | cache_put(&ek->h, &svc_expkey_cache); |
163 | else err = -ENOMEM; | ||
164 | } else { | 164 | } else { |
165 | struct nameidata nd; | 165 | struct nameidata nd; |
166 | struct svc_expkey *ek; | ||
167 | struct svc_export *exp; | ||
168 | err = path_lookup(buf, 0, &nd); | 166 | err = path_lookup(buf, 0, &nd); |
169 | if (err) | 167 | if (err) |
170 | goto out; | 168 | goto out; |
171 | 169 | ||
172 | dprintk("Found the path %s\n", buf); | 170 | dprintk("Found the path %s\n", buf); |
173 | exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL); | 171 | key.ek_mnt = nd.mnt; |
174 | 172 | key.ek_dentry = nd.dentry; | |
175 | err = -ENOENT; | ||
176 | if (!exp) | ||
177 | goto out_nd; | ||
178 | key.ek_export = exp; | ||
179 | dprintk("And found export\n"); | ||
180 | 173 | ||
181 | ek = svc_expkey_lookup(&key, 1); | 174 | ek = svc_expkey_update(&key, ek); |
182 | if (ek) | 175 | if (ek) |
183 | expkey_put(&ek->h, &svc_expkey_cache); | 176 | cache_put(&ek->h, &svc_expkey_cache); |
184 | exp_put(exp); | 177 | else |
185 | err = 0; | 178 | err = -ENOMEM; |
186 | out_nd: | ||
187 | path_release(&nd); | 179 | path_release(&nd); |
188 | } | 180 | } |
189 | cache_flush(); | 181 | cache_flush(); |
@@ -214,35 +206,31 @@ static int expkey_show(struct seq_file *m, | |||
214 | if (test_bit(CACHE_VALID, &h->flags) && | 206 | if (test_bit(CACHE_VALID, &h->flags) && |
215 | !test_bit(CACHE_NEGATIVE, &h->flags)) { | 207 | !test_bit(CACHE_NEGATIVE, &h->flags)) { |
216 | seq_printf(m, " "); | 208 | seq_printf(m, " "); |
217 | seq_path(m, ek->ek_export->ex_mnt, ek->ek_export->ex_dentry, "\\ \t\n"); | 209 | seq_path(m, ek->ek_mnt, ek->ek_dentry, "\\ \t\n"); |
218 | } | 210 | } |
219 | seq_printf(m, "\n"); | 211 | seq_printf(m, "\n"); |
220 | return 0; | 212 | return 0; |
221 | } | 213 | } |
222 | |||
223 | struct cache_detail svc_expkey_cache = { | ||
224 | .owner = THIS_MODULE, | ||
225 | .hash_size = EXPKEY_HASHMAX, | ||
226 | .hash_table = expkey_table, | ||
227 | .name = "nfsd.fh", | ||
228 | .cache_put = expkey_put, | ||
229 | .cache_request = expkey_request, | ||
230 | .cache_parse = expkey_parse, | ||
231 | .cache_show = expkey_show, | ||
232 | }; | ||
233 | 214 | ||
234 | static inline int svc_expkey_match (struct svc_expkey *a, struct svc_expkey *b) | 215 | static inline int expkey_match (struct cache_head *a, struct cache_head *b) |
235 | { | 216 | { |
236 | if (a->ek_fsidtype != b->ek_fsidtype || | 217 | struct svc_expkey *orig = container_of(a, struct svc_expkey, h); |
237 | a->ek_client != b->ek_client || | 218 | struct svc_expkey *new = container_of(b, struct svc_expkey, h); |
238 | memcmp(a->ek_fsid, b->ek_fsid, key_len(a->ek_fsidtype)) != 0) | 219 | |
220 | if (orig->ek_fsidtype != new->ek_fsidtype || | ||
221 | orig->ek_client != new->ek_client || | ||
222 | memcmp(orig->ek_fsid, new->ek_fsid, key_len(orig->ek_fsidtype)) != 0) | ||
239 | return 0; | 223 | return 0; |
240 | return 1; | 224 | return 1; |
241 | } | 225 | } |
242 | 226 | ||
243 | static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *item) | 227 | static inline void expkey_init(struct cache_head *cnew, |
228 | struct cache_head *citem) | ||
244 | { | 229 | { |
245 | cache_get(&item->ek_client->h); | 230 | struct svc_expkey *new = container_of(cnew, struct svc_expkey, h); |
231 | struct svc_expkey *item = container_of(citem, struct svc_expkey, h); | ||
232 | |||
233 | kref_get(&item->ek_client->ref); | ||
246 | new->ek_client = item->ek_client; | 234 | new->ek_client = item->ek_client; |
247 | new->ek_fsidtype = item->ek_fsidtype; | 235 | new->ek_fsidtype = item->ek_fsidtype; |
248 | new->ek_fsid[0] = item->ek_fsid[0]; | 236 | new->ek_fsid[0] = item->ek_fsid[0]; |
@@ -250,39 +238,94 @@ static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *it | |||
250 | new->ek_fsid[2] = item->ek_fsid[2]; | 238 | new->ek_fsid[2] = item->ek_fsid[2]; |
251 | } | 239 | } |
252 | 240 | ||
253 | static inline void svc_expkey_update(struct svc_expkey *new, struct svc_expkey *item) | 241 | static inline void expkey_update(struct cache_head *cnew, |
242 | struct cache_head *citem) | ||
243 | { | ||
244 | struct svc_expkey *new = container_of(cnew, struct svc_expkey, h); | ||
245 | struct svc_expkey *item = container_of(citem, struct svc_expkey, h); | ||
246 | |||
247 | new->ek_mnt = mntget(item->ek_mnt); | ||
248 | new->ek_dentry = dget(item->ek_dentry); | ||
249 | } | ||
250 | |||
251 | static struct cache_head *expkey_alloc(void) | ||
254 | { | 252 | { |
255 | cache_get(&item->ek_export->h); | 253 | struct svc_expkey *i = kmalloc(sizeof(*i), GFP_KERNEL); |
256 | new->ek_export = item->ek_export; | 254 | if (i) |
255 | return &i->h; | ||
256 | else | ||
257 | return NULL; | ||
257 | } | 258 | } |
258 | 259 | ||
259 | static DefineSimpleCacheLookup(svc_expkey,0) /* no inplace updates */ | 260 | static struct cache_detail svc_expkey_cache = { |
261 | .owner = THIS_MODULE, | ||
262 | .hash_size = EXPKEY_HASHMAX, | ||
263 | .hash_table = expkey_table, | ||
264 | .name = "nfsd.fh", | ||
265 | .cache_put = expkey_put, | ||
266 | .cache_request = expkey_request, | ||
267 | .cache_parse = expkey_parse, | ||
268 | .cache_show = expkey_show, | ||
269 | .match = expkey_match, | ||
270 | .init = expkey_init, | ||
271 | .update = expkey_update, | ||
272 | .alloc = expkey_alloc, | ||
273 | }; | ||
260 | 274 | ||
261 | #define EXPORT_HASHBITS 8 | 275 | static struct svc_expkey * |
262 | #define EXPORT_HASHMAX (1<< EXPORT_HASHBITS) | 276 | svc_expkey_lookup(struct svc_expkey *item) |
263 | #define EXPORT_HASHMASK (EXPORT_HASHMAX -1) | 277 | { |
278 | struct cache_head *ch; | ||
279 | int hash = item->ek_fsidtype; | ||
280 | char * cp = (char*)item->ek_fsid; | ||
281 | int len = key_len(item->ek_fsidtype); | ||
264 | 282 | ||
265 | static struct cache_head *export_table[EXPORT_HASHMAX]; | 283 | hash ^= hash_mem(cp, len, EXPKEY_HASHBITS); |
284 | hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS); | ||
285 | hash &= EXPKEY_HASHMASK; | ||
266 | 286 | ||
267 | static inline int svc_export_hash(struct svc_export *item) | 287 | ch = sunrpc_cache_lookup(&svc_expkey_cache, &item->h, |
288 | hash); | ||
289 | if (ch) | ||
290 | return container_of(ch, struct svc_expkey, h); | ||
291 | else | ||
292 | return NULL; | ||
293 | } | ||
294 | |||
295 | static struct svc_expkey * | ||
296 | svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old) | ||
268 | { | 297 | { |
269 | int rv; | 298 | struct cache_head *ch; |
299 | int hash = new->ek_fsidtype; | ||
300 | char * cp = (char*)new->ek_fsid; | ||
301 | int len = key_len(new->ek_fsidtype); | ||
270 | 302 | ||
271 | rv = hash_ptr(item->ex_client, EXPORT_HASHBITS); | 303 | hash ^= hash_mem(cp, len, EXPKEY_HASHBITS); |
272 | rv ^= hash_ptr(item->ex_dentry, EXPORT_HASHBITS); | 304 | hash ^= hash_ptr(new->ek_client, EXPKEY_HASHBITS); |
273 | rv ^= hash_ptr(item->ex_mnt, EXPORT_HASHBITS); | 305 | hash &= EXPKEY_HASHMASK; |
274 | return rv; | 306 | |
307 | ch = sunrpc_cache_update(&svc_expkey_cache, &new->h, | ||
308 | &old->h, hash); | ||
309 | if (ch) | ||
310 | return container_of(ch, struct svc_expkey, h); | ||
311 | else | ||
312 | return NULL; | ||
275 | } | 313 | } |
276 | 314 | ||
277 | void svc_export_put(struct cache_head *item, struct cache_detail *cd) | 315 | |
316 | #define EXPORT_HASHBITS 8 | ||
317 | #define EXPORT_HASHMAX (1<< EXPORT_HASHBITS) | ||
318 | #define EXPORT_HASHMASK (EXPORT_HASHMAX -1) | ||
319 | |||
320 | static struct cache_head *export_table[EXPORT_HASHMAX]; | ||
321 | |||
322 | static void svc_export_put(struct kref *ref) | ||
278 | { | 323 | { |
279 | if (cache_put(item, cd)) { | 324 | struct svc_export *exp = container_of(ref, struct svc_export, h.ref); |
280 | struct svc_export *exp = container_of(item, struct svc_export, h); | 325 | dput(exp->ex_dentry); |
281 | dput(exp->ex_dentry); | 326 | mntput(exp->ex_mnt); |
282 | mntput(exp->ex_mnt); | 327 | auth_domain_put(exp->ex_client); |
283 | auth_domain_put(exp->ex_client); | 328 | kfree(exp); |
284 | kfree(exp); | ||
285 | } | ||
286 | } | 329 | } |
287 | 330 | ||
288 | static void svc_export_request(struct cache_detail *cd, | 331 | static void svc_export_request(struct cache_detail *cd, |
@@ -304,7 +347,9 @@ static void svc_export_request(struct cache_detail *cd, | |||
304 | (*bpp)[-1] = '\n'; | 347 | (*bpp)[-1] = '\n'; |
305 | } | 348 | } |
306 | 349 | ||
307 | static struct svc_export *svc_export_lookup(struct svc_export *, int); | 350 | static struct svc_export *svc_export_update(struct svc_export *new, |
351 | struct svc_export *old); | ||
352 | static struct svc_export *svc_export_lookup(struct svc_export *); | ||
308 | 353 | ||
309 | static int check_export(struct inode *inode, int flags) | 354 | static int check_export(struct inode *inode, int flags) |
310 | { | 355 | { |
@@ -417,11 +462,16 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
417 | if (err) goto out; | 462 | if (err) goto out; |
418 | } | 463 | } |
419 | 464 | ||
420 | expp = svc_export_lookup(&exp, 1); | 465 | expp = svc_export_lookup(&exp); |
421 | if (expp) | 466 | if (expp) |
422 | exp_put(expp); | 467 | expp = svc_export_update(&exp, expp); |
423 | err = 0; | 468 | else |
469 | err = -ENOMEM; | ||
424 | cache_flush(); | 470 | cache_flush(); |
471 | if (expp == NULL) | ||
472 | err = -ENOMEM; | ||
473 | else | ||
474 | exp_put(expp); | ||
425 | out: | 475 | out: |
426 | if (nd.dentry) | 476 | if (nd.dentry) |
427 | path_release(&nd); | 477 | path_release(&nd); |
@@ -455,6 +505,46 @@ static int svc_export_show(struct seq_file *m, | |||
455 | seq_puts(m, ")\n"); | 505 | seq_puts(m, ")\n"); |
456 | return 0; | 506 | return 0; |
457 | } | 507 | } |
508 | static int svc_export_match(struct cache_head *a, struct cache_head *b) | ||
509 | { | ||
510 | struct svc_export *orig = container_of(a, struct svc_export, h); | ||
511 | struct svc_export *new = container_of(b, struct svc_export, h); | ||
512 | return orig->ex_client == new->ex_client && | ||
513 | orig->ex_dentry == new->ex_dentry && | ||
514 | orig->ex_mnt == new->ex_mnt; | ||
515 | } | ||
516 | |||
517 | static void svc_export_init(struct cache_head *cnew, struct cache_head *citem) | ||
518 | { | ||
519 | struct svc_export *new = container_of(cnew, struct svc_export, h); | ||
520 | struct svc_export *item = container_of(citem, struct svc_export, h); | ||
521 | |||
522 | kref_get(&item->ex_client->ref); | ||
523 | new->ex_client = item->ex_client; | ||
524 | new->ex_dentry = dget(item->ex_dentry); | ||
525 | new->ex_mnt = mntget(item->ex_mnt); | ||
526 | } | ||
527 | |||
528 | static void export_update(struct cache_head *cnew, struct cache_head *citem) | ||
529 | { | ||
530 | struct svc_export *new = container_of(cnew, struct svc_export, h); | ||
531 | struct svc_export *item = container_of(citem, struct svc_export, h); | ||
532 | |||
533 | new->ex_flags = item->ex_flags; | ||
534 | new->ex_anon_uid = item->ex_anon_uid; | ||
535 | new->ex_anon_gid = item->ex_anon_gid; | ||
536 | new->ex_fsid = item->ex_fsid; | ||
537 | } | ||
538 | |||
539 | static struct cache_head *svc_export_alloc(void) | ||
540 | { | ||
541 | struct svc_export *i = kmalloc(sizeof(*i), GFP_KERNEL); | ||
542 | if (i) | ||
543 | return &i->h; | ||
544 | else | ||
545 | return NULL; | ||
546 | } | ||
547 | |||
458 | struct cache_detail svc_export_cache = { | 548 | struct cache_detail svc_export_cache = { |
459 | .owner = THIS_MODULE, | 549 | .owner = THIS_MODULE, |
460 | .hash_size = EXPORT_HASHMAX, | 550 | .hash_size = EXPORT_HASHMAX, |
@@ -464,34 +554,49 @@ struct cache_detail svc_export_cache = { | |||
464 | .cache_request = svc_export_request, | 554 | .cache_request = svc_export_request, |
465 | .cache_parse = svc_export_parse, | 555 | .cache_parse = svc_export_parse, |
466 | .cache_show = svc_export_show, | 556 | .cache_show = svc_export_show, |
557 | .match = svc_export_match, | ||
558 | .init = svc_export_init, | ||
559 | .update = export_update, | ||
560 | .alloc = svc_export_alloc, | ||
467 | }; | 561 | }; |
468 | 562 | ||
469 | static inline int svc_export_match(struct svc_export *a, struct svc_export *b) | 563 | static struct svc_export * |
564 | svc_export_lookup(struct svc_export *exp) | ||
470 | { | 565 | { |
471 | return a->ex_client == b->ex_client && | 566 | struct cache_head *ch; |
472 | a->ex_dentry == b->ex_dentry && | 567 | int hash; |
473 | a->ex_mnt == b->ex_mnt; | 568 | hash = hash_ptr(exp->ex_client, EXPORT_HASHBITS); |
474 | } | 569 | hash ^= hash_ptr(exp->ex_dentry, EXPORT_HASHBITS); |
475 | static inline void svc_export_init(struct svc_export *new, struct svc_export *item) | 570 | hash ^= hash_ptr(exp->ex_mnt, EXPORT_HASHBITS); |
476 | { | 571 | |
477 | cache_get(&item->ex_client->h); | 572 | ch = sunrpc_cache_lookup(&svc_export_cache, &exp->h, |
478 | new->ex_client = item->ex_client; | 573 | hash); |
479 | new->ex_dentry = dget(item->ex_dentry); | 574 | if (ch) |
480 | new->ex_mnt = mntget(item->ex_mnt); | 575 | return container_of(ch, struct svc_export, h); |
576 | else | ||
577 | return NULL; | ||
481 | } | 578 | } |
482 | 579 | ||
483 | static inline void svc_export_update(struct svc_export *new, struct svc_export *item) | 580 | static struct svc_export * |
581 | svc_export_update(struct svc_export *new, struct svc_export *old) | ||
484 | { | 582 | { |
485 | new->ex_flags = item->ex_flags; | 583 | struct cache_head *ch; |
486 | new->ex_anon_uid = item->ex_anon_uid; | 584 | int hash; |
487 | new->ex_anon_gid = item->ex_anon_gid; | 585 | hash = hash_ptr(old->ex_client, EXPORT_HASHBITS); |
488 | new->ex_fsid = item->ex_fsid; | 586 | hash ^= hash_ptr(old->ex_dentry, EXPORT_HASHBITS); |
587 | hash ^= hash_ptr(old->ex_mnt, EXPORT_HASHBITS); | ||
588 | |||
589 | ch = sunrpc_cache_update(&svc_export_cache, &new->h, | ||
590 | &old->h, | ||
591 | hash); | ||
592 | if (ch) | ||
593 | return container_of(ch, struct svc_export, h); | ||
594 | else | ||
595 | return NULL; | ||
489 | } | 596 | } |
490 | 597 | ||
491 | static DefineSimpleCacheLookup(svc_export,1) /* allow inplace updates */ | ||
492 | 598 | ||
493 | 599 | static struct svc_expkey * | |
494 | struct svc_expkey * | ||
495 | exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp) | 600 | exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp) |
496 | { | 601 | { |
497 | struct svc_expkey key, *ek; | 602 | struct svc_expkey key, *ek; |
@@ -504,7 +609,7 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp) | |||
504 | key.ek_fsidtype = fsid_type; | 609 | key.ek_fsidtype = fsid_type; |
505 | memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); | 610 | memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); |
506 | 611 | ||
507 | ek = svc_expkey_lookup(&key, 0); | 612 | ek = svc_expkey_lookup(&key); |
508 | if (ek != NULL) | 613 | if (ek != NULL) |
509 | if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp))) | 614 | if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp))) |
510 | ek = ERR_PTR(err); | 615 | ek = ERR_PTR(err); |
@@ -519,13 +624,16 @@ static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv, | |||
519 | key.ek_client = clp; | 624 | key.ek_client = clp; |
520 | key.ek_fsidtype = fsid_type; | 625 | key.ek_fsidtype = fsid_type; |
521 | memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); | 626 | memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); |
522 | key.ek_export = exp; | 627 | key.ek_mnt = exp->ex_mnt; |
628 | key.ek_dentry = exp->ex_dentry; | ||
523 | key.h.expiry_time = NEVER; | 629 | key.h.expiry_time = NEVER; |
524 | key.h.flags = 0; | 630 | key.h.flags = 0; |
525 | 631 | ||
526 | ek = svc_expkey_lookup(&key, 1); | 632 | ek = svc_expkey_lookup(&key); |
633 | if (ek) | ||
634 | ek = svc_expkey_update(&key,ek); | ||
527 | if (ek) { | 635 | if (ek) { |
528 | expkey_put(&ek->h, &svc_expkey_cache); | 636 | cache_put(&ek->h, &svc_expkey_cache); |
529 | return 0; | 637 | return 0; |
530 | } | 638 | } |
531 | return -ENOMEM; | 639 | return -ENOMEM; |
@@ -573,7 +681,7 @@ exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry, | |||
573 | key.ex_mnt = mnt; | 681 | key.ex_mnt = mnt; |
574 | key.ex_dentry = dentry; | 682 | key.ex_dentry = dentry; |
575 | 683 | ||
576 | exp = svc_export_lookup(&key, 0); | 684 | exp = svc_export_lookup(&key); |
577 | if (exp != NULL) | 685 | if (exp != NULL) |
578 | switch (cache_check(&svc_export_cache, &exp->h, reqp)) { | 686 | switch (cache_check(&svc_export_cache, &exp->h, reqp)) { |
579 | case 0: break; | 687 | case 0: break; |
@@ -654,7 +762,7 @@ static void exp_fsid_unhash(struct svc_export *exp) | |||
654 | ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid); | 762 | ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid); |
655 | if (ek && !IS_ERR(ek)) { | 763 | if (ek && !IS_ERR(ek)) { |
656 | ek->h.expiry_time = get_seconds()-1; | 764 | ek->h.expiry_time = get_seconds()-1; |
657 | expkey_put(&ek->h, &svc_expkey_cache); | 765 | cache_put(&ek->h, &svc_expkey_cache); |
658 | } | 766 | } |
659 | svc_expkey_cache.nextcheck = get_seconds(); | 767 | svc_expkey_cache.nextcheck = get_seconds(); |
660 | } | 768 | } |
@@ -692,7 +800,7 @@ static void exp_unhash(struct svc_export *exp) | |||
692 | ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino); | 800 | ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino); |
693 | if (ek && !IS_ERR(ek)) { | 801 | if (ek && !IS_ERR(ek)) { |
694 | ek->h.expiry_time = get_seconds()-1; | 802 | ek->h.expiry_time = get_seconds()-1; |
695 | expkey_put(&ek->h, &svc_expkey_cache); | 803 | cache_put(&ek->h, &svc_expkey_cache); |
696 | } | 804 | } |
697 | svc_expkey_cache.nextcheck = get_seconds(); | 805 | svc_expkey_cache.nextcheck = get_seconds(); |
698 | } | 806 | } |
@@ -741,8 +849,8 @@ exp_export(struct nfsctl_export *nxp) | |||
741 | if ((nxp->ex_flags & NFSEXP_FSID) && | 849 | if ((nxp->ex_flags & NFSEXP_FSID) && |
742 | (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) && | 850 | (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) && |
743 | !IS_ERR(fsid_key) && | 851 | !IS_ERR(fsid_key) && |
744 | fsid_key->ek_export && | 852 | fsid_key->ek_mnt && |
745 | fsid_key->ek_export != exp) | 853 | (fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) ) |
746 | goto finish; | 854 | goto finish; |
747 | 855 | ||
748 | if (exp) { | 856 | if (exp) { |
@@ -775,13 +883,13 @@ exp_export(struct nfsctl_export *nxp) | |||
775 | new.ex_anon_gid = nxp->ex_anon_gid; | 883 | new.ex_anon_gid = nxp->ex_anon_gid; |
776 | new.ex_fsid = nxp->ex_dev; | 884 | new.ex_fsid = nxp->ex_dev; |
777 | 885 | ||
778 | exp = svc_export_lookup(&new, 1); | 886 | exp = svc_export_lookup(&new); |
887 | if (exp) | ||
888 | exp = svc_export_update(&new, exp); | ||
779 | 889 | ||
780 | if (exp == NULL) | 890 | if (!exp) |
781 | goto finish; | 891 | goto finish; |
782 | 892 | ||
783 | err = 0; | ||
784 | |||
785 | if (exp_hash(clp, exp) || | 893 | if (exp_hash(clp, exp) || |
786 | exp_fsid_hash(clp, exp)) { | 894 | exp_fsid_hash(clp, exp)) { |
787 | /* failed to create at least one index */ | 895 | /* failed to create at least one index */ |
@@ -794,7 +902,7 @@ finish: | |||
794 | if (exp) | 902 | if (exp) |
795 | exp_put(exp); | 903 | exp_put(exp); |
796 | if (fsid_key && !IS_ERR(fsid_key)) | 904 | if (fsid_key && !IS_ERR(fsid_key)) |
797 | expkey_put(&fsid_key->h, &svc_expkey_cache); | 905 | cache_put(&fsid_key->h, &svc_expkey_cache); |
798 | if (clp) | 906 | if (clp) |
799 | auth_domain_put(clp); | 907 | auth_domain_put(clp); |
800 | path_release(&nd); | 908 | path_release(&nd); |
@@ -912,6 +1020,24 @@ out: | |||
912 | return err; | 1020 | return err; |
913 | } | 1021 | } |
914 | 1022 | ||
1023 | struct svc_export * | ||
1024 | exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, | ||
1025 | struct cache_req *reqp) | ||
1026 | { | ||
1027 | struct svc_export *exp; | ||
1028 | struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp); | ||
1029 | if (!ek || IS_ERR(ek)) | ||
1030 | return ERR_PTR(PTR_ERR(ek)); | ||
1031 | |||
1032 | exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp); | ||
1033 | cache_put(&ek->h, &svc_expkey_cache); | ||
1034 | |||
1035 | if (!exp || IS_ERR(exp)) | ||
1036 | return ERR_PTR(PTR_ERR(exp)); | ||
1037 | return exp; | ||
1038 | } | ||
1039 | |||
1040 | |||
915 | /* | 1041 | /* |
916 | * Called when we need the filehandle for the root of the pseudofs, | 1042 | * Called when we need the filehandle for the root of the pseudofs, |
917 | * for a given NFSv4 client. The root is defined to be the | 1043 | * for a given NFSv4 client. The root is defined to be the |
@@ -922,6 +1048,7 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, | |||
922 | struct cache_req *creq) | 1048 | struct cache_req *creq) |
923 | { | 1049 | { |
924 | struct svc_expkey *fsid_key; | 1050 | struct svc_expkey *fsid_key; |
1051 | struct svc_export *exp; | ||
925 | int rv; | 1052 | int rv; |
926 | u32 fsidv[2]; | 1053 | u32 fsidv[2]; |
927 | 1054 | ||
@@ -933,9 +1060,15 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, | |||
933 | if (!fsid_key || IS_ERR(fsid_key)) | 1060 | if (!fsid_key || IS_ERR(fsid_key)) |
934 | return nfserr_perm; | 1061 | return nfserr_perm; |
935 | 1062 | ||
936 | rv = fh_compose(fhp, fsid_key->ek_export, | 1063 | exp = exp_get_by_name(clp, fsid_key->ek_mnt, fsid_key->ek_dentry, creq); |
937 | fsid_key->ek_export->ex_dentry, NULL); | 1064 | if (exp == NULL) |
938 | expkey_put(&fsid_key->h, &svc_expkey_cache); | 1065 | rv = nfserr_perm; |
1066 | else if (IS_ERR(exp)) | ||
1067 | rv = nfserrno(PTR_ERR(exp)); | ||
1068 | else | ||
1069 | rv = fh_compose(fhp, exp, | ||
1070 | fsid_key->ek_dentry, NULL); | ||
1071 | cache_put(&fsid_key->h, &svc_expkey_cache); | ||
939 | return rv; | 1072 | return rv; |
940 | } | 1073 | } |
941 | 1074 | ||
@@ -1054,7 +1187,7 @@ static int e_show(struct seq_file *m, void *p) | |||
1054 | cache_get(&exp->h); | 1187 | cache_get(&exp->h); |
1055 | if (cache_check(&svc_export_cache, &exp->h, NULL)) | 1188 | if (cache_check(&svc_export_cache, &exp->h, NULL)) |
1056 | return 0; | 1189 | return 0; |
1057 | if (cache_put(&exp->h, &svc_export_cache)) BUG(); | 1190 | cache_put(&exp->h, &svc_export_cache); |
1058 | return svc_export_show(m, &svc_export_cache, cp); | 1191 | return svc_export_show(m, &svc_export_cache, cp); |
1059 | } | 1192 | } |
1060 | 1193 | ||
@@ -1129,7 +1262,6 @@ exp_delclient(struct nfsctl_client *ncp) | |||
1129 | */ | 1262 | */ |
1130 | if (dom) { | 1263 | if (dom) { |
1131 | err = auth_unix_forget_old(dom); | 1264 | err = auth_unix_forget_old(dom); |
1132 | dom->h.expiry_time = get_seconds(); | ||
1133 | auth_domain_put(dom); | 1265 | auth_domain_put(dom); |
1134 | } | 1266 | } |
1135 | 1267 | ||
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 13369650cdf9..4b6aa60dfceb 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c | |||
@@ -76,21 +76,18 @@ struct ent { | |||
76 | char authname[IDMAP_NAMESZ]; | 76 | char authname[IDMAP_NAMESZ]; |
77 | }; | 77 | }; |
78 | 78 | ||
79 | #define DefineSimpleCacheLookupMap(STRUCT, FUNC) \ | ||
80 | DefineCacheLookup(struct STRUCT, h, FUNC##_lookup, \ | ||
81 | (struct STRUCT *item, int set), /*no setup */, \ | ||
82 | & FUNC##_cache, FUNC##_hash(item), FUNC##_match(item, tmp), \ | ||
83 | STRUCT##_init(new, item), STRUCT##_update(tmp, item), 0) | ||
84 | |||
85 | /* Common entry handling */ | 79 | /* Common entry handling */ |
86 | 80 | ||
87 | #define ENT_HASHBITS 8 | 81 | #define ENT_HASHBITS 8 |
88 | #define ENT_HASHMAX (1 << ENT_HASHBITS) | 82 | #define ENT_HASHMAX (1 << ENT_HASHBITS) |
89 | #define ENT_HASHMASK (ENT_HASHMAX - 1) | 83 | #define ENT_HASHMASK (ENT_HASHMAX - 1) |
90 | 84 | ||
91 | static inline void | 85 | static void |
92 | ent_init(struct ent *new, struct ent *itm) | 86 | ent_init(struct cache_head *cnew, struct cache_head *citm) |
93 | { | 87 | { |
88 | struct ent *new = container_of(cnew, struct ent, h); | ||
89 | struct ent *itm = container_of(citm, struct ent, h); | ||
90 | |||
94 | new->id = itm->id; | 91 | new->id = itm->id; |
95 | new->type = itm->type; | 92 | new->type = itm->type; |
96 | 93 | ||
@@ -98,19 +95,21 @@ ent_init(struct ent *new, struct ent *itm) | |||
98 | strlcpy(new->authname, itm->authname, sizeof(new->name)); | 95 | strlcpy(new->authname, itm->authname, sizeof(new->name)); |
99 | } | 96 | } |
100 | 97 | ||
101 | static inline void | 98 | static void |
102 | ent_update(struct ent *new, struct ent *itm) | 99 | ent_put(struct kref *ref) |
103 | { | 100 | { |
104 | ent_init(new, itm); | 101 | struct ent *map = container_of(ref, struct ent, h.ref); |
102 | kfree(map); | ||
105 | } | 103 | } |
106 | 104 | ||
107 | static void | 105 | static struct cache_head * |
108 | ent_put(struct cache_head *ch, struct cache_detail *cd) | 106 | ent_alloc(void) |
109 | { | 107 | { |
110 | if (cache_put(ch, cd)) { | 108 | struct ent *e = kmalloc(sizeof(*e), GFP_KERNEL); |
111 | struct ent *map = container_of(ch, struct ent, h); | 109 | if (e) |
112 | kfree(map); | 110 | return &e->h; |
113 | } | 111 | else |
112 | return NULL; | ||
114 | } | 113 | } |
115 | 114 | ||
116 | /* | 115 | /* |
@@ -149,9 +148,12 @@ idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, | |||
149 | (*bpp)[-1] = '\n'; | 148 | (*bpp)[-1] = '\n'; |
150 | } | 149 | } |
151 | 150 | ||
152 | static inline int | 151 | static int |
153 | idtoname_match(struct ent *a, struct ent *b) | 152 | idtoname_match(struct cache_head *ca, struct cache_head *cb) |
154 | { | 153 | { |
154 | struct ent *a = container_of(ca, struct ent, h); | ||
155 | struct ent *b = container_of(cb, struct ent, h); | ||
156 | |||
155 | return (a->id == b->id && a->type == b->type && | 157 | return (a->id == b->id && a->type == b->type && |
156 | strcmp(a->authname, b->authname) == 0); | 158 | strcmp(a->authname, b->authname) == 0); |
157 | } | 159 | } |
@@ -184,7 +186,8 @@ warn_no_idmapd(struct cache_detail *detail) | |||
184 | 186 | ||
185 | 187 | ||
186 | static int idtoname_parse(struct cache_detail *, char *, int); | 188 | static int idtoname_parse(struct cache_detail *, char *, int); |
187 | static struct ent *idtoname_lookup(struct ent *, int); | 189 | static struct ent *idtoname_lookup(struct ent *); |
190 | static struct ent *idtoname_update(struct ent *, struct ent *); | ||
188 | 191 | ||
189 | static struct cache_detail idtoname_cache = { | 192 | static struct cache_detail idtoname_cache = { |
190 | .owner = THIS_MODULE, | 193 | .owner = THIS_MODULE, |
@@ -196,6 +199,10 @@ static struct cache_detail idtoname_cache = { | |||
196 | .cache_parse = idtoname_parse, | 199 | .cache_parse = idtoname_parse, |
197 | .cache_show = idtoname_show, | 200 | .cache_show = idtoname_show, |
198 | .warn_no_listener = warn_no_idmapd, | 201 | .warn_no_listener = warn_no_idmapd, |
202 | .match = idtoname_match, | ||
203 | .init = ent_init, | ||
204 | .update = ent_init, | ||
205 | .alloc = ent_alloc, | ||
199 | }; | 206 | }; |
200 | 207 | ||
201 | int | 208 | int |
@@ -238,6 +245,11 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen) | |||
238 | if (ent.h.expiry_time == 0) | 245 | if (ent.h.expiry_time == 0) |
239 | goto out; | 246 | goto out; |
240 | 247 | ||
248 | error = -ENOMEM; | ||
249 | res = idtoname_lookup(&ent); | ||
250 | if (!res) | ||
251 | goto out; | ||
252 | |||
241 | /* Name */ | 253 | /* Name */ |
242 | error = qword_get(&buf, buf1, PAGE_SIZE); | 254 | error = qword_get(&buf, buf1, PAGE_SIZE); |
243 | if (error == -EINVAL) | 255 | if (error == -EINVAL) |
@@ -252,10 +264,11 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen) | |||
252 | memcpy(ent.name, buf1, sizeof(ent.name)); | 264 | memcpy(ent.name, buf1, sizeof(ent.name)); |
253 | } | 265 | } |
254 | error = -ENOMEM; | 266 | error = -ENOMEM; |
255 | if ((res = idtoname_lookup(&ent, 1)) == NULL) | 267 | res = idtoname_update(&ent, res); |
268 | if (res == NULL) | ||
256 | goto out; | 269 | goto out; |
257 | 270 | ||
258 | ent_put(&res->h, &idtoname_cache); | 271 | cache_put(&res->h, &idtoname_cache); |
259 | 272 | ||
260 | error = 0; | 273 | error = 0; |
261 | out: | 274 | out: |
@@ -264,7 +277,31 @@ out: | |||
264 | return error; | 277 | return error; |
265 | } | 278 | } |
266 | 279 | ||
267 | static DefineSimpleCacheLookupMap(ent, idtoname); | 280 | |
281 | static struct ent * | ||
282 | idtoname_lookup(struct ent *item) | ||
283 | { | ||
284 | struct cache_head *ch = sunrpc_cache_lookup(&idtoname_cache, | ||
285 | &item->h, | ||
286 | idtoname_hash(item)); | ||
287 | if (ch) | ||
288 | return container_of(ch, struct ent, h); | ||
289 | else | ||
290 | return NULL; | ||
291 | } | ||
292 | |||
293 | static struct ent * | ||
294 | idtoname_update(struct ent *new, struct ent *old) | ||
295 | { | ||
296 | struct cache_head *ch = sunrpc_cache_update(&idtoname_cache, | ||
297 | &new->h, &old->h, | ||
298 | idtoname_hash(new)); | ||
299 | if (ch) | ||
300 | return container_of(ch, struct ent, h); | ||
301 | else | ||
302 | return NULL; | ||
303 | } | ||
304 | |||
268 | 305 | ||
269 | /* | 306 | /* |
270 | * Name -> ID cache | 307 | * Name -> ID cache |
@@ -291,9 +328,12 @@ nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, | |||
291 | (*bpp)[-1] = '\n'; | 328 | (*bpp)[-1] = '\n'; |
292 | } | 329 | } |
293 | 330 | ||
294 | static inline int | 331 | static int |
295 | nametoid_match(struct ent *a, struct ent *b) | 332 | nametoid_match(struct cache_head *ca, struct cache_head *cb) |
296 | { | 333 | { |
334 | struct ent *a = container_of(ca, struct ent, h); | ||
335 | struct ent *b = container_of(cb, struct ent, h); | ||
336 | |||
297 | return (a->type == b->type && strcmp(a->name, b->name) == 0 && | 337 | return (a->type == b->type && strcmp(a->name, b->name) == 0 && |
298 | strcmp(a->authname, b->authname) == 0); | 338 | strcmp(a->authname, b->authname) == 0); |
299 | } | 339 | } |
@@ -317,7 +357,8 @@ nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) | |||
317 | return 0; | 357 | return 0; |
318 | } | 358 | } |
319 | 359 | ||
320 | static struct ent *nametoid_lookup(struct ent *, int); | 360 | static struct ent *nametoid_lookup(struct ent *); |
361 | static struct ent *nametoid_update(struct ent *, struct ent *); | ||
321 | static int nametoid_parse(struct cache_detail *, char *, int); | 362 | static int nametoid_parse(struct cache_detail *, char *, int); |
322 | 363 | ||
323 | static struct cache_detail nametoid_cache = { | 364 | static struct cache_detail nametoid_cache = { |
@@ -330,6 +371,10 @@ static struct cache_detail nametoid_cache = { | |||
330 | .cache_parse = nametoid_parse, | 371 | .cache_parse = nametoid_parse, |
331 | .cache_show = nametoid_show, | 372 | .cache_show = nametoid_show, |
332 | .warn_no_listener = warn_no_idmapd, | 373 | .warn_no_listener = warn_no_idmapd, |
374 | .match = nametoid_match, | ||
375 | .init = ent_init, | ||
376 | .update = ent_init, | ||
377 | .alloc = ent_alloc, | ||
333 | }; | 378 | }; |
334 | 379 | ||
335 | static int | 380 | static int |
@@ -379,10 +424,14 @@ nametoid_parse(struct cache_detail *cd, char *buf, int buflen) | |||
379 | set_bit(CACHE_NEGATIVE, &ent.h.flags); | 424 | set_bit(CACHE_NEGATIVE, &ent.h.flags); |
380 | 425 | ||
381 | error = -ENOMEM; | 426 | error = -ENOMEM; |
382 | if ((res = nametoid_lookup(&ent, 1)) == NULL) | 427 | res = nametoid_lookup(&ent); |
428 | if (res == NULL) | ||
429 | goto out; | ||
430 | res = nametoid_update(&ent, res); | ||
431 | if (res == NULL) | ||
383 | goto out; | 432 | goto out; |
384 | 433 | ||
385 | ent_put(&res->h, &nametoid_cache); | 434 | cache_put(&res->h, &nametoid_cache); |
386 | error = 0; | 435 | error = 0; |
387 | out: | 436 | out: |
388 | kfree(buf1); | 437 | kfree(buf1); |
@@ -390,7 +439,30 @@ out: | |||
390 | return (error); | 439 | return (error); |
391 | } | 440 | } |
392 | 441 | ||
393 | static DefineSimpleCacheLookupMap(ent, nametoid); | 442 | |
443 | static struct ent * | ||
444 | nametoid_lookup(struct ent *item) | ||
445 | { | ||
446 | struct cache_head *ch = sunrpc_cache_lookup(&nametoid_cache, | ||
447 | &item->h, | ||
448 | nametoid_hash(item)); | ||
449 | if (ch) | ||
450 | return container_of(ch, struct ent, h); | ||
451 | else | ||
452 | return NULL; | ||
453 | } | ||
454 | |||
455 | static struct ent * | ||
456 | nametoid_update(struct ent *new, struct ent *old) | ||
457 | { | ||
458 | struct cache_head *ch = sunrpc_cache_update(&nametoid_cache, | ||
459 | &new->h, &old->h, | ||
460 | nametoid_hash(new)); | ||
461 | if (ch) | ||
462 | return container_of(ch, struct ent, h); | ||
463 | else | ||
464 | return NULL; | ||
465 | } | ||
394 | 466 | ||
395 | /* | 467 | /* |
396 | * Exported API | 468 | * Exported API |
@@ -458,24 +530,24 @@ idmap_defer(struct cache_req *req) | |||
458 | } | 530 | } |
459 | 531 | ||
460 | static inline int | 532 | static inline int |
461 | do_idmap_lookup(struct ent *(*lookup_fn)(struct ent *, int), struct ent *key, | 533 | do_idmap_lookup(struct ent *(*lookup_fn)(struct ent *), struct ent *key, |
462 | struct cache_detail *detail, struct ent **item, | 534 | struct cache_detail *detail, struct ent **item, |
463 | struct idmap_defer_req *mdr) | 535 | struct idmap_defer_req *mdr) |
464 | { | 536 | { |
465 | *item = lookup_fn(key, 0); | 537 | *item = lookup_fn(key); |
466 | if (!*item) | 538 | if (!*item) |
467 | return -ENOMEM; | 539 | return -ENOMEM; |
468 | return cache_check(detail, &(*item)->h, &mdr->req); | 540 | return cache_check(detail, &(*item)->h, &mdr->req); |
469 | } | 541 | } |
470 | 542 | ||
471 | static inline int | 543 | static inline int |
472 | do_idmap_lookup_nowait(struct ent *(*lookup_fn)(struct ent *, int), | 544 | do_idmap_lookup_nowait(struct ent *(*lookup_fn)(struct ent *), |
473 | struct ent *key, struct cache_detail *detail, | 545 | struct ent *key, struct cache_detail *detail, |
474 | struct ent **item) | 546 | struct ent **item) |
475 | { | 547 | { |
476 | int ret = -ENOMEM; | 548 | int ret = -ENOMEM; |
477 | 549 | ||
478 | *item = lookup_fn(key, 0); | 550 | *item = lookup_fn(key); |
479 | if (!*item) | 551 | if (!*item) |
480 | goto out_err; | 552 | goto out_err; |
481 | ret = -ETIMEDOUT; | 553 | ret = -ETIMEDOUT; |
@@ -488,7 +560,7 @@ do_idmap_lookup_nowait(struct ent *(*lookup_fn)(struct ent *, int), | |||
488 | goto out_put; | 560 | goto out_put; |
489 | return 0; | 561 | return 0; |
490 | out_put: | 562 | out_put: |
491 | ent_put(&(*item)->h, detail); | 563 | cache_put(&(*item)->h, detail); |
492 | out_err: | 564 | out_err: |
493 | *item = NULL; | 565 | *item = NULL; |
494 | return ret; | 566 | return ret; |
@@ -496,7 +568,7 @@ out_err: | |||
496 | 568 | ||
497 | static int | 569 | static int |
498 | idmap_lookup(struct svc_rqst *rqstp, | 570 | idmap_lookup(struct svc_rqst *rqstp, |
499 | struct ent *(*lookup_fn)(struct ent *, int), struct ent *key, | 571 | struct ent *(*lookup_fn)(struct ent *), struct ent *key, |
500 | struct cache_detail *detail, struct ent **item) | 572 | struct cache_detail *detail, struct ent **item) |
501 | { | 573 | { |
502 | struct idmap_defer_req *mdr; | 574 | struct idmap_defer_req *mdr; |
@@ -539,7 +611,7 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen | |||
539 | if (ret) | 611 | if (ret) |
540 | return ret; | 612 | return ret; |
541 | *id = item->id; | 613 | *id = item->id; |
542 | ent_put(&item->h, &nametoid_cache); | 614 | cache_put(&item->h, &nametoid_cache); |
543 | return 0; | 615 | return 0; |
544 | } | 616 | } |
545 | 617 | ||
@@ -561,7 +633,7 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) | |||
561 | ret = strlen(item->name); | 633 | ret = strlen(item->name); |
562 | BUG_ON(ret > IDMAP_NAMESZ); | 634 | BUG_ON(ret > IDMAP_NAMESZ); |
563 | memcpy(name, item->name, ret); | 635 | memcpy(name, item->name, ret); |
564 | ent_put(&item->h, &idtoname_cache); | 636 | cache_put(&item->h, &idtoname_cache); |
565 | return ret; | 637 | return ret; |
566 | } | 638 | } |
567 | 639 | ||
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 7a3e397b4ed3..3f2ec2e6d06c 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
@@ -506,7 +506,7 @@ fh_put(struct svc_fh *fhp) | |||
506 | nfsd_nr_put++; | 506 | nfsd_nr_put++; |
507 | } | 507 | } |
508 | if (exp) { | 508 | if (exp) { |
509 | svc_export_put(&exp->h, &svc_export_cache); | 509 | cache_put(&exp->h, &svc_export_cache); |
510 | fhp->fh_export = NULL; | 510 | fhp->fh_export = NULL; |
511 | } | 511 | } |
512 | return; | 512 | return; |
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index f924f459bdb8..af0cb4b9e784 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
@@ -297,6 +297,25 @@ struct kobj_type ktype_part = { | |||
297 | .sysfs_ops = &part_sysfs_ops, | 297 | .sysfs_ops = &part_sysfs_ops, |
298 | }; | 298 | }; |
299 | 299 | ||
300 | static inline void partition_sysfs_add_subdir(struct hd_struct *p) | ||
301 | { | ||
302 | struct kobject *k; | ||
303 | |||
304 | k = kobject_get(&p->kobj); | ||
305 | p->holder_dir = kobject_add_dir(k, "holders"); | ||
306 | kobject_put(k); | ||
307 | } | ||
308 | |||
309 | static inline void disk_sysfs_add_subdirs(struct gendisk *disk) | ||
310 | { | ||
311 | struct kobject *k; | ||
312 | |||
313 | k = kobject_get(&disk->kobj); | ||
314 | disk->holder_dir = kobject_add_dir(k, "holders"); | ||
315 | disk->slave_dir = kobject_add_dir(k, "slaves"); | ||
316 | kobject_put(k); | ||
317 | } | ||
318 | |||
300 | void delete_partition(struct gendisk *disk, int part) | 319 | void delete_partition(struct gendisk *disk, int part) |
301 | { | 320 | { |
302 | struct hd_struct *p = disk->part[part-1]; | 321 | struct hd_struct *p = disk->part[part-1]; |
@@ -310,6 +329,8 @@ void delete_partition(struct gendisk *disk, int part) | |||
310 | p->ios[0] = p->ios[1] = 0; | 329 | p->ios[0] = p->ios[1] = 0; |
311 | p->sectors[0] = p->sectors[1] = 0; | 330 | p->sectors[0] = p->sectors[1] = 0; |
312 | devfs_remove("%s/part%d", disk->devfs_name, part); | 331 | devfs_remove("%s/part%d", disk->devfs_name, part); |
332 | if (p->holder_dir) | ||
333 | kobject_unregister(p->holder_dir); | ||
313 | kobject_unregister(&p->kobj); | 334 | kobject_unregister(&p->kobj); |
314 | } | 335 | } |
315 | 336 | ||
@@ -337,6 +358,7 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) | |||
337 | p->kobj.parent = &disk->kobj; | 358 | p->kobj.parent = &disk->kobj; |
338 | p->kobj.ktype = &ktype_part; | 359 | p->kobj.ktype = &ktype_part; |
339 | kobject_register(&p->kobj); | 360 | kobject_register(&p->kobj); |
361 | partition_sysfs_add_subdir(p); | ||
340 | disk->part[part-1] = p; | 362 | disk->part[part-1] = p; |
341 | } | 363 | } |
342 | 364 | ||
@@ -383,6 +405,7 @@ void register_disk(struct gendisk *disk) | |||
383 | if ((err = kobject_add(&disk->kobj))) | 405 | if ((err = kobject_add(&disk->kobj))) |
384 | return; | 406 | return; |
385 | disk_sysfs_symlinks(disk); | 407 | disk_sysfs_symlinks(disk); |
408 | disk_sysfs_add_subdirs(disk); | ||
386 | kobject_uevent(&disk->kobj, KOBJ_ADD); | 409 | kobject_uevent(&disk->kobj, KOBJ_ADD); |
387 | 410 | ||
388 | /* No minors to use for partitions */ | 411 | /* No minors to use for partitions */ |
@@ -483,6 +506,10 @@ void del_gendisk(struct gendisk *disk) | |||
483 | 506 | ||
484 | devfs_remove_disk(disk); | 507 | devfs_remove_disk(disk); |
485 | 508 | ||
509 | if (disk->holder_dir) | ||
510 | kobject_unregister(disk->holder_dir); | ||
511 | if (disk->slave_dir) | ||
512 | kobject_unregister(disk->slave_dir); | ||
486 | if (disk->driverfs_dev) { | 513 | if (disk->driverfs_dev) { |
487 | char *disk_name = make_block_name(disk); | 514 | char *disk_name = make_block_name(disk); |
488 | sysfs_remove_link(&disk->kobj, "device"); | 515 | sysfs_remove_link(&disk->kobj, "device"); |
diff --git a/include/asm-alpha/mmzone.h b/include/asm-alpha/mmzone.h index a011ef4cf3d3..192d80c875b0 100644 --- a/include/asm-alpha/mmzone.h +++ b/include/asm-alpha/mmzone.h | |||
@@ -59,9 +59,6 @@ PLAT_NODE_DATA_LOCALNR(unsigned long p, int n) | |||
59 | #define kvaddr_to_nid(kaddr) pa_to_nid(__pa(kaddr)) | 59 | #define kvaddr_to_nid(kaddr) pa_to_nid(__pa(kaddr)) |
60 | #define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn) | 60 | #define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn) |
61 | 61 | ||
62 | #define local_mapnr(kvaddr) \ | ||
63 | ((__pa(kvaddr) >> PAGE_SHIFT) - node_start_pfn(kvaddr_to_nid(kvaddr))) | ||
64 | |||
65 | /* | 62 | /* |
66 | * Given a kaddr, LOCAL_BASE_ADDR finds the owning node of the memory | 63 | * Given a kaddr, LOCAL_BASE_ADDR finds the owning node of the memory |
67 | * and returns the kaddr corresponding to first physical page in the | 64 | * and returns the kaddr corresponding to first physical page in the |
@@ -86,8 +83,7 @@ PLAT_NODE_DATA_LOCALNR(unsigned long p, int n) | |||
86 | pte_t pte; \ | 83 | pte_t pte; \ |
87 | unsigned long pfn; \ | 84 | unsigned long pfn; \ |
88 | \ | 85 | \ |
89 | pfn = ((unsigned long)((page)-page_zone(page)->zone_mem_map)) << 32; \ | 86 | pfn = page_to_pfn(page) << 32; \ |
90 | pfn += page_zone(page)->zone_start_pfn << 32; \ | ||
91 | pte_val(pte) = pfn | pgprot_val(pgprot); \ | 87 | pte_val(pte) = pfn | pgprot_val(pgprot); \ |
92 | \ | 88 | \ |
93 | pte; \ | 89 | pte; \ |
@@ -104,19 +100,8 @@ PLAT_NODE_DATA_LOCALNR(unsigned long p, int n) | |||
104 | __xx; \ | 100 | __xx; \ |
105 | }) | 101 | }) |
106 | 102 | ||
107 | #define pfn_to_page(pfn) \ | ||
108 | ({ \ | ||
109 | unsigned long kaddr = (unsigned long)__va((pfn) << PAGE_SHIFT); \ | ||
110 | (NODE_DATA(kvaddr_to_nid(kaddr))->node_mem_map + local_mapnr(kaddr)); \ | ||
111 | }) | ||
112 | |||
113 | #define page_to_pfn(page) \ | ||
114 | ((page) - page_zone(page)->zone_mem_map + \ | ||
115 | (page_zone(page)->zone_start_pfn)) | ||
116 | |||
117 | #define page_to_pa(page) \ | 103 | #define page_to_pa(page) \ |
118 | ((( (page) - page_zone(page)->zone_mem_map ) \ | 104 | (page_to_pfn(page) << PAGE_SHIFT) |
119 | + page_zone(page)->zone_start_pfn) << PAGE_SHIFT) | ||
120 | 105 | ||
121 | #define pfn_to_nid(pfn) pa_to_nid(((u64)(pfn) << PAGE_SHIFT)) | 106 | #define pfn_to_nid(pfn) pa_to_nid(((u64)(pfn) << PAGE_SHIFT)) |
122 | #define pfn_valid(pfn) \ | 107 | #define pfn_valid(pfn) \ |
diff --git a/include/asm-alpha/page.h b/include/asm-alpha/page.h index fa0b41b164a7..61bcf70b5eac 100644 --- a/include/asm-alpha/page.h +++ b/include/asm-alpha/page.h | |||
@@ -85,8 +85,6 @@ typedef unsigned long pgprot_t; | |||
85 | #define __pa(x) ((unsigned long) (x) - PAGE_OFFSET) | 85 | #define __pa(x) ((unsigned long) (x) - PAGE_OFFSET) |
86 | #define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET)) | 86 | #define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET)) |
87 | #ifndef CONFIG_DISCONTIGMEM | 87 | #ifndef CONFIG_DISCONTIGMEM |
88 | #define pfn_to_page(pfn) (mem_map + (pfn)) | ||
89 | #define page_to_pfn(page) ((unsigned long)((page) - mem_map)) | ||
90 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) | 88 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) |
91 | 89 | ||
92 | #define pfn_valid(pfn) ((pfn) < max_mapnr) | 90 | #define pfn_valid(pfn) ((pfn) < max_mapnr) |
@@ -95,9 +93,9 @@ typedef unsigned long pgprot_t; | |||
95 | 93 | ||
96 | #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ | 94 | #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ |
97 | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) | 95 | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) |
98 | |||
99 | #endif /* __KERNEL__ */ | 96 | #endif /* __KERNEL__ */ |
100 | 97 | ||
98 | #include <asm-generic/memory_model.h> | ||
101 | #include <asm-generic/page.h> | 99 | #include <asm-generic/page.h> |
102 | 100 | ||
103 | #endif /* _ALPHA_PAGE_H */ | 101 | #endif /* _ALPHA_PAGE_H */ |
diff --git a/include/asm-arm/memory.h b/include/asm-arm/memory.h index b4e1146ab682..afa5c3ea077c 100644 --- a/include/asm-arm/memory.h +++ b/include/asm-arm/memory.h | |||
@@ -172,9 +172,7 @@ static inline __deprecated void *bus_to_virt(unsigned long x) | |||
172 | * virt_addr_valid(k) indicates whether a virtual address is valid | 172 | * virt_addr_valid(k) indicates whether a virtual address is valid |
173 | */ | 173 | */ |
174 | #ifndef CONFIG_DISCONTIGMEM | 174 | #ifndef CONFIG_DISCONTIGMEM |
175 | 175 | #define ARCH_PFN_OFFSET (PHYS_PFN_OFFSET) | |
176 | #define page_to_pfn(page) (((page) - mem_map) + PHYS_PFN_OFFSET) | ||
177 | #define pfn_to_page(pfn) ((mem_map + (pfn)) - PHYS_PFN_OFFSET) | ||
178 | #define pfn_valid(pfn) ((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr)) | 176 | #define pfn_valid(pfn) ((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr)) |
179 | 177 | ||
180 | #define virt_to_page(kaddr) (pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)) | 178 | #define virt_to_page(kaddr) (pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)) |
@@ -189,13 +187,8 @@ static inline __deprecated void *bus_to_virt(unsigned long x) | |||
189 | * around in memory. | 187 | * around in memory. |
190 | */ | 188 | */ |
191 | #include <linux/numa.h> | 189 | #include <linux/numa.h> |
192 | 190 | #define arch_pfn_to_nid(pfn) (PFN_TO_NID(pfn)) | |
193 | #define page_to_pfn(page) \ | 191 | #define arch_local_page_offset(pfn, nid) (LOCAL_MAP_NR((pfn) << PAGE_OFFSET)) |
194 | (( (page) - page_zone(page)->zone_mem_map) \ | ||
195 | + page_zone(page)->zone_start_pfn) | ||
196 | |||
197 | #define pfn_to_page(pfn) \ | ||
198 | (PFN_TO_MAPBASE(pfn) + LOCAL_MAP_NR((pfn) << PAGE_SHIFT)) | ||
199 | 192 | ||
200 | #define pfn_valid(pfn) \ | 193 | #define pfn_valid(pfn) \ |
201 | ({ \ | 194 | ({ \ |
@@ -243,4 +236,6 @@ static inline __deprecated void *bus_to_virt(unsigned long x) | |||
243 | 236 | ||
244 | #endif | 237 | #endif |
245 | 238 | ||
239 | #include <asm-generic/memory_model.h> | ||
240 | |||
246 | #endif | 241 | #endif |
diff --git a/include/asm-arm/rtc.h b/include/asm-arm/rtc.h index 370dfe77589d..1a5c9232a91e 100644 --- a/include/asm-arm/rtc.h +++ b/include/asm-arm/rtc.h | |||
@@ -25,9 +25,6 @@ struct rtc_ops { | |||
25 | int (*proc)(char *buf); | 25 | int (*proc)(char *buf); |
26 | }; | 26 | }; |
27 | 27 | ||
28 | void rtc_time_to_tm(unsigned long, struct rtc_time *); | ||
29 | int rtc_tm_to_time(struct rtc_time *, unsigned long *); | ||
30 | int rtc_valid_tm(struct rtc_time *); | ||
31 | void rtc_next_alarm_time(struct rtc_time *, struct rtc_time *, struct rtc_time *); | 28 | void rtc_next_alarm_time(struct rtc_time *, struct rtc_time *, struct rtc_time *); |
32 | void rtc_update(unsigned long, unsigned long); | 29 | void rtc_update(unsigned long, unsigned long); |
33 | int register_rtc(struct rtc_ops *); | 30 | int register_rtc(struct rtc_ops *); |
diff --git a/include/asm-arm26/memory.h b/include/asm-arm26/memory.h index 20d78616f650..a65f10b80dfb 100644 --- a/include/asm-arm26/memory.h +++ b/include/asm-arm26/memory.h | |||
@@ -81,8 +81,7 @@ static inline void *phys_to_virt(unsigned long x) | |||
81 | * virt_to_page(k) convert a _valid_ virtual address to struct page * | 81 | * virt_to_page(k) convert a _valid_ virtual address to struct page * |
82 | * virt_addr_valid(k) indicates whether a virtual address is valid | 82 | * virt_addr_valid(k) indicates whether a virtual address is valid |
83 | */ | 83 | */ |
84 | #define page_to_pfn(page) (((page) - mem_map) + PHYS_PFN_OFFSET) | 84 | #define ARCH_PFN_OFFSET (PHYS_PFN_OFFSET) |
85 | #define pfn_to_page(pfn) ((mem_map + (pfn)) - PHYS_PFN_OFFSET) | ||
86 | #define pfn_valid(pfn) ((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr)) | 85 | #define pfn_valid(pfn) ((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr)) |
87 | 86 | ||
88 | #define virt_to_page(kaddr) (pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)) | 87 | #define virt_to_page(kaddr) (pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)) |
@@ -98,4 +97,5 @@ static inline void *phys_to_virt(unsigned long x) | |||
98 | */ | 97 | */ |
99 | #define page_to_bus(page) (page_address(page)) | 98 | #define page_to_bus(page) (page_address(page)) |
100 | 99 | ||
100 | #include <asm-generic/memory_model.h> | ||
101 | #endif | 101 | #endif |
diff --git a/include/asm-cris/page.h b/include/asm-cris/page.h index c99c478c482f..3787633e6209 100644 --- a/include/asm-cris/page.h +++ b/include/asm-cris/page.h | |||
@@ -43,8 +43,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; | |||
43 | 43 | ||
44 | /* On CRIS the PFN numbers doesn't start at 0 so we have to compensate */ | 44 | /* On CRIS the PFN numbers doesn't start at 0 so we have to compensate */ |
45 | /* for that before indexing into the page table starting at mem_map */ | 45 | /* for that before indexing into the page table starting at mem_map */ |
46 | #define pfn_to_page(pfn) (mem_map + ((pfn) - (PAGE_OFFSET >> PAGE_SHIFT))) | 46 | #define ARCH_PFN_OFFSET (PAGE_OFFSET >> PAGE_SHIFT) |
47 | #define page_to_pfn(page) ((unsigned long)((page) - mem_map) + (PAGE_OFFSET >> PAGE_SHIFT)) | ||
48 | #define pfn_valid(pfn) (((pfn) - (PAGE_OFFSET >> PAGE_SHIFT)) < max_mapnr) | 47 | #define pfn_valid(pfn) (((pfn) - (PAGE_OFFSET >> PAGE_SHIFT)) < max_mapnr) |
49 | 48 | ||
50 | /* to index into the page map. our pages all start at physical addr PAGE_OFFSET so | 49 | /* to index into the page map. our pages all start at physical addr PAGE_OFFSET so |
@@ -77,6 +76,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; | |||
77 | 76 | ||
78 | #endif /* __KERNEL__ */ | 77 | #endif /* __KERNEL__ */ |
79 | 78 | ||
79 | #include <asm-generic/memory_model.h> | ||
80 | #include <asm-generic/page.h> | 80 | #include <asm-generic/page.h> |
81 | 81 | ||
82 | #endif /* _CRIS_PAGE_H */ | 82 | #endif /* _CRIS_PAGE_H */ |
diff --git a/include/asm-frv/futex.h b/include/asm-frv/futex.h index fca9d90e32c9..08b3d1da3583 100644 --- a/include/asm-frv/futex.h +++ b/include/asm-frv/futex.h | |||
@@ -9,5 +9,11 @@ | |||
9 | 9 | ||
10 | extern int futex_atomic_op_inuser(int encoded_op, int __user *uaddr); | 10 | extern int futex_atomic_op_inuser(int encoded_op, int __user *uaddr); |
11 | 11 | ||
12 | static inline int | ||
13 | futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) | ||
14 | { | ||
15 | return -ENOSYS; | ||
16 | } | ||
17 | |||
12 | #endif | 18 | #endif |
13 | #endif | 19 | #endif |
diff --git a/include/asm-frv/page.h b/include/asm-frv/page.h index b8221b611b5c..dc0f7e08a4c2 100644 --- a/include/asm-frv/page.h +++ b/include/asm-frv/page.h | |||
@@ -57,13 +57,9 @@ extern unsigned long min_low_pfn; | |||
57 | extern unsigned long max_pfn; | 57 | extern unsigned long max_pfn; |
58 | 58 | ||
59 | #ifdef CONFIG_MMU | 59 | #ifdef CONFIG_MMU |
60 | #define pfn_to_page(pfn) (mem_map + (pfn)) | ||
61 | #define page_to_pfn(page) ((unsigned long) ((page) - mem_map)) | ||
62 | #define pfn_valid(pfn) ((pfn) < max_mapnr) | 60 | #define pfn_valid(pfn) ((pfn) < max_mapnr) |
63 | |||
64 | #else | 61 | #else |
65 | #define pfn_to_page(pfn) (&mem_map[(pfn) - (PAGE_OFFSET >> PAGE_SHIFT)]) | 62 | #define ARCH_PFN_OFFSET (PAGE_OFFSET >> PAGE_SHIFT) |
66 | #define page_to_pfn(page) ((PAGE_OFFSET >> PAGE_SHIFT) + (unsigned long) ((page) - mem_map)) | ||
67 | #define pfn_valid(pfn) ((pfn) >= min_low_pfn && (pfn) < max_low_pfn) | 63 | #define pfn_valid(pfn) ((pfn) >= min_low_pfn && (pfn) < max_low_pfn) |
68 | 64 | ||
69 | #endif | 65 | #endif |
@@ -87,6 +83,7 @@ extern unsigned long max_pfn; | |||
87 | #define WANT_PAGE_VIRTUAL 1 | 83 | #define WANT_PAGE_VIRTUAL 1 |
88 | #endif | 84 | #endif |
89 | 85 | ||
86 | #include <asm-generic/memory_model.h> | ||
90 | #include <asm-generic/page.h> | 87 | #include <asm-generic/page.h> |
91 | 88 | ||
92 | #endif /* _ASM_PAGE_H */ | 89 | #endif /* _ASM_PAGE_H */ |
diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h index 3ae2c7347549..df893c160318 100644 --- a/include/asm-generic/futex.h +++ b/include/asm-generic/futex.h | |||
@@ -49,5 +49,11 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) | |||
49 | return ret; | 49 | return ret; |
50 | } | 50 | } |
51 | 51 | ||
52 | static inline int | ||
53 | futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) | ||
54 | { | ||
55 | return -ENOSYS; | ||
56 | } | ||
57 | |||
52 | #endif | 58 | #endif |
53 | #endif | 59 | #endif |
diff --git a/include/asm-generic/memory_model.h b/include/asm-generic/memory_model.h new file mode 100644 index 000000000000..0cfb086dd373 --- /dev/null +++ b/include/asm-generic/memory_model.h | |||
@@ -0,0 +1,77 @@ | |||
1 | #ifndef __ASM_MEMORY_MODEL_H | ||
2 | #define __ASM_MEMORY_MODEL_H | ||
3 | |||
4 | #ifdef __KERNEL__ | ||
5 | #ifndef __ASSEMBLY__ | ||
6 | |||
7 | #if defined(CONFIG_FLATMEM) | ||
8 | |||
9 | #ifndef ARCH_PFN_OFFSET | ||
10 | #define ARCH_PFN_OFFSET (0UL) | ||
11 | #endif | ||
12 | |||
13 | #elif defined(CONFIG_DISCONTIGMEM) | ||
14 | |||
15 | #ifndef arch_pfn_to_nid | ||
16 | #define arch_pfn_to_nid(pfn) pfn_to_nid(pfn) | ||
17 | #endif | ||
18 | |||
19 | #ifndef arch_local_page_offset | ||
20 | #define arch_local_page_offset(pfn, nid) \ | ||
21 | ((pfn) - NODE_DATA(nid)->node_start_pfn) | ||
22 | #endif | ||
23 | |||
24 | #endif /* CONFIG_DISCONTIGMEM */ | ||
25 | |||
26 | #ifdef CONFIG_OUT_OF_LINE_PFN_TO_PAGE | ||
27 | struct page; | ||
28 | /* this is useful when inlined pfn_to_page is too big */ | ||
29 | extern struct page *pfn_to_page(unsigned long pfn); | ||
30 | extern unsigned long page_to_pfn(struct page *page); | ||
31 | #else | ||
32 | /* | ||
33 | * supports 3 memory models. | ||
34 | */ | ||
35 | #if defined(CONFIG_FLATMEM) | ||
36 | |||
37 | #define pfn_to_page(pfn) (mem_map + ((pfn) - ARCH_PFN_OFFSET)) | ||
38 | #define page_to_pfn(page) ((unsigned long)((page) - mem_map) + \ | ||
39 | ARCH_PFN_OFFSET) | ||
40 | #elif defined(CONFIG_DISCONTIGMEM) | ||
41 | |||
42 | #define pfn_to_page(pfn) \ | ||
43 | ({ unsigned long __pfn = (pfn); \ | ||
44 | unsigned long __nid = arch_pfn_to_nid(pfn); \ | ||
45 | NODE_DATA(__nid)->node_mem_map + arch_local_page_offset(__pfn, __nid);\ | ||
46 | }) | ||
47 | |||
48 | #define page_to_pfn(pg) \ | ||
49 | ({ struct page *__pg = (pg); \ | ||
50 | struct pglist_data *__pgdat = NODE_DATA(page_to_nid(__pg)); \ | ||
51 | (unsigned long)(__pg - __pgdat->node_mem_map) + \ | ||
52 | __pgdat->node_start_pfn; \ | ||
53 | }) | ||
54 | |||
55 | #elif defined(CONFIG_SPARSEMEM) | ||
56 | /* | ||
57 | * Note: section's mem_map is encorded to reflect its start_pfn. | ||
58 | * section[i].section_mem_map == mem_map's address - start_pfn; | ||
59 | */ | ||
60 | #define page_to_pfn(pg) \ | ||
61 | ({ struct page *__pg = (pg); \ | ||
62 | int __sec = page_to_section(__pg); \ | ||
63 | __pg - __section_mem_map_addr(__nr_to_section(__sec)); \ | ||
64 | }) | ||
65 | |||
66 | #define pfn_to_page(pfn) \ | ||
67 | ({ unsigned long __pfn = (pfn); \ | ||
68 | struct mem_section *__sec = __pfn_to_section(__pfn); \ | ||
69 | __section_mem_map_addr(__sec) + __pfn; \ | ||
70 | }) | ||
71 | #endif /* CONFIG_FLATMEM/DISCONTIGMEM/SPARSEMEM */ | ||
72 | #endif /* CONFIG_OUT_OF_LINE_PFN_TO_PAGE */ | ||
73 | |||
74 | #endif /* __ASSEMBLY__ */ | ||
75 | #endif /* __KERNEL__ */ | ||
76 | |||
77 | #endif | ||
diff --git a/include/asm-h8300/page.h b/include/asm-h8300/page.h index cd35b1cc6cde..6472c9f88227 100644 --- a/include/asm-h8300/page.h +++ b/include/asm-h8300/page.h | |||
@@ -71,8 +71,7 @@ extern unsigned long memory_end; | |||
71 | #define page_to_virt(page) ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET) | 71 | #define page_to_virt(page) ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET) |
72 | #define pfn_valid(page) (page < max_mapnr) | 72 | #define pfn_valid(page) (page < max_mapnr) |
73 | 73 | ||
74 | #define pfn_to_page(pfn) virt_to_page(pfn_to_virt(pfn)) | 74 | #define ARCH_PFN_OFFSET (PAGE_OFFSET >> PAGE_SHIFT) |
75 | #define page_to_pfn(page) virt_to_pfn(page_to_virt(page)) | ||
76 | 75 | ||
77 | #define virt_addr_valid(kaddr) (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \ | 76 | #define virt_addr_valid(kaddr) (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \ |
78 | ((void *)(kaddr) < (void *)memory_end)) | 77 | ((void *)(kaddr) < (void *)memory_end)) |
@@ -81,6 +80,7 @@ extern unsigned long memory_end; | |||
81 | 80 | ||
82 | #endif /* __KERNEL__ */ | 81 | #endif /* __KERNEL__ */ |
83 | 82 | ||
83 | #include <asm-generic/memory_model.h> | ||
84 | #include <asm-generic/page.h> | 84 | #include <asm-generic/page.h> |
85 | 85 | ||
86 | #endif /* _H8300_PAGE_H */ | 86 | #endif /* _H8300_PAGE_H */ |
diff --git a/include/asm-i386/futex.h b/include/asm-i386/futex.h index 44b9db806474..7b8ceefd010f 100644 --- a/include/asm-i386/futex.h +++ b/include/asm-i386/futex.h | |||
@@ -104,5 +104,32 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) | |||
104 | return ret; | 104 | return ret; |
105 | } | 105 | } |
106 | 106 | ||
107 | static inline int | ||
108 | futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) | ||
109 | { | ||
110 | if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) | ||
111 | return -EFAULT; | ||
112 | |||
113 | __asm__ __volatile__( | ||
114 | "1: " LOCK_PREFIX "cmpxchgl %3, %1 \n" | ||
115 | |||
116 | "2: .section .fixup, \"ax\" \n" | ||
117 | "3: mov %2, %0 \n" | ||
118 | " jmp 2b \n" | ||
119 | " .previous \n" | ||
120 | |||
121 | " .section __ex_table, \"a\" \n" | ||
122 | " .align 8 \n" | ||
123 | " .long 1b,3b \n" | ||
124 | " .previous \n" | ||
125 | |||
126 | : "=a" (oldval), "=m" (*uaddr) | ||
127 | : "i" (-EFAULT), "r" (newval), "0" (oldval) | ||
128 | : "memory" | ||
129 | ); | ||
130 | |||
131 | return oldval; | ||
132 | } | ||
133 | |||
107 | #endif | 134 | #endif |
108 | #endif | 135 | #endif |
diff --git a/include/asm-i386/kdebug.h b/include/asm-i386/kdebug.h index 316138e89910..96d0828ce096 100644 --- a/include/asm-i386/kdebug.h +++ b/include/asm-i386/kdebug.h | |||
@@ -17,11 +17,9 @@ struct die_args { | |||
17 | int signr; | 17 | int signr; |
18 | }; | 18 | }; |
19 | 19 | ||
20 | /* Note - you should never unregister because that can race with NMIs. | 20 | extern int register_die_notifier(struct notifier_block *); |
21 | If you really want to do it first unregister - then synchronize_sched - then free. | 21 | extern int unregister_die_notifier(struct notifier_block *); |
22 | */ | 22 | extern struct atomic_notifier_head i386die_chain; |
23 | int register_die_notifier(struct notifier_block *nb); | ||
24 | extern struct notifier_block *i386die_chain; | ||
25 | 23 | ||
26 | 24 | ||
27 | /* Grossly misnamed. */ | 25 | /* Grossly misnamed. */ |
@@ -51,7 +49,7 @@ static inline int notify_die(enum die_val val, const char *str, | |||
51 | .trapnr = trap, | 49 | .trapnr = trap, |
52 | .signr = sig | 50 | .signr = sig |
53 | }; | 51 | }; |
54 | return notifier_call_chain(&i386die_chain, val, &args); | 52 | return atomic_notifier_call_chain(&i386die_chain, val, &args); |
55 | } | 53 | } |
56 | 54 | ||
57 | #endif | 55 | #endif |
diff --git a/include/asm-i386/mmzone.h b/include/asm-i386/mmzone.h index 74f595d80579..e33e9f9e4c66 100644 --- a/include/asm-i386/mmzone.h +++ b/include/asm-i386/mmzone.h | |||
@@ -70,8 +70,6 @@ static inline int pfn_to_nid(unsigned long pfn) | |||
70 | #endif | 70 | #endif |
71 | } | 71 | } |
72 | 72 | ||
73 | #define node_localnr(pfn, nid) ((pfn) - node_data[nid]->node_start_pfn) | ||
74 | |||
75 | /* | 73 | /* |
76 | * Following are macros that each numa implmentation must define. | 74 | * Following are macros that each numa implmentation must define. |
77 | */ | 75 | */ |
@@ -86,21 +84,6 @@ static inline int pfn_to_nid(unsigned long pfn) | |||
86 | /* XXX: FIXME -- wli */ | 84 | /* XXX: FIXME -- wli */ |
87 | #define kern_addr_valid(kaddr) (0) | 85 | #define kern_addr_valid(kaddr) (0) |
88 | 86 | ||
89 | #define pfn_to_page(pfn) \ | ||
90 | ({ \ | ||
91 | unsigned long __pfn = pfn; \ | ||
92 | int __node = pfn_to_nid(__pfn); \ | ||
93 | &NODE_DATA(__node)->node_mem_map[node_localnr(__pfn,__node)]; \ | ||
94 | }) | ||
95 | |||
96 | #define page_to_pfn(pg) \ | ||
97 | ({ \ | ||
98 | struct page *__page = pg; \ | ||
99 | struct zone *__zone = page_zone(__page); \ | ||
100 | (unsigned long)(__page - __zone->zone_mem_map) \ | ||
101 | + __zone->zone_start_pfn; \ | ||
102 | }) | ||
103 | |||
104 | #ifdef CONFIG_X86_NUMAQ /* we have contiguous memory on NUMA-Q */ | 87 | #ifdef CONFIG_X86_NUMAQ /* we have contiguous memory on NUMA-Q */ |
105 | #define pfn_valid(pfn) ((pfn) < num_physpages) | 88 | #define pfn_valid(pfn) ((pfn) < num_physpages) |
106 | #else | 89 | #else |
diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h index 997ca5d17876..30f52a2263ba 100644 --- a/include/asm-i386/page.h +++ b/include/asm-i386/page.h | |||
@@ -126,8 +126,6 @@ extern int page_is_ram(unsigned long pagenr); | |||
126 | #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) | 126 | #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) |
127 | #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) | 127 | #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) |
128 | #ifdef CONFIG_FLATMEM | 128 | #ifdef CONFIG_FLATMEM |
129 | #define pfn_to_page(pfn) (mem_map + (pfn)) | ||
130 | #define page_to_pfn(page) ((unsigned long)((page) - mem_map)) | ||
131 | #define pfn_valid(pfn) ((pfn) < max_mapnr) | 129 | #define pfn_valid(pfn) ((pfn) < max_mapnr) |
132 | #endif /* CONFIG_FLATMEM */ | 130 | #endif /* CONFIG_FLATMEM */ |
133 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) | 131 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) |
@@ -141,6 +139,7 @@ extern int page_is_ram(unsigned long pagenr); | |||
141 | 139 | ||
142 | #endif /* __KERNEL__ */ | 140 | #endif /* __KERNEL__ */ |
143 | 141 | ||
142 | #include <asm-generic/memory_model.h> | ||
144 | #include <asm-generic/page.h> | 143 | #include <asm-generic/page.h> |
145 | 144 | ||
146 | #endif /* _I386_PAGE_H */ | 145 | #endif /* _I386_PAGE_H */ |
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index feca5d961e2b..af4bfd012475 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/config.h> | 20 | #include <linux/config.h> |
21 | #include <linux/threads.h> | 21 | #include <linux/threads.h> |
22 | #include <asm/percpu.h> | 22 | #include <asm/percpu.h> |
23 | #include <linux/cpumask.h> | ||
23 | 24 | ||
24 | /* flag for disabling the tsc */ | 25 | /* flag for disabling the tsc */ |
25 | extern int tsc_disable; | 26 | extern int tsc_disable; |
@@ -67,6 +68,9 @@ struct cpuinfo_x86 { | |||
67 | char pad0; | 68 | char pad0; |
68 | int x86_power; | 69 | int x86_power; |
69 | unsigned long loops_per_jiffy; | 70 | unsigned long loops_per_jiffy; |
71 | #ifdef CONFIG_SMP | ||
72 | cpumask_t llc_shared_map; /* cpus sharing the last level cache */ | ||
73 | #endif | ||
70 | unsigned char x86_max_cores; /* cpuid returned max cores value */ | 74 | unsigned char x86_max_cores; /* cpuid returned max cores value */ |
71 | unsigned char booted_cores; /* number of cores as seen by OS */ | 75 | unsigned char booted_cores; /* number of cores as seen by OS */ |
72 | unsigned char apicid; | 76 | unsigned char apicid; |
@@ -103,6 +107,7 @@ extern struct cpuinfo_x86 cpu_data[]; | |||
103 | 107 | ||
104 | extern int phys_proc_id[NR_CPUS]; | 108 | extern int phys_proc_id[NR_CPUS]; |
105 | extern int cpu_core_id[NR_CPUS]; | 109 | extern int cpu_core_id[NR_CPUS]; |
110 | extern int cpu_llc_id[NR_CPUS]; | ||
106 | extern char ignore_fpu_irq; | 111 | extern char ignore_fpu_irq; |
107 | 112 | ||
108 | extern void identify_cpu(struct cpuinfo_x86 *); | 113 | extern void identify_cpu(struct cpuinfo_x86 *); |
diff --git a/include/asm-i386/setup.h b/include/asm-i386/setup.h index 826a8ca50ac8..ee941457b55d 100644 --- a/include/asm-i386/setup.h +++ b/include/asm-i386/setup.h | |||
@@ -6,9 +6,7 @@ | |||
6 | #ifndef _i386_SETUP_H | 6 | #ifndef _i386_SETUP_H |
7 | #define _i386_SETUP_H | 7 | #define _i386_SETUP_H |
8 | 8 | ||
9 | #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) | 9 | #include <linux/pfn.h> |
10 | #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) | ||
11 | #define PFN_PHYS(x) ((x) << PAGE_SHIFT) | ||
12 | 10 | ||
13 | /* | 11 | /* |
14 | * Reserved space for vmalloc and iomap - defined in asm/page.h | 12 | * Reserved space for vmalloc and iomap - defined in asm/page.h |
diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h index aa958c6ee83e..b94e5eeef917 100644 --- a/include/asm-i386/topology.h +++ b/include/asm-i386/topology.h | |||
@@ -112,4 +112,6 @@ extern unsigned long node_remap_size[]; | |||
112 | 112 | ||
113 | #endif /* CONFIG_NUMA */ | 113 | #endif /* CONFIG_NUMA */ |
114 | 114 | ||
115 | extern cpumask_t cpu_coregroup_map(int cpu); | ||
116 | |||
115 | #endif /* _ASM_I386_TOPOLOGY_H */ | 117 | #endif /* _ASM_I386_TOPOLOGY_H */ |
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index d8afd0e3b81a..014e3562895b 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h | |||
@@ -316,8 +316,10 @@ | |||
316 | #define __NR_pselect6 308 | 316 | #define __NR_pselect6 308 |
317 | #define __NR_ppoll 309 | 317 | #define __NR_ppoll 309 |
318 | #define __NR_unshare 310 | 318 | #define __NR_unshare 310 |
319 | #define __NR_set_robust_list 311 | ||
320 | #define __NR_get_robust_list 312 | ||
319 | 321 | ||
320 | #define NR_syscalls 311 | 322 | #define NR_syscalls 313 |
321 | 323 | ||
322 | /* | 324 | /* |
323 | * user-visible error numbers are in the range -1 - -128: see | 325 | * user-visible error numbers are in the range -1 - -128: see |
diff --git a/include/asm-ia64/compat.h b/include/asm-ia64/compat.h index c0b19106665c..40d01d80610d 100644 --- a/include/asm-ia64/compat.h +++ b/include/asm-ia64/compat.h | |||
@@ -189,6 +189,12 @@ compat_ptr (compat_uptr_t uptr) | |||
189 | return (void __user *) (unsigned long) uptr; | 189 | return (void __user *) (unsigned long) uptr; |
190 | } | 190 | } |
191 | 191 | ||
192 | static inline compat_uptr_t | ||
193 | ptr_to_compat(void __user *uptr) | ||
194 | { | ||
195 | return (u32)(unsigned long)uptr; | ||
196 | } | ||
197 | |||
192 | static __inline__ void __user * | 198 | static __inline__ void __user * |
193 | compat_alloc_user_space (long len) | 199 | compat_alloc_user_space (long len) |
194 | { | 200 | { |
diff --git a/include/asm-ia64/kdebug.h b/include/asm-ia64/kdebug.h index 8b01a083dde6..218c458ab60c 100644 --- a/include/asm-ia64/kdebug.h +++ b/include/asm-ia64/kdebug.h | |||
@@ -40,7 +40,7 @@ struct die_args { | |||
40 | 40 | ||
41 | extern int register_die_notifier(struct notifier_block *); | 41 | extern int register_die_notifier(struct notifier_block *); |
42 | extern int unregister_die_notifier(struct notifier_block *); | 42 | extern int unregister_die_notifier(struct notifier_block *); |
43 | extern struct notifier_block *ia64die_chain; | 43 | extern struct atomic_notifier_head ia64die_chain; |
44 | 44 | ||
45 | enum die_val { | 45 | enum die_val { |
46 | DIE_BREAK = 1, | 46 | DIE_BREAK = 1, |
@@ -81,7 +81,7 @@ static inline int notify_die(enum die_val val, char *str, struct pt_regs *regs, | |||
81 | .signr = sig | 81 | .signr = sig |
82 | }; | 82 | }; |
83 | 83 | ||
84 | return notifier_call_chain(&ia64die_chain, val, &args); | 84 | return atomic_notifier_call_chain(&ia64die_chain, val, &args); |
85 | } | 85 | } |
86 | 86 | ||
87 | #endif | 87 | #endif |
diff --git a/include/asm-ia64/page.h b/include/asm-ia64/page.h index 6e9aa23250c4..2087825eefa4 100644 --- a/include/asm-ia64/page.h +++ b/include/asm-ia64/page.h | |||
@@ -106,17 +106,25 @@ extern int ia64_pfn_valid (unsigned long pfn); | |||
106 | # define ia64_pfn_valid(pfn) 1 | 106 | # define ia64_pfn_valid(pfn) 1 |
107 | #endif | 107 | #endif |
108 | 108 | ||
109 | #ifdef CONFIG_VIRTUAL_MEM_MAP | ||
110 | extern struct page *vmem_map; | ||
111 | #ifdef CONFIG_DISCONTIGMEM | ||
112 | # define page_to_pfn(page) ((unsigned long) (page - vmem_map)) | ||
113 | # define pfn_to_page(pfn) (vmem_map + (pfn)) | ||
114 | #endif | ||
115 | #endif | ||
116 | |||
117 | #if defined(CONFIG_FLATMEM) || defined(CONFIG_SPARSEMEM) | ||
118 | /* FLATMEM always configures mem_map (mem_map = vmem_map if necessary) */ | ||
119 | #include <asm-generic/memory_model.h> | ||
120 | #endif | ||
121 | |||
109 | #ifdef CONFIG_FLATMEM | 122 | #ifdef CONFIG_FLATMEM |
110 | # define pfn_valid(pfn) (((pfn) < max_mapnr) && ia64_pfn_valid(pfn)) | 123 | # define pfn_valid(pfn) (((pfn) < max_mapnr) && ia64_pfn_valid(pfn)) |
111 | # define page_to_pfn(page) ((unsigned long) (page - mem_map)) | ||
112 | # define pfn_to_page(pfn) (mem_map + (pfn)) | ||
113 | #elif defined(CONFIG_DISCONTIGMEM) | 124 | #elif defined(CONFIG_DISCONTIGMEM) |
114 | extern struct page *vmem_map; | ||
115 | extern unsigned long min_low_pfn; | 125 | extern unsigned long min_low_pfn; |
116 | extern unsigned long max_low_pfn; | 126 | extern unsigned long max_low_pfn; |
117 | # define pfn_valid(pfn) (((pfn) >= min_low_pfn) && ((pfn) < max_low_pfn) && ia64_pfn_valid(pfn)) | 127 | # define pfn_valid(pfn) (((pfn) >= min_low_pfn) && ((pfn) < max_low_pfn) && ia64_pfn_valid(pfn)) |
118 | # define page_to_pfn(page) ((unsigned long) (page - vmem_map)) | ||
119 | # define pfn_to_page(pfn) (vmem_map + (pfn)) | ||
120 | #endif | 128 | #endif |
121 | 129 | ||
122 | #define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) | 130 | #define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) |
diff --git a/include/asm-m32r/mmzone.h b/include/asm-m32r/mmzone.h index adc7970a77ec..9f3b5accda88 100644 --- a/include/asm-m32r/mmzone.h +++ b/include/asm-m32r/mmzone.h | |||
@@ -21,20 +21,6 @@ extern struct pglist_data *node_data[]; | |||
21 | __pgdat->node_start_pfn + __pgdat->node_spanned_pages - 1; \ | 21 | __pgdat->node_start_pfn + __pgdat->node_spanned_pages - 1; \ |
22 | }) | 22 | }) |
23 | 23 | ||
24 | #define pfn_to_page(pfn) \ | ||
25 | ({ \ | ||
26 | unsigned long __pfn = pfn; \ | ||
27 | int __node = pfn_to_nid(__pfn); \ | ||
28 | &NODE_DATA(__node)->node_mem_map[node_localnr(__pfn,__node)]; \ | ||
29 | }) | ||
30 | |||
31 | #define page_to_pfn(pg) \ | ||
32 | ({ \ | ||
33 | struct page *__page = pg; \ | ||
34 | struct zone *__zone = page_zone(__page); \ | ||
35 | (unsigned long)(__page - __zone->zone_mem_map) \ | ||
36 | + __zone->zone_start_pfn; \ | ||
37 | }) | ||
38 | #define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)) | 24 | #define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)) |
39 | /* | 25 | /* |
40 | * pfn_valid should be made as fast as possible, and the current definition | 26 | * pfn_valid should be made as fast as possible, and the current definition |
diff --git a/include/asm-m32r/page.h b/include/asm-m32r/page.h index 4ab578876361..9ddbc087dbc5 100644 --- a/include/asm-m32r/page.h +++ b/include/asm-m32r/page.h | |||
@@ -76,9 +76,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; | |||
76 | 76 | ||
77 | #ifndef CONFIG_DISCONTIGMEM | 77 | #ifndef CONFIG_DISCONTIGMEM |
78 | #define PFN_BASE (CONFIG_MEMORY_START >> PAGE_SHIFT) | 78 | #define PFN_BASE (CONFIG_MEMORY_START >> PAGE_SHIFT) |
79 | #define pfn_to_page(pfn) (mem_map + ((pfn) - PFN_BASE)) | 79 | #define ARCH_PFN_OFFSET PFN_BASE |
80 | #define page_to_pfn(page) \ | ||
81 | ((unsigned long)((page) - mem_map) + PFN_BASE) | ||
82 | #define pfn_valid(pfn) (((pfn) - PFN_BASE) < max_mapnr) | 80 | #define pfn_valid(pfn) (((pfn) - PFN_BASE) < max_mapnr) |
83 | #endif /* !CONFIG_DISCONTIGMEM */ | 81 | #endif /* !CONFIG_DISCONTIGMEM */ |
84 | 82 | ||
@@ -92,6 +90,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; | |||
92 | 90 | ||
93 | #endif /* __KERNEL__ */ | 91 | #endif /* __KERNEL__ */ |
94 | 92 | ||
93 | #include <asm-generic/memory_model.h> | ||
95 | #include <asm-generic/page.h> | 94 | #include <asm-generic/page.h> |
96 | 95 | ||
97 | #endif /* _ASM_M32R_PAGE_H */ | 96 | #endif /* _ASM_M32R_PAGE_H */ |
diff --git a/include/asm-m32r/setup.h b/include/asm-m32r/setup.h index 5f028dc26a9b..52f4fa29abfc 100644 --- a/include/asm-m32r/setup.h +++ b/include/asm-m32r/setup.h | |||
@@ -24,10 +24,6 @@ | |||
24 | #define RAMDISK_PROMPT_FLAG (0x8000) | 24 | #define RAMDISK_PROMPT_FLAG (0x8000) |
25 | #define RAMDISK_LOAD_FLAG (0x4000) | 25 | #define RAMDISK_LOAD_FLAG (0x4000) |
26 | 26 | ||
27 | #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) | ||
28 | #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) | ||
29 | #define PFN_PHYS(x) ((x) << PAGE_SHIFT) | ||
30 | |||
31 | extern unsigned long memory_start; | 27 | extern unsigned long memory_start; |
32 | extern unsigned long memory_end; | 28 | extern unsigned long memory_end; |
33 | 29 | ||
diff --git a/include/asm-mips/compat.h b/include/asm-mips/compat.h index 0012bd804d2d..986511db54a6 100644 --- a/include/asm-mips/compat.h +++ b/include/asm-mips/compat.h | |||
@@ -133,6 +133,11 @@ static inline void __user *compat_ptr(compat_uptr_t uptr) | |||
133 | return (void __user *)(long)uptr; | 133 | return (void __user *)(long)uptr; |
134 | } | 134 | } |
135 | 135 | ||
136 | static inline compat_uptr_t ptr_to_compat(void __user *uptr) | ||
137 | { | ||
138 | return (u32)(unsigned long)uptr; | ||
139 | } | ||
140 | |||
136 | static inline void __user *compat_alloc_user_space(long len) | 141 | static inline void __user *compat_alloc_user_space(long len) |
137 | { | 142 | { |
138 | struct pt_regs *regs = (struct pt_regs *) | 143 | struct pt_regs *regs = (struct pt_regs *) |
diff --git a/include/asm-mips/futex.h b/include/asm-mips/futex.h index 2454c44a8f54..a554089991f2 100644 --- a/include/asm-mips/futex.h +++ b/include/asm-mips/futex.h | |||
@@ -99,5 +99,11 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) | |||
99 | return ret; | 99 | return ret; |
100 | } | 100 | } |
101 | 101 | ||
102 | static inline int | ||
103 | futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) | ||
104 | { | ||
105 | return -ENOSYS; | ||
106 | } | ||
107 | |||
102 | #endif | 108 | #endif |
103 | #endif | 109 | #endif |
diff --git a/include/asm-mips/mmzone.h b/include/asm-mips/mmzone.h index 011caebac369..7bde4432092b 100644 --- a/include/asm-mips/mmzone.h +++ b/include/asm-mips/mmzone.h | |||
@@ -22,20 +22,6 @@ | |||
22 | NODE_DATA(__n)->node_spanned_pages) : 0);\ | 22 | NODE_DATA(__n)->node_spanned_pages) : 0);\ |
23 | }) | 23 | }) |
24 | 24 | ||
25 | #define pfn_to_page(pfn) \ | ||
26 | ({ \ | ||
27 | unsigned long __pfn = (pfn); \ | ||
28 | pg_data_t *__pg = NODE_DATA(pfn_to_nid(__pfn)); \ | ||
29 | __pg->node_mem_map + (__pfn - __pg->node_start_pfn); \ | ||
30 | }) | ||
31 | |||
32 | #define page_to_pfn(p) \ | ||
33 | ({ \ | ||
34 | struct page *__p = (p); \ | ||
35 | struct zone *__z = page_zone(__p); \ | ||
36 | ((__p - __z->zone_mem_map) + __z->zone_start_pfn); \ | ||
37 | }) | ||
38 | |||
39 | /* XXX: FIXME -- wli */ | 25 | /* XXX: FIXME -- wli */ |
40 | #define kern_addr_valid(addr) (0) | 26 | #define kern_addr_valid(addr) (0) |
41 | 27 | ||
diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h index ee25a779bf49..a1eab136ff6c 100644 --- a/include/asm-mips/page.h +++ b/include/asm-mips/page.h | |||
@@ -140,8 +140,6 @@ typedef struct { unsigned long pgprot; } pgprot_t; | |||
140 | #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) | 140 | #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) |
141 | 141 | ||
142 | #ifndef CONFIG_NEED_MULTIPLE_NODES | 142 | #ifndef CONFIG_NEED_MULTIPLE_NODES |
143 | #define pfn_to_page(pfn) (mem_map + (pfn)) | ||
144 | #define page_to_pfn(page) ((unsigned long)((page) - mem_map)) | ||
145 | #define pfn_valid(pfn) ((pfn) < max_mapnr) | 143 | #define pfn_valid(pfn) ((pfn) < max_mapnr) |
146 | #endif | 144 | #endif |
147 | 145 | ||
@@ -160,6 +158,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; | |||
160 | #define WANT_PAGE_VIRTUAL | 158 | #define WANT_PAGE_VIRTUAL |
161 | #endif | 159 | #endif |
162 | 160 | ||
161 | #include <asm-generic/memory_model.h> | ||
163 | #include <asm-generic/page.h> | 162 | #include <asm-generic/page.h> |
164 | 163 | ||
165 | #endif /* _ASM_PAGE_H */ | 164 | #endif /* _ASM_PAGE_H */ |
diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h index 9cc3564cc2c9..d897c8bb554d 100644 --- a/include/asm-mips/time.h +++ b/include/asm-mips/time.h | |||
@@ -26,14 +26,14 @@ extern spinlock_t rtc_lock; | |||
26 | 26 | ||
27 | /* | 27 | /* |
28 | * RTC ops. By default, they point to no-RTC functions. | 28 | * RTC ops. By default, they point to no-RTC functions. |
29 | * rtc_get_time - mktime(year, mon, day, hour, min, sec) in seconds. | 29 | * rtc_mips_get_time - mktime(year, mon, day, hour, min, sec) in seconds. |
30 | * rtc_set_time - reverse the above translation and set time to RTC. | 30 | * rtc_mips_set_time - reverse the above translation and set time to RTC. |
31 | * rtc_set_mmss - similar to rtc_set_time, but only min and sec need | 31 | * rtc_mips_set_mmss - similar to rtc_set_time, but only min and sec need |
32 | * to be set. Used by RTC sync-up. | 32 | * to be set. Used by RTC sync-up. |
33 | */ | 33 | */ |
34 | extern unsigned long (*rtc_get_time)(void); | 34 | extern unsigned long (*rtc_mips_get_time)(void); |
35 | extern int (*rtc_set_time)(unsigned long); | 35 | extern int (*rtc_mips_set_time)(unsigned long); |
36 | extern int (*rtc_set_mmss)(unsigned long); | 36 | extern int (*rtc_mips_set_mmss)(unsigned long); |
37 | 37 | ||
38 | /* | 38 | /* |
39 | * Timer interrupt functions. | 39 | * Timer interrupt functions. |
diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h index 38b918feead9..289624d8b2d4 100644 --- a/include/asm-parisc/compat.h +++ b/include/asm-parisc/compat.h | |||
@@ -138,6 +138,11 @@ static inline void __user *compat_ptr(compat_uptr_t uptr) | |||
138 | return (void __user *)(unsigned long)uptr; | 138 | return (void __user *)(unsigned long)uptr; |
139 | } | 139 | } |
140 | 140 | ||
141 | static inline compat_uptr_t ptr_to_compat(void __user *uptr) | ||
142 | { | ||
143 | return (u32)(unsigned long)uptr; | ||
144 | } | ||
145 | |||
141 | static __inline__ void __user *compat_alloc_user_space(long len) | 146 | static __inline__ void __user *compat_alloc_user_space(long len) |
142 | { | 147 | { |
143 | struct pt_regs *regs = ¤t->thread.regs; | 148 | struct pt_regs *regs = ¤t->thread.regs; |
diff --git a/include/asm-parisc/mmzone.h b/include/asm-parisc/mmzone.h index ae039f4fd711..ceb9b73199d1 100644 --- a/include/asm-parisc/mmzone.h +++ b/include/asm-parisc/mmzone.h | |||
@@ -25,23 +25,6 @@ extern struct node_map_data node_data[]; | |||
25 | pg_data_t *__pgdat = NODE_DATA(nid); \ | 25 | pg_data_t *__pgdat = NODE_DATA(nid); \ |
26 | __pgdat->node_start_pfn + __pgdat->node_spanned_pages; \ | 26 | __pgdat->node_start_pfn + __pgdat->node_spanned_pages; \ |
27 | }) | 27 | }) |
28 | #define node_localnr(pfn, nid) ((pfn) - node_start_pfn(nid)) | ||
29 | |||
30 | #define pfn_to_page(pfn) \ | ||
31 | ({ \ | ||
32 | unsigned long __pfn = (pfn); \ | ||
33 | int __node = pfn_to_nid(__pfn); \ | ||
34 | &NODE_DATA(__node)->node_mem_map[node_localnr(__pfn,__node)]; \ | ||
35 | }) | ||
36 | |||
37 | #define page_to_pfn(pg) \ | ||
38 | ({ \ | ||
39 | struct page *__page = pg; \ | ||
40 | struct zone *__zone = page_zone(__page); \ | ||
41 | BUG_ON(__zone == NULL); \ | ||
42 | (unsigned long)(__page - __zone->zone_mem_map) \ | ||
43 | + __zone->zone_start_pfn; \ | ||
44 | }) | ||
45 | 28 | ||
46 | /* We have these possible memory map layouts: | 29 | /* We have these possible memory map layouts: |
47 | * Astro: 0-3.75, 67.75-68, 4-64 | 30 | * Astro: 0-3.75, 67.75-68, 4-64 |
diff --git a/include/asm-parisc/page.h b/include/asm-parisc/page.h index 4a6752b0afed..9f303c0c3cd7 100644 --- a/include/asm-parisc/page.h +++ b/include/asm-parisc/page.h | |||
@@ -130,8 +130,6 @@ extern int npmem_ranges; | |||
130 | #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) | 130 | #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) |
131 | 131 | ||
132 | #ifndef CONFIG_DISCONTIGMEM | 132 | #ifndef CONFIG_DISCONTIGMEM |
133 | #define pfn_to_page(pfn) (mem_map + (pfn)) | ||
134 | #define page_to_pfn(page) ((unsigned long)((page) - mem_map)) | ||
135 | #define pfn_valid(pfn) ((pfn) < max_mapnr) | 133 | #define pfn_valid(pfn) ((pfn) < max_mapnr) |
136 | #endif /* CONFIG_DISCONTIGMEM */ | 134 | #endif /* CONFIG_DISCONTIGMEM */ |
137 | 135 | ||
@@ -152,6 +150,7 @@ extern int npmem_ranges; | |||
152 | 150 | ||
153 | #endif /* __KERNEL__ */ | 151 | #endif /* __KERNEL__ */ |
154 | 152 | ||
153 | #include <asm-generic/memory_model.h> | ||
155 | #include <asm-generic/page.h> | 154 | #include <asm-generic/page.h> |
156 | 155 | ||
157 | #endif /* _PARISC_PAGE_H */ | 156 | #endif /* _PARISC_PAGE_H */ |
diff --git a/include/asm-powerpc/futex.h b/include/asm-powerpc/futex.h index 39e85f320a76..f1b3c00bc1ce 100644 --- a/include/asm-powerpc/futex.h +++ b/include/asm-powerpc/futex.h | |||
@@ -81,5 +81,11 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr) | |||
81 | return ret; | 81 | return ret; |
82 | } | 82 | } |
83 | 83 | ||
84 | static inline int | ||
85 | futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) | ||
86 | { | ||
87 | return -ENOSYS; | ||
88 | } | ||
89 | |||
84 | #endif /* __KERNEL__ */ | 90 | #endif /* __KERNEL__ */ |
85 | #endif /* _ASM_POWERPC_FUTEX_H */ | 91 | #endif /* _ASM_POWERPC_FUTEX_H */ |
diff --git a/include/asm-powerpc/kdebug.h b/include/asm-powerpc/kdebug.h index 7c16265568e0..c01786ab5fa6 100644 --- a/include/asm-powerpc/kdebug.h +++ b/include/asm-powerpc/kdebug.h | |||
@@ -16,13 +16,9 @@ struct die_args { | |||
16 | int signr; | 16 | int signr; |
17 | }; | 17 | }; |
18 | 18 | ||
19 | /* | 19 | extern int register_die_notifier(struct notifier_block *); |
20 | Note - you should never unregister because that can race with NMIs. | 20 | extern int unregister_die_notifier(struct notifier_block *); |
21 | If you really want to do it first unregister - then synchronize_sched - | 21 | extern struct atomic_notifier_head powerpc_die_chain; |
22 | then free. | ||
23 | */ | ||
24 | int register_die_notifier(struct notifier_block *nb); | ||
25 | extern struct notifier_block *powerpc_die_chain; | ||
26 | 22 | ||
27 | /* Grossly misnamed. */ | 23 | /* Grossly misnamed. */ |
28 | enum die_val { | 24 | enum die_val { |
@@ -37,7 +33,7 @@ enum die_val { | |||
37 | static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,long err,int trap, int sig) | 33 | static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,long err,int trap, int sig) |
38 | { | 34 | { |
39 | struct die_args args = { .regs=regs, .str=str, .err=err, .trapnr=trap,.signr=sig }; | 35 | struct die_args args = { .regs=regs, .str=str, .err=err, .trapnr=trap,.signr=sig }; |
40 | return notifier_call_chain(&powerpc_die_chain, val, &args); | 36 | return atomic_notifier_call_chain(&powerpc_die_chain, val, &args); |
41 | } | 37 | } |
42 | 38 | ||
43 | #endif /* __KERNEL__ */ | 39 | #endif /* __KERNEL__ */ |
diff --git a/include/asm-powerpc/page.h b/include/asm-powerpc/page.h index 0b82df483f7f..2fbecebe1c92 100644 --- a/include/asm-powerpc/page.h +++ b/include/asm-powerpc/page.h | |||
@@ -69,8 +69,6 @@ | |||
69 | #endif | 69 | #endif |
70 | 70 | ||
71 | #ifdef CONFIG_FLATMEM | 71 | #ifdef CONFIG_FLATMEM |
72 | #define pfn_to_page(pfn) (mem_map + (pfn)) | ||
73 | #define page_to_pfn(page) ((unsigned long)((page) - mem_map)) | ||
74 | #define pfn_valid(pfn) ((pfn) < max_mapnr) | 72 | #define pfn_valid(pfn) ((pfn) < max_mapnr) |
75 | #endif | 73 | #endif |
76 | 74 | ||
@@ -200,6 +198,7 @@ extern void copy_user_page(void *to, void *from, unsigned long vaddr, | |||
200 | struct page *p); | 198 | struct page *p); |
201 | extern int page_is_ram(unsigned long pfn); | 199 | extern int page_is_ram(unsigned long pfn); |
202 | 200 | ||
201 | #include <asm-generic/memory_model.h> | ||
203 | #endif /* __ASSEMBLY__ */ | 202 | #endif /* __ASSEMBLY__ */ |
204 | 203 | ||
205 | #endif /* __KERNEL__ */ | 204 | #endif /* __KERNEL__ */ |
diff --git a/include/asm-ppc/page.h b/include/asm-ppc/page.h index 538e0c8ab243..a70ba2ee552d 100644 --- a/include/asm-ppc/page.h +++ b/include/asm-ppc/page.h | |||
@@ -149,8 +149,7 @@ extern int page_is_ram(unsigned long pfn); | |||
149 | #define __pa(x) ___pa((unsigned long)(x)) | 149 | #define __pa(x) ___pa((unsigned long)(x)) |
150 | #define __va(x) ((void *)(___va((unsigned long)(x)))) | 150 | #define __va(x) ((void *)(___va((unsigned long)(x)))) |
151 | 151 | ||
152 | #define pfn_to_page(pfn) (mem_map + ((pfn) - PPC_PGSTART)) | 152 | #define ARCH_PFN_OFFSET (PPC_PGSTART) |
153 | #define page_to_pfn(page) ((unsigned long)((page) - mem_map) + PPC_PGSTART) | ||
154 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) | 153 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) |
155 | #define page_to_virt(page) __va(page_to_pfn(page) << PAGE_SHIFT) | 154 | #define page_to_virt(page) __va(page_to_pfn(page) << PAGE_SHIFT) |
156 | 155 | ||
@@ -175,5 +174,6 @@ extern __inline__ int get_order(unsigned long size) | |||
175 | /* We do define AT_SYSINFO_EHDR but don't use the gate mecanism */ | 174 | /* We do define AT_SYSINFO_EHDR but don't use the gate mecanism */ |
176 | #define __HAVE_ARCH_GATE_AREA 1 | 175 | #define __HAVE_ARCH_GATE_AREA 1 |
177 | 176 | ||
177 | #include <asm-generic/memory_model.h> | ||
178 | #endif /* __KERNEL__ */ | 178 | #endif /* __KERNEL__ */ |
179 | #endif /* _PPC_PAGE_H */ | 179 | #endif /* _PPC_PAGE_H */ |
diff --git a/include/asm-s390/compat.h b/include/asm-s390/compat.h index a007715f4aea..356a0b183539 100644 --- a/include/asm-s390/compat.h +++ b/include/asm-s390/compat.h | |||
@@ -128,6 +128,11 @@ static inline void __user *compat_ptr(compat_uptr_t uptr) | |||
128 | return (void __user *)(unsigned long)(uptr & 0x7fffffffUL); | 128 | return (void __user *)(unsigned long)(uptr & 0x7fffffffUL); |
129 | } | 129 | } |
130 | 130 | ||
131 | static inline compat_uptr_t ptr_to_compat(void __user *uptr) | ||
132 | { | ||
133 | return (u32)(unsigned long)uptr; | ||
134 | } | ||
135 | |||
131 | static inline void __user *compat_alloc_user_space(long len) | 136 | static inline void __user *compat_alloc_user_space(long len) |
132 | { | 137 | { |
133 | unsigned long stack; | 138 | unsigned long stack; |
diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h index 2430c561e021..3b1138ac7e79 100644 --- a/include/asm-s390/page.h +++ b/include/asm-s390/page.h | |||
@@ -181,8 +181,6 @@ page_get_storage_key(unsigned long addr) | |||
181 | #define PAGE_OFFSET 0x0UL | 181 | #define PAGE_OFFSET 0x0UL |
182 | #define __pa(x) (unsigned long)(x) | 182 | #define __pa(x) (unsigned long)(x) |
183 | #define __va(x) (void *)(unsigned long)(x) | 183 | #define __va(x) (void *)(unsigned long)(x) |
184 | #define pfn_to_page(pfn) (mem_map + (pfn)) | ||
185 | #define page_to_pfn(page) ((unsigned long)((page) - mem_map)) | ||
186 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) | 184 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) |
187 | 185 | ||
188 | #define pfn_valid(pfn) ((pfn) < max_mapnr) | 186 | #define pfn_valid(pfn) ((pfn) < max_mapnr) |
@@ -193,6 +191,7 @@ page_get_storage_key(unsigned long addr) | |||
193 | 191 | ||
194 | #endif /* __KERNEL__ */ | 192 | #endif /* __KERNEL__ */ |
195 | 193 | ||
194 | #include <asm-generic/memory_model.h> | ||
196 | #include <asm-generic/page.h> | 195 | #include <asm-generic/page.h> |
197 | 196 | ||
198 | #endif /* _S390_PAGE_H */ | 197 | #endif /* _S390_PAGE_H */ |
diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h index 972c3f655b2a..9c89287c3e56 100644 --- a/include/asm-sh/page.h +++ b/include/asm-sh/page.h | |||
@@ -105,9 +105,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; | |||
105 | 105 | ||
106 | /* PFN start number, because of __MEMORY_START */ | 106 | /* PFN start number, because of __MEMORY_START */ |
107 | #define PFN_START (__MEMORY_START >> PAGE_SHIFT) | 107 | #define PFN_START (__MEMORY_START >> PAGE_SHIFT) |
108 | 108 | #define ARCH_PFN_OFFSET (FPN_START) | |
109 | #define pfn_to_page(pfn) (mem_map + (pfn) - PFN_START) | ||
110 | #define page_to_pfn(page) ((unsigned long)((page) - mem_map) + PFN_START) | ||
111 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) | 109 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) |
112 | #define pfn_valid(pfn) (((pfn) - PFN_START) < max_mapnr) | 110 | #define pfn_valid(pfn) (((pfn) - PFN_START) < max_mapnr) |
113 | #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) | 111 | #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) |
@@ -117,6 +115,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; | |||
117 | 115 | ||
118 | #endif /* __KERNEL__ */ | 116 | #endif /* __KERNEL__ */ |
119 | 117 | ||
118 | #include <asm-generic/memory_model.h> | ||
120 | #include <asm-generic/page.h> | 119 | #include <asm-generic/page.h> |
121 | 120 | ||
122 | #endif /* __ASM_SH_PAGE_H */ | 121 | #endif /* __ASM_SH_PAGE_H */ |
diff --git a/include/asm-sh64/page.h b/include/asm-sh64/page.h index c86df90f7cbd..e4937cdabebd 100644 --- a/include/asm-sh64/page.h +++ b/include/asm-sh64/page.h | |||
@@ -105,9 +105,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; | |||
105 | 105 | ||
106 | /* PFN start number, because of __MEMORY_START */ | 106 | /* PFN start number, because of __MEMORY_START */ |
107 | #define PFN_START (__MEMORY_START >> PAGE_SHIFT) | 107 | #define PFN_START (__MEMORY_START >> PAGE_SHIFT) |
108 | 108 | #define ARCH_PFN_OFFSET (PFN_START) | |
109 | #define pfn_to_page(pfn) (mem_map + (pfn) - PFN_START) | ||
110 | #define page_to_pfn(page) ((unsigned long)((page) - mem_map) + PFN_START) | ||
111 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) | 109 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) |
112 | #define pfn_valid(pfn) (((pfn) - PFN_START) < max_mapnr) | 110 | #define pfn_valid(pfn) (((pfn) - PFN_START) < max_mapnr) |
113 | #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) | 111 | #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) |
@@ -117,6 +115,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; | |||
117 | 115 | ||
118 | #endif /* __KERNEL__ */ | 116 | #endif /* __KERNEL__ */ |
119 | 117 | ||
118 | #include <asm-generic/memory_model.h> | ||
120 | #include <asm-generic/page.h> | 119 | #include <asm-generic/page.h> |
121 | 120 | ||
122 | #endif /* __ASM_SH64_PAGE_H */ | 121 | #endif /* __ASM_SH64_PAGE_H */ |
diff --git a/include/asm-sh64/platform.h b/include/asm-sh64/platform.h index 7046a9014027..bd0d9c405a80 100644 --- a/include/asm-sh64/platform.h +++ b/include/asm-sh64/platform.h | |||
@@ -61,9 +61,4 @@ extern int platform_int_priority[NR_INTC_IRQS]; | |||
61 | #define code_resource (platform_parms.kram_res_p[STANDARD_KRAM_RESOURCES - 2]) | 61 | #define code_resource (platform_parms.kram_res_p[STANDARD_KRAM_RESOURCES - 2]) |
62 | #define data_resource (platform_parms.kram_res_p[STANDARD_KRAM_RESOURCES - 1]) | 62 | #define data_resource (platform_parms.kram_res_p[STANDARD_KRAM_RESOURCES - 1]) |
63 | 63 | ||
64 | /* Be prepared to 64-bit sign extensions */ | ||
65 | #define PFN_UP(x) ((((x) + PAGE_SIZE-1) >> PAGE_SHIFT) & 0x000fffff) | ||
66 | #define PFN_DOWN(x) (((x) >> PAGE_SHIFT) & 0x000fffff) | ||
67 | #define PFN_PHYS(x) ((x) << PAGE_SHIFT) | ||
68 | |||
69 | #endif /* __ASM_SH64_PLATFORM_H */ | 64 | #endif /* __ASM_SH64_PLATFORM_H */ |
diff --git a/include/asm-sparc/page.h b/include/asm-sparc/page.h index 9122684f6c1e..ec3274b7ddf4 100644 --- a/include/asm-sparc/page.h +++ b/include/asm-sparc/page.h | |||
@@ -152,8 +152,7 @@ extern unsigned long pfn_base; | |||
152 | #define virt_to_phys __pa | 152 | #define virt_to_phys __pa |
153 | #define phys_to_virt __va | 153 | #define phys_to_virt __va |
154 | 154 | ||
155 | #define pfn_to_page(pfn) (mem_map + ((pfn)-(pfn_base))) | 155 | #define ARCH_PFN_OFFSET (pfn_base) |
156 | #define page_to_pfn(page) ((unsigned long)(((page) - mem_map) + pfn_base)) | ||
157 | #define virt_to_page(kaddr) (mem_map + ((((unsigned long)(kaddr)-PAGE_OFFSET)>>PAGE_SHIFT))) | 156 | #define virt_to_page(kaddr) (mem_map + ((((unsigned long)(kaddr)-PAGE_OFFSET)>>PAGE_SHIFT))) |
158 | 157 | ||
159 | #define pfn_valid(pfn) (((pfn) >= (pfn_base)) && (((pfn)-(pfn_base)) < max_mapnr)) | 158 | #define pfn_valid(pfn) (((pfn) >= (pfn_base)) && (((pfn)-(pfn_base)) < max_mapnr)) |
@@ -164,6 +163,7 @@ extern unsigned long pfn_base; | |||
164 | 163 | ||
165 | #endif /* __KERNEL__ */ | 164 | #endif /* __KERNEL__ */ |
166 | 165 | ||
166 | #include <asm-generic/memory_model.h> | ||
167 | #include <asm-generic/page.h> | 167 | #include <asm-generic/page.h> |
168 | 168 | ||
169 | #endif /* _SPARC_PAGE_H */ | 169 | #endif /* _SPARC_PAGE_H */ |
diff --git a/include/asm-sparc64/futex.h b/include/asm-sparc64/futex.h index 34c4b43d3f98..cd340a233156 100644 --- a/include/asm-sparc64/futex.h +++ b/include/asm-sparc64/futex.h | |||
@@ -83,4 +83,10 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr) | |||
83 | return ret; | 83 | return ret; |
84 | } | 84 | } |
85 | 85 | ||
86 | static inline int | ||
87 | futex_atomic_cmpxchg_inuser(int __user *uaddr, int oldval, int newval) | ||
88 | { | ||
89 | return -ENOSYS; | ||
90 | } | ||
91 | |||
86 | #endif /* !(_SPARC64_FUTEX_H) */ | 92 | #endif /* !(_SPARC64_FUTEX_H) */ |
diff --git a/include/asm-sparc64/kdebug.h b/include/asm-sparc64/kdebug.h index 6321f5a0198d..4040d127ac3e 100644 --- a/include/asm-sparc64/kdebug.h +++ b/include/asm-sparc64/kdebug.h | |||
@@ -15,12 +15,9 @@ struct die_args { | |||
15 | int signr; | 15 | int signr; |
16 | }; | 16 | }; |
17 | 17 | ||
18 | /* Note - you should never unregister because that can race with NMIs. | 18 | extern int register_die_notifier(struct notifier_block *); |
19 | * If you really want to do it first unregister - then synchronize_sched | 19 | extern int unregister_die_notifier(struct notifier_block *); |
20 | * - then free. | 20 | extern struct atomic_notifier_head sparc64die_chain; |
21 | */ | ||
22 | int register_die_notifier(struct notifier_block *nb); | ||
23 | extern struct notifier_block *sparc64die_chain; | ||
24 | 21 | ||
25 | extern void bad_trap(struct pt_regs *, long); | 22 | extern void bad_trap(struct pt_regs *, long); |
26 | 23 | ||
@@ -46,7 +43,7 @@ static inline int notify_die(enum die_val val,char *str, struct pt_regs *regs, | |||
46 | .trapnr = trap, | 43 | .trapnr = trap, |
47 | .signr = sig }; | 44 | .signr = sig }; |
48 | 45 | ||
49 | return notifier_call_chain(&sparc64die_chain, val, &args); | 46 | return atomic_notifier_call_chain(&sparc64die_chain, val, &args); |
50 | } | 47 | } |
51 | 48 | ||
52 | #endif | 49 | #endif |
diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h index 66fe4ac59fd6..aabb21906724 100644 --- a/include/asm-sparc64/page.h +++ b/include/asm-sparc64/page.h | |||
@@ -111,6 +111,8 @@ typedef unsigned long pgprot_t; | |||
111 | (_AC(0x0000000070000000,UL)) : \ | 111 | (_AC(0x0000000070000000,UL)) : \ |
112 | (_AC(0xfffff80000000000,UL) + (1UL << 32UL))) | 112 | (_AC(0xfffff80000000000,UL) + (1UL << 32UL))) |
113 | 113 | ||
114 | #include <asm-generic/memory_model.h> | ||
115 | |||
114 | #endif /* !(__ASSEMBLY__) */ | 116 | #endif /* !(__ASSEMBLY__) */ |
115 | 117 | ||
116 | /* to align the pointer to the (next) page boundary */ | 118 | /* to align the pointer to the (next) page boundary */ |
diff --git a/include/asm-um/page.h b/include/asm-um/page.h index 0229814af31e..41364330aff1 100644 --- a/include/asm-um/page.h +++ b/include/asm-um/page.h | |||
@@ -106,9 +106,6 @@ extern unsigned long uml_physmem; | |||
106 | #define __pa(virt) to_phys((void *) (unsigned long) (virt)) | 106 | #define __pa(virt) to_phys((void *) (unsigned long) (virt)) |
107 | #define __va(phys) to_virt((unsigned long) (phys)) | 107 | #define __va(phys) to_virt((unsigned long) (phys)) |
108 | 108 | ||
109 | #define page_to_pfn(page) ((page) - mem_map) | ||
110 | #define pfn_to_page(pfn) (mem_map + (pfn)) | ||
111 | |||
112 | #define phys_to_pfn(p) ((p) >> PAGE_SHIFT) | 109 | #define phys_to_pfn(p) ((p) >> PAGE_SHIFT) |
113 | #define pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT) | 110 | #define pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT) |
114 | 111 | ||
@@ -121,6 +118,7 @@ extern struct page *arch_validate(struct page *page, gfp_t mask, int order); | |||
121 | extern void arch_free_page(struct page *page, int order); | 118 | extern void arch_free_page(struct page *page, int order); |
122 | #define HAVE_ARCH_FREE_PAGE | 119 | #define HAVE_ARCH_FREE_PAGE |
123 | 120 | ||
121 | #include <asm-generic/memory_model.h> | ||
124 | #include <asm-generic/page.h> | 122 | #include <asm-generic/page.h> |
125 | 123 | ||
126 | #endif | 124 | #endif |
diff --git a/include/asm-um/uaccess.h b/include/asm-um/uaccess.h index 2ee028b8de9d..4e460d6f5ac8 100644 --- a/include/asm-um/uaccess.h +++ b/include/asm-um/uaccess.h | |||
@@ -41,16 +41,16 @@ | |||
41 | 41 | ||
42 | #define __get_user(x, ptr) \ | 42 | #define __get_user(x, ptr) \ |
43 | ({ \ | 43 | ({ \ |
44 | const __typeof__(ptr) __private_ptr = ptr; \ | 44 | const __typeof__(ptr) __private_ptr = ptr; \ |
45 | __typeof__(*(__private_ptr)) __private_val; \ | 45 | __typeof__(x) __private_val; \ |
46 | int __private_ret = -EFAULT; \ | 46 | int __private_ret = -EFAULT; \ |
47 | (x) = (__typeof__(*(__private_ptr)))0; \ | 47 | (x) = (__typeof__(*(__private_ptr)))0; \ |
48 | if (__copy_from_user(&__private_val, (__private_ptr), \ | 48 | if (__copy_from_user((void *) &__private_val, (__private_ptr), \ |
49 | sizeof(*(__private_ptr))) == 0) {\ | 49 | sizeof(*(__private_ptr))) == 0) { \ |
50 | (x) = (__typeof__(*(__private_ptr))) __private_val; \ | 50 | (x) = (__typeof__(*(__private_ptr))) __private_val; \ |
51 | __private_ret = 0; \ | 51 | __private_ret = 0; \ |
52 | } \ | 52 | } \ |
53 | __private_ret; \ | 53 | __private_ret; \ |
54 | }) | 54 | }) |
55 | 55 | ||
56 | #define get_user(x, ptr) \ | 56 | #define get_user(x, ptr) \ |
@@ -89,14 +89,3 @@ struct exception_table_entry | |||
89 | }; | 89 | }; |
90 | 90 | ||
91 | #endif | 91 | #endif |
92 | |||
93 | /* | ||
94 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
95 | * Emacs will notice this stuff at the end of the file and automatically | ||
96 | * adjust the settings for this buffer only. This must remain at the end | ||
97 | * of the file. | ||
98 | * --------------------------------------------------------------------------- | ||
99 | * Local variables: | ||
100 | * c-file-style: "linux" | ||
101 | * End: | ||
102 | */ | ||
diff --git a/include/asm-v850/page.h b/include/asm-v850/page.h index b4bc85e7b91a..ad03c46a1f92 100644 --- a/include/asm-v850/page.h +++ b/include/asm-v850/page.h | |||
@@ -111,8 +111,7 @@ typedef unsigned long pgprot_t; | |||
111 | #define page_to_virt(page) \ | 111 | #define page_to_virt(page) \ |
112 | ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET) | 112 | ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET) |
113 | 113 | ||
114 | #define pfn_to_page(pfn) virt_to_page (pfn_to_virt (pfn)) | 114 | #define ARCH_PFN_OFFSET (PAGE_OFFSET >> PAGE_SHIFT) |
115 | #define page_to_pfn(page) virt_to_pfn (page_to_virt (page)) | ||
116 | #define pfn_valid(pfn) ((pfn) < max_mapnr) | 115 | #define pfn_valid(pfn) ((pfn) < max_mapnr) |
117 | 116 | ||
118 | #define virt_addr_valid(kaddr) \ | 117 | #define virt_addr_valid(kaddr) \ |
@@ -125,6 +124,7 @@ typedef unsigned long pgprot_t; | |||
125 | 124 | ||
126 | #endif /* KERNEL */ | 125 | #endif /* KERNEL */ |
127 | 126 | ||
127 | #include <asm-generic/memory_model.h> | ||
128 | #include <asm-generic/page.h> | 128 | #include <asm-generic/page.h> |
129 | 129 | ||
130 | #endif /* __V850_PAGE_H__ */ | 130 | #endif /* __V850_PAGE_H__ */ |
diff --git a/include/asm-x86_64/futex.h b/include/asm-x86_64/futex.h index 8602c09bf89e..9804bf07b092 100644 --- a/include/asm-x86_64/futex.h +++ b/include/asm-x86_64/futex.h | |||
@@ -94,5 +94,32 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) | |||
94 | return ret; | 94 | return ret; |
95 | } | 95 | } |
96 | 96 | ||
97 | static inline int | ||
98 | futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) | ||
99 | { | ||
100 | if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) | ||
101 | return -EFAULT; | ||
102 | |||
103 | __asm__ __volatile__( | ||
104 | "1: " LOCK_PREFIX "cmpxchgl %3, %1 \n" | ||
105 | |||
106 | "2: .section .fixup, \"ax\" \n" | ||
107 | "3: mov %2, %0 \n" | ||
108 | " jmp 2b \n" | ||
109 | " .previous \n" | ||
110 | |||
111 | " .section __ex_table, \"a\" \n" | ||
112 | " .align 8 \n" | ||
113 | " .quad 1b,3b \n" | ||
114 | " .previous \n" | ||
115 | |||
116 | : "=a" (oldval), "=m" (*uaddr) | ||
117 | : "i" (-EFAULT), "r" (newval), "0" (oldval) | ||
118 | : "memory" | ||
119 | ); | ||
120 | |||
121 | return oldval; | ||
122 | } | ||
123 | |||
97 | #endif | 124 | #endif |
98 | #endif | 125 | #endif |
diff --git a/include/asm-x86_64/kdebug.h b/include/asm-x86_64/kdebug.h index b9ed4c0c8783..cf795631d9b4 100644 --- a/include/asm-x86_64/kdebug.h +++ b/include/asm-x86_64/kdebug.h | |||
@@ -5,21 +5,20 @@ | |||
5 | 5 | ||
6 | struct pt_regs; | 6 | struct pt_regs; |
7 | 7 | ||
8 | struct die_args { | 8 | struct die_args { |
9 | struct pt_regs *regs; | 9 | struct pt_regs *regs; |
10 | const char *str; | 10 | const char *str; |
11 | long err; | 11 | long err; |
12 | int trapnr; | 12 | int trapnr; |
13 | int signr; | 13 | int signr; |
14 | }; | 14 | }; |
15 | |||
16 | extern int register_die_notifier(struct notifier_block *); | ||
17 | extern int unregister_die_notifier(struct notifier_block *); | ||
18 | extern struct atomic_notifier_head die_chain; | ||
15 | 19 | ||
16 | /* Note - you should never unregister because that can race with NMIs. | ||
17 | If you really want to do it first unregister - then synchronize_sched - then free. | ||
18 | */ | ||
19 | int register_die_notifier(struct notifier_block *nb); | ||
20 | extern struct notifier_block *die_chain; | ||
21 | /* Grossly misnamed. */ | 20 | /* Grossly misnamed. */ |
22 | enum die_val { | 21 | enum die_val { |
23 | DIE_OOPS = 1, | 22 | DIE_OOPS = 1, |
24 | DIE_INT3, | 23 | DIE_INT3, |
25 | DIE_DEBUG, | 24 | DIE_DEBUG, |
@@ -33,8 +32,8 @@ enum die_val { | |||
33 | DIE_CALL, | 32 | DIE_CALL, |
34 | DIE_NMI_IPI, | 33 | DIE_NMI_IPI, |
35 | DIE_PAGE_FAULT, | 34 | DIE_PAGE_FAULT, |
36 | }; | 35 | }; |
37 | 36 | ||
38 | static inline int notify_die(enum die_val val, const char *str, | 37 | static inline int notify_die(enum die_val val, const char *str, |
39 | struct pt_regs *regs, long err, int trap, int sig) | 38 | struct pt_regs *regs, long err, int trap, int sig) |
40 | { | 39 | { |
@@ -45,7 +44,7 @@ static inline int notify_die(enum die_val val, const char *str, | |||
45 | .trapnr = trap, | 44 | .trapnr = trap, |
46 | .signr = sig | 45 | .signr = sig |
47 | }; | 46 | }; |
48 | return notifier_call_chain(&die_chain, val, &args); | 47 | return atomic_notifier_call_chain(&die_chain, val, &args); |
49 | } | 48 | } |
50 | 49 | ||
51 | extern int printk_address(unsigned long address); | 50 | extern int printk_address(unsigned long address); |
diff --git a/include/asm-x86_64/mmzone.h b/include/asm-x86_64/mmzone.h index 937f99b26883..6b18cd8f293d 100644 --- a/include/asm-x86_64/mmzone.h +++ b/include/asm-x86_64/mmzone.h | |||
@@ -44,12 +44,8 @@ static inline __attribute__((pure)) int phys_to_nid(unsigned long addr) | |||
44 | #define pfn_to_nid(pfn) phys_to_nid((unsigned long)(pfn) << PAGE_SHIFT) | 44 | #define pfn_to_nid(pfn) phys_to_nid((unsigned long)(pfn) << PAGE_SHIFT) |
45 | #define kvaddr_to_nid(kaddr) phys_to_nid(__pa(kaddr)) | 45 | #define kvaddr_to_nid(kaddr) phys_to_nid(__pa(kaddr)) |
46 | 46 | ||
47 | extern struct page *pfn_to_page(unsigned long pfn); | ||
48 | extern unsigned long page_to_pfn(struct page *page); | ||
49 | extern int pfn_valid(unsigned long pfn); | 47 | extern int pfn_valid(unsigned long pfn); |
50 | #endif | 48 | #endif |
51 | 49 | ||
52 | #define local_mapnr(kvaddr) \ | ||
53 | ( (__pa(kvaddr) >> PAGE_SHIFT) - node_start_pfn(kvaddr_to_nid(kvaddr)) ) | ||
54 | #endif | 50 | #endif |
55 | #endif | 51 | #endif |
diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h index 615e3e494929..408185bac351 100644 --- a/include/asm-x86_64/page.h +++ b/include/asm-x86_64/page.h | |||
@@ -123,8 +123,6 @@ typedef struct { unsigned long pgprot; } pgprot_t; | |||
123 | #define __boot_va(x) __va(x) | 123 | #define __boot_va(x) __va(x) |
124 | #define __boot_pa(x) __pa(x) | 124 | #define __boot_pa(x) __pa(x) |
125 | #ifdef CONFIG_FLATMEM | 125 | #ifdef CONFIG_FLATMEM |
126 | #define pfn_to_page(pfn) (mem_map + (pfn)) | ||
127 | #define page_to_pfn(page) ((unsigned long)((page) - mem_map)) | ||
128 | #define pfn_valid(pfn) ((pfn) < end_pfn) | 126 | #define pfn_valid(pfn) ((pfn) < end_pfn) |
129 | #endif | 127 | #endif |
130 | 128 | ||
@@ -140,6 +138,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; | |||
140 | 138 | ||
141 | #endif /* __KERNEL__ */ | 139 | #endif /* __KERNEL__ */ |
142 | 140 | ||
141 | #include <asm-generic/memory_model.h> | ||
143 | #include <asm-generic/page.h> | 142 | #include <asm-generic/page.h> |
144 | 143 | ||
145 | #endif /* _X86_64_PAGE_H */ | 144 | #endif /* _X86_64_PAGE_H */ |
diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h index 8c8d88c036ed..1aa2cee43344 100644 --- a/include/asm-x86_64/processor.h +++ b/include/asm-x86_64/processor.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <asm/mmsegment.h> | 20 | #include <asm/mmsegment.h> |
21 | #include <asm/percpu.h> | 21 | #include <asm/percpu.h> |
22 | #include <linux/personality.h> | 22 | #include <linux/personality.h> |
23 | #include <linux/cpumask.h> | ||
23 | 24 | ||
24 | #define TF_MASK 0x00000100 | 25 | #define TF_MASK 0x00000100 |
25 | #define IF_MASK 0x00000200 | 26 | #define IF_MASK 0x00000200 |
@@ -65,6 +66,9 @@ struct cpuinfo_x86 { | |||
65 | __u32 x86_power; | 66 | __u32 x86_power; |
66 | __u32 extended_cpuid_level; /* Max extended CPUID function supported */ | 67 | __u32 extended_cpuid_level; /* Max extended CPUID function supported */ |
67 | unsigned long loops_per_jiffy; | 68 | unsigned long loops_per_jiffy; |
69 | #ifdef CONFIG_SMP | ||
70 | cpumask_t llc_shared_map; /* cpus sharing the last level cache */ | ||
71 | #endif | ||
68 | __u8 apicid; | 72 | __u8 apicid; |
69 | __u8 booted_cores; /* number of cores as seen by OS */ | 73 | __u8 booted_cores; /* number of cores as seen by OS */ |
70 | } ____cacheline_aligned; | 74 | } ____cacheline_aligned; |
diff --git a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h index 9ccbb2cfd5c0..a4fdaeb5c397 100644 --- a/include/asm-x86_64/smp.h +++ b/include/asm-x86_64/smp.h | |||
@@ -56,6 +56,7 @@ extern cpumask_t cpu_sibling_map[NR_CPUS]; | |||
56 | extern cpumask_t cpu_core_map[NR_CPUS]; | 56 | extern cpumask_t cpu_core_map[NR_CPUS]; |
57 | extern u8 phys_proc_id[NR_CPUS]; | 57 | extern u8 phys_proc_id[NR_CPUS]; |
58 | extern u8 cpu_core_id[NR_CPUS]; | 58 | extern u8 cpu_core_id[NR_CPUS]; |
59 | extern u8 cpu_llc_id[NR_CPUS]; | ||
59 | 60 | ||
60 | #define SMP_TRAMPOLINE_BASE 0x6000 | 61 | #define SMP_TRAMPOLINE_BASE 0x6000 |
61 | 62 | ||
diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h index c642f5d9882d..9db54e9d17bb 100644 --- a/include/asm-x86_64/topology.h +++ b/include/asm-x86_64/topology.h | |||
@@ -68,4 +68,6 @@ extern int __node_distance(int, int); | |||
68 | 68 | ||
69 | #include <asm-generic/topology.h> | 69 | #include <asm-generic/topology.h> |
70 | 70 | ||
71 | extern cpumask_t cpu_coregroup_map(int cpu); | ||
72 | |||
71 | #endif | 73 | #endif |
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h index da0341c57949..fcc516353087 100644 --- a/include/asm-x86_64/unistd.h +++ b/include/asm-x86_64/unistd.h | |||
@@ -605,8 +605,12 @@ __SYSCALL(__NR_pselect6, sys_ni_syscall) /* for now */ | |||
605 | __SYSCALL(__NR_ppoll, sys_ni_syscall) /* for now */ | 605 | __SYSCALL(__NR_ppoll, sys_ni_syscall) /* for now */ |
606 | #define __NR_unshare 272 | 606 | #define __NR_unshare 272 |
607 | __SYSCALL(__NR_unshare, sys_unshare) | 607 | __SYSCALL(__NR_unshare, sys_unshare) |
608 | #define __NR_set_robust_list 273 | ||
609 | __SYSCALL(__NR_set_robust_list, sys_set_robust_list) | ||
610 | #define __NR_get_robust_list 274 | ||
611 | __SYSCALL(__NR_get_robust_list, sys_get_robust_list) | ||
608 | 612 | ||
609 | #define __NR_syscall_max __NR_unshare | 613 | #define __NR_syscall_max __NR_get_robust_list |
610 | 614 | ||
611 | #ifndef __NO_STUBS | 615 | #ifndef __NO_STUBS |
612 | 616 | ||
diff --git a/include/asm-xtensa/page.h b/include/asm-xtensa/page.h index 8ded36f255a2..992bac5c1258 100644 --- a/include/asm-xtensa/page.h +++ b/include/asm-xtensa/page.h | |||
@@ -109,10 +109,7 @@ void copy_user_page(void *to,void* from,unsigned long vaddr,struct page* page); | |||
109 | #define __pa(x) ((unsigned long) (x) - PAGE_OFFSET) | 109 | #define __pa(x) ((unsigned long) (x) - PAGE_OFFSET) |
110 | #define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET)) | 110 | #define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET)) |
111 | #define pfn_valid(pfn) ((unsigned long)pfn < max_mapnr) | 111 | #define pfn_valid(pfn) ((unsigned long)pfn < max_mapnr) |
112 | #ifndef CONFIG_DISCONTIGMEM | 112 | #ifdef CONFIG_DISCONTIGMEM |
113 | # define pfn_to_page(pfn) (mem_map + (pfn)) | ||
114 | # define page_to_pfn(page) ((unsigned long)((page) - mem_map)) | ||
115 | #else | ||
116 | # error CONFIG_DISCONTIGMEM not supported | 113 | # error CONFIG_DISCONTIGMEM not supported |
117 | #endif | 114 | #endif |
118 | 115 | ||
@@ -130,4 +127,5 @@ void copy_user_page(void *to,void* from,unsigned long vaddr,struct page* page); | |||
130 | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) | 127 | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) |
131 | 128 | ||
132 | #endif /* __KERNEL__ */ | 129 | #endif /* __KERNEL__ */ |
130 | #include <asm-generic/memory_model.h> | ||
133 | #endif /* _XTENSA_PAGE_H */ | 131 | #endif /* _XTENSA_PAGE_H */ |
diff --git a/include/linux/adb.h b/include/linux/adb.h index e9fdc63483c7..b7305b178279 100644 --- a/include/linux/adb.h +++ b/include/linux/adb.h | |||
@@ -85,7 +85,7 @@ enum adb_message { | |||
85 | ADB_MSG_POST_RESET /* Called after resetting the bus (re-do init & register) */ | 85 | ADB_MSG_POST_RESET /* Called after resetting the bus (re-do init & register) */ |
86 | }; | 86 | }; |
87 | extern struct adb_driver *adb_controller; | 87 | extern struct adb_driver *adb_controller; |
88 | extern struct notifier_block *adb_client_list; | 88 | extern struct blocking_notifier_head adb_client_list; |
89 | 89 | ||
90 | int adb_request(struct adb_request *req, void (*done)(struct adb_request *), | 90 | int adb_request(struct adb_request *req, void (*done)(struct adb_request *), |
91 | int flags, int nbytes, ...); | 91 | int flags, int nbytes, ...); |
diff --git a/include/linux/auto_fs4.h b/include/linux/auto_fs4.h index 9343c89d843c..0a6bc52ffe88 100644 --- a/include/linux/auto_fs4.h +++ b/include/linux/auto_fs4.h | |||
@@ -19,18 +19,37 @@ | |||
19 | #undef AUTOFS_MIN_PROTO_VERSION | 19 | #undef AUTOFS_MIN_PROTO_VERSION |
20 | #undef AUTOFS_MAX_PROTO_VERSION | 20 | #undef AUTOFS_MAX_PROTO_VERSION |
21 | 21 | ||
22 | #define AUTOFS_PROTO_VERSION 4 | 22 | #define AUTOFS_PROTO_VERSION 5 |
23 | #define AUTOFS_MIN_PROTO_VERSION 3 | 23 | #define AUTOFS_MIN_PROTO_VERSION 3 |
24 | #define AUTOFS_MAX_PROTO_VERSION 4 | 24 | #define AUTOFS_MAX_PROTO_VERSION 5 |
25 | 25 | ||
26 | #define AUTOFS_PROTO_SUBVERSION 7 | 26 | #define AUTOFS_PROTO_SUBVERSION 0 |
27 | 27 | ||
28 | /* Mask for expire behaviour */ | 28 | /* Mask for expire behaviour */ |
29 | #define AUTOFS_EXP_IMMEDIATE 1 | 29 | #define AUTOFS_EXP_IMMEDIATE 1 |
30 | #define AUTOFS_EXP_LEAVES 2 | 30 | #define AUTOFS_EXP_LEAVES 2 |
31 | 31 | ||
32 | /* New message type */ | 32 | /* Daemon notification packet types */ |
33 | #define autofs_ptype_expire_multi 2 /* Expire entry (umount request) */ | 33 | enum autofs_notify { |
34 | NFY_NONE, | ||
35 | NFY_MOUNT, | ||
36 | NFY_EXPIRE | ||
37 | }; | ||
38 | |||
39 | /* Kernel protocol version 4 packet types */ | ||
40 | |||
41 | /* Expire entry (umount request) */ | ||
42 | #define autofs_ptype_expire_multi 2 | ||
43 | |||
44 | /* Kernel protocol version 5 packet types */ | ||
45 | |||
46 | /* Indirect mount missing and expire requests. */ | ||
47 | #define autofs_ptype_missing_indirect 3 | ||
48 | #define autofs_ptype_expire_indirect 4 | ||
49 | |||
50 | /* Direct mount missing and expire requests */ | ||
51 | #define autofs_ptype_missing_direct 5 | ||
52 | #define autofs_ptype_expire_direct 6 | ||
34 | 53 | ||
35 | /* v4 multi expire (via pipe) */ | 54 | /* v4 multi expire (via pipe) */ |
36 | struct autofs_packet_expire_multi { | 55 | struct autofs_packet_expire_multi { |
@@ -40,14 +59,36 @@ struct autofs_packet_expire_multi { | |||
40 | char name[NAME_MAX+1]; | 59 | char name[NAME_MAX+1]; |
41 | }; | 60 | }; |
42 | 61 | ||
62 | /* autofs v5 common packet struct */ | ||
63 | struct autofs_v5_packet { | ||
64 | struct autofs_packet_hdr hdr; | ||
65 | autofs_wqt_t wait_queue_token; | ||
66 | __u32 dev; | ||
67 | __u64 ino; | ||
68 | __u32 uid; | ||
69 | __u32 gid; | ||
70 | __u32 pid; | ||
71 | __u32 tgid; | ||
72 | __u32 len; | ||
73 | char name[NAME_MAX+1]; | ||
74 | }; | ||
75 | |||
76 | typedef struct autofs_v5_packet autofs_packet_missing_indirect_t; | ||
77 | typedef struct autofs_v5_packet autofs_packet_expire_indirect_t; | ||
78 | typedef struct autofs_v5_packet autofs_packet_missing_direct_t; | ||
79 | typedef struct autofs_v5_packet autofs_packet_expire_direct_t; | ||
80 | |||
43 | union autofs_packet_union { | 81 | union autofs_packet_union { |
44 | struct autofs_packet_hdr hdr; | 82 | struct autofs_packet_hdr hdr; |
45 | struct autofs_packet_missing missing; | 83 | struct autofs_packet_missing missing; |
46 | struct autofs_packet_expire expire; | 84 | struct autofs_packet_expire expire; |
47 | struct autofs_packet_expire_multi expire_multi; | 85 | struct autofs_packet_expire_multi expire_multi; |
86 | struct autofs_v5_packet v5_packet; | ||
48 | }; | 87 | }; |
49 | 88 | ||
50 | #define AUTOFS_IOC_EXPIRE_MULTI _IOW(0x93,0x66,int) | 89 | #define AUTOFS_IOC_EXPIRE_MULTI _IOW(0x93,0x66,int) |
90 | #define AUTOFS_IOC_EXPIRE_INDIRECT AUTOFS_IOC_EXPIRE_MULTI | ||
91 | #define AUTOFS_IOC_EXPIRE_DIRECT AUTOFS_IOC_EXPIRE_MULTI | ||
51 | #define AUTOFS_IOC_PROTOSUBVER _IOR(0x93,0x67,int) | 92 | #define AUTOFS_IOC_PROTOSUBVER _IOR(0x93,0x67,int) |
52 | #define AUTOFS_IOC_ASKREGHOST _IOR(0x93,0x68,int) | 93 | #define AUTOFS_IOC_ASKREGHOST _IOR(0x93,0x68,int) |
53 | #define AUTOFS_IOC_TOGGLEREGHOST _IOR(0x93,0x69,int) | 94 | #define AUTOFS_IOC_TOGGLEREGHOST _IOR(0x93,0x69,int) |
diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h index 7155452fb4a8..de3eb8d8ae26 100644 --- a/include/linux/bootmem.h +++ b/include/linux/bootmem.h | |||
@@ -38,6 +38,7 @@ typedef struct bootmem_data { | |||
38 | unsigned long last_pos; | 38 | unsigned long last_pos; |
39 | unsigned long last_success; /* Previous allocation point. To speed | 39 | unsigned long last_success; /* Previous allocation point. To speed |
40 | * up searching */ | 40 | * up searching */ |
41 | struct list_head list; | ||
41 | } bootmem_data_t; | 42 | } bootmem_data_t; |
42 | 43 | ||
43 | extern unsigned long __init bootmem_bootmap_pages (unsigned long); | 44 | extern unsigned long __init bootmem_bootmap_pages (unsigned long); |
diff --git a/include/linux/compat.h b/include/linux/compat.h index 24d659cdbafe..6d3a654be1ae 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h | |||
@@ -147,6 +147,24 @@ typedef struct compat_sigevent { | |||
147 | } _sigev_un; | 147 | } _sigev_un; |
148 | } compat_sigevent_t; | 148 | } compat_sigevent_t; |
149 | 149 | ||
150 | struct compat_robust_list { | ||
151 | compat_uptr_t next; | ||
152 | }; | ||
153 | |||
154 | struct compat_robust_list_head { | ||
155 | struct compat_robust_list list; | ||
156 | compat_long_t futex_offset; | ||
157 | compat_uptr_t list_op_pending; | ||
158 | }; | ||
159 | |||
160 | extern void compat_exit_robust_list(struct task_struct *curr); | ||
161 | |||
162 | asmlinkage long | ||
163 | compat_sys_set_robust_list(struct compat_robust_list_head __user *head, | ||
164 | compat_size_t len); | ||
165 | asmlinkage long | ||
166 | compat_sys_get_robust_list(int pid, compat_uptr_t *head_ptr, | ||
167 | compat_size_t __user *len_ptr); | ||
150 | 168 | ||
151 | long compat_sys_semctl(int first, int second, int third, void __user *uptr); | 169 | long compat_sys_semctl(int first, int second, int third, void __user *uptr); |
152 | long compat_sys_msgsnd(int first, int second, int third, void __user *uptr); | 170 | long compat_sys_msgsnd(int first, int second, int third, void __user *uptr); |
diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index efb518f16bb3..89ab677cb993 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h | |||
@@ -140,6 +140,7 @@ COMPATIBLE_IOCTL(DM_TABLE_DEPS_32) | |||
140 | COMPATIBLE_IOCTL(DM_TABLE_STATUS_32) | 140 | COMPATIBLE_IOCTL(DM_TABLE_STATUS_32) |
141 | COMPATIBLE_IOCTL(DM_LIST_VERSIONS_32) | 141 | COMPATIBLE_IOCTL(DM_LIST_VERSIONS_32) |
142 | COMPATIBLE_IOCTL(DM_TARGET_MSG_32) | 142 | COMPATIBLE_IOCTL(DM_TARGET_MSG_32) |
143 | COMPATIBLE_IOCTL(DM_DEV_SET_GEOMETRY_32) | ||
143 | COMPATIBLE_IOCTL(DM_VERSION) | 144 | COMPATIBLE_IOCTL(DM_VERSION) |
144 | COMPATIBLE_IOCTL(DM_REMOVE_ALL) | 145 | COMPATIBLE_IOCTL(DM_REMOVE_ALL) |
145 | COMPATIBLE_IOCTL(DM_LIST_DEVICES) | 146 | COMPATIBLE_IOCTL(DM_LIST_DEVICES) |
@@ -155,6 +156,7 @@ COMPATIBLE_IOCTL(DM_TABLE_DEPS) | |||
155 | COMPATIBLE_IOCTL(DM_TABLE_STATUS) | 156 | COMPATIBLE_IOCTL(DM_TABLE_STATUS) |
156 | COMPATIBLE_IOCTL(DM_LIST_VERSIONS) | 157 | COMPATIBLE_IOCTL(DM_LIST_VERSIONS) |
157 | COMPATIBLE_IOCTL(DM_TARGET_MSG) | 158 | COMPATIBLE_IOCTL(DM_TARGET_MSG) |
159 | COMPATIBLE_IOCTL(DM_DEV_SET_GEOMETRY) | ||
158 | /* Big K */ | 160 | /* Big K */ |
159 | COMPATIBLE_IOCTL(PIO_FONT) | 161 | COMPATIBLE_IOCTL(PIO_FONT) |
160 | COMPATIBLE_IOCTL(GIO_FONT) | 162 | COMPATIBLE_IOCTL(GIO_FONT) |
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index 51e0e95a421a..aee10b2ea4c6 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h | |||
@@ -97,6 +97,7 @@ struct io_restrictions { | |||
97 | unsigned short hardsect_size; | 97 | unsigned short hardsect_size; |
98 | unsigned int max_segment_size; | 98 | unsigned int max_segment_size; |
99 | unsigned long seg_boundary_mask; | 99 | unsigned long seg_boundary_mask; |
100 | unsigned char no_cluster; /* inverted so that 0 is default */ | ||
100 | }; | 101 | }; |
101 | 102 | ||
102 | struct dm_target { | 103 | struct dm_target { |
diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h index fa75ba0d635e..c67c6786612a 100644 --- a/include/linux/dm-ioctl.h +++ b/include/linux/dm-ioctl.h | |||
@@ -80,6 +80,16 @@ | |||
80 | * | 80 | * |
81 | * DM_TARGET_MSG: | 81 | * DM_TARGET_MSG: |
82 | * Pass a message string to the target at a specific offset of a device. | 82 | * Pass a message string to the target at a specific offset of a device. |
83 | * | ||
84 | * DM_DEV_SET_GEOMETRY: | ||
85 | * Set the geometry of a device by passing in a string in this format: | ||
86 | * | ||
87 | * "cylinders heads sectors_per_track start_sector" | ||
88 | * | ||
89 | * Beware that CHS geometry is nearly obsolete and only provided | ||
90 | * for compatibility with dm devices that can be booted by a PC | ||
91 | * BIOS. See struct hd_geometry for range limits. Also note that | ||
92 | * the geometry is erased if the device size changes. | ||
83 | */ | 93 | */ |
84 | 94 | ||
85 | /* | 95 | /* |
@@ -218,6 +228,7 @@ enum { | |||
218 | /* Added later */ | 228 | /* Added later */ |
219 | DM_LIST_VERSIONS_CMD, | 229 | DM_LIST_VERSIONS_CMD, |
220 | DM_TARGET_MSG_CMD, | 230 | DM_TARGET_MSG_CMD, |
231 | DM_DEV_SET_GEOMETRY_CMD | ||
221 | }; | 232 | }; |
222 | 233 | ||
223 | /* | 234 | /* |
@@ -247,6 +258,7 @@ typedef char ioctl_struct[308]; | |||
247 | #define DM_TABLE_STATUS_32 _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, ioctl_struct) | 258 | #define DM_TABLE_STATUS_32 _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, ioctl_struct) |
248 | #define DM_LIST_VERSIONS_32 _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, ioctl_struct) | 259 | #define DM_LIST_VERSIONS_32 _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, ioctl_struct) |
249 | #define DM_TARGET_MSG_32 _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, ioctl_struct) | 260 | #define DM_TARGET_MSG_32 _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, ioctl_struct) |
261 | #define DM_DEV_SET_GEOMETRY_32 _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, ioctl_struct) | ||
250 | #endif | 262 | #endif |
251 | 263 | ||
252 | #define DM_IOCTL 0xfd | 264 | #define DM_IOCTL 0xfd |
@@ -270,11 +282,12 @@ typedef char ioctl_struct[308]; | |||
270 | #define DM_LIST_VERSIONS _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, struct dm_ioctl) | 282 | #define DM_LIST_VERSIONS _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, struct dm_ioctl) |
271 | 283 | ||
272 | #define DM_TARGET_MSG _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, struct dm_ioctl) | 284 | #define DM_TARGET_MSG _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, struct dm_ioctl) |
285 | #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) | ||
273 | 286 | ||
274 | #define DM_VERSION_MAJOR 4 | 287 | #define DM_VERSION_MAJOR 4 |
275 | #define DM_VERSION_MINOR 5 | 288 | #define DM_VERSION_MINOR 6 |
276 | #define DM_VERSION_PATCHLEVEL 0 | 289 | #define DM_VERSION_PATCHLEVEL 0 |
277 | #define DM_VERSION_EXTRA "-ioctl (2005-10-04)" | 290 | #define DM_VERSION_EXTRA "-ioctl (2006-02-17)" |
278 | 291 | ||
279 | /* Status bits */ | 292 | /* Status bits */ |
280 | #define DM_READONLY_FLAG (1 << 0) /* In/Out */ | 293 | #define DM_READONLY_FLAG (1 << 0) /* In/Out */ |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 9d9674946956..680d913350e7 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -410,6 +410,9 @@ struct block_device { | |||
410 | struct list_head bd_inodes; | 410 | struct list_head bd_inodes; |
411 | void * bd_holder; | 411 | void * bd_holder; |
412 | int bd_holders; | 412 | int bd_holders; |
413 | #ifdef CONFIG_SYSFS | ||
414 | struct list_head bd_holder_list; | ||
415 | #endif | ||
413 | struct block_device * bd_contains; | 416 | struct block_device * bd_contains; |
414 | unsigned bd_block_size; | 417 | unsigned bd_block_size; |
415 | struct hd_struct * bd_part; | 418 | struct hd_struct * bd_part; |
@@ -1399,6 +1402,13 @@ extern int blkdev_get(struct block_device *, mode_t, unsigned); | |||
1399 | extern int blkdev_put(struct block_device *); | 1402 | extern int blkdev_put(struct block_device *); |
1400 | extern int bd_claim(struct block_device *, void *); | 1403 | extern int bd_claim(struct block_device *, void *); |
1401 | extern void bd_release(struct block_device *); | 1404 | extern void bd_release(struct block_device *); |
1405 | #ifdef CONFIG_SYSFS | ||
1406 | extern int bd_claim_by_disk(struct block_device *, void *, struct gendisk *); | ||
1407 | extern void bd_release_from_disk(struct block_device *, struct gendisk *); | ||
1408 | #else | ||
1409 | #define bd_claim_by_disk(bdev, holder, disk) bd_claim(bdev, holder) | ||
1410 | #define bd_release_from_disk(bdev, disk) bd_release(bdev) | ||
1411 | #endif | ||
1402 | 1412 | ||
1403 | /* fs/char_dev.c */ | 1413 | /* fs/char_dev.c */ |
1404 | extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *); | 1414 | extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *); |
diff --git a/include/linux/futex.h b/include/linux/futex.h index 10f96c31971e..966a5b3da439 100644 --- a/include/linux/futex.h +++ b/include/linux/futex.h | |||
@@ -1,6 +1,8 @@ | |||
1 | #ifndef _LINUX_FUTEX_H | 1 | #ifndef _LINUX_FUTEX_H |
2 | #define _LINUX_FUTEX_H | 2 | #define _LINUX_FUTEX_H |
3 | 3 | ||
4 | #include <linux/sched.h> | ||
5 | |||
4 | /* Second argument to futex syscall */ | 6 | /* Second argument to futex syscall */ |
5 | 7 | ||
6 | 8 | ||
@@ -11,10 +13,97 @@ | |||
11 | #define FUTEX_CMP_REQUEUE 4 | 13 | #define FUTEX_CMP_REQUEUE 4 |
12 | #define FUTEX_WAKE_OP 5 | 14 | #define FUTEX_WAKE_OP 5 |
13 | 15 | ||
16 | /* | ||
17 | * Support for robust futexes: the kernel cleans up held futexes at | ||
18 | * thread exit time. | ||
19 | */ | ||
20 | |||
21 | /* | ||
22 | * Per-lock list entry - embedded in user-space locks, somewhere close | ||
23 | * to the futex field. (Note: user-space uses a double-linked list to | ||
24 | * achieve O(1) list add and remove, but the kernel only needs to know | ||
25 | * about the forward link) | ||
26 | * | ||
27 | * NOTE: this structure is part of the syscall ABI, and must not be | ||
28 | * changed. | ||
29 | */ | ||
30 | struct robust_list { | ||
31 | struct robust_list __user *next; | ||
32 | }; | ||
33 | |||
34 | /* | ||
35 | * Per-thread list head: | ||
36 | * | ||
37 | * NOTE: this structure is part of the syscall ABI, and must only be | ||
38 | * changed if the change is first communicated with the glibc folks. | ||
39 | * (When an incompatible change is done, we'll increase the structure | ||
40 | * size, which glibc will detect) | ||
41 | */ | ||
42 | struct robust_list_head { | ||
43 | /* | ||
44 | * The head of the list. Points back to itself if empty: | ||
45 | */ | ||
46 | struct robust_list list; | ||
47 | |||
48 | /* | ||
49 | * This relative offset is set by user-space, it gives the kernel | ||
50 | * the relative position of the futex field to examine. This way | ||
51 | * we keep userspace flexible, to freely shape its data-structure, | ||
52 | * without hardcoding any particular offset into the kernel: | ||
53 | */ | ||
54 | long futex_offset; | ||
55 | |||
56 | /* | ||
57 | * The death of the thread may race with userspace setting | ||
58 | * up a lock's links. So to handle this race, userspace first | ||
59 | * sets this field to the address of the to-be-taken lock, | ||
60 | * then does the lock acquire, and then adds itself to the | ||
61 | * list, and then clears this field. Hence the kernel will | ||
62 | * always have full knowledge of all locks that the thread | ||
63 | * _might_ have taken. We check the owner TID in any case, | ||
64 | * so only truly owned locks will be handled. | ||
65 | */ | ||
66 | struct robust_list __user *list_op_pending; | ||
67 | }; | ||
68 | |||
69 | /* | ||
70 | * Are there any waiters for this robust futex: | ||
71 | */ | ||
72 | #define FUTEX_WAITERS 0x80000000 | ||
73 | |||
74 | /* | ||
75 | * The kernel signals via this bit that a thread holding a futex | ||
76 | * has exited without unlocking the futex. The kernel also does | ||
77 | * a FUTEX_WAKE on such futexes, after setting the bit, to wake | ||
78 | * up any possible waiters: | ||
79 | */ | ||
80 | #define FUTEX_OWNER_DIED 0x40000000 | ||
81 | |||
82 | /* | ||
83 | * The rest of the robust-futex field is for the TID: | ||
84 | */ | ||
85 | #define FUTEX_TID_MASK 0x3fffffff | ||
86 | |||
87 | /* | ||
88 | * This limit protects against a deliberately circular list. | ||
89 | * (Not worth introducing an rlimit for it) | ||
90 | */ | ||
91 | #define ROBUST_LIST_LIMIT 2048 | ||
92 | |||
14 | long do_futex(unsigned long uaddr, int op, int val, | 93 | long do_futex(unsigned long uaddr, int op, int val, |
15 | unsigned long timeout, unsigned long uaddr2, int val2, | 94 | unsigned long timeout, unsigned long uaddr2, int val2, |
16 | int val3); | 95 | int val3); |
17 | 96 | ||
97 | extern int handle_futex_death(u32 __user *uaddr, struct task_struct *curr); | ||
98 | |||
99 | #ifdef CONFIG_FUTEX | ||
100 | extern void exit_robust_list(struct task_struct *curr); | ||
101 | #else | ||
102 | static inline void exit_robust_list(struct task_struct *curr) | ||
103 | { | ||
104 | } | ||
105 | #endif | ||
106 | |||
18 | #define FUTEX_OP_SET 0 /* *(int *)UADDR2 = OPARG; */ | 107 | #define FUTEX_OP_SET 0 /* *(int *)UADDR2 = OPARG; */ |
19 | #define FUTEX_OP_ADD 1 /* *(int *)UADDR2 += OPARG; */ | 108 | #define FUTEX_OP_ADD 1 /* *(int *)UADDR2 += OPARG; */ |
20 | #define FUTEX_OP_OR 2 /* *(int *)UADDR2 |= OPARG; */ | 109 | #define FUTEX_OP_OR 2 /* *(int *)UADDR2 |= OPARG; */ |
diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 179fea53fc81..3c1b0294a742 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h | |||
@@ -78,6 +78,7 @@ struct hd_struct { | |||
78 | sector_t start_sect; | 78 | sector_t start_sect; |
79 | sector_t nr_sects; | 79 | sector_t nr_sects; |
80 | struct kobject kobj; | 80 | struct kobject kobj; |
81 | struct kobject *holder_dir; | ||
81 | unsigned ios[2], sectors[2]; /* READs and WRITEs */ | 82 | unsigned ios[2], sectors[2]; /* READs and WRITEs */ |
82 | int policy, partno; | 83 | int policy, partno; |
83 | }; | 84 | }; |
@@ -114,6 +115,8 @@ struct gendisk { | |||
114 | int number; /* more of the same */ | 115 | int number; /* more of the same */ |
115 | struct device *driverfs_dev; | 116 | struct device *driverfs_dev; |
116 | struct kobject kobj; | 117 | struct kobject kobj; |
118 | struct kobject *holder_dir; | ||
119 | struct kobject *slave_dir; | ||
117 | 120 | ||
118 | struct timer_rand_state *random; | 121 | struct timer_rand_state *random; |
119 | int policy; | 122 | int policy; |
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 679b46a6a565..c8b81f419fd8 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h | |||
@@ -108,6 +108,10 @@ | |||
108 | #define I2C_DRIVERID_UPD64083 78 /* upd64083 video processor */ | 108 | #define I2C_DRIVERID_UPD64083 78 /* upd64083 video processor */ |
109 | #define I2C_DRIVERID_UPD64031A 79 /* upd64031a video processor */ | 109 | #define I2C_DRIVERID_UPD64031A 79 /* upd64031a video processor */ |
110 | #define I2C_DRIVERID_SAA717X 80 /* saa717x video encoder */ | 110 | #define I2C_DRIVERID_SAA717X 80 /* saa717x video encoder */ |
111 | #define I2C_DRIVERID_DS1672 81 /* Dallas/Maxim DS1672 RTC */ | ||
112 | #define I2C_DRIVERID_X1205 82 /* Xicor/Intersil X1205 RTC */ | ||
113 | #define I2C_DRIVERID_PCF8563 83 /* Philips PCF8563 RTC */ | ||
114 | #define I2C_DRIVERID_RS5C372 84 /* Ricoh RS5C372 RTC */ | ||
111 | 115 | ||
112 | #define I2C_DRIVERID_I2CDEV 900 | 116 | #define I2C_DRIVERID_I2CDEV 900 |
113 | #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ | 117 | #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ |
diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 03d6cfaa5b8a..a3720f973ea5 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h | |||
@@ -87,7 +87,7 @@ extern int cond_resched(void); | |||
87 | (__x < 0) ? -__x : __x; \ | 87 | (__x < 0) ? -__x : __x; \ |
88 | }) | 88 | }) |
89 | 89 | ||
90 | extern struct notifier_block *panic_notifier_list; | 90 | extern struct atomic_notifier_head panic_notifier_list; |
91 | extern long (*panic_blink)(long time); | 91 | extern long (*panic_blink)(long time); |
92 | NORET_TYPE void panic(const char * fmt, ...) | 92 | NORET_TYPE void panic(const char * fmt, ...) |
93 | __attribute__ ((NORET_AND format (printf, 1, 2))); | 93 | __attribute__ ((NORET_AND format (printf, 1, 2))); |
diff --git a/include/linux/m48t86.h b/include/linux/m48t86.h new file mode 100644 index 000000000000..9065199319d0 --- /dev/null +++ b/include/linux/m48t86.h | |||
@@ -0,0 +1,16 @@ | |||
1 | /* | ||
2 | * ST M48T86 / Dallas DS12887 RTC driver | ||
3 | * Copyright (c) 2006 Tower Technologies | ||
4 | * | ||
5 | * Author: Alessandro Zummo <a.zummo@towertech.it> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | struct m48t86_ops | ||
13 | { | ||
14 | void (*writeb)(unsigned char value, unsigned long addr); | ||
15 | unsigned char (*readb)(unsigned long addr); | ||
16 | }; | ||
diff --git a/include/linux/memory.h b/include/linux/memory.h index e251dc43d0f5..8f04143ca363 100644 --- a/include/linux/memory.h +++ b/include/linux/memory.h | |||
@@ -77,7 +77,6 @@ extern int remove_memory_block(unsigned long, struct mem_section *, int); | |||
77 | 77 | ||
78 | #define CONFIG_MEM_BLOCK_SIZE (PAGES_PER_SECTION<<PAGE_SHIFT) | 78 | #define CONFIG_MEM_BLOCK_SIZE (PAGES_PER_SECTION<<PAGE_SHIFT) |
79 | 79 | ||
80 | struct notifier_block; | ||
81 | 80 | ||
82 | #endif /* CONFIG_MEMORY_HOTPLUG */ | 81 | #endif /* CONFIG_MEMORY_HOTPLUG */ |
83 | 82 | ||
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index ebfc238cc243..b5c21122c299 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/numa.h> | 13 | #include <linux/numa.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/seqlock.h> | 15 | #include <linux/seqlock.h> |
16 | #include <linux/nodemask.h> | ||
16 | #include <asm/atomic.h> | 17 | #include <asm/atomic.h> |
17 | 18 | ||
18 | /* Free memory management - zoned buddy allocator. */ | 19 | /* Free memory management - zoned buddy allocator. */ |
@@ -225,7 +226,6 @@ struct zone { | |||
225 | * Discontig memory support fields. | 226 | * Discontig memory support fields. |
226 | */ | 227 | */ |
227 | struct pglist_data *zone_pgdat; | 228 | struct pglist_data *zone_pgdat; |
228 | struct page *zone_mem_map; | ||
229 | /* zone_start_pfn == zone_start_paddr >> PAGE_SHIFT */ | 229 | /* zone_start_pfn == zone_start_paddr >> PAGE_SHIFT */ |
230 | unsigned long zone_start_pfn; | 230 | unsigned long zone_start_pfn; |
231 | 231 | ||
@@ -307,7 +307,6 @@ typedef struct pglist_data { | |||
307 | unsigned long node_spanned_pages; /* total size of physical page | 307 | unsigned long node_spanned_pages; /* total size of physical page |
308 | range, including holes */ | 308 | range, including holes */ |
309 | int node_id; | 309 | int node_id; |
310 | struct pglist_data *pgdat_next; | ||
311 | wait_queue_head_t kswapd_wait; | 310 | wait_queue_head_t kswapd_wait; |
312 | struct task_struct *kswapd; | 311 | struct task_struct *kswapd; |
313 | int kswapd_max_order; | 312 | int kswapd_max_order; |
@@ -324,8 +323,6 @@ typedef struct pglist_data { | |||
324 | 323 | ||
325 | #include <linux/memory_hotplug.h> | 324 | #include <linux/memory_hotplug.h> |
326 | 325 | ||
327 | extern struct pglist_data *pgdat_list; | ||
328 | |||
329 | void __get_zone_counts(unsigned long *active, unsigned long *inactive, | 326 | void __get_zone_counts(unsigned long *active, unsigned long *inactive, |
330 | unsigned long *free, struct pglist_data *pgdat); | 327 | unsigned long *free, struct pglist_data *pgdat); |
331 | void get_zone_counts(unsigned long *active, unsigned long *inactive, | 328 | void get_zone_counts(unsigned long *active, unsigned long *inactive, |
@@ -350,57 +347,6 @@ unsigned long __init node_memmap_size_bytes(int, unsigned long, unsigned long); | |||
350 | */ | 347 | */ |
351 | #define zone_idx(zone) ((zone) - (zone)->zone_pgdat->node_zones) | 348 | #define zone_idx(zone) ((zone) - (zone)->zone_pgdat->node_zones) |
352 | 349 | ||
353 | /** | ||
354 | * for_each_pgdat - helper macro to iterate over all nodes | ||
355 | * @pgdat - pointer to a pg_data_t variable | ||
356 | * | ||
357 | * Meant to help with common loops of the form | ||
358 | * pgdat = pgdat_list; | ||
359 | * while(pgdat) { | ||
360 | * ... | ||
361 | * pgdat = pgdat->pgdat_next; | ||
362 | * } | ||
363 | */ | ||
364 | #define for_each_pgdat(pgdat) \ | ||
365 | for (pgdat = pgdat_list; pgdat; pgdat = pgdat->pgdat_next) | ||
366 | |||
367 | /* | ||
368 | * next_zone - helper magic for for_each_zone() | ||
369 | * Thanks to William Lee Irwin III for this piece of ingenuity. | ||
370 | */ | ||
371 | static inline struct zone *next_zone(struct zone *zone) | ||
372 | { | ||
373 | pg_data_t *pgdat = zone->zone_pgdat; | ||
374 | |||
375 | if (zone < pgdat->node_zones + MAX_NR_ZONES - 1) | ||
376 | zone++; | ||
377 | else if (pgdat->pgdat_next) { | ||
378 | pgdat = pgdat->pgdat_next; | ||
379 | zone = pgdat->node_zones; | ||
380 | } else | ||
381 | zone = NULL; | ||
382 | |||
383 | return zone; | ||
384 | } | ||
385 | |||
386 | /** | ||
387 | * for_each_zone - helper macro to iterate over all memory zones | ||
388 | * @zone - pointer to struct zone variable | ||
389 | * | ||
390 | * The user only needs to declare the zone variable, for_each_zone | ||
391 | * fills it in. This basically means for_each_zone() is an | ||
392 | * easier to read version of this piece of code: | ||
393 | * | ||
394 | * for (pgdat = pgdat_list; pgdat; pgdat = pgdat->node_next) | ||
395 | * for (i = 0; i < MAX_NR_ZONES; ++i) { | ||
396 | * struct zone * z = pgdat->node_zones + i; | ||
397 | * ... | ||
398 | * } | ||
399 | * } | ||
400 | */ | ||
401 | #define for_each_zone(zone) \ | ||
402 | for (zone = pgdat_list->node_zones; zone; zone = next_zone(zone)) | ||
403 | |||
404 | static inline int populated_zone(struct zone *zone) | 350 | static inline int populated_zone(struct zone *zone) |
405 | { | 351 | { |
406 | return (!!zone->present_pages); | 352 | return (!!zone->present_pages); |
@@ -472,6 +418,30 @@ extern struct pglist_data contig_page_data; | |||
472 | 418 | ||
473 | #endif /* !CONFIG_NEED_MULTIPLE_NODES */ | 419 | #endif /* !CONFIG_NEED_MULTIPLE_NODES */ |
474 | 420 | ||
421 | extern struct pglist_data *first_online_pgdat(void); | ||
422 | extern struct pglist_data *next_online_pgdat(struct pglist_data *pgdat); | ||
423 | extern struct zone *next_zone(struct zone *zone); | ||
424 | |||
425 | /** | ||
426 | * for_each_pgdat - helper macro to iterate over all nodes | ||
427 | * @pgdat - pointer to a pg_data_t variable | ||
428 | */ | ||
429 | #define for_each_online_pgdat(pgdat) \ | ||
430 | for (pgdat = first_online_pgdat(); \ | ||
431 | pgdat; \ | ||
432 | pgdat = next_online_pgdat(pgdat)) | ||
433 | /** | ||
434 | * for_each_zone - helper macro to iterate over all memory zones | ||
435 | * @zone - pointer to struct zone variable | ||
436 | * | ||
437 | * The user only needs to declare the zone variable, for_each_zone | ||
438 | * fills it in. | ||
439 | */ | ||
440 | #define for_each_zone(zone) \ | ||
441 | for (zone = (first_online_pgdat())->node_zones; \ | ||
442 | zone; \ | ||
443 | zone = next_zone(zone)) | ||
444 | |||
475 | #ifdef CONFIG_SPARSEMEM | 445 | #ifdef CONFIG_SPARSEMEM |
476 | #include <asm/sparsemem.h> | 446 | #include <asm/sparsemem.h> |
477 | #endif | 447 | #endif |
@@ -602,17 +572,6 @@ static inline struct mem_section *__pfn_to_section(unsigned long pfn) | |||
602 | return __nr_to_section(pfn_to_section_nr(pfn)); | 572 | return __nr_to_section(pfn_to_section_nr(pfn)); |
603 | } | 573 | } |
604 | 574 | ||
605 | #define pfn_to_page(pfn) \ | ||
606 | ({ \ | ||
607 | unsigned long __pfn = (pfn); \ | ||
608 | __section_mem_map_addr(__pfn_to_section(__pfn)) + __pfn; \ | ||
609 | }) | ||
610 | #define page_to_pfn(page) \ | ||
611 | ({ \ | ||
612 | page - __section_mem_map_addr(__nr_to_section( \ | ||
613 | page_to_section(page))); \ | ||
614 | }) | ||
615 | |||
616 | static inline int pfn_valid(unsigned long pfn) | 575 | static inline int pfn_valid(unsigned long pfn) |
617 | { | 576 | { |
618 | if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS) | 577 | if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS) |
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h index f32d75c4f4cf..d54d7b278e96 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h | |||
@@ -308,29 +308,30 @@ DECLARE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache); | |||
308 | 308 | ||
309 | #define CONNTRACK_ECACHE(x) (__get_cpu_var(ip_conntrack_ecache).x) | 309 | #define CONNTRACK_ECACHE(x) (__get_cpu_var(ip_conntrack_ecache).x) |
310 | 310 | ||
311 | extern struct notifier_block *ip_conntrack_chain; | 311 | extern struct atomic_notifier_head ip_conntrack_chain; |
312 | extern struct notifier_block *ip_conntrack_expect_chain; | 312 | extern struct atomic_notifier_head ip_conntrack_expect_chain; |
313 | 313 | ||
314 | static inline int ip_conntrack_register_notifier(struct notifier_block *nb) | 314 | static inline int ip_conntrack_register_notifier(struct notifier_block *nb) |
315 | { | 315 | { |
316 | return notifier_chain_register(&ip_conntrack_chain, nb); | 316 | return atomic_notifier_chain_register(&ip_conntrack_chain, nb); |
317 | } | 317 | } |
318 | 318 | ||
319 | static inline int ip_conntrack_unregister_notifier(struct notifier_block *nb) | 319 | static inline int ip_conntrack_unregister_notifier(struct notifier_block *nb) |
320 | { | 320 | { |
321 | return notifier_chain_unregister(&ip_conntrack_chain, nb); | 321 | return atomic_notifier_chain_unregister(&ip_conntrack_chain, nb); |
322 | } | 322 | } |
323 | 323 | ||
324 | static inline int | 324 | static inline int |
325 | ip_conntrack_expect_register_notifier(struct notifier_block *nb) | 325 | ip_conntrack_expect_register_notifier(struct notifier_block *nb) |
326 | { | 326 | { |
327 | return notifier_chain_register(&ip_conntrack_expect_chain, nb); | 327 | return atomic_notifier_chain_register(&ip_conntrack_expect_chain, nb); |
328 | } | 328 | } |
329 | 329 | ||
330 | static inline int | 330 | static inline int |
331 | ip_conntrack_expect_unregister_notifier(struct notifier_block *nb) | 331 | ip_conntrack_expect_unregister_notifier(struct notifier_block *nb) |
332 | { | 332 | { |
333 | return notifier_chain_unregister(&ip_conntrack_expect_chain, nb); | 333 | return atomic_notifier_chain_unregister(&ip_conntrack_expect_chain, |
334 | nb); | ||
334 | } | 335 | } |
335 | 336 | ||
336 | extern void ip_ct_deliver_cached_events(const struct ip_conntrack *ct); | 337 | extern void ip_ct_deliver_cached_events(const struct ip_conntrack *ct); |
@@ -355,14 +356,14 @@ static inline void ip_conntrack_event(enum ip_conntrack_events event, | |||
355 | struct ip_conntrack *ct) | 356 | struct ip_conntrack *ct) |
356 | { | 357 | { |
357 | if (is_confirmed(ct) && !is_dying(ct)) | 358 | if (is_confirmed(ct) && !is_dying(ct)) |
358 | notifier_call_chain(&ip_conntrack_chain, event, ct); | 359 | atomic_notifier_call_chain(&ip_conntrack_chain, event, ct); |
359 | } | 360 | } |
360 | 361 | ||
361 | static inline void | 362 | static inline void |
362 | ip_conntrack_expect_event(enum ip_conntrack_expect_events event, | 363 | ip_conntrack_expect_event(enum ip_conntrack_expect_events event, |
363 | struct ip_conntrack_expect *exp) | 364 | struct ip_conntrack_expect *exp) |
364 | { | 365 | { |
365 | notifier_call_chain(&ip_conntrack_expect_chain, event, exp); | 366 | atomic_notifier_call_chain(&ip_conntrack_expect_chain, event, exp); |
366 | } | 367 | } |
367 | #else /* CONFIG_IP_NF_CONNTRACK_EVENTS */ | 368 | #else /* CONFIG_IP_NF_CONNTRACK_EVENTS */ |
368 | static inline void ip_conntrack_event_cache(enum ip_conntrack_events event, | 369 | static inline void ip_conntrack_event_cache(enum ip_conntrack_events event, |
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index 6bad4766d3d9..d2a8abb5011a 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h | |||
@@ -67,7 +67,8 @@ struct svc_expkey { | |||
67 | int ek_fsidtype; | 67 | int ek_fsidtype; |
68 | u32 ek_fsid[3]; | 68 | u32 ek_fsid[3]; |
69 | 69 | ||
70 | struct svc_export * ek_export; | 70 | struct vfsmount * ek_mnt; |
71 | struct dentry * ek_dentry; | ||
71 | }; | 72 | }; |
72 | 73 | ||
73 | #define EX_SECURE(exp) (!((exp)->ex_flags & NFSEXP_INSECURE_PORT)) | 74 | #define EX_SECURE(exp) (!((exp)->ex_flags & NFSEXP_INSECURE_PORT)) |
@@ -85,9 +86,6 @@ void nfsd_export_shutdown(void); | |||
85 | void nfsd_export_flush(void); | 86 | void nfsd_export_flush(void); |
86 | void exp_readlock(void); | 87 | void exp_readlock(void); |
87 | void exp_readunlock(void); | 88 | void exp_readunlock(void); |
88 | struct svc_expkey * exp_find_key(struct auth_domain *clp, | ||
89 | int fsid_type, u32 *fsidv, | ||
90 | struct cache_req *reqp); | ||
91 | struct svc_export * exp_get_by_name(struct auth_domain *clp, | 89 | struct svc_export * exp_get_by_name(struct auth_domain *clp, |
92 | struct vfsmount *mnt, | 90 | struct vfsmount *mnt, |
93 | struct dentry *dentry, | 91 | struct dentry *dentry, |
@@ -101,35 +99,20 @@ int exp_rootfh(struct auth_domain *, | |||
101 | int exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq); | 99 | int exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq); |
102 | int nfserrno(int errno); | 100 | int nfserrno(int errno); |
103 | 101 | ||
104 | extern void expkey_put(struct cache_head *item, struct cache_detail *cd); | 102 | extern struct cache_detail svc_export_cache; |
105 | extern void svc_export_put(struct cache_head *item, struct cache_detail *cd); | ||
106 | extern struct cache_detail svc_export_cache, svc_expkey_cache; | ||
107 | 103 | ||
108 | static inline void exp_put(struct svc_export *exp) | 104 | static inline void exp_put(struct svc_export *exp) |
109 | { | 105 | { |
110 | svc_export_put(&exp->h, &svc_export_cache); | 106 | cache_put(&exp->h, &svc_export_cache); |
111 | } | 107 | } |
112 | 108 | ||
113 | static inline void exp_get(struct svc_export *exp) | 109 | static inline void exp_get(struct svc_export *exp) |
114 | { | 110 | { |
115 | cache_get(&exp->h); | 111 | cache_get(&exp->h); |
116 | } | 112 | } |
117 | static inline struct svc_export * | 113 | extern struct svc_export * |
118 | exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, | 114 | exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, |
119 | struct cache_req *reqp) | 115 | struct cache_req *reqp); |
120 | { | ||
121 | struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp); | ||
122 | if (ek && !IS_ERR(ek)) { | ||
123 | struct svc_export *exp = ek->ek_export; | ||
124 | int err; | ||
125 | exp_get(exp); | ||
126 | expkey_put(&ek->h, &svc_expkey_cache); | ||
127 | if ((err = cache_check(&svc_export_cache, &exp->h, reqp))) | ||
128 | exp = ERR_PTR(err); | ||
129 | return exp; | ||
130 | } else | ||
131 | return ERR_PTR(PTR_ERR(ek)); | ||
132 | } | ||
133 | 116 | ||
134 | #endif /* __KERNEL__ */ | 117 | #endif /* __KERNEL__ */ |
135 | 118 | ||
diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h index b959a4525cbd..1a9ef3e627d1 100644 --- a/include/linux/nodemask.h +++ b/include/linux/nodemask.h | |||
@@ -350,11 +350,15 @@ extern nodemask_t node_possible_map; | |||
350 | #define num_possible_nodes() nodes_weight(node_possible_map) | 350 | #define num_possible_nodes() nodes_weight(node_possible_map) |
351 | #define node_online(node) node_isset((node), node_online_map) | 351 | #define node_online(node) node_isset((node), node_online_map) |
352 | #define node_possible(node) node_isset((node), node_possible_map) | 352 | #define node_possible(node) node_isset((node), node_possible_map) |
353 | #define first_online_node first_node(node_online_map) | ||
354 | #define next_online_node(nid) next_node((nid), node_online_map) | ||
353 | #else | 355 | #else |
354 | #define num_online_nodes() 1 | 356 | #define num_online_nodes() 1 |
355 | #define num_possible_nodes() 1 | 357 | #define num_possible_nodes() 1 |
356 | #define node_online(node) ((node) == 0) | 358 | #define node_online(node) ((node) == 0) |
357 | #define node_possible(node) ((node) == 0) | 359 | #define node_possible(node) ((node) == 0) |
360 | #define first_online_node 0 | ||
361 | #define next_online_node(nid) (MAX_NUMNODES) | ||
358 | #endif | 362 | #endif |
359 | 363 | ||
360 | #define any_online_node(mask) \ | 364 | #define any_online_node(mask) \ |
diff --git a/include/linux/notifier.h b/include/linux/notifier.h index 5937dd6053c3..51dbab9710c7 100644 --- a/include/linux/notifier.h +++ b/include/linux/notifier.h | |||
@@ -10,25 +10,107 @@ | |||
10 | #ifndef _LINUX_NOTIFIER_H | 10 | #ifndef _LINUX_NOTIFIER_H |
11 | #define _LINUX_NOTIFIER_H | 11 | #define _LINUX_NOTIFIER_H |
12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
13 | #include <linux/mutex.h> | ||
14 | #include <linux/rwsem.h> | ||
13 | 15 | ||
14 | struct notifier_block | 16 | /* |
15 | { | 17 | * Notifier chains are of three types: |
16 | int (*notifier_call)(struct notifier_block *self, unsigned long, void *); | 18 | * |
19 | * Atomic notifier chains: Chain callbacks run in interrupt/atomic | ||
20 | * context. Callouts are not allowed to block. | ||
21 | * Blocking notifier chains: Chain callbacks run in process context. | ||
22 | * Callouts are allowed to block. | ||
23 | * Raw notifier chains: There are no restrictions on callbacks, | ||
24 | * registration, or unregistration. All locking and protection | ||
25 | * must be provided by the caller. | ||
26 | * | ||
27 | * atomic_notifier_chain_register() may be called from an atomic context, | ||
28 | * but blocking_notifier_chain_register() must be called from a process | ||
29 | * context. Ditto for the corresponding _unregister() routines. | ||
30 | * | ||
31 | * atomic_notifier_chain_unregister() and blocking_notifier_chain_unregister() | ||
32 | * _must not_ be called from within the call chain. | ||
33 | */ | ||
34 | |||
35 | struct notifier_block { | ||
36 | int (*notifier_call)(struct notifier_block *, unsigned long, void *); | ||
17 | struct notifier_block *next; | 37 | struct notifier_block *next; |
18 | int priority; | 38 | int priority; |
19 | }; | 39 | }; |
20 | 40 | ||
41 | struct atomic_notifier_head { | ||
42 | spinlock_t lock; | ||
43 | struct notifier_block *head; | ||
44 | }; | ||
45 | |||
46 | struct blocking_notifier_head { | ||
47 | struct rw_semaphore rwsem; | ||
48 | struct notifier_block *head; | ||
49 | }; | ||
50 | |||
51 | struct raw_notifier_head { | ||
52 | struct notifier_block *head; | ||
53 | }; | ||
54 | |||
55 | #define ATOMIC_INIT_NOTIFIER_HEAD(name) do { \ | ||
56 | spin_lock_init(&(name)->lock); \ | ||
57 | (name)->head = NULL; \ | ||
58 | } while (0) | ||
59 | #define BLOCKING_INIT_NOTIFIER_HEAD(name) do { \ | ||
60 | init_rwsem(&(name)->rwsem); \ | ||
61 | (name)->head = NULL; \ | ||
62 | } while (0) | ||
63 | #define RAW_INIT_NOTIFIER_HEAD(name) do { \ | ||
64 | (name)->head = NULL; \ | ||
65 | } while (0) | ||
66 | |||
67 | #define ATOMIC_NOTIFIER_INIT(name) { \ | ||
68 | .lock = SPIN_LOCK_UNLOCKED, \ | ||
69 | .head = NULL } | ||
70 | #define BLOCKING_NOTIFIER_INIT(name) { \ | ||
71 | .rwsem = __RWSEM_INITIALIZER((name).rwsem), \ | ||
72 | .head = NULL } | ||
73 | #define RAW_NOTIFIER_INIT(name) { \ | ||
74 | .head = NULL } | ||
75 | |||
76 | #define ATOMIC_NOTIFIER_HEAD(name) \ | ||
77 | struct atomic_notifier_head name = \ | ||
78 | ATOMIC_NOTIFIER_INIT(name) | ||
79 | #define BLOCKING_NOTIFIER_HEAD(name) \ | ||
80 | struct blocking_notifier_head name = \ | ||
81 | BLOCKING_NOTIFIER_INIT(name) | ||
82 | #define RAW_NOTIFIER_HEAD(name) \ | ||
83 | struct raw_notifier_head name = \ | ||
84 | RAW_NOTIFIER_INIT(name) | ||
21 | 85 | ||
22 | #ifdef __KERNEL__ | 86 | #ifdef __KERNEL__ |
23 | 87 | ||
24 | extern int notifier_chain_register(struct notifier_block **list, struct notifier_block *n); | 88 | extern int atomic_notifier_chain_register(struct atomic_notifier_head *, |
25 | extern int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n); | 89 | struct notifier_block *); |
26 | extern int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v); | 90 | extern int blocking_notifier_chain_register(struct blocking_notifier_head *, |
91 | struct notifier_block *); | ||
92 | extern int raw_notifier_chain_register(struct raw_notifier_head *, | ||
93 | struct notifier_block *); | ||
94 | |||
95 | extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *, | ||
96 | struct notifier_block *); | ||
97 | extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *, | ||
98 | struct notifier_block *); | ||
99 | extern int raw_notifier_chain_unregister(struct raw_notifier_head *, | ||
100 | struct notifier_block *); | ||
101 | |||
102 | extern int atomic_notifier_call_chain(struct atomic_notifier_head *, | ||
103 | unsigned long val, void *v); | ||
104 | extern int blocking_notifier_call_chain(struct blocking_notifier_head *, | ||
105 | unsigned long val, void *v); | ||
106 | extern int raw_notifier_call_chain(struct raw_notifier_head *, | ||
107 | unsigned long val, void *v); | ||
27 | 108 | ||
28 | #define NOTIFY_DONE 0x0000 /* Don't care */ | 109 | #define NOTIFY_DONE 0x0000 /* Don't care */ |
29 | #define NOTIFY_OK 0x0001 /* Suits me */ | 110 | #define NOTIFY_OK 0x0001 /* Suits me */ |
30 | #define NOTIFY_STOP_MASK 0x8000 /* Don't call further */ | 111 | #define NOTIFY_STOP_MASK 0x8000 /* Don't call further */ |
31 | #define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) /* Bad/Veto action */ | 112 | #define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) |
113 | /* Bad/Veto action */ | ||
32 | /* | 114 | /* |
33 | * Clean way to return from the notifier and stop further calls. | 115 | * Clean way to return from the notifier and stop further calls. |
34 | */ | 116 | */ |
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 6f080ae59286..02f6cf20b141 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h | |||
@@ -1052,6 +1052,7 @@ | |||
1052 | #define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT2 0x00f2 | 1052 | #define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT2 0x00f2 |
1053 | #define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6200_ALT1 0x00f3 | 1053 | #define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6200_ALT1 0x00f3 |
1054 | #define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_GT 0x00f9 | 1054 | #define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_GT 0x00f9 |
1055 | #define PCIE_DEVICE_ID_NVIDIA_QUADRO_NVS280 0x00fd | ||
1055 | #define PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR 0x0100 | 1056 | #define PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR 0x0100 |
1056 | #define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR 0x0101 | 1057 | #define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR 0x0101 |
1057 | #define PCI_DEVICE_ID_NVIDIA_QUADRO 0x0103 | 1058 | #define PCI_DEVICE_ID_NVIDIA_QUADRO 0x0103 |
diff --git a/include/linux/pfn.h b/include/linux/pfn.h new file mode 100644 index 000000000000..bb01f8b92b56 --- /dev/null +++ b/include/linux/pfn.h | |||
@@ -0,0 +1,9 @@ | |||
1 | #ifndef _LINUX_PFN_H_ | ||
2 | #define _LINUX_PFN_H_ | ||
3 | |||
4 | #define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) | ||
5 | #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) | ||
6 | #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) | ||
7 | #define PFN_PHYS(x) ((x) << PAGE_SHIFT) | ||
8 | |||
9 | #endif | ||
diff --git a/include/linux/raid/md.h b/include/linux/raid/md.h index b6e0bcad84e1..66b44e5e0d6e 100644 --- a/include/linux/raid/md.h +++ b/include/linux/raid/md.h | |||
@@ -92,7 +92,10 @@ extern void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev, | |||
92 | extern void md_super_wait(mddev_t *mddev); | 92 | extern void md_super_wait(mddev_t *mddev); |
93 | extern int sync_page_io(struct block_device *bdev, sector_t sector, int size, | 93 | extern int sync_page_io(struct block_device *bdev, sector_t sector, int size, |
94 | struct page *page, int rw); | 94 | struct page *page, int rw); |
95 | extern void md_do_sync(mddev_t *mddev); | ||
96 | extern void md_new_event(mddev_t *mddev); | ||
95 | 97 | ||
98 | extern void md_update_sb(mddev_t * mddev); | ||
96 | 99 | ||
97 | #define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); } | 100 | #define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); } |
98 | 101 | ||
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 617b9506c760..e2df61f5b09a 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h | |||
@@ -132,6 +132,14 @@ struct mddev_s | |||
132 | 132 | ||
133 | char uuid[16]; | 133 | char uuid[16]; |
134 | 134 | ||
135 | /* If the array is being reshaped, we need to record the | ||
136 | * new shape and an indication of where we are up to. | ||
137 | * This is written to the superblock. | ||
138 | * If reshape_position is MaxSector, then no reshape is happening (yet). | ||
139 | */ | ||
140 | sector_t reshape_position; | ||
141 | int delta_disks, new_level, new_layout, new_chunk; | ||
142 | |||
135 | struct mdk_thread_s *thread; /* management thread */ | 143 | struct mdk_thread_s *thread; /* management thread */ |
136 | struct mdk_thread_s *sync_thread; /* doing resync or reconstruct */ | 144 | struct mdk_thread_s *sync_thread; /* doing resync or reconstruct */ |
137 | sector_t curr_resync; /* blocks scheduled */ | 145 | sector_t curr_resync; /* blocks scheduled */ |
@@ -143,6 +151,10 @@ struct mddev_s | |||
143 | sector_t resync_mismatches; /* count of sectors where | 151 | sector_t resync_mismatches; /* count of sectors where |
144 | * parity/replica mismatch found | 152 | * parity/replica mismatch found |
145 | */ | 153 | */ |
154 | |||
155 | /* allow user-space to request suspension of IO to regions of the array */ | ||
156 | sector_t suspend_lo; | ||
157 | sector_t suspend_hi; | ||
146 | /* if zero, use the system-wide default */ | 158 | /* if zero, use the system-wide default */ |
147 | int sync_speed_min; | 159 | int sync_speed_min; |
148 | int sync_speed_max; | 160 | int sync_speed_max; |
@@ -157,6 +169,9 @@ struct mddev_s | |||
157 | * DONE: thread is done and is waiting to be reaped | 169 | * DONE: thread is done and is waiting to be reaped |
158 | * REQUEST: user-space has requested a sync (used with SYNC) | 170 | * REQUEST: user-space has requested a sync (used with SYNC) |
159 | * CHECK: user-space request for for check-only, no repair | 171 | * CHECK: user-space request for for check-only, no repair |
172 | * RESHAPE: A reshape is happening | ||
173 | * | ||
174 | * If neither SYNC or RESHAPE are set, then it is a recovery. | ||
160 | */ | 175 | */ |
161 | #define MD_RECOVERY_RUNNING 0 | 176 | #define MD_RECOVERY_RUNNING 0 |
162 | #define MD_RECOVERY_SYNC 1 | 177 | #define MD_RECOVERY_SYNC 1 |
@@ -166,10 +181,11 @@ struct mddev_s | |||
166 | #define MD_RECOVERY_NEEDED 5 | 181 | #define MD_RECOVERY_NEEDED 5 |
167 | #define MD_RECOVERY_REQUESTED 6 | 182 | #define MD_RECOVERY_REQUESTED 6 |
168 | #define MD_RECOVERY_CHECK 7 | 183 | #define MD_RECOVERY_CHECK 7 |
184 | #define MD_RECOVERY_RESHAPE 8 | ||
169 | unsigned long recovery; | 185 | unsigned long recovery; |
170 | 186 | ||
171 | int in_sync; /* know to not need resync */ | 187 | int in_sync; /* know to not need resync */ |
172 | struct semaphore reconfig_sem; | 188 | struct mutex reconfig_mutex; |
173 | atomic_t active; | 189 | atomic_t active; |
174 | 190 | ||
175 | int changed; /* true if we might need to reread partition info */ | 191 | int changed; /* true if we might need to reread partition info */ |
@@ -249,7 +265,8 @@ struct mdk_personality | |||
249 | int (*spare_active) (mddev_t *mddev); | 265 | int (*spare_active) (mddev_t *mddev); |
250 | sector_t (*sync_request)(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster); | 266 | sector_t (*sync_request)(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster); |
251 | int (*resize) (mddev_t *mddev, sector_t sectors); | 267 | int (*resize) (mddev_t *mddev, sector_t sectors); |
252 | int (*reshape) (mddev_t *mddev, int raid_disks); | 268 | int (*check_reshape) (mddev_t *mddev); |
269 | int (*start_reshape) (mddev_t *mddev); | ||
253 | int (*reconfig) (mddev_t *mddev, int layout, int chunk_size); | 270 | int (*reconfig) (mddev_t *mddev, int layout, int chunk_size); |
254 | /* quiesce moves between quiescence states | 271 | /* quiesce moves between quiescence states |
255 | * 0 - fully active | 272 | * 0 - fully active |
diff --git a/include/linux/raid/md_p.h b/include/linux/raid/md_p.h index c100fa5d4bfa..774e1acfb8c4 100644 --- a/include/linux/raid/md_p.h +++ b/include/linux/raid/md_p.h | |||
@@ -102,6 +102,18 @@ typedef struct mdp_device_descriptor_s { | |||
102 | #define MD_SB_ERRORS 1 | 102 | #define MD_SB_ERRORS 1 |
103 | 103 | ||
104 | #define MD_SB_BITMAP_PRESENT 8 /* bitmap may be present nearby */ | 104 | #define MD_SB_BITMAP_PRESENT 8 /* bitmap may be present nearby */ |
105 | |||
106 | /* | ||
107 | * Notes: | ||
108 | * - if an array is being reshaped (restriped) in order to change the | ||
109 | * the number of active devices in the array, 'raid_disks' will be | ||
110 | * the larger of the old and new numbers. 'delta_disks' will | ||
111 | * be the "new - old". So if +ve, raid_disks is the new value, and | ||
112 | * "raid_disks-delta_disks" is the old. If -ve, raid_disks is the | ||
113 | * old value and "raid_disks+delta_disks" is the new (smaller) value. | ||
114 | */ | ||
115 | |||
116 | |||
105 | typedef struct mdp_superblock_s { | 117 | typedef struct mdp_superblock_s { |
106 | /* | 118 | /* |
107 | * Constant generic information | 119 | * Constant generic information |
@@ -146,7 +158,13 @@ typedef struct mdp_superblock_s { | |||
146 | __u32 cp_events_hi; /* 10 high-order of checkpoint update count */ | 158 | __u32 cp_events_hi; /* 10 high-order of checkpoint update count */ |
147 | #endif | 159 | #endif |
148 | __u32 recovery_cp; /* 11 recovery checkpoint sector count */ | 160 | __u32 recovery_cp; /* 11 recovery checkpoint sector count */ |
149 | __u32 gstate_sreserved[MD_SB_GENERIC_STATE_WORDS - 12]; | 161 | /* There are only valid for minor_version > 90 */ |
162 | __u64 reshape_position; /* 12,13 next address in array-space for reshape */ | ||
163 | __u32 new_level; /* 14 new level we are reshaping to */ | ||
164 | __u32 delta_disks; /* 15 change in number of raid_disks */ | ||
165 | __u32 new_layout; /* 16 new layout */ | ||
166 | __u32 new_chunk; /* 17 new chunk size (bytes) */ | ||
167 | __u32 gstate_sreserved[MD_SB_GENERIC_STATE_WORDS - 18]; | ||
150 | 168 | ||
151 | /* | 169 | /* |
152 | * Personality information | 170 | * Personality information |
@@ -207,7 +225,14 @@ struct mdp_superblock_1 { | |||
207 | * NOTE: signed, so bitmap can be before superblock | 225 | * NOTE: signed, so bitmap can be before superblock |
208 | * only meaningful of feature_map[0] is set. | 226 | * only meaningful of feature_map[0] is set. |
209 | */ | 227 | */ |
210 | __u8 pad1[128-100]; /* set to 0 when written */ | 228 | |
229 | /* These are only valid with feature bit '4' */ | ||
230 | __u64 reshape_position; /* next address in array-space for reshape */ | ||
231 | __u32 new_level; /* new level we are reshaping to */ | ||
232 | __u32 delta_disks; /* change in number of raid_disks */ | ||
233 | __u32 new_layout; /* new layout */ | ||
234 | __u32 new_chunk; /* new chunk size (bytes) */ | ||
235 | __u8 pad1[128-124]; /* set to 0 when written */ | ||
211 | 236 | ||
212 | /* constant this-device information - 64 bytes */ | 237 | /* constant this-device information - 64 bytes */ |
213 | __u64 data_offset; /* sector start of data, often 0 */ | 238 | __u64 data_offset; /* sector start of data, often 0 */ |
@@ -240,8 +265,9 @@ struct mdp_superblock_1 { | |||
240 | 265 | ||
241 | /* feature_map bits */ | 266 | /* feature_map bits */ |
242 | #define MD_FEATURE_BITMAP_OFFSET 1 | 267 | #define MD_FEATURE_BITMAP_OFFSET 1 |
268 | #define MD_FEATURE_RESHAPE_ACTIVE 4 | ||
243 | 269 | ||
244 | #define MD_FEATURE_ALL 1 | 270 | #define MD_FEATURE_ALL 5 |
245 | 271 | ||
246 | #endif | 272 | #endif |
247 | 273 | ||
diff --git a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h index 394da8207b34..914af667044f 100644 --- a/include/linux/raid/raid5.h +++ b/include/linux/raid/raid5.h | |||
@@ -135,6 +135,7 @@ struct stripe_head { | |||
135 | atomic_t count; /* nr of active thread/requests */ | 135 | atomic_t count; /* nr of active thread/requests */ |
136 | spinlock_t lock; | 136 | spinlock_t lock; |
137 | int bm_seq; /* sequence number for bitmap flushes */ | 137 | int bm_seq; /* sequence number for bitmap flushes */ |
138 | int disks; /* disks in stripe */ | ||
138 | struct r5dev { | 139 | struct r5dev { |
139 | struct bio req; | 140 | struct bio req; |
140 | struct bio_vec vec; | 141 | struct bio_vec vec; |
@@ -156,6 +157,7 @@ struct stripe_head { | |||
156 | #define R5_ReadError 8 /* seen a read error here recently */ | 157 | #define R5_ReadError 8 /* seen a read error here recently */ |
157 | #define R5_ReWrite 9 /* have tried to over-write the readerror */ | 158 | #define R5_ReWrite 9 /* have tried to over-write the readerror */ |
158 | 159 | ||
160 | #define R5_Expanded 10 /* This block now has post-expand data */ | ||
159 | /* | 161 | /* |
160 | * Write method | 162 | * Write method |
161 | */ | 163 | */ |
@@ -174,7 +176,9 @@ struct stripe_head { | |||
174 | #define STRIPE_DELAYED 6 | 176 | #define STRIPE_DELAYED 6 |
175 | #define STRIPE_DEGRADED 7 | 177 | #define STRIPE_DEGRADED 7 |
176 | #define STRIPE_BIT_DELAY 8 | 178 | #define STRIPE_BIT_DELAY 8 |
177 | 179 | #define STRIPE_EXPANDING 9 | |
180 | #define STRIPE_EXPAND_SOURCE 10 | ||
181 | #define STRIPE_EXPAND_READY 11 | ||
178 | /* | 182 | /* |
179 | * Plugging: | 183 | * Plugging: |
180 | * | 184 | * |
@@ -211,12 +215,24 @@ struct raid5_private_data { | |||
211 | int raid_disks, working_disks, failed_disks; | 215 | int raid_disks, working_disks, failed_disks; |
212 | int max_nr_stripes; | 216 | int max_nr_stripes; |
213 | 217 | ||
218 | /* used during an expand */ | ||
219 | sector_t expand_progress; /* MaxSector when no expand happening */ | ||
220 | sector_t expand_lo; /* from here up to expand_progress it out-of-bounds | ||
221 | * as we haven't flushed the metadata yet | ||
222 | */ | ||
223 | int previous_raid_disks; | ||
224 | |||
214 | struct list_head handle_list; /* stripes needing handling */ | 225 | struct list_head handle_list; /* stripes needing handling */ |
215 | struct list_head delayed_list; /* stripes that have plugged requests */ | 226 | struct list_head delayed_list; /* stripes that have plugged requests */ |
216 | struct list_head bitmap_list; /* stripes delaying awaiting bitmap update */ | 227 | struct list_head bitmap_list; /* stripes delaying awaiting bitmap update */ |
217 | atomic_t preread_active_stripes; /* stripes with scheduled io */ | 228 | atomic_t preread_active_stripes; /* stripes with scheduled io */ |
218 | 229 | ||
219 | char cache_name[20]; | 230 | atomic_t reshape_stripes; /* stripes with pending writes for reshape */ |
231 | /* unfortunately we need two cache names as we temporarily have | ||
232 | * two caches. | ||
233 | */ | ||
234 | int active_name; | ||
235 | char cache_name[2][20]; | ||
220 | kmem_cache_t *slab_cache; /* for allocating stripes */ | 236 | kmem_cache_t *slab_cache; /* for allocating stripes */ |
221 | 237 | ||
222 | int seq_flush, seq_write; | 238 | int seq_flush, seq_write; |
@@ -238,9 +254,10 @@ struct raid5_private_data { | |||
238 | wait_queue_head_t wait_for_overlap; | 254 | wait_queue_head_t wait_for_overlap; |
239 | int inactive_blocked; /* release of inactive stripes blocked, | 255 | int inactive_blocked; /* release of inactive stripes blocked, |
240 | * waiting for 25% to be free | 256 | * waiting for 25% to be free |
241 | */ | 257 | */ |
258 | int pool_size; /* number of disks in stripeheads in pool */ | ||
242 | spinlock_t device_lock; | 259 | spinlock_t device_lock; |
243 | struct disk_info disks[0]; | 260 | struct disk_info *disks; |
244 | }; | 261 | }; |
245 | 262 | ||
246 | typedef struct raid5_private_data raid5_conf_t; | 263 | typedef struct raid5_private_data raid5_conf_t; |
diff --git a/include/linux/rtc.h b/include/linux/rtc.h index b739ac1f7ca0..ab61cd1199f2 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h | |||
@@ -91,10 +91,102 @@ struct rtc_pll_info { | |||
91 | #define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */ | 91 | #define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */ |
92 | #define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */ | 92 | #define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */ |
93 | 93 | ||
94 | /* interrupt flags */ | ||
95 | #define RTC_IRQF 0x80 /* any of the following is active */ | ||
96 | #define RTC_PF 0x40 | ||
97 | #define RTC_AF 0x20 | ||
98 | #define RTC_UF 0x10 | ||
99 | |||
94 | #ifdef __KERNEL__ | 100 | #ifdef __KERNEL__ |
95 | 101 | ||
96 | #include <linux/interrupt.h> | 102 | #include <linux/interrupt.h> |
97 | 103 | ||
104 | extern int rtc_month_days(unsigned int month, unsigned int year); | ||
105 | extern int rtc_valid_tm(struct rtc_time *tm); | ||
106 | extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time); | ||
107 | extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm); | ||
108 | |||
109 | #include <linux/device.h> | ||
110 | #include <linux/seq_file.h> | ||
111 | #include <linux/cdev.h> | ||
112 | #include <linux/poll.h> | ||
113 | #include <linux/mutex.h> | ||
114 | |||
115 | extern struct class *rtc_class; | ||
116 | |||
117 | struct rtc_class_ops { | ||
118 | int (*open)(struct device *); | ||
119 | void (*release)(struct device *); | ||
120 | int (*ioctl)(struct device *, unsigned int, unsigned long); | ||
121 | int (*read_time)(struct device *, struct rtc_time *); | ||
122 | int (*set_time)(struct device *, struct rtc_time *); | ||
123 | int (*read_alarm)(struct device *, struct rtc_wkalrm *); | ||
124 | int (*set_alarm)(struct device *, struct rtc_wkalrm *); | ||
125 | int (*proc)(struct device *, struct seq_file *); | ||
126 | int (*set_mmss)(struct device *, unsigned long secs); | ||
127 | int (*irq_set_state)(struct device *, int enabled); | ||
128 | int (*irq_set_freq)(struct device *, int freq); | ||
129 | int (*read_callback)(struct device *, int data); | ||
130 | }; | ||
131 | |||
132 | #define RTC_DEVICE_NAME_SIZE 20 | ||
133 | struct rtc_task; | ||
134 | |||
135 | struct rtc_device | ||
136 | { | ||
137 | struct class_device class_dev; | ||
138 | struct module *owner; | ||
139 | |||
140 | int id; | ||
141 | char name[RTC_DEVICE_NAME_SIZE]; | ||
142 | |||
143 | struct rtc_class_ops *ops; | ||
144 | struct mutex ops_lock; | ||
145 | |||
146 | struct class_device *rtc_dev; | ||
147 | struct cdev char_dev; | ||
148 | struct mutex char_lock; | ||
149 | |||
150 | unsigned long irq_data; | ||
151 | spinlock_t irq_lock; | ||
152 | wait_queue_head_t irq_queue; | ||
153 | struct fasync_struct *async_queue; | ||
154 | |||
155 | struct rtc_task *irq_task; | ||
156 | spinlock_t irq_task_lock; | ||
157 | int irq_freq; | ||
158 | }; | ||
159 | #define to_rtc_device(d) container_of(d, struct rtc_device, class_dev) | ||
160 | |||
161 | extern struct rtc_device *rtc_device_register(const char *name, | ||
162 | struct device *dev, | ||
163 | struct rtc_class_ops *ops, | ||
164 | struct module *owner); | ||
165 | extern void rtc_device_unregister(struct rtc_device *rdev); | ||
166 | extern int rtc_interface_register(struct class_interface *intf); | ||
167 | |||
168 | extern int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm); | ||
169 | extern int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm); | ||
170 | extern int rtc_set_mmss(struct class_device *class_dev, unsigned long secs); | ||
171 | extern int rtc_read_alarm(struct class_device *class_dev, | ||
172 | struct rtc_wkalrm *alrm); | ||
173 | extern int rtc_set_alarm(struct class_device *class_dev, | ||
174 | struct rtc_wkalrm *alrm); | ||
175 | extern void rtc_update_irq(struct class_device *class_dev, | ||
176 | unsigned long num, unsigned long events); | ||
177 | |||
178 | extern struct class_device *rtc_class_open(char *name); | ||
179 | extern void rtc_class_close(struct class_device *class_dev); | ||
180 | |||
181 | extern int rtc_irq_register(struct class_device *class_dev, | ||
182 | struct rtc_task *task); | ||
183 | extern void rtc_irq_unregister(struct class_device *class_dev, | ||
184 | struct rtc_task *task); | ||
185 | extern int rtc_irq_set_state(struct class_device *class_dev, | ||
186 | struct rtc_task *task, int enabled); | ||
187 | extern int rtc_irq_set_freq(struct class_device *class_dev, | ||
188 | struct rtc_task *task, int freq); | ||
189 | |||
98 | typedef struct rtc_task { | 190 | typedef struct rtc_task { |
99 | void (*func)(void *private_data); | 191 | void (*func)(void *private_data); |
100 | void *private_data; | 192 | void *private_data; |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 036d14d2bf90..20b4f0372e44 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/topology.h> | 35 | #include <linux/topology.h> |
36 | #include <linux/seccomp.h> | 36 | #include <linux/seccomp.h> |
37 | #include <linux/rcupdate.h> | 37 | #include <linux/rcupdate.h> |
38 | #include <linux/futex.h> | ||
38 | 39 | ||
39 | #include <linux/auxvec.h> /* For AT_VECTOR_SIZE */ | 40 | #include <linux/auxvec.h> /* For AT_VECTOR_SIZE */ |
40 | 41 | ||
@@ -872,6 +873,11 @@ struct task_struct { | |||
872 | int cpuset_mems_generation; | 873 | int cpuset_mems_generation; |
873 | int cpuset_mem_spread_rotor; | 874 | int cpuset_mem_spread_rotor; |
874 | #endif | 875 | #endif |
876 | struct robust_list_head __user *robust_list; | ||
877 | #ifdef CONFIG_COMPAT | ||
878 | struct compat_robust_list_head __user *compat_robust_list; | ||
879 | #endif | ||
880 | |||
875 | atomic_t fs_excl; /* holding fs exclusive resources */ | 881 | atomic_t fs_excl; /* holding fs exclusive resources */ |
876 | struct rcu_head rcu; | 882 | struct rcu_head rcu; |
877 | }; | 883 | }; |
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index c4e3ea7cf154..b5612c958cce 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h | |||
@@ -50,7 +50,7 @@ struct cache_head { | |||
50 | time_t last_refresh; /* If CACHE_PENDING, this is when upcall | 50 | time_t last_refresh; /* If CACHE_PENDING, this is when upcall |
51 | * was sent, else this is when update was received | 51 | * was sent, else this is when update was received |
52 | */ | 52 | */ |
53 | atomic_t refcnt; | 53 | struct kref ref; |
54 | unsigned long flags; | 54 | unsigned long flags; |
55 | }; | 55 | }; |
56 | #define CACHE_VALID 0 /* Entry contains valid data */ | 56 | #define CACHE_VALID 0 /* Entry contains valid data */ |
@@ -68,8 +68,7 @@ struct cache_detail { | |||
68 | atomic_t inuse; /* active user-space update or lookup */ | 68 | atomic_t inuse; /* active user-space update or lookup */ |
69 | 69 | ||
70 | char *name; | 70 | char *name; |
71 | void (*cache_put)(struct cache_head *, | 71 | void (*cache_put)(struct kref *); |
72 | struct cache_detail*); | ||
73 | 72 | ||
74 | void (*cache_request)(struct cache_detail *cd, | 73 | void (*cache_request)(struct cache_detail *cd, |
75 | struct cache_head *h, | 74 | struct cache_head *h, |
@@ -81,6 +80,11 @@ struct cache_detail { | |||
81 | struct cache_detail *cd, | 80 | struct cache_detail *cd, |
82 | struct cache_head *h); | 81 | struct cache_head *h); |
83 | 82 | ||
83 | struct cache_head * (*alloc)(void); | ||
84 | int (*match)(struct cache_head *orig, struct cache_head *new); | ||
85 | void (*init)(struct cache_head *orig, struct cache_head *new); | ||
86 | void (*update)(struct cache_head *orig, struct cache_head *new); | ||
87 | |||
84 | /* fields below this comment are for internal use | 88 | /* fields below this comment are for internal use |
85 | * and should not be touched by cache owners | 89 | * and should not be touched by cache owners |
86 | */ | 90 | */ |
@@ -123,126 +127,14 @@ struct cache_deferred_req { | |||
123 | int too_many); | 127 | int too_many); |
124 | }; | 128 | }; |
125 | 129 | ||
126 | /* | ||
127 | * just like a template in C++, this macro does cache lookup | ||
128 | * for us. | ||
129 | * The function is passed some sort of HANDLE from which a cache_detail | ||
130 | * structure can be determined (via SETUP, DETAIL), a template | ||
131 | * cache entry (type RTN*), and a "set" flag. Using the HASHFN and the | ||
132 | * TEST, the function will try to find a matching cache entry in the cache. | ||
133 | * If "set" == 0 : | ||
134 | * If an entry is found, it is returned | ||
135 | * If no entry is found, a new non-VALID entry is created. | ||
136 | * If "set" == 1 and INPLACE == 0 : | ||
137 | * If no entry is found a new one is inserted with data from "template" | ||
138 | * If a non-CACHE_VALID entry is found, it is updated from template using UPDATE | ||
139 | * If a CACHE_VALID entry is found, a new entry is swapped in with data | ||
140 | * from "template" | ||
141 | * If set == 1, and INPLACE == 1 : | ||
142 | * As above, except that if a CACHE_VALID entry is found, we UPDATE in place | ||
143 | * instead of swapping in a new entry. | ||
144 | * | ||
145 | * If the passed handle has the CACHE_NEGATIVE flag set, then UPDATE is not | ||
146 | * run but insteead CACHE_NEGATIVE is set in any new item. | ||
147 | 130 | ||
148 | * In any case, the new entry is returned with a reference count. | 131 | extern struct cache_head * |
149 | * | 132 | sunrpc_cache_lookup(struct cache_detail *detail, |
150 | * | 133 | struct cache_head *key, int hash); |
151 | * RTN is a struct type for a cache entry | 134 | extern struct cache_head * |
152 | * MEMBER is the member of the cache which is cache_head, which must be first | 135 | sunrpc_cache_update(struct cache_detail *detail, |
153 | * FNAME is the name for the function | 136 | struct cache_head *new, struct cache_head *old, int hash); |
154 | * ARGS are arguments to function and must contain RTN *item, int set. May | ||
155 | * also contain something to be usedby SETUP or DETAIL to find cache_detail. | ||
156 | * SETUP locates the cache detail and makes it available as... | ||
157 | * DETAIL identifies the cache detail, possibly set up by SETUP | ||
158 | * HASHFN returns a hash value of the cache entry "item" | ||
159 | * TEST tests if "tmp" matches "item" | ||
160 | * INIT copies key information from "item" to "new" | ||
161 | * UPDATE copies content information from "item" to "tmp" | ||
162 | * INPLACE is true if updates can happen inplace rather than allocating a new structure | ||
163 | * | ||
164 | * WARNING: any substantial changes to this must be reflected in | ||
165 | * net/sunrpc/svcauth.c(auth_domain_lookup) | ||
166 | * which is a similar routine that is open-coded. | ||
167 | */ | ||
168 | #define DefineCacheLookup(RTN,MEMBER,FNAME,ARGS,SETUP,DETAIL,HASHFN,TEST,INIT,UPDATE,INPLACE) \ | ||
169 | RTN *FNAME ARGS \ | ||
170 | { \ | ||
171 | RTN *tmp, *new=NULL; \ | ||
172 | struct cache_head **hp, **head; \ | ||
173 | SETUP; \ | ||
174 | head = &(DETAIL)->hash_table[HASHFN]; \ | ||
175 | retry: \ | ||
176 | if (set||new) write_lock(&(DETAIL)->hash_lock); \ | ||
177 | else read_lock(&(DETAIL)->hash_lock); \ | ||
178 | for(hp=head; *hp != NULL; hp = &tmp->MEMBER.next) { \ | ||
179 | tmp = container_of(*hp, RTN, MEMBER); \ | ||
180 | if (TEST) { /* found a match */ \ | ||
181 | \ | ||
182 | if (set && !INPLACE && test_bit(CACHE_VALID, &tmp->MEMBER.flags) && !new) \ | ||
183 | break; \ | ||
184 | \ | ||
185 | if (new) \ | ||
186 | {INIT;} \ | ||
187 | if (set) { \ | ||
188 | if (!INPLACE && test_bit(CACHE_VALID, &tmp->MEMBER.flags))\ | ||
189 | { /* need to swap in new */ \ | ||
190 | RTN *t2; \ | ||
191 | \ | ||
192 | new->MEMBER.next = tmp->MEMBER.next; \ | ||
193 | *hp = &new->MEMBER; \ | ||
194 | tmp->MEMBER.next = NULL; \ | ||
195 | t2 = tmp; tmp = new; new = t2; \ | ||
196 | } \ | ||
197 | if (test_bit(CACHE_NEGATIVE, &item->MEMBER.flags)) \ | ||
198 | set_bit(CACHE_NEGATIVE, &tmp->MEMBER.flags); \ | ||
199 | else { \ | ||
200 | UPDATE; \ | ||
201 | clear_bit(CACHE_NEGATIVE, &tmp->MEMBER.flags); \ | ||
202 | } \ | ||
203 | } \ | ||
204 | cache_get(&tmp->MEMBER); \ | ||
205 | if (set||new) write_unlock(&(DETAIL)->hash_lock); \ | ||
206 | else read_unlock(&(DETAIL)->hash_lock); \ | ||
207 | if (set) \ | ||
208 | cache_fresh(DETAIL, &tmp->MEMBER, item->MEMBER.expiry_time); \ | ||
209 | if (set && !INPLACE && new) cache_fresh(DETAIL, &new->MEMBER, 0); \ | ||
210 | if (new) (DETAIL)->cache_put(&new->MEMBER, DETAIL); \ | ||
211 | return tmp; \ | ||
212 | } \ | ||
213 | } \ | ||
214 | /* Didn't find anything */ \ | ||
215 | if (new) { \ | ||
216 | INIT; \ | ||
217 | new->MEMBER.next = *head; \ | ||
218 | *head = &new->MEMBER; \ | ||
219 | (DETAIL)->entries ++; \ | ||
220 | cache_get(&new->MEMBER); \ | ||
221 | if (set) { \ | ||
222 | tmp = new; \ | ||
223 | if (test_bit(CACHE_NEGATIVE, &item->MEMBER.flags)) \ | ||
224 | set_bit(CACHE_NEGATIVE, &tmp->MEMBER.flags); \ | ||
225 | else {UPDATE;} \ | ||
226 | } \ | ||
227 | } \ | ||
228 | if (set||new) write_unlock(&(DETAIL)->hash_lock); \ | ||
229 | else read_unlock(&(DETAIL)->hash_lock); \ | ||
230 | if (new && set) \ | ||
231 | cache_fresh(DETAIL, &new->MEMBER, item->MEMBER.expiry_time); \ | ||
232 | if (new) \ | ||
233 | return new; \ | ||
234 | new = kmalloc(sizeof(*new), GFP_KERNEL); \ | ||
235 | if (new) { \ | ||
236 | cache_init(&new->MEMBER); \ | ||
237 | goto retry; \ | ||
238 | } \ | ||
239 | return NULL; \ | ||
240 | } | ||
241 | 137 | ||
242 | #define DefineSimpleCacheLookup(STRUCT,INPLACE) \ | ||
243 | DefineCacheLookup(struct STRUCT, h, STRUCT##_lookup, (struct STRUCT *item, int set), /*no setup */, \ | ||
244 | & STRUCT##_cache, STRUCT##_hash(item), STRUCT##_match(item, tmp),\ | ||
245 | STRUCT##_init(new, item), STRUCT##_update(tmp, item),INPLACE) | ||
246 | 138 | ||
247 | #define cache_for_each(pos, detail, index, member) \ | 139 | #define cache_for_each(pos, detail, index, member) \ |
248 | for (({read_lock(&(detail)->hash_lock); index = (detail)->hash_size;}) ; \ | 140 | for (({read_lock(&(detail)->hash_lock); index = (detail)->hash_size;}) ; \ |
@@ -258,22 +150,19 @@ extern void cache_clean_deferred(void *owner); | |||
258 | 150 | ||
259 | static inline struct cache_head *cache_get(struct cache_head *h) | 151 | static inline struct cache_head *cache_get(struct cache_head *h) |
260 | { | 152 | { |
261 | atomic_inc(&h->refcnt); | 153 | kref_get(&h->ref); |
262 | return h; | 154 | return h; |
263 | } | 155 | } |
264 | 156 | ||
265 | 157 | ||
266 | static inline int cache_put(struct cache_head *h, struct cache_detail *cd) | 158 | static inline void cache_put(struct cache_head *h, struct cache_detail *cd) |
267 | { | 159 | { |
268 | if (atomic_read(&h->refcnt) <= 2 && | 160 | if (atomic_read(&h->ref.refcount) <= 2 && |
269 | h->expiry_time < cd->nextcheck) | 161 | h->expiry_time < cd->nextcheck) |
270 | cd->nextcheck = h->expiry_time; | 162 | cd->nextcheck = h->expiry_time; |
271 | return atomic_dec_and_test(&h->refcnt); | 163 | kref_put(&h->ref, cd->cache_put); |
272 | } | 164 | } |
273 | 165 | ||
274 | extern void cache_init(struct cache_head *h); | ||
275 | extern void cache_fresh(struct cache_detail *detail, | ||
276 | struct cache_head *head, time_t expiry); | ||
277 | extern int cache_check(struct cache_detail *detail, | 166 | extern int cache_check(struct cache_detail *detail, |
278 | struct cache_head *h, struct cache_req *rqstp); | 167 | struct cache_head *h, struct cache_req *rqstp); |
279 | extern void cache_flush(void); | 168 | extern void cache_flush(void); |
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h index c119ce7cbd22..2fe2087edd66 100644 --- a/include/linux/sunrpc/svcauth.h +++ b/include/linux/sunrpc/svcauth.h | |||
@@ -45,9 +45,10 @@ struct svc_rqst; /* forward decl */ | |||
45 | * of ip addresses to the given client. | 45 | * of ip addresses to the given client. |
46 | */ | 46 | */ |
47 | struct auth_domain { | 47 | struct auth_domain { |
48 | struct cache_head h; | 48 | struct kref ref; |
49 | struct hlist_node hash; | ||
49 | char *name; | 50 | char *name; |
50 | int flavour; | 51 | struct auth_ops *flavour; |
51 | }; | 52 | }; |
52 | 53 | ||
53 | /* | 54 | /* |
@@ -86,6 +87,9 @@ struct auth_domain { | |||
86 | * | 87 | * |
87 | * domain_release() | 88 | * domain_release() |
88 | * This call releases a domain. | 89 | * This call releases a domain. |
90 | * set_client() | ||
91 | * Givens a pending request (struct svc_rqst), finds and assigns | ||
92 | * an appropriate 'auth_domain' as the client. | ||
89 | */ | 93 | */ |
90 | struct auth_ops { | 94 | struct auth_ops { |
91 | char * name; | 95 | char * name; |
@@ -117,7 +121,7 @@ extern void svc_auth_unregister(rpc_authflavor_t flavor); | |||
117 | extern struct auth_domain *unix_domain_find(char *name); | 121 | extern struct auth_domain *unix_domain_find(char *name); |
118 | extern void auth_domain_put(struct auth_domain *item); | 122 | extern void auth_domain_put(struct auth_domain *item); |
119 | extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom); | 123 | extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom); |
120 | extern struct auth_domain *auth_domain_lookup(struct auth_domain *item, int set); | 124 | extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *new); |
121 | extern struct auth_domain *auth_domain_find(char *name); | 125 | extern struct auth_domain *auth_domain_find(char *name); |
122 | extern struct auth_domain *auth_unix_lookup(struct in_addr addr); | 126 | extern struct auth_domain *auth_unix_lookup(struct in_addr addr); |
123 | extern int auth_unix_forget_old(struct auth_domain *dom); | 127 | extern int auth_unix_forget_old(struct auth_domain *dom); |
@@ -160,8 +164,6 @@ static inline unsigned long hash_mem(char *buf, int length, int bits) | |||
160 | return hash >> (BITS_PER_LONG - bits); | 164 | return hash >> (BITS_PER_LONG - bits); |
161 | } | 165 | } |
162 | 166 | ||
163 | extern struct cache_detail auth_domain_cache, ip_map_cache; | ||
164 | |||
165 | #endif /* __KERNEL__ */ | 167 | #endif /* __KERNEL__ */ |
166 | 168 | ||
167 | #endif /* _LINUX_SUNRPC_SVCAUTH_H_ */ | 169 | #endif /* _LINUX_SUNRPC_SVCAUTH_H_ */ |
diff --git a/include/linux/threads.h b/include/linux/threads.h index b59738ac6197..e646bcdf2614 100644 --- a/include/linux/threads.h +++ b/include/linux/threads.h | |||
@@ -28,7 +28,8 @@ | |||
28 | #define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000) | 28 | #define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000) |
29 | 29 | ||
30 | /* | 30 | /* |
31 | * A maximum of 4 million PIDs should be enough for a while: | 31 | * A maximum of 4 million PIDs should be enough for a while. |
32 | * [NOTE: PID/TIDs are limited to 2^29 ~= 500+ million, see futex.h.] | ||
32 | */ | 33 | */ |
33 | #define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \ | 34 | #define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \ |
34 | (sizeof(long) > 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT)) | 35 | (sizeof(long) > 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT)) |
diff --git a/include/linux/topology.h b/include/linux/topology.h index e8eb0040ce3a..a305ae2e44b6 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h | |||
@@ -164,6 +164,15 @@ | |||
164 | .nr_balance_failed = 0, \ | 164 | .nr_balance_failed = 0, \ |
165 | } | 165 | } |
166 | 166 | ||
167 | #ifdef CONFIG_SCHED_MC | ||
168 | #ifndef SD_MC_INIT | ||
169 | /* for now its same as SD_CPU_INIT. | ||
170 | * TBD: Tune Domain parameters! | ||
171 | */ | ||
172 | #define SD_MC_INIT SD_CPU_INIT | ||
173 | #endif | ||
174 | #endif | ||
175 | |||
167 | #ifdef CONFIG_NUMA | 176 | #ifdef CONFIG_NUMA |
168 | #ifndef SD_NODE_INIT | 177 | #ifndef SD_NODE_INIT |
169 | #error Please define an appropriate SD_NODE_INIT in include/asm/topology.h!!! | 178 | #error Please define an appropriate SD_NODE_INIT in include/asm/topology.h!!! |
diff --git a/include/linux/x1205.h b/include/linux/x1205.h deleted file mode 100644 index 64fd3af894a5..000000000000 --- a/include/linux/x1205.h +++ /dev/null | |||
@@ -1,31 +0,0 @@ | |||
1 | /* | ||
2 | * x1205.h - defines for drivers/i2c/chips/x1205.c | ||
3 | * Copyright 2004 Karen Spearel | ||
4 | * Copyright 2005 Alessandro Zummo | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #ifndef __LINUX_X1205_H__ | ||
13 | #define __LINUX_X1205_H__ | ||
14 | |||
15 | /* commands */ | ||
16 | |||
17 | #define X1205_CMD_GETDATETIME 0 | ||
18 | #define X1205_CMD_SETTIME 1 | ||
19 | #define X1205_CMD_SETDATETIME 2 | ||
20 | #define X1205_CMD_GETALARM 3 | ||
21 | #define X1205_CMD_SETALARM 4 | ||
22 | #define X1205_CMD_GETDTRIM 5 | ||
23 | #define X1205_CMD_SETDTRIM 6 | ||
24 | #define X1205_CMD_GETATRIM 7 | ||
25 | #define X1205_CMD_SETATRIM 8 | ||
26 | |||
27 | extern int x1205_do_command(unsigned int cmd, void *arg); | ||
28 | extern int x1205_direct_attach(int adapter_id, | ||
29 | struct i2c_client_address_data *address_data); | ||
30 | |||
31 | #endif /* __LINUX_X1205_H__ */ | ||
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index b6f0905a4ee2..916013ca4a5c 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h | |||
@@ -300,29 +300,30 @@ DECLARE_PER_CPU(struct nf_conntrack_ecache, nf_conntrack_ecache); | |||
300 | 300 | ||
301 | #define CONNTRACK_ECACHE(x) (__get_cpu_var(nf_conntrack_ecache).x) | 301 | #define CONNTRACK_ECACHE(x) (__get_cpu_var(nf_conntrack_ecache).x) |
302 | 302 | ||
303 | extern struct notifier_block *nf_conntrack_chain; | 303 | extern struct atomic_notifier_head nf_conntrack_chain; |
304 | extern struct notifier_block *nf_conntrack_expect_chain; | 304 | extern struct atomic_notifier_head nf_conntrack_expect_chain; |
305 | 305 | ||
306 | static inline int nf_conntrack_register_notifier(struct notifier_block *nb) | 306 | static inline int nf_conntrack_register_notifier(struct notifier_block *nb) |
307 | { | 307 | { |
308 | return notifier_chain_register(&nf_conntrack_chain, nb); | 308 | return atomic_notifier_chain_register(&nf_conntrack_chain, nb); |
309 | } | 309 | } |
310 | 310 | ||
311 | static inline int nf_conntrack_unregister_notifier(struct notifier_block *nb) | 311 | static inline int nf_conntrack_unregister_notifier(struct notifier_block *nb) |
312 | { | 312 | { |
313 | return notifier_chain_unregister(&nf_conntrack_chain, nb); | 313 | return atomic_notifier_chain_unregister(&nf_conntrack_chain, nb); |
314 | } | 314 | } |
315 | 315 | ||
316 | static inline int | 316 | static inline int |
317 | nf_conntrack_expect_register_notifier(struct notifier_block *nb) | 317 | nf_conntrack_expect_register_notifier(struct notifier_block *nb) |
318 | { | 318 | { |
319 | return notifier_chain_register(&nf_conntrack_expect_chain, nb); | 319 | return atomic_notifier_chain_register(&nf_conntrack_expect_chain, nb); |
320 | } | 320 | } |
321 | 321 | ||
322 | static inline int | 322 | static inline int |
323 | nf_conntrack_expect_unregister_notifier(struct notifier_block *nb) | 323 | nf_conntrack_expect_unregister_notifier(struct notifier_block *nb) |
324 | { | 324 | { |
325 | return notifier_chain_unregister(&nf_conntrack_expect_chain, nb); | 325 | return atomic_notifier_chain_unregister(&nf_conntrack_expect_chain, |
326 | nb); | ||
326 | } | 327 | } |
327 | 328 | ||
328 | extern void nf_ct_deliver_cached_events(const struct nf_conn *ct); | 329 | extern void nf_ct_deliver_cached_events(const struct nf_conn *ct); |
@@ -347,14 +348,14 @@ static inline void nf_conntrack_event(enum ip_conntrack_events event, | |||
347 | struct nf_conn *ct) | 348 | struct nf_conn *ct) |
348 | { | 349 | { |
349 | if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) | 350 | if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) |
350 | notifier_call_chain(&nf_conntrack_chain, event, ct); | 351 | atomic_notifier_call_chain(&nf_conntrack_chain, event, ct); |
351 | } | 352 | } |
352 | 353 | ||
353 | static inline void | 354 | static inline void |
354 | nf_conntrack_expect_event(enum ip_conntrack_expect_events event, | 355 | nf_conntrack_expect_event(enum ip_conntrack_expect_events event, |
355 | struct nf_conntrack_expect *exp) | 356 | struct nf_conntrack_expect *exp) |
356 | { | 357 | { |
357 | notifier_call_chain(&nf_conntrack_expect_chain, event, exp); | 358 | atomic_notifier_call_chain(&nf_conntrack_expect_chain, event, exp); |
358 | } | 359 | } |
359 | #else /* CONFIG_NF_CONNTRACK_EVENTS */ | 360 | #else /* CONFIG_NF_CONNTRACK_EVENTS */ |
360 | static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, | 361 | static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, |
diff --git a/kernel/Makefile b/kernel/Makefile index ff1c11dc12cf..58908f9d156a 100644 --- a/kernel/Makefile +++ b/kernel/Makefile | |||
@@ -12,6 +12,9 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ | |||
12 | 12 | ||
13 | obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o | 13 | obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o |
14 | obj-$(CONFIG_FUTEX) += futex.o | 14 | obj-$(CONFIG_FUTEX) += futex.o |
15 | ifeq ($(CONFIG_COMPAT),y) | ||
16 | obj-$(CONFIG_FUTEX) += futex_compat.o | ||
17 | endif | ||
15 | obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o | 18 | obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o |
16 | obj-$(CONFIG_SMP) += cpu.o spinlock.o | 19 | obj-$(CONFIG_SMP) += cpu.o spinlock.o |
17 | obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o | 20 | obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o |
diff --git a/kernel/compat.c b/kernel/compat.c index b9bdd1271f44..c1601a84f8d8 100644 --- a/kernel/compat.c +++ b/kernel/compat.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <linux/time.h> | 17 | #include <linux/time.h> |
18 | #include <linux/signal.h> | 18 | #include <linux/signal.h> |
19 | #include <linux/sched.h> /* for MAX_SCHEDULE_TIMEOUT */ | 19 | #include <linux/sched.h> /* for MAX_SCHEDULE_TIMEOUT */ |
20 | #include <linux/futex.h> /* for FUTEX_WAIT */ | ||
21 | #include <linux/syscalls.h> | 20 | #include <linux/syscalls.h> |
22 | #include <linux/unistd.h> | 21 | #include <linux/unistd.h> |
23 | #include <linux/security.h> | 22 | #include <linux/security.h> |
@@ -239,28 +238,6 @@ asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *set, | |||
239 | return ret; | 238 | return ret; |
240 | } | 239 | } |
241 | 240 | ||
242 | #ifdef CONFIG_FUTEX | ||
243 | asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, int val, | ||
244 | struct compat_timespec __user *utime, u32 __user *uaddr2, | ||
245 | int val3) | ||
246 | { | ||
247 | struct timespec t; | ||
248 | unsigned long timeout = MAX_SCHEDULE_TIMEOUT; | ||
249 | int val2 = 0; | ||
250 | |||
251 | if ((op == FUTEX_WAIT) && utime) { | ||
252 | if (get_compat_timespec(&t, utime)) | ||
253 | return -EFAULT; | ||
254 | timeout = timespec_to_jiffies(&t) + 1; | ||
255 | } | ||
256 | if (op >= FUTEX_REQUEUE) | ||
257 | val2 = (int) (unsigned long) utime; | ||
258 | |||
259 | return do_futex((unsigned long)uaddr, op, val, timeout, | ||
260 | (unsigned long)uaddr2, val2, val3); | ||
261 | } | ||
262 | #endif | ||
263 | |||
264 | asmlinkage long compat_sys_setrlimit(unsigned int resource, | 241 | asmlinkage long compat_sys_setrlimit(unsigned int resource, |
265 | struct compat_rlimit __user *rlim) | 242 | struct compat_rlimit __user *rlim) |
266 | { | 243 | { |
diff --git a/kernel/cpu.c b/kernel/cpu.c index 8be22bd80933..fe2b8d0bfe4c 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
@@ -18,7 +18,7 @@ | |||
18 | /* This protects CPUs going up and down... */ | 18 | /* This protects CPUs going up and down... */ |
19 | static DECLARE_MUTEX(cpucontrol); | 19 | static DECLARE_MUTEX(cpucontrol); |
20 | 20 | ||
21 | static struct notifier_block *cpu_chain; | 21 | static BLOCKING_NOTIFIER_HEAD(cpu_chain); |
22 | 22 | ||
23 | #ifdef CONFIG_HOTPLUG_CPU | 23 | #ifdef CONFIG_HOTPLUG_CPU |
24 | static struct task_struct *lock_cpu_hotplug_owner; | 24 | static struct task_struct *lock_cpu_hotplug_owner; |
@@ -71,21 +71,13 @@ EXPORT_SYMBOL_GPL(lock_cpu_hotplug_interruptible); | |||
71 | /* Need to know about CPUs going up/down? */ | 71 | /* Need to know about CPUs going up/down? */ |
72 | int register_cpu_notifier(struct notifier_block *nb) | 72 | int register_cpu_notifier(struct notifier_block *nb) |
73 | { | 73 | { |
74 | int ret; | 74 | return blocking_notifier_chain_register(&cpu_chain, nb); |
75 | |||
76 | if ((ret = lock_cpu_hotplug_interruptible()) != 0) | ||
77 | return ret; | ||
78 | ret = notifier_chain_register(&cpu_chain, nb); | ||
79 | unlock_cpu_hotplug(); | ||
80 | return ret; | ||
81 | } | 75 | } |
82 | EXPORT_SYMBOL(register_cpu_notifier); | 76 | EXPORT_SYMBOL(register_cpu_notifier); |
83 | 77 | ||
84 | void unregister_cpu_notifier(struct notifier_block *nb) | 78 | void unregister_cpu_notifier(struct notifier_block *nb) |
85 | { | 79 | { |
86 | lock_cpu_hotplug(); | 80 | blocking_notifier_chain_unregister(&cpu_chain, nb); |
87 | notifier_chain_unregister(&cpu_chain, nb); | ||
88 | unlock_cpu_hotplug(); | ||
89 | } | 81 | } |
90 | EXPORT_SYMBOL(unregister_cpu_notifier); | 82 | EXPORT_SYMBOL(unregister_cpu_notifier); |
91 | 83 | ||
@@ -141,7 +133,7 @@ int cpu_down(unsigned int cpu) | |||
141 | goto out; | 133 | goto out; |
142 | } | 134 | } |
143 | 135 | ||
144 | err = notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, | 136 | err = blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, |
145 | (void *)(long)cpu); | 137 | (void *)(long)cpu); |
146 | if (err == NOTIFY_BAD) { | 138 | if (err == NOTIFY_BAD) { |
147 | printk("%s: attempt to take down CPU %u failed\n", | 139 | printk("%s: attempt to take down CPU %u failed\n", |
@@ -159,7 +151,7 @@ int cpu_down(unsigned int cpu) | |||
159 | p = __stop_machine_run(take_cpu_down, NULL, cpu); | 151 | p = __stop_machine_run(take_cpu_down, NULL, cpu); |
160 | if (IS_ERR(p)) { | 152 | if (IS_ERR(p)) { |
161 | /* CPU didn't die: tell everyone. Can't complain. */ | 153 | /* CPU didn't die: tell everyone. Can't complain. */ |
162 | if (notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, | 154 | if (blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, |
163 | (void *)(long)cpu) == NOTIFY_BAD) | 155 | (void *)(long)cpu) == NOTIFY_BAD) |
164 | BUG(); | 156 | BUG(); |
165 | 157 | ||
@@ -182,8 +174,8 @@ int cpu_down(unsigned int cpu) | |||
182 | put_cpu(); | 174 | put_cpu(); |
183 | 175 | ||
184 | /* CPU is completely dead: tell everyone. Too late to complain. */ | 176 | /* CPU is completely dead: tell everyone. Too late to complain. */ |
185 | if (notifier_call_chain(&cpu_chain, CPU_DEAD, (void *)(long)cpu) | 177 | if (blocking_notifier_call_chain(&cpu_chain, CPU_DEAD, |
186 | == NOTIFY_BAD) | 178 | (void *)(long)cpu) == NOTIFY_BAD) |
187 | BUG(); | 179 | BUG(); |
188 | 180 | ||
189 | check_for_tasks(cpu); | 181 | check_for_tasks(cpu); |
@@ -211,7 +203,7 @@ int __devinit cpu_up(unsigned int cpu) | |||
211 | goto out; | 203 | goto out; |
212 | } | 204 | } |
213 | 205 | ||
214 | ret = notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); | 206 | ret = blocking_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); |
215 | if (ret == NOTIFY_BAD) { | 207 | if (ret == NOTIFY_BAD) { |
216 | printk("%s: attempt to bring up CPU %u failed\n", | 208 | printk("%s: attempt to bring up CPU %u failed\n", |
217 | __FUNCTION__, cpu); | 209 | __FUNCTION__, cpu); |
@@ -226,11 +218,12 @@ int __devinit cpu_up(unsigned int cpu) | |||
226 | BUG_ON(!cpu_online(cpu)); | 218 | BUG_ON(!cpu_online(cpu)); |
227 | 219 | ||
228 | /* Now call notifier in preparation. */ | 220 | /* Now call notifier in preparation. */ |
229 | notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu); | 221 | blocking_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu); |
230 | 222 | ||
231 | out_notify: | 223 | out_notify: |
232 | if (ret != 0) | 224 | if (ret != 0) |
233 | notifier_call_chain(&cpu_chain, CPU_UP_CANCELED, hcpu); | 225 | blocking_notifier_call_chain(&cpu_chain, |
226 | CPU_UP_CANCELED, hcpu); | ||
234 | out: | 227 | out: |
235 | unlock_cpu_hotplug(); | 228 | unlock_cpu_hotplug(); |
236 | return ret; | 229 | return ret; |
diff --git a/kernel/exit.c b/kernel/exit.c index 8037405e136e..a8c7efc7a681 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -31,6 +31,8 @@ | |||
31 | #include <linux/signal.h> | 31 | #include <linux/signal.h> |
32 | #include <linux/cn_proc.h> | 32 | #include <linux/cn_proc.h> |
33 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
34 | #include <linux/futex.h> | ||
35 | #include <linux/compat.h> | ||
34 | 36 | ||
35 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
36 | #include <asm/unistd.h> | 38 | #include <asm/unistd.h> |
@@ -852,6 +854,12 @@ fastcall NORET_TYPE void do_exit(long code) | |||
852 | exit_itimers(tsk->signal); | 854 | exit_itimers(tsk->signal); |
853 | acct_process(code); | 855 | acct_process(code); |
854 | } | 856 | } |
857 | if (unlikely(tsk->robust_list)) | ||
858 | exit_robust_list(tsk); | ||
859 | #ifdef CONFIG_COMPAT | ||
860 | if (unlikely(tsk->compat_robust_list)) | ||
861 | compat_exit_robust_list(tsk); | ||
862 | #endif | ||
855 | exit_mm(tsk); | 863 | exit_mm(tsk); |
856 | 864 | ||
857 | exit_sem(tsk); | 865 | exit_sem(tsk); |
diff --git a/kernel/fork.c b/kernel/fork.c index e0a2b449dea6..c49bd193b058 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1061,7 +1061,10 @@ static task_t *copy_process(unsigned long clone_flags, | |||
1061 | * Clear TID on mm_release()? | 1061 | * Clear TID on mm_release()? |
1062 | */ | 1062 | */ |
1063 | p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr: NULL; | 1063 | p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr: NULL; |
1064 | 1064 | p->robust_list = NULL; | |
1065 | #ifdef CONFIG_COMPAT | ||
1066 | p->compat_robust_list = NULL; | ||
1067 | #endif | ||
1065 | /* | 1068 | /* |
1066 | * sigaltstack should be cleared when sharing the same VM | 1069 | * sigaltstack should be cleared when sharing the same VM |
1067 | */ | 1070 | */ |
diff --git a/kernel/futex.c b/kernel/futex.c index 5efa2f978032..9c9b2b6b22dd 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -8,6 +8,10 @@ | |||
8 | * Removed page pinning, fix privately mapped COW pages and other cleanups | 8 | * Removed page pinning, fix privately mapped COW pages and other cleanups |
9 | * (C) Copyright 2003, 2004 Jamie Lokier | 9 | * (C) Copyright 2003, 2004 Jamie Lokier |
10 | * | 10 | * |
11 | * Robust futex support started by Ingo Molnar | ||
12 | * (C) Copyright 2006 Red Hat Inc, All Rights Reserved | ||
13 | * Thanks to Thomas Gleixner for suggestions, analysis and fixes. | ||
14 | * | ||
11 | * Thanks to Ben LaHaise for yelling "hashed waitqueues" loudly | 15 | * Thanks to Ben LaHaise for yelling "hashed waitqueues" loudly |
12 | * enough at me, Linus for the original (flawed) idea, Matthew | 16 | * enough at me, Linus for the original (flawed) idea, Matthew |
13 | * Kirkwood for proof-of-concept implementation. | 17 | * Kirkwood for proof-of-concept implementation. |
@@ -829,6 +833,172 @@ error: | |||
829 | goto out; | 833 | goto out; |
830 | } | 834 | } |
831 | 835 | ||
836 | /* | ||
837 | * Support for robust futexes: the kernel cleans up held futexes at | ||
838 | * thread exit time. | ||
839 | * | ||
840 | * Implementation: user-space maintains a per-thread list of locks it | ||
841 | * is holding. Upon do_exit(), the kernel carefully walks this list, | ||
842 | * and marks all locks that are owned by this thread with the | ||
843 | * FUTEX_OWNER_DEAD bit, and wakes up a waiter (if any). The list is | ||
844 | * always manipulated with the lock held, so the list is private and | ||
845 | * per-thread. Userspace also maintains a per-thread 'list_op_pending' | ||
846 | * field, to allow the kernel to clean up if the thread dies after | ||
847 | * acquiring the lock, but just before it could have added itself to | ||
848 | * the list. There can only be one such pending lock. | ||
849 | */ | ||
850 | |||
851 | /** | ||
852 | * sys_set_robust_list - set the robust-futex list head of a task | ||
853 | * @head: pointer to the list-head | ||
854 | * @len: length of the list-head, as userspace expects | ||
855 | */ | ||
856 | asmlinkage long | ||
857 | sys_set_robust_list(struct robust_list_head __user *head, | ||
858 | size_t len) | ||
859 | { | ||
860 | /* | ||
861 | * The kernel knows only one size for now: | ||
862 | */ | ||
863 | if (unlikely(len != sizeof(*head))) | ||
864 | return -EINVAL; | ||
865 | |||
866 | current->robust_list = head; | ||
867 | |||
868 | return 0; | ||
869 | } | ||
870 | |||
871 | /** | ||
872 | * sys_get_robust_list - get the robust-futex list head of a task | ||
873 | * @pid: pid of the process [zero for current task] | ||
874 | * @head_ptr: pointer to a list-head pointer, the kernel fills it in | ||
875 | * @len_ptr: pointer to a length field, the kernel fills in the header size | ||
876 | */ | ||
877 | asmlinkage long | ||
878 | sys_get_robust_list(int pid, struct robust_list_head __user **head_ptr, | ||
879 | size_t __user *len_ptr) | ||
880 | { | ||
881 | struct robust_list_head *head; | ||
882 | unsigned long ret; | ||
883 | |||
884 | if (!pid) | ||
885 | head = current->robust_list; | ||
886 | else { | ||
887 | struct task_struct *p; | ||
888 | |||
889 | ret = -ESRCH; | ||
890 | read_lock(&tasklist_lock); | ||
891 | p = find_task_by_pid(pid); | ||
892 | if (!p) | ||
893 | goto err_unlock; | ||
894 | ret = -EPERM; | ||
895 | if ((current->euid != p->euid) && (current->euid != p->uid) && | ||
896 | !capable(CAP_SYS_PTRACE)) | ||
897 | goto err_unlock; | ||
898 | head = p->robust_list; | ||
899 | read_unlock(&tasklist_lock); | ||
900 | } | ||
901 | |||
902 | if (put_user(sizeof(*head), len_ptr)) | ||
903 | return -EFAULT; | ||
904 | return put_user(head, head_ptr); | ||
905 | |||
906 | err_unlock: | ||
907 | read_unlock(&tasklist_lock); | ||
908 | |||
909 | return ret; | ||
910 | } | ||
911 | |||
912 | /* | ||
913 | * Process a futex-list entry, check whether it's owned by the | ||
914 | * dying task, and do notification if so: | ||
915 | */ | ||
916 | int handle_futex_death(u32 __user *uaddr, struct task_struct *curr) | ||
917 | { | ||
918 | u32 uval; | ||
919 | |||
920 | retry: | ||
921 | if (get_user(uval, uaddr)) | ||
922 | return -1; | ||
923 | |||
924 | if ((uval & FUTEX_TID_MASK) == curr->pid) { | ||
925 | /* | ||
926 | * Ok, this dying thread is truly holding a futex | ||
927 | * of interest. Set the OWNER_DIED bit atomically | ||
928 | * via cmpxchg, and if the value had FUTEX_WAITERS | ||
929 | * set, wake up a waiter (if any). (We have to do a | ||
930 | * futex_wake() even if OWNER_DIED is already set - | ||
931 | * to handle the rare but possible case of recursive | ||
932 | * thread-death.) The rest of the cleanup is done in | ||
933 | * userspace. | ||
934 | */ | ||
935 | if (futex_atomic_cmpxchg_inatomic(uaddr, uval, | ||
936 | uval | FUTEX_OWNER_DIED) != uval) | ||
937 | goto retry; | ||
938 | |||
939 | if (uval & FUTEX_WAITERS) | ||
940 | futex_wake((unsigned long)uaddr, 1); | ||
941 | } | ||
942 | return 0; | ||
943 | } | ||
944 | |||
945 | /* | ||
946 | * Walk curr->robust_list (very carefully, it's a userspace list!) | ||
947 | * and mark any locks found there dead, and notify any waiters. | ||
948 | * | ||
949 | * We silently return on any sign of list-walking problem. | ||
950 | */ | ||
951 | void exit_robust_list(struct task_struct *curr) | ||
952 | { | ||
953 | struct robust_list_head __user *head = curr->robust_list; | ||
954 | struct robust_list __user *entry, *pending; | ||
955 | unsigned int limit = ROBUST_LIST_LIMIT; | ||
956 | unsigned long futex_offset; | ||
957 | |||
958 | /* | ||
959 | * Fetch the list head (which was registered earlier, via | ||
960 | * sys_set_robust_list()): | ||
961 | */ | ||
962 | if (get_user(entry, &head->list.next)) | ||
963 | return; | ||
964 | /* | ||
965 | * Fetch the relative futex offset: | ||
966 | */ | ||
967 | if (get_user(futex_offset, &head->futex_offset)) | ||
968 | return; | ||
969 | /* | ||
970 | * Fetch any possibly pending lock-add first, and handle it | ||
971 | * if it exists: | ||
972 | */ | ||
973 | if (get_user(pending, &head->list_op_pending)) | ||
974 | return; | ||
975 | if (pending) | ||
976 | handle_futex_death((void *)pending + futex_offset, curr); | ||
977 | |||
978 | while (entry != &head->list) { | ||
979 | /* | ||
980 | * A pending lock might already be on the list, so | ||
981 | * dont process it twice: | ||
982 | */ | ||
983 | if (entry != pending) | ||
984 | if (handle_futex_death((void *)entry + futex_offset, | ||
985 | curr)) | ||
986 | return; | ||
987 | /* | ||
988 | * Fetch the next entry in the list: | ||
989 | */ | ||
990 | if (get_user(entry, &entry->next)) | ||
991 | return; | ||
992 | /* | ||
993 | * Avoid excessively long or circular lists: | ||
994 | */ | ||
995 | if (!--limit) | ||
996 | break; | ||
997 | |||
998 | cond_resched(); | ||
999 | } | ||
1000 | } | ||
1001 | |||
832 | long do_futex(unsigned long uaddr, int op, int val, unsigned long timeout, | 1002 | long do_futex(unsigned long uaddr, int op, int val, unsigned long timeout, |
833 | unsigned long uaddr2, int val2, int val3) | 1003 | unsigned long uaddr2, int val2, int val3) |
834 | { | 1004 | { |
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c new file mode 100644 index 000000000000..9c077cf9aa84 --- /dev/null +++ b/kernel/futex_compat.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /* | ||
2 | * linux/kernel/futex_compat.c | ||
3 | * | ||
4 | * Futex compatibililty routines. | ||
5 | * | ||
6 | * Copyright 2006, Red Hat, Inc., Ingo Molnar | ||
7 | */ | ||
8 | |||
9 | #include <linux/linkage.h> | ||
10 | #include <linux/compat.h> | ||
11 | #include <linux/futex.h> | ||
12 | |||
13 | #include <asm/uaccess.h> | ||
14 | |||
15 | /* | ||
16 | * Walk curr->robust_list (very carefully, it's a userspace list!) | ||
17 | * and mark any locks found there dead, and notify any waiters. | ||
18 | * | ||
19 | * We silently return on any sign of list-walking problem. | ||
20 | */ | ||
21 | void compat_exit_robust_list(struct task_struct *curr) | ||
22 | { | ||
23 | struct compat_robust_list_head __user *head = curr->compat_robust_list; | ||
24 | struct robust_list __user *entry, *pending; | ||
25 | compat_uptr_t uentry, upending; | ||
26 | unsigned int limit = ROBUST_LIST_LIMIT; | ||
27 | compat_long_t futex_offset; | ||
28 | |||
29 | /* | ||
30 | * Fetch the list head (which was registered earlier, via | ||
31 | * sys_set_robust_list()): | ||
32 | */ | ||
33 | if (get_user(uentry, &head->list.next)) | ||
34 | return; | ||
35 | entry = compat_ptr(uentry); | ||
36 | /* | ||
37 | * Fetch the relative futex offset: | ||
38 | */ | ||
39 | if (get_user(futex_offset, &head->futex_offset)) | ||
40 | return; | ||
41 | /* | ||
42 | * Fetch any possibly pending lock-add first, and handle it | ||
43 | * if it exists: | ||
44 | */ | ||
45 | if (get_user(upending, &head->list_op_pending)) | ||
46 | return; | ||
47 | pending = compat_ptr(upending); | ||
48 | if (upending) | ||
49 | handle_futex_death((void *)pending + futex_offset, curr); | ||
50 | |||
51 | while (compat_ptr(uentry) != &head->list) { | ||
52 | /* | ||
53 | * A pending lock might already be on the list, so | ||
54 | * dont process it twice: | ||
55 | */ | ||
56 | if (entry != pending) | ||
57 | if (handle_futex_death((void *)entry + futex_offset, | ||
58 | curr)) | ||
59 | return; | ||
60 | |||
61 | /* | ||
62 | * Fetch the next entry in the list: | ||
63 | */ | ||
64 | if (get_user(uentry, (compat_uptr_t *)&entry->next)) | ||
65 | return; | ||
66 | entry = compat_ptr(uentry); | ||
67 | /* | ||
68 | * Avoid excessively long or circular lists: | ||
69 | */ | ||
70 | if (!--limit) | ||
71 | break; | ||
72 | |||
73 | cond_resched(); | ||
74 | } | ||
75 | } | ||
76 | |||
77 | asmlinkage long | ||
78 | compat_sys_set_robust_list(struct compat_robust_list_head __user *head, | ||
79 | compat_size_t len) | ||
80 | { | ||
81 | if (unlikely(len != sizeof(*head))) | ||
82 | return -EINVAL; | ||
83 | |||
84 | current->compat_robust_list = head; | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | asmlinkage long | ||
90 | compat_sys_get_robust_list(int pid, compat_uptr_t *head_ptr, | ||
91 | compat_size_t __user *len_ptr) | ||
92 | { | ||
93 | struct compat_robust_list_head *head; | ||
94 | unsigned long ret; | ||
95 | |||
96 | if (!pid) | ||
97 | head = current->compat_robust_list; | ||
98 | else { | ||
99 | struct task_struct *p; | ||
100 | |||
101 | ret = -ESRCH; | ||
102 | read_lock(&tasklist_lock); | ||
103 | p = find_task_by_pid(pid); | ||
104 | if (!p) | ||
105 | goto err_unlock; | ||
106 | ret = -EPERM; | ||
107 | if ((current->euid != p->euid) && (current->euid != p->uid) && | ||
108 | !capable(CAP_SYS_PTRACE)) | ||
109 | goto err_unlock; | ||
110 | head = p->compat_robust_list; | ||
111 | read_unlock(&tasklist_lock); | ||
112 | } | ||
113 | |||
114 | if (put_user(sizeof(*head), len_ptr)) | ||
115 | return -EFAULT; | ||
116 | return put_user(ptr_to_compat(head), head_ptr); | ||
117 | |||
118 | err_unlock: | ||
119 | read_unlock(&tasklist_lock); | ||
120 | |||
121 | return ret; | ||
122 | } | ||
123 | |||
124 | asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val, | ||
125 | struct compat_timespec __user *utime, u32 __user *uaddr2, | ||
126 | u32 val3) | ||
127 | { | ||
128 | struct timespec t; | ||
129 | unsigned long timeout = MAX_SCHEDULE_TIMEOUT; | ||
130 | int val2 = 0; | ||
131 | |||
132 | if ((op == FUTEX_WAIT) && utime) { | ||
133 | if (get_compat_timespec(&t, utime)) | ||
134 | return -EFAULT; | ||
135 | timeout = timespec_to_jiffies(&t) + 1; | ||
136 | } | ||
137 | if (op >= FUTEX_REQUEUE) | ||
138 | val2 = (int) (unsigned long) utime; | ||
139 | |||
140 | return do_futex(uaddr, op, val, timeout, uaddr2, val2, val3); | ||
141 | } | ||
diff --git a/kernel/module.c b/kernel/module.c index ddfe45ac2fd1..4fafd58038a0 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -64,26 +64,17 @@ static DEFINE_SPINLOCK(modlist_lock); | |||
64 | static DEFINE_MUTEX(module_mutex); | 64 | static DEFINE_MUTEX(module_mutex); |
65 | static LIST_HEAD(modules); | 65 | static LIST_HEAD(modules); |
66 | 66 | ||
67 | static DEFINE_MUTEX(notify_mutex); | 67 | static BLOCKING_NOTIFIER_HEAD(module_notify_list); |
68 | static struct notifier_block * module_notify_list; | ||
69 | 68 | ||
70 | int register_module_notifier(struct notifier_block * nb) | 69 | int register_module_notifier(struct notifier_block * nb) |
71 | { | 70 | { |
72 | int err; | 71 | return blocking_notifier_chain_register(&module_notify_list, nb); |
73 | mutex_lock(¬ify_mutex); | ||
74 | err = notifier_chain_register(&module_notify_list, nb); | ||
75 | mutex_unlock(¬ify_mutex); | ||
76 | return err; | ||
77 | } | 72 | } |
78 | EXPORT_SYMBOL(register_module_notifier); | 73 | EXPORT_SYMBOL(register_module_notifier); |
79 | 74 | ||
80 | int unregister_module_notifier(struct notifier_block * nb) | 75 | int unregister_module_notifier(struct notifier_block * nb) |
81 | { | 76 | { |
82 | int err; | 77 | return blocking_notifier_chain_unregister(&module_notify_list, nb); |
83 | mutex_lock(¬ify_mutex); | ||
84 | err = notifier_chain_unregister(&module_notify_list, nb); | ||
85 | mutex_unlock(¬ify_mutex); | ||
86 | return err; | ||
87 | } | 78 | } |
88 | EXPORT_SYMBOL(unregister_module_notifier); | 79 | EXPORT_SYMBOL(unregister_module_notifier); |
89 | 80 | ||
@@ -1816,9 +1807,8 @@ sys_init_module(void __user *umod, | |||
1816 | /* Drop lock so they can recurse */ | 1807 | /* Drop lock so they can recurse */ |
1817 | mutex_unlock(&module_mutex); | 1808 | mutex_unlock(&module_mutex); |
1818 | 1809 | ||
1819 | mutex_lock(¬ify_mutex); | 1810 | blocking_notifier_call_chain(&module_notify_list, |
1820 | notifier_call_chain(&module_notify_list, MODULE_STATE_COMING, mod); | 1811 | MODULE_STATE_COMING, mod); |
1821 | mutex_unlock(¬ify_mutex); | ||
1822 | 1812 | ||
1823 | /* Start the module */ | 1813 | /* Start the module */ |
1824 | if (mod->init != NULL) | 1814 | if (mod->init != NULL) |
diff --git a/kernel/panic.c b/kernel/panic.c index acd95adddb93..f895c7c01d5b 100644 --- a/kernel/panic.c +++ b/kernel/panic.c | |||
@@ -29,7 +29,7 @@ static DEFINE_SPINLOCK(pause_on_oops_lock); | |||
29 | int panic_timeout; | 29 | int panic_timeout; |
30 | EXPORT_SYMBOL(panic_timeout); | 30 | EXPORT_SYMBOL(panic_timeout); |
31 | 31 | ||
32 | struct notifier_block *panic_notifier_list; | 32 | ATOMIC_NOTIFIER_HEAD(panic_notifier_list); |
33 | 33 | ||
34 | EXPORT_SYMBOL(panic_notifier_list); | 34 | EXPORT_SYMBOL(panic_notifier_list); |
35 | 35 | ||
@@ -97,7 +97,7 @@ NORET_TYPE void panic(const char * fmt, ...) | |||
97 | smp_send_stop(); | 97 | smp_send_stop(); |
98 | #endif | 98 | #endif |
99 | 99 | ||
100 | notifier_call_chain(&panic_notifier_list, 0, buf); | 100 | atomic_notifier_call_chain(&panic_notifier_list, 0, buf); |
101 | 101 | ||
102 | if (!panic_blink) | 102 | if (!panic_blink) |
103 | panic_blink = no_blink; | 103 | panic_blink = no_blink; |
diff --git a/kernel/profile.c b/kernel/profile.c index ad81f799a9b4..5a730fdb1a2c 100644 --- a/kernel/profile.c +++ b/kernel/profile.c | |||
@@ -87,72 +87,52 @@ void __init profile_init(void) | |||
87 | 87 | ||
88 | #ifdef CONFIG_PROFILING | 88 | #ifdef CONFIG_PROFILING |
89 | 89 | ||
90 | static DECLARE_RWSEM(profile_rwsem); | 90 | static BLOCKING_NOTIFIER_HEAD(task_exit_notifier); |
91 | static DEFINE_RWLOCK(handoff_lock); | 91 | static ATOMIC_NOTIFIER_HEAD(task_free_notifier); |
92 | static struct notifier_block * task_exit_notifier; | 92 | static BLOCKING_NOTIFIER_HEAD(munmap_notifier); |
93 | static struct notifier_block * task_free_notifier; | ||
94 | static struct notifier_block * munmap_notifier; | ||
95 | 93 | ||
96 | void profile_task_exit(struct task_struct * task) | 94 | void profile_task_exit(struct task_struct * task) |
97 | { | 95 | { |
98 | down_read(&profile_rwsem); | 96 | blocking_notifier_call_chain(&task_exit_notifier, 0, task); |
99 | notifier_call_chain(&task_exit_notifier, 0, task); | ||
100 | up_read(&profile_rwsem); | ||
101 | } | 97 | } |
102 | 98 | ||
103 | int profile_handoff_task(struct task_struct * task) | 99 | int profile_handoff_task(struct task_struct * task) |
104 | { | 100 | { |
105 | int ret; | 101 | int ret; |
106 | read_lock(&handoff_lock); | 102 | ret = atomic_notifier_call_chain(&task_free_notifier, 0, task); |
107 | ret = notifier_call_chain(&task_free_notifier, 0, task); | ||
108 | read_unlock(&handoff_lock); | ||
109 | return (ret == NOTIFY_OK) ? 1 : 0; | 103 | return (ret == NOTIFY_OK) ? 1 : 0; |
110 | } | 104 | } |
111 | 105 | ||
112 | void profile_munmap(unsigned long addr) | 106 | void profile_munmap(unsigned long addr) |
113 | { | 107 | { |
114 | down_read(&profile_rwsem); | 108 | blocking_notifier_call_chain(&munmap_notifier, 0, (void *)addr); |
115 | notifier_call_chain(&munmap_notifier, 0, (void *)addr); | ||
116 | up_read(&profile_rwsem); | ||
117 | } | 109 | } |
118 | 110 | ||
119 | int task_handoff_register(struct notifier_block * n) | 111 | int task_handoff_register(struct notifier_block * n) |
120 | { | 112 | { |
121 | int err = -EINVAL; | 113 | return atomic_notifier_chain_register(&task_free_notifier, n); |
122 | |||
123 | write_lock(&handoff_lock); | ||
124 | err = notifier_chain_register(&task_free_notifier, n); | ||
125 | write_unlock(&handoff_lock); | ||
126 | return err; | ||
127 | } | 114 | } |
128 | 115 | ||
129 | int task_handoff_unregister(struct notifier_block * n) | 116 | int task_handoff_unregister(struct notifier_block * n) |
130 | { | 117 | { |
131 | int err = -EINVAL; | 118 | return atomic_notifier_chain_unregister(&task_free_notifier, n); |
132 | |||
133 | write_lock(&handoff_lock); | ||
134 | err = notifier_chain_unregister(&task_free_notifier, n); | ||
135 | write_unlock(&handoff_lock); | ||
136 | return err; | ||
137 | } | 119 | } |
138 | 120 | ||
139 | int profile_event_register(enum profile_type type, struct notifier_block * n) | 121 | int profile_event_register(enum profile_type type, struct notifier_block * n) |
140 | { | 122 | { |
141 | int err = -EINVAL; | 123 | int err = -EINVAL; |
142 | 124 | ||
143 | down_write(&profile_rwsem); | ||
144 | |||
145 | switch (type) { | 125 | switch (type) { |
146 | case PROFILE_TASK_EXIT: | 126 | case PROFILE_TASK_EXIT: |
147 | err = notifier_chain_register(&task_exit_notifier, n); | 127 | err = blocking_notifier_chain_register( |
128 | &task_exit_notifier, n); | ||
148 | break; | 129 | break; |
149 | case PROFILE_MUNMAP: | 130 | case PROFILE_MUNMAP: |
150 | err = notifier_chain_register(&munmap_notifier, n); | 131 | err = blocking_notifier_chain_register( |
132 | &munmap_notifier, n); | ||
151 | break; | 133 | break; |
152 | } | 134 | } |
153 | 135 | ||
154 | up_write(&profile_rwsem); | ||
155 | |||
156 | return err; | 136 | return err; |
157 | } | 137 | } |
158 | 138 | ||
@@ -161,18 +141,17 @@ int profile_event_unregister(enum profile_type type, struct notifier_block * n) | |||
161 | { | 141 | { |
162 | int err = -EINVAL; | 142 | int err = -EINVAL; |
163 | 143 | ||
164 | down_write(&profile_rwsem); | ||
165 | |||
166 | switch (type) { | 144 | switch (type) { |
167 | case PROFILE_TASK_EXIT: | 145 | case PROFILE_TASK_EXIT: |
168 | err = notifier_chain_unregister(&task_exit_notifier, n); | 146 | err = blocking_notifier_chain_unregister( |
147 | &task_exit_notifier, n); | ||
169 | break; | 148 | break; |
170 | case PROFILE_MUNMAP: | 149 | case PROFILE_MUNMAP: |
171 | err = notifier_chain_unregister(&munmap_notifier, n); | 150 | err = blocking_notifier_chain_unregister( |
151 | &munmap_notifier, n); | ||
172 | break; | 152 | break; |
173 | } | 153 | } |
174 | 154 | ||
175 | up_write(&profile_rwsem); | ||
176 | return err; | 155 | return err; |
177 | } | 156 | } |
178 | 157 | ||
diff --git a/kernel/sched.c b/kernel/sched.c index 78acdefeccca..7854ee516b92 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -145,7 +145,8 @@ | |||
145 | (v1) * (v2_max) / (v1_max) | 145 | (v1) * (v2_max) / (v1_max) |
146 | 146 | ||
147 | #define DELTA(p) \ | 147 | #define DELTA(p) \ |
148 | (SCALE(TASK_NICE(p), 40, MAX_BONUS) + INTERACTIVE_DELTA) | 148 | (SCALE(TASK_NICE(p) + 20, 40, MAX_BONUS) - 20 * MAX_BONUS / 40 + \ |
149 | INTERACTIVE_DELTA) | ||
149 | 150 | ||
150 | #define TASK_INTERACTIVE(p) \ | 151 | #define TASK_INTERACTIVE(p) \ |
151 | ((p)->prio <= (p)->static_prio - DELTA(p)) | 152 | ((p)->prio <= (p)->static_prio - DELTA(p)) |
@@ -2878,13 +2879,11 @@ asmlinkage void __sched schedule(void) | |||
2878 | * schedule() atomically, we ignore that path for now. | 2879 | * schedule() atomically, we ignore that path for now. |
2879 | * Otherwise, whine if we are scheduling when we should not be. | 2880 | * Otherwise, whine if we are scheduling when we should not be. |
2880 | */ | 2881 | */ |
2881 | if (likely(!current->exit_state)) { | 2882 | if (unlikely(in_atomic() && !current->exit_state)) { |
2882 | if (unlikely(in_atomic())) { | 2883 | printk(KERN_ERR "BUG: scheduling while atomic: " |
2883 | printk(KERN_ERR "BUG: scheduling while atomic: " | 2884 | "%s/0x%08x/%d\n", |
2884 | "%s/0x%08x/%d\n", | 2885 | current->comm, preempt_count(), current->pid); |
2885 | current->comm, preempt_count(), current->pid); | 2886 | dump_stack(); |
2886 | dump_stack(); | ||
2887 | } | ||
2888 | } | 2887 | } |
2889 | profile_hit(SCHED_PROFILING, __builtin_return_address(0)); | 2888 | profile_hit(SCHED_PROFILING, __builtin_return_address(0)); |
2890 | 2889 | ||
@@ -5575,11 +5574,31 @@ static int cpu_to_cpu_group(int cpu) | |||
5575 | } | 5574 | } |
5576 | #endif | 5575 | #endif |
5577 | 5576 | ||
5577 | #ifdef CONFIG_SCHED_MC | ||
5578 | static DEFINE_PER_CPU(struct sched_domain, core_domains); | ||
5579 | static struct sched_group sched_group_core[NR_CPUS]; | ||
5580 | #endif | ||
5581 | |||
5582 | #if defined(CONFIG_SCHED_MC) && defined(CONFIG_SCHED_SMT) | ||
5583 | static int cpu_to_core_group(int cpu) | ||
5584 | { | ||
5585 | return first_cpu(cpu_sibling_map[cpu]); | ||
5586 | } | ||
5587 | #elif defined(CONFIG_SCHED_MC) | ||
5588 | static int cpu_to_core_group(int cpu) | ||
5589 | { | ||
5590 | return cpu; | ||
5591 | } | ||
5592 | #endif | ||
5593 | |||
5578 | static DEFINE_PER_CPU(struct sched_domain, phys_domains); | 5594 | static DEFINE_PER_CPU(struct sched_domain, phys_domains); |
5579 | static struct sched_group sched_group_phys[NR_CPUS]; | 5595 | static struct sched_group sched_group_phys[NR_CPUS]; |
5580 | static int cpu_to_phys_group(int cpu) | 5596 | static int cpu_to_phys_group(int cpu) |
5581 | { | 5597 | { |
5582 | #ifdef CONFIG_SCHED_SMT | 5598 | #if defined(CONFIG_SCHED_MC) |
5599 | cpumask_t mask = cpu_coregroup_map(cpu); | ||
5600 | return first_cpu(mask); | ||
5601 | #elif defined(CONFIG_SCHED_SMT) | ||
5583 | return first_cpu(cpu_sibling_map[cpu]); | 5602 | return first_cpu(cpu_sibling_map[cpu]); |
5584 | #else | 5603 | #else |
5585 | return cpu; | 5604 | return cpu; |
@@ -5602,6 +5621,32 @@ static int cpu_to_allnodes_group(int cpu) | |||
5602 | { | 5621 | { |
5603 | return cpu_to_node(cpu); | 5622 | return cpu_to_node(cpu); |
5604 | } | 5623 | } |
5624 | static void init_numa_sched_groups_power(struct sched_group *group_head) | ||
5625 | { | ||
5626 | struct sched_group *sg = group_head; | ||
5627 | int j; | ||
5628 | |||
5629 | if (!sg) | ||
5630 | return; | ||
5631 | next_sg: | ||
5632 | for_each_cpu_mask(j, sg->cpumask) { | ||
5633 | struct sched_domain *sd; | ||
5634 | |||
5635 | sd = &per_cpu(phys_domains, j); | ||
5636 | if (j != first_cpu(sd->groups->cpumask)) { | ||
5637 | /* | ||
5638 | * Only add "power" once for each | ||
5639 | * physical package. | ||
5640 | */ | ||
5641 | continue; | ||
5642 | } | ||
5643 | |||
5644 | sg->cpu_power += sd->groups->cpu_power; | ||
5645 | } | ||
5646 | sg = sg->next; | ||
5647 | if (sg != group_head) | ||
5648 | goto next_sg; | ||
5649 | } | ||
5605 | #endif | 5650 | #endif |
5606 | 5651 | ||
5607 | /* | 5652 | /* |
@@ -5677,6 +5722,17 @@ void build_sched_domains(const cpumask_t *cpu_map) | |||
5677 | sd->parent = p; | 5722 | sd->parent = p; |
5678 | sd->groups = &sched_group_phys[group]; | 5723 | sd->groups = &sched_group_phys[group]; |
5679 | 5724 | ||
5725 | #ifdef CONFIG_SCHED_MC | ||
5726 | p = sd; | ||
5727 | sd = &per_cpu(core_domains, i); | ||
5728 | group = cpu_to_core_group(i); | ||
5729 | *sd = SD_MC_INIT; | ||
5730 | sd->span = cpu_coregroup_map(i); | ||
5731 | cpus_and(sd->span, sd->span, *cpu_map); | ||
5732 | sd->parent = p; | ||
5733 | sd->groups = &sched_group_core[group]; | ||
5734 | #endif | ||
5735 | |||
5680 | #ifdef CONFIG_SCHED_SMT | 5736 | #ifdef CONFIG_SCHED_SMT |
5681 | p = sd; | 5737 | p = sd; |
5682 | sd = &per_cpu(cpu_domains, i); | 5738 | sd = &per_cpu(cpu_domains, i); |
@@ -5702,6 +5758,19 @@ void build_sched_domains(const cpumask_t *cpu_map) | |||
5702 | } | 5758 | } |
5703 | #endif | 5759 | #endif |
5704 | 5760 | ||
5761 | #ifdef CONFIG_SCHED_MC | ||
5762 | /* Set up multi-core groups */ | ||
5763 | for_each_cpu_mask(i, *cpu_map) { | ||
5764 | cpumask_t this_core_map = cpu_coregroup_map(i); | ||
5765 | cpus_and(this_core_map, this_core_map, *cpu_map); | ||
5766 | if (i != first_cpu(this_core_map)) | ||
5767 | continue; | ||
5768 | init_sched_build_groups(sched_group_core, this_core_map, | ||
5769 | &cpu_to_core_group); | ||
5770 | } | ||
5771 | #endif | ||
5772 | |||
5773 | |||
5705 | /* Set up physical groups */ | 5774 | /* Set up physical groups */ |
5706 | for (i = 0; i < MAX_NUMNODES; i++) { | 5775 | for (i = 0; i < MAX_NUMNODES; i++) { |
5707 | cpumask_t nodemask = node_to_cpumask(i); | 5776 | cpumask_t nodemask = node_to_cpumask(i); |
@@ -5798,51 +5867,38 @@ void build_sched_domains(const cpumask_t *cpu_map) | |||
5798 | power = SCHED_LOAD_SCALE; | 5867 | power = SCHED_LOAD_SCALE; |
5799 | sd->groups->cpu_power = power; | 5868 | sd->groups->cpu_power = power; |
5800 | #endif | 5869 | #endif |
5870 | #ifdef CONFIG_SCHED_MC | ||
5871 | sd = &per_cpu(core_domains, i); | ||
5872 | power = SCHED_LOAD_SCALE + (cpus_weight(sd->groups->cpumask)-1) | ||
5873 | * SCHED_LOAD_SCALE / 10; | ||
5874 | sd->groups->cpu_power = power; | ||
5801 | 5875 | ||
5802 | sd = &per_cpu(phys_domains, i); | 5876 | sd = &per_cpu(phys_domains, i); |
5877 | |||
5878 | /* | ||
5879 | * This has to be < 2 * SCHED_LOAD_SCALE | ||
5880 | * Lets keep it SCHED_LOAD_SCALE, so that | ||
5881 | * while calculating NUMA group's cpu_power | ||
5882 | * we can simply do | ||
5883 | * numa_group->cpu_power += phys_group->cpu_power; | ||
5884 | * | ||
5885 | * See "only add power once for each physical pkg" | ||
5886 | * comment below | ||
5887 | */ | ||
5888 | sd->groups->cpu_power = SCHED_LOAD_SCALE; | ||
5889 | #else | ||
5890 | sd = &per_cpu(phys_domains, i); | ||
5803 | power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE * | 5891 | power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE * |
5804 | (cpus_weight(sd->groups->cpumask)-1) / 10; | 5892 | (cpus_weight(sd->groups->cpumask)-1) / 10; |
5805 | sd->groups->cpu_power = power; | 5893 | sd->groups->cpu_power = power; |
5806 | |||
5807 | #ifdef CONFIG_NUMA | ||
5808 | sd = &per_cpu(allnodes_domains, i); | ||
5809 | if (sd->groups) { | ||
5810 | power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE * | ||
5811 | (cpus_weight(sd->groups->cpumask)-1) / 10; | ||
5812 | sd->groups->cpu_power = power; | ||
5813 | } | ||
5814 | #endif | 5894 | #endif |
5815 | } | 5895 | } |
5816 | 5896 | ||
5817 | #ifdef CONFIG_NUMA | 5897 | #ifdef CONFIG_NUMA |
5818 | for (i = 0; i < MAX_NUMNODES; i++) { | 5898 | for (i = 0; i < MAX_NUMNODES; i++) |
5819 | struct sched_group *sg = sched_group_nodes[i]; | 5899 | init_numa_sched_groups_power(sched_group_nodes[i]); |
5820 | int j; | ||
5821 | |||
5822 | if (sg == NULL) | ||
5823 | continue; | ||
5824 | next_sg: | ||
5825 | for_each_cpu_mask(j, sg->cpumask) { | ||
5826 | struct sched_domain *sd; | ||
5827 | int power; | ||
5828 | |||
5829 | sd = &per_cpu(phys_domains, j); | ||
5830 | if (j != first_cpu(sd->groups->cpumask)) { | ||
5831 | /* | ||
5832 | * Only add "power" once for each | ||
5833 | * physical package. | ||
5834 | */ | ||
5835 | continue; | ||
5836 | } | ||
5837 | power = SCHED_LOAD_SCALE + SCHED_LOAD_SCALE * | ||
5838 | (cpus_weight(sd->groups->cpumask)-1) / 10; | ||
5839 | 5900 | ||
5840 | sg->cpu_power += power; | 5901 | init_numa_sched_groups_power(sched_group_allnodes); |
5841 | } | ||
5842 | sg = sg->next; | ||
5843 | if (sg != sched_group_nodes[i]) | ||
5844 | goto next_sg; | ||
5845 | } | ||
5846 | #endif | 5902 | #endif |
5847 | 5903 | ||
5848 | /* Attach the domains */ | 5904 | /* Attach the domains */ |
@@ -5850,6 +5906,8 @@ next_sg: | |||
5850 | struct sched_domain *sd; | 5906 | struct sched_domain *sd; |
5851 | #ifdef CONFIG_SCHED_SMT | 5907 | #ifdef CONFIG_SCHED_SMT |
5852 | sd = &per_cpu(cpu_domains, i); | 5908 | sd = &per_cpu(cpu_domains, i); |
5909 | #elif defined(CONFIG_SCHED_MC) | ||
5910 | sd = &per_cpu(core_domains, i); | ||
5853 | #else | 5911 | #else |
5854 | sd = &per_cpu(phys_domains, i); | 5912 | sd = &per_cpu(phys_domains, i); |
5855 | #endif | 5913 | #endif |
diff --git a/kernel/softlockup.c b/kernel/softlockup.c index d9b3d5847ed8..ced91e1ff564 100644 --- a/kernel/softlockup.c +++ b/kernel/softlockup.c | |||
@@ -152,5 +152,5 @@ __init void spawn_softlockup_task(void) | |||
152 | cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); | 152 | cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); |
153 | register_cpu_notifier(&cpu_nfb); | 153 | register_cpu_notifier(&cpu_nfb); |
154 | 154 | ||
155 | notifier_chain_register(&panic_notifier_list, &panic_block); | 155 | atomic_notifier_chain_register(&panic_notifier_list, &panic_block); |
156 | } | 156 | } |
diff --git a/kernel/sys.c b/kernel/sys.c index 38bc73ede2ba..c93d37f71aef 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -95,99 +95,304 @@ int cad_pid = 1; | |||
95 | * and the like. | 95 | * and the like. |
96 | */ | 96 | */ |
97 | 97 | ||
98 | static struct notifier_block *reboot_notifier_list; | 98 | static BLOCKING_NOTIFIER_HEAD(reboot_notifier_list); |
99 | static DEFINE_RWLOCK(notifier_lock); | 99 | |
100 | /* | ||
101 | * Notifier chain core routines. The exported routines below | ||
102 | * are layered on top of these, with appropriate locking added. | ||
103 | */ | ||
104 | |||
105 | static int notifier_chain_register(struct notifier_block **nl, | ||
106 | struct notifier_block *n) | ||
107 | { | ||
108 | while ((*nl) != NULL) { | ||
109 | if (n->priority > (*nl)->priority) | ||
110 | break; | ||
111 | nl = &((*nl)->next); | ||
112 | } | ||
113 | n->next = *nl; | ||
114 | rcu_assign_pointer(*nl, n); | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | static int notifier_chain_unregister(struct notifier_block **nl, | ||
119 | struct notifier_block *n) | ||
120 | { | ||
121 | while ((*nl) != NULL) { | ||
122 | if ((*nl) == n) { | ||
123 | rcu_assign_pointer(*nl, n->next); | ||
124 | return 0; | ||
125 | } | ||
126 | nl = &((*nl)->next); | ||
127 | } | ||
128 | return -ENOENT; | ||
129 | } | ||
130 | |||
131 | static int __kprobes notifier_call_chain(struct notifier_block **nl, | ||
132 | unsigned long val, void *v) | ||
133 | { | ||
134 | int ret = NOTIFY_DONE; | ||
135 | struct notifier_block *nb; | ||
136 | |||
137 | nb = rcu_dereference(*nl); | ||
138 | while (nb) { | ||
139 | ret = nb->notifier_call(nb, val, v); | ||
140 | if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK) | ||
141 | break; | ||
142 | nb = rcu_dereference(nb->next); | ||
143 | } | ||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | /* | ||
148 | * Atomic notifier chain routines. Registration and unregistration | ||
149 | * use a mutex, and call_chain is synchronized by RCU (no locks). | ||
150 | */ | ||
100 | 151 | ||
101 | /** | 152 | /** |
102 | * notifier_chain_register - Add notifier to a notifier chain | 153 | * atomic_notifier_chain_register - Add notifier to an atomic notifier chain |
103 | * @list: Pointer to root list pointer | 154 | * @nh: Pointer to head of the atomic notifier chain |
104 | * @n: New entry in notifier chain | 155 | * @n: New entry in notifier chain |
105 | * | 156 | * |
106 | * Adds a notifier to a notifier chain. | 157 | * Adds a notifier to an atomic notifier chain. |
107 | * | 158 | * |
108 | * Currently always returns zero. | 159 | * Currently always returns zero. |
109 | */ | 160 | */ |
161 | |||
162 | int atomic_notifier_chain_register(struct atomic_notifier_head *nh, | ||
163 | struct notifier_block *n) | ||
164 | { | ||
165 | unsigned long flags; | ||
166 | int ret; | ||
167 | |||
168 | spin_lock_irqsave(&nh->lock, flags); | ||
169 | ret = notifier_chain_register(&nh->head, n); | ||
170 | spin_unlock_irqrestore(&nh->lock, flags); | ||
171 | return ret; | ||
172 | } | ||
173 | |||
174 | EXPORT_SYMBOL_GPL(atomic_notifier_chain_register); | ||
175 | |||
176 | /** | ||
177 | * atomic_notifier_chain_unregister - Remove notifier from an atomic notifier chain | ||
178 | * @nh: Pointer to head of the atomic notifier chain | ||
179 | * @n: Entry to remove from notifier chain | ||
180 | * | ||
181 | * Removes a notifier from an atomic notifier chain. | ||
182 | * | ||
183 | * Returns zero on success or %-ENOENT on failure. | ||
184 | */ | ||
185 | int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, | ||
186 | struct notifier_block *n) | ||
187 | { | ||
188 | unsigned long flags; | ||
189 | int ret; | ||
190 | |||
191 | spin_lock_irqsave(&nh->lock, flags); | ||
192 | ret = notifier_chain_unregister(&nh->head, n); | ||
193 | spin_unlock_irqrestore(&nh->lock, flags); | ||
194 | synchronize_rcu(); | ||
195 | return ret; | ||
196 | } | ||
197 | |||
198 | EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister); | ||
199 | |||
200 | /** | ||
201 | * atomic_notifier_call_chain - Call functions in an atomic notifier chain | ||
202 | * @nh: Pointer to head of the atomic notifier chain | ||
203 | * @val: Value passed unmodified to notifier function | ||
204 | * @v: Pointer passed unmodified to notifier function | ||
205 | * | ||
206 | * Calls each function in a notifier chain in turn. The functions | ||
207 | * run in an atomic context, so they must not block. | ||
208 | * This routine uses RCU to synchronize with changes to the chain. | ||
209 | * | ||
210 | * If the return value of the notifier can be and'ed | ||
211 | * with %NOTIFY_STOP_MASK then atomic_notifier_call_chain | ||
212 | * will return immediately, with the return value of | ||
213 | * the notifier function which halted execution. | ||
214 | * Otherwise the return value is the return value | ||
215 | * of the last notifier function called. | ||
216 | */ | ||
110 | 217 | ||
111 | int notifier_chain_register(struct notifier_block **list, struct notifier_block *n) | 218 | int atomic_notifier_call_chain(struct atomic_notifier_head *nh, |
219 | unsigned long val, void *v) | ||
112 | { | 220 | { |
113 | write_lock(¬ifier_lock); | 221 | int ret; |
114 | while(*list) | 222 | |
115 | { | 223 | rcu_read_lock(); |
116 | if(n->priority > (*list)->priority) | 224 | ret = notifier_call_chain(&nh->head, val, v); |
117 | break; | 225 | rcu_read_unlock(); |
118 | list= &((*list)->next); | 226 | return ret; |
119 | } | ||
120 | n->next = *list; | ||
121 | *list=n; | ||
122 | write_unlock(¬ifier_lock); | ||
123 | return 0; | ||
124 | } | 227 | } |
125 | 228 | ||
126 | EXPORT_SYMBOL(notifier_chain_register); | 229 | EXPORT_SYMBOL_GPL(atomic_notifier_call_chain); |
230 | |||
231 | /* | ||
232 | * Blocking notifier chain routines. All access to the chain is | ||
233 | * synchronized by an rwsem. | ||
234 | */ | ||
127 | 235 | ||
128 | /** | 236 | /** |
129 | * notifier_chain_unregister - Remove notifier from a notifier chain | 237 | * blocking_notifier_chain_register - Add notifier to a blocking notifier chain |
130 | * @nl: Pointer to root list pointer | 238 | * @nh: Pointer to head of the blocking notifier chain |
131 | * @n: New entry in notifier chain | 239 | * @n: New entry in notifier chain |
132 | * | 240 | * |
133 | * Removes a notifier from a notifier chain. | 241 | * Adds a notifier to a blocking notifier chain. |
242 | * Must be called in process context. | ||
134 | * | 243 | * |
135 | * Returns zero on success, or %-ENOENT on failure. | 244 | * Currently always returns zero. |
136 | */ | 245 | */ |
137 | 246 | ||
138 | int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n) | 247 | int blocking_notifier_chain_register(struct blocking_notifier_head *nh, |
248 | struct notifier_block *n) | ||
139 | { | 249 | { |
140 | write_lock(¬ifier_lock); | 250 | int ret; |
141 | while((*nl)!=NULL) | 251 | |
142 | { | 252 | /* |
143 | if((*nl)==n) | 253 | * This code gets used during boot-up, when task switching is |
144 | { | 254 | * not yet working and interrupts must remain disabled. At |
145 | *nl=n->next; | 255 | * such times we must not call down_write(). |
146 | write_unlock(¬ifier_lock); | 256 | */ |
147 | return 0; | 257 | if (unlikely(system_state == SYSTEM_BOOTING)) |
148 | } | 258 | return notifier_chain_register(&nh->head, n); |
149 | nl=&((*nl)->next); | 259 | |
150 | } | 260 | down_write(&nh->rwsem); |
151 | write_unlock(¬ifier_lock); | 261 | ret = notifier_chain_register(&nh->head, n); |
152 | return -ENOENT; | 262 | up_write(&nh->rwsem); |
263 | return ret; | ||
153 | } | 264 | } |
154 | 265 | ||
155 | EXPORT_SYMBOL(notifier_chain_unregister); | 266 | EXPORT_SYMBOL_GPL(blocking_notifier_chain_register); |
156 | 267 | ||
157 | /** | 268 | /** |
158 | * notifier_call_chain - Call functions in a notifier chain | 269 | * blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain |
159 | * @n: Pointer to root pointer of notifier chain | 270 | * @nh: Pointer to head of the blocking notifier chain |
271 | * @n: Entry to remove from notifier chain | ||
272 | * | ||
273 | * Removes a notifier from a blocking notifier chain. | ||
274 | * Must be called from process context. | ||
275 | * | ||
276 | * Returns zero on success or %-ENOENT on failure. | ||
277 | */ | ||
278 | int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh, | ||
279 | struct notifier_block *n) | ||
280 | { | ||
281 | int ret; | ||
282 | |||
283 | /* | ||
284 | * This code gets used during boot-up, when task switching is | ||
285 | * not yet working and interrupts must remain disabled. At | ||
286 | * such times we must not call down_write(). | ||
287 | */ | ||
288 | if (unlikely(system_state == SYSTEM_BOOTING)) | ||
289 | return notifier_chain_unregister(&nh->head, n); | ||
290 | |||
291 | down_write(&nh->rwsem); | ||
292 | ret = notifier_chain_unregister(&nh->head, n); | ||
293 | up_write(&nh->rwsem); | ||
294 | return ret; | ||
295 | } | ||
296 | |||
297 | EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister); | ||
298 | |||
299 | /** | ||
300 | * blocking_notifier_call_chain - Call functions in a blocking notifier chain | ||
301 | * @nh: Pointer to head of the blocking notifier chain | ||
160 | * @val: Value passed unmodified to notifier function | 302 | * @val: Value passed unmodified to notifier function |
161 | * @v: Pointer passed unmodified to notifier function | 303 | * @v: Pointer passed unmodified to notifier function |
162 | * | 304 | * |
163 | * Calls each function in a notifier chain in turn. | 305 | * Calls each function in a notifier chain in turn. The functions |
306 | * run in a process context, so they are allowed to block. | ||
164 | * | 307 | * |
165 | * If the return value of the notifier can be and'd | 308 | * If the return value of the notifier can be and'ed |
166 | * with %NOTIFY_STOP_MASK, then notifier_call_chain | 309 | * with %NOTIFY_STOP_MASK then blocking_notifier_call_chain |
167 | * will return immediately, with the return value of | 310 | * will return immediately, with the return value of |
168 | * the notifier function which halted execution. | 311 | * the notifier function which halted execution. |
169 | * Otherwise, the return value is the return value | 312 | * Otherwise the return value is the return value |
170 | * of the last notifier function called. | 313 | * of the last notifier function called. |
171 | */ | 314 | */ |
172 | 315 | ||
173 | int __kprobes notifier_call_chain(struct notifier_block **n, unsigned long val, void *v) | 316 | int blocking_notifier_call_chain(struct blocking_notifier_head *nh, |
317 | unsigned long val, void *v) | ||
174 | { | 318 | { |
175 | int ret=NOTIFY_DONE; | 319 | int ret; |
176 | struct notifier_block *nb = *n; | ||
177 | 320 | ||
178 | while(nb) | 321 | down_read(&nh->rwsem); |
179 | { | 322 | ret = notifier_call_chain(&nh->head, val, v); |
180 | ret=nb->notifier_call(nb,val,v); | 323 | up_read(&nh->rwsem); |
181 | if(ret&NOTIFY_STOP_MASK) | ||
182 | { | ||
183 | return ret; | ||
184 | } | ||
185 | nb=nb->next; | ||
186 | } | ||
187 | return ret; | 324 | return ret; |
188 | } | 325 | } |
189 | 326 | ||
190 | EXPORT_SYMBOL(notifier_call_chain); | 327 | EXPORT_SYMBOL_GPL(blocking_notifier_call_chain); |
328 | |||
329 | /* | ||
330 | * Raw notifier chain routines. There is no protection; | ||
331 | * the caller must provide it. Use at your own risk! | ||
332 | */ | ||
333 | |||
334 | /** | ||
335 | * raw_notifier_chain_register - Add notifier to a raw notifier chain | ||
336 | * @nh: Pointer to head of the raw notifier chain | ||
337 | * @n: New entry in notifier chain | ||
338 | * | ||
339 | * Adds a notifier to a raw notifier chain. | ||
340 | * All locking must be provided by the caller. | ||
341 | * | ||
342 | * Currently always returns zero. | ||
343 | */ | ||
344 | |||
345 | int raw_notifier_chain_register(struct raw_notifier_head *nh, | ||
346 | struct notifier_block *n) | ||
347 | { | ||
348 | return notifier_chain_register(&nh->head, n); | ||
349 | } | ||
350 | |||
351 | EXPORT_SYMBOL_GPL(raw_notifier_chain_register); | ||
352 | |||
353 | /** | ||
354 | * raw_notifier_chain_unregister - Remove notifier from a raw notifier chain | ||
355 | * @nh: Pointer to head of the raw notifier chain | ||
356 | * @n: Entry to remove from notifier chain | ||
357 | * | ||
358 | * Removes a notifier from a raw notifier chain. | ||
359 | * All locking must be provided by the caller. | ||
360 | * | ||
361 | * Returns zero on success or %-ENOENT on failure. | ||
362 | */ | ||
363 | int raw_notifier_chain_unregister(struct raw_notifier_head *nh, | ||
364 | struct notifier_block *n) | ||
365 | { | ||
366 | return notifier_chain_unregister(&nh->head, n); | ||
367 | } | ||
368 | |||
369 | EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister); | ||
370 | |||
371 | /** | ||
372 | * raw_notifier_call_chain - Call functions in a raw notifier chain | ||
373 | * @nh: Pointer to head of the raw notifier chain | ||
374 | * @val: Value passed unmodified to notifier function | ||
375 | * @v: Pointer passed unmodified to notifier function | ||
376 | * | ||
377 | * Calls each function in a notifier chain in turn. The functions | ||
378 | * run in an undefined context. | ||
379 | * All locking must be provided by the caller. | ||
380 | * | ||
381 | * If the return value of the notifier can be and'ed | ||
382 | * with %NOTIFY_STOP_MASK then raw_notifier_call_chain | ||
383 | * will return immediately, with the return value of | ||
384 | * the notifier function which halted execution. | ||
385 | * Otherwise the return value is the return value | ||
386 | * of the last notifier function called. | ||
387 | */ | ||
388 | |||
389 | int raw_notifier_call_chain(struct raw_notifier_head *nh, | ||
390 | unsigned long val, void *v) | ||
391 | { | ||
392 | return notifier_call_chain(&nh->head, val, v); | ||
393 | } | ||
394 | |||
395 | EXPORT_SYMBOL_GPL(raw_notifier_call_chain); | ||
191 | 396 | ||
192 | /** | 397 | /** |
193 | * register_reboot_notifier - Register function to be called at reboot time | 398 | * register_reboot_notifier - Register function to be called at reboot time |
@@ -196,13 +401,13 @@ EXPORT_SYMBOL(notifier_call_chain); | |||
196 | * Registers a function with the list of functions | 401 | * Registers a function with the list of functions |
197 | * to be called at reboot time. | 402 | * to be called at reboot time. |
198 | * | 403 | * |
199 | * Currently always returns zero, as notifier_chain_register | 404 | * Currently always returns zero, as blocking_notifier_chain_register |
200 | * always returns zero. | 405 | * always returns zero. |
201 | */ | 406 | */ |
202 | 407 | ||
203 | int register_reboot_notifier(struct notifier_block * nb) | 408 | int register_reboot_notifier(struct notifier_block * nb) |
204 | { | 409 | { |
205 | return notifier_chain_register(&reboot_notifier_list, nb); | 410 | return blocking_notifier_chain_register(&reboot_notifier_list, nb); |
206 | } | 411 | } |
207 | 412 | ||
208 | EXPORT_SYMBOL(register_reboot_notifier); | 413 | EXPORT_SYMBOL(register_reboot_notifier); |
@@ -219,7 +424,7 @@ EXPORT_SYMBOL(register_reboot_notifier); | |||
219 | 424 | ||
220 | int unregister_reboot_notifier(struct notifier_block * nb) | 425 | int unregister_reboot_notifier(struct notifier_block * nb) |
221 | { | 426 | { |
222 | return notifier_chain_unregister(&reboot_notifier_list, nb); | 427 | return blocking_notifier_chain_unregister(&reboot_notifier_list, nb); |
223 | } | 428 | } |
224 | 429 | ||
225 | EXPORT_SYMBOL(unregister_reboot_notifier); | 430 | EXPORT_SYMBOL(unregister_reboot_notifier); |
@@ -380,7 +585,7 @@ EXPORT_SYMBOL_GPL(emergency_restart); | |||
380 | 585 | ||
381 | void kernel_restart_prepare(char *cmd) | 586 | void kernel_restart_prepare(char *cmd) |
382 | { | 587 | { |
383 | notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); | 588 | blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); |
384 | system_state = SYSTEM_RESTART; | 589 | system_state = SYSTEM_RESTART; |
385 | device_shutdown(); | 590 | device_shutdown(); |
386 | } | 591 | } |
@@ -430,7 +635,7 @@ EXPORT_SYMBOL_GPL(kernel_kexec); | |||
430 | 635 | ||
431 | void kernel_shutdown_prepare(enum system_states state) | 636 | void kernel_shutdown_prepare(enum system_states state) |
432 | { | 637 | { |
433 | notifier_call_chain(&reboot_notifier_list, | 638 | blocking_notifier_call_chain(&reboot_notifier_list, |
434 | (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL); | 639 | (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL); |
435 | system_state = state; | 640 | system_state = state; |
436 | device_shutdown(); | 641 | device_shutdown(); |
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 1067090db6b1..d82864c4a617 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c | |||
@@ -42,6 +42,10 @@ cond_syscall(sys_recvmsg); | |||
42 | cond_syscall(sys_socketcall); | 42 | cond_syscall(sys_socketcall); |
43 | cond_syscall(sys_futex); | 43 | cond_syscall(sys_futex); |
44 | cond_syscall(compat_sys_futex); | 44 | cond_syscall(compat_sys_futex); |
45 | cond_syscall(sys_set_robust_list); | ||
46 | cond_syscall(compat_sys_set_robust_list); | ||
47 | cond_syscall(sys_get_robust_list); | ||
48 | cond_syscall(compat_sys_get_robust_list); | ||
45 | cond_syscall(sys_epoll_create); | 49 | cond_syscall(sys_epoll_create); |
46 | cond_syscall(sys_epoll_ctl); | 50 | cond_syscall(sys_epoll_ctl); |
47 | cond_syscall(sys_epoll_wait); | 51 | cond_syscall(sys_epoll_wait); |
diff --git a/mm/Makefile b/mm/Makefile index f10c753dce6d..0b8f73f2ed16 100644 --- a/mm/Makefile +++ b/mm/Makefile | |||
@@ -10,7 +10,7 @@ mmu-$(CONFIG_MMU) := fremap.o highmem.o madvise.o memory.o mincore.o \ | |||
10 | obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \ | 10 | obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \ |
11 | page_alloc.o page-writeback.o pdflush.o \ | 11 | page_alloc.o page-writeback.o pdflush.o \ |
12 | readahead.o swap.o truncate.o vmscan.o \ | 12 | readahead.o swap.o truncate.o vmscan.o \ |
13 | prio_tree.o util.o $(mmu-y) | 13 | prio_tree.o util.o mmzone.o $(mmu-y) |
14 | 14 | ||
15 | obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o thrash.o | 15 | obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o thrash.o |
16 | obj-$(CONFIG_HUGETLBFS) += hugetlb.o | 16 | obj-$(CONFIG_HUGETLBFS) += hugetlb.o |
diff --git a/mm/bootmem.c b/mm/bootmem.c index b55bd39fc5dd..d3e3bd2ffcea 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c | |||
@@ -33,6 +33,7 @@ EXPORT_SYMBOL(max_pfn); /* This is exported so | |||
33 | * dma_get_required_mask(), which uses | 33 | * dma_get_required_mask(), which uses |
34 | * it, can be an inline function */ | 34 | * it, can be an inline function */ |
35 | 35 | ||
36 | static LIST_HEAD(bdata_list); | ||
36 | #ifdef CONFIG_CRASH_DUMP | 37 | #ifdef CONFIG_CRASH_DUMP |
37 | /* | 38 | /* |
38 | * If we have booted due to a crash, max_pfn will be a very low value. We need | 39 | * If we have booted due to a crash, max_pfn will be a very low value. We need |
@@ -52,6 +53,27 @@ unsigned long __init bootmem_bootmap_pages (unsigned long pages) | |||
52 | 53 | ||
53 | return mapsize; | 54 | return mapsize; |
54 | } | 55 | } |
56 | /* | ||
57 | * link bdata in order | ||
58 | */ | ||
59 | static void link_bootmem(bootmem_data_t *bdata) | ||
60 | { | ||
61 | bootmem_data_t *ent; | ||
62 | if (list_empty(&bdata_list)) { | ||
63 | list_add(&bdata->list, &bdata_list); | ||
64 | return; | ||
65 | } | ||
66 | /* insert in order */ | ||
67 | list_for_each_entry(ent, &bdata_list, list) { | ||
68 | if (bdata->node_boot_start < ent->node_boot_start) { | ||
69 | list_add_tail(&bdata->list, &ent->list); | ||
70 | return; | ||
71 | } | ||
72 | } | ||
73 | list_add_tail(&bdata->list, &bdata_list); | ||
74 | return; | ||
75 | } | ||
76 | |||
55 | 77 | ||
56 | /* | 78 | /* |
57 | * Called once to set up the allocator itself. | 79 | * Called once to set up the allocator itself. |
@@ -62,13 +84,11 @@ static unsigned long __init init_bootmem_core (pg_data_t *pgdat, | |||
62 | bootmem_data_t *bdata = pgdat->bdata; | 84 | bootmem_data_t *bdata = pgdat->bdata; |
63 | unsigned long mapsize = ((end - start)+7)/8; | 85 | unsigned long mapsize = ((end - start)+7)/8; |
64 | 86 | ||
65 | pgdat->pgdat_next = pgdat_list; | ||
66 | pgdat_list = pgdat; | ||
67 | |||
68 | mapsize = ALIGN(mapsize, sizeof(long)); | 87 | mapsize = ALIGN(mapsize, sizeof(long)); |
69 | bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT); | 88 | bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT); |
70 | bdata->node_boot_start = (start << PAGE_SHIFT); | 89 | bdata->node_boot_start = (start << PAGE_SHIFT); |
71 | bdata->node_low_pfn = end; | 90 | bdata->node_low_pfn = end; |
91 | link_bootmem(bdata); | ||
72 | 92 | ||
73 | /* | 93 | /* |
74 | * Initially all pages are reserved - setup_arch() has to | 94 | * Initially all pages are reserved - setup_arch() has to |
@@ -383,12 +403,11 @@ unsigned long __init free_all_bootmem (void) | |||
383 | 403 | ||
384 | void * __init __alloc_bootmem(unsigned long size, unsigned long align, unsigned long goal) | 404 | void * __init __alloc_bootmem(unsigned long size, unsigned long align, unsigned long goal) |
385 | { | 405 | { |
386 | pg_data_t *pgdat = pgdat_list; | 406 | bootmem_data_t *bdata; |
387 | void *ptr; | 407 | void *ptr; |
388 | 408 | ||
389 | for_each_pgdat(pgdat) | 409 | list_for_each_entry(bdata, &bdata_list, list) |
390 | if ((ptr = __alloc_bootmem_core(pgdat->bdata, size, | 410 | if ((ptr = __alloc_bootmem_core(bdata, size, align, goal, 0))) |
391 | align, goal, 0))) | ||
392 | return(ptr); | 411 | return(ptr); |
393 | 412 | ||
394 | /* | 413 | /* |
@@ -416,11 +435,11 @@ void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size, unsigne | |||
416 | 435 | ||
417 | void * __init __alloc_bootmem_low(unsigned long size, unsigned long align, unsigned long goal) | 436 | void * __init __alloc_bootmem_low(unsigned long size, unsigned long align, unsigned long goal) |
418 | { | 437 | { |
419 | pg_data_t *pgdat = pgdat_list; | 438 | bootmem_data_t *bdata; |
420 | void *ptr; | 439 | void *ptr; |
421 | 440 | ||
422 | for_each_pgdat(pgdat) | 441 | list_for_each_entry(bdata, &bdata_list, list) |
423 | if ((ptr = __alloc_bootmem_core(pgdat->bdata, size, | 442 | if ((ptr = __alloc_bootmem_core(bdata, size, |
424 | align, goal, LOW32LIMIT))) | 443 | align, goal, LOW32LIMIT))) |
425 | return(ptr); | 444 | return(ptr); |
426 | 445 | ||
diff --git a/mm/mmzone.c b/mm/mmzone.c new file mode 100644 index 000000000000..b022370e612e --- /dev/null +++ b/mm/mmzone.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * linux/mm/mmzone.c | ||
3 | * | ||
4 | * management codes for pgdats and zones. | ||
5 | */ | ||
6 | |||
7 | |||
8 | #include <linux/config.h> | ||
9 | #include <linux/stddef.h> | ||
10 | #include <linux/mmzone.h> | ||
11 | #include <linux/module.h> | ||
12 | |||
13 | struct pglist_data *first_online_pgdat(void) | ||
14 | { | ||
15 | return NODE_DATA(first_online_node); | ||
16 | } | ||
17 | |||
18 | EXPORT_SYMBOL(first_online_pgdat); | ||
19 | |||
20 | struct pglist_data *next_online_pgdat(struct pglist_data *pgdat) | ||
21 | { | ||
22 | int nid = next_online_node(pgdat->node_id); | ||
23 | |||
24 | if (nid == MAX_NUMNODES) | ||
25 | return NULL; | ||
26 | return NODE_DATA(nid); | ||
27 | } | ||
28 | EXPORT_SYMBOL(next_online_pgdat); | ||
29 | |||
30 | |||
31 | /* | ||
32 | * next_zone - helper magic for for_each_zone() | ||
33 | */ | ||
34 | struct zone *next_zone(struct zone *zone) | ||
35 | { | ||
36 | pg_data_t *pgdat = zone->zone_pgdat; | ||
37 | |||
38 | if (zone < pgdat->node_zones + MAX_NR_ZONES - 1) | ||
39 | zone++; | ||
40 | else { | ||
41 | pgdat = next_online_pgdat(pgdat); | ||
42 | if (pgdat) | ||
43 | zone = pgdat->node_zones; | ||
44 | else | ||
45 | zone = NULL; | ||
46 | } | ||
47 | return zone; | ||
48 | } | ||
49 | EXPORT_SYMBOL(next_zone); | ||
50 | |||
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 338a02bb004d..dc523a1f270d 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -49,7 +49,6 @@ nodemask_t node_online_map __read_mostly = { { [0] = 1UL } }; | |||
49 | EXPORT_SYMBOL(node_online_map); | 49 | EXPORT_SYMBOL(node_online_map); |
50 | nodemask_t node_possible_map __read_mostly = NODE_MASK_ALL; | 50 | nodemask_t node_possible_map __read_mostly = NODE_MASK_ALL; |
51 | EXPORT_SYMBOL(node_possible_map); | 51 | EXPORT_SYMBOL(node_possible_map); |
52 | struct pglist_data *pgdat_list __read_mostly; | ||
53 | unsigned long totalram_pages __read_mostly; | 52 | unsigned long totalram_pages __read_mostly; |
54 | unsigned long totalhigh_pages __read_mostly; | 53 | unsigned long totalhigh_pages __read_mostly; |
55 | long nr_swap_pages; | 54 | long nr_swap_pages; |
@@ -1201,7 +1200,7 @@ unsigned int nr_free_highpages (void) | |||
1201 | pg_data_t *pgdat; | 1200 | pg_data_t *pgdat; |
1202 | unsigned int pages = 0; | 1201 | unsigned int pages = 0; |
1203 | 1202 | ||
1204 | for_each_pgdat(pgdat) | 1203 | for_each_online_pgdat(pgdat) |
1205 | pages += pgdat->node_zones[ZONE_HIGHMEM].free_pages; | 1204 | pages += pgdat->node_zones[ZONE_HIGHMEM].free_pages; |
1206 | 1205 | ||
1207 | return pages; | 1206 | return pages; |
@@ -1343,7 +1342,7 @@ void get_zone_counts(unsigned long *active, | |||
1343 | *active = 0; | 1342 | *active = 0; |
1344 | *inactive = 0; | 1343 | *inactive = 0; |
1345 | *free = 0; | 1344 | *free = 0; |
1346 | for_each_pgdat(pgdat) { | 1345 | for_each_online_pgdat(pgdat) { |
1347 | unsigned long l, m, n; | 1346 | unsigned long l, m, n; |
1348 | __get_zone_counts(&l, &m, &n, pgdat); | 1347 | __get_zone_counts(&l, &m, &n, pgdat); |
1349 | *active += l; | 1348 | *active += l; |
@@ -2042,7 +2041,6 @@ static __meminit void init_currently_empty_zone(struct zone *zone, | |||
2042 | zone_wait_table_init(zone, size); | 2041 | zone_wait_table_init(zone, size); |
2043 | pgdat->nr_zones = zone_idx(zone) + 1; | 2042 | pgdat->nr_zones = zone_idx(zone) + 1; |
2044 | 2043 | ||
2045 | zone->zone_mem_map = pfn_to_page(zone_start_pfn); | ||
2046 | zone->zone_start_pfn = zone_start_pfn; | 2044 | zone->zone_start_pfn = zone_start_pfn; |
2047 | 2045 | ||
2048 | memmap_init(size, pgdat->node_id, zone_idx(zone), zone_start_pfn); | 2046 | memmap_init(size, pgdat->node_id, zone_idx(zone), zone_start_pfn); |
@@ -2170,8 +2168,9 @@ static void *frag_start(struct seq_file *m, loff_t *pos) | |||
2170 | { | 2168 | { |
2171 | pg_data_t *pgdat; | 2169 | pg_data_t *pgdat; |
2172 | loff_t node = *pos; | 2170 | loff_t node = *pos; |
2173 | 2171 | for (pgdat = first_online_pgdat(); | |
2174 | for (pgdat = pgdat_list; pgdat && node; pgdat = pgdat->pgdat_next) | 2172 | pgdat && node; |
2173 | pgdat = next_online_pgdat(pgdat)) | ||
2175 | --node; | 2174 | --node; |
2176 | 2175 | ||
2177 | return pgdat; | 2176 | return pgdat; |
@@ -2182,7 +2181,7 @@ static void *frag_next(struct seq_file *m, void *arg, loff_t *pos) | |||
2182 | pg_data_t *pgdat = (pg_data_t *)arg; | 2181 | pg_data_t *pgdat = (pg_data_t *)arg; |
2183 | 2182 | ||
2184 | (*pos)++; | 2183 | (*pos)++; |
2185 | return pgdat->pgdat_next; | 2184 | return next_online_pgdat(pgdat); |
2186 | } | 2185 | } |
2187 | 2186 | ||
2188 | static void frag_stop(struct seq_file *m, void *arg) | 2187 | static void frag_stop(struct seq_file *m, void *arg) |
@@ -2483,7 +2482,7 @@ static void setup_per_zone_lowmem_reserve(void) | |||
2483 | struct pglist_data *pgdat; | 2482 | struct pglist_data *pgdat; |
2484 | int j, idx; | 2483 | int j, idx; |
2485 | 2484 | ||
2486 | for_each_pgdat(pgdat) { | 2485 | for_each_online_pgdat(pgdat) { |
2487 | for (j = 0; j < MAX_NR_ZONES; j++) { | 2486 | for (j = 0; j < MAX_NR_ZONES; j++) { |
2488 | struct zone *zone = pgdat->node_zones + j; | 2487 | struct zone *zone = pgdat->node_zones + j; |
2489 | unsigned long present_pages = zone->present_pages; | 2488 | unsigned long present_pages = zone->present_pages; |
@@ -2745,3 +2744,44 @@ void *__init alloc_large_system_hash(const char *tablename, | |||
2745 | 2744 | ||
2746 | return table; | 2745 | return table; |
2747 | } | 2746 | } |
2747 | |||
2748 | #ifdef CONFIG_OUT_OF_LINE_PFN_TO_PAGE | ||
2749 | /* | ||
2750 | * pfn <-> page translation. out-of-line version. | ||
2751 | * (see asm-generic/memory_model.h) | ||
2752 | */ | ||
2753 | #if defined(CONFIG_FLATMEM) | ||
2754 | struct page *pfn_to_page(unsigned long pfn) | ||
2755 | { | ||
2756 | return mem_map + (pfn - ARCH_PFN_OFFSET); | ||
2757 | } | ||
2758 | unsigned long page_to_pfn(struct page *page) | ||
2759 | { | ||
2760 | return (page - mem_map) + ARCH_PFN_OFFSET; | ||
2761 | } | ||
2762 | #elif defined(CONFIG_DISCONTIGMEM) | ||
2763 | struct page *pfn_to_page(unsigned long pfn) | ||
2764 | { | ||
2765 | int nid = arch_pfn_to_nid(pfn); | ||
2766 | return NODE_DATA(nid)->node_mem_map + arch_local_page_offset(pfn,nid); | ||
2767 | } | ||
2768 | unsigned long page_to_pfn(struct page *page) | ||
2769 | { | ||
2770 | struct pglist_data *pgdat = NODE_DATA(page_to_nid(page)); | ||
2771 | return (page - pgdat->node_mem_map) + pgdat->node_start_pfn; | ||
2772 | } | ||
2773 | #elif defined(CONFIG_SPARSEMEM) | ||
2774 | struct page *pfn_to_page(unsigned long pfn) | ||
2775 | { | ||
2776 | return __section_mem_map_addr(__pfn_to_section(pfn)) + pfn; | ||
2777 | } | ||
2778 | |||
2779 | unsigned long page_to_pfn(struct page *page) | ||
2780 | { | ||
2781 | long section_id = page_to_section(page); | ||
2782 | return page - __section_mem_map_addr(__nr_to_section(section_id)); | ||
2783 | } | ||
2784 | #endif /* CONFIG_FLATMEM/DISCONTIGMME/SPARSEMEM */ | ||
2785 | EXPORT_SYMBOL(pfn_to_page); | ||
2786 | EXPORT_SYMBOL(page_to_pfn); | ||
2787 | #endif /* CONFIG_OUT_OF_LINE_PFN_TO_PAGE */ | ||
diff --git a/mm/vmscan.c b/mm/vmscan.c index 78865c849f8f..acdf001d6941 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c | |||
@@ -1305,7 +1305,7 @@ unsigned long shrink_all_memory(unsigned long nr_pages) | |||
1305 | 1305 | ||
1306 | current->reclaim_state = &reclaim_state; | 1306 | current->reclaim_state = &reclaim_state; |
1307 | repeat: | 1307 | repeat: |
1308 | for_each_pgdat(pgdat) { | 1308 | for_each_online_pgdat(pgdat) { |
1309 | unsigned long freed; | 1309 | unsigned long freed; |
1310 | 1310 | ||
1311 | freed = balance_pgdat(pgdat, nr_to_free, 0); | 1311 | freed = balance_pgdat(pgdat, nr_to_free, 0); |
@@ -1335,7 +1335,7 @@ static int __devinit cpu_callback(struct notifier_block *nfb, | |||
1335 | cpumask_t mask; | 1335 | cpumask_t mask; |
1336 | 1336 | ||
1337 | if (action == CPU_ONLINE) { | 1337 | if (action == CPU_ONLINE) { |
1338 | for_each_pgdat(pgdat) { | 1338 | for_each_online_pgdat(pgdat) { |
1339 | mask = node_to_cpumask(pgdat->node_id); | 1339 | mask = node_to_cpumask(pgdat->node_id); |
1340 | if (any_online_cpu(mask) != NR_CPUS) | 1340 | if (any_online_cpu(mask) != NR_CPUS) |
1341 | /* One of our CPUs online: restore mask */ | 1341 | /* One of our CPUs online: restore mask */ |
@@ -1351,7 +1351,7 @@ static int __init kswapd_init(void) | |||
1351 | pg_data_t *pgdat; | 1351 | pg_data_t *pgdat; |
1352 | 1352 | ||
1353 | swap_setup(); | 1353 | swap_setup(); |
1354 | for_each_pgdat(pgdat) { | 1354 | for_each_online_pgdat(pgdat) { |
1355 | pid_t pid; | 1355 | pid_t pid; |
1356 | 1356 | ||
1357 | pid = kernel_thread(kswapd, pgdat, CLONE_KERNEL); | 1357 | pid = kernel_thread(kswapd, pgdat, CLONE_KERNEL); |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9106354c781e..a49a6975092d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -73,23 +73,23 @@ DEFINE_RWLOCK(hci_cb_list_lock); | |||
73 | struct hci_proto *hci_proto[HCI_MAX_PROTO]; | 73 | struct hci_proto *hci_proto[HCI_MAX_PROTO]; |
74 | 74 | ||
75 | /* HCI notifiers list */ | 75 | /* HCI notifiers list */ |
76 | static struct notifier_block *hci_notifier; | 76 | static ATOMIC_NOTIFIER_HEAD(hci_notifier); |
77 | 77 | ||
78 | /* ---- HCI notifications ---- */ | 78 | /* ---- HCI notifications ---- */ |
79 | 79 | ||
80 | int hci_register_notifier(struct notifier_block *nb) | 80 | int hci_register_notifier(struct notifier_block *nb) |
81 | { | 81 | { |
82 | return notifier_chain_register(&hci_notifier, nb); | 82 | return atomic_notifier_chain_register(&hci_notifier, nb); |
83 | } | 83 | } |
84 | 84 | ||
85 | int hci_unregister_notifier(struct notifier_block *nb) | 85 | int hci_unregister_notifier(struct notifier_block *nb) |
86 | { | 86 | { |
87 | return notifier_chain_unregister(&hci_notifier, nb); | 87 | return atomic_notifier_chain_unregister(&hci_notifier, nb); |
88 | } | 88 | } |
89 | 89 | ||
90 | static void hci_notify(struct hci_dev *hdev, int event) | 90 | static void hci_notify(struct hci_dev *hdev, int event) |
91 | { | 91 | { |
92 | notifier_call_chain(&hci_notifier, event, hdev); | 92 | atomic_notifier_call_chain(&hci_notifier, event, hdev); |
93 | } | 93 | } |
94 | 94 | ||
95 | /* ---- HCI requests ---- */ | 95 | /* ---- HCI requests ---- */ |
diff --git a/net/core/dev.c b/net/core/dev.c index 8e1dc3051222..a3ab11f34153 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -193,7 +193,7 @@ static inline struct hlist_head *dev_index_hash(int ifindex) | |||
193 | * Our notifier list | 193 | * Our notifier list |
194 | */ | 194 | */ |
195 | 195 | ||
196 | static struct notifier_block *netdev_chain; | 196 | static BLOCKING_NOTIFIER_HEAD(netdev_chain); |
197 | 197 | ||
198 | /* | 198 | /* |
199 | * Device drivers call our routines to queue packets here. We empty the | 199 | * Device drivers call our routines to queue packets here. We empty the |
@@ -736,7 +736,8 @@ int dev_change_name(struct net_device *dev, char *newname) | |||
736 | if (!err) { | 736 | if (!err) { |
737 | hlist_del(&dev->name_hlist); | 737 | hlist_del(&dev->name_hlist); |
738 | hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name)); | 738 | hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name)); |
739 | notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); | 739 | blocking_notifier_call_chain(&netdev_chain, |
740 | NETDEV_CHANGENAME, dev); | ||
740 | } | 741 | } |
741 | 742 | ||
742 | return err; | 743 | return err; |
@@ -750,7 +751,7 @@ int dev_change_name(struct net_device *dev, char *newname) | |||
750 | */ | 751 | */ |
751 | void netdev_features_change(struct net_device *dev) | 752 | void netdev_features_change(struct net_device *dev) |
752 | { | 753 | { |
753 | notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev); | 754 | blocking_notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev); |
754 | } | 755 | } |
755 | EXPORT_SYMBOL(netdev_features_change); | 756 | EXPORT_SYMBOL(netdev_features_change); |
756 | 757 | ||
@@ -765,7 +766,8 @@ EXPORT_SYMBOL(netdev_features_change); | |||
765 | void netdev_state_change(struct net_device *dev) | 766 | void netdev_state_change(struct net_device *dev) |
766 | { | 767 | { |
767 | if (dev->flags & IFF_UP) { | 768 | if (dev->flags & IFF_UP) { |
768 | notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev); | 769 | blocking_notifier_call_chain(&netdev_chain, |
770 | NETDEV_CHANGE, dev); | ||
769 | rtmsg_ifinfo(RTM_NEWLINK, dev, 0); | 771 | rtmsg_ifinfo(RTM_NEWLINK, dev, 0); |
770 | } | 772 | } |
771 | } | 773 | } |
@@ -862,7 +864,7 @@ int dev_open(struct net_device *dev) | |||
862 | /* | 864 | /* |
863 | * ... and announce new interface. | 865 | * ... and announce new interface. |
864 | */ | 866 | */ |
865 | notifier_call_chain(&netdev_chain, NETDEV_UP, dev); | 867 | blocking_notifier_call_chain(&netdev_chain, NETDEV_UP, dev); |
866 | } | 868 | } |
867 | return ret; | 869 | return ret; |
868 | } | 870 | } |
@@ -885,7 +887,7 @@ int dev_close(struct net_device *dev) | |||
885 | * Tell people we are going down, so that they can | 887 | * Tell people we are going down, so that they can |
886 | * prepare to death, when device is still operating. | 888 | * prepare to death, when device is still operating. |
887 | */ | 889 | */ |
888 | notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev); | 890 | blocking_notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev); |
889 | 891 | ||
890 | dev_deactivate(dev); | 892 | dev_deactivate(dev); |
891 | 893 | ||
@@ -922,7 +924,7 @@ int dev_close(struct net_device *dev) | |||
922 | /* | 924 | /* |
923 | * Tell people we are down | 925 | * Tell people we are down |
924 | */ | 926 | */ |
925 | notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); | 927 | blocking_notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); |
926 | 928 | ||
927 | return 0; | 929 | return 0; |
928 | } | 930 | } |
@@ -953,7 +955,7 @@ int register_netdevice_notifier(struct notifier_block *nb) | |||
953 | int err; | 955 | int err; |
954 | 956 | ||
955 | rtnl_lock(); | 957 | rtnl_lock(); |
956 | err = notifier_chain_register(&netdev_chain, nb); | 958 | err = blocking_notifier_chain_register(&netdev_chain, nb); |
957 | if (!err) { | 959 | if (!err) { |
958 | for (dev = dev_base; dev; dev = dev->next) { | 960 | for (dev = dev_base; dev; dev = dev->next) { |
959 | nb->notifier_call(nb, NETDEV_REGISTER, dev); | 961 | nb->notifier_call(nb, NETDEV_REGISTER, dev); |
@@ -981,7 +983,7 @@ int unregister_netdevice_notifier(struct notifier_block *nb) | |||
981 | int err; | 983 | int err; |
982 | 984 | ||
983 | rtnl_lock(); | 985 | rtnl_lock(); |
984 | err = notifier_chain_unregister(&netdev_chain, nb); | 986 | err = blocking_notifier_chain_unregister(&netdev_chain, nb); |
985 | rtnl_unlock(); | 987 | rtnl_unlock(); |
986 | return err; | 988 | return err; |
987 | } | 989 | } |
@@ -992,12 +994,12 @@ int unregister_netdevice_notifier(struct notifier_block *nb) | |||
992 | * @v: pointer passed unmodified to notifier function | 994 | * @v: pointer passed unmodified to notifier function |
993 | * | 995 | * |
994 | * Call all network notifier blocks. Parameters and return value | 996 | * Call all network notifier blocks. Parameters and return value |
995 | * are as for notifier_call_chain(). | 997 | * are as for blocking_notifier_call_chain(). |
996 | */ | 998 | */ |
997 | 999 | ||
998 | int call_netdevice_notifiers(unsigned long val, void *v) | 1000 | int call_netdevice_notifiers(unsigned long val, void *v) |
999 | { | 1001 | { |
1000 | return notifier_call_chain(&netdev_chain, val, v); | 1002 | return blocking_notifier_call_chain(&netdev_chain, val, v); |
1001 | } | 1003 | } |
1002 | 1004 | ||
1003 | /* When > 0 there are consumers of rx skb time stamps */ | 1005 | /* When > 0 there are consumers of rx skb time stamps */ |
@@ -2242,7 +2244,8 @@ int dev_change_flags(struct net_device *dev, unsigned flags) | |||
2242 | if (dev->flags & IFF_UP && | 2244 | if (dev->flags & IFF_UP && |
2243 | ((old_flags ^ dev->flags) &~ (IFF_UP | IFF_PROMISC | IFF_ALLMULTI | | 2245 | ((old_flags ^ dev->flags) &~ (IFF_UP | IFF_PROMISC | IFF_ALLMULTI | |
2244 | IFF_VOLATILE))) | 2246 | IFF_VOLATILE))) |
2245 | notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev); | 2247 | blocking_notifier_call_chain(&netdev_chain, |
2248 | NETDEV_CHANGE, dev); | ||
2246 | 2249 | ||
2247 | if ((flags ^ dev->gflags) & IFF_PROMISC) { | 2250 | if ((flags ^ dev->gflags) & IFF_PROMISC) { |
2248 | int inc = (flags & IFF_PROMISC) ? +1 : -1; | 2251 | int inc = (flags & IFF_PROMISC) ? +1 : -1; |
@@ -2286,8 +2289,8 @@ int dev_set_mtu(struct net_device *dev, int new_mtu) | |||
2286 | else | 2289 | else |
2287 | dev->mtu = new_mtu; | 2290 | dev->mtu = new_mtu; |
2288 | if (!err && dev->flags & IFF_UP) | 2291 | if (!err && dev->flags & IFF_UP) |
2289 | notifier_call_chain(&netdev_chain, | 2292 | blocking_notifier_call_chain(&netdev_chain, |
2290 | NETDEV_CHANGEMTU, dev); | 2293 | NETDEV_CHANGEMTU, dev); |
2291 | return err; | 2294 | return err; |
2292 | } | 2295 | } |
2293 | 2296 | ||
@@ -2303,7 +2306,8 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa) | |||
2303 | return -ENODEV; | 2306 | return -ENODEV; |
2304 | err = dev->set_mac_address(dev, sa); | 2307 | err = dev->set_mac_address(dev, sa); |
2305 | if (!err) | 2308 | if (!err) |
2306 | notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); | 2309 | blocking_notifier_call_chain(&netdev_chain, |
2310 | NETDEV_CHANGEADDR, dev); | ||
2307 | return err; | 2311 | return err; |
2308 | } | 2312 | } |
2309 | 2313 | ||
@@ -2359,7 +2363,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) | |||
2359 | return -EINVAL; | 2363 | return -EINVAL; |
2360 | memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, | 2364 | memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, |
2361 | min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); | 2365 | min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); |
2362 | notifier_call_chain(&netdev_chain, | 2366 | blocking_notifier_call_chain(&netdev_chain, |
2363 | NETDEV_CHANGEADDR, dev); | 2367 | NETDEV_CHANGEADDR, dev); |
2364 | return 0; | 2368 | return 0; |
2365 | 2369 | ||
@@ -2813,7 +2817,7 @@ int register_netdevice(struct net_device *dev) | |||
2813 | write_unlock_bh(&dev_base_lock); | 2817 | write_unlock_bh(&dev_base_lock); |
2814 | 2818 | ||
2815 | /* Notify protocols, that a new device appeared. */ | 2819 | /* Notify protocols, that a new device appeared. */ |
2816 | notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); | 2820 | blocking_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); |
2817 | 2821 | ||
2818 | /* Finish registration after unlock */ | 2822 | /* Finish registration after unlock */ |
2819 | net_set_todo(dev); | 2823 | net_set_todo(dev); |
@@ -2892,7 +2896,7 @@ static void netdev_wait_allrefs(struct net_device *dev) | |||
2892 | rtnl_lock(); | 2896 | rtnl_lock(); |
2893 | 2897 | ||
2894 | /* Rebroadcast unregister notification */ | 2898 | /* Rebroadcast unregister notification */ |
2895 | notifier_call_chain(&netdev_chain, | 2899 | blocking_notifier_call_chain(&netdev_chain, |
2896 | NETDEV_UNREGISTER, dev); | 2900 | NETDEV_UNREGISTER, dev); |
2897 | 2901 | ||
2898 | if (test_bit(__LINK_STATE_LINKWATCH_PENDING, | 2902 | if (test_bit(__LINK_STATE_LINKWATCH_PENDING, |
@@ -3148,7 +3152,7 @@ int unregister_netdevice(struct net_device *dev) | |||
3148 | /* Notify protocols, that we are about to destroy | 3152 | /* Notify protocols, that we are about to destroy |
3149 | this device. They should clean all the things. | 3153 | this device. They should clean all the things. |
3150 | */ | 3154 | */ |
3151 | notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); | 3155 | blocking_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev); |
3152 | 3156 | ||
3153 | /* | 3157 | /* |
3154 | * Flush the multicast chain | 3158 | * Flush the multicast chain |
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index cc7b9d9255ef..d2ae9893ca17 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c | |||
@@ -68,7 +68,7 @@ __le16 decnet_address = 0; | |||
68 | 68 | ||
69 | static DEFINE_RWLOCK(dndev_lock); | 69 | static DEFINE_RWLOCK(dndev_lock); |
70 | static struct net_device *decnet_default_device; | 70 | static struct net_device *decnet_default_device; |
71 | static struct notifier_block *dnaddr_chain; | 71 | static BLOCKING_NOTIFIER_HEAD(dnaddr_chain); |
72 | 72 | ||
73 | static struct dn_dev *dn_dev_create(struct net_device *dev, int *err); | 73 | static struct dn_dev *dn_dev_create(struct net_device *dev, int *err); |
74 | static void dn_dev_delete(struct net_device *dev); | 74 | static void dn_dev_delete(struct net_device *dev); |
@@ -446,7 +446,7 @@ static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int de | |||
446 | } | 446 | } |
447 | 447 | ||
448 | rtmsg_ifa(RTM_DELADDR, ifa1); | 448 | rtmsg_ifa(RTM_DELADDR, ifa1); |
449 | notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1); | 449 | blocking_notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1); |
450 | if (destroy) { | 450 | if (destroy) { |
451 | dn_dev_free_ifa(ifa1); | 451 | dn_dev_free_ifa(ifa1); |
452 | 452 | ||
@@ -481,7 +481,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa) | |||
481 | dn_db->ifa_list = ifa; | 481 | dn_db->ifa_list = ifa; |
482 | 482 | ||
483 | rtmsg_ifa(RTM_NEWADDR, ifa); | 483 | rtmsg_ifa(RTM_NEWADDR, ifa); |
484 | notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa); | 484 | blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa); |
485 | 485 | ||
486 | return 0; | 486 | return 0; |
487 | } | 487 | } |
@@ -1285,12 +1285,12 @@ void dn_dev_devices_on(void) | |||
1285 | 1285 | ||
1286 | int register_dnaddr_notifier(struct notifier_block *nb) | 1286 | int register_dnaddr_notifier(struct notifier_block *nb) |
1287 | { | 1287 | { |
1288 | return notifier_chain_register(&dnaddr_chain, nb); | 1288 | return blocking_notifier_chain_register(&dnaddr_chain, nb); |
1289 | } | 1289 | } |
1290 | 1290 | ||
1291 | int unregister_dnaddr_notifier(struct notifier_block *nb) | 1291 | int unregister_dnaddr_notifier(struct notifier_block *nb) |
1292 | { | 1292 | { |
1293 | return notifier_chain_unregister(&dnaddr_chain, nb); | 1293 | return blocking_notifier_chain_unregister(&dnaddr_chain, nb); |
1294 | } | 1294 | } |
1295 | 1295 | ||
1296 | #ifdef CONFIG_PROC_FS | 1296 | #ifdef CONFIG_PROC_FS |
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 44fdf1413e2c..81c2f7885292 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -81,7 +81,7 @@ static struct ipv4_devconf ipv4_devconf_dflt = { | |||
81 | 81 | ||
82 | static void rtmsg_ifa(int event, struct in_ifaddr *); | 82 | static void rtmsg_ifa(int event, struct in_ifaddr *); |
83 | 83 | ||
84 | static struct notifier_block *inetaddr_chain; | 84 | static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); |
85 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | 85 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, |
86 | int destroy); | 86 | int destroy); |
87 | #ifdef CONFIG_SYSCTL | 87 | #ifdef CONFIG_SYSCTL |
@@ -267,7 +267,8 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
267 | *ifap1 = ifa->ifa_next; | 267 | *ifap1 = ifa->ifa_next; |
268 | 268 | ||
269 | rtmsg_ifa(RTM_DELADDR, ifa); | 269 | rtmsg_ifa(RTM_DELADDR, ifa); |
270 | notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa); | 270 | blocking_notifier_call_chain(&inetaddr_chain, |
271 | NETDEV_DOWN, ifa); | ||
271 | inet_free_ifa(ifa); | 272 | inet_free_ifa(ifa); |
272 | } else { | 273 | } else { |
273 | promote = ifa; | 274 | promote = ifa; |
@@ -291,7 +292,7 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
291 | So that, this order is correct. | 292 | So that, this order is correct. |
292 | */ | 293 | */ |
293 | rtmsg_ifa(RTM_DELADDR, ifa1); | 294 | rtmsg_ifa(RTM_DELADDR, ifa1); |
294 | notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); | 295 | blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); |
295 | 296 | ||
296 | if (promote) { | 297 | if (promote) { |
297 | 298 | ||
@@ -303,7 +304,8 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
303 | 304 | ||
304 | promote->ifa_flags &= ~IFA_F_SECONDARY; | 305 | promote->ifa_flags &= ~IFA_F_SECONDARY; |
305 | rtmsg_ifa(RTM_NEWADDR, promote); | 306 | rtmsg_ifa(RTM_NEWADDR, promote); |
306 | notifier_call_chain(&inetaddr_chain, NETDEV_UP, promote); | 307 | blocking_notifier_call_chain(&inetaddr_chain, |
308 | NETDEV_UP, promote); | ||
307 | for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) { | 309 | for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) { |
308 | if (ifa1->ifa_mask != ifa->ifa_mask || | 310 | if (ifa1->ifa_mask != ifa->ifa_mask || |
309 | !inet_ifa_match(ifa1->ifa_address, ifa)) | 311 | !inet_ifa_match(ifa1->ifa_address, ifa)) |
@@ -366,7 +368,7 @@ static int inet_insert_ifa(struct in_ifaddr *ifa) | |||
366 | Notifier will trigger FIB update, so that | 368 | Notifier will trigger FIB update, so that |
367 | listeners of netlink will know about new ifaddr */ | 369 | listeners of netlink will know about new ifaddr */ |
368 | rtmsg_ifa(RTM_NEWADDR, ifa); | 370 | rtmsg_ifa(RTM_NEWADDR, ifa); |
369 | notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa); | 371 | blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa); |
370 | 372 | ||
371 | return 0; | 373 | return 0; |
372 | } | 374 | } |
@@ -938,12 +940,12 @@ u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scop | |||
938 | 940 | ||
939 | int register_inetaddr_notifier(struct notifier_block *nb) | 941 | int register_inetaddr_notifier(struct notifier_block *nb) |
940 | { | 942 | { |
941 | return notifier_chain_register(&inetaddr_chain, nb); | 943 | return blocking_notifier_chain_register(&inetaddr_chain, nb); |
942 | } | 944 | } |
943 | 945 | ||
944 | int unregister_inetaddr_notifier(struct notifier_block *nb) | 946 | int unregister_inetaddr_notifier(struct notifier_block *nb) |
945 | { | 947 | { |
946 | return notifier_chain_unregister(&inetaddr_chain, nb); | 948 | return blocking_notifier_chain_unregister(&inetaddr_chain, nb); |
947 | } | 949 | } |
948 | 950 | ||
949 | /* Rename ifa_labels for a device name change. Make some effort to preserve existing | 951 | /* Rename ifa_labels for a device name change. Make some effort to preserve existing |
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 9e34034729a6..ceaabc18202b 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c | |||
@@ -80,8 +80,8 @@ static int ip_conntrack_vmalloc; | |||
80 | static unsigned int ip_conntrack_next_id; | 80 | static unsigned int ip_conntrack_next_id; |
81 | static unsigned int ip_conntrack_expect_next_id; | 81 | static unsigned int ip_conntrack_expect_next_id; |
82 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS | 82 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS |
83 | struct notifier_block *ip_conntrack_chain; | 83 | ATOMIC_NOTIFIER_HEAD(ip_conntrack_chain); |
84 | struct notifier_block *ip_conntrack_expect_chain; | 84 | ATOMIC_NOTIFIER_HEAD(ip_conntrack_expect_chain); |
85 | 85 | ||
86 | DEFINE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache); | 86 | DEFINE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache); |
87 | 87 | ||
@@ -92,7 +92,7 @@ __ip_ct_deliver_cached_events(struct ip_conntrack_ecache *ecache) | |||
92 | { | 92 | { |
93 | DEBUGP("ecache: delivering events for %p\n", ecache->ct); | 93 | DEBUGP("ecache: delivering events for %p\n", ecache->ct); |
94 | if (is_confirmed(ecache->ct) && !is_dying(ecache->ct) && ecache->events) | 94 | if (is_confirmed(ecache->ct) && !is_dying(ecache->ct) && ecache->events) |
95 | notifier_call_chain(&ip_conntrack_chain, ecache->events, | 95 | atomic_notifier_call_chain(&ip_conntrack_chain, ecache->events, |
96 | ecache->ct); | 96 | ecache->ct); |
97 | ecache->events = 0; | 97 | ecache->events = 0; |
98 | ip_conntrack_put(ecache->ct); | 98 | ip_conntrack_put(ecache->ct); |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 01c62a0d3742..445006ee4522 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -143,7 +143,7 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev, | |||
143 | struct prefix_info *pinfo); | 143 | struct prefix_info *pinfo); |
144 | static int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev); | 144 | static int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev); |
145 | 145 | ||
146 | static struct notifier_block *inet6addr_chain; | 146 | static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); |
147 | 147 | ||
148 | struct ipv6_devconf ipv6_devconf = { | 148 | struct ipv6_devconf ipv6_devconf = { |
149 | .forwarding = 0, | 149 | .forwarding = 0, |
@@ -593,7 +593,7 @@ out2: | |||
593 | read_unlock_bh(&addrconf_lock); | 593 | read_unlock_bh(&addrconf_lock); |
594 | 594 | ||
595 | if (likely(err == 0)) | 595 | if (likely(err == 0)) |
596 | notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa); | 596 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa); |
597 | else { | 597 | else { |
598 | kfree(ifa); | 598 | kfree(ifa); |
599 | ifa = ERR_PTR(err); | 599 | ifa = ERR_PTR(err); |
@@ -688,7 +688,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
688 | 688 | ||
689 | ipv6_ifa_notify(RTM_DELADDR, ifp); | 689 | ipv6_ifa_notify(RTM_DELADDR, ifp); |
690 | 690 | ||
691 | notifier_call_chain(&inet6addr_chain,NETDEV_DOWN,ifp); | 691 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifp); |
692 | 692 | ||
693 | addrconf_del_timer(ifp); | 693 | addrconf_del_timer(ifp); |
694 | 694 | ||
@@ -3767,12 +3767,12 @@ static void addrconf_sysctl_unregister(struct ipv6_devconf *p) | |||
3767 | 3767 | ||
3768 | int register_inet6addr_notifier(struct notifier_block *nb) | 3768 | int register_inet6addr_notifier(struct notifier_block *nb) |
3769 | { | 3769 | { |
3770 | return notifier_chain_register(&inet6addr_chain, nb); | 3770 | return atomic_notifier_chain_register(&inet6addr_chain, nb); |
3771 | } | 3771 | } |
3772 | 3772 | ||
3773 | int unregister_inet6addr_notifier(struct notifier_block *nb) | 3773 | int unregister_inet6addr_notifier(struct notifier_block *nb) |
3774 | { | 3774 | { |
3775 | return notifier_chain_unregister(&inet6addr_chain,nb); | 3775 | return atomic_notifier_chain_unregister(&inet6addr_chain,nb); |
3776 | } | 3776 | } |
3777 | 3777 | ||
3778 | /* | 3778 | /* |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 0ae281d9bfc3..56389c83557c 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -90,8 +90,8 @@ static int nf_conntrack_vmalloc; | |||
90 | static unsigned int nf_conntrack_next_id; | 90 | static unsigned int nf_conntrack_next_id; |
91 | static unsigned int nf_conntrack_expect_next_id; | 91 | static unsigned int nf_conntrack_expect_next_id; |
92 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | 92 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
93 | struct notifier_block *nf_conntrack_chain; | 93 | ATOMIC_NOTIFIER_HEAD(nf_conntrack_chain); |
94 | struct notifier_block *nf_conntrack_expect_chain; | 94 | ATOMIC_NOTIFIER_HEAD(nf_conntrack_expect_chain); |
95 | 95 | ||
96 | DEFINE_PER_CPU(struct nf_conntrack_ecache, nf_conntrack_ecache); | 96 | DEFINE_PER_CPU(struct nf_conntrack_ecache, nf_conntrack_ecache); |
97 | 97 | ||
@@ -103,7 +103,7 @@ __nf_ct_deliver_cached_events(struct nf_conntrack_ecache *ecache) | |||
103 | DEBUGP("ecache: delivering events for %p\n", ecache->ct); | 103 | DEBUGP("ecache: delivering events for %p\n", ecache->ct); |
104 | if (nf_ct_is_confirmed(ecache->ct) && !nf_ct_is_dying(ecache->ct) | 104 | if (nf_ct_is_confirmed(ecache->ct) && !nf_ct_is_dying(ecache->ct) |
105 | && ecache->events) | 105 | && ecache->events) |
106 | notifier_call_chain(&nf_conntrack_chain, ecache->events, | 106 | atomic_notifier_call_chain(&nf_conntrack_chain, ecache->events, |
107 | ecache->ct); | 107 | ecache->ct); |
108 | 108 | ||
109 | ecache->events = 0; | 109 | ecache->events = 0; |
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index d00a9034cb5f..2a233ffcf618 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -123,7 +123,7 @@ static void netlink_destroy_callback(struct netlink_callback *cb); | |||
123 | static DEFINE_RWLOCK(nl_table_lock); | 123 | static DEFINE_RWLOCK(nl_table_lock); |
124 | static atomic_t nl_table_users = ATOMIC_INIT(0); | 124 | static atomic_t nl_table_users = ATOMIC_INIT(0); |
125 | 125 | ||
126 | static struct notifier_block *netlink_chain; | 126 | static ATOMIC_NOTIFIER_HEAD(netlink_chain); |
127 | 127 | ||
128 | static u32 netlink_group_mask(u32 group) | 128 | static u32 netlink_group_mask(u32 group) |
129 | { | 129 | { |
@@ -469,7 +469,8 @@ static int netlink_release(struct socket *sock) | |||
469 | .protocol = sk->sk_protocol, | 469 | .protocol = sk->sk_protocol, |
470 | .pid = nlk->pid, | 470 | .pid = nlk->pid, |
471 | }; | 471 | }; |
472 | notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n); | 472 | atomic_notifier_call_chain(&netlink_chain, |
473 | NETLINK_URELEASE, &n); | ||
473 | } | 474 | } |
474 | 475 | ||
475 | if (nlk->module) | 476 | if (nlk->module) |
@@ -1695,12 +1696,12 @@ static struct file_operations netlink_seq_fops = { | |||
1695 | 1696 | ||
1696 | int netlink_register_notifier(struct notifier_block *nb) | 1697 | int netlink_register_notifier(struct notifier_block *nb) |
1697 | { | 1698 | { |
1698 | return notifier_chain_register(&netlink_chain, nb); | 1699 | return atomic_notifier_chain_register(&netlink_chain, nb); |
1699 | } | 1700 | } |
1700 | 1701 | ||
1701 | int netlink_unregister_notifier(struct notifier_block *nb) | 1702 | int netlink_unregister_notifier(struct notifier_block *nb) |
1702 | { | 1703 | { |
1703 | return notifier_chain_unregister(&netlink_chain, nb); | 1704 | return atomic_notifier_chain_unregister(&netlink_chain, nb); |
1704 | } | 1705 | } |
1705 | 1706 | ||
1706 | static const struct proto_ops netlink_ops = { | 1707 | static const struct proto_ops netlink_ops = { |
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 23632d84d8d7..4d7eb9e704da 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c | |||
@@ -78,7 +78,8 @@ struct rsi { | |||
78 | 78 | ||
79 | static struct cache_head *rsi_table[RSI_HASHMAX]; | 79 | static struct cache_head *rsi_table[RSI_HASHMAX]; |
80 | static struct cache_detail rsi_cache; | 80 | static struct cache_detail rsi_cache; |
81 | static struct rsi *rsi_lookup(struct rsi *item, int set); | 81 | static struct rsi *rsi_update(struct rsi *new, struct rsi *old); |
82 | static struct rsi *rsi_lookup(struct rsi *item); | ||
82 | 83 | ||
83 | static void rsi_free(struct rsi *rsii) | 84 | static void rsi_free(struct rsi *rsii) |
84 | { | 85 | { |
@@ -88,13 +89,11 @@ static void rsi_free(struct rsi *rsii) | |||
88 | kfree(rsii->out_token.data); | 89 | kfree(rsii->out_token.data); |
89 | } | 90 | } |
90 | 91 | ||
91 | static void rsi_put(struct cache_head *item, struct cache_detail *cd) | 92 | static void rsi_put(struct kref *ref) |
92 | { | 93 | { |
93 | struct rsi *rsii = container_of(item, struct rsi, h); | 94 | struct rsi *rsii = container_of(ref, struct rsi, h.ref); |
94 | if (cache_put(item, cd)) { | 95 | rsi_free(rsii); |
95 | rsi_free(rsii); | 96 | kfree(rsii); |
96 | kfree(rsii); | ||
97 | } | ||
98 | } | 97 | } |
99 | 98 | ||
100 | static inline int rsi_hash(struct rsi *item) | 99 | static inline int rsi_hash(struct rsi *item) |
@@ -103,8 +102,10 @@ static inline int rsi_hash(struct rsi *item) | |||
103 | ^ hash_mem(item->in_token.data, item->in_token.len, RSI_HASHBITS); | 102 | ^ hash_mem(item->in_token.data, item->in_token.len, RSI_HASHBITS); |
104 | } | 103 | } |
105 | 104 | ||
106 | static inline int rsi_match(struct rsi *item, struct rsi *tmp) | 105 | static int rsi_match(struct cache_head *a, struct cache_head *b) |
107 | { | 106 | { |
107 | struct rsi *item = container_of(a, struct rsi, h); | ||
108 | struct rsi *tmp = container_of(b, struct rsi, h); | ||
108 | return netobj_equal(&item->in_handle, &tmp->in_handle) | 109 | return netobj_equal(&item->in_handle, &tmp->in_handle) |
109 | && netobj_equal(&item->in_token, &tmp->in_token); | 110 | && netobj_equal(&item->in_token, &tmp->in_token); |
110 | } | 111 | } |
@@ -125,8 +126,11 @@ static inline int dup_netobj(struct xdr_netobj *dst, struct xdr_netobj *src) | |||
125 | return dup_to_netobj(dst, src->data, src->len); | 126 | return dup_to_netobj(dst, src->data, src->len); |
126 | } | 127 | } |
127 | 128 | ||
128 | static inline void rsi_init(struct rsi *new, struct rsi *item) | 129 | static void rsi_init(struct cache_head *cnew, struct cache_head *citem) |
129 | { | 130 | { |
131 | struct rsi *new = container_of(cnew, struct rsi, h); | ||
132 | struct rsi *item = container_of(citem, struct rsi, h); | ||
133 | |||
130 | new->out_handle.data = NULL; | 134 | new->out_handle.data = NULL; |
131 | new->out_handle.len = 0; | 135 | new->out_handle.len = 0; |
132 | new->out_token.data = NULL; | 136 | new->out_token.data = NULL; |
@@ -141,8 +145,11 @@ static inline void rsi_init(struct rsi *new, struct rsi *item) | |||
141 | item->in_token.data = NULL; | 145 | item->in_token.data = NULL; |
142 | } | 146 | } |
143 | 147 | ||
144 | static inline void rsi_update(struct rsi *new, struct rsi *item) | 148 | static void update_rsi(struct cache_head *cnew, struct cache_head *citem) |
145 | { | 149 | { |
150 | struct rsi *new = container_of(cnew, struct rsi, h); | ||
151 | struct rsi *item = container_of(citem, struct rsi, h); | ||
152 | |||
146 | BUG_ON(new->out_handle.data || new->out_token.data); | 153 | BUG_ON(new->out_handle.data || new->out_token.data); |
147 | new->out_handle.len = item->out_handle.len; | 154 | new->out_handle.len = item->out_handle.len; |
148 | item->out_handle.len = 0; | 155 | item->out_handle.len = 0; |
@@ -157,6 +164,15 @@ static inline void rsi_update(struct rsi *new, struct rsi *item) | |||
157 | new->minor_status = item->minor_status; | 164 | new->minor_status = item->minor_status; |
158 | } | 165 | } |
159 | 166 | ||
167 | static struct cache_head *rsi_alloc(void) | ||
168 | { | ||
169 | struct rsi *rsii = kmalloc(sizeof(*rsii), GFP_KERNEL); | ||
170 | if (rsii) | ||
171 | return &rsii->h; | ||
172 | else | ||
173 | return NULL; | ||
174 | } | ||
175 | |||
160 | static void rsi_request(struct cache_detail *cd, | 176 | static void rsi_request(struct cache_detail *cd, |
161 | struct cache_head *h, | 177 | struct cache_head *h, |
162 | char **bpp, int *blen) | 178 | char **bpp, int *blen) |
@@ -198,6 +214,10 @@ static int rsi_parse(struct cache_detail *cd, | |||
198 | if (dup_to_netobj(&rsii.in_token, buf, len)) | 214 | if (dup_to_netobj(&rsii.in_token, buf, len)) |
199 | goto out; | 215 | goto out; |
200 | 216 | ||
217 | rsip = rsi_lookup(&rsii); | ||
218 | if (!rsip) | ||
219 | goto out; | ||
220 | |||
201 | rsii.h.flags = 0; | 221 | rsii.h.flags = 0; |
202 | /* expiry */ | 222 | /* expiry */ |
203 | expiry = get_expiry(&mesg); | 223 | expiry = get_expiry(&mesg); |
@@ -240,12 +260,14 @@ static int rsi_parse(struct cache_detail *cd, | |||
240 | goto out; | 260 | goto out; |
241 | } | 261 | } |
242 | rsii.h.expiry_time = expiry; | 262 | rsii.h.expiry_time = expiry; |
243 | rsip = rsi_lookup(&rsii, 1); | 263 | rsip = rsi_update(&rsii, rsip); |
244 | status = 0; | 264 | status = 0; |
245 | out: | 265 | out: |
246 | rsi_free(&rsii); | 266 | rsi_free(&rsii); |
247 | if (rsip) | 267 | if (rsip) |
248 | rsi_put(&rsip->h, &rsi_cache); | 268 | cache_put(&rsip->h, &rsi_cache); |
269 | else | ||
270 | status = -ENOMEM; | ||
249 | return status; | 271 | return status; |
250 | } | 272 | } |
251 | 273 | ||
@@ -257,9 +279,37 @@ static struct cache_detail rsi_cache = { | |||
257 | .cache_put = rsi_put, | 279 | .cache_put = rsi_put, |
258 | .cache_request = rsi_request, | 280 | .cache_request = rsi_request, |
259 | .cache_parse = rsi_parse, | 281 | .cache_parse = rsi_parse, |
282 | .match = rsi_match, | ||
283 | .init = rsi_init, | ||
284 | .update = update_rsi, | ||
285 | .alloc = rsi_alloc, | ||
260 | }; | 286 | }; |
261 | 287 | ||
262 | static DefineSimpleCacheLookup(rsi, 0) | 288 | static struct rsi *rsi_lookup(struct rsi *item) |
289 | { | ||
290 | struct cache_head *ch; | ||
291 | int hash = rsi_hash(item); | ||
292 | |||
293 | ch = sunrpc_cache_lookup(&rsi_cache, &item->h, hash); | ||
294 | if (ch) | ||
295 | return container_of(ch, struct rsi, h); | ||
296 | else | ||
297 | return NULL; | ||
298 | } | ||
299 | |||
300 | static struct rsi *rsi_update(struct rsi *new, struct rsi *old) | ||
301 | { | ||
302 | struct cache_head *ch; | ||
303 | int hash = rsi_hash(new); | ||
304 | |||
305 | ch = sunrpc_cache_update(&rsi_cache, &new->h, | ||
306 | &old->h, hash); | ||
307 | if (ch) | ||
308 | return container_of(ch, struct rsi, h); | ||
309 | else | ||
310 | return NULL; | ||
311 | } | ||
312 | |||
263 | 313 | ||
264 | /* | 314 | /* |
265 | * The rpcsec_context cache is used to store a context that is | 315 | * The rpcsec_context cache is used to store a context that is |
@@ -293,7 +343,8 @@ struct rsc { | |||
293 | 343 | ||
294 | static struct cache_head *rsc_table[RSC_HASHMAX]; | 344 | static struct cache_head *rsc_table[RSC_HASHMAX]; |
295 | static struct cache_detail rsc_cache; | 345 | static struct cache_detail rsc_cache; |
296 | static struct rsc *rsc_lookup(struct rsc *item, int set); | 346 | static struct rsc *rsc_update(struct rsc *new, struct rsc *old); |
347 | static struct rsc *rsc_lookup(struct rsc *item); | ||
297 | 348 | ||
298 | static void rsc_free(struct rsc *rsci) | 349 | static void rsc_free(struct rsc *rsci) |
299 | { | 350 | { |
@@ -304,14 +355,12 @@ static void rsc_free(struct rsc *rsci) | |||
304 | put_group_info(rsci->cred.cr_group_info); | 355 | put_group_info(rsci->cred.cr_group_info); |
305 | } | 356 | } |
306 | 357 | ||
307 | static void rsc_put(struct cache_head *item, struct cache_detail *cd) | 358 | static void rsc_put(struct kref *ref) |
308 | { | 359 | { |
309 | struct rsc *rsci = container_of(item, struct rsc, h); | 360 | struct rsc *rsci = container_of(ref, struct rsc, h.ref); |
310 | 361 | ||
311 | if (cache_put(item, cd)) { | 362 | rsc_free(rsci); |
312 | rsc_free(rsci); | 363 | kfree(rsci); |
313 | kfree(rsci); | ||
314 | } | ||
315 | } | 364 | } |
316 | 365 | ||
317 | static inline int | 366 | static inline int |
@@ -320,15 +369,21 @@ rsc_hash(struct rsc *rsci) | |||
320 | return hash_mem(rsci->handle.data, rsci->handle.len, RSC_HASHBITS); | 369 | return hash_mem(rsci->handle.data, rsci->handle.len, RSC_HASHBITS); |
321 | } | 370 | } |
322 | 371 | ||
323 | static inline int | 372 | static int |
324 | rsc_match(struct rsc *new, struct rsc *tmp) | 373 | rsc_match(struct cache_head *a, struct cache_head *b) |
325 | { | 374 | { |
375 | struct rsc *new = container_of(a, struct rsc, h); | ||
376 | struct rsc *tmp = container_of(b, struct rsc, h); | ||
377 | |||
326 | return netobj_equal(&new->handle, &tmp->handle); | 378 | return netobj_equal(&new->handle, &tmp->handle); |
327 | } | 379 | } |
328 | 380 | ||
329 | static inline void | 381 | static void |
330 | rsc_init(struct rsc *new, struct rsc *tmp) | 382 | rsc_init(struct cache_head *cnew, struct cache_head *ctmp) |
331 | { | 383 | { |
384 | struct rsc *new = container_of(cnew, struct rsc, h); | ||
385 | struct rsc *tmp = container_of(ctmp, struct rsc, h); | ||
386 | |||
332 | new->handle.len = tmp->handle.len; | 387 | new->handle.len = tmp->handle.len; |
333 | tmp->handle.len = 0; | 388 | tmp->handle.len = 0; |
334 | new->handle.data = tmp->handle.data; | 389 | new->handle.data = tmp->handle.data; |
@@ -337,9 +392,12 @@ rsc_init(struct rsc *new, struct rsc *tmp) | |||
337 | new->cred.cr_group_info = NULL; | 392 | new->cred.cr_group_info = NULL; |
338 | } | 393 | } |
339 | 394 | ||
340 | static inline void | 395 | static void |
341 | rsc_update(struct rsc *new, struct rsc *tmp) | 396 | update_rsc(struct cache_head *cnew, struct cache_head *ctmp) |
342 | { | 397 | { |
398 | struct rsc *new = container_of(cnew, struct rsc, h); | ||
399 | struct rsc *tmp = container_of(ctmp, struct rsc, h); | ||
400 | |||
343 | new->mechctx = tmp->mechctx; | 401 | new->mechctx = tmp->mechctx; |
344 | tmp->mechctx = NULL; | 402 | tmp->mechctx = NULL; |
345 | memset(&new->seqdata, 0, sizeof(new->seqdata)); | 403 | memset(&new->seqdata, 0, sizeof(new->seqdata)); |
@@ -348,6 +406,16 @@ rsc_update(struct rsc *new, struct rsc *tmp) | |||
348 | tmp->cred.cr_group_info = NULL; | 406 | tmp->cred.cr_group_info = NULL; |
349 | } | 407 | } |
350 | 408 | ||
409 | static struct cache_head * | ||
410 | rsc_alloc(void) | ||
411 | { | ||
412 | struct rsc *rsci = kmalloc(sizeof(*rsci), GFP_KERNEL); | ||
413 | if (rsci) | ||
414 | return &rsci->h; | ||
415 | else | ||
416 | return NULL; | ||
417 | } | ||
418 | |||
351 | static int rsc_parse(struct cache_detail *cd, | 419 | static int rsc_parse(struct cache_detail *cd, |
352 | char *mesg, int mlen) | 420 | char *mesg, int mlen) |
353 | { | 421 | { |
@@ -373,6 +441,10 @@ static int rsc_parse(struct cache_detail *cd, | |||
373 | if (expiry == 0) | 441 | if (expiry == 0) |
374 | goto out; | 442 | goto out; |
375 | 443 | ||
444 | rscp = rsc_lookup(&rsci); | ||
445 | if (!rscp) | ||
446 | goto out; | ||
447 | |||
376 | /* uid, or NEGATIVE */ | 448 | /* uid, or NEGATIVE */ |
377 | rv = get_int(&mesg, &rsci.cred.cr_uid); | 449 | rv = get_int(&mesg, &rsci.cred.cr_uid); |
378 | if (rv == -EINVAL) | 450 | if (rv == -EINVAL) |
@@ -428,12 +500,14 @@ static int rsc_parse(struct cache_detail *cd, | |||
428 | gss_mech_put(gm); | 500 | gss_mech_put(gm); |
429 | } | 501 | } |
430 | rsci.h.expiry_time = expiry; | 502 | rsci.h.expiry_time = expiry; |
431 | rscp = rsc_lookup(&rsci, 1); | 503 | rscp = rsc_update(&rsci, rscp); |
432 | status = 0; | 504 | status = 0; |
433 | out: | 505 | out: |
434 | rsc_free(&rsci); | 506 | rsc_free(&rsci); |
435 | if (rscp) | 507 | if (rscp) |
436 | rsc_put(&rscp->h, &rsc_cache); | 508 | cache_put(&rscp->h, &rsc_cache); |
509 | else | ||
510 | status = -ENOMEM; | ||
437 | return status; | 511 | return status; |
438 | } | 512 | } |
439 | 513 | ||
@@ -444,9 +518,37 @@ static struct cache_detail rsc_cache = { | |||
444 | .name = "auth.rpcsec.context", | 518 | .name = "auth.rpcsec.context", |
445 | .cache_put = rsc_put, | 519 | .cache_put = rsc_put, |
446 | .cache_parse = rsc_parse, | 520 | .cache_parse = rsc_parse, |
521 | .match = rsc_match, | ||
522 | .init = rsc_init, | ||
523 | .update = update_rsc, | ||
524 | .alloc = rsc_alloc, | ||
447 | }; | 525 | }; |
448 | 526 | ||
449 | static DefineSimpleCacheLookup(rsc, 0); | 527 | static struct rsc *rsc_lookup(struct rsc *item) |
528 | { | ||
529 | struct cache_head *ch; | ||
530 | int hash = rsc_hash(item); | ||
531 | |||
532 | ch = sunrpc_cache_lookup(&rsc_cache, &item->h, hash); | ||
533 | if (ch) | ||
534 | return container_of(ch, struct rsc, h); | ||
535 | else | ||
536 | return NULL; | ||
537 | } | ||
538 | |||
539 | static struct rsc *rsc_update(struct rsc *new, struct rsc *old) | ||
540 | { | ||
541 | struct cache_head *ch; | ||
542 | int hash = rsc_hash(new); | ||
543 | |||
544 | ch = sunrpc_cache_update(&rsc_cache, &new->h, | ||
545 | &old->h, hash); | ||
546 | if (ch) | ||
547 | return container_of(ch, struct rsc, h); | ||
548 | else | ||
549 | return NULL; | ||
550 | } | ||
551 | |||
450 | 552 | ||
451 | static struct rsc * | 553 | static struct rsc * |
452 | gss_svc_searchbyctx(struct xdr_netobj *handle) | 554 | gss_svc_searchbyctx(struct xdr_netobj *handle) |
@@ -457,7 +559,7 @@ gss_svc_searchbyctx(struct xdr_netobj *handle) | |||
457 | memset(&rsci, 0, sizeof(rsci)); | 559 | memset(&rsci, 0, sizeof(rsci)); |
458 | if (dup_to_netobj(&rsci.handle, handle->data, handle->len)) | 560 | if (dup_to_netobj(&rsci.handle, handle->data, handle->len)) |
459 | return NULL; | 561 | return NULL; |
460 | found = rsc_lookup(&rsci, 0); | 562 | found = rsc_lookup(&rsci); |
461 | rsc_free(&rsci); | 563 | rsc_free(&rsci); |
462 | if (!found) | 564 | if (!found) |
463 | return NULL; | 565 | return NULL; |
@@ -645,6 +747,8 @@ find_gss_auth_domain(struct gss_ctx *ctx, u32 svc) | |||
645 | return auth_domain_find(name); | 747 | return auth_domain_find(name); |
646 | } | 748 | } |
647 | 749 | ||
750 | static struct auth_ops svcauthops_gss; | ||
751 | |||
648 | int | 752 | int |
649 | svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name) | 753 | svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name) |
650 | { | 754 | { |
@@ -655,20 +759,18 @@ svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name) | |||
655 | new = kmalloc(sizeof(*new), GFP_KERNEL); | 759 | new = kmalloc(sizeof(*new), GFP_KERNEL); |
656 | if (!new) | 760 | if (!new) |
657 | goto out; | 761 | goto out; |
658 | cache_init(&new->h.h); | 762 | kref_init(&new->h.ref); |
659 | new->h.name = kmalloc(strlen(name) + 1, GFP_KERNEL); | 763 | new->h.name = kmalloc(strlen(name) + 1, GFP_KERNEL); |
660 | if (!new->h.name) | 764 | if (!new->h.name) |
661 | goto out_free_dom; | 765 | goto out_free_dom; |
662 | strcpy(new->h.name, name); | 766 | strcpy(new->h.name, name); |
663 | new->h.flavour = RPC_AUTH_GSS; | 767 | new->h.flavour = &svcauthops_gss; |
664 | new->pseudoflavor = pseudoflavor; | 768 | new->pseudoflavor = pseudoflavor; |
665 | new->h.h.expiry_time = NEVER; | ||
666 | 769 | ||
667 | test = auth_domain_lookup(&new->h, 1); | 770 | test = auth_domain_lookup(name, &new->h); |
668 | if (test == &new->h) { | 771 | if (test != &new->h) { /* XXX Duplicate registration? */ |
669 | BUG_ON(atomic_dec_and_test(&new->h.h.refcnt)); | ||
670 | } else { /* XXX Duplicate registration? */ | ||
671 | auth_domain_put(&new->h); | 772 | auth_domain_put(&new->h); |
773 | /* dangling ref-count... */ | ||
672 | goto out; | 774 | goto out; |
673 | } | 775 | } |
674 | return 0; | 776 | return 0; |
@@ -895,7 +997,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp) | |||
895 | goto drop; | 997 | goto drop; |
896 | } | 998 | } |
897 | 999 | ||
898 | rsip = rsi_lookup(&rsikey, 0); | 1000 | rsip = rsi_lookup(&rsikey); |
899 | rsi_free(&rsikey); | 1001 | rsi_free(&rsikey); |
900 | if (!rsip) { | 1002 | if (!rsip) { |
901 | goto drop; | 1003 | goto drop; |
@@ -970,7 +1072,7 @@ drop: | |||
970 | ret = SVC_DROP; | 1072 | ret = SVC_DROP; |
971 | out: | 1073 | out: |
972 | if (rsci) | 1074 | if (rsci) |
973 | rsc_put(&rsci->h, &rsc_cache); | 1075 | cache_put(&rsci->h, &rsc_cache); |
974 | return ret; | 1076 | return ret; |
975 | } | 1077 | } |
976 | 1078 | ||
@@ -1062,7 +1164,7 @@ out_err: | |||
1062 | put_group_info(rqstp->rq_cred.cr_group_info); | 1164 | put_group_info(rqstp->rq_cred.cr_group_info); |
1063 | rqstp->rq_cred.cr_group_info = NULL; | 1165 | rqstp->rq_cred.cr_group_info = NULL; |
1064 | if (gsd->rsci) | 1166 | if (gsd->rsci) |
1065 | rsc_put(&gsd->rsci->h, &rsc_cache); | 1167 | cache_put(&gsd->rsci->h, &rsc_cache); |
1066 | gsd->rsci = NULL; | 1168 | gsd->rsci = NULL; |
1067 | 1169 | ||
1068 | return stat; | 1170 | return stat; |
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 0acccfeeb284..3ac4193a78ed 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
@@ -37,16 +37,138 @@ | |||
37 | static void cache_defer_req(struct cache_req *req, struct cache_head *item); | 37 | static void cache_defer_req(struct cache_req *req, struct cache_head *item); |
38 | static void cache_revisit_request(struct cache_head *item); | 38 | static void cache_revisit_request(struct cache_head *item); |
39 | 39 | ||
40 | void cache_init(struct cache_head *h) | 40 | static void cache_init(struct cache_head *h) |
41 | { | 41 | { |
42 | time_t now = get_seconds(); | 42 | time_t now = get_seconds(); |
43 | h->next = NULL; | 43 | h->next = NULL; |
44 | h->flags = 0; | 44 | h->flags = 0; |
45 | atomic_set(&h->refcnt, 1); | 45 | kref_init(&h->ref); |
46 | h->expiry_time = now + CACHE_NEW_EXPIRY; | 46 | h->expiry_time = now + CACHE_NEW_EXPIRY; |
47 | h->last_refresh = now; | 47 | h->last_refresh = now; |
48 | } | 48 | } |
49 | 49 | ||
50 | struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail, | ||
51 | struct cache_head *key, int hash) | ||
52 | { | ||
53 | struct cache_head **head, **hp; | ||
54 | struct cache_head *new = NULL; | ||
55 | |||
56 | head = &detail->hash_table[hash]; | ||
57 | |||
58 | read_lock(&detail->hash_lock); | ||
59 | |||
60 | for (hp=head; *hp != NULL ; hp = &(*hp)->next) { | ||
61 | struct cache_head *tmp = *hp; | ||
62 | if (detail->match(tmp, key)) { | ||
63 | cache_get(tmp); | ||
64 | read_unlock(&detail->hash_lock); | ||
65 | return tmp; | ||
66 | } | ||
67 | } | ||
68 | read_unlock(&detail->hash_lock); | ||
69 | /* Didn't find anything, insert an empty entry */ | ||
70 | |||
71 | new = detail->alloc(); | ||
72 | if (!new) | ||
73 | return NULL; | ||
74 | cache_init(new); | ||
75 | |||
76 | write_lock(&detail->hash_lock); | ||
77 | |||
78 | /* check if entry appeared while we slept */ | ||
79 | for (hp=head; *hp != NULL ; hp = &(*hp)->next) { | ||
80 | struct cache_head *tmp = *hp; | ||
81 | if (detail->match(tmp, key)) { | ||
82 | cache_get(tmp); | ||
83 | write_unlock(&detail->hash_lock); | ||
84 | cache_put(new, detail); | ||
85 | return tmp; | ||
86 | } | ||
87 | } | ||
88 | detail->init(new, key); | ||
89 | new->next = *head; | ||
90 | *head = new; | ||
91 | detail->entries++; | ||
92 | cache_get(new); | ||
93 | write_unlock(&detail->hash_lock); | ||
94 | |||
95 | return new; | ||
96 | } | ||
97 | EXPORT_SYMBOL(sunrpc_cache_lookup); | ||
98 | |||
99 | |||
100 | static void queue_loose(struct cache_detail *detail, struct cache_head *ch); | ||
101 | |||
102 | static int cache_fresh_locked(struct cache_head *head, time_t expiry) | ||
103 | { | ||
104 | head->expiry_time = expiry; | ||
105 | head->last_refresh = get_seconds(); | ||
106 | return !test_and_set_bit(CACHE_VALID, &head->flags); | ||
107 | } | ||
108 | |||
109 | static void cache_fresh_unlocked(struct cache_head *head, | ||
110 | struct cache_detail *detail, int new) | ||
111 | { | ||
112 | if (new) | ||
113 | cache_revisit_request(head); | ||
114 | if (test_and_clear_bit(CACHE_PENDING, &head->flags)) { | ||
115 | cache_revisit_request(head); | ||
116 | queue_loose(detail, head); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | struct cache_head *sunrpc_cache_update(struct cache_detail *detail, | ||
121 | struct cache_head *new, struct cache_head *old, int hash) | ||
122 | { | ||
123 | /* The 'old' entry is to be replaced by 'new'. | ||
124 | * If 'old' is not VALID, we update it directly, | ||
125 | * otherwise we need to replace it | ||
126 | */ | ||
127 | struct cache_head **head; | ||
128 | struct cache_head *tmp; | ||
129 | int is_new; | ||
130 | |||
131 | if (!test_bit(CACHE_VALID, &old->flags)) { | ||
132 | write_lock(&detail->hash_lock); | ||
133 | if (!test_bit(CACHE_VALID, &old->flags)) { | ||
134 | if (test_bit(CACHE_NEGATIVE, &new->flags)) | ||
135 | set_bit(CACHE_NEGATIVE, &old->flags); | ||
136 | else | ||
137 | detail->update(old, new); | ||
138 | is_new = cache_fresh_locked(old, new->expiry_time); | ||
139 | write_unlock(&detail->hash_lock); | ||
140 | cache_fresh_unlocked(old, detail, is_new); | ||
141 | return old; | ||
142 | } | ||
143 | write_unlock(&detail->hash_lock); | ||
144 | } | ||
145 | /* We need to insert a new entry */ | ||
146 | tmp = detail->alloc(); | ||
147 | if (!tmp) { | ||
148 | cache_put(old, detail); | ||
149 | return NULL; | ||
150 | } | ||
151 | cache_init(tmp); | ||
152 | detail->init(tmp, old); | ||
153 | head = &detail->hash_table[hash]; | ||
154 | |||
155 | write_lock(&detail->hash_lock); | ||
156 | if (test_bit(CACHE_NEGATIVE, &new->flags)) | ||
157 | set_bit(CACHE_NEGATIVE, &tmp->flags); | ||
158 | else | ||
159 | detail->update(tmp, new); | ||
160 | tmp->next = *head; | ||
161 | *head = tmp; | ||
162 | cache_get(tmp); | ||
163 | is_new = cache_fresh_locked(tmp, new->expiry_time); | ||
164 | cache_fresh_locked(old, 0); | ||
165 | write_unlock(&detail->hash_lock); | ||
166 | cache_fresh_unlocked(tmp, detail, is_new); | ||
167 | cache_fresh_unlocked(old, detail, 0); | ||
168 | cache_put(old, detail); | ||
169 | return tmp; | ||
170 | } | ||
171 | EXPORT_SYMBOL(sunrpc_cache_update); | ||
50 | 172 | ||
51 | static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h); | 173 | static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h); |
52 | /* | 174 | /* |
@@ -94,7 +216,8 @@ int cache_check(struct cache_detail *detail, | |||
94 | clear_bit(CACHE_PENDING, &h->flags); | 216 | clear_bit(CACHE_PENDING, &h->flags); |
95 | if (rv == -EAGAIN) { | 217 | if (rv == -EAGAIN) { |
96 | set_bit(CACHE_NEGATIVE, &h->flags); | 218 | set_bit(CACHE_NEGATIVE, &h->flags); |
97 | cache_fresh(detail, h, get_seconds()+CACHE_NEW_EXPIRY); | 219 | cache_fresh_unlocked(h, detail, |
220 | cache_fresh_locked(h, get_seconds()+CACHE_NEW_EXPIRY)); | ||
98 | rv = -ENOENT; | 221 | rv = -ENOENT; |
99 | } | 222 | } |
100 | break; | 223 | break; |
@@ -110,25 +233,11 @@ int cache_check(struct cache_detail *detail, | |||
110 | if (rv == -EAGAIN) | 233 | if (rv == -EAGAIN) |
111 | cache_defer_req(rqstp, h); | 234 | cache_defer_req(rqstp, h); |
112 | 235 | ||
113 | if (rv && h) | 236 | if (rv) |
114 | detail->cache_put(h, detail); | 237 | cache_put(h, detail); |
115 | return rv; | 238 | return rv; |
116 | } | 239 | } |
117 | 240 | ||
118 | static void queue_loose(struct cache_detail *detail, struct cache_head *ch); | ||
119 | |||
120 | void cache_fresh(struct cache_detail *detail, | ||
121 | struct cache_head *head, time_t expiry) | ||
122 | { | ||
123 | |||
124 | head->expiry_time = expiry; | ||
125 | head->last_refresh = get_seconds(); | ||
126 | if (!test_and_set_bit(CACHE_VALID, &head->flags)) | ||
127 | cache_revisit_request(head); | ||
128 | if (test_and_clear_bit(CACHE_PENDING, &head->flags)) | ||
129 | queue_loose(detail, head); | ||
130 | } | ||
131 | |||
132 | /* | 241 | /* |
133 | * caches need to be periodically cleaned. | 242 | * caches need to be periodically cleaned. |
134 | * For this we maintain a list of cache_detail and | 243 | * For this we maintain a list of cache_detail and |
@@ -322,7 +431,7 @@ static int cache_clean(void) | |||
322 | if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) | 431 | if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) |
323 | queue_loose(current_detail, ch); | 432 | queue_loose(current_detail, ch); |
324 | 433 | ||
325 | if (atomic_read(&ch->refcnt) == 1) | 434 | if (atomic_read(&ch->ref.refcount) == 1) |
326 | break; | 435 | break; |
327 | } | 436 | } |
328 | if (ch) { | 437 | if (ch) { |
@@ -337,7 +446,7 @@ static int cache_clean(void) | |||
337 | current_index ++; | 446 | current_index ++; |
338 | spin_unlock(&cache_list_lock); | 447 | spin_unlock(&cache_list_lock); |
339 | if (ch) | 448 | if (ch) |
340 | d->cache_put(ch, d); | 449 | cache_put(ch, d); |
341 | } else | 450 | } else |
342 | spin_unlock(&cache_list_lock); | 451 | spin_unlock(&cache_list_lock); |
343 | 452 | ||
@@ -453,7 +562,7 @@ static void cache_defer_req(struct cache_req *req, struct cache_head *item) | |||
453 | /* there was one too many */ | 562 | /* there was one too many */ |
454 | dreq->revisit(dreq, 1); | 563 | dreq->revisit(dreq, 1); |
455 | } | 564 | } |
456 | if (test_bit(CACHE_VALID, &item->flags)) { | 565 | if (!test_bit(CACHE_PENDING, &item->flags)) { |
457 | /* must have just been validated... */ | 566 | /* must have just been validated... */ |
458 | cache_revisit_request(item); | 567 | cache_revisit_request(item); |
459 | } | 568 | } |
@@ -614,7 +723,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) | |||
614 | !test_bit(CACHE_PENDING, &rq->item->flags)) { | 723 | !test_bit(CACHE_PENDING, &rq->item->flags)) { |
615 | list_del(&rq->q.list); | 724 | list_del(&rq->q.list); |
616 | spin_unlock(&queue_lock); | 725 | spin_unlock(&queue_lock); |
617 | cd->cache_put(rq->item, cd); | 726 | cache_put(rq->item, cd); |
618 | kfree(rq->buf); | 727 | kfree(rq->buf); |
619 | kfree(rq); | 728 | kfree(rq); |
620 | } else | 729 | } else |
@@ -794,10 +903,10 @@ static void queue_loose(struct cache_detail *detail, struct cache_head *ch) | |||
794 | if (cr->item != ch) | 903 | if (cr->item != ch) |
795 | continue; | 904 | continue; |
796 | if (cr->readers != 0) | 905 | if (cr->readers != 0) |
797 | break; | 906 | continue; |
798 | list_del(&cr->q.list); | 907 | list_del(&cr->q.list); |
799 | spin_unlock(&queue_lock); | 908 | spin_unlock(&queue_lock); |
800 | detail->cache_put(cr->item, detail); | 909 | cache_put(cr->item, detail); |
801 | kfree(cr->buf); | 910 | kfree(cr->buf); |
802 | kfree(cr); | 911 | kfree(cr); |
803 | return; | 912 | return; |
@@ -1082,8 +1191,8 @@ static int c_show(struct seq_file *m, void *p) | |||
1082 | return cd->cache_show(m, cd, NULL); | 1191 | return cd->cache_show(m, cd, NULL); |
1083 | 1192 | ||
1084 | ifdebug(CACHE) | 1193 | ifdebug(CACHE) |
1085 | seq_printf(m, "# expiry=%ld refcnt=%d\n", | 1194 | seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx\n", |
1086 | cp->expiry_time, atomic_read(&cp->refcnt)); | 1195 | cp->expiry_time, atomic_read(&cp->ref.refcount), cp->flags); |
1087 | cache_get(cp); | 1196 | cache_get(cp); |
1088 | if (cache_check(cd, cp, NULL)) | 1197 | if (cache_check(cd, cp, NULL)) |
1089 | /* cache_check does a cache_put on failure */ | 1198 | /* cache_check does a cache_put on failure */ |
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 9f7373203592..769114f0f886 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c | |||
@@ -105,8 +105,6 @@ EXPORT_SYMBOL(auth_unix_lookup); | |||
105 | EXPORT_SYMBOL(cache_check); | 105 | EXPORT_SYMBOL(cache_check); |
106 | EXPORT_SYMBOL(cache_flush); | 106 | EXPORT_SYMBOL(cache_flush); |
107 | EXPORT_SYMBOL(cache_purge); | 107 | EXPORT_SYMBOL(cache_purge); |
108 | EXPORT_SYMBOL(cache_fresh); | ||
109 | EXPORT_SYMBOL(cache_init); | ||
110 | EXPORT_SYMBOL(cache_register); | 108 | EXPORT_SYMBOL(cache_register); |
111 | EXPORT_SYMBOL(cache_unregister); | 109 | EXPORT_SYMBOL(cache_unregister); |
112 | EXPORT_SYMBOL(qword_add); | 110 | EXPORT_SYMBOL(qword_add); |
@@ -142,6 +140,7 @@ EXPORT_SYMBOL(nlm_debug); | |||
142 | 140 | ||
143 | extern int register_rpc_pipefs(void); | 141 | extern int register_rpc_pipefs(void); |
144 | extern void unregister_rpc_pipefs(void); | 142 | extern void unregister_rpc_pipefs(void); |
143 | extern struct cache_detail ip_map_cache; | ||
145 | 144 | ||
146 | static int __init | 145 | static int __init |
147 | init_sunrpc(void) | 146 | init_sunrpc(void) |
@@ -158,7 +157,6 @@ init_sunrpc(void) | |||
158 | #ifdef CONFIG_PROC_FS | 157 | #ifdef CONFIG_PROC_FS |
159 | rpc_proc_init(); | 158 | rpc_proc_init(); |
160 | #endif | 159 | #endif |
161 | cache_register(&auth_domain_cache); | ||
162 | cache_register(&ip_map_cache); | 160 | cache_register(&ip_map_cache); |
163 | out: | 161 | out: |
164 | return err; | 162 | return err; |
@@ -169,8 +167,6 @@ cleanup_sunrpc(void) | |||
169 | { | 167 | { |
170 | unregister_rpc_pipefs(); | 168 | unregister_rpc_pipefs(); |
171 | rpc_destroy_mempool(); | 169 | rpc_destroy_mempool(); |
172 | if (cache_unregister(&auth_domain_cache)) | ||
173 | printk(KERN_ERR "sunrpc: failed to unregister auth_domain cache\n"); | ||
174 | if (cache_unregister(&ip_map_cache)) | 170 | if (cache_unregister(&ip_map_cache)) |
175 | printk(KERN_ERR "sunrpc: failed to unregister ip_map cache\n"); | 171 | printk(KERN_ERR "sunrpc: failed to unregister ip_map cache\n"); |
176 | #ifdef RPC_DEBUG | 172 | #ifdef RPC_DEBUG |
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c index dda4f0c63511..5b28c6176806 100644 --- a/net/sunrpc/svcauth.c +++ b/net/sunrpc/svcauth.c | |||
@@ -106,112 +106,56 @@ svc_auth_unregister(rpc_authflavor_t flavor) | |||
106 | EXPORT_SYMBOL(svc_auth_unregister); | 106 | EXPORT_SYMBOL(svc_auth_unregister); |
107 | 107 | ||
108 | /************************************************** | 108 | /************************************************** |
109 | * cache for domain name to auth_domain | 109 | * 'auth_domains' are stored in a hash table indexed by name. |
110 | * Entries are only added by flavours which will normally | 110 | * When the last reference to an 'auth_domain' is dropped, |
111 | * have a structure that 'inherits' from auth_domain. | 111 | * the object is unhashed and freed. |
112 | * e.g. when an IP -> domainname is given to auth_unix, | 112 | * If auth_domain_lookup fails to find an entry, it will return |
113 | * and the domain name doesn't exist, it will create a | 113 | * it's second argument 'new'. If this is non-null, it will |
114 | * auth_unix_domain and add it to this hash table. | 114 | * have been atomically linked into the table. |
115 | * If it finds the name does exist, but isn't AUTH_UNIX, | ||
116 | * it will complain. | ||
117 | */ | 115 | */ |
118 | 116 | ||
119 | /* | ||
120 | * Auth auth_domain cache is somewhat different to other caches, | ||
121 | * largely because the entries are possibly of different types: | ||
122 | * each auth flavour has it's own type. | ||
123 | * One consequence of this that DefineCacheLookup cannot | ||
124 | * allocate a new structure as it cannot know the size. | ||
125 | * Notice that the "INIT" code fragment is quite different | ||
126 | * from other caches. When auth_domain_lookup might be | ||
127 | * creating a new domain, the new domain is passed in | ||
128 | * complete and it is used as-is rather than being copied into | ||
129 | * another structure. | ||
130 | */ | ||
131 | #define DN_HASHBITS 6 | 117 | #define DN_HASHBITS 6 |
132 | #define DN_HASHMAX (1<<DN_HASHBITS) | 118 | #define DN_HASHMAX (1<<DN_HASHBITS) |
133 | #define DN_HASHMASK (DN_HASHMAX-1) | 119 | #define DN_HASHMASK (DN_HASHMAX-1) |
134 | 120 | ||
135 | static struct cache_head *auth_domain_table[DN_HASHMAX]; | 121 | static struct hlist_head auth_domain_table[DN_HASHMAX]; |
136 | 122 | static spinlock_t auth_domain_lock = SPIN_LOCK_UNLOCKED; | |
137 | static void auth_domain_drop(struct cache_head *item, struct cache_detail *cd) | ||
138 | { | ||
139 | struct auth_domain *dom = container_of(item, struct auth_domain, h); | ||
140 | if (cache_put(item,cd)) | ||
141 | authtab[dom->flavour]->domain_release(dom); | ||
142 | } | ||
143 | |||
144 | |||
145 | struct cache_detail auth_domain_cache = { | ||
146 | .owner = THIS_MODULE, | ||
147 | .hash_size = DN_HASHMAX, | ||
148 | .hash_table = auth_domain_table, | ||
149 | .name = "auth.domain", | ||
150 | .cache_put = auth_domain_drop, | ||
151 | }; | ||
152 | 123 | ||
153 | void auth_domain_put(struct auth_domain *dom) | 124 | void auth_domain_put(struct auth_domain *dom) |
154 | { | 125 | { |
155 | auth_domain_drop(&dom->h, &auth_domain_cache); | 126 | if (atomic_dec_and_lock(&dom->ref.refcount, &auth_domain_lock)) { |
156 | } | 127 | hlist_del(&dom->hash); |
157 | 128 | dom->flavour->domain_release(dom); | |
158 | static inline int auth_domain_hash(struct auth_domain *item) | 129 | } |
159 | { | ||
160 | return hash_str(item->name, DN_HASHBITS); | ||
161 | } | ||
162 | static inline int auth_domain_match(struct auth_domain *tmp, struct auth_domain *item) | ||
163 | { | ||
164 | return strcmp(tmp->name, item->name) == 0; | ||
165 | } | 130 | } |
166 | 131 | ||
167 | struct auth_domain * | 132 | struct auth_domain * |
168 | auth_domain_lookup(struct auth_domain *item, int set) | 133 | auth_domain_lookup(char *name, struct auth_domain *new) |
169 | { | 134 | { |
170 | struct auth_domain *tmp = NULL; | 135 | struct auth_domain *hp; |
171 | struct cache_head **hp, **head; | 136 | struct hlist_head *head; |
172 | head = &auth_domain_cache.hash_table[auth_domain_hash(item)]; | 137 | struct hlist_node *np; |
173 | 138 | ||
174 | if (set) | 139 | head = &auth_domain_table[hash_str(name, DN_HASHBITS)]; |
175 | write_lock(&auth_domain_cache.hash_lock); | 140 | |
176 | else | 141 | spin_lock(&auth_domain_lock); |
177 | read_lock(&auth_domain_cache.hash_lock); | 142 | |
178 | for (hp=head; *hp != NULL; hp = &tmp->h.next) { | 143 | hlist_for_each_entry(hp, np, head, hash) { |
179 | tmp = container_of(*hp, struct auth_domain, h); | 144 | if (strcmp(hp->name, name)==0) { |
180 | if (!auth_domain_match(tmp, item)) | 145 | kref_get(&hp->ref); |
181 | continue; | 146 | spin_unlock(&auth_domain_lock); |
182 | if (!set) { | 147 | return hp; |
183 | cache_get(&tmp->h); | ||
184 | goto out_noset; | ||
185 | } | 148 | } |
186 | *hp = tmp->h.next; | ||
187 | tmp->h.next = NULL; | ||
188 | auth_domain_drop(&tmp->h, &auth_domain_cache); | ||
189 | goto out_set; | ||
190 | } | 149 | } |
191 | /* Didn't find anything */ | 150 | if (new) { |
192 | if (!set) | 151 | hlist_add_head(&new->hash, head); |
193 | goto out_nada; | 152 | kref_get(&new->ref); |
194 | auth_domain_cache.entries++; | 153 | } |
195 | out_set: | 154 | spin_unlock(&auth_domain_lock); |
196 | item->h.next = *head; | 155 | return new; |
197 | *head = &item->h; | ||
198 | cache_get(&item->h); | ||
199 | write_unlock(&auth_domain_cache.hash_lock); | ||
200 | cache_fresh(&auth_domain_cache, &item->h, item->h.expiry_time); | ||
201 | cache_get(&item->h); | ||
202 | return item; | ||
203 | out_nada: | ||
204 | tmp = NULL; | ||
205 | out_noset: | ||
206 | read_unlock(&auth_domain_cache.hash_lock); | ||
207 | return tmp; | ||
208 | } | 156 | } |
209 | 157 | ||
210 | struct auth_domain *auth_domain_find(char *name) | 158 | struct auth_domain *auth_domain_find(char *name) |
211 | { | 159 | { |
212 | struct auth_domain *rv, ad; | 160 | return auth_domain_lookup(name, NULL); |
213 | |||
214 | ad.name = name; | ||
215 | rv = auth_domain_lookup(&ad, 0); | ||
216 | return rv; | ||
217 | } | 161 | } |
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 3e6c694bbad1..7e5707e2d6b6 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c | |||
@@ -27,41 +27,35 @@ struct unix_domain { | |||
27 | /* other stuff later */ | 27 | /* other stuff later */ |
28 | }; | 28 | }; |
29 | 29 | ||
30 | extern struct auth_ops svcauth_unix; | ||
31 | |||
30 | struct auth_domain *unix_domain_find(char *name) | 32 | struct auth_domain *unix_domain_find(char *name) |
31 | { | 33 | { |
32 | struct auth_domain *rv, ud; | 34 | struct auth_domain *rv; |
33 | struct unix_domain *new; | 35 | struct unix_domain *new = NULL; |
34 | 36 | ||
35 | ud.name = name; | 37 | rv = auth_domain_lookup(name, NULL); |
36 | 38 | while(1) { | |
37 | rv = auth_domain_lookup(&ud, 0); | 39 | if (rv) { |
38 | 40 | if (new && rv != &new->h) | |
39 | foundit: | 41 | auth_domain_put(&new->h); |
40 | if (rv && rv->flavour != RPC_AUTH_UNIX) { | 42 | |
41 | auth_domain_put(rv); | 43 | if (rv->flavour != &svcauth_unix) { |
42 | return NULL; | 44 | auth_domain_put(rv); |
43 | } | 45 | return NULL; |
44 | if (rv) | 46 | } |
45 | return rv; | 47 | return rv; |
46 | 48 | } | |
47 | new = kmalloc(sizeof(*new), GFP_KERNEL); | 49 | |
48 | if (new == NULL) | 50 | new = kmalloc(sizeof(*new), GFP_KERNEL); |
49 | return NULL; | 51 | if (new == NULL) |
50 | cache_init(&new->h.h); | 52 | return NULL; |
51 | new->h.name = kstrdup(name, GFP_KERNEL); | 53 | kref_init(&new->h.ref); |
52 | new->h.flavour = RPC_AUTH_UNIX; | 54 | new->h.name = kstrdup(name, GFP_KERNEL); |
53 | new->addr_changes = 0; | 55 | new->h.flavour = &svcauth_unix; |
54 | new->h.h.expiry_time = NEVER; | 56 | new->addr_changes = 0; |
55 | 57 | rv = auth_domain_lookup(name, &new->h); | |
56 | rv = auth_domain_lookup(&new->h, 2); | ||
57 | if (rv == &new->h) { | ||
58 | if (atomic_dec_and_test(&new->h.h.refcnt)) BUG(); | ||
59 | } else { | ||
60 | auth_domain_put(&new->h); | ||
61 | goto foundit; | ||
62 | } | 58 | } |
63 | |||
64 | return rv; | ||
65 | } | 59 | } |
66 | 60 | ||
67 | static void svcauth_unix_domain_release(struct auth_domain *dom) | 61 | static void svcauth_unix_domain_release(struct auth_domain *dom) |
@@ -90,15 +84,15 @@ struct ip_map { | |||
90 | }; | 84 | }; |
91 | static struct cache_head *ip_table[IP_HASHMAX]; | 85 | static struct cache_head *ip_table[IP_HASHMAX]; |
92 | 86 | ||
93 | static void ip_map_put(struct cache_head *item, struct cache_detail *cd) | 87 | static void ip_map_put(struct kref *kref) |
94 | { | 88 | { |
89 | struct cache_head *item = container_of(kref, struct cache_head, ref); | ||
95 | struct ip_map *im = container_of(item, struct ip_map,h); | 90 | struct ip_map *im = container_of(item, struct ip_map,h); |
96 | if (cache_put(item, cd)) { | 91 | |
97 | if (test_bit(CACHE_VALID, &item->flags) && | 92 | if (test_bit(CACHE_VALID, &item->flags) && |
98 | !test_bit(CACHE_NEGATIVE, &item->flags)) | 93 | !test_bit(CACHE_NEGATIVE, &item->flags)) |
99 | auth_domain_put(&im->m_client->h); | 94 | auth_domain_put(&im->m_client->h); |
100 | kfree(im); | 95 | kfree(im); |
101 | } | ||
102 | } | 96 | } |
103 | 97 | ||
104 | #if IP_HASHBITS == 8 | 98 | #if IP_HASHBITS == 8 |
@@ -112,28 +106,38 @@ static inline int hash_ip(unsigned long ip) | |||
112 | return (hash ^ (hash>>8)) & 0xff; | 106 | return (hash ^ (hash>>8)) & 0xff; |
113 | } | 107 | } |
114 | #endif | 108 | #endif |
115 | 109 | static int ip_map_match(struct cache_head *corig, struct cache_head *cnew) | |
116 | static inline int ip_map_hash(struct ip_map *item) | ||
117 | { | ||
118 | return hash_str(item->m_class, IP_HASHBITS) ^ | ||
119 | hash_ip((unsigned long)item->m_addr.s_addr); | ||
120 | } | ||
121 | static inline int ip_map_match(struct ip_map *item, struct ip_map *tmp) | ||
122 | { | 110 | { |
123 | return strcmp(tmp->m_class, item->m_class) == 0 | 111 | struct ip_map *orig = container_of(corig, struct ip_map, h); |
124 | && tmp->m_addr.s_addr == item->m_addr.s_addr; | 112 | struct ip_map *new = container_of(cnew, struct ip_map, h); |
113 | return strcmp(orig->m_class, new->m_class) == 0 | ||
114 | && orig->m_addr.s_addr == new->m_addr.s_addr; | ||
125 | } | 115 | } |
126 | static inline void ip_map_init(struct ip_map *new, struct ip_map *item) | 116 | static void ip_map_init(struct cache_head *cnew, struct cache_head *citem) |
127 | { | 117 | { |
118 | struct ip_map *new = container_of(cnew, struct ip_map, h); | ||
119 | struct ip_map *item = container_of(citem, struct ip_map, h); | ||
120 | |||
128 | strcpy(new->m_class, item->m_class); | 121 | strcpy(new->m_class, item->m_class); |
129 | new->m_addr.s_addr = item->m_addr.s_addr; | 122 | new->m_addr.s_addr = item->m_addr.s_addr; |
130 | } | 123 | } |
131 | static inline void ip_map_update(struct ip_map *new, struct ip_map *item) | 124 | static void update(struct cache_head *cnew, struct cache_head *citem) |
132 | { | 125 | { |
133 | cache_get(&item->m_client->h.h); | 126 | struct ip_map *new = container_of(cnew, struct ip_map, h); |
127 | struct ip_map *item = container_of(citem, struct ip_map, h); | ||
128 | |||
129 | kref_get(&item->m_client->h.ref); | ||
134 | new->m_client = item->m_client; | 130 | new->m_client = item->m_client; |
135 | new->m_add_change = item->m_add_change; | 131 | new->m_add_change = item->m_add_change; |
136 | } | 132 | } |
133 | static struct cache_head *ip_map_alloc(void) | ||
134 | { | ||
135 | struct ip_map *i = kmalloc(sizeof(*i), GFP_KERNEL); | ||
136 | if (i) | ||
137 | return &i->h; | ||
138 | else | ||
139 | return NULL; | ||
140 | } | ||
137 | 141 | ||
138 | static void ip_map_request(struct cache_detail *cd, | 142 | static void ip_map_request(struct cache_detail *cd, |
139 | struct cache_head *h, | 143 | struct cache_head *h, |
@@ -154,7 +158,8 @@ static void ip_map_request(struct cache_detail *cd, | |||
154 | (*bpp)[-1] = '\n'; | 158 | (*bpp)[-1] = '\n'; |
155 | } | 159 | } |
156 | 160 | ||
157 | static struct ip_map *ip_map_lookup(struct ip_map *, int); | 161 | static struct ip_map *ip_map_lookup(char *class, struct in_addr addr); |
162 | static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry); | ||
158 | 163 | ||
159 | static int ip_map_parse(struct cache_detail *cd, | 164 | static int ip_map_parse(struct cache_detail *cd, |
160 | char *mesg, int mlen) | 165 | char *mesg, int mlen) |
@@ -166,7 +171,11 @@ static int ip_map_parse(struct cache_detail *cd, | |||
166 | int len; | 171 | int len; |
167 | int b1,b2,b3,b4; | 172 | int b1,b2,b3,b4; |
168 | char c; | 173 | char c; |
169 | struct ip_map ipm, *ipmp; | 174 | char class[8]; |
175 | struct in_addr addr; | ||
176 | int err; | ||
177 | |||
178 | struct ip_map *ipmp; | ||
170 | struct auth_domain *dom; | 179 | struct auth_domain *dom; |
171 | time_t expiry; | 180 | time_t expiry; |
172 | 181 | ||
@@ -175,7 +184,7 @@ static int ip_map_parse(struct cache_detail *cd, | |||
175 | mesg[mlen-1] = 0; | 184 | mesg[mlen-1] = 0; |
176 | 185 | ||
177 | /* class */ | 186 | /* class */ |
178 | len = qword_get(&mesg, ipm.m_class, sizeof(ipm.m_class)); | 187 | len = qword_get(&mesg, class, sizeof(class)); |
179 | if (len <= 0) return -EINVAL; | 188 | if (len <= 0) return -EINVAL; |
180 | 189 | ||
181 | /* ip address */ | 190 | /* ip address */ |
@@ -200,25 +209,22 @@ static int ip_map_parse(struct cache_detail *cd, | |||
200 | } else | 209 | } else |
201 | dom = NULL; | 210 | dom = NULL; |
202 | 211 | ||
203 | ipm.m_addr.s_addr = | 212 | addr.s_addr = |
204 | htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4); | 213 | htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4); |
205 | ipm.h.flags = 0; | 214 | |
206 | if (dom) { | 215 | ipmp = ip_map_lookup(class,addr); |
207 | ipm.m_client = container_of(dom, struct unix_domain, h); | 216 | if (ipmp) { |
208 | ipm.m_add_change = ipm.m_client->addr_changes; | 217 | err = ip_map_update(ipmp, |
218 | container_of(dom, struct unix_domain, h), | ||
219 | expiry); | ||
209 | } else | 220 | } else |
210 | set_bit(CACHE_NEGATIVE, &ipm.h.flags); | 221 | err = -ENOMEM; |
211 | ipm.h.expiry_time = expiry; | ||
212 | 222 | ||
213 | ipmp = ip_map_lookup(&ipm, 1); | ||
214 | if (ipmp) | ||
215 | ip_map_put(&ipmp->h, &ip_map_cache); | ||
216 | if (dom) | 223 | if (dom) |
217 | auth_domain_put(dom); | 224 | auth_domain_put(dom); |
218 | if (!ipmp) | 225 | |
219 | return -ENOMEM; | ||
220 | cache_flush(); | 226 | cache_flush(); |
221 | return 0; | 227 | return err; |
222 | } | 228 | } |
223 | 229 | ||
224 | static int ip_map_show(struct seq_file *m, | 230 | static int ip_map_show(struct seq_file *m, |
@@ -262,32 +268,70 @@ struct cache_detail ip_map_cache = { | |||
262 | .cache_request = ip_map_request, | 268 | .cache_request = ip_map_request, |
263 | .cache_parse = ip_map_parse, | 269 | .cache_parse = ip_map_parse, |
264 | .cache_show = ip_map_show, | 270 | .cache_show = ip_map_show, |
271 | .match = ip_map_match, | ||
272 | .init = ip_map_init, | ||
273 | .update = update, | ||
274 | .alloc = ip_map_alloc, | ||
265 | }; | 275 | }; |
266 | 276 | ||
267 | static DefineSimpleCacheLookup(ip_map, 0) | 277 | static struct ip_map *ip_map_lookup(char *class, struct in_addr addr) |
278 | { | ||
279 | struct ip_map ip; | ||
280 | struct cache_head *ch; | ||
281 | |||
282 | strcpy(ip.m_class, class); | ||
283 | ip.m_addr = addr; | ||
284 | ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h, | ||
285 | hash_str(class, IP_HASHBITS) ^ | ||
286 | hash_ip((unsigned long)addr.s_addr)); | ||
287 | |||
288 | if (ch) | ||
289 | return container_of(ch, struct ip_map, h); | ||
290 | else | ||
291 | return NULL; | ||
292 | } | ||
268 | 293 | ||
294 | static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry) | ||
295 | { | ||
296 | struct ip_map ip; | ||
297 | struct cache_head *ch; | ||
298 | |||
299 | ip.m_client = udom; | ||
300 | ip.h.flags = 0; | ||
301 | if (!udom) | ||
302 | set_bit(CACHE_NEGATIVE, &ip.h.flags); | ||
303 | else { | ||
304 | ip.m_add_change = udom->addr_changes; | ||
305 | /* if this is from the legacy set_client system call, | ||
306 | * we need m_add_change to be one higher | ||
307 | */ | ||
308 | if (expiry == NEVER) | ||
309 | ip.m_add_change++; | ||
310 | } | ||
311 | ip.h.expiry_time = expiry; | ||
312 | ch = sunrpc_cache_update(&ip_map_cache, | ||
313 | &ip.h, &ipm->h, | ||
314 | hash_str(ipm->m_class, IP_HASHBITS) ^ | ||
315 | hash_ip((unsigned long)ipm->m_addr.s_addr)); | ||
316 | if (!ch) | ||
317 | return -ENOMEM; | ||
318 | cache_put(ch, &ip_map_cache); | ||
319 | return 0; | ||
320 | } | ||
269 | 321 | ||
270 | int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom) | 322 | int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom) |
271 | { | 323 | { |
272 | struct unix_domain *udom; | 324 | struct unix_domain *udom; |
273 | struct ip_map ip, *ipmp; | 325 | struct ip_map *ipmp; |
274 | 326 | ||
275 | if (dom->flavour != RPC_AUTH_UNIX) | 327 | if (dom->flavour != &svcauth_unix) |
276 | return -EINVAL; | 328 | return -EINVAL; |
277 | udom = container_of(dom, struct unix_domain, h); | 329 | udom = container_of(dom, struct unix_domain, h); |
278 | strcpy(ip.m_class, "nfsd"); | 330 | ipmp = ip_map_lookup("nfsd", addr); |
279 | ip.m_addr = addr; | ||
280 | ip.m_client = udom; | ||
281 | ip.m_add_change = udom->addr_changes+1; | ||
282 | ip.h.flags = 0; | ||
283 | ip.h.expiry_time = NEVER; | ||
284 | |||
285 | ipmp = ip_map_lookup(&ip, 1); | ||
286 | 331 | ||
287 | if (ipmp) { | 332 | if (ipmp) |
288 | ip_map_put(&ipmp->h, &ip_map_cache); | 333 | return ip_map_update(ipmp, udom, NEVER); |
289 | return 0; | 334 | else |
290 | } else | ||
291 | return -ENOMEM; | 335 | return -ENOMEM; |
292 | } | 336 | } |
293 | 337 | ||
@@ -295,7 +339,7 @@ int auth_unix_forget_old(struct auth_domain *dom) | |||
295 | { | 339 | { |
296 | struct unix_domain *udom; | 340 | struct unix_domain *udom; |
297 | 341 | ||
298 | if (dom->flavour != RPC_AUTH_UNIX) | 342 | if (dom->flavour != &svcauth_unix) |
299 | return -EINVAL; | 343 | return -EINVAL; |
300 | udom = container_of(dom, struct unix_domain, h); | 344 | udom = container_of(dom, struct unix_domain, h); |
301 | udom->addr_changes++; | 345 | udom->addr_changes++; |
@@ -310,7 +354,7 @@ struct auth_domain *auth_unix_lookup(struct in_addr addr) | |||
310 | strcpy(key.m_class, "nfsd"); | 354 | strcpy(key.m_class, "nfsd"); |
311 | key.m_addr = addr; | 355 | key.m_addr = addr; |
312 | 356 | ||
313 | ipm = ip_map_lookup(&key, 0); | 357 | ipm = ip_map_lookup("nfsd", addr); |
314 | 358 | ||
315 | if (!ipm) | 359 | if (!ipm) |
316 | return NULL; | 360 | return NULL; |
@@ -323,31 +367,28 @@ struct auth_domain *auth_unix_lookup(struct in_addr addr) | |||
323 | rv = NULL; | 367 | rv = NULL; |
324 | } else { | 368 | } else { |
325 | rv = &ipm->m_client->h; | 369 | rv = &ipm->m_client->h; |
326 | cache_get(&rv->h); | 370 | kref_get(&rv->ref); |
327 | } | 371 | } |
328 | ip_map_put(&ipm->h, &ip_map_cache); | 372 | cache_put(&ipm->h, &ip_map_cache); |
329 | return rv; | 373 | return rv; |
330 | } | 374 | } |
331 | 375 | ||
332 | void svcauth_unix_purge(void) | 376 | void svcauth_unix_purge(void) |
333 | { | 377 | { |
334 | cache_purge(&ip_map_cache); | 378 | cache_purge(&ip_map_cache); |
335 | cache_purge(&auth_domain_cache); | ||
336 | } | 379 | } |
337 | 380 | ||
338 | static int | 381 | static int |
339 | svcauth_unix_set_client(struct svc_rqst *rqstp) | 382 | svcauth_unix_set_client(struct svc_rqst *rqstp) |
340 | { | 383 | { |
341 | struct ip_map key, *ipm; | 384 | struct ip_map *ipm; |
342 | 385 | ||
343 | rqstp->rq_client = NULL; | 386 | rqstp->rq_client = NULL; |
344 | if (rqstp->rq_proc == 0) | 387 | if (rqstp->rq_proc == 0) |
345 | return SVC_OK; | 388 | return SVC_OK; |
346 | 389 | ||
347 | strcpy(key.m_class, rqstp->rq_server->sv_program->pg_class); | 390 | ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class, |
348 | key.m_addr = rqstp->rq_addr.sin_addr; | 391 | rqstp->rq_addr.sin_addr); |
349 | |||
350 | ipm = ip_map_lookup(&key, 0); | ||
351 | 392 | ||
352 | if (ipm == NULL) | 393 | if (ipm == NULL) |
353 | return SVC_DENIED; | 394 | return SVC_DENIED; |
@@ -361,8 +402,8 @@ svcauth_unix_set_client(struct svc_rqst *rqstp) | |||
361 | return SVC_DENIED; | 402 | return SVC_DENIED; |
362 | case 0: | 403 | case 0: |
363 | rqstp->rq_client = &ipm->m_client->h; | 404 | rqstp->rq_client = &ipm->m_client->h; |
364 | cache_get(&rqstp->rq_client->h); | 405 | kref_get(&rqstp->rq_client->ref); |
365 | ip_map_put(&ipm->h, &ip_map_cache); | 406 | cache_put(&ipm->h, &ip_map_cache); |
366 | break; | 407 | break; |
367 | } | 408 | } |
368 | return SVC_OK; | 409 | return SVC_OK; |
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c index 9d10d79e27af..9ea3059a7064 100644 --- a/sound/drivers/mpu401/mpu401.c +++ b/sound/drivers/mpu401/mpu401.c | |||
@@ -59,7 +59,8 @@ module_param_array(irq, int, NULL, 0444); | |||
59 | MODULE_PARM_DESC(irq, "IRQ # for MPU-401 device."); | 59 | MODULE_PARM_DESC(irq, "IRQ # for MPU-401 device."); |
60 | 60 | ||
61 | static struct platform_device *platform_devices[SNDRV_CARDS]; | 61 | static struct platform_device *platform_devices[SNDRV_CARDS]; |
62 | static int pnp_registered = 0; | 62 | static int pnp_registered; |
63 | static unsigned int snd_mpu401_devices; | ||
63 | 64 | ||
64 | static int snd_mpu401_create(int dev, struct snd_card **rcard) | 65 | static int snd_mpu401_create(int dev, struct snd_card **rcard) |
65 | { | 66 | { |
@@ -197,6 +198,7 @@ static int __devinit snd_mpu401_pnp_probe(struct pnp_dev *pnp_dev, | |||
197 | } | 198 | } |
198 | snd_card_set_dev(card, &pnp_dev->dev); | 199 | snd_card_set_dev(card, &pnp_dev->dev); |
199 | pnp_set_drvdata(pnp_dev, card); | 200 | pnp_set_drvdata(pnp_dev, card); |
201 | snd_mpu401_devices++; | ||
200 | ++dev; | 202 | ++dev; |
201 | return 0; | 203 | return 0; |
202 | } | 204 | } |
@@ -234,12 +236,11 @@ static void __init_or_module snd_mpu401_unregister_all(void) | |||
234 | 236 | ||
235 | static int __init alsa_card_mpu401_init(void) | 237 | static int __init alsa_card_mpu401_init(void) |
236 | { | 238 | { |
237 | int i, err, devices; | 239 | int i, err; |
238 | 240 | ||
239 | if ((err = platform_driver_register(&snd_mpu401_driver)) < 0) | 241 | if ((err = platform_driver_register(&snd_mpu401_driver)) < 0) |
240 | return err; | 242 | return err; |
241 | 243 | ||
242 | devices = 0; | ||
243 | for (i = 0; i < SNDRV_CARDS; i++) { | 244 | for (i = 0; i < SNDRV_CARDS; i++) { |
244 | struct platform_device *device; | 245 | struct platform_device *device; |
245 | if (! enable[i]) | 246 | if (! enable[i]) |
@@ -255,14 +256,13 @@ static int __init alsa_card_mpu401_init(void) | |||
255 | goto errout; | 256 | goto errout; |
256 | } | 257 | } |
257 | platform_devices[i] = device; | 258 | platform_devices[i] = device; |
258 | devices++; | 259 | snd_mpu401_devices++; |
259 | } | 260 | } |
260 | if ((err = pnp_register_driver(&snd_mpu401_pnp_driver)) >= 0) { | 261 | err = pnp_register_driver(&snd_mpu401_pnp_driver); |
262 | if (!err) | ||
261 | pnp_registered = 1; | 263 | pnp_registered = 1; |
262 | devices += err; | ||
263 | } | ||
264 | 264 | ||
265 | if (!devices) { | 265 | if (!snd_mpu401_devices) { |
266 | #ifdef MODULE | 266 | #ifdef MODULE |
267 | printk(KERN_ERR "MPU-401 device not found or device busy\n"); | 267 | printk(KERN_ERR "MPU-401 device not found or device busy\n"); |
268 | #endif | 268 | #endif |
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index 7051f7798ed7..31f299aed281 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/sound/isa/ad1816a/ad1816a.c | |||
@@ -262,6 +262,8 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard | |||
262 | return 0; | 262 | return 0; |
263 | } | 263 | } |
264 | 264 | ||
265 | static unsigned int __devinitdata ad1816a_devices; | ||
266 | |||
265 | static int __devinit snd_ad1816a_pnp_detect(struct pnp_card_link *card, | 267 | static int __devinit snd_ad1816a_pnp_detect(struct pnp_card_link *card, |
266 | const struct pnp_card_device_id *id) | 268 | const struct pnp_card_device_id *id) |
267 | { | 269 | { |
@@ -275,6 +277,7 @@ static int __devinit snd_ad1816a_pnp_detect(struct pnp_card_link *card, | |||
275 | if (res < 0) | 277 | if (res < 0) |
276 | return res; | 278 | return res; |
277 | dev++; | 279 | dev++; |
280 | ad1816a_devices++; | ||
278 | return 0; | 281 | return 0; |
279 | } | 282 | } |
280 | return -ENODEV; | 283 | return -ENODEV; |
@@ -297,10 +300,13 @@ static struct pnp_card_driver ad1816a_pnpc_driver = { | |||
297 | 300 | ||
298 | static int __init alsa_card_ad1816a_init(void) | 301 | static int __init alsa_card_ad1816a_init(void) |
299 | { | 302 | { |
300 | int cards; | 303 | int err; |
304 | |||
305 | err = pnp_register_card_driver(&ad1816a_pnpc_driver); | ||
306 | if (err) | ||
307 | return err; | ||
301 | 308 | ||
302 | cards = pnp_register_card_driver(&ad1816a_pnpc_driver); | 309 | if (!ad1816a_devices) { |
303 | if (cards <= 0) { | ||
304 | pnp_unregister_card_driver(&ad1816a_pnpc_driver); | 310 | pnp_unregister_card_driver(&ad1816a_pnpc_driver); |
305 | #ifdef MODULE | 311 | #ifdef MODULE |
306 | printk(KERN_ERR "no AD1816A based soundcards found.\n"); | 312 | printk(KERN_ERR "no AD1816A based soundcards found.\n"); |
diff --git a/sound/isa/als100.c b/sound/isa/als100.c index 9b77c17b3f66..a52bd8a14c9b 100644 --- a/sound/isa/als100.c +++ b/sound/isa/als100.c | |||
@@ -199,7 +199,7 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard, | |||
199 | return 0; | 199 | return 0; |
200 | } | 200 | } |
201 | 201 | ||
202 | static int __init snd_card_als100_probe(int dev, | 202 | static int __devinit snd_card_als100_probe(int dev, |
203 | struct pnp_card_link *pcard, | 203 | struct pnp_card_link *pcard, |
204 | const struct pnp_card_device_id *pid) | 204 | const struct pnp_card_device_id *pid) |
205 | { | 205 | { |
@@ -281,6 +281,8 @@ static int __init snd_card_als100_probe(int dev, | |||
281 | return 0; | 281 | return 0; |
282 | } | 282 | } |
283 | 283 | ||
284 | static unsigned int __devinitdata als100_devices; | ||
285 | |||
284 | static int __devinit snd_als100_pnp_detect(struct pnp_card_link *card, | 286 | static int __devinit snd_als100_pnp_detect(struct pnp_card_link *card, |
285 | const struct pnp_card_device_id *id) | 287 | const struct pnp_card_device_id *id) |
286 | { | 288 | { |
@@ -294,6 +296,7 @@ static int __devinit snd_als100_pnp_detect(struct pnp_card_link *card, | |||
294 | if (res < 0) | 296 | if (res < 0) |
295 | return res; | 297 | return res; |
296 | dev++; | 298 | dev++; |
299 | als100_devices++; | ||
297 | return 0; | 300 | return 0; |
298 | } | 301 | } |
299 | return -ENODEV; | 302 | return -ENODEV; |
@@ -345,10 +348,13 @@ static struct pnp_card_driver als100_pnpc_driver = { | |||
345 | 348 | ||
346 | static int __init alsa_card_als100_init(void) | 349 | static int __init alsa_card_als100_init(void) |
347 | { | 350 | { |
348 | int cards; | 351 | int err; |
352 | |||
353 | err = pnp_register_card_driver(&als100_pnpc_driver); | ||
354 | if (err) | ||
355 | return err; | ||
349 | 356 | ||
350 | cards = pnp_register_card_driver(&als100_pnpc_driver); | 357 | if (!als100_devices) { |
351 | if (cards <= 0) { | ||
352 | pnp_unregister_card_driver(&als100_pnpc_driver); | 358 | pnp_unregister_card_driver(&als100_pnpc_driver); |
353 | #ifdef MODULE | 359 | #ifdef MODULE |
354 | snd_printk(KERN_ERR "no ALS100 based soundcards found\n"); | 360 | snd_printk(KERN_ERR "no ALS100 based soundcards found\n"); |
diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c index a530691bf4f7..15e59283aac6 100644 --- a/sound/isa/azt2320.c +++ b/sound/isa/azt2320.c | |||
@@ -310,6 +310,8 @@ static int __devinit snd_card_azt2320_probe(int dev, | |||
310 | return 0; | 310 | return 0; |
311 | } | 311 | } |
312 | 312 | ||
313 | static unsigned int __devinitdata azt2320_devices; | ||
314 | |||
313 | static int __devinit snd_azt2320_pnp_detect(struct pnp_card_link *card, | 315 | static int __devinit snd_azt2320_pnp_detect(struct pnp_card_link *card, |
314 | const struct pnp_card_device_id *id) | 316 | const struct pnp_card_device_id *id) |
315 | { | 317 | { |
@@ -323,6 +325,7 @@ static int __devinit snd_azt2320_pnp_detect(struct pnp_card_link *card, | |||
323 | if (res < 0) | 325 | if (res < 0) |
324 | return res; | 326 | return res; |
325 | dev++; | 327 | dev++; |
328 | azt2320_devices++; | ||
326 | return 0; | 329 | return 0; |
327 | } | 330 | } |
328 | return -ENODEV; | 331 | return -ENODEV; |
@@ -372,10 +375,13 @@ static struct pnp_card_driver azt2320_pnpc_driver = { | |||
372 | 375 | ||
373 | static int __init alsa_card_azt2320_init(void) | 376 | static int __init alsa_card_azt2320_init(void) |
374 | { | 377 | { |
375 | int cards; | 378 | int err; |
379 | |||
380 | err = pnp_register_card_driver(&azt2320_pnpc_driver); | ||
381 | if (err) | ||
382 | return err; | ||
376 | 383 | ||
377 | cards = pnp_register_card_driver(&azt2320_pnpc_driver); | 384 | if (!azt2320_devices) { |
378 | if (cards <= 0) { | ||
379 | pnp_unregister_card_driver(&azt2320_pnpc_driver); | 385 | pnp_unregister_card_driver(&azt2320_pnpc_driver); |
380 | #ifdef MODULE | 386 | #ifdef MODULE |
381 | snd_printk(KERN_ERR "no AZT2320 based soundcards found\n"); | 387 | snd_printk(KERN_ERR "no AZT2320 based soundcards found\n"); |
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index fd9bb2575de8..fa63048a8b9d 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c | |||
@@ -175,7 +175,7 @@ MODULE_DEVICE_TABLE(pnp_card, snd_cmi8330_pnpids); | |||
175 | #endif | 175 | #endif |
176 | 176 | ||
177 | 177 | ||
178 | static struct ad1848_mix_elem snd_cmi8330_controls[] __initdata = { | 178 | static struct ad1848_mix_elem snd_cmi8330_controls[] __devinitdata = { |
179 | AD1848_DOUBLE("Master Playback Volume", 0, CMI8330_MASTVOL, CMI8330_MASTVOL, 4, 0, 15, 0), | 179 | AD1848_DOUBLE("Master Playback Volume", 0, CMI8330_MASTVOL, CMI8330_MASTVOL, 4, 0, 15, 0), |
180 | AD1848_SINGLE("Loud Playback Switch", 0, CMI8330_MUTEMUX, 6, 1, 1), | 180 | AD1848_SINGLE("Loud Playback Switch", 0, CMI8330_MUTEMUX, 6, 1, 1), |
181 | AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1), | 181 | AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1), |
@@ -204,7 +204,7 @@ AD1848_SINGLE(SNDRV_CTL_NAME_IEC958("Input ",PLAYBACK,SWITCH), 0, CMI8330_MUTEMU | |||
204 | }; | 204 | }; |
205 | 205 | ||
206 | #ifdef ENABLE_SB_MIXER | 206 | #ifdef ENABLE_SB_MIXER |
207 | static struct sbmix_elem cmi8330_sb_mixers[] __initdata = { | 207 | static struct sbmix_elem cmi8330_sb_mixers[] __devinitdata = { |
208 | SB_DOUBLE("SB Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31), | 208 | SB_DOUBLE("SB Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31), |
209 | SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15), | 209 | SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15), |
210 | SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15), | 210 | SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15), |
@@ -222,7 +222,7 @@ SB_DOUBLE("SB Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6 | |||
222 | SB_SINGLE("SB Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1), | 222 | SB_SINGLE("SB Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1), |
223 | }; | 223 | }; |
224 | 224 | ||
225 | static unsigned char cmi8330_sb_init_values[][2] __initdata = { | 225 | static unsigned char cmi8330_sb_init_values[][2] __devinitdata = { |
226 | { SB_DSP4_MASTER_DEV + 0, 0 }, | 226 | { SB_DSP4_MASTER_DEV + 0, 0 }, |
227 | { SB_DSP4_MASTER_DEV + 1, 0 }, | 227 | { SB_DSP4_MASTER_DEV + 1, 0 }, |
228 | { SB_DSP4_PCM_DEV + 0, 0 }, | 228 | { SB_DSP4_PCM_DEV + 0, 0 }, |
@@ -545,7 +545,7 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev) | |||
545 | return snd_card_register(card); | 545 | return snd_card_register(card); |
546 | } | 546 | } |
547 | 547 | ||
548 | static int __init snd_cmi8330_nonpnp_probe(struct platform_device *pdev) | 548 | static int __devinit snd_cmi8330_nonpnp_probe(struct platform_device *pdev) |
549 | { | 549 | { |
550 | struct snd_card *card; | 550 | struct snd_card *card; |
551 | int err; | 551 | int err; |
@@ -607,6 +607,8 @@ static struct platform_driver snd_cmi8330_driver = { | |||
607 | 607 | ||
608 | 608 | ||
609 | #ifdef CONFIG_PNP | 609 | #ifdef CONFIG_PNP |
610 | static unsigned int __devinitdata cmi8330_pnp_devices; | ||
611 | |||
610 | static int __devinit snd_cmi8330_pnp_detect(struct pnp_card_link *pcard, | 612 | static int __devinit snd_cmi8330_pnp_detect(struct pnp_card_link *pcard, |
611 | const struct pnp_card_device_id *pid) | 613 | const struct pnp_card_device_id *pid) |
612 | { | 614 | { |
@@ -636,6 +638,7 @@ static int __devinit snd_cmi8330_pnp_detect(struct pnp_card_link *pcard, | |||
636 | } | 638 | } |
637 | pnp_set_card_drvdata(pcard, card); | 639 | pnp_set_card_drvdata(pcard, card); |
638 | dev++; | 640 | dev++; |
641 | cmi8330_pnp_devices++; | ||
639 | return 0; | 642 | return 0; |
640 | } | 643 | } |
641 | 644 | ||
@@ -706,9 +709,9 @@ static int __init alsa_card_cmi8330_init(void) | |||
706 | 709 | ||
707 | #ifdef CONFIG_PNP | 710 | #ifdef CONFIG_PNP |
708 | err = pnp_register_card_driver(&cmi8330_pnpc_driver); | 711 | err = pnp_register_card_driver(&cmi8330_pnpc_driver); |
709 | if (err >= 0) { | 712 | if (!err) { |
710 | pnp_registered = 1; | 713 | pnp_registered = 1; |
711 | cards += err; | 714 | cards += cmi8330_pnp_devices; |
712 | } | 715 | } |
713 | #endif | 716 | #endif |
714 | 717 | ||
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index 4060918e0327..382bb17ef49f 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c | |||
@@ -133,6 +133,7 @@ static int pnpc_registered; | |||
133 | static int pnp_registered; | 133 | static int pnp_registered; |
134 | #endif | 134 | #endif |
135 | #endif /* CONFIG_PNP */ | 135 | #endif /* CONFIG_PNP */ |
136 | static unsigned int snd_cs423x_devices; | ||
136 | 137 | ||
137 | struct snd_card_cs4236 { | 138 | struct snd_card_cs4236 { |
138 | struct snd_cs4231 *chip; | 139 | struct snd_cs4231 *chip; |
@@ -564,7 +565,7 @@ static int __init snd_cs423x_nonpnp_probe(struct platform_device *pdev) | |||
564 | snd_card_free(card); | 565 | snd_card_free(card); |
565 | return err; | 566 | return err; |
566 | } | 567 | } |
567 | 568 | ||
568 | platform_set_drvdata(pdev, card); | 569 | platform_set_drvdata(pdev, card); |
569 | return 0; | 570 | return 0; |
570 | } | 571 | } |
@@ -650,6 +651,7 @@ static int __devinit snd_cs4232_pnpbios_detect(struct pnp_dev *pdev, | |||
650 | } | 651 | } |
651 | pnp_set_drvdata(pdev, card); | 652 | pnp_set_drvdata(pdev, card); |
652 | dev++; | 653 | dev++; |
654 | snd_cs423x_devices++; | ||
653 | return 0; | 655 | return 0; |
654 | } | 656 | } |
655 | 657 | ||
@@ -713,6 +715,7 @@ static int __devinit snd_cs423x_pnpc_detect(struct pnp_card_link *pcard, | |||
713 | } | 715 | } |
714 | pnp_set_card_drvdata(pcard, card); | 716 | pnp_set_card_drvdata(pcard, card); |
715 | dev++; | 717 | dev++; |
718 | snd_cs423x_devices++; | ||
716 | return 0; | 719 | return 0; |
717 | } | 720 | } |
718 | 721 | ||
@@ -721,7 +724,7 @@ static void __devexit snd_cs423x_pnpc_remove(struct pnp_card_link * pcard) | |||
721 | snd_card_free(pnp_get_card_drvdata(pcard)); | 724 | snd_card_free(pnp_get_card_drvdata(pcard)); |
722 | pnp_set_card_drvdata(pcard, NULL); | 725 | pnp_set_card_drvdata(pcard, NULL); |
723 | } | 726 | } |
724 | 727 | ||
725 | #ifdef CONFIG_PM | 728 | #ifdef CONFIG_PM |
726 | static int snd_cs423x_pnpc_suspend(struct pnp_card_link *pcard, pm_message_t state) | 729 | static int snd_cs423x_pnpc_suspend(struct pnp_card_link *pcard, pm_message_t state) |
727 | { | 730 | { |
@@ -766,7 +769,7 @@ static void __init_or_module snd_cs423x_unregister_all(void) | |||
766 | 769 | ||
767 | static int __init alsa_card_cs423x_init(void) | 770 | static int __init alsa_card_cs423x_init(void) |
768 | { | 771 | { |
769 | int i, err, cards = 0; | 772 | int i, err; |
770 | 773 | ||
771 | if ((err = platform_driver_register(&cs423x_nonpnp_driver)) < 0) | 774 | if ((err = platform_driver_register(&cs423x_nonpnp_driver)) < 0) |
772 | return err; | 775 | return err; |
@@ -782,24 +785,20 @@ static int __init alsa_card_cs423x_init(void) | |||
782 | goto errout; | 785 | goto errout; |
783 | } | 786 | } |
784 | platform_devices[i] = device; | 787 | platform_devices[i] = device; |
785 | cards++; | 788 | snd_cs423x_devices++; |
786 | } | 789 | } |
787 | #ifdef CONFIG_PNP | 790 | #ifdef CONFIG_PNP |
788 | #ifdef CS4232 | 791 | #ifdef CS4232 |
789 | i = pnp_register_driver(&cs4232_pnp_driver); | 792 | err = pnp_register_driver(&cs4232_pnp_driver); |
790 | if (i >= 0) { | 793 | if (!err) |
791 | pnp_registered = 1; | 794 | pnp_registered = 1; |
792 | cards += i; | ||
793 | } | ||
794 | #endif | 795 | #endif |
795 | i = pnp_register_card_driver(&cs423x_pnpc_driver); | 796 | err = pnp_register_card_driver(&cs423x_pnpc_driver); |
796 | if (i >= 0) { | 797 | if (!err) |
797 | pnpc_registered = 1; | 798 | pnpc_registered = 1; |
798 | cards += i; | ||
799 | } | ||
800 | #endif /* CONFIG_PNP */ | 799 | #endif /* CONFIG_PNP */ |
801 | 800 | ||
802 | if (!cards) { | 801 | if (!snd_cs423x_devices) { |
803 | #ifdef MODULE | 802 | #ifdef MODULE |
804 | printk(KERN_ERR IDENT " soundcard not found or device busy\n"); | 803 | printk(KERN_ERR IDENT " soundcard not found or device busy\n"); |
805 | #endif | 804 | #endif |
diff --git a/sound/isa/dt019x.c b/sound/isa/dt019x.c index 50e7bc5ef561..0acb4e5da47f 100644 --- a/sound/isa/dt019x.c +++ b/sound/isa/dt019x.c | |||
@@ -272,6 +272,8 @@ static int __devinit snd_card_dt019x_probe(int dev, struct pnp_card_link *pcard, | |||
272 | return 0; | 272 | return 0; |
273 | } | 273 | } |
274 | 274 | ||
275 | static unsigned int __devinitdata dt019x_devices; | ||
276 | |||
275 | static int __devinit snd_dt019x_pnp_probe(struct pnp_card_link *card, | 277 | static int __devinit snd_dt019x_pnp_probe(struct pnp_card_link *card, |
276 | const struct pnp_card_device_id *pid) | 278 | const struct pnp_card_device_id *pid) |
277 | { | 279 | { |
@@ -285,6 +287,7 @@ static int __devinit snd_dt019x_pnp_probe(struct pnp_card_link *card, | |||
285 | if (res < 0) | 287 | if (res < 0) |
286 | return res; | 288 | return res; |
287 | dev++; | 289 | dev++; |
290 | dt019x_devices++; | ||
288 | return 0; | 291 | return 0; |
289 | } | 292 | } |
290 | return -ENODEV; | 293 | return -ENODEV; |
@@ -336,10 +339,13 @@ static struct pnp_card_driver dt019x_pnpc_driver = { | |||
336 | 339 | ||
337 | static int __init alsa_card_dt019x_init(void) | 340 | static int __init alsa_card_dt019x_init(void) |
338 | { | 341 | { |
339 | int cards = 0; | 342 | int err; |
343 | |||
344 | err = pnp_register_card_driver(&dt019x_pnpc_driver); | ||
345 | if (err) | ||
346 | return err; | ||
340 | 347 | ||
341 | cards = pnp_register_card_driver(&dt019x_pnpc_driver); | 348 | if (!dt019x_devices) { |
342 | if (cards <= 0) { | ||
343 | pnp_unregister_card_driver(&dt019x_pnpc_driver); | 349 | pnp_unregister_card_driver(&dt019x_pnpc_driver); |
344 | #ifdef MODULE | 350 | #ifdef MODULE |
345 | snd_printk(KERN_ERR "no DT-019X / ALS-007 based soundcards found\n"); | 351 | snd_printk(KERN_ERR "no DT-019X / ALS-007 based soundcards found\n"); |
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 721955d26194..9fbc185b4cc2 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c | |||
@@ -2204,7 +2204,7 @@ static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev) | |||
2204 | return snd_card_register(card); | 2204 | return snd_card_register(card); |
2205 | } | 2205 | } |
2206 | 2206 | ||
2207 | static int __init snd_es18xx_nonpnp_probe1(int dev, struct platform_device *devptr) | 2207 | static int __devinit snd_es18xx_nonpnp_probe1(int dev, struct platform_device *devptr) |
2208 | { | 2208 | { |
2209 | struct snd_card *card; | 2209 | struct snd_card *card; |
2210 | int err; | 2210 | int err; |
@@ -2221,7 +2221,7 @@ static int __init snd_es18xx_nonpnp_probe1(int dev, struct platform_device *devp | |||
2221 | return 0; | 2221 | return 0; |
2222 | } | 2222 | } |
2223 | 2223 | ||
2224 | static int __init snd_es18xx_nonpnp_probe(struct platform_device *pdev) | 2224 | static int __devinit snd_es18xx_nonpnp_probe(struct platform_device *pdev) |
2225 | { | 2225 | { |
2226 | int dev = pdev->id; | 2226 | int dev = pdev->id; |
2227 | int err; | 2227 | int err; |
@@ -2297,6 +2297,8 @@ static struct platform_driver snd_es18xx_nonpnp_driver = { | |||
2297 | 2297 | ||
2298 | 2298 | ||
2299 | #ifdef CONFIG_PNP | 2299 | #ifdef CONFIG_PNP |
2300 | static unsigned int __devinitdata es18xx_pnp_devices; | ||
2301 | |||
2300 | static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard, | 2302 | static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard, |
2301 | const struct pnp_card_device_id *pid) | 2303 | const struct pnp_card_device_id *pid) |
2302 | { | 2304 | { |
@@ -2327,6 +2329,7 @@ static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard, | |||
2327 | 2329 | ||
2328 | pnp_set_card_drvdata(pcard, card); | 2330 | pnp_set_card_drvdata(pcard, card); |
2329 | dev++; | 2331 | dev++; |
2332 | es18xx_pnp_devices++; | ||
2330 | return 0; | 2333 | return 0; |
2331 | } | 2334 | } |
2332 | 2335 | ||
@@ -2397,10 +2400,10 @@ static int __init alsa_card_es18xx_init(void) | |||
2397 | } | 2400 | } |
2398 | 2401 | ||
2399 | #ifdef CONFIG_PNP | 2402 | #ifdef CONFIG_PNP |
2400 | i = pnp_register_card_driver(&es18xx_pnpc_driver); | 2403 | err = pnp_register_card_driver(&es18xx_pnpc_driver); |
2401 | if (i >= 0) { | 2404 | if (!err) { |
2402 | pnp_registered = 1; | 2405 | pnp_registered = 1; |
2403 | cards += i; | 2406 | cards += es18xx_pnp_devices; |
2404 | } | 2407 | } |
2405 | #endif | 2408 | #endif |
2406 | 2409 | ||
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index 2cacd0fa6871..de71b7a99c83 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c | |||
@@ -791,7 +791,7 @@ static int __devinit snd_interwave_probe(struct snd_card *card, int dev) | |||
791 | return 0; | 791 | return 0; |
792 | } | 792 | } |
793 | 793 | ||
794 | static int __init snd_interwave_nonpnp_probe1(int dev, struct platform_device *devptr) | 794 | static int __devinit snd_interwave_nonpnp_probe1(int dev, struct platform_device *devptr) |
795 | { | 795 | { |
796 | struct snd_card *card; | 796 | struct snd_card *card; |
797 | int err; | 797 | int err; |
@@ -809,7 +809,7 @@ static int __init snd_interwave_nonpnp_probe1(int dev, struct platform_device *d | |||
809 | return 0; | 809 | return 0; |
810 | } | 810 | } |
811 | 811 | ||
812 | static int __init snd_interwave_nonpnp_probe(struct platform_device *pdev) | 812 | static int __devinit snd_interwave_nonpnp_probe(struct platform_device *pdev) |
813 | { | 813 | { |
814 | int dev = pdev->id; | 814 | int dev = pdev->id; |
815 | int err; | 815 | int err; |
@@ -867,6 +867,7 @@ static struct platform_driver snd_interwave_driver = { | |||
867 | }; | 867 | }; |
868 | 868 | ||
869 | #ifdef CONFIG_PNP | 869 | #ifdef CONFIG_PNP |
870 | static unsigned int __devinitdata interwave_pnp_devices; | ||
870 | 871 | ||
871 | static int __devinit snd_interwave_pnp_detect(struct pnp_card_link *pcard, | 872 | static int __devinit snd_interwave_pnp_detect(struct pnp_card_link *pcard, |
872 | const struct pnp_card_device_id *pid) | 873 | const struct pnp_card_device_id *pid) |
@@ -897,6 +898,7 @@ static int __devinit snd_interwave_pnp_detect(struct pnp_card_link *pcard, | |||
897 | } | 898 | } |
898 | pnp_set_card_drvdata(pcard, card); | 899 | pnp_set_card_drvdata(pcard, card); |
899 | dev++; | 900 | dev++; |
901 | interwave_pnp_devices++; | ||
900 | return 0; | 902 | return 0; |
901 | } | 903 | } |
902 | 904 | ||
@@ -954,10 +956,10 @@ static int __init alsa_card_interwave_init(void) | |||
954 | } | 956 | } |
955 | 957 | ||
956 | /* ISA PnP cards */ | 958 | /* ISA PnP cards */ |
957 | i = pnp_register_card_driver(&interwave_pnpc_driver); | 959 | err = pnp_register_card_driver(&interwave_pnpc_driver); |
958 | if (i >= 0) { | 960 | if (!err) { |
959 | pnp_registered = 1; | 961 | pnp_registered = 1; |
960 | cards += i; | 962 | cards += interwave_pnp_devices;; |
961 | } | 963 | } |
962 | 964 | ||
963 | if (!cards) { | 965 | if (!cards) { |
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index 56fcd8a946a4..c906e205d7d5 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c | |||
@@ -95,6 +95,7 @@ static struct platform_device *platform_devices[SNDRV_CARDS]; | |||
95 | static int pnp_registered; | 95 | static int pnp_registered; |
96 | static int pnpc_registered; | 96 | static int pnpc_registered; |
97 | #endif | 97 | #endif |
98 | static unsigned int snd_opl3sa2_devices; | ||
98 | 99 | ||
99 | /* control ports */ | 100 | /* control ports */ |
100 | #define OPL3SA2_PM_CTRL 0x01 | 101 | #define OPL3SA2_PM_CTRL 0x01 |
@@ -760,6 +761,7 @@ static int __devinit snd_opl3sa2_pnp_detect(struct pnp_dev *pdev, | |||
760 | } | 761 | } |
761 | pnp_set_drvdata(pdev, card); | 762 | pnp_set_drvdata(pdev, card); |
762 | dev++; | 763 | dev++; |
764 | snd_opl3sa2_devices++; | ||
763 | return 0; | 765 | return 0; |
764 | } | 766 | } |
765 | 767 | ||
@@ -826,6 +828,7 @@ static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *pcard, | |||
826 | } | 828 | } |
827 | pnp_set_card_drvdata(pcard, card); | 829 | pnp_set_card_drvdata(pcard, card); |
828 | dev++; | 830 | dev++; |
831 | snd_opl3sa2_devices++; | ||
829 | return 0; | 832 | return 0; |
830 | } | 833 | } |
831 | 834 | ||
@@ -944,7 +947,7 @@ static void __init_or_module snd_opl3sa2_unregister_all(void) | |||
944 | 947 | ||
945 | static int __init alsa_card_opl3sa2_init(void) | 948 | static int __init alsa_card_opl3sa2_init(void) |
946 | { | 949 | { |
947 | int i, err, cards = 0; | 950 | int i, err; |
948 | 951 | ||
949 | if ((err = platform_driver_register(&snd_opl3sa2_nonpnp_driver)) < 0) | 952 | if ((err = platform_driver_register(&snd_opl3sa2_nonpnp_driver)) < 0) |
950 | return err; | 953 | return err; |
@@ -964,23 +967,19 @@ static int __init alsa_card_opl3sa2_init(void) | |||
964 | goto errout; | 967 | goto errout; |
965 | } | 968 | } |
966 | platform_devices[i] = device; | 969 | platform_devices[i] = device; |
967 | cards++; | 970 | snd_opl3sa2_devices++; |
968 | } | 971 | } |
969 | 972 | ||
970 | #ifdef CONFIG_PNP | 973 | #ifdef CONFIG_PNP |
971 | err = pnp_register_driver(&opl3sa2_pnp_driver); | 974 | err = pnp_register_driver(&opl3sa2_pnp_driver); |
972 | if (err >= 0) { | 975 | if (!err) |
973 | pnp_registered = 1; | 976 | pnp_registered = 1; |
974 | cards += err; | ||
975 | } | ||
976 | err = pnp_register_card_driver(&opl3sa2_pnpc_driver); | 977 | err = pnp_register_card_driver(&opl3sa2_pnpc_driver); |
977 | if (err >= 0) { | 978 | if (!err) |
978 | pnpc_registered = 1; | 979 | pnpc_registered = 1; |
979 | cards += err; | ||
980 | } | ||
981 | #endif | 980 | #endif |
982 | 981 | ||
983 | if (!cards) { | 982 | if (!snd_opl3sa2_devices) { |
984 | #ifdef MODULE | 983 | #ifdef MODULE |
985 | snd_printk(KERN_ERR "Yamaha OPL3-SA soundcard not found or device busy\n"); | 984 | snd_printk(KERN_ERR "Yamaha OPL3-SA soundcard not found or device busy\n"); |
986 | #endif | 985 | #endif |
diff --git a/sound/isa/sb/es968.c b/sound/isa/sb/es968.c index 9da80bfa3027..d4d65b84265a 100644 --- a/sound/isa/sb/es968.c +++ b/sound/isa/sb/es968.c | |||
@@ -124,7 +124,7 @@ static int __devinit snd_card_es968_pnp(int dev, struct snd_card_es968 *acard, | |||
124 | return 0; | 124 | return 0; |
125 | } | 125 | } |
126 | 126 | ||
127 | static int __init snd_card_es968_probe(int dev, | 127 | static int __devinit snd_card_es968_probe(int dev, |
128 | struct pnp_card_link *pcard, | 128 | struct pnp_card_link *pcard, |
129 | const struct pnp_card_device_id *pid) | 129 | const struct pnp_card_device_id *pid) |
130 | { | 130 | { |
@@ -182,6 +182,8 @@ static int __init snd_card_es968_probe(int dev, | |||
182 | return 0; | 182 | return 0; |
183 | } | 183 | } |
184 | 184 | ||
185 | static unsigned int __devinitdata es968_devices; | ||
186 | |||
185 | static int __devinit snd_es968_pnp_detect(struct pnp_card_link *card, | 187 | static int __devinit snd_es968_pnp_detect(struct pnp_card_link *card, |
186 | const struct pnp_card_device_id *id) | 188 | const struct pnp_card_device_id *id) |
187 | { | 189 | { |
@@ -195,6 +197,7 @@ static int __devinit snd_es968_pnp_detect(struct pnp_card_link *card, | |||
195 | if (res < 0) | 197 | if (res < 0) |
196 | return res; | 198 | return res; |
197 | dev++; | 199 | dev++; |
200 | es968_devices++; | ||
198 | return 0; | 201 | return 0; |
199 | } | 202 | } |
200 | return -ENODEV; | 203 | return -ENODEV; |
@@ -246,8 +249,11 @@ static struct pnp_card_driver es968_pnpc_driver = { | |||
246 | 249 | ||
247 | static int __init alsa_card_es968_init(void) | 250 | static int __init alsa_card_es968_init(void) |
248 | { | 251 | { |
249 | int cards = pnp_register_card_driver(&es968_pnpc_driver); | 252 | int err = pnp_register_card_driver(&es968_pnpc_driver); |
250 | if (cards <= 0) { | 253 | if (err) |
254 | return err; | ||
255 | |||
256 | if (!es968_devices) { | ||
251 | pnp_unregister_card_driver(&es968_pnpc_driver); | 257 | pnp_unregister_card_driver(&es968_pnpc_driver); |
252 | #ifdef MODULE | 258 | #ifdef MODULE |
253 | snd_printk(KERN_ERR "no ES968 based soundcards found\n"); | 259 | snd_printk(KERN_ERR "no ES968 based soundcards found\n"); |
diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c index 5737ab76160c..21ea65925a9e 100644 --- a/sound/isa/sb/sb16.c +++ b/sound/isa/sb/sb16.c | |||
@@ -369,7 +369,7 @@ static struct snd_card *snd_sb16_card_new(int dev) | |||
369 | return card; | 369 | return card; |
370 | } | 370 | } |
371 | 371 | ||
372 | static int __init snd_sb16_probe(struct snd_card *card, int dev) | 372 | static int __devinit snd_sb16_probe(struct snd_card *card, int dev) |
373 | { | 373 | { |
374 | int xirq, xdma8, xdma16; | 374 | int xirq, xdma8, xdma16; |
375 | struct snd_sb *chip; | 375 | struct snd_sb *chip; |
@@ -518,7 +518,7 @@ static int snd_sb16_resume(struct snd_card *card) | |||
518 | } | 518 | } |
519 | #endif | 519 | #endif |
520 | 520 | ||
521 | static int __init snd_sb16_nonpnp_probe1(int dev, struct platform_device *devptr) | 521 | static int __devinit snd_sb16_nonpnp_probe1(int dev, struct platform_device *devptr) |
522 | { | 522 | { |
523 | struct snd_card_sb16 *acard; | 523 | struct snd_card_sb16 *acard; |
524 | struct snd_card *card; | 524 | struct snd_card *card; |
@@ -548,7 +548,7 @@ static int __init snd_sb16_nonpnp_probe1(int dev, struct platform_device *devptr | |||
548 | } | 548 | } |
549 | 549 | ||
550 | 550 | ||
551 | static int __init snd_sb16_nonpnp_probe(struct platform_device *pdev) | 551 | static int __devinit snd_sb16_nonpnp_probe(struct platform_device *pdev) |
552 | { | 552 | { |
553 | int dev = pdev->id; | 553 | int dev = pdev->id; |
554 | int err; | 554 | int err; |
@@ -629,6 +629,7 @@ static struct platform_driver snd_sb16_nonpnp_driver = { | |||
629 | 629 | ||
630 | 630 | ||
631 | #ifdef CONFIG_PNP | 631 | #ifdef CONFIG_PNP |
632 | static unsigned int __devinitdata sb16_pnp_devices; | ||
632 | 633 | ||
633 | static int __devinit snd_sb16_pnp_detect(struct pnp_card_link *pcard, | 634 | static int __devinit snd_sb16_pnp_detect(struct pnp_card_link *pcard, |
634 | const struct pnp_card_device_id *pid) | 635 | const struct pnp_card_device_id *pid) |
@@ -651,6 +652,7 @@ static int __devinit snd_sb16_pnp_detect(struct pnp_card_link *pcard, | |||
651 | } | 652 | } |
652 | pnp_set_card_drvdata(pcard, card); | 653 | pnp_set_card_drvdata(pcard, card); |
653 | dev++; | 654 | dev++; |
655 | sb16_pnp_devices++; | ||
654 | return 0; | 656 | return 0; |
655 | } | 657 | } |
656 | 658 | ||
@@ -727,10 +729,10 @@ static int __init alsa_card_sb16_init(void) | |||
727 | } | 729 | } |
728 | #ifdef CONFIG_PNP | 730 | #ifdef CONFIG_PNP |
729 | /* PnP cards at last */ | 731 | /* PnP cards at last */ |
730 | i = pnp_register_card_driver(&sb16_pnpc_driver); | 732 | err = pnp_register_card_driver(&sb16_pnpc_driver); |
731 | if (i >= 0) { | 733 | if (!err) { |
732 | pnp_registered = 1; | 734 | pnp_registered = 1; |
733 | cards += i; | 735 | cards += sb16_pnp_devices; |
734 | } | 736 | } |
735 | #endif | 737 | #endif |
736 | 738 | ||
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 29bba8cc3ef3..48e5552d3444 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c | |||
@@ -1255,7 +1255,7 @@ static int __devinit create_sscape(int dev, struct snd_card **rcardp) | |||
1255 | } | 1255 | } |
1256 | 1256 | ||
1257 | 1257 | ||
1258 | static int __init snd_sscape_probe(struct platform_device *pdev) | 1258 | static int __devinit snd_sscape_probe(struct platform_device *pdev) |
1259 | { | 1259 | { |
1260 | int dev = pdev->id; | 1260 | int dev = pdev->id; |
1261 | struct snd_card *card; | 1261 | struct snd_card *card; |
@@ -1469,7 +1469,7 @@ static int __init sscape_init(void) | |||
1469 | if (ret < 0) | 1469 | if (ret < 0) |
1470 | return ret; | 1470 | return ret; |
1471 | #ifdef CONFIG_PNP | 1471 | #ifdef CONFIG_PNP |
1472 | if (pnp_register_card_driver(&sscape_pnpc_driver) >= 0) | 1472 | if (pnp_register_card_driver(&sscape_pnpc_driver) == 0) |
1473 | pnp_registered = 1; | 1473 | pnp_registered = 1; |
1474 | #endif | 1474 | #endif |
1475 | return 0; | 1475 | return 0; |
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c index c0115bf9065e..2f13cd5d4dcb 100644 --- a/sound/isa/wavefront/wavefront.c +++ b/sound/isa/wavefront/wavefront.c | |||
@@ -589,7 +589,7 @@ snd_wavefront_probe (struct snd_card *card, int dev) | |||
589 | return snd_card_register(card); | 589 | return snd_card_register(card); |
590 | } | 590 | } |
591 | 591 | ||
592 | static int __init snd_wavefront_nonpnp_probe(struct platform_device *pdev) | 592 | static int __devinit snd_wavefront_nonpnp_probe(struct platform_device *pdev) |
593 | { | 593 | { |
594 | int dev = pdev->id; | 594 | int dev = pdev->id; |
595 | struct snd_card *card; | 595 | struct snd_card *card; |
@@ -637,6 +637,7 @@ static struct platform_driver snd_wavefront_driver = { | |||
637 | 637 | ||
638 | 638 | ||
639 | #ifdef CONFIG_PNP | 639 | #ifdef CONFIG_PNP |
640 | static unsigned int __devinitdata wavefront_pnp_devices; | ||
640 | 641 | ||
641 | static int __devinit snd_wavefront_pnp_detect(struct pnp_card_link *pcard, | 642 | static int __devinit snd_wavefront_pnp_detect(struct pnp_card_link *pcard, |
642 | const struct pnp_card_device_id *pid) | 643 | const struct pnp_card_device_id *pid) |
@@ -670,6 +671,7 @@ static int __devinit snd_wavefront_pnp_detect(struct pnp_card_link *pcard, | |||
670 | 671 | ||
671 | pnp_set_card_drvdata(pcard, card); | 672 | pnp_set_card_drvdata(pcard, card); |
672 | dev++; | 673 | dev++; |
674 | wavefront_pnp_devices++; | ||
673 | return 0; | 675 | return 0; |
674 | } | 676 | } |
675 | 677 | ||
@@ -729,10 +731,10 @@ static int __init alsa_card_wavefront_init(void) | |||
729 | } | 731 | } |
730 | 732 | ||
731 | #ifdef CONFIG_PNP | 733 | #ifdef CONFIG_PNP |
732 | i = pnp_register_card_driver(&wavefront_pnpc_driver); | 734 | err = pnp_register_card_driver(&wavefront_pnpc_driver); |
733 | if (i >= 0) { | 735 | if (!err) { |
734 | pnp_registered = 1; | 736 | pnp_registered = 1; |
735 | cards += i; | 737 | cards += wavefront_pnp_devices; |
736 | } | 738 | } |
737 | #endif | 739 | #endif |
738 | 740 | ||
diff --git a/sound/oss/cs4232.c b/sound/oss/cs4232.c index 7c59e2d4003a..c7f86f09c28d 100644 --- a/sound/oss/cs4232.c +++ b/sound/oss/cs4232.c | |||
@@ -360,6 +360,8 @@ static int __initdata synthio = -1; | |||
360 | static int __initdata synthirq = -1; | 360 | static int __initdata synthirq = -1; |
361 | static int __initdata isapnp = 1; | 361 | static int __initdata isapnp = 1; |
362 | 362 | ||
363 | static unsigned int cs4232_devices; | ||
364 | |||
363 | MODULE_DESCRIPTION("CS4232 based soundcard driver"); | 365 | MODULE_DESCRIPTION("CS4232 based soundcard driver"); |
364 | MODULE_AUTHOR("Hannu Savolainen, Paul Barton-Davis"); | 366 | MODULE_AUTHOR("Hannu Savolainen, Paul Barton-Davis"); |
365 | MODULE_LICENSE("GPL"); | 367 | MODULE_LICENSE("GPL"); |
@@ -421,6 +423,7 @@ static int cs4232_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev | |||
421 | return -ENODEV; | 423 | return -ENODEV; |
422 | } | 424 | } |
423 | pnp_set_drvdata(dev,isapnpcfg); | 425 | pnp_set_drvdata(dev,isapnpcfg); |
426 | cs4232_devices++; | ||
424 | return 0; | 427 | return 0; |
425 | } | 428 | } |
426 | 429 | ||
@@ -455,10 +458,11 @@ static int __init init_cs4232(void) | |||
455 | #endif | 458 | #endif |
456 | cfg.irq = -1; | 459 | cfg.irq = -1; |
457 | 460 | ||
458 | if (isapnp && | 461 | if (isapnp) { |
459 | (pnp_register_driver(&cs4232_driver) > 0) | 462 | pnp_register_driver(&cs4232_driver); |
460 | ) | 463 | if (cs4232_devices) |
461 | return 0; | 464 | return 0; |
465 | } | ||
462 | 466 | ||
463 | if(io==-1||irq==-1||dma==-1) | 467 | if(io==-1||irq==-1||dma==-1) |
464 | { | 468 | { |
@@ -503,7 +507,8 @@ static int __init setup_cs4232(char *str) | |||
503 | int ints[7]; | 507 | int ints[7]; |
504 | 508 | ||
505 | /* If we have isapnp cards, no need for options */ | 509 | /* If we have isapnp cards, no need for options */ |
506 | if (pnp_register_driver(&cs4232_driver) > 0) | 510 | pnp_register_driver(&cs4232_driver); |
511 | if (cs4232_devices) | ||
507 | return 1; | 512 | return 1; |
508 | 513 | ||
509 | str = get_options(str, ARRAY_SIZE(ints), ints); | 514 | str = get_options(str, ARRAY_SIZE(ints), ints); |
diff --git a/sound/oss/sb_card.c b/sound/oss/sb_card.c index 680b82e15298..d38e88abc8fa 100644 --- a/sound/oss/sb_card.c +++ b/sound/oss/sb_card.c | |||
@@ -52,6 +52,7 @@ static int __initdata sm_games = 0; /* Logitech soundman games? */ | |||
52 | static struct sb_card_config *legacy = NULL; | 52 | static struct sb_card_config *legacy = NULL; |
53 | 53 | ||
54 | #ifdef CONFIG_PNP | 54 | #ifdef CONFIG_PNP |
55 | static int pnp_registered; | ||
55 | static int __initdata pnp = 1; | 56 | static int __initdata pnp = 1; |
56 | /* | 57 | /* |
57 | static int __initdata uart401 = 0; | 58 | static int __initdata uart401 = 0; |
@@ -133,7 +134,7 @@ static void sb_unload(struct sb_card_config *scc) | |||
133 | } | 134 | } |
134 | 135 | ||
135 | /* Register legacy card with OSS subsystem */ | 136 | /* Register legacy card with OSS subsystem */ |
136 | static int sb_init_legacy(void) | 137 | static int __init sb_init_legacy(void) |
137 | { | 138 | { |
138 | struct sb_module_options sbmo = {0}; | 139 | struct sb_module_options sbmo = {0}; |
139 | 140 | ||
@@ -234,6 +235,8 @@ static void sb_dev2cfg(struct pnp_dev *dev, struct sb_card_config *scc) | |||
234 | } | 235 | } |
235 | } | 236 | } |
236 | 237 | ||
238 | static unsigned int sb_pnp_devices; | ||
239 | |||
237 | /* Probe callback function for the PnP API */ | 240 | /* Probe callback function for the PnP API */ |
238 | static int sb_pnp_probe(struct pnp_card_link *card, const struct pnp_card_device_id *card_id) | 241 | static int sb_pnp_probe(struct pnp_card_link *card, const struct pnp_card_device_id *card_id) |
239 | { | 242 | { |
@@ -264,6 +267,7 @@ static int sb_pnp_probe(struct pnp_card_link *card, const struct pnp_card_device | |||
264 | scc->conf.dma, scc->conf.dma2); | 267 | scc->conf.dma, scc->conf.dma2); |
265 | 268 | ||
266 | pnp_set_card_drvdata(card, scc); | 269 | pnp_set_card_drvdata(card, scc); |
270 | sb_pnp_devices++; | ||
267 | 271 | ||
268 | return sb_register_oss(scc, &sbmo); | 272 | return sb_register_oss(scc, &sbmo); |
269 | } | 273 | } |
@@ -289,6 +293,14 @@ static struct pnp_card_driver sb_pnp_driver = { | |||
289 | MODULE_DEVICE_TABLE(pnp_card, sb_pnp_card_table); | 293 | MODULE_DEVICE_TABLE(pnp_card, sb_pnp_card_table); |
290 | #endif /* CONFIG_PNP */ | 294 | #endif /* CONFIG_PNP */ |
291 | 295 | ||
296 | static void __init_or_module sb_unregister_all(void) | ||
297 | { | ||
298 | #ifdef CONFIG_PNP | ||
299 | if (pnp_registered) | ||
300 | pnp_unregister_card_driver(&sb_pnp_driver); | ||
301 | #endif | ||
302 | } | ||
303 | |||
292 | static int __init sb_init(void) | 304 | static int __init sb_init(void) |
293 | { | 305 | { |
294 | int lres = 0; | 306 | int lres = 0; |
@@ -307,17 +319,18 @@ static int __init sb_init(void) | |||
307 | 319 | ||
308 | #ifdef CONFIG_PNP | 320 | #ifdef CONFIG_PNP |
309 | if(pnp) { | 321 | if(pnp) { |
310 | pres = pnp_register_card_driver(&sb_pnp_driver); | 322 | int err = pnp_register_card_driver(&sb_pnp_driver); |
323 | if (!err) | ||
324 | pnp_registered = 1; | ||
325 | pres = sb_pnp_devices; | ||
311 | } | 326 | } |
312 | #endif | 327 | #endif |
313 | printk(KERN_INFO "sb: Init: Done\n"); | 328 | printk(KERN_INFO "sb: Init: Done\n"); |
314 | 329 | ||
315 | /* If either PnP or Legacy registered a card then return | 330 | /* If either PnP or Legacy registered a card then return |
316 | * success */ | 331 | * success */ |
317 | if (pres <= 0 && lres <= 0) { | 332 | if (pres == 0 && lres <= 0) { |
318 | #ifdef CONFIG_PNP | 333 | sb_unregister_all(); |
319 | pnp_unregister_card_driver(&sb_pnp_driver); | ||
320 | #endif | ||
321 | return -ENODEV; | 334 | return -ENODEV; |
322 | } | 335 | } |
323 | return 0; | 336 | return 0; |
@@ -333,9 +346,7 @@ static void __exit sb_exit(void) | |||
333 | sb_unload(legacy); | 346 | sb_unload(legacy); |
334 | } | 347 | } |
335 | 348 | ||
336 | #ifdef CONFIG_PNP | 349 | sb_unregister_all(); |
337 | pnp_unregister_card_driver(&sb_pnp_driver); | ||
338 | #endif | ||
339 | 350 | ||
340 | if (smw_free) { | 351 | if (smw_free) { |
341 | vfree(smw_free); | 352 | vfree(smw_free); |