diff options
author | Tejun Heo <tj@kernel.org> | 2011-05-24 03:59:36 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2011-05-24 03:59:36 -0400 |
commit | 6988f20fe04e9ef3aea488cb8ab57fbeb78e12f0 (patch) | |
tree | c9d7fc50a2e2147a5ca07e3096e7eeb916ad2da9 | |
parent | 0415b00d175e0d8945e6785aad21b5f157976ce0 (diff) | |
parent | 6ea0c34dac89611126455537552cffe6c7e832ad (diff) |
Merge branch 'fixes-2.6.39' into for-2.6.40
830 files changed, 33294 insertions, 15847 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss b/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss index 4f29e5f1ebfa..f5bb0a3bb8c0 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss +++ b/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss | |||
@@ -59,3 +59,15 @@ Kernel Version: 2.6.31 | |||
59 | Contact: iss_storagedev@hp.com | 59 | Contact: iss_storagedev@hp.com |
60 | Description: Displays the usage count (number of opens) of logical drive Y | 60 | Description: Displays the usage count (number of opens) of logical drive Y |
61 | of controller X. | 61 | of controller X. |
62 | |||
63 | Where: /sys/bus/pci/devices/<dev>/ccissX/resettable | ||
64 | Date: February 2011 | ||
65 | Kernel Version: 2.6.38 | ||
66 | Contact: iss_storagedev@hp.com | ||
67 | Description: Value of 1 indicates the controller can honor the reset_devices | ||
68 | kernel parameter. Value of 0 indicates reset_devices cannot be | ||
69 | honored. This is to allow, for example, kexec tools to be able | ||
70 | to warn the user if they designate an unresettable device as | ||
71 | a dump device, as kdump requires resetting the device in order | ||
72 | to work reliably. | ||
73 | |||
diff --git a/Documentation/ABI/testing/sysfs-fs-ext4 b/Documentation/ABI/testing/sysfs-fs-ext4 index 5fb709997d96..f22ac0872ae8 100644 --- a/Documentation/ABI/testing/sysfs-fs-ext4 +++ b/Documentation/ABI/testing/sysfs-fs-ext4 | |||
@@ -48,7 +48,7 @@ Description: | |||
48 | will have its blocks allocated out of its own unique | 48 | will have its blocks allocated out of its own unique |
49 | preallocation pool. | 49 | preallocation pool. |
50 | 50 | ||
51 | What: /sys/fs/ext4/<disk>/inode_readahead | 51 | What: /sys/fs/ext4/<disk>/inode_readahead_blks |
52 | Date: March 2008 | 52 | Date: March 2008 |
53 | Contact: "Theodore Ts'o" <tytso@mit.edu> | 53 | Contact: "Theodore Ts'o" <tytso@mit.edu> |
54 | Description: | 54 | Description: |
@@ -85,7 +85,14 @@ Date: June 2008 | |||
85 | Contact: "Theodore Ts'o" <tytso@mit.edu> | 85 | Contact: "Theodore Ts'o" <tytso@mit.edu> |
86 | Description: | 86 | Description: |
87 | Tuning parameter which (if non-zero) controls the goal | 87 | Tuning parameter which (if non-zero) controls the goal |
88 | inode used by the inode allocator in p0reference to | 88 | inode used by the inode allocator in preference to |
89 | all other allocation hueristics. This is intended for | 89 | all other allocation heuristics. This is intended for |
90 | debugging use only, and should be 0 on production | 90 | debugging use only, and should be 0 on production |
91 | systems. | 91 | systems. |
92 | |||
93 | What: /sys/fs/ext4/<disk>/max_writeback_mb_bump | ||
94 | Date: September 2009 | ||
95 | Contact: "Theodore Ts'o" <tytso@mit.edu> | ||
96 | Description: | ||
97 | The maximum number of megabytes the writeback code will | ||
98 | try to write out before move on to another inode. | ||
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 2deb069aedf1..8436b018c289 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile | |||
@@ -55,7 +55,6 @@ mandocs: $(MAN) | |||
55 | build_images = mkdir -p $(objtree)/Documentation/DocBook/media/ && \ | 55 | build_images = mkdir -p $(objtree)/Documentation/DocBook/media/ && \ |
56 | cp $(srctree)/Documentation/DocBook/dvb/*.png \ | 56 | cp $(srctree)/Documentation/DocBook/dvb/*.png \ |
57 | $(srctree)/Documentation/DocBook/v4l/*.gif \ | 57 | $(srctree)/Documentation/DocBook/v4l/*.gif \ |
58 | $(srctree)/Documentation/DocBook/v4l/*.png \ | ||
59 | $(objtree)/Documentation/DocBook/media/ | 58 | $(objtree)/Documentation/DocBook/media/ |
60 | 59 | ||
61 | xmldoclinks: | 60 | xmldoclinks: |
diff --git a/Documentation/DocBook/rapidio.tmpl b/Documentation/DocBook/rapidio.tmpl index 54eb26b57372..50479360d845 100644 --- a/Documentation/DocBook/rapidio.tmpl +++ b/Documentation/DocBook/rapidio.tmpl | |||
@@ -133,7 +133,6 @@ | |||
133 | !Idrivers/rapidio/rio-sysfs.c | 133 | !Idrivers/rapidio/rio-sysfs.c |
134 | </sect1> | 134 | </sect1> |
135 | <sect1 id="PPC32_support"><title>PPC32 support</title> | 135 | <sect1 id="PPC32_support"><title>PPC32 support</title> |
136 | !Earch/powerpc/sysdev/fsl_rio.c | ||
137 | !Iarch/powerpc/sysdev/fsl_rio.c | 136 | !Iarch/powerpc/sysdev/fsl_rio.c |
138 | </sect1> | 137 | </sect1> |
139 | </chapter> | 138 | </chapter> |
diff --git a/Documentation/development-process/1.Intro b/Documentation/development-process/1.Intro index 8cc2cba2b10d..9b614480aa84 100644 --- a/Documentation/development-process/1.Intro +++ b/Documentation/development-process/1.Intro | |||
@@ -56,13 +56,13 @@ information on kernel development. | |||
56 | 56 | ||
57 | 1.2: WHAT THIS DOCUMENT IS ABOUT | 57 | 1.2: WHAT THIS DOCUMENT IS ABOUT |
58 | 58 | ||
59 | The Linux kernel, at over 6 million lines of code and well over 1000 active | 59 | The Linux kernel, at over 8 million lines of code and well over 1000 |
60 | contributors, is one of the largest and most active free software projects | 60 | contributors to each release, is one of the largest and most active free |
61 | in existence. Since its humble beginning in 1991, this kernel has evolved | 61 | software projects in existence. Since its humble beginning in 1991, this |
62 | into a best-of-breed operating system component which runs on pocket-sized | 62 | kernel has evolved into a best-of-breed operating system component which |
63 | digital music players, desktop PCs, the largest supercomputers in | 63 | runs on pocket-sized digital music players, desktop PCs, the largest |
64 | existence, and all types of systems in between. It is a robust, efficient, | 64 | supercomputers in existence, and all types of systems in between. It is a |
65 | and scalable solution for almost any situation. | 65 | robust, efficient, and scalable solution for almost any situation. |
66 | 66 | ||
67 | With the growth of Linux has come an increase in the number of developers | 67 | With the growth of Linux has come an increase in the number of developers |
68 | (and companies) wishing to participate in its development. Hardware | 68 | (and companies) wishing to participate in its development. Hardware |
@@ -115,7 +115,7 @@ This document was written by Jonathan Corbet, corbet@lwn.net. It has been | |||
115 | improved by comments from Johannes Berg, James Berry, Alex Chiang, Roland | 115 | improved by comments from Johannes Berg, James Berry, Alex Chiang, Roland |
116 | Dreier, Randy Dunlap, Jake Edge, Jiri Kosina, Matt Mackall, Arthur Marsh, | 116 | Dreier, Randy Dunlap, Jake Edge, Jiri Kosina, Matt Mackall, Arthur Marsh, |
117 | Amanda McPherson, Andrew Morton, Andrew Price, Tsugikazu Shibata, and | 117 | Amanda McPherson, Andrew Morton, Andrew Price, Tsugikazu Shibata, and |
118 | Jochen Voß. | 118 | Jochen Voß. |
119 | 119 | ||
120 | This work was supported by the Linux Foundation; thanks especially to | 120 | This work was supported by the Linux Foundation; thanks especially to |
121 | Amanda McPherson, who saw the value of this effort and made it all happen. | 121 | Amanda McPherson, who saw the value of this effort and made it all happen. |
@@ -221,7 +221,7 @@ include: | |||
221 | - Everything that was said above about code review applies doubly to | 221 | - Everything that was said above about code review applies doubly to |
222 | closed-source code. Since this code is not available at all, it cannot | 222 | closed-source code. Since this code is not available at all, it cannot |
223 | have been reviewed by the community and will, beyond doubt, have serious | 223 | have been reviewed by the community and will, beyond doubt, have serious |
224 | problems. | 224 | problems. |
225 | 225 | ||
226 | Makers of embedded systems, in particular, may be tempted to disregard much | 226 | Makers of embedded systems, in particular, may be tempted to disregard much |
227 | of what has been said in this section in the belief that they are shipping | 227 | of what has been said in this section in the belief that they are shipping |
diff --git a/Documentation/development-process/2.Process b/Documentation/development-process/2.Process index 911a45186340..4823577c6509 100644 --- a/Documentation/development-process/2.Process +++ b/Documentation/development-process/2.Process | |||
@@ -14,16 +14,15 @@ The kernel developers use a loosely time-based release process, with a new | |||
14 | major kernel release happening every two or three months. The recent | 14 | major kernel release happening every two or three months. The recent |
15 | release history looks like this: | 15 | release history looks like this: |
16 | 16 | ||
17 | 2.6.26 July 13, 2008 | 17 | 2.6.38 March 14, 2011 |
18 | 2.6.25 April 16, 2008 | 18 | 2.6.37 January 4, 2011 |
19 | 2.6.24 January 24, 2008 | 19 | 2.6.36 October 20, 2010 |
20 | 2.6.23 October 9, 2007 | 20 | 2.6.35 August 1, 2010 |
21 | 2.6.22 July 8, 2007 | 21 | 2.6.34 May 15, 2010 |
22 | 2.6.21 April 25, 2007 | 22 | 2.6.33 February 24, 2010 |
23 | 2.6.20 February 4, 2007 | ||
24 | 23 | ||
25 | Every 2.6.x release is a major kernel release with new features, internal | 24 | Every 2.6.x release is a major kernel release with new features, internal |
26 | API changes, and more. A typical 2.6 release can contain over 10,000 | 25 | API changes, and more. A typical 2.6 release can contain nearly 10,000 |
27 | changesets with changes to several hundred thousand lines of code. 2.6 is | 26 | changesets with changes to several hundred thousand lines of code. 2.6 is |
28 | thus the leading edge of Linux kernel development; the kernel uses a | 27 | thus the leading edge of Linux kernel development; the kernel uses a |
29 | rolling development model which is continually integrating major changes. | 28 | rolling development model which is continually integrating major changes. |
@@ -42,13 +41,13 @@ merge window do not come out of thin air; they have been collected, tested, | |||
42 | and staged ahead of time. How that process works will be described in | 41 | and staged ahead of time. How that process works will be described in |
43 | detail later on). | 42 | detail later on). |
44 | 43 | ||
45 | The merge window lasts for two weeks. At the end of this time, Linus | 44 | The merge window lasts for approximately two weeks. At the end of this |
46 | Torvalds will declare that the window is closed and release the first of | 45 | time, Linus Torvalds will declare that the window is closed and release the |
47 | the "rc" kernels. For the kernel which is destined to be 2.6.26, for | 46 | first of the "rc" kernels. For the kernel which is destined to be 2.6.40, |
48 | example, the release which happens at the end of the merge window will be | 47 | for example, the release which happens at the end of the merge window will |
49 | called 2.6.26-rc1. The -rc1 release is the signal that the time to merge | 48 | be called 2.6.40-rc1. The -rc1 release is the signal that the time to |
50 | new features has passed, and that the time to stabilize the next kernel has | 49 | merge new features has passed, and that the time to stabilize the next |
51 | begun. | 50 | kernel has begun. |
52 | 51 | ||
53 | Over the next six to ten weeks, only patches which fix problems should be | 52 | Over the next six to ten weeks, only patches which fix problems should be |
54 | submitted to the mainline. On occasion a more significant change will be | 53 | submitted to the mainline. On occasion a more significant change will be |
@@ -66,20 +65,19 @@ will get up to somewhere between -rc6 and -rc9 before the kernel is | |||
66 | considered to be sufficiently stable and the final 2.6.x release is made. | 65 | considered to be sufficiently stable and the final 2.6.x release is made. |
67 | At that point the whole process starts over again. | 66 | At that point the whole process starts over again. |
68 | 67 | ||
69 | As an example, here is how the 2.6.25 development cycle went (all dates in | 68 | As an example, here is how the 2.6.38 development cycle went (all dates in |
70 | 2008): | 69 | 2011): |
71 | 70 | ||
72 | January 24 2.6.24 stable release | 71 | January 4 2.6.37 stable release |
73 | February 10 2.6.25-rc1, merge window closes | 72 | January 18 2.6.38-rc1, merge window closes |
74 | February 15 2.6.25-rc2 | 73 | January 21 2.6.38-rc2 |
75 | February 24 2.6.25-rc3 | 74 | February 1 2.6.38-rc3 |
76 | March 4 2.6.25-rc4 | 75 | February 7 2.6.38-rc4 |
77 | March 9 2.6.25-rc5 | 76 | February 15 2.6.38-rc5 |
78 | March 16 2.6.25-rc6 | 77 | February 21 2.6.38-rc6 |
79 | March 25 2.6.25-rc7 | 78 | March 1 2.6.38-rc7 |
80 | April 1 2.6.25-rc8 | 79 | March 7 2.6.38-rc8 |
81 | April 11 2.6.25-rc9 | 80 | March 14 2.6.38 stable release |
82 | April 16 2.6.25 stable release | ||
83 | 81 | ||
84 | How do the developers decide when to close the development cycle and create | 82 | How do the developers decide when to close the development cycle and create |
85 | the stable release? The most significant metric used is the list of | 83 | the stable release? The most significant metric used is the list of |
@@ -87,7 +85,7 @@ regressions from previous releases. No bugs are welcome, but those which | |||
87 | break systems which worked in the past are considered to be especially | 85 | break systems which worked in the past are considered to be especially |
88 | serious. For this reason, patches which cause regressions are looked upon | 86 | serious. For this reason, patches which cause regressions are looked upon |
89 | unfavorably and are quite likely to be reverted during the stabilization | 87 | unfavorably and are quite likely to be reverted during the stabilization |
90 | period. | 88 | period. |
91 | 89 | ||
92 | The developers' goal is to fix all known regressions before the stable | 90 | The developers' goal is to fix all known regressions before the stable |
93 | release is made. In the real world, this kind of perfection is hard to | 91 | release is made. In the real world, this kind of perfection is hard to |
@@ -99,26 +97,34 @@ kernels go out with a handful of known regressions though, hopefully, none | |||
99 | of them are serious. | 97 | of them are serious. |
100 | 98 | ||
101 | Once a stable release is made, its ongoing maintenance is passed off to the | 99 | Once a stable release is made, its ongoing maintenance is passed off to the |
102 | "stable team," currently comprised of Greg Kroah-Hartman and Chris Wright. | 100 | "stable team," currently consisting of Greg Kroah-Hartman. The stable team |
103 | The stable team will release occasional updates to the stable release using | 101 | will release occasional updates to the stable release using the 2.6.x.y |
104 | the 2.6.x.y numbering scheme. To be considered for an update release, a | 102 | numbering scheme. To be considered for an update release, a patch must (1) |
105 | patch must (1) fix a significant bug, and (2) already be merged into the | 103 | fix a significant bug, and (2) already be merged into the mainline for the |
106 | mainline for the next development kernel. Continuing our 2.6.25 example, | 104 | next development kernel. Kernels will typically receive stable updates for |
107 | the history (as of this writing) is: | 105 | a little more than one development cycle past their initial release. So, |
108 | 106 | for example, the 2.6.36 kernel's history looked like: | |
109 | May 1 2.6.25.1 | 107 | |
110 | May 6 2.6.25.2 | 108 | October 10 2.6.36 stable release |
111 | May 9 2.6.25.3 | 109 | November 22 2.6.36.1 |
112 | May 15 2.6.25.4 | 110 | December 9 2.6.36.2 |
113 | June 7 2.6.25.5 | 111 | January 7 2.6.36.3 |
114 | June 9 2.6.25.6 | 112 | February 17 2.6.36.4 |
115 | June 16 2.6.25.7 | 113 | |
116 | June 21 2.6.25.8 | 114 | 2.6.36.4 was the final stable update for the 2.6.36 release. |
117 | June 24 2.6.25.9 | 115 | |
118 | 116 | Some kernels are designated "long term" kernels; they will receive support | |
119 | Stable updates for a given kernel are made for approximately six months; | 117 | for a longer period. As of this writing, the current long term kernels |
120 | after that, the maintenance of stable releases is solely the responsibility | 118 | and their maintainers are: |
121 | of the distributors which have shipped that particular kernel. | 119 | |
120 | 2.6.27 Willy Tarreau (Deep-frozen stable kernel) | ||
121 | 2.6.32 Greg Kroah-Hartman | ||
122 | 2.6.35 Andi Kleen (Embedded flag kernel) | ||
123 | |||
124 | The selection of a kernel for long-term support is purely a matter of a | ||
125 | maintainer having the need and the time to maintain that release. There | ||
126 | are no known plans for long-term support for any specific upcoming | ||
127 | release. | ||
122 | 128 | ||
123 | 129 | ||
124 | 2.2: THE LIFECYCLE OF A PATCH | 130 | 2.2: THE LIFECYCLE OF A PATCH |
@@ -130,7 +136,7 @@ each patch implements a change which is desirable to have in the mainline. | |||
130 | This process can happen quickly for minor fixes, or, in the case of large | 136 | This process can happen quickly for minor fixes, or, in the case of large |
131 | and controversial changes, go on for years. Much developer frustration | 137 | and controversial changes, go on for years. Much developer frustration |
132 | comes from a lack of understanding of this process or from attempts to | 138 | comes from a lack of understanding of this process or from attempts to |
133 | circumvent it. | 139 | circumvent it. |
134 | 140 | ||
135 | In the hopes of reducing that frustration, this document will describe how | 141 | In the hopes of reducing that frustration, this document will describe how |
136 | a patch gets into the kernel. What follows below is an introduction which | 142 | a patch gets into the kernel. What follows below is an introduction which |
@@ -193,8 +199,8 @@ involved. | |||
193 | 2.3: HOW PATCHES GET INTO THE KERNEL | 199 | 2.3: HOW PATCHES GET INTO THE KERNEL |
194 | 200 | ||
195 | There is exactly one person who can merge patches into the mainline kernel | 201 | There is exactly one person who can merge patches into the mainline kernel |
196 | repository: Linus Torvalds. But, of the over 12,000 patches which went | 202 | repository: Linus Torvalds. But, of the over 9,500 patches which went |
197 | into the 2.6.25 kernel, only 250 (around 2%) were directly chosen by Linus | 203 | into the 2.6.38 kernel, only 112 (around 1.3%) were directly chosen by Linus |
198 | himself. The kernel project has long since grown to a size where no single | 204 | himself. The kernel project has long since grown to a size where no single |
199 | developer could possibly inspect and select every patch unassisted. The | 205 | developer could possibly inspect and select every patch unassisted. The |
200 | way the kernel developers have addressed this growth is through the use of | 206 | way the kernel developers have addressed this growth is through the use of |
@@ -229,7 +235,7 @@ first in trees dedicated to network device drivers, wireless networking, | |||
229 | etc. This chain of repositories can be arbitrarily long, though it rarely | 235 | etc. This chain of repositories can be arbitrarily long, though it rarely |
230 | exceeds two or three links. Since each maintainer in the chain trusts | 236 | exceeds two or three links. Since each maintainer in the chain trusts |
231 | those managing lower-level trees, this process is known as the "chain of | 237 | those managing lower-level trees, this process is known as the "chain of |
232 | trust." | 238 | trust." |
233 | 239 | ||
234 | Clearly, in a system like this, getting patches into the kernel depends on | 240 | Clearly, in a system like this, getting patches into the kernel depends on |
235 | finding the right maintainer. Sending patches directly to Linus is not | 241 | finding the right maintainer. Sending patches directly to Linus is not |
@@ -254,7 +260,7 @@ The answer comes in the form of -next trees, where subsystem trees are | |||
254 | collected for testing and review. The older of these trees, maintained by | 260 | collected for testing and review. The older of these trees, maintained by |
255 | Andrew Morton, is called "-mm" (for memory management, which is how it got | 261 | Andrew Morton, is called "-mm" (for memory management, which is how it got |
256 | started). The -mm tree integrates patches from a long list of subsystem | 262 | started). The -mm tree integrates patches from a long list of subsystem |
257 | trees; it also has some patches aimed at helping with debugging. | 263 | trees; it also has some patches aimed at helping with debugging. |
258 | 264 | ||
259 | Beyond that, -mm contains a significant collection of patches which have | 265 | Beyond that, -mm contains a significant collection of patches which have |
260 | been selected by Andrew directly. These patches may have been posted on a | 266 | been selected by Andrew directly. These patches may have been posted on a |
@@ -264,8 +270,8 @@ subsystem tree of last resort; if there is no other obvious path for a | |||
264 | patch into the mainline, it is likely to end up in -mm. Miscellaneous | 270 | patch into the mainline, it is likely to end up in -mm. Miscellaneous |
265 | patches which accumulate in -mm will eventually either be forwarded on to | 271 | patches which accumulate in -mm will eventually either be forwarded on to |
266 | an appropriate subsystem tree or be sent directly to Linus. In a typical | 272 | an appropriate subsystem tree or be sent directly to Linus. In a typical |
267 | development cycle, approximately 10% of the patches going into the mainline | 273 | development cycle, approximately 5-10% of the patches going into the |
268 | get there via -mm. | 274 | mainline get there via -mm. |
269 | 275 | ||
270 | The current -mm patch is available in the "mmotm" (-mm of the moment) | 276 | The current -mm patch is available in the "mmotm" (-mm of the moment) |
271 | directory at: | 277 | directory at: |
@@ -275,7 +281,7 @@ directory at: | |||
275 | Use of the MMOTM tree is likely to be a frustrating experience, though; | 281 | Use of the MMOTM tree is likely to be a frustrating experience, though; |
276 | there is a definite chance that it will not even compile. | 282 | there is a definite chance that it will not even compile. |
277 | 283 | ||
278 | The other -next tree, started more recently, is linux-next, maintained by | 284 | The primary tree for next-cycle patch merging is linux-next, maintained by |
279 | Stephen Rothwell. The linux-next tree is, by design, a snapshot of what | 285 | Stephen Rothwell. The linux-next tree is, by design, a snapshot of what |
280 | the mainline is expected to look like after the next merge window closes. | 286 | the mainline is expected to look like after the next merge window closes. |
281 | Linux-next trees are announced on the linux-kernel and linux-next mailing | 287 | Linux-next trees are announced on the linux-kernel and linux-next mailing |
@@ -287,25 +293,14 @@ Some information about linux-next has been gathered at: | |||
287 | 293 | ||
288 | http://linux.f-seidel.de/linux-next/pmwiki/ | 294 | http://linux.f-seidel.de/linux-next/pmwiki/ |
289 | 295 | ||
290 | How the linux-next tree will fit into the development process is still | 296 | Linux-next has become an integral part of the kernel development process; |
291 | changing. As of this writing, the first full development cycle involving | 297 | all patches merged during a given merge window should really have found |
292 | linux-next (2.6.26) is coming to an end; thus far, it has proved to be a | 298 | their way into linux-next some time before the merge window opens. |
293 | valuable resource for finding and fixing integration problems before the | 299 | |
294 | beginning of the merge window. See http://lwn.net/Articles/287155/ for | ||
295 | more information on how linux-next has worked to set up the 2.6.27 merge | ||
296 | window. | ||
297 | |||
298 | Some developers have begun to suggest that linux-next should be used as the | ||
299 | target for future development as well. The linux-next tree does tend to be | ||
300 | far ahead of the mainline and is more representative of the tree into which | ||
301 | any new work will be merged. The downside to this idea is that the | ||
302 | volatility of linux-next tends to make it a difficult development target. | ||
303 | See http://lwn.net/Articles/289013/ for more information on this topic, and | ||
304 | stay tuned; much is still in flux where linux-next is involved. | ||
305 | 300 | ||
306 | 2.4.1: STAGING TREES | 301 | 2.4.1: STAGING TREES |
307 | 302 | ||
308 | The kernel source tree now contains the drivers/staging/ directory, where | 303 | The kernel source tree contains the drivers/staging/ directory, where |
309 | many sub-directories for drivers or filesystems that are on their way to | 304 | many sub-directories for drivers or filesystems that are on their way to |
310 | being added to the kernel tree live. They remain in drivers/staging while | 305 | being added to the kernel tree live. They remain in drivers/staging while |
311 | they still need more work; once complete, they can be moved into the | 306 | they still need more work; once complete, they can be moved into the |
@@ -313,15 +308,23 @@ kernel proper. This is a way to keep track of drivers that aren't | |||
313 | up to Linux kernel coding or quality standards, but people may want to use | 308 | up to Linux kernel coding or quality standards, but people may want to use |
314 | them and track development. | 309 | them and track development. |
315 | 310 | ||
316 | Greg Kroah-Hartman currently (as of 2.6.36) maintains the staging tree. | 311 | Greg Kroah-Hartman currently maintains the staging tree. Drivers that |
317 | Drivers that still need work are sent to him, with each driver having | 312 | still need work are sent to him, with each driver having its own |
318 | its own subdirectory in drivers/staging/. Along with the driver source | 313 | subdirectory in drivers/staging/. Along with the driver source files, a |
319 | files, a TODO file should be present in the directory as well. The TODO | 314 | TODO file should be present in the directory as well. The TODO file lists |
320 | file lists the pending work that the driver needs for acceptance into | 315 | the pending work that the driver needs for acceptance into the kernel |
321 | the kernel proper, as well as a list of people that should be Cc'd for any | 316 | proper, as well as a list of people that should be Cc'd for any patches to |
322 | patches to the driver. Staging drivers that don't currently build should | 317 | the driver. Current rules require that drivers contributed to staging |
323 | have their config entries depend upon CONFIG_BROKEN. Once they can | 318 | must, at a minimum, compile properly. |
324 | be successfully built without outside patches, CONFIG_BROKEN can be removed. | 319 | |
320 | Staging can be a relatively easy way to get new drivers into the mainline | ||
321 | where, with luck, they will come to the attention of other developers and | ||
322 | improve quickly. Entry into staging is not the end of the story, though; | ||
323 | code in staging which is not seeing regular progress will eventually be | ||
324 | removed. Distributors also tend to be relatively reluctant to enable | ||
325 | staging drivers. So staging is, at best, a stop on the way toward becoming | ||
326 | a proper mainline driver. | ||
327 | |||
325 | 328 | ||
326 | 2.5: TOOLS | 329 | 2.5: TOOLS |
327 | 330 | ||
@@ -347,11 +350,7 @@ page at: | |||
347 | 350 | ||
348 | http://git-scm.com/ | 351 | http://git-scm.com/ |
349 | 352 | ||
350 | That page has pointers to documentation and tutorials. One should be | 353 | That page has pointers to documentation and tutorials. |
351 | aware, in particular, of the Kernel Hacker's Guide to git, which has | ||
352 | information specific to kernel development: | ||
353 | |||
354 | http://linux.yyz.us/git-howto.html | ||
355 | 354 | ||
356 | Among the kernel developers who do not use git, the most popular choice is | 355 | Among the kernel developers who do not use git, the most popular choice is |
357 | almost certainly Mercurial: | 356 | almost certainly Mercurial: |
@@ -408,7 +407,7 @@ There are a few hints which can help with linux-kernel survival: | |||
408 | important to filter on both the topic of interest (though note that | 407 | important to filter on both the topic of interest (though note that |
409 | long-running conversations can drift away from the original subject | 408 | long-running conversations can drift away from the original subject |
410 | without changing the email subject line) and the people who are | 409 | without changing the email subject line) and the people who are |
411 | participating. | 410 | participating. |
412 | 411 | ||
413 | - Do not feed the trolls. If somebody is trying to stir up an angry | 412 | - Do not feed the trolls. If somebody is trying to stir up an angry |
414 | response, ignore them. | 413 | response, ignore them. |
diff --git a/Documentation/development-process/3.Early-stage b/Documentation/development-process/3.Early-stage index 307a159a70ca..f87ba7b3fbac 100644 --- a/Documentation/development-process/3.Early-stage +++ b/Documentation/development-process/3.Early-stage | |||
@@ -110,8 +110,8 @@ the kernel community's standards. Some examples include: | |||
110 | 110 | ||
111 | - The AppArmor security module made use of internal virtual filesystem | 111 | - The AppArmor security module made use of internal virtual filesystem |
112 | data structures in ways which were considered to be unsafe and | 112 | data structures in ways which were considered to be unsafe and |
113 | unreliable. This code has since been significantly reworked, but | 113 | unreliable. This concern (among others) kept AppArmor out of the |
114 | remains outside of the mainline. | 114 | mainline for years. |
115 | 115 | ||
116 | In each of these cases, a great deal of pain and extra work could have been | 116 | In each of these cases, a great deal of pain and extra work could have been |
117 | avoided with some early discussion with the kernel developers. | 117 | avoided with some early discussion with the kernel developers. |
@@ -138,6 +138,19 @@ patches, and who, if anybody, is attaching Signed-off-by lines to those | |||
138 | patches. Those are the people who will be best placed to help with a new | 138 | patches. Those are the people who will be best placed to help with a new |
139 | development project. | 139 | development project. |
140 | 140 | ||
141 | The task of finding the right maintainer is sometimes challenging enough | ||
142 | that the kernel developers have added a script to ease the process: | ||
143 | |||
144 | .../scripts/get_maintainer.pl | ||
145 | |||
146 | This script will return the current maintainer(s) for a given file or | ||
147 | directory when given the "-f" option. If passed a patch on the | ||
148 | command line, it will list the maintainers who should probably receive | ||
149 | copies of the patch. There are a number of options regulating how hard | ||
150 | get_maintainer.pl will search for maintainers; please be careful about | ||
151 | using the more aggressive options as you may end up including developers | ||
152 | who have no real interest in the code you are modifying. | ||
153 | |||
141 | If all else fails, talking to Andrew Morton can be an effective way to | 154 | If all else fails, talking to Andrew Morton can be an effective way to |
142 | track down a maintainer for a specific piece of code. | 155 | track down a maintainer for a specific piece of code. |
143 | 156 | ||
@@ -155,11 +168,15 @@ reaction, but, instead, little or no reaction at all. The sad truth of the | |||
155 | matter is (1) kernel developers tend to be busy, (2) there is no shortage | 168 | matter is (1) kernel developers tend to be busy, (2) there is no shortage |
156 | of people with grand plans and little code (or even prospect of code) to | 169 | of people with grand plans and little code (or even prospect of code) to |
157 | back them up, and (3) nobody is obligated to review or comment on ideas | 170 | back them up, and (3) nobody is obligated to review or comment on ideas |
158 | posted by others. If a request-for-comments posting yields little in the | 171 | posted by others. Beyond that, high-level designs often hide problems |
159 | way of comments, do not assume that it means there is no interest in the | 172 | which are only reviewed when somebody actually tries to implement those |
160 | project. Unfortunately, you also cannot assume that there are no problems | 173 | designs; for that reason, kernel developers would rather see the code. |
161 | with your idea. The best thing to do in this situation is to proceed, | 174 | |
162 | keeping the community informed as you go. | 175 | If a request-for-comments posting yields little in the way of comments, do |
176 | not assume that it means there is no interest in the project. | ||
177 | Unfortunately, you also cannot assume that there are no problems with your | ||
178 | idea. The best thing to do in this situation is to proceed, keeping the | ||
179 | community informed as you go. | ||
163 | 180 | ||
164 | 181 | ||
165 | 3.5: GETTING OFFICIAL BUY-IN | 182 | 3.5: GETTING OFFICIAL BUY-IN |
diff --git a/Documentation/development-process/4.Coding b/Documentation/development-process/4.Coding index 2278693c8ffa..f3f1a469443c 100644 --- a/Documentation/development-process/4.Coding +++ b/Documentation/development-process/4.Coding | |||
@@ -131,6 +131,11 @@ classic time/space tradeoff taught in beginning data structures classes | |||
131 | often does not apply to contemporary hardware. Space *is* time, in that a | 131 | often does not apply to contemporary hardware. Space *is* time, in that a |
132 | larger program will run slower than one which is more compact. | 132 | larger program will run slower than one which is more compact. |
133 | 133 | ||
134 | More recent compilers take an increasingly active role in deciding whether | ||
135 | a given function should actually be inlined or not. So the liberal | ||
136 | placement of "inline" keywords may not just be excessive; it could also be | ||
137 | irrelevant. | ||
138 | |||
134 | 139 | ||
135 | * Locking | 140 | * Locking |
136 | 141 | ||
@@ -285,6 +290,13 @@ be found at https://sparse.wiki.kernel.org/index.php/Main_Page if your | |||
285 | distributor does not package it); it can then be run on the code by adding | 290 | distributor does not package it); it can then be run on the code by adding |
286 | "C=1" to your make command. | 291 | "C=1" to your make command. |
287 | 292 | ||
293 | The "Coccinelle" tool (http://coccinelle.lip6.fr/) is able to find a wide | ||
294 | variety of potential coding problems; it can also propose fixes for those | ||
295 | problems. Quite a few "semantic patches" for the kernel have been packaged | ||
296 | under the scripts/coccinelle directory; running "make coccicheck" will run | ||
297 | through those semantic patches and report on any problems found. See | ||
298 | Documentation/coccinelle.txt for more information. | ||
299 | |||
288 | Other kinds of portability errors are best found by compiling your code for | 300 | Other kinds of portability errors are best found by compiling your code for |
289 | other architectures. If you do not happen to have an S/390 system or a | 301 | other architectures. If you do not happen to have an S/390 system or a |
290 | Blackfin development board handy, you can still perform the compilation | 302 | Blackfin development board handy, you can still perform the compilation |
@@ -308,7 +320,9 @@ The first piece of documentation for any patch is its associated | |||
308 | changelog. Log entries should describe the problem being solved, the form | 320 | changelog. Log entries should describe the problem being solved, the form |
309 | of the solution, the people who worked on the patch, any relevant | 321 | of the solution, the people who worked on the patch, any relevant |
310 | effects on performance, and anything else that might be needed to | 322 | effects on performance, and anything else that might be needed to |
311 | understand the patch. | 323 | understand the patch. Be sure that the changelog says *why* the patch is |
324 | worth applying; a surprising number of developers fail to provide that | ||
325 | information. | ||
312 | 326 | ||
313 | Any code which adds a new user-space interface - including new sysfs or | 327 | Any code which adds a new user-space interface - including new sysfs or |
314 | /proc files - should include documentation of that interface which enables | 328 | /proc files - should include documentation of that interface which enables |
@@ -321,7 +335,7 @@ boot-time parameters. Any patch which adds new parameters should add the | |||
321 | appropriate entries to this file. | 335 | appropriate entries to this file. |
322 | 336 | ||
323 | Any new configuration options must be accompanied by help text which | 337 | Any new configuration options must be accompanied by help text which |
324 | clearly explains the options and when the user might want to select them. | 338 | clearly explains the options and when the user might want to select them. |
325 | 339 | ||
326 | Internal API information for many subsystems is documented by way of | 340 | Internal API information for many subsystems is documented by way of |
327 | specially-formatted comments; these comments can be extracted and formatted | 341 | specially-formatted comments; these comments can be extracted and formatted |
@@ -372,7 +386,8 @@ which is broken by the change. For a widely-used function, this duty can | |||
372 | lead to literally hundreds or thousands of changes - many of which are | 386 | lead to literally hundreds or thousands of changes - many of which are |
373 | likely to conflict with work being done by other developers. Needless to | 387 | likely to conflict with work being done by other developers. Needless to |
374 | say, this can be a large job, so it is best to be sure that the | 388 | say, this can be a large job, so it is best to be sure that the |
375 | justification is solid. | 389 | justification is solid. Note that the Coccinelle tool can help with |
390 | wide-ranging API changes. | ||
376 | 391 | ||
377 | When making an incompatible API change, one should, whenever possible, | 392 | When making an incompatible API change, one should, whenever possible, |
378 | ensure that code which has not been updated is caught by the compiler. | 393 | ensure that code which has not been updated is caught by the compiler. |
diff --git a/Documentation/development-process/5.Posting b/Documentation/development-process/5.Posting index f622c1e9f0f9..903a2546f138 100644 --- a/Documentation/development-process/5.Posting +++ b/Documentation/development-process/5.Posting | |||
@@ -60,12 +60,15 @@ even in the short term. | |||
60 | 60 | ||
61 | Patches must be prepared against a specific version of the kernel. As a | 61 | Patches must be prepared against a specific version of the kernel. As a |
62 | general rule, a patch should be based on the current mainline as found in | 62 | general rule, a patch should be based on the current mainline as found in |
63 | Linus's git tree. It may become necessary to make versions against -mm, | 63 | Linus's git tree. When basing on mainline, start with a well-known release |
64 | linux-next, or a subsystem tree, though, to facilitate wider testing and | 64 | point - a stable or -rc release - rather than branching off the mainline at |
65 | review. Depending on the area of your patch and what is going on | 65 | an arbitrary spot. |
66 | elsewhere, basing a patch against these other trees can require a | 66 | |
67 | significant amount of work resolving conflicts and dealing with API | 67 | It may become necessary to make versions against -mm, linux-next, or a |
68 | changes. | 68 | subsystem tree, though, to facilitate wider testing and review. Depending |
69 | on the area of your patch and what is going on elsewhere, basing a patch | ||
70 | against these other trees can require a significant amount of work | ||
71 | resolving conflicts and dealing with API changes. | ||
69 | 72 | ||
70 | Only the most simple changes should be formatted as a single patch; | 73 | Only the most simple changes should be formatted as a single patch; |
71 | everything else should be made as a logical series of changes. Splitting | 74 | everything else should be made as a logical series of changes. Splitting |
@@ -100,11 +103,11 @@ rules of thumb, however, which can help considerably: | |||
100 | result is a broken kernel, you will make life harder for developers and | 103 | result is a broken kernel, you will make life harder for developers and |
101 | users who are engaging in the noble work of tracking down problems. | 104 | users who are engaging in the noble work of tracking down problems. |
102 | 105 | ||
103 | - Do not overdo it, though. One developer recently posted a set of edits | 106 | - Do not overdo it, though. One developer once posted a set of edits |
104 | to a single file as 500 separate patches - an act which did not make him | 107 | to a single file as 500 separate patches - an act which did not make him |
105 | the most popular person on the kernel mailing list. A single patch can | 108 | the most popular person on the kernel mailing list. A single patch can |
106 | be reasonably large as long as it still contains a single *logical* | 109 | be reasonably large as long as it still contains a single *logical* |
107 | change. | 110 | change. |
108 | 111 | ||
109 | - It can be tempting to add a whole new infrastructure with a series of | 112 | - It can be tempting to add a whole new infrastructure with a series of |
110 | patches, but to leave that infrastructure unused until the final patch | 113 | patches, but to leave that infrastructure unused until the final patch |
@@ -162,7 +165,8 @@ To that end, the summary line should describe the effects of and motivation | |||
162 | for the change as well as possible given the one-line constraint. The | 165 | for the change as well as possible given the one-line constraint. The |
163 | detailed description can then amplify on those topics and provide any | 166 | detailed description can then amplify on those topics and provide any |
164 | needed additional information. If the patch fixes a bug, cite the commit | 167 | needed additional information. If the patch fixes a bug, cite the commit |
165 | which introduced the bug if possible. If a problem is associated with | 168 | which introduced the bug if possible (and please provide both the commit ID |
169 | and the title when citing commits). If a problem is associated with | ||
166 | specific log or compiler output, include that output to help others | 170 | specific log or compiler output, include that output to help others |
167 | searching for a solution to the same problem. If the change is meant to | 171 | searching for a solution to the same problem. If the change is meant to |
168 | support other changes coming in later patch, say so. If internal APIs are | 172 | support other changes coming in later patch, say so. If internal APIs are |
@@ -230,7 +234,7 @@ take care of: | |||
230 | which have had gratuitous white-space changes or line wrapping performed | 234 | which have had gratuitous white-space changes or line wrapping performed |
231 | by the mail client will not apply at the other end, and often will not | 235 | by the mail client will not apply at the other end, and often will not |
232 | be examined in any detail. If there is any doubt at all, mail the patch | 236 | be examined in any detail. If there is any doubt at all, mail the patch |
233 | to yourself and convince yourself that it shows up intact. | 237 | to yourself and convince yourself that it shows up intact. |
234 | 238 | ||
235 | Documentation/email-clients.txt has some helpful hints on making | 239 | Documentation/email-clients.txt has some helpful hints on making |
236 | specific mail clients work for sending patches. | 240 | specific mail clients work for sending patches. |
@@ -287,7 +291,7 @@ something like: | |||
287 | 291 | ||
288 | where "nn" is the ordinal number of the patch, "mm" is the total number of | 292 | where "nn" is the ordinal number of the patch, "mm" is the total number of |
289 | patches in the series, and "subsys" is the name of the affected subsystem. | 293 | patches in the series, and "subsys" is the name of the affected subsystem. |
290 | Clearly, nn/mm can be omitted for a single, standalone patch. | 294 | Clearly, nn/mm can be omitted for a single, standalone patch. |
291 | 295 | ||
292 | If you have a significant series of patches, it is customary to send an | 296 | If you have a significant series of patches, it is customary to send an |
293 | introductory description as part zero. This convention is not universally | 297 | introductory description as part zero. This convention is not universally |
@@ -299,5 +303,5 @@ In general, the second and following parts of a multi-part patch should be | |||
299 | sent as a reply to the first part so that they all thread together at the | 303 | sent as a reply to the first part so that they all thread together at the |
300 | receiving end. Tools like git and quilt have commands to mail out a set of | 304 | receiving end. Tools like git and quilt have commands to mail out a set of |
301 | patches with the proper threading. If you have a long series, though, and | 305 | patches with the proper threading. If you have a long series, though, and |
302 | are using git, please provide the --no-chain-reply-to option to avoid | 306 | are using git, please stay away from the --chain-reply-to option to avoid |
303 | creating exceptionally deep nesting. | 307 | creating exceptionally deep nesting. |
diff --git a/Documentation/development-process/6.Followthrough b/Documentation/development-process/6.Followthrough index a8fba3d83a85..41d324a9420d 100644 --- a/Documentation/development-process/6.Followthrough +++ b/Documentation/development-process/6.Followthrough | |||
@@ -66,6 +66,11 @@ be easy to become blinded by your own solution to a problem to the point | |||
66 | that you don't realize that something is fundamentally wrong or, perhaps, | 66 | that you don't realize that something is fundamentally wrong or, perhaps, |
67 | you're not even solving the right problem. | 67 | you're not even solving the right problem. |
68 | 68 | ||
69 | Andrew Morton has suggested that every review comment which does not result | ||
70 | in a code change should result in an additional code comment instead; that | ||
71 | can help future reviewers avoid the questions which came up the first time | ||
72 | around. | ||
73 | |||
69 | One fatal mistake is to ignore review comments in the hope that they will | 74 | One fatal mistake is to ignore review comments in the hope that they will |
70 | go away. They will not go away. If you repost code without having | 75 | go away. They will not go away. If you repost code without having |
71 | responded to the comments you got the time before, you're likely to find | 76 | responded to the comments you got the time before, you're likely to find |
@@ -100,7 +105,7 @@ entry into a subsystem maintainer's tree. How that works varies from one | |||
100 | subsystem to the next; each maintainer has his or her own way of doing | 105 | subsystem to the next; each maintainer has his or her own way of doing |
101 | things. In particular, there may be more than one tree - one, perhaps, | 106 | things. In particular, there may be more than one tree - one, perhaps, |
102 | dedicated to patches planned for the next merge window, and another for | 107 | dedicated to patches planned for the next merge window, and another for |
103 | longer-term work. | 108 | longer-term work. |
104 | 109 | ||
105 | For patches applying to areas for which there is no obvious subsystem tree | 110 | For patches applying to areas for which there is no obvious subsystem tree |
106 | (memory management patches, for example), the default tree often ends up | 111 | (memory management patches, for example), the default tree often ends up |
@@ -109,11 +114,10 @@ through the -mm tree. | |||
109 | 114 | ||
110 | Inclusion into a subsystem tree can bring a higher level of visibility to a | 115 | Inclusion into a subsystem tree can bring a higher level of visibility to a |
111 | patch. Now other developers working with that tree will get the patch by | 116 | patch. Now other developers working with that tree will get the patch by |
112 | default. Subsystem trees typically feed into -mm and linux-next as well, | 117 | default. Subsystem trees typically feed linux-next as well, making their |
113 | making their contents visible to the development community as a whole. At | 118 | contents visible to the development community as a whole. At this point, |
114 | this point, there's a good chance that you will get more comments from a | 119 | there's a good chance that you will get more comments from a new set of |
115 | new set of reviewers; these comments need to be answered as in the previous | 120 | reviewers; these comments need to be answered as in the previous round. |
116 | round. | ||
117 | 121 | ||
118 | What may also happen at this point, depending on the nature of your patch, | 122 | What may also happen at this point, depending on the nature of your patch, |
119 | is that conflicts with work being done by others turn up. In the worst | 123 | is that conflicts with work being done by others turn up. In the worst |
diff --git a/Documentation/development-process/7.AdvancedTopics b/Documentation/development-process/7.AdvancedTopics index 837179447e17..26dc3fa196e4 100644 --- a/Documentation/development-process/7.AdvancedTopics +++ b/Documentation/development-process/7.AdvancedTopics | |||
@@ -119,7 +119,7 @@ can affect your ability to get trees pulled in the future. Quoting Linus: | |||
119 | to trust things *without* then having to go and check every | 119 | to trust things *without* then having to go and check every |
120 | individual change by hand. | 120 | individual change by hand. |
121 | 121 | ||
122 | (http://lwn.net/Articles/224135/). | 122 | (http://lwn.net/Articles/224135/). |
123 | 123 | ||
124 | To avoid this kind of situation, ensure that all patches within a given | 124 | To avoid this kind of situation, ensure that all patches within a given |
125 | branch stick closely to the associated topic; a "driver fixes" branch | 125 | branch stick closely to the associated topic; a "driver fixes" branch |
@@ -138,7 +138,7 @@ When requesting a pull, be sure to give all the relevant information: where | |||
138 | your tree is, what branch to pull, and what changes will result from the | 138 | your tree is, what branch to pull, and what changes will result from the |
139 | pull. The git request-pull command can be helpful in this regard; it will | 139 | pull. The git request-pull command can be helpful in this regard; it will |
140 | format the request as other developers expect, and will also check to be | 140 | format the request as other developers expect, and will also check to be |
141 | sure that you have remembered to push those changes to the public server. | 141 | sure that you have remembered to push those changes to the public server. |
142 | 142 | ||
143 | 143 | ||
144 | 7.2: REVIEWING PATCHES | 144 | 7.2: REVIEWING PATCHES |
diff --git a/Documentation/device-mapper/dm-flakey.txt b/Documentation/device-mapper/dm-flakey.txt new file mode 100644 index 000000000000..c8efdfd19a65 --- /dev/null +++ b/Documentation/device-mapper/dm-flakey.txt | |||
@@ -0,0 +1,17 @@ | |||
1 | dm-flakey | ||
2 | ========= | ||
3 | |||
4 | This target is the same as the linear target except that it returns I/O | ||
5 | errors periodically. It's been found useful in simulating failing | ||
6 | devices for testing purposes. | ||
7 | |||
8 | Starting from the time the table is loaded, the device is available for | ||
9 | <up interval> seconds, then returns errors for <down interval> seconds, | ||
10 | and then this cycle repeats. | ||
11 | |||
12 | Parameters: <dev path> <offset> <up interval> <down interval> | ||
13 | <dev path>: Full pathname to the underlying block-device, or a | ||
14 | "major:minor" device-number. | ||
15 | <offset>: Starting sector within the device. | ||
16 | <up interval>: Number of seconds device is available. | ||
17 | <down interval>: Number of seconds device returns errors. | ||
diff --git a/Documentation/dynamic-debug-howto.txt b/Documentation/dynamic-debug-howto.txt index e6c4b757025b..f959909d7154 100644 --- a/Documentation/dynamic-debug-howto.txt +++ b/Documentation/dynamic-debug-howto.txt | |||
@@ -6,7 +6,7 @@ This document describes how to use the dynamic debug (ddebug) feature. | |||
6 | 6 | ||
7 | Dynamic debug is designed to allow you to dynamically enable/disable kernel | 7 | Dynamic debug is designed to allow you to dynamically enable/disable kernel |
8 | code to obtain additional kernel information. Currently, if | 8 | code to obtain additional kernel information. Currently, if |
9 | CONFIG_DYNAMIC_DEBUG is set, then all pr_debug()/dev_debug() calls can be | 9 | CONFIG_DYNAMIC_DEBUG is set, then all pr_debug()/dev_dbg() calls can be |
10 | dynamically enabled per-callsite. | 10 | dynamically enabled per-callsite. |
11 | 11 | ||
12 | Dynamic debug has even more useful features: | 12 | Dynamic debug has even more useful features: |
@@ -26,7 +26,7 @@ Dynamic debug has even more useful features: | |||
26 | Controlling dynamic debug Behaviour | 26 | Controlling dynamic debug Behaviour |
27 | =================================== | 27 | =================================== |
28 | 28 | ||
29 | The behaviour of pr_debug()/dev_debug()s are controlled via writing to a | 29 | The behaviour of pr_debug()/dev_dbg()s are controlled via writing to a |
30 | control file in the 'debugfs' filesystem. Thus, you must first mount the debugfs | 30 | control file in the 'debugfs' filesystem. Thus, you must first mount the debugfs |
31 | filesystem, in order to make use of this feature. Subsequently, we refer to the | 31 | filesystem, in order to make use of this feature. Subsequently, we refer to the |
32 | control file as: <debugfs>/dynamic_debug/control. For example, if you want to | 32 | control file as: <debugfs>/dynamic_debug/control. For example, if you want to |
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 2e994efe12cb..61b31acb9176 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking | |||
@@ -128,7 +128,7 @@ alloc_inode: | |||
128 | destroy_inode: | 128 | destroy_inode: |
129 | dirty_inode: (must not sleep) | 129 | dirty_inode: (must not sleep) |
130 | write_inode: | 130 | write_inode: |
131 | drop_inode: !!!inode_lock!!! | 131 | drop_inode: !!!inode->i_lock!!! |
132 | evict_inode: | 132 | evict_inode: |
133 | put_super: write | 133 | put_super: write |
134 | write_super: read | 134 | write_super: read |
diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt index 6ab9442d7eeb..6b050464a90d 100644 --- a/Documentation/filesystems/ext4.txt +++ b/Documentation/filesystems/ext4.txt | |||
@@ -367,12 +367,47 @@ init_itable=n The lazy itable init code will wait n times the | |||
367 | minimizes the impact on the systme performance | 367 | minimizes the impact on the systme performance |
368 | while file system's inode table is being initialized. | 368 | while file system's inode table is being initialized. |
369 | 369 | ||
370 | discard Controls whether ext4 should issue discard/TRIM | 370 | discard Controls whether ext4 should issue discard/TRIM |
371 | nodiscard(*) commands to the underlying block device when | 371 | nodiscard(*) commands to the underlying block device when |
372 | blocks are freed. This is useful for SSD devices | 372 | blocks are freed. This is useful for SSD devices |
373 | and sparse/thinly-provisioned LUNs, but it is off | 373 | and sparse/thinly-provisioned LUNs, but it is off |
374 | by default until sufficient testing has been done. | 374 | by default until sufficient testing has been done. |
375 | 375 | ||
376 | nouid32 Disables 32-bit UIDs and GIDs. This is for | ||
377 | interoperability with older kernels which only | ||
378 | store and expect 16-bit values. | ||
379 | |||
380 | resize Allows to resize filesystem to the end of the last | ||
381 | existing block group, further resize has to be done | ||
382 | with resize2fs either online, or offline. It can be | ||
383 | used only with conjunction with remount. | ||
384 | |||
385 | block_validity This options allows to enables/disables the in-kernel | ||
386 | noblock_validity facility for tracking filesystem metadata blocks | ||
387 | within internal data structures. This allows multi- | ||
388 | block allocator and other routines to quickly locate | ||
389 | extents which might overlap with filesystem metadata | ||
390 | blocks. This option is intended for debugging | ||
391 | purposes and since it negatively affects the | ||
392 | performance, it is off by default. | ||
393 | |||
394 | dioread_lock Controls whether or not ext4 should use the DIO read | ||
395 | dioread_nolock locking. If the dioread_nolock option is specified | ||
396 | ext4 will allocate uninitialized extent before buffer | ||
397 | write and convert the extent to initialized after IO | ||
398 | completes. This approach allows ext4 code to avoid | ||
399 | using inode mutex, which improves scalability on high | ||
400 | speed storages. However this does not work with nobh | ||
401 | option and the mount will fail. Nor does it work with | ||
402 | data journaling and dioread_nolock option will be | ||
403 | ignored with kernel warning. Note that dioread_nolock | ||
404 | code path is only used for extent-based files. | ||
405 | Because of the restrictions this options comprises | ||
406 | it is off by default (e.g. dioread_lock). | ||
407 | |||
408 | i_version Enable 64-bit inode version support. This option is | ||
409 | off by default. | ||
410 | |||
376 | Data Mode | 411 | Data Mode |
377 | ========= | 412 | ========= |
378 | There are 3 different data modes: | 413 | There are 3 different data modes: |
@@ -400,6 +435,176 @@ needs to be read from and written to disk at the same time where it | |||
400 | outperforms all others modes. Currently ext4 does not have delayed | 435 | outperforms all others modes. Currently ext4 does not have delayed |
401 | allocation support if this data journalling mode is selected. | 436 | allocation support if this data journalling mode is selected. |
402 | 437 | ||
438 | /proc entries | ||
439 | ============= | ||
440 | |||
441 | Information about mounted ext4 file systems can be found in | ||
442 | /proc/fs/ext4. Each mounted filesystem will have a directory in | ||
443 | /proc/fs/ext4 based on its device name (i.e., /proc/fs/ext4/hdc or | ||
444 | /proc/fs/ext4/dm-0). The files in each per-device directory are shown | ||
445 | in table below. | ||
446 | |||
447 | Files in /proc/fs/ext4/<devname> | ||
448 | .............................................................................. | ||
449 | File Content | ||
450 | mb_groups details of multiblock allocator buddy cache of free blocks | ||
451 | .............................................................................. | ||
452 | |||
453 | /sys entries | ||
454 | ============ | ||
455 | |||
456 | Information about mounted ext4 file systems can be found in | ||
457 | /sys/fs/ext4. Each mounted filesystem will have a directory in | ||
458 | /sys/fs/ext4 based on its device name (i.e., /sys/fs/ext4/hdc or | ||
459 | /sys/fs/ext4/dm-0). The files in each per-device directory are shown | ||
460 | in table below. | ||
461 | |||
462 | Files in /sys/fs/ext4/<devname> | ||
463 | (see also Documentation/ABI/testing/sysfs-fs-ext4) | ||
464 | .............................................................................. | ||
465 | File Content | ||
466 | |||
467 | delayed_allocation_blocks This file is read-only and shows the number of | ||
468 | blocks that are dirty in the page cache, but | ||
469 | which do not have their location in the | ||
470 | filesystem allocated yet. | ||
471 | |||
472 | inode_goal Tuning parameter which (if non-zero) controls | ||
473 | the goal inode used by the inode allocator in | ||
474 | preference to all other allocation heuristics. | ||
475 | This is intended for debugging use only, and | ||
476 | should be 0 on production systems. | ||
477 | |||
478 | inode_readahead_blks Tuning parameter which controls the maximum | ||
479 | number of inode table blocks that ext4's inode | ||
480 | table readahead algorithm will pre-read into | ||
481 | the buffer cache | ||
482 | |||
483 | lifetime_write_kbytes This file is read-only and shows the number of | ||
484 | kilobytes of data that have been written to this | ||
485 | filesystem since it was created. | ||
486 | |||
487 | max_writeback_mb_bump The maximum number of megabytes the writeback | ||
488 | code will try to write out before move on to | ||
489 | another inode. | ||
490 | |||
491 | mb_group_prealloc The multiblock allocator will round up allocation | ||
492 | requests to a multiple of this tuning parameter if | ||
493 | the stripe size is not set in the ext4 superblock | ||
494 | |||
495 | mb_max_to_scan The maximum number of extents the multiblock | ||
496 | allocator will search to find the best extent | ||
497 | |||
498 | mb_min_to_scan The minimum number of extents the multiblock | ||
499 | allocator will search to find the best extent | ||
500 | |||
501 | mb_order2_req Tuning parameter which controls the minimum size | ||
502 | for requests (as a power of 2) where the buddy | ||
503 | cache is used | ||
504 | |||
505 | mb_stats Controls whether the multiblock allocator should | ||
506 | collect statistics, which are shown during the | ||
507 | unmount. 1 means to collect statistics, 0 means | ||
508 | not to collect statistics | ||
509 | |||
510 | mb_stream_req Files which have fewer blocks than this tunable | ||
511 | parameter will have their blocks allocated out | ||
512 | of a block group specific preallocation pool, so | ||
513 | that small files are packed closely together. | ||
514 | Each large file will have its blocks allocated | ||
515 | out of its own unique preallocation pool. | ||
516 | |||
517 | session_write_kbytes This file is read-only and shows the number of | ||
518 | kilobytes of data that have been written to this | ||
519 | filesystem since it was mounted. | ||
520 | .............................................................................. | ||
521 | |||
522 | Ioctls | ||
523 | ====== | ||
524 | |||
525 | There is some Ext4 specific functionality which can be accessed by applications | ||
526 | through the system call interfaces. The list of all Ext4 specific ioctls are | ||
527 | shown in the table below. | ||
528 | |||
529 | Table of Ext4 specific ioctls | ||
530 | .............................................................................. | ||
531 | Ioctl Description | ||
532 | EXT4_IOC_GETFLAGS Get additional attributes associated with inode. | ||
533 | The ioctl argument is an integer bitfield, with | ||
534 | bit values described in ext4.h. This ioctl is an | ||
535 | alias for FS_IOC_GETFLAGS. | ||
536 | |||
537 | EXT4_IOC_SETFLAGS Set additional attributes associated with inode. | ||
538 | The ioctl argument is an integer bitfield, with | ||
539 | bit values described in ext4.h. This ioctl is an | ||
540 | alias for FS_IOC_SETFLAGS. | ||
541 | |||
542 | EXT4_IOC_GETVERSION | ||
543 | EXT4_IOC_GETVERSION_OLD | ||
544 | Get the inode i_generation number stored for | ||
545 | each inode. The i_generation number is normally | ||
546 | changed only when new inode is created and it is | ||
547 | particularly useful for network filesystems. The | ||
548 | '_OLD' version of this ioctl is an alias for | ||
549 | FS_IOC_GETVERSION. | ||
550 | |||
551 | EXT4_IOC_SETVERSION | ||
552 | EXT4_IOC_SETVERSION_OLD | ||
553 | Set the inode i_generation number stored for | ||
554 | each inode. The '_OLD' version of this ioctl | ||
555 | is an alias for FS_IOC_SETVERSION. | ||
556 | |||
557 | EXT4_IOC_GROUP_EXTEND This ioctl has the same purpose as the resize | ||
558 | mount option. It allows to resize filesystem | ||
559 | to the end of the last existing block group, | ||
560 | further resize has to be done with resize2fs, | ||
561 | either online, or offline. The argument points | ||
562 | to the unsigned logn number representing the | ||
563 | filesystem new block count. | ||
564 | |||
565 | EXT4_IOC_MOVE_EXT Move the block extents from orig_fd (the one | ||
566 | this ioctl is pointing to) to the donor_fd (the | ||
567 | one specified in move_extent structure passed | ||
568 | as an argument to this ioctl). Then, exchange | ||
569 | inode metadata between orig_fd and donor_fd. | ||
570 | This is especially useful for online | ||
571 | defragmentation, because the allocator has the | ||
572 | opportunity to allocate moved blocks better, | ||
573 | ideally into one contiguous extent. | ||
574 | |||
575 | EXT4_IOC_GROUP_ADD Add a new group descriptor to an existing or | ||
576 | new group descriptor block. The new group | ||
577 | descriptor is described by ext4_new_group_input | ||
578 | structure, which is passed as an argument to | ||
579 | this ioctl. This is especially useful in | ||
580 | conjunction with EXT4_IOC_GROUP_EXTEND, | ||
581 | which allows online resize of the filesystem | ||
582 | to the end of the last existing block group. | ||
583 | Those two ioctls combined is used in userspace | ||
584 | online resize tool (e.g. resize2fs). | ||
585 | |||
586 | EXT4_IOC_MIGRATE This ioctl operates on the filesystem itself. | ||
587 | It converts (migrates) ext3 indirect block mapped | ||
588 | inode to ext4 extent mapped inode by walking | ||
589 | through indirect block mapping of the original | ||
590 | inode and converting contiguous block ranges | ||
591 | into ext4 extents of the temporary inode. Then, | ||
592 | inodes are swapped. This ioctl might help, when | ||
593 | migrating from ext3 to ext4 filesystem, however | ||
594 | suggestion is to create fresh ext4 filesystem | ||
595 | and copy data from the backup. Note, that | ||
596 | filesystem has to support extents for this ioctl | ||
597 | to work. | ||
598 | |||
599 | EXT4_IOC_ALLOC_DA_BLKS Force all of the delay allocated blocks to be | ||
600 | allocated to preserve application-expected ext3 | ||
601 | behaviour. Note that this will also start | ||
602 | triggering a write of the data blocks, but this | ||
603 | behaviour may change in the future as it is | ||
604 | not necessary and has been done this way only | ||
605 | for sake of simplicity. | ||
606 | .............................................................................. | ||
607 | |||
403 | References | 608 | References |
404 | ========== | 609 | ========== |
405 | 610 | ||
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index 0c986c9e8519..6e29954851a2 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting | |||
@@ -298,11 +298,14 @@ be used instead. It gets called whenever the inode is evicted, whether it has | |||
298 | remaining links or not. Caller does *not* evict the pagecache or inode-associated | 298 | remaining links or not. Caller does *not* evict the pagecache or inode-associated |
299 | metadata buffers; getting rid of those is responsibility of method, as it had | 299 | metadata buffers; getting rid of those is responsibility of method, as it had |
300 | been for ->delete_inode(). | 300 | been for ->delete_inode(). |
301 | ->drop_inode() returns int now; it's called on final iput() with inode_lock | 301 | |
302 | held and it returns true if filesystems wants the inode to be dropped. As before, | 302 | ->drop_inode() returns int now; it's called on final iput() with |
303 | generic_drop_inode() is still the default and it's been updated appropriately. | 303 | inode->i_lock held and it returns true if filesystems wants the inode to be |
304 | generic_delete_inode() is also alive and it consists simply of return 1. Note that | 304 | dropped. As before, generic_drop_inode() is still the default and it's been |
305 | all actual eviction work is done by caller after ->drop_inode() returns. | 305 | updated appropriately. generic_delete_inode() is also alive and it consists |
306 | simply of return 1. Note that all actual eviction work is done by caller after | ||
307 | ->drop_inode() returns. | ||
308 | |||
306 | clear_inode() is gone; use end_writeback() instead. As before, it must | 309 | clear_inode() is gone; use end_writeback() instead. As before, it must |
307 | be called exactly once on each call of ->evict_inode() (as it used to be for | 310 | be called exactly once on each call of ->evict_inode() (as it used to be for |
308 | each call of ->delete_inode()). Unlike before, if you are using inode-associated | 311 | each call of ->delete_inode()). Unlike before, if you are using inode-associated |
@@ -397,6 +400,9 @@ a file off. | |||
397 | 400 | ||
398 | -- | 401 | -- |
399 | [mandatory] | 402 | [mandatory] |
403 | |||
404 | -- | ||
405 | [mandatory] | ||
400 | ->get_sb() is gone. Switch to use of ->mount(). Typically it's just | 406 | ->get_sb() is gone. Switch to use of ->mount(). Typically it's just |
401 | a matter of switching from calling get_sb_... to mount_... and changing the | 407 | a matter of switching from calling get_sb_... to mount_... and changing the |
402 | function type. If you were doing it manually, just switch from setting ->mnt_root | 408 | function type. If you were doing it manually, just switch from setting ->mnt_root |
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 306f0ae8df09..80815ed654cb 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt | |||
@@ -254,7 +254,7 @@ or bottom half). | |||
254 | should be synchronous or not, not all filesystems check this flag. | 254 | should be synchronous or not, not all filesystems check this flag. |
255 | 255 | ||
256 | drop_inode: called when the last access to the inode is dropped, | 256 | drop_inode: called when the last access to the inode is dropped, |
257 | with the inode_lock spinlock held. | 257 | with the inode->i_lock spinlock held. |
258 | 258 | ||
259 | This method should be either NULL (normal UNIX filesystem | 259 | This method should be either NULL (normal UNIX filesystem |
260 | semantics) or "generic_delete_inode" (for filesystems that do not | 260 | semantics) or "generic_delete_inode" (for filesystems that do not |
diff --git a/Documentation/hwmon/f71882fg b/Documentation/hwmon/f71882fg index 4d0bc70f1852..df02245d1419 100644 --- a/Documentation/hwmon/f71882fg +++ b/Documentation/hwmon/f71882fg | |||
@@ -2,6 +2,10 @@ Kernel driver f71882fg | |||
2 | ====================== | 2 | ====================== |
3 | 3 | ||
4 | Supported chips: | 4 | Supported chips: |
5 | * Fintek F71808E | ||
6 | Prefix: 'f71808e' | ||
7 | Addresses scanned: none, address read from Super I/O config space | ||
8 | Datasheet: Not public | ||
5 | * Fintek F71858FG | 9 | * Fintek F71858FG |
6 | Prefix: 'f71858fg' | 10 | Prefix: 'f71858fg' |
7 | Addresses scanned: none, address read from Super I/O config space | 11 | Addresses scanned: none, address read from Super I/O config space |
@@ -26,10 +30,25 @@ Supported chips: | |||
26 | Prefix: 'f71889ed' | 30 | Prefix: 'f71889ed' |
27 | Addresses scanned: none, address read from Super I/O config space | 31 | Addresses scanned: none, address read from Super I/O config space |
28 | Datasheet: Should become available on the Fintek website soon | 32 | Datasheet: Should become available on the Fintek website soon |
33 | * Fintek F71889A | ||
34 | Prefix: 'f71889a' | ||
35 | Addresses scanned: none, address read from Super I/O config space | ||
36 | Datasheet: Should become available on the Fintek website soon | ||
29 | * Fintek F8000 | 37 | * Fintek F8000 |
30 | Prefix: 'f8000' | 38 | Prefix: 'f8000' |
31 | Addresses scanned: none, address read from Super I/O config space | 39 | Addresses scanned: none, address read from Super I/O config space |
32 | Datasheet: Not public | 40 | Datasheet: Not public |
41 | * Fintek F81801U | ||
42 | Prefix: 'f71889fg' | ||
43 | Addresses scanned: none, address read from Super I/O config space | ||
44 | Datasheet: Not public | ||
45 | Note: This is the 64-pin variant of the F71889FG, they have the | ||
46 | same device ID and are fully compatible as far as hardware | ||
47 | monitoring is concerned. | ||
48 | * Fintek F81865F | ||
49 | Prefix: 'f81865f' | ||
50 | Addresses scanned: none, address read from Super I/O config space | ||
51 | Datasheet: Available from the Fintek website | ||
33 | 52 | ||
34 | Author: Hans de Goede <hdegoede@redhat.com> | 53 | Author: Hans de Goede <hdegoede@redhat.com> |
35 | 54 | ||
diff --git a/Documentation/scheduler/sched-design-CFS.txt b/Documentation/scheduler/sched-design-CFS.txt index 8239ebbcddce..99961993257a 100644 --- a/Documentation/scheduler/sched-design-CFS.txt +++ b/Documentation/scheduler/sched-design-CFS.txt | |||
@@ -164,7 +164,7 @@ This is the (partial) list of the hooks: | |||
164 | It puts the scheduling entity (task) into the red-black tree and | 164 | It puts the scheduling entity (task) into the red-black tree and |
165 | increments the nr_running variable. | 165 | increments the nr_running variable. |
166 | 166 | ||
167 | - dequeue_tree(...) | 167 | - dequeue_task(...) |
168 | 168 | ||
169 | When a task is no longer runnable, this function is called to keep the | 169 | When a task is no longer runnable, this function is called to keep the |
170 | corresponding scheduling entity out of the red-black tree. It decrements | 170 | corresponding scheduling entity out of the red-black tree. It decrements |
@@ -195,11 +195,6 @@ This is the (partial) list of the hooks: | |||
195 | This function is mostly called from time tick functions; it might lead to | 195 | This function is mostly called from time tick functions; it might lead to |
196 | process switch. This drives the running preemption. | 196 | process switch. This drives the running preemption. |
197 | 197 | ||
198 | - task_new(...) | ||
199 | |||
200 | The core scheduler gives the scheduling module an opportunity to manage new | ||
201 | task startup. The CFS scheduling module uses it for group scheduling, while | ||
202 | the scheduling module for a real-time task does not use it. | ||
203 | 198 | ||
204 | 199 | ||
205 | 200 | ||
diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index dbeb8a0d7175..7ef9b843d529 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py | |||
@@ -239,8 +239,8 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): | |||
239 | buf += "#include <target/target_core_configfs.h>\n" | 239 | buf += "#include <target/target_core_configfs.h>\n" |
240 | buf += "#include <target/target_core_base.h>\n" | 240 | buf += "#include <target/target_core_base.h>\n" |
241 | buf += "#include <target/configfs_macros.h>\n\n" | 241 | buf += "#include <target/configfs_macros.h>\n\n" |
242 | buf += "#include <" + fabric_mod_name + "_base.h>\n" | 242 | buf += "#include \"" + fabric_mod_name + "_base.h\"\n" |
243 | buf += "#include <" + fabric_mod_name + "_fabric.h>\n\n" | 243 | buf += "#include \"" + fabric_mod_name + "_fabric.h\"\n\n" |
244 | 244 | ||
245 | buf += "/* Local pointer to allocated TCM configfs fabric module */\n" | 245 | buf += "/* Local pointer to allocated TCM configfs fabric module */\n" |
246 | buf += "struct target_fabric_configfs *" + fabric_mod_name + "_fabric_configfs;\n\n" | 246 | buf += "struct target_fabric_configfs *" + fabric_mod_name + "_fabric_configfs;\n\n" |
@@ -289,6 +289,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): | |||
289 | buf += "{\n" | 289 | buf += "{\n" |
290 | buf += " struct " + fabric_mod_name + "_nacl *nacl = container_of(se_acl,\n" | 290 | buf += " struct " + fabric_mod_name + "_nacl *nacl = container_of(se_acl,\n" |
291 | buf += " struct " + fabric_mod_name + "_nacl, se_node_acl);\n" | 291 | buf += " struct " + fabric_mod_name + "_nacl, se_node_acl);\n" |
292 | buf += " core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);\n" | ||
292 | buf += " kfree(nacl);\n" | 293 | buf += " kfree(nacl);\n" |
293 | buf += "}\n\n" | 294 | buf += "}\n\n" |
294 | 295 | ||
@@ -583,9 +584,9 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): | |||
583 | buf += "#include <target/target_core_fabric_lib.h>\n" | 584 | buf += "#include <target/target_core_fabric_lib.h>\n" |
584 | buf += "#include <target/target_core_device.h>\n" | 585 | buf += "#include <target/target_core_device.h>\n" |
585 | buf += "#include <target/target_core_tpg.h>\n" | 586 | buf += "#include <target/target_core_tpg.h>\n" |
586 | buf += "#include <target/target_core_configfs.h>\n" | 587 | buf += "#include <target/target_core_configfs.h>\n\n" |
587 | buf += "#include <" + fabric_mod_name + "_base.h>\n" | 588 | buf += "#include \"" + fabric_mod_name + "_base.h\"\n" |
588 | buf += "#include <" + fabric_mod_name + "_fabric.h>\n\n" | 589 | buf += "#include \"" + fabric_mod_name + "_fabric.h\"\n\n" |
589 | 590 | ||
590 | buf += "int " + fabric_mod_name + "_check_true(struct se_portal_group *se_tpg)\n" | 591 | buf += "int " + fabric_mod_name + "_check_true(struct se_portal_group *se_tpg)\n" |
591 | buf += "{\n" | 592 | buf += "{\n" |
@@ -973,14 +974,13 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): | |||
973 | def tcm_mod_build_kbuild(fabric_mod_dir_var, fabric_mod_name): | 974 | def tcm_mod_build_kbuild(fabric_mod_dir_var, fabric_mod_name): |
974 | 975 | ||
975 | buf = "" | 976 | buf = "" |
976 | f = fabric_mod_dir_var + "/Kbuild" | 977 | f = fabric_mod_dir_var + "/Makefile" |
977 | print "Writing file: " + f | 978 | print "Writing file: " + f |
978 | 979 | ||
979 | p = open(f, 'w') | 980 | p = open(f, 'w') |
980 | if not p: | 981 | if not p: |
981 | tcm_mod_err("Unable to open file: " + f) | 982 | tcm_mod_err("Unable to open file: " + f) |
982 | 983 | ||
983 | buf = "EXTRA_CFLAGS += -I$(srctree)/drivers/target/ -I$(srctree)/include/ -I$(srctree)/drivers/scsi/ -I$(srctree)/include/scsi/ -I$(srctree)/drivers/target/" + fabric_mod_name + "\n\n" | ||
984 | buf += fabric_mod_name + "-objs := " + fabric_mod_name + "_fabric.o \\\n" | 984 | buf += fabric_mod_name + "-objs := " + fabric_mod_name + "_fabric.o \\\n" |
985 | buf += " " + fabric_mod_name + "_configfs.o\n" | 985 | buf += " " + fabric_mod_name + "_configfs.o\n" |
986 | buf += "obj-$(CONFIG_" + fabric_mod_name.upper() + ") += " + fabric_mod_name + ".o\n" | 986 | buf += "obj-$(CONFIG_" + fabric_mod_name.upper() + ") += " + fabric_mod_name + ".o\n" |
@@ -1018,7 +1018,7 @@ def tcm_mod_build_kconfig(fabric_mod_dir_var, fabric_mod_name): | |||
1018 | 1018 | ||
1019 | def tcm_mod_add_kbuild(tcm_dir, fabric_mod_name): | 1019 | def tcm_mod_add_kbuild(tcm_dir, fabric_mod_name): |
1020 | buf = "obj-$(CONFIG_" + fabric_mod_name.upper() + ") += " + fabric_mod_name.lower() + "/\n" | 1020 | buf = "obj-$(CONFIG_" + fabric_mod_name.upper() + ") += " + fabric_mod_name.lower() + "/\n" |
1021 | kbuild = tcm_dir + "/drivers/target/Kbuild" | 1021 | kbuild = tcm_dir + "/drivers/target/Makefile" |
1022 | 1022 | ||
1023 | f = open(kbuild, 'a') | 1023 | f = open(kbuild, 'a') |
1024 | f.write(buf) | 1024 | f.write(buf) |
@@ -1064,7 +1064,7 @@ def main(modname, proto_ident): | |||
1064 | tcm_mod_build_kbuild(fabric_mod_dir, fabric_mod_name) | 1064 | tcm_mod_build_kbuild(fabric_mod_dir, fabric_mod_name) |
1065 | tcm_mod_build_kconfig(fabric_mod_dir, fabric_mod_name) | 1065 | tcm_mod_build_kconfig(fabric_mod_dir, fabric_mod_name) |
1066 | 1066 | ||
1067 | input = raw_input("Would you like to add " + fabric_mod_name + "to drivers/target/Kbuild..? [yes,no]: ") | 1067 | input = raw_input("Would you like to add " + fabric_mod_name + "to drivers/target/Makefile..? [yes,no]: ") |
1068 | if input == "yes" or input == "y": | 1068 | if input == "yes" or input == "y": |
1069 | tcm_mod_add_kbuild(tcm_dir, fabric_mod_name) | 1069 | tcm_mod_add_kbuild(tcm_dir, fabric_mod_name) |
1070 | 1070 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 749f9cd38089..8aa1cacddbcc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -548,10 +548,8 @@ S: Maintained | |||
548 | F: sound/aoa/ | 548 | F: sound/aoa/ |
549 | 549 | ||
550 | APM DRIVER | 550 | APM DRIVER |
551 | M: Stephen Rothwell <sfr@canb.auug.org.au> | ||
552 | L: linux-laptop@vger.kernel.org | 551 | L: linux-laptop@vger.kernel.org |
553 | W: http://www.canb.auug.org.au/~sfr/ | 552 | S: Orphan |
554 | S: Supported | ||
555 | F: arch/x86/kernel/apm_32.c | 553 | F: arch/x86/kernel/apm_32.c |
556 | F: include/linux/apm_bios.h | 554 | F: include/linux/apm_bios.h |
557 | 555 | ||
@@ -5291,6 +5289,11 @@ S: Maintained | |||
5291 | F: drivers/mtd/nand/r852.c | 5289 | F: drivers/mtd/nand/r852.c |
5292 | F: drivers/mtd/nand/r852.h | 5290 | F: drivers/mtd/nand/r852.h |
5293 | 5291 | ||
5292 | RICOH R5C592 MEMORYSTICK DRIVER | ||
5293 | M: Maxim Levitsky <maximlevitsky@gmail.com> | ||
5294 | S: Maintained | ||
5295 | F: drivers/memstick/host/r592.* | ||
5296 | |||
5294 | RISCOM8 DRIVER | 5297 | RISCOM8 DRIVER |
5295 | S: Orphan | 5298 | S: Orphan |
5296 | F: Documentation/serial/riscom8.txt | 5299 | F: Documentation/serial/riscom8.txt |
@@ -6628,6 +6631,7 @@ F: drivers/media/video/zr364xx.c | |||
6628 | 6631 | ||
6629 | USER-MODE LINUX (UML) | 6632 | USER-MODE LINUX (UML) |
6630 | M: Jeff Dike <jdike@addtoit.com> | 6633 | M: Jeff Dike <jdike@addtoit.com> |
6634 | M: Richard Weinberger <richard@nod.at> | ||
6631 | L: user-mode-linux-devel@lists.sourceforge.net | 6635 | L: user-mode-linux-devel@lists.sourceforge.net |
6632 | L: user-mode-linux-user@lists.sourceforge.net | 6636 | L: user-mode-linux-user@lists.sourceforge.net |
6633 | W: http://user-mode-linux.sourceforge.net | 6637 | W: http://user-mode-linux.sourceforge.net |
diff --git a/arch/arm/mach-ep93xx/gpio.c b/arch/arm/mach-ep93xx/gpio.c index a889fa7c3ba1..34e071d79761 100644 --- a/arch/arm/mach-ep93xx/gpio.c +++ b/arch/arm/mach-ep93xx/gpio.c | |||
@@ -360,52 +360,14 @@ static void ep93xx_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) | |||
360 | gpio = ep93xx_chip->chip.base; | 360 | gpio = ep93xx_chip->chip.base; |
361 | for (i = 0; i < chip->ngpio; i++, gpio++) { | 361 | for (i = 0; i < chip->ngpio; i++, gpio++) { |
362 | int is_out = data_dir_reg & (1 << i); | 362 | int is_out = data_dir_reg & (1 << i); |
363 | int irq = gpio_to_irq(gpio); | ||
363 | 364 | ||
364 | seq_printf(s, " %s%d gpio-%-3d (%-12s) %s %s", | 365 | seq_printf(s, " %s%d gpio-%-3d (%-12s) %s %s %s\n", |
365 | chip->label, i, gpio, | 366 | chip->label, i, gpio, |
366 | gpiochip_is_requested(chip, i) ? : "", | 367 | gpiochip_is_requested(chip, i) ? : "", |
367 | is_out ? "out" : "in ", | 368 | is_out ? "out" : "in ", |
368 | (data_reg & (1 << i)) ? "hi" : "lo"); | 369 | (data_reg & (1<< i)) ? "hi" : "lo", |
369 | 370 | (!is_out && irq>= 0) ? "(interrupt)" : ""); | |
370 | if (!is_out) { | ||
371 | int irq = gpio_to_irq(gpio); | ||
372 | struct irq_desc *desc = irq_desc + irq; | ||
373 | |||
374 | if (irq >= 0 && desc->action) { | ||
375 | char *trigger; | ||
376 | |||
377 | switch (desc->status & IRQ_TYPE_SENSE_MASK) { | ||
378 | case IRQ_TYPE_NONE: | ||
379 | trigger = "(default)"; | ||
380 | break; | ||
381 | case IRQ_TYPE_EDGE_FALLING: | ||
382 | trigger = "edge-falling"; | ||
383 | break; | ||
384 | case IRQ_TYPE_EDGE_RISING: | ||
385 | trigger = "edge-rising"; | ||
386 | break; | ||
387 | case IRQ_TYPE_EDGE_BOTH: | ||
388 | trigger = "edge-both"; | ||
389 | break; | ||
390 | case IRQ_TYPE_LEVEL_HIGH: | ||
391 | trigger = "level-high"; | ||
392 | break; | ||
393 | case IRQ_TYPE_LEVEL_LOW: | ||
394 | trigger = "level-low"; | ||
395 | break; | ||
396 | default: | ||
397 | trigger = "?trigger?"; | ||
398 | break; | ||
399 | } | ||
400 | |||
401 | seq_printf(s, " irq-%d %s%s", | ||
402 | irq, trigger, | ||
403 | (desc->status & IRQ_WAKEUP) | ||
404 | ? " wakeup" : ""); | ||
405 | } | ||
406 | } | ||
407 | |||
408 | seq_printf(s, "\n"); | ||
409 | } | 371 | } |
410 | } | 372 | } |
411 | 373 | ||
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index c936c6d7ded0..f3a7b1011914 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c | |||
@@ -285,19 +285,6 @@ static int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers) | |||
285 | return 0; | 285 | return 0; |
286 | } | 286 | } |
287 | 287 | ||
288 | static struct regulator_init_data omap4_panda_vaux1 = { | ||
289 | .constraints = { | ||
290 | .min_uV = 1000000, | ||
291 | .max_uV = 3000000, | ||
292 | .apply_uV = true, | ||
293 | .valid_modes_mask = REGULATOR_MODE_NORMAL | ||
294 | | REGULATOR_MODE_STANDBY, | ||
295 | .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | ||
296 | | REGULATOR_CHANGE_MODE | ||
297 | | REGULATOR_CHANGE_STATUS, | ||
298 | }, | ||
299 | }; | ||
300 | |||
301 | static struct regulator_init_data omap4_panda_vaux2 = { | 288 | static struct regulator_init_data omap4_panda_vaux2 = { |
302 | .constraints = { | 289 | .constraints = { |
303 | .min_uV = 1200000, | 290 | .min_uV = 1200000, |
@@ -353,19 +340,6 @@ static struct regulator_init_data omap4_panda_vpp = { | |||
353 | }, | 340 | }, |
354 | }; | 341 | }; |
355 | 342 | ||
356 | static struct regulator_init_data omap4_panda_vusim = { | ||
357 | .constraints = { | ||
358 | .min_uV = 1200000, | ||
359 | .max_uV = 2900000, | ||
360 | .apply_uV = true, | ||
361 | .valid_modes_mask = REGULATOR_MODE_NORMAL | ||
362 | | REGULATOR_MODE_STANDBY, | ||
363 | .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | ||
364 | | REGULATOR_CHANGE_MODE | ||
365 | | REGULATOR_CHANGE_STATUS, | ||
366 | }, | ||
367 | }; | ||
368 | |||
369 | static struct regulator_init_data omap4_panda_vana = { | 343 | static struct regulator_init_data omap4_panda_vana = { |
370 | .constraints = { | 344 | .constraints = { |
371 | .min_uV = 2100000, | 345 | .min_uV = 2100000, |
@@ -424,12 +398,10 @@ static struct twl4030_platform_data omap4_panda_twldata = { | |||
424 | /* Regulators */ | 398 | /* Regulators */ |
425 | .vmmc = &omap4_panda_vmmc, | 399 | .vmmc = &omap4_panda_vmmc, |
426 | .vpp = &omap4_panda_vpp, | 400 | .vpp = &omap4_panda_vpp, |
427 | .vusim = &omap4_panda_vusim, | ||
428 | .vana = &omap4_panda_vana, | 401 | .vana = &omap4_panda_vana, |
429 | .vcxio = &omap4_panda_vcxio, | 402 | .vcxio = &omap4_panda_vcxio, |
430 | .vdac = &omap4_panda_vdac, | 403 | .vdac = &omap4_panda_vdac, |
431 | .vusb = &omap4_panda_vusb, | 404 | .vusb = &omap4_panda_vusb, |
432 | .vaux1 = &omap4_panda_vaux1, | ||
433 | .vaux2 = &omap4_panda_vaux2, | 405 | .vaux2 = &omap4_panda_vaux2, |
434 | .vaux3 = &omap4_panda_vaux3, | 406 | .vaux3 = &omap4_panda_vaux3, |
435 | .clk32kg = &omap4_panda_clk32kg, | 407 | .clk32kg = &omap4_panda_clk32kg, |
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index e97851492847..84d1b735fe80 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c | |||
@@ -66,7 +66,7 @@ static int __init omap3_l3_init(void) | |||
66 | 66 | ||
67 | WARN(IS_ERR(od), "could not build omap_device for %s\n", oh_name); | 67 | WARN(IS_ERR(od), "could not build omap_device for %s\n", oh_name); |
68 | 68 | ||
69 | return PTR_ERR(od); | 69 | return IS_ERR(od) ? PTR_ERR(od) : 0; |
70 | } | 70 | } |
71 | postcore_initcall(omap3_l3_init); | 71 | postcore_initcall(omap3_l3_init); |
72 | 72 | ||
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 674174365f78..493505c3b2f5 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c | |||
@@ -693,6 +693,7 @@ static int __init gpmc_init(void) | |||
693 | { | 693 | { |
694 | u32 l, irq; | 694 | u32 l, irq; |
695 | int cs, ret = -EINVAL; | 695 | int cs, ret = -EINVAL; |
696 | int gpmc_irq; | ||
696 | char *ck = NULL; | 697 | char *ck = NULL; |
697 | 698 | ||
698 | if (cpu_is_omap24xx()) { | 699 | if (cpu_is_omap24xx()) { |
@@ -701,12 +702,15 @@ static int __init gpmc_init(void) | |||
701 | l = OMAP2420_GPMC_BASE; | 702 | l = OMAP2420_GPMC_BASE; |
702 | else | 703 | else |
703 | l = OMAP34XX_GPMC_BASE; | 704 | l = OMAP34XX_GPMC_BASE; |
705 | gpmc_irq = INT_34XX_GPMC_IRQ; | ||
704 | } else if (cpu_is_omap34xx()) { | 706 | } else if (cpu_is_omap34xx()) { |
705 | ck = "gpmc_fck"; | 707 | ck = "gpmc_fck"; |
706 | l = OMAP34XX_GPMC_BASE; | 708 | l = OMAP34XX_GPMC_BASE; |
709 | gpmc_irq = INT_34XX_GPMC_IRQ; | ||
707 | } else if (cpu_is_omap44xx()) { | 710 | } else if (cpu_is_omap44xx()) { |
708 | ck = "gpmc_ck"; | 711 | ck = "gpmc_ck"; |
709 | l = OMAP44XX_GPMC_BASE; | 712 | l = OMAP44XX_GPMC_BASE; |
713 | gpmc_irq = OMAP44XX_IRQ_GPMC; | ||
710 | } | 714 | } |
711 | 715 | ||
712 | if (WARN_ON(!ck)) | 716 | if (WARN_ON(!ck)) |
@@ -739,16 +743,17 @@ static int __init gpmc_init(void) | |||
739 | /* initalize the irq_chained */ | 743 | /* initalize the irq_chained */ |
740 | irq = OMAP_GPMC_IRQ_BASE; | 744 | irq = OMAP_GPMC_IRQ_BASE; |
741 | for (cs = 0; cs < GPMC_CS_NUM; cs++) { | 745 | for (cs = 0; cs < GPMC_CS_NUM; cs++) { |
742 | set_irq_handler(irq, handle_simple_irq); | 746 | set_irq_chip_and_handler(irq, &dummy_irq_chip, |
747 | handle_simple_irq); | ||
743 | set_irq_flags(irq, IRQF_VALID); | 748 | set_irq_flags(irq, IRQF_VALID); |
744 | irq++; | 749 | irq++; |
745 | } | 750 | } |
746 | 751 | ||
747 | ret = request_irq(INT_34XX_GPMC_IRQ, | 752 | ret = request_irq(gpmc_irq, |
748 | gpmc_handle_irq, IRQF_SHARED, "gpmc", gpmc_base); | 753 | gpmc_handle_irq, IRQF_SHARED, "gpmc", gpmc_base); |
749 | if (ret) | 754 | if (ret) |
750 | pr_err("gpmc: irq-%d could not claim: err %d\n", | 755 | pr_err("gpmc: irq-%d could not claim: err %d\n", |
751 | INT_34XX_GPMC_IRQ, ret); | 756 | gpmc_irq, ret); |
752 | return ret; | 757 | return ret; |
753 | } | 758 | } |
754 | postcore_initcall(gpmc_init); | 759 | postcore_initcall(gpmc_init); |
@@ -757,8 +762,6 @@ static irqreturn_t gpmc_handle_irq(int irq, void *dev) | |||
757 | { | 762 | { |
758 | u8 cs; | 763 | u8 cs; |
759 | 764 | ||
760 | if (irq != INT_34XX_GPMC_IRQ) | ||
761 | return IRQ_HANDLED; | ||
762 | /* check cs to invoke the irq */ | 765 | /* check cs to invoke the irq */ |
763 | cs = ((gpmc_read_reg(GPMC_PREFETCH_CONFIG1)) >> CS_NUM_SHIFT) & 0x7; | 766 | cs = ((gpmc_read_reg(GPMC_PREFETCH_CONFIG1)) >> CS_NUM_SHIFT) & 0x7; |
764 | if (OMAP_GPMC_IRQ_BASE+cs <= OMAP_GPMC_IRQ_END) | 767 | if (OMAP_GPMC_IRQ_BASE+cs <= OMAP_GPMC_IRQ_END) |
diff --git a/arch/arm/mach-omap2/omap_l3_smx.c b/arch/arm/mach-omap2/omap_l3_smx.c index 265bff3acb9e..5f2da7565b68 100644 --- a/arch/arm/mach-omap2/omap_l3_smx.c +++ b/arch/arm/mach-omap2/omap_l3_smx.c | |||
@@ -226,7 +226,6 @@ static int __init omap3_l3_probe(struct platform_device *pdev) | |||
226 | struct omap3_l3 *l3; | 226 | struct omap3_l3 *l3; |
227 | struct resource *res; | 227 | struct resource *res; |
228 | int ret; | 228 | int ret; |
229 | int irq; | ||
230 | 229 | ||
231 | l3 = kzalloc(sizeof(*l3), GFP_KERNEL); | 230 | l3 = kzalloc(sizeof(*l3), GFP_KERNEL); |
232 | if (!l3) { | 231 | if (!l3) { |
@@ -249,18 +248,17 @@ static int __init omap3_l3_probe(struct platform_device *pdev) | |||
249 | goto err2; | 248 | goto err2; |
250 | } | 249 | } |
251 | 250 | ||
252 | irq = platform_get_irq(pdev, 0); | 251 | l3->debug_irq = platform_get_irq(pdev, 0); |
253 | ret = request_irq(irq, omap3_l3_app_irq, | 252 | ret = request_irq(l3->debug_irq, omap3_l3_app_irq, |
254 | IRQF_DISABLED | IRQF_TRIGGER_RISING, | 253 | IRQF_DISABLED | IRQF_TRIGGER_RISING, |
255 | "l3-debug-irq", l3); | 254 | "l3-debug-irq", l3); |
256 | if (ret) { | 255 | if (ret) { |
257 | dev_err(&pdev->dev, "couldn't request debug irq\n"); | 256 | dev_err(&pdev->dev, "couldn't request debug irq\n"); |
258 | goto err3; | 257 | goto err3; |
259 | } | 258 | } |
260 | l3->debug_irq = irq; | ||
261 | 259 | ||
262 | irq = platform_get_irq(pdev, 1); | 260 | l3->app_irq = platform_get_irq(pdev, 1); |
263 | ret = request_irq(irq, omap3_l3_app_irq, | 261 | ret = request_irq(l3->app_irq, omap3_l3_app_irq, |
264 | IRQF_DISABLED | IRQF_TRIGGER_RISING, | 262 | IRQF_DISABLED | IRQF_TRIGGER_RISING, |
265 | "l3-app-irq", l3); | 263 | "l3-app-irq", l3); |
266 | 264 | ||
@@ -269,7 +267,6 @@ static int __init omap3_l3_probe(struct platform_device *pdev) | |||
269 | goto err4; | 267 | goto err4; |
270 | } | 268 | } |
271 | 269 | ||
272 | l3->app_irq = irq; | ||
273 | goto err0; | 270 | goto err0; |
274 | 271 | ||
275 | err4: | 272 | err4: |
diff --git a/arch/arm/mach-ux500/board-mop500-regulators.h b/arch/arm/mach-ux500/board-mop500-regulators.h index 2675fae52537..f979b892e4fa 100644 --- a/arch/arm/mach-ux500/board-mop500-regulators.h +++ b/arch/arm/mach-ux500/board-mop500-regulators.h | |||
@@ -14,6 +14,8 @@ | |||
14 | #include <linux/regulator/machine.h> | 14 | #include <linux/regulator/machine.h> |
15 | #include <linux/regulator/ab8500.h> | 15 | #include <linux/regulator/ab8500.h> |
16 | 16 | ||
17 | extern struct ab8500_regulator_reg_init | ||
18 | ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS]; | ||
17 | extern struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS]; | 19 | extern struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS]; |
18 | 20 | ||
19 | #endif | 21 | #endif |
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index 8790d984cac8..d0076453d7ff 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/amba/serial.h> | 20 | #include <linux/amba/serial.h> |
21 | #include <linux/spi/spi.h> | 21 | #include <linux/spi/spi.h> |
22 | #include <linux/mfd/ab8500.h> | 22 | #include <linux/mfd/ab8500.h> |
23 | #include <linux/regulator/ab8500.h> | ||
23 | #include <linux/mfd/tc3589x.h> | 24 | #include <linux/mfd/tc3589x.h> |
24 | #include <linux/leds-lp5521.h> | 25 | #include <linux/leds-lp5521.h> |
25 | #include <linux/input.h> | 26 | #include <linux/input.h> |
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index b3b0f0f5053d..e5f6fc428348 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c | |||
@@ -78,7 +78,7 @@ __tagtable(ATAG_INITRD2, parse_tag_initrd2); | |||
78 | */ | 78 | */ |
79 | struct meminfo meminfo; | 79 | struct meminfo meminfo; |
80 | 80 | ||
81 | void show_mem(void) | 81 | void show_mem(unsigned int filter) |
82 | { | 82 | { |
83 | int free = 0, total = 0, reserved = 0; | 83 | int free = 0, total = 0, reserved = 0; |
84 | int shared = 0, cached = 0, slab = 0, i; | 84 | int shared = 0, cached = 0, slab = 0, i; |
diff --git a/arch/arm/plat-nomadik/gpio.c b/arch/arm/plat-nomadik/gpio.c index 70620426ee55..80643bc38e10 100644 --- a/arch/arm/plat-nomadik/gpio.c +++ b/arch/arm/plat-nomadik/gpio.c | |||
@@ -832,51 +832,6 @@ static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) | |||
832 | : "? ", | 832 | : "? ", |
833 | (mode < 0) ? "unknown" : modes[mode], | 833 | (mode < 0) ? "unknown" : modes[mode], |
834 | pull ? "pull" : "none"); | 834 | pull ? "pull" : "none"); |
835 | |||
836 | if (!is_out) { | ||
837 | int irq = gpio_to_irq(gpio); | ||
838 | struct irq_desc *desc = irq_to_desc(irq); | ||
839 | |||
840 | /* This races with request_irq(), set_irq_type(), | ||
841 | * and set_irq_wake() ... but those are "rare". | ||
842 | * | ||
843 | * More significantly, trigger type flags aren't | ||
844 | * currently maintained by genirq. | ||
845 | */ | ||
846 | if (irq >= 0 && desc->action) { | ||
847 | char *trigger; | ||
848 | |||
849 | switch (desc->status & IRQ_TYPE_SENSE_MASK) { | ||
850 | case IRQ_TYPE_NONE: | ||
851 | trigger = "(default)"; | ||
852 | break; | ||
853 | case IRQ_TYPE_EDGE_FALLING: | ||
854 | trigger = "edge-falling"; | ||
855 | break; | ||
856 | case IRQ_TYPE_EDGE_RISING: | ||
857 | trigger = "edge-rising"; | ||
858 | break; | ||
859 | case IRQ_TYPE_EDGE_BOTH: | ||
860 | trigger = "edge-both"; | ||
861 | break; | ||
862 | case IRQ_TYPE_LEVEL_HIGH: | ||
863 | trigger = "level-high"; | ||
864 | break; | ||
865 | case IRQ_TYPE_LEVEL_LOW: | ||
866 | trigger = "level-low"; | ||
867 | break; | ||
868 | default: | ||
869 | trigger = "?trigger?"; | ||
870 | break; | ||
871 | } | ||
872 | |||
873 | seq_printf(s, " irq-%d %s%s", | ||
874 | irq, trigger, | ||
875 | (desc->status & IRQ_WAKEUP) | ||
876 | ? " wakeup" : ""); | ||
877 | } | ||
878 | } | ||
879 | |||
880 | seq_printf(s, "\n"); | 835 | seq_printf(s, "\n"); |
881 | } | 836 | } |
882 | } | 837 | } |
diff --git a/arch/arm/plat-omap/include/plat/irqs.h b/arch/arm/plat-omap/include/plat/irqs.h index d77928370463..5a25098ea7ea 100644 --- a/arch/arm/plat-omap/include/plat/irqs.h +++ b/arch/arm/plat-omap/include/plat/irqs.h | |||
@@ -416,7 +416,7 @@ | |||
416 | 416 | ||
417 | /* GPMC related */ | 417 | /* GPMC related */ |
418 | #define OMAP_GPMC_IRQ_BASE (TWL_IRQ_END) | 418 | #define OMAP_GPMC_IRQ_BASE (TWL_IRQ_END) |
419 | #define OMAP_GPMC_NR_IRQS 7 | 419 | #define OMAP_GPMC_NR_IRQS 8 |
420 | #define OMAP_GPMC_IRQ_END (OMAP_GPMC_IRQ_BASE + OMAP_GPMC_NR_IRQS) | 420 | #define OMAP_GPMC_IRQ_END (OMAP_GPMC_IRQ_BASE + OMAP_GPMC_NR_IRQS) |
421 | 421 | ||
422 | 422 | ||
diff --git a/arch/arm/plat-omap/include/plat/onenand.h b/arch/arm/plat-omap/include/plat/onenand.h index cbe897ca7f9e..2858667d2e4f 100644 --- a/arch/arm/plat-omap/include/plat/onenand.h +++ b/arch/arm/plat-omap/include/plat/onenand.h | |||
@@ -32,6 +32,7 @@ struct omap_onenand_platform_data { | |||
32 | int dma_channel; | 32 | int dma_channel; |
33 | u8 flags; | 33 | u8 flags; |
34 | u8 regulator_can_sleep; | 34 | u8 regulator_can_sleep; |
35 | u8 skip_initial_unlocking; | ||
35 | }; | 36 | }; |
36 | 37 | ||
37 | #define ONENAND_MAX_PARTITIONS 8 | 38 | #define ONENAND_MAX_PARTITIONS 8 |
diff --git a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h index 01a8448e471c..442301fe48b4 100644 --- a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h +++ b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h | |||
@@ -30,6 +30,7 @@ struct pxa3xx_nand_cmdset { | |||
30 | }; | 30 | }; |
31 | 31 | ||
32 | struct pxa3xx_nand_flash { | 32 | struct pxa3xx_nand_flash { |
33 | char *name; | ||
33 | uint32_t chip_id; | 34 | uint32_t chip_id; |
34 | unsigned int page_per_block; /* Pages per block (PG_PER_BLK) */ | 35 | unsigned int page_per_block; /* Pages per block (PG_PER_BLK) */ |
35 | unsigned int page_size; /* Page size in bytes (PAGE_SZ) */ | 36 | unsigned int page_size; /* Page size in bytes (PAGE_SZ) */ |
@@ -37,7 +38,6 @@ struct pxa3xx_nand_flash { | |||
37 | unsigned int dfc_width; /* Width of flash controller(DWIDTH_C) */ | 38 | unsigned int dfc_width; /* Width of flash controller(DWIDTH_C) */ |
38 | unsigned int num_blocks; /* Number of physical blocks in Flash */ | 39 | unsigned int num_blocks; /* Number of physical blocks in Flash */ |
39 | 40 | ||
40 | struct pxa3xx_nand_cmdset *cmdset; /* NAND command set */ | ||
41 | struct pxa3xx_nand_timing *timing; /* NAND Flash timing */ | 41 | struct pxa3xx_nand_timing *timing; /* NAND Flash timing */ |
42 | }; | 42 | }; |
43 | 43 | ||
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig index cd2062fe0f61..49642b59f73d 100644 --- a/arch/avr32/Kconfig +++ b/arch/avr32/Kconfig | |||
@@ -6,6 +6,11 @@ config AVR32 | |||
6 | select HAVE_CLK | 6 | select HAVE_CLK |
7 | select HAVE_OPROFILE | 7 | select HAVE_OPROFILE |
8 | select HAVE_KPROBES | 8 | select HAVE_KPROBES |
9 | select HAVE_GENERIC_HARDIRQS | ||
10 | select GENERIC_IRQ_PROBE | ||
11 | select HARDIRQS_SW_RESEND | ||
12 | select GENERIC_IRQ_SHOW | ||
13 | select GENERIC_HARDIRQS_NO_DEPRECATED | ||
9 | help | 14 | help |
10 | AVR32 is a high-performance 32-bit RISC microprocessor core, | 15 | AVR32 is a high-performance 32-bit RISC microprocessor core, |
11 | designed for cost-sensitive embedded applications, with particular | 16 | designed for cost-sensitive embedded applications, with particular |
@@ -17,9 +22,6 @@ config AVR32 | |||
17 | config GENERIC_GPIO | 22 | config GENERIC_GPIO |
18 | def_bool y | 23 | def_bool y |
19 | 24 | ||
20 | config GENERIC_HARDIRQS | ||
21 | def_bool y | ||
22 | |||
23 | config STACKTRACE_SUPPORT | 25 | config STACKTRACE_SUPPORT |
24 | def_bool y | 26 | def_bool y |
25 | 27 | ||
@@ -29,12 +31,6 @@ config LOCKDEP_SUPPORT | |||
29 | config TRACE_IRQFLAGS_SUPPORT | 31 | config TRACE_IRQFLAGS_SUPPORT |
30 | def_bool y | 32 | def_bool y |
31 | 33 | ||
32 | config HARDIRQS_SW_RESEND | ||
33 | def_bool y | ||
34 | |||
35 | config GENERIC_IRQ_PROBE | ||
36 | def_bool y | ||
37 | |||
38 | config RWSEM_GENERIC_SPINLOCK | 34 | config RWSEM_GENERIC_SPINLOCK |
39 | def_bool y | 35 | def_bool y |
40 | 36 | ||
diff --git a/arch/avr32/boards/atngw100/mrmt.c b/arch/avr32/boards/atngw100/mrmt.c index 7919be311f4a..f91431963452 100644 --- a/arch/avr32/boards/atngw100/mrmt.c +++ b/arch/avr32/boards/atngw100/mrmt.c | |||
@@ -301,7 +301,7 @@ static int __init mrmt1_init(void) | |||
301 | /* Select the Touchscreen interrupt pin mode */ | 301 | /* Select the Touchscreen interrupt pin mode */ |
302 | at32_select_periph( GPIO_PIOB_BASE, 1 << (PB_EXTINT_BASE+TS_IRQ), | 302 | at32_select_periph( GPIO_PIOB_BASE, 1 << (PB_EXTINT_BASE+TS_IRQ), |
303 | GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH); | 303 | GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH); |
304 | set_irq_type( AT32_EXTINT(TS_IRQ), IRQ_TYPE_EDGE_FALLING ); | 304 | irq_set_irq_type(AT32_EXTINT(TS_IRQ), IRQ_TYPE_EDGE_FALLING); |
305 | at32_spi_setup_slaves(0,spi01_board_info,ARRAY_SIZE(spi01_board_info)); | 305 | at32_spi_setup_slaves(0,spi01_board_info,ARRAY_SIZE(spi01_board_info)); |
306 | spi_register_board_info(spi01_board_info,ARRAY_SIZE(spi01_board_info)); | 306 | spi_register_board_info(spi01_board_info,ARRAY_SIZE(spi01_board_info)); |
307 | #endif | 307 | #endif |
diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c index 659d119ce712..fafed4c38fd2 100644 --- a/arch/avr32/boards/atngw100/setup.c +++ b/arch/avr32/boards/atngw100/setup.c | |||
@@ -322,6 +322,6 @@ static int __init atngw100_arch_init(void) | |||
322 | /* set_irq_type() after the arch_initcall for EIC has run, and | 322 | /* set_irq_type() after the arch_initcall for EIC has run, and |
323 | * before the I2C subsystem could try using this IRQ. | 323 | * before the I2C subsystem could try using this IRQ. |
324 | */ | 324 | */ |
325 | return set_irq_type(AT32_EXTINT(3), IRQ_TYPE_EDGE_FALLING); | 325 | return irq_set_irq_type(AT32_EXTINT(3), IRQ_TYPE_EDGE_FALLING); |
326 | } | 326 | } |
327 | arch_initcall(atngw100_arch_init); | 327 | arch_initcall(atngw100_arch_init); |
diff --git a/arch/avr32/kernel/irq.c b/arch/avr32/kernel/irq.c index 9604f7758f9a..bc3aa18293df 100644 --- a/arch/avr32/kernel/irq.c +++ b/arch/avr32/kernel/irq.c | |||
@@ -26,40 +26,3 @@ void __weak nmi_disable(void) | |||
26 | { | 26 | { |
27 | 27 | ||
28 | } | 28 | } |
29 | |||
30 | #ifdef CONFIG_PROC_FS | ||
31 | int show_interrupts(struct seq_file *p, void *v) | ||
32 | { | ||
33 | int i = *(loff_t *)v, cpu; | ||
34 | struct irqaction *action; | ||
35 | unsigned long flags; | ||
36 | |||
37 | if (i == 0) { | ||
38 | seq_puts(p, " "); | ||
39 | for_each_online_cpu(cpu) | ||
40 | seq_printf(p, "CPU%d ", cpu); | ||
41 | seq_putc(p, '\n'); | ||
42 | } | ||
43 | |||
44 | if (i < NR_IRQS) { | ||
45 | raw_spin_lock_irqsave(&irq_desc[i].lock, flags); | ||
46 | action = irq_desc[i].action; | ||
47 | if (!action) | ||
48 | goto unlock; | ||
49 | |||
50 | seq_printf(p, "%3d: ", i); | ||
51 | for_each_online_cpu(cpu) | ||
52 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu)); | ||
53 | seq_printf(p, " %8s", irq_desc[i].chip->name ? : "-"); | ||
54 | seq_printf(p, " %s", action->name); | ||
55 | for (action = action->next; action; action = action->next) | ||
56 | seq_printf(p, ", %s", action->name); | ||
57 | |||
58 | seq_putc(p, '\n'); | ||
59 | unlock: | ||
60 | raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags); | ||
61 | } | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | #endif | ||
diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c index e9d12058ffd3..47ba4b9b6db1 100644 --- a/arch/avr32/mach-at32ap/extint.c +++ b/arch/avr32/mach-at32ap/extint.c | |||
@@ -61,45 +61,42 @@ struct eic { | |||
61 | static struct eic *nmi_eic; | 61 | static struct eic *nmi_eic; |
62 | static bool nmi_enabled; | 62 | static bool nmi_enabled; |
63 | 63 | ||
64 | static void eic_ack_irq(unsigned int irq) | 64 | static void eic_ack_irq(struct irq_chip *d) |
65 | { | 65 | { |
66 | struct eic *eic = get_irq_chip_data(irq); | 66 | struct eic *eic = irq_data_get_irq_chip_data(data); |
67 | eic_writel(eic, ICR, 1 << (irq - eic->first_irq)); | 67 | eic_writel(eic, ICR, 1 << (d->irq - eic->first_irq)); |
68 | } | 68 | } |
69 | 69 | ||
70 | static void eic_mask_irq(unsigned int irq) | 70 | static void eic_mask_irq(struct irq_chip *d) |
71 | { | 71 | { |
72 | struct eic *eic = get_irq_chip_data(irq); | 72 | struct eic *eic = irq_data_get_irq_chip_data(data); |
73 | eic_writel(eic, IDR, 1 << (irq - eic->first_irq)); | 73 | eic_writel(eic, IDR, 1 << (d->irq - eic->first_irq)); |
74 | } | 74 | } |
75 | 75 | ||
76 | static void eic_mask_ack_irq(unsigned int irq) | 76 | static void eic_mask_ack_irq(struct irq_chip *d) |
77 | { | 77 | { |
78 | struct eic *eic = get_irq_chip_data(irq); | 78 | struct eic *eic = irq_data_get_irq_chip_data(data); |
79 | eic_writel(eic, ICR, 1 << (irq - eic->first_irq)); | 79 | eic_writel(eic, ICR, 1 << (d->irq - eic->first_irq)); |
80 | eic_writel(eic, IDR, 1 << (irq - eic->first_irq)); | 80 | eic_writel(eic, IDR, 1 << (d->irq - eic->first_irq)); |
81 | } | 81 | } |
82 | 82 | ||
83 | static void eic_unmask_irq(unsigned int irq) | 83 | static void eic_unmask_irq(struct irq_chip *d) |
84 | { | 84 | { |
85 | struct eic *eic = get_irq_chip_data(irq); | 85 | struct eic *eic = irq_data_get_irq_chip_data(data); |
86 | eic_writel(eic, IER, 1 << (irq - eic->first_irq)); | 86 | eic_writel(eic, IER, 1 << (d->irq - eic->first_irq)); |
87 | } | 87 | } |
88 | 88 | ||
89 | static int eic_set_irq_type(unsigned int irq, unsigned int flow_type) | 89 | static int eic_set_irq_type(struct irq_chip *d, unsigned int flow_type) |
90 | { | 90 | { |
91 | struct eic *eic = get_irq_chip_data(irq); | 91 | struct eic *eic = irq_data_get_irq_chip_data(data); |
92 | struct irq_desc *desc; | 92 | unsigned int irq = d->irq; |
93 | unsigned int i = irq - eic->first_irq; | 93 | unsigned int i = irq - eic->first_irq; |
94 | u32 mode, edge, level; | 94 | u32 mode, edge, level; |
95 | int ret = 0; | ||
96 | 95 | ||
97 | flow_type &= IRQ_TYPE_SENSE_MASK; | 96 | flow_type &= IRQ_TYPE_SENSE_MASK; |
98 | if (flow_type == IRQ_TYPE_NONE) | 97 | if (flow_type == IRQ_TYPE_NONE) |
99 | flow_type = IRQ_TYPE_LEVEL_LOW; | 98 | flow_type = IRQ_TYPE_LEVEL_LOW; |
100 | 99 | ||
101 | desc = &irq_desc[irq]; | ||
102 | |||
103 | mode = eic_readl(eic, MODE); | 100 | mode = eic_readl(eic, MODE); |
104 | edge = eic_readl(eic, EDGE); | 101 | edge = eic_readl(eic, EDGE); |
105 | level = eic_readl(eic, LEVEL); | 102 | level = eic_readl(eic, LEVEL); |
@@ -122,39 +119,34 @@ static int eic_set_irq_type(unsigned int irq, unsigned int flow_type) | |||
122 | edge &= ~(1 << i); | 119 | edge &= ~(1 << i); |
123 | break; | 120 | break; |
124 | default: | 121 | default: |
125 | ret = -EINVAL; | 122 | return -EINVAL; |
126 | break; | ||
127 | } | 123 | } |
128 | 124 | ||
129 | if (ret == 0) { | 125 | eic_writel(eic, MODE, mode); |
130 | eic_writel(eic, MODE, mode); | 126 | eic_writel(eic, EDGE, edge); |
131 | eic_writel(eic, EDGE, edge); | 127 | eic_writel(eic, LEVEL, level); |
132 | eic_writel(eic, LEVEL, level); | ||
133 | |||
134 | if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) { | ||
135 | flow_type |= IRQ_LEVEL; | ||
136 | __set_irq_handler_unlocked(irq, handle_level_irq); | ||
137 | } else | ||
138 | __set_irq_handler_unlocked(irq, handle_edge_irq); | ||
139 | desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); | ||
140 | desc->status |= flow_type; | ||
141 | } | ||
142 | 128 | ||
143 | return ret; | 129 | irqd_set_trigger_type(d, flow_type); |
130 | if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) | ||
131 | __irq_set_handler_locked(irq, handle_level_irq); | ||
132 | else | ||
133 | __irq_set_handler_locked(irq, handle_edge_irq); | ||
134 | |||
135 | return IRQ_SET_MASK_OK_NOCOPY; | ||
144 | } | 136 | } |
145 | 137 | ||
146 | static struct irq_chip eic_chip = { | 138 | static struct irq_chip eic_chip = { |
147 | .name = "eic", | 139 | .name = "eic", |
148 | .ack = eic_ack_irq, | 140 | .irq_ack = eic_ack_irq, |
149 | .mask = eic_mask_irq, | 141 | .irq_mask = eic_mask_irq, |
150 | .mask_ack = eic_mask_ack_irq, | 142 | .irq_mask_ack = eic_mask_ack_irq, |
151 | .unmask = eic_unmask_irq, | 143 | .irq_unmask = eic_unmask_irq, |
152 | .set_type = eic_set_irq_type, | 144 | .irq_set_type = eic_set_irq_type, |
153 | }; | 145 | }; |
154 | 146 | ||
155 | static void demux_eic_irq(unsigned int irq, struct irq_desc *desc) | 147 | static void demux_eic_irq(unsigned int irq, struct irq_desc *desc) |
156 | { | 148 | { |
157 | struct eic *eic = desc->handler_data; | 149 | struct eic *eic = irq_desc_get_handler_data(desc); |
158 | unsigned long status, pending; | 150 | unsigned long status, pending; |
159 | unsigned int i; | 151 | unsigned int i; |
160 | 152 | ||
@@ -234,13 +226,13 @@ static int __init eic_probe(struct platform_device *pdev) | |||
234 | eic->chip = &eic_chip; | 226 | eic->chip = &eic_chip; |
235 | 227 | ||
236 | for (i = 0; i < nr_of_irqs; i++) { | 228 | for (i = 0; i < nr_of_irqs; i++) { |
237 | set_irq_chip_and_handler(eic->first_irq + i, &eic_chip, | 229 | irq_set_chip_and_handler(eic->first_irq + i, &eic_chip, |
238 | handle_level_irq); | 230 | handle_level_irq); |
239 | set_irq_chip_data(eic->first_irq + i, eic); | 231 | irq_set_chip_data(eic->first_irq + i, eic); |
240 | } | 232 | } |
241 | 233 | ||
242 | set_irq_chained_handler(int_irq, demux_eic_irq); | 234 | irq_set_chained_handler(int_irq, demux_eic_irq); |
243 | set_irq_data(int_irq, eic); | 235 | irq_set_handler_data(int_irq, eic); |
244 | 236 | ||
245 | if (pdev->id == 0) { | 237 | if (pdev->id == 0) { |
246 | nmi_eic = eic; | 238 | nmi_eic = eic; |
diff --git a/arch/avr32/mach-at32ap/intc.c b/arch/avr32/mach-at32ap/intc.c index 994c4545e2b7..21ce35f33aa5 100644 --- a/arch/avr32/mach-at32ap/intc.c +++ b/arch/avr32/mach-at32ap/intc.c | |||
@@ -34,12 +34,12 @@ extern struct platform_device at32_intc0_device; | |||
34 | * TODO: We may be able to implement mask/unmask by setting IxM flags | 34 | * TODO: We may be able to implement mask/unmask by setting IxM flags |
35 | * in the status register. | 35 | * in the status register. |
36 | */ | 36 | */ |
37 | static void intc_mask_irq(unsigned int irq) | 37 | static void intc_mask_irq(struct irq_data *d) |
38 | { | 38 | { |
39 | 39 | ||
40 | } | 40 | } |
41 | 41 | ||
42 | static void intc_unmask_irq(unsigned int irq) | 42 | static void intc_unmask_irq(struct irq_data *d) |
43 | { | 43 | { |
44 | 44 | ||
45 | } | 45 | } |
@@ -47,8 +47,8 @@ static void intc_unmask_irq(unsigned int irq) | |||
47 | static struct intc intc0 = { | 47 | static struct intc intc0 = { |
48 | .chip = { | 48 | .chip = { |
49 | .name = "intc", | 49 | .name = "intc", |
50 | .mask = intc_mask_irq, | 50 | .irq_mask = intc_mask_irq, |
51 | .unmask = intc_unmask_irq, | 51 | .irq_unmask = intc_unmask_irq, |
52 | }, | 52 | }, |
53 | }; | 53 | }; |
54 | 54 | ||
@@ -57,7 +57,6 @@ static struct intc intc0 = { | |||
57 | */ | 57 | */ |
58 | asmlinkage void do_IRQ(int level, struct pt_regs *regs) | 58 | asmlinkage void do_IRQ(int level, struct pt_regs *regs) |
59 | { | 59 | { |
60 | struct irq_desc *desc; | ||
61 | struct pt_regs *old_regs; | 60 | struct pt_regs *old_regs; |
62 | unsigned int irq; | 61 | unsigned int irq; |
63 | unsigned long status_reg; | 62 | unsigned long status_reg; |
@@ -69,8 +68,7 @@ asmlinkage void do_IRQ(int level, struct pt_regs *regs) | |||
69 | irq_enter(); | 68 | irq_enter(); |
70 | 69 | ||
71 | irq = intc_readl(&intc0, INTCAUSE0 - 4 * level); | 70 | irq = intc_readl(&intc0, INTCAUSE0 - 4 * level); |
72 | desc = irq_desc + irq; | 71 | generic_handle_irq(irq); |
73 | desc->handle_irq(irq, desc); | ||
74 | 72 | ||
75 | /* | 73 | /* |
76 | * Clear all interrupt level masks so that we may handle | 74 | * Clear all interrupt level masks so that we may handle |
@@ -128,7 +126,7 @@ void __init init_IRQ(void) | |||
128 | intc_writel(&intc0, INTPR0 + 4 * i, offset); | 126 | intc_writel(&intc0, INTPR0 + 4 * i, offset); |
129 | readback = intc_readl(&intc0, INTPR0 + 4 * i); | 127 | readback = intc_readl(&intc0, INTPR0 + 4 * i); |
130 | if (readback == offset) | 128 | if (readback == offset) |
131 | set_irq_chip_and_handler(i, &intc0.chip, | 129 | irq_set_chip_and_handler(i, &intc0.chip, |
132 | handle_simple_irq); | 130 | handle_simple_irq); |
133 | } | 131 | } |
134 | 132 | ||
diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c index 09a274c9d0b7..37534103574e 100644 --- a/arch/avr32/mach-at32ap/pio.c +++ b/arch/avr32/mach-at32ap/pio.c | |||
@@ -249,23 +249,23 @@ static void gpio_set(struct gpio_chip *chip, unsigned offset, int value) | |||
249 | 249 | ||
250 | /* GPIO IRQ support */ | 250 | /* GPIO IRQ support */ |
251 | 251 | ||
252 | static void gpio_irq_mask(unsigned irq) | 252 | static void gpio_irq_mask(struct irq_data *d) |
253 | { | 253 | { |
254 | unsigned gpio = irq_to_gpio(irq); | 254 | unsigned gpio = irq_to_gpio(d->irq); |
255 | struct pio_device *pio = &pio_dev[gpio >> 5]; | 255 | struct pio_device *pio = &pio_dev[gpio >> 5]; |
256 | 256 | ||
257 | pio_writel(pio, IDR, 1 << (gpio & 0x1f)); | 257 | pio_writel(pio, IDR, 1 << (gpio & 0x1f)); |
258 | } | 258 | } |
259 | 259 | ||
260 | static void gpio_irq_unmask(unsigned irq) | 260 | static void gpio_irq_unmask(struct irq_data *d)) |
261 | { | 261 | { |
262 | unsigned gpio = irq_to_gpio(irq); | 262 | unsigned gpio = irq_to_gpio(d->irq); |
263 | struct pio_device *pio = &pio_dev[gpio >> 5]; | 263 | struct pio_device *pio = &pio_dev[gpio >> 5]; |
264 | 264 | ||
265 | pio_writel(pio, IER, 1 << (gpio & 0x1f)); | 265 | pio_writel(pio, IER, 1 << (gpio & 0x1f)); |
266 | } | 266 | } |
267 | 267 | ||
268 | static int gpio_irq_type(unsigned irq, unsigned type) | 268 | static int gpio_irq_type(struct irq_data *d, unsigned type) |
269 | { | 269 | { |
270 | if (type != IRQ_TYPE_EDGE_BOTH && type != IRQ_TYPE_NONE) | 270 | if (type != IRQ_TYPE_EDGE_BOTH && type != IRQ_TYPE_NONE) |
271 | return -EINVAL; | 271 | return -EINVAL; |
@@ -275,20 +275,19 @@ static int gpio_irq_type(unsigned irq, unsigned type) | |||
275 | 275 | ||
276 | static struct irq_chip gpio_irqchip = { | 276 | static struct irq_chip gpio_irqchip = { |
277 | .name = "gpio", | 277 | .name = "gpio", |
278 | .mask = gpio_irq_mask, | 278 | .irq_mask = gpio_irq_mask, |
279 | .unmask = gpio_irq_unmask, | 279 | .irq_unmask = gpio_irq_unmask, |
280 | .set_type = gpio_irq_type, | 280 | .irq_set_type = gpio_irq_type, |
281 | }; | 281 | }; |
282 | 282 | ||
283 | static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) | 283 | static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) |
284 | { | 284 | { |
285 | struct pio_device *pio = get_irq_chip_data(irq); | 285 | struct pio_device *pio = get_irq_desc_chip_data(desc); |
286 | unsigned gpio_irq; | 286 | unsigned gpio_irq; |
287 | 287 | ||
288 | gpio_irq = (unsigned) get_irq_data(irq); | 288 | gpio_irq = (unsigned) irq_get_handler_data(irq); |
289 | for (;;) { | 289 | for (;;) { |
290 | u32 isr; | 290 | u32 isr; |
291 | struct irq_desc *d; | ||
292 | 291 | ||
293 | /* ack pending GPIO interrupts */ | 292 | /* ack pending GPIO interrupts */ |
294 | isr = pio_readl(pio, ISR) & pio_readl(pio, IMR); | 293 | isr = pio_readl(pio, ISR) & pio_readl(pio, IMR); |
@@ -301,9 +300,7 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) | |||
301 | isr &= ~(1 << i); | 300 | isr &= ~(1 << i); |
302 | 301 | ||
303 | i += gpio_irq; | 302 | i += gpio_irq; |
304 | d = &irq_desc[i]; | 303 | generic_handle_irq(i); |
305 | |||
306 | d->handle_irq(i, d); | ||
307 | } while (isr); | 304 | } while (isr); |
308 | } | 305 | } |
309 | } | 306 | } |
@@ -313,16 +310,16 @@ gpio_irq_setup(struct pio_device *pio, int irq, int gpio_irq) | |||
313 | { | 310 | { |
314 | unsigned i; | 311 | unsigned i; |
315 | 312 | ||
316 | set_irq_chip_data(irq, pio); | 313 | irq_set_chip_data(irq, pio); |
317 | set_irq_data(irq, (void *) gpio_irq); | 314 | irq_set_handler_data(irq, (void *)gpio_irq); |
318 | 315 | ||
319 | for (i = 0; i < 32; i++, gpio_irq++) { | 316 | for (i = 0; i < 32; i++, gpio_irq++) { |
320 | set_irq_chip_data(gpio_irq, pio); | 317 | irq_set_chip_data(gpio_irq, pio); |
321 | set_irq_chip_and_handler(gpio_irq, &gpio_irqchip, | 318 | irq_set_chip_and_handler(gpio_irq, &gpio_irqchip, |
322 | handle_simple_irq); | 319 | handle_simple_irq); |
323 | } | 320 | } |
324 | 321 | ||
325 | set_irq_chained_handler(irq, gpio_irq_handler); | 322 | irq_set_chained_handler(irq, gpio_irq_handler); |
326 | } | 323 | } |
327 | 324 | ||
328 | /*--------------------------------------------------------------------------*/ | 325 | /*--------------------------------------------------------------------------*/ |
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index 4db5b46e1eff..04a7fc5eaf46 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig | |||
@@ -276,7 +276,6 @@ config ETRAX_AXISFLASHMAP | |||
276 | select MTD_CHAR | 276 | select MTD_CHAR |
277 | select MTD_BLOCK | 277 | select MTD_BLOCK |
278 | select MTD_PARTITIONS | 278 | select MTD_PARTITIONS |
279 | select MTD_CONCAT | ||
280 | select MTD_COMPLEX_MAPPINGS | 279 | select MTD_COMPLEX_MAPPINGS |
281 | help | 280 | help |
282 | This option enables MTD mapping of flash devices. Needed to use | 281 | This option enables MTD mapping of flash devices. Needed to use |
diff --git a/arch/cris/arch-v10/drivers/axisflashmap.c b/arch/cris/arch-v10/drivers/axisflashmap.c index b2079703af7e..ed708e19d09e 100644 --- a/arch/cris/arch-v10/drivers/axisflashmap.c +++ b/arch/cris/arch-v10/drivers/axisflashmap.c | |||
@@ -234,7 +234,6 @@ static struct mtd_info *flash_probe(void) | |||
234 | } | 234 | } |
235 | 235 | ||
236 | if (mtd_cse0 && mtd_cse1) { | 236 | if (mtd_cse0 && mtd_cse1) { |
237 | #ifdef CONFIG_MTD_CONCAT | ||
238 | struct mtd_info *mtds[] = { mtd_cse0, mtd_cse1 }; | 237 | struct mtd_info *mtds[] = { mtd_cse0, mtd_cse1 }; |
239 | 238 | ||
240 | /* Since the concatenation layer adds a small overhead we | 239 | /* Since the concatenation layer adds a small overhead we |
@@ -246,11 +245,6 @@ static struct mtd_info *flash_probe(void) | |||
246 | */ | 245 | */ |
247 | mtd_cse = mtd_concat_create(mtds, ARRAY_SIZE(mtds), | 246 | mtd_cse = mtd_concat_create(mtds, ARRAY_SIZE(mtds), |
248 | "cse0+cse1"); | 247 | "cse0+cse1"); |
249 | #else | ||
250 | printk(KERN_ERR "%s and %s: Cannot concatenate due to kernel " | ||
251 | "(mis)configuration!\n", map_cse0.name, map_cse1.name); | ||
252 | mtd_cse = NULL; | ||
253 | #endif | ||
254 | if (!mtd_cse) { | 248 | if (!mtd_cse) { |
255 | printk(KERN_ERR "%s and %s: Concatenation failed!\n", | 249 | printk(KERN_ERR "%s and %s: Concatenation failed!\n", |
256 | map_cse0.name, map_cse1.name); | 250 | map_cse0.name, map_cse1.name); |
diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig index a2dd740c5907..1633b120aa81 100644 --- a/arch/cris/arch-v32/drivers/Kconfig +++ b/arch/cris/arch-v32/drivers/Kconfig | |||
@@ -406,7 +406,6 @@ config ETRAX_AXISFLASHMAP | |||
406 | select MTD_CHAR | 406 | select MTD_CHAR |
407 | select MTD_BLOCK | 407 | select MTD_BLOCK |
408 | select MTD_PARTITIONS | 408 | select MTD_PARTITIONS |
409 | select MTD_CONCAT | ||
410 | select MTD_COMPLEX_MAPPINGS | 409 | select MTD_COMPLEX_MAPPINGS |
411 | help | 410 | help |
412 | This option enables MTD mapping of flash devices. Needed to use | 411 | This option enables MTD mapping of flash devices. Needed to use |
diff --git a/arch/cris/arch-v32/drivers/axisflashmap.c b/arch/cris/arch-v32/drivers/axisflashmap.c index 51e1e85df96d..3d751250271b 100644 --- a/arch/cris/arch-v32/drivers/axisflashmap.c +++ b/arch/cris/arch-v32/drivers/axisflashmap.c | |||
@@ -275,7 +275,6 @@ static struct mtd_info *flash_probe(void) | |||
275 | } | 275 | } |
276 | 276 | ||
277 | if (count > 1) { | 277 | if (count > 1) { |
278 | #ifdef CONFIG_MTD_CONCAT | ||
279 | /* Since the concatenation layer adds a small overhead we | 278 | /* Since the concatenation layer adds a small overhead we |
280 | * could try to figure out if the chips in cse0 and cse1 are | 279 | * could try to figure out if the chips in cse0 and cse1 are |
281 | * identical and reprobe the whole cse0+cse1 window. But since | 280 | * identical and reprobe the whole cse0+cse1 window. But since |
@@ -284,11 +283,6 @@ static struct mtd_info *flash_probe(void) | |||
284 | * complicating the probing procedure. | 283 | * complicating the probing procedure. |
285 | */ | 284 | */ |
286 | mtd_total = mtd_concat_create(mtds, count, "cse0+cse1"); | 285 | mtd_total = mtd_concat_create(mtds, count, "cse0+cse1"); |
287 | #else | ||
288 | printk(KERN_ERR "%s and %s: Cannot concatenate due to kernel " | ||
289 | "(mis)configuration!\n", map_cse0.name, map_cse1.name); | ||
290 | mtd_toal = NULL; | ||
291 | #endif | ||
292 | if (!mtd_total) { | 286 | if (!mtd_total) { |
293 | printk(KERN_ERR "%s and %s: Concatenation failed!\n", | 287 | printk(KERN_ERR "%s and %s: Concatenation failed!\n", |
294 | map_cse0.name, map_cse1.name); | 288 | map_cse0.name, map_cse1.name); |
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig index 9624db193e3c..931a1ac99ff1 100644 --- a/arch/h8300/Kconfig +++ b/arch/h8300/Kconfig | |||
@@ -4,6 +4,7 @@ config H8300 | |||
4 | select HAVE_IDE | 4 | select HAVE_IDE |
5 | select HAVE_GENERIC_HARDIRQS | 5 | select HAVE_GENERIC_HARDIRQS |
6 | select GENERIC_HARDIRQS_NO_DEPRECATED | 6 | select GENERIC_HARDIRQS_NO_DEPRECATED |
7 | select GENERIC_IRQ_SHOW | ||
7 | 8 | ||
8 | config SYMBOL_PREFIX | 9 | config SYMBOL_PREFIX |
9 | string | 10 | string |
diff --git a/arch/h8300/kernel/irq.c b/arch/h8300/kernel/irq.c index 7643d39925d6..1f67fed476af 100644 --- a/arch/h8300/kernel/irq.c +++ b/arch/h8300/kernel/irq.c | |||
@@ -155,7 +155,7 @@ void __init init_IRQ(void) | |||
155 | setup_vector(); | 155 | setup_vector(); |
156 | 156 | ||
157 | for (c = 0; c < NR_IRQS; c++) | 157 | for (c = 0; c < NR_IRQS; c++) |
158 | set_irq_chip_and_handler(c, &h8300irq_chip, handle_simple_irq); | 158 | irq_set_chip_and_handler(c, &h8300irq_chip, handle_simple_irq); |
159 | } | 159 | } |
160 | 160 | ||
161 | asmlinkage void do_IRQ(int irq) | 161 | asmlinkage void do_IRQ(int irq) |
@@ -164,34 +164,3 @@ asmlinkage void do_IRQ(int irq) | |||
164 | generic_handle_irq(irq); | 164 | generic_handle_irq(irq); |
165 | irq_exit(); | 165 | irq_exit(); |
166 | } | 166 | } |
167 | |||
168 | #if defined(CONFIG_PROC_FS) | ||
169 | int show_interrupts(struct seq_file *p, void *v) | ||
170 | { | ||
171 | int i = *(loff_t *) v; | ||
172 | struct irqaction * action; | ||
173 | unsigned long flags; | ||
174 | |||
175 | if (i == 0) | ||
176 | seq_puts(p, " CPU0"); | ||
177 | |||
178 | if (i < NR_IRQS) { | ||
179 | raw_spin_lock_irqsave(&irq_desc[i].lock, flags); | ||
180 | action = irq_desc[i].action; | ||
181 | if (!action) | ||
182 | goto unlock; | ||
183 | seq_printf(p, "%3d: ",i); | ||
184 | seq_printf(p, "%10u ", kstat_irqs(i)); | ||
185 | seq_printf(p, " %14s", irq_desc[i].irq_data.chip->name); | ||
186 | seq_printf(p, "-%-8s", irq_desc[i].name); | ||
187 | seq_printf(p, " %s", action->name); | ||
188 | |||
189 | for (action=action->next; action; action = action->next) | ||
190 | seq_printf(p, ", %s", action->name); | ||
191 | seq_putc(p, '\n'); | ||
192 | unlock: | ||
193 | raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags); | ||
194 | } | ||
195 | return 0; | ||
196 | } | ||
197 | #endif | ||
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c index 54bf54059811..9a018cde5d84 100644 --- a/arch/ia64/mm/contig.c +++ b/arch/ia64/mm/contig.c | |||
@@ -36,7 +36,7 @@ static unsigned long max_gap; | |||
36 | * Shows a simple page count of reserved and used pages in the system. | 36 | * Shows a simple page count of reserved and used pages in the system. |
37 | * For discontig machines, it does this on a per-pgdat basis. | 37 | * For discontig machines, it does this on a per-pgdat basis. |
38 | */ | 38 | */ |
39 | void show_mem(void) | 39 | void show_mem(unsigned int filter) |
40 | { | 40 | { |
41 | int i, total_reserved = 0; | 41 | int i, total_reserved = 0; |
42 | int total_shared = 0, total_cached = 0; | 42 | int total_shared = 0, total_cached = 0; |
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c index 61620323bb60..82ab1bc6afb1 100644 --- a/arch/ia64/mm/discontig.c +++ b/arch/ia64/mm/discontig.c | |||
@@ -614,7 +614,7 @@ void __cpuinit *per_cpu_init(void) | |||
614 | * Shows a simple page count of reserved and used pages in the system. | 614 | * Shows a simple page count of reserved and used pages in the system. |
615 | * For discontig machines, it does this on a per-pgdat basis. | 615 | * For discontig machines, it does this on a per-pgdat basis. |
616 | */ | 616 | */ |
617 | void show_mem(void) | 617 | void show_mem(unsigned int filter) |
618 | { | 618 | { |
619 | int i, total_reserved = 0; | 619 | int i, total_reserved = 0; |
620 | int total_shared = 0, total_cached = 0; | 620 | int total_shared = 0, total_cached = 0; |
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig index 62afe23c9a49..b28d0908a402 100644 --- a/arch/m32r/Kconfig +++ b/arch/m32r/Kconfig | |||
@@ -10,6 +10,7 @@ config M32R | |||
10 | select HAVE_GENERIC_HARDIRQS | 10 | select HAVE_GENERIC_HARDIRQS |
11 | select GENERIC_HARDIRQS_NO_DEPRECATED | 11 | select GENERIC_HARDIRQS_NO_DEPRECATED |
12 | select GENERIC_IRQ_PROBE | 12 | select GENERIC_IRQ_PROBE |
13 | select GENERIC_IRQ_SHOW | ||
13 | 14 | ||
14 | config SBUS | 15 | config SBUS |
15 | bool | 16 | bool |
diff --git a/arch/m32r/kernel/irq.c b/arch/m32r/kernel/irq.c index 76eaf3883fbd..c7272b894283 100644 --- a/arch/m32r/kernel/irq.c +++ b/arch/m32r/kernel/irq.c | |||
@@ -18,55 +18,10 @@ | |||
18 | 18 | ||
19 | #include <linux/kernel_stat.h> | 19 | #include <linux/kernel_stat.h> |
20 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
21 | #include <linux/seq_file.h> | ||
22 | #include <linux/module.h> | 21 | #include <linux/module.h> |
23 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
24 | 23 | ||
25 | /* | 24 | /* |
26 | * Generic, controller-independent functions: | ||
27 | */ | ||
28 | |||
29 | int show_interrupts(struct seq_file *p, void *v) | ||
30 | { | ||
31 | int i = *(loff_t *) v, j; | ||
32 | struct irqaction * action; | ||
33 | unsigned long flags; | ||
34 | |||
35 | if (i == 0) { | ||
36 | seq_printf(p, " "); | ||
37 | for_each_online_cpu(j) | ||
38 | seq_printf(p, "CPU%d ",j); | ||
39 | seq_putc(p, '\n'); | ||
40 | } | ||
41 | |||
42 | if (i < NR_IRQS) { | ||
43 | struct irq_desc *desc = irq_to_desc(i); | ||
44 | |||
45 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
46 | action = desc->action; | ||
47 | if (!action) | ||
48 | goto skip; | ||
49 | seq_printf(p, "%3d: ",i); | ||
50 | #ifndef CONFIG_SMP | ||
51 | seq_printf(p, "%10u ", kstat_irqs(i)); | ||
52 | #else | ||
53 | for_each_online_cpu(j) | ||
54 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); | ||
55 | #endif | ||
56 | seq_printf(p, " %14s", desc->irq_data.chip->name); | ||
57 | seq_printf(p, " %s", action->name); | ||
58 | |||
59 | for (action=action->next; action; action = action->next) | ||
60 | seq_printf(p, ", %s", action->name); | ||
61 | |||
62 | seq_putc(p, '\n'); | ||
63 | skip: | ||
64 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
65 | } | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * do_IRQ handles all normal device IRQs (the special | 25 | * do_IRQ handles all normal device IRQs (the special |
71 | * SMP cross-CPU interrupts have their own specific | 26 | * SMP cross-CPU interrupts have their own specific |
72 | * handlers). | 27 | * handlers). |
diff --git a/arch/m32r/platforms/m32104ut/setup.c b/arch/m32r/platforms/m32104ut/setup.c index 4a693d02c1e1..34671d32cefc 100644 --- a/arch/m32r/platforms/m32104ut/setup.c +++ b/arch/m32r/platforms/m32104ut/setup.c | |||
@@ -76,7 +76,7 @@ void __init init_IRQ(void) | |||
76 | 76 | ||
77 | #if defined(CONFIG_SMC91X) | 77 | #if defined(CONFIG_SMC91X) |
78 | /* INT#0: LAN controller on M32104UT-LAN (SMC91C111)*/ | 78 | /* INT#0: LAN controller on M32104UT-LAN (SMC91C111)*/ |
79 | set_irq_chip_and_handler(M32R_IRQ_INT0, &m32104ut_irq_type, | 79 | irq_set_chip_and_handler(M32R_IRQ_INT0, &m32104ut_irq_type, |
80 | handle_level_irq); | 80 | handle_level_irq); |
81 | /* "H" level sense */ | 81 | /* "H" level sense */ |
82 | cu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD11; | 82 | cu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD11; |
@@ -84,20 +84,20 @@ void __init init_IRQ(void) | |||
84 | #endif /* CONFIG_SMC91X */ | 84 | #endif /* CONFIG_SMC91X */ |
85 | 85 | ||
86 | /* MFT2 : system timer */ | 86 | /* MFT2 : system timer */ |
87 | set_irq_chip_and_handler(M32R_IRQ_MFT2, &m32104ut_irq_type, | 87 | irq_set_chip_and_handler(M32R_IRQ_MFT2, &m32104ut_irq_type, |
88 | handle_level_irq); | 88 | handle_level_irq); |
89 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; | 89 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; |
90 | disable_m32104ut_irq(M32R_IRQ_MFT2); | 90 | disable_m32104ut_irq(M32R_IRQ_MFT2); |
91 | 91 | ||
92 | #ifdef CONFIG_SERIAL_M32R_SIO | 92 | #ifdef CONFIG_SERIAL_M32R_SIO |
93 | /* SIO0_R : uart receive data */ | 93 | /* SIO0_R : uart receive data */ |
94 | set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &m32104ut_irq_type, | 94 | irq_set_chip_and_handler(M32R_IRQ_SIO0_R, &m32104ut_irq_type, |
95 | handle_level_irq); | 95 | handle_level_irq); |
96 | icu_data[M32R_IRQ_SIO0_R].icucr = M32R_ICUCR_IEN; | 96 | icu_data[M32R_IRQ_SIO0_R].icucr = M32R_ICUCR_IEN; |
97 | disable_m32104ut_irq(M32R_IRQ_SIO0_R); | 97 | disable_m32104ut_irq(M32R_IRQ_SIO0_R); |
98 | 98 | ||
99 | /* SIO0_S : uart send data */ | 99 | /* SIO0_S : uart send data */ |
100 | set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &m32104ut_irq_type, | 100 | irq_set_chip_and_handler(M32R_IRQ_SIO0_S, &m32104ut_irq_type, |
101 | handle_level_irq); | 101 | handle_level_irq); |
102 | icu_data[M32R_IRQ_SIO0_S].icucr = M32R_ICUCR_IEN; | 102 | icu_data[M32R_IRQ_SIO0_S].icucr = M32R_ICUCR_IEN; |
103 | disable_m32104ut_irq(M32R_IRQ_SIO0_S); | 103 | disable_m32104ut_irq(M32R_IRQ_SIO0_S); |
diff --git a/arch/m32r/platforms/m32700ut/setup.c b/arch/m32r/platforms/m32700ut/setup.c index 2074bcc841eb..1053e1cb7401 100644 --- a/arch/m32r/platforms/m32700ut/setup.c +++ b/arch/m32r/platforms/m32700ut/setup.c | |||
@@ -259,76 +259,76 @@ void __init init_IRQ(void) | |||
259 | { | 259 | { |
260 | #if defined(CONFIG_SMC91X) | 260 | #if defined(CONFIG_SMC91X) |
261 | /* INT#0: LAN controller on M32700UT-LAN (SMC91C111)*/ | 261 | /* INT#0: LAN controller on M32700UT-LAN (SMC91C111)*/ |
262 | set_irq_chip_and_handler(M32700UT_LAN_IRQ_LAN, | 262 | irq_set_chip_and_handler(M32700UT_LAN_IRQ_LAN, |
263 | &m32700ut_lanpld_irq_type, handle_level_irq); | 263 | &m32700ut_lanpld_irq_type, handle_level_irq); |
264 | lanpld_icu_data[irq2lanpldirq(M32700UT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* "H" edge sense */ | 264 | lanpld_icu_data[irq2lanpldirq(M32700UT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* "H" edge sense */ |
265 | disable_m32700ut_lanpld_irq(M32700UT_LAN_IRQ_LAN); | 265 | disable_m32700ut_lanpld_irq(M32700UT_LAN_IRQ_LAN); |
266 | #endif /* CONFIG_SMC91X */ | 266 | #endif /* CONFIG_SMC91X */ |
267 | 267 | ||
268 | /* MFT2 : system timer */ | 268 | /* MFT2 : system timer */ |
269 | set_irq_chip_and_handler(M32R_IRQ_MFT2, &m32700ut_irq_type, | 269 | irq_set_chip_and_handler(M32R_IRQ_MFT2, &m32700ut_irq_type, |
270 | handle_level_irq); | 270 | handle_level_irq); |
271 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; | 271 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; |
272 | disable_m32700ut_irq(M32R_IRQ_MFT2); | 272 | disable_m32700ut_irq(M32R_IRQ_MFT2); |
273 | 273 | ||
274 | /* SIO0 : receive */ | 274 | /* SIO0 : receive */ |
275 | set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &m32700ut_irq_type, | 275 | irq_set_chip_and_handler(M32R_IRQ_SIO0_R, &m32700ut_irq_type, |
276 | handle_level_irq); | 276 | handle_level_irq); |
277 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; | 277 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; |
278 | disable_m32700ut_irq(M32R_IRQ_SIO0_R); | 278 | disable_m32700ut_irq(M32R_IRQ_SIO0_R); |
279 | 279 | ||
280 | /* SIO0 : send */ | 280 | /* SIO0 : send */ |
281 | set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &m32700ut_irq_type, | 281 | irq_set_chip_and_handler(M32R_IRQ_SIO0_S, &m32700ut_irq_type, |
282 | handle_level_irq); | 282 | handle_level_irq); |
283 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; | 283 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; |
284 | disable_m32700ut_irq(M32R_IRQ_SIO0_S); | 284 | disable_m32700ut_irq(M32R_IRQ_SIO0_S); |
285 | 285 | ||
286 | /* SIO1 : receive */ | 286 | /* SIO1 : receive */ |
287 | set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &m32700ut_irq_type, | 287 | irq_set_chip_and_handler(M32R_IRQ_SIO1_R, &m32700ut_irq_type, |
288 | handle_level_irq); | 288 | handle_level_irq); |
289 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; | 289 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; |
290 | disable_m32700ut_irq(M32R_IRQ_SIO1_R); | 290 | disable_m32700ut_irq(M32R_IRQ_SIO1_R); |
291 | 291 | ||
292 | /* SIO1 : send */ | 292 | /* SIO1 : send */ |
293 | set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &m32700ut_irq_type, | 293 | irq_set_chip_and_handler(M32R_IRQ_SIO1_S, &m32700ut_irq_type, |
294 | handle_level_irq); | 294 | handle_level_irq); |
295 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; | 295 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; |
296 | disable_m32700ut_irq(M32R_IRQ_SIO1_S); | 296 | disable_m32700ut_irq(M32R_IRQ_SIO1_S); |
297 | 297 | ||
298 | /* DMA1 : */ | 298 | /* DMA1 : */ |
299 | set_irq_chip_and_handler(M32R_IRQ_DMA1, &m32700ut_irq_type, | 299 | irq_set_chip_and_handler(M32R_IRQ_DMA1, &m32700ut_irq_type, |
300 | handle_level_irq); | 300 | handle_level_irq); |
301 | icu_data[M32R_IRQ_DMA1].icucr = 0; | 301 | icu_data[M32R_IRQ_DMA1].icucr = 0; |
302 | disable_m32700ut_irq(M32R_IRQ_DMA1); | 302 | disable_m32700ut_irq(M32R_IRQ_DMA1); |
303 | 303 | ||
304 | #ifdef CONFIG_SERIAL_M32R_PLDSIO | 304 | #ifdef CONFIG_SERIAL_M32R_PLDSIO |
305 | /* INT#1: SIO0 Receive on PLD */ | 305 | /* INT#1: SIO0 Receive on PLD */ |
306 | set_irq_chip_and_handler(PLD_IRQ_SIO0_RCV, &m32700ut_pld_irq_type, | 306 | irq_set_chip_and_handler(PLD_IRQ_SIO0_RCV, &m32700ut_pld_irq_type, |
307 | handle_level_irq); | 307 | handle_level_irq); |
308 | pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; | 308 | pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; |
309 | disable_m32700ut_pld_irq(PLD_IRQ_SIO0_RCV); | 309 | disable_m32700ut_pld_irq(PLD_IRQ_SIO0_RCV); |
310 | 310 | ||
311 | /* INT#1: SIO0 Send on PLD */ | 311 | /* INT#1: SIO0 Send on PLD */ |
312 | set_irq_chip_and_handler(PLD_IRQ_SIO0_SND, &m32700ut_pld_irq_type, | 312 | irq_set_chip_and_handler(PLD_IRQ_SIO0_SND, &m32700ut_pld_irq_type, |
313 | handle_level_irq); | 313 | handle_level_irq); |
314 | pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; | 314 | pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; |
315 | disable_m32700ut_pld_irq(PLD_IRQ_SIO0_SND); | 315 | disable_m32700ut_pld_irq(PLD_IRQ_SIO0_SND); |
316 | #endif /* CONFIG_SERIAL_M32R_PLDSIO */ | 316 | #endif /* CONFIG_SERIAL_M32R_PLDSIO */ |
317 | 317 | ||
318 | /* INT#1: CFC IREQ on PLD */ | 318 | /* INT#1: CFC IREQ on PLD */ |
319 | set_irq_chip_and_handler(PLD_IRQ_CFIREQ, &m32700ut_pld_irq_type, | 319 | irq_set_chip_and_handler(PLD_IRQ_CFIREQ, &m32700ut_pld_irq_type, |
320 | handle_level_irq); | 320 | handle_level_irq); |
321 | pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* 'L' level sense */ | 321 | pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* 'L' level sense */ |
322 | disable_m32700ut_pld_irq(PLD_IRQ_CFIREQ); | 322 | disable_m32700ut_pld_irq(PLD_IRQ_CFIREQ); |
323 | 323 | ||
324 | /* INT#1: CFC Insert on PLD */ | 324 | /* INT#1: CFC Insert on PLD */ |
325 | set_irq_chip_and_handler(PLD_IRQ_CFC_INSERT, &m32700ut_pld_irq_type, | 325 | irq_set_chip_and_handler(PLD_IRQ_CFC_INSERT, &m32700ut_pld_irq_type, |
326 | handle_level_irq); | 326 | handle_level_irq); |
327 | pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00; /* 'L' edge sense */ | 327 | pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00; /* 'L' edge sense */ |
328 | disable_m32700ut_pld_irq(PLD_IRQ_CFC_INSERT); | 328 | disable_m32700ut_pld_irq(PLD_IRQ_CFC_INSERT); |
329 | 329 | ||
330 | /* INT#1: CFC Eject on PLD */ | 330 | /* INT#1: CFC Eject on PLD */ |
331 | set_irq_chip_and_handler(PLD_IRQ_CFC_EJECT, &m32700ut_pld_irq_type, | 331 | irq_set_chip_and_handler(PLD_IRQ_CFC_EJECT, &m32700ut_pld_irq_type, |
332 | handle_level_irq); | 332 | handle_level_irq); |
333 | pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* 'H' edge sense */ | 333 | pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* 'H' edge sense */ |
334 | disable_m32700ut_pld_irq(PLD_IRQ_CFC_EJECT); | 334 | disable_m32700ut_pld_irq(PLD_IRQ_CFC_EJECT); |
@@ -349,7 +349,7 @@ void __init init_IRQ(void) | |||
349 | 349 | ||
350 | #if defined(CONFIG_USB) | 350 | #if defined(CONFIG_USB) |
351 | outw(USBCR_OTGS, USBCR); /* USBCR: non-OTG */ | 351 | outw(USBCR_OTGS, USBCR); /* USBCR: non-OTG */ |
352 | set_irq_chip_and_handler(M32700UT_LCD_IRQ_USB_INT1, | 352 | irq_set_chip_and_handler(M32700UT_LCD_IRQ_USB_INT1, |
353 | &m32700ut_lcdpld_irq_type, handle_level_irq); | 353 | &m32700ut_lcdpld_irq_type, handle_level_irq); |
354 | 354 | ||
355 | lcdpld_icu_data[irq2lcdpldirq(M32700UT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* "L" level sense */ | 355 | lcdpld_icu_data[irq2lcdpldirq(M32700UT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* "L" level sense */ |
@@ -366,7 +366,7 @@ void __init init_IRQ(void) | |||
366 | /* | 366 | /* |
367 | * INT3# is used for AR | 367 | * INT3# is used for AR |
368 | */ | 368 | */ |
369 | set_irq_chip_and_handler(M32R_IRQ_INT3, &m32700ut_irq_type, | 369 | irq_set_chip_and_handler(M32R_IRQ_INT3, &m32700ut_irq_type, |
370 | handle_level_irq); | 370 | handle_level_irq); |
371 | icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; | 371 | icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; |
372 | disable_m32700ut_irq(M32R_IRQ_INT3); | 372 | disable_m32700ut_irq(M32R_IRQ_INT3); |
diff --git a/arch/m32r/platforms/mappi/setup.c b/arch/m32r/platforms/mappi/setup.c index cdd8c4574027..35130ac3f8d1 100644 --- a/arch/m32r/platforms/mappi/setup.c +++ b/arch/m32r/platforms/mappi/setup.c | |||
@@ -75,39 +75,39 @@ void __init init_IRQ(void) | |||
75 | 75 | ||
76 | #ifdef CONFIG_NE2000 | 76 | #ifdef CONFIG_NE2000 |
77 | /* INT0 : LAN controller (RTL8019AS) */ | 77 | /* INT0 : LAN controller (RTL8019AS) */ |
78 | set_irq_chip_and_handler(M32R_IRQ_INT0, &mappi_irq_type, | 78 | irq_set_chip_and_handler(M32R_IRQ_INT0, &mappi_irq_type, |
79 | handle_level_irq); | 79 | handle_level_irq); |
80 | icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11; | 80 | icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11; |
81 | disable_mappi_irq(M32R_IRQ_INT0); | 81 | disable_mappi_irq(M32R_IRQ_INT0); |
82 | #endif /* CONFIG_M32R_NE2000 */ | 82 | #endif /* CONFIG_M32R_NE2000 */ |
83 | 83 | ||
84 | /* MFT2 : system timer */ | 84 | /* MFT2 : system timer */ |
85 | set_irq_chip_and_handler(M32R_IRQ_MFT2, &mappi_irq_type, | 85 | irq_set_chip_and_handler(M32R_IRQ_MFT2, &mappi_irq_type, |
86 | handle_level_irq); | 86 | handle_level_irq); |
87 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; | 87 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; |
88 | disable_mappi_irq(M32R_IRQ_MFT2); | 88 | disable_mappi_irq(M32R_IRQ_MFT2); |
89 | 89 | ||
90 | #ifdef CONFIG_SERIAL_M32R_SIO | 90 | #ifdef CONFIG_SERIAL_M32R_SIO |
91 | /* SIO0_R : uart receive data */ | 91 | /* SIO0_R : uart receive data */ |
92 | set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &mappi_irq_type, | 92 | irq_set_chip_and_handler(M32R_IRQ_SIO0_R, &mappi_irq_type, |
93 | handle_level_irq); | 93 | handle_level_irq); |
94 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; | 94 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; |
95 | disable_mappi_irq(M32R_IRQ_SIO0_R); | 95 | disable_mappi_irq(M32R_IRQ_SIO0_R); |
96 | 96 | ||
97 | /* SIO0_S : uart send data */ | 97 | /* SIO0_S : uart send data */ |
98 | set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &mappi_irq_type, | 98 | irq_set_chip_and_handler(M32R_IRQ_SIO0_S, &mappi_irq_type, |
99 | handle_level_irq); | 99 | handle_level_irq); |
100 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; | 100 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; |
101 | disable_mappi_irq(M32R_IRQ_SIO0_S); | 101 | disable_mappi_irq(M32R_IRQ_SIO0_S); |
102 | 102 | ||
103 | /* SIO1_R : uart receive data */ | 103 | /* SIO1_R : uart receive data */ |
104 | set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &mappi_irq_type, | 104 | irq_set_chip_and_handler(M32R_IRQ_SIO1_R, &mappi_irq_type, |
105 | handle_level_irq); | 105 | handle_level_irq); |
106 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; | 106 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; |
107 | disable_mappi_irq(M32R_IRQ_SIO1_R); | 107 | disable_mappi_irq(M32R_IRQ_SIO1_R); |
108 | 108 | ||
109 | /* SIO1_S : uart send data */ | 109 | /* SIO1_S : uart send data */ |
110 | set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &mappi_irq_type, | 110 | irq_set_chip_and_handler(M32R_IRQ_SIO1_S, &mappi_irq_type, |
111 | handle_level_irq); | 111 | handle_level_irq); |
112 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; | 112 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; |
113 | disable_mappi_irq(M32R_IRQ_SIO1_S); | 113 | disable_mappi_irq(M32R_IRQ_SIO1_S); |
@@ -115,13 +115,13 @@ void __init init_IRQ(void) | |||
115 | 115 | ||
116 | #if defined(CONFIG_M32R_PCC) | 116 | #if defined(CONFIG_M32R_PCC) |
117 | /* INT1 : pccard0 interrupt */ | 117 | /* INT1 : pccard0 interrupt */ |
118 | set_irq_chip_and_handler(M32R_IRQ_INT1, &mappi_irq_type, | 118 | irq_set_chip_and_handler(M32R_IRQ_INT1, &mappi_irq_type, |
119 | handle_level_irq); | 119 | handle_level_irq); |
120 | icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00; | 120 | icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00; |
121 | disable_mappi_irq(M32R_IRQ_INT1); | 121 | disable_mappi_irq(M32R_IRQ_INT1); |
122 | 122 | ||
123 | /* INT2 : pccard1 interrupt */ | 123 | /* INT2 : pccard1 interrupt */ |
124 | set_irq_chip_and_handler(M32R_IRQ_INT2, &mappi_irq_type, | 124 | irq_set_chip_and_handler(M32R_IRQ_INT2, &mappi_irq_type, |
125 | handle_level_irq); | 125 | handle_level_irq); |
126 | icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00; | 126 | icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00; |
127 | disable_mappi_irq(M32R_IRQ_INT2); | 127 | disable_mappi_irq(M32R_IRQ_INT2); |
diff --git a/arch/m32r/platforms/mappi2/setup.c b/arch/m32r/platforms/mappi2/setup.c index 9117c30ea365..f3ed6b60a5f8 100644 --- a/arch/m32r/platforms/mappi2/setup.c +++ b/arch/m32r/platforms/mappi2/setup.c | |||
@@ -76,38 +76,38 @@ void __init init_IRQ(void) | |||
76 | { | 76 | { |
77 | #if defined(CONFIG_SMC91X) | 77 | #if defined(CONFIG_SMC91X) |
78 | /* INT0 : LAN controller (SMC91111) */ | 78 | /* INT0 : LAN controller (SMC91111) */ |
79 | set_irq_chip_and_handler(M32R_IRQ_INT0, &mappi2_irq_type, | 79 | irq_set_chip_and_handler(M32R_IRQ_INT0, &mappi2_irq_type, |
80 | handle_level_irq); | 80 | handle_level_irq); |
81 | icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; | 81 | icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; |
82 | disable_mappi2_irq(M32R_IRQ_INT0); | 82 | disable_mappi2_irq(M32R_IRQ_INT0); |
83 | #endif /* CONFIG_SMC91X */ | 83 | #endif /* CONFIG_SMC91X */ |
84 | 84 | ||
85 | /* MFT2 : system timer */ | 85 | /* MFT2 : system timer */ |
86 | set_irq_chip_and_handler(M32R_IRQ_MFT2, &mappi2_irq_type, | 86 | irq_set_chip_and_handler(M32R_IRQ_MFT2, &mappi2_irq_type, |
87 | handle_level_irq); | 87 | handle_level_irq); |
88 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; | 88 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; |
89 | disable_mappi2_irq(M32R_IRQ_MFT2); | 89 | disable_mappi2_irq(M32R_IRQ_MFT2); |
90 | 90 | ||
91 | #ifdef CONFIG_SERIAL_M32R_SIO | 91 | #ifdef CONFIG_SERIAL_M32R_SIO |
92 | /* SIO0_R : uart receive data */ | 92 | /* SIO0_R : uart receive data */ |
93 | set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &mappi2_irq_type, | 93 | irq_set_chip_and_handler(M32R_IRQ_SIO0_R, &mappi2_irq_type, |
94 | handle_level_irq); | 94 | handle_level_irq); |
95 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; | 95 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; |
96 | disable_mappi2_irq(M32R_IRQ_SIO0_R); | 96 | disable_mappi2_irq(M32R_IRQ_SIO0_R); |
97 | 97 | ||
98 | /* SIO0_S : uart send data */ | 98 | /* SIO0_S : uart send data */ |
99 | set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &mappi2_irq_type, | 99 | irq_set_chip_and_handler(M32R_IRQ_SIO0_S, &mappi2_irq_type, |
100 | handle_level_irq); | 100 | handle_level_irq); |
101 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; | 101 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; |
102 | disable_mappi2_irq(M32R_IRQ_SIO0_S); | 102 | disable_mappi2_irq(M32R_IRQ_SIO0_S); |
103 | /* SIO1_R : uart receive data */ | 103 | /* SIO1_R : uart receive data */ |
104 | set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &mappi2_irq_type, | 104 | irq_set_chip_and_handler(M32R_IRQ_SIO1_R, &mappi2_irq_type, |
105 | handle_level_irq); | 105 | handle_level_irq); |
106 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; | 106 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; |
107 | disable_mappi2_irq(M32R_IRQ_SIO1_R); | 107 | disable_mappi2_irq(M32R_IRQ_SIO1_R); |
108 | 108 | ||
109 | /* SIO1_S : uart send data */ | 109 | /* SIO1_S : uart send data */ |
110 | set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &mappi2_irq_type, | 110 | irq_set_chip_and_handler(M32R_IRQ_SIO1_S, &mappi2_irq_type, |
111 | handle_level_irq); | 111 | handle_level_irq); |
112 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; | 112 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; |
113 | disable_mappi2_irq(M32R_IRQ_SIO1_S); | 113 | disable_mappi2_irq(M32R_IRQ_SIO1_S); |
@@ -115,27 +115,27 @@ void __init init_IRQ(void) | |||
115 | 115 | ||
116 | #if defined(CONFIG_USB) | 116 | #if defined(CONFIG_USB) |
117 | /* INT1 : USB Host controller interrupt */ | 117 | /* INT1 : USB Host controller interrupt */ |
118 | set_irq_chip_and_handler(M32R_IRQ_INT1, &mappi2_irq_type, | 118 | irq_set_chip_and_handler(M32R_IRQ_INT1, &mappi2_irq_type, |
119 | handle_level_irq); | 119 | handle_level_irq); |
120 | icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01; | 120 | icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01; |
121 | disable_mappi2_irq(M32R_IRQ_INT1); | 121 | disable_mappi2_irq(M32R_IRQ_INT1); |
122 | #endif /* CONFIG_USB */ | 122 | #endif /* CONFIG_USB */ |
123 | 123 | ||
124 | /* ICUCR40: CFC IREQ */ | 124 | /* ICUCR40: CFC IREQ */ |
125 | set_irq_chip_and_handler(PLD_IRQ_CFIREQ, &mappi2_irq_type, | 125 | irq_set_chip_and_handler(PLD_IRQ_CFIREQ, &mappi2_irq_type, |
126 | handle_level_irq); | 126 | handle_level_irq); |
127 | icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; | 127 | icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; |
128 | disable_mappi2_irq(PLD_IRQ_CFIREQ); | 128 | disable_mappi2_irq(PLD_IRQ_CFIREQ); |
129 | 129 | ||
130 | #if defined(CONFIG_M32R_CFC) | 130 | #if defined(CONFIG_M32R_CFC) |
131 | /* ICUCR41: CFC Insert */ | 131 | /* ICUCR41: CFC Insert */ |
132 | set_irq_chip_and_handler(PLD_IRQ_CFC_INSERT, &mappi2_irq_type, | 132 | irq_set_chip_and_handler(PLD_IRQ_CFC_INSERT, &mappi2_irq_type, |
133 | handle_level_irq); | 133 | handle_level_irq); |
134 | icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00; | 134 | icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00; |
135 | disable_mappi2_irq(PLD_IRQ_CFC_INSERT); | 135 | disable_mappi2_irq(PLD_IRQ_CFC_INSERT); |
136 | 136 | ||
137 | /* ICUCR42: CFC Eject */ | 137 | /* ICUCR42: CFC Eject */ |
138 | set_irq_chip_and_handler(PLD_IRQ_CFC_EJECT, &mappi2_irq_type, | 138 | irq_set_chip_and_handler(PLD_IRQ_CFC_EJECT, &mappi2_irq_type, |
139 | handle_level_irq); | 139 | handle_level_irq); |
140 | icu_data[PLD_IRQ_CFC_EJECT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; | 140 | icu_data[PLD_IRQ_CFC_EJECT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; |
141 | disable_mappi2_irq(PLD_IRQ_CFC_EJECT); | 141 | disable_mappi2_irq(PLD_IRQ_CFC_EJECT); |
diff --git a/arch/m32r/platforms/mappi3/setup.c b/arch/m32r/platforms/mappi3/setup.c index b44f5ded2bbe..2408e356ad10 100644 --- a/arch/m32r/platforms/mappi3/setup.c +++ b/arch/m32r/platforms/mappi3/setup.c | |||
@@ -75,38 +75,38 @@ void __init init_IRQ(void) | |||
75 | { | 75 | { |
76 | #if defined(CONFIG_SMC91X) | 76 | #if defined(CONFIG_SMC91X) |
77 | /* INT0 : LAN controller (SMC91111) */ | 77 | /* INT0 : LAN controller (SMC91111) */ |
78 | set_irq_chip_and_handler(M32R_IRQ_INT0, &mappi3_irq_type, | 78 | irq_set_chip_and_handler(M32R_IRQ_INT0, &mappi3_irq_type, |
79 | handle_level_irq); | 79 | handle_level_irq); |
80 | icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; | 80 | icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; |
81 | disable_mappi3_irq(M32R_IRQ_INT0); | 81 | disable_mappi3_irq(M32R_IRQ_INT0); |
82 | #endif /* CONFIG_SMC91X */ | 82 | #endif /* CONFIG_SMC91X */ |
83 | 83 | ||
84 | /* MFT2 : system timer */ | 84 | /* MFT2 : system timer */ |
85 | set_irq_chip_and_handler(M32R_IRQ_MFT2, &mappi3_irq_type, | 85 | irq_set_chip_and_handler(M32R_IRQ_MFT2, &mappi3_irq_type, |
86 | handle_level_irq); | 86 | handle_level_irq); |
87 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; | 87 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; |
88 | disable_mappi3_irq(M32R_IRQ_MFT2); | 88 | disable_mappi3_irq(M32R_IRQ_MFT2); |
89 | 89 | ||
90 | #ifdef CONFIG_SERIAL_M32R_SIO | 90 | #ifdef CONFIG_SERIAL_M32R_SIO |
91 | /* SIO0_R : uart receive data */ | 91 | /* SIO0_R : uart receive data */ |
92 | set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &mappi3_irq_type, | 92 | irq_set_chip_and_handler(M32R_IRQ_SIO0_R, &mappi3_irq_type, |
93 | handle_level_irq); | 93 | handle_level_irq); |
94 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; | 94 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; |
95 | disable_mappi3_irq(M32R_IRQ_SIO0_R); | 95 | disable_mappi3_irq(M32R_IRQ_SIO0_R); |
96 | 96 | ||
97 | /* SIO0_S : uart send data */ | 97 | /* SIO0_S : uart send data */ |
98 | set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &mappi3_irq_type, | 98 | irq_set_chip_and_handler(M32R_IRQ_SIO0_S, &mappi3_irq_type, |
99 | handle_level_irq); | 99 | handle_level_irq); |
100 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; | 100 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; |
101 | disable_mappi3_irq(M32R_IRQ_SIO0_S); | 101 | disable_mappi3_irq(M32R_IRQ_SIO0_S); |
102 | /* SIO1_R : uart receive data */ | 102 | /* SIO1_R : uart receive data */ |
103 | set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &mappi3_irq_type, | 103 | irq_set_chip_and_handler(M32R_IRQ_SIO1_R, &mappi3_irq_type, |
104 | handle_level_irq); | 104 | handle_level_irq); |
105 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; | 105 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; |
106 | disable_mappi3_irq(M32R_IRQ_SIO1_R); | 106 | disable_mappi3_irq(M32R_IRQ_SIO1_R); |
107 | 107 | ||
108 | /* SIO1_S : uart send data */ | 108 | /* SIO1_S : uart send data */ |
109 | set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &mappi3_irq_type, | 109 | irq_set_chip_and_handler(M32R_IRQ_SIO1_S, &mappi3_irq_type, |
110 | handle_level_irq); | 110 | handle_level_irq); |
111 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; | 111 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; |
112 | disable_mappi3_irq(M32R_IRQ_SIO1_S); | 112 | disable_mappi3_irq(M32R_IRQ_SIO1_S); |
@@ -114,21 +114,21 @@ void __init init_IRQ(void) | |||
114 | 114 | ||
115 | #if defined(CONFIG_USB) | 115 | #if defined(CONFIG_USB) |
116 | /* INT1 : USB Host controller interrupt */ | 116 | /* INT1 : USB Host controller interrupt */ |
117 | set_irq_chip_and_handler(M32R_IRQ_INT1, &mappi3_irq_type, | 117 | irq_set_chip_and_handler(M32R_IRQ_INT1, &mappi3_irq_type, |
118 | handle_level_irq); | 118 | handle_level_irq); |
119 | icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01; | 119 | icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01; |
120 | disable_mappi3_irq(M32R_IRQ_INT1); | 120 | disable_mappi3_irq(M32R_IRQ_INT1); |
121 | #endif /* CONFIG_USB */ | 121 | #endif /* CONFIG_USB */ |
122 | 122 | ||
123 | /* CFC IREQ */ | 123 | /* CFC IREQ */ |
124 | set_irq_chip_and_handler(PLD_IRQ_CFIREQ, &mappi3_irq_type, | 124 | irq_set_chip_and_handler(PLD_IRQ_CFIREQ, &mappi3_irq_type, |
125 | handle_level_irq); | 125 | handle_level_irq); |
126 | icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; | 126 | icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; |
127 | disable_mappi3_irq(PLD_IRQ_CFIREQ); | 127 | disable_mappi3_irq(PLD_IRQ_CFIREQ); |
128 | 128 | ||
129 | #if defined(CONFIG_M32R_CFC) | 129 | #if defined(CONFIG_M32R_CFC) |
130 | /* ICUCR41: CFC Insert & eject */ | 130 | /* ICUCR41: CFC Insert & eject */ |
131 | set_irq_chip_and_handler(PLD_IRQ_CFC_INSERT, &mappi3_irq_type, | 131 | irq_set_chip_and_handler(PLD_IRQ_CFC_INSERT, &mappi3_irq_type, |
132 | handle_level_irq); | 132 | handle_level_irq); |
133 | icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00; | 133 | icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00; |
134 | disable_mappi3_irq(PLD_IRQ_CFC_INSERT); | 134 | disable_mappi3_irq(PLD_IRQ_CFC_INSERT); |
@@ -136,7 +136,7 @@ void __init init_IRQ(void) | |||
136 | #endif /* CONFIG_M32R_CFC */ | 136 | #endif /* CONFIG_M32R_CFC */ |
137 | 137 | ||
138 | /* IDE IREQ */ | 138 | /* IDE IREQ */ |
139 | set_irq_chip_and_handler(PLD_IRQ_IDEIREQ, &mappi3_irq_type, | 139 | irq_set_chip_and_handler(PLD_IRQ_IDEIREQ, &mappi3_irq_type, |
140 | handle_level_irq); | 140 | handle_level_irq); |
141 | icu_data[PLD_IRQ_IDEIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; | 141 | icu_data[PLD_IRQ_IDEIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; |
142 | disable_mappi3_irq(PLD_IRQ_IDEIREQ); | 142 | disable_mappi3_irq(PLD_IRQ_IDEIREQ); |
diff --git a/arch/m32r/platforms/oaks32r/setup.c b/arch/m32r/platforms/oaks32r/setup.c index 19a02db7b818..83b46b067a17 100644 --- a/arch/m32r/platforms/oaks32r/setup.c +++ b/arch/m32r/platforms/oaks32r/setup.c | |||
@@ -74,39 +74,39 @@ void __init init_IRQ(void) | |||
74 | 74 | ||
75 | #ifdef CONFIG_NE2000 | 75 | #ifdef CONFIG_NE2000 |
76 | /* INT3 : LAN controller (RTL8019AS) */ | 76 | /* INT3 : LAN controller (RTL8019AS) */ |
77 | set_irq_chip_and_handler(M32R_IRQ_INT3, &oaks32r_irq_type, | 77 | irq_set_chip_and_handler(M32R_IRQ_INT3, &oaks32r_irq_type, |
78 | handle_level_irq); | 78 | handle_level_irq); |
79 | icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; | 79 | icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; |
80 | disable_oaks32r_irq(M32R_IRQ_INT3); | 80 | disable_oaks32r_irq(M32R_IRQ_INT3); |
81 | #endif /* CONFIG_M32R_NE2000 */ | 81 | #endif /* CONFIG_M32R_NE2000 */ |
82 | 82 | ||
83 | /* MFT2 : system timer */ | 83 | /* MFT2 : system timer */ |
84 | set_irq_chip_and_handler(M32R_IRQ_MFT2, &oaks32r_irq_type, | 84 | irq_set_chip_and_handler(M32R_IRQ_MFT2, &oaks32r_irq_type, |
85 | handle_level_irq); | 85 | handle_level_irq); |
86 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; | 86 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; |
87 | disable_oaks32r_irq(M32R_IRQ_MFT2); | 87 | disable_oaks32r_irq(M32R_IRQ_MFT2); |
88 | 88 | ||
89 | #ifdef CONFIG_SERIAL_M32R_SIO | 89 | #ifdef CONFIG_SERIAL_M32R_SIO |
90 | /* SIO0_R : uart receive data */ | 90 | /* SIO0_R : uart receive data */ |
91 | set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &oaks32r_irq_type, | 91 | irq_set_chip_and_handler(M32R_IRQ_SIO0_R, &oaks32r_irq_type, |
92 | handle_level_irq); | 92 | handle_level_irq); |
93 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; | 93 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; |
94 | disable_oaks32r_irq(M32R_IRQ_SIO0_R); | 94 | disable_oaks32r_irq(M32R_IRQ_SIO0_R); |
95 | 95 | ||
96 | /* SIO0_S : uart send data */ | 96 | /* SIO0_S : uart send data */ |
97 | set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &oaks32r_irq_type, | 97 | irq_set_chip_and_handler(M32R_IRQ_SIO0_S, &oaks32r_irq_type, |
98 | handle_level_irq); | 98 | handle_level_irq); |
99 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; | 99 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; |
100 | disable_oaks32r_irq(M32R_IRQ_SIO0_S); | 100 | disable_oaks32r_irq(M32R_IRQ_SIO0_S); |
101 | 101 | ||
102 | /* SIO1_R : uart receive data */ | 102 | /* SIO1_R : uart receive data */ |
103 | set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &oaks32r_irq_type, | 103 | irq_set_chip_and_handler(M32R_IRQ_SIO1_R, &oaks32r_irq_type, |
104 | handle_level_irq); | 104 | handle_level_irq); |
105 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; | 105 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; |
106 | disable_oaks32r_irq(M32R_IRQ_SIO1_R); | 106 | disable_oaks32r_irq(M32R_IRQ_SIO1_R); |
107 | 107 | ||
108 | /* SIO1_S : uart send data */ | 108 | /* SIO1_S : uart send data */ |
109 | set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &oaks32r_irq_type, | 109 | irq_set_chip_and_handler(M32R_IRQ_SIO1_S, &oaks32r_irq_type, |
110 | handle_level_irq); | 110 | handle_level_irq); |
111 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; | 111 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; |
112 | disable_oaks32r_irq(M32R_IRQ_SIO1_S); | 112 | disable_oaks32r_irq(M32R_IRQ_SIO1_S); |
diff --git a/arch/m32r/platforms/opsput/setup.c b/arch/m32r/platforms/opsput/setup.c index 12731547e8bf..32660705f5fd 100644 --- a/arch/m32r/platforms/opsput/setup.c +++ b/arch/m32r/platforms/opsput/setup.c | |||
@@ -259,76 +259,76 @@ void __init init_IRQ(void) | |||
259 | { | 259 | { |
260 | #if defined(CONFIG_SMC91X) | 260 | #if defined(CONFIG_SMC91X) |
261 | /* INT#0: LAN controller on OPSPUT-LAN (SMC91C111)*/ | 261 | /* INT#0: LAN controller on OPSPUT-LAN (SMC91C111)*/ |
262 | set_irq_chip_and_handler(OPSPUT_LAN_IRQ_LAN, &opsput_lanpld_irq_type, | 262 | irq_set_chip_and_handler(OPSPUT_LAN_IRQ_LAN, &opsput_lanpld_irq_type, |
263 | handle_level_irq); | 263 | handle_level_irq); |
264 | lanpld_icu_data[irq2lanpldirq(OPSPUT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* "H" edge sense */ | 264 | lanpld_icu_data[irq2lanpldirq(OPSPUT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* "H" edge sense */ |
265 | disable_opsput_lanpld_irq(OPSPUT_LAN_IRQ_LAN); | 265 | disable_opsput_lanpld_irq(OPSPUT_LAN_IRQ_LAN); |
266 | #endif /* CONFIG_SMC91X */ | 266 | #endif /* CONFIG_SMC91X */ |
267 | 267 | ||
268 | /* MFT2 : system timer */ | 268 | /* MFT2 : system timer */ |
269 | set_irq_chip_and_handler(M32R_IRQ_MFT2, &opsput_irq_type, | 269 | irq_set_chip_and_handler(M32R_IRQ_MFT2, &opsput_irq_type, |
270 | handle_level_irq); | 270 | handle_level_irq); |
271 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; | 271 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; |
272 | disable_opsput_irq(M32R_IRQ_MFT2); | 272 | disable_opsput_irq(M32R_IRQ_MFT2); |
273 | 273 | ||
274 | /* SIO0 : receive */ | 274 | /* SIO0 : receive */ |
275 | set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &opsput_irq_type, | 275 | irq_set_chip_and_handler(M32R_IRQ_SIO0_R, &opsput_irq_type, |
276 | handle_level_irq); | 276 | handle_level_irq); |
277 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; | 277 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; |
278 | disable_opsput_irq(M32R_IRQ_SIO0_R); | 278 | disable_opsput_irq(M32R_IRQ_SIO0_R); |
279 | 279 | ||
280 | /* SIO0 : send */ | 280 | /* SIO0 : send */ |
281 | set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &opsput_irq_type, | 281 | irq_set_chip_and_handler(M32R_IRQ_SIO0_S, &opsput_irq_type, |
282 | handle_level_irq); | 282 | handle_level_irq); |
283 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; | 283 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; |
284 | disable_opsput_irq(M32R_IRQ_SIO0_S); | 284 | disable_opsput_irq(M32R_IRQ_SIO0_S); |
285 | 285 | ||
286 | /* SIO1 : receive */ | 286 | /* SIO1 : receive */ |
287 | set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &opsput_irq_type, | 287 | irq_set_chip_and_handler(M32R_IRQ_SIO1_R, &opsput_irq_type, |
288 | handle_level_irq); | 288 | handle_level_irq); |
289 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; | 289 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; |
290 | disable_opsput_irq(M32R_IRQ_SIO1_R); | 290 | disable_opsput_irq(M32R_IRQ_SIO1_R); |
291 | 291 | ||
292 | /* SIO1 : send */ | 292 | /* SIO1 : send */ |
293 | set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &opsput_irq_type, | 293 | irq_set_chip_and_handler(M32R_IRQ_SIO1_S, &opsput_irq_type, |
294 | handle_level_irq); | 294 | handle_level_irq); |
295 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; | 295 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; |
296 | disable_opsput_irq(M32R_IRQ_SIO1_S); | 296 | disable_opsput_irq(M32R_IRQ_SIO1_S); |
297 | 297 | ||
298 | /* DMA1 : */ | 298 | /* DMA1 : */ |
299 | set_irq_chip_and_handler(M32R_IRQ_DMA1, &opsput_irq_type, | 299 | irq_set_chip_and_handler(M32R_IRQ_DMA1, &opsput_irq_type, |
300 | handle_level_irq); | 300 | handle_level_irq); |
301 | icu_data[M32R_IRQ_DMA1].icucr = 0; | 301 | icu_data[M32R_IRQ_DMA1].icucr = 0; |
302 | disable_opsput_irq(M32R_IRQ_DMA1); | 302 | disable_opsput_irq(M32R_IRQ_DMA1); |
303 | 303 | ||
304 | #ifdef CONFIG_SERIAL_M32R_PLDSIO | 304 | #ifdef CONFIG_SERIAL_M32R_PLDSIO |
305 | /* INT#1: SIO0 Receive on PLD */ | 305 | /* INT#1: SIO0 Receive on PLD */ |
306 | set_irq_chip_and_handler(PLD_IRQ_SIO0_RCV, &opsput_pld_irq_type, | 306 | irq_set_chip_and_handler(PLD_IRQ_SIO0_RCV, &opsput_pld_irq_type, |
307 | handle_level_irq); | 307 | handle_level_irq); |
308 | pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; | 308 | pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; |
309 | disable_opsput_pld_irq(PLD_IRQ_SIO0_RCV); | 309 | disable_opsput_pld_irq(PLD_IRQ_SIO0_RCV); |
310 | 310 | ||
311 | /* INT#1: SIO0 Send on PLD */ | 311 | /* INT#1: SIO0 Send on PLD */ |
312 | set_irq_chip_and_handler(PLD_IRQ_SIO0_SND, &opsput_pld_irq_type, | 312 | irq_set_chip_and_handler(PLD_IRQ_SIO0_SND, &opsput_pld_irq_type, |
313 | handle_level_irq); | 313 | handle_level_irq); |
314 | pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; | 314 | pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03; |
315 | disable_opsput_pld_irq(PLD_IRQ_SIO0_SND); | 315 | disable_opsput_pld_irq(PLD_IRQ_SIO0_SND); |
316 | #endif /* CONFIG_SERIAL_M32R_PLDSIO */ | 316 | #endif /* CONFIG_SERIAL_M32R_PLDSIO */ |
317 | 317 | ||
318 | /* INT#1: CFC IREQ on PLD */ | 318 | /* INT#1: CFC IREQ on PLD */ |
319 | set_irq_chip_and_handler(PLD_IRQ_CFIREQ, &opsput_pld_irq_type, | 319 | irq_set_chip_and_handler(PLD_IRQ_CFIREQ, &opsput_pld_irq_type, |
320 | handle_level_irq); | 320 | handle_level_irq); |
321 | pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* 'L' level sense */ | 321 | pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* 'L' level sense */ |
322 | disable_opsput_pld_irq(PLD_IRQ_CFIREQ); | 322 | disable_opsput_pld_irq(PLD_IRQ_CFIREQ); |
323 | 323 | ||
324 | /* INT#1: CFC Insert on PLD */ | 324 | /* INT#1: CFC Insert on PLD */ |
325 | set_irq_chip_and_handler(PLD_IRQ_CFC_INSERT, &opsput_pld_irq_type, | 325 | irq_set_chip_and_handler(PLD_IRQ_CFC_INSERT, &opsput_pld_irq_type, |
326 | handle_level_irq); | 326 | handle_level_irq); |
327 | pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00; /* 'L' edge sense */ | 327 | pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00; /* 'L' edge sense */ |
328 | disable_opsput_pld_irq(PLD_IRQ_CFC_INSERT); | 328 | disable_opsput_pld_irq(PLD_IRQ_CFC_INSERT); |
329 | 329 | ||
330 | /* INT#1: CFC Eject on PLD */ | 330 | /* INT#1: CFC Eject on PLD */ |
331 | set_irq_chip_and_handler(PLD_IRQ_CFC_EJECT, &opsput_pld_irq_type, | 331 | irq_set_chip_and_handler(PLD_IRQ_CFC_EJECT, &opsput_pld_irq_type, |
332 | handle_level_irq); | 332 | handle_level_irq); |
333 | pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* 'H' edge sense */ | 333 | pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* 'H' edge sense */ |
334 | disable_opsput_pld_irq(PLD_IRQ_CFC_EJECT); | 334 | disable_opsput_pld_irq(PLD_IRQ_CFC_EJECT); |
@@ -349,7 +349,7 @@ void __init init_IRQ(void) | |||
349 | 349 | ||
350 | #if defined(CONFIG_USB) | 350 | #if defined(CONFIG_USB) |
351 | outw(USBCR_OTGS, USBCR); /* USBCR: non-OTG */ | 351 | outw(USBCR_OTGS, USBCR); /* USBCR: non-OTG */ |
352 | set_irq_chip_and_handler(OPSPUT_LCD_IRQ_USB_INT1, | 352 | irq_set_chip_and_handler(OPSPUT_LCD_IRQ_USB_INT1, |
353 | &opsput_lcdpld_irq_type, handle_level_irq); | 353 | &opsput_lcdpld_irq_type, handle_level_irq); |
354 | lcdpld_icu_data[irq2lcdpldirq(OPSPUT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* "L" level sense */ | 354 | lcdpld_icu_data[irq2lcdpldirq(OPSPUT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* "L" level sense */ |
355 | disable_opsput_lcdpld_irq(OPSPUT_LCD_IRQ_USB_INT1); | 355 | disable_opsput_lcdpld_irq(OPSPUT_LCD_IRQ_USB_INT1); |
@@ -365,7 +365,7 @@ void __init init_IRQ(void) | |||
365 | /* | 365 | /* |
366 | * INT3# is used for AR | 366 | * INT3# is used for AR |
367 | */ | 367 | */ |
368 | set_irq_chip_and_handler(M32R_IRQ_INT3, &opsput_irq_type, | 368 | irq_set_chip_and_handler(M32R_IRQ_INT3, &opsput_irq_type, |
369 | handle_level_irq); | 369 | handle_level_irq); |
370 | icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; | 370 | icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; |
371 | disable_opsput_irq(M32R_IRQ_INT3); | 371 | disable_opsput_irq(M32R_IRQ_INT3); |
diff --git a/arch/m32r/platforms/usrv/setup.c b/arch/m32r/platforms/usrv/setup.c index f3cff26d6e74..0c7a1e8c77b0 100644 --- a/arch/m32r/platforms/usrv/setup.c +++ b/arch/m32r/platforms/usrv/setup.c | |||
@@ -138,32 +138,32 @@ void __init init_IRQ(void) | |||
138 | once++; | 138 | once++; |
139 | 139 | ||
140 | /* MFT2 : system timer */ | 140 | /* MFT2 : system timer */ |
141 | set_irq_chip_and_handler(M32R_IRQ_MFT2, &mappi_irq_type, | 141 | irq_set_chip_and_handler(M32R_IRQ_MFT2, &mappi_irq_type, |
142 | handle_level_irq); | 142 | handle_level_irq); |
143 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; | 143 | icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN; |
144 | disable_mappi_irq(M32R_IRQ_MFT2); | 144 | disable_mappi_irq(M32R_IRQ_MFT2); |
145 | 145 | ||
146 | #if defined(CONFIG_SERIAL_M32R_SIO) | 146 | #if defined(CONFIG_SERIAL_M32R_SIO) |
147 | /* SIO0_R : uart receive data */ | 147 | /* SIO0_R : uart receive data */ |
148 | set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &mappi_irq_type, | 148 | irq_set_chip_and_handler(M32R_IRQ_SIO0_R, &mappi_irq_type, |
149 | handle_level_irq); | 149 | handle_level_irq); |
150 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; | 150 | icu_data[M32R_IRQ_SIO0_R].icucr = 0; |
151 | disable_mappi_irq(M32R_IRQ_SIO0_R); | 151 | disable_mappi_irq(M32R_IRQ_SIO0_R); |
152 | 152 | ||
153 | /* SIO0_S : uart send data */ | 153 | /* SIO0_S : uart send data */ |
154 | set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &mappi_irq_type, | 154 | irq_set_chip_and_handler(M32R_IRQ_SIO0_S, &mappi_irq_type, |
155 | handle_level_irq); | 155 | handle_level_irq); |
156 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; | 156 | icu_data[M32R_IRQ_SIO0_S].icucr = 0; |
157 | disable_mappi_irq(M32R_IRQ_SIO0_S); | 157 | disable_mappi_irq(M32R_IRQ_SIO0_S); |
158 | 158 | ||
159 | /* SIO1_R : uart receive data */ | 159 | /* SIO1_R : uart receive data */ |
160 | set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &mappi_irq_type, | 160 | irq_set_chip_and_handler(M32R_IRQ_SIO1_R, &mappi_irq_type, |
161 | handle_level_irq); | 161 | handle_level_irq); |
162 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; | 162 | icu_data[M32R_IRQ_SIO1_R].icucr = 0; |
163 | disable_mappi_irq(M32R_IRQ_SIO1_R); | 163 | disable_mappi_irq(M32R_IRQ_SIO1_R); |
164 | 164 | ||
165 | /* SIO1_S : uart send data */ | 165 | /* SIO1_S : uart send data */ |
166 | set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &mappi_irq_type, | 166 | irq_set_chip_and_handler(M32R_IRQ_SIO1_S, &mappi_irq_type, |
167 | handle_level_irq); | 167 | handle_level_irq); |
168 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; | 168 | icu_data[M32R_IRQ_SIO1_S].icucr = 0; |
169 | disable_mappi_irq(M32R_IRQ_SIO1_S); | 169 | disable_mappi_irq(M32R_IRQ_SIO1_S); |
@@ -171,7 +171,7 @@ void __init init_IRQ(void) | |||
171 | 171 | ||
172 | /* INT#67-#71: CFC#0 IREQ on PLD */ | 172 | /* INT#67-#71: CFC#0 IREQ on PLD */ |
173 | for (i = 0 ; i < CONFIG_M32R_CFC_NUM ; i++ ) { | 173 | for (i = 0 ; i < CONFIG_M32R_CFC_NUM ; i++ ) { |
174 | set_irq_chip_and_handler(PLD_IRQ_CF0 + i, | 174 | irq_set_chip_and_handler(PLD_IRQ_CF0 + i, |
175 | &m32700ut_pld_irq_type, | 175 | &m32700ut_pld_irq_type, |
176 | handle_level_irq); | 176 | handle_level_irq); |
177 | pld_icu_data[irq2pldirq(PLD_IRQ_CF0 + i)].icucr | 177 | pld_icu_data[irq2pldirq(PLD_IRQ_CF0 + i)].icucr |
@@ -181,14 +181,14 @@ void __init init_IRQ(void) | |||
181 | 181 | ||
182 | #if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE) | 182 | #if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE) |
183 | /* INT#76: 16552D#0 IREQ on PLD */ | 183 | /* INT#76: 16552D#0 IREQ on PLD */ |
184 | set_irq_chip_and_handler(PLD_IRQ_UART0, &m32700ut_pld_irq_type, | 184 | irq_set_chip_and_handler(PLD_IRQ_UART0, &m32700ut_pld_irq_type, |
185 | handle_level_irq); | 185 | handle_level_irq); |
186 | pld_icu_data[irq2pldirq(PLD_IRQ_UART0)].icucr | 186 | pld_icu_data[irq2pldirq(PLD_IRQ_UART0)].icucr |
187 | = PLD_ICUCR_ISMOD03; /* 'H' level sense */ | 187 | = PLD_ICUCR_ISMOD03; /* 'H' level sense */ |
188 | disable_m32700ut_pld_irq(PLD_IRQ_UART0); | 188 | disable_m32700ut_pld_irq(PLD_IRQ_UART0); |
189 | 189 | ||
190 | /* INT#77: 16552D#1 IREQ on PLD */ | 190 | /* INT#77: 16552D#1 IREQ on PLD */ |
191 | set_irq_chip_and_handler(PLD_IRQ_UART1, &m32700ut_pld_irq_type, | 191 | irq_set_chip_and_handler(PLD_IRQ_UART1, &m32700ut_pld_irq_type, |
192 | handle_level_irq); | 192 | handle_level_irq); |
193 | pld_icu_data[irq2pldirq(PLD_IRQ_UART1)].icucr | 193 | pld_icu_data[irq2pldirq(PLD_IRQ_UART1)].icucr |
194 | = PLD_ICUCR_ISMOD03; /* 'H' level sense */ | 194 | = PLD_ICUCR_ISMOD03; /* 'H' level sense */ |
@@ -197,7 +197,7 @@ void __init init_IRQ(void) | |||
197 | 197 | ||
198 | #if defined(CONFIG_IDC_AK4524) || defined(CONFIG_IDC_AK4524_MODULE) | 198 | #if defined(CONFIG_IDC_AK4524) || defined(CONFIG_IDC_AK4524_MODULE) |
199 | /* INT#80: AK4524 IREQ on PLD */ | 199 | /* INT#80: AK4524 IREQ on PLD */ |
200 | set_irq_chip_and_handler(PLD_IRQ_SNDINT, &m32700ut_pld_irq_type, | 200 | irq_set_chip_and_handler(PLD_IRQ_SNDINT, &m32700ut_pld_irq_type, |
201 | handle_level_irq); | 201 | handle_level_irq); |
202 | pld_icu_data[irq2pldirq(PLD_IRQ_SNDINT)].icucr | 202 | pld_icu_data[irq2pldirq(PLD_IRQ_SNDINT)].icucr |
203 | = PLD_ICUCR_ISMOD01; /* 'L' level sense */ | 203 | = PLD_ICUCR_ISMOD01; /* 'L' level sense */ |
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index 525174d41679..6e056d3c5d01 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig | |||
@@ -1,13 +1,11 @@ | |||
1 | config M68K | 1 | config M68K |
2 | bool | 2 | bool |
3 | default y | 3 | default y |
4 | select HAVE_AOUT | ||
5 | select HAVE_IDE | 4 | select HAVE_IDE |
6 | select GENERIC_ATOMIC64 | 5 | select HAVE_AOUT if MMU |
7 | 6 | select GENERIC_ATOMIC64 if MMU | |
8 | config MMU | 7 | select HAVE_GENERIC_HARDIRQS if !MMU |
9 | bool | 8 | select GENERIC_HARDIRQS_NO_DEPRECATED if !MMU |
10 | default y | ||
11 | 9 | ||
12 | config RWSEM_GENERIC_SPINLOCK | 10 | config RWSEM_GENERIC_SPINLOCK |
13 | bool | 11 | bool |
@@ -34,457 +32,67 @@ config TIME_LOW_RES | |||
34 | bool | 32 | bool |
35 | default y | 33 | default y |
36 | 34 | ||
37 | config GENERIC_IOMAP | ||
38 | bool | ||
39 | default y | ||
40 | |||
41 | config ARCH_MAY_HAVE_PC_FDC | ||
42 | bool | ||
43 | depends on BROKEN && (Q40 || SUN3X) | ||
44 | default y | ||
45 | |||
46 | config NO_IOPORT | 35 | config NO_IOPORT |
47 | def_bool y | 36 | def_bool y |
48 | 37 | ||
49 | config NO_DMA | 38 | config NO_DMA |
50 | def_bool SUN3 | 39 | def_bool (MMU && SUN3) || (!MMU && !COLDFIRE) |
51 | 40 | ||
41 | config ZONE_DMA | ||
42 | bool | ||
43 | default y | ||
52 | config HZ | 44 | config HZ |
53 | int | 45 | int |
46 | default 1000 if CLEOPATRA | ||
54 | default 100 | 47 | default 100 |
55 | 48 | ||
56 | config ARCH_USES_GETTIMEOFFSET | ||
57 | def_bool y | ||
58 | |||
59 | source "init/Kconfig" | 49 | source "init/Kconfig" |
60 | 50 | ||
61 | source "kernel/Kconfig.freezer" | 51 | source "kernel/Kconfig.freezer" |
62 | 52 | ||
63 | menu "Platform dependent setup" | 53 | config MMU |
64 | 54 | bool "MMU-based Paged Memory Management Support" | |
65 | config EISA | ||
66 | bool | ||
67 | ---help--- | ||
68 | The Extended Industry Standard Architecture (EISA) bus was | ||
69 | developed as an open alternative to the IBM MicroChannel bus. | ||
70 | |||
71 | The EISA bus provided some of the features of the IBM MicroChannel | ||
72 | bus while maintaining backward compatibility with cards made for | ||
73 | the older ISA bus. The EISA bus saw limited use between 1988 and | ||
74 | 1995 when it was made obsolete by the PCI bus. | ||
75 | |||
76 | Say Y here if you are building a kernel for an EISA-based machine. | ||
77 | |||
78 | Otherwise, say N. | ||
79 | |||
80 | config MCA | ||
81 | bool | ||
82 | help | ||
83 | MicroChannel Architecture is found in some IBM PS/2 machines and | ||
84 | laptops. It is a bus system similar to PCI or ISA. See | ||
85 | <file:Documentation/mca.txt> (and especially the web page given | ||
86 | there) before attempting to build an MCA bus kernel. | ||
87 | |||
88 | config PCMCIA | ||
89 | tristate | ||
90 | ---help--- | ||
91 | Say Y here if you want to attach PCMCIA- or PC-cards to your Linux | ||
92 | computer. These are credit-card size devices such as network cards, | ||
93 | modems or hard drives often used with laptops computers. There are | ||
94 | actually two varieties of these cards: the older 16 bit PCMCIA cards | ||
95 | and the newer 32 bit CardBus cards. If you want to use CardBus | ||
96 | cards, you need to say Y here and also to "CardBus support" below. | ||
97 | |||
98 | To use your PC-cards, you will need supporting software from David | ||
99 | Hinds' pcmcia-cs package (see the file <file:Documentation/Changes> | ||
100 | for location). Please also read the PCMCIA-HOWTO, available from | ||
101 | <http://www.tldp.org/docs.html#howto>. | ||
102 | |||
103 | To compile this driver as modules, choose M here: the | ||
104 | modules will be called pcmcia_core and ds. | ||
105 | |||
106 | config AMIGA | ||
107 | bool "Amiga support" | ||
108 | select MMU_MOTOROLA if MMU | ||
109 | help | ||
110 | This option enables support for the Amiga series of computers. If | ||
111 | you plan to use this kernel on an Amiga, say Y here and browse the | ||
112 | material available in <file:Documentation/m68k>; otherwise say N. | ||
113 | |||
114 | config ATARI | ||
115 | bool "Atari support" | ||
116 | select MMU_MOTOROLA if MMU | ||
117 | help | ||
118 | This option enables support for the 68000-based Atari series of | ||
119 | computers (including the TT, Falcon and Medusa). If you plan to use | ||
120 | this kernel on an Atari, say Y here and browse the material | ||
121 | available in <file:Documentation/m68k>; otherwise say N. | ||
122 | |||
123 | config MAC | ||
124 | bool "Macintosh support" | ||
125 | select MMU_MOTOROLA if MMU | ||
126 | help | ||
127 | This option enables support for the Apple Macintosh series of | ||
128 | computers (yes, there is experimental support now, at least for part | ||
129 | of the series). | ||
130 | |||
131 | Say N unless you're willing to code the remaining necessary support. | ||
132 | ;) | ||
133 | |||
134 | config NUBUS | ||
135 | bool | ||
136 | depends on MAC | ||
137 | default y | ||
138 | |||
139 | config M68K_L2_CACHE | ||
140 | bool | ||
141 | depends on MAC | ||
142 | default y | ||
143 | |||
144 | config APOLLO | ||
145 | bool "Apollo support" | ||
146 | select MMU_MOTOROLA if MMU | ||
147 | help | ||
148 | Say Y here if you want to run Linux on an MC680x0-based Apollo | ||
149 | Domain workstation such as the DN3500. | ||
150 | |||
151 | config VME | ||
152 | bool "VME (Motorola and BVM) support" | ||
153 | select MMU_MOTOROLA if MMU | ||
154 | help | ||
155 | Say Y here if you want to build a kernel for a 680x0 based VME | ||
156 | board. Boards currently supported include Motorola boards MVME147, | ||
157 | MVME162, MVME166, MVME167, MVME172, and MVME177. BVME4000 and | ||
158 | BVME6000 boards from BVM Ltd are also supported. | ||
159 | |||
160 | config MVME147 | ||
161 | bool "MVME147 support" | ||
162 | depends on VME | ||
163 | help | ||
164 | Say Y to include support for early Motorola VME boards. This will | ||
165 | build a kernel which can run on MVME147 single-board computers. If | ||
166 | you select this option you will have to select the appropriate | ||
167 | drivers for SCSI, Ethernet and serial ports later on. | ||
168 | |||
169 | config MVME16x | ||
170 | bool "MVME162, 166 and 167 support" | ||
171 | depends on VME | ||
172 | help | ||
173 | Say Y to include support for Motorola VME boards. This will build a | ||
174 | kernel which can run on MVME162, MVME166, MVME167, MVME172, and | ||
175 | MVME177 boards. If you select this option you will have to select | ||
176 | the appropriate drivers for SCSI, Ethernet and serial ports later | ||
177 | on. | ||
178 | |||
179 | config BVME6000 | ||
180 | bool "BVME4000 and BVME6000 support" | ||
181 | depends on VME | ||
182 | help | ||
183 | Say Y to include support for VME boards from BVM Ltd. This will | ||
184 | build a kernel which can run on BVME4000 and BVME6000 boards. If | ||
185 | you select this option you will have to select the appropriate | ||
186 | drivers for SCSI, Ethernet and serial ports later on. | ||
187 | |||
188 | config HP300 | ||
189 | bool "HP9000/300 and HP9000/400 support" | ||
190 | select MMU_MOTOROLA if MMU | ||
191 | help | ||
192 | This option enables support for the HP9000/300 and HP9000/400 series | ||
193 | of workstations. Support for these machines is still somewhat | ||
194 | experimental. If you plan to try to use the kernel on such a machine | ||
195 | say Y here. | ||
196 | Everybody else says N. | ||
197 | |||
198 | config DIO | ||
199 | bool "DIO bus support" | ||
200 | depends on HP300 | ||
201 | default y | 55 | default y |
202 | help | 56 | help |
203 | Say Y here to enable support for the "DIO" expansion bus used in | 57 | Select if you want MMU-based virtualised addressing space |
204 | HP300 machines. If you are using such a system you almost certainly | 58 | support by paged memory management. If unsure, say 'Y'. |
205 | want this. | ||
206 | |||
207 | config SUN3X | ||
208 | bool "Sun3x support" | ||
209 | select MMU_MOTOROLA if MMU | ||
210 | select M68030 | ||
211 | help | ||
212 | This option enables support for the Sun 3x series of workstations. | ||
213 | Be warned that this support is very experimental. | ||
214 | Note that Sun 3x kernels are not compatible with Sun 3 hardware. | ||
215 | General Linux information on the Sun 3x series (now discontinued) | ||
216 | is at <http://www.angelfire.com/ca2/tech68k/sun3.html>. | ||
217 | |||
218 | If you don't want to compile a kernel for a Sun 3x, say N. | ||
219 | |||
220 | config Q40 | ||
221 | bool "Q40/Q60 support" | ||
222 | select MMU_MOTOROLA if MMU | ||
223 | help | ||
224 | The Q40 is a Motorola 68040-based successor to the Sinclair QL | ||
225 | manufactured in Germany. There is an official Q40 home page at | ||
226 | <http://www.q40.de/>. This option enables support for the Q40 and | ||
227 | Q60. Select your CPU below. For 68LC060 don't forget to enable FPU | ||
228 | emulation. | ||
229 | |||
230 | config SUN3 | ||
231 | bool "Sun3 support" | ||
232 | depends on !MMU_MOTOROLA | ||
233 | select MMU_SUN3 if MMU | ||
234 | select M68020 | ||
235 | help | ||
236 | This option enables support for the Sun 3 series of workstations | ||
237 | (3/50, 3/60, 3/1xx, 3/2xx systems). Enabling this option requires | ||
238 | that all other hardware types must be disabled, as Sun 3 kernels | ||
239 | are incompatible with all other m68k targets (including Sun 3x!). | ||
240 | |||
241 | If you don't want to compile a kernel exclusively for a Sun 3, say N. | ||
242 | |||
243 | config NATFEAT | ||
244 | bool "ARAnyM emulator support" | ||
245 | depends on ATARI | ||
246 | help | ||
247 | This option enables support for ARAnyM native features, such as | ||
248 | access to a disk image as /dev/hda. | ||
249 | |||
250 | config NFBLOCK | ||
251 | tristate "NatFeat block device support" | ||
252 | depends on BLOCK && NATFEAT | ||
253 | help | ||
254 | Say Y to include support for the ARAnyM NatFeat block device | ||
255 | which allows direct access to the hard drives without using | ||
256 | the hardware emulation. | ||
257 | |||
258 | config NFCON | ||
259 | tristate "NatFeat console driver" | ||
260 | depends on NATFEAT | ||
261 | help | ||
262 | Say Y to include support for the ARAnyM NatFeat console driver | ||
263 | which allows the console output to be redirected to the stderr | ||
264 | output of ARAnyM. | ||
265 | |||
266 | config NFETH | ||
267 | tristate "NatFeat Ethernet support" | ||
268 | depends on NET_ETHERNET && NATFEAT | ||
269 | help | ||
270 | Say Y to include support for the ARAnyM NatFeat network device | ||
271 | which will emulate a regular ethernet device while presenting an | ||
272 | ethertap device to the host system. | ||
273 | |||
274 | comment "Processor type" | ||
275 | |||
276 | config M68020 | ||
277 | bool "68020 support" | ||
278 | help | ||
279 | If you anticipate running this kernel on a computer with a MC68020 | ||
280 | processor, say Y. Otherwise, say N. Note that the 68020 requires a | ||
281 | 68851 MMU (Memory Management Unit) to run Linux/m68k, except on the | ||
282 | Sun 3, which provides its own version. | ||
283 | |||
284 | config M68030 | ||
285 | bool "68030 support" | ||
286 | depends on !MMU_SUN3 | ||
287 | help | ||
288 | If you anticipate running this kernel on a computer with a MC68030 | ||
289 | processor, say Y. Otherwise, say N. Note that a MC68EC030 will not | ||
290 | work, as it does not include an MMU (Memory Management Unit). | ||
291 | |||
292 | config M68040 | ||
293 | bool "68040 support" | ||
294 | depends on !MMU_SUN3 | ||
295 | help | ||
296 | If you anticipate running this kernel on a computer with a MC68LC040 | ||
297 | or MC68040 processor, say Y. Otherwise, say N. Note that an | ||
298 | MC68EC040 will not work, as it does not include an MMU (Memory | ||
299 | Management Unit). | ||
300 | |||
301 | config M68060 | ||
302 | bool "68060 support" | ||
303 | depends on !MMU_SUN3 | ||
304 | help | ||
305 | If you anticipate running this kernel on a computer with a MC68060 | ||
306 | processor, say Y. Otherwise, say N. | ||
307 | |||
308 | config MMU_MOTOROLA | ||
309 | bool | ||
310 | |||
311 | config MMU_SUN3 | ||
312 | bool | ||
313 | depends on MMU && !MMU_MOTOROLA | ||
314 | |||
315 | config M68KFPU_EMU | ||
316 | bool "Math emulation support (EXPERIMENTAL)" | ||
317 | depends on EXPERIMENTAL | ||
318 | help | ||
319 | At some point in the future, this will cause floating-point math | ||
320 | instructions to be emulated by the kernel on machines that lack a | ||
321 | floating-point math coprocessor. Thrill-seekers and chronically | ||
322 | sleep-deprived psychotic hacker types can say Y now, everyone else | ||
323 | should probably wait a while. | ||
324 | |||
325 | config M68KFPU_EMU_EXTRAPREC | ||
326 | bool "Math emulation extra precision" | ||
327 | depends on M68KFPU_EMU | ||
328 | help | ||
329 | The fpu uses normally a few bit more during calculations for | ||
330 | correct rounding, the emulator can (often) do the same but this | ||
331 | extra calculation can cost quite some time, so you can disable | ||
332 | it here. The emulator will then "only" calculate with a 64 bit | ||
333 | mantissa and round slightly incorrect, what is more than enough | ||
334 | for normal usage. | ||
335 | |||
336 | config M68KFPU_EMU_ONLY | ||
337 | bool "Math emulation only kernel" | ||
338 | depends on M68KFPU_EMU | ||
339 | help | ||
340 | This option prevents any floating-point instructions from being | ||
341 | compiled into the kernel, thereby the kernel doesn't save any | ||
342 | floating point context anymore during task switches, so this | ||
343 | kernel will only be usable on machines without a floating-point | ||
344 | math coprocessor. This makes the kernel a bit faster as no tests | ||
345 | needs to be executed whether a floating-point instruction in the | ||
346 | kernel should be executed or not. | ||
347 | |||
348 | config ADVANCED | ||
349 | bool "Advanced configuration options" | ||
350 | ---help--- | ||
351 | This gives you access to some advanced options for the CPU. The | ||
352 | defaults should be fine for most users, but these options may make | ||
353 | it possible for you to improve performance somewhat if you know what | ||
354 | you are doing. | ||
355 | |||
356 | Note that the answer to this question won't directly affect the | ||
357 | kernel: saying N will just cause the configurator to skip all | ||
358 | the questions about these options. | ||
359 | 59 | ||
360 | Most users should say N to this question. | 60 | menu "Platform dependent setup" |
361 | |||
362 | config RMW_INSNS | ||
363 | bool "Use read-modify-write instructions" | ||
364 | depends on ADVANCED | ||
365 | ---help--- | ||
366 | This allows to use certain instructions that work with indivisible | ||
367 | read-modify-write bus cycles. While this is faster than the | ||
368 | workaround of disabling interrupts, it can conflict with DMA | ||
369 | ( = direct memory access) on many Amiga systems, and it is also said | ||
370 | to destabilize other machines. It is very likely that this will | ||
371 | cause serious problems on any Amiga or Atari Medusa if set. The only | ||
372 | configuration where it should work are 68030-based Ataris, where it | ||
373 | apparently improves performance. But you've been warned! Unless you | ||
374 | really know what you are doing, say N. Try Y only if you're quite | ||
375 | adventurous. | ||
376 | |||
377 | config SINGLE_MEMORY_CHUNK | ||
378 | bool "Use one physical chunk of memory only" if ADVANCED && !SUN3 | ||
379 | default y if SUN3 | ||
380 | select NEED_MULTIPLE_NODES | ||
381 | help | ||
382 | Ignore all but the first contiguous chunk of physical memory for VM | ||
383 | purposes. This will save a few bytes kernel size and may speed up | ||
384 | some operations. Say N if not sure. | ||
385 | 61 | ||
386 | config 060_WRITETHROUGH | 62 | if MMU |
387 | bool "Use write-through caching for 68060 supervisor accesses" | 63 | source arch/m68k/Kconfig.mmu |
388 | depends on ADVANCED && M68060 | 64 | endif |
389 | ---help--- | 65 | if !MMU |
390 | The 68060 generally uses copyback caching of recently accessed data. | 66 | source arch/m68k/Kconfig.nommu |
391 | Copyback caching means that memory writes will be held in an on-chip | 67 | endif |
392 | cache and only written back to memory some time later. Saying Y | ||
393 | here will force supervisor (kernel) accesses to use writethrough | ||
394 | caching. Writethrough caching means that data is written to memory | ||
395 | straight away, so that cache and memory data always agree. | ||
396 | Writethrough caching is less efficient, but is needed for some | ||
397 | drivers on 68060 based systems where the 68060 bus snooping signal | ||
398 | is hardwired on. The 53c710 SCSI driver is known to suffer from | ||
399 | this problem. | ||
400 | |||
401 | config ARCH_DISCONTIGMEM_ENABLE | ||
402 | def_bool !SINGLE_MEMORY_CHUNK | ||
403 | |||
404 | config NODES_SHIFT | ||
405 | int | ||
406 | default "3" | ||
407 | depends on !SINGLE_MEMORY_CHUNK | ||
408 | 68 | ||
409 | source "mm/Kconfig" | 69 | source "mm/Kconfig" |
410 | 70 | ||
411 | endmenu | 71 | endmenu |
412 | 72 | ||
413 | menu "General setup" | 73 | menu "Executable file formats" |
414 | 74 | ||
415 | source "fs/Kconfig.binfmt" | 75 | source "fs/Kconfig.binfmt" |
416 | 76 | ||
417 | config ZORRO | 77 | endmenu |
418 | bool "Amiga Zorro (AutoConfig) bus support" | ||
419 | depends on AMIGA | ||
420 | help | ||
421 | This enables support for the Zorro bus in the Amiga. If you have | ||
422 | expansion cards in your Amiga that conform to the Amiga | ||
423 | AutoConfig(tm) specification, say Y, otherwise N. Note that even | ||
424 | expansion cards that do not fit in the Zorro slots but fit in e.g. | ||
425 | the CPU slot may fall in this category, so you have to say Y to let | ||
426 | Linux use these. | ||
427 | |||
428 | config AMIGA_PCMCIA | ||
429 | bool "Amiga 1200/600 PCMCIA support (EXPERIMENTAL)" | ||
430 | depends on AMIGA && EXPERIMENTAL | ||
431 | help | ||
432 | Include support in the kernel for pcmcia on Amiga 1200 and Amiga | ||
433 | 600. If you intend to use pcmcia cards say Y; otherwise say N. | ||
434 | |||
435 | config STRAM_PROC | ||
436 | bool "ST-RAM statistics in /proc" | ||
437 | depends on ATARI | ||
438 | help | ||
439 | Say Y here to report ST-RAM usage statistics in /proc/stram. | ||
440 | |||
441 | config HEARTBEAT | ||
442 | bool "Use power LED as a heartbeat" if AMIGA || APOLLO || ATARI || MAC ||Q40 | ||
443 | default y if !AMIGA && !APOLLO && !ATARI && !MAC && !Q40 && HP300 | ||
444 | help | ||
445 | Use the power-on LED on your machine as a load meter. The exact | ||
446 | behavior is platform-dependent, but normally the flash frequency is | ||
447 | a hyperbolic function of the 5-minute load average. | ||
448 | |||
449 | # We have a dedicated heartbeat LED. :-) | ||
450 | config PROC_HARDWARE | ||
451 | bool "/proc/hardware support" | ||
452 | help | ||
453 | Say Y here to support the /proc/hardware file, which gives you | ||
454 | access to information about the machine you're running on, | ||
455 | including the model, CPU, MMU, clock speed, BogoMIPS rating, | ||
456 | and memory size. | ||
457 | |||
458 | config ISA | ||
459 | bool | ||
460 | depends on Q40 || AMIGA_PCMCIA | ||
461 | default y | ||
462 | help | ||
463 | Find out whether you have ISA slots on your motherboard. ISA is the | ||
464 | name of a bus system, i.e. the way the CPU talks to the other stuff | ||
465 | inside your box. Other bus systems are PCI, EISA, MicroChannel | ||
466 | (MCA) or VESA. ISA is an older system, now being displaced by PCI; | ||
467 | newer boards don't support it. If you have ISA, say Y, otherwise N. | ||
468 | |||
469 | config GENERIC_ISA_DMA | ||
470 | bool | ||
471 | depends on Q40 || AMIGA_PCMCIA | ||
472 | default y | ||
473 | |||
474 | config ZONE_DMA | ||
475 | bool | ||
476 | default y | ||
477 | 78 | ||
478 | source "drivers/pci/Kconfig" | 79 | if !MMU |
80 | menu "Power management options" | ||
479 | 81 | ||
480 | source "drivers/zorro/Kconfig" | 82 | config PM |
83 | bool "Power Management support" | ||
84 | help | ||
85 | Support processor power management modes | ||
481 | 86 | ||
482 | endmenu | 87 | endmenu |
88 | endif | ||
483 | 89 | ||
484 | source "net/Kconfig" | 90 | source "net/Kconfig" |
485 | 91 | ||
486 | source "drivers/Kconfig" | 92 | source "drivers/Kconfig" |
487 | 93 | ||
94 | if MMU | ||
95 | |||
488 | menu "Character devices" | 96 | menu "Character devices" |
489 | 97 | ||
490 | config ATARI_MFPSER | 98 | config ATARI_MFPSER |
@@ -627,6 +235,8 @@ config SERIAL_CONSOLE | |||
627 | 235 | ||
628 | endmenu | 236 | endmenu |
629 | 237 | ||
238 | endif | ||
239 | |||
630 | source "fs/Kconfig" | 240 | source "fs/Kconfig" |
631 | 241 | ||
632 | source "arch/m68k/Kconfig.debug" | 242 | source "arch/m68k/Kconfig.debug" |
diff --git a/arch/m68k/Kconfig.debug b/arch/m68k/Kconfig.debug index f53b6d5300e5..2bdb1b01115c 100644 --- a/arch/m68k/Kconfig.debug +++ b/arch/m68k/Kconfig.debug | |||
@@ -2,4 +2,38 @@ menu "Kernel hacking" | |||
2 | 2 | ||
3 | source "lib/Kconfig.debug" | 3 | source "lib/Kconfig.debug" |
4 | 4 | ||
5 | if !MMU | ||
6 | |||
7 | config FULLDEBUG | ||
8 | bool "Full Symbolic/Source Debugging support" | ||
9 | help | ||
10 | Enable debugging symbols on kernel build. | ||
11 | |||
12 | config HIGHPROFILE | ||
13 | bool "Use fast second timer for profiling" | ||
14 | depends on COLDFIRE | ||
15 | help | ||
16 | Use a fast secondary clock to produce profiling information. | ||
17 | |||
18 | config BOOTPARAM | ||
19 | bool 'Compiled-in Kernel Boot Parameter' | ||
20 | |||
21 | config BOOTPARAM_STRING | ||
22 | string 'Kernel Boot Parameter' | ||
23 | default 'console=ttyS0,19200' | ||
24 | depends on BOOTPARAM | ||
25 | |||
26 | config NO_KERNEL_MSG | ||
27 | bool "Suppress Kernel BUG Messages" | ||
28 | help | ||
29 | Do not output any debug BUG messages within the kernel. | ||
30 | |||
31 | config BDM_DISABLE | ||
32 | bool "Disable BDM signals" | ||
33 | depends on (EXPERIMENTAL && COLDFIRE) | ||
34 | help | ||
35 | Disable the ColdFire CPU's BDM signals. | ||
36 | |||
37 | endif | ||
38 | |||
5 | endmenu | 39 | endmenu |
diff --git a/arch/m68k/Kconfig.mmu b/arch/m68k/Kconfig.mmu new file mode 100644 index 000000000000..16539b1d5d3a --- /dev/null +++ b/arch/m68k/Kconfig.mmu | |||
@@ -0,0 +1,417 @@ | |||
1 | config GENERIC_IOMAP | ||
2 | bool | ||
3 | default y | ||
4 | |||
5 | config ARCH_MAY_HAVE_PC_FDC | ||
6 | bool | ||
7 | depends on BROKEN && (Q40 || SUN3X) | ||
8 | default y | ||
9 | |||
10 | config ARCH_USES_GETTIMEOFFSET | ||
11 | def_bool y | ||
12 | |||
13 | config EISA | ||
14 | bool | ||
15 | ---help--- | ||
16 | The Extended Industry Standard Architecture (EISA) bus was | ||
17 | developed as an open alternative to the IBM MicroChannel bus. | ||
18 | |||
19 | The EISA bus provided some of the features of the IBM MicroChannel | ||
20 | bus while maintaining backward compatibility with cards made for | ||
21 | the older ISA bus. The EISA bus saw limited use between 1988 and | ||
22 | 1995 when it was made obsolete by the PCI bus. | ||
23 | |||
24 | Say Y here if you are building a kernel for an EISA-based machine. | ||
25 | |||
26 | Otherwise, say N. | ||
27 | |||
28 | config MCA | ||
29 | bool | ||
30 | help | ||
31 | MicroChannel Architecture is found in some IBM PS/2 machines and | ||
32 | laptops. It is a bus system similar to PCI or ISA. See | ||
33 | <file:Documentation/mca.txt> (and especially the web page given | ||
34 | there) before attempting to build an MCA bus kernel. | ||
35 | |||
36 | config PCMCIA | ||
37 | tristate | ||
38 | ---help--- | ||
39 | Say Y here if you want to attach PCMCIA- or PC-cards to your Linux | ||
40 | computer. These are credit-card size devices such as network cards, | ||
41 | modems or hard drives often used with laptops computers. There are | ||
42 | actually two varieties of these cards: the older 16 bit PCMCIA cards | ||
43 | and the newer 32 bit CardBus cards. If you want to use CardBus | ||
44 | cards, you need to say Y here and also to "CardBus support" below. | ||
45 | |||
46 | To use your PC-cards, you will need supporting software from David | ||
47 | Hinds' pcmcia-cs package (see the file <file:Documentation/Changes> | ||
48 | for location). Please also read the PCMCIA-HOWTO, available from | ||
49 | <http://www.tldp.org/docs.html#howto>. | ||
50 | |||
51 | To compile this driver as modules, choose M here: the | ||
52 | modules will be called pcmcia_core and ds. | ||
53 | |||
54 | config AMIGA | ||
55 | bool "Amiga support" | ||
56 | select MMU_MOTOROLA if MMU | ||
57 | help | ||
58 | This option enables support for the Amiga series of computers. If | ||
59 | you plan to use this kernel on an Amiga, say Y here and browse the | ||
60 | material available in <file:Documentation/m68k>; otherwise say N. | ||
61 | |||
62 | config ATARI | ||
63 | bool "Atari support" | ||
64 | select MMU_MOTOROLA if MMU | ||
65 | help | ||
66 | This option enables support for the 68000-based Atari series of | ||
67 | computers (including the TT, Falcon and Medusa). If you plan to use | ||
68 | this kernel on an Atari, say Y here and browse the material | ||
69 | available in <file:Documentation/m68k>; otherwise say N. | ||
70 | |||
71 | config MAC | ||
72 | bool "Macintosh support" | ||
73 | select MMU_MOTOROLA if MMU | ||
74 | help | ||
75 | This option enables support for the Apple Macintosh series of | ||
76 | computers (yes, there is experimental support now, at least for part | ||
77 | of the series). | ||
78 | |||
79 | Say N unless you're willing to code the remaining necessary support. | ||
80 | ;) | ||
81 | |||
82 | config NUBUS | ||
83 | bool | ||
84 | depends on MAC | ||
85 | default y | ||
86 | |||
87 | config M68K_L2_CACHE | ||
88 | bool | ||
89 | depends on MAC | ||
90 | default y | ||
91 | |||
92 | config APOLLO | ||
93 | bool "Apollo support" | ||
94 | select MMU_MOTOROLA if MMU | ||
95 | help | ||
96 | Say Y here if you want to run Linux on an MC680x0-based Apollo | ||
97 | Domain workstation such as the DN3500. | ||
98 | |||
99 | config VME | ||
100 | bool "VME (Motorola and BVM) support" | ||
101 | select MMU_MOTOROLA if MMU | ||
102 | help | ||
103 | Say Y here if you want to build a kernel for a 680x0 based VME | ||
104 | board. Boards currently supported include Motorola boards MVME147, | ||
105 | MVME162, MVME166, MVME167, MVME172, and MVME177. BVME4000 and | ||
106 | BVME6000 boards from BVM Ltd are also supported. | ||
107 | |||
108 | config MVME147 | ||
109 | bool "MVME147 support" | ||
110 | depends on VME | ||
111 | help | ||
112 | Say Y to include support for early Motorola VME boards. This will | ||
113 | build a kernel which can run on MVME147 single-board computers. If | ||
114 | you select this option you will have to select the appropriate | ||
115 | drivers for SCSI, Ethernet and serial ports later on. | ||
116 | |||
117 | config MVME16x | ||
118 | bool "MVME162, 166 and 167 support" | ||
119 | depends on VME | ||
120 | help | ||
121 | Say Y to include support for Motorola VME boards. This will build a | ||
122 | kernel which can run on MVME162, MVME166, MVME167, MVME172, and | ||
123 | MVME177 boards. If you select this option you will have to select | ||
124 | the appropriate drivers for SCSI, Ethernet and serial ports later | ||
125 | on. | ||
126 | |||
127 | config BVME6000 | ||
128 | bool "BVME4000 and BVME6000 support" | ||
129 | depends on VME | ||
130 | help | ||
131 | Say Y to include support for VME boards from BVM Ltd. This will | ||
132 | build a kernel which can run on BVME4000 and BVME6000 boards. If | ||
133 | you select this option you will have to select the appropriate | ||
134 | drivers for SCSI, Ethernet and serial ports later on. | ||
135 | |||
136 | config HP300 | ||
137 | bool "HP9000/300 and HP9000/400 support" | ||
138 | select MMU_MOTOROLA if MMU | ||
139 | help | ||
140 | This option enables support for the HP9000/300 and HP9000/400 series | ||
141 | of workstations. Support for these machines is still somewhat | ||
142 | experimental. If you plan to try to use the kernel on such a machine | ||
143 | say Y here. | ||
144 | Everybody else says N. | ||
145 | |||
146 | config DIO | ||
147 | bool "DIO bus support" | ||
148 | depends on HP300 | ||
149 | default y | ||
150 | help | ||
151 | Say Y here to enable support for the "DIO" expansion bus used in | ||
152 | HP300 machines. If you are using such a system you almost certainly | ||
153 | want this. | ||
154 | |||
155 | config SUN3X | ||
156 | bool "Sun3x support" | ||
157 | select MMU_MOTOROLA if MMU | ||
158 | select M68030 | ||
159 | help | ||
160 | This option enables support for the Sun 3x series of workstations. | ||
161 | Be warned that this support is very experimental. | ||
162 | Note that Sun 3x kernels are not compatible with Sun 3 hardware. | ||
163 | General Linux information on the Sun 3x series (now discontinued) | ||
164 | is at <http://www.angelfire.com/ca2/tech68k/sun3.html>. | ||
165 | |||
166 | If you don't want to compile a kernel for a Sun 3x, say N. | ||
167 | |||
168 | config Q40 | ||
169 | bool "Q40/Q60 support" | ||
170 | select MMU_MOTOROLA if MMU | ||
171 | help | ||
172 | The Q40 is a Motorola 68040-based successor to the Sinclair QL | ||
173 | manufactured in Germany. There is an official Q40 home page at | ||
174 | <http://www.q40.de/>. This option enables support for the Q40 and | ||
175 | Q60. Select your CPU below. For 68LC060 don't forget to enable FPU | ||
176 | emulation. | ||
177 | |||
178 | config SUN3 | ||
179 | bool "Sun3 support" | ||
180 | depends on !MMU_MOTOROLA | ||
181 | select MMU_SUN3 if MMU | ||
182 | select M68020 | ||
183 | help | ||
184 | This option enables support for the Sun 3 series of workstations | ||
185 | (3/50, 3/60, 3/1xx, 3/2xx systems). Enabling this option requires | ||
186 | that all other hardware types must be disabled, as Sun 3 kernels | ||
187 | are incompatible with all other m68k targets (including Sun 3x!). | ||
188 | |||
189 | If you don't want to compile a kernel exclusively for a Sun 3, say N. | ||
190 | |||
191 | config NATFEAT | ||
192 | bool "ARAnyM emulator support" | ||
193 | depends on ATARI | ||
194 | help | ||
195 | This option enables support for ARAnyM native features, such as | ||
196 | access to a disk image as /dev/hda. | ||
197 | |||
198 | config NFBLOCK | ||
199 | tristate "NatFeat block device support" | ||
200 | depends on BLOCK && NATFEAT | ||
201 | help | ||
202 | Say Y to include support for the ARAnyM NatFeat block device | ||
203 | which allows direct access to the hard drives without using | ||
204 | the hardware emulation. | ||
205 | |||
206 | config NFCON | ||
207 | tristate "NatFeat console driver" | ||
208 | depends on NATFEAT | ||
209 | help | ||
210 | Say Y to include support for the ARAnyM NatFeat console driver | ||
211 | which allows the console output to be redirected to the stderr | ||
212 | output of ARAnyM. | ||
213 | |||
214 | config NFETH | ||
215 | tristate "NatFeat Ethernet support" | ||
216 | depends on NET_ETHERNET && NATFEAT | ||
217 | help | ||
218 | Say Y to include support for the ARAnyM NatFeat network device | ||
219 | which will emulate a regular ethernet device while presenting an | ||
220 | ethertap device to the host system. | ||
221 | |||
222 | comment "Processor type" | ||
223 | |||
224 | config M68020 | ||
225 | bool "68020 support" | ||
226 | help | ||
227 | If you anticipate running this kernel on a computer with a MC68020 | ||
228 | processor, say Y. Otherwise, say N. Note that the 68020 requires a | ||
229 | 68851 MMU (Memory Management Unit) to run Linux/m68k, except on the | ||
230 | Sun 3, which provides its own version. | ||
231 | |||
232 | config M68030 | ||
233 | bool "68030 support" | ||
234 | depends on !MMU_SUN3 | ||
235 | help | ||
236 | If you anticipate running this kernel on a computer with a MC68030 | ||
237 | processor, say Y. Otherwise, say N. Note that a MC68EC030 will not | ||
238 | work, as it does not include an MMU (Memory Management Unit). | ||
239 | |||
240 | config M68040 | ||
241 | bool "68040 support" | ||
242 | depends on !MMU_SUN3 | ||
243 | help | ||
244 | If you anticipate running this kernel on a computer with a MC68LC040 | ||
245 | or MC68040 processor, say Y. Otherwise, say N. Note that an | ||
246 | MC68EC040 will not work, as it does not include an MMU (Memory | ||
247 | Management Unit). | ||
248 | |||
249 | config M68060 | ||
250 | bool "68060 support" | ||
251 | depends on !MMU_SUN3 | ||
252 | help | ||
253 | If you anticipate running this kernel on a computer with a MC68060 | ||
254 | processor, say Y. Otherwise, say N. | ||
255 | |||
256 | config MMU_MOTOROLA | ||
257 | bool | ||
258 | |||
259 | config MMU_SUN3 | ||
260 | bool | ||
261 | depends on MMU && !MMU_MOTOROLA | ||
262 | |||
263 | config M68KFPU_EMU | ||
264 | bool "Math emulation support (EXPERIMENTAL)" | ||
265 | depends on EXPERIMENTAL | ||
266 | help | ||
267 | At some point in the future, this will cause floating-point math | ||
268 | instructions to be emulated by the kernel on machines that lack a | ||
269 | floating-point math coprocessor. Thrill-seekers and chronically | ||
270 | sleep-deprived psychotic hacker types can say Y now, everyone else | ||
271 | should probably wait a while. | ||
272 | |||
273 | config M68KFPU_EMU_EXTRAPREC | ||
274 | bool "Math emulation extra precision" | ||
275 | depends on M68KFPU_EMU | ||
276 | help | ||
277 | The fpu uses normally a few bit more during calculations for | ||
278 | correct rounding, the emulator can (often) do the same but this | ||
279 | extra calculation can cost quite some time, so you can disable | ||
280 | it here. The emulator will then "only" calculate with a 64 bit | ||
281 | mantissa and round slightly incorrect, what is more than enough | ||
282 | for normal usage. | ||
283 | |||
284 | config M68KFPU_EMU_ONLY | ||
285 | bool "Math emulation only kernel" | ||
286 | depends on M68KFPU_EMU | ||
287 | help | ||
288 | This option prevents any floating-point instructions from being | ||
289 | compiled into the kernel, thereby the kernel doesn't save any | ||
290 | floating point context anymore during task switches, so this | ||
291 | kernel will only be usable on machines without a floating-point | ||
292 | math coprocessor. This makes the kernel a bit faster as no tests | ||
293 | needs to be executed whether a floating-point instruction in the | ||
294 | kernel should be executed or not. | ||
295 | |||
296 | config ADVANCED | ||
297 | bool "Advanced configuration options" | ||
298 | ---help--- | ||
299 | This gives you access to some advanced options for the CPU. The | ||
300 | defaults should be fine for most users, but these options may make | ||
301 | it possible for you to improve performance somewhat if you know what | ||
302 | you are doing. | ||
303 | |||
304 | Note that the answer to this question won't directly affect the | ||
305 | kernel: saying N will just cause the configurator to skip all | ||
306 | the questions about these options. | ||
307 | |||
308 | Most users should say N to this question. | ||
309 | |||
310 | config RMW_INSNS | ||
311 | bool "Use read-modify-write instructions" | ||
312 | depends on ADVANCED | ||
313 | ---help--- | ||
314 | This allows to use certain instructions that work with indivisible | ||
315 | read-modify-write bus cycles. While this is faster than the | ||
316 | workaround of disabling interrupts, it can conflict with DMA | ||
317 | ( = direct memory access) on many Amiga systems, and it is also said | ||
318 | to destabilize other machines. It is very likely that this will | ||
319 | cause serious problems on any Amiga or Atari Medusa if set. The only | ||
320 | configuration where it should work are 68030-based Ataris, where it | ||
321 | apparently improves performance. But you've been warned! Unless you | ||
322 | really know what you are doing, say N. Try Y only if you're quite | ||
323 | adventurous. | ||
324 | |||
325 | config SINGLE_MEMORY_CHUNK | ||
326 | bool "Use one physical chunk of memory only" if ADVANCED && !SUN3 | ||
327 | default y if SUN3 | ||
328 | select NEED_MULTIPLE_NODES | ||
329 | help | ||
330 | Ignore all but the first contiguous chunk of physical memory for VM | ||
331 | purposes. This will save a few bytes kernel size and may speed up | ||
332 | some operations. Say N if not sure. | ||
333 | |||
334 | config 060_WRITETHROUGH | ||
335 | bool "Use write-through caching for 68060 supervisor accesses" | ||
336 | depends on ADVANCED && M68060 | ||
337 | ---help--- | ||
338 | The 68060 generally uses copyback caching of recently accessed data. | ||
339 | Copyback caching means that memory writes will be held in an on-chip | ||
340 | cache and only written back to memory some time later. Saying Y | ||
341 | here will force supervisor (kernel) accesses to use writethrough | ||
342 | caching. Writethrough caching means that data is written to memory | ||
343 | straight away, so that cache and memory data always agree. | ||
344 | Writethrough caching is less efficient, but is needed for some | ||
345 | drivers on 68060 based systems where the 68060 bus snooping signal | ||
346 | is hardwired on. The 53c710 SCSI driver is known to suffer from | ||
347 | this problem. | ||
348 | |||
349 | config ARCH_DISCONTIGMEM_ENABLE | ||
350 | def_bool !SINGLE_MEMORY_CHUNK | ||
351 | |||
352 | config NODES_SHIFT | ||
353 | int | ||
354 | default "3" | ||
355 | depends on !SINGLE_MEMORY_CHUNK | ||
356 | |||
357 | config ZORRO | ||
358 | bool "Amiga Zorro (AutoConfig) bus support" | ||
359 | depends on AMIGA | ||
360 | help | ||
361 | This enables support for the Zorro bus in the Amiga. If you have | ||
362 | expansion cards in your Amiga that conform to the Amiga | ||
363 | AutoConfig(tm) specification, say Y, otherwise N. Note that even | ||
364 | expansion cards that do not fit in the Zorro slots but fit in e.g. | ||
365 | the CPU slot may fall in this category, so you have to say Y to let | ||
366 | Linux use these. | ||
367 | |||
368 | config AMIGA_PCMCIA | ||
369 | bool "Amiga 1200/600 PCMCIA support (EXPERIMENTAL)" | ||
370 | depends on AMIGA && EXPERIMENTAL | ||
371 | help | ||
372 | Include support in the kernel for pcmcia on Amiga 1200 and Amiga | ||
373 | 600. If you intend to use pcmcia cards say Y; otherwise say N. | ||
374 | |||
375 | config STRAM_PROC | ||
376 | bool "ST-RAM statistics in /proc" | ||
377 | depends on ATARI | ||
378 | help | ||
379 | Say Y here to report ST-RAM usage statistics in /proc/stram. | ||
380 | |||
381 | config HEARTBEAT | ||
382 | bool "Use power LED as a heartbeat" if AMIGA || APOLLO || ATARI || MAC ||Q40 | ||
383 | default y if !AMIGA && !APOLLO && !ATARI && !MAC && !Q40 && HP300 | ||
384 | help | ||
385 | Use the power-on LED on your machine as a load meter. The exact | ||
386 | behavior is platform-dependent, but normally the flash frequency is | ||
387 | a hyperbolic function of the 5-minute load average. | ||
388 | |||
389 | # We have a dedicated heartbeat LED. :-) | ||
390 | config PROC_HARDWARE | ||
391 | bool "/proc/hardware support" | ||
392 | help | ||
393 | Say Y here to support the /proc/hardware file, which gives you | ||
394 | access to information about the machine you're running on, | ||
395 | including the model, CPU, MMU, clock speed, BogoMIPS rating, | ||
396 | and memory size. | ||
397 | |||
398 | config ISA | ||
399 | bool | ||
400 | depends on Q40 || AMIGA_PCMCIA | ||
401 | default y | ||
402 | help | ||
403 | Find out whether you have ISA slots on your motherboard. ISA is the | ||
404 | name of a bus system, i.e. the way the CPU talks to the other stuff | ||
405 | inside your box. Other bus systems are PCI, EISA, MicroChannel | ||
406 | (MCA) or VESA. ISA is an older system, now being displaced by PCI; | ||
407 | newer boards don't support it. If you have ISA, say Y, otherwise N. | ||
408 | |||
409 | config GENERIC_ISA_DMA | ||
410 | bool | ||
411 | depends on Q40 || AMIGA_PCMCIA | ||
412 | default y | ||
413 | |||
414 | source "drivers/pci/Kconfig" | ||
415 | |||
416 | source "drivers/zorro/Kconfig" | ||
417 | |||
diff --git a/arch/m68knommu/Kconfig b/arch/m68k/Kconfig.nommu index b5424cf948e6..273bccab9517 100644 --- a/arch/m68knommu/Kconfig +++ b/arch/m68k/Kconfig.nommu | |||
@@ -1,43 +1,7 @@ | |||
1 | config M68K | ||
2 | bool | ||
3 | default y | ||
4 | select HAVE_IDE | ||
5 | select HAVE_GENERIC_HARDIRQS | ||
6 | select GENERIC_HARDIRQS_NO_DEPRECATED | ||
7 | |||
8 | config MMU | ||
9 | bool | ||
10 | default n | ||
11 | |||
12 | config NO_DMA | ||
13 | bool | ||
14 | depends on !COLDFIRE | ||
15 | default y | ||
16 | |||
17 | config FPU | 1 | config FPU |
18 | bool | 2 | bool |
19 | default n | 3 | default n |
20 | 4 | ||
21 | config ZONE_DMA | ||
22 | bool | ||
23 | default y | ||
24 | |||
25 | config RWSEM_GENERIC_SPINLOCK | ||
26 | bool | ||
27 | default y | ||
28 | |||
29 | config RWSEM_XCHGADD_ALGORITHM | ||
30 | bool | ||
31 | default n | ||
32 | |||
33 | config ARCH_HAS_ILOG2_U32 | ||
34 | bool | ||
35 | default n | ||
36 | |||
37 | config ARCH_HAS_ILOG2_U64 | ||
38 | bool | ||
39 | default n | ||
40 | |||
41 | config GENERIC_FIND_NEXT_BIT | 5 | config GENERIC_FIND_NEXT_BIT |
42 | bool | 6 | bool |
43 | default y | 7 | default y |
@@ -46,29 +10,14 @@ config GENERIC_GPIO | |||
46 | bool | 10 | bool |
47 | default n | 11 | default n |
48 | 12 | ||
49 | config GENERIC_HWEIGHT | ||
50 | bool | ||
51 | default y | ||
52 | |||
53 | config GENERIC_CALIBRATE_DELAY | ||
54 | bool | ||
55 | default y | ||
56 | |||
57 | config GENERIC_CMOS_UPDATE | 13 | config GENERIC_CMOS_UPDATE |
58 | bool | 14 | bool |
59 | default y | 15 | default y |
60 | 16 | ||
61 | config TIME_LOW_RES | ||
62 | bool | ||
63 | default y | ||
64 | |||
65 | config GENERIC_CLOCKEVENTS | 17 | config GENERIC_CLOCKEVENTS |
66 | bool | 18 | bool |
67 | default n | 19 | default n |
68 | 20 | ||
69 | config NO_IOPORT | ||
70 | def_bool y | ||
71 | |||
72 | config COLDFIRE_SW_A7 | 21 | config COLDFIRE_SW_A7 |
73 | bool | 22 | bool |
74 | default n | 23 | default n |
@@ -85,12 +34,6 @@ config HAVE_MBAR | |||
85 | config HAVE_IPSBAR | 34 | config HAVE_IPSBAR |
86 | bool | 35 | bool |
87 | 36 | ||
88 | source "init/Kconfig" | ||
89 | |||
90 | source "kernel/Kconfig.freezer" | ||
91 | |||
92 | menu "Processor type and features" | ||
93 | |||
94 | choice | 37 | choice |
95 | prompt "CPU" | 38 | prompt "CPU" |
96 | default M68EZ328 | 39 | default M68EZ328 |
@@ -630,11 +573,6 @@ config 4KSTACKS | |||
630 | running more threads on a system and also reduces the pressure | 573 | running more threads on a system and also reduces the pressure |
631 | on the VM subsystem for higher order allocations. | 574 | on the VM subsystem for higher order allocations. |
632 | 575 | ||
633 | config HZ | ||
634 | int | ||
635 | default 1000 if CLEOPATRA | ||
636 | default 100 | ||
637 | |||
638 | comment "RAM configuration" | 576 | comment "RAM configuration" |
639 | 577 | ||
640 | config RAMBASE | 578 | config RAMBASE |
@@ -803,10 +741,6 @@ endif | |||
803 | 741 | ||
804 | source "kernel/time/Kconfig" | 742 | source "kernel/time/Kconfig" |
805 | 743 | ||
806 | source "mm/Kconfig" | ||
807 | |||
808 | endmenu | ||
809 | |||
810 | config ISA_DMA_API | 744 | config ISA_DMA_API |
811 | bool | 745 | bool |
812 | depends on !M5272 | 746 | depends on !M5272 |
@@ -814,31 +748,3 @@ config ISA_DMA_API | |||
814 | 748 | ||
815 | source "drivers/pcmcia/Kconfig" | 749 | source "drivers/pcmcia/Kconfig" |
816 | 750 | ||
817 | menu "Executable file formats" | ||
818 | |||
819 | source "fs/Kconfig.binfmt" | ||
820 | |||
821 | endmenu | ||
822 | |||
823 | menu "Power management options" | ||
824 | |||
825 | config PM | ||
826 | bool "Power Management support" | ||
827 | help | ||
828 | Support processor power management modes | ||
829 | |||
830 | endmenu | ||
831 | |||
832 | source "net/Kconfig" | ||
833 | |||
834 | source "drivers/Kconfig" | ||
835 | |||
836 | source "fs/Kconfig" | ||
837 | |||
838 | source "arch/m68knommu/Kconfig.debug" | ||
839 | |||
840 | source "security/Kconfig" | ||
841 | |||
842 | source "crypto/Kconfig" | ||
843 | |||
844 | source "lib/Kconfig" | ||
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile index b793163abc61..be46cadd4017 100644 --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile | |||
@@ -1,123 +1,7 @@ | |||
1 | # | ||
2 | # m68k/Makefile | ||
3 | # | ||
4 | # This file is included by the global makefile so that you can add your own | ||
5 | # architecture-specific flags and dependencies. Remember to do have actions | ||
6 | # for "archclean" and "archdep" for cleaning up and making dependencies for | ||
7 | # this architecture | ||
8 | # | ||
9 | # This file is subject to the terms and conditions of the GNU General Public | ||
10 | # License. See the file "COPYING" in the main directory of this archive | ||
11 | # for more details. | ||
12 | # | ||
13 | # Copyright (C) 1994 by Hamish Macdonald | ||
14 | # | ||
15 | |||
16 | KBUILD_DEFCONFIG := multi_defconfig | 1 | KBUILD_DEFCONFIG := multi_defconfig |
17 | 2 | ||
18 | # override top level makefile | 3 | ifdef CONFIG_MMU |
19 | AS += -m68020 | 4 | include $(srctree)/arch/m68k/Makefile_mm |
20 | LDFLAGS := -m m68kelf | ||
21 | KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds | ||
22 | ifneq ($(SUBARCH),$(ARCH)) | ||
23 | ifeq ($(CROSS_COMPILE),) | ||
24 | CROSS_COMPILE := $(call cc-cross-prefix, \ | ||
25 | m68k-linux-gnu- m68k-linux- m68k-unknown-linux-gnu-) | ||
26 | endif | ||
27 | endif | ||
28 | |||
29 | ifdef CONFIG_SUN3 | ||
30 | LDFLAGS_vmlinux = -N | ||
31 | endif | ||
32 | |||
33 | CHECKFLAGS += -D__mc68000__ | ||
34 | |||
35 | # without -fno-strength-reduce the 53c7xx.c driver fails ;-( | ||
36 | KBUILD_CFLAGS += -pipe -fno-strength-reduce -ffixed-a2 | ||
37 | |||
38 | # enable processor switch if compiled only for a single cpu | ||
39 | ifndef CONFIG_M68020 | ||
40 | ifndef CONFIG_M68030 | ||
41 | |||
42 | ifndef CONFIG_M68060 | ||
43 | KBUILD_CFLAGS += -m68040 | ||
44 | endif | ||
45 | |||
46 | ifndef CONFIG_M68040 | ||
47 | KBUILD_CFLAGS += -m68060 | ||
48 | endif | ||
49 | |||
50 | endif | ||
51 | endif | ||
52 | |||
53 | ifdef CONFIG_KGDB | ||
54 | # If configured for kgdb support, include debugging infos and keep the | ||
55 | # frame pointer | ||
56 | KBUILD_CFLAGS := $(subst -fomit-frame-pointer,,$(KBUILD_CFLAGS)) -g | ||
57 | endif | ||
58 | |||
59 | ifndef CONFIG_SUN3 | ||
60 | head-y := arch/m68k/kernel/head.o | ||
61 | else | 5 | else |
62 | head-y := arch/m68k/kernel/sun3-head.o | 6 | include $(srctree)/arch/m68k/Makefile_no |
63 | endif | 7 | endif |
64 | |||
65 | core-y += arch/m68k/kernel/ arch/m68k/mm/ | ||
66 | libs-y += arch/m68k/lib/ | ||
67 | |||
68 | core-$(CONFIG_Q40) += arch/m68k/q40/ | ||
69 | core-$(CONFIG_AMIGA) += arch/m68k/amiga/ | ||
70 | core-$(CONFIG_ATARI) += arch/m68k/atari/ | ||
71 | core-$(CONFIG_MAC) += arch/m68k/mac/ | ||
72 | core-$(CONFIG_HP300) += arch/m68k/hp300/ | ||
73 | core-$(CONFIG_APOLLO) += arch/m68k/apollo/ | ||
74 | core-$(CONFIG_MVME147) += arch/m68k/mvme147/ | ||
75 | core-$(CONFIG_MVME16x) += arch/m68k/mvme16x/ | ||
76 | core-$(CONFIG_BVME6000) += arch/m68k/bvme6000/ | ||
77 | core-$(CONFIG_SUN3X) += arch/m68k/sun3x/ arch/m68k/sun3/ | ||
78 | core-$(CONFIG_SUN3) += arch/m68k/sun3/ arch/m68k/sun3/prom/ | ||
79 | core-$(CONFIG_NATFEAT) += arch/m68k/emu/ | ||
80 | core-$(CONFIG_M68040) += arch/m68k/fpsp040/ | ||
81 | core-$(CONFIG_M68060) += arch/m68k/ifpsp060/ | ||
82 | core-$(CONFIG_M68KFPU_EMU) += arch/m68k/math-emu/ | ||
83 | |||
84 | all: zImage | ||
85 | |||
86 | lilo: vmlinux | ||
87 | if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi | ||
88 | if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi | ||
89 | cat vmlinux > $(INSTALL_PATH)/vmlinux | ||
90 | cp System.map $(INSTALL_PATH)/System.map | ||
91 | if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi | ||
92 | |||
93 | zImage compressed: vmlinux.gz | ||
94 | |||
95 | vmlinux.gz: vmlinux | ||
96 | |||
97 | ifndef CONFIG_KGDB | ||
98 | cp vmlinux vmlinux.tmp | ||
99 | $(STRIP) vmlinux.tmp | ||
100 | gzip -9c vmlinux.tmp >vmlinux.gz | ||
101 | rm vmlinux.tmp | ||
102 | else | ||
103 | gzip -9c vmlinux >vmlinux.gz | ||
104 | endif | ||
105 | |||
106 | bzImage: vmlinux.bz2 | ||
107 | |||
108 | vmlinux.bz2: vmlinux | ||
109 | |||
110 | ifndef CONFIG_KGDB | ||
111 | cp vmlinux vmlinux.tmp | ||
112 | $(STRIP) vmlinux.tmp | ||
113 | bzip2 -1c vmlinux.tmp >vmlinux.bz2 | ||
114 | rm vmlinux.tmp | ||
115 | else | ||
116 | bzip2 -1c vmlinux >vmlinux.bz2 | ||
117 | endif | ||
118 | |||
119 | archclean: | ||
120 | rm -f vmlinux.gz vmlinux.bz2 | ||
121 | |||
122 | install: | ||
123 | sh $(srctree)/arch/m68k/install.sh $(KERNELRELEASE) vmlinux.gz System.map "$(INSTALL_PATH)" | ||
diff --git a/arch/m68k/Makefile_mm b/arch/m68k/Makefile_mm new file mode 100644 index 000000000000..d449b6d5aecf --- /dev/null +++ b/arch/m68k/Makefile_mm | |||
@@ -0,0 +1,121 @@ | |||
1 | # | ||
2 | # m68k/Makefile | ||
3 | # | ||
4 | # This file is included by the global makefile so that you can add your own | ||
5 | # architecture-specific flags and dependencies. Remember to do have actions | ||
6 | # for "archclean" and "archdep" for cleaning up and making dependencies for | ||
7 | # this architecture | ||
8 | # | ||
9 | # This file is subject to the terms and conditions of the GNU General Public | ||
10 | # License. See the file "COPYING" in the main directory of this archive | ||
11 | # for more details. | ||
12 | # | ||
13 | # Copyright (C) 1994 by Hamish Macdonald | ||
14 | # | ||
15 | |||
16 | # override top level makefile | ||
17 | AS += -m68020 | ||
18 | LDFLAGS := -m m68kelf | ||
19 | KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds | ||
20 | ifneq ($(SUBARCH),$(ARCH)) | ||
21 | ifeq ($(CROSS_COMPILE),) | ||
22 | CROSS_COMPILE := $(call cc-cross-prefix, \ | ||
23 | m68k-linux-gnu- m68k-linux- m68k-unknown-linux-gnu-) | ||
24 | endif | ||
25 | endif | ||
26 | |||
27 | ifdef CONFIG_SUN3 | ||
28 | LDFLAGS_vmlinux = -N | ||
29 | endif | ||
30 | |||
31 | CHECKFLAGS += -D__mc68000__ | ||
32 | |||
33 | # without -fno-strength-reduce the 53c7xx.c driver fails ;-( | ||
34 | KBUILD_CFLAGS += -pipe -fno-strength-reduce -ffixed-a2 | ||
35 | |||
36 | # enable processor switch if compiled only for a single cpu | ||
37 | ifndef CONFIG_M68020 | ||
38 | ifndef CONFIG_M68030 | ||
39 | |||
40 | ifndef CONFIG_M68060 | ||
41 | KBUILD_CFLAGS += -m68040 | ||
42 | endif | ||
43 | |||
44 | ifndef CONFIG_M68040 | ||
45 | KBUILD_CFLAGS += -m68060 | ||
46 | endif | ||
47 | |||
48 | endif | ||
49 | endif | ||
50 | |||
51 | ifdef CONFIG_KGDB | ||
52 | # If configured for kgdb support, include debugging infos and keep the | ||
53 | # frame pointer | ||
54 | KBUILD_CFLAGS := $(subst -fomit-frame-pointer,,$(KBUILD_CFLAGS)) -g | ||
55 | endif | ||
56 | |||
57 | ifndef CONFIG_SUN3 | ||
58 | head-y := arch/m68k/kernel/head.o | ||
59 | else | ||
60 | head-y := arch/m68k/kernel/sun3-head.o | ||
61 | endif | ||
62 | |||
63 | core-y += arch/m68k/kernel/ arch/m68k/mm/ | ||
64 | libs-y += arch/m68k/lib/ | ||
65 | |||
66 | core-$(CONFIG_Q40) += arch/m68k/q40/ | ||
67 | core-$(CONFIG_AMIGA) += arch/m68k/amiga/ | ||
68 | core-$(CONFIG_ATARI) += arch/m68k/atari/ | ||
69 | core-$(CONFIG_MAC) += arch/m68k/mac/ | ||
70 | core-$(CONFIG_HP300) += arch/m68k/hp300/ | ||
71 | core-$(CONFIG_APOLLO) += arch/m68k/apollo/ | ||
72 | core-$(CONFIG_MVME147) += arch/m68k/mvme147/ | ||
73 | core-$(CONFIG_MVME16x) += arch/m68k/mvme16x/ | ||
74 | core-$(CONFIG_BVME6000) += arch/m68k/bvme6000/ | ||
75 | core-$(CONFIG_SUN3X) += arch/m68k/sun3x/ arch/m68k/sun3/ | ||
76 | core-$(CONFIG_SUN3) += arch/m68k/sun3/ arch/m68k/sun3/prom/ | ||
77 | core-$(CONFIG_NATFEAT) += arch/m68k/emu/ | ||
78 | core-$(CONFIG_M68040) += arch/m68k/fpsp040/ | ||
79 | core-$(CONFIG_M68060) += arch/m68k/ifpsp060/ | ||
80 | core-$(CONFIG_M68KFPU_EMU) += arch/m68k/math-emu/ | ||
81 | |||
82 | all: zImage | ||
83 | |||
84 | lilo: vmlinux | ||
85 | if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi | ||
86 | if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi | ||
87 | cat vmlinux > $(INSTALL_PATH)/vmlinux | ||
88 | cp System.map $(INSTALL_PATH)/System.map | ||
89 | if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi | ||
90 | |||
91 | zImage compressed: vmlinux.gz | ||
92 | |||
93 | vmlinux.gz: vmlinux | ||
94 | |||
95 | ifndef CONFIG_KGDB | ||
96 | cp vmlinux vmlinux.tmp | ||
97 | $(STRIP) vmlinux.tmp | ||
98 | gzip -9c vmlinux.tmp >vmlinux.gz | ||
99 | rm vmlinux.tmp | ||
100 | else | ||
101 | gzip -9c vmlinux >vmlinux.gz | ||
102 | endif | ||
103 | |||
104 | bzImage: vmlinux.bz2 | ||
105 | |||
106 | vmlinux.bz2: vmlinux | ||
107 | |||
108 | ifndef CONFIG_KGDB | ||
109 | cp vmlinux vmlinux.tmp | ||
110 | $(STRIP) vmlinux.tmp | ||
111 | bzip2 -1c vmlinux.tmp >vmlinux.bz2 | ||
112 | rm vmlinux.tmp | ||
113 | else | ||
114 | bzip2 -1c vmlinux >vmlinux.bz2 | ||
115 | endif | ||
116 | |||
117 | archclean: | ||
118 | rm -f vmlinux.gz vmlinux.bz2 | ||
119 | |||
120 | install: | ||
121 | sh $(srctree)/arch/m68k/install.sh $(KERNELRELEASE) vmlinux.gz System.map "$(INSTALL_PATH)" | ||
diff --git a/arch/m68knommu/Makefile b/arch/m68k/Makefile_no index 589613fed31d..81652ab893e1 100644 --- a/arch/m68knommu/Makefile +++ b/arch/m68k/Makefile_no | |||
@@ -1,5 +1,5 @@ | |||
1 | # | 1 | # |
2 | # arch/m68knommu/Makefile | 2 | # arch/m68k/Makefile |
3 | # | 3 | # |
4 | # This file is subject to the terms and conditions of the GNU General Public | 4 | # This file is subject to the terms and conditions of the GNU General Public |
5 | # License. See the file "COPYING" in the main directory of this archive | 5 | # License. See the file "COPYING" in the main directory of this archive |
@@ -8,8 +8,6 @@ | |||
8 | # (C) Copyright 2002, Greg Ungerer <gerg@snapgear.com> | 8 | # (C) Copyright 2002, Greg Ungerer <gerg@snapgear.com> |
9 | # | 9 | # |
10 | 10 | ||
11 | KBUILD_DEFCONFIG := m5208evb_defconfig | ||
12 | |||
13 | platform-$(CONFIG_M68328) := 68328 | 11 | platform-$(CONFIG_M68328) := 68328 |
14 | platform-$(CONFIG_M68EZ328) := 68EZ328 | 12 | platform-$(CONFIG_M68EZ328) := 68EZ328 |
15 | platform-$(CONFIG_M68VZ328) := 68VZ328 | 13 | platform-$(CONFIG_M68VZ328) := 68VZ328 |
@@ -82,7 +80,7 @@ cpuclass-$(CONFIG_M68360) := 68360 | |||
82 | CPUCLASS := $(cpuclass-y) | 80 | CPUCLASS := $(cpuclass-y) |
83 | 81 | ||
84 | ifneq ($(CPUCLASS),$(PLATFORM)) | 82 | ifneq ($(CPUCLASS),$(PLATFORM)) |
85 | CLASSDIR := arch/m68knommu/platform/$(cpuclass-y)/ | 83 | CLASSDIR := arch/m68k/platform/$(cpuclass-y)/ |
86 | endif | 84 | endif |
87 | 85 | ||
88 | export PLATFORM BOARD MODEL CPUCLASS | 86 | export PLATFORM BOARD MODEL CPUCLASS |
@@ -114,13 +112,13 @@ KBUILD_CFLAGS += $(cflags-y) | |||
114 | KBUILD_CFLAGS += -D__linux__ | 112 | KBUILD_CFLAGS += -D__linux__ |
115 | KBUILD_CFLAGS += -DUTS_SYSNAME=\"uClinux\" | 113 | KBUILD_CFLAGS += -DUTS_SYSNAME=\"uClinux\" |
116 | 114 | ||
117 | head-y := arch/m68knommu/platform/$(cpuclass-y)/head.o | 115 | head-y := arch/m68k/platform/$(cpuclass-y)/head.o |
118 | 116 | ||
119 | core-y += arch/m68knommu/kernel/ \ | 117 | core-y += arch/m68k/kernel/ \ |
120 | arch/m68knommu/mm/ \ | 118 | arch/m68k/mm/ \ |
121 | $(CLASSDIR) \ | 119 | $(CLASSDIR) \ |
122 | arch/m68knommu/platform/$(PLATFORM)/ | 120 | arch/m68k/platform/$(PLATFORM)/ |
123 | libs-y += arch/m68knommu/lib/ | 121 | libs-y += arch/m68k/lib/ |
124 | 122 | ||
125 | archclean: | 123 | archclean: |
126 | 124 | ||
diff --git a/arch/m68knommu/configs/m5208evb_defconfig b/arch/m68k/configs/m5208evb_defconfig index 2f5655c577af..c1616824e201 100644 --- a/arch/m68knommu/configs/m5208evb_defconfig +++ b/arch/m68k/configs/m5208evb_defconfig | |||
@@ -1,3 +1,4 @@ | |||
1 | # CONFIG_MMU is not set | ||
1 | CONFIG_EXPERIMENTAL=y | 2 | CONFIG_EXPERIMENTAL=y |
2 | CONFIG_LOG_BUF_SHIFT=14 | 3 | CONFIG_LOG_BUF_SHIFT=14 |
3 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set | 4 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set |
@@ -37,6 +38,7 @@ CONFIG_INET=y | |||
37 | # CONFIG_INET_LRO is not set | 38 | # CONFIG_INET_LRO is not set |
38 | # CONFIG_INET_DIAG is not set | 39 | # CONFIG_INET_DIAG is not set |
39 | # CONFIG_IPV6 is not set | 40 | # CONFIG_IPV6 is not set |
41 | # CONFIG_FW_LOADER is not set | ||
40 | CONFIG_MTD=y | 42 | CONFIG_MTD=y |
41 | CONFIG_MTD_PARTITIONS=y | 43 | CONFIG_MTD_PARTITIONS=y |
42 | CONFIG_MTD_CHAR=y | 44 | CONFIG_MTD_CHAR=y |
diff --git a/arch/m68knommu/configs/m5249evb_defconfig b/arch/m68k/configs/m5249evb_defconfig index 16df72bfbd45..a6599e42facf 100644 --- a/arch/m68knommu/configs/m5249evb_defconfig +++ b/arch/m68k/configs/m5249evb_defconfig | |||
@@ -1,3 +1,4 @@ | |||
1 | # CONFIG_MMU is not set | ||
1 | CONFIG_EXPERIMENTAL=y | 2 | CONFIG_EXPERIMENTAL=y |
2 | CONFIG_LOG_BUF_SHIFT=14 | 3 | CONFIG_LOG_BUF_SHIFT=14 |
3 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set | 4 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set |
@@ -35,6 +36,7 @@ CONFIG_INET=y | |||
35 | # CONFIG_INET_LRO is not set | 36 | # CONFIG_INET_LRO is not set |
36 | # CONFIG_INET_DIAG is not set | 37 | # CONFIG_INET_DIAG is not set |
37 | # CONFIG_IPV6 is not set | 38 | # CONFIG_IPV6 is not set |
39 | # CONFIG_FW_LOADER is not set | ||
38 | CONFIG_MTD=y | 40 | CONFIG_MTD=y |
39 | CONFIG_MTD_PARTITIONS=y | 41 | CONFIG_MTD_PARTITIONS=y |
40 | CONFIG_MTD_CHAR=y | 42 | CONFIG_MTD_CHAR=y |
diff --git a/arch/m68knommu/configs/m5272c3_defconfig b/arch/m68k/configs/m5272c3_defconfig index 4e6ea50c7f33..3fa60a57a0f9 100644 --- a/arch/m68knommu/configs/m5272c3_defconfig +++ b/arch/m68k/configs/m5272c3_defconfig | |||
@@ -1,3 +1,4 @@ | |||
1 | # CONFIG_MMU is not set | ||
1 | CONFIG_EXPERIMENTAL=y | 2 | CONFIG_EXPERIMENTAL=y |
2 | CONFIG_LOG_BUF_SHIFT=14 | 3 | CONFIG_LOG_BUF_SHIFT=14 |
3 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set | 4 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set |
@@ -33,6 +34,7 @@ CONFIG_INET=y | |||
33 | # CONFIG_INET_LRO is not set | 34 | # CONFIG_INET_LRO is not set |
34 | # CONFIG_INET_DIAG is not set | 35 | # CONFIG_INET_DIAG is not set |
35 | # CONFIG_IPV6 is not set | 36 | # CONFIG_IPV6 is not set |
37 | # CONFIG_FW_LOADER is not set | ||
36 | CONFIG_MTD=y | 38 | CONFIG_MTD=y |
37 | CONFIG_MTD_PARTITIONS=y | 39 | CONFIG_MTD_PARTITIONS=y |
38 | CONFIG_MTD_CHAR=y | 40 | CONFIG_MTD_CHAR=y |
diff --git a/arch/m68knommu/configs/m5275evb_defconfig b/arch/m68k/configs/m5275evb_defconfig index f3dd74115a34..33c32aeca12b 100644 --- a/arch/m68knommu/configs/m5275evb_defconfig +++ b/arch/m68k/configs/m5275evb_defconfig | |||
@@ -1,3 +1,4 @@ | |||
1 | # CONFIG_MMU is not set | ||
1 | CONFIG_EXPERIMENTAL=y | 2 | CONFIG_EXPERIMENTAL=y |
2 | CONFIG_LOG_BUF_SHIFT=14 | 3 | CONFIG_LOG_BUF_SHIFT=14 |
3 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set | 4 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set |
@@ -36,6 +37,7 @@ CONFIG_INET=y | |||
36 | # CONFIG_INET_LRO is not set | 37 | # CONFIG_INET_LRO is not set |
37 | # CONFIG_INET_DIAG is not set | 38 | # CONFIG_INET_DIAG is not set |
38 | # CONFIG_IPV6 is not set | 39 | # CONFIG_IPV6 is not set |
40 | # CONFIG_FW_LOADER is not set | ||
39 | CONFIG_MTD=y | 41 | CONFIG_MTD=y |
40 | CONFIG_MTD_PARTITIONS=y | 42 | CONFIG_MTD_PARTITIONS=y |
41 | CONFIG_MTD_CHAR=y | 43 | CONFIG_MTD_CHAR=y |
diff --git a/arch/m68knommu/configs/m5307c3_defconfig b/arch/m68k/configs/m5307c3_defconfig index bce0a20c3737..43795f41f7c7 100644 --- a/arch/m68knommu/configs/m5307c3_defconfig +++ b/arch/m68k/configs/m5307c3_defconfig | |||
@@ -1,3 +1,4 @@ | |||
1 | # CONFIG_MMU is not set | ||
1 | CONFIG_EXPERIMENTAL=y | 2 | CONFIG_EXPERIMENTAL=y |
2 | CONFIG_LOG_BUF_SHIFT=14 | 3 | CONFIG_LOG_BUF_SHIFT=14 |
3 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set | 4 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set |
@@ -35,6 +36,7 @@ CONFIG_INET=y | |||
35 | # CONFIG_INET_LRO is not set | 36 | # CONFIG_INET_LRO is not set |
36 | # CONFIG_INET_DIAG is not set | 37 | # CONFIG_INET_DIAG is not set |
37 | # CONFIG_IPV6 is not set | 38 | # CONFIG_IPV6 is not set |
39 | # CONFIG_FW_LOADER is not set | ||
38 | CONFIG_MTD=y | 40 | CONFIG_MTD=y |
39 | CONFIG_MTD_PARTITIONS=y | 41 | CONFIG_MTD_PARTITIONS=y |
40 | CONFIG_MTD_CHAR=y | 42 | CONFIG_MTD_CHAR=y |
diff --git a/arch/m68knommu/configs/m5407c3_defconfig b/arch/m68k/configs/m5407c3_defconfig index 618cc32691f2..72746c57a571 100644 --- a/arch/m68knommu/configs/m5407c3_defconfig +++ b/arch/m68k/configs/m5407c3_defconfig | |||
@@ -1,3 +1,4 @@ | |||
1 | # CONFIG_MMU is not set | ||
1 | CONFIG_EXPERIMENTAL=y | 2 | CONFIG_EXPERIMENTAL=y |
2 | CONFIG_LOG_BUF_SHIFT=14 | 3 | CONFIG_LOG_BUF_SHIFT=14 |
3 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set | 4 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set |
@@ -35,6 +36,7 @@ CONFIG_INET=y | |||
35 | # CONFIG_INET_LRO is not set | 36 | # CONFIG_INET_LRO is not set |
36 | # CONFIG_INET_DIAG is not set | 37 | # CONFIG_INET_DIAG is not set |
37 | # CONFIG_IPV6 is not set | 38 | # CONFIG_IPV6 is not set |
39 | # CONFIG_FW_LOADER is not set | ||
38 | CONFIG_MTD=y | 40 | CONFIG_MTD=y |
39 | CONFIG_MTD_PARTITIONS=y | 41 | CONFIG_MTD_PARTITIONS=y |
40 | CONFIG_MTD_CHAR=y | 42 | CONFIG_MTD_CHAR=y |
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index 55d5d6b680a2..c482ebc9dd54 100644 --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile | |||
@@ -1,17 +1,5 @@ | |||
1 | # | 1 | ifdef CONFIG_MMU |
2 | # Makefile for the linux kernel. | 2 | include arch/m68k/kernel/Makefile_mm |
3 | # | ||
4 | |||
5 | ifndef CONFIG_SUN3 | ||
6 | extra-y := head.o | ||
7 | else | 3 | else |
8 | extra-y := sun3-head.o | 4 | include arch/m68k/kernel/Makefile_no |
9 | endif | 5 | endif |
10 | extra-y += vmlinux.lds | ||
11 | |||
12 | obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \ | ||
13 | sys_m68k.o time.o setup.o m68k_ksyms.o devres.o | ||
14 | |||
15 | devres-y = ../../../kernel/irq/devres.o | ||
16 | |||
17 | obj-y$(CONFIG_MMU_SUN3) += dma.o # no, it's not a typo | ||
diff --git a/arch/m68k/kernel/Makefile_mm b/arch/m68k/kernel/Makefile_mm new file mode 100644 index 000000000000..55d5d6b680a2 --- /dev/null +++ b/arch/m68k/kernel/Makefile_mm | |||
@@ -0,0 +1,17 @@ | |||
1 | # | ||
2 | # Makefile for the linux kernel. | ||
3 | # | ||
4 | |||
5 | ifndef CONFIG_SUN3 | ||
6 | extra-y := head.o | ||
7 | else | ||
8 | extra-y := sun3-head.o | ||
9 | endif | ||
10 | extra-y += vmlinux.lds | ||
11 | |||
12 | obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \ | ||
13 | sys_m68k.o time.o setup.o m68k_ksyms.o devres.o | ||
14 | |||
15 | devres-y = ../../../kernel/irq/devres.o | ||
16 | |||
17 | obj-y$(CONFIG_MMU_SUN3) += dma.o # no, it's not a typo | ||
diff --git a/arch/m68knommu/kernel/Makefile b/arch/m68k/kernel/Makefile_no index 37c3fc074c0a..37c3fc074c0a 100644 --- a/arch/m68knommu/kernel/Makefile +++ b/arch/m68k/kernel/Makefile_no | |||
diff --git a/arch/m68k/kernel/asm-offsets.c b/arch/m68k/kernel/asm-offsets.c index 78e59b82ebc3..59a69a5c62f2 100644 --- a/arch/m68k/kernel/asm-offsets.c +++ b/arch/m68k/kernel/asm-offsets.c | |||
@@ -1,100 +1,5 @@ | |||
1 | /* | ||
2 | * This program is used to generate definitions needed by | ||
3 | * assembly language modules. | ||
4 | * | ||
5 | * We use the technique used in the OSF Mach kernel code: | ||
6 | * generate asm statements containing #defines, | ||
7 | * compile this file to assembler, and then extract the | ||
8 | * #defines from the assembly-language output. | ||
9 | */ | ||
10 | |||
11 | #define ASM_OFFSETS_C | ||
12 | |||
13 | #include <linux/stddef.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/kernel_stat.h> | ||
16 | #include <linux/kbuild.h> | ||
17 | #include <asm/bootinfo.h> | ||
18 | #include <asm/irq.h> | ||
19 | #include <asm/amigahw.h> | ||
20 | #include <linux/font.h> | ||
21 | |||
22 | int main(void) | ||
23 | { | ||
24 | /* offsets into the task struct */ | ||
25 | DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); | ||
26 | DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info)); | ||
27 | DEFINE(TASK_MM, offsetof(struct task_struct, mm)); | ||
28 | #ifdef CONFIG_MMU | 1 | #ifdef CONFIG_MMU |
29 | DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info)); | 2 | #include "asm-offsets_mm.c" |
3 | #else | ||
4 | #include "asm-offsets_no.c" | ||
30 | #endif | 5 | #endif |
31 | |||
32 | /* offsets into the thread struct */ | ||
33 | DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp)); | ||
34 | DEFINE(THREAD_USP, offsetof(struct thread_struct, usp)); | ||
35 | DEFINE(THREAD_SR, offsetof(struct thread_struct, sr)); | ||
36 | DEFINE(THREAD_FS, offsetof(struct thread_struct, fs)); | ||
37 | DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp)); | ||
38 | DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0)); | ||
39 | DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp)); | ||
40 | DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl)); | ||
41 | DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate)); | ||
42 | |||
43 | /* offsets into the thread_info struct */ | ||
44 | DEFINE(TINFO_PREEMPT, offsetof(struct thread_info, preempt_count)); | ||
45 | DEFINE(TINFO_FLAGS, offsetof(struct thread_info, flags)); | ||
46 | |||
47 | /* offsets into the pt_regs */ | ||
48 | DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0)); | ||
49 | DEFINE(PT_OFF_ORIG_D0, offsetof(struct pt_regs, orig_d0)); | ||
50 | DEFINE(PT_OFF_D1, offsetof(struct pt_regs, d1)); | ||
51 | DEFINE(PT_OFF_D2, offsetof(struct pt_regs, d2)); | ||
52 | DEFINE(PT_OFF_D3, offsetof(struct pt_regs, d3)); | ||
53 | DEFINE(PT_OFF_D4, offsetof(struct pt_regs, d4)); | ||
54 | DEFINE(PT_OFF_D5, offsetof(struct pt_regs, d5)); | ||
55 | DEFINE(PT_OFF_A0, offsetof(struct pt_regs, a0)); | ||
56 | DEFINE(PT_OFF_A1, offsetof(struct pt_regs, a1)); | ||
57 | DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2)); | ||
58 | DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc)); | ||
59 | DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr)); | ||
60 | /* bitfields are a bit difficult */ | ||
61 | DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4); | ||
62 | |||
63 | /* offsets into the irq_cpustat_t struct */ | ||
64 | DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); | ||
65 | |||
66 | /* offsets into the bi_record struct */ | ||
67 | DEFINE(BIR_TAG, offsetof(struct bi_record, tag)); | ||
68 | DEFINE(BIR_SIZE, offsetof(struct bi_record, size)); | ||
69 | DEFINE(BIR_DATA, offsetof(struct bi_record, data)); | ||
70 | |||
71 | /* offsets into font_desc (drivers/video/console/font.h) */ | ||
72 | DEFINE(FONT_DESC_IDX, offsetof(struct font_desc, idx)); | ||
73 | DEFINE(FONT_DESC_NAME, offsetof(struct font_desc, name)); | ||
74 | DEFINE(FONT_DESC_WIDTH, offsetof(struct font_desc, width)); | ||
75 | DEFINE(FONT_DESC_HEIGHT, offsetof(struct font_desc, height)); | ||
76 | DEFINE(FONT_DESC_DATA, offsetof(struct font_desc, data)); | ||
77 | DEFINE(FONT_DESC_PREF, offsetof(struct font_desc, pref)); | ||
78 | |||
79 | /* signal defines */ | ||
80 | DEFINE(LSIGSEGV, SIGSEGV); | ||
81 | DEFINE(LSEGV_MAPERR, SEGV_MAPERR); | ||
82 | DEFINE(LSIGTRAP, SIGTRAP); | ||
83 | DEFINE(LTRAP_TRACE, TRAP_TRACE); | ||
84 | |||
85 | /* offsets into the custom struct */ | ||
86 | DEFINE(CUSTOMBASE, &amiga_custom); | ||
87 | DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar)); | ||
88 | DEFINE(C_INTREQR, offsetof(struct CUSTOM, intreqr)); | ||
89 | DEFINE(C_INTENA, offsetof(struct CUSTOM, intena)); | ||
90 | DEFINE(C_INTREQ, offsetof(struct CUSTOM, intreq)); | ||
91 | DEFINE(C_SERDATR, offsetof(struct CUSTOM, serdatr)); | ||
92 | DEFINE(C_SERDAT, offsetof(struct CUSTOM, serdat)); | ||
93 | DEFINE(C_SERPER, offsetof(struct CUSTOM, serper)); | ||
94 | DEFINE(CIAABASE, &ciaa); | ||
95 | DEFINE(CIABBASE, &ciab); | ||
96 | DEFINE(C_PRA, offsetof(struct CIA, pra)); | ||
97 | DEFINE(ZTWOBASE, zTwoBase); | ||
98 | |||
99 | return 0; | ||
100 | } | ||
diff --git a/arch/m68k/kernel/asm-offsets_mm.c b/arch/m68k/kernel/asm-offsets_mm.c new file mode 100644 index 000000000000..78e59b82ebc3 --- /dev/null +++ b/arch/m68k/kernel/asm-offsets_mm.c | |||
@@ -0,0 +1,100 @@ | |||
1 | /* | ||
2 | * This program is used to generate definitions needed by | ||
3 | * assembly language modules. | ||
4 | * | ||
5 | * We use the technique used in the OSF Mach kernel code: | ||
6 | * generate asm statements containing #defines, | ||
7 | * compile this file to assembler, and then extract the | ||
8 | * #defines from the assembly-language output. | ||
9 | */ | ||
10 | |||
11 | #define ASM_OFFSETS_C | ||
12 | |||
13 | #include <linux/stddef.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/kernel_stat.h> | ||
16 | #include <linux/kbuild.h> | ||
17 | #include <asm/bootinfo.h> | ||
18 | #include <asm/irq.h> | ||
19 | #include <asm/amigahw.h> | ||
20 | #include <linux/font.h> | ||
21 | |||
22 | int main(void) | ||
23 | { | ||
24 | /* offsets into the task struct */ | ||
25 | DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); | ||
26 | DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info)); | ||
27 | DEFINE(TASK_MM, offsetof(struct task_struct, mm)); | ||
28 | #ifdef CONFIG_MMU | ||
29 | DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info)); | ||
30 | #endif | ||
31 | |||
32 | /* offsets into the thread struct */ | ||
33 | DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp)); | ||
34 | DEFINE(THREAD_USP, offsetof(struct thread_struct, usp)); | ||
35 | DEFINE(THREAD_SR, offsetof(struct thread_struct, sr)); | ||
36 | DEFINE(THREAD_FS, offsetof(struct thread_struct, fs)); | ||
37 | DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp)); | ||
38 | DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0)); | ||
39 | DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp)); | ||
40 | DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl)); | ||
41 | DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate)); | ||
42 | |||
43 | /* offsets into the thread_info struct */ | ||
44 | DEFINE(TINFO_PREEMPT, offsetof(struct thread_info, preempt_count)); | ||
45 | DEFINE(TINFO_FLAGS, offsetof(struct thread_info, flags)); | ||
46 | |||
47 | /* offsets into the pt_regs */ | ||
48 | DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0)); | ||
49 | DEFINE(PT_OFF_ORIG_D0, offsetof(struct pt_regs, orig_d0)); | ||
50 | DEFINE(PT_OFF_D1, offsetof(struct pt_regs, d1)); | ||
51 | DEFINE(PT_OFF_D2, offsetof(struct pt_regs, d2)); | ||
52 | DEFINE(PT_OFF_D3, offsetof(struct pt_regs, d3)); | ||
53 | DEFINE(PT_OFF_D4, offsetof(struct pt_regs, d4)); | ||
54 | DEFINE(PT_OFF_D5, offsetof(struct pt_regs, d5)); | ||
55 | DEFINE(PT_OFF_A0, offsetof(struct pt_regs, a0)); | ||
56 | DEFINE(PT_OFF_A1, offsetof(struct pt_regs, a1)); | ||
57 | DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2)); | ||
58 | DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc)); | ||
59 | DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr)); | ||
60 | /* bitfields are a bit difficult */ | ||
61 | DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4); | ||
62 | |||
63 | /* offsets into the irq_cpustat_t struct */ | ||
64 | DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); | ||
65 | |||
66 | /* offsets into the bi_record struct */ | ||
67 | DEFINE(BIR_TAG, offsetof(struct bi_record, tag)); | ||
68 | DEFINE(BIR_SIZE, offsetof(struct bi_record, size)); | ||
69 | DEFINE(BIR_DATA, offsetof(struct bi_record, data)); | ||
70 | |||
71 | /* offsets into font_desc (drivers/video/console/font.h) */ | ||
72 | DEFINE(FONT_DESC_IDX, offsetof(struct font_desc, idx)); | ||
73 | DEFINE(FONT_DESC_NAME, offsetof(struct font_desc, name)); | ||
74 | DEFINE(FONT_DESC_WIDTH, offsetof(struct font_desc, width)); | ||
75 | DEFINE(FONT_DESC_HEIGHT, offsetof(struct font_desc, height)); | ||
76 | DEFINE(FONT_DESC_DATA, offsetof(struct font_desc, data)); | ||
77 | DEFINE(FONT_DESC_PREF, offsetof(struct font_desc, pref)); | ||
78 | |||
79 | /* signal defines */ | ||
80 | DEFINE(LSIGSEGV, SIGSEGV); | ||
81 | DEFINE(LSEGV_MAPERR, SEGV_MAPERR); | ||
82 | DEFINE(LSIGTRAP, SIGTRAP); | ||
83 | DEFINE(LTRAP_TRACE, TRAP_TRACE); | ||
84 | |||
85 | /* offsets into the custom struct */ | ||
86 | DEFINE(CUSTOMBASE, &amiga_custom); | ||
87 | DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar)); | ||
88 | DEFINE(C_INTREQR, offsetof(struct CUSTOM, intreqr)); | ||
89 | DEFINE(C_INTENA, offsetof(struct CUSTOM, intena)); | ||
90 | DEFINE(C_INTREQ, offsetof(struct CUSTOM, intreq)); | ||
91 | DEFINE(C_SERDATR, offsetof(struct CUSTOM, serdatr)); | ||
92 | DEFINE(C_SERDAT, offsetof(struct CUSTOM, serdat)); | ||
93 | DEFINE(C_SERPER, offsetof(struct CUSTOM, serper)); | ||
94 | DEFINE(CIAABASE, &ciaa); | ||
95 | DEFINE(CIABBASE, &ciab); | ||
96 | DEFINE(C_PRA, offsetof(struct CIA, pra)); | ||
97 | DEFINE(ZTWOBASE, zTwoBase); | ||
98 | |||
99 | return 0; | ||
100 | } | ||
diff --git a/arch/m68knommu/kernel/asm-offsets.c b/arch/m68k/kernel/asm-offsets_no.c index ffe02f41ad46..ffe02f41ad46 100644 --- a/arch/m68knommu/kernel/asm-offsets.c +++ b/arch/m68k/kernel/asm-offsets_no.c | |||
diff --git a/arch/m68k/kernel/dma.c b/arch/m68k/kernel/dma.c index 4bbb3c2a8880..90e8cb726c8c 100644 --- a/arch/m68k/kernel/dma.c +++ b/arch/m68k/kernel/dma.c | |||
@@ -1,130 +1,5 @@ | |||
1 | /* | 1 | #ifdef CONFIG_MMU |
2 | * This file is subject to the terms and conditions of the GNU General Public | 2 | #include "dma_mm.c" |
3 | * License. See the file COPYING in the main directory of this archive | 3 | #else |
4 | * for more details. | 4 | #include "dma_no.c" |
5 | */ | 5 | #endif |
6 | |||
7 | #undef DEBUG | ||
8 | |||
9 | #include <linux/dma-mapping.h> | ||
10 | #include <linux/device.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/scatterlist.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/vmalloc.h> | ||
15 | |||
16 | #include <asm/pgalloc.h> | ||
17 | |||
18 | void *dma_alloc_coherent(struct device *dev, size_t size, | ||
19 | dma_addr_t *handle, gfp_t flag) | ||
20 | { | ||
21 | struct page *page, **map; | ||
22 | pgprot_t pgprot; | ||
23 | void *addr; | ||
24 | int i, order; | ||
25 | |||
26 | pr_debug("dma_alloc_coherent: %d,%x\n", size, flag); | ||
27 | |||
28 | size = PAGE_ALIGN(size); | ||
29 | order = get_order(size); | ||
30 | |||
31 | page = alloc_pages(flag, order); | ||
32 | if (!page) | ||
33 | return NULL; | ||
34 | |||
35 | *handle = page_to_phys(page); | ||
36 | map = kmalloc(sizeof(struct page *) << order, flag & ~__GFP_DMA); | ||
37 | if (!map) { | ||
38 | __free_pages(page, order); | ||
39 | return NULL; | ||
40 | } | ||
41 | split_page(page, order); | ||
42 | |||
43 | order = 1 << order; | ||
44 | size >>= PAGE_SHIFT; | ||
45 | map[0] = page; | ||
46 | for (i = 1; i < size; i++) | ||
47 | map[i] = page + i; | ||
48 | for (; i < order; i++) | ||
49 | __free_page(page + i); | ||
50 | pgprot = __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY); | ||
51 | if (CPU_IS_040_OR_060) | ||
52 | pgprot_val(pgprot) |= _PAGE_GLOBAL040 | _PAGE_NOCACHE_S; | ||
53 | else | ||
54 | pgprot_val(pgprot) |= _PAGE_NOCACHE030; | ||
55 | addr = vmap(map, size, VM_MAP, pgprot); | ||
56 | kfree(map); | ||
57 | |||
58 | return addr; | ||
59 | } | ||
60 | EXPORT_SYMBOL(dma_alloc_coherent); | ||
61 | |||
62 | void dma_free_coherent(struct device *dev, size_t size, | ||
63 | void *addr, dma_addr_t handle) | ||
64 | { | ||
65 | pr_debug("dma_free_coherent: %p, %x\n", addr, handle); | ||
66 | vfree(addr); | ||
67 | } | ||
68 | EXPORT_SYMBOL(dma_free_coherent); | ||
69 | |||
70 | void dma_sync_single_for_device(struct device *dev, dma_addr_t handle, | ||
71 | size_t size, enum dma_data_direction dir) | ||
72 | { | ||
73 | switch (dir) { | ||
74 | case DMA_TO_DEVICE: | ||
75 | cache_push(handle, size); | ||
76 | break; | ||
77 | case DMA_FROM_DEVICE: | ||
78 | cache_clear(handle, size); | ||
79 | break; | ||
80 | default: | ||
81 | if (printk_ratelimit()) | ||
82 | printk("dma_sync_single_for_device: unsupported dir %u\n", dir); | ||
83 | break; | ||
84 | } | ||
85 | } | ||
86 | EXPORT_SYMBOL(dma_sync_single_for_device); | ||
87 | |||
88 | void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents, | ||
89 | enum dma_data_direction dir) | ||
90 | { | ||
91 | int i; | ||
92 | |||
93 | for (i = 0; i < nents; sg++, i++) | ||
94 | dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir); | ||
95 | } | ||
96 | EXPORT_SYMBOL(dma_sync_sg_for_device); | ||
97 | |||
98 | dma_addr_t dma_map_single(struct device *dev, void *addr, size_t size, | ||
99 | enum dma_data_direction dir) | ||
100 | { | ||
101 | dma_addr_t handle = virt_to_bus(addr); | ||
102 | |||
103 | dma_sync_single_for_device(dev, handle, size, dir); | ||
104 | return handle; | ||
105 | } | ||
106 | EXPORT_SYMBOL(dma_map_single); | ||
107 | |||
108 | dma_addr_t dma_map_page(struct device *dev, struct page *page, | ||
109 | unsigned long offset, size_t size, | ||
110 | enum dma_data_direction dir) | ||
111 | { | ||
112 | dma_addr_t handle = page_to_phys(page) + offset; | ||
113 | |||
114 | dma_sync_single_for_device(dev, handle, size, dir); | ||
115 | return handle; | ||
116 | } | ||
117 | EXPORT_SYMBOL(dma_map_page); | ||
118 | |||
119 | int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, | ||
120 | enum dma_data_direction dir) | ||
121 | { | ||
122 | int i; | ||
123 | |||
124 | for (i = 0; i < nents; sg++, i++) { | ||
125 | sg->dma_address = sg_phys(sg); | ||
126 | dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir); | ||
127 | } | ||
128 | return nents; | ||
129 | } | ||
130 | EXPORT_SYMBOL(dma_map_sg); | ||
diff --git a/arch/m68k/kernel/dma_mm.c b/arch/m68k/kernel/dma_mm.c new file mode 100644 index 000000000000..4bbb3c2a8880 --- /dev/null +++ b/arch/m68k/kernel/dma_mm.c | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file COPYING in the main directory of this archive | ||
4 | * for more details. | ||
5 | */ | ||
6 | |||
7 | #undef DEBUG | ||
8 | |||
9 | #include <linux/dma-mapping.h> | ||
10 | #include <linux/device.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/scatterlist.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/vmalloc.h> | ||
15 | |||
16 | #include <asm/pgalloc.h> | ||
17 | |||
18 | void *dma_alloc_coherent(struct device *dev, size_t size, | ||
19 | dma_addr_t *handle, gfp_t flag) | ||
20 | { | ||
21 | struct page *page, **map; | ||
22 | pgprot_t pgprot; | ||
23 | void *addr; | ||
24 | int i, order; | ||
25 | |||
26 | pr_debug("dma_alloc_coherent: %d,%x\n", size, flag); | ||
27 | |||
28 | size = PAGE_ALIGN(size); | ||
29 | order = get_order(size); | ||
30 | |||
31 | page = alloc_pages(flag, order); | ||
32 | if (!page) | ||
33 | return NULL; | ||
34 | |||
35 | *handle = page_to_phys(page); | ||
36 | map = kmalloc(sizeof(struct page *) << order, flag & ~__GFP_DMA); | ||
37 | if (!map) { | ||
38 | __free_pages(page, order); | ||
39 | return NULL; | ||
40 | } | ||
41 | split_page(page, order); | ||
42 | |||
43 | order = 1 << order; | ||
44 | size >>= PAGE_SHIFT; | ||
45 | map[0] = page; | ||
46 | for (i = 1; i < size; i++) | ||
47 | map[i] = page + i; | ||
48 | for (; i < order; i++) | ||
49 | __free_page(page + i); | ||
50 | pgprot = __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY); | ||
51 | if (CPU_IS_040_OR_060) | ||
52 | pgprot_val(pgprot) |= _PAGE_GLOBAL040 | _PAGE_NOCACHE_S; | ||
53 | else | ||
54 | pgprot_val(pgprot) |= _PAGE_NOCACHE030; | ||
55 | addr = vmap(map, size, VM_MAP, pgprot); | ||
56 | kfree(map); | ||
57 | |||
58 | return addr; | ||
59 | } | ||
60 | EXPORT_SYMBOL(dma_alloc_coherent); | ||
61 | |||
62 | void dma_free_coherent(struct device *dev, size_t size, | ||
63 | void *addr, dma_addr_t handle) | ||
64 | { | ||
65 | pr_debug("dma_free_coherent: %p, %x\n", addr, handle); | ||
66 | vfree(addr); | ||
67 | } | ||
68 | EXPORT_SYMBOL(dma_free_coherent); | ||
69 | |||
70 | void dma_sync_single_for_device(struct device *dev, dma_addr_t handle, | ||
71 | size_t size, enum dma_data_direction dir) | ||
72 | { | ||
73 | switch (dir) { | ||
74 | case DMA_TO_DEVICE: | ||
75 | cache_push(handle, size); | ||
76 | break; | ||
77 | case DMA_FROM_DEVICE: | ||
78 | cache_clear(handle, size); | ||
79 | break; | ||
80 | default: | ||
81 | if (printk_ratelimit()) | ||
82 | printk("dma_sync_single_for_device: unsupported dir %u\n", dir); | ||
83 | break; | ||
84 | } | ||
85 | } | ||
86 | EXPORT_SYMBOL(dma_sync_single_for_device); | ||
87 | |||
88 | void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents, | ||
89 | enum dma_data_direction dir) | ||
90 | { | ||
91 | int i; | ||
92 | |||
93 | for (i = 0; i < nents; sg++, i++) | ||
94 | dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir); | ||
95 | } | ||
96 | EXPORT_SYMBOL(dma_sync_sg_for_device); | ||
97 | |||
98 | dma_addr_t dma_map_single(struct device *dev, void *addr, size_t size, | ||
99 | enum dma_data_direction dir) | ||
100 | { | ||
101 | dma_addr_t handle = virt_to_bus(addr); | ||
102 | |||
103 | dma_sync_single_for_device(dev, handle, size, dir); | ||
104 | return handle; | ||
105 | } | ||
106 | EXPORT_SYMBOL(dma_map_single); | ||
107 | |||
108 | dma_addr_t dma_map_page(struct device *dev, struct page *page, | ||
109 | unsigned long offset, size_t size, | ||
110 | enum dma_data_direction dir) | ||
111 | { | ||
112 | dma_addr_t handle = page_to_phys(page) + offset; | ||
113 | |||
114 | dma_sync_single_for_device(dev, handle, size, dir); | ||
115 | return handle; | ||
116 | } | ||
117 | EXPORT_SYMBOL(dma_map_page); | ||
118 | |||
119 | int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, | ||
120 | enum dma_data_direction dir) | ||
121 | { | ||
122 | int i; | ||
123 | |||
124 | for (i = 0; i < nents; sg++, i++) { | ||
125 | sg->dma_address = sg_phys(sg); | ||
126 | dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir); | ||
127 | } | ||
128 | return nents; | ||
129 | } | ||
130 | EXPORT_SYMBOL(dma_map_sg); | ||
diff --git a/arch/m68knommu/kernel/dma.c b/arch/m68k/kernel/dma_no.c index fc61541aeb71..fc61541aeb71 100644 --- a/arch/m68knommu/kernel/dma.c +++ b/arch/m68k/kernel/dma_no.c | |||
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 1559dea36e55..081cf96f243b 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S | |||
@@ -1,753 +1,5 @@ | |||
1 | /* -*- mode: asm -*- | 1 | #ifdef CONFIG_MMU |
2 | * | 2 | #include "entry_mm.S" |
3 | * linux/arch/m68k/kernel/entry.S | 3 | #else |
4 | * | 4 | #include "entry_no.S" |
5 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file README.legal in the main directory of this archive | ||
9 | * for more details. | ||
10 | * | ||
11 | * Linux/m68k support by Hamish Macdonald | ||
12 | * | ||
13 | * 68060 fixes by Jesper Skov | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * entry.S contains the system-call and fault low-level handling routines. | ||
19 | * This also contains the timer-interrupt handler, as well as all interrupts | ||
20 | * and faults that can result in a task-switch. | ||
21 | * | ||
22 | * NOTE: This code handles signal-recognition, which happens every time | ||
23 | * after a timer-interrupt and after each system call. | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | /* | ||
28 | * 12/03/96 Jes: Currently we only support m68k single-cpu systems, so | ||
29 | * all pointers that used to be 'current' are now entry | ||
30 | * number 0 in the 'current_set' list. | ||
31 | * | ||
32 | * 6/05/00 RZ: addedd writeback completion after return from sighandler | ||
33 | * for 68040 | ||
34 | */ | ||
35 | |||
36 | #include <linux/linkage.h> | ||
37 | #include <asm/entry.h> | ||
38 | #include <asm/errno.h> | ||
39 | #include <asm/setup.h> | ||
40 | #include <asm/segment.h> | ||
41 | #include <asm/traps.h> | ||
42 | #include <asm/unistd.h> | ||
43 | |||
44 | #include <asm/asm-offsets.h> | ||
45 | |||
46 | .globl system_call, buserr, trap, resume | ||
47 | .globl sys_call_table | ||
48 | .globl sys_fork, sys_clone, sys_vfork | ||
49 | .globl ret_from_interrupt, bad_interrupt | ||
50 | .globl auto_irqhandler_fixup | ||
51 | .globl user_irqvec_fixup, user_irqhandler_fixup | ||
52 | |||
53 | .text | ||
54 | ENTRY(buserr) | ||
55 | SAVE_ALL_INT | ||
56 | GET_CURRENT(%d0) | ||
57 | movel %sp,%sp@- | stack frame pointer argument | ||
58 | bsrl buserr_c | ||
59 | addql #4,%sp | ||
60 | jra .Lret_from_exception | ||
61 | |||
62 | ENTRY(trap) | ||
63 | SAVE_ALL_INT | ||
64 | GET_CURRENT(%d0) | ||
65 | movel %sp,%sp@- | stack frame pointer argument | ||
66 | bsrl trap_c | ||
67 | addql #4,%sp | ||
68 | jra .Lret_from_exception | ||
69 | |||
70 | | After a fork we jump here directly from resume, | ||
71 | | so that %d1 contains the previous task | ||
72 | | schedule_tail now used regardless of CONFIG_SMP | ||
73 | ENTRY(ret_from_fork) | ||
74 | movel %d1,%sp@- | ||
75 | jsr schedule_tail | ||
76 | addql #4,%sp | ||
77 | jra .Lret_from_exception | ||
78 | |||
79 | do_trace_entry: | ||
80 | movel #-ENOSYS,%sp@(PT_OFF_D0)| needed for strace | ||
81 | subql #4,%sp | ||
82 | SAVE_SWITCH_STACK | ||
83 | jbsr syscall_trace | ||
84 | RESTORE_SWITCH_STACK | ||
85 | addql #4,%sp | ||
86 | movel %sp@(PT_OFF_ORIG_D0),%d0 | ||
87 | cmpl #NR_syscalls,%d0 | ||
88 | jcs syscall | ||
89 | badsys: | ||
90 | movel #-ENOSYS,%sp@(PT_OFF_D0) | ||
91 | jra ret_from_syscall | ||
92 | |||
93 | do_trace_exit: | ||
94 | subql #4,%sp | ||
95 | SAVE_SWITCH_STACK | ||
96 | jbsr syscall_trace | ||
97 | RESTORE_SWITCH_STACK | ||
98 | addql #4,%sp | ||
99 | jra .Lret_from_exception | ||
100 | |||
101 | ENTRY(ret_from_signal) | ||
102 | tstb %curptr@(TASK_INFO+TINFO_FLAGS+2) | ||
103 | jge 1f | ||
104 | jbsr syscall_trace | ||
105 | 1: RESTORE_SWITCH_STACK | ||
106 | addql #4,%sp | ||
107 | /* on 68040 complete pending writebacks if any */ | ||
108 | #ifdef CONFIG_M68040 | ||
109 | bfextu %sp@(PT_OFF_FORMATVEC){#0,#4},%d0 | ||
110 | subql #7,%d0 | bus error frame ? | ||
111 | jbne 1f | ||
112 | movel %sp,%sp@- | ||
113 | jbsr berr_040cleanup | ||
114 | addql #4,%sp | ||
115 | 1: | ||
116 | #endif | 5 | #endif |
117 | jra .Lret_from_exception | ||
118 | |||
119 | ENTRY(system_call) | ||
120 | SAVE_ALL_SYS | ||
121 | |||
122 | GET_CURRENT(%d1) | ||
123 | | save top of frame | ||
124 | movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0) | ||
125 | |||
126 | | syscall trace? | ||
127 | tstb %curptr@(TASK_INFO+TINFO_FLAGS+2) | ||
128 | jmi do_trace_entry | ||
129 | cmpl #NR_syscalls,%d0 | ||
130 | jcc badsys | ||
131 | syscall: | ||
132 | jbsr @(sys_call_table,%d0:l:4)@(0) | ||
133 | movel %d0,%sp@(PT_OFF_D0) | save the return value | ||
134 | ret_from_syscall: | ||
135 | |oriw #0x0700,%sr | ||
136 | movew %curptr@(TASK_INFO+TINFO_FLAGS+2),%d0 | ||
137 | jne syscall_exit_work | ||
138 | 1: RESTORE_ALL | ||
139 | |||
140 | syscall_exit_work: | ||
141 | btst #5,%sp@(PT_OFF_SR) | check if returning to kernel | ||
142 | bnes 1b | if so, skip resched, signals | ||
143 | lslw #1,%d0 | ||
144 | jcs do_trace_exit | ||
145 | jmi do_delayed_trace | ||
146 | lslw #8,%d0 | ||
147 | jmi do_signal_return | ||
148 | pea resume_userspace | ||
149 | jra schedule | ||
150 | |||
151 | |||
152 | ENTRY(ret_from_exception) | ||
153 | .Lret_from_exception: | ||
154 | btst #5,%sp@(PT_OFF_SR) | check if returning to kernel | ||
155 | bnes 1f | if so, skip resched, signals | ||
156 | | only allow interrupts when we are really the last one on the | ||
157 | | kernel stack, otherwise stack overflow can occur during | ||
158 | | heavy interrupt load | ||
159 | andw #ALLOWINT,%sr | ||
160 | |||
161 | resume_userspace: | ||
162 | moveb %curptr@(TASK_INFO+TINFO_FLAGS+3),%d0 | ||
163 | jne exit_work | ||
164 | 1: RESTORE_ALL | ||
165 | |||
166 | exit_work: | ||
167 | | save top of frame | ||
168 | movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0) | ||
169 | lslb #1,%d0 | ||
170 | jmi do_signal_return | ||
171 | pea resume_userspace | ||
172 | jra schedule | ||
173 | |||
174 | |||
175 | do_signal_return: | ||
176 | |andw #ALLOWINT,%sr | ||
177 | subql #4,%sp | dummy return address | ||
178 | SAVE_SWITCH_STACK | ||
179 | pea %sp@(SWITCH_STACK_SIZE) | ||
180 | bsrl do_signal | ||
181 | addql #4,%sp | ||
182 | RESTORE_SWITCH_STACK | ||
183 | addql #4,%sp | ||
184 | jbra resume_userspace | ||
185 | |||
186 | do_delayed_trace: | ||
187 | bclr #7,%sp@(PT_OFF_SR) | clear trace bit in SR | ||
188 | pea 1 | send SIGTRAP | ||
189 | movel %curptr,%sp@- | ||
190 | pea LSIGTRAP | ||
191 | jbsr send_sig | ||
192 | addql #8,%sp | ||
193 | addql #4,%sp | ||
194 | jbra resume_userspace | ||
195 | |||
196 | |||
197 | /* This is the main interrupt handler for autovector interrupts */ | ||
198 | |||
199 | ENTRY(auto_inthandler) | ||
200 | SAVE_ALL_INT | ||
201 | GET_CURRENT(%d0) | ||
202 | addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) | ||
203 | | put exception # in d0 | ||
204 | bfextu %sp@(PT_OFF_FORMATVEC){#4,#10},%d0 | ||
205 | subw #VEC_SPUR,%d0 | ||
206 | |||
207 | movel %sp,%sp@- | ||
208 | movel %d0,%sp@- | put vector # on stack | ||
209 | auto_irqhandler_fixup = . + 2 | ||
210 | jsr __m68k_handle_int | process the IRQ | ||
211 | addql #8,%sp | pop parameters off stack | ||
212 | |||
213 | ret_from_interrupt: | ||
214 | subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) | ||
215 | jeq ret_from_last_interrupt | ||
216 | 2: RESTORE_ALL | ||
217 | |||
218 | ALIGN | ||
219 | ret_from_last_interrupt: | ||
220 | moveq #(~ALLOWINT>>8)&0xff,%d0 | ||
221 | andb %sp@(PT_OFF_SR),%d0 | ||
222 | jne 2b | ||
223 | |||
224 | /* check if we need to do software interrupts */ | ||
225 | tstl irq_stat+CPUSTAT_SOFTIRQ_PENDING | ||
226 | jeq .Lret_from_exception | ||
227 | pea ret_from_exception | ||
228 | jra do_softirq | ||
229 | |||
230 | /* Handler for user defined interrupt vectors */ | ||
231 | |||
232 | ENTRY(user_inthandler) | ||
233 | SAVE_ALL_INT | ||
234 | GET_CURRENT(%d0) | ||
235 | addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) | ||
236 | | put exception # in d0 | ||
237 | bfextu %sp@(PT_OFF_FORMATVEC){#4,#10},%d0 | ||
238 | user_irqvec_fixup = . + 2 | ||
239 | subw #VEC_USER,%d0 | ||
240 | |||
241 | movel %sp,%sp@- | ||
242 | movel %d0,%sp@- | put vector # on stack | ||
243 | user_irqhandler_fixup = . + 2 | ||
244 | jsr __m68k_handle_int | process the IRQ | ||
245 | addql #8,%sp | pop parameters off stack | ||
246 | |||
247 | subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) | ||
248 | jeq ret_from_last_interrupt | ||
249 | RESTORE_ALL | ||
250 | |||
251 | /* Handler for uninitialized and spurious interrupts */ | ||
252 | |||
253 | ENTRY(bad_inthandler) | ||
254 | SAVE_ALL_INT | ||
255 | GET_CURRENT(%d0) | ||
256 | addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) | ||
257 | |||
258 | movel %sp,%sp@- | ||
259 | jsr handle_badint | ||
260 | addql #4,%sp | ||
261 | |||
262 | subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) | ||
263 | jeq ret_from_last_interrupt | ||
264 | RESTORE_ALL | ||
265 | |||
266 | |||
267 | ENTRY(sys_fork) | ||
268 | SAVE_SWITCH_STACK | ||
269 | pea %sp@(SWITCH_STACK_SIZE) | ||
270 | jbsr m68k_fork | ||
271 | addql #4,%sp | ||
272 | RESTORE_SWITCH_STACK | ||
273 | rts | ||
274 | |||
275 | ENTRY(sys_clone) | ||
276 | SAVE_SWITCH_STACK | ||
277 | pea %sp@(SWITCH_STACK_SIZE) | ||
278 | jbsr m68k_clone | ||
279 | addql #4,%sp | ||
280 | RESTORE_SWITCH_STACK | ||
281 | rts | ||
282 | |||
283 | ENTRY(sys_vfork) | ||
284 | SAVE_SWITCH_STACK | ||
285 | pea %sp@(SWITCH_STACK_SIZE) | ||
286 | jbsr m68k_vfork | ||
287 | addql #4,%sp | ||
288 | RESTORE_SWITCH_STACK | ||
289 | rts | ||
290 | |||
291 | ENTRY(sys_sigreturn) | ||
292 | SAVE_SWITCH_STACK | ||
293 | jbsr do_sigreturn | ||
294 | RESTORE_SWITCH_STACK | ||
295 | rts | ||
296 | |||
297 | ENTRY(sys_rt_sigreturn) | ||
298 | SAVE_SWITCH_STACK | ||
299 | jbsr do_rt_sigreturn | ||
300 | RESTORE_SWITCH_STACK | ||
301 | rts | ||
302 | |||
303 | resume: | ||
304 | /* | ||
305 | * Beware - when entering resume, prev (the current task) is | ||
306 | * in a0, next (the new task) is in a1,so don't change these | ||
307 | * registers until their contents are no longer needed. | ||
308 | */ | ||
309 | |||
310 | /* save sr */ | ||
311 | movew %sr,%a0@(TASK_THREAD+THREAD_SR) | ||
312 | |||
313 | /* save fs (sfc,%dfc) (may be pointing to kernel memory) */ | ||
314 | movec %sfc,%d0 | ||
315 | movew %d0,%a0@(TASK_THREAD+THREAD_FS) | ||
316 | |||
317 | /* save usp */ | ||
318 | /* it is better to use a movel here instead of a movew 8*) */ | ||
319 | movec %usp,%d0 | ||
320 | movel %d0,%a0@(TASK_THREAD+THREAD_USP) | ||
321 | |||
322 | /* save non-scratch registers on stack */ | ||
323 | SAVE_SWITCH_STACK | ||
324 | |||
325 | /* save current kernel stack pointer */ | ||
326 | movel %sp,%a0@(TASK_THREAD+THREAD_KSP) | ||
327 | |||
328 | /* save floating point context */ | ||
329 | #ifndef CONFIG_M68KFPU_EMU_ONLY | ||
330 | #ifdef CONFIG_M68KFPU_EMU | ||
331 | tstl m68k_fputype | ||
332 | jeq 3f | ||
333 | #endif | ||
334 | fsave %a0@(TASK_THREAD+THREAD_FPSTATE) | ||
335 | |||
336 | #if defined(CONFIG_M68060) | ||
337 | #if !defined(CPU_M68060_ONLY) | ||
338 | btst #3,m68k_cputype+3 | ||
339 | beqs 1f | ||
340 | #endif | ||
341 | /* The 060 FPU keeps status in bits 15-8 of the first longword */ | ||
342 | tstb %a0@(TASK_THREAD+THREAD_FPSTATE+2) | ||
343 | jeq 3f | ||
344 | #if !defined(CPU_M68060_ONLY) | ||
345 | jra 2f | ||
346 | #endif | ||
347 | #endif /* CONFIG_M68060 */ | ||
348 | #if !defined(CPU_M68060_ONLY) | ||
349 | 1: tstb %a0@(TASK_THREAD+THREAD_FPSTATE) | ||
350 | jeq 3f | ||
351 | #endif | ||
352 | 2: fmovemx %fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG) | ||
353 | fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_THREAD+THREAD_FPCNTL) | ||
354 | 3: | ||
355 | #endif /* CONFIG_M68KFPU_EMU_ONLY */ | ||
356 | /* Return previous task in %d1 */ | ||
357 | movel %curptr,%d1 | ||
358 | |||
359 | /* switch to new task (a1 contains new task) */ | ||
360 | movel %a1,%curptr | ||
361 | |||
362 | /* restore floating point context */ | ||
363 | #ifndef CONFIG_M68KFPU_EMU_ONLY | ||
364 | #ifdef CONFIG_M68KFPU_EMU | ||
365 | tstl m68k_fputype | ||
366 | jeq 4f | ||
367 | #endif | ||
368 | #if defined(CONFIG_M68060) | ||
369 | #if !defined(CPU_M68060_ONLY) | ||
370 | btst #3,m68k_cputype+3 | ||
371 | beqs 1f | ||
372 | #endif | ||
373 | /* The 060 FPU keeps status in bits 15-8 of the first longword */ | ||
374 | tstb %a1@(TASK_THREAD+THREAD_FPSTATE+2) | ||
375 | jeq 3f | ||
376 | #if !defined(CPU_M68060_ONLY) | ||
377 | jra 2f | ||
378 | #endif | ||
379 | #endif /* CONFIG_M68060 */ | ||
380 | #if !defined(CPU_M68060_ONLY) | ||
381 | 1: tstb %a1@(TASK_THREAD+THREAD_FPSTATE) | ||
382 | jeq 3f | ||
383 | #endif | ||
384 | 2: fmovemx %a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7 | ||
385 | fmoveml %a1@(TASK_THREAD+THREAD_FPCNTL),%fpcr/%fpsr/%fpiar | ||
386 | 3: frestore %a1@(TASK_THREAD+THREAD_FPSTATE) | ||
387 | 4: | ||
388 | #endif /* CONFIG_M68KFPU_EMU_ONLY */ | ||
389 | |||
390 | /* restore the kernel stack pointer */ | ||
391 | movel %a1@(TASK_THREAD+THREAD_KSP),%sp | ||
392 | |||
393 | /* restore non-scratch registers */ | ||
394 | RESTORE_SWITCH_STACK | ||
395 | |||
396 | /* restore user stack pointer */ | ||
397 | movel %a1@(TASK_THREAD+THREAD_USP),%a0 | ||
398 | movel %a0,%usp | ||
399 | |||
400 | /* restore fs (sfc,%dfc) */ | ||
401 | movew %a1@(TASK_THREAD+THREAD_FS),%a0 | ||
402 | movec %a0,%sfc | ||
403 | movec %a0,%dfc | ||
404 | |||
405 | /* restore status register */ | ||
406 | movew %a1@(TASK_THREAD+THREAD_SR),%sr | ||
407 | |||
408 | rts | ||
409 | |||
410 | .data | ||
411 | ALIGN | ||
412 | sys_call_table: | ||
413 | .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ | ||
414 | .long sys_exit | ||
415 | .long sys_fork | ||
416 | .long sys_read | ||
417 | .long sys_write | ||
418 | .long sys_open /* 5 */ | ||
419 | .long sys_close | ||
420 | .long sys_waitpid | ||
421 | .long sys_creat | ||
422 | .long sys_link | ||
423 | .long sys_unlink /* 10 */ | ||
424 | .long sys_execve | ||
425 | .long sys_chdir | ||
426 | .long sys_time | ||
427 | .long sys_mknod | ||
428 | .long sys_chmod /* 15 */ | ||
429 | .long sys_chown16 | ||
430 | .long sys_ni_syscall /* old break syscall holder */ | ||
431 | .long sys_stat | ||
432 | .long sys_lseek | ||
433 | .long sys_getpid /* 20 */ | ||
434 | .long sys_mount | ||
435 | .long sys_oldumount | ||
436 | .long sys_setuid16 | ||
437 | .long sys_getuid16 | ||
438 | .long sys_stime /* 25 */ | ||
439 | .long sys_ptrace | ||
440 | .long sys_alarm | ||
441 | .long sys_fstat | ||
442 | .long sys_pause | ||
443 | .long sys_utime /* 30 */ | ||
444 | .long sys_ni_syscall /* old stty syscall holder */ | ||
445 | .long sys_ni_syscall /* old gtty syscall holder */ | ||
446 | .long sys_access | ||
447 | .long sys_nice | ||
448 | .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ | ||
449 | .long sys_sync | ||
450 | .long sys_kill | ||
451 | .long sys_rename | ||
452 | .long sys_mkdir | ||
453 | .long sys_rmdir /* 40 */ | ||
454 | .long sys_dup | ||
455 | .long sys_pipe | ||
456 | .long sys_times | ||
457 | .long sys_ni_syscall /* old prof syscall holder */ | ||
458 | .long sys_brk /* 45 */ | ||
459 | .long sys_setgid16 | ||
460 | .long sys_getgid16 | ||
461 | .long sys_signal | ||
462 | .long sys_geteuid16 | ||
463 | .long sys_getegid16 /* 50 */ | ||
464 | .long sys_acct | ||
465 | .long sys_umount /* recycled never used phys() */ | ||
466 | .long sys_ni_syscall /* old lock syscall holder */ | ||
467 | .long sys_ioctl | ||
468 | .long sys_fcntl /* 55 */ | ||
469 | .long sys_ni_syscall /* old mpx syscall holder */ | ||
470 | .long sys_setpgid | ||
471 | .long sys_ni_syscall /* old ulimit syscall holder */ | ||
472 | .long sys_ni_syscall | ||
473 | .long sys_umask /* 60 */ | ||
474 | .long sys_chroot | ||
475 | .long sys_ustat | ||
476 | .long sys_dup2 | ||
477 | .long sys_getppid | ||
478 | .long sys_getpgrp /* 65 */ | ||
479 | .long sys_setsid | ||
480 | .long sys_sigaction | ||
481 | .long sys_sgetmask | ||
482 | .long sys_ssetmask | ||
483 | .long sys_setreuid16 /* 70 */ | ||
484 | .long sys_setregid16 | ||
485 | .long sys_sigsuspend | ||
486 | .long sys_sigpending | ||
487 | .long sys_sethostname | ||
488 | .long sys_setrlimit /* 75 */ | ||
489 | .long sys_old_getrlimit | ||
490 | .long sys_getrusage | ||
491 | .long sys_gettimeofday | ||
492 | .long sys_settimeofday | ||
493 | .long sys_getgroups16 /* 80 */ | ||
494 | .long sys_setgroups16 | ||
495 | .long sys_old_select | ||
496 | .long sys_symlink | ||
497 | .long sys_lstat | ||
498 | .long sys_readlink /* 85 */ | ||
499 | .long sys_uselib | ||
500 | .long sys_swapon | ||
501 | .long sys_reboot | ||
502 | .long sys_old_readdir | ||
503 | .long sys_old_mmap /* 90 */ | ||
504 | .long sys_munmap | ||
505 | .long sys_truncate | ||
506 | .long sys_ftruncate | ||
507 | .long sys_fchmod | ||
508 | .long sys_fchown16 /* 95 */ | ||
509 | .long sys_getpriority | ||
510 | .long sys_setpriority | ||
511 | .long sys_ni_syscall /* old profil syscall holder */ | ||
512 | .long sys_statfs | ||
513 | .long sys_fstatfs /* 100 */ | ||
514 | .long sys_ni_syscall /* ioperm for i386 */ | ||
515 | .long sys_socketcall | ||
516 | .long sys_syslog | ||
517 | .long sys_setitimer | ||
518 | .long sys_getitimer /* 105 */ | ||
519 | .long sys_newstat | ||
520 | .long sys_newlstat | ||
521 | .long sys_newfstat | ||
522 | .long sys_ni_syscall | ||
523 | .long sys_ni_syscall /* 110 */ /* iopl for i386 */ | ||
524 | .long sys_vhangup | ||
525 | .long sys_ni_syscall /* obsolete idle() syscall */ | ||
526 | .long sys_ni_syscall /* vm86old for i386 */ | ||
527 | .long sys_wait4 | ||
528 | .long sys_swapoff /* 115 */ | ||
529 | .long sys_sysinfo | ||
530 | .long sys_ipc | ||
531 | .long sys_fsync | ||
532 | .long sys_sigreturn | ||
533 | .long sys_clone /* 120 */ | ||
534 | .long sys_setdomainname | ||
535 | .long sys_newuname | ||
536 | .long sys_cacheflush /* modify_ldt for i386 */ | ||
537 | .long sys_adjtimex | ||
538 | .long sys_mprotect /* 125 */ | ||
539 | .long sys_sigprocmask | ||
540 | .long sys_ni_syscall /* old "create_module" */ | ||
541 | .long sys_init_module | ||
542 | .long sys_delete_module | ||
543 | .long sys_ni_syscall /* 130 - old "get_kernel_syms" */ | ||
544 | .long sys_quotactl | ||
545 | .long sys_getpgid | ||
546 | .long sys_fchdir | ||
547 | .long sys_bdflush | ||
548 | .long sys_sysfs /* 135 */ | ||
549 | .long sys_personality | ||
550 | .long sys_ni_syscall /* for afs_syscall */ | ||
551 | .long sys_setfsuid16 | ||
552 | .long sys_setfsgid16 | ||
553 | .long sys_llseek /* 140 */ | ||
554 | .long sys_getdents | ||
555 | .long sys_select | ||
556 | .long sys_flock | ||
557 | .long sys_msync | ||
558 | .long sys_readv /* 145 */ | ||
559 | .long sys_writev | ||
560 | .long sys_getsid | ||
561 | .long sys_fdatasync | ||
562 | .long sys_sysctl | ||
563 | .long sys_mlock /* 150 */ | ||
564 | .long sys_munlock | ||
565 | .long sys_mlockall | ||
566 | .long sys_munlockall | ||
567 | .long sys_sched_setparam | ||
568 | .long sys_sched_getparam /* 155 */ | ||
569 | .long sys_sched_setscheduler | ||
570 | .long sys_sched_getscheduler | ||
571 | .long sys_sched_yield | ||
572 | .long sys_sched_get_priority_max | ||
573 | .long sys_sched_get_priority_min /* 160 */ | ||
574 | .long sys_sched_rr_get_interval | ||
575 | .long sys_nanosleep | ||
576 | .long sys_mremap | ||
577 | .long sys_setresuid16 | ||
578 | .long sys_getresuid16 /* 165 */ | ||
579 | .long sys_getpagesize | ||
580 | .long sys_ni_syscall /* old sys_query_module */ | ||
581 | .long sys_poll | ||
582 | .long sys_nfsservctl | ||
583 | .long sys_setresgid16 /* 170 */ | ||
584 | .long sys_getresgid16 | ||
585 | .long sys_prctl | ||
586 | .long sys_rt_sigreturn | ||
587 | .long sys_rt_sigaction | ||
588 | .long sys_rt_sigprocmask /* 175 */ | ||
589 | .long sys_rt_sigpending | ||
590 | .long sys_rt_sigtimedwait | ||
591 | .long sys_rt_sigqueueinfo | ||
592 | .long sys_rt_sigsuspend | ||
593 | .long sys_pread64 /* 180 */ | ||
594 | .long sys_pwrite64 | ||
595 | .long sys_lchown16; | ||
596 | .long sys_getcwd | ||
597 | .long sys_capget | ||
598 | .long sys_capset /* 185 */ | ||
599 | .long sys_sigaltstack | ||
600 | .long sys_sendfile | ||
601 | .long sys_ni_syscall /* streams1 */ | ||
602 | .long sys_ni_syscall /* streams2 */ | ||
603 | .long sys_vfork /* 190 */ | ||
604 | .long sys_getrlimit | ||
605 | .long sys_mmap2 | ||
606 | .long sys_truncate64 | ||
607 | .long sys_ftruncate64 | ||
608 | .long sys_stat64 /* 195 */ | ||
609 | .long sys_lstat64 | ||
610 | .long sys_fstat64 | ||
611 | .long sys_chown | ||
612 | .long sys_getuid | ||
613 | .long sys_getgid /* 200 */ | ||
614 | .long sys_geteuid | ||
615 | .long sys_getegid | ||
616 | .long sys_setreuid | ||
617 | .long sys_setregid | ||
618 | .long sys_getgroups /* 205 */ | ||
619 | .long sys_setgroups | ||
620 | .long sys_fchown | ||
621 | .long sys_setresuid | ||
622 | .long sys_getresuid | ||
623 | .long sys_setresgid /* 210 */ | ||
624 | .long sys_getresgid | ||
625 | .long sys_lchown | ||
626 | .long sys_setuid | ||
627 | .long sys_setgid | ||
628 | .long sys_setfsuid /* 215 */ | ||
629 | .long sys_setfsgid | ||
630 | .long sys_pivot_root | ||
631 | .long sys_ni_syscall | ||
632 | .long sys_ni_syscall | ||
633 | .long sys_getdents64 /* 220 */ | ||
634 | .long sys_gettid | ||
635 | .long sys_tkill | ||
636 | .long sys_setxattr | ||
637 | .long sys_lsetxattr | ||
638 | .long sys_fsetxattr /* 225 */ | ||
639 | .long sys_getxattr | ||
640 | .long sys_lgetxattr | ||
641 | .long sys_fgetxattr | ||
642 | .long sys_listxattr | ||
643 | .long sys_llistxattr /* 230 */ | ||
644 | .long sys_flistxattr | ||
645 | .long sys_removexattr | ||
646 | .long sys_lremovexattr | ||
647 | .long sys_fremovexattr | ||
648 | .long sys_futex /* 235 */ | ||
649 | .long sys_sendfile64 | ||
650 | .long sys_mincore | ||
651 | .long sys_madvise | ||
652 | .long sys_fcntl64 | ||
653 | .long sys_readahead /* 240 */ | ||
654 | .long sys_io_setup | ||
655 | .long sys_io_destroy | ||
656 | .long sys_io_getevents | ||
657 | .long sys_io_submit | ||
658 | .long sys_io_cancel /* 245 */ | ||
659 | .long sys_fadvise64 | ||
660 | .long sys_exit_group | ||
661 | .long sys_lookup_dcookie | ||
662 | .long sys_epoll_create | ||
663 | .long sys_epoll_ctl /* 250 */ | ||
664 | .long sys_epoll_wait | ||
665 | .long sys_remap_file_pages | ||
666 | .long sys_set_tid_address | ||
667 | .long sys_timer_create | ||
668 | .long sys_timer_settime /* 255 */ | ||
669 | .long sys_timer_gettime | ||
670 | .long sys_timer_getoverrun | ||
671 | .long sys_timer_delete | ||
672 | .long sys_clock_settime | ||
673 | .long sys_clock_gettime /* 260 */ | ||
674 | .long sys_clock_getres | ||
675 | .long sys_clock_nanosleep | ||
676 | .long sys_statfs64 | ||
677 | .long sys_fstatfs64 | ||
678 | .long sys_tgkill /* 265 */ | ||
679 | .long sys_utimes | ||
680 | .long sys_fadvise64_64 | ||
681 | .long sys_mbind | ||
682 | .long sys_get_mempolicy | ||
683 | .long sys_set_mempolicy /* 270 */ | ||
684 | .long sys_mq_open | ||
685 | .long sys_mq_unlink | ||
686 | .long sys_mq_timedsend | ||
687 | .long sys_mq_timedreceive | ||
688 | .long sys_mq_notify /* 275 */ | ||
689 | .long sys_mq_getsetattr | ||
690 | .long sys_waitid | ||
691 | .long sys_ni_syscall /* for sys_vserver */ | ||
692 | .long sys_add_key | ||
693 | .long sys_request_key /* 280 */ | ||
694 | .long sys_keyctl | ||
695 | .long sys_ioprio_set | ||
696 | .long sys_ioprio_get | ||
697 | .long sys_inotify_init | ||
698 | .long sys_inotify_add_watch /* 285 */ | ||
699 | .long sys_inotify_rm_watch | ||
700 | .long sys_migrate_pages | ||
701 | .long sys_openat | ||
702 | .long sys_mkdirat | ||
703 | .long sys_mknodat /* 290 */ | ||
704 | .long sys_fchownat | ||
705 | .long sys_futimesat | ||
706 | .long sys_fstatat64 | ||
707 | .long sys_unlinkat | ||
708 | .long sys_renameat /* 295 */ | ||
709 | .long sys_linkat | ||
710 | .long sys_symlinkat | ||
711 | .long sys_readlinkat | ||
712 | .long sys_fchmodat | ||
713 | .long sys_faccessat /* 300 */ | ||
714 | .long sys_ni_syscall /* Reserved for pselect6 */ | ||
715 | .long sys_ni_syscall /* Reserved for ppoll */ | ||
716 | .long sys_unshare | ||
717 | .long sys_set_robust_list | ||
718 | .long sys_get_robust_list /* 305 */ | ||
719 | .long sys_splice | ||
720 | .long sys_sync_file_range | ||
721 | .long sys_tee | ||
722 | .long sys_vmsplice | ||
723 | .long sys_move_pages /* 310 */ | ||
724 | .long sys_sched_setaffinity | ||
725 | .long sys_sched_getaffinity | ||
726 | .long sys_kexec_load | ||
727 | .long sys_getcpu | ||
728 | .long sys_epoll_pwait /* 315 */ | ||
729 | .long sys_utimensat | ||
730 | .long sys_signalfd | ||
731 | .long sys_timerfd_create | ||
732 | .long sys_eventfd | ||
733 | .long sys_fallocate /* 320 */ | ||
734 | .long sys_timerfd_settime | ||
735 | .long sys_timerfd_gettime | ||
736 | .long sys_signalfd4 | ||
737 | .long sys_eventfd2 | ||
738 | .long sys_epoll_create1 /* 325 */ | ||
739 | .long sys_dup3 | ||
740 | .long sys_pipe2 | ||
741 | .long sys_inotify_init1 | ||
742 | .long sys_preadv | ||
743 | .long sys_pwritev /* 330 */ | ||
744 | .long sys_rt_tgsigqueueinfo | ||
745 | .long sys_perf_event_open | ||
746 | .long sys_get_thread_area | ||
747 | .long sys_set_thread_area | ||
748 | .long sys_atomic_cmpxchg_32 /* 335 */ | ||
749 | .long sys_atomic_barrier | ||
750 | .long sys_fanotify_init | ||
751 | .long sys_fanotify_mark | ||
752 | .long sys_prlimit64 | ||
753 | |||
diff --git a/arch/m68k/kernel/entry_mm.S b/arch/m68k/kernel/entry_mm.S new file mode 100644 index 000000000000..1559dea36e55 --- /dev/null +++ b/arch/m68k/kernel/entry_mm.S | |||
@@ -0,0 +1,753 @@ | |||
1 | /* -*- mode: asm -*- | ||
2 | * | ||
3 | * linux/arch/m68k/kernel/entry.S | ||
4 | * | ||
5 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file README.legal in the main directory of this archive | ||
9 | * for more details. | ||
10 | * | ||
11 | * Linux/m68k support by Hamish Macdonald | ||
12 | * | ||
13 | * 68060 fixes by Jesper Skov | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * entry.S contains the system-call and fault low-level handling routines. | ||
19 | * This also contains the timer-interrupt handler, as well as all interrupts | ||
20 | * and faults that can result in a task-switch. | ||
21 | * | ||
22 | * NOTE: This code handles signal-recognition, which happens every time | ||
23 | * after a timer-interrupt and after each system call. | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | /* | ||
28 | * 12/03/96 Jes: Currently we only support m68k single-cpu systems, so | ||
29 | * all pointers that used to be 'current' are now entry | ||
30 | * number 0 in the 'current_set' list. | ||
31 | * | ||
32 | * 6/05/00 RZ: addedd writeback completion after return from sighandler | ||
33 | * for 68040 | ||
34 | */ | ||
35 | |||
36 | #include <linux/linkage.h> | ||
37 | #include <asm/entry.h> | ||
38 | #include <asm/errno.h> | ||
39 | #include <asm/setup.h> | ||
40 | #include <asm/segment.h> | ||
41 | #include <asm/traps.h> | ||
42 | #include <asm/unistd.h> | ||
43 | |||
44 | #include <asm/asm-offsets.h> | ||
45 | |||
46 | .globl system_call, buserr, trap, resume | ||
47 | .globl sys_call_table | ||
48 | .globl sys_fork, sys_clone, sys_vfork | ||
49 | .globl ret_from_interrupt, bad_interrupt | ||
50 | .globl auto_irqhandler_fixup | ||
51 | .globl user_irqvec_fixup, user_irqhandler_fixup | ||
52 | |||
53 | .text | ||
54 | ENTRY(buserr) | ||
55 | SAVE_ALL_INT | ||
56 | GET_CURRENT(%d0) | ||
57 | movel %sp,%sp@- | stack frame pointer argument | ||
58 | bsrl buserr_c | ||
59 | addql #4,%sp | ||
60 | jra .Lret_from_exception | ||
61 | |||
62 | ENTRY(trap) | ||
63 | SAVE_ALL_INT | ||
64 | GET_CURRENT(%d0) | ||
65 | movel %sp,%sp@- | stack frame pointer argument | ||
66 | bsrl trap_c | ||
67 | addql #4,%sp | ||
68 | jra .Lret_from_exception | ||
69 | |||
70 | | After a fork we jump here directly from resume, | ||
71 | | so that %d1 contains the previous task | ||
72 | | schedule_tail now used regardless of CONFIG_SMP | ||
73 | ENTRY(ret_from_fork) | ||
74 | movel %d1,%sp@- | ||
75 | jsr schedule_tail | ||
76 | addql #4,%sp | ||
77 | jra .Lret_from_exception | ||
78 | |||
79 | do_trace_entry: | ||
80 | movel #-ENOSYS,%sp@(PT_OFF_D0)| needed for strace | ||
81 | subql #4,%sp | ||
82 | SAVE_SWITCH_STACK | ||
83 | jbsr syscall_trace | ||
84 | RESTORE_SWITCH_STACK | ||
85 | addql #4,%sp | ||
86 | movel %sp@(PT_OFF_ORIG_D0),%d0 | ||
87 | cmpl #NR_syscalls,%d0 | ||
88 | jcs syscall | ||
89 | badsys: | ||
90 | movel #-ENOSYS,%sp@(PT_OFF_D0) | ||
91 | jra ret_from_syscall | ||
92 | |||
93 | do_trace_exit: | ||
94 | subql #4,%sp | ||
95 | SAVE_SWITCH_STACK | ||
96 | jbsr syscall_trace | ||
97 | RESTORE_SWITCH_STACK | ||
98 | addql #4,%sp | ||
99 | jra .Lret_from_exception | ||
100 | |||
101 | ENTRY(ret_from_signal) | ||
102 | tstb %curptr@(TASK_INFO+TINFO_FLAGS+2) | ||
103 | jge 1f | ||
104 | jbsr syscall_trace | ||
105 | 1: RESTORE_SWITCH_STACK | ||
106 | addql #4,%sp | ||
107 | /* on 68040 complete pending writebacks if any */ | ||
108 | #ifdef CONFIG_M68040 | ||
109 | bfextu %sp@(PT_OFF_FORMATVEC){#0,#4},%d0 | ||
110 | subql #7,%d0 | bus error frame ? | ||
111 | jbne 1f | ||
112 | movel %sp,%sp@- | ||
113 | jbsr berr_040cleanup | ||
114 | addql #4,%sp | ||
115 | 1: | ||
116 | #endif | ||
117 | jra .Lret_from_exception | ||
118 | |||
119 | ENTRY(system_call) | ||
120 | SAVE_ALL_SYS | ||
121 | |||
122 | GET_CURRENT(%d1) | ||
123 | | save top of frame | ||
124 | movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0) | ||
125 | |||
126 | | syscall trace? | ||
127 | tstb %curptr@(TASK_INFO+TINFO_FLAGS+2) | ||
128 | jmi do_trace_entry | ||
129 | cmpl #NR_syscalls,%d0 | ||
130 | jcc badsys | ||
131 | syscall: | ||
132 | jbsr @(sys_call_table,%d0:l:4)@(0) | ||
133 | movel %d0,%sp@(PT_OFF_D0) | save the return value | ||
134 | ret_from_syscall: | ||
135 | |oriw #0x0700,%sr | ||
136 | movew %curptr@(TASK_INFO+TINFO_FLAGS+2),%d0 | ||
137 | jne syscall_exit_work | ||
138 | 1: RESTORE_ALL | ||
139 | |||
140 | syscall_exit_work: | ||
141 | btst #5,%sp@(PT_OFF_SR) | check if returning to kernel | ||
142 | bnes 1b | if so, skip resched, signals | ||
143 | lslw #1,%d0 | ||
144 | jcs do_trace_exit | ||
145 | jmi do_delayed_trace | ||
146 | lslw #8,%d0 | ||
147 | jmi do_signal_return | ||
148 | pea resume_userspace | ||
149 | jra schedule | ||
150 | |||
151 | |||
152 | ENTRY(ret_from_exception) | ||
153 | .Lret_from_exception: | ||
154 | btst #5,%sp@(PT_OFF_SR) | check if returning to kernel | ||
155 | bnes 1f | if so, skip resched, signals | ||
156 | | only allow interrupts when we are really the last one on the | ||
157 | | kernel stack, otherwise stack overflow can occur during | ||
158 | | heavy interrupt load | ||
159 | andw #ALLOWINT,%sr | ||
160 | |||
161 | resume_userspace: | ||
162 | moveb %curptr@(TASK_INFO+TINFO_FLAGS+3),%d0 | ||
163 | jne exit_work | ||
164 | 1: RESTORE_ALL | ||
165 | |||
166 | exit_work: | ||
167 | | save top of frame | ||
168 | movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0) | ||
169 | lslb #1,%d0 | ||
170 | jmi do_signal_return | ||
171 | pea resume_userspace | ||
172 | jra schedule | ||
173 | |||
174 | |||
175 | do_signal_return: | ||
176 | |andw #ALLOWINT,%sr | ||
177 | subql #4,%sp | dummy return address | ||
178 | SAVE_SWITCH_STACK | ||
179 | pea %sp@(SWITCH_STACK_SIZE) | ||
180 | bsrl do_signal | ||
181 | addql #4,%sp | ||
182 | RESTORE_SWITCH_STACK | ||
183 | addql #4,%sp | ||
184 | jbra resume_userspace | ||
185 | |||
186 | do_delayed_trace: | ||
187 | bclr #7,%sp@(PT_OFF_SR) | clear trace bit in SR | ||
188 | pea 1 | send SIGTRAP | ||
189 | movel %curptr,%sp@- | ||
190 | pea LSIGTRAP | ||
191 | jbsr send_sig | ||
192 | addql #8,%sp | ||
193 | addql #4,%sp | ||
194 | jbra resume_userspace | ||
195 | |||
196 | |||
197 | /* This is the main interrupt handler for autovector interrupts */ | ||
198 | |||
199 | ENTRY(auto_inthandler) | ||
200 | SAVE_ALL_INT | ||
201 | GET_CURRENT(%d0) | ||
202 | addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) | ||
203 | | put exception # in d0 | ||
204 | bfextu %sp@(PT_OFF_FORMATVEC){#4,#10},%d0 | ||
205 | subw #VEC_SPUR,%d0 | ||
206 | |||
207 | movel %sp,%sp@- | ||
208 | movel %d0,%sp@- | put vector # on stack | ||
209 | auto_irqhandler_fixup = . + 2 | ||
210 | jsr __m68k_handle_int | process the IRQ | ||
211 | addql #8,%sp | pop parameters off stack | ||
212 | |||
213 | ret_from_interrupt: | ||
214 | subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) | ||
215 | jeq ret_from_last_interrupt | ||
216 | 2: RESTORE_ALL | ||
217 | |||
218 | ALIGN | ||
219 | ret_from_last_interrupt: | ||
220 | moveq #(~ALLOWINT>>8)&0xff,%d0 | ||
221 | andb %sp@(PT_OFF_SR),%d0 | ||
222 | jne 2b | ||
223 | |||
224 | /* check if we need to do software interrupts */ | ||
225 | tstl irq_stat+CPUSTAT_SOFTIRQ_PENDING | ||
226 | jeq .Lret_from_exception | ||
227 | pea ret_from_exception | ||
228 | jra do_softirq | ||
229 | |||
230 | /* Handler for user defined interrupt vectors */ | ||
231 | |||
232 | ENTRY(user_inthandler) | ||
233 | SAVE_ALL_INT | ||
234 | GET_CURRENT(%d0) | ||
235 | addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) | ||
236 | | put exception # in d0 | ||
237 | bfextu %sp@(PT_OFF_FORMATVEC){#4,#10},%d0 | ||
238 | user_irqvec_fixup = . + 2 | ||
239 | subw #VEC_USER,%d0 | ||
240 | |||
241 | movel %sp,%sp@- | ||
242 | movel %d0,%sp@- | put vector # on stack | ||
243 | user_irqhandler_fixup = . + 2 | ||
244 | jsr __m68k_handle_int | process the IRQ | ||
245 | addql #8,%sp | pop parameters off stack | ||
246 | |||
247 | subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) | ||
248 | jeq ret_from_last_interrupt | ||
249 | RESTORE_ALL | ||
250 | |||
251 | /* Handler for uninitialized and spurious interrupts */ | ||
252 | |||
253 | ENTRY(bad_inthandler) | ||
254 | SAVE_ALL_INT | ||
255 | GET_CURRENT(%d0) | ||
256 | addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) | ||
257 | |||
258 | movel %sp,%sp@- | ||
259 | jsr handle_badint | ||
260 | addql #4,%sp | ||
261 | |||
262 | subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) | ||
263 | jeq ret_from_last_interrupt | ||
264 | RESTORE_ALL | ||
265 | |||
266 | |||
267 | ENTRY(sys_fork) | ||
268 | SAVE_SWITCH_STACK | ||
269 | pea %sp@(SWITCH_STACK_SIZE) | ||
270 | jbsr m68k_fork | ||
271 | addql #4,%sp | ||
272 | RESTORE_SWITCH_STACK | ||
273 | rts | ||
274 | |||
275 | ENTRY(sys_clone) | ||
276 | SAVE_SWITCH_STACK | ||
277 | pea %sp@(SWITCH_STACK_SIZE) | ||
278 | jbsr m68k_clone | ||
279 | addql #4,%sp | ||
280 | RESTORE_SWITCH_STACK | ||
281 | rts | ||
282 | |||
283 | ENTRY(sys_vfork) | ||
284 | SAVE_SWITCH_STACK | ||
285 | pea %sp@(SWITCH_STACK_SIZE) | ||
286 | jbsr m68k_vfork | ||
287 | addql #4,%sp | ||
288 | RESTORE_SWITCH_STACK | ||
289 | rts | ||
290 | |||
291 | ENTRY(sys_sigreturn) | ||
292 | SAVE_SWITCH_STACK | ||
293 | jbsr do_sigreturn | ||
294 | RESTORE_SWITCH_STACK | ||
295 | rts | ||
296 | |||
297 | ENTRY(sys_rt_sigreturn) | ||
298 | SAVE_SWITCH_STACK | ||
299 | jbsr do_rt_sigreturn | ||
300 | RESTORE_SWITCH_STACK | ||
301 | rts | ||
302 | |||
303 | resume: | ||
304 | /* | ||
305 | * Beware - when entering resume, prev (the current task) is | ||
306 | * in a0, next (the new task) is in a1,so don't change these | ||
307 | * registers until their contents are no longer needed. | ||
308 | */ | ||
309 | |||
310 | /* save sr */ | ||
311 | movew %sr,%a0@(TASK_THREAD+THREAD_SR) | ||
312 | |||
313 | /* save fs (sfc,%dfc) (may be pointing to kernel memory) */ | ||
314 | movec %sfc,%d0 | ||
315 | movew %d0,%a0@(TASK_THREAD+THREAD_FS) | ||
316 | |||
317 | /* save usp */ | ||
318 | /* it is better to use a movel here instead of a movew 8*) */ | ||
319 | movec %usp,%d0 | ||
320 | movel %d0,%a0@(TASK_THREAD+THREAD_USP) | ||
321 | |||
322 | /* save non-scratch registers on stack */ | ||
323 | SAVE_SWITCH_STACK | ||
324 | |||
325 | /* save current kernel stack pointer */ | ||
326 | movel %sp,%a0@(TASK_THREAD+THREAD_KSP) | ||
327 | |||
328 | /* save floating point context */ | ||
329 | #ifndef CONFIG_M68KFPU_EMU_ONLY | ||
330 | #ifdef CONFIG_M68KFPU_EMU | ||
331 | tstl m68k_fputype | ||
332 | jeq 3f | ||
333 | #endif | ||
334 | fsave %a0@(TASK_THREAD+THREAD_FPSTATE) | ||
335 | |||
336 | #if defined(CONFIG_M68060) | ||
337 | #if !defined(CPU_M68060_ONLY) | ||
338 | btst #3,m68k_cputype+3 | ||
339 | beqs 1f | ||
340 | #endif | ||
341 | /* The 060 FPU keeps status in bits 15-8 of the first longword */ | ||
342 | tstb %a0@(TASK_THREAD+THREAD_FPSTATE+2) | ||
343 | jeq 3f | ||
344 | #if !defined(CPU_M68060_ONLY) | ||
345 | jra 2f | ||
346 | #endif | ||
347 | #endif /* CONFIG_M68060 */ | ||
348 | #if !defined(CPU_M68060_ONLY) | ||
349 | 1: tstb %a0@(TASK_THREAD+THREAD_FPSTATE) | ||
350 | jeq 3f | ||
351 | #endif | ||
352 | 2: fmovemx %fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG) | ||
353 | fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_THREAD+THREAD_FPCNTL) | ||
354 | 3: | ||
355 | #endif /* CONFIG_M68KFPU_EMU_ONLY */ | ||
356 | /* Return previous task in %d1 */ | ||
357 | movel %curptr,%d1 | ||
358 | |||
359 | /* switch to new task (a1 contains new task) */ | ||
360 | movel %a1,%curptr | ||
361 | |||
362 | /* restore floating point context */ | ||
363 | #ifndef CONFIG_M68KFPU_EMU_ONLY | ||
364 | #ifdef CONFIG_M68KFPU_EMU | ||
365 | tstl m68k_fputype | ||
366 | jeq 4f | ||
367 | #endif | ||
368 | #if defined(CONFIG_M68060) | ||
369 | #if !defined(CPU_M68060_ONLY) | ||
370 | btst #3,m68k_cputype+3 | ||
371 | beqs 1f | ||
372 | #endif | ||
373 | /* The 060 FPU keeps status in bits 15-8 of the first longword */ | ||
374 | tstb %a1@(TASK_THREAD+THREAD_FPSTATE+2) | ||
375 | jeq 3f | ||
376 | #if !defined(CPU_M68060_ONLY) | ||
377 | jra 2f | ||
378 | #endif | ||
379 | #endif /* CONFIG_M68060 */ | ||
380 | #if !defined(CPU_M68060_ONLY) | ||
381 | 1: tstb %a1@(TASK_THREAD+THREAD_FPSTATE) | ||
382 | jeq 3f | ||
383 | #endif | ||
384 | 2: fmovemx %a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7 | ||
385 | fmoveml %a1@(TASK_THREAD+THREAD_FPCNTL),%fpcr/%fpsr/%fpiar | ||
386 | 3: frestore %a1@(TASK_THREAD+THREAD_FPSTATE) | ||
387 | 4: | ||
388 | #endif /* CONFIG_M68KFPU_EMU_ONLY */ | ||
389 | |||
390 | /* restore the kernel stack pointer */ | ||
391 | movel %a1@(TASK_THREAD+THREAD_KSP),%sp | ||
392 | |||
393 | /* restore non-scratch registers */ | ||
394 | RESTORE_SWITCH_STACK | ||
395 | |||
396 | /* restore user stack pointer */ | ||
397 | movel %a1@(TASK_THREAD+THREAD_USP),%a0 | ||
398 | movel %a0,%usp | ||
399 | |||
400 | /* restore fs (sfc,%dfc) */ | ||
401 | movew %a1@(TASK_THREAD+THREAD_FS),%a0 | ||
402 | movec %a0,%sfc | ||
403 | movec %a0,%dfc | ||
404 | |||
405 | /* restore status register */ | ||
406 | movew %a1@(TASK_THREAD+THREAD_SR),%sr | ||
407 | |||
408 | rts | ||
409 | |||
410 | .data | ||
411 | ALIGN | ||
412 | sys_call_table: | ||
413 | .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ | ||
414 | .long sys_exit | ||
415 | .long sys_fork | ||
416 | .long sys_read | ||
417 | .long sys_write | ||
418 | .long sys_open /* 5 */ | ||
419 | .long sys_close | ||
420 | .long sys_waitpid | ||
421 | .long sys_creat | ||
422 | .long sys_link | ||
423 | .long sys_unlink /* 10 */ | ||
424 | .long sys_execve | ||
425 | .long sys_chdir | ||
426 | .long sys_time | ||
427 | .long sys_mknod | ||
428 | .long sys_chmod /* 15 */ | ||
429 | .long sys_chown16 | ||
430 | .long sys_ni_syscall /* old break syscall holder */ | ||
431 | .long sys_stat | ||
432 | .long sys_lseek | ||
433 | .long sys_getpid /* 20 */ | ||
434 | .long sys_mount | ||
435 | .long sys_oldumount | ||
436 | .long sys_setuid16 | ||
437 | .long sys_getuid16 | ||
438 | .long sys_stime /* 25 */ | ||
439 | .long sys_ptrace | ||
440 | .long sys_alarm | ||
441 | .long sys_fstat | ||
442 | .long sys_pause | ||
443 | .long sys_utime /* 30 */ | ||
444 | .long sys_ni_syscall /* old stty syscall holder */ | ||
445 | .long sys_ni_syscall /* old gtty syscall holder */ | ||
446 | .long sys_access | ||
447 | .long sys_nice | ||
448 | .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ | ||
449 | .long sys_sync | ||
450 | .long sys_kill | ||
451 | .long sys_rename | ||
452 | .long sys_mkdir | ||
453 | .long sys_rmdir /* 40 */ | ||
454 | .long sys_dup | ||
455 | .long sys_pipe | ||
456 | .long sys_times | ||
457 | .long sys_ni_syscall /* old prof syscall holder */ | ||
458 | .long sys_brk /* 45 */ | ||
459 | .long sys_setgid16 | ||
460 | .long sys_getgid16 | ||
461 | .long sys_signal | ||
462 | .long sys_geteuid16 | ||
463 | .long sys_getegid16 /* 50 */ | ||
464 | .long sys_acct | ||
465 | .long sys_umount /* recycled never used phys() */ | ||
466 | .long sys_ni_syscall /* old lock syscall holder */ | ||
467 | .long sys_ioctl | ||
468 | .long sys_fcntl /* 55 */ | ||
469 | .long sys_ni_syscall /* old mpx syscall holder */ | ||
470 | .long sys_setpgid | ||
471 | .long sys_ni_syscall /* old ulimit syscall holder */ | ||
472 | .long sys_ni_syscall | ||
473 | .long sys_umask /* 60 */ | ||
474 | .long sys_chroot | ||
475 | .long sys_ustat | ||
476 | .long sys_dup2 | ||
477 | .long sys_getppid | ||
478 | .long sys_getpgrp /* 65 */ | ||
479 | .long sys_setsid | ||
480 | .long sys_sigaction | ||
481 | .long sys_sgetmask | ||
482 | .long sys_ssetmask | ||
483 | .long sys_setreuid16 /* 70 */ | ||
484 | .long sys_setregid16 | ||
485 | .long sys_sigsuspend | ||
486 | .long sys_sigpending | ||
487 | .long sys_sethostname | ||
488 | .long sys_setrlimit /* 75 */ | ||
489 | .long sys_old_getrlimit | ||
490 | .long sys_getrusage | ||
491 | .long sys_gettimeofday | ||
492 | .long sys_settimeofday | ||
493 | .long sys_getgroups16 /* 80 */ | ||
494 | .long sys_setgroups16 | ||
495 | .long sys_old_select | ||
496 | .long sys_symlink | ||
497 | .long sys_lstat | ||
498 | .long sys_readlink /* 85 */ | ||
499 | .long sys_uselib | ||
500 | .long sys_swapon | ||
501 | .long sys_reboot | ||
502 | .long sys_old_readdir | ||
503 | .long sys_old_mmap /* 90 */ | ||
504 | .long sys_munmap | ||
505 | .long sys_truncate | ||
506 | .long sys_ftruncate | ||
507 | .long sys_fchmod | ||
508 | .long sys_fchown16 /* 95 */ | ||
509 | .long sys_getpriority | ||
510 | .long sys_setpriority | ||
511 | .long sys_ni_syscall /* old profil syscall holder */ | ||
512 | .long sys_statfs | ||
513 | .long sys_fstatfs /* 100 */ | ||
514 | .long sys_ni_syscall /* ioperm for i386 */ | ||
515 | .long sys_socketcall | ||
516 | .long sys_syslog | ||
517 | .long sys_setitimer | ||
518 | .long sys_getitimer /* 105 */ | ||
519 | .long sys_newstat | ||
520 | .long sys_newlstat | ||
521 | .long sys_newfstat | ||
522 | .long sys_ni_syscall | ||
523 | .long sys_ni_syscall /* 110 */ /* iopl for i386 */ | ||
524 | .long sys_vhangup | ||
525 | .long sys_ni_syscall /* obsolete idle() syscall */ | ||
526 | .long sys_ni_syscall /* vm86old for i386 */ | ||
527 | .long sys_wait4 | ||
528 | .long sys_swapoff /* 115 */ | ||
529 | .long sys_sysinfo | ||
530 | .long sys_ipc | ||
531 | .long sys_fsync | ||
532 | .long sys_sigreturn | ||
533 | .long sys_clone /* 120 */ | ||
534 | .long sys_setdomainname | ||
535 | .long sys_newuname | ||
536 | .long sys_cacheflush /* modify_ldt for i386 */ | ||
537 | .long sys_adjtimex | ||
538 | .long sys_mprotect /* 125 */ | ||
539 | .long sys_sigprocmask | ||
540 | .long sys_ni_syscall /* old "create_module" */ | ||
541 | .long sys_init_module | ||
542 | .long sys_delete_module | ||
543 | .long sys_ni_syscall /* 130 - old "get_kernel_syms" */ | ||
544 | .long sys_quotactl | ||
545 | .long sys_getpgid | ||
546 | .long sys_fchdir | ||
547 | .long sys_bdflush | ||
548 | .long sys_sysfs /* 135 */ | ||
549 | .long sys_personality | ||
550 | .long sys_ni_syscall /* for afs_syscall */ | ||
551 | .long sys_setfsuid16 | ||
552 | .long sys_setfsgid16 | ||
553 | .long sys_llseek /* 140 */ | ||
554 | .long sys_getdents | ||
555 | .long sys_select | ||
556 | .long sys_flock | ||
557 | .long sys_msync | ||
558 | .long sys_readv /* 145 */ | ||
559 | .long sys_writev | ||
560 | .long sys_getsid | ||
561 | .long sys_fdatasync | ||
562 | .long sys_sysctl | ||
563 | .long sys_mlock /* 150 */ | ||
564 | .long sys_munlock | ||
565 | .long sys_mlockall | ||
566 | .long sys_munlockall | ||
567 | .long sys_sched_setparam | ||
568 | .long sys_sched_getparam /* 155 */ | ||
569 | .long sys_sched_setscheduler | ||
570 | .long sys_sched_getscheduler | ||
571 | .long sys_sched_yield | ||
572 | .long sys_sched_get_priority_max | ||
573 | .long sys_sched_get_priority_min /* 160 */ | ||
574 | .long sys_sched_rr_get_interval | ||
575 | .long sys_nanosleep | ||
576 | .long sys_mremap | ||
577 | .long sys_setresuid16 | ||
578 | .long sys_getresuid16 /* 165 */ | ||
579 | .long sys_getpagesize | ||
580 | .long sys_ni_syscall /* old sys_query_module */ | ||
581 | .long sys_poll | ||
582 | .long sys_nfsservctl | ||
583 | .long sys_setresgid16 /* 170 */ | ||
584 | .long sys_getresgid16 | ||
585 | .long sys_prctl | ||
586 | .long sys_rt_sigreturn | ||
587 | .long sys_rt_sigaction | ||
588 | .long sys_rt_sigprocmask /* 175 */ | ||
589 | .long sys_rt_sigpending | ||
590 | .long sys_rt_sigtimedwait | ||
591 | .long sys_rt_sigqueueinfo | ||
592 | .long sys_rt_sigsuspend | ||
593 | .long sys_pread64 /* 180 */ | ||
594 | .long sys_pwrite64 | ||
595 | .long sys_lchown16; | ||
596 | .long sys_getcwd | ||
597 | .long sys_capget | ||
598 | .long sys_capset /* 185 */ | ||
599 | .long sys_sigaltstack | ||
600 | .long sys_sendfile | ||
601 | .long sys_ni_syscall /* streams1 */ | ||
602 | .long sys_ni_syscall /* streams2 */ | ||
603 | .long sys_vfork /* 190 */ | ||
604 | .long sys_getrlimit | ||
605 | .long sys_mmap2 | ||
606 | .long sys_truncate64 | ||
607 | .long sys_ftruncate64 | ||
608 | .long sys_stat64 /* 195 */ | ||
609 | .long sys_lstat64 | ||
610 | .long sys_fstat64 | ||
611 | .long sys_chown | ||
612 | .long sys_getuid | ||
613 | .long sys_getgid /* 200 */ | ||
614 | .long sys_geteuid | ||
615 | .long sys_getegid | ||
616 | .long sys_setreuid | ||
617 | .long sys_setregid | ||
618 | .long sys_getgroups /* 205 */ | ||
619 | .long sys_setgroups | ||
620 | .long sys_fchown | ||
621 | .long sys_setresuid | ||
622 | .long sys_getresuid | ||
623 | .long sys_setresgid /* 210 */ | ||
624 | .long sys_getresgid | ||
625 | .long sys_lchown | ||
626 | .long sys_setuid | ||
627 | .long sys_setgid | ||
628 | .long sys_setfsuid /* 215 */ | ||
629 | .long sys_setfsgid | ||
630 | .long sys_pivot_root | ||
631 | .long sys_ni_syscall | ||
632 | .long sys_ni_syscall | ||
633 | .long sys_getdents64 /* 220 */ | ||
634 | .long sys_gettid | ||
635 | .long sys_tkill | ||
636 | .long sys_setxattr | ||
637 | .long sys_lsetxattr | ||
638 | .long sys_fsetxattr /* 225 */ | ||
639 | .long sys_getxattr | ||
640 | .long sys_lgetxattr | ||
641 | .long sys_fgetxattr | ||
642 | .long sys_listxattr | ||
643 | .long sys_llistxattr /* 230 */ | ||
644 | .long sys_flistxattr | ||
645 | .long sys_removexattr | ||
646 | .long sys_lremovexattr | ||
647 | .long sys_fremovexattr | ||
648 | .long sys_futex /* 235 */ | ||
649 | .long sys_sendfile64 | ||
650 | .long sys_mincore | ||
651 | .long sys_madvise | ||
652 | .long sys_fcntl64 | ||
653 | .long sys_readahead /* 240 */ | ||
654 | .long sys_io_setup | ||
655 | .long sys_io_destroy | ||
656 | .long sys_io_getevents | ||
657 | .long sys_io_submit | ||
658 | .long sys_io_cancel /* 245 */ | ||
659 | .long sys_fadvise64 | ||
660 | .long sys_exit_group | ||
661 | .long sys_lookup_dcookie | ||
662 | .long sys_epoll_create | ||
663 | .long sys_epoll_ctl /* 250 */ | ||
664 | .long sys_epoll_wait | ||
665 | .long sys_remap_file_pages | ||
666 | .long sys_set_tid_address | ||
667 | .long sys_timer_create | ||
668 | .long sys_timer_settime /* 255 */ | ||
669 | .long sys_timer_gettime | ||
670 | .long sys_timer_getoverrun | ||
671 | .long sys_timer_delete | ||
672 | .long sys_clock_settime | ||
673 | .long sys_clock_gettime /* 260 */ | ||
674 | .long sys_clock_getres | ||
675 | .long sys_clock_nanosleep | ||
676 | .long sys_statfs64 | ||
677 | .long sys_fstatfs64 | ||
678 | .long sys_tgkill /* 265 */ | ||
679 | .long sys_utimes | ||
680 | .long sys_fadvise64_64 | ||
681 | .long sys_mbind | ||
682 | .long sys_get_mempolicy | ||
683 | .long sys_set_mempolicy /* 270 */ | ||
684 | .long sys_mq_open | ||
685 | .long sys_mq_unlink | ||
686 | .long sys_mq_timedsend | ||
687 | .long sys_mq_timedreceive | ||
688 | .long sys_mq_notify /* 275 */ | ||
689 | .long sys_mq_getsetattr | ||
690 | .long sys_waitid | ||
691 | .long sys_ni_syscall /* for sys_vserver */ | ||
692 | .long sys_add_key | ||
693 | .long sys_request_key /* 280 */ | ||
694 | .long sys_keyctl | ||
695 | .long sys_ioprio_set | ||
696 | .long sys_ioprio_get | ||
697 | .long sys_inotify_init | ||
698 | .long sys_inotify_add_watch /* 285 */ | ||
699 | .long sys_inotify_rm_watch | ||
700 | .long sys_migrate_pages | ||
701 | .long sys_openat | ||
702 | .long sys_mkdirat | ||
703 | .long sys_mknodat /* 290 */ | ||
704 | .long sys_fchownat | ||
705 | .long sys_futimesat | ||
706 | .long sys_fstatat64 | ||
707 | .long sys_unlinkat | ||
708 | .long sys_renameat /* 295 */ | ||
709 | .long sys_linkat | ||
710 | .long sys_symlinkat | ||
711 | .long sys_readlinkat | ||
712 | .long sys_fchmodat | ||
713 | .long sys_faccessat /* 300 */ | ||
714 | .long sys_ni_syscall /* Reserved for pselect6 */ | ||
715 | .long sys_ni_syscall /* Reserved for ppoll */ | ||
716 | .long sys_unshare | ||
717 | .long sys_set_robust_list | ||
718 | .long sys_get_robust_list /* 305 */ | ||
719 | .long sys_splice | ||
720 | .long sys_sync_file_range | ||
721 | .long sys_tee | ||
722 | .long sys_vmsplice | ||
723 | .long sys_move_pages /* 310 */ | ||
724 | .long sys_sched_setaffinity | ||
725 | .long sys_sched_getaffinity | ||
726 | .long sys_kexec_load | ||
727 | .long sys_getcpu | ||
728 | .long sys_epoll_pwait /* 315 */ | ||
729 | .long sys_utimensat | ||
730 | .long sys_signalfd | ||
731 | .long sys_timerfd_create | ||
732 | .long sys_eventfd | ||
733 | .long sys_fallocate /* 320 */ | ||
734 | .long sys_timerfd_settime | ||
735 | .long sys_timerfd_gettime | ||
736 | .long sys_signalfd4 | ||
737 | .long sys_eventfd2 | ||
738 | .long sys_epoll_create1 /* 325 */ | ||
739 | .long sys_dup3 | ||
740 | .long sys_pipe2 | ||
741 | .long sys_inotify_init1 | ||
742 | .long sys_preadv | ||
743 | .long sys_pwritev /* 330 */ | ||
744 | .long sys_rt_tgsigqueueinfo | ||
745 | .long sys_perf_event_open | ||
746 | .long sys_get_thread_area | ||
747 | .long sys_set_thread_area | ||
748 | .long sys_atomic_cmpxchg_32 /* 335 */ | ||
749 | .long sys_atomic_barrier | ||
750 | .long sys_fanotify_init | ||
751 | .long sys_fanotify_mark | ||
752 | .long sys_prlimit64 | ||
753 | |||
diff --git a/arch/m68knommu/kernel/entry.S b/arch/m68k/kernel/entry_no.S index 2783f25e38bd..2783f25e38bd 100644 --- a/arch/m68knommu/kernel/entry.S +++ b/arch/m68k/kernel/entry_no.S | |||
diff --git a/arch/m68knommu/kernel/init_task.c b/arch/m68k/kernel/init_task.c index cbf9dc3cc51d..cbf9dc3cc51d 100644 --- a/arch/m68knommu/kernel/init_task.c +++ b/arch/m68k/kernel/init_task.c | |||
diff --git a/arch/m68knommu/kernel/irq.c b/arch/m68k/kernel/irq.c index c7dd48f37bee..c7dd48f37bee 100644 --- a/arch/m68knommu/kernel/irq.c +++ b/arch/m68k/kernel/irq.c | |||
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c index d900e77e5363..4752c28ce0ac 100644 --- a/arch/m68k/kernel/m68k_ksyms.c +++ b/arch/m68k/kernel/m68k_ksyms.c | |||
@@ -1,16 +1,5 @@ | |||
1 | #include <linux/module.h> | 1 | #ifdef CONFIG_MMU |
2 | 2 | #include "m68k_ksyms_mm.c" | |
3 | asmlinkage long long __ashldi3 (long long, int); | 3 | #else |
4 | asmlinkage long long __ashrdi3 (long long, int); | 4 | #include "m68k_ksyms_no.c" |
5 | asmlinkage long long __lshrdi3 (long long, int); | 5 | #endif |
6 | asmlinkage long long __muldi3 (long long, long long); | ||
7 | |||
8 | /* The following are special because they're not called | ||
9 | explicitly (the C compiler generates them). Fortunately, | ||
10 | their interface isn't gonna change any time soon now, so | ||
11 | it's OK to leave it out of version control. */ | ||
12 | EXPORT_SYMBOL(__ashldi3); | ||
13 | EXPORT_SYMBOL(__ashrdi3); | ||
14 | EXPORT_SYMBOL(__lshrdi3); | ||
15 | EXPORT_SYMBOL(__muldi3); | ||
16 | |||
diff --git a/arch/m68k/kernel/m68k_ksyms_mm.c b/arch/m68k/kernel/m68k_ksyms_mm.c new file mode 100644 index 000000000000..d900e77e5363 --- /dev/null +++ b/arch/m68k/kernel/m68k_ksyms_mm.c | |||
@@ -0,0 +1,16 @@ | |||
1 | #include <linux/module.h> | ||
2 | |||
3 | asmlinkage long long __ashldi3 (long long, int); | ||
4 | asmlinkage long long __ashrdi3 (long long, int); | ||
5 | asmlinkage long long __lshrdi3 (long long, int); | ||
6 | asmlinkage long long __muldi3 (long long, long long); | ||
7 | |||
8 | /* The following are special because they're not called | ||
9 | explicitly (the C compiler generates them). Fortunately, | ||
10 | their interface isn't gonna change any time soon now, so | ||
11 | it's OK to leave it out of version control. */ | ||
12 | EXPORT_SYMBOL(__ashldi3); | ||
13 | EXPORT_SYMBOL(__ashrdi3); | ||
14 | EXPORT_SYMBOL(__lshrdi3); | ||
15 | EXPORT_SYMBOL(__muldi3); | ||
16 | |||
diff --git a/arch/m68knommu/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms_no.c index 39fe0a7aec32..39fe0a7aec32 100644 --- a/arch/m68knommu/kernel/m68k_ksyms.c +++ b/arch/m68k/kernel/m68k_ksyms_no.c | |||
diff --git a/arch/m68k/kernel/module.c b/arch/m68k/kernel/module.c index cd6bcb1c957e..7ea203ce6b1a 100644 --- a/arch/m68k/kernel/module.c +++ b/arch/m68k/kernel/module.c | |||
@@ -1,155 +1,5 @@ | |||
1 | /* | 1 | #ifdef CONFIG_MMU |
2 | * This file is subject to the terms and conditions of the GNU General Public | 2 | #include "module_mm.c" |
3 | * License. See the file COPYING in the main directory of this archive | ||
4 | * for more details. | ||
5 | */ | ||
6 | |||
7 | #include <linux/moduleloader.h> | ||
8 | #include <linux/elf.h> | ||
9 | #include <linux/vmalloc.h> | ||
10 | #include <linux/fs.h> | ||
11 | #include <linux/string.h> | ||
12 | #include <linux/kernel.h> | ||
13 | |||
14 | #if 0 | ||
15 | #define DEBUGP printk | ||
16 | #else | 3 | #else |
17 | #define DEBUGP(fmt...) | 4 | #include "module_no.c" |
18 | #endif | 5 | #endif |
19 | |||
20 | #ifdef CONFIG_MODULES | ||
21 | |||
22 | void *module_alloc(unsigned long size) | ||
23 | { | ||
24 | if (size == 0) | ||
25 | return NULL; | ||
26 | return vmalloc(size); | ||
27 | } | ||
28 | |||
29 | |||
30 | /* Free memory returned from module_alloc */ | ||
31 | void module_free(struct module *mod, void *module_region) | ||
32 | { | ||
33 | vfree(module_region); | ||
34 | } | ||
35 | |||
36 | /* We don't need anything special. */ | ||
37 | int module_frob_arch_sections(Elf_Ehdr *hdr, | ||
38 | Elf_Shdr *sechdrs, | ||
39 | char *secstrings, | ||
40 | struct module *mod) | ||
41 | { | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | int apply_relocate(Elf32_Shdr *sechdrs, | ||
46 | const char *strtab, | ||
47 | unsigned int symindex, | ||
48 | unsigned int relsec, | ||
49 | struct module *me) | ||
50 | { | ||
51 | unsigned int i; | ||
52 | Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; | ||
53 | Elf32_Sym *sym; | ||
54 | uint32_t *location; | ||
55 | |||
56 | DEBUGP("Applying relocate section %u to %u\n", relsec, | ||
57 | sechdrs[relsec].sh_info); | ||
58 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { | ||
59 | /* This is where to make the change */ | ||
60 | location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr | ||
61 | + rel[i].r_offset; | ||
62 | /* This is the symbol it is referring to. Note that all | ||
63 | undefined symbols have been resolved. */ | ||
64 | sym = (Elf32_Sym *)sechdrs[symindex].sh_addr | ||
65 | + ELF32_R_SYM(rel[i].r_info); | ||
66 | |||
67 | switch (ELF32_R_TYPE(rel[i].r_info)) { | ||
68 | case R_68K_32: | ||
69 | /* We add the value into the location given */ | ||
70 | *location += sym->st_value; | ||
71 | break; | ||
72 | case R_68K_PC32: | ||
73 | /* Add the value, subtract its postition */ | ||
74 | *location += sym->st_value - (uint32_t)location; | ||
75 | break; | ||
76 | default: | ||
77 | printk(KERN_ERR "module %s: Unknown relocation: %u\n", | ||
78 | me->name, ELF32_R_TYPE(rel[i].r_info)); | ||
79 | return -ENOEXEC; | ||
80 | } | ||
81 | } | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | int apply_relocate_add(Elf32_Shdr *sechdrs, | ||
86 | const char *strtab, | ||
87 | unsigned int symindex, | ||
88 | unsigned int relsec, | ||
89 | struct module *me) | ||
90 | { | ||
91 | unsigned int i; | ||
92 | Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; | ||
93 | Elf32_Sym *sym; | ||
94 | uint32_t *location; | ||
95 | |||
96 | DEBUGP("Applying relocate_add section %u to %u\n", relsec, | ||
97 | sechdrs[relsec].sh_info); | ||
98 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { | ||
99 | /* This is where to make the change */ | ||
100 | location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr | ||
101 | + rel[i].r_offset; | ||
102 | /* This is the symbol it is referring to. Note that all | ||
103 | undefined symbols have been resolved. */ | ||
104 | sym = (Elf32_Sym *)sechdrs[symindex].sh_addr | ||
105 | + ELF32_R_SYM(rel[i].r_info); | ||
106 | |||
107 | switch (ELF32_R_TYPE(rel[i].r_info)) { | ||
108 | case R_68K_32: | ||
109 | /* We add the value into the location given */ | ||
110 | *location = rel[i].r_addend + sym->st_value; | ||
111 | break; | ||
112 | case R_68K_PC32: | ||
113 | /* Add the value, subtract its postition */ | ||
114 | *location = rel[i].r_addend + sym->st_value - (uint32_t)location; | ||
115 | break; | ||
116 | default: | ||
117 | printk(KERN_ERR "module %s: Unknown relocation: %u\n", | ||
118 | me->name, ELF32_R_TYPE(rel[i].r_info)); | ||
119 | return -ENOEXEC; | ||
120 | } | ||
121 | } | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | int module_finalize(const Elf_Ehdr *hdr, | ||
126 | const Elf_Shdr *sechdrs, | ||
127 | struct module *mod) | ||
128 | { | ||
129 | module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end); | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | void module_arch_cleanup(struct module *mod) | ||
135 | { | ||
136 | } | ||
137 | |||
138 | #endif /* CONFIG_MODULES */ | ||
139 | |||
140 | void module_fixup(struct module *mod, struct m68k_fixup_info *start, | ||
141 | struct m68k_fixup_info *end) | ||
142 | { | ||
143 | struct m68k_fixup_info *fixup; | ||
144 | |||
145 | for (fixup = start; fixup < end; fixup++) { | ||
146 | switch (fixup->type) { | ||
147 | case m68k_fixup_memoffset: | ||
148 | *(u32 *)fixup->addr = m68k_memoffset; | ||
149 | break; | ||
150 | case m68k_fixup_vnode_shift: | ||
151 | *(u16 *)fixup->addr += m68k_virt_to_node_shift; | ||
152 | break; | ||
153 | } | ||
154 | } | ||
155 | } | ||
diff --git a/arch/m68k/kernel/module_mm.c b/arch/m68k/kernel/module_mm.c new file mode 100644 index 000000000000..cd6bcb1c957e --- /dev/null +++ b/arch/m68k/kernel/module_mm.c | |||
@@ -0,0 +1,155 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file COPYING in the main directory of this archive | ||
4 | * for more details. | ||
5 | */ | ||
6 | |||
7 | #include <linux/moduleloader.h> | ||
8 | #include <linux/elf.h> | ||
9 | #include <linux/vmalloc.h> | ||
10 | #include <linux/fs.h> | ||
11 | #include <linux/string.h> | ||
12 | #include <linux/kernel.h> | ||
13 | |||
14 | #if 0 | ||
15 | #define DEBUGP printk | ||
16 | #else | ||
17 | #define DEBUGP(fmt...) | ||
18 | #endif | ||
19 | |||
20 | #ifdef CONFIG_MODULES | ||
21 | |||
22 | void *module_alloc(unsigned long size) | ||
23 | { | ||
24 | if (size == 0) | ||
25 | return NULL; | ||
26 | return vmalloc(size); | ||
27 | } | ||
28 | |||
29 | |||
30 | /* Free memory returned from module_alloc */ | ||
31 | void module_free(struct module *mod, void *module_region) | ||
32 | { | ||
33 | vfree(module_region); | ||
34 | } | ||
35 | |||
36 | /* We don't need anything special. */ | ||
37 | int module_frob_arch_sections(Elf_Ehdr *hdr, | ||
38 | Elf_Shdr *sechdrs, | ||
39 | char *secstrings, | ||
40 | struct module *mod) | ||
41 | { | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | int apply_relocate(Elf32_Shdr *sechdrs, | ||
46 | const char *strtab, | ||
47 | unsigned int symindex, | ||
48 | unsigned int relsec, | ||
49 | struct module *me) | ||
50 | { | ||
51 | unsigned int i; | ||
52 | Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; | ||
53 | Elf32_Sym *sym; | ||
54 | uint32_t *location; | ||
55 | |||
56 | DEBUGP("Applying relocate section %u to %u\n", relsec, | ||
57 | sechdrs[relsec].sh_info); | ||
58 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { | ||
59 | /* This is where to make the change */ | ||
60 | location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr | ||
61 | + rel[i].r_offset; | ||
62 | /* This is the symbol it is referring to. Note that all | ||
63 | undefined symbols have been resolved. */ | ||
64 | sym = (Elf32_Sym *)sechdrs[symindex].sh_addr | ||
65 | + ELF32_R_SYM(rel[i].r_info); | ||
66 | |||
67 | switch (ELF32_R_TYPE(rel[i].r_info)) { | ||
68 | case R_68K_32: | ||
69 | /* We add the value into the location given */ | ||
70 | *location += sym->st_value; | ||
71 | break; | ||
72 | case R_68K_PC32: | ||
73 | /* Add the value, subtract its postition */ | ||
74 | *location += sym->st_value - (uint32_t)location; | ||
75 | break; | ||
76 | default: | ||
77 | printk(KERN_ERR "module %s: Unknown relocation: %u\n", | ||
78 | me->name, ELF32_R_TYPE(rel[i].r_info)); | ||
79 | return -ENOEXEC; | ||
80 | } | ||
81 | } | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | int apply_relocate_add(Elf32_Shdr *sechdrs, | ||
86 | const char *strtab, | ||
87 | unsigned int symindex, | ||
88 | unsigned int relsec, | ||
89 | struct module *me) | ||
90 | { | ||
91 | unsigned int i; | ||
92 | Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; | ||
93 | Elf32_Sym *sym; | ||
94 | uint32_t *location; | ||
95 | |||
96 | DEBUGP("Applying relocate_add section %u to %u\n", relsec, | ||
97 | sechdrs[relsec].sh_info); | ||
98 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { | ||
99 | /* This is where to make the change */ | ||
100 | location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr | ||
101 | + rel[i].r_offset; | ||
102 | /* This is the symbol it is referring to. Note that all | ||
103 | undefined symbols have been resolved. */ | ||
104 | sym = (Elf32_Sym *)sechdrs[symindex].sh_addr | ||
105 | + ELF32_R_SYM(rel[i].r_info); | ||
106 | |||
107 | switch (ELF32_R_TYPE(rel[i].r_info)) { | ||
108 | case R_68K_32: | ||
109 | /* We add the value into the location given */ | ||
110 | *location = rel[i].r_addend + sym->st_value; | ||
111 | break; | ||
112 | case R_68K_PC32: | ||
113 | /* Add the value, subtract its postition */ | ||
114 | *location = rel[i].r_addend + sym->st_value - (uint32_t)location; | ||
115 | break; | ||
116 | default: | ||
117 | printk(KERN_ERR "module %s: Unknown relocation: %u\n", | ||
118 | me->name, ELF32_R_TYPE(rel[i].r_info)); | ||
119 | return -ENOEXEC; | ||
120 | } | ||
121 | } | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | int module_finalize(const Elf_Ehdr *hdr, | ||
126 | const Elf_Shdr *sechdrs, | ||
127 | struct module *mod) | ||
128 | { | ||
129 | module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end); | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | void module_arch_cleanup(struct module *mod) | ||
135 | { | ||
136 | } | ||
137 | |||
138 | #endif /* CONFIG_MODULES */ | ||
139 | |||
140 | void module_fixup(struct module *mod, struct m68k_fixup_info *start, | ||
141 | struct m68k_fixup_info *end) | ||
142 | { | ||
143 | struct m68k_fixup_info *fixup; | ||
144 | |||
145 | for (fixup = start; fixup < end; fixup++) { | ||
146 | switch (fixup->type) { | ||
147 | case m68k_fixup_memoffset: | ||
148 | *(u32 *)fixup->addr = m68k_memoffset; | ||
149 | break; | ||
150 | case m68k_fixup_vnode_shift: | ||
151 | *(u16 *)fixup->addr += m68k_virt_to_node_shift; | ||
152 | break; | ||
153 | } | ||
154 | } | ||
155 | } | ||
diff --git a/arch/m68knommu/kernel/module.c b/arch/m68k/kernel/module_no.c index d11ffae7956a..d11ffae7956a 100644 --- a/arch/m68knommu/kernel/module.c +++ b/arch/m68k/kernel/module_no.c | |||
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index c2a1fc23dd75..6cf4bd6e34f8 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c | |||
@@ -1,354 +1,5 @@ | |||
1 | /* | 1 | #ifdef CONFIG_MMU |
2 | * linux/arch/m68k/kernel/process.c | 2 | #include "process_mm.c" |
3 | * | ||
4 | * Copyright (C) 1995 Hamish Macdonald | ||
5 | * | ||
6 | * 68060 fixes by Jesper Skov | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * This file handles the architecture-dependent parts of process handling.. | ||
11 | */ | ||
12 | |||
13 | #include <linux/errno.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/fs.h> | ||
20 | #include <linux/smp.h> | ||
21 | #include <linux/stddef.h> | ||
22 | #include <linux/unistd.h> | ||
23 | #include <linux/ptrace.h> | ||
24 | #include <linux/user.h> | ||
25 | #include <linux/reboot.h> | ||
26 | #include <linux/init_task.h> | ||
27 | #include <linux/mqueue.h> | ||
28 | |||
29 | #include <asm/uaccess.h> | ||
30 | #include <asm/system.h> | ||
31 | #include <asm/traps.h> | ||
32 | #include <asm/machdep.h> | ||
33 | #include <asm/setup.h> | ||
34 | #include <asm/pgtable.h> | ||
35 | |||
36 | /* | ||
37 | * Initial task/thread structure. Make this a per-architecture thing, | ||
38 | * because different architectures tend to have different | ||
39 | * alignment requirements and potentially different initial | ||
40 | * setup. | ||
41 | */ | ||
42 | static struct signal_struct init_signals = INIT_SIGNALS(init_signals); | ||
43 | static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); | ||
44 | union thread_union init_thread_union __init_task_data | ||
45 | __attribute__((aligned(THREAD_SIZE))) = | ||
46 | { INIT_THREAD_INFO(init_task) }; | ||
47 | |||
48 | /* initial task structure */ | ||
49 | struct task_struct init_task = INIT_TASK(init_task); | ||
50 | |||
51 | EXPORT_SYMBOL(init_task); | ||
52 | |||
53 | asmlinkage void ret_from_fork(void); | ||
54 | |||
55 | |||
56 | /* | ||
57 | * Return saved PC from a blocked thread | ||
58 | */ | ||
59 | unsigned long thread_saved_pc(struct task_struct *tsk) | ||
60 | { | ||
61 | struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp; | ||
62 | /* Check whether the thread is blocked in resume() */ | ||
63 | if (in_sched_functions(sw->retpc)) | ||
64 | return ((unsigned long *)sw->a6)[1]; | ||
65 | else | ||
66 | return sw->retpc; | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * The idle loop on an m68k.. | ||
71 | */ | ||
72 | static void default_idle(void) | ||
73 | { | ||
74 | if (!need_resched()) | ||
75 | #if defined(MACH_ATARI_ONLY) | ||
76 | /* block out HSYNC on the atari (falcon) */ | ||
77 | __asm__("stop #0x2200" : : : "cc"); | ||
78 | #else | 3 | #else |
79 | __asm__("stop #0x2000" : : : "cc"); | 4 | #include "process_no.c" |
80 | #endif | 5 | #endif |
81 | } | ||
82 | |||
83 | void (*idle)(void) = default_idle; | ||
84 | |||
85 | /* | ||
86 | * The idle thread. There's no useful work to be | ||
87 | * done, so just try to conserve power and have a | ||
88 | * low exit latency (ie sit in a loop waiting for | ||
89 | * somebody to say that they'd like to reschedule) | ||
90 | */ | ||
91 | void cpu_idle(void) | ||
92 | { | ||
93 | /* endless idle loop with no priority at all */ | ||
94 | while (1) { | ||
95 | while (!need_resched()) | ||
96 | idle(); | ||
97 | preempt_enable_no_resched(); | ||
98 | schedule(); | ||
99 | preempt_disable(); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | void machine_restart(char * __unused) | ||
104 | { | ||
105 | if (mach_reset) | ||
106 | mach_reset(); | ||
107 | for (;;); | ||
108 | } | ||
109 | |||
110 | void machine_halt(void) | ||
111 | { | ||
112 | if (mach_halt) | ||
113 | mach_halt(); | ||
114 | for (;;); | ||
115 | } | ||
116 | |||
117 | void machine_power_off(void) | ||
118 | { | ||
119 | if (mach_power_off) | ||
120 | mach_power_off(); | ||
121 | for (;;); | ||
122 | } | ||
123 | |||
124 | void (*pm_power_off)(void) = machine_power_off; | ||
125 | EXPORT_SYMBOL(pm_power_off); | ||
126 | |||
127 | void show_regs(struct pt_regs * regs) | ||
128 | { | ||
129 | printk("\n"); | ||
130 | printk("Format %02x Vector: %04x PC: %08lx Status: %04x %s\n", | ||
131 | regs->format, regs->vector, regs->pc, regs->sr, print_tainted()); | ||
132 | printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n", | ||
133 | regs->orig_d0, regs->d0, regs->a2, regs->a1); | ||
134 | printk("A0: %08lx D5: %08lx D4: %08lx\n", | ||
135 | regs->a0, regs->d5, regs->d4); | ||
136 | printk("D3: %08lx D2: %08lx D1: %08lx\n", | ||
137 | regs->d3, regs->d2, regs->d1); | ||
138 | if (!(regs->sr & PS_S)) | ||
139 | printk("USP: %08lx\n", rdusp()); | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | * Create a kernel thread | ||
144 | */ | ||
145 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
146 | { | ||
147 | int pid; | ||
148 | mm_segment_t fs; | ||
149 | |||
150 | fs = get_fs(); | ||
151 | set_fs (KERNEL_DS); | ||
152 | |||
153 | { | ||
154 | register long retval __asm__ ("d0"); | ||
155 | register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED; | ||
156 | |||
157 | retval = __NR_clone; | ||
158 | __asm__ __volatile__ | ||
159 | ("clrl %%d2\n\t" | ||
160 | "trap #0\n\t" /* Linux/m68k system call */ | ||
161 | "tstl %0\n\t" /* child or parent */ | ||
162 | "jne 1f\n\t" /* parent - jump */ | ||
163 | "lea %%sp@(%c7),%6\n\t" /* reload current */ | ||
164 | "movel %6@,%6\n\t" | ||
165 | "movel %3,%%sp@-\n\t" /* push argument */ | ||
166 | "jsr %4@\n\t" /* call fn */ | ||
167 | "movel %0,%%d1\n\t" /* pass exit value */ | ||
168 | "movel %2,%%d0\n\t" /* exit */ | ||
169 | "trap #0\n" | ||
170 | "1:" | ||
171 | : "+d" (retval) | ||
172 | : "i" (__NR_clone), "i" (__NR_exit), | ||
173 | "r" (arg), "a" (fn), "d" (clone_arg), "r" (current), | ||
174 | "i" (-THREAD_SIZE) | ||
175 | : "d2"); | ||
176 | |||
177 | pid = retval; | ||
178 | } | ||
179 | |||
180 | set_fs (fs); | ||
181 | return pid; | ||
182 | } | ||
183 | EXPORT_SYMBOL(kernel_thread); | ||
184 | |||
185 | void flush_thread(void) | ||
186 | { | ||
187 | unsigned long zero = 0; | ||
188 | set_fs(USER_DS); | ||
189 | current->thread.fs = __USER_DS; | ||
190 | if (!FPU_IS_EMU) | ||
191 | asm volatile (".chip 68k/68881\n\t" | ||
192 | "frestore %0@\n\t" | ||
193 | ".chip 68k" : : "a" (&zero)); | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * "m68k_fork()".. By the time we get here, the | ||
198 | * non-volatile registers have also been saved on the | ||
199 | * stack. We do some ugly pointer stuff here.. (see | ||
200 | * also copy_thread) | ||
201 | */ | ||
202 | |||
203 | asmlinkage int m68k_fork(struct pt_regs *regs) | ||
204 | { | ||
205 | return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); | ||
206 | } | ||
207 | |||
208 | asmlinkage int m68k_vfork(struct pt_regs *regs) | ||
209 | { | ||
210 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, | ||
211 | NULL, NULL); | ||
212 | } | ||
213 | |||
214 | asmlinkage int m68k_clone(struct pt_regs *regs) | ||
215 | { | ||
216 | unsigned long clone_flags; | ||
217 | unsigned long newsp; | ||
218 | int __user *parent_tidptr, *child_tidptr; | ||
219 | |||
220 | /* syscall2 puts clone_flags in d1 and usp in d2 */ | ||
221 | clone_flags = regs->d1; | ||
222 | newsp = regs->d2; | ||
223 | parent_tidptr = (int __user *)regs->d3; | ||
224 | child_tidptr = (int __user *)regs->d4; | ||
225 | if (!newsp) | ||
226 | newsp = rdusp(); | ||
227 | return do_fork(clone_flags, newsp, regs, 0, | ||
228 | parent_tidptr, child_tidptr); | ||
229 | } | ||
230 | |||
231 | int copy_thread(unsigned long clone_flags, unsigned long usp, | ||
232 | unsigned long unused, | ||
233 | struct task_struct * p, struct pt_regs * regs) | ||
234 | { | ||
235 | struct pt_regs * childregs; | ||
236 | struct switch_stack * childstack, *stack; | ||
237 | unsigned long *retp; | ||
238 | |||
239 | childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; | ||
240 | |||
241 | *childregs = *regs; | ||
242 | childregs->d0 = 0; | ||
243 | |||
244 | retp = ((unsigned long *) regs); | ||
245 | stack = ((struct switch_stack *) retp) - 1; | ||
246 | |||
247 | childstack = ((struct switch_stack *) childregs) - 1; | ||
248 | *childstack = *stack; | ||
249 | childstack->retpc = (unsigned long)ret_from_fork; | ||
250 | |||
251 | p->thread.usp = usp; | ||
252 | p->thread.ksp = (unsigned long)childstack; | ||
253 | |||
254 | if (clone_flags & CLONE_SETTLS) | ||
255 | task_thread_info(p)->tp_value = regs->d5; | ||
256 | |||
257 | /* | ||
258 | * Must save the current SFC/DFC value, NOT the value when | ||
259 | * the parent was last descheduled - RGH 10-08-96 | ||
260 | */ | ||
261 | p->thread.fs = get_fs().seg; | ||
262 | |||
263 | if (!FPU_IS_EMU) { | ||
264 | /* Copy the current fpu state */ | ||
265 | asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); | ||
266 | |||
267 | if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) | ||
268 | asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" | ||
269 | "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" | ||
270 | : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0]) | ||
271 | : "memory"); | ||
272 | /* Restore the state in case the fpu was busy */ | ||
273 | asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); | ||
274 | } | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | /* Fill in the fpu structure for a core dump. */ | ||
280 | |||
281 | int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) | ||
282 | { | ||
283 | char fpustate[216]; | ||
284 | |||
285 | if (FPU_IS_EMU) { | ||
286 | int i; | ||
287 | |||
288 | memcpy(fpu->fpcntl, current->thread.fpcntl, 12); | ||
289 | memcpy(fpu->fpregs, current->thread.fp, 96); | ||
290 | /* Convert internal fpu reg representation | ||
291 | * into long double format | ||
292 | */ | ||
293 | for (i = 0; i < 24; i += 3) | ||
294 | fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | | ||
295 | ((fpu->fpregs[i] & 0x0000ffff) << 16); | ||
296 | return 1; | ||
297 | } | ||
298 | |||
299 | /* First dump the fpu context to avoid protocol violation. */ | ||
300 | asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); | ||
301 | if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) | ||
302 | return 0; | ||
303 | |||
304 | asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" | ||
305 | :: "m" (fpu->fpcntl[0]) | ||
306 | : "memory"); | ||
307 | asm volatile ("fmovemx %/fp0-%/fp7,%0" | ||
308 | :: "m" (fpu->fpregs[0]) | ||
309 | : "memory"); | ||
310 | return 1; | ||
311 | } | ||
312 | EXPORT_SYMBOL(dump_fpu); | ||
313 | |||
314 | /* | ||
315 | * sys_execve() executes a new program. | ||
316 | */ | ||
317 | asmlinkage int sys_execve(const char __user *name, | ||
318 | const char __user *const __user *argv, | ||
319 | const char __user *const __user *envp) | ||
320 | { | ||
321 | int error; | ||
322 | char * filename; | ||
323 | struct pt_regs *regs = (struct pt_regs *) &name; | ||
324 | |||
325 | filename = getname(name); | ||
326 | error = PTR_ERR(filename); | ||
327 | if (IS_ERR(filename)) | ||
328 | return error; | ||
329 | error = do_execve(filename, argv, envp, regs); | ||
330 | putname(filename); | ||
331 | return error; | ||
332 | } | ||
333 | |||
334 | unsigned long get_wchan(struct task_struct *p) | ||
335 | { | ||
336 | unsigned long fp, pc; | ||
337 | unsigned long stack_page; | ||
338 | int count = 0; | ||
339 | if (!p || p == current || p->state == TASK_RUNNING) | ||
340 | return 0; | ||
341 | |||
342 | stack_page = (unsigned long)task_stack_page(p); | ||
343 | fp = ((struct switch_stack *)p->thread.ksp)->a6; | ||
344 | do { | ||
345 | if (fp < stack_page+sizeof(struct thread_info) || | ||
346 | fp >= 8184+stack_page) | ||
347 | return 0; | ||
348 | pc = ((unsigned long *)fp)[1]; | ||
349 | if (!in_sched_functions(pc)) | ||
350 | return pc; | ||
351 | fp = *(unsigned long *) fp; | ||
352 | } while (count++ < 16); | ||
353 | return 0; | ||
354 | } | ||
diff --git a/arch/m68k/kernel/process_mm.c b/arch/m68k/kernel/process_mm.c new file mode 100644 index 000000000000..c2a1fc23dd75 --- /dev/null +++ b/arch/m68k/kernel/process_mm.c | |||
@@ -0,0 +1,354 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/kernel/process.c | ||
3 | * | ||
4 | * Copyright (C) 1995 Hamish Macdonald | ||
5 | * | ||
6 | * 68060 fixes by Jesper Skov | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * This file handles the architecture-dependent parts of process handling.. | ||
11 | */ | ||
12 | |||
13 | #include <linux/errno.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/fs.h> | ||
20 | #include <linux/smp.h> | ||
21 | #include <linux/stddef.h> | ||
22 | #include <linux/unistd.h> | ||
23 | #include <linux/ptrace.h> | ||
24 | #include <linux/user.h> | ||
25 | #include <linux/reboot.h> | ||
26 | #include <linux/init_task.h> | ||
27 | #include <linux/mqueue.h> | ||
28 | |||
29 | #include <asm/uaccess.h> | ||
30 | #include <asm/system.h> | ||
31 | #include <asm/traps.h> | ||
32 | #include <asm/machdep.h> | ||
33 | #include <asm/setup.h> | ||
34 | #include <asm/pgtable.h> | ||
35 | |||
36 | /* | ||
37 | * Initial task/thread structure. Make this a per-architecture thing, | ||
38 | * because different architectures tend to have different | ||
39 | * alignment requirements and potentially different initial | ||
40 | * setup. | ||
41 | */ | ||
42 | static struct signal_struct init_signals = INIT_SIGNALS(init_signals); | ||
43 | static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); | ||
44 | union thread_union init_thread_union __init_task_data | ||
45 | __attribute__((aligned(THREAD_SIZE))) = | ||
46 | { INIT_THREAD_INFO(init_task) }; | ||
47 | |||
48 | /* initial task structure */ | ||
49 | struct task_struct init_task = INIT_TASK(init_task); | ||
50 | |||
51 | EXPORT_SYMBOL(init_task); | ||
52 | |||
53 | asmlinkage void ret_from_fork(void); | ||
54 | |||
55 | |||
56 | /* | ||
57 | * Return saved PC from a blocked thread | ||
58 | */ | ||
59 | unsigned long thread_saved_pc(struct task_struct *tsk) | ||
60 | { | ||
61 | struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp; | ||
62 | /* Check whether the thread is blocked in resume() */ | ||
63 | if (in_sched_functions(sw->retpc)) | ||
64 | return ((unsigned long *)sw->a6)[1]; | ||
65 | else | ||
66 | return sw->retpc; | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * The idle loop on an m68k.. | ||
71 | */ | ||
72 | static void default_idle(void) | ||
73 | { | ||
74 | if (!need_resched()) | ||
75 | #if defined(MACH_ATARI_ONLY) | ||
76 | /* block out HSYNC on the atari (falcon) */ | ||
77 | __asm__("stop #0x2200" : : : "cc"); | ||
78 | #else | ||
79 | __asm__("stop #0x2000" : : : "cc"); | ||
80 | #endif | ||
81 | } | ||
82 | |||
83 | void (*idle)(void) = default_idle; | ||
84 | |||
85 | /* | ||
86 | * The idle thread. There's no useful work to be | ||
87 | * done, so just try to conserve power and have a | ||
88 | * low exit latency (ie sit in a loop waiting for | ||
89 | * somebody to say that they'd like to reschedule) | ||
90 | */ | ||
91 | void cpu_idle(void) | ||
92 | { | ||
93 | /* endless idle loop with no priority at all */ | ||
94 | while (1) { | ||
95 | while (!need_resched()) | ||
96 | idle(); | ||
97 | preempt_enable_no_resched(); | ||
98 | schedule(); | ||
99 | preempt_disable(); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | void machine_restart(char * __unused) | ||
104 | { | ||
105 | if (mach_reset) | ||
106 | mach_reset(); | ||
107 | for (;;); | ||
108 | } | ||
109 | |||
110 | void machine_halt(void) | ||
111 | { | ||
112 | if (mach_halt) | ||
113 | mach_halt(); | ||
114 | for (;;); | ||
115 | } | ||
116 | |||
117 | void machine_power_off(void) | ||
118 | { | ||
119 | if (mach_power_off) | ||
120 | mach_power_off(); | ||
121 | for (;;); | ||
122 | } | ||
123 | |||
124 | void (*pm_power_off)(void) = machine_power_off; | ||
125 | EXPORT_SYMBOL(pm_power_off); | ||
126 | |||
127 | void show_regs(struct pt_regs * regs) | ||
128 | { | ||
129 | printk("\n"); | ||
130 | printk("Format %02x Vector: %04x PC: %08lx Status: %04x %s\n", | ||
131 | regs->format, regs->vector, regs->pc, regs->sr, print_tainted()); | ||
132 | printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n", | ||
133 | regs->orig_d0, regs->d0, regs->a2, regs->a1); | ||
134 | printk("A0: %08lx D5: %08lx D4: %08lx\n", | ||
135 | regs->a0, regs->d5, regs->d4); | ||
136 | printk("D3: %08lx D2: %08lx D1: %08lx\n", | ||
137 | regs->d3, regs->d2, regs->d1); | ||
138 | if (!(regs->sr & PS_S)) | ||
139 | printk("USP: %08lx\n", rdusp()); | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | * Create a kernel thread | ||
144 | */ | ||
145 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
146 | { | ||
147 | int pid; | ||
148 | mm_segment_t fs; | ||
149 | |||
150 | fs = get_fs(); | ||
151 | set_fs (KERNEL_DS); | ||
152 | |||
153 | { | ||
154 | register long retval __asm__ ("d0"); | ||
155 | register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED; | ||
156 | |||
157 | retval = __NR_clone; | ||
158 | __asm__ __volatile__ | ||
159 | ("clrl %%d2\n\t" | ||
160 | "trap #0\n\t" /* Linux/m68k system call */ | ||
161 | "tstl %0\n\t" /* child or parent */ | ||
162 | "jne 1f\n\t" /* parent - jump */ | ||
163 | "lea %%sp@(%c7),%6\n\t" /* reload current */ | ||
164 | "movel %6@,%6\n\t" | ||
165 | "movel %3,%%sp@-\n\t" /* push argument */ | ||
166 | "jsr %4@\n\t" /* call fn */ | ||
167 | "movel %0,%%d1\n\t" /* pass exit value */ | ||
168 | "movel %2,%%d0\n\t" /* exit */ | ||
169 | "trap #0\n" | ||
170 | "1:" | ||
171 | : "+d" (retval) | ||
172 | : "i" (__NR_clone), "i" (__NR_exit), | ||
173 | "r" (arg), "a" (fn), "d" (clone_arg), "r" (current), | ||
174 | "i" (-THREAD_SIZE) | ||
175 | : "d2"); | ||
176 | |||
177 | pid = retval; | ||
178 | } | ||
179 | |||
180 | set_fs (fs); | ||
181 | return pid; | ||
182 | } | ||
183 | EXPORT_SYMBOL(kernel_thread); | ||
184 | |||
185 | void flush_thread(void) | ||
186 | { | ||
187 | unsigned long zero = 0; | ||
188 | set_fs(USER_DS); | ||
189 | current->thread.fs = __USER_DS; | ||
190 | if (!FPU_IS_EMU) | ||
191 | asm volatile (".chip 68k/68881\n\t" | ||
192 | "frestore %0@\n\t" | ||
193 | ".chip 68k" : : "a" (&zero)); | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * "m68k_fork()".. By the time we get here, the | ||
198 | * non-volatile registers have also been saved on the | ||
199 | * stack. We do some ugly pointer stuff here.. (see | ||
200 | * also copy_thread) | ||
201 | */ | ||
202 | |||
203 | asmlinkage int m68k_fork(struct pt_regs *regs) | ||
204 | { | ||
205 | return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); | ||
206 | } | ||
207 | |||
208 | asmlinkage int m68k_vfork(struct pt_regs *regs) | ||
209 | { | ||
210 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, | ||
211 | NULL, NULL); | ||
212 | } | ||
213 | |||
214 | asmlinkage int m68k_clone(struct pt_regs *regs) | ||
215 | { | ||
216 | unsigned long clone_flags; | ||
217 | unsigned long newsp; | ||
218 | int __user *parent_tidptr, *child_tidptr; | ||
219 | |||
220 | /* syscall2 puts clone_flags in d1 and usp in d2 */ | ||
221 | clone_flags = regs->d1; | ||
222 | newsp = regs->d2; | ||
223 | parent_tidptr = (int __user *)regs->d3; | ||
224 | child_tidptr = (int __user *)regs->d4; | ||
225 | if (!newsp) | ||
226 | newsp = rdusp(); | ||
227 | return do_fork(clone_flags, newsp, regs, 0, | ||
228 | parent_tidptr, child_tidptr); | ||
229 | } | ||
230 | |||
231 | int copy_thread(unsigned long clone_flags, unsigned long usp, | ||
232 | unsigned long unused, | ||
233 | struct task_struct * p, struct pt_regs * regs) | ||
234 | { | ||
235 | struct pt_regs * childregs; | ||
236 | struct switch_stack * childstack, *stack; | ||
237 | unsigned long *retp; | ||
238 | |||
239 | childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; | ||
240 | |||
241 | *childregs = *regs; | ||
242 | childregs->d0 = 0; | ||
243 | |||
244 | retp = ((unsigned long *) regs); | ||
245 | stack = ((struct switch_stack *) retp) - 1; | ||
246 | |||
247 | childstack = ((struct switch_stack *) childregs) - 1; | ||
248 | *childstack = *stack; | ||
249 | childstack->retpc = (unsigned long)ret_from_fork; | ||
250 | |||
251 | p->thread.usp = usp; | ||
252 | p->thread.ksp = (unsigned long)childstack; | ||
253 | |||
254 | if (clone_flags & CLONE_SETTLS) | ||
255 | task_thread_info(p)->tp_value = regs->d5; | ||
256 | |||
257 | /* | ||
258 | * Must save the current SFC/DFC value, NOT the value when | ||
259 | * the parent was last descheduled - RGH 10-08-96 | ||
260 | */ | ||
261 | p->thread.fs = get_fs().seg; | ||
262 | |||
263 | if (!FPU_IS_EMU) { | ||
264 | /* Copy the current fpu state */ | ||
265 | asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); | ||
266 | |||
267 | if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) | ||
268 | asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" | ||
269 | "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" | ||
270 | : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0]) | ||
271 | : "memory"); | ||
272 | /* Restore the state in case the fpu was busy */ | ||
273 | asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); | ||
274 | } | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | /* Fill in the fpu structure for a core dump. */ | ||
280 | |||
281 | int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) | ||
282 | { | ||
283 | char fpustate[216]; | ||
284 | |||
285 | if (FPU_IS_EMU) { | ||
286 | int i; | ||
287 | |||
288 | memcpy(fpu->fpcntl, current->thread.fpcntl, 12); | ||
289 | memcpy(fpu->fpregs, current->thread.fp, 96); | ||
290 | /* Convert internal fpu reg representation | ||
291 | * into long double format | ||
292 | */ | ||
293 | for (i = 0; i < 24; i += 3) | ||
294 | fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | | ||
295 | ((fpu->fpregs[i] & 0x0000ffff) << 16); | ||
296 | return 1; | ||
297 | } | ||
298 | |||
299 | /* First dump the fpu context to avoid protocol violation. */ | ||
300 | asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); | ||
301 | if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) | ||
302 | return 0; | ||
303 | |||
304 | asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" | ||
305 | :: "m" (fpu->fpcntl[0]) | ||
306 | : "memory"); | ||
307 | asm volatile ("fmovemx %/fp0-%/fp7,%0" | ||
308 | :: "m" (fpu->fpregs[0]) | ||
309 | : "memory"); | ||
310 | return 1; | ||
311 | } | ||
312 | EXPORT_SYMBOL(dump_fpu); | ||
313 | |||
314 | /* | ||
315 | * sys_execve() executes a new program. | ||
316 | */ | ||
317 | asmlinkage int sys_execve(const char __user *name, | ||
318 | const char __user *const __user *argv, | ||
319 | const char __user *const __user *envp) | ||
320 | { | ||
321 | int error; | ||
322 | char * filename; | ||
323 | struct pt_regs *regs = (struct pt_regs *) &name; | ||
324 | |||
325 | filename = getname(name); | ||
326 | error = PTR_ERR(filename); | ||
327 | if (IS_ERR(filename)) | ||
328 | return error; | ||
329 | error = do_execve(filename, argv, envp, regs); | ||
330 | putname(filename); | ||
331 | return error; | ||
332 | } | ||
333 | |||
334 | unsigned long get_wchan(struct task_struct *p) | ||
335 | { | ||
336 | unsigned long fp, pc; | ||
337 | unsigned long stack_page; | ||
338 | int count = 0; | ||
339 | if (!p || p == current || p->state == TASK_RUNNING) | ||
340 | return 0; | ||
341 | |||
342 | stack_page = (unsigned long)task_stack_page(p); | ||
343 | fp = ((struct switch_stack *)p->thread.ksp)->a6; | ||
344 | do { | ||
345 | if (fp < stack_page+sizeof(struct thread_info) || | ||
346 | fp >= 8184+stack_page) | ||
347 | return 0; | ||
348 | pc = ((unsigned long *)fp)[1]; | ||
349 | if (!in_sched_functions(pc)) | ||
350 | return pc; | ||
351 | fp = *(unsigned long *) fp; | ||
352 | } while (count++ < 16); | ||
353 | return 0; | ||
354 | } | ||
diff --git a/arch/m68knommu/kernel/process.c b/arch/m68k/kernel/process_no.c index e2a63af5d517..e2a63af5d517 100644 --- a/arch/m68knommu/kernel/process.c +++ b/arch/m68k/kernel/process_no.c | |||
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c index 0b252683cefb..07a417550e94 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c | |||
@@ -1,277 +1,5 @@ | |||
1 | /* | 1 | #ifdef CONFIG_MMU |
2 | * linux/arch/m68k/kernel/ptrace.c | 2 | #include "ptrace_mm.c" |
3 | * | 3 | #else |
4 | * Copyright (C) 1994 by Hamish Macdonald | 4 | #include "ptrace_no.c" |
5 | * Taken from linux/kernel/ptrace.c and modified for M680x0. | 5 | #endif |
6 | * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General | ||
9 | * Public License. See the file COPYING in the main directory of | ||
10 | * this archive for more details. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/smp.h> | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/ptrace.h> | ||
19 | #include <linux/user.h> | ||
20 | #include <linux/signal.h> | ||
21 | |||
22 | #include <asm/uaccess.h> | ||
23 | #include <asm/page.h> | ||
24 | #include <asm/pgtable.h> | ||
25 | #include <asm/system.h> | ||
26 | #include <asm/processor.h> | ||
27 | |||
28 | /* | ||
29 | * does not yet catch signals sent when the child dies. | ||
30 | * in exit.c or in signal.c. | ||
31 | */ | ||
32 | |||
33 | /* determines which bits in the SR the user has access to. */ | ||
34 | /* 1 = access 0 = no access */ | ||
35 | #define SR_MASK 0x001f | ||
36 | |||
37 | /* sets the trace bits. */ | ||
38 | #define TRACE_BITS 0xC000 | ||
39 | #define T1_BIT 0x8000 | ||
40 | #define T0_BIT 0x4000 | ||
41 | |||
42 | /* Find the stack offset for a register, relative to thread.esp0. */ | ||
43 | #define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) | ||
44 | #define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \ | ||
45 | - sizeof(struct switch_stack)) | ||
46 | /* Mapping from PT_xxx to the stack offset at which the register is | ||
47 | saved. Notice that usp has no stack-slot and needs to be treated | ||
48 | specially (see get_reg/put_reg below). */ | ||
49 | static const int regoff[] = { | ||
50 | [0] = PT_REG(d1), | ||
51 | [1] = PT_REG(d2), | ||
52 | [2] = PT_REG(d3), | ||
53 | [3] = PT_REG(d4), | ||
54 | [4] = PT_REG(d5), | ||
55 | [5] = SW_REG(d6), | ||
56 | [6] = SW_REG(d7), | ||
57 | [7] = PT_REG(a0), | ||
58 | [8] = PT_REG(a1), | ||
59 | [9] = PT_REG(a2), | ||
60 | [10] = SW_REG(a3), | ||
61 | [11] = SW_REG(a4), | ||
62 | [12] = SW_REG(a5), | ||
63 | [13] = SW_REG(a6), | ||
64 | [14] = PT_REG(d0), | ||
65 | [15] = -1, | ||
66 | [16] = PT_REG(orig_d0), | ||
67 | [17] = PT_REG(sr), | ||
68 | [18] = PT_REG(pc), | ||
69 | }; | ||
70 | |||
71 | /* | ||
72 | * Get contents of register REGNO in task TASK. | ||
73 | */ | ||
74 | static inline long get_reg(struct task_struct *task, int regno) | ||
75 | { | ||
76 | unsigned long *addr; | ||
77 | |||
78 | if (regno == PT_USP) | ||
79 | addr = &task->thread.usp; | ||
80 | else if (regno < ARRAY_SIZE(regoff)) | ||
81 | addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); | ||
82 | else | ||
83 | return 0; | ||
84 | /* Need to take stkadj into account. */ | ||
85 | if (regno == PT_SR || regno == PT_PC) { | ||
86 | long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj)); | ||
87 | addr = (unsigned long *) ((unsigned long)addr + stkadj); | ||
88 | /* The sr is actually a 16 bit register. */ | ||
89 | if (regno == PT_SR) | ||
90 | return *(unsigned short *)addr; | ||
91 | } | ||
92 | return *addr; | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * Write contents of register REGNO in task TASK. | ||
97 | */ | ||
98 | static inline int put_reg(struct task_struct *task, int regno, | ||
99 | unsigned long data) | ||
100 | { | ||
101 | unsigned long *addr; | ||
102 | |||
103 | if (regno == PT_USP) | ||
104 | addr = &task->thread.usp; | ||
105 | else if (regno < ARRAY_SIZE(regoff)) | ||
106 | addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); | ||
107 | else | ||
108 | return -1; | ||
109 | /* Need to take stkadj into account. */ | ||
110 | if (regno == PT_SR || regno == PT_PC) { | ||
111 | long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj)); | ||
112 | addr = (unsigned long *) ((unsigned long)addr + stkadj); | ||
113 | /* The sr is actually a 16 bit register. */ | ||
114 | if (regno == PT_SR) { | ||
115 | *(unsigned short *)addr = data; | ||
116 | return 0; | ||
117 | } | ||
118 | } | ||
119 | *addr = data; | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * Make sure the single step bit is not set. | ||
125 | */ | ||
126 | static inline void singlestep_disable(struct task_struct *child) | ||
127 | { | ||
128 | unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; | ||
129 | put_reg(child, PT_SR, tmp); | ||
130 | clear_tsk_thread_flag(child, TIF_DELAYED_TRACE); | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * Called by kernel/ptrace.c when detaching.. | ||
135 | */ | ||
136 | void ptrace_disable(struct task_struct *child) | ||
137 | { | ||
138 | singlestep_disable(child); | ||
139 | } | ||
140 | |||
141 | void user_enable_single_step(struct task_struct *child) | ||
142 | { | ||
143 | unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; | ||
144 | put_reg(child, PT_SR, tmp | T1_BIT); | ||
145 | set_tsk_thread_flag(child, TIF_DELAYED_TRACE); | ||
146 | } | ||
147 | |||
148 | void user_enable_block_step(struct task_struct *child) | ||
149 | { | ||
150 | unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; | ||
151 | put_reg(child, PT_SR, tmp | T0_BIT); | ||
152 | } | ||
153 | |||
154 | void user_disable_single_step(struct task_struct *child) | ||
155 | { | ||
156 | singlestep_disable(child); | ||
157 | } | ||
158 | |||
159 | long arch_ptrace(struct task_struct *child, long request, | ||
160 | unsigned long addr, unsigned long data) | ||
161 | { | ||
162 | unsigned long tmp; | ||
163 | int i, ret = 0; | ||
164 | int regno = addr >> 2; /* temporary hack. */ | ||
165 | unsigned long __user *datap = (unsigned long __user *) data; | ||
166 | |||
167 | switch (request) { | ||
168 | /* read the word at location addr in the USER area. */ | ||
169 | case PTRACE_PEEKUSR: | ||
170 | if (addr & 3) | ||
171 | goto out_eio; | ||
172 | |||
173 | if (regno >= 0 && regno < 19) { | ||
174 | tmp = get_reg(child, regno); | ||
175 | } else if (regno >= 21 && regno < 49) { | ||
176 | tmp = child->thread.fp[regno - 21]; | ||
177 | /* Convert internal fpu reg representation | ||
178 | * into long double format | ||
179 | */ | ||
180 | if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) | ||
181 | tmp = ((tmp & 0xffff0000) << 15) | | ||
182 | ((tmp & 0x0000ffff) << 16); | ||
183 | } else | ||
184 | goto out_eio; | ||
185 | ret = put_user(tmp, datap); | ||
186 | break; | ||
187 | |||
188 | case PTRACE_POKEUSR: | ||
189 | /* write the word at location addr in the USER area */ | ||
190 | if (addr & 3) | ||
191 | goto out_eio; | ||
192 | |||
193 | if (regno == PT_SR) { | ||
194 | data &= SR_MASK; | ||
195 | data |= get_reg(child, PT_SR) & ~SR_MASK; | ||
196 | } | ||
197 | if (regno >= 0 && regno < 19) { | ||
198 | if (put_reg(child, regno, data)) | ||
199 | goto out_eio; | ||
200 | } else if (regno >= 21 && regno < 48) { | ||
201 | /* Convert long double format | ||
202 | * into internal fpu reg representation | ||
203 | */ | ||
204 | if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) { | ||
205 | data <<= 15; | ||
206 | data = (data & 0xffff0000) | | ||
207 | ((data & 0x0000ffff) >> 1); | ||
208 | } | ||
209 | child->thread.fp[regno - 21] = data; | ||
210 | } else | ||
211 | goto out_eio; | ||
212 | break; | ||
213 | |||
214 | case PTRACE_GETREGS: /* Get all gp regs from the child. */ | ||
215 | for (i = 0; i < 19; i++) { | ||
216 | tmp = get_reg(child, i); | ||
217 | ret = put_user(tmp, datap); | ||
218 | if (ret) | ||
219 | break; | ||
220 | datap++; | ||
221 | } | ||
222 | break; | ||
223 | |||
224 | case PTRACE_SETREGS: /* Set all gp regs in the child. */ | ||
225 | for (i = 0; i < 19; i++) { | ||
226 | ret = get_user(tmp, datap); | ||
227 | if (ret) | ||
228 | break; | ||
229 | if (i == PT_SR) { | ||
230 | tmp &= SR_MASK; | ||
231 | tmp |= get_reg(child, PT_SR) & ~SR_MASK; | ||
232 | } | ||
233 | put_reg(child, i, tmp); | ||
234 | datap++; | ||
235 | } | ||
236 | break; | ||
237 | |||
238 | case PTRACE_GETFPREGS: /* Get the child FPU state. */ | ||
239 | if (copy_to_user(datap, &child->thread.fp, | ||
240 | sizeof(struct user_m68kfp_struct))) | ||
241 | ret = -EFAULT; | ||
242 | break; | ||
243 | |||
244 | case PTRACE_SETFPREGS: /* Set the child FPU state. */ | ||
245 | if (copy_from_user(&child->thread.fp, datap, | ||
246 | sizeof(struct user_m68kfp_struct))) | ||
247 | ret = -EFAULT; | ||
248 | break; | ||
249 | |||
250 | case PTRACE_GET_THREAD_AREA: | ||
251 | ret = put_user(task_thread_info(child)->tp_value, datap); | ||
252 | break; | ||
253 | |||
254 | default: | ||
255 | ret = ptrace_request(child, request, addr, data); | ||
256 | break; | ||
257 | } | ||
258 | |||
259 | return ret; | ||
260 | out_eio: | ||
261 | return -EIO; | ||
262 | } | ||
263 | |||
264 | asmlinkage void syscall_trace(void) | ||
265 | { | ||
266 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) | ||
267 | ? 0x80 : 0)); | ||
268 | /* | ||
269 | * this isn't the same as continuing with a signal, but it will do | ||
270 | * for normal use. strace only continues with a signal if the | ||
271 | * stopping signal is not SIGTRAP. -brl | ||
272 | */ | ||
273 | if (current->exit_code) { | ||
274 | send_sig(current->exit_code, current, 1); | ||
275 | current->exit_code = 0; | ||
276 | } | ||
277 | } | ||
diff --git a/arch/m68k/kernel/ptrace_mm.c b/arch/m68k/kernel/ptrace_mm.c new file mode 100644 index 000000000000..0b252683cefb --- /dev/null +++ b/arch/m68k/kernel/ptrace_mm.c | |||
@@ -0,0 +1,277 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/kernel/ptrace.c | ||
3 | * | ||
4 | * Copyright (C) 1994 by Hamish Macdonald | ||
5 | * Taken from linux/kernel/ptrace.c and modified for M680x0. | ||
6 | * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General | ||
9 | * Public License. See the file COPYING in the main directory of | ||
10 | * this archive for more details. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/smp.h> | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/ptrace.h> | ||
19 | #include <linux/user.h> | ||
20 | #include <linux/signal.h> | ||
21 | |||
22 | #include <asm/uaccess.h> | ||
23 | #include <asm/page.h> | ||
24 | #include <asm/pgtable.h> | ||
25 | #include <asm/system.h> | ||
26 | #include <asm/processor.h> | ||
27 | |||
28 | /* | ||
29 | * does not yet catch signals sent when the child dies. | ||
30 | * in exit.c or in signal.c. | ||
31 | */ | ||
32 | |||
33 | /* determines which bits in the SR the user has access to. */ | ||
34 | /* 1 = access 0 = no access */ | ||
35 | #define SR_MASK 0x001f | ||
36 | |||
37 | /* sets the trace bits. */ | ||
38 | #define TRACE_BITS 0xC000 | ||
39 | #define T1_BIT 0x8000 | ||
40 | #define T0_BIT 0x4000 | ||
41 | |||
42 | /* Find the stack offset for a register, relative to thread.esp0. */ | ||
43 | #define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) | ||
44 | #define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \ | ||
45 | - sizeof(struct switch_stack)) | ||
46 | /* Mapping from PT_xxx to the stack offset at which the register is | ||
47 | saved. Notice that usp has no stack-slot and needs to be treated | ||
48 | specially (see get_reg/put_reg below). */ | ||
49 | static const int regoff[] = { | ||
50 | [0] = PT_REG(d1), | ||
51 | [1] = PT_REG(d2), | ||
52 | [2] = PT_REG(d3), | ||
53 | [3] = PT_REG(d4), | ||
54 | [4] = PT_REG(d5), | ||
55 | [5] = SW_REG(d6), | ||
56 | [6] = SW_REG(d7), | ||
57 | [7] = PT_REG(a0), | ||
58 | [8] = PT_REG(a1), | ||
59 | [9] = PT_REG(a2), | ||
60 | [10] = SW_REG(a3), | ||
61 | [11] = SW_REG(a4), | ||
62 | [12] = SW_REG(a5), | ||
63 | [13] = SW_REG(a6), | ||
64 | [14] = PT_REG(d0), | ||
65 | [15] = -1, | ||
66 | [16] = PT_REG(orig_d0), | ||
67 | [17] = PT_REG(sr), | ||
68 | [18] = PT_REG(pc), | ||
69 | }; | ||
70 | |||
71 | /* | ||
72 | * Get contents of register REGNO in task TASK. | ||
73 | */ | ||
74 | static inline long get_reg(struct task_struct *task, int regno) | ||
75 | { | ||
76 | unsigned long *addr; | ||
77 | |||
78 | if (regno == PT_USP) | ||
79 | addr = &task->thread.usp; | ||
80 | else if (regno < ARRAY_SIZE(regoff)) | ||
81 | addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); | ||
82 | else | ||
83 | return 0; | ||
84 | /* Need to take stkadj into account. */ | ||
85 | if (regno == PT_SR || regno == PT_PC) { | ||
86 | long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj)); | ||
87 | addr = (unsigned long *) ((unsigned long)addr + stkadj); | ||
88 | /* The sr is actually a 16 bit register. */ | ||
89 | if (regno == PT_SR) | ||
90 | return *(unsigned short *)addr; | ||
91 | } | ||
92 | return *addr; | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * Write contents of register REGNO in task TASK. | ||
97 | */ | ||
98 | static inline int put_reg(struct task_struct *task, int regno, | ||
99 | unsigned long data) | ||
100 | { | ||
101 | unsigned long *addr; | ||
102 | |||
103 | if (regno == PT_USP) | ||
104 | addr = &task->thread.usp; | ||
105 | else if (regno < ARRAY_SIZE(regoff)) | ||
106 | addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); | ||
107 | else | ||
108 | return -1; | ||
109 | /* Need to take stkadj into account. */ | ||
110 | if (regno == PT_SR || regno == PT_PC) { | ||
111 | long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj)); | ||
112 | addr = (unsigned long *) ((unsigned long)addr + stkadj); | ||
113 | /* The sr is actually a 16 bit register. */ | ||
114 | if (regno == PT_SR) { | ||
115 | *(unsigned short *)addr = data; | ||
116 | return 0; | ||
117 | } | ||
118 | } | ||
119 | *addr = data; | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * Make sure the single step bit is not set. | ||
125 | */ | ||
126 | static inline void singlestep_disable(struct task_struct *child) | ||
127 | { | ||
128 | unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; | ||
129 | put_reg(child, PT_SR, tmp); | ||
130 | clear_tsk_thread_flag(child, TIF_DELAYED_TRACE); | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * Called by kernel/ptrace.c when detaching.. | ||
135 | */ | ||
136 | void ptrace_disable(struct task_struct *child) | ||
137 | { | ||
138 | singlestep_disable(child); | ||
139 | } | ||
140 | |||
141 | void user_enable_single_step(struct task_struct *child) | ||
142 | { | ||
143 | unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; | ||
144 | put_reg(child, PT_SR, tmp | T1_BIT); | ||
145 | set_tsk_thread_flag(child, TIF_DELAYED_TRACE); | ||
146 | } | ||
147 | |||
148 | void user_enable_block_step(struct task_struct *child) | ||
149 | { | ||
150 | unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; | ||
151 | put_reg(child, PT_SR, tmp | T0_BIT); | ||
152 | } | ||
153 | |||
154 | void user_disable_single_step(struct task_struct *child) | ||
155 | { | ||
156 | singlestep_disable(child); | ||
157 | } | ||
158 | |||
159 | long arch_ptrace(struct task_struct *child, long request, | ||
160 | unsigned long addr, unsigned long data) | ||
161 | { | ||
162 | unsigned long tmp; | ||
163 | int i, ret = 0; | ||
164 | int regno = addr >> 2; /* temporary hack. */ | ||
165 | unsigned long __user *datap = (unsigned long __user *) data; | ||
166 | |||
167 | switch (request) { | ||
168 | /* read the word at location addr in the USER area. */ | ||
169 | case PTRACE_PEEKUSR: | ||
170 | if (addr & 3) | ||
171 | goto out_eio; | ||
172 | |||
173 | if (regno >= 0 && regno < 19) { | ||
174 | tmp = get_reg(child, regno); | ||
175 | } else if (regno >= 21 && regno < 49) { | ||
176 | tmp = child->thread.fp[regno - 21]; | ||
177 | /* Convert internal fpu reg representation | ||
178 | * into long double format | ||
179 | */ | ||
180 | if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) | ||
181 | tmp = ((tmp & 0xffff0000) << 15) | | ||
182 | ((tmp & 0x0000ffff) << 16); | ||
183 | } else | ||
184 | goto out_eio; | ||
185 | ret = put_user(tmp, datap); | ||
186 | break; | ||
187 | |||
188 | case PTRACE_POKEUSR: | ||
189 | /* write the word at location addr in the USER area */ | ||
190 | if (addr & 3) | ||
191 | goto out_eio; | ||
192 | |||
193 | if (regno == PT_SR) { | ||
194 | data &= SR_MASK; | ||
195 | data |= get_reg(child, PT_SR) & ~SR_MASK; | ||
196 | } | ||
197 | if (regno >= 0 && regno < 19) { | ||
198 | if (put_reg(child, regno, data)) | ||
199 | goto out_eio; | ||
200 | } else if (regno >= 21 && regno < 48) { | ||
201 | /* Convert long double format | ||
202 | * into internal fpu reg representation | ||
203 | */ | ||
204 | if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) { | ||
205 | data <<= 15; | ||
206 | data = (data & 0xffff0000) | | ||
207 | ((data & 0x0000ffff) >> 1); | ||
208 | } | ||
209 | child->thread.fp[regno - 21] = data; | ||
210 | } else | ||
211 | goto out_eio; | ||
212 | break; | ||
213 | |||
214 | case PTRACE_GETREGS: /* Get all gp regs from the child. */ | ||
215 | for (i = 0; i < 19; i++) { | ||
216 | tmp = get_reg(child, i); | ||
217 | ret = put_user(tmp, datap); | ||
218 | if (ret) | ||
219 | break; | ||
220 | datap++; | ||
221 | } | ||
222 | break; | ||
223 | |||
224 | case PTRACE_SETREGS: /* Set all gp regs in the child. */ | ||
225 | for (i = 0; i < 19; i++) { | ||
226 | ret = get_user(tmp, datap); | ||
227 | if (ret) | ||
228 | break; | ||
229 | if (i == PT_SR) { | ||
230 | tmp &= SR_MASK; | ||
231 | tmp |= get_reg(child, PT_SR) & ~SR_MASK; | ||
232 | } | ||
233 | put_reg(child, i, tmp); | ||
234 | datap++; | ||
235 | } | ||
236 | break; | ||
237 | |||
238 | case PTRACE_GETFPREGS: /* Get the child FPU state. */ | ||
239 | if (copy_to_user(datap, &child->thread.fp, | ||
240 | sizeof(struct user_m68kfp_struct))) | ||
241 | ret = -EFAULT; | ||
242 | break; | ||
243 | |||
244 | case PTRACE_SETFPREGS: /* Set the child FPU state. */ | ||
245 | if (copy_from_user(&child->thread.fp, datap, | ||
246 | sizeof(struct user_m68kfp_struct))) | ||
247 | ret = -EFAULT; | ||
248 | break; | ||
249 | |||
250 | case PTRACE_GET_THREAD_AREA: | ||
251 | ret = put_user(task_thread_info(child)->tp_value, datap); | ||
252 | break; | ||
253 | |||
254 | default: | ||
255 | ret = ptrace_request(child, request, addr, data); | ||
256 | break; | ||
257 | } | ||
258 | |||
259 | return ret; | ||
260 | out_eio: | ||
261 | return -EIO; | ||
262 | } | ||
263 | |||
264 | asmlinkage void syscall_trace(void) | ||
265 | { | ||
266 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) | ||
267 | ? 0x80 : 0)); | ||
268 | /* | ||
269 | * this isn't the same as continuing with a signal, but it will do | ||
270 | * for normal use. strace only continues with a signal if the | ||
271 | * stopping signal is not SIGTRAP. -brl | ||
272 | */ | ||
273 | if (current->exit_code) { | ||
274 | send_sig(current->exit_code, current, 1); | ||
275 | current->exit_code = 0; | ||
276 | } | ||
277 | } | ||
diff --git a/arch/m68knommu/kernel/ptrace.c b/arch/m68k/kernel/ptrace_no.c index 6709fb707335..6709fb707335 100644 --- a/arch/m68knommu/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace_no.c | |||
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c index 334d83640376..4bf129f1d2e2 100644 --- a/arch/m68k/kernel/setup.c +++ b/arch/m68k/kernel/setup.c | |||
@@ -1,533 +1,5 @@ | |||
1 | /* | 1 | #ifdef CONFIG_MMU |
2 | * linux/arch/m68k/kernel/setup.c | 2 | #include "setup_mm.c" |
3 | * | ||
4 | * Copyright (C) 1995 Hamish Macdonald | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * This file handles the architecture-dependent parts of system setup | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/mm.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/fs.h> | ||
17 | #include <linux/console.h> | ||
18 | #include <linux/genhd.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/bootmem.h> | ||
23 | #include <linux/proc_fs.h> | ||
24 | #include <linux/seq_file.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/initrd.h> | ||
27 | |||
28 | #include <asm/bootinfo.h> | ||
29 | #include <asm/sections.h> | ||
30 | #include <asm/setup.h> | ||
31 | #include <asm/fpu.h> | ||
32 | #include <asm/irq.h> | ||
33 | #include <asm/io.h> | ||
34 | #include <asm/machdep.h> | ||
35 | #ifdef CONFIG_AMIGA | ||
36 | #include <asm/amigahw.h> | ||
37 | #endif | ||
38 | #ifdef CONFIG_ATARI | ||
39 | #include <asm/atarihw.h> | ||
40 | #include <asm/atari_stram.h> | ||
41 | #endif | ||
42 | #ifdef CONFIG_SUN3X | ||
43 | #include <asm/dvma.h> | ||
44 | #endif | ||
45 | #include <asm/natfeat.h> | ||
46 | |||
47 | #if !FPSTATESIZE || !NR_IRQS | ||
48 | #warning No CPU/platform type selected, your kernel will not work! | ||
49 | #warning Are you building an allnoconfig kernel? | ||
50 | #endif | ||
51 | |||
52 | unsigned long m68k_machtype; | ||
53 | EXPORT_SYMBOL(m68k_machtype); | ||
54 | unsigned long m68k_cputype; | ||
55 | EXPORT_SYMBOL(m68k_cputype); | ||
56 | unsigned long m68k_fputype; | ||
57 | unsigned long m68k_mmutype; | ||
58 | EXPORT_SYMBOL(m68k_mmutype); | ||
59 | #ifdef CONFIG_VME | ||
60 | unsigned long vme_brdtype; | ||
61 | EXPORT_SYMBOL(vme_brdtype); | ||
62 | #endif | ||
63 | |||
64 | int m68k_is040or060; | ||
65 | EXPORT_SYMBOL(m68k_is040or060); | ||
66 | |||
67 | extern unsigned long availmem; | ||
68 | |||
69 | int m68k_num_memory; | ||
70 | EXPORT_SYMBOL(m68k_num_memory); | ||
71 | int m68k_realnum_memory; | ||
72 | EXPORT_SYMBOL(m68k_realnum_memory); | ||
73 | unsigned long m68k_memoffset; | ||
74 | struct mem_info m68k_memory[NUM_MEMINFO]; | ||
75 | EXPORT_SYMBOL(m68k_memory); | ||
76 | |||
77 | struct mem_info m68k_ramdisk; | ||
78 | |||
79 | static char m68k_command_line[CL_SIZE]; | ||
80 | |||
81 | void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL; | ||
82 | /* machine dependent irq functions */ | ||
83 | void (*mach_init_IRQ) (void) __initdata = NULL; | ||
84 | void (*mach_get_model) (char *model); | ||
85 | void (*mach_get_hardware_list) (struct seq_file *m); | ||
86 | /* machine dependent timer functions */ | ||
87 | unsigned long (*mach_gettimeoffset) (void); | ||
88 | int (*mach_hwclk) (int, struct rtc_time*); | ||
89 | EXPORT_SYMBOL(mach_hwclk); | ||
90 | int (*mach_set_clock_mmss) (unsigned long); | ||
91 | unsigned int (*mach_get_ss)(void); | ||
92 | int (*mach_get_rtc_pll)(struct rtc_pll_info *); | ||
93 | int (*mach_set_rtc_pll)(struct rtc_pll_info *); | ||
94 | EXPORT_SYMBOL(mach_get_ss); | ||
95 | EXPORT_SYMBOL(mach_get_rtc_pll); | ||
96 | EXPORT_SYMBOL(mach_set_rtc_pll); | ||
97 | void (*mach_reset)( void ); | ||
98 | void (*mach_halt)( void ); | ||
99 | void (*mach_power_off)( void ); | ||
100 | long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */ | ||
101 | #ifdef CONFIG_HEARTBEAT | ||
102 | void (*mach_heartbeat) (int); | ||
103 | EXPORT_SYMBOL(mach_heartbeat); | ||
104 | #endif | ||
105 | #ifdef CONFIG_M68K_L2_CACHE | ||
106 | void (*mach_l2_flush) (int); | ||
107 | #endif | ||
108 | #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) | ||
109 | void (*mach_beep)(unsigned int, unsigned int); | ||
110 | EXPORT_SYMBOL(mach_beep); | ||
111 | #endif | ||
112 | #if defined(CONFIG_ISA) && defined(MULTI_ISA) | ||
113 | int isa_type; | ||
114 | int isa_sex; | ||
115 | EXPORT_SYMBOL(isa_type); | ||
116 | EXPORT_SYMBOL(isa_sex); | ||
117 | #endif | ||
118 | |||
119 | extern int amiga_parse_bootinfo(const struct bi_record *); | ||
120 | extern int atari_parse_bootinfo(const struct bi_record *); | ||
121 | extern int mac_parse_bootinfo(const struct bi_record *); | ||
122 | extern int q40_parse_bootinfo(const struct bi_record *); | ||
123 | extern int bvme6000_parse_bootinfo(const struct bi_record *); | ||
124 | extern int mvme16x_parse_bootinfo(const struct bi_record *); | ||
125 | extern int mvme147_parse_bootinfo(const struct bi_record *); | ||
126 | extern int hp300_parse_bootinfo(const struct bi_record *); | ||
127 | extern int apollo_parse_bootinfo(const struct bi_record *); | ||
128 | |||
129 | extern void config_amiga(void); | ||
130 | extern void config_atari(void); | ||
131 | extern void config_mac(void); | ||
132 | extern void config_sun3(void); | ||
133 | extern void config_apollo(void); | ||
134 | extern void config_mvme147(void); | ||
135 | extern void config_mvme16x(void); | ||
136 | extern void config_bvme6000(void); | ||
137 | extern void config_hp300(void); | ||
138 | extern void config_q40(void); | ||
139 | extern void config_sun3x(void); | ||
140 | |||
141 | #define MASK_256K 0xfffc0000 | ||
142 | |||
143 | extern void paging_init(void); | ||
144 | |||
145 | static void __init m68k_parse_bootinfo(const struct bi_record *record) | ||
146 | { | ||
147 | while (record->tag != BI_LAST) { | ||
148 | int unknown = 0; | ||
149 | const unsigned long *data = record->data; | ||
150 | |||
151 | switch (record->tag) { | ||
152 | case BI_MACHTYPE: | ||
153 | case BI_CPUTYPE: | ||
154 | case BI_FPUTYPE: | ||
155 | case BI_MMUTYPE: | ||
156 | /* Already set up by head.S */ | ||
157 | break; | ||
158 | |||
159 | case BI_MEMCHUNK: | ||
160 | if (m68k_num_memory < NUM_MEMINFO) { | ||
161 | m68k_memory[m68k_num_memory].addr = data[0]; | ||
162 | m68k_memory[m68k_num_memory].size = data[1]; | ||
163 | m68k_num_memory++; | ||
164 | } else | ||
165 | printk("m68k_parse_bootinfo: too many memory chunks\n"); | ||
166 | break; | ||
167 | |||
168 | case BI_RAMDISK: | ||
169 | m68k_ramdisk.addr = data[0]; | ||
170 | m68k_ramdisk.size = data[1]; | ||
171 | break; | ||
172 | |||
173 | case BI_COMMAND_LINE: | ||
174 | strlcpy(m68k_command_line, (const char *)data, | ||
175 | sizeof(m68k_command_line)); | ||
176 | break; | ||
177 | |||
178 | default: | ||
179 | if (MACH_IS_AMIGA) | ||
180 | unknown = amiga_parse_bootinfo(record); | ||
181 | else if (MACH_IS_ATARI) | ||
182 | unknown = atari_parse_bootinfo(record); | ||
183 | else if (MACH_IS_MAC) | ||
184 | unknown = mac_parse_bootinfo(record); | ||
185 | else if (MACH_IS_Q40) | ||
186 | unknown = q40_parse_bootinfo(record); | ||
187 | else if (MACH_IS_BVME6000) | ||
188 | unknown = bvme6000_parse_bootinfo(record); | ||
189 | else if (MACH_IS_MVME16x) | ||
190 | unknown = mvme16x_parse_bootinfo(record); | ||
191 | else if (MACH_IS_MVME147) | ||
192 | unknown = mvme147_parse_bootinfo(record); | ||
193 | else if (MACH_IS_HP300) | ||
194 | unknown = hp300_parse_bootinfo(record); | ||
195 | else if (MACH_IS_APOLLO) | ||
196 | unknown = apollo_parse_bootinfo(record); | ||
197 | else | ||
198 | unknown = 1; | ||
199 | } | ||
200 | if (unknown) | ||
201 | printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n", | ||
202 | record->tag); | ||
203 | record = (struct bi_record *)((unsigned long)record + | ||
204 | record->size); | ||
205 | } | ||
206 | |||
207 | m68k_realnum_memory = m68k_num_memory; | ||
208 | #ifdef CONFIG_SINGLE_MEMORY_CHUNK | ||
209 | if (m68k_num_memory > 1) { | ||
210 | printk("Ignoring last %i chunks of physical memory\n", | ||
211 | (m68k_num_memory - 1)); | ||
212 | m68k_num_memory = 1; | ||
213 | } | ||
214 | #endif | ||
215 | } | ||
216 | |||
217 | void __init setup_arch(char **cmdline_p) | ||
218 | { | ||
219 | int i; | ||
220 | |||
221 | /* The bootinfo is located right after the kernel bss */ | ||
222 | m68k_parse_bootinfo((const struct bi_record *)_end); | ||
223 | |||
224 | if (CPU_IS_040) | ||
225 | m68k_is040or060 = 4; | ||
226 | else if (CPU_IS_060) | ||
227 | m68k_is040or060 = 6; | ||
228 | |||
229 | /* FIXME: m68k_fputype is passed in by Penguin booter, which can | ||
230 | * be confused by software FPU emulation. BEWARE. | ||
231 | * We should really do our own FPU check at startup. | ||
232 | * [what do we do with buggy 68LC040s? if we have problems | ||
233 | * with them, we should add a test to check_bugs() below] */ | ||
234 | #ifndef CONFIG_M68KFPU_EMU_ONLY | ||
235 | /* clear the fpu if we have one */ | ||
236 | if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) { | ||
237 | volatile int zero = 0; | ||
238 | asm volatile ("frestore %0" : : "m" (zero)); | ||
239 | } | ||
240 | #endif | ||
241 | |||
242 | if (CPU_IS_060) { | ||
243 | u32 pcr; | ||
244 | |||
245 | asm (".chip 68060; movec %%pcr,%0; .chip 68k" | ||
246 | : "=d" (pcr)); | ||
247 | if (((pcr >> 8) & 0xff) <= 5) { | ||
248 | printk("Enabling workaround for errata I14\n"); | ||
249 | asm (".chip 68060; movec %0,%%pcr; .chip 68k" | ||
250 | : : "d" (pcr | 0x20)); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | init_mm.start_code = PAGE_OFFSET; | ||
255 | init_mm.end_code = (unsigned long)_etext; | ||
256 | init_mm.end_data = (unsigned long)_edata; | ||
257 | init_mm.brk = (unsigned long)_end; | ||
258 | |||
259 | *cmdline_p = m68k_command_line; | ||
260 | memcpy(boot_command_line, *cmdline_p, CL_SIZE); | ||
261 | |||
262 | parse_early_param(); | ||
263 | |||
264 | #ifdef CONFIG_DUMMY_CONSOLE | ||
265 | conswitchp = &dummy_con; | ||
266 | #endif | ||
267 | |||
268 | switch (m68k_machtype) { | ||
269 | #ifdef CONFIG_AMIGA | ||
270 | case MACH_AMIGA: | ||
271 | config_amiga(); | ||
272 | break; | ||
273 | #endif | ||
274 | #ifdef CONFIG_ATARI | ||
275 | case MACH_ATARI: | ||
276 | config_atari(); | ||
277 | break; | ||
278 | #endif | ||
279 | #ifdef CONFIG_MAC | ||
280 | case MACH_MAC: | ||
281 | config_mac(); | ||
282 | break; | ||
283 | #endif | ||
284 | #ifdef CONFIG_SUN3 | ||
285 | case MACH_SUN3: | ||
286 | config_sun3(); | ||
287 | break; | ||
288 | #endif | ||
289 | #ifdef CONFIG_APOLLO | ||
290 | case MACH_APOLLO: | ||
291 | config_apollo(); | ||
292 | break; | ||
293 | #endif | ||
294 | #ifdef CONFIG_MVME147 | ||
295 | case MACH_MVME147: | ||
296 | config_mvme147(); | ||
297 | break; | ||
298 | #endif | ||
299 | #ifdef CONFIG_MVME16x | ||
300 | case MACH_MVME16x: | ||
301 | config_mvme16x(); | ||
302 | break; | ||
303 | #endif | ||
304 | #ifdef CONFIG_BVME6000 | ||
305 | case MACH_BVME6000: | ||
306 | config_bvme6000(); | ||
307 | break; | ||
308 | #endif | ||
309 | #ifdef CONFIG_HP300 | ||
310 | case MACH_HP300: | ||
311 | config_hp300(); | ||
312 | break; | ||
313 | #endif | ||
314 | #ifdef CONFIG_Q40 | ||
315 | case MACH_Q40: | ||
316 | config_q40(); | ||
317 | break; | ||
318 | #endif | ||
319 | #ifdef CONFIG_SUN3X | ||
320 | case MACH_SUN3X: | ||
321 | config_sun3x(); | ||
322 | break; | ||
323 | #endif | ||
324 | default: | ||
325 | panic("No configuration setup"); | ||
326 | } | ||
327 | |||
328 | #ifdef CONFIG_NATFEAT | ||
329 | nf_init(); | ||
330 | #endif | ||
331 | |||
332 | paging_init(); | ||
333 | |||
334 | #ifndef CONFIG_SUN3 | ||
335 | for (i = 1; i < m68k_num_memory; i++) | ||
336 | free_bootmem_node(NODE_DATA(i), m68k_memory[i].addr, | ||
337 | m68k_memory[i].size); | ||
338 | #ifdef CONFIG_BLK_DEV_INITRD | ||
339 | if (m68k_ramdisk.size) { | ||
340 | reserve_bootmem_node(__virt_to_node(phys_to_virt(m68k_ramdisk.addr)), | ||
341 | m68k_ramdisk.addr, m68k_ramdisk.size, | ||
342 | BOOTMEM_DEFAULT); | ||
343 | initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr); | ||
344 | initrd_end = initrd_start + m68k_ramdisk.size; | ||
345 | printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end); | ||
346 | } | ||
347 | #endif | ||
348 | |||
349 | #ifdef CONFIG_ATARI | ||
350 | if (MACH_IS_ATARI) | ||
351 | atari_stram_reserve_pages((void *)availmem); | ||
352 | #endif | ||
353 | #ifdef CONFIG_SUN3X | ||
354 | if (MACH_IS_SUN3X) { | ||
355 | dvma_init(); | ||
356 | } | ||
357 | #endif | ||
358 | |||
359 | #endif /* !CONFIG_SUN3 */ | ||
360 | |||
361 | /* set ISA defs early as possible */ | ||
362 | #if defined(CONFIG_ISA) && defined(MULTI_ISA) | ||
363 | if (MACH_IS_Q40) { | ||
364 | isa_type = ISA_TYPE_Q40; | ||
365 | isa_sex = 0; | ||
366 | } | ||
367 | #ifdef CONFIG_AMIGA_PCMCIA | ||
368 | if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)) { | ||
369 | isa_type = ISA_TYPE_AG; | ||
370 | isa_sex = 1; | ||
371 | } | ||
372 | #endif | ||
373 | #endif | ||
374 | } | ||
375 | |||
376 | static int show_cpuinfo(struct seq_file *m, void *v) | ||
377 | { | ||
378 | const char *cpu, *mmu, *fpu; | ||
379 | unsigned long clockfreq, clockfactor; | ||
380 | |||
381 | #define LOOP_CYCLES_68020 (8) | ||
382 | #define LOOP_CYCLES_68030 (8) | ||
383 | #define LOOP_CYCLES_68040 (3) | ||
384 | #define LOOP_CYCLES_68060 (1) | ||
385 | |||
386 | if (CPU_IS_020) { | ||
387 | cpu = "68020"; | ||
388 | clockfactor = LOOP_CYCLES_68020; | ||
389 | } else if (CPU_IS_030) { | ||
390 | cpu = "68030"; | ||
391 | clockfactor = LOOP_CYCLES_68030; | ||
392 | } else if (CPU_IS_040) { | ||
393 | cpu = "68040"; | ||
394 | clockfactor = LOOP_CYCLES_68040; | ||
395 | } else if (CPU_IS_060) { | ||
396 | cpu = "68060"; | ||
397 | clockfactor = LOOP_CYCLES_68060; | ||
398 | } else { | ||
399 | cpu = "680x0"; | ||
400 | clockfactor = 0; | ||
401 | } | ||
402 | |||
403 | #ifdef CONFIG_M68KFPU_EMU_ONLY | ||
404 | fpu = "none(soft float)"; | ||
405 | #else | 3 | #else |
406 | if (m68k_fputype & FPU_68881) | 4 | #include "setup_no.c" |
407 | fpu = "68881"; | ||
408 | else if (m68k_fputype & FPU_68882) | ||
409 | fpu = "68882"; | ||
410 | else if (m68k_fputype & FPU_68040) | ||
411 | fpu = "68040"; | ||
412 | else if (m68k_fputype & FPU_68060) | ||
413 | fpu = "68060"; | ||
414 | else if (m68k_fputype & FPU_SUNFPA) | ||
415 | fpu = "Sun FPA"; | ||
416 | else | ||
417 | fpu = "none"; | ||
418 | #endif | ||
419 | |||
420 | if (m68k_mmutype & MMU_68851) | ||
421 | mmu = "68851"; | ||
422 | else if (m68k_mmutype & MMU_68030) | ||
423 | mmu = "68030"; | ||
424 | else if (m68k_mmutype & MMU_68040) | ||
425 | mmu = "68040"; | ||
426 | else if (m68k_mmutype & MMU_68060) | ||
427 | mmu = "68060"; | ||
428 | else if (m68k_mmutype & MMU_SUN3) | ||
429 | mmu = "Sun-3"; | ||
430 | else if (m68k_mmutype & MMU_APOLLO) | ||
431 | mmu = "Apollo"; | ||
432 | else | ||
433 | mmu = "unknown"; | ||
434 | |||
435 | clockfreq = loops_per_jiffy * HZ * clockfactor; | ||
436 | |||
437 | seq_printf(m, "CPU:\t\t%s\n" | ||
438 | "MMU:\t\t%s\n" | ||
439 | "FPU:\t\t%s\n" | ||
440 | "Clocking:\t%lu.%1luMHz\n" | ||
441 | "BogoMips:\t%lu.%02lu\n" | ||
442 | "Calibration:\t%lu loops\n", | ||
443 | cpu, mmu, fpu, | ||
444 | clockfreq/1000000,(clockfreq/100000)%10, | ||
445 | loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ))%100, | ||
446 | loops_per_jiffy); | ||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | static void *c_start(struct seq_file *m, loff_t *pos) | ||
451 | { | ||
452 | return *pos < 1 ? (void *)1 : NULL; | ||
453 | } | ||
454 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | ||
455 | { | ||
456 | ++*pos; | ||
457 | return NULL; | ||
458 | } | ||
459 | static void c_stop(struct seq_file *m, void *v) | ||
460 | { | ||
461 | } | ||
462 | const struct seq_operations cpuinfo_op = { | ||
463 | .start = c_start, | ||
464 | .next = c_next, | ||
465 | .stop = c_stop, | ||
466 | .show = show_cpuinfo, | ||
467 | }; | ||
468 | |||
469 | #ifdef CONFIG_PROC_HARDWARE | ||
470 | static int hardware_proc_show(struct seq_file *m, void *v) | ||
471 | { | ||
472 | char model[80]; | ||
473 | unsigned long mem; | ||
474 | int i; | ||
475 | |||
476 | if (mach_get_model) | ||
477 | mach_get_model(model); | ||
478 | else | ||
479 | strcpy(model, "Unknown m68k"); | ||
480 | |||
481 | seq_printf(m, "Model:\t\t%s\n", model); | ||
482 | for (mem = 0, i = 0; i < m68k_num_memory; i++) | ||
483 | mem += m68k_memory[i].size; | ||
484 | seq_printf(m, "System Memory:\t%ldK\n", mem >> 10); | ||
485 | |||
486 | if (mach_get_hardware_list) | ||
487 | mach_get_hardware_list(m); | ||
488 | |||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | static int hardware_proc_open(struct inode *inode, struct file *file) | ||
493 | { | ||
494 | return single_open(file, hardware_proc_show, NULL); | ||
495 | } | ||
496 | |||
497 | static const struct file_operations hardware_proc_fops = { | ||
498 | .open = hardware_proc_open, | ||
499 | .read = seq_read, | ||
500 | .llseek = seq_lseek, | ||
501 | .release = single_release, | ||
502 | }; | ||
503 | |||
504 | static int __init proc_hardware_init(void) | ||
505 | { | ||
506 | proc_create("hardware", 0, NULL, &hardware_proc_fops); | ||
507 | return 0; | ||
508 | } | ||
509 | module_init(proc_hardware_init); | ||
510 | #endif | 5 | #endif |
511 | |||
512 | void check_bugs(void) | ||
513 | { | ||
514 | #ifndef CONFIG_M68KFPU_EMU | ||
515 | if (m68k_fputype == 0) { | ||
516 | printk(KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, " | ||
517 | "WHICH IS REQUIRED BY LINUX/M68K ***\n"); | ||
518 | printk(KERN_EMERG "Upgrade your hardware or join the FPU " | ||
519 | "emulation project\n"); | ||
520 | panic("no FPU"); | ||
521 | } | ||
522 | #endif /* !CONFIG_M68KFPU_EMU */ | ||
523 | } | ||
524 | |||
525 | #ifdef CONFIG_ADB | ||
526 | static int __init adb_probe_sync_enable (char *str) { | ||
527 | extern int __adb_probe_sync; | ||
528 | __adb_probe_sync = 1; | ||
529 | return 1; | ||
530 | } | ||
531 | |||
532 | __setup("adb_sync", adb_probe_sync_enable); | ||
533 | #endif /* CONFIG_ADB */ | ||
diff --git a/arch/m68k/kernel/setup_mm.c b/arch/m68k/kernel/setup_mm.c new file mode 100644 index 000000000000..334d83640376 --- /dev/null +++ b/arch/m68k/kernel/setup_mm.c | |||
@@ -0,0 +1,533 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/kernel/setup.c | ||
3 | * | ||
4 | * Copyright (C) 1995 Hamish Macdonald | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * This file handles the architecture-dependent parts of system setup | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/mm.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/fs.h> | ||
17 | #include <linux/console.h> | ||
18 | #include <linux/genhd.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/bootmem.h> | ||
23 | #include <linux/proc_fs.h> | ||
24 | #include <linux/seq_file.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/initrd.h> | ||
27 | |||
28 | #include <asm/bootinfo.h> | ||
29 | #include <asm/sections.h> | ||
30 | #include <asm/setup.h> | ||
31 | #include <asm/fpu.h> | ||
32 | #include <asm/irq.h> | ||
33 | #include <asm/io.h> | ||
34 | #include <asm/machdep.h> | ||
35 | #ifdef CONFIG_AMIGA | ||
36 | #include <asm/amigahw.h> | ||
37 | #endif | ||
38 | #ifdef CONFIG_ATARI | ||
39 | #include <asm/atarihw.h> | ||
40 | #include <asm/atari_stram.h> | ||
41 | #endif | ||
42 | #ifdef CONFIG_SUN3X | ||
43 | #include <asm/dvma.h> | ||
44 | #endif | ||
45 | #include <asm/natfeat.h> | ||
46 | |||
47 | #if !FPSTATESIZE || !NR_IRQS | ||
48 | #warning No CPU/platform type selected, your kernel will not work! | ||
49 | #warning Are you building an allnoconfig kernel? | ||
50 | #endif | ||
51 | |||
52 | unsigned long m68k_machtype; | ||
53 | EXPORT_SYMBOL(m68k_machtype); | ||
54 | unsigned long m68k_cputype; | ||
55 | EXPORT_SYMBOL(m68k_cputype); | ||
56 | unsigned long m68k_fputype; | ||
57 | unsigned long m68k_mmutype; | ||
58 | EXPORT_SYMBOL(m68k_mmutype); | ||
59 | #ifdef CONFIG_VME | ||
60 | unsigned long vme_brdtype; | ||
61 | EXPORT_SYMBOL(vme_brdtype); | ||
62 | #endif | ||
63 | |||
64 | int m68k_is040or060; | ||
65 | EXPORT_SYMBOL(m68k_is040or060); | ||
66 | |||
67 | extern unsigned long availmem; | ||
68 | |||
69 | int m68k_num_memory; | ||
70 | EXPORT_SYMBOL(m68k_num_memory); | ||
71 | int m68k_realnum_memory; | ||
72 | EXPORT_SYMBOL(m68k_realnum_memory); | ||
73 | unsigned long m68k_memoffset; | ||
74 | struct mem_info m68k_memory[NUM_MEMINFO]; | ||
75 | EXPORT_SYMBOL(m68k_memory); | ||
76 | |||
77 | struct mem_info m68k_ramdisk; | ||
78 | |||
79 | static char m68k_command_line[CL_SIZE]; | ||
80 | |||
81 | void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL; | ||
82 | /* machine dependent irq functions */ | ||
83 | void (*mach_init_IRQ) (void) __initdata = NULL; | ||
84 | void (*mach_get_model) (char *model); | ||
85 | void (*mach_get_hardware_list) (struct seq_file *m); | ||
86 | /* machine dependent timer functions */ | ||
87 | unsigned long (*mach_gettimeoffset) (void); | ||
88 | int (*mach_hwclk) (int, struct rtc_time*); | ||
89 | EXPORT_SYMBOL(mach_hwclk); | ||
90 | int (*mach_set_clock_mmss) (unsigned long); | ||
91 | unsigned int (*mach_get_ss)(void); | ||
92 | int (*mach_get_rtc_pll)(struct rtc_pll_info *); | ||
93 | int (*mach_set_rtc_pll)(struct rtc_pll_info *); | ||
94 | EXPORT_SYMBOL(mach_get_ss); | ||
95 | EXPORT_SYMBOL(mach_get_rtc_pll); | ||
96 | EXPORT_SYMBOL(mach_set_rtc_pll); | ||
97 | void (*mach_reset)( void ); | ||
98 | void (*mach_halt)( void ); | ||
99 | void (*mach_power_off)( void ); | ||
100 | long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */ | ||
101 | #ifdef CONFIG_HEARTBEAT | ||
102 | void (*mach_heartbeat) (int); | ||
103 | EXPORT_SYMBOL(mach_heartbeat); | ||
104 | #endif | ||
105 | #ifdef CONFIG_M68K_L2_CACHE | ||
106 | void (*mach_l2_flush) (int); | ||
107 | #endif | ||
108 | #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) | ||
109 | void (*mach_beep)(unsigned int, unsigned int); | ||
110 | EXPORT_SYMBOL(mach_beep); | ||
111 | #endif | ||
112 | #if defined(CONFIG_ISA) && defined(MULTI_ISA) | ||
113 | int isa_type; | ||
114 | int isa_sex; | ||
115 | EXPORT_SYMBOL(isa_type); | ||
116 | EXPORT_SYMBOL(isa_sex); | ||
117 | #endif | ||
118 | |||
119 | extern int amiga_parse_bootinfo(const struct bi_record *); | ||
120 | extern int atari_parse_bootinfo(const struct bi_record *); | ||
121 | extern int mac_parse_bootinfo(const struct bi_record *); | ||
122 | extern int q40_parse_bootinfo(const struct bi_record *); | ||
123 | extern int bvme6000_parse_bootinfo(const struct bi_record *); | ||
124 | extern int mvme16x_parse_bootinfo(const struct bi_record *); | ||
125 | extern int mvme147_parse_bootinfo(const struct bi_record *); | ||
126 | extern int hp300_parse_bootinfo(const struct bi_record *); | ||
127 | extern int apollo_parse_bootinfo(const struct bi_record *); | ||
128 | |||
129 | extern void config_amiga(void); | ||
130 | extern void config_atari(void); | ||
131 | extern void config_mac(void); | ||
132 | extern void config_sun3(void); | ||
133 | extern void config_apollo(void); | ||
134 | extern void config_mvme147(void); | ||
135 | extern void config_mvme16x(void); | ||
136 | extern void config_bvme6000(void); | ||
137 | extern void config_hp300(void); | ||
138 | extern void config_q40(void); | ||
139 | extern void config_sun3x(void); | ||
140 | |||
141 | #define MASK_256K 0xfffc0000 | ||
142 | |||
143 | extern void paging_init(void); | ||
144 | |||
145 | static void __init m68k_parse_bootinfo(const struct bi_record *record) | ||
146 | { | ||
147 | while (record->tag != BI_LAST) { | ||
148 | int unknown = 0; | ||
149 | const unsigned long *data = record->data; | ||
150 | |||
151 | switch (record->tag) { | ||
152 | case BI_MACHTYPE: | ||
153 | case BI_CPUTYPE: | ||
154 | case BI_FPUTYPE: | ||
155 | case BI_MMUTYPE: | ||
156 | /* Already set up by head.S */ | ||
157 | break; | ||
158 | |||
159 | case BI_MEMCHUNK: | ||
160 | if (m68k_num_memory < NUM_MEMINFO) { | ||
161 | m68k_memory[m68k_num_memory].addr = data[0]; | ||
162 | m68k_memory[m68k_num_memory].size = data[1]; | ||
163 | m68k_num_memory++; | ||
164 | } else | ||
165 | printk("m68k_parse_bootinfo: too many memory chunks\n"); | ||
166 | break; | ||
167 | |||
168 | case BI_RAMDISK: | ||
169 | m68k_ramdisk.addr = data[0]; | ||
170 | m68k_ramdisk.size = data[1]; | ||
171 | break; | ||
172 | |||
173 | case BI_COMMAND_LINE: | ||
174 | strlcpy(m68k_command_line, (const char *)data, | ||
175 | sizeof(m68k_command_line)); | ||
176 | break; | ||
177 | |||
178 | default: | ||
179 | if (MACH_IS_AMIGA) | ||
180 | unknown = amiga_parse_bootinfo(record); | ||
181 | else if (MACH_IS_ATARI) | ||
182 | unknown = atari_parse_bootinfo(record); | ||
183 | else if (MACH_IS_MAC) | ||
184 | unknown = mac_parse_bootinfo(record); | ||
185 | else if (MACH_IS_Q40) | ||
186 | unknown = q40_parse_bootinfo(record); | ||
187 | else if (MACH_IS_BVME6000) | ||
188 | unknown = bvme6000_parse_bootinfo(record); | ||
189 | else if (MACH_IS_MVME16x) | ||
190 | unknown = mvme16x_parse_bootinfo(record); | ||
191 | else if (MACH_IS_MVME147) | ||
192 | unknown = mvme147_parse_bootinfo(record); | ||
193 | else if (MACH_IS_HP300) | ||
194 | unknown = hp300_parse_bootinfo(record); | ||
195 | else if (MACH_IS_APOLLO) | ||
196 | unknown = apollo_parse_bootinfo(record); | ||
197 | else | ||
198 | unknown = 1; | ||
199 | } | ||
200 | if (unknown) | ||
201 | printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n", | ||
202 | record->tag); | ||
203 | record = (struct bi_record *)((unsigned long)record + | ||
204 | record->size); | ||
205 | } | ||
206 | |||
207 | m68k_realnum_memory = m68k_num_memory; | ||
208 | #ifdef CONFIG_SINGLE_MEMORY_CHUNK | ||
209 | if (m68k_num_memory > 1) { | ||
210 | printk("Ignoring last %i chunks of physical memory\n", | ||
211 | (m68k_num_memory - 1)); | ||
212 | m68k_num_memory = 1; | ||
213 | } | ||
214 | #endif | ||
215 | } | ||
216 | |||
217 | void __init setup_arch(char **cmdline_p) | ||
218 | { | ||
219 | int i; | ||
220 | |||
221 | /* The bootinfo is located right after the kernel bss */ | ||
222 | m68k_parse_bootinfo((const struct bi_record *)_end); | ||
223 | |||
224 | if (CPU_IS_040) | ||
225 | m68k_is040or060 = 4; | ||
226 | else if (CPU_IS_060) | ||
227 | m68k_is040or060 = 6; | ||
228 | |||
229 | /* FIXME: m68k_fputype is passed in by Penguin booter, which can | ||
230 | * be confused by software FPU emulation. BEWARE. | ||
231 | * We should really do our own FPU check at startup. | ||
232 | * [what do we do with buggy 68LC040s? if we have problems | ||
233 | * with them, we should add a test to check_bugs() below] */ | ||
234 | #ifndef CONFIG_M68KFPU_EMU_ONLY | ||
235 | /* clear the fpu if we have one */ | ||
236 | if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) { | ||
237 | volatile int zero = 0; | ||
238 | asm volatile ("frestore %0" : : "m" (zero)); | ||
239 | } | ||
240 | #endif | ||
241 | |||
242 | if (CPU_IS_060) { | ||
243 | u32 pcr; | ||
244 | |||
245 | asm (".chip 68060; movec %%pcr,%0; .chip 68k" | ||
246 | : "=d" (pcr)); | ||
247 | if (((pcr >> 8) & 0xff) <= 5) { | ||
248 | printk("Enabling workaround for errata I14\n"); | ||
249 | asm (".chip 68060; movec %0,%%pcr; .chip 68k" | ||
250 | : : "d" (pcr | 0x20)); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | init_mm.start_code = PAGE_OFFSET; | ||
255 | init_mm.end_code = (unsigned long)_etext; | ||
256 | init_mm.end_data = (unsigned long)_edata; | ||
257 | init_mm.brk = (unsigned long)_end; | ||
258 | |||
259 | *cmdline_p = m68k_command_line; | ||
260 | memcpy(boot_command_line, *cmdline_p, CL_SIZE); | ||
261 | |||
262 | parse_early_param(); | ||
263 | |||
264 | #ifdef CONFIG_DUMMY_CONSOLE | ||
265 | conswitchp = &dummy_con; | ||
266 | #endif | ||
267 | |||
268 | switch (m68k_machtype) { | ||
269 | #ifdef CONFIG_AMIGA | ||
270 | case MACH_AMIGA: | ||
271 | config_amiga(); | ||
272 | break; | ||
273 | #endif | ||
274 | #ifdef CONFIG_ATARI | ||
275 | case MACH_ATARI: | ||
276 | config_atari(); | ||
277 | break; | ||
278 | #endif | ||
279 | #ifdef CONFIG_MAC | ||
280 | case MACH_MAC: | ||
281 | config_mac(); | ||
282 | break; | ||
283 | #endif | ||
284 | #ifdef CONFIG_SUN3 | ||
285 | case MACH_SUN3: | ||
286 | config_sun3(); | ||
287 | break; | ||
288 | #endif | ||
289 | #ifdef CONFIG_APOLLO | ||
290 | case MACH_APOLLO: | ||
291 | config_apollo(); | ||
292 | break; | ||
293 | #endif | ||
294 | #ifdef CONFIG_MVME147 | ||
295 | case MACH_MVME147: | ||
296 | config_mvme147(); | ||
297 | break; | ||
298 | #endif | ||
299 | #ifdef CONFIG_MVME16x | ||
300 | case MACH_MVME16x: | ||
301 | config_mvme16x(); | ||
302 | break; | ||
303 | #endif | ||
304 | #ifdef CONFIG_BVME6000 | ||
305 | case MACH_BVME6000: | ||
306 | config_bvme6000(); | ||
307 | break; | ||
308 | #endif | ||
309 | #ifdef CONFIG_HP300 | ||
310 | case MACH_HP300: | ||
311 | config_hp300(); | ||
312 | break; | ||
313 | #endif | ||
314 | #ifdef CONFIG_Q40 | ||
315 | case MACH_Q40: | ||
316 | config_q40(); | ||
317 | break; | ||
318 | #endif | ||
319 | #ifdef CONFIG_SUN3X | ||
320 | case MACH_SUN3X: | ||
321 | config_sun3x(); | ||
322 | break; | ||
323 | #endif | ||
324 | default: | ||
325 | panic("No configuration setup"); | ||
326 | } | ||
327 | |||
328 | #ifdef CONFIG_NATFEAT | ||
329 | nf_init(); | ||
330 | #endif | ||
331 | |||
332 | paging_init(); | ||
333 | |||
334 | #ifndef CONFIG_SUN3 | ||
335 | for (i = 1; i < m68k_num_memory; i++) | ||
336 | free_bootmem_node(NODE_DATA(i), m68k_memory[i].addr, | ||
337 | m68k_memory[i].size); | ||
338 | #ifdef CONFIG_BLK_DEV_INITRD | ||
339 | if (m68k_ramdisk.size) { | ||
340 | reserve_bootmem_node(__virt_to_node(phys_to_virt(m68k_ramdisk.addr)), | ||
341 | m68k_ramdisk.addr, m68k_ramdisk.size, | ||
342 | BOOTMEM_DEFAULT); | ||
343 | initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr); | ||
344 | initrd_end = initrd_start + m68k_ramdisk.size; | ||
345 | printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end); | ||
346 | } | ||
347 | #endif | ||
348 | |||
349 | #ifdef CONFIG_ATARI | ||
350 | if (MACH_IS_ATARI) | ||
351 | atari_stram_reserve_pages((void *)availmem); | ||
352 | #endif | ||
353 | #ifdef CONFIG_SUN3X | ||
354 | if (MACH_IS_SUN3X) { | ||
355 | dvma_init(); | ||
356 | } | ||
357 | #endif | ||
358 | |||
359 | #endif /* !CONFIG_SUN3 */ | ||
360 | |||
361 | /* set ISA defs early as possible */ | ||
362 | #if defined(CONFIG_ISA) && defined(MULTI_ISA) | ||
363 | if (MACH_IS_Q40) { | ||
364 | isa_type = ISA_TYPE_Q40; | ||
365 | isa_sex = 0; | ||
366 | } | ||
367 | #ifdef CONFIG_AMIGA_PCMCIA | ||
368 | if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)) { | ||
369 | isa_type = ISA_TYPE_AG; | ||
370 | isa_sex = 1; | ||
371 | } | ||
372 | #endif | ||
373 | #endif | ||
374 | } | ||
375 | |||
376 | static int show_cpuinfo(struct seq_file *m, void *v) | ||
377 | { | ||
378 | const char *cpu, *mmu, *fpu; | ||
379 | unsigned long clockfreq, clockfactor; | ||
380 | |||
381 | #define LOOP_CYCLES_68020 (8) | ||
382 | #define LOOP_CYCLES_68030 (8) | ||
383 | #define LOOP_CYCLES_68040 (3) | ||
384 | #define LOOP_CYCLES_68060 (1) | ||
385 | |||
386 | if (CPU_IS_020) { | ||
387 | cpu = "68020"; | ||
388 | clockfactor = LOOP_CYCLES_68020; | ||
389 | } else if (CPU_IS_030) { | ||
390 | cpu = "68030"; | ||
391 | clockfactor = LOOP_CYCLES_68030; | ||
392 | } else if (CPU_IS_040) { | ||
393 | cpu = "68040"; | ||
394 | clockfactor = LOOP_CYCLES_68040; | ||
395 | } else if (CPU_IS_060) { | ||
396 | cpu = "68060"; | ||
397 | clockfactor = LOOP_CYCLES_68060; | ||
398 | } else { | ||
399 | cpu = "680x0"; | ||
400 | clockfactor = 0; | ||
401 | } | ||
402 | |||
403 | #ifdef CONFIG_M68KFPU_EMU_ONLY | ||
404 | fpu = "none(soft float)"; | ||
405 | #else | ||
406 | if (m68k_fputype & FPU_68881) | ||
407 | fpu = "68881"; | ||
408 | else if (m68k_fputype & FPU_68882) | ||
409 | fpu = "68882"; | ||
410 | else if (m68k_fputype & FPU_68040) | ||
411 | fpu = "68040"; | ||
412 | else if (m68k_fputype & FPU_68060) | ||
413 | fpu = "68060"; | ||
414 | else if (m68k_fputype & FPU_SUNFPA) | ||
415 | fpu = "Sun FPA"; | ||
416 | else | ||
417 | fpu = "none"; | ||
418 | #endif | ||
419 | |||
420 | if (m68k_mmutype & MMU_68851) | ||
421 | mmu = "68851"; | ||
422 | else if (m68k_mmutype & MMU_68030) | ||
423 | mmu = "68030"; | ||
424 | else if (m68k_mmutype & MMU_68040) | ||
425 | mmu = "68040"; | ||
426 | else if (m68k_mmutype & MMU_68060) | ||
427 | mmu = "68060"; | ||
428 | else if (m68k_mmutype & MMU_SUN3) | ||
429 | mmu = "Sun-3"; | ||
430 | else if (m68k_mmutype & MMU_APOLLO) | ||
431 | mmu = "Apollo"; | ||
432 | else | ||
433 | mmu = "unknown"; | ||
434 | |||
435 | clockfreq = loops_per_jiffy * HZ * clockfactor; | ||
436 | |||
437 | seq_printf(m, "CPU:\t\t%s\n" | ||
438 | "MMU:\t\t%s\n" | ||
439 | "FPU:\t\t%s\n" | ||
440 | "Clocking:\t%lu.%1luMHz\n" | ||
441 | "BogoMips:\t%lu.%02lu\n" | ||
442 | "Calibration:\t%lu loops\n", | ||
443 | cpu, mmu, fpu, | ||
444 | clockfreq/1000000,(clockfreq/100000)%10, | ||
445 | loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ))%100, | ||
446 | loops_per_jiffy); | ||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | static void *c_start(struct seq_file *m, loff_t *pos) | ||
451 | { | ||
452 | return *pos < 1 ? (void *)1 : NULL; | ||
453 | } | ||
454 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | ||
455 | { | ||
456 | ++*pos; | ||
457 | return NULL; | ||
458 | } | ||
459 | static void c_stop(struct seq_file *m, void *v) | ||
460 | { | ||
461 | } | ||
462 | const struct seq_operations cpuinfo_op = { | ||
463 | .start = c_start, | ||
464 | .next = c_next, | ||
465 | .stop = c_stop, | ||
466 | .show = show_cpuinfo, | ||
467 | }; | ||
468 | |||
469 | #ifdef CONFIG_PROC_HARDWARE | ||
470 | static int hardware_proc_show(struct seq_file *m, void *v) | ||
471 | { | ||
472 | char model[80]; | ||
473 | unsigned long mem; | ||
474 | int i; | ||
475 | |||
476 | if (mach_get_model) | ||
477 | mach_get_model(model); | ||
478 | else | ||
479 | strcpy(model, "Unknown m68k"); | ||
480 | |||
481 | seq_printf(m, "Model:\t\t%s\n", model); | ||
482 | for (mem = 0, i = 0; i < m68k_num_memory; i++) | ||
483 | mem += m68k_memory[i].size; | ||
484 | seq_printf(m, "System Memory:\t%ldK\n", mem >> 10); | ||
485 | |||
486 | if (mach_get_hardware_list) | ||
487 | mach_get_hardware_list(m); | ||
488 | |||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | static int hardware_proc_open(struct inode *inode, struct file *file) | ||
493 | { | ||
494 | return single_open(file, hardware_proc_show, NULL); | ||
495 | } | ||
496 | |||
497 | static const struct file_operations hardware_proc_fops = { | ||
498 | .open = hardware_proc_open, | ||
499 | .read = seq_read, | ||
500 | .llseek = seq_lseek, | ||
501 | .release = single_release, | ||
502 | }; | ||
503 | |||
504 | static int __init proc_hardware_init(void) | ||
505 | { | ||
506 | proc_create("hardware", 0, NULL, &hardware_proc_fops); | ||
507 | return 0; | ||
508 | } | ||
509 | module_init(proc_hardware_init); | ||
510 | #endif | ||
511 | |||
512 | void check_bugs(void) | ||
513 | { | ||
514 | #ifndef CONFIG_M68KFPU_EMU | ||
515 | if (m68k_fputype == 0) { | ||
516 | printk(KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, " | ||
517 | "WHICH IS REQUIRED BY LINUX/M68K ***\n"); | ||
518 | printk(KERN_EMERG "Upgrade your hardware or join the FPU " | ||
519 | "emulation project\n"); | ||
520 | panic("no FPU"); | ||
521 | } | ||
522 | #endif /* !CONFIG_M68KFPU_EMU */ | ||
523 | } | ||
524 | |||
525 | #ifdef CONFIG_ADB | ||
526 | static int __init adb_probe_sync_enable (char *str) { | ||
527 | extern int __adb_probe_sync; | ||
528 | __adb_probe_sync = 1; | ||
529 | return 1; | ||
530 | } | ||
531 | |||
532 | __setup("adb_sync", adb_probe_sync_enable); | ||
533 | #endif /* CONFIG_ADB */ | ||
diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68k/kernel/setup_no.c index 16b2de7f5101..16b2de7f5101 100644 --- a/arch/m68knommu/kernel/setup.c +++ b/arch/m68k/kernel/setup_no.c | |||
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index a0afc239304e..2e25713e2ead 100644 --- a/arch/m68k/kernel/signal.c +++ b/arch/m68k/kernel/signal.c | |||
@@ -1,1017 +1,5 @@ | |||
1 | /* | 1 | #ifdef CONFIG_MMU |
2 | * linux/arch/m68k/kernel/signal.c | 2 | #include "signal_mm.c" |
3 | * | ||
4 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file COPYING in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * Linux/m68k support by Hamish Macdonald | ||
13 | * | ||
14 | * 68060 fixes by Jesper Skov | ||
15 | * | ||
16 | * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab | ||
17 | * | ||
18 | * mathemu support by Roman Zippel | ||
19 | * (Note: fpstate in the signal context is completely ignored for the emulator | ||
20 | * and the internal floating point format is put on stack) | ||
21 | */ | ||
22 | |||
23 | /* | ||
24 | * ++roman (07/09/96): implemented signal stacks (specially for tosemu on | ||
25 | * Atari :-) Current limitation: Only one sigstack can be active at one time. | ||
26 | * If a second signal with SA_ONSTACK set arrives while working on a sigstack, | ||
27 | * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested | ||
28 | * signal handlers! | ||
29 | */ | ||
30 | |||
31 | #include <linux/sched.h> | ||
32 | #include <linux/mm.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/signal.h> | ||
35 | #include <linux/syscalls.h> | ||
36 | #include <linux/errno.h> | ||
37 | #include <linux/wait.h> | ||
38 | #include <linux/ptrace.h> | ||
39 | #include <linux/unistd.h> | ||
40 | #include <linux/stddef.h> | ||
41 | #include <linux/highuid.h> | ||
42 | #include <linux/personality.h> | ||
43 | #include <linux/tty.h> | ||
44 | #include <linux/binfmts.h> | ||
45 | #include <linux/module.h> | ||
46 | |||
47 | #include <asm/setup.h> | ||
48 | #include <asm/uaccess.h> | ||
49 | #include <asm/pgtable.h> | ||
50 | #include <asm/traps.h> | ||
51 | #include <asm/ucontext.h> | ||
52 | |||
53 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | ||
54 | |||
55 | static const int frame_extra_sizes[16] = { | ||
56 | [1] = -1, /* sizeof(((struct frame *)0)->un.fmt1), */ | ||
57 | [2] = sizeof(((struct frame *)0)->un.fmt2), | ||
58 | [3] = sizeof(((struct frame *)0)->un.fmt3), | ||
59 | [4] = sizeof(((struct frame *)0)->un.fmt4), | ||
60 | [5] = -1, /* sizeof(((struct frame *)0)->un.fmt5), */ | ||
61 | [6] = -1, /* sizeof(((struct frame *)0)->un.fmt6), */ | ||
62 | [7] = sizeof(((struct frame *)0)->un.fmt7), | ||
63 | [8] = -1, /* sizeof(((struct frame *)0)->un.fmt8), */ | ||
64 | [9] = sizeof(((struct frame *)0)->un.fmt9), | ||
65 | [10] = sizeof(((struct frame *)0)->un.fmta), | ||
66 | [11] = sizeof(((struct frame *)0)->un.fmtb), | ||
67 | [12] = -1, /* sizeof(((struct frame *)0)->un.fmtc), */ | ||
68 | [13] = -1, /* sizeof(((struct frame *)0)->un.fmtd), */ | ||
69 | [14] = -1, /* sizeof(((struct frame *)0)->un.fmte), */ | ||
70 | [15] = -1, /* sizeof(((struct frame *)0)->un.fmtf), */ | ||
71 | }; | ||
72 | |||
73 | int handle_kernel_fault(struct pt_regs *regs) | ||
74 | { | ||
75 | const struct exception_table_entry *fixup; | ||
76 | struct pt_regs *tregs; | ||
77 | |||
78 | /* Are we prepared to handle this kernel fault? */ | ||
79 | fixup = search_exception_tables(regs->pc); | ||
80 | if (!fixup) | ||
81 | return 0; | ||
82 | |||
83 | /* Create a new four word stack frame, discarding the old one. */ | ||
84 | regs->stkadj = frame_extra_sizes[regs->format]; | ||
85 | tregs = (struct pt_regs *)((long)regs + regs->stkadj); | ||
86 | tregs->vector = regs->vector; | ||
87 | tregs->format = 0; | ||
88 | tregs->pc = fixup->fixup; | ||
89 | tregs->sr = regs->sr; | ||
90 | |||
91 | return 1; | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * Atomically swap in the new signal mask, and wait for a signal. | ||
96 | */ | ||
97 | asmlinkage int | ||
98 | sys_sigsuspend(int unused0, int unused1, old_sigset_t mask) | ||
99 | { | ||
100 | mask &= _BLOCKABLE; | ||
101 | spin_lock_irq(¤t->sighand->siglock); | ||
102 | current->saved_sigmask = current->blocked; | ||
103 | siginitset(¤t->blocked, mask); | ||
104 | recalc_sigpending(); | ||
105 | spin_unlock_irq(¤t->sighand->siglock); | ||
106 | |||
107 | current->state = TASK_INTERRUPTIBLE; | ||
108 | schedule(); | ||
109 | set_restore_sigmask(); | ||
110 | |||
111 | return -ERESTARTNOHAND; | ||
112 | } | ||
113 | |||
114 | asmlinkage int | ||
115 | sys_sigaction(int sig, const struct old_sigaction __user *act, | ||
116 | struct old_sigaction __user *oact) | ||
117 | { | ||
118 | struct k_sigaction new_ka, old_ka; | ||
119 | int ret; | ||
120 | |||
121 | if (act) { | ||
122 | old_sigset_t mask; | ||
123 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | ||
124 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | ||
125 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || | ||
126 | __get_user(new_ka.sa.sa_flags, &act->sa_flags) || | ||
127 | __get_user(mask, &act->sa_mask)) | ||
128 | return -EFAULT; | ||
129 | siginitset(&new_ka.sa.sa_mask, mask); | ||
130 | } | ||
131 | |||
132 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | ||
133 | |||
134 | if (!ret && oact) { | ||
135 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | ||
136 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | ||
137 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || | ||
138 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || | ||
139 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) | ||
140 | return -EFAULT; | ||
141 | } | ||
142 | |||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | asmlinkage int | ||
147 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) | ||
148 | { | ||
149 | return do_sigaltstack(uss, uoss, rdusp()); | ||
150 | } | ||
151 | |||
152 | |||
153 | /* | ||
154 | * Do a signal return; undo the signal stack. | ||
155 | * | ||
156 | * Keep the return code on the stack quadword aligned! | ||
157 | * That makes the cache flush below easier. | ||
158 | */ | ||
159 | |||
160 | struct sigframe | ||
161 | { | ||
162 | char __user *pretcode; | ||
163 | int sig; | ||
164 | int code; | ||
165 | struct sigcontext __user *psc; | ||
166 | char retcode[8]; | ||
167 | unsigned long extramask[_NSIG_WORDS-1]; | ||
168 | struct sigcontext sc; | ||
169 | }; | ||
170 | |||
171 | struct rt_sigframe | ||
172 | { | ||
173 | char __user *pretcode; | ||
174 | int sig; | ||
175 | struct siginfo __user *pinfo; | ||
176 | void __user *puc; | ||
177 | char retcode[8]; | ||
178 | struct siginfo info; | ||
179 | struct ucontext uc; | ||
180 | }; | ||
181 | |||
182 | |||
183 | static unsigned char fpu_version; /* version number of fpu, set by setup_frame */ | ||
184 | |||
185 | static inline int restore_fpu_state(struct sigcontext *sc) | ||
186 | { | ||
187 | int err = 1; | ||
188 | |||
189 | if (FPU_IS_EMU) { | ||
190 | /* restore registers */ | ||
191 | memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12); | ||
192 | memcpy(current->thread.fp, sc->sc_fpregs, 24); | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { | ||
197 | /* Verify the frame format. */ | ||
198 | if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version)) | ||
199 | goto out; | ||
200 | if (CPU_IS_020_OR_030) { | ||
201 | if (m68k_fputype & FPU_68881 && | ||
202 | !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4)) | ||
203 | goto out; | ||
204 | if (m68k_fputype & FPU_68882 && | ||
205 | !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4)) | ||
206 | goto out; | ||
207 | } else if (CPU_IS_040) { | ||
208 | if (!(sc->sc_fpstate[1] == 0x00 || | ||
209 | sc->sc_fpstate[1] == 0x28 || | ||
210 | sc->sc_fpstate[1] == 0x60)) | ||
211 | goto out; | ||
212 | } else if (CPU_IS_060) { | ||
213 | if (!(sc->sc_fpstate[3] == 0x00 || | ||
214 | sc->sc_fpstate[3] == 0x60 || | ||
215 | sc->sc_fpstate[3] == 0xe0)) | ||
216 | goto out; | ||
217 | } else | ||
218 | goto out; | ||
219 | |||
220 | __asm__ volatile (".chip 68k/68881\n\t" | ||
221 | "fmovemx %0,%%fp0-%%fp1\n\t" | ||
222 | "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t" | ||
223 | ".chip 68k" | ||
224 | : /* no outputs */ | ||
225 | : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl)); | ||
226 | } | ||
227 | __asm__ volatile (".chip 68k/68881\n\t" | ||
228 | "frestore %0\n\t" | ||
229 | ".chip 68k" : : "m" (*sc->sc_fpstate)); | ||
230 | err = 0; | ||
231 | |||
232 | out: | ||
233 | return err; | ||
234 | } | ||
235 | |||
236 | #define FPCONTEXT_SIZE 216 | ||
237 | #define uc_fpstate uc_filler[0] | ||
238 | #define uc_formatvec uc_filler[FPCONTEXT_SIZE/4] | ||
239 | #define uc_extra uc_filler[FPCONTEXT_SIZE/4+1] | ||
240 | |||
241 | static inline int rt_restore_fpu_state(struct ucontext __user *uc) | ||
242 | { | ||
243 | unsigned char fpstate[FPCONTEXT_SIZE]; | ||
244 | int context_size = CPU_IS_060 ? 8 : 0; | ||
245 | fpregset_t fpregs; | ||
246 | int err = 1; | ||
247 | |||
248 | if (FPU_IS_EMU) { | ||
249 | /* restore fpu control register */ | ||
250 | if (__copy_from_user(current->thread.fpcntl, | ||
251 | uc->uc_mcontext.fpregs.f_fpcntl, 12)) | ||
252 | goto out; | ||
253 | /* restore all other fpu register */ | ||
254 | if (__copy_from_user(current->thread.fp, | ||
255 | uc->uc_mcontext.fpregs.f_fpregs, 96)) | ||
256 | goto out; | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | if (__get_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate)) | ||
261 | goto out; | ||
262 | if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { | ||
263 | if (!CPU_IS_060) | ||
264 | context_size = fpstate[1]; | ||
265 | /* Verify the frame format. */ | ||
266 | if (!CPU_IS_060 && (fpstate[0] != fpu_version)) | ||
267 | goto out; | ||
268 | if (CPU_IS_020_OR_030) { | ||
269 | if (m68k_fputype & FPU_68881 && | ||
270 | !(context_size == 0x18 || context_size == 0xb4)) | ||
271 | goto out; | ||
272 | if (m68k_fputype & FPU_68882 && | ||
273 | !(context_size == 0x38 || context_size == 0xd4)) | ||
274 | goto out; | ||
275 | } else if (CPU_IS_040) { | ||
276 | if (!(context_size == 0x00 || | ||
277 | context_size == 0x28 || | ||
278 | context_size == 0x60)) | ||
279 | goto out; | ||
280 | } else if (CPU_IS_060) { | ||
281 | if (!(fpstate[3] == 0x00 || | ||
282 | fpstate[3] == 0x60 || | ||
283 | fpstate[3] == 0xe0)) | ||
284 | goto out; | ||
285 | } else | ||
286 | goto out; | ||
287 | if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs, | ||
288 | sizeof(fpregs))) | ||
289 | goto out; | ||
290 | __asm__ volatile (".chip 68k/68881\n\t" | ||
291 | "fmovemx %0,%%fp0-%%fp7\n\t" | ||
292 | "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t" | ||
293 | ".chip 68k" | ||
294 | : /* no outputs */ | ||
295 | : "m" (*fpregs.f_fpregs), | ||
296 | "m" (*fpregs.f_fpcntl)); | ||
297 | } | ||
298 | if (context_size && | ||
299 | __copy_from_user(fpstate + 4, (long __user *)&uc->uc_fpstate + 1, | ||
300 | context_size)) | ||
301 | goto out; | ||
302 | __asm__ volatile (".chip 68k/68881\n\t" | ||
303 | "frestore %0\n\t" | ||
304 | ".chip 68k" : : "m" (*fpstate)); | ||
305 | err = 0; | ||
306 | |||
307 | out: | ||
308 | return err; | ||
309 | } | ||
310 | |||
311 | static int mangle_kernel_stack(struct pt_regs *regs, int formatvec, | ||
312 | void __user *fp) | ||
313 | { | ||
314 | int fsize = frame_extra_sizes[formatvec >> 12]; | ||
315 | if (fsize < 0) { | ||
316 | /* | ||
317 | * user process trying to return with weird frame format | ||
318 | */ | ||
319 | #ifdef DEBUG | ||
320 | printk("user process returning with weird frame format\n"); | ||
321 | #endif | ||
322 | return 1; | ||
323 | } | ||
324 | if (!fsize) { | ||
325 | regs->format = formatvec >> 12; | ||
326 | regs->vector = formatvec & 0xfff; | ||
327 | } else { | ||
328 | struct switch_stack *sw = (struct switch_stack *)regs - 1; | ||
329 | unsigned long buf[fsize / 2]; /* yes, twice as much */ | ||
330 | |||
331 | /* that'll make sure that expansion won't crap over data */ | ||
332 | if (copy_from_user(buf + fsize / 4, fp, fsize)) | ||
333 | return 1; | ||
334 | |||
335 | /* point of no return */ | ||
336 | regs->format = formatvec >> 12; | ||
337 | regs->vector = formatvec & 0xfff; | ||
338 | #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) | ||
339 | __asm__ __volatile__ | ||
340 | (" movel %0,%/a0\n\t" | ||
341 | " subl %1,%/a0\n\t" /* make room on stack */ | ||
342 | " movel %/a0,%/sp\n\t" /* set stack pointer */ | ||
343 | /* move switch_stack and pt_regs */ | ||
344 | "1: movel %0@+,%/a0@+\n\t" | ||
345 | " dbra %2,1b\n\t" | ||
346 | " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */ | ||
347 | " lsrl #2,%1\n\t" | ||
348 | " subql #1,%1\n\t" | ||
349 | /* copy to the gap we'd made */ | ||
350 | "2: movel %4@+,%/a0@+\n\t" | ||
351 | " dbra %1,2b\n\t" | ||
352 | " bral ret_from_signal\n" | ||
353 | : /* no outputs, it doesn't ever return */ | ||
354 | : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), | ||
355 | "n" (frame_offset), "a" (buf + fsize/4) | ||
356 | : "a0"); | ||
357 | #undef frame_offset | ||
358 | } | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static inline int | ||
363 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp) | ||
364 | { | ||
365 | int formatvec; | ||
366 | struct sigcontext context; | ||
367 | int err; | ||
368 | |||
369 | /* Always make any pending restarted system calls return -EINTR */ | ||
370 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
371 | |||
372 | /* get previous context */ | ||
373 | if (copy_from_user(&context, usc, sizeof(context))) | ||
374 | goto badframe; | ||
375 | |||
376 | /* restore passed registers */ | ||
377 | regs->d0 = context.sc_d0; | ||
378 | regs->d1 = context.sc_d1; | ||
379 | regs->a0 = context.sc_a0; | ||
380 | regs->a1 = context.sc_a1; | ||
381 | regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff); | ||
382 | regs->pc = context.sc_pc; | ||
383 | regs->orig_d0 = -1; /* disable syscall checks */ | ||
384 | wrusp(context.sc_usp); | ||
385 | formatvec = context.sc_formatvec; | ||
386 | |||
387 | err = restore_fpu_state(&context); | ||
388 | |||
389 | if (err || mangle_kernel_stack(regs, formatvec, fp)) | ||
390 | goto badframe; | ||
391 | |||
392 | return 0; | ||
393 | |||
394 | badframe: | ||
395 | return 1; | ||
396 | } | ||
397 | |||
398 | static inline int | ||
399 | rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, | ||
400 | struct ucontext __user *uc) | ||
401 | { | ||
402 | int temp; | ||
403 | greg_t __user *gregs = uc->uc_mcontext.gregs; | ||
404 | unsigned long usp; | ||
405 | int err; | ||
406 | |||
407 | /* Always make any pending restarted system calls return -EINTR */ | ||
408 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
409 | |||
410 | err = __get_user(temp, &uc->uc_mcontext.version); | ||
411 | if (temp != MCONTEXT_VERSION) | ||
412 | goto badframe; | ||
413 | /* restore passed registers */ | ||
414 | err |= __get_user(regs->d0, &gregs[0]); | ||
415 | err |= __get_user(regs->d1, &gregs[1]); | ||
416 | err |= __get_user(regs->d2, &gregs[2]); | ||
417 | err |= __get_user(regs->d3, &gregs[3]); | ||
418 | err |= __get_user(regs->d4, &gregs[4]); | ||
419 | err |= __get_user(regs->d5, &gregs[5]); | ||
420 | err |= __get_user(sw->d6, &gregs[6]); | ||
421 | err |= __get_user(sw->d7, &gregs[7]); | ||
422 | err |= __get_user(regs->a0, &gregs[8]); | ||
423 | err |= __get_user(regs->a1, &gregs[9]); | ||
424 | err |= __get_user(regs->a2, &gregs[10]); | ||
425 | err |= __get_user(sw->a3, &gregs[11]); | ||
426 | err |= __get_user(sw->a4, &gregs[12]); | ||
427 | err |= __get_user(sw->a5, &gregs[13]); | ||
428 | err |= __get_user(sw->a6, &gregs[14]); | ||
429 | err |= __get_user(usp, &gregs[15]); | ||
430 | wrusp(usp); | ||
431 | err |= __get_user(regs->pc, &gregs[16]); | ||
432 | err |= __get_user(temp, &gregs[17]); | ||
433 | regs->sr = (regs->sr & 0xff00) | (temp & 0xff); | ||
434 | regs->orig_d0 = -1; /* disable syscall checks */ | ||
435 | err |= __get_user(temp, &uc->uc_formatvec); | ||
436 | |||
437 | err |= rt_restore_fpu_state(uc); | ||
438 | |||
439 | if (err || do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) | ||
440 | goto badframe; | ||
441 | |||
442 | if (mangle_kernel_stack(regs, temp, &uc->uc_extra)) | ||
443 | goto badframe; | ||
444 | |||
445 | return 0; | ||
446 | |||
447 | badframe: | ||
448 | return 1; | ||
449 | } | ||
450 | |||
451 | asmlinkage int do_sigreturn(unsigned long __unused) | ||
452 | { | ||
453 | struct switch_stack *sw = (struct switch_stack *) &__unused; | ||
454 | struct pt_regs *regs = (struct pt_regs *) (sw + 1); | ||
455 | unsigned long usp = rdusp(); | ||
456 | struct sigframe __user *frame = (struct sigframe __user *)(usp - 4); | ||
457 | sigset_t set; | ||
458 | |||
459 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
460 | goto badframe; | ||
461 | if (__get_user(set.sig[0], &frame->sc.sc_mask) || | ||
462 | (_NSIG_WORDS > 1 && | ||
463 | __copy_from_user(&set.sig[1], &frame->extramask, | ||
464 | sizeof(frame->extramask)))) | ||
465 | goto badframe; | ||
466 | |||
467 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
468 | current->blocked = set; | ||
469 | recalc_sigpending(); | ||
470 | |||
471 | if (restore_sigcontext(regs, &frame->sc, frame + 1)) | ||
472 | goto badframe; | ||
473 | return regs->d0; | ||
474 | |||
475 | badframe: | ||
476 | force_sig(SIGSEGV, current); | ||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | asmlinkage int do_rt_sigreturn(unsigned long __unused) | ||
481 | { | ||
482 | struct switch_stack *sw = (struct switch_stack *) &__unused; | ||
483 | struct pt_regs *regs = (struct pt_regs *) (sw + 1); | ||
484 | unsigned long usp = rdusp(); | ||
485 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4); | ||
486 | sigset_t set; | ||
487 | |||
488 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
489 | goto badframe; | ||
490 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | ||
491 | goto badframe; | ||
492 | |||
493 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
494 | current->blocked = set; | ||
495 | recalc_sigpending(); | ||
496 | |||
497 | if (rt_restore_ucontext(regs, sw, &frame->uc)) | ||
498 | goto badframe; | ||
499 | return regs->d0; | ||
500 | |||
501 | badframe: | ||
502 | force_sig(SIGSEGV, current); | ||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | /* | ||
507 | * Set up a signal frame. | ||
508 | */ | ||
509 | |||
510 | static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs) | ||
511 | { | ||
512 | if (FPU_IS_EMU) { | ||
513 | /* save registers */ | ||
514 | memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12); | ||
515 | memcpy(sc->sc_fpregs, current->thread.fp, 24); | ||
516 | return; | ||
517 | } | ||
518 | |||
519 | __asm__ volatile (".chip 68k/68881\n\t" | ||
520 | "fsave %0\n\t" | ||
521 | ".chip 68k" | ||
522 | : : "m" (*sc->sc_fpstate) : "memory"); | ||
523 | |||
524 | if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { | ||
525 | fpu_version = sc->sc_fpstate[0]; | ||
526 | if (CPU_IS_020_OR_030 && | ||
527 | regs->vector >= (VEC_FPBRUC * 4) && | ||
528 | regs->vector <= (VEC_FPNAN * 4)) { | ||
529 | /* Clear pending exception in 68882 idle frame */ | ||
530 | if (*(unsigned short *) sc->sc_fpstate == 0x1f38) | ||
531 | sc->sc_fpstate[0x38] |= 1 << 3; | ||
532 | } | ||
533 | __asm__ volatile (".chip 68k/68881\n\t" | ||
534 | "fmovemx %%fp0-%%fp1,%0\n\t" | ||
535 | "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t" | ||
536 | ".chip 68k" | ||
537 | : "=m" (*sc->sc_fpregs), | ||
538 | "=m" (*sc->sc_fpcntl) | ||
539 | : /* no inputs */ | ||
540 | : "memory"); | ||
541 | } | ||
542 | } | ||
543 | |||
544 | static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *regs) | ||
545 | { | ||
546 | unsigned char fpstate[FPCONTEXT_SIZE]; | ||
547 | int context_size = CPU_IS_060 ? 8 : 0; | ||
548 | int err = 0; | ||
549 | |||
550 | if (FPU_IS_EMU) { | ||
551 | /* save fpu control register */ | ||
552 | err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpcntl, | ||
553 | current->thread.fpcntl, 12); | ||
554 | /* save all other fpu register */ | ||
555 | err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs, | ||
556 | current->thread.fp, 96); | ||
557 | return err; | ||
558 | } | ||
559 | |||
560 | __asm__ volatile (".chip 68k/68881\n\t" | ||
561 | "fsave %0\n\t" | ||
562 | ".chip 68k" | ||
563 | : : "m" (*fpstate) : "memory"); | ||
564 | |||
565 | err |= __put_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate); | ||
566 | if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { | ||
567 | fpregset_t fpregs; | ||
568 | if (!CPU_IS_060) | ||
569 | context_size = fpstate[1]; | ||
570 | fpu_version = fpstate[0]; | ||
571 | if (CPU_IS_020_OR_030 && | ||
572 | regs->vector >= (VEC_FPBRUC * 4) && | ||
573 | regs->vector <= (VEC_FPNAN * 4)) { | ||
574 | /* Clear pending exception in 68882 idle frame */ | ||
575 | if (*(unsigned short *) fpstate == 0x1f38) | ||
576 | fpstate[0x38] |= 1 << 3; | ||
577 | } | ||
578 | __asm__ volatile (".chip 68k/68881\n\t" | ||
579 | "fmovemx %%fp0-%%fp7,%0\n\t" | ||
580 | "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t" | ||
581 | ".chip 68k" | ||
582 | : "=m" (*fpregs.f_fpregs), | ||
583 | "=m" (*fpregs.f_fpcntl) | ||
584 | : /* no inputs */ | ||
585 | : "memory"); | ||
586 | err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, | ||
587 | sizeof(fpregs)); | ||
588 | } | ||
589 | if (context_size) | ||
590 | err |= copy_to_user((long __user *)&uc->uc_fpstate + 1, fpstate + 4, | ||
591 | context_size); | ||
592 | return err; | ||
593 | } | ||
594 | |||
595 | static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, | ||
596 | unsigned long mask) | ||
597 | { | ||
598 | sc->sc_mask = mask; | ||
599 | sc->sc_usp = rdusp(); | ||
600 | sc->sc_d0 = regs->d0; | ||
601 | sc->sc_d1 = regs->d1; | ||
602 | sc->sc_a0 = regs->a0; | ||
603 | sc->sc_a1 = regs->a1; | ||
604 | sc->sc_sr = regs->sr; | ||
605 | sc->sc_pc = regs->pc; | ||
606 | sc->sc_formatvec = regs->format << 12 | regs->vector; | ||
607 | save_fpu_state(sc, regs); | ||
608 | } | ||
609 | |||
610 | static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs) | ||
611 | { | ||
612 | struct switch_stack *sw = (struct switch_stack *)regs - 1; | ||
613 | greg_t __user *gregs = uc->uc_mcontext.gregs; | ||
614 | int err = 0; | ||
615 | |||
616 | err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); | ||
617 | err |= __put_user(regs->d0, &gregs[0]); | ||
618 | err |= __put_user(regs->d1, &gregs[1]); | ||
619 | err |= __put_user(regs->d2, &gregs[2]); | ||
620 | err |= __put_user(regs->d3, &gregs[3]); | ||
621 | err |= __put_user(regs->d4, &gregs[4]); | ||
622 | err |= __put_user(regs->d5, &gregs[5]); | ||
623 | err |= __put_user(sw->d6, &gregs[6]); | ||
624 | err |= __put_user(sw->d7, &gregs[7]); | ||
625 | err |= __put_user(regs->a0, &gregs[8]); | ||
626 | err |= __put_user(regs->a1, &gregs[9]); | ||
627 | err |= __put_user(regs->a2, &gregs[10]); | ||
628 | err |= __put_user(sw->a3, &gregs[11]); | ||
629 | err |= __put_user(sw->a4, &gregs[12]); | ||
630 | err |= __put_user(sw->a5, &gregs[13]); | ||
631 | err |= __put_user(sw->a6, &gregs[14]); | ||
632 | err |= __put_user(rdusp(), &gregs[15]); | ||
633 | err |= __put_user(regs->pc, &gregs[16]); | ||
634 | err |= __put_user(regs->sr, &gregs[17]); | ||
635 | err |= __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec); | ||
636 | err |= rt_save_fpu_state(uc, regs); | ||
637 | return err; | ||
638 | } | ||
639 | |||
640 | static inline void push_cache (unsigned long vaddr) | ||
641 | { | ||
642 | /* | ||
643 | * Using the old cache_push_v() was really a big waste. | ||
644 | * | ||
645 | * What we are trying to do is to flush 8 bytes to ram. | ||
646 | * Flushing 2 cache lines of 16 bytes is much cheaper than | ||
647 | * flushing 1 or 2 pages, as previously done in | ||
648 | * cache_push_v(). | ||
649 | * Jes | ||
650 | */ | ||
651 | if (CPU_IS_040) { | ||
652 | unsigned long temp; | ||
653 | |||
654 | __asm__ __volatile__ (".chip 68040\n\t" | ||
655 | "nop\n\t" | ||
656 | "ptestr (%1)\n\t" | ||
657 | "movec %%mmusr,%0\n\t" | ||
658 | ".chip 68k" | ||
659 | : "=r" (temp) | ||
660 | : "a" (vaddr)); | ||
661 | |||
662 | temp &= PAGE_MASK; | ||
663 | temp |= vaddr & ~PAGE_MASK; | ||
664 | |||
665 | __asm__ __volatile__ (".chip 68040\n\t" | ||
666 | "nop\n\t" | ||
667 | "cpushl %%bc,(%0)\n\t" | ||
668 | ".chip 68k" | ||
669 | : : "a" (temp)); | ||
670 | } | ||
671 | else if (CPU_IS_060) { | ||
672 | unsigned long temp; | ||
673 | __asm__ __volatile__ (".chip 68060\n\t" | ||
674 | "plpar (%0)\n\t" | ||
675 | ".chip 68k" | ||
676 | : "=a" (temp) | ||
677 | : "0" (vaddr)); | ||
678 | __asm__ __volatile__ (".chip 68060\n\t" | ||
679 | "cpushl %%bc,(%0)\n\t" | ||
680 | ".chip 68k" | ||
681 | : : "a" (temp)); | ||
682 | } | ||
683 | else { | ||
684 | /* | ||
685 | * 68030/68020 have no writeback cache; | ||
686 | * still need to clear icache. | ||
687 | * Note that vaddr is guaranteed to be long word aligned. | ||
688 | */ | ||
689 | unsigned long temp; | ||
690 | asm volatile ("movec %%cacr,%0" : "=r" (temp)); | ||
691 | temp += 4; | ||
692 | asm volatile ("movec %0,%%caar\n\t" | ||
693 | "movec %1,%%cacr" | ||
694 | : : "r" (vaddr), "r" (temp)); | ||
695 | asm volatile ("movec %0,%%caar\n\t" | ||
696 | "movec %1,%%cacr" | ||
697 | : : "r" (vaddr + 4), "r" (temp)); | ||
698 | } | ||
699 | } | ||
700 | |||
701 | static inline void __user * | ||
702 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | ||
703 | { | ||
704 | unsigned long usp; | ||
705 | |||
706 | /* Default to using normal stack. */ | ||
707 | usp = rdusp(); | ||
708 | |||
709 | /* This is the X/Open sanctioned signal stack switching. */ | ||
710 | if (ka->sa.sa_flags & SA_ONSTACK) { | ||
711 | if (!sas_ss_flags(usp)) | ||
712 | usp = current->sas_ss_sp + current->sas_ss_size; | ||
713 | } | ||
714 | return (void __user *)((usp - frame_size) & -8UL); | ||
715 | } | ||
716 | |||
717 | static int setup_frame (int sig, struct k_sigaction *ka, | ||
718 | sigset_t *set, struct pt_regs *regs) | ||
719 | { | ||
720 | struct sigframe __user *frame; | ||
721 | int fsize = frame_extra_sizes[regs->format]; | ||
722 | struct sigcontext context; | ||
723 | int err = 0; | ||
724 | |||
725 | if (fsize < 0) { | ||
726 | #ifdef DEBUG | ||
727 | printk ("setup_frame: Unknown frame format %#x\n", | ||
728 | regs->format); | ||
729 | #endif | ||
730 | goto give_sigsegv; | ||
731 | } | ||
732 | |||
733 | frame = get_sigframe(ka, regs, sizeof(*frame) + fsize); | ||
734 | |||
735 | if (fsize) | ||
736 | err |= copy_to_user (frame + 1, regs + 1, fsize); | ||
737 | |||
738 | err |= __put_user((current_thread_info()->exec_domain | ||
739 | && current_thread_info()->exec_domain->signal_invmap | ||
740 | && sig < 32 | ||
741 | ? current_thread_info()->exec_domain->signal_invmap[sig] | ||
742 | : sig), | ||
743 | &frame->sig); | ||
744 | |||
745 | err |= __put_user(regs->vector, &frame->code); | ||
746 | err |= __put_user(&frame->sc, &frame->psc); | ||
747 | |||
748 | if (_NSIG_WORDS > 1) | ||
749 | err |= copy_to_user(frame->extramask, &set->sig[1], | ||
750 | sizeof(frame->extramask)); | ||
751 | |||
752 | setup_sigcontext(&context, regs, set->sig[0]); | ||
753 | err |= copy_to_user (&frame->sc, &context, sizeof(context)); | ||
754 | |||
755 | /* Set up to return from userspace. */ | ||
756 | err |= __put_user(frame->retcode, &frame->pretcode); | ||
757 | /* moveq #,d0; trap #0 */ | ||
758 | err |= __put_user(0x70004e40 + (__NR_sigreturn << 16), | ||
759 | (long __user *)(frame->retcode)); | ||
760 | |||
761 | if (err) | ||
762 | goto give_sigsegv; | ||
763 | |||
764 | push_cache ((unsigned long) &frame->retcode); | ||
765 | |||
766 | /* | ||
767 | * Set up registers for signal handler. All the state we are about | ||
768 | * to destroy is successfully copied to sigframe. | ||
769 | */ | ||
770 | wrusp ((unsigned long) frame); | ||
771 | regs->pc = (unsigned long) ka->sa.sa_handler; | ||
772 | |||
773 | /* | ||
774 | * This is subtle; if we build more than one sigframe, all but the | ||
775 | * first one will see frame format 0 and have fsize == 0, so we won't | ||
776 | * screw stkadj. | ||
777 | */ | ||
778 | if (fsize) | ||
779 | regs->stkadj = fsize; | ||
780 | |||
781 | /* Prepare to skip over the extra stuff in the exception frame. */ | ||
782 | if (regs->stkadj) { | ||
783 | struct pt_regs *tregs = | ||
784 | (struct pt_regs *)((ulong)regs + regs->stkadj); | ||
785 | #ifdef DEBUG | ||
786 | printk("Performing stackadjust=%04x\n", regs->stkadj); | ||
787 | #endif | ||
788 | /* This must be copied with decreasing addresses to | ||
789 | handle overlaps. */ | ||
790 | tregs->vector = 0; | ||
791 | tregs->format = 0; | ||
792 | tregs->pc = regs->pc; | ||
793 | tregs->sr = regs->sr; | ||
794 | } | ||
795 | return 0; | ||
796 | |||
797 | give_sigsegv: | ||
798 | force_sigsegv(sig, current); | ||
799 | return err; | ||
800 | } | ||
801 | |||
802 | static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, | ||
803 | sigset_t *set, struct pt_regs *regs) | ||
804 | { | ||
805 | struct rt_sigframe __user *frame; | ||
806 | int fsize = frame_extra_sizes[regs->format]; | ||
807 | int err = 0; | ||
808 | |||
809 | if (fsize < 0) { | ||
810 | #ifdef DEBUG | ||
811 | printk ("setup_frame: Unknown frame format %#x\n", | ||
812 | regs->format); | ||
813 | #endif | ||
814 | goto give_sigsegv; | ||
815 | } | ||
816 | |||
817 | frame = get_sigframe(ka, regs, sizeof(*frame)); | ||
818 | |||
819 | if (fsize) | ||
820 | err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize); | ||
821 | |||
822 | err |= __put_user((current_thread_info()->exec_domain | ||
823 | && current_thread_info()->exec_domain->signal_invmap | ||
824 | && sig < 32 | ||
825 | ? current_thread_info()->exec_domain->signal_invmap[sig] | ||
826 | : sig), | ||
827 | &frame->sig); | ||
828 | err |= __put_user(&frame->info, &frame->pinfo); | ||
829 | err |= __put_user(&frame->uc, &frame->puc); | ||
830 | err |= copy_siginfo_to_user(&frame->info, info); | ||
831 | |||
832 | /* Create the ucontext. */ | ||
833 | err |= __put_user(0, &frame->uc.uc_flags); | ||
834 | err |= __put_user(NULL, &frame->uc.uc_link); | ||
835 | err |= __put_user((void __user *)current->sas_ss_sp, | ||
836 | &frame->uc.uc_stack.ss_sp); | ||
837 | err |= __put_user(sas_ss_flags(rdusp()), | ||
838 | &frame->uc.uc_stack.ss_flags); | ||
839 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | ||
840 | err |= rt_setup_ucontext(&frame->uc, regs); | ||
841 | err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
842 | |||
843 | /* Set up to return from userspace. */ | ||
844 | err |= __put_user(frame->retcode, &frame->pretcode); | ||
845 | #ifdef __mcoldfire__ | ||
846 | /* movel #__NR_rt_sigreturn,d0; trap #0 */ | ||
847 | err |= __put_user(0x203c0000, (long __user *)(frame->retcode + 0)); | ||
848 | err |= __put_user(0x00004e40 + (__NR_rt_sigreturn << 16), | ||
849 | (long __user *)(frame->retcode + 4)); | ||
850 | #else | 3 | #else |
851 | /* moveq #,d0; notb d0; trap #0 */ | 4 | #include "signal_no.c" |
852 | err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16), | ||
853 | (long __user *)(frame->retcode + 0)); | ||
854 | err |= __put_user(0x4e40, (short __user *)(frame->retcode + 4)); | ||
855 | #endif | ||
856 | |||
857 | if (err) | ||
858 | goto give_sigsegv; | ||
859 | |||
860 | push_cache ((unsigned long) &frame->retcode); | ||
861 | |||
862 | /* | ||
863 | * Set up registers for signal handler. All the state we are about | ||
864 | * to destroy is successfully copied to sigframe. | ||
865 | */ | ||
866 | wrusp ((unsigned long) frame); | ||
867 | regs->pc = (unsigned long) ka->sa.sa_handler; | ||
868 | |||
869 | /* | ||
870 | * This is subtle; if we build more than one sigframe, all but the | ||
871 | * first one will see frame format 0 and have fsize == 0, so we won't | ||
872 | * screw stkadj. | ||
873 | */ | ||
874 | if (fsize) | ||
875 | regs->stkadj = fsize; | ||
876 | |||
877 | /* Prepare to skip over the extra stuff in the exception frame. */ | ||
878 | if (regs->stkadj) { | ||
879 | struct pt_regs *tregs = | ||
880 | (struct pt_regs *)((ulong)regs + regs->stkadj); | ||
881 | #ifdef DEBUG | ||
882 | printk("Performing stackadjust=%04x\n", regs->stkadj); | ||
883 | #endif | 5 | #endif |
884 | /* This must be copied with decreasing addresses to | ||
885 | handle overlaps. */ | ||
886 | tregs->vector = 0; | ||
887 | tregs->format = 0; | ||
888 | tregs->pc = regs->pc; | ||
889 | tregs->sr = regs->sr; | ||
890 | } | ||
891 | return 0; | ||
892 | |||
893 | give_sigsegv: | ||
894 | force_sigsegv(sig, current); | ||
895 | return err; | ||
896 | } | ||
897 | |||
898 | static inline void | ||
899 | handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) | ||
900 | { | ||
901 | switch (regs->d0) { | ||
902 | case -ERESTARTNOHAND: | ||
903 | if (!has_handler) | ||
904 | goto do_restart; | ||
905 | regs->d0 = -EINTR; | ||
906 | break; | ||
907 | |||
908 | case -ERESTART_RESTARTBLOCK: | ||
909 | if (!has_handler) { | ||
910 | regs->d0 = __NR_restart_syscall; | ||
911 | regs->pc -= 2; | ||
912 | break; | ||
913 | } | ||
914 | regs->d0 = -EINTR; | ||
915 | break; | ||
916 | |||
917 | case -ERESTARTSYS: | ||
918 | if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { | ||
919 | regs->d0 = -EINTR; | ||
920 | break; | ||
921 | } | ||
922 | /* fallthrough */ | ||
923 | case -ERESTARTNOINTR: | ||
924 | do_restart: | ||
925 | regs->d0 = regs->orig_d0; | ||
926 | regs->pc -= 2; | ||
927 | break; | ||
928 | } | ||
929 | } | ||
930 | |||
931 | void ptrace_signal_deliver(struct pt_regs *regs, void *cookie) | ||
932 | { | ||
933 | if (regs->orig_d0 < 0) | ||
934 | return; | ||
935 | switch (regs->d0) { | ||
936 | case -ERESTARTNOHAND: | ||
937 | case -ERESTARTSYS: | ||
938 | case -ERESTARTNOINTR: | ||
939 | regs->d0 = regs->orig_d0; | ||
940 | regs->orig_d0 = -1; | ||
941 | regs->pc -= 2; | ||
942 | break; | ||
943 | } | ||
944 | } | ||
945 | |||
946 | /* | ||
947 | * OK, we're invoking a handler | ||
948 | */ | ||
949 | static void | ||
950 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
951 | sigset_t *oldset, struct pt_regs *regs) | ||
952 | { | ||
953 | int err; | ||
954 | /* are we from a system call? */ | ||
955 | if (regs->orig_d0 >= 0) | ||
956 | /* If so, check system call restarting.. */ | ||
957 | handle_restart(regs, ka, 1); | ||
958 | |||
959 | /* set up the stack frame */ | ||
960 | if (ka->sa.sa_flags & SA_SIGINFO) | ||
961 | err = setup_rt_frame(sig, ka, info, oldset, regs); | ||
962 | else | ||
963 | err = setup_frame(sig, ka, oldset, regs); | ||
964 | |||
965 | if (err) | ||
966 | return; | ||
967 | |||
968 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | ||
969 | if (!(ka->sa.sa_flags & SA_NODEFER)) | ||
970 | sigaddset(¤t->blocked,sig); | ||
971 | recalc_sigpending(); | ||
972 | |||
973 | if (test_thread_flag(TIF_DELAYED_TRACE)) { | ||
974 | regs->sr &= ~0x8000; | ||
975 | send_sig(SIGTRAP, current, 1); | ||
976 | } | ||
977 | |||
978 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
979 | } | ||
980 | |||
981 | /* | ||
982 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
983 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
984 | * mistake. | ||
985 | */ | ||
986 | asmlinkage void do_signal(struct pt_regs *regs) | ||
987 | { | ||
988 | siginfo_t info; | ||
989 | struct k_sigaction ka; | ||
990 | int signr; | ||
991 | sigset_t *oldset; | ||
992 | |||
993 | current->thread.esp0 = (unsigned long) regs; | ||
994 | |||
995 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
996 | oldset = ¤t->saved_sigmask; | ||
997 | else | ||
998 | oldset = ¤t->blocked; | ||
999 | |||
1000 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | ||
1001 | if (signr > 0) { | ||
1002 | /* Whee! Actually deliver the signal. */ | ||
1003 | handle_signal(signr, &ka, &info, oldset, regs); | ||
1004 | return; | ||
1005 | } | ||
1006 | |||
1007 | /* Did we come from a system call? */ | ||
1008 | if (regs->orig_d0 >= 0) | ||
1009 | /* Restart the system call - no handlers present */ | ||
1010 | handle_restart(regs, NULL, 0); | ||
1011 | |||
1012 | /* If there's no signal to deliver, we just restore the saved mask. */ | ||
1013 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
1014 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
1015 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
1016 | } | ||
1017 | } | ||
diff --git a/arch/m68k/kernel/signal_mm.c b/arch/m68k/kernel/signal_mm.c new file mode 100644 index 000000000000..a0afc239304e --- /dev/null +++ b/arch/m68k/kernel/signal_mm.c | |||
@@ -0,0 +1,1017 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/kernel/signal.c | ||
3 | * | ||
4 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file COPYING in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * Linux/m68k support by Hamish Macdonald | ||
13 | * | ||
14 | * 68060 fixes by Jesper Skov | ||
15 | * | ||
16 | * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab | ||
17 | * | ||
18 | * mathemu support by Roman Zippel | ||
19 | * (Note: fpstate in the signal context is completely ignored for the emulator | ||
20 | * and the internal floating point format is put on stack) | ||
21 | */ | ||
22 | |||
23 | /* | ||
24 | * ++roman (07/09/96): implemented signal stacks (specially for tosemu on | ||
25 | * Atari :-) Current limitation: Only one sigstack can be active at one time. | ||
26 | * If a second signal with SA_ONSTACK set arrives while working on a sigstack, | ||
27 | * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested | ||
28 | * signal handlers! | ||
29 | */ | ||
30 | |||
31 | #include <linux/sched.h> | ||
32 | #include <linux/mm.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/signal.h> | ||
35 | #include <linux/syscalls.h> | ||
36 | #include <linux/errno.h> | ||
37 | #include <linux/wait.h> | ||
38 | #include <linux/ptrace.h> | ||
39 | #include <linux/unistd.h> | ||
40 | #include <linux/stddef.h> | ||
41 | #include <linux/highuid.h> | ||
42 | #include <linux/personality.h> | ||
43 | #include <linux/tty.h> | ||
44 | #include <linux/binfmts.h> | ||
45 | #include <linux/module.h> | ||
46 | |||
47 | #include <asm/setup.h> | ||
48 | #include <asm/uaccess.h> | ||
49 | #include <asm/pgtable.h> | ||
50 | #include <asm/traps.h> | ||
51 | #include <asm/ucontext.h> | ||
52 | |||
53 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | ||
54 | |||
55 | static const int frame_extra_sizes[16] = { | ||
56 | [1] = -1, /* sizeof(((struct frame *)0)->un.fmt1), */ | ||
57 | [2] = sizeof(((struct frame *)0)->un.fmt2), | ||
58 | [3] = sizeof(((struct frame *)0)->un.fmt3), | ||
59 | [4] = sizeof(((struct frame *)0)->un.fmt4), | ||
60 | [5] = -1, /* sizeof(((struct frame *)0)->un.fmt5), */ | ||
61 | [6] = -1, /* sizeof(((struct frame *)0)->un.fmt6), */ | ||
62 | [7] = sizeof(((struct frame *)0)->un.fmt7), | ||
63 | [8] = -1, /* sizeof(((struct frame *)0)->un.fmt8), */ | ||
64 | [9] = sizeof(((struct frame *)0)->un.fmt9), | ||
65 | [10] = sizeof(((struct frame *)0)->un.fmta), | ||
66 | [11] = sizeof(((struct frame *)0)->un.fmtb), | ||
67 | [12] = -1, /* sizeof(((struct frame *)0)->un.fmtc), */ | ||
68 | [13] = -1, /* sizeof(((struct frame *)0)->un.fmtd), */ | ||
69 | [14] = -1, /* sizeof(((struct frame *)0)->un.fmte), */ | ||
70 | [15] = -1, /* sizeof(((struct frame *)0)->un.fmtf), */ | ||
71 | }; | ||
72 | |||
73 | int handle_kernel_fault(struct pt_regs *regs) | ||
74 | { | ||
75 | const struct exception_table_entry *fixup; | ||
76 | struct pt_regs *tregs; | ||
77 | |||
78 | /* Are we prepared to handle this kernel fault? */ | ||
79 | fixup = search_exception_tables(regs->pc); | ||
80 | if (!fixup) | ||
81 | return 0; | ||
82 | |||
83 | /* Create a new four word stack frame, discarding the old one. */ | ||
84 | regs->stkadj = frame_extra_sizes[regs->format]; | ||
85 | tregs = (struct pt_regs *)((long)regs + regs->stkadj); | ||
86 | tregs->vector = regs->vector; | ||
87 | tregs->format = 0; | ||
88 | tregs->pc = fixup->fixup; | ||
89 | tregs->sr = regs->sr; | ||
90 | |||
91 | return 1; | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * Atomically swap in the new signal mask, and wait for a signal. | ||
96 | */ | ||
97 | asmlinkage int | ||
98 | sys_sigsuspend(int unused0, int unused1, old_sigset_t mask) | ||
99 | { | ||
100 | mask &= _BLOCKABLE; | ||
101 | spin_lock_irq(¤t->sighand->siglock); | ||
102 | current->saved_sigmask = current->blocked; | ||
103 | siginitset(¤t->blocked, mask); | ||
104 | recalc_sigpending(); | ||
105 | spin_unlock_irq(¤t->sighand->siglock); | ||
106 | |||
107 | current->state = TASK_INTERRUPTIBLE; | ||
108 | schedule(); | ||
109 | set_restore_sigmask(); | ||
110 | |||
111 | return -ERESTARTNOHAND; | ||
112 | } | ||
113 | |||
114 | asmlinkage int | ||
115 | sys_sigaction(int sig, const struct old_sigaction __user *act, | ||
116 | struct old_sigaction __user *oact) | ||
117 | { | ||
118 | struct k_sigaction new_ka, old_ka; | ||
119 | int ret; | ||
120 | |||
121 | if (act) { | ||
122 | old_sigset_t mask; | ||
123 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | ||
124 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | ||
125 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || | ||
126 | __get_user(new_ka.sa.sa_flags, &act->sa_flags) || | ||
127 | __get_user(mask, &act->sa_mask)) | ||
128 | return -EFAULT; | ||
129 | siginitset(&new_ka.sa.sa_mask, mask); | ||
130 | } | ||
131 | |||
132 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | ||
133 | |||
134 | if (!ret && oact) { | ||
135 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | ||
136 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | ||
137 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || | ||
138 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || | ||
139 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) | ||
140 | return -EFAULT; | ||
141 | } | ||
142 | |||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | asmlinkage int | ||
147 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) | ||
148 | { | ||
149 | return do_sigaltstack(uss, uoss, rdusp()); | ||
150 | } | ||
151 | |||
152 | |||
153 | /* | ||
154 | * Do a signal return; undo the signal stack. | ||
155 | * | ||
156 | * Keep the return code on the stack quadword aligned! | ||
157 | * That makes the cache flush below easier. | ||
158 | */ | ||
159 | |||
160 | struct sigframe | ||
161 | { | ||
162 | char __user *pretcode; | ||
163 | int sig; | ||
164 | int code; | ||
165 | struct sigcontext __user *psc; | ||
166 | char retcode[8]; | ||
167 | unsigned long extramask[_NSIG_WORDS-1]; | ||
168 | struct sigcontext sc; | ||
169 | }; | ||
170 | |||
171 | struct rt_sigframe | ||
172 | { | ||
173 | char __user *pretcode; | ||
174 | int sig; | ||
175 | struct siginfo __user *pinfo; | ||
176 | void __user *puc; | ||
177 | char retcode[8]; | ||
178 | struct siginfo info; | ||
179 | struct ucontext uc; | ||
180 | }; | ||
181 | |||
182 | |||
183 | static unsigned char fpu_version; /* version number of fpu, set by setup_frame */ | ||
184 | |||
185 | static inline int restore_fpu_state(struct sigcontext *sc) | ||
186 | { | ||
187 | int err = 1; | ||
188 | |||
189 | if (FPU_IS_EMU) { | ||
190 | /* restore registers */ | ||
191 | memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12); | ||
192 | memcpy(current->thread.fp, sc->sc_fpregs, 24); | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { | ||
197 | /* Verify the frame format. */ | ||
198 | if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version)) | ||
199 | goto out; | ||
200 | if (CPU_IS_020_OR_030) { | ||
201 | if (m68k_fputype & FPU_68881 && | ||
202 | !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4)) | ||
203 | goto out; | ||
204 | if (m68k_fputype & FPU_68882 && | ||
205 | !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4)) | ||
206 | goto out; | ||
207 | } else if (CPU_IS_040) { | ||
208 | if (!(sc->sc_fpstate[1] == 0x00 || | ||
209 | sc->sc_fpstate[1] == 0x28 || | ||
210 | sc->sc_fpstate[1] == 0x60)) | ||
211 | goto out; | ||
212 | } else if (CPU_IS_060) { | ||
213 | if (!(sc->sc_fpstate[3] == 0x00 || | ||
214 | sc->sc_fpstate[3] == 0x60 || | ||
215 | sc->sc_fpstate[3] == 0xe0)) | ||
216 | goto out; | ||
217 | } else | ||
218 | goto out; | ||
219 | |||
220 | __asm__ volatile (".chip 68k/68881\n\t" | ||
221 | "fmovemx %0,%%fp0-%%fp1\n\t" | ||
222 | "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t" | ||
223 | ".chip 68k" | ||
224 | : /* no outputs */ | ||
225 | : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl)); | ||
226 | } | ||
227 | __asm__ volatile (".chip 68k/68881\n\t" | ||
228 | "frestore %0\n\t" | ||
229 | ".chip 68k" : : "m" (*sc->sc_fpstate)); | ||
230 | err = 0; | ||
231 | |||
232 | out: | ||
233 | return err; | ||
234 | } | ||
235 | |||
236 | #define FPCONTEXT_SIZE 216 | ||
237 | #define uc_fpstate uc_filler[0] | ||
238 | #define uc_formatvec uc_filler[FPCONTEXT_SIZE/4] | ||
239 | #define uc_extra uc_filler[FPCONTEXT_SIZE/4+1] | ||
240 | |||
241 | static inline int rt_restore_fpu_state(struct ucontext __user *uc) | ||
242 | { | ||
243 | unsigned char fpstate[FPCONTEXT_SIZE]; | ||
244 | int context_size = CPU_IS_060 ? 8 : 0; | ||
245 | fpregset_t fpregs; | ||
246 | int err = 1; | ||
247 | |||
248 | if (FPU_IS_EMU) { | ||
249 | /* restore fpu control register */ | ||
250 | if (__copy_from_user(current->thread.fpcntl, | ||
251 | uc->uc_mcontext.fpregs.f_fpcntl, 12)) | ||
252 | goto out; | ||
253 | /* restore all other fpu register */ | ||
254 | if (__copy_from_user(current->thread.fp, | ||
255 | uc->uc_mcontext.fpregs.f_fpregs, 96)) | ||
256 | goto out; | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | if (__get_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate)) | ||
261 | goto out; | ||
262 | if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { | ||
263 | if (!CPU_IS_060) | ||
264 | context_size = fpstate[1]; | ||
265 | /* Verify the frame format. */ | ||
266 | if (!CPU_IS_060 && (fpstate[0] != fpu_version)) | ||
267 | goto out; | ||
268 | if (CPU_IS_020_OR_030) { | ||
269 | if (m68k_fputype & FPU_68881 && | ||
270 | !(context_size == 0x18 || context_size == 0xb4)) | ||
271 | goto out; | ||
272 | if (m68k_fputype & FPU_68882 && | ||
273 | !(context_size == 0x38 || context_size == 0xd4)) | ||
274 | goto out; | ||
275 | } else if (CPU_IS_040) { | ||
276 | if (!(context_size == 0x00 || | ||
277 | context_size == 0x28 || | ||
278 | context_size == 0x60)) | ||
279 | goto out; | ||
280 | } else if (CPU_IS_060) { | ||
281 | if (!(fpstate[3] == 0x00 || | ||
282 | fpstate[3] == 0x60 || | ||
283 | fpstate[3] == 0xe0)) | ||
284 | goto out; | ||
285 | } else | ||
286 | goto out; | ||
287 | if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs, | ||
288 | sizeof(fpregs))) | ||
289 | goto out; | ||
290 | __asm__ volatile (".chip 68k/68881\n\t" | ||
291 | "fmovemx %0,%%fp0-%%fp7\n\t" | ||
292 | "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t" | ||
293 | ".chip 68k" | ||
294 | : /* no outputs */ | ||
295 | : "m" (*fpregs.f_fpregs), | ||
296 | "m" (*fpregs.f_fpcntl)); | ||
297 | } | ||
298 | if (context_size && | ||
299 | __copy_from_user(fpstate + 4, (long __user *)&uc->uc_fpstate + 1, | ||
300 | context_size)) | ||
301 | goto out; | ||
302 | __asm__ volatile (".chip 68k/68881\n\t" | ||
303 | "frestore %0\n\t" | ||
304 | ".chip 68k" : : "m" (*fpstate)); | ||
305 | err = 0; | ||
306 | |||
307 | out: | ||
308 | return err; | ||
309 | } | ||
310 | |||
311 | static int mangle_kernel_stack(struct pt_regs *regs, int formatvec, | ||
312 | void __user *fp) | ||
313 | { | ||
314 | int fsize = frame_extra_sizes[formatvec >> 12]; | ||
315 | if (fsize < 0) { | ||
316 | /* | ||
317 | * user process trying to return with weird frame format | ||
318 | */ | ||
319 | #ifdef DEBUG | ||
320 | printk("user process returning with weird frame format\n"); | ||
321 | #endif | ||
322 | return 1; | ||
323 | } | ||
324 | if (!fsize) { | ||
325 | regs->format = formatvec >> 12; | ||
326 | regs->vector = formatvec & 0xfff; | ||
327 | } else { | ||
328 | struct switch_stack *sw = (struct switch_stack *)regs - 1; | ||
329 | unsigned long buf[fsize / 2]; /* yes, twice as much */ | ||
330 | |||
331 | /* that'll make sure that expansion won't crap over data */ | ||
332 | if (copy_from_user(buf + fsize / 4, fp, fsize)) | ||
333 | return 1; | ||
334 | |||
335 | /* point of no return */ | ||
336 | regs->format = formatvec >> 12; | ||
337 | regs->vector = formatvec & 0xfff; | ||
338 | #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) | ||
339 | __asm__ __volatile__ | ||
340 | (" movel %0,%/a0\n\t" | ||
341 | " subl %1,%/a0\n\t" /* make room on stack */ | ||
342 | " movel %/a0,%/sp\n\t" /* set stack pointer */ | ||
343 | /* move switch_stack and pt_regs */ | ||
344 | "1: movel %0@+,%/a0@+\n\t" | ||
345 | " dbra %2,1b\n\t" | ||
346 | " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */ | ||
347 | " lsrl #2,%1\n\t" | ||
348 | " subql #1,%1\n\t" | ||
349 | /* copy to the gap we'd made */ | ||
350 | "2: movel %4@+,%/a0@+\n\t" | ||
351 | " dbra %1,2b\n\t" | ||
352 | " bral ret_from_signal\n" | ||
353 | : /* no outputs, it doesn't ever return */ | ||
354 | : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), | ||
355 | "n" (frame_offset), "a" (buf + fsize/4) | ||
356 | : "a0"); | ||
357 | #undef frame_offset | ||
358 | } | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static inline int | ||
363 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp) | ||
364 | { | ||
365 | int formatvec; | ||
366 | struct sigcontext context; | ||
367 | int err; | ||
368 | |||
369 | /* Always make any pending restarted system calls return -EINTR */ | ||
370 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
371 | |||
372 | /* get previous context */ | ||
373 | if (copy_from_user(&context, usc, sizeof(context))) | ||
374 | goto badframe; | ||
375 | |||
376 | /* restore passed registers */ | ||
377 | regs->d0 = context.sc_d0; | ||
378 | regs->d1 = context.sc_d1; | ||
379 | regs->a0 = context.sc_a0; | ||
380 | regs->a1 = context.sc_a1; | ||
381 | regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff); | ||
382 | regs->pc = context.sc_pc; | ||
383 | regs->orig_d0 = -1; /* disable syscall checks */ | ||
384 | wrusp(context.sc_usp); | ||
385 | formatvec = context.sc_formatvec; | ||
386 | |||
387 | err = restore_fpu_state(&context); | ||
388 | |||
389 | if (err || mangle_kernel_stack(regs, formatvec, fp)) | ||
390 | goto badframe; | ||
391 | |||
392 | return 0; | ||
393 | |||
394 | badframe: | ||
395 | return 1; | ||
396 | } | ||
397 | |||
398 | static inline int | ||
399 | rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, | ||
400 | struct ucontext __user *uc) | ||
401 | { | ||
402 | int temp; | ||
403 | greg_t __user *gregs = uc->uc_mcontext.gregs; | ||
404 | unsigned long usp; | ||
405 | int err; | ||
406 | |||
407 | /* Always make any pending restarted system calls return -EINTR */ | ||
408 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
409 | |||
410 | err = __get_user(temp, &uc->uc_mcontext.version); | ||
411 | if (temp != MCONTEXT_VERSION) | ||
412 | goto badframe; | ||
413 | /* restore passed registers */ | ||
414 | err |= __get_user(regs->d0, &gregs[0]); | ||
415 | err |= __get_user(regs->d1, &gregs[1]); | ||
416 | err |= __get_user(regs->d2, &gregs[2]); | ||
417 | err |= __get_user(regs->d3, &gregs[3]); | ||
418 | err |= __get_user(regs->d4, &gregs[4]); | ||
419 | err |= __get_user(regs->d5, &gregs[5]); | ||
420 | err |= __get_user(sw->d6, &gregs[6]); | ||
421 | err |= __get_user(sw->d7, &gregs[7]); | ||
422 | err |= __get_user(regs->a0, &gregs[8]); | ||
423 | err |= __get_user(regs->a1, &gregs[9]); | ||
424 | err |= __get_user(regs->a2, &gregs[10]); | ||
425 | err |= __get_user(sw->a3, &gregs[11]); | ||
426 | err |= __get_user(sw->a4, &gregs[12]); | ||
427 | err |= __get_user(sw->a5, &gregs[13]); | ||
428 | err |= __get_user(sw->a6, &gregs[14]); | ||
429 | err |= __get_user(usp, &gregs[15]); | ||
430 | wrusp(usp); | ||
431 | err |= __get_user(regs->pc, &gregs[16]); | ||
432 | err |= __get_user(temp, &gregs[17]); | ||
433 | regs->sr = (regs->sr & 0xff00) | (temp & 0xff); | ||
434 | regs->orig_d0 = -1; /* disable syscall checks */ | ||
435 | err |= __get_user(temp, &uc->uc_formatvec); | ||
436 | |||
437 | err |= rt_restore_fpu_state(uc); | ||
438 | |||
439 | if (err || do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) | ||
440 | goto badframe; | ||
441 | |||
442 | if (mangle_kernel_stack(regs, temp, &uc->uc_extra)) | ||
443 | goto badframe; | ||
444 | |||
445 | return 0; | ||
446 | |||
447 | badframe: | ||
448 | return 1; | ||
449 | } | ||
450 | |||
451 | asmlinkage int do_sigreturn(unsigned long __unused) | ||
452 | { | ||
453 | struct switch_stack *sw = (struct switch_stack *) &__unused; | ||
454 | struct pt_regs *regs = (struct pt_regs *) (sw + 1); | ||
455 | unsigned long usp = rdusp(); | ||
456 | struct sigframe __user *frame = (struct sigframe __user *)(usp - 4); | ||
457 | sigset_t set; | ||
458 | |||
459 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
460 | goto badframe; | ||
461 | if (__get_user(set.sig[0], &frame->sc.sc_mask) || | ||
462 | (_NSIG_WORDS > 1 && | ||
463 | __copy_from_user(&set.sig[1], &frame->extramask, | ||
464 | sizeof(frame->extramask)))) | ||
465 | goto badframe; | ||
466 | |||
467 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
468 | current->blocked = set; | ||
469 | recalc_sigpending(); | ||
470 | |||
471 | if (restore_sigcontext(regs, &frame->sc, frame + 1)) | ||
472 | goto badframe; | ||
473 | return regs->d0; | ||
474 | |||
475 | badframe: | ||
476 | force_sig(SIGSEGV, current); | ||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | asmlinkage int do_rt_sigreturn(unsigned long __unused) | ||
481 | { | ||
482 | struct switch_stack *sw = (struct switch_stack *) &__unused; | ||
483 | struct pt_regs *regs = (struct pt_regs *) (sw + 1); | ||
484 | unsigned long usp = rdusp(); | ||
485 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4); | ||
486 | sigset_t set; | ||
487 | |||
488 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
489 | goto badframe; | ||
490 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | ||
491 | goto badframe; | ||
492 | |||
493 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
494 | current->blocked = set; | ||
495 | recalc_sigpending(); | ||
496 | |||
497 | if (rt_restore_ucontext(regs, sw, &frame->uc)) | ||
498 | goto badframe; | ||
499 | return regs->d0; | ||
500 | |||
501 | badframe: | ||
502 | force_sig(SIGSEGV, current); | ||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | /* | ||
507 | * Set up a signal frame. | ||
508 | */ | ||
509 | |||
510 | static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs) | ||
511 | { | ||
512 | if (FPU_IS_EMU) { | ||
513 | /* save registers */ | ||
514 | memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12); | ||
515 | memcpy(sc->sc_fpregs, current->thread.fp, 24); | ||
516 | return; | ||
517 | } | ||
518 | |||
519 | __asm__ volatile (".chip 68k/68881\n\t" | ||
520 | "fsave %0\n\t" | ||
521 | ".chip 68k" | ||
522 | : : "m" (*sc->sc_fpstate) : "memory"); | ||
523 | |||
524 | if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { | ||
525 | fpu_version = sc->sc_fpstate[0]; | ||
526 | if (CPU_IS_020_OR_030 && | ||
527 | regs->vector >= (VEC_FPBRUC * 4) && | ||
528 | regs->vector <= (VEC_FPNAN * 4)) { | ||
529 | /* Clear pending exception in 68882 idle frame */ | ||
530 | if (*(unsigned short *) sc->sc_fpstate == 0x1f38) | ||
531 | sc->sc_fpstate[0x38] |= 1 << 3; | ||
532 | } | ||
533 | __asm__ volatile (".chip 68k/68881\n\t" | ||
534 | "fmovemx %%fp0-%%fp1,%0\n\t" | ||
535 | "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t" | ||
536 | ".chip 68k" | ||
537 | : "=m" (*sc->sc_fpregs), | ||
538 | "=m" (*sc->sc_fpcntl) | ||
539 | : /* no inputs */ | ||
540 | : "memory"); | ||
541 | } | ||
542 | } | ||
543 | |||
544 | static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *regs) | ||
545 | { | ||
546 | unsigned char fpstate[FPCONTEXT_SIZE]; | ||
547 | int context_size = CPU_IS_060 ? 8 : 0; | ||
548 | int err = 0; | ||
549 | |||
550 | if (FPU_IS_EMU) { | ||
551 | /* save fpu control register */ | ||
552 | err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpcntl, | ||
553 | current->thread.fpcntl, 12); | ||
554 | /* save all other fpu register */ | ||
555 | err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs, | ||
556 | current->thread.fp, 96); | ||
557 | return err; | ||
558 | } | ||
559 | |||
560 | __asm__ volatile (".chip 68k/68881\n\t" | ||
561 | "fsave %0\n\t" | ||
562 | ".chip 68k" | ||
563 | : : "m" (*fpstate) : "memory"); | ||
564 | |||
565 | err |= __put_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate); | ||
566 | if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { | ||
567 | fpregset_t fpregs; | ||
568 | if (!CPU_IS_060) | ||
569 | context_size = fpstate[1]; | ||
570 | fpu_version = fpstate[0]; | ||
571 | if (CPU_IS_020_OR_030 && | ||
572 | regs->vector >= (VEC_FPBRUC * 4) && | ||
573 | regs->vector <= (VEC_FPNAN * 4)) { | ||
574 | /* Clear pending exception in 68882 idle frame */ | ||
575 | if (*(unsigned short *) fpstate == 0x1f38) | ||
576 | fpstate[0x38] |= 1 << 3; | ||
577 | } | ||
578 | __asm__ volatile (".chip 68k/68881\n\t" | ||
579 | "fmovemx %%fp0-%%fp7,%0\n\t" | ||
580 | "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t" | ||
581 | ".chip 68k" | ||
582 | : "=m" (*fpregs.f_fpregs), | ||
583 | "=m" (*fpregs.f_fpcntl) | ||
584 | : /* no inputs */ | ||
585 | : "memory"); | ||
586 | err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, | ||
587 | sizeof(fpregs)); | ||
588 | } | ||
589 | if (context_size) | ||
590 | err |= copy_to_user((long __user *)&uc->uc_fpstate + 1, fpstate + 4, | ||
591 | context_size); | ||
592 | return err; | ||
593 | } | ||
594 | |||
595 | static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, | ||
596 | unsigned long mask) | ||
597 | { | ||
598 | sc->sc_mask = mask; | ||
599 | sc->sc_usp = rdusp(); | ||
600 | sc->sc_d0 = regs->d0; | ||
601 | sc->sc_d1 = regs->d1; | ||
602 | sc->sc_a0 = regs->a0; | ||
603 | sc->sc_a1 = regs->a1; | ||
604 | sc->sc_sr = regs->sr; | ||
605 | sc->sc_pc = regs->pc; | ||
606 | sc->sc_formatvec = regs->format << 12 | regs->vector; | ||
607 | save_fpu_state(sc, regs); | ||
608 | } | ||
609 | |||
610 | static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs) | ||
611 | { | ||
612 | struct switch_stack *sw = (struct switch_stack *)regs - 1; | ||
613 | greg_t __user *gregs = uc->uc_mcontext.gregs; | ||
614 | int err = 0; | ||
615 | |||
616 | err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); | ||
617 | err |= __put_user(regs->d0, &gregs[0]); | ||
618 | err |= __put_user(regs->d1, &gregs[1]); | ||
619 | err |= __put_user(regs->d2, &gregs[2]); | ||
620 | err |= __put_user(regs->d3, &gregs[3]); | ||
621 | err |= __put_user(regs->d4, &gregs[4]); | ||
622 | err |= __put_user(regs->d5, &gregs[5]); | ||
623 | err |= __put_user(sw->d6, &gregs[6]); | ||
624 | err |= __put_user(sw->d7, &gregs[7]); | ||
625 | err |= __put_user(regs->a0, &gregs[8]); | ||
626 | err |= __put_user(regs->a1, &gregs[9]); | ||
627 | err |= __put_user(regs->a2, &gregs[10]); | ||
628 | err |= __put_user(sw->a3, &gregs[11]); | ||
629 | err |= __put_user(sw->a4, &gregs[12]); | ||
630 | err |= __put_user(sw->a5, &gregs[13]); | ||
631 | err |= __put_user(sw->a6, &gregs[14]); | ||
632 | err |= __put_user(rdusp(), &gregs[15]); | ||
633 | err |= __put_user(regs->pc, &gregs[16]); | ||
634 | err |= __put_user(regs->sr, &gregs[17]); | ||
635 | err |= __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec); | ||
636 | err |= rt_save_fpu_state(uc, regs); | ||
637 | return err; | ||
638 | } | ||
639 | |||
640 | static inline void push_cache (unsigned long vaddr) | ||
641 | { | ||
642 | /* | ||
643 | * Using the old cache_push_v() was really a big waste. | ||
644 | * | ||
645 | * What we are trying to do is to flush 8 bytes to ram. | ||
646 | * Flushing 2 cache lines of 16 bytes is much cheaper than | ||
647 | * flushing 1 or 2 pages, as previously done in | ||
648 | * cache_push_v(). | ||
649 | * Jes | ||
650 | */ | ||
651 | if (CPU_IS_040) { | ||
652 | unsigned long temp; | ||
653 | |||
654 | __asm__ __volatile__ (".chip 68040\n\t" | ||
655 | "nop\n\t" | ||
656 | "ptestr (%1)\n\t" | ||
657 | "movec %%mmusr,%0\n\t" | ||
658 | ".chip 68k" | ||
659 | : "=r" (temp) | ||
660 | : "a" (vaddr)); | ||
661 | |||
662 | temp &= PAGE_MASK; | ||
663 | temp |= vaddr & ~PAGE_MASK; | ||
664 | |||
665 | __asm__ __volatile__ (".chip 68040\n\t" | ||
666 | "nop\n\t" | ||
667 | "cpushl %%bc,(%0)\n\t" | ||
668 | ".chip 68k" | ||
669 | : : "a" (temp)); | ||
670 | } | ||
671 | else if (CPU_IS_060) { | ||
672 | unsigned long temp; | ||
673 | __asm__ __volatile__ (".chip 68060\n\t" | ||
674 | "plpar (%0)\n\t" | ||
675 | ".chip 68k" | ||
676 | : "=a" (temp) | ||
677 | : "0" (vaddr)); | ||
678 | __asm__ __volatile__ (".chip 68060\n\t" | ||
679 | "cpushl %%bc,(%0)\n\t" | ||
680 | ".chip 68k" | ||
681 | : : "a" (temp)); | ||
682 | } | ||
683 | else { | ||
684 | /* | ||
685 | * 68030/68020 have no writeback cache; | ||
686 | * still need to clear icache. | ||
687 | * Note that vaddr is guaranteed to be long word aligned. | ||
688 | */ | ||
689 | unsigned long temp; | ||
690 | asm volatile ("movec %%cacr,%0" : "=r" (temp)); | ||
691 | temp += 4; | ||
692 | asm volatile ("movec %0,%%caar\n\t" | ||
693 | "movec %1,%%cacr" | ||
694 | : : "r" (vaddr), "r" (temp)); | ||
695 | asm volatile ("movec %0,%%caar\n\t" | ||
696 | "movec %1,%%cacr" | ||
697 | : : "r" (vaddr + 4), "r" (temp)); | ||
698 | } | ||
699 | } | ||
700 | |||
701 | static inline void __user * | ||
702 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | ||
703 | { | ||
704 | unsigned long usp; | ||
705 | |||
706 | /* Default to using normal stack. */ | ||
707 | usp = rdusp(); | ||
708 | |||
709 | /* This is the X/Open sanctioned signal stack switching. */ | ||
710 | if (ka->sa.sa_flags & SA_ONSTACK) { | ||
711 | if (!sas_ss_flags(usp)) | ||
712 | usp = current->sas_ss_sp + current->sas_ss_size; | ||
713 | } | ||
714 | return (void __user *)((usp - frame_size) & -8UL); | ||
715 | } | ||
716 | |||
717 | static int setup_frame (int sig, struct k_sigaction *ka, | ||
718 | sigset_t *set, struct pt_regs *regs) | ||
719 | { | ||
720 | struct sigframe __user *frame; | ||
721 | int fsize = frame_extra_sizes[regs->format]; | ||
722 | struct sigcontext context; | ||
723 | int err = 0; | ||
724 | |||
725 | if (fsize < 0) { | ||
726 | #ifdef DEBUG | ||
727 | printk ("setup_frame: Unknown frame format %#x\n", | ||
728 | regs->format); | ||
729 | #endif | ||
730 | goto give_sigsegv; | ||
731 | } | ||
732 | |||
733 | frame = get_sigframe(ka, regs, sizeof(*frame) + fsize); | ||
734 | |||
735 | if (fsize) | ||
736 | err |= copy_to_user (frame + 1, regs + 1, fsize); | ||
737 | |||
738 | err |= __put_user((current_thread_info()->exec_domain | ||
739 | && current_thread_info()->exec_domain->signal_invmap | ||
740 | && sig < 32 | ||
741 | ? current_thread_info()->exec_domain->signal_invmap[sig] | ||
742 | : sig), | ||
743 | &frame->sig); | ||
744 | |||
745 | err |= __put_user(regs->vector, &frame->code); | ||
746 | err |= __put_user(&frame->sc, &frame->psc); | ||
747 | |||
748 | if (_NSIG_WORDS > 1) | ||
749 | err |= copy_to_user(frame->extramask, &set->sig[1], | ||
750 | sizeof(frame->extramask)); | ||
751 | |||
752 | setup_sigcontext(&context, regs, set->sig[0]); | ||
753 | err |= copy_to_user (&frame->sc, &context, sizeof(context)); | ||
754 | |||
755 | /* Set up to return from userspace. */ | ||
756 | err |= __put_user(frame->retcode, &frame->pretcode); | ||
757 | /* moveq #,d0; trap #0 */ | ||
758 | err |= __put_user(0x70004e40 + (__NR_sigreturn << 16), | ||
759 | (long __user *)(frame->retcode)); | ||
760 | |||
761 | if (err) | ||
762 | goto give_sigsegv; | ||
763 | |||
764 | push_cache ((unsigned long) &frame->retcode); | ||
765 | |||
766 | /* | ||
767 | * Set up registers for signal handler. All the state we are about | ||
768 | * to destroy is successfully copied to sigframe. | ||
769 | */ | ||
770 | wrusp ((unsigned long) frame); | ||
771 | regs->pc = (unsigned long) ka->sa.sa_handler; | ||
772 | |||
773 | /* | ||
774 | * This is subtle; if we build more than one sigframe, all but the | ||
775 | * first one will see frame format 0 and have fsize == 0, so we won't | ||
776 | * screw stkadj. | ||
777 | */ | ||
778 | if (fsize) | ||
779 | regs->stkadj = fsize; | ||
780 | |||
781 | /* Prepare to skip over the extra stuff in the exception frame. */ | ||
782 | if (regs->stkadj) { | ||
783 | struct pt_regs *tregs = | ||
784 | (struct pt_regs *)((ulong)regs + regs->stkadj); | ||
785 | #ifdef DEBUG | ||
786 | printk("Performing stackadjust=%04x\n", regs->stkadj); | ||
787 | #endif | ||
788 | /* This must be copied with decreasing addresses to | ||
789 | handle overlaps. */ | ||
790 | tregs->vector = 0; | ||
791 | tregs->format = 0; | ||
792 | tregs->pc = regs->pc; | ||
793 | tregs->sr = regs->sr; | ||
794 | } | ||
795 | return 0; | ||
796 | |||
797 | give_sigsegv: | ||
798 | force_sigsegv(sig, current); | ||
799 | return err; | ||
800 | } | ||
801 | |||
802 | static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, | ||
803 | sigset_t *set, struct pt_regs *regs) | ||
804 | { | ||
805 | struct rt_sigframe __user *frame; | ||
806 | int fsize = frame_extra_sizes[regs->format]; | ||
807 | int err = 0; | ||
808 | |||
809 | if (fsize < 0) { | ||
810 | #ifdef DEBUG | ||
811 | printk ("setup_frame: Unknown frame format %#x\n", | ||
812 | regs->format); | ||
813 | #endif | ||
814 | goto give_sigsegv; | ||
815 | } | ||
816 | |||
817 | frame = get_sigframe(ka, regs, sizeof(*frame)); | ||
818 | |||
819 | if (fsize) | ||
820 | err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize); | ||
821 | |||
822 | err |= __put_user((current_thread_info()->exec_domain | ||
823 | && current_thread_info()->exec_domain->signal_invmap | ||
824 | && sig < 32 | ||
825 | ? current_thread_info()->exec_domain->signal_invmap[sig] | ||
826 | : sig), | ||
827 | &frame->sig); | ||
828 | err |= __put_user(&frame->info, &frame->pinfo); | ||
829 | err |= __put_user(&frame->uc, &frame->puc); | ||
830 | err |= copy_siginfo_to_user(&frame->info, info); | ||
831 | |||
832 | /* Create the ucontext. */ | ||
833 | err |= __put_user(0, &frame->uc.uc_flags); | ||
834 | err |= __put_user(NULL, &frame->uc.uc_link); | ||
835 | err |= __put_user((void __user *)current->sas_ss_sp, | ||
836 | &frame->uc.uc_stack.ss_sp); | ||
837 | err |= __put_user(sas_ss_flags(rdusp()), | ||
838 | &frame->uc.uc_stack.ss_flags); | ||
839 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | ||
840 | err |= rt_setup_ucontext(&frame->uc, regs); | ||
841 | err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
842 | |||
843 | /* Set up to return from userspace. */ | ||
844 | err |= __put_user(frame->retcode, &frame->pretcode); | ||
845 | #ifdef __mcoldfire__ | ||
846 | /* movel #__NR_rt_sigreturn,d0; trap #0 */ | ||
847 | err |= __put_user(0x203c0000, (long __user *)(frame->retcode + 0)); | ||
848 | err |= __put_user(0x00004e40 + (__NR_rt_sigreturn << 16), | ||
849 | (long __user *)(frame->retcode + 4)); | ||
850 | #else | ||
851 | /* moveq #,d0; notb d0; trap #0 */ | ||
852 | err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16), | ||
853 | (long __user *)(frame->retcode + 0)); | ||
854 | err |= __put_user(0x4e40, (short __user *)(frame->retcode + 4)); | ||
855 | #endif | ||
856 | |||
857 | if (err) | ||
858 | goto give_sigsegv; | ||
859 | |||
860 | push_cache ((unsigned long) &frame->retcode); | ||
861 | |||
862 | /* | ||
863 | * Set up registers for signal handler. All the state we are about | ||
864 | * to destroy is successfully copied to sigframe. | ||
865 | */ | ||
866 | wrusp ((unsigned long) frame); | ||
867 | regs->pc = (unsigned long) ka->sa.sa_handler; | ||
868 | |||
869 | /* | ||
870 | * This is subtle; if we build more than one sigframe, all but the | ||
871 | * first one will see frame format 0 and have fsize == 0, so we won't | ||
872 | * screw stkadj. | ||
873 | */ | ||
874 | if (fsize) | ||
875 | regs->stkadj = fsize; | ||
876 | |||
877 | /* Prepare to skip over the extra stuff in the exception frame. */ | ||
878 | if (regs->stkadj) { | ||
879 | struct pt_regs *tregs = | ||
880 | (struct pt_regs *)((ulong)regs + regs->stkadj); | ||
881 | #ifdef DEBUG | ||
882 | printk("Performing stackadjust=%04x\n", regs->stkadj); | ||
883 | #endif | ||
884 | /* This must be copied with decreasing addresses to | ||
885 | handle overlaps. */ | ||
886 | tregs->vector = 0; | ||
887 | tregs->format = 0; | ||
888 | tregs->pc = regs->pc; | ||
889 | tregs->sr = regs->sr; | ||
890 | } | ||
891 | return 0; | ||
892 | |||
893 | give_sigsegv: | ||
894 | force_sigsegv(sig, current); | ||
895 | return err; | ||
896 | } | ||
897 | |||
898 | static inline void | ||
899 | handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) | ||
900 | { | ||
901 | switch (regs->d0) { | ||
902 | case -ERESTARTNOHAND: | ||
903 | if (!has_handler) | ||
904 | goto do_restart; | ||
905 | regs->d0 = -EINTR; | ||
906 | break; | ||
907 | |||
908 | case -ERESTART_RESTARTBLOCK: | ||
909 | if (!has_handler) { | ||
910 | regs->d0 = __NR_restart_syscall; | ||
911 | regs->pc -= 2; | ||
912 | break; | ||
913 | } | ||
914 | regs->d0 = -EINTR; | ||
915 | break; | ||
916 | |||
917 | case -ERESTARTSYS: | ||
918 | if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { | ||
919 | regs->d0 = -EINTR; | ||
920 | break; | ||
921 | } | ||
922 | /* fallthrough */ | ||
923 | case -ERESTARTNOINTR: | ||
924 | do_restart: | ||
925 | regs->d0 = regs->orig_d0; | ||
926 | regs->pc -= 2; | ||
927 | break; | ||
928 | } | ||
929 | } | ||
930 | |||
931 | void ptrace_signal_deliver(struct pt_regs *regs, void *cookie) | ||
932 | { | ||
933 | if (regs->orig_d0 < 0) | ||
934 | return; | ||
935 | switch (regs->d0) { | ||
936 | case -ERESTARTNOHAND: | ||
937 | case -ERESTARTSYS: | ||
938 | case -ERESTARTNOINTR: | ||
939 | regs->d0 = regs->orig_d0; | ||
940 | regs->orig_d0 = -1; | ||
941 | regs->pc -= 2; | ||
942 | break; | ||
943 | } | ||
944 | } | ||
945 | |||
946 | /* | ||
947 | * OK, we're invoking a handler | ||
948 | */ | ||
949 | static void | ||
950 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
951 | sigset_t *oldset, struct pt_regs *regs) | ||
952 | { | ||
953 | int err; | ||
954 | /* are we from a system call? */ | ||
955 | if (regs->orig_d0 >= 0) | ||
956 | /* If so, check system call restarting.. */ | ||
957 | handle_restart(regs, ka, 1); | ||
958 | |||
959 | /* set up the stack frame */ | ||
960 | if (ka->sa.sa_flags & SA_SIGINFO) | ||
961 | err = setup_rt_frame(sig, ka, info, oldset, regs); | ||
962 | else | ||
963 | err = setup_frame(sig, ka, oldset, regs); | ||
964 | |||
965 | if (err) | ||
966 | return; | ||
967 | |||
968 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | ||
969 | if (!(ka->sa.sa_flags & SA_NODEFER)) | ||
970 | sigaddset(¤t->blocked,sig); | ||
971 | recalc_sigpending(); | ||
972 | |||
973 | if (test_thread_flag(TIF_DELAYED_TRACE)) { | ||
974 | regs->sr &= ~0x8000; | ||
975 | send_sig(SIGTRAP, current, 1); | ||
976 | } | ||
977 | |||
978 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
979 | } | ||
980 | |||
981 | /* | ||
982 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
983 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
984 | * mistake. | ||
985 | */ | ||
986 | asmlinkage void do_signal(struct pt_regs *regs) | ||
987 | { | ||
988 | siginfo_t info; | ||
989 | struct k_sigaction ka; | ||
990 | int signr; | ||
991 | sigset_t *oldset; | ||
992 | |||
993 | current->thread.esp0 = (unsigned long) regs; | ||
994 | |||
995 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
996 | oldset = ¤t->saved_sigmask; | ||
997 | else | ||
998 | oldset = ¤t->blocked; | ||
999 | |||
1000 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | ||
1001 | if (signr > 0) { | ||
1002 | /* Whee! Actually deliver the signal. */ | ||
1003 | handle_signal(signr, &ka, &info, oldset, regs); | ||
1004 | return; | ||
1005 | } | ||
1006 | |||
1007 | /* Did we come from a system call? */ | ||
1008 | if (regs->orig_d0 >= 0) | ||
1009 | /* Restart the system call - no handlers present */ | ||
1010 | handle_restart(regs, NULL, 0); | ||
1011 | |||
1012 | /* If there's no signal to deliver, we just restore the saved mask. */ | ||
1013 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
1014 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
1015 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
1016 | } | ||
1017 | } | ||
diff --git a/arch/m68knommu/kernel/signal.c b/arch/m68k/kernel/signal_no.c index 36a81bb6835a..36a81bb6835a 100644 --- a/arch/m68knommu/kernel/signal.c +++ b/arch/m68k/kernel/signal_no.c | |||
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index 3db2e7f902aa..63013df33584 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c | |||
@@ -1,546 +1,5 @@ | |||
1 | /* | 1 | #ifdef CONFIG_MMU |
2 | * linux/arch/m68k/kernel/sys_m68k.c | 2 | #include "sys_m68k_mm.c" |
3 | * | 3 | #else |
4 | * This file contains various random system calls that | 4 | #include "sys_m68k_no.c" |
5 | * have a non-standard calling sequence on the Linux/m68k | 5 | #endif |
6 | * platform. | ||
7 | */ | ||
8 | |||
9 | #include <linux/capability.h> | ||
10 | #include <linux/errno.h> | ||
11 | #include <linux/sched.h> | ||
12 | #include <linux/mm.h> | ||
13 | #include <linux/fs.h> | ||
14 | #include <linux/smp.h> | ||
15 | #include <linux/sem.h> | ||
16 | #include <linux/msg.h> | ||
17 | #include <linux/shm.h> | ||
18 | #include <linux/stat.h> | ||
19 | #include <linux/syscalls.h> | ||
20 | #include <linux/mman.h> | ||
21 | #include <linux/file.h> | ||
22 | #include <linux/ipc.h> | ||
23 | |||
24 | #include <asm/setup.h> | ||
25 | #include <asm/uaccess.h> | ||
26 | #include <asm/cachectl.h> | ||
27 | #include <asm/traps.h> | ||
28 | #include <asm/page.h> | ||
29 | #include <asm/unistd.h> | ||
30 | #include <linux/elf.h> | ||
31 | #include <asm/tlb.h> | ||
32 | |||
33 | asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, | ||
34 | unsigned long error_code); | ||
35 | |||
36 | asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, | ||
37 | unsigned long prot, unsigned long flags, | ||
38 | unsigned long fd, unsigned long pgoff) | ||
39 | { | ||
40 | /* | ||
41 | * This is wrong for sun3 - there PAGE_SIZE is 8Kb, | ||
42 | * so we need to shift the argument down by 1; m68k mmap64(3) | ||
43 | * (in libc) expects the last argument of mmap2 in 4Kb units. | ||
44 | */ | ||
45 | return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); | ||
46 | } | ||
47 | |||
48 | /* Convert virtual (user) address VADDR to physical address PADDR */ | ||
49 | #define virt_to_phys_040(vaddr) \ | ||
50 | ({ \ | ||
51 | unsigned long _mmusr, _paddr; \ | ||
52 | \ | ||
53 | __asm__ __volatile__ (".chip 68040\n\t" \ | ||
54 | "ptestr (%1)\n\t" \ | ||
55 | "movec %%mmusr,%0\n\t" \ | ||
56 | ".chip 68k" \ | ||
57 | : "=r" (_mmusr) \ | ||
58 | : "a" (vaddr)); \ | ||
59 | _paddr = (_mmusr & MMU_R_040) ? (_mmusr & PAGE_MASK) : 0; \ | ||
60 | _paddr; \ | ||
61 | }) | ||
62 | |||
63 | static inline int | ||
64 | cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len) | ||
65 | { | ||
66 | unsigned long paddr, i; | ||
67 | |||
68 | switch (scope) | ||
69 | { | ||
70 | case FLUSH_SCOPE_ALL: | ||
71 | switch (cache) | ||
72 | { | ||
73 | case FLUSH_CACHE_DATA: | ||
74 | /* This nop is needed for some broken versions of the 68040. */ | ||
75 | __asm__ __volatile__ ("nop\n\t" | ||
76 | ".chip 68040\n\t" | ||
77 | "cpusha %dc\n\t" | ||
78 | ".chip 68k"); | ||
79 | break; | ||
80 | case FLUSH_CACHE_INSN: | ||
81 | __asm__ __volatile__ ("nop\n\t" | ||
82 | ".chip 68040\n\t" | ||
83 | "cpusha %ic\n\t" | ||
84 | ".chip 68k"); | ||
85 | break; | ||
86 | default: | ||
87 | case FLUSH_CACHE_BOTH: | ||
88 | __asm__ __volatile__ ("nop\n\t" | ||
89 | ".chip 68040\n\t" | ||
90 | "cpusha %bc\n\t" | ||
91 | ".chip 68k"); | ||
92 | break; | ||
93 | } | ||
94 | break; | ||
95 | |||
96 | case FLUSH_SCOPE_LINE: | ||
97 | /* Find the physical address of the first mapped page in the | ||
98 | address range. */ | ||
99 | if ((paddr = virt_to_phys_040(addr))) { | ||
100 | paddr += addr & ~(PAGE_MASK | 15); | ||
101 | len = (len + (addr & 15) + 15) >> 4; | ||
102 | } else { | ||
103 | unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK); | ||
104 | |||
105 | if (len <= tmp) | ||
106 | return 0; | ||
107 | addr += tmp; | ||
108 | len -= tmp; | ||
109 | tmp = PAGE_SIZE; | ||
110 | for (;;) | ||
111 | { | ||
112 | if ((paddr = virt_to_phys_040(addr))) | ||
113 | break; | ||
114 | if (len <= tmp) | ||
115 | return 0; | ||
116 | addr += tmp; | ||
117 | len -= tmp; | ||
118 | } | ||
119 | len = (len + 15) >> 4; | ||
120 | } | ||
121 | i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4; | ||
122 | while (len--) | ||
123 | { | ||
124 | switch (cache) | ||
125 | { | ||
126 | case FLUSH_CACHE_DATA: | ||
127 | __asm__ __volatile__ ("nop\n\t" | ||
128 | ".chip 68040\n\t" | ||
129 | "cpushl %%dc,(%0)\n\t" | ||
130 | ".chip 68k" | ||
131 | : : "a" (paddr)); | ||
132 | break; | ||
133 | case FLUSH_CACHE_INSN: | ||
134 | __asm__ __volatile__ ("nop\n\t" | ||
135 | ".chip 68040\n\t" | ||
136 | "cpushl %%ic,(%0)\n\t" | ||
137 | ".chip 68k" | ||
138 | : : "a" (paddr)); | ||
139 | break; | ||
140 | default: | ||
141 | case FLUSH_CACHE_BOTH: | ||
142 | __asm__ __volatile__ ("nop\n\t" | ||
143 | ".chip 68040\n\t" | ||
144 | "cpushl %%bc,(%0)\n\t" | ||
145 | ".chip 68k" | ||
146 | : : "a" (paddr)); | ||
147 | break; | ||
148 | } | ||
149 | if (!--i && len) | ||
150 | { | ||
151 | /* | ||
152 | * No need to page align here since it is done by | ||
153 | * virt_to_phys_040(). | ||
154 | */ | ||
155 | addr += PAGE_SIZE; | ||
156 | i = PAGE_SIZE / 16; | ||
157 | /* Recompute physical address when crossing a page | ||
158 | boundary. */ | ||
159 | for (;;) | ||
160 | { | ||
161 | if ((paddr = virt_to_phys_040(addr))) | ||
162 | break; | ||
163 | if (len <= i) | ||
164 | return 0; | ||
165 | len -= i; | ||
166 | addr += PAGE_SIZE; | ||
167 | } | ||
168 | } | ||
169 | else | ||
170 | paddr += 16; | ||
171 | } | ||
172 | break; | ||
173 | |||
174 | default: | ||
175 | case FLUSH_SCOPE_PAGE: | ||
176 | len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1); | ||
177 | for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE) | ||
178 | { | ||
179 | if (!(paddr = virt_to_phys_040(addr))) | ||
180 | continue; | ||
181 | switch (cache) | ||
182 | { | ||
183 | case FLUSH_CACHE_DATA: | ||
184 | __asm__ __volatile__ ("nop\n\t" | ||
185 | ".chip 68040\n\t" | ||
186 | "cpushp %%dc,(%0)\n\t" | ||
187 | ".chip 68k" | ||
188 | : : "a" (paddr)); | ||
189 | break; | ||
190 | case FLUSH_CACHE_INSN: | ||
191 | __asm__ __volatile__ ("nop\n\t" | ||
192 | ".chip 68040\n\t" | ||
193 | "cpushp %%ic,(%0)\n\t" | ||
194 | ".chip 68k" | ||
195 | : : "a" (paddr)); | ||
196 | break; | ||
197 | default: | ||
198 | case FLUSH_CACHE_BOTH: | ||
199 | __asm__ __volatile__ ("nop\n\t" | ||
200 | ".chip 68040\n\t" | ||
201 | "cpushp %%bc,(%0)\n\t" | ||
202 | ".chip 68k" | ||
203 | : : "a" (paddr)); | ||
204 | break; | ||
205 | } | ||
206 | } | ||
207 | break; | ||
208 | } | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | #define virt_to_phys_060(vaddr) \ | ||
213 | ({ \ | ||
214 | unsigned long paddr; \ | ||
215 | __asm__ __volatile__ (".chip 68060\n\t" \ | ||
216 | "plpar (%0)\n\t" \ | ||
217 | ".chip 68k" \ | ||
218 | : "=a" (paddr) \ | ||
219 | : "0" (vaddr)); \ | ||
220 | (paddr); /* XXX */ \ | ||
221 | }) | ||
222 | |||
223 | static inline int | ||
224 | cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len) | ||
225 | { | ||
226 | unsigned long paddr, i; | ||
227 | |||
228 | /* | ||
229 | * 68060 manual says: | ||
230 | * cpush %dc : flush DC, remains valid (with our %cacr setup) | ||
231 | * cpush %ic : invalidate IC | ||
232 | * cpush %bc : flush DC + invalidate IC | ||
233 | */ | ||
234 | switch (scope) | ||
235 | { | ||
236 | case FLUSH_SCOPE_ALL: | ||
237 | switch (cache) | ||
238 | { | ||
239 | case FLUSH_CACHE_DATA: | ||
240 | __asm__ __volatile__ (".chip 68060\n\t" | ||
241 | "cpusha %dc\n\t" | ||
242 | ".chip 68k"); | ||
243 | break; | ||
244 | case FLUSH_CACHE_INSN: | ||
245 | __asm__ __volatile__ (".chip 68060\n\t" | ||
246 | "cpusha %ic\n\t" | ||
247 | ".chip 68k"); | ||
248 | break; | ||
249 | default: | ||
250 | case FLUSH_CACHE_BOTH: | ||
251 | __asm__ __volatile__ (".chip 68060\n\t" | ||
252 | "cpusha %bc\n\t" | ||
253 | ".chip 68k"); | ||
254 | break; | ||
255 | } | ||
256 | break; | ||
257 | |||
258 | case FLUSH_SCOPE_LINE: | ||
259 | /* Find the physical address of the first mapped page in the | ||
260 | address range. */ | ||
261 | len += addr & 15; | ||
262 | addr &= -16; | ||
263 | if (!(paddr = virt_to_phys_060(addr))) { | ||
264 | unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK); | ||
265 | |||
266 | if (len <= tmp) | ||
267 | return 0; | ||
268 | addr += tmp; | ||
269 | len -= tmp; | ||
270 | tmp = PAGE_SIZE; | ||
271 | for (;;) | ||
272 | { | ||
273 | if ((paddr = virt_to_phys_060(addr))) | ||
274 | break; | ||
275 | if (len <= tmp) | ||
276 | return 0; | ||
277 | addr += tmp; | ||
278 | len -= tmp; | ||
279 | } | ||
280 | } | ||
281 | len = (len + 15) >> 4; | ||
282 | i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4; | ||
283 | while (len--) | ||
284 | { | ||
285 | switch (cache) | ||
286 | { | ||
287 | case FLUSH_CACHE_DATA: | ||
288 | __asm__ __volatile__ (".chip 68060\n\t" | ||
289 | "cpushl %%dc,(%0)\n\t" | ||
290 | ".chip 68k" | ||
291 | : : "a" (paddr)); | ||
292 | break; | ||
293 | case FLUSH_CACHE_INSN: | ||
294 | __asm__ __volatile__ (".chip 68060\n\t" | ||
295 | "cpushl %%ic,(%0)\n\t" | ||
296 | ".chip 68k" | ||
297 | : : "a" (paddr)); | ||
298 | break; | ||
299 | default: | ||
300 | case FLUSH_CACHE_BOTH: | ||
301 | __asm__ __volatile__ (".chip 68060\n\t" | ||
302 | "cpushl %%bc,(%0)\n\t" | ||
303 | ".chip 68k" | ||
304 | : : "a" (paddr)); | ||
305 | break; | ||
306 | } | ||
307 | if (!--i && len) | ||
308 | { | ||
309 | |||
310 | /* | ||
311 | * We just want to jump to the first cache line | ||
312 | * in the next page. | ||
313 | */ | ||
314 | addr += PAGE_SIZE; | ||
315 | addr &= PAGE_MASK; | ||
316 | |||
317 | i = PAGE_SIZE / 16; | ||
318 | /* Recompute physical address when crossing a page | ||
319 | boundary. */ | ||
320 | for (;;) | ||
321 | { | ||
322 | if ((paddr = virt_to_phys_060(addr))) | ||
323 | break; | ||
324 | if (len <= i) | ||
325 | return 0; | ||
326 | len -= i; | ||
327 | addr += PAGE_SIZE; | ||
328 | } | ||
329 | } | ||
330 | else | ||
331 | paddr += 16; | ||
332 | } | ||
333 | break; | ||
334 | |||
335 | default: | ||
336 | case FLUSH_SCOPE_PAGE: | ||
337 | len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1); | ||
338 | addr &= PAGE_MASK; /* Workaround for bug in some | ||
339 | revisions of the 68060 */ | ||
340 | for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE) | ||
341 | { | ||
342 | if (!(paddr = virt_to_phys_060(addr))) | ||
343 | continue; | ||
344 | switch (cache) | ||
345 | { | ||
346 | case FLUSH_CACHE_DATA: | ||
347 | __asm__ __volatile__ (".chip 68060\n\t" | ||
348 | "cpushp %%dc,(%0)\n\t" | ||
349 | ".chip 68k" | ||
350 | : : "a" (paddr)); | ||
351 | break; | ||
352 | case FLUSH_CACHE_INSN: | ||
353 | __asm__ __volatile__ (".chip 68060\n\t" | ||
354 | "cpushp %%ic,(%0)\n\t" | ||
355 | ".chip 68k" | ||
356 | : : "a" (paddr)); | ||
357 | break; | ||
358 | default: | ||
359 | case FLUSH_CACHE_BOTH: | ||
360 | __asm__ __volatile__ (".chip 68060\n\t" | ||
361 | "cpushp %%bc,(%0)\n\t" | ||
362 | ".chip 68k" | ||
363 | : : "a" (paddr)); | ||
364 | break; | ||
365 | } | ||
366 | } | ||
367 | break; | ||
368 | } | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | /* sys_cacheflush -- flush (part of) the processor cache. */ | ||
373 | asmlinkage int | ||
374 | sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len) | ||
375 | { | ||
376 | struct vm_area_struct *vma; | ||
377 | int ret = -EINVAL; | ||
378 | |||
379 | if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL || | ||
380 | cache & ~FLUSH_CACHE_BOTH) | ||
381 | goto out; | ||
382 | |||
383 | if (scope == FLUSH_SCOPE_ALL) { | ||
384 | /* Only the superuser may explicitly flush the whole cache. */ | ||
385 | ret = -EPERM; | ||
386 | if (!capable(CAP_SYS_ADMIN)) | ||
387 | goto out; | ||
388 | } else { | ||
389 | /* | ||
390 | * Verify that the specified address region actually belongs | ||
391 | * to this process. | ||
392 | */ | ||
393 | vma = find_vma (current->mm, addr); | ||
394 | ret = -EINVAL; | ||
395 | /* Check for overflow. */ | ||
396 | if (addr + len < addr) | ||
397 | goto out; | ||
398 | if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end) | ||
399 | goto out; | ||
400 | } | ||
401 | |||
402 | if (CPU_IS_020_OR_030) { | ||
403 | if (scope == FLUSH_SCOPE_LINE && len < 256) { | ||
404 | unsigned long cacr; | ||
405 | __asm__ ("movec %%cacr, %0" : "=r" (cacr)); | ||
406 | if (cache & FLUSH_CACHE_INSN) | ||
407 | cacr |= 4; | ||
408 | if (cache & FLUSH_CACHE_DATA) | ||
409 | cacr |= 0x400; | ||
410 | len >>= 2; | ||
411 | while (len--) { | ||
412 | __asm__ __volatile__ ("movec %1, %%caar\n\t" | ||
413 | "movec %0, %%cacr" | ||
414 | : /* no outputs */ | ||
415 | : "r" (cacr), "r" (addr)); | ||
416 | addr += 4; | ||
417 | } | ||
418 | } else { | ||
419 | /* Flush the whole cache, even if page granularity requested. */ | ||
420 | unsigned long cacr; | ||
421 | __asm__ ("movec %%cacr, %0" : "=r" (cacr)); | ||
422 | if (cache & FLUSH_CACHE_INSN) | ||
423 | cacr |= 8; | ||
424 | if (cache & FLUSH_CACHE_DATA) | ||
425 | cacr |= 0x800; | ||
426 | __asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr)); | ||
427 | } | ||
428 | ret = 0; | ||
429 | goto out; | ||
430 | } else { | ||
431 | /* | ||
432 | * 040 or 060: don't blindly trust 'scope', someone could | ||
433 | * try to flush a few megs of memory. | ||
434 | */ | ||
435 | |||
436 | if (len>=3*PAGE_SIZE && scope<FLUSH_SCOPE_PAGE) | ||
437 | scope=FLUSH_SCOPE_PAGE; | ||
438 | if (len>=10*PAGE_SIZE && scope<FLUSH_SCOPE_ALL) | ||
439 | scope=FLUSH_SCOPE_ALL; | ||
440 | if (CPU_IS_040) { | ||
441 | ret = cache_flush_040 (addr, scope, cache, len); | ||
442 | } else if (CPU_IS_060) { | ||
443 | ret = cache_flush_060 (addr, scope, cache, len); | ||
444 | } | ||
445 | } | ||
446 | out: | ||
447 | return ret; | ||
448 | } | ||
449 | |||
450 | asmlinkage int sys_getpagesize(void) | ||
451 | { | ||
452 | return PAGE_SIZE; | ||
453 | } | ||
454 | |||
455 | /* | ||
456 | * Do a system call from kernel instead of calling sys_execve so we | ||
457 | * end up with proper pt_regs. | ||
458 | */ | ||
459 | int kernel_execve(const char *filename, | ||
460 | const char *const argv[], | ||
461 | const char *const envp[]) | ||
462 | { | ||
463 | register long __res asm ("%d0") = __NR_execve; | ||
464 | register long __a asm ("%d1") = (long)(filename); | ||
465 | register long __b asm ("%d2") = (long)(argv); | ||
466 | register long __c asm ("%d3") = (long)(envp); | ||
467 | asm volatile ("trap #0" : "+d" (__res) | ||
468 | : "d" (__a), "d" (__b), "d" (__c)); | ||
469 | return __res; | ||
470 | } | ||
471 | |||
472 | asmlinkage unsigned long sys_get_thread_area(void) | ||
473 | { | ||
474 | return current_thread_info()->tp_value; | ||
475 | } | ||
476 | |||
477 | asmlinkage int sys_set_thread_area(unsigned long tp) | ||
478 | { | ||
479 | current_thread_info()->tp_value = tp; | ||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | /* This syscall gets its arguments in A0 (mem), D2 (oldval) and | ||
484 | D1 (newval). */ | ||
485 | asmlinkage int | ||
486 | sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5, | ||
487 | unsigned long __user * mem) | ||
488 | { | ||
489 | /* This was borrowed from ARM's implementation. */ | ||
490 | for (;;) { | ||
491 | struct mm_struct *mm = current->mm; | ||
492 | pgd_t *pgd; | ||
493 | pmd_t *pmd; | ||
494 | pte_t *pte; | ||
495 | spinlock_t *ptl; | ||
496 | unsigned long mem_value; | ||
497 | |||
498 | down_read(&mm->mmap_sem); | ||
499 | pgd = pgd_offset(mm, (unsigned long)mem); | ||
500 | if (!pgd_present(*pgd)) | ||
501 | goto bad_access; | ||
502 | pmd = pmd_offset(pgd, (unsigned long)mem); | ||
503 | if (!pmd_present(*pmd)) | ||
504 | goto bad_access; | ||
505 | pte = pte_offset_map_lock(mm, pmd, (unsigned long)mem, &ptl); | ||
506 | if (!pte_present(*pte) || !pte_dirty(*pte) | ||
507 | || !pte_write(*pte)) { | ||
508 | pte_unmap_unlock(pte, ptl); | ||
509 | goto bad_access; | ||
510 | } | ||
511 | |||
512 | mem_value = *mem; | ||
513 | if (mem_value == oldval) | ||
514 | *mem = newval; | ||
515 | |||
516 | pte_unmap_unlock(pte, ptl); | ||
517 | up_read(&mm->mmap_sem); | ||
518 | return mem_value; | ||
519 | |||
520 | bad_access: | ||
521 | up_read(&mm->mmap_sem); | ||
522 | /* This is not necessarily a bad access, we can get here if | ||
523 | a memory we're trying to write to should be copied-on-write. | ||
524 | Make the kernel do the necessary page stuff, then re-iterate. | ||
525 | Simulate a write access fault to do that. */ | ||
526 | { | ||
527 | /* The first argument of the function corresponds to | ||
528 | D1, which is the first field of struct pt_regs. */ | ||
529 | struct pt_regs *fp = (struct pt_regs *)&newval; | ||
530 | |||
531 | /* '3' is an RMW flag. */ | ||
532 | if (do_page_fault(fp, (unsigned long)mem, 3)) | ||
533 | /* If the do_page_fault() failed, we don't | ||
534 | have anything meaningful to return. | ||
535 | There should be a SIGSEGV pending for | ||
536 | the process. */ | ||
537 | return 0xdeadbeef; | ||
538 | } | ||
539 | } | ||
540 | } | ||
541 | |||
542 | asmlinkage int sys_atomic_barrier(void) | ||
543 | { | ||
544 | /* no code needed for uniprocs */ | ||
545 | return 0; | ||
546 | } | ||
diff --git a/arch/m68k/kernel/sys_m68k_mm.c b/arch/m68k/kernel/sys_m68k_mm.c new file mode 100644 index 000000000000..3db2e7f902aa --- /dev/null +++ b/arch/m68k/kernel/sys_m68k_mm.c | |||
@@ -0,0 +1,546 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/kernel/sys_m68k.c | ||
3 | * | ||
4 | * This file contains various random system calls that | ||
5 | * have a non-standard calling sequence on the Linux/m68k | ||
6 | * platform. | ||
7 | */ | ||
8 | |||
9 | #include <linux/capability.h> | ||
10 | #include <linux/errno.h> | ||
11 | #include <linux/sched.h> | ||
12 | #include <linux/mm.h> | ||
13 | #include <linux/fs.h> | ||
14 | #include <linux/smp.h> | ||
15 | #include <linux/sem.h> | ||
16 | #include <linux/msg.h> | ||
17 | #include <linux/shm.h> | ||
18 | #include <linux/stat.h> | ||
19 | #include <linux/syscalls.h> | ||
20 | #include <linux/mman.h> | ||
21 | #include <linux/file.h> | ||
22 | #include <linux/ipc.h> | ||
23 | |||
24 | #include <asm/setup.h> | ||
25 | #include <asm/uaccess.h> | ||
26 | #include <asm/cachectl.h> | ||
27 | #include <asm/traps.h> | ||
28 | #include <asm/page.h> | ||
29 | #include <asm/unistd.h> | ||
30 | #include <linux/elf.h> | ||
31 | #include <asm/tlb.h> | ||
32 | |||
33 | asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, | ||
34 | unsigned long error_code); | ||
35 | |||
36 | asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, | ||
37 | unsigned long prot, unsigned long flags, | ||
38 | unsigned long fd, unsigned long pgoff) | ||
39 | { | ||
40 | /* | ||
41 | * This is wrong for sun3 - there PAGE_SIZE is 8Kb, | ||
42 | * so we need to shift the argument down by 1; m68k mmap64(3) | ||
43 | * (in libc) expects the last argument of mmap2 in 4Kb units. | ||
44 | */ | ||
45 | return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); | ||
46 | } | ||
47 | |||
48 | /* Convert virtual (user) address VADDR to physical address PADDR */ | ||
49 | #define virt_to_phys_040(vaddr) \ | ||
50 | ({ \ | ||
51 | unsigned long _mmusr, _paddr; \ | ||
52 | \ | ||
53 | __asm__ __volatile__ (".chip 68040\n\t" \ | ||
54 | "ptestr (%1)\n\t" \ | ||
55 | "movec %%mmusr,%0\n\t" \ | ||
56 | ".chip 68k" \ | ||
57 | : "=r" (_mmusr) \ | ||
58 | : "a" (vaddr)); \ | ||
59 | _paddr = (_mmusr & MMU_R_040) ? (_mmusr & PAGE_MASK) : 0; \ | ||
60 | _paddr; \ | ||
61 | }) | ||
62 | |||
63 | static inline int | ||
64 | cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len) | ||
65 | { | ||
66 | unsigned long paddr, i; | ||
67 | |||
68 | switch (scope) | ||
69 | { | ||
70 | case FLUSH_SCOPE_ALL: | ||
71 | switch (cache) | ||
72 | { | ||
73 | case FLUSH_CACHE_DATA: | ||
74 | /* This nop is needed for some broken versions of the 68040. */ | ||
75 | __asm__ __volatile__ ("nop\n\t" | ||
76 | ".chip 68040\n\t" | ||
77 | "cpusha %dc\n\t" | ||
78 | ".chip 68k"); | ||
79 | break; | ||
80 | case FLUSH_CACHE_INSN: | ||
81 | __asm__ __volatile__ ("nop\n\t" | ||
82 | ".chip 68040\n\t" | ||
83 | "cpusha %ic\n\t" | ||
84 | ".chip 68k"); | ||
85 | break; | ||
86 | default: | ||
87 | case FLUSH_CACHE_BOTH: | ||
88 | __asm__ __volatile__ ("nop\n\t" | ||
89 | ".chip 68040\n\t" | ||
90 | "cpusha %bc\n\t" | ||
91 | ".chip 68k"); | ||
92 | break; | ||
93 | } | ||
94 | break; | ||
95 | |||
96 | case FLUSH_SCOPE_LINE: | ||
97 | /* Find the physical address of the first mapped page in the | ||
98 | address range. */ | ||
99 | if ((paddr = virt_to_phys_040(addr))) { | ||
100 | paddr += addr & ~(PAGE_MASK | 15); | ||
101 | len = (len + (addr & 15) + 15) >> 4; | ||
102 | } else { | ||
103 | unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK); | ||
104 | |||
105 | if (len <= tmp) | ||
106 | return 0; | ||
107 | addr += tmp; | ||
108 | len -= tmp; | ||
109 | tmp = PAGE_SIZE; | ||
110 | for (;;) | ||
111 | { | ||
112 | if ((paddr = virt_to_phys_040(addr))) | ||
113 | break; | ||
114 | if (len <= tmp) | ||
115 | return 0; | ||
116 | addr += tmp; | ||
117 | len -= tmp; | ||
118 | } | ||
119 | len = (len + 15) >> 4; | ||
120 | } | ||
121 | i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4; | ||
122 | while (len--) | ||
123 | { | ||
124 | switch (cache) | ||
125 | { | ||
126 | case FLUSH_CACHE_DATA: | ||
127 | __asm__ __volatile__ ("nop\n\t" | ||
128 | ".chip 68040\n\t" | ||
129 | "cpushl %%dc,(%0)\n\t" | ||
130 | ".chip 68k" | ||
131 | : : "a" (paddr)); | ||
132 | break; | ||
133 | case FLUSH_CACHE_INSN: | ||
134 | __asm__ __volatile__ ("nop\n\t" | ||
135 | ".chip 68040\n\t" | ||
136 | "cpushl %%ic,(%0)\n\t" | ||
137 | ".chip 68k" | ||
138 | : : "a" (paddr)); | ||
139 | break; | ||
140 | default: | ||
141 | case FLUSH_CACHE_BOTH: | ||
142 | __asm__ __volatile__ ("nop\n\t" | ||
143 | ".chip 68040\n\t" | ||
144 | "cpushl %%bc,(%0)\n\t" | ||
145 | ".chip 68k" | ||
146 | : : "a" (paddr)); | ||
147 | break; | ||
148 | } | ||
149 | if (!--i && len) | ||
150 | { | ||
151 | /* | ||
152 | * No need to page align here since it is done by | ||
153 | * virt_to_phys_040(). | ||
154 | */ | ||
155 | addr += PAGE_SIZE; | ||
156 | i = PAGE_SIZE / 16; | ||
157 | /* Recompute physical address when crossing a page | ||
158 | boundary. */ | ||
159 | for (;;) | ||
160 | { | ||
161 | if ((paddr = virt_to_phys_040(addr))) | ||
162 | break; | ||
163 | if (len <= i) | ||
164 | return 0; | ||
165 | len -= i; | ||
166 | addr += PAGE_SIZE; | ||
167 | } | ||
168 | } | ||
169 | else | ||
170 | paddr += 16; | ||
171 | } | ||
172 | break; | ||
173 | |||
174 | default: | ||
175 | case FLUSH_SCOPE_PAGE: | ||
176 | len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1); | ||
177 | for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE) | ||
178 | { | ||
179 | if (!(paddr = virt_to_phys_040(addr))) | ||
180 | continue; | ||
181 | switch (cache) | ||
182 | { | ||
183 | case FLUSH_CACHE_DATA: | ||
184 | __asm__ __volatile__ ("nop\n\t" | ||
185 | ".chip 68040\n\t" | ||
186 | "cpushp %%dc,(%0)\n\t" | ||
187 | ".chip 68k" | ||
188 | : : "a" (paddr)); | ||
189 | break; | ||
190 | case FLUSH_CACHE_INSN: | ||
191 | __asm__ __volatile__ ("nop\n\t" | ||
192 | ".chip 68040\n\t" | ||
193 | "cpushp %%ic,(%0)\n\t" | ||
194 | ".chip 68k" | ||
195 | : : "a" (paddr)); | ||
196 | break; | ||
197 | default: | ||
198 | case FLUSH_CACHE_BOTH: | ||
199 | __asm__ __volatile__ ("nop\n\t" | ||
200 | ".chip 68040\n\t" | ||
201 | "cpushp %%bc,(%0)\n\t" | ||
202 | ".chip 68k" | ||
203 | : : "a" (paddr)); | ||
204 | break; | ||
205 | } | ||
206 | } | ||
207 | break; | ||
208 | } | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | #define virt_to_phys_060(vaddr) \ | ||
213 | ({ \ | ||
214 | unsigned long paddr; \ | ||
215 | __asm__ __volatile__ (".chip 68060\n\t" \ | ||
216 | "plpar (%0)\n\t" \ | ||
217 | ".chip 68k" \ | ||
218 | : "=a" (paddr) \ | ||
219 | : "0" (vaddr)); \ | ||
220 | (paddr); /* XXX */ \ | ||
221 | }) | ||
222 | |||
223 | static inline int | ||
224 | cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len) | ||
225 | { | ||
226 | unsigned long paddr, i; | ||
227 | |||
228 | /* | ||
229 | * 68060 manual says: | ||
230 | * cpush %dc : flush DC, remains valid (with our %cacr setup) | ||
231 | * cpush %ic : invalidate IC | ||
232 | * cpush %bc : flush DC + invalidate IC | ||
233 | */ | ||
234 | switch (scope) | ||
235 | { | ||
236 | case FLUSH_SCOPE_ALL: | ||
237 | switch (cache) | ||
238 | { | ||
239 | case FLUSH_CACHE_DATA: | ||
240 | __asm__ __volatile__ (".chip 68060\n\t" | ||
241 | "cpusha %dc\n\t" | ||
242 | ".chip 68k"); | ||
243 | break; | ||
244 | case FLUSH_CACHE_INSN: | ||
245 | __asm__ __volatile__ (".chip 68060\n\t" | ||
246 | "cpusha %ic\n\t" | ||
247 | ".chip 68k"); | ||
248 | break; | ||
249 | default: | ||
250 | case FLUSH_CACHE_BOTH: | ||
251 | __asm__ __volatile__ (".chip 68060\n\t" | ||
252 | "cpusha %bc\n\t" | ||
253 | ".chip 68k"); | ||
254 | break; | ||
255 | } | ||
256 | break; | ||
257 | |||
258 | case FLUSH_SCOPE_LINE: | ||
259 | /* Find the physical address of the first mapped page in the | ||
260 | address range. */ | ||
261 | len += addr & 15; | ||
262 | addr &= -16; | ||
263 | if (!(paddr = virt_to_phys_060(addr))) { | ||
264 | unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK); | ||
265 | |||
266 | if (len <= tmp) | ||
267 | return 0; | ||
268 | addr += tmp; | ||
269 | len -= tmp; | ||
270 | tmp = PAGE_SIZE; | ||
271 | for (;;) | ||
272 | { | ||
273 | if ((paddr = virt_to_phys_060(addr))) | ||
274 | break; | ||
275 | if (len <= tmp) | ||
276 | return 0; | ||
277 | addr += tmp; | ||
278 | len -= tmp; | ||
279 | } | ||
280 | } | ||
281 | len = (len + 15) >> 4; | ||
282 | i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4; | ||
283 | while (len--) | ||
284 | { | ||
285 | switch (cache) | ||
286 | { | ||
287 | case FLUSH_CACHE_DATA: | ||
288 | __asm__ __volatile__ (".chip 68060\n\t" | ||
289 | "cpushl %%dc,(%0)\n\t" | ||
290 | ".chip 68k" | ||
291 | : : "a" (paddr)); | ||
292 | break; | ||
293 | case FLUSH_CACHE_INSN: | ||
294 | __asm__ __volatile__ (".chip 68060\n\t" | ||
295 | "cpushl %%ic,(%0)\n\t" | ||
296 | ".chip 68k" | ||
297 | : : "a" (paddr)); | ||
298 | break; | ||
299 | default: | ||
300 | case FLUSH_CACHE_BOTH: | ||
301 | __asm__ __volatile__ (".chip 68060\n\t" | ||
302 | "cpushl %%bc,(%0)\n\t" | ||
303 | ".chip 68k" | ||
304 | : : "a" (paddr)); | ||
305 | break; | ||
306 | } | ||
307 | if (!--i && len) | ||
308 | { | ||
309 | |||
310 | /* | ||
311 | * We just want to jump to the first cache line | ||
312 | * in the next page. | ||
313 | */ | ||
314 | addr += PAGE_SIZE; | ||
315 | addr &= PAGE_MASK; | ||
316 | |||
317 | i = PAGE_SIZE / 16; | ||
318 | /* Recompute physical address when crossing a page | ||
319 | boundary. */ | ||
320 | for (;;) | ||
321 | { | ||
322 | if ((paddr = virt_to_phys_060(addr))) | ||
323 | break; | ||
324 | if (len <= i) | ||
325 | return 0; | ||
326 | len -= i; | ||
327 | addr += PAGE_SIZE; | ||
328 | } | ||
329 | } | ||
330 | else | ||
331 | paddr += 16; | ||
332 | } | ||
333 | break; | ||
334 | |||
335 | default: | ||
336 | case FLUSH_SCOPE_PAGE: | ||
337 | len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1); | ||
338 | addr &= PAGE_MASK; /* Workaround for bug in some | ||
339 | revisions of the 68060 */ | ||
340 | for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE) | ||
341 | { | ||
342 | if (!(paddr = virt_to_phys_060(addr))) | ||
343 | continue; | ||
344 | switch (cache) | ||
345 | { | ||
346 | case FLUSH_CACHE_DATA: | ||
347 | __asm__ __volatile__ (".chip 68060\n\t" | ||
348 | "cpushp %%dc,(%0)\n\t" | ||
349 | ".chip 68k" | ||
350 | : : "a" (paddr)); | ||
351 | break; | ||
352 | case FLUSH_CACHE_INSN: | ||
353 | __asm__ __volatile__ (".chip 68060\n\t" | ||
354 | "cpushp %%ic,(%0)\n\t" | ||
355 | ".chip 68k" | ||
356 | : : "a" (paddr)); | ||
357 | break; | ||
358 | default: | ||
359 | case FLUSH_CACHE_BOTH: | ||
360 | __asm__ __volatile__ (".chip 68060\n\t" | ||
361 | "cpushp %%bc,(%0)\n\t" | ||
362 | ".chip 68k" | ||
363 | : : "a" (paddr)); | ||
364 | break; | ||
365 | } | ||
366 | } | ||
367 | break; | ||
368 | } | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | /* sys_cacheflush -- flush (part of) the processor cache. */ | ||
373 | asmlinkage int | ||
374 | sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len) | ||
375 | { | ||
376 | struct vm_area_struct *vma; | ||
377 | int ret = -EINVAL; | ||
378 | |||
379 | if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL || | ||
380 | cache & ~FLUSH_CACHE_BOTH) | ||
381 | goto out; | ||
382 | |||
383 | if (scope == FLUSH_SCOPE_ALL) { | ||
384 | /* Only the superuser may explicitly flush the whole cache. */ | ||
385 | ret = -EPERM; | ||
386 | if (!capable(CAP_SYS_ADMIN)) | ||
387 | goto out; | ||
388 | } else { | ||
389 | /* | ||
390 | * Verify that the specified address region actually belongs | ||
391 | * to this process. | ||
392 | */ | ||
393 | vma = find_vma (current->mm, addr); | ||
394 | ret = -EINVAL; | ||
395 | /* Check for overflow. */ | ||
396 | if (addr + len < addr) | ||
397 | goto out; | ||
398 | if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end) | ||
399 | goto out; | ||
400 | } | ||
401 | |||
402 | if (CPU_IS_020_OR_030) { | ||
403 | if (scope == FLUSH_SCOPE_LINE && len < 256) { | ||
404 | unsigned long cacr; | ||
405 | __asm__ ("movec %%cacr, %0" : "=r" (cacr)); | ||
406 | if (cache & FLUSH_CACHE_INSN) | ||
407 | cacr |= 4; | ||
408 | if (cache & FLUSH_CACHE_DATA) | ||
409 | cacr |= 0x400; | ||
410 | len >>= 2; | ||
411 | while (len--) { | ||
412 | __asm__ __volatile__ ("movec %1, %%caar\n\t" | ||
413 | "movec %0, %%cacr" | ||
414 | : /* no outputs */ | ||
415 | : "r" (cacr), "r" (addr)); | ||
416 | addr += 4; | ||
417 | } | ||
418 | } else { | ||
419 | /* Flush the whole cache, even if page granularity requested. */ | ||
420 | unsigned long cacr; | ||
421 | __asm__ ("movec %%cacr, %0" : "=r" (cacr)); | ||
422 | if (cache & FLUSH_CACHE_INSN) | ||
423 | cacr |= 8; | ||
424 | if (cache & FLUSH_CACHE_DATA) | ||
425 | cacr |= 0x800; | ||
426 | __asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr)); | ||
427 | } | ||
428 | ret = 0; | ||
429 | goto out; | ||
430 | } else { | ||
431 | /* | ||
432 | * 040 or 060: don't blindly trust 'scope', someone could | ||
433 | * try to flush a few megs of memory. | ||
434 | */ | ||
435 | |||
436 | if (len>=3*PAGE_SIZE && scope<FLUSH_SCOPE_PAGE) | ||
437 | scope=FLUSH_SCOPE_PAGE; | ||
438 | if (len>=10*PAGE_SIZE && scope<FLUSH_SCOPE_ALL) | ||
439 | scope=FLUSH_SCOPE_ALL; | ||
440 | if (CPU_IS_040) { | ||
441 | ret = cache_flush_040 (addr, scope, cache, len); | ||
442 | } else if (CPU_IS_060) { | ||
443 | ret = cache_flush_060 (addr, scope, cache, len); | ||
444 | } | ||
445 | } | ||
446 | out: | ||
447 | return ret; | ||
448 | } | ||
449 | |||
450 | asmlinkage int sys_getpagesize(void) | ||
451 | { | ||
452 | return PAGE_SIZE; | ||
453 | } | ||
454 | |||
455 | /* | ||
456 | * Do a system call from kernel instead of calling sys_execve so we | ||
457 | * end up with proper pt_regs. | ||
458 | */ | ||
459 | int kernel_execve(const char *filename, | ||
460 | const char *const argv[], | ||
461 | const char *const envp[]) | ||
462 | { | ||
463 | register long __res asm ("%d0") = __NR_execve; | ||
464 | register long __a asm ("%d1") = (long)(filename); | ||
465 | register long __b asm ("%d2") = (long)(argv); | ||
466 | register long __c asm ("%d3") = (long)(envp); | ||
467 | asm volatile ("trap #0" : "+d" (__res) | ||
468 | : "d" (__a), "d" (__b), "d" (__c)); | ||
469 | return __res; | ||
470 | } | ||
471 | |||
472 | asmlinkage unsigned long sys_get_thread_area(void) | ||
473 | { | ||
474 | return current_thread_info()->tp_value; | ||
475 | } | ||
476 | |||
477 | asmlinkage int sys_set_thread_area(unsigned long tp) | ||
478 | { | ||
479 | current_thread_info()->tp_value = tp; | ||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | /* This syscall gets its arguments in A0 (mem), D2 (oldval) and | ||
484 | D1 (newval). */ | ||
485 | asmlinkage int | ||
486 | sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5, | ||
487 | unsigned long __user * mem) | ||
488 | { | ||
489 | /* This was borrowed from ARM's implementation. */ | ||
490 | for (;;) { | ||
491 | struct mm_struct *mm = current->mm; | ||
492 | pgd_t *pgd; | ||
493 | pmd_t *pmd; | ||
494 | pte_t *pte; | ||
495 | spinlock_t *ptl; | ||
496 | unsigned long mem_value; | ||
497 | |||
498 | down_read(&mm->mmap_sem); | ||
499 | pgd = pgd_offset(mm, (unsigned long)mem); | ||
500 | if (!pgd_present(*pgd)) | ||
501 | goto bad_access; | ||
502 | pmd = pmd_offset(pgd, (unsigned long)mem); | ||
503 | if (!pmd_present(*pmd)) | ||
504 | goto bad_access; | ||
505 | pte = pte_offset_map_lock(mm, pmd, (unsigned long)mem, &ptl); | ||
506 | if (!pte_present(*pte) || !pte_dirty(*pte) | ||
507 | || !pte_write(*pte)) { | ||
508 | pte_unmap_unlock(pte, ptl); | ||
509 | goto bad_access; | ||
510 | } | ||
511 | |||
512 | mem_value = *mem; | ||
513 | if (mem_value == oldval) | ||
514 | *mem = newval; | ||
515 | |||
516 | pte_unmap_unlock(pte, ptl); | ||
517 | up_read(&mm->mmap_sem); | ||
518 | return mem_value; | ||
519 | |||
520 | bad_access: | ||
521 | up_read(&mm->mmap_sem); | ||
522 | /* This is not necessarily a bad access, we can get here if | ||
523 | a memory we're trying to write to should be copied-on-write. | ||
524 | Make the kernel do the necessary page stuff, then re-iterate. | ||
525 | Simulate a write access fault to do that. */ | ||
526 | { | ||
527 | /* The first argument of the function corresponds to | ||
528 | D1, which is the first field of struct pt_regs. */ | ||
529 | struct pt_regs *fp = (struct pt_regs *)&newval; | ||
530 | |||
531 | /* '3' is an RMW flag. */ | ||
532 | if (do_page_fault(fp, (unsigned long)mem, 3)) | ||
533 | /* If the do_page_fault() failed, we don't | ||
534 | have anything meaningful to return. | ||
535 | There should be a SIGSEGV pending for | ||
536 | the process. */ | ||
537 | return 0xdeadbeef; | ||
538 | } | ||
539 | } | ||
540 | } | ||
541 | |||
542 | asmlinkage int sys_atomic_barrier(void) | ||
543 | { | ||
544 | /* no code needed for uniprocs */ | ||
545 | return 0; | ||
546 | } | ||
diff --git a/arch/m68knommu/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k_no.c index 68488ae47f0a..68488ae47f0a 100644 --- a/arch/m68knommu/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k_no.c | |||
diff --git a/arch/m68knommu/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S index 79b1ed198c07..79b1ed198c07 100644 --- a/arch/m68knommu/kernel/syscalltable.S +++ b/arch/m68k/kernel/syscalltable.S | |||
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c index 18b34ee5db3b..a5cf40c26de5 100644 --- a/arch/m68k/kernel/time.c +++ b/arch/m68k/kernel/time.c | |||
@@ -1,114 +1,5 @@ | |||
1 | /* | 1 | #ifdef CONFIG_MMU |
2 | * linux/arch/m68k/kernel/time.c | 2 | #include "time_mm.c" |
3 | * | 3 | #else |
4 | * Copyright (C) 1991, 1992, 1995 Linus Torvalds | 4 | #include "time_no.c" |
5 | * | 5 | #endif |
6 | * This file contains the m68k-specific time handling details. | ||
7 | * Most of the stuff is located in the machine specific files. | ||
8 | * | ||
9 | * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 | ||
10 | * "A Kernel Model for Precision Timekeeping" by Dave Mills | ||
11 | */ | ||
12 | |||
13 | #include <linux/errno.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/param.h> | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/mm.h> | ||
20 | #include <linux/rtc.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | |||
23 | #include <asm/machdep.h> | ||
24 | #include <asm/io.h> | ||
25 | #include <asm/irq_regs.h> | ||
26 | |||
27 | #include <linux/time.h> | ||
28 | #include <linux/timex.h> | ||
29 | #include <linux/profile.h> | ||
30 | |||
31 | static inline int set_rtc_mmss(unsigned long nowtime) | ||
32 | { | ||
33 | if (mach_set_clock_mmss) | ||
34 | return mach_set_clock_mmss (nowtime); | ||
35 | return -1; | ||
36 | } | ||
37 | |||
38 | /* | ||
39 | * timer_interrupt() needs to keep up the real-time clock, | ||
40 | * as well as call the "xtime_update()" routine every clocktick | ||
41 | */ | ||
42 | static irqreturn_t timer_interrupt(int irq, void *dummy) | ||
43 | { | ||
44 | xtime_update(1); | ||
45 | update_process_times(user_mode(get_irq_regs())); | ||
46 | profile_tick(CPU_PROFILING); | ||
47 | |||
48 | #ifdef CONFIG_HEARTBEAT | ||
49 | /* use power LED as a heartbeat instead -- much more useful | ||
50 | for debugging -- based on the version for PReP by Cort */ | ||
51 | /* acts like an actual heart beat -- ie thump-thump-pause... */ | ||
52 | if (mach_heartbeat) { | ||
53 | static unsigned cnt = 0, period = 0, dist = 0; | ||
54 | |||
55 | if (cnt == 0 || cnt == dist) | ||
56 | mach_heartbeat( 1 ); | ||
57 | else if (cnt == 7 || cnt == dist+7) | ||
58 | mach_heartbeat( 0 ); | ||
59 | |||
60 | if (++cnt > period) { | ||
61 | cnt = 0; | ||
62 | /* The hyperbolic function below modifies the heartbeat period | ||
63 | * length in dependency of the current (5min) load. It goes | ||
64 | * through the points f(0)=126, f(1)=86, f(5)=51, | ||
65 | * f(inf)->30. */ | ||
66 | period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; | ||
67 | dist = period / 4; | ||
68 | } | ||
69 | } | ||
70 | #endif /* CONFIG_HEARTBEAT */ | ||
71 | return IRQ_HANDLED; | ||
72 | } | ||
73 | |||
74 | void read_persistent_clock(struct timespec *ts) | ||
75 | { | ||
76 | struct rtc_time time; | ||
77 | ts->tv_sec = 0; | ||
78 | ts->tv_nsec = 0; | ||
79 | |||
80 | if (mach_hwclk) { | ||
81 | mach_hwclk(0, &time); | ||
82 | |||
83 | if ((time.tm_year += 1900) < 1970) | ||
84 | time.tm_year += 100; | ||
85 | ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday, | ||
86 | time.tm_hour, time.tm_min, time.tm_sec); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | void __init time_init(void) | ||
91 | { | ||
92 | mach_sched_init(timer_interrupt); | ||
93 | } | ||
94 | |||
95 | u32 arch_gettimeoffset(void) | ||
96 | { | ||
97 | return mach_gettimeoffset() * 1000; | ||
98 | } | ||
99 | |||
100 | static int __init rtc_init(void) | ||
101 | { | ||
102 | struct platform_device *pdev; | ||
103 | |||
104 | if (!mach_hwclk) | ||
105 | return -ENODEV; | ||
106 | |||
107 | pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0); | ||
108 | if (IS_ERR(pdev)) | ||
109 | return PTR_ERR(pdev); | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | module_init(rtc_init); | ||
diff --git a/arch/m68k/kernel/time_mm.c b/arch/m68k/kernel/time_mm.c new file mode 100644 index 000000000000..18b34ee5db3b --- /dev/null +++ b/arch/m68k/kernel/time_mm.c | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/kernel/time.c | ||
3 | * | ||
4 | * Copyright (C) 1991, 1992, 1995 Linus Torvalds | ||
5 | * | ||
6 | * This file contains the m68k-specific time handling details. | ||
7 | * Most of the stuff is located in the machine specific files. | ||
8 | * | ||
9 | * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 | ||
10 | * "A Kernel Model for Precision Timekeeping" by Dave Mills | ||
11 | */ | ||
12 | |||
13 | #include <linux/errno.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/param.h> | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/mm.h> | ||
20 | #include <linux/rtc.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | |||
23 | #include <asm/machdep.h> | ||
24 | #include <asm/io.h> | ||
25 | #include <asm/irq_regs.h> | ||
26 | |||
27 | #include <linux/time.h> | ||
28 | #include <linux/timex.h> | ||
29 | #include <linux/profile.h> | ||
30 | |||
31 | static inline int set_rtc_mmss(unsigned long nowtime) | ||
32 | { | ||
33 | if (mach_set_clock_mmss) | ||
34 | return mach_set_clock_mmss (nowtime); | ||
35 | return -1; | ||
36 | } | ||
37 | |||
38 | /* | ||
39 | * timer_interrupt() needs to keep up the real-time clock, | ||
40 | * as well as call the "xtime_update()" routine every clocktick | ||
41 | */ | ||
42 | static irqreturn_t timer_interrupt(int irq, void *dummy) | ||
43 | { | ||
44 | xtime_update(1); | ||
45 | update_process_times(user_mode(get_irq_regs())); | ||
46 | profile_tick(CPU_PROFILING); | ||
47 | |||
48 | #ifdef CONFIG_HEARTBEAT | ||
49 | /* use power LED as a heartbeat instead -- much more useful | ||
50 | for debugging -- based on the version for PReP by Cort */ | ||
51 | /* acts like an actual heart beat -- ie thump-thump-pause... */ | ||
52 | if (mach_heartbeat) { | ||
53 | static unsigned cnt = 0, period = 0, dist = 0; | ||
54 | |||
55 | if (cnt == 0 || cnt == dist) | ||
56 | mach_heartbeat( 1 ); | ||
57 | else if (cnt == 7 || cnt == dist+7) | ||
58 | mach_heartbeat( 0 ); | ||
59 | |||
60 | if (++cnt > period) { | ||
61 | cnt = 0; | ||
62 | /* The hyperbolic function below modifies the heartbeat period | ||
63 | * length in dependency of the current (5min) load. It goes | ||
64 | * through the points f(0)=126, f(1)=86, f(5)=51, | ||
65 | * f(inf)->30. */ | ||
66 | period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; | ||
67 | dist = period / 4; | ||
68 | } | ||
69 | } | ||
70 | #endif /* CONFIG_HEARTBEAT */ | ||
71 | return IRQ_HANDLED; | ||
72 | } | ||
73 | |||
74 | void read_persistent_clock(struct timespec *ts) | ||
75 | { | ||
76 | struct rtc_time time; | ||
77 | ts->tv_sec = 0; | ||
78 | ts->tv_nsec = 0; | ||
79 | |||
80 | if (mach_hwclk) { | ||
81 | mach_hwclk(0, &time); | ||
82 | |||
83 | if ((time.tm_year += 1900) < 1970) | ||
84 | time.tm_year += 100; | ||
85 | ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday, | ||
86 | time.tm_hour, time.tm_min, time.tm_sec); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | void __init time_init(void) | ||
91 | { | ||
92 | mach_sched_init(timer_interrupt); | ||
93 | } | ||
94 | |||
95 | u32 arch_gettimeoffset(void) | ||
96 | { | ||
97 | return mach_gettimeoffset() * 1000; | ||
98 | } | ||
99 | |||
100 | static int __init rtc_init(void) | ||
101 | { | ||
102 | struct platform_device *pdev; | ||
103 | |||
104 | if (!mach_hwclk) | ||
105 | return -ENODEV; | ||
106 | |||
107 | pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0); | ||
108 | if (IS_ERR(pdev)) | ||
109 | return PTR_ERR(pdev); | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | module_init(rtc_init); | ||
diff --git a/arch/m68knommu/kernel/time.c b/arch/m68k/kernel/time_no.c index 6623909f70e6..6623909f70e6 100644 --- a/arch/m68knommu/kernel/time.c +++ b/arch/m68k/kernel/time_no.c | |||
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c index 4022bbc28878..c98add3f5f0f 100644 --- a/arch/m68k/kernel/traps.c +++ b/arch/m68k/kernel/traps.c | |||
@@ -1,1207 +1,5 @@ | |||
1 | /* | 1 | #ifdef CONFIG_MMU |
2 | * linux/arch/m68k/kernel/traps.c | 2 | #include "traps_mm.c" |
3 | * | ||
4 | * Copyright (C) 1993, 1994 by Hamish Macdonald | ||
5 | * | ||
6 | * 68040 fixes by Michael Rausch | ||
7 | * 68040 fixes by Martin Apel | ||
8 | * 68040 fixes and writeback by Richard Zidlicky | ||
9 | * 68060 fixes by Roman Hodek | ||
10 | * 68060 fixes by Jesper Skov | ||
11 | * | ||
12 | * This file is subject to the terms and conditions of the GNU General Public | ||
13 | * License. See the file COPYING in the main directory of this archive | ||
14 | * for more details. | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * Sets up all exception vectors | ||
19 | */ | ||
20 | |||
21 | #include <linux/sched.h> | ||
22 | #include <linux/signal.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/user.h> | ||
27 | #include <linux/string.h> | ||
28 | #include <linux/linkage.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/ptrace.h> | ||
31 | #include <linux/kallsyms.h> | ||
32 | |||
33 | #include <asm/setup.h> | ||
34 | #include <asm/fpu.h> | ||
35 | #include <asm/system.h> | ||
36 | #include <asm/uaccess.h> | ||
37 | #include <asm/traps.h> | ||
38 | #include <asm/pgalloc.h> | ||
39 | #include <asm/machdep.h> | ||
40 | #include <asm/siginfo.h> | ||
41 | |||
42 | /* assembler routines */ | ||
43 | asmlinkage void system_call(void); | ||
44 | asmlinkage void buserr(void); | ||
45 | asmlinkage void trap(void); | ||
46 | asmlinkage void nmihandler(void); | ||
47 | #ifdef CONFIG_M68KFPU_EMU | ||
48 | asmlinkage void fpu_emu(void); | ||
49 | #endif | ||
50 | |||
51 | e_vector vectors[256]; | ||
52 | |||
53 | /* nmi handler for the Amiga */ | ||
54 | asm(".text\n" | ||
55 | __ALIGN_STR "\n" | ||
56 | "nmihandler: rte"); | ||
57 | |||
58 | /* | ||
59 | * this must be called very early as the kernel might | ||
60 | * use some instruction that are emulated on the 060 | ||
61 | * and so we're prepared for early probe attempts (e.g. nf_init). | ||
62 | */ | ||
63 | void __init base_trap_init(void) | ||
64 | { | ||
65 | if (MACH_IS_SUN3X) { | ||
66 | extern e_vector *sun3x_prom_vbr; | ||
67 | |||
68 | __asm__ volatile ("movec %%vbr, %0" : "=r" (sun3x_prom_vbr)); | ||
69 | } | ||
70 | |||
71 | /* setup the exception vector table */ | ||
72 | __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors)); | ||
73 | |||
74 | if (CPU_IS_060) { | ||
75 | /* set up ISP entry points */ | ||
76 | asmlinkage void unimp_vec(void) asm ("_060_isp_unimp"); | ||
77 | |||
78 | vectors[VEC_UNIMPII] = unimp_vec; | ||
79 | } | ||
80 | |||
81 | vectors[VEC_BUSERR] = buserr; | ||
82 | vectors[VEC_ILLEGAL] = trap; | ||
83 | vectors[VEC_SYS] = system_call; | ||
84 | } | ||
85 | |||
86 | void __init trap_init (void) | ||
87 | { | ||
88 | int i; | ||
89 | |||
90 | for (i = VEC_SPUR; i <= VEC_INT7; i++) | ||
91 | vectors[i] = bad_inthandler; | ||
92 | |||
93 | for (i = 0; i < VEC_USER; i++) | ||
94 | if (!vectors[i]) | ||
95 | vectors[i] = trap; | ||
96 | |||
97 | for (i = VEC_USER; i < 256; i++) | ||
98 | vectors[i] = bad_inthandler; | ||
99 | |||
100 | #ifdef CONFIG_M68KFPU_EMU | ||
101 | if (FPU_IS_EMU) | ||
102 | vectors[VEC_LINE11] = fpu_emu; | ||
103 | #endif | ||
104 | |||
105 | if (CPU_IS_040 && !FPU_IS_EMU) { | ||
106 | /* set up FPSP entry points */ | ||
107 | asmlinkage void dz_vec(void) asm ("dz"); | ||
108 | asmlinkage void inex_vec(void) asm ("inex"); | ||
109 | asmlinkage void ovfl_vec(void) asm ("ovfl"); | ||
110 | asmlinkage void unfl_vec(void) asm ("unfl"); | ||
111 | asmlinkage void snan_vec(void) asm ("snan"); | ||
112 | asmlinkage void operr_vec(void) asm ("operr"); | ||
113 | asmlinkage void bsun_vec(void) asm ("bsun"); | ||
114 | asmlinkage void fline_vec(void) asm ("fline"); | ||
115 | asmlinkage void unsupp_vec(void) asm ("unsupp"); | ||
116 | |||
117 | vectors[VEC_FPDIVZ] = dz_vec; | ||
118 | vectors[VEC_FPIR] = inex_vec; | ||
119 | vectors[VEC_FPOVER] = ovfl_vec; | ||
120 | vectors[VEC_FPUNDER] = unfl_vec; | ||
121 | vectors[VEC_FPNAN] = snan_vec; | ||
122 | vectors[VEC_FPOE] = operr_vec; | ||
123 | vectors[VEC_FPBRUC] = bsun_vec; | ||
124 | vectors[VEC_LINE11] = fline_vec; | ||
125 | vectors[VEC_FPUNSUP] = unsupp_vec; | ||
126 | } | ||
127 | |||
128 | if (CPU_IS_060 && !FPU_IS_EMU) { | ||
129 | /* set up IFPSP entry points */ | ||
130 | asmlinkage void snan_vec6(void) asm ("_060_fpsp_snan"); | ||
131 | asmlinkage void operr_vec6(void) asm ("_060_fpsp_operr"); | ||
132 | asmlinkage void ovfl_vec6(void) asm ("_060_fpsp_ovfl"); | ||
133 | asmlinkage void unfl_vec6(void) asm ("_060_fpsp_unfl"); | ||
134 | asmlinkage void dz_vec6(void) asm ("_060_fpsp_dz"); | ||
135 | asmlinkage void inex_vec6(void) asm ("_060_fpsp_inex"); | ||
136 | asmlinkage void fline_vec6(void) asm ("_060_fpsp_fline"); | ||
137 | asmlinkage void unsupp_vec6(void) asm ("_060_fpsp_unsupp"); | ||
138 | asmlinkage void effadd_vec6(void) asm ("_060_fpsp_effadd"); | ||
139 | |||
140 | vectors[VEC_FPNAN] = snan_vec6; | ||
141 | vectors[VEC_FPOE] = operr_vec6; | ||
142 | vectors[VEC_FPOVER] = ovfl_vec6; | ||
143 | vectors[VEC_FPUNDER] = unfl_vec6; | ||
144 | vectors[VEC_FPDIVZ] = dz_vec6; | ||
145 | vectors[VEC_FPIR] = inex_vec6; | ||
146 | vectors[VEC_LINE11] = fline_vec6; | ||
147 | vectors[VEC_FPUNSUP] = unsupp_vec6; | ||
148 | vectors[VEC_UNIMPEA] = effadd_vec6; | ||
149 | } | ||
150 | |||
151 | /* if running on an amiga, make the NMI interrupt do nothing */ | ||
152 | if (MACH_IS_AMIGA) { | ||
153 | vectors[VEC_INT7] = nmihandler; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | |||
158 | static const char *vec_names[] = { | ||
159 | [VEC_RESETSP] = "RESET SP", | ||
160 | [VEC_RESETPC] = "RESET PC", | ||
161 | [VEC_BUSERR] = "BUS ERROR", | ||
162 | [VEC_ADDRERR] = "ADDRESS ERROR", | ||
163 | [VEC_ILLEGAL] = "ILLEGAL INSTRUCTION", | ||
164 | [VEC_ZERODIV] = "ZERO DIVIDE", | ||
165 | [VEC_CHK] = "CHK", | ||
166 | [VEC_TRAP] = "TRAPcc", | ||
167 | [VEC_PRIV] = "PRIVILEGE VIOLATION", | ||
168 | [VEC_TRACE] = "TRACE", | ||
169 | [VEC_LINE10] = "LINE 1010", | ||
170 | [VEC_LINE11] = "LINE 1111", | ||
171 | [VEC_RESV12] = "UNASSIGNED RESERVED 12", | ||
172 | [VEC_COPROC] = "COPROCESSOR PROTOCOL VIOLATION", | ||
173 | [VEC_FORMAT] = "FORMAT ERROR", | ||
174 | [VEC_UNINT] = "UNINITIALIZED INTERRUPT", | ||
175 | [VEC_RESV16] = "UNASSIGNED RESERVED 16", | ||
176 | [VEC_RESV17] = "UNASSIGNED RESERVED 17", | ||
177 | [VEC_RESV18] = "UNASSIGNED RESERVED 18", | ||
178 | [VEC_RESV19] = "UNASSIGNED RESERVED 19", | ||
179 | [VEC_RESV20] = "UNASSIGNED RESERVED 20", | ||
180 | [VEC_RESV21] = "UNASSIGNED RESERVED 21", | ||
181 | [VEC_RESV22] = "UNASSIGNED RESERVED 22", | ||
182 | [VEC_RESV23] = "UNASSIGNED RESERVED 23", | ||
183 | [VEC_SPUR] = "SPURIOUS INTERRUPT", | ||
184 | [VEC_INT1] = "LEVEL 1 INT", | ||
185 | [VEC_INT2] = "LEVEL 2 INT", | ||
186 | [VEC_INT3] = "LEVEL 3 INT", | ||
187 | [VEC_INT4] = "LEVEL 4 INT", | ||
188 | [VEC_INT5] = "LEVEL 5 INT", | ||
189 | [VEC_INT6] = "LEVEL 6 INT", | ||
190 | [VEC_INT7] = "LEVEL 7 INT", | ||
191 | [VEC_SYS] = "SYSCALL", | ||
192 | [VEC_TRAP1] = "TRAP #1", | ||
193 | [VEC_TRAP2] = "TRAP #2", | ||
194 | [VEC_TRAP3] = "TRAP #3", | ||
195 | [VEC_TRAP4] = "TRAP #4", | ||
196 | [VEC_TRAP5] = "TRAP #5", | ||
197 | [VEC_TRAP6] = "TRAP #6", | ||
198 | [VEC_TRAP7] = "TRAP #7", | ||
199 | [VEC_TRAP8] = "TRAP #8", | ||
200 | [VEC_TRAP9] = "TRAP #9", | ||
201 | [VEC_TRAP10] = "TRAP #10", | ||
202 | [VEC_TRAP11] = "TRAP #11", | ||
203 | [VEC_TRAP12] = "TRAP #12", | ||
204 | [VEC_TRAP13] = "TRAP #13", | ||
205 | [VEC_TRAP14] = "TRAP #14", | ||
206 | [VEC_TRAP15] = "TRAP #15", | ||
207 | [VEC_FPBRUC] = "FPCP BSUN", | ||
208 | [VEC_FPIR] = "FPCP INEXACT", | ||
209 | [VEC_FPDIVZ] = "FPCP DIV BY 0", | ||
210 | [VEC_FPUNDER] = "FPCP UNDERFLOW", | ||
211 | [VEC_FPOE] = "FPCP OPERAND ERROR", | ||
212 | [VEC_FPOVER] = "FPCP OVERFLOW", | ||
213 | [VEC_FPNAN] = "FPCP SNAN", | ||
214 | [VEC_FPUNSUP] = "FPCP UNSUPPORTED OPERATION", | ||
215 | [VEC_MMUCFG] = "MMU CONFIGURATION ERROR", | ||
216 | [VEC_MMUILL] = "MMU ILLEGAL OPERATION ERROR", | ||
217 | [VEC_MMUACC] = "MMU ACCESS LEVEL VIOLATION ERROR", | ||
218 | [VEC_RESV59] = "UNASSIGNED RESERVED 59", | ||
219 | [VEC_UNIMPEA] = "UNASSIGNED RESERVED 60", | ||
220 | [VEC_UNIMPII] = "UNASSIGNED RESERVED 61", | ||
221 | [VEC_RESV62] = "UNASSIGNED RESERVED 62", | ||
222 | [VEC_RESV63] = "UNASSIGNED RESERVED 63", | ||
223 | }; | ||
224 | |||
225 | static const char *space_names[] = { | ||
226 | [0] = "Space 0", | ||
227 | [USER_DATA] = "User Data", | ||
228 | [USER_PROGRAM] = "User Program", | ||
229 | #ifndef CONFIG_SUN3 | ||
230 | [3] = "Space 3", | ||
231 | #else | 3 | #else |
232 | [FC_CONTROL] = "Control", | 4 | #include "traps_no.c" |
233 | #endif | ||
234 | [4] = "Space 4", | ||
235 | [SUPER_DATA] = "Super Data", | ||
236 | [SUPER_PROGRAM] = "Super Program", | ||
237 | [CPU_SPACE] = "CPU" | ||
238 | }; | ||
239 | |||
240 | void die_if_kernel(char *,struct pt_regs *,int); | ||
241 | asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, | ||
242 | unsigned long error_code); | ||
243 | int send_fault_sig(struct pt_regs *regs); | ||
244 | |||
245 | asmlinkage void trap_c(struct frame *fp); | ||
246 | |||
247 | #if defined (CONFIG_M68060) | ||
248 | static inline void access_error060 (struct frame *fp) | ||
249 | { | ||
250 | unsigned long fslw = fp->un.fmt4.pc; /* is really FSLW for access error */ | ||
251 | |||
252 | #ifdef DEBUG | ||
253 | printk("fslw=%#lx, fa=%#lx\n", fslw, fp->un.fmt4.effaddr); | ||
254 | #endif | ||
255 | |||
256 | if (fslw & MMU060_BPE) { | ||
257 | /* branch prediction error -> clear branch cache */ | ||
258 | __asm__ __volatile__ ("movec %/cacr,%/d0\n\t" | ||
259 | "orl #0x00400000,%/d0\n\t" | ||
260 | "movec %/d0,%/cacr" | ||
261 | : : : "d0" ); | ||
262 | /* return if there's no other error */ | ||
263 | if (!(fslw & MMU060_ERR_BITS) && !(fslw & MMU060_SEE)) | ||
264 | return; | ||
265 | } | ||
266 | |||
267 | if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) { | ||
268 | unsigned long errorcode; | ||
269 | unsigned long addr = fp->un.fmt4.effaddr; | ||
270 | |||
271 | if (fslw & MMU060_MA) | ||
272 | addr = (addr + PAGE_SIZE - 1) & PAGE_MASK; | ||
273 | |||
274 | errorcode = 1; | ||
275 | if (fslw & MMU060_DESC_ERR) { | ||
276 | __flush_tlb040_one(addr); | ||
277 | errorcode = 0; | ||
278 | } | ||
279 | if (fslw & MMU060_W) | ||
280 | errorcode |= 2; | ||
281 | #ifdef DEBUG | ||
282 | printk("errorcode = %d\n", errorcode ); | ||
283 | #endif | ||
284 | do_page_fault(&fp->ptregs, addr, errorcode); | ||
285 | } else if (fslw & (MMU060_SEE)){ | ||
286 | /* Software Emulation Error. | ||
287 | * fault during mem_read/mem_write in ifpsp060/os.S | ||
288 | */ | ||
289 | send_fault_sig(&fp->ptregs); | ||
290 | } else if (!(fslw & (MMU060_RE|MMU060_WE)) || | ||
291 | send_fault_sig(&fp->ptregs) > 0) { | ||
292 | printk("pc=%#lx, fa=%#lx\n", fp->ptregs.pc, fp->un.fmt4.effaddr); | ||
293 | printk( "68060 access error, fslw=%lx\n", fslw ); | ||
294 | trap_c( fp ); | ||
295 | } | ||
296 | } | ||
297 | #endif /* CONFIG_M68060 */ | ||
298 | |||
299 | #if defined (CONFIG_M68040) | ||
300 | static inline unsigned long probe040(int iswrite, unsigned long addr, int wbs) | ||
301 | { | ||
302 | unsigned long mmusr; | ||
303 | mm_segment_t old_fs = get_fs(); | ||
304 | |||
305 | set_fs(MAKE_MM_SEG(wbs)); | ||
306 | |||
307 | if (iswrite) | ||
308 | asm volatile (".chip 68040; ptestw (%0); .chip 68k" : : "a" (addr)); | ||
309 | else | ||
310 | asm volatile (".chip 68040; ptestr (%0); .chip 68k" : : "a" (addr)); | ||
311 | |||
312 | asm volatile (".chip 68040; movec %%mmusr,%0; .chip 68k" : "=r" (mmusr)); | ||
313 | |||
314 | set_fs(old_fs); | ||
315 | |||
316 | return mmusr; | ||
317 | } | ||
318 | |||
319 | static inline int do_040writeback1(unsigned short wbs, unsigned long wba, | ||
320 | unsigned long wbd) | ||
321 | { | ||
322 | int res = 0; | ||
323 | mm_segment_t old_fs = get_fs(); | ||
324 | |||
325 | /* set_fs can not be moved, otherwise put_user() may oops */ | ||
326 | set_fs(MAKE_MM_SEG(wbs)); | ||
327 | |||
328 | switch (wbs & WBSIZ_040) { | ||
329 | case BA_SIZE_BYTE: | ||
330 | res = put_user(wbd & 0xff, (char __user *)wba); | ||
331 | break; | ||
332 | case BA_SIZE_WORD: | ||
333 | res = put_user(wbd & 0xffff, (short __user *)wba); | ||
334 | break; | ||
335 | case BA_SIZE_LONG: | ||
336 | res = put_user(wbd, (int __user *)wba); | ||
337 | break; | ||
338 | } | ||
339 | |||
340 | /* set_fs can not be moved, otherwise put_user() may oops */ | ||
341 | set_fs(old_fs); | ||
342 | |||
343 | |||
344 | #ifdef DEBUG | ||
345 | printk("do_040writeback1, res=%d\n",res); | ||
346 | #endif | ||
347 | |||
348 | return res; | ||
349 | } | ||
350 | |||
351 | /* after an exception in a writeback the stack frame corresponding | ||
352 | * to that exception is discarded, set a few bits in the old frame | ||
353 | * to simulate what it should look like | ||
354 | */ | ||
355 | static inline void fix_xframe040(struct frame *fp, unsigned long wba, unsigned short wbs) | ||
356 | { | ||
357 | fp->un.fmt7.faddr = wba; | ||
358 | fp->un.fmt7.ssw = wbs & 0xff; | ||
359 | if (wba != current->thread.faddr) | ||
360 | fp->un.fmt7.ssw |= MA_040; | ||
361 | } | ||
362 | |||
363 | static inline void do_040writebacks(struct frame *fp) | ||
364 | { | ||
365 | int res = 0; | ||
366 | #if 0 | ||
367 | if (fp->un.fmt7.wb1s & WBV_040) | ||
368 | printk("access_error040: cannot handle 1st writeback. oops.\n"); | ||
369 | #endif | ||
370 | |||
371 | if ((fp->un.fmt7.wb2s & WBV_040) && | ||
372 | !(fp->un.fmt7.wb2s & WBTT_040)) { | ||
373 | res = do_040writeback1(fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, | ||
374 | fp->un.fmt7.wb2d); | ||
375 | if (res) | ||
376 | fix_xframe040(fp, fp->un.fmt7.wb2a, fp->un.fmt7.wb2s); | ||
377 | else | ||
378 | fp->un.fmt7.wb2s = 0; | ||
379 | } | ||
380 | |||
381 | /* do the 2nd wb only if the first one was successful (except for a kernel wb) */ | ||
382 | if (fp->un.fmt7.wb3s & WBV_040 && (!res || fp->un.fmt7.wb3s & 4)) { | ||
383 | res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, | ||
384 | fp->un.fmt7.wb3d); | ||
385 | if (res) | ||
386 | { | ||
387 | fix_xframe040(fp, fp->un.fmt7.wb3a, fp->un.fmt7.wb3s); | ||
388 | |||
389 | fp->un.fmt7.wb2s = fp->un.fmt7.wb3s; | ||
390 | fp->un.fmt7.wb3s &= (~WBV_040); | ||
391 | fp->un.fmt7.wb2a = fp->un.fmt7.wb3a; | ||
392 | fp->un.fmt7.wb2d = fp->un.fmt7.wb3d; | ||
393 | } | ||
394 | else | ||
395 | fp->un.fmt7.wb3s = 0; | ||
396 | } | ||
397 | |||
398 | if (res) | ||
399 | send_fault_sig(&fp->ptregs); | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * called from sigreturn(), must ensure userspace code didn't | ||
404 | * manipulate exception frame to circumvent protection, then complete | ||
405 | * pending writebacks | ||
406 | * we just clear TM2 to turn it into a userspace access | ||
407 | */ | ||
408 | asmlinkage void berr_040cleanup(struct frame *fp) | ||
409 | { | ||
410 | fp->un.fmt7.wb2s &= ~4; | ||
411 | fp->un.fmt7.wb3s &= ~4; | ||
412 | |||
413 | do_040writebacks(fp); | ||
414 | } | ||
415 | |||
416 | static inline void access_error040(struct frame *fp) | ||
417 | { | ||
418 | unsigned short ssw = fp->un.fmt7.ssw; | ||
419 | unsigned long mmusr; | ||
420 | |||
421 | #ifdef DEBUG | ||
422 | printk("ssw=%#x, fa=%#lx\n", ssw, fp->un.fmt7.faddr); | ||
423 | printk("wb1s=%#x, wb2s=%#x, wb3s=%#x\n", fp->un.fmt7.wb1s, | ||
424 | fp->un.fmt7.wb2s, fp->un.fmt7.wb3s); | ||
425 | printk ("wb2a=%lx, wb3a=%lx, wb2d=%lx, wb3d=%lx\n", | ||
426 | fp->un.fmt7.wb2a, fp->un.fmt7.wb3a, | ||
427 | fp->un.fmt7.wb2d, fp->un.fmt7.wb3d); | ||
428 | #endif | ||
429 | |||
430 | if (ssw & ATC_040) { | ||
431 | unsigned long addr = fp->un.fmt7.faddr; | ||
432 | unsigned long errorcode; | ||
433 | |||
434 | /* | ||
435 | * The MMU status has to be determined AFTER the address | ||
436 | * has been corrected if there was a misaligned access (MA). | ||
437 | */ | ||
438 | if (ssw & MA_040) | ||
439 | addr = (addr + 7) & -8; | ||
440 | |||
441 | /* MMU error, get the MMUSR info for this access */ | ||
442 | mmusr = probe040(!(ssw & RW_040), addr, ssw); | ||
443 | #ifdef DEBUG | ||
444 | printk("mmusr = %lx\n", mmusr); | ||
445 | #endif | ||
446 | errorcode = 1; | ||
447 | if (!(mmusr & MMU_R_040)) { | ||
448 | /* clear the invalid atc entry */ | ||
449 | __flush_tlb040_one(addr); | ||
450 | errorcode = 0; | ||
451 | } | ||
452 | |||
453 | /* despite what documentation seems to say, RMW | ||
454 | * accesses have always both the LK and RW bits set */ | ||
455 | if (!(ssw & RW_040) || (ssw & LK_040)) | ||
456 | errorcode |= 2; | ||
457 | |||
458 | if (do_page_fault(&fp->ptregs, addr, errorcode)) { | ||
459 | #ifdef DEBUG | ||
460 | printk("do_page_fault() !=0\n"); | ||
461 | #endif | ||
462 | if (user_mode(&fp->ptregs)){ | ||
463 | /* delay writebacks after signal delivery */ | ||
464 | #ifdef DEBUG | ||
465 | printk(".. was usermode - return\n"); | ||
466 | #endif | ||
467 | return; | ||
468 | } | ||
469 | /* disable writeback into user space from kernel | ||
470 | * (if do_page_fault didn't fix the mapping, | ||
471 | * the writeback won't do good) | ||
472 | */ | ||
473 | disable_wb: | ||
474 | #ifdef DEBUG | ||
475 | printk(".. disabling wb2\n"); | ||
476 | #endif | ||
477 | if (fp->un.fmt7.wb2a == fp->un.fmt7.faddr) | ||
478 | fp->un.fmt7.wb2s &= ~WBV_040; | ||
479 | if (fp->un.fmt7.wb3a == fp->un.fmt7.faddr) | ||
480 | fp->un.fmt7.wb3s &= ~WBV_040; | ||
481 | } | ||
482 | } else { | ||
483 | /* In case of a bus error we either kill the process or expect | ||
484 | * the kernel to catch the fault, which then is also responsible | ||
485 | * for cleaning up the mess. | ||
486 | */ | ||
487 | current->thread.signo = SIGBUS; | ||
488 | current->thread.faddr = fp->un.fmt7.faddr; | ||
489 | if (send_fault_sig(&fp->ptregs) >= 0) | ||
490 | printk("68040 bus error (ssw=%x, faddr=%lx)\n", ssw, | ||
491 | fp->un.fmt7.faddr); | ||
492 | goto disable_wb; | ||
493 | } | ||
494 | |||
495 | do_040writebacks(fp); | ||
496 | } | ||
497 | #endif /* CONFIG_M68040 */ | ||
498 | |||
499 | #if defined(CONFIG_SUN3) | ||
500 | #include <asm/sun3mmu.h> | ||
501 | |||
502 | extern int mmu_emu_handle_fault (unsigned long, int, int); | ||
503 | |||
504 | /* sun3 version of bus_error030 */ | ||
505 | |||
506 | static inline void bus_error030 (struct frame *fp) | ||
507 | { | ||
508 | unsigned char buserr_type = sun3_get_buserr (); | ||
509 | unsigned long addr, errorcode; | ||
510 | unsigned short ssw = fp->un.fmtb.ssw; | ||
511 | extern unsigned long _sun3_map_test_start, _sun3_map_test_end; | ||
512 | |||
513 | #ifdef DEBUG | ||
514 | if (ssw & (FC | FB)) | ||
515 | printk ("Instruction fault at %#010lx\n", | ||
516 | ssw & FC ? | ||
517 | fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2 | ||
518 | : | ||
519 | fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); | ||
520 | if (ssw & DF) | ||
521 | printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
522 | ssw & RW ? "read" : "write", | ||
523 | fp->un.fmtb.daddr, | ||
524 | space_names[ssw & DFC], fp->ptregs.pc); | ||
525 | #endif | ||
526 | |||
527 | /* | ||
528 | * Check if this page should be demand-mapped. This needs to go before | ||
529 | * the testing for a bad kernel-space access (demand-mapping applies | ||
530 | * to kernel accesses too). | ||
531 | */ | ||
532 | |||
533 | if ((ssw & DF) | ||
534 | && (buserr_type & (SUN3_BUSERR_PROTERR | SUN3_BUSERR_INVALID))) { | ||
535 | if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 0)) | ||
536 | return; | ||
537 | } | ||
538 | |||
539 | /* Check for kernel-space pagefault (BAD). */ | ||
540 | if (fp->ptregs.sr & PS_S) { | ||
541 | /* kernel fault must be a data fault to user space */ | ||
542 | if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) { | ||
543 | // try checking the kernel mappings before surrender | ||
544 | if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 1)) | ||
545 | return; | ||
546 | /* instruction fault or kernel data fault! */ | ||
547 | if (ssw & (FC | FB)) | ||
548 | printk ("Instruction fault at %#010lx\n", | ||
549 | fp->ptregs.pc); | ||
550 | if (ssw & DF) { | ||
551 | /* was this fault incurred testing bus mappings? */ | ||
552 | if((fp->ptregs.pc >= (unsigned long)&_sun3_map_test_start) && | ||
553 | (fp->ptregs.pc <= (unsigned long)&_sun3_map_test_end)) { | ||
554 | send_fault_sig(&fp->ptregs); | ||
555 | return; | ||
556 | } | ||
557 | |||
558 | printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
559 | ssw & RW ? "read" : "write", | ||
560 | fp->un.fmtb.daddr, | ||
561 | space_names[ssw & DFC], fp->ptregs.pc); | ||
562 | } | ||
563 | printk ("BAD KERNEL BUSERR\n"); | ||
564 | |||
565 | die_if_kernel("Oops", &fp->ptregs,0); | ||
566 | force_sig(SIGKILL, current); | ||
567 | return; | ||
568 | } | ||
569 | } else { | ||
570 | /* user fault */ | ||
571 | if (!(ssw & (FC | FB)) && !(ssw & DF)) | ||
572 | /* not an instruction fault or data fault! BAD */ | ||
573 | panic ("USER BUSERR w/o instruction or data fault"); | ||
574 | } | ||
575 | |||
576 | |||
577 | /* First handle the data fault, if any. */ | ||
578 | if (ssw & DF) { | ||
579 | addr = fp->un.fmtb.daddr; | ||
580 | |||
581 | // errorcode bit 0: 0 -> no page 1 -> protection fault | ||
582 | // errorcode bit 1: 0 -> read fault 1 -> write fault | ||
583 | |||
584 | // (buserr_type & SUN3_BUSERR_PROTERR) -> protection fault | ||
585 | // (buserr_type & SUN3_BUSERR_INVALID) -> invalid page fault | ||
586 | |||
587 | if (buserr_type & SUN3_BUSERR_PROTERR) | ||
588 | errorcode = 0x01; | ||
589 | else if (buserr_type & SUN3_BUSERR_INVALID) | ||
590 | errorcode = 0x00; | ||
591 | else { | ||
592 | #ifdef DEBUG | ||
593 | printk ("*** unexpected busfault type=%#04x\n", buserr_type); | ||
594 | printk ("invalid %s access at %#lx from pc %#lx\n", | ||
595 | !(ssw & RW) ? "write" : "read", addr, | ||
596 | fp->ptregs.pc); | ||
597 | #endif | ||
598 | die_if_kernel ("Oops", &fp->ptregs, buserr_type); | ||
599 | force_sig (SIGBUS, current); | ||
600 | return; | ||
601 | } | ||
602 | |||
603 | //todo: wtf is RM bit? --m | ||
604 | if (!(ssw & RW) || ssw & RM) | ||
605 | errorcode |= 0x02; | ||
606 | |||
607 | /* Handle page fault. */ | ||
608 | do_page_fault (&fp->ptregs, addr, errorcode); | ||
609 | |||
610 | /* Retry the data fault now. */ | ||
611 | return; | ||
612 | } | ||
613 | |||
614 | /* Now handle the instruction fault. */ | ||
615 | |||
616 | /* Get the fault address. */ | ||
617 | if (fp->ptregs.format == 0xA) | ||
618 | addr = fp->ptregs.pc + 4; | ||
619 | else | ||
620 | addr = fp->un.fmtb.baddr; | ||
621 | if (ssw & FC) | ||
622 | addr -= 2; | ||
623 | |||
624 | if (buserr_type & SUN3_BUSERR_INVALID) { | ||
625 | if (!mmu_emu_handle_fault (fp->un.fmtb.daddr, 1, 0)) | ||
626 | do_page_fault (&fp->ptregs, addr, 0); | ||
627 | } else { | ||
628 | #ifdef DEBUG | ||
629 | printk ("protection fault on insn access (segv).\n"); | ||
630 | #endif | ||
631 | force_sig (SIGSEGV, current); | ||
632 | } | ||
633 | } | ||
634 | #else | ||
635 | #if defined(CPU_M68020_OR_M68030) | ||
636 | static inline void bus_error030 (struct frame *fp) | ||
637 | { | ||
638 | volatile unsigned short temp; | ||
639 | unsigned short mmusr; | ||
640 | unsigned long addr, errorcode; | ||
641 | unsigned short ssw = fp->un.fmtb.ssw; | ||
642 | #ifdef DEBUG | ||
643 | unsigned long desc; | ||
644 | |||
645 | printk ("pid = %x ", current->pid); | ||
646 | printk ("SSW=%#06x ", ssw); | ||
647 | |||
648 | if (ssw & (FC | FB)) | ||
649 | printk ("Instruction fault at %#010lx\n", | ||
650 | ssw & FC ? | ||
651 | fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2 | ||
652 | : | ||
653 | fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); | ||
654 | if (ssw & DF) | ||
655 | printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
656 | ssw & RW ? "read" : "write", | ||
657 | fp->un.fmtb.daddr, | ||
658 | space_names[ssw & DFC], fp->ptregs.pc); | ||
659 | #endif | ||
660 | |||
661 | /* ++andreas: If a data fault and an instruction fault happen | ||
662 | at the same time map in both pages. */ | ||
663 | |||
664 | /* First handle the data fault, if any. */ | ||
665 | if (ssw & DF) { | ||
666 | addr = fp->un.fmtb.daddr; | ||
667 | |||
668 | #ifdef DEBUG | ||
669 | asm volatile ("ptestr %3,%2@,#7,%0\n\t" | ||
670 | "pmove %%psr,%1@" | ||
671 | : "=a&" (desc) | ||
672 | : "a" (&temp), "a" (addr), "d" (ssw)); | ||
673 | #else | ||
674 | asm volatile ("ptestr %2,%1@,#7\n\t" | ||
675 | "pmove %%psr,%0@" | ||
676 | : : "a" (&temp), "a" (addr), "d" (ssw)); | ||
677 | #endif | ||
678 | mmusr = temp; | ||
679 | |||
680 | #ifdef DEBUG | ||
681 | printk("mmusr is %#x for addr %#lx in task %p\n", | ||
682 | mmusr, addr, current); | ||
683 | printk("descriptor address is %#lx, contents %#lx\n", | ||
684 | __va(desc), *(unsigned long *)__va(desc)); | ||
685 | #endif | ||
686 | |||
687 | errorcode = (mmusr & MMU_I) ? 0 : 1; | ||
688 | if (!(ssw & RW) || (ssw & RM)) | ||
689 | errorcode |= 2; | ||
690 | |||
691 | if (mmusr & (MMU_I | MMU_WP)) { | ||
692 | if (ssw & 4) { | ||
693 | printk("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
694 | ssw & RW ? "read" : "write", | ||
695 | fp->un.fmtb.daddr, | ||
696 | space_names[ssw & DFC], fp->ptregs.pc); | ||
697 | goto buserr; | ||
698 | } | ||
699 | /* Don't try to do anything further if an exception was | ||
700 | handled. */ | ||
701 | if (do_page_fault (&fp->ptregs, addr, errorcode) < 0) | ||
702 | return; | ||
703 | } else if (!(mmusr & MMU_I)) { | ||
704 | /* probably a 020 cas fault */ | ||
705 | if (!(ssw & RM) && send_fault_sig(&fp->ptregs) > 0) | ||
706 | printk("unexpected bus error (%#x,%#x)\n", ssw, mmusr); | ||
707 | } else if (mmusr & (MMU_B|MMU_L|MMU_S)) { | ||
708 | printk("invalid %s access at %#lx from pc %#lx\n", | ||
709 | !(ssw & RW) ? "write" : "read", addr, | ||
710 | fp->ptregs.pc); | ||
711 | die_if_kernel("Oops",&fp->ptregs,mmusr); | ||
712 | force_sig(SIGSEGV, current); | ||
713 | return; | ||
714 | } else { | ||
715 | #if 0 | ||
716 | static volatile long tlong; | ||
717 | #endif | ||
718 | |||
719 | printk("weird %s access at %#lx from pc %#lx (ssw is %#x)\n", | ||
720 | !(ssw & RW) ? "write" : "read", addr, | ||
721 | fp->ptregs.pc, ssw); | ||
722 | asm volatile ("ptestr #1,%1@,#0\n\t" | ||
723 | "pmove %%psr,%0@" | ||
724 | : /* no outputs */ | ||
725 | : "a" (&temp), "a" (addr)); | ||
726 | mmusr = temp; | ||
727 | |||
728 | printk ("level 0 mmusr is %#x\n", mmusr); | ||
729 | #if 0 | ||
730 | asm volatile ("pmove %%tt0,%0@" | ||
731 | : /* no outputs */ | ||
732 | : "a" (&tlong)); | ||
733 | printk("tt0 is %#lx, ", tlong); | ||
734 | asm volatile ("pmove %%tt1,%0@" | ||
735 | : /* no outputs */ | ||
736 | : "a" (&tlong)); | ||
737 | printk("tt1 is %#lx\n", tlong); | ||
738 | #endif | ||
739 | #ifdef DEBUG | ||
740 | printk("Unknown SIGSEGV - 1\n"); | ||
741 | #endif | ||
742 | die_if_kernel("Oops",&fp->ptregs,mmusr); | ||
743 | force_sig(SIGSEGV, current); | ||
744 | return; | ||
745 | } | ||
746 | |||
747 | /* setup an ATC entry for the access about to be retried */ | ||
748 | if (!(ssw & RW) || (ssw & RM)) | ||
749 | asm volatile ("ploadw %1,%0@" : /* no outputs */ | ||
750 | : "a" (addr), "d" (ssw)); | ||
751 | else | ||
752 | asm volatile ("ploadr %1,%0@" : /* no outputs */ | ||
753 | : "a" (addr), "d" (ssw)); | ||
754 | } | ||
755 | |||
756 | /* Now handle the instruction fault. */ | ||
757 | |||
758 | if (!(ssw & (FC|FB))) | ||
759 | return; | ||
760 | |||
761 | if (fp->ptregs.sr & PS_S) { | ||
762 | printk("Instruction fault at %#010lx\n", | ||
763 | fp->ptregs.pc); | ||
764 | buserr: | ||
765 | printk ("BAD KERNEL BUSERR\n"); | ||
766 | die_if_kernel("Oops",&fp->ptregs,0); | ||
767 | force_sig(SIGKILL, current); | ||
768 | return; | ||
769 | } | ||
770 | |||
771 | /* get the fault address */ | ||
772 | if (fp->ptregs.format == 10) | ||
773 | addr = fp->ptregs.pc + 4; | ||
774 | else | ||
775 | addr = fp->un.fmtb.baddr; | ||
776 | if (ssw & FC) | ||
777 | addr -= 2; | ||
778 | |||
779 | if ((ssw & DF) && ((addr ^ fp->un.fmtb.daddr) & PAGE_MASK) == 0) | ||
780 | /* Insn fault on same page as data fault. But we | ||
781 | should still create the ATC entry. */ | ||
782 | goto create_atc_entry; | ||
783 | |||
784 | #ifdef DEBUG | ||
785 | asm volatile ("ptestr #1,%2@,#7,%0\n\t" | ||
786 | "pmove %%psr,%1@" | ||
787 | : "=a&" (desc) | ||
788 | : "a" (&temp), "a" (addr)); | ||
789 | #else | ||
790 | asm volatile ("ptestr #1,%1@,#7\n\t" | ||
791 | "pmove %%psr,%0@" | ||
792 | : : "a" (&temp), "a" (addr)); | ||
793 | #endif | ||
794 | mmusr = temp; | ||
795 | |||
796 | #ifdef DEBUG | ||
797 | printk ("mmusr is %#x for addr %#lx in task %p\n", | ||
798 | mmusr, addr, current); | ||
799 | printk ("descriptor address is %#lx, contents %#lx\n", | ||
800 | __va(desc), *(unsigned long *)__va(desc)); | ||
801 | #endif | ||
802 | |||
803 | if (mmusr & MMU_I) | ||
804 | do_page_fault (&fp->ptregs, addr, 0); | ||
805 | else if (mmusr & (MMU_B|MMU_L|MMU_S)) { | ||
806 | printk ("invalid insn access at %#lx from pc %#lx\n", | ||
807 | addr, fp->ptregs.pc); | ||
808 | #ifdef DEBUG | ||
809 | printk("Unknown SIGSEGV - 2\n"); | ||
810 | #endif | ||
811 | die_if_kernel("Oops",&fp->ptregs,mmusr); | ||
812 | force_sig(SIGSEGV, current); | ||
813 | return; | ||
814 | } | ||
815 | |||
816 | create_atc_entry: | ||
817 | /* setup an ATC entry for the access about to be retried */ | ||
818 | asm volatile ("ploadr #2,%0@" : /* no outputs */ | ||
819 | : "a" (addr)); | ||
820 | } | ||
821 | #endif /* CPU_M68020_OR_M68030 */ | ||
822 | #endif /* !CONFIG_SUN3 */ | ||
823 | |||
824 | asmlinkage void buserr_c(struct frame *fp) | ||
825 | { | ||
826 | /* Only set esp0 if coming from user mode */ | ||
827 | if (user_mode(&fp->ptregs)) | ||
828 | current->thread.esp0 = (unsigned long) fp; | ||
829 | |||
830 | #ifdef DEBUG | ||
831 | printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format); | ||
832 | #endif | ||
833 | |||
834 | switch (fp->ptregs.format) { | ||
835 | #if defined (CONFIG_M68060) | ||
836 | case 4: /* 68060 access error */ | ||
837 | access_error060 (fp); | ||
838 | break; | ||
839 | #endif | ||
840 | #if defined (CONFIG_M68040) | ||
841 | case 0x7: /* 68040 access error */ | ||
842 | access_error040 (fp); | ||
843 | break; | ||
844 | #endif | ||
845 | #if defined (CPU_M68020_OR_M68030) | ||
846 | case 0xa: | ||
847 | case 0xb: | ||
848 | bus_error030 (fp); | ||
849 | break; | ||
850 | #endif | ||
851 | default: | ||
852 | die_if_kernel("bad frame format",&fp->ptregs,0); | ||
853 | #ifdef DEBUG | ||
854 | printk("Unknown SIGSEGV - 4\n"); | ||
855 | #endif | ||
856 | force_sig(SIGSEGV, current); | ||
857 | } | ||
858 | } | ||
859 | |||
860 | |||
861 | static int kstack_depth_to_print = 48; | ||
862 | |||
863 | void show_trace(unsigned long *stack) | ||
864 | { | ||
865 | unsigned long *endstack; | ||
866 | unsigned long addr; | ||
867 | int i; | ||
868 | |||
869 | printk("Call Trace:"); | ||
870 | addr = (unsigned long)stack + THREAD_SIZE - 1; | ||
871 | endstack = (unsigned long *)(addr & -THREAD_SIZE); | ||
872 | i = 0; | ||
873 | while (stack + 1 <= endstack) { | ||
874 | addr = *stack++; | ||
875 | /* | ||
876 | * If the address is either in the text segment of the | ||
877 | * kernel, or in the region which contains vmalloc'ed | ||
878 | * memory, it *may* be the address of a calling | ||
879 | * routine; if so, print it so that someone tracing | ||
880 | * down the cause of the crash will be able to figure | ||
881 | * out the call path that was taken. | ||
882 | */ | ||
883 | if (__kernel_text_address(addr)) { | ||
884 | #ifndef CONFIG_KALLSYMS | ||
885 | if (i % 5 == 0) | ||
886 | printk("\n "); | ||
887 | #endif | ||
888 | printk(" [<%08lx>] %pS\n", addr, (void *)addr); | ||
889 | i++; | ||
890 | } | ||
891 | } | ||
892 | printk("\n"); | ||
893 | } | ||
894 | |||
895 | void show_registers(struct pt_regs *regs) | ||
896 | { | ||
897 | struct frame *fp = (struct frame *)regs; | ||
898 | mm_segment_t old_fs = get_fs(); | ||
899 | u16 c, *cp; | ||
900 | unsigned long addr; | ||
901 | int i; | ||
902 | |||
903 | print_modules(); | ||
904 | printk("PC: [<%08lx>] %pS\n", regs->pc, (void *)regs->pc); | ||
905 | printk("SR: %04x SP: %p a2: %08lx\n", regs->sr, regs, regs->a2); | ||
906 | printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", | ||
907 | regs->d0, regs->d1, regs->d2, regs->d3); | ||
908 | printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", | ||
909 | regs->d4, regs->d5, regs->a0, regs->a1); | ||
910 | |||
911 | printk("Process %s (pid: %d, task=%p)\n", | ||
912 | current->comm, task_pid_nr(current), current); | ||
913 | addr = (unsigned long)&fp->un; | ||
914 | printk("Frame format=%X ", regs->format); | ||
915 | switch (regs->format) { | ||
916 | case 0x2: | ||
917 | printk("instr addr=%08lx\n", fp->un.fmt2.iaddr); | ||
918 | addr += sizeof(fp->un.fmt2); | ||
919 | break; | ||
920 | case 0x3: | ||
921 | printk("eff addr=%08lx\n", fp->un.fmt3.effaddr); | ||
922 | addr += sizeof(fp->un.fmt3); | ||
923 | break; | ||
924 | case 0x4: | ||
925 | printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n" | ||
926 | : "eff addr=%08lx pc=%08lx\n"), | ||
927 | fp->un.fmt4.effaddr, fp->un.fmt4.pc); | ||
928 | addr += sizeof(fp->un.fmt4); | ||
929 | break; | ||
930 | case 0x7: | ||
931 | printk("eff addr=%08lx ssw=%04x faddr=%08lx\n", | ||
932 | fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr); | ||
933 | printk("wb 1 stat/addr/data: %04x %08lx %08lx\n", | ||
934 | fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0); | ||
935 | printk("wb 2 stat/addr/data: %04x %08lx %08lx\n", | ||
936 | fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d); | ||
937 | printk("wb 3 stat/addr/data: %04x %08lx %08lx\n", | ||
938 | fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d); | ||
939 | printk("push data: %08lx %08lx %08lx %08lx\n", | ||
940 | fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2, | ||
941 | fp->un.fmt7.pd3); | ||
942 | addr += sizeof(fp->un.fmt7); | ||
943 | break; | ||
944 | case 0x9: | ||
945 | printk("instr addr=%08lx\n", fp->un.fmt9.iaddr); | ||
946 | addr += sizeof(fp->un.fmt9); | ||
947 | break; | ||
948 | case 0xa: | ||
949 | printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n", | ||
950 | fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb, | ||
951 | fp->un.fmta.daddr, fp->un.fmta.dobuf); | ||
952 | addr += sizeof(fp->un.fmta); | ||
953 | break; | ||
954 | case 0xb: | ||
955 | printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n", | ||
956 | fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb, | ||
957 | fp->un.fmtb.daddr, fp->un.fmtb.dobuf); | ||
958 | printk("baddr=%08lx dibuf=%08lx ver=%x\n", | ||
959 | fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver); | ||
960 | addr += sizeof(fp->un.fmtb); | ||
961 | break; | ||
962 | default: | ||
963 | printk("\n"); | ||
964 | } | ||
965 | show_stack(NULL, (unsigned long *)addr); | ||
966 | |||
967 | printk("Code:"); | ||
968 | set_fs(KERNEL_DS); | ||
969 | cp = (u16 *)regs->pc; | ||
970 | for (i = -8; i < 16; i++) { | ||
971 | if (get_user(c, cp + i) && i >= 0) { | ||
972 | printk(" Bad PC value."); | ||
973 | break; | ||
974 | } | ||
975 | printk(i ? " %04x" : " <%04x>", c); | ||
976 | } | ||
977 | set_fs(old_fs); | ||
978 | printk ("\n"); | ||
979 | } | ||
980 | |||
981 | void show_stack(struct task_struct *task, unsigned long *stack) | ||
982 | { | ||
983 | unsigned long *p; | ||
984 | unsigned long *endstack; | ||
985 | int i; | ||
986 | |||
987 | if (!stack) { | ||
988 | if (task) | ||
989 | stack = (unsigned long *)task->thread.esp0; | ||
990 | else | ||
991 | stack = (unsigned long *)&stack; | ||
992 | } | ||
993 | endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE); | ||
994 | |||
995 | printk("Stack from %08lx:", (unsigned long)stack); | ||
996 | p = stack; | ||
997 | for (i = 0; i < kstack_depth_to_print; i++) { | ||
998 | if (p + 1 > endstack) | ||
999 | break; | ||
1000 | if (i % 8 == 0) | ||
1001 | printk("\n "); | ||
1002 | printk(" %08lx", *p++); | ||
1003 | } | ||
1004 | printk("\n"); | ||
1005 | show_trace(stack); | ||
1006 | } | ||
1007 | |||
1008 | /* | ||
1009 | * The architecture-independent backtrace generator | ||
1010 | */ | ||
1011 | void dump_stack(void) | ||
1012 | { | ||
1013 | unsigned long stack; | ||
1014 | |||
1015 | show_trace(&stack); | ||
1016 | } | ||
1017 | |||
1018 | EXPORT_SYMBOL(dump_stack); | ||
1019 | |||
1020 | void bad_super_trap (struct frame *fp) | ||
1021 | { | ||
1022 | console_verbose(); | ||
1023 | if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names)) | ||
1024 | printk ("*** %s *** FORMAT=%X\n", | ||
1025 | vec_names[(fp->ptregs.vector) >> 2], | ||
1026 | fp->ptregs.format); | ||
1027 | else | ||
1028 | printk ("*** Exception %d *** FORMAT=%X\n", | ||
1029 | (fp->ptregs.vector) >> 2, | ||
1030 | fp->ptregs.format); | ||
1031 | if (fp->ptregs.vector >> 2 == VEC_ADDRERR && CPU_IS_020_OR_030) { | ||
1032 | unsigned short ssw = fp->un.fmtb.ssw; | ||
1033 | |||
1034 | printk ("SSW=%#06x ", ssw); | ||
1035 | |||
1036 | if (ssw & RC) | ||
1037 | printk ("Pipe stage C instruction fault at %#010lx\n", | ||
1038 | (fp->ptregs.format) == 0xA ? | ||
1039 | fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2); | ||
1040 | if (ssw & RB) | ||
1041 | printk ("Pipe stage B instruction fault at %#010lx\n", | ||
1042 | (fp->ptregs.format) == 0xA ? | ||
1043 | fp->ptregs.pc + 4 : fp->un.fmtb.baddr); | ||
1044 | if (ssw & DF) | ||
1045 | printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
1046 | ssw & RW ? "read" : "write", | ||
1047 | fp->un.fmtb.daddr, space_names[ssw & DFC], | ||
1048 | fp->ptregs.pc); | ||
1049 | } | ||
1050 | printk ("Current process id is %d\n", task_pid_nr(current)); | ||
1051 | die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); | ||
1052 | } | ||
1053 | |||
1054 | asmlinkage void trap_c(struct frame *fp) | ||
1055 | { | ||
1056 | int sig; | ||
1057 | siginfo_t info; | ||
1058 | |||
1059 | if (fp->ptregs.sr & PS_S) { | ||
1060 | if (fp->ptregs.vector == VEC_TRACE << 2) { | ||
1061 | /* traced a trapping instruction on a 68020/30, | ||
1062 | * real exception will be executed afterwards. | ||
1063 | */ | ||
1064 | } else if (!handle_kernel_fault(&fp->ptregs)) | ||
1065 | bad_super_trap(fp); | ||
1066 | return; | ||
1067 | } | ||
1068 | |||
1069 | /* send the appropriate signal to the user program */ | ||
1070 | switch ((fp->ptregs.vector) >> 2) { | ||
1071 | case VEC_ADDRERR: | ||
1072 | info.si_code = BUS_ADRALN; | ||
1073 | sig = SIGBUS; | ||
1074 | break; | ||
1075 | case VEC_ILLEGAL: | ||
1076 | case VEC_LINE10: | ||
1077 | case VEC_LINE11: | ||
1078 | info.si_code = ILL_ILLOPC; | ||
1079 | sig = SIGILL; | ||
1080 | break; | ||
1081 | case VEC_PRIV: | ||
1082 | info.si_code = ILL_PRVOPC; | ||
1083 | sig = SIGILL; | ||
1084 | break; | ||
1085 | case VEC_COPROC: | ||
1086 | info.si_code = ILL_COPROC; | ||
1087 | sig = SIGILL; | ||
1088 | break; | ||
1089 | case VEC_TRAP1: | ||
1090 | case VEC_TRAP2: | ||
1091 | case VEC_TRAP3: | ||
1092 | case VEC_TRAP4: | ||
1093 | case VEC_TRAP5: | ||
1094 | case VEC_TRAP6: | ||
1095 | case VEC_TRAP7: | ||
1096 | case VEC_TRAP8: | ||
1097 | case VEC_TRAP9: | ||
1098 | case VEC_TRAP10: | ||
1099 | case VEC_TRAP11: | ||
1100 | case VEC_TRAP12: | ||
1101 | case VEC_TRAP13: | ||
1102 | case VEC_TRAP14: | ||
1103 | info.si_code = ILL_ILLTRP; | ||
1104 | sig = SIGILL; | ||
1105 | break; | ||
1106 | case VEC_FPBRUC: | ||
1107 | case VEC_FPOE: | ||
1108 | case VEC_FPNAN: | ||
1109 | info.si_code = FPE_FLTINV; | ||
1110 | sig = SIGFPE; | ||
1111 | break; | ||
1112 | case VEC_FPIR: | ||
1113 | info.si_code = FPE_FLTRES; | ||
1114 | sig = SIGFPE; | ||
1115 | break; | ||
1116 | case VEC_FPDIVZ: | ||
1117 | info.si_code = FPE_FLTDIV; | ||
1118 | sig = SIGFPE; | ||
1119 | break; | ||
1120 | case VEC_FPUNDER: | ||
1121 | info.si_code = FPE_FLTUND; | ||
1122 | sig = SIGFPE; | ||
1123 | break; | ||
1124 | case VEC_FPOVER: | ||
1125 | info.si_code = FPE_FLTOVF; | ||
1126 | sig = SIGFPE; | ||
1127 | break; | ||
1128 | case VEC_ZERODIV: | ||
1129 | info.si_code = FPE_INTDIV; | ||
1130 | sig = SIGFPE; | ||
1131 | break; | ||
1132 | case VEC_CHK: | ||
1133 | case VEC_TRAP: | ||
1134 | info.si_code = FPE_INTOVF; | ||
1135 | sig = SIGFPE; | ||
1136 | break; | ||
1137 | case VEC_TRACE: /* ptrace single step */ | ||
1138 | info.si_code = TRAP_TRACE; | ||
1139 | sig = SIGTRAP; | ||
1140 | break; | ||
1141 | case VEC_TRAP15: /* breakpoint */ | ||
1142 | info.si_code = TRAP_BRKPT; | ||
1143 | sig = SIGTRAP; | ||
1144 | break; | ||
1145 | default: | ||
1146 | info.si_code = ILL_ILLOPC; | ||
1147 | sig = SIGILL; | ||
1148 | break; | ||
1149 | } | ||
1150 | info.si_signo = sig; | ||
1151 | info.si_errno = 0; | ||
1152 | switch (fp->ptregs.format) { | ||
1153 | default: | ||
1154 | info.si_addr = (void *) fp->ptregs.pc; | ||
1155 | break; | ||
1156 | case 2: | ||
1157 | info.si_addr = (void *) fp->un.fmt2.iaddr; | ||
1158 | break; | ||
1159 | case 7: | ||
1160 | info.si_addr = (void *) fp->un.fmt7.effaddr; | ||
1161 | break; | ||
1162 | case 9: | ||
1163 | info.si_addr = (void *) fp->un.fmt9.iaddr; | ||
1164 | break; | ||
1165 | case 10: | ||
1166 | info.si_addr = (void *) fp->un.fmta.daddr; | ||
1167 | break; | ||
1168 | case 11: | ||
1169 | info.si_addr = (void *) fp->un.fmtb.daddr; | ||
1170 | break; | ||
1171 | } | ||
1172 | force_sig_info (sig, &info, current); | ||
1173 | } | ||
1174 | |||
1175 | void die_if_kernel (char *str, struct pt_regs *fp, int nr) | ||
1176 | { | ||
1177 | if (!(fp->sr & PS_S)) | ||
1178 | return; | ||
1179 | |||
1180 | console_verbose(); | ||
1181 | printk("%s: %08x\n",str,nr); | ||
1182 | show_registers(fp); | ||
1183 | add_taint(TAINT_DIE); | ||
1184 | do_exit(SIGSEGV); | ||
1185 | } | ||
1186 | |||
1187 | /* | ||
1188 | * This function is called if an error occur while accessing | ||
1189 | * user-space from the fpsp040 code. | ||
1190 | */ | ||
1191 | asmlinkage void fpsp040_die(void) | ||
1192 | { | ||
1193 | do_exit(SIGSEGV); | ||
1194 | } | ||
1195 | |||
1196 | #ifdef CONFIG_M68KFPU_EMU | ||
1197 | asmlinkage void fpemu_signal(int signal, int code, void *addr) | ||
1198 | { | ||
1199 | siginfo_t info; | ||
1200 | |||
1201 | info.si_signo = signal; | ||
1202 | info.si_errno = 0; | ||
1203 | info.si_code = code; | ||
1204 | info.si_addr = addr; | ||
1205 | force_sig_info(signal, &info, current); | ||
1206 | } | ||
1207 | #endif | 5 | #endif |
diff --git a/arch/m68k/kernel/traps_mm.c b/arch/m68k/kernel/traps_mm.c new file mode 100644 index 000000000000..4022bbc28878 --- /dev/null +++ b/arch/m68k/kernel/traps_mm.c | |||
@@ -0,0 +1,1207 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/kernel/traps.c | ||
3 | * | ||
4 | * Copyright (C) 1993, 1994 by Hamish Macdonald | ||
5 | * | ||
6 | * 68040 fixes by Michael Rausch | ||
7 | * 68040 fixes by Martin Apel | ||
8 | * 68040 fixes and writeback by Richard Zidlicky | ||
9 | * 68060 fixes by Roman Hodek | ||
10 | * 68060 fixes by Jesper Skov | ||
11 | * | ||
12 | * This file is subject to the terms and conditions of the GNU General Public | ||
13 | * License. See the file COPYING in the main directory of this archive | ||
14 | * for more details. | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * Sets up all exception vectors | ||
19 | */ | ||
20 | |||
21 | #include <linux/sched.h> | ||
22 | #include <linux/signal.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/user.h> | ||
27 | #include <linux/string.h> | ||
28 | #include <linux/linkage.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/ptrace.h> | ||
31 | #include <linux/kallsyms.h> | ||
32 | |||
33 | #include <asm/setup.h> | ||
34 | #include <asm/fpu.h> | ||
35 | #include <asm/system.h> | ||
36 | #include <asm/uaccess.h> | ||
37 | #include <asm/traps.h> | ||
38 | #include <asm/pgalloc.h> | ||
39 | #include <asm/machdep.h> | ||
40 | #include <asm/siginfo.h> | ||
41 | |||
42 | /* assembler routines */ | ||
43 | asmlinkage void system_call(void); | ||
44 | asmlinkage void buserr(void); | ||
45 | asmlinkage void trap(void); | ||
46 | asmlinkage void nmihandler(void); | ||
47 | #ifdef CONFIG_M68KFPU_EMU | ||
48 | asmlinkage void fpu_emu(void); | ||
49 | #endif | ||
50 | |||
51 | e_vector vectors[256]; | ||
52 | |||
53 | /* nmi handler for the Amiga */ | ||
54 | asm(".text\n" | ||
55 | __ALIGN_STR "\n" | ||
56 | "nmihandler: rte"); | ||
57 | |||
58 | /* | ||
59 | * this must be called very early as the kernel might | ||
60 | * use some instruction that are emulated on the 060 | ||
61 | * and so we're prepared for early probe attempts (e.g. nf_init). | ||
62 | */ | ||
63 | void __init base_trap_init(void) | ||
64 | { | ||
65 | if (MACH_IS_SUN3X) { | ||
66 | extern e_vector *sun3x_prom_vbr; | ||
67 | |||
68 | __asm__ volatile ("movec %%vbr, %0" : "=r" (sun3x_prom_vbr)); | ||
69 | } | ||
70 | |||
71 | /* setup the exception vector table */ | ||
72 | __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors)); | ||
73 | |||
74 | if (CPU_IS_060) { | ||
75 | /* set up ISP entry points */ | ||
76 | asmlinkage void unimp_vec(void) asm ("_060_isp_unimp"); | ||
77 | |||
78 | vectors[VEC_UNIMPII] = unimp_vec; | ||
79 | } | ||
80 | |||
81 | vectors[VEC_BUSERR] = buserr; | ||
82 | vectors[VEC_ILLEGAL] = trap; | ||
83 | vectors[VEC_SYS] = system_call; | ||
84 | } | ||
85 | |||
86 | void __init trap_init (void) | ||
87 | { | ||
88 | int i; | ||
89 | |||
90 | for (i = VEC_SPUR; i <= VEC_INT7; i++) | ||
91 | vectors[i] = bad_inthandler; | ||
92 | |||
93 | for (i = 0; i < VEC_USER; i++) | ||
94 | if (!vectors[i]) | ||
95 | vectors[i] = trap; | ||
96 | |||
97 | for (i = VEC_USER; i < 256; i++) | ||
98 | vectors[i] = bad_inthandler; | ||
99 | |||
100 | #ifdef CONFIG_M68KFPU_EMU | ||
101 | if (FPU_IS_EMU) | ||
102 | vectors[VEC_LINE11] = fpu_emu; | ||
103 | #endif | ||
104 | |||
105 | if (CPU_IS_040 && !FPU_IS_EMU) { | ||
106 | /* set up FPSP entry points */ | ||
107 | asmlinkage void dz_vec(void) asm ("dz"); | ||
108 | asmlinkage void inex_vec(void) asm ("inex"); | ||
109 | asmlinkage void ovfl_vec(void) asm ("ovfl"); | ||
110 | asmlinkage void unfl_vec(void) asm ("unfl"); | ||
111 | asmlinkage void snan_vec(void) asm ("snan"); | ||
112 | asmlinkage void operr_vec(void) asm ("operr"); | ||
113 | asmlinkage void bsun_vec(void) asm ("bsun"); | ||
114 | asmlinkage void fline_vec(void) asm ("fline"); | ||
115 | asmlinkage void unsupp_vec(void) asm ("unsupp"); | ||
116 | |||
117 | vectors[VEC_FPDIVZ] = dz_vec; | ||
118 | vectors[VEC_FPIR] = inex_vec; | ||
119 | vectors[VEC_FPOVER] = ovfl_vec; | ||
120 | vectors[VEC_FPUNDER] = unfl_vec; | ||
121 | vectors[VEC_FPNAN] = snan_vec; | ||
122 | vectors[VEC_FPOE] = operr_vec; | ||
123 | vectors[VEC_FPBRUC] = bsun_vec; | ||
124 | vectors[VEC_LINE11] = fline_vec; | ||
125 | vectors[VEC_FPUNSUP] = unsupp_vec; | ||
126 | } | ||
127 | |||
128 | if (CPU_IS_060 && !FPU_IS_EMU) { | ||
129 | /* set up IFPSP entry points */ | ||
130 | asmlinkage void snan_vec6(void) asm ("_060_fpsp_snan"); | ||
131 | asmlinkage void operr_vec6(void) asm ("_060_fpsp_operr"); | ||
132 | asmlinkage void ovfl_vec6(void) asm ("_060_fpsp_ovfl"); | ||
133 | asmlinkage void unfl_vec6(void) asm ("_060_fpsp_unfl"); | ||
134 | asmlinkage void dz_vec6(void) asm ("_060_fpsp_dz"); | ||
135 | asmlinkage void inex_vec6(void) asm ("_060_fpsp_inex"); | ||
136 | asmlinkage void fline_vec6(void) asm ("_060_fpsp_fline"); | ||
137 | asmlinkage void unsupp_vec6(void) asm ("_060_fpsp_unsupp"); | ||
138 | asmlinkage void effadd_vec6(void) asm ("_060_fpsp_effadd"); | ||
139 | |||
140 | vectors[VEC_FPNAN] = snan_vec6; | ||
141 | vectors[VEC_FPOE] = operr_vec6; | ||
142 | vectors[VEC_FPOVER] = ovfl_vec6; | ||
143 | vectors[VEC_FPUNDER] = unfl_vec6; | ||
144 | vectors[VEC_FPDIVZ] = dz_vec6; | ||
145 | vectors[VEC_FPIR] = inex_vec6; | ||
146 | vectors[VEC_LINE11] = fline_vec6; | ||
147 | vectors[VEC_FPUNSUP] = unsupp_vec6; | ||
148 | vectors[VEC_UNIMPEA] = effadd_vec6; | ||
149 | } | ||
150 | |||
151 | /* if running on an amiga, make the NMI interrupt do nothing */ | ||
152 | if (MACH_IS_AMIGA) { | ||
153 | vectors[VEC_INT7] = nmihandler; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | |||
158 | static const char *vec_names[] = { | ||
159 | [VEC_RESETSP] = "RESET SP", | ||
160 | [VEC_RESETPC] = "RESET PC", | ||
161 | [VEC_BUSERR] = "BUS ERROR", | ||
162 | [VEC_ADDRERR] = "ADDRESS ERROR", | ||
163 | [VEC_ILLEGAL] = "ILLEGAL INSTRUCTION", | ||
164 | [VEC_ZERODIV] = "ZERO DIVIDE", | ||
165 | [VEC_CHK] = "CHK", | ||
166 | [VEC_TRAP] = "TRAPcc", | ||
167 | [VEC_PRIV] = "PRIVILEGE VIOLATION", | ||
168 | [VEC_TRACE] = "TRACE", | ||
169 | [VEC_LINE10] = "LINE 1010", | ||
170 | [VEC_LINE11] = "LINE 1111", | ||
171 | [VEC_RESV12] = "UNASSIGNED RESERVED 12", | ||
172 | [VEC_COPROC] = "COPROCESSOR PROTOCOL VIOLATION", | ||
173 | [VEC_FORMAT] = "FORMAT ERROR", | ||
174 | [VEC_UNINT] = "UNINITIALIZED INTERRUPT", | ||
175 | [VEC_RESV16] = "UNASSIGNED RESERVED 16", | ||
176 | [VEC_RESV17] = "UNASSIGNED RESERVED 17", | ||
177 | [VEC_RESV18] = "UNASSIGNED RESERVED 18", | ||
178 | [VEC_RESV19] = "UNASSIGNED RESERVED 19", | ||
179 | [VEC_RESV20] = "UNASSIGNED RESERVED 20", | ||
180 | [VEC_RESV21] = "UNASSIGNED RESERVED 21", | ||
181 | [VEC_RESV22] = "UNASSIGNED RESERVED 22", | ||
182 | [VEC_RESV23] = "UNASSIGNED RESERVED 23", | ||
183 | [VEC_SPUR] = "SPURIOUS INTERRUPT", | ||
184 | [VEC_INT1] = "LEVEL 1 INT", | ||
185 | [VEC_INT2] = "LEVEL 2 INT", | ||
186 | [VEC_INT3] = "LEVEL 3 INT", | ||
187 | [VEC_INT4] = "LEVEL 4 INT", | ||
188 | [VEC_INT5] = "LEVEL 5 INT", | ||
189 | [VEC_INT6] = "LEVEL 6 INT", | ||
190 | [VEC_INT7] = "LEVEL 7 INT", | ||
191 | [VEC_SYS] = "SYSCALL", | ||
192 | [VEC_TRAP1] = "TRAP #1", | ||
193 | [VEC_TRAP2] = "TRAP #2", | ||
194 | [VEC_TRAP3] = "TRAP #3", | ||
195 | [VEC_TRAP4] = "TRAP #4", | ||
196 | [VEC_TRAP5] = "TRAP #5", | ||
197 | [VEC_TRAP6] = "TRAP #6", | ||
198 | [VEC_TRAP7] = "TRAP #7", | ||
199 | [VEC_TRAP8] = "TRAP #8", | ||
200 | [VEC_TRAP9] = "TRAP #9", | ||
201 | [VEC_TRAP10] = "TRAP #10", | ||
202 | [VEC_TRAP11] = "TRAP #11", | ||
203 | [VEC_TRAP12] = "TRAP #12", | ||
204 | [VEC_TRAP13] = "TRAP #13", | ||
205 | [VEC_TRAP14] = "TRAP #14", | ||
206 | [VEC_TRAP15] = "TRAP #15", | ||
207 | [VEC_FPBRUC] = "FPCP BSUN", | ||
208 | [VEC_FPIR] = "FPCP INEXACT", | ||
209 | [VEC_FPDIVZ] = "FPCP DIV BY 0", | ||
210 | [VEC_FPUNDER] = "FPCP UNDERFLOW", | ||
211 | [VEC_FPOE] = "FPCP OPERAND ERROR", | ||
212 | [VEC_FPOVER] = "FPCP OVERFLOW", | ||
213 | [VEC_FPNAN] = "FPCP SNAN", | ||
214 | [VEC_FPUNSUP] = "FPCP UNSUPPORTED OPERATION", | ||
215 | [VEC_MMUCFG] = "MMU CONFIGURATION ERROR", | ||
216 | [VEC_MMUILL] = "MMU ILLEGAL OPERATION ERROR", | ||
217 | [VEC_MMUACC] = "MMU ACCESS LEVEL VIOLATION ERROR", | ||
218 | [VEC_RESV59] = "UNASSIGNED RESERVED 59", | ||
219 | [VEC_UNIMPEA] = "UNASSIGNED RESERVED 60", | ||
220 | [VEC_UNIMPII] = "UNASSIGNED RESERVED 61", | ||
221 | [VEC_RESV62] = "UNASSIGNED RESERVED 62", | ||
222 | [VEC_RESV63] = "UNASSIGNED RESERVED 63", | ||
223 | }; | ||
224 | |||
225 | static const char *space_names[] = { | ||
226 | [0] = "Space 0", | ||
227 | [USER_DATA] = "User Data", | ||
228 | [USER_PROGRAM] = "User Program", | ||
229 | #ifndef CONFIG_SUN3 | ||
230 | [3] = "Space 3", | ||
231 | #else | ||
232 | [FC_CONTROL] = "Control", | ||
233 | #endif | ||
234 | [4] = "Space 4", | ||
235 | [SUPER_DATA] = "Super Data", | ||
236 | [SUPER_PROGRAM] = "Super Program", | ||
237 | [CPU_SPACE] = "CPU" | ||
238 | }; | ||
239 | |||
240 | void die_if_kernel(char *,struct pt_regs *,int); | ||
241 | asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, | ||
242 | unsigned long error_code); | ||
243 | int send_fault_sig(struct pt_regs *regs); | ||
244 | |||
245 | asmlinkage void trap_c(struct frame *fp); | ||
246 | |||
247 | #if defined (CONFIG_M68060) | ||
248 | static inline void access_error060 (struct frame *fp) | ||
249 | { | ||
250 | unsigned long fslw = fp->un.fmt4.pc; /* is really FSLW for access error */ | ||
251 | |||
252 | #ifdef DEBUG | ||
253 | printk("fslw=%#lx, fa=%#lx\n", fslw, fp->un.fmt4.effaddr); | ||
254 | #endif | ||
255 | |||
256 | if (fslw & MMU060_BPE) { | ||
257 | /* branch prediction error -> clear branch cache */ | ||
258 | __asm__ __volatile__ ("movec %/cacr,%/d0\n\t" | ||
259 | "orl #0x00400000,%/d0\n\t" | ||
260 | "movec %/d0,%/cacr" | ||
261 | : : : "d0" ); | ||
262 | /* return if there's no other error */ | ||
263 | if (!(fslw & MMU060_ERR_BITS) && !(fslw & MMU060_SEE)) | ||
264 | return; | ||
265 | } | ||
266 | |||
267 | if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) { | ||
268 | unsigned long errorcode; | ||
269 | unsigned long addr = fp->un.fmt4.effaddr; | ||
270 | |||
271 | if (fslw & MMU060_MA) | ||
272 | addr = (addr + PAGE_SIZE - 1) & PAGE_MASK; | ||
273 | |||
274 | errorcode = 1; | ||
275 | if (fslw & MMU060_DESC_ERR) { | ||
276 | __flush_tlb040_one(addr); | ||
277 | errorcode = 0; | ||
278 | } | ||
279 | if (fslw & MMU060_W) | ||
280 | errorcode |= 2; | ||
281 | #ifdef DEBUG | ||
282 | printk("errorcode = %d\n", errorcode ); | ||
283 | #endif | ||
284 | do_page_fault(&fp->ptregs, addr, errorcode); | ||
285 | } else if (fslw & (MMU060_SEE)){ | ||
286 | /* Software Emulation Error. | ||
287 | * fault during mem_read/mem_write in ifpsp060/os.S | ||
288 | */ | ||
289 | send_fault_sig(&fp->ptregs); | ||
290 | } else if (!(fslw & (MMU060_RE|MMU060_WE)) || | ||
291 | send_fault_sig(&fp->ptregs) > 0) { | ||
292 | printk("pc=%#lx, fa=%#lx\n", fp->ptregs.pc, fp->un.fmt4.effaddr); | ||
293 | printk( "68060 access error, fslw=%lx\n", fslw ); | ||
294 | trap_c( fp ); | ||
295 | } | ||
296 | } | ||
297 | #endif /* CONFIG_M68060 */ | ||
298 | |||
299 | #if defined (CONFIG_M68040) | ||
300 | static inline unsigned long probe040(int iswrite, unsigned long addr, int wbs) | ||
301 | { | ||
302 | unsigned long mmusr; | ||
303 | mm_segment_t old_fs = get_fs(); | ||
304 | |||
305 | set_fs(MAKE_MM_SEG(wbs)); | ||
306 | |||
307 | if (iswrite) | ||
308 | asm volatile (".chip 68040; ptestw (%0); .chip 68k" : : "a" (addr)); | ||
309 | else | ||
310 | asm volatile (".chip 68040; ptestr (%0); .chip 68k" : : "a" (addr)); | ||
311 | |||
312 | asm volatile (".chip 68040; movec %%mmusr,%0; .chip 68k" : "=r" (mmusr)); | ||
313 | |||
314 | set_fs(old_fs); | ||
315 | |||
316 | return mmusr; | ||
317 | } | ||
318 | |||
319 | static inline int do_040writeback1(unsigned short wbs, unsigned long wba, | ||
320 | unsigned long wbd) | ||
321 | { | ||
322 | int res = 0; | ||
323 | mm_segment_t old_fs = get_fs(); | ||
324 | |||
325 | /* set_fs can not be moved, otherwise put_user() may oops */ | ||
326 | set_fs(MAKE_MM_SEG(wbs)); | ||
327 | |||
328 | switch (wbs & WBSIZ_040) { | ||
329 | case BA_SIZE_BYTE: | ||
330 | res = put_user(wbd & 0xff, (char __user *)wba); | ||
331 | break; | ||
332 | case BA_SIZE_WORD: | ||
333 | res = put_user(wbd & 0xffff, (short __user *)wba); | ||
334 | break; | ||
335 | case BA_SIZE_LONG: | ||
336 | res = put_user(wbd, (int __user *)wba); | ||
337 | break; | ||
338 | } | ||
339 | |||
340 | /* set_fs can not be moved, otherwise put_user() may oops */ | ||
341 | set_fs(old_fs); | ||
342 | |||
343 | |||
344 | #ifdef DEBUG | ||
345 | printk("do_040writeback1, res=%d\n",res); | ||
346 | #endif | ||
347 | |||
348 | return res; | ||
349 | } | ||
350 | |||
351 | /* after an exception in a writeback the stack frame corresponding | ||
352 | * to that exception is discarded, set a few bits in the old frame | ||
353 | * to simulate what it should look like | ||
354 | */ | ||
355 | static inline void fix_xframe040(struct frame *fp, unsigned long wba, unsigned short wbs) | ||
356 | { | ||
357 | fp->un.fmt7.faddr = wba; | ||
358 | fp->un.fmt7.ssw = wbs & 0xff; | ||
359 | if (wba != current->thread.faddr) | ||
360 | fp->un.fmt7.ssw |= MA_040; | ||
361 | } | ||
362 | |||
363 | static inline void do_040writebacks(struct frame *fp) | ||
364 | { | ||
365 | int res = 0; | ||
366 | #if 0 | ||
367 | if (fp->un.fmt7.wb1s & WBV_040) | ||
368 | printk("access_error040: cannot handle 1st writeback. oops.\n"); | ||
369 | #endif | ||
370 | |||
371 | if ((fp->un.fmt7.wb2s & WBV_040) && | ||
372 | !(fp->un.fmt7.wb2s & WBTT_040)) { | ||
373 | res = do_040writeback1(fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, | ||
374 | fp->un.fmt7.wb2d); | ||
375 | if (res) | ||
376 | fix_xframe040(fp, fp->un.fmt7.wb2a, fp->un.fmt7.wb2s); | ||
377 | else | ||
378 | fp->un.fmt7.wb2s = 0; | ||
379 | } | ||
380 | |||
381 | /* do the 2nd wb only if the first one was successful (except for a kernel wb) */ | ||
382 | if (fp->un.fmt7.wb3s & WBV_040 && (!res || fp->un.fmt7.wb3s & 4)) { | ||
383 | res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, | ||
384 | fp->un.fmt7.wb3d); | ||
385 | if (res) | ||
386 | { | ||
387 | fix_xframe040(fp, fp->un.fmt7.wb3a, fp->un.fmt7.wb3s); | ||
388 | |||
389 | fp->un.fmt7.wb2s = fp->un.fmt7.wb3s; | ||
390 | fp->un.fmt7.wb3s &= (~WBV_040); | ||
391 | fp->un.fmt7.wb2a = fp->un.fmt7.wb3a; | ||
392 | fp->un.fmt7.wb2d = fp->un.fmt7.wb3d; | ||
393 | } | ||
394 | else | ||
395 | fp->un.fmt7.wb3s = 0; | ||
396 | } | ||
397 | |||
398 | if (res) | ||
399 | send_fault_sig(&fp->ptregs); | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * called from sigreturn(), must ensure userspace code didn't | ||
404 | * manipulate exception frame to circumvent protection, then complete | ||
405 | * pending writebacks | ||
406 | * we just clear TM2 to turn it into a userspace access | ||
407 | */ | ||
408 | asmlinkage void berr_040cleanup(struct frame *fp) | ||
409 | { | ||
410 | fp->un.fmt7.wb2s &= ~4; | ||
411 | fp->un.fmt7.wb3s &= ~4; | ||
412 | |||
413 | do_040writebacks(fp); | ||
414 | } | ||
415 | |||
416 | static inline void access_error040(struct frame *fp) | ||
417 | { | ||
418 | unsigned short ssw = fp->un.fmt7.ssw; | ||
419 | unsigned long mmusr; | ||
420 | |||
421 | #ifdef DEBUG | ||
422 | printk("ssw=%#x, fa=%#lx\n", ssw, fp->un.fmt7.faddr); | ||
423 | printk("wb1s=%#x, wb2s=%#x, wb3s=%#x\n", fp->un.fmt7.wb1s, | ||
424 | fp->un.fmt7.wb2s, fp->un.fmt7.wb3s); | ||
425 | printk ("wb2a=%lx, wb3a=%lx, wb2d=%lx, wb3d=%lx\n", | ||
426 | fp->un.fmt7.wb2a, fp->un.fmt7.wb3a, | ||
427 | fp->un.fmt7.wb2d, fp->un.fmt7.wb3d); | ||
428 | #endif | ||
429 | |||
430 | if (ssw & ATC_040) { | ||
431 | unsigned long addr = fp->un.fmt7.faddr; | ||
432 | unsigned long errorcode; | ||
433 | |||
434 | /* | ||
435 | * The MMU status has to be determined AFTER the address | ||
436 | * has been corrected if there was a misaligned access (MA). | ||
437 | */ | ||
438 | if (ssw & MA_040) | ||
439 | addr = (addr + 7) & -8; | ||
440 | |||
441 | /* MMU error, get the MMUSR info for this access */ | ||
442 | mmusr = probe040(!(ssw & RW_040), addr, ssw); | ||
443 | #ifdef DEBUG | ||
444 | printk("mmusr = %lx\n", mmusr); | ||
445 | #endif | ||
446 | errorcode = 1; | ||
447 | if (!(mmusr & MMU_R_040)) { | ||
448 | /* clear the invalid atc entry */ | ||
449 | __flush_tlb040_one(addr); | ||
450 | errorcode = 0; | ||
451 | } | ||
452 | |||
453 | /* despite what documentation seems to say, RMW | ||
454 | * accesses have always both the LK and RW bits set */ | ||
455 | if (!(ssw & RW_040) || (ssw & LK_040)) | ||
456 | errorcode |= 2; | ||
457 | |||
458 | if (do_page_fault(&fp->ptregs, addr, errorcode)) { | ||
459 | #ifdef DEBUG | ||
460 | printk("do_page_fault() !=0\n"); | ||
461 | #endif | ||
462 | if (user_mode(&fp->ptregs)){ | ||
463 | /* delay writebacks after signal delivery */ | ||
464 | #ifdef DEBUG | ||
465 | printk(".. was usermode - return\n"); | ||
466 | #endif | ||
467 | return; | ||
468 | } | ||
469 | /* disable writeback into user space from kernel | ||
470 | * (if do_page_fault didn't fix the mapping, | ||
471 | * the writeback won't do good) | ||
472 | */ | ||
473 | disable_wb: | ||
474 | #ifdef DEBUG | ||
475 | printk(".. disabling wb2\n"); | ||
476 | #endif | ||
477 | if (fp->un.fmt7.wb2a == fp->un.fmt7.faddr) | ||
478 | fp->un.fmt7.wb2s &= ~WBV_040; | ||
479 | if (fp->un.fmt7.wb3a == fp->un.fmt7.faddr) | ||
480 | fp->un.fmt7.wb3s &= ~WBV_040; | ||
481 | } | ||
482 | } else { | ||
483 | /* In case of a bus error we either kill the process or expect | ||
484 | * the kernel to catch the fault, which then is also responsible | ||
485 | * for cleaning up the mess. | ||
486 | */ | ||
487 | current->thread.signo = SIGBUS; | ||
488 | current->thread.faddr = fp->un.fmt7.faddr; | ||
489 | if (send_fault_sig(&fp->ptregs) >= 0) | ||
490 | printk("68040 bus error (ssw=%x, faddr=%lx)\n", ssw, | ||
491 | fp->un.fmt7.faddr); | ||
492 | goto disable_wb; | ||
493 | } | ||
494 | |||
495 | do_040writebacks(fp); | ||
496 | } | ||
497 | #endif /* CONFIG_M68040 */ | ||
498 | |||
499 | #if defined(CONFIG_SUN3) | ||
500 | #include <asm/sun3mmu.h> | ||
501 | |||
502 | extern int mmu_emu_handle_fault (unsigned long, int, int); | ||
503 | |||
504 | /* sun3 version of bus_error030 */ | ||
505 | |||
506 | static inline void bus_error030 (struct frame *fp) | ||
507 | { | ||
508 | unsigned char buserr_type = sun3_get_buserr (); | ||
509 | unsigned long addr, errorcode; | ||
510 | unsigned short ssw = fp->un.fmtb.ssw; | ||
511 | extern unsigned long _sun3_map_test_start, _sun3_map_test_end; | ||
512 | |||
513 | #ifdef DEBUG | ||
514 | if (ssw & (FC | FB)) | ||
515 | printk ("Instruction fault at %#010lx\n", | ||
516 | ssw & FC ? | ||
517 | fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2 | ||
518 | : | ||
519 | fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); | ||
520 | if (ssw & DF) | ||
521 | printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
522 | ssw & RW ? "read" : "write", | ||
523 | fp->un.fmtb.daddr, | ||
524 | space_names[ssw & DFC], fp->ptregs.pc); | ||
525 | #endif | ||
526 | |||
527 | /* | ||
528 | * Check if this page should be demand-mapped. This needs to go before | ||
529 | * the testing for a bad kernel-space access (demand-mapping applies | ||
530 | * to kernel accesses too). | ||
531 | */ | ||
532 | |||
533 | if ((ssw & DF) | ||
534 | && (buserr_type & (SUN3_BUSERR_PROTERR | SUN3_BUSERR_INVALID))) { | ||
535 | if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 0)) | ||
536 | return; | ||
537 | } | ||
538 | |||
539 | /* Check for kernel-space pagefault (BAD). */ | ||
540 | if (fp->ptregs.sr & PS_S) { | ||
541 | /* kernel fault must be a data fault to user space */ | ||
542 | if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) { | ||
543 | // try checking the kernel mappings before surrender | ||
544 | if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 1)) | ||
545 | return; | ||
546 | /* instruction fault or kernel data fault! */ | ||
547 | if (ssw & (FC | FB)) | ||
548 | printk ("Instruction fault at %#010lx\n", | ||
549 | fp->ptregs.pc); | ||
550 | if (ssw & DF) { | ||
551 | /* was this fault incurred testing bus mappings? */ | ||
552 | if((fp->ptregs.pc >= (unsigned long)&_sun3_map_test_start) && | ||
553 | (fp->ptregs.pc <= (unsigned long)&_sun3_map_test_end)) { | ||
554 | send_fault_sig(&fp->ptregs); | ||
555 | return; | ||
556 | } | ||
557 | |||
558 | printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
559 | ssw & RW ? "read" : "write", | ||
560 | fp->un.fmtb.daddr, | ||
561 | space_names[ssw & DFC], fp->ptregs.pc); | ||
562 | } | ||
563 | printk ("BAD KERNEL BUSERR\n"); | ||
564 | |||
565 | die_if_kernel("Oops", &fp->ptregs,0); | ||
566 | force_sig(SIGKILL, current); | ||
567 | return; | ||
568 | } | ||
569 | } else { | ||
570 | /* user fault */ | ||
571 | if (!(ssw & (FC | FB)) && !(ssw & DF)) | ||
572 | /* not an instruction fault or data fault! BAD */ | ||
573 | panic ("USER BUSERR w/o instruction or data fault"); | ||
574 | } | ||
575 | |||
576 | |||
577 | /* First handle the data fault, if any. */ | ||
578 | if (ssw & DF) { | ||
579 | addr = fp->un.fmtb.daddr; | ||
580 | |||
581 | // errorcode bit 0: 0 -> no page 1 -> protection fault | ||
582 | // errorcode bit 1: 0 -> read fault 1 -> write fault | ||
583 | |||
584 | // (buserr_type & SUN3_BUSERR_PROTERR) -> protection fault | ||
585 | // (buserr_type & SUN3_BUSERR_INVALID) -> invalid page fault | ||
586 | |||
587 | if (buserr_type & SUN3_BUSERR_PROTERR) | ||
588 | errorcode = 0x01; | ||
589 | else if (buserr_type & SUN3_BUSERR_INVALID) | ||
590 | errorcode = 0x00; | ||
591 | else { | ||
592 | #ifdef DEBUG | ||
593 | printk ("*** unexpected busfault type=%#04x\n", buserr_type); | ||
594 | printk ("invalid %s access at %#lx from pc %#lx\n", | ||
595 | !(ssw & RW) ? "write" : "read", addr, | ||
596 | fp->ptregs.pc); | ||
597 | #endif | ||
598 | die_if_kernel ("Oops", &fp->ptregs, buserr_type); | ||
599 | force_sig (SIGBUS, current); | ||
600 | return; | ||
601 | } | ||
602 | |||
603 | //todo: wtf is RM bit? --m | ||
604 | if (!(ssw & RW) || ssw & RM) | ||
605 | errorcode |= 0x02; | ||
606 | |||
607 | /* Handle page fault. */ | ||
608 | do_page_fault (&fp->ptregs, addr, errorcode); | ||
609 | |||
610 | /* Retry the data fault now. */ | ||
611 | return; | ||
612 | } | ||
613 | |||
614 | /* Now handle the instruction fault. */ | ||
615 | |||
616 | /* Get the fault address. */ | ||
617 | if (fp->ptregs.format == 0xA) | ||
618 | addr = fp->ptregs.pc + 4; | ||
619 | else | ||
620 | addr = fp->un.fmtb.baddr; | ||
621 | if (ssw & FC) | ||
622 | addr -= 2; | ||
623 | |||
624 | if (buserr_type & SUN3_BUSERR_INVALID) { | ||
625 | if (!mmu_emu_handle_fault (fp->un.fmtb.daddr, 1, 0)) | ||
626 | do_page_fault (&fp->ptregs, addr, 0); | ||
627 | } else { | ||
628 | #ifdef DEBUG | ||
629 | printk ("protection fault on insn access (segv).\n"); | ||
630 | #endif | ||
631 | force_sig (SIGSEGV, current); | ||
632 | } | ||
633 | } | ||
634 | #else | ||
635 | #if defined(CPU_M68020_OR_M68030) | ||
636 | static inline void bus_error030 (struct frame *fp) | ||
637 | { | ||
638 | volatile unsigned short temp; | ||
639 | unsigned short mmusr; | ||
640 | unsigned long addr, errorcode; | ||
641 | unsigned short ssw = fp->un.fmtb.ssw; | ||
642 | #ifdef DEBUG | ||
643 | unsigned long desc; | ||
644 | |||
645 | printk ("pid = %x ", current->pid); | ||
646 | printk ("SSW=%#06x ", ssw); | ||
647 | |||
648 | if (ssw & (FC | FB)) | ||
649 | printk ("Instruction fault at %#010lx\n", | ||
650 | ssw & FC ? | ||
651 | fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2 | ||
652 | : | ||
653 | fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); | ||
654 | if (ssw & DF) | ||
655 | printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
656 | ssw & RW ? "read" : "write", | ||
657 | fp->un.fmtb.daddr, | ||
658 | space_names[ssw & DFC], fp->ptregs.pc); | ||
659 | #endif | ||
660 | |||
661 | /* ++andreas: If a data fault and an instruction fault happen | ||
662 | at the same time map in both pages. */ | ||
663 | |||
664 | /* First handle the data fault, if any. */ | ||
665 | if (ssw & DF) { | ||
666 | addr = fp->un.fmtb.daddr; | ||
667 | |||
668 | #ifdef DEBUG | ||
669 | asm volatile ("ptestr %3,%2@,#7,%0\n\t" | ||
670 | "pmove %%psr,%1@" | ||
671 | : "=a&" (desc) | ||
672 | : "a" (&temp), "a" (addr), "d" (ssw)); | ||
673 | #else | ||
674 | asm volatile ("ptestr %2,%1@,#7\n\t" | ||
675 | "pmove %%psr,%0@" | ||
676 | : : "a" (&temp), "a" (addr), "d" (ssw)); | ||
677 | #endif | ||
678 | mmusr = temp; | ||
679 | |||
680 | #ifdef DEBUG | ||
681 | printk("mmusr is %#x for addr %#lx in task %p\n", | ||
682 | mmusr, addr, current); | ||
683 | printk("descriptor address is %#lx, contents %#lx\n", | ||
684 | __va(desc), *(unsigned long *)__va(desc)); | ||
685 | #endif | ||
686 | |||
687 | errorcode = (mmusr & MMU_I) ? 0 : 1; | ||
688 | if (!(ssw & RW) || (ssw & RM)) | ||
689 | errorcode |= 2; | ||
690 | |||
691 | if (mmusr & (MMU_I | MMU_WP)) { | ||
692 | if (ssw & 4) { | ||
693 | printk("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
694 | ssw & RW ? "read" : "write", | ||
695 | fp->un.fmtb.daddr, | ||
696 | space_names[ssw & DFC], fp->ptregs.pc); | ||
697 | goto buserr; | ||
698 | } | ||
699 | /* Don't try to do anything further if an exception was | ||
700 | handled. */ | ||
701 | if (do_page_fault (&fp->ptregs, addr, errorcode) < 0) | ||
702 | return; | ||
703 | } else if (!(mmusr & MMU_I)) { | ||
704 | /* probably a 020 cas fault */ | ||
705 | if (!(ssw & RM) && send_fault_sig(&fp->ptregs) > 0) | ||
706 | printk("unexpected bus error (%#x,%#x)\n", ssw, mmusr); | ||
707 | } else if (mmusr & (MMU_B|MMU_L|MMU_S)) { | ||
708 | printk("invalid %s access at %#lx from pc %#lx\n", | ||
709 | !(ssw & RW) ? "write" : "read", addr, | ||
710 | fp->ptregs.pc); | ||
711 | die_if_kernel("Oops",&fp->ptregs,mmusr); | ||
712 | force_sig(SIGSEGV, current); | ||
713 | return; | ||
714 | } else { | ||
715 | #if 0 | ||
716 | static volatile long tlong; | ||
717 | #endif | ||
718 | |||
719 | printk("weird %s access at %#lx from pc %#lx (ssw is %#x)\n", | ||
720 | !(ssw & RW) ? "write" : "read", addr, | ||
721 | fp->ptregs.pc, ssw); | ||
722 | asm volatile ("ptestr #1,%1@,#0\n\t" | ||
723 | "pmove %%psr,%0@" | ||
724 | : /* no outputs */ | ||
725 | : "a" (&temp), "a" (addr)); | ||
726 | mmusr = temp; | ||
727 | |||
728 | printk ("level 0 mmusr is %#x\n", mmusr); | ||
729 | #if 0 | ||
730 | asm volatile ("pmove %%tt0,%0@" | ||
731 | : /* no outputs */ | ||
732 | : "a" (&tlong)); | ||
733 | printk("tt0 is %#lx, ", tlong); | ||
734 | asm volatile ("pmove %%tt1,%0@" | ||
735 | : /* no outputs */ | ||
736 | : "a" (&tlong)); | ||
737 | printk("tt1 is %#lx\n", tlong); | ||
738 | #endif | ||
739 | #ifdef DEBUG | ||
740 | printk("Unknown SIGSEGV - 1\n"); | ||
741 | #endif | ||
742 | die_if_kernel("Oops",&fp->ptregs,mmusr); | ||
743 | force_sig(SIGSEGV, current); | ||
744 | return; | ||
745 | } | ||
746 | |||
747 | /* setup an ATC entry for the access about to be retried */ | ||
748 | if (!(ssw & RW) || (ssw & RM)) | ||
749 | asm volatile ("ploadw %1,%0@" : /* no outputs */ | ||
750 | : "a" (addr), "d" (ssw)); | ||
751 | else | ||
752 | asm volatile ("ploadr %1,%0@" : /* no outputs */ | ||
753 | : "a" (addr), "d" (ssw)); | ||
754 | } | ||
755 | |||
756 | /* Now handle the instruction fault. */ | ||
757 | |||
758 | if (!(ssw & (FC|FB))) | ||
759 | return; | ||
760 | |||
761 | if (fp->ptregs.sr & PS_S) { | ||
762 | printk("Instruction fault at %#010lx\n", | ||
763 | fp->ptregs.pc); | ||
764 | buserr: | ||
765 | printk ("BAD KERNEL BUSERR\n"); | ||
766 | die_if_kernel("Oops",&fp->ptregs,0); | ||
767 | force_sig(SIGKILL, current); | ||
768 | return; | ||
769 | } | ||
770 | |||
771 | /* get the fault address */ | ||
772 | if (fp->ptregs.format == 10) | ||
773 | addr = fp->ptregs.pc + 4; | ||
774 | else | ||
775 | addr = fp->un.fmtb.baddr; | ||
776 | if (ssw & FC) | ||
777 | addr -= 2; | ||
778 | |||
779 | if ((ssw & DF) && ((addr ^ fp->un.fmtb.daddr) & PAGE_MASK) == 0) | ||
780 | /* Insn fault on same page as data fault. But we | ||
781 | should still create the ATC entry. */ | ||
782 | goto create_atc_entry; | ||
783 | |||
784 | #ifdef DEBUG | ||
785 | asm volatile ("ptestr #1,%2@,#7,%0\n\t" | ||
786 | "pmove %%psr,%1@" | ||
787 | : "=a&" (desc) | ||
788 | : "a" (&temp), "a" (addr)); | ||
789 | #else | ||
790 | asm volatile ("ptestr #1,%1@,#7\n\t" | ||
791 | "pmove %%psr,%0@" | ||
792 | : : "a" (&temp), "a" (addr)); | ||
793 | #endif | ||
794 | mmusr = temp; | ||
795 | |||
796 | #ifdef DEBUG | ||
797 | printk ("mmusr is %#x for addr %#lx in task %p\n", | ||
798 | mmusr, addr, current); | ||
799 | printk ("descriptor address is %#lx, contents %#lx\n", | ||
800 | __va(desc), *(unsigned long *)__va(desc)); | ||
801 | #endif | ||
802 | |||
803 | if (mmusr & MMU_I) | ||
804 | do_page_fault (&fp->ptregs, addr, 0); | ||
805 | else if (mmusr & (MMU_B|MMU_L|MMU_S)) { | ||
806 | printk ("invalid insn access at %#lx from pc %#lx\n", | ||
807 | addr, fp->ptregs.pc); | ||
808 | #ifdef DEBUG | ||
809 | printk("Unknown SIGSEGV - 2\n"); | ||
810 | #endif | ||
811 | die_if_kernel("Oops",&fp->ptregs,mmusr); | ||
812 | force_sig(SIGSEGV, current); | ||
813 | return; | ||
814 | } | ||
815 | |||
816 | create_atc_entry: | ||
817 | /* setup an ATC entry for the access about to be retried */ | ||
818 | asm volatile ("ploadr #2,%0@" : /* no outputs */ | ||
819 | : "a" (addr)); | ||
820 | } | ||
821 | #endif /* CPU_M68020_OR_M68030 */ | ||
822 | #endif /* !CONFIG_SUN3 */ | ||
823 | |||
824 | asmlinkage void buserr_c(struct frame *fp) | ||
825 | { | ||
826 | /* Only set esp0 if coming from user mode */ | ||
827 | if (user_mode(&fp->ptregs)) | ||
828 | current->thread.esp0 = (unsigned long) fp; | ||
829 | |||
830 | #ifdef DEBUG | ||
831 | printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format); | ||
832 | #endif | ||
833 | |||
834 | switch (fp->ptregs.format) { | ||
835 | #if defined (CONFIG_M68060) | ||
836 | case 4: /* 68060 access error */ | ||
837 | access_error060 (fp); | ||
838 | break; | ||
839 | #endif | ||
840 | #if defined (CONFIG_M68040) | ||
841 | case 0x7: /* 68040 access error */ | ||
842 | access_error040 (fp); | ||
843 | break; | ||
844 | #endif | ||
845 | #if defined (CPU_M68020_OR_M68030) | ||
846 | case 0xa: | ||
847 | case 0xb: | ||
848 | bus_error030 (fp); | ||
849 | break; | ||
850 | #endif | ||
851 | default: | ||
852 | die_if_kernel("bad frame format",&fp->ptregs,0); | ||
853 | #ifdef DEBUG | ||
854 | printk("Unknown SIGSEGV - 4\n"); | ||
855 | #endif | ||
856 | force_sig(SIGSEGV, current); | ||
857 | } | ||
858 | } | ||
859 | |||
860 | |||
861 | static int kstack_depth_to_print = 48; | ||
862 | |||
863 | void show_trace(unsigned long *stack) | ||
864 | { | ||
865 | unsigned long *endstack; | ||
866 | unsigned long addr; | ||
867 | int i; | ||
868 | |||
869 | printk("Call Trace:"); | ||
870 | addr = (unsigned long)stack + THREAD_SIZE - 1; | ||
871 | endstack = (unsigned long *)(addr & -THREAD_SIZE); | ||
872 | i = 0; | ||
873 | while (stack + 1 <= endstack) { | ||
874 | addr = *stack++; | ||
875 | /* | ||
876 | * If the address is either in the text segment of the | ||
877 | * kernel, or in the region which contains vmalloc'ed | ||
878 | * memory, it *may* be the address of a calling | ||
879 | * routine; if so, print it so that someone tracing | ||
880 | * down the cause of the crash will be able to figure | ||
881 | * out the call path that was taken. | ||
882 | */ | ||
883 | if (__kernel_text_address(addr)) { | ||
884 | #ifndef CONFIG_KALLSYMS | ||
885 | if (i % 5 == 0) | ||
886 | printk("\n "); | ||
887 | #endif | ||
888 | printk(" [<%08lx>] %pS\n", addr, (void *)addr); | ||
889 | i++; | ||
890 | } | ||
891 | } | ||
892 | printk("\n"); | ||
893 | } | ||
894 | |||
895 | void show_registers(struct pt_regs *regs) | ||
896 | { | ||
897 | struct frame *fp = (struct frame *)regs; | ||
898 | mm_segment_t old_fs = get_fs(); | ||
899 | u16 c, *cp; | ||
900 | unsigned long addr; | ||
901 | int i; | ||
902 | |||
903 | print_modules(); | ||
904 | printk("PC: [<%08lx>] %pS\n", regs->pc, (void *)regs->pc); | ||
905 | printk("SR: %04x SP: %p a2: %08lx\n", regs->sr, regs, regs->a2); | ||
906 | printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", | ||
907 | regs->d0, regs->d1, regs->d2, regs->d3); | ||
908 | printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", | ||
909 | regs->d4, regs->d5, regs->a0, regs->a1); | ||
910 | |||
911 | printk("Process %s (pid: %d, task=%p)\n", | ||
912 | current->comm, task_pid_nr(current), current); | ||
913 | addr = (unsigned long)&fp->un; | ||
914 | printk("Frame format=%X ", regs->format); | ||
915 | switch (regs->format) { | ||
916 | case 0x2: | ||
917 | printk("instr addr=%08lx\n", fp->un.fmt2.iaddr); | ||
918 | addr += sizeof(fp->un.fmt2); | ||
919 | break; | ||
920 | case 0x3: | ||
921 | printk("eff addr=%08lx\n", fp->un.fmt3.effaddr); | ||
922 | addr += sizeof(fp->un.fmt3); | ||
923 | break; | ||
924 | case 0x4: | ||
925 | printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n" | ||
926 | : "eff addr=%08lx pc=%08lx\n"), | ||
927 | fp->un.fmt4.effaddr, fp->un.fmt4.pc); | ||
928 | addr += sizeof(fp->un.fmt4); | ||
929 | break; | ||
930 | case 0x7: | ||
931 | printk("eff addr=%08lx ssw=%04x faddr=%08lx\n", | ||
932 | fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr); | ||
933 | printk("wb 1 stat/addr/data: %04x %08lx %08lx\n", | ||
934 | fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0); | ||
935 | printk("wb 2 stat/addr/data: %04x %08lx %08lx\n", | ||
936 | fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d); | ||
937 | printk("wb 3 stat/addr/data: %04x %08lx %08lx\n", | ||
938 | fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d); | ||
939 | printk("push data: %08lx %08lx %08lx %08lx\n", | ||
940 | fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2, | ||
941 | fp->un.fmt7.pd3); | ||
942 | addr += sizeof(fp->un.fmt7); | ||
943 | break; | ||
944 | case 0x9: | ||
945 | printk("instr addr=%08lx\n", fp->un.fmt9.iaddr); | ||
946 | addr += sizeof(fp->un.fmt9); | ||
947 | break; | ||
948 | case 0xa: | ||
949 | printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n", | ||
950 | fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb, | ||
951 | fp->un.fmta.daddr, fp->un.fmta.dobuf); | ||
952 | addr += sizeof(fp->un.fmta); | ||
953 | break; | ||
954 | case 0xb: | ||
955 | printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n", | ||
956 | fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb, | ||
957 | fp->un.fmtb.daddr, fp->un.fmtb.dobuf); | ||
958 | printk("baddr=%08lx dibuf=%08lx ver=%x\n", | ||
959 | fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver); | ||
960 | addr += sizeof(fp->un.fmtb); | ||
961 | break; | ||
962 | default: | ||
963 | printk("\n"); | ||
964 | } | ||
965 | show_stack(NULL, (unsigned long *)addr); | ||
966 | |||
967 | printk("Code:"); | ||
968 | set_fs(KERNEL_DS); | ||
969 | cp = (u16 *)regs->pc; | ||
970 | for (i = -8; i < 16; i++) { | ||
971 | if (get_user(c, cp + i) && i >= 0) { | ||
972 | printk(" Bad PC value."); | ||
973 | break; | ||
974 | } | ||
975 | printk(i ? " %04x" : " <%04x>", c); | ||
976 | } | ||
977 | set_fs(old_fs); | ||
978 | printk ("\n"); | ||
979 | } | ||
980 | |||
981 | void show_stack(struct task_struct *task, unsigned long *stack) | ||
982 | { | ||
983 | unsigned long *p; | ||
984 | unsigned long *endstack; | ||
985 | int i; | ||
986 | |||
987 | if (!stack) { | ||
988 | if (task) | ||
989 | stack = (unsigned long *)task->thread.esp0; | ||
990 | else | ||
991 | stack = (unsigned long *)&stack; | ||
992 | } | ||
993 | endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE); | ||
994 | |||
995 | printk("Stack from %08lx:", (unsigned long)stack); | ||
996 | p = stack; | ||
997 | for (i = 0; i < kstack_depth_to_print; i++) { | ||
998 | if (p + 1 > endstack) | ||
999 | break; | ||
1000 | if (i % 8 == 0) | ||
1001 | printk("\n "); | ||
1002 | printk(" %08lx", *p++); | ||
1003 | } | ||
1004 | printk("\n"); | ||
1005 | show_trace(stack); | ||
1006 | } | ||
1007 | |||
1008 | /* | ||
1009 | * The architecture-independent backtrace generator | ||
1010 | */ | ||
1011 | void dump_stack(void) | ||
1012 | { | ||
1013 | unsigned long stack; | ||
1014 | |||
1015 | show_trace(&stack); | ||
1016 | } | ||
1017 | |||
1018 | EXPORT_SYMBOL(dump_stack); | ||
1019 | |||
1020 | void bad_super_trap (struct frame *fp) | ||
1021 | { | ||
1022 | console_verbose(); | ||
1023 | if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names)) | ||
1024 | printk ("*** %s *** FORMAT=%X\n", | ||
1025 | vec_names[(fp->ptregs.vector) >> 2], | ||
1026 | fp->ptregs.format); | ||
1027 | else | ||
1028 | printk ("*** Exception %d *** FORMAT=%X\n", | ||
1029 | (fp->ptregs.vector) >> 2, | ||
1030 | fp->ptregs.format); | ||
1031 | if (fp->ptregs.vector >> 2 == VEC_ADDRERR && CPU_IS_020_OR_030) { | ||
1032 | unsigned short ssw = fp->un.fmtb.ssw; | ||
1033 | |||
1034 | printk ("SSW=%#06x ", ssw); | ||
1035 | |||
1036 | if (ssw & RC) | ||
1037 | printk ("Pipe stage C instruction fault at %#010lx\n", | ||
1038 | (fp->ptregs.format) == 0xA ? | ||
1039 | fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2); | ||
1040 | if (ssw & RB) | ||
1041 | printk ("Pipe stage B instruction fault at %#010lx\n", | ||
1042 | (fp->ptregs.format) == 0xA ? | ||
1043 | fp->ptregs.pc + 4 : fp->un.fmtb.baddr); | ||
1044 | if (ssw & DF) | ||
1045 | printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
1046 | ssw & RW ? "read" : "write", | ||
1047 | fp->un.fmtb.daddr, space_names[ssw & DFC], | ||
1048 | fp->ptregs.pc); | ||
1049 | } | ||
1050 | printk ("Current process id is %d\n", task_pid_nr(current)); | ||
1051 | die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); | ||
1052 | } | ||
1053 | |||
1054 | asmlinkage void trap_c(struct frame *fp) | ||
1055 | { | ||
1056 | int sig; | ||
1057 | siginfo_t info; | ||
1058 | |||
1059 | if (fp->ptregs.sr & PS_S) { | ||
1060 | if (fp->ptregs.vector == VEC_TRACE << 2) { | ||
1061 | /* traced a trapping instruction on a 68020/30, | ||
1062 | * real exception will be executed afterwards. | ||
1063 | */ | ||
1064 | } else if (!handle_kernel_fault(&fp->ptregs)) | ||
1065 | bad_super_trap(fp); | ||
1066 | return; | ||
1067 | } | ||
1068 | |||
1069 | /* send the appropriate signal to the user program */ | ||
1070 | switch ((fp->ptregs.vector) >> 2) { | ||
1071 | case VEC_ADDRERR: | ||
1072 | info.si_code = BUS_ADRALN; | ||
1073 | sig = SIGBUS; | ||
1074 | break; | ||
1075 | case VEC_ILLEGAL: | ||
1076 | case VEC_LINE10: | ||
1077 | case VEC_LINE11: | ||
1078 | info.si_code = ILL_ILLOPC; | ||
1079 | sig = SIGILL; | ||
1080 | break; | ||
1081 | case VEC_PRIV: | ||
1082 | info.si_code = ILL_PRVOPC; | ||
1083 | sig = SIGILL; | ||
1084 | break; | ||
1085 | case VEC_COPROC: | ||
1086 | info.si_code = ILL_COPROC; | ||
1087 | sig = SIGILL; | ||
1088 | break; | ||
1089 | case VEC_TRAP1: | ||
1090 | case VEC_TRAP2: | ||
1091 | case VEC_TRAP3: | ||
1092 | case VEC_TRAP4: | ||
1093 | case VEC_TRAP5: | ||
1094 | case VEC_TRAP6: | ||
1095 | case VEC_TRAP7: | ||
1096 | case VEC_TRAP8: | ||
1097 | case VEC_TRAP9: | ||
1098 | case VEC_TRAP10: | ||
1099 | case VEC_TRAP11: | ||
1100 | case VEC_TRAP12: | ||
1101 | case VEC_TRAP13: | ||
1102 | case VEC_TRAP14: | ||
1103 | info.si_code = ILL_ILLTRP; | ||
1104 | sig = SIGILL; | ||
1105 | break; | ||
1106 | case VEC_FPBRUC: | ||
1107 | case VEC_FPOE: | ||
1108 | case VEC_FPNAN: | ||
1109 | info.si_code = FPE_FLTINV; | ||
1110 | sig = SIGFPE; | ||
1111 | break; | ||
1112 | case VEC_FPIR: | ||
1113 | info.si_code = FPE_FLTRES; | ||
1114 | sig = SIGFPE; | ||
1115 | break; | ||
1116 | case VEC_FPDIVZ: | ||
1117 | info.si_code = FPE_FLTDIV; | ||
1118 | sig = SIGFPE; | ||
1119 | break; | ||
1120 | case VEC_FPUNDER: | ||
1121 | info.si_code = FPE_FLTUND; | ||
1122 | sig = SIGFPE; | ||
1123 | break; | ||
1124 | case VEC_FPOVER: | ||
1125 | info.si_code = FPE_FLTOVF; | ||
1126 | sig = SIGFPE; | ||
1127 | break; | ||
1128 | case VEC_ZERODIV: | ||
1129 | info.si_code = FPE_INTDIV; | ||
1130 | sig = SIGFPE; | ||
1131 | break; | ||
1132 | case VEC_CHK: | ||
1133 | case VEC_TRAP: | ||
1134 | info.si_code = FPE_INTOVF; | ||
1135 | sig = SIGFPE; | ||
1136 | break; | ||
1137 | case VEC_TRACE: /* ptrace single step */ | ||
1138 | info.si_code = TRAP_TRACE; | ||
1139 | sig = SIGTRAP; | ||
1140 | break; | ||
1141 | case VEC_TRAP15: /* breakpoint */ | ||
1142 | info.si_code = TRAP_BRKPT; | ||
1143 | sig = SIGTRAP; | ||
1144 | break; | ||
1145 | default: | ||
1146 | info.si_code = ILL_ILLOPC; | ||
1147 | sig = SIGILL; | ||
1148 | break; | ||
1149 | } | ||
1150 | info.si_signo = sig; | ||
1151 | info.si_errno = 0; | ||
1152 | switch (fp->ptregs.format) { | ||
1153 | default: | ||
1154 | info.si_addr = (void *) fp->ptregs.pc; | ||
1155 | break; | ||
1156 | case 2: | ||
1157 | info.si_addr = (void *) fp->un.fmt2.iaddr; | ||
1158 | break; | ||
1159 | case 7: | ||
1160 | info.si_addr = (void *) fp->un.fmt7.effaddr; | ||
1161 | break; | ||
1162 | case 9: | ||
1163 | info.si_addr = (void *) fp->un.fmt9.iaddr; | ||
1164 | break; | ||
1165 | case 10: | ||
1166 | info.si_addr = (void *) fp->un.fmta.daddr; | ||
1167 | break; | ||
1168 | case 11: | ||
1169 | info.si_addr = (void *) fp->un.fmtb.daddr; | ||
1170 | break; | ||
1171 | } | ||
1172 | force_sig_info (sig, &info, current); | ||
1173 | } | ||
1174 | |||
1175 | void die_if_kernel (char *str, struct pt_regs *fp, int nr) | ||
1176 | { | ||
1177 | if (!(fp->sr & PS_S)) | ||
1178 | return; | ||
1179 | |||
1180 | console_verbose(); | ||
1181 | printk("%s: %08x\n",str,nr); | ||
1182 | show_registers(fp); | ||
1183 | add_taint(TAINT_DIE); | ||
1184 | do_exit(SIGSEGV); | ||
1185 | } | ||
1186 | |||
1187 | /* | ||
1188 | * This function is called if an error occur while accessing | ||
1189 | * user-space from the fpsp040 code. | ||
1190 | */ | ||
1191 | asmlinkage void fpsp040_die(void) | ||
1192 | { | ||
1193 | do_exit(SIGSEGV); | ||
1194 | } | ||
1195 | |||
1196 | #ifdef CONFIG_M68KFPU_EMU | ||
1197 | asmlinkage void fpemu_signal(int signal, int code, void *addr) | ||
1198 | { | ||
1199 | siginfo_t info; | ||
1200 | |||
1201 | info.si_signo = signal; | ||
1202 | info.si_errno = 0; | ||
1203 | info.si_code = code; | ||
1204 | info.si_addr = addr; | ||
1205 | force_sig_info(signal, &info, current); | ||
1206 | } | ||
1207 | #endif | ||
diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68k/kernel/traps_no.c index a768008dfd06..a768008dfd06 100644 --- a/arch/m68knommu/kernel/traps.c +++ b/arch/m68k/kernel/traps_no.c | |||
diff --git a/arch/m68k/kernel/vmlinux.lds.S b/arch/m68k/kernel/vmlinux.lds.S index 99ba315bd0a8..030dabf0bc53 100644 --- a/arch/m68k/kernel/vmlinux.lds.S +++ b/arch/m68k/kernel/vmlinux.lds.S | |||
@@ -1,10 +1,5 @@ | |||
1 | PHDRS | 1 | #ifdef CONFIG_MMU |
2 | { | 2 | #include "vmlinux.lds_mm.S" |
3 | text PT_LOAD FILEHDR PHDRS FLAGS (7); | ||
4 | data PT_LOAD FLAGS (7); | ||
5 | } | ||
6 | #ifdef CONFIG_SUN3 | ||
7 | #include "vmlinux-sun3.lds" | ||
8 | #else | 3 | #else |
9 | #include "vmlinux-std.lds" | 4 | #include "vmlinux.lds_no.S" |
10 | #endif | 5 | #endif |
diff --git a/arch/m68k/kernel/vmlinux.lds_mm.S b/arch/m68k/kernel/vmlinux.lds_mm.S new file mode 100644 index 000000000000..99ba315bd0a8 --- /dev/null +++ b/arch/m68k/kernel/vmlinux.lds_mm.S | |||
@@ -0,0 +1,10 @@ | |||
1 | PHDRS | ||
2 | { | ||
3 | text PT_LOAD FILEHDR PHDRS FLAGS (7); | ||
4 | data PT_LOAD FLAGS (7); | ||
5 | } | ||
6 | #ifdef CONFIG_SUN3 | ||
7 | #include "vmlinux-sun3.lds" | ||
8 | #else | ||
9 | #include "vmlinux-std.lds" | ||
10 | #endif | ||
diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68k/kernel/vmlinux.lds_no.S index 47e15ebfd893..47e15ebfd893 100644 --- a/arch/m68knommu/kernel/vmlinux.lds.S +++ b/arch/m68k/kernel/vmlinux.lds_no.S | |||
diff --git a/arch/m68k/lib/Makefile b/arch/m68k/lib/Makefile index af9abf8d9d98..1f95881d8437 100644 --- a/arch/m68k/lib/Makefile +++ b/arch/m68k/lib/Makefile | |||
@@ -1,6 +1,5 @@ | |||
1 | # | 1 | ifdef CONFIG_MMU |
2 | # Makefile for m68k-specific library files.. | 2 | include arch/m68k/lib/Makefile_mm |
3 | # | 3 | else |
4 | 4 | include arch/m68k/lib/Makefile_no | |
5 | lib-y := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ | 5 | endif |
6 | checksum.o string.o uaccess.o | ||
diff --git a/arch/m68k/lib/Makefile_mm b/arch/m68k/lib/Makefile_mm new file mode 100644 index 000000000000..af9abf8d9d98 --- /dev/null +++ b/arch/m68k/lib/Makefile_mm | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for m68k-specific library files.. | ||
3 | # | ||
4 | |||
5 | lib-y := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ | ||
6 | checksum.o string.o uaccess.o | ||
diff --git a/arch/m68knommu/lib/Makefile b/arch/m68k/lib/Makefile_no index 32d852e586d7..32d852e586d7 100644 --- a/arch/m68knommu/lib/Makefile +++ b/arch/m68k/lib/Makefile_no | |||
diff --git a/arch/m68k/lib/checksum.c b/arch/m68k/lib/checksum.c index 6216f12a756b..1297536060de 100644 --- a/arch/m68k/lib/checksum.c +++ b/arch/m68k/lib/checksum.c | |||
@@ -1,425 +1,5 @@ | |||
1 | /* | 1 | #ifdef CONFIG_MMU |
2 | * INET An implementation of the TCP/IP protocol suite for the LINUX | 2 | #include "checksum_mm.c" |
3 | * operating system. INET is implemented using the BSD Socket | 3 | #else |
4 | * interface as the means of communication with the user level. | 4 | #include "checksum_no.c" |
5 | * | 5 | #endif |
6 | * IP/TCP/UDP checksumming routines | ||
7 | * | ||
8 | * Authors: Jorge Cwik, <jorge@laser.satlink.net> | ||
9 | * Arnt Gulbrandsen, <agulbra@nvg.unit.no> | ||
10 | * Tom May, <ftom@netcom.com> | ||
11 | * Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de> | ||
12 | * Lots of code moved from tcp.c and ip.c; see those files | ||
13 | * for more names. | ||
14 | * | ||
15 | * 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek: | ||
16 | * Fixed some nasty bugs, causing some horrible crashes. | ||
17 | * A: At some points, the sum (%0) was used as | ||
18 | * length-counter instead of the length counter | ||
19 | * (%1). Thanks to Roman Hodek for pointing this out. | ||
20 | * B: GCC seems to mess up if one uses too many | ||
21 | * data-registers to hold input values and one tries to | ||
22 | * specify d0 and d1 as scratch registers. Letting gcc | ||
23 | * choose these registers itself solves the problem. | ||
24 | * | ||
25 | * This program is free software; you can redistribute it and/or | ||
26 | * modify it under the terms of the GNU General Public License | ||
27 | * as published by the Free Software Foundation; either version | ||
28 | * 2 of the License, or (at your option) any later version. | ||
29 | * | ||
30 | * 1998/8/31 Andreas Schwab: | ||
31 | * Zero out rest of buffer on exception in | ||
32 | * csum_partial_copy_from_user. | ||
33 | */ | ||
34 | |||
35 | #include <linux/module.h> | ||
36 | #include <net/checksum.h> | ||
37 | |||
38 | /* | ||
39 | * computes a partial checksum, e.g. for TCP/UDP fragments | ||
40 | */ | ||
41 | |||
42 | __wsum csum_partial(const void *buff, int len, __wsum sum) | ||
43 | { | ||
44 | unsigned long tmp1, tmp2; | ||
45 | /* | ||
46 | * Experiments with ethernet and slip connections show that buff | ||
47 | * is aligned on either a 2-byte or 4-byte boundary. | ||
48 | */ | ||
49 | __asm__("movel %2,%3\n\t" | ||
50 | "btst #1,%3\n\t" /* Check alignment */ | ||
51 | "jeq 2f\n\t" | ||
52 | "subql #2,%1\n\t" /* buff%4==2: treat first word */ | ||
53 | "jgt 1f\n\t" | ||
54 | "addql #2,%1\n\t" /* len was == 2, treat only rest */ | ||
55 | "jra 4f\n" | ||
56 | "1:\t" | ||
57 | "addw %2@+,%0\n\t" /* add first word to sum */ | ||
58 | "clrl %3\n\t" | ||
59 | "addxl %3,%0\n" /* add X bit */ | ||
60 | "2:\t" | ||
61 | /* unrolled loop for the main part: do 8 longs at once */ | ||
62 | "movel %1,%3\n\t" /* save len in tmp1 */ | ||
63 | "lsrl #5,%1\n\t" /* len/32 */ | ||
64 | "jeq 2f\n\t" /* not enough... */ | ||
65 | "subql #1,%1\n" | ||
66 | "1:\t" | ||
67 | "movel %2@+,%4\n\t" | ||
68 | "addxl %4,%0\n\t" | ||
69 | "movel %2@+,%4\n\t" | ||
70 | "addxl %4,%0\n\t" | ||
71 | "movel %2@+,%4\n\t" | ||
72 | "addxl %4,%0\n\t" | ||
73 | "movel %2@+,%4\n\t" | ||
74 | "addxl %4,%0\n\t" | ||
75 | "movel %2@+,%4\n\t" | ||
76 | "addxl %4,%0\n\t" | ||
77 | "movel %2@+,%4\n\t" | ||
78 | "addxl %4,%0\n\t" | ||
79 | "movel %2@+,%4\n\t" | ||
80 | "addxl %4,%0\n\t" | ||
81 | "movel %2@+,%4\n\t" | ||
82 | "addxl %4,%0\n\t" | ||
83 | "dbra %1,1b\n\t" | ||
84 | "clrl %4\n\t" | ||
85 | "addxl %4,%0\n\t" /* add X bit */ | ||
86 | "clrw %1\n\t" | ||
87 | "subql #1,%1\n\t" | ||
88 | "jcc 1b\n" | ||
89 | "2:\t" | ||
90 | "movel %3,%1\n\t" /* restore len from tmp1 */ | ||
91 | "andw #0x1c,%3\n\t" /* number of rest longs */ | ||
92 | "jeq 4f\n\t" | ||
93 | "lsrw #2,%3\n\t" | ||
94 | "subqw #1,%3\n" | ||
95 | "3:\t" | ||
96 | /* loop for rest longs */ | ||
97 | "movel %2@+,%4\n\t" | ||
98 | "addxl %4,%0\n\t" | ||
99 | "dbra %3,3b\n\t" | ||
100 | "clrl %4\n\t" | ||
101 | "addxl %4,%0\n" /* add X bit */ | ||
102 | "4:\t" | ||
103 | /* now check for rest bytes that do not fit into longs */ | ||
104 | "andw #3,%1\n\t" | ||
105 | "jeq 7f\n\t" | ||
106 | "clrl %4\n\t" /* clear tmp2 for rest bytes */ | ||
107 | "subqw #2,%1\n\t" | ||
108 | "jlt 5f\n\t" | ||
109 | "movew %2@+,%4\n\t" /* have rest >= 2: get word */ | ||
110 | "swap %4\n\t" /* into bits 16..31 */ | ||
111 | "tstw %1\n\t" /* another byte? */ | ||
112 | "jeq 6f\n" | ||
113 | "5:\t" | ||
114 | "moveb %2@,%4\n\t" /* have odd rest: get byte */ | ||
115 | "lslw #8,%4\n\t" /* into bits 8..15; 16..31 untouched */ | ||
116 | "6:\t" | ||
117 | "addl %4,%0\n\t" /* now add rest long to sum */ | ||
118 | "clrl %4\n\t" | ||
119 | "addxl %4,%0\n" /* add X bit */ | ||
120 | "7:\t" | ||
121 | : "=d" (sum), "=d" (len), "=a" (buff), | ||
122 | "=&d" (tmp1), "=&d" (tmp2) | ||
123 | : "0" (sum), "1" (len), "2" (buff) | ||
124 | ); | ||
125 | return(sum); | ||
126 | } | ||
127 | |||
128 | EXPORT_SYMBOL(csum_partial); | ||
129 | |||
130 | |||
131 | /* | ||
132 | * copy from user space while checksumming, with exception handling. | ||
133 | */ | ||
134 | |||
135 | __wsum | ||
136 | csum_partial_copy_from_user(const void __user *src, void *dst, | ||
137 | int len, __wsum sum, int *csum_err) | ||
138 | { | ||
139 | /* | ||
140 | * GCC doesn't like more than 10 operands for the asm | ||
141 | * statements so we have to use tmp2 for the error | ||
142 | * code. | ||
143 | */ | ||
144 | unsigned long tmp1, tmp2; | ||
145 | |||
146 | __asm__("movel %2,%4\n\t" | ||
147 | "btst #1,%4\n\t" /* Check alignment */ | ||
148 | "jeq 2f\n\t" | ||
149 | "subql #2,%1\n\t" /* buff%4==2: treat first word */ | ||
150 | "jgt 1f\n\t" | ||
151 | "addql #2,%1\n\t" /* len was == 2, treat only rest */ | ||
152 | "jra 4f\n" | ||
153 | "1:\n" | ||
154 | "10:\t" | ||
155 | "movesw %2@+,%4\n\t" /* add first word to sum */ | ||
156 | "addw %4,%0\n\t" | ||
157 | "movew %4,%3@+\n\t" | ||
158 | "clrl %4\n\t" | ||
159 | "addxl %4,%0\n" /* add X bit */ | ||
160 | "2:\t" | ||
161 | /* unrolled loop for the main part: do 8 longs at once */ | ||
162 | "movel %1,%4\n\t" /* save len in tmp1 */ | ||
163 | "lsrl #5,%1\n\t" /* len/32 */ | ||
164 | "jeq 2f\n\t" /* not enough... */ | ||
165 | "subql #1,%1\n" | ||
166 | "1:\n" | ||
167 | "11:\t" | ||
168 | "movesl %2@+,%5\n\t" | ||
169 | "addxl %5,%0\n\t" | ||
170 | "movel %5,%3@+\n\t" | ||
171 | "12:\t" | ||
172 | "movesl %2@+,%5\n\t" | ||
173 | "addxl %5,%0\n\t" | ||
174 | "movel %5,%3@+\n\t" | ||
175 | "13:\t" | ||
176 | "movesl %2@+,%5\n\t" | ||
177 | "addxl %5,%0\n\t" | ||
178 | "movel %5,%3@+\n\t" | ||
179 | "14:\t" | ||
180 | "movesl %2@+,%5\n\t" | ||
181 | "addxl %5,%0\n\t" | ||
182 | "movel %5,%3@+\n\t" | ||
183 | "15:\t" | ||
184 | "movesl %2@+,%5\n\t" | ||
185 | "addxl %5,%0\n\t" | ||
186 | "movel %5,%3@+\n\t" | ||
187 | "16:\t" | ||
188 | "movesl %2@+,%5\n\t" | ||
189 | "addxl %5,%0\n\t" | ||
190 | "movel %5,%3@+\n\t" | ||
191 | "17:\t" | ||
192 | "movesl %2@+,%5\n\t" | ||
193 | "addxl %5,%0\n\t" | ||
194 | "movel %5,%3@+\n\t" | ||
195 | "18:\t" | ||
196 | "movesl %2@+,%5\n\t" | ||
197 | "addxl %5,%0\n\t" | ||
198 | "movel %5,%3@+\n\t" | ||
199 | "dbra %1,1b\n\t" | ||
200 | "clrl %5\n\t" | ||
201 | "addxl %5,%0\n\t" /* add X bit */ | ||
202 | "clrw %1\n\t" | ||
203 | "subql #1,%1\n\t" | ||
204 | "jcc 1b\n" | ||
205 | "2:\t" | ||
206 | "movel %4,%1\n\t" /* restore len from tmp1 */ | ||
207 | "andw #0x1c,%4\n\t" /* number of rest longs */ | ||
208 | "jeq 4f\n\t" | ||
209 | "lsrw #2,%4\n\t" | ||
210 | "subqw #1,%4\n" | ||
211 | "3:\n" | ||
212 | /* loop for rest longs */ | ||
213 | "19:\t" | ||
214 | "movesl %2@+,%5\n\t" | ||
215 | "addxl %5,%0\n\t" | ||
216 | "movel %5,%3@+\n\t" | ||
217 | "dbra %4,3b\n\t" | ||
218 | "clrl %5\n\t" | ||
219 | "addxl %5,%0\n" /* add X bit */ | ||
220 | "4:\t" | ||
221 | /* now check for rest bytes that do not fit into longs */ | ||
222 | "andw #3,%1\n\t" | ||
223 | "jeq 7f\n\t" | ||
224 | "clrl %5\n\t" /* clear tmp2 for rest bytes */ | ||
225 | "subqw #2,%1\n\t" | ||
226 | "jlt 5f\n\t" | ||
227 | "20:\t" | ||
228 | "movesw %2@+,%5\n\t" /* have rest >= 2: get word */ | ||
229 | "movew %5,%3@+\n\t" | ||
230 | "swap %5\n\t" /* into bits 16..31 */ | ||
231 | "tstw %1\n\t" /* another byte? */ | ||
232 | "jeq 6f\n" | ||
233 | "5:\n" | ||
234 | "21:\t" | ||
235 | "movesb %2@,%5\n\t" /* have odd rest: get byte */ | ||
236 | "moveb %5,%3@+\n\t" | ||
237 | "lslw #8,%5\n\t" /* into bits 8..15; 16..31 untouched */ | ||
238 | "6:\t" | ||
239 | "addl %5,%0\n\t" /* now add rest long to sum */ | ||
240 | "clrl %5\n\t" | ||
241 | "addxl %5,%0\n\t" /* add X bit */ | ||
242 | "7:\t" | ||
243 | "clrl %5\n" /* no error - clear return value */ | ||
244 | "8:\n" | ||
245 | ".section .fixup,\"ax\"\n" | ||
246 | ".even\n" | ||
247 | /* If any exception occurs zero out the rest. | ||
248 | Similarities with the code above are intentional :-) */ | ||
249 | "90:\t" | ||
250 | "clrw %3@+\n\t" | ||
251 | "movel %1,%4\n\t" | ||
252 | "lsrl #5,%1\n\t" | ||
253 | "jeq 1f\n\t" | ||
254 | "subql #1,%1\n" | ||
255 | "91:\t" | ||
256 | "clrl %3@+\n" | ||
257 | "92:\t" | ||
258 | "clrl %3@+\n" | ||
259 | "93:\t" | ||
260 | "clrl %3@+\n" | ||
261 | "94:\t" | ||
262 | "clrl %3@+\n" | ||
263 | "95:\t" | ||
264 | "clrl %3@+\n" | ||
265 | "96:\t" | ||
266 | "clrl %3@+\n" | ||
267 | "97:\t" | ||
268 | "clrl %3@+\n" | ||
269 | "98:\t" | ||
270 | "clrl %3@+\n\t" | ||
271 | "dbra %1,91b\n\t" | ||
272 | "clrw %1\n\t" | ||
273 | "subql #1,%1\n\t" | ||
274 | "jcc 91b\n" | ||
275 | "1:\t" | ||
276 | "movel %4,%1\n\t" | ||
277 | "andw #0x1c,%4\n\t" | ||
278 | "jeq 1f\n\t" | ||
279 | "lsrw #2,%4\n\t" | ||
280 | "subqw #1,%4\n" | ||
281 | "99:\t" | ||
282 | "clrl %3@+\n\t" | ||
283 | "dbra %4,99b\n\t" | ||
284 | "1:\t" | ||
285 | "andw #3,%1\n\t" | ||
286 | "jeq 9f\n" | ||
287 | "100:\t" | ||
288 | "clrw %3@+\n\t" | ||
289 | "tstw %1\n\t" | ||
290 | "jeq 9f\n" | ||
291 | "101:\t" | ||
292 | "clrb %3@+\n" | ||
293 | "9:\t" | ||
294 | #define STR(X) STR1(X) | ||
295 | #define STR1(X) #X | ||
296 | "moveq #-" STR(EFAULT) ",%5\n\t" | ||
297 | "jra 8b\n" | ||
298 | ".previous\n" | ||
299 | ".section __ex_table,\"a\"\n" | ||
300 | ".long 10b,90b\n" | ||
301 | ".long 11b,91b\n" | ||
302 | ".long 12b,92b\n" | ||
303 | ".long 13b,93b\n" | ||
304 | ".long 14b,94b\n" | ||
305 | ".long 15b,95b\n" | ||
306 | ".long 16b,96b\n" | ||
307 | ".long 17b,97b\n" | ||
308 | ".long 18b,98b\n" | ||
309 | ".long 19b,99b\n" | ||
310 | ".long 20b,100b\n" | ||
311 | ".long 21b,101b\n" | ||
312 | ".previous" | ||
313 | : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst), | ||
314 | "=&d" (tmp1), "=d" (tmp2) | ||
315 | : "0" (sum), "1" (len), "2" (src), "3" (dst) | ||
316 | ); | ||
317 | |||
318 | *csum_err = tmp2; | ||
319 | |||
320 | return(sum); | ||
321 | } | ||
322 | |||
323 | EXPORT_SYMBOL(csum_partial_copy_from_user); | ||
324 | |||
325 | |||
326 | /* | ||
327 | * copy from kernel space while checksumming, otherwise like csum_partial | ||
328 | */ | ||
329 | |||
330 | __wsum | ||
331 | csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum) | ||
332 | { | ||
333 | unsigned long tmp1, tmp2; | ||
334 | __asm__("movel %2,%4\n\t" | ||
335 | "btst #1,%4\n\t" /* Check alignment */ | ||
336 | "jeq 2f\n\t" | ||
337 | "subql #2,%1\n\t" /* buff%4==2: treat first word */ | ||
338 | "jgt 1f\n\t" | ||
339 | "addql #2,%1\n\t" /* len was == 2, treat only rest */ | ||
340 | "jra 4f\n" | ||
341 | "1:\t" | ||
342 | "movew %2@+,%4\n\t" /* add first word to sum */ | ||
343 | "addw %4,%0\n\t" | ||
344 | "movew %4,%3@+\n\t" | ||
345 | "clrl %4\n\t" | ||
346 | "addxl %4,%0\n" /* add X bit */ | ||
347 | "2:\t" | ||
348 | /* unrolled loop for the main part: do 8 longs at once */ | ||
349 | "movel %1,%4\n\t" /* save len in tmp1 */ | ||
350 | "lsrl #5,%1\n\t" /* len/32 */ | ||
351 | "jeq 2f\n\t" /* not enough... */ | ||
352 | "subql #1,%1\n" | ||
353 | "1:\t" | ||
354 | "movel %2@+,%5\n\t" | ||
355 | "addxl %5,%0\n\t" | ||
356 | "movel %5,%3@+\n\t" | ||
357 | "movel %2@+,%5\n\t" | ||
358 | "addxl %5,%0\n\t" | ||
359 | "movel %5,%3@+\n\t" | ||
360 | "movel %2@+,%5\n\t" | ||
361 | "addxl %5,%0\n\t" | ||
362 | "movel %5,%3@+\n\t" | ||
363 | "movel %2@+,%5\n\t" | ||
364 | "addxl %5,%0\n\t" | ||
365 | "movel %5,%3@+\n\t" | ||
366 | "movel %2@+,%5\n\t" | ||
367 | "addxl %5,%0\n\t" | ||
368 | "movel %5,%3@+\n\t" | ||
369 | "movel %2@+,%5\n\t" | ||
370 | "addxl %5,%0\n\t" | ||
371 | "movel %5,%3@+\n\t" | ||
372 | "movel %2@+,%5\n\t" | ||
373 | "addxl %5,%0\n\t" | ||
374 | "movel %5,%3@+\n\t" | ||
375 | "movel %2@+,%5\n\t" | ||
376 | "addxl %5,%0\n\t" | ||
377 | "movel %5,%3@+\n\t" | ||
378 | "dbra %1,1b\n\t" | ||
379 | "clrl %5\n\t" | ||
380 | "addxl %5,%0\n\t" /* add X bit */ | ||
381 | "clrw %1\n\t" | ||
382 | "subql #1,%1\n\t" | ||
383 | "jcc 1b\n" | ||
384 | "2:\t" | ||
385 | "movel %4,%1\n\t" /* restore len from tmp1 */ | ||
386 | "andw #0x1c,%4\n\t" /* number of rest longs */ | ||
387 | "jeq 4f\n\t" | ||
388 | "lsrw #2,%4\n\t" | ||
389 | "subqw #1,%4\n" | ||
390 | "3:\t" | ||
391 | /* loop for rest longs */ | ||
392 | "movel %2@+,%5\n\t" | ||
393 | "addxl %5,%0\n\t" | ||
394 | "movel %5,%3@+\n\t" | ||
395 | "dbra %4,3b\n\t" | ||
396 | "clrl %5\n\t" | ||
397 | "addxl %5,%0\n" /* add X bit */ | ||
398 | "4:\t" | ||
399 | /* now check for rest bytes that do not fit into longs */ | ||
400 | "andw #3,%1\n\t" | ||
401 | "jeq 7f\n\t" | ||
402 | "clrl %5\n\t" /* clear tmp2 for rest bytes */ | ||
403 | "subqw #2,%1\n\t" | ||
404 | "jlt 5f\n\t" | ||
405 | "movew %2@+,%5\n\t" /* have rest >= 2: get word */ | ||
406 | "movew %5,%3@+\n\t" | ||
407 | "swap %5\n\t" /* into bits 16..31 */ | ||
408 | "tstw %1\n\t" /* another byte? */ | ||
409 | "jeq 6f\n" | ||
410 | "5:\t" | ||
411 | "moveb %2@,%5\n\t" /* have odd rest: get byte */ | ||
412 | "moveb %5,%3@+\n\t" | ||
413 | "lslw #8,%5\n" /* into bits 8..15; 16..31 untouched */ | ||
414 | "6:\t" | ||
415 | "addl %5,%0\n\t" /* now add rest long to sum */ | ||
416 | "clrl %5\n\t" | ||
417 | "addxl %5,%0\n" /* add X bit */ | ||
418 | "7:\t" | ||
419 | : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst), | ||
420 | "=&d" (tmp1), "=&d" (tmp2) | ||
421 | : "0" (sum), "1" (len), "2" (src), "3" (dst) | ||
422 | ); | ||
423 | return(sum); | ||
424 | } | ||
425 | EXPORT_SYMBOL(csum_partial_copy_nocheck); | ||
diff --git a/arch/m68k/lib/checksum_mm.c b/arch/m68k/lib/checksum_mm.c new file mode 100644 index 000000000000..6216f12a756b --- /dev/null +++ b/arch/m68k/lib/checksum_mm.c | |||
@@ -0,0 +1,425 @@ | |||
1 | /* | ||
2 | * INET An implementation of the TCP/IP protocol suite for the LINUX | ||
3 | * operating system. INET is implemented using the BSD Socket | ||
4 | * interface as the means of communication with the user level. | ||
5 | * | ||
6 | * IP/TCP/UDP checksumming routines | ||
7 | * | ||
8 | * Authors: Jorge Cwik, <jorge@laser.satlink.net> | ||
9 | * Arnt Gulbrandsen, <agulbra@nvg.unit.no> | ||
10 | * Tom May, <ftom@netcom.com> | ||
11 | * Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de> | ||
12 | * Lots of code moved from tcp.c and ip.c; see those files | ||
13 | * for more names. | ||
14 | * | ||
15 | * 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek: | ||
16 | * Fixed some nasty bugs, causing some horrible crashes. | ||
17 | * A: At some points, the sum (%0) was used as | ||
18 | * length-counter instead of the length counter | ||
19 | * (%1). Thanks to Roman Hodek for pointing this out. | ||
20 | * B: GCC seems to mess up if one uses too many | ||
21 | * data-registers to hold input values and one tries to | ||
22 | * specify d0 and d1 as scratch registers. Letting gcc | ||
23 | * choose these registers itself solves the problem. | ||
24 | * | ||
25 | * This program is free software; you can redistribute it and/or | ||
26 | * modify it under the terms of the GNU General Public License | ||
27 | * as published by the Free Software Foundation; either version | ||
28 | * 2 of the License, or (at your option) any later version. | ||
29 | * | ||
30 | * 1998/8/31 Andreas Schwab: | ||
31 | * Zero out rest of buffer on exception in | ||
32 | * csum_partial_copy_from_user. | ||
33 | */ | ||
34 | |||
35 | #include <linux/module.h> | ||
36 | #include <net/checksum.h> | ||
37 | |||
38 | /* | ||
39 | * computes a partial checksum, e.g. for TCP/UDP fragments | ||
40 | */ | ||
41 | |||
42 | __wsum csum_partial(const void *buff, int len, __wsum sum) | ||
43 | { | ||
44 | unsigned long tmp1, tmp2; | ||
45 | /* | ||
46 | * Experiments with ethernet and slip connections show that buff | ||
47 | * is aligned on either a 2-byte or 4-byte boundary. | ||
48 | */ | ||
49 | __asm__("movel %2,%3\n\t" | ||
50 | "btst #1,%3\n\t" /* Check alignment */ | ||
51 | "jeq 2f\n\t" | ||
52 | "subql #2,%1\n\t" /* buff%4==2: treat first word */ | ||
53 | "jgt 1f\n\t" | ||
54 | "addql #2,%1\n\t" /* len was == 2, treat only rest */ | ||
55 | "jra 4f\n" | ||
56 | "1:\t" | ||
57 | "addw %2@+,%0\n\t" /* add first word to sum */ | ||
58 | "clrl %3\n\t" | ||
59 | "addxl %3,%0\n" /* add X bit */ | ||
60 | "2:\t" | ||
61 | /* unrolled loop for the main part: do 8 longs at once */ | ||
62 | "movel %1,%3\n\t" /* save len in tmp1 */ | ||
63 | "lsrl #5,%1\n\t" /* len/32 */ | ||
64 | "jeq 2f\n\t" /* not enough... */ | ||
65 | "subql #1,%1\n" | ||
66 | "1:\t" | ||
67 | "movel %2@+,%4\n\t" | ||
68 | "addxl %4,%0\n\t" | ||
69 | "movel %2@+,%4\n\t" | ||
70 | "addxl %4,%0\n\t" | ||
71 | "movel %2@+,%4\n\t" | ||
72 | "addxl %4,%0\n\t" | ||
73 | "movel %2@+,%4\n\t" | ||
74 | "addxl %4,%0\n\t" | ||
75 | "movel %2@+,%4\n\t" | ||
76 | "addxl %4,%0\n\t" | ||
77 | "movel %2@+,%4\n\t" | ||
78 | "addxl %4,%0\n\t" | ||
79 | "movel %2@+,%4\n\t" | ||
80 | "addxl %4,%0\n\t" | ||
81 | "movel %2@+,%4\n\t" | ||
82 | "addxl %4,%0\n\t" | ||
83 | "dbra %1,1b\n\t" | ||
84 | "clrl %4\n\t" | ||
85 | "addxl %4,%0\n\t" /* add X bit */ | ||
86 | "clrw %1\n\t" | ||
87 | "subql #1,%1\n\t" | ||
88 | "jcc 1b\n" | ||
89 | "2:\t" | ||
90 | "movel %3,%1\n\t" /* restore len from tmp1 */ | ||
91 | "andw #0x1c,%3\n\t" /* number of rest longs */ | ||
92 | "jeq 4f\n\t" | ||
93 | "lsrw #2,%3\n\t" | ||
94 | "subqw #1,%3\n" | ||
95 | "3:\t" | ||
96 | /* loop for rest longs */ | ||
97 | "movel %2@+,%4\n\t" | ||
98 | "addxl %4,%0\n\t" | ||
99 | "dbra %3,3b\n\t" | ||
100 | "clrl %4\n\t" | ||
101 | "addxl %4,%0\n" /* add X bit */ | ||
102 | "4:\t" | ||
103 | /* now check for rest bytes that do not fit into longs */ | ||
104 | "andw #3,%1\n\t" | ||
105 | "jeq 7f\n\t" | ||
106 | "clrl %4\n\t" /* clear tmp2 for rest bytes */ | ||
107 | "subqw #2,%1\n\t" | ||
108 | "jlt 5f\n\t" | ||
109 | "movew %2@+,%4\n\t" /* have rest >= 2: get word */ | ||
110 | "swap %4\n\t" /* into bits 16..31 */ | ||
111 | "tstw %1\n\t" /* another byte? */ | ||
112 | "jeq 6f\n" | ||
113 | "5:\t" | ||
114 | "moveb %2@,%4\n\t" /* have odd rest: get byte */ | ||
115 | "lslw #8,%4\n\t" /* into bits 8..15; 16..31 untouched */ | ||
116 | "6:\t" | ||
117 | "addl %4,%0\n\t" /* now add rest long to sum */ | ||
118 | "clrl %4\n\t" | ||
119 | "addxl %4,%0\n" /* add X bit */ | ||
120 | "7:\t" | ||
121 | : "=d" (sum), "=d" (len), "=a" (buff), | ||
122 | "=&d" (tmp1), "=&d" (tmp2) | ||
123 | : "0" (sum), "1" (len), "2" (buff) | ||
124 | ); | ||
125 | return(sum); | ||
126 | } | ||
127 | |||
128 | EXPORT_SYMBOL(csum_partial); | ||
129 | |||
130 | |||
131 | /* | ||
132 | * copy from user space while checksumming, with exception handling. | ||
133 | */ | ||
134 | |||
135 | __wsum | ||
136 | csum_partial_copy_from_user(const void __user *src, void *dst, | ||
137 | int len, __wsum sum, int *csum_err) | ||
138 | { | ||
139 | /* | ||
140 | * GCC doesn't like more than 10 operands for the asm | ||
141 | * statements so we have to use tmp2 for the error | ||
142 | * code. | ||
143 | */ | ||
144 | unsigned long tmp1, tmp2; | ||
145 | |||
146 | __asm__("movel %2,%4\n\t" | ||
147 | "btst #1,%4\n\t" /* Check alignment */ | ||
148 | "jeq 2f\n\t" | ||
149 | "subql #2,%1\n\t" /* buff%4==2: treat first word */ | ||
150 | "jgt 1f\n\t" | ||
151 | "addql #2,%1\n\t" /* len was == 2, treat only rest */ | ||
152 | "jra 4f\n" | ||
153 | "1:\n" | ||
154 | "10:\t" | ||
155 | "movesw %2@+,%4\n\t" /* add first word to sum */ | ||
156 | "addw %4,%0\n\t" | ||
157 | "movew %4,%3@+\n\t" | ||
158 | "clrl %4\n\t" | ||
159 | "addxl %4,%0\n" /* add X bit */ | ||
160 | "2:\t" | ||
161 | /* unrolled loop for the main part: do 8 longs at once */ | ||
162 | "movel %1,%4\n\t" /* save len in tmp1 */ | ||
163 | "lsrl #5,%1\n\t" /* len/32 */ | ||
164 | "jeq 2f\n\t" /* not enough... */ | ||
165 | "subql #1,%1\n" | ||
166 | "1:\n" | ||
167 | "11:\t" | ||
168 | "movesl %2@+,%5\n\t" | ||
169 | "addxl %5,%0\n\t" | ||
170 | "movel %5,%3@+\n\t" | ||
171 | "12:\t" | ||
172 | "movesl %2@+,%5\n\t" | ||
173 | "addxl %5,%0\n\t" | ||
174 | "movel %5,%3@+\n\t" | ||
175 | "13:\t" | ||
176 | "movesl %2@+,%5\n\t" | ||
177 | "addxl %5,%0\n\t" | ||
178 | "movel %5,%3@+\n\t" | ||
179 | "14:\t" | ||
180 | "movesl %2@+,%5\n\t" | ||
181 | "addxl %5,%0\n\t" | ||
182 | "movel %5,%3@+\n\t" | ||
183 | "15:\t" | ||
184 | "movesl %2@+,%5\n\t" | ||
185 | "addxl %5,%0\n\t" | ||
186 | "movel %5,%3@+\n\t" | ||
187 | "16:\t" | ||
188 | "movesl %2@+,%5\n\t" | ||
189 | "addxl %5,%0\n\t" | ||
190 | "movel %5,%3@+\n\t" | ||
191 | "17:\t" | ||
192 | "movesl %2@+,%5\n\t" | ||
193 | "addxl %5,%0\n\t" | ||
194 | "movel %5,%3@+\n\t" | ||
195 | "18:\t" | ||
196 | "movesl %2@+,%5\n\t" | ||
197 | "addxl %5,%0\n\t" | ||
198 | "movel %5,%3@+\n\t" | ||
199 | "dbra %1,1b\n\t" | ||
200 | "clrl %5\n\t" | ||
201 | "addxl %5,%0\n\t" /* add X bit */ | ||
202 | "clrw %1\n\t" | ||
203 | "subql #1,%1\n\t" | ||
204 | "jcc 1b\n" | ||
205 | "2:\t" | ||
206 | "movel %4,%1\n\t" /* restore len from tmp1 */ | ||
207 | "andw #0x1c,%4\n\t" /* number of rest longs */ | ||
208 | "jeq 4f\n\t" | ||
209 | "lsrw #2,%4\n\t" | ||
210 | "subqw #1,%4\n" | ||
211 | "3:\n" | ||
212 | /* loop for rest longs */ | ||
213 | "19:\t" | ||
214 | "movesl %2@+,%5\n\t" | ||
215 | "addxl %5,%0\n\t" | ||
216 | "movel %5,%3@+\n\t" | ||
217 | "dbra %4,3b\n\t" | ||
218 | "clrl %5\n\t" | ||
219 | "addxl %5,%0\n" /* add X bit */ | ||
220 | "4:\t" | ||
221 | /* now check for rest bytes that do not fit into longs */ | ||
222 | "andw #3,%1\n\t" | ||
223 | "jeq 7f\n\t" | ||
224 | "clrl %5\n\t" /* clear tmp2 for rest bytes */ | ||
225 | "subqw #2,%1\n\t" | ||
226 | "jlt 5f\n\t" | ||
227 | "20:\t" | ||
228 | "movesw %2@+,%5\n\t" /* have rest >= 2: get word */ | ||
229 | "movew %5,%3@+\n\t" | ||
230 | "swap %5\n\t" /* into bits 16..31 */ | ||
231 | "tstw %1\n\t" /* another byte? */ | ||
232 | "jeq 6f\n" | ||
233 | "5:\n" | ||
234 | "21:\t" | ||
235 | "movesb %2@,%5\n\t" /* have odd rest: get byte */ | ||
236 | "moveb %5,%3@+\n\t" | ||
237 | "lslw #8,%5\n\t" /* into bits 8..15; 16..31 untouched */ | ||
238 | "6:\t" | ||
239 | "addl %5,%0\n\t" /* now add rest long to sum */ | ||
240 | "clrl %5\n\t" | ||
241 | "addxl %5,%0\n\t" /* add X bit */ | ||
242 | "7:\t" | ||
243 | "clrl %5\n" /* no error - clear return value */ | ||
244 | "8:\n" | ||
245 | ".section .fixup,\"ax\"\n" | ||
246 | ".even\n" | ||
247 | /* If any exception occurs zero out the rest. | ||
248 | Similarities with the code above are intentional :-) */ | ||
249 | "90:\t" | ||
250 | "clrw %3@+\n\t" | ||
251 | "movel %1,%4\n\t" | ||
252 | "lsrl #5,%1\n\t" | ||
253 | "jeq 1f\n\t" | ||
254 | "subql #1,%1\n" | ||
255 | "91:\t" | ||
256 | "clrl %3@+\n" | ||
257 | "92:\t" | ||
258 | "clrl %3@+\n" | ||
259 | "93:\t" | ||
260 | "clrl %3@+\n" | ||
261 | "94:\t" | ||
262 | "clrl %3@+\n" | ||
263 | "95:\t" | ||
264 | "clrl %3@+\n" | ||
265 | "96:\t" | ||
266 | "clrl %3@+\n" | ||
267 | "97:\t" | ||
268 | "clrl %3@+\n" | ||
269 | "98:\t" | ||
270 | "clrl %3@+\n\t" | ||
271 | "dbra %1,91b\n\t" | ||
272 | "clrw %1\n\t" | ||
273 | "subql #1,%1\n\t" | ||
274 | "jcc 91b\n" | ||
275 | "1:\t" | ||
276 | "movel %4,%1\n\t" | ||
277 | "andw #0x1c,%4\n\t" | ||
278 | "jeq 1f\n\t" | ||
279 | "lsrw #2,%4\n\t" | ||
280 | "subqw #1,%4\n" | ||
281 | "99:\t" | ||
282 | "clrl %3@+\n\t" | ||
283 | "dbra %4,99b\n\t" | ||
284 | "1:\t" | ||
285 | "andw #3,%1\n\t" | ||
286 | "jeq 9f\n" | ||
287 | "100:\t" | ||
288 | "clrw %3@+\n\t" | ||
289 | "tstw %1\n\t" | ||
290 | "jeq 9f\n" | ||
291 | "101:\t" | ||
292 | "clrb %3@+\n" | ||
293 | "9:\t" | ||
294 | #define STR(X) STR1(X) | ||
295 | #define STR1(X) #X | ||
296 | "moveq #-" STR(EFAULT) ",%5\n\t" | ||
297 | "jra 8b\n" | ||
298 | ".previous\n" | ||
299 | ".section __ex_table,\"a\"\n" | ||
300 | ".long 10b,90b\n" | ||
301 | ".long 11b,91b\n" | ||
302 | ".long 12b,92b\n" | ||
303 | ".long 13b,93b\n" | ||
304 | ".long 14b,94b\n" | ||
305 | ".long 15b,95b\n" | ||
306 | ".long 16b,96b\n" | ||
307 | ".long 17b,97b\n" | ||
308 | ".long 18b,98b\n" | ||
309 | ".long 19b,99b\n" | ||
310 | ".long 20b,100b\n" | ||
311 | ".long 21b,101b\n" | ||
312 | ".previous" | ||
313 | : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst), | ||
314 | "=&d" (tmp1), "=d" (tmp2) | ||
315 | : "0" (sum), "1" (len), "2" (src), "3" (dst) | ||
316 | ); | ||
317 | |||
318 | *csum_err = tmp2; | ||
319 | |||
320 | return(sum); | ||
321 | } | ||
322 | |||
323 | EXPORT_SYMBOL(csum_partial_copy_from_user); | ||
324 | |||
325 | |||
326 | /* | ||
327 | * copy from kernel space while checksumming, otherwise like csum_partial | ||
328 | */ | ||
329 | |||
330 | __wsum | ||
331 | csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum) | ||
332 | { | ||
333 | unsigned long tmp1, tmp2; | ||
334 | __asm__("movel %2,%4\n\t" | ||
335 | "btst #1,%4\n\t" /* Check alignment */ | ||
336 | "jeq 2f\n\t" | ||
337 | "subql #2,%1\n\t" /* buff%4==2: treat first word */ | ||
338 | "jgt 1f\n\t" | ||
339 | "addql #2,%1\n\t" /* len was == 2, treat only rest */ | ||
340 | "jra 4f\n" | ||
341 | "1:\t" | ||
342 | "movew %2@+,%4\n\t" /* add first word to sum */ | ||
343 | "addw %4,%0\n\t" | ||
344 | "movew %4,%3@+\n\t" | ||
345 | "clrl %4\n\t" | ||
346 | "addxl %4,%0\n" /* add X bit */ | ||
347 | "2:\t" | ||
348 | /* unrolled loop for the main part: do 8 longs at once */ | ||
349 | "movel %1,%4\n\t" /* save len in tmp1 */ | ||
350 | "lsrl #5,%1\n\t" /* len/32 */ | ||
351 | "jeq 2f\n\t" /* not enough... */ | ||
352 | "subql #1,%1\n" | ||
353 | "1:\t" | ||
354 | "movel %2@+,%5\n\t" | ||
355 | "addxl %5,%0\n\t" | ||
356 | "movel %5,%3@+\n\t" | ||
357 | "movel %2@+,%5\n\t" | ||
358 | "addxl %5,%0\n\t" | ||
359 | "movel %5,%3@+\n\t" | ||
360 | "movel %2@+,%5\n\t" | ||
361 | "addxl %5,%0\n\t" | ||
362 | "movel %5,%3@+\n\t" | ||
363 | "movel %2@+,%5\n\t" | ||
364 | "addxl %5,%0\n\t" | ||
365 | "movel %5,%3@+\n\t" | ||
366 | "movel %2@+,%5\n\t" | ||
367 | "addxl %5,%0\n\t" | ||
368 | "movel %5,%3@+\n\t" | ||
369 | "movel %2@+,%5\n\t" | ||
370 | "addxl %5,%0\n\t" | ||
371 | "movel %5,%3@+\n\t" | ||
372 | "movel %2@+,%5\n\t" | ||
373 | "addxl %5,%0\n\t" | ||
374 | "movel %5,%3@+\n\t" | ||
375 | "movel %2@+,%5\n\t" | ||
376 | "addxl %5,%0\n\t" | ||
377 | "movel %5,%3@+\n\t" | ||
378 | "dbra %1,1b\n\t" | ||
379 | "clrl %5\n\t" | ||
380 | "addxl %5,%0\n\t" /* add X bit */ | ||
381 | "clrw %1\n\t" | ||
382 | "subql #1,%1\n\t" | ||
383 | "jcc 1b\n" | ||
384 | "2:\t" | ||
385 | "movel %4,%1\n\t" /* restore len from tmp1 */ | ||
386 | "andw #0x1c,%4\n\t" /* number of rest longs */ | ||
387 | "jeq 4f\n\t" | ||
388 | "lsrw #2,%4\n\t" | ||
389 | "subqw #1,%4\n" | ||
390 | "3:\t" | ||
391 | /* loop for rest longs */ | ||
392 | "movel %2@+,%5\n\t" | ||
393 | "addxl %5,%0\n\t" | ||
394 | "movel %5,%3@+\n\t" | ||
395 | "dbra %4,3b\n\t" | ||
396 | "clrl %5\n\t" | ||
397 | "addxl %5,%0\n" /* add X bit */ | ||
398 | "4:\t" | ||
399 | /* now check for rest bytes that do not fit into longs */ | ||
400 | "andw #3,%1\n\t" | ||
401 | "jeq 7f\n\t" | ||
402 | "clrl %5\n\t" /* clear tmp2 for rest bytes */ | ||
403 | "subqw #2,%1\n\t" | ||
404 | "jlt 5f\n\t" | ||
405 | "movew %2@+,%5\n\t" /* have rest >= 2: get word */ | ||
406 | "movew %5,%3@+\n\t" | ||
407 | "swap %5\n\t" /* into bits 16..31 */ | ||
408 | "tstw %1\n\t" /* another byte? */ | ||
409 | "jeq 6f\n" | ||
410 | "5:\t" | ||
411 | "moveb %2@,%5\n\t" /* have odd rest: get byte */ | ||
412 | "moveb %5,%3@+\n\t" | ||
413 | "lslw #8,%5\n" /* into bits 8..15; 16..31 untouched */ | ||
414 | "6:\t" | ||
415 | "addl %5,%0\n\t" /* now add rest long to sum */ | ||
416 | "clrl %5\n\t" | ||
417 | "addxl %5,%0\n" /* add X bit */ | ||
418 | "7:\t" | ||
419 | : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst), | ||
420 | "=&d" (tmp1), "=&d" (tmp2) | ||
421 | : "0" (sum), "1" (len), "2" (src), "3" (dst) | ||
422 | ); | ||
423 | return(sum); | ||
424 | } | ||
425 | EXPORT_SYMBOL(csum_partial_copy_nocheck); | ||
diff --git a/arch/m68knommu/lib/checksum.c b/arch/m68k/lib/checksum_no.c index eccf25d3d73e..eccf25d3d73e 100644 --- a/arch/m68knommu/lib/checksum.c +++ b/arch/m68k/lib/checksum_no.c | |||
diff --git a/arch/m68knommu/lib/delay.c b/arch/m68k/lib/delay.c index 5bd5472d38a0..5bd5472d38a0 100644 --- a/arch/m68knommu/lib/delay.c +++ b/arch/m68k/lib/delay.c | |||
diff --git a/arch/m68knommu/lib/divsi3.S b/arch/m68k/lib/divsi3.S index ec307b61991e..ec307b61991e 100644 --- a/arch/m68knommu/lib/divsi3.S +++ b/arch/m68k/lib/divsi3.S | |||
diff --git a/arch/m68knommu/lib/memcpy.c b/arch/m68k/lib/memcpy.c index b50dbcad4746..b50dbcad4746 100644 --- a/arch/m68knommu/lib/memcpy.c +++ b/arch/m68k/lib/memcpy.c | |||
diff --git a/arch/m68knommu/lib/memmove.c b/arch/m68k/lib/memmove.c index b3dcfe9dab7e..b3dcfe9dab7e 100644 --- a/arch/m68knommu/lib/memmove.c +++ b/arch/m68k/lib/memmove.c | |||
diff --git a/arch/m68knommu/lib/memset.c b/arch/m68k/lib/memset.c index 1389bf455633..1389bf455633 100644 --- a/arch/m68knommu/lib/memset.c +++ b/arch/m68k/lib/memset.c | |||
diff --git a/arch/m68knommu/lib/modsi3.S b/arch/m68k/lib/modsi3.S index ef3849435768..ef3849435768 100644 --- a/arch/m68knommu/lib/modsi3.S +++ b/arch/m68k/lib/modsi3.S | |||
diff --git a/arch/m68k/lib/muldi3.c b/arch/m68k/lib/muldi3.c index be4f275649e3..16e0eb338ee0 100644 --- a/arch/m68k/lib/muldi3.c +++ b/arch/m68k/lib/muldi3.c | |||
@@ -1,63 +1,5 @@ | |||
1 | /* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and | 1 | #ifdef CONFIG_MMU |
2 | gcc-2.7.2.3/longlong.h which is: */ | 2 | #include "muldi3_mm.c" |
3 | /* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. | 3 | #else |
4 | 4 | #include "muldi3_no.c" | |
5 | This file is part of GNU CC. | 5 | #endif |
6 | |||
7 | GNU CC is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | GNU CC is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with GNU CC; see the file COPYING. If not, write to | ||
19 | the Free Software Foundation, 59 Temple Place - Suite 330, | ||
20 | Boston, MA 02111-1307, USA. */ | ||
21 | |||
22 | #define BITS_PER_UNIT 8 | ||
23 | |||
24 | #define umul_ppmm(w1, w0, u, v) \ | ||
25 | __asm__ ("mulu%.l %3,%1:%0" \ | ||
26 | : "=d" ((USItype)(w0)), \ | ||
27 | "=d" ((USItype)(w1)) \ | ||
28 | : "%0" ((USItype)(u)), \ | ||
29 | "dmi" ((USItype)(v))) | ||
30 | |||
31 | #define __umulsidi3(u, v) \ | ||
32 | ({DIunion __w; \ | ||
33 | umul_ppmm (__w.s.high, __w.s.low, u, v); \ | ||
34 | __w.ll; }) | ||
35 | |||
36 | typedef int SItype __attribute__ ((mode (SI))); | ||
37 | typedef unsigned int USItype __attribute__ ((mode (SI))); | ||
38 | typedef int DItype __attribute__ ((mode (DI))); | ||
39 | typedef int word_type __attribute__ ((mode (__word__))); | ||
40 | |||
41 | struct DIstruct {SItype high, low;}; | ||
42 | |||
43 | typedef union | ||
44 | { | ||
45 | struct DIstruct s; | ||
46 | DItype ll; | ||
47 | } DIunion; | ||
48 | |||
49 | DItype | ||
50 | __muldi3 (DItype u, DItype v) | ||
51 | { | ||
52 | DIunion w; | ||
53 | DIunion uu, vv; | ||
54 | |||
55 | uu.ll = u, | ||
56 | vv.ll = v; | ||
57 | |||
58 | w.ll = __umulsidi3 (uu.s.low, vv.s.low); | ||
59 | w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high | ||
60 | + (USItype) uu.s.high * (USItype) vv.s.low); | ||
61 | |||
62 | return w.ll; | ||
63 | } | ||
diff --git a/arch/m68knommu/lib/ashrdi3.c b/arch/m68k/lib/muldi3_mm.c index 78efb65e315a..be4f275649e3 100644 --- a/arch/m68knommu/lib/ashrdi3.c +++ b/arch/m68k/lib/muldi3_mm.c | |||
@@ -1,4 +1,5 @@ | |||
1 | /* ashrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */ | 1 | /* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and |
2 | gcc-2.7.2.3/longlong.h which is: */ | ||
2 | /* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. | 3 | /* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. |
3 | 4 | ||
4 | This file is part of GNU CC. | 5 | This file is part of GNU CC. |
@@ -20,7 +21,19 @@ Boston, MA 02111-1307, USA. */ | |||
20 | 21 | ||
21 | #define BITS_PER_UNIT 8 | 22 | #define BITS_PER_UNIT 8 |
22 | 23 | ||
23 | typedef int SItype __attribute__ ((mode (SI))); | 24 | #define umul_ppmm(w1, w0, u, v) \ |
25 | __asm__ ("mulu%.l %3,%1:%0" \ | ||
26 | : "=d" ((USItype)(w0)), \ | ||
27 | "=d" ((USItype)(w1)) \ | ||
28 | : "%0" ((USItype)(u)), \ | ||
29 | "dmi" ((USItype)(v))) | ||
30 | |||
31 | #define __umulsidi3(u, v) \ | ||
32 | ({DIunion __w; \ | ||
33 | umul_ppmm (__w.s.high, __w.s.low, u, v); \ | ||
34 | __w.ll; }) | ||
35 | |||
36 | typedef int SItype __attribute__ ((mode (SI))); | ||
24 | typedef unsigned int USItype __attribute__ ((mode (SI))); | 37 | typedef unsigned int USItype __attribute__ ((mode (SI))); |
25 | typedef int DItype __attribute__ ((mode (DI))); | 38 | typedef int DItype __attribute__ ((mode (DI))); |
26 | typedef int word_type __attribute__ ((mode (__word__))); | 39 | typedef int word_type __attribute__ ((mode (__word__))); |
@@ -34,30 +47,17 @@ typedef union | |||
34 | } DIunion; | 47 | } DIunion; |
35 | 48 | ||
36 | DItype | 49 | DItype |
37 | __ashrdi3 (DItype u, word_type b) | 50 | __muldi3 (DItype u, DItype v) |
38 | { | 51 | { |
39 | DIunion w; | 52 | DIunion w; |
40 | word_type bm; | 53 | DIunion uu, vv; |
41 | DIunion uu; | 54 | |
42 | 55 | uu.ll = u, | |
43 | if (b == 0) | 56 | vv.ll = v; |
44 | return u; | 57 | |
45 | 58 | w.ll = __umulsidi3 (uu.s.low, vv.s.low); | |
46 | uu.ll = u; | 59 | w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high |
47 | 60 | + (USItype) uu.s.high * (USItype) vv.s.low); | |
48 | bm = (sizeof (SItype) * BITS_PER_UNIT) - b; | ||
49 | if (bm <= 0) | ||
50 | { | ||
51 | /* w.s.high = 1..1 or 0..0 */ | ||
52 | w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1); | ||
53 | w.s.low = uu.s.high >> -bm; | ||
54 | } | ||
55 | else | ||
56 | { | ||
57 | USItype carries = (USItype)uu.s.high << bm; | ||
58 | w.s.high = uu.s.high >> b; | ||
59 | w.s.low = ((USItype)uu.s.low >> b) | carries; | ||
60 | } | ||
61 | 61 | ||
62 | return w.ll; | 62 | return w.ll; |
63 | } | 63 | } |
diff --git a/arch/m68knommu/lib/muldi3.c b/arch/m68k/lib/muldi3_no.c index 34af72c30303..34af72c30303 100644 --- a/arch/m68knommu/lib/muldi3.c +++ b/arch/m68k/lib/muldi3_no.c | |||
diff --git a/arch/m68knommu/lib/mulsi3.S b/arch/m68k/lib/mulsi3.S index ce29ea37b45f..ce29ea37b45f 100644 --- a/arch/m68knommu/lib/mulsi3.S +++ b/arch/m68k/lib/mulsi3.S | |||
diff --git a/arch/m68knommu/lib/udivsi3.S b/arch/m68k/lib/udivsi3.S index c424c4a1f0a3..c424c4a1f0a3 100644 --- a/arch/m68knommu/lib/udivsi3.S +++ b/arch/m68k/lib/udivsi3.S | |||
diff --git a/arch/m68knommu/lib/umodsi3.S b/arch/m68k/lib/umodsi3.S index 5def5f626478..5def5f626478 100644 --- a/arch/m68knommu/lib/umodsi3.S +++ b/arch/m68k/lib/umodsi3.S | |||
diff --git a/arch/m68k/mm/Makefile b/arch/m68k/mm/Makefile index 5eaa43c4cb3c..b60270e4954b 100644 --- a/arch/m68k/mm/Makefile +++ b/arch/m68k/mm/Makefile | |||
@@ -1,8 +1,5 @@ | |||
1 | # | 1 | ifdef CONFIG_MMU |
2 | # Makefile for the linux m68k-specific parts of the memory manager. | 2 | include arch/m68k/mm/Makefile_mm |
3 | # | 3 | else |
4 | 4 | include arch/m68k/mm/Makefile_no | |
5 | obj-y := cache.o init.o fault.o hwtest.o | 5 | endif |
6 | |||
7 | obj-$(CONFIG_MMU_MOTOROLA) += kmap.o memory.o motorola.o | ||
8 | obj-$(CONFIG_MMU_SUN3) += sun3kmap.o sun3mmu.o | ||
diff --git a/arch/m68k/mm/Makefile_mm b/arch/m68k/mm/Makefile_mm new file mode 100644 index 000000000000..5eaa43c4cb3c --- /dev/null +++ b/arch/m68k/mm/Makefile_mm | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Makefile for the linux m68k-specific parts of the memory manager. | ||
3 | # | ||
4 | |||
5 | obj-y := cache.o init.o fault.o hwtest.o | ||
6 | |||
7 | obj-$(CONFIG_MMU_MOTOROLA) += kmap.o memory.o motorola.o | ||
8 | obj-$(CONFIG_MMU_SUN3) += sun3kmap.o sun3mmu.o | ||
diff --git a/arch/m68knommu/mm/Makefile b/arch/m68k/mm/Makefile_no index b54ab6b4b523..b54ab6b4b523 100644 --- a/arch/m68knommu/mm/Makefile +++ b/arch/m68k/mm/Makefile_no | |||
diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c index 8bc842554e5b..27b5ce089a34 100644 --- a/arch/m68k/mm/init.c +++ b/arch/m68k/mm/init.c | |||
@@ -1,150 +1,5 @@ | |||
1 | /* | 1 | #ifdef CONFIG_MMU |
2 | * linux/arch/m68k/mm/init.c | 2 | #include "init_mm.c" |
3 | * | 3 | #else |
4 | * Copyright (C) 1995 Hamish Macdonald | 4 | #include "init_no.c" |
5 | * | ||
6 | * Contains common initialization routines, specific init code moved | ||
7 | * to motorola.c and sun3mmu.c | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/signal.h> | ||
12 | #include <linux/sched.h> | ||
13 | #include <linux/mm.h> | ||
14 | #include <linux/swap.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/bootmem.h> | ||
20 | #include <linux/gfp.h> | ||
21 | |||
22 | #include <asm/setup.h> | ||
23 | #include <asm/uaccess.h> | ||
24 | #include <asm/page.h> | ||
25 | #include <asm/pgalloc.h> | ||
26 | #include <asm/system.h> | ||
27 | #include <asm/machdep.h> | ||
28 | #include <asm/io.h> | ||
29 | #ifdef CONFIG_ATARI | ||
30 | #include <asm/atari_stram.h> | ||
31 | #endif | ||
32 | #include <asm/sections.h> | ||
33 | #include <asm/tlb.h> | ||
34 | |||
35 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); | ||
36 | |||
37 | pg_data_t pg_data_map[MAX_NUMNODES]; | ||
38 | EXPORT_SYMBOL(pg_data_map); | ||
39 | |||
40 | int m68k_virt_to_node_shift; | ||
41 | |||
42 | #ifndef CONFIG_SINGLE_MEMORY_CHUNK | ||
43 | pg_data_t *pg_data_table[65]; | ||
44 | EXPORT_SYMBOL(pg_data_table); | ||
45 | #endif | ||
46 | |||
47 | void __init m68k_setup_node(int node) | ||
48 | { | ||
49 | #ifndef CONFIG_SINGLE_MEMORY_CHUNK | ||
50 | struct mem_info *info = m68k_memory + node; | ||
51 | int i, end; | ||
52 | |||
53 | i = (unsigned long)phys_to_virt(info->addr) >> __virt_to_node_shift(); | ||
54 | end = (unsigned long)phys_to_virt(info->addr + info->size - 1) >> __virt_to_node_shift(); | ||
55 | for (; i <= end; i++) { | ||
56 | if (pg_data_table[i]) | ||
57 | printk("overlap at %u for chunk %u\n", i, node); | ||
58 | pg_data_table[i] = pg_data_map + node; | ||
59 | } | ||
60 | #endif | ||
61 | pg_data_map[node].bdata = bootmem_node_data + node; | ||
62 | node_set_online(node); | ||
63 | } | ||
64 | |||
65 | |||
66 | /* | ||
67 | * ZERO_PAGE is a special page that is used for zero-initialized | ||
68 | * data and COW. | ||
69 | */ | ||
70 | |||
71 | void *empty_zero_page; | ||
72 | EXPORT_SYMBOL(empty_zero_page); | ||
73 | |||
74 | extern void init_pointer_table(unsigned long ptable); | ||
75 | |||
76 | /* References to section boundaries */ | ||
77 | |||
78 | extern pmd_t *zero_pgtable; | ||
79 | |||
80 | void __init mem_init(void) | ||
81 | { | ||
82 | pg_data_t *pgdat; | ||
83 | int codepages = 0; | ||
84 | int datapages = 0; | ||
85 | int initpages = 0; | ||
86 | int i; | ||
87 | |||
88 | #ifdef CONFIG_ATARI | ||
89 | if (MACH_IS_ATARI) | ||
90 | atari_stram_mem_init_hook(); | ||
91 | #endif | ||
92 | |||
93 | /* this will put all memory onto the freelists */ | ||
94 | totalram_pages = num_physpages = 0; | ||
95 | for_each_online_pgdat(pgdat) { | ||
96 | num_physpages += pgdat->node_present_pages; | ||
97 | |||
98 | totalram_pages += free_all_bootmem_node(pgdat); | ||
99 | for (i = 0; i < pgdat->node_spanned_pages; i++) { | ||
100 | struct page *page = pgdat->node_mem_map + i; | ||
101 | char *addr = page_to_virt(page); | ||
102 | |||
103 | if (!PageReserved(page)) | ||
104 | continue; | ||
105 | if (addr >= _text && | ||
106 | addr < _etext) | ||
107 | codepages++; | ||
108 | else if (addr >= __init_begin && | ||
109 | addr < __init_end) | ||
110 | initpages++; | ||
111 | else | ||
112 | datapages++; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | #ifndef CONFIG_SUN3 | ||
117 | /* insert pointer tables allocated so far into the tablelist */ | ||
118 | init_pointer_table((unsigned long)kernel_pg_dir); | ||
119 | for (i = 0; i < PTRS_PER_PGD; i++) { | ||
120 | if (pgd_present(kernel_pg_dir[i])) | ||
121 | init_pointer_table(__pgd_page(kernel_pg_dir[i])); | ||
122 | } | ||
123 | |||
124 | /* insert also pointer table that we used to unmap the zero page */ | ||
125 | if (zero_pgtable) | ||
126 | init_pointer_table((unsigned long)zero_pgtable); | ||
127 | #endif | ||
128 | |||
129 | printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n", | ||
130 | nr_free_pages() << (PAGE_SHIFT-10), | ||
131 | totalram_pages << (PAGE_SHIFT-10), | ||
132 | codepages << (PAGE_SHIFT-10), | ||
133 | datapages << (PAGE_SHIFT-10), | ||
134 | initpages << (PAGE_SHIFT-10)); | ||
135 | } | ||
136 | |||
137 | #ifdef CONFIG_BLK_DEV_INITRD | ||
138 | void free_initrd_mem(unsigned long start, unsigned long end) | ||
139 | { | ||
140 | int pages = 0; | ||
141 | for (; start < end; start += PAGE_SIZE) { | ||
142 | ClearPageReserved(virt_to_page(start)); | ||
143 | init_page_count(virt_to_page(start)); | ||
144 | free_page(start); | ||
145 | totalram_pages++; | ||
146 | pages++; | ||
147 | } | ||
148 | printk ("Freeing initrd memory: %dk freed\n", pages); | ||
149 | } | ||
150 | #endif | 5 | #endif |
diff --git a/arch/m68k/mm/init_mm.c b/arch/m68k/mm/init_mm.c new file mode 100644 index 000000000000..8bc842554e5b --- /dev/null +++ b/arch/m68k/mm/init_mm.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/mm/init.c | ||
3 | * | ||
4 | * Copyright (C) 1995 Hamish Macdonald | ||
5 | * | ||
6 | * Contains common initialization routines, specific init code moved | ||
7 | * to motorola.c and sun3mmu.c | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/signal.h> | ||
12 | #include <linux/sched.h> | ||
13 | #include <linux/mm.h> | ||
14 | #include <linux/swap.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/bootmem.h> | ||
20 | #include <linux/gfp.h> | ||
21 | |||
22 | #include <asm/setup.h> | ||
23 | #include <asm/uaccess.h> | ||
24 | #include <asm/page.h> | ||
25 | #include <asm/pgalloc.h> | ||
26 | #include <asm/system.h> | ||
27 | #include <asm/machdep.h> | ||
28 | #include <asm/io.h> | ||
29 | #ifdef CONFIG_ATARI | ||
30 | #include <asm/atari_stram.h> | ||
31 | #endif | ||
32 | #include <asm/sections.h> | ||
33 | #include <asm/tlb.h> | ||
34 | |||
35 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); | ||
36 | |||
37 | pg_data_t pg_data_map[MAX_NUMNODES]; | ||
38 | EXPORT_SYMBOL(pg_data_map); | ||
39 | |||
40 | int m68k_virt_to_node_shift; | ||
41 | |||
42 | #ifndef CONFIG_SINGLE_MEMORY_CHUNK | ||
43 | pg_data_t *pg_data_table[65]; | ||
44 | EXPORT_SYMBOL(pg_data_table); | ||
45 | #endif | ||
46 | |||
47 | void __init m68k_setup_node(int node) | ||
48 | { | ||
49 | #ifndef CONFIG_SINGLE_MEMORY_CHUNK | ||
50 | struct mem_info *info = m68k_memory + node; | ||
51 | int i, end; | ||
52 | |||
53 | i = (unsigned long)phys_to_virt(info->addr) >> __virt_to_node_shift(); | ||
54 | end = (unsigned long)phys_to_virt(info->addr + info->size - 1) >> __virt_to_node_shift(); | ||
55 | for (; i <= end; i++) { | ||
56 | if (pg_data_table[i]) | ||
57 | printk("overlap at %u for chunk %u\n", i, node); | ||
58 | pg_data_table[i] = pg_data_map + node; | ||
59 | } | ||
60 | #endif | ||
61 | pg_data_map[node].bdata = bootmem_node_data + node; | ||
62 | node_set_online(node); | ||
63 | } | ||
64 | |||
65 | |||
66 | /* | ||
67 | * ZERO_PAGE is a special page that is used for zero-initialized | ||
68 | * data and COW. | ||
69 | */ | ||
70 | |||
71 | void *empty_zero_page; | ||
72 | EXPORT_SYMBOL(empty_zero_page); | ||
73 | |||
74 | extern void init_pointer_table(unsigned long ptable); | ||
75 | |||
76 | /* References to section boundaries */ | ||
77 | |||
78 | extern pmd_t *zero_pgtable; | ||
79 | |||
80 | void __init mem_init(void) | ||
81 | { | ||
82 | pg_data_t *pgdat; | ||
83 | int codepages = 0; | ||
84 | int datapages = 0; | ||
85 | int initpages = 0; | ||
86 | int i; | ||
87 | |||
88 | #ifdef CONFIG_ATARI | ||
89 | if (MACH_IS_ATARI) | ||
90 | atari_stram_mem_init_hook(); | ||
91 | #endif | ||
92 | |||
93 | /* this will put all memory onto the freelists */ | ||
94 | totalram_pages = num_physpages = 0; | ||
95 | for_each_online_pgdat(pgdat) { | ||
96 | num_physpages += pgdat->node_present_pages; | ||
97 | |||
98 | totalram_pages += free_all_bootmem_node(pgdat); | ||
99 | for (i = 0; i < pgdat->node_spanned_pages; i++) { | ||
100 | struct page *page = pgdat->node_mem_map + i; | ||
101 | char *addr = page_to_virt(page); | ||
102 | |||
103 | if (!PageReserved(page)) | ||
104 | continue; | ||
105 | if (addr >= _text && | ||
106 | addr < _etext) | ||
107 | codepages++; | ||
108 | else if (addr >= __init_begin && | ||
109 | addr < __init_end) | ||
110 | initpages++; | ||
111 | else | ||
112 | datapages++; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | #ifndef CONFIG_SUN3 | ||
117 | /* insert pointer tables allocated so far into the tablelist */ | ||
118 | init_pointer_table((unsigned long)kernel_pg_dir); | ||
119 | for (i = 0; i < PTRS_PER_PGD; i++) { | ||
120 | if (pgd_present(kernel_pg_dir[i])) | ||
121 | init_pointer_table(__pgd_page(kernel_pg_dir[i])); | ||
122 | } | ||
123 | |||
124 | /* insert also pointer table that we used to unmap the zero page */ | ||
125 | if (zero_pgtable) | ||
126 | init_pointer_table((unsigned long)zero_pgtable); | ||
127 | #endif | ||
128 | |||
129 | printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n", | ||
130 | nr_free_pages() << (PAGE_SHIFT-10), | ||
131 | totalram_pages << (PAGE_SHIFT-10), | ||
132 | codepages << (PAGE_SHIFT-10), | ||
133 | datapages << (PAGE_SHIFT-10), | ||
134 | initpages << (PAGE_SHIFT-10)); | ||
135 | } | ||
136 | |||
137 | #ifdef CONFIG_BLK_DEV_INITRD | ||
138 | void free_initrd_mem(unsigned long start, unsigned long end) | ||
139 | { | ||
140 | int pages = 0; | ||
141 | for (; start < end; start += PAGE_SIZE) { | ||
142 | ClearPageReserved(virt_to_page(start)); | ||
143 | init_page_count(virt_to_page(start)); | ||
144 | free_page(start); | ||
145 | totalram_pages++; | ||
146 | pages++; | ||
147 | } | ||
148 | printk ("Freeing initrd memory: %dk freed\n", pages); | ||
149 | } | ||
150 | #endif | ||
diff --git a/arch/m68knommu/mm/init.c b/arch/m68k/mm/init_no.c index 8a6653f56bd8..8a6653f56bd8 100644 --- a/arch/m68knommu/mm/init.c +++ b/arch/m68k/mm/init_no.c | |||
diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c index 69345849454b..a373d136b2b2 100644 --- a/arch/m68k/mm/kmap.c +++ b/arch/m68k/mm/kmap.c | |||
@@ -1,367 +1,5 @@ | |||
1 | /* | 1 | #ifdef CONFIG_MMU |
2 | * linux/arch/m68k/mm/kmap.c | 2 | #include "kmap_mm.c" |
3 | * | ||
4 | * Copyright (C) 1997 Roman Hodek | ||
5 | * | ||
6 | * 10/01/99 cleaned up the code and changing to the same interface | ||
7 | * used by other architectures /Roman Zippel | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/mm.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/string.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/vmalloc.h> | ||
17 | |||
18 | #include <asm/setup.h> | ||
19 | #include <asm/segment.h> | ||
20 | #include <asm/page.h> | ||
21 | #include <asm/pgalloc.h> | ||
22 | #include <asm/io.h> | ||
23 | #include <asm/system.h> | ||
24 | |||
25 | #undef DEBUG | ||
26 | |||
27 | #define PTRTREESIZE (256*1024) | ||
28 | |||
29 | /* | ||
30 | * For 040/060 we can use the virtual memory area like other architectures, | ||
31 | * but for 020/030 we want to use early termination page descriptor and we | ||
32 | * can't mix this with normal page descriptors, so we have to copy that code | ||
33 | * (mm/vmalloc.c) and return appriorate aligned addresses. | ||
34 | */ | ||
35 | |||
36 | #ifdef CPU_M68040_OR_M68060_ONLY | ||
37 | |||
38 | #define IO_SIZE PAGE_SIZE | ||
39 | |||
40 | static inline struct vm_struct *get_io_area(unsigned long size) | ||
41 | { | ||
42 | return get_vm_area(size, VM_IOREMAP); | ||
43 | } | ||
44 | |||
45 | |||
46 | static inline void free_io_area(void *addr) | ||
47 | { | ||
48 | vfree((void *)(PAGE_MASK & (unsigned long)addr)); | ||
49 | } | ||
50 | |||
51 | #else | 3 | #else |
52 | 4 | #include "kmap_no.c" | |
53 | #define IO_SIZE (256*1024) | ||
54 | |||
55 | static struct vm_struct *iolist; | ||
56 | |||
57 | static struct vm_struct *get_io_area(unsigned long size) | ||
58 | { | ||
59 | unsigned long addr; | ||
60 | struct vm_struct **p, *tmp, *area; | ||
61 | |||
62 | area = kmalloc(sizeof(*area), GFP_KERNEL); | ||
63 | if (!area) | ||
64 | return NULL; | ||
65 | addr = KMAP_START; | ||
66 | for (p = &iolist; (tmp = *p) ; p = &tmp->next) { | ||
67 | if (size + addr < (unsigned long)tmp->addr) | ||
68 | break; | ||
69 | if (addr > KMAP_END-size) { | ||
70 | kfree(area); | ||
71 | return NULL; | ||
72 | } | ||
73 | addr = tmp->size + (unsigned long)tmp->addr; | ||
74 | } | ||
75 | area->addr = (void *)addr; | ||
76 | area->size = size + IO_SIZE; | ||
77 | area->next = *p; | ||
78 | *p = area; | ||
79 | return area; | ||
80 | } | ||
81 | |||
82 | static inline void free_io_area(void *addr) | ||
83 | { | ||
84 | struct vm_struct **p, *tmp; | ||
85 | |||
86 | if (!addr) | ||
87 | return; | ||
88 | addr = (void *)((unsigned long)addr & -IO_SIZE); | ||
89 | for (p = &iolist ; (tmp = *p) ; p = &tmp->next) { | ||
90 | if (tmp->addr == addr) { | ||
91 | *p = tmp->next; | ||
92 | __iounmap(tmp->addr, tmp->size); | ||
93 | kfree(tmp); | ||
94 | return; | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | |||
99 | #endif | 5 | #endif |
100 | |||
101 | /* | ||
102 | * Map some physical address range into the kernel address space. | ||
103 | */ | ||
104 | /* Rewritten by Andreas Schwab to remove all races. */ | ||
105 | |||
106 | void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag) | ||
107 | { | ||
108 | struct vm_struct *area; | ||
109 | unsigned long virtaddr, retaddr; | ||
110 | long offset; | ||
111 | pgd_t *pgd_dir; | ||
112 | pmd_t *pmd_dir; | ||
113 | pte_t *pte_dir; | ||
114 | |||
115 | /* | ||
116 | * Don't allow mappings that wrap.. | ||
117 | */ | ||
118 | if (!size || physaddr > (unsigned long)(-size)) | ||
119 | return NULL; | ||
120 | |||
121 | #ifdef CONFIG_AMIGA | ||
122 | if (MACH_IS_AMIGA) { | ||
123 | if ((physaddr >= 0x40000000) && (physaddr + size < 0x60000000) | ||
124 | && (cacheflag == IOMAP_NOCACHE_SER)) | ||
125 | return (void __iomem *)physaddr; | ||
126 | } | ||
127 | #endif | ||
128 | |||
129 | #ifdef DEBUG | ||
130 | printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag); | ||
131 | #endif | ||
132 | /* | ||
133 | * Mappings have to be aligned | ||
134 | */ | ||
135 | offset = physaddr & (IO_SIZE - 1); | ||
136 | physaddr &= -IO_SIZE; | ||
137 | size = (size + offset + IO_SIZE - 1) & -IO_SIZE; | ||
138 | |||
139 | /* | ||
140 | * Ok, go for it.. | ||
141 | */ | ||
142 | area = get_io_area(size); | ||
143 | if (!area) | ||
144 | return NULL; | ||
145 | |||
146 | virtaddr = (unsigned long)area->addr; | ||
147 | retaddr = virtaddr + offset; | ||
148 | #ifdef DEBUG | ||
149 | printk("0x%lx,0x%lx,0x%lx", physaddr, virtaddr, retaddr); | ||
150 | #endif | ||
151 | |||
152 | /* | ||
153 | * add cache and table flags to physical address | ||
154 | */ | ||
155 | if (CPU_IS_040_OR_060) { | ||
156 | physaddr |= (_PAGE_PRESENT | _PAGE_GLOBAL040 | | ||
157 | _PAGE_ACCESSED | _PAGE_DIRTY); | ||
158 | switch (cacheflag) { | ||
159 | case IOMAP_FULL_CACHING: | ||
160 | physaddr |= _PAGE_CACHE040; | ||
161 | break; | ||
162 | case IOMAP_NOCACHE_SER: | ||
163 | default: | ||
164 | physaddr |= _PAGE_NOCACHE_S; | ||
165 | break; | ||
166 | case IOMAP_NOCACHE_NONSER: | ||
167 | physaddr |= _PAGE_NOCACHE; | ||
168 | break; | ||
169 | case IOMAP_WRITETHROUGH: | ||
170 | physaddr |= _PAGE_CACHE040W; | ||
171 | break; | ||
172 | } | ||
173 | } else { | ||
174 | physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY); | ||
175 | switch (cacheflag) { | ||
176 | case IOMAP_NOCACHE_SER: | ||
177 | case IOMAP_NOCACHE_NONSER: | ||
178 | default: | ||
179 | physaddr |= _PAGE_NOCACHE030; | ||
180 | break; | ||
181 | case IOMAP_FULL_CACHING: | ||
182 | case IOMAP_WRITETHROUGH: | ||
183 | break; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | while ((long)size > 0) { | ||
188 | #ifdef DEBUG | ||
189 | if (!(virtaddr & (PTRTREESIZE-1))) | ||
190 | printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr); | ||
191 | #endif | ||
192 | pgd_dir = pgd_offset_k(virtaddr); | ||
193 | pmd_dir = pmd_alloc(&init_mm, pgd_dir, virtaddr); | ||
194 | if (!pmd_dir) { | ||
195 | printk("ioremap: no mem for pmd_dir\n"); | ||
196 | return NULL; | ||
197 | } | ||
198 | |||
199 | if (CPU_IS_020_OR_030) { | ||
200 | pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr; | ||
201 | physaddr += PTRTREESIZE; | ||
202 | virtaddr += PTRTREESIZE; | ||
203 | size -= PTRTREESIZE; | ||
204 | } else { | ||
205 | pte_dir = pte_alloc_kernel(pmd_dir, virtaddr); | ||
206 | if (!pte_dir) { | ||
207 | printk("ioremap: no mem for pte_dir\n"); | ||
208 | return NULL; | ||
209 | } | ||
210 | |||
211 | pte_val(*pte_dir) = physaddr; | ||
212 | virtaddr += PAGE_SIZE; | ||
213 | physaddr += PAGE_SIZE; | ||
214 | size -= PAGE_SIZE; | ||
215 | } | ||
216 | } | ||
217 | #ifdef DEBUG | ||
218 | printk("\n"); | ||
219 | #endif | ||
220 | flush_tlb_all(); | ||
221 | |||
222 | return (void __iomem *)retaddr; | ||
223 | } | ||
224 | EXPORT_SYMBOL(__ioremap); | ||
225 | |||
226 | /* | ||
227 | * Unmap a ioremap()ed region again | ||
228 | */ | ||
229 | void iounmap(void __iomem *addr) | ||
230 | { | ||
231 | #ifdef CONFIG_AMIGA | ||
232 | if ((!MACH_IS_AMIGA) || | ||
233 | (((unsigned long)addr < 0x40000000) || | ||
234 | ((unsigned long)addr > 0x60000000))) | ||
235 | free_io_area((__force void *)addr); | ||
236 | #else | ||
237 | free_io_area((__force void *)addr); | ||
238 | #endif | ||
239 | } | ||
240 | EXPORT_SYMBOL(iounmap); | ||
241 | |||
242 | /* | ||
243 | * __iounmap unmaps nearly everything, so be careful | ||
244 | * it doesn't free currently pointer/page tables anymore but it | ||
245 | * wans't used anyway and might be added later. | ||
246 | */ | ||
247 | void __iounmap(void *addr, unsigned long size) | ||
248 | { | ||
249 | unsigned long virtaddr = (unsigned long)addr; | ||
250 | pgd_t *pgd_dir; | ||
251 | pmd_t *pmd_dir; | ||
252 | pte_t *pte_dir; | ||
253 | |||
254 | while ((long)size > 0) { | ||
255 | pgd_dir = pgd_offset_k(virtaddr); | ||
256 | if (pgd_bad(*pgd_dir)) { | ||
257 | printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir)); | ||
258 | pgd_clear(pgd_dir); | ||
259 | return; | ||
260 | } | ||
261 | pmd_dir = pmd_offset(pgd_dir, virtaddr); | ||
262 | |||
263 | if (CPU_IS_020_OR_030) { | ||
264 | int pmd_off = (virtaddr/PTRTREESIZE) & 15; | ||
265 | int pmd_type = pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK; | ||
266 | |||
267 | if (pmd_type == _PAGE_PRESENT) { | ||
268 | pmd_dir->pmd[pmd_off] = 0; | ||
269 | virtaddr += PTRTREESIZE; | ||
270 | size -= PTRTREESIZE; | ||
271 | continue; | ||
272 | } else if (pmd_type == 0) | ||
273 | continue; | ||
274 | } | ||
275 | |||
276 | if (pmd_bad(*pmd_dir)) { | ||
277 | printk("iounmap: bad pmd (%08lx)\n", pmd_val(*pmd_dir)); | ||
278 | pmd_clear(pmd_dir); | ||
279 | return; | ||
280 | } | ||
281 | pte_dir = pte_offset_kernel(pmd_dir, virtaddr); | ||
282 | |||
283 | pte_val(*pte_dir) = 0; | ||
284 | virtaddr += PAGE_SIZE; | ||
285 | size -= PAGE_SIZE; | ||
286 | } | ||
287 | |||
288 | flush_tlb_all(); | ||
289 | } | ||
290 | |||
291 | /* | ||
292 | * Set new cache mode for some kernel address space. | ||
293 | * The caller must push data for that range itself, if such data may already | ||
294 | * be in the cache. | ||
295 | */ | ||
296 | void kernel_set_cachemode(void *addr, unsigned long size, int cmode) | ||
297 | { | ||
298 | unsigned long virtaddr = (unsigned long)addr; | ||
299 | pgd_t *pgd_dir; | ||
300 | pmd_t *pmd_dir; | ||
301 | pte_t *pte_dir; | ||
302 | |||
303 | if (CPU_IS_040_OR_060) { | ||
304 | switch (cmode) { | ||
305 | case IOMAP_FULL_CACHING: | ||
306 | cmode = _PAGE_CACHE040; | ||
307 | break; | ||
308 | case IOMAP_NOCACHE_SER: | ||
309 | default: | ||
310 | cmode = _PAGE_NOCACHE_S; | ||
311 | break; | ||
312 | case IOMAP_NOCACHE_NONSER: | ||
313 | cmode = _PAGE_NOCACHE; | ||
314 | break; | ||
315 | case IOMAP_WRITETHROUGH: | ||
316 | cmode = _PAGE_CACHE040W; | ||
317 | break; | ||
318 | } | ||
319 | } else { | ||
320 | switch (cmode) { | ||
321 | case IOMAP_NOCACHE_SER: | ||
322 | case IOMAP_NOCACHE_NONSER: | ||
323 | default: | ||
324 | cmode = _PAGE_NOCACHE030; | ||
325 | break; | ||
326 | case IOMAP_FULL_CACHING: | ||
327 | case IOMAP_WRITETHROUGH: | ||
328 | cmode = 0; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | while ((long)size > 0) { | ||
333 | pgd_dir = pgd_offset_k(virtaddr); | ||
334 | if (pgd_bad(*pgd_dir)) { | ||
335 | printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir)); | ||
336 | pgd_clear(pgd_dir); | ||
337 | return; | ||
338 | } | ||
339 | pmd_dir = pmd_offset(pgd_dir, virtaddr); | ||
340 | |||
341 | if (CPU_IS_020_OR_030) { | ||
342 | int pmd_off = (virtaddr/PTRTREESIZE) & 15; | ||
343 | |||
344 | if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) { | ||
345 | pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] & | ||
346 | _CACHEMASK040) | cmode; | ||
347 | virtaddr += PTRTREESIZE; | ||
348 | size -= PTRTREESIZE; | ||
349 | continue; | ||
350 | } | ||
351 | } | ||
352 | |||
353 | if (pmd_bad(*pmd_dir)) { | ||
354 | printk("iocachemode: bad pmd (%08lx)\n", pmd_val(*pmd_dir)); | ||
355 | pmd_clear(pmd_dir); | ||
356 | return; | ||
357 | } | ||
358 | pte_dir = pte_offset_kernel(pmd_dir, virtaddr); | ||
359 | |||
360 | pte_val(*pte_dir) = (pte_val(*pte_dir) & _CACHEMASK040) | cmode; | ||
361 | virtaddr += PAGE_SIZE; | ||
362 | size -= PAGE_SIZE; | ||
363 | } | ||
364 | |||
365 | flush_tlb_all(); | ||
366 | } | ||
367 | EXPORT_SYMBOL(kernel_set_cachemode); | ||
diff --git a/arch/m68k/mm/kmap_mm.c b/arch/m68k/mm/kmap_mm.c new file mode 100644 index 000000000000..69345849454b --- /dev/null +++ b/arch/m68k/mm/kmap_mm.c | |||
@@ -0,0 +1,367 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/mm/kmap.c | ||
3 | * | ||
4 | * Copyright (C) 1997 Roman Hodek | ||
5 | * | ||
6 | * 10/01/99 cleaned up the code and changing to the same interface | ||
7 | * used by other architectures /Roman Zippel | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/mm.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/string.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/vmalloc.h> | ||
17 | |||
18 | #include <asm/setup.h> | ||
19 | #include <asm/segment.h> | ||
20 | #include <asm/page.h> | ||
21 | #include <asm/pgalloc.h> | ||
22 | #include <asm/io.h> | ||
23 | #include <asm/system.h> | ||
24 | |||
25 | #undef DEBUG | ||
26 | |||
27 | #define PTRTREESIZE (256*1024) | ||
28 | |||
29 | /* | ||
30 | * For 040/060 we can use the virtual memory area like other architectures, | ||
31 | * but for 020/030 we want to use early termination page descriptor and we | ||
32 | * can't mix this with normal page descriptors, so we have to copy that code | ||
33 | * (mm/vmalloc.c) and return appriorate aligned addresses. | ||
34 | */ | ||
35 | |||
36 | #ifdef CPU_M68040_OR_M68060_ONLY | ||
37 | |||
38 | #define IO_SIZE PAGE_SIZE | ||
39 | |||
40 | static inline struct vm_struct *get_io_area(unsigned long size) | ||
41 | { | ||
42 | return get_vm_area(size, VM_IOREMAP); | ||
43 | } | ||
44 | |||
45 | |||
46 | static inline void free_io_area(void *addr) | ||
47 | { | ||
48 | vfree((void *)(PAGE_MASK & (unsigned long)addr)); | ||
49 | } | ||
50 | |||
51 | #else | ||
52 | |||
53 | #define IO_SIZE (256*1024) | ||
54 | |||
55 | static struct vm_struct *iolist; | ||
56 | |||
57 | static struct vm_struct *get_io_area(unsigned long size) | ||
58 | { | ||
59 | unsigned long addr; | ||
60 | struct vm_struct **p, *tmp, *area; | ||
61 | |||
62 | area = kmalloc(sizeof(*area), GFP_KERNEL); | ||
63 | if (!area) | ||
64 | return NULL; | ||
65 | addr = KMAP_START; | ||
66 | for (p = &iolist; (tmp = *p) ; p = &tmp->next) { | ||
67 | if (size + addr < (unsigned long)tmp->addr) | ||
68 | break; | ||
69 | if (addr > KMAP_END-size) { | ||
70 | kfree(area); | ||
71 | return NULL; | ||
72 | } | ||
73 | addr = tmp->size + (unsigned long)tmp->addr; | ||
74 | } | ||
75 | area->addr = (void *)addr; | ||
76 | area->size = size + IO_SIZE; | ||
77 | area->next = *p; | ||
78 | *p = area; | ||
79 | return area; | ||
80 | } | ||
81 | |||
82 | static inline void free_io_area(void *addr) | ||
83 | { | ||
84 | struct vm_struct **p, *tmp; | ||
85 | |||
86 | if (!addr) | ||
87 | return; | ||
88 | addr = (void *)((unsigned long)addr & -IO_SIZE); | ||
89 | for (p = &iolist ; (tmp = *p) ; p = &tmp->next) { | ||
90 | if (tmp->addr == addr) { | ||
91 | *p = tmp->next; | ||
92 | __iounmap(tmp->addr, tmp->size); | ||
93 | kfree(tmp); | ||
94 | return; | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | |||
99 | #endif | ||
100 | |||
101 | /* | ||
102 | * Map some physical address range into the kernel address space. | ||
103 | */ | ||
104 | /* Rewritten by Andreas Schwab to remove all races. */ | ||
105 | |||
106 | void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag) | ||
107 | { | ||
108 | struct vm_struct *area; | ||
109 | unsigned long virtaddr, retaddr; | ||
110 | long offset; | ||
111 | pgd_t *pgd_dir; | ||
112 | pmd_t *pmd_dir; | ||
113 | pte_t *pte_dir; | ||
114 | |||
115 | /* | ||
116 | * Don't allow mappings that wrap.. | ||
117 | */ | ||
118 | if (!size || physaddr > (unsigned long)(-size)) | ||
119 | return NULL; | ||
120 | |||
121 | #ifdef CONFIG_AMIGA | ||
122 | if (MACH_IS_AMIGA) { | ||
123 | if ((physaddr >= 0x40000000) && (physaddr + size < 0x60000000) | ||
124 | && (cacheflag == IOMAP_NOCACHE_SER)) | ||
125 | return (void __iomem *)physaddr; | ||
126 | } | ||
127 | #endif | ||
128 | |||
129 | #ifdef DEBUG | ||
130 | printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag); | ||
131 | #endif | ||
132 | /* | ||
133 | * Mappings have to be aligned | ||
134 | */ | ||
135 | offset = physaddr & (IO_SIZE - 1); | ||
136 | physaddr &= -IO_SIZE; | ||
137 | size = (size + offset + IO_SIZE - 1) & -IO_SIZE; | ||
138 | |||
139 | /* | ||
140 | * Ok, go for it.. | ||
141 | */ | ||
142 | area = get_io_area(size); | ||
143 | if (!area) | ||
144 | return NULL; | ||
145 | |||
146 | virtaddr = (unsigned long)area->addr; | ||
147 | retaddr = virtaddr + offset; | ||
148 | #ifdef DEBUG | ||
149 | printk("0x%lx,0x%lx,0x%lx", physaddr, virtaddr, retaddr); | ||
150 | #endif | ||
151 | |||
152 | /* | ||
153 | * add cache and table flags to physical address | ||
154 | */ | ||
155 | if (CPU_IS_040_OR_060) { | ||
156 | physaddr |= (_PAGE_PRESENT | _PAGE_GLOBAL040 | | ||
157 | _PAGE_ACCESSED | _PAGE_DIRTY); | ||
158 | switch (cacheflag) { | ||
159 | case IOMAP_FULL_CACHING: | ||
160 | physaddr |= _PAGE_CACHE040; | ||
161 | break; | ||
162 | case IOMAP_NOCACHE_SER: | ||
163 | default: | ||
164 | physaddr |= _PAGE_NOCACHE_S; | ||
165 | break; | ||
166 | case IOMAP_NOCACHE_NONSER: | ||
167 | physaddr |= _PAGE_NOCACHE; | ||
168 | break; | ||
169 | case IOMAP_WRITETHROUGH: | ||
170 | physaddr |= _PAGE_CACHE040W; | ||
171 | break; | ||
172 | } | ||
173 | } else { | ||
174 | physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY); | ||
175 | switch (cacheflag) { | ||
176 | case IOMAP_NOCACHE_SER: | ||
177 | case IOMAP_NOCACHE_NONSER: | ||
178 | default: | ||
179 | physaddr |= _PAGE_NOCACHE030; | ||
180 | break; | ||
181 | case IOMAP_FULL_CACHING: | ||
182 | case IOMAP_WRITETHROUGH: | ||
183 | break; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | while ((long)size > 0) { | ||
188 | #ifdef DEBUG | ||
189 | if (!(virtaddr & (PTRTREESIZE-1))) | ||
190 | printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr); | ||
191 | #endif | ||
192 | pgd_dir = pgd_offset_k(virtaddr); | ||
193 | pmd_dir = pmd_alloc(&init_mm, pgd_dir, virtaddr); | ||
194 | if (!pmd_dir) { | ||
195 | printk("ioremap: no mem for pmd_dir\n"); | ||
196 | return NULL; | ||
197 | } | ||
198 | |||
199 | if (CPU_IS_020_OR_030) { | ||
200 | pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr; | ||
201 | physaddr += PTRTREESIZE; | ||
202 | virtaddr += PTRTREESIZE; | ||
203 | size -= PTRTREESIZE; | ||
204 | } else { | ||
205 | pte_dir = pte_alloc_kernel(pmd_dir, virtaddr); | ||
206 | if (!pte_dir) { | ||
207 | printk("ioremap: no mem for pte_dir\n"); | ||
208 | return NULL; | ||
209 | } | ||
210 | |||
211 | pte_val(*pte_dir) = physaddr; | ||
212 | virtaddr += PAGE_SIZE; | ||
213 | physaddr += PAGE_SIZE; | ||
214 | size -= PAGE_SIZE; | ||
215 | } | ||
216 | } | ||
217 | #ifdef DEBUG | ||
218 | printk("\n"); | ||
219 | #endif | ||
220 | flush_tlb_all(); | ||
221 | |||
222 | return (void __iomem *)retaddr; | ||
223 | } | ||
224 | EXPORT_SYMBOL(__ioremap); | ||
225 | |||
226 | /* | ||
227 | * Unmap a ioremap()ed region again | ||
228 | */ | ||
229 | void iounmap(void __iomem *addr) | ||
230 | { | ||
231 | #ifdef CONFIG_AMIGA | ||
232 | if ((!MACH_IS_AMIGA) || | ||
233 | (((unsigned long)addr < 0x40000000) || | ||
234 | ((unsigned long)addr > 0x60000000))) | ||
235 | free_io_area((__force void *)addr); | ||
236 | #else | ||
237 | free_io_area((__force void *)addr); | ||
238 | #endif | ||
239 | } | ||
240 | EXPORT_SYMBOL(iounmap); | ||
241 | |||
242 | /* | ||
243 | * __iounmap unmaps nearly everything, so be careful | ||
244 | * it doesn't free currently pointer/page tables anymore but it | ||
245 | * wans't used anyway and might be added later. | ||
246 | */ | ||
247 | void __iounmap(void *addr, unsigned long size) | ||
248 | { | ||
249 | unsigned long virtaddr = (unsigned long)addr; | ||
250 | pgd_t *pgd_dir; | ||
251 | pmd_t *pmd_dir; | ||
252 | pte_t *pte_dir; | ||
253 | |||
254 | while ((long)size > 0) { | ||
255 | pgd_dir = pgd_offset_k(virtaddr); | ||
256 | if (pgd_bad(*pgd_dir)) { | ||
257 | printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir)); | ||
258 | pgd_clear(pgd_dir); | ||
259 | return; | ||
260 | } | ||
261 | pmd_dir = pmd_offset(pgd_dir, virtaddr); | ||
262 | |||
263 | if (CPU_IS_020_OR_030) { | ||
264 | int pmd_off = (virtaddr/PTRTREESIZE) & 15; | ||
265 | int pmd_type = pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK; | ||
266 | |||
267 | if (pmd_type == _PAGE_PRESENT) { | ||
268 | pmd_dir->pmd[pmd_off] = 0; | ||
269 | virtaddr += PTRTREESIZE; | ||
270 | size -= PTRTREESIZE; | ||
271 | continue; | ||
272 | } else if (pmd_type == 0) | ||
273 | continue; | ||
274 | } | ||
275 | |||
276 | if (pmd_bad(*pmd_dir)) { | ||
277 | printk("iounmap: bad pmd (%08lx)\n", pmd_val(*pmd_dir)); | ||
278 | pmd_clear(pmd_dir); | ||
279 | return; | ||
280 | } | ||
281 | pte_dir = pte_offset_kernel(pmd_dir, virtaddr); | ||
282 | |||
283 | pte_val(*pte_dir) = 0; | ||
284 | virtaddr += PAGE_SIZE; | ||
285 | size -= PAGE_SIZE; | ||
286 | } | ||
287 | |||
288 | flush_tlb_all(); | ||
289 | } | ||
290 | |||
291 | /* | ||
292 | * Set new cache mode for some kernel address space. | ||
293 | * The caller must push data for that range itself, if such data may already | ||
294 | * be in the cache. | ||
295 | */ | ||
296 | void kernel_set_cachemode(void *addr, unsigned long size, int cmode) | ||
297 | { | ||
298 | unsigned long virtaddr = (unsigned long)addr; | ||
299 | pgd_t *pgd_dir; | ||
300 | pmd_t *pmd_dir; | ||
301 | pte_t *pte_dir; | ||
302 | |||
303 | if (CPU_IS_040_OR_060) { | ||
304 | switch (cmode) { | ||
305 | case IOMAP_FULL_CACHING: | ||
306 | cmode = _PAGE_CACHE040; | ||
307 | break; | ||
308 | case IOMAP_NOCACHE_SER: | ||
309 | default: | ||
310 | cmode = _PAGE_NOCACHE_S; | ||
311 | break; | ||
312 | case IOMAP_NOCACHE_NONSER: | ||
313 | cmode = _PAGE_NOCACHE; | ||
314 | break; | ||
315 | case IOMAP_WRITETHROUGH: | ||
316 | cmode = _PAGE_CACHE040W; | ||
317 | break; | ||
318 | } | ||
319 | } else { | ||
320 | switch (cmode) { | ||
321 | case IOMAP_NOCACHE_SER: | ||
322 | case IOMAP_NOCACHE_NONSER: | ||
323 | default: | ||
324 | cmode = _PAGE_NOCACHE030; | ||
325 | break; | ||
326 | case IOMAP_FULL_CACHING: | ||
327 | case IOMAP_WRITETHROUGH: | ||
328 | cmode = 0; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | while ((long)size > 0) { | ||
333 | pgd_dir = pgd_offset_k(virtaddr); | ||
334 | if (pgd_bad(*pgd_dir)) { | ||
335 | printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir)); | ||
336 | pgd_clear(pgd_dir); | ||
337 | return; | ||
338 | } | ||
339 | pmd_dir = pmd_offset(pgd_dir, virtaddr); | ||
340 | |||
341 | if (CPU_IS_020_OR_030) { | ||
342 | int pmd_off = (virtaddr/PTRTREESIZE) & 15; | ||
343 | |||
344 | if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) { | ||
345 | pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] & | ||
346 | _CACHEMASK040) | cmode; | ||
347 | virtaddr += PTRTREESIZE; | ||
348 | size -= PTRTREESIZE; | ||
349 | continue; | ||
350 | } | ||
351 | } | ||
352 | |||
353 | if (pmd_bad(*pmd_dir)) { | ||
354 | printk("iocachemode: bad pmd (%08lx)\n", pmd_val(*pmd_dir)); | ||
355 | pmd_clear(pmd_dir); | ||
356 | return; | ||
357 | } | ||
358 | pte_dir = pte_offset_kernel(pmd_dir, virtaddr); | ||
359 | |||
360 | pte_val(*pte_dir) = (pte_val(*pte_dir) & _CACHEMASK040) | cmode; | ||
361 | virtaddr += PAGE_SIZE; | ||
362 | size -= PAGE_SIZE; | ||
363 | } | ||
364 | |||
365 | flush_tlb_all(); | ||
366 | } | ||
367 | EXPORT_SYMBOL(kernel_set_cachemode); | ||
diff --git a/arch/m68knommu/mm/kmap.c b/arch/m68k/mm/kmap_no.c index ece8d5ad4e6c..ece8d5ad4e6c 100644 --- a/arch/m68knommu/mm/kmap.c +++ b/arch/m68k/mm/kmap_no.c | |||
diff --git a/arch/m68knommu/platform/5206/Makefile b/arch/m68k/platform/5206/Makefile index b5db05625cfa..b5db05625cfa 100644 --- a/arch/m68knommu/platform/5206/Makefile +++ b/arch/m68k/platform/5206/Makefile | |||
diff --git a/arch/m68knommu/platform/5206/config.c b/arch/m68k/platform/5206/config.c index 9c335465e66d..9c335465e66d 100644 --- a/arch/m68knommu/platform/5206/config.c +++ b/arch/m68k/platform/5206/config.c | |||
diff --git a/arch/m68knommu/platform/5206/gpio.c b/arch/m68k/platform/5206/gpio.c index b9ab4a120f28..b9ab4a120f28 100644 --- a/arch/m68knommu/platform/5206/gpio.c +++ b/arch/m68k/platform/5206/gpio.c | |||
diff --git a/arch/m68knommu/platform/5206e/Makefile b/arch/m68k/platform/5206e/Makefile index b5db05625cfa..b5db05625cfa 100644 --- a/arch/m68knommu/platform/5206e/Makefile +++ b/arch/m68k/platform/5206e/Makefile | |||
diff --git a/arch/m68knommu/platform/5206e/config.c b/arch/m68k/platform/5206e/config.c index 942397984c66..942397984c66 100644 --- a/arch/m68knommu/platform/5206e/config.c +++ b/arch/m68k/platform/5206e/config.c | |||
diff --git a/arch/m68knommu/platform/5206e/gpio.c b/arch/m68k/platform/5206e/gpio.c index b9ab4a120f28..b9ab4a120f28 100644 --- a/arch/m68knommu/platform/5206e/gpio.c +++ b/arch/m68k/platform/5206e/gpio.c | |||
diff --git a/arch/m68knommu/platform/520x/Makefile b/arch/m68k/platform/520x/Makefile index ad3f4e5a57ce..ad3f4e5a57ce 100644 --- a/arch/m68knommu/platform/520x/Makefile +++ b/arch/m68k/platform/520x/Makefile | |||
diff --git a/arch/m68knommu/platform/520x/config.c b/arch/m68k/platform/520x/config.c index 621238f1a219..621238f1a219 100644 --- a/arch/m68knommu/platform/520x/config.c +++ b/arch/m68k/platform/520x/config.c | |||
diff --git a/arch/m68knommu/platform/520x/gpio.c b/arch/m68k/platform/520x/gpio.c index d757328563d1..d757328563d1 100644 --- a/arch/m68knommu/platform/520x/gpio.c +++ b/arch/m68k/platform/520x/gpio.c | |||
diff --git a/arch/m68knommu/platform/523x/Makefile b/arch/m68k/platform/523x/Makefile index c04b8f71c88c..c04b8f71c88c 100644 --- a/arch/m68knommu/platform/523x/Makefile +++ b/arch/m68k/platform/523x/Makefile | |||
diff --git a/arch/m68knommu/platform/523x/config.c b/arch/m68k/platform/523x/config.c index 418a76feb1e3..418a76feb1e3 100644 --- a/arch/m68knommu/platform/523x/config.c +++ b/arch/m68k/platform/523x/config.c | |||
diff --git a/arch/m68knommu/platform/523x/gpio.c b/arch/m68k/platform/523x/gpio.c index 327ebf142c8e..327ebf142c8e 100644 --- a/arch/m68knommu/platform/523x/gpio.c +++ b/arch/m68k/platform/523x/gpio.c | |||
diff --git a/arch/m68knommu/platform/5249/Makefile b/arch/m68k/platform/5249/Makefile index 4bed30fd0073..4bed30fd0073 100644 --- a/arch/m68knommu/platform/5249/Makefile +++ b/arch/m68k/platform/5249/Makefile | |||
diff --git a/arch/m68knommu/platform/5249/config.c b/arch/m68k/platform/5249/config.c index ceb31e5744a6..ceb31e5744a6 100644 --- a/arch/m68knommu/platform/5249/config.c +++ b/arch/m68k/platform/5249/config.c | |||
diff --git a/arch/m68knommu/platform/5249/gpio.c b/arch/m68k/platform/5249/gpio.c index 2b56c6ef65bf..2b56c6ef65bf 100644 --- a/arch/m68knommu/platform/5249/gpio.c +++ b/arch/m68k/platform/5249/gpio.c | |||
diff --git a/arch/m68knommu/platform/5249/intc2.c b/arch/m68k/platform/5249/intc2.c index 8f4b63e17366..8f4b63e17366 100644 --- a/arch/m68knommu/platform/5249/intc2.c +++ b/arch/m68k/platform/5249/intc2.c | |||
diff --git a/arch/m68knommu/platform/5272/Makefile b/arch/m68k/platform/5272/Makefile index 34110fc14301..34110fc14301 100644 --- a/arch/m68knommu/platform/5272/Makefile +++ b/arch/m68k/platform/5272/Makefile | |||
diff --git a/arch/m68knommu/platform/5272/config.c b/arch/m68k/platform/5272/config.c index 65bb582734e1..65bb582734e1 100644 --- a/arch/m68knommu/platform/5272/config.c +++ b/arch/m68k/platform/5272/config.c | |||
diff --git a/arch/m68knommu/platform/5272/gpio.c b/arch/m68k/platform/5272/gpio.c index 57ac10a5d7f7..57ac10a5d7f7 100644 --- a/arch/m68knommu/platform/5272/gpio.c +++ b/arch/m68k/platform/5272/gpio.c | |||
diff --git a/arch/m68knommu/platform/5272/intc.c b/arch/m68k/platform/5272/intc.c index 969ff0a467c6..969ff0a467c6 100644 --- a/arch/m68knommu/platform/5272/intc.c +++ b/arch/m68k/platform/5272/intc.c | |||
diff --git a/arch/m68knommu/platform/527x/Makefile b/arch/m68k/platform/527x/Makefile index 6ac4b57370ea..6ac4b57370ea 100644 --- a/arch/m68knommu/platform/527x/Makefile +++ b/arch/m68k/platform/527x/Makefile | |||
diff --git a/arch/m68knommu/platform/527x/config.c b/arch/m68k/platform/527x/config.c index fa359593b613..fa359593b613 100644 --- a/arch/m68knommu/platform/527x/config.c +++ b/arch/m68k/platform/527x/config.c | |||
diff --git a/arch/m68knommu/platform/527x/gpio.c b/arch/m68k/platform/527x/gpio.c index 205da0aa0f2d..205da0aa0f2d 100644 --- a/arch/m68knommu/platform/527x/gpio.c +++ b/arch/m68k/platform/527x/gpio.c | |||
diff --git a/arch/m68knommu/platform/528x/Makefile b/arch/m68k/platform/528x/Makefile index 6ac4b57370ea..6ac4b57370ea 100644 --- a/arch/m68knommu/platform/528x/Makefile +++ b/arch/m68k/platform/528x/Makefile | |||
diff --git a/arch/m68knommu/platform/528x/config.c b/arch/m68k/platform/528x/config.c index ac39fc661219..ac39fc661219 100644 --- a/arch/m68knommu/platform/528x/config.c +++ b/arch/m68k/platform/528x/config.c | |||
diff --git a/arch/m68knommu/platform/528x/gpio.c b/arch/m68k/platform/528x/gpio.c index 526db665d87e..526db665d87e 100644 --- a/arch/m68knommu/platform/528x/gpio.c +++ b/arch/m68k/platform/528x/gpio.c | |||
diff --git a/arch/m68knommu/platform/5307/Makefile b/arch/m68k/platform/5307/Makefile index d4293b791f2e..d4293b791f2e 100644 --- a/arch/m68knommu/platform/5307/Makefile +++ b/arch/m68k/platform/5307/Makefile | |||
diff --git a/arch/m68knommu/platform/5307/config.c b/arch/m68k/platform/5307/config.c index 00900ac06a9c..00900ac06a9c 100644 --- a/arch/m68knommu/platform/5307/config.c +++ b/arch/m68k/platform/5307/config.c | |||
diff --git a/arch/m68knommu/platform/5307/gpio.c b/arch/m68k/platform/5307/gpio.c index 5850612b4a38..5850612b4a38 100644 --- a/arch/m68knommu/platform/5307/gpio.c +++ b/arch/m68k/platform/5307/gpio.c | |||
diff --git a/arch/m68knommu/platform/5307/nettel.c b/arch/m68k/platform/5307/nettel.c index e925ea4602f8..e925ea4602f8 100644 --- a/arch/m68knommu/platform/5307/nettel.c +++ b/arch/m68k/platform/5307/nettel.c | |||
diff --git a/arch/m68knommu/platform/532x/Makefile b/arch/m68k/platform/532x/Makefile index ce01669399c6..ce01669399c6 100644 --- a/arch/m68knommu/platform/532x/Makefile +++ b/arch/m68k/platform/532x/Makefile | |||
diff --git a/arch/m68knommu/platform/532x/config.c b/arch/m68k/platform/532x/config.c index ca51323f957b..ca51323f957b 100644 --- a/arch/m68knommu/platform/532x/config.c +++ b/arch/m68k/platform/532x/config.c | |||
diff --git a/arch/m68knommu/platform/532x/gpio.c b/arch/m68k/platform/532x/gpio.c index 212a85deac90..212a85deac90 100644 --- a/arch/m68knommu/platform/532x/gpio.c +++ b/arch/m68k/platform/532x/gpio.c | |||
diff --git a/arch/m68knommu/platform/5407/Makefile b/arch/m68k/platform/5407/Makefile index e83fe148eddc..e83fe148eddc 100644 --- a/arch/m68knommu/platform/5407/Makefile +++ b/arch/m68k/platform/5407/Makefile | |||
diff --git a/arch/m68knommu/platform/5407/config.c b/arch/m68k/platform/5407/config.c index 70ea789a400c..70ea789a400c 100644 --- a/arch/m68knommu/platform/5407/config.c +++ b/arch/m68k/platform/5407/config.c | |||
diff --git a/arch/m68knommu/platform/5407/gpio.c b/arch/m68k/platform/5407/gpio.c index 5850612b4a38..5850612b4a38 100644 --- a/arch/m68knommu/platform/5407/gpio.c +++ b/arch/m68k/platform/5407/gpio.c | |||
diff --git a/arch/m68knommu/platform/54xx/Makefile b/arch/m68k/platform/54xx/Makefile index 6cfd090ec3cd..6cfd090ec3cd 100644 --- a/arch/m68knommu/platform/54xx/Makefile +++ b/arch/m68k/platform/54xx/Makefile | |||
diff --git a/arch/m68knommu/platform/54xx/config.c b/arch/m68k/platform/54xx/config.c index 78130984db95..78130984db95 100644 --- a/arch/m68knommu/platform/54xx/config.c +++ b/arch/m68k/platform/54xx/config.c | |||
diff --git a/arch/m68knommu/platform/54xx/firebee.c b/arch/m68k/platform/54xx/firebee.c index 46d50534f981..46d50534f981 100644 --- a/arch/m68knommu/platform/54xx/firebee.c +++ b/arch/m68k/platform/54xx/firebee.c | |||
diff --git a/arch/m68knommu/platform/68328/Makefile b/arch/m68k/platform/68328/Makefile index 5e5435552d56..5e5435552d56 100644 --- a/arch/m68knommu/platform/68328/Makefile +++ b/arch/m68k/platform/68328/Makefile | |||
diff --git a/arch/m68knommu/platform/68328/bootlogo.h b/arch/m68k/platform/68328/bootlogo.h index 67bc2c17386e..67bc2c17386e 100644 --- a/arch/m68knommu/platform/68328/bootlogo.h +++ b/arch/m68k/platform/68328/bootlogo.h | |||
diff --git a/arch/m68knommu/platform/68328/bootlogo.pl b/arch/m68k/platform/68328/bootlogo.pl index b04ae3f50da5..b04ae3f50da5 100644 --- a/arch/m68knommu/platform/68328/bootlogo.pl +++ b/arch/m68k/platform/68328/bootlogo.pl | |||
diff --git a/arch/m68knommu/platform/68328/config.c b/arch/m68k/platform/68328/config.c index a7bd21deb00f..a7bd21deb00f 100644 --- a/arch/m68knommu/platform/68328/config.c +++ b/arch/m68k/platform/68328/config.c | |||
diff --git a/arch/m68knommu/platform/68328/entry.S b/arch/m68k/platform/68328/entry.S index 676960cf022a..676960cf022a 100644 --- a/arch/m68knommu/platform/68328/entry.S +++ b/arch/m68k/platform/68328/entry.S | |||
diff --git a/arch/m68knommu/platform/68328/head-de2.S b/arch/m68k/platform/68328/head-de2.S index f632fdcb93e9..f632fdcb93e9 100644 --- a/arch/m68knommu/platform/68328/head-de2.S +++ b/arch/m68k/platform/68328/head-de2.S | |||
diff --git a/arch/m68knommu/platform/68328/head-pilot.S b/arch/m68k/platform/68328/head-pilot.S index aecff532b343..aecff532b343 100644 --- a/arch/m68knommu/platform/68328/head-pilot.S +++ b/arch/m68k/platform/68328/head-pilot.S | |||
diff --git a/arch/m68knommu/platform/68328/head-ram.S b/arch/m68k/platform/68328/head-ram.S index 7f1aeeacb219..7f1aeeacb219 100644 --- a/arch/m68knommu/platform/68328/head-ram.S +++ b/arch/m68k/platform/68328/head-ram.S | |||
diff --git a/arch/m68knommu/platform/68328/head-rom.S b/arch/m68k/platform/68328/head-rom.S index 6ec77d3ea0b3..6ec77d3ea0b3 100644 --- a/arch/m68knommu/platform/68328/head-rom.S +++ b/arch/m68k/platform/68328/head-rom.S | |||
diff --git a/arch/m68knommu/platform/68328/ints.c b/arch/m68k/platform/68328/ints.c index e5631831a200..e5631831a200 100644 --- a/arch/m68knommu/platform/68328/ints.c +++ b/arch/m68k/platform/68328/ints.c | |||
diff --git a/arch/m68knommu/platform/68328/romvec.S b/arch/m68k/platform/68328/romvec.S index 31084466eae8..31084466eae8 100644 --- a/arch/m68knommu/platform/68328/romvec.S +++ b/arch/m68k/platform/68328/romvec.S | |||
diff --git a/arch/m68knommu/platform/68328/timers.c b/arch/m68k/platform/68328/timers.c index 309f725995bf..309f725995bf 100644 --- a/arch/m68knommu/platform/68328/timers.c +++ b/arch/m68k/platform/68328/timers.c | |||
diff --git a/arch/m68knommu/platform/68360/Makefile b/arch/m68k/platform/68360/Makefile index cf5af73a5789..cf5af73a5789 100644 --- a/arch/m68knommu/platform/68360/Makefile +++ b/arch/m68k/platform/68360/Makefile | |||
diff --git a/arch/m68knommu/platform/68360/commproc.c b/arch/m68k/platform/68360/commproc.c index 8e4e10cc0080..8e4e10cc0080 100644 --- a/arch/m68knommu/platform/68360/commproc.c +++ b/arch/m68k/platform/68360/commproc.c | |||
diff --git a/arch/m68knommu/platform/68360/config.c b/arch/m68k/platform/68360/config.c index 9dd5bca38749..9dd5bca38749 100644 --- a/arch/m68knommu/platform/68360/config.c +++ b/arch/m68k/platform/68360/config.c | |||
diff --git a/arch/m68knommu/platform/68360/entry.S b/arch/m68k/platform/68360/entry.S index 46c1b18c9dcb..46c1b18c9dcb 100644 --- a/arch/m68knommu/platform/68360/entry.S +++ b/arch/m68k/platform/68360/entry.S | |||
diff --git a/arch/m68knommu/platform/68360/head-ram.S b/arch/m68k/platform/68360/head-ram.S index 8eb94fb6b971..8eb94fb6b971 100644 --- a/arch/m68knommu/platform/68360/head-ram.S +++ b/arch/m68k/platform/68360/head-ram.S | |||
diff --git a/arch/m68knommu/platform/68360/head-rom.S b/arch/m68k/platform/68360/head-rom.S index 97510e55b802..97510e55b802 100644 --- a/arch/m68knommu/platform/68360/head-rom.S +++ b/arch/m68k/platform/68360/head-rom.S | |||
diff --git a/arch/m68knommu/platform/68360/ints.c b/arch/m68k/platform/68360/ints.c index 8de3feb568c6..8de3feb568c6 100644 --- a/arch/m68knommu/platform/68360/ints.c +++ b/arch/m68k/platform/68360/ints.c | |||
diff --git a/arch/m68knommu/platform/68EZ328/Makefile b/arch/m68k/platform/68EZ328/Makefile index ee97735a242c..ee97735a242c 100644 --- a/arch/m68knommu/platform/68EZ328/Makefile +++ b/arch/m68k/platform/68EZ328/Makefile | |||
diff --git a/arch/m68knommu/platform/68EZ328/bootlogo.h b/arch/m68k/platform/68EZ328/bootlogo.h index e842bdae5839..e842bdae5839 100644 --- a/arch/m68knommu/platform/68EZ328/bootlogo.h +++ b/arch/m68k/platform/68EZ328/bootlogo.h | |||
diff --git a/arch/m68knommu/platform/68EZ328/config.c b/arch/m68k/platform/68EZ328/config.c index 1be1a16f6896..1be1a16f6896 100644 --- a/arch/m68knommu/platform/68EZ328/config.c +++ b/arch/m68k/platform/68EZ328/config.c | |||
diff --git a/arch/m68knommu/platform/68VZ328/Makefile b/arch/m68k/platform/68VZ328/Makefile index 447ffa0fd7c7..447ffa0fd7c7 100644 --- a/arch/m68knommu/platform/68VZ328/Makefile +++ b/arch/m68k/platform/68VZ328/Makefile | |||
diff --git a/arch/m68knommu/platform/68VZ328/config.c b/arch/m68k/platform/68VZ328/config.c index eabaabe8af36..eabaabe8af36 100644 --- a/arch/m68knommu/platform/68VZ328/config.c +++ b/arch/m68k/platform/68VZ328/config.c | |||
diff --git a/arch/m68knommu/platform/Makefile b/arch/m68k/platform/Makefile index fc932bf65d34..fc932bf65d34 100644 --- a/arch/m68knommu/platform/Makefile +++ b/arch/m68k/platform/Makefile | |||
diff --git a/arch/m68knommu/platform/coldfire/Makefile b/arch/m68k/platform/coldfire/Makefile index a8967baabd72..a8967baabd72 100644 --- a/arch/m68knommu/platform/coldfire/Makefile +++ b/arch/m68k/platform/coldfire/Makefile | |||
diff --git a/arch/m68knommu/platform/coldfire/cache.c b/arch/m68k/platform/coldfire/cache.c index 235d3c4f4f0f..235d3c4f4f0f 100644 --- a/arch/m68knommu/platform/coldfire/cache.c +++ b/arch/m68k/platform/coldfire/cache.c | |||
diff --git a/arch/m68knommu/platform/coldfire/clk.c b/arch/m68k/platform/coldfire/clk.c index 9f1260c5e2ad..9f1260c5e2ad 100644 --- a/arch/m68knommu/platform/coldfire/clk.c +++ b/arch/m68k/platform/coldfire/clk.c | |||
diff --git a/arch/m68knommu/platform/coldfire/dma.c b/arch/m68k/platform/coldfire/dma.c index e88b95e2cc62..e88b95e2cc62 100644 --- a/arch/m68knommu/platform/coldfire/dma.c +++ b/arch/m68k/platform/coldfire/dma.c | |||
diff --git a/arch/m68knommu/platform/coldfire/dma_timer.c b/arch/m68k/platform/coldfire/dma_timer.c index a5f562823d7a..a5f562823d7a 100644 --- a/arch/m68knommu/platform/coldfire/dma_timer.c +++ b/arch/m68k/platform/coldfire/dma_timer.c | |||
diff --git a/arch/m68knommu/platform/coldfire/entry.S b/arch/m68k/platform/coldfire/entry.S index 5837cf080b6d..5837cf080b6d 100644 --- a/arch/m68knommu/platform/coldfire/entry.S +++ b/arch/m68k/platform/coldfire/entry.S | |||
diff --git a/arch/m68knommu/platform/coldfire/gpio.c b/arch/m68k/platform/coldfire/gpio.c index ff0045793450..ff0045793450 100644 --- a/arch/m68knommu/platform/coldfire/gpio.c +++ b/arch/m68k/platform/coldfire/gpio.c | |||
diff --git a/arch/m68knommu/platform/coldfire/head.S b/arch/m68k/platform/coldfire/head.S index 129bff4956b5..129bff4956b5 100644 --- a/arch/m68knommu/platform/coldfire/head.S +++ b/arch/m68k/platform/coldfire/head.S | |||
diff --git a/arch/m68knommu/platform/coldfire/intc-2.c b/arch/m68k/platform/coldfire/intc-2.c index 2cbfbf035db9..2cbfbf035db9 100644 --- a/arch/m68knommu/platform/coldfire/intc-2.c +++ b/arch/m68k/platform/coldfire/intc-2.c | |||
diff --git a/arch/m68knommu/platform/coldfire/intc-simr.c b/arch/m68k/platform/coldfire/intc-simr.c index e642b24ab729..e642b24ab729 100644 --- a/arch/m68knommu/platform/coldfire/intc-simr.c +++ b/arch/m68k/platform/coldfire/intc-simr.c | |||
diff --git a/arch/m68knommu/platform/coldfire/intc.c b/arch/m68k/platform/coldfire/intc.c index d648081a63f6..d648081a63f6 100644 --- a/arch/m68knommu/platform/coldfire/intc.c +++ b/arch/m68k/platform/coldfire/intc.c | |||
diff --git a/arch/m68knommu/platform/coldfire/pinmux.c b/arch/m68k/platform/coldfire/pinmux.c index 8c62b825939f..8c62b825939f 100644 --- a/arch/m68knommu/platform/coldfire/pinmux.c +++ b/arch/m68k/platform/coldfire/pinmux.c | |||
diff --git a/arch/m68knommu/platform/coldfire/pit.c b/arch/m68k/platform/coldfire/pit.c index c2b980926bec..c2b980926bec 100644 --- a/arch/m68knommu/platform/coldfire/pit.c +++ b/arch/m68k/platform/coldfire/pit.c | |||
diff --git a/arch/m68knommu/platform/coldfire/sltimers.c b/arch/m68k/platform/coldfire/sltimers.c index 0a1b937c3e18..0a1b937c3e18 100644 --- a/arch/m68knommu/platform/coldfire/sltimers.c +++ b/arch/m68k/platform/coldfire/sltimers.c | |||
diff --git a/arch/m68knommu/platform/coldfire/timers.c b/arch/m68k/platform/coldfire/timers.c index 60242f65fea9..60242f65fea9 100644 --- a/arch/m68knommu/platform/coldfire/timers.c +++ b/arch/m68k/platform/coldfire/timers.c | |||
diff --git a/arch/m68knommu/platform/coldfire/vectors.c b/arch/m68k/platform/coldfire/vectors.c index a21d3f870b7a..a21d3f870b7a 100644 --- a/arch/m68knommu/platform/coldfire/vectors.c +++ b/arch/m68k/platform/coldfire/vectors.c | |||
diff --git a/arch/m68knommu/Kconfig.debug b/arch/m68knommu/Kconfig.debug deleted file mode 100644 index ed6d9a83bfdb..000000000000 --- a/arch/m68knommu/Kconfig.debug +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | menu "Kernel hacking" | ||
2 | |||
3 | source "lib/Kconfig.debug" | ||
4 | |||
5 | config FULLDEBUG | ||
6 | bool "Full Symbolic/Source Debugging support" | ||
7 | help | ||
8 | Enable debugging symbols on kernel build. | ||
9 | |||
10 | config HIGHPROFILE | ||
11 | bool "Use fast second timer for profiling" | ||
12 | depends on COLDFIRE | ||
13 | help | ||
14 | Use a fast secondary clock to produce profiling information. | ||
15 | |||
16 | config BOOTPARAM | ||
17 | bool 'Compiled-in Kernel Boot Parameter' | ||
18 | |||
19 | config BOOTPARAM_STRING | ||
20 | string 'Kernel Boot Parameter' | ||
21 | default 'console=ttyS0,19200' | ||
22 | depends on BOOTPARAM | ||
23 | |||
24 | config NO_KERNEL_MSG | ||
25 | bool "Suppress Kernel BUG Messages" | ||
26 | help | ||
27 | Do not output any debug BUG messages within the kernel. | ||
28 | |||
29 | config BDM_DISABLE | ||
30 | bool "Disable BDM signals" | ||
31 | depends on (EXPERIMENTAL && COLDFIRE) | ||
32 | help | ||
33 | Disable the ColdFire CPU's BDM signals. | ||
34 | |||
35 | endmenu | ||
diff --git a/arch/m68knommu/defconfig b/arch/m68knommu/defconfig deleted file mode 100644 index 2f5655c577af..000000000000 --- a/arch/m68knommu/defconfig +++ /dev/null | |||
@@ -1,74 +0,0 @@ | |||
1 | CONFIG_EXPERIMENTAL=y | ||
2 | CONFIG_LOG_BUF_SHIFT=14 | ||
3 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set | ||
4 | CONFIG_EXPERT=y | ||
5 | # CONFIG_KALLSYMS is not set | ||
6 | # CONFIG_HOTPLUG is not set | ||
7 | # CONFIG_FUTEX is not set | ||
8 | # CONFIG_EPOLL is not set | ||
9 | # CONFIG_SIGNALFD is not set | ||
10 | # CONFIG_TIMERFD is not set | ||
11 | # CONFIG_EVENTFD is not set | ||
12 | # CONFIG_AIO is not set | ||
13 | # CONFIG_VM_EVENT_COUNTERS is not set | ||
14 | # CONFIG_COMPAT_BRK is not set | ||
15 | # CONFIG_BLK_DEV_BSG is not set | ||
16 | # CONFIG_IOSCHED_DEADLINE is not set | ||
17 | # CONFIG_IOSCHED_CFQ is not set | ||
18 | CONFIG_M520x=y | ||
19 | CONFIG_CLOCK_SET=y | ||
20 | CONFIG_CLOCK_FREQ=166666666 | ||
21 | CONFIG_CLOCK_DIV=2 | ||
22 | CONFIG_M5208EVB=y | ||
23 | # CONFIG_4KSTACKS is not set | ||
24 | CONFIG_RAMBASE=0x40000000 | ||
25 | CONFIG_RAMSIZE=0x2000000 | ||
26 | CONFIG_VECTORBASE=0x40000000 | ||
27 | CONFIG_KERNELBASE=0x40020000 | ||
28 | CONFIG_RAM16BIT=y | ||
29 | CONFIG_BINFMT_FLAT=y | ||
30 | CONFIG_NET=y | ||
31 | CONFIG_PACKET=y | ||
32 | CONFIG_UNIX=y | ||
33 | CONFIG_INET=y | ||
34 | # CONFIG_INET_XFRM_MODE_TRANSPORT is not set | ||
35 | # CONFIG_INET_XFRM_MODE_TUNNEL is not set | ||
36 | # CONFIG_INET_XFRM_MODE_BEET is not set | ||
37 | # CONFIG_INET_LRO is not set | ||
38 | # CONFIG_INET_DIAG is not set | ||
39 | # CONFIG_IPV6 is not set | ||
40 | CONFIG_MTD=y | ||
41 | CONFIG_MTD_PARTITIONS=y | ||
42 | CONFIG_MTD_CHAR=y | ||
43 | CONFIG_MTD_BLOCK=y | ||
44 | CONFIG_MTD_RAM=y | ||
45 | CONFIG_MTD_UCLINUX=y | ||
46 | CONFIG_BLK_DEV_RAM=y | ||
47 | # CONFIG_MISC_DEVICES is not set | ||
48 | CONFIG_NETDEVICES=y | ||
49 | CONFIG_NET_ETHERNET=y | ||
50 | CONFIG_FEC=y | ||
51 | # CONFIG_NETDEV_1000 is not set | ||
52 | # CONFIG_NETDEV_10000 is not set | ||
53 | # CONFIG_INPUT is not set | ||
54 | # CONFIG_SERIO is not set | ||
55 | # CONFIG_VT is not set | ||
56 | CONFIG_SERIAL_MCF=y | ||
57 | CONFIG_SERIAL_MCF_BAUDRATE=115200 | ||
58 | CONFIG_SERIAL_MCF_CONSOLE=y | ||
59 | # CONFIG_UNIX98_PTYS is not set | ||
60 | # CONFIG_HW_RANDOM is not set | ||
61 | # CONFIG_HWMON is not set | ||
62 | # CONFIG_USB_SUPPORT is not set | ||
63 | CONFIG_EXT2_FS=y | ||
64 | # CONFIG_FILE_LOCKING is not set | ||
65 | # CONFIG_DNOTIFY is not set | ||
66 | # CONFIG_SYSFS is not set | ||
67 | CONFIG_ROMFS_FS=y | ||
68 | CONFIG_ROMFS_BACKED_BY_MTD=y | ||
69 | # CONFIG_NETWORK_FILESYSTEMS is not set | ||
70 | # CONFIG_RCU_CPU_STALL_DETECTOR is not set | ||
71 | CONFIG_SYSCTL_SYSCALL_CHECK=y | ||
72 | CONFIG_FULLDEBUG=y | ||
73 | CONFIG_BOOTPARAM=y | ||
74 | CONFIG_BOOTPARAM_STRING="root=/dev/mtdblock0" | ||
diff --git a/arch/m68knommu/kernel/.gitignore b/arch/m68knommu/kernel/.gitignore deleted file mode 100644 index c5f676c3c224..000000000000 --- a/arch/m68knommu/kernel/.gitignore +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | vmlinux.lds | ||
diff --git a/arch/m68knommu/lib/ashldi3.c b/arch/m68knommu/lib/ashldi3.c deleted file mode 100644 index 008403eb8ce2..000000000000 --- a/arch/m68knommu/lib/ashldi3.c +++ /dev/null | |||
@@ -1,62 +0,0 @@ | |||
1 | /* ashrdi3.c extracted from gcc-2.95.2/libgcc2.c which is: */ | ||
2 | /* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc. | ||
3 | |||
4 | This file is part of GNU CC. | ||
5 | |||
6 | GNU CC 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, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | GNU CC is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with GNU CC; see the file COPYING. If not, write to | ||
18 | the Free Software Foundation, 59 Temple Place - Suite 330, | ||
19 | Boston, MA 02111-1307, USA. */ | ||
20 | |||
21 | #define BITS_PER_UNIT 8 | ||
22 | |||
23 | typedef int SItype __attribute__ ((mode (SI))); | ||
24 | typedef unsigned int USItype __attribute__ ((mode (SI))); | ||
25 | typedef int DItype __attribute__ ((mode (DI))); | ||
26 | typedef int word_type __attribute__ ((mode (__word__))); | ||
27 | |||
28 | struct DIstruct {SItype high, low;}; | ||
29 | |||
30 | typedef union | ||
31 | { | ||
32 | struct DIstruct s; | ||
33 | DItype ll; | ||
34 | } DIunion; | ||
35 | |||
36 | DItype | ||
37 | __ashldi3 (DItype u, word_type b) | ||
38 | { | ||
39 | DIunion w; | ||
40 | word_type bm; | ||
41 | DIunion uu; | ||
42 | |||
43 | if (b == 0) | ||
44 | return u; | ||
45 | |||
46 | uu.ll = u; | ||
47 | |||
48 | bm = (sizeof (SItype) * BITS_PER_UNIT) - b; | ||
49 | if (bm <= 0) | ||
50 | { | ||
51 | w.s.low = 0; | ||
52 | w.s.high = (USItype)uu.s.low << -bm; | ||
53 | } | ||
54 | else | ||
55 | { | ||
56 | USItype carries = (USItype)uu.s.low >> bm; | ||
57 | w.s.low = (USItype)uu.s.low << b; | ||
58 | w.s.high = ((USItype)uu.s.high << b) | carries; | ||
59 | } | ||
60 | |||
61 | return w.ll; | ||
62 | } | ||
diff --git a/arch/m68knommu/lib/lshrdi3.c b/arch/m68knommu/lib/lshrdi3.c deleted file mode 100644 index 93b1cb6fdee8..000000000000 --- a/arch/m68knommu/lib/lshrdi3.c +++ /dev/null | |||
@@ -1,62 +0,0 @@ | |||
1 | /* lshrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */ | ||
2 | /* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. | ||
3 | |||
4 | This file is part of GNU CC. | ||
5 | |||
6 | GNU CC 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, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | GNU CC is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with GNU CC; see the file COPYING. If not, write to | ||
18 | the Free Software Foundation, 59 Temple Place - Suite 330, | ||
19 | Boston, MA 02111-1307, USA. */ | ||
20 | |||
21 | #define BITS_PER_UNIT 8 | ||
22 | |||
23 | typedef int SItype __attribute__ ((mode (SI))); | ||
24 | typedef unsigned int USItype __attribute__ ((mode (SI))); | ||
25 | typedef int DItype __attribute__ ((mode (DI))); | ||
26 | typedef int word_type __attribute__ ((mode (__word__))); | ||
27 | |||
28 | struct DIstruct {SItype high, low;}; | ||
29 | |||
30 | typedef union | ||
31 | { | ||
32 | struct DIstruct s; | ||
33 | DItype ll; | ||
34 | } DIunion; | ||
35 | |||
36 | DItype | ||
37 | __lshrdi3 (DItype u, word_type b) | ||
38 | { | ||
39 | DIunion w; | ||
40 | word_type bm; | ||
41 | DIunion uu; | ||
42 | |||
43 | if (b == 0) | ||
44 | return u; | ||
45 | |||
46 | uu.ll = u; | ||
47 | |||
48 | bm = (sizeof (SItype) * BITS_PER_UNIT) - b; | ||
49 | if (bm <= 0) | ||
50 | { | ||
51 | w.s.high = 0; | ||
52 | w.s.low = (USItype)uu.s.high >> -bm; | ||
53 | } | ||
54 | else | ||
55 | { | ||
56 | USItype carries = (USItype)uu.s.high << bm; | ||
57 | w.s.high = (USItype)uu.s.high >> b; | ||
58 | w.s.low = ((USItype)uu.s.low >> b) | carries; | ||
59 | } | ||
60 | |||
61 | return w.ll; | ||
62 | } | ||
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 9905e2e85de4..83aa5fb8e8f1 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
@@ -22,6 +22,7 @@ config MIPS | |||
22 | select HAVE_DMA_API_DEBUG | 22 | select HAVE_DMA_API_DEBUG |
23 | select HAVE_GENERIC_HARDIRQS | 23 | select HAVE_GENERIC_HARDIRQS |
24 | select GENERIC_IRQ_PROBE | 24 | select GENERIC_IRQ_PROBE |
25 | select GENERIC_IRQ_SHOW | ||
25 | select HAVE_ARCH_JUMP_LABEL | 26 | select HAVE_ARCH_JUMP_LABEL |
26 | 27 | ||
27 | menu "Machine selection" | 28 | menu "Machine selection" |
@@ -862,6 +863,9 @@ config GPIO_TXX9 | |||
862 | config CFE | 863 | config CFE |
863 | bool | 864 | bool |
864 | 865 | ||
866 | config ARCH_DMA_ADDR_T_64BIT | ||
867 | def_bool (HIGHMEM && 64BIT_PHYS_ADDR) || 64BIT | ||
868 | |||
865 | config DMA_COHERENT | 869 | config DMA_COHERENT |
866 | bool | 870 | bool |
867 | 871 | ||
diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c index 9f78ada83b3c..55dd7c888517 100644 --- a/arch/mips/alchemy/common/irq.c +++ b/arch/mips/alchemy/common/irq.c | |||
@@ -39,7 +39,7 @@ | |||
39 | #include <asm/mach-pb1x00/pb1000.h> | 39 | #include <asm/mach-pb1x00/pb1000.h> |
40 | #endif | 40 | #endif |
41 | 41 | ||
42 | static int au1x_ic_settype(unsigned int irq, unsigned int flow_type); | 42 | static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type); |
43 | 43 | ||
44 | /* NOTE on interrupt priorities: The original writers of this code said: | 44 | /* NOTE on interrupt priorities: The original writers of this code said: |
45 | * | 45 | * |
@@ -218,17 +218,17 @@ struct au1xxx_irqmap au1200_irqmap[] __initdata = { | |||
218 | }; | 218 | }; |
219 | 219 | ||
220 | 220 | ||
221 | static void au1x_ic0_unmask(unsigned int irq_nr) | 221 | static void au1x_ic0_unmask(struct irq_data *d) |
222 | { | 222 | { |
223 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; | 223 | unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; |
224 | au_writel(1 << bit, IC0_MASKSET); | 224 | au_writel(1 << bit, IC0_MASKSET); |
225 | au_writel(1 << bit, IC0_WAKESET); | 225 | au_writel(1 << bit, IC0_WAKESET); |
226 | au_sync(); | 226 | au_sync(); |
227 | } | 227 | } |
228 | 228 | ||
229 | static void au1x_ic1_unmask(unsigned int irq_nr) | 229 | static void au1x_ic1_unmask(struct irq_data *d) |
230 | { | 230 | { |
231 | unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE; | 231 | unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; |
232 | au_writel(1 << bit, IC1_MASKSET); | 232 | au_writel(1 << bit, IC1_MASKSET); |
233 | au_writel(1 << bit, IC1_WAKESET); | 233 | au_writel(1 << bit, IC1_WAKESET); |
234 | 234 | ||
@@ -236,31 +236,31 @@ static void au1x_ic1_unmask(unsigned int irq_nr) | |||
236 | * nowhere in the current kernel sources is it disabled. --mlau | 236 | * nowhere in the current kernel sources is it disabled. --mlau |
237 | */ | 237 | */ |
238 | #if defined(CONFIG_MIPS_PB1000) | 238 | #if defined(CONFIG_MIPS_PB1000) |
239 | if (irq_nr == AU1000_GPIO15_INT) | 239 | if (d->irq == AU1000_GPIO15_INT) |
240 | au_writel(0x4000, PB1000_MDR); /* enable int */ | 240 | au_writel(0x4000, PB1000_MDR); /* enable int */ |
241 | #endif | 241 | #endif |
242 | au_sync(); | 242 | au_sync(); |
243 | } | 243 | } |
244 | 244 | ||
245 | static void au1x_ic0_mask(unsigned int irq_nr) | 245 | static void au1x_ic0_mask(struct irq_data *d) |
246 | { | 246 | { |
247 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; | 247 | unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; |
248 | au_writel(1 << bit, IC0_MASKCLR); | 248 | au_writel(1 << bit, IC0_MASKCLR); |
249 | au_writel(1 << bit, IC0_WAKECLR); | 249 | au_writel(1 << bit, IC0_WAKECLR); |
250 | au_sync(); | 250 | au_sync(); |
251 | } | 251 | } |
252 | 252 | ||
253 | static void au1x_ic1_mask(unsigned int irq_nr) | 253 | static void au1x_ic1_mask(struct irq_data *d) |
254 | { | 254 | { |
255 | unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE; | 255 | unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; |
256 | au_writel(1 << bit, IC1_MASKCLR); | 256 | au_writel(1 << bit, IC1_MASKCLR); |
257 | au_writel(1 << bit, IC1_WAKECLR); | 257 | au_writel(1 << bit, IC1_WAKECLR); |
258 | au_sync(); | 258 | au_sync(); |
259 | } | 259 | } |
260 | 260 | ||
261 | static void au1x_ic0_ack(unsigned int irq_nr) | 261 | static void au1x_ic0_ack(struct irq_data *d) |
262 | { | 262 | { |
263 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; | 263 | unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; |
264 | 264 | ||
265 | /* | 265 | /* |
266 | * This may assume that we don't get interrupts from | 266 | * This may assume that we don't get interrupts from |
@@ -271,9 +271,9 @@ static void au1x_ic0_ack(unsigned int irq_nr) | |||
271 | au_sync(); | 271 | au_sync(); |
272 | } | 272 | } |
273 | 273 | ||
274 | static void au1x_ic1_ack(unsigned int irq_nr) | 274 | static void au1x_ic1_ack(struct irq_data *d) |
275 | { | 275 | { |
276 | unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE; | 276 | unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; |
277 | 277 | ||
278 | /* | 278 | /* |
279 | * This may assume that we don't get interrupts from | 279 | * This may assume that we don't get interrupts from |
@@ -284,9 +284,9 @@ static void au1x_ic1_ack(unsigned int irq_nr) | |||
284 | au_sync(); | 284 | au_sync(); |
285 | } | 285 | } |
286 | 286 | ||
287 | static void au1x_ic0_maskack(unsigned int irq_nr) | 287 | static void au1x_ic0_maskack(struct irq_data *d) |
288 | { | 288 | { |
289 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; | 289 | unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; |
290 | 290 | ||
291 | au_writel(1 << bit, IC0_WAKECLR); | 291 | au_writel(1 << bit, IC0_WAKECLR); |
292 | au_writel(1 << bit, IC0_MASKCLR); | 292 | au_writel(1 << bit, IC0_MASKCLR); |
@@ -295,9 +295,9 @@ static void au1x_ic0_maskack(unsigned int irq_nr) | |||
295 | au_sync(); | 295 | au_sync(); |
296 | } | 296 | } |
297 | 297 | ||
298 | static void au1x_ic1_maskack(unsigned int irq_nr) | 298 | static void au1x_ic1_maskack(struct irq_data *d) |
299 | { | 299 | { |
300 | unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE; | 300 | unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; |
301 | 301 | ||
302 | au_writel(1 << bit, IC1_WAKECLR); | 302 | au_writel(1 << bit, IC1_WAKECLR); |
303 | au_writel(1 << bit, IC1_MASKCLR); | 303 | au_writel(1 << bit, IC1_MASKCLR); |
@@ -306,9 +306,9 @@ static void au1x_ic1_maskack(unsigned int irq_nr) | |||
306 | au_sync(); | 306 | au_sync(); |
307 | } | 307 | } |
308 | 308 | ||
309 | static int au1x_ic1_setwake(unsigned int irq, unsigned int on) | 309 | static int au1x_ic1_setwake(struct irq_data *d, unsigned int on) |
310 | { | 310 | { |
311 | int bit = irq - AU1000_INTC1_INT_BASE; | 311 | int bit = d->irq - AU1000_INTC1_INT_BASE; |
312 | unsigned long wakemsk, flags; | 312 | unsigned long wakemsk, flags; |
313 | 313 | ||
314 | /* only GPIO 0-7 can act as wakeup source. Fortunately these | 314 | /* only GPIO 0-7 can act as wakeup source. Fortunately these |
@@ -336,28 +336,30 @@ static int au1x_ic1_setwake(unsigned int irq, unsigned int on) | |||
336 | */ | 336 | */ |
337 | static struct irq_chip au1x_ic0_chip = { | 337 | static struct irq_chip au1x_ic0_chip = { |
338 | .name = "Alchemy-IC0", | 338 | .name = "Alchemy-IC0", |
339 | .ack = au1x_ic0_ack, | 339 | .irq_ack = au1x_ic0_ack, |
340 | .mask = au1x_ic0_mask, | 340 | .irq_mask = au1x_ic0_mask, |
341 | .mask_ack = au1x_ic0_maskack, | 341 | .irq_mask_ack = au1x_ic0_maskack, |
342 | .unmask = au1x_ic0_unmask, | 342 | .irq_unmask = au1x_ic0_unmask, |
343 | .set_type = au1x_ic_settype, | 343 | .irq_set_type = au1x_ic_settype, |
344 | }; | 344 | }; |
345 | 345 | ||
346 | static struct irq_chip au1x_ic1_chip = { | 346 | static struct irq_chip au1x_ic1_chip = { |
347 | .name = "Alchemy-IC1", | 347 | .name = "Alchemy-IC1", |
348 | .ack = au1x_ic1_ack, | 348 | .irq_ack = au1x_ic1_ack, |
349 | .mask = au1x_ic1_mask, | 349 | .irq_mask = au1x_ic1_mask, |
350 | .mask_ack = au1x_ic1_maskack, | 350 | .irq_mask_ack = au1x_ic1_maskack, |
351 | .unmask = au1x_ic1_unmask, | 351 | .irq_unmask = au1x_ic1_unmask, |
352 | .set_type = au1x_ic_settype, | 352 | .irq_set_type = au1x_ic_settype, |
353 | .set_wake = au1x_ic1_setwake, | 353 | .irq_set_wake = au1x_ic1_setwake, |
354 | }; | 354 | }; |
355 | 355 | ||
356 | static int au1x_ic_settype(unsigned int irq, unsigned int flow_type) | 356 | static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type) |
357 | { | 357 | { |
358 | struct irq_chip *chip; | 358 | struct irq_chip *chip; |
359 | unsigned long icr[6]; | 359 | unsigned long icr[6]; |
360 | unsigned int bit, ic; | 360 | unsigned int bit, ic, irq = d->irq; |
361 | irq_flow_handler_t handler = NULL; | ||
362 | unsigned char *name = NULL; | ||
361 | int ret; | 363 | int ret; |
362 | 364 | ||
363 | if (irq >= AU1000_INTC1_INT_BASE) { | 365 | if (irq >= AU1000_INTC1_INT_BASE) { |
@@ -387,47 +389,47 @@ static int au1x_ic_settype(unsigned int irq, unsigned int flow_type) | |||
387 | au_writel(1 << bit, icr[5]); | 389 | au_writel(1 << bit, icr[5]); |
388 | au_writel(1 << bit, icr[4]); | 390 | au_writel(1 << bit, icr[4]); |
389 | au_writel(1 << bit, icr[0]); | 391 | au_writel(1 << bit, icr[0]); |
390 | set_irq_chip_and_handler_name(irq, chip, | 392 | handler = handle_edge_irq; |
391 | handle_edge_irq, "riseedge"); | 393 | name = "riseedge"; |
392 | break; | 394 | break; |
393 | case IRQ_TYPE_EDGE_FALLING: /* 0:1:0 */ | 395 | case IRQ_TYPE_EDGE_FALLING: /* 0:1:0 */ |
394 | au_writel(1 << bit, icr[5]); | 396 | au_writel(1 << bit, icr[5]); |
395 | au_writel(1 << bit, icr[1]); | 397 | au_writel(1 << bit, icr[1]); |
396 | au_writel(1 << bit, icr[3]); | 398 | au_writel(1 << bit, icr[3]); |
397 | set_irq_chip_and_handler_name(irq, chip, | 399 | handler = handle_edge_irq; |
398 | handle_edge_irq, "falledge"); | 400 | name = "falledge"; |
399 | break; | 401 | break; |
400 | case IRQ_TYPE_EDGE_BOTH: /* 0:1:1 */ | 402 | case IRQ_TYPE_EDGE_BOTH: /* 0:1:1 */ |
401 | au_writel(1 << bit, icr[5]); | 403 | au_writel(1 << bit, icr[5]); |
402 | au_writel(1 << bit, icr[1]); | 404 | au_writel(1 << bit, icr[1]); |
403 | au_writel(1 << bit, icr[0]); | 405 | au_writel(1 << bit, icr[0]); |
404 | set_irq_chip_and_handler_name(irq, chip, | 406 | handler = handle_edge_irq; |
405 | handle_edge_irq, "bothedge"); | 407 | name = "bothedge"; |
406 | break; | 408 | break; |
407 | case IRQ_TYPE_LEVEL_HIGH: /* 1:0:1 */ | 409 | case IRQ_TYPE_LEVEL_HIGH: /* 1:0:1 */ |
408 | au_writel(1 << bit, icr[2]); | 410 | au_writel(1 << bit, icr[2]); |
409 | au_writel(1 << bit, icr[4]); | 411 | au_writel(1 << bit, icr[4]); |
410 | au_writel(1 << bit, icr[0]); | 412 | au_writel(1 << bit, icr[0]); |
411 | set_irq_chip_and_handler_name(irq, chip, | 413 | handler = handle_level_irq; |
412 | handle_level_irq, "hilevel"); | 414 | name = "hilevel"; |
413 | break; | 415 | break; |
414 | case IRQ_TYPE_LEVEL_LOW: /* 1:1:0 */ | 416 | case IRQ_TYPE_LEVEL_LOW: /* 1:1:0 */ |
415 | au_writel(1 << bit, icr[2]); | 417 | au_writel(1 << bit, icr[2]); |
416 | au_writel(1 << bit, icr[1]); | 418 | au_writel(1 << bit, icr[1]); |
417 | au_writel(1 << bit, icr[3]); | 419 | au_writel(1 << bit, icr[3]); |
418 | set_irq_chip_and_handler_name(irq, chip, | 420 | handler = handle_level_irq; |
419 | handle_level_irq, "lowlevel"); | 421 | name = "lowlevel"; |
420 | break; | 422 | break; |
421 | case IRQ_TYPE_NONE: /* 0:0:0 */ | 423 | case IRQ_TYPE_NONE: /* 0:0:0 */ |
422 | au_writel(1 << bit, icr[5]); | 424 | au_writel(1 << bit, icr[5]); |
423 | au_writel(1 << bit, icr[4]); | 425 | au_writel(1 << bit, icr[4]); |
424 | au_writel(1 << bit, icr[3]); | 426 | au_writel(1 << bit, icr[3]); |
425 | /* set at least chip so we can call set_irq_type() on it */ | ||
426 | set_irq_chip(irq, chip); | ||
427 | break; | 427 | break; |
428 | default: | 428 | default: |
429 | ret = -EINVAL; | 429 | ret = -EINVAL; |
430 | } | 430 | } |
431 | __irq_set_chip_handler_name_locked(d->irq, chip, handler, name); | ||
432 | |||
431 | au_sync(); | 433 | au_sync(); |
432 | 434 | ||
433 | return ret; | 435 | return ret; |
@@ -504,11 +506,11 @@ static void __init au1000_init_irq(struct au1xxx_irqmap *map) | |||
504 | */ | 506 | */ |
505 | for (i = AU1000_INTC0_INT_BASE; | 507 | for (i = AU1000_INTC0_INT_BASE; |
506 | (i < AU1000_INTC0_INT_BASE + 32); i++) | 508 | (i < AU1000_INTC0_INT_BASE + 32); i++) |
507 | au1x_ic_settype(i, IRQ_TYPE_NONE); | 509 | au1x_ic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE); |
508 | 510 | ||
509 | for (i = AU1000_INTC1_INT_BASE; | 511 | for (i = AU1000_INTC1_INT_BASE; |
510 | (i < AU1000_INTC1_INT_BASE + 32); i++) | 512 | (i < AU1000_INTC1_INT_BASE + 32); i++) |
511 | au1x_ic_settype(i, IRQ_TYPE_NONE); | 513 | au1x_ic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE); |
512 | 514 | ||
513 | /* | 515 | /* |
514 | * Initialize IC0, which is fixed per processor. | 516 | * Initialize IC0, which is fixed per processor. |
@@ -526,7 +528,7 @@ static void __init au1000_init_irq(struct au1xxx_irqmap *map) | |||
526 | au_writel(1 << bit, IC0_ASSIGNSET); | 528 | au_writel(1 << bit, IC0_ASSIGNSET); |
527 | } | 529 | } |
528 | 530 | ||
529 | au1x_ic_settype(irq_nr, map->im_type); | 531 | au1x_ic_settype(irq_get_irq_data(irq_nr), map->im_type); |
530 | ++map; | 532 | ++map; |
531 | } | 533 | } |
532 | 534 | ||
diff --git a/arch/mips/alchemy/devboards/bcsr.c b/arch/mips/alchemy/devboards/bcsr.c index c52af8821da0..f91c43a7d5dc 100644 --- a/arch/mips/alchemy/devboards/bcsr.c +++ b/arch/mips/alchemy/devboards/bcsr.c | |||
@@ -97,26 +97,26 @@ static void bcsr_csc_handler(unsigned int irq, struct irq_desc *d) | |||
97 | * CPLD generates tons of spurious interrupts (at least on my DB1200). | 97 | * CPLD generates tons of spurious interrupts (at least on my DB1200). |
98 | * -- mlau | 98 | * -- mlau |
99 | */ | 99 | */ |
100 | static void bcsr_irq_mask(unsigned int irq_nr) | 100 | static void bcsr_irq_mask(struct irq_data *d) |
101 | { | 101 | { |
102 | unsigned short v = 1 << (irq_nr - bcsr_csc_base); | 102 | unsigned short v = 1 << (d->irq - bcsr_csc_base); |
103 | __raw_writew(v, bcsr_virt + BCSR_REG_INTCLR); | 103 | __raw_writew(v, bcsr_virt + BCSR_REG_INTCLR); |
104 | __raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR); | 104 | __raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR); |
105 | wmb(); | 105 | wmb(); |
106 | } | 106 | } |
107 | 107 | ||
108 | static void bcsr_irq_maskack(unsigned int irq_nr) | 108 | static void bcsr_irq_maskack(struct irq_data *d) |
109 | { | 109 | { |
110 | unsigned short v = 1 << (irq_nr - bcsr_csc_base); | 110 | unsigned short v = 1 << (d->irq - bcsr_csc_base); |
111 | __raw_writew(v, bcsr_virt + BCSR_REG_INTCLR); | 111 | __raw_writew(v, bcsr_virt + BCSR_REG_INTCLR); |
112 | __raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR); | 112 | __raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR); |
113 | __raw_writew(v, bcsr_virt + BCSR_REG_INTSTAT); /* ack */ | 113 | __raw_writew(v, bcsr_virt + BCSR_REG_INTSTAT); /* ack */ |
114 | wmb(); | 114 | wmb(); |
115 | } | 115 | } |
116 | 116 | ||
117 | static void bcsr_irq_unmask(unsigned int irq_nr) | 117 | static void bcsr_irq_unmask(struct irq_data *d) |
118 | { | 118 | { |
119 | unsigned short v = 1 << (irq_nr - bcsr_csc_base); | 119 | unsigned short v = 1 << (d->irq - bcsr_csc_base); |
120 | __raw_writew(v, bcsr_virt + BCSR_REG_INTSET); | 120 | __raw_writew(v, bcsr_virt + BCSR_REG_INTSET); |
121 | __raw_writew(v, bcsr_virt + BCSR_REG_MASKSET); | 121 | __raw_writew(v, bcsr_virt + BCSR_REG_MASKSET); |
122 | wmb(); | 122 | wmb(); |
@@ -124,9 +124,9 @@ static void bcsr_irq_unmask(unsigned int irq_nr) | |||
124 | 124 | ||
125 | static struct irq_chip bcsr_irq_type = { | 125 | static struct irq_chip bcsr_irq_type = { |
126 | .name = "CPLD", | 126 | .name = "CPLD", |
127 | .mask = bcsr_irq_mask, | 127 | .irq_mask = bcsr_irq_mask, |
128 | .mask_ack = bcsr_irq_maskack, | 128 | .irq_mask_ack = bcsr_irq_maskack, |
129 | .unmask = bcsr_irq_unmask, | 129 | .irq_unmask = bcsr_irq_unmask, |
130 | }; | 130 | }; |
131 | 131 | ||
132 | void __init bcsr_init_irq(int csc_start, int csc_end, int hook_irq) | 132 | void __init bcsr_init_irq(int csc_start, int csc_end, int hook_irq) |
diff --git a/arch/mips/ar7/irq.c b/arch/mips/ar7/irq.c index 4ec2642c568f..a6484b60642f 100644 --- a/arch/mips/ar7/irq.c +++ b/arch/mips/ar7/irq.c | |||
@@ -49,51 +49,51 @@ | |||
49 | 49 | ||
50 | static int ar7_irq_base; | 50 | static int ar7_irq_base; |
51 | 51 | ||
52 | static void ar7_unmask_irq(unsigned int irq) | 52 | static void ar7_unmask_irq(struct irq_data *d) |
53 | { | 53 | { |
54 | writel(1 << ((irq - ar7_irq_base) % 32), | 54 | writel(1 << ((d->irq - ar7_irq_base) % 32), |
55 | REG(ESR_OFFSET(irq - ar7_irq_base))); | 55 | REG(ESR_OFFSET(d->irq - ar7_irq_base))); |
56 | } | 56 | } |
57 | 57 | ||
58 | static void ar7_mask_irq(unsigned int irq) | 58 | static void ar7_mask_irq(struct irq_data *d) |
59 | { | 59 | { |
60 | writel(1 << ((irq - ar7_irq_base) % 32), | 60 | writel(1 << ((d->irq - ar7_irq_base) % 32), |
61 | REG(ECR_OFFSET(irq - ar7_irq_base))); | 61 | REG(ECR_OFFSET(d->irq - ar7_irq_base))); |
62 | } | 62 | } |
63 | 63 | ||
64 | static void ar7_ack_irq(unsigned int irq) | 64 | static void ar7_ack_irq(struct irq_data *d) |
65 | { | 65 | { |
66 | writel(1 << ((irq - ar7_irq_base) % 32), | 66 | writel(1 << ((d->irq - ar7_irq_base) % 32), |
67 | REG(CR_OFFSET(irq - ar7_irq_base))); | 67 | REG(CR_OFFSET(d->irq - ar7_irq_base))); |
68 | } | 68 | } |
69 | 69 | ||
70 | static void ar7_unmask_sec_irq(unsigned int irq) | 70 | static void ar7_unmask_sec_irq(struct irq_data *d) |
71 | { | 71 | { |
72 | writel(1 << (irq - ar7_irq_base - 40), REG(SEC_ESR_OFFSET)); | 72 | writel(1 << (d->irq - ar7_irq_base - 40), REG(SEC_ESR_OFFSET)); |
73 | } | 73 | } |
74 | 74 | ||
75 | static void ar7_mask_sec_irq(unsigned int irq) | 75 | static void ar7_mask_sec_irq(struct irq_data *d) |
76 | { | 76 | { |
77 | writel(1 << (irq - ar7_irq_base - 40), REG(SEC_ECR_OFFSET)); | 77 | writel(1 << (d->irq - ar7_irq_base - 40), REG(SEC_ECR_OFFSET)); |
78 | } | 78 | } |
79 | 79 | ||
80 | static void ar7_ack_sec_irq(unsigned int irq) | 80 | static void ar7_ack_sec_irq(struct irq_data *d) |
81 | { | 81 | { |
82 | writel(1 << (irq - ar7_irq_base - 40), REG(SEC_CR_OFFSET)); | 82 | writel(1 << (d->irq - ar7_irq_base - 40), REG(SEC_CR_OFFSET)); |
83 | } | 83 | } |
84 | 84 | ||
85 | static struct irq_chip ar7_irq_type = { | 85 | static struct irq_chip ar7_irq_type = { |
86 | .name = "AR7", | 86 | .name = "AR7", |
87 | .unmask = ar7_unmask_irq, | 87 | .irq_unmask = ar7_unmask_irq, |
88 | .mask = ar7_mask_irq, | 88 | .irq_mask = ar7_mask_irq, |
89 | .ack = ar7_ack_irq | 89 | .irq_ack = ar7_ack_irq |
90 | }; | 90 | }; |
91 | 91 | ||
92 | static struct irq_chip ar7_sec_irq_type = { | 92 | static struct irq_chip ar7_sec_irq_type = { |
93 | .name = "AR7", | 93 | .name = "AR7", |
94 | .unmask = ar7_unmask_sec_irq, | 94 | .irq_unmask = ar7_unmask_sec_irq, |
95 | .mask = ar7_mask_sec_irq, | 95 | .irq_mask = ar7_mask_sec_irq, |
96 | .ack = ar7_ack_sec_irq, | 96 | .irq_ack = ar7_ack_sec_irq, |
97 | }; | 97 | }; |
98 | 98 | ||
99 | static struct irqaction ar7_cascade_action = { | 99 | static struct irqaction ar7_cascade_action = { |
diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c index 1bf7f719ba53..7c02bc948a31 100644 --- a/arch/mips/ath79/irq.c +++ b/arch/mips/ath79/irq.c | |||
@@ -62,13 +62,12 @@ static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc) | |||
62 | spurious_interrupt(); | 62 | spurious_interrupt(); |
63 | } | 63 | } |
64 | 64 | ||
65 | static void ar71xx_misc_irq_unmask(unsigned int irq) | 65 | static void ar71xx_misc_irq_unmask(struct irq_data *d) |
66 | { | 66 | { |
67 | unsigned int irq = d->irq - ATH79_MISC_IRQ_BASE; | ||
67 | void __iomem *base = ath79_reset_base; | 68 | void __iomem *base = ath79_reset_base; |
68 | u32 t; | 69 | u32 t; |
69 | 70 | ||
70 | irq -= ATH79_MISC_IRQ_BASE; | ||
71 | |||
72 | t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); | 71 | t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); |
73 | __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); | 72 | __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); |
74 | 73 | ||
@@ -76,13 +75,12 @@ static void ar71xx_misc_irq_unmask(unsigned int irq) | |||
76 | __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); | 75 | __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); |
77 | } | 76 | } |
78 | 77 | ||
79 | static void ar71xx_misc_irq_mask(unsigned int irq) | 78 | static void ar71xx_misc_irq_mask(struct irq_data *d) |
80 | { | 79 | { |
80 | unsigned int irq = d->irq - ATH79_MISC_IRQ_BASE; | ||
81 | void __iomem *base = ath79_reset_base; | 81 | void __iomem *base = ath79_reset_base; |
82 | u32 t; | 82 | u32 t; |
83 | 83 | ||
84 | irq -= ATH79_MISC_IRQ_BASE; | ||
85 | |||
86 | t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); | 84 | t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); |
87 | __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); | 85 | __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); |
88 | 86 | ||
@@ -90,13 +88,12 @@ static void ar71xx_misc_irq_mask(unsigned int irq) | |||
90 | __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); | 88 | __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); |
91 | } | 89 | } |
92 | 90 | ||
93 | static void ar724x_misc_irq_ack(unsigned int irq) | 91 | static void ar724x_misc_irq_ack(struct irq_data *d) |
94 | { | 92 | { |
93 | unsigned int irq = d->irq - ATH79_MISC_IRQ_BASE; | ||
95 | void __iomem *base = ath79_reset_base; | 94 | void __iomem *base = ath79_reset_base; |
96 | u32 t; | 95 | u32 t; |
97 | 96 | ||
98 | irq -= ATH79_MISC_IRQ_BASE; | ||
99 | |||
100 | t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); | 97 | t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); |
101 | __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_STATUS); | 98 | __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_STATUS); |
102 | 99 | ||
@@ -106,8 +103,8 @@ static void ar724x_misc_irq_ack(unsigned int irq) | |||
106 | 103 | ||
107 | static struct irq_chip ath79_misc_irq_chip = { | 104 | static struct irq_chip ath79_misc_irq_chip = { |
108 | .name = "MISC", | 105 | .name = "MISC", |
109 | .unmask = ar71xx_misc_irq_unmask, | 106 | .irq_unmask = ar71xx_misc_irq_unmask, |
110 | .mask = ar71xx_misc_irq_mask, | 107 | .irq_mask = ar71xx_misc_irq_mask, |
111 | }; | 108 | }; |
112 | 109 | ||
113 | static void __init ath79_misc_irq_init(void) | 110 | static void __init ath79_misc_irq_init(void) |
@@ -119,15 +116,14 @@ static void __init ath79_misc_irq_init(void) | |||
119 | __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS); | 116 | __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS); |
120 | 117 | ||
121 | if (soc_is_ar71xx() || soc_is_ar913x()) | 118 | if (soc_is_ar71xx() || soc_is_ar913x()) |
122 | ath79_misc_irq_chip.mask_ack = ar71xx_misc_irq_mask; | 119 | ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask; |
123 | else if (soc_is_ar724x()) | 120 | else if (soc_is_ar724x()) |
124 | ath79_misc_irq_chip.ack = ar724x_misc_irq_ack; | 121 | ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack; |
125 | else | 122 | else |
126 | BUG(); | 123 | BUG(); |
127 | 124 | ||
128 | for (i = ATH79_MISC_IRQ_BASE; | 125 | for (i = ATH79_MISC_IRQ_BASE; |
129 | i < ATH79_MISC_IRQ_BASE + ATH79_MISC_IRQ_COUNT; i++) { | 126 | i < ATH79_MISC_IRQ_BASE + ATH79_MISC_IRQ_COUNT; i++) { |
130 | irq_desc[i].status = IRQ_DISABLED; | ||
131 | set_irq_chip_and_handler(i, &ath79_misc_irq_chip, | 127 | set_irq_chip_and_handler(i, &ath79_misc_irq_chip, |
132 | handle_level_irq); | 128 | handle_level_irq); |
133 | } | 129 | } |
diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c index 3be87f2422f0..1691531aa34d 100644 --- a/arch/mips/bcm63xx/irq.c +++ b/arch/mips/bcm63xx/irq.c | |||
@@ -76,88 +76,80 @@ asmlinkage void plat_irq_dispatch(void) | |||
76 | * internal IRQs operations: only mask/unmask on PERF irq mask | 76 | * internal IRQs operations: only mask/unmask on PERF irq mask |
77 | * register. | 77 | * register. |
78 | */ | 78 | */ |
79 | static inline void bcm63xx_internal_irq_mask(unsigned int irq) | 79 | static inline void bcm63xx_internal_irq_mask(struct irq_data *d) |
80 | { | 80 | { |
81 | unsigned int irq = d->irq - IRQ_INTERNAL_BASE; | ||
81 | u32 mask; | 82 | u32 mask; |
82 | 83 | ||
83 | irq -= IRQ_INTERNAL_BASE; | ||
84 | mask = bcm_perf_readl(PERF_IRQMASK_REG); | 84 | mask = bcm_perf_readl(PERF_IRQMASK_REG); |
85 | mask &= ~(1 << irq); | 85 | mask &= ~(1 << irq); |
86 | bcm_perf_writel(mask, PERF_IRQMASK_REG); | 86 | bcm_perf_writel(mask, PERF_IRQMASK_REG); |
87 | } | 87 | } |
88 | 88 | ||
89 | static void bcm63xx_internal_irq_unmask(unsigned int irq) | 89 | static void bcm63xx_internal_irq_unmask(struct irq_data *d) |
90 | { | 90 | { |
91 | unsigned int irq = d->irq - IRQ_INTERNAL_BASE; | ||
91 | u32 mask; | 92 | u32 mask; |
92 | 93 | ||
93 | irq -= IRQ_INTERNAL_BASE; | ||
94 | mask = bcm_perf_readl(PERF_IRQMASK_REG); | 94 | mask = bcm_perf_readl(PERF_IRQMASK_REG); |
95 | mask |= (1 << irq); | 95 | mask |= (1 << irq); |
96 | bcm_perf_writel(mask, PERF_IRQMASK_REG); | 96 | bcm_perf_writel(mask, PERF_IRQMASK_REG); |
97 | } | 97 | } |
98 | 98 | ||
99 | static unsigned int bcm63xx_internal_irq_startup(unsigned int irq) | ||
100 | { | ||
101 | bcm63xx_internal_irq_unmask(irq); | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | /* | 99 | /* |
106 | * external IRQs operations: mask/unmask and clear on PERF external | 100 | * external IRQs operations: mask/unmask and clear on PERF external |
107 | * irq control register. | 101 | * irq control register. |
108 | */ | 102 | */ |
109 | static void bcm63xx_external_irq_mask(unsigned int irq) | 103 | static void bcm63xx_external_irq_mask(struct irq_data *d) |
110 | { | 104 | { |
105 | unsigned int irq = d->irq - IRQ_EXT_BASE; | ||
111 | u32 reg; | 106 | u32 reg; |
112 | 107 | ||
113 | irq -= IRQ_EXT_BASE; | ||
114 | reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); | 108 | reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); |
115 | reg &= ~EXTIRQ_CFG_MASK(irq); | 109 | reg &= ~EXTIRQ_CFG_MASK(irq); |
116 | bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); | 110 | bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); |
117 | } | 111 | } |
118 | 112 | ||
119 | static void bcm63xx_external_irq_unmask(unsigned int irq) | 113 | static void bcm63xx_external_irq_unmask(struct irq_data *d) |
120 | { | 114 | { |
115 | unsigned int irq = d->irq - IRQ_EXT_BASE; | ||
121 | u32 reg; | 116 | u32 reg; |
122 | 117 | ||
123 | irq -= IRQ_EXT_BASE; | ||
124 | reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); | 118 | reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); |
125 | reg |= EXTIRQ_CFG_MASK(irq); | 119 | reg |= EXTIRQ_CFG_MASK(irq); |
126 | bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); | 120 | bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); |
127 | } | 121 | } |
128 | 122 | ||
129 | static void bcm63xx_external_irq_clear(unsigned int irq) | 123 | static void bcm63xx_external_irq_clear(struct irq_data *d) |
130 | { | 124 | { |
125 | unsigned int irq = d->irq - IRQ_EXT_BASE; | ||
131 | u32 reg; | 126 | u32 reg; |
132 | 127 | ||
133 | irq -= IRQ_EXT_BASE; | ||
134 | reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); | 128 | reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); |
135 | reg |= EXTIRQ_CFG_CLEAR(irq); | 129 | reg |= EXTIRQ_CFG_CLEAR(irq); |
136 | bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); | 130 | bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); |
137 | } | 131 | } |
138 | 132 | ||
139 | static unsigned int bcm63xx_external_irq_startup(unsigned int irq) | 133 | static unsigned int bcm63xx_external_irq_startup(struct irq_data *d) |
140 | { | 134 | { |
141 | set_c0_status(0x100 << (irq - IRQ_MIPS_BASE)); | 135 | set_c0_status(0x100 << (d->irq - IRQ_MIPS_BASE)); |
142 | irq_enable_hazard(); | 136 | irq_enable_hazard(); |
143 | bcm63xx_external_irq_unmask(irq); | 137 | bcm63xx_external_irq_unmask(d); |
144 | return 0; | 138 | return 0; |
145 | } | 139 | } |
146 | 140 | ||
147 | static void bcm63xx_external_irq_shutdown(unsigned int irq) | 141 | static void bcm63xx_external_irq_shutdown(struct irq_data *d) |
148 | { | 142 | { |
149 | bcm63xx_external_irq_mask(irq); | 143 | bcm63xx_external_irq_mask(d); |
150 | clear_c0_status(0x100 << (irq - IRQ_MIPS_BASE)); | 144 | clear_c0_status(0x100 << (d->irq - IRQ_MIPS_BASE)); |
151 | irq_disable_hazard(); | 145 | irq_disable_hazard(); |
152 | } | 146 | } |
153 | 147 | ||
154 | static int bcm63xx_external_irq_set_type(unsigned int irq, | 148 | static int bcm63xx_external_irq_set_type(struct irq_data *d, |
155 | unsigned int flow_type) | 149 | unsigned int flow_type) |
156 | { | 150 | { |
151 | unsigned int irq = d->irq - IRQ_EXT_BASE; | ||
157 | u32 reg; | 152 | u32 reg; |
158 | struct irq_desc *desc = irq_desc + irq; | ||
159 | |||
160 | irq -= IRQ_EXT_BASE; | ||
161 | 153 | ||
162 | flow_type &= IRQ_TYPE_SENSE_MASK; | 154 | flow_type &= IRQ_TYPE_SENSE_MASK; |
163 | 155 | ||
@@ -199,37 +191,32 @@ static int bcm63xx_external_irq_set_type(unsigned int irq, | |||
199 | } | 191 | } |
200 | bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); | 192 | bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); |
201 | 193 | ||
202 | if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) { | 194 | irqd_set_trigger_type(d, flow_type); |
203 | desc->status |= IRQ_LEVEL; | 195 | if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) |
204 | desc->handle_irq = handle_level_irq; | 196 | __irq_set_handler_locked(d->irq, handle_level_irq); |
205 | } else { | 197 | else |
206 | desc->handle_irq = handle_edge_irq; | 198 | __irq_set_handler_locked(d->irq, handle_edge_irq); |
207 | } | ||
208 | 199 | ||
209 | return 0; | 200 | return IRQ_SET_MASK_OK_NOCOPY; |
210 | } | 201 | } |
211 | 202 | ||
212 | static struct irq_chip bcm63xx_internal_irq_chip = { | 203 | static struct irq_chip bcm63xx_internal_irq_chip = { |
213 | .name = "bcm63xx_ipic", | 204 | .name = "bcm63xx_ipic", |
214 | .startup = bcm63xx_internal_irq_startup, | 205 | .irq_mask = bcm63xx_internal_irq_mask, |
215 | .shutdown = bcm63xx_internal_irq_mask, | 206 | .irq_unmask = bcm63xx_internal_irq_unmask, |
216 | |||
217 | .mask = bcm63xx_internal_irq_mask, | ||
218 | .mask_ack = bcm63xx_internal_irq_mask, | ||
219 | .unmask = bcm63xx_internal_irq_unmask, | ||
220 | }; | 207 | }; |
221 | 208 | ||
222 | static struct irq_chip bcm63xx_external_irq_chip = { | 209 | static struct irq_chip bcm63xx_external_irq_chip = { |
223 | .name = "bcm63xx_epic", | 210 | .name = "bcm63xx_epic", |
224 | .startup = bcm63xx_external_irq_startup, | 211 | .irq_startup = bcm63xx_external_irq_startup, |
225 | .shutdown = bcm63xx_external_irq_shutdown, | 212 | .irq_shutdown = bcm63xx_external_irq_shutdown, |
226 | 213 | ||
227 | .ack = bcm63xx_external_irq_clear, | 214 | .irq_ack = bcm63xx_external_irq_clear, |
228 | 215 | ||
229 | .mask = bcm63xx_external_irq_mask, | 216 | .irq_mask = bcm63xx_external_irq_mask, |
230 | .unmask = bcm63xx_external_irq_unmask, | 217 | .irq_unmask = bcm63xx_external_irq_unmask, |
231 | 218 | ||
232 | .set_type = bcm63xx_external_irq_set_type, | 219 | .irq_set_type = bcm63xx_external_irq_set_type, |
233 | }; | 220 | }; |
234 | 221 | ||
235 | static struct irqaction cpu_ip2_cascade_action = { | 222 | static struct irqaction cpu_ip2_cascade_action = { |
diff --git a/arch/mips/dec/ioasic-irq.c b/arch/mips/dec/ioasic-irq.c index cb41954fc321..8d9a5fc607e4 100644 --- a/arch/mips/dec/ioasic-irq.c +++ b/arch/mips/dec/ioasic-irq.c | |||
@@ -17,80 +17,48 @@ | |||
17 | #include <asm/dec/ioasic_addrs.h> | 17 | #include <asm/dec/ioasic_addrs.h> |
18 | #include <asm/dec/ioasic_ints.h> | 18 | #include <asm/dec/ioasic_ints.h> |
19 | 19 | ||
20 | |||
21 | static int ioasic_irq_base; | 20 | static int ioasic_irq_base; |
22 | 21 | ||
23 | 22 | static void unmask_ioasic_irq(struct irq_data *d) | |
24 | static inline void unmask_ioasic_irq(unsigned int irq) | ||
25 | { | 23 | { |
26 | u32 simr; | 24 | u32 simr; |
27 | 25 | ||
28 | simr = ioasic_read(IO_REG_SIMR); | 26 | simr = ioasic_read(IO_REG_SIMR); |
29 | simr |= (1 << (irq - ioasic_irq_base)); | 27 | simr |= (1 << (d->irq - ioasic_irq_base)); |
30 | ioasic_write(IO_REG_SIMR, simr); | 28 | ioasic_write(IO_REG_SIMR, simr); |
31 | } | 29 | } |
32 | 30 | ||
33 | static inline void mask_ioasic_irq(unsigned int irq) | 31 | static void mask_ioasic_irq(struct irq_data *d) |
34 | { | 32 | { |
35 | u32 simr; | 33 | u32 simr; |
36 | 34 | ||
37 | simr = ioasic_read(IO_REG_SIMR); | 35 | simr = ioasic_read(IO_REG_SIMR); |
38 | simr &= ~(1 << (irq - ioasic_irq_base)); | 36 | simr &= ~(1 << (d->irq - ioasic_irq_base)); |
39 | ioasic_write(IO_REG_SIMR, simr); | 37 | ioasic_write(IO_REG_SIMR, simr); |
40 | } | 38 | } |
41 | 39 | ||
42 | static inline void clear_ioasic_irq(unsigned int irq) | 40 | static void ack_ioasic_irq(struct irq_data *d) |
43 | { | 41 | { |
44 | u32 sir; | 42 | mask_ioasic_irq(d); |
45 | |||
46 | sir = ~(1 << (irq - ioasic_irq_base)); | ||
47 | ioasic_write(IO_REG_SIR, sir); | ||
48 | } | ||
49 | |||
50 | static inline void ack_ioasic_irq(unsigned int irq) | ||
51 | { | ||
52 | mask_ioasic_irq(irq); | ||
53 | fast_iob(); | 43 | fast_iob(); |
54 | } | 44 | } |
55 | 45 | ||
56 | static inline void end_ioasic_irq(unsigned int irq) | ||
57 | { | ||
58 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | ||
59 | unmask_ioasic_irq(irq); | ||
60 | } | ||
61 | |||
62 | static struct irq_chip ioasic_irq_type = { | 46 | static struct irq_chip ioasic_irq_type = { |
63 | .name = "IO-ASIC", | 47 | .name = "IO-ASIC", |
64 | .ack = ack_ioasic_irq, | 48 | .irq_ack = ack_ioasic_irq, |
65 | .mask = mask_ioasic_irq, | 49 | .irq_mask = mask_ioasic_irq, |
66 | .mask_ack = ack_ioasic_irq, | 50 | .irq_mask_ack = ack_ioasic_irq, |
67 | .unmask = unmask_ioasic_irq, | 51 | .irq_unmask = unmask_ioasic_irq, |
68 | }; | 52 | }; |
69 | 53 | ||
70 | |||
71 | #define unmask_ioasic_dma_irq unmask_ioasic_irq | ||
72 | |||
73 | #define mask_ioasic_dma_irq mask_ioasic_irq | ||
74 | |||
75 | #define ack_ioasic_dma_irq ack_ioasic_irq | ||
76 | |||
77 | static inline void end_ioasic_dma_irq(unsigned int irq) | ||
78 | { | ||
79 | clear_ioasic_irq(irq); | ||
80 | fast_iob(); | ||
81 | end_ioasic_irq(irq); | ||
82 | } | ||
83 | |||
84 | static struct irq_chip ioasic_dma_irq_type = { | 54 | static struct irq_chip ioasic_dma_irq_type = { |
85 | .name = "IO-ASIC-DMA", | 55 | .name = "IO-ASIC-DMA", |
86 | .ack = ack_ioasic_dma_irq, | 56 | .irq_ack = ack_ioasic_irq, |
87 | .mask = mask_ioasic_dma_irq, | 57 | .irq_mask = mask_ioasic_irq, |
88 | .mask_ack = ack_ioasic_dma_irq, | 58 | .irq_mask_ack = ack_ioasic_irq, |
89 | .unmask = unmask_ioasic_dma_irq, | 59 | .irq_unmask = unmask_ioasic_irq, |
90 | .end = end_ioasic_dma_irq, | ||
91 | }; | 60 | }; |
92 | 61 | ||
93 | |||
94 | void __init init_ioasic_irqs(int base) | 62 | void __init init_ioasic_irqs(int base) |
95 | { | 63 | { |
96 | int i; | 64 | int i; |
diff --git a/arch/mips/dec/kn02-irq.c b/arch/mips/dec/kn02-irq.c index ed90a8deabcc..ef31d98c4fb8 100644 --- a/arch/mips/dec/kn02-irq.c +++ b/arch/mips/dec/kn02-irq.c | |||
@@ -27,43 +27,40 @@ | |||
27 | */ | 27 | */ |
28 | u32 cached_kn02_csr; | 28 | u32 cached_kn02_csr; |
29 | 29 | ||
30 | |||
31 | static int kn02_irq_base; | 30 | static int kn02_irq_base; |
32 | 31 | ||
33 | 32 | static void unmask_kn02_irq(struct irq_data *d) | |
34 | static inline void unmask_kn02_irq(unsigned int irq) | ||
35 | { | 33 | { |
36 | volatile u32 *csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE + | 34 | volatile u32 *csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE + |
37 | KN02_CSR); | 35 | KN02_CSR); |
38 | 36 | ||
39 | cached_kn02_csr |= (1 << (irq - kn02_irq_base + 16)); | 37 | cached_kn02_csr |= (1 << (d->irq - kn02_irq_base + 16)); |
40 | *csr = cached_kn02_csr; | 38 | *csr = cached_kn02_csr; |
41 | } | 39 | } |
42 | 40 | ||
43 | static inline void mask_kn02_irq(unsigned int irq) | 41 | static void mask_kn02_irq(struct irq_data *d) |
44 | { | 42 | { |
45 | volatile u32 *csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE + | 43 | volatile u32 *csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE + |
46 | KN02_CSR); | 44 | KN02_CSR); |
47 | 45 | ||
48 | cached_kn02_csr &= ~(1 << (irq - kn02_irq_base + 16)); | 46 | cached_kn02_csr &= ~(1 << (d->irq - kn02_irq_base + 16)); |
49 | *csr = cached_kn02_csr; | 47 | *csr = cached_kn02_csr; |
50 | } | 48 | } |
51 | 49 | ||
52 | static void ack_kn02_irq(unsigned int irq) | 50 | static void ack_kn02_irq(struct irq_data *d) |
53 | { | 51 | { |
54 | mask_kn02_irq(irq); | 52 | mask_kn02_irq(d); |
55 | iob(); | 53 | iob(); |
56 | } | 54 | } |
57 | 55 | ||
58 | static struct irq_chip kn02_irq_type = { | 56 | static struct irq_chip kn02_irq_type = { |
59 | .name = "KN02-CSR", | 57 | .name = "KN02-CSR", |
60 | .ack = ack_kn02_irq, | 58 | .irq_ack = ack_kn02_irq, |
61 | .mask = mask_kn02_irq, | 59 | .irq_mask = mask_kn02_irq, |
62 | .mask_ack = ack_kn02_irq, | 60 | .irq_mask_ack = ack_kn02_irq, |
63 | .unmask = unmask_kn02_irq, | 61 | .irq_unmask = unmask_kn02_irq, |
64 | }; | 62 | }; |
65 | 63 | ||
66 | |||
67 | void __init init_kn02_irqs(int base) | 64 | void __init init_kn02_irqs(int base) |
68 | { | 65 | { |
69 | volatile u32 *csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE + | 66 | volatile u32 *csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE + |
diff --git a/arch/mips/emma/markeins/irq.c b/arch/mips/emma/markeins/irq.c index 3a96799eb65f..9b1207ae2256 100644 --- a/arch/mips/emma/markeins/irq.c +++ b/arch/mips/emma/markeins/irq.c | |||
@@ -34,13 +34,10 @@ | |||
34 | 34 | ||
35 | #include <asm/emma/emma2rh.h> | 35 | #include <asm/emma/emma2rh.h> |
36 | 36 | ||
37 | static void emma2rh_irq_enable(unsigned int irq) | 37 | static void emma2rh_irq_enable(struct irq_data *d) |
38 | { | 38 | { |
39 | u32 reg_value; | 39 | unsigned int irq = d->irq - EMMA2RH_IRQ_BASE; |
40 | u32 reg_bitmask; | 40 | u32 reg_value, reg_bitmask, reg_index; |
41 | u32 reg_index; | ||
42 | |||
43 | irq -= EMMA2RH_IRQ_BASE; | ||
44 | 41 | ||
45 | reg_index = EMMA2RH_BHIF_INT_EN_0 + | 42 | reg_index = EMMA2RH_BHIF_INT_EN_0 + |
46 | (EMMA2RH_BHIF_INT_EN_1 - EMMA2RH_BHIF_INT_EN_0) * (irq / 32); | 43 | (EMMA2RH_BHIF_INT_EN_1 - EMMA2RH_BHIF_INT_EN_0) * (irq / 32); |
@@ -49,13 +46,10 @@ static void emma2rh_irq_enable(unsigned int irq) | |||
49 | emma2rh_out32(reg_index, reg_value | reg_bitmask); | 46 | emma2rh_out32(reg_index, reg_value | reg_bitmask); |
50 | } | 47 | } |
51 | 48 | ||
52 | static void emma2rh_irq_disable(unsigned int irq) | 49 | static void emma2rh_irq_disable(struct irq_data *d) |
53 | { | 50 | { |
54 | u32 reg_value; | 51 | unsigned int irq = d->irq - EMMA2RH_IRQ_BASE; |
55 | u32 reg_bitmask; | 52 | u32 reg_value, reg_bitmask, reg_index; |
56 | u32 reg_index; | ||
57 | |||
58 | irq -= EMMA2RH_IRQ_BASE; | ||
59 | 53 | ||
60 | reg_index = EMMA2RH_BHIF_INT_EN_0 + | 54 | reg_index = EMMA2RH_BHIF_INT_EN_0 + |
61 | (EMMA2RH_BHIF_INT_EN_1 - EMMA2RH_BHIF_INT_EN_0) * (irq / 32); | 55 | (EMMA2RH_BHIF_INT_EN_1 - EMMA2RH_BHIF_INT_EN_0) * (irq / 32); |
@@ -66,10 +60,8 @@ static void emma2rh_irq_disable(unsigned int irq) | |||
66 | 60 | ||
67 | struct irq_chip emma2rh_irq_controller = { | 61 | struct irq_chip emma2rh_irq_controller = { |
68 | .name = "emma2rh_irq", | 62 | .name = "emma2rh_irq", |
69 | .ack = emma2rh_irq_disable, | 63 | .irq_mask = emma2rh_irq_disable, |
70 | .mask = emma2rh_irq_disable, | 64 | .irq_unmask = emma2rh_irq_enable, |
71 | .mask_ack = emma2rh_irq_disable, | ||
72 | .unmask = emma2rh_irq_enable, | ||
73 | }; | 65 | }; |
74 | 66 | ||
75 | void emma2rh_irq_init(void) | 67 | void emma2rh_irq_init(void) |
@@ -82,23 +74,21 @@ void emma2rh_irq_init(void) | |||
82 | handle_level_irq, "level"); | 74 | handle_level_irq, "level"); |
83 | } | 75 | } |
84 | 76 | ||
85 | static void emma2rh_sw_irq_enable(unsigned int irq) | 77 | static void emma2rh_sw_irq_enable(struct irq_data *d) |
86 | { | 78 | { |
79 | unsigned int irq = d->irq - EMMA2RH_SW_IRQ_BASE; | ||
87 | u32 reg; | 80 | u32 reg; |
88 | 81 | ||
89 | irq -= EMMA2RH_SW_IRQ_BASE; | ||
90 | |||
91 | reg = emma2rh_in32(EMMA2RH_BHIF_SW_INT_EN); | 82 | reg = emma2rh_in32(EMMA2RH_BHIF_SW_INT_EN); |
92 | reg |= 1 << irq; | 83 | reg |= 1 << irq; |
93 | emma2rh_out32(EMMA2RH_BHIF_SW_INT_EN, reg); | 84 | emma2rh_out32(EMMA2RH_BHIF_SW_INT_EN, reg); |
94 | } | 85 | } |
95 | 86 | ||
96 | static void emma2rh_sw_irq_disable(unsigned int irq) | 87 | static void emma2rh_sw_irq_disable(struct irq_data *d) |
97 | { | 88 | { |
89 | unsigned int irq = d->irq - EMMA2RH_SW_IRQ_BASE; | ||
98 | u32 reg; | 90 | u32 reg; |
99 | 91 | ||
100 | irq -= EMMA2RH_SW_IRQ_BASE; | ||
101 | |||
102 | reg = emma2rh_in32(EMMA2RH_BHIF_SW_INT_EN); | 92 | reg = emma2rh_in32(EMMA2RH_BHIF_SW_INT_EN); |
103 | reg &= ~(1 << irq); | 93 | reg &= ~(1 << irq); |
104 | emma2rh_out32(EMMA2RH_BHIF_SW_INT_EN, reg); | 94 | emma2rh_out32(EMMA2RH_BHIF_SW_INT_EN, reg); |
@@ -106,10 +96,8 @@ static void emma2rh_sw_irq_disable(unsigned int irq) | |||
106 | 96 | ||
107 | struct irq_chip emma2rh_sw_irq_controller = { | 97 | struct irq_chip emma2rh_sw_irq_controller = { |
108 | .name = "emma2rh_sw_irq", | 98 | .name = "emma2rh_sw_irq", |
109 | .ack = emma2rh_sw_irq_disable, | 99 | .irq_mask = emma2rh_sw_irq_disable, |
110 | .mask = emma2rh_sw_irq_disable, | 100 | .irq_unmask = emma2rh_sw_irq_enable, |
111 | .mask_ack = emma2rh_sw_irq_disable, | ||
112 | .unmask = emma2rh_sw_irq_enable, | ||
113 | }; | 101 | }; |
114 | 102 | ||
115 | void emma2rh_sw_irq_init(void) | 103 | void emma2rh_sw_irq_init(void) |
@@ -122,39 +110,38 @@ void emma2rh_sw_irq_init(void) | |||
122 | handle_level_irq, "level"); | 110 | handle_level_irq, "level"); |
123 | } | 111 | } |
124 | 112 | ||
125 | static void emma2rh_gpio_irq_enable(unsigned int irq) | 113 | static void emma2rh_gpio_irq_enable(struct irq_data *d) |
126 | { | 114 | { |
115 | unsigned int irq = d->irq - EMMA2RH_GPIO_IRQ_BASE; | ||
127 | u32 reg; | 116 | u32 reg; |
128 | 117 | ||
129 | irq -= EMMA2RH_GPIO_IRQ_BASE; | ||
130 | |||
131 | reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK); | 118 | reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK); |
132 | reg |= 1 << irq; | 119 | reg |= 1 << irq; |
133 | emma2rh_out32(EMMA2RH_GPIO_INT_MASK, reg); | 120 | emma2rh_out32(EMMA2RH_GPIO_INT_MASK, reg); |
134 | } | 121 | } |
135 | 122 | ||
136 | static void emma2rh_gpio_irq_disable(unsigned int irq) | 123 | static void emma2rh_gpio_irq_disable(struct irq_data *d) |
137 | { | 124 | { |
125 | unsigned int irq = d->irq - EMMA2RH_GPIO_IRQ_BASE; | ||
138 | u32 reg; | 126 | u32 reg; |
139 | 127 | ||
140 | irq -= EMMA2RH_GPIO_IRQ_BASE; | ||
141 | |||
142 | reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK); | 128 | reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK); |
143 | reg &= ~(1 << irq); | 129 | reg &= ~(1 << irq); |
144 | emma2rh_out32(EMMA2RH_GPIO_INT_MASK, reg); | 130 | emma2rh_out32(EMMA2RH_GPIO_INT_MASK, reg); |
145 | } | 131 | } |
146 | 132 | ||
147 | static void emma2rh_gpio_irq_ack(unsigned int irq) | 133 | static void emma2rh_gpio_irq_ack(struct irq_data *d) |
148 | { | 134 | { |
149 | irq -= EMMA2RH_GPIO_IRQ_BASE; | 135 | unsigned int irq = d->irq - EMMA2RH_GPIO_IRQ_BASE; |
136 | |||
150 | emma2rh_out32(EMMA2RH_GPIO_INT_ST, ~(1 << irq)); | 137 | emma2rh_out32(EMMA2RH_GPIO_INT_ST, ~(1 << irq)); |
151 | } | 138 | } |
152 | 139 | ||
153 | static void emma2rh_gpio_irq_mask_ack(unsigned int irq) | 140 | static void emma2rh_gpio_irq_mask_ack(struct irq_data *d) |
154 | { | 141 | { |
142 | unsigned int irq = d->irq - EMMA2RH_GPIO_IRQ_BASE; | ||
155 | u32 reg; | 143 | u32 reg; |
156 | 144 | ||
157 | irq -= EMMA2RH_GPIO_IRQ_BASE; | ||
158 | emma2rh_out32(EMMA2RH_GPIO_INT_ST, ~(1 << irq)); | 145 | emma2rh_out32(EMMA2RH_GPIO_INT_ST, ~(1 << irq)); |
159 | 146 | ||
160 | reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK); | 147 | reg = emma2rh_in32(EMMA2RH_GPIO_INT_MASK); |
@@ -164,10 +151,10 @@ static void emma2rh_gpio_irq_mask_ack(unsigned int irq) | |||
164 | 151 | ||
165 | struct irq_chip emma2rh_gpio_irq_controller = { | 152 | struct irq_chip emma2rh_gpio_irq_controller = { |
166 | .name = "emma2rh_gpio_irq", | 153 | .name = "emma2rh_gpio_irq", |
167 | .ack = emma2rh_gpio_irq_ack, | 154 | .irq_ack = emma2rh_gpio_irq_ack, |
168 | .mask = emma2rh_gpio_irq_disable, | 155 | .irq_mask = emma2rh_gpio_irq_disable, |
169 | .mask_ack = emma2rh_gpio_irq_mask_ack, | 156 | .irq_mask_ack = emma2rh_gpio_irq_mask_ack, |
170 | .unmask = emma2rh_gpio_irq_enable, | 157 | .irq_unmask = emma2rh_gpio_irq_enable, |
171 | }; | 158 | }; |
172 | 159 | ||
173 | void emma2rh_gpio_irq_init(void) | 160 | void emma2rh_gpio_irq_init(void) |
diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h index b003ed52ed17..0ec01294b063 100644 --- a/arch/mips/include/asm/irq.h +++ b/arch/mips/include/asm/irq.h | |||
@@ -55,9 +55,9 @@ static inline void smtc_im_ack_irq(unsigned int irq) | |||
55 | #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF | 55 | #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF |
56 | #include <linux/cpumask.h> | 56 | #include <linux/cpumask.h> |
57 | 57 | ||
58 | extern int plat_set_irq_affinity(unsigned int irq, | 58 | extern int plat_set_irq_affinity(struct irq_data *d, |
59 | const struct cpumask *affinity); | 59 | const struct cpumask *affinity, bool force); |
60 | extern void smtc_forward_irq(unsigned int irq); | 60 | extern void smtc_forward_irq(struct irq_data *d); |
61 | 61 | ||
62 | /* | 62 | /* |
63 | * IRQ affinity hook invoked at the beginning of interrupt dispatch | 63 | * IRQ affinity hook invoked at the beginning of interrupt dispatch |
@@ -70,51 +70,53 @@ extern void smtc_forward_irq(unsigned int irq); | |||
70 | * cpumask implementations, this version is optimistically assuming | 70 | * cpumask implementations, this version is optimistically assuming |
71 | * that cpumask.h macro overhead is reasonable during interrupt dispatch. | 71 | * that cpumask.h macro overhead is reasonable during interrupt dispatch. |
72 | */ | 72 | */ |
73 | #define IRQ_AFFINITY_HOOK(irq) \ | 73 | static inline int handle_on_other_cpu(unsigned int irq) |
74 | do { \ | 74 | { |
75 | if (!cpumask_test_cpu(smp_processor_id(), irq_desc[irq].affinity)) {\ | 75 | struct irq_data *d = irq_get_irq_data(irq); |
76 | smtc_forward_irq(irq); \ | 76 | |
77 | irq_exit(); \ | 77 | if (cpumask_test_cpu(smp_processor_id(), d->affinity)) |
78 | return; \ | 78 | return 0; |
79 | } \ | 79 | smtc_forward_irq(d); |
80 | } while (0) | 80 | return 1; |
81 | } | ||
81 | 82 | ||
82 | #else /* Not doing SMTC affinity */ | 83 | #else /* Not doing SMTC affinity */ |
83 | 84 | ||
84 | #define IRQ_AFFINITY_HOOK(irq) do { } while (0) | 85 | static inline int handle_on_other_cpu(unsigned int irq) { return 0; } |
85 | 86 | ||
86 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ | 87 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ |
87 | 88 | ||
88 | #ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP | 89 | #ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP |
89 | 90 | ||
91 | static inline void smtc_im_backstop(unsigned int irq) | ||
92 | { | ||
93 | if (irq_hwmask[irq] & 0x0000ff00) | ||
94 | write_c0_tccontext(read_c0_tccontext() & | ||
95 | ~(irq_hwmask[irq] & 0x0000ff00)); | ||
96 | } | ||
97 | |||
90 | /* | 98 | /* |
91 | * Clear interrupt mask handling "backstop" if irq_hwmask | 99 | * Clear interrupt mask handling "backstop" if irq_hwmask |
92 | * entry so indicates. This implies that the ack() or end() | 100 | * entry so indicates. This implies that the ack() or end() |
93 | * functions will take over re-enabling the low-level mask. | 101 | * functions will take over re-enabling the low-level mask. |
94 | * Otherwise it will be done on return from exception. | 102 | * Otherwise it will be done on return from exception. |
95 | */ | 103 | */ |
96 | #define __DO_IRQ_SMTC_HOOK(irq) \ | 104 | static inline int smtc_handle_on_other_cpu(unsigned int irq) |
97 | do { \ | 105 | { |
98 | IRQ_AFFINITY_HOOK(irq); \ | 106 | int ret = handle_on_other_cpu(irq); |
99 | if (irq_hwmask[irq] & 0x0000ff00) \ | 107 | |
100 | write_c0_tccontext(read_c0_tccontext() & \ | 108 | if (!ret) |
101 | ~(irq_hwmask[irq] & 0x0000ff00)); \ | 109 | smtc_im_backstop(irq); |
102 | } while (0) | 110 | return ret; |
103 | 111 | } | |
104 | #define __NO_AFFINITY_IRQ_SMTC_HOOK(irq) \ | ||
105 | do { \ | ||
106 | if (irq_hwmask[irq] & 0x0000ff00) \ | ||
107 | write_c0_tccontext(read_c0_tccontext() & \ | ||
108 | ~(irq_hwmask[irq] & 0x0000ff00)); \ | ||
109 | } while (0) | ||
110 | 112 | ||
111 | #else | 113 | #else |
112 | 114 | ||
113 | #define __DO_IRQ_SMTC_HOOK(irq) \ | 115 | static inline void smtc_im_backstop(unsigned int irq) { } |
114 | do { \ | 116 | static inline int smtc_handle_on_other_cpu(unsigned int irq) |
115 | IRQ_AFFINITY_HOOK(irq); \ | 117 | { |
116 | } while (0) | 118 | return handle_on_other_cpu(irq); |
117 | #define __NO_AFFINITY_IRQ_SMTC_HOOK(irq) do { } while (0) | 119 | } |
118 | 120 | ||
119 | #endif | 121 | #endif |
120 | 122 | ||
diff --git a/arch/mips/include/asm/pmc-sierra/msp71xx/cpu-feature-overrides.h b/arch/mips/include/asm/pmc-sierra/msp71xx/cpu-feature-overrides.h new file mode 100644 index 000000000000..a80801b094bd --- /dev/null +++ b/arch/mips/include/asm/pmc-sierra/msp71xx/cpu-feature-overrides.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2003, 04, 07 Ralf Baechle (ralf@linux-mips.org) | ||
7 | */ | ||
8 | #ifndef __ASM_MACH_MSP71XX_CPU_FEATURE_OVERRIDES_H | ||
9 | #define __ASM_MACH_MSP71XX_CPU_FEATURE_OVERRIDES_H | ||
10 | |||
11 | #define cpu_has_mips16 1 | ||
12 | #define cpu_has_dsp 1 | ||
13 | #define cpu_has_mipsmt 1 | ||
14 | #define cpu_has_fpu 0 | ||
15 | |||
16 | #define cpu_has_mips32r1 0 | ||
17 | #define cpu_has_mips32r2 1 | ||
18 | #define cpu_has_mips64r1 0 | ||
19 | #define cpu_has_mips64r2 0 | ||
20 | |||
21 | #endif /* __ASM_MACH_MSP71XX_CPU_FEATURE_OVERRIDES_H */ | ||
diff --git a/arch/mips/include/asm/pmc-sierra/msp71xx/msp_gpio_macros.h b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_gpio_macros.h new file mode 100644 index 000000000000..156f320c69e7 --- /dev/null +++ b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_gpio_macros.h | |||
@@ -0,0 +1,343 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Macros for external SMP-safe access to the PMC MSP71xx reference | ||
4 | * board GPIO pins | ||
5 | * | ||
6 | * Copyright 2010 PMC-Sierra, Inc. | ||
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 __MSP_GPIO_MACROS_H__ | ||
30 | #define __MSP_GPIO_MACROS_H__ | ||
31 | |||
32 | #include <msp_regops.h> | ||
33 | #include <msp_regs.h> | ||
34 | |||
35 | #ifdef CONFIG_PMC_MSP7120_GW | ||
36 | #define MSP_NUM_GPIOS 20 | ||
37 | #else | ||
38 | #define MSP_NUM_GPIOS 28 | ||
39 | #endif | ||
40 | |||
41 | /* -- GPIO Enumerations -- */ | ||
42 | enum msp_gpio_data { | ||
43 | MSP_GPIO_LO = 0, | ||
44 | MSP_GPIO_HI = 1, | ||
45 | MSP_GPIO_NONE, /* Special - Means pin is out of range */ | ||
46 | MSP_GPIO_TOGGLE, /* Special - Sets pin to opposite */ | ||
47 | }; | ||
48 | |||
49 | enum msp_gpio_mode { | ||
50 | MSP_GPIO_INPUT = 0x0, | ||
51 | /* MSP_GPIO_ INTERRUPT = 0x1, Not supported yet */ | ||
52 | MSP_GPIO_UART_INPUT = 0x2, /* Only GPIO 4 or 5 */ | ||
53 | MSP_GPIO_OUTPUT = 0x8, | ||
54 | MSP_GPIO_UART_OUTPUT = 0x9, /* Only GPIO 2 or 3 */ | ||
55 | MSP_GPIO_PERIF_TIMERA = 0x9, /* Only GPIO 0 or 1 */ | ||
56 | MSP_GPIO_PERIF_TIMERB = 0xa, /* Only GPIO 0 or 1 */ | ||
57 | MSP_GPIO_UNKNOWN = 0xb, /* No such GPIO or mode */ | ||
58 | }; | ||
59 | |||
60 | /* -- Static Tables -- */ | ||
61 | |||
62 | /* Maps pins to data register */ | ||
63 | static volatile u32 * const MSP_GPIO_DATA_REGISTER[] = { | ||
64 | /* GPIO 0 and 1 on the first register */ | ||
65 | GPIO_DATA1_REG, GPIO_DATA1_REG, | ||
66 | /* GPIO 2, 3, 4, and 5 on the second register */ | ||
67 | GPIO_DATA2_REG, GPIO_DATA2_REG, GPIO_DATA2_REG, GPIO_DATA2_REG, | ||
68 | /* GPIO 6, 7, 8, and 9 on the third register */ | ||
69 | GPIO_DATA3_REG, GPIO_DATA3_REG, GPIO_DATA3_REG, GPIO_DATA3_REG, | ||
70 | /* GPIO 10, 11, 12, 13, 14, and 15 on the fourth register */ | ||
71 | GPIO_DATA4_REG, GPIO_DATA4_REG, GPIO_DATA4_REG, GPIO_DATA4_REG, | ||
72 | GPIO_DATA4_REG, GPIO_DATA4_REG, | ||
73 | /* GPIO 16 - 23 on the first strange EXTENDED register */ | ||
74 | EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, | ||
75 | EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, | ||
76 | EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, | ||
77 | /* GPIO 24 - 27 on the second strange EXTENDED register */ | ||
78 | EXTENDED_GPIO2_REG, EXTENDED_GPIO2_REG, EXTENDED_GPIO2_REG, | ||
79 | EXTENDED_GPIO2_REG, | ||
80 | }; | ||
81 | |||
82 | /* Maps pins to mode register */ | ||
83 | static volatile u32 * const MSP_GPIO_MODE_REGISTER[] = { | ||
84 | /* GPIO 0 and 1 on the first register */ | ||
85 | GPIO_CFG1_REG, GPIO_CFG1_REG, | ||
86 | /* GPIO 2, 3, 4, and 5 on the second register */ | ||
87 | GPIO_CFG2_REG, GPIO_CFG2_REG, GPIO_CFG2_REG, GPIO_CFG2_REG, | ||
88 | /* GPIO 6, 7, 8, and 9 on the third register */ | ||
89 | GPIO_CFG3_REG, GPIO_CFG3_REG, GPIO_CFG3_REG, GPIO_CFG3_REG, | ||
90 | /* GPIO 10, 11, 12, 13, 14, and 15 on the fourth register */ | ||
91 | GPIO_CFG4_REG, GPIO_CFG4_REG, GPIO_CFG4_REG, GPIO_CFG4_REG, | ||
92 | GPIO_CFG4_REG, GPIO_CFG4_REG, | ||
93 | /* GPIO 16 - 23 on the first strange EXTENDED register */ | ||
94 | EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, | ||
95 | EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, | ||
96 | EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, | ||
97 | /* GPIO 24 - 27 on the second strange EXTENDED register */ | ||
98 | EXTENDED_GPIO2_REG, EXTENDED_GPIO2_REG, EXTENDED_GPIO2_REG, | ||
99 | EXTENDED_GPIO2_REG, | ||
100 | }; | ||
101 | |||
102 | /* Maps 'basic' pins to relative offset from 0 per register */ | ||
103 | static int MSP_GPIO_OFFSET[] = { | ||
104 | /* GPIO 0 and 1 on the first register */ | ||
105 | 0, 0, | ||
106 | /* GPIO 2, 3, 4, and 5 on the second register */ | ||
107 | 2, 2, 2, 2, | ||
108 | /* GPIO 6, 7, 8, and 9 on the third register */ | ||
109 | 6, 6, 6, 6, | ||
110 | /* GPIO 10, 11, 12, 13, 14, and 15 on the fourth register */ | ||
111 | 10, 10, 10, 10, 10, 10, | ||
112 | }; | ||
113 | |||
114 | /* Maps MODE to allowed pin mask */ | ||
115 | static unsigned int MSP_GPIO_MODE_ALLOWED[] = { | ||
116 | 0xffffffff, /* Mode 0 - INPUT */ | ||
117 | 0x00000, /* Mode 1 - INTERRUPT */ | ||
118 | 0x00030, /* Mode 2 - UART_INPUT (GPIO 4, 5)*/ | ||
119 | 0, 0, 0, 0, 0, /* Modes 3, 4, 5, 6, and 7 are reserved */ | ||
120 | 0xffffffff, /* Mode 8 - OUTPUT */ | ||
121 | 0x0000f, /* Mode 9 - UART_OUTPUT/ | ||
122 | PERF_TIMERA (GPIO 0, 1, 2, 3) */ | ||
123 | 0x00003, /* Mode a - PERF_TIMERB (GPIO 0, 1) */ | ||
124 | 0x00000, /* Mode b - Not really a mode! */ | ||
125 | }; | ||
126 | |||
127 | /* -- Bit masks -- */ | ||
128 | |||
129 | /* This gives you the 'register relative offset gpio' number */ | ||
130 | #define OFFSET_GPIO_NUMBER(gpio) (gpio - MSP_GPIO_OFFSET[gpio]) | ||
131 | |||
132 | /* These take the 'register relative offset gpio' number */ | ||
133 | #define BASIC_DATA_REG_MASK(ogpio) (1 << ogpio) | ||
134 | #define BASIC_MODE_REG_VALUE(mode, ogpio) \ | ||
135 | (mode << BASIC_MODE_REG_SHIFT(ogpio)) | ||
136 | #define BASIC_MODE_REG_MASK(ogpio) \ | ||
137 | BASIC_MODE_REG_VALUE(0xf, ogpio) | ||
138 | #define BASIC_MODE_REG_SHIFT(ogpio) (ogpio * 4) | ||
139 | #define BASIC_MODE_REG_FROM_REG(data, ogpio) \ | ||
140 | ((data & BASIC_MODE_REG_MASK(ogpio)) >> BASIC_MODE_REG_SHIFT(ogpio)) | ||
141 | |||
142 | /* These take the actual GPIO number (0 through 15) */ | ||
143 | #define BASIC_DATA_MASK(gpio) \ | ||
144 | BASIC_DATA_REG_MASK(OFFSET_GPIO_NUMBER(gpio)) | ||
145 | #define BASIC_MODE_MASK(gpio) \ | ||
146 | BASIC_MODE_REG_MASK(OFFSET_GPIO_NUMBER(gpio)) | ||
147 | #define BASIC_MODE(mode, gpio) \ | ||
148 | BASIC_MODE_REG_VALUE(mode, OFFSET_GPIO_NUMBER(gpio)) | ||
149 | #define BASIC_MODE_SHIFT(gpio) \ | ||
150 | BASIC_MODE_REG_SHIFT(OFFSET_GPIO_NUMBER(gpio)) | ||
151 | #define BASIC_MODE_FROM_REG(data, gpio) \ | ||
152 | BASIC_MODE_REG_FROM_REG(data, OFFSET_GPIO_NUMBER(gpio)) | ||
153 | |||
154 | /* | ||
155 | * Each extended GPIO register is 32 bits long and is responsible for up to | ||
156 | * eight GPIOs. The least significant 16 bits contain the set and clear bit | ||
157 | * pair for each of the GPIOs. The most significant 16 bits contain the | ||
158 | * disable and enable bit pair for each of the GPIOs. For example, the | ||
159 | * extended GPIO reg for GPIOs 16-23 is as follows: | ||
160 | * | ||
161 | * 31: GPIO23_DISABLE | ||
162 | * ... | ||
163 | * 19: GPIO17_DISABLE | ||
164 | * 18: GPIO17_ENABLE | ||
165 | * 17: GPIO16_DISABLE | ||
166 | * 16: GPIO16_ENABLE | ||
167 | * ... | ||
168 | * 3: GPIO17_SET | ||
169 | * 2: GPIO17_CLEAR | ||
170 | * 1: GPIO16_SET | ||
171 | * 0: GPIO16_CLEAR | ||
172 | */ | ||
173 | |||
174 | /* This gives the 'register relative offset gpio' number */ | ||
175 | #define EXTENDED_OFFSET_GPIO(gpio) (gpio < 24 ? gpio - 16 : gpio - 24) | ||
176 | |||
177 | /* These take the 'register relative offset gpio' number */ | ||
178 | #define EXTENDED_REG_DISABLE(ogpio) (0x2 << ((ogpio * 2) + 16)) | ||
179 | #define EXTENDED_REG_ENABLE(ogpio) (0x1 << ((ogpio * 2) + 16)) | ||
180 | #define EXTENDED_REG_SET(ogpio) (0x2 << (ogpio * 2)) | ||
181 | #define EXTENDED_REG_CLR(ogpio) (0x1 << (ogpio * 2)) | ||
182 | |||
183 | /* These take the actual GPIO number (16 through 27) */ | ||
184 | #define EXTENDED_DISABLE(gpio) \ | ||
185 | EXTENDED_REG_DISABLE(EXTENDED_OFFSET_GPIO(gpio)) | ||
186 | #define EXTENDED_ENABLE(gpio) \ | ||
187 | EXTENDED_REG_ENABLE(EXTENDED_OFFSET_GPIO(gpio)) | ||
188 | #define EXTENDED_SET(gpio) \ | ||
189 | EXTENDED_REG_SET(EXTENDED_OFFSET_GPIO(gpio)) | ||
190 | #define EXTENDED_CLR(gpio) \ | ||
191 | EXTENDED_REG_CLR(EXTENDED_OFFSET_GPIO(gpio)) | ||
192 | |||
193 | #define EXTENDED_FULL_MASK (0xffffffff) | ||
194 | |||
195 | /* -- API inline-functions -- */ | ||
196 | |||
197 | /* | ||
198 | * Gets the current value of the specified pin | ||
199 | */ | ||
200 | static inline enum msp_gpio_data msp_gpio_pin_get(unsigned int gpio) | ||
201 | { | ||
202 | u32 pinhi_mask = 0, pinhi_mask2 = 0; | ||
203 | |||
204 | if (gpio >= MSP_NUM_GPIOS) | ||
205 | return MSP_GPIO_NONE; | ||
206 | |||
207 | if (gpio < 16) { | ||
208 | pinhi_mask = BASIC_DATA_MASK(gpio); | ||
209 | } else { | ||
210 | /* | ||
211 | * Two cases are possible with the EXTENDED register: | ||
212 | * - In output mode (ENABLED flag set), check the CLR bit | ||
213 | * - In input mode (ENABLED flag not set), check the SET bit | ||
214 | */ | ||
215 | pinhi_mask = EXTENDED_ENABLE(gpio) | EXTENDED_CLR(gpio); | ||
216 | pinhi_mask2 = EXTENDED_SET(gpio); | ||
217 | } | ||
218 | if (((*MSP_GPIO_DATA_REGISTER[gpio] & pinhi_mask) == pinhi_mask) || | ||
219 | (*MSP_GPIO_DATA_REGISTER[gpio] & pinhi_mask2)) | ||
220 | return MSP_GPIO_HI; | ||
221 | else | ||
222 | return MSP_GPIO_LO; | ||
223 | } | ||
224 | |||
225 | /* Sets the specified pin to the specified value */ | ||
226 | static inline void msp_gpio_pin_set(enum msp_gpio_data data, unsigned int gpio) | ||
227 | { | ||
228 | if (gpio >= MSP_NUM_GPIOS) | ||
229 | return; | ||
230 | |||
231 | if (gpio < 16) { | ||
232 | if (data == MSP_GPIO_TOGGLE) | ||
233 | toggle_reg32(MSP_GPIO_DATA_REGISTER[gpio], | ||
234 | BASIC_DATA_MASK(gpio)); | ||
235 | else if (data == MSP_GPIO_HI) | ||
236 | set_reg32(MSP_GPIO_DATA_REGISTER[gpio], | ||
237 | BASIC_DATA_MASK(gpio)); | ||
238 | else | ||
239 | clear_reg32(MSP_GPIO_DATA_REGISTER[gpio], | ||
240 | BASIC_DATA_MASK(gpio)); | ||
241 | } else { | ||
242 | if (data == MSP_GPIO_TOGGLE) { | ||
243 | /* Special ugly case: | ||
244 | * We have to read the CLR bit. | ||
245 | * If set, we write the CLR bit. | ||
246 | * If not, we write the SET bit. | ||
247 | */ | ||
248 | u32 tmpdata; | ||
249 | |||
250 | custom_read_reg32(MSP_GPIO_DATA_REGISTER[gpio], | ||
251 | tmpdata); | ||
252 | if (tmpdata & EXTENDED_CLR(gpio)) | ||
253 | tmpdata = EXTENDED_CLR(gpio); | ||
254 | else | ||
255 | tmpdata = EXTENDED_SET(gpio); | ||
256 | custom_write_reg32(MSP_GPIO_DATA_REGISTER[gpio], | ||
257 | tmpdata); | ||
258 | } else { | ||
259 | u32 newdata; | ||
260 | |||
261 | if (data == MSP_GPIO_HI) | ||
262 | newdata = EXTENDED_SET(gpio); | ||
263 | else | ||
264 | newdata = EXTENDED_CLR(gpio); | ||
265 | set_value_reg32(MSP_GPIO_DATA_REGISTER[gpio], | ||
266 | EXTENDED_FULL_MASK, newdata); | ||
267 | } | ||
268 | } | ||
269 | } | ||
270 | |||
271 | /* Sets the specified pin to the specified value */ | ||
272 | static inline void msp_gpio_pin_hi(unsigned int gpio) | ||
273 | { | ||
274 | msp_gpio_pin_set(MSP_GPIO_HI, gpio); | ||
275 | } | ||
276 | |||
277 | /* Sets the specified pin to the specified value */ | ||
278 | static inline void msp_gpio_pin_lo(unsigned int gpio) | ||
279 | { | ||
280 | msp_gpio_pin_set(MSP_GPIO_LO, gpio); | ||
281 | } | ||
282 | |||
283 | /* Sets the specified pin to the opposite value */ | ||
284 | static inline void msp_gpio_pin_toggle(unsigned int gpio) | ||
285 | { | ||
286 | msp_gpio_pin_set(MSP_GPIO_TOGGLE, gpio); | ||
287 | } | ||
288 | |||
289 | /* Gets the mode of the specified pin */ | ||
290 | static inline enum msp_gpio_mode msp_gpio_pin_get_mode(unsigned int gpio) | ||
291 | { | ||
292 | enum msp_gpio_mode retval = MSP_GPIO_UNKNOWN; | ||
293 | uint32_t data; | ||
294 | |||
295 | if (gpio >= MSP_NUM_GPIOS) | ||
296 | return retval; | ||
297 | |||
298 | data = *MSP_GPIO_MODE_REGISTER[gpio]; | ||
299 | |||
300 | if (gpio < 16) { | ||
301 | retval = BASIC_MODE_FROM_REG(data, gpio); | ||
302 | } else { | ||
303 | /* Extended pins can only be either INPUT or OUTPUT */ | ||
304 | if (data & EXTENDED_ENABLE(gpio)) | ||
305 | retval = MSP_GPIO_OUTPUT; | ||
306 | else | ||
307 | retval = MSP_GPIO_INPUT; | ||
308 | } | ||
309 | |||
310 | return retval; | ||
311 | } | ||
312 | |||
313 | /* | ||
314 | * Sets the specified mode on the requested pin | ||
315 | * Returns 0 on success, or -1 if that mode is not allowed on this pin | ||
316 | */ | ||
317 | static inline int msp_gpio_pin_mode(enum msp_gpio_mode mode, unsigned int gpio) | ||
318 | { | ||
319 | u32 modemask, newmode; | ||
320 | |||
321 | if ((1 << gpio) & ~MSP_GPIO_MODE_ALLOWED[mode]) | ||
322 | return -1; | ||
323 | |||
324 | if (gpio >= MSP_NUM_GPIOS) | ||
325 | return -1; | ||
326 | |||
327 | if (gpio < 16) { | ||
328 | modemask = BASIC_MODE_MASK(gpio); | ||
329 | newmode = BASIC_MODE(mode, gpio); | ||
330 | } else { | ||
331 | modemask = EXTENDED_FULL_MASK; | ||
332 | if (mode == MSP_GPIO_INPUT) | ||
333 | newmode = EXTENDED_DISABLE(gpio); | ||
334 | else | ||
335 | newmode = EXTENDED_ENABLE(gpio); | ||
336 | } | ||
337 | /* Do the set atomically */ | ||
338 | set_value_reg32(MSP_GPIO_MODE_REGISTER[gpio], modemask, newmode); | ||
339 | |||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | #endif /* __MSP_GPIO_MACROS_H__ */ | ||
diff --git a/arch/mips/include/asm/pmc-sierra/msp71xx/msp_regs.h b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_regs.h index 603eb737b4a8..692c1b658b92 100644 --- a/arch/mips/include/asm/pmc-sierra/msp71xx/msp_regs.h +++ b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_regs.h | |||
@@ -91,12 +91,10 @@ | |||
91 | /* MAC C device registers */ | 91 | /* MAC C device registers */ |
92 | #define MSP_ADSL2_BASE (MSP_MSB_BASE + 0xA80000) | 92 | #define MSP_ADSL2_BASE (MSP_MSB_BASE + 0xA80000) |
93 | /* ADSL2 device registers */ | 93 | /* ADSL2 device registers */ |
94 | #define MSP_USB_BASE (MSP_MSB_BASE + 0xB40000) | 94 | #define MSP_USB0_BASE (MSP_MSB_BASE + 0xB00000) |
95 | /* USB device registers */ | 95 | /* USB0 device registers */ |
96 | #define MSP_USB_BASE_START (MSP_MSB_BASE + 0xB40100) | 96 | #define MSP_USB1_BASE (MSP_MSB_BASE + 0x300000) |
97 | /* USB device registers */ | 97 | /* USB1 device registers */ |
98 | #define MSP_USB_BASE_END (MSP_MSB_BASE + 0xB401FF) | ||
99 | /* USB device registers */ | ||
100 | #define MSP_CPUIF_BASE (MSP_MSB_BASE + 0xC00000) | 98 | #define MSP_CPUIF_BASE (MSP_MSB_BASE + 0xC00000) |
101 | /* CPU interface registers */ | 99 | /* CPU interface registers */ |
102 | 100 | ||
@@ -319,8 +317,11 @@ | |||
319 | #define CPU_ERR2_REG regptr(MSP_SLP_BASE + 0x184) | 317 | #define CPU_ERR2_REG regptr(MSP_SLP_BASE + 0x184) |
320 | /* CPU/SLP Error status 1 */ | 318 | /* CPU/SLP Error status 1 */ |
321 | 319 | ||
322 | #define EXTENDED_GPIO_REG regptr(MSP_SLP_BASE + 0x188) | 320 | /* Extended GPIO registers */ |
323 | /* Extended GPIO register */ | 321 | #define EXTENDED_GPIO1_REG regptr(MSP_SLP_BASE + 0x188) |
322 | #define EXTENDED_GPIO2_REG regptr(MSP_SLP_BASE + 0x18c) | ||
323 | #define EXTENDED_GPIO_REG EXTENDED_GPIO1_REG | ||
324 | /* Backward-compatibility */ | ||
324 | 325 | ||
325 | /* System Error registers */ | 326 | /* System Error registers */ |
326 | #define SLP_ERR_STS_REG regptr(MSP_SLP_BASE + 0x190) | 327 | #define SLP_ERR_STS_REG regptr(MSP_SLP_BASE + 0x190) |
diff --git a/arch/mips/include/asm/pmc-sierra/msp71xx/msp_usb.h b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_usb.h new file mode 100644 index 000000000000..4c9348df9df2 --- /dev/null +++ b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_usb.h | |||
@@ -0,0 +1,144 @@ | |||
1 | /****************************************************************** | ||
2 | * Copyright (c) 2000-2007 PMC-Sierra INC. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it | ||
5 | * and/or modify it under the terms of the GNU General | ||
6 | * Public License as published by the Free Software | ||
7 | * Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be | ||
11 | * useful, but WITHOUT ANY WARRANTY; without even the implied | ||
12 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR | ||
13 | * PURPOSE. See the GNU General Public License for more | ||
14 | * details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public | ||
17 | * License along with this program; if not, write to the Free | ||
18 | * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA | ||
19 | * 02139, USA. | ||
20 | * | ||
21 | * PMC-SIERRA INC. DISCLAIMS ANY LIABILITY OF ANY KIND | ||
22 | * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS | ||
23 | * SOFTWARE. | ||
24 | */ | ||
25 | #ifndef MSP_USB_H_ | ||
26 | #define MSP_USB_H_ | ||
27 | |||
28 | #ifdef CONFIG_MSP_HAS_DUAL_USB | ||
29 | #define NUM_USB_DEVS 2 | ||
30 | #else | ||
31 | #define NUM_USB_DEVS 1 | ||
32 | #endif | ||
33 | |||
34 | /* Register spaces for USB host 0 */ | ||
35 | #define MSP_USB0_MAB_START (MSP_USB0_BASE + 0x0) | ||
36 | #define MSP_USB0_MAB_END (MSP_USB0_BASE + 0x17) | ||
37 | #define MSP_USB0_ID_START (MSP_USB0_BASE + 0x40000) | ||
38 | #define MSP_USB0_ID_END (MSP_USB0_BASE + 0x4008f) | ||
39 | #define MSP_USB0_HS_START (MSP_USB0_BASE + 0x40100) | ||
40 | #define MSP_USB0_HS_END (MSP_USB0_BASE + 0x401FF) | ||
41 | |||
42 | /* Register spaces for USB host 1 */ | ||
43 | #define MSP_USB1_MAB_START (MSP_USB1_BASE + 0x0) | ||
44 | #define MSP_USB1_MAB_END (MSP_USB1_BASE + 0x17) | ||
45 | #define MSP_USB1_ID_START (MSP_USB1_BASE + 0x40000) | ||
46 | #define MSP_USB1_ID_END (MSP_USB1_BASE + 0x4008f) | ||
47 | #define MSP_USB1_HS_START (MSP_USB1_BASE + 0x40100) | ||
48 | #define MSP_USB1_HS_END (MSP_USB1_BASE + 0x401ff) | ||
49 | |||
50 | /* USB Identification registers */ | ||
51 | struct msp_usbid_regs { | ||
52 | u32 id; /* 0x0: Identification register */ | ||
53 | u32 hwgen; /* 0x4: General HW params */ | ||
54 | u32 hwhost; /* 0x8: Host HW params */ | ||
55 | u32 hwdev; /* 0xc: Device HW params */ | ||
56 | u32 hwtxbuf; /* 0x10: Tx buffer HW params */ | ||
57 | u32 hwrxbuf; /* 0x14: Rx buffer HW params */ | ||
58 | u32 reserved[26]; | ||
59 | u32 timer0_load; /* 0x80: General-purpose timer 0 load*/ | ||
60 | u32 timer0_ctrl; /* 0x84: General-purpose timer 0 control */ | ||
61 | u32 timer1_load; /* 0x88: General-purpose timer 1 load*/ | ||
62 | u32 timer1_ctrl; /* 0x8c: General-purpose timer 1 control */ | ||
63 | }; | ||
64 | |||
65 | /* MSBus to AMBA registers */ | ||
66 | struct msp_mab_regs { | ||
67 | u32 isr; /* 0x0: Interrupt status */ | ||
68 | u32 imr; /* 0x4: Interrupt mask */ | ||
69 | u32 thcr0; /* 0x8: Transaction header capture 0 */ | ||
70 | u32 thcr1; /* 0xc: Transaction header capture 1 */ | ||
71 | u32 int_stat; /* 0x10: Interrupt status summary */ | ||
72 | u32 phy_cfg; /* 0x14: USB phy config */ | ||
73 | }; | ||
74 | |||
75 | /* EHCI registers */ | ||
76 | struct msp_usbhs_regs { | ||
77 | u32 hciver; /* 0x0: Version and offset to operational regs */ | ||
78 | u32 hcsparams; /* 0x4: Host control structural parameters */ | ||
79 | u32 hccparams; /* 0x8: Host control capability parameters */ | ||
80 | u32 reserved0[5]; | ||
81 | u32 dciver; /* 0x20: Device interface version */ | ||
82 | u32 dccparams; /* 0x24: Device control capability parameters */ | ||
83 | u32 reserved1[6]; | ||
84 | u32 cmd; /* 0x40: USB command */ | ||
85 | u32 sts; /* 0x44: USB status */ | ||
86 | u32 int_ena; /* 0x48: USB interrupt enable */ | ||
87 | u32 frindex; /* 0x4c: Frame index */ | ||
88 | u32 reserved3; | ||
89 | union { | ||
90 | struct { | ||
91 | u32 flb_addr; /* 0x54: Frame list base address */ | ||
92 | u32 next_async_addr; /* 0x58: next asynchronous addr */ | ||
93 | u32 ttctrl; /* 0x5c: embedded transaction translator | ||
94 | async buffer status */ | ||
95 | u32 burst_size; /* 0x60: Controller burst size */ | ||
96 | u32 tx_fifo_ctrl; /* 0x64: Tx latency FIFO tuning */ | ||
97 | u32 reserved0[4]; | ||
98 | u32 endpt_nak; /* 0x78: Endpoint NAK */ | ||
99 | u32 endpt_nak_ena; /* 0x7c: Endpoint NAK enable */ | ||
100 | u32 cfg_flag; /* 0x80: Config flag */ | ||
101 | u32 port_sc1; /* 0x84: Port status & control 1 */ | ||
102 | u32 reserved1[7]; | ||
103 | u32 otgsc; /* 0xa4: OTG status & control */ | ||
104 | u32 mode; /* 0xa8: USB controller mode */ | ||
105 | } host; | ||
106 | |||
107 | struct { | ||
108 | u32 dev_addr; /* 0x54: Device address */ | ||
109 | u32 endpt_list_addr; /* 0x58: Endpoint list address */ | ||
110 | u32 reserved0[7]; | ||
111 | u32 endpt_nak; /* 0x74 */ | ||
112 | u32 endpt_nak_ctrl; /* 0x78 */ | ||
113 | u32 cfg_flag; /* 0x80 */ | ||
114 | u32 port_sc1; /* 0x84: Port status & control 1 */ | ||
115 | u32 reserved[7]; | ||
116 | u32 otgsc; /* 0xa4: OTG status & control */ | ||
117 | u32 mode; /* 0xa8: USB controller mode */ | ||
118 | u32 endpt_setup_stat; /* 0xac */ | ||
119 | u32 endpt_prime; /* 0xb0 */ | ||
120 | u32 endpt_flush; /* 0xb4 */ | ||
121 | u32 endpt_stat; /* 0xb8 */ | ||
122 | u32 endpt_complete; /* 0xbc */ | ||
123 | u32 endpt_ctrl0; /* 0xc0 */ | ||
124 | u32 endpt_ctrl1; /* 0xc4 */ | ||
125 | u32 endpt_ctrl2; /* 0xc8 */ | ||
126 | u32 endpt_ctrl3; /* 0xcc */ | ||
127 | } device; | ||
128 | } u; | ||
129 | }; | ||
130 | /* | ||
131 | * Container for the more-generic platform_device. | ||
132 | * This exists mainly as a way to map the non-standard register | ||
133 | * spaces and make them accessible to the USB ISR. | ||
134 | */ | ||
135 | struct mspusb_device { | ||
136 | struct msp_mab_regs __iomem *mab_regs; | ||
137 | struct msp_usbid_regs __iomem *usbid_regs; | ||
138 | struct msp_usbhs_regs __iomem *usbhs_regs; | ||
139 | struct platform_device dev; | ||
140 | }; | ||
141 | |||
142 | #define to_mspusb_device(x) container_of((x), struct mspusb_device, dev) | ||
143 | #define TO_HOST_ID(x) ((x) & 0x3) | ||
144 | #endif /*MSP_USB_H_*/ | ||
diff --git a/arch/mips/include/asm/spinlock.h b/arch/mips/include/asm/spinlock.h index 396e402fbe2c..ca61e846ab0f 100644 --- a/arch/mips/include/asm/spinlock.h +++ b/arch/mips/include/asm/spinlock.h | |||
@@ -245,16 +245,16 @@ static inline void arch_read_lock(arch_rwlock_t *rw) | |||
245 | __asm__ __volatile__( | 245 | __asm__ __volatile__( |
246 | " .set noreorder # arch_read_lock \n" | 246 | " .set noreorder # arch_read_lock \n" |
247 | "1: ll %1, %2 \n" | 247 | "1: ll %1, %2 \n" |
248 | " bltz %1, 2f \n" | 248 | " bltz %1, 3f \n" |
249 | " addu %1, 1 \n" | 249 | " addu %1, 1 \n" |
250 | " sc %1, %0 \n" | 250 | "2: sc %1, %0 \n" |
251 | " beqz %1, 1b \n" | 251 | " beqz %1, 1b \n" |
252 | " nop \n" | 252 | " nop \n" |
253 | " .subsection 2 \n" | 253 | " .subsection 2 \n" |
254 | "2: ll %1, %2 \n" | 254 | "3: ll %1, %2 \n" |
255 | " bltz %1, 2b \n" | 255 | " bltz %1, 3b \n" |
256 | " addu %1, 1 \n" | 256 | " addu %1, 1 \n" |
257 | " b 1b \n" | 257 | " b 2b \n" |
258 | " nop \n" | 258 | " nop \n" |
259 | " .previous \n" | 259 | " .previous \n" |
260 | " .set reorder \n" | 260 | " .set reorder \n" |
@@ -324,16 +324,16 @@ static inline void arch_write_lock(arch_rwlock_t *rw) | |||
324 | __asm__ __volatile__( | 324 | __asm__ __volatile__( |
325 | " .set noreorder # arch_write_lock \n" | 325 | " .set noreorder # arch_write_lock \n" |
326 | "1: ll %1, %2 \n" | 326 | "1: ll %1, %2 \n" |
327 | " bnez %1, 2f \n" | 327 | " bnez %1, 3f \n" |
328 | " lui %1, 0x8000 \n" | 328 | " lui %1, 0x8000 \n" |
329 | " sc %1, %0 \n" | 329 | "2: sc %1, %0 \n" |
330 | " beqz %1, 2f \n" | 330 | " beqz %1, 3f \n" |
331 | " nop \n" | 331 | " nop \n" |
332 | " .subsection 2 \n" | 332 | " .subsection 2 \n" |
333 | "2: ll %1, %2 \n" | 333 | "3: ll %1, %2 \n" |
334 | " bnez %1, 2b \n" | 334 | " bnez %1, 3b \n" |
335 | " lui %1, 0x8000 \n" | 335 | " lui %1, 0x8000 \n" |
336 | " b 1b \n" | 336 | " b 2b \n" |
337 | " nop \n" | 337 | " nop \n" |
338 | " .previous \n" | 338 | " .previous \n" |
339 | " .set reorder \n" | 339 | " .set reorder \n" |
diff --git a/arch/mips/include/asm/unistd.h b/arch/mips/include/asm/unistd.h index 550725b881d5..dae22c1d2c82 100644 --- a/arch/mips/include/asm/unistd.h +++ b/arch/mips/include/asm/unistd.h | |||
@@ -359,16 +359,20 @@ | |||
359 | #define __NR_fanotify_init (__NR_Linux + 336) | 359 | #define __NR_fanotify_init (__NR_Linux + 336) |
360 | #define __NR_fanotify_mark (__NR_Linux + 337) | 360 | #define __NR_fanotify_mark (__NR_Linux + 337) |
361 | #define __NR_prlimit64 (__NR_Linux + 338) | 361 | #define __NR_prlimit64 (__NR_Linux + 338) |
362 | #define __NR_name_to_handle_at (__NR_Linux + 339) | ||
363 | #define __NR_open_by_handle_at (__NR_Linux + 340) | ||
364 | #define __NR_clock_adjtime (__NR_Linux + 341) | ||
365 | #define __NR_syncfs (__NR_Linux + 342) | ||
362 | 366 | ||
363 | /* | 367 | /* |
364 | * Offset of the last Linux o32 flavoured syscall | 368 | * Offset of the last Linux o32 flavoured syscall |
365 | */ | 369 | */ |
366 | #define __NR_Linux_syscalls 338 | 370 | #define __NR_Linux_syscalls 342 |
367 | 371 | ||
368 | #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ | 372 | #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ |
369 | 373 | ||
370 | #define __NR_O32_Linux 4000 | 374 | #define __NR_O32_Linux 4000 |
371 | #define __NR_O32_Linux_syscalls 338 | 375 | #define __NR_O32_Linux_syscalls 342 |
372 | 376 | ||
373 | #if _MIPS_SIM == _MIPS_SIM_ABI64 | 377 | #if _MIPS_SIM == _MIPS_SIM_ABI64 |
374 | 378 | ||
@@ -674,16 +678,20 @@ | |||
674 | #define __NR_fanotify_init (__NR_Linux + 295) | 678 | #define __NR_fanotify_init (__NR_Linux + 295) |
675 | #define __NR_fanotify_mark (__NR_Linux + 296) | 679 | #define __NR_fanotify_mark (__NR_Linux + 296) |
676 | #define __NR_prlimit64 (__NR_Linux + 297) | 680 | #define __NR_prlimit64 (__NR_Linux + 297) |
681 | #define __NR_name_to_handle_at (__NR_Linux + 298) | ||
682 | #define __NR_open_by_handle_at (__NR_Linux + 299) | ||
683 | #define __NR_clock_adjtime (__NR_Linux + 300) | ||
684 | #define __NR_syncfs (__NR_Linux + 301) | ||
677 | 685 | ||
678 | /* | 686 | /* |
679 | * Offset of the last Linux 64-bit flavoured syscall | 687 | * Offset of the last Linux 64-bit flavoured syscall |
680 | */ | 688 | */ |
681 | #define __NR_Linux_syscalls 297 | 689 | #define __NR_Linux_syscalls 301 |
682 | 690 | ||
683 | #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */ | 691 | #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */ |
684 | 692 | ||
685 | #define __NR_64_Linux 5000 | 693 | #define __NR_64_Linux 5000 |
686 | #define __NR_64_Linux_syscalls 297 | 694 | #define __NR_64_Linux_syscalls 301 |
687 | 695 | ||
688 | #if _MIPS_SIM == _MIPS_SIM_NABI32 | 696 | #if _MIPS_SIM == _MIPS_SIM_NABI32 |
689 | 697 | ||
@@ -994,16 +1002,20 @@ | |||
994 | #define __NR_fanotify_init (__NR_Linux + 300) | 1002 | #define __NR_fanotify_init (__NR_Linux + 300) |
995 | #define __NR_fanotify_mark (__NR_Linux + 301) | 1003 | #define __NR_fanotify_mark (__NR_Linux + 301) |
996 | #define __NR_prlimit64 (__NR_Linux + 302) | 1004 | #define __NR_prlimit64 (__NR_Linux + 302) |
1005 | #define __NR_name_to_handle_at (__NR_Linux + 303) | ||
1006 | #define __NR_open_by_handle_at (__NR_Linux + 304) | ||
1007 | #define __NR_clock_adjtime (__NR_Linux + 305) | ||
1008 | #define __NR_clock_adjtime (__NR_Linux + 306) | ||
997 | 1009 | ||
998 | /* | 1010 | /* |
999 | * Offset of the last N32 flavoured syscall | 1011 | * Offset of the last N32 flavoured syscall |
1000 | */ | 1012 | */ |
1001 | #define __NR_Linux_syscalls 302 | 1013 | #define __NR_Linux_syscalls 306 |
1002 | 1014 | ||
1003 | #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */ | 1015 | #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */ |
1004 | 1016 | ||
1005 | #define __NR_N32_Linux 6000 | 1017 | #define __NR_N32_Linux 6000 |
1006 | #define __NR_N32_Linux_syscalls 302 | 1018 | #define __NR_N32_Linux_syscalls 306 |
1007 | 1019 | ||
1008 | #ifdef __KERNEL__ | 1020 | #ifdef __KERNEL__ |
1009 | 1021 | ||
diff --git a/arch/mips/jazz/irq.c b/arch/mips/jazz/irq.c index 35b3e2f0af04..40f7c6b1e260 100644 --- a/arch/mips/jazz/irq.c +++ b/arch/mips/jazz/irq.c | |||
@@ -23,9 +23,9 @@ | |||
23 | 23 | ||
24 | static DEFINE_RAW_SPINLOCK(r4030_lock); | 24 | static DEFINE_RAW_SPINLOCK(r4030_lock); |
25 | 25 | ||
26 | static void enable_r4030_irq(unsigned int irq) | 26 | static void enable_r4030_irq(struct irq_data *d) |
27 | { | 27 | { |
28 | unsigned int mask = 1 << (irq - JAZZ_IRQ_START); | 28 | unsigned int mask = 1 << (d->irq - JAZZ_IRQ_START); |
29 | unsigned long flags; | 29 | unsigned long flags; |
30 | 30 | ||
31 | raw_spin_lock_irqsave(&r4030_lock, flags); | 31 | raw_spin_lock_irqsave(&r4030_lock, flags); |
@@ -34,9 +34,9 @@ static void enable_r4030_irq(unsigned int irq) | |||
34 | raw_spin_unlock_irqrestore(&r4030_lock, flags); | 34 | raw_spin_unlock_irqrestore(&r4030_lock, flags); |
35 | } | 35 | } |
36 | 36 | ||
37 | void disable_r4030_irq(unsigned int irq) | 37 | void disable_r4030_irq(struct irq_data *d) |
38 | { | 38 | { |
39 | unsigned int mask = ~(1 << (irq - JAZZ_IRQ_START)); | 39 | unsigned int mask = ~(1 << (d->irq - JAZZ_IRQ_START)); |
40 | unsigned long flags; | 40 | unsigned long flags; |
41 | 41 | ||
42 | raw_spin_lock_irqsave(&r4030_lock, flags); | 42 | raw_spin_lock_irqsave(&r4030_lock, flags); |
@@ -47,10 +47,8 @@ void disable_r4030_irq(unsigned int irq) | |||
47 | 47 | ||
48 | static struct irq_chip r4030_irq_type = { | 48 | static struct irq_chip r4030_irq_type = { |
49 | .name = "R4030", | 49 | .name = "R4030", |
50 | .ack = disable_r4030_irq, | 50 | .irq_mask = disable_r4030_irq, |
51 | .mask = disable_r4030_irq, | 51 | .irq_unmask = enable_r4030_irq, |
52 | .mask_ack = disable_r4030_irq, | ||
53 | .unmask = enable_r4030_irq, | ||
54 | }; | 52 | }; |
55 | 53 | ||
56 | void __init init_r4030_ints(void) | 54 | void __init init_r4030_ints(void) |
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c index 2c0e107966ad..bc18daaa8f84 100644 --- a/arch/mips/jz4740/board-qi_lb60.c +++ b/arch/mips/jz4740/board-qi_lb60.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/spi/spi_gpio.h> | 23 | #include <linux/spi/spi_gpio.h> |
24 | #include <linux/power_supply.h> | 24 | #include <linux/power_supply.h> |
25 | #include <linux/power/jz4740-battery.h> | 25 | #include <linux/power/jz4740-battery.h> |
26 | #include <linux/power/gpio-charger.h> | ||
26 | 27 | ||
27 | #include <asm/mach-jz4740/jz4740_fb.h> | 28 | #include <asm/mach-jz4740/jz4740_fb.h> |
28 | #include <asm/mach-jz4740/jz4740_mmc.h> | 29 | #include <asm/mach-jz4740/jz4740_mmc.h> |
@@ -49,14 +50,14 @@ static bool is_avt2; | |||
49 | 50 | ||
50 | /* NAND */ | 51 | /* NAND */ |
51 | static struct nand_ecclayout qi_lb60_ecclayout_1gb = { | 52 | static struct nand_ecclayout qi_lb60_ecclayout_1gb = { |
52 | /* .eccbytes = 36, | 53 | .eccbytes = 36, |
53 | .eccpos = { | 54 | .eccpos = { |
54 | 6, 7, 8, 9, 10, 11, 12, 13, | 55 | 6, 7, 8, 9, 10, 11, 12, 13, |
55 | 14, 15, 16, 17, 18, 19, 20, 21, | 56 | 14, 15, 16, 17, 18, 19, 20, 21, |
56 | 22, 23, 24, 25, 26, 27, 28, 29, | 57 | 22, 23, 24, 25, 26, 27, 28, 29, |
57 | 30, 31, 32, 33, 34, 35, 36, 37, | 58 | 30, 31, 32, 33, 34, 35, 36, 37, |
58 | 38, 39, 40, 41 | 59 | 38, 39, 40, 41 |
59 | },*/ | 60 | }, |
60 | .oobfree = { | 61 | .oobfree = { |
61 | { .offset = 2, .length = 4 }, | 62 | { .offset = 2, .length = 4 }, |
62 | { .offset = 42, .length = 22 } | 63 | { .offset = 42, .length = 22 } |
@@ -85,7 +86,7 @@ static struct mtd_partition qi_lb60_partitions_1gb[] = { | |||
85 | }; | 86 | }; |
86 | 87 | ||
87 | static struct nand_ecclayout qi_lb60_ecclayout_2gb = { | 88 | static struct nand_ecclayout qi_lb60_ecclayout_2gb = { |
88 | /* .eccbytes = 72, | 89 | .eccbytes = 72, |
89 | .eccpos = { | 90 | .eccpos = { |
90 | 12, 13, 14, 15, 16, 17, 18, 19, | 91 | 12, 13, 14, 15, 16, 17, 18, 19, |
91 | 20, 21, 22, 23, 24, 25, 26, 27, | 92 | 20, 21, 22, 23, 24, 25, 26, 27, |
@@ -96,7 +97,7 @@ static struct nand_ecclayout qi_lb60_ecclayout_2gb = { | |||
96 | 60, 61, 62, 63, 64, 65, 66, 67, | 97 | 60, 61, 62, 63, 64, 65, 66, 67, |
97 | 68, 69, 70, 71, 72, 73, 74, 75, | 98 | 68, 69, 70, 71, 72, 73, 74, 75, |
98 | 76, 77, 78, 79, 80, 81, 82, 83 | 99 | 76, 77, 78, 79, 80, 81, 82, 83 |
99 | },*/ | 100 | }, |
100 | .oobfree = { | 101 | .oobfree = { |
101 | { .offset = 2, .length = 10 }, | 102 | { .offset = 2, .length = 10 }, |
102 | { .offset = 84, .length = 44 }, | 103 | { .offset = 84, .length = 44 }, |
@@ -396,6 +397,28 @@ static struct platform_device qi_lb60_pwm_beeper = { | |||
396 | }, | 397 | }, |
397 | }; | 398 | }; |
398 | 399 | ||
400 | /* charger */ | ||
401 | static char *qi_lb60_batteries[] = { | ||
402 | "battery", | ||
403 | }; | ||
404 | |||
405 | static struct gpio_charger_platform_data qi_lb60_charger_pdata = { | ||
406 | .name = "usb", | ||
407 | .type = POWER_SUPPLY_TYPE_USB, | ||
408 | .gpio = JZ_GPIO_PORTD(28), | ||
409 | .gpio_active_low = 1, | ||
410 | .supplied_to = qi_lb60_batteries, | ||
411 | .num_supplicants = ARRAY_SIZE(qi_lb60_batteries), | ||
412 | }; | ||
413 | |||
414 | static struct platform_device qi_lb60_charger_device = { | ||
415 | .name = "gpio-charger", | ||
416 | .dev = { | ||
417 | .platform_data = &qi_lb60_charger_pdata, | ||
418 | }, | ||
419 | }; | ||
420 | |||
421 | |||
399 | static struct platform_device *jz_platform_devices[] __initdata = { | 422 | static struct platform_device *jz_platform_devices[] __initdata = { |
400 | &jz4740_udc_device, | 423 | &jz4740_udc_device, |
401 | &jz4740_mmc_device, | 424 | &jz4740_mmc_device, |
@@ -410,6 +433,7 @@ static struct platform_device *jz_platform_devices[] __initdata = { | |||
410 | &jz4740_adc_device, | 433 | &jz4740_adc_device, |
411 | &qi_lb60_gpio_keys, | 434 | &qi_lb60_gpio_keys, |
412 | &qi_lb60_pwm_beeper, | 435 | &qi_lb60_pwm_beeper, |
436 | &qi_lb60_charger_device, | ||
413 | }; | 437 | }; |
414 | 438 | ||
415 | static void __init board_gpio_setup(void) | 439 | static void __init board_gpio_setup(void) |
diff --git a/arch/mips/jz4740/gpio.c b/arch/mips/jz4740/gpio.c index 88e6aeda5bf1..bd2fc29b95e0 100644 --- a/arch/mips/jz4740/gpio.c +++ b/arch/mips/jz4740/gpio.c | |||
@@ -86,7 +86,6 @@ struct jz_gpio_chip { | |||
86 | spinlock_t lock; | 86 | spinlock_t lock; |
87 | 87 | ||
88 | struct gpio_chip gpio_chip; | 88 | struct gpio_chip gpio_chip; |
89 | struct irq_chip irq_chip; | ||
90 | struct sys_device sysdev; | 89 | struct sys_device sysdev; |
91 | }; | 90 | }; |
92 | 91 | ||
@@ -102,9 +101,9 @@ static inline struct jz_gpio_chip *gpio_chip_to_jz_gpio_chip(struct gpio_chip *g | |||
102 | return container_of(gpio_chip, struct jz_gpio_chip, gpio_chip); | 101 | return container_of(gpio_chip, struct jz_gpio_chip, gpio_chip); |
103 | } | 102 | } |
104 | 103 | ||
105 | static inline struct jz_gpio_chip *irq_to_jz_gpio_chip(unsigned int irq) | 104 | static inline struct jz_gpio_chip *irq_to_jz_gpio_chip(struct irq_data *data) |
106 | { | 105 | { |
107 | return get_irq_chip_data(irq); | 106 | return irq_data_get_irq_chip_data(data); |
108 | } | 107 | } |
109 | 108 | ||
110 | static inline void jz_gpio_write_bit(unsigned int gpio, unsigned int reg) | 109 | static inline void jz_gpio_write_bit(unsigned int gpio, unsigned int reg) |
@@ -325,62 +324,52 @@ static void jz_gpio_irq_demux_handler(unsigned int irq, struct irq_desc *desc) | |||
325 | generic_handle_irq(gpio_irq); | 324 | generic_handle_irq(gpio_irq); |
326 | }; | 325 | }; |
327 | 326 | ||
328 | static inline void jz_gpio_set_irq_bit(unsigned int irq, unsigned int reg) | 327 | static inline void jz_gpio_set_irq_bit(struct irq_data *data, unsigned int reg) |
329 | { | 328 | { |
330 | struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq); | 329 | struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data); |
331 | writel(IRQ_TO_BIT(irq), chip->base + reg); | 330 | writel(IRQ_TO_BIT(data->irq), chip->base + reg); |
332 | } | 331 | } |
333 | 332 | ||
334 | static void jz_gpio_irq_mask(unsigned int irq) | 333 | static void jz_gpio_irq_mask(struct irq_data *data) |
335 | { | 334 | { |
336 | jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_MASK_SET); | 335 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_MASK_SET); |
337 | }; | 336 | }; |
338 | 337 | ||
339 | static void jz_gpio_irq_unmask(unsigned int irq) | 338 | static void jz_gpio_irq_unmask(struct irq_data *data) |
340 | { | 339 | { |
341 | struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq); | 340 | struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data); |
342 | 341 | ||
343 | jz_gpio_check_trigger_both(chip, irq); | 342 | jz_gpio_check_trigger_both(chip, data->irq); |
344 | 343 | ||
345 | jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_MASK_CLEAR); | 344 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_MASK_CLEAR); |
346 | }; | 345 | }; |
347 | 346 | ||
348 | /* TODO: Check if function is gpio */ | 347 | /* TODO: Check if function is gpio */ |
349 | static unsigned int jz_gpio_irq_startup(unsigned int irq) | 348 | static unsigned int jz_gpio_irq_startup(struct irq_data *data) |
350 | { | 349 | { |
351 | struct irq_desc *desc = irq_to_desc(irq); | 350 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_SELECT_SET); |
352 | 351 | jz_gpio_irq_unmask(data); | |
353 | jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_SELECT_SET); | ||
354 | |||
355 | desc->status &= ~IRQ_MASKED; | ||
356 | jz_gpio_irq_unmask(irq); | ||
357 | |||
358 | return 0; | 352 | return 0; |
359 | } | 353 | } |
360 | 354 | ||
361 | static void jz_gpio_irq_shutdown(unsigned int irq) | 355 | static void jz_gpio_irq_shutdown(struct irq_data *data) |
362 | { | 356 | { |
363 | struct irq_desc *desc = irq_to_desc(irq); | 357 | jz_gpio_irq_mask(data); |
364 | |||
365 | jz_gpio_irq_mask(irq); | ||
366 | desc->status |= IRQ_MASKED; | ||
367 | 358 | ||
368 | /* Set direction to input */ | 359 | /* Set direction to input */ |
369 | jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_CLEAR); | 360 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR); |
370 | jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_SELECT_CLEAR); | 361 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_SELECT_CLEAR); |
371 | } | 362 | } |
372 | 363 | ||
373 | static void jz_gpio_irq_ack(unsigned int irq) | 364 | static void jz_gpio_irq_ack(struct irq_data *data) |
374 | { | 365 | { |
375 | jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_FLAG_CLEAR); | 366 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_FLAG_CLEAR); |
376 | }; | 367 | }; |
377 | 368 | ||
378 | static int jz_gpio_irq_set_type(unsigned int irq, unsigned int flow_type) | 369 | static int jz_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type) |
379 | { | 370 | { |
380 | struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq); | 371 | struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data); |
381 | struct irq_desc *desc = irq_to_desc(irq); | 372 | unsigned int irq = data->irq; |
382 | |||
383 | jz_gpio_irq_mask(irq); | ||
384 | 373 | ||
385 | if (flow_type == IRQ_TYPE_EDGE_BOTH) { | 374 | if (flow_type == IRQ_TYPE_EDGE_BOTH) { |
386 | uint32_t value = readl(chip->base + JZ_REG_GPIO_PIN); | 375 | uint32_t value = readl(chip->base + JZ_REG_GPIO_PIN); |
@@ -395,45 +384,54 @@ static int jz_gpio_irq_set_type(unsigned int irq, unsigned int flow_type) | |||
395 | 384 | ||
396 | switch (flow_type) { | 385 | switch (flow_type) { |
397 | case IRQ_TYPE_EDGE_RISING: | 386 | case IRQ_TYPE_EDGE_RISING: |
398 | jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_SET); | 387 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_SET); |
399 | jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_SET); | 388 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_SET); |
400 | break; | 389 | break; |
401 | case IRQ_TYPE_EDGE_FALLING: | 390 | case IRQ_TYPE_EDGE_FALLING: |
402 | jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_CLEAR); | 391 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR); |
403 | jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_SET); | 392 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_SET); |
404 | break; | 393 | break; |
405 | case IRQ_TYPE_LEVEL_HIGH: | 394 | case IRQ_TYPE_LEVEL_HIGH: |
406 | jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_SET); | 395 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_SET); |
407 | jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_CLEAR); | 396 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_CLEAR); |
408 | break; | 397 | break; |
409 | case IRQ_TYPE_LEVEL_LOW: | 398 | case IRQ_TYPE_LEVEL_LOW: |
410 | jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_CLEAR); | 399 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR); |
411 | jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_CLEAR); | 400 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_CLEAR); |
412 | break; | 401 | break; |
413 | default: | 402 | default: |
414 | return -EINVAL; | 403 | return -EINVAL; |
415 | } | 404 | } |
416 | 405 | ||
417 | if (!(desc->status & IRQ_MASKED)) | ||
418 | jz_gpio_irq_unmask(irq); | ||
419 | |||
420 | return 0; | 406 | return 0; |
421 | } | 407 | } |
422 | 408 | ||
423 | static int jz_gpio_irq_set_wake(unsigned int irq, unsigned int on) | 409 | static int jz_gpio_irq_set_wake(struct irq_data *data, unsigned int on) |
424 | { | 410 | { |
425 | struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq); | 411 | struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data); |
426 | spin_lock(&chip->lock); | 412 | spin_lock(&chip->lock); |
427 | if (on) | 413 | if (on) |
428 | chip->wakeup |= IRQ_TO_BIT(irq); | 414 | chip->wakeup |= IRQ_TO_BIT(data->irq); |
429 | else | 415 | else |
430 | chip->wakeup &= ~IRQ_TO_BIT(irq); | 416 | chip->wakeup &= ~IRQ_TO_BIT(data->irq); |
431 | spin_unlock(&chip->lock); | 417 | spin_unlock(&chip->lock); |
432 | 418 | ||
433 | set_irq_wake(chip->irq, on); | 419 | set_irq_wake(chip->irq, on); |
434 | return 0; | 420 | return 0; |
435 | } | 421 | } |
436 | 422 | ||
423 | static struct irq_chip jz_gpio_irq_chip = { | ||
424 | .name = "GPIO", | ||
425 | .irq_mask = jz_gpio_irq_mask, | ||
426 | .irq_unmask = jz_gpio_irq_unmask, | ||
427 | .irq_ack = jz_gpio_irq_ack, | ||
428 | .irq_startup = jz_gpio_irq_startup, | ||
429 | .irq_shutdown = jz_gpio_irq_shutdown, | ||
430 | .irq_set_type = jz_gpio_irq_set_type, | ||
431 | .irq_set_wake = jz_gpio_irq_set_wake, | ||
432 | .flags = IRQCHIP_SET_TYPE_MASKED, | ||
433 | }; | ||
434 | |||
437 | /* | 435 | /* |
438 | * This lock class tells lockdep that GPIO irqs are in a different | 436 | * This lock class tells lockdep that GPIO irqs are in a different |
439 | * category than their parents, so it won't report false recursion. | 437 | * category than their parents, so it won't report false recursion. |
@@ -452,16 +450,6 @@ static struct lock_class_key gpio_lock_class; | |||
452 | .base = JZ4740_GPIO_BASE_ ## _bank, \ | 450 | .base = JZ4740_GPIO_BASE_ ## _bank, \ |
453 | .ngpio = JZ4740_GPIO_NUM_ ## _bank, \ | 451 | .ngpio = JZ4740_GPIO_NUM_ ## _bank, \ |
454 | }, \ | 452 | }, \ |
455 | .irq_chip = { \ | ||
456 | .name = "GPIO Bank " # _bank, \ | ||
457 | .mask = jz_gpio_irq_mask, \ | ||
458 | .unmask = jz_gpio_irq_unmask, \ | ||
459 | .ack = jz_gpio_irq_ack, \ | ||
460 | .startup = jz_gpio_irq_startup, \ | ||
461 | .shutdown = jz_gpio_irq_shutdown, \ | ||
462 | .set_type = jz_gpio_irq_set_type, \ | ||
463 | .set_wake = jz_gpio_irq_set_wake, \ | ||
464 | }, \ | ||
465 | } | 453 | } |
466 | 454 | ||
467 | static struct jz_gpio_chip jz4740_gpio_chips[] = { | 455 | static struct jz_gpio_chip jz4740_gpio_chips[] = { |
@@ -526,9 +514,10 @@ static int jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id) | |||
526 | set_irq_chained_handler(chip->irq, jz_gpio_irq_demux_handler); | 514 | set_irq_chained_handler(chip->irq, jz_gpio_irq_demux_handler); |
527 | 515 | ||
528 | for (irq = chip->irq_base; irq < chip->irq_base + chip->gpio_chip.ngpio; ++irq) { | 516 | for (irq = chip->irq_base; irq < chip->irq_base + chip->gpio_chip.ngpio; ++irq) { |
529 | lockdep_set_class(&irq_desc[irq].lock, &gpio_lock_class); | 517 | irq_set_lockdep_class(irq, &gpio_lock_class); |
530 | set_irq_chip_data(irq, chip); | 518 | set_irq_chip_data(irq, chip); |
531 | set_irq_chip_and_handler(irq, &chip->irq_chip, handle_level_irq); | 519 | set_irq_chip_and_handler(irq, &jz_gpio_irq_chip, |
520 | handle_level_irq); | ||
532 | } | 521 | } |
533 | 522 | ||
534 | return 0; | 523 | return 0; |
diff --git a/arch/mips/jz4740/irq.c b/arch/mips/jz4740/irq.c index 7d33ff83580f..dcc5593a9389 100644 --- a/arch/mips/jz4740/irq.c +++ b/arch/mips/jz4740/irq.c | |||
@@ -43,32 +43,37 @@ static uint32_t jz_intc_saved; | |||
43 | 43 | ||
44 | #define IRQ_BIT(x) BIT((x) - JZ4740_IRQ_BASE) | 44 | #define IRQ_BIT(x) BIT((x) - JZ4740_IRQ_BASE) |
45 | 45 | ||
46 | static void intc_irq_unmask(unsigned int irq) | 46 | static inline unsigned long intc_irq_bit(struct irq_data *data) |
47 | { | 47 | { |
48 | writel(IRQ_BIT(irq), jz_intc_base + JZ_REG_INTC_CLEAR_MASK); | 48 | return (unsigned long)irq_data_get_irq_chip_data(data); |
49 | } | 49 | } |
50 | 50 | ||
51 | static void intc_irq_mask(unsigned int irq) | 51 | static void intc_irq_unmask(struct irq_data *data) |
52 | { | 52 | { |
53 | writel(IRQ_BIT(irq), jz_intc_base + JZ_REG_INTC_SET_MASK); | 53 | writel(intc_irq_bit(data), jz_intc_base + JZ_REG_INTC_CLEAR_MASK); |
54 | } | 54 | } |
55 | 55 | ||
56 | static int intc_irq_set_wake(unsigned int irq, unsigned int on) | 56 | static void intc_irq_mask(struct irq_data *data) |
57 | { | ||
58 | writel(intc_irq_bit(data), jz_intc_base + JZ_REG_INTC_SET_MASK); | ||
59 | } | ||
60 | |||
61 | static int intc_irq_set_wake(struct irq_data *data, unsigned int on) | ||
57 | { | 62 | { |
58 | if (on) | 63 | if (on) |
59 | jz_intc_wakeup |= IRQ_BIT(irq); | 64 | jz_intc_wakeup |= intc_irq_bit(data); |
60 | else | 65 | else |
61 | jz_intc_wakeup &= ~IRQ_BIT(irq); | 66 | jz_intc_wakeup &= ~intc_irq_bit(data); |
62 | 67 | ||
63 | return 0; | 68 | return 0; |
64 | } | 69 | } |
65 | 70 | ||
66 | static struct irq_chip intc_irq_type = { | 71 | static struct irq_chip intc_irq_type = { |
67 | .name = "INTC", | 72 | .name = "INTC", |
68 | .mask = intc_irq_mask, | 73 | .irq_mask = intc_irq_mask, |
69 | .mask_ack = intc_irq_mask, | 74 | .irq_mask_ack = intc_irq_mask, |
70 | .unmask = intc_irq_unmask, | 75 | .irq_unmask = intc_irq_unmask, |
71 | .set_wake = intc_irq_set_wake, | 76 | .irq_set_wake = intc_irq_set_wake, |
72 | }; | 77 | }; |
73 | 78 | ||
74 | static irqreturn_t jz4740_cascade(int irq, void *data) | 79 | static irqreturn_t jz4740_cascade(int irq, void *data) |
@@ -95,8 +100,11 @@ void __init arch_init_irq(void) | |||
95 | 100 | ||
96 | jz_intc_base = ioremap(JZ4740_INTC_BASE_ADDR, 0x14); | 101 | jz_intc_base = ioremap(JZ4740_INTC_BASE_ADDR, 0x14); |
97 | 102 | ||
103 | /* Mask all irqs */ | ||
104 | writel(0xffffffff, jz_intc_base + JZ_REG_INTC_SET_MASK); | ||
105 | |||
98 | for (i = JZ4740_IRQ_BASE; i < JZ4740_IRQ_BASE + 32; i++) { | 106 | for (i = JZ4740_IRQ_BASE; i < JZ4740_IRQ_BASE + 32; i++) { |
99 | intc_irq_mask(i); | 107 | set_irq_chip_data(i, (void *)IRQ_BIT(i)); |
100 | set_irq_chip_and_handler(i, &intc_irq_type, handle_level_irq); | 108 | set_irq_chip_and_handler(i, &intc_irq_type, handle_level_irq); |
101 | } | 109 | } |
102 | 110 | ||
diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index c58176cc796b..e221662bb80c 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c | |||
@@ -31,19 +31,19 @@ | |||
31 | 31 | ||
32 | static int i8259A_auto_eoi = -1; | 32 | static int i8259A_auto_eoi = -1; |
33 | DEFINE_RAW_SPINLOCK(i8259A_lock); | 33 | DEFINE_RAW_SPINLOCK(i8259A_lock); |
34 | static void disable_8259A_irq(unsigned int irq); | 34 | static void disable_8259A_irq(struct irq_data *d); |
35 | static void enable_8259A_irq(unsigned int irq); | 35 | static void enable_8259A_irq(struct irq_data *d); |
36 | static void mask_and_ack_8259A(unsigned int irq); | 36 | static void mask_and_ack_8259A(struct irq_data *d); |
37 | static void init_8259A(int auto_eoi); | 37 | static void init_8259A(int auto_eoi); |
38 | 38 | ||
39 | static struct irq_chip i8259A_chip = { | 39 | static struct irq_chip i8259A_chip = { |
40 | .name = "XT-PIC", | 40 | .name = "XT-PIC", |
41 | .mask = disable_8259A_irq, | 41 | .irq_mask = disable_8259A_irq, |
42 | .disable = disable_8259A_irq, | 42 | .irq_disable = disable_8259A_irq, |
43 | .unmask = enable_8259A_irq, | 43 | .irq_unmask = enable_8259A_irq, |
44 | .mask_ack = mask_and_ack_8259A, | 44 | .irq_mask_ack = mask_and_ack_8259A, |
45 | #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF | 45 | #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF |
46 | .set_affinity = plat_set_irq_affinity, | 46 | .irq_set_affinity = plat_set_irq_affinity, |
47 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ | 47 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ |
48 | }; | 48 | }; |
49 | 49 | ||
@@ -59,12 +59,11 @@ static unsigned int cached_irq_mask = 0xffff; | |||
59 | #define cached_master_mask (cached_irq_mask) | 59 | #define cached_master_mask (cached_irq_mask) |
60 | #define cached_slave_mask (cached_irq_mask >> 8) | 60 | #define cached_slave_mask (cached_irq_mask >> 8) |
61 | 61 | ||
62 | static void disable_8259A_irq(unsigned int irq) | 62 | static void disable_8259A_irq(struct irq_data *d) |
63 | { | 63 | { |
64 | unsigned int mask; | 64 | unsigned int mask, irq = d->irq - I8259A_IRQ_BASE; |
65 | unsigned long flags; | 65 | unsigned long flags; |
66 | 66 | ||
67 | irq -= I8259A_IRQ_BASE; | ||
68 | mask = 1 << irq; | 67 | mask = 1 << irq; |
69 | raw_spin_lock_irqsave(&i8259A_lock, flags); | 68 | raw_spin_lock_irqsave(&i8259A_lock, flags); |
70 | cached_irq_mask |= mask; | 69 | cached_irq_mask |= mask; |
@@ -75,12 +74,11 @@ static void disable_8259A_irq(unsigned int irq) | |||
75 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); | 74 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); |
76 | } | 75 | } |
77 | 76 | ||
78 | static void enable_8259A_irq(unsigned int irq) | 77 | static void enable_8259A_irq(struct irq_data *d) |
79 | { | 78 | { |
80 | unsigned int mask; | 79 | unsigned int mask, irq = d->irq - I8259A_IRQ_BASE; |
81 | unsigned long flags; | 80 | unsigned long flags; |
82 | 81 | ||
83 | irq -= I8259A_IRQ_BASE; | ||
84 | mask = ~(1 << irq); | 82 | mask = ~(1 << irq); |
85 | raw_spin_lock_irqsave(&i8259A_lock, flags); | 83 | raw_spin_lock_irqsave(&i8259A_lock, flags); |
86 | cached_irq_mask &= mask; | 84 | cached_irq_mask &= mask; |
@@ -145,12 +143,11 @@ static inline int i8259A_irq_real(unsigned int irq) | |||
145 | * first, _then_ send the EOI, and the order of EOI | 143 | * first, _then_ send the EOI, and the order of EOI |
146 | * to the two 8259s is important! | 144 | * to the two 8259s is important! |
147 | */ | 145 | */ |
148 | static void mask_and_ack_8259A(unsigned int irq) | 146 | static void mask_and_ack_8259A(struct irq_data *d) |
149 | { | 147 | { |
150 | unsigned int irqmask; | 148 | unsigned int irqmask, irq = d->irq - I8259A_IRQ_BASE; |
151 | unsigned long flags; | 149 | unsigned long flags; |
152 | 150 | ||
153 | irq -= I8259A_IRQ_BASE; | ||
154 | irqmask = 1 << irq; | 151 | irqmask = 1 << irq; |
155 | raw_spin_lock_irqsave(&i8259A_lock, flags); | 152 | raw_spin_lock_irqsave(&i8259A_lock, flags); |
156 | /* | 153 | /* |
@@ -290,9 +287,9 @@ static void init_8259A(int auto_eoi) | |||
290 | * In AEOI mode we just have to mask the interrupt | 287 | * In AEOI mode we just have to mask the interrupt |
291 | * when acking. | 288 | * when acking. |
292 | */ | 289 | */ |
293 | i8259A_chip.mask_ack = disable_8259A_irq; | 290 | i8259A_chip.irq_mask_ack = disable_8259A_irq; |
294 | else | 291 | else |
295 | i8259A_chip.mask_ack = mask_and_ack_8259A; | 292 | i8259A_chip.irq_mask_ack = mask_and_ack_8259A; |
296 | 293 | ||
297 | udelay(100); /* wait for 8259A to initialize */ | 294 | udelay(100); /* wait for 8259A to initialize */ |
298 | 295 | ||
diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c index 1774271af848..43cd9628251a 100644 --- a/arch/mips/kernel/irq-gic.c +++ b/arch/mips/kernel/irq-gic.c | |||
@@ -87,17 +87,10 @@ unsigned int gic_get_int(void) | |||
87 | return i; | 87 | return i; |
88 | } | 88 | } |
89 | 89 | ||
90 | static unsigned int gic_irq_startup(unsigned int irq) | 90 | static void gic_irq_ack(struct irq_data *d) |
91 | { | 91 | { |
92 | irq -= _irqbase; | 92 | unsigned int irq = d->irq - _irqbase; |
93 | pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); | ||
94 | GIC_SET_INTR_MASK(irq); | ||
95 | return 0; | ||
96 | } | ||
97 | 93 | ||
98 | static void gic_irq_ack(unsigned int irq) | ||
99 | { | ||
100 | irq -= _irqbase; | ||
101 | pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); | 94 | pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); |
102 | GIC_CLR_INTR_MASK(irq); | 95 | GIC_CLR_INTR_MASK(irq); |
103 | 96 | ||
@@ -105,16 +98,16 @@ static void gic_irq_ack(unsigned int irq) | |||
105 | GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq); | 98 | GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq); |
106 | } | 99 | } |
107 | 100 | ||
108 | static void gic_mask_irq(unsigned int irq) | 101 | static void gic_mask_irq(struct irq_data *d) |
109 | { | 102 | { |
110 | irq -= _irqbase; | 103 | unsigned int irq = d->irq - _irqbase; |
111 | pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); | 104 | pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); |
112 | GIC_CLR_INTR_MASK(irq); | 105 | GIC_CLR_INTR_MASK(irq); |
113 | } | 106 | } |
114 | 107 | ||
115 | static void gic_unmask_irq(unsigned int irq) | 108 | static void gic_unmask_irq(struct irq_data *d) |
116 | { | 109 | { |
117 | irq -= _irqbase; | 110 | unsigned int irq = d->irq - _irqbase; |
118 | pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); | 111 | pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); |
119 | GIC_SET_INTR_MASK(irq); | 112 | GIC_SET_INTR_MASK(irq); |
120 | } | 113 | } |
@@ -123,13 +116,14 @@ static void gic_unmask_irq(unsigned int irq) | |||
123 | 116 | ||
124 | static DEFINE_SPINLOCK(gic_lock); | 117 | static DEFINE_SPINLOCK(gic_lock); |
125 | 118 | ||
126 | static int gic_set_affinity(unsigned int irq, const struct cpumask *cpumask) | 119 | static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, |
120 | bool force) | ||
127 | { | 121 | { |
122 | unsigned int irq = d->irq - _irqbase; | ||
128 | cpumask_t tmp = CPU_MASK_NONE; | 123 | cpumask_t tmp = CPU_MASK_NONE; |
129 | unsigned long flags; | 124 | unsigned long flags; |
130 | int i; | 125 | int i; |
131 | 126 | ||
132 | irq -= _irqbase; | ||
133 | pr_debug("%s(%d) called\n", __func__, irq); | 127 | pr_debug("%s(%d) called\n", __func__, irq); |
134 | cpumask_and(&tmp, cpumask, cpu_online_mask); | 128 | cpumask_and(&tmp, cpumask, cpu_online_mask); |
135 | if (cpus_empty(tmp)) | 129 | if (cpus_empty(tmp)) |
@@ -147,23 +141,22 @@ static int gic_set_affinity(unsigned int irq, const struct cpumask *cpumask) | |||
147 | set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask); | 141 | set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask); |
148 | 142 | ||
149 | } | 143 | } |
150 | cpumask_copy(irq_desc[irq].affinity, cpumask); | 144 | cpumask_copy(d->affinity, cpumask); |
151 | spin_unlock_irqrestore(&gic_lock, flags); | 145 | spin_unlock_irqrestore(&gic_lock, flags); |
152 | 146 | ||
153 | return 0; | 147 | return IRQ_SET_MASK_OK_NOCOPY; |
154 | } | 148 | } |
155 | #endif | 149 | #endif |
156 | 150 | ||
157 | static struct irq_chip gic_irq_controller = { | 151 | static struct irq_chip gic_irq_controller = { |
158 | .name = "MIPS GIC", | 152 | .name = "MIPS GIC", |
159 | .startup = gic_irq_startup, | 153 | .irq_ack = gic_irq_ack, |
160 | .ack = gic_irq_ack, | 154 | .irq_mask = gic_mask_irq, |
161 | .mask = gic_mask_irq, | 155 | .irq_mask_ack = gic_mask_irq, |
162 | .mask_ack = gic_mask_irq, | 156 | .irq_unmask = gic_unmask_irq, |
163 | .unmask = gic_unmask_irq, | 157 | .irq_eoi = gic_unmask_irq, |
164 | .eoi = gic_unmask_irq, | ||
165 | #ifdef CONFIG_SMP | 158 | #ifdef CONFIG_SMP |
166 | .set_affinity = gic_set_affinity, | 159 | .irq_set_affinity = gic_set_affinity, |
167 | #endif | 160 | #endif |
168 | }; | 161 | }; |
169 | 162 | ||
diff --git a/arch/mips/kernel/irq-gt641xx.c b/arch/mips/kernel/irq-gt641xx.c index 42ef81461bfc..7fd176fa367a 100644 --- a/arch/mips/kernel/irq-gt641xx.c +++ b/arch/mips/kernel/irq-gt641xx.c | |||
@@ -29,64 +29,64 @@ | |||
29 | 29 | ||
30 | static DEFINE_RAW_SPINLOCK(gt641xx_irq_lock); | 30 | static DEFINE_RAW_SPINLOCK(gt641xx_irq_lock); |
31 | 31 | ||
32 | static void ack_gt641xx_irq(unsigned int irq) | 32 | static void ack_gt641xx_irq(struct irq_data *d) |
33 | { | 33 | { |
34 | unsigned long flags; | 34 | unsigned long flags; |
35 | u32 cause; | 35 | u32 cause; |
36 | 36 | ||
37 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); | 37 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); |
38 | cause = GT_READ(GT_INTRCAUSE_OFS); | 38 | cause = GT_READ(GT_INTRCAUSE_OFS); |
39 | cause &= ~GT641XX_IRQ_TO_BIT(irq); | 39 | cause &= ~GT641XX_IRQ_TO_BIT(d->irq); |
40 | GT_WRITE(GT_INTRCAUSE_OFS, cause); | 40 | GT_WRITE(GT_INTRCAUSE_OFS, cause); |
41 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); | 41 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); |
42 | } | 42 | } |
43 | 43 | ||
44 | static void mask_gt641xx_irq(unsigned int irq) | 44 | static void mask_gt641xx_irq(struct irq_data *d) |
45 | { | 45 | { |
46 | unsigned long flags; | 46 | unsigned long flags; |
47 | u32 mask; | 47 | u32 mask; |
48 | 48 | ||
49 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); | 49 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); |
50 | mask = GT_READ(GT_INTRMASK_OFS); | 50 | mask = GT_READ(GT_INTRMASK_OFS); |
51 | mask &= ~GT641XX_IRQ_TO_BIT(irq); | 51 | mask &= ~GT641XX_IRQ_TO_BIT(d->irq); |
52 | GT_WRITE(GT_INTRMASK_OFS, mask); | 52 | GT_WRITE(GT_INTRMASK_OFS, mask); |
53 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); | 53 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); |
54 | } | 54 | } |
55 | 55 | ||
56 | static void mask_ack_gt641xx_irq(unsigned int irq) | 56 | static void mask_ack_gt641xx_irq(struct irq_data *d) |
57 | { | 57 | { |
58 | unsigned long flags; | 58 | unsigned long flags; |
59 | u32 cause, mask; | 59 | u32 cause, mask; |
60 | 60 | ||
61 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); | 61 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); |
62 | mask = GT_READ(GT_INTRMASK_OFS); | 62 | mask = GT_READ(GT_INTRMASK_OFS); |
63 | mask &= ~GT641XX_IRQ_TO_BIT(irq); | 63 | mask &= ~GT641XX_IRQ_TO_BIT(d->irq); |
64 | GT_WRITE(GT_INTRMASK_OFS, mask); | 64 | GT_WRITE(GT_INTRMASK_OFS, mask); |
65 | 65 | ||
66 | cause = GT_READ(GT_INTRCAUSE_OFS); | 66 | cause = GT_READ(GT_INTRCAUSE_OFS); |
67 | cause &= ~GT641XX_IRQ_TO_BIT(irq); | 67 | cause &= ~GT641XX_IRQ_TO_BIT(d->irq); |
68 | GT_WRITE(GT_INTRCAUSE_OFS, cause); | 68 | GT_WRITE(GT_INTRCAUSE_OFS, cause); |
69 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); | 69 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); |
70 | } | 70 | } |
71 | 71 | ||
72 | static void unmask_gt641xx_irq(unsigned int irq) | 72 | static void unmask_gt641xx_irq(struct irq_data *d) |
73 | { | 73 | { |
74 | unsigned long flags; | 74 | unsigned long flags; |
75 | u32 mask; | 75 | u32 mask; |
76 | 76 | ||
77 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); | 77 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); |
78 | mask = GT_READ(GT_INTRMASK_OFS); | 78 | mask = GT_READ(GT_INTRMASK_OFS); |
79 | mask |= GT641XX_IRQ_TO_BIT(irq); | 79 | mask |= GT641XX_IRQ_TO_BIT(d->irq); |
80 | GT_WRITE(GT_INTRMASK_OFS, mask); | 80 | GT_WRITE(GT_INTRMASK_OFS, mask); |
81 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); | 81 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); |
82 | } | 82 | } |
83 | 83 | ||
84 | static struct irq_chip gt641xx_irq_chip = { | 84 | static struct irq_chip gt641xx_irq_chip = { |
85 | .name = "GT641xx", | 85 | .name = "GT641xx", |
86 | .ack = ack_gt641xx_irq, | 86 | .irq_ack = ack_gt641xx_irq, |
87 | .mask = mask_gt641xx_irq, | 87 | .irq_mask = mask_gt641xx_irq, |
88 | .mask_ack = mask_ack_gt641xx_irq, | 88 | .irq_mask_ack = mask_ack_gt641xx_irq, |
89 | .unmask = unmask_gt641xx_irq, | 89 | .irq_unmask = unmask_gt641xx_irq, |
90 | }; | 90 | }; |
91 | 91 | ||
92 | void gt641xx_irq_dispatch(void) | 92 | void gt641xx_irq_dispatch(void) |
diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c index 6a8cd28133d5..fc800cd9947e 100644 --- a/arch/mips/kernel/irq-msc01.c +++ b/arch/mips/kernel/irq-msc01.c | |||
@@ -28,8 +28,10 @@ static unsigned long _icctrl_msc; | |||
28 | static unsigned int irq_base; | 28 | static unsigned int irq_base; |
29 | 29 | ||
30 | /* mask off an interrupt */ | 30 | /* mask off an interrupt */ |
31 | static inline void mask_msc_irq(unsigned int irq) | 31 | static inline void mask_msc_irq(struct irq_data *d) |
32 | { | 32 | { |
33 | unsigned int irq = d->irq; | ||
34 | |||
33 | if (irq < (irq_base + 32)) | 35 | if (irq < (irq_base + 32)) |
34 | MSCIC_WRITE(MSC01_IC_DISL, 1<<(irq - irq_base)); | 36 | MSCIC_WRITE(MSC01_IC_DISL, 1<<(irq - irq_base)); |
35 | else | 37 | else |
@@ -37,8 +39,10 @@ static inline void mask_msc_irq(unsigned int irq) | |||
37 | } | 39 | } |
38 | 40 | ||
39 | /* unmask an interrupt */ | 41 | /* unmask an interrupt */ |
40 | static inline void unmask_msc_irq(unsigned int irq) | 42 | static inline void unmask_msc_irq(struct irq_data *d) |
41 | { | 43 | { |
44 | unsigned int irq = d->irq; | ||
45 | |||
42 | if (irq < (irq_base + 32)) | 46 | if (irq < (irq_base + 32)) |
43 | MSCIC_WRITE(MSC01_IC_ENAL, 1<<(irq - irq_base)); | 47 | MSCIC_WRITE(MSC01_IC_ENAL, 1<<(irq - irq_base)); |
44 | else | 48 | else |
@@ -48,9 +52,11 @@ static inline void unmask_msc_irq(unsigned int irq) | |||
48 | /* | 52 | /* |
49 | * Masks and ACKs an IRQ | 53 | * Masks and ACKs an IRQ |
50 | */ | 54 | */ |
51 | static void level_mask_and_ack_msc_irq(unsigned int irq) | 55 | static void level_mask_and_ack_msc_irq(struct irq_data *d) |
52 | { | 56 | { |
53 | mask_msc_irq(irq); | 57 | unsigned int irq = d->irq; |
58 | |||
59 | mask_msc_irq(d); | ||
54 | if (!cpu_has_veic) | 60 | if (!cpu_has_veic) |
55 | MSCIC_WRITE(MSC01_IC_EOI, 0); | 61 | MSCIC_WRITE(MSC01_IC_EOI, 0); |
56 | /* This actually needs to be a call into platform code */ | 62 | /* This actually needs to be a call into platform code */ |
@@ -60,9 +66,11 @@ static void level_mask_and_ack_msc_irq(unsigned int irq) | |||
60 | /* | 66 | /* |
61 | * Masks and ACKs an IRQ | 67 | * Masks and ACKs an IRQ |
62 | */ | 68 | */ |
63 | static void edge_mask_and_ack_msc_irq(unsigned int irq) | 69 | static void edge_mask_and_ack_msc_irq(struct irq_data *d) |
64 | { | 70 | { |
65 | mask_msc_irq(irq); | 71 | unsigned int irq = d->irq; |
72 | |||
73 | mask_msc_irq(d); | ||
66 | if (!cpu_has_veic) | 74 | if (!cpu_has_veic) |
67 | MSCIC_WRITE(MSC01_IC_EOI, 0); | 75 | MSCIC_WRITE(MSC01_IC_EOI, 0); |
68 | else { | 76 | else { |
@@ -75,15 +83,6 @@ static void edge_mask_and_ack_msc_irq(unsigned int irq) | |||
75 | } | 83 | } |
76 | 84 | ||
77 | /* | 85 | /* |
78 | * End IRQ processing | ||
79 | */ | ||
80 | static void end_msc_irq(unsigned int irq) | ||
81 | { | ||
82 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
83 | unmask_msc_irq(irq); | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * Interrupt handler for interrupts coming from SOC-it. | 86 | * Interrupt handler for interrupts coming from SOC-it. |
88 | */ | 87 | */ |
89 | void ll_msc_irq(void) | 88 | void ll_msc_irq(void) |
@@ -107,22 +106,20 @@ static void msc_bind_eic_interrupt(int irq, int set) | |||
107 | 106 | ||
108 | static struct irq_chip msc_levelirq_type = { | 107 | static struct irq_chip msc_levelirq_type = { |
109 | .name = "SOC-it-Level", | 108 | .name = "SOC-it-Level", |
110 | .ack = level_mask_and_ack_msc_irq, | 109 | .irq_ack = level_mask_and_ack_msc_irq, |
111 | .mask = mask_msc_irq, | 110 | .irq_mask = mask_msc_irq, |
112 | .mask_ack = level_mask_and_ack_msc_irq, | 111 | .irq_mask_ack = level_mask_and_ack_msc_irq, |
113 | .unmask = unmask_msc_irq, | 112 | .irq_unmask = unmask_msc_irq, |
114 | .eoi = unmask_msc_irq, | 113 | .irq_eoi = unmask_msc_irq, |
115 | .end = end_msc_irq, | ||
116 | }; | 114 | }; |
117 | 115 | ||
118 | static struct irq_chip msc_edgeirq_type = { | 116 | static struct irq_chip msc_edgeirq_type = { |
119 | .name = "SOC-it-Edge", | 117 | .name = "SOC-it-Edge", |
120 | .ack = edge_mask_and_ack_msc_irq, | 118 | .irq_ack = edge_mask_and_ack_msc_irq, |
121 | .mask = mask_msc_irq, | 119 | .irq_mask = mask_msc_irq, |
122 | .mask_ack = edge_mask_and_ack_msc_irq, | 120 | .irq_mask_ack = edge_mask_and_ack_msc_irq, |
123 | .unmask = unmask_msc_irq, | 121 | .irq_unmask = unmask_msc_irq, |
124 | .eoi = unmask_msc_irq, | 122 | .irq_eoi = unmask_msc_irq, |
125 | .end = end_msc_irq, | ||
126 | }; | 123 | }; |
127 | 124 | ||
128 | 125 | ||
diff --git a/arch/mips/kernel/irq-rm7000.c b/arch/mips/kernel/irq-rm7000.c index 9731e8b47862..fd24fd98b041 100644 --- a/arch/mips/kernel/irq-rm7000.c +++ b/arch/mips/kernel/irq-rm7000.c | |||
@@ -18,23 +18,23 @@ | |||
18 | #include <asm/mipsregs.h> | 18 | #include <asm/mipsregs.h> |
19 | #include <asm/system.h> | 19 | #include <asm/system.h> |
20 | 20 | ||
21 | static inline void unmask_rm7k_irq(unsigned int irq) | 21 | static inline void unmask_rm7k_irq(struct irq_data *d) |
22 | { | 22 | { |
23 | set_c0_intcontrol(0x100 << (irq - RM7K_CPU_IRQ_BASE)); | 23 | set_c0_intcontrol(0x100 << (d->irq - RM7K_CPU_IRQ_BASE)); |
24 | } | 24 | } |
25 | 25 | ||
26 | static inline void mask_rm7k_irq(unsigned int irq) | 26 | static inline void mask_rm7k_irq(struct irq_data *d) |
27 | { | 27 | { |
28 | clear_c0_intcontrol(0x100 << (irq - RM7K_CPU_IRQ_BASE)); | 28 | clear_c0_intcontrol(0x100 << (d->irq - RM7K_CPU_IRQ_BASE)); |
29 | } | 29 | } |
30 | 30 | ||
31 | static struct irq_chip rm7k_irq_controller = { | 31 | static struct irq_chip rm7k_irq_controller = { |
32 | .name = "RM7000", | 32 | .name = "RM7000", |
33 | .ack = mask_rm7k_irq, | 33 | .irq_ack = mask_rm7k_irq, |
34 | .mask = mask_rm7k_irq, | 34 | .irq_mask = mask_rm7k_irq, |
35 | .mask_ack = mask_rm7k_irq, | 35 | .irq_mask_ack = mask_rm7k_irq, |
36 | .unmask = unmask_rm7k_irq, | 36 | .irq_unmask = unmask_rm7k_irq, |
37 | .eoi = unmask_rm7k_irq | 37 | .irq_eoi = unmask_rm7k_irq |
38 | }; | 38 | }; |
39 | 39 | ||
40 | void __init rm7k_cpu_irq_init(void) | 40 | void __init rm7k_cpu_irq_init(void) |
diff --git a/arch/mips/kernel/irq-rm9000.c b/arch/mips/kernel/irq-rm9000.c index b7e4025b58a8..ca463ec9bad5 100644 --- a/arch/mips/kernel/irq-rm9000.c +++ b/arch/mips/kernel/irq-rm9000.c | |||
@@ -19,22 +19,22 @@ | |||
19 | #include <asm/mipsregs.h> | 19 | #include <asm/mipsregs.h> |
20 | #include <asm/system.h> | 20 | #include <asm/system.h> |
21 | 21 | ||
22 | static inline void unmask_rm9k_irq(unsigned int irq) | 22 | static inline void unmask_rm9k_irq(struct irq_data *d) |
23 | { | 23 | { |
24 | set_c0_intcontrol(0x1000 << (irq - RM9K_CPU_IRQ_BASE)); | 24 | set_c0_intcontrol(0x1000 << (d->irq - RM9K_CPU_IRQ_BASE)); |
25 | } | 25 | } |
26 | 26 | ||
27 | static inline void mask_rm9k_irq(unsigned int irq) | 27 | static inline void mask_rm9k_irq(struct irq_data *d) |
28 | { | 28 | { |
29 | clear_c0_intcontrol(0x1000 << (irq - RM9K_CPU_IRQ_BASE)); | 29 | clear_c0_intcontrol(0x1000 << (d->irq - RM9K_CPU_IRQ_BASE)); |
30 | } | 30 | } |
31 | 31 | ||
32 | static inline void rm9k_cpu_irq_enable(unsigned int irq) | 32 | static inline void rm9k_cpu_irq_enable(struct irq_data *d) |
33 | { | 33 | { |
34 | unsigned long flags; | 34 | unsigned long flags; |
35 | 35 | ||
36 | local_irq_save(flags); | 36 | local_irq_save(flags); |
37 | unmask_rm9k_irq(irq); | 37 | unmask_rm9k_irq(d); |
38 | local_irq_restore(flags); | 38 | local_irq_restore(flags); |
39 | } | 39 | } |
40 | 40 | ||
@@ -43,50 +43,47 @@ static inline void rm9k_cpu_irq_enable(unsigned int irq) | |||
43 | */ | 43 | */ |
44 | static void local_rm9k_perfcounter_irq_startup(void *args) | 44 | static void local_rm9k_perfcounter_irq_startup(void *args) |
45 | { | 45 | { |
46 | unsigned int irq = (unsigned int) args; | 46 | rm9k_cpu_irq_enable(args); |
47 | |||
48 | rm9k_cpu_irq_enable(irq); | ||
49 | } | 47 | } |
50 | 48 | ||
51 | static unsigned int rm9k_perfcounter_irq_startup(unsigned int irq) | 49 | static unsigned int rm9k_perfcounter_irq_startup(struct irq_data *d) |
52 | { | 50 | { |
53 | on_each_cpu(local_rm9k_perfcounter_irq_startup, (void *) irq, 1); | 51 | on_each_cpu(local_rm9k_perfcounter_irq_startup, d, 1); |
54 | 52 | ||
55 | return 0; | 53 | return 0; |
56 | } | 54 | } |
57 | 55 | ||
58 | static void local_rm9k_perfcounter_irq_shutdown(void *args) | 56 | static void local_rm9k_perfcounter_irq_shutdown(void *args) |
59 | { | 57 | { |
60 | unsigned int irq = (unsigned int) args; | ||
61 | unsigned long flags; | 58 | unsigned long flags; |
62 | 59 | ||
63 | local_irq_save(flags); | 60 | local_irq_save(flags); |
64 | mask_rm9k_irq(irq); | 61 | mask_rm9k_irq(args); |
65 | local_irq_restore(flags); | 62 | local_irq_restore(flags); |
66 | } | 63 | } |
67 | 64 | ||
68 | static void rm9k_perfcounter_irq_shutdown(unsigned int irq) | 65 | static void rm9k_perfcounter_irq_shutdown(struct irq_data *d) |
69 | { | 66 | { |
70 | on_each_cpu(local_rm9k_perfcounter_irq_shutdown, (void *) irq, 1); | 67 | on_each_cpu(local_rm9k_perfcounter_irq_shutdown, d, 1); |
71 | } | 68 | } |
72 | 69 | ||
73 | static struct irq_chip rm9k_irq_controller = { | 70 | static struct irq_chip rm9k_irq_controller = { |
74 | .name = "RM9000", | 71 | .name = "RM9000", |
75 | .ack = mask_rm9k_irq, | 72 | .irq_ack = mask_rm9k_irq, |
76 | .mask = mask_rm9k_irq, | 73 | .irq_mask = mask_rm9k_irq, |
77 | .mask_ack = mask_rm9k_irq, | 74 | .irq_mask_ack = mask_rm9k_irq, |
78 | .unmask = unmask_rm9k_irq, | 75 | .irq_unmask = unmask_rm9k_irq, |
79 | .eoi = unmask_rm9k_irq | 76 | .irq_eoi = unmask_rm9k_irq |
80 | }; | 77 | }; |
81 | 78 | ||
82 | static struct irq_chip rm9k_perfcounter_irq = { | 79 | static struct irq_chip rm9k_perfcounter_irq = { |
83 | .name = "RM9000", | 80 | .name = "RM9000", |
84 | .startup = rm9k_perfcounter_irq_startup, | 81 | .irq_startup = rm9k_perfcounter_irq_startup, |
85 | .shutdown = rm9k_perfcounter_irq_shutdown, | 82 | .irq_shutdown = rm9k_perfcounter_irq_shutdown, |
86 | .ack = mask_rm9k_irq, | 83 | .irq_ack = mask_rm9k_irq, |
87 | .mask = mask_rm9k_irq, | 84 | .irq_mask = mask_rm9k_irq, |
88 | .mask_ack = mask_rm9k_irq, | 85 | .irq_mask_ack = mask_rm9k_irq, |
89 | .unmask = unmask_rm9k_irq, | 86 | .irq_unmask = unmask_rm9k_irq, |
90 | }; | 87 | }; |
91 | 88 | ||
92 | unsigned int rm9000_perfcount_irq; | 89 | unsigned int rm9000_perfcount_irq; |
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index 4f93db58a79e..1b68ebe1b458 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c | |||
@@ -81,48 +81,9 @@ void ack_bad_irq(unsigned int irq) | |||
81 | 81 | ||
82 | atomic_t irq_err_count; | 82 | atomic_t irq_err_count; |
83 | 83 | ||
84 | /* | 84 | int arch_show_interrupts(struct seq_file *p, int prec) |
85 | * Generic, controller-independent functions: | ||
86 | */ | ||
87 | |||
88 | int show_interrupts(struct seq_file *p, void *v) | ||
89 | { | 85 | { |
90 | int i = *(loff_t *) v, j; | 86 | seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count)); |
91 | struct irqaction * action; | ||
92 | unsigned long flags; | ||
93 | |||
94 | if (i == 0) { | ||
95 | seq_printf(p, " "); | ||
96 | for_each_online_cpu(j) | ||
97 | seq_printf(p, "CPU%d ", j); | ||
98 | seq_putc(p, '\n'); | ||
99 | } | ||
100 | |||
101 | if (i < NR_IRQS) { | ||
102 | raw_spin_lock_irqsave(&irq_desc[i].lock, flags); | ||
103 | action = irq_desc[i].action; | ||
104 | if (!action) | ||
105 | goto skip; | ||
106 | seq_printf(p, "%3d: ", i); | ||
107 | #ifndef CONFIG_SMP | ||
108 | seq_printf(p, "%10u ", kstat_irqs(i)); | ||
109 | #else | ||
110 | for_each_online_cpu(j) | ||
111 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); | ||
112 | #endif | ||
113 | seq_printf(p, " %14s", irq_desc[i].chip->name); | ||
114 | seq_printf(p, " %s", action->name); | ||
115 | |||
116 | for (action=action->next; action; action = action->next) | ||
117 | seq_printf(p, ", %s", action->name); | ||
118 | |||
119 | seq_putc(p, '\n'); | ||
120 | skip: | ||
121 | raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags); | ||
122 | } else if (i == NR_IRQS) { | ||
123 | seq_putc(p, '\n'); | ||
124 | seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); | ||
125 | } | ||
126 | return 0; | 87 | return 0; |
127 | } | 88 | } |
128 | 89 | ||
@@ -183,8 +144,8 @@ void __irq_entry do_IRQ(unsigned int irq) | |||
183 | { | 144 | { |
184 | irq_enter(); | 145 | irq_enter(); |
185 | check_stack_overflow(); | 146 | check_stack_overflow(); |
186 | __DO_IRQ_SMTC_HOOK(irq); | 147 | if (!smtc_handle_on_other_cpu(irq)) |
187 | generic_handle_irq(irq); | 148 | generic_handle_irq(irq); |
188 | irq_exit(); | 149 | irq_exit(); |
189 | } | 150 | } |
190 | 151 | ||
@@ -197,7 +158,7 @@ void __irq_entry do_IRQ(unsigned int irq) | |||
197 | void __irq_entry do_IRQ_no_affinity(unsigned int irq) | 158 | void __irq_entry do_IRQ_no_affinity(unsigned int irq) |
198 | { | 159 | { |
199 | irq_enter(); | 160 | irq_enter(); |
200 | __NO_AFFINITY_IRQ_SMTC_HOOK(irq); | 161 | smtc_im_backstop(irq); |
201 | generic_handle_irq(irq); | 162 | generic_handle_irq(irq); |
202 | irq_exit(); | 163 | irq_exit(); |
203 | } | 164 | } |
diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c index 0262abe09121..fd945c56bc33 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c | |||
@@ -37,42 +37,38 @@ | |||
37 | #include <asm/mipsmtregs.h> | 37 | #include <asm/mipsmtregs.h> |
38 | #include <asm/system.h> | 38 | #include <asm/system.h> |
39 | 39 | ||
40 | static inline void unmask_mips_irq(unsigned int irq) | 40 | static inline void unmask_mips_irq(struct irq_data *d) |
41 | { | 41 | { |
42 | set_c0_status(0x100 << (irq - MIPS_CPU_IRQ_BASE)); | 42 | set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); |
43 | irq_enable_hazard(); | 43 | irq_enable_hazard(); |
44 | } | 44 | } |
45 | 45 | ||
46 | static inline void mask_mips_irq(unsigned int irq) | 46 | static inline void mask_mips_irq(struct irq_data *d) |
47 | { | 47 | { |
48 | clear_c0_status(0x100 << (irq - MIPS_CPU_IRQ_BASE)); | 48 | clear_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); |
49 | irq_disable_hazard(); | 49 | irq_disable_hazard(); |
50 | } | 50 | } |
51 | 51 | ||
52 | static struct irq_chip mips_cpu_irq_controller = { | 52 | static struct irq_chip mips_cpu_irq_controller = { |
53 | .name = "MIPS", | 53 | .name = "MIPS", |
54 | .ack = mask_mips_irq, | 54 | .irq_ack = mask_mips_irq, |
55 | .mask = mask_mips_irq, | 55 | .irq_mask = mask_mips_irq, |
56 | .mask_ack = mask_mips_irq, | 56 | .irq_mask_ack = mask_mips_irq, |
57 | .unmask = unmask_mips_irq, | 57 | .irq_unmask = unmask_mips_irq, |
58 | .eoi = unmask_mips_irq, | 58 | .irq_eoi = unmask_mips_irq, |
59 | }; | 59 | }; |
60 | 60 | ||
61 | /* | 61 | /* |
62 | * Basically the same as above but taking care of all the MT stuff | 62 | * Basically the same as above but taking care of all the MT stuff |
63 | */ | 63 | */ |
64 | 64 | ||
65 | #define unmask_mips_mt_irq unmask_mips_irq | 65 | static unsigned int mips_mt_cpu_irq_startup(struct irq_data *d) |
66 | #define mask_mips_mt_irq mask_mips_irq | ||
67 | |||
68 | static unsigned int mips_mt_cpu_irq_startup(unsigned int irq) | ||
69 | { | 66 | { |
70 | unsigned int vpflags = dvpe(); | 67 | unsigned int vpflags = dvpe(); |
71 | 68 | ||
72 | clear_c0_cause(0x100 << (irq - MIPS_CPU_IRQ_BASE)); | 69 | clear_c0_cause(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); |
73 | evpe(vpflags); | 70 | evpe(vpflags); |
74 | unmask_mips_mt_irq(irq); | 71 | unmask_mips_irq(d); |
75 | |||
76 | return 0; | 72 | return 0; |
77 | } | 73 | } |
78 | 74 | ||
@@ -80,22 +76,22 @@ static unsigned int mips_mt_cpu_irq_startup(unsigned int irq) | |||
80 | * While we ack the interrupt interrupts are disabled and thus we don't need | 76 | * While we ack the interrupt interrupts are disabled and thus we don't need |
81 | * to deal with concurrency issues. Same for mips_cpu_irq_end. | 77 | * to deal with concurrency issues. Same for mips_cpu_irq_end. |
82 | */ | 78 | */ |
83 | static void mips_mt_cpu_irq_ack(unsigned int irq) | 79 | static void mips_mt_cpu_irq_ack(struct irq_data *d) |
84 | { | 80 | { |
85 | unsigned int vpflags = dvpe(); | 81 | unsigned int vpflags = dvpe(); |
86 | clear_c0_cause(0x100 << (irq - MIPS_CPU_IRQ_BASE)); | 82 | clear_c0_cause(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); |
87 | evpe(vpflags); | 83 | evpe(vpflags); |
88 | mask_mips_mt_irq(irq); | 84 | mask_mips_irq(d); |
89 | } | 85 | } |
90 | 86 | ||
91 | static struct irq_chip mips_mt_cpu_irq_controller = { | 87 | static struct irq_chip mips_mt_cpu_irq_controller = { |
92 | .name = "MIPS", | 88 | .name = "MIPS", |
93 | .startup = mips_mt_cpu_irq_startup, | 89 | .irq_startup = mips_mt_cpu_irq_startup, |
94 | .ack = mips_mt_cpu_irq_ack, | 90 | .irq_ack = mips_mt_cpu_irq_ack, |
95 | .mask = mask_mips_mt_irq, | 91 | .irq_mask = mask_mips_irq, |
96 | .mask_ack = mips_mt_cpu_irq_ack, | 92 | .irq_mask_ack = mips_mt_cpu_irq_ack, |
97 | .unmask = unmask_mips_mt_irq, | 93 | .irq_unmask = unmask_mips_irq, |
98 | .eoi = unmask_mips_mt_irq, | 94 | .irq_eoi = unmask_mips_irq, |
99 | }; | 95 | }; |
100 | 96 | ||
101 | void __init mips_cpu_irq_init(void) | 97 | void __init mips_cpu_irq_init(void) |
diff --git a/arch/mips/kernel/irq_txx9.c b/arch/mips/kernel/irq_txx9.c index 95a96f69172d..526e1581549a 100644 --- a/arch/mips/kernel/irq_txx9.c +++ b/arch/mips/kernel/irq_txx9.c | |||
@@ -63,9 +63,9 @@ static struct { | |||
63 | unsigned char mode; | 63 | unsigned char mode; |
64 | } txx9irq[TXx9_MAX_IR] __read_mostly; | 64 | } txx9irq[TXx9_MAX_IR] __read_mostly; |
65 | 65 | ||
66 | static void txx9_irq_unmask(unsigned int irq) | 66 | static void txx9_irq_unmask(struct irq_data *d) |
67 | { | 67 | { |
68 | unsigned int irq_nr = irq - TXX9_IRQ_BASE; | 68 | unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; |
69 | u32 __iomem *ilrp = &txx9_ircptr->ilr[(irq_nr % 16 ) / 2]; | 69 | u32 __iomem *ilrp = &txx9_ircptr->ilr[(irq_nr % 16 ) / 2]; |
70 | int ofs = irq_nr / 16 * 16 + (irq_nr & 1) * 8; | 70 | int ofs = irq_nr / 16 * 16 + (irq_nr & 1) * 8; |
71 | 71 | ||
@@ -79,9 +79,9 @@ static void txx9_irq_unmask(unsigned int irq) | |||
79 | #endif | 79 | #endif |
80 | } | 80 | } |
81 | 81 | ||
82 | static inline void txx9_irq_mask(unsigned int irq) | 82 | static inline void txx9_irq_mask(struct irq_data *d) |
83 | { | 83 | { |
84 | unsigned int irq_nr = irq - TXX9_IRQ_BASE; | 84 | unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; |
85 | u32 __iomem *ilrp = &txx9_ircptr->ilr[(irq_nr % 16) / 2]; | 85 | u32 __iomem *ilrp = &txx9_ircptr->ilr[(irq_nr % 16) / 2]; |
86 | int ofs = irq_nr / 16 * 16 + (irq_nr & 1) * 8; | 86 | int ofs = irq_nr / 16 * 16 + (irq_nr & 1) * 8; |
87 | 87 | ||
@@ -99,19 +99,19 @@ static inline void txx9_irq_mask(unsigned int irq) | |||
99 | #endif | 99 | #endif |
100 | } | 100 | } |
101 | 101 | ||
102 | static void txx9_irq_mask_ack(unsigned int irq) | 102 | static void txx9_irq_mask_ack(struct irq_data *d) |
103 | { | 103 | { |
104 | unsigned int irq_nr = irq - TXX9_IRQ_BASE; | 104 | unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; |
105 | 105 | ||
106 | txx9_irq_mask(irq); | 106 | txx9_irq_mask(d); |
107 | /* clear edge detection */ | 107 | /* clear edge detection */ |
108 | if (unlikely(TXx9_IRCR_EDGE(txx9irq[irq_nr].mode))) | 108 | if (unlikely(TXx9_IRCR_EDGE(txx9irq[irq_nr].mode))) |
109 | __raw_writel(TXx9_IRSCR_EIClrE | irq_nr, &txx9_ircptr->scr); | 109 | __raw_writel(TXx9_IRSCR_EIClrE | irq_nr, &txx9_ircptr->scr); |
110 | } | 110 | } |
111 | 111 | ||
112 | static int txx9_irq_set_type(unsigned int irq, unsigned int flow_type) | 112 | static int txx9_irq_set_type(struct irq_data *d, unsigned int flow_type) |
113 | { | 113 | { |
114 | unsigned int irq_nr = irq - TXX9_IRQ_BASE; | 114 | unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; |
115 | u32 cr; | 115 | u32 cr; |
116 | u32 __iomem *crp; | 116 | u32 __iomem *crp; |
117 | int ofs; | 117 | int ofs; |
@@ -139,11 +139,11 @@ static int txx9_irq_set_type(unsigned int irq, unsigned int flow_type) | |||
139 | 139 | ||
140 | static struct irq_chip txx9_irq_chip = { | 140 | static struct irq_chip txx9_irq_chip = { |
141 | .name = "TXX9", | 141 | .name = "TXX9", |
142 | .ack = txx9_irq_mask_ack, | 142 | .irq_ack = txx9_irq_mask_ack, |
143 | .mask = txx9_irq_mask, | 143 | .irq_mask = txx9_irq_mask, |
144 | .mask_ack = txx9_irq_mask_ack, | 144 | .irq_mask_ack = txx9_irq_mask_ack, |
145 | .unmask = txx9_irq_unmask, | 145 | .irq_unmask = txx9_irq_unmask, |
146 | .set_type = txx9_irq_set_type, | 146 | .irq_set_type = txx9_irq_set_type, |
147 | }; | 147 | }; |
148 | 148 | ||
149 | void __init txx9_irq_init(unsigned long baseaddr) | 149 | void __init txx9_irq_init(unsigned long baseaddr) |
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index fbaabad0e6e2..7f5468b38d4c 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S | |||
@@ -586,6 +586,10 @@ einval: li v0, -ENOSYS | |||
586 | sys sys_fanotify_init 2 | 586 | sys sys_fanotify_init 2 |
587 | sys sys_fanotify_mark 6 | 587 | sys sys_fanotify_mark 6 |
588 | sys sys_prlimit64 4 | 588 | sys sys_prlimit64 4 |
589 | sys sys_name_to_handle_at 5 | ||
590 | sys sys_open_by_handle_at 3 /* 4340 */ | ||
591 | sys sys_clock_adjtime 2 | ||
592 | sys sys_syncfs 1 | ||
589 | .endm | 593 | .endm |
590 | 594 | ||
591 | /* We pre-compute the number of _instruction_ bytes needed to | 595 | /* We pre-compute the number of _instruction_ bytes needed to |
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 3f4179283207..a2e1fcbc41dc 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S | |||
@@ -425,4 +425,8 @@ sys_call_table: | |||
425 | PTR sys_fanotify_init /* 5295 */ | 425 | PTR sys_fanotify_init /* 5295 */ |
426 | PTR sys_fanotify_mark | 426 | PTR sys_fanotify_mark |
427 | PTR sys_prlimit64 | 427 | PTR sys_prlimit64 |
428 | PTR sys_name_to_handle_at | ||
429 | PTR sys_open_by_handle_at | ||
430 | PTR sys_clock_adjtime /* 5300 */ | ||
431 | PTR sys_syncfs | ||
428 | .size sys_call_table,.-sys_call_table | 432 | .size sys_call_table,.-sys_call_table |
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index f08ece6d8acc..b2c7624995b8 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S | |||
@@ -425,4 +425,8 @@ EXPORT(sysn32_call_table) | |||
425 | PTR sys_fanotify_init /* 6300 */ | 425 | PTR sys_fanotify_init /* 6300 */ |
426 | PTR sys_fanotify_mark | 426 | PTR sys_fanotify_mark |
427 | PTR sys_prlimit64 | 427 | PTR sys_prlimit64 |
428 | PTR sys_name_to_handle_at | ||
429 | PTR sys_open_by_handle_at | ||
430 | PTR compat_sys_clock_adjtime /* 6305 */ | ||
431 | PTR sys_syncfs | ||
428 | .size sysn32_call_table,.-sysn32_call_table | 432 | .size sysn32_call_table,.-sysn32_call_table |
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 78d768a3e19d..049a9c8c49a0 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S | |||
@@ -543,4 +543,8 @@ sys_call_table: | |||
543 | PTR sys_fanotify_init | 543 | PTR sys_fanotify_init |
544 | PTR sys_32_fanotify_mark | 544 | PTR sys_32_fanotify_mark |
545 | PTR sys_prlimit64 | 545 | PTR sys_prlimit64 |
546 | PTR sys_name_to_handle_at | ||
547 | PTR compat_sys_open_by_handle_at /* 4340 */ | ||
548 | PTR compat_sys_clock_adjtime | ||
549 | PTR sys_syncfs | ||
546 | .size sys_call_table,.-sys_call_table | 550 | .size sys_call_table,.-sys_call_table |
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index 39c08254b0f1..f7e2c7807d7b 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c | |||
@@ -677,8 +677,9 @@ void smtc_set_irq_affinity(unsigned int irq, cpumask_t affinity) | |||
677 | */ | 677 | */ |
678 | } | 678 | } |
679 | 679 | ||
680 | void smtc_forward_irq(unsigned int irq) | 680 | void smtc_forward_irq(struct irq_data *d) |
681 | { | 681 | { |
682 | unsigned int irq = d->irq; | ||
682 | int target; | 683 | int target; |
683 | 684 | ||
684 | /* | 685 | /* |
@@ -692,7 +693,7 @@ void smtc_forward_irq(unsigned int irq) | |||
692 | * and efficiency, we just pick the easiest one to find. | 693 | * and efficiency, we just pick the easiest one to find. |
693 | */ | 694 | */ |
694 | 695 | ||
695 | target = cpumask_first(irq_desc[irq].affinity); | 696 | target = cpumask_first(d->affinity); |
696 | 697 | ||
697 | /* | 698 | /* |
698 | * We depend on the platform code to have correctly processed | 699 | * We depend on the platform code to have correctly processed |
@@ -707,12 +708,10 @@ void smtc_forward_irq(unsigned int irq) | |||
707 | */ | 708 | */ |
708 | 709 | ||
709 | /* If no one is eligible, service locally */ | 710 | /* If no one is eligible, service locally */ |
710 | if (target >= NR_CPUS) { | 711 | if (target >= NR_CPUS) |
711 | do_IRQ_no_affinity(irq); | 712 | do_IRQ_no_affinity(irq); |
712 | return; | 713 | else |
713 | } | 714 | smtc_send_ipi(target, IRQ_AFFINITY_IPI, irq); |
714 | |||
715 | smtc_send_ipi(target, IRQ_AFFINITY_IPI, irq); | ||
716 | } | 715 | } |
717 | 716 | ||
718 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ | 717 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ |
diff --git a/arch/mips/lasat/interrupt.c b/arch/mips/lasat/interrupt.c index 1353fb135ed3..670e3e70d198 100644 --- a/arch/mips/lasat/interrupt.c +++ b/arch/mips/lasat/interrupt.c | |||
@@ -32,24 +32,24 @@ static volatile int *lasat_int_status; | |||
32 | static volatile int *lasat_int_mask; | 32 | static volatile int *lasat_int_mask; |
33 | static volatile int lasat_int_mask_shift; | 33 | static volatile int lasat_int_mask_shift; |
34 | 34 | ||
35 | void disable_lasat_irq(unsigned int irq_nr) | 35 | void disable_lasat_irq(struct irq_data *d) |
36 | { | 36 | { |
37 | irq_nr -= LASAT_IRQ_BASE; | 37 | unsigned int irq_nr = d->irq - LASAT_IRQ_BASE; |
38 | |||
38 | *lasat_int_mask &= ~(1 << irq_nr) << lasat_int_mask_shift; | 39 | *lasat_int_mask &= ~(1 << irq_nr) << lasat_int_mask_shift; |
39 | } | 40 | } |
40 | 41 | ||
41 | void enable_lasat_irq(unsigned int irq_nr) | 42 | void enable_lasat_irq(struct irq_data *d) |
42 | { | 43 | { |
43 | irq_nr -= LASAT_IRQ_BASE; | 44 | unsigned int irq_nr = d->irq - LASAT_IRQ_BASE; |
45 | |||
44 | *lasat_int_mask |= (1 << irq_nr) << lasat_int_mask_shift; | 46 | *lasat_int_mask |= (1 << irq_nr) << lasat_int_mask_shift; |
45 | } | 47 | } |
46 | 48 | ||
47 | static struct irq_chip lasat_irq_type = { | 49 | static struct irq_chip lasat_irq_type = { |
48 | .name = "Lasat", | 50 | .name = "Lasat", |
49 | .ack = disable_lasat_irq, | 51 | .irq_mask = disable_lasat_irq, |
50 | .mask = disable_lasat_irq, | 52 | .irq_unmask = enable_lasat_irq, |
51 | .mask_ack = disable_lasat_irq, | ||
52 | .unmask = enable_lasat_irq, | ||
53 | }; | 53 | }; |
54 | 54 | ||
55 | static inline int ls1bit32(unsigned int x) | 55 | static inline int ls1bit32(unsigned int x) |
diff --git a/arch/mips/loongson/common/bonito-irq.c b/arch/mips/loongson/common/bonito-irq.c index 2dc2a4cc632a..1549361696ad 100644 --- a/arch/mips/loongson/common/bonito-irq.c +++ b/arch/mips/loongson/common/bonito-irq.c | |||
@@ -16,24 +16,22 @@ | |||
16 | 16 | ||
17 | #include <loongson.h> | 17 | #include <loongson.h> |
18 | 18 | ||
19 | static inline void bonito_irq_enable(unsigned int irq) | 19 | static inline void bonito_irq_enable(struct irq_data *d) |
20 | { | 20 | { |
21 | LOONGSON_INTENSET = (1 << (irq - LOONGSON_IRQ_BASE)); | 21 | LOONGSON_INTENSET = (1 << (d->irq - LOONGSON_IRQ_BASE)); |
22 | mmiowb(); | 22 | mmiowb(); |
23 | } | 23 | } |
24 | 24 | ||
25 | static inline void bonito_irq_disable(unsigned int irq) | 25 | static inline void bonito_irq_disable(struct irq_data *d) |
26 | { | 26 | { |
27 | LOONGSON_INTENCLR = (1 << (irq - LOONGSON_IRQ_BASE)); | 27 | LOONGSON_INTENCLR = (1 << (d->irq - LOONGSON_IRQ_BASE)); |
28 | mmiowb(); | 28 | mmiowb(); |
29 | } | 29 | } |
30 | 30 | ||
31 | static struct irq_chip bonito_irq_type = { | 31 | static struct irq_chip bonito_irq_type = { |
32 | .name = "bonito_irq", | 32 | .name = "bonito_irq", |
33 | .ack = bonito_irq_disable, | 33 | .irq_mask = bonito_irq_disable, |
34 | .mask = bonito_irq_disable, | 34 | .irq_unmask = bonito_irq_enable, |
35 | .mask_ack = bonito_irq_disable, | ||
36 | .unmask = bonito_irq_enable, | ||
37 | }; | 35 | }; |
38 | 36 | ||
39 | static struct irqaction __maybe_unused dma_timeout_irqaction = { | 37 | static struct irqaction __maybe_unused dma_timeout_irqaction = { |
diff --git a/arch/mips/mipssim/sim_smtc.c b/arch/mips/mipssim/sim_smtc.c index 5da30b6a65b7..30df47258c2c 100644 --- a/arch/mips/mipssim/sim_smtc.c +++ b/arch/mips/mipssim/sim_smtc.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <asm/atomic.h> | 27 | #include <asm/atomic.h> |
28 | #include <asm/cpu.h> | 28 | #include <asm/cpu.h> |
29 | #include <asm/processor.h> | 29 | #include <asm/processor.h> |
30 | #include <asm/smtc.h> | ||
30 | #include <asm/system.h> | 31 | #include <asm/system.h> |
31 | #include <asm/mmu_context.h> | 32 | #include <asm/mmu_context.h> |
32 | #include <asm/smtc_ipi.h> | 33 | #include <asm/smtc_ipi.h> |
@@ -57,8 +58,6 @@ static inline void ssmtc_send_ipi_mask(const struct cpumask *mask, | |||
57 | */ | 58 | */ |
58 | static void __cpuinit ssmtc_init_secondary(void) | 59 | static void __cpuinit ssmtc_init_secondary(void) |
59 | { | 60 | { |
60 | void smtc_init_secondary(void); | ||
61 | |||
62 | smtc_init_secondary(); | 61 | smtc_init_secondary(); |
63 | } | 62 | } |
64 | 63 | ||
diff --git a/arch/mips/mti-malta/malta-smtc.c b/arch/mips/mti-malta/malta-smtc.c index 192cfd2a539c..e67891521ac1 100644 --- a/arch/mips/mti-malta/malta-smtc.c +++ b/arch/mips/mti-malta/malta-smtc.c | |||
@@ -34,7 +34,6 @@ static void msmtc_send_ipi_mask(const struct cpumask *mask, unsigned int action) | |||
34 | */ | 34 | */ |
35 | static void __cpuinit msmtc_init_secondary(void) | 35 | static void __cpuinit msmtc_init_secondary(void) |
36 | { | 36 | { |
37 | void smtc_init_secondary(void); | ||
38 | int myvpe; | 37 | int myvpe; |
39 | 38 | ||
40 | /* Don't enable Malta I/O interrupts (IP2) for secondary VPEs */ | 39 | /* Don't enable Malta I/O interrupts (IP2) for secondary VPEs */ |
@@ -114,7 +113,8 @@ struct plat_smp_ops msmtc_smp_ops = { | |||
114 | */ | 113 | */ |
115 | 114 | ||
116 | 115 | ||
117 | int plat_set_irq_affinity(unsigned int irq, const struct cpumask *affinity) | 116 | int plat_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity, |
117 | bool force) | ||
118 | { | 118 | { |
119 | cpumask_t tmask; | 119 | cpumask_t tmask; |
120 | int cpu = 0; | 120 | int cpu = 0; |
@@ -144,7 +144,7 @@ int plat_set_irq_affinity(unsigned int irq, const struct cpumask *affinity) | |||
144 | if ((cpu_data[cpu].vpe_id != 0) || !cpu_online(cpu)) | 144 | if ((cpu_data[cpu].vpe_id != 0) || !cpu_online(cpu)) |
145 | cpu_clear(cpu, tmask); | 145 | cpu_clear(cpu, tmask); |
146 | } | 146 | } |
147 | cpumask_copy(irq_desc[irq].affinity, &tmask); | 147 | cpumask_copy(d->affinity, &tmask); |
148 | 148 | ||
149 | if (cpus_empty(tmask)) | 149 | if (cpus_empty(tmask)) |
150 | /* | 150 | /* |
@@ -155,8 +155,8 @@ int plat_set_irq_affinity(unsigned int irq, const struct cpumask *affinity) | |||
155 | "IRQ affinity leaves no legal CPU for IRQ %d\n", irq); | 155 | "IRQ affinity leaves no legal CPU for IRQ %d\n", irq); |
156 | 156 | ||
157 | /* Do any generic SMTC IRQ affinity setup */ | 157 | /* Do any generic SMTC IRQ affinity setup */ |
158 | smtc_set_irq_affinity(irq, tmask); | 158 | smtc_set_irq_affinity(d->irq, tmask); |
159 | 159 | ||
160 | return 0; | 160 | return IRQ_SET_MASK_OK_NOCOPY; |
161 | } | 161 | } |
162 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ | 162 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ |
diff --git a/arch/mips/pmc-sierra/Kconfig b/arch/mips/pmc-sierra/Kconfig index 8d798497c614..bbd76082fa8c 100644 --- a/arch/mips/pmc-sierra/Kconfig +++ b/arch/mips/pmc-sierra/Kconfig | |||
@@ -23,6 +23,8 @@ config PMC_MSP7120_GW | |||
23 | select SYS_SUPPORTS_MULTITHREADING | 23 | select SYS_SUPPORTS_MULTITHREADING |
24 | select IRQ_MSP_CIC | 24 | select IRQ_MSP_CIC |
25 | select HW_HAS_PCI | 25 | select HW_HAS_PCI |
26 | select MSP_HAS_USB | ||
27 | select MSP_ETH | ||
26 | 28 | ||
27 | config PMC_MSP7120_FPGA | 29 | config PMC_MSP7120_FPGA |
28 | bool "PMC-Sierra MSP7120 FPGA" | 30 | bool "PMC-Sierra MSP7120 FPGA" |
@@ -35,3 +37,16 @@ endchoice | |||
35 | config HYPERTRANSPORT | 37 | config HYPERTRANSPORT |
36 | bool "Hypertransport Support for PMC-Sierra Yosemite" | 38 | bool "Hypertransport Support for PMC-Sierra Yosemite" |
37 | depends on PMC_YOSEMITE | 39 | depends on PMC_YOSEMITE |
40 | |||
41 | config MSP_HAS_USB | ||
42 | boolean | ||
43 | depends on PMC_MSP | ||
44 | |||
45 | config MSP_ETH | ||
46 | boolean | ||
47 | select MSP_HAS_MAC | ||
48 | depends on PMC_MSP | ||
49 | |||
50 | config MSP_HAS_MAC | ||
51 | boolean | ||
52 | depends on PMC_MSP | ||
diff --git a/arch/mips/pmc-sierra/msp71xx/Makefile b/arch/mips/pmc-sierra/msp71xx/Makefile index e107f79b1491..cefba7733b73 100644 --- a/arch/mips/pmc-sierra/msp71xx/Makefile +++ b/arch/mips/pmc-sierra/msp71xx/Makefile | |||
@@ -6,7 +6,9 @@ obj-y += msp_prom.o msp_setup.o msp_irq.o \ | |||
6 | obj-$(CONFIG_HAVE_GPIO_LIB) += gpio.o gpio_extended.o | 6 | obj-$(CONFIG_HAVE_GPIO_LIB) += gpio.o gpio_extended.o |
7 | obj-$(CONFIG_PMC_MSP7120_GW) += msp_hwbutton.o | 7 | obj-$(CONFIG_PMC_MSP7120_GW) += msp_hwbutton.o |
8 | obj-$(CONFIG_IRQ_MSP_SLP) += msp_irq_slp.o | 8 | obj-$(CONFIG_IRQ_MSP_SLP) += msp_irq_slp.o |
9 | obj-$(CONFIG_IRQ_MSP_CIC) += msp_irq_cic.o | 9 | obj-$(CONFIG_IRQ_MSP_CIC) += msp_irq_cic.o msp_irq_per.o |
10 | obj-$(CONFIG_PCI) += msp_pci.o | 10 | obj-$(CONFIG_PCI) += msp_pci.o |
11 | obj-$(CONFIG_MSPETH) += msp_eth.o | 11 | obj-$(CONFIG_MSP_HAS_MAC) += msp_eth.o |
12 | obj-$(CONFIG_USB_MSP71XX) += msp_usb.o | 12 | obj-$(CONFIG_MSP_HAS_USB) += msp_usb.o |
13 | obj-$(CONFIG_MIPS_MT_SMP) += msp_smp.o | ||
14 | obj-$(CONFIG_MIPS_MT_SMTC) += msp_smtc.o | ||
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_eth.c b/arch/mips/pmc-sierra/msp71xx/msp_eth.c new file mode 100644 index 000000000000..c584df393de2 --- /dev/null +++ b/arch/mips/pmc-sierra/msp71xx/msp_eth.c | |||
@@ -0,0 +1,187 @@ | |||
1 | /* | ||
2 | * The setup file for ethernet related hardware on PMC-Sierra MSP processors. | ||
3 | * | ||
4 | * Copyright 2010 PMC-Sierra, Inc. | ||
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 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
12 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
14 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
15 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
16 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
17 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
18 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
19 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
20 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License along | ||
23 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
24 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #include <linux/init.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/ioport.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/delay.h> | ||
32 | #include <msp_regs.h> | ||
33 | #include <msp_int.h> | ||
34 | #include <msp_gpio_macros.h> | ||
35 | |||
36 | |||
37 | #define MSP_ETHERNET_GPIO0 14 | ||
38 | #define MSP_ETHERNET_GPIO1 15 | ||
39 | #define MSP_ETHERNET_GPIO2 16 | ||
40 | |||
41 | #ifdef CONFIG_MSP_HAS_TSMAC | ||
42 | #define MSP_TSMAC_SIZE 0x10020 | ||
43 | #define MSP_TSMAC_ID "pmc_tsmac" | ||
44 | |||
45 | static struct resource msp_tsmac0_resources[] = { | ||
46 | [0] = { | ||
47 | .start = MSP_MAC0_BASE, | ||
48 | .end = MSP_MAC0_BASE + MSP_TSMAC_SIZE - 1, | ||
49 | .flags = IORESOURCE_MEM, | ||
50 | }, | ||
51 | [1] = { | ||
52 | .start = MSP_INT_MAC0, | ||
53 | .end = MSP_INT_MAC0, | ||
54 | .flags = IORESOURCE_IRQ, | ||
55 | }, | ||
56 | }; | ||
57 | |||
58 | static struct resource msp_tsmac1_resources[] = { | ||
59 | [0] = { | ||
60 | .start = MSP_MAC1_BASE, | ||
61 | .end = MSP_MAC1_BASE + MSP_TSMAC_SIZE - 1, | ||
62 | .flags = IORESOURCE_MEM, | ||
63 | }, | ||
64 | [1] = { | ||
65 | .start = MSP_INT_MAC1, | ||
66 | .end = MSP_INT_MAC1, | ||
67 | .flags = IORESOURCE_IRQ, | ||
68 | }, | ||
69 | }; | ||
70 | static struct resource msp_tsmac2_resources[] = { | ||
71 | [0] = { | ||
72 | .start = MSP_MAC2_BASE, | ||
73 | .end = MSP_MAC2_BASE + MSP_TSMAC_SIZE - 1, | ||
74 | .flags = IORESOURCE_MEM, | ||
75 | }, | ||
76 | [1] = { | ||
77 | .start = MSP_INT_SAR, | ||
78 | .end = MSP_INT_SAR, | ||
79 | .flags = IORESOURCE_IRQ, | ||
80 | }, | ||
81 | }; | ||
82 | |||
83 | |||
84 | static struct platform_device tsmac_device[] = { | ||
85 | [0] = { | ||
86 | .name = MSP_TSMAC_ID, | ||
87 | .id = 0, | ||
88 | .num_resources = ARRAY_SIZE(msp_tsmac0_resources), | ||
89 | .resource = msp_tsmac0_resources, | ||
90 | }, | ||
91 | [1] = { | ||
92 | .name = MSP_TSMAC_ID, | ||
93 | .id = 1, | ||
94 | .num_resources = ARRAY_SIZE(msp_tsmac1_resources), | ||
95 | .resource = msp_tsmac1_resources, | ||
96 | }, | ||
97 | [2] = { | ||
98 | .name = MSP_TSMAC_ID, | ||
99 | .id = 2, | ||
100 | .num_resources = ARRAY_SIZE(msp_tsmac2_resources), | ||
101 | .resource = msp_tsmac2_resources, | ||
102 | }, | ||
103 | }; | ||
104 | #define msp_eth_devs tsmac_device | ||
105 | |||
106 | #else | ||
107 | /* If it is not TSMAC assume MSP_ETH (100Mbps) */ | ||
108 | #define MSP_ETH_ID "pmc_mspeth" | ||
109 | #define MSP_ETH_SIZE 0xE0 | ||
110 | static struct resource msp_eth0_resources[] = { | ||
111 | [0] = { | ||
112 | .start = MSP_MAC0_BASE, | ||
113 | .end = MSP_MAC0_BASE + MSP_ETH_SIZE - 1, | ||
114 | .flags = IORESOURCE_MEM, | ||
115 | }, | ||
116 | [1] = { | ||
117 | .start = MSP_INT_MAC0, | ||
118 | .end = MSP_INT_MAC0, | ||
119 | .flags = IORESOURCE_IRQ, | ||
120 | }, | ||
121 | }; | ||
122 | |||
123 | static struct resource msp_eth1_resources[] = { | ||
124 | [0] = { | ||
125 | .start = MSP_MAC1_BASE, | ||
126 | .end = MSP_MAC1_BASE + MSP_ETH_SIZE - 1, | ||
127 | .flags = IORESOURCE_MEM, | ||
128 | }, | ||
129 | [1] = { | ||
130 | .start = MSP_INT_MAC1, | ||
131 | .end = MSP_INT_MAC1, | ||
132 | .flags = IORESOURCE_IRQ, | ||
133 | }, | ||
134 | }; | ||
135 | |||
136 | |||
137 | |||
138 | static struct platform_device mspeth_device[] = { | ||
139 | [0] = { | ||
140 | .name = MSP_ETH_ID, | ||
141 | .id = 0, | ||
142 | .num_resources = ARRAY_SIZE(msp_eth0_resources), | ||
143 | .resource = msp_eth0_resources, | ||
144 | }, | ||
145 | [1] = { | ||
146 | .name = MSP_ETH_ID, | ||
147 | .id = 1, | ||
148 | .num_resources = ARRAY_SIZE(msp_eth1_resources), | ||
149 | .resource = msp_eth1_resources, | ||
150 | }, | ||
151 | |||
152 | }; | ||
153 | #define msp_eth_devs mspeth_device | ||
154 | |||
155 | #endif | ||
156 | int __init msp_eth_setup(void) | ||
157 | { | ||
158 | int i, ret = 0; | ||
159 | |||
160 | /* Configure the GPIO and take the ethernet PHY out of reset */ | ||
161 | msp_gpio_pin_mode(MSP_GPIO_OUTPUT, MSP_ETHERNET_GPIO0); | ||
162 | msp_gpio_pin_hi(MSP_ETHERNET_GPIO0); | ||
163 | |||
164 | #ifdef CONFIG_MSP_HAS_TSMAC | ||
165 | /* 3 phys on boards with TSMAC */ | ||
166 | msp_gpio_pin_mode(MSP_GPIO_OUTPUT, MSP_ETHERNET_GPIO1); | ||
167 | msp_gpio_pin_hi(MSP_ETHERNET_GPIO1); | ||
168 | |||
169 | msp_gpio_pin_mode(MSP_GPIO_OUTPUT, MSP_ETHERNET_GPIO2); | ||
170 | msp_gpio_pin_hi(MSP_ETHERNET_GPIO2); | ||
171 | #endif | ||
172 | for (i = 0; i < ARRAY_SIZE(msp_eth_devs); i++) { | ||
173 | ret = platform_device_register(&msp_eth_devs[i]); | ||
174 | printk(KERN_INFO "device: %d, return value = %d\n", i, ret); | ||
175 | if (ret) { | ||
176 | platform_device_unregister(&msp_eth_devs[i]); | ||
177 | break; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | if (ret) | ||
182 | printk(KERN_WARNING "Could not initialize " | ||
183 | "MSPETH device structures.\n"); | ||
184 | |||
185 | return ret; | ||
186 | } | ||
187 | subsys_initcall(msp_eth_setup); | ||
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_irq.c b/arch/mips/pmc-sierra/msp71xx/msp_irq.c index 734d598a2e3a..4531c4a514bc 100644 --- a/arch/mips/pmc-sierra/msp71xx/msp_irq.c +++ b/arch/mips/pmc-sierra/msp71xx/msp_irq.c | |||
@@ -19,8 +19,6 @@ | |||
19 | 19 | ||
20 | #include <msp_int.h> | 20 | #include <msp_int.h> |
21 | 21 | ||
22 | extern void msp_int_handle(void); | ||
23 | |||
24 | /* SLP bases systems */ | 22 | /* SLP bases systems */ |
25 | extern void msp_slp_irq_init(void); | 23 | extern void msp_slp_irq_init(void); |
26 | extern void msp_slp_irq_dispatch(void); | 24 | extern void msp_slp_irq_dispatch(void); |
@@ -29,6 +27,18 @@ extern void msp_slp_irq_dispatch(void); | |||
29 | extern void msp_cic_irq_init(void); | 27 | extern void msp_cic_irq_init(void); |
30 | extern void msp_cic_irq_dispatch(void); | 28 | extern void msp_cic_irq_dispatch(void); |
31 | 29 | ||
30 | /* VSMP support init */ | ||
31 | extern void msp_vsmp_int_init(void); | ||
32 | |||
33 | /* vectored interrupt implementation */ | ||
34 | |||
35 | /* SW0/1 interrupts are used for SMP/SMTC */ | ||
36 | static inline void mac0_int_dispatch(void) { do_IRQ(MSP_INT_MAC0); } | ||
37 | static inline void mac1_int_dispatch(void) { do_IRQ(MSP_INT_MAC1); } | ||
38 | static inline void mac2_int_dispatch(void) { do_IRQ(MSP_INT_SAR); } | ||
39 | static inline void usb_int_dispatch(void) { do_IRQ(MSP_INT_USB); } | ||
40 | static inline void sec_int_dispatch(void) { do_IRQ(MSP_INT_SEC); } | ||
41 | |||
32 | /* | 42 | /* |
33 | * The PMC-Sierra MSP interrupts are arranged in a 3 level cascaded | 43 | * The PMC-Sierra MSP interrupts are arranged in a 3 level cascaded |
34 | * hierarchical system. The first level are the direct MIPS interrupts | 44 | * hierarchical system. The first level are the direct MIPS interrupts |
@@ -96,29 +106,57 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs) | |||
96 | do_IRQ(MSP_INT_SW1); | 106 | do_IRQ(MSP_INT_SW1); |
97 | } | 107 | } |
98 | 108 | ||
99 | static struct irqaction cascade_msp = { | 109 | static struct irqaction cic_cascade_msp = { |
100 | .handler = no_action, | 110 | .handler = no_action, |
101 | .name = "MSP cascade" | 111 | .name = "MSP CIC cascade" |
102 | }; | 112 | }; |
103 | 113 | ||
114 | static struct irqaction per_cascade_msp = { | ||
115 | .handler = no_action, | ||
116 | .name = "MSP PER cascade" | ||
117 | }; | ||
104 | 118 | ||
105 | void __init arch_init_irq(void) | 119 | void __init arch_init_irq(void) |
106 | { | 120 | { |
121 | /* assume we'll be using vectored interrupt mode except in UP mode*/ | ||
122 | #ifdef CONFIG_MIPS_MT | ||
123 | BUG_ON(!cpu_has_vint); | ||
124 | #endif | ||
107 | /* initialize the 1st-level CPU based interrupt controller */ | 125 | /* initialize the 1st-level CPU based interrupt controller */ |
108 | mips_cpu_irq_init(); | 126 | mips_cpu_irq_init(); |
109 | 127 | ||
110 | #ifdef CONFIG_IRQ_MSP_CIC | 128 | #ifdef CONFIG_IRQ_MSP_CIC |
111 | msp_cic_irq_init(); | 129 | msp_cic_irq_init(); |
112 | 130 | #ifdef CONFIG_MIPS_MT | |
131 | set_vi_handler(MSP_INT_CIC, msp_cic_irq_dispatch); | ||
132 | set_vi_handler(MSP_INT_MAC0, mac0_int_dispatch); | ||
133 | set_vi_handler(MSP_INT_MAC1, mac1_int_dispatch); | ||
134 | set_vi_handler(MSP_INT_SAR, mac2_int_dispatch); | ||
135 | set_vi_handler(MSP_INT_USB, usb_int_dispatch); | ||
136 | set_vi_handler(MSP_INT_SEC, sec_int_dispatch); | ||
137 | #ifdef CONFIG_MIPS_MT_SMP | ||
138 | msp_vsmp_int_init(); | ||
139 | #elif defined CONFIG_MIPS_MT_SMTC | ||
140 | /*Set hwmask for all platform devices */ | ||
141 | irq_hwmask[MSP_INT_MAC0] = C_IRQ0; | ||
142 | irq_hwmask[MSP_INT_MAC1] = C_IRQ1; | ||
143 | irq_hwmask[MSP_INT_USB] = C_IRQ2; | ||
144 | irq_hwmask[MSP_INT_SAR] = C_IRQ3; | ||
145 | irq_hwmask[MSP_INT_SEC] = C_IRQ5; | ||
146 | |||
147 | #endif /* CONFIG_MIPS_MT_SMP */ | ||
148 | #endif /* CONFIG_MIPS_MT */ | ||
113 | /* setup the cascaded interrupts */ | 149 | /* setup the cascaded interrupts */ |
114 | setup_irq(MSP_INT_CIC, &cascade_msp); | 150 | setup_irq(MSP_INT_CIC, &cic_cascade_msp); |
115 | setup_irq(MSP_INT_PER, &cascade_msp); | 151 | setup_irq(MSP_INT_PER, &per_cascade_msp); |
152 | |||
116 | #else | 153 | #else |
117 | /* setup the 2nd-level SLP register based interrupt controller */ | 154 | /* setup the 2nd-level SLP register based interrupt controller */ |
155 | /* VSMP /SMTC support support is not enabled for SLP */ | ||
118 | msp_slp_irq_init(); | 156 | msp_slp_irq_init(); |
119 | 157 | ||
120 | /* setup the cascaded SLP/PER interrupts */ | 158 | /* setup the cascaded SLP/PER interrupts */ |
121 | setup_irq(MSP_INT_SLP, &cascade_msp); | 159 | setup_irq(MSP_INT_SLP, &cic_cascade_msp); |
122 | setup_irq(MSP_INT_PER, &cascade_msp); | 160 | setup_irq(MSP_INT_PER, &per_cascade_msp); |
123 | #endif | 161 | #endif |
124 | } | 162 | } |
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c b/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c index 07e71ff2433f..352f29d9226f 100644 --- a/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c +++ b/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c | |||
@@ -1,8 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * This file define the irq handler for MSP SLM subsystem interrupts. | 2 | * Copyright 2010 PMC-Sierra, Inc, derived from irq_cpu.c |
3 | * | 3 | * |
4 | * Copyright 2005-2007 PMC-Sierra, Inc, derived from irq_cpu.c | 4 | * This file define the irq handler for MSP CIC subsystem interrupts. |
5 | * Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.com | ||
6 | * | 5 | * |
7 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
8 | * under the terms of the GNU General Public License as published by the | 7 | * under the terms of the GNU General Public License as published by the |
@@ -16,119 +15,203 @@ | |||
16 | #include <linux/bitops.h> | 15 | #include <linux/bitops.h> |
17 | #include <linux/irq.h> | 16 | #include <linux/irq.h> |
18 | 17 | ||
18 | #include <asm/mipsregs.h> | ||
19 | #include <asm/system.h> | 19 | #include <asm/system.h> |
20 | 20 | ||
21 | #include <msp_cic_int.h> | 21 | #include <msp_cic_int.h> |
22 | #include <msp_regs.h> | 22 | #include <msp_regs.h> |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * NOTE: We are only enabling support for VPE0 right now. | 25 | * External API |
26 | */ | 26 | */ |
27 | extern void msp_per_irq_init(void); | ||
28 | extern void msp_per_irq_dispatch(void); | ||
27 | 29 | ||
28 | static inline void unmask_msp_cic_irq(unsigned int irq) | 30 | |
31 | /* | ||
32 | * Convenience Macro. Should be somewhere generic. | ||
33 | */ | ||
34 | #define get_current_vpe() \ | ||
35 | ((read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE) | ||
36 | |||
37 | #ifdef CONFIG_SMP | ||
38 | |||
39 | #define LOCK_VPE(flags, mtflags) \ | ||
40 | do { \ | ||
41 | local_irq_save(flags); \ | ||
42 | mtflags = dmt(); \ | ||
43 | } while (0) | ||
44 | |||
45 | #define UNLOCK_VPE(flags, mtflags) \ | ||
46 | do { \ | ||
47 | emt(mtflags); \ | ||
48 | local_irq_restore(flags);\ | ||
49 | } while (0) | ||
50 | |||
51 | #define LOCK_CORE(flags, mtflags) \ | ||
52 | do { \ | ||
53 | local_irq_save(flags); \ | ||
54 | mtflags = dvpe(); \ | ||
55 | } while (0) | ||
56 | |||
57 | #define UNLOCK_CORE(flags, mtflags) \ | ||
58 | do { \ | ||
59 | evpe(mtflags); \ | ||
60 | local_irq_restore(flags);\ | ||
61 | } while (0) | ||
62 | |||
63 | #else | ||
64 | |||
65 | #define LOCK_VPE(flags, mtflags) | ||
66 | #define UNLOCK_VPE(flags, mtflags) | ||
67 | #endif | ||
68 | |||
69 | /* ensure writes to cic are completed */ | ||
70 | static inline void cic_wmb(void) | ||
29 | { | 71 | { |
72 | const volatile void __iomem *cic_mem = CIC_VPE0_MSK_REG; | ||
73 | volatile u32 dummy_read; | ||
30 | 74 | ||
31 | /* check for PER interrupt range */ | 75 | wmb(); |
32 | if (irq < MSP_PER_INTBASE) | 76 | dummy_read = __raw_readl(cic_mem); |
33 | *CIC_VPE0_MSK_REG |= (1 << (irq - MSP_CIC_INTBASE)); | 77 | dummy_read++; |
34 | else | ||
35 | *PER_INT_MSK_REG |= (1 << (irq - MSP_PER_INTBASE)); | ||
36 | } | 78 | } |
37 | 79 | ||
38 | static inline void mask_msp_cic_irq(unsigned int irq) | 80 | static void unmask_cic_irq(struct irq_data *d) |
39 | { | 81 | { |
40 | /* check for PER interrupt range */ | 82 | volatile u32 *cic_msk_reg = CIC_VPE0_MSK_REG; |
41 | if (irq < MSP_PER_INTBASE) | 83 | int vpe; |
42 | *CIC_VPE0_MSK_REG &= ~(1 << (irq - MSP_CIC_INTBASE)); | 84 | #ifdef CONFIG_SMP |
43 | else | 85 | unsigned int mtflags; |
44 | *PER_INT_MSK_REG &= ~(1 << (irq - MSP_PER_INTBASE)); | 86 | unsigned long flags; |
87 | |||
88 | /* | ||
89 | * Make sure we have IRQ affinity. It may have changed while | ||
90 | * we were processing the IRQ. | ||
91 | */ | ||
92 | if (!cpumask_test_cpu(smp_processor_id(), d->affinity)) | ||
93 | return; | ||
94 | #endif | ||
95 | |||
96 | vpe = get_current_vpe(); | ||
97 | LOCK_VPE(flags, mtflags); | ||
98 | cic_msk_reg[vpe] |= (1 << (d->irq - MSP_CIC_INTBASE)); | ||
99 | UNLOCK_VPE(flags, mtflags); | ||
100 | cic_wmb(); | ||
45 | } | 101 | } |
46 | 102 | ||
47 | /* | 103 | static void mask_cic_irq(struct irq_data *d) |
48 | * While we ack the interrupt interrupts are disabled and thus we don't need | ||
49 | * to deal with concurrency issues. Same for msp_cic_irq_end. | ||
50 | */ | ||
51 | static inline void ack_msp_cic_irq(unsigned int irq) | ||
52 | { | 104 | { |
53 | mask_msp_cic_irq(irq); | 105 | volatile u32 *cic_msk_reg = CIC_VPE0_MSK_REG; |
54 | 106 | int vpe = get_current_vpe(); | |
107 | #ifdef CONFIG_SMP | ||
108 | unsigned long flags, mtflags; | ||
109 | #endif | ||
110 | LOCK_VPE(flags, mtflags); | ||
111 | cic_msk_reg[vpe] &= ~(1 << (d->irq - MSP_CIC_INTBASE)); | ||
112 | UNLOCK_VPE(flags, mtflags); | ||
113 | cic_wmb(); | ||
114 | } | ||
115 | static void msp_cic_irq_ack(struct irq_data *d) | ||
116 | { | ||
117 | mask_cic_irq(d); | ||
55 | /* | 118 | /* |
56 | * only really necessary for 18, 16-14 and sometimes 3:0 (since | 119 | * Only really necessary for 18, 16-14 and sometimes 3:0 |
57 | * these can be edge sensitive) but it doesn't hurt for the others. | 120 | * (since these can be edge sensitive) but it doesn't |
58 | */ | 121 | * hurt for the others |
59 | 122 | */ | |
60 | /* check for PER interrupt range */ | 123 | *CIC_STS_REG = (1 << (d->irq - MSP_CIC_INTBASE)); |
61 | if (irq < MSP_PER_INTBASE) | 124 | smtc_im_ack_irq(d->irq); |
62 | *CIC_STS_REG = (1 << (irq - MSP_CIC_INTBASE)); | ||
63 | else | ||
64 | *PER_INT_STS_REG = (1 << (irq - MSP_PER_INTBASE)); | ||
65 | } | 125 | } |
66 | 126 | ||
127 | /*Note: Limiting to VSMP . Not tested in SMTC */ | ||
128 | |||
129 | #ifdef CONFIG_MIPS_MT_SMP | ||
130 | static int msp_cic_irq_set_affinity(struct irq_data *d, | ||
131 | const struct cpumask *cpumask, bool force) | ||
132 | { | ||
133 | int cpu; | ||
134 | unsigned long flags; | ||
135 | unsigned int mtflags; | ||
136 | unsigned long imask = (1 << (irq - MSP_CIC_INTBASE)); | ||
137 | volatile u32 *cic_mask = (volatile u32 *)CIC_VPE0_MSK_REG; | ||
138 | |||
139 | /* timer balancing should be disabled in kernel code */ | ||
140 | BUG_ON(irq == MSP_INT_VPE0_TIMER || irq == MSP_INT_VPE1_TIMER); | ||
141 | |||
142 | LOCK_CORE(flags, mtflags); | ||
143 | /* enable if any of each VPE's TCs require this IRQ */ | ||
144 | for_each_online_cpu(cpu) { | ||
145 | if (cpumask_test_cpu(cpu, cpumask)) | ||
146 | cic_mask[cpu] |= imask; | ||
147 | else | ||
148 | cic_mask[cpu] &= ~imask; | ||
149 | |||
150 | } | ||
151 | |||
152 | UNLOCK_CORE(flags, mtflags); | ||
153 | return 0; | ||
154 | |||
155 | } | ||
156 | #endif | ||
157 | |||
67 | static struct irq_chip msp_cic_irq_controller = { | 158 | static struct irq_chip msp_cic_irq_controller = { |
68 | .name = "MSP_CIC", | 159 | .name = "MSP_CIC", |
69 | .ack = ack_msp_cic_irq, | 160 | .irq_mask = mask_cic_irq, |
70 | .mask = ack_msp_cic_irq, | 161 | .irq_mask_ack = msp_cic_irq_ack, |
71 | .mask_ack = ack_msp_cic_irq, | 162 | .irq_unmask = unmask_cic_irq, |
72 | .unmask = unmask_msp_cic_irq, | 163 | .irq_ack = msp_cic_irq_ack, |
164 | #ifdef CONFIG_MIPS_MT_SMP | ||
165 | .irq_set_affinity = msp_cic_irq_set_affinity, | ||
166 | #endif | ||
73 | }; | 167 | }; |
74 | 168 | ||
75 | |||
76 | void __init msp_cic_irq_init(void) | 169 | void __init msp_cic_irq_init(void) |
77 | { | 170 | { |
78 | int i; | 171 | int i; |
79 | |||
80 | /* Mask/clear interrupts. */ | 172 | /* Mask/clear interrupts. */ |
81 | *CIC_VPE0_MSK_REG = 0x00000000; | 173 | *CIC_VPE0_MSK_REG = 0x00000000; |
82 | *PER_INT_MSK_REG = 0x00000000; | 174 | *CIC_VPE1_MSK_REG = 0x00000000; |
83 | *CIC_STS_REG = 0xFFFFFFFF; | 175 | *CIC_STS_REG = 0xFFFFFFFF; |
84 | *PER_INT_STS_REG = 0xFFFFFFFF; | ||
85 | |||
86 | #if defined(CONFIG_PMC_MSP7120_GW) || \ | ||
87 | defined(CONFIG_PMC_MSP7120_EVAL) | ||
88 | /* | 176 | /* |
89 | * The MSP7120 RG and EVBD boards use IRQ[6:4] for PCI. | 177 | * The MSP7120 RG and EVBD boards use IRQ[6:4] for PCI. |
90 | * These inputs map to EXT_INT_POL[6:4] inside the CIC. | 178 | * These inputs map to EXT_INT_POL[6:4] inside the CIC. |
91 | * They are to be active low, level sensitive. | 179 | * They are to be active low, level sensitive. |
92 | */ | 180 | */ |
93 | *CIC_EXT_CFG_REG &= 0xFFFF8F8F; | 181 | *CIC_EXT_CFG_REG &= 0xFFFF8F8F; |
94 | #endif | ||
95 | 182 | ||
96 | /* initialize all the IRQ descriptors */ | 183 | /* initialize all the IRQ descriptors */ |
97 | for (i = MSP_CIC_INTBASE; i < MSP_PER_INTBASE + 32; i++) | 184 | for (i = MSP_CIC_INTBASE ; i < MSP_CIC_INTBASE + 32 ; i++) { |
98 | set_irq_chip_and_handler(i, &msp_cic_irq_controller, | 185 | set_irq_chip_and_handler(i, &msp_cic_irq_controller, |
99 | handle_level_irq); | 186 | handle_level_irq); |
187 | #ifdef CONFIG_MIPS_MT_SMTC | ||
188 | /* Mask of CIC interrupt */ | ||
189 | irq_hwmask[i] = C_IRQ4; | ||
190 | #endif | ||
191 | } | ||
192 | |||
193 | /* Initialize the PER interrupt sub-system */ | ||
194 | msp_per_irq_init(); | ||
100 | } | 195 | } |
101 | 196 | ||
197 | /* CIC masked by CIC vector processing before dispatch called */ | ||
102 | void msp_cic_irq_dispatch(void) | 198 | void msp_cic_irq_dispatch(void) |
103 | { | 199 | { |
104 | u32 pending; | 200 | volatile u32 *cic_msk_reg = (volatile u32 *)CIC_VPE0_MSK_REG; |
105 | int intbase; | 201 | u32 cic_mask; |
106 | 202 | u32 pending; | |
107 | intbase = MSP_CIC_INTBASE; | 203 | int cic_status = *CIC_STS_REG; |
108 | pending = *CIC_STS_REG & *CIC_VPE0_MSK_REG; | 204 | cic_mask = cic_msk_reg[get_current_vpe()]; |
109 | 205 | pending = cic_status & cic_mask; | |
110 | /* check for PER interrupt */ | 206 | if (pending & (1 << (MSP_INT_VPE0_TIMER - MSP_CIC_INTBASE))) { |
111 | if (pending == (1 << (MSP_INT_PER - MSP_CIC_INTBASE))) { | ||
112 | intbase = MSP_PER_INTBASE; | ||
113 | pending = *PER_INT_STS_REG & *PER_INT_MSK_REG; | ||
114 | } | ||
115 | |||
116 | /* check for spurious interrupt */ | ||
117 | if (pending == 0x00000000) { | ||
118 | printk(KERN_ERR | ||
119 | "Spurious %s interrupt? status %08x, mask %08x\n", | ||
120 | (intbase == MSP_CIC_INTBASE) ? "CIC" : "PER", | ||
121 | (intbase == MSP_CIC_INTBASE) ? | ||
122 | *CIC_STS_REG : *PER_INT_STS_REG, | ||
123 | (intbase == MSP_CIC_INTBASE) ? | ||
124 | *CIC_VPE0_MSK_REG : *PER_INT_MSK_REG); | ||
125 | return; | ||
126 | } | ||
127 | |||
128 | /* check for the timer and dispatch it first */ | ||
129 | if ((intbase == MSP_CIC_INTBASE) && | ||
130 | (pending & (1 << (MSP_INT_VPE0_TIMER - MSP_CIC_INTBASE)))) | ||
131 | do_IRQ(MSP_INT_VPE0_TIMER); | 207 | do_IRQ(MSP_INT_VPE0_TIMER); |
132 | else | 208 | } else if (pending & (1 << (MSP_INT_VPE1_TIMER - MSP_CIC_INTBASE))) { |
133 | do_IRQ(ffs(pending) + intbase - 1); | 209 | do_IRQ(MSP_INT_VPE1_TIMER); |
210 | } else if (pending & (1 << (MSP_INT_PER - MSP_CIC_INTBASE))) { | ||
211 | msp_per_irq_dispatch(); | ||
212 | } else if (pending) { | ||
213 | do_IRQ(ffs(pending) + MSP_CIC_INTBASE - 1); | ||
214 | } else{ | ||
215 | spurious_interrupt(); | ||
216 | } | ||
134 | } | 217 | } |
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_irq_per.c b/arch/mips/pmc-sierra/msp71xx/msp_irq_per.c new file mode 100644 index 000000000000..f9b9dcdfa9dd --- /dev/null +++ b/arch/mips/pmc-sierra/msp71xx/msp_irq_per.c | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * Copyright 2010 PMC-Sierra, Inc, derived from irq_cpu.c | ||
3 | * | ||
4 | * This file define the irq handler for MSP PER subsystem interrupts. | ||
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 | #include <linux/init.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/spinlock.h> | ||
16 | #include <linux/bitops.h> | ||
17 | |||
18 | #include <asm/mipsregs.h> | ||
19 | #include <asm/system.h> | ||
20 | |||
21 | #include <msp_cic_int.h> | ||
22 | #include <msp_regs.h> | ||
23 | |||
24 | |||
25 | /* | ||
26 | * Convenience Macro. Should be somewhere generic. | ||
27 | */ | ||
28 | #define get_current_vpe() \ | ||
29 | ((read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE) | ||
30 | |||
31 | #ifdef CONFIG_SMP | ||
32 | /* | ||
33 | * The PER registers must be protected from concurrent access. | ||
34 | */ | ||
35 | |||
36 | static DEFINE_SPINLOCK(per_lock); | ||
37 | #endif | ||
38 | |||
39 | /* ensure writes to per are completed */ | ||
40 | |||
41 | static inline void per_wmb(void) | ||
42 | { | ||
43 | const volatile void __iomem *per_mem = PER_INT_MSK_REG; | ||
44 | volatile u32 dummy_read; | ||
45 | |||
46 | wmb(); | ||
47 | dummy_read = __raw_readl(per_mem); | ||
48 | dummy_read++; | ||
49 | } | ||
50 | |||
51 | static inline void unmask_per_irq(struct irq_data *d) | ||
52 | { | ||
53 | #ifdef CONFIG_SMP | ||
54 | unsigned long flags; | ||
55 | spin_lock_irqsave(&per_lock, flags); | ||
56 | *PER_INT_MSK_REG |= (1 << (d->irq - MSP_PER_INTBASE)); | ||
57 | spin_unlock_irqrestore(&per_lock, flags); | ||
58 | #else | ||
59 | *PER_INT_MSK_REG |= (1 << (d->irq - MSP_PER_INTBASE)); | ||
60 | #endif | ||
61 | per_wmb(); | ||
62 | } | ||
63 | |||
64 | static inline void mask_per_irq(struct irq_data *d) | ||
65 | { | ||
66 | #ifdef CONFIG_SMP | ||
67 | unsigned long flags; | ||
68 | spin_lock_irqsave(&per_lock, flags); | ||
69 | *PER_INT_MSK_REG &= ~(1 << (d->irq - MSP_PER_INTBASE)); | ||
70 | spin_unlock_irqrestore(&per_lock, flags); | ||
71 | #else | ||
72 | *PER_INT_MSK_REG &= ~(1 << (d->irq - MSP_PER_INTBASE)); | ||
73 | #endif | ||
74 | per_wmb(); | ||
75 | } | ||
76 | |||
77 | static inline void msp_per_irq_ack(struct irq_data *d) | ||
78 | { | ||
79 | mask_per_irq(d); | ||
80 | /* | ||
81 | * In the PER interrupt controller, only bits 11 and 10 | ||
82 | * are write-to-clear, (SPI TX complete, SPI RX complete). | ||
83 | * It does nothing for any others. | ||
84 | */ | ||
85 | *PER_INT_STS_REG = (1 << (d->irq - MSP_PER_INTBASE)); | ||
86 | } | ||
87 | |||
88 | #ifdef CONFIG_SMP | ||
89 | static int msp_per_irq_set_affinity(struct irq_data *d, | ||
90 | const struct cpumask *affinity, bool force) | ||
91 | { | ||
92 | /* WTF is this doing ????? */ | ||
93 | unmask_per_irq(d); | ||
94 | return 0; | ||
95 | } | ||
96 | #endif | ||
97 | |||
98 | static struct irq_chip msp_per_irq_controller = { | ||
99 | .name = "MSP_PER", | ||
100 | .irq_enable = unmask_per_irq. | ||
101 | .irq_disable = mask_per_irq, | ||
102 | .irq_ack = msp_per_irq_ack, | ||
103 | #ifdef CONFIG_SMP | ||
104 | .irq_set_affinity = msp_per_irq_set_affinity, | ||
105 | #endif | ||
106 | }; | ||
107 | |||
108 | void __init msp_per_irq_init(void) | ||
109 | { | ||
110 | int i; | ||
111 | /* Mask/clear interrupts. */ | ||
112 | *PER_INT_MSK_REG = 0x00000000; | ||
113 | *PER_INT_STS_REG = 0xFFFFFFFF; | ||
114 | /* initialize all the IRQ descriptors */ | ||
115 | for (i = MSP_PER_INTBASE; i < MSP_PER_INTBASE + 32; i++) { | ||
116 | irq_set_chip(i, &msp_per_irq_controller); | ||
117 | #ifdef CONFIG_MIPS_MT_SMTC | ||
118 | irq_hwmask[i] = C_IRQ4; | ||
119 | #endif | ||
120 | } | ||
121 | } | ||
122 | |||
123 | void msp_per_irq_dispatch(void) | ||
124 | { | ||
125 | u32 per_mask = *PER_INT_MSK_REG; | ||
126 | u32 per_status = *PER_INT_STS_REG; | ||
127 | u32 pending; | ||
128 | |||
129 | pending = per_status & per_mask; | ||
130 | if (pending) { | ||
131 | do_IRQ(ffs(pending) + MSP_PER_INTBASE - 1); | ||
132 | } else { | ||
133 | spurious_interrupt(); | ||
134 | } | ||
135 | } | ||
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_irq_slp.c b/arch/mips/pmc-sierra/msp71xx/msp_irq_slp.c index 61f390232346..8f51e4adc438 100644 --- a/arch/mips/pmc-sierra/msp71xx/msp_irq_slp.c +++ b/arch/mips/pmc-sierra/msp71xx/msp_irq_slp.c | |||
@@ -21,8 +21,10 @@ | |||
21 | #include <msp_slp_int.h> | 21 | #include <msp_slp_int.h> |
22 | #include <msp_regs.h> | 22 | #include <msp_regs.h> |
23 | 23 | ||
24 | static inline void unmask_msp_slp_irq(unsigned int irq) | 24 | static inline void unmask_msp_slp_irq(struct irq_data *d) |
25 | { | 25 | { |
26 | unsigned int irq = d->irq; | ||
27 | |||
26 | /* check for PER interrupt range */ | 28 | /* check for PER interrupt range */ |
27 | if (irq < MSP_PER_INTBASE) | 29 | if (irq < MSP_PER_INTBASE) |
28 | *SLP_INT_MSK_REG |= (1 << (irq - MSP_SLP_INTBASE)); | 30 | *SLP_INT_MSK_REG |= (1 << (irq - MSP_SLP_INTBASE)); |
@@ -30,8 +32,10 @@ static inline void unmask_msp_slp_irq(unsigned int irq) | |||
30 | *PER_INT_MSK_REG |= (1 << (irq - MSP_PER_INTBASE)); | 32 | *PER_INT_MSK_REG |= (1 << (irq - MSP_PER_INTBASE)); |
31 | } | 33 | } |
32 | 34 | ||
33 | static inline void mask_msp_slp_irq(unsigned int irq) | 35 | static inline void mask_msp_slp_irq(struct irq_data *d) |
34 | { | 36 | { |
37 | unsigned int irq = d->irq; | ||
38 | |||
35 | /* check for PER interrupt range */ | 39 | /* check for PER interrupt range */ |
36 | if (irq < MSP_PER_INTBASE) | 40 | if (irq < MSP_PER_INTBASE) |
37 | *SLP_INT_MSK_REG &= ~(1 << (irq - MSP_SLP_INTBASE)); | 41 | *SLP_INT_MSK_REG &= ~(1 << (irq - MSP_SLP_INTBASE)); |
@@ -43,8 +47,10 @@ static inline void mask_msp_slp_irq(unsigned int irq) | |||
43 | * While we ack the interrupt interrupts are disabled and thus we don't need | 47 | * While we ack the interrupt interrupts are disabled and thus we don't need |
44 | * to deal with concurrency issues. Same for msp_slp_irq_end. | 48 | * to deal with concurrency issues. Same for msp_slp_irq_end. |
45 | */ | 49 | */ |
46 | static inline void ack_msp_slp_irq(unsigned int irq) | 50 | static inline void ack_msp_slp_irq(struct irq_data *d) |
47 | { | 51 | { |
52 | unsigned int irq = d->irq; | ||
53 | |||
48 | /* check for PER interrupt range */ | 54 | /* check for PER interrupt range */ |
49 | if (irq < MSP_PER_INTBASE) | 55 | if (irq < MSP_PER_INTBASE) |
50 | *SLP_INT_STS_REG = (1 << (irq - MSP_SLP_INTBASE)); | 56 | *SLP_INT_STS_REG = (1 << (irq - MSP_SLP_INTBASE)); |
@@ -54,9 +60,9 @@ static inline void ack_msp_slp_irq(unsigned int irq) | |||
54 | 60 | ||
55 | static struct irq_chip msp_slp_irq_controller = { | 61 | static struct irq_chip msp_slp_irq_controller = { |
56 | .name = "MSP_SLP", | 62 | .name = "MSP_SLP", |
57 | .ack = ack_msp_slp_irq, | 63 | .irq_ack = ack_msp_slp_irq, |
58 | .mask = mask_msp_slp_irq, | 64 | .irq_mask = mask_msp_slp_irq, |
59 | .unmask = unmask_msp_slp_irq, | 65 | .irq_unmask = unmask_msp_slp_irq, |
60 | }; | 66 | }; |
61 | 67 | ||
62 | void __init msp_slp_irq_init(void) | 68 | void __init msp_slp_irq_init(void) |
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_setup.c b/arch/mips/pmc-sierra/msp71xx/msp_setup.c index a54e85b3cf29..fb37a10e0309 100644 --- a/arch/mips/pmc-sierra/msp71xx/msp_setup.c +++ b/arch/mips/pmc-sierra/msp71xx/msp_setup.c | |||
@@ -146,6 +146,8 @@ void __init plat_mem_setup(void) | |||
146 | pm_power_off = msp_power_off; | 146 | pm_power_off = msp_power_off; |
147 | } | 147 | } |
148 | 148 | ||
149 | extern struct plat_smp_ops msp_smtc_smp_ops; | ||
150 | |||
149 | void __init prom_init(void) | 151 | void __init prom_init(void) |
150 | { | 152 | { |
151 | unsigned long family; | 153 | unsigned long family; |
@@ -226,6 +228,14 @@ void __init prom_init(void) | |||
226 | */ | 228 | */ |
227 | msp_serial_setup(); | 229 | msp_serial_setup(); |
228 | 230 | ||
231 | #ifdef CONFIG_MIPS_MT_SMP | ||
232 | register_smp_ops(&vsmp_smp_ops); | ||
233 | #endif | ||
234 | |||
235 | #ifdef CONFIG_MIPS_MT_SMTC | ||
236 | register_smp_ops(&msp_smtc_smp_ops); | ||
237 | #endif | ||
238 | |||
229 | #ifdef CONFIG_PMCTWILED | 239 | #ifdef CONFIG_PMCTWILED |
230 | /* | 240 | /* |
231 | * Setup LED states before the subsys_initcall loads other | 241 | * Setup LED states before the subsys_initcall loads other |
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_smp.c b/arch/mips/pmc-sierra/msp71xx/msp_smp.c new file mode 100644 index 000000000000..43a9e26e1c69 --- /dev/null +++ b/arch/mips/pmc-sierra/msp71xx/msp_smp.c | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000, 2001, 2004 MIPS Technologies, Inc. | ||
3 | * Copyright (C) 2001 Ralf Baechle | ||
4 | * Copyright (C) 2010 PMC-Sierra, Inc. | ||
5 | * | ||
6 | * VSMP support for MSP platforms . Derived from malta vsmp support. | ||
7 | * | ||
8 | * This program is free software; you can distribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License (Version 2) as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
15 | * for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
20 | * | ||
21 | */ | ||
22 | #include <linux/smp.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | |||
25 | #ifdef CONFIG_MIPS_MT_SMP | ||
26 | #define MIPS_CPU_IPI_RESCHED_IRQ 0 /* SW int 0 for resched */ | ||
27 | #define MIPS_CPU_IPI_CALL_IRQ 1 /* SW int 1 for call */ | ||
28 | |||
29 | |||
30 | static void ipi_resched_dispatch(void) | ||
31 | { | ||
32 | do_IRQ(MIPS_CPU_IPI_RESCHED_IRQ); | ||
33 | } | ||
34 | |||
35 | static void ipi_call_dispatch(void) | ||
36 | { | ||
37 | do_IRQ(MIPS_CPU_IPI_CALL_IRQ); | ||
38 | } | ||
39 | |||
40 | static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) | ||
41 | { | ||
42 | return IRQ_HANDLED; | ||
43 | } | ||
44 | |||
45 | static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) | ||
46 | { | ||
47 | smp_call_function_interrupt(); | ||
48 | |||
49 | return IRQ_HANDLED; | ||
50 | } | ||
51 | |||
52 | static struct irqaction irq_resched = { | ||
53 | .handler = ipi_resched_interrupt, | ||
54 | .flags = IRQF_DISABLED | IRQF_PERCPU, | ||
55 | .name = "IPI_resched" | ||
56 | }; | ||
57 | |||
58 | static struct irqaction irq_call = { | ||
59 | .handler = ipi_call_interrupt, | ||
60 | .flags = IRQF_DISABLED | IRQF_PERCPU, | ||
61 | .name = "IPI_call" | ||
62 | }; | ||
63 | |||
64 | void __init arch_init_ipiirq(int irq, struct irqaction *action) | ||
65 | { | ||
66 | setup_irq(irq, action); | ||
67 | set_irq_handler(irq, handle_percpu_irq); | ||
68 | } | ||
69 | |||
70 | void __init msp_vsmp_int_init(void) | ||
71 | { | ||
72 | set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch); | ||
73 | set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch); | ||
74 | arch_init_ipiirq(MIPS_CPU_IPI_RESCHED_IRQ, &irq_resched); | ||
75 | arch_init_ipiirq(MIPS_CPU_IPI_CALL_IRQ, &irq_call); | ||
76 | } | ||
77 | #endif /* CONFIG_MIPS_MT_SMP */ | ||
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_smtc.c b/arch/mips/pmc-sierra/msp71xx/msp_smtc.c new file mode 100644 index 000000000000..c8dcc1c01e18 --- /dev/null +++ b/arch/mips/pmc-sierra/msp71xx/msp_smtc.c | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * MSP71xx Platform-specific hooks for SMP operation | ||
3 | */ | ||
4 | #include <linux/irq.h> | ||
5 | #include <linux/init.h> | ||
6 | |||
7 | #include <asm/mipsmtregs.h> | ||
8 | #include <asm/mipsregs.h> | ||
9 | #include <asm/smtc.h> | ||
10 | #include <asm/smtc_ipi.h> | ||
11 | |||
12 | /* VPE/SMP Prototype implements platform interfaces directly */ | ||
13 | |||
14 | /* | ||
15 | * Cause the specified action to be performed on a targeted "CPU" | ||
16 | */ | ||
17 | |||
18 | static void msp_smtc_send_ipi_single(int cpu, unsigned int action) | ||
19 | { | ||
20 | /* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */ | ||
21 | smtc_send_ipi(cpu, LINUX_SMP_IPI, action); | ||
22 | } | ||
23 | |||
24 | static void msp_smtc_send_ipi_mask(const struct cpumask *mask, | ||
25 | unsigned int action) | ||
26 | { | ||
27 | unsigned int i; | ||
28 | |||
29 | for_each_cpu(i, mask) | ||
30 | msp_smtc_send_ipi_single(i, action); | ||
31 | } | ||
32 | |||
33 | /* | ||
34 | * Post-config but pre-boot cleanup entry point | ||
35 | */ | ||
36 | static void __cpuinit msp_smtc_init_secondary(void) | ||
37 | { | ||
38 | int myvpe; | ||
39 | |||
40 | /* Don't enable Malta I/O interrupts (IP2) for secondary VPEs */ | ||
41 | myvpe = read_c0_tcbind() & TCBIND_CURVPE; | ||
42 | if (myvpe > 0) | ||
43 | change_c0_status(ST0_IM, STATUSF_IP0 | STATUSF_IP1 | | ||
44 | STATUSF_IP6 | STATUSF_IP7); | ||
45 | smtc_init_secondary(); | ||
46 | } | ||
47 | |||
48 | /* | ||
49 | * Platform "CPU" startup hook | ||
50 | */ | ||
51 | static void __cpuinit msp_smtc_boot_secondary(int cpu, | ||
52 | struct task_struct *idle) | ||
53 | { | ||
54 | smtc_boot_secondary(cpu, idle); | ||
55 | } | ||
56 | |||
57 | /* | ||
58 | * SMP initialization finalization entry point | ||
59 | */ | ||
60 | static void __cpuinit msp_smtc_smp_finish(void) | ||
61 | { | ||
62 | smtc_smp_finish(); | ||
63 | } | ||
64 | |||
65 | /* | ||
66 | * Hook for after all CPUs are online | ||
67 | */ | ||
68 | |||
69 | static void msp_smtc_cpus_done(void) | ||
70 | { | ||
71 | } | ||
72 | |||
73 | /* | ||
74 | * Platform SMP pre-initialization | ||
75 | * | ||
76 | * As noted above, we can assume a single CPU for now | ||
77 | * but it may be multithreaded. | ||
78 | */ | ||
79 | |||
80 | static void __init msp_smtc_smp_setup(void) | ||
81 | { | ||
82 | /* | ||
83 | * we won't get the definitive value until | ||
84 | * we've run smtc_prepare_cpus later, but | ||
85 | */ | ||
86 | |||
87 | if (read_c0_config3() & (1 << 2)) | ||
88 | smp_num_siblings = smtc_build_cpu_map(0); | ||
89 | } | ||
90 | |||
91 | static void __init msp_smtc_prepare_cpus(unsigned int max_cpus) | ||
92 | { | ||
93 | smtc_prepare_cpus(max_cpus); | ||
94 | } | ||
95 | |||
96 | struct plat_smp_ops msp_smtc_smp_ops = { | ||
97 | .send_ipi_single = msp_smtc_send_ipi_single, | ||
98 | .send_ipi_mask = msp_smtc_send_ipi_mask, | ||
99 | .init_secondary = msp_smtc_init_secondary, | ||
100 | .smp_finish = msp_smtc_smp_finish, | ||
101 | .cpus_done = msp_smtc_cpus_done, | ||
102 | .boot_secondary = msp_smtc_boot_secondary, | ||
103 | .smp_setup = msp_smtc_smp_setup, | ||
104 | .prepare_cpus = msp_smtc_prepare_cpus, | ||
105 | }; | ||
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_time.c b/arch/mips/pmc-sierra/msp71xx/msp_time.c index 01df84ce31e2..8b42f307a7a7 100644 --- a/arch/mips/pmc-sierra/msp71xx/msp_time.c +++ b/arch/mips/pmc-sierra/msp71xx/msp_time.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | #include <linux/ptrace.h> | 30 | #include <linux/ptrace.h> |
31 | 31 | ||
32 | #include <asm/cevt-r4k.h> | ||
32 | #include <asm/mipsregs.h> | 33 | #include <asm/mipsregs.h> |
33 | #include <asm/time.h> | 34 | #include <asm/time.h> |
34 | 35 | ||
@@ -36,6 +37,12 @@ | |||
36 | #include <msp_int.h> | 37 | #include <msp_int.h> |
37 | #include <msp_regs.h> | 38 | #include <msp_regs.h> |
38 | 39 | ||
40 | #define get_current_vpe() \ | ||
41 | ((read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE) | ||
42 | |||
43 | static struct irqaction timer_vpe1; | ||
44 | static int tim_installed; | ||
45 | |||
39 | void __init plat_time_init(void) | 46 | void __init plat_time_init(void) |
40 | { | 47 | { |
41 | char *endp, *s; | 48 | char *endp, *s; |
@@ -83,5 +90,12 @@ void __init plat_time_init(void) | |||
83 | 90 | ||
84 | unsigned int __cpuinit get_c0_compare_int(void) | 91 | unsigned int __cpuinit get_c0_compare_int(void) |
85 | { | 92 | { |
86 | return MSP_INT_VPE0_TIMER; | 93 | /* MIPS_MT modes may want timer for second VPE */ |
94 | if ((get_current_vpe()) && !tim_installed) { | ||
95 | memcpy(&timer_vpe1, &c0_compare_irqaction, sizeof(timer_vpe1)); | ||
96 | setup_irq(MSP_INT_VPE1_TIMER, &timer_vpe1); | ||
97 | tim_installed++; | ||
98 | } | ||
99 | |||
100 | return get_current_vpe() ? MSP_INT_VPE1_TIMER : MSP_INT_VPE0_TIMER; | ||
87 | } | 101 | } |
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_usb.c b/arch/mips/pmc-sierra/msp71xx/msp_usb.c index 0ee01e359dd8..9a1aef89bd4c 100644 --- a/arch/mips/pmc-sierra/msp71xx/msp_usb.c +++ b/arch/mips/pmc-sierra/msp71xx/msp_usb.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * The setup file for USB related hardware on PMC-Sierra MSP processors. | 2 | * The setup file for USB related hardware on PMC-Sierra MSP processors. |
3 | * | 3 | * |
4 | * Copyright 2006-2007 PMC-Sierra, Inc. | 4 | * Copyright 2006 PMC-Sierra, Inc. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 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 | 7 | * under the terms of the GNU General Public License as published by the |
@@ -23,8 +23,8 @@ | |||
23 | * with this program; if not, write to the Free Software Foundation, Inc., | 23 | * with this program; if not, write to the Free Software Foundation, Inc., |
24 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 24 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
25 | */ | 25 | */ |
26 | #if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_GADGET) | ||
26 | 27 | ||
27 | #include <linux/dma-mapping.h> | ||
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <linux/ioport.h> | 29 | #include <linux/ioport.h> |
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
@@ -34,40 +34,56 @@ | |||
34 | #include <msp_regs.h> | 34 | #include <msp_regs.h> |
35 | #include <msp_int.h> | 35 | #include <msp_int.h> |
36 | #include <msp_prom.h> | 36 | #include <msp_prom.h> |
37 | #include <msp_usb.h> | ||
38 | |||
37 | 39 | ||
38 | #if defined(CONFIG_USB_EHCI_HCD) | 40 | #if defined(CONFIG_USB_EHCI_HCD) |
39 | static struct resource msp_usbhost_resources [] = { | 41 | static struct resource msp_usbhost0_resources[] = { |
40 | [0] = { | 42 | [0] = { /* EHCI-HS operational and capabilities registers */ |
41 | .start = MSP_USB_BASE_START, | 43 | .start = MSP_USB0_HS_START, |
42 | .end = MSP_USB_BASE_END, | 44 | .end = MSP_USB0_HS_END, |
43 | .flags = IORESOURCE_MEM, | 45 | .flags = IORESOURCE_MEM, |
44 | }, | 46 | }, |
45 | [1] = { | 47 | [1] = { |
46 | .start = MSP_INT_USB, | 48 | .start = MSP_INT_USB, |
47 | .end = MSP_INT_USB, | 49 | .end = MSP_INT_USB, |
48 | .flags = IORESOURCE_IRQ, | 50 | .flags = IORESOURCE_IRQ, |
51 | }, | ||
52 | [2] = { /* MSBus-to-AMBA bridge register space */ | ||
53 | .start = MSP_USB0_MAB_START, | ||
54 | .end = MSP_USB0_MAB_END, | ||
55 | .flags = IORESOURCE_MEM, | ||
56 | }, | ||
57 | [3] = { /* Identification and general hardware parameters */ | ||
58 | .start = MSP_USB0_ID_START, | ||
59 | .end = MSP_USB0_ID_END, | ||
60 | .flags = IORESOURCE_MEM, | ||
49 | }, | 61 | }, |
50 | }; | 62 | }; |
51 | 63 | ||
52 | static u64 msp_usbhost_dma_mask = DMA_BIT_MASK(32); | 64 | static u64 msp_usbhost0_dma_mask = 0xffffffffUL; |
53 | 65 | ||
54 | static struct platform_device msp_usbhost_device = { | 66 | static struct mspusb_device msp_usbhost0_device = { |
55 | .name = "pmcmsp-ehci", | ||
56 | .id = 0, | ||
57 | .dev = { | 67 | .dev = { |
58 | .dma_mask = &msp_usbhost_dma_mask, | 68 | .name = "pmcmsp-ehci", |
59 | .coherent_dma_mask = DMA_BIT_MASK(32), | 69 | .id = 0, |
70 | .dev = { | ||
71 | .dma_mask = &msp_usbhost0_dma_mask, | ||
72 | .coherent_dma_mask = 0xffffffffUL, | ||
73 | }, | ||
74 | .num_resources = ARRAY_SIZE(msp_usbhost0_resources), | ||
75 | .resource = msp_usbhost0_resources, | ||
60 | }, | 76 | }, |
61 | .num_resources = ARRAY_SIZE(msp_usbhost_resources), | ||
62 | .resource = msp_usbhost_resources, | ||
63 | }; | 77 | }; |
64 | #endif /* CONFIG_USB_EHCI_HCD */ | ||
65 | 78 | ||
66 | #if defined(CONFIG_USB_GADGET) | 79 | /* MSP7140/MSP82XX has two USB2 hosts. */ |
67 | static struct resource msp_usbdev_resources [] = { | 80 | #ifdef CONFIG_MSP_HAS_DUAL_USB |
68 | [0] = { | 81 | static u64 msp_usbhost1_dma_mask = 0xffffffffUL; |
69 | .start = MSP_USB_BASE, | 82 | |
70 | .end = MSP_USB_BASE_END, | 83 | static struct resource msp_usbhost1_resources[] = { |
84 | [0] = { /* EHCI-HS operational and capabilities registers */ | ||
85 | .start = MSP_USB1_HS_START, | ||
86 | .end = MSP_USB1_HS_END, | ||
71 | .flags = IORESOURCE_MEM, | 87 | .flags = IORESOURCE_MEM, |
72 | }, | 88 | }, |
73 | [1] = { | 89 | [1] = { |
@@ -75,76 +91,173 @@ static struct resource msp_usbdev_resources [] = { | |||
75 | .end = MSP_INT_USB, | 91 | .end = MSP_INT_USB, |
76 | .flags = IORESOURCE_IRQ, | 92 | .flags = IORESOURCE_IRQ, |
77 | }, | 93 | }, |
94 | [2] = { /* MSBus-to-AMBA bridge register space */ | ||
95 | .start = MSP_USB1_MAB_START, | ||
96 | .end = MSP_USB1_MAB_END, | ||
97 | .flags = IORESOURCE_MEM, | ||
98 | }, | ||
99 | [3] = { /* Identification and general hardware parameters */ | ||
100 | .start = MSP_USB1_ID_START, | ||
101 | .end = MSP_USB1_ID_END, | ||
102 | .flags = IORESOURCE_MEM, | ||
103 | }, | ||
104 | }; | ||
105 | |||
106 | static struct mspusb_device msp_usbhost1_device = { | ||
107 | .dev = { | ||
108 | .name = "pmcmsp-ehci", | ||
109 | .id = 1, | ||
110 | .dev = { | ||
111 | .dma_mask = &msp_usbhost1_dma_mask, | ||
112 | .coherent_dma_mask = 0xffffffffUL, | ||
113 | }, | ||
114 | .num_resources = ARRAY_SIZE(msp_usbhost1_resources), | ||
115 | .resource = msp_usbhost1_resources, | ||
116 | }, | ||
78 | }; | 117 | }; |
118 | #endif /* CONFIG_MSP_HAS_DUAL_USB */ | ||
119 | #endif /* CONFIG_USB_EHCI_HCD */ | ||
79 | 120 | ||
80 | static u64 msp_usbdev_dma_mask = DMA_BIT_MASK(32); | 121 | #if defined(CONFIG_USB_GADGET) |
122 | static struct resource msp_usbdev0_resources[] = { | ||
123 | [0] = { /* EHCI-HS operational and capabilities registers */ | ||
124 | .start = MSP_USB0_HS_START, | ||
125 | .end = MSP_USB0_HS_END, | ||
126 | .flags = IORESOURCE_MEM, | ||
127 | }, | ||
128 | [1] = { | ||
129 | .start = MSP_INT_USB, | ||
130 | .end = MSP_INT_USB, | ||
131 | .flags = IORESOURCE_IRQ, | ||
132 | }, | ||
133 | [2] = { /* MSBus-to-AMBA bridge register space */ | ||
134 | .start = MSP_USB0_MAB_START, | ||
135 | .end = MSP_USB0_MAB_END, | ||
136 | .flags = IORESOURCE_MEM, | ||
137 | }, | ||
138 | [3] = { /* Identification and general hardware parameters */ | ||
139 | .start = MSP_USB0_ID_START, | ||
140 | .end = MSP_USB0_ID_END, | ||
141 | .flags = IORESOURCE_MEM, | ||
142 | }, | ||
143 | }; | ||
81 | 144 | ||
82 | static struct platform_device msp_usbdev_device = { | 145 | static u64 msp_usbdev_dma_mask = 0xffffffffUL; |
83 | .name = "msp71xx_udc", | 146 | |
84 | .id = 0, | 147 | /* This may need to be converted to a mspusb_device, too. */ |
148 | static struct mspusb_device msp_usbdev0_device = { | ||
85 | .dev = { | 149 | .dev = { |
86 | .dma_mask = &msp_usbdev_dma_mask, | 150 | .name = "msp71xx_udc", |
87 | .coherent_dma_mask = DMA_BIT_MASK(32), | 151 | .id = 0, |
152 | .dev = { | ||
153 | .dma_mask = &msp_usbdev_dma_mask, | ||
154 | .coherent_dma_mask = 0xffffffffUL, | ||
155 | }, | ||
156 | .num_resources = ARRAY_SIZE(msp_usbdev0_resources), | ||
157 | .resource = msp_usbdev0_resources, | ||
88 | }, | 158 | }, |
89 | .num_resources = ARRAY_SIZE(msp_usbdev_resources), | ||
90 | .resource = msp_usbdev_resources, | ||
91 | }; | 159 | }; |
92 | #endif /* CONFIG_USB_GADGET */ | ||
93 | 160 | ||
94 | #if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_GADGET) | 161 | #ifdef CONFIG_MSP_HAS_DUAL_USB |
95 | static struct platform_device *msp_devs[1]; | 162 | static struct resource msp_usbdev1_resources[] = { |
96 | #endif | 163 | [0] = { /* EHCI-HS operational and capabilities registers */ |
164 | .start = MSP_USB1_HS_START, | ||
165 | .end = MSP_USB1_HS_END, | ||
166 | .flags = IORESOURCE_MEM, | ||
167 | }, | ||
168 | [1] = { | ||
169 | .start = MSP_INT_USB, | ||
170 | .end = MSP_INT_USB, | ||
171 | .flags = IORESOURCE_IRQ, | ||
172 | }, | ||
173 | [2] = { /* MSBus-to-AMBA bridge register space */ | ||
174 | .start = MSP_USB1_MAB_START, | ||
175 | .end = MSP_USB1_MAB_END, | ||
176 | .flags = IORESOURCE_MEM, | ||
177 | }, | ||
178 | [3] = { /* Identification and general hardware parameters */ | ||
179 | .start = MSP_USB1_ID_START, | ||
180 | .end = MSP_USB1_ID_END, | ||
181 | .flags = IORESOURCE_MEM, | ||
182 | }, | ||
183 | }; | ||
97 | 184 | ||
185 | /* This may need to be converted to a mspusb_device, too. */ | ||
186 | static struct mspusb_device msp_usbdev1_device = { | ||
187 | .dev = { | ||
188 | .name = "msp71xx_udc", | ||
189 | .id = 0, | ||
190 | .dev = { | ||
191 | .dma_mask = &msp_usbdev_dma_mask, | ||
192 | .coherent_dma_mask = 0xffffffffUL, | ||
193 | }, | ||
194 | .num_resources = ARRAY_SIZE(msp_usbdev1_resources), | ||
195 | .resource = msp_usbdev1_resources, | ||
196 | }, | ||
197 | }; | ||
198 | |||
199 | #endif /* CONFIG_MSP_HAS_DUAL_USB */ | ||
200 | #endif /* CONFIG_USB_GADGET */ | ||
98 | 201 | ||
99 | static int __init msp_usb_setup(void) | 202 | static int __init msp_usb_setup(void) |
100 | { | 203 | { |
101 | #if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_GADGET) | 204 | char *strp; |
102 | char *strp; | 205 | char envstr[32]; |
103 | char envstr[32]; | 206 | struct platform_device *msp_devs[NUM_USB_DEVS]; |
104 | unsigned int val = 0; | 207 | unsigned int val; |
105 | int result = 0; | ||
106 | 208 | ||
209 | /* construct environment name usbmode */ | ||
210 | /* set usbmode <host/device> as pmon environment var */ | ||
107 | /* | 211 | /* |
108 | * construct environment name usbmode | 212 | * Could this perhaps be integrated into the "features" env var? |
109 | * set usbmode <host/device> as pmon environment var | 213 | * Use the features key "U", and follow with "H" for host-mode, |
214 | * "D" for device-mode. If it works for Ethernet, why not USB... | ||
215 | * -- hammtrev, 2007/03/22 | ||
110 | */ | 216 | */ |
111 | snprintf((char *)&envstr[0], sizeof(envstr), "usbmode"); | 217 | snprintf((char *)&envstr[0], sizeof(envstr), "usbmode"); |
112 | 218 | ||
113 | #if defined(CONFIG_USB_EHCI_HCD) | 219 | /* set default host mode */ |
114 | /* default to host mode */ | ||
115 | val = 1; | 220 | val = 1; |
116 | #endif | ||
117 | 221 | ||
118 | /* get environment string */ | 222 | /* get environment string */ |
119 | strp = prom_getenv((char *)&envstr[0]); | 223 | strp = prom_getenv((char *)&envstr[0]); |
120 | if (strp) { | 224 | if (strp) { |
225 | /* compare string */ | ||
121 | if (!strcmp(strp, "device")) | 226 | if (!strcmp(strp, "device")) |
122 | val = 0; | 227 | val = 0; |
123 | } | 228 | } |
124 | 229 | ||
125 | if (val) { | 230 | if (val) { |
126 | #if defined(CONFIG_USB_EHCI_HCD) | 231 | #if defined(CONFIG_USB_EHCI_HCD) |
127 | /* get host mode device */ | 232 | msp_devs[0] = &msp_usbhost0_device.dev; |
128 | msp_devs[0] = &msp_usbhost_device; | 233 | ppfinit("platform add USB HOST done %s.\n", msp_devs[0]->name); |
129 | ppfinit("platform add USB HOST done %s.\n", | 234 | #ifdef CONFIG_MSP_HAS_DUAL_USB |
130 | msp_devs[0]->name); | 235 | msp_devs[1] = &msp_usbhost1_device.dev; |
131 | 236 | ppfinit("platform add USB HOST done %s.\n", msp_devs[1]->name); | |
132 | result = platform_add_devices(msp_devs, ARRAY_SIZE(msp_devs)); | 237 | #endif |
133 | #endif /* CONFIG_USB_EHCI_HCD */ | 238 | #else |
134 | } | 239 | ppfinit("%s: echi_hcd not supported\n", __FILE__); |
240 | #endif /* CONFIG_USB_EHCI_HCD */ | ||
241 | } else { | ||
135 | #if defined(CONFIG_USB_GADGET) | 242 | #if defined(CONFIG_USB_GADGET) |
136 | else { | ||
137 | /* get device mode structure */ | 243 | /* get device mode structure */ |
138 | msp_devs[0] = &msp_usbdev_device; | 244 | msp_devs[0] = &msp_usbdev0_device.dev; |
139 | ppfinit("platform add USB DEVICE done %s.\n", | 245 | ppfinit("platform add USB DEVICE done %s.\n" |
140 | msp_devs[0]->name); | 246 | , msp_devs[0]->name); |
141 | 247 | #ifdef CONFIG_MSP_HAS_DUAL_USB | |
142 | result = platform_add_devices(msp_devs, ARRAY_SIZE(msp_devs)); | 248 | msp_devs[1] = &msp_usbdev1_device.dev; |
249 | ppfinit("platform add USB DEVICE done %s.\n" | ||
250 | , msp_devs[1]->name); | ||
251 | #endif | ||
252 | #else | ||
253 | ppfinit("%s: usb_gadget not supported\n", __FILE__); | ||
254 | #endif /* CONFIG_USB_GADGET */ | ||
143 | } | 255 | } |
144 | #endif /* CONFIG_USB_GADGET */ | 256 | /* add device */ |
145 | #endif /* CONFIG_USB_EHCI_HCD || CONFIG_USB_GADGET */ | 257 | platform_add_devices(msp_devs, ARRAY_SIZE(msp_devs)); |
146 | 258 | ||
147 | return result; | 259 | return 0; |
148 | } | 260 | } |
149 | 261 | ||
150 | subsys_initcall(msp_usb_setup); | 262 | subsys_initcall(msp_usb_setup); |
263 | #endif /* CONFIG_USB_EHCI_HCD || CONFIG_USB_GADGET */ | ||
diff --git a/arch/mips/pnx833x/common/interrupts.c b/arch/mips/pnx833x/common/interrupts.c index 941916f8aaff..b226bcb0a2f4 100644 --- a/arch/mips/pnx833x/common/interrupts.c +++ b/arch/mips/pnx833x/common/interrupts.c | |||
@@ -152,10 +152,6 @@ static inline void pnx833x_hard_disable_pic_irq(unsigned int irq) | |||
152 | PNX833X_PIC_INT_REG(irq) = 0; | 152 | PNX833X_PIC_INT_REG(irq) = 0; |
153 | } | 153 | } |
154 | 154 | ||
155 | static int irqflags[PNX833X_PIC_NUM_IRQ]; /* initialized by zeroes */ | ||
156 | #define IRQFLAG_STARTED 1 | ||
157 | #define IRQFLAG_DISABLED 2 | ||
158 | |||
159 | static DEFINE_RAW_SPINLOCK(pnx833x_irq_lock); | 155 | static DEFINE_RAW_SPINLOCK(pnx833x_irq_lock); |
160 | 156 | ||
161 | static unsigned int pnx833x_startup_pic_irq(unsigned int irq) | 157 | static unsigned int pnx833x_startup_pic_irq(unsigned int irq) |
@@ -164,108 +160,54 @@ static unsigned int pnx833x_startup_pic_irq(unsigned int irq) | |||
164 | unsigned int pic_irq = irq - PNX833X_PIC_IRQ_BASE; | 160 | unsigned int pic_irq = irq - PNX833X_PIC_IRQ_BASE; |
165 | 161 | ||
166 | raw_spin_lock_irqsave(&pnx833x_irq_lock, flags); | 162 | raw_spin_lock_irqsave(&pnx833x_irq_lock, flags); |
167 | |||
168 | irqflags[pic_irq] = IRQFLAG_STARTED; /* started, not disabled */ | ||
169 | pnx833x_hard_enable_pic_irq(pic_irq); | 163 | pnx833x_hard_enable_pic_irq(pic_irq); |
170 | |||
171 | raw_spin_unlock_irqrestore(&pnx833x_irq_lock, flags); | 164 | raw_spin_unlock_irqrestore(&pnx833x_irq_lock, flags); |
172 | return 0; | 165 | return 0; |
173 | } | 166 | } |
174 | 167 | ||
175 | static void pnx833x_shutdown_pic_irq(unsigned int irq) | 168 | static void pnx833x_enable_pic_irq(struct irq_data *d) |
176 | { | ||
177 | unsigned long flags; | ||
178 | unsigned int pic_irq = irq - PNX833X_PIC_IRQ_BASE; | ||
179 | |||
180 | raw_spin_lock_irqsave(&pnx833x_irq_lock, flags); | ||
181 | |||
182 | irqflags[pic_irq] = 0; /* not started */ | ||
183 | pnx833x_hard_disable_pic_irq(pic_irq); | ||
184 | |||
185 | raw_spin_unlock_irqrestore(&pnx833x_irq_lock, flags); | ||
186 | } | ||
187 | |||
188 | static void pnx833x_enable_pic_irq(unsigned int irq) | ||
189 | { | 169 | { |
190 | unsigned long flags; | 170 | unsigned long flags; |
191 | unsigned int pic_irq = irq - PNX833X_PIC_IRQ_BASE; | 171 | unsigned int pic_irq = d->irq - PNX833X_PIC_IRQ_BASE; |
192 | 172 | ||
193 | raw_spin_lock_irqsave(&pnx833x_irq_lock, flags); | 173 | raw_spin_lock_irqsave(&pnx833x_irq_lock, flags); |
194 | 174 | pnx833x_hard_enable_pic_irq(pic_irq); | |
195 | irqflags[pic_irq] &= ~IRQFLAG_DISABLED; | ||
196 | if (irqflags[pic_irq] == IRQFLAG_STARTED) | ||
197 | pnx833x_hard_enable_pic_irq(pic_irq); | ||
198 | |||
199 | raw_spin_unlock_irqrestore(&pnx833x_irq_lock, flags); | 175 | raw_spin_unlock_irqrestore(&pnx833x_irq_lock, flags); |
200 | } | 176 | } |
201 | 177 | ||
202 | static void pnx833x_disable_pic_irq(unsigned int irq) | 178 | static void pnx833x_disable_pic_irq(struct irq_data *d) |
203 | { | 179 | { |
204 | unsigned long flags; | 180 | unsigned long flags; |
205 | unsigned int pic_irq = irq - PNX833X_PIC_IRQ_BASE; | 181 | unsigned int pic_irq = d->irq - PNX833X_PIC_IRQ_BASE; |
206 | 182 | ||
207 | raw_spin_lock_irqsave(&pnx833x_irq_lock, flags); | 183 | raw_spin_lock_irqsave(&pnx833x_irq_lock, flags); |
208 | |||
209 | irqflags[pic_irq] |= IRQFLAG_DISABLED; | ||
210 | pnx833x_hard_disable_pic_irq(pic_irq); | 184 | pnx833x_hard_disable_pic_irq(pic_irq); |
211 | |||
212 | raw_spin_unlock_irqrestore(&pnx833x_irq_lock, flags); | 185 | raw_spin_unlock_irqrestore(&pnx833x_irq_lock, flags); |
213 | } | 186 | } |
214 | 187 | ||
215 | static void pnx833x_ack_pic_irq(unsigned int irq) | ||
216 | { | ||
217 | } | ||
218 | |||
219 | static void pnx833x_end_pic_irq(unsigned int irq) | ||
220 | { | ||
221 | } | ||
222 | |||
223 | static DEFINE_RAW_SPINLOCK(pnx833x_gpio_pnx833x_irq_lock); | 188 | static DEFINE_RAW_SPINLOCK(pnx833x_gpio_pnx833x_irq_lock); |
224 | 189 | ||
225 | static unsigned int pnx833x_startup_gpio_irq(unsigned int irq) | 190 | static void pnx833x_enable_gpio_irq(struct irq_data *d) |
226 | { | ||
227 | int pin = irq - PNX833X_GPIO_IRQ_BASE; | ||
228 | unsigned long flags; | ||
229 | raw_spin_lock_irqsave(&pnx833x_gpio_pnx833x_irq_lock, flags); | ||
230 | pnx833x_gpio_enable_irq(pin); | ||
231 | raw_spin_unlock_irqrestore(&pnx833x_gpio_pnx833x_irq_lock, flags); | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | static void pnx833x_enable_gpio_irq(unsigned int irq) | ||
236 | { | 191 | { |
237 | int pin = irq - PNX833X_GPIO_IRQ_BASE; | 192 | int pin = d->irq - PNX833X_GPIO_IRQ_BASE; |
238 | unsigned long flags; | 193 | unsigned long flags; |
239 | raw_spin_lock_irqsave(&pnx833x_gpio_pnx833x_irq_lock, flags); | 194 | raw_spin_lock_irqsave(&pnx833x_gpio_pnx833x_irq_lock, flags); |
240 | pnx833x_gpio_enable_irq(pin); | 195 | pnx833x_gpio_enable_irq(pin); |
241 | raw_spin_unlock_irqrestore(&pnx833x_gpio_pnx833x_irq_lock, flags); | 196 | raw_spin_unlock_irqrestore(&pnx833x_gpio_pnx833x_irq_lock, flags); |
242 | } | 197 | } |
243 | 198 | ||
244 | static void pnx833x_disable_gpio_irq(unsigned int irq) | 199 | static void pnx833x_disable_gpio_irq(struct irq_data *d) |
245 | { | 200 | { |
246 | int pin = irq - PNX833X_GPIO_IRQ_BASE; | 201 | int pin = d->irq - PNX833X_GPIO_IRQ_BASE; |
247 | unsigned long flags; | 202 | unsigned long flags; |
248 | raw_spin_lock_irqsave(&pnx833x_gpio_pnx833x_irq_lock, flags); | 203 | raw_spin_lock_irqsave(&pnx833x_gpio_pnx833x_irq_lock, flags); |
249 | pnx833x_gpio_disable_irq(pin); | 204 | pnx833x_gpio_disable_irq(pin); |
250 | raw_spin_unlock_irqrestore(&pnx833x_gpio_pnx833x_irq_lock, flags); | 205 | raw_spin_unlock_irqrestore(&pnx833x_gpio_pnx833x_irq_lock, flags); |
251 | } | 206 | } |
252 | 207 | ||
253 | static void pnx833x_ack_gpio_irq(unsigned int irq) | 208 | static int pnx833x_set_type_gpio_irq(struct irq_data *d, unsigned int flow_type) |
254 | { | ||
255 | } | ||
256 | |||
257 | static void pnx833x_end_gpio_irq(unsigned int irq) | ||
258 | { | ||
259 | int pin = irq - PNX833X_GPIO_IRQ_BASE; | ||
260 | unsigned long flags; | ||
261 | raw_spin_lock_irqsave(&pnx833x_gpio_pnx833x_irq_lock, flags); | ||
262 | pnx833x_gpio_clear_irq(pin); | ||
263 | raw_spin_unlock_irqrestore(&pnx833x_gpio_pnx833x_irq_lock, flags); | ||
264 | } | ||
265 | |||
266 | static int pnx833x_set_type_gpio_irq(unsigned int irq, unsigned int flow_type) | ||
267 | { | 209 | { |
268 | int pin = irq - PNX833X_GPIO_IRQ_BASE; | 210 | int pin = d->irq - PNX833X_GPIO_IRQ_BASE; |
269 | int gpio_mode; | 211 | int gpio_mode; |
270 | 212 | ||
271 | switch (flow_type) { | 213 | switch (flow_type) { |
@@ -296,23 +238,15 @@ static int pnx833x_set_type_gpio_irq(unsigned int irq, unsigned int flow_type) | |||
296 | 238 | ||
297 | static struct irq_chip pnx833x_pic_irq_type = { | 239 | static struct irq_chip pnx833x_pic_irq_type = { |
298 | .name = "PNX-PIC", | 240 | .name = "PNX-PIC", |
299 | .startup = pnx833x_startup_pic_irq, | 241 | .irq_enable = pnx833x_enable_pic_irq, |
300 | .shutdown = pnx833x_shutdown_pic_irq, | 242 | .irq_disable = pnx833x_disable_pic_irq, |
301 | .enable = pnx833x_enable_pic_irq, | ||
302 | .disable = pnx833x_disable_pic_irq, | ||
303 | .ack = pnx833x_ack_pic_irq, | ||
304 | .end = pnx833x_end_pic_irq | ||
305 | }; | 243 | }; |
306 | 244 | ||
307 | static struct irq_chip pnx833x_gpio_irq_type = { | 245 | static struct irq_chip pnx833x_gpio_irq_type = { |
308 | .name = "PNX-GPIO", | 246 | .name = "PNX-GPIO", |
309 | .startup = pnx833x_startup_gpio_irq, | 247 | .irq_enable = pnx833x_enable_gpio_irq, |
310 | .shutdown = pnx833x_disable_gpio_irq, | 248 | .irq_disable = pnx833x_disable_gpio_irq, |
311 | .enable = pnx833x_enable_gpio_irq, | 249 | .irq_set_type = pnx833x_set_type_gpio_irq, |
312 | .disable = pnx833x_disable_gpio_irq, | ||
313 | .ack = pnx833x_ack_gpio_irq, | ||
314 | .end = pnx833x_end_gpio_irq, | ||
315 | .set_type = pnx833x_set_type_gpio_irq | ||
316 | }; | 250 | }; |
317 | 251 | ||
318 | void __init arch_init_irq(void) | 252 | void __init arch_init_irq(void) |
diff --git a/arch/mips/pnx8550/common/int.c b/arch/mips/pnx8550/common/int.c index cfed5051dc6d..dbdc35c3531d 100644 --- a/arch/mips/pnx8550/common/int.c +++ b/arch/mips/pnx8550/common/int.c | |||
@@ -114,8 +114,10 @@ static inline void unmask_gic_int(unsigned int irq_nr) | |||
114 | PNX8550_GIC_REQ(irq_nr) = (1<<26 | 1<<16) | (1<<28) | gic_prio[irq_nr]; | 114 | PNX8550_GIC_REQ(irq_nr) = (1<<26 | 1<<16) | (1<<28) | gic_prio[irq_nr]; |
115 | } | 115 | } |
116 | 116 | ||
117 | static inline void mask_irq(unsigned int irq_nr) | 117 | static inline void mask_irq(struct irq_data *d) |
118 | { | 118 | { |
119 | unsigned int irq_nr = d->irq; | ||
120 | |||
119 | if ((PNX8550_INT_CP0_MIN <= irq_nr) && (irq_nr <= PNX8550_INT_CP0_MAX)) { | 121 | if ((PNX8550_INT_CP0_MIN <= irq_nr) && (irq_nr <= PNX8550_INT_CP0_MAX)) { |
120 | modify_cp0_intmask(1 << irq_nr, 0); | 122 | modify_cp0_intmask(1 << irq_nr, 0); |
121 | } else if ((PNX8550_INT_GIC_MIN <= irq_nr) && | 123 | } else if ((PNX8550_INT_GIC_MIN <= irq_nr) && |
@@ -129,8 +131,10 @@ static inline void mask_irq(unsigned int irq_nr) | |||
129 | } | 131 | } |
130 | } | 132 | } |
131 | 133 | ||
132 | static inline void unmask_irq(unsigned int irq_nr) | 134 | static inline void unmask_irq(struct irq_data *d) |
133 | { | 135 | { |
136 | unsigned int irq_nr = d->irq; | ||
137 | |||
134 | if ((PNX8550_INT_CP0_MIN <= irq_nr) && (irq_nr <= PNX8550_INT_CP0_MAX)) { | 138 | if ((PNX8550_INT_CP0_MIN <= irq_nr) && (irq_nr <= PNX8550_INT_CP0_MAX)) { |
135 | modify_cp0_intmask(0, 1 << irq_nr); | 139 | modify_cp0_intmask(0, 1 << irq_nr); |
136 | } else if ((PNX8550_INT_GIC_MIN <= irq_nr) && | 140 | } else if ((PNX8550_INT_GIC_MIN <= irq_nr) && |
@@ -157,10 +161,8 @@ int pnx8550_set_gic_priority(int irq, int priority) | |||
157 | 161 | ||
158 | static struct irq_chip level_irq_type = { | 162 | static struct irq_chip level_irq_type = { |
159 | .name = "PNX Level IRQ", | 163 | .name = "PNX Level IRQ", |
160 | .ack = mask_irq, | 164 | .irq_mask = mask_irq, |
161 | .mask = mask_irq, | 165 | .irq_unmask = unmask_irq, |
162 | .mask_ack = mask_irq, | ||
163 | .unmask = unmask_irq, | ||
164 | }; | 166 | }; |
165 | 167 | ||
166 | static struct irqaction gic_action = { | 168 | static struct irqaction gic_action = { |
@@ -180,10 +182,8 @@ void __init arch_init_irq(void) | |||
180 | int i; | 182 | int i; |
181 | int configPR; | 183 | int configPR; |
182 | 184 | ||
183 | for (i = 0; i < PNX8550_INT_CP0_TOTINT; i++) { | 185 | for (i = 0; i < PNX8550_INT_CP0_TOTINT; i++) |
184 | set_irq_chip_and_handler(i, &level_irq_type, handle_level_irq); | 186 | set_irq_chip_and_handler(i, &level_irq_type, handle_level_irq); |
185 | mask_irq(i); /* mask the irq just in case */ | ||
186 | } | ||
187 | 187 | ||
188 | /* init of GIC/IPC interrupts */ | 188 | /* init of GIC/IPC interrupts */ |
189 | /* should be done before cp0 since cp0 init enables the GIC int */ | 189 | /* should be done before cp0 since cp0 init enables the GIC int */ |
diff --git a/arch/mips/powertv/asic/irq_asic.c b/arch/mips/powertv/asic/irq_asic.c index e55382434155..6f1c8ef6a719 100644 --- a/arch/mips/powertv/asic/irq_asic.c +++ b/arch/mips/powertv/asic/irq_asic.c | |||
@@ -21,9 +21,10 @@ | |||
21 | 21 | ||
22 | #include <asm/mach-powertv/asic_regs.h> | 22 | #include <asm/mach-powertv/asic_regs.h> |
23 | 23 | ||
24 | static inline void unmask_asic_irq(unsigned int irq) | 24 | static inline void unmask_asic_irq(struct irq_data *d) |
25 | { | 25 | { |
26 | unsigned long enable_bit; | 26 | unsigned long enable_bit; |
27 | unsigned int irq = d->irq; | ||
27 | 28 | ||
28 | enable_bit = (1 << (irq & 0x1f)); | 29 | enable_bit = (1 << (irq & 0x1f)); |
29 | 30 | ||
@@ -45,9 +46,10 @@ static inline void unmask_asic_irq(unsigned int irq) | |||
45 | } | 46 | } |
46 | } | 47 | } |
47 | 48 | ||
48 | static inline void mask_asic_irq(unsigned int irq) | 49 | static inline void mask_asic_irq(struct irq_data *d) |
49 | { | 50 | { |
50 | unsigned long disable_mask; | 51 | unsigned long disable_mask; |
52 | unsigned int irq = d->irq; | ||
51 | 53 | ||
52 | disable_mask = ~(1 << (irq & 0x1f)); | 54 | disable_mask = ~(1 << (irq & 0x1f)); |
53 | 55 | ||
@@ -71,11 +73,8 @@ static inline void mask_asic_irq(unsigned int irq) | |||
71 | 73 | ||
72 | static struct irq_chip asic_irq_chip = { | 74 | static struct irq_chip asic_irq_chip = { |
73 | .name = "ASIC Level", | 75 | .name = "ASIC Level", |
74 | .ack = mask_asic_irq, | 76 | .irq_mask = mask_asic_irq, |
75 | .mask = mask_asic_irq, | 77 | .irq_unmask = unmask_asic_irq, |
76 | .mask_ack = mask_asic_irq, | ||
77 | .unmask = unmask_asic_irq, | ||
78 | .eoi = unmask_asic_irq, | ||
79 | }; | 78 | }; |
80 | 79 | ||
81 | void __init asic_irq_init(void) | 80 | void __init asic_irq_init(void) |
diff --git a/arch/mips/rb532/irq.c b/arch/mips/rb532/irq.c index ea6cec3c1e0d..b32a768da894 100644 --- a/arch/mips/rb532/irq.c +++ b/arch/mips/rb532/irq.c | |||
@@ -111,10 +111,10 @@ static inline void ack_local_irq(unsigned int ip) | |||
111 | clear_c0_cause(ipnum); | 111 | clear_c0_cause(ipnum); |
112 | } | 112 | } |
113 | 113 | ||
114 | static void rb532_enable_irq(unsigned int irq_nr) | 114 | static void rb532_enable_irq(struct irq_data *d) |
115 | { | 115 | { |
116 | unsigned int group, intr_bit, irq_nr = d->irq; | ||
116 | int ip = irq_nr - GROUP0_IRQ_BASE; | 117 | int ip = irq_nr - GROUP0_IRQ_BASE; |
117 | unsigned int group, intr_bit; | ||
118 | volatile unsigned int *addr; | 118 | volatile unsigned int *addr; |
119 | 119 | ||
120 | if (ip < 0) | 120 | if (ip < 0) |
@@ -132,10 +132,10 @@ static void rb532_enable_irq(unsigned int irq_nr) | |||
132 | } | 132 | } |
133 | } | 133 | } |
134 | 134 | ||
135 | static void rb532_disable_irq(unsigned int irq_nr) | 135 | static void rb532_disable_irq(struct irq_data *d) |
136 | { | 136 | { |
137 | unsigned int group, intr_bit, mask, irq_nr = d->irq; | ||
137 | int ip = irq_nr - GROUP0_IRQ_BASE; | 138 | int ip = irq_nr - GROUP0_IRQ_BASE; |
138 | unsigned int group, intr_bit, mask; | ||
139 | volatile unsigned int *addr; | 139 | volatile unsigned int *addr; |
140 | 140 | ||
141 | if (ip < 0) { | 141 | if (ip < 0) { |
@@ -163,18 +163,18 @@ static void rb532_disable_irq(unsigned int irq_nr) | |||
163 | } | 163 | } |
164 | } | 164 | } |
165 | 165 | ||
166 | static void rb532_mask_and_ack_irq(unsigned int irq_nr) | 166 | static void rb532_mask_and_ack_irq(struct irq_data *d) |
167 | { | 167 | { |
168 | rb532_disable_irq(irq_nr); | 168 | rb532_disable_irq(d); |
169 | ack_local_irq(group_to_ip(irq_to_group(irq_nr))); | 169 | ack_local_irq(group_to_ip(irq_to_group(d->irq))); |
170 | } | 170 | } |
171 | 171 | ||
172 | static int rb532_set_type(unsigned int irq_nr, unsigned type) | 172 | static int rb532_set_type(struct irq_data *d, unsigned type) |
173 | { | 173 | { |
174 | int gpio = irq_nr - GPIO_MAPPED_IRQ_BASE; | 174 | int gpio = d->irq - GPIO_MAPPED_IRQ_BASE; |
175 | int group = irq_to_group(irq_nr); | 175 | int group = irq_to_group(d->irq); |
176 | 176 | ||
177 | if (group != GPIO_MAPPED_IRQ_GROUP || irq_nr > (GROUP4_IRQ_BASE + 13)) | 177 | if (group != GPIO_MAPPED_IRQ_GROUP || d->irq > (GROUP4_IRQ_BASE + 13)) |
178 | return (type == IRQ_TYPE_LEVEL_HIGH) ? 0 : -EINVAL; | 178 | return (type == IRQ_TYPE_LEVEL_HIGH) ? 0 : -EINVAL; |
179 | 179 | ||
180 | switch (type) { | 180 | switch (type) { |
@@ -193,11 +193,11 @@ static int rb532_set_type(unsigned int irq_nr, unsigned type) | |||
193 | 193 | ||
194 | static struct irq_chip rc32434_irq_type = { | 194 | static struct irq_chip rc32434_irq_type = { |
195 | .name = "RB532", | 195 | .name = "RB532", |
196 | .ack = rb532_disable_irq, | 196 | .irq_ack = rb532_disable_irq, |
197 | .mask = rb532_disable_irq, | 197 | .irq_mask = rb532_disable_irq, |
198 | .mask_ack = rb532_mask_and_ack_irq, | 198 | .irq_mask_ack = rb532_mask_and_ack_irq, |
199 | .unmask = rb532_enable_irq, | 199 | .irq_unmask = rb532_enable_irq, |
200 | .set_type = rb532_set_type, | 200 | .irq_set_type = rb532_set_type, |
201 | }; | 201 | }; |
202 | 202 | ||
203 | void __init arch_init_irq(void) | 203 | void __init arch_init_irq(void) |
diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c index 383f11d7f442..e6e64750e90a 100644 --- a/arch/mips/sgi-ip22/ip22-int.c +++ b/arch/mips/sgi-ip22/ip22-int.c | |||
@@ -31,88 +31,80 @@ static char lc3msk_to_irqnr[256]; | |||
31 | 31 | ||
32 | extern int ip22_eisa_init(void); | 32 | extern int ip22_eisa_init(void); |
33 | 33 | ||
34 | static void enable_local0_irq(unsigned int irq) | 34 | static void enable_local0_irq(struct irq_data *d) |
35 | { | 35 | { |
36 | /* don't allow mappable interrupt to be enabled from setup_irq, | 36 | /* don't allow mappable interrupt to be enabled from setup_irq, |
37 | * we have our own way to do so */ | 37 | * we have our own way to do so */ |
38 | if (irq != SGI_MAP_0_IRQ) | 38 | if (d->irq != SGI_MAP_0_IRQ) |
39 | sgint->imask0 |= (1 << (irq - SGINT_LOCAL0)); | 39 | sgint->imask0 |= (1 << (d->irq - SGINT_LOCAL0)); |
40 | } | 40 | } |
41 | 41 | ||
42 | static void disable_local0_irq(unsigned int irq) | 42 | static void disable_local0_irq(struct irq_data *d) |
43 | { | 43 | { |
44 | sgint->imask0 &= ~(1 << (irq - SGINT_LOCAL0)); | 44 | sgint->imask0 &= ~(1 << (d->irq - SGINT_LOCAL0)); |
45 | } | 45 | } |
46 | 46 | ||
47 | static struct irq_chip ip22_local0_irq_type = { | 47 | static struct irq_chip ip22_local0_irq_type = { |
48 | .name = "IP22 local 0", | 48 | .name = "IP22 local 0", |
49 | .ack = disable_local0_irq, | 49 | .irq_mask = disable_local0_irq, |
50 | .mask = disable_local0_irq, | 50 | .irq_unmask = enable_local0_irq, |
51 | .mask_ack = disable_local0_irq, | ||
52 | .unmask = enable_local0_irq, | ||
53 | }; | 51 | }; |
54 | 52 | ||
55 | static void enable_local1_irq(unsigned int irq) | 53 | static void enable_local1_irq(struct irq_data *d) |
56 | { | 54 | { |
57 | /* don't allow mappable interrupt to be enabled from setup_irq, | 55 | /* don't allow mappable interrupt to be enabled from setup_irq, |
58 | * we have our own way to do so */ | 56 | * we have our own way to do so */ |
59 | if (irq != SGI_MAP_1_IRQ) | 57 | if (d->irq != SGI_MAP_1_IRQ) |
60 | sgint->imask1 |= (1 << (irq - SGINT_LOCAL1)); | 58 | sgint->imask1 |= (1 << (d->irq - SGINT_LOCAL1)); |
61 | } | 59 | } |
62 | 60 | ||
63 | static void disable_local1_irq(unsigned int irq) | 61 | static void disable_local1_irq(struct irq_data *d) |
64 | { | 62 | { |
65 | sgint->imask1 &= ~(1 << (irq - SGINT_LOCAL1)); | 63 | sgint->imask1 &= ~(1 << (d->irq - SGINT_LOCAL1)); |
66 | } | 64 | } |
67 | 65 | ||
68 | static struct irq_chip ip22_local1_irq_type = { | 66 | static struct irq_chip ip22_local1_irq_type = { |
69 | .name = "IP22 local 1", | 67 | .name = "IP22 local 1", |
70 | .ack = disable_local1_irq, | 68 | .irq_mask = disable_local1_irq, |
71 | .mask = disable_local1_irq, | 69 | .irq_unmask = enable_local1_irq, |
72 | .mask_ack = disable_local1_irq, | ||
73 | .unmask = enable_local1_irq, | ||
74 | }; | 70 | }; |
75 | 71 | ||
76 | static void enable_local2_irq(unsigned int irq) | 72 | static void enable_local2_irq(struct irq_data *d) |
77 | { | 73 | { |
78 | sgint->imask0 |= (1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0)); | 74 | sgint->imask0 |= (1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0)); |
79 | sgint->cmeimask0 |= (1 << (irq - SGINT_LOCAL2)); | 75 | sgint->cmeimask0 |= (1 << (d->irq - SGINT_LOCAL2)); |
80 | } | 76 | } |
81 | 77 | ||
82 | static void disable_local2_irq(unsigned int irq) | 78 | static void disable_local2_irq(struct irq_data *d) |
83 | { | 79 | { |
84 | sgint->cmeimask0 &= ~(1 << (irq - SGINT_LOCAL2)); | 80 | sgint->cmeimask0 &= ~(1 << (d->irq - SGINT_LOCAL2)); |
85 | if (!sgint->cmeimask0) | 81 | if (!sgint->cmeimask0) |
86 | sgint->imask0 &= ~(1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0)); | 82 | sgint->imask0 &= ~(1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0)); |
87 | } | 83 | } |
88 | 84 | ||
89 | static struct irq_chip ip22_local2_irq_type = { | 85 | static struct irq_chip ip22_local2_irq_type = { |
90 | .name = "IP22 local 2", | 86 | .name = "IP22 local 2", |
91 | .ack = disable_local2_irq, | 87 | .irq_mask = disable_local2_irq, |
92 | .mask = disable_local2_irq, | 88 | .irq_unmask = enable_local2_irq, |
93 | .mask_ack = disable_local2_irq, | ||
94 | .unmask = enable_local2_irq, | ||
95 | }; | 89 | }; |
96 | 90 | ||
97 | static void enable_local3_irq(unsigned int irq) | 91 | static void enable_local3_irq(struct irq_data *d) |
98 | { | 92 | { |
99 | sgint->imask1 |= (1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1)); | 93 | sgint->imask1 |= (1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1)); |
100 | sgint->cmeimask1 |= (1 << (irq - SGINT_LOCAL3)); | 94 | sgint->cmeimask1 |= (1 << (d->irq - SGINT_LOCAL3)); |
101 | } | 95 | } |
102 | 96 | ||
103 | static void disable_local3_irq(unsigned int irq) | 97 | static void disable_local3_irq(struct irq_data *d) |
104 | { | 98 | { |
105 | sgint->cmeimask1 &= ~(1 << (irq - SGINT_LOCAL3)); | 99 | sgint->cmeimask1 &= ~(1 << (d->irq - SGINT_LOCAL3)); |
106 | if (!sgint->cmeimask1) | 100 | if (!sgint->cmeimask1) |
107 | sgint->imask1 &= ~(1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1)); | 101 | sgint->imask1 &= ~(1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1)); |
108 | } | 102 | } |
109 | 103 | ||
110 | static struct irq_chip ip22_local3_irq_type = { | 104 | static struct irq_chip ip22_local3_irq_type = { |
111 | .name = "IP22 local 3", | 105 | .name = "IP22 local 3", |
112 | .ack = disable_local3_irq, | 106 | .irq_mask = disable_local3_irq, |
113 | .mask = disable_local3_irq, | 107 | .irq_unmask = enable_local3_irq, |
114 | .mask_ack = disable_local3_irq, | ||
115 | .unmask = enable_local3_irq, | ||
116 | }; | 108 | }; |
117 | 109 | ||
118 | static void indy_local0_irqdispatch(void) | 110 | static void indy_local0_irqdispatch(void) |
diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c index 6a123ea72de5..f2d09d7700dd 100644 --- a/arch/mips/sgi-ip27/ip27-irq.c +++ b/arch/mips/sgi-ip27/ip27-irq.c | |||
@@ -240,7 +240,7 @@ static int intr_disconnect_level(int cpu, int bit) | |||
240 | } | 240 | } |
241 | 241 | ||
242 | /* Startup one of the (PCI ...) IRQs routes over a bridge. */ | 242 | /* Startup one of the (PCI ...) IRQs routes over a bridge. */ |
243 | static unsigned int startup_bridge_irq(unsigned int irq) | 243 | static unsigned int startup_bridge_irq(struct irq_data *d) |
244 | { | 244 | { |
245 | struct bridge_controller *bc; | 245 | struct bridge_controller *bc; |
246 | bridgereg_t device; | 246 | bridgereg_t device; |
@@ -248,16 +248,16 @@ static unsigned int startup_bridge_irq(unsigned int irq) | |||
248 | int pin, swlevel; | 248 | int pin, swlevel; |
249 | cpuid_t cpu; | 249 | cpuid_t cpu; |
250 | 250 | ||
251 | pin = SLOT_FROM_PCI_IRQ(irq); | 251 | pin = SLOT_FROM_PCI_IRQ(d->irq); |
252 | bc = IRQ_TO_BRIDGE(irq); | 252 | bc = IRQ_TO_BRIDGE(d->irq); |
253 | bridge = bc->base; | 253 | bridge = bc->base; |
254 | 254 | ||
255 | pr_debug("bridge_startup(): irq= 0x%x pin=%d\n", irq, pin); | 255 | pr_debug("bridge_startup(): irq= 0x%x pin=%d\n", d->irq, pin); |
256 | /* | 256 | /* |
257 | * "map" irq to a swlevel greater than 6 since the first 6 bits | 257 | * "map" irq to a swlevel greater than 6 since the first 6 bits |
258 | * of INT_PEND0 are taken | 258 | * of INT_PEND0 are taken |
259 | */ | 259 | */ |
260 | swlevel = find_level(&cpu, irq); | 260 | swlevel = find_level(&cpu, d->irq); |
261 | bridge->b_int_addr[pin].addr = (0x20000 | swlevel | (bc->nasid << 8)); | 261 | bridge->b_int_addr[pin].addr = (0x20000 | swlevel | (bc->nasid << 8)); |
262 | bridge->b_int_enable |= (1 << pin); | 262 | bridge->b_int_enable |= (1 << pin); |
263 | bridge->b_int_enable |= 0x7ffffe00; /* more stuff in int_enable */ | 263 | bridge->b_int_enable |= 0x7ffffe00; /* more stuff in int_enable */ |
@@ -288,53 +288,51 @@ static unsigned int startup_bridge_irq(unsigned int irq) | |||
288 | } | 288 | } |
289 | 289 | ||
290 | /* Shutdown one of the (PCI ...) IRQs routes over a bridge. */ | 290 | /* Shutdown one of the (PCI ...) IRQs routes over a bridge. */ |
291 | static void shutdown_bridge_irq(unsigned int irq) | 291 | static void shutdown_bridge_irq(struct irq_data *d) |
292 | { | 292 | { |
293 | struct bridge_controller *bc = IRQ_TO_BRIDGE(irq); | 293 | struct bridge_controller *bc = IRQ_TO_BRIDGE(d->irq); |
294 | bridge_t *bridge = bc->base; | 294 | bridge_t *bridge = bc->base; |
295 | int pin, swlevel; | 295 | int pin, swlevel; |
296 | cpuid_t cpu; | 296 | cpuid_t cpu; |
297 | 297 | ||
298 | pr_debug("bridge_shutdown: irq 0x%x\n", irq); | 298 | pr_debug("bridge_shutdown: irq 0x%x\n", d->irq); |
299 | pin = SLOT_FROM_PCI_IRQ(irq); | 299 | pin = SLOT_FROM_PCI_IRQ(d->irq); |
300 | 300 | ||
301 | /* | 301 | /* |
302 | * map irq to a swlevel greater than 6 since the first 6 bits | 302 | * map irq to a swlevel greater than 6 since the first 6 bits |
303 | * of INT_PEND0 are taken | 303 | * of INT_PEND0 are taken |
304 | */ | 304 | */ |
305 | swlevel = find_level(&cpu, irq); | 305 | swlevel = find_level(&cpu, d->irq); |
306 | intr_disconnect_level(cpu, swlevel); | 306 | intr_disconnect_level(cpu, swlevel); |
307 | 307 | ||
308 | bridge->b_int_enable &= ~(1 << pin); | 308 | bridge->b_int_enable &= ~(1 << pin); |
309 | bridge->b_wid_tflush; | 309 | bridge->b_wid_tflush; |
310 | } | 310 | } |
311 | 311 | ||
312 | static inline void enable_bridge_irq(unsigned int irq) | 312 | static inline void enable_bridge_irq(struct irq_data *d) |
313 | { | 313 | { |
314 | cpuid_t cpu; | 314 | cpuid_t cpu; |
315 | int swlevel; | 315 | int swlevel; |
316 | 316 | ||
317 | swlevel = find_level(&cpu, irq); /* Criminal offence */ | 317 | swlevel = find_level(&cpu, d->irq); /* Criminal offence */ |
318 | intr_connect_level(cpu, swlevel); | 318 | intr_connect_level(cpu, swlevel); |
319 | } | 319 | } |
320 | 320 | ||
321 | static inline void disable_bridge_irq(unsigned int irq) | 321 | static inline void disable_bridge_irq(struct irq_data *d) |
322 | { | 322 | { |
323 | cpuid_t cpu; | 323 | cpuid_t cpu; |
324 | int swlevel; | 324 | int swlevel; |
325 | 325 | ||
326 | swlevel = find_level(&cpu, irq); /* Criminal offence */ | 326 | swlevel = find_level(&cpu, d->irq); /* Criminal offence */ |
327 | intr_disconnect_level(cpu, swlevel); | 327 | intr_disconnect_level(cpu, swlevel); |
328 | } | 328 | } |
329 | 329 | ||
330 | static struct irq_chip bridge_irq_type = { | 330 | static struct irq_chip bridge_irq_type = { |
331 | .name = "bridge", | 331 | .name = "bridge", |
332 | .startup = startup_bridge_irq, | 332 | .irq_startup = startup_bridge_irq, |
333 | .shutdown = shutdown_bridge_irq, | 333 | .irq_shutdown = shutdown_bridge_irq, |
334 | .ack = disable_bridge_irq, | 334 | .irq_mask = disable_bridge_irq, |
335 | .mask = disable_bridge_irq, | 335 | .irq_unmask = enable_bridge_irq, |
336 | .mask_ack = disable_bridge_irq, | ||
337 | .unmask = enable_bridge_irq, | ||
338 | }; | 336 | }; |
339 | 337 | ||
340 | void __devinit register_bridge_irq(unsigned int irq) | 338 | void __devinit register_bridge_irq(unsigned int irq) |
diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index d6802d6d1f82..c01f558a2a09 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c | |||
@@ -36,21 +36,18 @@ | |||
36 | #include <asm/sn/sn0/hubio.h> | 36 | #include <asm/sn/sn0/hubio.h> |
37 | #include <asm/pci/bridge.h> | 37 | #include <asm/pci/bridge.h> |
38 | 38 | ||
39 | static void enable_rt_irq(unsigned int irq) | 39 | static void enable_rt_irq(struct irq_data *d) |
40 | { | 40 | { |
41 | } | 41 | } |
42 | 42 | ||
43 | static void disable_rt_irq(unsigned int irq) | 43 | static void disable_rt_irq(struct irq_data *d) |
44 | { | 44 | { |
45 | } | 45 | } |
46 | 46 | ||
47 | static struct irq_chip rt_irq_type = { | 47 | static struct irq_chip rt_irq_type = { |
48 | .name = "SN HUB RT timer", | 48 | .name = "SN HUB RT timer", |
49 | .ack = disable_rt_irq, | 49 | .irq_mask = disable_rt_irq, |
50 | .mask = disable_rt_irq, | 50 | .irq_unmask = enable_rt_irq, |
51 | .mask_ack = disable_rt_irq, | ||
52 | .unmask = enable_rt_irq, | ||
53 | .eoi = enable_rt_irq, | ||
54 | }; | 51 | }; |
55 | 52 | ||
56 | static int rt_next_event(unsigned long delta, struct clock_event_device *evt) | 53 | static int rt_next_event(unsigned long delta, struct clock_event_device *evt) |
diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c index eb40824b172a..e0a3ce4a8d48 100644 --- a/arch/mips/sgi-ip32/ip32-irq.c +++ b/arch/mips/sgi-ip32/ip32-irq.c | |||
@@ -130,70 +130,48 @@ static struct irqaction cpuerr_irq = { | |||
130 | 130 | ||
131 | static uint64_t crime_mask; | 131 | static uint64_t crime_mask; |
132 | 132 | ||
133 | static inline void crime_enable_irq(unsigned int irq) | 133 | static inline void crime_enable_irq(struct irq_data *d) |
134 | { | 134 | { |
135 | unsigned int bit = irq - CRIME_IRQ_BASE; | 135 | unsigned int bit = d->irq - CRIME_IRQ_BASE; |
136 | 136 | ||
137 | crime_mask |= 1 << bit; | 137 | crime_mask |= 1 << bit; |
138 | crime->imask = crime_mask; | 138 | crime->imask = crime_mask; |
139 | } | 139 | } |
140 | 140 | ||
141 | static inline void crime_disable_irq(unsigned int irq) | 141 | static inline void crime_disable_irq(struct irq_data *d) |
142 | { | 142 | { |
143 | unsigned int bit = irq - CRIME_IRQ_BASE; | 143 | unsigned int bit = d->irq - CRIME_IRQ_BASE; |
144 | 144 | ||
145 | crime_mask &= ~(1 << bit); | 145 | crime_mask &= ~(1 << bit); |
146 | crime->imask = crime_mask; | 146 | crime->imask = crime_mask; |
147 | flush_crime_bus(); | 147 | flush_crime_bus(); |
148 | } | 148 | } |
149 | 149 | ||
150 | static void crime_level_mask_and_ack_irq(unsigned int irq) | ||
151 | { | ||
152 | crime_disable_irq(irq); | ||
153 | } | ||
154 | |||
155 | static void crime_level_end_irq(unsigned int irq) | ||
156 | { | ||
157 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | ||
158 | crime_enable_irq(irq); | ||
159 | } | ||
160 | |||
161 | static struct irq_chip crime_level_interrupt = { | 150 | static struct irq_chip crime_level_interrupt = { |
162 | .name = "IP32 CRIME", | 151 | .name = "IP32 CRIME", |
163 | .ack = crime_level_mask_and_ack_irq, | 152 | .irq_mask = crime_disable_irq, |
164 | .mask = crime_disable_irq, | 153 | .irq_unmask = crime_enable_irq, |
165 | .mask_ack = crime_level_mask_and_ack_irq, | ||
166 | .unmask = crime_enable_irq, | ||
167 | .end = crime_level_end_irq, | ||
168 | }; | 154 | }; |
169 | 155 | ||
170 | static void crime_edge_mask_and_ack_irq(unsigned int irq) | 156 | static void crime_edge_mask_and_ack_irq(struct irq_data *d) |
171 | { | 157 | { |
172 | unsigned int bit = irq - CRIME_IRQ_BASE; | 158 | unsigned int bit = d->irq - CRIME_IRQ_BASE; |
173 | uint64_t crime_int; | 159 | uint64_t crime_int; |
174 | 160 | ||
175 | /* Edge triggered interrupts must be cleared. */ | 161 | /* Edge triggered interrupts must be cleared. */ |
176 | |||
177 | crime_int = crime->hard_int; | 162 | crime_int = crime->hard_int; |
178 | crime_int &= ~(1 << bit); | 163 | crime_int &= ~(1 << bit); |
179 | crime->hard_int = crime_int; | 164 | crime->hard_int = crime_int; |
180 | 165 | ||
181 | crime_disable_irq(irq); | 166 | crime_disable_irq(d); |
182 | } | ||
183 | |||
184 | static void crime_edge_end_irq(unsigned int irq) | ||
185 | { | ||
186 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | ||
187 | crime_enable_irq(irq); | ||
188 | } | 167 | } |
189 | 168 | ||
190 | static struct irq_chip crime_edge_interrupt = { | 169 | static struct irq_chip crime_edge_interrupt = { |
191 | .name = "IP32 CRIME", | 170 | .name = "IP32 CRIME", |
192 | .ack = crime_edge_mask_and_ack_irq, | 171 | .irq_ack = crime_edge_mask_and_ack_irq, |
193 | .mask = crime_disable_irq, | 172 | .irq_mask = crime_disable_irq, |
194 | .mask_ack = crime_edge_mask_and_ack_irq, | 173 | .irq_mask_ack = crime_edge_mask_and_ack_irq, |
195 | .unmask = crime_enable_irq, | 174 | .irq_unmask = crime_enable_irq, |
196 | .end = crime_edge_end_irq, | ||
197 | }; | 175 | }; |
198 | 176 | ||
199 | /* | 177 | /* |
@@ -204,37 +182,28 @@ static struct irq_chip crime_edge_interrupt = { | |||
204 | 182 | ||
205 | static unsigned long macepci_mask; | 183 | static unsigned long macepci_mask; |
206 | 184 | ||
207 | static void enable_macepci_irq(unsigned int irq) | 185 | static void enable_macepci_irq(struct irq_data *d) |
208 | { | 186 | { |
209 | macepci_mask |= MACEPCI_CONTROL_INT(irq - MACEPCI_SCSI0_IRQ); | 187 | macepci_mask |= MACEPCI_CONTROL_INT(d->irq - MACEPCI_SCSI0_IRQ); |
210 | mace->pci.control = macepci_mask; | 188 | mace->pci.control = macepci_mask; |
211 | crime_mask |= 1 << (irq - CRIME_IRQ_BASE); | 189 | crime_mask |= 1 << (d->irq - CRIME_IRQ_BASE); |
212 | crime->imask = crime_mask; | 190 | crime->imask = crime_mask; |
213 | } | 191 | } |
214 | 192 | ||
215 | static void disable_macepci_irq(unsigned int irq) | 193 | static void disable_macepci_irq(struct irq_data *d) |
216 | { | 194 | { |
217 | crime_mask &= ~(1 << (irq - CRIME_IRQ_BASE)); | 195 | crime_mask &= ~(1 << (d->irq - CRIME_IRQ_BASE)); |
218 | crime->imask = crime_mask; | 196 | crime->imask = crime_mask; |
219 | flush_crime_bus(); | 197 | flush_crime_bus(); |
220 | macepci_mask &= ~MACEPCI_CONTROL_INT(irq - MACEPCI_SCSI0_IRQ); | 198 | macepci_mask &= ~MACEPCI_CONTROL_INT(d->irq - MACEPCI_SCSI0_IRQ); |
221 | mace->pci.control = macepci_mask; | 199 | mace->pci.control = macepci_mask; |
222 | flush_mace_bus(); | 200 | flush_mace_bus(); |
223 | } | 201 | } |
224 | 202 | ||
225 | static void end_macepci_irq(unsigned int irq) | ||
226 | { | ||
227 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
228 | enable_macepci_irq(irq); | ||
229 | } | ||
230 | |||
231 | static struct irq_chip ip32_macepci_interrupt = { | 203 | static struct irq_chip ip32_macepci_interrupt = { |
232 | .name = "IP32 MACE PCI", | 204 | .name = "IP32 MACE PCI", |
233 | .ack = disable_macepci_irq, | 205 | .irq_mask = disable_macepci_irq, |
234 | .mask = disable_macepci_irq, | 206 | .irq_unmask = enable_macepci_irq, |
235 | .mask_ack = disable_macepci_irq, | ||
236 | .unmask = enable_macepci_irq, | ||
237 | .end = end_macepci_irq, | ||
238 | }; | 207 | }; |
239 | 208 | ||
240 | /* This is used for MACE ISA interrupts. That means bits 4-6 in the | 209 | /* This is used for MACE ISA interrupts. That means bits 4-6 in the |
@@ -276,13 +245,13 @@ static struct irq_chip ip32_macepci_interrupt = { | |||
276 | 245 | ||
277 | static unsigned long maceisa_mask; | 246 | static unsigned long maceisa_mask; |
278 | 247 | ||
279 | static void enable_maceisa_irq(unsigned int irq) | 248 | static void enable_maceisa_irq(struct irq_data *d) |
280 | { | 249 | { |
281 | unsigned int crime_int = 0; | 250 | unsigned int crime_int = 0; |
282 | 251 | ||
283 | pr_debug("maceisa enable: %u\n", irq); | 252 | pr_debug("maceisa enable: %u\n", d->irq); |
284 | 253 | ||
285 | switch (irq) { | 254 | switch (d->irq) { |
286 | case MACEISA_AUDIO_SW_IRQ ... MACEISA_AUDIO3_MERR_IRQ: | 255 | case MACEISA_AUDIO_SW_IRQ ... MACEISA_AUDIO3_MERR_IRQ: |
287 | crime_int = MACE_AUDIO_INT; | 256 | crime_int = MACE_AUDIO_INT; |
288 | break; | 257 | break; |
@@ -296,15 +265,15 @@ static void enable_maceisa_irq(unsigned int irq) | |||
296 | pr_debug("crime_int %08x enabled\n", crime_int); | 265 | pr_debug("crime_int %08x enabled\n", crime_int); |
297 | crime_mask |= crime_int; | 266 | crime_mask |= crime_int; |
298 | crime->imask = crime_mask; | 267 | crime->imask = crime_mask; |
299 | maceisa_mask |= 1 << (irq - MACEISA_AUDIO_SW_IRQ); | 268 | maceisa_mask |= 1 << (d->irq - MACEISA_AUDIO_SW_IRQ); |
300 | mace->perif.ctrl.imask = maceisa_mask; | 269 | mace->perif.ctrl.imask = maceisa_mask; |
301 | } | 270 | } |
302 | 271 | ||
303 | static void disable_maceisa_irq(unsigned int irq) | 272 | static void disable_maceisa_irq(struct irq_data *d) |
304 | { | 273 | { |
305 | unsigned int crime_int = 0; | 274 | unsigned int crime_int = 0; |
306 | 275 | ||
307 | maceisa_mask &= ~(1 << (irq - MACEISA_AUDIO_SW_IRQ)); | 276 | maceisa_mask &= ~(1 << (d->irq - MACEISA_AUDIO_SW_IRQ)); |
308 | if (!(maceisa_mask & MACEISA_AUDIO_INT)) | 277 | if (!(maceisa_mask & MACEISA_AUDIO_INT)) |
309 | crime_int |= MACE_AUDIO_INT; | 278 | crime_int |= MACE_AUDIO_INT; |
310 | if (!(maceisa_mask & MACEISA_MISC_INT)) | 279 | if (!(maceisa_mask & MACEISA_MISC_INT)) |
@@ -318,76 +287,57 @@ static void disable_maceisa_irq(unsigned int irq) | |||
318 | flush_mace_bus(); | 287 | flush_mace_bus(); |
319 | } | 288 | } |
320 | 289 | ||
321 | static void mask_and_ack_maceisa_irq(unsigned int irq) | 290 | static void mask_and_ack_maceisa_irq(struct irq_data *d) |
322 | { | 291 | { |
323 | unsigned long mace_int; | 292 | unsigned long mace_int; |
324 | 293 | ||
325 | /* edge triggered */ | 294 | /* edge triggered */ |
326 | mace_int = mace->perif.ctrl.istat; | 295 | mace_int = mace->perif.ctrl.istat; |
327 | mace_int &= ~(1 << (irq - MACEISA_AUDIO_SW_IRQ)); | 296 | mace_int &= ~(1 << (d->irq - MACEISA_AUDIO_SW_IRQ)); |
328 | mace->perif.ctrl.istat = mace_int; | 297 | mace->perif.ctrl.istat = mace_int; |
329 | 298 | ||
330 | disable_maceisa_irq(irq); | 299 | disable_maceisa_irq(d); |
331 | } | ||
332 | |||
333 | static void end_maceisa_irq(unsigned irq) | ||
334 | { | ||
335 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | ||
336 | enable_maceisa_irq(irq); | ||
337 | } | 300 | } |
338 | 301 | ||
339 | static struct irq_chip ip32_maceisa_level_interrupt = { | 302 | static struct irq_chip ip32_maceisa_level_interrupt = { |
340 | .name = "IP32 MACE ISA", | 303 | .name = "IP32 MACE ISA", |
341 | .ack = disable_maceisa_irq, | 304 | .irq_mask = disable_maceisa_irq, |
342 | .mask = disable_maceisa_irq, | 305 | .irq_unmask = enable_maceisa_irq, |
343 | .mask_ack = disable_maceisa_irq, | ||
344 | .unmask = enable_maceisa_irq, | ||
345 | .end = end_maceisa_irq, | ||
346 | }; | 306 | }; |
347 | 307 | ||
348 | static struct irq_chip ip32_maceisa_edge_interrupt = { | 308 | static struct irq_chip ip32_maceisa_edge_interrupt = { |
349 | .name = "IP32 MACE ISA", | 309 | .name = "IP32 MACE ISA", |
350 | .ack = mask_and_ack_maceisa_irq, | 310 | .irq_ack = mask_and_ack_maceisa_irq, |
351 | .mask = disable_maceisa_irq, | 311 | .irq_mask = disable_maceisa_irq, |
352 | .mask_ack = mask_and_ack_maceisa_irq, | 312 | .irq_mask_ack = mask_and_ack_maceisa_irq, |
353 | .unmask = enable_maceisa_irq, | 313 | .irq_unmask = enable_maceisa_irq, |
354 | .end = end_maceisa_irq, | ||
355 | }; | 314 | }; |
356 | 315 | ||
357 | /* This is used for regular non-ISA, non-PCI MACE interrupts. That means | 316 | /* This is used for regular non-ISA, non-PCI MACE interrupts. That means |
358 | * bits 0-3 and 7 in the CRIME register. | 317 | * bits 0-3 and 7 in the CRIME register. |
359 | */ | 318 | */ |
360 | 319 | ||
361 | static void enable_mace_irq(unsigned int irq) | 320 | static void enable_mace_irq(struct irq_data *d) |
362 | { | 321 | { |
363 | unsigned int bit = irq - CRIME_IRQ_BASE; | 322 | unsigned int bit = d->irq - CRIME_IRQ_BASE; |
364 | 323 | ||
365 | crime_mask |= (1 << bit); | 324 | crime_mask |= (1 << bit); |
366 | crime->imask = crime_mask; | 325 | crime->imask = crime_mask; |
367 | } | 326 | } |
368 | 327 | ||
369 | static void disable_mace_irq(unsigned int irq) | 328 | static void disable_mace_irq(struct irq_data *d) |
370 | { | 329 | { |
371 | unsigned int bit = irq - CRIME_IRQ_BASE; | 330 | unsigned int bit = d->irq - CRIME_IRQ_BASE; |
372 | 331 | ||
373 | crime_mask &= ~(1 << bit); | 332 | crime_mask &= ~(1 << bit); |
374 | crime->imask = crime_mask; | 333 | crime->imask = crime_mask; |
375 | flush_crime_bus(); | 334 | flush_crime_bus(); |
376 | } | 335 | } |
377 | 336 | ||
378 | static void end_mace_irq(unsigned int irq) | ||
379 | { | ||
380 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
381 | enable_mace_irq(irq); | ||
382 | } | ||
383 | |||
384 | static struct irq_chip ip32_mace_interrupt = { | 337 | static struct irq_chip ip32_mace_interrupt = { |
385 | .name = "IP32 MACE", | 338 | .name = "IP32 MACE", |
386 | .ack = disable_mace_irq, | 339 | .irq_mask = disable_mace_irq, |
387 | .mask = disable_mace_irq, | 340 | .irq_unmask = enable_mace_irq, |
388 | .mask_ack = disable_mace_irq, | ||
389 | .unmask = enable_mace_irq, | ||
390 | .end = end_mace_irq, | ||
391 | }; | 341 | }; |
392 | 342 | ||
393 | static void ip32_unknown_interrupt(void) | 343 | static void ip32_unknown_interrupt(void) |
diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c index 044bbe462c2c..89e8188a4665 100644 --- a/arch/mips/sibyte/bcm1480/irq.c +++ b/arch/mips/sibyte/bcm1480/irq.c | |||
@@ -44,31 +44,10 @@ | |||
44 | * for interrupt lines | 44 | * for interrupt lines |
45 | */ | 45 | */ |
46 | 46 | ||
47 | |||
48 | static void end_bcm1480_irq(unsigned int irq); | ||
49 | static void enable_bcm1480_irq(unsigned int irq); | ||
50 | static void disable_bcm1480_irq(unsigned int irq); | ||
51 | static void ack_bcm1480_irq(unsigned int irq); | ||
52 | #ifdef CONFIG_SMP | ||
53 | static int bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask); | ||
54 | #endif | ||
55 | |||
56 | #ifdef CONFIG_PCI | 47 | #ifdef CONFIG_PCI |
57 | extern unsigned long ht_eoi_space; | 48 | extern unsigned long ht_eoi_space; |
58 | #endif | 49 | #endif |
59 | 50 | ||
60 | static struct irq_chip bcm1480_irq_type = { | ||
61 | .name = "BCM1480-IMR", | ||
62 | .ack = ack_bcm1480_irq, | ||
63 | .mask = disable_bcm1480_irq, | ||
64 | .mask_ack = ack_bcm1480_irq, | ||
65 | .unmask = enable_bcm1480_irq, | ||
66 | .end = end_bcm1480_irq, | ||
67 | #ifdef CONFIG_SMP | ||
68 | .set_affinity = bcm1480_set_affinity | ||
69 | #endif | ||
70 | }; | ||
71 | |||
72 | /* Store the CPU id (not the logical number) */ | 51 | /* Store the CPU id (not the logical number) */ |
73 | int bcm1480_irq_owner[BCM1480_NR_IRQS]; | 52 | int bcm1480_irq_owner[BCM1480_NR_IRQS]; |
74 | 53 | ||
@@ -109,12 +88,13 @@ void bcm1480_unmask_irq(int cpu, int irq) | |||
109 | } | 88 | } |
110 | 89 | ||
111 | #ifdef CONFIG_SMP | 90 | #ifdef CONFIG_SMP |
112 | static int bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask) | 91 | static int bcm1480_set_affinity(struct irq_data *d, const struct cpumask *mask, |
92 | bool force) | ||
113 | { | 93 | { |
94 | unsigned int irq_dirty, irq = d->irq; | ||
114 | int i = 0, old_cpu, cpu, int_on, k; | 95 | int i = 0, old_cpu, cpu, int_on, k; |
115 | u64 cur_ints; | 96 | u64 cur_ints; |
116 | unsigned long flags; | 97 | unsigned long flags; |
117 | unsigned int irq_dirty; | ||
118 | 98 | ||
119 | i = cpumask_first(mask); | 99 | i = cpumask_first(mask); |
120 | 100 | ||
@@ -156,21 +136,25 @@ static int bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask) | |||
156 | 136 | ||
157 | /*****************************************************************************/ | 137 | /*****************************************************************************/ |
158 | 138 | ||
159 | static void disable_bcm1480_irq(unsigned int irq) | 139 | static void disable_bcm1480_irq(struct irq_data *d) |
160 | { | 140 | { |
141 | unsigned int irq = d->irq; | ||
142 | |||
161 | bcm1480_mask_irq(bcm1480_irq_owner[irq], irq); | 143 | bcm1480_mask_irq(bcm1480_irq_owner[irq], irq); |
162 | } | 144 | } |
163 | 145 | ||
164 | static void enable_bcm1480_irq(unsigned int irq) | 146 | static void enable_bcm1480_irq(struct irq_data *d) |
165 | { | 147 | { |
148 | unsigned int irq = d->irq; | ||
149 | |||
166 | bcm1480_unmask_irq(bcm1480_irq_owner[irq], irq); | 150 | bcm1480_unmask_irq(bcm1480_irq_owner[irq], irq); |
167 | } | 151 | } |
168 | 152 | ||
169 | 153 | ||
170 | static void ack_bcm1480_irq(unsigned int irq) | 154 | static void ack_bcm1480_irq(struct irq_data *d) |
171 | { | 155 | { |
156 | unsigned int irq_dirty, irq = d->irq; | ||
172 | u64 pending; | 157 | u64 pending; |
173 | unsigned int irq_dirty; | ||
174 | int k; | 158 | int k; |
175 | 159 | ||
176 | /* | 160 | /* |
@@ -217,14 +201,15 @@ static void ack_bcm1480_irq(unsigned int irq) | |||
217 | bcm1480_mask_irq(bcm1480_irq_owner[irq], irq); | 201 | bcm1480_mask_irq(bcm1480_irq_owner[irq], irq); |
218 | } | 202 | } |
219 | 203 | ||
220 | 204 | static struct irq_chip bcm1480_irq_type = { | |
221 | static void end_bcm1480_irq(unsigned int irq) | 205 | .name = "BCM1480-IMR", |
222 | { | 206 | .irq_mask_ack = ack_bcm1480_irq, |
223 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { | 207 | .irq_mask = disable_bcm1480_irq, |
224 | bcm1480_unmask_irq(bcm1480_irq_owner[irq], irq); | 208 | .irq_unmask = enable_bcm1480_irq, |
225 | } | 209 | #ifdef CONFIG_SMP |
226 | } | 210 | .irq_set_affinity = bcm1480_set_affinity |
227 | 211 | #endif | |
212 | }; | ||
228 | 213 | ||
229 | void __init init_bcm1480_irqs(void) | 214 | void __init init_bcm1480_irqs(void) |
230 | { | 215 | { |
diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c index 12ac04a658ee..fd269ea8d8a8 100644 --- a/arch/mips/sibyte/sb1250/irq.c +++ b/arch/mips/sibyte/sb1250/irq.c | |||
@@ -43,31 +43,10 @@ | |||
43 | * for interrupt lines | 43 | * for interrupt lines |
44 | */ | 44 | */ |
45 | 45 | ||
46 | |||
47 | static void end_sb1250_irq(unsigned int irq); | ||
48 | static void enable_sb1250_irq(unsigned int irq); | ||
49 | static void disable_sb1250_irq(unsigned int irq); | ||
50 | static void ack_sb1250_irq(unsigned int irq); | ||
51 | #ifdef CONFIG_SMP | ||
52 | static int sb1250_set_affinity(unsigned int irq, const struct cpumask *mask); | ||
53 | #endif | ||
54 | |||
55 | #ifdef CONFIG_SIBYTE_HAS_LDT | 46 | #ifdef CONFIG_SIBYTE_HAS_LDT |
56 | extern unsigned long ldt_eoi_space; | 47 | extern unsigned long ldt_eoi_space; |
57 | #endif | 48 | #endif |
58 | 49 | ||
59 | static struct irq_chip sb1250_irq_type = { | ||
60 | .name = "SB1250-IMR", | ||
61 | .ack = ack_sb1250_irq, | ||
62 | .mask = disable_sb1250_irq, | ||
63 | .mask_ack = ack_sb1250_irq, | ||
64 | .unmask = enable_sb1250_irq, | ||
65 | .end = end_sb1250_irq, | ||
66 | #ifdef CONFIG_SMP | ||
67 | .set_affinity = sb1250_set_affinity | ||
68 | #endif | ||
69 | }; | ||
70 | |||
71 | /* Store the CPU id (not the logical number) */ | 50 | /* Store the CPU id (not the logical number) */ |
72 | int sb1250_irq_owner[SB1250_NR_IRQS]; | 51 | int sb1250_irq_owner[SB1250_NR_IRQS]; |
73 | 52 | ||
@@ -102,9 +81,11 @@ void sb1250_unmask_irq(int cpu, int irq) | |||
102 | } | 81 | } |
103 | 82 | ||
104 | #ifdef CONFIG_SMP | 83 | #ifdef CONFIG_SMP |
105 | static int sb1250_set_affinity(unsigned int irq, const struct cpumask *mask) | 84 | static int sb1250_set_affinity(struct irq_data *d, const struct cpumask *mask, |
85 | bool force) | ||
106 | { | 86 | { |
107 | int i = 0, old_cpu, cpu, int_on; | 87 | int i = 0, old_cpu, cpu, int_on; |
88 | unsigned int irq = d->irq; | ||
108 | u64 cur_ints; | 89 | u64 cur_ints; |
109 | unsigned long flags; | 90 | unsigned long flags; |
110 | 91 | ||
@@ -142,21 +123,17 @@ static int sb1250_set_affinity(unsigned int irq, const struct cpumask *mask) | |||
142 | } | 123 | } |
143 | #endif | 124 | #endif |
144 | 125 | ||
145 | /*****************************************************************************/ | 126 | static void enable_sb1250_irq(struct irq_data *d) |
146 | |||
147 | static void disable_sb1250_irq(unsigned int irq) | ||
148 | { | 127 | { |
149 | sb1250_mask_irq(sb1250_irq_owner[irq], irq); | 128 | unsigned int irq = d->irq; |
150 | } | ||
151 | 129 | ||
152 | static void enable_sb1250_irq(unsigned int irq) | ||
153 | { | ||
154 | sb1250_unmask_irq(sb1250_irq_owner[irq], irq); | 130 | sb1250_unmask_irq(sb1250_irq_owner[irq], irq); |
155 | } | 131 | } |
156 | 132 | ||
157 | 133 | ||
158 | static void ack_sb1250_irq(unsigned int irq) | 134 | static void ack_sb1250_irq(struct irq_data *d) |
159 | { | 135 | { |
136 | unsigned int irq = d->irq; | ||
160 | #ifdef CONFIG_SIBYTE_HAS_LDT | 137 | #ifdef CONFIG_SIBYTE_HAS_LDT |
161 | u64 pending; | 138 | u64 pending; |
162 | 139 | ||
@@ -199,14 +176,14 @@ static void ack_sb1250_irq(unsigned int irq) | |||
199 | sb1250_mask_irq(sb1250_irq_owner[irq], irq); | 176 | sb1250_mask_irq(sb1250_irq_owner[irq], irq); |
200 | } | 177 | } |
201 | 178 | ||
202 | 179 | static struct irq_chip sb1250_irq_type = { | |
203 | static void end_sb1250_irq(unsigned int irq) | 180 | .name = "SB1250-IMR", |
204 | { | 181 | .irq_mask_ack = ack_sb1250_irq, |
205 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { | 182 | .irq_unmask = enable_sb1250_irq, |
206 | sb1250_unmask_irq(sb1250_irq_owner[irq], irq); | 183 | #ifdef CONFIG_SMP |
207 | } | 184 | .irq_set_affinity = sb1250_set_affinity |
208 | } | 185 | #endif |
209 | 186 | }; | |
210 | 187 | ||
211 | void __init init_sb1250_irqs(void) | 188 | void __init init_sb1250_irqs(void) |
212 | { | 189 | { |
diff --git a/arch/mips/sni/a20r.c b/arch/mips/sni/a20r.c index bbe7187879fa..72b94155778d 100644 --- a/arch/mips/sni/a20r.c +++ b/arch/mips/sni/a20r.c | |||
@@ -168,33 +168,22 @@ static u32 a20r_ack_hwint(void) | |||
168 | return status; | 168 | return status; |
169 | } | 169 | } |
170 | 170 | ||
171 | static inline void unmask_a20r_irq(unsigned int irq) | 171 | static inline void unmask_a20r_irq(struct irq_data *d) |
172 | { | 172 | { |
173 | set_c0_status(0x100 << (irq - SNI_A20R_IRQ_BASE)); | 173 | set_c0_status(0x100 << (d->irq - SNI_A20R_IRQ_BASE)); |
174 | irq_enable_hazard(); | 174 | irq_enable_hazard(); |
175 | } | 175 | } |
176 | 176 | ||
177 | static inline void mask_a20r_irq(unsigned int irq) | 177 | static inline void mask_a20r_irq(struct irq_data *d) |
178 | { | 178 | { |
179 | clear_c0_status(0x100 << (irq - SNI_A20R_IRQ_BASE)); | 179 | clear_c0_status(0x100 << (d->irq - SNI_A20R_IRQ_BASE)); |
180 | irq_disable_hazard(); | 180 | irq_disable_hazard(); |
181 | } | 181 | } |
182 | 182 | ||
183 | static void end_a20r_irq(unsigned int irq) | ||
184 | { | ||
185 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { | ||
186 | a20r_ack_hwint(); | ||
187 | unmask_a20r_irq(irq); | ||
188 | } | ||
189 | } | ||
190 | |||
191 | static struct irq_chip a20r_irq_type = { | 183 | static struct irq_chip a20r_irq_type = { |
192 | .name = "A20R", | 184 | .name = "A20R", |
193 | .ack = mask_a20r_irq, | 185 | .irq_mask = mask_a20r_irq, |
194 | .mask = mask_a20r_irq, | 186 | .irq_unmask = unmask_a20r_irq, |
195 | .mask_ack = mask_a20r_irq, | ||
196 | .unmask = unmask_a20r_irq, | ||
197 | .end = end_a20r_irq, | ||
198 | }; | 187 | }; |
199 | 188 | ||
200 | /* | 189 | /* |
diff --git a/arch/mips/sni/pcimt.c b/arch/mips/sni/pcimt.c index 8c92c73bc717..cfcc68abc5b2 100644 --- a/arch/mips/sni/pcimt.c +++ b/arch/mips/sni/pcimt.c | |||
@@ -194,33 +194,24 @@ static struct pci_controller sni_controller = { | |||
194 | .io_map_base = SNI_PORT_BASE | 194 | .io_map_base = SNI_PORT_BASE |
195 | }; | 195 | }; |
196 | 196 | ||
197 | static void enable_pcimt_irq(unsigned int irq) | 197 | static void enable_pcimt_irq(struct irq_data *d) |
198 | { | 198 | { |
199 | unsigned int mask = 1 << (irq - PCIMT_IRQ_INT2); | 199 | unsigned int mask = 1 << (d->irq - PCIMT_IRQ_INT2); |
200 | 200 | ||
201 | *(volatile u8 *) PCIMT_IRQSEL |= mask; | 201 | *(volatile u8 *) PCIMT_IRQSEL |= mask; |
202 | } | 202 | } |
203 | 203 | ||
204 | void disable_pcimt_irq(unsigned int irq) | 204 | void disable_pcimt_irq(struct irq_data *d) |
205 | { | 205 | { |
206 | unsigned int mask = ~(1 << (irq - PCIMT_IRQ_INT2)); | 206 | unsigned int mask = ~(1 << (d->irq - PCIMT_IRQ_INT2)); |
207 | 207 | ||
208 | *(volatile u8 *) PCIMT_IRQSEL &= mask; | 208 | *(volatile u8 *) PCIMT_IRQSEL &= mask; |
209 | } | 209 | } |
210 | 210 | ||
211 | static void end_pcimt_irq(unsigned int irq) | ||
212 | { | ||
213 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
214 | enable_pcimt_irq(irq); | ||
215 | } | ||
216 | |||
217 | static struct irq_chip pcimt_irq_type = { | 211 | static struct irq_chip pcimt_irq_type = { |
218 | .name = "PCIMT", | 212 | .name = "PCIMT", |
219 | .ack = disable_pcimt_irq, | 213 | .irq_mask = disable_pcimt_irq, |
220 | .mask = disable_pcimt_irq, | 214 | .irq_unmask = enable_pcimt_irq, |
221 | .mask_ack = disable_pcimt_irq, | ||
222 | .unmask = enable_pcimt_irq, | ||
223 | .end = end_pcimt_irq, | ||
224 | }; | 215 | }; |
225 | 216 | ||
226 | /* | 217 | /* |
diff --git a/arch/mips/sni/pcit.c b/arch/mips/sni/pcit.c index dc9874553bec..0846e99a6efe 100644 --- a/arch/mips/sni/pcit.c +++ b/arch/mips/sni/pcit.c | |||
@@ -156,33 +156,24 @@ static struct pci_controller sni_pcit_controller = { | |||
156 | .io_map_base = SNI_PORT_BASE | 156 | .io_map_base = SNI_PORT_BASE |
157 | }; | 157 | }; |
158 | 158 | ||
159 | static void enable_pcit_irq(unsigned int irq) | 159 | static void enable_pcit_irq(struct irq_data *d) |
160 | { | 160 | { |
161 | u32 mask = 1 << (irq - SNI_PCIT_INT_START + 24); | 161 | u32 mask = 1 << (d->irq - SNI_PCIT_INT_START + 24); |
162 | 162 | ||
163 | *(volatile u32 *)SNI_PCIT_INT_REG |= mask; | 163 | *(volatile u32 *)SNI_PCIT_INT_REG |= mask; |
164 | } | 164 | } |
165 | 165 | ||
166 | void disable_pcit_irq(unsigned int irq) | 166 | void disable_pcit_irq(struct irq_data *d) |
167 | { | 167 | { |
168 | u32 mask = 1 << (irq - SNI_PCIT_INT_START + 24); | 168 | u32 mask = 1 << (d->irq - SNI_PCIT_INT_START + 24); |
169 | 169 | ||
170 | *(volatile u32 *)SNI_PCIT_INT_REG &= ~mask; | 170 | *(volatile u32 *)SNI_PCIT_INT_REG &= ~mask; |
171 | } | 171 | } |
172 | 172 | ||
173 | void end_pcit_irq(unsigned int irq) | ||
174 | { | ||
175 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
176 | enable_pcit_irq(irq); | ||
177 | } | ||
178 | |||
179 | static struct irq_chip pcit_irq_type = { | 173 | static struct irq_chip pcit_irq_type = { |
180 | .name = "PCIT", | 174 | .name = "PCIT", |
181 | .ack = disable_pcit_irq, | 175 | .irq_mask = disable_pcit_irq, |
182 | .mask = disable_pcit_irq, | 176 | .irq_unmask = enable_pcit_irq, |
183 | .mask_ack = disable_pcit_irq, | ||
184 | .unmask = enable_pcit_irq, | ||
185 | .end = end_pcit_irq, | ||
186 | }; | 177 | }; |
187 | 178 | ||
188 | static void pcit_hwint1(void) | 179 | static void pcit_hwint1(void) |
diff --git a/arch/mips/sni/rm200.c b/arch/mips/sni/rm200.c index 0e6f42c2bbc8..f05d8e593300 100644 --- a/arch/mips/sni/rm200.c +++ b/arch/mips/sni/rm200.c | |||
@@ -155,12 +155,11 @@ static __iomem u8 *rm200_pic_slave; | |||
155 | #define cached_master_mask (rm200_cached_irq_mask) | 155 | #define cached_master_mask (rm200_cached_irq_mask) |
156 | #define cached_slave_mask (rm200_cached_irq_mask >> 8) | 156 | #define cached_slave_mask (rm200_cached_irq_mask >> 8) |
157 | 157 | ||
158 | static void sni_rm200_disable_8259A_irq(unsigned int irq) | 158 | static void sni_rm200_disable_8259A_irq(struct irq_data *d) |
159 | { | 159 | { |
160 | unsigned int mask; | 160 | unsigned int mask, irq = d->irq - RM200_I8259A_IRQ_BASE; |
161 | unsigned long flags; | 161 | unsigned long flags; |
162 | 162 | ||
163 | irq -= RM200_I8259A_IRQ_BASE; | ||
164 | mask = 1 << irq; | 163 | mask = 1 << irq; |
165 | raw_spin_lock_irqsave(&sni_rm200_i8259A_lock, flags); | 164 | raw_spin_lock_irqsave(&sni_rm200_i8259A_lock, flags); |
166 | rm200_cached_irq_mask |= mask; | 165 | rm200_cached_irq_mask |= mask; |
@@ -171,12 +170,11 @@ static void sni_rm200_disable_8259A_irq(unsigned int irq) | |||
171 | raw_spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags); | 170 | raw_spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags); |
172 | } | 171 | } |
173 | 172 | ||
174 | static void sni_rm200_enable_8259A_irq(unsigned int irq) | 173 | static void sni_rm200_enable_8259A_irq(struct irq_data *d) |
175 | { | 174 | { |
176 | unsigned int mask; | 175 | unsigned int mask, irq = d->irq - RM200_I8259A_IRQ_BASE; |
177 | unsigned long flags; | 176 | unsigned long flags; |
178 | 177 | ||
179 | irq -= RM200_I8259A_IRQ_BASE; | ||
180 | mask = ~(1 << irq); | 178 | mask = ~(1 << irq); |
181 | raw_spin_lock_irqsave(&sni_rm200_i8259A_lock, flags); | 179 | raw_spin_lock_irqsave(&sni_rm200_i8259A_lock, flags); |
182 | rm200_cached_irq_mask &= mask; | 180 | rm200_cached_irq_mask &= mask; |
@@ -210,12 +208,11 @@ static inline int sni_rm200_i8259A_irq_real(unsigned int irq) | |||
210 | * first, _then_ send the EOI, and the order of EOI | 208 | * first, _then_ send the EOI, and the order of EOI |
211 | * to the two 8259s is important! | 209 | * to the two 8259s is important! |
212 | */ | 210 | */ |
213 | void sni_rm200_mask_and_ack_8259A(unsigned int irq) | 211 | void sni_rm200_mask_and_ack_8259A(struct irq_data *d) |
214 | { | 212 | { |
215 | unsigned int irqmask; | 213 | unsigned int irqmask, irq = d->irq - RM200_I8259A_IRQ_BASE; |
216 | unsigned long flags; | 214 | unsigned long flags; |
217 | 215 | ||
218 | irq -= RM200_I8259A_IRQ_BASE; | ||
219 | irqmask = 1 << irq; | 216 | irqmask = 1 << irq; |
220 | raw_spin_lock_irqsave(&sni_rm200_i8259A_lock, flags); | 217 | raw_spin_lock_irqsave(&sni_rm200_i8259A_lock, flags); |
221 | /* | 218 | /* |
@@ -285,9 +282,9 @@ spurious_8259A_irq: | |||
285 | 282 | ||
286 | static struct irq_chip sni_rm200_i8259A_chip = { | 283 | static struct irq_chip sni_rm200_i8259A_chip = { |
287 | .name = "RM200-XT-PIC", | 284 | .name = "RM200-XT-PIC", |
288 | .mask = sni_rm200_disable_8259A_irq, | 285 | .irq_mask = sni_rm200_disable_8259A_irq, |
289 | .unmask = sni_rm200_enable_8259A_irq, | 286 | .irq_unmask = sni_rm200_enable_8259A_irq, |
290 | .mask_ack = sni_rm200_mask_and_ack_8259A, | 287 | .irq_mask_ack = sni_rm200_mask_and_ack_8259A, |
291 | }; | 288 | }; |
292 | 289 | ||
293 | /* | 290 | /* |
@@ -429,33 +426,24 @@ void __init sni_rm200_i8259_irqs(void) | |||
429 | #define SNI_RM200_INT_START 24 | 426 | #define SNI_RM200_INT_START 24 |
430 | #define SNI_RM200_INT_END 28 | 427 | #define SNI_RM200_INT_END 28 |
431 | 428 | ||
432 | static void enable_rm200_irq(unsigned int irq) | 429 | static void enable_rm200_irq(struct irq_data *d) |
433 | { | 430 | { |
434 | unsigned int mask = 1 << (irq - SNI_RM200_INT_START); | 431 | unsigned int mask = 1 << (d->irq - SNI_RM200_INT_START); |
435 | 432 | ||
436 | *(volatile u8 *)SNI_RM200_INT_ENA_REG &= ~mask; | 433 | *(volatile u8 *)SNI_RM200_INT_ENA_REG &= ~mask; |
437 | } | 434 | } |
438 | 435 | ||
439 | void disable_rm200_irq(unsigned int irq) | 436 | void disable_rm200_irq(struct irq_data *d) |
440 | { | 437 | { |
441 | unsigned int mask = 1 << (irq - SNI_RM200_INT_START); | 438 | unsigned int mask = 1 << (d->irq - SNI_RM200_INT_START); |
442 | 439 | ||
443 | *(volatile u8 *)SNI_RM200_INT_ENA_REG |= mask; | 440 | *(volatile u8 *)SNI_RM200_INT_ENA_REG |= mask; |
444 | } | 441 | } |
445 | 442 | ||
446 | void end_rm200_irq(unsigned int irq) | ||
447 | { | ||
448 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
449 | enable_rm200_irq(irq); | ||
450 | } | ||
451 | |||
452 | static struct irq_chip rm200_irq_type = { | 443 | static struct irq_chip rm200_irq_type = { |
453 | .name = "RM200", | 444 | .name = "RM200", |
454 | .ack = disable_rm200_irq, | 445 | .irq_mask = disable_rm200_irq, |
455 | .mask = disable_rm200_irq, | 446 | .irq_unmask = enable_rm200_irq, |
456 | .mask_ack = disable_rm200_irq, | ||
457 | .unmask = enable_rm200_irq, | ||
458 | .end = end_rm200_irq, | ||
459 | }; | 447 | }; |
460 | 448 | ||
461 | static void sni_rm200_hwint(void) | 449 | static void sni_rm200_hwint(void) |
diff --git a/arch/mips/txx9/generic/irq_tx4939.c b/arch/mips/txx9/generic/irq_tx4939.c index 3886ad77cbad..93b6edbedd64 100644 --- a/arch/mips/txx9/generic/irq_tx4939.c +++ b/arch/mips/txx9/generic/irq_tx4939.c | |||
@@ -50,9 +50,9 @@ static struct { | |||
50 | unsigned char mode; | 50 | unsigned char mode; |
51 | } tx4939irq[TX4939_NUM_IR] __read_mostly; | 51 | } tx4939irq[TX4939_NUM_IR] __read_mostly; |
52 | 52 | ||
53 | static void tx4939_irq_unmask(unsigned int irq) | 53 | static void tx4939_irq_unmask(struct irq_data *d) |
54 | { | 54 | { |
55 | unsigned int irq_nr = irq - TXX9_IRQ_BASE; | 55 | unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; |
56 | u32 __iomem *lvlp; | 56 | u32 __iomem *lvlp; |
57 | int ofs; | 57 | int ofs; |
58 | if (irq_nr < 32) { | 58 | if (irq_nr < 32) { |
@@ -68,9 +68,9 @@ static void tx4939_irq_unmask(unsigned int irq) | |||
68 | lvlp); | 68 | lvlp); |
69 | } | 69 | } |
70 | 70 | ||
71 | static inline void tx4939_irq_mask(unsigned int irq) | 71 | static inline void tx4939_irq_mask(struct irq_data *d) |
72 | { | 72 | { |
73 | unsigned int irq_nr = irq - TXX9_IRQ_BASE; | 73 | unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; |
74 | u32 __iomem *lvlp; | 74 | u32 __iomem *lvlp; |
75 | int ofs; | 75 | int ofs; |
76 | if (irq_nr < 32) { | 76 | if (irq_nr < 32) { |
@@ -87,11 +87,11 @@ static inline void tx4939_irq_mask(unsigned int irq) | |||
87 | mmiowb(); | 87 | mmiowb(); |
88 | } | 88 | } |
89 | 89 | ||
90 | static void tx4939_irq_mask_ack(unsigned int irq) | 90 | static void tx4939_irq_mask_ack(struct irq_data *d) |
91 | { | 91 | { |
92 | unsigned int irq_nr = irq - TXX9_IRQ_BASE; | 92 | unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; |
93 | 93 | ||
94 | tx4939_irq_mask(irq); | 94 | tx4939_irq_mask(d); |
95 | if (TXx9_IRCR_EDGE(tx4939irq[irq_nr].mode)) { | 95 | if (TXx9_IRCR_EDGE(tx4939irq[irq_nr].mode)) { |
96 | irq_nr--; | 96 | irq_nr--; |
97 | /* clear edge detection */ | 97 | /* clear edge detection */ |
@@ -101,9 +101,9 @@ static void tx4939_irq_mask_ack(unsigned int irq) | |||
101 | } | 101 | } |
102 | } | 102 | } |
103 | 103 | ||
104 | static int tx4939_irq_set_type(unsigned int irq, unsigned int flow_type) | 104 | static int tx4939_irq_set_type(struct irq_data *d, unsigned int flow_type) |
105 | { | 105 | { |
106 | unsigned int irq_nr = irq - TXX9_IRQ_BASE; | 106 | unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; |
107 | u32 cr; | 107 | u32 cr; |
108 | u32 __iomem *crp; | 108 | u32 __iomem *crp; |
109 | int ofs; | 109 | int ofs; |
@@ -145,11 +145,11 @@ static int tx4939_irq_set_type(unsigned int irq, unsigned int flow_type) | |||
145 | 145 | ||
146 | static struct irq_chip tx4939_irq_chip = { | 146 | static struct irq_chip tx4939_irq_chip = { |
147 | .name = "TX4939", | 147 | .name = "TX4939", |
148 | .ack = tx4939_irq_mask_ack, | 148 | .irq_ack = tx4939_irq_mask_ack, |
149 | .mask = tx4939_irq_mask, | 149 | .irq_mask = tx4939_irq_mask, |
150 | .mask_ack = tx4939_irq_mask_ack, | 150 | .irq_mask_ack = tx4939_irq_mask_ack, |
151 | .unmask = tx4939_irq_unmask, | 151 | .irq_unmask = tx4939_irq_unmask, |
152 | .set_type = tx4939_irq_set_type, | 152 | .irq_set_type = tx4939_irq_set_type, |
153 | }; | 153 | }; |
154 | 154 | ||
155 | static int tx4939_irq_set_pri(int irc_irq, int new_pri) | 155 | static int tx4939_irq_set_pri(int irc_irq, int new_pri) |
diff --git a/arch/mips/txx9/jmr3927/irq.c b/arch/mips/txx9/jmr3927/irq.c index 0a7f8e3b9fd7..92a5c1b400f0 100644 --- a/arch/mips/txx9/jmr3927/irq.c +++ b/arch/mips/txx9/jmr3927/irq.c | |||
@@ -47,20 +47,20 @@ | |||
47 | * CP0_STATUS is a thread's resource (saved/restored on context switch). | 47 | * CP0_STATUS is a thread's resource (saved/restored on context switch). |
48 | * So disable_irq/enable_irq MUST handle IOC/IRC registers. | 48 | * So disable_irq/enable_irq MUST handle IOC/IRC registers. |
49 | */ | 49 | */ |
50 | static void mask_irq_ioc(unsigned int irq) | 50 | static void mask_irq_ioc(struct irq_data *d) |
51 | { | 51 | { |
52 | /* 0: mask */ | 52 | /* 0: mask */ |
53 | unsigned int irq_nr = irq - JMR3927_IRQ_IOC; | 53 | unsigned int irq_nr = d->irq - JMR3927_IRQ_IOC; |
54 | unsigned char imask = jmr3927_ioc_reg_in(JMR3927_IOC_INTM_ADDR); | 54 | unsigned char imask = jmr3927_ioc_reg_in(JMR3927_IOC_INTM_ADDR); |
55 | unsigned int bit = 1 << irq_nr; | 55 | unsigned int bit = 1 << irq_nr; |
56 | jmr3927_ioc_reg_out(imask & ~bit, JMR3927_IOC_INTM_ADDR); | 56 | jmr3927_ioc_reg_out(imask & ~bit, JMR3927_IOC_INTM_ADDR); |
57 | /* flush write buffer */ | 57 | /* flush write buffer */ |
58 | (void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR); | 58 | (void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR); |
59 | } | 59 | } |
60 | static void unmask_irq_ioc(unsigned int irq) | 60 | static void unmask_irq_ioc(struct irq_data *d) |
61 | { | 61 | { |
62 | /* 0: mask */ | 62 | /* 0: mask */ |
63 | unsigned int irq_nr = irq - JMR3927_IRQ_IOC; | 63 | unsigned int irq_nr = d->irq - JMR3927_IRQ_IOC; |
64 | unsigned char imask = jmr3927_ioc_reg_in(JMR3927_IOC_INTM_ADDR); | 64 | unsigned char imask = jmr3927_ioc_reg_in(JMR3927_IOC_INTM_ADDR); |
65 | unsigned int bit = 1 << irq_nr; | 65 | unsigned int bit = 1 << irq_nr; |
66 | jmr3927_ioc_reg_out(imask | bit, JMR3927_IOC_INTM_ADDR); | 66 | jmr3927_ioc_reg_out(imask | bit, JMR3927_IOC_INTM_ADDR); |
@@ -95,10 +95,8 @@ static int jmr3927_irq_dispatch(int pending) | |||
95 | 95 | ||
96 | static struct irq_chip jmr3927_irq_ioc = { | 96 | static struct irq_chip jmr3927_irq_ioc = { |
97 | .name = "jmr3927_ioc", | 97 | .name = "jmr3927_ioc", |
98 | .ack = mask_irq_ioc, | 98 | .irq_mask = mask_irq_ioc, |
99 | .mask = mask_irq_ioc, | 99 | .irq_unmask = unmask_irq_ioc, |
100 | .mask_ack = mask_irq_ioc, | ||
101 | .unmask = unmask_irq_ioc, | ||
102 | }; | 100 | }; |
103 | 101 | ||
104 | void __init jmr3927_irq_setup(void) | 102 | void __init jmr3927_irq_setup(void) |
diff --git a/arch/mips/txx9/rbtx4927/irq.c b/arch/mips/txx9/rbtx4927/irq.c index c4b54d20efd3..7c0a048b307c 100644 --- a/arch/mips/txx9/rbtx4927/irq.c +++ b/arch/mips/txx9/rbtx4927/irq.c | |||
@@ -117,18 +117,6 @@ | |||
117 | #include <asm/txx9/generic.h> | 117 | #include <asm/txx9/generic.h> |
118 | #include <asm/txx9/rbtx4927.h> | 118 | #include <asm/txx9/rbtx4927.h> |
119 | 119 | ||
120 | static void toshiba_rbtx4927_irq_ioc_enable(unsigned int irq); | ||
121 | static void toshiba_rbtx4927_irq_ioc_disable(unsigned int irq); | ||
122 | |||
123 | #define TOSHIBA_RBTX4927_IOC_NAME "RBTX4927-IOC" | ||
124 | static struct irq_chip toshiba_rbtx4927_irq_ioc_type = { | ||
125 | .name = TOSHIBA_RBTX4927_IOC_NAME, | ||
126 | .ack = toshiba_rbtx4927_irq_ioc_disable, | ||
127 | .mask = toshiba_rbtx4927_irq_ioc_disable, | ||
128 | .mask_ack = toshiba_rbtx4927_irq_ioc_disable, | ||
129 | .unmask = toshiba_rbtx4927_irq_ioc_enable, | ||
130 | }; | ||
131 | |||
132 | static int toshiba_rbtx4927_irq_nested(int sw_irq) | 120 | static int toshiba_rbtx4927_irq_nested(int sw_irq) |
133 | { | 121 | { |
134 | u8 level3; | 122 | u8 level3; |
@@ -139,41 +127,47 @@ static int toshiba_rbtx4927_irq_nested(int sw_irq) | |||
139 | return RBTX4927_IRQ_IOC + __fls8(level3); | 127 | return RBTX4927_IRQ_IOC + __fls8(level3); |
140 | } | 128 | } |
141 | 129 | ||
142 | static void __init toshiba_rbtx4927_irq_ioc_init(void) | 130 | static void toshiba_rbtx4927_irq_ioc_enable(struct irq_data *d) |
143 | { | ||
144 | int i; | ||
145 | |||
146 | /* mask all IOC interrupts */ | ||
147 | writeb(0, rbtx4927_imask_addr); | ||
148 | /* clear SoftInt interrupts */ | ||
149 | writeb(0, rbtx4927_softint_addr); | ||
150 | |||
151 | for (i = RBTX4927_IRQ_IOC; | ||
152 | i < RBTX4927_IRQ_IOC + RBTX4927_NR_IRQ_IOC; i++) | ||
153 | set_irq_chip_and_handler(i, &toshiba_rbtx4927_irq_ioc_type, | ||
154 | handle_level_irq); | ||
155 | set_irq_chained_handler(RBTX4927_IRQ_IOCINT, handle_simple_irq); | ||
156 | } | ||
157 | |||
158 | static void toshiba_rbtx4927_irq_ioc_enable(unsigned int irq) | ||
159 | { | 131 | { |
160 | unsigned char v; | 132 | unsigned char v; |
161 | 133 | ||
162 | v = readb(rbtx4927_imask_addr); | 134 | v = readb(rbtx4927_imask_addr); |
163 | v |= (1 << (irq - RBTX4927_IRQ_IOC)); | 135 | v |= (1 << (d->irq - RBTX4927_IRQ_IOC)); |
164 | writeb(v, rbtx4927_imask_addr); | 136 | writeb(v, rbtx4927_imask_addr); |
165 | } | 137 | } |
166 | 138 | ||
167 | static void toshiba_rbtx4927_irq_ioc_disable(unsigned int irq) | 139 | static void toshiba_rbtx4927_irq_ioc_disable(struct irq_data *d) |
168 | { | 140 | { |
169 | unsigned char v; | 141 | unsigned char v; |
170 | 142 | ||
171 | v = readb(rbtx4927_imask_addr); | 143 | v = readb(rbtx4927_imask_addr); |
172 | v &= ~(1 << (irq - RBTX4927_IRQ_IOC)); | 144 | v &= ~(1 << (d->irq - RBTX4927_IRQ_IOC)); |
173 | writeb(v, rbtx4927_imask_addr); | 145 | writeb(v, rbtx4927_imask_addr); |
174 | mmiowb(); | 146 | mmiowb(); |
175 | } | 147 | } |
176 | 148 | ||
149 | #define TOSHIBA_RBTX4927_IOC_NAME "RBTX4927-IOC" | ||
150 | static struct irq_chip toshiba_rbtx4927_irq_ioc_type = { | ||
151 | .name = TOSHIBA_RBTX4927_IOC_NAME, | ||
152 | .irq_mask = toshiba_rbtx4927_irq_ioc_disable, | ||
153 | .irq_unmask = toshiba_rbtx4927_irq_ioc_enable, | ||
154 | }; | ||
155 | |||
156 | static void __init toshiba_rbtx4927_irq_ioc_init(void) | ||
157 | { | ||
158 | int i; | ||
159 | |||
160 | /* mask all IOC interrupts */ | ||
161 | writeb(0, rbtx4927_imask_addr); | ||
162 | /* clear SoftInt interrupts */ | ||
163 | writeb(0, rbtx4927_softint_addr); | ||
164 | |||
165 | for (i = RBTX4927_IRQ_IOC; | ||
166 | i < RBTX4927_IRQ_IOC + RBTX4927_NR_IRQ_IOC; i++) | ||
167 | set_irq_chip_and_handler(i, &toshiba_rbtx4927_irq_ioc_type, | ||
168 | handle_level_irq); | ||
169 | set_irq_chained_handler(RBTX4927_IRQ_IOCINT, handle_simple_irq); | ||
170 | } | ||
177 | 171 | ||
178 | static int rbtx4927_irq_dispatch(int pending) | 172 | static int rbtx4927_irq_dispatch(int pending) |
179 | { | 173 | { |
diff --git a/arch/mips/txx9/rbtx4938/irq.c b/arch/mips/txx9/rbtx4938/irq.c index 67a73a8065ec..2ec4fe1b1670 100644 --- a/arch/mips/txx9/rbtx4938/irq.c +++ b/arch/mips/txx9/rbtx4938/irq.c | |||
@@ -69,18 +69,6 @@ | |||
69 | #include <asm/txx9/generic.h> | 69 | #include <asm/txx9/generic.h> |
70 | #include <asm/txx9/rbtx4938.h> | 70 | #include <asm/txx9/rbtx4938.h> |
71 | 71 | ||
72 | static void toshiba_rbtx4938_irq_ioc_enable(unsigned int irq); | ||
73 | static void toshiba_rbtx4938_irq_ioc_disable(unsigned int irq); | ||
74 | |||
75 | #define TOSHIBA_RBTX4938_IOC_NAME "RBTX4938-IOC" | ||
76 | static struct irq_chip toshiba_rbtx4938_irq_ioc_type = { | ||
77 | .name = TOSHIBA_RBTX4938_IOC_NAME, | ||
78 | .ack = toshiba_rbtx4938_irq_ioc_disable, | ||
79 | .mask = toshiba_rbtx4938_irq_ioc_disable, | ||
80 | .mask_ack = toshiba_rbtx4938_irq_ioc_disable, | ||
81 | .unmask = toshiba_rbtx4938_irq_ioc_enable, | ||
82 | }; | ||
83 | |||
84 | static int toshiba_rbtx4938_irq_nested(int sw_irq) | 72 | static int toshiba_rbtx4938_irq_nested(int sw_irq) |
85 | { | 73 | { |
86 | u8 level3; | 74 | u8 level3; |
@@ -92,41 +80,33 @@ static int toshiba_rbtx4938_irq_nested(int sw_irq) | |||
92 | return RBTX4938_IRQ_IOC + __fls8(level3); | 80 | return RBTX4938_IRQ_IOC + __fls8(level3); |
93 | } | 81 | } |
94 | 82 | ||
95 | static void __init | 83 | static void toshiba_rbtx4938_irq_ioc_enable(struct irq_data *d) |
96 | toshiba_rbtx4938_irq_ioc_init(void) | ||
97 | { | ||
98 | int i; | ||
99 | |||
100 | for (i = RBTX4938_IRQ_IOC; | ||
101 | i < RBTX4938_IRQ_IOC + RBTX4938_NR_IRQ_IOC; i++) | ||
102 | set_irq_chip_and_handler(i, &toshiba_rbtx4938_irq_ioc_type, | ||
103 | handle_level_irq); | ||
104 | |||
105 | set_irq_chained_handler(RBTX4938_IRQ_IOCINT, handle_simple_irq); | ||
106 | } | ||
107 | |||
108 | static void | ||
109 | toshiba_rbtx4938_irq_ioc_enable(unsigned int irq) | ||
110 | { | 84 | { |
111 | unsigned char v; | 85 | unsigned char v; |
112 | 86 | ||
113 | v = readb(rbtx4938_imask_addr); | 87 | v = readb(rbtx4938_imask_addr); |
114 | v |= (1 << (irq - RBTX4938_IRQ_IOC)); | 88 | v |= (1 << (d->irq - RBTX4938_IRQ_IOC)); |
115 | writeb(v, rbtx4938_imask_addr); | 89 | writeb(v, rbtx4938_imask_addr); |
116 | mmiowb(); | 90 | mmiowb(); |
117 | } | 91 | } |
118 | 92 | ||
119 | static void | 93 | static void toshiba_rbtx4938_irq_ioc_disable(struct irq_data *d) |
120 | toshiba_rbtx4938_irq_ioc_disable(unsigned int irq) | ||
121 | { | 94 | { |
122 | unsigned char v; | 95 | unsigned char v; |
123 | 96 | ||
124 | v = readb(rbtx4938_imask_addr); | 97 | v = readb(rbtx4938_imask_addr); |
125 | v &= ~(1 << (irq - RBTX4938_IRQ_IOC)); | 98 | v &= ~(1 << (d->irq - RBTX4938_IRQ_IOC)); |
126 | writeb(v, rbtx4938_imask_addr); | 99 | writeb(v, rbtx4938_imask_addr); |
127 | mmiowb(); | 100 | mmiowb(); |
128 | } | 101 | } |
129 | 102 | ||
103 | #define TOSHIBA_RBTX4938_IOC_NAME "RBTX4938-IOC" | ||
104 | static struct irq_chip toshiba_rbtx4938_irq_ioc_type = { | ||
105 | .name = TOSHIBA_RBTX4938_IOC_NAME, | ||
106 | .irq_mask = toshiba_rbtx4938_irq_ioc_disable, | ||
107 | .irq_unmask = toshiba_rbtx4938_irq_ioc_enable, | ||
108 | }; | ||
109 | |||
130 | static int rbtx4938_irq_dispatch(int pending) | 110 | static int rbtx4938_irq_dispatch(int pending) |
131 | { | 111 | { |
132 | int irq; | 112 | int irq; |
@@ -146,6 +126,18 @@ static int rbtx4938_irq_dispatch(int pending) | |||
146 | return irq; | 126 | return irq; |
147 | } | 127 | } |
148 | 128 | ||
129 | static void __init toshiba_rbtx4938_irq_ioc_init(void) | ||
130 | { | ||
131 | int i; | ||
132 | |||
133 | for (i = RBTX4938_IRQ_IOC; | ||
134 | i < RBTX4938_IRQ_IOC + RBTX4938_NR_IRQ_IOC; i++) | ||
135 | set_irq_chip_and_handler(i, &toshiba_rbtx4938_irq_ioc_type, | ||
136 | handle_level_irq); | ||
137 | |||
138 | set_irq_chained_handler(RBTX4938_IRQ_IOCINT, handle_simple_irq); | ||
139 | } | ||
140 | |||
149 | void __init rbtx4938_irq_setup(void) | 141 | void __init rbtx4938_irq_setup(void) |
150 | { | 142 | { |
151 | txx9_irq_dispatch = rbtx4938_irq_dispatch; | 143 | txx9_irq_dispatch = rbtx4938_irq_dispatch; |
diff --git a/arch/mips/txx9/rbtx4939/irq.c b/arch/mips/txx9/rbtx4939/irq.c index 57fa740a7205..70074632fb99 100644 --- a/arch/mips/txx9/rbtx4939/irq.c +++ b/arch/mips/txx9/rbtx4939/irq.c | |||
@@ -19,16 +19,16 @@ | |||
19 | * RBTX4939 IOC controller definition | 19 | * RBTX4939 IOC controller definition |
20 | */ | 20 | */ |
21 | 21 | ||
22 | static void rbtx4939_ioc_irq_unmask(unsigned int irq) | 22 | static void rbtx4939_ioc_irq_unmask(struct irq_data *d) |
23 | { | 23 | { |
24 | int ioc_nr = irq - RBTX4939_IRQ_IOC; | 24 | int ioc_nr = d->irq - RBTX4939_IRQ_IOC; |
25 | 25 | ||
26 | writeb(readb(rbtx4939_ien_addr) | (1 << ioc_nr), rbtx4939_ien_addr); | 26 | writeb(readb(rbtx4939_ien_addr) | (1 << ioc_nr), rbtx4939_ien_addr); |
27 | } | 27 | } |
28 | 28 | ||
29 | static void rbtx4939_ioc_irq_mask(unsigned int irq) | 29 | static void rbtx4939_ioc_irq_mask(struct irq_data *d) |
30 | { | 30 | { |
31 | int ioc_nr = irq - RBTX4939_IRQ_IOC; | 31 | int ioc_nr = d->irq - RBTX4939_IRQ_IOC; |
32 | 32 | ||
33 | writeb(readb(rbtx4939_ien_addr) & ~(1 << ioc_nr), rbtx4939_ien_addr); | 33 | writeb(readb(rbtx4939_ien_addr) & ~(1 << ioc_nr), rbtx4939_ien_addr); |
34 | mmiowb(); | 34 | mmiowb(); |
@@ -36,10 +36,8 @@ static void rbtx4939_ioc_irq_mask(unsigned int irq) | |||
36 | 36 | ||
37 | static struct irq_chip rbtx4939_ioc_irq_chip = { | 37 | static struct irq_chip rbtx4939_ioc_irq_chip = { |
38 | .name = "IOC", | 38 | .name = "IOC", |
39 | .ack = rbtx4939_ioc_irq_mask, | 39 | .irq_mask = rbtx4939_ioc_irq_mask, |
40 | .mask = rbtx4939_ioc_irq_mask, | 40 | .irq_unmask = rbtx4939_ioc_irq_unmask, |
41 | .mask_ack = rbtx4939_ioc_irq_mask, | ||
42 | .unmask = rbtx4939_ioc_irq_unmask, | ||
43 | }; | 41 | }; |
44 | 42 | ||
45 | 43 | ||
diff --git a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c index 6153b6a05ccf..f53156bb9aa8 100644 --- a/arch/mips/vr41xx/common/icu.c +++ b/arch/mips/vr41xx/common/icu.c | |||
@@ -154,7 +154,7 @@ static inline uint16_t icu2_clear(uint8_t offset, uint16_t clear) | |||
154 | 154 | ||
155 | void vr41xx_enable_piuint(uint16_t mask) | 155 | void vr41xx_enable_piuint(uint16_t mask) |
156 | { | 156 | { |
157 | struct irq_desc *desc = irq_desc + PIU_IRQ; | 157 | struct irq_desc *desc = irq_to_desc(PIU_IRQ); |
158 | unsigned long flags; | 158 | unsigned long flags; |
159 | 159 | ||
160 | if (current_cpu_type() == CPU_VR4111 || | 160 | if (current_cpu_type() == CPU_VR4111 || |
@@ -169,7 +169,7 @@ EXPORT_SYMBOL(vr41xx_enable_piuint); | |||
169 | 169 | ||
170 | void vr41xx_disable_piuint(uint16_t mask) | 170 | void vr41xx_disable_piuint(uint16_t mask) |
171 | { | 171 | { |
172 | struct irq_desc *desc = irq_desc + PIU_IRQ; | 172 | struct irq_desc *desc = irq_to_desc(PIU_IRQ); |
173 | unsigned long flags; | 173 | unsigned long flags; |
174 | 174 | ||
175 | if (current_cpu_type() == CPU_VR4111 || | 175 | if (current_cpu_type() == CPU_VR4111 || |
@@ -184,7 +184,7 @@ EXPORT_SYMBOL(vr41xx_disable_piuint); | |||
184 | 184 | ||
185 | void vr41xx_enable_aiuint(uint16_t mask) | 185 | void vr41xx_enable_aiuint(uint16_t mask) |
186 | { | 186 | { |
187 | struct irq_desc *desc = irq_desc + AIU_IRQ; | 187 | struct irq_desc *desc = irq_to_desc(AIU_IRQ); |
188 | unsigned long flags; | 188 | unsigned long flags; |
189 | 189 | ||
190 | if (current_cpu_type() == CPU_VR4111 || | 190 | if (current_cpu_type() == CPU_VR4111 || |
@@ -199,7 +199,7 @@ EXPORT_SYMBOL(vr41xx_enable_aiuint); | |||
199 | 199 | ||
200 | void vr41xx_disable_aiuint(uint16_t mask) | 200 | void vr41xx_disable_aiuint(uint16_t mask) |
201 | { | 201 | { |
202 | struct irq_desc *desc = irq_desc + AIU_IRQ; | 202 | struct irq_desc *desc = irq_to_desc(AIU_IRQ); |
203 | unsigned long flags; | 203 | unsigned long flags; |
204 | 204 | ||
205 | if (current_cpu_type() == CPU_VR4111 || | 205 | if (current_cpu_type() == CPU_VR4111 || |
@@ -214,7 +214,7 @@ EXPORT_SYMBOL(vr41xx_disable_aiuint); | |||
214 | 214 | ||
215 | void vr41xx_enable_kiuint(uint16_t mask) | 215 | void vr41xx_enable_kiuint(uint16_t mask) |
216 | { | 216 | { |
217 | struct irq_desc *desc = irq_desc + KIU_IRQ; | 217 | struct irq_desc *desc = irq_to_desc(KIU_IRQ); |
218 | unsigned long flags; | 218 | unsigned long flags; |
219 | 219 | ||
220 | if (current_cpu_type() == CPU_VR4111 || | 220 | if (current_cpu_type() == CPU_VR4111 || |
@@ -229,7 +229,7 @@ EXPORT_SYMBOL(vr41xx_enable_kiuint); | |||
229 | 229 | ||
230 | void vr41xx_disable_kiuint(uint16_t mask) | 230 | void vr41xx_disable_kiuint(uint16_t mask) |
231 | { | 231 | { |
232 | struct irq_desc *desc = irq_desc + KIU_IRQ; | 232 | struct irq_desc *desc = irq_to_desc(KIU_IRQ); |
233 | unsigned long flags; | 233 | unsigned long flags; |
234 | 234 | ||
235 | if (current_cpu_type() == CPU_VR4111 || | 235 | if (current_cpu_type() == CPU_VR4111 || |
@@ -244,7 +244,7 @@ EXPORT_SYMBOL(vr41xx_disable_kiuint); | |||
244 | 244 | ||
245 | void vr41xx_enable_macint(uint16_t mask) | 245 | void vr41xx_enable_macint(uint16_t mask) |
246 | { | 246 | { |
247 | struct irq_desc *desc = irq_desc + ETHERNET_IRQ; | 247 | struct irq_desc *desc = irq_to_desc(ETHERNET_IRQ); |
248 | unsigned long flags; | 248 | unsigned long flags; |
249 | 249 | ||
250 | raw_spin_lock_irqsave(&desc->lock, flags); | 250 | raw_spin_lock_irqsave(&desc->lock, flags); |
@@ -256,7 +256,7 @@ EXPORT_SYMBOL(vr41xx_enable_macint); | |||
256 | 256 | ||
257 | void vr41xx_disable_macint(uint16_t mask) | 257 | void vr41xx_disable_macint(uint16_t mask) |
258 | { | 258 | { |
259 | struct irq_desc *desc = irq_desc + ETHERNET_IRQ; | 259 | struct irq_desc *desc = irq_to_desc(ETHERNET_IRQ); |
260 | unsigned long flags; | 260 | unsigned long flags; |
261 | 261 | ||
262 | raw_spin_lock_irqsave(&desc->lock, flags); | 262 | raw_spin_lock_irqsave(&desc->lock, flags); |
@@ -268,7 +268,7 @@ EXPORT_SYMBOL(vr41xx_disable_macint); | |||
268 | 268 | ||
269 | void vr41xx_enable_dsiuint(uint16_t mask) | 269 | void vr41xx_enable_dsiuint(uint16_t mask) |
270 | { | 270 | { |
271 | struct irq_desc *desc = irq_desc + DSIU_IRQ; | 271 | struct irq_desc *desc = irq_to_desc(DSIU_IRQ); |
272 | unsigned long flags; | 272 | unsigned long flags; |
273 | 273 | ||
274 | raw_spin_lock_irqsave(&desc->lock, flags); | 274 | raw_spin_lock_irqsave(&desc->lock, flags); |
@@ -280,7 +280,7 @@ EXPORT_SYMBOL(vr41xx_enable_dsiuint); | |||
280 | 280 | ||
281 | void vr41xx_disable_dsiuint(uint16_t mask) | 281 | void vr41xx_disable_dsiuint(uint16_t mask) |
282 | { | 282 | { |
283 | struct irq_desc *desc = irq_desc + DSIU_IRQ; | 283 | struct irq_desc *desc = irq_to_desc(DSIU_IRQ); |
284 | unsigned long flags; | 284 | unsigned long flags; |
285 | 285 | ||
286 | raw_spin_lock_irqsave(&desc->lock, flags); | 286 | raw_spin_lock_irqsave(&desc->lock, flags); |
@@ -292,7 +292,7 @@ EXPORT_SYMBOL(vr41xx_disable_dsiuint); | |||
292 | 292 | ||
293 | void vr41xx_enable_firint(uint16_t mask) | 293 | void vr41xx_enable_firint(uint16_t mask) |
294 | { | 294 | { |
295 | struct irq_desc *desc = irq_desc + FIR_IRQ; | 295 | struct irq_desc *desc = irq_to_desc(FIR_IRQ); |
296 | unsigned long flags; | 296 | unsigned long flags; |
297 | 297 | ||
298 | raw_spin_lock_irqsave(&desc->lock, flags); | 298 | raw_spin_lock_irqsave(&desc->lock, flags); |
@@ -304,7 +304,7 @@ EXPORT_SYMBOL(vr41xx_enable_firint); | |||
304 | 304 | ||
305 | void vr41xx_disable_firint(uint16_t mask) | 305 | void vr41xx_disable_firint(uint16_t mask) |
306 | { | 306 | { |
307 | struct irq_desc *desc = irq_desc + FIR_IRQ; | 307 | struct irq_desc *desc = irq_to_desc(FIR_IRQ); |
308 | unsigned long flags; | 308 | unsigned long flags; |
309 | 309 | ||
310 | raw_spin_lock_irqsave(&desc->lock, flags); | 310 | raw_spin_lock_irqsave(&desc->lock, flags); |
@@ -316,7 +316,7 @@ EXPORT_SYMBOL(vr41xx_disable_firint); | |||
316 | 316 | ||
317 | void vr41xx_enable_pciint(void) | 317 | void vr41xx_enable_pciint(void) |
318 | { | 318 | { |
319 | struct irq_desc *desc = irq_desc + PCI_IRQ; | 319 | struct irq_desc *desc = irq_to_desc(PCI_IRQ); |
320 | unsigned long flags; | 320 | unsigned long flags; |
321 | 321 | ||
322 | if (current_cpu_type() == CPU_VR4122 || | 322 | if (current_cpu_type() == CPU_VR4122 || |
@@ -332,7 +332,7 @@ EXPORT_SYMBOL(vr41xx_enable_pciint); | |||
332 | 332 | ||
333 | void vr41xx_disable_pciint(void) | 333 | void vr41xx_disable_pciint(void) |
334 | { | 334 | { |
335 | struct irq_desc *desc = irq_desc + PCI_IRQ; | 335 | struct irq_desc *desc = irq_to_desc(PCI_IRQ); |
336 | unsigned long flags; | 336 | unsigned long flags; |
337 | 337 | ||
338 | if (current_cpu_type() == CPU_VR4122 || | 338 | if (current_cpu_type() == CPU_VR4122 || |
@@ -348,7 +348,7 @@ EXPORT_SYMBOL(vr41xx_disable_pciint); | |||
348 | 348 | ||
349 | void vr41xx_enable_scuint(void) | 349 | void vr41xx_enable_scuint(void) |
350 | { | 350 | { |
351 | struct irq_desc *desc = irq_desc + SCU_IRQ; | 351 | struct irq_desc *desc = irq_to_desc(SCU_IRQ); |
352 | unsigned long flags; | 352 | unsigned long flags; |
353 | 353 | ||
354 | if (current_cpu_type() == CPU_VR4122 || | 354 | if (current_cpu_type() == CPU_VR4122 || |
@@ -364,7 +364,7 @@ EXPORT_SYMBOL(vr41xx_enable_scuint); | |||
364 | 364 | ||
365 | void vr41xx_disable_scuint(void) | 365 | void vr41xx_disable_scuint(void) |
366 | { | 366 | { |
367 | struct irq_desc *desc = irq_desc + SCU_IRQ; | 367 | struct irq_desc *desc = irq_to_desc(SCU_IRQ); |
368 | unsigned long flags; | 368 | unsigned long flags; |
369 | 369 | ||
370 | if (current_cpu_type() == CPU_VR4122 || | 370 | if (current_cpu_type() == CPU_VR4122 || |
@@ -380,7 +380,7 @@ EXPORT_SYMBOL(vr41xx_disable_scuint); | |||
380 | 380 | ||
381 | void vr41xx_enable_csiint(uint16_t mask) | 381 | void vr41xx_enable_csiint(uint16_t mask) |
382 | { | 382 | { |
383 | struct irq_desc *desc = irq_desc + CSI_IRQ; | 383 | struct irq_desc *desc = irq_to_desc(CSI_IRQ); |
384 | unsigned long flags; | 384 | unsigned long flags; |
385 | 385 | ||
386 | if (current_cpu_type() == CPU_VR4122 || | 386 | if (current_cpu_type() == CPU_VR4122 || |
@@ -396,7 +396,7 @@ EXPORT_SYMBOL(vr41xx_enable_csiint); | |||
396 | 396 | ||
397 | void vr41xx_disable_csiint(uint16_t mask) | 397 | void vr41xx_disable_csiint(uint16_t mask) |
398 | { | 398 | { |
399 | struct irq_desc *desc = irq_desc + CSI_IRQ; | 399 | struct irq_desc *desc = irq_to_desc(CSI_IRQ); |
400 | unsigned long flags; | 400 | unsigned long flags; |
401 | 401 | ||
402 | if (current_cpu_type() == CPU_VR4122 || | 402 | if (current_cpu_type() == CPU_VR4122 || |
@@ -412,7 +412,7 @@ EXPORT_SYMBOL(vr41xx_disable_csiint); | |||
412 | 412 | ||
413 | void vr41xx_enable_bcuint(void) | 413 | void vr41xx_enable_bcuint(void) |
414 | { | 414 | { |
415 | struct irq_desc *desc = irq_desc + BCU_IRQ; | 415 | struct irq_desc *desc = irq_to_desc(BCU_IRQ); |
416 | unsigned long flags; | 416 | unsigned long flags; |
417 | 417 | ||
418 | if (current_cpu_type() == CPU_VR4122 || | 418 | if (current_cpu_type() == CPU_VR4122 || |
@@ -428,7 +428,7 @@ EXPORT_SYMBOL(vr41xx_enable_bcuint); | |||
428 | 428 | ||
429 | void vr41xx_disable_bcuint(void) | 429 | void vr41xx_disable_bcuint(void) |
430 | { | 430 | { |
431 | struct irq_desc *desc = irq_desc + BCU_IRQ; | 431 | struct irq_desc *desc = irq_to_desc(BCU_IRQ); |
432 | unsigned long flags; | 432 | unsigned long flags; |
433 | 433 | ||
434 | if (current_cpu_type() == CPU_VR4122 || | 434 | if (current_cpu_type() == CPU_VR4122 || |
@@ -442,45 +442,41 @@ void vr41xx_disable_bcuint(void) | |||
442 | 442 | ||
443 | EXPORT_SYMBOL(vr41xx_disable_bcuint); | 443 | EXPORT_SYMBOL(vr41xx_disable_bcuint); |
444 | 444 | ||
445 | static void disable_sysint1_irq(unsigned int irq) | 445 | static void disable_sysint1_irq(struct irq_data *d) |
446 | { | 446 | { |
447 | icu1_clear(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(irq)); | 447 | icu1_clear(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(d->irq)); |
448 | } | 448 | } |
449 | 449 | ||
450 | static void enable_sysint1_irq(unsigned int irq) | 450 | static void enable_sysint1_irq(struct irq_data *d) |
451 | { | 451 | { |
452 | icu1_set(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(irq)); | 452 | icu1_set(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(d->irq)); |
453 | } | 453 | } |
454 | 454 | ||
455 | static struct irq_chip sysint1_irq_type = { | 455 | static struct irq_chip sysint1_irq_type = { |
456 | .name = "SYSINT1", | 456 | .name = "SYSINT1", |
457 | .ack = disable_sysint1_irq, | 457 | .irq_mask = disable_sysint1_irq, |
458 | .mask = disable_sysint1_irq, | 458 | .irq_unmask = enable_sysint1_irq, |
459 | .mask_ack = disable_sysint1_irq, | ||
460 | .unmask = enable_sysint1_irq, | ||
461 | }; | 459 | }; |
462 | 460 | ||
463 | static void disable_sysint2_irq(unsigned int irq) | 461 | static void disable_sysint2_irq(struct irq_data *d) |
464 | { | 462 | { |
465 | icu2_clear(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(irq)); | 463 | icu2_clear(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(d->irq)); |
466 | } | 464 | } |
467 | 465 | ||
468 | static void enable_sysint2_irq(unsigned int irq) | 466 | static void enable_sysint2_irq(struct irq_data *d) |
469 | { | 467 | { |
470 | icu2_set(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(irq)); | 468 | icu2_set(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(d->irq)); |
471 | } | 469 | } |
472 | 470 | ||
473 | static struct irq_chip sysint2_irq_type = { | 471 | static struct irq_chip sysint2_irq_type = { |
474 | .name = "SYSINT2", | 472 | .name = "SYSINT2", |
475 | .ack = disable_sysint2_irq, | 473 | .irq_mask = disable_sysint2_irq, |
476 | .mask = disable_sysint2_irq, | 474 | .irq_unmask = enable_sysint2_irq, |
477 | .mask_ack = disable_sysint2_irq, | ||
478 | .unmask = enable_sysint2_irq, | ||
479 | }; | 475 | }; |
480 | 476 | ||
481 | static inline int set_sysint1_assign(unsigned int irq, unsigned char assign) | 477 | static inline int set_sysint1_assign(unsigned int irq, unsigned char assign) |
482 | { | 478 | { |
483 | struct irq_desc *desc = irq_desc + irq; | 479 | struct irq_desc *desc = irq_to_desc(irq); |
484 | uint16_t intassign0, intassign1; | 480 | uint16_t intassign0, intassign1; |
485 | unsigned int pin; | 481 | unsigned int pin; |
486 | 482 | ||
@@ -540,7 +536,7 @@ static inline int set_sysint1_assign(unsigned int irq, unsigned char assign) | |||
540 | 536 | ||
541 | static inline int set_sysint2_assign(unsigned int irq, unsigned char assign) | 537 | static inline int set_sysint2_assign(unsigned int irq, unsigned char assign) |
542 | { | 538 | { |
543 | struct irq_desc *desc = irq_desc + irq; | 539 | struct irq_desc *desc = irq_to_desc(irq); |
544 | uint16_t intassign2, intassign3; | 540 | uint16_t intassign2, intassign3; |
545 | unsigned int pin; | 541 | unsigned int pin; |
546 | 542 | ||
diff --git a/arch/mips/vr41xx/common/irq.c b/arch/mips/vr41xx/common/irq.c index 0975eb72d385..9ff7f397c0e1 100644 --- a/arch/mips/vr41xx/common/irq.c +++ b/arch/mips/vr41xx/common/irq.c | |||
@@ -62,7 +62,6 @@ EXPORT_SYMBOL_GPL(cascade_irq); | |||
62 | static void irq_dispatch(unsigned int irq) | 62 | static void irq_dispatch(unsigned int irq) |
63 | { | 63 | { |
64 | irq_cascade_t *cascade; | 64 | irq_cascade_t *cascade; |
65 | struct irq_desc *desc; | ||
66 | 65 | ||
67 | if (irq >= NR_IRQS) { | 66 | if (irq >= NR_IRQS) { |
68 | atomic_inc(&irq_err_count); | 67 | atomic_inc(&irq_err_count); |
@@ -71,14 +70,16 @@ static void irq_dispatch(unsigned int irq) | |||
71 | 70 | ||
72 | cascade = irq_cascade + irq; | 71 | cascade = irq_cascade + irq; |
73 | if (cascade->get_irq != NULL) { | 72 | if (cascade->get_irq != NULL) { |
74 | unsigned int source_irq = irq; | 73 | struct irq_desc *desc = irq_to_desc(irq); |
74 | struct irq_data *idata = irq_desc_get_irq_data(desc); | ||
75 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
75 | int ret; | 76 | int ret; |
76 | desc = irq_desc + source_irq; | 77 | |
77 | if (desc->chip->mask_ack) | 78 | if (chip->irq_mask_ack) |
78 | desc->chip->mask_ack(source_irq); | 79 | chip->irq_mask_ack(idata); |
79 | else { | 80 | else { |
80 | desc->chip->mask(source_irq); | 81 | chip->irq_mask(idata); |
81 | desc->chip->ack(source_irq); | 82 | chip->irq_ack(idata); |
82 | } | 83 | } |
83 | ret = cascade->get_irq(irq); | 84 | ret = cascade->get_irq(irq); |
84 | irq = ret; | 85 | irq = ret; |
@@ -86,8 +87,8 @@ static void irq_dispatch(unsigned int irq) | |||
86 | atomic_inc(&irq_err_count); | 87 | atomic_inc(&irq_err_count); |
87 | else | 88 | else |
88 | irq_dispatch(irq); | 89 | irq_dispatch(irq); |
89 | if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) | 90 | if (!(desc->status & IRQ_DISABLED) && chip->irq_unmask) |
90 | desc->chip->unmask(source_irq); | 91 | chip->irq_unmask(idata); |
91 | } else | 92 | } else |
92 | do_IRQ(irq); | 93 | do_IRQ(irq); |
93 | } | 94 | } |
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index f4f4d700833a..b7ed8d7a9b33 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c | |||
@@ -544,7 +544,7 @@ void __init mem_init(void) | |||
544 | unsigned long *empty_zero_page __read_mostly; | 544 | unsigned long *empty_zero_page __read_mostly; |
545 | EXPORT_SYMBOL(empty_zero_page); | 545 | EXPORT_SYMBOL(empty_zero_page); |
546 | 546 | ||
547 | void show_mem(void) | 547 | void show_mem(unsigned int filter) |
548 | { | 548 | { |
549 | int i,free = 0,total = 0,reserved = 0; | 549 | int i,free = 0,total = 0,reserved = 0; |
550 | int shared = 0, cached = 0; | 550 | int shared = 0, cached = 0; |
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index d17d04cfb2cd..33794c1d92c3 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c | |||
@@ -821,7 +821,7 @@ cmds(struct pt_regs *excp) | |||
821 | memzcan(); | 821 | memzcan(); |
822 | break; | 822 | break; |
823 | case 'i': | 823 | case 'i': |
824 | show_mem(); | 824 | show_mem(0); |
825 | break; | 825 | break; |
826 | default: | 826 | default: |
827 | termch = cmd; | 827 | termch = cmd; |
diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h index ff6f62e0ec3e..623f2fb71774 100644 --- a/arch/s390/include/asm/ccwdev.h +++ b/arch/s390/include/asm/ccwdev.h | |||
@@ -112,7 +112,6 @@ enum uc_todo { | |||
112 | 112 | ||
113 | /** | 113 | /** |
114 | * struct ccw driver - device driver for channel attached devices | 114 | * struct ccw driver - device driver for channel attached devices |
115 | * @owner: owning module | ||
116 | * @ids: ids supported by this driver | 115 | * @ids: ids supported by this driver |
117 | * @probe: function called on probe | 116 | * @probe: function called on probe |
118 | * @remove: function called on remove | 117 | * @remove: function called on remove |
@@ -128,10 +127,8 @@ enum uc_todo { | |||
128 | * @restore: callback for restoring after hibernation | 127 | * @restore: callback for restoring after hibernation |
129 | * @uc_handler: callback for unit check handler | 128 | * @uc_handler: callback for unit check handler |
130 | * @driver: embedded device driver structure | 129 | * @driver: embedded device driver structure |
131 | * @name: device driver name | ||
132 | */ | 130 | */ |
133 | struct ccw_driver { | 131 | struct ccw_driver { |
134 | struct module *owner; | ||
135 | struct ccw_device_id *ids; | 132 | struct ccw_device_id *ids; |
136 | int (*probe) (struct ccw_device *); | 133 | int (*probe) (struct ccw_device *); |
137 | void (*remove) (struct ccw_device *); | 134 | void (*remove) (struct ccw_device *); |
@@ -147,7 +144,6 @@ struct ccw_driver { | |||
147 | int (*restore)(struct ccw_device *); | 144 | int (*restore)(struct ccw_device *); |
148 | enum uc_todo (*uc_handler) (struct ccw_device *, struct irb *); | 145 | enum uc_todo (*uc_handler) (struct ccw_device *, struct irb *); |
149 | struct device_driver driver; | 146 | struct device_driver driver; |
150 | char *name; | ||
151 | }; | 147 | }; |
152 | 148 | ||
153 | extern struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv, | 149 | extern struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv, |
diff --git a/arch/s390/include/asm/ccwgroup.h b/arch/s390/include/asm/ccwgroup.h index c79c1e787b86..f2ea2c56a7e1 100644 --- a/arch/s390/include/asm/ccwgroup.h +++ b/arch/s390/include/asm/ccwgroup.h | |||
@@ -29,8 +29,6 @@ struct ccwgroup_device { | |||
29 | 29 | ||
30 | /** | 30 | /** |
31 | * struct ccwgroup_driver - driver for ccw group devices | 31 | * struct ccwgroup_driver - driver for ccw group devices |
32 | * @owner: driver owner | ||
33 | * @name: driver name | ||
34 | * @max_slaves: maximum number of slave devices | 32 | * @max_slaves: maximum number of slave devices |
35 | * @driver_id: unique id | 33 | * @driver_id: unique id |
36 | * @probe: function called on probe | 34 | * @probe: function called on probe |
@@ -46,8 +44,6 @@ struct ccwgroup_device { | |||
46 | * @driver: embedded driver structure | 44 | * @driver: embedded driver structure |
47 | */ | 45 | */ |
48 | struct ccwgroup_driver { | 46 | struct ccwgroup_driver { |
49 | struct module *owner; | ||
50 | char *name; | ||
51 | int max_slaves; | 47 | int max_slaves; |
52 | unsigned long driver_id; | 48 | unsigned long driver_id; |
53 | 49 | ||
diff --git a/arch/s390/include/asm/cmpxchg.h b/arch/s390/include/asm/cmpxchg.h new file mode 100644 index 000000000000..7488e52efa97 --- /dev/null +++ b/arch/s390/include/asm/cmpxchg.h | |||
@@ -0,0 +1,225 @@ | |||
1 | /* | ||
2 | * Copyright IBM Corp. 1999, 2011 | ||
3 | * | ||
4 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>, | ||
5 | */ | ||
6 | |||
7 | #ifndef __ASM_CMPXCHG_H | ||
8 | #define __ASM_CMPXCHG_H | ||
9 | |||
10 | #include <linux/types.h> | ||
11 | |||
12 | extern void __xchg_called_with_bad_pointer(void); | ||
13 | |||
14 | static inline unsigned long __xchg(unsigned long x, void *ptr, int size) | ||
15 | { | ||
16 | unsigned long addr, old; | ||
17 | int shift; | ||
18 | |||
19 | switch (size) { | ||
20 | case 1: | ||
21 | addr = (unsigned long) ptr; | ||
22 | shift = (3 ^ (addr & 3)) << 3; | ||
23 | addr ^= addr & 3; | ||
24 | asm volatile( | ||
25 | " l %0,%4\n" | ||
26 | "0: lr 0,%0\n" | ||
27 | " nr 0,%3\n" | ||
28 | " or 0,%2\n" | ||
29 | " cs %0,0,%4\n" | ||
30 | " jl 0b\n" | ||
31 | : "=&d" (old), "=Q" (*(int *) addr) | ||
32 | : "d" (x << shift), "d" (~(255 << shift)), | ||
33 | "Q" (*(int *) addr) : "memory", "cc", "0"); | ||
34 | return old >> shift; | ||
35 | case 2: | ||
36 | addr = (unsigned long) ptr; | ||
37 | shift = (2 ^ (addr & 2)) << 3; | ||
38 | addr ^= addr & 2; | ||
39 | asm volatile( | ||
40 | " l %0,%4\n" | ||
41 | "0: lr 0,%0\n" | ||
42 | " nr 0,%3\n" | ||
43 | " or 0,%2\n" | ||
44 | " cs %0,0,%4\n" | ||
45 | " jl 0b\n" | ||
46 | : "=&d" (old), "=Q" (*(int *) addr) | ||
47 | : "d" (x << shift), "d" (~(65535 << shift)), | ||
48 | "Q" (*(int *) addr) : "memory", "cc", "0"); | ||
49 | return old >> shift; | ||
50 | case 4: | ||
51 | asm volatile( | ||
52 | " l %0,%3\n" | ||
53 | "0: cs %0,%2,%3\n" | ||
54 | " jl 0b\n" | ||
55 | : "=&d" (old), "=Q" (*(int *) ptr) | ||
56 | : "d" (x), "Q" (*(int *) ptr) | ||
57 | : "memory", "cc"); | ||
58 | return old; | ||
59 | #ifdef CONFIG_64BIT | ||
60 | case 8: | ||
61 | asm volatile( | ||
62 | " lg %0,%3\n" | ||
63 | "0: csg %0,%2,%3\n" | ||
64 | " jl 0b\n" | ||
65 | : "=&d" (old), "=m" (*(long *) ptr) | ||
66 | : "d" (x), "Q" (*(long *) ptr) | ||
67 | : "memory", "cc"); | ||
68 | return old; | ||
69 | #endif /* CONFIG_64BIT */ | ||
70 | } | ||
71 | __xchg_called_with_bad_pointer(); | ||
72 | return x; | ||
73 | } | ||
74 | |||
75 | #define xchg(ptr, x) \ | ||
76 | ({ \ | ||
77 | __typeof__(*(ptr)) __ret; \ | ||
78 | __ret = (__typeof__(*(ptr))) \ | ||
79 | __xchg((unsigned long)(x), (void *)(ptr), sizeof(*(ptr)));\ | ||
80 | __ret; \ | ||
81 | }) | ||
82 | |||
83 | /* | ||
84 | * Atomic compare and exchange. Compare OLD with MEM, if identical, | ||
85 | * store NEW in MEM. Return the initial value in MEM. Success is | ||
86 | * indicated by comparing RETURN with OLD. | ||
87 | */ | ||
88 | |||
89 | #define __HAVE_ARCH_CMPXCHG | ||
90 | |||
91 | extern void __cmpxchg_called_with_bad_pointer(void); | ||
92 | |||
93 | static inline unsigned long __cmpxchg(void *ptr, unsigned long old, | ||
94 | unsigned long new, int size) | ||
95 | { | ||
96 | unsigned long addr, prev, tmp; | ||
97 | int shift; | ||
98 | |||
99 | switch (size) { | ||
100 | case 1: | ||
101 | addr = (unsigned long) ptr; | ||
102 | shift = (3 ^ (addr & 3)) << 3; | ||
103 | addr ^= addr & 3; | ||
104 | asm volatile( | ||
105 | " l %0,%2\n" | ||
106 | "0: nr %0,%5\n" | ||
107 | " lr %1,%0\n" | ||
108 | " or %0,%3\n" | ||
109 | " or %1,%4\n" | ||
110 | " cs %0,%1,%2\n" | ||
111 | " jnl 1f\n" | ||
112 | " xr %1,%0\n" | ||
113 | " nr %1,%5\n" | ||
114 | " jnz 0b\n" | ||
115 | "1:" | ||
116 | : "=&d" (prev), "=&d" (tmp), "=Q" (*(int *) ptr) | ||
117 | : "d" (old << shift), "d" (new << shift), | ||
118 | "d" (~(255 << shift)), "Q" (*(int *) ptr) | ||
119 | : "memory", "cc"); | ||
120 | return prev >> shift; | ||
121 | case 2: | ||
122 | addr = (unsigned long) ptr; | ||
123 | shift = (2 ^ (addr & 2)) << 3; | ||
124 | addr ^= addr & 2; | ||
125 | asm volatile( | ||
126 | " l %0,%2\n" | ||
127 | "0: nr %0,%5\n" | ||
128 | " lr %1,%0\n" | ||
129 | " or %0,%3\n" | ||
130 | " or %1,%4\n" | ||
131 | " cs %0,%1,%2\n" | ||
132 | " jnl 1f\n" | ||
133 | " xr %1,%0\n" | ||
134 | " nr %1,%5\n" | ||
135 | " jnz 0b\n" | ||
136 | "1:" | ||
137 | : "=&d" (prev), "=&d" (tmp), "=Q" (*(int *) ptr) | ||
138 | : "d" (old << shift), "d" (new << shift), | ||
139 | "d" (~(65535 << shift)), "Q" (*(int *) ptr) | ||
140 | : "memory", "cc"); | ||
141 | return prev >> shift; | ||
142 | case 4: | ||
143 | asm volatile( | ||
144 | " cs %0,%3,%1\n" | ||
145 | : "=&d" (prev), "=Q" (*(int *) ptr) | ||
146 | : "0" (old), "d" (new), "Q" (*(int *) ptr) | ||
147 | : "memory", "cc"); | ||
148 | return prev; | ||
149 | #ifdef CONFIG_64BIT | ||
150 | case 8: | ||
151 | asm volatile( | ||
152 | " csg %0,%3,%1\n" | ||
153 | : "=&d" (prev), "=Q" (*(long *) ptr) | ||
154 | : "0" (old), "d" (new), "Q" (*(long *) ptr) | ||
155 | : "memory", "cc"); | ||
156 | return prev; | ||
157 | #endif /* CONFIG_64BIT */ | ||
158 | } | ||
159 | __cmpxchg_called_with_bad_pointer(); | ||
160 | return old; | ||
161 | } | ||
162 | |||
163 | #define cmpxchg(ptr, o, n) \ | ||
164 | ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \ | ||
165 | (unsigned long)(n), sizeof(*(ptr)))) | ||
166 | |||
167 | #ifdef CONFIG_64BIT | ||
168 | #define cmpxchg64(ptr, o, n) \ | ||
169 | ({ \ | ||
170 | BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ | ||
171 | cmpxchg((ptr), (o), (n)); \ | ||
172 | }) | ||
173 | #else /* CONFIG_64BIT */ | ||
174 | static inline unsigned long long __cmpxchg64(void *ptr, | ||
175 | unsigned long long old, | ||
176 | unsigned long long new) | ||
177 | { | ||
178 | register_pair rp_old = {.pair = old}; | ||
179 | register_pair rp_new = {.pair = new}; | ||
180 | |||
181 | asm volatile( | ||
182 | " cds %0,%2,%1" | ||
183 | : "+&d" (rp_old), "=Q" (ptr) | ||
184 | : "d" (rp_new), "Q" (ptr) | ||
185 | : "cc"); | ||
186 | return rp_old.pair; | ||
187 | } | ||
188 | #define cmpxchg64(ptr, o, n) \ | ||
189 | ((__typeof__(*(ptr)))__cmpxchg64((ptr), \ | ||
190 | (unsigned long long)(o), \ | ||
191 | (unsigned long long)(n))) | ||
192 | #endif /* CONFIG_64BIT */ | ||
193 | |||
194 | #include <asm-generic/cmpxchg-local.h> | ||
195 | |||
196 | static inline unsigned long __cmpxchg_local(void *ptr, | ||
197 | unsigned long old, | ||
198 | unsigned long new, int size) | ||
199 | { | ||
200 | switch (size) { | ||
201 | case 1: | ||
202 | case 2: | ||
203 | case 4: | ||
204 | #ifdef CONFIG_64BIT | ||
205 | case 8: | ||
206 | #endif | ||
207 | return __cmpxchg(ptr, old, new, size); | ||
208 | default: | ||
209 | return __cmpxchg_local_generic(ptr, old, new, size); | ||
210 | } | ||
211 | |||
212 | return old; | ||
213 | } | ||
214 | |||
215 | /* | ||
216 | * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make | ||
217 | * them available. | ||
218 | */ | ||
219 | #define cmpxchg_local(ptr, o, n) \ | ||
220 | ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \ | ||
221 | (unsigned long)(n), sizeof(*(ptr)))) | ||
222 | |||
223 | #define cmpxchg64_local(ptr, o, n) cmpxchg64((ptr), (o), (n)) | ||
224 | |||
225 | #endif /* __ASM_CMPXCHG_H */ | ||
diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h index 8f8d759f6a7b..d382629a0172 100644 --- a/arch/s390/include/asm/system.h +++ b/arch/s390/include/asm/system.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <asm/setup.h> | 14 | #include <asm/setup.h> |
15 | #include <asm/processor.h> | 15 | #include <asm/processor.h> |
16 | #include <asm/lowcore.h> | 16 | #include <asm/lowcore.h> |
17 | #include <asm/cmpxchg.h> | ||
17 | 18 | ||
18 | #ifdef __KERNEL__ | 19 | #ifdef __KERNEL__ |
19 | 20 | ||
@@ -120,161 +121,6 @@ extern int memcpy_real(void *, void *, size_t); | |||
120 | 121 | ||
121 | #define nop() asm volatile("nop") | 122 | #define nop() asm volatile("nop") |
122 | 123 | ||
123 | #define xchg(ptr,x) \ | ||
124 | ({ \ | ||
125 | __typeof__(*(ptr)) __ret; \ | ||
126 | __ret = (__typeof__(*(ptr))) \ | ||
127 | __xchg((unsigned long)(x), (void *)(ptr),sizeof(*(ptr))); \ | ||
128 | __ret; \ | ||
129 | }) | ||
130 | |||
131 | extern void __xchg_called_with_bad_pointer(void); | ||
132 | |||
133 | static inline unsigned long __xchg(unsigned long x, void * ptr, int size) | ||
134 | { | ||
135 | unsigned long addr, old; | ||
136 | int shift; | ||
137 | |||
138 | switch (size) { | ||
139 | case 1: | ||
140 | addr = (unsigned long) ptr; | ||
141 | shift = (3 ^ (addr & 3)) << 3; | ||
142 | addr ^= addr & 3; | ||
143 | asm volatile( | ||
144 | " l %0,%4\n" | ||
145 | "0: lr 0,%0\n" | ||
146 | " nr 0,%3\n" | ||
147 | " or 0,%2\n" | ||
148 | " cs %0,0,%4\n" | ||
149 | " jl 0b\n" | ||
150 | : "=&d" (old), "=Q" (*(int *) addr) | ||
151 | : "d" (x << shift), "d" (~(255 << shift)), | ||
152 | "Q" (*(int *) addr) : "memory", "cc", "0"); | ||
153 | return old >> shift; | ||
154 | case 2: | ||
155 | addr = (unsigned long) ptr; | ||
156 | shift = (2 ^ (addr & 2)) << 3; | ||
157 | addr ^= addr & 2; | ||
158 | asm volatile( | ||
159 | " l %0,%4\n" | ||
160 | "0: lr 0,%0\n" | ||
161 | " nr 0,%3\n" | ||
162 | " or 0,%2\n" | ||
163 | " cs %0,0,%4\n" | ||
164 | " jl 0b\n" | ||
165 | : "=&d" (old), "=Q" (*(int *) addr) | ||
166 | : "d" (x << shift), "d" (~(65535 << shift)), | ||
167 | "Q" (*(int *) addr) : "memory", "cc", "0"); | ||
168 | return old >> shift; | ||
169 | case 4: | ||
170 | asm volatile( | ||
171 | " l %0,%3\n" | ||
172 | "0: cs %0,%2,%3\n" | ||
173 | " jl 0b\n" | ||
174 | : "=&d" (old), "=Q" (*(int *) ptr) | ||
175 | : "d" (x), "Q" (*(int *) ptr) | ||
176 | : "memory", "cc"); | ||
177 | return old; | ||
178 | #ifdef __s390x__ | ||
179 | case 8: | ||
180 | asm volatile( | ||
181 | " lg %0,%3\n" | ||
182 | "0: csg %0,%2,%3\n" | ||
183 | " jl 0b\n" | ||
184 | : "=&d" (old), "=m" (*(long *) ptr) | ||
185 | : "d" (x), "Q" (*(long *) ptr) | ||
186 | : "memory", "cc"); | ||
187 | return old; | ||
188 | #endif /* __s390x__ */ | ||
189 | } | ||
190 | __xchg_called_with_bad_pointer(); | ||
191 | return x; | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * Atomic compare and exchange. Compare OLD with MEM, if identical, | ||
196 | * store NEW in MEM. Return the initial value in MEM. Success is | ||
197 | * indicated by comparing RETURN with OLD. | ||
198 | */ | ||
199 | |||
200 | #define __HAVE_ARCH_CMPXCHG 1 | ||
201 | |||
202 | #define cmpxchg(ptr, o, n) \ | ||
203 | ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \ | ||
204 | (unsigned long)(n), sizeof(*(ptr)))) | ||
205 | |||
206 | extern void __cmpxchg_called_with_bad_pointer(void); | ||
207 | |||
208 | static inline unsigned long | ||
209 | __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) | ||
210 | { | ||
211 | unsigned long addr, prev, tmp; | ||
212 | int shift; | ||
213 | |||
214 | switch (size) { | ||
215 | case 1: | ||
216 | addr = (unsigned long) ptr; | ||
217 | shift = (3 ^ (addr & 3)) << 3; | ||
218 | addr ^= addr & 3; | ||
219 | asm volatile( | ||
220 | " l %0,%2\n" | ||
221 | "0: nr %0,%5\n" | ||
222 | " lr %1,%0\n" | ||
223 | " or %0,%3\n" | ||
224 | " or %1,%4\n" | ||
225 | " cs %0,%1,%2\n" | ||
226 | " jnl 1f\n" | ||
227 | " xr %1,%0\n" | ||
228 | " nr %1,%5\n" | ||
229 | " jnz 0b\n" | ||
230 | "1:" | ||
231 | : "=&d" (prev), "=&d" (tmp), "=Q" (*(int *) ptr) | ||
232 | : "d" (old << shift), "d" (new << shift), | ||
233 | "d" (~(255 << shift)), "Q" (*(int *) ptr) | ||
234 | : "memory", "cc"); | ||
235 | return prev >> shift; | ||
236 | case 2: | ||
237 | addr = (unsigned long) ptr; | ||
238 | shift = (2 ^ (addr & 2)) << 3; | ||
239 | addr ^= addr & 2; | ||
240 | asm volatile( | ||
241 | " l %0,%2\n" | ||
242 | "0: nr %0,%5\n" | ||
243 | " lr %1,%0\n" | ||
244 | " or %0,%3\n" | ||
245 | " or %1,%4\n" | ||
246 | " cs %0,%1,%2\n" | ||
247 | " jnl 1f\n" | ||
248 | " xr %1,%0\n" | ||
249 | " nr %1,%5\n" | ||
250 | " jnz 0b\n" | ||
251 | "1:" | ||
252 | : "=&d" (prev), "=&d" (tmp), "=Q" (*(int *) ptr) | ||
253 | : "d" (old << shift), "d" (new << shift), | ||
254 | "d" (~(65535 << shift)), "Q" (*(int *) ptr) | ||
255 | : "memory", "cc"); | ||
256 | return prev >> shift; | ||
257 | case 4: | ||
258 | asm volatile( | ||
259 | " cs %0,%3,%1\n" | ||
260 | : "=&d" (prev), "=Q" (*(int *) ptr) | ||
261 | : "0" (old), "d" (new), "Q" (*(int *) ptr) | ||
262 | : "memory", "cc"); | ||
263 | return prev; | ||
264 | #ifdef __s390x__ | ||
265 | case 8: | ||
266 | asm volatile( | ||
267 | " csg %0,%3,%1\n" | ||
268 | : "=&d" (prev), "=Q" (*(long *) ptr) | ||
269 | : "0" (old), "d" (new), "Q" (*(long *) ptr) | ||
270 | : "memory", "cc"); | ||
271 | return prev; | ||
272 | #endif /* __s390x__ */ | ||
273 | } | ||
274 | __cmpxchg_called_with_bad_pointer(); | ||
275 | return old; | ||
276 | } | ||
277 | |||
278 | /* | 124 | /* |
279 | * Force strict CPU ordering. | 125 | * Force strict CPU ordering. |
280 | * And yes, this is required on UP too when we're talking | 126 | * And yes, this is required on UP too when we're talking |
@@ -353,46 +199,6 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) | |||
353 | __ctl_load(__dummy, cr, cr); \ | 199 | __ctl_load(__dummy, cr, cr); \ |
354 | }) | 200 | }) |
355 | 201 | ||
356 | #include <linux/irqflags.h> | ||
357 | |||
358 | #include <asm-generic/cmpxchg-local.h> | ||
359 | |||
360 | static inline unsigned long __cmpxchg_local(volatile void *ptr, | ||
361 | unsigned long old, | ||
362 | unsigned long new, int size) | ||
363 | { | ||
364 | switch (size) { | ||
365 | case 1: | ||
366 | case 2: | ||
367 | case 4: | ||
368 | #ifdef __s390x__ | ||
369 | case 8: | ||
370 | #endif | ||
371 | return __cmpxchg(ptr, old, new, size); | ||
372 | default: | ||
373 | return __cmpxchg_local_generic(ptr, old, new, size); | ||
374 | } | ||
375 | |||
376 | return old; | ||
377 | } | ||
378 | |||
379 | /* | ||
380 | * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make | ||
381 | * them available. | ||
382 | */ | ||
383 | #define cmpxchg_local(ptr, o, n) \ | ||
384 | ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \ | ||
385 | (unsigned long)(n), sizeof(*(ptr)))) | ||
386 | #ifdef __s390x__ | ||
387 | #define cmpxchg64_local(ptr, o, n) \ | ||
388 | ({ \ | ||
389 | BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ | ||
390 | cmpxchg_local((ptr), (o), (n)); \ | ||
391 | }) | ||
392 | #else | ||
393 | #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) | ||
394 | #endif | ||
395 | |||
396 | /* | 202 | /* |
397 | * Use to set psw mask except for the first byte which | 203 | * Use to set psw mask except for the first byte which |
398 | * won't be changed by this function. | 204 | * won't be changed by this function. |
diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h index 1049ef27c15e..e82152572377 100644 --- a/arch/s390/include/asm/unistd.h +++ b/arch/s390/include/asm/unistd.h | |||
@@ -272,7 +272,11 @@ | |||
272 | #define __NR_fanotify_init 332 | 272 | #define __NR_fanotify_init 332 |
273 | #define __NR_fanotify_mark 333 | 273 | #define __NR_fanotify_mark 333 |
274 | #define __NR_prlimit64 334 | 274 | #define __NR_prlimit64 334 |
275 | #define NR_syscalls 335 | 275 | #define __NR_name_to_handle_at 335 |
276 | #define __NR_open_by_handle_at 336 | ||
277 | #define __NR_clock_adjtime 337 | ||
278 | #define __NR_syncfs 338 | ||
279 | #define NR_syscalls 339 | ||
276 | 280 | ||
277 | /* | 281 | /* |
278 | * There are some system calls that are not present on 64 bit, some | 282 | * There are some system calls that are not present on 64 bit, some |
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 8e60fb23b90d..1dc96ea08fa8 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S | |||
@@ -1877,3 +1877,30 @@ sys_prlimit64_wrapper: | |||
1877 | llgtr %r4,%r4 # const struct rlimit64 __user * | 1877 | llgtr %r4,%r4 # const struct rlimit64 __user * |
1878 | llgtr %r5,%r5 # struct rlimit64 __user * | 1878 | llgtr %r5,%r5 # struct rlimit64 __user * |
1879 | jg sys_prlimit64 # branch to system call | 1879 | jg sys_prlimit64 # branch to system call |
1880 | |||
1881 | .globl sys_name_to_handle_at_wrapper | ||
1882 | sys_name_to_handle_at_wrapper: | ||
1883 | lgfr %r2,%r2 # int | ||
1884 | llgtr %r3,%r3 # const char __user * | ||
1885 | llgtr %r4,%r4 # struct file_handle __user * | ||
1886 | llgtr %r5,%r5 # int __user * | ||
1887 | lgfr %r6,%r6 # int | ||
1888 | jg sys_name_to_handle_at | ||
1889 | |||
1890 | .globl compat_sys_open_by_handle_at_wrapper | ||
1891 | compat_sys_open_by_handle_at_wrapper: | ||
1892 | lgfr %r2,%r2 # int | ||
1893 | llgtr %r3,%r3 # struct file_handle __user * | ||
1894 | lgfr %r4,%r4 # int | ||
1895 | jg compat_sys_open_by_handle_at | ||
1896 | |||
1897 | .globl compat_sys_clock_adjtime_wrapper | ||
1898 | compat_sys_clock_adjtime_wrapper: | ||
1899 | lgfr %r2,%r2 # clockid_t (int) | ||
1900 | llgtr %r3,%r3 # struct compat_timex __user * | ||
1901 | jg compat_sys_clock_adjtime | ||
1902 | |||
1903 | .globl sys_syncfs_wrapper | ||
1904 | sys_syncfs_wrapper: | ||
1905 | lgfr %r2,%r2 # int | ||
1906 | jg sys_syncfs | ||
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 3b7e7dddc324..068f8465c4ee 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c | |||
@@ -94,6 +94,7 @@ static noinline __init void create_kernel_nss(void) | |||
94 | unsigned int sinitrd_pfn, einitrd_pfn; | 94 | unsigned int sinitrd_pfn, einitrd_pfn; |
95 | #endif | 95 | #endif |
96 | int response; | 96 | int response; |
97 | int hlen; | ||
97 | size_t len; | 98 | size_t len; |
98 | char *savesys_ptr; | 99 | char *savesys_ptr; |
99 | char defsys_cmd[DEFSYS_CMD_SIZE]; | 100 | char defsys_cmd[DEFSYS_CMD_SIZE]; |
@@ -124,24 +125,27 @@ static noinline __init void create_kernel_nss(void) | |||
124 | end_pfn = PFN_UP(__pa(&_end)); | 125 | end_pfn = PFN_UP(__pa(&_end)); |
125 | min_size = end_pfn << 2; | 126 | min_size = end_pfn << 2; |
126 | 127 | ||
127 | sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X", | 128 | hlen = snprintf(defsys_cmd, DEFSYS_CMD_SIZE, |
128 | kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1, | 129 | "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X", |
129 | eshared_pfn, end_pfn); | 130 | kernel_nss_name, stext_pfn - 1, stext_pfn, |
131 | eshared_pfn - 1, eshared_pfn, end_pfn); | ||
130 | 132 | ||
131 | #ifdef CONFIG_BLK_DEV_INITRD | 133 | #ifdef CONFIG_BLK_DEV_INITRD |
132 | if (INITRD_START && INITRD_SIZE) { | 134 | if (INITRD_START && INITRD_SIZE) { |
133 | sinitrd_pfn = PFN_DOWN(__pa(INITRD_START)); | 135 | sinitrd_pfn = PFN_DOWN(__pa(INITRD_START)); |
134 | einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE)); | 136 | einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE)); |
135 | min_size = einitrd_pfn << 2; | 137 | min_size = einitrd_pfn << 2; |
136 | sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd, | 138 | hlen += snprintf(defsys_cmd + hlen, DEFSYS_CMD_SIZE - hlen, |
137 | sinitrd_pfn, einitrd_pfn); | 139 | " EW %.5X-%.5X", sinitrd_pfn, einitrd_pfn); |
138 | } | 140 | } |
139 | #endif | 141 | #endif |
140 | 142 | ||
141 | sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK PARMREGS=0-13", | 143 | snprintf(defsys_cmd + hlen, DEFSYS_CMD_SIZE - hlen, |
142 | defsys_cmd, min_size); | 144 | " EW MINSIZE=%.7iK PARMREGS=0-13", min_size); |
143 | sprintf(savesys_cmd, "SAVESYS %s \n IPL %s", | 145 | defsys_cmd[DEFSYS_CMD_SIZE - 1] = '\0'; |
144 | kernel_nss_name, kernel_nss_name); | 146 | snprintf(savesys_cmd, SAVESYS_CMD_SIZE, "SAVESYS %s \n IPL %s", |
147 | kernel_nss_name, kernel_nss_name); | ||
148 | savesys_cmd[SAVESYS_CMD_SIZE - 1] = '\0'; | ||
145 | 149 | ||
146 | __cpcmd(defsys_cmd, NULL, 0, &response); | 150 | __cpcmd(defsys_cmd, NULL, 0, &response); |
147 | 151 | ||
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 6f6350826c81..ed183c2c6168 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -102,16 +102,6 @@ EXPORT_SYMBOL(lowcore_ptr); | |||
102 | 102 | ||
103 | #include <asm/setup.h> | 103 | #include <asm/setup.h> |
104 | 104 | ||
105 | static struct resource code_resource = { | ||
106 | .name = "Kernel code", | ||
107 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM, | ||
108 | }; | ||
109 | |||
110 | static struct resource data_resource = { | ||
111 | .name = "Kernel data", | ||
112 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM, | ||
113 | }; | ||
114 | |||
115 | /* | 105 | /* |
116 | * condev= and conmode= setup parameter. | 106 | * condev= and conmode= setup parameter. |
117 | */ | 107 | */ |
@@ -436,21 +426,43 @@ setup_lowcore(void) | |||
436 | lowcore_ptr[0] = lc; | 426 | lowcore_ptr[0] = lc; |
437 | } | 427 | } |
438 | 428 | ||
439 | static void __init | 429 | static struct resource code_resource = { |
440 | setup_resources(void) | 430 | .name = "Kernel code", |
431 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM, | ||
432 | }; | ||
433 | |||
434 | static struct resource data_resource = { | ||
435 | .name = "Kernel data", | ||
436 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM, | ||
437 | }; | ||
438 | |||
439 | static struct resource bss_resource = { | ||
440 | .name = "Kernel bss", | ||
441 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM, | ||
442 | }; | ||
443 | |||
444 | static struct resource __initdata *standard_resources[] = { | ||
445 | &code_resource, | ||
446 | &data_resource, | ||
447 | &bss_resource, | ||
448 | }; | ||
449 | |||
450 | static void __init setup_resources(void) | ||
441 | { | 451 | { |
442 | struct resource *res, *sub_res; | 452 | struct resource *res, *std_res, *sub_res; |
443 | int i; | 453 | int i, j; |
444 | 454 | ||
445 | code_resource.start = (unsigned long) &_text; | 455 | code_resource.start = (unsigned long) &_text; |
446 | code_resource.end = (unsigned long) &_etext - 1; | 456 | code_resource.end = (unsigned long) &_etext - 1; |
447 | data_resource.start = (unsigned long) &_etext; | 457 | data_resource.start = (unsigned long) &_etext; |
448 | data_resource.end = (unsigned long) &_edata - 1; | 458 | data_resource.end = (unsigned long) &_edata - 1; |
459 | bss_resource.start = (unsigned long) &__bss_start; | ||
460 | bss_resource.end = (unsigned long) &__bss_stop - 1; | ||
449 | 461 | ||
450 | for (i = 0; i < MEMORY_CHUNKS; i++) { | 462 | for (i = 0; i < MEMORY_CHUNKS; i++) { |
451 | if (!memory_chunk[i].size) | 463 | if (!memory_chunk[i].size) |
452 | continue; | 464 | continue; |
453 | res = alloc_bootmem_low(sizeof(struct resource)); | 465 | res = alloc_bootmem_low(sizeof(*res)); |
454 | res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; | 466 | res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; |
455 | switch (memory_chunk[i].type) { | 467 | switch (memory_chunk[i].type) { |
456 | case CHUNK_READ_WRITE: | 468 | case CHUNK_READ_WRITE: |
@@ -464,40 +476,24 @@ setup_resources(void) | |||
464 | res->name = "reserved"; | 476 | res->name = "reserved"; |
465 | } | 477 | } |
466 | res->start = memory_chunk[i].addr; | 478 | res->start = memory_chunk[i].addr; |
467 | res->end = memory_chunk[i].addr + memory_chunk[i].size - 1; | 479 | res->end = res->start + memory_chunk[i].size - 1; |
468 | request_resource(&iomem_resource, res); | 480 | request_resource(&iomem_resource, res); |
469 | 481 | ||
470 | if (code_resource.start >= res->start && | 482 | for (j = 0; j < ARRAY_SIZE(standard_resources); j++) { |
471 | code_resource.start <= res->end && | 483 | std_res = standard_resources[j]; |
472 | code_resource.end > res->end) { | 484 | if (std_res->start < res->start || |
473 | sub_res = alloc_bootmem_low(sizeof(struct resource)); | 485 | std_res->start > res->end) |
474 | memcpy(sub_res, &code_resource, | 486 | continue; |
475 | sizeof(struct resource)); | 487 | if (std_res->end > res->end) { |
476 | sub_res->end = res->end; | 488 | sub_res = alloc_bootmem_low(sizeof(*sub_res)); |
477 | code_resource.start = res->end + 1; | 489 | *sub_res = *std_res; |
478 | request_resource(res, sub_res); | 490 | sub_res->end = res->end; |
479 | } | 491 | std_res->start = res->end + 1; |
480 | 492 | request_resource(res, sub_res); | |
481 | if (code_resource.start >= res->start && | 493 | } else { |
482 | code_resource.start <= res->end && | 494 | request_resource(res, std_res); |
483 | code_resource.end <= res->end) | 495 | } |
484 | request_resource(res, &code_resource); | ||
485 | |||
486 | if (data_resource.start >= res->start && | ||
487 | data_resource.start <= res->end && | ||
488 | data_resource.end > res->end) { | ||
489 | sub_res = alloc_bootmem_low(sizeof(struct resource)); | ||
490 | memcpy(sub_res, &data_resource, | ||
491 | sizeof(struct resource)); | ||
492 | sub_res->end = res->end; | ||
493 | data_resource.start = res->end + 1; | ||
494 | request_resource(res, sub_res); | ||
495 | } | 496 | } |
496 | |||
497 | if (data_resource.start >= res->start && | ||
498 | data_resource.start <= res->end && | ||
499 | data_resource.end <= res->end) | ||
500 | request_resource(res, &data_resource); | ||
501 | } | 497 | } |
502 | } | 498 | } |
503 | 499 | ||
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index a8fee1b14395..9c65fd4ddce0 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S | |||
@@ -343,3 +343,7 @@ SYSCALL(sys_perf_event_open,sys_perf_event_open,sys_perf_event_open_wrapper) | |||
343 | SYSCALL(sys_fanotify_init,sys_fanotify_init,sys_fanotify_init_wrapper) | 343 | SYSCALL(sys_fanotify_init,sys_fanotify_init,sys_fanotify_init_wrapper) |
344 | SYSCALL(sys_fanotify_mark,sys_fanotify_mark,sys_fanotify_mark_wrapper) | 344 | SYSCALL(sys_fanotify_mark,sys_fanotify_mark,sys_fanotify_mark_wrapper) |
345 | SYSCALL(sys_prlimit64,sys_prlimit64,sys_prlimit64_wrapper) | 345 | SYSCALL(sys_prlimit64,sys_prlimit64,sys_prlimit64_wrapper) |
346 | SYSCALL(sys_name_to_handle_at,sys_name_to_handle_at,sys_name_to_handle_at_wrapper) /* 335 */ | ||
347 | SYSCALL(sys_open_by_handle_at,sys_open_by_handle_at,compat_sys_open_by_handle_at_wrapper) | ||
348 | SYSCALL(sys_clock_adjtime,sys_clock_adjtime,compat_sys_clock_adjtime_wrapper) | ||
349 | SYSCALL(sys_syncfs,sys_syncfs,sys_syncfs_wrapper) | ||
diff --git a/arch/s390/oprofile/Makefile b/arch/s390/oprofile/Makefile index d698cddcfbdd..524c4b615821 100644 --- a/arch/s390/oprofile/Makefile +++ b/arch/s390/oprofile/Makefile | |||
@@ -6,4 +6,5 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ | |||
6 | oprofilefs.o oprofile_stats.o \ | 6 | oprofilefs.o oprofile_stats.o \ |
7 | timer_int.o ) | 7 | timer_int.o ) |
8 | 8 | ||
9 | oprofile-y := $(DRIVER_OBJS) init.o backtrace.o hwsampler.o | 9 | oprofile-y := $(DRIVER_OBJS) init.o backtrace.o |
10 | oprofile-$(CONFIG_64BIT) += hwsampler.o | ||
diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c index 16c76def4a9d..c63d7e58352b 100644 --- a/arch/s390/oprofile/init.c +++ b/arch/s390/oprofile/init.c | |||
@@ -18,6 +18,11 @@ | |||
18 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
19 | 19 | ||
20 | #include "../../../drivers/oprofile/oprof.h" | 20 | #include "../../../drivers/oprofile/oprof.h" |
21 | |||
22 | extern void s390_backtrace(struct pt_regs * const regs, unsigned int depth); | ||
23 | |||
24 | #ifdef CONFIG_64BIT | ||
25 | |||
21 | #include "hwsampler.h" | 26 | #include "hwsampler.h" |
22 | 27 | ||
23 | #define DEFAULT_INTERVAL 4096 | 28 | #define DEFAULT_INTERVAL 4096 |
@@ -37,8 +42,6 @@ static int hwsampler_running; /* start_mutex must be held to change */ | |||
37 | 42 | ||
38 | static struct oprofile_operations timer_ops; | 43 | static struct oprofile_operations timer_ops; |
39 | 44 | ||
40 | extern void s390_backtrace(struct pt_regs * const regs, unsigned int depth); | ||
41 | |||
42 | static int oprofile_hwsampler_start(void) | 45 | static int oprofile_hwsampler_start(void) |
43 | { | 46 | { |
44 | int retval; | 47 | int retval; |
@@ -172,14 +175,22 @@ static void oprofile_hwsampler_exit(void) | |||
172 | hwsampler_shutdown(); | 175 | hwsampler_shutdown(); |
173 | } | 176 | } |
174 | 177 | ||
178 | #endif /* CONFIG_64BIT */ | ||
179 | |||
175 | int __init oprofile_arch_init(struct oprofile_operations *ops) | 180 | int __init oprofile_arch_init(struct oprofile_operations *ops) |
176 | { | 181 | { |
177 | ops->backtrace = s390_backtrace; | 182 | ops->backtrace = s390_backtrace; |
178 | 183 | ||
184 | #ifdef CONFIG_64BIT | ||
179 | return oprofile_hwsampler_init(ops); | 185 | return oprofile_hwsampler_init(ops); |
186 | #else | ||
187 | return -ENODEV; | ||
188 | #endif | ||
180 | } | 189 | } |
181 | 190 | ||
182 | void oprofile_arch_exit(void) | 191 | void oprofile_arch_exit(void) |
183 | { | 192 | { |
193 | #ifdef CONFIG_64BIT | ||
184 | oprofile_hwsampler_exit(); | 194 | oprofile_hwsampler_exit(); |
195 | #endif | ||
185 | } | 196 | } |
diff --git a/arch/sparc/kernel/time_32.c b/arch/sparc/kernel/time_32.c index 8237dd4dfeb4..4e236391b635 100644 --- a/arch/sparc/kernel/time_32.c +++ b/arch/sparc/kernel/time_32.c | |||
@@ -145,6 +145,10 @@ static int __devinit clock_probe(struct platform_device *op) | |||
145 | if (!model) | 145 | if (!model) |
146 | return -ENODEV; | 146 | return -ENODEV; |
147 | 147 | ||
148 | /* Only the primary RTC has an address property */ | ||
149 | if (!of_find_property(dp, "address", NULL)) | ||
150 | return -ENODEV; | ||
151 | |||
148 | m48t59_rtc.resource = &op->resource[0]; | 152 | m48t59_rtc.resource = &op->resource[0]; |
149 | if (!strcmp(model, "mk48t02")) { | 153 | if (!strcmp(model, "mk48t02")) { |
150 | /* Map the clock register io area read-only */ | 154 | /* Map the clock register io area read-only */ |
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c index 6d0e02c4fe09..4c31e2b6e71b 100644 --- a/arch/sparc/mm/init_32.c +++ b/arch/sparc/mm/init_32.c | |||
@@ -75,7 +75,7 @@ void __init kmap_init(void) | |||
75 | kmap_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV | SRMMU_CACHE); | 75 | kmap_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV | SRMMU_CACHE); |
76 | } | 76 | } |
77 | 77 | ||
78 | void show_mem(void) | 78 | void show_mem(unsigned int filter) |
79 | { | 79 | { |
80 | printk("Mem-info:\n"); | 80 | printk("Mem-info:\n"); |
81 | show_free_areas(); | 81 | show_free_areas(); |
diff --git a/arch/tile/mm/pgtable.c b/arch/tile/mm/pgtable.c index 1a2b36f8866d..de7d8e21e01d 100644 --- a/arch/tile/mm/pgtable.c +++ b/arch/tile/mm/pgtable.c | |||
@@ -41,7 +41,7 @@ | |||
41 | * The normal show_free_areas() is too verbose on Tile, with dozens | 41 | * The normal show_free_areas() is too verbose on Tile, with dozens |
42 | * of processors and often four NUMA zones each with high and lowmem. | 42 | * of processors and often four NUMA zones each with high and lowmem. |
43 | */ | 43 | */ |
44 | void show_mem(void) | 44 | void show_mem(unsigned int filter) |
45 | { | 45 | { |
46 | struct zone *zone; | 46 | struct zone *zone; |
47 | 47 | ||
diff --git a/arch/um/Kconfig.common b/arch/um/Kconfig.common index 1e78940218c0..109ddc0071c6 100644 --- a/arch/um/Kconfig.common +++ b/arch/um/Kconfig.common | |||
@@ -8,6 +8,7 @@ config UML | |||
8 | default y | 8 | default y |
9 | select HAVE_GENERIC_HARDIRQS | 9 | select HAVE_GENERIC_HARDIRQS |
10 | select GENERIC_HARDIRQS_NO_DEPRECATED | 10 | select GENERIC_HARDIRQS_NO_DEPRECATED |
11 | select GENERIC_IRQ_SHOW | ||
11 | 12 | ||
12 | config MMU | 13 | config MMU |
13 | bool | 14 | bool |
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 64cfea80cfe2..9e485c770308 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c | |||
@@ -18,52 +18,6 @@ | |||
18 | #include "os.h" | 18 | #include "os.h" |
19 | 19 | ||
20 | /* | 20 | /* |
21 | * Generic, controller-independent functions: | ||
22 | */ | ||
23 | |||
24 | int show_interrupts(struct seq_file *p, void *v) | ||
25 | { | ||
26 | int i = *(loff_t *) v, j; | ||
27 | struct irqaction * action; | ||
28 | unsigned long flags; | ||
29 | |||
30 | if (i == 0) { | ||
31 | seq_printf(p, " "); | ||
32 | for_each_online_cpu(j) | ||
33 | seq_printf(p, "CPU%d ",j); | ||
34 | seq_putc(p, '\n'); | ||
35 | } | ||
36 | |||
37 | if (i < NR_IRQS) { | ||
38 | struct irq_desc *desc = irq_to_desc(i); | ||
39 | |||
40 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
41 | action = desc->action; | ||
42 | if (!action) | ||
43 | goto skip; | ||
44 | seq_printf(p, "%3d: ",i); | ||
45 | #ifndef CONFIG_SMP | ||
46 | seq_printf(p, "%10u ", kstat_irqs(i)); | ||
47 | #else | ||
48 | for_each_online_cpu(j) | ||
49 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); | ||
50 | #endif | ||
51 | seq_printf(p, " %14s", get_irq_desc_chip(desc)->name); | ||
52 | seq_printf(p, " %s", action->name); | ||
53 | |||
54 | for (action=action->next; action; action = action->next) | ||
55 | seq_printf(p, ", %s", action->name); | ||
56 | |||
57 | seq_putc(p, '\n'); | ||
58 | skip: | ||
59 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
60 | } else if (i == NR_IRQS) | ||
61 | seq_putc(p, '\n'); | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | /* | ||
67 | * This list is accessed under irq_lock, except in sigio_handler, | 21 | * This list is accessed under irq_lock, except in sigio_handler, |
68 | * where it is safe from being modified. IRQ handlers won't change it - | 22 | * where it is safe from being modified. IRQ handlers won't change it - |
69 | * if an IRQ source has vanished, it will be freed by free_irqs just | 23 | * if an IRQ source has vanished, it will be freed by free_irqs just |
@@ -390,11 +344,10 @@ void __init init_IRQ(void) | |||
390 | { | 344 | { |
391 | int i; | 345 | int i; |
392 | 346 | ||
393 | set_irq_chip_and_handler(TIMER_IRQ, &SIGVTALRM_irq_type, handle_edge_irq); | 347 | irq_set_chip_and_handler(TIMER_IRQ, &SIGVTALRM_irq_type, handle_edge_irq); |
394 | 348 | ||
395 | for (i = 1; i < NR_IRQS; i++) { | 349 | for (i = 1; i < NR_IRQS; i++) |
396 | set_irq_chip_and_handler(i, &normal_irq_type, handle_edge_irq); | 350 | irq_set_chip_and_handler(i, &normal_irq_type, handle_edge_irq); |
397 | } | ||
398 | } | 351 | } |
399 | 352 | ||
400 | /* | 353 | /* |
diff --git a/arch/unicore32/mm/init.c b/arch/unicore32/mm/init.c index 3dbe3709b69d..1fc02633f700 100644 --- a/arch/unicore32/mm/init.c +++ b/arch/unicore32/mm/init.c | |||
@@ -55,7 +55,7 @@ early_param("initrd", early_initrd); | |||
55 | */ | 55 | */ |
56 | struct meminfo meminfo; | 56 | struct meminfo meminfo; |
57 | 57 | ||
58 | void show_mem(void) | 58 | void show_mem(unsigned int filter) |
59 | { | 59 | { |
60 | int free = 0, total = 0, reserved = 0; | 60 | int free = 0, total = 0, reserved = 0; |
61 | int shared = 0, cached = 0, slab = 0, i; | 61 | int shared = 0, cached = 0, slab = 0, i; |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 140e254fe546..cc6c53a95bfd 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -71,6 +71,7 @@ config X86 | |||
71 | select GENERIC_IRQ_SHOW | 71 | select GENERIC_IRQ_SHOW |
72 | select IRQ_FORCED_THREADING | 72 | select IRQ_FORCED_THREADING |
73 | select USE_GENERIC_SMP_HELPERS if SMP | 73 | select USE_GENERIC_SMP_HELPERS if SMP |
74 | select ARCH_NO_SYSDEV_OPS | ||
74 | 75 | ||
75 | config INSTRUCTION_DECODER | 76 | config INSTRUCTION_DECODER |
76 | def_bool (KPROBES || PERF_EVENTS) | 77 | def_bool (KPROBES || PERF_EVENTS) |
diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index a09e1f052d84..d68fca61ad91 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h | |||
@@ -45,7 +45,7 @@ | |||
45 | #include <linux/stringify.h> | 45 | #include <linux/stringify.h> |
46 | 46 | ||
47 | #ifdef CONFIG_SMP | 47 | #ifdef CONFIG_SMP |
48 | #define __percpu_arg(x) "%%"__stringify(__percpu_seg)":%P" #x | 48 | #define __percpu_prefix "%%"__stringify(__percpu_seg)":" |
49 | #define __my_cpu_offset percpu_read(this_cpu_off) | 49 | #define __my_cpu_offset percpu_read(this_cpu_off) |
50 | 50 | ||
51 | /* | 51 | /* |
@@ -62,9 +62,11 @@ | |||
62 | (typeof(*(ptr)) __kernel __force *)tcp_ptr__; \ | 62 | (typeof(*(ptr)) __kernel __force *)tcp_ptr__; \ |
63 | }) | 63 | }) |
64 | #else | 64 | #else |
65 | #define __percpu_arg(x) "%P" #x | 65 | #define __percpu_prefix "" |
66 | #endif | 66 | #endif |
67 | 67 | ||
68 | #define __percpu_arg(x) __percpu_prefix "%P" #x | ||
69 | |||
68 | /* | 70 | /* |
69 | * Initialized pointers to per-cpu variables needed for the boot | 71 | * Initialized pointers to per-cpu variables needed for the boot |
70 | * processor need to use these macros to get the proper address | 72 | * processor need to use these macros to get the proper address |
@@ -507,6 +509,11 @@ do { \ | |||
507 | * it in software. The address used in the cmpxchg16 instruction must be | 509 | * it in software. The address used in the cmpxchg16 instruction must be |
508 | * aligned to a 16 byte boundary. | 510 | * aligned to a 16 byte boundary. |
509 | */ | 511 | */ |
512 | #ifdef CONFIG_SMP | ||
513 | #define CMPXCHG16B_EMU_CALL "call this_cpu_cmpxchg16b_emu\n\t" P6_NOP3 | ||
514 | #else | ||
515 | #define CMPXCHG16B_EMU_CALL "call this_cpu_cmpxchg16b_emu\n\t" P6_NOP2 | ||
516 | #endif | ||
510 | #define percpu_cmpxchg16b_double(pcp1, o1, o2, n1, n2) \ | 517 | #define percpu_cmpxchg16b_double(pcp1, o1, o2, n1, n2) \ |
511 | ({ \ | 518 | ({ \ |
512 | char __ret; \ | 519 | char __ret; \ |
@@ -515,12 +522,12 @@ do { \ | |||
515 | typeof(o2) __o2 = o2; \ | 522 | typeof(o2) __o2 = o2; \ |
516 | typeof(o2) __n2 = n2; \ | 523 | typeof(o2) __n2 = n2; \ |
517 | typeof(o2) __dummy; \ | 524 | typeof(o2) __dummy; \ |
518 | alternative_io("call this_cpu_cmpxchg16b_emu\n\t" P6_NOP4, \ | 525 | alternative_io(CMPXCHG16B_EMU_CALL, \ |
519 | "cmpxchg16b %%gs:(%%rsi)\n\tsetz %0\n\t", \ | 526 | "cmpxchg16b " __percpu_prefix "(%%rsi)\n\tsetz %0\n\t", \ |
520 | X86_FEATURE_CX16, \ | 527 | X86_FEATURE_CX16, \ |
521 | ASM_OUTPUT2("=a"(__ret), "=d"(__dummy)), \ | 528 | ASM_OUTPUT2("=a"(__ret), "=d"(__dummy)), \ |
522 | "S" (&pcp1), "b"(__n1), "c"(__n2), \ | 529 | "S" (&pcp1), "b"(__n1), "c"(__n2), \ |
523 | "a"(__o1), "d"(__o2)); \ | 530 | "a"(__o1), "d"(__o2) : "memory"); \ |
524 | __ret; \ | 531 | __ret; \ |
525 | }) | 532 | }) |
526 | 533 | ||
diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 6e11c8134158..246d727b65b7 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c | |||
@@ -21,7 +21,7 @@ | |||
21 | #include <linux/acpi.h> | 21 | #include <linux/acpi.h> |
22 | #include <linux/list.h> | 22 | #include <linux/list.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/sysdev.h> | 24 | #include <linux/syscore_ops.h> |
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/msi.h> | 26 | #include <linux/msi.h> |
27 | #include <asm/pci-direct.h> | 27 | #include <asm/pci-direct.h> |
@@ -1260,7 +1260,7 @@ static void disable_iommus(void) | |||
1260 | * disable suspend until real resume implemented | 1260 | * disable suspend until real resume implemented |
1261 | */ | 1261 | */ |
1262 | 1262 | ||
1263 | static int amd_iommu_resume(struct sys_device *dev) | 1263 | static void amd_iommu_resume(void) |
1264 | { | 1264 | { |
1265 | struct amd_iommu *iommu; | 1265 | struct amd_iommu *iommu; |
1266 | 1266 | ||
@@ -1276,11 +1276,9 @@ static int amd_iommu_resume(struct sys_device *dev) | |||
1276 | */ | 1276 | */ |
1277 | amd_iommu_flush_all_devices(); | 1277 | amd_iommu_flush_all_devices(); |
1278 | amd_iommu_flush_all_domains(); | 1278 | amd_iommu_flush_all_domains(); |
1279 | |||
1280 | return 0; | ||
1281 | } | 1279 | } |
1282 | 1280 | ||
1283 | static int amd_iommu_suspend(struct sys_device *dev, pm_message_t state) | 1281 | static int amd_iommu_suspend(void) |
1284 | { | 1282 | { |
1285 | /* disable IOMMUs to go out of the way for BIOS */ | 1283 | /* disable IOMMUs to go out of the way for BIOS */ |
1286 | disable_iommus(); | 1284 | disable_iommus(); |
@@ -1288,17 +1286,11 @@ static int amd_iommu_suspend(struct sys_device *dev, pm_message_t state) | |||
1288 | return 0; | 1286 | return 0; |
1289 | } | 1287 | } |
1290 | 1288 | ||
1291 | static struct sysdev_class amd_iommu_sysdev_class = { | 1289 | static struct syscore_ops amd_iommu_syscore_ops = { |
1292 | .name = "amd_iommu", | ||
1293 | .suspend = amd_iommu_suspend, | 1290 | .suspend = amd_iommu_suspend, |
1294 | .resume = amd_iommu_resume, | 1291 | .resume = amd_iommu_resume, |
1295 | }; | 1292 | }; |
1296 | 1293 | ||
1297 | static struct sys_device device_amd_iommu = { | ||
1298 | .id = 0, | ||
1299 | .cls = &amd_iommu_sysdev_class, | ||
1300 | }; | ||
1301 | |||
1302 | /* | 1294 | /* |
1303 | * This is the core init function for AMD IOMMU hardware in the system. | 1295 | * This is the core init function for AMD IOMMU hardware in the system. |
1304 | * This function is called from the generic x86 DMA layer initialization | 1296 | * This function is called from the generic x86 DMA layer initialization |
@@ -1415,14 +1407,6 @@ static int __init amd_iommu_init(void) | |||
1415 | goto free; | 1407 | goto free; |
1416 | } | 1408 | } |
1417 | 1409 | ||
1418 | ret = sysdev_class_register(&amd_iommu_sysdev_class); | ||
1419 | if (ret) | ||
1420 | goto free; | ||
1421 | |||
1422 | ret = sysdev_register(&device_amd_iommu); | ||
1423 | if (ret) | ||
1424 | goto free; | ||
1425 | |||
1426 | ret = amd_iommu_init_devices(); | 1410 | ret = amd_iommu_init_devices(); |
1427 | if (ret) | 1411 | if (ret) |
1428 | goto free; | 1412 | goto free; |
@@ -1441,6 +1425,8 @@ static int __init amd_iommu_init(void) | |||
1441 | 1425 | ||
1442 | amd_iommu_init_notifier(); | 1426 | amd_iommu_init_notifier(); |
1443 | 1427 | ||
1428 | register_syscore_ops(&amd_iommu_syscore_ops); | ||
1429 | |||
1444 | if (iommu_pass_through) | 1430 | if (iommu_pass_through) |
1445 | goto out; | 1431 | goto out; |
1446 | 1432 | ||
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 966673f44141..fabf01eff771 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include <linux/ftrace.h> | 24 | #include <linux/ftrace.h> |
25 | #include <linux/ioport.h> | 25 | #include <linux/ioport.h> |
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/sysdev.h> | 27 | #include <linux/syscore_ops.h> |
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | #include <linux/timex.h> | 29 | #include <linux/timex.h> |
30 | #include <linux/dmar.h> | 30 | #include <linux/dmar.h> |
@@ -2046,7 +2046,7 @@ static struct { | |||
2046 | unsigned int apic_thmr; | 2046 | unsigned int apic_thmr; |
2047 | } apic_pm_state; | 2047 | } apic_pm_state; |
2048 | 2048 | ||
2049 | static int lapic_suspend(struct sys_device *dev, pm_message_t state) | 2049 | static int lapic_suspend(void) |
2050 | { | 2050 | { |
2051 | unsigned long flags; | 2051 | unsigned long flags; |
2052 | int maxlvt; | 2052 | int maxlvt; |
@@ -2084,23 +2084,21 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state) | |||
2084 | return 0; | 2084 | return 0; |
2085 | } | 2085 | } |
2086 | 2086 | ||
2087 | static int lapic_resume(struct sys_device *dev) | 2087 | static void lapic_resume(void) |
2088 | { | 2088 | { |
2089 | unsigned int l, h; | 2089 | unsigned int l, h; |
2090 | unsigned long flags; | 2090 | unsigned long flags; |
2091 | int maxlvt; | 2091 | int maxlvt, ret; |
2092 | int ret = 0; | ||
2093 | struct IO_APIC_route_entry **ioapic_entries = NULL; | 2092 | struct IO_APIC_route_entry **ioapic_entries = NULL; |
2094 | 2093 | ||
2095 | if (!apic_pm_state.active) | 2094 | if (!apic_pm_state.active) |
2096 | return 0; | 2095 | return; |
2097 | 2096 | ||
2098 | local_irq_save(flags); | 2097 | local_irq_save(flags); |
2099 | if (intr_remapping_enabled) { | 2098 | if (intr_remapping_enabled) { |
2100 | ioapic_entries = alloc_ioapic_entries(); | 2099 | ioapic_entries = alloc_ioapic_entries(); |
2101 | if (!ioapic_entries) { | 2100 | if (!ioapic_entries) { |
2102 | WARN(1, "Alloc ioapic_entries in lapic resume failed."); | 2101 | WARN(1, "Alloc ioapic_entries in lapic resume failed."); |
2103 | ret = -ENOMEM; | ||
2104 | goto restore; | 2102 | goto restore; |
2105 | } | 2103 | } |
2106 | 2104 | ||
@@ -2162,8 +2160,6 @@ static int lapic_resume(struct sys_device *dev) | |||
2162 | } | 2160 | } |
2163 | restore: | 2161 | restore: |
2164 | local_irq_restore(flags); | 2162 | local_irq_restore(flags); |
2165 | |||
2166 | return ret; | ||
2167 | } | 2163 | } |
2168 | 2164 | ||
2169 | /* | 2165 | /* |
@@ -2171,17 +2167,11 @@ restore: | |||
2171 | * are needed on every CPU up until machine_halt/restart/poweroff. | 2167 | * are needed on every CPU up until machine_halt/restart/poweroff. |
2172 | */ | 2168 | */ |
2173 | 2169 | ||
2174 | static struct sysdev_class lapic_sysclass = { | 2170 | static struct syscore_ops lapic_syscore_ops = { |
2175 | .name = "lapic", | ||
2176 | .resume = lapic_resume, | 2171 | .resume = lapic_resume, |
2177 | .suspend = lapic_suspend, | 2172 | .suspend = lapic_suspend, |
2178 | }; | 2173 | }; |
2179 | 2174 | ||
2180 | static struct sys_device device_lapic = { | ||
2181 | .id = 0, | ||
2182 | .cls = &lapic_sysclass, | ||
2183 | }; | ||
2184 | |||
2185 | static void __cpuinit apic_pm_activate(void) | 2175 | static void __cpuinit apic_pm_activate(void) |
2186 | { | 2176 | { |
2187 | apic_pm_state.active = 1; | 2177 | apic_pm_state.active = 1; |
@@ -2189,16 +2179,11 @@ static void __cpuinit apic_pm_activate(void) | |||
2189 | 2179 | ||
2190 | static int __init init_lapic_sysfs(void) | 2180 | static int __init init_lapic_sysfs(void) |
2191 | { | 2181 | { |
2192 | int error; | ||
2193 | |||
2194 | if (!cpu_has_apic) | ||
2195 | return 0; | ||
2196 | /* XXX: remove suspend/resume procs if !apic_pm_state.active? */ | 2182 | /* XXX: remove suspend/resume procs if !apic_pm_state.active? */ |
2183 | if (cpu_has_apic) | ||
2184 | register_syscore_ops(&lapic_syscore_ops); | ||
2197 | 2185 | ||
2198 | error = sysdev_class_register(&lapic_sysclass); | 2186 | return 0; |
2199 | if (!error) | ||
2200 | error = sysdev_register(&device_lapic); | ||
2201 | return error; | ||
2202 | } | 2187 | } |
2203 | 2188 | ||
2204 | /* local apic needs to resume before other devices access its registers. */ | 2189 | /* local apic needs to resume before other devices access its registers. */ |
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 180ca240e03c..68df09bba92e 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -30,7 +30,7 @@ | |||
30 | #include <linux/compiler.h> | 30 | #include <linux/compiler.h> |
31 | #include <linux/acpi.h> | 31 | #include <linux/acpi.h> |
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <linux/sysdev.h> | 33 | #include <linux/syscore_ops.h> |
34 | #include <linux/msi.h> | 34 | #include <linux/msi.h> |
35 | #include <linux/htirq.h> | 35 | #include <linux/htirq.h> |
36 | #include <linux/freezer.h> | 36 | #include <linux/freezer.h> |
@@ -2918,89 +2918,84 @@ static int __init io_apic_bug_finalize(void) | |||
2918 | 2918 | ||
2919 | late_initcall(io_apic_bug_finalize); | 2919 | late_initcall(io_apic_bug_finalize); |
2920 | 2920 | ||
2921 | struct sysfs_ioapic_data { | 2921 | static struct IO_APIC_route_entry *ioapic_saved_data[MAX_IO_APICS]; |
2922 | struct sys_device dev; | ||
2923 | struct IO_APIC_route_entry entry[0]; | ||
2924 | }; | ||
2925 | static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS]; | ||
2926 | 2922 | ||
2927 | static int ioapic_suspend(struct sys_device *dev, pm_message_t state) | 2923 | static void suspend_ioapic(int ioapic_id) |
2928 | { | 2924 | { |
2929 | struct IO_APIC_route_entry *entry; | 2925 | struct IO_APIC_route_entry *saved_data = ioapic_saved_data[ioapic_id]; |
2930 | struct sysfs_ioapic_data *data; | ||
2931 | int i; | 2926 | int i; |
2932 | 2927 | ||
2933 | data = container_of(dev, struct sysfs_ioapic_data, dev); | 2928 | if (!saved_data) |
2934 | entry = data->entry; | 2929 | return; |
2935 | for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) | 2930 | |
2936 | *entry = ioapic_read_entry(dev->id, i); | 2931 | for (i = 0; i < nr_ioapic_registers[ioapic_id]; i++) |
2932 | saved_data[i] = ioapic_read_entry(ioapic_id, i); | ||
2933 | } | ||
2934 | |||
2935 | static int ioapic_suspend(void) | ||
2936 | { | ||
2937 | int ioapic_id; | ||
2938 | |||
2939 | for (ioapic_id = 0; ioapic_id < nr_ioapics; ioapic_id++) | ||
2940 | suspend_ioapic(ioapic_id); | ||
2937 | 2941 | ||
2938 | return 0; | 2942 | return 0; |
2939 | } | 2943 | } |
2940 | 2944 | ||
2941 | static int ioapic_resume(struct sys_device *dev) | 2945 | static void resume_ioapic(int ioapic_id) |
2942 | { | 2946 | { |
2943 | struct IO_APIC_route_entry *entry; | 2947 | struct IO_APIC_route_entry *saved_data = ioapic_saved_data[ioapic_id]; |
2944 | struct sysfs_ioapic_data *data; | ||
2945 | unsigned long flags; | 2948 | unsigned long flags; |
2946 | union IO_APIC_reg_00 reg_00; | 2949 | union IO_APIC_reg_00 reg_00; |
2947 | int i; | 2950 | int i; |
2948 | 2951 | ||
2949 | data = container_of(dev, struct sysfs_ioapic_data, dev); | 2952 | if (!saved_data) |
2950 | entry = data->entry; | 2953 | return; |
2951 | 2954 | ||
2952 | raw_spin_lock_irqsave(&ioapic_lock, flags); | 2955 | raw_spin_lock_irqsave(&ioapic_lock, flags); |
2953 | reg_00.raw = io_apic_read(dev->id, 0); | 2956 | reg_00.raw = io_apic_read(ioapic_id, 0); |
2954 | if (reg_00.bits.ID != mp_ioapics[dev->id].apicid) { | 2957 | if (reg_00.bits.ID != mp_ioapics[ioapic_id].apicid) { |
2955 | reg_00.bits.ID = mp_ioapics[dev->id].apicid; | 2958 | reg_00.bits.ID = mp_ioapics[ioapic_id].apicid; |
2956 | io_apic_write(dev->id, 0, reg_00.raw); | 2959 | io_apic_write(ioapic_id, 0, reg_00.raw); |
2957 | } | 2960 | } |
2958 | raw_spin_unlock_irqrestore(&ioapic_lock, flags); | 2961 | raw_spin_unlock_irqrestore(&ioapic_lock, flags); |
2959 | for (i = 0; i < nr_ioapic_registers[dev->id]; i++) | 2962 | for (i = 0; i < nr_ioapic_registers[ioapic_id]; i++) |
2960 | ioapic_write_entry(dev->id, i, entry[i]); | 2963 | ioapic_write_entry(ioapic_id, i, saved_data[i]); |
2964 | } | ||
2961 | 2965 | ||
2962 | return 0; | 2966 | static void ioapic_resume(void) |
2967 | { | ||
2968 | int ioapic_id; | ||
2969 | |||
2970 | for (ioapic_id = nr_ioapics - 1; ioapic_id >= 0; ioapic_id--) | ||
2971 | resume_ioapic(ioapic_id); | ||
2963 | } | 2972 | } |
2964 | 2973 | ||
2965 | static struct sysdev_class ioapic_sysdev_class = { | 2974 | static struct syscore_ops ioapic_syscore_ops = { |
2966 | .name = "ioapic", | ||
2967 | .suspend = ioapic_suspend, | 2975 | .suspend = ioapic_suspend, |
2968 | .resume = ioapic_resume, | 2976 | .resume = ioapic_resume, |
2969 | }; | 2977 | }; |
2970 | 2978 | ||
2971 | static int __init ioapic_init_sysfs(void) | 2979 | static int __init ioapic_init_ops(void) |
2972 | { | 2980 | { |
2973 | struct sys_device * dev; | 2981 | int i; |
2974 | int i, size, error; | ||
2975 | 2982 | ||
2976 | error = sysdev_class_register(&ioapic_sysdev_class); | 2983 | for (i = 0; i < nr_ioapics; i++) { |
2977 | if (error) | 2984 | unsigned int size; |
2978 | return error; | ||
2979 | 2985 | ||
2980 | for (i = 0; i < nr_ioapics; i++ ) { | 2986 | size = nr_ioapic_registers[i] |
2981 | size = sizeof(struct sys_device) + nr_ioapic_registers[i] | ||
2982 | * sizeof(struct IO_APIC_route_entry); | 2987 | * sizeof(struct IO_APIC_route_entry); |
2983 | mp_ioapic_data[i] = kzalloc(size, GFP_KERNEL); | 2988 | ioapic_saved_data[i] = kzalloc(size, GFP_KERNEL); |
2984 | if (!mp_ioapic_data[i]) { | 2989 | if (!ioapic_saved_data[i]) |
2985 | printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); | 2990 | pr_err("IOAPIC %d: suspend/resume impossible!\n", i); |
2986 | continue; | ||
2987 | } | ||
2988 | dev = &mp_ioapic_data[i]->dev; | ||
2989 | dev->id = i; | ||
2990 | dev->cls = &ioapic_sysdev_class; | ||
2991 | error = sysdev_register(dev); | ||
2992 | if (error) { | ||
2993 | kfree(mp_ioapic_data[i]); | ||
2994 | mp_ioapic_data[i] = NULL; | ||
2995 | printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); | ||
2996 | continue; | ||
2997 | } | ||
2998 | } | 2991 | } |
2999 | 2992 | ||
2993 | register_syscore_ops(&ioapic_syscore_ops); | ||
2994 | |||
3000 | return 0; | 2995 | return 0; |
3001 | } | 2996 | } |
3002 | 2997 | ||
3003 | device_initcall(ioapic_init_sysfs); | 2998 | device_initcall(ioapic_init_ops); |
3004 | 2999 | ||
3005 | /* | 3000 | /* |
3006 | * Dynamic irq allocate and deallocation | 3001 | * Dynamic irq allocate and deallocation |
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index ab1122998dba..5a05ef63eb4a 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/percpu.h> | 21 | #include <linux/percpu.h> |
22 | #include <linux/string.h> | 22 | #include <linux/string.h> |
23 | #include <linux/sysdev.h> | 23 | #include <linux/sysdev.h> |
24 | #include <linux/syscore_ops.h> | ||
24 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
25 | #include <linux/ctype.h> | 26 | #include <linux/ctype.h> |
26 | #include <linux/sched.h> | 27 | #include <linux/sched.h> |
@@ -1749,14 +1750,14 @@ static int mce_disable_error_reporting(void) | |||
1749 | return 0; | 1750 | return 0; |
1750 | } | 1751 | } |
1751 | 1752 | ||
1752 | static int mce_suspend(struct sys_device *dev, pm_message_t state) | 1753 | static int mce_suspend(void) |
1753 | { | 1754 | { |
1754 | return mce_disable_error_reporting(); | 1755 | return mce_disable_error_reporting(); |
1755 | } | 1756 | } |
1756 | 1757 | ||
1757 | static int mce_shutdown(struct sys_device *dev) | 1758 | static void mce_shutdown(void) |
1758 | { | 1759 | { |
1759 | return mce_disable_error_reporting(); | 1760 | mce_disable_error_reporting(); |
1760 | } | 1761 | } |
1761 | 1762 | ||
1762 | /* | 1763 | /* |
@@ -1764,14 +1765,18 @@ static int mce_shutdown(struct sys_device *dev) | |||
1764 | * Only one CPU is active at this time, the others get re-added later using | 1765 | * Only one CPU is active at this time, the others get re-added later using |
1765 | * CPU hotplug: | 1766 | * CPU hotplug: |
1766 | */ | 1767 | */ |
1767 | static int mce_resume(struct sys_device *dev) | 1768 | static void mce_resume(void) |
1768 | { | 1769 | { |
1769 | __mcheck_cpu_init_generic(); | 1770 | __mcheck_cpu_init_generic(); |
1770 | __mcheck_cpu_init_vendor(__this_cpu_ptr(&cpu_info)); | 1771 | __mcheck_cpu_init_vendor(__this_cpu_ptr(&cpu_info)); |
1771 | |||
1772 | return 0; | ||
1773 | } | 1772 | } |
1774 | 1773 | ||
1774 | static struct syscore_ops mce_syscore_ops = { | ||
1775 | .suspend = mce_suspend, | ||
1776 | .shutdown = mce_shutdown, | ||
1777 | .resume = mce_resume, | ||
1778 | }; | ||
1779 | |||
1775 | static void mce_cpu_restart(void *data) | 1780 | static void mce_cpu_restart(void *data) |
1776 | { | 1781 | { |
1777 | del_timer_sync(&__get_cpu_var(mce_timer)); | 1782 | del_timer_sync(&__get_cpu_var(mce_timer)); |
@@ -1808,9 +1813,6 @@ static void mce_enable_ce(void *all) | |||
1808 | } | 1813 | } |
1809 | 1814 | ||
1810 | static struct sysdev_class mce_sysclass = { | 1815 | static struct sysdev_class mce_sysclass = { |
1811 | .suspend = mce_suspend, | ||
1812 | .shutdown = mce_shutdown, | ||
1813 | .resume = mce_resume, | ||
1814 | .name = "machinecheck", | 1816 | .name = "machinecheck", |
1815 | }; | 1817 | }; |
1816 | 1818 | ||
@@ -2139,6 +2141,7 @@ static __init int mcheck_init_device(void) | |||
2139 | return err; | 2141 | return err; |
2140 | } | 2142 | } |
2141 | 2143 | ||
2144 | register_syscore_ops(&mce_syscore_ops); | ||
2142 | register_hotcpu_notifier(&mce_cpu_notifier); | 2145 | register_hotcpu_notifier(&mce_cpu_notifier); |
2143 | misc_register(&mce_log_device); | 2146 | misc_register(&mce_log_device); |
2144 | 2147 | ||
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c index bebabec5b448..307dfbbf4a8e 100644 --- a/arch/x86/kernel/cpu/mtrr/main.c +++ b/arch/x86/kernel/cpu/mtrr/main.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <linux/cpu.h> | 45 | #include <linux/cpu.h> |
46 | #include <linux/pci.h> | 46 | #include <linux/pci.h> |
47 | #include <linux/smp.h> | 47 | #include <linux/smp.h> |
48 | #include <linux/syscore_ops.h> | ||
48 | 49 | ||
49 | #include <asm/processor.h> | 50 | #include <asm/processor.h> |
50 | #include <asm/e820.h> | 51 | #include <asm/e820.h> |
@@ -630,7 +631,7 @@ struct mtrr_value { | |||
630 | 631 | ||
631 | static struct mtrr_value mtrr_value[MTRR_MAX_VAR_RANGES]; | 632 | static struct mtrr_value mtrr_value[MTRR_MAX_VAR_RANGES]; |
632 | 633 | ||
633 | static int mtrr_save(struct sys_device *sysdev, pm_message_t state) | 634 | static int mtrr_save(void) |
634 | { | 635 | { |
635 | int i; | 636 | int i; |
636 | 637 | ||
@@ -642,7 +643,7 @@ static int mtrr_save(struct sys_device *sysdev, pm_message_t state) | |||
642 | return 0; | 643 | return 0; |
643 | } | 644 | } |
644 | 645 | ||
645 | static int mtrr_restore(struct sys_device *sysdev) | 646 | static void mtrr_restore(void) |
646 | { | 647 | { |
647 | int i; | 648 | int i; |
648 | 649 | ||
@@ -653,12 +654,11 @@ static int mtrr_restore(struct sys_device *sysdev) | |||
653 | mtrr_value[i].ltype); | 654 | mtrr_value[i].ltype); |
654 | } | 655 | } |
655 | } | 656 | } |
656 | return 0; | ||
657 | } | 657 | } |
658 | 658 | ||
659 | 659 | ||
660 | 660 | ||
661 | static struct sysdev_driver mtrr_sysdev_driver = { | 661 | static struct syscore_ops mtrr_syscore_ops = { |
662 | .suspend = mtrr_save, | 662 | .suspend = mtrr_save, |
663 | .resume = mtrr_restore, | 663 | .resume = mtrr_restore, |
664 | }; | 664 | }; |
@@ -839,7 +839,7 @@ static int __init mtrr_init_finialize(void) | |||
839 | * TBD: is there any system with such CPU which supports | 839 | * TBD: is there any system with such CPU which supports |
840 | * suspend/resume? If no, we should remove the code. | 840 | * suspend/resume? If no, we should remove the code. |
841 | */ | 841 | */ |
842 | sysdev_driver_register(&cpu_sysdev_class, &mtrr_sysdev_driver); | 842 | register_syscore_ops(&mtrr_syscore_ops); |
843 | 843 | ||
844 | return 0; | 844 | return 0; |
845 | } | 845 | } |
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 87eab4a27dfc..eed3673a8656 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
@@ -500,12 +500,17 @@ static bool check_hw_exists(void) | |||
500 | return true; | 500 | return true; |
501 | 501 | ||
502 | bios_fail: | 502 | bios_fail: |
503 | printk(KERN_CONT "Broken BIOS detected, using software events only.\n"); | 503 | /* |
504 | * We still allow the PMU driver to operate: | ||
505 | */ | ||
506 | printk(KERN_CONT "Broken BIOS detected, complain to your hardware vendor.\n"); | ||
504 | printk(KERN_ERR FW_BUG "the BIOS has corrupted hw-PMU resources (MSR %x is %Lx)\n", reg, val); | 507 | printk(KERN_ERR FW_BUG "the BIOS has corrupted hw-PMU resources (MSR %x is %Lx)\n", reg, val); |
505 | return false; | 508 | |
509 | return true; | ||
506 | 510 | ||
507 | msr_fail: | 511 | msr_fail: |
508 | printk(KERN_CONT "Broken PMU hardware detected, using software events only.\n"); | 512 | printk(KERN_CONT "Broken PMU hardware detected, using software events only.\n"); |
513 | |||
509 | return false; | 514 | return false; |
510 | } | 515 | } |
511 | 516 | ||
@@ -912,7 +917,7 @@ static inline void x86_assign_hw_event(struct perf_event *event, | |||
912 | hwc->event_base = 0; | 917 | hwc->event_base = 0; |
913 | } else if (hwc->idx >= X86_PMC_IDX_FIXED) { | 918 | } else if (hwc->idx >= X86_PMC_IDX_FIXED) { |
914 | hwc->config_base = MSR_ARCH_PERFMON_FIXED_CTR_CTRL; | 919 | hwc->config_base = MSR_ARCH_PERFMON_FIXED_CTR_CTRL; |
915 | hwc->event_base = MSR_ARCH_PERFMON_FIXED_CTR0; | 920 | hwc->event_base = MSR_ARCH_PERFMON_FIXED_CTR0 + (hwc->idx - X86_PMC_IDX_FIXED); |
916 | } else { | 921 | } else { |
917 | hwc->config_base = x86_pmu_config_addr(hwc->idx); | 922 | hwc->config_base = x86_pmu_config_addr(hwc->idx); |
918 | hwc->event_base = x86_pmu_event_addr(hwc->idx); | 923 | hwc->event_base = x86_pmu_event_addr(hwc->idx); |
diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c index 0811f5ebfba6..c2520e178d32 100644 --- a/arch/x86/kernel/cpu/perf_event_p4.c +++ b/arch/x86/kernel/cpu/perf_event_p4.c | |||
@@ -777,6 +777,7 @@ static inline int p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc) | |||
777 | * the counter has reached zero value and continued counting before | 777 | * the counter has reached zero value and continued counting before |
778 | * real NMI signal was received: | 778 | * real NMI signal was received: |
779 | */ | 779 | */ |
780 | rdmsrl(hwc->event_base, v); | ||
780 | if (!(v & ARCH_P4_UNFLAGGED_BIT)) | 781 | if (!(v & ARCH_P4_UNFLAGGED_BIT)) |
781 | return 1; | 782 | return 1; |
782 | 783 | ||
diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c index 7a8cebc9ff29..706a9fb46a58 100644 --- a/arch/x86/kernel/devicetree.c +++ b/arch/x86/kernel/devicetree.c | |||
@@ -65,12 +65,10 @@ unsigned int irq_create_of_mapping(struct device_node *controller, | |||
65 | return 0; | 65 | return 0; |
66 | ret = ih->xlate(ih, intspec, intsize, &virq, &type); | 66 | ret = ih->xlate(ih, intspec, intsize, &virq, &type); |
67 | if (ret) | 67 | if (ret) |
68 | return ret; | 68 | return 0; |
69 | if (type == IRQ_TYPE_NONE) | 69 | if (type == IRQ_TYPE_NONE) |
70 | return virq; | 70 | return virq; |
71 | /* set the mask if it is different from current */ | 71 | irq_set_irq_type(virq, type); |
72 | if (type == (irq_to_desc(virq)->status & IRQF_TRIGGER_MASK)) | ||
73 | set_irq_type(virq, type); | ||
74 | return virq; | 72 | return virq; |
75 | } | 73 | } |
76 | EXPORT_SYMBOL_GPL(irq_create_of_mapping); | 74 | EXPORT_SYMBOL_GPL(irq_create_of_mapping); |
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 81ac6c78c01c..e2a3f0606da4 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c | |||
@@ -27,7 +27,7 @@ static int die_counter; | |||
27 | 27 | ||
28 | void printk_address(unsigned long address, int reliable) | 28 | void printk_address(unsigned long address, int reliable) |
29 | { | 29 | { |
30 | printk(" [<%p>] %s%pS\n", (void *) address, | 30 | printk(" [<%p>] %s%pB\n", (void *) address, |
31 | reliable ? "" : "? ", (void *) address); | 31 | reliable ? "" : "? ", (void *) address); |
32 | } | 32 | } |
33 | 33 | ||
diff --git a/arch/x86/kernel/i8237.c b/arch/x86/kernel/i8237.c index b42ca694dc68..8eeaa81de066 100644 --- a/arch/x86/kernel/i8237.c +++ b/arch/x86/kernel/i8237.c | |||
@@ -10,7 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/sysdev.h> | 13 | #include <linux/syscore_ops.h> |
14 | 14 | ||
15 | #include <asm/dma.h> | 15 | #include <asm/dma.h> |
16 | 16 | ||
@@ -21,7 +21,7 @@ | |||
21 | * in asm/dma.h. | 21 | * in asm/dma.h. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | static int i8237A_resume(struct sys_device *dev) | 24 | static void i8237A_resume(void) |
25 | { | 25 | { |
26 | unsigned long flags; | 26 | unsigned long flags; |
27 | int i; | 27 | int i; |
@@ -41,31 +41,15 @@ static int i8237A_resume(struct sys_device *dev) | |||
41 | enable_dma(4); | 41 | enable_dma(4); |
42 | 42 | ||
43 | release_dma_lock(flags); | 43 | release_dma_lock(flags); |
44 | |||
45 | return 0; | ||
46 | } | 44 | } |
47 | 45 | ||
48 | static int i8237A_suspend(struct sys_device *dev, pm_message_t state) | 46 | static struct syscore_ops i8237_syscore_ops = { |
49 | { | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | static struct sysdev_class i8237_sysdev_class = { | ||
54 | .name = "i8237", | ||
55 | .suspend = i8237A_suspend, | ||
56 | .resume = i8237A_resume, | 47 | .resume = i8237A_resume, |
57 | }; | 48 | }; |
58 | 49 | ||
59 | static struct sys_device device_i8237A = { | 50 | static int __init i8237A_init_ops(void) |
60 | .id = 0, | ||
61 | .cls = &i8237_sysdev_class, | ||
62 | }; | ||
63 | |||
64 | static int __init i8237A_init_sysfs(void) | ||
65 | { | 51 | { |
66 | int error = sysdev_class_register(&i8237_sysdev_class); | 52 | register_syscore_ops(&i8237_syscore_ops); |
67 | if (!error) | 53 | return 0; |
68 | error = sysdev_register(&device_i8237A); | ||
69 | return error; | ||
70 | } | 54 | } |
71 | device_initcall(i8237A_init_sysfs); | 55 | device_initcall(i8237A_init_ops); |
diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c index d9ca749c123b..65b8f5c2eebf 100644 --- a/arch/x86/kernel/i8259.c +++ b/arch/x86/kernel/i8259.c | |||
@@ -8,7 +8,7 @@ | |||
8 | #include <linux/random.h> | 8 | #include <linux/random.h> |
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | #include <linux/kernel_stat.h> | 10 | #include <linux/kernel_stat.h> |
11 | #include <linux/sysdev.h> | 11 | #include <linux/syscore_ops.h> |
12 | #include <linux/bitops.h> | 12 | #include <linux/bitops.h> |
13 | #include <linux/acpi.h> | 13 | #include <linux/acpi.h> |
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
@@ -245,20 +245,19 @@ static void save_ELCR(char *trigger) | |||
245 | trigger[1] = inb(0x4d1) & 0xDE; | 245 | trigger[1] = inb(0x4d1) & 0xDE; |
246 | } | 246 | } |
247 | 247 | ||
248 | static int i8259A_resume(struct sys_device *dev) | 248 | static void i8259A_resume(void) |
249 | { | 249 | { |
250 | init_8259A(i8259A_auto_eoi); | 250 | init_8259A(i8259A_auto_eoi); |
251 | restore_ELCR(irq_trigger); | 251 | restore_ELCR(irq_trigger); |
252 | return 0; | ||
253 | } | 252 | } |
254 | 253 | ||
255 | static int i8259A_suspend(struct sys_device *dev, pm_message_t state) | 254 | static int i8259A_suspend(void) |
256 | { | 255 | { |
257 | save_ELCR(irq_trigger); | 256 | save_ELCR(irq_trigger); |
258 | return 0; | 257 | return 0; |
259 | } | 258 | } |
260 | 259 | ||
261 | static int i8259A_shutdown(struct sys_device *dev) | 260 | static void i8259A_shutdown(void) |
262 | { | 261 | { |
263 | /* Put the i8259A into a quiescent state that | 262 | /* Put the i8259A into a quiescent state that |
264 | * the kernel initialization code can get it | 263 | * the kernel initialization code can get it |
@@ -266,21 +265,14 @@ static int i8259A_shutdown(struct sys_device *dev) | |||
266 | */ | 265 | */ |
267 | outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ | 266 | outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ |
268 | outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-1 */ | 267 | outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-1 */ |
269 | return 0; | ||
270 | } | 268 | } |
271 | 269 | ||
272 | static struct sysdev_class i8259_sysdev_class = { | 270 | static struct syscore_ops i8259_syscore_ops = { |
273 | .name = "i8259", | ||
274 | .suspend = i8259A_suspend, | 271 | .suspend = i8259A_suspend, |
275 | .resume = i8259A_resume, | 272 | .resume = i8259A_resume, |
276 | .shutdown = i8259A_shutdown, | 273 | .shutdown = i8259A_shutdown, |
277 | }; | 274 | }; |
278 | 275 | ||
279 | static struct sys_device device_i8259A = { | ||
280 | .id = 0, | ||
281 | .cls = &i8259_sysdev_class, | ||
282 | }; | ||
283 | |||
284 | static void mask_8259A(void) | 276 | static void mask_8259A(void) |
285 | { | 277 | { |
286 | unsigned long flags; | 278 | unsigned long flags; |
@@ -399,17 +391,12 @@ struct legacy_pic default_legacy_pic = { | |||
399 | 391 | ||
400 | struct legacy_pic *legacy_pic = &default_legacy_pic; | 392 | struct legacy_pic *legacy_pic = &default_legacy_pic; |
401 | 393 | ||
402 | static int __init i8259A_init_sysfs(void) | 394 | static int __init i8259A_init_ops(void) |
403 | { | 395 | { |
404 | int error; | 396 | if (legacy_pic == &default_legacy_pic) |
405 | 397 | register_syscore_ops(&i8259_syscore_ops); | |
406 | if (legacy_pic != &default_legacy_pic) | ||
407 | return 0; | ||
408 | 398 | ||
409 | error = sysdev_class_register(&i8259_sysdev_class); | 399 | return 0; |
410 | if (!error) | ||
411 | error = sysdev_register(&device_i8259A); | ||
412 | return error; | ||
413 | } | 400 | } |
414 | 401 | ||
415 | device_initcall(i8259A_init_sysfs); | 402 | device_initcall(i8259A_init_ops); |
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index dba0b36941a5..5f9ecff328b5 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c | |||
@@ -121,8 +121,8 @@ char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) | |||
121 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, | 121 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, |
122 | dbg_reg_def[regno].size); | 122 | dbg_reg_def[regno].size); |
123 | 123 | ||
124 | switch (regno) { | ||
125 | #ifdef CONFIG_X86_32 | 124 | #ifdef CONFIG_X86_32 |
125 | switch (regno) { | ||
126 | case GDB_SS: | 126 | case GDB_SS: |
127 | if (!user_mode_vm(regs)) | 127 | if (!user_mode_vm(regs)) |
128 | *(unsigned long *)mem = __KERNEL_DS; | 128 | *(unsigned long *)mem = __KERNEL_DS; |
@@ -135,8 +135,8 @@ char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) | |||
135 | case GDB_FS: | 135 | case GDB_FS: |
136 | *(unsigned long *)mem = 0xFFFF; | 136 | *(unsigned long *)mem = 0xFFFF; |
137 | break; | 137 | break; |
138 | #endif | ||
139 | } | 138 | } |
139 | #endif | ||
140 | return dbg_reg_def[regno].name; | 140 | return dbg_reg_def[regno].name; |
141 | } | 141 | } |
142 | 142 | ||
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c index 87af68e0e1e1..5ed0ab549eb8 100644 --- a/arch/x86/kernel/microcode_core.c +++ b/arch/x86/kernel/microcode_core.c | |||
@@ -82,6 +82,7 @@ | |||
82 | #include <linux/cpu.h> | 82 | #include <linux/cpu.h> |
83 | #include <linux/fs.h> | 83 | #include <linux/fs.h> |
84 | #include <linux/mm.h> | 84 | #include <linux/mm.h> |
85 | #include <linux/syscore_ops.h> | ||
85 | 86 | ||
86 | #include <asm/microcode.h> | 87 | #include <asm/microcode.h> |
87 | #include <asm/processor.h> | 88 | #include <asm/processor.h> |
@@ -438,33 +439,25 @@ static int mc_sysdev_remove(struct sys_device *sys_dev) | |||
438 | return 0; | 439 | return 0; |
439 | } | 440 | } |
440 | 441 | ||
441 | static int mc_sysdev_resume(struct sys_device *dev) | 442 | static struct sysdev_driver mc_sysdev_driver = { |
443 | .add = mc_sysdev_add, | ||
444 | .remove = mc_sysdev_remove, | ||
445 | }; | ||
446 | |||
447 | /** | ||
448 | * mc_bp_resume - Update boot CPU microcode during resume. | ||
449 | */ | ||
450 | static void mc_bp_resume(void) | ||
442 | { | 451 | { |
443 | int cpu = dev->id; | 452 | int cpu = smp_processor_id(); |
444 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 453 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
445 | 454 | ||
446 | if (!cpu_online(cpu)) | ||
447 | return 0; | ||
448 | |||
449 | /* | ||
450 | * All non-bootup cpus are still disabled, | ||
451 | * so only CPU 0 will apply ucode here. | ||
452 | * | ||
453 | * Moreover, there can be no concurrent | ||
454 | * updates from any other places at this point. | ||
455 | */ | ||
456 | WARN_ON(cpu != 0); | ||
457 | |||
458 | if (uci->valid && uci->mc) | 455 | if (uci->valid && uci->mc) |
459 | microcode_ops->apply_microcode(cpu); | 456 | microcode_ops->apply_microcode(cpu); |
460 | |||
461 | return 0; | ||
462 | } | 457 | } |
463 | 458 | ||
464 | static struct sysdev_driver mc_sysdev_driver = { | 459 | static struct syscore_ops mc_syscore_ops = { |
465 | .add = mc_sysdev_add, | 460 | .resume = mc_bp_resume, |
466 | .remove = mc_sysdev_remove, | ||
467 | .resume = mc_sysdev_resume, | ||
468 | }; | 461 | }; |
469 | 462 | ||
470 | static __cpuinit int | 463 | static __cpuinit int |
@@ -542,6 +535,7 @@ static int __init microcode_init(void) | |||
542 | if (error) | 535 | if (error) |
543 | return error; | 536 | return error; |
544 | 537 | ||
538 | register_syscore_ops(&mc_syscore_ops); | ||
545 | register_hotcpu_notifier(&mc_cpu_notifier); | 539 | register_hotcpu_notifier(&mc_cpu_notifier); |
546 | 540 | ||
547 | pr_info("Microcode Update Driver: v" MICROCODE_VERSION | 541 | pr_info("Microcode Update Driver: v" MICROCODE_VERSION |
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index 6f789a887c06..5a532ce646bf 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c | |||
@@ -714,10 +714,6 @@ static void __init check_irq_src(struct mpc_intsrc *m, int *nr_m_spare) | |||
714 | *nr_m_spare += 1; | 714 | *nr_m_spare += 1; |
715 | } | 715 | } |
716 | } | 716 | } |
717 | #else /* CONFIG_X86_IO_APIC */ | ||
718 | static | ||
719 | inline void __init check_irq_src(struct mpc_intsrc *m, int *nr_m_spare) {} | ||
720 | #endif /* CONFIG_X86_IO_APIC */ | ||
721 | 717 | ||
722 | static int | 718 | static int |
723 | check_slot(unsigned long mpc_new_phys, unsigned long mpc_new_length, int count) | 719 | check_slot(unsigned long mpc_new_phys, unsigned long mpc_new_length, int count) |
@@ -731,6 +727,10 @@ check_slot(unsigned long mpc_new_phys, unsigned long mpc_new_length, int count) | |||
731 | 727 | ||
732 | return ret; | 728 | return ret; |
733 | } | 729 | } |
730 | #else /* CONFIG_X86_IO_APIC */ | ||
731 | static | ||
732 | inline void __init check_irq_src(struct mpc_intsrc *m, int *nr_m_spare) {} | ||
733 | #endif /* CONFIG_X86_IO_APIC */ | ||
734 | 734 | ||
735 | static int __init replace_intsrc_all(struct mpc_table *mpc, | 735 | static int __init replace_intsrc_all(struct mpc_table *mpc, |
736 | unsigned long mpc_new_phys, | 736 | unsigned long mpc_new_phys, |
diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index c01ffa5b9b87..82ada01625b9 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c | |||
@@ -27,7 +27,7 @@ | |||
27 | #include <linux/kdebug.h> | 27 | #include <linux/kdebug.h> |
28 | #include <linux/scatterlist.h> | 28 | #include <linux/scatterlist.h> |
29 | #include <linux/iommu-helper.h> | 29 | #include <linux/iommu-helper.h> |
30 | #include <linux/sysdev.h> | 30 | #include <linux/syscore_ops.h> |
31 | #include <linux/io.h> | 31 | #include <linux/io.h> |
32 | #include <linux/gfp.h> | 32 | #include <linux/gfp.h> |
33 | #include <asm/atomic.h> | 33 | #include <asm/atomic.h> |
@@ -589,7 +589,7 @@ void set_up_gart_resume(u32 aper_order, u32 aper_alloc) | |||
589 | aperture_alloc = aper_alloc; | 589 | aperture_alloc = aper_alloc; |
590 | } | 590 | } |
591 | 591 | ||
592 | static void gart_fixup_northbridges(struct sys_device *dev) | 592 | static void gart_fixup_northbridges(void) |
593 | { | 593 | { |
594 | int i; | 594 | int i; |
595 | 595 | ||
@@ -613,33 +613,20 @@ static void gart_fixup_northbridges(struct sys_device *dev) | |||
613 | } | 613 | } |
614 | } | 614 | } |
615 | 615 | ||
616 | static int gart_resume(struct sys_device *dev) | 616 | static void gart_resume(void) |
617 | { | 617 | { |
618 | pr_info("PCI-DMA: Resuming GART IOMMU\n"); | 618 | pr_info("PCI-DMA: Resuming GART IOMMU\n"); |
619 | 619 | ||
620 | gart_fixup_northbridges(dev); | 620 | gart_fixup_northbridges(); |
621 | 621 | ||
622 | enable_gart_translations(); | 622 | enable_gart_translations(); |
623 | |||
624 | return 0; | ||
625 | } | 623 | } |
626 | 624 | ||
627 | static int gart_suspend(struct sys_device *dev, pm_message_t state) | 625 | static struct syscore_ops gart_syscore_ops = { |
628 | { | ||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | static struct sysdev_class gart_sysdev_class = { | ||
633 | .name = "gart", | ||
634 | .suspend = gart_suspend, | ||
635 | .resume = gart_resume, | 626 | .resume = gart_resume, |
636 | 627 | ||
637 | }; | 628 | }; |
638 | 629 | ||
639 | static struct sys_device device_gart = { | ||
640 | .cls = &gart_sysdev_class, | ||
641 | }; | ||
642 | |||
643 | /* | 630 | /* |
644 | * Private Northbridge GATT initialization in case we cannot use the | 631 | * Private Northbridge GATT initialization in case we cannot use the |
645 | * AGP driver for some reason. | 632 | * AGP driver for some reason. |
@@ -650,7 +637,7 @@ static __init int init_amd_gatt(struct agp_kern_info *info) | |||
650 | unsigned aper_base, new_aper_base; | 637 | unsigned aper_base, new_aper_base; |
651 | struct pci_dev *dev; | 638 | struct pci_dev *dev; |
652 | void *gatt; | 639 | void *gatt; |
653 | int i, error; | 640 | int i; |
654 | 641 | ||
655 | pr_info("PCI-DMA: Disabling AGP.\n"); | 642 | pr_info("PCI-DMA: Disabling AGP.\n"); |
656 | 643 | ||
@@ -685,12 +672,7 @@ static __init int init_amd_gatt(struct agp_kern_info *info) | |||
685 | 672 | ||
686 | agp_gatt_table = gatt; | 673 | agp_gatt_table = gatt; |
687 | 674 | ||
688 | error = sysdev_class_register(&gart_sysdev_class); | 675 | register_syscore_ops(&gart_syscore_ops); |
689 | if (!error) | ||
690 | error = sysdev_register(&device_gart); | ||
691 | if (error) | ||
692 | panic("Could not register gart_sysdev -- " | ||
693 | "would corrupt data on next suspend"); | ||
694 | 676 | ||
695 | flush_gart(); | 677 | flush_gart(); |
696 | 678 | ||
diff --git a/arch/x86/lib/cmpxchg16b_emu.S b/arch/x86/lib/cmpxchg16b_emu.S index 3e8b08a6de2b..1e572c507d06 100644 --- a/arch/x86/lib/cmpxchg16b_emu.S +++ b/arch/x86/lib/cmpxchg16b_emu.S | |||
@@ -10,6 +10,12 @@ | |||
10 | #include <asm/frame.h> | 10 | #include <asm/frame.h> |
11 | #include <asm/dwarf2.h> | 11 | #include <asm/dwarf2.h> |
12 | 12 | ||
13 | #ifdef CONFIG_SMP | ||
14 | #define SEG_PREFIX %gs: | ||
15 | #else | ||
16 | #define SEG_PREFIX | ||
17 | #endif | ||
18 | |||
13 | .text | 19 | .text |
14 | 20 | ||
15 | /* | 21 | /* |
@@ -37,13 +43,13 @@ this_cpu_cmpxchg16b_emu: | |||
37 | pushf | 43 | pushf |
38 | cli | 44 | cli |
39 | 45 | ||
40 | cmpq %gs:(%rsi), %rax | 46 | cmpq SEG_PREFIX(%rsi), %rax |
41 | jne not_same | 47 | jne not_same |
42 | cmpq %gs:8(%rsi), %rdx | 48 | cmpq SEG_PREFIX 8(%rsi), %rdx |
43 | jne not_same | 49 | jne not_same |
44 | 50 | ||
45 | movq %rbx, %gs:(%rsi) | 51 | movq %rbx, SEG_PREFIX(%rsi) |
46 | movq %rcx, %gs:8(%rsi) | 52 | movq %rcx, SEG_PREFIX 8(%rsi) |
47 | 53 | ||
48 | popf | 54 | popf |
49 | mov $1, %al | 55 | mov $1, %al |
diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index e2b7b0c06cdf..8dace181c88e 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c | |||
@@ -15,7 +15,7 @@ | |||
15 | #include <linux/notifier.h> | 15 | #include <linux/notifier.h> |
16 | #include <linux/smp.h> | 16 | #include <linux/smp.h> |
17 | #include <linux/oprofile.h> | 17 | #include <linux/oprofile.h> |
18 | #include <linux/sysdev.h> | 18 | #include <linux/syscore_ops.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/moduleparam.h> | 20 | #include <linux/moduleparam.h> |
21 | #include <linux/kdebug.h> | 21 | #include <linux/kdebug.h> |
@@ -536,7 +536,7 @@ static void nmi_shutdown(void) | |||
536 | 536 | ||
537 | #ifdef CONFIG_PM | 537 | #ifdef CONFIG_PM |
538 | 538 | ||
539 | static int nmi_suspend(struct sys_device *dev, pm_message_t state) | 539 | static int nmi_suspend(void) |
540 | { | 540 | { |
541 | /* Only one CPU left, just stop that one */ | 541 | /* Only one CPU left, just stop that one */ |
542 | if (nmi_enabled == 1) | 542 | if (nmi_enabled == 1) |
@@ -544,49 +544,31 @@ static int nmi_suspend(struct sys_device *dev, pm_message_t state) | |||
544 | return 0; | 544 | return 0; |
545 | } | 545 | } |
546 | 546 | ||
547 | static int nmi_resume(struct sys_device *dev) | 547 | static void nmi_resume(void) |
548 | { | 548 | { |
549 | if (nmi_enabled == 1) | 549 | if (nmi_enabled == 1) |
550 | nmi_cpu_start(NULL); | 550 | nmi_cpu_start(NULL); |
551 | return 0; | ||
552 | } | 551 | } |
553 | 552 | ||
554 | static struct sysdev_class oprofile_sysclass = { | 553 | static struct syscore_ops oprofile_syscore_ops = { |
555 | .name = "oprofile", | ||
556 | .resume = nmi_resume, | 554 | .resume = nmi_resume, |
557 | .suspend = nmi_suspend, | 555 | .suspend = nmi_suspend, |
558 | }; | 556 | }; |
559 | 557 | ||
560 | static struct sys_device device_oprofile = { | 558 | static void __init init_suspend_resume(void) |
561 | .id = 0, | ||
562 | .cls = &oprofile_sysclass, | ||
563 | }; | ||
564 | |||
565 | static int __init init_sysfs(void) | ||
566 | { | 559 | { |
567 | int error; | 560 | register_syscore_ops(&oprofile_syscore_ops); |
568 | |||
569 | error = sysdev_class_register(&oprofile_sysclass); | ||
570 | if (error) | ||
571 | return error; | ||
572 | |||
573 | error = sysdev_register(&device_oprofile); | ||
574 | if (error) | ||
575 | sysdev_class_unregister(&oprofile_sysclass); | ||
576 | |||
577 | return error; | ||
578 | } | 561 | } |
579 | 562 | ||
580 | static void exit_sysfs(void) | 563 | static void exit_suspend_resume(void) |
581 | { | 564 | { |
582 | sysdev_unregister(&device_oprofile); | 565 | unregister_syscore_ops(&oprofile_syscore_ops); |
583 | sysdev_class_unregister(&oprofile_sysclass); | ||
584 | } | 566 | } |
585 | 567 | ||
586 | #else | 568 | #else |
587 | 569 | ||
588 | static inline int init_sysfs(void) { return 0; } | 570 | static inline void init_suspend_resume(void) { } |
589 | static inline void exit_sysfs(void) { } | 571 | static inline void exit_suspend_resume(void) { } |
590 | 572 | ||
591 | #endif /* CONFIG_PM */ | 573 | #endif /* CONFIG_PM */ |
592 | 574 | ||
@@ -789,9 +771,7 @@ int __init op_nmi_init(struct oprofile_operations *ops) | |||
789 | 771 | ||
790 | mux_init(ops); | 772 | mux_init(ops); |
791 | 773 | ||
792 | ret = init_sysfs(); | 774 | init_suspend_resume(); |
793 | if (ret) | ||
794 | return ret; | ||
795 | 775 | ||
796 | printk(KERN_INFO "oprofile: using NMI interrupt.\n"); | 776 | printk(KERN_INFO "oprofile: using NMI interrupt.\n"); |
797 | return 0; | 777 | return 0; |
@@ -799,5 +779,5 @@ int __init op_nmi_init(struct oprofile_operations *ops) | |||
799 | 779 | ||
800 | void op_nmi_exit(void) | 780 | void op_nmi_exit(void) |
801 | { | 781 | { |
802 | exit_sysfs(); | 782 | exit_suspend_resume(); |
803 | } | 783 | } |
diff --git a/arch/x86/platform/olpc/olpc-xo1.c b/arch/x86/platform/olpc/olpc-xo1.c index 99513642a0e6..ab81fb271760 100644 --- a/arch/x86/platform/olpc/olpc-xo1.c +++ b/arch/x86/platform/olpc/olpc-xo1.c | |||
@@ -72,9 +72,9 @@ static int __devinit olpc_xo1_probe(struct platform_device *pdev) | |||
72 | dev_err(&pdev->dev, "can't fetch device resource info\n"); | 72 | dev_err(&pdev->dev, "can't fetch device resource info\n"); |
73 | return -EIO; | 73 | return -EIO; |
74 | } | 74 | } |
75 | if (strcmp(pdev->name, "olpc-xo1-pms") == 0) | 75 | if (strcmp(pdev->name, "cs5535-pms") == 0) |
76 | pms_base = res->start; | 76 | pms_base = res->start; |
77 | else if (strcmp(pdev->name, "olpc-xo1-ac-acpi") == 0) | 77 | else if (strcmp(pdev->name, "olpc-xo1-pm-acpi") == 0) |
78 | acpi_base = res->start; | 78 | acpi_base = res->start; |
79 | 79 | ||
80 | /* If we have both addresses, we can override the poweroff hook */ | 80 | /* If we have both addresses, we can override the poweroff hook */ |
@@ -90,9 +90,9 @@ static int __devexit olpc_xo1_remove(struct platform_device *pdev) | |||
90 | { | 90 | { |
91 | mfd_cell_disable(pdev); | 91 | mfd_cell_disable(pdev); |
92 | 92 | ||
93 | if (strcmp(pdev->name, "olpc-xo1-pms") == 0) | 93 | if (strcmp(pdev->name, "cs5535-pms") == 0) |
94 | pms_base = 0; | 94 | pms_base = 0; |
95 | else if (strcmp(pdev->name, "olpc-xo1-acpi") == 0) | 95 | else if (strcmp(pdev->name, "olpc-xo1-pm-acpi") == 0) |
96 | acpi_base = 0; | 96 | acpi_base = 0; |
97 | 97 | ||
98 | pm_power_off = NULL; | 98 | pm_power_off = NULL; |
@@ -101,7 +101,7 @@ static int __devexit olpc_xo1_remove(struct platform_device *pdev) | |||
101 | 101 | ||
102 | static struct platform_driver cs5535_pms_drv = { | 102 | static struct platform_driver cs5535_pms_drv = { |
103 | .driver = { | 103 | .driver = { |
104 | .name = "olpc-xo1-pms", | 104 | .name = "cs5535-pms", |
105 | .owner = THIS_MODULE, | 105 | .owner = THIS_MODULE, |
106 | }, | 106 | }, |
107 | .probe = olpc_xo1_probe, | 107 | .probe = olpc_xo1_probe, |
@@ -110,7 +110,7 @@ static struct platform_driver cs5535_pms_drv = { | |||
110 | 110 | ||
111 | static struct platform_driver cs5535_acpi_drv = { | 111 | static struct platform_driver cs5535_acpi_drv = { |
112 | .driver = { | 112 | .driver = { |
113 | .name = "olpc-xo1-acpi", | 113 | .name = "olpc-xo1-pm-acpi", |
114 | .owner = THIS_MODULE, | 114 | .owner = THIS_MODULE, |
115 | }, | 115 | }, |
116 | .probe = olpc_xo1_probe, | 116 | .probe = olpc_xo1_probe, |
@@ -121,22 +121,21 @@ static int __init olpc_xo1_init(void) | |||
121 | { | 121 | { |
122 | int r; | 122 | int r; |
123 | 123 | ||
124 | r = mfd_shared_platform_driver_register(&cs5535_pms_drv, "cs5535-pms"); | 124 | r = platform_driver_register(&cs5535_pms_drv); |
125 | if (r) | 125 | if (r) |
126 | return r; | 126 | return r; |
127 | 127 | ||
128 | r = mfd_shared_platform_driver_register(&cs5535_acpi_drv, | 128 | r = platform_driver_register(&cs5535_acpi_drv); |
129 | "cs5535-acpi"); | ||
130 | if (r) | 129 | if (r) |
131 | mfd_shared_platform_driver_unregister(&cs5535_pms_drv); | 130 | platform_driver_unregister(&cs5535_pms_drv); |
132 | 131 | ||
133 | return r; | 132 | return r; |
134 | } | 133 | } |
135 | 134 | ||
136 | static void __exit olpc_xo1_exit(void) | 135 | static void __exit olpc_xo1_exit(void) |
137 | { | 136 | { |
138 | mfd_shared_platform_driver_unregister(&cs5535_acpi_drv); | 137 | platform_driver_unregister(&cs5535_acpi_drv); |
139 | mfd_shared_platform_driver_unregister(&cs5535_pms_drv); | 138 | platform_driver_unregister(&cs5535_pms_drv); |
140 | } | 139 | } |
141 | 140 | ||
142 | MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>"); | 141 | MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>"); |
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 72839190f503..1d730b5579a0 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig | |||
@@ -7,6 +7,9 @@ config ZONE_DMA | |||
7 | config XTENSA | 7 | config XTENSA |
8 | def_bool y | 8 | def_bool y |
9 | select HAVE_IDE | 9 | select HAVE_IDE |
10 | select HAVE_GENERIC_HARDIRQS | ||
11 | select GENERIC_IRQ_SHOW | ||
12 | select GENERIC_HARDIRQS_NO_DEPRECATED | ||
10 | help | 13 | help |
11 | Xtensa processors are 32-bit RISC machines designed by Tensilica | 14 | Xtensa processors are 32-bit RISC machines designed by Tensilica |
12 | primarily for embedded systems. These processors are both | 15 | primarily for embedded systems. These processors are both |
@@ -27,9 +30,6 @@ config GENERIC_FIND_BIT_LE | |||
27 | config GENERIC_HWEIGHT | 30 | config GENERIC_HWEIGHT |
28 | def_bool y | 31 | def_bool y |
29 | 32 | ||
30 | config GENERIC_HARDIRQS | ||
31 | def_bool y | ||
32 | |||
33 | config GENERIC_GPIO | 33 | config GENERIC_GPIO |
34 | def_bool y | 34 | def_bool y |
35 | 35 | ||
diff --git a/arch/xtensa/kernel/irq.c b/arch/xtensa/kernel/irq.c index 87508886cbbd..d77089df412e 100644 --- a/arch/xtensa/kernel/irq.c +++ b/arch/xtensa/kernel/irq.c | |||
@@ -35,7 +35,6 @@ atomic_t irq_err_count; | |||
35 | asmlinkage void do_IRQ(int irq, struct pt_regs *regs) | 35 | asmlinkage void do_IRQ(int irq, struct pt_regs *regs) |
36 | { | 36 | { |
37 | struct pt_regs *old_regs = set_irq_regs(regs); | 37 | struct pt_regs *old_regs = set_irq_regs(regs); |
38 | struct irq_desc *desc = irq_desc + irq; | ||
39 | 38 | ||
40 | if (irq >= NR_IRQS) { | 39 | if (irq >= NR_IRQS) { |
41 | printk(KERN_EMERG "%s: cannot handle IRQ %d\n", | 40 | printk(KERN_EMERG "%s: cannot handle IRQ %d\n", |
@@ -57,104 +56,69 @@ asmlinkage void do_IRQ(int irq, struct pt_regs *regs) | |||
57 | sp - sizeof(struct thread_info)); | 56 | sp - sizeof(struct thread_info)); |
58 | } | 57 | } |
59 | #endif | 58 | #endif |
60 | desc->handle_irq(irq, desc); | 59 | generic_handle_irq(irq); |
61 | 60 | ||
62 | irq_exit(); | 61 | irq_exit(); |
63 | set_irq_regs(old_regs); | 62 | set_irq_regs(old_regs); |
64 | } | 63 | } |
65 | 64 | ||
66 | /* | 65 | int arch_show_interrupts(struct seq_file *p, int prec) |
67 | * Generic, controller-independent functions: | ||
68 | */ | ||
69 | |||
70 | int show_interrupts(struct seq_file *p, void *v) | ||
71 | { | 66 | { |
72 | int i = *(loff_t *) v, j; | 67 | int j; |
73 | struct irqaction * action; | 68 | |
74 | unsigned long flags; | 69 | seq_printf(p, "%*s: ", prec, "NMI"); |
75 | 70 | for_each_online_cpu(j) | |
76 | if (i == 0) { | 71 | seq_printf(p, "%10u ", nmi_count(j)); |
77 | seq_printf(p, " "); | 72 | seq_putc(p, '\n'); |
78 | for_each_online_cpu(j) | 73 | seq_printf(p, "%*s: ", prec, "ERR"); |
79 | seq_printf(p, "CPU%d ",j); | 74 | seq_printf(p, "%10u\n", atomic_read(&irq_err_count)); |
80 | seq_putc(p, '\n'); | ||
81 | } | ||
82 | |||
83 | if (i < NR_IRQS) { | ||
84 | raw_spin_lock_irqsave(&irq_desc[i].lock, flags); | ||
85 | action = irq_desc[i].action; | ||
86 | if (!action) | ||
87 | goto skip; | ||
88 | seq_printf(p, "%3d: ",i); | ||
89 | #ifndef CONFIG_SMP | ||
90 | seq_printf(p, "%10u ", kstat_irqs(i)); | ||
91 | #else | ||
92 | for_each_online_cpu(j) | ||
93 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); | ||
94 | #endif | ||
95 | seq_printf(p, " %14s", irq_desc[i].chip->name); | ||
96 | seq_printf(p, " %s", action->name); | ||
97 | |||
98 | for (action=action->next; action; action = action->next) | ||
99 | seq_printf(p, ", %s", action->name); | ||
100 | |||
101 | seq_putc(p, '\n'); | ||
102 | skip: | ||
103 | raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags); | ||
104 | } else if (i == NR_IRQS) { | ||
105 | seq_printf(p, "NMI: "); | ||
106 | for_each_online_cpu(j) | ||
107 | seq_printf(p, "%10u ", nmi_count(j)); | ||
108 | seq_putc(p, '\n'); | ||
109 | seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); | ||
110 | } | ||
111 | return 0; | 75 | return 0; |
112 | } | 76 | } |
113 | 77 | ||
114 | static void xtensa_irq_mask(unsigned int irq) | 78 | static void xtensa_irq_mask(struct irq_chip *d) |
115 | { | 79 | { |
116 | cached_irq_mask &= ~(1 << irq); | 80 | cached_irq_mask &= ~(1 << d->irq); |
117 | set_sr (cached_irq_mask, INTENABLE); | 81 | set_sr (cached_irq_mask, INTENABLE); |
118 | } | 82 | } |
119 | 83 | ||
120 | static void xtensa_irq_unmask(unsigned int irq) | 84 | static void xtensa_irq_unmask(struct irq_chip *d) |
121 | { | 85 | { |
122 | cached_irq_mask |= 1 << irq; | 86 | cached_irq_mask |= 1 << d->irq; |
123 | set_sr (cached_irq_mask, INTENABLE); | 87 | set_sr (cached_irq_mask, INTENABLE); |
124 | } | 88 | } |
125 | 89 | ||
126 | static void xtensa_irq_enable(unsigned int irq) | 90 | static void xtensa_irq_enable(struct irq_chip *d) |
127 | { | 91 | { |
128 | variant_irq_enable(irq); | 92 | variant_irq_enable(d->irq); |
129 | xtensa_irq_unmask(irq); | 93 | xtensa_irq_unmask(d->irq); |
130 | } | 94 | } |
131 | 95 | ||
132 | static void xtensa_irq_disable(unsigned int irq) | 96 | static void xtensa_irq_disable(struct irq_chip *d) |
133 | { | 97 | { |
134 | xtensa_irq_mask(irq); | 98 | xtensa_irq_mask(d->irq); |
135 | variant_irq_disable(irq); | 99 | variant_irq_disable(d->irq); |
136 | } | 100 | } |
137 | 101 | ||
138 | static void xtensa_irq_ack(unsigned int irq) | 102 | static void xtensa_irq_ack(struct irq_chip *d) |
139 | { | 103 | { |
140 | set_sr(1 << irq, INTCLEAR); | 104 | set_sr(1 << d->irq, INTCLEAR); |
141 | } | 105 | } |
142 | 106 | ||
143 | static int xtensa_irq_retrigger(unsigned int irq) | 107 | static int xtensa_irq_retrigger(struct irq_chip *d) |
144 | { | 108 | { |
145 | set_sr (1 << irq, INTSET); | 109 | set_sr (1 << d->irq, INTSET); |
146 | return 1; | 110 | return 1; |
147 | } | 111 | } |
148 | 112 | ||
149 | 113 | ||
150 | static struct irq_chip xtensa_irq_chip = { | 114 | static struct irq_chip xtensa_irq_chip = { |
151 | .name = "xtensa", | 115 | .name = "xtensa", |
152 | .enable = xtensa_irq_enable, | 116 | .irq_enable = xtensa_irq_enable, |
153 | .disable = xtensa_irq_disable, | 117 | .irq_disable = xtensa_irq_disable, |
154 | .mask = xtensa_irq_mask, | 118 | .irq_mask = xtensa_irq_mask, |
155 | .unmask = xtensa_irq_unmask, | 119 | .irq_unmask = xtensa_irq_unmask, |
156 | .ack = xtensa_irq_ack, | 120 | .irq_ack = xtensa_irq_ack, |
157 | .retrigger = xtensa_irq_retrigger, | 121 | .irq_retrigger = xtensa_irq_retrigger, |
158 | }; | 122 | }; |
159 | 123 | ||
160 | void __init init_IRQ(void) | 124 | void __init init_IRQ(void) |
@@ -165,25 +129,25 @@ void __init init_IRQ(void) | |||
165 | int mask = 1 << index; | 129 | int mask = 1 << index; |
166 | 130 | ||
167 | if (mask & XCHAL_INTTYPE_MASK_SOFTWARE) | 131 | if (mask & XCHAL_INTTYPE_MASK_SOFTWARE) |
168 | set_irq_chip_and_handler(index, &xtensa_irq_chip, | 132 | irq_set_chip_and_handler(index, &xtensa_irq_chip, |
169 | handle_simple_irq); | 133 | handle_simple_irq); |
170 | 134 | ||
171 | else if (mask & XCHAL_INTTYPE_MASK_EXTERN_EDGE) | 135 | else if (mask & XCHAL_INTTYPE_MASK_EXTERN_EDGE) |
172 | set_irq_chip_and_handler(index, &xtensa_irq_chip, | 136 | irq_set_chip_and_handler(index, &xtensa_irq_chip, |
173 | handle_edge_irq); | 137 | handle_edge_irq); |
174 | 138 | ||
175 | else if (mask & XCHAL_INTTYPE_MASK_EXTERN_LEVEL) | 139 | else if (mask & XCHAL_INTTYPE_MASK_EXTERN_LEVEL) |
176 | set_irq_chip_and_handler(index, &xtensa_irq_chip, | 140 | irq_set_chip_and_handler(index, &xtensa_irq_chip, |
177 | handle_level_irq); | 141 | handle_level_irq); |
178 | 142 | ||
179 | else if (mask & XCHAL_INTTYPE_MASK_TIMER) | 143 | else if (mask & XCHAL_INTTYPE_MASK_TIMER) |
180 | set_irq_chip_and_handler(index, &xtensa_irq_chip, | 144 | irq_set_chip_and_handler(index, &xtensa_irq_chip, |
181 | handle_edge_irq); | 145 | handle_edge_irq); |
182 | 146 | ||
183 | else /* XCHAL_INTTYPE_MASK_WRITE_ERROR */ | 147 | else /* XCHAL_INTTYPE_MASK_WRITE_ERROR */ |
184 | /* XCHAL_INTTYPE_MASK_NMI */ | 148 | /* XCHAL_INTTYPE_MASK_NMI */ |
185 | 149 | ||
186 | set_irq_chip_and_handler(index, &xtensa_irq_chip, | 150 | irq_set_chip_and_handler(index, &xtensa_irq_chip, |
187 | handle_level_irq); | 151 | handle_level_irq); |
188 | } | 152 | } |
189 | 153 | ||
diff --git a/arch/xtensa/platforms/s6105/device.c b/arch/xtensa/platforms/s6105/device.c index 65333ffefb07..4f4fc971042f 100644 --- a/arch/xtensa/platforms/s6105/device.c +++ b/arch/xtensa/platforms/s6105/device.c | |||
@@ -120,7 +120,7 @@ static int __init prepare_phy_irq(int pin) | |||
120 | irq = gpio_to_irq(pin); | 120 | irq = gpio_to_irq(pin); |
121 | if (irq < 0) | 121 | if (irq < 0) |
122 | goto free; | 122 | goto free; |
123 | if (set_irq_type(irq, IRQ_TYPE_LEVEL_LOW) < 0) | 123 | if (irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW) < 0) |
124 | goto free; | 124 | goto free; |
125 | return irq; | 125 | return irq; |
126 | free: | 126 | free: |
diff --git a/arch/xtensa/variants/s6000/gpio.c b/arch/xtensa/variants/s6000/gpio.c index 380a70fff756..7af0757e001b 100644 --- a/arch/xtensa/variants/s6000/gpio.c +++ b/arch/xtensa/variants/s6000/gpio.c | |||
@@ -85,30 +85,29 @@ int s6_gpio_init(u32 afsel) | |||
85 | return gpiochip_add(&gpiochip); | 85 | return gpiochip_add(&gpiochip); |
86 | } | 86 | } |
87 | 87 | ||
88 | static void ack(unsigned int irq) | 88 | static void ack(struct irq_data *d) |
89 | { | 89 | { |
90 | writeb(1 << (irq - IRQ_BASE), S6_REG_GPIO + S6_GPIO_IC); | 90 | writeb(1 << (d->irq - IRQ_BASE), S6_REG_GPIO + S6_GPIO_IC); |
91 | } | 91 | } |
92 | 92 | ||
93 | static void mask(unsigned int irq) | 93 | static void mask(struct irq_data *d) |
94 | { | 94 | { |
95 | u8 r = readb(S6_REG_GPIO + S6_GPIO_IE); | 95 | u8 r = readb(S6_REG_GPIO + S6_GPIO_IE); |
96 | r &= ~(1 << (irq - IRQ_BASE)); | 96 | r &= ~(1 << (d->irq - IRQ_BASE)); |
97 | writeb(r, S6_REG_GPIO + S6_GPIO_IE); | 97 | writeb(r, S6_REG_GPIO + S6_GPIO_IE); |
98 | } | 98 | } |
99 | 99 | ||
100 | static void unmask(unsigned int irq) | 100 | static void unmask(struct irq_data *d) |
101 | { | 101 | { |
102 | u8 m = readb(S6_REG_GPIO + S6_GPIO_IE); | 102 | u8 m = readb(S6_REG_GPIO + S6_GPIO_IE); |
103 | m |= 1 << (irq - IRQ_BASE); | 103 | m |= 1 << (d->irq - IRQ_BASE); |
104 | writeb(m, S6_REG_GPIO + S6_GPIO_IE); | 104 | writeb(m, S6_REG_GPIO + S6_GPIO_IE); |
105 | } | 105 | } |
106 | 106 | ||
107 | static int set_type(unsigned int irq, unsigned int type) | 107 | static int set_type(struct irq_data *d, unsigned int type) |
108 | { | 108 | { |
109 | const u8 m = 1 << (irq - IRQ_BASE); | 109 | const u8 m = 1 << (d->irq - IRQ_BASE); |
110 | irq_flow_handler_t handler; | 110 | irq_flow_handler_t handler; |
111 | struct irq_desc *desc; | ||
112 | u8 reg; | 111 | u8 reg; |
113 | 112 | ||
114 | if (type == IRQ_TYPE_PROBE) { | 113 | if (type == IRQ_TYPE_PROBE) { |
@@ -129,8 +128,7 @@ static int set_type(unsigned int irq, unsigned int type) | |||
129 | handler = handle_edge_irq; | 128 | handler = handle_edge_irq; |
130 | } | 129 | } |
131 | writeb(reg, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IS); | 130 | writeb(reg, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IS); |
132 | desc = irq_to_desc(irq); | 131 | __irq_set_handler_locked(irq, handler); |
133 | desc->handle_irq = handler; | ||
134 | 132 | ||
135 | reg = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IEV); | 133 | reg = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IEV); |
136 | if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_EDGE_RISING)) | 134 | if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_EDGE_RISING)) |
@@ -150,22 +148,23 @@ static int set_type(unsigned int irq, unsigned int type) | |||
150 | 148 | ||
151 | static struct irq_chip gpioirqs = { | 149 | static struct irq_chip gpioirqs = { |
152 | .name = "GPIO", | 150 | .name = "GPIO", |
153 | .ack = ack, | 151 | .irq_ack = ack, |
154 | .mask = mask, | 152 | .irq_mask = mask, |
155 | .unmask = unmask, | 153 | .irq_unmask = unmask, |
156 | .set_type = set_type, | 154 | .irq_set_type = set_type, |
157 | }; | 155 | }; |
158 | 156 | ||
159 | static u8 demux_masks[4]; | 157 | static u8 demux_masks[4]; |
160 | 158 | ||
161 | static void demux_irqs(unsigned int irq, struct irq_desc *desc) | 159 | static void demux_irqs(unsigned int irq, struct irq_desc *desc) |
162 | { | 160 | { |
163 | u8 *mask = get_irq_desc_data(desc); | 161 | struct irq_chip *chip = irq_desc_get_chip(desc); |
162 | u8 *mask = irq_desc_get_handler_data(desc); | ||
164 | u8 pending; | 163 | u8 pending; |
165 | int cirq; | 164 | int cirq; |
166 | 165 | ||
167 | desc->chip->mask(irq); | 166 | chip->irq_mask(&desc->irq_data); |
168 | desc->chip->ack(irq); | 167 | chip->irq_ack(&desc->irq_data)); |
169 | pending = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_MIS) & *mask; | 168 | pending = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_MIS) & *mask; |
170 | cirq = IRQ_BASE - 1; | 169 | cirq = IRQ_BASE - 1; |
171 | while (pending) { | 170 | while (pending) { |
@@ -174,7 +173,7 @@ static void demux_irqs(unsigned int irq, struct irq_desc *desc) | |||
174 | pending >>= n; | 173 | pending >>= n; |
175 | generic_handle_irq(cirq); | 174 | generic_handle_irq(cirq); |
176 | } | 175 | } |
177 | desc->chip->unmask(irq); | 176 | chip->irq_unmask(&desc->irq_data)); |
178 | } | 177 | } |
179 | 178 | ||
180 | extern const signed char *platform_irq_mappings[XTENSA_NR_IRQS]; | 179 | extern const signed char *platform_irq_mappings[XTENSA_NR_IRQS]; |
@@ -219,11 +218,11 @@ void __init variant_init_irq(void) | |||
219 | i = ffs(mask); | 218 | i = ffs(mask); |
220 | cirq += i; | 219 | cirq += i; |
221 | mask >>= i; | 220 | mask >>= i; |
222 | set_irq_chip(cirq, &gpioirqs); | 221 | irq_set_chip(cirq, &gpioirqs); |
223 | set_irq_type(irq, IRQ_TYPE_LEVEL_LOW); | 222 | irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW); |
224 | } while (mask); | 223 | } while (mask); |
225 | set_irq_data(irq, demux_masks + n); | 224 | irq_set_handler_data(irq, demux_masks + n); |
226 | set_irq_chained_handler(irq, demux_irqs); | 225 | irq_set_chained_handler(irq, demux_irqs); |
227 | if (++n == ARRAY_SIZE(demux_masks)) | 226 | if (++n == ARRAY_SIZE(demux_masks)) |
228 | break; | 227 | break; |
229 | } | 228 | } |
diff --git a/block/blk-core.c b/block/blk-core.c index 59b5c00c0126..e0a062363937 100644 --- a/block/blk-core.c +++ b/block/blk-core.c | |||
@@ -271,7 +271,7 @@ EXPORT_SYMBOL(blk_start_queue); | |||
271 | **/ | 271 | **/ |
272 | void blk_stop_queue(struct request_queue *q) | 272 | void blk_stop_queue(struct request_queue *q) |
273 | { | 273 | { |
274 | cancel_delayed_work(&q->delay_work); | 274 | __cancel_delayed_work(&q->delay_work); |
275 | queue_flag_set(QUEUE_FLAG_STOPPED, q); | 275 | queue_flag_set(QUEUE_FLAG_STOPPED, q); |
276 | } | 276 | } |
277 | EXPORT_SYMBOL(blk_stop_queue); | 277 | EXPORT_SYMBOL(blk_stop_queue); |
@@ -2702,7 +2702,10 @@ static void flush_plug_list(struct blk_plug *plug) | |||
2702 | /* | 2702 | /* |
2703 | * rq is already accounted, so use raw insert | 2703 | * rq is already accounted, so use raw insert |
2704 | */ | 2704 | */ |
2705 | __elv_add_request(q, rq, ELEVATOR_INSERT_SORT_MERGE); | 2705 | if (rq->cmd_flags & (REQ_FLUSH | REQ_FUA)) |
2706 | __elv_add_request(q, rq, ELEVATOR_INSERT_FLUSH); | ||
2707 | else | ||
2708 | __elv_add_request(q, rq, ELEVATOR_INSERT_SORT_MERGE); | ||
2706 | } | 2709 | } |
2707 | 2710 | ||
2708 | if (q) { | 2711 | if (q) { |
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 85249395623b..f911a2f8cc34 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/pm_runtime.h> | 32 | #include <linux/pm_runtime.h> |
33 | #include <linux/pci.h> | 33 | #include <linux/pci.h> |
34 | #include <linux/pci-acpi.h> | 34 | #include <linux/pci-acpi.h> |
35 | #include <linux/pci-aspm.h> | ||
35 | #include <linux/acpi.h> | 36 | #include <linux/acpi.h> |
36 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
37 | #include <acpi/acpi_bus.h> | 38 | #include <acpi/acpi_bus.h> |
@@ -564,7 +565,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) | |||
564 | /* Indicate support for various _OSC capabilities. */ | 565 | /* Indicate support for various _OSC capabilities. */ |
565 | if (pci_ext_cfg_avail(root->bus->self)) | 566 | if (pci_ext_cfg_avail(root->bus->self)) |
566 | flags |= OSC_EXT_PCI_CONFIG_SUPPORT; | 567 | flags |= OSC_EXT_PCI_CONFIG_SUPPORT; |
567 | if (pcie_aspm_enabled()) | 568 | if (pcie_aspm_support_enabled()) |
568 | flags |= OSC_ACTIVE_STATE_PWR_SUPPORT | | 569 | flags |= OSC_ACTIVE_STATE_PWR_SUPPORT | |
569 | OSC_CLOCK_PWR_CAPABILITY_SUPPORT; | 570 | OSC_CLOCK_PWR_CAPABILITY_SUPPORT; |
570 | if (pci_msi_enabled()) | 571 | if (pci_msi_enabled()) |
@@ -591,12 +592,16 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) | |||
591 | 592 | ||
592 | status = acpi_pci_osc_control_set(device->handle, &flags, | 593 | status = acpi_pci_osc_control_set(device->handle, &flags, |
593 | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); | 594 | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); |
594 | if (ACPI_SUCCESS(status)) | 595 | if (ACPI_SUCCESS(status)) { |
595 | dev_info(root->bus->bridge, | 596 | dev_info(root->bus->bridge, |
596 | "ACPI _OSC control (0x%02x) granted\n", flags); | 597 | "ACPI _OSC control (0x%02x) granted\n", flags); |
597 | else | 598 | } else { |
598 | dev_dbg(root->bus->bridge, | 599 | dev_dbg(root->bus->bridge, |
599 | "ACPI _OSC request failed (code %d)\n", status); | 600 | "ACPI _OSC request failed (code %d)\n", status); |
601 | printk(KERN_INFO "Unable to assume _OSC PCIe control. " | ||
602 | "Disabling ASPM\n"); | ||
603 | pcie_no_aspm(); | ||
604 | } | ||
600 | } | 605 | } |
601 | 606 | ||
602 | pci_acpi_add_bus_pm_notifier(device, root->bus); | 607 | pci_acpi_add_bus_pm_notifier(device, root->bus); |
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index d57e8d0fb823..e9e5238f3106 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig | |||
@@ -168,4 +168,11 @@ config SYS_HYPERVISOR | |||
168 | bool | 168 | bool |
169 | default n | 169 | default n |
170 | 170 | ||
171 | config ARCH_NO_SYSDEV_OPS | ||
172 | bool | ||
173 | ---help--- | ||
174 | To be selected by architectures that don't use sysdev class or | ||
175 | sysdev driver power management (suspend/resume) and shutdown | ||
176 | operations. | ||
177 | |||
171 | endmenu | 178 | endmenu |
diff --git a/drivers/base/sys.c b/drivers/base/sys.c index f6fb54741602..fbe72da6c414 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c | |||
@@ -329,7 +329,7 @@ void sysdev_unregister(struct sys_device *sysdev) | |||
329 | } | 329 | } |
330 | 330 | ||
331 | 331 | ||
332 | 332 | #ifndef CONFIG_ARCH_NO_SYSDEV_OPS | |
333 | /** | 333 | /** |
334 | * sysdev_shutdown - Shut down all system devices. | 334 | * sysdev_shutdown - Shut down all system devices. |
335 | * | 335 | * |
@@ -524,6 +524,7 @@ int sysdev_resume(void) | |||
524 | return 0; | 524 | return 0; |
525 | } | 525 | } |
526 | EXPORT_SYMBOL_GPL(sysdev_resume); | 526 | EXPORT_SYMBOL_GPL(sysdev_resume); |
527 | #endif /* CONFIG_ARCH_NO_SYSDEV_OPS */ | ||
527 | 528 | ||
528 | int __init system_bus_init(void) | 529 | int __init system_bus_init(void) |
529 | { | 530 | { |
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 35658f445fca..9bf13988f1a2 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -193,7 +193,7 @@ static int __devinit cciss_find_cfg_addrs(struct pci_dev *pdev, | |||
193 | u64 *cfg_offset); | 193 | u64 *cfg_offset); |
194 | static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev, | 194 | static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev, |
195 | unsigned long *memory_bar); | 195 | unsigned long *memory_bar); |
196 | 196 | static inline u32 cciss_tag_discard_error_bits(ctlr_info_t *h, u32 tag); | |
197 | 197 | ||
198 | /* performant mode helper functions */ | 198 | /* performant mode helper functions */ |
199 | static void calc_bucket_map(int *bucket, int num_buckets, int nsgs, | 199 | static void calc_bucket_map(int *bucket, int num_buckets, int nsgs, |
@@ -231,7 +231,7 @@ static const struct block_device_operations cciss_fops = { | |||
231 | */ | 231 | */ |
232 | static void set_performant_mode(ctlr_info_t *h, CommandList_struct *c) | 232 | static void set_performant_mode(ctlr_info_t *h, CommandList_struct *c) |
233 | { | 233 | { |
234 | if (likely(h->transMethod == CFGTBL_Trans_Performant)) | 234 | if (likely(h->transMethod & CFGTBL_Trans_Performant)) |
235 | c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1); | 235 | c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1); |
236 | } | 236 | } |
237 | 237 | ||
@@ -556,6 +556,44 @@ static void __devinit cciss_procinit(ctlr_info_t *h) | |||
556 | #define to_hba(n) container_of(n, struct ctlr_info, dev) | 556 | #define to_hba(n) container_of(n, struct ctlr_info, dev) |
557 | #define to_drv(n) container_of(n, drive_info_struct, dev) | 557 | #define to_drv(n) container_of(n, drive_info_struct, dev) |
558 | 558 | ||
559 | /* List of controllers which cannot be reset on kexec with reset_devices */ | ||
560 | static u32 unresettable_controller[] = { | ||
561 | 0x324a103C, /* Smart Array P712m */ | ||
562 | 0x324b103C, /* SmartArray P711m */ | ||
563 | 0x3223103C, /* Smart Array P800 */ | ||
564 | 0x3234103C, /* Smart Array P400 */ | ||
565 | 0x3235103C, /* Smart Array P400i */ | ||
566 | 0x3211103C, /* Smart Array E200i */ | ||
567 | 0x3212103C, /* Smart Array E200 */ | ||
568 | 0x3213103C, /* Smart Array E200i */ | ||
569 | 0x3214103C, /* Smart Array E200i */ | ||
570 | 0x3215103C, /* Smart Array E200i */ | ||
571 | 0x3237103C, /* Smart Array E500 */ | ||
572 | 0x323D103C, /* Smart Array P700m */ | ||
573 | 0x409C0E11, /* Smart Array 6400 */ | ||
574 | 0x409D0E11, /* Smart Array 6400 EM */ | ||
575 | }; | ||
576 | |||
577 | static int ctlr_is_resettable(struct ctlr_info *h) | ||
578 | { | ||
579 | int i; | ||
580 | |||
581 | for (i = 0; i < ARRAY_SIZE(unresettable_controller); i++) | ||
582 | if (unresettable_controller[i] == h->board_id) | ||
583 | return 0; | ||
584 | return 1; | ||
585 | } | ||
586 | |||
587 | static ssize_t host_show_resettable(struct device *dev, | ||
588 | struct device_attribute *attr, | ||
589 | char *buf) | ||
590 | { | ||
591 | struct ctlr_info *h = to_hba(dev); | ||
592 | |||
593 | return snprintf(buf, 20, "%d\n", ctlr_is_resettable(h)); | ||
594 | } | ||
595 | static DEVICE_ATTR(resettable, S_IRUGO, host_show_resettable, NULL); | ||
596 | |||
559 | static ssize_t host_store_rescan(struct device *dev, | 597 | static ssize_t host_store_rescan(struct device *dev, |
560 | struct device_attribute *attr, | 598 | struct device_attribute *attr, |
561 | const char *buf, size_t count) | 599 | const char *buf, size_t count) |
@@ -741,6 +779,7 @@ static DEVICE_ATTR(usage_count, S_IRUGO, cciss_show_usage_count, NULL); | |||
741 | 779 | ||
742 | static struct attribute *cciss_host_attrs[] = { | 780 | static struct attribute *cciss_host_attrs[] = { |
743 | &dev_attr_rescan.attr, | 781 | &dev_attr_rescan.attr, |
782 | &dev_attr_resettable.attr, | ||
744 | NULL | 783 | NULL |
745 | }; | 784 | }; |
746 | 785 | ||
@@ -973,8 +1012,8 @@ static void cmd_special_free(ctlr_info_t *h, CommandList_struct *c) | |||
973 | temp64.val32.upper = c->ErrDesc.Addr.upper; | 1012 | temp64.val32.upper = c->ErrDesc.Addr.upper; |
974 | pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct), | 1013 | pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct), |
975 | c->err_info, (dma_addr_t) temp64.val); | 1014 | c->err_info, (dma_addr_t) temp64.val); |
976 | pci_free_consistent(h->pdev, sizeof(CommandList_struct), | 1015 | pci_free_consistent(h->pdev, sizeof(CommandList_struct), c, |
977 | c, (dma_addr_t) c->busaddr); | 1016 | (dma_addr_t) cciss_tag_discard_error_bits(h, (u32) c->busaddr)); |
978 | } | 1017 | } |
979 | 1018 | ||
980 | static inline ctlr_info_t *get_host(struct gendisk *disk) | 1019 | static inline ctlr_info_t *get_host(struct gendisk *disk) |
@@ -1490,8 +1529,7 @@ static int cciss_bigpassthru(ctlr_info_t *h, void __user *argp) | |||
1490 | return -EINVAL; | 1529 | return -EINVAL; |
1491 | if (!capable(CAP_SYS_RAWIO)) | 1530 | if (!capable(CAP_SYS_RAWIO)) |
1492 | return -EPERM; | 1531 | return -EPERM; |
1493 | ioc = (BIG_IOCTL_Command_struct *) | 1532 | ioc = kmalloc(sizeof(*ioc), GFP_KERNEL); |
1494 | kmalloc(sizeof(*ioc), GFP_KERNEL); | ||
1495 | if (!ioc) { | 1533 | if (!ioc) { |
1496 | status = -ENOMEM; | 1534 | status = -ENOMEM; |
1497 | goto cleanup1; | 1535 | goto cleanup1; |
@@ -2653,6 +2691,10 @@ static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c) | |||
2653 | c->Request.CDB[0]); | 2691 | c->Request.CDB[0]); |
2654 | return_status = IO_NEEDS_RETRY; | 2692 | return_status = IO_NEEDS_RETRY; |
2655 | break; | 2693 | break; |
2694 | case CMD_UNABORTABLE: | ||
2695 | dev_warn(&h->pdev->dev, "cmd unabortable\n"); | ||
2696 | return_status = IO_ERROR; | ||
2697 | break; | ||
2656 | default: | 2698 | default: |
2657 | dev_warn(&h->pdev->dev, "cmd 0x%02x returned " | 2699 | dev_warn(&h->pdev->dev, "cmd 0x%02x returned " |
2658 | "unknown status %x\n", c->Request.CDB[0], | 2700 | "unknown status %x\n", c->Request.CDB[0], |
@@ -3103,6 +3145,13 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, | |||
3103 | (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ? | 3145 | (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ? |
3104 | DID_PASSTHROUGH : DID_ERROR); | 3146 | DID_PASSTHROUGH : DID_ERROR); |
3105 | break; | 3147 | break; |
3148 | case CMD_UNABORTABLE: | ||
3149 | dev_warn(&h->pdev->dev, "cmd %p unabortable\n", cmd); | ||
3150 | rq->errors = make_status_bytes(SAM_STAT_GOOD, | ||
3151 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
3152 | cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC ? | ||
3153 | DID_PASSTHROUGH : DID_ERROR); | ||
3154 | break; | ||
3106 | default: | 3155 | default: |
3107 | dev_warn(&h->pdev->dev, "cmd %p returned " | 3156 | dev_warn(&h->pdev->dev, "cmd %p returned " |
3108 | "unknown status %x\n", cmd, | 3157 | "unknown status %x\n", cmd, |
@@ -3136,10 +3185,13 @@ static inline u32 cciss_tag_to_index(u32 tag) | |||
3136 | return tag >> DIRECT_LOOKUP_SHIFT; | 3185 | return tag >> DIRECT_LOOKUP_SHIFT; |
3137 | } | 3186 | } |
3138 | 3187 | ||
3139 | static inline u32 cciss_tag_discard_error_bits(u32 tag) | 3188 | static inline u32 cciss_tag_discard_error_bits(ctlr_info_t *h, u32 tag) |
3140 | { | 3189 | { |
3141 | #define CCISS_ERROR_BITS 0x03 | 3190 | #define CCISS_PERF_ERROR_BITS ((1 << DIRECT_LOOKUP_SHIFT) - 1) |
3142 | return tag & ~CCISS_ERROR_BITS; | 3191 | #define CCISS_SIMPLE_ERROR_BITS 0x03 |
3192 | if (likely(h->transMethod & CFGTBL_Trans_Performant)) | ||
3193 | return tag & ~CCISS_PERF_ERROR_BITS; | ||
3194 | return tag & ~CCISS_SIMPLE_ERROR_BITS; | ||
3143 | } | 3195 | } |
3144 | 3196 | ||
3145 | static inline void cciss_mark_tag_indexed(u32 *tag) | 3197 | static inline void cciss_mark_tag_indexed(u32 *tag) |
@@ -3359,7 +3411,7 @@ static inline u32 next_command(ctlr_info_t *h) | |||
3359 | { | 3411 | { |
3360 | u32 a; | 3412 | u32 a; |
3361 | 3413 | ||
3362 | if (unlikely(h->transMethod != CFGTBL_Trans_Performant)) | 3414 | if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant))) |
3363 | return h->access.command_completed(h); | 3415 | return h->access.command_completed(h); |
3364 | 3416 | ||
3365 | if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) { | 3417 | if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) { |
@@ -3394,14 +3446,12 @@ static inline u32 process_indexed_cmd(ctlr_info_t *h, u32 raw_tag) | |||
3394 | /* process completion of a non-indexed command */ | 3446 | /* process completion of a non-indexed command */ |
3395 | static inline u32 process_nonindexed_cmd(ctlr_info_t *h, u32 raw_tag) | 3447 | static inline u32 process_nonindexed_cmd(ctlr_info_t *h, u32 raw_tag) |
3396 | { | 3448 | { |
3397 | u32 tag; | ||
3398 | CommandList_struct *c = NULL; | 3449 | CommandList_struct *c = NULL; |
3399 | __u32 busaddr_masked, tag_masked; | 3450 | __u32 busaddr_masked, tag_masked; |
3400 | 3451 | ||
3401 | tag = cciss_tag_discard_error_bits(raw_tag); | 3452 | tag_masked = cciss_tag_discard_error_bits(h, raw_tag); |
3402 | list_for_each_entry(c, &h->cmpQ, list) { | 3453 | list_for_each_entry(c, &h->cmpQ, list) { |
3403 | busaddr_masked = cciss_tag_discard_error_bits(c->busaddr); | 3454 | busaddr_masked = cciss_tag_discard_error_bits(h, c->busaddr); |
3404 | tag_masked = cciss_tag_discard_error_bits(tag); | ||
3405 | if (busaddr_masked == tag_masked) { | 3455 | if (busaddr_masked == tag_masked) { |
3406 | finish_cmd(h, c, raw_tag); | 3456 | finish_cmd(h, c, raw_tag); |
3407 | return next_command(h); | 3457 | return next_command(h); |
@@ -3753,7 +3803,8 @@ static void __devinit cciss_wait_for_mode_change_ack(ctlr_info_t *h) | |||
3753 | } | 3803 | } |
3754 | } | 3804 | } |
3755 | 3805 | ||
3756 | static __devinit void cciss_enter_performant_mode(ctlr_info_t *h) | 3806 | static __devinit void cciss_enter_performant_mode(ctlr_info_t *h, |
3807 | u32 use_short_tags) | ||
3757 | { | 3808 | { |
3758 | /* This is a bit complicated. There are 8 registers on | 3809 | /* This is a bit complicated. There are 8 registers on |
3759 | * the controller which we write to to tell it 8 different | 3810 | * the controller which we write to to tell it 8 different |
@@ -3808,7 +3859,7 @@ static __devinit void cciss_enter_performant_mode(ctlr_info_t *h) | |||
3808 | writel(0, &h->transtable->RepQCtrAddrHigh32); | 3859 | writel(0, &h->transtable->RepQCtrAddrHigh32); |
3809 | writel(h->reply_pool_dhandle, &h->transtable->RepQAddr0Low32); | 3860 | writel(h->reply_pool_dhandle, &h->transtable->RepQAddr0Low32); |
3810 | writel(0, &h->transtable->RepQAddr0High32); | 3861 | writel(0, &h->transtable->RepQAddr0High32); |
3811 | writel(CFGTBL_Trans_Performant, | 3862 | writel(CFGTBL_Trans_Performant | use_short_tags, |
3812 | &(h->cfgtable->HostWrite.TransportRequest)); | 3863 | &(h->cfgtable->HostWrite.TransportRequest)); |
3813 | 3864 | ||
3814 | writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); | 3865 | writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); |
@@ -3855,7 +3906,8 @@ static void __devinit cciss_put_controller_into_performant_mode(ctlr_info_t *h) | |||
3855 | if ((h->reply_pool == NULL) || (h->blockFetchTable == NULL)) | 3906 | if ((h->reply_pool == NULL) || (h->blockFetchTable == NULL)) |
3856 | goto clean_up; | 3907 | goto clean_up; |
3857 | 3908 | ||
3858 | cciss_enter_performant_mode(h); | 3909 | cciss_enter_performant_mode(h, |
3910 | trans_support & CFGTBL_Trans_use_short_tags); | ||
3859 | 3911 | ||
3860 | /* Change the access methods to the performant access methods */ | 3912 | /* Change the access methods to the performant access methods */ |
3861 | h->access = SA5_performant_access; | 3913 | h->access = SA5_performant_access; |
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 579f74918493..554bbd907d14 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h | |||
@@ -222,6 +222,7 @@ static void SA5_submit_command( ctlr_info_t *h, CommandList_struct *c) | |||
222 | h->ctlr, c->busaddr); | 222 | h->ctlr, c->busaddr); |
223 | #endif /* CCISS_DEBUG */ | 223 | #endif /* CCISS_DEBUG */ |
224 | writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); | 224 | writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); |
225 | readl(h->vaddr + SA5_REQUEST_PORT_OFFSET); | ||
225 | h->commands_outstanding++; | 226 | h->commands_outstanding++; |
226 | if ( h->commands_outstanding > h->max_outstanding) | 227 | if ( h->commands_outstanding > h->max_outstanding) |
227 | h->max_outstanding = h->commands_outstanding; | 228 | h->max_outstanding = h->commands_outstanding; |
diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h index 35463d2f0ee7..cd441bef031f 100644 --- a/drivers/block/cciss_cmd.h +++ b/drivers/block/cciss_cmd.h | |||
@@ -56,6 +56,7 @@ | |||
56 | 56 | ||
57 | #define CFGTBL_Trans_Simple 0x00000002l | 57 | #define CFGTBL_Trans_Simple 0x00000002l |
58 | #define CFGTBL_Trans_Performant 0x00000004l | 58 | #define CFGTBL_Trans_Performant 0x00000004l |
59 | #define CFGTBL_Trans_use_short_tags 0x20000000l | ||
59 | 60 | ||
60 | #define CFGTBL_BusType_Ultra2 0x00000001l | 61 | #define CFGTBL_BusType_Ultra2 0x00000001l |
61 | #define CFGTBL_BusType_Ultra3 0x00000002l | 62 | #define CFGTBL_BusType_Ultra3 0x00000002l |
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index 727d0225b7d0..df793803f5ae 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c | |||
@@ -824,13 +824,18 @@ static void complete_scsi_command(CommandList_struct *c, int timeout, | |||
824 | break; | 824 | break; |
825 | case CMD_UNSOLICITED_ABORT: | 825 | case CMD_UNSOLICITED_ABORT: |
826 | cmd->result = DID_ABORT << 16; | 826 | cmd->result = DID_ABORT << 16; |
827 | dev_warn(&h->pdev->dev, "%p aborted do to an " | 827 | dev_warn(&h->pdev->dev, "%p aborted due to an " |
828 | "unsolicited abort\n", c); | 828 | "unsolicited abort\n", c); |
829 | break; | 829 | break; |
830 | case CMD_TIMEOUT: | 830 | case CMD_TIMEOUT: |
831 | cmd->result = DID_TIME_OUT << 16; | 831 | cmd->result = DID_TIME_OUT << 16; |
832 | dev_warn(&h->pdev->dev, "%p timedout\n", c); | 832 | dev_warn(&h->pdev->dev, "%p timedout\n", c); |
833 | break; | 833 | break; |
834 | case CMD_UNABORTABLE: | ||
835 | cmd->result = DID_ERROR << 16; | ||
836 | dev_warn(&h->pdev->dev, "c %p command " | ||
837 | "unabortable\n", c); | ||
838 | break; | ||
834 | default: | 839 | default: |
835 | cmd->result = DID_ERROR << 16; | 840 | cmd->result = DID_ERROR << 16; |
836 | dev_warn(&h->pdev->dev, | 841 | dev_warn(&h->pdev->dev, |
@@ -1007,11 +1012,15 @@ cciss_scsi_interpret_error(ctlr_info_t *h, CommandList_struct *c) | |||
1007 | break; | 1012 | break; |
1008 | case CMD_UNSOLICITED_ABORT: | 1013 | case CMD_UNSOLICITED_ABORT: |
1009 | dev_warn(&h->pdev->dev, | 1014 | dev_warn(&h->pdev->dev, |
1010 | "%p aborted do to an unsolicited abort\n", c); | 1015 | "%p aborted due to an unsolicited abort\n", c); |
1011 | break; | 1016 | break; |
1012 | case CMD_TIMEOUT: | 1017 | case CMD_TIMEOUT: |
1013 | dev_warn(&h->pdev->dev, "%p timedout\n", c); | 1018 | dev_warn(&h->pdev->dev, "%p timedout\n", c); |
1014 | break; | 1019 | break; |
1020 | case CMD_UNABORTABLE: | ||
1021 | dev_warn(&h->pdev->dev, | ||
1022 | "%p unabortable\n", c); | ||
1023 | break; | ||
1015 | default: | 1024 | default: |
1016 | dev_warn(&h->pdev->dev, | 1025 | dev_warn(&h->pdev->dev, |
1017 | "%p returned unknown status %x\n", | 1026 | "%p returned unknown status %x\n", |
diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index aca302492ff2..2a1642bc451d 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c | |||
@@ -92,7 +92,7 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev, | |||
92 | bio->bi_end_io = drbd_md_io_complete; | 92 | bio->bi_end_io = drbd_md_io_complete; |
93 | bio->bi_rw = rw; | 93 | bio->bi_rw = rw; |
94 | 94 | ||
95 | if (FAULT_ACTIVE(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) | 95 | if (drbd_insert_fault(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) |
96 | bio_endio(bio, -EIO); | 96 | bio_endio(bio, -EIO); |
97 | else | 97 | else |
98 | submit_bio(rw, bio); | 98 | submit_bio(rw, bio); |
@@ -176,13 +176,17 @@ static struct lc_element *_al_get(struct drbd_conf *mdev, unsigned int enr) | |||
176 | struct lc_element *al_ext; | 176 | struct lc_element *al_ext; |
177 | struct lc_element *tmp; | 177 | struct lc_element *tmp; |
178 | unsigned long al_flags = 0; | 178 | unsigned long al_flags = 0; |
179 | int wake; | ||
179 | 180 | ||
180 | spin_lock_irq(&mdev->al_lock); | 181 | spin_lock_irq(&mdev->al_lock); |
181 | tmp = lc_find(mdev->resync, enr/AL_EXT_PER_BM_SECT); | 182 | tmp = lc_find(mdev->resync, enr/AL_EXT_PER_BM_SECT); |
182 | if (unlikely(tmp != NULL)) { | 183 | if (unlikely(tmp != NULL)) { |
183 | struct bm_extent *bm_ext = lc_entry(tmp, struct bm_extent, lce); | 184 | struct bm_extent *bm_ext = lc_entry(tmp, struct bm_extent, lce); |
184 | if (test_bit(BME_NO_WRITES, &bm_ext->flags)) { | 185 | if (test_bit(BME_NO_WRITES, &bm_ext->flags)) { |
186 | wake = !test_and_set_bit(BME_PRIORITY, &bm_ext->flags); | ||
185 | spin_unlock_irq(&mdev->al_lock); | 187 | spin_unlock_irq(&mdev->al_lock); |
188 | if (wake) | ||
189 | wake_up(&mdev->al_wait); | ||
186 | return NULL; | 190 | return NULL; |
187 | } | 191 | } |
188 | } | 192 | } |
@@ -258,6 +262,33 @@ void drbd_al_complete_io(struct drbd_conf *mdev, sector_t sector) | |||
258 | spin_unlock_irqrestore(&mdev->al_lock, flags); | 262 | spin_unlock_irqrestore(&mdev->al_lock, flags); |
259 | } | 263 | } |
260 | 264 | ||
265 | #if (PAGE_SHIFT + 3) < (AL_EXTENT_SHIFT - BM_BLOCK_SHIFT) | ||
266 | /* Currently BM_BLOCK_SHIFT, BM_EXT_SHIFT and AL_EXTENT_SHIFT | ||
267 | * are still coupled, or assume too much about their relation. | ||
268 | * Code below will not work if this is violated. | ||
269 | * Will be cleaned up with some followup patch. | ||
270 | */ | ||
271 | # error FIXME | ||
272 | #endif | ||
273 | |||
274 | static unsigned int al_extent_to_bm_page(unsigned int al_enr) | ||
275 | { | ||
276 | return al_enr >> | ||
277 | /* bit to page */ | ||
278 | ((PAGE_SHIFT + 3) - | ||
279 | /* al extent number to bit */ | ||
280 | (AL_EXTENT_SHIFT - BM_BLOCK_SHIFT)); | ||
281 | } | ||
282 | |||
283 | static unsigned int rs_extent_to_bm_page(unsigned int rs_enr) | ||
284 | { | ||
285 | return rs_enr >> | ||
286 | /* bit to page */ | ||
287 | ((PAGE_SHIFT + 3) - | ||
288 | /* al extent number to bit */ | ||
289 | (BM_EXT_SHIFT - BM_BLOCK_SHIFT)); | ||
290 | } | ||
291 | |||
261 | int | 292 | int |
262 | w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused) | 293 | w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused) |
263 | { | 294 | { |
@@ -285,7 +316,7 @@ w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused) | |||
285 | * For now, we must not write the transaction, | 316 | * For now, we must not write the transaction, |
286 | * if we cannot write out the bitmap of the evicted extent. */ | 317 | * if we cannot write out the bitmap of the evicted extent. */ |
287 | if (mdev->state.conn < C_CONNECTED && evicted != LC_FREE) | 318 | if (mdev->state.conn < C_CONNECTED && evicted != LC_FREE) |
288 | drbd_bm_write_sect(mdev, evicted/AL_EXT_PER_BM_SECT); | 319 | drbd_bm_write_page(mdev, al_extent_to_bm_page(evicted)); |
289 | 320 | ||
290 | /* The bitmap write may have failed, causing a state change. */ | 321 | /* The bitmap write may have failed, causing a state change. */ |
291 | if (mdev->state.disk < D_INCONSISTENT) { | 322 | if (mdev->state.disk < D_INCONSISTENT) { |
@@ -334,7 +365,7 @@ w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused) | |||
334 | + mdev->ldev->md.al_offset + mdev->al_tr_pos; | 365 | + mdev->ldev->md.al_offset + mdev->al_tr_pos; |
335 | 366 | ||
336 | if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) | 367 | if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) |
337 | drbd_chk_io_error(mdev, 1, TRUE); | 368 | drbd_chk_io_error(mdev, 1, true); |
338 | 369 | ||
339 | if (++mdev->al_tr_pos > | 370 | if (++mdev->al_tr_pos > |
340 | div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT)) | 371 | div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT)) |
@@ -511,225 +542,6 @@ cancel: | |||
511 | return 1; | 542 | return 1; |
512 | } | 543 | } |
513 | 544 | ||
514 | static void atodb_endio(struct bio *bio, int error) | ||
515 | { | ||
516 | struct drbd_atodb_wait *wc = bio->bi_private; | ||
517 | struct drbd_conf *mdev = wc->mdev; | ||
518 | struct page *page; | ||
519 | int uptodate = bio_flagged(bio, BIO_UPTODATE); | ||
520 | |||
521 | /* strange behavior of some lower level drivers... | ||
522 | * fail the request by clearing the uptodate flag, | ||
523 | * but do not return any error?! */ | ||
524 | if (!error && !uptodate) | ||
525 | error = -EIO; | ||
526 | |||
527 | drbd_chk_io_error(mdev, error, TRUE); | ||
528 | if (error && wc->error == 0) | ||
529 | wc->error = error; | ||
530 | |||
531 | if (atomic_dec_and_test(&wc->count)) | ||
532 | complete(&wc->io_done); | ||
533 | |||
534 | page = bio->bi_io_vec[0].bv_page; | ||
535 | put_page(page); | ||
536 | bio_put(bio); | ||
537 | mdev->bm_writ_cnt++; | ||
538 | put_ldev(mdev); | ||
539 | } | ||
540 | |||
541 | /* sector to word */ | ||
542 | #define S2W(s) ((s)<<(BM_EXT_SHIFT-BM_BLOCK_SHIFT-LN2_BPL)) | ||
543 | |||
544 | /* activity log to on disk bitmap -- prepare bio unless that sector | ||
545 | * is already covered by previously prepared bios */ | ||
546 | static int atodb_prepare_unless_covered(struct drbd_conf *mdev, | ||
547 | struct bio **bios, | ||
548 | unsigned int enr, | ||
549 | struct drbd_atodb_wait *wc) __must_hold(local) | ||
550 | { | ||
551 | struct bio *bio; | ||
552 | struct page *page; | ||
553 | sector_t on_disk_sector; | ||
554 | unsigned int page_offset = PAGE_SIZE; | ||
555 | int offset; | ||
556 | int i = 0; | ||
557 | int err = -ENOMEM; | ||
558 | |||
559 | /* We always write aligned, full 4k blocks, | ||
560 | * so we can ignore the logical_block_size (for now) */ | ||
561 | enr &= ~7U; | ||
562 | on_disk_sector = enr + mdev->ldev->md.md_offset | ||
563 | + mdev->ldev->md.bm_offset; | ||
564 | |||
565 | D_ASSERT(!(on_disk_sector & 7U)); | ||
566 | |||
567 | /* Check if that enr is already covered by an already created bio. | ||
568 | * Caution, bios[] is not NULL terminated, | ||
569 | * but only initialized to all NULL. | ||
570 | * For completely scattered activity log, | ||
571 | * the last invocation iterates over all bios, | ||
572 | * and finds the last NULL entry. | ||
573 | */ | ||
574 | while ((bio = bios[i])) { | ||
575 | if (bio->bi_sector == on_disk_sector) | ||
576 | return 0; | ||
577 | i++; | ||
578 | } | ||
579 | /* bios[i] == NULL, the next not yet used slot */ | ||
580 | |||
581 | /* GFP_KERNEL, we are not in the write-out path */ | ||
582 | bio = bio_alloc(GFP_KERNEL, 1); | ||
583 | if (bio == NULL) | ||
584 | return -ENOMEM; | ||
585 | |||
586 | if (i > 0) { | ||
587 | const struct bio_vec *prev_bv = bios[i-1]->bi_io_vec; | ||
588 | page_offset = prev_bv->bv_offset + prev_bv->bv_len; | ||
589 | page = prev_bv->bv_page; | ||
590 | } | ||
591 | if (page_offset == PAGE_SIZE) { | ||
592 | page = alloc_page(__GFP_HIGHMEM); | ||
593 | if (page == NULL) | ||
594 | goto out_bio_put; | ||
595 | page_offset = 0; | ||
596 | } else { | ||
597 | get_page(page); | ||
598 | } | ||
599 | |||
600 | offset = S2W(enr); | ||
601 | drbd_bm_get_lel(mdev, offset, | ||
602 | min_t(size_t, S2W(8), drbd_bm_words(mdev) - offset), | ||
603 | kmap(page) + page_offset); | ||
604 | kunmap(page); | ||
605 | |||
606 | bio->bi_private = wc; | ||
607 | bio->bi_end_io = atodb_endio; | ||
608 | bio->bi_bdev = mdev->ldev->md_bdev; | ||
609 | bio->bi_sector = on_disk_sector; | ||
610 | |||
611 | if (bio_add_page(bio, page, 4096, page_offset) != 4096) | ||
612 | goto out_put_page; | ||
613 | |||
614 | atomic_inc(&wc->count); | ||
615 | /* we already know that we may do this... | ||
616 | * get_ldev_if_state(mdev,D_ATTACHING); | ||
617 | * just get the extra reference, so that the local_cnt reflects | ||
618 | * the number of pending IO requests DRBD at its backing device. | ||
619 | */ | ||
620 | atomic_inc(&mdev->local_cnt); | ||
621 | |||
622 | bios[i] = bio; | ||
623 | |||
624 | return 0; | ||
625 | |||
626 | out_put_page: | ||
627 | err = -EINVAL; | ||
628 | put_page(page); | ||
629 | out_bio_put: | ||
630 | bio_put(bio); | ||
631 | return err; | ||
632 | } | ||
633 | |||
634 | /** | ||
635 | * drbd_al_to_on_disk_bm() - * Writes bitmap parts covered by active AL extents | ||
636 | * @mdev: DRBD device. | ||
637 | * | ||
638 | * Called when we detach (unconfigure) local storage, | ||
639 | * or when we go from R_PRIMARY to R_SECONDARY role. | ||
640 | */ | ||
641 | void drbd_al_to_on_disk_bm(struct drbd_conf *mdev) | ||
642 | { | ||
643 | int i, nr_elements; | ||
644 | unsigned int enr; | ||
645 | struct bio **bios; | ||
646 | struct drbd_atodb_wait wc; | ||
647 | |||
648 | ERR_IF (!get_ldev_if_state(mdev, D_ATTACHING)) | ||
649 | return; /* sorry, I don't have any act_log etc... */ | ||
650 | |||
651 | wait_event(mdev->al_wait, lc_try_lock(mdev->act_log)); | ||
652 | |||
653 | nr_elements = mdev->act_log->nr_elements; | ||
654 | |||
655 | /* GFP_KERNEL, we are not in anyone's write-out path */ | ||
656 | bios = kzalloc(sizeof(struct bio *) * nr_elements, GFP_KERNEL); | ||
657 | if (!bios) | ||
658 | goto submit_one_by_one; | ||
659 | |||
660 | atomic_set(&wc.count, 0); | ||
661 | init_completion(&wc.io_done); | ||
662 | wc.mdev = mdev; | ||
663 | wc.error = 0; | ||
664 | |||
665 | for (i = 0; i < nr_elements; i++) { | ||
666 | enr = lc_element_by_index(mdev->act_log, i)->lc_number; | ||
667 | if (enr == LC_FREE) | ||
668 | continue; | ||
669 | /* next statement also does atomic_inc wc.count and local_cnt */ | ||
670 | if (atodb_prepare_unless_covered(mdev, bios, | ||
671 | enr/AL_EXT_PER_BM_SECT, | ||
672 | &wc)) | ||
673 | goto free_bios_submit_one_by_one; | ||
674 | } | ||
675 | |||
676 | /* unnecessary optimization? */ | ||
677 | lc_unlock(mdev->act_log); | ||
678 | wake_up(&mdev->al_wait); | ||
679 | |||
680 | /* all prepared, submit them */ | ||
681 | for (i = 0; i < nr_elements; i++) { | ||
682 | if (bios[i] == NULL) | ||
683 | break; | ||
684 | if (FAULT_ACTIVE(mdev, DRBD_FAULT_MD_WR)) { | ||
685 | bios[i]->bi_rw = WRITE; | ||
686 | bio_endio(bios[i], -EIO); | ||
687 | } else { | ||
688 | submit_bio(WRITE, bios[i]); | ||
689 | } | ||
690 | } | ||
691 | |||
692 | /* always (try to) flush bitmap to stable storage */ | ||
693 | drbd_md_flush(mdev); | ||
694 | |||
695 | /* In case we did not submit a single IO do not wait for | ||
696 | * them to complete. ( Because we would wait forever here. ) | ||
697 | * | ||
698 | * In case we had IOs and they are already complete, there | ||
699 | * is not point in waiting anyways. | ||
700 | * Therefore this if () ... */ | ||
701 | if (atomic_read(&wc.count)) | ||
702 | wait_for_completion(&wc.io_done); | ||
703 | |||
704 | put_ldev(mdev); | ||
705 | |||
706 | kfree(bios); | ||
707 | return; | ||
708 | |||
709 | free_bios_submit_one_by_one: | ||
710 | /* free everything by calling the endio callback directly. */ | ||
711 | for (i = 0; i < nr_elements && bios[i]; i++) | ||
712 | bio_endio(bios[i], 0); | ||
713 | |||
714 | kfree(bios); | ||
715 | |||
716 | submit_one_by_one: | ||
717 | dev_warn(DEV, "Using the slow drbd_al_to_on_disk_bm()\n"); | ||
718 | |||
719 | for (i = 0; i < mdev->act_log->nr_elements; i++) { | ||
720 | enr = lc_element_by_index(mdev->act_log, i)->lc_number; | ||
721 | if (enr == LC_FREE) | ||
722 | continue; | ||
723 | /* Really slow: if we have al-extents 16..19 active, | ||
724 | * sector 4 will be written four times! Synchronous! */ | ||
725 | drbd_bm_write_sect(mdev, enr/AL_EXT_PER_BM_SECT); | ||
726 | } | ||
727 | |||
728 | lc_unlock(mdev->act_log); | ||
729 | wake_up(&mdev->al_wait); | ||
730 | put_ldev(mdev); | ||
731 | } | ||
732 | |||
733 | /** | 545 | /** |
734 | * drbd_al_apply_to_bm() - Sets the bitmap to diry(1) where covered ba active AL extents | 546 | * drbd_al_apply_to_bm() - Sets the bitmap to diry(1) where covered ba active AL extents |
735 | * @mdev: DRBD device. | 547 | * @mdev: DRBD device. |
@@ -809,7 +621,7 @@ static int w_update_odbm(struct drbd_conf *mdev, struct drbd_work *w, int unused | |||
809 | return 1; | 621 | return 1; |
810 | } | 622 | } |
811 | 623 | ||
812 | drbd_bm_write_sect(mdev, udw->enr); | 624 | drbd_bm_write_page(mdev, rs_extent_to_bm_page(udw->enr)); |
813 | put_ldev(mdev); | 625 | put_ldev(mdev); |
814 | 626 | ||
815 | kfree(udw); | 627 | kfree(udw); |
@@ -889,7 +701,6 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector, | |||
889 | dev_warn(DEV, "Kicking resync_lru element enr=%u " | 701 | dev_warn(DEV, "Kicking resync_lru element enr=%u " |
890 | "out with rs_failed=%d\n", | 702 | "out with rs_failed=%d\n", |
891 | ext->lce.lc_number, ext->rs_failed); | 703 | ext->lce.lc_number, ext->rs_failed); |
892 | set_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags); | ||
893 | } | 704 | } |
894 | ext->rs_left = rs_left; | 705 | ext->rs_left = rs_left; |
895 | ext->rs_failed = success ? 0 : count; | 706 | ext->rs_failed = success ? 0 : count; |
@@ -908,7 +719,6 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector, | |||
908 | drbd_queue_work_front(&mdev->data.work, &udw->w); | 719 | drbd_queue_work_front(&mdev->data.work, &udw->w); |
909 | } else { | 720 | } else { |
910 | dev_warn(DEV, "Could not kmalloc an udw\n"); | 721 | dev_warn(DEV, "Could not kmalloc an udw\n"); |
911 | set_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags); | ||
912 | } | 722 | } |
913 | } | 723 | } |
914 | } else { | 724 | } else { |
@@ -919,6 +729,22 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector, | |||
919 | } | 729 | } |
920 | } | 730 | } |
921 | 731 | ||
732 | void drbd_advance_rs_marks(struct drbd_conf *mdev, unsigned long still_to_go) | ||
733 | { | ||
734 | unsigned long now = jiffies; | ||
735 | unsigned long last = mdev->rs_mark_time[mdev->rs_last_mark]; | ||
736 | int next = (mdev->rs_last_mark + 1) % DRBD_SYNC_MARKS; | ||
737 | if (time_after_eq(now, last + DRBD_SYNC_MARK_STEP)) { | ||
738 | if (mdev->rs_mark_left[mdev->rs_last_mark] != still_to_go && | ||
739 | mdev->state.conn != C_PAUSED_SYNC_T && | ||
740 | mdev->state.conn != C_PAUSED_SYNC_S) { | ||
741 | mdev->rs_mark_time[next] = now; | ||
742 | mdev->rs_mark_left[next] = still_to_go; | ||
743 | mdev->rs_last_mark = next; | ||
744 | } | ||
745 | } | ||
746 | } | ||
747 | |||
922 | /* clear the bit corresponding to the piece of storage in question: | 748 | /* clear the bit corresponding to the piece of storage in question: |
923 | * size byte of data starting from sector. Only clear a bits of the affected | 749 | * size byte of data starting from sector. Only clear a bits of the affected |
924 | * one ore more _aligned_ BM_BLOCK_SIZE blocks. | 750 | * one ore more _aligned_ BM_BLOCK_SIZE blocks. |
@@ -936,7 +762,7 @@ void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size, | |||
936 | int wake_up = 0; | 762 | int wake_up = 0; |
937 | unsigned long flags; | 763 | unsigned long flags; |
938 | 764 | ||
939 | if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) { | 765 | if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_BIO_SIZE) { |
940 | dev_err(DEV, "drbd_set_in_sync: sector=%llus size=%d nonsense!\n", | 766 | dev_err(DEV, "drbd_set_in_sync: sector=%llus size=%d nonsense!\n", |
941 | (unsigned long long)sector, size); | 767 | (unsigned long long)sector, size); |
942 | return; | 768 | return; |
@@ -969,21 +795,9 @@ void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size, | |||
969 | */ | 795 | */ |
970 | count = drbd_bm_clear_bits(mdev, sbnr, ebnr); | 796 | count = drbd_bm_clear_bits(mdev, sbnr, ebnr); |
971 | if (count && get_ldev(mdev)) { | 797 | if (count && get_ldev(mdev)) { |
972 | unsigned long now = jiffies; | 798 | drbd_advance_rs_marks(mdev, drbd_bm_total_weight(mdev)); |
973 | unsigned long last = mdev->rs_mark_time[mdev->rs_last_mark]; | ||
974 | int next = (mdev->rs_last_mark + 1) % DRBD_SYNC_MARKS; | ||
975 | if (time_after_eq(now, last + DRBD_SYNC_MARK_STEP)) { | ||
976 | unsigned long tw = drbd_bm_total_weight(mdev); | ||
977 | if (mdev->rs_mark_left[mdev->rs_last_mark] != tw && | ||
978 | mdev->state.conn != C_PAUSED_SYNC_T && | ||
979 | mdev->state.conn != C_PAUSED_SYNC_S) { | ||
980 | mdev->rs_mark_time[next] = now; | ||
981 | mdev->rs_mark_left[next] = tw; | ||
982 | mdev->rs_last_mark = next; | ||
983 | } | ||
984 | } | ||
985 | spin_lock_irqsave(&mdev->al_lock, flags); | 799 | spin_lock_irqsave(&mdev->al_lock, flags); |
986 | drbd_try_clear_on_disk_bm(mdev, sector, count, TRUE); | 800 | drbd_try_clear_on_disk_bm(mdev, sector, count, true); |
987 | spin_unlock_irqrestore(&mdev->al_lock, flags); | 801 | spin_unlock_irqrestore(&mdev->al_lock, flags); |
988 | 802 | ||
989 | /* just wake_up unconditional now, various lc_chaged(), | 803 | /* just wake_up unconditional now, various lc_chaged(), |
@@ -998,27 +812,27 @@ void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size, | |||
998 | /* | 812 | /* |
999 | * this is intended to set one request worth of data out of sync. | 813 | * this is intended to set one request worth of data out of sync. |
1000 | * affects at least 1 bit, | 814 | * affects at least 1 bit, |
1001 | * and at most 1+DRBD_MAX_SEGMENT_SIZE/BM_BLOCK_SIZE bits. | 815 | * and at most 1+DRBD_MAX_BIO_SIZE/BM_BLOCK_SIZE bits. |
1002 | * | 816 | * |
1003 | * called by tl_clear and drbd_send_dblock (==drbd_make_request). | 817 | * called by tl_clear and drbd_send_dblock (==drbd_make_request). |
1004 | * so this can be _any_ process. | 818 | * so this can be _any_ process. |
1005 | */ | 819 | */ |
1006 | void __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size, | 820 | int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size, |
1007 | const char *file, const unsigned int line) | 821 | const char *file, const unsigned int line) |
1008 | { | 822 | { |
1009 | unsigned long sbnr, ebnr, lbnr, flags; | 823 | unsigned long sbnr, ebnr, lbnr, flags; |
1010 | sector_t esector, nr_sectors; | 824 | sector_t esector, nr_sectors; |
1011 | unsigned int enr, count; | 825 | unsigned int enr, count = 0; |
1012 | struct lc_element *e; | 826 | struct lc_element *e; |
1013 | 827 | ||
1014 | if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) { | 828 | if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_BIO_SIZE) { |
1015 | dev_err(DEV, "sector: %llus, size: %d\n", | 829 | dev_err(DEV, "sector: %llus, size: %d\n", |
1016 | (unsigned long long)sector, size); | 830 | (unsigned long long)sector, size); |
1017 | return; | 831 | return 0; |
1018 | } | 832 | } |
1019 | 833 | ||
1020 | if (!get_ldev(mdev)) | 834 | if (!get_ldev(mdev)) |
1021 | return; /* no disk, no metadata, no bitmap to set bits in */ | 835 | return 0; /* no disk, no metadata, no bitmap to set bits in */ |
1022 | 836 | ||
1023 | nr_sectors = drbd_get_capacity(mdev->this_bdev); | 837 | nr_sectors = drbd_get_capacity(mdev->this_bdev); |
1024 | esector = sector + (size >> 9) - 1; | 838 | esector = sector + (size >> 9) - 1; |
@@ -1048,6 +862,8 @@ void __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size, | |||
1048 | 862 | ||
1049 | out: | 863 | out: |
1050 | put_ldev(mdev); | 864 | put_ldev(mdev); |
865 | |||
866 | return count; | ||
1051 | } | 867 | } |
1052 | 868 | ||
1053 | static | 869 | static |
@@ -1128,7 +944,10 @@ int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector) | |||
1128 | unsigned int enr = BM_SECT_TO_EXT(sector); | 944 | unsigned int enr = BM_SECT_TO_EXT(sector); |
1129 | struct bm_extent *bm_ext; | 945 | struct bm_extent *bm_ext; |
1130 | int i, sig; | 946 | int i, sig; |
947 | int sa = 200; /* Step aside 200 times, then grab the extent and let app-IO wait. | ||
948 | 200 times -> 20 seconds. */ | ||
1131 | 949 | ||
950 | retry: | ||
1132 | sig = wait_event_interruptible(mdev->al_wait, | 951 | sig = wait_event_interruptible(mdev->al_wait, |
1133 | (bm_ext = _bme_get(mdev, enr))); | 952 | (bm_ext = _bme_get(mdev, enr))); |
1134 | if (sig) | 953 | if (sig) |
@@ -1139,16 +958,25 @@ int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector) | |||
1139 | 958 | ||
1140 | for (i = 0; i < AL_EXT_PER_BM_SECT; i++) { | 959 | for (i = 0; i < AL_EXT_PER_BM_SECT; i++) { |
1141 | sig = wait_event_interruptible(mdev->al_wait, | 960 | sig = wait_event_interruptible(mdev->al_wait, |
1142 | !_is_in_al(mdev, enr * AL_EXT_PER_BM_SECT + i)); | 961 | !_is_in_al(mdev, enr * AL_EXT_PER_BM_SECT + i) || |
1143 | if (sig) { | 962 | test_bit(BME_PRIORITY, &bm_ext->flags)); |
963 | |||
964 | if (sig || (test_bit(BME_PRIORITY, &bm_ext->flags) && sa)) { | ||
1144 | spin_lock_irq(&mdev->al_lock); | 965 | spin_lock_irq(&mdev->al_lock); |
1145 | if (lc_put(mdev->resync, &bm_ext->lce) == 0) { | 966 | if (lc_put(mdev->resync, &bm_ext->lce) == 0) { |
1146 | clear_bit(BME_NO_WRITES, &bm_ext->flags); | 967 | bm_ext->flags = 0; /* clears BME_NO_WRITES and eventually BME_PRIORITY */ |
1147 | mdev->resync_locked--; | 968 | mdev->resync_locked--; |
1148 | wake_up(&mdev->al_wait); | 969 | wake_up(&mdev->al_wait); |
1149 | } | 970 | } |
1150 | spin_unlock_irq(&mdev->al_lock); | 971 | spin_unlock_irq(&mdev->al_lock); |
1151 | return -EINTR; | 972 | if (sig) |
973 | return -EINTR; | ||
974 | if (schedule_timeout_interruptible(HZ/10)) | ||
975 | return -EINTR; | ||
976 | if (sa && --sa == 0) | ||
977 | dev_warn(DEV,"drbd_rs_begin_io() stepped aside for 20sec." | ||
978 | "Resync stalled?\n"); | ||
979 | goto retry; | ||
1152 | } | 980 | } |
1153 | } | 981 | } |
1154 | set_bit(BME_LOCKED, &bm_ext->flags); | 982 | set_bit(BME_LOCKED, &bm_ext->flags); |
@@ -1291,8 +1119,7 @@ void drbd_rs_complete_io(struct drbd_conf *mdev, sector_t sector) | |||
1291 | } | 1119 | } |
1292 | 1120 | ||
1293 | if (lc_put(mdev->resync, &bm_ext->lce) == 0) { | 1121 | if (lc_put(mdev->resync, &bm_ext->lce) == 0) { |
1294 | clear_bit(BME_LOCKED, &bm_ext->flags); | 1122 | bm_ext->flags = 0; /* clear BME_LOCKED, BME_NO_WRITES and BME_PRIORITY */ |
1295 | clear_bit(BME_NO_WRITES, &bm_ext->flags); | ||
1296 | mdev->resync_locked--; | 1123 | mdev->resync_locked--; |
1297 | wake_up(&mdev->al_wait); | 1124 | wake_up(&mdev->al_wait); |
1298 | } | 1125 | } |
@@ -1383,7 +1210,7 @@ void drbd_rs_failed_io(struct drbd_conf *mdev, sector_t sector, int size) | |||
1383 | sector_t esector, nr_sectors; | 1210 | sector_t esector, nr_sectors; |
1384 | int wake_up = 0; | 1211 | int wake_up = 0; |
1385 | 1212 | ||
1386 | if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) { | 1213 | if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_BIO_SIZE) { |
1387 | dev_err(DEV, "drbd_rs_failed_io: sector=%llus size=%d nonsense!\n", | 1214 | dev_err(DEV, "drbd_rs_failed_io: sector=%llus size=%d nonsense!\n", |
1388 | (unsigned long long)sector, size); | 1215 | (unsigned long long)sector, size); |
1389 | return; | 1216 | return; |
@@ -1420,7 +1247,7 @@ void drbd_rs_failed_io(struct drbd_conf *mdev, sector_t sector, int size) | |||
1420 | mdev->rs_failed += count; | 1247 | mdev->rs_failed += count; |
1421 | 1248 | ||
1422 | if (get_ldev(mdev)) { | 1249 | if (get_ldev(mdev)) { |
1423 | drbd_try_clear_on_disk_bm(mdev, sector, count, FALSE); | 1250 | drbd_try_clear_on_disk_bm(mdev, sector, count, false); |
1424 | put_ldev(mdev); | 1251 | put_ldev(mdev); |
1425 | } | 1252 | } |
1426 | 1253 | ||
diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 0645ca829a94..f0ae63d2df65 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c | |||
@@ -28,18 +28,58 @@ | |||
28 | #include <linux/drbd.h> | 28 | #include <linux/drbd.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <asm/kmap_types.h> | 30 | #include <asm/kmap_types.h> |
31 | |||
32 | #include <asm-generic/bitops/le.h> | ||
33 | |||
31 | #include "drbd_int.h" | 34 | #include "drbd_int.h" |
32 | 35 | ||
36 | |||
33 | /* OPAQUE outside this file! | 37 | /* OPAQUE outside this file! |
34 | * interface defined in drbd_int.h | 38 | * interface defined in drbd_int.h |
35 | 39 | ||
36 | * convention: | 40 | * convention: |
37 | * function name drbd_bm_... => used elsewhere, "public". | 41 | * function name drbd_bm_... => used elsewhere, "public". |
38 | * function name bm_... => internal to implementation, "private". | 42 | * function name bm_... => internal to implementation, "private". |
43 | */ | ||
44 | |||
45 | |||
46 | /* | ||
47 | * LIMITATIONS: | ||
48 | * We want to support >= peta byte of backend storage, while for now still using | ||
49 | * a granularity of one bit per 4KiB of storage. | ||
50 | * 1 << 50 bytes backend storage (1 PiB) | ||
51 | * 1 << (50 - 12) bits needed | ||
52 | * 38 --> we need u64 to index and count bits | ||
53 | * 1 << (38 - 3) bitmap bytes needed | ||
54 | * 35 --> we still need u64 to index and count bytes | ||
55 | * (that's 32 GiB of bitmap for 1 PiB storage) | ||
56 | * 1 << (35 - 2) 32bit longs needed | ||
57 | * 33 --> we'd even need u64 to index and count 32bit long words. | ||
58 | * 1 << (35 - 3) 64bit longs needed | ||
59 | * 32 --> we could get away with a 32bit unsigned int to index and count | ||
60 | * 64bit long words, but I rather stay with unsigned long for now. | ||
61 | * We probably should neither count nor point to bytes or long words | ||
62 | * directly, but either by bitnumber, or by page index and offset. | ||
63 | * 1 << (35 - 12) | ||
64 | * 22 --> we need that much 4KiB pages of bitmap. | ||
65 | * 1 << (22 + 3) --> on a 64bit arch, | ||
66 | * we need 32 MiB to store the array of page pointers. | ||
67 | * | ||
68 | * Because I'm lazy, and because the resulting patch was too large, too ugly | ||
69 | * and still incomplete, on 32bit we still "only" support 16 TiB (minus some), | ||
70 | * (1 << 32) bits * 4k storage. | ||
71 | * | ||
39 | 72 | ||
40 | * Note that since find_first_bit returns int, at the current granularity of | 73 | * bitmap storage and IO: |
41 | * the bitmap (4KB per byte), this implementation "only" supports up to | 74 | * Bitmap is stored little endian on disk, and is kept little endian in |
42 | * 1<<(32+12) == 16 TB... | 75 | * core memory. Currently we still hold the full bitmap in core as long |
76 | * as we are "attached" to a local disk, which at 32 GiB for 1PiB storage | ||
77 | * seems excessive. | ||
78 | * | ||
79 | * We plan to reduce the amount of in-core bitmap pages by pageing them in | ||
80 | * and out against their on-disk location as necessary, but need to make | ||
81 | * sure we don't cause too much meta data IO, and must not deadlock in | ||
82 | * tight memory situations. This needs some more work. | ||
43 | */ | 83 | */ |
44 | 84 | ||
45 | /* | 85 | /* |
@@ -55,13 +95,9 @@ | |||
55 | struct drbd_bitmap { | 95 | struct drbd_bitmap { |
56 | struct page **bm_pages; | 96 | struct page **bm_pages; |
57 | spinlock_t bm_lock; | 97 | spinlock_t bm_lock; |
58 | /* WARNING unsigned long bm_*: | 98 | |
59 | * 32bit number of bit offset is just enough for 512 MB bitmap. | 99 | /* see LIMITATIONS: above */ |
60 | * it will blow up if we make the bitmap bigger... | 100 | |
61 | * not that it makes much sense to have a bitmap that large, | ||
62 | * rather change the granularity to 16k or 64k or something. | ||
63 | * (that implies other problems, however...) | ||
64 | */ | ||
65 | unsigned long bm_set; /* nr of set bits; THINK maybe atomic_t? */ | 101 | unsigned long bm_set; /* nr of set bits; THINK maybe atomic_t? */ |
66 | unsigned long bm_bits; | 102 | unsigned long bm_bits; |
67 | size_t bm_words; | 103 | size_t bm_words; |
@@ -69,29 +105,18 @@ struct drbd_bitmap { | |||
69 | sector_t bm_dev_capacity; | 105 | sector_t bm_dev_capacity; |
70 | struct mutex bm_change; /* serializes resize operations */ | 106 | struct mutex bm_change; /* serializes resize operations */ |
71 | 107 | ||
72 | atomic_t bm_async_io; | 108 | wait_queue_head_t bm_io_wait; /* used to serialize IO of single pages */ |
73 | wait_queue_head_t bm_io_wait; | ||
74 | 109 | ||
75 | unsigned long bm_flags; | 110 | enum bm_flag bm_flags; |
76 | 111 | ||
77 | /* debugging aid, in case we are still racy somewhere */ | 112 | /* debugging aid, in case we are still racy somewhere */ |
78 | char *bm_why; | 113 | char *bm_why; |
79 | struct task_struct *bm_task; | 114 | struct task_struct *bm_task; |
80 | }; | 115 | }; |
81 | 116 | ||
82 | /* definition of bits in bm_flags */ | ||
83 | #define BM_LOCKED 0 | ||
84 | #define BM_MD_IO_ERROR 1 | ||
85 | #define BM_P_VMALLOCED 2 | ||
86 | |||
87 | static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, | 117 | static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, |
88 | unsigned long e, int val, const enum km_type km); | 118 | unsigned long e, int val, const enum km_type km); |
89 | 119 | ||
90 | static int bm_is_locked(struct drbd_bitmap *b) | ||
91 | { | ||
92 | return test_bit(BM_LOCKED, &b->bm_flags); | ||
93 | } | ||
94 | |||
95 | #define bm_print_lock_info(m) __bm_print_lock_info(m, __func__) | 120 | #define bm_print_lock_info(m) __bm_print_lock_info(m, __func__) |
96 | static void __bm_print_lock_info(struct drbd_conf *mdev, const char *func) | 121 | static void __bm_print_lock_info(struct drbd_conf *mdev, const char *func) |
97 | { | 122 | { |
@@ -108,7 +133,7 @@ static void __bm_print_lock_info(struct drbd_conf *mdev, const char *func) | |||
108 | b->bm_task == mdev->worker.task ? "worker" : "?"); | 133 | b->bm_task == mdev->worker.task ? "worker" : "?"); |
109 | } | 134 | } |
110 | 135 | ||
111 | void drbd_bm_lock(struct drbd_conf *mdev, char *why) | 136 | void drbd_bm_lock(struct drbd_conf *mdev, char *why, enum bm_flag flags) |
112 | { | 137 | { |
113 | struct drbd_bitmap *b = mdev->bitmap; | 138 | struct drbd_bitmap *b = mdev->bitmap; |
114 | int trylock_failed; | 139 | int trylock_failed; |
@@ -131,8 +156,9 @@ void drbd_bm_lock(struct drbd_conf *mdev, char *why) | |||
131 | b->bm_task == mdev->worker.task ? "worker" : "?"); | 156 | b->bm_task == mdev->worker.task ? "worker" : "?"); |
132 | mutex_lock(&b->bm_change); | 157 | mutex_lock(&b->bm_change); |
133 | } | 158 | } |
134 | if (__test_and_set_bit(BM_LOCKED, &b->bm_flags)) | 159 | if (BM_LOCKED_MASK & b->bm_flags) |
135 | dev_err(DEV, "FIXME bitmap already locked in bm_lock\n"); | 160 | dev_err(DEV, "FIXME bitmap already locked in bm_lock\n"); |
161 | b->bm_flags |= flags & BM_LOCKED_MASK; | ||
136 | 162 | ||
137 | b->bm_why = why; | 163 | b->bm_why = why; |
138 | b->bm_task = current; | 164 | b->bm_task = current; |
@@ -146,31 +172,137 @@ void drbd_bm_unlock(struct drbd_conf *mdev) | |||
146 | return; | 172 | return; |
147 | } | 173 | } |
148 | 174 | ||
149 | if (!__test_and_clear_bit(BM_LOCKED, &mdev->bitmap->bm_flags)) | 175 | if (!(BM_LOCKED_MASK & mdev->bitmap->bm_flags)) |
150 | dev_err(DEV, "FIXME bitmap not locked in bm_unlock\n"); | 176 | dev_err(DEV, "FIXME bitmap not locked in bm_unlock\n"); |
151 | 177 | ||
178 | b->bm_flags &= ~BM_LOCKED_MASK; | ||
152 | b->bm_why = NULL; | 179 | b->bm_why = NULL; |
153 | b->bm_task = NULL; | 180 | b->bm_task = NULL; |
154 | mutex_unlock(&b->bm_change); | 181 | mutex_unlock(&b->bm_change); |
155 | } | 182 | } |
156 | 183 | ||
157 | /* word offset to long pointer */ | 184 | /* we store some "meta" info about our pages in page->private */ |
158 | static unsigned long *__bm_map_paddr(struct drbd_bitmap *b, unsigned long offset, const enum km_type km) | 185 | /* at a granularity of 4k storage per bitmap bit: |
186 | * one peta byte storage: 1<<50 byte, 1<<38 * 4k storage blocks | ||
187 | * 1<<38 bits, | ||
188 | * 1<<23 4k bitmap pages. | ||
189 | * Use 24 bits as page index, covers 2 peta byte storage | ||
190 | * at a granularity of 4k per bit. | ||
191 | * Used to report the failed page idx on io error from the endio handlers. | ||
192 | */ | ||
193 | #define BM_PAGE_IDX_MASK ((1UL<<24)-1) | ||
194 | /* this page is currently read in, or written back */ | ||
195 | #define BM_PAGE_IO_LOCK 31 | ||
196 | /* if there has been an IO error for this page */ | ||
197 | #define BM_PAGE_IO_ERROR 30 | ||
198 | /* this is to be able to intelligently skip disk IO, | ||
199 | * set if bits have been set since last IO. */ | ||
200 | #define BM_PAGE_NEED_WRITEOUT 29 | ||
201 | /* to mark for lazy writeout once syncer cleared all clearable bits, | ||
202 | * we if bits have been cleared since last IO. */ | ||
203 | #define BM_PAGE_LAZY_WRITEOUT 28 | ||
204 | |||
205 | /* store_page_idx uses non-atomic assingment. It is only used directly after | ||
206 | * allocating the page. All other bm_set_page_* and bm_clear_page_* need to | ||
207 | * use atomic bit manipulation, as set_out_of_sync (and therefore bitmap | ||
208 | * changes) may happen from various contexts, and wait_on_bit/wake_up_bit | ||
209 | * requires it all to be atomic as well. */ | ||
210 | static void bm_store_page_idx(struct page *page, unsigned long idx) | ||
159 | { | 211 | { |
160 | struct page *page; | 212 | BUG_ON(0 != (idx & ~BM_PAGE_IDX_MASK)); |
161 | unsigned long page_nr; | 213 | page_private(page) |= idx; |
214 | } | ||
215 | |||
216 | static unsigned long bm_page_to_idx(struct page *page) | ||
217 | { | ||
218 | return page_private(page) & BM_PAGE_IDX_MASK; | ||
219 | } | ||
220 | |||
221 | /* As is very unlikely that the same page is under IO from more than one | ||
222 | * context, we can get away with a bit per page and one wait queue per bitmap. | ||
223 | */ | ||
224 | static void bm_page_lock_io(struct drbd_conf *mdev, int page_nr) | ||
225 | { | ||
226 | struct drbd_bitmap *b = mdev->bitmap; | ||
227 | void *addr = &page_private(b->bm_pages[page_nr]); | ||
228 | wait_event(b->bm_io_wait, !test_and_set_bit(BM_PAGE_IO_LOCK, addr)); | ||
229 | } | ||
230 | |||
231 | static void bm_page_unlock_io(struct drbd_conf *mdev, int page_nr) | ||
232 | { | ||
233 | struct drbd_bitmap *b = mdev->bitmap; | ||
234 | void *addr = &page_private(b->bm_pages[page_nr]); | ||
235 | clear_bit(BM_PAGE_IO_LOCK, addr); | ||
236 | smp_mb__after_clear_bit(); | ||
237 | wake_up(&mdev->bitmap->bm_io_wait); | ||
238 | } | ||
239 | |||
240 | /* set _before_ submit_io, so it may be reset due to being changed | ||
241 | * while this page is in flight... will get submitted later again */ | ||
242 | static void bm_set_page_unchanged(struct page *page) | ||
243 | { | ||
244 | /* use cmpxchg? */ | ||
245 | clear_bit(BM_PAGE_NEED_WRITEOUT, &page_private(page)); | ||
246 | clear_bit(BM_PAGE_LAZY_WRITEOUT, &page_private(page)); | ||
247 | } | ||
162 | 248 | ||
249 | static void bm_set_page_need_writeout(struct page *page) | ||
250 | { | ||
251 | set_bit(BM_PAGE_NEED_WRITEOUT, &page_private(page)); | ||
252 | } | ||
253 | |||
254 | static int bm_test_page_unchanged(struct page *page) | ||
255 | { | ||
256 | volatile const unsigned long *addr = &page_private(page); | ||
257 | return (*addr & ((1UL<<BM_PAGE_NEED_WRITEOUT)|(1UL<<BM_PAGE_LAZY_WRITEOUT))) == 0; | ||
258 | } | ||
259 | |||
260 | static void bm_set_page_io_err(struct page *page) | ||
261 | { | ||
262 | set_bit(BM_PAGE_IO_ERROR, &page_private(page)); | ||
263 | } | ||
264 | |||
265 | static void bm_clear_page_io_err(struct page *page) | ||
266 | { | ||
267 | clear_bit(BM_PAGE_IO_ERROR, &page_private(page)); | ||
268 | } | ||
269 | |||
270 | static void bm_set_page_lazy_writeout(struct page *page) | ||
271 | { | ||
272 | set_bit(BM_PAGE_LAZY_WRITEOUT, &page_private(page)); | ||
273 | } | ||
274 | |||
275 | static int bm_test_page_lazy_writeout(struct page *page) | ||
276 | { | ||
277 | return test_bit(BM_PAGE_LAZY_WRITEOUT, &page_private(page)); | ||
278 | } | ||
279 | |||
280 | /* on a 32bit box, this would allow for exactly (2<<38) bits. */ | ||
281 | static unsigned int bm_word_to_page_idx(struct drbd_bitmap *b, unsigned long long_nr) | ||
282 | { | ||
163 | /* page_nr = (word*sizeof(long)) >> PAGE_SHIFT; */ | 283 | /* page_nr = (word*sizeof(long)) >> PAGE_SHIFT; */ |
164 | page_nr = offset >> (PAGE_SHIFT - LN2_BPL + 3); | 284 | unsigned int page_nr = long_nr >> (PAGE_SHIFT - LN2_BPL + 3); |
165 | BUG_ON(page_nr >= b->bm_number_of_pages); | 285 | BUG_ON(page_nr >= b->bm_number_of_pages); |
166 | page = b->bm_pages[page_nr]; | 286 | return page_nr; |
287 | } | ||
167 | 288 | ||
289 | static unsigned int bm_bit_to_page_idx(struct drbd_bitmap *b, u64 bitnr) | ||
290 | { | ||
291 | /* page_nr = (bitnr/8) >> PAGE_SHIFT; */ | ||
292 | unsigned int page_nr = bitnr >> (PAGE_SHIFT + 3); | ||
293 | BUG_ON(page_nr >= b->bm_number_of_pages); | ||
294 | return page_nr; | ||
295 | } | ||
296 | |||
297 | static unsigned long *__bm_map_pidx(struct drbd_bitmap *b, unsigned int idx, const enum km_type km) | ||
298 | { | ||
299 | struct page *page = b->bm_pages[idx]; | ||
168 | return (unsigned long *) kmap_atomic(page, km); | 300 | return (unsigned long *) kmap_atomic(page, km); |
169 | } | 301 | } |
170 | 302 | ||
171 | static unsigned long * bm_map_paddr(struct drbd_bitmap *b, unsigned long offset) | 303 | static unsigned long *bm_map_pidx(struct drbd_bitmap *b, unsigned int idx) |
172 | { | 304 | { |
173 | return __bm_map_paddr(b, offset, KM_IRQ1); | 305 | return __bm_map_pidx(b, idx, KM_IRQ1); |
174 | } | 306 | } |
175 | 307 | ||
176 | static void __bm_unmap(unsigned long *p_addr, const enum km_type km) | 308 | static void __bm_unmap(unsigned long *p_addr, const enum km_type km) |
@@ -202,6 +334,7 @@ static void bm_unmap(unsigned long *p_addr) | |||
202 | * to be able to report device specific. | 334 | * to be able to report device specific. |
203 | */ | 335 | */ |
204 | 336 | ||
337 | |||
205 | static void bm_free_pages(struct page **pages, unsigned long number) | 338 | static void bm_free_pages(struct page **pages, unsigned long number) |
206 | { | 339 | { |
207 | unsigned long i; | 340 | unsigned long i; |
@@ -269,6 +402,9 @@ static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want) | |||
269 | bm_vk_free(new_pages, vmalloced); | 402 | bm_vk_free(new_pages, vmalloced); |
270 | return NULL; | 403 | return NULL; |
271 | } | 404 | } |
405 | /* we want to know which page it is | ||
406 | * from the endio handlers */ | ||
407 | bm_store_page_idx(page, i); | ||
272 | new_pages[i] = page; | 408 | new_pages[i] = page; |
273 | } | 409 | } |
274 | } else { | 410 | } else { |
@@ -280,9 +416,9 @@ static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want) | |||
280 | } | 416 | } |
281 | 417 | ||
282 | if (vmalloced) | 418 | if (vmalloced) |
283 | set_bit(BM_P_VMALLOCED, &b->bm_flags); | 419 | b->bm_flags |= BM_P_VMALLOCED; |
284 | else | 420 | else |
285 | clear_bit(BM_P_VMALLOCED, &b->bm_flags); | 421 | b->bm_flags &= ~BM_P_VMALLOCED; |
286 | 422 | ||
287 | return new_pages; | 423 | return new_pages; |
288 | } | 424 | } |
@@ -319,7 +455,7 @@ void drbd_bm_cleanup(struct drbd_conf *mdev) | |||
319 | { | 455 | { |
320 | ERR_IF (!mdev->bitmap) return; | 456 | ERR_IF (!mdev->bitmap) return; |
321 | bm_free_pages(mdev->bitmap->bm_pages, mdev->bitmap->bm_number_of_pages); | 457 | bm_free_pages(mdev->bitmap->bm_pages, mdev->bitmap->bm_number_of_pages); |
322 | bm_vk_free(mdev->bitmap->bm_pages, test_bit(BM_P_VMALLOCED, &mdev->bitmap->bm_flags)); | 458 | bm_vk_free(mdev->bitmap->bm_pages, (BM_P_VMALLOCED & mdev->bitmap->bm_flags)); |
323 | kfree(mdev->bitmap); | 459 | kfree(mdev->bitmap); |
324 | mdev->bitmap = NULL; | 460 | mdev->bitmap = NULL; |
325 | } | 461 | } |
@@ -329,22 +465,39 @@ void drbd_bm_cleanup(struct drbd_conf *mdev) | |||
329 | * this masks out the remaining bits. | 465 | * this masks out the remaining bits. |
330 | * Returns the number of bits cleared. | 466 | * Returns the number of bits cleared. |
331 | */ | 467 | */ |
468 | #define BITS_PER_PAGE (1UL << (PAGE_SHIFT + 3)) | ||
469 | #define BITS_PER_PAGE_MASK (BITS_PER_PAGE - 1) | ||
470 | #define BITS_PER_LONG_MASK (BITS_PER_LONG - 1) | ||
332 | static int bm_clear_surplus(struct drbd_bitmap *b) | 471 | static int bm_clear_surplus(struct drbd_bitmap *b) |
333 | { | 472 | { |
334 | const unsigned long mask = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) - 1; | 473 | unsigned long mask; |
335 | size_t w = b->bm_bits >> LN2_BPL; | ||
336 | int cleared = 0; | ||
337 | unsigned long *p_addr, *bm; | 474 | unsigned long *p_addr, *bm; |
475 | int tmp; | ||
476 | int cleared = 0; | ||
338 | 477 | ||
339 | p_addr = bm_map_paddr(b, w); | 478 | /* number of bits modulo bits per page */ |
340 | bm = p_addr + MLPP(w); | 479 | tmp = (b->bm_bits & BITS_PER_PAGE_MASK); |
341 | if (w < b->bm_words) { | 480 | /* mask the used bits of the word containing the last bit */ |
481 | mask = (1UL << (tmp & BITS_PER_LONG_MASK)) -1; | ||
482 | /* bitmap is always stored little endian, | ||
483 | * on disk and in core memory alike */ | ||
484 | mask = cpu_to_lel(mask); | ||
485 | |||
486 | p_addr = bm_map_pidx(b, b->bm_number_of_pages - 1); | ||
487 | bm = p_addr + (tmp/BITS_PER_LONG); | ||
488 | if (mask) { | ||
489 | /* If mask != 0, we are not exactly aligned, so bm now points | ||
490 | * to the long containing the last bit. | ||
491 | * If mask == 0, bm already points to the word immediately | ||
492 | * after the last (long word aligned) bit. */ | ||
342 | cleared = hweight_long(*bm & ~mask); | 493 | cleared = hweight_long(*bm & ~mask); |
343 | *bm &= mask; | 494 | *bm &= mask; |
344 | w++; bm++; | 495 | bm++; |
345 | } | 496 | } |
346 | 497 | ||
347 | if (w < b->bm_words) { | 498 | if (BITS_PER_LONG == 32 && ((bm - p_addr) & 1) == 1) { |
499 | /* on a 32bit arch, we may need to zero out | ||
500 | * a padding long to align with a 64bit remote */ | ||
348 | cleared += hweight_long(*bm); | 501 | cleared += hweight_long(*bm); |
349 | *bm = 0; | 502 | *bm = 0; |
350 | } | 503 | } |
@@ -354,66 +507,75 @@ static int bm_clear_surplus(struct drbd_bitmap *b) | |||
354 | 507 | ||
355 | static void bm_set_surplus(struct drbd_bitmap *b) | 508 | static void bm_set_surplus(struct drbd_bitmap *b) |
356 | { | 509 | { |
357 | const unsigned long mask = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) - 1; | 510 | unsigned long mask; |
358 | size_t w = b->bm_bits >> LN2_BPL; | ||
359 | unsigned long *p_addr, *bm; | 511 | unsigned long *p_addr, *bm; |
360 | 512 | int tmp; | |
361 | p_addr = bm_map_paddr(b, w); | 513 | |
362 | bm = p_addr + MLPP(w); | 514 | /* number of bits modulo bits per page */ |
363 | if (w < b->bm_words) { | 515 | tmp = (b->bm_bits & BITS_PER_PAGE_MASK); |
516 | /* mask the used bits of the word containing the last bit */ | ||
517 | mask = (1UL << (tmp & BITS_PER_LONG_MASK)) -1; | ||
518 | /* bitmap is always stored little endian, | ||
519 | * on disk and in core memory alike */ | ||
520 | mask = cpu_to_lel(mask); | ||
521 | |||
522 | p_addr = bm_map_pidx(b, b->bm_number_of_pages - 1); | ||
523 | bm = p_addr + (tmp/BITS_PER_LONG); | ||
524 | if (mask) { | ||
525 | /* If mask != 0, we are not exactly aligned, so bm now points | ||
526 | * to the long containing the last bit. | ||
527 | * If mask == 0, bm already points to the word immediately | ||
528 | * after the last (long word aligned) bit. */ | ||
364 | *bm |= ~mask; | 529 | *bm |= ~mask; |
365 | bm++; w++; | 530 | bm++; |
366 | } | 531 | } |
367 | 532 | ||
368 | if (w < b->bm_words) { | 533 | if (BITS_PER_LONG == 32 && ((bm - p_addr) & 1) == 1) { |
369 | *bm = ~(0UL); | 534 | /* on a 32bit arch, we may need to zero out |
535 | * a padding long to align with a 64bit remote */ | ||
536 | *bm = ~0UL; | ||
370 | } | 537 | } |
371 | bm_unmap(p_addr); | 538 | bm_unmap(p_addr); |
372 | } | 539 | } |
373 | 540 | ||
374 | static unsigned long __bm_count_bits(struct drbd_bitmap *b, const int swap_endian) | 541 | /* you better not modify the bitmap while this is running, |
542 | * or its results will be stale */ | ||
543 | static unsigned long bm_count_bits(struct drbd_bitmap *b) | ||
375 | { | 544 | { |
376 | unsigned long *p_addr, *bm, offset = 0; | 545 | unsigned long *p_addr; |
377 | unsigned long bits = 0; | 546 | unsigned long bits = 0; |
378 | unsigned long i, do_now; | 547 | unsigned long mask = (1UL << (b->bm_bits & BITS_PER_LONG_MASK)) -1; |
379 | 548 | int idx, i, last_word; | |
380 | while (offset < b->bm_words) { | 549 | |
381 | i = do_now = min_t(size_t, b->bm_words-offset, LWPP); | 550 | /* all but last page */ |
382 | p_addr = __bm_map_paddr(b, offset, KM_USER0); | 551 | for (idx = 0; idx < b->bm_number_of_pages - 1; idx++) { |
383 | bm = p_addr + MLPP(offset); | 552 | p_addr = __bm_map_pidx(b, idx, KM_USER0); |
384 | while (i--) { | 553 | for (i = 0; i < LWPP; i++) |
385 | #ifndef __LITTLE_ENDIAN | 554 | bits += hweight_long(p_addr[i]); |
386 | if (swap_endian) | ||
387 | *bm = lel_to_cpu(*bm); | ||
388 | #endif | ||
389 | bits += hweight_long(*bm++); | ||
390 | } | ||
391 | __bm_unmap(p_addr, KM_USER0); | 555 | __bm_unmap(p_addr, KM_USER0); |
392 | offset += do_now; | ||
393 | cond_resched(); | 556 | cond_resched(); |
394 | } | 557 | } |
395 | 558 | /* last (or only) page */ | |
559 | last_word = ((b->bm_bits - 1) & BITS_PER_PAGE_MASK) >> LN2_BPL; | ||
560 | p_addr = __bm_map_pidx(b, idx, KM_USER0); | ||
561 | for (i = 0; i < last_word; i++) | ||
562 | bits += hweight_long(p_addr[i]); | ||
563 | p_addr[last_word] &= cpu_to_lel(mask); | ||
564 | bits += hweight_long(p_addr[last_word]); | ||
565 | /* 32bit arch, may have an unused padding long */ | ||
566 | if (BITS_PER_LONG == 32 && (last_word & 1) == 0) | ||
567 | p_addr[last_word+1] = 0; | ||
568 | __bm_unmap(p_addr, KM_USER0); | ||
396 | return bits; | 569 | return bits; |
397 | } | 570 | } |
398 | 571 | ||
399 | static unsigned long bm_count_bits(struct drbd_bitmap *b) | ||
400 | { | ||
401 | return __bm_count_bits(b, 0); | ||
402 | } | ||
403 | |||
404 | static unsigned long bm_count_bits_swap_endian(struct drbd_bitmap *b) | ||
405 | { | ||
406 | return __bm_count_bits(b, 1); | ||
407 | } | ||
408 | |||
409 | /* offset and len in long words.*/ | 572 | /* offset and len in long words.*/ |
410 | static void bm_memset(struct drbd_bitmap *b, size_t offset, int c, size_t len) | 573 | static void bm_memset(struct drbd_bitmap *b, size_t offset, int c, size_t len) |
411 | { | 574 | { |
412 | unsigned long *p_addr, *bm; | 575 | unsigned long *p_addr, *bm; |
576 | unsigned int idx; | ||
413 | size_t do_now, end; | 577 | size_t do_now, end; |
414 | 578 | ||
415 | #define BM_SECTORS_PER_BIT (BM_BLOCK_SIZE/512) | ||
416 | |||
417 | end = offset + len; | 579 | end = offset + len; |
418 | 580 | ||
419 | if (end > b->bm_words) { | 581 | if (end > b->bm_words) { |
@@ -423,15 +585,16 @@ static void bm_memset(struct drbd_bitmap *b, size_t offset, int c, size_t len) | |||
423 | 585 | ||
424 | while (offset < end) { | 586 | while (offset < end) { |
425 | do_now = min_t(size_t, ALIGN(offset + 1, LWPP), end) - offset; | 587 | do_now = min_t(size_t, ALIGN(offset + 1, LWPP), end) - offset; |
426 | p_addr = bm_map_paddr(b, offset); | 588 | idx = bm_word_to_page_idx(b, offset); |
589 | p_addr = bm_map_pidx(b, idx); | ||
427 | bm = p_addr + MLPP(offset); | 590 | bm = p_addr + MLPP(offset); |
428 | if (bm+do_now > p_addr + LWPP) { | 591 | if (bm+do_now > p_addr + LWPP) { |
429 | printk(KERN_ALERT "drbd: BUG BUG BUG! p_addr:%p bm:%p do_now:%d\n", | 592 | printk(KERN_ALERT "drbd: BUG BUG BUG! p_addr:%p bm:%p do_now:%d\n", |
430 | p_addr, bm, (int)do_now); | 593 | p_addr, bm, (int)do_now); |
431 | break; /* breaks to after catch_oob_access_end() only! */ | 594 | } else |
432 | } | 595 | memset(bm, c, do_now * sizeof(long)); |
433 | memset(bm, c, do_now * sizeof(long)); | ||
434 | bm_unmap(p_addr); | 596 | bm_unmap(p_addr); |
597 | bm_set_page_need_writeout(b->bm_pages[idx]); | ||
435 | offset += do_now; | 598 | offset += do_now; |
436 | } | 599 | } |
437 | } | 600 | } |
@@ -447,7 +610,7 @@ static void bm_memset(struct drbd_bitmap *b, size_t offset, int c, size_t len) | |||
447 | int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits) | 610 | int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits) |
448 | { | 611 | { |
449 | struct drbd_bitmap *b = mdev->bitmap; | 612 | struct drbd_bitmap *b = mdev->bitmap; |
450 | unsigned long bits, words, owords, obits, *p_addr, *bm; | 613 | unsigned long bits, words, owords, obits; |
451 | unsigned long want, have, onpages; /* number of pages */ | 614 | unsigned long want, have, onpages; /* number of pages */ |
452 | struct page **npages, **opages = NULL; | 615 | struct page **npages, **opages = NULL; |
453 | int err = 0, growing; | 616 | int err = 0, growing; |
@@ -455,7 +618,7 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits) | |||
455 | 618 | ||
456 | ERR_IF(!b) return -ENOMEM; | 619 | ERR_IF(!b) return -ENOMEM; |
457 | 620 | ||
458 | drbd_bm_lock(mdev, "resize"); | 621 | drbd_bm_lock(mdev, "resize", BM_LOCKED_MASK); |
459 | 622 | ||
460 | dev_info(DEV, "drbd_bm_resize called with capacity == %llu\n", | 623 | dev_info(DEV, "drbd_bm_resize called with capacity == %llu\n", |
461 | (unsigned long long)capacity); | 624 | (unsigned long long)capacity); |
@@ -463,7 +626,7 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits) | |||
463 | if (capacity == b->bm_dev_capacity) | 626 | if (capacity == b->bm_dev_capacity) |
464 | goto out; | 627 | goto out; |
465 | 628 | ||
466 | opages_vmalloced = test_bit(BM_P_VMALLOCED, &b->bm_flags); | 629 | opages_vmalloced = (BM_P_VMALLOCED & b->bm_flags); |
467 | 630 | ||
468 | if (capacity == 0) { | 631 | if (capacity == 0) { |
469 | spin_lock_irq(&b->bm_lock); | 632 | spin_lock_irq(&b->bm_lock); |
@@ -491,18 +654,23 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits) | |||
491 | words = ALIGN(bits, 64) >> LN2_BPL; | 654 | words = ALIGN(bits, 64) >> LN2_BPL; |
492 | 655 | ||
493 | if (get_ldev(mdev)) { | 656 | if (get_ldev(mdev)) { |
494 | D_ASSERT((u64)bits <= (((u64)mdev->ldev->md.md_size_sect-MD_BM_OFFSET) << 12)); | 657 | u64 bits_on_disk = ((u64)mdev->ldev->md.md_size_sect-MD_BM_OFFSET) << 12; |
495 | put_ldev(mdev); | 658 | put_ldev(mdev); |
659 | if (bits > bits_on_disk) { | ||
660 | dev_info(DEV, "bits = %lu\n", bits); | ||
661 | dev_info(DEV, "bits_on_disk = %llu\n", bits_on_disk); | ||
662 | err = -ENOSPC; | ||
663 | goto out; | ||
664 | } | ||
496 | } | 665 | } |
497 | 666 | ||
498 | /* one extra long to catch off by one errors */ | 667 | want = ALIGN(words*sizeof(long), PAGE_SIZE) >> PAGE_SHIFT; |
499 | want = ALIGN((words+1)*sizeof(long), PAGE_SIZE) >> PAGE_SHIFT; | ||
500 | have = b->bm_number_of_pages; | 668 | have = b->bm_number_of_pages; |
501 | if (want == have) { | 669 | if (want == have) { |
502 | D_ASSERT(b->bm_pages != NULL); | 670 | D_ASSERT(b->bm_pages != NULL); |
503 | npages = b->bm_pages; | 671 | npages = b->bm_pages; |
504 | } else { | 672 | } else { |
505 | if (FAULT_ACTIVE(mdev, DRBD_FAULT_BM_ALLOC)) | 673 | if (drbd_insert_fault(mdev, DRBD_FAULT_BM_ALLOC)) |
506 | npages = NULL; | 674 | npages = NULL; |
507 | else | 675 | else |
508 | npages = bm_realloc_pages(b, want); | 676 | npages = bm_realloc_pages(b, want); |
@@ -542,11 +710,6 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits) | |||
542 | bm_free_pages(opages + want, have - want); | 710 | bm_free_pages(opages + want, have - want); |
543 | } | 711 | } |
544 | 712 | ||
545 | p_addr = bm_map_paddr(b, words); | ||
546 | bm = p_addr + MLPP(words); | ||
547 | *bm = DRBD_MAGIC; | ||
548 | bm_unmap(p_addr); | ||
549 | |||
550 | (void)bm_clear_surplus(b); | 713 | (void)bm_clear_surplus(b); |
551 | 714 | ||
552 | spin_unlock_irq(&b->bm_lock); | 715 | spin_unlock_irq(&b->bm_lock); |
@@ -554,7 +717,7 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits) | |||
554 | bm_vk_free(opages, opages_vmalloced); | 717 | bm_vk_free(opages, opages_vmalloced); |
555 | if (!growing) | 718 | if (!growing) |
556 | b->bm_set = bm_count_bits(b); | 719 | b->bm_set = bm_count_bits(b); |
557 | dev_info(DEV, "resync bitmap: bits=%lu words=%lu\n", bits, words); | 720 | dev_info(DEV, "resync bitmap: bits=%lu words=%lu pages=%lu\n", bits, words, want); |
558 | 721 | ||
559 | out: | 722 | out: |
560 | drbd_bm_unlock(mdev); | 723 | drbd_bm_unlock(mdev); |
@@ -624,6 +787,7 @@ void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, size_t number, | |||
624 | struct drbd_bitmap *b = mdev->bitmap; | 787 | struct drbd_bitmap *b = mdev->bitmap; |
625 | unsigned long *p_addr, *bm; | 788 | unsigned long *p_addr, *bm; |
626 | unsigned long word, bits; | 789 | unsigned long word, bits; |
790 | unsigned int idx; | ||
627 | size_t end, do_now; | 791 | size_t end, do_now; |
628 | 792 | ||
629 | end = offset + number; | 793 | end = offset + number; |
@@ -638,16 +802,18 @@ void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, size_t number, | |||
638 | spin_lock_irq(&b->bm_lock); | 802 | spin_lock_irq(&b->bm_lock); |
639 | while (offset < end) { | 803 | while (offset < end) { |
640 | do_now = min_t(size_t, ALIGN(offset+1, LWPP), end) - offset; | 804 | do_now = min_t(size_t, ALIGN(offset+1, LWPP), end) - offset; |
641 | p_addr = bm_map_paddr(b, offset); | 805 | idx = bm_word_to_page_idx(b, offset); |
806 | p_addr = bm_map_pidx(b, idx); | ||
642 | bm = p_addr + MLPP(offset); | 807 | bm = p_addr + MLPP(offset); |
643 | offset += do_now; | 808 | offset += do_now; |
644 | while (do_now--) { | 809 | while (do_now--) { |
645 | bits = hweight_long(*bm); | 810 | bits = hweight_long(*bm); |
646 | word = *bm | lel_to_cpu(*buffer++); | 811 | word = *bm | *buffer++; |
647 | *bm++ = word; | 812 | *bm++ = word; |
648 | b->bm_set += hweight_long(word) - bits; | 813 | b->bm_set += hweight_long(word) - bits; |
649 | } | 814 | } |
650 | bm_unmap(p_addr); | 815 | bm_unmap(p_addr); |
816 | bm_set_page_need_writeout(b->bm_pages[idx]); | ||
651 | } | 817 | } |
652 | /* with 32bit <-> 64bit cross-platform connect | 818 | /* with 32bit <-> 64bit cross-platform connect |
653 | * this is only correct for current usage, | 819 | * this is only correct for current usage, |
@@ -656,7 +822,6 @@ void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, size_t number, | |||
656 | */ | 822 | */ |
657 | if (end == b->bm_words) | 823 | if (end == b->bm_words) |
658 | b->bm_set -= bm_clear_surplus(b); | 824 | b->bm_set -= bm_clear_surplus(b); |
659 | |||
660 | spin_unlock_irq(&b->bm_lock); | 825 | spin_unlock_irq(&b->bm_lock); |
661 | } | 826 | } |
662 | 827 | ||
@@ -686,11 +851,11 @@ void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, size_t number, | |||
686 | else { | 851 | else { |
687 | while (offset < end) { | 852 | while (offset < end) { |
688 | do_now = min_t(size_t, ALIGN(offset+1, LWPP), end) - offset; | 853 | do_now = min_t(size_t, ALIGN(offset+1, LWPP), end) - offset; |
689 | p_addr = bm_map_paddr(b, offset); | 854 | p_addr = bm_map_pidx(b, bm_word_to_page_idx(b, offset)); |
690 | bm = p_addr + MLPP(offset); | 855 | bm = p_addr + MLPP(offset); |
691 | offset += do_now; | 856 | offset += do_now; |
692 | while (do_now--) | 857 | while (do_now--) |
693 | *buffer++ = cpu_to_lel(*bm++); | 858 | *buffer++ = *bm++; |
694 | bm_unmap(p_addr); | 859 | bm_unmap(p_addr); |
695 | } | 860 | } |
696 | } | 861 | } |
@@ -724,9 +889,22 @@ void drbd_bm_clear_all(struct drbd_conf *mdev) | |||
724 | spin_unlock_irq(&b->bm_lock); | 889 | spin_unlock_irq(&b->bm_lock); |
725 | } | 890 | } |
726 | 891 | ||
892 | struct bm_aio_ctx { | ||
893 | struct drbd_conf *mdev; | ||
894 | atomic_t in_flight; | ||
895 | struct completion done; | ||
896 | unsigned flags; | ||
897 | #define BM_AIO_COPY_PAGES 1 | ||
898 | int error; | ||
899 | }; | ||
900 | |||
901 | /* bv_page may be a copy, or may be the original */ | ||
727 | static void bm_async_io_complete(struct bio *bio, int error) | 902 | static void bm_async_io_complete(struct bio *bio, int error) |
728 | { | 903 | { |
729 | struct drbd_bitmap *b = bio->bi_private; | 904 | struct bm_aio_ctx *ctx = bio->bi_private; |
905 | struct drbd_conf *mdev = ctx->mdev; | ||
906 | struct drbd_bitmap *b = mdev->bitmap; | ||
907 | unsigned int idx = bm_page_to_idx(bio->bi_io_vec[0].bv_page); | ||
730 | int uptodate = bio_flagged(bio, BIO_UPTODATE); | 908 | int uptodate = bio_flagged(bio, BIO_UPTODATE); |
731 | 909 | ||
732 | 910 | ||
@@ -737,38 +915,83 @@ static void bm_async_io_complete(struct bio *bio, int error) | |||
737 | if (!error && !uptodate) | 915 | if (!error && !uptodate) |
738 | error = -EIO; | 916 | error = -EIO; |
739 | 917 | ||
918 | if ((ctx->flags & BM_AIO_COPY_PAGES) == 0 && | ||
919 | !bm_test_page_unchanged(b->bm_pages[idx])) | ||
920 | dev_warn(DEV, "bitmap page idx %u changed during IO!\n", idx); | ||
921 | |||
740 | if (error) { | 922 | if (error) { |
741 | /* doh. what now? | 923 | /* ctx error will hold the completed-last non-zero error code, |
742 | * for now, set all bits, and flag MD_IO_ERROR */ | 924 | * in case error codes differ. */ |
743 | __set_bit(BM_MD_IO_ERROR, &b->bm_flags); | 925 | ctx->error = error; |
926 | bm_set_page_io_err(b->bm_pages[idx]); | ||
927 | /* Not identical to on disk version of it. | ||
928 | * Is BM_PAGE_IO_ERROR enough? */ | ||
929 | if (__ratelimit(&drbd_ratelimit_state)) | ||
930 | dev_err(DEV, "IO ERROR %d on bitmap page idx %u\n", | ||
931 | error, idx); | ||
932 | } else { | ||
933 | bm_clear_page_io_err(b->bm_pages[idx]); | ||
934 | dynamic_dev_dbg(DEV, "bitmap page idx %u completed\n", idx); | ||
744 | } | 935 | } |
745 | if (atomic_dec_and_test(&b->bm_async_io)) | 936 | |
746 | wake_up(&b->bm_io_wait); | 937 | bm_page_unlock_io(mdev, idx); |
938 | |||
939 | /* FIXME give back to page pool */ | ||
940 | if (ctx->flags & BM_AIO_COPY_PAGES) | ||
941 | put_page(bio->bi_io_vec[0].bv_page); | ||
747 | 942 | ||
748 | bio_put(bio); | 943 | bio_put(bio); |
944 | |||
945 | if (atomic_dec_and_test(&ctx->in_flight)) | ||
946 | complete(&ctx->done); | ||
749 | } | 947 | } |
750 | 948 | ||
751 | static void bm_page_io_async(struct drbd_conf *mdev, struct drbd_bitmap *b, int page_nr, int rw) __must_hold(local) | 949 | static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must_hold(local) |
752 | { | 950 | { |
753 | /* we are process context. we always get a bio */ | 951 | /* we are process context. we always get a bio */ |
754 | struct bio *bio = bio_alloc(GFP_KERNEL, 1); | 952 | struct bio *bio = bio_alloc(GFP_KERNEL, 1); |
953 | struct drbd_conf *mdev = ctx->mdev; | ||
954 | struct drbd_bitmap *b = mdev->bitmap; | ||
955 | struct page *page; | ||
755 | unsigned int len; | 956 | unsigned int len; |
957 | |||
756 | sector_t on_disk_sector = | 958 | sector_t on_disk_sector = |
757 | mdev->ldev->md.md_offset + mdev->ldev->md.bm_offset; | 959 | mdev->ldev->md.md_offset + mdev->ldev->md.bm_offset; |
758 | on_disk_sector += ((sector_t)page_nr) << (PAGE_SHIFT-9); | 960 | on_disk_sector += ((sector_t)page_nr) << (PAGE_SHIFT-9); |
759 | 961 | ||
760 | /* this might happen with very small | 962 | /* this might happen with very small |
761 | * flexible external meta data device */ | 963 | * flexible external meta data device, |
964 | * or with PAGE_SIZE > 4k */ | ||
762 | len = min_t(unsigned int, PAGE_SIZE, | 965 | len = min_t(unsigned int, PAGE_SIZE, |
763 | (drbd_md_last_sector(mdev->ldev) - on_disk_sector + 1)<<9); | 966 | (drbd_md_last_sector(mdev->ldev) - on_disk_sector + 1)<<9); |
764 | 967 | ||
968 | /* serialize IO on this page */ | ||
969 | bm_page_lock_io(mdev, page_nr); | ||
970 | /* before memcpy and submit, | ||
971 | * so it can be redirtied any time */ | ||
972 | bm_set_page_unchanged(b->bm_pages[page_nr]); | ||
973 | |||
974 | if (ctx->flags & BM_AIO_COPY_PAGES) { | ||
975 | /* FIXME alloc_page is good enough for now, but actually needs | ||
976 | * to use pre-allocated page pool */ | ||
977 | void *src, *dest; | ||
978 | page = alloc_page(__GFP_HIGHMEM|__GFP_WAIT); | ||
979 | dest = kmap_atomic(page, KM_USER0); | ||
980 | src = kmap_atomic(b->bm_pages[page_nr], KM_USER1); | ||
981 | memcpy(dest, src, PAGE_SIZE); | ||
982 | kunmap_atomic(src, KM_USER1); | ||
983 | kunmap_atomic(dest, KM_USER0); | ||
984 | bm_store_page_idx(page, page_nr); | ||
985 | } else | ||
986 | page = b->bm_pages[page_nr]; | ||
987 | |||
765 | bio->bi_bdev = mdev->ldev->md_bdev; | 988 | bio->bi_bdev = mdev->ldev->md_bdev; |
766 | bio->bi_sector = on_disk_sector; | 989 | bio->bi_sector = on_disk_sector; |
767 | bio_add_page(bio, b->bm_pages[page_nr], len, 0); | 990 | bio_add_page(bio, page, len, 0); |
768 | bio->bi_private = b; | 991 | bio->bi_private = ctx; |
769 | bio->bi_end_io = bm_async_io_complete; | 992 | bio->bi_end_io = bm_async_io_complete; |
770 | 993 | ||
771 | if (FAULT_ACTIVE(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) { | 994 | if (drbd_insert_fault(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) { |
772 | bio->bi_rw |= rw; | 995 | bio->bi_rw |= rw; |
773 | bio_endio(bio, -EIO); | 996 | bio_endio(bio, -EIO); |
774 | } else { | 997 | } else { |
@@ -776,87 +999,84 @@ static void bm_page_io_async(struct drbd_conf *mdev, struct drbd_bitmap *b, int | |||
776 | } | 999 | } |
777 | } | 1000 | } |
778 | 1001 | ||
779 | # if defined(__LITTLE_ENDIAN) | ||
780 | /* nothing to do, on disk == in memory */ | ||
781 | # define bm_cpu_to_lel(x) ((void)0) | ||
782 | # else | ||
783 | static void bm_cpu_to_lel(struct drbd_bitmap *b) | ||
784 | { | ||
785 | /* need to cpu_to_lel all the pages ... | ||
786 | * this may be optimized by using | ||
787 | * cpu_to_lel(-1) == -1 and cpu_to_lel(0) == 0; | ||
788 | * the following is still not optimal, but better than nothing */ | ||
789 | unsigned int i; | ||
790 | unsigned long *p_addr, *bm; | ||
791 | if (b->bm_set == 0) { | ||
792 | /* no page at all; avoid swap if all is 0 */ | ||
793 | i = b->bm_number_of_pages; | ||
794 | } else if (b->bm_set == b->bm_bits) { | ||
795 | /* only the last page */ | ||
796 | i = b->bm_number_of_pages - 1; | ||
797 | } else { | ||
798 | /* all pages */ | ||
799 | i = 0; | ||
800 | } | ||
801 | for (; i < b->bm_number_of_pages; i++) { | ||
802 | p_addr = kmap_atomic(b->bm_pages[i], KM_USER0); | ||
803 | for (bm = p_addr; bm < p_addr + PAGE_SIZE/sizeof(long); bm++) | ||
804 | *bm = cpu_to_lel(*bm); | ||
805 | kunmap_atomic(p_addr, KM_USER0); | ||
806 | } | ||
807 | } | ||
808 | # endif | ||
809 | /* lel_to_cpu == cpu_to_lel */ | ||
810 | # define bm_lel_to_cpu(x) bm_cpu_to_lel(x) | ||
811 | |||
812 | /* | 1002 | /* |
813 | * bm_rw: read/write the whole bitmap from/to its on disk location. | 1003 | * bm_rw: read/write the whole bitmap from/to its on disk location. |
814 | */ | 1004 | */ |
815 | static int bm_rw(struct drbd_conf *mdev, int rw) __must_hold(local) | 1005 | static int bm_rw(struct drbd_conf *mdev, int rw, unsigned lazy_writeout_upper_idx) __must_hold(local) |
816 | { | 1006 | { |
1007 | struct bm_aio_ctx ctx = { | ||
1008 | .mdev = mdev, | ||
1009 | .in_flight = ATOMIC_INIT(1), | ||
1010 | .done = COMPLETION_INITIALIZER_ONSTACK(ctx.done), | ||
1011 | .flags = lazy_writeout_upper_idx ? BM_AIO_COPY_PAGES : 0, | ||
1012 | }; | ||
817 | struct drbd_bitmap *b = mdev->bitmap; | 1013 | struct drbd_bitmap *b = mdev->bitmap; |
818 | /* sector_t sector; */ | 1014 | int num_pages, i, count = 0; |
819 | int bm_words, num_pages, i; | ||
820 | unsigned long now; | 1015 | unsigned long now; |
821 | char ppb[10]; | 1016 | char ppb[10]; |
822 | int err = 0; | 1017 | int err = 0; |
823 | 1018 | ||
824 | WARN_ON(!bm_is_locked(b)); | 1019 | /* |
825 | 1020 | * We are protected against bitmap disappearing/resizing by holding an | |
826 | /* no spinlock here, the drbd_bm_lock should be enough! */ | 1021 | * ldev reference (caller must have called get_ldev()). |
827 | 1022 | * For read/write, we are protected against changes to the bitmap by | |
828 | bm_words = drbd_bm_words(mdev); | 1023 | * the bitmap lock (see drbd_bitmap_io). |
829 | num_pages = (bm_words*sizeof(long) + PAGE_SIZE-1) >> PAGE_SHIFT; | 1024 | * For lazy writeout, we don't care for ongoing changes to the bitmap, |
1025 | * as we submit copies of pages anyways. | ||
1026 | */ | ||
1027 | if (!ctx.flags) | ||
1028 | WARN_ON(!(BM_LOCKED_MASK & b->bm_flags)); | ||
830 | 1029 | ||
831 | /* on disk bitmap is little endian */ | 1030 | num_pages = b->bm_number_of_pages; |
832 | if (rw == WRITE) | ||
833 | bm_cpu_to_lel(b); | ||
834 | 1031 | ||
835 | now = jiffies; | 1032 | now = jiffies; |
836 | atomic_set(&b->bm_async_io, num_pages); | ||
837 | __clear_bit(BM_MD_IO_ERROR, &b->bm_flags); | ||
838 | 1033 | ||
839 | /* let the layers below us try to merge these bios... */ | 1034 | /* let the layers below us try to merge these bios... */ |
840 | for (i = 0; i < num_pages; i++) | 1035 | for (i = 0; i < num_pages; i++) { |
841 | bm_page_io_async(mdev, b, i, rw); | 1036 | /* ignore completely unchanged pages */ |
1037 | if (lazy_writeout_upper_idx && i == lazy_writeout_upper_idx) | ||
1038 | break; | ||
1039 | if (rw & WRITE) { | ||
1040 | if (bm_test_page_unchanged(b->bm_pages[i])) { | ||
1041 | dynamic_dev_dbg(DEV, "skipped bm write for idx %u\n", i); | ||
1042 | continue; | ||
1043 | } | ||
1044 | /* during lazy writeout, | ||
1045 | * ignore those pages not marked for lazy writeout. */ | ||
1046 | if (lazy_writeout_upper_idx && | ||
1047 | !bm_test_page_lazy_writeout(b->bm_pages[i])) { | ||
1048 | dynamic_dev_dbg(DEV, "skipped bm lazy write for idx %u\n", i); | ||
1049 | continue; | ||
1050 | } | ||
1051 | } | ||
1052 | atomic_inc(&ctx.in_flight); | ||
1053 | bm_page_io_async(&ctx, i, rw); | ||
1054 | ++count; | ||
1055 | cond_resched(); | ||
1056 | } | ||
842 | 1057 | ||
843 | wait_event(b->bm_io_wait, atomic_read(&b->bm_async_io) == 0); | 1058 | /* |
1059 | * We initialize ctx.in_flight to one to make sure bm_async_io_complete | ||
1060 | * will not complete() early, and decrement / test it here. If there | ||
1061 | * are still some bios in flight, we need to wait for them here. | ||
1062 | */ | ||
1063 | if (!atomic_dec_and_test(&ctx.in_flight)) | ||
1064 | wait_for_completion(&ctx.done); | ||
1065 | dev_info(DEV, "bitmap %s of %u pages took %lu jiffies\n", | ||
1066 | rw == WRITE ? "WRITE" : "READ", | ||
1067 | count, jiffies - now); | ||
844 | 1068 | ||
845 | if (test_bit(BM_MD_IO_ERROR, &b->bm_flags)) { | 1069 | if (ctx.error) { |
846 | dev_alert(DEV, "we had at least one MD IO ERROR during bitmap IO\n"); | 1070 | dev_alert(DEV, "we had at least one MD IO ERROR during bitmap IO\n"); |
847 | drbd_chk_io_error(mdev, 1, TRUE); | 1071 | drbd_chk_io_error(mdev, 1, true); |
848 | err = -EIO; | 1072 | err = -EIO; /* ctx.error ? */ |
849 | } | 1073 | } |
850 | 1074 | ||
851 | now = jiffies; | 1075 | now = jiffies; |
852 | if (rw == WRITE) { | 1076 | if (rw == WRITE) { |
853 | /* swap back endianness */ | ||
854 | bm_lel_to_cpu(b); | ||
855 | /* flush bitmap to stable storage */ | ||
856 | drbd_md_flush(mdev); | 1077 | drbd_md_flush(mdev); |
857 | } else /* rw == READ */ { | 1078 | } else /* rw == READ */ { |
858 | /* just read, if necessary adjust endianness */ | 1079 | b->bm_set = bm_count_bits(b); |
859 | b->bm_set = bm_count_bits_swap_endian(b); | ||
860 | dev_info(DEV, "recounting of set bits took additional %lu jiffies\n", | 1080 | dev_info(DEV, "recounting of set bits took additional %lu jiffies\n", |
861 | jiffies - now); | 1081 | jiffies - now); |
862 | } | 1082 | } |
@@ -874,112 +1094,128 @@ static int bm_rw(struct drbd_conf *mdev, int rw) __must_hold(local) | |||
874 | */ | 1094 | */ |
875 | int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local) | 1095 | int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local) |
876 | { | 1096 | { |
877 | return bm_rw(mdev, READ); | 1097 | return bm_rw(mdev, READ, 0); |
878 | } | 1098 | } |
879 | 1099 | ||
880 | /** | 1100 | /** |
881 | * drbd_bm_write() - Write the whole bitmap to its on disk location. | 1101 | * drbd_bm_write() - Write the whole bitmap to its on disk location. |
882 | * @mdev: DRBD device. | 1102 | * @mdev: DRBD device. |
1103 | * | ||
1104 | * Will only write pages that have changed since last IO. | ||
883 | */ | 1105 | */ |
884 | int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local) | 1106 | int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local) |
885 | { | 1107 | { |
886 | return bm_rw(mdev, WRITE); | 1108 | return bm_rw(mdev, WRITE, 0); |
887 | } | 1109 | } |
888 | 1110 | ||
889 | /** | 1111 | /** |
890 | * drbd_bm_write_sect: Writes a 512 (MD_SECTOR_SIZE) byte piece of the bitmap | 1112 | * drbd_bm_lazy_write_out() - Write bitmap pages 0 to @upper_idx-1, if they have changed. |
891 | * @mdev: DRBD device. | 1113 | * @mdev: DRBD device. |
892 | * @enr: Extent number in the resync lru (happens to be sector offset) | 1114 | * @upper_idx: 0: write all changed pages; +ve: page index to stop scanning for changed pages |
893 | * | ||
894 | * The BM_EXT_SIZE is on purpose exactly the amount of the bitmap covered | ||
895 | * by a single sector write. Therefore enr == sector offset from the | ||
896 | * start of the bitmap. | ||
897 | */ | 1115 | */ |
898 | int drbd_bm_write_sect(struct drbd_conf *mdev, unsigned long enr) __must_hold(local) | 1116 | int drbd_bm_write_lazy(struct drbd_conf *mdev, unsigned upper_idx) __must_hold(local) |
899 | { | 1117 | { |
900 | sector_t on_disk_sector = enr + mdev->ldev->md.md_offset | 1118 | return bm_rw(mdev, WRITE, upper_idx); |
901 | + mdev->ldev->md.bm_offset; | 1119 | } |
902 | int bm_words, num_words, offset; | 1120 | |
903 | int err = 0; | ||
904 | 1121 | ||
905 | mutex_lock(&mdev->md_io_mutex); | 1122 | /** |
906 | bm_words = drbd_bm_words(mdev); | 1123 | * drbd_bm_write_page: Writes a PAGE_SIZE aligned piece of bitmap |
907 | offset = S2W(enr); /* word offset into bitmap */ | 1124 | * @mdev: DRBD device. |
908 | num_words = min(S2W(1), bm_words - offset); | 1125 | * @idx: bitmap page index |
909 | if (num_words < S2W(1)) | 1126 | * |
910 | memset(page_address(mdev->md_io_page), 0, MD_SECTOR_SIZE); | 1127 | * We don't want to special case on logical_block_size of the backend device, |
911 | drbd_bm_get_lel(mdev, offset, num_words, | 1128 | * so we submit PAGE_SIZE aligned pieces. |
912 | page_address(mdev->md_io_page)); | 1129 | * Note that on "most" systems, PAGE_SIZE is 4k. |
913 | if (!drbd_md_sync_page_io(mdev, mdev->ldev, on_disk_sector, WRITE)) { | 1130 | * |
914 | int i; | 1131 | * In case this becomes an issue on systems with larger PAGE_SIZE, |
915 | err = -EIO; | 1132 | * we may want to change this again to write 4k aligned 4k pieces. |
916 | dev_err(DEV, "IO ERROR writing bitmap sector %lu " | 1133 | */ |
917 | "(meta-disk sector %llus)\n", | 1134 | int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(local) |
918 | enr, (unsigned long long)on_disk_sector); | 1135 | { |
919 | drbd_chk_io_error(mdev, 1, TRUE); | 1136 | struct bm_aio_ctx ctx = { |
920 | for (i = 0; i < AL_EXT_PER_BM_SECT; i++) | 1137 | .mdev = mdev, |
921 | drbd_bm_ALe_set_all(mdev, enr*AL_EXT_PER_BM_SECT+i); | 1138 | .in_flight = ATOMIC_INIT(1), |
1139 | .done = COMPLETION_INITIALIZER_ONSTACK(ctx.done), | ||
1140 | .flags = BM_AIO_COPY_PAGES, | ||
1141 | }; | ||
1142 | |||
1143 | if (bm_test_page_unchanged(mdev->bitmap->bm_pages[idx])) { | ||
1144 | dynamic_dev_dbg(DEV, "skipped bm page write for idx %u\n", idx); | ||
1145 | return 0; | ||
922 | } | 1146 | } |
1147 | |||
1148 | bm_page_io_async(&ctx, idx, WRITE_SYNC); | ||
1149 | wait_for_completion(&ctx.done); | ||
1150 | |||
1151 | if (ctx.error) | ||
1152 | drbd_chk_io_error(mdev, 1, true); | ||
1153 | /* that should force detach, so the in memory bitmap will be | ||
1154 | * gone in a moment as well. */ | ||
1155 | |||
923 | mdev->bm_writ_cnt++; | 1156 | mdev->bm_writ_cnt++; |
924 | mutex_unlock(&mdev->md_io_mutex); | 1157 | return ctx.error; |
925 | return err; | ||
926 | } | 1158 | } |
927 | 1159 | ||
928 | /* NOTE | 1160 | /* NOTE |
929 | * find_first_bit returns int, we return unsigned long. | 1161 | * find_first_bit returns int, we return unsigned long. |
930 | * should not make much difference anyways, but ... | 1162 | * For this to work on 32bit arch with bitnumbers > (1<<32), |
1163 | * we'd need to return u64, and get a whole lot of other places | ||
1164 | * fixed where we still use unsigned long. | ||
931 | * | 1165 | * |
932 | * this returns a bit number, NOT a sector! | 1166 | * this returns a bit number, NOT a sector! |
933 | */ | 1167 | */ |
934 | #define BPP_MASK ((1UL << (PAGE_SHIFT+3)) - 1) | ||
935 | static unsigned long __bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo, | 1168 | static unsigned long __bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo, |
936 | const int find_zero_bit, const enum km_type km) | 1169 | const int find_zero_bit, const enum km_type km) |
937 | { | 1170 | { |
938 | struct drbd_bitmap *b = mdev->bitmap; | 1171 | struct drbd_bitmap *b = mdev->bitmap; |
939 | unsigned long i = -1UL; | ||
940 | unsigned long *p_addr; | 1172 | unsigned long *p_addr; |
941 | unsigned long bit_offset; /* bit offset of the mapped page. */ | 1173 | unsigned long bit_offset; |
1174 | unsigned i; | ||
1175 | |||
942 | 1176 | ||
943 | if (bm_fo > b->bm_bits) { | 1177 | if (bm_fo > b->bm_bits) { |
944 | dev_err(DEV, "bm_fo=%lu bm_bits=%lu\n", bm_fo, b->bm_bits); | 1178 | dev_err(DEV, "bm_fo=%lu bm_bits=%lu\n", bm_fo, b->bm_bits); |
1179 | bm_fo = DRBD_END_OF_BITMAP; | ||
945 | } else { | 1180 | } else { |
946 | while (bm_fo < b->bm_bits) { | 1181 | while (bm_fo < b->bm_bits) { |
947 | unsigned long offset; | 1182 | /* bit offset of the first bit in the page */ |
948 | bit_offset = bm_fo & ~BPP_MASK; /* bit offset of the page */ | 1183 | bit_offset = bm_fo & ~BITS_PER_PAGE_MASK; |
949 | offset = bit_offset >> LN2_BPL; /* word offset of the page */ | 1184 | p_addr = __bm_map_pidx(b, bm_bit_to_page_idx(b, bm_fo), km); |
950 | p_addr = __bm_map_paddr(b, offset, km); | ||
951 | 1185 | ||
952 | if (find_zero_bit) | 1186 | if (find_zero_bit) |
953 | i = find_next_zero_bit(p_addr, PAGE_SIZE*8, bm_fo & BPP_MASK); | 1187 | i = generic_find_next_zero_le_bit(p_addr, |
1188 | PAGE_SIZE*8, bm_fo & BITS_PER_PAGE_MASK); | ||
954 | else | 1189 | else |
955 | i = find_next_bit(p_addr, PAGE_SIZE*8, bm_fo & BPP_MASK); | 1190 | i = generic_find_next_le_bit(p_addr, |
1191 | PAGE_SIZE*8, bm_fo & BITS_PER_PAGE_MASK); | ||
956 | 1192 | ||
957 | __bm_unmap(p_addr, km); | 1193 | __bm_unmap(p_addr, km); |
958 | if (i < PAGE_SIZE*8) { | 1194 | if (i < PAGE_SIZE*8) { |
959 | i = bit_offset + i; | 1195 | bm_fo = bit_offset + i; |
960 | if (i >= b->bm_bits) | 1196 | if (bm_fo >= b->bm_bits) |
961 | break; | 1197 | break; |
962 | goto found; | 1198 | goto found; |
963 | } | 1199 | } |
964 | bm_fo = bit_offset + PAGE_SIZE*8; | 1200 | bm_fo = bit_offset + PAGE_SIZE*8; |
965 | } | 1201 | } |
966 | i = -1UL; | 1202 | bm_fo = DRBD_END_OF_BITMAP; |
967 | } | 1203 | } |
968 | found: | 1204 | found: |
969 | return i; | 1205 | return bm_fo; |
970 | } | 1206 | } |
971 | 1207 | ||
972 | static unsigned long bm_find_next(struct drbd_conf *mdev, | 1208 | static unsigned long bm_find_next(struct drbd_conf *mdev, |
973 | unsigned long bm_fo, const int find_zero_bit) | 1209 | unsigned long bm_fo, const int find_zero_bit) |
974 | { | 1210 | { |
975 | struct drbd_bitmap *b = mdev->bitmap; | 1211 | struct drbd_bitmap *b = mdev->bitmap; |
976 | unsigned long i = -1UL; | 1212 | unsigned long i = DRBD_END_OF_BITMAP; |
977 | 1213 | ||
978 | ERR_IF(!b) return i; | 1214 | ERR_IF(!b) return i; |
979 | ERR_IF(!b->bm_pages) return i; | 1215 | ERR_IF(!b->bm_pages) return i; |
980 | 1216 | ||
981 | spin_lock_irq(&b->bm_lock); | 1217 | spin_lock_irq(&b->bm_lock); |
982 | if (bm_is_locked(b)) | 1218 | if (BM_DONT_TEST & b->bm_flags) |
983 | bm_print_lock_info(mdev); | 1219 | bm_print_lock_info(mdev); |
984 | 1220 | ||
985 | i = __bm_find_next(mdev, bm_fo, find_zero_bit, KM_IRQ1); | 1221 | i = __bm_find_next(mdev, bm_fo, find_zero_bit, KM_IRQ1); |
@@ -1005,13 +1241,13 @@ unsigned long drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo | |||
1005 | * you must take drbd_bm_lock() first */ | 1241 | * you must take drbd_bm_lock() first */ |
1006 | unsigned long _drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo) | 1242 | unsigned long _drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo) |
1007 | { | 1243 | { |
1008 | /* WARN_ON(!bm_is_locked(mdev)); */ | 1244 | /* WARN_ON(!(BM_DONT_SET & mdev->b->bm_flags)); */ |
1009 | return __bm_find_next(mdev, bm_fo, 0, KM_USER1); | 1245 | return __bm_find_next(mdev, bm_fo, 0, KM_USER1); |
1010 | } | 1246 | } |
1011 | 1247 | ||
1012 | unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo) | 1248 | unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo) |
1013 | { | 1249 | { |
1014 | /* WARN_ON(!bm_is_locked(mdev)); */ | 1250 | /* WARN_ON(!(BM_DONT_SET & mdev->b->bm_flags)); */ |
1015 | return __bm_find_next(mdev, bm_fo, 1, KM_USER1); | 1251 | return __bm_find_next(mdev, bm_fo, 1, KM_USER1); |
1016 | } | 1252 | } |
1017 | 1253 | ||
@@ -1027,8 +1263,9 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, | |||
1027 | struct drbd_bitmap *b = mdev->bitmap; | 1263 | struct drbd_bitmap *b = mdev->bitmap; |
1028 | unsigned long *p_addr = NULL; | 1264 | unsigned long *p_addr = NULL; |
1029 | unsigned long bitnr; | 1265 | unsigned long bitnr; |
1030 | unsigned long last_page_nr = -1UL; | 1266 | unsigned int last_page_nr = -1U; |
1031 | int c = 0; | 1267 | int c = 0; |
1268 | int changed_total = 0; | ||
1032 | 1269 | ||
1033 | if (e >= b->bm_bits) { | 1270 | if (e >= b->bm_bits) { |
1034 | dev_err(DEV, "ASSERT FAILED: bit_s=%lu bit_e=%lu bm_bits=%lu\n", | 1271 | dev_err(DEV, "ASSERT FAILED: bit_s=%lu bit_e=%lu bm_bits=%lu\n", |
@@ -1036,23 +1273,33 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, | |||
1036 | e = b->bm_bits ? b->bm_bits -1 : 0; | 1273 | e = b->bm_bits ? b->bm_bits -1 : 0; |
1037 | } | 1274 | } |
1038 | for (bitnr = s; bitnr <= e; bitnr++) { | 1275 | for (bitnr = s; bitnr <= e; bitnr++) { |
1039 | unsigned long offset = bitnr>>LN2_BPL; | 1276 | unsigned int page_nr = bm_bit_to_page_idx(b, bitnr); |
1040 | unsigned long page_nr = offset >> (PAGE_SHIFT - LN2_BPL + 3); | ||
1041 | if (page_nr != last_page_nr) { | 1277 | if (page_nr != last_page_nr) { |
1042 | if (p_addr) | 1278 | if (p_addr) |
1043 | __bm_unmap(p_addr, km); | 1279 | __bm_unmap(p_addr, km); |
1044 | p_addr = __bm_map_paddr(b, offset, km); | 1280 | if (c < 0) |
1281 | bm_set_page_lazy_writeout(b->bm_pages[last_page_nr]); | ||
1282 | else if (c > 0) | ||
1283 | bm_set_page_need_writeout(b->bm_pages[last_page_nr]); | ||
1284 | changed_total += c; | ||
1285 | c = 0; | ||
1286 | p_addr = __bm_map_pidx(b, page_nr, km); | ||
1045 | last_page_nr = page_nr; | 1287 | last_page_nr = page_nr; |
1046 | } | 1288 | } |
1047 | if (val) | 1289 | if (val) |
1048 | c += (0 == __test_and_set_bit(bitnr & BPP_MASK, p_addr)); | 1290 | c += (0 == generic___test_and_set_le_bit(bitnr & BITS_PER_PAGE_MASK, p_addr)); |
1049 | else | 1291 | else |
1050 | c -= (0 != __test_and_clear_bit(bitnr & BPP_MASK, p_addr)); | 1292 | c -= (0 != generic___test_and_clear_le_bit(bitnr & BITS_PER_PAGE_MASK, p_addr)); |
1051 | } | 1293 | } |
1052 | if (p_addr) | 1294 | if (p_addr) |
1053 | __bm_unmap(p_addr, km); | 1295 | __bm_unmap(p_addr, km); |
1054 | b->bm_set += c; | 1296 | if (c < 0) |
1055 | return c; | 1297 | bm_set_page_lazy_writeout(b->bm_pages[last_page_nr]); |
1298 | else if (c > 0) | ||
1299 | bm_set_page_need_writeout(b->bm_pages[last_page_nr]); | ||
1300 | changed_total += c; | ||
1301 | b->bm_set += changed_total; | ||
1302 | return changed_total; | ||
1056 | } | 1303 | } |
1057 | 1304 | ||
1058 | /* returns number of bits actually changed. | 1305 | /* returns number of bits actually changed. |
@@ -1070,7 +1317,7 @@ static int bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, | |||
1070 | ERR_IF(!b->bm_pages) return 0; | 1317 | ERR_IF(!b->bm_pages) return 0; |
1071 | 1318 | ||
1072 | spin_lock_irqsave(&b->bm_lock, flags); | 1319 | spin_lock_irqsave(&b->bm_lock, flags); |
1073 | if (bm_is_locked(b)) | 1320 | if ((val ? BM_DONT_SET : BM_DONT_CLEAR) & b->bm_flags) |
1074 | bm_print_lock_info(mdev); | 1321 | bm_print_lock_info(mdev); |
1075 | 1322 | ||
1076 | c = __bm_change_bits_to(mdev, s, e, val, KM_IRQ1); | 1323 | c = __bm_change_bits_to(mdev, s, e, val, KM_IRQ1); |
@@ -1187,12 +1434,11 @@ int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr) | |||
1187 | ERR_IF(!b->bm_pages) return 0; | 1434 | ERR_IF(!b->bm_pages) return 0; |
1188 | 1435 | ||
1189 | spin_lock_irqsave(&b->bm_lock, flags); | 1436 | spin_lock_irqsave(&b->bm_lock, flags); |
1190 | if (bm_is_locked(b)) | 1437 | if (BM_DONT_TEST & b->bm_flags) |
1191 | bm_print_lock_info(mdev); | 1438 | bm_print_lock_info(mdev); |
1192 | if (bitnr < b->bm_bits) { | 1439 | if (bitnr < b->bm_bits) { |
1193 | unsigned long offset = bitnr>>LN2_BPL; | 1440 | p_addr = bm_map_pidx(b, bm_bit_to_page_idx(b, bitnr)); |
1194 | p_addr = bm_map_paddr(b, offset); | 1441 | i = generic_test_le_bit(bitnr & BITS_PER_PAGE_MASK, p_addr) ? 1 : 0; |
1195 | i = test_bit(bitnr & BPP_MASK, p_addr) ? 1 : 0; | ||
1196 | bm_unmap(p_addr); | 1442 | bm_unmap(p_addr); |
1197 | } else if (bitnr == b->bm_bits) { | 1443 | } else if (bitnr == b->bm_bits) { |
1198 | i = -1; | 1444 | i = -1; |
@@ -1210,10 +1456,10 @@ int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsi | |||
1210 | { | 1456 | { |
1211 | unsigned long flags; | 1457 | unsigned long flags; |
1212 | struct drbd_bitmap *b = mdev->bitmap; | 1458 | struct drbd_bitmap *b = mdev->bitmap; |
1213 | unsigned long *p_addr = NULL, page_nr = -1; | 1459 | unsigned long *p_addr = NULL; |
1214 | unsigned long bitnr; | 1460 | unsigned long bitnr; |
1461 | unsigned int page_nr = -1U; | ||
1215 | int c = 0; | 1462 | int c = 0; |
1216 | size_t w; | ||
1217 | 1463 | ||
1218 | /* If this is called without a bitmap, that is a bug. But just to be | 1464 | /* If this is called without a bitmap, that is a bug. But just to be |
1219 | * robust in case we screwed up elsewhere, in that case pretend there | 1465 | * robust in case we screwed up elsewhere, in that case pretend there |
@@ -1223,20 +1469,20 @@ int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsi | |||
1223 | ERR_IF(!b->bm_pages) return 1; | 1469 | ERR_IF(!b->bm_pages) return 1; |
1224 | 1470 | ||
1225 | spin_lock_irqsave(&b->bm_lock, flags); | 1471 | spin_lock_irqsave(&b->bm_lock, flags); |
1226 | if (bm_is_locked(b)) | 1472 | if (BM_DONT_TEST & b->bm_flags) |
1227 | bm_print_lock_info(mdev); | 1473 | bm_print_lock_info(mdev); |
1228 | for (bitnr = s; bitnr <= e; bitnr++) { | 1474 | for (bitnr = s; bitnr <= e; bitnr++) { |
1229 | w = bitnr >> LN2_BPL; | 1475 | unsigned int idx = bm_bit_to_page_idx(b, bitnr); |
1230 | if (page_nr != w >> (PAGE_SHIFT - LN2_BPL + 3)) { | 1476 | if (page_nr != idx) { |
1231 | page_nr = w >> (PAGE_SHIFT - LN2_BPL + 3); | 1477 | page_nr = idx; |
1232 | if (p_addr) | 1478 | if (p_addr) |
1233 | bm_unmap(p_addr); | 1479 | bm_unmap(p_addr); |
1234 | p_addr = bm_map_paddr(b, w); | 1480 | p_addr = bm_map_pidx(b, idx); |
1235 | } | 1481 | } |
1236 | ERR_IF (bitnr >= b->bm_bits) { | 1482 | ERR_IF (bitnr >= b->bm_bits) { |
1237 | dev_err(DEV, "bitnr=%lu bm_bits=%lu\n", bitnr, b->bm_bits); | 1483 | dev_err(DEV, "bitnr=%lu bm_bits=%lu\n", bitnr, b->bm_bits); |
1238 | } else { | 1484 | } else { |
1239 | c += (0 != test_bit(bitnr - (page_nr << (PAGE_SHIFT+3)), p_addr)); | 1485 | c += (0 != generic_test_le_bit(bitnr - (page_nr << (PAGE_SHIFT+3)), p_addr)); |
1240 | } | 1486 | } |
1241 | } | 1487 | } |
1242 | if (p_addr) | 1488 | if (p_addr) |
@@ -1271,7 +1517,7 @@ int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr) | |||
1271 | ERR_IF(!b->bm_pages) return 0; | 1517 | ERR_IF(!b->bm_pages) return 0; |
1272 | 1518 | ||
1273 | spin_lock_irqsave(&b->bm_lock, flags); | 1519 | spin_lock_irqsave(&b->bm_lock, flags); |
1274 | if (bm_is_locked(b)) | 1520 | if (BM_DONT_TEST & b->bm_flags) |
1275 | bm_print_lock_info(mdev); | 1521 | bm_print_lock_info(mdev); |
1276 | 1522 | ||
1277 | s = S2W(enr); | 1523 | s = S2W(enr); |
@@ -1279,7 +1525,7 @@ int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr) | |||
1279 | count = 0; | 1525 | count = 0; |
1280 | if (s < b->bm_words) { | 1526 | if (s < b->bm_words) { |
1281 | int n = e-s; | 1527 | int n = e-s; |
1282 | p_addr = bm_map_paddr(b, s); | 1528 | p_addr = bm_map_pidx(b, bm_word_to_page_idx(b, s)); |
1283 | bm = p_addr + MLPP(s); | 1529 | bm = p_addr + MLPP(s); |
1284 | while (n--) | 1530 | while (n--) |
1285 | count += hweight_long(*bm++); | 1531 | count += hweight_long(*bm++); |
@@ -1291,18 +1537,20 @@ int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr) | |||
1291 | return count; | 1537 | return count; |
1292 | } | 1538 | } |
1293 | 1539 | ||
1294 | /* set all bits covered by the AL-extent al_enr */ | 1540 | /* Set all bits covered by the AL-extent al_enr. |
1541 | * Returns number of bits changed. */ | ||
1295 | unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, unsigned long al_enr) | 1542 | unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, unsigned long al_enr) |
1296 | { | 1543 | { |
1297 | struct drbd_bitmap *b = mdev->bitmap; | 1544 | struct drbd_bitmap *b = mdev->bitmap; |
1298 | unsigned long *p_addr, *bm; | 1545 | unsigned long *p_addr, *bm; |
1299 | unsigned long weight; | 1546 | unsigned long weight; |
1300 | int count, s, e, i, do_now; | 1547 | unsigned long s, e; |
1548 | int count, i, do_now; | ||
1301 | ERR_IF(!b) return 0; | 1549 | ERR_IF(!b) return 0; |
1302 | ERR_IF(!b->bm_pages) return 0; | 1550 | ERR_IF(!b->bm_pages) return 0; |
1303 | 1551 | ||
1304 | spin_lock_irq(&b->bm_lock); | 1552 | spin_lock_irq(&b->bm_lock); |
1305 | if (bm_is_locked(b)) | 1553 | if (BM_DONT_SET & b->bm_flags) |
1306 | bm_print_lock_info(mdev); | 1554 | bm_print_lock_info(mdev); |
1307 | weight = b->bm_set; | 1555 | weight = b->bm_set; |
1308 | 1556 | ||
@@ -1314,7 +1562,7 @@ unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, unsigned long al_enr) | |||
1314 | count = 0; | 1562 | count = 0; |
1315 | if (s < b->bm_words) { | 1563 | if (s < b->bm_words) { |
1316 | i = do_now = e-s; | 1564 | i = do_now = e-s; |
1317 | p_addr = bm_map_paddr(b, s); | 1565 | p_addr = bm_map_pidx(b, bm_word_to_page_idx(b, s)); |
1318 | bm = p_addr + MLPP(s); | 1566 | bm = p_addr + MLPP(s); |
1319 | while (i--) { | 1567 | while (i--) { |
1320 | count += hweight_long(*bm); | 1568 | count += hweight_long(*bm); |
@@ -1326,7 +1574,7 @@ unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, unsigned long al_enr) | |||
1326 | if (e == b->bm_words) | 1574 | if (e == b->bm_words) |
1327 | b->bm_set -= bm_clear_surplus(b); | 1575 | b->bm_set -= bm_clear_surplus(b); |
1328 | } else { | 1576 | } else { |
1329 | dev_err(DEV, "start offset (%d) too large in drbd_bm_ALe_set_all\n", s); | 1577 | dev_err(DEV, "start offset (%lu) too large in drbd_bm_ALe_set_all\n", s); |
1330 | } | 1578 | } |
1331 | weight = b->bm_set - weight; | 1579 | weight = b->bm_set - weight; |
1332 | spin_unlock_irq(&b->bm_lock); | 1580 | spin_unlock_irq(&b->bm_lock); |
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index b0bd27dfc1e8..81030d8d654b 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h | |||
@@ -72,13 +72,6 @@ extern int fault_devs; | |||
72 | extern char usermode_helper[]; | 72 | extern char usermode_helper[]; |
73 | 73 | ||
74 | 74 | ||
75 | #ifndef TRUE | ||
76 | #define TRUE 1 | ||
77 | #endif | ||
78 | #ifndef FALSE | ||
79 | #define FALSE 0 | ||
80 | #endif | ||
81 | |||
82 | /* I don't remember why XCPU ... | 75 | /* I don't remember why XCPU ... |
83 | * This is used to wake the asender, | 76 | * This is used to wake the asender, |
84 | * and to interrupt sending the sending task | 77 | * and to interrupt sending the sending task |
@@ -104,6 +97,7 @@ extern char usermode_helper[]; | |||
104 | #define ID_SYNCER (-1ULL) | 97 | #define ID_SYNCER (-1ULL) |
105 | #define ID_VACANT 0 | 98 | #define ID_VACANT 0 |
106 | #define is_syncer_block_id(id) ((id) == ID_SYNCER) | 99 | #define is_syncer_block_id(id) ((id) == ID_SYNCER) |
100 | #define UUID_NEW_BM_OFFSET ((u64)0x0001000000000000ULL) | ||
107 | 101 | ||
108 | struct drbd_conf; | 102 | struct drbd_conf; |
109 | 103 | ||
@@ -137,20 +131,19 @@ enum { | |||
137 | DRBD_FAULT_MAX, | 131 | DRBD_FAULT_MAX, |
138 | }; | 132 | }; |
139 | 133 | ||
140 | #ifdef CONFIG_DRBD_FAULT_INJECTION | ||
141 | extern unsigned int | 134 | extern unsigned int |
142 | _drbd_insert_fault(struct drbd_conf *mdev, unsigned int type); | 135 | _drbd_insert_fault(struct drbd_conf *mdev, unsigned int type); |
136 | |||
143 | static inline int | 137 | static inline int |
144 | drbd_insert_fault(struct drbd_conf *mdev, unsigned int type) { | 138 | drbd_insert_fault(struct drbd_conf *mdev, unsigned int type) { |
139 | #ifdef CONFIG_DRBD_FAULT_INJECTION | ||
145 | return fault_rate && | 140 | return fault_rate && |
146 | (enable_faults & (1<<type)) && | 141 | (enable_faults & (1<<type)) && |
147 | _drbd_insert_fault(mdev, type); | 142 | _drbd_insert_fault(mdev, type); |
148 | } | ||
149 | #define FAULT_ACTIVE(_m, _t) (drbd_insert_fault((_m), (_t))) | ||
150 | |||
151 | #else | 143 | #else |
152 | #define FAULT_ACTIVE(_m, _t) (0) | 144 | return 0; |
153 | #endif | 145 | #endif |
146 | } | ||
154 | 147 | ||
155 | /* integer division, round _UP_ to the next integer */ | 148 | /* integer division, round _UP_ to the next integer */ |
156 | #define div_ceil(A, B) ((A)/(B) + ((A)%(B) ? 1 : 0)) | 149 | #define div_ceil(A, B) ((A)/(B) + ((A)%(B) ? 1 : 0)) |
@@ -212,8 +205,10 @@ enum drbd_packets { | |||
212 | /* P_CKPT_FENCE_REQ = 0x25, * currently reserved for protocol D */ | 205 | /* P_CKPT_FENCE_REQ = 0x25, * currently reserved for protocol D */ |
213 | /* P_CKPT_DISABLE_REQ = 0x26, * currently reserved for protocol D */ | 206 | /* P_CKPT_DISABLE_REQ = 0x26, * currently reserved for protocol D */ |
214 | P_DELAY_PROBE = 0x27, /* is used on BOTH sockets */ | 207 | P_DELAY_PROBE = 0x27, /* is used on BOTH sockets */ |
208 | P_OUT_OF_SYNC = 0x28, /* Mark as out of sync (Outrunning), data socket */ | ||
209 | P_RS_CANCEL = 0x29, /* meta: Used to cancel RS_DATA_REQUEST packet by SyncSource */ | ||
215 | 210 | ||
216 | P_MAX_CMD = 0x28, | 211 | P_MAX_CMD = 0x2A, |
217 | P_MAY_IGNORE = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */ | 212 | P_MAY_IGNORE = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */ |
218 | P_MAX_OPT_CMD = 0x101, | 213 | P_MAX_OPT_CMD = 0x101, |
219 | 214 | ||
@@ -269,6 +264,7 @@ static inline const char *cmdname(enum drbd_packets cmd) | |||
269 | [P_RS_IS_IN_SYNC] = "CsumRSIsInSync", | 264 | [P_RS_IS_IN_SYNC] = "CsumRSIsInSync", |
270 | [P_COMPRESSED_BITMAP] = "CBitmap", | 265 | [P_COMPRESSED_BITMAP] = "CBitmap", |
271 | [P_DELAY_PROBE] = "DelayProbe", | 266 | [P_DELAY_PROBE] = "DelayProbe", |
267 | [P_OUT_OF_SYNC] = "OutOfSync", | ||
272 | [P_MAX_CMD] = NULL, | 268 | [P_MAX_CMD] = NULL, |
273 | }; | 269 | }; |
274 | 270 | ||
@@ -512,7 +508,7 @@ struct p_sizes { | |||
512 | u64 d_size; /* size of disk */ | 508 | u64 d_size; /* size of disk */ |
513 | u64 u_size; /* user requested size */ | 509 | u64 u_size; /* user requested size */ |
514 | u64 c_size; /* current exported size */ | 510 | u64 c_size; /* current exported size */ |
515 | u32 max_segment_size; /* Maximal size of a BIO */ | 511 | u32 max_bio_size; /* Maximal size of a BIO */ |
516 | u16 queue_order_type; /* not yet implemented in DRBD*/ | 512 | u16 queue_order_type; /* not yet implemented in DRBD*/ |
517 | u16 dds_flags; /* use enum dds_flags here. */ | 513 | u16 dds_flags; /* use enum dds_flags here. */ |
518 | } __packed; | 514 | } __packed; |
@@ -550,6 +546,13 @@ struct p_discard { | |||
550 | u32 pad; | 546 | u32 pad; |
551 | } __packed; | 547 | } __packed; |
552 | 548 | ||
549 | struct p_block_desc { | ||
550 | struct p_header80 head; | ||
551 | u64 sector; | ||
552 | u32 blksize; | ||
553 | u32 pad; /* to multiple of 8 Byte */ | ||
554 | } __packed; | ||
555 | |||
553 | /* Valid values for the encoding field. | 556 | /* Valid values for the encoding field. |
554 | * Bump proto version when changing this. */ | 557 | * Bump proto version when changing this. */ |
555 | enum drbd_bitmap_code { | 558 | enum drbd_bitmap_code { |
@@ -647,6 +650,7 @@ union p_polymorph { | |||
647 | struct p_block_req block_req; | 650 | struct p_block_req block_req; |
648 | struct p_delay_probe93 delay_probe93; | 651 | struct p_delay_probe93 delay_probe93; |
649 | struct p_rs_uuid rs_uuid; | 652 | struct p_rs_uuid rs_uuid; |
653 | struct p_block_desc block_desc; | ||
650 | } __packed; | 654 | } __packed; |
651 | 655 | ||
652 | /**********************************************************************/ | 656 | /**********************************************************************/ |
@@ -677,13 +681,6 @@ static inline enum drbd_thread_state get_t_state(struct drbd_thread *thi) | |||
677 | return thi->t_state; | 681 | return thi->t_state; |
678 | } | 682 | } |
679 | 683 | ||
680 | |||
681 | /* | ||
682 | * Having this as the first member of a struct provides sort of "inheritance". | ||
683 | * "derived" structs can be "drbd_queue_work()"ed. | ||
684 | * The callback should know and cast back to the descendant struct. | ||
685 | * drbd_request and drbd_epoch_entry are descendants of drbd_work. | ||
686 | */ | ||
687 | struct drbd_work; | 684 | struct drbd_work; |
688 | typedef int (*drbd_work_cb)(struct drbd_conf *, struct drbd_work *, int cancel); | 685 | typedef int (*drbd_work_cb)(struct drbd_conf *, struct drbd_work *, int cancel); |
689 | struct drbd_work { | 686 | struct drbd_work { |
@@ -712,9 +709,6 @@ struct drbd_request { | |||
712 | * starting a new epoch... | 709 | * starting a new epoch... |
713 | */ | 710 | */ |
714 | 711 | ||
715 | /* up to here, the struct layout is identical to drbd_epoch_entry; | ||
716 | * we might be able to use that to our advantage... */ | ||
717 | |||
718 | struct list_head tl_requests; /* ring list in the transfer log */ | 712 | struct list_head tl_requests; /* ring list in the transfer log */ |
719 | struct bio *master_bio; /* master bio pointer */ | 713 | struct bio *master_bio; /* master bio pointer */ |
720 | unsigned long rq_state; /* see comments above _req_mod() */ | 714 | unsigned long rq_state; /* see comments above _req_mod() */ |
@@ -831,7 +825,7 @@ enum { | |||
831 | CRASHED_PRIMARY, /* This node was a crashed primary. | 825 | CRASHED_PRIMARY, /* This node was a crashed primary. |
832 | * Gets cleared when the state.conn | 826 | * Gets cleared when the state.conn |
833 | * goes into C_CONNECTED state. */ | 827 | * goes into C_CONNECTED state. */ |
834 | WRITE_BM_AFTER_RESYNC, /* A kmalloc() during resync failed */ | 828 | NO_BARRIER_SUPP, /* underlying block device doesn't implement barriers */ |
835 | CONSIDER_RESYNC, | 829 | CONSIDER_RESYNC, |
836 | 830 | ||
837 | MD_NO_FUA, /* Users wants us to not use FUA/FLUSH on meta data dev */ | 831 | MD_NO_FUA, /* Users wants us to not use FUA/FLUSH on meta data dev */ |
@@ -856,10 +850,37 @@ enum { | |||
856 | GOT_PING_ACK, /* set when we receive a ping_ack packet, misc wait gets woken */ | 850 | GOT_PING_ACK, /* set when we receive a ping_ack packet, misc wait gets woken */ |
857 | NEW_CUR_UUID, /* Create new current UUID when thawing IO */ | 851 | NEW_CUR_UUID, /* Create new current UUID when thawing IO */ |
858 | AL_SUSPENDED, /* Activity logging is currently suspended. */ | 852 | AL_SUSPENDED, /* Activity logging is currently suspended. */ |
853 | AHEAD_TO_SYNC_SOURCE, /* Ahead -> SyncSource queued */ | ||
859 | }; | 854 | }; |
860 | 855 | ||
861 | struct drbd_bitmap; /* opaque for drbd_conf */ | 856 | struct drbd_bitmap; /* opaque for drbd_conf */ |
862 | 857 | ||
858 | /* definition of bits in bm_flags to be used in drbd_bm_lock | ||
859 | * and drbd_bitmap_io and friends. */ | ||
860 | enum bm_flag { | ||
861 | /* do we need to kfree, or vfree bm_pages? */ | ||
862 | BM_P_VMALLOCED = 0x10000, /* internal use only, will be masked out */ | ||
863 | |||
864 | /* currently locked for bulk operation */ | ||
865 | BM_LOCKED_MASK = 0x7, | ||
866 | |||
867 | /* in detail, that is: */ | ||
868 | BM_DONT_CLEAR = 0x1, | ||
869 | BM_DONT_SET = 0x2, | ||
870 | BM_DONT_TEST = 0x4, | ||
871 | |||
872 | /* (test bit, count bit) allowed (common case) */ | ||
873 | BM_LOCKED_TEST_ALLOWED = 0x3, | ||
874 | |||
875 | /* testing bits, as well as setting new bits allowed, but clearing bits | ||
876 | * would be unexpected. Used during bitmap receive. Setting new bits | ||
877 | * requires sending of "out-of-sync" information, though. */ | ||
878 | BM_LOCKED_SET_ALLOWED = 0x1, | ||
879 | |||
880 | /* clear is not expected while bitmap is locked for bulk operation */ | ||
881 | }; | ||
882 | |||
883 | |||
863 | /* TODO sort members for performance | 884 | /* TODO sort members for performance |
864 | * MAYBE group them further */ | 885 | * MAYBE group them further */ |
865 | 886 | ||
@@ -925,6 +946,7 @@ struct drbd_md_io { | |||
925 | struct bm_io_work { | 946 | struct bm_io_work { |
926 | struct drbd_work w; | 947 | struct drbd_work w; |
927 | char *why; | 948 | char *why; |
949 | enum bm_flag flags; | ||
928 | int (*io_fn)(struct drbd_conf *mdev); | 950 | int (*io_fn)(struct drbd_conf *mdev); |
929 | void (*done)(struct drbd_conf *mdev, int rv); | 951 | void (*done)(struct drbd_conf *mdev, int rv); |
930 | }; | 952 | }; |
@@ -963,9 +985,12 @@ struct drbd_conf { | |||
963 | struct drbd_work resync_work, | 985 | struct drbd_work resync_work, |
964 | unplug_work, | 986 | unplug_work, |
965 | go_diskless, | 987 | go_diskless, |
966 | md_sync_work; | 988 | md_sync_work, |
989 | start_resync_work; | ||
967 | struct timer_list resync_timer; | 990 | struct timer_list resync_timer; |
968 | struct timer_list md_sync_timer; | 991 | struct timer_list md_sync_timer; |
992 | struct timer_list start_resync_timer; | ||
993 | struct timer_list request_timer; | ||
969 | #ifdef DRBD_DEBUG_MD_SYNC | 994 | #ifdef DRBD_DEBUG_MD_SYNC |
970 | struct { | 995 | struct { |
971 | unsigned int line; | 996 | unsigned int line; |
@@ -1000,9 +1025,9 @@ struct drbd_conf { | |||
1000 | struct hlist_head *tl_hash; | 1025 | struct hlist_head *tl_hash; |
1001 | unsigned int tl_hash_s; | 1026 | unsigned int tl_hash_s; |
1002 | 1027 | ||
1003 | /* blocks to sync in this run [unit BM_BLOCK_SIZE] */ | 1028 | /* blocks to resync in this run [unit BM_BLOCK_SIZE] */ |
1004 | unsigned long rs_total; | 1029 | unsigned long rs_total; |
1005 | /* number of sync IOs that failed in this run */ | 1030 | /* number of resync blocks that failed in this run */ |
1006 | unsigned long rs_failed; | 1031 | unsigned long rs_failed; |
1007 | /* Syncer's start time [unit jiffies] */ | 1032 | /* Syncer's start time [unit jiffies] */ |
1008 | unsigned long rs_start; | 1033 | unsigned long rs_start; |
@@ -1102,6 +1127,7 @@ struct drbd_conf { | |||
1102 | struct fifo_buffer rs_plan_s; /* correction values of resync planer */ | 1127 | struct fifo_buffer rs_plan_s; /* correction values of resync planer */ |
1103 | int rs_in_flight; /* resync sectors in flight (to proxy, in proxy and from proxy) */ | 1128 | int rs_in_flight; /* resync sectors in flight (to proxy, in proxy and from proxy) */ |
1104 | int rs_planed; /* resync sectors already planed */ | 1129 | int rs_planed; /* resync sectors already planed */ |
1130 | atomic_t ap_in_flight; /* App sectors in flight (waiting for ack) */ | ||
1105 | }; | 1131 | }; |
1106 | 1132 | ||
1107 | static inline struct drbd_conf *minor_to_mdev(unsigned int minor) | 1133 | static inline struct drbd_conf *minor_to_mdev(unsigned int minor) |
@@ -1163,14 +1189,19 @@ enum dds_flags { | |||
1163 | }; | 1189 | }; |
1164 | 1190 | ||
1165 | extern void drbd_init_set_defaults(struct drbd_conf *mdev); | 1191 | extern void drbd_init_set_defaults(struct drbd_conf *mdev); |
1166 | extern int drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f, | 1192 | extern enum drbd_state_rv drbd_change_state(struct drbd_conf *mdev, |
1167 | union drbd_state mask, union drbd_state val); | 1193 | enum chg_state_flags f, |
1194 | union drbd_state mask, | ||
1195 | union drbd_state val); | ||
1168 | extern void drbd_force_state(struct drbd_conf *, union drbd_state, | 1196 | extern void drbd_force_state(struct drbd_conf *, union drbd_state, |
1169 | union drbd_state); | 1197 | union drbd_state); |
1170 | extern int _drbd_request_state(struct drbd_conf *, union drbd_state, | 1198 | extern enum drbd_state_rv _drbd_request_state(struct drbd_conf *, |
1171 | union drbd_state, enum chg_state_flags); | 1199 | union drbd_state, |
1172 | extern int __drbd_set_state(struct drbd_conf *, union drbd_state, | 1200 | union drbd_state, |
1173 | enum chg_state_flags, struct completion *done); | 1201 | enum chg_state_flags); |
1202 | extern enum drbd_state_rv __drbd_set_state(struct drbd_conf *, union drbd_state, | ||
1203 | enum chg_state_flags, | ||
1204 | struct completion *done); | ||
1174 | extern void print_st_err(struct drbd_conf *, union drbd_state, | 1205 | extern void print_st_err(struct drbd_conf *, union drbd_state, |
1175 | union drbd_state, int); | 1206 | union drbd_state, int); |
1176 | extern int drbd_thread_start(struct drbd_thread *thi); | 1207 | extern int drbd_thread_start(struct drbd_thread *thi); |
@@ -1195,7 +1226,7 @@ extern int drbd_send(struct drbd_conf *mdev, struct socket *sock, | |||
1195 | extern int drbd_send_protocol(struct drbd_conf *mdev); | 1226 | extern int drbd_send_protocol(struct drbd_conf *mdev); |
1196 | extern int drbd_send_uuids(struct drbd_conf *mdev); | 1227 | extern int drbd_send_uuids(struct drbd_conf *mdev); |
1197 | extern int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev); | 1228 | extern int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev); |
1198 | extern int drbd_send_sync_uuid(struct drbd_conf *mdev, u64 val); | 1229 | extern int drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev); |
1199 | extern int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags flags); | 1230 | extern int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags flags); |
1200 | extern int _drbd_send_state(struct drbd_conf *mdev); | 1231 | extern int _drbd_send_state(struct drbd_conf *mdev); |
1201 | extern int drbd_send_state(struct drbd_conf *mdev); | 1232 | extern int drbd_send_state(struct drbd_conf *mdev); |
@@ -1220,11 +1251,10 @@ extern int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packets cmd, | |||
1220 | struct p_data *dp, int data_size); | 1251 | struct p_data *dp, int data_size); |
1221 | extern int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packets cmd, | 1252 | extern int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packets cmd, |
1222 | sector_t sector, int blksize, u64 block_id); | 1253 | sector_t sector, int blksize, u64 block_id); |
1254 | extern int drbd_send_oos(struct drbd_conf *mdev, struct drbd_request *req); | ||
1223 | extern int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, | 1255 | extern int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, |
1224 | struct drbd_epoch_entry *e); | 1256 | struct drbd_epoch_entry *e); |
1225 | extern int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req); | 1257 | extern int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req); |
1226 | extern int _drbd_send_barrier(struct drbd_conf *mdev, | ||
1227 | struct drbd_tl_epoch *barrier); | ||
1228 | extern int drbd_send_drequest(struct drbd_conf *mdev, int cmd, | 1258 | extern int drbd_send_drequest(struct drbd_conf *mdev, int cmd, |
1229 | sector_t sector, int size, u64 block_id); | 1259 | sector_t sector, int size, u64 block_id); |
1230 | extern int drbd_send_drequest_csum(struct drbd_conf *mdev, | 1260 | extern int drbd_send_drequest_csum(struct drbd_conf *mdev, |
@@ -1235,14 +1265,13 @@ extern int drbd_send_ov_request(struct drbd_conf *mdev,sector_t sector,int size) | |||
1235 | 1265 | ||
1236 | extern int drbd_send_bitmap(struct drbd_conf *mdev); | 1266 | extern int drbd_send_bitmap(struct drbd_conf *mdev); |
1237 | extern int _drbd_send_bitmap(struct drbd_conf *mdev); | 1267 | extern int _drbd_send_bitmap(struct drbd_conf *mdev); |
1238 | extern int drbd_send_sr_reply(struct drbd_conf *mdev, int retcode); | 1268 | extern int drbd_send_sr_reply(struct drbd_conf *mdev, enum drbd_state_rv retcode); |
1239 | extern void drbd_free_bc(struct drbd_backing_dev *ldev); | 1269 | extern void drbd_free_bc(struct drbd_backing_dev *ldev); |
1240 | extern void drbd_mdev_cleanup(struct drbd_conf *mdev); | 1270 | extern void drbd_mdev_cleanup(struct drbd_conf *mdev); |
1271 | void drbd_print_uuids(struct drbd_conf *mdev, const char *text); | ||
1241 | 1272 | ||
1242 | /* drbd_meta-data.c (still in drbd_main.c) */ | ||
1243 | extern void drbd_md_sync(struct drbd_conf *mdev); | 1273 | extern void drbd_md_sync(struct drbd_conf *mdev); |
1244 | extern int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev); | 1274 | extern int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev); |
1245 | /* maybe define them below as inline? */ | ||
1246 | extern void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local); | 1275 | extern void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local); |
1247 | extern void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local); | 1276 | extern void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local); |
1248 | extern void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local); | 1277 | extern void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local); |
@@ -1261,10 +1290,12 @@ extern void drbd_md_mark_dirty_(struct drbd_conf *mdev, | |||
1261 | extern void drbd_queue_bitmap_io(struct drbd_conf *mdev, | 1290 | extern void drbd_queue_bitmap_io(struct drbd_conf *mdev, |
1262 | int (*io_fn)(struct drbd_conf *), | 1291 | int (*io_fn)(struct drbd_conf *), |
1263 | void (*done)(struct drbd_conf *, int), | 1292 | void (*done)(struct drbd_conf *, int), |
1264 | char *why); | 1293 | char *why, enum bm_flag flags); |
1294 | extern int drbd_bitmap_io(struct drbd_conf *mdev, | ||
1295 | int (*io_fn)(struct drbd_conf *), | ||
1296 | char *why, enum bm_flag flags); | ||
1265 | extern int drbd_bmio_set_n_write(struct drbd_conf *mdev); | 1297 | extern int drbd_bmio_set_n_write(struct drbd_conf *mdev); |
1266 | extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev); | 1298 | extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev); |
1267 | extern int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why); | ||
1268 | extern void drbd_go_diskless(struct drbd_conf *mdev); | 1299 | extern void drbd_go_diskless(struct drbd_conf *mdev); |
1269 | extern void drbd_ldev_destroy(struct drbd_conf *mdev); | 1300 | extern void drbd_ldev_destroy(struct drbd_conf *mdev); |
1270 | 1301 | ||
@@ -1313,6 +1344,7 @@ struct bm_extent { | |||
1313 | 1344 | ||
1314 | #define BME_NO_WRITES 0 /* bm_extent.flags: no more requests on this one! */ | 1345 | #define BME_NO_WRITES 0 /* bm_extent.flags: no more requests on this one! */ |
1315 | #define BME_LOCKED 1 /* bm_extent.flags: syncer active on this one. */ | 1346 | #define BME_LOCKED 1 /* bm_extent.flags: syncer active on this one. */ |
1347 | #define BME_PRIORITY 2 /* finish resync IO on this extent ASAP! App IO waiting! */ | ||
1316 | 1348 | ||
1317 | /* drbd_bitmap.c */ | 1349 | /* drbd_bitmap.c */ |
1318 | /* | 1350 | /* |
@@ -1390,7 +1422,9 @@ struct bm_extent { | |||
1390 | * you should use 64bit OS for that much storage, anyways. */ | 1422 | * you should use 64bit OS for that much storage, anyways. */ |
1391 | #define DRBD_MAX_SECTORS_FLEX BM_BIT_TO_SECT(0xffff7fff) | 1423 | #define DRBD_MAX_SECTORS_FLEX BM_BIT_TO_SECT(0xffff7fff) |
1392 | #else | 1424 | #else |
1393 | #define DRBD_MAX_SECTORS_FLEX BM_BIT_TO_SECT(0x1LU << 32) | 1425 | /* we allow up to 1 PiB now on 64bit architecture with "flexible" meta data */ |
1426 | #define DRBD_MAX_SECTORS_FLEX (1UL << 51) | ||
1427 | /* corresponds to (1UL << 38) bits right now. */ | ||
1394 | #endif | 1428 | #endif |
1395 | #endif | 1429 | #endif |
1396 | 1430 | ||
@@ -1398,7 +1432,7 @@ struct bm_extent { | |||
1398 | * With a value of 8 all IO in one 128K block make it to the same slot of the | 1432 | * With a value of 8 all IO in one 128K block make it to the same slot of the |
1399 | * hash table. */ | 1433 | * hash table. */ |
1400 | #define HT_SHIFT 8 | 1434 | #define HT_SHIFT 8 |
1401 | #define DRBD_MAX_SEGMENT_SIZE (1U<<(9+HT_SHIFT)) | 1435 | #define DRBD_MAX_BIO_SIZE (1U<<(9+HT_SHIFT)) |
1402 | 1436 | ||
1403 | #define DRBD_MAX_SIZE_H80_PACKET (1 << 15) /* The old header only allows packets up to 32Kib data */ | 1437 | #define DRBD_MAX_SIZE_H80_PACKET (1 << 15) /* The old header only allows packets up to 32Kib data */ |
1404 | 1438 | ||
@@ -1410,16 +1444,20 @@ extern int drbd_bm_resize(struct drbd_conf *mdev, sector_t sectors, int set_new | |||
1410 | extern void drbd_bm_cleanup(struct drbd_conf *mdev); | 1444 | extern void drbd_bm_cleanup(struct drbd_conf *mdev); |
1411 | extern void drbd_bm_set_all(struct drbd_conf *mdev); | 1445 | extern void drbd_bm_set_all(struct drbd_conf *mdev); |
1412 | extern void drbd_bm_clear_all(struct drbd_conf *mdev); | 1446 | extern void drbd_bm_clear_all(struct drbd_conf *mdev); |
1447 | /* set/clear/test only a few bits at a time */ | ||
1413 | extern int drbd_bm_set_bits( | 1448 | extern int drbd_bm_set_bits( |
1414 | struct drbd_conf *mdev, unsigned long s, unsigned long e); | 1449 | struct drbd_conf *mdev, unsigned long s, unsigned long e); |
1415 | extern int drbd_bm_clear_bits( | 1450 | extern int drbd_bm_clear_bits( |
1416 | struct drbd_conf *mdev, unsigned long s, unsigned long e); | 1451 | struct drbd_conf *mdev, unsigned long s, unsigned long e); |
1417 | /* bm_set_bits variant for use while holding drbd_bm_lock */ | 1452 | extern int drbd_bm_count_bits( |
1453 | struct drbd_conf *mdev, const unsigned long s, const unsigned long e); | ||
1454 | /* bm_set_bits variant for use while holding drbd_bm_lock, | ||
1455 | * may process the whole bitmap in one go */ | ||
1418 | extern void _drbd_bm_set_bits(struct drbd_conf *mdev, | 1456 | extern void _drbd_bm_set_bits(struct drbd_conf *mdev, |
1419 | const unsigned long s, const unsigned long e); | 1457 | const unsigned long s, const unsigned long e); |
1420 | extern int drbd_bm_test_bit(struct drbd_conf *mdev, unsigned long bitnr); | 1458 | extern int drbd_bm_test_bit(struct drbd_conf *mdev, unsigned long bitnr); |
1421 | extern int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr); | 1459 | extern int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr); |
1422 | extern int drbd_bm_write_sect(struct drbd_conf *mdev, unsigned long enr) __must_hold(local); | 1460 | extern int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(local); |
1423 | extern int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local); | 1461 | extern int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local); |
1424 | extern int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local); | 1462 | extern int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local); |
1425 | extern unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, | 1463 | extern unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, |
@@ -1427,6 +1465,8 @@ extern unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, | |||
1427 | extern size_t drbd_bm_words(struct drbd_conf *mdev); | 1465 | extern size_t drbd_bm_words(struct drbd_conf *mdev); |
1428 | extern unsigned long drbd_bm_bits(struct drbd_conf *mdev); | 1466 | extern unsigned long drbd_bm_bits(struct drbd_conf *mdev); |
1429 | extern sector_t drbd_bm_capacity(struct drbd_conf *mdev); | 1467 | extern sector_t drbd_bm_capacity(struct drbd_conf *mdev); |
1468 | |||
1469 | #define DRBD_END_OF_BITMAP (~(unsigned long)0) | ||
1430 | extern unsigned long drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo); | 1470 | extern unsigned long drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo); |
1431 | /* bm_find_next variants for use while you hold drbd_bm_lock() */ | 1471 | /* bm_find_next variants for use while you hold drbd_bm_lock() */ |
1432 | extern unsigned long _drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo); | 1472 | extern unsigned long _drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo); |
@@ -1437,14 +1477,12 @@ extern int drbd_bm_rs_done(struct drbd_conf *mdev); | |||
1437 | /* for receive_bitmap */ | 1477 | /* for receive_bitmap */ |
1438 | extern void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, | 1478 | extern void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, |
1439 | size_t number, unsigned long *buffer); | 1479 | size_t number, unsigned long *buffer); |
1440 | /* for _drbd_send_bitmap and drbd_bm_write_sect */ | 1480 | /* for _drbd_send_bitmap */ |
1441 | extern void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, | 1481 | extern void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, |
1442 | size_t number, unsigned long *buffer); | 1482 | size_t number, unsigned long *buffer); |
1443 | 1483 | ||
1444 | extern void drbd_bm_lock(struct drbd_conf *mdev, char *why); | 1484 | extern void drbd_bm_lock(struct drbd_conf *mdev, char *why, enum bm_flag flags); |
1445 | extern void drbd_bm_unlock(struct drbd_conf *mdev); | 1485 | extern void drbd_bm_unlock(struct drbd_conf *mdev); |
1446 | |||
1447 | extern int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e); | ||
1448 | /* drbd_main.c */ | 1486 | /* drbd_main.c */ |
1449 | 1487 | ||
1450 | extern struct kmem_cache *drbd_request_cache; | 1488 | extern struct kmem_cache *drbd_request_cache; |
@@ -1467,7 +1505,7 @@ extern void drbd_free_mdev(struct drbd_conf *mdev); | |||
1467 | extern int proc_details; | 1505 | extern int proc_details; |
1468 | 1506 | ||
1469 | /* drbd_req */ | 1507 | /* drbd_req */ |
1470 | extern int drbd_make_request_26(struct request_queue *q, struct bio *bio); | 1508 | extern int drbd_make_request(struct request_queue *q, struct bio *bio); |
1471 | extern int drbd_read_remote(struct drbd_conf *mdev, struct drbd_request *req); | 1509 | extern int drbd_read_remote(struct drbd_conf *mdev, struct drbd_request *req); |
1472 | extern int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec); | 1510 | extern int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec); |
1473 | extern int is_valid_ar_handle(struct drbd_request *, sector_t); | 1511 | extern int is_valid_ar_handle(struct drbd_request *, sector_t); |
@@ -1482,8 +1520,9 @@ enum determine_dev_size { dev_size_error = -1, unchanged = 0, shrunk = 1, grew = | |||
1482 | extern enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *, enum dds_flags) __must_hold(local); | 1520 | extern enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *, enum dds_flags) __must_hold(local); |
1483 | extern void resync_after_online_grow(struct drbd_conf *); | 1521 | extern void resync_after_online_grow(struct drbd_conf *); |
1484 | extern void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int) __must_hold(local); | 1522 | extern void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int) __must_hold(local); |
1485 | extern int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, | 1523 | extern enum drbd_state_rv drbd_set_role(struct drbd_conf *mdev, |
1486 | int force); | 1524 | enum drbd_role new_role, |
1525 | int force); | ||
1487 | extern enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev); | 1526 | extern enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev); |
1488 | extern void drbd_try_outdate_peer_async(struct drbd_conf *mdev); | 1527 | extern void drbd_try_outdate_peer_async(struct drbd_conf *mdev); |
1489 | extern int drbd_khelper(struct drbd_conf *mdev, char *cmd); | 1528 | extern int drbd_khelper(struct drbd_conf *mdev, char *cmd); |
@@ -1499,6 +1538,7 @@ extern int drbd_resync_finished(struct drbd_conf *mdev); | |||
1499 | extern int drbd_md_sync_page_io(struct drbd_conf *mdev, | 1538 | extern int drbd_md_sync_page_io(struct drbd_conf *mdev, |
1500 | struct drbd_backing_dev *bdev, sector_t sector, int rw); | 1539 | struct drbd_backing_dev *bdev, sector_t sector, int rw); |
1501 | extern void drbd_ov_oos_found(struct drbd_conf*, sector_t, int); | 1540 | extern void drbd_ov_oos_found(struct drbd_conf*, sector_t, int); |
1541 | extern void drbd_rs_controller_reset(struct drbd_conf *mdev); | ||
1502 | 1542 | ||
1503 | static inline void ov_oos_print(struct drbd_conf *mdev) | 1543 | static inline void ov_oos_print(struct drbd_conf *mdev) |
1504 | { | 1544 | { |
@@ -1522,21 +1562,23 @@ extern int w_e_end_csum_rs_req(struct drbd_conf *, struct drbd_work *, int); | |||
1522 | extern int w_e_end_ov_reply(struct drbd_conf *, struct drbd_work *, int); | 1562 | extern int w_e_end_ov_reply(struct drbd_conf *, struct drbd_work *, int); |
1523 | extern int w_e_end_ov_req(struct drbd_conf *, struct drbd_work *, int); | 1563 | extern int w_e_end_ov_req(struct drbd_conf *, struct drbd_work *, int); |
1524 | extern int w_ov_finished(struct drbd_conf *, struct drbd_work *, int); | 1564 | extern int w_ov_finished(struct drbd_conf *, struct drbd_work *, int); |
1525 | extern int w_resync_inactive(struct drbd_conf *, struct drbd_work *, int); | 1565 | extern int w_resync_timer(struct drbd_conf *, struct drbd_work *, int); |
1526 | extern int w_resume_next_sg(struct drbd_conf *, struct drbd_work *, int); | 1566 | extern int w_resume_next_sg(struct drbd_conf *, struct drbd_work *, int); |
1527 | extern int w_send_write_hint(struct drbd_conf *, struct drbd_work *, int); | 1567 | extern int w_send_write_hint(struct drbd_conf *, struct drbd_work *, int); |
1528 | extern int w_make_resync_request(struct drbd_conf *, struct drbd_work *, int); | ||
1529 | extern int w_send_dblock(struct drbd_conf *, struct drbd_work *, int); | 1568 | extern int w_send_dblock(struct drbd_conf *, struct drbd_work *, int); |
1530 | extern int w_send_barrier(struct drbd_conf *, struct drbd_work *, int); | 1569 | extern int w_send_barrier(struct drbd_conf *, struct drbd_work *, int); |
1531 | extern int w_send_read_req(struct drbd_conf *, struct drbd_work *, int); | 1570 | extern int w_send_read_req(struct drbd_conf *, struct drbd_work *, int); |
1532 | extern int w_prev_work_done(struct drbd_conf *, struct drbd_work *, int); | 1571 | extern int w_prev_work_done(struct drbd_conf *, struct drbd_work *, int); |
1533 | extern int w_e_reissue(struct drbd_conf *, struct drbd_work *, int); | 1572 | extern int w_e_reissue(struct drbd_conf *, struct drbd_work *, int); |
1534 | extern int w_restart_disk_io(struct drbd_conf *, struct drbd_work *, int); | 1573 | extern int w_restart_disk_io(struct drbd_conf *, struct drbd_work *, int); |
1574 | extern int w_send_oos(struct drbd_conf *, struct drbd_work *, int); | ||
1575 | extern int w_start_resync(struct drbd_conf *, struct drbd_work *, int); | ||
1535 | 1576 | ||
1536 | extern void resync_timer_fn(unsigned long data); | 1577 | extern void resync_timer_fn(unsigned long data); |
1578 | extern void start_resync_timer_fn(unsigned long data); | ||
1537 | 1579 | ||
1538 | /* drbd_receiver.c */ | 1580 | /* drbd_receiver.c */ |
1539 | extern int drbd_rs_should_slow_down(struct drbd_conf *mdev); | 1581 | extern int drbd_rs_should_slow_down(struct drbd_conf *mdev, sector_t sector); |
1540 | extern int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, | 1582 | extern int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, |
1541 | const unsigned rw, const int fault_type); | 1583 | const unsigned rw, const int fault_type); |
1542 | extern int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list); | 1584 | extern int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list); |
@@ -1619,16 +1661,16 @@ extern int drbd_rs_del_all(struct drbd_conf *mdev); | |||
1619 | extern void drbd_rs_failed_io(struct drbd_conf *mdev, | 1661 | extern void drbd_rs_failed_io(struct drbd_conf *mdev, |
1620 | sector_t sector, int size); | 1662 | sector_t sector, int size); |
1621 | extern int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *); | 1663 | extern int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *); |
1664 | extern void drbd_advance_rs_marks(struct drbd_conf *mdev, unsigned long still_to_go); | ||
1622 | extern void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, | 1665 | extern void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, |
1623 | int size, const char *file, const unsigned int line); | 1666 | int size, const char *file, const unsigned int line); |
1624 | #define drbd_set_in_sync(mdev, sector, size) \ | 1667 | #define drbd_set_in_sync(mdev, sector, size) \ |
1625 | __drbd_set_in_sync(mdev, sector, size, __FILE__, __LINE__) | 1668 | __drbd_set_in_sync(mdev, sector, size, __FILE__, __LINE__) |
1626 | extern void __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, | 1669 | extern int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, |
1627 | int size, const char *file, const unsigned int line); | 1670 | int size, const char *file, const unsigned int line); |
1628 | #define drbd_set_out_of_sync(mdev, sector, size) \ | 1671 | #define drbd_set_out_of_sync(mdev, sector, size) \ |
1629 | __drbd_set_out_of_sync(mdev, sector, size, __FILE__, __LINE__) | 1672 | __drbd_set_out_of_sync(mdev, sector, size, __FILE__, __LINE__) |
1630 | extern void drbd_al_apply_to_bm(struct drbd_conf *mdev); | 1673 | extern void drbd_al_apply_to_bm(struct drbd_conf *mdev); |
1631 | extern void drbd_al_to_on_disk_bm(struct drbd_conf *mdev); | ||
1632 | extern void drbd_al_shrink(struct drbd_conf *mdev); | 1674 | extern void drbd_al_shrink(struct drbd_conf *mdev); |
1633 | 1675 | ||
1634 | 1676 | ||
@@ -1747,11 +1789,11 @@ static inline void drbd_state_unlock(struct drbd_conf *mdev) | |||
1747 | wake_up(&mdev->misc_wait); | 1789 | wake_up(&mdev->misc_wait); |
1748 | } | 1790 | } |
1749 | 1791 | ||
1750 | static inline int _drbd_set_state(struct drbd_conf *mdev, | 1792 | static inline enum drbd_state_rv |
1751 | union drbd_state ns, enum chg_state_flags flags, | 1793 | _drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, |
1752 | struct completion *done) | 1794 | enum chg_state_flags flags, struct completion *done) |
1753 | { | 1795 | { |
1754 | int rv; | 1796 | enum drbd_state_rv rv; |
1755 | 1797 | ||
1756 | read_lock(&global_state_lock); | 1798 | read_lock(&global_state_lock); |
1757 | rv = __drbd_set_state(mdev, ns, flags, done); | 1799 | rv = __drbd_set_state(mdev, ns, flags, done); |
@@ -1982,17 +2024,17 @@ static inline int drbd_send_ping_ack(struct drbd_conf *mdev) | |||
1982 | 2024 | ||
1983 | static inline void drbd_thread_stop(struct drbd_thread *thi) | 2025 | static inline void drbd_thread_stop(struct drbd_thread *thi) |
1984 | { | 2026 | { |
1985 | _drbd_thread_stop(thi, FALSE, TRUE); | 2027 | _drbd_thread_stop(thi, false, true); |
1986 | } | 2028 | } |
1987 | 2029 | ||
1988 | static inline void drbd_thread_stop_nowait(struct drbd_thread *thi) | 2030 | static inline void drbd_thread_stop_nowait(struct drbd_thread *thi) |
1989 | { | 2031 | { |
1990 | _drbd_thread_stop(thi, FALSE, FALSE); | 2032 | _drbd_thread_stop(thi, false, false); |
1991 | } | 2033 | } |
1992 | 2034 | ||
1993 | static inline void drbd_thread_restart_nowait(struct drbd_thread *thi) | 2035 | static inline void drbd_thread_restart_nowait(struct drbd_thread *thi) |
1994 | { | 2036 | { |
1995 | _drbd_thread_stop(thi, TRUE, FALSE); | 2037 | _drbd_thread_stop(thi, true, false); |
1996 | } | 2038 | } |
1997 | 2039 | ||
1998 | /* counts how many answer packets packets we expect from our peer, | 2040 | /* counts how many answer packets packets we expect from our peer, |
@@ -2146,17 +2188,18 @@ extern int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins) | |||
2146 | static inline void drbd_get_syncer_progress(struct drbd_conf *mdev, | 2188 | static inline void drbd_get_syncer_progress(struct drbd_conf *mdev, |
2147 | unsigned long *bits_left, unsigned int *per_mil_done) | 2189 | unsigned long *bits_left, unsigned int *per_mil_done) |
2148 | { | 2190 | { |
2149 | /* | 2191 | /* this is to break it at compile time when we change that, in case we |
2150 | * this is to break it at compile time when we change that | 2192 | * want to support more than (1<<32) bits on a 32bit arch. */ |
2151 | * (we may feel 4TB maximum storage per drbd is not enough) | ||
2152 | */ | ||
2153 | typecheck(unsigned long, mdev->rs_total); | 2193 | typecheck(unsigned long, mdev->rs_total); |
2154 | 2194 | ||
2155 | /* note: both rs_total and rs_left are in bits, i.e. in | 2195 | /* note: both rs_total and rs_left are in bits, i.e. in |
2156 | * units of BM_BLOCK_SIZE. | 2196 | * units of BM_BLOCK_SIZE. |
2157 | * for the percentage, we don't care. */ | 2197 | * for the percentage, we don't care. */ |
2158 | 2198 | ||
2159 | *bits_left = drbd_bm_total_weight(mdev) - mdev->rs_failed; | 2199 | if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T) |
2200 | *bits_left = mdev->ov_left; | ||
2201 | else | ||
2202 | *bits_left = drbd_bm_total_weight(mdev) - mdev->rs_failed; | ||
2160 | /* >> 10 to prevent overflow, | 2203 | /* >> 10 to prevent overflow, |
2161 | * +1 to prevent division by zero */ | 2204 | * +1 to prevent division by zero */ |
2162 | if (*bits_left > mdev->rs_total) { | 2205 | if (*bits_left > mdev->rs_total) { |
@@ -2171,10 +2214,19 @@ static inline void drbd_get_syncer_progress(struct drbd_conf *mdev, | |||
2171 | *bits_left, mdev->rs_total, mdev->rs_failed); | 2214 | *bits_left, mdev->rs_total, mdev->rs_failed); |
2172 | *per_mil_done = 0; | 2215 | *per_mil_done = 0; |
2173 | } else { | 2216 | } else { |
2174 | /* make sure the calculation happens in long context */ | 2217 | /* Make sure the division happens in long context. |
2175 | unsigned long tmp = 1000UL - | 2218 | * We allow up to one petabyte storage right now, |
2176 | (*bits_left >> 10)*1000UL | 2219 | * at a granularity of 4k per bit that is 2**38 bits. |
2177 | / ((mdev->rs_total >> 10) + 1UL); | 2220 | * After shift right and multiplication by 1000, |
2221 | * this should still fit easily into a 32bit long, | ||
2222 | * so we don't need a 64bit division on 32bit arch. | ||
2223 | * Note: currently we don't support such large bitmaps on 32bit | ||
2224 | * arch anyways, but no harm done to be prepared for it here. | ||
2225 | */ | ||
2226 | unsigned int shift = mdev->rs_total >= (1ULL << 32) ? 16 : 10; | ||
2227 | unsigned long left = *bits_left >> shift; | ||
2228 | unsigned long total = 1UL + (mdev->rs_total >> shift); | ||
2229 | unsigned long tmp = 1000UL - left * 1000UL/total; | ||
2178 | *per_mil_done = tmp; | 2230 | *per_mil_done = tmp; |
2179 | } | 2231 | } |
2180 | } | 2232 | } |
@@ -2193,8 +2245,9 @@ static inline int drbd_get_max_buffers(struct drbd_conf *mdev) | |||
2193 | return mxb; | 2245 | return mxb; |
2194 | } | 2246 | } |
2195 | 2247 | ||
2196 | static inline int drbd_state_is_stable(union drbd_state s) | 2248 | static inline int drbd_state_is_stable(struct drbd_conf *mdev) |
2197 | { | 2249 | { |
2250 | union drbd_state s = mdev->state; | ||
2198 | 2251 | ||
2199 | /* DO NOT add a default clause, we want the compiler to warn us | 2252 | /* DO NOT add a default clause, we want the compiler to warn us |
2200 | * for any newly introduced state we may have forgotten to add here */ | 2253 | * for any newly introduced state we may have forgotten to add here */ |
@@ -2211,11 +2264,9 @@ static inline int drbd_state_is_stable(union drbd_state s) | |||
2211 | case C_VERIFY_T: | 2264 | case C_VERIFY_T: |
2212 | case C_PAUSED_SYNC_S: | 2265 | case C_PAUSED_SYNC_S: |
2213 | case C_PAUSED_SYNC_T: | 2266 | case C_PAUSED_SYNC_T: |
2214 | /* maybe stable, look at the disk state */ | 2267 | case C_AHEAD: |
2215 | break; | 2268 | case C_BEHIND: |
2216 | 2269 | /* transitional states, IO allowed */ | |
2217 | /* no new io accepted during tansitional states | ||
2218 | * like handshake or teardown */ | ||
2219 | case C_DISCONNECTING: | 2270 | case C_DISCONNECTING: |
2220 | case C_UNCONNECTED: | 2271 | case C_UNCONNECTED: |
2221 | case C_TIMEOUT: | 2272 | case C_TIMEOUT: |
@@ -2226,7 +2277,15 @@ static inline int drbd_state_is_stable(union drbd_state s) | |||
2226 | case C_WF_REPORT_PARAMS: | 2277 | case C_WF_REPORT_PARAMS: |
2227 | case C_STARTING_SYNC_S: | 2278 | case C_STARTING_SYNC_S: |
2228 | case C_STARTING_SYNC_T: | 2279 | case C_STARTING_SYNC_T: |
2280 | break; | ||
2281 | |||
2282 | /* Allow IO in BM exchange states with new protocols */ | ||
2229 | case C_WF_BITMAP_S: | 2283 | case C_WF_BITMAP_S: |
2284 | if (mdev->agreed_pro_version < 96) | ||
2285 | return 0; | ||
2286 | break; | ||
2287 | |||
2288 | /* no new io accepted in these states */ | ||
2230 | case C_WF_BITMAP_T: | 2289 | case C_WF_BITMAP_T: |
2231 | case C_WF_SYNC_UUID: | 2290 | case C_WF_SYNC_UUID: |
2232 | case C_MASK: | 2291 | case C_MASK: |
@@ -2261,41 +2320,47 @@ static inline int is_susp(union drbd_state s) | |||
2261 | return s.susp || s.susp_nod || s.susp_fen; | 2320 | return s.susp || s.susp_nod || s.susp_fen; |
2262 | } | 2321 | } |
2263 | 2322 | ||
2264 | static inline int __inc_ap_bio_cond(struct drbd_conf *mdev) | 2323 | static inline bool may_inc_ap_bio(struct drbd_conf *mdev) |
2265 | { | 2324 | { |
2266 | int mxb = drbd_get_max_buffers(mdev); | 2325 | int mxb = drbd_get_max_buffers(mdev); |
2267 | 2326 | ||
2268 | if (is_susp(mdev->state)) | 2327 | if (is_susp(mdev->state)) |
2269 | return 0; | 2328 | return false; |
2270 | if (test_bit(SUSPEND_IO, &mdev->flags)) | 2329 | if (test_bit(SUSPEND_IO, &mdev->flags)) |
2271 | return 0; | 2330 | return false; |
2272 | 2331 | ||
2273 | /* to avoid potential deadlock or bitmap corruption, | 2332 | /* to avoid potential deadlock or bitmap corruption, |
2274 | * in various places, we only allow new application io | 2333 | * in various places, we only allow new application io |
2275 | * to start during "stable" states. */ | 2334 | * to start during "stable" states. */ |
2276 | 2335 | ||
2277 | /* no new io accepted when attaching or detaching the disk */ | 2336 | /* no new io accepted when attaching or detaching the disk */ |
2278 | if (!drbd_state_is_stable(mdev->state)) | 2337 | if (!drbd_state_is_stable(mdev)) |
2279 | return 0; | 2338 | return false; |
2280 | 2339 | ||
2281 | /* since some older kernels don't have atomic_add_unless, | 2340 | /* since some older kernels don't have atomic_add_unless, |
2282 | * and we are within the spinlock anyways, we have this workaround. */ | 2341 | * and we are within the spinlock anyways, we have this workaround. */ |
2283 | if (atomic_read(&mdev->ap_bio_cnt) > mxb) | 2342 | if (atomic_read(&mdev->ap_bio_cnt) > mxb) |
2284 | return 0; | 2343 | return false; |
2285 | if (test_bit(BITMAP_IO, &mdev->flags)) | 2344 | if (test_bit(BITMAP_IO, &mdev->flags)) |
2286 | return 0; | 2345 | return false; |
2287 | return 1; | 2346 | return true; |
2288 | } | 2347 | } |
2289 | 2348 | ||
2290 | /* I'd like to use wait_event_lock_irq, | 2349 | static inline bool inc_ap_bio_cond(struct drbd_conf *mdev, int count) |
2291 | * but I'm not sure when it got introduced, | ||
2292 | * and not sure when it has 3 or 4 arguments */ | ||
2293 | static inline void inc_ap_bio(struct drbd_conf *mdev, int count) | ||
2294 | { | 2350 | { |
2295 | /* compare with after_state_ch, | 2351 | bool rv = false; |
2296 | * os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S */ | 2352 | |
2297 | DEFINE_WAIT(wait); | 2353 | spin_lock_irq(&mdev->req_lock); |
2354 | rv = may_inc_ap_bio(mdev); | ||
2355 | if (rv) | ||
2356 | atomic_add(count, &mdev->ap_bio_cnt); | ||
2357 | spin_unlock_irq(&mdev->req_lock); | ||
2358 | |||
2359 | return rv; | ||
2360 | } | ||
2298 | 2361 | ||
2362 | static inline void inc_ap_bio(struct drbd_conf *mdev, int count) | ||
2363 | { | ||
2299 | /* we wait here | 2364 | /* we wait here |
2300 | * as long as the device is suspended | 2365 | * as long as the device is suspended |
2301 | * until the bitmap is no longer on the fly during connection | 2366 | * until the bitmap is no longer on the fly during connection |
@@ -2304,16 +2369,7 @@ static inline void inc_ap_bio(struct drbd_conf *mdev, int count) | |||
2304 | * to avoid races with the reconnect code, | 2369 | * to avoid races with the reconnect code, |
2305 | * we need to atomic_inc within the spinlock. */ | 2370 | * we need to atomic_inc within the spinlock. */ |
2306 | 2371 | ||
2307 | spin_lock_irq(&mdev->req_lock); | 2372 | wait_event(mdev->misc_wait, inc_ap_bio_cond(mdev, count)); |
2308 | while (!__inc_ap_bio_cond(mdev)) { | ||
2309 | prepare_to_wait(&mdev->misc_wait, &wait, TASK_UNINTERRUPTIBLE); | ||
2310 | spin_unlock_irq(&mdev->req_lock); | ||
2311 | schedule(); | ||
2312 | finish_wait(&mdev->misc_wait, &wait); | ||
2313 | spin_lock_irq(&mdev->req_lock); | ||
2314 | } | ||
2315 | atomic_add(count, &mdev->ap_bio_cnt); | ||
2316 | spin_unlock_irq(&mdev->req_lock); | ||
2317 | } | 2373 | } |
2318 | 2374 | ||
2319 | static inline void dec_ap_bio(struct drbd_conf *mdev) | 2375 | static inline void dec_ap_bio(struct drbd_conf *mdev) |
@@ -2333,9 +2389,11 @@ static inline void dec_ap_bio(struct drbd_conf *mdev) | |||
2333 | } | 2389 | } |
2334 | } | 2390 | } |
2335 | 2391 | ||
2336 | static inline void drbd_set_ed_uuid(struct drbd_conf *mdev, u64 val) | 2392 | static inline int drbd_set_ed_uuid(struct drbd_conf *mdev, u64 val) |
2337 | { | 2393 | { |
2394 | int changed = mdev->ed_uuid != val; | ||
2338 | mdev->ed_uuid = val; | 2395 | mdev->ed_uuid = val; |
2396 | return changed; | ||
2339 | } | 2397 | } |
2340 | 2398 | ||
2341 | static inline int seq_cmp(u32 a, u32 b) | 2399 | static inline int seq_cmp(u32 a, u32 b) |
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 8a43ce0edeed..dfc85f32d317 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c | |||
@@ -85,7 +85,8 @@ MODULE_AUTHOR("Philipp Reisner <phil@linbit.com>, " | |||
85 | MODULE_DESCRIPTION("drbd - Distributed Replicated Block Device v" REL_VERSION); | 85 | MODULE_DESCRIPTION("drbd - Distributed Replicated Block Device v" REL_VERSION); |
86 | MODULE_VERSION(REL_VERSION); | 86 | MODULE_VERSION(REL_VERSION); |
87 | MODULE_LICENSE("GPL"); | 87 | MODULE_LICENSE("GPL"); |
88 | MODULE_PARM_DESC(minor_count, "Maximum number of drbd devices (1-255)"); | 88 | MODULE_PARM_DESC(minor_count, "Maximum number of drbd devices (" |
89 | __stringify(DRBD_MINOR_COUNT_MIN) "-" __stringify(DRBD_MINOR_COUNT_MAX) ")"); | ||
89 | MODULE_ALIAS_BLOCKDEV_MAJOR(DRBD_MAJOR); | 90 | MODULE_ALIAS_BLOCKDEV_MAJOR(DRBD_MAJOR); |
90 | 91 | ||
91 | #include <linux/moduleparam.h> | 92 | #include <linux/moduleparam.h> |
@@ -115,7 +116,7 @@ module_param(fault_devs, int, 0644); | |||
115 | #endif | 116 | #endif |
116 | 117 | ||
117 | /* module parameter, defined */ | 118 | /* module parameter, defined */ |
118 | unsigned int minor_count = 32; | 119 | unsigned int minor_count = DRBD_MINOR_COUNT_DEF; |
119 | int disable_sendpage; | 120 | int disable_sendpage; |
120 | int allow_oos; | 121 | int allow_oos; |
121 | unsigned int cn_idx = CN_IDX_DRBD; | 122 | unsigned int cn_idx = CN_IDX_DRBD; |
@@ -335,6 +336,7 @@ bail: | |||
335 | drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR)); | 336 | drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR)); |
336 | } | 337 | } |
337 | 338 | ||
339 | |||
338 | /** | 340 | /** |
339 | * _tl_restart() - Walks the transfer log, and applies an action to all requests | 341 | * _tl_restart() - Walks the transfer log, and applies an action to all requests |
340 | * @mdev: DRBD device. | 342 | * @mdev: DRBD device. |
@@ -456,7 +458,7 @@ void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) | |||
456 | } | 458 | } |
457 | 459 | ||
458 | /** | 460 | /** |
459 | * cl_wide_st_chg() - TRUE if the state change is a cluster wide one | 461 | * cl_wide_st_chg() - true if the state change is a cluster wide one |
460 | * @mdev: DRBD device. | 462 | * @mdev: DRBD device. |
461 | * @os: old (current) state. | 463 | * @os: old (current) state. |
462 | * @ns: new (wanted) state. | 464 | * @ns: new (wanted) state. |
@@ -473,12 +475,13 @@ static int cl_wide_st_chg(struct drbd_conf *mdev, | |||
473 | (os.conn == C_CONNECTED && ns.conn == C_VERIFY_S); | 475 | (os.conn == C_CONNECTED && ns.conn == C_VERIFY_S); |
474 | } | 476 | } |
475 | 477 | ||
476 | int drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f, | 478 | enum drbd_state_rv |
477 | union drbd_state mask, union drbd_state val) | 479 | drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f, |
480 | union drbd_state mask, union drbd_state val) | ||
478 | { | 481 | { |
479 | unsigned long flags; | 482 | unsigned long flags; |
480 | union drbd_state os, ns; | 483 | union drbd_state os, ns; |
481 | int rv; | 484 | enum drbd_state_rv rv; |
482 | 485 | ||
483 | spin_lock_irqsave(&mdev->req_lock, flags); | 486 | spin_lock_irqsave(&mdev->req_lock, flags); |
484 | os = mdev->state; | 487 | os = mdev->state; |
@@ -502,20 +505,22 @@ void drbd_force_state(struct drbd_conf *mdev, | |||
502 | drbd_change_state(mdev, CS_HARD, mask, val); | 505 | drbd_change_state(mdev, CS_HARD, mask, val); |
503 | } | 506 | } |
504 | 507 | ||
505 | static int is_valid_state(struct drbd_conf *mdev, union drbd_state ns); | 508 | static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state); |
506 | static int is_valid_state_transition(struct drbd_conf *, | 509 | static enum drbd_state_rv is_valid_state_transition(struct drbd_conf *, |
507 | union drbd_state, union drbd_state); | 510 | union drbd_state, |
511 | union drbd_state); | ||
508 | static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, | 512 | static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, |
509 | union drbd_state ns, const char **warn_sync_abort); | 513 | union drbd_state ns, const char **warn_sync_abort); |
510 | int drbd_send_state_req(struct drbd_conf *, | 514 | int drbd_send_state_req(struct drbd_conf *, |
511 | union drbd_state, union drbd_state); | 515 | union drbd_state, union drbd_state); |
512 | 516 | ||
513 | static enum drbd_state_ret_codes _req_st_cond(struct drbd_conf *mdev, | 517 | static enum drbd_state_rv |
514 | union drbd_state mask, union drbd_state val) | 518 | _req_st_cond(struct drbd_conf *mdev, union drbd_state mask, |
519 | union drbd_state val) | ||
515 | { | 520 | { |
516 | union drbd_state os, ns; | 521 | union drbd_state os, ns; |
517 | unsigned long flags; | 522 | unsigned long flags; |
518 | int rv; | 523 | enum drbd_state_rv rv; |
519 | 524 | ||
520 | if (test_and_clear_bit(CL_ST_CHG_SUCCESS, &mdev->flags)) | 525 | if (test_and_clear_bit(CL_ST_CHG_SUCCESS, &mdev->flags)) |
521 | return SS_CW_SUCCESS; | 526 | return SS_CW_SUCCESS; |
@@ -536,7 +541,7 @@ static enum drbd_state_ret_codes _req_st_cond(struct drbd_conf *mdev, | |||
536 | if (rv == SS_SUCCESS) { | 541 | if (rv == SS_SUCCESS) { |
537 | rv = is_valid_state_transition(mdev, ns, os); | 542 | rv = is_valid_state_transition(mdev, ns, os); |
538 | if (rv == SS_SUCCESS) | 543 | if (rv == SS_SUCCESS) |
539 | rv = 0; /* cont waiting, otherwise fail. */ | 544 | rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ |
540 | } | 545 | } |
541 | } | 546 | } |
542 | spin_unlock_irqrestore(&mdev->req_lock, flags); | 547 | spin_unlock_irqrestore(&mdev->req_lock, flags); |
@@ -554,14 +559,14 @@ static enum drbd_state_ret_codes _req_st_cond(struct drbd_conf *mdev, | |||
554 | * Should not be called directly, use drbd_request_state() or | 559 | * Should not be called directly, use drbd_request_state() or |
555 | * _drbd_request_state(). | 560 | * _drbd_request_state(). |
556 | */ | 561 | */ |
557 | static int drbd_req_state(struct drbd_conf *mdev, | 562 | static enum drbd_state_rv |
558 | union drbd_state mask, union drbd_state val, | 563 | drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, |
559 | enum chg_state_flags f) | 564 | union drbd_state val, enum chg_state_flags f) |
560 | { | 565 | { |
561 | struct completion done; | 566 | struct completion done; |
562 | unsigned long flags; | 567 | unsigned long flags; |
563 | union drbd_state os, ns; | 568 | union drbd_state os, ns; |
564 | int rv; | 569 | enum drbd_state_rv rv; |
565 | 570 | ||
566 | init_completion(&done); | 571 | init_completion(&done); |
567 | 572 | ||
@@ -636,10 +641,11 @@ abort: | |||
636 | * Cousin of drbd_request_state(), useful with the CS_WAIT_COMPLETE | 641 | * Cousin of drbd_request_state(), useful with the CS_WAIT_COMPLETE |
637 | * flag, or when logging of failed state change requests is not desired. | 642 | * flag, or when logging of failed state change requests is not desired. |
638 | */ | 643 | */ |
639 | int _drbd_request_state(struct drbd_conf *mdev, union drbd_state mask, | 644 | enum drbd_state_rv |
640 | union drbd_state val, enum chg_state_flags f) | 645 | _drbd_request_state(struct drbd_conf *mdev, union drbd_state mask, |
646 | union drbd_state val, enum chg_state_flags f) | ||
641 | { | 647 | { |
642 | int rv; | 648 | enum drbd_state_rv rv; |
643 | 649 | ||
644 | wait_event(mdev->state_wait, | 650 | wait_event(mdev->state_wait, |
645 | (rv = drbd_req_state(mdev, mask, val, f)) != SS_IN_TRANSIENT_STATE); | 651 | (rv = drbd_req_state(mdev, mask, val, f)) != SS_IN_TRANSIENT_STATE); |
@@ -663,8 +669,8 @@ static void print_st(struct drbd_conf *mdev, char *name, union drbd_state ns) | |||
663 | ); | 669 | ); |
664 | } | 670 | } |
665 | 671 | ||
666 | void print_st_err(struct drbd_conf *mdev, | 672 | void print_st_err(struct drbd_conf *mdev, union drbd_state os, |
667 | union drbd_state os, union drbd_state ns, int err) | 673 | union drbd_state ns, enum drbd_state_rv err) |
668 | { | 674 | { |
669 | if (err == SS_IN_TRANSIENT_STATE) | 675 | if (err == SS_IN_TRANSIENT_STATE) |
670 | return; | 676 | return; |
@@ -674,32 +680,18 @@ void print_st_err(struct drbd_conf *mdev, | |||
674 | } | 680 | } |
675 | 681 | ||
676 | 682 | ||
677 | #define drbd_peer_str drbd_role_str | ||
678 | #define drbd_pdsk_str drbd_disk_str | ||
679 | |||
680 | #define drbd_susp_str(A) ((A) ? "1" : "0") | ||
681 | #define drbd_aftr_isp_str(A) ((A) ? "1" : "0") | ||
682 | #define drbd_peer_isp_str(A) ((A) ? "1" : "0") | ||
683 | #define drbd_user_isp_str(A) ((A) ? "1" : "0") | ||
684 | |||
685 | #define PSC(A) \ | ||
686 | ({ if (ns.A != os.A) { \ | ||
687 | pbp += sprintf(pbp, #A "( %s -> %s ) ", \ | ||
688 | drbd_##A##_str(os.A), \ | ||
689 | drbd_##A##_str(ns.A)); \ | ||
690 | } }) | ||
691 | |||
692 | /** | 683 | /** |
693 | * is_valid_state() - Returns an SS_ error code if ns is not valid | 684 | * is_valid_state() - Returns an SS_ error code if ns is not valid |
694 | * @mdev: DRBD device. | 685 | * @mdev: DRBD device. |
695 | * @ns: State to consider. | 686 | * @ns: State to consider. |
696 | */ | 687 | */ |
697 | static int is_valid_state(struct drbd_conf *mdev, union drbd_state ns) | 688 | static enum drbd_state_rv |
689 | is_valid_state(struct drbd_conf *mdev, union drbd_state ns) | ||
698 | { | 690 | { |
699 | /* See drbd_state_sw_errors in drbd_strings.c */ | 691 | /* See drbd_state_sw_errors in drbd_strings.c */ |
700 | 692 | ||
701 | enum drbd_fencing_p fp; | 693 | enum drbd_fencing_p fp; |
702 | int rv = SS_SUCCESS; | 694 | enum drbd_state_rv rv = SS_SUCCESS; |
703 | 695 | ||
704 | fp = FP_DONT_CARE; | 696 | fp = FP_DONT_CARE; |
705 | if (get_ldev(mdev)) { | 697 | if (get_ldev(mdev)) { |
@@ -762,10 +754,11 @@ static int is_valid_state(struct drbd_conf *mdev, union drbd_state ns) | |||
762 | * @ns: new state. | 754 | * @ns: new state. |
763 | * @os: old state. | 755 | * @os: old state. |
764 | */ | 756 | */ |
765 | static int is_valid_state_transition(struct drbd_conf *mdev, | 757 | static enum drbd_state_rv |
766 | union drbd_state ns, union drbd_state os) | 758 | is_valid_state_transition(struct drbd_conf *mdev, union drbd_state ns, |
759 | union drbd_state os) | ||
767 | { | 760 | { |
768 | int rv = SS_SUCCESS; | 761 | enum drbd_state_rv rv = SS_SUCCESS; |
769 | 762 | ||
770 | if ((ns.conn == C_STARTING_SYNC_T || ns.conn == C_STARTING_SYNC_S) && | 763 | if ((ns.conn == C_STARTING_SYNC_T || ns.conn == C_STARTING_SYNC_S) && |
771 | os.conn > C_CONNECTED) | 764 | os.conn > C_CONNECTED) |
@@ -800,6 +793,10 @@ static int is_valid_state_transition(struct drbd_conf *mdev, | |||
800 | os.conn < C_CONNECTED) | 793 | os.conn < C_CONNECTED) |
801 | rv = SS_NEED_CONNECTION; | 794 | rv = SS_NEED_CONNECTION; |
802 | 795 | ||
796 | if ((ns.conn == C_SYNC_TARGET || ns.conn == C_SYNC_SOURCE) | ||
797 | && os.conn < C_WF_REPORT_PARAMS) | ||
798 | rv = SS_NEED_CONNECTION; /* No NetworkFailure -> SyncTarget etc... */ | ||
799 | |||
803 | return rv; | 800 | return rv; |
804 | } | 801 | } |
805 | 802 | ||
@@ -817,6 +814,7 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state | |||
817 | union drbd_state ns, const char **warn_sync_abort) | 814 | union drbd_state ns, const char **warn_sync_abort) |
818 | { | 815 | { |
819 | enum drbd_fencing_p fp; | 816 | enum drbd_fencing_p fp; |
817 | enum drbd_disk_state disk_min, disk_max, pdsk_min, pdsk_max; | ||
820 | 818 | ||
821 | fp = FP_DONT_CARE; | 819 | fp = FP_DONT_CARE; |
822 | if (get_ldev(mdev)) { | 820 | if (get_ldev(mdev)) { |
@@ -869,56 +867,6 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state | |||
869 | ns.conn = C_CONNECTED; | 867 | ns.conn = C_CONNECTED; |
870 | } | 868 | } |
871 | 869 | ||
872 | if (ns.conn >= C_CONNECTED && | ||
873 | ((ns.disk == D_CONSISTENT || ns.disk == D_OUTDATED) || | ||
874 | (ns.disk == D_NEGOTIATING && ns.conn == C_WF_BITMAP_T))) { | ||
875 | switch (ns.conn) { | ||
876 | case C_WF_BITMAP_T: | ||
877 | case C_PAUSED_SYNC_T: | ||
878 | ns.disk = D_OUTDATED; | ||
879 | break; | ||
880 | case C_CONNECTED: | ||
881 | case C_WF_BITMAP_S: | ||
882 | case C_SYNC_SOURCE: | ||
883 | case C_PAUSED_SYNC_S: | ||
884 | ns.disk = D_UP_TO_DATE; | ||
885 | break; | ||
886 | case C_SYNC_TARGET: | ||
887 | ns.disk = D_INCONSISTENT; | ||
888 | dev_warn(DEV, "Implicitly set disk state Inconsistent!\n"); | ||
889 | break; | ||
890 | } | ||
891 | if (os.disk == D_OUTDATED && ns.disk == D_UP_TO_DATE) | ||
892 | dev_warn(DEV, "Implicitly set disk from Outdated to UpToDate\n"); | ||
893 | } | ||
894 | |||
895 | if (ns.conn >= C_CONNECTED && | ||
896 | (ns.pdsk == D_CONSISTENT || ns.pdsk == D_OUTDATED)) { | ||
897 | switch (ns.conn) { | ||
898 | case C_CONNECTED: | ||
899 | case C_WF_BITMAP_T: | ||
900 | case C_PAUSED_SYNC_T: | ||
901 | case C_SYNC_TARGET: | ||
902 | ns.pdsk = D_UP_TO_DATE; | ||
903 | break; | ||
904 | case C_WF_BITMAP_S: | ||
905 | case C_PAUSED_SYNC_S: | ||
906 | /* remap any consistent state to D_OUTDATED, | ||
907 | * but disallow "upgrade" of not even consistent states. | ||
908 | */ | ||
909 | ns.pdsk = | ||
910 | (D_DISKLESS < os.pdsk && os.pdsk < D_OUTDATED) | ||
911 | ? os.pdsk : D_OUTDATED; | ||
912 | break; | ||
913 | case C_SYNC_SOURCE: | ||
914 | ns.pdsk = D_INCONSISTENT; | ||
915 | dev_warn(DEV, "Implicitly set pdsk Inconsistent!\n"); | ||
916 | break; | ||
917 | } | ||
918 | if (os.pdsk == D_OUTDATED && ns.pdsk == D_UP_TO_DATE) | ||
919 | dev_warn(DEV, "Implicitly set pdsk from Outdated to UpToDate\n"); | ||
920 | } | ||
921 | |||
922 | /* Connection breaks down before we finished "Negotiating" */ | 870 | /* Connection breaks down before we finished "Negotiating" */ |
923 | if (ns.conn < C_CONNECTED && ns.disk == D_NEGOTIATING && | 871 | if (ns.conn < C_CONNECTED && ns.disk == D_NEGOTIATING && |
924 | get_ldev_if_state(mdev, D_NEGOTIATING)) { | 872 | get_ldev_if_state(mdev, D_NEGOTIATING)) { |
@@ -933,6 +881,94 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state | |||
933 | put_ldev(mdev); | 881 | put_ldev(mdev); |
934 | } | 882 | } |
935 | 883 | ||
884 | /* D_CONSISTENT and D_OUTDATED vanish when we get connected */ | ||
885 | if (ns.conn >= C_CONNECTED && ns.conn < C_AHEAD) { | ||
886 | if (ns.disk == D_CONSISTENT || ns.disk == D_OUTDATED) | ||
887 | ns.disk = D_UP_TO_DATE; | ||
888 | if (ns.pdsk == D_CONSISTENT || ns.pdsk == D_OUTDATED) | ||
889 | ns.pdsk = D_UP_TO_DATE; | ||
890 | } | ||
891 | |||
892 | /* Implications of the connection stat on the disk states */ | ||
893 | disk_min = D_DISKLESS; | ||
894 | disk_max = D_UP_TO_DATE; | ||
895 | pdsk_min = D_INCONSISTENT; | ||
896 | pdsk_max = D_UNKNOWN; | ||
897 | switch ((enum drbd_conns)ns.conn) { | ||
898 | case C_WF_BITMAP_T: | ||
899 | case C_PAUSED_SYNC_T: | ||
900 | case C_STARTING_SYNC_T: | ||
901 | case C_WF_SYNC_UUID: | ||
902 | case C_BEHIND: | ||
903 | disk_min = D_INCONSISTENT; | ||
904 | disk_max = D_OUTDATED; | ||
905 | pdsk_min = D_UP_TO_DATE; | ||
906 | pdsk_max = D_UP_TO_DATE; | ||
907 | break; | ||
908 | case C_VERIFY_S: | ||
909 | case C_VERIFY_T: | ||
910 | disk_min = D_UP_TO_DATE; | ||
911 | disk_max = D_UP_TO_DATE; | ||
912 | pdsk_min = D_UP_TO_DATE; | ||
913 | pdsk_max = D_UP_TO_DATE; | ||
914 | break; | ||
915 | case C_CONNECTED: | ||
916 | disk_min = D_DISKLESS; | ||
917 | disk_max = D_UP_TO_DATE; | ||
918 | pdsk_min = D_DISKLESS; | ||
919 | pdsk_max = D_UP_TO_DATE; | ||
920 | break; | ||
921 | case C_WF_BITMAP_S: | ||
922 | case C_PAUSED_SYNC_S: | ||
923 | case C_STARTING_SYNC_S: | ||
924 | case C_AHEAD: | ||
925 | disk_min = D_UP_TO_DATE; | ||
926 | disk_max = D_UP_TO_DATE; | ||
927 | pdsk_min = D_INCONSISTENT; | ||
928 | pdsk_max = D_CONSISTENT; /* D_OUTDATED would be nice. But explicit outdate necessary*/ | ||
929 | break; | ||
930 | case C_SYNC_TARGET: | ||
931 | disk_min = D_INCONSISTENT; | ||
932 | disk_max = D_INCONSISTENT; | ||
933 | pdsk_min = D_UP_TO_DATE; | ||
934 | pdsk_max = D_UP_TO_DATE; | ||
935 | break; | ||
936 | case C_SYNC_SOURCE: | ||
937 | disk_min = D_UP_TO_DATE; | ||
938 | disk_max = D_UP_TO_DATE; | ||
939 | pdsk_min = D_INCONSISTENT; | ||
940 | pdsk_max = D_INCONSISTENT; | ||
941 | break; | ||
942 | case C_STANDALONE: | ||
943 | case C_DISCONNECTING: | ||
944 | case C_UNCONNECTED: | ||
945 | case C_TIMEOUT: | ||
946 | case C_BROKEN_PIPE: | ||
947 | case C_NETWORK_FAILURE: | ||
948 | case C_PROTOCOL_ERROR: | ||
949 | case C_TEAR_DOWN: | ||
950 | case C_WF_CONNECTION: | ||
951 | case C_WF_REPORT_PARAMS: | ||
952 | case C_MASK: | ||
953 | break; | ||
954 | } | ||
955 | if (ns.disk > disk_max) | ||
956 | ns.disk = disk_max; | ||
957 | |||
958 | if (ns.disk < disk_min) { | ||
959 | dev_warn(DEV, "Implicitly set disk from %s to %s\n", | ||
960 | drbd_disk_str(ns.disk), drbd_disk_str(disk_min)); | ||
961 | ns.disk = disk_min; | ||
962 | } | ||
963 | if (ns.pdsk > pdsk_max) | ||
964 | ns.pdsk = pdsk_max; | ||
965 | |||
966 | if (ns.pdsk < pdsk_min) { | ||
967 | dev_warn(DEV, "Implicitly set pdsk from %s to %s\n", | ||
968 | drbd_disk_str(ns.pdsk), drbd_disk_str(pdsk_min)); | ||
969 | ns.pdsk = pdsk_min; | ||
970 | } | ||
971 | |||
936 | if (fp == FP_STONITH && | 972 | if (fp == FP_STONITH && |
937 | (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED) && | 973 | (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED) && |
938 | !(os.role == R_PRIMARY && os.conn < C_CONNECTED && os.pdsk > D_OUTDATED)) | 974 | !(os.role == R_PRIMARY && os.conn < C_CONNECTED && os.pdsk > D_OUTDATED)) |
@@ -961,6 +997,10 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state | |||
961 | /* helper for __drbd_set_state */ | 997 | /* helper for __drbd_set_state */ |
962 | static void set_ov_position(struct drbd_conf *mdev, enum drbd_conns cs) | 998 | static void set_ov_position(struct drbd_conf *mdev, enum drbd_conns cs) |
963 | { | 999 | { |
1000 | if (mdev->agreed_pro_version < 90) | ||
1001 | mdev->ov_start_sector = 0; | ||
1002 | mdev->rs_total = drbd_bm_bits(mdev); | ||
1003 | mdev->ov_position = 0; | ||
964 | if (cs == C_VERIFY_T) { | 1004 | if (cs == C_VERIFY_T) { |
965 | /* starting online verify from an arbitrary position | 1005 | /* starting online verify from an arbitrary position |
966 | * does not fit well into the existing protocol. | 1006 | * does not fit well into the existing protocol. |
@@ -970,11 +1010,15 @@ static void set_ov_position(struct drbd_conf *mdev, enum drbd_conns cs) | |||
970 | mdev->ov_start_sector = ~(sector_t)0; | 1010 | mdev->ov_start_sector = ~(sector_t)0; |
971 | } else { | 1011 | } else { |
972 | unsigned long bit = BM_SECT_TO_BIT(mdev->ov_start_sector); | 1012 | unsigned long bit = BM_SECT_TO_BIT(mdev->ov_start_sector); |
973 | if (bit >= mdev->rs_total) | 1013 | if (bit >= mdev->rs_total) { |
974 | mdev->ov_start_sector = | 1014 | mdev->ov_start_sector = |
975 | BM_BIT_TO_SECT(mdev->rs_total - 1); | 1015 | BM_BIT_TO_SECT(mdev->rs_total - 1); |
1016 | mdev->rs_total = 1; | ||
1017 | } else | ||
1018 | mdev->rs_total -= bit; | ||
976 | mdev->ov_position = mdev->ov_start_sector; | 1019 | mdev->ov_position = mdev->ov_start_sector; |
977 | } | 1020 | } |
1021 | mdev->ov_left = mdev->rs_total; | ||
978 | } | 1022 | } |
979 | 1023 | ||
980 | static void drbd_resume_al(struct drbd_conf *mdev) | 1024 | static void drbd_resume_al(struct drbd_conf *mdev) |
@@ -992,12 +1036,12 @@ static void drbd_resume_al(struct drbd_conf *mdev) | |||
992 | * | 1036 | * |
993 | * Caller needs to hold req_lock, and global_state_lock. Do not call directly. | 1037 | * Caller needs to hold req_lock, and global_state_lock. Do not call directly. |
994 | */ | 1038 | */ |
995 | int __drbd_set_state(struct drbd_conf *mdev, | 1039 | enum drbd_state_rv |
996 | union drbd_state ns, enum chg_state_flags flags, | 1040 | __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, |
997 | struct completion *done) | 1041 | enum chg_state_flags flags, struct completion *done) |
998 | { | 1042 | { |
999 | union drbd_state os; | 1043 | union drbd_state os; |
1000 | int rv = SS_SUCCESS; | 1044 | enum drbd_state_rv rv = SS_SUCCESS; |
1001 | const char *warn_sync_abort = NULL; | 1045 | const char *warn_sync_abort = NULL; |
1002 | struct after_state_chg_work *ascw; | 1046 | struct after_state_chg_work *ascw; |
1003 | 1047 | ||
@@ -1033,22 +1077,46 @@ int __drbd_set_state(struct drbd_conf *mdev, | |||
1033 | dev_warn(DEV, "%s aborted.\n", warn_sync_abort); | 1077 | dev_warn(DEV, "%s aborted.\n", warn_sync_abort); |
1034 | 1078 | ||
1035 | { | 1079 | { |
1036 | char *pbp, pb[300]; | 1080 | char *pbp, pb[300]; |
1037 | pbp = pb; | 1081 | pbp = pb; |
1038 | *pbp = 0; | 1082 | *pbp = 0; |
1039 | PSC(role); | 1083 | if (ns.role != os.role) |
1040 | PSC(peer); | 1084 | pbp += sprintf(pbp, "role( %s -> %s ) ", |
1041 | PSC(conn); | 1085 | drbd_role_str(os.role), |
1042 | PSC(disk); | 1086 | drbd_role_str(ns.role)); |
1043 | PSC(pdsk); | 1087 | if (ns.peer != os.peer) |
1044 | if (is_susp(ns) != is_susp(os)) | 1088 | pbp += sprintf(pbp, "peer( %s -> %s ) ", |
1045 | pbp += sprintf(pbp, "susp( %s -> %s ) ", | 1089 | drbd_role_str(os.peer), |
1046 | drbd_susp_str(is_susp(os)), | 1090 | drbd_role_str(ns.peer)); |
1047 | drbd_susp_str(is_susp(ns))); | 1091 | if (ns.conn != os.conn) |
1048 | PSC(aftr_isp); | 1092 | pbp += sprintf(pbp, "conn( %s -> %s ) ", |
1049 | PSC(peer_isp); | 1093 | drbd_conn_str(os.conn), |
1050 | PSC(user_isp); | 1094 | drbd_conn_str(ns.conn)); |
1051 | dev_info(DEV, "%s\n", pb); | 1095 | if (ns.disk != os.disk) |
1096 | pbp += sprintf(pbp, "disk( %s -> %s ) ", | ||
1097 | drbd_disk_str(os.disk), | ||
1098 | drbd_disk_str(ns.disk)); | ||
1099 | if (ns.pdsk != os.pdsk) | ||
1100 | pbp += sprintf(pbp, "pdsk( %s -> %s ) ", | ||
1101 | drbd_disk_str(os.pdsk), | ||
1102 | drbd_disk_str(ns.pdsk)); | ||
1103 | if (is_susp(ns) != is_susp(os)) | ||
1104 | pbp += sprintf(pbp, "susp( %d -> %d ) ", | ||
1105 | is_susp(os), | ||
1106 | is_susp(ns)); | ||
1107 | if (ns.aftr_isp != os.aftr_isp) | ||
1108 | pbp += sprintf(pbp, "aftr_isp( %d -> %d ) ", | ||
1109 | os.aftr_isp, | ||
1110 | ns.aftr_isp); | ||
1111 | if (ns.peer_isp != os.peer_isp) | ||
1112 | pbp += sprintf(pbp, "peer_isp( %d -> %d ) ", | ||
1113 | os.peer_isp, | ||
1114 | ns.peer_isp); | ||
1115 | if (ns.user_isp != os.user_isp) | ||
1116 | pbp += sprintf(pbp, "user_isp( %d -> %d ) ", | ||
1117 | os.user_isp, | ||
1118 | ns.user_isp); | ||
1119 | dev_info(DEV, "%s\n", pb); | ||
1052 | } | 1120 | } |
1053 | 1121 | ||
1054 | /* solve the race between becoming unconfigured, | 1122 | /* solve the race between becoming unconfigured, |
@@ -1074,6 +1142,10 @@ int __drbd_set_state(struct drbd_conf *mdev, | |||
1074 | atomic_inc(&mdev->local_cnt); | 1142 | atomic_inc(&mdev->local_cnt); |
1075 | 1143 | ||
1076 | mdev->state = ns; | 1144 | mdev->state = ns; |
1145 | |||
1146 | if (os.disk == D_ATTACHING && ns.disk >= D_NEGOTIATING) | ||
1147 | drbd_print_uuids(mdev, "attached to UUIDs"); | ||
1148 | |||
1077 | wake_up(&mdev->misc_wait); | 1149 | wake_up(&mdev->misc_wait); |
1078 | wake_up(&mdev->state_wait); | 1150 | wake_up(&mdev->state_wait); |
1079 | 1151 | ||
@@ -1081,7 +1153,7 @@ int __drbd_set_state(struct drbd_conf *mdev, | |||
1081 | if ((os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) && | 1153 | if ((os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) && |
1082 | ns.conn < C_CONNECTED) { | 1154 | ns.conn < C_CONNECTED) { |
1083 | mdev->ov_start_sector = | 1155 | mdev->ov_start_sector = |
1084 | BM_BIT_TO_SECT(mdev->rs_total - mdev->ov_left); | 1156 | BM_BIT_TO_SECT(drbd_bm_bits(mdev) - mdev->ov_left); |
1085 | dev_info(DEV, "Online Verify reached sector %llu\n", | 1157 | dev_info(DEV, "Online Verify reached sector %llu\n", |
1086 | (unsigned long long)mdev->ov_start_sector); | 1158 | (unsigned long long)mdev->ov_start_sector); |
1087 | } | 1159 | } |
@@ -1106,14 +1178,7 @@ int __drbd_set_state(struct drbd_conf *mdev, | |||
1106 | unsigned long now = jiffies; | 1178 | unsigned long now = jiffies; |
1107 | int i; | 1179 | int i; |
1108 | 1180 | ||
1109 | mdev->ov_position = 0; | 1181 | set_ov_position(mdev, ns.conn); |
1110 | mdev->rs_total = drbd_bm_bits(mdev); | ||
1111 | if (mdev->agreed_pro_version >= 90) | ||
1112 | set_ov_position(mdev, ns.conn); | ||
1113 | else | ||
1114 | mdev->ov_start_sector = 0; | ||
1115 | mdev->ov_left = mdev->rs_total | ||
1116 | - BM_SECT_TO_BIT(mdev->ov_position); | ||
1117 | mdev->rs_start = now; | 1182 | mdev->rs_start = now; |
1118 | mdev->rs_last_events = 0; | 1183 | mdev->rs_last_events = 0; |
1119 | mdev->rs_last_sect_ev = 0; | 1184 | mdev->rs_last_sect_ev = 0; |
@@ -1121,10 +1186,12 @@ int __drbd_set_state(struct drbd_conf *mdev, | |||
1121 | mdev->ov_last_oos_start = 0; | 1186 | mdev->ov_last_oos_start = 0; |
1122 | 1187 | ||
1123 | for (i = 0; i < DRBD_SYNC_MARKS; i++) { | 1188 | for (i = 0; i < DRBD_SYNC_MARKS; i++) { |
1124 | mdev->rs_mark_left[i] = mdev->rs_total; | 1189 | mdev->rs_mark_left[i] = mdev->ov_left; |
1125 | mdev->rs_mark_time[i] = now; | 1190 | mdev->rs_mark_time[i] = now; |
1126 | } | 1191 | } |
1127 | 1192 | ||
1193 | drbd_rs_controller_reset(mdev); | ||
1194 | |||
1128 | if (ns.conn == C_VERIFY_S) { | 1195 | if (ns.conn == C_VERIFY_S) { |
1129 | dev_info(DEV, "Starting Online Verify from sector %llu\n", | 1196 | dev_info(DEV, "Starting Online Verify from sector %llu\n", |
1130 | (unsigned long long)mdev->ov_position); | 1197 | (unsigned long long)mdev->ov_position); |
@@ -1228,6 +1295,26 @@ static void abw_start_sync(struct drbd_conf *mdev, int rv) | |||
1228 | } | 1295 | } |
1229 | } | 1296 | } |
1230 | 1297 | ||
1298 | int drbd_bitmap_io_from_worker(struct drbd_conf *mdev, | ||
1299 | int (*io_fn)(struct drbd_conf *), | ||
1300 | char *why, enum bm_flag flags) | ||
1301 | { | ||
1302 | int rv; | ||
1303 | |||
1304 | D_ASSERT(current == mdev->worker.task); | ||
1305 | |||
1306 | /* open coded non-blocking drbd_suspend_io(mdev); */ | ||
1307 | set_bit(SUSPEND_IO, &mdev->flags); | ||
1308 | |||
1309 | drbd_bm_lock(mdev, why, flags); | ||
1310 | rv = io_fn(mdev); | ||
1311 | drbd_bm_unlock(mdev); | ||
1312 | |||
1313 | drbd_resume_io(mdev); | ||
1314 | |||
1315 | return rv; | ||
1316 | } | ||
1317 | |||
1231 | /** | 1318 | /** |
1232 | * after_state_ch() - Perform after state change actions that may sleep | 1319 | * after_state_ch() - Perform after state change actions that may sleep |
1233 | * @mdev: DRBD device. | 1320 | * @mdev: DRBD device. |
@@ -1266,16 +1353,14 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, | |||
1266 | 1353 | ||
1267 | nsm.i = -1; | 1354 | nsm.i = -1; |
1268 | if (ns.susp_nod) { | 1355 | if (ns.susp_nod) { |
1269 | if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) { | 1356 | if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) |
1270 | if (ns.conn == C_CONNECTED) | 1357 | what = resend; |
1271 | what = resend, nsm.susp_nod = 0; | ||
1272 | else /* ns.conn > C_CONNECTED */ | ||
1273 | dev_err(DEV, "Unexpected Resynd going on!\n"); | ||
1274 | } | ||
1275 | 1358 | ||
1276 | if (os.disk == D_ATTACHING && ns.disk > D_ATTACHING) | 1359 | if (os.disk == D_ATTACHING && ns.disk > D_ATTACHING) |
1277 | what = restart_frozen_disk_io, nsm.susp_nod = 0; | 1360 | what = restart_frozen_disk_io; |
1278 | 1361 | ||
1362 | if (what != nothing) | ||
1363 | nsm.susp_nod = 0; | ||
1279 | } | 1364 | } |
1280 | 1365 | ||
1281 | if (ns.susp_fen) { | 1366 | if (ns.susp_fen) { |
@@ -1306,13 +1391,30 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, | |||
1306 | spin_unlock_irq(&mdev->req_lock); | 1391 | spin_unlock_irq(&mdev->req_lock); |
1307 | } | 1392 | } |
1308 | 1393 | ||
1394 | /* Became sync source. With protocol >= 96, we still need to send out | ||
1395 | * the sync uuid now. Need to do that before any drbd_send_state, or | ||
1396 | * the other side may go "paused sync" before receiving the sync uuids, | ||
1397 | * which is unexpected. */ | ||
1398 | if ((os.conn != C_SYNC_SOURCE && os.conn != C_PAUSED_SYNC_S) && | ||
1399 | (ns.conn == C_SYNC_SOURCE || ns.conn == C_PAUSED_SYNC_S) && | ||
1400 | mdev->agreed_pro_version >= 96 && get_ldev(mdev)) { | ||
1401 | drbd_gen_and_send_sync_uuid(mdev); | ||
1402 | put_ldev(mdev); | ||
1403 | } | ||
1404 | |||
1309 | /* Do not change the order of the if above and the two below... */ | 1405 | /* Do not change the order of the if above and the two below... */ |
1310 | if (os.pdsk == D_DISKLESS && ns.pdsk > D_DISKLESS) { /* attach on the peer */ | 1406 | if (os.pdsk == D_DISKLESS && ns.pdsk > D_DISKLESS) { /* attach on the peer */ |
1311 | drbd_send_uuids(mdev); | 1407 | drbd_send_uuids(mdev); |
1312 | drbd_send_state(mdev); | 1408 | drbd_send_state(mdev); |
1313 | } | 1409 | } |
1314 | if (os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S) | 1410 | /* No point in queuing send_bitmap if we don't have a connection |
1315 | drbd_queue_bitmap_io(mdev, &drbd_send_bitmap, NULL, "send_bitmap (WFBitMapS)"); | 1411 | * anymore, so check also the _current_ state, not only the new state |
1412 | * at the time this work was queued. */ | ||
1413 | if (os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S && | ||
1414 | mdev->state.conn == C_WF_BITMAP_S) | ||
1415 | drbd_queue_bitmap_io(mdev, &drbd_send_bitmap, NULL, | ||
1416 | "send_bitmap (WFBitMapS)", | ||
1417 | BM_LOCKED_TEST_ALLOWED); | ||
1316 | 1418 | ||
1317 | /* Lost contact to peer's copy of the data */ | 1419 | /* Lost contact to peer's copy of the data */ |
1318 | if ((os.pdsk >= D_INCONSISTENT && | 1420 | if ((os.pdsk >= D_INCONSISTENT && |
@@ -1343,7 +1445,23 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, | |||
1343 | 1445 | ||
1344 | /* D_DISKLESS Peer becomes secondary */ | 1446 | /* D_DISKLESS Peer becomes secondary */ |
1345 | if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY) | 1447 | if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY) |
1346 | drbd_al_to_on_disk_bm(mdev); | 1448 | /* We may still be Primary ourselves. |
1449 | * No harm done if the bitmap still changes, | ||
1450 | * redirtied pages will follow later. */ | ||
1451 | drbd_bitmap_io_from_worker(mdev, &drbd_bm_write, | ||
1452 | "demote diskless peer", BM_LOCKED_SET_ALLOWED); | ||
1453 | put_ldev(mdev); | ||
1454 | } | ||
1455 | |||
1456 | /* Write out all changed bits on demote. | ||
1457 | * Though, no need to da that just yet | ||
1458 | * if there is a resync going on still */ | ||
1459 | if (os.role == R_PRIMARY && ns.role == R_SECONDARY && | ||
1460 | mdev->state.conn <= C_CONNECTED && get_ldev(mdev)) { | ||
1461 | /* No changes to the bitmap expected this time, so assert that, | ||
1462 | * even though no harm was done if it did change. */ | ||
1463 | drbd_bitmap_io_from_worker(mdev, &drbd_bm_write, | ||
1464 | "demote", BM_LOCKED_TEST_ALLOWED); | ||
1347 | put_ldev(mdev); | 1465 | put_ldev(mdev); |
1348 | } | 1466 | } |
1349 | 1467 | ||
@@ -1371,15 +1489,23 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, | |||
1371 | if (os.conn == C_WF_REPORT_PARAMS && ns.conn >= C_CONNECTED) | 1489 | if (os.conn == C_WF_REPORT_PARAMS && ns.conn >= C_CONNECTED) |
1372 | drbd_send_state(mdev); | 1490 | drbd_send_state(mdev); |
1373 | 1491 | ||
1492 | if (os.conn != C_AHEAD && ns.conn == C_AHEAD) | ||
1493 | drbd_send_state(mdev); | ||
1494 | |||
1374 | /* We are in the progress to start a full sync... */ | 1495 | /* We are in the progress to start a full sync... */ |
1375 | if ((os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) || | 1496 | if ((os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) || |
1376 | (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S)) | 1497 | (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S)) |
1377 | drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, &abw_start_sync, "set_n_write from StartingSync"); | 1498 | /* no other bitmap changes expected during this phase */ |
1499 | drbd_queue_bitmap_io(mdev, | ||
1500 | &drbd_bmio_set_n_write, &abw_start_sync, | ||
1501 | "set_n_write from StartingSync", BM_LOCKED_TEST_ALLOWED); | ||
1378 | 1502 | ||
1379 | /* We are invalidating our self... */ | 1503 | /* We are invalidating our self... */ |
1380 | if (os.conn < C_CONNECTED && ns.conn < C_CONNECTED && | 1504 | if (os.conn < C_CONNECTED && ns.conn < C_CONNECTED && |
1381 | os.disk > D_INCONSISTENT && ns.disk == D_INCONSISTENT) | 1505 | os.disk > D_INCONSISTENT && ns.disk == D_INCONSISTENT) |
1382 | drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL, "set_n_write from invalidate"); | 1506 | /* other bitmap operation expected during this phase */ |
1507 | drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL, | ||
1508 | "set_n_write from invalidate", BM_LOCKED_MASK); | ||
1383 | 1509 | ||
1384 | /* first half of local IO error, failure to attach, | 1510 | /* first half of local IO error, failure to attach, |
1385 | * or administrative detach */ | 1511 | * or administrative detach */ |
@@ -1434,8 +1560,6 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, | |||
1434 | 1560 | ||
1435 | if (drbd_send_state(mdev)) | 1561 | if (drbd_send_state(mdev)) |
1436 | dev_warn(DEV, "Notified peer that I'm now diskless.\n"); | 1562 | dev_warn(DEV, "Notified peer that I'm now diskless.\n"); |
1437 | else | ||
1438 | dev_err(DEV, "Sending state for being diskless failed\n"); | ||
1439 | /* corresponding get_ldev in __drbd_set_state | 1563 | /* corresponding get_ldev in __drbd_set_state |
1440 | * this may finaly trigger drbd_ldev_destroy. */ | 1564 | * this may finaly trigger drbd_ldev_destroy. */ |
1441 | put_ldev(mdev); | 1565 | put_ldev(mdev); |
@@ -1459,6 +1583,19 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, | |||
1459 | if (os.disk < D_UP_TO_DATE && os.conn >= C_SYNC_SOURCE && ns.conn == C_CONNECTED) | 1583 | if (os.disk < D_UP_TO_DATE && os.conn >= C_SYNC_SOURCE && ns.conn == C_CONNECTED) |
1460 | drbd_send_state(mdev); | 1584 | drbd_send_state(mdev); |
1461 | 1585 | ||
1586 | /* This triggers bitmap writeout of potentially still unwritten pages | ||
1587 | * if the resync finished cleanly, or aborted because of peer disk | ||
1588 | * failure, or because of connection loss. | ||
1589 | * For resync aborted because of local disk failure, we cannot do | ||
1590 | * any bitmap writeout anymore. | ||
1591 | * No harm done if some bits change during this phase. | ||
1592 | */ | ||
1593 | if (os.conn > C_CONNECTED && ns.conn <= C_CONNECTED && get_ldev(mdev)) { | ||
1594 | drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, | ||
1595 | "write from resync_finished", BM_LOCKED_SET_ALLOWED); | ||
1596 | put_ldev(mdev); | ||
1597 | } | ||
1598 | |||
1462 | /* free tl_hash if we Got thawed and are C_STANDALONE */ | 1599 | /* free tl_hash if we Got thawed and are C_STANDALONE */ |
1463 | if (ns.conn == C_STANDALONE && !is_susp(ns) && mdev->tl_hash) | 1600 | if (ns.conn == C_STANDALONE && !is_susp(ns) && mdev->tl_hash) |
1464 | drbd_free_tl_hash(mdev); | 1601 | drbd_free_tl_hash(mdev); |
@@ -1559,7 +1696,7 @@ int drbd_thread_start(struct drbd_thread *thi) | |||
1559 | if (!try_module_get(THIS_MODULE)) { | 1696 | if (!try_module_get(THIS_MODULE)) { |
1560 | dev_err(DEV, "Failed to get module reference in drbd_thread_start\n"); | 1697 | dev_err(DEV, "Failed to get module reference in drbd_thread_start\n"); |
1561 | spin_unlock_irqrestore(&thi->t_lock, flags); | 1698 | spin_unlock_irqrestore(&thi->t_lock, flags); |
1562 | return FALSE; | 1699 | return false; |
1563 | } | 1700 | } |
1564 | 1701 | ||
1565 | init_completion(&thi->stop); | 1702 | init_completion(&thi->stop); |
@@ -1576,7 +1713,7 @@ int drbd_thread_start(struct drbd_thread *thi) | |||
1576 | dev_err(DEV, "Couldn't start thread\n"); | 1713 | dev_err(DEV, "Couldn't start thread\n"); |
1577 | 1714 | ||
1578 | module_put(THIS_MODULE); | 1715 | module_put(THIS_MODULE); |
1579 | return FALSE; | 1716 | return false; |
1580 | } | 1717 | } |
1581 | spin_lock_irqsave(&thi->t_lock, flags); | 1718 | spin_lock_irqsave(&thi->t_lock, flags); |
1582 | thi->task = nt; | 1719 | thi->task = nt; |
@@ -1596,7 +1733,7 @@ int drbd_thread_start(struct drbd_thread *thi) | |||
1596 | break; | 1733 | break; |
1597 | } | 1734 | } |
1598 | 1735 | ||
1599 | return TRUE; | 1736 | return true; |
1600 | } | 1737 | } |
1601 | 1738 | ||
1602 | 1739 | ||
@@ -1694,8 +1831,8 @@ int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, | |||
1694 | { | 1831 | { |
1695 | int sent, ok; | 1832 | int sent, ok; |
1696 | 1833 | ||
1697 | ERR_IF(!h) return FALSE; | 1834 | ERR_IF(!h) return false; |
1698 | ERR_IF(!size) return FALSE; | 1835 | ERR_IF(!size) return false; |
1699 | 1836 | ||
1700 | h->magic = BE_DRBD_MAGIC; | 1837 | h->magic = BE_DRBD_MAGIC; |
1701 | h->command = cpu_to_be16(cmd); | 1838 | h->command = cpu_to_be16(cmd); |
@@ -1704,8 +1841,8 @@ int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, | |||
1704 | sent = drbd_send(mdev, sock, h, size, msg_flags); | 1841 | sent = drbd_send(mdev, sock, h, size, msg_flags); |
1705 | 1842 | ||
1706 | ok = (sent == size); | 1843 | ok = (sent == size); |
1707 | if (!ok) | 1844 | if (!ok && !signal_pending(current)) |
1708 | dev_err(DEV, "short sent %s size=%d sent=%d\n", | 1845 | dev_warn(DEV, "short sent %s size=%d sent=%d\n", |
1709 | cmdname(cmd), (int)size, sent); | 1846 | cmdname(cmd), (int)size, sent); |
1710 | return ok; | 1847 | return ok; |
1711 | } | 1848 | } |
@@ -1840,7 +1977,7 @@ int drbd_send_protocol(struct drbd_conf *mdev) | |||
1840 | else { | 1977 | else { |
1841 | dev_err(DEV, "--dry-run is not supported by peer"); | 1978 | dev_err(DEV, "--dry-run is not supported by peer"); |
1842 | kfree(p); | 1979 | kfree(p); |
1843 | return 0; | 1980 | return -1; |
1844 | } | 1981 | } |
1845 | } | 1982 | } |
1846 | p->conn_flags = cpu_to_be32(cf); | 1983 | p->conn_flags = cpu_to_be32(cf); |
@@ -1888,12 +2025,36 @@ int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev) | |||
1888 | return _drbd_send_uuids(mdev, 8); | 2025 | return _drbd_send_uuids(mdev, 8); |
1889 | } | 2026 | } |
1890 | 2027 | ||
2028 | void drbd_print_uuids(struct drbd_conf *mdev, const char *text) | ||
2029 | { | ||
2030 | if (get_ldev_if_state(mdev, D_NEGOTIATING)) { | ||
2031 | u64 *uuid = mdev->ldev->md.uuid; | ||
2032 | dev_info(DEV, "%s %016llX:%016llX:%016llX:%016llX\n", | ||
2033 | text, | ||
2034 | (unsigned long long)uuid[UI_CURRENT], | ||
2035 | (unsigned long long)uuid[UI_BITMAP], | ||
2036 | (unsigned long long)uuid[UI_HISTORY_START], | ||
2037 | (unsigned long long)uuid[UI_HISTORY_END]); | ||
2038 | put_ldev(mdev); | ||
2039 | } else { | ||
2040 | dev_info(DEV, "%s effective data uuid: %016llX\n", | ||
2041 | text, | ||
2042 | (unsigned long long)mdev->ed_uuid); | ||
2043 | } | ||
2044 | } | ||
1891 | 2045 | ||
1892 | int drbd_send_sync_uuid(struct drbd_conf *mdev, u64 val) | 2046 | int drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev) |
1893 | { | 2047 | { |
1894 | struct p_rs_uuid p; | 2048 | struct p_rs_uuid p; |
2049 | u64 uuid; | ||
1895 | 2050 | ||
1896 | p.uuid = cpu_to_be64(val); | 2051 | D_ASSERT(mdev->state.disk == D_UP_TO_DATE); |
2052 | |||
2053 | uuid = mdev->ldev->md.uuid[UI_BITMAP] + UUID_NEW_BM_OFFSET; | ||
2054 | drbd_uuid_set(mdev, UI_BITMAP, uuid); | ||
2055 | drbd_print_uuids(mdev, "updated sync UUID"); | ||
2056 | drbd_md_sync(mdev); | ||
2057 | p.uuid = cpu_to_be64(uuid); | ||
1897 | 2058 | ||
1898 | return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_SYNC_UUID, | 2059 | return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_SYNC_UUID, |
1899 | (struct p_header80 *)&p, sizeof(p)); | 2060 | (struct p_header80 *)&p, sizeof(p)); |
@@ -1921,7 +2082,7 @@ int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags fl | |||
1921 | p.d_size = cpu_to_be64(d_size); | 2082 | p.d_size = cpu_to_be64(d_size); |
1922 | p.u_size = cpu_to_be64(u_size); | 2083 | p.u_size = cpu_to_be64(u_size); |
1923 | p.c_size = cpu_to_be64(trigger_reply ? 0 : drbd_get_capacity(mdev->this_bdev)); | 2084 | p.c_size = cpu_to_be64(trigger_reply ? 0 : drbd_get_capacity(mdev->this_bdev)); |
1924 | p.max_segment_size = cpu_to_be32(queue_max_segment_size(mdev->rq_queue)); | 2085 | p.max_bio_size = cpu_to_be32(queue_max_hw_sectors(mdev->rq_queue) << 9); |
1925 | p.queue_order_type = cpu_to_be16(q_order_type); | 2086 | p.queue_order_type = cpu_to_be16(q_order_type); |
1926 | p.dds_flags = cpu_to_be16(flags); | 2087 | p.dds_flags = cpu_to_be16(flags); |
1927 | 2088 | ||
@@ -1972,7 +2133,7 @@ int drbd_send_state_req(struct drbd_conf *mdev, | |||
1972 | (struct p_header80 *)&p, sizeof(p)); | 2133 | (struct p_header80 *)&p, sizeof(p)); |
1973 | } | 2134 | } |
1974 | 2135 | ||
1975 | int drbd_send_sr_reply(struct drbd_conf *mdev, int retcode) | 2136 | int drbd_send_sr_reply(struct drbd_conf *mdev, enum drbd_state_rv retcode) |
1976 | { | 2137 | { |
1977 | struct p_req_state_reply p; | 2138 | struct p_req_state_reply p; |
1978 | 2139 | ||
@@ -2076,9 +2237,15 @@ int fill_bitmap_rle_bits(struct drbd_conf *mdev, | |||
2076 | return len; | 2237 | return len; |
2077 | } | 2238 | } |
2078 | 2239 | ||
2079 | enum { OK, FAILED, DONE } | 2240 | /** |
2241 | * send_bitmap_rle_or_plain | ||
2242 | * | ||
2243 | * Return 0 when done, 1 when another iteration is needed, and a negative error | ||
2244 | * code upon failure. | ||
2245 | */ | ||
2246 | static int | ||
2080 | send_bitmap_rle_or_plain(struct drbd_conf *mdev, | 2247 | send_bitmap_rle_or_plain(struct drbd_conf *mdev, |
2081 | struct p_header80 *h, struct bm_xfer_ctx *c) | 2248 | struct p_header80 *h, struct bm_xfer_ctx *c) |
2082 | { | 2249 | { |
2083 | struct p_compressed_bm *p = (void*)h; | 2250 | struct p_compressed_bm *p = (void*)h; |
2084 | unsigned long num_words; | 2251 | unsigned long num_words; |
@@ -2088,7 +2255,7 @@ send_bitmap_rle_or_plain(struct drbd_conf *mdev, | |||
2088 | len = fill_bitmap_rle_bits(mdev, p, c); | 2255 | len = fill_bitmap_rle_bits(mdev, p, c); |
2089 | 2256 | ||
2090 | if (len < 0) | 2257 | if (len < 0) |
2091 | return FAILED; | 2258 | return -EIO; |
2092 | 2259 | ||
2093 | if (len) { | 2260 | if (len) { |
2094 | DCBP_set_code(p, RLE_VLI_Bits); | 2261 | DCBP_set_code(p, RLE_VLI_Bits); |
@@ -2118,11 +2285,14 @@ send_bitmap_rle_or_plain(struct drbd_conf *mdev, | |||
2118 | if (c->bit_offset > c->bm_bits) | 2285 | if (c->bit_offset > c->bm_bits) |
2119 | c->bit_offset = c->bm_bits; | 2286 | c->bit_offset = c->bm_bits; |
2120 | } | 2287 | } |
2121 | ok = ok ? ((len == 0) ? DONE : OK) : FAILED; | 2288 | if (ok) { |
2122 | 2289 | if (len == 0) { | |
2123 | if (ok == DONE) | 2290 | INFO_bm_xfer_stats(mdev, "send", c); |
2124 | INFO_bm_xfer_stats(mdev, "send", c); | 2291 | return 0; |
2125 | return ok; | 2292 | } else |
2293 | return 1; | ||
2294 | } | ||
2295 | return -EIO; | ||
2126 | } | 2296 | } |
2127 | 2297 | ||
2128 | /* See the comment at receive_bitmap() */ | 2298 | /* See the comment at receive_bitmap() */ |
@@ -2130,16 +2300,16 @@ int _drbd_send_bitmap(struct drbd_conf *mdev) | |||
2130 | { | 2300 | { |
2131 | struct bm_xfer_ctx c; | 2301 | struct bm_xfer_ctx c; |
2132 | struct p_header80 *p; | 2302 | struct p_header80 *p; |
2133 | int ret; | 2303 | int err; |
2134 | 2304 | ||
2135 | ERR_IF(!mdev->bitmap) return FALSE; | 2305 | ERR_IF(!mdev->bitmap) return false; |
2136 | 2306 | ||
2137 | /* maybe we should use some per thread scratch page, | 2307 | /* maybe we should use some per thread scratch page, |
2138 | * and allocate that during initial device creation? */ | 2308 | * and allocate that during initial device creation? */ |
2139 | p = (struct p_header80 *) __get_free_page(GFP_NOIO); | 2309 | p = (struct p_header80 *) __get_free_page(GFP_NOIO); |
2140 | if (!p) { | 2310 | if (!p) { |
2141 | dev_err(DEV, "failed to allocate one page buffer in %s\n", __func__); | 2311 | dev_err(DEV, "failed to allocate one page buffer in %s\n", __func__); |
2142 | return FALSE; | 2312 | return false; |
2143 | } | 2313 | } |
2144 | 2314 | ||
2145 | if (get_ldev(mdev)) { | 2315 | if (get_ldev(mdev)) { |
@@ -2165,11 +2335,11 @@ int _drbd_send_bitmap(struct drbd_conf *mdev) | |||
2165 | }; | 2335 | }; |
2166 | 2336 | ||
2167 | do { | 2337 | do { |
2168 | ret = send_bitmap_rle_or_plain(mdev, p, &c); | 2338 | err = send_bitmap_rle_or_plain(mdev, p, &c); |
2169 | } while (ret == OK); | 2339 | } while (err > 0); |
2170 | 2340 | ||
2171 | free_page((unsigned long) p); | 2341 | free_page((unsigned long) p); |
2172 | return (ret == DONE); | 2342 | return err == 0; |
2173 | } | 2343 | } |
2174 | 2344 | ||
2175 | int drbd_send_bitmap(struct drbd_conf *mdev) | 2345 | int drbd_send_bitmap(struct drbd_conf *mdev) |
@@ -2192,7 +2362,7 @@ int drbd_send_b_ack(struct drbd_conf *mdev, u32 barrier_nr, u32 set_size) | |||
2192 | p.set_size = cpu_to_be32(set_size); | 2362 | p.set_size = cpu_to_be32(set_size); |
2193 | 2363 | ||
2194 | if (mdev->state.conn < C_CONNECTED) | 2364 | if (mdev->state.conn < C_CONNECTED) |
2195 | return FALSE; | 2365 | return false; |
2196 | ok = drbd_send_cmd(mdev, USE_META_SOCKET, P_BARRIER_ACK, | 2366 | ok = drbd_send_cmd(mdev, USE_META_SOCKET, P_BARRIER_ACK, |
2197 | (struct p_header80 *)&p, sizeof(p)); | 2367 | (struct p_header80 *)&p, sizeof(p)); |
2198 | return ok; | 2368 | return ok; |
@@ -2220,7 +2390,7 @@ static int _drbd_send_ack(struct drbd_conf *mdev, enum drbd_packets cmd, | |||
2220 | p.seq_num = cpu_to_be32(atomic_add_return(1, &mdev->packet_seq)); | 2390 | p.seq_num = cpu_to_be32(atomic_add_return(1, &mdev->packet_seq)); |
2221 | 2391 | ||
2222 | if (!mdev->meta.socket || mdev->state.conn < C_CONNECTED) | 2392 | if (!mdev->meta.socket || mdev->state.conn < C_CONNECTED) |
2223 | return FALSE; | 2393 | return false; |
2224 | ok = drbd_send_cmd(mdev, USE_META_SOCKET, cmd, | 2394 | ok = drbd_send_cmd(mdev, USE_META_SOCKET, cmd, |
2225 | (struct p_header80 *)&p, sizeof(p)); | 2395 | (struct p_header80 *)&p, sizeof(p)); |
2226 | return ok; | 2396 | return ok; |
@@ -2326,8 +2496,8 @@ int drbd_send_ov_request(struct drbd_conf *mdev, sector_t sector, int size) | |||
2326 | } | 2496 | } |
2327 | 2497 | ||
2328 | /* called on sndtimeo | 2498 | /* called on sndtimeo |
2329 | * returns FALSE if we should retry, | 2499 | * returns false if we should retry, |
2330 | * TRUE if we think connection is dead | 2500 | * true if we think connection is dead |
2331 | */ | 2501 | */ |
2332 | static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket *sock) | 2502 | static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket *sock) |
2333 | { | 2503 | { |
@@ -2340,7 +2510,7 @@ static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket * | |||
2340 | || mdev->state.conn < C_CONNECTED; | 2510 | || mdev->state.conn < C_CONNECTED; |
2341 | 2511 | ||
2342 | if (drop_it) | 2512 | if (drop_it) |
2343 | return TRUE; | 2513 | return true; |
2344 | 2514 | ||
2345 | drop_it = !--mdev->ko_count; | 2515 | drop_it = !--mdev->ko_count; |
2346 | if (!drop_it) { | 2516 | if (!drop_it) { |
@@ -2531,13 +2701,39 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) | |||
2531 | if (ok && dgs) { | 2701 | if (ok && dgs) { |
2532 | dgb = mdev->int_dig_out; | 2702 | dgb = mdev->int_dig_out; |
2533 | drbd_csum_bio(mdev, mdev->integrity_w_tfm, req->master_bio, dgb); | 2703 | drbd_csum_bio(mdev, mdev->integrity_w_tfm, req->master_bio, dgb); |
2534 | ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, 0); | 2704 | ok = dgs == drbd_send(mdev, mdev->data.socket, dgb, dgs, 0); |
2535 | } | 2705 | } |
2536 | if (ok) { | 2706 | if (ok) { |
2537 | if (mdev->net_conf->wire_protocol == DRBD_PROT_A) | 2707 | /* For protocol A, we have to memcpy the payload into |
2708 | * socket buffers, as we may complete right away | ||
2709 | * as soon as we handed it over to tcp, at which point the data | ||
2710 | * pages may become invalid. | ||
2711 | * | ||
2712 | * For data-integrity enabled, we copy it as well, so we can be | ||
2713 | * sure that even if the bio pages may still be modified, it | ||
2714 | * won't change the data on the wire, thus if the digest checks | ||
2715 | * out ok after sending on this side, but does not fit on the | ||
2716 | * receiving side, we sure have detected corruption elsewhere. | ||
2717 | */ | ||
2718 | if (mdev->net_conf->wire_protocol == DRBD_PROT_A || dgs) | ||
2538 | ok = _drbd_send_bio(mdev, req->master_bio); | 2719 | ok = _drbd_send_bio(mdev, req->master_bio); |
2539 | else | 2720 | else |
2540 | ok = _drbd_send_zc_bio(mdev, req->master_bio); | 2721 | ok = _drbd_send_zc_bio(mdev, req->master_bio); |
2722 | |||
2723 | /* double check digest, sometimes buffers have been modified in flight. */ | ||
2724 | if (dgs > 0 && dgs <= 64) { | ||
2725 | /* 64 byte, 512 bit, is the larges digest size | ||
2726 | * currently supported in kernel crypto. */ | ||
2727 | unsigned char digest[64]; | ||
2728 | drbd_csum_bio(mdev, mdev->integrity_w_tfm, req->master_bio, digest); | ||
2729 | if (memcmp(mdev->int_dig_out, digest, dgs)) { | ||
2730 | dev_warn(DEV, | ||
2731 | "Digest mismatch, buffer modified by upper layers during write: %llus +%u\n", | ||
2732 | (unsigned long long)req->sector, req->size); | ||
2733 | } | ||
2734 | } /* else if (dgs > 64) { | ||
2735 | ... Be noisy about digest too large ... | ||
2736 | } */ | ||
2541 | } | 2737 | } |
2542 | 2738 | ||
2543 | drbd_put_data_sock(mdev); | 2739 | drbd_put_data_sock(mdev); |
@@ -2587,7 +2783,7 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, | |||
2587 | if (ok && dgs) { | 2783 | if (ok && dgs) { |
2588 | dgb = mdev->int_dig_out; | 2784 | dgb = mdev->int_dig_out; |
2589 | drbd_csum_ee(mdev, mdev->integrity_w_tfm, e, dgb); | 2785 | drbd_csum_ee(mdev, mdev->integrity_w_tfm, e, dgb); |
2590 | ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, 0); | 2786 | ok = dgs == drbd_send(mdev, mdev->data.socket, dgb, dgs, 0); |
2591 | } | 2787 | } |
2592 | if (ok) | 2788 | if (ok) |
2593 | ok = _drbd_send_zc_ee(mdev, e); | 2789 | ok = _drbd_send_zc_ee(mdev, e); |
@@ -2597,6 +2793,16 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, | |||
2597 | return ok; | 2793 | return ok; |
2598 | } | 2794 | } |
2599 | 2795 | ||
2796 | int drbd_send_oos(struct drbd_conf *mdev, struct drbd_request *req) | ||
2797 | { | ||
2798 | struct p_block_desc p; | ||
2799 | |||
2800 | p.sector = cpu_to_be64(req->sector); | ||
2801 | p.blksize = cpu_to_be32(req->size); | ||
2802 | |||
2803 | return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_OUT_OF_SYNC, &p.head, sizeof(p)); | ||
2804 | } | ||
2805 | |||
2600 | /* | 2806 | /* |
2601 | drbd_send distinguishes two cases: | 2807 | drbd_send distinguishes two cases: |
2602 | 2808 | ||
@@ -2770,6 +2976,7 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) | |||
2770 | atomic_set(&mdev->pp_in_use_by_net, 0); | 2976 | atomic_set(&mdev->pp_in_use_by_net, 0); |
2771 | atomic_set(&mdev->rs_sect_in, 0); | 2977 | atomic_set(&mdev->rs_sect_in, 0); |
2772 | atomic_set(&mdev->rs_sect_ev, 0); | 2978 | atomic_set(&mdev->rs_sect_ev, 0); |
2979 | atomic_set(&mdev->ap_in_flight, 0); | ||
2773 | 2980 | ||
2774 | mutex_init(&mdev->md_io_mutex); | 2981 | mutex_init(&mdev->md_io_mutex); |
2775 | mutex_init(&mdev->data.mutex); | 2982 | mutex_init(&mdev->data.mutex); |
@@ -2798,19 +3005,27 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) | |||
2798 | INIT_LIST_HEAD(&mdev->unplug_work.list); | 3005 | INIT_LIST_HEAD(&mdev->unplug_work.list); |
2799 | INIT_LIST_HEAD(&mdev->go_diskless.list); | 3006 | INIT_LIST_HEAD(&mdev->go_diskless.list); |
2800 | INIT_LIST_HEAD(&mdev->md_sync_work.list); | 3007 | INIT_LIST_HEAD(&mdev->md_sync_work.list); |
3008 | INIT_LIST_HEAD(&mdev->start_resync_work.list); | ||
2801 | INIT_LIST_HEAD(&mdev->bm_io_work.w.list); | 3009 | INIT_LIST_HEAD(&mdev->bm_io_work.w.list); |
2802 | 3010 | ||
2803 | mdev->resync_work.cb = w_resync_inactive; | 3011 | mdev->resync_work.cb = w_resync_timer; |
2804 | mdev->unplug_work.cb = w_send_write_hint; | 3012 | mdev->unplug_work.cb = w_send_write_hint; |
2805 | mdev->go_diskless.cb = w_go_diskless; | 3013 | mdev->go_diskless.cb = w_go_diskless; |
2806 | mdev->md_sync_work.cb = w_md_sync; | 3014 | mdev->md_sync_work.cb = w_md_sync; |
2807 | mdev->bm_io_work.w.cb = w_bitmap_io; | 3015 | mdev->bm_io_work.w.cb = w_bitmap_io; |
3016 | mdev->start_resync_work.cb = w_start_resync; | ||
2808 | init_timer(&mdev->resync_timer); | 3017 | init_timer(&mdev->resync_timer); |
2809 | init_timer(&mdev->md_sync_timer); | 3018 | init_timer(&mdev->md_sync_timer); |
3019 | init_timer(&mdev->start_resync_timer); | ||
3020 | init_timer(&mdev->request_timer); | ||
2810 | mdev->resync_timer.function = resync_timer_fn; | 3021 | mdev->resync_timer.function = resync_timer_fn; |
2811 | mdev->resync_timer.data = (unsigned long) mdev; | 3022 | mdev->resync_timer.data = (unsigned long) mdev; |
2812 | mdev->md_sync_timer.function = md_sync_timer_fn; | 3023 | mdev->md_sync_timer.function = md_sync_timer_fn; |
2813 | mdev->md_sync_timer.data = (unsigned long) mdev; | 3024 | mdev->md_sync_timer.data = (unsigned long) mdev; |
3025 | mdev->start_resync_timer.function = start_resync_timer_fn; | ||
3026 | mdev->start_resync_timer.data = (unsigned long) mdev; | ||
3027 | mdev->request_timer.function = request_timer_fn; | ||
3028 | mdev->request_timer.data = (unsigned long) mdev; | ||
2814 | 3029 | ||
2815 | init_waitqueue_head(&mdev->misc_wait); | 3030 | init_waitqueue_head(&mdev->misc_wait); |
2816 | init_waitqueue_head(&mdev->state_wait); | 3031 | init_waitqueue_head(&mdev->state_wait); |
@@ -2881,6 +3096,8 @@ void drbd_mdev_cleanup(struct drbd_conf *mdev) | |||
2881 | D_ASSERT(list_empty(&mdev->resync_work.list)); | 3096 | D_ASSERT(list_empty(&mdev->resync_work.list)); |
2882 | D_ASSERT(list_empty(&mdev->unplug_work.list)); | 3097 | D_ASSERT(list_empty(&mdev->unplug_work.list)); |
2883 | D_ASSERT(list_empty(&mdev->go_diskless.list)); | 3098 | D_ASSERT(list_empty(&mdev->go_diskless.list)); |
3099 | |||
3100 | drbd_set_defaults(mdev); | ||
2884 | } | 3101 | } |
2885 | 3102 | ||
2886 | 3103 | ||
@@ -2923,7 +3140,7 @@ static void drbd_destroy_mempools(void) | |||
2923 | static int drbd_create_mempools(void) | 3140 | static int drbd_create_mempools(void) |
2924 | { | 3141 | { |
2925 | struct page *page; | 3142 | struct page *page; |
2926 | const int number = (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE) * minor_count; | 3143 | const int number = (DRBD_MAX_BIO_SIZE/PAGE_SIZE) * minor_count; |
2927 | int i; | 3144 | int i; |
2928 | 3145 | ||
2929 | /* prepare our caches and mempools */ | 3146 | /* prepare our caches and mempools */ |
@@ -3087,11 +3304,20 @@ static void drbd_cleanup(void) | |||
3087 | 3304 | ||
3088 | unregister_reboot_notifier(&drbd_notifier); | 3305 | unregister_reboot_notifier(&drbd_notifier); |
3089 | 3306 | ||
3307 | /* first remove proc, | ||
3308 | * drbdsetup uses it's presence to detect | ||
3309 | * whether DRBD is loaded. | ||
3310 | * If we would get stuck in proc removal, | ||
3311 | * but have netlink already deregistered, | ||
3312 | * some drbdsetup commands may wait forever | ||
3313 | * for an answer. | ||
3314 | */ | ||
3315 | if (drbd_proc) | ||
3316 | remove_proc_entry("drbd", NULL); | ||
3317 | |||
3090 | drbd_nl_cleanup(); | 3318 | drbd_nl_cleanup(); |
3091 | 3319 | ||
3092 | if (minor_table) { | 3320 | if (minor_table) { |
3093 | if (drbd_proc) | ||
3094 | remove_proc_entry("drbd", NULL); | ||
3095 | i = minor_count; | 3321 | i = minor_count; |
3096 | while (i--) | 3322 | while (i--) |
3097 | drbd_delete_device(i); | 3323 | drbd_delete_device(i); |
@@ -3119,7 +3345,7 @@ static int drbd_congested(void *congested_data, int bdi_bits) | |||
3119 | char reason = '-'; | 3345 | char reason = '-'; |
3120 | int r = 0; | 3346 | int r = 0; |
3121 | 3347 | ||
3122 | if (!__inc_ap_bio_cond(mdev)) { | 3348 | if (!may_inc_ap_bio(mdev)) { |
3123 | /* DRBD has frozen IO */ | 3349 | /* DRBD has frozen IO */ |
3124 | r = bdi_bits; | 3350 | r = bdi_bits; |
3125 | reason = 'd'; | 3351 | reason = 'd'; |
@@ -3172,7 +3398,7 @@ struct drbd_conf *drbd_new_device(unsigned int minor) | |||
3172 | goto out_no_disk; | 3398 | goto out_no_disk; |
3173 | mdev->vdisk = disk; | 3399 | mdev->vdisk = disk; |
3174 | 3400 | ||
3175 | set_disk_ro(disk, TRUE); | 3401 | set_disk_ro(disk, true); |
3176 | 3402 | ||
3177 | disk->queue = q; | 3403 | disk->queue = q; |
3178 | disk->major = DRBD_MAJOR; | 3404 | disk->major = DRBD_MAJOR; |
@@ -3188,8 +3414,8 @@ struct drbd_conf *drbd_new_device(unsigned int minor) | |||
3188 | q->backing_dev_info.congested_fn = drbd_congested; | 3414 | q->backing_dev_info.congested_fn = drbd_congested; |
3189 | q->backing_dev_info.congested_data = mdev; | 3415 | q->backing_dev_info.congested_data = mdev; |
3190 | 3416 | ||
3191 | blk_queue_make_request(q, drbd_make_request_26); | 3417 | blk_queue_make_request(q, drbd_make_request); |
3192 | blk_queue_max_segment_size(q, DRBD_MAX_SEGMENT_SIZE); | 3418 | blk_queue_max_hw_sectors(q, DRBD_MAX_BIO_SIZE >> 9); |
3193 | blk_queue_bounce_limit(q, BLK_BOUNCE_ANY); | 3419 | blk_queue_bounce_limit(q, BLK_BOUNCE_ANY); |
3194 | blk_queue_merge_bvec(q, drbd_merge_bvec); | 3420 | blk_queue_merge_bvec(q, drbd_merge_bvec); |
3195 | q->queue_lock = &mdev->req_lock; | 3421 | q->queue_lock = &mdev->req_lock; |
@@ -3251,6 +3477,7 @@ void drbd_free_mdev(struct drbd_conf *mdev) | |||
3251 | put_disk(mdev->vdisk); | 3477 | put_disk(mdev->vdisk); |
3252 | blk_cleanup_queue(mdev->rq_queue); | 3478 | blk_cleanup_queue(mdev->rq_queue); |
3253 | free_cpumask_var(mdev->cpu_mask); | 3479 | free_cpumask_var(mdev->cpu_mask); |
3480 | drbd_free_tl_hash(mdev); | ||
3254 | kfree(mdev); | 3481 | kfree(mdev); |
3255 | } | 3482 | } |
3256 | 3483 | ||
@@ -3266,7 +3493,7 @@ int __init drbd_init(void) | |||
3266 | return -EINVAL; | 3493 | return -EINVAL; |
3267 | } | 3494 | } |
3268 | 3495 | ||
3269 | if (1 > minor_count || minor_count > 255) { | 3496 | if (minor_count < DRBD_MINOR_COUNT_MIN || minor_count > DRBD_MINOR_COUNT_MAX) { |
3270 | printk(KERN_ERR | 3497 | printk(KERN_ERR |
3271 | "drbd: invalid minor_count (%d)\n", minor_count); | 3498 | "drbd: invalid minor_count (%d)\n", minor_count); |
3272 | #ifdef MODULE | 3499 | #ifdef MODULE |
@@ -3448,7 +3675,7 @@ void drbd_md_sync(struct drbd_conf *mdev) | |||
3448 | if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) { | 3675 | if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) { |
3449 | /* this was a try anyways ... */ | 3676 | /* this was a try anyways ... */ |
3450 | dev_err(DEV, "meta data update failed!\n"); | 3677 | dev_err(DEV, "meta data update failed!\n"); |
3451 | drbd_chk_io_error(mdev, 1, TRUE); | 3678 | drbd_chk_io_error(mdev, 1, true); |
3452 | } | 3679 | } |
3453 | 3680 | ||
3454 | /* Update mdev->ldev->md.la_size_sect, | 3681 | /* Update mdev->ldev->md.la_size_sect, |
@@ -3464,7 +3691,7 @@ void drbd_md_sync(struct drbd_conf *mdev) | |||
3464 | * @mdev: DRBD device. | 3691 | * @mdev: DRBD device. |
3465 | * @bdev: Device from which the meta data should be read in. | 3692 | * @bdev: Device from which the meta data should be read in. |
3466 | * | 3693 | * |
3467 | * Return 0 (NO_ERROR) on success, and an enum drbd_ret_codes in case | 3694 | * Return 0 (NO_ERROR) on success, and an enum drbd_ret_code in case |
3468 | * something goes wrong. Currently only: ERR_IO_MD_DISK, ERR_MD_INVALID. | 3695 | * something goes wrong. Currently only: ERR_IO_MD_DISK, ERR_MD_INVALID. |
3469 | */ | 3696 | */ |
3470 | int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) | 3697 | int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) |
@@ -3534,28 +3761,6 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) | |||
3534 | return rv; | 3761 | return rv; |
3535 | } | 3762 | } |
3536 | 3763 | ||
3537 | static void debug_drbd_uuid(struct drbd_conf *mdev, enum drbd_uuid_index index) | ||
3538 | { | ||
3539 | static char *uuid_str[UI_EXTENDED_SIZE] = { | ||
3540 | [UI_CURRENT] = "CURRENT", | ||
3541 | [UI_BITMAP] = "BITMAP", | ||
3542 | [UI_HISTORY_START] = "HISTORY_START", | ||
3543 | [UI_HISTORY_END] = "HISTORY_END", | ||
3544 | [UI_SIZE] = "SIZE", | ||
3545 | [UI_FLAGS] = "FLAGS", | ||
3546 | }; | ||
3547 | |||
3548 | if (index >= UI_EXTENDED_SIZE) { | ||
3549 | dev_warn(DEV, " uuid_index >= EXTENDED_SIZE\n"); | ||
3550 | return; | ||
3551 | } | ||
3552 | |||
3553 | dynamic_dev_dbg(DEV, " uuid[%s] now %016llX\n", | ||
3554 | uuid_str[index], | ||
3555 | (unsigned long long)mdev->ldev->md.uuid[index]); | ||
3556 | } | ||
3557 | |||
3558 | |||
3559 | /** | 3764 | /** |
3560 | * drbd_md_mark_dirty() - Mark meta data super block as dirty | 3765 | * drbd_md_mark_dirty() - Mark meta data super block as dirty |
3561 | * @mdev: DRBD device. | 3766 | * @mdev: DRBD device. |
@@ -3585,10 +3790,8 @@ static void drbd_uuid_move_history(struct drbd_conf *mdev) __must_hold(local) | |||
3585 | { | 3790 | { |
3586 | int i; | 3791 | int i; |
3587 | 3792 | ||
3588 | for (i = UI_HISTORY_START; i < UI_HISTORY_END; i++) { | 3793 | for (i = UI_HISTORY_START; i < UI_HISTORY_END; i++) |
3589 | mdev->ldev->md.uuid[i+1] = mdev->ldev->md.uuid[i]; | 3794 | mdev->ldev->md.uuid[i+1] = mdev->ldev->md.uuid[i]; |
3590 | debug_drbd_uuid(mdev, i+1); | ||
3591 | } | ||
3592 | } | 3795 | } |
3593 | 3796 | ||
3594 | void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) | 3797 | void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) |
@@ -3603,7 +3806,6 @@ void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) | |||
3603 | } | 3806 | } |
3604 | 3807 | ||
3605 | mdev->ldev->md.uuid[idx] = val; | 3808 | mdev->ldev->md.uuid[idx] = val; |
3606 | debug_drbd_uuid(mdev, idx); | ||
3607 | drbd_md_mark_dirty(mdev); | 3809 | drbd_md_mark_dirty(mdev); |
3608 | } | 3810 | } |
3609 | 3811 | ||
@@ -3613,7 +3815,6 @@ void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) | |||
3613 | if (mdev->ldev->md.uuid[idx]) { | 3815 | if (mdev->ldev->md.uuid[idx]) { |
3614 | drbd_uuid_move_history(mdev); | 3816 | drbd_uuid_move_history(mdev); |
3615 | mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[idx]; | 3817 | mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[idx]; |
3616 | debug_drbd_uuid(mdev, UI_HISTORY_START); | ||
3617 | } | 3818 | } |
3618 | _drbd_uuid_set(mdev, idx, val); | 3819 | _drbd_uuid_set(mdev, idx, val); |
3619 | } | 3820 | } |
@@ -3628,14 +3829,16 @@ void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) | |||
3628 | void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local) | 3829 | void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local) |
3629 | { | 3830 | { |
3630 | u64 val; | 3831 | u64 val; |
3832 | unsigned long long bm_uuid = mdev->ldev->md.uuid[UI_BITMAP]; | ||
3833 | |||
3834 | if (bm_uuid) | ||
3835 | dev_warn(DEV, "bm UUID was already set: %llX\n", bm_uuid); | ||
3631 | 3836 | ||
3632 | dev_info(DEV, "Creating new current UUID\n"); | ||
3633 | D_ASSERT(mdev->ldev->md.uuid[UI_BITMAP] == 0); | ||
3634 | mdev->ldev->md.uuid[UI_BITMAP] = mdev->ldev->md.uuid[UI_CURRENT]; | 3837 | mdev->ldev->md.uuid[UI_BITMAP] = mdev->ldev->md.uuid[UI_CURRENT]; |
3635 | debug_drbd_uuid(mdev, UI_BITMAP); | ||
3636 | 3838 | ||
3637 | get_random_bytes(&val, sizeof(u64)); | 3839 | get_random_bytes(&val, sizeof(u64)); |
3638 | _drbd_uuid_set(mdev, UI_CURRENT, val); | 3840 | _drbd_uuid_set(mdev, UI_CURRENT, val); |
3841 | drbd_print_uuids(mdev, "new current UUID"); | ||
3639 | /* get it to stable storage _now_ */ | 3842 | /* get it to stable storage _now_ */ |
3640 | drbd_md_sync(mdev); | 3843 | drbd_md_sync(mdev); |
3641 | } | 3844 | } |
@@ -3649,16 +3852,12 @@ void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local) | |||
3649 | drbd_uuid_move_history(mdev); | 3852 | drbd_uuid_move_history(mdev); |
3650 | mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[UI_BITMAP]; | 3853 | mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[UI_BITMAP]; |
3651 | mdev->ldev->md.uuid[UI_BITMAP] = 0; | 3854 | mdev->ldev->md.uuid[UI_BITMAP] = 0; |
3652 | debug_drbd_uuid(mdev, UI_HISTORY_START); | ||
3653 | debug_drbd_uuid(mdev, UI_BITMAP); | ||
3654 | } else { | 3855 | } else { |
3655 | if (mdev->ldev->md.uuid[UI_BITMAP]) | 3856 | unsigned long long bm_uuid = mdev->ldev->md.uuid[UI_BITMAP]; |
3656 | dev_warn(DEV, "bm UUID already set"); | 3857 | if (bm_uuid) |
3657 | 3858 | dev_warn(DEV, "bm UUID was already set: %llX\n", bm_uuid); | |
3658 | mdev->ldev->md.uuid[UI_BITMAP] = val; | ||
3659 | mdev->ldev->md.uuid[UI_BITMAP] &= ~((u64)1); | ||
3660 | 3859 | ||
3661 | debug_drbd_uuid(mdev, UI_BITMAP); | 3860 | mdev->ldev->md.uuid[UI_BITMAP] = val & ~((u64)1); |
3662 | } | 3861 | } |
3663 | drbd_md_mark_dirty(mdev); | 3862 | drbd_md_mark_dirty(mdev); |
3664 | } | 3863 | } |
@@ -3714,15 +3913,19 @@ int drbd_bmio_clear_n_write(struct drbd_conf *mdev) | |||
3714 | static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused) | 3913 | static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused) |
3715 | { | 3914 | { |
3716 | struct bm_io_work *work = container_of(w, struct bm_io_work, w); | 3915 | struct bm_io_work *work = container_of(w, struct bm_io_work, w); |
3717 | int rv; | 3916 | int rv = -EIO; |
3718 | 3917 | ||
3719 | D_ASSERT(atomic_read(&mdev->ap_bio_cnt) == 0); | 3918 | D_ASSERT(atomic_read(&mdev->ap_bio_cnt) == 0); |
3720 | 3919 | ||
3721 | drbd_bm_lock(mdev, work->why); | 3920 | if (get_ldev(mdev)) { |
3722 | rv = work->io_fn(mdev); | 3921 | drbd_bm_lock(mdev, work->why, work->flags); |
3723 | drbd_bm_unlock(mdev); | 3922 | rv = work->io_fn(mdev); |
3923 | drbd_bm_unlock(mdev); | ||
3924 | put_ldev(mdev); | ||
3925 | } | ||
3724 | 3926 | ||
3725 | clear_bit(BITMAP_IO, &mdev->flags); | 3927 | clear_bit(BITMAP_IO, &mdev->flags); |
3928 | smp_mb__after_clear_bit(); | ||
3726 | wake_up(&mdev->misc_wait); | 3929 | wake_up(&mdev->misc_wait); |
3727 | 3930 | ||
3728 | if (work->done) | 3931 | if (work->done) |
@@ -3730,6 +3933,7 @@ static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused) | |||
3730 | 3933 | ||
3731 | clear_bit(BITMAP_IO_QUEUED, &mdev->flags); | 3934 | clear_bit(BITMAP_IO_QUEUED, &mdev->flags); |
3732 | work->why = NULL; | 3935 | work->why = NULL; |
3936 | work->flags = 0; | ||
3733 | 3937 | ||
3734 | return 1; | 3938 | return 1; |
3735 | } | 3939 | } |
@@ -3784,7 +3988,7 @@ void drbd_go_diskless(struct drbd_conf *mdev) | |||
3784 | void drbd_queue_bitmap_io(struct drbd_conf *mdev, | 3988 | void drbd_queue_bitmap_io(struct drbd_conf *mdev, |
3785 | int (*io_fn)(struct drbd_conf *), | 3989 | int (*io_fn)(struct drbd_conf *), |
3786 | void (*done)(struct drbd_conf *, int), | 3990 | void (*done)(struct drbd_conf *, int), |
3787 | char *why) | 3991 | char *why, enum bm_flag flags) |
3788 | { | 3992 | { |
3789 | D_ASSERT(current == mdev->worker.task); | 3993 | D_ASSERT(current == mdev->worker.task); |
3790 | 3994 | ||
@@ -3798,15 +4002,15 @@ void drbd_queue_bitmap_io(struct drbd_conf *mdev, | |||
3798 | mdev->bm_io_work.io_fn = io_fn; | 4002 | mdev->bm_io_work.io_fn = io_fn; |
3799 | mdev->bm_io_work.done = done; | 4003 | mdev->bm_io_work.done = done; |
3800 | mdev->bm_io_work.why = why; | 4004 | mdev->bm_io_work.why = why; |
4005 | mdev->bm_io_work.flags = flags; | ||
3801 | 4006 | ||
4007 | spin_lock_irq(&mdev->req_lock); | ||
3802 | set_bit(BITMAP_IO, &mdev->flags); | 4008 | set_bit(BITMAP_IO, &mdev->flags); |
3803 | if (atomic_read(&mdev->ap_bio_cnt) == 0) { | 4009 | if (atomic_read(&mdev->ap_bio_cnt) == 0) { |
3804 | if (list_empty(&mdev->bm_io_work.w.list)) { | 4010 | if (!test_and_set_bit(BITMAP_IO_QUEUED, &mdev->flags)) |
3805 | set_bit(BITMAP_IO_QUEUED, &mdev->flags); | ||
3806 | drbd_queue_work(&mdev->data.work, &mdev->bm_io_work.w); | 4011 | drbd_queue_work(&mdev->data.work, &mdev->bm_io_work.w); |
3807 | } else | ||
3808 | dev_err(DEV, "FIXME avoided double queuing bm_io_work\n"); | ||
3809 | } | 4012 | } |
4013 | spin_unlock_irq(&mdev->req_lock); | ||
3810 | } | 4014 | } |
3811 | 4015 | ||
3812 | /** | 4016 | /** |
@@ -3818,19 +4022,22 @@ void drbd_queue_bitmap_io(struct drbd_conf *mdev, | |||
3818 | * freezes application IO while that the actual IO operations runs. This | 4022 | * freezes application IO while that the actual IO operations runs. This |
3819 | * functions MAY NOT be called from worker context. | 4023 | * functions MAY NOT be called from worker context. |
3820 | */ | 4024 | */ |
3821 | int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why) | 4025 | int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), |
4026 | char *why, enum bm_flag flags) | ||
3822 | { | 4027 | { |
3823 | int rv; | 4028 | int rv; |
3824 | 4029 | ||
3825 | D_ASSERT(current != mdev->worker.task); | 4030 | D_ASSERT(current != mdev->worker.task); |
3826 | 4031 | ||
3827 | drbd_suspend_io(mdev); | 4032 | if ((flags & BM_LOCKED_SET_ALLOWED) == 0) |
4033 | drbd_suspend_io(mdev); | ||
3828 | 4034 | ||
3829 | drbd_bm_lock(mdev, why); | 4035 | drbd_bm_lock(mdev, why, flags); |
3830 | rv = io_fn(mdev); | 4036 | rv = io_fn(mdev); |
3831 | drbd_bm_unlock(mdev); | 4037 | drbd_bm_unlock(mdev); |
3832 | 4038 | ||
3833 | drbd_resume_io(mdev); | 4039 | if ((flags & BM_LOCKED_SET_ALLOWED) == 0) |
4040 | drbd_resume_io(mdev); | ||
3834 | 4041 | ||
3835 | return rv; | 4042 | return rv; |
3836 | } | 4043 | } |
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index fe81c851ca88..03b29f78a37d 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c | |||
@@ -288,10 +288,11 @@ void drbd_try_outdate_peer_async(struct drbd_conf *mdev) | |||
288 | dev_err(DEV, "out of mem, failed to invoke fence-peer helper\n"); | 288 | dev_err(DEV, "out of mem, failed to invoke fence-peer helper\n"); |
289 | } | 289 | } |
290 | 290 | ||
291 | int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) | 291 | enum drbd_state_rv |
292 | drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) | ||
292 | { | 293 | { |
293 | const int max_tries = 4; | 294 | const int max_tries = 4; |
294 | int r = 0; | 295 | enum drbd_state_rv rv = SS_UNKNOWN_ERROR; |
295 | int try = 0; | 296 | int try = 0; |
296 | int forced = 0; | 297 | int forced = 0; |
297 | union drbd_state mask, val; | 298 | union drbd_state mask, val; |
@@ -306,17 +307,17 @@ int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) | |||
306 | val.i = 0; val.role = new_role; | 307 | val.i = 0; val.role = new_role; |
307 | 308 | ||
308 | while (try++ < max_tries) { | 309 | while (try++ < max_tries) { |
309 | r = _drbd_request_state(mdev, mask, val, CS_WAIT_COMPLETE); | 310 | rv = _drbd_request_state(mdev, mask, val, CS_WAIT_COMPLETE); |
310 | 311 | ||
311 | /* in case we first succeeded to outdate, | 312 | /* in case we first succeeded to outdate, |
312 | * but now suddenly could establish a connection */ | 313 | * but now suddenly could establish a connection */ |
313 | if (r == SS_CW_FAILED_BY_PEER && mask.pdsk != 0) { | 314 | if (rv == SS_CW_FAILED_BY_PEER && mask.pdsk != 0) { |
314 | val.pdsk = 0; | 315 | val.pdsk = 0; |
315 | mask.pdsk = 0; | 316 | mask.pdsk = 0; |
316 | continue; | 317 | continue; |
317 | } | 318 | } |
318 | 319 | ||
319 | if (r == SS_NO_UP_TO_DATE_DISK && force && | 320 | if (rv == SS_NO_UP_TO_DATE_DISK && force && |
320 | (mdev->state.disk < D_UP_TO_DATE && | 321 | (mdev->state.disk < D_UP_TO_DATE && |
321 | mdev->state.disk >= D_INCONSISTENT)) { | 322 | mdev->state.disk >= D_INCONSISTENT)) { |
322 | mask.disk = D_MASK; | 323 | mask.disk = D_MASK; |
@@ -325,7 +326,7 @@ int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) | |||
325 | continue; | 326 | continue; |
326 | } | 327 | } |
327 | 328 | ||
328 | if (r == SS_NO_UP_TO_DATE_DISK && | 329 | if (rv == SS_NO_UP_TO_DATE_DISK && |
329 | mdev->state.disk == D_CONSISTENT && mask.pdsk == 0) { | 330 | mdev->state.disk == D_CONSISTENT && mask.pdsk == 0) { |
330 | D_ASSERT(mdev->state.pdsk == D_UNKNOWN); | 331 | D_ASSERT(mdev->state.pdsk == D_UNKNOWN); |
331 | nps = drbd_try_outdate_peer(mdev); | 332 | nps = drbd_try_outdate_peer(mdev); |
@@ -341,9 +342,9 @@ int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) | |||
341 | continue; | 342 | continue; |
342 | } | 343 | } |
343 | 344 | ||
344 | if (r == SS_NOTHING_TO_DO) | 345 | if (rv == SS_NOTHING_TO_DO) |
345 | goto fail; | 346 | goto fail; |
346 | if (r == SS_PRIMARY_NOP && mask.pdsk == 0) { | 347 | if (rv == SS_PRIMARY_NOP && mask.pdsk == 0) { |
347 | nps = drbd_try_outdate_peer(mdev); | 348 | nps = drbd_try_outdate_peer(mdev); |
348 | 349 | ||
349 | if (force && nps > D_OUTDATED) { | 350 | if (force && nps > D_OUTDATED) { |
@@ -356,25 +357,24 @@ int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) | |||
356 | 357 | ||
357 | continue; | 358 | continue; |
358 | } | 359 | } |
359 | if (r == SS_TWO_PRIMARIES) { | 360 | if (rv == SS_TWO_PRIMARIES) { |
360 | /* Maybe the peer is detected as dead very soon... | 361 | /* Maybe the peer is detected as dead very soon... |
361 | retry at most once more in this case. */ | 362 | retry at most once more in this case. */ |
362 | __set_current_state(TASK_INTERRUPTIBLE); | 363 | schedule_timeout_interruptible((mdev->net_conf->ping_timeo+1)*HZ/10); |
363 | schedule_timeout((mdev->net_conf->ping_timeo+1)*HZ/10); | ||
364 | if (try < max_tries) | 364 | if (try < max_tries) |
365 | try = max_tries - 1; | 365 | try = max_tries - 1; |
366 | continue; | 366 | continue; |
367 | } | 367 | } |
368 | if (r < SS_SUCCESS) { | 368 | if (rv < SS_SUCCESS) { |
369 | r = _drbd_request_state(mdev, mask, val, | 369 | rv = _drbd_request_state(mdev, mask, val, |
370 | CS_VERBOSE + CS_WAIT_COMPLETE); | 370 | CS_VERBOSE + CS_WAIT_COMPLETE); |
371 | if (r < SS_SUCCESS) | 371 | if (rv < SS_SUCCESS) |
372 | goto fail; | 372 | goto fail; |
373 | } | 373 | } |
374 | break; | 374 | break; |
375 | } | 375 | } |
376 | 376 | ||
377 | if (r < SS_SUCCESS) | 377 | if (rv < SS_SUCCESS) |
378 | goto fail; | 378 | goto fail; |
379 | 379 | ||
380 | if (forced) | 380 | if (forced) |
@@ -384,7 +384,7 @@ int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) | |||
384 | wait_event(mdev->misc_wait, atomic_read(&mdev->ap_pending_cnt) == 0); | 384 | wait_event(mdev->misc_wait, atomic_read(&mdev->ap_pending_cnt) == 0); |
385 | 385 | ||
386 | if (new_role == R_SECONDARY) { | 386 | if (new_role == R_SECONDARY) { |
387 | set_disk_ro(mdev->vdisk, TRUE); | 387 | set_disk_ro(mdev->vdisk, true); |
388 | if (get_ldev(mdev)) { | 388 | if (get_ldev(mdev)) { |
389 | mdev->ldev->md.uuid[UI_CURRENT] &= ~(u64)1; | 389 | mdev->ldev->md.uuid[UI_CURRENT] &= ~(u64)1; |
390 | put_ldev(mdev); | 390 | put_ldev(mdev); |
@@ -394,7 +394,7 @@ int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) | |||
394 | mdev->net_conf->want_lose = 0; | 394 | mdev->net_conf->want_lose = 0; |
395 | put_net_conf(mdev); | 395 | put_net_conf(mdev); |
396 | } | 396 | } |
397 | set_disk_ro(mdev->vdisk, FALSE); | 397 | set_disk_ro(mdev->vdisk, false); |
398 | if (get_ldev(mdev)) { | 398 | if (get_ldev(mdev)) { |
399 | if (((mdev->state.conn < C_CONNECTED || | 399 | if (((mdev->state.conn < C_CONNECTED || |
400 | mdev->state.pdsk <= D_FAILED) | 400 | mdev->state.pdsk <= D_FAILED) |
@@ -406,10 +406,8 @@ int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) | |||
406 | } | 406 | } |
407 | } | 407 | } |
408 | 408 | ||
409 | if ((new_role == R_SECONDARY) && get_ldev(mdev)) { | 409 | /* writeout of activity log covered areas of the bitmap |
410 | drbd_al_to_on_disk_bm(mdev); | 410 | * to stable storage done in after state change already */ |
411 | put_ldev(mdev); | ||
412 | } | ||
413 | 411 | ||
414 | if (mdev->state.conn >= C_WF_REPORT_PARAMS) { | 412 | if (mdev->state.conn >= C_WF_REPORT_PARAMS) { |
415 | /* if this was forced, we should consider sync */ | 413 | /* if this was forced, we should consider sync */ |
@@ -423,7 +421,7 @@ int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) | |||
423 | kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE); | 421 | kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE); |
424 | fail: | 422 | fail: |
425 | mutex_unlock(&mdev->state_mutex); | 423 | mutex_unlock(&mdev->state_mutex); |
426 | return r; | 424 | return rv; |
427 | } | 425 | } |
428 | 426 | ||
429 | static struct drbd_conf *ensure_mdev(int minor, int create) | 427 | static struct drbd_conf *ensure_mdev(int minor, int create) |
@@ -528,17 +526,19 @@ static void drbd_md_set_sector_offsets(struct drbd_conf *mdev, | |||
528 | } | 526 | } |
529 | } | 527 | } |
530 | 528 | ||
529 | /* input size is expected to be in KB */ | ||
531 | char *ppsize(char *buf, unsigned long long size) | 530 | char *ppsize(char *buf, unsigned long long size) |
532 | { | 531 | { |
533 | /* Needs 9 bytes at max. */ | 532 | /* Needs 9 bytes at max including trailing NUL: |
533 | * -1ULL ==> "16384 EB" */ | ||
534 | static char units[] = { 'K', 'M', 'G', 'T', 'P', 'E' }; | 534 | static char units[] = { 'K', 'M', 'G', 'T', 'P', 'E' }; |
535 | int base = 0; | 535 | int base = 0; |
536 | while (size >= 10000) { | 536 | while (size >= 10000 && base < sizeof(units)-1) { |
537 | /* shift + round */ | 537 | /* shift + round */ |
538 | size = (size >> 10) + !!(size & (1<<9)); | 538 | size = (size >> 10) + !!(size & (1<<9)); |
539 | base++; | 539 | base++; |
540 | } | 540 | } |
541 | sprintf(buf, "%lu %cB", (long)size, units[base]); | 541 | sprintf(buf, "%u %cB", (unsigned)size, units[base]); |
542 | 542 | ||
543 | return buf; | 543 | return buf; |
544 | } | 544 | } |
@@ -642,11 +642,19 @@ enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *mdev, enum dds_ | |||
642 | || prev_size != mdev->ldev->md.md_size_sect; | 642 | || prev_size != mdev->ldev->md.md_size_sect; |
643 | 643 | ||
644 | if (la_size_changed || md_moved) { | 644 | if (la_size_changed || md_moved) { |
645 | int err; | ||
646 | |||
645 | drbd_al_shrink(mdev); /* All extents inactive. */ | 647 | drbd_al_shrink(mdev); /* All extents inactive. */ |
646 | dev_info(DEV, "Writing the whole bitmap, %s\n", | 648 | dev_info(DEV, "Writing the whole bitmap, %s\n", |
647 | la_size_changed && md_moved ? "size changed and md moved" : | 649 | la_size_changed && md_moved ? "size changed and md moved" : |
648 | la_size_changed ? "size changed" : "md moved"); | 650 | la_size_changed ? "size changed" : "md moved"); |
649 | rv = drbd_bitmap_io(mdev, &drbd_bm_write, "size changed"); /* does drbd_resume_io() ! */ | 651 | /* next line implicitly does drbd_suspend_io()+drbd_resume_io() */ |
652 | err = drbd_bitmap_io(mdev, &drbd_bm_write, | ||
653 | "size changed", BM_LOCKED_MASK); | ||
654 | if (err) { | ||
655 | rv = dev_size_error; | ||
656 | goto out; | ||
657 | } | ||
650 | drbd_md_mark_dirty(mdev); | 658 | drbd_md_mark_dirty(mdev); |
651 | } | 659 | } |
652 | 660 | ||
@@ -765,22 +773,21 @@ static int drbd_check_al_size(struct drbd_conf *mdev) | |||
765 | return 0; | 773 | return 0; |
766 | } | 774 | } |
767 | 775 | ||
768 | void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_seg_s) __must_hold(local) | 776 | void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_bio_size) __must_hold(local) |
769 | { | 777 | { |
770 | struct request_queue * const q = mdev->rq_queue; | 778 | struct request_queue * const q = mdev->rq_queue; |
771 | struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue; | 779 | struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue; |
772 | int max_segments = mdev->ldev->dc.max_bio_bvecs; | 780 | int max_segments = mdev->ldev->dc.max_bio_bvecs; |
781 | int max_hw_sectors = min(queue_max_hw_sectors(b), max_bio_size >> 9); | ||
773 | 782 | ||
774 | max_seg_s = min(queue_max_sectors(b) * queue_logical_block_size(b), max_seg_s); | ||
775 | |||
776 | blk_queue_max_hw_sectors(q, max_seg_s >> 9); | ||
777 | blk_queue_max_segments(q, max_segments ? max_segments : BLK_MAX_SEGMENTS); | ||
778 | blk_queue_max_segment_size(q, max_seg_s); | ||
779 | blk_queue_logical_block_size(q, 512); | 783 | blk_queue_logical_block_size(q, 512); |
780 | blk_queue_segment_boundary(q, PAGE_SIZE-1); | 784 | blk_queue_max_hw_sectors(q, max_hw_sectors); |
781 | blk_stack_limits(&q->limits, &b->limits, 0); | 785 | /* This is the workaround for "bio would need to, but cannot, be split" */ |
786 | blk_queue_max_segments(q, max_segments ? max_segments : BLK_MAX_SEGMENTS); | ||
787 | blk_queue_segment_boundary(q, PAGE_CACHE_SIZE-1); | ||
788 | blk_queue_stack_limits(q, b); | ||
782 | 789 | ||
783 | dev_info(DEV, "max_segment_size ( = BIO size ) = %u\n", queue_max_segment_size(q)); | 790 | dev_info(DEV, "max BIO size = %u\n", queue_max_hw_sectors(q) << 9); |
784 | 791 | ||
785 | if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) { | 792 | if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) { |
786 | dev_info(DEV, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n", | 793 | dev_info(DEV, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n", |
@@ -850,7 +857,7 @@ static void drbd_suspend_al(struct drbd_conf *mdev) | |||
850 | static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, | 857 | static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, |
851 | struct drbd_nl_cfg_reply *reply) | 858 | struct drbd_nl_cfg_reply *reply) |
852 | { | 859 | { |
853 | enum drbd_ret_codes retcode; | 860 | enum drbd_ret_code retcode; |
854 | enum determine_dev_size dd; | 861 | enum determine_dev_size dd; |
855 | sector_t max_possible_sectors; | 862 | sector_t max_possible_sectors; |
856 | sector_t min_md_device_sectors; | 863 | sector_t min_md_device_sectors; |
@@ -858,8 +865,8 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp | |||
858 | struct block_device *bdev; | 865 | struct block_device *bdev; |
859 | struct lru_cache *resync_lru = NULL; | 866 | struct lru_cache *resync_lru = NULL; |
860 | union drbd_state ns, os; | 867 | union drbd_state ns, os; |
861 | unsigned int max_seg_s; | 868 | unsigned int max_bio_size; |
862 | int rv; | 869 | enum drbd_state_rv rv; |
863 | int cp_discovered = 0; | 870 | int cp_discovered = 0; |
864 | int logical_block_size; | 871 | int logical_block_size; |
865 | 872 | ||
@@ -1005,9 +1012,10 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp | |||
1005 | /* and for any other previously queued work */ | 1012 | /* and for any other previously queued work */ |
1006 | drbd_flush_workqueue(mdev); | 1013 | drbd_flush_workqueue(mdev); |
1007 | 1014 | ||
1008 | retcode = _drbd_request_state(mdev, NS(disk, D_ATTACHING), CS_VERBOSE); | 1015 | rv = _drbd_request_state(mdev, NS(disk, D_ATTACHING), CS_VERBOSE); |
1016 | retcode = rv; /* FIXME: Type mismatch. */ | ||
1009 | drbd_resume_io(mdev); | 1017 | drbd_resume_io(mdev); |
1010 | if (retcode < SS_SUCCESS) | 1018 | if (rv < SS_SUCCESS) |
1011 | goto fail; | 1019 | goto fail; |
1012 | 1020 | ||
1013 | if (!get_ldev_if_state(mdev, D_ATTACHING)) | 1021 | if (!get_ldev_if_state(mdev, D_ATTACHING)) |
@@ -1109,20 +1117,20 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp | |||
1109 | mdev->read_cnt = 0; | 1117 | mdev->read_cnt = 0; |
1110 | mdev->writ_cnt = 0; | 1118 | mdev->writ_cnt = 0; |
1111 | 1119 | ||
1112 | max_seg_s = DRBD_MAX_SEGMENT_SIZE; | 1120 | max_bio_size = DRBD_MAX_BIO_SIZE; |
1113 | if (mdev->state.conn == C_CONNECTED) { | 1121 | if (mdev->state.conn == C_CONNECTED) { |
1114 | /* We are Primary, Connected, and now attach a new local | 1122 | /* We are Primary, Connected, and now attach a new local |
1115 | * backing store. We must not increase the user visible maximum | 1123 | * backing store. We must not increase the user visible maximum |
1116 | * bio size on this device to something the peer may not be | 1124 | * bio size on this device to something the peer may not be |
1117 | * able to handle. */ | 1125 | * able to handle. */ |
1118 | if (mdev->agreed_pro_version < 94) | 1126 | if (mdev->agreed_pro_version < 94) |
1119 | max_seg_s = queue_max_segment_size(mdev->rq_queue); | 1127 | max_bio_size = queue_max_hw_sectors(mdev->rq_queue) << 9; |
1120 | else if (mdev->agreed_pro_version == 94) | 1128 | else if (mdev->agreed_pro_version == 94) |
1121 | max_seg_s = DRBD_MAX_SIZE_H80_PACKET; | 1129 | max_bio_size = DRBD_MAX_SIZE_H80_PACKET; |
1122 | /* else: drbd 8.3.9 and later, stay with default */ | 1130 | /* else: drbd 8.3.9 and later, stay with default */ |
1123 | } | 1131 | } |
1124 | 1132 | ||
1125 | drbd_setup_queue_param(mdev, max_seg_s); | 1133 | drbd_setup_queue_param(mdev, max_bio_size); |
1126 | 1134 | ||
1127 | /* If I am currently not R_PRIMARY, | 1135 | /* If I am currently not R_PRIMARY, |
1128 | * but meta data primary indicator is set, | 1136 | * but meta data primary indicator is set, |
@@ -1154,12 +1162,14 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp | |||
1154 | if (drbd_md_test_flag(mdev->ldev, MDF_FULL_SYNC)) { | 1162 | if (drbd_md_test_flag(mdev->ldev, MDF_FULL_SYNC)) { |
1155 | dev_info(DEV, "Assuming that all blocks are out of sync " | 1163 | dev_info(DEV, "Assuming that all blocks are out of sync " |
1156 | "(aka FullSync)\n"); | 1164 | "(aka FullSync)\n"); |
1157 | if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write, "set_n_write from attaching")) { | 1165 | if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write, |
1166 | "set_n_write from attaching", BM_LOCKED_MASK)) { | ||
1158 | retcode = ERR_IO_MD_DISK; | 1167 | retcode = ERR_IO_MD_DISK; |
1159 | goto force_diskless_dec; | 1168 | goto force_diskless_dec; |
1160 | } | 1169 | } |
1161 | } else { | 1170 | } else { |
1162 | if (drbd_bitmap_io(mdev, &drbd_bm_read, "read from attaching") < 0) { | 1171 | if (drbd_bitmap_io(mdev, &drbd_bm_read, |
1172 | "read from attaching", BM_LOCKED_MASK) < 0) { | ||
1163 | retcode = ERR_IO_MD_DISK; | 1173 | retcode = ERR_IO_MD_DISK; |
1164 | goto force_diskless_dec; | 1174 | goto force_diskless_dec; |
1165 | } | 1175 | } |
@@ -1167,7 +1177,11 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp | |||
1167 | 1177 | ||
1168 | if (cp_discovered) { | 1178 | if (cp_discovered) { |
1169 | drbd_al_apply_to_bm(mdev); | 1179 | drbd_al_apply_to_bm(mdev); |
1170 | drbd_al_to_on_disk_bm(mdev); | 1180 | if (drbd_bitmap_io(mdev, &drbd_bm_write, |
1181 | "crashed primary apply AL", BM_LOCKED_MASK)) { | ||
1182 | retcode = ERR_IO_MD_DISK; | ||
1183 | goto force_diskless_dec; | ||
1184 | } | ||
1171 | } | 1185 | } |
1172 | 1186 | ||
1173 | if (_drbd_bm_total_weight(mdev) == drbd_bm_bits(mdev)) | 1187 | if (_drbd_bm_total_weight(mdev) == drbd_bm_bits(mdev)) |
@@ -1279,7 +1293,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, | |||
1279 | struct drbd_nl_cfg_reply *reply) | 1293 | struct drbd_nl_cfg_reply *reply) |
1280 | { | 1294 | { |
1281 | int i, ns; | 1295 | int i, ns; |
1282 | enum drbd_ret_codes retcode; | 1296 | enum drbd_ret_code retcode; |
1283 | struct net_conf *new_conf = NULL; | 1297 | struct net_conf *new_conf = NULL; |
1284 | struct crypto_hash *tfm = NULL; | 1298 | struct crypto_hash *tfm = NULL; |
1285 | struct crypto_hash *integrity_w_tfm = NULL; | 1299 | struct crypto_hash *integrity_w_tfm = NULL; |
@@ -1324,6 +1338,8 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, | |||
1324 | new_conf->wire_protocol = DRBD_PROT_C; | 1338 | new_conf->wire_protocol = DRBD_PROT_C; |
1325 | new_conf->ping_timeo = DRBD_PING_TIMEO_DEF; | 1339 | new_conf->ping_timeo = DRBD_PING_TIMEO_DEF; |
1326 | new_conf->rr_conflict = DRBD_RR_CONFLICT_DEF; | 1340 | new_conf->rr_conflict = DRBD_RR_CONFLICT_DEF; |
1341 | new_conf->on_congestion = DRBD_ON_CONGESTION_DEF; | ||
1342 | new_conf->cong_extents = DRBD_CONG_EXTENTS_DEF; | ||
1327 | 1343 | ||
1328 | if (!net_conf_from_tags(mdev, nlp->tag_list, new_conf)) { | 1344 | if (!net_conf_from_tags(mdev, nlp->tag_list, new_conf)) { |
1329 | retcode = ERR_MANDATORY_TAG; | 1345 | retcode = ERR_MANDATORY_TAG; |
@@ -1345,6 +1361,11 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, | |||
1345 | } | 1361 | } |
1346 | } | 1362 | } |
1347 | 1363 | ||
1364 | if (new_conf->on_congestion != OC_BLOCK && new_conf->wire_protocol != DRBD_PROT_A) { | ||
1365 | retcode = ERR_CONG_NOT_PROTO_A; | ||
1366 | goto fail; | ||
1367 | } | ||
1368 | |||
1348 | if (mdev->state.role == R_PRIMARY && new_conf->want_lose) { | 1369 | if (mdev->state.role == R_PRIMARY && new_conf->want_lose) { |
1349 | retcode = ERR_DISCARD; | 1370 | retcode = ERR_DISCARD; |
1350 | goto fail; | 1371 | goto fail; |
@@ -1525,6 +1546,21 @@ static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl | |||
1525 | struct drbd_nl_cfg_reply *reply) | 1546 | struct drbd_nl_cfg_reply *reply) |
1526 | { | 1547 | { |
1527 | int retcode; | 1548 | int retcode; |
1549 | struct disconnect dc; | ||
1550 | |||
1551 | memset(&dc, 0, sizeof(struct disconnect)); | ||
1552 | if (!disconnect_from_tags(mdev, nlp->tag_list, &dc)) { | ||
1553 | retcode = ERR_MANDATORY_TAG; | ||
1554 | goto fail; | ||
1555 | } | ||
1556 | |||
1557 | if (dc.force) { | ||
1558 | spin_lock_irq(&mdev->req_lock); | ||
1559 | if (mdev->state.conn >= C_WF_CONNECTION) | ||
1560 | _drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), CS_HARD, NULL); | ||
1561 | spin_unlock_irq(&mdev->req_lock); | ||
1562 | goto done; | ||
1563 | } | ||
1528 | 1564 | ||
1529 | retcode = _drbd_request_state(mdev, NS(conn, C_DISCONNECTING), CS_ORDERED); | 1565 | retcode = _drbd_request_state(mdev, NS(conn, C_DISCONNECTING), CS_ORDERED); |
1530 | 1566 | ||
@@ -1842,6 +1878,10 @@ static int drbd_nl_invalidate(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl | |||
1842 | { | 1878 | { |
1843 | int retcode; | 1879 | int retcode; |
1844 | 1880 | ||
1881 | /* If there is still bitmap IO pending, probably because of a previous | ||
1882 | * resync just being finished, wait for it before requesting a new resync. */ | ||
1883 | wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags)); | ||
1884 | |||
1845 | retcode = _drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_T), CS_ORDERED); | 1885 | retcode = _drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_T), CS_ORDERED); |
1846 | 1886 | ||
1847 | if (retcode < SS_SUCCESS && retcode != SS_NEED_CONNECTION) | 1887 | if (retcode < SS_SUCCESS && retcode != SS_NEED_CONNECTION) |
@@ -1877,6 +1917,10 @@ static int drbd_nl_invalidate_peer(struct drbd_conf *mdev, struct drbd_nl_cfg_re | |||
1877 | { | 1917 | { |
1878 | int retcode; | 1918 | int retcode; |
1879 | 1919 | ||
1920 | /* If there is still bitmap IO pending, probably because of a previous | ||
1921 | * resync just being finished, wait for it before requesting a new resync. */ | ||
1922 | wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags)); | ||
1923 | |||
1880 | retcode = _drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_S), CS_ORDERED); | 1924 | retcode = _drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_S), CS_ORDERED); |
1881 | 1925 | ||
1882 | if (retcode < SS_SUCCESS) { | 1926 | if (retcode < SS_SUCCESS) { |
@@ -1885,9 +1929,9 @@ static int drbd_nl_invalidate_peer(struct drbd_conf *mdev, struct drbd_nl_cfg_re | |||
1885 | into a full resync. */ | 1929 | into a full resync. */ |
1886 | retcode = drbd_request_state(mdev, NS(pdsk, D_INCONSISTENT)); | 1930 | retcode = drbd_request_state(mdev, NS(pdsk, D_INCONSISTENT)); |
1887 | if (retcode >= SS_SUCCESS) { | 1931 | if (retcode >= SS_SUCCESS) { |
1888 | /* open coded drbd_bitmap_io() */ | ||
1889 | if (drbd_bitmap_io(mdev, &drbd_bmio_set_susp_al, | 1932 | if (drbd_bitmap_io(mdev, &drbd_bmio_set_susp_al, |
1890 | "set_n_write from invalidate_peer")) | 1933 | "set_n_write from invalidate_peer", |
1934 | BM_LOCKED_SET_ALLOWED)) | ||
1891 | retcode = ERR_IO_MD_DISK; | 1935 | retcode = ERR_IO_MD_DISK; |
1892 | } | 1936 | } |
1893 | } else | 1937 | } else |
@@ -1914,9 +1958,17 @@ static int drbd_nl_resume_sync(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n | |||
1914 | struct drbd_nl_cfg_reply *reply) | 1958 | struct drbd_nl_cfg_reply *reply) |
1915 | { | 1959 | { |
1916 | int retcode = NO_ERROR; | 1960 | int retcode = NO_ERROR; |
1961 | union drbd_state s; | ||
1917 | 1962 | ||
1918 | if (drbd_request_state(mdev, NS(user_isp, 0)) == SS_NOTHING_TO_DO) | 1963 | if (drbd_request_state(mdev, NS(user_isp, 0)) == SS_NOTHING_TO_DO) { |
1919 | retcode = ERR_PAUSE_IS_CLEAR; | 1964 | s = mdev->state; |
1965 | if (s.conn == C_PAUSED_SYNC_S || s.conn == C_PAUSED_SYNC_T) { | ||
1966 | retcode = s.aftr_isp ? ERR_PIC_AFTER_DEP : | ||
1967 | s.peer_isp ? ERR_PIC_PEER_DEP : ERR_PAUSE_IS_CLEAR; | ||
1968 | } else { | ||
1969 | retcode = ERR_PAUSE_IS_CLEAR; | ||
1970 | } | ||
1971 | } | ||
1920 | 1972 | ||
1921 | reply->ret_code = retcode; | 1973 | reply->ret_code = retcode; |
1922 | return 0; | 1974 | return 0; |
@@ -2054,6 +2106,11 @@ static int drbd_nl_start_ov(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, | |||
2054 | reply->ret_code = ERR_MANDATORY_TAG; | 2106 | reply->ret_code = ERR_MANDATORY_TAG; |
2055 | return 0; | 2107 | return 0; |
2056 | } | 2108 | } |
2109 | |||
2110 | /* If there is still bitmap IO pending, e.g. previous resync or verify | ||
2111 | * just being finished, wait for it before requesting a new resync. */ | ||
2112 | wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags)); | ||
2113 | |||
2057 | /* w_make_ov_request expects position to be aligned */ | 2114 | /* w_make_ov_request expects position to be aligned */ |
2058 | mdev->ov_start_sector = args.start_sector & ~BM_SECT_PER_BIT; | 2115 | mdev->ov_start_sector = args.start_sector & ~BM_SECT_PER_BIT; |
2059 | reply->ret_code = drbd_request_state(mdev,NS(conn,C_VERIFY_S)); | 2116 | reply->ret_code = drbd_request_state(mdev,NS(conn,C_VERIFY_S)); |
@@ -2097,7 +2154,8 @@ static int drbd_nl_new_c_uuid(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl | |||
2097 | drbd_uuid_new_current(mdev); /* New current, previous to UI_BITMAP */ | 2154 | drbd_uuid_new_current(mdev); /* New current, previous to UI_BITMAP */ |
2098 | 2155 | ||
2099 | if (args.clear_bm) { | 2156 | if (args.clear_bm) { |
2100 | err = drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write, "clear_n_write from new_c_uuid"); | 2157 | err = drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write, |
2158 | "clear_n_write from new_c_uuid", BM_LOCKED_MASK); | ||
2101 | if (err) { | 2159 | if (err) { |
2102 | dev_err(DEV, "Writing bitmap failed with %d\n",err); | 2160 | dev_err(DEV, "Writing bitmap failed with %d\n",err); |
2103 | retcode = ERR_IO_MD_DISK; | 2161 | retcode = ERR_IO_MD_DISK; |
@@ -2105,6 +2163,7 @@ static int drbd_nl_new_c_uuid(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl | |||
2105 | if (skip_initial_sync) { | 2163 | if (skip_initial_sync) { |
2106 | drbd_send_uuids_skip_initial_sync(mdev); | 2164 | drbd_send_uuids_skip_initial_sync(mdev); |
2107 | _drbd_uuid_set(mdev, UI_BITMAP, 0); | 2165 | _drbd_uuid_set(mdev, UI_BITMAP, 0); |
2166 | drbd_print_uuids(mdev, "cleared bitmap UUID"); | ||
2108 | spin_lock_irq(&mdev->req_lock); | 2167 | spin_lock_irq(&mdev->req_lock); |
2109 | _drbd_set_state(_NS2(mdev, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE), | 2168 | _drbd_set_state(_NS2(mdev, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE), |
2110 | CS_VERBOSE, NULL); | 2169 | CS_VERBOSE, NULL); |
@@ -2189,7 +2248,8 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms | |||
2189 | goto fail; | 2248 | goto fail; |
2190 | } | 2249 | } |
2191 | 2250 | ||
2192 | if (nlp->packet_type >= P_nl_after_last_packet) { | 2251 | if (nlp->packet_type >= P_nl_after_last_packet || |
2252 | nlp->packet_type == P_return_code_only) { | ||
2193 | retcode = ERR_PACKET_NR; | 2253 | retcode = ERR_PACKET_NR; |
2194 | goto fail; | 2254 | goto fail; |
2195 | } | 2255 | } |
@@ -2205,7 +2265,7 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms | |||
2205 | reply_size += cm->reply_body_size; | 2265 | reply_size += cm->reply_body_size; |
2206 | 2266 | ||
2207 | /* allocation not in the IO path, cqueue thread context */ | 2267 | /* allocation not in the IO path, cqueue thread context */ |
2208 | cn_reply = kmalloc(reply_size, GFP_KERNEL); | 2268 | cn_reply = kzalloc(reply_size, GFP_KERNEL); |
2209 | if (!cn_reply) { | 2269 | if (!cn_reply) { |
2210 | retcode = ERR_NOMEM; | 2270 | retcode = ERR_NOMEM; |
2211 | goto fail; | 2271 | goto fail; |
@@ -2213,7 +2273,7 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms | |||
2213 | reply = (struct drbd_nl_cfg_reply *) cn_reply->data; | 2273 | reply = (struct drbd_nl_cfg_reply *) cn_reply->data; |
2214 | 2274 | ||
2215 | reply->packet_type = | 2275 | reply->packet_type = |
2216 | cm->reply_body_size ? nlp->packet_type : P_nl_after_last_packet; | 2276 | cm->reply_body_size ? nlp->packet_type : P_return_code_only; |
2217 | reply->minor = nlp->drbd_minor; | 2277 | reply->minor = nlp->drbd_minor; |
2218 | reply->ret_code = NO_ERROR; /* Might by modified by cm->function. */ | 2278 | reply->ret_code = NO_ERROR; /* Might by modified by cm->function. */ |
2219 | /* reply->tag_list; might be modified by cm->function. */ | 2279 | /* reply->tag_list; might be modified by cm->function. */ |
@@ -2376,7 +2436,7 @@ void drbd_bcast_ee(struct drbd_conf *mdev, | |||
2376 | /* receiver thread context, which is not in the writeout path (of this node), | 2436 | /* receiver thread context, which is not in the writeout path (of this node), |
2377 | * but may be in the writeout path of the _other_ node. | 2437 | * but may be in the writeout path of the _other_ node. |
2378 | * GFP_NOIO to avoid potential "distributed deadlock". */ | 2438 | * GFP_NOIO to avoid potential "distributed deadlock". */ |
2379 | cn_reply = kmalloc( | 2439 | cn_reply = kzalloc( |
2380 | sizeof(struct cn_msg)+ | 2440 | sizeof(struct cn_msg)+ |
2381 | sizeof(struct drbd_nl_cfg_reply)+ | 2441 | sizeof(struct drbd_nl_cfg_reply)+ |
2382 | sizeof(struct dump_ee_tag_len_struct)+ | 2442 | sizeof(struct dump_ee_tag_len_struct)+ |
@@ -2398,10 +2458,11 @@ void drbd_bcast_ee(struct drbd_conf *mdev, | |||
2398 | tl = tl_add_int(tl, T_ee_sector, &e->sector); | 2458 | tl = tl_add_int(tl, T_ee_sector, &e->sector); |
2399 | tl = tl_add_int(tl, T_ee_block_id, &e->block_id); | 2459 | tl = tl_add_int(tl, T_ee_block_id, &e->block_id); |
2400 | 2460 | ||
2461 | /* dump the first 32k */ | ||
2462 | len = min_t(unsigned, e->size, 32 << 10); | ||
2401 | put_unaligned(T_ee_data, tl++); | 2463 | put_unaligned(T_ee_data, tl++); |
2402 | put_unaligned(e->size, tl++); | 2464 | put_unaligned(len, tl++); |
2403 | 2465 | ||
2404 | len = e->size; | ||
2405 | page = e->pages; | 2466 | page = e->pages; |
2406 | page_chain_for_each(page) { | 2467 | page_chain_for_each(page) { |
2407 | void *d = kmap_atomic(page, KM_USER0); | 2468 | void *d = kmap_atomic(page, KM_USER0); |
@@ -2410,6 +2471,8 @@ void drbd_bcast_ee(struct drbd_conf *mdev, | |||
2410 | kunmap_atomic(d, KM_USER0); | 2471 | kunmap_atomic(d, KM_USER0); |
2411 | tl = (unsigned short*)((char*)tl + l); | 2472 | tl = (unsigned short*)((char*)tl + l); |
2412 | len -= l; | 2473 | len -= l; |
2474 | if (len == 0) | ||
2475 | break; | ||
2413 | } | 2476 | } |
2414 | put_unaligned(TT_END, tl++); /* Close the tag list */ | 2477 | put_unaligned(TT_END, tl++); /* Close the tag list */ |
2415 | 2478 | ||
@@ -2508,6 +2571,7 @@ void drbd_nl_send_reply(struct cn_msg *req, int ret_code) | |||
2508 | (struct drbd_nl_cfg_reply *)cn_reply->data; | 2571 | (struct drbd_nl_cfg_reply *)cn_reply->data; |
2509 | int rr; | 2572 | int rr; |
2510 | 2573 | ||
2574 | memset(buffer, 0, sizeof(buffer)); | ||
2511 | cn_reply->id = req->id; | 2575 | cn_reply->id = req->id; |
2512 | 2576 | ||
2513 | cn_reply->seq = req->seq; | 2577 | cn_reply->seq = req->seq; |
@@ -2515,6 +2579,7 @@ void drbd_nl_send_reply(struct cn_msg *req, int ret_code) | |||
2515 | cn_reply->len = sizeof(struct drbd_nl_cfg_reply); | 2579 | cn_reply->len = sizeof(struct drbd_nl_cfg_reply); |
2516 | cn_reply->flags = 0; | 2580 | cn_reply->flags = 0; |
2517 | 2581 | ||
2582 | reply->packet_type = P_return_code_only; | ||
2518 | reply->minor = ((struct drbd_nl_cfg_req *)req->data)->drbd_minor; | 2583 | reply->minor = ((struct drbd_nl_cfg_req *)req->data)->drbd_minor; |
2519 | reply->ret_code = ret_code; | 2584 | reply->ret_code = ret_code; |
2520 | 2585 | ||
diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index 7e6ac307e2de..2959cdfb77f5 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include "drbd_int.h" | 34 | #include "drbd_int.h" |
35 | 35 | ||
36 | static int drbd_proc_open(struct inode *inode, struct file *file); | 36 | static int drbd_proc_open(struct inode *inode, struct file *file); |
37 | static int drbd_proc_release(struct inode *inode, struct file *file); | ||
37 | 38 | ||
38 | 39 | ||
39 | struct proc_dir_entry *drbd_proc; | 40 | struct proc_dir_entry *drbd_proc; |
@@ -42,9 +43,22 @@ const struct file_operations drbd_proc_fops = { | |||
42 | .open = drbd_proc_open, | 43 | .open = drbd_proc_open, |
43 | .read = seq_read, | 44 | .read = seq_read, |
44 | .llseek = seq_lseek, | 45 | .llseek = seq_lseek, |
45 | .release = single_release, | 46 | .release = drbd_proc_release, |
46 | }; | 47 | }; |
47 | 48 | ||
49 | void seq_printf_with_thousands_grouping(struct seq_file *seq, long v) | ||
50 | { | ||
51 | /* v is in kB/sec. We don't expect TiByte/sec yet. */ | ||
52 | if (unlikely(v >= 1000000)) { | ||
53 | /* cool: > GiByte/s */ | ||
54 | seq_printf(seq, "%ld,", v / 1000000); | ||
55 | v /= 1000000; | ||
56 | seq_printf(seq, "%03ld,%03ld", v/1000, v % 1000); | ||
57 | } else if (likely(v >= 1000)) | ||
58 | seq_printf(seq, "%ld,%03ld", v/1000, v % 1000); | ||
59 | else | ||
60 | seq_printf(seq, "%ld", v); | ||
61 | } | ||
48 | 62 | ||
49 | /*lge | 63 | /*lge |
50 | * progress bars shamelessly adapted from driver/md/md.c | 64 | * progress bars shamelessly adapted from driver/md/md.c |
@@ -71,10 +85,15 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) | |||
71 | seq_printf(seq, "."); | 85 | seq_printf(seq, "."); |
72 | seq_printf(seq, "] "); | 86 | seq_printf(seq, "] "); |
73 | 87 | ||
74 | seq_printf(seq, "sync'ed:%3u.%u%% ", res / 10, res % 10); | 88 | if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T) |
75 | /* if more than 1 GB display in MB */ | 89 | seq_printf(seq, "verified:"); |
76 | if (mdev->rs_total > 0x100000L) | 90 | else |
77 | seq_printf(seq, "(%lu/%lu)M\n\t", | 91 | seq_printf(seq, "sync'ed:"); |
92 | seq_printf(seq, "%3u.%u%% ", res / 10, res % 10); | ||
93 | |||
94 | /* if more than a few GB, display in MB */ | ||
95 | if (mdev->rs_total > (4UL << (30 - BM_BLOCK_SHIFT))) | ||
96 | seq_printf(seq, "(%lu/%lu)M", | ||
78 | (unsigned long) Bit2KB(rs_left >> 10), | 97 | (unsigned long) Bit2KB(rs_left >> 10), |
79 | (unsigned long) Bit2KB(mdev->rs_total >> 10)); | 98 | (unsigned long) Bit2KB(mdev->rs_total >> 10)); |
80 | else | 99 | else |
@@ -94,6 +113,7 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) | |||
94 | /* Rolling marks. last_mark+1 may just now be modified. last_mark+2 is | 113 | /* Rolling marks. last_mark+1 may just now be modified. last_mark+2 is |
95 | * at least (DRBD_SYNC_MARKS-2)*DRBD_SYNC_MARK_STEP old, and has at | 114 | * at least (DRBD_SYNC_MARKS-2)*DRBD_SYNC_MARK_STEP old, and has at |
96 | * least DRBD_SYNC_MARK_STEP time before it will be modified. */ | 115 | * least DRBD_SYNC_MARK_STEP time before it will be modified. */ |
116 | /* ------------------------ ~18s average ------------------------ */ | ||
97 | i = (mdev->rs_last_mark + 2) % DRBD_SYNC_MARKS; | 117 | i = (mdev->rs_last_mark + 2) % DRBD_SYNC_MARKS; |
98 | dt = (jiffies - mdev->rs_mark_time[i]) / HZ; | 118 | dt = (jiffies - mdev->rs_mark_time[i]) / HZ; |
99 | if (dt > (DRBD_SYNC_MARK_STEP * DRBD_SYNC_MARKS)) | 119 | if (dt > (DRBD_SYNC_MARK_STEP * DRBD_SYNC_MARKS)) |
@@ -107,14 +127,24 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) | |||
107 | seq_printf(seq, "finish: %lu:%02lu:%02lu", | 127 | seq_printf(seq, "finish: %lu:%02lu:%02lu", |
108 | rt / 3600, (rt % 3600) / 60, rt % 60); | 128 | rt / 3600, (rt % 3600) / 60, rt % 60); |
109 | 129 | ||
110 | /* current speed average over (SYNC_MARKS * SYNC_MARK_STEP) jiffies */ | ||
111 | dbdt = Bit2KB(db/dt); | 130 | dbdt = Bit2KB(db/dt); |
112 | if (dbdt > 1000) | 131 | seq_printf(seq, " speed: "); |
113 | seq_printf(seq, " speed: %ld,%03ld", | 132 | seq_printf_with_thousands_grouping(seq, dbdt); |
114 | dbdt/1000, dbdt % 1000); | 133 | seq_printf(seq, " ("); |
115 | else | 134 | /* ------------------------- ~3s average ------------------------ */ |
116 | seq_printf(seq, " speed: %ld", dbdt); | 135 | if (proc_details >= 1) { |
136 | /* this is what drbd_rs_should_slow_down() uses */ | ||
137 | i = (mdev->rs_last_mark + DRBD_SYNC_MARKS-1) % DRBD_SYNC_MARKS; | ||
138 | dt = (jiffies - mdev->rs_mark_time[i]) / HZ; | ||
139 | if (!dt) | ||
140 | dt++; | ||
141 | db = mdev->rs_mark_left[i] - rs_left; | ||
142 | dbdt = Bit2KB(db/dt); | ||
143 | seq_printf_with_thousands_grouping(seq, dbdt); | ||
144 | seq_printf(seq, " -- "); | ||
145 | } | ||
117 | 146 | ||
147 | /* --------------------- long term average ---------------------- */ | ||
118 | /* mean speed since syncer started | 148 | /* mean speed since syncer started |
119 | * we do account for PausedSync periods */ | 149 | * we do account for PausedSync periods */ |
120 | dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ; | 150 | dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ; |
@@ -122,20 +152,34 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) | |||
122 | dt = 1; | 152 | dt = 1; |
123 | db = mdev->rs_total - rs_left; | 153 | db = mdev->rs_total - rs_left; |
124 | dbdt = Bit2KB(db/dt); | 154 | dbdt = Bit2KB(db/dt); |
125 | if (dbdt > 1000) | 155 | seq_printf_with_thousands_grouping(seq, dbdt); |
126 | seq_printf(seq, " (%ld,%03ld)", | 156 | seq_printf(seq, ")"); |
127 | dbdt/1000, dbdt % 1000); | ||
128 | else | ||
129 | seq_printf(seq, " (%ld)", dbdt); | ||
130 | 157 | ||
131 | if (mdev->state.conn == C_SYNC_TARGET) { | 158 | if (mdev->state.conn == C_SYNC_TARGET || |
132 | if (mdev->c_sync_rate > 1000) | 159 | mdev->state.conn == C_VERIFY_S) { |
133 | seq_printf(seq, " want: %d,%03d", | 160 | seq_printf(seq, " want: "); |
134 | mdev->c_sync_rate / 1000, mdev->c_sync_rate % 1000); | 161 | seq_printf_with_thousands_grouping(seq, mdev->c_sync_rate); |
135 | else | ||
136 | seq_printf(seq, " want: %d", mdev->c_sync_rate); | ||
137 | } | 162 | } |
138 | seq_printf(seq, " K/sec%s\n", stalled ? " (stalled)" : ""); | 163 | seq_printf(seq, " K/sec%s\n", stalled ? " (stalled)" : ""); |
164 | |||
165 | if (proc_details >= 1) { | ||
166 | /* 64 bit: | ||
167 | * we convert to sectors in the display below. */ | ||
168 | unsigned long bm_bits = drbd_bm_bits(mdev); | ||
169 | unsigned long bit_pos; | ||
170 | if (mdev->state.conn == C_VERIFY_S || | ||
171 | mdev->state.conn == C_VERIFY_T) | ||
172 | bit_pos = bm_bits - mdev->ov_left; | ||
173 | else | ||
174 | bit_pos = mdev->bm_resync_fo; | ||
175 | /* Total sectors may be slightly off for oddly | ||
176 | * sized devices. So what. */ | ||
177 | seq_printf(seq, | ||
178 | "\t%3d%% sector pos: %llu/%llu\n", | ||
179 | (int)(bit_pos / (bm_bits/100+1)), | ||
180 | (unsigned long long)bit_pos * BM_SECT_PER_BIT, | ||
181 | (unsigned long long)bm_bits * BM_SECT_PER_BIT); | ||
182 | } | ||
139 | } | 183 | } |
140 | 184 | ||
141 | static void resync_dump_detail(struct seq_file *seq, struct lc_element *e) | 185 | static void resync_dump_detail(struct seq_file *seq, struct lc_element *e) |
@@ -232,20 +276,16 @@ static int drbd_seq_show(struct seq_file *seq, void *v) | |||
232 | mdev->epochs, | 276 | mdev->epochs, |
233 | write_ordering_chars[mdev->write_ordering] | 277 | write_ordering_chars[mdev->write_ordering] |
234 | ); | 278 | ); |
235 | seq_printf(seq, " oos:%lu\n", | 279 | seq_printf(seq, " oos:%llu\n", |
236 | Bit2KB(drbd_bm_total_weight(mdev))); | 280 | Bit2KB((unsigned long long) |
281 | drbd_bm_total_weight(mdev))); | ||
237 | } | 282 | } |
238 | if (mdev->state.conn == C_SYNC_SOURCE || | 283 | if (mdev->state.conn == C_SYNC_SOURCE || |
239 | mdev->state.conn == C_SYNC_TARGET) | 284 | mdev->state.conn == C_SYNC_TARGET || |
285 | mdev->state.conn == C_VERIFY_S || | ||
286 | mdev->state.conn == C_VERIFY_T) | ||
240 | drbd_syncer_progress(mdev, seq); | 287 | drbd_syncer_progress(mdev, seq); |
241 | 288 | ||
242 | if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T) | ||
243 | seq_printf(seq, "\t%3d%% %lu/%lu\n", | ||
244 | (int)((mdev->rs_total-mdev->ov_left) / | ||
245 | (mdev->rs_total/100+1)), | ||
246 | mdev->rs_total - mdev->ov_left, | ||
247 | mdev->rs_total); | ||
248 | |||
249 | if (proc_details >= 1 && get_ldev_if_state(mdev, D_FAILED)) { | 289 | if (proc_details >= 1 && get_ldev_if_state(mdev, D_FAILED)) { |
250 | lc_seq_printf_stats(seq, mdev->resync); | 290 | lc_seq_printf_stats(seq, mdev->resync); |
251 | lc_seq_printf_stats(seq, mdev->act_log); | 291 | lc_seq_printf_stats(seq, mdev->act_log); |
@@ -265,7 +305,15 @@ static int drbd_seq_show(struct seq_file *seq, void *v) | |||
265 | 305 | ||
266 | static int drbd_proc_open(struct inode *inode, struct file *file) | 306 | static int drbd_proc_open(struct inode *inode, struct file *file) |
267 | { | 307 | { |
268 | return single_open(file, drbd_seq_show, PDE(inode)->data); | 308 | if (try_module_get(THIS_MODULE)) |
309 | return single_open(file, drbd_seq_show, PDE(inode)->data); | ||
310 | return -ENODEV; | ||
311 | } | ||
312 | |||
313 | static int drbd_proc_release(struct inode *inode, struct file *file) | ||
314 | { | ||
315 | module_put(THIS_MODULE); | ||
316 | return single_release(inode, file); | ||
269 | } | 317 | } |
270 | 318 | ||
271 | /* PROC FS stuff end */ | 319 | /* PROC FS stuff end */ |
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 8e68be939deb..fe1564c7d8b6 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c | |||
@@ -277,7 +277,7 @@ static void drbd_pp_free(struct drbd_conf *mdev, struct page *page, int is_net) | |||
277 | atomic_t *a = is_net ? &mdev->pp_in_use_by_net : &mdev->pp_in_use; | 277 | atomic_t *a = is_net ? &mdev->pp_in_use_by_net : &mdev->pp_in_use; |
278 | int i; | 278 | int i; |
279 | 279 | ||
280 | if (drbd_pp_vacant > (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE)*minor_count) | 280 | if (drbd_pp_vacant > (DRBD_MAX_BIO_SIZE/PAGE_SIZE)*minor_count) |
281 | i = page_chain_free(page); | 281 | i = page_chain_free(page); |
282 | else { | 282 | else { |
283 | struct page *tmp; | 283 | struct page *tmp; |
@@ -319,7 +319,7 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, | |||
319 | struct page *page; | 319 | struct page *page; |
320 | unsigned nr_pages = (data_size + PAGE_SIZE -1) >> PAGE_SHIFT; | 320 | unsigned nr_pages = (data_size + PAGE_SIZE -1) >> PAGE_SHIFT; |
321 | 321 | ||
322 | if (FAULT_ACTIVE(mdev, DRBD_FAULT_AL_EE)) | 322 | if (drbd_insert_fault(mdev, DRBD_FAULT_AL_EE)) |
323 | return NULL; | 323 | return NULL; |
324 | 324 | ||
325 | e = mempool_alloc(drbd_ee_mempool, gfp_mask & ~__GFP_HIGHMEM); | 325 | e = mempool_alloc(drbd_ee_mempool, gfp_mask & ~__GFP_HIGHMEM); |
@@ -725,16 +725,16 @@ static int drbd_socket_okay(struct drbd_conf *mdev, struct socket **sock) | |||
725 | char tb[4]; | 725 | char tb[4]; |
726 | 726 | ||
727 | if (!*sock) | 727 | if (!*sock) |
728 | return FALSE; | 728 | return false; |
729 | 729 | ||
730 | rr = drbd_recv_short(mdev, *sock, tb, 4, MSG_DONTWAIT | MSG_PEEK); | 730 | rr = drbd_recv_short(mdev, *sock, tb, 4, MSG_DONTWAIT | MSG_PEEK); |
731 | 731 | ||
732 | if (rr > 0 || rr == -EAGAIN) { | 732 | if (rr > 0 || rr == -EAGAIN) { |
733 | return TRUE; | 733 | return true; |
734 | } else { | 734 | } else { |
735 | sock_release(*sock); | 735 | sock_release(*sock); |
736 | *sock = NULL; | 736 | *sock = NULL; |
737 | return FALSE; | 737 | return false; |
738 | } | 738 | } |
739 | } | 739 | } |
740 | 740 | ||
@@ -768,8 +768,7 @@ static int drbd_connect(struct drbd_conf *mdev) | |||
768 | if (s || ++try >= 3) | 768 | if (s || ++try >= 3) |
769 | break; | 769 | break; |
770 | /* give the other side time to call bind() & listen() */ | 770 | /* give the other side time to call bind() & listen() */ |
771 | __set_current_state(TASK_INTERRUPTIBLE); | 771 | schedule_timeout_interruptible(HZ / 10); |
772 | schedule_timeout(HZ / 10); | ||
773 | } | 772 | } |
774 | 773 | ||
775 | if (s) { | 774 | if (s) { |
@@ -788,8 +787,7 @@ static int drbd_connect(struct drbd_conf *mdev) | |||
788 | } | 787 | } |
789 | 788 | ||
790 | if (sock && msock) { | 789 | if (sock && msock) { |
791 | __set_current_state(TASK_INTERRUPTIBLE); | 790 | schedule_timeout_interruptible(HZ / 10); |
792 | schedule_timeout(HZ / 10); | ||
793 | ok = drbd_socket_okay(mdev, &sock); | 791 | ok = drbd_socket_okay(mdev, &sock); |
794 | ok = drbd_socket_okay(mdev, &msock) && ok; | 792 | ok = drbd_socket_okay(mdev, &msock) && ok; |
795 | if (ok) | 793 | if (ok) |
@@ -906,7 +904,7 @@ retry: | |||
906 | put_ldev(mdev); | 904 | put_ldev(mdev); |
907 | } | 905 | } |
908 | 906 | ||
909 | if (!drbd_send_protocol(mdev)) | 907 | if (drbd_send_protocol(mdev) == -1) |
910 | return -1; | 908 | return -1; |
911 | drbd_send_sync_param(mdev, &mdev->sync_conf); | 909 | drbd_send_sync_param(mdev, &mdev->sync_conf); |
912 | drbd_send_sizes(mdev, 0, 0); | 910 | drbd_send_sizes(mdev, 0, 0); |
@@ -914,6 +912,7 @@ retry: | |||
914 | drbd_send_state(mdev); | 912 | drbd_send_state(mdev); |
915 | clear_bit(USE_DEGR_WFC_T, &mdev->flags); | 913 | clear_bit(USE_DEGR_WFC_T, &mdev->flags); |
916 | clear_bit(RESIZE_PENDING, &mdev->flags); | 914 | clear_bit(RESIZE_PENDING, &mdev->flags); |
915 | mod_timer(&mdev->request_timer, jiffies + HZ); /* just start it here. */ | ||
917 | 916 | ||
918 | return 1; | 917 | return 1; |
919 | 918 | ||
@@ -932,8 +931,9 @@ static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsi | |||
932 | 931 | ||
933 | r = drbd_recv(mdev, h, sizeof(*h)); | 932 | r = drbd_recv(mdev, h, sizeof(*h)); |
934 | if (unlikely(r != sizeof(*h))) { | 933 | if (unlikely(r != sizeof(*h))) { |
935 | dev_err(DEV, "short read expecting header on sock: r=%d\n", r); | 934 | if (!signal_pending(current)) |
936 | return FALSE; | 935 | dev_warn(DEV, "short read expecting header on sock: r=%d\n", r); |
936 | return false; | ||
937 | } | 937 | } |
938 | 938 | ||
939 | if (likely(h->h80.magic == BE_DRBD_MAGIC)) { | 939 | if (likely(h->h80.magic == BE_DRBD_MAGIC)) { |
@@ -947,11 +947,11 @@ static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsi | |||
947 | be32_to_cpu(h->h80.magic), | 947 | be32_to_cpu(h->h80.magic), |
948 | be16_to_cpu(h->h80.command), | 948 | be16_to_cpu(h->h80.command), |
949 | be16_to_cpu(h->h80.length)); | 949 | be16_to_cpu(h->h80.length)); |
950 | return FALSE; | 950 | return false; |
951 | } | 951 | } |
952 | mdev->last_received = jiffies; | 952 | mdev->last_received = jiffies; |
953 | 953 | ||
954 | return TRUE; | 954 | return true; |
955 | } | 955 | } |
956 | 956 | ||
957 | static void drbd_flush(struct drbd_conf *mdev) | 957 | static void drbd_flush(struct drbd_conf *mdev) |
@@ -1074,6 +1074,16 @@ void drbd_bump_write_ordering(struct drbd_conf *mdev, enum write_ordering_e wo) | |||
1074 | * @mdev: DRBD device. | 1074 | * @mdev: DRBD device. |
1075 | * @e: epoch entry | 1075 | * @e: epoch entry |
1076 | * @rw: flag field, see bio->bi_rw | 1076 | * @rw: flag field, see bio->bi_rw |
1077 | * | ||
1078 | * May spread the pages to multiple bios, | ||
1079 | * depending on bio_add_page restrictions. | ||
1080 | * | ||
1081 | * Returns 0 if all bios have been submitted, | ||
1082 | * -ENOMEM if we could not allocate enough bios, | ||
1083 | * -ENOSPC (any better suggestion?) if we have not been able to bio_add_page a | ||
1084 | * single page to an empty bio (which should never happen and likely indicates | ||
1085 | * that the lower level IO stack is in some way broken). This has been observed | ||
1086 | * on certain Xen deployments. | ||
1077 | */ | 1087 | */ |
1078 | /* TODO allocate from our own bio_set. */ | 1088 | /* TODO allocate from our own bio_set. */ |
1079 | int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, | 1089 | int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, |
@@ -1086,6 +1096,7 @@ int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, | |||
1086 | unsigned ds = e->size; | 1096 | unsigned ds = e->size; |
1087 | unsigned n_bios = 0; | 1097 | unsigned n_bios = 0; |
1088 | unsigned nr_pages = (ds + PAGE_SIZE -1) >> PAGE_SHIFT; | 1098 | unsigned nr_pages = (ds + PAGE_SIZE -1) >> PAGE_SHIFT; |
1099 | int err = -ENOMEM; | ||
1089 | 1100 | ||
1090 | /* In most cases, we will only need one bio. But in case the lower | 1101 | /* In most cases, we will only need one bio. But in case the lower |
1091 | * level restrictions happen to be different at this offset on this | 1102 | * level restrictions happen to be different at this offset on this |
@@ -1111,8 +1122,17 @@ next_bio: | |||
1111 | page_chain_for_each(page) { | 1122 | page_chain_for_each(page) { |
1112 | unsigned len = min_t(unsigned, ds, PAGE_SIZE); | 1123 | unsigned len = min_t(unsigned, ds, PAGE_SIZE); |
1113 | if (!bio_add_page(bio, page, len, 0)) { | 1124 | if (!bio_add_page(bio, page, len, 0)) { |
1114 | /* a single page must always be possible! */ | 1125 | /* A single page must always be possible! |
1115 | BUG_ON(bio->bi_vcnt == 0); | 1126 | * But in case it fails anyways, |
1127 | * we deal with it, and complain (below). */ | ||
1128 | if (bio->bi_vcnt == 0) { | ||
1129 | dev_err(DEV, | ||
1130 | "bio_add_page failed for len=%u, " | ||
1131 | "bi_vcnt=0 (bi_sector=%llu)\n", | ||
1132 | len, (unsigned long long)bio->bi_sector); | ||
1133 | err = -ENOSPC; | ||
1134 | goto fail; | ||
1135 | } | ||
1116 | goto next_bio; | 1136 | goto next_bio; |
1117 | } | 1137 | } |
1118 | ds -= len; | 1138 | ds -= len; |
@@ -1138,7 +1158,7 @@ fail: | |||
1138 | bios = bios->bi_next; | 1158 | bios = bios->bi_next; |
1139 | bio_put(bio); | 1159 | bio_put(bio); |
1140 | } | 1160 | } |
1141 | return -ENOMEM; | 1161 | return err; |
1142 | } | 1162 | } |
1143 | 1163 | ||
1144 | static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) | 1164 | static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) |
@@ -1160,7 +1180,7 @@ static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsign | |||
1160 | switch (mdev->write_ordering) { | 1180 | switch (mdev->write_ordering) { |
1161 | case WO_none: | 1181 | case WO_none: |
1162 | if (rv == FE_RECYCLED) | 1182 | if (rv == FE_RECYCLED) |
1163 | return TRUE; | 1183 | return true; |
1164 | 1184 | ||
1165 | /* receiver context, in the writeout path of the other node. | 1185 | /* receiver context, in the writeout path of the other node. |
1166 | * avoid potential distributed deadlock */ | 1186 | * avoid potential distributed deadlock */ |
@@ -1188,10 +1208,10 @@ static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsign | |||
1188 | D_ASSERT(atomic_read(&epoch->active) == 0); | 1208 | D_ASSERT(atomic_read(&epoch->active) == 0); |
1189 | D_ASSERT(epoch->flags == 0); | 1209 | D_ASSERT(epoch->flags == 0); |
1190 | 1210 | ||
1191 | return TRUE; | 1211 | return true; |
1192 | default: | 1212 | default: |
1193 | dev_err(DEV, "Strangeness in mdev->write_ordering %d\n", mdev->write_ordering); | 1213 | dev_err(DEV, "Strangeness in mdev->write_ordering %d\n", mdev->write_ordering); |
1194 | return FALSE; | 1214 | return false; |
1195 | } | 1215 | } |
1196 | 1216 | ||
1197 | epoch->flags = 0; | 1217 | epoch->flags = 0; |
@@ -1209,7 +1229,7 @@ static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsign | |||
1209 | } | 1229 | } |
1210 | spin_unlock(&mdev->epoch_lock); | 1230 | spin_unlock(&mdev->epoch_lock); |
1211 | 1231 | ||
1212 | return TRUE; | 1232 | return true; |
1213 | } | 1233 | } |
1214 | 1234 | ||
1215 | /* used from receive_RSDataReply (recv_resync_read) | 1235 | /* used from receive_RSDataReply (recv_resync_read) |
@@ -1231,21 +1251,25 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __ | |||
1231 | if (dgs) { | 1251 | if (dgs) { |
1232 | rr = drbd_recv(mdev, dig_in, dgs); | 1252 | rr = drbd_recv(mdev, dig_in, dgs); |
1233 | if (rr != dgs) { | 1253 | if (rr != dgs) { |
1234 | dev_warn(DEV, "short read receiving data digest: read %d expected %d\n", | 1254 | if (!signal_pending(current)) |
1235 | rr, dgs); | 1255 | dev_warn(DEV, |
1256 | "short read receiving data digest: read %d expected %d\n", | ||
1257 | rr, dgs); | ||
1236 | return NULL; | 1258 | return NULL; |
1237 | } | 1259 | } |
1238 | } | 1260 | } |
1239 | 1261 | ||
1240 | data_size -= dgs; | 1262 | data_size -= dgs; |
1241 | 1263 | ||
1264 | ERR_IF(data_size == 0) return NULL; | ||
1242 | ERR_IF(data_size & 0x1ff) return NULL; | 1265 | ERR_IF(data_size & 0x1ff) return NULL; |
1243 | ERR_IF(data_size > DRBD_MAX_SEGMENT_SIZE) return NULL; | 1266 | ERR_IF(data_size > DRBD_MAX_BIO_SIZE) return NULL; |
1244 | 1267 | ||
1245 | /* even though we trust out peer, | 1268 | /* even though we trust out peer, |
1246 | * we sometimes have to double check. */ | 1269 | * we sometimes have to double check. */ |
1247 | if (sector + (data_size>>9) > capacity) { | 1270 | if (sector + (data_size>>9) > capacity) { |
1248 | dev_err(DEV, "capacity: %llus < sector: %llus + size: %u\n", | 1271 | dev_err(DEV, "request from peer beyond end of local disk: " |
1272 | "capacity: %llus < sector: %llus + size: %u\n", | ||
1249 | (unsigned long long)capacity, | 1273 | (unsigned long long)capacity, |
1250 | (unsigned long long)sector, data_size); | 1274 | (unsigned long long)sector, data_size); |
1251 | return NULL; | 1275 | return NULL; |
@@ -1264,15 +1288,16 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __ | |||
1264 | unsigned len = min_t(int, ds, PAGE_SIZE); | 1288 | unsigned len = min_t(int, ds, PAGE_SIZE); |
1265 | data = kmap(page); | 1289 | data = kmap(page); |
1266 | rr = drbd_recv(mdev, data, len); | 1290 | rr = drbd_recv(mdev, data, len); |
1267 | if (FAULT_ACTIVE(mdev, DRBD_FAULT_RECEIVE)) { | 1291 | if (drbd_insert_fault(mdev, DRBD_FAULT_RECEIVE)) { |
1268 | dev_err(DEV, "Fault injection: Corrupting data on receive\n"); | 1292 | dev_err(DEV, "Fault injection: Corrupting data on receive\n"); |
1269 | data[0] = data[0] ^ (unsigned long)-1; | 1293 | data[0] = data[0] ^ (unsigned long)-1; |
1270 | } | 1294 | } |
1271 | kunmap(page); | 1295 | kunmap(page); |
1272 | if (rr != len) { | 1296 | if (rr != len) { |
1273 | drbd_free_ee(mdev, e); | 1297 | drbd_free_ee(mdev, e); |
1274 | dev_warn(DEV, "short read receiving data: read %d expected %d\n", | 1298 | if (!signal_pending(current)) |
1275 | rr, len); | 1299 | dev_warn(DEV, "short read receiving data: read %d expected %d\n", |
1300 | rr, len); | ||
1276 | return NULL; | 1301 | return NULL; |
1277 | } | 1302 | } |
1278 | ds -= rr; | 1303 | ds -= rr; |
@@ -1281,7 +1306,8 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __ | |||
1281 | if (dgs) { | 1306 | if (dgs) { |
1282 | drbd_csum_ee(mdev, mdev->integrity_r_tfm, e, dig_vv); | 1307 | drbd_csum_ee(mdev, mdev->integrity_r_tfm, e, dig_vv); |
1283 | if (memcmp(dig_in, dig_vv, dgs)) { | 1308 | if (memcmp(dig_in, dig_vv, dgs)) { |
1284 | dev_err(DEV, "Digest integrity check FAILED.\n"); | 1309 | dev_err(DEV, "Digest integrity check FAILED: %llus +%u\n", |
1310 | (unsigned long long)sector, data_size); | ||
1285 | drbd_bcast_ee(mdev, "digest failed", | 1311 | drbd_bcast_ee(mdev, "digest failed", |
1286 | dgs, dig_in, dig_vv, e); | 1312 | dgs, dig_in, dig_vv, e); |
1287 | drbd_free_ee(mdev, e); | 1313 | drbd_free_ee(mdev, e); |
@@ -1302,7 +1328,7 @@ static int drbd_drain_block(struct drbd_conf *mdev, int data_size) | |||
1302 | void *data; | 1328 | void *data; |
1303 | 1329 | ||
1304 | if (!data_size) | 1330 | if (!data_size) |
1305 | return TRUE; | 1331 | return true; |
1306 | 1332 | ||
1307 | page = drbd_pp_alloc(mdev, 1, 1); | 1333 | page = drbd_pp_alloc(mdev, 1, 1); |
1308 | 1334 | ||
@@ -1311,8 +1337,10 @@ static int drbd_drain_block(struct drbd_conf *mdev, int data_size) | |||
1311 | rr = drbd_recv(mdev, data, min_t(int, data_size, PAGE_SIZE)); | 1337 | rr = drbd_recv(mdev, data, min_t(int, data_size, PAGE_SIZE)); |
1312 | if (rr != min_t(int, data_size, PAGE_SIZE)) { | 1338 | if (rr != min_t(int, data_size, PAGE_SIZE)) { |
1313 | rv = 0; | 1339 | rv = 0; |
1314 | dev_warn(DEV, "short read receiving data: read %d expected %d\n", | 1340 | if (!signal_pending(current)) |
1315 | rr, min_t(int, data_size, PAGE_SIZE)); | 1341 | dev_warn(DEV, |
1342 | "short read receiving data: read %d expected %d\n", | ||
1343 | rr, min_t(int, data_size, PAGE_SIZE)); | ||
1316 | break; | 1344 | break; |
1317 | } | 1345 | } |
1318 | data_size -= rr; | 1346 | data_size -= rr; |
@@ -1337,8 +1365,10 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, | |||
1337 | if (dgs) { | 1365 | if (dgs) { |
1338 | rr = drbd_recv(mdev, dig_in, dgs); | 1366 | rr = drbd_recv(mdev, dig_in, dgs); |
1339 | if (rr != dgs) { | 1367 | if (rr != dgs) { |
1340 | dev_warn(DEV, "short read receiving data reply digest: read %d expected %d\n", | 1368 | if (!signal_pending(current)) |
1341 | rr, dgs); | 1369 | dev_warn(DEV, |
1370 | "short read receiving data reply digest: read %d expected %d\n", | ||
1371 | rr, dgs); | ||
1342 | return 0; | 1372 | return 0; |
1343 | } | 1373 | } |
1344 | } | 1374 | } |
@@ -1359,9 +1389,10 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, | |||
1359 | expect); | 1389 | expect); |
1360 | kunmap(bvec->bv_page); | 1390 | kunmap(bvec->bv_page); |
1361 | if (rr != expect) { | 1391 | if (rr != expect) { |
1362 | dev_warn(DEV, "short read receiving data reply: " | 1392 | if (!signal_pending(current)) |
1363 | "read %d expected %d\n", | 1393 | dev_warn(DEV, "short read receiving data reply: " |
1364 | rr, expect); | 1394 | "read %d expected %d\n", |
1395 | rr, expect); | ||
1365 | return 0; | 1396 | return 0; |
1366 | } | 1397 | } |
1367 | data_size -= rr; | 1398 | data_size -= rr; |
@@ -1425,11 +1456,10 @@ static int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_si | |||
1425 | 1456 | ||
1426 | atomic_add(data_size >> 9, &mdev->rs_sect_ev); | 1457 | atomic_add(data_size >> 9, &mdev->rs_sect_ev); |
1427 | if (drbd_submit_ee(mdev, e, WRITE, DRBD_FAULT_RS_WR) == 0) | 1458 | if (drbd_submit_ee(mdev, e, WRITE, DRBD_FAULT_RS_WR) == 0) |
1428 | return TRUE; | 1459 | return true; |
1429 | 1460 | ||
1430 | /* drbd_submit_ee currently fails for one reason only: | 1461 | /* don't care for the reason here */ |
1431 | * not being able to allocate enough bios. | 1462 | dev_err(DEV, "submit failed, triggering re-connect\n"); |
1432 | * Is dropping the connection going to help? */ | ||
1433 | spin_lock_irq(&mdev->req_lock); | 1463 | spin_lock_irq(&mdev->req_lock); |
1434 | list_del(&e->w.list); | 1464 | list_del(&e->w.list); |
1435 | spin_unlock_irq(&mdev->req_lock); | 1465 | spin_unlock_irq(&mdev->req_lock); |
@@ -1437,7 +1467,7 @@ static int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_si | |||
1437 | drbd_free_ee(mdev, e); | 1467 | drbd_free_ee(mdev, e); |
1438 | fail: | 1468 | fail: |
1439 | put_ldev(mdev); | 1469 | put_ldev(mdev); |
1440 | return FALSE; | 1470 | return false; |
1441 | } | 1471 | } |
1442 | 1472 | ||
1443 | static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) | 1473 | static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) |
@@ -1454,7 +1484,7 @@ static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsi | |||
1454 | spin_unlock_irq(&mdev->req_lock); | 1484 | spin_unlock_irq(&mdev->req_lock); |
1455 | if (unlikely(!req)) { | 1485 | if (unlikely(!req)) { |
1456 | dev_err(DEV, "Got a corrupt block_id/sector pair(1).\n"); | 1486 | dev_err(DEV, "Got a corrupt block_id/sector pair(1).\n"); |
1457 | return FALSE; | 1487 | return false; |
1458 | } | 1488 | } |
1459 | 1489 | ||
1460 | /* hlist_del(&req->colision) is done in _req_may_be_done, to avoid | 1490 | /* hlist_del(&req->colision) is done in _req_may_be_done, to avoid |
@@ -1611,15 +1641,15 @@ static int drbd_wait_peer_seq(struct drbd_conf *mdev, const u32 packet_seq) | |||
1611 | return ret; | 1641 | return ret; |
1612 | } | 1642 | } |
1613 | 1643 | ||
1614 | static unsigned long write_flags_to_bio(struct drbd_conf *mdev, u32 dpf) | 1644 | /* see also bio_flags_to_wire() |
1645 | * DRBD_REQ_*, because we need to semantically map the flags to data packet | ||
1646 | * flags and back. We may replicate to other kernel versions. */ | ||
1647 | static unsigned long wire_flags_to_bio(struct drbd_conf *mdev, u32 dpf) | ||
1615 | { | 1648 | { |
1616 | if (mdev->agreed_pro_version >= 95) | 1649 | return (dpf & DP_RW_SYNC ? REQ_SYNC : 0) | |
1617 | return (dpf & DP_RW_SYNC ? REQ_SYNC : 0) | | 1650 | (dpf & DP_FUA ? REQ_FUA : 0) | |
1618 | (dpf & DP_FUA ? REQ_FUA : 0) | | 1651 | (dpf & DP_FLUSH ? REQ_FLUSH : 0) | |
1619 | (dpf & DP_FLUSH ? REQ_FUA : 0) | | 1652 | (dpf & DP_DISCARD ? REQ_DISCARD : 0); |
1620 | (dpf & DP_DISCARD ? REQ_DISCARD : 0); | ||
1621 | else | ||
1622 | return dpf & DP_RW_SYNC ? REQ_SYNC : 0; | ||
1623 | } | 1653 | } |
1624 | 1654 | ||
1625 | /* mirrored write */ | 1655 | /* mirrored write */ |
@@ -1632,9 +1662,6 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
1632 | u32 dp_flags; | 1662 | u32 dp_flags; |
1633 | 1663 | ||
1634 | if (!get_ldev(mdev)) { | 1664 | if (!get_ldev(mdev)) { |
1635 | if (__ratelimit(&drbd_ratelimit_state)) | ||
1636 | dev_err(DEV, "Can not write mirrored data block " | ||
1637 | "to local disk.\n"); | ||
1638 | spin_lock(&mdev->peer_seq_lock); | 1665 | spin_lock(&mdev->peer_seq_lock); |
1639 | if (mdev->peer_seq+1 == be32_to_cpu(p->seq_num)) | 1666 | if (mdev->peer_seq+1 == be32_to_cpu(p->seq_num)) |
1640 | mdev->peer_seq++; | 1667 | mdev->peer_seq++; |
@@ -1654,23 +1681,23 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
1654 | e = read_in_block(mdev, p->block_id, sector, data_size); | 1681 | e = read_in_block(mdev, p->block_id, sector, data_size); |
1655 | if (!e) { | 1682 | if (!e) { |
1656 | put_ldev(mdev); | 1683 | put_ldev(mdev); |
1657 | return FALSE; | 1684 | return false; |
1658 | } | 1685 | } |
1659 | 1686 | ||
1660 | e->w.cb = e_end_block; | 1687 | e->w.cb = e_end_block; |
1661 | 1688 | ||
1689 | dp_flags = be32_to_cpu(p->dp_flags); | ||
1690 | rw |= wire_flags_to_bio(mdev, dp_flags); | ||
1691 | |||
1692 | if (dp_flags & DP_MAY_SET_IN_SYNC) | ||
1693 | e->flags |= EE_MAY_SET_IN_SYNC; | ||
1694 | |||
1662 | spin_lock(&mdev->epoch_lock); | 1695 | spin_lock(&mdev->epoch_lock); |
1663 | e->epoch = mdev->current_epoch; | 1696 | e->epoch = mdev->current_epoch; |
1664 | atomic_inc(&e->epoch->epoch_size); | 1697 | atomic_inc(&e->epoch->epoch_size); |
1665 | atomic_inc(&e->epoch->active); | 1698 | atomic_inc(&e->epoch->active); |
1666 | spin_unlock(&mdev->epoch_lock); | 1699 | spin_unlock(&mdev->epoch_lock); |
1667 | 1700 | ||
1668 | dp_flags = be32_to_cpu(p->dp_flags); | ||
1669 | rw |= write_flags_to_bio(mdev, dp_flags); | ||
1670 | |||
1671 | if (dp_flags & DP_MAY_SET_IN_SYNC) | ||
1672 | e->flags |= EE_MAY_SET_IN_SYNC; | ||
1673 | |||
1674 | /* I'm the receiver, I do hold a net_cnt reference. */ | 1701 | /* I'm the receiver, I do hold a net_cnt reference. */ |
1675 | if (!mdev->net_conf->two_primaries) { | 1702 | if (!mdev->net_conf->two_primaries) { |
1676 | spin_lock_irq(&mdev->req_lock); | 1703 | spin_lock_irq(&mdev->req_lock); |
@@ -1773,7 +1800,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
1773 | put_ldev(mdev); | 1800 | put_ldev(mdev); |
1774 | wake_asender(mdev); | 1801 | wake_asender(mdev); |
1775 | finish_wait(&mdev->misc_wait, &wait); | 1802 | finish_wait(&mdev->misc_wait, &wait); |
1776 | return TRUE; | 1803 | return true; |
1777 | } | 1804 | } |
1778 | 1805 | ||
1779 | if (signal_pending(current)) { | 1806 | if (signal_pending(current)) { |
@@ -1829,11 +1856,10 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
1829 | } | 1856 | } |
1830 | 1857 | ||
1831 | if (drbd_submit_ee(mdev, e, rw, DRBD_FAULT_DT_WR) == 0) | 1858 | if (drbd_submit_ee(mdev, e, rw, DRBD_FAULT_DT_WR) == 0) |
1832 | return TRUE; | 1859 | return true; |
1833 | 1860 | ||
1834 | /* drbd_submit_ee currently fails for one reason only: | 1861 | /* don't care for the reason here */ |
1835 | * not being able to allocate enough bios. | 1862 | dev_err(DEV, "submit failed, triggering re-connect\n"); |
1836 | * Is dropping the connection going to help? */ | ||
1837 | spin_lock_irq(&mdev->req_lock); | 1863 | spin_lock_irq(&mdev->req_lock); |
1838 | list_del(&e->w.list); | 1864 | list_del(&e->w.list); |
1839 | hlist_del_init(&e->colision); | 1865 | hlist_del_init(&e->colision); |
@@ -1842,12 +1868,10 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
1842 | drbd_al_complete_io(mdev, e->sector); | 1868 | drbd_al_complete_io(mdev, e->sector); |
1843 | 1869 | ||
1844 | out_interrupted: | 1870 | out_interrupted: |
1845 | /* yes, the epoch_size now is imbalanced. | 1871 | drbd_may_finish_epoch(mdev, e->epoch, EV_PUT + EV_CLEANUP); |
1846 | * but we drop the connection anyways, so we don't have a chance to | ||
1847 | * receive a barrier... atomic_inc(&mdev->epoch_size); */ | ||
1848 | put_ldev(mdev); | 1872 | put_ldev(mdev); |
1849 | drbd_free_ee(mdev, e); | 1873 | drbd_free_ee(mdev, e); |
1850 | return FALSE; | 1874 | return false; |
1851 | } | 1875 | } |
1852 | 1876 | ||
1853 | /* We may throttle resync, if the lower device seems to be busy, | 1877 | /* We may throttle resync, if the lower device seems to be busy, |
@@ -1861,10 +1885,11 @@ out_interrupted: | |||
1861 | * The current sync rate used here uses only the most recent two step marks, | 1885 | * The current sync rate used here uses only the most recent two step marks, |
1862 | * to have a short time average so we can react faster. | 1886 | * to have a short time average so we can react faster. |
1863 | */ | 1887 | */ |
1864 | int drbd_rs_should_slow_down(struct drbd_conf *mdev) | 1888 | int drbd_rs_should_slow_down(struct drbd_conf *mdev, sector_t sector) |
1865 | { | 1889 | { |
1866 | struct gendisk *disk = mdev->ldev->backing_bdev->bd_contains->bd_disk; | 1890 | struct gendisk *disk = mdev->ldev->backing_bdev->bd_contains->bd_disk; |
1867 | unsigned long db, dt, dbdt; | 1891 | unsigned long db, dt, dbdt; |
1892 | struct lc_element *tmp; | ||
1868 | int curr_events; | 1893 | int curr_events; |
1869 | int throttle = 0; | 1894 | int throttle = 0; |
1870 | 1895 | ||
@@ -1872,9 +1897,22 @@ int drbd_rs_should_slow_down(struct drbd_conf *mdev) | |||
1872 | if (mdev->sync_conf.c_min_rate == 0) | 1897 | if (mdev->sync_conf.c_min_rate == 0) |
1873 | return 0; | 1898 | return 0; |
1874 | 1899 | ||
1900 | spin_lock_irq(&mdev->al_lock); | ||
1901 | tmp = lc_find(mdev->resync, BM_SECT_TO_EXT(sector)); | ||
1902 | if (tmp) { | ||
1903 | struct bm_extent *bm_ext = lc_entry(tmp, struct bm_extent, lce); | ||
1904 | if (test_bit(BME_PRIORITY, &bm_ext->flags)) { | ||
1905 | spin_unlock_irq(&mdev->al_lock); | ||
1906 | return 0; | ||
1907 | } | ||
1908 | /* Do not slow down if app IO is already waiting for this extent */ | ||
1909 | } | ||
1910 | spin_unlock_irq(&mdev->al_lock); | ||
1911 | |||
1875 | curr_events = (int)part_stat_read(&disk->part0, sectors[0]) + | 1912 | curr_events = (int)part_stat_read(&disk->part0, sectors[0]) + |
1876 | (int)part_stat_read(&disk->part0, sectors[1]) - | 1913 | (int)part_stat_read(&disk->part0, sectors[1]) - |
1877 | atomic_read(&mdev->rs_sect_ev); | 1914 | atomic_read(&mdev->rs_sect_ev); |
1915 | |||
1878 | if (!mdev->rs_last_events || curr_events - mdev->rs_last_events > 64) { | 1916 | if (!mdev->rs_last_events || curr_events - mdev->rs_last_events > 64) { |
1879 | unsigned long rs_left; | 1917 | unsigned long rs_left; |
1880 | int i; | 1918 | int i; |
@@ -1883,8 +1921,12 @@ int drbd_rs_should_slow_down(struct drbd_conf *mdev) | |||
1883 | 1921 | ||
1884 | /* sync speed average over the last 2*DRBD_SYNC_MARK_STEP, | 1922 | /* sync speed average over the last 2*DRBD_SYNC_MARK_STEP, |
1885 | * approx. */ | 1923 | * approx. */ |
1886 | i = (mdev->rs_last_mark + DRBD_SYNC_MARKS-2) % DRBD_SYNC_MARKS; | 1924 | i = (mdev->rs_last_mark + DRBD_SYNC_MARKS-1) % DRBD_SYNC_MARKS; |
1887 | rs_left = drbd_bm_total_weight(mdev) - mdev->rs_failed; | 1925 | |
1926 | if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T) | ||
1927 | rs_left = mdev->ov_left; | ||
1928 | else | ||
1929 | rs_left = drbd_bm_total_weight(mdev) - mdev->rs_failed; | ||
1888 | 1930 | ||
1889 | dt = ((long)jiffies - (long)mdev->rs_mark_time[i]) / HZ; | 1931 | dt = ((long)jiffies - (long)mdev->rs_mark_time[i]) / HZ; |
1890 | if (!dt) | 1932 | if (!dt) |
@@ -1912,15 +1954,15 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, un | |||
1912 | sector = be64_to_cpu(p->sector); | 1954 | sector = be64_to_cpu(p->sector); |
1913 | size = be32_to_cpu(p->blksize); | 1955 | size = be32_to_cpu(p->blksize); |
1914 | 1956 | ||
1915 | if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) { | 1957 | if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_BIO_SIZE) { |
1916 | dev_err(DEV, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__, | 1958 | dev_err(DEV, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__, |
1917 | (unsigned long long)sector, size); | 1959 | (unsigned long long)sector, size); |
1918 | return FALSE; | 1960 | return false; |
1919 | } | 1961 | } |
1920 | if (sector + (size>>9) > capacity) { | 1962 | if (sector + (size>>9) > capacity) { |
1921 | dev_err(DEV, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__, | 1963 | dev_err(DEV, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__, |
1922 | (unsigned long long)sector, size); | 1964 | (unsigned long long)sector, size); |
1923 | return FALSE; | 1965 | return false; |
1924 | } | 1966 | } |
1925 | 1967 | ||
1926 | if (!get_ldev_if_state(mdev, D_UP_TO_DATE)) { | 1968 | if (!get_ldev_if_state(mdev, D_UP_TO_DATE)) { |
@@ -1957,7 +1999,7 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, un | |||
1957 | e = drbd_alloc_ee(mdev, p->block_id, sector, size, GFP_NOIO); | 1999 | e = drbd_alloc_ee(mdev, p->block_id, sector, size, GFP_NOIO); |
1958 | if (!e) { | 2000 | if (!e) { |
1959 | put_ldev(mdev); | 2001 | put_ldev(mdev); |
1960 | return FALSE; | 2002 | return false; |
1961 | } | 2003 | } |
1962 | 2004 | ||
1963 | switch (cmd) { | 2005 | switch (cmd) { |
@@ -1970,6 +2012,8 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, un | |||
1970 | case P_RS_DATA_REQUEST: | 2012 | case P_RS_DATA_REQUEST: |
1971 | e->w.cb = w_e_end_rsdata_req; | 2013 | e->w.cb = w_e_end_rsdata_req; |
1972 | fault_type = DRBD_FAULT_RS_RD; | 2014 | fault_type = DRBD_FAULT_RS_RD; |
2015 | /* used in the sector offset progress display */ | ||
2016 | mdev->bm_resync_fo = BM_SECT_TO_BIT(sector); | ||
1973 | break; | 2017 | break; |
1974 | 2018 | ||
1975 | case P_OV_REPLY: | 2019 | case P_OV_REPLY: |
@@ -1991,7 +2035,11 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, un | |||
1991 | if (cmd == P_CSUM_RS_REQUEST) { | 2035 | if (cmd == P_CSUM_RS_REQUEST) { |
1992 | D_ASSERT(mdev->agreed_pro_version >= 89); | 2036 | D_ASSERT(mdev->agreed_pro_version >= 89); |
1993 | e->w.cb = w_e_end_csum_rs_req; | 2037 | e->w.cb = w_e_end_csum_rs_req; |
2038 | /* used in the sector offset progress display */ | ||
2039 | mdev->bm_resync_fo = BM_SECT_TO_BIT(sector); | ||
1994 | } else if (cmd == P_OV_REPLY) { | 2040 | } else if (cmd == P_OV_REPLY) { |
2041 | /* track progress, we may need to throttle */ | ||
2042 | atomic_add(size >> 9, &mdev->rs_sect_in); | ||
1995 | e->w.cb = w_e_end_ov_reply; | 2043 | e->w.cb = w_e_end_ov_reply; |
1996 | dec_rs_pending(mdev); | 2044 | dec_rs_pending(mdev); |
1997 | /* drbd_rs_begin_io done when we sent this request, | 2045 | /* drbd_rs_begin_io done when we sent this request, |
@@ -2003,9 +2051,16 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, un | |||
2003 | case P_OV_REQUEST: | 2051 | case P_OV_REQUEST: |
2004 | if (mdev->ov_start_sector == ~(sector_t)0 && | 2052 | if (mdev->ov_start_sector == ~(sector_t)0 && |
2005 | mdev->agreed_pro_version >= 90) { | 2053 | mdev->agreed_pro_version >= 90) { |
2054 | unsigned long now = jiffies; | ||
2055 | int i; | ||
2006 | mdev->ov_start_sector = sector; | 2056 | mdev->ov_start_sector = sector; |
2007 | mdev->ov_position = sector; | 2057 | mdev->ov_position = sector; |
2008 | mdev->ov_left = mdev->rs_total - BM_SECT_TO_BIT(sector); | 2058 | mdev->ov_left = drbd_bm_bits(mdev) - BM_SECT_TO_BIT(sector); |
2059 | mdev->rs_total = mdev->ov_left; | ||
2060 | for (i = 0; i < DRBD_SYNC_MARKS; i++) { | ||
2061 | mdev->rs_mark_left[i] = mdev->ov_left; | ||
2062 | mdev->rs_mark_time[i] = now; | ||
2063 | } | ||
2009 | dev_info(DEV, "Online Verify start sector: %llu\n", | 2064 | dev_info(DEV, "Online Verify start sector: %llu\n", |
2010 | (unsigned long long)sector); | 2065 | (unsigned long long)sector); |
2011 | } | 2066 | } |
@@ -2042,9 +2097,9 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, un | |||
2042 | * we would also throttle its application reads. | 2097 | * we would also throttle its application reads. |
2043 | * In that case, throttling is done on the SyncTarget only. | 2098 | * In that case, throttling is done on the SyncTarget only. |
2044 | */ | 2099 | */ |
2045 | if (mdev->state.peer != R_PRIMARY && drbd_rs_should_slow_down(mdev)) | 2100 | if (mdev->state.peer != R_PRIMARY && drbd_rs_should_slow_down(mdev, sector)) |
2046 | msleep(100); | 2101 | schedule_timeout_uninterruptible(HZ/10); |
2047 | if (drbd_rs_begin_io(mdev, e->sector)) | 2102 | if (drbd_rs_begin_io(mdev, sector)) |
2048 | goto out_free_e; | 2103 | goto out_free_e; |
2049 | 2104 | ||
2050 | submit_for_resync: | 2105 | submit_for_resync: |
@@ -2057,11 +2112,10 @@ submit: | |||
2057 | spin_unlock_irq(&mdev->req_lock); | 2112 | spin_unlock_irq(&mdev->req_lock); |
2058 | 2113 | ||
2059 | if (drbd_submit_ee(mdev, e, READ, fault_type) == 0) | 2114 | if (drbd_submit_ee(mdev, e, READ, fault_type) == 0) |
2060 | return TRUE; | 2115 | return true; |
2061 | 2116 | ||
2062 | /* drbd_submit_ee currently fails for one reason only: | 2117 | /* don't care for the reason here */ |
2063 | * not being able to allocate enough bios. | 2118 | dev_err(DEV, "submit failed, triggering re-connect\n"); |
2064 | * Is dropping the connection going to help? */ | ||
2065 | spin_lock_irq(&mdev->req_lock); | 2119 | spin_lock_irq(&mdev->req_lock); |
2066 | list_del(&e->w.list); | 2120 | list_del(&e->w.list); |
2067 | spin_unlock_irq(&mdev->req_lock); | 2121 | spin_unlock_irq(&mdev->req_lock); |
@@ -2070,7 +2124,7 @@ submit: | |||
2070 | out_free_e: | 2124 | out_free_e: |
2071 | put_ldev(mdev); | 2125 | put_ldev(mdev); |
2072 | drbd_free_ee(mdev, e); | 2126 | drbd_free_ee(mdev, e); |
2073 | return FALSE; | 2127 | return false; |
2074 | } | 2128 | } |
2075 | 2129 | ||
2076 | static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local) | 2130 | static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local) |
@@ -2147,10 +2201,7 @@ static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local) | |||
2147 | 2201 | ||
2148 | static int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local) | 2202 | static int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local) |
2149 | { | 2203 | { |
2150 | int self, peer, hg, rv = -100; | 2204 | int hg, rv = -100; |
2151 | |||
2152 | self = mdev->ldev->md.uuid[UI_BITMAP] & 1; | ||
2153 | peer = mdev->p_uuid[UI_BITMAP] & 1; | ||
2154 | 2205 | ||
2155 | switch (mdev->net_conf->after_sb_1p) { | 2206 | switch (mdev->net_conf->after_sb_1p) { |
2156 | case ASB_DISCARD_YOUNGER_PRI: | 2207 | case ASB_DISCARD_YOUNGER_PRI: |
@@ -2177,12 +2228,14 @@ static int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local) | |||
2177 | case ASB_CALL_HELPER: | 2228 | case ASB_CALL_HELPER: |
2178 | hg = drbd_asb_recover_0p(mdev); | 2229 | hg = drbd_asb_recover_0p(mdev); |
2179 | if (hg == -1 && mdev->state.role == R_PRIMARY) { | 2230 | if (hg == -1 && mdev->state.role == R_PRIMARY) { |
2180 | self = drbd_set_role(mdev, R_SECONDARY, 0); | 2231 | enum drbd_state_rv rv2; |
2232 | |||
2233 | drbd_set_role(mdev, R_SECONDARY, 0); | ||
2181 | /* drbd_change_state() does not sleep while in SS_IN_TRANSIENT_STATE, | 2234 | /* drbd_change_state() does not sleep while in SS_IN_TRANSIENT_STATE, |
2182 | * we might be here in C_WF_REPORT_PARAMS which is transient. | 2235 | * we might be here in C_WF_REPORT_PARAMS which is transient. |
2183 | * we do not need to wait for the after state change work either. */ | 2236 | * we do not need to wait for the after state change work either. */ |
2184 | self = drbd_change_state(mdev, CS_VERBOSE, NS(role, R_SECONDARY)); | 2237 | rv2 = drbd_change_state(mdev, CS_VERBOSE, NS(role, R_SECONDARY)); |
2185 | if (self != SS_SUCCESS) { | 2238 | if (rv2 != SS_SUCCESS) { |
2186 | drbd_khelper(mdev, "pri-lost-after-sb"); | 2239 | drbd_khelper(mdev, "pri-lost-after-sb"); |
2187 | } else { | 2240 | } else { |
2188 | dev_warn(DEV, "Successfully gave up primary role.\n"); | 2241 | dev_warn(DEV, "Successfully gave up primary role.\n"); |
@@ -2197,10 +2250,7 @@ static int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local) | |||
2197 | 2250 | ||
2198 | static int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local) | 2251 | static int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local) |
2199 | { | 2252 | { |
2200 | int self, peer, hg, rv = -100; | 2253 | int hg, rv = -100; |
2201 | |||
2202 | self = mdev->ldev->md.uuid[UI_BITMAP] & 1; | ||
2203 | peer = mdev->p_uuid[UI_BITMAP] & 1; | ||
2204 | 2254 | ||
2205 | switch (mdev->net_conf->after_sb_2p) { | 2255 | switch (mdev->net_conf->after_sb_2p) { |
2206 | case ASB_DISCARD_YOUNGER_PRI: | 2256 | case ASB_DISCARD_YOUNGER_PRI: |
@@ -2220,11 +2270,13 @@ static int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local) | |||
2220 | case ASB_CALL_HELPER: | 2270 | case ASB_CALL_HELPER: |
2221 | hg = drbd_asb_recover_0p(mdev); | 2271 | hg = drbd_asb_recover_0p(mdev); |
2222 | if (hg == -1) { | 2272 | if (hg == -1) { |
2273 | enum drbd_state_rv rv2; | ||
2274 | |||
2223 | /* drbd_change_state() does not sleep while in SS_IN_TRANSIENT_STATE, | 2275 | /* drbd_change_state() does not sleep while in SS_IN_TRANSIENT_STATE, |
2224 | * we might be here in C_WF_REPORT_PARAMS which is transient. | 2276 | * we might be here in C_WF_REPORT_PARAMS which is transient. |
2225 | * we do not need to wait for the after state change work either. */ | 2277 | * we do not need to wait for the after state change work either. */ |
2226 | self = drbd_change_state(mdev, CS_VERBOSE, NS(role, R_SECONDARY)); | 2278 | rv2 = drbd_change_state(mdev, CS_VERBOSE, NS(role, R_SECONDARY)); |
2227 | if (self != SS_SUCCESS) { | 2279 | if (rv2 != SS_SUCCESS) { |
2228 | drbd_khelper(mdev, "pri-lost-after-sb"); | 2280 | drbd_khelper(mdev, "pri-lost-after-sb"); |
2229 | } else { | 2281 | } else { |
2230 | dev_warn(DEV, "Successfully gave up primary role.\n"); | 2282 | dev_warn(DEV, "Successfully gave up primary role.\n"); |
@@ -2263,6 +2315,8 @@ static void drbd_uuid_dump(struct drbd_conf *mdev, char *text, u64 *uuid, | |||
2263 | -2 C_SYNC_TARGET set BitMap | 2315 | -2 C_SYNC_TARGET set BitMap |
2264 | -100 after split brain, disconnect | 2316 | -100 after split brain, disconnect |
2265 | -1000 unrelated data | 2317 | -1000 unrelated data |
2318 | -1091 requires proto 91 | ||
2319 | -1096 requires proto 96 | ||
2266 | */ | 2320 | */ |
2267 | static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(local) | 2321 | static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(local) |
2268 | { | 2322 | { |
@@ -2292,7 +2346,7 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l | |||
2292 | if (mdev->p_uuid[UI_BITMAP] == (u64)0 && mdev->ldev->md.uuid[UI_BITMAP] != (u64)0) { | 2346 | if (mdev->p_uuid[UI_BITMAP] == (u64)0 && mdev->ldev->md.uuid[UI_BITMAP] != (u64)0) { |
2293 | 2347 | ||
2294 | if (mdev->agreed_pro_version < 91) | 2348 | if (mdev->agreed_pro_version < 91) |
2295 | return -1001; | 2349 | return -1091; |
2296 | 2350 | ||
2297 | if ((mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1)) && | 2351 | if ((mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1)) && |
2298 | (mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START + 1] & ~((u64)1))) { | 2352 | (mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START + 1] & ~((u64)1))) { |
@@ -2313,7 +2367,7 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l | |||
2313 | if (mdev->ldev->md.uuid[UI_BITMAP] == (u64)0 && mdev->p_uuid[UI_BITMAP] != (u64)0) { | 2367 | if (mdev->ldev->md.uuid[UI_BITMAP] == (u64)0 && mdev->p_uuid[UI_BITMAP] != (u64)0) { |
2314 | 2368 | ||
2315 | if (mdev->agreed_pro_version < 91) | 2369 | if (mdev->agreed_pro_version < 91) |
2316 | return -1001; | 2370 | return -1091; |
2317 | 2371 | ||
2318 | if ((mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (mdev->p_uuid[UI_BITMAP] & ~((u64)1)) && | 2372 | if ((mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (mdev->p_uuid[UI_BITMAP] & ~((u64)1)) && |
2319 | (mdev->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1))) { | 2373 | (mdev->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1))) { |
@@ -2358,17 +2412,22 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l | |||
2358 | *rule_nr = 51; | 2412 | *rule_nr = 51; |
2359 | peer = mdev->p_uuid[UI_HISTORY_START] & ~((u64)1); | 2413 | peer = mdev->p_uuid[UI_HISTORY_START] & ~((u64)1); |
2360 | if (self == peer) { | 2414 | if (self == peer) { |
2361 | self = mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1); | 2415 | if (mdev->agreed_pro_version < 96 ? |
2362 | peer = mdev->p_uuid[UI_HISTORY_START + 1] & ~((u64)1); | 2416 | (mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == |
2363 | if (self == peer) { | 2417 | (mdev->p_uuid[UI_HISTORY_START + 1] & ~((u64)1)) : |
2418 | peer + UUID_NEW_BM_OFFSET == (mdev->p_uuid[UI_BITMAP] & ~((u64)1))) { | ||
2364 | /* The last P_SYNC_UUID did not get though. Undo the last start of | 2419 | /* The last P_SYNC_UUID did not get though. Undo the last start of |
2365 | resync as sync source modifications of the peer's UUIDs. */ | 2420 | resync as sync source modifications of the peer's UUIDs. */ |
2366 | 2421 | ||
2367 | if (mdev->agreed_pro_version < 91) | 2422 | if (mdev->agreed_pro_version < 91) |
2368 | return -1001; | 2423 | return -1091; |
2369 | 2424 | ||
2370 | mdev->p_uuid[UI_BITMAP] = mdev->p_uuid[UI_HISTORY_START]; | 2425 | mdev->p_uuid[UI_BITMAP] = mdev->p_uuid[UI_HISTORY_START]; |
2371 | mdev->p_uuid[UI_HISTORY_START] = mdev->p_uuid[UI_HISTORY_START + 1]; | 2426 | mdev->p_uuid[UI_HISTORY_START] = mdev->p_uuid[UI_HISTORY_START + 1]; |
2427 | |||
2428 | dev_info(DEV, "Did not got last syncUUID packet, corrected:\n"); | ||
2429 | drbd_uuid_dump(mdev, "peer", mdev->p_uuid, mdev->p_uuid[UI_SIZE], mdev->p_uuid[UI_FLAGS]); | ||
2430 | |||
2372 | return -1; | 2431 | return -1; |
2373 | } | 2432 | } |
2374 | } | 2433 | } |
@@ -2390,20 +2449,20 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l | |||
2390 | *rule_nr = 71; | 2449 | *rule_nr = 71; |
2391 | self = mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1); | 2450 | self = mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1); |
2392 | if (self == peer) { | 2451 | if (self == peer) { |
2393 | self = mdev->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1); | 2452 | if (mdev->agreed_pro_version < 96 ? |
2394 | peer = mdev->p_uuid[UI_HISTORY_START] & ~((u64)1); | 2453 | (mdev->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1)) == |
2395 | if (self == peer) { | 2454 | (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1)) : |
2455 | self + UUID_NEW_BM_OFFSET == (mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1))) { | ||
2396 | /* The last P_SYNC_UUID did not get though. Undo the last start of | 2456 | /* The last P_SYNC_UUID did not get though. Undo the last start of |
2397 | resync as sync source modifications of our UUIDs. */ | 2457 | resync as sync source modifications of our UUIDs. */ |
2398 | 2458 | ||
2399 | if (mdev->agreed_pro_version < 91) | 2459 | if (mdev->agreed_pro_version < 91) |
2400 | return -1001; | 2460 | return -1091; |
2401 | 2461 | ||
2402 | _drbd_uuid_set(mdev, UI_BITMAP, mdev->ldev->md.uuid[UI_HISTORY_START]); | 2462 | _drbd_uuid_set(mdev, UI_BITMAP, mdev->ldev->md.uuid[UI_HISTORY_START]); |
2403 | _drbd_uuid_set(mdev, UI_HISTORY_START, mdev->ldev->md.uuid[UI_HISTORY_START + 1]); | 2463 | _drbd_uuid_set(mdev, UI_HISTORY_START, mdev->ldev->md.uuid[UI_HISTORY_START + 1]); |
2404 | 2464 | ||
2405 | dev_info(DEV, "Undid last start of resync:\n"); | 2465 | dev_info(DEV, "Last syncUUID did not get through, corrected:\n"); |
2406 | |||
2407 | drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid, | 2466 | drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid, |
2408 | mdev->state.disk >= D_NEGOTIATING ? drbd_bm_total_weight(mdev) : 0, 0); | 2467 | mdev->state.disk >= D_NEGOTIATING ? drbd_bm_total_weight(mdev) : 0, 0); |
2409 | 2468 | ||
@@ -2466,8 +2525,8 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol | |||
2466 | dev_alert(DEV, "Unrelated data, aborting!\n"); | 2525 | dev_alert(DEV, "Unrelated data, aborting!\n"); |
2467 | return C_MASK; | 2526 | return C_MASK; |
2468 | } | 2527 | } |
2469 | if (hg == -1001) { | 2528 | if (hg < -1000) { |
2470 | dev_alert(DEV, "To resolve this both sides have to support at least protocol\n"); | 2529 | dev_alert(DEV, "To resolve this both sides have to support at least protocol %d\n", -hg - 1000); |
2471 | return C_MASK; | 2530 | return C_MASK; |
2472 | } | 2531 | } |
2473 | 2532 | ||
@@ -2566,7 +2625,8 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol | |||
2566 | 2625 | ||
2567 | if (abs(hg) >= 2) { | 2626 | if (abs(hg) >= 2) { |
2568 | dev_info(DEV, "Writing the whole bitmap, full sync required after drbd_sync_handshake.\n"); | 2627 | dev_info(DEV, "Writing the whole bitmap, full sync required after drbd_sync_handshake.\n"); |
2569 | if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write, "set_n_write from sync_handshake")) | 2628 | if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write, "set_n_write from sync_handshake", |
2629 | BM_LOCKED_SET_ALLOWED)) | ||
2570 | return C_MASK; | 2630 | return C_MASK; |
2571 | } | 2631 | } |
2572 | 2632 | ||
@@ -2660,7 +2720,7 @@ static int receive_protocol(struct drbd_conf *mdev, enum drbd_packets cmd, unsig | |||
2660 | unsigned char *my_alg = mdev->net_conf->integrity_alg; | 2720 | unsigned char *my_alg = mdev->net_conf->integrity_alg; |
2661 | 2721 | ||
2662 | if (drbd_recv(mdev, p_integrity_alg, data_size) != data_size) | 2722 | if (drbd_recv(mdev, p_integrity_alg, data_size) != data_size) |
2663 | return FALSE; | 2723 | return false; |
2664 | 2724 | ||
2665 | p_integrity_alg[SHARED_SECRET_MAX-1] = 0; | 2725 | p_integrity_alg[SHARED_SECRET_MAX-1] = 0; |
2666 | if (strcmp(p_integrity_alg, my_alg)) { | 2726 | if (strcmp(p_integrity_alg, my_alg)) { |
@@ -2671,11 +2731,11 @@ static int receive_protocol(struct drbd_conf *mdev, enum drbd_packets cmd, unsig | |||
2671 | my_alg[0] ? my_alg : (unsigned char *)"<not-used>"); | 2731 | my_alg[0] ? my_alg : (unsigned char *)"<not-used>"); |
2672 | } | 2732 | } |
2673 | 2733 | ||
2674 | return TRUE; | 2734 | return true; |
2675 | 2735 | ||
2676 | disconnect: | 2736 | disconnect: |
2677 | drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); | 2737 | drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); |
2678 | return FALSE; | 2738 | return false; |
2679 | } | 2739 | } |
2680 | 2740 | ||
2681 | /* helper function | 2741 | /* helper function |
@@ -2707,7 +2767,7 @@ struct crypto_hash *drbd_crypto_alloc_digest_safe(const struct drbd_conf *mdev, | |||
2707 | 2767 | ||
2708 | static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int packet_size) | 2768 | static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int packet_size) |
2709 | { | 2769 | { |
2710 | int ok = TRUE; | 2770 | int ok = true; |
2711 | struct p_rs_param_95 *p = &mdev->data.rbuf.rs_param_95; | 2771 | struct p_rs_param_95 *p = &mdev->data.rbuf.rs_param_95; |
2712 | unsigned int header_size, data_size, exp_max_sz; | 2772 | unsigned int header_size, data_size, exp_max_sz; |
2713 | struct crypto_hash *verify_tfm = NULL; | 2773 | struct crypto_hash *verify_tfm = NULL; |
@@ -2725,7 +2785,7 @@ static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packets cmd, unsi | |||
2725 | if (packet_size > exp_max_sz) { | 2785 | if (packet_size > exp_max_sz) { |
2726 | dev_err(DEV, "SyncParam packet too long: received %u, expected <= %u bytes\n", | 2786 | dev_err(DEV, "SyncParam packet too long: received %u, expected <= %u bytes\n", |
2727 | packet_size, exp_max_sz); | 2787 | packet_size, exp_max_sz); |
2728 | return FALSE; | 2788 | return false; |
2729 | } | 2789 | } |
2730 | 2790 | ||
2731 | if (apv <= 88) { | 2791 | if (apv <= 88) { |
@@ -2745,7 +2805,7 @@ static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packets cmd, unsi | |||
2745 | memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX); | 2805 | memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX); |
2746 | 2806 | ||
2747 | if (drbd_recv(mdev, &p->head.payload, header_size) != header_size) | 2807 | if (drbd_recv(mdev, &p->head.payload, header_size) != header_size) |
2748 | return FALSE; | 2808 | return false; |
2749 | 2809 | ||
2750 | mdev->sync_conf.rate = be32_to_cpu(p->rate); | 2810 | mdev->sync_conf.rate = be32_to_cpu(p->rate); |
2751 | 2811 | ||
@@ -2755,11 +2815,11 @@ static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packets cmd, unsi | |||
2755 | dev_err(DEV, "verify-alg too long, " | 2815 | dev_err(DEV, "verify-alg too long, " |
2756 | "peer wants %u, accepting only %u byte\n", | 2816 | "peer wants %u, accepting only %u byte\n", |
2757 | data_size, SHARED_SECRET_MAX); | 2817 | data_size, SHARED_SECRET_MAX); |
2758 | return FALSE; | 2818 | return false; |
2759 | } | 2819 | } |
2760 | 2820 | ||
2761 | if (drbd_recv(mdev, p->verify_alg, data_size) != data_size) | 2821 | if (drbd_recv(mdev, p->verify_alg, data_size) != data_size) |
2762 | return FALSE; | 2822 | return false; |
2763 | 2823 | ||
2764 | /* we expect NUL terminated string */ | 2824 | /* we expect NUL terminated string */ |
2765 | /* but just in case someone tries to be evil */ | 2825 | /* but just in case someone tries to be evil */ |
@@ -2853,7 +2913,7 @@ disconnect: | |||
2853 | /* but free the verify_tfm again, if csums_tfm did not work out */ | 2913 | /* but free the verify_tfm again, if csums_tfm did not work out */ |
2854 | crypto_free_hash(verify_tfm); | 2914 | crypto_free_hash(verify_tfm); |
2855 | drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); | 2915 | drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); |
2856 | return FALSE; | 2916 | return false; |
2857 | } | 2917 | } |
2858 | 2918 | ||
2859 | static void drbd_setup_order_type(struct drbd_conf *mdev, int peer) | 2919 | static void drbd_setup_order_type(struct drbd_conf *mdev, int peer) |
@@ -2879,7 +2939,7 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
2879 | { | 2939 | { |
2880 | struct p_sizes *p = &mdev->data.rbuf.sizes; | 2940 | struct p_sizes *p = &mdev->data.rbuf.sizes; |
2881 | enum determine_dev_size dd = unchanged; | 2941 | enum determine_dev_size dd = unchanged; |
2882 | unsigned int max_seg_s; | 2942 | unsigned int max_bio_size; |
2883 | sector_t p_size, p_usize, my_usize; | 2943 | sector_t p_size, p_usize, my_usize; |
2884 | int ldsc = 0; /* local disk size changed */ | 2944 | int ldsc = 0; /* local disk size changed */ |
2885 | enum dds_flags ddsf; | 2945 | enum dds_flags ddsf; |
@@ -2890,7 +2950,7 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
2890 | if (p_size == 0 && mdev->state.disk == D_DISKLESS) { | 2950 | if (p_size == 0 && mdev->state.disk == D_DISKLESS) { |
2891 | dev_err(DEV, "some backing storage is needed\n"); | 2951 | dev_err(DEV, "some backing storage is needed\n"); |
2892 | drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); | 2952 | drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); |
2893 | return FALSE; | 2953 | return false; |
2894 | } | 2954 | } |
2895 | 2955 | ||
2896 | /* just store the peer's disk size for now. | 2956 | /* just store the peer's disk size for now. |
@@ -2927,18 +2987,17 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
2927 | drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); | 2987 | drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); |
2928 | mdev->ldev->dc.disk_size = my_usize; | 2988 | mdev->ldev->dc.disk_size = my_usize; |
2929 | put_ldev(mdev); | 2989 | put_ldev(mdev); |
2930 | return FALSE; | 2990 | return false; |
2931 | } | 2991 | } |
2932 | put_ldev(mdev); | 2992 | put_ldev(mdev); |
2933 | } | 2993 | } |
2934 | #undef min_not_zero | ||
2935 | 2994 | ||
2936 | ddsf = be16_to_cpu(p->dds_flags); | 2995 | ddsf = be16_to_cpu(p->dds_flags); |
2937 | if (get_ldev(mdev)) { | 2996 | if (get_ldev(mdev)) { |
2938 | dd = drbd_determin_dev_size(mdev, ddsf); | 2997 | dd = drbd_determin_dev_size(mdev, ddsf); |
2939 | put_ldev(mdev); | 2998 | put_ldev(mdev); |
2940 | if (dd == dev_size_error) | 2999 | if (dd == dev_size_error) |
2941 | return FALSE; | 3000 | return false; |
2942 | drbd_md_sync(mdev); | 3001 | drbd_md_sync(mdev); |
2943 | } else { | 3002 | } else { |
2944 | /* I am diskless, need to accept the peer's size. */ | 3003 | /* I am diskless, need to accept the peer's size. */ |
@@ -2952,14 +3011,14 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
2952 | } | 3011 | } |
2953 | 3012 | ||
2954 | if (mdev->agreed_pro_version < 94) | 3013 | if (mdev->agreed_pro_version < 94) |
2955 | max_seg_s = be32_to_cpu(p->max_segment_size); | 3014 | max_bio_size = be32_to_cpu(p->max_bio_size); |
2956 | else if (mdev->agreed_pro_version == 94) | 3015 | else if (mdev->agreed_pro_version == 94) |
2957 | max_seg_s = DRBD_MAX_SIZE_H80_PACKET; | 3016 | max_bio_size = DRBD_MAX_SIZE_H80_PACKET; |
2958 | else /* drbd 8.3.8 onwards */ | 3017 | else /* drbd 8.3.8 onwards */ |
2959 | max_seg_s = DRBD_MAX_SEGMENT_SIZE; | 3018 | max_bio_size = DRBD_MAX_BIO_SIZE; |
2960 | 3019 | ||
2961 | if (max_seg_s != queue_max_segment_size(mdev->rq_queue)) | 3020 | if (max_bio_size != queue_max_hw_sectors(mdev->rq_queue) << 9) |
2962 | drbd_setup_queue_param(mdev, max_seg_s); | 3021 | drbd_setup_queue_param(mdev, max_bio_size); |
2963 | 3022 | ||
2964 | drbd_setup_order_type(mdev, be16_to_cpu(p->queue_order_type)); | 3023 | drbd_setup_order_type(mdev, be16_to_cpu(p->queue_order_type)); |
2965 | put_ldev(mdev); | 3024 | put_ldev(mdev); |
@@ -2985,14 +3044,14 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
2985 | } | 3044 | } |
2986 | } | 3045 | } |
2987 | 3046 | ||
2988 | return TRUE; | 3047 | return true; |
2989 | } | 3048 | } |
2990 | 3049 | ||
2991 | static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) | 3050 | static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) |
2992 | { | 3051 | { |
2993 | struct p_uuids *p = &mdev->data.rbuf.uuids; | 3052 | struct p_uuids *p = &mdev->data.rbuf.uuids; |
2994 | u64 *p_uuid; | 3053 | u64 *p_uuid; |
2995 | int i; | 3054 | int i, updated_uuids = 0; |
2996 | 3055 | ||
2997 | p_uuid = kmalloc(sizeof(u64)*UI_EXTENDED_SIZE, GFP_NOIO); | 3056 | p_uuid = kmalloc(sizeof(u64)*UI_EXTENDED_SIZE, GFP_NOIO); |
2998 | 3057 | ||
@@ -3009,7 +3068,7 @@ static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
3009 | dev_err(DEV, "Can only connect to data with current UUID=%016llX\n", | 3068 | dev_err(DEV, "Can only connect to data with current UUID=%016llX\n", |
3010 | (unsigned long long)mdev->ed_uuid); | 3069 | (unsigned long long)mdev->ed_uuid); |
3011 | drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); | 3070 | drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); |
3012 | return FALSE; | 3071 | return false; |
3013 | } | 3072 | } |
3014 | 3073 | ||
3015 | if (get_ldev(mdev)) { | 3074 | if (get_ldev(mdev)) { |
@@ -3021,19 +3080,21 @@ static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
3021 | if (skip_initial_sync) { | 3080 | if (skip_initial_sync) { |
3022 | dev_info(DEV, "Accepted new current UUID, preparing to skip initial sync\n"); | 3081 | dev_info(DEV, "Accepted new current UUID, preparing to skip initial sync\n"); |
3023 | drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write, | 3082 | drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write, |
3024 | "clear_n_write from receive_uuids"); | 3083 | "clear_n_write from receive_uuids", |
3084 | BM_LOCKED_TEST_ALLOWED); | ||
3025 | _drbd_uuid_set(mdev, UI_CURRENT, p_uuid[UI_CURRENT]); | 3085 | _drbd_uuid_set(mdev, UI_CURRENT, p_uuid[UI_CURRENT]); |
3026 | _drbd_uuid_set(mdev, UI_BITMAP, 0); | 3086 | _drbd_uuid_set(mdev, UI_BITMAP, 0); |
3027 | _drbd_set_state(_NS2(mdev, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE), | 3087 | _drbd_set_state(_NS2(mdev, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE), |
3028 | CS_VERBOSE, NULL); | 3088 | CS_VERBOSE, NULL); |
3029 | drbd_md_sync(mdev); | 3089 | drbd_md_sync(mdev); |
3090 | updated_uuids = 1; | ||
3030 | } | 3091 | } |
3031 | put_ldev(mdev); | 3092 | put_ldev(mdev); |
3032 | } else if (mdev->state.disk < D_INCONSISTENT && | 3093 | } else if (mdev->state.disk < D_INCONSISTENT && |
3033 | mdev->state.role == R_PRIMARY) { | 3094 | mdev->state.role == R_PRIMARY) { |
3034 | /* I am a diskless primary, the peer just created a new current UUID | 3095 | /* I am a diskless primary, the peer just created a new current UUID |
3035 | for me. */ | 3096 | for me. */ |
3036 | drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]); | 3097 | updated_uuids = drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]); |
3037 | } | 3098 | } |
3038 | 3099 | ||
3039 | /* Before we test for the disk state, we should wait until an eventually | 3100 | /* Before we test for the disk state, we should wait until an eventually |
@@ -3042,9 +3103,12 @@ static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
3042 | new disk state... */ | 3103 | new disk state... */ |
3043 | wait_event(mdev->misc_wait, !test_bit(CLUSTER_ST_CHANGE, &mdev->flags)); | 3104 | wait_event(mdev->misc_wait, !test_bit(CLUSTER_ST_CHANGE, &mdev->flags)); |
3044 | if (mdev->state.conn >= C_CONNECTED && mdev->state.disk < D_INCONSISTENT) | 3105 | if (mdev->state.conn >= C_CONNECTED && mdev->state.disk < D_INCONSISTENT) |
3045 | drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]); | 3106 | updated_uuids |= drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]); |
3046 | 3107 | ||
3047 | return TRUE; | 3108 | if (updated_uuids) |
3109 | drbd_print_uuids(mdev, "receiver updated UUIDs to"); | ||
3110 | |||
3111 | return true; | ||
3048 | } | 3112 | } |
3049 | 3113 | ||
3050 | /** | 3114 | /** |
@@ -3081,7 +3145,7 @@ static int receive_req_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsi | |||
3081 | { | 3145 | { |
3082 | struct p_req_state *p = &mdev->data.rbuf.req_state; | 3146 | struct p_req_state *p = &mdev->data.rbuf.req_state; |
3083 | union drbd_state mask, val; | 3147 | union drbd_state mask, val; |
3084 | int rv; | 3148 | enum drbd_state_rv rv; |
3085 | 3149 | ||
3086 | mask.i = be32_to_cpu(p->mask); | 3150 | mask.i = be32_to_cpu(p->mask); |
3087 | val.i = be32_to_cpu(p->val); | 3151 | val.i = be32_to_cpu(p->val); |
@@ -3089,7 +3153,7 @@ static int receive_req_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsi | |||
3089 | if (test_bit(DISCARD_CONCURRENT, &mdev->flags) && | 3153 | if (test_bit(DISCARD_CONCURRENT, &mdev->flags) && |
3090 | test_bit(CLUSTER_ST_CHANGE, &mdev->flags)) { | 3154 | test_bit(CLUSTER_ST_CHANGE, &mdev->flags)) { |
3091 | drbd_send_sr_reply(mdev, SS_CONCURRENT_ST_CHG); | 3155 | drbd_send_sr_reply(mdev, SS_CONCURRENT_ST_CHG); |
3092 | return TRUE; | 3156 | return true; |
3093 | } | 3157 | } |
3094 | 3158 | ||
3095 | mask = convert_state(mask); | 3159 | mask = convert_state(mask); |
@@ -3100,7 +3164,7 @@ static int receive_req_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsi | |||
3100 | drbd_send_sr_reply(mdev, rv); | 3164 | drbd_send_sr_reply(mdev, rv); |
3101 | drbd_md_sync(mdev); | 3165 | drbd_md_sync(mdev); |
3102 | 3166 | ||
3103 | return TRUE; | 3167 | return true; |
3104 | } | 3168 | } |
3105 | 3169 | ||
3106 | static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) | 3170 | static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) |
@@ -3145,7 +3209,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
3145 | peer_state.conn == C_CONNECTED) { | 3209 | peer_state.conn == C_CONNECTED) { |
3146 | if (drbd_bm_total_weight(mdev) <= mdev->rs_failed) | 3210 | if (drbd_bm_total_weight(mdev) <= mdev->rs_failed) |
3147 | drbd_resync_finished(mdev); | 3211 | drbd_resync_finished(mdev); |
3148 | return TRUE; | 3212 | return true; |
3149 | } | 3213 | } |
3150 | } | 3214 | } |
3151 | 3215 | ||
@@ -3161,6 +3225,9 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
3161 | if (ns.conn == C_WF_REPORT_PARAMS) | 3225 | if (ns.conn == C_WF_REPORT_PARAMS) |
3162 | ns.conn = C_CONNECTED; | 3226 | ns.conn = C_CONNECTED; |
3163 | 3227 | ||
3228 | if (peer_state.conn == C_AHEAD) | ||
3229 | ns.conn = C_BEHIND; | ||
3230 | |||
3164 | if (mdev->p_uuid && peer_state.disk >= D_NEGOTIATING && | 3231 | if (mdev->p_uuid && peer_state.disk >= D_NEGOTIATING && |
3165 | get_ldev_if_state(mdev, D_NEGOTIATING)) { | 3232 | get_ldev_if_state(mdev, D_NEGOTIATING)) { |
3166 | int cr; /* consider resync */ | 3233 | int cr; /* consider resync */ |
@@ -3195,10 +3262,10 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
3195 | real_peer_disk = D_DISKLESS; | 3262 | real_peer_disk = D_DISKLESS; |
3196 | } else { | 3263 | } else { |
3197 | if (test_and_clear_bit(CONN_DRY_RUN, &mdev->flags)) | 3264 | if (test_and_clear_bit(CONN_DRY_RUN, &mdev->flags)) |
3198 | return FALSE; | 3265 | return false; |
3199 | D_ASSERT(os.conn == C_WF_REPORT_PARAMS); | 3266 | D_ASSERT(os.conn == C_WF_REPORT_PARAMS); |
3200 | drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); | 3267 | drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); |
3201 | return FALSE; | 3268 | return false; |
3202 | } | 3269 | } |
3203 | } | 3270 | } |
3204 | } | 3271 | } |
@@ -3223,7 +3290,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
3223 | drbd_uuid_new_current(mdev); | 3290 | drbd_uuid_new_current(mdev); |
3224 | clear_bit(NEW_CUR_UUID, &mdev->flags); | 3291 | clear_bit(NEW_CUR_UUID, &mdev->flags); |
3225 | drbd_force_state(mdev, NS2(conn, C_PROTOCOL_ERROR, susp, 0)); | 3292 | drbd_force_state(mdev, NS2(conn, C_PROTOCOL_ERROR, susp, 0)); |
3226 | return FALSE; | 3293 | return false; |
3227 | } | 3294 | } |
3228 | rv = _drbd_set_state(mdev, ns, cs_flags, NULL); | 3295 | rv = _drbd_set_state(mdev, ns, cs_flags, NULL); |
3229 | ns = mdev->state; | 3296 | ns = mdev->state; |
@@ -3231,7 +3298,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
3231 | 3298 | ||
3232 | if (rv < SS_SUCCESS) { | 3299 | if (rv < SS_SUCCESS) { |
3233 | drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); | 3300 | drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); |
3234 | return FALSE; | 3301 | return false; |
3235 | } | 3302 | } |
3236 | 3303 | ||
3237 | if (os.conn > C_WF_REPORT_PARAMS) { | 3304 | if (os.conn > C_WF_REPORT_PARAMS) { |
@@ -3249,7 +3316,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned | |||
3249 | 3316 | ||
3250 | drbd_md_sync(mdev); /* update connected indicator, la_size, ... */ | 3317 | drbd_md_sync(mdev); /* update connected indicator, la_size, ... */ |
3251 | 3318 | ||
3252 | return TRUE; | 3319 | return true; |
3253 | } | 3320 | } |
3254 | 3321 | ||
3255 | static int receive_sync_uuid(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) | 3322 | static int receive_sync_uuid(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) |
@@ -3258,6 +3325,7 @@ static int receive_sync_uuid(struct drbd_conf *mdev, enum drbd_packets cmd, unsi | |||
3258 | 3325 | ||
3259 | wait_event(mdev->misc_wait, | 3326 | wait_event(mdev->misc_wait, |
3260 | mdev->state.conn == C_WF_SYNC_UUID || | 3327 | mdev->state.conn == C_WF_SYNC_UUID || |
3328 | mdev->state.conn == C_BEHIND || | ||
3261 | mdev->state.conn < C_CONNECTED || | 3329 | mdev->state.conn < C_CONNECTED || |
3262 | mdev->state.disk < D_NEGOTIATING); | 3330 | mdev->state.disk < D_NEGOTIATING); |
3263 | 3331 | ||
@@ -3269,32 +3337,42 @@ static int receive_sync_uuid(struct drbd_conf *mdev, enum drbd_packets cmd, unsi | |||
3269 | _drbd_uuid_set(mdev, UI_CURRENT, be64_to_cpu(p->uuid)); | 3337 | _drbd_uuid_set(mdev, UI_CURRENT, be64_to_cpu(p->uuid)); |
3270 | _drbd_uuid_set(mdev, UI_BITMAP, 0UL); | 3338 | _drbd_uuid_set(mdev, UI_BITMAP, 0UL); |
3271 | 3339 | ||
3340 | drbd_print_uuids(mdev, "updated sync uuid"); | ||
3272 | drbd_start_resync(mdev, C_SYNC_TARGET); | 3341 | drbd_start_resync(mdev, C_SYNC_TARGET); |
3273 | 3342 | ||
3274 | put_ldev(mdev); | 3343 | put_ldev(mdev); |
3275 | } else | 3344 | } else |
3276 | dev_err(DEV, "Ignoring SyncUUID packet!\n"); | 3345 | dev_err(DEV, "Ignoring SyncUUID packet!\n"); |
3277 | 3346 | ||
3278 | return TRUE; | 3347 | return true; |
3279 | } | 3348 | } |
3280 | 3349 | ||
3281 | enum receive_bitmap_ret { OK, DONE, FAILED }; | 3350 | /** |
3282 | 3351 | * receive_bitmap_plain | |
3283 | static enum receive_bitmap_ret | 3352 | * |
3353 | * Return 0 when done, 1 when another iteration is needed, and a negative error | ||
3354 | * code upon failure. | ||
3355 | */ | ||
3356 | static int | ||
3284 | receive_bitmap_plain(struct drbd_conf *mdev, unsigned int data_size, | 3357 | receive_bitmap_plain(struct drbd_conf *mdev, unsigned int data_size, |
3285 | unsigned long *buffer, struct bm_xfer_ctx *c) | 3358 | unsigned long *buffer, struct bm_xfer_ctx *c) |
3286 | { | 3359 | { |
3287 | unsigned num_words = min_t(size_t, BM_PACKET_WORDS, c->bm_words - c->word_offset); | 3360 | unsigned num_words = min_t(size_t, BM_PACKET_WORDS, c->bm_words - c->word_offset); |
3288 | unsigned want = num_words * sizeof(long); | 3361 | unsigned want = num_words * sizeof(long); |
3362 | int err; | ||
3289 | 3363 | ||
3290 | if (want != data_size) { | 3364 | if (want != data_size) { |
3291 | dev_err(DEV, "%s:want (%u) != data_size (%u)\n", __func__, want, data_size); | 3365 | dev_err(DEV, "%s:want (%u) != data_size (%u)\n", __func__, want, data_size); |
3292 | return FAILED; | 3366 | return -EIO; |
3293 | } | 3367 | } |
3294 | if (want == 0) | 3368 | if (want == 0) |
3295 | return DONE; | 3369 | return 0; |
3296 | if (drbd_recv(mdev, buffer, want) != want) | 3370 | err = drbd_recv(mdev, buffer, want); |
3297 | return FAILED; | 3371 | if (err != want) { |
3372 | if (err >= 0) | ||
3373 | err = -EIO; | ||
3374 | return err; | ||
3375 | } | ||
3298 | 3376 | ||
3299 | drbd_bm_merge_lel(mdev, c->word_offset, num_words, buffer); | 3377 | drbd_bm_merge_lel(mdev, c->word_offset, num_words, buffer); |
3300 | 3378 | ||
@@ -3303,10 +3381,16 @@ receive_bitmap_plain(struct drbd_conf *mdev, unsigned int data_size, | |||
3303 | if (c->bit_offset > c->bm_bits) | 3381 | if (c->bit_offset > c->bm_bits) |
3304 | c->bit_offset = c->bm_bits; | 3382 | c->bit_offset = c->bm_bits; |
3305 | 3383 | ||
3306 | return OK; | 3384 | return 1; |
3307 | } | 3385 | } |
3308 | 3386 | ||
3309 | static enum receive_bitmap_ret | 3387 | /** |
3388 | * recv_bm_rle_bits | ||
3389 | * | ||
3390 | * Return 0 when done, 1 when another iteration is needed, and a negative error | ||
3391 | * code upon failure. | ||
3392 | */ | ||
3393 | static int | ||
3310 | recv_bm_rle_bits(struct drbd_conf *mdev, | 3394 | recv_bm_rle_bits(struct drbd_conf *mdev, |
3311 | struct p_compressed_bm *p, | 3395 | struct p_compressed_bm *p, |
3312 | struct bm_xfer_ctx *c) | 3396 | struct bm_xfer_ctx *c) |
@@ -3326,18 +3410,18 @@ recv_bm_rle_bits(struct drbd_conf *mdev, | |||
3326 | 3410 | ||
3327 | bits = bitstream_get_bits(&bs, &look_ahead, 64); | 3411 | bits = bitstream_get_bits(&bs, &look_ahead, 64); |
3328 | if (bits < 0) | 3412 | if (bits < 0) |
3329 | return FAILED; | 3413 | return -EIO; |
3330 | 3414 | ||
3331 | for (have = bits; have > 0; s += rl, toggle = !toggle) { | 3415 | for (have = bits; have > 0; s += rl, toggle = !toggle) { |
3332 | bits = vli_decode_bits(&rl, look_ahead); | 3416 | bits = vli_decode_bits(&rl, look_ahead); |
3333 | if (bits <= 0) | 3417 | if (bits <= 0) |
3334 | return FAILED; | 3418 | return -EIO; |
3335 | 3419 | ||
3336 | if (toggle) { | 3420 | if (toggle) { |
3337 | e = s + rl -1; | 3421 | e = s + rl -1; |
3338 | if (e >= c->bm_bits) { | 3422 | if (e >= c->bm_bits) { |
3339 | dev_err(DEV, "bitmap overflow (e:%lu) while decoding bm RLE packet\n", e); | 3423 | dev_err(DEV, "bitmap overflow (e:%lu) while decoding bm RLE packet\n", e); |
3340 | return FAILED; | 3424 | return -EIO; |
3341 | } | 3425 | } |
3342 | _drbd_bm_set_bits(mdev, s, e); | 3426 | _drbd_bm_set_bits(mdev, s, e); |
3343 | } | 3427 | } |
@@ -3347,14 +3431,14 @@ recv_bm_rle_bits(struct drbd_conf *mdev, | |||
3347 | have, bits, look_ahead, | 3431 | have, bits, look_ahead, |
3348 | (unsigned int)(bs.cur.b - p->code), | 3432 | (unsigned int)(bs.cur.b - p->code), |
3349 | (unsigned int)bs.buf_len); | 3433 | (unsigned int)bs.buf_len); |
3350 | return FAILED; | 3434 | return -EIO; |
3351 | } | 3435 | } |
3352 | look_ahead >>= bits; | 3436 | look_ahead >>= bits; |
3353 | have -= bits; | 3437 | have -= bits; |
3354 | 3438 | ||
3355 | bits = bitstream_get_bits(&bs, &tmp, 64 - have); | 3439 | bits = bitstream_get_bits(&bs, &tmp, 64 - have); |
3356 | if (bits < 0) | 3440 | if (bits < 0) |
3357 | return FAILED; | 3441 | return -EIO; |
3358 | look_ahead |= tmp << have; | 3442 | look_ahead |= tmp << have; |
3359 | have += bits; | 3443 | have += bits; |
3360 | } | 3444 | } |
@@ -3362,10 +3446,16 @@ recv_bm_rle_bits(struct drbd_conf *mdev, | |||
3362 | c->bit_offset = s; | 3446 | c->bit_offset = s; |
3363 | bm_xfer_ctx_bit_to_word_offset(c); | 3447 | bm_xfer_ctx_bit_to_word_offset(c); |
3364 | 3448 | ||
3365 | return (s == c->bm_bits) ? DONE : OK; | 3449 | return (s != c->bm_bits); |
3366 | } | 3450 | } |
3367 | 3451 | ||
3368 | static enum receive_bitmap_ret | 3452 | /** |
3453 | * decode_bitmap_c | ||
3454 | * | ||
3455 | * Return 0 when done, 1 when another iteration is needed, and a negative error | ||
3456 | * code upon failure. | ||
3457 | */ | ||
3458 | static int | ||
3369 | decode_bitmap_c(struct drbd_conf *mdev, | 3459 | decode_bitmap_c(struct drbd_conf *mdev, |
3370 | struct p_compressed_bm *p, | 3460 | struct p_compressed_bm *p, |
3371 | struct bm_xfer_ctx *c) | 3461 | struct bm_xfer_ctx *c) |
@@ -3379,7 +3469,7 @@ decode_bitmap_c(struct drbd_conf *mdev, | |||
3379 | 3469 | ||
3380 | dev_err(DEV, "receive_bitmap_c: unknown encoding %u\n", p->encoding); | 3470 | dev_err(DEV, "receive_bitmap_c: unknown encoding %u\n", p->encoding); |
3381 | drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR)); | 3471 | drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR)); |
3382 | return FAILED; | 3472 | return -EIO; |
3383 | } | 3473 | } |
3384 | 3474 | ||
3385 | void INFO_bm_xfer_stats(struct drbd_conf *mdev, | 3475 | void INFO_bm_xfer_stats(struct drbd_conf *mdev, |
@@ -3428,13 +3518,13 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne | |||
3428 | { | 3518 | { |
3429 | struct bm_xfer_ctx c; | 3519 | struct bm_xfer_ctx c; |
3430 | void *buffer; | 3520 | void *buffer; |
3431 | enum receive_bitmap_ret ret; | 3521 | int err; |
3432 | int ok = FALSE; | 3522 | int ok = false; |
3433 | struct p_header80 *h = &mdev->data.rbuf.header.h80; | 3523 | struct p_header80 *h = &mdev->data.rbuf.header.h80; |
3434 | 3524 | ||
3435 | wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt)); | 3525 | drbd_bm_lock(mdev, "receive bitmap", BM_LOCKED_SET_ALLOWED); |
3436 | 3526 | /* you are supposed to send additional out-of-sync information | |
3437 | drbd_bm_lock(mdev, "receive bitmap"); | 3527 | * if you actually set bits during this phase */ |
3438 | 3528 | ||
3439 | /* maybe we should use some per thread scratch page, | 3529 | /* maybe we should use some per thread scratch page, |
3440 | * and allocate that during initial device creation? */ | 3530 | * and allocate that during initial device creation? */ |
@@ -3449,9 +3539,9 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne | |||
3449 | .bm_words = drbd_bm_words(mdev), | 3539 | .bm_words = drbd_bm_words(mdev), |
3450 | }; | 3540 | }; |
3451 | 3541 | ||
3452 | do { | 3542 | for(;;) { |
3453 | if (cmd == P_BITMAP) { | 3543 | if (cmd == P_BITMAP) { |
3454 | ret = receive_bitmap_plain(mdev, data_size, buffer, &c); | 3544 | err = receive_bitmap_plain(mdev, data_size, buffer, &c); |
3455 | } else if (cmd == P_COMPRESSED_BITMAP) { | 3545 | } else if (cmd == P_COMPRESSED_BITMAP) { |
3456 | /* MAYBE: sanity check that we speak proto >= 90, | 3546 | /* MAYBE: sanity check that we speak proto >= 90, |
3457 | * and the feature is enabled! */ | 3547 | * and the feature is enabled! */ |
@@ -3468,9 +3558,9 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne | |||
3468 | goto out; | 3558 | goto out; |
3469 | if (data_size <= (sizeof(*p) - sizeof(p->head))) { | 3559 | if (data_size <= (sizeof(*p) - sizeof(p->head))) { |
3470 | dev_err(DEV, "ReportCBitmap packet too small (l:%u)\n", data_size); | 3560 | dev_err(DEV, "ReportCBitmap packet too small (l:%u)\n", data_size); |
3471 | return FAILED; | 3561 | goto out; |
3472 | } | 3562 | } |
3473 | ret = decode_bitmap_c(mdev, p, &c); | 3563 | err = decode_bitmap_c(mdev, p, &c); |
3474 | } else { | 3564 | } else { |
3475 | dev_warn(DEV, "receive_bitmap: cmd neither ReportBitMap nor ReportCBitMap (is 0x%x)", cmd); | 3565 | dev_warn(DEV, "receive_bitmap: cmd neither ReportBitMap nor ReportCBitMap (is 0x%x)", cmd); |
3476 | goto out; | 3566 | goto out; |
@@ -3479,24 +3569,26 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne | |||
3479 | c.packets[cmd == P_BITMAP]++; | 3569 | c.packets[cmd == P_BITMAP]++; |
3480 | c.bytes[cmd == P_BITMAP] += sizeof(struct p_header80) + data_size; | 3570 | c.bytes[cmd == P_BITMAP] += sizeof(struct p_header80) + data_size; |
3481 | 3571 | ||
3482 | if (ret != OK) | 3572 | if (err <= 0) { |
3573 | if (err < 0) | ||
3574 | goto out; | ||
3483 | break; | 3575 | break; |
3484 | 3576 | } | |
3485 | if (!drbd_recv_header(mdev, &cmd, &data_size)) | 3577 | if (!drbd_recv_header(mdev, &cmd, &data_size)) |
3486 | goto out; | 3578 | goto out; |
3487 | } while (ret == OK); | 3579 | } |
3488 | if (ret == FAILED) | ||
3489 | goto out; | ||
3490 | 3580 | ||
3491 | INFO_bm_xfer_stats(mdev, "receive", &c); | 3581 | INFO_bm_xfer_stats(mdev, "receive", &c); |
3492 | 3582 | ||
3493 | if (mdev->state.conn == C_WF_BITMAP_T) { | 3583 | if (mdev->state.conn == C_WF_BITMAP_T) { |
3584 | enum drbd_state_rv rv; | ||
3585 | |||
3494 | ok = !drbd_send_bitmap(mdev); | 3586 | ok = !drbd_send_bitmap(mdev); |
3495 | if (!ok) | 3587 | if (!ok) |
3496 | goto out; | 3588 | goto out; |
3497 | /* Omit CS_ORDERED with this state transition to avoid deadlocks. */ | 3589 | /* Omit CS_ORDERED with this state transition to avoid deadlocks. */ |
3498 | ok = _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE); | 3590 | rv = _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE); |
3499 | D_ASSERT(ok == SS_SUCCESS); | 3591 | D_ASSERT(rv == SS_SUCCESS); |
3500 | } else if (mdev->state.conn != C_WF_BITMAP_S) { | 3592 | } else if (mdev->state.conn != C_WF_BITMAP_S) { |
3501 | /* admin may have requested C_DISCONNECTING, | 3593 | /* admin may have requested C_DISCONNECTING, |
3502 | * other threads may have noticed network errors */ | 3594 | * other threads may have noticed network errors */ |
@@ -3504,7 +3596,7 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne | |||
3504 | drbd_conn_str(mdev->state.conn)); | 3596 | drbd_conn_str(mdev->state.conn)); |
3505 | } | 3597 | } |
3506 | 3598 | ||
3507 | ok = TRUE; | 3599 | ok = true; |
3508 | out: | 3600 | out: |
3509 | drbd_bm_unlock(mdev); | 3601 | drbd_bm_unlock(mdev); |
3510 | if (ok && mdev->state.conn == C_WF_BITMAP_S) | 3602 | if (ok && mdev->state.conn == C_WF_BITMAP_S) |
@@ -3538,7 +3630,26 @@ static int receive_UnplugRemote(struct drbd_conf *mdev, enum drbd_packets cmd, u | |||
3538 | * with the data requests being unplugged */ | 3630 | * with the data requests being unplugged */ |
3539 | drbd_tcp_quickack(mdev->data.socket); | 3631 | drbd_tcp_quickack(mdev->data.socket); |
3540 | 3632 | ||
3541 | return TRUE; | 3633 | return true; |
3634 | } | ||
3635 | |||
3636 | static int receive_out_of_sync(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) | ||
3637 | { | ||
3638 | struct p_block_desc *p = &mdev->data.rbuf.block_desc; | ||
3639 | |||
3640 | switch (mdev->state.conn) { | ||
3641 | case C_WF_SYNC_UUID: | ||
3642 | case C_WF_BITMAP_T: | ||
3643 | case C_BEHIND: | ||
3644 | break; | ||
3645 | default: | ||
3646 | dev_err(DEV, "ASSERT FAILED cstate = %s, expected: WFSyncUUID|WFBitMapT|Behind\n", | ||
3647 | drbd_conn_str(mdev->state.conn)); | ||
3648 | } | ||
3649 | |||
3650 | drbd_set_out_of_sync(mdev, be64_to_cpu(p->sector), be32_to_cpu(p->blksize)); | ||
3651 | |||
3652 | return true; | ||
3542 | } | 3653 | } |
3543 | 3654 | ||
3544 | typedef int (*drbd_cmd_handler_f)(struct drbd_conf *, enum drbd_packets cmd, unsigned int to_receive); | 3655 | typedef int (*drbd_cmd_handler_f)(struct drbd_conf *, enum drbd_packets cmd, unsigned int to_receive); |
@@ -3571,6 +3682,7 @@ static struct data_cmd drbd_cmd_handler[] = { | |||
3571 | [P_OV_REPLY] = { 1, sizeof(struct p_block_req), receive_DataRequest }, | 3682 | [P_OV_REPLY] = { 1, sizeof(struct p_block_req), receive_DataRequest }, |
3572 | [P_CSUM_RS_REQUEST] = { 1, sizeof(struct p_block_req), receive_DataRequest }, | 3683 | [P_CSUM_RS_REQUEST] = { 1, sizeof(struct p_block_req), receive_DataRequest }, |
3573 | [P_DELAY_PROBE] = { 0, sizeof(struct p_delay_probe93), receive_skip }, | 3684 | [P_DELAY_PROBE] = { 0, sizeof(struct p_delay_probe93), receive_skip }, |
3685 | [P_OUT_OF_SYNC] = { 0, sizeof(struct p_block_desc), receive_out_of_sync }, | ||
3574 | /* anything missing from this table is in | 3686 | /* anything missing from this table is in |
3575 | * the asender_tbl, see get_asender_cmd */ | 3687 | * the asender_tbl, see get_asender_cmd */ |
3576 | [P_MAX_CMD] = { 0, 0, NULL }, | 3688 | [P_MAX_CMD] = { 0, 0, NULL }, |
@@ -3610,7 +3722,8 @@ static void drbdd(struct drbd_conf *mdev) | |||
3610 | if (shs) { | 3722 | if (shs) { |
3611 | rv = drbd_recv(mdev, &header->h80.payload, shs); | 3723 | rv = drbd_recv(mdev, &header->h80.payload, shs); |
3612 | if (unlikely(rv != shs)) { | 3724 | if (unlikely(rv != shs)) { |
3613 | dev_err(DEV, "short read while reading sub header: rv=%d\n", rv); | 3725 | if (!signal_pending(current)) |
3726 | dev_warn(DEV, "short read while reading sub header: rv=%d\n", rv); | ||
3614 | goto err_out; | 3727 | goto err_out; |
3615 | } | 3728 | } |
3616 | } | 3729 | } |
@@ -3682,9 +3795,6 @@ static void drbd_disconnect(struct drbd_conf *mdev) | |||
3682 | 3795 | ||
3683 | if (mdev->state.conn == C_STANDALONE) | 3796 | if (mdev->state.conn == C_STANDALONE) |
3684 | return; | 3797 | return; |
3685 | if (mdev->state.conn >= C_WF_CONNECTION) | ||
3686 | dev_err(DEV, "ASSERT FAILED cstate = %s, expected < WFConnection\n", | ||
3687 | drbd_conn_str(mdev->state.conn)); | ||
3688 | 3798 | ||
3689 | /* asender does not clean up anything. it must not interfere, either */ | 3799 | /* asender does not clean up anything. it must not interfere, either */ |
3690 | drbd_thread_stop(&mdev->asender); | 3800 | drbd_thread_stop(&mdev->asender); |
@@ -3713,6 +3823,8 @@ static void drbd_disconnect(struct drbd_conf *mdev) | |||
3713 | atomic_set(&mdev->rs_pending_cnt, 0); | 3823 | atomic_set(&mdev->rs_pending_cnt, 0); |
3714 | wake_up(&mdev->misc_wait); | 3824 | wake_up(&mdev->misc_wait); |
3715 | 3825 | ||
3826 | del_timer(&mdev->request_timer); | ||
3827 | |||
3716 | /* make sure syncer is stopped and w_resume_next_sg queued */ | 3828 | /* make sure syncer is stopped and w_resume_next_sg queued */ |
3717 | del_timer_sync(&mdev->resync_timer); | 3829 | del_timer_sync(&mdev->resync_timer); |
3718 | resync_timer_fn((unsigned long)mdev); | 3830 | resync_timer_fn((unsigned long)mdev); |
@@ -3758,13 +3870,6 @@ static void drbd_disconnect(struct drbd_conf *mdev) | |||
3758 | if (os.conn == C_DISCONNECTING) { | 3870 | if (os.conn == C_DISCONNECTING) { |
3759 | wait_event(mdev->net_cnt_wait, atomic_read(&mdev->net_cnt) == 0); | 3871 | wait_event(mdev->net_cnt_wait, atomic_read(&mdev->net_cnt) == 0); |
3760 | 3872 | ||
3761 | if (!is_susp(mdev->state)) { | ||
3762 | /* we must not free the tl_hash | ||
3763 | * while application io is still on the fly */ | ||
3764 | wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt)); | ||
3765 | drbd_free_tl_hash(mdev); | ||
3766 | } | ||
3767 | |||
3768 | crypto_free_hash(mdev->cram_hmac_tfm); | 3873 | crypto_free_hash(mdev->cram_hmac_tfm); |
3769 | mdev->cram_hmac_tfm = NULL; | 3874 | mdev->cram_hmac_tfm = NULL; |
3770 | 3875 | ||
@@ -3773,6 +3878,10 @@ static void drbd_disconnect(struct drbd_conf *mdev) | |||
3773 | drbd_request_state(mdev, NS(conn, C_STANDALONE)); | 3878 | drbd_request_state(mdev, NS(conn, C_STANDALONE)); |
3774 | } | 3879 | } |
3775 | 3880 | ||
3881 | /* serialize with bitmap writeout triggered by the state change, | ||
3882 | * if any. */ | ||
3883 | wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags)); | ||
3884 | |||
3776 | /* tcp_close and release of sendpage pages can be deferred. I don't | 3885 | /* tcp_close and release of sendpage pages can be deferred. I don't |
3777 | * want to use SO_LINGER, because apparently it can be deferred for | 3886 | * want to use SO_LINGER, because apparently it can be deferred for |
3778 | * more than 20 seconds (longest time I checked). | 3887 | * more than 20 seconds (longest time I checked). |
@@ -3873,7 +3982,8 @@ static int drbd_do_handshake(struct drbd_conf *mdev) | |||
3873 | rv = drbd_recv(mdev, &p->head.payload, expect); | 3982 | rv = drbd_recv(mdev, &p->head.payload, expect); |
3874 | 3983 | ||
3875 | if (rv != expect) { | 3984 | if (rv != expect) { |
3876 | dev_err(DEV, "short read receiving handshake packet: l=%u\n", rv); | 3985 | if (!signal_pending(current)) |
3986 | dev_warn(DEV, "short read receiving handshake packet: l=%u\n", rv); | ||
3877 | return 0; | 3987 | return 0; |
3878 | } | 3988 | } |
3879 | 3989 | ||
@@ -3975,7 +4085,8 @@ static int drbd_do_auth(struct drbd_conf *mdev) | |||
3975 | rv = drbd_recv(mdev, peers_ch, length); | 4085 | rv = drbd_recv(mdev, peers_ch, length); |
3976 | 4086 | ||
3977 | if (rv != length) { | 4087 | if (rv != length) { |
3978 | dev_err(DEV, "short read AuthChallenge: l=%u\n", rv); | 4088 | if (!signal_pending(current)) |
4089 | dev_warn(DEV, "short read AuthChallenge: l=%u\n", rv); | ||
3979 | rv = 0; | 4090 | rv = 0; |
3980 | goto fail; | 4091 | goto fail; |
3981 | } | 4092 | } |
@@ -4022,7 +4133,8 @@ static int drbd_do_auth(struct drbd_conf *mdev) | |||
4022 | rv = drbd_recv(mdev, response , resp_size); | 4133 | rv = drbd_recv(mdev, response , resp_size); |
4023 | 4134 | ||
4024 | if (rv != resp_size) { | 4135 | if (rv != resp_size) { |
4025 | dev_err(DEV, "short read receiving AuthResponse: l=%u\n", rv); | 4136 | if (!signal_pending(current)) |
4137 | dev_warn(DEV, "short read receiving AuthResponse: l=%u\n", rv); | ||
4026 | rv = 0; | 4138 | rv = 0; |
4027 | goto fail; | 4139 | goto fail; |
4028 | } | 4140 | } |
@@ -4074,8 +4186,7 @@ int drbdd_init(struct drbd_thread *thi) | |||
4074 | h = drbd_connect(mdev); | 4186 | h = drbd_connect(mdev); |
4075 | if (h == 0) { | 4187 | if (h == 0) { |
4076 | drbd_disconnect(mdev); | 4188 | drbd_disconnect(mdev); |
4077 | __set_current_state(TASK_INTERRUPTIBLE); | 4189 | schedule_timeout_interruptible(HZ); |
4078 | schedule_timeout(HZ); | ||
4079 | } | 4190 | } |
4080 | if (h == -1) { | 4191 | if (h == -1) { |
4081 | dev_warn(DEV, "Discarding network configuration.\n"); | 4192 | dev_warn(DEV, "Discarding network configuration.\n"); |
@@ -4113,7 +4224,7 @@ static int got_RqSReply(struct drbd_conf *mdev, struct p_header80 *h) | |||
4113 | } | 4224 | } |
4114 | wake_up(&mdev->state_wait); | 4225 | wake_up(&mdev->state_wait); |
4115 | 4226 | ||
4116 | return TRUE; | 4227 | return true; |
4117 | } | 4228 | } |
4118 | 4229 | ||
4119 | static int got_Ping(struct drbd_conf *mdev, struct p_header80 *h) | 4230 | static int got_Ping(struct drbd_conf *mdev, struct p_header80 *h) |
@@ -4129,7 +4240,7 @@ static int got_PingAck(struct drbd_conf *mdev, struct p_header80 *h) | |||
4129 | if (!test_and_set_bit(GOT_PING_ACK, &mdev->flags)) | 4240 | if (!test_and_set_bit(GOT_PING_ACK, &mdev->flags)) |
4130 | wake_up(&mdev->misc_wait); | 4241 | wake_up(&mdev->misc_wait); |
4131 | 4242 | ||
4132 | return TRUE; | 4243 | return true; |
4133 | } | 4244 | } |
4134 | 4245 | ||
4135 | static int got_IsInSync(struct drbd_conf *mdev, struct p_header80 *h) | 4246 | static int got_IsInSync(struct drbd_conf *mdev, struct p_header80 *h) |
@@ -4152,7 +4263,7 @@ static int got_IsInSync(struct drbd_conf *mdev, struct p_header80 *h) | |||
4152 | dec_rs_pending(mdev); | 4263 | dec_rs_pending(mdev); |
4153 | atomic_add(blksize >> 9, &mdev->rs_sect_in); | 4264 | atomic_add(blksize >> 9, &mdev->rs_sect_in); |
4154 | 4265 | ||
4155 | return TRUE; | 4266 | return true; |
4156 | } | 4267 | } |
4157 | 4268 | ||
4158 | /* when we receive the ACK for a write request, | 4269 | /* when we receive the ACK for a write request, |
@@ -4176,8 +4287,6 @@ static struct drbd_request *_ack_id_to_req(struct drbd_conf *mdev, | |||
4176 | return req; | 4287 | return req; |
4177 | } | 4288 | } |
4178 | } | 4289 | } |
4179 | dev_err(DEV, "_ack_id_to_req: failed to find req %p, sector %llus in list\n", | ||
4180 | (void *)(unsigned long)id, (unsigned long long)sector); | ||
4181 | return NULL; | 4290 | return NULL; |
4182 | } | 4291 | } |
4183 | 4292 | ||
@@ -4195,15 +4304,17 @@ static int validate_req_change_req_state(struct drbd_conf *mdev, | |||
4195 | req = validator(mdev, id, sector); | 4304 | req = validator(mdev, id, sector); |
4196 | if (unlikely(!req)) { | 4305 | if (unlikely(!req)) { |
4197 | spin_unlock_irq(&mdev->req_lock); | 4306 | spin_unlock_irq(&mdev->req_lock); |
4198 | dev_err(DEV, "%s: got a corrupt block_id/sector pair\n", func); | 4307 | |
4199 | return FALSE; | 4308 | dev_err(DEV, "%s: failed to find req %p, sector %llus\n", func, |
4309 | (void *)(unsigned long)id, (unsigned long long)sector); | ||
4310 | return false; | ||
4200 | } | 4311 | } |
4201 | __req_mod(req, what, &m); | 4312 | __req_mod(req, what, &m); |
4202 | spin_unlock_irq(&mdev->req_lock); | 4313 | spin_unlock_irq(&mdev->req_lock); |
4203 | 4314 | ||
4204 | if (m.bio) | 4315 | if (m.bio) |
4205 | complete_master_bio(mdev, &m); | 4316 | complete_master_bio(mdev, &m); |
4206 | return TRUE; | 4317 | return true; |
4207 | } | 4318 | } |
4208 | 4319 | ||
4209 | static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h) | 4320 | static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h) |
@@ -4218,7 +4329,7 @@ static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h) | |||
4218 | if (is_syncer_block_id(p->block_id)) { | 4329 | if (is_syncer_block_id(p->block_id)) { |
4219 | drbd_set_in_sync(mdev, sector, blksize); | 4330 | drbd_set_in_sync(mdev, sector, blksize); |
4220 | dec_rs_pending(mdev); | 4331 | dec_rs_pending(mdev); |
4221 | return TRUE; | 4332 | return true; |
4222 | } | 4333 | } |
4223 | switch (be16_to_cpu(h->command)) { | 4334 | switch (be16_to_cpu(h->command)) { |
4224 | case P_RS_WRITE_ACK: | 4335 | case P_RS_WRITE_ACK: |
@@ -4239,7 +4350,7 @@ static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h) | |||
4239 | break; | 4350 | break; |
4240 | default: | 4351 | default: |
4241 | D_ASSERT(0); | 4352 | D_ASSERT(0); |
4242 | return FALSE; | 4353 | return false; |
4243 | } | 4354 | } |
4244 | 4355 | ||
4245 | return validate_req_change_req_state(mdev, p->block_id, sector, | 4356 | return validate_req_change_req_state(mdev, p->block_id, sector, |
@@ -4250,20 +4361,44 @@ static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) | |||
4250 | { | 4361 | { |
4251 | struct p_block_ack *p = (struct p_block_ack *)h; | 4362 | struct p_block_ack *p = (struct p_block_ack *)h; |
4252 | sector_t sector = be64_to_cpu(p->sector); | 4363 | sector_t sector = be64_to_cpu(p->sector); |
4253 | 4364 | int size = be32_to_cpu(p->blksize); | |
4254 | if (__ratelimit(&drbd_ratelimit_state)) | 4365 | struct drbd_request *req; |
4255 | dev_warn(DEV, "Got NegAck packet. Peer is in troubles?\n"); | 4366 | struct bio_and_error m; |
4256 | 4367 | ||
4257 | update_peer_seq(mdev, be32_to_cpu(p->seq_num)); | 4368 | update_peer_seq(mdev, be32_to_cpu(p->seq_num)); |
4258 | 4369 | ||
4259 | if (is_syncer_block_id(p->block_id)) { | 4370 | if (is_syncer_block_id(p->block_id)) { |
4260 | int size = be32_to_cpu(p->blksize); | ||
4261 | dec_rs_pending(mdev); | 4371 | dec_rs_pending(mdev); |
4262 | drbd_rs_failed_io(mdev, sector, size); | 4372 | drbd_rs_failed_io(mdev, sector, size); |
4263 | return TRUE; | 4373 | return true; |
4264 | } | 4374 | } |
4265 | return validate_req_change_req_state(mdev, p->block_id, sector, | 4375 | |
4266 | _ack_id_to_req, __func__ , neg_acked); | 4376 | spin_lock_irq(&mdev->req_lock); |
4377 | req = _ack_id_to_req(mdev, p->block_id, sector); | ||
4378 | if (!req) { | ||
4379 | spin_unlock_irq(&mdev->req_lock); | ||
4380 | if (mdev->net_conf->wire_protocol == DRBD_PROT_A || | ||
4381 | mdev->net_conf->wire_protocol == DRBD_PROT_B) { | ||
4382 | /* Protocol A has no P_WRITE_ACKs, but has P_NEG_ACKs. | ||
4383 | The master bio might already be completed, therefore the | ||
4384 | request is no longer in the collision hash. | ||
4385 | => Do not try to validate block_id as request. */ | ||
4386 | /* In Protocol B we might already have got a P_RECV_ACK | ||
4387 | but then get a P_NEG_ACK after wards. */ | ||
4388 | drbd_set_out_of_sync(mdev, sector, size); | ||
4389 | return true; | ||
4390 | } else { | ||
4391 | dev_err(DEV, "%s: failed to find req %p, sector %llus\n", __func__, | ||
4392 | (void *)(unsigned long)p->block_id, (unsigned long long)sector); | ||
4393 | return false; | ||
4394 | } | ||
4395 | } | ||
4396 | __req_mod(req, neg_acked, &m); | ||
4397 | spin_unlock_irq(&mdev->req_lock); | ||
4398 | |||
4399 | if (m.bio) | ||
4400 | complete_master_bio(mdev, &m); | ||
4401 | return true; | ||
4267 | } | 4402 | } |
4268 | 4403 | ||
4269 | static int got_NegDReply(struct drbd_conf *mdev, struct p_header80 *h) | 4404 | static int got_NegDReply(struct drbd_conf *mdev, struct p_header80 *h) |
@@ -4294,11 +4429,20 @@ static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header80 *h) | |||
4294 | 4429 | ||
4295 | if (get_ldev_if_state(mdev, D_FAILED)) { | 4430 | if (get_ldev_if_state(mdev, D_FAILED)) { |
4296 | drbd_rs_complete_io(mdev, sector); | 4431 | drbd_rs_complete_io(mdev, sector); |
4297 | drbd_rs_failed_io(mdev, sector, size); | 4432 | switch (be16_to_cpu(h->command)) { |
4433 | case P_NEG_RS_DREPLY: | ||
4434 | drbd_rs_failed_io(mdev, sector, size); | ||
4435 | case P_RS_CANCEL: | ||
4436 | break; | ||
4437 | default: | ||
4438 | D_ASSERT(0); | ||
4439 | put_ldev(mdev); | ||
4440 | return false; | ||
4441 | } | ||
4298 | put_ldev(mdev); | 4442 | put_ldev(mdev); |
4299 | } | 4443 | } |
4300 | 4444 | ||
4301 | return TRUE; | 4445 | return true; |
4302 | } | 4446 | } |
4303 | 4447 | ||
4304 | static int got_BarrierAck(struct drbd_conf *mdev, struct p_header80 *h) | 4448 | static int got_BarrierAck(struct drbd_conf *mdev, struct p_header80 *h) |
@@ -4307,7 +4451,14 @@ static int got_BarrierAck(struct drbd_conf *mdev, struct p_header80 *h) | |||
4307 | 4451 | ||
4308 | tl_release(mdev, p->barrier, be32_to_cpu(p->set_size)); | 4452 | tl_release(mdev, p->barrier, be32_to_cpu(p->set_size)); |
4309 | 4453 | ||
4310 | return TRUE; | 4454 | if (mdev->state.conn == C_AHEAD && |
4455 | atomic_read(&mdev->ap_in_flight) == 0 && | ||
4456 | !test_and_set_bit(AHEAD_TO_SYNC_SOURCE, &mdev->current_epoch->flags)) { | ||
4457 | mdev->start_resync_timer.expires = jiffies + HZ; | ||
4458 | add_timer(&mdev->start_resync_timer); | ||
4459 | } | ||
4460 | |||
4461 | return true; | ||
4311 | } | 4462 | } |
4312 | 4463 | ||
4313 | static int got_OVResult(struct drbd_conf *mdev, struct p_header80 *h) | 4464 | static int got_OVResult(struct drbd_conf *mdev, struct p_header80 *h) |
@@ -4328,12 +4479,18 @@ static int got_OVResult(struct drbd_conf *mdev, struct p_header80 *h) | |||
4328 | ov_oos_print(mdev); | 4479 | ov_oos_print(mdev); |
4329 | 4480 | ||
4330 | if (!get_ldev(mdev)) | 4481 | if (!get_ldev(mdev)) |
4331 | return TRUE; | 4482 | return true; |
4332 | 4483 | ||
4333 | drbd_rs_complete_io(mdev, sector); | 4484 | drbd_rs_complete_io(mdev, sector); |
4334 | dec_rs_pending(mdev); | 4485 | dec_rs_pending(mdev); |
4335 | 4486 | ||
4336 | if (--mdev->ov_left == 0) { | 4487 | --mdev->ov_left; |
4488 | |||
4489 | /* let's advance progress step marks only for every other megabyte */ | ||
4490 | if ((mdev->ov_left & 0x200) == 0x200) | ||
4491 | drbd_advance_rs_marks(mdev, mdev->ov_left); | ||
4492 | |||
4493 | if (mdev->ov_left == 0) { | ||
4337 | w = kmalloc(sizeof(*w), GFP_NOIO); | 4494 | w = kmalloc(sizeof(*w), GFP_NOIO); |
4338 | if (w) { | 4495 | if (w) { |
4339 | w->cb = w_ov_finished; | 4496 | w->cb = w_ov_finished; |
@@ -4345,12 +4502,12 @@ static int got_OVResult(struct drbd_conf *mdev, struct p_header80 *h) | |||
4345 | } | 4502 | } |
4346 | } | 4503 | } |
4347 | put_ldev(mdev); | 4504 | put_ldev(mdev); |
4348 | return TRUE; | 4505 | return true; |
4349 | } | 4506 | } |
4350 | 4507 | ||
4351 | static int got_skip(struct drbd_conf *mdev, struct p_header80 *h) | 4508 | static int got_skip(struct drbd_conf *mdev, struct p_header80 *h) |
4352 | { | 4509 | { |
4353 | return TRUE; | 4510 | return true; |
4354 | } | 4511 | } |
4355 | 4512 | ||
4356 | struct asender_cmd { | 4513 | struct asender_cmd { |
@@ -4378,6 +4535,7 @@ static struct asender_cmd *get_asender_cmd(int cmd) | |||
4378 | [P_STATE_CHG_REPLY] = { sizeof(struct p_req_state_reply), got_RqSReply }, | 4535 | [P_STATE_CHG_REPLY] = { sizeof(struct p_req_state_reply), got_RqSReply }, |
4379 | [P_RS_IS_IN_SYNC] = { sizeof(struct p_block_ack), got_IsInSync }, | 4536 | [P_RS_IS_IN_SYNC] = { sizeof(struct p_block_ack), got_IsInSync }, |
4380 | [P_DELAY_PROBE] = { sizeof(struct p_delay_probe93), got_skip }, | 4537 | [P_DELAY_PROBE] = { sizeof(struct p_delay_probe93), got_skip }, |
4538 | [P_RS_CANCEL] = { sizeof(struct p_block_ack), got_NegRSDReply}, | ||
4381 | [P_MAX_CMD] = { 0, NULL }, | 4539 | [P_MAX_CMD] = { 0, NULL }, |
4382 | }; | 4540 | }; |
4383 | if (cmd > P_MAX_CMD || asender_tbl[cmd].process == NULL) | 4541 | if (cmd > P_MAX_CMD || asender_tbl[cmd].process == NULL) |
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index ad3fc6228f27..5c0c8be1bb0a 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c | |||
@@ -140,9 +140,14 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev, | |||
140 | struct hlist_node *n; | 140 | struct hlist_node *n; |
141 | struct hlist_head *slot; | 141 | struct hlist_head *slot; |
142 | 142 | ||
143 | /* before we can signal completion to the upper layers, | 143 | /* Before we can signal completion to the upper layers, |
144 | * we may need to close the current epoch */ | 144 | * we may need to close the current epoch. |
145 | * We can skip this, if this request has not even been sent, because we | ||
146 | * did not have a fully established connection yet/anymore, during | ||
147 | * bitmap exchange, or while we are C_AHEAD due to congestion policy. | ||
148 | */ | ||
145 | if (mdev->state.conn >= C_CONNECTED && | 149 | if (mdev->state.conn >= C_CONNECTED && |
150 | (s & RQ_NET_SENT) != 0 && | ||
146 | req->epoch == mdev->newest_tle->br_number) | 151 | req->epoch == mdev->newest_tle->br_number) |
147 | queue_barrier(mdev); | 152 | queue_barrier(mdev); |
148 | 153 | ||
@@ -440,7 +445,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, | |||
440 | req->rq_state |= RQ_LOCAL_COMPLETED; | 445 | req->rq_state |= RQ_LOCAL_COMPLETED; |
441 | req->rq_state &= ~RQ_LOCAL_PENDING; | 446 | req->rq_state &= ~RQ_LOCAL_PENDING; |
442 | 447 | ||
443 | __drbd_chk_io_error(mdev, FALSE); | 448 | __drbd_chk_io_error(mdev, false); |
444 | _req_may_be_done_not_susp(req, m); | 449 | _req_may_be_done_not_susp(req, m); |
445 | put_ldev(mdev); | 450 | put_ldev(mdev); |
446 | break; | 451 | break; |
@@ -461,7 +466,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, | |||
461 | 466 | ||
462 | D_ASSERT(!(req->rq_state & RQ_NET_MASK)); | 467 | D_ASSERT(!(req->rq_state & RQ_NET_MASK)); |
463 | 468 | ||
464 | __drbd_chk_io_error(mdev, FALSE); | 469 | __drbd_chk_io_error(mdev, false); |
465 | put_ldev(mdev); | 470 | put_ldev(mdev); |
466 | 471 | ||
467 | /* no point in retrying if there is no good remote data, | 472 | /* no point in retrying if there is no good remote data, |
@@ -545,6 +550,14 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, | |||
545 | 550 | ||
546 | break; | 551 | break; |
547 | 552 | ||
553 | case queue_for_send_oos: | ||
554 | req->rq_state |= RQ_NET_QUEUED; | ||
555 | req->w.cb = w_send_oos; | ||
556 | drbd_queue_work(&mdev->data.work, &req->w); | ||
557 | break; | ||
558 | |||
559 | case oos_handed_to_network: | ||
560 | /* actually the same */ | ||
548 | case send_canceled: | 561 | case send_canceled: |
549 | /* treat it the same */ | 562 | /* treat it the same */ |
550 | case send_failed: | 563 | case send_failed: |
@@ -558,6 +571,9 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, | |||
558 | 571 | ||
559 | case handed_over_to_network: | 572 | case handed_over_to_network: |
560 | /* assert something? */ | 573 | /* assert something? */ |
574 | if (bio_data_dir(req->master_bio) == WRITE) | ||
575 | atomic_add(req->size>>9, &mdev->ap_in_flight); | ||
576 | |||
561 | if (bio_data_dir(req->master_bio) == WRITE && | 577 | if (bio_data_dir(req->master_bio) == WRITE && |
562 | mdev->net_conf->wire_protocol == DRBD_PROT_A) { | 578 | mdev->net_conf->wire_protocol == DRBD_PROT_A) { |
563 | /* this is what is dangerous about protocol A: | 579 | /* this is what is dangerous about protocol A: |
@@ -591,6 +607,9 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, | |||
591 | dec_ap_pending(mdev); | 607 | dec_ap_pending(mdev); |
592 | req->rq_state &= ~(RQ_NET_OK|RQ_NET_PENDING); | 608 | req->rq_state &= ~(RQ_NET_OK|RQ_NET_PENDING); |
593 | req->rq_state |= RQ_NET_DONE; | 609 | req->rq_state |= RQ_NET_DONE; |
610 | if (req->rq_state & RQ_NET_SENT && req->rq_state & RQ_WRITE) | ||
611 | atomic_sub(req->size>>9, &mdev->ap_in_flight); | ||
612 | |||
594 | /* if it is still queued, we may not complete it here. | 613 | /* if it is still queued, we may not complete it here. |
595 | * it will be canceled soon. */ | 614 | * it will be canceled soon. */ |
596 | if (!(req->rq_state & RQ_NET_QUEUED)) | 615 | if (!(req->rq_state & RQ_NET_QUEUED)) |
@@ -628,14 +647,17 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, | |||
628 | req->rq_state |= RQ_NET_OK; | 647 | req->rq_state |= RQ_NET_OK; |
629 | D_ASSERT(req->rq_state & RQ_NET_PENDING); | 648 | D_ASSERT(req->rq_state & RQ_NET_PENDING); |
630 | dec_ap_pending(mdev); | 649 | dec_ap_pending(mdev); |
650 | atomic_sub(req->size>>9, &mdev->ap_in_flight); | ||
631 | req->rq_state &= ~RQ_NET_PENDING; | 651 | req->rq_state &= ~RQ_NET_PENDING; |
632 | _req_may_be_done_not_susp(req, m); | 652 | _req_may_be_done_not_susp(req, m); |
633 | break; | 653 | break; |
634 | 654 | ||
635 | case neg_acked: | 655 | case neg_acked: |
636 | /* assert something? */ | 656 | /* assert something? */ |
637 | if (req->rq_state & RQ_NET_PENDING) | 657 | if (req->rq_state & RQ_NET_PENDING) { |
638 | dec_ap_pending(mdev); | 658 | dec_ap_pending(mdev); |
659 | atomic_sub(req->size>>9, &mdev->ap_in_flight); | ||
660 | } | ||
639 | req->rq_state &= ~(RQ_NET_OK|RQ_NET_PENDING); | 661 | req->rq_state &= ~(RQ_NET_OK|RQ_NET_PENDING); |
640 | 662 | ||
641 | req->rq_state |= RQ_NET_DONE; | 663 | req->rq_state |= RQ_NET_DONE; |
@@ -690,8 +712,11 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, | |||
690 | dev_err(DEV, "FIXME (barrier_acked but pending)\n"); | 712 | dev_err(DEV, "FIXME (barrier_acked but pending)\n"); |
691 | list_move(&req->tl_requests, &mdev->out_of_sequence_requests); | 713 | list_move(&req->tl_requests, &mdev->out_of_sequence_requests); |
692 | } | 714 | } |
693 | D_ASSERT(req->rq_state & RQ_NET_SENT); | 715 | if ((req->rq_state & RQ_NET_MASK) != 0) { |
694 | req->rq_state |= RQ_NET_DONE; | 716 | req->rq_state |= RQ_NET_DONE; |
717 | if (mdev->net_conf->wire_protocol == DRBD_PROT_A) | ||
718 | atomic_sub(req->size>>9, &mdev->ap_in_flight); | ||
719 | } | ||
695 | _req_may_be_done(req, m); /* Allowed while state.susp */ | 720 | _req_may_be_done(req, m); /* Allowed while state.susp */ |
696 | break; | 721 | break; |
697 | 722 | ||
@@ -738,14 +763,14 @@ static int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int s | |||
738 | return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr); | 763 | return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr); |
739 | } | 764 | } |
740 | 765 | ||
741 | static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio) | 766 | static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time) |
742 | { | 767 | { |
743 | const int rw = bio_rw(bio); | 768 | const int rw = bio_rw(bio); |
744 | const int size = bio->bi_size; | 769 | const int size = bio->bi_size; |
745 | const sector_t sector = bio->bi_sector; | 770 | const sector_t sector = bio->bi_sector; |
746 | struct drbd_tl_epoch *b = NULL; | 771 | struct drbd_tl_epoch *b = NULL; |
747 | struct drbd_request *req; | 772 | struct drbd_request *req; |
748 | int local, remote; | 773 | int local, remote, send_oos = 0; |
749 | int err = -EIO; | 774 | int err = -EIO; |
750 | int ret = 0; | 775 | int ret = 0; |
751 | 776 | ||
@@ -759,6 +784,7 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio) | |||
759 | bio_endio(bio, -ENOMEM); | 784 | bio_endio(bio, -ENOMEM); |
760 | return 0; | 785 | return 0; |
761 | } | 786 | } |
787 | req->start_time = start_time; | ||
762 | 788 | ||
763 | local = get_ldev(mdev); | 789 | local = get_ldev(mdev); |
764 | if (!local) { | 790 | if (!local) { |
@@ -808,9 +834,9 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio) | |||
808 | drbd_al_begin_io(mdev, sector); | 834 | drbd_al_begin_io(mdev, sector); |
809 | } | 835 | } |
810 | 836 | ||
811 | remote = remote && (mdev->state.pdsk == D_UP_TO_DATE || | 837 | remote = remote && drbd_should_do_remote(mdev->state); |
812 | (mdev->state.pdsk == D_INCONSISTENT && | 838 | send_oos = rw == WRITE && drbd_should_send_oos(mdev->state); |
813 | mdev->state.conn >= C_CONNECTED)); | 839 | D_ASSERT(!(remote && send_oos)); |
814 | 840 | ||
815 | if (!(local || remote) && !is_susp(mdev->state)) { | 841 | if (!(local || remote) && !is_susp(mdev->state)) { |
816 | if (__ratelimit(&drbd_ratelimit_state)) | 842 | if (__ratelimit(&drbd_ratelimit_state)) |
@@ -824,7 +850,7 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio) | |||
824 | * but there is a race between testing the bit and pointer outside the | 850 | * but there is a race between testing the bit and pointer outside the |
825 | * spinlock, and grabbing the spinlock. | 851 | * spinlock, and grabbing the spinlock. |
826 | * if we lost that race, we retry. */ | 852 | * if we lost that race, we retry. */ |
827 | if (rw == WRITE && remote && | 853 | if (rw == WRITE && (remote || send_oos) && |
828 | mdev->unused_spare_tle == NULL && | 854 | mdev->unused_spare_tle == NULL && |
829 | test_bit(CREATE_BARRIER, &mdev->flags)) { | 855 | test_bit(CREATE_BARRIER, &mdev->flags)) { |
830 | allocate_barrier: | 856 | allocate_barrier: |
@@ -842,18 +868,19 @@ allocate_barrier: | |||
842 | if (is_susp(mdev->state)) { | 868 | if (is_susp(mdev->state)) { |
843 | /* If we got suspended, use the retry mechanism of | 869 | /* If we got suspended, use the retry mechanism of |
844 | generic_make_request() to restart processing of this | 870 | generic_make_request() to restart processing of this |
845 | bio. In the next call to drbd_make_request_26 | 871 | bio. In the next call to drbd_make_request |
846 | we sleep in inc_ap_bio() */ | 872 | we sleep in inc_ap_bio() */ |
847 | ret = 1; | 873 | ret = 1; |
848 | spin_unlock_irq(&mdev->req_lock); | 874 | spin_unlock_irq(&mdev->req_lock); |
849 | goto fail_free_complete; | 875 | goto fail_free_complete; |
850 | } | 876 | } |
851 | 877 | ||
852 | if (remote) { | 878 | if (remote || send_oos) { |
853 | remote = (mdev->state.pdsk == D_UP_TO_DATE || | 879 | remote = drbd_should_do_remote(mdev->state); |
854 | (mdev->state.pdsk == D_INCONSISTENT && | 880 | send_oos = rw == WRITE && drbd_should_send_oos(mdev->state); |
855 | mdev->state.conn >= C_CONNECTED)); | 881 | D_ASSERT(!(remote && send_oos)); |
856 | if (!remote) | 882 | |
883 | if (!(remote || send_oos)) | ||
857 | dev_warn(DEV, "lost connection while grabbing the req_lock!\n"); | 884 | dev_warn(DEV, "lost connection while grabbing the req_lock!\n"); |
858 | if (!(local || remote)) { | 885 | if (!(local || remote)) { |
859 | dev_err(DEV, "IO ERROR: neither local nor remote disk\n"); | 886 | dev_err(DEV, "IO ERROR: neither local nor remote disk\n"); |
@@ -866,7 +893,7 @@ allocate_barrier: | |||
866 | mdev->unused_spare_tle = b; | 893 | mdev->unused_spare_tle = b; |
867 | b = NULL; | 894 | b = NULL; |
868 | } | 895 | } |
869 | if (rw == WRITE && remote && | 896 | if (rw == WRITE && (remote || send_oos) && |
870 | mdev->unused_spare_tle == NULL && | 897 | mdev->unused_spare_tle == NULL && |
871 | test_bit(CREATE_BARRIER, &mdev->flags)) { | 898 | test_bit(CREATE_BARRIER, &mdev->flags)) { |
872 | /* someone closed the current epoch | 899 | /* someone closed the current epoch |
@@ -889,7 +916,7 @@ allocate_barrier: | |||
889 | * barrier packet. To get the write ordering right, we only have to | 916 | * barrier packet. To get the write ordering right, we only have to |
890 | * make sure that, if this is a write request and it triggered a | 917 | * make sure that, if this is a write request and it triggered a |
891 | * barrier packet, this request is queued within the same spinlock. */ | 918 | * barrier packet, this request is queued within the same spinlock. */ |
892 | if (remote && mdev->unused_spare_tle && | 919 | if ((remote || send_oos) && mdev->unused_spare_tle && |
893 | test_and_clear_bit(CREATE_BARRIER, &mdev->flags)) { | 920 | test_and_clear_bit(CREATE_BARRIER, &mdev->flags)) { |
894 | _tl_add_barrier(mdev, mdev->unused_spare_tle); | 921 | _tl_add_barrier(mdev, mdev->unused_spare_tle); |
895 | mdev->unused_spare_tle = NULL; | 922 | mdev->unused_spare_tle = NULL; |
@@ -937,6 +964,34 @@ allocate_barrier: | |||
937 | ? queue_for_net_write | 964 | ? queue_for_net_write |
938 | : queue_for_net_read); | 965 | : queue_for_net_read); |
939 | } | 966 | } |
967 | if (send_oos && drbd_set_out_of_sync(mdev, sector, size)) | ||
968 | _req_mod(req, queue_for_send_oos); | ||
969 | |||
970 | if (remote && | ||
971 | mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96) { | ||
972 | int congested = 0; | ||
973 | |||
974 | if (mdev->net_conf->cong_fill && | ||
975 | atomic_read(&mdev->ap_in_flight) >= mdev->net_conf->cong_fill) { | ||
976 | dev_info(DEV, "Congestion-fill threshold reached\n"); | ||
977 | congested = 1; | ||
978 | } | ||
979 | |||
980 | if (mdev->act_log->used >= mdev->net_conf->cong_extents) { | ||
981 | dev_info(DEV, "Congestion-extents threshold reached\n"); | ||
982 | congested = 1; | ||
983 | } | ||
984 | |||
985 | if (congested) { | ||
986 | queue_barrier(mdev); /* last barrier, after mirrored writes */ | ||
987 | |||
988 | if (mdev->net_conf->on_congestion == OC_PULL_AHEAD) | ||
989 | _drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL); | ||
990 | else /*mdev->net_conf->on_congestion == OC_DISCONNECT */ | ||
991 | _drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), 0, NULL); | ||
992 | } | ||
993 | } | ||
994 | |||
940 | spin_unlock_irq(&mdev->req_lock); | 995 | spin_unlock_irq(&mdev->req_lock); |
941 | kfree(b); /* if someone else has beaten us to it... */ | 996 | kfree(b); /* if someone else has beaten us to it... */ |
942 | 997 | ||
@@ -949,9 +1004,9 @@ allocate_barrier: | |||
949 | * stable storage, and this is a WRITE, we may not even submit | 1004 | * stable storage, and this is a WRITE, we may not even submit |
950 | * this bio. */ | 1005 | * this bio. */ |
951 | if (get_ldev(mdev)) { | 1006 | if (get_ldev(mdev)) { |
952 | if (FAULT_ACTIVE(mdev, rw == WRITE ? DRBD_FAULT_DT_WR | 1007 | if (drbd_insert_fault(mdev, rw == WRITE ? DRBD_FAULT_DT_WR |
953 | : rw == READ ? DRBD_FAULT_DT_RD | 1008 | : rw == READ ? DRBD_FAULT_DT_RD |
954 | : DRBD_FAULT_DT_RA)) | 1009 | : DRBD_FAULT_DT_RA)) |
955 | bio_endio(req->private_bio, -EIO); | 1010 | bio_endio(req->private_bio, -EIO); |
956 | else | 1011 | else |
957 | generic_make_request(req->private_bio); | 1012 | generic_make_request(req->private_bio); |
@@ -1018,16 +1073,19 @@ static int drbd_fail_request_early(struct drbd_conf *mdev, int is_write) | |||
1018 | return 0; | 1073 | return 0; |
1019 | } | 1074 | } |
1020 | 1075 | ||
1021 | int drbd_make_request_26(struct request_queue *q, struct bio *bio) | 1076 | int drbd_make_request(struct request_queue *q, struct bio *bio) |
1022 | { | 1077 | { |
1023 | unsigned int s_enr, e_enr; | 1078 | unsigned int s_enr, e_enr; |
1024 | struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata; | 1079 | struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata; |
1080 | unsigned long start_time; | ||
1025 | 1081 | ||
1026 | if (drbd_fail_request_early(mdev, bio_data_dir(bio) & WRITE)) { | 1082 | if (drbd_fail_request_early(mdev, bio_data_dir(bio) & WRITE)) { |
1027 | bio_endio(bio, -EPERM); | 1083 | bio_endio(bio, -EPERM); |
1028 | return 0; | 1084 | return 0; |
1029 | } | 1085 | } |
1030 | 1086 | ||
1087 | start_time = jiffies; | ||
1088 | |||
1031 | /* | 1089 | /* |
1032 | * what we "blindly" assume: | 1090 | * what we "blindly" assume: |
1033 | */ | 1091 | */ |
@@ -1042,12 +1100,12 @@ int drbd_make_request_26(struct request_queue *q, struct bio *bio) | |||
1042 | 1100 | ||
1043 | if (likely(s_enr == e_enr)) { | 1101 | if (likely(s_enr == e_enr)) { |
1044 | inc_ap_bio(mdev, 1); | 1102 | inc_ap_bio(mdev, 1); |
1045 | return drbd_make_request_common(mdev, bio); | 1103 | return drbd_make_request_common(mdev, bio, start_time); |
1046 | } | 1104 | } |
1047 | 1105 | ||
1048 | /* can this bio be split generically? | 1106 | /* can this bio be split generically? |
1049 | * Maybe add our own split-arbitrary-bios function. */ | 1107 | * Maybe add our own split-arbitrary-bios function. */ |
1050 | if (bio->bi_vcnt != 1 || bio->bi_idx != 0 || bio->bi_size > DRBD_MAX_SEGMENT_SIZE) { | 1108 | if (bio->bi_vcnt != 1 || bio->bi_idx != 0 || bio->bi_size > DRBD_MAX_BIO_SIZE) { |
1051 | /* rather error out here than BUG in bio_split */ | 1109 | /* rather error out here than BUG in bio_split */ |
1052 | dev_err(DEV, "bio would need to, but cannot, be split: " | 1110 | dev_err(DEV, "bio would need to, but cannot, be split: " |
1053 | "(vcnt=%u,idx=%u,size=%u,sector=%llu)\n", | 1111 | "(vcnt=%u,idx=%u,size=%u,sector=%llu)\n", |
@@ -1069,11 +1127,7 @@ int drbd_make_request_26(struct request_queue *q, struct bio *bio) | |||
1069 | const int sps = 1 << HT_SHIFT; /* sectors per slot */ | 1127 | const int sps = 1 << HT_SHIFT; /* sectors per slot */ |
1070 | const int mask = sps - 1; | 1128 | const int mask = sps - 1; |
1071 | const sector_t first_sectors = sps - (sect & mask); | 1129 | const sector_t first_sectors = sps - (sect & mask); |
1072 | bp = bio_split(bio, | 1130 | bp = bio_split(bio, first_sectors); |
1073 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) | ||
1074 | bio_split_pool, | ||
1075 | #endif | ||
1076 | first_sectors); | ||
1077 | 1131 | ||
1078 | /* we need to get a "reference count" (ap_bio_cnt) | 1132 | /* we need to get a "reference count" (ap_bio_cnt) |
1079 | * to avoid races with the disconnect/reconnect/suspend code. | 1133 | * to avoid races with the disconnect/reconnect/suspend code. |
@@ -1084,10 +1138,10 @@ int drbd_make_request_26(struct request_queue *q, struct bio *bio) | |||
1084 | 1138 | ||
1085 | D_ASSERT(e_enr == s_enr + 1); | 1139 | D_ASSERT(e_enr == s_enr + 1); |
1086 | 1140 | ||
1087 | while (drbd_make_request_common(mdev, &bp->bio1)) | 1141 | while (drbd_make_request_common(mdev, &bp->bio1, start_time)) |
1088 | inc_ap_bio(mdev, 1); | 1142 | inc_ap_bio(mdev, 1); |
1089 | 1143 | ||
1090 | while (drbd_make_request_common(mdev, &bp->bio2)) | 1144 | while (drbd_make_request_common(mdev, &bp->bio2, start_time)) |
1091 | inc_ap_bio(mdev, 1); | 1145 | inc_ap_bio(mdev, 1); |
1092 | 1146 | ||
1093 | dec_ap_bio(mdev); | 1147 | dec_ap_bio(mdev); |
@@ -1098,7 +1152,7 @@ int drbd_make_request_26(struct request_queue *q, struct bio *bio) | |||
1098 | } | 1152 | } |
1099 | 1153 | ||
1100 | /* This is called by bio_add_page(). With this function we reduce | 1154 | /* This is called by bio_add_page(). With this function we reduce |
1101 | * the number of BIOs that span over multiple DRBD_MAX_SEGMENT_SIZEs | 1155 | * the number of BIOs that span over multiple DRBD_MAX_BIO_SIZEs |
1102 | * units (was AL_EXTENTs). | 1156 | * units (was AL_EXTENTs). |
1103 | * | 1157 | * |
1104 | * we do the calculation within the lower 32bit of the byte offsets, | 1158 | * we do the calculation within the lower 32bit of the byte offsets, |
@@ -1108,7 +1162,7 @@ int drbd_make_request_26(struct request_queue *q, struct bio *bio) | |||
1108 | * As long as the BIO is empty we have to allow at least one bvec, | 1162 | * As long as the BIO is empty we have to allow at least one bvec, |
1109 | * regardless of size and offset. so the resulting bio may still | 1163 | * regardless of size and offset. so the resulting bio may still |
1110 | * cross extent boundaries. those are dealt with (bio_split) in | 1164 | * cross extent boundaries. those are dealt with (bio_split) in |
1111 | * drbd_make_request_26. | 1165 | * drbd_make_request. |
1112 | */ | 1166 | */ |
1113 | int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec) | 1167 | int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec) |
1114 | { | 1168 | { |
@@ -1118,8 +1172,8 @@ int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct | |||
1118 | unsigned int bio_size = bvm->bi_size; | 1172 | unsigned int bio_size = bvm->bi_size; |
1119 | int limit, backing_limit; | 1173 | int limit, backing_limit; |
1120 | 1174 | ||
1121 | limit = DRBD_MAX_SEGMENT_SIZE | 1175 | limit = DRBD_MAX_BIO_SIZE |
1122 | - ((bio_offset & (DRBD_MAX_SEGMENT_SIZE-1)) + bio_size); | 1176 | - ((bio_offset & (DRBD_MAX_BIO_SIZE-1)) + bio_size); |
1123 | if (limit < 0) | 1177 | if (limit < 0) |
1124 | limit = 0; | 1178 | limit = 0; |
1125 | if (bio_size == 0) { | 1179 | if (bio_size == 0) { |
@@ -1136,3 +1190,42 @@ int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct | |||
1136 | } | 1190 | } |
1137 | return limit; | 1191 | return limit; |
1138 | } | 1192 | } |
1193 | |||
1194 | void request_timer_fn(unsigned long data) | ||
1195 | { | ||
1196 | struct drbd_conf *mdev = (struct drbd_conf *) data; | ||
1197 | struct drbd_request *req; /* oldest request */ | ||
1198 | struct list_head *le; | ||
1199 | unsigned long et = 0; /* effective timeout = ko_count * timeout */ | ||
1200 | |||
1201 | if (get_net_conf(mdev)) { | ||
1202 | et = mdev->net_conf->timeout*HZ/10 * mdev->net_conf->ko_count; | ||
1203 | put_net_conf(mdev); | ||
1204 | } | ||
1205 | if (!et || mdev->state.conn < C_WF_REPORT_PARAMS) | ||
1206 | return; /* Recurring timer stopped */ | ||
1207 | |||
1208 | spin_lock_irq(&mdev->req_lock); | ||
1209 | le = &mdev->oldest_tle->requests; | ||
1210 | if (list_empty(le)) { | ||
1211 | spin_unlock_irq(&mdev->req_lock); | ||
1212 | mod_timer(&mdev->request_timer, jiffies + et); | ||
1213 | return; | ||
1214 | } | ||
1215 | |||
1216 | le = le->prev; | ||
1217 | req = list_entry(le, struct drbd_request, tl_requests); | ||
1218 | if (time_is_before_eq_jiffies(req->start_time + et)) { | ||
1219 | if (req->rq_state & RQ_NET_PENDING) { | ||
1220 | dev_warn(DEV, "Remote failed to finish a request within ko-count * timeout\n"); | ||
1221 | _drbd_set_state(_NS(mdev, conn, C_TIMEOUT), CS_VERBOSE, NULL); | ||
1222 | } else { | ||
1223 | dev_warn(DEV, "Local backing block device frozen?\n"); | ||
1224 | mod_timer(&mdev->request_timer, jiffies + et); | ||
1225 | } | ||
1226 | } else { | ||
1227 | mod_timer(&mdev->request_timer, req->start_time + et); | ||
1228 | } | ||
1229 | |||
1230 | spin_unlock_irq(&mdev->req_lock); | ||
1231 | } | ||
diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index ab2bd09d54b4..32e2c3e6a813 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h | |||
@@ -82,14 +82,16 @@ enum drbd_req_event { | |||
82 | to_be_submitted, | 82 | to_be_submitted, |
83 | 83 | ||
84 | /* XXX yes, now I am inconsistent... | 84 | /* XXX yes, now I am inconsistent... |
85 | * these two are not "events" but "actions" | 85 | * these are not "events" but "actions" |
86 | * oh, well... */ | 86 | * oh, well... */ |
87 | queue_for_net_write, | 87 | queue_for_net_write, |
88 | queue_for_net_read, | 88 | queue_for_net_read, |
89 | queue_for_send_oos, | ||
89 | 90 | ||
90 | send_canceled, | 91 | send_canceled, |
91 | send_failed, | 92 | send_failed, |
92 | handed_over_to_network, | 93 | handed_over_to_network, |
94 | oos_handed_to_network, | ||
93 | connection_lost_while_pending, | 95 | connection_lost_while_pending, |
94 | read_retry_remote_canceled, | 96 | read_retry_remote_canceled, |
95 | recv_acked_by_peer, | 97 | recv_acked_by_peer, |
@@ -289,7 +291,6 @@ static inline struct drbd_request *drbd_req_new(struct drbd_conf *mdev, | |||
289 | req->epoch = 0; | 291 | req->epoch = 0; |
290 | req->sector = bio_src->bi_sector; | 292 | req->sector = bio_src->bi_sector; |
291 | req->size = bio_src->bi_size; | 293 | req->size = bio_src->bi_size; |
292 | req->start_time = jiffies; | ||
293 | INIT_HLIST_NODE(&req->colision); | 294 | INIT_HLIST_NODE(&req->colision); |
294 | INIT_LIST_HEAD(&req->tl_requests); | 295 | INIT_LIST_HEAD(&req->tl_requests); |
295 | INIT_LIST_HEAD(&req->w.list); | 296 | INIT_LIST_HEAD(&req->w.list); |
@@ -321,6 +322,7 @@ extern int __req_mod(struct drbd_request *req, enum drbd_req_event what, | |||
321 | struct bio_and_error *m); | 322 | struct bio_and_error *m); |
322 | extern void complete_master_bio(struct drbd_conf *mdev, | 323 | extern void complete_master_bio(struct drbd_conf *mdev, |
323 | struct bio_and_error *m); | 324 | struct bio_and_error *m); |
325 | extern void request_timer_fn(unsigned long data); | ||
324 | 326 | ||
325 | /* use this if you don't want to deal with calling complete_master_bio() | 327 | /* use this if you don't want to deal with calling complete_master_bio() |
326 | * outside the spinlock, e.g. when walking some list on cleanup. */ | 328 | * outside the spinlock, e.g. when walking some list on cleanup. */ |
@@ -338,23 +340,43 @@ static inline int _req_mod(struct drbd_request *req, enum drbd_req_event what) | |||
338 | return rv; | 340 | return rv; |
339 | } | 341 | } |
340 | 342 | ||
341 | /* completion of master bio is outside of spinlock. | 343 | /* completion of master bio is outside of our spinlock. |
342 | * If you need it irqsave, do it your self! | 344 | * We still may or may not be inside some irqs disabled section |
343 | * Which means: don't use from bio endio callback. */ | 345 | * of the lower level driver completion callback, so we need to |
346 | * spin_lock_irqsave here. */ | ||
344 | static inline int req_mod(struct drbd_request *req, | 347 | static inline int req_mod(struct drbd_request *req, |
345 | enum drbd_req_event what) | 348 | enum drbd_req_event what) |
346 | { | 349 | { |
350 | unsigned long flags; | ||
347 | struct drbd_conf *mdev = req->mdev; | 351 | struct drbd_conf *mdev = req->mdev; |
348 | struct bio_and_error m; | 352 | struct bio_and_error m; |
349 | int rv; | 353 | int rv; |
350 | 354 | ||
351 | spin_lock_irq(&mdev->req_lock); | 355 | spin_lock_irqsave(&mdev->req_lock, flags); |
352 | rv = __req_mod(req, what, &m); | 356 | rv = __req_mod(req, what, &m); |
353 | spin_unlock_irq(&mdev->req_lock); | 357 | spin_unlock_irqrestore(&mdev->req_lock, flags); |
354 | 358 | ||
355 | if (m.bio) | 359 | if (m.bio) |
356 | complete_master_bio(mdev, &m); | 360 | complete_master_bio(mdev, &m); |
357 | 361 | ||
358 | return rv; | 362 | return rv; |
359 | } | 363 | } |
364 | |||
365 | static inline bool drbd_should_do_remote(union drbd_state s) | ||
366 | { | ||
367 | return s.pdsk == D_UP_TO_DATE || | ||
368 | (s.pdsk >= D_INCONSISTENT && | ||
369 | s.conn >= C_WF_BITMAP_T && | ||
370 | s.conn < C_AHEAD); | ||
371 | /* Before proto 96 that was >= CONNECTED instead of >= C_WF_BITMAP_T. | ||
372 | That is equivalent since before 96 IO was frozen in the C_WF_BITMAP* | ||
373 | states. */ | ||
374 | } | ||
375 | static inline bool drbd_should_send_oos(union drbd_state s) | ||
376 | { | ||
377 | return s.conn == C_AHEAD || s.conn == C_WF_BITMAP_S; | ||
378 | /* pdsk = D_INCONSISTENT as a consequence. Protocol 96 check not necessary | ||
379 | since we enter state C_AHEAD only if proto >= 96 */ | ||
380 | } | ||
381 | |||
360 | #endif | 382 | #endif |
diff --git a/drivers/block/drbd/drbd_strings.c b/drivers/block/drbd/drbd_strings.c index 85179e1fb50a..c44a2a602772 100644 --- a/drivers/block/drbd/drbd_strings.c +++ b/drivers/block/drbd/drbd_strings.c | |||
@@ -48,6 +48,8 @@ static const char *drbd_conn_s_names[] = { | |||
48 | [C_PAUSED_SYNC_T] = "PausedSyncT", | 48 | [C_PAUSED_SYNC_T] = "PausedSyncT", |
49 | [C_VERIFY_S] = "VerifyS", | 49 | [C_VERIFY_S] = "VerifyS", |
50 | [C_VERIFY_T] = "VerifyT", | 50 | [C_VERIFY_T] = "VerifyT", |
51 | [C_AHEAD] = "Ahead", | ||
52 | [C_BEHIND] = "Behind", | ||
51 | }; | 53 | }; |
52 | 54 | ||
53 | static const char *drbd_role_s_names[] = { | 55 | static const char *drbd_role_s_names[] = { |
@@ -92,7 +94,7 @@ static const char *drbd_state_sw_errors[] = { | |||
92 | const char *drbd_conn_str(enum drbd_conns s) | 94 | const char *drbd_conn_str(enum drbd_conns s) |
93 | { | 95 | { |
94 | /* enums are unsigned... */ | 96 | /* enums are unsigned... */ |
95 | return s > C_PAUSED_SYNC_T ? "TOO_LARGE" : drbd_conn_s_names[s]; | 97 | return s > C_BEHIND ? "TOO_LARGE" : drbd_conn_s_names[s]; |
96 | } | 98 | } |
97 | 99 | ||
98 | const char *drbd_role_str(enum drbd_role s) | 100 | const char *drbd_role_str(enum drbd_role s) |
@@ -105,7 +107,7 @@ const char *drbd_disk_str(enum drbd_disk_state s) | |||
105 | return s > D_UP_TO_DATE ? "TOO_LARGE" : drbd_disk_s_names[s]; | 107 | return s > D_UP_TO_DATE ? "TOO_LARGE" : drbd_disk_s_names[s]; |
106 | } | 108 | } |
107 | 109 | ||
108 | const char *drbd_set_st_err_str(enum drbd_state_ret_codes err) | 110 | const char *drbd_set_st_err_str(enum drbd_state_rv err) |
109 | { | 111 | { |
110 | return err <= SS_AFTER_LAST_ERROR ? "TOO_SMALL" : | 112 | return err <= SS_AFTER_LAST_ERROR ? "TOO_SMALL" : |
111 | err > SS_TWO_PRIMARIES ? "TOO_LARGE" | 113 | err > SS_TWO_PRIMARIES ? "TOO_LARGE" |
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index e027446590d3..f7e6c92f8d03 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c | |||
@@ -39,18 +39,17 @@ | |||
39 | #include "drbd_req.h" | 39 | #include "drbd_req.h" |
40 | 40 | ||
41 | static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int cancel); | 41 | static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int cancel); |
42 | static int w_make_resync_request(struct drbd_conf *mdev, | ||
43 | struct drbd_work *w, int cancel); | ||
42 | 44 | ||
43 | 45 | ||
44 | 46 | ||
45 | /* defined here: | 47 | /* endio handlers: |
46 | drbd_md_io_complete | 48 | * drbd_md_io_complete (defined here) |
47 | drbd_endio_sec | 49 | * drbd_endio_pri (defined here) |
48 | drbd_endio_pri | 50 | * drbd_endio_sec (defined here) |
49 | 51 | * bm_async_io_complete (defined in drbd_bitmap.c) | |
50 | * more endio handlers: | 52 | * |
51 | atodb_endio in drbd_actlog.c | ||
52 | drbd_bm_async_io_complete in drbd_bitmap.c | ||
53 | |||
54 | * For all these callbacks, note the following: | 53 | * For all these callbacks, note the following: |
55 | * The callbacks will be called in irq context by the IDE drivers, | 54 | * The callbacks will be called in irq context by the IDE drivers, |
56 | * and in Softirqs/Tasklets/BH context by the SCSI drivers. | 55 | * and in Softirqs/Tasklets/BH context by the SCSI drivers. |
@@ -94,7 +93,7 @@ void drbd_endio_read_sec_final(struct drbd_epoch_entry *e) __releases(local) | |||
94 | if (list_empty(&mdev->read_ee)) | 93 | if (list_empty(&mdev->read_ee)) |
95 | wake_up(&mdev->ee_wait); | 94 | wake_up(&mdev->ee_wait); |
96 | if (test_bit(__EE_WAS_ERROR, &e->flags)) | 95 | if (test_bit(__EE_WAS_ERROR, &e->flags)) |
97 | __drbd_chk_io_error(mdev, FALSE); | 96 | __drbd_chk_io_error(mdev, false); |
98 | spin_unlock_irqrestore(&mdev->req_lock, flags); | 97 | spin_unlock_irqrestore(&mdev->req_lock, flags); |
99 | 98 | ||
100 | drbd_queue_work(&mdev->data.work, &e->w); | 99 | drbd_queue_work(&mdev->data.work, &e->w); |
@@ -137,7 +136,7 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo | |||
137 | : list_empty(&mdev->active_ee); | 136 | : list_empty(&mdev->active_ee); |
138 | 137 | ||
139 | if (test_bit(__EE_WAS_ERROR, &e->flags)) | 138 | if (test_bit(__EE_WAS_ERROR, &e->flags)) |
140 | __drbd_chk_io_error(mdev, FALSE); | 139 | __drbd_chk_io_error(mdev, false); |
141 | spin_unlock_irqrestore(&mdev->req_lock, flags); | 140 | spin_unlock_irqrestore(&mdev->req_lock, flags); |
142 | 141 | ||
143 | if (is_syncer_req) | 142 | if (is_syncer_req) |
@@ -163,14 +162,15 @@ void drbd_endio_sec(struct bio *bio, int error) | |||
163 | int uptodate = bio_flagged(bio, BIO_UPTODATE); | 162 | int uptodate = bio_flagged(bio, BIO_UPTODATE); |
164 | int is_write = bio_data_dir(bio) == WRITE; | 163 | int is_write = bio_data_dir(bio) == WRITE; |
165 | 164 | ||
166 | if (error) | 165 | if (error && __ratelimit(&drbd_ratelimit_state)) |
167 | dev_warn(DEV, "%s: error=%d s=%llus\n", | 166 | dev_warn(DEV, "%s: error=%d s=%llus\n", |
168 | is_write ? "write" : "read", error, | 167 | is_write ? "write" : "read", error, |
169 | (unsigned long long)e->sector); | 168 | (unsigned long long)e->sector); |
170 | if (!error && !uptodate) { | 169 | if (!error && !uptodate) { |
171 | dev_warn(DEV, "%s: setting error to -EIO s=%llus\n", | 170 | if (__ratelimit(&drbd_ratelimit_state)) |
172 | is_write ? "write" : "read", | 171 | dev_warn(DEV, "%s: setting error to -EIO s=%llus\n", |
173 | (unsigned long long)e->sector); | 172 | is_write ? "write" : "read", |
173 | (unsigned long long)e->sector); | ||
174 | /* strange behavior of some lower level drivers... | 174 | /* strange behavior of some lower level drivers... |
175 | * fail the request by clearing the uptodate flag, | 175 | * fail the request by clearing the uptodate flag, |
176 | * but do not return any error?! */ | 176 | * but do not return any error?! */ |
@@ -250,13 +250,6 @@ int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel) | |||
250 | return w_send_read_req(mdev, w, 0); | 250 | return w_send_read_req(mdev, w, 0); |
251 | } | 251 | } |
252 | 252 | ||
253 | int w_resync_inactive(struct drbd_conf *mdev, struct drbd_work *w, int cancel) | ||
254 | { | ||
255 | ERR_IF(cancel) return 1; | ||
256 | dev_err(DEV, "resync inactive, but callback triggered??\n"); | ||
257 | return 1; /* Simply ignore this! */ | ||
258 | } | ||
259 | |||
260 | void drbd_csum_ee(struct drbd_conf *mdev, struct crypto_hash *tfm, struct drbd_epoch_entry *e, void *digest) | 253 | void drbd_csum_ee(struct drbd_conf *mdev, struct crypto_hash *tfm, struct drbd_epoch_entry *e, void *digest) |
261 | { | 254 | { |
262 | struct hash_desc desc; | 255 | struct hash_desc desc; |
@@ -355,7 +348,7 @@ static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size) | |||
355 | if (!get_ldev(mdev)) | 348 | if (!get_ldev(mdev)) |
356 | return -EIO; | 349 | return -EIO; |
357 | 350 | ||
358 | if (drbd_rs_should_slow_down(mdev)) | 351 | if (drbd_rs_should_slow_down(mdev, sector)) |
359 | goto defer; | 352 | goto defer; |
360 | 353 | ||
361 | /* GFP_TRY, because if there is no memory available right now, this may | 354 | /* GFP_TRY, because if there is no memory available right now, this may |
@@ -373,9 +366,10 @@ static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size) | |||
373 | if (drbd_submit_ee(mdev, e, READ, DRBD_FAULT_RS_RD) == 0) | 366 | if (drbd_submit_ee(mdev, e, READ, DRBD_FAULT_RS_RD) == 0) |
374 | return 0; | 367 | return 0; |
375 | 368 | ||
376 | /* drbd_submit_ee currently fails for one reason only: | 369 | /* If it failed because of ENOMEM, retry should help. If it failed |
377 | * not being able to allocate enough bios. | 370 | * because bio_add_page failed (probably broken lower level driver), |
378 | * Is dropping the connection going to help? */ | 371 | * retry may or may not help. |
372 | * If it does not, you may need to force disconnect. */ | ||
379 | spin_lock_irq(&mdev->req_lock); | 373 | spin_lock_irq(&mdev->req_lock); |
380 | list_del(&e->w.list); | 374 | list_del(&e->w.list); |
381 | spin_unlock_irq(&mdev->req_lock); | 375 | spin_unlock_irq(&mdev->req_lock); |
@@ -386,26 +380,25 @@ defer: | |||
386 | return -EAGAIN; | 380 | return -EAGAIN; |
387 | } | 381 | } |
388 | 382 | ||
389 | void resync_timer_fn(unsigned long data) | 383 | int w_resync_timer(struct drbd_conf *mdev, struct drbd_work *w, int cancel) |
390 | { | 384 | { |
391 | struct drbd_conf *mdev = (struct drbd_conf *) data; | ||
392 | int queue; | ||
393 | |||
394 | queue = 1; | ||
395 | switch (mdev->state.conn) { | 385 | switch (mdev->state.conn) { |
396 | case C_VERIFY_S: | 386 | case C_VERIFY_S: |
397 | mdev->resync_work.cb = w_make_ov_request; | 387 | w_make_ov_request(mdev, w, cancel); |
398 | break; | 388 | break; |
399 | case C_SYNC_TARGET: | 389 | case C_SYNC_TARGET: |
400 | mdev->resync_work.cb = w_make_resync_request; | 390 | w_make_resync_request(mdev, w, cancel); |
401 | break; | 391 | break; |
402 | default: | ||
403 | queue = 0; | ||
404 | mdev->resync_work.cb = w_resync_inactive; | ||
405 | } | 392 | } |
406 | 393 | ||
407 | /* harmless race: list_empty outside data.work.q_lock */ | 394 | return 1; |
408 | if (list_empty(&mdev->resync_work.list) && queue) | 395 | } |
396 | |||
397 | void resync_timer_fn(unsigned long data) | ||
398 | { | ||
399 | struct drbd_conf *mdev = (struct drbd_conf *) data; | ||
400 | |||
401 | if (list_empty(&mdev->resync_work.list)) | ||
409 | drbd_queue_work(&mdev->data.work, &mdev->resync_work); | 402 | drbd_queue_work(&mdev->data.work, &mdev->resync_work); |
410 | } | 403 | } |
411 | 404 | ||
@@ -438,7 +431,7 @@ static void fifo_add_val(struct fifo_buffer *fb, int value) | |||
438 | fb->values[i] += value; | 431 | fb->values[i] += value; |
439 | } | 432 | } |
440 | 433 | ||
441 | int drbd_rs_controller(struct drbd_conf *mdev) | 434 | static int drbd_rs_controller(struct drbd_conf *mdev) |
442 | { | 435 | { |
443 | unsigned int sect_in; /* Number of sectors that came in since the last turn */ | 436 | unsigned int sect_in; /* Number of sectors that came in since the last turn */ |
444 | unsigned int want; /* The number of sectors we want in the proxy */ | 437 | unsigned int want; /* The number of sectors we want in the proxy */ |
@@ -492,29 +485,36 @@ int drbd_rs_controller(struct drbd_conf *mdev) | |||
492 | return req_sect; | 485 | return req_sect; |
493 | } | 486 | } |
494 | 487 | ||
495 | int w_make_resync_request(struct drbd_conf *mdev, | 488 | static int drbd_rs_number_requests(struct drbd_conf *mdev) |
496 | struct drbd_work *w, int cancel) | 489 | { |
490 | int number; | ||
491 | if (mdev->rs_plan_s.size) { /* mdev->sync_conf.c_plan_ahead */ | ||
492 | number = drbd_rs_controller(mdev) >> (BM_BLOCK_SHIFT - 9); | ||
493 | mdev->c_sync_rate = number * HZ * (BM_BLOCK_SIZE / 1024) / SLEEP_TIME; | ||
494 | } else { | ||
495 | mdev->c_sync_rate = mdev->sync_conf.rate; | ||
496 | number = SLEEP_TIME * mdev->c_sync_rate / ((BM_BLOCK_SIZE / 1024) * HZ); | ||
497 | } | ||
498 | |||
499 | /* ignore the amount of pending requests, the resync controller should | ||
500 | * throttle down to incoming reply rate soon enough anyways. */ | ||
501 | return number; | ||
502 | } | ||
503 | |||
504 | static int w_make_resync_request(struct drbd_conf *mdev, | ||
505 | struct drbd_work *w, int cancel) | ||
497 | { | 506 | { |
498 | unsigned long bit; | 507 | unsigned long bit; |
499 | sector_t sector; | 508 | sector_t sector; |
500 | const sector_t capacity = drbd_get_capacity(mdev->this_bdev); | 509 | const sector_t capacity = drbd_get_capacity(mdev->this_bdev); |
501 | int max_segment_size; | 510 | int max_bio_size; |
502 | int number, rollback_i, size, pe, mx; | 511 | int number, rollback_i, size; |
503 | int align, queued, sndbuf; | 512 | int align, queued, sndbuf; |
504 | int i = 0; | 513 | int i = 0; |
505 | 514 | ||
506 | if (unlikely(cancel)) | 515 | if (unlikely(cancel)) |
507 | return 1; | 516 | return 1; |
508 | 517 | ||
509 | if (unlikely(mdev->state.conn < C_CONNECTED)) { | ||
510 | dev_err(DEV, "Confused in w_make_resync_request()! cstate < Connected"); | ||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | if (mdev->state.conn != C_SYNC_TARGET) | ||
515 | dev_err(DEV, "%s in w_make_resync_request\n", | ||
516 | drbd_conn_str(mdev->state.conn)); | ||
517 | |||
518 | if (mdev->rs_total == 0) { | 518 | if (mdev->rs_total == 0) { |
519 | /* empty resync? */ | 519 | /* empty resync? */ |
520 | drbd_resync_finished(mdev); | 520 | drbd_resync_finished(mdev); |
@@ -527,49 +527,19 @@ int w_make_resync_request(struct drbd_conf *mdev, | |||
527 | to continue resync with a broken disk makes no sense at | 527 | to continue resync with a broken disk makes no sense at |
528 | all */ | 528 | all */ |
529 | dev_err(DEV, "Disk broke down during resync!\n"); | 529 | dev_err(DEV, "Disk broke down during resync!\n"); |
530 | mdev->resync_work.cb = w_resync_inactive; | ||
531 | return 1; | 530 | return 1; |
532 | } | 531 | } |
533 | 532 | ||
534 | /* starting with drbd 8.3.8, we can handle multi-bio EEs, | 533 | /* starting with drbd 8.3.8, we can handle multi-bio EEs, |
535 | * if it should be necessary */ | 534 | * if it should be necessary */ |
536 | max_segment_size = | 535 | max_bio_size = |
537 | mdev->agreed_pro_version < 94 ? queue_max_segment_size(mdev->rq_queue) : | 536 | mdev->agreed_pro_version < 94 ? queue_max_hw_sectors(mdev->rq_queue) << 9 : |
538 | mdev->agreed_pro_version < 95 ? DRBD_MAX_SIZE_H80_PACKET : DRBD_MAX_SEGMENT_SIZE; | 537 | mdev->agreed_pro_version < 95 ? DRBD_MAX_SIZE_H80_PACKET : DRBD_MAX_BIO_SIZE; |
539 | 538 | ||
540 | if (mdev->rs_plan_s.size) { /* mdev->sync_conf.c_plan_ahead */ | 539 | number = drbd_rs_number_requests(mdev); |
541 | number = drbd_rs_controller(mdev) >> (BM_BLOCK_SHIFT - 9); | 540 | if (number == 0) |
542 | mdev->c_sync_rate = number * HZ * (BM_BLOCK_SIZE / 1024) / SLEEP_TIME; | ||
543 | } else { | ||
544 | mdev->c_sync_rate = mdev->sync_conf.rate; | ||
545 | number = SLEEP_TIME * mdev->c_sync_rate / ((BM_BLOCK_SIZE / 1024) * HZ); | ||
546 | } | ||
547 | |||
548 | /* Throttle resync on lower level disk activity, which may also be | ||
549 | * caused by application IO on Primary/SyncTarget. | ||
550 | * Keep this after the call to drbd_rs_controller, as that assumes | ||
551 | * to be called as precisely as possible every SLEEP_TIME, | ||
552 | * and would be confused otherwise. */ | ||
553 | if (drbd_rs_should_slow_down(mdev)) | ||
554 | goto requeue; | 541 | goto requeue; |
555 | 542 | ||
556 | mutex_lock(&mdev->data.mutex); | ||
557 | if (mdev->data.socket) | ||
558 | mx = mdev->data.socket->sk->sk_rcvbuf / sizeof(struct p_block_req); | ||
559 | else | ||
560 | mx = 1; | ||
561 | mutex_unlock(&mdev->data.mutex); | ||
562 | |||
563 | /* For resync rates >160MB/sec, allow more pending RS requests */ | ||
564 | if (number > mx) | ||
565 | mx = number; | ||
566 | |||
567 | /* Limit the number of pending RS requests to no more than the peer's receive buffer */ | ||
568 | pe = atomic_read(&mdev->rs_pending_cnt); | ||
569 | if ((pe + number) > mx) { | ||
570 | number = mx - pe; | ||
571 | } | ||
572 | |||
573 | for (i = 0; i < number; i++) { | 543 | for (i = 0; i < number; i++) { |
574 | /* Stop generating RS requests, when half of the send buffer is filled */ | 544 | /* Stop generating RS requests, when half of the send buffer is filled */ |
575 | mutex_lock(&mdev->data.mutex); | 545 | mutex_lock(&mdev->data.mutex); |
@@ -588,16 +558,16 @@ next_sector: | |||
588 | size = BM_BLOCK_SIZE; | 558 | size = BM_BLOCK_SIZE; |
589 | bit = drbd_bm_find_next(mdev, mdev->bm_resync_fo); | 559 | bit = drbd_bm_find_next(mdev, mdev->bm_resync_fo); |
590 | 560 | ||
591 | if (bit == -1UL) { | 561 | if (bit == DRBD_END_OF_BITMAP) { |
592 | mdev->bm_resync_fo = drbd_bm_bits(mdev); | 562 | mdev->bm_resync_fo = drbd_bm_bits(mdev); |
593 | mdev->resync_work.cb = w_resync_inactive; | ||
594 | put_ldev(mdev); | 563 | put_ldev(mdev); |
595 | return 1; | 564 | return 1; |
596 | } | 565 | } |
597 | 566 | ||
598 | sector = BM_BIT_TO_SECT(bit); | 567 | sector = BM_BIT_TO_SECT(bit); |
599 | 568 | ||
600 | if (drbd_try_rs_begin_io(mdev, sector)) { | 569 | if (drbd_rs_should_slow_down(mdev, sector) || |
570 | drbd_try_rs_begin_io(mdev, sector)) { | ||
601 | mdev->bm_resync_fo = bit; | 571 | mdev->bm_resync_fo = bit; |
602 | goto requeue; | 572 | goto requeue; |
603 | } | 573 | } |
@@ -608,7 +578,7 @@ next_sector: | |||
608 | goto next_sector; | 578 | goto next_sector; |
609 | } | 579 | } |
610 | 580 | ||
611 | #if DRBD_MAX_SEGMENT_SIZE > BM_BLOCK_SIZE | 581 | #if DRBD_MAX_BIO_SIZE > BM_BLOCK_SIZE |
612 | /* try to find some adjacent bits. | 582 | /* try to find some adjacent bits. |
613 | * we stop if we have already the maximum req size. | 583 | * we stop if we have already the maximum req size. |
614 | * | 584 | * |
@@ -618,7 +588,7 @@ next_sector: | |||
618 | align = 1; | 588 | align = 1; |
619 | rollback_i = i; | 589 | rollback_i = i; |
620 | for (;;) { | 590 | for (;;) { |
621 | if (size + BM_BLOCK_SIZE > max_segment_size) | 591 | if (size + BM_BLOCK_SIZE > max_bio_size) |
622 | break; | 592 | break; |
623 | 593 | ||
624 | /* Be always aligned */ | 594 | /* Be always aligned */ |
@@ -685,7 +655,6 @@ next_sector: | |||
685 | * resync data block, and the last bit is cleared. | 655 | * resync data block, and the last bit is cleared. |
686 | * until then resync "work" is "inactive" ... | 656 | * until then resync "work" is "inactive" ... |
687 | */ | 657 | */ |
688 | mdev->resync_work.cb = w_resync_inactive; | ||
689 | put_ldev(mdev); | 658 | put_ldev(mdev); |
690 | return 1; | 659 | return 1; |
691 | } | 660 | } |
@@ -706,27 +675,18 @@ static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int ca | |||
706 | if (unlikely(cancel)) | 675 | if (unlikely(cancel)) |
707 | return 1; | 676 | return 1; |
708 | 677 | ||
709 | if (unlikely(mdev->state.conn < C_CONNECTED)) { | 678 | number = drbd_rs_number_requests(mdev); |
710 | dev_err(DEV, "Confused in w_make_ov_request()! cstate < Connected"); | ||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | number = SLEEP_TIME*mdev->sync_conf.rate / ((BM_BLOCK_SIZE/1024)*HZ); | ||
715 | if (atomic_read(&mdev->rs_pending_cnt) > number) | ||
716 | goto requeue; | ||
717 | |||
718 | number -= atomic_read(&mdev->rs_pending_cnt); | ||
719 | 679 | ||
720 | sector = mdev->ov_position; | 680 | sector = mdev->ov_position; |
721 | for (i = 0; i < number; i++) { | 681 | for (i = 0; i < number; i++) { |
722 | if (sector >= capacity) { | 682 | if (sector >= capacity) { |
723 | mdev->resync_work.cb = w_resync_inactive; | ||
724 | return 1; | 683 | return 1; |
725 | } | 684 | } |
726 | 685 | ||
727 | size = BM_BLOCK_SIZE; | 686 | size = BM_BLOCK_SIZE; |
728 | 687 | ||
729 | if (drbd_try_rs_begin_io(mdev, sector)) { | 688 | if (drbd_rs_should_slow_down(mdev, sector) || |
689 | drbd_try_rs_begin_io(mdev, sector)) { | ||
730 | mdev->ov_position = sector; | 690 | mdev->ov_position = sector; |
731 | goto requeue; | 691 | goto requeue; |
732 | } | 692 | } |
@@ -744,11 +704,33 @@ static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int ca | |||
744 | mdev->ov_position = sector; | 704 | mdev->ov_position = sector; |
745 | 705 | ||
746 | requeue: | 706 | requeue: |
707 | mdev->rs_in_flight += (i << (BM_BLOCK_SHIFT - 9)); | ||
747 | mod_timer(&mdev->resync_timer, jiffies + SLEEP_TIME); | 708 | mod_timer(&mdev->resync_timer, jiffies + SLEEP_TIME); |
748 | return 1; | 709 | return 1; |
749 | } | 710 | } |
750 | 711 | ||
751 | 712 | ||
713 | void start_resync_timer_fn(unsigned long data) | ||
714 | { | ||
715 | struct drbd_conf *mdev = (struct drbd_conf *) data; | ||
716 | |||
717 | drbd_queue_work(&mdev->data.work, &mdev->start_resync_work); | ||
718 | } | ||
719 | |||
720 | int w_start_resync(struct drbd_conf *mdev, struct drbd_work *w, int cancel) | ||
721 | { | ||
722 | if (atomic_read(&mdev->unacked_cnt) || atomic_read(&mdev->rs_pending_cnt)) { | ||
723 | dev_warn(DEV, "w_start_resync later...\n"); | ||
724 | mdev->start_resync_timer.expires = jiffies + HZ/10; | ||
725 | add_timer(&mdev->start_resync_timer); | ||
726 | return 1; | ||
727 | } | ||
728 | |||
729 | drbd_start_resync(mdev, C_SYNC_SOURCE); | ||
730 | clear_bit(AHEAD_TO_SYNC_SOURCE, &mdev->current_epoch->flags); | ||
731 | return 1; | ||
732 | } | ||
733 | |||
752 | int w_ov_finished(struct drbd_conf *mdev, struct drbd_work *w, int cancel) | 734 | int w_ov_finished(struct drbd_conf *mdev, struct drbd_work *w, int cancel) |
753 | { | 735 | { |
754 | kfree(w); | 736 | kfree(w); |
@@ -782,6 +764,7 @@ int drbd_resync_finished(struct drbd_conf *mdev) | |||
782 | union drbd_state os, ns; | 764 | union drbd_state os, ns; |
783 | struct drbd_work *w; | 765 | struct drbd_work *w; |
784 | char *khelper_cmd = NULL; | 766 | char *khelper_cmd = NULL; |
767 | int verify_done = 0; | ||
785 | 768 | ||
786 | /* Remove all elements from the resync LRU. Since future actions | 769 | /* Remove all elements from the resync LRU. Since future actions |
787 | * might set bits in the (main) bitmap, then the entries in the | 770 | * might set bits in the (main) bitmap, then the entries in the |
@@ -792,8 +775,7 @@ int drbd_resync_finished(struct drbd_conf *mdev) | |||
792 | * queue (or even the read operations for those packets | 775 | * queue (or even the read operations for those packets |
793 | * is not finished by now). Retry in 100ms. */ | 776 | * is not finished by now). Retry in 100ms. */ |
794 | 777 | ||
795 | __set_current_state(TASK_INTERRUPTIBLE); | 778 | schedule_timeout_interruptible(HZ / 10); |
796 | schedule_timeout(HZ / 10); | ||
797 | w = kmalloc(sizeof(struct drbd_work), GFP_ATOMIC); | 779 | w = kmalloc(sizeof(struct drbd_work), GFP_ATOMIC); |
798 | if (w) { | 780 | if (w) { |
799 | w->cb = w_resync_finished; | 781 | w->cb = w_resync_finished; |
@@ -818,6 +800,8 @@ int drbd_resync_finished(struct drbd_conf *mdev) | |||
818 | spin_lock_irq(&mdev->req_lock); | 800 | spin_lock_irq(&mdev->req_lock); |
819 | os = mdev->state; | 801 | os = mdev->state; |
820 | 802 | ||
803 | verify_done = (os.conn == C_VERIFY_S || os.conn == C_VERIFY_T); | ||
804 | |||
821 | /* This protects us against multiple calls (that can happen in the presence | 805 | /* This protects us against multiple calls (that can happen in the presence |
822 | of application IO), and against connectivity loss just before we arrive here. */ | 806 | of application IO), and against connectivity loss just before we arrive here. */ |
823 | if (os.conn <= C_CONNECTED) | 807 | if (os.conn <= C_CONNECTED) |
@@ -827,8 +811,7 @@ int drbd_resync_finished(struct drbd_conf *mdev) | |||
827 | ns.conn = C_CONNECTED; | 811 | ns.conn = C_CONNECTED; |
828 | 812 | ||
829 | dev_info(DEV, "%s done (total %lu sec; paused %lu sec; %lu K/sec)\n", | 813 | dev_info(DEV, "%s done (total %lu sec; paused %lu sec; %lu K/sec)\n", |
830 | (os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) ? | 814 | verify_done ? "Online verify " : "Resync", |
831 | "Online verify " : "Resync", | ||
832 | dt + mdev->rs_paused, mdev->rs_paused, dbdt); | 815 | dt + mdev->rs_paused, mdev->rs_paused, dbdt); |
833 | 816 | ||
834 | n_oos = drbd_bm_total_weight(mdev); | 817 | n_oos = drbd_bm_total_weight(mdev); |
@@ -886,14 +869,18 @@ int drbd_resync_finished(struct drbd_conf *mdev) | |||
886 | } | 869 | } |
887 | } | 870 | } |
888 | 871 | ||
889 | drbd_uuid_set_bm(mdev, 0UL); | 872 | if (!(os.conn == C_VERIFY_S || os.conn == C_VERIFY_T)) { |
890 | 873 | /* for verify runs, we don't update uuids here, | |
891 | if (mdev->p_uuid) { | 874 | * so there would be nothing to report. */ |
892 | /* Now the two UUID sets are equal, update what we | 875 | drbd_uuid_set_bm(mdev, 0UL); |
893 | * know of the peer. */ | 876 | drbd_print_uuids(mdev, "updated UUIDs"); |
894 | int i; | 877 | if (mdev->p_uuid) { |
895 | for (i = UI_CURRENT ; i <= UI_HISTORY_END ; i++) | 878 | /* Now the two UUID sets are equal, update what we |
896 | mdev->p_uuid[i] = mdev->ldev->md.uuid[i]; | 879 | * know of the peer. */ |
880 | int i; | ||
881 | for (i = UI_CURRENT ; i <= UI_HISTORY_END ; i++) | ||
882 | mdev->p_uuid[i] = mdev->ldev->md.uuid[i]; | ||
883 | } | ||
897 | } | 884 | } |
898 | } | 885 | } |
899 | 886 | ||
@@ -905,15 +892,11 @@ out: | |||
905 | mdev->rs_total = 0; | 892 | mdev->rs_total = 0; |
906 | mdev->rs_failed = 0; | 893 | mdev->rs_failed = 0; |
907 | mdev->rs_paused = 0; | 894 | mdev->rs_paused = 0; |
908 | mdev->ov_start_sector = 0; | 895 | if (verify_done) |
896 | mdev->ov_start_sector = 0; | ||
909 | 897 | ||
910 | drbd_md_sync(mdev); | 898 | drbd_md_sync(mdev); |
911 | 899 | ||
912 | if (test_and_clear_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags)) { | ||
913 | dev_info(DEV, "Writing the whole bitmap\n"); | ||
914 | drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, "write from resync_finished"); | ||
915 | } | ||
916 | |||
917 | if (khelper_cmd) | 900 | if (khelper_cmd) |
918 | drbd_khelper(mdev, khelper_cmd); | 901 | drbd_khelper(mdev, khelper_cmd); |
919 | 902 | ||
@@ -994,7 +977,9 @@ int w_e_end_rsdata_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) | |||
994 | put_ldev(mdev); | 977 | put_ldev(mdev); |
995 | } | 978 | } |
996 | 979 | ||
997 | if (likely((e->flags & EE_WAS_ERROR) == 0)) { | 980 | if (mdev->state.conn == C_AHEAD) { |
981 | ok = drbd_send_ack(mdev, P_RS_CANCEL, e); | ||
982 | } else if (likely((e->flags & EE_WAS_ERROR) == 0)) { | ||
998 | if (likely(mdev->state.pdsk >= D_INCONSISTENT)) { | 983 | if (likely(mdev->state.pdsk >= D_INCONSISTENT)) { |
999 | inc_rs_pending(mdev); | 984 | inc_rs_pending(mdev); |
1000 | ok = drbd_send_block(mdev, P_RS_DATA_REPLY, e); | 985 | ok = drbd_send_block(mdev, P_RS_DATA_REPLY, e); |
@@ -1096,25 +1081,27 @@ int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) | |||
1096 | if (unlikely(cancel)) | 1081 | if (unlikely(cancel)) |
1097 | goto out; | 1082 | goto out; |
1098 | 1083 | ||
1099 | if (unlikely((e->flags & EE_WAS_ERROR) != 0)) | ||
1100 | goto out; | ||
1101 | |||
1102 | digest_size = crypto_hash_digestsize(mdev->verify_tfm); | 1084 | digest_size = crypto_hash_digestsize(mdev->verify_tfm); |
1103 | /* FIXME if this allocation fails, online verify will not terminate! */ | ||
1104 | digest = kmalloc(digest_size, GFP_NOIO); | 1085 | digest = kmalloc(digest_size, GFP_NOIO); |
1105 | if (digest) { | 1086 | if (!digest) { |
1106 | drbd_csum_ee(mdev, mdev->verify_tfm, e, digest); | 1087 | ok = 0; /* terminate the connection in case the allocation failed */ |
1107 | inc_rs_pending(mdev); | 1088 | goto out; |
1108 | ok = drbd_send_drequest_csum(mdev, e->sector, e->size, | ||
1109 | digest, digest_size, P_OV_REPLY); | ||
1110 | if (!ok) | ||
1111 | dec_rs_pending(mdev); | ||
1112 | kfree(digest); | ||
1113 | } | 1089 | } |
1114 | 1090 | ||
1091 | if (likely(!(e->flags & EE_WAS_ERROR))) | ||
1092 | drbd_csum_ee(mdev, mdev->verify_tfm, e, digest); | ||
1093 | else | ||
1094 | memset(digest, 0, digest_size); | ||
1095 | |||
1096 | inc_rs_pending(mdev); | ||
1097 | ok = drbd_send_drequest_csum(mdev, e->sector, e->size, | ||
1098 | digest, digest_size, P_OV_REPLY); | ||
1099 | if (!ok) | ||
1100 | dec_rs_pending(mdev); | ||
1101 | kfree(digest); | ||
1102 | |||
1115 | out: | 1103 | out: |
1116 | drbd_free_ee(mdev, e); | 1104 | drbd_free_ee(mdev, e); |
1117 | |||
1118 | dec_unacked(mdev); | 1105 | dec_unacked(mdev); |
1119 | 1106 | ||
1120 | return ok; | 1107 | return ok; |
@@ -1129,7 +1116,6 @@ void drbd_ov_oos_found(struct drbd_conf *mdev, sector_t sector, int size) | |||
1129 | mdev->ov_last_oos_size = size>>9; | 1116 | mdev->ov_last_oos_size = size>>9; |
1130 | } | 1117 | } |
1131 | drbd_set_out_of_sync(mdev, sector, size); | 1118 | drbd_set_out_of_sync(mdev, sector, size); |
1132 | set_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags); | ||
1133 | } | 1119 | } |
1134 | 1120 | ||
1135 | int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) | 1121 | int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) |
@@ -1165,10 +1151,6 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) | |||
1165 | eq = !memcmp(digest, di->digest, digest_size); | 1151 | eq = !memcmp(digest, di->digest, digest_size); |
1166 | kfree(digest); | 1152 | kfree(digest); |
1167 | } | 1153 | } |
1168 | } else { | ||
1169 | ok = drbd_send_ack(mdev, P_NEG_RS_DREPLY, e); | ||
1170 | if (__ratelimit(&drbd_ratelimit_state)) | ||
1171 | dev_err(DEV, "Sending NegDReply. I guess it gets messy.\n"); | ||
1172 | } | 1154 | } |
1173 | 1155 | ||
1174 | dec_unacked(mdev); | 1156 | dec_unacked(mdev); |
@@ -1182,7 +1164,13 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) | |||
1182 | 1164 | ||
1183 | drbd_free_ee(mdev, e); | 1165 | drbd_free_ee(mdev, e); |
1184 | 1166 | ||
1185 | if (--mdev->ov_left == 0) { | 1167 | --mdev->ov_left; |
1168 | |||
1169 | /* let's advance progress step marks only for every other megabyte */ | ||
1170 | if ((mdev->ov_left & 0x200) == 0x200) | ||
1171 | drbd_advance_rs_marks(mdev, mdev->ov_left); | ||
1172 | |||
1173 | if (mdev->ov_left == 0) { | ||
1186 | ov_oos_print(mdev); | 1174 | ov_oos_print(mdev); |
1187 | drbd_resync_finished(mdev); | 1175 | drbd_resync_finished(mdev); |
1188 | } | 1176 | } |
@@ -1235,6 +1223,22 @@ int w_send_write_hint(struct drbd_conf *mdev, struct drbd_work *w, int cancel) | |||
1235 | return drbd_send_short_cmd(mdev, P_UNPLUG_REMOTE); | 1223 | return drbd_send_short_cmd(mdev, P_UNPLUG_REMOTE); |
1236 | } | 1224 | } |
1237 | 1225 | ||
1226 | int w_send_oos(struct drbd_conf *mdev, struct drbd_work *w, int cancel) | ||
1227 | { | ||
1228 | struct drbd_request *req = container_of(w, struct drbd_request, w); | ||
1229 | int ok; | ||
1230 | |||
1231 | if (unlikely(cancel)) { | ||
1232 | req_mod(req, send_canceled); | ||
1233 | return 1; | ||
1234 | } | ||
1235 | |||
1236 | ok = drbd_send_oos(mdev, req); | ||
1237 | req_mod(req, oos_handed_to_network); | ||
1238 | |||
1239 | return ok; | ||
1240 | } | ||
1241 | |||
1238 | /** | 1242 | /** |
1239 | * w_send_dblock() - Worker callback to send a P_DATA packet in order to mirror a write request | 1243 | * w_send_dblock() - Worker callback to send a P_DATA packet in order to mirror a write request |
1240 | * @mdev: DRBD device. | 1244 | * @mdev: DRBD device. |
@@ -1430,6 +1434,17 @@ int drbd_alter_sa(struct drbd_conf *mdev, int na) | |||
1430 | return retcode; | 1434 | return retcode; |
1431 | } | 1435 | } |
1432 | 1436 | ||
1437 | void drbd_rs_controller_reset(struct drbd_conf *mdev) | ||
1438 | { | ||
1439 | atomic_set(&mdev->rs_sect_in, 0); | ||
1440 | atomic_set(&mdev->rs_sect_ev, 0); | ||
1441 | mdev->rs_in_flight = 0; | ||
1442 | mdev->rs_planed = 0; | ||
1443 | spin_lock(&mdev->peer_seq_lock); | ||
1444 | fifo_set(&mdev->rs_plan_s, 0); | ||
1445 | spin_unlock(&mdev->peer_seq_lock); | ||
1446 | } | ||
1447 | |||
1433 | /** | 1448 | /** |
1434 | * drbd_start_resync() - Start the resync process | 1449 | * drbd_start_resync() - Start the resync process |
1435 | * @mdev: DRBD device. | 1450 | * @mdev: DRBD device. |
@@ -1443,13 +1458,18 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) | |||
1443 | union drbd_state ns; | 1458 | union drbd_state ns; |
1444 | int r; | 1459 | int r; |
1445 | 1460 | ||
1446 | if (mdev->state.conn >= C_SYNC_SOURCE) { | 1461 | if (mdev->state.conn >= C_SYNC_SOURCE && mdev->state.conn < C_AHEAD) { |
1447 | dev_err(DEV, "Resync already running!\n"); | 1462 | dev_err(DEV, "Resync already running!\n"); |
1448 | return; | 1463 | return; |
1449 | } | 1464 | } |
1450 | 1465 | ||
1451 | /* In case a previous resync run was aborted by an IO error/detach on the peer. */ | 1466 | if (mdev->state.conn < C_AHEAD) { |
1452 | drbd_rs_cancel_all(mdev); | 1467 | /* In case a previous resync run was aborted by an IO error/detach on the peer. */ |
1468 | drbd_rs_cancel_all(mdev); | ||
1469 | /* This should be done when we abort the resync. We definitely do not | ||
1470 | want to have this for connections going back and forth between | ||
1471 | Ahead/Behind and SyncSource/SyncTarget */ | ||
1472 | } | ||
1453 | 1473 | ||
1454 | if (side == C_SYNC_TARGET) { | 1474 | if (side == C_SYNC_TARGET) { |
1455 | /* Since application IO was locked out during C_WF_BITMAP_T and | 1475 | /* Since application IO was locked out during C_WF_BITMAP_T and |
@@ -1463,6 +1483,20 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) | |||
1463 | drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); | 1483 | drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); |
1464 | return; | 1484 | return; |
1465 | } | 1485 | } |
1486 | } else /* C_SYNC_SOURCE */ { | ||
1487 | r = drbd_khelper(mdev, "before-resync-source"); | ||
1488 | r = (r >> 8) & 0xff; | ||
1489 | if (r > 0) { | ||
1490 | if (r == 3) { | ||
1491 | dev_info(DEV, "before-resync-source handler returned %d, " | ||
1492 | "ignoring. Old userland tools?", r); | ||
1493 | } else { | ||
1494 | dev_info(DEV, "before-resync-source handler returned %d, " | ||
1495 | "dropping connection.\n", r); | ||
1496 | drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); | ||
1497 | return; | ||
1498 | } | ||
1499 | } | ||
1466 | } | 1500 | } |
1467 | 1501 | ||
1468 | drbd_state_lock(mdev); | 1502 | drbd_state_lock(mdev); |
@@ -1472,18 +1506,6 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) | |||
1472 | return; | 1506 | return; |
1473 | } | 1507 | } |
1474 | 1508 | ||
1475 | if (side == C_SYNC_TARGET) { | ||
1476 | mdev->bm_resync_fo = 0; | ||
1477 | } else /* side == C_SYNC_SOURCE */ { | ||
1478 | u64 uuid; | ||
1479 | |||
1480 | get_random_bytes(&uuid, sizeof(u64)); | ||
1481 | drbd_uuid_set(mdev, UI_BITMAP, uuid); | ||
1482 | drbd_send_sync_uuid(mdev, uuid); | ||
1483 | |||
1484 | D_ASSERT(mdev->state.disk == D_UP_TO_DATE); | ||
1485 | } | ||
1486 | |||
1487 | write_lock_irq(&global_state_lock); | 1509 | write_lock_irq(&global_state_lock); |
1488 | ns = mdev->state; | 1510 | ns = mdev->state; |
1489 | 1511 | ||
@@ -1521,13 +1543,24 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) | |||
1521 | _drbd_pause_after(mdev); | 1543 | _drbd_pause_after(mdev); |
1522 | } | 1544 | } |
1523 | write_unlock_irq(&global_state_lock); | 1545 | write_unlock_irq(&global_state_lock); |
1524 | put_ldev(mdev); | ||
1525 | 1546 | ||
1526 | if (r == SS_SUCCESS) { | 1547 | if (r == SS_SUCCESS) { |
1527 | dev_info(DEV, "Began resync as %s (will sync %lu KB [%lu bits set]).\n", | 1548 | dev_info(DEV, "Began resync as %s (will sync %lu KB [%lu bits set]).\n", |
1528 | drbd_conn_str(ns.conn), | 1549 | drbd_conn_str(ns.conn), |
1529 | (unsigned long) mdev->rs_total << (BM_BLOCK_SHIFT-10), | 1550 | (unsigned long) mdev->rs_total << (BM_BLOCK_SHIFT-10), |
1530 | (unsigned long) mdev->rs_total); | 1551 | (unsigned long) mdev->rs_total); |
1552 | if (side == C_SYNC_TARGET) | ||
1553 | mdev->bm_resync_fo = 0; | ||
1554 | |||
1555 | /* Since protocol 96, we must serialize drbd_gen_and_send_sync_uuid | ||
1556 | * with w_send_oos, or the sync target will get confused as to | ||
1557 | * how much bits to resync. We cannot do that always, because for an | ||
1558 | * empty resync and protocol < 95, we need to do it here, as we call | ||
1559 | * drbd_resync_finished from here in that case. | ||
1560 | * We drbd_gen_and_send_sync_uuid here for protocol < 96, | ||
1561 | * and from after_state_ch otherwise. */ | ||
1562 | if (side == C_SYNC_SOURCE && mdev->agreed_pro_version < 96) | ||
1563 | drbd_gen_and_send_sync_uuid(mdev); | ||
1531 | 1564 | ||
1532 | if (mdev->agreed_pro_version < 95 && mdev->rs_total == 0) { | 1565 | if (mdev->agreed_pro_version < 95 && mdev->rs_total == 0) { |
1533 | /* This still has a race (about when exactly the peers | 1566 | /* This still has a race (about when exactly the peers |
@@ -1547,13 +1580,7 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) | |||
1547 | drbd_resync_finished(mdev); | 1580 | drbd_resync_finished(mdev); |
1548 | } | 1581 | } |
1549 | 1582 | ||
1550 | atomic_set(&mdev->rs_sect_in, 0); | 1583 | drbd_rs_controller_reset(mdev); |
1551 | atomic_set(&mdev->rs_sect_ev, 0); | ||
1552 | mdev->rs_in_flight = 0; | ||
1553 | mdev->rs_planed = 0; | ||
1554 | spin_lock(&mdev->peer_seq_lock); | ||
1555 | fifo_set(&mdev->rs_plan_s, 0); | ||
1556 | spin_unlock(&mdev->peer_seq_lock); | ||
1557 | /* ns.conn may already be != mdev->state.conn, | 1584 | /* ns.conn may already be != mdev->state.conn, |
1558 | * we may have been paused in between, or become paused until | 1585 | * we may have been paused in between, or become paused until |
1559 | * the timer triggers. | 1586 | * the timer triggers. |
@@ -1563,6 +1590,7 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) | |||
1563 | 1590 | ||
1564 | drbd_md_sync(mdev); | 1591 | drbd_md_sync(mdev); |
1565 | } | 1592 | } |
1593 | put_ldev(mdev); | ||
1566 | drbd_state_unlock(mdev); | 1594 | drbd_state_unlock(mdev); |
1567 | } | 1595 | } |
1568 | 1596 | ||
diff --git a/drivers/block/drbd/drbd_wrappers.h b/drivers/block/drbd/drbd_wrappers.h index 53586fa5ae1b..151f1a37478f 100644 --- a/drivers/block/drbd/drbd_wrappers.h +++ b/drivers/block/drbd/drbd_wrappers.h | |||
@@ -39,7 +39,7 @@ static inline void drbd_generic_make_request(struct drbd_conf *mdev, | |||
39 | return; | 39 | return; |
40 | } | 40 | } |
41 | 41 | ||
42 | if (FAULT_ACTIVE(mdev, fault_type)) | 42 | if (drbd_insert_fault(mdev, fault_type)) |
43 | bio_endio(bio, -EIO); | 43 | bio_endio(bio, -EIO); |
44 | else | 44 | else |
45 | generic_make_request(bio); | 45 | generic_make_request(bio); |
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 0f17ad8585d7..b03771d4787c 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/cpu.h> | 28 | #include <linux/cpu.h> |
29 | #include <linux/completion.h> | 29 | #include <linux/completion.h> |
30 | #include <linux/mutex.h> | 30 | #include <linux/mutex.h> |
31 | #include <linux/syscore_ops.h> | ||
31 | 32 | ||
32 | #include <trace/events/power.h> | 33 | #include <trace/events/power.h> |
33 | 34 | ||
@@ -1340,35 +1341,31 @@ out: | |||
1340 | } | 1341 | } |
1341 | EXPORT_SYMBOL(cpufreq_get); | 1342 | EXPORT_SYMBOL(cpufreq_get); |
1342 | 1343 | ||
1344 | static struct sysdev_driver cpufreq_sysdev_driver = { | ||
1345 | .add = cpufreq_add_dev, | ||
1346 | .remove = cpufreq_remove_dev, | ||
1347 | }; | ||
1348 | |||
1343 | 1349 | ||
1344 | /** | 1350 | /** |
1345 | * cpufreq_suspend - let the low level driver prepare for suspend | 1351 | * cpufreq_bp_suspend - Prepare the boot CPU for system suspend. |
1352 | * | ||
1353 | * This function is only executed for the boot processor. The other CPUs | ||
1354 | * have been put offline by means of CPU hotplug. | ||
1346 | */ | 1355 | */ |
1347 | 1356 | static int cpufreq_bp_suspend(void) | |
1348 | static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg) | ||
1349 | { | 1357 | { |
1350 | int ret = 0; | 1358 | int ret = 0; |
1351 | 1359 | ||
1352 | int cpu = sysdev->id; | 1360 | int cpu = smp_processor_id(); |
1353 | struct cpufreq_policy *cpu_policy; | 1361 | struct cpufreq_policy *cpu_policy; |
1354 | 1362 | ||
1355 | dprintk("suspending cpu %u\n", cpu); | 1363 | dprintk("suspending cpu %u\n", cpu); |
1356 | 1364 | ||
1357 | if (!cpu_online(cpu)) | 1365 | /* If there's no policy for the boot CPU, we have nothing to do. */ |
1358 | return 0; | ||
1359 | |||
1360 | /* we may be lax here as interrupts are off. Nonetheless | ||
1361 | * we need to grab the correct cpu policy, as to check | ||
1362 | * whether we really run on this CPU. | ||
1363 | */ | ||
1364 | |||
1365 | cpu_policy = cpufreq_cpu_get(cpu); | 1366 | cpu_policy = cpufreq_cpu_get(cpu); |
1366 | if (!cpu_policy) | 1367 | if (!cpu_policy) |
1367 | return -EINVAL; | 1368 | return 0; |
1368 | |||
1369 | /* only handle each CPU group once */ | ||
1370 | if (unlikely(cpu_policy->cpu != cpu)) | ||
1371 | goto out; | ||
1372 | 1369 | ||
1373 | if (cpufreq_driver->suspend) { | 1370 | if (cpufreq_driver->suspend) { |
1374 | ret = cpufreq_driver->suspend(cpu_policy); | 1371 | ret = cpufreq_driver->suspend(cpu_policy); |
@@ -1377,13 +1374,12 @@ static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg) | |||
1377 | "step on CPU %u\n", cpu_policy->cpu); | 1374 | "step on CPU %u\n", cpu_policy->cpu); |
1378 | } | 1375 | } |
1379 | 1376 | ||
1380 | out: | ||
1381 | cpufreq_cpu_put(cpu_policy); | 1377 | cpufreq_cpu_put(cpu_policy); |
1382 | return ret; | 1378 | return ret; |
1383 | } | 1379 | } |
1384 | 1380 | ||
1385 | /** | 1381 | /** |
1386 | * cpufreq_resume - restore proper CPU frequency handling after resume | 1382 | * cpufreq_bp_resume - Restore proper frequency handling of the boot CPU. |
1387 | * | 1383 | * |
1388 | * 1.) resume CPUfreq hardware support (cpufreq_driver->resume()) | 1384 | * 1.) resume CPUfreq hardware support (cpufreq_driver->resume()) |
1389 | * 2.) schedule call cpufreq_update_policy() ASAP as interrupts are | 1385 | * 2.) schedule call cpufreq_update_policy() ASAP as interrupts are |
@@ -1391,31 +1387,23 @@ out: | |||
1391 | * what we believe it to be. This is a bit later than when it | 1387 | * what we believe it to be. This is a bit later than when it |
1392 | * should be, but nonethteless it's better than calling | 1388 | * should be, but nonethteless it's better than calling |
1393 | * cpufreq_driver->get() here which might re-enable interrupts... | 1389 | * cpufreq_driver->get() here which might re-enable interrupts... |
1390 | * | ||
1391 | * This function is only executed for the boot CPU. The other CPUs have not | ||
1392 | * been turned on yet. | ||
1394 | */ | 1393 | */ |
1395 | static int cpufreq_resume(struct sys_device *sysdev) | 1394 | static void cpufreq_bp_resume(void) |
1396 | { | 1395 | { |
1397 | int ret = 0; | 1396 | int ret = 0; |
1398 | 1397 | ||
1399 | int cpu = sysdev->id; | 1398 | int cpu = smp_processor_id(); |
1400 | struct cpufreq_policy *cpu_policy; | 1399 | struct cpufreq_policy *cpu_policy; |
1401 | 1400 | ||
1402 | dprintk("resuming cpu %u\n", cpu); | 1401 | dprintk("resuming cpu %u\n", cpu); |
1403 | 1402 | ||
1404 | if (!cpu_online(cpu)) | 1403 | /* If there's no policy for the boot CPU, we have nothing to do. */ |
1405 | return 0; | ||
1406 | |||
1407 | /* we may be lax here as interrupts are off. Nonetheless | ||
1408 | * we need to grab the correct cpu policy, as to check | ||
1409 | * whether we really run on this CPU. | ||
1410 | */ | ||
1411 | |||
1412 | cpu_policy = cpufreq_cpu_get(cpu); | 1404 | cpu_policy = cpufreq_cpu_get(cpu); |
1413 | if (!cpu_policy) | 1405 | if (!cpu_policy) |
1414 | return -EINVAL; | 1406 | return; |
1415 | |||
1416 | /* only handle each CPU group once */ | ||
1417 | if (unlikely(cpu_policy->cpu != cpu)) | ||
1418 | goto fail; | ||
1419 | 1407 | ||
1420 | if (cpufreq_driver->resume) { | 1408 | if (cpufreq_driver->resume) { |
1421 | ret = cpufreq_driver->resume(cpu_policy); | 1409 | ret = cpufreq_driver->resume(cpu_policy); |
@@ -1430,14 +1418,11 @@ static int cpufreq_resume(struct sys_device *sysdev) | |||
1430 | 1418 | ||
1431 | fail: | 1419 | fail: |
1432 | cpufreq_cpu_put(cpu_policy); | 1420 | cpufreq_cpu_put(cpu_policy); |
1433 | return ret; | ||
1434 | } | 1421 | } |
1435 | 1422 | ||
1436 | static struct sysdev_driver cpufreq_sysdev_driver = { | 1423 | static struct syscore_ops cpufreq_syscore_ops = { |
1437 | .add = cpufreq_add_dev, | 1424 | .suspend = cpufreq_bp_suspend, |
1438 | .remove = cpufreq_remove_dev, | 1425 | .resume = cpufreq_bp_resume, |
1439 | .suspend = cpufreq_suspend, | ||
1440 | .resume = cpufreq_resume, | ||
1441 | }; | 1426 | }; |
1442 | 1427 | ||
1443 | 1428 | ||
@@ -2002,6 +1987,7 @@ static int __init cpufreq_core_init(void) | |||
2002 | cpufreq_global_kobject = kobject_create_and_add("cpufreq", | 1987 | cpufreq_global_kobject = kobject_create_and_add("cpufreq", |
2003 | &cpu_sysdev_class.kset.kobj); | 1988 | &cpu_sysdev_class.kset.kobj); |
2004 | BUG_ON(!cpufreq_global_kobject); | 1989 | BUG_ON(!cpufreq_global_kobject); |
1990 | register_syscore_ops(&cpufreq_syscore_ops); | ||
2005 | 1991 | ||
2006 | return 0; | 1992 | return 0; |
2007 | } | 1993 | } |
diff --git a/drivers/gpio/adp5588-gpio.c b/drivers/gpio/adp5588-gpio.c index 33fc685cb385..3525ad918771 100644 --- a/drivers/gpio/adp5588-gpio.c +++ b/drivers/gpio/adp5588-gpio.c | |||
@@ -289,10 +289,10 @@ static int adp5588_irq_setup(struct adp5588_gpio *dev) | |||
289 | 289 | ||
290 | for (gpio = 0; gpio < dev->gpio_chip.ngpio; gpio++) { | 290 | for (gpio = 0; gpio < dev->gpio_chip.ngpio; gpio++) { |
291 | int irq = gpio + dev->irq_base; | 291 | int irq = gpio + dev->irq_base; |
292 | set_irq_chip_data(irq, dev); | 292 | irq_set_chip_data(irq, dev); |
293 | set_irq_chip_and_handler(irq, &adp5588_irq_chip, | 293 | irq_set_chip_and_handler(irq, &adp5588_irq_chip, |
294 | handle_level_irq); | 294 | handle_level_irq); |
295 | set_irq_nested_thread(irq, 1); | 295 | irq_set_nested_thread(irq, 1); |
296 | #ifdef CONFIG_ARM | 296 | #ifdef CONFIG_ARM |
297 | /* | 297 | /* |
298 | * ARM needs us to explicitly flag the IRQ as VALID, | 298 | * ARM needs us to explicitly flag the IRQ as VALID, |
@@ -300,7 +300,7 @@ static int adp5588_irq_setup(struct adp5588_gpio *dev) | |||
300 | */ | 300 | */ |
301 | set_irq_flags(irq, IRQF_VALID); | 301 | set_irq_flags(irq, IRQF_VALID); |
302 | #else | 302 | #else |
303 | set_irq_noprobe(irq); | 303 | irq_set_noprobe(irq); |
304 | #endif | 304 | #endif |
305 | } | 305 | } |
306 | 306 | ||
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 649550e2cae9..36a2974815b7 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c | |||
@@ -1656,51 +1656,6 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) | |||
1656 | chip->get | 1656 | chip->get |
1657 | ? (chip->get(chip, i) ? "hi" : "lo") | 1657 | ? (chip->get(chip, i) ? "hi" : "lo") |
1658 | : "? "); | 1658 | : "? "); |
1659 | |||
1660 | if (!is_out) { | ||
1661 | int irq = gpio_to_irq(gpio); | ||
1662 | struct irq_desc *desc = irq_to_desc(irq); | ||
1663 | |||
1664 | /* This races with request_irq(), set_irq_type(), | ||
1665 | * and set_irq_wake() ... but those are "rare". | ||
1666 | * | ||
1667 | * More significantly, trigger type flags aren't | ||
1668 | * currently maintained by genirq. | ||
1669 | */ | ||
1670 | if (irq >= 0 && desc->action) { | ||
1671 | char *trigger; | ||
1672 | |||
1673 | switch (desc->status & IRQ_TYPE_SENSE_MASK) { | ||
1674 | case IRQ_TYPE_NONE: | ||
1675 | trigger = "(default)"; | ||
1676 | break; | ||
1677 | case IRQ_TYPE_EDGE_FALLING: | ||
1678 | trigger = "edge-falling"; | ||
1679 | break; | ||
1680 | case IRQ_TYPE_EDGE_RISING: | ||
1681 | trigger = "edge-rising"; | ||
1682 | break; | ||
1683 | case IRQ_TYPE_EDGE_BOTH: | ||
1684 | trigger = "edge-both"; | ||
1685 | break; | ||
1686 | case IRQ_TYPE_LEVEL_HIGH: | ||
1687 | trigger = "level-high"; | ||
1688 | break; | ||
1689 | case IRQ_TYPE_LEVEL_LOW: | ||
1690 | trigger = "level-low"; | ||
1691 | break; | ||
1692 | default: | ||
1693 | trigger = "?trigger?"; | ||
1694 | break; | ||
1695 | } | ||
1696 | |||
1697 | seq_printf(s, " irq-%d %s%s", | ||
1698 | irq, trigger, | ||
1699 | (desc->status & IRQ_WAKEUP) | ||
1700 | ? " wakeup" : ""); | ||
1701 | } | ||
1702 | } | ||
1703 | |||
1704 | seq_printf(s, "\n"); | 1659 | seq_printf(s, "\n"); |
1705 | } | 1660 | } |
1706 | } | 1661 | } |
diff --git a/drivers/gpio/max732x.c b/drivers/gpio/max732x.c index 9e1d01f0071a..ad6951edc16c 100644 --- a/drivers/gpio/max732x.c +++ b/drivers/gpio/max732x.c | |||
@@ -470,14 +470,14 @@ static int max732x_irq_setup(struct max732x_chip *chip, | |||
470 | if (!(chip->dir_input & (1 << lvl))) | 470 | if (!(chip->dir_input & (1 << lvl))) |
471 | continue; | 471 | continue; |
472 | 472 | ||
473 | set_irq_chip_data(irq, chip); | 473 | irq_set_chip_data(irq, chip); |
474 | set_irq_chip_and_handler(irq, &max732x_irq_chip, | 474 | irq_set_chip_and_handler(irq, &max732x_irq_chip, |
475 | handle_edge_irq); | 475 | handle_edge_irq); |
476 | set_irq_nested_thread(irq, 1); | 476 | irq_set_nested_thread(irq, 1); |
477 | #ifdef CONFIG_ARM | 477 | #ifdef CONFIG_ARM |
478 | set_irq_flags(irq, IRQF_VALID); | 478 | set_irq_flags(irq, IRQF_VALID); |
479 | #else | 479 | #else |
480 | set_irq_noprobe(irq); | 480 | irq_set_noprobe(irq); |
481 | #endif | 481 | #endif |
482 | } | 482 | } |
483 | 483 | ||
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 2fc25dec7cf5..583e92592073 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c | |||
@@ -395,13 +395,13 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, | |||
395 | for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) { | 395 | for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) { |
396 | int irq = lvl + chip->irq_base; | 396 | int irq = lvl + chip->irq_base; |
397 | 397 | ||
398 | set_irq_chip_data(irq, chip); | 398 | irq_set_chip_data(irq, chip); |
399 | set_irq_chip_and_handler(irq, &pca953x_irq_chip, | 399 | irq_set_chip_and_handler(irq, &pca953x_irq_chip, |
400 | handle_edge_irq); | 400 | handle_edge_irq); |
401 | #ifdef CONFIG_ARM | 401 | #ifdef CONFIG_ARM |
402 | set_irq_flags(irq, IRQF_VALID); | 402 | set_irq_flags(irq, IRQF_VALID); |
403 | #else | 403 | #else |
404 | set_irq_noprobe(irq); | 404 | irq_set_noprobe(irq); |
405 | #endif | 405 | #endif |
406 | } | 406 | } |
407 | 407 | ||
diff --git a/drivers/gpio/pl061.c b/drivers/gpio/pl061.c index 838ddbdf90cc..6fcb28cdd862 100644 --- a/drivers/gpio/pl061.c +++ b/drivers/gpio/pl061.c | |||
@@ -210,7 +210,7 @@ static struct irq_chip pl061_irqchip = { | |||
210 | 210 | ||
211 | static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) | 211 | static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) |
212 | { | 212 | { |
213 | struct list_head *chip_list = get_irq_data(irq); | 213 | struct list_head *chip_list = irq_get_handler_data(irq); |
214 | struct list_head *ptr; | 214 | struct list_head *ptr; |
215 | struct pl061_gpio *chip; | 215 | struct pl061_gpio *chip; |
216 | 216 | ||
@@ -294,7 +294,7 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) | |||
294 | ret = -ENODEV; | 294 | ret = -ENODEV; |
295 | goto iounmap; | 295 | goto iounmap; |
296 | } | 296 | } |
297 | set_irq_chained_handler(irq, pl061_irq_handler); | 297 | irq_set_chained_handler(irq, pl061_irq_handler); |
298 | if (!test_and_set_bit(irq, init_irq)) { /* list initialized? */ | 298 | if (!test_and_set_bit(irq, init_irq)) { /* list initialized? */ |
299 | chip_list = kmalloc(sizeof(*chip_list), GFP_KERNEL); | 299 | chip_list = kmalloc(sizeof(*chip_list), GFP_KERNEL); |
300 | if (chip_list == NULL) { | 300 | if (chip_list == NULL) { |
@@ -303,9 +303,9 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) | |||
303 | goto iounmap; | 303 | goto iounmap; |
304 | } | 304 | } |
305 | INIT_LIST_HEAD(chip_list); | 305 | INIT_LIST_HEAD(chip_list); |
306 | set_irq_data(irq, chip_list); | 306 | irq_set_handler_data(irq, chip_list); |
307 | } else | 307 | } else |
308 | chip_list = get_irq_data(irq); | 308 | chip_list = irq_get_handler_data(irq); |
309 | list_add(&chip->list, chip_list); | 309 | list_add(&chip->list, chip_list); |
310 | 310 | ||
311 | for (i = 0; i < PL061_GPIO_NR; i++) { | 311 | for (i = 0; i < PL061_GPIO_NR; i++) { |
@@ -315,10 +315,10 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) | |||
315 | else | 315 | else |
316 | pl061_direction_input(&chip->gc, i); | 316 | pl061_direction_input(&chip->gc, i); |
317 | 317 | ||
318 | set_irq_chip(i+chip->irq_base, &pl061_irqchip); | 318 | irq_set_chip_and_handler(i + chip->irq_base, &pl061_irqchip, |
319 | set_irq_handler(i+chip->irq_base, handle_simple_irq); | 319 | handle_simple_irq); |
320 | set_irq_flags(i+chip->irq_base, IRQF_VALID); | 320 | set_irq_flags(i+chip->irq_base, IRQF_VALID); |
321 | set_irq_chip_data(i+chip->irq_base, chip); | 321 | irq_set_chip_data(i + chip->irq_base, chip); |
322 | } | 322 | } |
323 | 323 | ||
324 | return 0; | 324 | return 0; |
diff --git a/drivers/gpio/stmpe-gpio.c b/drivers/gpio/stmpe-gpio.c index eb2901f8ab5e..4c980b573328 100644 --- a/drivers/gpio/stmpe-gpio.c +++ b/drivers/gpio/stmpe-gpio.c | |||
@@ -254,14 +254,14 @@ static int __devinit stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio) | |||
254 | int irq; | 254 | int irq; |
255 | 255 | ||
256 | for (irq = base; irq < base + stmpe_gpio->chip.ngpio; irq++) { | 256 | for (irq = base; irq < base + stmpe_gpio->chip.ngpio; irq++) { |
257 | set_irq_chip_data(irq, stmpe_gpio); | 257 | irq_set_chip_data(irq, stmpe_gpio); |
258 | set_irq_chip_and_handler(irq, &stmpe_gpio_irq_chip, | 258 | irq_set_chip_and_handler(irq, &stmpe_gpio_irq_chip, |
259 | handle_simple_irq); | 259 | handle_simple_irq); |
260 | set_irq_nested_thread(irq, 1); | 260 | irq_set_nested_thread(irq, 1); |
261 | #ifdef CONFIG_ARM | 261 | #ifdef CONFIG_ARM |
262 | set_irq_flags(irq, IRQF_VALID); | 262 | set_irq_flags(irq, IRQF_VALID); |
263 | #else | 263 | #else |
264 | set_irq_noprobe(irq); | 264 | irq_set_noprobe(irq); |
265 | #endif | 265 | #endif |
266 | } | 266 | } |
267 | 267 | ||
@@ -277,8 +277,8 @@ static void stmpe_gpio_irq_remove(struct stmpe_gpio *stmpe_gpio) | |||
277 | #ifdef CONFIG_ARM | 277 | #ifdef CONFIG_ARM |
278 | set_irq_flags(irq, 0); | 278 | set_irq_flags(irq, 0); |
279 | #endif | 279 | #endif |
280 | set_irq_chip_and_handler(irq, NULL, NULL); | 280 | irq_set_chip_and_handler(irq, NULL, NULL); |
281 | set_irq_chip_data(irq, NULL); | 281 | irq_set_chip_data(irq, NULL); |
282 | } | 282 | } |
283 | } | 283 | } |
284 | 284 | ||
diff --git a/drivers/gpio/sx150x.c b/drivers/gpio/sx150x.c index d2f874c3d3d5..a4f73534394e 100644 --- a/drivers/gpio/sx150x.c +++ b/drivers/gpio/sx150x.c | |||
@@ -551,12 +551,12 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip, | |||
551 | 551 | ||
552 | for (n = 0; n < chip->dev_cfg->ngpios; ++n) { | 552 | for (n = 0; n < chip->dev_cfg->ngpios; ++n) { |
553 | irq = irq_base + n; | 553 | irq = irq_base + n; |
554 | set_irq_chip_and_handler(irq, &chip->irq_chip, handle_edge_irq); | 554 | irq_set_chip_and_handler(irq, &chip->irq_chip, handle_edge_irq); |
555 | set_irq_nested_thread(irq, 1); | 555 | irq_set_nested_thread(irq, 1); |
556 | #ifdef CONFIG_ARM | 556 | #ifdef CONFIG_ARM |
557 | set_irq_flags(irq, IRQF_VALID); | 557 | set_irq_flags(irq, IRQF_VALID); |
558 | #else | 558 | #else |
559 | set_irq_noprobe(irq); | 559 | irq_set_noprobe(irq); |
560 | #endif | 560 | #endif |
561 | } | 561 | } |
562 | 562 | ||
@@ -583,8 +583,7 @@ static void sx150x_remove_irq_chip(struct sx150x_chip *chip) | |||
583 | 583 | ||
584 | for (n = 0; n < chip->dev_cfg->ngpios; ++n) { | 584 | for (n = 0; n < chip->dev_cfg->ngpios; ++n) { |
585 | irq = chip->irq_base + n; | 585 | irq = chip->irq_base + n; |
586 | set_irq_handler(irq, NULL); | 586 | irq_set_chip_and_handler(irq, NULL, NULL); |
587 | set_irq_chip(irq, NULL); | ||
588 | } | 587 | } |
589 | } | 588 | } |
590 | 589 | ||
diff --git a/drivers/gpio/tc3589x-gpio.c b/drivers/gpio/tc3589x-gpio.c index 27200af1a595..2a82e8999a42 100644 --- a/drivers/gpio/tc3589x-gpio.c +++ b/drivers/gpio/tc3589x-gpio.c | |||
@@ -239,14 +239,14 @@ static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio) | |||
239 | int irq; | 239 | int irq; |
240 | 240 | ||
241 | for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) { | 241 | for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) { |
242 | set_irq_chip_data(irq, tc3589x_gpio); | 242 | irq_set_chip_data(irq, tc3589x_gpio); |
243 | set_irq_chip_and_handler(irq, &tc3589x_gpio_irq_chip, | 243 | irq_set_chip_and_handler(irq, &tc3589x_gpio_irq_chip, |
244 | handle_simple_irq); | 244 | handle_simple_irq); |
245 | set_irq_nested_thread(irq, 1); | 245 | irq_set_nested_thread(irq, 1); |
246 | #ifdef CONFIG_ARM | 246 | #ifdef CONFIG_ARM |
247 | set_irq_flags(irq, IRQF_VALID); | 247 | set_irq_flags(irq, IRQF_VALID); |
248 | #else | 248 | #else |
249 | set_irq_noprobe(irq); | 249 | irq_set_noprobe(irq); |
250 | #endif | 250 | #endif |
251 | } | 251 | } |
252 | 252 | ||
@@ -262,8 +262,8 @@ static void tc3589x_gpio_irq_remove(struct tc3589x_gpio *tc3589x_gpio) | |||
262 | #ifdef CONFIG_ARM | 262 | #ifdef CONFIG_ARM |
263 | set_irq_flags(irq, 0); | 263 | set_irq_flags(irq, 0); |
264 | #endif | 264 | #endif |
265 | set_irq_chip_and_handler(irq, NULL, NULL); | 265 | irq_set_chip_and_handler(irq, NULL, NULL); |
266 | set_irq_chip_data(irq, NULL); | 266 | irq_set_chip_data(irq, NULL); |
267 | } | 267 | } |
268 | } | 268 | } |
269 | 269 | ||
diff --git a/drivers/gpio/timbgpio.c b/drivers/gpio/timbgpio.c index ffcd815b8b8b..edbe1eae531f 100644 --- a/drivers/gpio/timbgpio.c +++ b/drivers/gpio/timbgpio.c | |||
@@ -196,7 +196,7 @@ out: | |||
196 | 196 | ||
197 | static void timbgpio_irq(unsigned int irq, struct irq_desc *desc) | 197 | static void timbgpio_irq(unsigned int irq, struct irq_desc *desc) |
198 | { | 198 | { |
199 | struct timbgpio *tgpio = get_irq_data(irq); | 199 | struct timbgpio *tgpio = irq_get_handler_data(irq); |
200 | unsigned long ipr; | 200 | unsigned long ipr; |
201 | int offset; | 201 | int offset; |
202 | 202 | ||
@@ -292,16 +292,16 @@ static int __devinit timbgpio_probe(struct platform_device *pdev) | |||
292 | return 0; | 292 | return 0; |
293 | 293 | ||
294 | for (i = 0; i < pdata->nr_pins; i++) { | 294 | for (i = 0; i < pdata->nr_pins; i++) { |
295 | set_irq_chip_and_handler_name(tgpio->irq_base + i, | 295 | irq_set_chip_and_handler_name(tgpio->irq_base + i, |
296 | &timbgpio_irqchip, handle_simple_irq, "mux"); | 296 | &timbgpio_irqchip, handle_simple_irq, "mux"); |
297 | set_irq_chip_data(tgpio->irq_base + i, tgpio); | 297 | irq_set_chip_data(tgpio->irq_base + i, tgpio); |
298 | #ifdef CONFIG_ARM | 298 | #ifdef CONFIG_ARM |
299 | set_irq_flags(tgpio->irq_base + i, IRQF_VALID | IRQF_PROBE); | 299 | set_irq_flags(tgpio->irq_base + i, IRQF_VALID | IRQF_PROBE); |
300 | #endif | 300 | #endif |
301 | } | 301 | } |
302 | 302 | ||
303 | set_irq_data(irq, tgpio); | 303 | irq_set_handler_data(irq, tgpio); |
304 | set_irq_chained_handler(irq, timbgpio_irq); | 304 | irq_set_chained_handler(irq, timbgpio_irq); |
305 | 305 | ||
306 | return 0; | 306 | return 0; |
307 | 307 | ||
@@ -327,12 +327,12 @@ static int __devexit timbgpio_remove(struct platform_device *pdev) | |||
327 | if (irq >= 0 && tgpio->irq_base > 0) { | 327 | if (irq >= 0 && tgpio->irq_base > 0) { |
328 | int i; | 328 | int i; |
329 | for (i = 0; i < tgpio->gpio.ngpio; i++) { | 329 | for (i = 0; i < tgpio->gpio.ngpio; i++) { |
330 | set_irq_chip(tgpio->irq_base + i, NULL); | 330 | irq_set_chip(tgpio->irq_base + i, NULL); |
331 | set_irq_chip_data(tgpio->irq_base + i, NULL); | 331 | irq_set_chip_data(tgpio->irq_base + i, NULL); |
332 | } | 332 | } |
333 | 333 | ||
334 | set_irq_handler(irq, NULL); | 334 | irq_set_handler(irq, NULL); |
335 | set_irq_data(irq, NULL); | 335 | irq_set_handler_data(irq, NULL); |
336 | } | 336 | } |
337 | 337 | ||
338 | err = gpiochip_remove(&tgpio->gpio); | 338 | err = gpiochip_remove(&tgpio->gpio); |
diff --git a/drivers/gpio/vr41xx_giu.c b/drivers/gpio/vr41xx_giu.c index cffa3bd7ad3b..a365be040b36 100644 --- a/drivers/gpio/vr41xx_giu.c +++ b/drivers/gpio/vr41xx_giu.c | |||
@@ -238,13 +238,13 @@ void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, | |||
238 | break; | 238 | break; |
239 | } | 239 | } |
240 | } | 240 | } |
241 | set_irq_chip_and_handler(GIU_IRQ(pin), | 241 | irq_set_chip_and_handler(GIU_IRQ(pin), |
242 | &giuint_low_irq_chip, | 242 | &giuint_low_irq_chip, |
243 | handle_edge_irq); | 243 | handle_edge_irq); |
244 | } else { | 244 | } else { |
245 | giu_clear(GIUINTTYPL, mask); | 245 | giu_clear(GIUINTTYPL, mask); |
246 | giu_clear(GIUINTHTSELL, mask); | 246 | giu_clear(GIUINTHTSELL, mask); |
247 | set_irq_chip_and_handler(GIU_IRQ(pin), | 247 | irq_set_chip_and_handler(GIU_IRQ(pin), |
248 | &giuint_low_irq_chip, | 248 | &giuint_low_irq_chip, |
249 | handle_level_irq); | 249 | handle_level_irq); |
250 | } | 250 | } |
@@ -273,13 +273,13 @@ void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, | |||
273 | break; | 273 | break; |
274 | } | 274 | } |
275 | } | 275 | } |
276 | set_irq_chip_and_handler(GIU_IRQ(pin), | 276 | irq_set_chip_and_handler(GIU_IRQ(pin), |
277 | &giuint_high_irq_chip, | 277 | &giuint_high_irq_chip, |
278 | handle_edge_irq); | 278 | handle_edge_irq); |
279 | } else { | 279 | } else { |
280 | giu_clear(GIUINTTYPH, mask); | 280 | giu_clear(GIUINTTYPH, mask); |
281 | giu_clear(GIUINTHTSELH, mask); | 281 | giu_clear(GIUINTHTSELH, mask); |
282 | set_irq_chip_and_handler(GIU_IRQ(pin), | 282 | irq_set_chip_and_handler(GIU_IRQ(pin), |
283 | &giuint_high_irq_chip, | 283 | &giuint_high_irq_chip, |
284 | handle_level_irq); | 284 | handle_level_irq); |
285 | } | 285 | } |
@@ -539,9 +539,9 @@ static int __devinit giu_probe(struct platform_device *pdev) | |||
539 | chip = &giuint_high_irq_chip; | 539 | chip = &giuint_high_irq_chip; |
540 | 540 | ||
541 | if (trigger & (1 << pin)) | 541 | if (trigger & (1 << pin)) |
542 | set_irq_chip_and_handler(i, chip, handle_edge_irq); | 542 | irq_set_chip_and_handler(i, chip, handle_edge_irq); |
543 | else | 543 | else |
544 | set_irq_chip_and_handler(i, chip, handle_level_irq); | 544 | irq_set_chip_and_handler(i, chip, handle_level_irq); |
545 | 545 | ||
546 | } | 546 | } |
547 | 547 | ||
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 4c95b5fd9df3..799e1490cf24 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -1073,6 +1073,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data, | |||
1073 | uint32_t __user *encoder_id; | 1073 | uint32_t __user *encoder_id; |
1074 | struct drm_mode_group *mode_group; | 1074 | struct drm_mode_group *mode_group; |
1075 | 1075 | ||
1076 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1077 | return -EINVAL; | ||
1078 | |||
1076 | mutex_lock(&dev->mode_config.mutex); | 1079 | mutex_lock(&dev->mode_config.mutex); |
1077 | 1080 | ||
1078 | /* | 1081 | /* |
@@ -1244,6 +1247,9 @@ int drm_mode_getcrtc(struct drm_device *dev, | |||
1244 | struct drm_mode_object *obj; | 1247 | struct drm_mode_object *obj; |
1245 | int ret = 0; | 1248 | int ret = 0; |
1246 | 1249 | ||
1250 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1251 | return -EINVAL; | ||
1252 | |||
1247 | mutex_lock(&dev->mode_config.mutex); | 1253 | mutex_lock(&dev->mode_config.mutex); |
1248 | 1254 | ||
1249 | obj = drm_mode_object_find(dev, crtc_resp->crtc_id, | 1255 | obj = drm_mode_object_find(dev, crtc_resp->crtc_id, |
@@ -1312,6 +1318,9 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
1312 | uint64_t __user *prop_values; | 1318 | uint64_t __user *prop_values; |
1313 | uint32_t __user *encoder_ptr; | 1319 | uint32_t __user *encoder_ptr; |
1314 | 1320 | ||
1321 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1322 | return -EINVAL; | ||
1323 | |||
1315 | memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); | 1324 | memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); |
1316 | 1325 | ||
1317 | DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); | 1326 | DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); |
@@ -1431,6 +1440,9 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, | |||
1431 | struct drm_encoder *encoder; | 1440 | struct drm_encoder *encoder; |
1432 | int ret = 0; | 1441 | int ret = 0; |
1433 | 1442 | ||
1443 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1444 | return -EINVAL; | ||
1445 | |||
1434 | mutex_lock(&dev->mode_config.mutex); | 1446 | mutex_lock(&dev->mode_config.mutex); |
1435 | obj = drm_mode_object_find(dev, enc_resp->encoder_id, | 1447 | obj = drm_mode_object_find(dev, enc_resp->encoder_id, |
1436 | DRM_MODE_OBJECT_ENCODER); | 1448 | DRM_MODE_OBJECT_ENCODER); |
@@ -1486,6 +1498,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, | |||
1486 | int ret = 0; | 1498 | int ret = 0; |
1487 | int i; | 1499 | int i; |
1488 | 1500 | ||
1501 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1502 | return -EINVAL; | ||
1503 | |||
1489 | mutex_lock(&dev->mode_config.mutex); | 1504 | mutex_lock(&dev->mode_config.mutex); |
1490 | obj = drm_mode_object_find(dev, crtc_req->crtc_id, | 1505 | obj = drm_mode_object_find(dev, crtc_req->crtc_id, |
1491 | DRM_MODE_OBJECT_CRTC); | 1506 | DRM_MODE_OBJECT_CRTC); |
@@ -1603,6 +1618,9 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, | |||
1603 | struct drm_crtc *crtc; | 1618 | struct drm_crtc *crtc; |
1604 | int ret = 0; | 1619 | int ret = 0; |
1605 | 1620 | ||
1621 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1622 | return -EINVAL; | ||
1623 | |||
1606 | if (!req->flags) { | 1624 | if (!req->flags) { |
1607 | DRM_ERROR("no operation set\n"); | 1625 | DRM_ERROR("no operation set\n"); |
1608 | return -EINVAL; | 1626 | return -EINVAL; |
@@ -1667,6 +1685,9 @@ int drm_mode_addfb(struct drm_device *dev, | |||
1667 | struct drm_framebuffer *fb; | 1685 | struct drm_framebuffer *fb; |
1668 | int ret = 0; | 1686 | int ret = 0; |
1669 | 1687 | ||
1688 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1689 | return -EINVAL; | ||
1690 | |||
1670 | if ((config->min_width > r->width) || (r->width > config->max_width)) { | 1691 | if ((config->min_width > r->width) || (r->width > config->max_width)) { |
1671 | DRM_ERROR("mode new framebuffer width not within limits\n"); | 1692 | DRM_ERROR("mode new framebuffer width not within limits\n"); |
1672 | return -EINVAL; | 1693 | return -EINVAL; |
@@ -1724,6 +1745,9 @@ int drm_mode_rmfb(struct drm_device *dev, | |||
1724 | int ret = 0; | 1745 | int ret = 0; |
1725 | int found = 0; | 1746 | int found = 0; |
1726 | 1747 | ||
1748 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1749 | return -EINVAL; | ||
1750 | |||
1727 | mutex_lock(&dev->mode_config.mutex); | 1751 | mutex_lock(&dev->mode_config.mutex); |
1728 | obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB); | 1752 | obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB); |
1729 | /* TODO check that we realy get a framebuffer back. */ | 1753 | /* TODO check that we realy get a framebuffer back. */ |
@@ -1780,6 +1804,9 @@ int drm_mode_getfb(struct drm_device *dev, | |||
1780 | struct drm_framebuffer *fb; | 1804 | struct drm_framebuffer *fb; |
1781 | int ret = 0; | 1805 | int ret = 0; |
1782 | 1806 | ||
1807 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1808 | return -EINVAL; | ||
1809 | |||
1783 | mutex_lock(&dev->mode_config.mutex); | 1810 | mutex_lock(&dev->mode_config.mutex); |
1784 | obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); | 1811 | obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); |
1785 | if (!obj) { | 1812 | if (!obj) { |
@@ -1813,6 +1840,9 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, | |||
1813 | int num_clips; | 1840 | int num_clips; |
1814 | int ret = 0; | 1841 | int ret = 0; |
1815 | 1842 | ||
1843 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1844 | return -EINVAL; | ||
1845 | |||
1816 | mutex_lock(&dev->mode_config.mutex); | 1846 | mutex_lock(&dev->mode_config.mutex); |
1817 | obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); | 1847 | obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); |
1818 | if (!obj) { | 1848 | if (!obj) { |
@@ -1996,6 +2026,9 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev, | |||
1996 | struct drm_mode_modeinfo *umode = &mode_cmd->mode; | 2026 | struct drm_mode_modeinfo *umode = &mode_cmd->mode; |
1997 | int ret = 0; | 2027 | int ret = 0; |
1998 | 2028 | ||
2029 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
2030 | return -EINVAL; | ||
2031 | |||
1999 | mutex_lock(&dev->mode_config.mutex); | 2032 | mutex_lock(&dev->mode_config.mutex); |
2000 | 2033 | ||
2001 | obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); | 2034 | obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); |
@@ -2042,6 +2075,9 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev, | |||
2042 | struct drm_mode_modeinfo *umode = &mode_cmd->mode; | 2075 | struct drm_mode_modeinfo *umode = &mode_cmd->mode; |
2043 | int ret = 0; | 2076 | int ret = 0; |
2044 | 2077 | ||
2078 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
2079 | return -EINVAL; | ||
2080 | |||
2045 | mutex_lock(&dev->mode_config.mutex); | 2081 | mutex_lock(&dev->mode_config.mutex); |
2046 | 2082 | ||
2047 | obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); | 2083 | obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); |
@@ -2211,6 +2247,9 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, | |||
2211 | uint64_t __user *values_ptr; | 2247 | uint64_t __user *values_ptr; |
2212 | uint32_t __user *blob_length_ptr; | 2248 | uint32_t __user *blob_length_ptr; |
2213 | 2249 | ||
2250 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
2251 | return -EINVAL; | ||
2252 | |||
2214 | mutex_lock(&dev->mode_config.mutex); | 2253 | mutex_lock(&dev->mode_config.mutex); |
2215 | obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); | 2254 | obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); |
2216 | if (!obj) { | 2255 | if (!obj) { |
@@ -2333,6 +2372,9 @@ int drm_mode_getblob_ioctl(struct drm_device *dev, | |||
2333 | int ret = 0; | 2372 | int ret = 0; |
2334 | void *blob_ptr; | 2373 | void *blob_ptr; |
2335 | 2374 | ||
2375 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
2376 | return -EINVAL; | ||
2377 | |||
2336 | mutex_lock(&dev->mode_config.mutex); | 2378 | mutex_lock(&dev->mode_config.mutex); |
2337 | obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB); | 2379 | obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB); |
2338 | if (!obj) { | 2380 | if (!obj) { |
@@ -2393,6 +2435,9 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev, | |||
2393 | int ret = -EINVAL; | 2435 | int ret = -EINVAL; |
2394 | int i; | 2436 | int i; |
2395 | 2437 | ||
2438 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
2439 | return -EINVAL; | ||
2440 | |||
2396 | mutex_lock(&dev->mode_config.mutex); | 2441 | mutex_lock(&dev->mode_config.mutex); |
2397 | 2442 | ||
2398 | obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR); | 2443 | obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR); |
@@ -2509,6 +2554,9 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, | |||
2509 | int size; | 2554 | int size; |
2510 | int ret = 0; | 2555 | int ret = 0; |
2511 | 2556 | ||
2557 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
2558 | return -EINVAL; | ||
2559 | |||
2512 | mutex_lock(&dev->mode_config.mutex); | 2560 | mutex_lock(&dev->mode_config.mutex); |
2513 | obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); | 2561 | obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); |
2514 | if (!obj) { | 2562 | if (!obj) { |
@@ -2560,6 +2608,9 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, | |||
2560 | int size; | 2608 | int size; |
2561 | int ret = 0; | 2609 | int ret = 0; |
2562 | 2610 | ||
2611 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
2612 | return -EINVAL; | ||
2613 | |||
2563 | mutex_lock(&dev->mode_config.mutex); | 2614 | mutex_lock(&dev->mode_config.mutex); |
2564 | obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); | 2615 | obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); |
2565 | if (!obj) { | 2616 | if (!obj) { |
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 57ce27c9a747..74e4ff578017 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c | |||
@@ -499,11 +499,12 @@ EXPORT_SYMBOL(drm_gem_vm_open); | |||
499 | void drm_gem_vm_close(struct vm_area_struct *vma) | 499 | void drm_gem_vm_close(struct vm_area_struct *vma) |
500 | { | 500 | { |
501 | struct drm_gem_object *obj = vma->vm_private_data; | 501 | struct drm_gem_object *obj = vma->vm_private_data; |
502 | struct drm_device *dev = obj->dev; | ||
502 | 503 | ||
503 | mutex_lock(&obj->dev->struct_mutex); | 504 | mutex_lock(&dev->struct_mutex); |
504 | drm_vm_close_locked(vma); | 505 | drm_vm_close_locked(vma); |
505 | drm_gem_object_unreference(obj); | 506 | drm_gem_object_unreference(obj); |
506 | mutex_unlock(&obj->dev->struct_mutex); | 507 | mutex_unlock(&dev->struct_mutex); |
507 | } | 508 | } |
508 | EXPORT_SYMBOL(drm_gem_vm_close); | 509 | EXPORT_SYMBOL(drm_gem_vm_close); |
509 | 510 | ||
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 7f6912a16761..904d7e9c8e47 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c | |||
@@ -280,6 +280,9 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) | |||
280 | if (dev->driver->dumb_create) | 280 | if (dev->driver->dumb_create) |
281 | req->value = 1; | 281 | req->value = 1; |
282 | break; | 282 | break; |
283 | case DRM_CAP_VBLANK_HIGH_CRTC: | ||
284 | req->value = 1; | ||
285 | break; | ||
283 | default: | 286 | default: |
284 | return -EINVAL; | 287 | return -EINVAL; |
285 | } | 288 | } |
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index a34ef97d3c81..741457bd1c46 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c | |||
@@ -1125,7 +1125,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
1125 | { | 1125 | { |
1126 | union drm_wait_vblank *vblwait = data; | 1126 | union drm_wait_vblank *vblwait = data; |
1127 | int ret = 0; | 1127 | int ret = 0; |
1128 | unsigned int flags, seq, crtc; | 1128 | unsigned int flags, seq, crtc, high_crtc; |
1129 | 1129 | ||
1130 | if ((!drm_dev_to_irq(dev)) || (!dev->irq_enabled)) | 1130 | if ((!drm_dev_to_irq(dev)) || (!dev->irq_enabled)) |
1131 | return -EINVAL; | 1131 | return -EINVAL; |
@@ -1134,16 +1134,21 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
1134 | return -EINVAL; | 1134 | return -EINVAL; |
1135 | 1135 | ||
1136 | if (vblwait->request.type & | 1136 | if (vblwait->request.type & |
1137 | ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) { | 1137 | ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | |
1138 | _DRM_VBLANK_HIGH_CRTC_MASK)) { | ||
1138 | DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", | 1139 | DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", |
1139 | vblwait->request.type, | 1140 | vblwait->request.type, |
1140 | (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)); | 1141 | (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | |
1142 | _DRM_VBLANK_HIGH_CRTC_MASK)); | ||
1141 | return -EINVAL; | 1143 | return -EINVAL; |
1142 | } | 1144 | } |
1143 | 1145 | ||
1144 | flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; | 1146 | flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; |
1145 | crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; | 1147 | high_crtc = (vblwait->request.type & _DRM_VBLANK_HIGH_CRTC_MASK); |
1146 | 1148 | if (high_crtc) | |
1149 | crtc = high_crtc >> _DRM_VBLANK_HIGH_CRTC_SHIFT; | ||
1150 | else | ||
1151 | crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; | ||
1147 | if (crtc >= dev->num_crtcs) | 1152 | if (crtc >= dev->num_crtcs) |
1148 | return -EINVAL; | 1153 | return -EINVAL; |
1149 | 1154 | ||
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 09e0327fc6ce..87c8e29465e3 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c | |||
@@ -892,7 +892,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) | |||
892 | seq_printf(m, "Render p-state limit: %d\n", | 892 | seq_printf(m, "Render p-state limit: %d\n", |
893 | rp_state_limits & 0xff); | 893 | rp_state_limits & 0xff); |
894 | seq_printf(m, "CAGF: %dMHz\n", ((rpstat & GEN6_CAGF_MASK) >> | 894 | seq_printf(m, "CAGF: %dMHz\n", ((rpstat & GEN6_CAGF_MASK) >> |
895 | GEN6_CAGF_SHIFT) * 100); | 895 | GEN6_CAGF_SHIFT) * 50); |
896 | seq_printf(m, "RP CUR UP EI: %dus\n", rpupei & | 896 | seq_printf(m, "RP CUR UP EI: %dus\n", rpupei & |
897 | GEN6_CURICONT_MASK); | 897 | GEN6_CURICONT_MASK); |
898 | seq_printf(m, "RP CUR UP: %dus\n", rpcurup & | 898 | seq_printf(m, "RP CUR UP: %dus\n", rpcurup & |
@@ -908,15 +908,15 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) | |||
908 | 908 | ||
909 | max_freq = (rp_state_cap & 0xff0000) >> 16; | 909 | max_freq = (rp_state_cap & 0xff0000) >> 16; |
910 | seq_printf(m, "Lowest (RPN) frequency: %dMHz\n", | 910 | seq_printf(m, "Lowest (RPN) frequency: %dMHz\n", |
911 | max_freq * 100); | 911 | max_freq * 50); |
912 | 912 | ||
913 | max_freq = (rp_state_cap & 0xff00) >> 8; | 913 | max_freq = (rp_state_cap & 0xff00) >> 8; |
914 | seq_printf(m, "Nominal (RP1) frequency: %dMHz\n", | 914 | seq_printf(m, "Nominal (RP1) frequency: %dMHz\n", |
915 | max_freq * 100); | 915 | max_freq * 50); |
916 | 916 | ||
917 | max_freq = rp_state_cap & 0xff; | 917 | max_freq = rp_state_cap & 0xff; |
918 | seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", | 918 | seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", |
919 | max_freq * 100); | 919 | max_freq * 50); |
920 | 920 | ||
921 | __gen6_gt_force_wake_put(dev_priv); | 921 | __gen6_gt_force_wake_put(dev_priv); |
922 | } else { | 922 | } else { |
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c4c2855d002d..7ce3f353af33 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -224,7 +224,7 @@ i915_gem_dumb_create(struct drm_file *file, | |||
224 | struct drm_mode_create_dumb *args) | 224 | struct drm_mode_create_dumb *args) |
225 | { | 225 | { |
226 | /* have to work out size/pitch and return them */ | 226 | /* have to work out size/pitch and return them */ |
227 | args->pitch = ALIGN(args->width & ((args->bpp + 1) / 8), 64); | 227 | args->pitch = ALIGN(args->width * ((args->bpp + 7) / 8), 64); |
228 | args->size = args->pitch * args->height; | 228 | args->size = args->pitch * args->height; |
229 | return i915_gem_create(file, dev, | 229 | return i915_gem_create(file, dev, |
230 | args->size, &args->handle); | 230 | args->size, &args->handle); |
@@ -1356,9 +1356,10 @@ i915_gem_release_mmap(struct drm_i915_gem_object *obj) | |||
1356 | if (!obj->fault_mappable) | 1356 | if (!obj->fault_mappable) |
1357 | return; | 1357 | return; |
1358 | 1358 | ||
1359 | unmap_mapping_range(obj->base.dev->dev_mapping, | 1359 | if (obj->base.dev->dev_mapping) |
1360 | (loff_t)obj->base.map_list.hash.key<<PAGE_SHIFT, | 1360 | unmap_mapping_range(obj->base.dev->dev_mapping, |
1361 | obj->base.size, 1); | 1361 | (loff_t)obj->base.map_list.hash.key<<PAGE_SHIFT, |
1362 | obj->base.size, 1); | ||
1362 | 1363 | ||
1363 | obj->fault_mappable = false; | 1364 | obj->fault_mappable = false; |
1364 | } | 1365 | } |
@@ -1796,8 +1797,10 @@ i915_gem_request_remove_from_client(struct drm_i915_gem_request *request) | |||
1796 | return; | 1797 | return; |
1797 | 1798 | ||
1798 | spin_lock(&file_priv->mm.lock); | 1799 | spin_lock(&file_priv->mm.lock); |
1799 | list_del(&request->client_list); | 1800 | if (request->file_priv) { |
1800 | request->file_priv = NULL; | 1801 | list_del(&request->client_list); |
1802 | request->file_priv = NULL; | ||
1803 | } | ||
1801 | spin_unlock(&file_priv->mm.lock); | 1804 | spin_unlock(&file_priv->mm.lock); |
1802 | } | 1805 | } |
1803 | 1806 | ||
@@ -2217,13 +2220,18 @@ i915_gem_flush_ring(struct intel_ring_buffer *ring, | |||
2217 | { | 2220 | { |
2218 | int ret; | 2221 | int ret; |
2219 | 2222 | ||
2223 | if (((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) == 0) | ||
2224 | return 0; | ||
2225 | |||
2220 | trace_i915_gem_ring_flush(ring, invalidate_domains, flush_domains); | 2226 | trace_i915_gem_ring_flush(ring, invalidate_domains, flush_domains); |
2221 | 2227 | ||
2222 | ret = ring->flush(ring, invalidate_domains, flush_domains); | 2228 | ret = ring->flush(ring, invalidate_domains, flush_domains); |
2223 | if (ret) | 2229 | if (ret) |
2224 | return ret; | 2230 | return ret; |
2225 | 2231 | ||
2226 | i915_gem_process_flushing_list(ring, flush_domains); | 2232 | if (flush_domains & I915_GEM_GPU_DOMAINS) |
2233 | i915_gem_process_flushing_list(ring, flush_domains); | ||
2234 | |||
2227 | return 0; | 2235 | return 0; |
2228 | } | 2236 | } |
2229 | 2237 | ||
@@ -2579,8 +2587,23 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj, | |||
2579 | reg = &dev_priv->fence_regs[obj->fence_reg]; | 2587 | reg = &dev_priv->fence_regs[obj->fence_reg]; |
2580 | list_move_tail(®->lru_list, &dev_priv->mm.fence_list); | 2588 | list_move_tail(®->lru_list, &dev_priv->mm.fence_list); |
2581 | 2589 | ||
2582 | if (!obj->fenced_gpu_access && !obj->last_fenced_seqno) | 2590 | if (obj->tiling_changed) { |
2583 | pipelined = NULL; | 2591 | ret = i915_gem_object_flush_fence(obj, pipelined); |
2592 | if (ret) | ||
2593 | return ret; | ||
2594 | |||
2595 | if (!obj->fenced_gpu_access && !obj->last_fenced_seqno) | ||
2596 | pipelined = NULL; | ||
2597 | |||
2598 | if (pipelined) { | ||
2599 | reg->setup_seqno = | ||
2600 | i915_gem_next_request_seqno(pipelined); | ||
2601 | obj->last_fenced_seqno = reg->setup_seqno; | ||
2602 | obj->last_fenced_ring = pipelined; | ||
2603 | } | ||
2604 | |||
2605 | goto update; | ||
2606 | } | ||
2584 | 2607 | ||
2585 | if (!pipelined) { | 2608 | if (!pipelined) { |
2586 | if (reg->setup_seqno) { | 2609 | if (reg->setup_seqno) { |
@@ -2599,31 +2622,6 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj, | |||
2599 | ret = i915_gem_object_flush_fence(obj, pipelined); | 2622 | ret = i915_gem_object_flush_fence(obj, pipelined); |
2600 | if (ret) | 2623 | if (ret) |
2601 | return ret; | 2624 | return ret; |
2602 | } else if (obj->tiling_changed) { | ||
2603 | if (obj->fenced_gpu_access) { | ||
2604 | if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) { | ||
2605 | ret = i915_gem_flush_ring(obj->ring, | ||
2606 | 0, obj->base.write_domain); | ||
2607 | if (ret) | ||
2608 | return ret; | ||
2609 | } | ||
2610 | |||
2611 | obj->fenced_gpu_access = false; | ||
2612 | } | ||
2613 | } | ||
2614 | |||
2615 | if (!obj->fenced_gpu_access && !obj->last_fenced_seqno) | ||
2616 | pipelined = NULL; | ||
2617 | BUG_ON(!pipelined && reg->setup_seqno); | ||
2618 | |||
2619 | if (obj->tiling_changed) { | ||
2620 | if (pipelined) { | ||
2621 | reg->setup_seqno = | ||
2622 | i915_gem_next_request_seqno(pipelined); | ||
2623 | obj->last_fenced_seqno = reg->setup_seqno; | ||
2624 | obj->last_fenced_ring = pipelined; | ||
2625 | } | ||
2626 | goto update; | ||
2627 | } | 2625 | } |
2628 | 2626 | ||
2629 | return 0; | 2627 | return 0; |
@@ -3606,6 +3604,8 @@ static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj) | |||
3606 | return; | 3604 | return; |
3607 | } | 3605 | } |
3608 | 3606 | ||
3607 | trace_i915_gem_object_destroy(obj); | ||
3608 | |||
3609 | if (obj->base.map_list.map) | 3609 | if (obj->base.map_list.map) |
3610 | i915_gem_free_mmap_offset(obj); | 3610 | i915_gem_free_mmap_offset(obj); |
3611 | 3611 | ||
@@ -3615,8 +3615,6 @@ static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj) | |||
3615 | kfree(obj->page_cpu_valid); | 3615 | kfree(obj->page_cpu_valid); |
3616 | kfree(obj->bit_17); | 3616 | kfree(obj->bit_17); |
3617 | kfree(obj); | 3617 | kfree(obj); |
3618 | |||
3619 | trace_i915_gem_object_destroy(obj); | ||
3620 | } | 3618 | } |
3621 | 3619 | ||
3622 | void i915_gem_free_object(struct drm_gem_object *gem_obj) | 3620 | void i915_gem_free_object(struct drm_gem_object *gem_obj) |
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 7ff7f933ddf1..20a4cc5b818f 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c | |||
@@ -367,6 +367,10 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, | |||
367 | uint32_t __iomem *reloc_entry; | 367 | uint32_t __iomem *reloc_entry; |
368 | void __iomem *reloc_page; | 368 | void __iomem *reloc_page; |
369 | 369 | ||
370 | /* We can't wait for rendering with pagefaults disabled */ | ||
371 | if (obj->active && in_atomic()) | ||
372 | return -EFAULT; | ||
373 | |||
370 | ret = i915_gem_object_set_to_gtt_domain(obj, 1); | 374 | ret = i915_gem_object_set_to_gtt_domain(obj, 1); |
371 | if (ret) | 375 | if (ret) |
372 | return ret; | 376 | return ret; |
@@ -440,15 +444,24 @@ i915_gem_execbuffer_relocate(struct drm_device *dev, | |||
440 | struct list_head *objects) | 444 | struct list_head *objects) |
441 | { | 445 | { |
442 | struct drm_i915_gem_object *obj; | 446 | struct drm_i915_gem_object *obj; |
443 | int ret; | 447 | int ret = 0; |
444 | 448 | ||
449 | /* This is the fast path and we cannot handle a pagefault whilst | ||
450 | * holding the struct mutex lest the user pass in the relocations | ||
451 | * contained within a mmaped bo. For in such a case we, the page | ||
452 | * fault handler would call i915_gem_fault() and we would try to | ||
453 | * acquire the struct mutex again. Obviously this is bad and so | ||
454 | * lockdep complains vehemently. | ||
455 | */ | ||
456 | pagefault_disable(); | ||
445 | list_for_each_entry(obj, objects, exec_list) { | 457 | list_for_each_entry(obj, objects, exec_list) { |
446 | ret = i915_gem_execbuffer_relocate_object(obj, eb); | 458 | ret = i915_gem_execbuffer_relocate_object(obj, eb); |
447 | if (ret) | 459 | if (ret) |
448 | return ret; | 460 | break; |
449 | } | 461 | } |
462 | pagefault_enable(); | ||
450 | 463 | ||
451 | return 0; | 464 | return ret; |
452 | } | 465 | } |
453 | 466 | ||
454 | static int | 467 | static int |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3106c0dc8389..432fc04c6bff 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -1516,9 +1516,10 @@ static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, | |||
1516 | 1516 | ||
1517 | reg = PIPECONF(pipe); | 1517 | reg = PIPECONF(pipe); |
1518 | val = I915_READ(reg); | 1518 | val = I915_READ(reg); |
1519 | val |= PIPECONF_ENABLE; | 1519 | if (val & PIPECONF_ENABLE) |
1520 | I915_WRITE(reg, val); | 1520 | return; |
1521 | POSTING_READ(reg); | 1521 | |
1522 | I915_WRITE(reg, val | PIPECONF_ENABLE); | ||
1522 | intel_wait_for_vblank(dev_priv->dev, pipe); | 1523 | intel_wait_for_vblank(dev_priv->dev, pipe); |
1523 | } | 1524 | } |
1524 | 1525 | ||
@@ -1552,9 +1553,10 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv, | |||
1552 | 1553 | ||
1553 | reg = PIPECONF(pipe); | 1554 | reg = PIPECONF(pipe); |
1554 | val = I915_READ(reg); | 1555 | val = I915_READ(reg); |
1555 | val &= ~PIPECONF_ENABLE; | 1556 | if ((val & PIPECONF_ENABLE) == 0) |
1556 | I915_WRITE(reg, val); | 1557 | return; |
1557 | POSTING_READ(reg); | 1558 | |
1559 | I915_WRITE(reg, val & ~PIPECONF_ENABLE); | ||
1558 | intel_wait_for_pipe_off(dev_priv->dev, pipe); | 1560 | intel_wait_for_pipe_off(dev_priv->dev, pipe); |
1559 | } | 1561 | } |
1560 | 1562 | ||
@@ -1577,9 +1579,10 @@ static void intel_enable_plane(struct drm_i915_private *dev_priv, | |||
1577 | 1579 | ||
1578 | reg = DSPCNTR(plane); | 1580 | reg = DSPCNTR(plane); |
1579 | val = I915_READ(reg); | 1581 | val = I915_READ(reg); |
1580 | val |= DISPLAY_PLANE_ENABLE; | 1582 | if (val & DISPLAY_PLANE_ENABLE) |
1581 | I915_WRITE(reg, val); | 1583 | return; |
1582 | POSTING_READ(reg); | 1584 | |
1585 | I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE); | ||
1583 | intel_wait_for_vblank(dev_priv->dev, pipe); | 1586 | intel_wait_for_vblank(dev_priv->dev, pipe); |
1584 | } | 1587 | } |
1585 | 1588 | ||
@@ -1610,9 +1613,10 @@ static void intel_disable_plane(struct drm_i915_private *dev_priv, | |||
1610 | 1613 | ||
1611 | reg = DSPCNTR(plane); | 1614 | reg = DSPCNTR(plane); |
1612 | val = I915_READ(reg); | 1615 | val = I915_READ(reg); |
1613 | val &= ~DISPLAY_PLANE_ENABLE; | 1616 | if ((val & DISPLAY_PLANE_ENABLE) == 0) |
1614 | I915_WRITE(reg, val); | 1617 | return; |
1615 | POSTING_READ(reg); | 1618 | |
1619 | I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE); | ||
1616 | intel_flush_display_plane(dev_priv, plane); | 1620 | intel_flush_display_plane(dev_priv, plane); |
1617 | intel_wait_for_vblank(dev_priv->dev, pipe); | 1621 | intel_wait_for_vblank(dev_priv->dev, pipe); |
1618 | } | 1622 | } |
@@ -1769,7 +1773,6 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) | |||
1769 | return; | 1773 | return; |
1770 | 1774 | ||
1771 | I915_WRITE(DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN); | 1775 | I915_WRITE(DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN); |
1772 | POSTING_READ(DPFC_CONTROL); | ||
1773 | intel_wait_for_vblank(dev, intel_crtc->pipe); | 1776 | intel_wait_for_vblank(dev, intel_crtc->pipe); |
1774 | } | 1777 | } |
1775 | 1778 | ||
@@ -1861,7 +1864,6 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) | |||
1861 | return; | 1864 | return; |
1862 | 1865 | ||
1863 | I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN); | 1866 | I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN); |
1864 | POSTING_READ(ILK_DPFC_CONTROL); | ||
1865 | intel_wait_for_vblank(dev, intel_crtc->pipe); | 1867 | intel_wait_for_vblank(dev, intel_crtc->pipe); |
1866 | } | 1868 | } |
1867 | 1869 | ||
@@ -3883,10 +3885,7 @@ static bool g4x_compute_srwm(struct drm_device *dev, | |||
3883 | display, cursor); | 3885 | display, cursor); |
3884 | } | 3886 | } |
3885 | 3887 | ||
3886 | static inline bool single_plane_enabled(unsigned int mask) | 3888 | #define single_plane_enabled(mask) is_power_of_2(mask) |
3887 | { | ||
3888 | return mask && (mask & -mask) == 0; | ||
3889 | } | ||
3890 | 3889 | ||
3891 | static void g4x_update_wm(struct drm_device *dev) | 3890 | static void g4x_update_wm(struct drm_device *dev) |
3892 | { | 3891 | { |
@@ -5777,7 +5776,6 @@ static void intel_increase_pllclock(struct drm_crtc *crtc) | |||
5777 | 5776 | ||
5778 | dpll &= ~DISPLAY_RATE_SELECT_FPA1; | 5777 | dpll &= ~DISPLAY_RATE_SELECT_FPA1; |
5779 | I915_WRITE(dpll_reg, dpll); | 5778 | I915_WRITE(dpll_reg, dpll); |
5780 | POSTING_READ(dpll_reg); | ||
5781 | intel_wait_for_vblank(dev, pipe); | 5779 | intel_wait_for_vblank(dev, pipe); |
5782 | 5780 | ||
5783 | dpll = I915_READ(dpll_reg); | 5781 | dpll = I915_READ(dpll_reg); |
@@ -5821,7 +5819,6 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc) | |||
5821 | 5819 | ||
5822 | dpll |= DISPLAY_RATE_SELECT_FPA1; | 5820 | dpll |= DISPLAY_RATE_SELECT_FPA1; |
5823 | I915_WRITE(dpll_reg, dpll); | 5821 | I915_WRITE(dpll_reg, dpll); |
5824 | dpll = I915_READ(dpll_reg); | ||
5825 | intel_wait_for_vblank(dev, pipe); | 5822 | intel_wait_for_vblank(dev, pipe); |
5826 | dpll = I915_READ(dpll_reg); | 5823 | dpll = I915_READ(dpll_reg); |
5827 | if (!(dpll & DISPLAY_RATE_SELECT_FPA1)) | 5824 | if (!(dpll & DISPLAY_RATE_SELECT_FPA1)) |
@@ -6933,7 +6930,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) | |||
6933 | DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); | 6930 | DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); |
6934 | if (pcu_mbox & (1<<31)) { /* OC supported */ | 6931 | if (pcu_mbox & (1<<31)) { /* OC supported */ |
6935 | max_freq = pcu_mbox & 0xff; | 6932 | max_freq = pcu_mbox & 0xff; |
6936 | DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 100); | 6933 | DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50); |
6937 | } | 6934 | } |
6938 | 6935 | ||
6939 | /* In units of 100MHz */ | 6936 | /* In units of 100MHz */ |
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index d29e33f815d7..0daefca5cbb8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
@@ -1957,9 +1957,9 @@ intel_dp_init(struct drm_device *dev, int output_reg) | |||
1957 | DP_NO_AUX_HANDSHAKE_LINK_TRAINING; | 1957 | DP_NO_AUX_HANDSHAKE_LINK_TRAINING; |
1958 | } else { | 1958 | } else { |
1959 | /* if this fails, presume the device is a ghost */ | 1959 | /* if this fails, presume the device is a ghost */ |
1960 | DRM_ERROR("failed to retrieve link info\n"); | 1960 | DRM_INFO("failed to retrieve link info, disabling eDP\n"); |
1961 | intel_dp_destroy(&intel_connector->base); | ||
1962 | intel_dp_encoder_destroy(&intel_dp->base.base); | 1961 | intel_dp_encoder_destroy(&intel_dp->base.base); |
1962 | intel_dp_destroy(&intel_connector->base); | ||
1963 | return; | 1963 | return; |
1964 | } | 1964 | } |
1965 | } | 1965 | } |
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 789c47801ba8..e9e6f71418a4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c | |||
@@ -65,62 +65,60 @@ render_ring_flush(struct intel_ring_buffer *ring, | |||
65 | u32 cmd; | 65 | u32 cmd; |
66 | int ret; | 66 | int ret; |
67 | 67 | ||
68 | if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) { | 68 | /* |
69 | * read/write caches: | ||
70 | * | ||
71 | * I915_GEM_DOMAIN_RENDER is always invalidated, but is | ||
72 | * only flushed if MI_NO_WRITE_FLUSH is unset. On 965, it is | ||
73 | * also flushed at 2d versus 3d pipeline switches. | ||
74 | * | ||
75 | * read-only caches: | ||
76 | * | ||
77 | * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if | ||
78 | * MI_READ_FLUSH is set, and is always flushed on 965. | ||
79 | * | ||
80 | * I915_GEM_DOMAIN_COMMAND may not exist? | ||
81 | * | ||
82 | * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is | ||
83 | * invalidated when MI_EXE_FLUSH is set. | ||
84 | * | ||
85 | * I915_GEM_DOMAIN_VERTEX, which exists on 965, is | ||
86 | * invalidated with every MI_FLUSH. | ||
87 | * | ||
88 | * TLBs: | ||
89 | * | ||
90 | * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND | ||
91 | * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and | ||
92 | * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER | ||
93 | * are flushed at any MI_FLUSH. | ||
94 | */ | ||
95 | |||
96 | cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; | ||
97 | if ((invalidate_domains|flush_domains) & | ||
98 | I915_GEM_DOMAIN_RENDER) | ||
99 | cmd &= ~MI_NO_WRITE_FLUSH; | ||
100 | if (INTEL_INFO(dev)->gen < 4) { | ||
69 | /* | 101 | /* |
70 | * read/write caches: | 102 | * On the 965, the sampler cache always gets flushed |
71 | * | 103 | * and this bit is reserved. |
72 | * I915_GEM_DOMAIN_RENDER is always invalidated, but is | ||
73 | * only flushed if MI_NO_WRITE_FLUSH is unset. On 965, it is | ||
74 | * also flushed at 2d versus 3d pipeline switches. | ||
75 | * | ||
76 | * read-only caches: | ||
77 | * | ||
78 | * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if | ||
79 | * MI_READ_FLUSH is set, and is always flushed on 965. | ||
80 | * | ||
81 | * I915_GEM_DOMAIN_COMMAND may not exist? | ||
82 | * | ||
83 | * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is | ||
84 | * invalidated when MI_EXE_FLUSH is set. | ||
85 | * | ||
86 | * I915_GEM_DOMAIN_VERTEX, which exists on 965, is | ||
87 | * invalidated with every MI_FLUSH. | ||
88 | * | ||
89 | * TLBs: | ||
90 | * | ||
91 | * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND | ||
92 | * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and | ||
93 | * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER | ||
94 | * are flushed at any MI_FLUSH. | ||
95 | */ | 104 | */ |
105 | if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER) | ||
106 | cmd |= MI_READ_FLUSH; | ||
107 | } | ||
108 | if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION) | ||
109 | cmd |= MI_EXE_FLUSH; | ||
96 | 110 | ||
97 | cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; | 111 | if (invalidate_domains & I915_GEM_DOMAIN_COMMAND && |
98 | if ((invalidate_domains|flush_domains) & | 112 | (IS_G4X(dev) || IS_GEN5(dev))) |
99 | I915_GEM_DOMAIN_RENDER) | 113 | cmd |= MI_INVALIDATE_ISP; |
100 | cmd &= ~MI_NO_WRITE_FLUSH; | ||
101 | if (INTEL_INFO(dev)->gen < 4) { | ||
102 | /* | ||
103 | * On the 965, the sampler cache always gets flushed | ||
104 | * and this bit is reserved. | ||
105 | */ | ||
106 | if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER) | ||
107 | cmd |= MI_READ_FLUSH; | ||
108 | } | ||
109 | if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION) | ||
110 | cmd |= MI_EXE_FLUSH; | ||
111 | |||
112 | if (invalidate_domains & I915_GEM_DOMAIN_COMMAND && | ||
113 | (IS_G4X(dev) || IS_GEN5(dev))) | ||
114 | cmd |= MI_INVALIDATE_ISP; | ||
115 | 114 | ||
116 | ret = intel_ring_begin(ring, 2); | 115 | ret = intel_ring_begin(ring, 2); |
117 | if (ret) | 116 | if (ret) |
118 | return ret; | 117 | return ret; |
119 | 118 | ||
120 | intel_ring_emit(ring, cmd); | 119 | intel_ring_emit(ring, cmd); |
121 | intel_ring_emit(ring, MI_NOOP); | 120 | intel_ring_emit(ring, MI_NOOP); |
122 | intel_ring_advance(ring); | 121 | intel_ring_advance(ring); |
123 | } | ||
124 | 122 | ||
125 | return 0; | 123 | return 0; |
126 | } | 124 | } |
@@ -568,9 +566,6 @@ bsd_ring_flush(struct intel_ring_buffer *ring, | |||
568 | { | 566 | { |
569 | int ret; | 567 | int ret; |
570 | 568 | ||
571 | if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0) | ||
572 | return 0; | ||
573 | |||
574 | ret = intel_ring_begin(ring, 2); | 569 | ret = intel_ring_begin(ring, 2); |
575 | if (ret) | 570 | if (ret) |
576 | return ret; | 571 | return ret; |
@@ -1056,9 +1051,6 @@ static int gen6_ring_flush(struct intel_ring_buffer *ring, | |||
1056 | uint32_t cmd; | 1051 | uint32_t cmd; |
1057 | int ret; | 1052 | int ret; |
1058 | 1053 | ||
1059 | if (((invalidate | flush) & I915_GEM_GPU_DOMAINS) == 0) | ||
1060 | return 0; | ||
1061 | |||
1062 | ret = intel_ring_begin(ring, 4); | 1054 | ret = intel_ring_begin(ring, 4); |
1063 | if (ret) | 1055 | if (ret) |
1064 | return ret; | 1056 | return ret; |
@@ -1230,9 +1222,6 @@ static int blt_ring_flush(struct intel_ring_buffer *ring, | |||
1230 | uint32_t cmd; | 1222 | uint32_t cmd; |
1231 | int ret; | 1223 | int ret; |
1232 | 1224 | ||
1233 | if (((invalidate | flush) & I915_GEM_DOMAIN_RENDER) == 0) | ||
1234 | return 0; | ||
1235 | |||
1236 | ret = blt_ring_begin(ring, 4); | 1225 | ret = blt_ring_begin(ring, 4); |
1237 | if (ret) | 1226 | if (ret) |
1238 | return ret; | 1227 | return ret; |
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 3cd3234ba0af..10e41af6b026 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c | |||
@@ -957,7 +957,11 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode | |||
957 | /* adjust pixel clock as needed */ | 957 | /* adjust pixel clock as needed */ |
958 | adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss); | 958 | adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss); |
959 | 959 | ||
960 | if (ASIC_IS_AVIVO(rdev)) | 960 | if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) |
961 | /* TV seems to prefer the legacy algo on some boards */ | ||
962 | radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, | ||
963 | &ref_div, &post_div); | ||
964 | else if (ASIC_IS_AVIVO(rdev)) | ||
961 | radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, | 965 | radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, |
962 | &ref_div, &post_div); | 966 | &ref_div, &post_div); |
963 | else | 967 | else |
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index cf7c8d5b4ec2..cf602e2d0718 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c | |||
@@ -448,7 +448,7 @@ static uint16_t combios_get_table_offset(struct drm_device *dev, | |||
448 | 448 | ||
449 | bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev) | 449 | bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev) |
450 | { | 450 | { |
451 | int edid_info; | 451 | int edid_info, size; |
452 | struct edid *edid; | 452 | struct edid *edid; |
453 | unsigned char *raw; | 453 | unsigned char *raw; |
454 | edid_info = combios_get_table_offset(rdev->ddev, COMBIOS_HARDCODED_EDID_TABLE); | 454 | edid_info = combios_get_table_offset(rdev->ddev, COMBIOS_HARDCODED_EDID_TABLE); |
@@ -456,11 +456,12 @@ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev) | |||
456 | return false; | 456 | return false; |
457 | 457 | ||
458 | raw = rdev->bios + edid_info; | 458 | raw = rdev->bios + edid_info; |
459 | edid = kmalloc(EDID_LENGTH * (raw[0x7e] + 1), GFP_KERNEL); | 459 | size = EDID_LENGTH * (raw[0x7e] + 1); |
460 | edid = kmalloc(size, GFP_KERNEL); | ||
460 | if (edid == NULL) | 461 | if (edid == NULL) |
461 | return false; | 462 | return false; |
462 | 463 | ||
463 | memcpy((unsigned char *)edid, raw, EDID_LENGTH * (raw[0x7e] + 1)); | 464 | memcpy((unsigned char *)edid, raw, size); |
464 | 465 | ||
465 | if (!drm_edid_is_valid(edid)) { | 466 | if (!drm_edid_is_valid(edid)) { |
466 | kfree(edid); | 467 | kfree(edid); |
@@ -468,6 +469,7 @@ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev) | |||
468 | } | 469 | } |
469 | 470 | ||
470 | rdev->mode_info.bios_hardcoded_edid = edid; | 471 | rdev->mode_info.bios_hardcoded_edid = edid; |
472 | rdev->mode_info.bios_hardcoded_edid_size = size; | ||
471 | return true; | 473 | return true; |
472 | } | 474 | } |
473 | 475 | ||
@@ -475,8 +477,17 @@ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev) | |||
475 | struct edid * | 477 | struct edid * |
476 | radeon_bios_get_hardcoded_edid(struct radeon_device *rdev) | 478 | radeon_bios_get_hardcoded_edid(struct radeon_device *rdev) |
477 | { | 479 | { |
478 | if (rdev->mode_info.bios_hardcoded_edid) | 480 | struct edid *edid; |
479 | return rdev->mode_info.bios_hardcoded_edid; | 481 | |
482 | if (rdev->mode_info.bios_hardcoded_edid) { | ||
483 | edid = kmalloc(rdev->mode_info.bios_hardcoded_edid_size, GFP_KERNEL); | ||
484 | if (edid) { | ||
485 | memcpy((unsigned char *)edid, | ||
486 | (unsigned char *)rdev->mode_info.bios_hardcoded_edid, | ||
487 | rdev->mode_info.bios_hardcoded_edid_size); | ||
488 | return edid; | ||
489 | } | ||
490 | } | ||
480 | return NULL; | 491 | return NULL; |
481 | } | 492 | } |
482 | 493 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 28c7961cd19b..2ef6d5135064 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c | |||
@@ -633,6 +633,8 @@ static int radeon_vga_mode_valid(struct drm_connector *connector, | |||
633 | static enum drm_connector_status | 633 | static enum drm_connector_status |
634 | radeon_vga_detect(struct drm_connector *connector, bool force) | 634 | radeon_vga_detect(struct drm_connector *connector, bool force) |
635 | { | 635 | { |
636 | struct drm_device *dev = connector->dev; | ||
637 | struct radeon_device *rdev = dev->dev_private; | ||
636 | struct radeon_connector *radeon_connector = to_radeon_connector(connector); | 638 | struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
637 | struct drm_encoder *encoder; | 639 | struct drm_encoder *encoder; |
638 | struct drm_encoder_helper_funcs *encoder_funcs; | 640 | struct drm_encoder_helper_funcs *encoder_funcs; |
@@ -683,6 +685,17 @@ radeon_vga_detect(struct drm_connector *connector, bool force) | |||
683 | 685 | ||
684 | if (ret == connector_status_connected) | 686 | if (ret == connector_status_connected) |
685 | ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true); | 687 | ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true); |
688 | |||
689 | /* RN50 and some RV100 asics in servers often have a hardcoded EDID in the | ||
690 | * vbios to deal with KVMs. If we have one and are not able to detect a monitor | ||
691 | * by other means, assume the CRT is connected and use that EDID. | ||
692 | */ | ||
693 | if ((!rdev->is_atom_bios) && | ||
694 | (ret == connector_status_disconnected) && | ||
695 | rdev->mode_info.bios_hardcoded_edid_size) { | ||
696 | ret = connector_status_connected; | ||
697 | } | ||
698 | |||
686 | radeon_connector_update_scratch_regs(connector, ret); | 699 | radeon_connector_update_scratch_regs(connector, ret); |
687 | return ret; | 700 | return ret; |
688 | } | 701 | } |
@@ -794,6 +807,8 @@ static int radeon_dvi_get_modes(struct drm_connector *connector) | |||
794 | static enum drm_connector_status | 807 | static enum drm_connector_status |
795 | radeon_dvi_detect(struct drm_connector *connector, bool force) | 808 | radeon_dvi_detect(struct drm_connector *connector, bool force) |
796 | { | 809 | { |
810 | struct drm_device *dev = connector->dev; | ||
811 | struct radeon_device *rdev = dev->dev_private; | ||
797 | struct radeon_connector *radeon_connector = to_radeon_connector(connector); | 812 | struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
798 | struct drm_encoder *encoder = NULL; | 813 | struct drm_encoder *encoder = NULL; |
799 | struct drm_encoder_helper_funcs *encoder_funcs; | 814 | struct drm_encoder_helper_funcs *encoder_funcs; |
@@ -833,8 +848,6 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) | |||
833 | * you don't really know what's connected to which port as both are digital. | 848 | * you don't really know what's connected to which port as both are digital. |
834 | */ | 849 | */ |
835 | if (radeon_connector->shared_ddc && (ret == connector_status_connected)) { | 850 | if (radeon_connector->shared_ddc && (ret == connector_status_connected)) { |
836 | struct drm_device *dev = connector->dev; | ||
837 | struct radeon_device *rdev = dev->dev_private; | ||
838 | struct drm_connector *list_connector; | 851 | struct drm_connector *list_connector; |
839 | struct radeon_connector *list_radeon_connector; | 852 | struct radeon_connector *list_radeon_connector; |
840 | list_for_each_entry(list_connector, &dev->mode_config.connector_list, head) { | 853 | list_for_each_entry(list_connector, &dev->mode_config.connector_list, head) { |
@@ -899,6 +912,19 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) | |||
899 | ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true); | 912 | ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true); |
900 | } | 913 | } |
901 | 914 | ||
915 | /* RN50 and some RV100 asics in servers often have a hardcoded EDID in the | ||
916 | * vbios to deal with KVMs. If we have one and are not able to detect a monitor | ||
917 | * by other means, assume the DFP is connected and use that EDID. In most | ||
918 | * cases the DVI port is actually a virtual KVM port connected to the service | ||
919 | * processor. | ||
920 | */ | ||
921 | if ((!rdev->is_atom_bios) && | ||
922 | (ret == connector_status_disconnected) && | ||
923 | rdev->mode_info.bios_hardcoded_edid_size) { | ||
924 | radeon_connector->use_digital = true; | ||
925 | ret = connector_status_connected; | ||
926 | } | ||
927 | |||
902 | out: | 928 | out: |
903 | /* updated in get modes as well since we need to know if it's analog or digital */ | 929 | /* updated in get modes as well since we need to know if it's analog or digital */ |
904 | radeon_connector_update_scratch_regs(connector, ret); | 930 | radeon_connector_update_scratch_regs(connector, ret); |
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index e4582814bb78..9c57538231d5 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
@@ -239,6 +239,7 @@ struct radeon_mode_info { | |||
239 | struct drm_property *underscan_vborder_property; | 239 | struct drm_property *underscan_vborder_property; |
240 | /* hardcoded DFP edid from BIOS */ | 240 | /* hardcoded DFP edid from BIOS */ |
241 | struct edid *bios_hardcoded_edid; | 241 | struct edid *bios_hardcoded_edid; |
242 | int bios_hardcoded_edid_size; | ||
242 | 243 | ||
243 | /* pointer to fbdev info structure */ | 244 | /* pointer to fbdev info structure */ |
244 | struct radeon_fbdev *rfbdev; | 245 | struct radeon_fbdev *rfbdev; |
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 2aed03bde4b2..08de669e025a 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c | |||
@@ -365,12 +365,14 @@ static ssize_t radeon_set_pm_profile(struct device *dev, | |||
365 | else if (strncmp("high", buf, strlen("high")) == 0) | 365 | else if (strncmp("high", buf, strlen("high")) == 0) |
366 | rdev->pm.profile = PM_PROFILE_HIGH; | 366 | rdev->pm.profile = PM_PROFILE_HIGH; |
367 | else { | 367 | else { |
368 | DRM_ERROR("invalid power profile!\n"); | 368 | count = -EINVAL; |
369 | goto fail; | 369 | goto fail; |
370 | } | 370 | } |
371 | radeon_pm_update_profile(rdev); | 371 | radeon_pm_update_profile(rdev); |
372 | radeon_pm_set_clocks(rdev); | 372 | radeon_pm_set_clocks(rdev); |
373 | } | 373 | } else |
374 | count = -EINVAL; | ||
375 | |||
374 | fail: | 376 | fail: |
375 | mutex_unlock(&rdev->pm.mutex); | 377 | mutex_unlock(&rdev->pm.mutex); |
376 | 378 | ||
@@ -413,7 +415,7 @@ static ssize_t radeon_set_pm_method(struct device *dev, | |||
413 | mutex_unlock(&rdev->pm.mutex); | 415 | mutex_unlock(&rdev->pm.mutex); |
414 | cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); | 416 | cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); |
415 | } else { | 417 | } else { |
416 | DRM_ERROR("invalid power method!\n"); | 418 | count = -EINVAL; |
417 | goto fail; | 419 | goto fail; |
418 | } | 420 | } |
419 | radeon_pm_compute_clocks(rdev); | 421 | radeon_pm_compute_clocks(rdev); |
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 81131eda5544..060ef6327876 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -315,11 +315,22 @@ config SENSORS_F71805F | |||
315 | will be called f71805f. | 315 | will be called f71805f. |
316 | 316 | ||
317 | config SENSORS_F71882FG | 317 | config SENSORS_F71882FG |
318 | tristate "Fintek F71858FG, F71862FG, F71882FG, F71889FG and F8000" | 318 | tristate "Fintek F71882FG and compatibles" |
319 | help | 319 | help |
320 | If you say yes here you get support for hardware monitoring | 320 | If you say yes here you get support for hardware monitoring |
321 | features of the Fintek F71858FG, F71862FG/71863FG, F71882FG/F71883FG, | 321 | features of many Fintek Super-I/O (LPC) chips. The currently |
322 | F71889FG and F8000 Super-I/O chips. | 322 | supported chips are: |
323 | F71808E | ||
324 | F71858FG | ||
325 | F71862FG | ||
326 | F71863FG | ||
327 | F71869F/E | ||
328 | F71882FG | ||
329 | F71883FG | ||
330 | F71889FG/ED/A | ||
331 | F8000 | ||
332 | F81801U | ||
333 | F81865F | ||
323 | 334 | ||
324 | This driver can also be built as a module. If so, the module | 335 | This driver can also be built as a module. If so, the module |
325 | will be called f71882fg. | 336 | will be called f71882fg. |
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index a4d430ee7e20..ca07a32447c2 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c | |||
@@ -54,7 +54,9 @@ | |||
54 | #define SIO_F71882_ID 0x0541 /* Chipset ID */ | 54 | #define SIO_F71882_ID 0x0541 /* Chipset ID */ |
55 | #define SIO_F71889_ID 0x0723 /* Chipset ID */ | 55 | #define SIO_F71889_ID 0x0723 /* Chipset ID */ |
56 | #define SIO_F71889E_ID 0x0909 /* Chipset ID */ | 56 | #define SIO_F71889E_ID 0x0909 /* Chipset ID */ |
57 | #define SIO_F71889A_ID 0x1005 /* Chipset ID */ | ||
57 | #define SIO_F8000_ID 0x0581 /* Chipset ID */ | 58 | #define SIO_F8000_ID 0x0581 /* Chipset ID */ |
59 | #define SIO_F81865_ID 0x0704 /* Chipset ID */ | ||
58 | 60 | ||
59 | #define REGION_LENGTH 8 | 61 | #define REGION_LENGTH 8 |
60 | #define ADDR_REG_OFFSET 5 | 62 | #define ADDR_REG_OFFSET 5 |
@@ -106,7 +108,7 @@ module_param(force_id, ushort, 0); | |||
106 | MODULE_PARM_DESC(force_id, "Override the detected device ID"); | 108 | MODULE_PARM_DESC(force_id, "Override the detected device ID"); |
107 | 109 | ||
108 | enum chips { f71808e, f71858fg, f71862fg, f71869, f71882fg, f71889fg, | 110 | enum chips { f71808e, f71858fg, f71862fg, f71869, f71882fg, f71889fg, |
109 | f71889ed, f8000 }; | 111 | f71889ed, f71889a, f8000, f81865f }; |
110 | 112 | ||
111 | static const char *f71882fg_names[] = { | 113 | static const char *f71882fg_names[] = { |
112 | "f71808e", | 114 | "f71808e", |
@@ -114,42 +116,76 @@ static const char *f71882fg_names[] = { | |||
114 | "f71862fg", | 116 | "f71862fg", |
115 | "f71869", /* Both f71869f and f71869e, reg. compatible and same id */ | 117 | "f71869", /* Both f71869f and f71869e, reg. compatible and same id */ |
116 | "f71882fg", | 118 | "f71882fg", |
117 | "f71889fg", | 119 | "f71889fg", /* f81801u too, same id */ |
118 | "f71889ed", | 120 | "f71889ed", |
121 | "f71889a", | ||
119 | "f8000", | 122 | "f8000", |
123 | "f81865f", | ||
120 | }; | 124 | }; |
121 | 125 | ||
122 | static const char f71882fg_has_in[8][F71882FG_MAX_INS] = { | 126 | static const char f71882fg_has_in[][F71882FG_MAX_INS] = { |
123 | { 1, 1, 1, 1, 1, 1, 0, 1, 1 }, /* f71808e */ | 127 | [f71808e] = { 1, 1, 1, 1, 1, 1, 0, 1, 1 }, |
124 | { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, /* f71858fg */ | 128 | [f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, |
125 | { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71862fg */ | 129 | [f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, |
126 | { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71869 */ | 130 | [f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, |
127 | { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71882fg */ | 131 | [f71882fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, |
128 | { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71889fg */ | 132 | [f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, |
129 | { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71889ed */ | 133 | [f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, |
130 | { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, /* f8000 */ | 134 | [f71889a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, |
135 | [f8000] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, | ||
136 | [f81865f] = { 1, 1, 1, 1, 1, 1, 1, 0, 0 }, | ||
131 | }; | 137 | }; |
132 | 138 | ||
133 | static const char f71882fg_has_in1_alarm[8] = { | 139 | static const char f71882fg_has_in1_alarm[] = { |
134 | 0, /* f71808e */ | 140 | [f71808e] = 0, |
135 | 0, /* f71858fg */ | 141 | [f71858fg] = 0, |
136 | 0, /* f71862fg */ | 142 | [f71862fg] = 0, |
137 | 0, /* f71869 */ | 143 | [f71869] = 0, |
138 | 1, /* f71882fg */ | 144 | [f71882fg] = 1, |
139 | 1, /* f71889fg */ | 145 | [f71889fg] = 1, |
140 | 1, /* f71889ed */ | 146 | [f71889ed] = 1, |
141 | 0, /* f8000 */ | 147 | [f71889a] = 1, |
148 | [f8000] = 0, | ||
149 | [f81865f] = 1, | ||
142 | }; | 150 | }; |
143 | 151 | ||
144 | static const char f71882fg_has_beep[8] = { | 152 | static const char f71882fg_has_beep[] = { |
145 | 0, /* f71808e */ | 153 | [f71808e] = 0, |
146 | 0, /* f71858fg */ | 154 | [f71858fg] = 0, |
147 | 1, /* f71862fg */ | 155 | [f71862fg] = 1, |
148 | 1, /* f71869 */ | 156 | [f71869] = 1, |
149 | 1, /* f71882fg */ | 157 | [f71882fg] = 1, |
150 | 1, /* f71889fg */ | 158 | [f71889fg] = 1, |
151 | 1, /* f71889ed */ | 159 | [f71889ed] = 1, |
152 | 0, /* f8000 */ | 160 | [f71889a] = 1, |
161 | [f8000] = 0, | ||
162 | [f81865f] = 1, | ||
163 | }; | ||
164 | |||
165 | static const char f71882fg_nr_fans[] = { | ||
166 | [f71808e] = 3, | ||
167 | [f71858fg] = 3, | ||
168 | [f71862fg] = 3, | ||
169 | [f71869] = 3, | ||
170 | [f71882fg] = 4, | ||
171 | [f71889fg] = 3, | ||
172 | [f71889ed] = 3, | ||
173 | [f71889a] = 3, | ||
174 | [f8000] = 3, | ||
175 | [f81865f] = 2, | ||
176 | }; | ||
177 | |||
178 | static const char f71882fg_nr_temps[] = { | ||
179 | [f71808e] = 2, | ||
180 | [f71858fg] = 3, | ||
181 | [f71862fg] = 3, | ||
182 | [f71869] = 3, | ||
183 | [f71882fg] = 3, | ||
184 | [f71889fg] = 3, | ||
185 | [f71889ed] = 3, | ||
186 | [f71889a] = 3, | ||
187 | [f8000] = 3, | ||
188 | [f81865f] = 2, | ||
153 | }; | 189 | }; |
154 | 190 | ||
155 | static struct platform_device *f71882fg_pdev; | 191 | static struct platform_device *f71882fg_pdev; |
@@ -1071,9 +1107,9 @@ static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr) | |||
1071 | static struct f71882fg_data *f71882fg_update_device(struct device *dev) | 1107 | static struct f71882fg_data *f71882fg_update_device(struct device *dev) |
1072 | { | 1108 | { |
1073 | struct f71882fg_data *data = dev_get_drvdata(dev); | 1109 | struct f71882fg_data *data = dev_get_drvdata(dev); |
1110 | int nr_fans = f71882fg_nr_fans[data->type]; | ||
1111 | int nr_temps = f71882fg_nr_temps[data->type]; | ||
1074 | int nr, reg, point; | 1112 | int nr, reg, point; |
1075 | int nr_fans = (data->type == f71882fg) ? 4 : 3; | ||
1076 | int nr_temps = (data->type == f71808e) ? 2 : 3; | ||
1077 | 1113 | ||
1078 | mutex_lock(&data->update_lock); | 1114 | mutex_lock(&data->update_lock); |
1079 | 1115 | ||
@@ -2042,8 +2078,9 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) | |||
2042 | { | 2078 | { |
2043 | struct f71882fg_data *data; | 2079 | struct f71882fg_data *data; |
2044 | struct f71882fg_sio_data *sio_data = pdev->dev.platform_data; | 2080 | struct f71882fg_sio_data *sio_data = pdev->dev.platform_data; |
2045 | int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3; | 2081 | int nr_fans = f71882fg_nr_fans[sio_data->type]; |
2046 | int nr_temps = (sio_data->type == f71808e) ? 2 : 3; | 2082 | int nr_temps = f71882fg_nr_temps[sio_data->type]; |
2083 | int err, i; | ||
2047 | u8 start_reg, reg; | 2084 | u8 start_reg, reg; |
2048 | 2085 | ||
2049 | data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL); | 2086 | data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL); |
@@ -2138,6 +2175,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) | |||
2138 | /* Fall through to select correct fan/pwm reg bank! */ | 2175 | /* Fall through to select correct fan/pwm reg bank! */ |
2139 | case f71889fg: | 2176 | case f71889fg: |
2140 | case f71889ed: | 2177 | case f71889ed: |
2178 | case f71889a: | ||
2141 | reg = f71882fg_read8(data, F71882FG_REG_FAN_FAULT_T); | 2179 | reg = f71882fg_read8(data, F71882FG_REG_FAN_FAULT_T); |
2142 | if (reg & F71882FG_FAN_NEG_TEMP_EN) | 2180 | if (reg & F71882FG_FAN_NEG_TEMP_EN) |
2143 | data->auto_point_temp_signed = 1; | 2181 | data->auto_point_temp_signed = 1; |
@@ -2163,16 +2201,12 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) | |||
2163 | case f71862fg: | 2201 | case f71862fg: |
2164 | err = (data->pwm_enable & 0x15) != 0x15; | 2202 | err = (data->pwm_enable & 0x15) != 0x15; |
2165 | break; | 2203 | break; |
2166 | case f71808e: | ||
2167 | case f71869: | ||
2168 | case f71882fg: | ||
2169 | case f71889fg: | ||
2170 | case f71889ed: | ||
2171 | err = 0; | ||
2172 | break; | ||
2173 | case f8000: | 2204 | case f8000: |
2174 | err = data->pwm_enable & 0x20; | 2205 | err = data->pwm_enable & 0x20; |
2175 | break; | 2206 | break; |
2207 | default: | ||
2208 | err = 0; | ||
2209 | break; | ||
2176 | } | 2210 | } |
2177 | if (err) { | 2211 | if (err) { |
2178 | dev_err(&pdev->dev, | 2212 | dev_err(&pdev->dev, |
@@ -2199,6 +2233,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) | |||
2199 | case f71869: | 2233 | case f71869: |
2200 | case f71889fg: | 2234 | case f71889fg: |
2201 | case f71889ed: | 2235 | case f71889ed: |
2236 | case f71889a: | ||
2202 | for (i = 0; i < nr_fans; i++) { | 2237 | for (i = 0; i < nr_fans; i++) { |
2203 | data->pwm_auto_point_mapping[i] = | 2238 | data->pwm_auto_point_mapping[i] = |
2204 | f71882fg_read8(data, | 2239 | f71882fg_read8(data, |
@@ -2276,8 +2311,9 @@ exit_free: | |||
2276 | static int f71882fg_remove(struct platform_device *pdev) | 2311 | static int f71882fg_remove(struct platform_device *pdev) |
2277 | { | 2312 | { |
2278 | struct f71882fg_data *data = platform_get_drvdata(pdev); | 2313 | struct f71882fg_data *data = platform_get_drvdata(pdev); |
2279 | int i, nr_fans = (data->type == f71882fg) ? 4 : 3; | 2314 | int nr_fans = f71882fg_nr_fans[data->type]; |
2280 | int nr_temps = (data->type == f71808e) ? 2 : 3; | 2315 | int nr_temps = f71882fg_nr_temps[data->type]; |
2316 | int i; | ||
2281 | u8 start_reg = f71882fg_read8(data, F71882FG_REG_START); | 2317 | u8 start_reg = f71882fg_read8(data, F71882FG_REG_START); |
2282 | 2318 | ||
2283 | if (data->hwmon_dev) | 2319 | if (data->hwmon_dev) |
@@ -2406,9 +2442,15 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, | |||
2406 | case SIO_F71889E_ID: | 2442 | case SIO_F71889E_ID: |
2407 | sio_data->type = f71889ed; | 2443 | sio_data->type = f71889ed; |
2408 | break; | 2444 | break; |
2445 | case SIO_F71889A_ID: | ||
2446 | sio_data->type = f71889a; | ||
2447 | break; | ||
2409 | case SIO_F8000_ID: | 2448 | case SIO_F8000_ID: |
2410 | sio_data->type = f8000; | 2449 | sio_data->type = f8000; |
2411 | break; | 2450 | break; |
2451 | case SIO_F81865_ID: | ||
2452 | sio_data->type = f81865f; | ||
2453 | break; | ||
2412 | default: | 2454 | default: |
2413 | pr_info("Unsupported Fintek device: %04x\n", | 2455 | pr_info("Unsupported Fintek device: %04x\n", |
2414 | (unsigned int)devid); | 2456 | (unsigned int)devid); |
diff --git a/drivers/hwmon/pmbus_core.c b/drivers/hwmon/pmbus_core.c index 6474512f49b0..edfb92e41735 100644 --- a/drivers/hwmon/pmbus_core.c +++ b/drivers/hwmon/pmbus_core.c | |||
@@ -752,7 +752,7 @@ static void pmbus_add_boolean_cmp(struct pmbus_data *data, | |||
752 | static void pmbus_add_sensor(struct pmbus_data *data, | 752 | static void pmbus_add_sensor(struct pmbus_data *data, |
753 | const char *name, const char *type, int seq, | 753 | const char *name, const char *type, int seq, |
754 | int page, int reg, enum pmbus_sensor_classes class, | 754 | int page, int reg, enum pmbus_sensor_classes class, |
755 | bool update) | 755 | bool update, bool readonly) |
756 | { | 756 | { |
757 | struct pmbus_sensor *sensor; | 757 | struct pmbus_sensor *sensor; |
758 | 758 | ||
@@ -765,7 +765,7 @@ static void pmbus_add_sensor(struct pmbus_data *data, | |||
765 | sensor->reg = reg; | 765 | sensor->reg = reg; |
766 | sensor->class = class; | 766 | sensor->class = class; |
767 | sensor->update = update; | 767 | sensor->update = update; |
768 | if (update) | 768 | if (readonly) |
769 | PMBUS_ADD_GET_ATTR(data, sensor->name, sensor, | 769 | PMBUS_ADD_GET_ATTR(data, sensor->name, sensor, |
770 | data->num_sensors); | 770 | data->num_sensors); |
771 | else | 771 | else |
@@ -916,14 +916,14 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
916 | 916 | ||
917 | i0 = data->num_sensors; | 917 | i0 = data->num_sensors; |
918 | pmbus_add_label(data, "in", in_index, "vin", 0); | 918 | pmbus_add_label(data, "in", in_index, "vin", 0); |
919 | pmbus_add_sensor(data, "in", "input", in_index, | 919 | pmbus_add_sensor(data, "in", "input", in_index, 0, |
920 | 0, PMBUS_READ_VIN, PSC_VOLTAGE_IN, true); | 920 | PMBUS_READ_VIN, PSC_VOLTAGE_IN, true, true); |
921 | if (pmbus_check_word_register(client, 0, | 921 | if (pmbus_check_word_register(client, 0, |
922 | PMBUS_VIN_UV_WARN_LIMIT)) { | 922 | PMBUS_VIN_UV_WARN_LIMIT)) { |
923 | i1 = data->num_sensors; | 923 | i1 = data->num_sensors; |
924 | pmbus_add_sensor(data, "in", "min", in_index, | 924 | pmbus_add_sensor(data, "in", "min", in_index, |
925 | 0, PMBUS_VIN_UV_WARN_LIMIT, | 925 | 0, PMBUS_VIN_UV_WARN_LIMIT, |
926 | PSC_VOLTAGE_IN, false); | 926 | PSC_VOLTAGE_IN, false, false); |
927 | if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) { | 927 | if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) { |
928 | pmbus_add_boolean_reg(data, "in", "min_alarm", | 928 | pmbus_add_boolean_reg(data, "in", "min_alarm", |
929 | in_index, | 929 | in_index, |
@@ -937,7 +937,7 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
937 | i1 = data->num_sensors; | 937 | i1 = data->num_sensors; |
938 | pmbus_add_sensor(data, "in", "lcrit", in_index, | 938 | pmbus_add_sensor(data, "in", "lcrit", in_index, |
939 | 0, PMBUS_VIN_UV_FAULT_LIMIT, | 939 | 0, PMBUS_VIN_UV_FAULT_LIMIT, |
940 | PSC_VOLTAGE_IN, false); | 940 | PSC_VOLTAGE_IN, false, false); |
941 | if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) { | 941 | if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) { |
942 | pmbus_add_boolean_reg(data, "in", "lcrit_alarm", | 942 | pmbus_add_boolean_reg(data, "in", "lcrit_alarm", |
943 | in_index, | 943 | in_index, |
@@ -951,7 +951,7 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
951 | i1 = data->num_sensors; | 951 | i1 = data->num_sensors; |
952 | pmbus_add_sensor(data, "in", "max", in_index, | 952 | pmbus_add_sensor(data, "in", "max", in_index, |
953 | 0, PMBUS_VIN_OV_WARN_LIMIT, | 953 | 0, PMBUS_VIN_OV_WARN_LIMIT, |
954 | PSC_VOLTAGE_IN, false); | 954 | PSC_VOLTAGE_IN, false, false); |
955 | if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) { | 955 | if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) { |
956 | pmbus_add_boolean_reg(data, "in", "max_alarm", | 956 | pmbus_add_boolean_reg(data, "in", "max_alarm", |
957 | in_index, | 957 | in_index, |
@@ -965,7 +965,7 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
965 | i1 = data->num_sensors; | 965 | i1 = data->num_sensors; |
966 | pmbus_add_sensor(data, "in", "crit", in_index, | 966 | pmbus_add_sensor(data, "in", "crit", in_index, |
967 | 0, PMBUS_VIN_OV_FAULT_LIMIT, | 967 | 0, PMBUS_VIN_OV_FAULT_LIMIT, |
968 | PSC_VOLTAGE_IN, false); | 968 | PSC_VOLTAGE_IN, false, false); |
969 | if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) { | 969 | if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) { |
970 | pmbus_add_boolean_reg(data, "in", "crit_alarm", | 970 | pmbus_add_boolean_reg(data, "in", "crit_alarm", |
971 | in_index, | 971 | in_index, |
@@ -988,7 +988,7 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
988 | if (info->func[0] & PMBUS_HAVE_VCAP) { | 988 | if (info->func[0] & PMBUS_HAVE_VCAP) { |
989 | pmbus_add_label(data, "in", in_index, "vcap", 0); | 989 | pmbus_add_label(data, "in", in_index, "vcap", 0); |
990 | pmbus_add_sensor(data, "in", "input", in_index, 0, | 990 | pmbus_add_sensor(data, "in", "input", in_index, 0, |
991 | PMBUS_READ_VCAP, PSC_VOLTAGE_IN, true); | 991 | PMBUS_READ_VCAP, PSC_VOLTAGE_IN, true, true); |
992 | in_index++; | 992 | in_index++; |
993 | } | 993 | } |
994 | 994 | ||
@@ -1004,13 +1004,13 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1004 | i0 = data->num_sensors; | 1004 | i0 = data->num_sensors; |
1005 | pmbus_add_label(data, "in", in_index, "vout", page + 1); | 1005 | pmbus_add_label(data, "in", in_index, "vout", page + 1); |
1006 | pmbus_add_sensor(data, "in", "input", in_index, page, | 1006 | pmbus_add_sensor(data, "in", "input", in_index, page, |
1007 | PMBUS_READ_VOUT, PSC_VOLTAGE_OUT, true); | 1007 | PMBUS_READ_VOUT, PSC_VOLTAGE_OUT, true, true); |
1008 | if (pmbus_check_word_register(client, page, | 1008 | if (pmbus_check_word_register(client, page, |
1009 | PMBUS_VOUT_UV_WARN_LIMIT)) { | 1009 | PMBUS_VOUT_UV_WARN_LIMIT)) { |
1010 | i1 = data->num_sensors; | 1010 | i1 = data->num_sensors; |
1011 | pmbus_add_sensor(data, "in", "min", in_index, page, | 1011 | pmbus_add_sensor(data, "in", "min", in_index, page, |
1012 | PMBUS_VOUT_UV_WARN_LIMIT, | 1012 | PMBUS_VOUT_UV_WARN_LIMIT, |
1013 | PSC_VOLTAGE_OUT, false); | 1013 | PSC_VOLTAGE_OUT, false, false); |
1014 | if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) { | 1014 | if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) { |
1015 | pmbus_add_boolean_reg(data, "in", "min_alarm", | 1015 | pmbus_add_boolean_reg(data, "in", "min_alarm", |
1016 | in_index, | 1016 | in_index, |
@@ -1025,7 +1025,7 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1025 | i1 = data->num_sensors; | 1025 | i1 = data->num_sensors; |
1026 | pmbus_add_sensor(data, "in", "lcrit", in_index, page, | 1026 | pmbus_add_sensor(data, "in", "lcrit", in_index, page, |
1027 | PMBUS_VOUT_UV_FAULT_LIMIT, | 1027 | PMBUS_VOUT_UV_FAULT_LIMIT, |
1028 | PSC_VOLTAGE_OUT, false); | 1028 | PSC_VOLTAGE_OUT, false, false); |
1029 | if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) { | 1029 | if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) { |
1030 | pmbus_add_boolean_reg(data, "in", "lcrit_alarm", | 1030 | pmbus_add_boolean_reg(data, "in", "lcrit_alarm", |
1031 | in_index, | 1031 | in_index, |
@@ -1040,7 +1040,7 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1040 | i1 = data->num_sensors; | 1040 | i1 = data->num_sensors; |
1041 | pmbus_add_sensor(data, "in", "max", in_index, page, | 1041 | pmbus_add_sensor(data, "in", "max", in_index, page, |
1042 | PMBUS_VOUT_OV_WARN_LIMIT, | 1042 | PMBUS_VOUT_OV_WARN_LIMIT, |
1043 | PSC_VOLTAGE_OUT, false); | 1043 | PSC_VOLTAGE_OUT, false, false); |
1044 | if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) { | 1044 | if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) { |
1045 | pmbus_add_boolean_reg(data, "in", "max_alarm", | 1045 | pmbus_add_boolean_reg(data, "in", "max_alarm", |
1046 | in_index, | 1046 | in_index, |
@@ -1055,7 +1055,7 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1055 | i1 = data->num_sensors; | 1055 | i1 = data->num_sensors; |
1056 | pmbus_add_sensor(data, "in", "crit", in_index, page, | 1056 | pmbus_add_sensor(data, "in", "crit", in_index, page, |
1057 | PMBUS_VOUT_OV_FAULT_LIMIT, | 1057 | PMBUS_VOUT_OV_FAULT_LIMIT, |
1058 | PSC_VOLTAGE_OUT, false); | 1058 | PSC_VOLTAGE_OUT, false, false); |
1059 | if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) { | 1059 | if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) { |
1060 | pmbus_add_boolean_reg(data, "in", "crit_alarm", | 1060 | pmbus_add_boolean_reg(data, "in", "crit_alarm", |
1061 | in_index, | 1061 | in_index, |
@@ -1088,14 +1088,14 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1088 | if (info->func[0] & PMBUS_HAVE_IIN) { | 1088 | if (info->func[0] & PMBUS_HAVE_IIN) { |
1089 | i0 = data->num_sensors; | 1089 | i0 = data->num_sensors; |
1090 | pmbus_add_label(data, "curr", in_index, "iin", 0); | 1090 | pmbus_add_label(data, "curr", in_index, "iin", 0); |
1091 | pmbus_add_sensor(data, "curr", "input", in_index, | 1091 | pmbus_add_sensor(data, "curr", "input", in_index, 0, |
1092 | 0, PMBUS_READ_IIN, PSC_CURRENT_IN, true); | 1092 | PMBUS_READ_IIN, PSC_CURRENT_IN, true, true); |
1093 | if (pmbus_check_word_register(client, 0, | 1093 | if (pmbus_check_word_register(client, 0, |
1094 | PMBUS_IIN_OC_WARN_LIMIT)) { | 1094 | PMBUS_IIN_OC_WARN_LIMIT)) { |
1095 | i1 = data->num_sensors; | 1095 | i1 = data->num_sensors; |
1096 | pmbus_add_sensor(data, "curr", "max", in_index, | 1096 | pmbus_add_sensor(data, "curr", "max", in_index, |
1097 | 0, PMBUS_IIN_OC_WARN_LIMIT, | 1097 | 0, PMBUS_IIN_OC_WARN_LIMIT, |
1098 | PSC_CURRENT_IN, false); | 1098 | PSC_CURRENT_IN, false, false); |
1099 | if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) { | 1099 | if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) { |
1100 | pmbus_add_boolean_reg(data, "curr", "max_alarm", | 1100 | pmbus_add_boolean_reg(data, "curr", "max_alarm", |
1101 | in_index, | 1101 | in_index, |
@@ -1108,7 +1108,7 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1108 | i1 = data->num_sensors; | 1108 | i1 = data->num_sensors; |
1109 | pmbus_add_sensor(data, "curr", "crit", in_index, | 1109 | pmbus_add_sensor(data, "curr", "crit", in_index, |
1110 | 0, PMBUS_IIN_OC_FAULT_LIMIT, | 1110 | 0, PMBUS_IIN_OC_FAULT_LIMIT, |
1111 | PSC_CURRENT_IN, false); | 1111 | PSC_CURRENT_IN, false, false); |
1112 | if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) | 1112 | if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) |
1113 | pmbus_add_boolean_reg(data, "curr", | 1113 | pmbus_add_boolean_reg(data, "curr", |
1114 | "crit_alarm", | 1114 | "crit_alarm", |
@@ -1131,13 +1131,13 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1131 | i0 = data->num_sensors; | 1131 | i0 = data->num_sensors; |
1132 | pmbus_add_label(data, "curr", in_index, "iout", page + 1); | 1132 | pmbus_add_label(data, "curr", in_index, "iout", page + 1); |
1133 | pmbus_add_sensor(data, "curr", "input", in_index, page, | 1133 | pmbus_add_sensor(data, "curr", "input", in_index, page, |
1134 | PMBUS_READ_IOUT, PSC_CURRENT_OUT, true); | 1134 | PMBUS_READ_IOUT, PSC_CURRENT_OUT, true, true); |
1135 | if (pmbus_check_word_register(client, page, | 1135 | if (pmbus_check_word_register(client, page, |
1136 | PMBUS_IOUT_OC_WARN_LIMIT)) { | 1136 | PMBUS_IOUT_OC_WARN_LIMIT)) { |
1137 | i1 = data->num_sensors; | 1137 | i1 = data->num_sensors; |
1138 | pmbus_add_sensor(data, "curr", "max", in_index, page, | 1138 | pmbus_add_sensor(data, "curr", "max", in_index, page, |
1139 | PMBUS_IOUT_OC_WARN_LIMIT, | 1139 | PMBUS_IOUT_OC_WARN_LIMIT, |
1140 | PSC_CURRENT_OUT, false); | 1140 | PSC_CURRENT_OUT, false, false); |
1141 | if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) { | 1141 | if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) { |
1142 | pmbus_add_boolean_reg(data, "curr", "max_alarm", | 1142 | pmbus_add_boolean_reg(data, "curr", "max_alarm", |
1143 | in_index, | 1143 | in_index, |
@@ -1151,7 +1151,7 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1151 | i1 = data->num_sensors; | 1151 | i1 = data->num_sensors; |
1152 | pmbus_add_sensor(data, "curr", "lcrit", in_index, page, | 1152 | pmbus_add_sensor(data, "curr", "lcrit", in_index, page, |
1153 | PMBUS_IOUT_UC_FAULT_LIMIT, | 1153 | PMBUS_IOUT_UC_FAULT_LIMIT, |
1154 | PSC_CURRENT_OUT, false); | 1154 | PSC_CURRENT_OUT, false, false); |
1155 | if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) { | 1155 | if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) { |
1156 | pmbus_add_boolean_reg(data, "curr", | 1156 | pmbus_add_boolean_reg(data, "curr", |
1157 | "lcrit_alarm", | 1157 | "lcrit_alarm", |
@@ -1166,7 +1166,7 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1166 | i1 = data->num_sensors; | 1166 | i1 = data->num_sensors; |
1167 | pmbus_add_sensor(data, "curr", "crit", in_index, page, | 1167 | pmbus_add_sensor(data, "curr", "crit", in_index, page, |
1168 | PMBUS_IOUT_OC_FAULT_LIMIT, | 1168 | PMBUS_IOUT_OC_FAULT_LIMIT, |
1169 | PSC_CURRENT_OUT, false); | 1169 | PSC_CURRENT_OUT, false, false); |
1170 | if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) { | 1170 | if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) { |
1171 | pmbus_add_boolean_reg(data, "curr", | 1171 | pmbus_add_boolean_reg(data, "curr", |
1172 | "crit_alarm", | 1172 | "crit_alarm", |
@@ -1199,13 +1199,13 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1199 | i0 = data->num_sensors; | 1199 | i0 = data->num_sensors; |
1200 | pmbus_add_label(data, "power", in_index, "pin", 0); | 1200 | pmbus_add_label(data, "power", in_index, "pin", 0); |
1201 | pmbus_add_sensor(data, "power", "input", in_index, | 1201 | pmbus_add_sensor(data, "power", "input", in_index, |
1202 | 0, PMBUS_READ_PIN, PSC_POWER, true); | 1202 | 0, PMBUS_READ_PIN, PSC_POWER, true, true); |
1203 | if (pmbus_check_word_register(client, 0, | 1203 | if (pmbus_check_word_register(client, 0, |
1204 | PMBUS_PIN_OP_WARN_LIMIT)) { | 1204 | PMBUS_PIN_OP_WARN_LIMIT)) { |
1205 | i1 = data->num_sensors; | 1205 | i1 = data->num_sensors; |
1206 | pmbus_add_sensor(data, "power", "max", in_index, | 1206 | pmbus_add_sensor(data, "power", "max", in_index, |
1207 | 0, PMBUS_PIN_OP_WARN_LIMIT, PSC_POWER, | 1207 | 0, PMBUS_PIN_OP_WARN_LIMIT, PSC_POWER, |
1208 | false); | 1208 | false, false); |
1209 | if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) | 1209 | if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) |
1210 | pmbus_add_boolean_reg(data, "power", | 1210 | pmbus_add_boolean_reg(data, "power", |
1211 | "alarm", | 1211 | "alarm", |
@@ -1228,7 +1228,7 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1228 | i0 = data->num_sensors; | 1228 | i0 = data->num_sensors; |
1229 | pmbus_add_label(data, "power", in_index, "pout", page + 1); | 1229 | pmbus_add_label(data, "power", in_index, "pout", page + 1); |
1230 | pmbus_add_sensor(data, "power", "input", in_index, page, | 1230 | pmbus_add_sensor(data, "power", "input", in_index, page, |
1231 | PMBUS_READ_POUT, PSC_POWER, true); | 1231 | PMBUS_READ_POUT, PSC_POWER, true, true); |
1232 | /* | 1232 | /* |
1233 | * Per hwmon sysfs API, power_cap is to be used to limit output | 1233 | * Per hwmon sysfs API, power_cap is to be used to limit output |
1234 | * power. | 1234 | * power. |
@@ -1241,7 +1241,8 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1241 | if (pmbus_check_word_register(client, page, PMBUS_POUT_MAX)) { | 1241 | if (pmbus_check_word_register(client, page, PMBUS_POUT_MAX)) { |
1242 | i1 = data->num_sensors; | 1242 | i1 = data->num_sensors; |
1243 | pmbus_add_sensor(data, "power", "cap", in_index, page, | 1243 | pmbus_add_sensor(data, "power", "cap", in_index, page, |
1244 | PMBUS_POUT_MAX, PSC_POWER, false); | 1244 | PMBUS_POUT_MAX, PSC_POWER, |
1245 | false, false); | ||
1245 | need_alarm = true; | 1246 | need_alarm = true; |
1246 | } | 1247 | } |
1247 | if (pmbus_check_word_register(client, page, | 1248 | if (pmbus_check_word_register(client, page, |
@@ -1249,7 +1250,7 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1249 | i1 = data->num_sensors; | 1250 | i1 = data->num_sensors; |
1250 | pmbus_add_sensor(data, "power", "max", in_index, page, | 1251 | pmbus_add_sensor(data, "power", "max", in_index, page, |
1251 | PMBUS_POUT_OP_WARN_LIMIT, PSC_POWER, | 1252 | PMBUS_POUT_OP_WARN_LIMIT, PSC_POWER, |
1252 | false); | 1253 | false, false); |
1253 | need_alarm = true; | 1254 | need_alarm = true; |
1254 | } | 1255 | } |
1255 | if (need_alarm && (info->func[page] & PMBUS_HAVE_STATUS_IOUT)) | 1256 | if (need_alarm && (info->func[page] & PMBUS_HAVE_STATUS_IOUT)) |
@@ -1264,7 +1265,7 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1264 | i1 = data->num_sensors; | 1265 | i1 = data->num_sensors; |
1265 | pmbus_add_sensor(data, "power", "crit", in_index, page, | 1266 | pmbus_add_sensor(data, "power", "crit", in_index, page, |
1266 | PMBUS_POUT_OP_FAULT_LIMIT, PSC_POWER, | 1267 | PMBUS_POUT_OP_FAULT_LIMIT, PSC_POWER, |
1267 | false); | 1268 | false, false); |
1268 | if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) | 1269 | if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) |
1269 | pmbus_add_boolean_reg(data, "power", | 1270 | pmbus_add_boolean_reg(data, "power", |
1270 | "crit_alarm", | 1271 | "crit_alarm", |
@@ -1302,7 +1303,7 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1302 | i0 = data->num_sensors; | 1303 | i0 = data->num_sensors; |
1303 | pmbus_add_sensor(data, "temp", "input", in_index, page, | 1304 | pmbus_add_sensor(data, "temp", "input", in_index, page, |
1304 | pmbus_temp_registers[t], | 1305 | pmbus_temp_registers[t], |
1305 | PSC_TEMPERATURE, true); | 1306 | PSC_TEMPERATURE, true, true); |
1306 | 1307 | ||
1307 | /* | 1308 | /* |
1308 | * PMBus provides only one status register for TEMP1-3. | 1309 | * PMBus provides only one status register for TEMP1-3. |
@@ -1323,7 +1324,7 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1323 | i1 = data->num_sensors; | 1324 | i1 = data->num_sensors; |
1324 | pmbus_add_sensor(data, "temp", "min", in_index, | 1325 | pmbus_add_sensor(data, "temp", "min", in_index, |
1325 | page, PMBUS_UT_WARN_LIMIT, | 1326 | page, PMBUS_UT_WARN_LIMIT, |
1326 | PSC_TEMPERATURE, true); | 1327 | PSC_TEMPERATURE, true, false); |
1327 | if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) { | 1328 | if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) { |
1328 | pmbus_add_boolean_cmp(data, "temp", | 1329 | pmbus_add_boolean_cmp(data, "temp", |
1329 | "min_alarm", in_index, i1, i0, | 1330 | "min_alarm", in_index, i1, i0, |
@@ -1338,7 +1339,7 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1338 | pmbus_add_sensor(data, "temp", "lcrit", | 1339 | pmbus_add_sensor(data, "temp", "lcrit", |
1339 | in_index, page, | 1340 | in_index, page, |
1340 | PMBUS_UT_FAULT_LIMIT, | 1341 | PMBUS_UT_FAULT_LIMIT, |
1341 | PSC_TEMPERATURE, true); | 1342 | PSC_TEMPERATURE, true, false); |
1342 | if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) { | 1343 | if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) { |
1343 | pmbus_add_boolean_cmp(data, "temp", | 1344 | pmbus_add_boolean_cmp(data, "temp", |
1344 | "lcrit_alarm", in_index, i1, i0, | 1345 | "lcrit_alarm", in_index, i1, i0, |
@@ -1352,7 +1353,7 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1352 | i1 = data->num_sensors; | 1353 | i1 = data->num_sensors; |
1353 | pmbus_add_sensor(data, "temp", "max", in_index, | 1354 | pmbus_add_sensor(data, "temp", "max", in_index, |
1354 | page, PMBUS_OT_WARN_LIMIT, | 1355 | page, PMBUS_OT_WARN_LIMIT, |
1355 | PSC_TEMPERATURE, true); | 1356 | PSC_TEMPERATURE, true, false); |
1356 | if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) { | 1357 | if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) { |
1357 | pmbus_add_boolean_cmp(data, "temp", | 1358 | pmbus_add_boolean_cmp(data, "temp", |
1358 | "max_alarm", in_index, i0, i1, | 1359 | "max_alarm", in_index, i0, i1, |
@@ -1366,7 +1367,7 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1366 | i1 = data->num_sensors; | 1367 | i1 = data->num_sensors; |
1367 | pmbus_add_sensor(data, "temp", "crit", in_index, | 1368 | pmbus_add_sensor(data, "temp", "crit", in_index, |
1368 | page, PMBUS_OT_FAULT_LIMIT, | 1369 | page, PMBUS_OT_FAULT_LIMIT, |
1369 | PSC_TEMPERATURE, true); | 1370 | PSC_TEMPERATURE, true, false); |
1370 | if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) { | 1371 | if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) { |
1371 | pmbus_add_boolean_cmp(data, "temp", | 1372 | pmbus_add_boolean_cmp(data, "temp", |
1372 | "crit_alarm", in_index, i0, i1, | 1373 | "crit_alarm", in_index, i0, i1, |
@@ -1421,7 +1422,8 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1421 | 1422 | ||
1422 | i0 = data->num_sensors; | 1423 | i0 = data->num_sensors; |
1423 | pmbus_add_sensor(data, "fan", "input", in_index, page, | 1424 | pmbus_add_sensor(data, "fan", "input", in_index, page, |
1424 | pmbus_fan_registers[f], PSC_FAN, true); | 1425 | pmbus_fan_registers[f], PSC_FAN, true, |
1426 | true); | ||
1425 | 1427 | ||
1426 | /* | 1428 | /* |
1427 | * Each fan status register covers multiple fans, | 1429 | * Each fan status register covers multiple fans, |
diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig index eb4af28f8567..1f29bab6b3e5 100644 --- a/drivers/hwspinlock/Kconfig +++ b/drivers/hwspinlock/Kconfig | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | config HWSPINLOCK | 5 | config HWSPINLOCK |
6 | tristate "Generic Hardware Spinlock framework" | 6 | tristate "Generic Hardware Spinlock framework" |
7 | depends on ARCH_OMAP4 | ||
7 | help | 8 | help |
8 | Say y here to support the generic hardware spinlock framework. | 9 | Say y here to support the generic hardware spinlock framework. |
9 | You only need to enable this if you have hardware spinlock module | 10 | You only need to enable this if you have hardware spinlock module |
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index f4077840d3ab..0e406d73b2c8 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c | |||
@@ -440,6 +440,7 @@ void do_ide_request(struct request_queue *q) | |||
440 | struct ide_host *host = hwif->host; | 440 | struct ide_host *host = hwif->host; |
441 | struct request *rq = NULL; | 441 | struct request *rq = NULL; |
442 | ide_startstop_t startstop; | 442 | ide_startstop_t startstop; |
443 | unsigned long queue_run_ms = 3; /* old plug delay */ | ||
443 | 444 | ||
444 | spin_unlock_irq(q->queue_lock); | 445 | spin_unlock_irq(q->queue_lock); |
445 | 446 | ||
@@ -459,6 +460,9 @@ repeat: | |||
459 | prev_port = hwif->host->cur_port; | 460 | prev_port = hwif->host->cur_port; |
460 | if (drive->dev_flags & IDE_DFLAG_SLEEPING && | 461 | if (drive->dev_flags & IDE_DFLAG_SLEEPING && |
461 | time_after(drive->sleep, jiffies)) { | 462 | time_after(drive->sleep, jiffies)) { |
463 | unsigned long left = jiffies - drive->sleep; | ||
464 | |||
465 | queue_run_ms = jiffies_to_msecs(left + 1); | ||
462 | ide_unlock_port(hwif); | 466 | ide_unlock_port(hwif); |
463 | goto plug_device; | 467 | goto plug_device; |
464 | } | 468 | } |
@@ -547,8 +551,10 @@ plug_device: | |||
547 | plug_device_2: | 551 | plug_device_2: |
548 | spin_lock_irq(q->queue_lock); | 552 | spin_lock_irq(q->queue_lock); |
549 | 553 | ||
550 | if (rq) | 554 | if (rq) { |
551 | blk_requeue_request(q, rq); | 555 | blk_requeue_request(q, rq); |
556 | blk_delay_queue(q, queue_run_ms); | ||
557 | } | ||
552 | } | 558 | } |
553 | 559 | ||
554 | void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq) | 560 | void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq) |
@@ -562,6 +568,10 @@ void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq) | |||
562 | blk_requeue_request(q, rq); | 568 | blk_requeue_request(q, rq); |
563 | 569 | ||
564 | spin_unlock_irqrestore(q->queue_lock, flags); | 570 | spin_unlock_irqrestore(q->queue_lock, flags); |
571 | |||
572 | /* Use 3ms as that was the old plug delay */ | ||
573 | if (rq) | ||
574 | blk_delay_queue(q, 3); | ||
565 | } | 575 | } |
566 | 576 | ||
567 | static int drive_is_ready(ide_drive_t *drive) | 577 | static int drive_is_ready(ide_drive_t *drive) |
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index c7a6213c6996..fbe1973f77b0 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c | |||
@@ -625,7 +625,7 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) | |||
625 | 625 | ||
626 | err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, | 626 | err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, |
627 | !!(mqp->flags & MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK), | 627 | !!(mqp->flags & MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK), |
628 | MLX4_PROTOCOL_IB); | 628 | MLX4_PROT_IB_IPV6); |
629 | if (err) | 629 | if (err) |
630 | return err; | 630 | return err; |
631 | 631 | ||
@@ -636,7 +636,7 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) | |||
636 | return 0; | 636 | return 0; |
637 | 637 | ||
638 | err_add: | 638 | err_add: |
639 | mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw, MLX4_PROTOCOL_IB); | 639 | mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw, MLX4_PROT_IB_IPV6); |
640 | return err; | 640 | return err; |
641 | } | 641 | } |
642 | 642 | ||
@@ -666,7 +666,7 @@ static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) | |||
666 | struct mlx4_ib_gid_entry *ge; | 666 | struct mlx4_ib_gid_entry *ge; |
667 | 667 | ||
668 | err = mlx4_multicast_detach(mdev->dev, | 668 | err = mlx4_multicast_detach(mdev->dev, |
669 | &mqp->mqp, gid->raw, MLX4_PROTOCOL_IB); | 669 | &mqp->mqp, gid->raw, MLX4_PROT_IB_IPV6); |
670 | if (err) | 670 | if (err) |
671 | return err; | 671 | return err; |
672 | 672 | ||
@@ -721,7 +721,6 @@ static int init_node_data(struct mlx4_ib_dev *dev) | |||
721 | if (err) | 721 | if (err) |
722 | goto out; | 722 | goto out; |
723 | 723 | ||
724 | dev->dev->rev_id = be32_to_cpup((__be32 *) (out_mad->data + 32)); | ||
725 | memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8); | 724 | memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8); |
726 | 725 | ||
727 | out: | 726 | out: |
@@ -954,7 +953,7 @@ static int mlx4_ib_netdev_event(struct notifier_block *this, unsigned long event | |||
954 | mlx4_foreach_ib_transport_port(port, ibdev->dev) { | 953 | mlx4_foreach_ib_transport_port(port, ibdev->dev) { |
955 | oldnd = iboe->netdevs[port - 1]; | 954 | oldnd = iboe->netdevs[port - 1]; |
956 | iboe->netdevs[port - 1] = | 955 | iboe->netdevs[port - 1] = |
957 | mlx4_get_protocol_dev(ibdev->dev, MLX4_PROTOCOL_EN, port); | 956 | mlx4_get_protocol_dev(ibdev->dev, MLX4_PROT_ETH, port); |
958 | if (oldnd != iboe->netdevs[port - 1]) { | 957 | if (oldnd != iboe->netdevs[port - 1]) { |
959 | if (iboe->netdevs[port - 1]) | 958 | if (iboe->netdevs[port - 1]) |
960 | netdev_added(ibdev, port); | 959 | netdev_added(ibdev, port); |
@@ -1207,7 +1206,7 @@ static struct mlx4_interface mlx4_ib_interface = { | |||
1207 | .add = mlx4_ib_add, | 1206 | .add = mlx4_ib_add, |
1208 | .remove = mlx4_ib_remove, | 1207 | .remove = mlx4_ib_remove, |
1209 | .event = mlx4_ib_event, | 1208 | .event = mlx4_ib_event, |
1210 | .protocol = MLX4_PROTOCOL_IB | 1209 | .protocol = MLX4_PROT_IB_IPV6 |
1211 | }; | 1210 | }; |
1212 | 1211 | ||
1213 | static int __init mlx4_ib_init(void) | 1212 | static int __init mlx4_ib_init(void) |
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index ef3291551bc6..cfa3a2b22232 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c | |||
@@ -1116,7 +1116,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi | |||
1116 | return rc; | 1116 | return rc; |
1117 | } | 1117 | } |
1118 | 1118 | ||
1119 | if (netif_is_bond_slave(netdev)) | 1119 | if (netif_is_bond_slave(nesvnic->netdev)) |
1120 | netdev = nesvnic->netdev->master; | 1120 | netdev = nesvnic->netdev->master; |
1121 | else | 1121 | else |
1122 | netdev = nesvnic->netdev; | 1122 | netdev = nesvnic->netdev; |
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 112ec55f2939..434fd800cd24 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -641,7 +641,7 @@ config TOUCHSCREEN_TOUCHIT213 | |||
641 | 641 | ||
642 | config TOUCHSCREEN_TSC2005 | 642 | config TOUCHSCREEN_TSC2005 |
643 | tristate "TSC2005 based touchscreens" | 643 | tristate "TSC2005 based touchscreens" |
644 | depends on SPI_MASTER | 644 | depends on SPI_MASTER && GENERIC_HARDIRQS |
645 | help | 645 | help |
646 | Say Y here if you have a TSC2005 based touchscreen. | 646 | Say Y here if you have a TSC2005 based touchscreen. |
647 | 647 | ||
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 87420616efa4..cbf0ff322676 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c | |||
@@ -358,7 +358,7 @@ static void __tsc2005_enable(struct tsc2005 *ts) | |||
358 | if (ts->esd_timeout && ts->set_reset) { | 358 | if (ts->esd_timeout && ts->set_reset) { |
359 | ts->last_valid_interrupt = jiffies; | 359 | ts->last_valid_interrupt = jiffies; |
360 | schedule_delayed_work(&ts->esd_work, | 360 | schedule_delayed_work(&ts->esd_work, |
361 | round_jiffies(jiffies + | 361 | round_jiffies_relative( |
362 | msecs_to_jiffies(ts->esd_timeout))); | 362 | msecs_to_jiffies(ts->esd_timeout))); |
363 | } | 363 | } |
364 | 364 | ||
@@ -477,7 +477,14 @@ static void tsc2005_esd_work(struct work_struct *work) | |||
477 | int error; | 477 | int error; |
478 | u16 r; | 478 | u16 r; |
479 | 479 | ||
480 | mutex_lock(&ts->mutex); | 480 | if (!mutex_trylock(&ts->mutex)) { |
481 | /* | ||
482 | * If the mutex is taken, it means that disable or enable is in | ||
483 | * progress. In that case just reschedule the work. If the work | ||
484 | * is not needed, it will be canceled by disable. | ||
485 | */ | ||
486 | goto reschedule; | ||
487 | } | ||
481 | 488 | ||
482 | if (time_is_after_jiffies(ts->last_valid_interrupt + | 489 | if (time_is_after_jiffies(ts->last_valid_interrupt + |
483 | msecs_to_jiffies(ts->esd_timeout))) | 490 | msecs_to_jiffies(ts->esd_timeout))) |
@@ -510,11 +517,12 @@ static void tsc2005_esd_work(struct work_struct *work) | |||
510 | tsc2005_start_scan(ts); | 517 | tsc2005_start_scan(ts); |
511 | 518 | ||
512 | out: | 519 | out: |
520 | mutex_unlock(&ts->mutex); | ||
521 | reschedule: | ||
513 | /* re-arm the watchdog */ | 522 | /* re-arm the watchdog */ |
514 | schedule_delayed_work(&ts->esd_work, | 523 | schedule_delayed_work(&ts->esd_work, |
515 | round_jiffies(jiffies + | 524 | round_jiffies_relative( |
516 | msecs_to_jiffies(ts->esd_timeout))); | 525 | msecs_to_jiffies(ts->esd_timeout))); |
517 | mutex_unlock(&ts->mutex); | ||
518 | } | 526 | } |
519 | 527 | ||
520 | static int tsc2005_open(struct input_dev *input) | 528 | static int tsc2005_open(struct input_dev *input) |
@@ -663,7 +671,7 @@ static int __devinit tsc2005_probe(struct spi_device *spi) | |||
663 | goto err_remove_sysfs; | 671 | goto err_remove_sysfs; |
664 | } | 672 | } |
665 | 673 | ||
666 | set_irq_wake(spi->irq, 1); | 674 | irq_set_irq_wake(spi->irq, 1); |
667 | return 0; | 675 | return 0; |
668 | 676 | ||
669 | err_remove_sysfs: | 677 | err_remove_sysfs: |
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index c41eb6180c9c..4bebae733349 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c | |||
@@ -231,6 +231,26 @@ void led_trigger_event(struct led_trigger *trigger, | |||
231 | } | 231 | } |
232 | EXPORT_SYMBOL_GPL(led_trigger_event); | 232 | EXPORT_SYMBOL_GPL(led_trigger_event); |
233 | 233 | ||
234 | void led_trigger_blink(struct led_trigger *trigger, | ||
235 | unsigned long *delay_on, | ||
236 | unsigned long *delay_off) | ||
237 | { | ||
238 | struct list_head *entry; | ||
239 | |||
240 | if (!trigger) | ||
241 | return; | ||
242 | |||
243 | read_lock(&trigger->leddev_list_lock); | ||
244 | list_for_each(entry, &trigger->led_cdevs) { | ||
245 | struct led_classdev *led_cdev; | ||
246 | |||
247 | led_cdev = list_entry(entry, struct led_classdev, trig_list); | ||
248 | led_blink_set(led_cdev, delay_on, delay_off); | ||
249 | } | ||
250 | read_unlock(&trigger->leddev_list_lock); | ||
251 | } | ||
252 | EXPORT_SYMBOL_GPL(led_trigger_blink); | ||
253 | |||
234 | void led_trigger_register_simple(const char *name, struct led_trigger **tp) | 254 | void led_trigger_register_simple(const char *name, struct led_trigger **tp) |
235 | { | 255 | { |
236 | struct led_trigger *trigger; | 256 | struct led_trigger *trigger; |
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 98d9ec85e0eb..8420129fc5ee 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig | |||
@@ -327,4 +327,10 @@ config DM_UEVENT | |||
327 | ---help--- | 327 | ---help--- |
328 | Generate udev events for DM events. | 328 | Generate udev events for DM events. |
329 | 329 | ||
330 | config DM_FLAKEY | ||
331 | tristate "Flakey target (EXPERIMENTAL)" | ||
332 | depends on BLK_DEV_DM && EXPERIMENTAL | ||
333 | ---help--- | ||
334 | A target that intermittently fails I/O for debugging purposes. | ||
335 | |||
330 | endif # MD | 336 | endif # MD |
diff --git a/drivers/md/Makefile b/drivers/md/Makefile index d0138606c2e8..448838b1f92a 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile | |||
@@ -29,6 +29,7 @@ obj-$(CONFIG_BLK_DEV_MD) += md-mod.o | |||
29 | obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o | 29 | obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o |
30 | obj-$(CONFIG_DM_CRYPT) += dm-crypt.o | 30 | obj-$(CONFIG_DM_CRYPT) += dm-crypt.o |
31 | obj-$(CONFIG_DM_DELAY) += dm-delay.o | 31 | obj-$(CONFIG_DM_DELAY) += dm-delay.o |
32 | obj-$(CONFIG_DM_FLAKEY) += dm-flakey.o | ||
32 | obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o | 33 | obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o |
33 | obj-$(CONFIG_DM_MULTIPATH_QL) += dm-queue-length.o | 34 | obj-$(CONFIG_DM_MULTIPATH_QL) += dm-queue-length.o |
34 | obj-$(CONFIG_DM_MULTIPATH_ST) += dm-service-time.o | 35 | obj-$(CONFIG_DM_MULTIPATH_ST) += dm-service-time.o |
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 2c62c1169f78..c8827ffd85bb 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c | |||
@@ -1324,20 +1324,29 @@ static int crypt_setkey_allcpus(struct crypt_config *cc) | |||
1324 | 1324 | ||
1325 | static int crypt_set_key(struct crypt_config *cc, char *key) | 1325 | static int crypt_set_key(struct crypt_config *cc, char *key) |
1326 | { | 1326 | { |
1327 | int r = -EINVAL; | ||
1328 | int key_string_len = strlen(key); | ||
1329 | |||
1327 | /* The key size may not be changed. */ | 1330 | /* The key size may not be changed. */ |
1328 | if (cc->key_size != (strlen(key) >> 1)) | 1331 | if (cc->key_size != (key_string_len >> 1)) |
1329 | return -EINVAL; | 1332 | goto out; |
1330 | 1333 | ||
1331 | /* Hyphen (which gives a key_size of zero) means there is no key. */ | 1334 | /* Hyphen (which gives a key_size of zero) means there is no key. */ |
1332 | if (!cc->key_size && strcmp(key, "-")) | 1335 | if (!cc->key_size && strcmp(key, "-")) |
1333 | return -EINVAL; | 1336 | goto out; |
1334 | 1337 | ||
1335 | if (cc->key_size && crypt_decode_key(cc->key, key, cc->key_size) < 0) | 1338 | if (cc->key_size && crypt_decode_key(cc->key, key, cc->key_size) < 0) |
1336 | return -EINVAL; | 1339 | goto out; |
1337 | 1340 | ||
1338 | set_bit(DM_CRYPT_KEY_VALID, &cc->flags); | 1341 | set_bit(DM_CRYPT_KEY_VALID, &cc->flags); |
1339 | 1342 | ||
1340 | return crypt_setkey_allcpus(cc); | 1343 | r = crypt_setkey_allcpus(cc); |
1344 | |||
1345 | out: | ||
1346 | /* Hex key string not needed after here, so wipe it. */ | ||
1347 | memset(key, '0', key_string_len); | ||
1348 | |||
1349 | return r; | ||
1341 | } | 1350 | } |
1342 | 1351 | ||
1343 | static int crypt_wipe_key(struct crypt_config *cc) | 1352 | static int crypt_wipe_key(struct crypt_config *cc) |
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c new file mode 100644 index 000000000000..ea790623c30b --- /dev/null +++ b/drivers/md/dm-flakey.c | |||
@@ -0,0 +1,212 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2003 Sistina Software (UK) Limited. | ||
3 | * Copyright (C) 2004, 2010 Red Hat, Inc. All rights reserved. | ||
4 | * | ||
5 | * This file is released under the GPL. | ||
6 | */ | ||
7 | |||
8 | #include <linux/device-mapper.h> | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/blkdev.h> | ||
13 | #include <linux/bio.h> | ||
14 | #include <linux/slab.h> | ||
15 | |||
16 | #define DM_MSG_PREFIX "flakey" | ||
17 | |||
18 | /* | ||
19 | * Flakey: Used for testing only, simulates intermittent, | ||
20 | * catastrophic device failure. | ||
21 | */ | ||
22 | struct flakey_c { | ||
23 | struct dm_dev *dev; | ||
24 | unsigned long start_time; | ||
25 | sector_t start; | ||
26 | unsigned up_interval; | ||
27 | unsigned down_interval; | ||
28 | }; | ||
29 | |||
30 | /* | ||
31 | * Construct a flakey mapping: <dev_path> <offset> <up interval> <down interval> | ||
32 | */ | ||
33 | static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv) | ||
34 | { | ||
35 | struct flakey_c *fc; | ||
36 | unsigned long long tmp; | ||
37 | |||
38 | if (argc != 4) { | ||
39 | ti->error = "dm-flakey: Invalid argument count"; | ||
40 | return -EINVAL; | ||
41 | } | ||
42 | |||
43 | fc = kmalloc(sizeof(*fc), GFP_KERNEL); | ||
44 | if (!fc) { | ||
45 | ti->error = "dm-flakey: Cannot allocate linear context"; | ||
46 | return -ENOMEM; | ||
47 | } | ||
48 | fc->start_time = jiffies; | ||
49 | |||
50 | if (sscanf(argv[1], "%llu", &tmp) != 1) { | ||
51 | ti->error = "dm-flakey: Invalid device sector"; | ||
52 | goto bad; | ||
53 | } | ||
54 | fc->start = tmp; | ||
55 | |||
56 | if (sscanf(argv[2], "%u", &fc->up_interval) != 1) { | ||
57 | ti->error = "dm-flakey: Invalid up interval"; | ||
58 | goto bad; | ||
59 | } | ||
60 | |||
61 | if (sscanf(argv[3], "%u", &fc->down_interval) != 1) { | ||
62 | ti->error = "dm-flakey: Invalid down interval"; | ||
63 | goto bad; | ||
64 | } | ||
65 | |||
66 | if (!(fc->up_interval + fc->down_interval)) { | ||
67 | ti->error = "dm-flakey: Total (up + down) interval is zero"; | ||
68 | goto bad; | ||
69 | } | ||
70 | |||
71 | if (fc->up_interval + fc->down_interval < fc->up_interval) { | ||
72 | ti->error = "dm-flakey: Interval overflow"; | ||
73 | goto bad; | ||
74 | } | ||
75 | |||
76 | if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &fc->dev)) { | ||
77 | ti->error = "dm-flakey: Device lookup failed"; | ||
78 | goto bad; | ||
79 | } | ||
80 | |||
81 | ti->num_flush_requests = 1; | ||
82 | ti->private = fc; | ||
83 | return 0; | ||
84 | |||
85 | bad: | ||
86 | kfree(fc); | ||
87 | return -EINVAL; | ||
88 | } | ||
89 | |||
90 | static void flakey_dtr(struct dm_target *ti) | ||
91 | { | ||
92 | struct flakey_c *fc = ti->private; | ||
93 | |||
94 | dm_put_device(ti, fc->dev); | ||
95 | kfree(fc); | ||
96 | } | ||
97 | |||
98 | static sector_t flakey_map_sector(struct dm_target *ti, sector_t bi_sector) | ||
99 | { | ||
100 | struct flakey_c *fc = ti->private; | ||
101 | |||
102 | return fc->start + (bi_sector - ti->begin); | ||
103 | } | ||
104 | |||
105 | static void flakey_map_bio(struct dm_target *ti, struct bio *bio) | ||
106 | { | ||
107 | struct flakey_c *fc = ti->private; | ||
108 | |||
109 | bio->bi_bdev = fc->dev->bdev; | ||
110 | if (bio_sectors(bio)) | ||
111 | bio->bi_sector = flakey_map_sector(ti, bio->bi_sector); | ||
112 | } | ||
113 | |||
114 | static int flakey_map(struct dm_target *ti, struct bio *bio, | ||
115 | union map_info *map_context) | ||
116 | { | ||
117 | struct flakey_c *fc = ti->private; | ||
118 | unsigned elapsed; | ||
119 | |||
120 | /* Are we alive ? */ | ||
121 | elapsed = (jiffies - fc->start_time) / HZ; | ||
122 | if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) | ||
123 | return -EIO; | ||
124 | |||
125 | flakey_map_bio(ti, bio); | ||
126 | |||
127 | return DM_MAPIO_REMAPPED; | ||
128 | } | ||
129 | |||
130 | static int flakey_status(struct dm_target *ti, status_type_t type, | ||
131 | char *result, unsigned int maxlen) | ||
132 | { | ||
133 | struct flakey_c *fc = ti->private; | ||
134 | |||
135 | switch (type) { | ||
136 | case STATUSTYPE_INFO: | ||
137 | result[0] = '\0'; | ||
138 | break; | ||
139 | |||
140 | case STATUSTYPE_TABLE: | ||
141 | snprintf(result, maxlen, "%s %llu %u %u", fc->dev->name, | ||
142 | (unsigned long long)fc->start, fc->up_interval, | ||
143 | fc->down_interval); | ||
144 | break; | ||
145 | } | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int flakey_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg) | ||
150 | { | ||
151 | struct flakey_c *fc = ti->private; | ||
152 | |||
153 | return __blkdev_driver_ioctl(fc->dev->bdev, fc->dev->mode, cmd, arg); | ||
154 | } | ||
155 | |||
156 | static int flakey_merge(struct dm_target *ti, struct bvec_merge_data *bvm, | ||
157 | struct bio_vec *biovec, int max_size) | ||
158 | { | ||
159 | struct flakey_c *fc = ti->private; | ||
160 | struct request_queue *q = bdev_get_queue(fc->dev->bdev); | ||
161 | |||
162 | if (!q->merge_bvec_fn) | ||
163 | return max_size; | ||
164 | |||
165 | bvm->bi_bdev = fc->dev->bdev; | ||
166 | bvm->bi_sector = flakey_map_sector(ti, bvm->bi_sector); | ||
167 | |||
168 | return min(max_size, q->merge_bvec_fn(q, bvm, biovec)); | ||
169 | } | ||
170 | |||
171 | static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data) | ||
172 | { | ||
173 | struct flakey_c *fc = ti->private; | ||
174 | |||
175 | return fn(ti, fc->dev, fc->start, ti->len, data); | ||
176 | } | ||
177 | |||
178 | static struct target_type flakey_target = { | ||
179 | .name = "flakey", | ||
180 | .version = {1, 1, 0}, | ||
181 | .module = THIS_MODULE, | ||
182 | .ctr = flakey_ctr, | ||
183 | .dtr = flakey_dtr, | ||
184 | .map = flakey_map, | ||
185 | .status = flakey_status, | ||
186 | .ioctl = flakey_ioctl, | ||
187 | .merge = flakey_merge, | ||
188 | .iterate_devices = flakey_iterate_devices, | ||
189 | }; | ||
190 | |||
191 | static int __init dm_flakey_init(void) | ||
192 | { | ||
193 | int r = dm_register_target(&flakey_target); | ||
194 | |||
195 | if (r < 0) | ||
196 | DMERR("register failed %d", r); | ||
197 | |||
198 | return r; | ||
199 | } | ||
200 | |||
201 | static void __exit dm_flakey_exit(void) | ||
202 | { | ||
203 | dm_unregister_target(&flakey_target); | ||
204 | } | ||
205 | |||
206 | /* Module hooks */ | ||
207 | module_init(dm_flakey_init); | ||
208 | module_exit(dm_flakey_exit); | ||
209 | |||
210 | MODULE_DESCRIPTION(DM_NAME " flakey target"); | ||
211 | MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>"); | ||
212 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 6d12775a1061..4cacdad2270a 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c | |||
@@ -1501,14 +1501,10 @@ static int check_version(unsigned int cmd, struct dm_ioctl __user *user) | |||
1501 | return r; | 1501 | return r; |
1502 | } | 1502 | } |
1503 | 1503 | ||
1504 | static void free_params(struct dm_ioctl *param) | ||
1505 | { | ||
1506 | vfree(param); | ||
1507 | } | ||
1508 | |||
1509 | static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) | 1504 | static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) |
1510 | { | 1505 | { |
1511 | struct dm_ioctl tmp, *dmi; | 1506 | struct dm_ioctl tmp, *dmi; |
1507 | int secure_data; | ||
1512 | 1508 | ||
1513 | if (copy_from_user(&tmp, user, sizeof(tmp) - sizeof(tmp.data))) | 1509 | if (copy_from_user(&tmp, user, sizeof(tmp) - sizeof(tmp.data))) |
1514 | return -EFAULT; | 1510 | return -EFAULT; |
@@ -1516,17 +1512,30 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) | |||
1516 | if (tmp.data_size < (sizeof(tmp) - sizeof(tmp.data))) | 1512 | if (tmp.data_size < (sizeof(tmp) - sizeof(tmp.data))) |
1517 | return -EINVAL; | 1513 | return -EINVAL; |
1518 | 1514 | ||
1515 | secure_data = tmp.flags & DM_SECURE_DATA_FLAG; | ||
1516 | |||
1519 | dmi = vmalloc(tmp.data_size); | 1517 | dmi = vmalloc(tmp.data_size); |
1520 | if (!dmi) | 1518 | if (!dmi) { |
1519 | if (secure_data && clear_user(user, tmp.data_size)) | ||
1520 | return -EFAULT; | ||
1521 | return -ENOMEM; | 1521 | return -ENOMEM; |
1522 | |||
1523 | if (copy_from_user(dmi, user, tmp.data_size)) { | ||
1524 | vfree(dmi); | ||
1525 | return -EFAULT; | ||
1526 | } | 1522 | } |
1527 | 1523 | ||
1524 | if (copy_from_user(dmi, user, tmp.data_size)) | ||
1525 | goto bad; | ||
1526 | |||
1527 | /* Wipe the user buffer so we do not return it to userspace */ | ||
1528 | if (secure_data && clear_user(user, tmp.data_size)) | ||
1529 | goto bad; | ||
1530 | |||
1528 | *param = dmi; | 1531 | *param = dmi; |
1529 | return 0; | 1532 | return 0; |
1533 | |||
1534 | bad: | ||
1535 | if (secure_data) | ||
1536 | memset(dmi, 0, tmp.data_size); | ||
1537 | vfree(dmi); | ||
1538 | return -EFAULT; | ||
1530 | } | 1539 | } |
1531 | 1540 | ||
1532 | static int validate_params(uint cmd, struct dm_ioctl *param) | 1541 | static int validate_params(uint cmd, struct dm_ioctl *param) |
@@ -1534,6 +1543,7 @@ static int validate_params(uint cmd, struct dm_ioctl *param) | |||
1534 | /* Always clear this flag */ | 1543 | /* Always clear this flag */ |
1535 | param->flags &= ~DM_BUFFER_FULL_FLAG; | 1544 | param->flags &= ~DM_BUFFER_FULL_FLAG; |
1536 | param->flags &= ~DM_UEVENT_GENERATED_FLAG; | 1545 | param->flags &= ~DM_UEVENT_GENERATED_FLAG; |
1546 | param->flags &= ~DM_SECURE_DATA_FLAG; | ||
1537 | 1547 | ||
1538 | /* Ignores parameters */ | 1548 | /* Ignores parameters */ |
1539 | if (cmd == DM_REMOVE_ALL_CMD || | 1549 | if (cmd == DM_REMOVE_ALL_CMD || |
@@ -1561,10 +1571,11 @@ static int validate_params(uint cmd, struct dm_ioctl *param) | |||
1561 | static int ctl_ioctl(uint command, struct dm_ioctl __user *user) | 1571 | static int ctl_ioctl(uint command, struct dm_ioctl __user *user) |
1562 | { | 1572 | { |
1563 | int r = 0; | 1573 | int r = 0; |
1574 | int wipe_buffer; | ||
1564 | unsigned int cmd; | 1575 | unsigned int cmd; |
1565 | struct dm_ioctl *uninitialized_var(param); | 1576 | struct dm_ioctl *uninitialized_var(param); |
1566 | ioctl_fn fn = NULL; | 1577 | ioctl_fn fn = NULL; |
1567 | size_t param_size; | 1578 | size_t input_param_size; |
1568 | 1579 | ||
1569 | /* only root can play with this */ | 1580 | /* only root can play with this */ |
1570 | if (!capable(CAP_SYS_ADMIN)) | 1581 | if (!capable(CAP_SYS_ADMIN)) |
@@ -1611,13 +1622,15 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) | |||
1611 | if (r) | 1622 | if (r) |
1612 | return r; | 1623 | return r; |
1613 | 1624 | ||
1625 | input_param_size = param->data_size; | ||
1626 | wipe_buffer = param->flags & DM_SECURE_DATA_FLAG; | ||
1627 | |||
1614 | r = validate_params(cmd, param); | 1628 | r = validate_params(cmd, param); |
1615 | if (r) | 1629 | if (r) |
1616 | goto out; | 1630 | goto out; |
1617 | 1631 | ||
1618 | param_size = param->data_size; | ||
1619 | param->data_size = sizeof(*param); | 1632 | param->data_size = sizeof(*param); |
1620 | r = fn(param, param_size); | 1633 | r = fn(param, input_param_size); |
1621 | 1634 | ||
1622 | /* | 1635 | /* |
1623 | * Copy the results back to userland. | 1636 | * Copy the results back to userland. |
@@ -1625,8 +1638,11 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) | |||
1625 | if (!r && copy_to_user(user, param, param->data_size)) | 1638 | if (!r && copy_to_user(user, param, param->data_size)) |
1626 | r = -EFAULT; | 1639 | r = -EFAULT; |
1627 | 1640 | ||
1628 | out: | 1641 | out: |
1629 | free_params(param); | 1642 | if (wipe_buffer) |
1643 | memset(param, 0, input_param_size); | ||
1644 | |||
1645 | vfree(param); | ||
1630 | return r; | 1646 | return r; |
1631 | } | 1647 | } |
1632 | 1648 | ||
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index 57968eb382c1..a1f321889676 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c | |||
@@ -543,7 +543,7 @@ static int disk_ctr(struct dm_dirty_log *log, struct dm_target *ti, | |||
543 | return -EINVAL; | 543 | return -EINVAL; |
544 | } | 544 | } |
545 | 545 | ||
546 | r = dm_get_device(ti, argv[0], FMODE_READ | FMODE_WRITE, &dev); | 546 | r = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &dev); |
547 | if (r) | 547 | if (r) |
548 | return r; | 548 | return r; |
549 | 549 | ||
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 4b0b63c290a6..a550a057d991 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
@@ -844,8 +844,8 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, | |||
844 | { | 844 | { |
845 | /* target parameters */ | 845 | /* target parameters */ |
846 | static struct param _params[] = { | 846 | static struct param _params[] = { |
847 | {1, 1024, "invalid number of priority groups"}, | 847 | {0, 1024, "invalid number of priority groups"}, |
848 | {1, 1024, "invalid initial priority group number"}, | 848 | {0, 1024, "invalid initial priority group number"}, |
849 | }; | 849 | }; |
850 | 850 | ||
851 | int r; | 851 | int r; |
@@ -879,6 +879,13 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, | |||
879 | if (r) | 879 | if (r) |
880 | goto bad; | 880 | goto bad; |
881 | 881 | ||
882 | if ((!m->nr_priority_groups && next_pg_num) || | ||
883 | (m->nr_priority_groups && !next_pg_num)) { | ||
884 | ti->error = "invalid initial priority group"; | ||
885 | r = -EINVAL; | ||
886 | goto bad; | ||
887 | } | ||
888 | |||
882 | /* parse the priority groups */ | 889 | /* parse the priority groups */ |
883 | while (as.argc) { | 890 | while (as.argc) { |
884 | struct priority_group *pg; | 891 | struct priority_group *pg; |
@@ -1065,7 +1072,7 @@ out: | |||
1065 | static int action_dev(struct multipath *m, struct dm_dev *dev, | 1072 | static int action_dev(struct multipath *m, struct dm_dev *dev, |
1066 | action_fn action) | 1073 | action_fn action) |
1067 | { | 1074 | { |
1068 | int r = 0; | 1075 | int r = -EINVAL; |
1069 | struct pgpath *pgpath; | 1076 | struct pgpath *pgpath; |
1070 | struct priority_group *pg; | 1077 | struct priority_group *pg; |
1071 | 1078 | ||
@@ -1415,7 +1422,7 @@ static int multipath_status(struct dm_target *ti, status_type_t type, | |||
1415 | else if (m->current_pg) | 1422 | else if (m->current_pg) |
1416 | pg_num = m->current_pg->pg_num; | 1423 | pg_num = m->current_pg->pg_num; |
1417 | else | 1424 | else |
1418 | pg_num = 1; | 1425 | pg_num = (m->nr_priority_groups ? 1 : 0); |
1419 | 1426 | ||
1420 | DMEMIT("%u ", pg_num); | 1427 | DMEMIT("%u ", pg_num); |
1421 | 1428 | ||
@@ -1669,7 +1676,7 @@ out: | |||
1669 | *---------------------------------------------------------------*/ | 1676 | *---------------------------------------------------------------*/ |
1670 | static struct target_type multipath_target = { | 1677 | static struct target_type multipath_target = { |
1671 | .name = "multipath", | 1678 | .name = "multipath", |
1672 | .version = {1, 2, 0}, | 1679 | .version = {1, 3, 0}, |
1673 | .module = THIS_MODULE, | 1680 | .module = THIS_MODULE, |
1674 | .ctr = multipath_ctr, | 1681 | .ctr = multipath_ctr, |
1675 | .dtr = multipath_dtr, | 1682 | .dtr = multipath_dtr, |
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index fdde53cd12b7..a2d330942cb2 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -1080,7 +1080,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1080 | argv++; | 1080 | argv++; |
1081 | argc--; | 1081 | argc--; |
1082 | 1082 | ||
1083 | r = dm_get_device(ti, cow_path, FMODE_READ | FMODE_WRITE, &s->cow); | 1083 | r = dm_get_device(ti, cow_path, dm_table_get_mode(ti->table), &s->cow); |
1084 | if (r) { | 1084 | if (r) { |
1085 | ti->error = "Cannot get COW device"; | 1085 | ti->error = "Cannot get COW device"; |
1086 | goto bad_cow; | 1086 | goto bad_cow; |
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index dddfa14f2982..3d80cf0c152d 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c | |||
@@ -396,9 +396,29 @@ static void stripe_io_hints(struct dm_target *ti, | |||
396 | blk_limits_io_opt(limits, chunk_size * sc->stripes); | 396 | blk_limits_io_opt(limits, chunk_size * sc->stripes); |
397 | } | 397 | } |
398 | 398 | ||
399 | static int stripe_merge(struct dm_target *ti, struct bvec_merge_data *bvm, | ||
400 | struct bio_vec *biovec, int max_size) | ||
401 | { | ||
402 | struct stripe_c *sc = ti->private; | ||
403 | sector_t bvm_sector = bvm->bi_sector; | ||
404 | uint32_t stripe; | ||
405 | struct request_queue *q; | ||
406 | |||
407 | stripe_map_sector(sc, bvm_sector, &stripe, &bvm_sector); | ||
408 | |||
409 | q = bdev_get_queue(sc->stripe[stripe].dev->bdev); | ||
410 | if (!q->merge_bvec_fn) | ||
411 | return max_size; | ||
412 | |||
413 | bvm->bi_bdev = sc->stripe[stripe].dev->bdev; | ||
414 | bvm->bi_sector = sc->stripe[stripe].physical_start + bvm_sector; | ||
415 | |||
416 | return min(max_size, q->merge_bvec_fn(q, bvm, biovec)); | ||
417 | } | ||
418 | |||
399 | static struct target_type stripe_target = { | 419 | static struct target_type stripe_target = { |
400 | .name = "striped", | 420 | .name = "striped", |
401 | .version = {1, 3, 1}, | 421 | .version = {1, 4, 0}, |
402 | .module = THIS_MODULE, | 422 | .module = THIS_MODULE, |
403 | .ctr = stripe_ctr, | 423 | .ctr = stripe_ctr, |
404 | .dtr = stripe_dtr, | 424 | .dtr = stripe_dtr, |
@@ -407,6 +427,7 @@ static struct target_type stripe_target = { | |||
407 | .status = stripe_status, | 427 | .status = stripe_status, |
408 | .iterate_devices = stripe_iterate_devices, | 428 | .iterate_devices = stripe_iterate_devices, |
409 | .io_hints = stripe_io_hints, | 429 | .io_hints = stripe_io_hints, |
430 | .merge = stripe_merge, | ||
410 | }; | 431 | }; |
411 | 432 | ||
412 | int __init dm_stripe_init(void) | 433 | int __init dm_stripe_init(void) |
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index 9be6a830f1d2..ac0e42b47b2a 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c | |||
@@ -187,7 +187,7 @@ static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int | |||
187 | sample_period = dev->params.sample_period; | 187 | sample_period = dev->params.sample_period; |
188 | ldata = (unsigned long *)data; | 188 | ldata = (unsigned long *)data; |
189 | size = length << 3; | 189 | size = length << 3; |
190 | next_one = generic_find_next_le_bit(ldata, size, 0); | 190 | next_one = find_next_bit_le(ldata, size, 0); |
191 | if (next_one > 0) { | 191 | if (next_one > 0) { |
192 | ev.pulse = true; | 192 | ev.pulse = true; |
193 | ev.duration = | 193 | ev.duration = |
@@ -196,14 +196,14 @@ static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int | |||
196 | } | 196 | } |
197 | 197 | ||
198 | while (next_one < size) { | 198 | while (next_one < size) { |
199 | next_zero = generic_find_next_zero_le_bit(ldata, size, next_one + 1); | 199 | next_zero = find_next_zero_bit_le(ldata, size, next_one + 1); |
200 | ev.pulse = false; | 200 | ev.pulse = false; |
201 | ev.duration = ITE_BITS_TO_NS(next_zero - next_one, sample_period); | 201 | ev.duration = ITE_BITS_TO_NS(next_zero - next_one, sample_period); |
202 | ir_raw_event_store_with_filter(dev->rdev, &ev); | 202 | ir_raw_event_store_with_filter(dev->rdev, &ev); |
203 | 203 | ||
204 | if (next_zero < size) { | 204 | if (next_zero < size) { |
205 | next_one = | 205 | next_one = |
206 | generic_find_next_le_bit(ldata, | 206 | find_next_bit_le(ldata, |
207 | size, | 207 | size, |
208 | next_zero + 1); | 208 | next_zero + 1); |
209 | ev.pulse = true; | 209 | ev.pulse = true; |
diff --git a/drivers/memstick/host/Kconfig b/drivers/memstick/host/Kconfig index 4ce5c8dffb68..cc0997a05171 100644 --- a/drivers/memstick/host/Kconfig +++ b/drivers/memstick/host/Kconfig | |||
@@ -30,3 +30,15 @@ config MEMSTICK_JMICRON_38X | |||
30 | 30 | ||
31 | To compile this driver as a module, choose M here: the | 31 | To compile this driver as a module, choose M here: the |
32 | module will be called jmb38x_ms. | 32 | module will be called jmb38x_ms. |
33 | |||
34 | config MEMSTICK_R592 | ||
35 | tristate "Ricoh R5C592 MemoryStick interface support (EXPERIMENTAL)" | ||
36 | depends on EXPERIMENTAL && PCI | ||
37 | |||
38 | help | ||
39 | Say Y here if you want to be able to access MemoryStick cards with | ||
40 | the Ricoh R5C592 MemoryStick card reader (which is part of 5 in one | ||
41 | multifunction reader) | ||
42 | |||
43 | To compile this driver as a module, choose M here: the module will | ||
44 | be called r592. | ||
diff --git a/drivers/memstick/host/Makefile b/drivers/memstick/host/Makefile index a1815e9dd019..31ba8d378e46 100644 --- a/drivers/memstick/host/Makefile +++ b/drivers/memstick/host/Makefile | |||
@@ -4,3 +4,4 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_MEMSTICK_TIFM_MS) += tifm_ms.o | 5 | obj-$(CONFIG_MEMSTICK_TIFM_MS) += tifm_ms.o |
6 | obj-$(CONFIG_MEMSTICK_JMICRON_38X) += jmb38x_ms.o | 6 | obj-$(CONFIG_MEMSTICK_JMICRON_38X) += jmb38x_ms.o |
7 | obj-$(CONFIG_MEMSTICK_R592) += r592.o | ||
diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c new file mode 100644 index 000000000000..767406c95291 --- /dev/null +++ b/drivers/memstick/host/r592.c | |||
@@ -0,0 +1,908 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 - Maxim Levitsky | ||
3 | * driver for Ricoh memstick readers | ||
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/kernel.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/freezer.h> | ||
13 | #include <linux/jiffies.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/pci.h> | ||
16 | #include <linux/pci_ids.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/kthread.h> | ||
20 | #include <linux/sched.h> | ||
21 | #include <linux/highmem.h> | ||
22 | #include <asm/byteorder.h> | ||
23 | #include <linux/swab.h> | ||
24 | #include "r592.h" | ||
25 | |||
26 | static int enable_dma = 1; | ||
27 | static int debug; | ||
28 | |||
29 | static const char *tpc_names[] = { | ||
30 | "MS_TPC_READ_MG_STATUS", | ||
31 | "MS_TPC_READ_LONG_DATA", | ||
32 | "MS_TPC_READ_SHORT_DATA", | ||
33 | "MS_TPC_READ_REG", | ||
34 | "MS_TPC_READ_QUAD_DATA", | ||
35 | "INVALID", | ||
36 | "MS_TPC_GET_INT", | ||
37 | "MS_TPC_SET_RW_REG_ADRS", | ||
38 | "MS_TPC_EX_SET_CMD", | ||
39 | "MS_TPC_WRITE_QUAD_DATA", | ||
40 | "MS_TPC_WRITE_REG", | ||
41 | "MS_TPC_WRITE_SHORT_DATA", | ||
42 | "MS_TPC_WRITE_LONG_DATA", | ||
43 | "MS_TPC_SET_CMD", | ||
44 | }; | ||
45 | |||
46 | /** | ||
47 | * memstick_debug_get_tpc_name - debug helper that returns string for | ||
48 | * a TPC number | ||
49 | */ | ||
50 | const char *memstick_debug_get_tpc_name(int tpc) | ||
51 | { | ||
52 | return tpc_names[tpc-1]; | ||
53 | } | ||
54 | EXPORT_SYMBOL(memstick_debug_get_tpc_name); | ||
55 | |||
56 | |||
57 | /* Read a register*/ | ||
58 | static inline u32 r592_read_reg(struct r592_device *dev, int address) | ||
59 | { | ||
60 | u32 value = readl(dev->mmio + address); | ||
61 | dbg_reg("reg #%02d == 0x%08x", address, value); | ||
62 | return value; | ||
63 | } | ||
64 | |||
65 | /* Write a register */ | ||
66 | static inline void r592_write_reg(struct r592_device *dev, | ||
67 | int address, u32 value) | ||
68 | { | ||
69 | dbg_reg("reg #%02d <- 0x%08x", address, value); | ||
70 | writel(value, dev->mmio + address); | ||
71 | } | ||
72 | |||
73 | /* Reads a big endian DWORD register */ | ||
74 | static inline u32 r592_read_reg_raw_be(struct r592_device *dev, int address) | ||
75 | { | ||
76 | u32 value = __raw_readl(dev->mmio + address); | ||
77 | dbg_reg("reg #%02d == 0x%08x", address, value); | ||
78 | return be32_to_cpu(value); | ||
79 | } | ||
80 | |||
81 | /* Writes a big endian DWORD register */ | ||
82 | static inline void r592_write_reg_raw_be(struct r592_device *dev, | ||
83 | int address, u32 value) | ||
84 | { | ||
85 | dbg_reg("reg #%02d <- 0x%08x", address, value); | ||
86 | __raw_writel(cpu_to_be32(value), dev->mmio + address); | ||
87 | } | ||
88 | |||
89 | /* Set specific bits in a register (little endian) */ | ||
90 | static inline void r592_set_reg_mask(struct r592_device *dev, | ||
91 | int address, u32 mask) | ||
92 | { | ||
93 | u32 reg = readl(dev->mmio + address); | ||
94 | dbg_reg("reg #%02d |= 0x%08x (old =0x%08x)", address, mask, reg); | ||
95 | writel(reg | mask , dev->mmio + address); | ||
96 | } | ||
97 | |||
98 | /* Clear specific bits in a register (little endian) */ | ||
99 | static inline void r592_clear_reg_mask(struct r592_device *dev, | ||
100 | int address, u32 mask) | ||
101 | { | ||
102 | u32 reg = readl(dev->mmio + address); | ||
103 | dbg_reg("reg #%02d &= 0x%08x (old = 0x%08x, mask = 0x%08x)", | ||
104 | address, ~mask, reg, mask); | ||
105 | writel(reg & ~mask, dev->mmio + address); | ||
106 | } | ||
107 | |||
108 | |||
109 | /* Wait for status bits while checking for errors */ | ||
110 | static int r592_wait_status(struct r592_device *dev, u32 mask, u32 wanted_mask) | ||
111 | { | ||
112 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); | ||
113 | u32 reg = r592_read_reg(dev, R592_STATUS); | ||
114 | |||
115 | if ((reg & mask) == wanted_mask) | ||
116 | return 0; | ||
117 | |||
118 | while (time_before(jiffies, timeout)) { | ||
119 | |||
120 | reg = r592_read_reg(dev, R592_STATUS); | ||
121 | |||
122 | if ((reg & mask) == wanted_mask) | ||
123 | return 0; | ||
124 | |||
125 | if (reg & (R592_STATUS_SEND_ERR | R592_STATUS_RECV_ERR)) | ||
126 | return -EIO; | ||
127 | |||
128 | cpu_relax(); | ||
129 | } | ||
130 | return -ETIME; | ||
131 | } | ||
132 | |||
133 | |||
134 | /* Enable/disable device */ | ||
135 | static int r592_enable_device(struct r592_device *dev, bool enable) | ||
136 | { | ||
137 | dbg("%sabling the device", enable ? "en" : "dis"); | ||
138 | |||
139 | if (enable) { | ||
140 | |||
141 | /* Power up the card */ | ||
142 | r592_write_reg(dev, R592_POWER, R592_POWER_0 | R592_POWER_1); | ||
143 | |||
144 | /* Perform a reset */ | ||
145 | r592_set_reg_mask(dev, R592_IO, R592_IO_RESET); | ||
146 | |||
147 | msleep(100); | ||
148 | } else | ||
149 | /* Power down the card */ | ||
150 | r592_write_reg(dev, R592_POWER, 0); | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | /* Set serial/parallel mode */ | ||
156 | static int r592_set_mode(struct r592_device *dev, bool parallel_mode) | ||
157 | { | ||
158 | if (!parallel_mode) { | ||
159 | dbg("switching to serial mode"); | ||
160 | |||
161 | /* Set serial mode */ | ||
162 | r592_write_reg(dev, R592_IO_MODE, R592_IO_MODE_SERIAL); | ||
163 | |||
164 | r592_clear_reg_mask(dev, R592_POWER, R592_POWER_20); | ||
165 | |||
166 | } else { | ||
167 | dbg("switching to parallel mode"); | ||
168 | |||
169 | /* This setting should be set _before_ switch TPC */ | ||
170 | r592_set_reg_mask(dev, R592_POWER, R592_POWER_20); | ||
171 | |||
172 | r592_clear_reg_mask(dev, R592_IO, | ||
173 | R592_IO_SERIAL1 | R592_IO_SERIAL2); | ||
174 | |||
175 | /* Set the parallel mode now */ | ||
176 | r592_write_reg(dev, R592_IO_MODE, R592_IO_MODE_PARALLEL); | ||
177 | } | ||
178 | |||
179 | dev->parallel_mode = parallel_mode; | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | /* Perform a controller reset without powering down the card */ | ||
184 | static void r592_host_reset(struct r592_device *dev) | ||
185 | { | ||
186 | r592_set_reg_mask(dev, R592_IO, R592_IO_RESET); | ||
187 | msleep(100); | ||
188 | r592_set_mode(dev, dev->parallel_mode); | ||
189 | } | ||
190 | |||
191 | /* Disable all hardware interrupts */ | ||
192 | static void r592_clear_interrupts(struct r592_device *dev) | ||
193 | { | ||
194 | /* Disable & ACK all interrupts */ | ||
195 | r592_clear_reg_mask(dev, R592_REG_MSC, IRQ_ALL_ACK_MASK); | ||
196 | r592_clear_reg_mask(dev, R592_REG_MSC, IRQ_ALL_EN_MASK); | ||
197 | } | ||
198 | |||
199 | /* Tests if there is an CRC error */ | ||
200 | static int r592_test_io_error(struct r592_device *dev) | ||
201 | { | ||
202 | if (!(r592_read_reg(dev, R592_STATUS) & | ||
203 | (R592_STATUS_SEND_ERR | R592_STATUS_RECV_ERR))) | ||
204 | return 0; | ||
205 | |||
206 | return -EIO; | ||
207 | } | ||
208 | |||
209 | /* Ensure that FIFO is ready for use */ | ||
210 | static int r592_test_fifo_empty(struct r592_device *dev) | ||
211 | { | ||
212 | if (r592_read_reg(dev, R592_REG_MSC) & R592_REG_MSC_FIFO_EMPTY) | ||
213 | return 0; | ||
214 | |||
215 | dbg("FIFO not ready, trying to reset the device"); | ||
216 | r592_host_reset(dev); | ||
217 | |||
218 | if (r592_read_reg(dev, R592_REG_MSC) & R592_REG_MSC_FIFO_EMPTY) | ||
219 | return 0; | ||
220 | |||
221 | message("FIFO still not ready, giving up"); | ||
222 | return -EIO; | ||
223 | } | ||
224 | |||
225 | /* Activates the DMA transfer from to FIFO */ | ||
226 | static void r592_start_dma(struct r592_device *dev, bool is_write) | ||
227 | { | ||
228 | unsigned long flags; | ||
229 | u32 reg; | ||
230 | spin_lock_irqsave(&dev->irq_lock, flags); | ||
231 | |||
232 | /* Ack interrupts (just in case) + enable them */ | ||
233 | r592_clear_reg_mask(dev, R592_REG_MSC, DMA_IRQ_ACK_MASK); | ||
234 | r592_set_reg_mask(dev, R592_REG_MSC, DMA_IRQ_EN_MASK); | ||
235 | |||
236 | /* Set DMA address */ | ||
237 | r592_write_reg(dev, R592_FIFO_DMA, sg_dma_address(&dev->req->sg)); | ||
238 | |||
239 | /* Enable the DMA */ | ||
240 | reg = r592_read_reg(dev, R592_FIFO_DMA_SETTINGS); | ||
241 | reg |= R592_FIFO_DMA_SETTINGS_EN; | ||
242 | |||
243 | if (!is_write) | ||
244 | reg |= R592_FIFO_DMA_SETTINGS_DIR; | ||
245 | else | ||
246 | reg &= ~R592_FIFO_DMA_SETTINGS_DIR; | ||
247 | r592_write_reg(dev, R592_FIFO_DMA_SETTINGS, reg); | ||
248 | |||
249 | spin_unlock_irqrestore(&dev->irq_lock, flags); | ||
250 | } | ||
251 | |||
252 | /* Cleanups DMA related settings */ | ||
253 | static void r592_stop_dma(struct r592_device *dev, int error) | ||
254 | { | ||
255 | r592_clear_reg_mask(dev, R592_FIFO_DMA_SETTINGS, | ||
256 | R592_FIFO_DMA_SETTINGS_EN); | ||
257 | |||
258 | /* This is only a precation */ | ||
259 | r592_write_reg(dev, R592_FIFO_DMA, | ||
260 | dev->dummy_dma_page_physical_address); | ||
261 | |||
262 | r592_clear_reg_mask(dev, R592_REG_MSC, DMA_IRQ_EN_MASK); | ||
263 | r592_clear_reg_mask(dev, R592_REG_MSC, DMA_IRQ_ACK_MASK); | ||
264 | dev->dma_error = error; | ||
265 | } | ||
266 | |||
267 | /* Test if hardware supports DMA */ | ||
268 | static void r592_check_dma(struct r592_device *dev) | ||
269 | { | ||
270 | dev->dma_capable = enable_dma && | ||
271 | (r592_read_reg(dev, R592_FIFO_DMA_SETTINGS) & | ||
272 | R592_FIFO_DMA_SETTINGS_CAP); | ||
273 | } | ||
274 | |||
275 | /* Transfers fifo contents in/out using DMA */ | ||
276 | static int r592_transfer_fifo_dma(struct r592_device *dev) | ||
277 | { | ||
278 | int len, sg_count; | ||
279 | bool is_write; | ||
280 | |||
281 | if (!dev->dma_capable || !dev->req->long_data) | ||
282 | return -EINVAL; | ||
283 | |||
284 | len = dev->req->sg.length; | ||
285 | is_write = dev->req->data_dir == WRITE; | ||
286 | |||
287 | if (len != R592_LFIFO_SIZE) | ||
288 | return -EINVAL; | ||
289 | |||
290 | dbg_verbose("doing dma transfer"); | ||
291 | |||
292 | dev->dma_error = 0; | ||
293 | INIT_COMPLETION(dev->dma_done); | ||
294 | |||
295 | /* TODO: hidden assumption about nenth beeing always 1 */ | ||
296 | sg_count = dma_map_sg(&dev->pci_dev->dev, &dev->req->sg, 1, is_write ? | ||
297 | PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); | ||
298 | |||
299 | if (sg_count != 1 || | ||
300 | (sg_dma_len(&dev->req->sg) < dev->req->sg.length)) { | ||
301 | message("problem in dma_map_sg"); | ||
302 | return -EIO; | ||
303 | } | ||
304 | |||
305 | r592_start_dma(dev, is_write); | ||
306 | |||
307 | /* Wait for DMA completion */ | ||
308 | if (!wait_for_completion_timeout( | ||
309 | &dev->dma_done, msecs_to_jiffies(1000))) { | ||
310 | message("DMA timeout"); | ||
311 | r592_stop_dma(dev, -ETIMEDOUT); | ||
312 | } | ||
313 | |||
314 | dma_unmap_sg(&dev->pci_dev->dev, &dev->req->sg, 1, is_write ? | ||
315 | PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); | ||
316 | |||
317 | |||
318 | return dev->dma_error; | ||
319 | } | ||
320 | |||
321 | /* | ||
322 | * Writes the FIFO in 4 byte chunks. | ||
323 | * If length isn't 4 byte aligned, rest of the data if put to a fifo | ||
324 | * to be written later | ||
325 | * Use r592_flush_fifo_write to flush that fifo when writing for the | ||
326 | * last time | ||
327 | */ | ||
328 | static void r592_write_fifo_pio(struct r592_device *dev, | ||
329 | unsigned char *buffer, int len) | ||
330 | { | ||
331 | /* flush spill from former write */ | ||
332 | if (!kfifo_is_empty(&dev->pio_fifo)) { | ||
333 | |||
334 | u8 tmp[4] = {0}; | ||
335 | int copy_len = kfifo_in(&dev->pio_fifo, buffer, len); | ||
336 | |||
337 | if (!kfifo_is_full(&dev->pio_fifo)) | ||
338 | return; | ||
339 | len -= copy_len; | ||
340 | buffer += copy_len; | ||
341 | |||
342 | copy_len = kfifo_out(&dev->pio_fifo, tmp, 4); | ||
343 | WARN_ON(copy_len != 4); | ||
344 | r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)tmp); | ||
345 | } | ||
346 | |||
347 | WARN_ON(!kfifo_is_empty(&dev->pio_fifo)); | ||
348 | |||
349 | /* write full dwords */ | ||
350 | while (len >= 4) { | ||
351 | r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)buffer); | ||
352 | buffer += 4; | ||
353 | len -= 4; | ||
354 | } | ||
355 | |||
356 | /* put remaining bytes to the spill */ | ||
357 | if (len) | ||
358 | kfifo_in(&dev->pio_fifo, buffer, len); | ||
359 | } | ||
360 | |||
361 | /* Flushes the temporary FIFO used to make aligned DWORD writes */ | ||
362 | static void r592_flush_fifo_write(struct r592_device *dev) | ||
363 | { | ||
364 | u8 buffer[4] = { 0 }; | ||
365 | int len; | ||
366 | |||
367 | if (kfifo_is_empty(&dev->pio_fifo)) | ||
368 | return; | ||
369 | |||
370 | len = kfifo_out(&dev->pio_fifo, buffer, 4); | ||
371 | r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)buffer); | ||
372 | } | ||
373 | |||
374 | /* | ||
375 | * Read a fifo in 4 bytes chunks. | ||
376 | * If input doesn't fit the buffer, it places bytes of last dword in spill | ||
377 | * buffer, so that they don't get lost on last read, just throw these away. | ||
378 | */ | ||
379 | static void r592_read_fifo_pio(struct r592_device *dev, | ||
380 | unsigned char *buffer, int len) | ||
381 | { | ||
382 | u8 tmp[4]; | ||
383 | |||
384 | /* Read from last spill */ | ||
385 | if (!kfifo_is_empty(&dev->pio_fifo)) { | ||
386 | int bytes_copied = | ||
387 | kfifo_out(&dev->pio_fifo, buffer, min(4, len)); | ||
388 | buffer += bytes_copied; | ||
389 | len -= bytes_copied; | ||
390 | |||
391 | if (!kfifo_is_empty(&dev->pio_fifo)) | ||
392 | return; | ||
393 | } | ||
394 | |||
395 | /* Reads dwords from FIFO */ | ||
396 | while (len >= 4) { | ||
397 | *(u32 *)buffer = r592_read_reg_raw_be(dev, R592_FIFO_PIO); | ||
398 | buffer += 4; | ||
399 | len -= 4; | ||
400 | } | ||
401 | |||
402 | if (len) { | ||
403 | *(u32 *)tmp = r592_read_reg_raw_be(dev, R592_FIFO_PIO); | ||
404 | kfifo_in(&dev->pio_fifo, tmp, 4); | ||
405 | len -= kfifo_out(&dev->pio_fifo, buffer, len); | ||
406 | } | ||
407 | |||
408 | WARN_ON(len); | ||
409 | return; | ||
410 | } | ||
411 | |||
412 | /* Transfers actual data using PIO. */ | ||
413 | static int r592_transfer_fifo_pio(struct r592_device *dev) | ||
414 | { | ||
415 | unsigned long flags; | ||
416 | |||
417 | bool is_write = dev->req->tpc >= MS_TPC_SET_RW_REG_ADRS; | ||
418 | struct sg_mapping_iter miter; | ||
419 | |||
420 | kfifo_reset(&dev->pio_fifo); | ||
421 | |||
422 | if (!dev->req->long_data) { | ||
423 | if (is_write) { | ||
424 | r592_write_fifo_pio(dev, dev->req->data, | ||
425 | dev->req->data_len); | ||
426 | r592_flush_fifo_write(dev); | ||
427 | } else | ||
428 | r592_read_fifo_pio(dev, dev->req->data, | ||
429 | dev->req->data_len); | ||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | local_irq_save(flags); | ||
434 | sg_miter_start(&miter, &dev->req->sg, 1, SG_MITER_ATOMIC | | ||
435 | (is_write ? SG_MITER_FROM_SG : SG_MITER_TO_SG)); | ||
436 | |||
437 | /* Do the transfer fifo<->memory*/ | ||
438 | while (sg_miter_next(&miter)) | ||
439 | if (is_write) | ||
440 | r592_write_fifo_pio(dev, miter.addr, miter.length); | ||
441 | else | ||
442 | r592_read_fifo_pio(dev, miter.addr, miter.length); | ||
443 | |||
444 | |||
445 | /* Write last few non aligned bytes*/ | ||
446 | if (is_write) | ||
447 | r592_flush_fifo_write(dev); | ||
448 | |||
449 | sg_miter_stop(&miter); | ||
450 | local_irq_restore(flags); | ||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | /* Executes one TPC (data is read/written from small or large fifo) */ | ||
455 | static void r592_execute_tpc(struct r592_device *dev) | ||
456 | { | ||
457 | bool is_write = dev->req->tpc >= MS_TPC_SET_RW_REG_ADRS; | ||
458 | int len, error; | ||
459 | u32 status, reg; | ||
460 | |||
461 | if (!dev->req) { | ||
462 | message("BUG: tpc execution without request!"); | ||
463 | return; | ||
464 | } | ||
465 | |||
466 | len = dev->req->long_data ? | ||
467 | dev->req->sg.length : dev->req->data_len; | ||
468 | |||
469 | /* Ensure that FIFO can hold the input data */ | ||
470 | if (len > R592_LFIFO_SIZE) { | ||
471 | message("IO: hardware doesn't support TPCs longer that 512"); | ||
472 | error = -ENOSYS; | ||
473 | goto out; | ||
474 | } | ||
475 | |||
476 | if (!(r592_read_reg(dev, R592_REG_MSC) & R592_REG_MSC_PRSNT)) { | ||
477 | dbg("IO: refusing to send TPC because card is absent"); | ||
478 | error = -ENODEV; | ||
479 | goto out; | ||
480 | } | ||
481 | |||
482 | dbg("IO: executing %s LEN=%d", | ||
483 | memstick_debug_get_tpc_name(dev->req->tpc), len); | ||
484 | |||
485 | /* Set IO direction */ | ||
486 | if (is_write) | ||
487 | r592_set_reg_mask(dev, R592_IO, R592_IO_DIRECTION); | ||
488 | else | ||
489 | r592_clear_reg_mask(dev, R592_IO, R592_IO_DIRECTION); | ||
490 | |||
491 | |||
492 | error = r592_test_fifo_empty(dev); | ||
493 | if (error) | ||
494 | goto out; | ||
495 | |||
496 | /* Transfer write data */ | ||
497 | if (is_write) { | ||
498 | error = r592_transfer_fifo_dma(dev); | ||
499 | if (error == -EINVAL) | ||
500 | error = r592_transfer_fifo_pio(dev); | ||
501 | } | ||
502 | |||
503 | if (error) | ||
504 | goto out; | ||
505 | |||
506 | /* Trigger the TPC */ | ||
507 | reg = (len << R592_TPC_EXEC_LEN_SHIFT) | | ||
508 | (dev->req->tpc << R592_TPC_EXEC_TPC_SHIFT) | | ||
509 | R592_TPC_EXEC_BIG_FIFO; | ||
510 | |||
511 | r592_write_reg(dev, R592_TPC_EXEC, reg); | ||
512 | |||
513 | /* Wait for TPC completion */ | ||
514 | status = R592_STATUS_RDY; | ||
515 | if (dev->req->need_card_int) | ||
516 | status |= R592_STATUS_CED; | ||
517 | |||
518 | error = r592_wait_status(dev, status, status); | ||
519 | if (error) { | ||
520 | message("card didn't respond"); | ||
521 | goto out; | ||
522 | } | ||
523 | |||
524 | /* Test IO errors */ | ||
525 | error = r592_test_io_error(dev); | ||
526 | if (error) { | ||
527 | dbg("IO error"); | ||
528 | goto out; | ||
529 | } | ||
530 | |||
531 | /* Read data from FIFO */ | ||
532 | if (!is_write) { | ||
533 | error = r592_transfer_fifo_dma(dev); | ||
534 | if (error == -EINVAL) | ||
535 | error = r592_transfer_fifo_pio(dev); | ||
536 | } | ||
537 | |||
538 | /* read INT reg. This can be shortened with shifts, but that way | ||
539 | its more readable */ | ||
540 | if (dev->parallel_mode && dev->req->need_card_int) { | ||
541 | |||
542 | dev->req->int_reg = 0; | ||
543 | status = r592_read_reg(dev, R592_STATUS); | ||
544 | |||
545 | if (status & R592_STATUS_P_CMDNACK) | ||
546 | dev->req->int_reg |= MEMSTICK_INT_CMDNAK; | ||
547 | if (status & R592_STATUS_P_BREQ) | ||
548 | dev->req->int_reg |= MEMSTICK_INT_BREQ; | ||
549 | if (status & R592_STATUS_P_INTERR) | ||
550 | dev->req->int_reg |= MEMSTICK_INT_ERR; | ||
551 | if (status & R592_STATUS_P_CED) | ||
552 | dev->req->int_reg |= MEMSTICK_INT_CED; | ||
553 | } | ||
554 | |||
555 | if (error) | ||
556 | dbg("FIFO read error"); | ||
557 | out: | ||
558 | dev->req->error = error; | ||
559 | r592_clear_reg_mask(dev, R592_REG_MSC, R592_REG_MSC_LED); | ||
560 | return; | ||
561 | } | ||
562 | |||
563 | /* Main request processing thread */ | ||
564 | static int r592_process_thread(void *data) | ||
565 | { | ||
566 | int error; | ||
567 | struct r592_device *dev = (struct r592_device *)data; | ||
568 | unsigned long flags; | ||
569 | |||
570 | while (!kthread_should_stop()) { | ||
571 | spin_lock_irqsave(&dev->io_thread_lock, flags); | ||
572 | set_current_state(TASK_INTERRUPTIBLE); | ||
573 | error = memstick_next_req(dev->host, &dev->req); | ||
574 | spin_unlock_irqrestore(&dev->io_thread_lock, flags); | ||
575 | |||
576 | if (error) { | ||
577 | if (error == -ENXIO || error == -EAGAIN) { | ||
578 | dbg_verbose("IO: done IO, sleeping"); | ||
579 | } else { | ||
580 | dbg("IO: unknown error from " | ||
581 | "memstick_next_req %d", error); | ||
582 | } | ||
583 | |||
584 | if (kthread_should_stop()) | ||
585 | set_current_state(TASK_RUNNING); | ||
586 | |||
587 | schedule(); | ||
588 | } else { | ||
589 | set_current_state(TASK_RUNNING); | ||
590 | r592_execute_tpc(dev); | ||
591 | } | ||
592 | } | ||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | /* Reprogram chip to detect change in card state */ | ||
597 | /* eg, if card is detected, arm it to detect removal, and vice versa */ | ||
598 | static void r592_update_card_detect(struct r592_device *dev) | ||
599 | { | ||
600 | u32 reg = r592_read_reg(dev, R592_REG_MSC); | ||
601 | bool card_detected = reg & R592_REG_MSC_PRSNT; | ||
602 | |||
603 | dbg("update card detect. card state: %s", card_detected ? | ||
604 | "present" : "absent"); | ||
605 | |||
606 | reg &= ~((R592_REG_MSC_IRQ_REMOVE | R592_REG_MSC_IRQ_INSERT) << 16); | ||
607 | |||
608 | if (card_detected) | ||
609 | reg |= (R592_REG_MSC_IRQ_REMOVE << 16); | ||
610 | else | ||
611 | reg |= (R592_REG_MSC_IRQ_INSERT << 16); | ||
612 | |||
613 | r592_write_reg(dev, R592_REG_MSC, reg); | ||
614 | } | ||
615 | |||
616 | /* Timer routine that fires 1 second after last card detection event, */ | ||
617 | static void r592_detect_timer(long unsigned int data) | ||
618 | { | ||
619 | struct r592_device *dev = (struct r592_device *)data; | ||
620 | r592_update_card_detect(dev); | ||
621 | memstick_detect_change(dev->host); | ||
622 | } | ||
623 | |||
624 | /* Interrupt handler */ | ||
625 | static irqreturn_t r592_irq(int irq, void *data) | ||
626 | { | ||
627 | struct r592_device *dev = (struct r592_device *)data; | ||
628 | irqreturn_t ret = IRQ_NONE; | ||
629 | u32 reg; | ||
630 | u16 irq_enable, irq_status; | ||
631 | unsigned long flags; | ||
632 | int error; | ||
633 | |||
634 | spin_lock_irqsave(&dev->irq_lock, flags); | ||
635 | |||
636 | reg = r592_read_reg(dev, R592_REG_MSC); | ||
637 | irq_enable = reg >> 16; | ||
638 | irq_status = reg & 0xFFFF; | ||
639 | |||
640 | /* Ack the interrupts */ | ||
641 | reg &= ~irq_status; | ||
642 | r592_write_reg(dev, R592_REG_MSC, reg); | ||
643 | |||
644 | /* Get the IRQ status minus bits that aren't enabled */ | ||
645 | irq_status &= (irq_enable); | ||
646 | |||
647 | /* Due to limitation of memstick core, we don't look at bits that | ||
648 | indicate that card was removed/inserted and/or present */ | ||
649 | if (irq_status & (R592_REG_MSC_IRQ_INSERT | R592_REG_MSC_IRQ_REMOVE)) { | ||
650 | |||
651 | bool card_was_added = irq_status & R592_REG_MSC_IRQ_INSERT; | ||
652 | ret = IRQ_HANDLED; | ||
653 | |||
654 | message("IRQ: card %s", card_was_added ? "added" : "removed"); | ||
655 | |||
656 | mod_timer(&dev->detect_timer, | ||
657 | jiffies + msecs_to_jiffies(card_was_added ? 500 : 50)); | ||
658 | } | ||
659 | |||
660 | if (irq_status & | ||
661 | (R592_REG_MSC_FIFO_DMA_DONE | R592_REG_MSC_FIFO_DMA_ERR)) { | ||
662 | ret = IRQ_HANDLED; | ||
663 | |||
664 | if (irq_status & R592_REG_MSC_FIFO_DMA_ERR) { | ||
665 | message("IRQ: DMA error"); | ||
666 | error = -EIO; | ||
667 | } else { | ||
668 | dbg_verbose("IRQ: dma done"); | ||
669 | error = 0; | ||
670 | } | ||
671 | |||
672 | r592_stop_dma(dev, error); | ||
673 | complete(&dev->dma_done); | ||
674 | } | ||
675 | |||
676 | spin_unlock_irqrestore(&dev->irq_lock, flags); | ||
677 | return ret; | ||
678 | } | ||
679 | |||
680 | /* External inteface: set settings */ | ||
681 | static int r592_set_param(struct memstick_host *host, | ||
682 | enum memstick_param param, int value) | ||
683 | { | ||
684 | struct r592_device *dev = memstick_priv(host); | ||
685 | |||
686 | switch (param) { | ||
687 | case MEMSTICK_POWER: | ||
688 | switch (value) { | ||
689 | case MEMSTICK_POWER_ON: | ||
690 | return r592_enable_device(dev, true); | ||
691 | case MEMSTICK_POWER_OFF: | ||
692 | return r592_enable_device(dev, false); | ||
693 | default: | ||
694 | return -EINVAL; | ||
695 | } | ||
696 | case MEMSTICK_INTERFACE: | ||
697 | switch (value) { | ||
698 | case MEMSTICK_SERIAL: | ||
699 | return r592_set_mode(dev, 0); | ||
700 | case MEMSTICK_PAR4: | ||
701 | return r592_set_mode(dev, 1); | ||
702 | default: | ||
703 | return -EINVAL; | ||
704 | } | ||
705 | default: | ||
706 | return -EINVAL; | ||
707 | } | ||
708 | } | ||
709 | |||
710 | /* External interface: submit requests */ | ||
711 | static void r592_submit_req(struct memstick_host *host) | ||
712 | { | ||
713 | struct r592_device *dev = memstick_priv(host); | ||
714 | unsigned long flags; | ||
715 | |||
716 | if (dev->req) | ||
717 | return; | ||
718 | |||
719 | spin_lock_irqsave(&dev->io_thread_lock, flags); | ||
720 | if (wake_up_process(dev->io_thread)) | ||
721 | dbg_verbose("IO thread woken to process requests"); | ||
722 | spin_unlock_irqrestore(&dev->io_thread_lock, flags); | ||
723 | } | ||
724 | |||
725 | static const struct pci_device_id r592_pci_id_tbl[] = { | ||
726 | |||
727 | { PCI_VDEVICE(RICOH, 0x0592), }, | ||
728 | { }, | ||
729 | }; | ||
730 | |||
731 | /* Main entry */ | ||
732 | static int r592_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||
733 | { | ||
734 | int error = -ENOMEM; | ||
735 | struct memstick_host *host; | ||
736 | struct r592_device *dev; | ||
737 | |||
738 | /* Allocate memory */ | ||
739 | host = memstick_alloc_host(sizeof(struct r592_device), &pdev->dev); | ||
740 | if (!host) | ||
741 | goto error1; | ||
742 | |||
743 | dev = memstick_priv(host); | ||
744 | dev->host = host; | ||
745 | dev->pci_dev = pdev; | ||
746 | pci_set_drvdata(pdev, dev); | ||
747 | |||
748 | /* pci initialization */ | ||
749 | error = pci_enable_device(pdev); | ||
750 | if (error) | ||
751 | goto error2; | ||
752 | |||
753 | pci_set_master(pdev); | ||
754 | error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); | ||
755 | if (error) | ||
756 | goto error3; | ||
757 | |||
758 | error = pci_request_regions(pdev, DRV_NAME); | ||
759 | if (error) | ||
760 | goto error3; | ||
761 | |||
762 | dev->mmio = pci_ioremap_bar(pdev, 0); | ||
763 | if (!dev->mmio) | ||
764 | goto error4; | ||
765 | |||
766 | dev->irq = pdev->irq; | ||
767 | spin_lock_init(&dev->irq_lock); | ||
768 | spin_lock_init(&dev->io_thread_lock); | ||
769 | init_completion(&dev->dma_done); | ||
770 | INIT_KFIFO(dev->pio_fifo); | ||
771 | setup_timer(&dev->detect_timer, | ||
772 | r592_detect_timer, (long unsigned int)dev); | ||
773 | |||
774 | /* Host initialization */ | ||
775 | host->caps = MEMSTICK_CAP_PAR4; | ||
776 | host->request = r592_submit_req; | ||
777 | host->set_param = r592_set_param; | ||
778 | r592_check_dma(dev); | ||
779 | |||
780 | dev->io_thread = kthread_run(r592_process_thread, dev, "r592_io"); | ||
781 | if (IS_ERR(dev->io_thread)) { | ||
782 | error = PTR_ERR(dev->io_thread); | ||
783 | goto error5; | ||
784 | } | ||
785 | |||
786 | /* This is just a precation, so don't fail */ | ||
787 | dev->dummy_dma_page = pci_alloc_consistent(pdev, PAGE_SIZE, | ||
788 | &dev->dummy_dma_page_physical_address); | ||
789 | r592_stop_dma(dev , 0); | ||
790 | |||
791 | if (request_irq(dev->irq, &r592_irq, IRQF_SHARED, | ||
792 | DRV_NAME, dev)) | ||
793 | goto error6; | ||
794 | |||
795 | r592_update_card_detect(dev); | ||
796 | if (memstick_add_host(host)) | ||
797 | goto error7; | ||
798 | |||
799 | message("driver succesfully loaded"); | ||
800 | return 0; | ||
801 | error7: | ||
802 | free_irq(dev->irq, dev); | ||
803 | error6: | ||
804 | if (dev->dummy_dma_page) | ||
805 | pci_free_consistent(pdev, PAGE_SIZE, dev->dummy_dma_page, | ||
806 | dev->dummy_dma_page_physical_address); | ||
807 | |||
808 | kthread_stop(dev->io_thread); | ||
809 | error5: | ||
810 | iounmap(dev->mmio); | ||
811 | error4: | ||
812 | pci_release_regions(pdev); | ||
813 | error3: | ||
814 | pci_disable_device(pdev); | ||
815 | error2: | ||
816 | memstick_free_host(host); | ||
817 | error1: | ||
818 | return error; | ||
819 | } | ||
820 | |||
821 | static void r592_remove(struct pci_dev *pdev) | ||
822 | { | ||
823 | int error = 0; | ||
824 | struct r592_device *dev = pci_get_drvdata(pdev); | ||
825 | |||
826 | /* Stop the processing thread. | ||
827 | That ensures that we won't take any more requests */ | ||
828 | kthread_stop(dev->io_thread); | ||
829 | |||
830 | r592_enable_device(dev, false); | ||
831 | |||
832 | while (!error && dev->req) { | ||
833 | dev->req->error = -ETIME; | ||
834 | error = memstick_next_req(dev->host, &dev->req); | ||
835 | } | ||
836 | memstick_remove_host(dev->host); | ||
837 | |||
838 | free_irq(dev->irq, dev); | ||
839 | iounmap(dev->mmio); | ||
840 | pci_release_regions(pdev); | ||
841 | pci_disable_device(pdev); | ||
842 | memstick_free_host(dev->host); | ||
843 | |||
844 | if (dev->dummy_dma_page) | ||
845 | pci_free_consistent(pdev, PAGE_SIZE, dev->dummy_dma_page, | ||
846 | dev->dummy_dma_page_physical_address); | ||
847 | } | ||
848 | |||
849 | #ifdef CONFIG_PM | ||
850 | static int r592_suspend(struct device *core_dev) | ||
851 | { | ||
852 | struct pci_dev *pdev = to_pci_dev(core_dev); | ||
853 | struct r592_device *dev = pci_get_drvdata(pdev); | ||
854 | |||
855 | r592_clear_interrupts(dev); | ||
856 | memstick_suspend_host(dev->host); | ||
857 | del_timer_sync(&dev->detect_timer); | ||
858 | return 0; | ||
859 | } | ||
860 | |||
861 | static int r592_resume(struct device *core_dev) | ||
862 | { | ||
863 | struct pci_dev *pdev = to_pci_dev(core_dev); | ||
864 | struct r592_device *dev = pci_get_drvdata(pdev); | ||
865 | |||
866 | r592_clear_interrupts(dev); | ||
867 | r592_enable_device(dev, false); | ||
868 | memstick_resume_host(dev->host); | ||
869 | r592_update_card_detect(dev); | ||
870 | return 0; | ||
871 | } | ||
872 | |||
873 | SIMPLE_DEV_PM_OPS(r592_pm_ops, r592_suspend, r592_resume); | ||
874 | #endif | ||
875 | |||
876 | MODULE_DEVICE_TABLE(pci, r592_pci_id_tbl); | ||
877 | |||
878 | static struct pci_driver r852_pci_driver = { | ||
879 | .name = DRV_NAME, | ||
880 | .id_table = r592_pci_id_tbl, | ||
881 | .probe = r592_probe, | ||
882 | .remove = r592_remove, | ||
883 | #ifdef CONFIG_PM | ||
884 | .driver.pm = &r592_pm_ops, | ||
885 | #endif | ||
886 | }; | ||
887 | |||
888 | static __init int r592_module_init(void) | ||
889 | { | ||
890 | return pci_register_driver(&r852_pci_driver); | ||
891 | } | ||
892 | |||
893 | static void __exit r592_module_exit(void) | ||
894 | { | ||
895 | pci_unregister_driver(&r852_pci_driver); | ||
896 | } | ||
897 | |||
898 | module_init(r592_module_init); | ||
899 | module_exit(r592_module_exit); | ||
900 | |||
901 | module_param(enable_dma, bool, S_IRUGO); | ||
902 | MODULE_PARM_DESC(enable_dma, "Enable usage of the DMA (default)"); | ||
903 | module_param(debug, int, S_IRUGO | S_IWUSR); | ||
904 | MODULE_PARM_DESC(debug, "Debug level (0-3)"); | ||
905 | |||
906 | MODULE_LICENSE("GPL"); | ||
907 | MODULE_AUTHOR("Maxim Levitsky <maximlevitsky@gmail.com>"); | ||
908 | MODULE_DESCRIPTION("Ricoh R5C592 Memstick/Memstick PRO card reader driver"); | ||
diff --git a/drivers/memstick/host/r592.h b/drivers/memstick/host/r592.h new file mode 100644 index 000000000000..eee264e6028f --- /dev/null +++ b/drivers/memstick/host/r592.h | |||
@@ -0,0 +1,175 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 - Maxim Levitsky | ||
3 | * driver for Ricoh memstick readers | ||
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 | #ifndef R592_H | ||
11 | |||
12 | #include <linux/memstick.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/workqueue.h> | ||
16 | #include <linux/kfifo.h> | ||
17 | #include <linux/ctype.h> | ||
18 | |||
19 | /* write to this reg (number,len) triggers TPC execution */ | ||
20 | #define R592_TPC_EXEC 0x00 | ||
21 | #define R592_TPC_EXEC_LEN_SHIFT 16 /* Bits 16..25 are TPC len */ | ||
22 | #define R592_TPC_EXEC_BIG_FIFO (1 << 26) /* If bit 26 is set, large fifo is used (reg 48) */ | ||
23 | #define R592_TPC_EXEC_TPC_SHIFT 28 /* Bits 28..31 are the TPC number */ | ||
24 | |||
25 | |||
26 | /* Window for small TPC fifo (big endian)*/ | ||
27 | /* reads and writes always are done in 8 byte chunks */ | ||
28 | /* Not used in driver, because large fifo does better job */ | ||
29 | #define R592_SFIFO 0x08 | ||
30 | |||
31 | |||
32 | /* Status register (ms int, small fifo, IO)*/ | ||
33 | #define R592_STATUS 0x10 | ||
34 | /* Parallel INT bits */ | ||
35 | #define R592_STATUS_P_CMDNACK (1 << 16) /* INT reg: NACK (parallel mode) */ | ||
36 | #define R592_STATUS_P_BREQ (1 << 17) /* INT reg: card ready (parallel mode)*/ | ||
37 | #define R592_STATUS_P_INTERR (1 << 18) /* INT reg: int error (parallel mode)*/ | ||
38 | #define R592_STATUS_P_CED (1 << 19) /* INT reg: command done (parallel mode) */ | ||
39 | |||
40 | /* Fifo status */ | ||
41 | #define R592_STATUS_SFIFO_FULL (1 << 20) /* Small Fifo almost full (last chunk is written) */ | ||
42 | #define R592_STATUS_SFIFO_EMPTY (1 << 21) /* Small Fifo empty */ | ||
43 | |||
44 | /* Error detection via CRC */ | ||
45 | #define R592_STATUS_SEND_ERR (1 << 24) /* Send failed */ | ||
46 | #define R592_STATUS_RECV_ERR (1 << 25) /* Recieve failed */ | ||
47 | |||
48 | /* Card state */ | ||
49 | #define R592_STATUS_RDY (1 << 28) /* RDY signal recieved */ | ||
50 | #define R592_STATUS_CED (1 << 29) /* INT: Command done (serial mode)*/ | ||
51 | #define R592_STATUS_SFIFO_INPUT (1 << 30) /* Small fifo recieved data*/ | ||
52 | |||
53 | #define R592_SFIFO_SIZE 32 /* total size of small fifo is 32 bytes */ | ||
54 | #define R592_SFIFO_PACKET 8 /* packet size of small fifo */ | ||
55 | |||
56 | /* IO control */ | ||
57 | #define R592_IO 0x18 | ||
58 | #define R592_IO_16 (1 << 16) /* Set by default, can be cleared */ | ||
59 | #define R592_IO_18 (1 << 18) /* Set by default, can be cleared */ | ||
60 | #define R592_IO_SERIAL1 (1 << 20) /* Set by default, can be cleared, (cleared on parallel) */ | ||
61 | #define R592_IO_22 (1 << 22) /* Set by default, can be cleared */ | ||
62 | #define R592_IO_DIRECTION (1 << 24) /* TPC direction (1 write 0 read) */ | ||
63 | #define R592_IO_26 (1 << 26) /* Set by default, can be cleared */ | ||
64 | #define R592_IO_SERIAL2 (1 << 30) /* Set by default, can be cleared (cleared on parallel), serial doesn't work if unset */ | ||
65 | #define R592_IO_RESET (1 << 31) /* Reset, sets defaults*/ | ||
66 | |||
67 | |||
68 | /* Turns hardware on/off */ | ||
69 | #define R592_POWER 0x20 /* bits 0-7 writeable */ | ||
70 | #define R592_POWER_0 (1 << 0) /* set on start, cleared on stop - must be set*/ | ||
71 | #define R592_POWER_1 (1 << 1) /* set on start, cleared on stop - must be set*/ | ||
72 | #define R592_POWER_3 (1 << 3) /* must be clear */ | ||
73 | #define R592_POWER_20 (1 << 5) /* set before switch to parallel */ | ||
74 | |||
75 | /* IO mode*/ | ||
76 | #define R592_IO_MODE 0x24 | ||
77 | #define R592_IO_MODE_SERIAL 1 | ||
78 | #define R592_IO_MODE_PARALLEL 3 | ||
79 | |||
80 | |||
81 | /* IRQ,card detection,large fifo (first word irq status, second enable) */ | ||
82 | /* IRQs are ACKed by clearing the bits */ | ||
83 | #define R592_REG_MSC 0x28 | ||
84 | #define R592_REG_MSC_PRSNT (1 << 1) /* card present (only status)*/ | ||
85 | #define R592_REG_MSC_IRQ_INSERT (1 << 8) /* detect insert / card insered */ | ||
86 | #define R592_REG_MSC_IRQ_REMOVE (1 << 9) /* detect removal / card removed */ | ||
87 | #define R592_REG_MSC_FIFO_EMPTY (1 << 10) /* fifo is empty */ | ||
88 | #define R592_REG_MSC_FIFO_DMA_DONE (1 << 11) /* dma enable / dma done */ | ||
89 | |||
90 | #define R592_REG_MSC_FIFO_USER_ORN (1 << 12) /* set if software reads empty fifo (if R592_REG_MSC_FIFO_EMPTY is set) */ | ||
91 | #define R592_REG_MSC_FIFO_MISMATH (1 << 13) /* set if amount of data in fifo doesn't match amount in TPC */ | ||
92 | #define R592_REG_MSC_FIFO_DMA_ERR (1 << 14) /* IO failure */ | ||
93 | #define R592_REG_MSC_LED (1 << 15) /* clear to turn led off (only status)*/ | ||
94 | |||
95 | #define DMA_IRQ_ACK_MASK \ | ||
96 | (R592_REG_MSC_FIFO_DMA_DONE | R592_REG_MSC_FIFO_DMA_ERR) | ||
97 | |||
98 | #define DMA_IRQ_EN_MASK (DMA_IRQ_ACK_MASK << 16) | ||
99 | |||
100 | #define IRQ_ALL_ACK_MASK 0x00007F00 | ||
101 | #define IRQ_ALL_EN_MASK (IRQ_ALL_ACK_MASK << 16) | ||
102 | |||
103 | /* DMA address for large FIFO read/writes*/ | ||
104 | #define R592_FIFO_DMA 0x2C | ||
105 | |||
106 | /* PIO access to large FIFO (512 bytes) (big endian)*/ | ||
107 | #define R592_FIFO_PIO 0x30 | ||
108 | #define R592_LFIFO_SIZE 512 /* large fifo size */ | ||
109 | |||
110 | |||
111 | /* large FIFO DMA settings */ | ||
112 | #define R592_FIFO_DMA_SETTINGS 0x34 | ||
113 | #define R592_FIFO_DMA_SETTINGS_EN (1 << 0) /* DMA enabled */ | ||
114 | #define R592_FIFO_DMA_SETTINGS_DIR (1 << 1) /* Dma direction (1 read, 0 write) */ | ||
115 | #define R592_FIFO_DMA_SETTINGS_CAP (1 << 24) /* Dma is aviable */ | ||
116 | |||
117 | /* Maybe just an delay */ | ||
118 | /* Bits 17..19 are just number */ | ||
119 | /* bit 16 is set, then bit 20 is waited */ | ||
120 | /* time to wait is about 50 spins * 2 ^ (bits 17..19) */ | ||
121 | /* seems to be possible just to ignore */ | ||
122 | /* Probably debug register */ | ||
123 | #define R592_REG38 0x38 | ||
124 | #define R592_REG38_CHANGE (1 << 16) /* Start bit */ | ||
125 | #define R592_REG38_DONE (1 << 20) /* HW set this after the delay */ | ||
126 | #define R592_REG38_SHIFT 17 | ||
127 | |||
128 | /* Debug register, written (0xABCDEF00) when error happens - not used*/ | ||
129 | #define R592_REG_3C 0x3C | ||
130 | |||
131 | struct r592_device { | ||
132 | struct pci_dev *pci_dev; | ||
133 | struct memstick_host *host; /* host backpointer */ | ||
134 | struct memstick_request *req; /* current request */ | ||
135 | |||
136 | /* Registers, IRQ */ | ||
137 | void __iomem *mmio; | ||
138 | int irq; | ||
139 | spinlock_t irq_lock; | ||
140 | spinlock_t io_thread_lock; | ||
141 | struct timer_list detect_timer; | ||
142 | |||
143 | struct task_struct *io_thread; | ||
144 | bool parallel_mode; | ||
145 | |||
146 | DECLARE_KFIFO(pio_fifo, u8, sizeof(u32)); | ||
147 | |||
148 | /* DMA area */ | ||
149 | int dma_capable; | ||
150 | int dma_error; | ||
151 | struct completion dma_done; | ||
152 | void *dummy_dma_page; | ||
153 | dma_addr_t dummy_dma_page_physical_address; | ||
154 | |||
155 | }; | ||
156 | |||
157 | #define DRV_NAME "r592" | ||
158 | |||
159 | |||
160 | #define message(format, ...) \ | ||
161 | printk(KERN_INFO DRV_NAME ": " format "\n", ## __VA_ARGS__) | ||
162 | |||
163 | #define __dbg(level, format, ...) \ | ||
164 | do { \ | ||
165 | if (debug >= level) \ | ||
166 | printk(KERN_DEBUG DRV_NAME \ | ||
167 | ": " format "\n", ## __VA_ARGS__); \ | ||
168 | } while (0) | ||
169 | |||
170 | |||
171 | #define dbg(format, ...) __dbg(1, format, ## __VA_ARGS__) | ||
172 | #define dbg_verbose(format, ...) __dbg(2, format, ## __VA_ARGS__) | ||
173 | #define dbg_reg(format, ...) __dbg(3, format, ## __VA_ARGS__) | ||
174 | |||
175 | #endif | ||
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 9c511c1604a5..011cb6ce861b 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c | |||
@@ -416,7 +416,6 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, | |||
416 | : chip->companion; | 416 | : chip->companion; |
417 | unsigned char status_buf[INT_STATUS_NUM]; | 417 | unsigned char status_buf[INT_STATUS_NUM]; |
418 | unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; | 418 | unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; |
419 | struct irq_desc *desc; | ||
420 | int i, data, mask, ret = -EINVAL; | 419 | int i, data, mask, ret = -EINVAL; |
421 | int __irq; | 420 | int __irq; |
422 | 421 | ||
@@ -468,19 +467,17 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, | |||
468 | if (!chip->core_irq) | 467 | if (!chip->core_irq) |
469 | goto out; | 468 | goto out; |
470 | 469 | ||
471 | desc = irq_to_desc(chip->core_irq); | ||
472 | |||
473 | /* register IRQ by genirq */ | 470 | /* register IRQ by genirq */ |
474 | for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { | 471 | for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { |
475 | __irq = i + chip->irq_base; | 472 | __irq = i + chip->irq_base; |
476 | set_irq_chip_data(__irq, chip); | 473 | irq_set_chip_data(__irq, chip); |
477 | set_irq_chip_and_handler(__irq, &pm860x_irq_chip, | 474 | irq_set_chip_and_handler(__irq, &pm860x_irq_chip, |
478 | handle_edge_irq); | 475 | handle_edge_irq); |
479 | set_irq_nested_thread(__irq, 1); | 476 | irq_set_nested_thread(__irq, 1); |
480 | #ifdef CONFIG_ARM | 477 | #ifdef CONFIG_ARM |
481 | set_irq_flags(__irq, IRQF_VALID); | 478 | set_irq_flags(__irq, IRQF_VALID); |
482 | #else | 479 | #else |
483 | set_irq_noprobe(__irq); | 480 | irq_set_noprobe(__irq); |
484 | #endif | 481 | #endif |
485 | } | 482 | } |
486 | 483 | ||
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index a9a1af49281e..e986f91fff9c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -133,6 +133,7 @@ config TPS6105X | |||
133 | tristate "TPS61050/61052 Boost Converters" | 133 | tristate "TPS61050/61052 Boost Converters" |
134 | depends on I2C | 134 | depends on I2C |
135 | select REGULATOR | 135 | select REGULATOR |
136 | select MFD_CORE | ||
136 | select REGULATOR_FIXED_VOLTAGE | 137 | select REGULATOR_FIXED_VOLTAGE |
137 | help | 138 | help |
138 | This option enables a driver for the TP61050/TPS61052 | 139 | This option enables a driver for the TP61050/TPS61052 |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 47f5709f3828..ef489f253402 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -63,7 +63,7 @@ obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o | |||
63 | obj-$(CONFIG_PMIC_DA903X) += da903x.o | 63 | obj-$(CONFIG_PMIC_DA903X) += da903x.o |
64 | max8925-objs := max8925-core.o max8925-i2c.o | 64 | max8925-objs := max8925-core.o max8925-i2c.o |
65 | obj-$(CONFIG_MFD_MAX8925) += max8925.o | 65 | obj-$(CONFIG_MFD_MAX8925) += max8925.o |
66 | obj-$(CONFIG_MFD_MAX8997) += max8997.o | 66 | obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o |
67 | obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o | 67 | obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o |
68 | 68 | ||
69 | pcf50633-objs := pcf50633-core.o pcf50633-irq.o | 69 | pcf50633-objs := pcf50633-core.o pcf50633-irq.o |
diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c index c12d04285226..ff86acf3e6bd 100644 --- a/drivers/mfd/ab3550-core.c +++ b/drivers/mfd/ab3550-core.c | |||
@@ -668,7 +668,7 @@ static int ab3550_startup_irq_enabled(struct device *dev, unsigned int irq) | |||
668 | struct ab3550_platform_data *plf_data; | 668 | struct ab3550_platform_data *plf_data; |
669 | bool val; | 669 | bool val; |
670 | 670 | ||
671 | ab = get_irq_chip_data(irq); | 671 | ab = irq_get_chip_data(irq); |
672 | plf_data = ab->i2c_client[0]->dev.platform_data; | 672 | plf_data = ab->i2c_client[0]->dev.platform_data; |
673 | irq -= plf_data->irq.base; | 673 | irq -= plf_data->irq.base; |
674 | val = ((ab->startup_events[irq / 8] & BIT(irq % 8)) != 0); | 674 | val = ((ab->startup_events[irq / 8] & BIT(irq % 8)) != 0); |
@@ -1296,14 +1296,14 @@ static int __init ab3550_probe(struct i2c_client *client, | |||
1296 | unsigned int irq; | 1296 | unsigned int irq; |
1297 | 1297 | ||
1298 | irq = ab3550_plf_data->irq.base + i; | 1298 | irq = ab3550_plf_data->irq.base + i; |
1299 | set_irq_chip_data(irq, ab); | 1299 | irq_set_chip_data(irq, ab); |
1300 | set_irq_chip_and_handler(irq, &ab3550_irq_chip, | 1300 | irq_set_chip_and_handler(irq, &ab3550_irq_chip, |
1301 | handle_simple_irq); | 1301 | handle_simple_irq); |
1302 | set_irq_nested_thread(irq, 1); | 1302 | irq_set_nested_thread(irq, 1); |
1303 | #ifdef CONFIG_ARM | 1303 | #ifdef CONFIG_ARM |
1304 | set_irq_flags(irq, IRQF_VALID); | 1304 | set_irq_flags(irq, IRQF_VALID); |
1305 | #else | 1305 | #else |
1306 | set_irq_noprobe(irq); | 1306 | irq_set_noprobe(irq); |
1307 | #endif | 1307 | #endif |
1308 | } | 1308 | } |
1309 | 1309 | ||
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 6e185b272d00..62e33e2258d4 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c | |||
@@ -334,14 +334,14 @@ static int ab8500_irq_init(struct ab8500 *ab8500) | |||
334 | int irq; | 334 | int irq; |
335 | 335 | ||
336 | for (irq = base; irq < base + AB8500_NR_IRQS; irq++) { | 336 | for (irq = base; irq < base + AB8500_NR_IRQS; irq++) { |
337 | set_irq_chip_data(irq, ab8500); | 337 | irq_set_chip_data(irq, ab8500); |
338 | set_irq_chip_and_handler(irq, &ab8500_irq_chip, | 338 | irq_set_chip_and_handler(irq, &ab8500_irq_chip, |
339 | handle_simple_irq); | 339 | handle_simple_irq); |
340 | set_irq_nested_thread(irq, 1); | 340 | irq_set_nested_thread(irq, 1); |
341 | #ifdef CONFIG_ARM | 341 | #ifdef CONFIG_ARM |
342 | set_irq_flags(irq, IRQF_VALID); | 342 | set_irq_flags(irq, IRQF_VALID); |
343 | #else | 343 | #else |
344 | set_irq_noprobe(irq); | 344 | irq_set_noprobe(irq); |
345 | #endif | 345 | #endif |
346 | } | 346 | } |
347 | 347 | ||
@@ -357,8 +357,8 @@ static void ab8500_irq_remove(struct ab8500 *ab8500) | |||
357 | #ifdef CONFIG_ARM | 357 | #ifdef CONFIG_ARM |
358 | set_irq_flags(irq, 0); | 358 | set_irq_flags(irq, 0); |
359 | #endif | 359 | #endif |
360 | set_irq_chip_and_handler(irq, NULL, NULL); | 360 | irq_set_chip_and_handler(irq, NULL, NULL); |
361 | set_irq_chip_data(irq, NULL); | 361 | irq_set_chip_data(irq, NULL); |
362 | } | 362 | } |
363 | } | 363 | } |
364 | 364 | ||
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 0241f08fc00d..d4a851c6b5bf 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c | |||
@@ -139,13 +139,12 @@ static void asic3_irq_flip_edge(struct asic3 *asic, | |||
139 | 139 | ||
140 | static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) | 140 | static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) |
141 | { | 141 | { |
142 | struct asic3 *asic = irq_desc_get_handler_data(desc); | ||
143 | struct irq_data *data = irq_desc_get_irq_data(desc); | ||
142 | int iter, i; | 144 | int iter, i; |
143 | unsigned long flags; | 145 | unsigned long flags; |
144 | struct asic3 *asic; | ||
145 | |||
146 | desc->irq_data.chip->irq_ack(&desc->irq_data); | ||
147 | 146 | ||
148 | asic = get_irq_data(irq); | 147 | data->chip->irq_ack(irq_data); |
149 | 148 | ||
150 | for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) { | 149 | for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) { |
151 | u32 status; | 150 | u32 status; |
@@ -188,8 +187,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) | |||
188 | irqnr = asic->irq_base + | 187 | irqnr = asic->irq_base + |
189 | (ASIC3_GPIOS_PER_BANK * bank) | 188 | (ASIC3_GPIOS_PER_BANK * bank) |
190 | + i; | 189 | + i; |
191 | desc = irq_to_desc(irqnr); | 190 | generic_handle_irq(irqnr); |
192 | desc->handle_irq(irqnr, desc); | ||
193 | if (asic->irq_bothedge[bank] & bit) | 191 | if (asic->irq_bothedge[bank] & bit) |
194 | asic3_irq_flip_edge(asic, base, | 192 | asic3_irq_flip_edge(asic, base, |
195 | bit); | 193 | bit); |
@@ -200,11 +198,8 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) | |||
200 | /* Handle remaining IRQs in the status register */ | 198 | /* Handle remaining IRQs in the status register */ |
201 | for (i = ASIC3_NUM_GPIOS; i < ASIC3_NR_IRQS; i++) { | 199 | for (i = ASIC3_NUM_GPIOS; i < ASIC3_NR_IRQS; i++) { |
202 | /* They start at bit 4 and go up */ | 200 | /* They start at bit 4 and go up */ |
203 | if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) { | 201 | if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) |
204 | desc = irq_to_desc(asic->irq_base + i); | 202 | generic_handle_irq(asic->irq_base + i); |
205 | desc->handle_irq(asic->irq_base + i, | ||
206 | desc); | ||
207 | } | ||
208 | } | 203 | } |
209 | } | 204 | } |
210 | 205 | ||
@@ -393,21 +388,21 @@ static int __init asic3_irq_probe(struct platform_device *pdev) | |||
393 | 388 | ||
394 | for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { | 389 | for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { |
395 | if (irq < asic->irq_base + ASIC3_NUM_GPIOS) | 390 | if (irq < asic->irq_base + ASIC3_NUM_GPIOS) |
396 | set_irq_chip(irq, &asic3_gpio_irq_chip); | 391 | irq_set_chip(irq, &asic3_gpio_irq_chip); |
397 | else | 392 | else |
398 | set_irq_chip(irq, &asic3_irq_chip); | 393 | irq_set_chip(irq, &asic3_irq_chip); |
399 | 394 | ||
400 | set_irq_chip_data(irq, asic); | 395 | irq_set_chip_data(irq, asic); |
401 | set_irq_handler(irq, handle_level_irq); | 396 | irq_set_handler(irq, handle_level_irq); |
402 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 397 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
403 | } | 398 | } |
404 | 399 | ||
405 | asic3_write_register(asic, ASIC3_OFFSET(INTR, INT_MASK), | 400 | asic3_write_register(asic, ASIC3_OFFSET(INTR, INT_MASK), |
406 | ASIC3_INTMASK_GINTMASK); | 401 | ASIC3_INTMASK_GINTMASK); |
407 | 402 | ||
408 | set_irq_chained_handler(asic->irq_nr, asic3_irq_demux); | 403 | irq_set_chained_handler(asic->irq_nr, asic3_irq_demux); |
409 | set_irq_type(asic->irq_nr, IRQ_TYPE_EDGE_RISING); | 404 | irq_set_irq_type(asic->irq_nr, IRQ_TYPE_EDGE_RISING); |
410 | set_irq_data(asic->irq_nr, asic); | 405 | irq_set_handler_data(asic->irq_nr, asic); |
411 | 406 | ||
412 | return 0; | 407 | return 0; |
413 | } | 408 | } |
@@ -421,11 +416,10 @@ static void asic3_irq_remove(struct platform_device *pdev) | |||
421 | 416 | ||
422 | for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { | 417 | for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { |
423 | set_irq_flags(irq, 0); | 418 | set_irq_flags(irq, 0); |
424 | set_irq_handler(irq, NULL); | 419 | irq_set_chip_and_handler(irq, NULL, NULL); |
425 | set_irq_chip(irq, NULL); | 420 | irq_set_chip_data(irq, NULL); |
426 | set_irq_chip_data(irq, NULL); | ||
427 | } | 421 | } |
428 | set_irq_chained_handler(asic->irq_nr, NULL); | 422 | irq_set_chained_handler(asic->irq_nr, NULL); |
429 | } | 423 | } |
430 | 424 | ||
431 | /* GPIOs */ | 425 | /* GPIOs */ |
diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c index 886a06871065..155fa0407882 100644 --- a/drivers/mfd/cs5535-mfd.c +++ b/drivers/mfd/cs5535-mfd.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/mfd/core.h> | 27 | #include <linux/mfd/core.h> |
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
30 | #include <asm/olpc.h> | ||
30 | 31 | ||
31 | #define DRV_NAME "cs5535-mfd" | 32 | #define DRV_NAME "cs5535-mfd" |
32 | 33 | ||
@@ -111,6 +112,20 @@ static __devinitdata struct mfd_cell cs5535_mfd_cells[] = { | |||
111 | }, | 112 | }, |
112 | }; | 113 | }; |
113 | 114 | ||
115 | #ifdef CONFIG_OLPC | ||
116 | static void __devinit cs5535_clone_olpc_cells(void) | ||
117 | { | ||
118 | const char *acpi_clones[] = { "olpc-xo1-pm-acpi", "olpc-xo1-sci-acpi" }; | ||
119 | |||
120 | if (!machine_is_olpc()) | ||
121 | return; | ||
122 | |||
123 | mfd_clone_cell("cs5535-acpi", acpi_clones, ARRAY_SIZE(acpi_clones)); | ||
124 | } | ||
125 | #else | ||
126 | static void cs5535_clone_olpc_cells(void) { } | ||
127 | #endif | ||
128 | |||
114 | static int __devinit cs5535_mfd_probe(struct pci_dev *pdev, | 129 | static int __devinit cs5535_mfd_probe(struct pci_dev *pdev, |
115 | const struct pci_device_id *id) | 130 | const struct pci_device_id *id) |
116 | { | 131 | { |
@@ -139,6 +154,7 @@ static int __devinit cs5535_mfd_probe(struct pci_dev *pdev, | |||
139 | dev_err(&pdev->dev, "MFD add devices failed: %d\n", err); | 154 | dev_err(&pdev->dev, "MFD add devices failed: %d\n", err); |
140 | goto err_disable; | 155 | goto err_disable; |
141 | } | 156 | } |
157 | cs5535_clone_olpc_cells(); | ||
142 | 158 | ||
143 | dev_info(&pdev->dev, "%zu devices registered.\n", | 159 | dev_info(&pdev->dev, "%zu devices registered.\n", |
144 | ARRAY_SIZE(cs5535_mfd_cells)); | 160 | ARRAY_SIZE(cs5535_mfd_cells)); |
diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 9e2d8dd5f9e5..f2f4029e21a0 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c | |||
@@ -162,6 +162,7 @@ static void pcap_unmask_irq(struct irq_data *d) | |||
162 | 162 | ||
163 | static struct irq_chip pcap_irq_chip = { | 163 | static struct irq_chip pcap_irq_chip = { |
164 | .name = "pcap", | 164 | .name = "pcap", |
165 | .irq_disable = pcap_mask_irq, | ||
165 | .irq_mask = pcap_mask_irq, | 166 | .irq_mask = pcap_mask_irq, |
166 | .irq_unmask = pcap_unmask_irq, | 167 | .irq_unmask = pcap_unmask_irq, |
167 | }; | 168 | }; |
@@ -196,17 +197,8 @@ static void pcap_isr_work(struct work_struct *work) | |||
196 | local_irq_disable(); | 197 | local_irq_disable(); |
197 | service = isr & ~msr; | 198 | service = isr & ~msr; |
198 | for (irq = pcap->irq_base; service; service >>= 1, irq++) { | 199 | for (irq = pcap->irq_base; service; service >>= 1, irq++) { |
199 | if (service & 1) { | 200 | if (service & 1) |
200 | struct irq_desc *desc = irq_to_desc(irq); | 201 | generic_handle_irq(irq); |
201 | |||
202 | if (WARN(!desc, "Invalid PCAP IRQ %d\n", irq)) | ||
203 | break; | ||
204 | |||
205 | if (desc->status & IRQ_DISABLED) | ||
206 | note_interrupt(irq, desc, IRQ_NONE); | ||
207 | else | ||
208 | desc->handle_irq(irq, desc); | ||
209 | } | ||
210 | } | 202 | } |
211 | local_irq_enable(); | 203 | local_irq_enable(); |
212 | ezx_pcap_write(pcap, PCAP_REG_MSR, pcap->msr); | 204 | ezx_pcap_write(pcap, PCAP_REG_MSR, pcap->msr); |
@@ -215,7 +207,7 @@ static void pcap_isr_work(struct work_struct *work) | |||
215 | 207 | ||
216 | static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc) | 208 | static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc) |
217 | { | 209 | { |
218 | struct pcap_chip *pcap = get_irq_data(irq); | 210 | struct pcap_chip *pcap = irq_get_handler_data(irq); |
219 | 211 | ||
220 | desc->irq_data.chip->irq_ack(&desc->irq_data); | 212 | desc->irq_data.chip->irq_ack(&desc->irq_data); |
221 | queue_work(pcap->workqueue, &pcap->isr_work); | 213 | queue_work(pcap->workqueue, &pcap->isr_work); |
@@ -419,7 +411,7 @@ static int __devexit ezx_pcap_remove(struct spi_device *spi) | |||
419 | 411 | ||
420 | /* cleanup irqchip */ | 412 | /* cleanup irqchip */ |
421 | for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) | 413 | for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) |
422 | set_irq_chip_and_handler(i, NULL, NULL); | 414 | irq_set_chip_and_handler(i, NULL, NULL); |
423 | 415 | ||
424 | destroy_workqueue(pcap->workqueue); | 416 | destroy_workqueue(pcap->workqueue); |
425 | 417 | ||
@@ -476,12 +468,12 @@ static int __devinit ezx_pcap_probe(struct spi_device *spi) | |||
476 | 468 | ||
477 | /* setup irq chip */ | 469 | /* setup irq chip */ |
478 | for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) { | 470 | for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) { |
479 | set_irq_chip_and_handler(i, &pcap_irq_chip, handle_simple_irq); | 471 | irq_set_chip_and_handler(i, &pcap_irq_chip, handle_simple_irq); |
480 | set_irq_chip_data(i, pcap); | 472 | irq_set_chip_data(i, pcap); |
481 | #ifdef CONFIG_ARM | 473 | #ifdef CONFIG_ARM |
482 | set_irq_flags(i, IRQF_VALID); | 474 | set_irq_flags(i, IRQF_VALID); |
483 | #else | 475 | #else |
484 | set_irq_noprobe(i); | 476 | irq_set_noprobe(i); |
485 | #endif | 477 | #endif |
486 | } | 478 | } |
487 | 479 | ||
@@ -490,10 +482,10 @@ static int __devinit ezx_pcap_probe(struct spi_device *spi) | |||
490 | ezx_pcap_write(pcap, PCAP_REG_ISR, PCAP_CLEAR_INTERRUPT_REGISTER); | 482 | ezx_pcap_write(pcap, PCAP_REG_ISR, PCAP_CLEAR_INTERRUPT_REGISTER); |
491 | pcap->msr = PCAP_MASK_ALL_INTERRUPT; | 483 | pcap->msr = PCAP_MASK_ALL_INTERRUPT; |
492 | 484 | ||
493 | set_irq_type(spi->irq, IRQ_TYPE_EDGE_RISING); | 485 | irq_set_irq_type(spi->irq, IRQ_TYPE_EDGE_RISING); |
494 | set_irq_data(spi->irq, pcap); | 486 | irq_set_handler_data(spi->irq, pcap); |
495 | set_irq_chained_handler(spi->irq, pcap_irq_handler); | 487 | irq_set_chained_handler(spi->irq, pcap_irq_handler); |
496 | set_irq_wake(spi->irq, 1); | 488 | irq_set_irq_wake(spi->irq, 1); |
497 | 489 | ||
498 | /* ADC */ | 490 | /* ADC */ |
499 | adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? | 491 | adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? |
@@ -522,7 +514,7 @@ remove_subdevs: | |||
522 | free_irq(adc_irq, pcap); | 514 | free_irq(adc_irq, pcap); |
523 | free_irqchip: | 515 | free_irqchip: |
524 | for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) | 516 | for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) |
525 | set_irq_chip_and_handler(i, NULL, NULL); | 517 | irq_set_chip_and_handler(i, NULL, NULL); |
526 | /* destroy_workqueue: */ | 518 | /* destroy_workqueue: */ |
527 | destroy_workqueue(pcap->workqueue); | 519 | destroy_workqueue(pcap->workqueue); |
528 | free_pcap: | 520 | free_pcap: |
diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c index d00b6d1a69e5..bbaec0ccba8f 100644 --- a/drivers/mfd/htc-egpio.c +++ b/drivers/mfd/htc-egpio.c | |||
@@ -100,7 +100,7 @@ static struct irq_chip egpio_muxed_chip = { | |||
100 | 100 | ||
101 | static void egpio_handler(unsigned int irq, struct irq_desc *desc) | 101 | static void egpio_handler(unsigned int irq, struct irq_desc *desc) |
102 | { | 102 | { |
103 | struct egpio_info *ei = get_irq_data(irq); | 103 | struct egpio_info *ei = irq_desc_get_handler_data(desc); |
104 | int irqpin; | 104 | int irqpin; |
105 | 105 | ||
106 | /* Read current pins. */ | 106 | /* Read current pins. */ |
@@ -113,9 +113,7 @@ static void egpio_handler(unsigned int irq, struct irq_desc *desc) | |||
113 | for_each_set_bit(irqpin, &readval, ei->nirqs) { | 113 | for_each_set_bit(irqpin, &readval, ei->nirqs) { |
114 | /* Run irq handler */ | 114 | /* Run irq handler */ |
115 | pr_debug("got IRQ %d\n", irqpin); | 115 | pr_debug("got IRQ %d\n", irqpin); |
116 | irq = ei->irq_start + irqpin; | 116 | generic_handle_irq(ei->irq_start + irqpin); |
117 | desc = irq_to_desc(irq); | ||
118 | desc->handle_irq(irq, desc); | ||
119 | } | 117 | } |
120 | } | 118 | } |
121 | 119 | ||
@@ -346,14 +344,14 @@ static int __init egpio_probe(struct platform_device *pdev) | |||
346 | ei->ack_write = 0; | 344 | ei->ack_write = 0; |
347 | irq_end = ei->irq_start + ei->nirqs; | 345 | irq_end = ei->irq_start + ei->nirqs; |
348 | for (irq = ei->irq_start; irq < irq_end; irq++) { | 346 | for (irq = ei->irq_start; irq < irq_end; irq++) { |
349 | set_irq_chip(irq, &egpio_muxed_chip); | 347 | irq_set_chip_and_handler(irq, &egpio_muxed_chip, |
350 | set_irq_chip_data(irq, ei); | 348 | handle_simple_irq); |
351 | set_irq_handler(irq, handle_simple_irq); | 349 | irq_set_chip_data(irq, ei); |
352 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 350 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
353 | } | 351 | } |
354 | set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING); | 352 | irq_set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING); |
355 | set_irq_data(ei->chained_irq, ei); | 353 | irq_set_handler_data(ei->chained_irq, ei); |
356 | set_irq_chained_handler(ei->chained_irq, egpio_handler); | 354 | irq_set_chained_handler(ei->chained_irq, egpio_handler); |
357 | ack_irqs(ei); | 355 | ack_irqs(ei); |
358 | 356 | ||
359 | device_init_wakeup(&pdev->dev, 1); | 357 | device_init_wakeup(&pdev->dev, 1); |
@@ -375,11 +373,10 @@ static int __exit egpio_remove(struct platform_device *pdev) | |||
375 | if (ei->chained_irq) { | 373 | if (ei->chained_irq) { |
376 | irq_end = ei->irq_start + ei->nirqs; | 374 | irq_end = ei->irq_start + ei->nirqs; |
377 | for (irq = ei->irq_start; irq < irq_end; irq++) { | 375 | for (irq = ei->irq_start; irq < irq_end; irq++) { |
378 | set_irq_chip(irq, NULL); | 376 | irq_set_chip_and_handler(irq, NULL, NULL); |
379 | set_irq_handler(irq, NULL); | ||
380 | set_irq_flags(irq, 0); | 377 | set_irq_flags(irq, 0); |
381 | } | 378 | } |
382 | set_irq_chained_handler(ei->chained_irq, NULL); | 379 | irq_set_chained_handler(ei->chained_irq, NULL); |
383 | device_init_wakeup(&pdev->dev, 0); | 380 | device_init_wakeup(&pdev->dev, 0); |
384 | } | 381 | } |
385 | iounmap(ei->base_addr); | 382 | iounmap(ei->base_addr); |
diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c index 296ad1562f69..d55065cc324c 100644 --- a/drivers/mfd/htc-i2cpld.c +++ b/drivers/mfd/htc-i2cpld.c | |||
@@ -58,6 +58,7 @@ struct htcpld_chip { | |||
58 | uint irq_start; | 58 | uint irq_start; |
59 | int nirqs; | 59 | int nirqs; |
60 | 60 | ||
61 | unsigned int flow_type; | ||
61 | /* | 62 | /* |
62 | * Work structure to allow for setting values outside of any | 63 | * Work structure to allow for setting values outside of any |
63 | * possible interrupt context | 64 | * possible interrupt context |
@@ -97,12 +98,7 @@ static void htcpld_unmask(struct irq_data *data) | |||
97 | 98 | ||
98 | static int htcpld_set_type(struct irq_data *data, unsigned int flags) | 99 | static int htcpld_set_type(struct irq_data *data, unsigned int flags) |
99 | { | 100 | { |
100 | struct irq_desc *d = irq_to_desc(data->irq); | 101 | struct htcpld_chip *chip = irq_data_get_irq_chip_data(data); |
101 | |||
102 | if (!d) { | ||
103 | pr_err("HTCPLD invalid IRQ: %d\n", data->irq); | ||
104 | return -EINVAL; | ||
105 | } | ||
106 | 102 | ||
107 | if (flags & ~IRQ_TYPE_SENSE_MASK) | 103 | if (flags & ~IRQ_TYPE_SENSE_MASK) |
108 | return -EINVAL; | 104 | return -EINVAL; |
@@ -111,9 +107,7 @@ static int htcpld_set_type(struct irq_data *data, unsigned int flags) | |||
111 | if (flags & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)) | 107 | if (flags & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)) |
112 | return -EINVAL; | 108 | return -EINVAL; |
113 | 109 | ||
114 | d->status &= ~IRQ_TYPE_SENSE_MASK; | 110 | chip->flow_type = flags; |
115 | d->status |= flags; | ||
116 | |||
117 | return 0; | 111 | return 0; |
118 | } | 112 | } |
119 | 113 | ||
@@ -135,7 +129,6 @@ static irqreturn_t htcpld_handler(int irq, void *dev) | |||
135 | unsigned int i; | 129 | unsigned int i; |
136 | unsigned long flags; | 130 | unsigned long flags; |
137 | int irqpin; | 131 | int irqpin; |
138 | struct irq_desc *desc; | ||
139 | 132 | ||
140 | if (!htcpld) { | 133 | if (!htcpld) { |
141 | pr_debug("htcpld is null in ISR\n"); | 134 | pr_debug("htcpld is null in ISR\n"); |
@@ -195,23 +188,19 @@ static irqreturn_t htcpld_handler(int irq, void *dev) | |||
195 | * associated interrupts. | 188 | * associated interrupts. |
196 | */ | 189 | */ |
197 | for (irqpin = 0; irqpin < chip->nirqs; irqpin++) { | 190 | for (irqpin = 0; irqpin < chip->nirqs; irqpin++) { |
198 | unsigned oldb, newb; | 191 | unsigned oldb, newb, type = chip->flow_type; |
199 | int flags; | ||
200 | 192 | ||
201 | irq = chip->irq_start + irqpin; | 193 | irq = chip->irq_start + irqpin; |
202 | desc = irq_to_desc(irq); | ||
203 | flags = desc->status; | ||
204 | 194 | ||
205 | /* Run the IRQ handler, but only if the bit value | 195 | /* Run the IRQ handler, but only if the bit value |
206 | * changed, and the proper flags are set */ | 196 | * changed, and the proper flags are set */ |
207 | oldb = (old_val >> irqpin) & 1; | 197 | oldb = (old_val >> irqpin) & 1; |
208 | newb = (uval >> irqpin) & 1; | 198 | newb = (uval >> irqpin) & 1; |
209 | 199 | ||
210 | if ((!oldb && newb && (flags & IRQ_TYPE_EDGE_RISING)) || | 200 | if ((!oldb && newb && (type & IRQ_TYPE_EDGE_RISING)) || |
211 | (oldb && !newb && | 201 | (oldb && !newb && (type & IRQ_TYPE_EDGE_FALLING))) { |
212 | (flags & IRQ_TYPE_EDGE_FALLING))) { | ||
213 | pr_debug("fire IRQ %d\n", irqpin); | 202 | pr_debug("fire IRQ %d\n", irqpin); |
214 | desc->handle_irq(irq, desc); | 203 | generic_handle_irq(irq); |
215 | } | 204 | } |
216 | } | 205 | } |
217 | } | 206 | } |
@@ -359,13 +348,13 @@ static int __devinit htcpld_setup_chip_irq( | |||
359 | /* Setup irq handlers */ | 348 | /* Setup irq handlers */ |
360 | irq_end = chip->irq_start + chip->nirqs; | 349 | irq_end = chip->irq_start + chip->nirqs; |
361 | for (irq = chip->irq_start; irq < irq_end; irq++) { | 350 | for (irq = chip->irq_start; irq < irq_end; irq++) { |
362 | set_irq_chip(irq, &htcpld_muxed_chip); | 351 | irq_set_chip_and_handler(irq, &htcpld_muxed_chip, |
363 | set_irq_chip_data(irq, chip); | 352 | handle_simple_irq); |
364 | set_irq_handler(irq, handle_simple_irq); | 353 | irq_set_chip_data(irq, chip); |
365 | #ifdef CONFIG_ARM | 354 | #ifdef CONFIG_ARM |
366 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 355 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
367 | #else | 356 | #else |
368 | set_irq_probe(irq); | 357 | irq_set_probe(irq); |
369 | #endif | 358 | #endif |
370 | } | 359 | } |
371 | 360 | ||
diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index aa518b9beaf5..a0bd0cf05af3 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c | |||
@@ -112,7 +112,7 @@ static struct irq_chip jz4740_adc_irq_chip = { | |||
112 | 112 | ||
113 | static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc) | 113 | static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc) |
114 | { | 114 | { |
115 | struct jz4740_adc *adc = get_irq_desc_data(desc); | 115 | struct jz4740_adc *adc = irq_desc_get_handler_data(desc); |
116 | uint8_t status; | 116 | uint8_t status; |
117 | unsigned int i; | 117 | unsigned int i; |
118 | 118 | ||
@@ -310,13 +310,13 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev) | |||
310 | platform_set_drvdata(pdev, adc); | 310 | platform_set_drvdata(pdev, adc); |
311 | 311 | ||
312 | for (irq = adc->irq_base; irq < adc->irq_base + 5; ++irq) { | 312 | for (irq = adc->irq_base; irq < adc->irq_base + 5; ++irq) { |
313 | set_irq_chip_data(irq, adc); | 313 | irq_set_chip_data(irq, adc); |
314 | set_irq_chip_and_handler(irq, &jz4740_adc_irq_chip, | 314 | irq_set_chip_and_handler(irq, &jz4740_adc_irq_chip, |
315 | handle_level_irq); | 315 | handle_level_irq); |
316 | } | 316 | } |
317 | 317 | ||
318 | set_irq_data(adc->irq, adc); | 318 | irq_set_handler_data(adc->irq, adc); |
319 | set_irq_chained_handler(adc->irq, jz4740_adc_irq_demux); | 319 | irq_set_chained_handler(adc->irq, jz4740_adc_irq_demux); |
320 | 320 | ||
321 | writeb(0x00, adc->base + JZ_REG_ADC_ENABLE); | 321 | writeb(0x00, adc->base + JZ_REG_ADC_ENABLE); |
322 | writeb(0xff, adc->base + JZ_REG_ADC_CTRL); | 322 | writeb(0xff, adc->base + JZ_REG_ADC_CTRL); |
@@ -347,8 +347,8 @@ static int __devexit jz4740_adc_remove(struct platform_device *pdev) | |||
347 | 347 | ||
348 | mfd_remove_devices(&pdev->dev); | 348 | mfd_remove_devices(&pdev->dev); |
349 | 349 | ||
350 | set_irq_data(adc->irq, NULL); | 350 | irq_set_handler_data(adc->irq, NULL); |
351 | set_irq_chained_handler(adc->irq, NULL); | 351 | irq_set_chained_handler(adc->irq, NULL); |
352 | 352 | ||
353 | iounmap(adc->base); | 353 | iounmap(adc->base); |
354 | release_mem_region(adc->mem->start, resource_size(adc->mem)); | 354 | release_mem_region(adc->mem->start, resource_size(adc->mem)); |
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 0e998dc4e7d8..58cc5fdde016 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c | |||
@@ -517,7 +517,6 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq, | |||
517 | struct max8925_platform_data *pdata) | 517 | struct max8925_platform_data *pdata) |
518 | { | 518 | { |
519 | unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; | 519 | unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; |
520 | struct irq_desc *desc; | ||
521 | int i, ret; | 520 | int i, ret; |
522 | int __irq; | 521 | int __irq; |
523 | 522 | ||
@@ -544,19 +543,18 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq, | |||
544 | mutex_init(&chip->irq_lock); | 543 | mutex_init(&chip->irq_lock); |
545 | chip->core_irq = irq; | 544 | chip->core_irq = irq; |
546 | chip->irq_base = pdata->irq_base; | 545 | chip->irq_base = pdata->irq_base; |
547 | desc = irq_to_desc(chip->core_irq); | ||
548 | 546 | ||
549 | /* register with genirq */ | 547 | /* register with genirq */ |
550 | for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) { | 548 | for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) { |
551 | __irq = i + chip->irq_base; | 549 | __irq = i + chip->irq_base; |
552 | set_irq_chip_data(__irq, chip); | 550 | irq_set_chip_data(__irq, chip); |
553 | set_irq_chip_and_handler(__irq, &max8925_irq_chip, | 551 | irq_set_chip_and_handler(__irq, &max8925_irq_chip, |
554 | handle_edge_irq); | 552 | handle_edge_irq); |
555 | set_irq_nested_thread(__irq, 1); | 553 | irq_set_nested_thread(__irq, 1); |
556 | #ifdef CONFIG_ARM | 554 | #ifdef CONFIG_ARM |
557 | set_irq_flags(__irq, IRQF_VALID); | 555 | set_irq_flags(__irq, IRQF_VALID); |
558 | #else | 556 | #else |
559 | set_irq_noprobe(__irq); | 557 | irq_set_noprobe(__irq); |
560 | #endif | 558 | #endif |
561 | } | 559 | } |
562 | if (!irq) { | 560 | if (!irq) { |
diff --git a/drivers/mfd/max8997-irq.c b/drivers/mfd/max8997-irq.c new file mode 100644 index 000000000000..638bf7e4d3b3 --- /dev/null +++ b/drivers/mfd/max8997-irq.c | |||
@@ -0,0 +1,377 @@ | |||
1 | /* | ||
2 | * max8997-irq.c - Interrupt controller support for MAX8997 | ||
3 | * | ||
4 | * Copyright (C) 2011 Samsung Electronics Co.Ltd | ||
5 | * MyungJoo Ham <myungjoo.ham@samsung.com> | ||
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 as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | * | ||
21 | * This driver is based on max8998-irq.c | ||
22 | */ | ||
23 | |||
24 | #include <linux/err.h> | ||
25 | #include <linux/irq.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/mfd/max8997.h> | ||
28 | #include <linux/mfd/max8997-private.h> | ||
29 | |||
30 | static const u8 max8997_mask_reg[] = { | ||
31 | [PMIC_INT1] = MAX8997_REG_INT1MSK, | ||
32 | [PMIC_INT2] = MAX8997_REG_INT2MSK, | ||
33 | [PMIC_INT3] = MAX8997_REG_INT3MSK, | ||
34 | [PMIC_INT4] = MAX8997_REG_INT4MSK, | ||
35 | [FUEL_GAUGE] = MAX8997_REG_INVALID, | ||
36 | [MUIC_INT1] = MAX8997_MUIC_REG_INTMASK1, | ||
37 | [MUIC_INT2] = MAX8997_MUIC_REG_INTMASK2, | ||
38 | [MUIC_INT3] = MAX8997_MUIC_REG_INTMASK3, | ||
39 | [GPIO_LOW] = MAX8997_REG_INVALID, | ||
40 | [GPIO_HI] = MAX8997_REG_INVALID, | ||
41 | [FLASH_STATUS] = MAX8997_REG_INVALID, | ||
42 | }; | ||
43 | |||
44 | static struct i2c_client *get_i2c(struct max8997_dev *max8997, | ||
45 | enum max8997_irq_source src) | ||
46 | { | ||
47 | switch (src) { | ||
48 | case PMIC_INT1 ... PMIC_INT4: | ||
49 | return max8997->i2c; | ||
50 | case FUEL_GAUGE: | ||
51 | return NULL; | ||
52 | case MUIC_INT1 ... MUIC_INT3: | ||
53 | return max8997->muic; | ||
54 | case GPIO_LOW ... GPIO_HI: | ||
55 | return max8997->i2c; | ||
56 | case FLASH_STATUS: | ||
57 | return max8997->i2c; | ||
58 | default: | ||
59 | return ERR_PTR(-EINVAL); | ||
60 | } | ||
61 | |||
62 | return ERR_PTR(-EINVAL); | ||
63 | } | ||
64 | |||
65 | struct max8997_irq_data { | ||
66 | int mask; | ||
67 | enum max8997_irq_source group; | ||
68 | }; | ||
69 | |||
70 | #define DECLARE_IRQ(idx, _group, _mask) \ | ||
71 | [(idx)] = { .group = (_group), .mask = (_mask) } | ||
72 | static const struct max8997_irq_data max8997_irqs[] = { | ||
73 | DECLARE_IRQ(MAX8997_PMICIRQ_PWRONR, PMIC_INT1, 1 << 0), | ||
74 | DECLARE_IRQ(MAX8997_PMICIRQ_PWRONF, PMIC_INT1, 1 << 1), | ||
75 | DECLARE_IRQ(MAX8997_PMICIRQ_PWRON1SEC, PMIC_INT1, 1 << 3), | ||
76 | DECLARE_IRQ(MAX8997_PMICIRQ_JIGONR, PMIC_INT1, 1 << 4), | ||
77 | DECLARE_IRQ(MAX8997_PMICIRQ_JIGONF, PMIC_INT1, 1 << 5), | ||
78 | DECLARE_IRQ(MAX8997_PMICIRQ_LOWBAT2, PMIC_INT1, 1 << 6), | ||
79 | DECLARE_IRQ(MAX8997_PMICIRQ_LOWBAT1, PMIC_INT1, 1 << 7), | ||
80 | |||
81 | DECLARE_IRQ(MAX8997_PMICIRQ_JIGR, PMIC_INT2, 1 << 0), | ||
82 | DECLARE_IRQ(MAX8997_PMICIRQ_JIGF, PMIC_INT2, 1 << 1), | ||
83 | DECLARE_IRQ(MAX8997_PMICIRQ_MR, PMIC_INT2, 1 << 2), | ||
84 | DECLARE_IRQ(MAX8997_PMICIRQ_DVS1OK, PMIC_INT2, 1 << 3), | ||
85 | DECLARE_IRQ(MAX8997_PMICIRQ_DVS2OK, PMIC_INT2, 1 << 4), | ||
86 | DECLARE_IRQ(MAX8997_PMICIRQ_DVS3OK, PMIC_INT2, 1 << 5), | ||
87 | DECLARE_IRQ(MAX8997_PMICIRQ_DVS4OK, PMIC_INT2, 1 << 6), | ||
88 | |||
89 | DECLARE_IRQ(MAX8997_PMICIRQ_CHGINS, PMIC_INT3, 1 << 0), | ||
90 | DECLARE_IRQ(MAX8997_PMICIRQ_CHGRM, PMIC_INT3, 1 << 1), | ||
91 | DECLARE_IRQ(MAX8997_PMICIRQ_DCINOVP, PMIC_INT3, 1 << 2), | ||
92 | DECLARE_IRQ(MAX8997_PMICIRQ_TOPOFFR, PMIC_INT3, 1 << 3), | ||
93 | DECLARE_IRQ(MAX8997_PMICIRQ_CHGRSTF, PMIC_INT3, 1 << 5), | ||
94 | DECLARE_IRQ(MAX8997_PMICIRQ_MBCHGTMEXPD, PMIC_INT3, 1 << 7), | ||
95 | |||
96 | DECLARE_IRQ(MAX8997_PMICIRQ_RTC60S, PMIC_INT4, 1 << 0), | ||
97 | DECLARE_IRQ(MAX8997_PMICIRQ_RTCA1, PMIC_INT4, 1 << 1), | ||
98 | DECLARE_IRQ(MAX8997_PMICIRQ_RTCA2, PMIC_INT4, 1 << 2), | ||
99 | DECLARE_IRQ(MAX8997_PMICIRQ_SMPL_INT, PMIC_INT4, 1 << 3), | ||
100 | DECLARE_IRQ(MAX8997_PMICIRQ_RTC1S, PMIC_INT4, 1 << 4), | ||
101 | DECLARE_IRQ(MAX8997_PMICIRQ_WTSR, PMIC_INT4, 1 << 5), | ||
102 | |||
103 | DECLARE_IRQ(MAX8997_MUICIRQ_ADCError, MUIC_INT1, 1 << 2), | ||
104 | DECLARE_IRQ(MAX8997_MUICIRQ_ADCLow, MUIC_INT1, 1 << 1), | ||
105 | DECLARE_IRQ(MAX8997_MUICIRQ_ADC, MUIC_INT1, 1 << 0), | ||
106 | |||
107 | DECLARE_IRQ(MAX8997_MUICIRQ_VBVolt, MUIC_INT2, 1 << 4), | ||
108 | DECLARE_IRQ(MAX8997_MUICIRQ_DBChg, MUIC_INT2, 1 << 3), | ||
109 | DECLARE_IRQ(MAX8997_MUICIRQ_DCDTmr, MUIC_INT2, 1 << 2), | ||
110 | DECLARE_IRQ(MAX8997_MUICIRQ_ChgDetRun, MUIC_INT2, 1 << 1), | ||
111 | DECLARE_IRQ(MAX8997_MUICIRQ_ChgTyp, MUIC_INT2, 1 << 0), | ||
112 | |||
113 | DECLARE_IRQ(MAX8997_MUICIRQ_OVP, MUIC_INT3, 1 << 2), | ||
114 | }; | ||
115 | |||
116 | static void max8997_irq_lock(struct irq_data *data) | ||
117 | { | ||
118 | struct max8997_dev *max8997 = irq_get_chip_data(data->irq); | ||
119 | |||
120 | mutex_lock(&max8997->irqlock); | ||
121 | } | ||
122 | |||
123 | static void max8997_irq_sync_unlock(struct irq_data *data) | ||
124 | { | ||
125 | struct max8997_dev *max8997 = irq_get_chip_data(data->irq); | ||
126 | int i; | ||
127 | |||
128 | for (i = 0; i < MAX8997_IRQ_GROUP_NR; i++) { | ||
129 | u8 mask_reg = max8997_mask_reg[i]; | ||
130 | struct i2c_client *i2c = get_i2c(max8997, i); | ||
131 | |||
132 | if (mask_reg == MAX8997_REG_INVALID || | ||
133 | IS_ERR_OR_NULL(i2c)) | ||
134 | continue; | ||
135 | max8997->irq_masks_cache[i] = max8997->irq_masks_cur[i]; | ||
136 | |||
137 | max8997_write_reg(i2c, max8997_mask_reg[i], | ||
138 | max8997->irq_masks_cur[i]); | ||
139 | } | ||
140 | |||
141 | mutex_unlock(&max8997->irqlock); | ||
142 | } | ||
143 | |||
144 | static const inline struct max8997_irq_data * | ||
145 | irq_to_max8997_irq(struct max8997_dev *max8997, int irq) | ||
146 | { | ||
147 | return &max8997_irqs[irq - max8997->irq_base]; | ||
148 | } | ||
149 | |||
150 | static void max8997_irq_mask(struct irq_data *data) | ||
151 | { | ||
152 | struct max8997_dev *max8997 = irq_get_chip_data(data->irq); | ||
153 | const struct max8997_irq_data *irq_data = irq_to_max8997_irq(max8997, | ||
154 | data->irq); | ||
155 | |||
156 | max8997->irq_masks_cur[irq_data->group] |= irq_data->mask; | ||
157 | } | ||
158 | |||
159 | static void max8997_irq_unmask(struct irq_data *data) | ||
160 | { | ||
161 | struct max8997_dev *max8997 = irq_get_chip_data(data->irq); | ||
162 | const struct max8997_irq_data *irq_data = irq_to_max8997_irq(max8997, | ||
163 | data->irq); | ||
164 | |||
165 | max8997->irq_masks_cur[irq_data->group] &= ~irq_data->mask; | ||
166 | } | ||
167 | |||
168 | static struct irq_chip max8997_irq_chip = { | ||
169 | .name = "max8997", | ||
170 | .irq_bus_lock = max8997_irq_lock, | ||
171 | .irq_bus_sync_unlock = max8997_irq_sync_unlock, | ||
172 | .irq_mask = max8997_irq_mask, | ||
173 | .irq_unmask = max8997_irq_unmask, | ||
174 | }; | ||
175 | |||
176 | #define MAX8997_IRQSRC_PMIC (1 << 1) | ||
177 | #define MAX8997_IRQSRC_FUELGAUGE (1 << 2) | ||
178 | #define MAX8997_IRQSRC_MUIC (1 << 3) | ||
179 | #define MAX8997_IRQSRC_GPIO (1 << 4) | ||
180 | #define MAX8997_IRQSRC_FLASH (1 << 5) | ||
181 | static irqreturn_t max8997_irq_thread(int irq, void *data) | ||
182 | { | ||
183 | struct max8997_dev *max8997 = data; | ||
184 | u8 irq_reg[MAX8997_IRQ_GROUP_NR] = {}; | ||
185 | u8 irq_src; | ||
186 | int ret; | ||
187 | int i; | ||
188 | |||
189 | ret = max8997_read_reg(max8997->i2c, MAX8997_REG_INTSRC, &irq_src); | ||
190 | if (ret < 0) { | ||
191 | dev_err(max8997->dev, "Failed to read interrupt source: %d\n", | ||
192 | ret); | ||
193 | return IRQ_NONE; | ||
194 | } | ||
195 | |||
196 | if (irq_src & MAX8997_IRQSRC_PMIC) { | ||
197 | /* PMIC INT1 ~ INT4 */ | ||
198 | max8997_bulk_read(max8997->i2c, MAX8997_REG_INT1, 4, | ||
199 | &irq_reg[PMIC_INT1]); | ||
200 | } | ||
201 | if (irq_src & MAX8997_IRQSRC_FUELGAUGE) { | ||
202 | /* | ||
203 | * TODO: FUEL GAUGE | ||
204 | * | ||
205 | * This is to be supported by Max17042 driver. When | ||
206 | * an interrupt incurs here, it should be relayed to a | ||
207 | * Max17042 device that is connected (probably by | ||
208 | * platform-data). However, we do not have interrupt | ||
209 | * handling in Max17042 driver currently. The Max17042 IRQ | ||
210 | * driver should be ready to be used as a stand-alone device and | ||
211 | * a Max8997-dependent device. Because it is not ready in | ||
212 | * Max17042-side and it is not too critical in operating | ||
213 | * Max8997, we do not implement this in initial releases. | ||
214 | */ | ||
215 | irq_reg[FUEL_GAUGE] = 0; | ||
216 | } | ||
217 | if (irq_src & MAX8997_IRQSRC_MUIC) { | ||
218 | /* MUIC INT1 ~ INT3 */ | ||
219 | max8997_bulk_read(max8997->muic, MAX8997_MUIC_REG_INT1, 3, | ||
220 | &irq_reg[MUIC_INT1]); | ||
221 | } | ||
222 | if (irq_src & MAX8997_IRQSRC_GPIO) { | ||
223 | /* GPIO Interrupt */ | ||
224 | u8 gpio_info[MAX8997_NUM_GPIO]; | ||
225 | |||
226 | irq_reg[GPIO_LOW] = 0; | ||
227 | irq_reg[GPIO_HI] = 0; | ||
228 | |||
229 | max8997_bulk_read(max8997->i2c, MAX8997_REG_GPIOCNTL1, | ||
230 | MAX8997_NUM_GPIO, gpio_info); | ||
231 | for (i = 0; i < MAX8997_NUM_GPIO; i++) { | ||
232 | bool interrupt = false; | ||
233 | |||
234 | switch (gpio_info[i] & MAX8997_GPIO_INT_MASK) { | ||
235 | case MAX8997_GPIO_INT_BOTH: | ||
236 | if (max8997->gpio_status[i] != gpio_info[i]) | ||
237 | interrupt = true; | ||
238 | break; | ||
239 | case MAX8997_GPIO_INT_RISE: | ||
240 | if ((max8997->gpio_status[i] != gpio_info[i]) && | ||
241 | (gpio_info[i] & MAX8997_GPIO_DATA_MASK)) | ||
242 | interrupt = true; | ||
243 | break; | ||
244 | case MAX8997_GPIO_INT_FALL: | ||
245 | if ((max8997->gpio_status[i] != gpio_info[i]) && | ||
246 | !(gpio_info[i] & MAX8997_GPIO_DATA_MASK)) | ||
247 | interrupt = true; | ||
248 | break; | ||
249 | default: | ||
250 | break; | ||
251 | } | ||
252 | |||
253 | if (interrupt) { | ||
254 | if (i < 8) | ||
255 | irq_reg[GPIO_LOW] |= (1 << i); | ||
256 | else | ||
257 | irq_reg[GPIO_HI] |= (1 << (i - 8)); | ||
258 | } | ||
259 | |||
260 | } | ||
261 | } | ||
262 | if (irq_src & MAX8997_IRQSRC_FLASH) { | ||
263 | /* Flash Status Interrupt */ | ||
264 | ret = max8997_read_reg(max8997->i2c, MAX8997_REG_FLASHSTATUS, | ||
265 | &irq_reg[FLASH_STATUS]); | ||
266 | } | ||
267 | |||
268 | /* Apply masking */ | ||
269 | for (i = 0; i < MAX8997_IRQ_GROUP_NR; i++) | ||
270 | irq_reg[i] &= ~max8997->irq_masks_cur[i]; | ||
271 | |||
272 | /* Report */ | ||
273 | for (i = 0; i < MAX8997_IRQ_NR; i++) { | ||
274 | if (irq_reg[max8997_irqs[i].group] & max8997_irqs[i].mask) | ||
275 | handle_nested_irq(max8997->irq_base + i); | ||
276 | } | ||
277 | |||
278 | return IRQ_HANDLED; | ||
279 | } | ||
280 | |||
281 | int max8997_irq_resume(struct max8997_dev *max8997) | ||
282 | { | ||
283 | if (max8997->irq && max8997->irq_base) | ||
284 | max8997_irq_thread(max8997->irq_base, max8997); | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | int max8997_irq_init(struct max8997_dev *max8997) | ||
289 | { | ||
290 | int i; | ||
291 | int cur_irq; | ||
292 | int ret; | ||
293 | u8 val; | ||
294 | |||
295 | if (!max8997->irq) { | ||
296 | dev_warn(max8997->dev, "No interrupt specified.\n"); | ||
297 | max8997->irq_base = 0; | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | if (!max8997->irq_base) { | ||
302 | dev_err(max8997->dev, "No interrupt base specified.\n"); | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | mutex_init(&max8997->irqlock); | ||
307 | |||
308 | /* Mask individual interrupt sources */ | ||
309 | for (i = 0; i < MAX8997_IRQ_GROUP_NR; i++) { | ||
310 | struct i2c_client *i2c; | ||
311 | |||
312 | max8997->irq_masks_cur[i] = 0xff; | ||
313 | max8997->irq_masks_cache[i] = 0xff; | ||
314 | i2c = get_i2c(max8997, i); | ||
315 | |||
316 | if (IS_ERR_OR_NULL(i2c)) | ||
317 | continue; | ||
318 | if (max8997_mask_reg[i] == MAX8997_REG_INVALID) | ||
319 | continue; | ||
320 | |||
321 | max8997_write_reg(i2c, max8997_mask_reg[i], 0xff); | ||
322 | } | ||
323 | |||
324 | for (i = 0; i < MAX8997_NUM_GPIO; i++) { | ||
325 | max8997->gpio_status[i] = (max8997_read_reg(max8997->i2c, | ||
326 | MAX8997_REG_GPIOCNTL1 + i, | ||
327 | &val) | ||
328 | & MAX8997_GPIO_DATA_MASK) ? | ||
329 | true : false; | ||
330 | } | ||
331 | |||
332 | /* Register with genirq */ | ||
333 | for (i = 0; i < MAX8997_IRQ_NR; i++) { | ||
334 | cur_irq = i + max8997->irq_base; | ||
335 | irq_set_chip_data(cur_irq, max8997); | ||
336 | irq_set_chip_and_handler(cur_irq, &max8997_irq_chip, | ||
337 | handle_edge_irq); | ||
338 | irq_set_nested_thread(cur_irq, 1); | ||
339 | #ifdef CONFIG_ARM | ||
340 | set_irq_flags(cur_irq, IRQF_VALID); | ||
341 | #else | ||
342 | irq_set_noprobe(cur_irq); | ||
343 | #endif | ||
344 | } | ||
345 | |||
346 | ret = request_threaded_irq(max8997->irq, NULL, max8997_irq_thread, | ||
347 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
348 | "max8997-irq", max8997); | ||
349 | |||
350 | if (ret) { | ||
351 | dev_err(max8997->dev, "Failed to request IRQ %d: %d\n", | ||
352 | max8997->irq, ret); | ||
353 | return ret; | ||
354 | } | ||
355 | |||
356 | if (!max8997->ono) | ||
357 | return 0; | ||
358 | |||
359 | ret = request_threaded_irq(max8997->ono, NULL, max8997_irq_thread, | ||
360 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | | ||
361 | IRQF_ONESHOT, "max8997-ono", max8997); | ||
362 | |||
363 | if (ret) | ||
364 | dev_err(max8997->dev, "Failed to request ono-IRQ %d: %d\n", | ||
365 | max8997->ono, ret); | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | void max8997_irq_exit(struct max8997_dev *max8997) | ||
371 | { | ||
372 | if (max8997->ono) | ||
373 | free_irq(max8997->ono, max8997); | ||
374 | |||
375 | if (max8997->irq) | ||
376 | free_irq(max8997->irq, max8997); | ||
377 | } | ||
diff --git a/drivers/mfd/max8998-irq.c b/drivers/mfd/max8998-irq.c index 3903e1fbb334..5919710dc9ed 100644 --- a/drivers/mfd/max8998-irq.c +++ b/drivers/mfd/max8998-irq.c | |||
@@ -224,14 +224,14 @@ int max8998_irq_init(struct max8998_dev *max8998) | |||
224 | /* register with genirq */ | 224 | /* register with genirq */ |
225 | for (i = 0; i < MAX8998_IRQ_NR; i++) { | 225 | for (i = 0; i < MAX8998_IRQ_NR; i++) { |
226 | cur_irq = i + max8998->irq_base; | 226 | cur_irq = i + max8998->irq_base; |
227 | set_irq_chip_data(cur_irq, max8998); | 227 | irq_set_chip_data(cur_irq, max8998); |
228 | set_irq_chip_and_handler(cur_irq, &max8998_irq_chip, | 228 | irq_set_chip_and_handler(cur_irq, &max8998_irq_chip, |
229 | handle_edge_irq); | 229 | handle_edge_irq); |
230 | set_irq_nested_thread(cur_irq, 1); | 230 | irq_set_nested_thread(cur_irq, 1); |
231 | #ifdef CONFIG_ARM | 231 | #ifdef CONFIG_ARM |
232 | set_irq_flags(cur_irq, IRQF_VALID); | 232 | set_irq_flags(cur_irq, IRQF_VALID); |
233 | #else | 233 | #else |
234 | set_irq_noprobe(cur_irq); | 234 | irq_set_noprobe(cur_irq); |
235 | #endif | 235 | #endif |
236 | } | 236 | } |
237 | 237 | ||
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index c00214257da2..9ec7570f5b81 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c | |||
@@ -209,7 +209,7 @@ static int max8998_suspend(struct device *dev) | |||
209 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); | 209 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); |
210 | 210 | ||
211 | if (max8998->wakeup) | 211 | if (max8998->wakeup) |
212 | set_irq_wake(max8998->irq, 1); | 212 | irq_set_irq_wake(max8998->irq, 1); |
213 | return 0; | 213 | return 0; |
214 | } | 214 | } |
215 | 215 | ||
@@ -219,7 +219,7 @@ static int max8998_resume(struct device *dev) | |||
219 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); | 219 | struct max8998_dev *max8998 = i2c_get_clientdata(i2c); |
220 | 220 | ||
221 | if (max8998->wakeup) | 221 | if (max8998->wakeup) |
222 | set_irq_wake(max8998->irq, 0); | 222 | irq_set_irq_wake(max8998->irq, 0); |
223 | /* | 223 | /* |
224 | * In LP3974, if IRQ registers are not "read & clear" | 224 | * In LP3974, if IRQ registers are not "read & clear" |
225 | * when it's set during sleep, the interrupt becomes | 225 | * when it's set during sleep, the interrupt becomes |
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 79eda0264fb2..d01574d98870 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c | |||
@@ -184,16 +184,12 @@ void mfd_remove_devices(struct device *parent) | |||
184 | } | 184 | } |
185 | EXPORT_SYMBOL(mfd_remove_devices); | 185 | EXPORT_SYMBOL(mfd_remove_devices); |
186 | 186 | ||
187 | static int add_shared_platform_device(const char *cell, const char *name) | 187 | int mfd_clone_cell(const char *cell, const char **clones, size_t n_clones) |
188 | { | 188 | { |
189 | struct mfd_cell cell_entry; | 189 | struct mfd_cell cell_entry; |
190 | struct device *dev; | 190 | struct device *dev; |
191 | struct platform_device *pdev; | 191 | struct platform_device *pdev; |
192 | int err; | 192 | int i; |
193 | |||
194 | /* check if we've already registered a device (don't fail if we have) */ | ||
195 | if (bus_find_device_by_name(&platform_bus_type, NULL, name)) | ||
196 | return 0; | ||
197 | 193 | ||
198 | /* fetch the parent cell's device (should already be registered!) */ | 194 | /* fetch the parent cell's device (should already be registered!) */ |
199 | dev = bus_find_device_by_name(&platform_bus_type, NULL, cell); | 195 | dev = bus_find_device_by_name(&platform_bus_type, NULL, cell); |
@@ -206,44 +202,17 @@ static int add_shared_platform_device(const char *cell, const char *name) | |||
206 | 202 | ||
207 | WARN_ON(!cell_entry.enable); | 203 | WARN_ON(!cell_entry.enable); |
208 | 204 | ||
209 | cell_entry.name = name; | 205 | for (i = 0; i < n_clones; i++) { |
210 | err = mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0); | 206 | cell_entry.name = clones[i]; |
211 | if (err) | 207 | /* don't give up if a single call fails; just report error */ |
212 | dev_err(dev, "MFD add devices failed: %d\n", err); | 208 | if (mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0)) |
213 | return err; | 209 | dev_err(dev, "failed to create platform device '%s'\n", |
214 | } | 210 | clones[i]); |
215 | 211 | } | |
216 | int mfd_shared_platform_driver_register(struct platform_driver *drv, | ||
217 | const char *cellname) | ||
218 | { | ||
219 | int err; | ||
220 | |||
221 | err = add_shared_platform_device(cellname, drv->driver.name); | ||
222 | if (err) | ||
223 | printk(KERN_ERR "failed to add platform device %s\n", | ||
224 | drv->driver.name); | ||
225 | |||
226 | err = platform_driver_register(drv); | ||
227 | if (err) | ||
228 | printk(KERN_ERR "failed to add platform driver %s\n", | ||
229 | drv->driver.name); | ||
230 | |||
231 | return err; | ||
232 | } | ||
233 | EXPORT_SYMBOL(mfd_shared_platform_driver_register); | ||
234 | |||
235 | void mfd_shared_platform_driver_unregister(struct platform_driver *drv) | ||
236 | { | ||
237 | struct device *dev; | ||
238 | |||
239 | dev = bus_find_device_by_name(&platform_bus_type, NULL, | ||
240 | drv->driver.name); | ||
241 | if (dev) | ||
242 | platform_device_unregister(to_platform_device(dev)); | ||
243 | 212 | ||
244 | platform_driver_unregister(drv); | 213 | return 0; |
245 | } | 214 | } |
246 | EXPORT_SYMBOL(mfd_shared_platform_driver_unregister); | 215 | EXPORT_SYMBOL(mfd_clone_cell); |
247 | 216 | ||
248 | MODULE_LICENSE("GPL"); | 217 | MODULE_LICENSE("GPL"); |
249 | MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov"); | 218 | MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov"); |
diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index c1306ed43e3c..c7687f6a78a0 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c | |||
@@ -356,7 +356,7 @@ static int __devexit pcf50633_remove(struct i2c_client *client) | |||
356 | return 0; | 356 | return 0; |
357 | } | 357 | } |
358 | 358 | ||
359 | static struct i2c_device_id pcf50633_id_table[] = { | 359 | static const struct i2c_device_id pcf50633_id_table[] = { |
360 | {"pcf50633", 0x73}, | 360 | {"pcf50633", 0x73}, |
361 | {/* end of list */} | 361 | {/* end of list */} |
362 | }; | 362 | }; |
diff --git a/drivers/mfd/rdc321x-southbridge.c b/drivers/mfd/rdc321x-southbridge.c index 193c940225b5..10dbe6374a89 100644 --- a/drivers/mfd/rdc321x-southbridge.c +++ b/drivers/mfd/rdc321x-southbridge.c | |||
@@ -97,6 +97,7 @@ static DEFINE_PCI_DEVICE_TABLE(rdc321x_sb_table) = { | |||
97 | { PCI_DEVICE(PCI_VENDOR_ID_RDC, PCI_DEVICE_ID_RDC_R6030) }, | 97 | { PCI_DEVICE(PCI_VENDOR_ID_RDC, PCI_DEVICE_ID_RDC_R6030) }, |
98 | {} | 98 | {} |
99 | }; | 99 | }; |
100 | MODULE_DEVICE_TABLE(pci, rdc321x_sb_table); | ||
100 | 101 | ||
101 | static struct pci_driver rdc321x_sb_driver = { | 102 | static struct pci_driver rdc321x_sb_driver = { |
102 | .name = "RDC321x Southbridge", | 103 | .name = "RDC321x Southbridge", |
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 3e5732b58c49..7ab7746631d4 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c | |||
@@ -762,14 +762,14 @@ static int __devinit stmpe_irq_init(struct stmpe *stmpe) | |||
762 | int irq; | 762 | int irq; |
763 | 763 | ||
764 | for (irq = base; irq < base + num_irqs; irq++) { | 764 | for (irq = base; irq < base + num_irqs; irq++) { |
765 | set_irq_chip_data(irq, stmpe); | 765 | irq_set_chip_data(irq, stmpe); |
766 | set_irq_chip_and_handler(irq, &stmpe_irq_chip, | 766 | irq_set_chip_and_handler(irq, &stmpe_irq_chip, |
767 | handle_edge_irq); | 767 | handle_edge_irq); |
768 | set_irq_nested_thread(irq, 1); | 768 | irq_set_nested_thread(irq, 1); |
769 | #ifdef CONFIG_ARM | 769 | #ifdef CONFIG_ARM |
770 | set_irq_flags(irq, IRQF_VALID); | 770 | set_irq_flags(irq, IRQF_VALID); |
771 | #else | 771 | #else |
772 | set_irq_noprobe(irq); | 772 | irq_set_noprobe(irq); |
773 | #endif | 773 | #endif |
774 | } | 774 | } |
775 | 775 | ||
@@ -786,8 +786,8 @@ static void stmpe_irq_remove(struct stmpe *stmpe) | |||
786 | #ifdef CONFIG_ARM | 786 | #ifdef CONFIG_ARM |
787 | set_irq_flags(irq, 0); | 787 | set_irq_flags(irq, 0); |
788 | #endif | 788 | #endif |
789 | set_irq_chip_and_handler(irq, NULL, NULL); | 789 | irq_set_chip_and_handler(irq, NULL, NULL); |
790 | set_irq_chip_data(irq, NULL); | 790 | irq_set_chip_data(irq, NULL); |
791 | } | 791 | } |
792 | } | 792 | } |
793 | 793 | ||
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index af57fc706a4c..42830e692964 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c | |||
@@ -186,7 +186,7 @@ static struct mfd_cell t7l66xb_cells[] = { | |||
186 | /* Handle the T7L66XB interrupt mux */ | 186 | /* Handle the T7L66XB interrupt mux */ |
187 | static void t7l66xb_irq(unsigned int irq, struct irq_desc *desc) | 187 | static void t7l66xb_irq(unsigned int irq, struct irq_desc *desc) |
188 | { | 188 | { |
189 | struct t7l66xb *t7l66xb = get_irq_data(irq); | 189 | struct t7l66xb *t7l66xb = irq_get_handler_data(irq); |
190 | unsigned int isr; | 190 | unsigned int isr; |
191 | unsigned int i, irq_base; | 191 | unsigned int i, irq_base; |
192 | 192 | ||
@@ -243,17 +243,16 @@ static void t7l66xb_attach_irq(struct platform_device *dev) | |||
243 | irq_base = t7l66xb->irq_base; | 243 | irq_base = t7l66xb->irq_base; |
244 | 244 | ||
245 | for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { | 245 | for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { |
246 | set_irq_chip(irq, &t7l66xb_chip); | 246 | irq_set_chip_and_handler(irq, &t7l66xb_chip, handle_level_irq); |
247 | set_irq_chip_data(irq, t7l66xb); | 247 | irq_set_chip_data(irq, t7l66xb); |
248 | set_irq_handler(irq, handle_level_irq); | ||
249 | #ifdef CONFIG_ARM | 248 | #ifdef CONFIG_ARM |
250 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 249 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
251 | #endif | 250 | #endif |
252 | } | 251 | } |
253 | 252 | ||
254 | set_irq_type(t7l66xb->irq, IRQ_TYPE_EDGE_FALLING); | 253 | irq_set_irq_type(t7l66xb->irq, IRQ_TYPE_EDGE_FALLING); |
255 | set_irq_data(t7l66xb->irq, t7l66xb); | 254 | irq_set_handler_data(t7l66xb->irq, t7l66xb); |
256 | set_irq_chained_handler(t7l66xb->irq, t7l66xb_irq); | 255 | irq_set_chained_handler(t7l66xb->irq, t7l66xb_irq); |
257 | } | 256 | } |
258 | 257 | ||
259 | static void t7l66xb_detach_irq(struct platform_device *dev) | 258 | static void t7l66xb_detach_irq(struct platform_device *dev) |
@@ -263,15 +262,15 @@ static void t7l66xb_detach_irq(struct platform_device *dev) | |||
263 | 262 | ||
264 | irq_base = t7l66xb->irq_base; | 263 | irq_base = t7l66xb->irq_base; |
265 | 264 | ||
266 | set_irq_chained_handler(t7l66xb->irq, NULL); | 265 | irq_set_chained_handler(t7l66xb->irq, NULL); |
267 | set_irq_data(t7l66xb->irq, NULL); | 266 | irq_set_handler_data(t7l66xb->irq, NULL); |
268 | 267 | ||
269 | for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { | 268 | for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { |
270 | #ifdef CONFIG_ARM | 269 | #ifdef CONFIG_ARM |
271 | set_irq_flags(irq, 0); | 270 | set_irq_flags(irq, 0); |
272 | #endif | 271 | #endif |
273 | set_irq_chip(irq, NULL); | 272 | irq_set_chip(irq, NULL); |
274 | set_irq_chip_data(irq, NULL); | 273 | irq_set_chip_data(irq, NULL); |
275 | } | 274 | } |
276 | } | 275 | } |
277 | 276 | ||
diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index 729dbeed2ce0..c27e515b0722 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c | |||
@@ -192,14 +192,14 @@ static int tc3589x_irq_init(struct tc3589x *tc3589x) | |||
192 | int irq; | 192 | int irq; |
193 | 193 | ||
194 | for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) { | 194 | for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) { |
195 | set_irq_chip_data(irq, tc3589x); | 195 | irq_set_chip_data(irq, tc3589x); |
196 | set_irq_chip_and_handler(irq, &dummy_irq_chip, | 196 | irq_set_chip_and_handler(irq, &dummy_irq_chip, |
197 | handle_edge_irq); | 197 | handle_edge_irq); |
198 | set_irq_nested_thread(irq, 1); | 198 | irq_set_nested_thread(irq, 1); |
199 | #ifdef CONFIG_ARM | 199 | #ifdef CONFIG_ARM |
200 | set_irq_flags(irq, IRQF_VALID); | 200 | set_irq_flags(irq, IRQF_VALID); |
201 | #else | 201 | #else |
202 | set_irq_noprobe(irq); | 202 | irq_set_noprobe(irq); |
203 | #endif | 203 | #endif |
204 | } | 204 | } |
205 | 205 | ||
@@ -215,8 +215,8 @@ static void tc3589x_irq_remove(struct tc3589x *tc3589x) | |||
215 | #ifdef CONFIG_ARM | 215 | #ifdef CONFIG_ARM |
216 | set_irq_flags(irq, 0); | 216 | set_irq_flags(irq, 0); |
217 | #endif | 217 | #endif |
218 | set_irq_chip_and_handler(irq, NULL, NULL); | 218 | irq_set_chip_and_handler(irq, NULL, NULL); |
219 | set_irq_chip_data(irq, NULL); | 219 | irq_set_chip_data(irq, NULL); |
220 | } | 220 | } |
221 | } | 221 | } |
222 | 222 | ||
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 3d62ded86a8f..fc53ce287601 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c | |||
@@ -513,7 +513,7 @@ static int tc6393xb_register_gpio(struct tc6393xb *tc6393xb, int gpio_base) | |||
513 | static void | 513 | static void |
514 | tc6393xb_irq(unsigned int irq, struct irq_desc *desc) | 514 | tc6393xb_irq(unsigned int irq, struct irq_desc *desc) |
515 | { | 515 | { |
516 | struct tc6393xb *tc6393xb = get_irq_data(irq); | 516 | struct tc6393xb *tc6393xb = irq_get_handler_data(irq); |
517 | unsigned int isr; | 517 | unsigned int isr; |
518 | unsigned int i, irq_base; | 518 | unsigned int i, irq_base; |
519 | 519 | ||
@@ -572,15 +572,14 @@ static void tc6393xb_attach_irq(struct platform_device *dev) | |||
572 | irq_base = tc6393xb->irq_base; | 572 | irq_base = tc6393xb->irq_base; |
573 | 573 | ||
574 | for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { | 574 | for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { |
575 | set_irq_chip(irq, &tc6393xb_chip); | 575 | irq_set_chip_and_handler(irq, &tc6393xb_chip, handle_edge_irq); |
576 | set_irq_chip_data(irq, tc6393xb); | 576 | irq_set_chip_data(irq, tc6393xb); |
577 | set_irq_handler(irq, handle_edge_irq); | ||
578 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 577 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
579 | } | 578 | } |
580 | 579 | ||
581 | set_irq_type(tc6393xb->irq, IRQ_TYPE_EDGE_FALLING); | 580 | irq_set_irq_type(tc6393xb->irq, IRQ_TYPE_EDGE_FALLING); |
582 | set_irq_data(tc6393xb->irq, tc6393xb); | 581 | irq_set_handler_data(tc6393xb->irq, tc6393xb); |
583 | set_irq_chained_handler(tc6393xb->irq, tc6393xb_irq); | 582 | irq_set_chained_handler(tc6393xb->irq, tc6393xb_irq); |
584 | } | 583 | } |
585 | 584 | ||
586 | static void tc6393xb_detach_irq(struct platform_device *dev) | 585 | static void tc6393xb_detach_irq(struct platform_device *dev) |
@@ -588,15 +587,15 @@ static void tc6393xb_detach_irq(struct platform_device *dev) | |||
588 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | 587 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); |
589 | unsigned int irq, irq_base; | 588 | unsigned int irq, irq_base; |
590 | 589 | ||
591 | set_irq_chained_handler(tc6393xb->irq, NULL); | 590 | irq_set_chained_handler(tc6393xb->irq, NULL); |
592 | set_irq_data(tc6393xb->irq, NULL); | 591 | irq_set_handler_data(tc6393xb->irq, NULL); |
593 | 592 | ||
594 | irq_base = tc6393xb->irq_base; | 593 | irq_base = tc6393xb->irq_base; |
595 | 594 | ||
596 | for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { | 595 | for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { |
597 | set_irq_flags(irq, 0); | 596 | set_irq_flags(irq, 0); |
598 | set_irq_chip(irq, NULL); | 597 | irq_set_chip(irq, NULL); |
599 | set_irq_chip_data(irq, NULL); | 598 | irq_set_chip_data(irq, NULL); |
600 | } | 599 | } |
601 | } | 600 | } |
602 | 601 | ||
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 0aa9186aec19..b600808690c1 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c | |||
@@ -422,10 +422,10 @@ static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq, | |||
422 | 422 | ||
423 | for (i = 0; i < ARRAY_SIZE(tps6586x_irqs); i++) { | 423 | for (i = 0; i < ARRAY_SIZE(tps6586x_irqs); i++) { |
424 | int __irq = i + tps6586x->irq_base; | 424 | int __irq = i + tps6586x->irq_base; |
425 | set_irq_chip_data(__irq, tps6586x); | 425 | irq_set_chip_data(__irq, tps6586x); |
426 | set_irq_chip_and_handler(__irq, &tps6586x->irq_chip, | 426 | irq_set_chip_and_handler(__irq, &tps6586x->irq_chip, |
427 | handle_simple_irq); | 427 | handle_simple_irq); |
428 | set_irq_nested_thread(__irq, 1); | 428 | irq_set_nested_thread(__irq, 1); |
429 | #ifdef CONFIG_ARM | 429 | #ifdef CONFIG_ARM |
430 | set_irq_flags(__irq, IRQF_VALID); | 430 | set_irq_flags(__irq, IRQF_VALID); |
431 | #endif | 431 | #endif |
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index 63a30e88908f..8a7ee3139b86 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c | |||
@@ -320,24 +320,8 @@ static int twl4030_irq_thread(void *data) | |||
320 | for (module_irq = twl4030_irq_base; | 320 | for (module_irq = twl4030_irq_base; |
321 | pih_isr; | 321 | pih_isr; |
322 | pih_isr >>= 1, module_irq++) { | 322 | pih_isr >>= 1, module_irq++) { |
323 | if (pih_isr & 0x1) { | 323 | if (pih_isr & 0x1) |
324 | struct irq_desc *d = irq_to_desc(module_irq); | 324 | generic_handle_irq(module_irq); |
325 | |||
326 | if (!d) { | ||
327 | pr_err("twl4030: Invalid SIH IRQ: %d\n", | ||
328 | module_irq); | ||
329 | return -EINVAL; | ||
330 | } | ||
331 | |||
332 | /* These can't be masked ... always warn | ||
333 | * if we get any surprises. | ||
334 | */ | ||
335 | if (d->status & IRQ_DISABLED) | ||
336 | note_interrupt(module_irq, d, | ||
337 | IRQ_NONE); | ||
338 | else | ||
339 | d->handle_irq(module_irq, d); | ||
340 | } | ||
341 | } | 325 | } |
342 | local_irq_enable(); | 326 | local_irq_enable(); |
343 | 327 | ||
@@ -470,7 +454,7 @@ static inline void activate_irq(int irq) | |||
470 | set_irq_flags(irq, IRQF_VALID); | 454 | set_irq_flags(irq, IRQF_VALID); |
471 | #else | 455 | #else |
472 | /* same effect on other architectures */ | 456 | /* same effect on other architectures */ |
473 | set_irq_noprobe(irq); | 457 | irq_set_noprobe(irq); |
474 | #endif | 458 | #endif |
475 | } | 459 | } |
476 | 460 | ||
@@ -560,24 +544,18 @@ static void twl4030_sih_do_edge(struct work_struct *work) | |||
560 | /* Modify only the bits we know must change */ | 544 | /* Modify only the bits we know must change */ |
561 | while (edge_change) { | 545 | while (edge_change) { |
562 | int i = fls(edge_change) - 1; | 546 | int i = fls(edge_change) - 1; |
563 | struct irq_desc *d = irq_to_desc(i + agent->irq_base); | 547 | struct irq_data *idata = irq_get_irq_data(i + agent->irq_base); |
564 | int byte = 1 + (i >> 2); | 548 | int byte = 1 + (i >> 2); |
565 | int off = (i & 0x3) * 2; | 549 | int off = (i & 0x3) * 2; |
566 | 550 | unsigned int type; | |
567 | if (!d) { | ||
568 | pr_err("twl4030: Invalid IRQ: %d\n", | ||
569 | i + agent->irq_base); | ||
570 | return; | ||
571 | } | ||
572 | 551 | ||
573 | bytes[byte] &= ~(0x03 << off); | 552 | bytes[byte] &= ~(0x03 << off); |
574 | 553 | ||
575 | raw_spin_lock_irq(&d->lock); | 554 | type = irqd_get_trigger_type(idata); |
576 | if (d->status & IRQ_TYPE_EDGE_RISING) | 555 | if (type & IRQ_TYPE_EDGE_RISING) |
577 | bytes[byte] |= BIT(off + 1); | 556 | bytes[byte] |= BIT(off + 1); |
578 | if (d->status & IRQ_TYPE_EDGE_FALLING) | 557 | if (type & IRQ_TYPE_EDGE_FALLING) |
579 | bytes[byte] |= BIT(off + 0); | 558 | bytes[byte] |= BIT(off + 0); |
580 | raw_spin_unlock_irq(&d->lock); | ||
581 | 559 | ||
582 | edge_change &= ~BIT(i); | 560 | edge_change &= ~BIT(i); |
583 | } | 561 | } |
@@ -626,21 +604,13 @@ static void twl4030_sih_unmask(struct irq_data *data) | |||
626 | static int twl4030_sih_set_type(struct irq_data *data, unsigned trigger) | 604 | static int twl4030_sih_set_type(struct irq_data *data, unsigned trigger) |
627 | { | 605 | { |
628 | struct sih_agent *sih = irq_data_get_irq_chip_data(data); | 606 | struct sih_agent *sih = irq_data_get_irq_chip_data(data); |
629 | struct irq_desc *desc = irq_to_desc(data->irq); | ||
630 | unsigned long flags; | 607 | unsigned long flags; |
631 | 608 | ||
632 | if (!desc) { | ||
633 | pr_err("twl4030: Invalid IRQ: %d\n", data->irq); | ||
634 | return -EINVAL; | ||
635 | } | ||
636 | |||
637 | if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) | 609 | if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) |
638 | return -EINVAL; | 610 | return -EINVAL; |
639 | 611 | ||
640 | spin_lock_irqsave(&sih_agent_lock, flags); | 612 | spin_lock_irqsave(&sih_agent_lock, flags); |
641 | if ((desc->status & IRQ_TYPE_SENSE_MASK) != trigger) { | 613 | if (irqd_get_trigger_type(data) != trigger) { |
642 | desc->status &= ~IRQ_TYPE_SENSE_MASK; | ||
643 | desc->status |= trigger; | ||
644 | sih->edge_change |= BIT(data->irq - sih->irq_base); | 614 | sih->edge_change |= BIT(data->irq - sih->irq_base); |
645 | queue_work(wq, &sih->edge_work); | 615 | queue_work(wq, &sih->edge_work); |
646 | } | 616 | } |
@@ -680,7 +650,7 @@ static inline int sih_read_isr(const struct sih *sih) | |||
680 | */ | 650 | */ |
681 | static void handle_twl4030_sih(unsigned irq, struct irq_desc *desc) | 651 | static void handle_twl4030_sih(unsigned irq, struct irq_desc *desc) |
682 | { | 652 | { |
683 | struct sih_agent *agent = get_irq_data(irq); | 653 | struct sih_agent *agent = irq_get_handler_data(irq); |
684 | const struct sih *sih = agent->sih; | 654 | const struct sih *sih = agent->sih; |
685 | int isr; | 655 | int isr; |
686 | 656 | ||
@@ -754,9 +724,9 @@ int twl4030_sih_setup(int module) | |||
754 | for (i = 0; i < sih->bits; i++) { | 724 | for (i = 0; i < sih->bits; i++) { |
755 | irq = irq_base + i; | 725 | irq = irq_base + i; |
756 | 726 | ||
757 | set_irq_chip_and_handler(irq, &twl4030_sih_irq_chip, | 727 | irq_set_chip_and_handler(irq, &twl4030_sih_irq_chip, |
758 | handle_edge_irq); | 728 | handle_edge_irq); |
759 | set_irq_chip_data(irq, agent); | 729 | irq_set_chip_data(irq, agent); |
760 | activate_irq(irq); | 730 | activate_irq(irq); |
761 | } | 731 | } |
762 | 732 | ||
@@ -765,8 +735,8 @@ int twl4030_sih_setup(int module) | |||
765 | 735 | ||
766 | /* replace generic PIH handler (handle_simple_irq) */ | 736 | /* replace generic PIH handler (handle_simple_irq) */ |
767 | irq = sih_mod + twl4030_irq_base; | 737 | irq = sih_mod + twl4030_irq_base; |
768 | set_irq_data(irq, agent); | 738 | irq_set_handler_data(irq, agent); |
769 | set_irq_chained_handler(irq, handle_twl4030_sih); | 739 | irq_set_chained_handler(irq, handle_twl4030_sih); |
770 | 740 | ||
771 | pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name, | 741 | pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name, |
772 | irq, irq_base, twl4030_irq_next - 1); | 742 | irq, irq_base, twl4030_irq_next - 1); |
@@ -815,8 +785,8 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | |||
815 | twl4030_sih_irq_chip.irq_ack = dummy_irq_chip.irq_ack; | 785 | twl4030_sih_irq_chip.irq_ack = dummy_irq_chip.irq_ack; |
816 | 786 | ||
817 | for (i = irq_base; i < irq_end; i++) { | 787 | for (i = irq_base; i < irq_end; i++) { |
818 | set_irq_chip_and_handler(i, &twl4030_irq_chip, | 788 | irq_set_chip_and_handler(i, &twl4030_irq_chip, |
819 | handle_simple_irq); | 789 | handle_simple_irq); |
820 | activate_irq(i); | 790 | activate_irq(i); |
821 | } | 791 | } |
822 | twl4030_irq_next = i; | 792 | twl4030_irq_next = i; |
@@ -856,7 +826,7 @@ fail_rqirq: | |||
856 | /* clean up twl4030_sih_setup */ | 826 | /* clean up twl4030_sih_setup */ |
857 | fail: | 827 | fail: |
858 | for (i = irq_base; i < irq_end; i++) | 828 | for (i = irq_base; i < irq_end; i++) |
859 | set_irq_chip_and_handler(i, NULL, NULL); | 829 | irq_set_chip_and_handler(i, NULL, NULL); |
860 | destroy_workqueue(wq); | 830 | destroy_workqueue(wq); |
861 | wq = NULL; | 831 | wq = NULL; |
862 | return status; | 832 | return status; |
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 4082ed73613f..fa937052fbab 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c | |||
@@ -140,22 +140,7 @@ static int twl6030_irq_thread(void *data) | |||
140 | if (sts.int_sts & 0x1) { | 140 | if (sts.int_sts & 0x1) { |
141 | int module_irq = twl6030_irq_base + | 141 | int module_irq = twl6030_irq_base + |
142 | twl6030_interrupt_mapping[i]; | 142 | twl6030_interrupt_mapping[i]; |
143 | struct irq_desc *d = irq_to_desc(module_irq); | 143 | generic_handle_irq(module_irq); |
144 | |||
145 | if (!d) { | ||
146 | pr_err("twl6030: Invalid SIH IRQ: %d\n", | ||
147 | module_irq); | ||
148 | return -EINVAL; | ||
149 | } | ||
150 | |||
151 | /* These can't be masked ... always warn | ||
152 | * if we get any surprises. | ||
153 | */ | ||
154 | if (d->status & IRQ_DISABLED) | ||
155 | note_interrupt(module_irq, d, | ||
156 | IRQ_NONE); | ||
157 | else | ||
158 | d->handle_irq(module_irq, d); | ||
159 | 144 | ||
160 | } | 145 | } |
161 | local_irq_enable(); | 146 | local_irq_enable(); |
@@ -198,7 +183,7 @@ static inline void activate_irq(int irq) | |||
198 | set_irq_flags(irq, IRQF_VALID); | 183 | set_irq_flags(irq, IRQF_VALID); |
199 | #else | 184 | #else |
200 | /* same effect on other architectures */ | 185 | /* same effect on other architectures */ |
201 | set_irq_noprobe(irq); | 186 | irq_set_noprobe(irq); |
202 | #endif | 187 | #endif |
203 | } | 188 | } |
204 | 189 | ||
@@ -335,8 +320,8 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) | |||
335 | twl6030_irq_chip.irq_set_type = NULL; | 320 | twl6030_irq_chip.irq_set_type = NULL; |
336 | 321 | ||
337 | for (i = irq_base; i < irq_end; i++) { | 322 | for (i = irq_base; i < irq_end; i++) { |
338 | set_irq_chip_and_handler(i, &twl6030_irq_chip, | 323 | irq_set_chip_and_handler(i, &twl6030_irq_chip, |
339 | handle_simple_irq); | 324 | handle_simple_irq); |
340 | activate_irq(i); | 325 | activate_irq(i); |
341 | } | 326 | } |
342 | 327 | ||
@@ -365,7 +350,7 @@ fail_irq: | |||
365 | 350 | ||
366 | fail_kthread: | 351 | fail_kthread: |
367 | for (i = irq_base; i < irq_end; i++) | 352 | for (i = irq_base; i < irq_end; i++) |
368 | set_irq_chip_and_handler(i, NULL, NULL); | 353 | irq_set_chip_and_handler(i, NULL, NULL); |
369 | return status; | 354 | return status; |
370 | } | 355 | } |
371 | 356 | ||
diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index f76f6c798046..04914f2836c0 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c | |||
@@ -25,7 +25,7 @@ | |||
25 | 25 | ||
26 | #define DRIVER_DESC "WL1273 FM Radio Core" | 26 | #define DRIVER_DESC "WL1273 FM Radio Core" |
27 | 27 | ||
28 | static struct i2c_device_id wl1273_driver_id_table[] = { | 28 | static const struct i2c_device_id wl1273_driver_id_table[] = { |
29 | { WL1273_FM_DRIVER_NAME, 0 }, | 29 | { WL1273_FM_DRIVER_NAME, 0 }, |
30 | { } | 30 | { } |
31 | }; | 31 | }; |
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index a5cd17e18d09..23e66af89dea 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c | |||
@@ -553,17 +553,17 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) | |||
553 | for (cur_irq = wm831x->irq_base; | 553 | for (cur_irq = wm831x->irq_base; |
554 | cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base; | 554 | cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base; |
555 | cur_irq++) { | 555 | cur_irq++) { |
556 | set_irq_chip_data(cur_irq, wm831x); | 556 | irq_set_chip_data(cur_irq, wm831x); |
557 | set_irq_chip_and_handler(cur_irq, &wm831x_irq_chip, | 557 | irq_set_chip_and_handler(cur_irq, &wm831x_irq_chip, |
558 | handle_edge_irq); | 558 | handle_edge_irq); |
559 | set_irq_nested_thread(cur_irq, 1); | 559 | irq_set_nested_thread(cur_irq, 1); |
560 | 560 | ||
561 | /* ARM needs us to explicitly flag the IRQ as valid | 561 | /* ARM needs us to explicitly flag the IRQ as valid |
562 | * and will set them noprobe when we do so. */ | 562 | * and will set them noprobe when we do so. */ |
563 | #ifdef CONFIG_ARM | 563 | #ifdef CONFIG_ARM |
564 | set_irq_flags(cur_irq, IRQF_VALID); | 564 | set_irq_flags(cur_irq, IRQF_VALID); |
565 | #else | 565 | #else |
566 | set_irq_noprobe(cur_irq); | 566 | irq_set_noprobe(cur_irq); |
567 | #endif | 567 | #endif |
568 | } | 568 | } |
569 | 569 | ||
diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c index 5839966ebd85..ed4b22a167b3 100644 --- a/drivers/mfd/wm8350-irq.c +++ b/drivers/mfd/wm8350-irq.c | |||
@@ -518,17 +518,17 @@ int wm8350_irq_init(struct wm8350 *wm8350, int irq, | |||
518 | for (cur_irq = wm8350->irq_base; | 518 | for (cur_irq = wm8350->irq_base; |
519 | cur_irq < ARRAY_SIZE(wm8350_irqs) + wm8350->irq_base; | 519 | cur_irq < ARRAY_SIZE(wm8350_irqs) + wm8350->irq_base; |
520 | cur_irq++) { | 520 | cur_irq++) { |
521 | set_irq_chip_data(cur_irq, wm8350); | 521 | irq_set_chip_data(cur_irq, wm8350); |
522 | set_irq_chip_and_handler(cur_irq, &wm8350_irq_chip, | 522 | irq_set_chip_and_handler(cur_irq, &wm8350_irq_chip, |
523 | handle_edge_irq); | 523 | handle_edge_irq); |
524 | set_irq_nested_thread(cur_irq, 1); | 524 | irq_set_nested_thread(cur_irq, 1); |
525 | 525 | ||
526 | /* ARM needs us to explicitly flag the IRQ as valid | 526 | /* ARM needs us to explicitly flag the IRQ as valid |
527 | * and will set them noprobe when we do so. */ | 527 | * and will set them noprobe when we do so. */ |
528 | #ifdef CONFIG_ARM | 528 | #ifdef CONFIG_ARM |
529 | set_irq_flags(cur_irq, IRQF_VALID); | 529 | set_irq_flags(cur_irq, IRQF_VALID); |
530 | #else | 530 | #else |
531 | set_irq_noprobe(cur_irq); | 531 | irq_set_noprobe(cur_irq); |
532 | #endif | 532 | #endif |
533 | } | 533 | } |
534 | 534 | ||
diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c index 1e3bf4a2ff8e..71c6e8f9aedb 100644 --- a/drivers/mfd/wm8994-irq.c +++ b/drivers/mfd/wm8994-irq.c | |||
@@ -278,17 +278,17 @@ int wm8994_irq_init(struct wm8994 *wm8994) | |||
278 | for (cur_irq = wm8994->irq_base; | 278 | for (cur_irq = wm8994->irq_base; |
279 | cur_irq < ARRAY_SIZE(wm8994_irqs) + wm8994->irq_base; | 279 | cur_irq < ARRAY_SIZE(wm8994_irqs) + wm8994->irq_base; |
280 | cur_irq++) { | 280 | cur_irq++) { |
281 | set_irq_chip_data(cur_irq, wm8994); | 281 | irq_set_chip_data(cur_irq, wm8994); |
282 | set_irq_chip_and_handler(cur_irq, &wm8994_irq_chip, | 282 | irq_set_chip_and_handler(cur_irq, &wm8994_irq_chip, |
283 | handle_edge_irq); | 283 | handle_edge_irq); |
284 | set_irq_nested_thread(cur_irq, 1); | 284 | irq_set_nested_thread(cur_irq, 1); |
285 | 285 | ||
286 | /* ARM needs us to explicitly flag the IRQ as valid | 286 | /* ARM needs us to explicitly flag the IRQ as valid |
287 | * and will set them noprobe when we do so. */ | 287 | * and will set them noprobe when we do so. */ |
288 | #ifdef CONFIG_ARM | 288 | #ifdef CONFIG_ARM |
289 | set_irq_flags(cur_irq, IRQF_VALID); | 289 | set_irq_flags(cur_irq, IRQF_VALID); |
290 | #else | 290 | #else |
291 | set_irq_noprobe(cur_irq); | 291 | irq_set_noprobe(cur_irq); |
292 | #endif | 292 | #endif |
293 | } | 293 | } |
294 | 294 | ||
diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 59c118c19a91..27dc463097f3 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c | |||
@@ -988,7 +988,7 @@ static void kgdbts_run_tests(void) | |||
988 | 988 | ||
989 | static int kgdbts_option_setup(char *opt) | 989 | static int kgdbts_option_setup(char *opt) |
990 | { | 990 | { |
991 | if (strlen(opt) > MAX_CONFIG_LEN) { | 991 | if (strlen(opt) >= MAX_CONFIG_LEN) { |
992 | printk(KERN_ERR "kgdbts: config string too long\n"); | 992 | printk(KERN_ERR "kgdbts: config string too long\n"); |
993 | return -ENOSPC; | 993 | return -ENOSPC; |
994 | } | 994 | } |
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 77414702cb00..b4567c35a322 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig | |||
@@ -33,14 +33,6 @@ config MTD_TESTS | |||
33 | should normally be compiled as kernel modules. The modules perform | 33 | should normally be compiled as kernel modules. The modules perform |
34 | various checks and verifications when loaded. | 34 | various checks and verifications when loaded. |
35 | 35 | ||
36 | config MTD_CONCAT | ||
37 | tristate "MTD concatenating support" | ||
38 | help | ||
39 | Support for concatenating several MTD devices into a single | ||
40 | (virtual) one. This allows you to have -for example- a JFFS(2) | ||
41 | file system spanning multiple physical flash chips. If unsure, | ||
42 | say 'Y'. | ||
43 | |||
44 | config MTD_PARTITIONS | 36 | config MTD_PARTITIONS |
45 | bool "MTD partitioning support" | 37 | bool "MTD partitioning support" |
46 | help | 38 | help |
@@ -333,6 +325,16 @@ config MTD_OOPS | |||
333 | To use, add console=ttyMTDx to the kernel command line, | 325 | To use, add console=ttyMTDx to the kernel command line, |
334 | where x is the MTD device number to use. | 326 | where x is the MTD device number to use. |
335 | 327 | ||
328 | config MTD_SWAP | ||
329 | tristate "Swap on MTD device support" | ||
330 | depends on MTD && SWAP | ||
331 | select MTD_BLKDEVS | ||
332 | help | ||
333 | Provides volatile block device driver on top of mtd partition | ||
334 | suitable for swapping. The mapping of written blocks is not saved. | ||
335 | The driver provides wear leveling by storing erase counter into the | ||
336 | OOB. | ||
337 | |||
336 | source "drivers/mtd/chips/Kconfig" | 338 | source "drivers/mtd/chips/Kconfig" |
337 | 339 | ||
338 | source "drivers/mtd/maps/Kconfig" | 340 | source "drivers/mtd/maps/Kconfig" |
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index d4e7f25b1ebb..d578095fb255 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile | |||
@@ -4,11 +4,10 @@ | |||
4 | 4 | ||
5 | # Core functionality. | 5 | # Core functionality. |
6 | obj-$(CONFIG_MTD) += mtd.o | 6 | obj-$(CONFIG_MTD) += mtd.o |
7 | mtd-y := mtdcore.o mtdsuper.o | 7 | mtd-y := mtdcore.o mtdsuper.o mtdconcat.o |
8 | mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o | 8 | mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o |
9 | mtd-$(CONFIG_MTD_OF_PARTS) += ofpart.o | 9 | mtd-$(CONFIG_MTD_OF_PARTS) += ofpart.o |
10 | 10 | ||
11 | obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o | ||
12 | obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o | 11 | obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o |
13 | obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o | 12 | obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o |
14 | obj-$(CONFIG_MTD_AFS_PARTS) += afs.o | 13 | obj-$(CONFIG_MTD_AFS_PARTS) += afs.o |
@@ -26,6 +25,7 @@ obj-$(CONFIG_RFD_FTL) += rfd_ftl.o | |||
26 | obj-$(CONFIG_SSFDC) += ssfdc.o | 25 | obj-$(CONFIG_SSFDC) += ssfdc.o |
27 | obj-$(CONFIG_SM_FTL) += sm_ftl.o | 26 | obj-$(CONFIG_SM_FTL) += sm_ftl.o |
28 | obj-$(CONFIG_MTD_OOPS) += mtdoops.o | 27 | obj-$(CONFIG_MTD_OOPS) += mtdoops.o |
28 | obj-$(CONFIG_MTD_SWAP) += mtdswap.o | ||
29 | 29 | ||
30 | nftl-objs := nftlcore.o nftlmount.o | 30 | nftl-objs := nftlcore.o nftlmount.o |
31 | inftl-objs := inftlcore.o inftlmount.o | 31 | inftl-objs := inftlcore.o inftlmount.o |
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 4aaa88f8ab5f..092aef11120c 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c | |||
@@ -455,7 +455,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) | |||
455 | mtd->flags = MTD_CAP_NORFLASH; | 455 | mtd->flags = MTD_CAP_NORFLASH; |
456 | mtd->name = map->name; | 456 | mtd->name = map->name; |
457 | mtd->writesize = 1; | 457 | mtd->writesize = 1; |
458 | mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize; | 458 | mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; |
459 | 459 | ||
460 | mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; | 460 | mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; |
461 | 461 | ||
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index f072fcfde04e..f9a5331e9445 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c | |||
@@ -349,6 +349,7 @@ static struct cfi_fixup cfi_fixup_table[] = { | |||
349 | { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri }, | 349 | { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri }, |
350 | #ifdef AMD_BOOTLOC_BUG | 350 | #ifdef AMD_BOOTLOC_BUG |
351 | { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock }, | 351 | { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock }, |
352 | { CFI_MFR_AMIC, CFI_ID_ANY, fixup_amd_bootblock }, | ||
352 | { CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock }, | 353 | { CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock }, |
353 | #endif | 354 | #endif |
354 | { CFI_MFR_AMD, 0x0050, fixup_use_secsi }, | 355 | { CFI_MFR_AMD, 0x0050, fixup_use_secsi }, |
@@ -440,7 +441,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | |||
440 | mtd->flags = MTD_CAP_NORFLASH; | 441 | mtd->flags = MTD_CAP_NORFLASH; |
441 | mtd->name = map->name; | 442 | mtd->name = map->name; |
442 | mtd->writesize = 1; | 443 | mtd->writesize = 1; |
443 | mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize; | 444 | mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; |
444 | 445 | ||
445 | DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): write buffer size %d\n", | 446 | DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): write buffer size %d\n", |
446 | __func__, mtd->writebufsize); | 447 | __func__, mtd->writebufsize); |
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index c04b7658abe9..ed56ad3884fb 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c | |||
@@ -238,7 +238,7 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) | |||
238 | mtd->resume = cfi_staa_resume; | 238 | mtd->resume = cfi_staa_resume; |
239 | mtd->flags = MTD_CAP_NORFLASH & ~MTD_BIT_WRITEABLE; | 239 | mtd->flags = MTD_CAP_NORFLASH & ~MTD_BIT_WRITEABLE; |
240 | mtd->writesize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */ | 240 | mtd->writesize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */ |
241 | mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize; | 241 | mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; |
242 | map->fldrv = &cfi_staa_chipdrv; | 242 | map->fldrv = &cfi_staa_chipdrv; |
243 | __module_get(THIS_MODULE); | 243 | __module_get(THIS_MODULE); |
244 | mtd->name = map->name; | 244 | mtd->name = map->name; |
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index e4eba6cc1b2e..3fb981d4bb51 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c | |||
@@ -655,7 +655,8 @@ static const struct spi_device_id m25p_ids[] = { | |||
655 | { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) }, | 655 | { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) }, |
656 | { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, | 656 | { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, |
657 | 657 | ||
658 | /* EON -- en25pxx */ | 658 | /* EON -- en25xxx */ |
659 | { "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) }, | ||
659 | { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, | 660 | { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, |
660 | { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, | 661 | { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, |
661 | 662 | ||
@@ -728,6 +729,8 @@ static const struct spi_device_id m25p_ids[] = { | |||
728 | { "m25pe80", INFO(0x208014, 0, 64 * 1024, 16, 0) }, | 729 | { "m25pe80", INFO(0x208014, 0, 64 * 1024, 16, 0) }, |
729 | { "m25pe16", INFO(0x208015, 0, 64 * 1024, 32, SECT_4K) }, | 730 | { "m25pe16", INFO(0x208015, 0, 64 * 1024, 32, SECT_4K) }, |
730 | 731 | ||
732 | { "m25px64", INFO(0x207117, 0, 64 * 1024, 128, 0) }, | ||
733 | |||
731 | /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ | 734 | /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ |
732 | { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, | 735 | { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, |
733 | { "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) }, | 736 | { "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) }, |
diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index 26a6e809013d..1483e18971ce 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c | |||
@@ -121,6 +121,7 @@ int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, | |||
121 | mtd->flags = MTD_CAP_RAM; | 121 | mtd->flags = MTD_CAP_RAM; |
122 | mtd->size = size; | 122 | mtd->size = size; |
123 | mtd->writesize = 1; | 123 | mtd->writesize = 1; |
124 | mtd->writebufsize = 64; /* Mimic CFI NOR flashes */ | ||
124 | mtd->erasesize = MTDRAM_ERASE_SIZE; | 125 | mtd->erasesize = MTDRAM_ERASE_SIZE; |
125 | mtd->priv = mapped_address; | 126 | mtd->priv = mapped_address; |
126 | 127 | ||
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 52393282eaf1..8d28fa02a5a2 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c | |||
@@ -117,6 +117,7 @@ static void unregister_devices(void) | |||
117 | list_for_each_entry_safe(this, safe, &phram_list, list) { | 117 | list_for_each_entry_safe(this, safe, &phram_list, list) { |
118 | del_mtd_device(&this->mtd); | 118 | del_mtd_device(&this->mtd); |
119 | iounmap(this->mtd.priv); | 119 | iounmap(this->mtd.priv); |
120 | kfree(this->mtd.name); | ||
120 | kfree(this); | 121 | kfree(this); |
121 | } | 122 | } |
122 | } | 123 | } |
@@ -275,6 +276,8 @@ static int phram_setup(const char *val, struct kernel_param *kp) | |||
275 | ret = register_device(name, start, len); | 276 | ret = register_device(name, start, len); |
276 | if (!ret) | 277 | if (!ret) |
277 | pr_info("%s device: %#x at %#x\n", name, len, start); | 278 | pr_info("%s device: %#x at %#x\n", name, len, start); |
279 | else | ||
280 | kfree(name); | ||
278 | 281 | ||
279 | return ret; | 282 | return ret; |
280 | } | 283 | } |
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 5d37d315fa98..44b1f46458ca 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig | |||
@@ -114,7 +114,7 @@ config MTD_SUN_UFLASH | |||
114 | 114 | ||
115 | config MTD_SC520CDP | 115 | config MTD_SC520CDP |
116 | tristate "CFI Flash device mapped on AMD SC520 CDP" | 116 | tristate "CFI Flash device mapped on AMD SC520 CDP" |
117 | depends on X86 && MTD_CFI && MTD_CONCAT | 117 | depends on X86 && MTD_CFI |
118 | help | 118 | help |
119 | The SC520 CDP board has two banks of CFI-compliant chips and one | 119 | The SC520 CDP board has two banks of CFI-compliant chips and one |
120 | Dual-in-line JEDEC chip. This 'mapping' driver supports that | 120 | Dual-in-line JEDEC chip. This 'mapping' driver supports that |
@@ -262,7 +262,7 @@ config MTD_BCM963XX | |||
262 | 262 | ||
263 | config MTD_DILNETPC | 263 | config MTD_DILNETPC |
264 | tristate "CFI Flash device mapped on DIL/Net PC" | 264 | tristate "CFI Flash device mapped on DIL/Net PC" |
265 | depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN | 265 | depends on X86 && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN |
266 | help | 266 | help |
267 | MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP". | 267 | MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP". |
268 | For details, see <http://www.ssv-embedded.de/ssv/pc104/p169.htm> | 268 | For details, see <http://www.ssv-embedded.de/ssv/pc104/p169.htm> |
@@ -552,4 +552,13 @@ config MTD_PISMO | |||
552 | 552 | ||
553 | When built as a module, it will be called pismo.ko | 553 | When built as a module, it will be called pismo.ko |
554 | 554 | ||
555 | config MTD_LATCH_ADDR | ||
556 | tristate "Latch-assisted Flash Chip Support" | ||
557 | depends on MTD_COMPLEX_MAPPINGS | ||
558 | help | ||
559 | Map driver which allows flashes to be partially physically addressed | ||
560 | and have the upper address lines set by a board specific code. | ||
561 | |||
562 | If compiled as a module, it will be called latch-addr-flash. | ||
563 | |||
555 | endmenu | 564 | endmenu |
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index c7869c7a6b18..08533bd5cba7 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile | |||
@@ -59,3 +59,4 @@ obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o | |||
59 | obj-$(CONFIG_MTD_VMU) += vmu-flash.o | 59 | obj-$(CONFIG_MTD_VMU) += vmu-flash.o |
60 | obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o | 60 | obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o |
61 | obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o | 61 | obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o |
62 | obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o | ||
diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c index c09f4f57093e..e5f645b775ad 100644 --- a/drivers/mtd/maps/ceiva.c +++ b/drivers/mtd/maps/ceiva.c | |||
@@ -194,16 +194,10 @@ static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info | |||
194 | * We detected multiple devices. Concatenate | 194 | * We detected multiple devices. Concatenate |
195 | * them together. | 195 | * them together. |
196 | */ | 196 | */ |
197 | #ifdef CONFIG_MTD_CONCAT | ||
198 | *rmtd = mtd_concat_create(subdev, found, | 197 | *rmtd = mtd_concat_create(subdev, found, |
199 | "clps flash"); | 198 | "clps flash"); |
200 | if (*rmtd == NULL) | 199 | if (*rmtd == NULL) |
201 | ret = -ENXIO; | 200 | ret = -ENXIO; |
202 | #else | ||
203 | printk(KERN_ERR "clps flash: multiple devices " | ||
204 | "found but MTD concat support disabled.\n"); | ||
205 | ret = -ENXIO; | ||
206 | #endif | ||
207 | } | 201 | } |
208 | } | 202 | } |
209 | 203 | ||
diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c index 2aac41bde8b3..e22ff5adbbf4 100644 --- a/drivers/mtd/maps/integrator-flash.c +++ b/drivers/mtd/maps/integrator-flash.c | |||
@@ -202,7 +202,6 @@ static int armflash_probe(struct platform_device *dev) | |||
202 | if (info->nr_subdev == 1) | 202 | if (info->nr_subdev == 1) |
203 | info->mtd = info->subdev[0].mtd; | 203 | info->mtd = info->subdev[0].mtd; |
204 | else if (info->nr_subdev > 1) { | 204 | else if (info->nr_subdev > 1) { |
205 | #ifdef CONFIG_MTD_CONCAT | ||
206 | struct mtd_info *cdev[info->nr_subdev]; | 205 | struct mtd_info *cdev[info->nr_subdev]; |
207 | 206 | ||
208 | /* | 207 | /* |
@@ -215,11 +214,6 @@ static int armflash_probe(struct platform_device *dev) | |||
215 | dev_name(&dev->dev)); | 214 | dev_name(&dev->dev)); |
216 | if (info->mtd == NULL) | 215 | if (info->mtd == NULL) |
217 | err = -ENXIO; | 216 | err = -ENXIO; |
218 | #else | ||
219 | printk(KERN_ERR "armflash: multiple devices found but " | ||
220 | "MTD concat support disabled.\n"); | ||
221 | err = -ENXIO; | ||
222 | #endif | ||
223 | } | 217 | } |
224 | 218 | ||
225 | if (err < 0) | 219 | if (err < 0) |
@@ -244,10 +238,8 @@ static int armflash_probe(struct platform_device *dev) | |||
244 | cleanup: | 238 | cleanup: |
245 | if (info->mtd) { | 239 | if (info->mtd) { |
246 | del_mtd_partitions(info->mtd); | 240 | del_mtd_partitions(info->mtd); |
247 | #ifdef CONFIG_MTD_CONCAT | ||
248 | if (info->mtd != info->subdev[0].mtd) | 241 | if (info->mtd != info->subdev[0].mtd) |
249 | mtd_concat_destroy(info->mtd); | 242 | mtd_concat_destroy(info->mtd); |
250 | #endif | ||
251 | } | 243 | } |
252 | kfree(info->parts); | 244 | kfree(info->parts); |
253 | subdev_err: | 245 | subdev_err: |
@@ -272,10 +264,8 @@ static int armflash_remove(struct platform_device *dev) | |||
272 | if (info) { | 264 | if (info) { |
273 | if (info->mtd) { | 265 | if (info->mtd) { |
274 | del_mtd_partitions(info->mtd); | 266 | del_mtd_partitions(info->mtd); |
275 | #ifdef CONFIG_MTD_CONCAT | ||
276 | if (info->mtd != info->subdev[0].mtd) | 267 | if (info->mtd != info->subdev[0].mtd) |
277 | mtd_concat_destroy(info->mtd); | 268 | mtd_concat_destroy(info->mtd); |
278 | #endif | ||
279 | } | 269 | } |
280 | kfree(info->parts); | 270 | kfree(info->parts); |
281 | 271 | ||
diff --git a/drivers/mtd/maps/latch-addr-flash.c b/drivers/mtd/maps/latch-addr-flash.c new file mode 100644 index 000000000000..ee2548085334 --- /dev/null +++ b/drivers/mtd/maps/latch-addr-flash.c | |||
@@ -0,0 +1,272 @@ | |||
1 | /* | ||
2 | * Interface for NOR flash driver whose high address lines are latched | ||
3 | * | ||
4 | * Copyright © 2000 Nicolas Pitre <nico@cam.org> | ||
5 | * Copyright © 2005-2008 Analog Devices Inc. | ||
6 | * Copyright © 2008 MontaVista Software, Inc. <source@mvista.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public License | ||
9 | * version 2. This program is licensed "as is" without any warranty of any | ||
10 | * kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/mtd/mtd.h> | ||
17 | #include <linux/mtd/map.h> | ||
18 | #include <linux/mtd/partitions.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/mtd/latch-addr-flash.h> | ||
21 | #include <linux/slab.h> | ||
22 | |||
23 | #define DRIVER_NAME "latch-addr-flash" | ||
24 | |||
25 | struct latch_addr_flash_info { | ||
26 | struct mtd_info *mtd; | ||
27 | struct map_info map; | ||
28 | struct resource *res; | ||
29 | |||
30 | void (*set_window)(unsigned long offset, void *data); | ||
31 | void *data; | ||
32 | |||
33 | /* cache; could be found out of res */ | ||
34 | unsigned long win_mask; | ||
35 | |||
36 | int nr_parts; | ||
37 | struct mtd_partition *parts; | ||
38 | |||
39 | spinlock_t lock; | ||
40 | }; | ||
41 | |||
42 | static map_word lf_read(struct map_info *map, unsigned long ofs) | ||
43 | { | ||
44 | struct latch_addr_flash_info *info; | ||
45 | map_word datum; | ||
46 | |||
47 | info = (struct latch_addr_flash_info *)map->map_priv_1; | ||
48 | |||
49 | spin_lock(&info->lock); | ||
50 | |||
51 | info->set_window(ofs, info->data); | ||
52 | datum = inline_map_read(map, info->win_mask & ofs); | ||
53 | |||
54 | spin_unlock(&info->lock); | ||
55 | |||
56 | return datum; | ||
57 | } | ||
58 | |||
59 | static void lf_write(struct map_info *map, map_word datum, unsigned long ofs) | ||
60 | { | ||
61 | struct latch_addr_flash_info *info; | ||
62 | |||
63 | info = (struct latch_addr_flash_info *)map->map_priv_1; | ||
64 | |||
65 | spin_lock(&info->lock); | ||
66 | |||
67 | info->set_window(ofs, info->data); | ||
68 | inline_map_write(map, datum, info->win_mask & ofs); | ||
69 | |||
70 | spin_unlock(&info->lock); | ||
71 | } | ||
72 | |||
73 | static void lf_copy_from(struct map_info *map, void *to, | ||
74 | unsigned long from, ssize_t len) | ||
75 | { | ||
76 | struct latch_addr_flash_info *info = | ||
77 | (struct latch_addr_flash_info *) map->map_priv_1; | ||
78 | unsigned n; | ||
79 | |||
80 | while (len > 0) { | ||
81 | n = info->win_mask + 1 - (from & info->win_mask); | ||
82 | if (n > len) | ||
83 | n = len; | ||
84 | |||
85 | spin_lock(&info->lock); | ||
86 | |||
87 | info->set_window(from, info->data); | ||
88 | memcpy_fromio(to, map->virt + (from & info->win_mask), n); | ||
89 | |||
90 | spin_unlock(&info->lock); | ||
91 | |||
92 | to += n; | ||
93 | from += n; | ||
94 | len -= n; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | static char *rom_probe_types[] = { "cfi_probe", NULL }; | ||
99 | |||
100 | static char *part_probe_types[] = { "cmdlinepart", NULL }; | ||
101 | |||
102 | static int latch_addr_flash_remove(struct platform_device *dev) | ||
103 | { | ||
104 | struct latch_addr_flash_info *info; | ||
105 | struct latch_addr_flash_data *latch_addr_data; | ||
106 | |||
107 | info = platform_get_drvdata(dev); | ||
108 | if (info == NULL) | ||
109 | return 0; | ||
110 | platform_set_drvdata(dev, NULL); | ||
111 | |||
112 | latch_addr_data = dev->dev.platform_data; | ||
113 | |||
114 | if (info->mtd != NULL) { | ||
115 | if (mtd_has_partitions()) { | ||
116 | if (info->nr_parts) { | ||
117 | del_mtd_partitions(info->mtd); | ||
118 | kfree(info->parts); | ||
119 | } else if (latch_addr_data->nr_parts) { | ||
120 | del_mtd_partitions(info->mtd); | ||
121 | } else { | ||
122 | del_mtd_device(info->mtd); | ||
123 | } | ||
124 | } else { | ||
125 | del_mtd_device(info->mtd); | ||
126 | } | ||
127 | map_destroy(info->mtd); | ||
128 | } | ||
129 | |||
130 | if (info->map.virt != NULL) | ||
131 | iounmap(info->map.virt); | ||
132 | |||
133 | if (info->res != NULL) | ||
134 | release_mem_region(info->res->start, resource_size(info->res)); | ||
135 | |||
136 | kfree(info); | ||
137 | |||
138 | if (latch_addr_data->done) | ||
139 | latch_addr_data->done(latch_addr_data->data); | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int __devinit latch_addr_flash_probe(struct platform_device *dev) | ||
145 | { | ||
146 | struct latch_addr_flash_data *latch_addr_data; | ||
147 | struct latch_addr_flash_info *info; | ||
148 | resource_size_t win_base = dev->resource->start; | ||
149 | resource_size_t win_size = resource_size(dev->resource); | ||
150 | char **probe_type; | ||
151 | int chipsel; | ||
152 | int err; | ||
153 | |||
154 | latch_addr_data = dev->dev.platform_data; | ||
155 | if (latch_addr_data == NULL) | ||
156 | return -ENODEV; | ||
157 | |||
158 | pr_notice("latch-addr platform flash device: %#llx byte " | ||
159 | "window at %#.8llx\n", | ||
160 | (unsigned long long)win_size, (unsigned long long)win_base); | ||
161 | |||
162 | chipsel = dev->id; | ||
163 | |||
164 | if (latch_addr_data->init) { | ||
165 | err = latch_addr_data->init(latch_addr_data->data, chipsel); | ||
166 | if (err != 0) | ||
167 | return err; | ||
168 | } | ||
169 | |||
170 | info = kzalloc(sizeof(struct latch_addr_flash_info), GFP_KERNEL); | ||
171 | if (info == NULL) { | ||
172 | err = -ENOMEM; | ||
173 | goto done; | ||
174 | } | ||
175 | |||
176 | platform_set_drvdata(dev, info); | ||
177 | |||
178 | info->res = request_mem_region(win_base, win_size, DRIVER_NAME); | ||
179 | if (info->res == NULL) { | ||
180 | dev_err(&dev->dev, "Could not reserve memory region\n"); | ||
181 | err = -EBUSY; | ||
182 | goto free_info; | ||
183 | } | ||
184 | |||
185 | info->map.name = DRIVER_NAME; | ||
186 | info->map.size = latch_addr_data->size; | ||
187 | info->map.bankwidth = latch_addr_data->width; | ||
188 | |||
189 | info->map.phys = NO_XIP; | ||
190 | info->map.virt = ioremap(win_base, win_size); | ||
191 | if (!info->map.virt) { | ||
192 | err = -ENOMEM; | ||
193 | goto free_res; | ||
194 | } | ||
195 | |||
196 | info->map.map_priv_1 = (unsigned long)info; | ||
197 | |||
198 | info->map.read = lf_read; | ||
199 | info->map.copy_from = lf_copy_from; | ||
200 | info->map.write = lf_write; | ||
201 | info->set_window = latch_addr_data->set_window; | ||
202 | info->data = latch_addr_data->data; | ||
203 | info->win_mask = win_size - 1; | ||
204 | |||
205 | spin_lock_init(&info->lock); | ||
206 | |||
207 | for (probe_type = rom_probe_types; !info->mtd && *probe_type; | ||
208 | probe_type++) | ||
209 | info->mtd = do_map_probe(*probe_type, &info->map); | ||
210 | |||
211 | if (info->mtd == NULL) { | ||
212 | dev_err(&dev->dev, "map_probe failed\n"); | ||
213 | err = -ENODEV; | ||
214 | goto iounmap; | ||
215 | } | ||
216 | info->mtd->owner = THIS_MODULE; | ||
217 | |||
218 | if (mtd_has_partitions()) { | ||
219 | |||
220 | err = parse_mtd_partitions(info->mtd, | ||
221 | (const char **)part_probe_types, | ||
222 | &info->parts, 0); | ||
223 | if (err > 0) { | ||
224 | add_mtd_partitions(info->mtd, info->parts, err); | ||
225 | return 0; | ||
226 | } | ||
227 | if (latch_addr_data->nr_parts) { | ||
228 | pr_notice("Using latch-addr-flash partition information\n"); | ||
229 | add_mtd_partitions(info->mtd, latch_addr_data->parts, | ||
230 | latch_addr_data->nr_parts); | ||
231 | return 0; | ||
232 | } | ||
233 | } | ||
234 | add_mtd_device(info->mtd); | ||
235 | return 0; | ||
236 | |||
237 | iounmap: | ||
238 | iounmap(info->map.virt); | ||
239 | free_res: | ||
240 | release_mem_region(info->res->start, resource_size(info->res)); | ||
241 | free_info: | ||
242 | kfree(info); | ||
243 | done: | ||
244 | if (latch_addr_data->done) | ||
245 | latch_addr_data->done(latch_addr_data->data); | ||
246 | return err; | ||
247 | } | ||
248 | |||
249 | static struct platform_driver latch_addr_flash_driver = { | ||
250 | .probe = latch_addr_flash_probe, | ||
251 | .remove = __devexit_p(latch_addr_flash_remove), | ||
252 | .driver = { | ||
253 | .name = DRIVER_NAME, | ||
254 | }, | ||
255 | }; | ||
256 | |||
257 | static int __init latch_addr_flash_init(void) | ||
258 | { | ||
259 | return platform_driver_register(&latch_addr_flash_driver); | ||
260 | } | ||
261 | module_init(latch_addr_flash_init); | ||
262 | |||
263 | static void __exit latch_addr_flash_exit(void) | ||
264 | { | ||
265 | platform_driver_unregister(&latch_addr_flash_driver); | ||
266 | } | ||
267 | module_exit(latch_addr_flash_exit); | ||
268 | |||
269 | MODULE_AUTHOR("David Griego <dgriego@mvista.com>"); | ||
270 | MODULE_DESCRIPTION("MTD map driver for flashes addressed physically with upper " | ||
271 | "address lines being set board specifically"); | ||
272 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index 4c18b98a3110..7522df4f71f1 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c | |||
@@ -59,10 +59,8 @@ static int physmap_flash_remove(struct platform_device *dev) | |||
59 | #else | 59 | #else |
60 | del_mtd_device(info->cmtd); | 60 | del_mtd_device(info->cmtd); |
61 | #endif | 61 | #endif |
62 | #ifdef CONFIG_MTD_CONCAT | ||
63 | if (info->cmtd != info->mtd[0]) | 62 | if (info->cmtd != info->mtd[0]) |
64 | mtd_concat_destroy(info->cmtd); | 63 | mtd_concat_destroy(info->cmtd); |
65 | #endif | ||
66 | } | 64 | } |
67 | 65 | ||
68 | for (i = 0; i < MAX_RESOURCES; i++) { | 66 | for (i = 0; i < MAX_RESOURCES; i++) { |
@@ -159,15 +157,9 @@ static int physmap_flash_probe(struct platform_device *dev) | |||
159 | /* | 157 | /* |
160 | * We detected multiple devices. Concatenate them together. | 158 | * We detected multiple devices. Concatenate them together. |
161 | */ | 159 | */ |
162 | #ifdef CONFIG_MTD_CONCAT | ||
163 | info->cmtd = mtd_concat_create(info->mtd, devices_found, dev_name(&dev->dev)); | 160 | info->cmtd = mtd_concat_create(info->mtd, devices_found, dev_name(&dev->dev)); |
164 | if (info->cmtd == NULL) | 161 | if (info->cmtd == NULL) |
165 | err = -ENXIO; | 162 | err = -ENXIO; |
166 | #else | ||
167 | printk(KERN_ERR "physmap-flash: multiple devices " | ||
168 | "found but MTD concat support disabled.\n"); | ||
169 | err = -ENXIO; | ||
170 | #endif | ||
171 | } | 163 | } |
172 | if (err) | 164 | if (err) |
173 | goto err_out; | 165 | goto err_out; |
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 3db0cb083d31..bd483f0c57e1 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c | |||
@@ -104,12 +104,10 @@ static int of_flash_remove(struct platform_device *dev) | |||
104 | return 0; | 104 | return 0; |
105 | dev_set_drvdata(&dev->dev, NULL); | 105 | dev_set_drvdata(&dev->dev, NULL); |
106 | 106 | ||
107 | #ifdef CONFIG_MTD_CONCAT | ||
108 | if (info->cmtd != info->list[0].mtd) { | 107 | if (info->cmtd != info->list[0].mtd) { |
109 | del_mtd_device(info->cmtd); | 108 | del_mtd_device(info->cmtd); |
110 | mtd_concat_destroy(info->cmtd); | 109 | mtd_concat_destroy(info->cmtd); |
111 | } | 110 | } |
112 | #endif | ||
113 | 111 | ||
114 | if (info->cmtd) { | 112 | if (info->cmtd) { |
115 | if (OF_FLASH_PARTS(info)) { | 113 | if (OF_FLASH_PARTS(info)) { |
@@ -337,16 +335,10 @@ static int __devinit of_flash_probe(struct platform_device *dev) | |||
337 | /* | 335 | /* |
338 | * We detected multiple devices. Concatenate them together. | 336 | * We detected multiple devices. Concatenate them together. |
339 | */ | 337 | */ |
340 | #ifdef CONFIG_MTD_CONCAT | ||
341 | info->cmtd = mtd_concat_create(mtd_list, info->list_size, | 338 | info->cmtd = mtd_concat_create(mtd_list, info->list_size, |
342 | dev_name(&dev->dev)); | 339 | dev_name(&dev->dev)); |
343 | if (info->cmtd == NULL) | 340 | if (info->cmtd == NULL) |
344 | err = -ENXIO; | 341 | err = -ENXIO; |
345 | #else | ||
346 | printk(KERN_ERR "physmap_of: multiple devices " | ||
347 | "found but MTD concat support disabled.\n"); | ||
348 | err = -ENXIO; | ||
349 | #endif | ||
350 | } | 342 | } |
351 | if (err) | 343 | if (err) |
352 | goto err_out; | 344 | goto err_out; |
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index f3af87e08ecd..da875908ea8e 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c | |||
@@ -232,10 +232,8 @@ static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *pla | |||
232 | else | 232 | else |
233 | del_mtd_partitions(info->mtd); | 233 | del_mtd_partitions(info->mtd); |
234 | #endif | 234 | #endif |
235 | #ifdef CONFIG_MTD_CONCAT | ||
236 | if (info->mtd != info->subdev[0].mtd) | 235 | if (info->mtd != info->subdev[0].mtd) |
237 | mtd_concat_destroy(info->mtd); | 236 | mtd_concat_destroy(info->mtd); |
238 | #endif | ||
239 | } | 237 | } |
240 | 238 | ||
241 | kfree(info->parts); | 239 | kfree(info->parts); |
@@ -321,7 +319,6 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat) | |||
321 | info->mtd = info->subdev[0].mtd; | 319 | info->mtd = info->subdev[0].mtd; |
322 | ret = 0; | 320 | ret = 0; |
323 | } else if (info->num_subdev > 1) { | 321 | } else if (info->num_subdev > 1) { |
324 | #ifdef CONFIG_MTD_CONCAT | ||
325 | struct mtd_info *cdev[nr]; | 322 | struct mtd_info *cdev[nr]; |
326 | /* | 323 | /* |
327 | * We detected multiple devices. Concatenate them together. | 324 | * We detected multiple devices. Concatenate them together. |
@@ -333,11 +330,6 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat) | |||
333 | plat->name); | 330 | plat->name); |
334 | if (info->mtd == NULL) | 331 | if (info->mtd == NULL) |
335 | ret = -ENXIO; | 332 | ret = -ENXIO; |
336 | #else | ||
337 | printk(KERN_ERR "SA1100 flash: multiple devices " | ||
338 | "found but MTD concat support disabled.\n"); | ||
339 | ret = -ENXIO; | ||
340 | #endif | ||
341 | } | 333 | } |
342 | 334 | ||
343 | if (ret == 0) | 335 | if (ret == 0) |
diff --git a/drivers/mtd/maps/ts5500_flash.c b/drivers/mtd/maps/ts5500_flash.c index e2147bf11c88..e02dfa9d4ddd 100644 --- a/drivers/mtd/maps/ts5500_flash.c +++ b/drivers/mtd/maps/ts5500_flash.c | |||
@@ -94,7 +94,6 @@ static int __init init_ts5500_map(void) | |||
94 | return 0; | 94 | return 0; |
95 | 95 | ||
96 | err1: | 96 | err1: |
97 | map_destroy(mymtd); | ||
98 | iounmap(ts5500_map.virt); | 97 | iounmap(ts5500_map.virt); |
99 | err2: | 98 | err2: |
100 | return rc; | 99 | return rc; |
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index e0a2373bf0e2..a534e1f0c348 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c | |||
@@ -40,7 +40,7 @@ | |||
40 | static LIST_HEAD(blktrans_majors); | 40 | static LIST_HEAD(blktrans_majors); |
41 | static DEFINE_MUTEX(blktrans_ref_mutex); | 41 | static DEFINE_MUTEX(blktrans_ref_mutex); |
42 | 42 | ||
43 | void blktrans_dev_release(struct kref *kref) | 43 | static void blktrans_dev_release(struct kref *kref) |
44 | { | 44 | { |
45 | struct mtd_blktrans_dev *dev = | 45 | struct mtd_blktrans_dev *dev = |
46 | container_of(kref, struct mtd_blktrans_dev, ref); | 46 | container_of(kref, struct mtd_blktrans_dev, ref); |
@@ -67,7 +67,7 @@ unlock: | |||
67 | return dev; | 67 | return dev; |
68 | } | 68 | } |
69 | 69 | ||
70 | void blktrans_dev_put(struct mtd_blktrans_dev *dev) | 70 | static void blktrans_dev_put(struct mtd_blktrans_dev *dev) |
71 | { | 71 | { |
72 | mutex_lock(&blktrans_ref_mutex); | 72 | mutex_lock(&blktrans_ref_mutex); |
73 | kref_put(&dev->ref, blktrans_dev_release); | 73 | kref_put(&dev->ref, blktrans_dev_release); |
@@ -119,18 +119,43 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, | |||
119 | } | 119 | } |
120 | } | 120 | } |
121 | 121 | ||
122 | int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev) | ||
123 | { | ||
124 | if (kthread_should_stop()) | ||
125 | return 1; | ||
126 | |||
127 | return dev->bg_stop; | ||
128 | } | ||
129 | EXPORT_SYMBOL_GPL(mtd_blktrans_cease_background); | ||
130 | |||
122 | static int mtd_blktrans_thread(void *arg) | 131 | static int mtd_blktrans_thread(void *arg) |
123 | { | 132 | { |
124 | struct mtd_blktrans_dev *dev = arg; | 133 | struct mtd_blktrans_dev *dev = arg; |
134 | struct mtd_blktrans_ops *tr = dev->tr; | ||
125 | struct request_queue *rq = dev->rq; | 135 | struct request_queue *rq = dev->rq; |
126 | struct request *req = NULL; | 136 | struct request *req = NULL; |
137 | int background_done = 0; | ||
127 | 138 | ||
128 | spin_lock_irq(rq->queue_lock); | 139 | spin_lock_irq(rq->queue_lock); |
129 | 140 | ||
130 | while (!kthread_should_stop()) { | 141 | while (!kthread_should_stop()) { |
131 | int res; | 142 | int res; |
132 | 143 | ||
144 | dev->bg_stop = false; | ||
133 | if (!req && !(req = blk_fetch_request(rq))) { | 145 | if (!req && !(req = blk_fetch_request(rq))) { |
146 | if (tr->background && !background_done) { | ||
147 | spin_unlock_irq(rq->queue_lock); | ||
148 | mutex_lock(&dev->lock); | ||
149 | tr->background(dev); | ||
150 | mutex_unlock(&dev->lock); | ||
151 | spin_lock_irq(rq->queue_lock); | ||
152 | /* | ||
153 | * Do background processing just once per idle | ||
154 | * period. | ||
155 | */ | ||
156 | background_done = !dev->bg_stop; | ||
157 | continue; | ||
158 | } | ||
134 | set_current_state(TASK_INTERRUPTIBLE); | 159 | set_current_state(TASK_INTERRUPTIBLE); |
135 | 160 | ||
136 | if (kthread_should_stop()) | 161 | if (kthread_should_stop()) |
@@ -152,6 +177,8 @@ static int mtd_blktrans_thread(void *arg) | |||
152 | 177 | ||
153 | if (!__blk_end_request_cur(req, res)) | 178 | if (!__blk_end_request_cur(req, res)) |
154 | req = NULL; | 179 | req = NULL; |
180 | |||
181 | background_done = 0; | ||
155 | } | 182 | } |
156 | 183 | ||
157 | if (req) | 184 | if (req) |
@@ -172,8 +199,10 @@ static void mtd_blktrans_request(struct request_queue *rq) | |||
172 | if (!dev) | 199 | if (!dev) |
173 | while ((req = blk_fetch_request(rq)) != NULL) | 200 | while ((req = blk_fetch_request(rq)) != NULL) |
174 | __blk_end_request_all(req, -ENODEV); | 201 | __blk_end_request_all(req, -ENODEV); |
175 | else | 202 | else { |
203 | dev->bg_stop = true; | ||
176 | wake_up_process(dev->thread); | 204 | wake_up_process(dev->thread); |
205 | } | ||
177 | } | 206 | } |
178 | 207 | ||
179 | static int blktrans_open(struct block_device *bdev, fmode_t mode) | 208 | static int blktrans_open(struct block_device *bdev, fmode_t mode) |
@@ -379,9 +408,10 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | |||
379 | new->rq->queuedata = new; | 408 | new->rq->queuedata = new; |
380 | blk_queue_logical_block_size(new->rq, tr->blksize); | 409 | blk_queue_logical_block_size(new->rq, tr->blksize); |
381 | 410 | ||
382 | if (tr->discard) | 411 | if (tr->discard) { |
383 | queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, | 412 | queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, new->rq); |
384 | new->rq); | 413 | new->rq->limits.max_discard_sectors = UINT_MAX; |
414 | } | ||
385 | 415 | ||
386 | gd->queue = new->rq; | 416 | gd->queue = new->rq; |
387 | 417 | ||
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 5f5777bd3f75..5060e608ea5d 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c | |||
@@ -750,6 +750,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c | |||
750 | struct mtd_concat *concat; | 750 | struct mtd_concat *concat; |
751 | uint32_t max_erasesize, curr_erasesize; | 751 | uint32_t max_erasesize, curr_erasesize; |
752 | int num_erase_region; | 752 | int num_erase_region; |
753 | int max_writebufsize = 0; | ||
753 | 754 | ||
754 | printk(KERN_NOTICE "Concatenating MTD devices:\n"); | 755 | printk(KERN_NOTICE "Concatenating MTD devices:\n"); |
755 | for (i = 0; i < num_devs; i++) | 756 | for (i = 0; i < num_devs; i++) |
@@ -776,7 +777,12 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c | |||
776 | concat->mtd.size = subdev[0]->size; | 777 | concat->mtd.size = subdev[0]->size; |
777 | concat->mtd.erasesize = subdev[0]->erasesize; | 778 | concat->mtd.erasesize = subdev[0]->erasesize; |
778 | concat->mtd.writesize = subdev[0]->writesize; | 779 | concat->mtd.writesize = subdev[0]->writesize; |
779 | concat->mtd.writebufsize = subdev[0]->writebufsize; | 780 | |
781 | for (i = 0; i < num_devs; i++) | ||
782 | if (max_writebufsize < subdev[i]->writebufsize) | ||
783 | max_writebufsize = subdev[i]->writebufsize; | ||
784 | concat->mtd.writebufsize = max_writebufsize; | ||
785 | |||
780 | concat->mtd.subpage_sft = subdev[0]->subpage_sft; | 786 | concat->mtd.subpage_sft = subdev[0]->subpage_sft; |
781 | concat->mtd.oobsize = subdev[0]->oobsize; | 787 | concat->mtd.oobsize = subdev[0]->oobsize; |
782 | concat->mtd.oobavail = subdev[0]->oobavail; | 788 | concat->mtd.oobavail = subdev[0]->oobavail; |
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 527cebf58da4..da69bc8a5a7d 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c | |||
@@ -43,7 +43,7 @@ | |||
43 | * backing device capabilities for non-mappable devices (such as NAND flash) | 43 | * backing device capabilities for non-mappable devices (such as NAND flash) |
44 | * - permits private mappings, copies are taken of the data | 44 | * - permits private mappings, copies are taken of the data |
45 | */ | 45 | */ |
46 | struct backing_dev_info mtd_bdi_unmappable = { | 46 | static struct backing_dev_info mtd_bdi_unmappable = { |
47 | .capabilities = BDI_CAP_MAP_COPY, | 47 | .capabilities = BDI_CAP_MAP_COPY, |
48 | }; | 48 | }; |
49 | 49 | ||
@@ -52,7 +52,7 @@ struct backing_dev_info mtd_bdi_unmappable = { | |||
52 | * - permits private mappings, copies are taken of the data | 52 | * - permits private mappings, copies are taken of the data |
53 | * - permits non-writable shared mappings | 53 | * - permits non-writable shared mappings |
54 | */ | 54 | */ |
55 | struct backing_dev_info mtd_bdi_ro_mappable = { | 55 | static struct backing_dev_info mtd_bdi_ro_mappable = { |
56 | .capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT | | 56 | .capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT | |
57 | BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP), | 57 | BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP), |
58 | }; | 58 | }; |
@@ -62,7 +62,7 @@ struct backing_dev_info mtd_bdi_ro_mappable = { | |||
62 | * - permits private mappings, copies are taken of the data | 62 | * - permits private mappings, copies are taken of the data |
63 | * - permits non-writable shared mappings | 63 | * - permits non-writable shared mappings |
64 | */ | 64 | */ |
65 | struct backing_dev_info mtd_bdi_rw_mappable = { | 65 | static struct backing_dev_info mtd_bdi_rw_mappable = { |
66 | .capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT | | 66 | .capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT | |
67 | BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP | | 67 | BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP | |
68 | BDI_CAP_WRITE_MAP), | 68 | BDI_CAP_WRITE_MAP), |
diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c new file mode 100644 index 000000000000..237913c5c92c --- /dev/null +++ b/drivers/mtd/mtdswap.c | |||
@@ -0,0 +1,1587 @@ | |||
1 | /* | ||
2 | * Swap block device support for MTDs | ||
3 | * Turns an MTD device into a swap device with block wear leveling | ||
4 | * | ||
5 | * Copyright © 2007,2011 Nokia Corporation. All rights reserved. | ||
6 | * | ||
7 | * Authors: Jarkko Lavinen <jarkko.lavinen@nokia.com> | ||
8 | * | ||
9 | * Based on Richard Purdie's earlier implementation in 2007. Background | ||
10 | * support and lock-less operation written by Adrian Hunter. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * version 2 as published by the Free Software Foundation. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, but | ||
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
24 | * 02110-1301 USA | ||
25 | */ | ||
26 | |||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/mtd/mtd.h> | ||
30 | #include <linux/mtd/blktrans.h> | ||
31 | #include <linux/rbtree.h> | ||
32 | #include <linux/sched.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/vmalloc.h> | ||
35 | #include <linux/genhd.h> | ||
36 | #include <linux/swap.h> | ||
37 | #include <linux/debugfs.h> | ||
38 | #include <linux/seq_file.h> | ||
39 | #include <linux/device.h> | ||
40 | #include <linux/math64.h> | ||
41 | |||
42 | #define MTDSWAP_PREFIX "mtdswap" | ||
43 | |||
44 | /* | ||
45 | * The number of free eraseblocks when GC should stop | ||
46 | */ | ||
47 | #define CLEAN_BLOCK_THRESHOLD 20 | ||
48 | |||
49 | /* | ||
50 | * Number of free eraseblocks below which GC can also collect low frag | ||
51 | * blocks. | ||
52 | */ | ||
53 | #define LOW_FRAG_GC_TRESHOLD 5 | ||
54 | |||
55 | /* | ||
56 | * Wear level cost amortization. We want to do wear leveling on the background | ||
57 | * without disturbing gc too much. This is made by defining max GC frequency. | ||
58 | * Frequency value 6 means 1/6 of the GC passes will pick an erase block based | ||
59 | * on the biggest wear difference rather than the biggest dirtiness. | ||
60 | * | ||
61 | * The lower freq2 should be chosen so that it makes sure the maximum erase | ||
62 | * difference will decrease even if a malicious application is deliberately | ||
63 | * trying to make erase differences large. | ||
64 | */ | ||
65 | #define MAX_ERASE_DIFF 4000 | ||
66 | #define COLLECT_NONDIRTY_BASE MAX_ERASE_DIFF | ||
67 | #define COLLECT_NONDIRTY_FREQ1 6 | ||
68 | #define COLLECT_NONDIRTY_FREQ2 4 | ||
69 | |||
70 | #define PAGE_UNDEF UINT_MAX | ||
71 | #define BLOCK_UNDEF UINT_MAX | ||
72 | #define BLOCK_ERROR (UINT_MAX - 1) | ||
73 | #define BLOCK_MAX (UINT_MAX - 2) | ||
74 | |||
75 | #define EBLOCK_BAD (1 << 0) | ||
76 | #define EBLOCK_NOMAGIC (1 << 1) | ||
77 | #define EBLOCK_BITFLIP (1 << 2) | ||
78 | #define EBLOCK_FAILED (1 << 3) | ||
79 | #define EBLOCK_READERR (1 << 4) | ||
80 | #define EBLOCK_IDX_SHIFT 5 | ||
81 | |||
82 | struct swap_eb { | ||
83 | struct rb_node rb; | ||
84 | struct rb_root *root; | ||
85 | |||
86 | unsigned int flags; | ||
87 | unsigned int active_count; | ||
88 | unsigned int erase_count; | ||
89 | unsigned int pad; /* speeds up pointer decremtnt */ | ||
90 | }; | ||
91 | |||
92 | #define MTDSWAP_ECNT_MIN(rbroot) (rb_entry(rb_first(rbroot), struct swap_eb, \ | ||
93 | rb)->erase_count) | ||
94 | #define MTDSWAP_ECNT_MAX(rbroot) (rb_entry(rb_last(rbroot), struct swap_eb, \ | ||
95 | rb)->erase_count) | ||
96 | |||
97 | struct mtdswap_tree { | ||
98 | struct rb_root root; | ||
99 | unsigned int count; | ||
100 | }; | ||
101 | |||
102 | enum { | ||
103 | MTDSWAP_CLEAN, | ||
104 | MTDSWAP_USED, | ||
105 | MTDSWAP_LOWFRAG, | ||
106 | MTDSWAP_HIFRAG, | ||
107 | MTDSWAP_DIRTY, | ||
108 | MTDSWAP_BITFLIP, | ||
109 | MTDSWAP_FAILING, | ||
110 | MTDSWAP_TREE_CNT, | ||
111 | }; | ||
112 | |||
113 | struct mtdswap_dev { | ||
114 | struct mtd_blktrans_dev *mbd_dev; | ||
115 | struct mtd_info *mtd; | ||
116 | struct device *dev; | ||
117 | |||
118 | unsigned int *page_data; | ||
119 | unsigned int *revmap; | ||
120 | |||
121 | unsigned int eblks; | ||
122 | unsigned int spare_eblks; | ||
123 | unsigned int pages_per_eblk; | ||
124 | unsigned int max_erase_count; | ||
125 | struct swap_eb *eb_data; | ||
126 | |||
127 | struct mtdswap_tree trees[MTDSWAP_TREE_CNT]; | ||
128 | |||
129 | unsigned long long sect_read_count; | ||
130 | unsigned long long sect_write_count; | ||
131 | unsigned long long mtd_write_count; | ||
132 | unsigned long long mtd_read_count; | ||
133 | unsigned long long discard_count; | ||
134 | unsigned long long discard_page_count; | ||
135 | |||
136 | unsigned int curr_write_pos; | ||
137 | struct swap_eb *curr_write; | ||
138 | |||
139 | char *page_buf; | ||
140 | char *oob_buf; | ||
141 | |||
142 | struct dentry *debugfs_root; | ||
143 | }; | ||
144 | |||
145 | struct mtdswap_oobdata { | ||
146 | __le16 magic; | ||
147 | __le32 count; | ||
148 | } __attribute__((packed)); | ||
149 | |||
150 | #define MTDSWAP_MAGIC_CLEAN 0x2095 | ||
151 | #define MTDSWAP_MAGIC_DIRTY (MTDSWAP_MAGIC_CLEAN + 1) | ||
152 | #define MTDSWAP_TYPE_CLEAN 0 | ||
153 | #define MTDSWAP_TYPE_DIRTY 1 | ||
154 | #define MTDSWAP_OOBSIZE sizeof(struct mtdswap_oobdata) | ||
155 | |||
156 | #define MTDSWAP_ERASE_RETRIES 3 /* Before marking erase block bad */ | ||
157 | #define MTDSWAP_IO_RETRIES 3 | ||
158 | |||
159 | enum { | ||
160 | MTDSWAP_SCANNED_CLEAN, | ||
161 | MTDSWAP_SCANNED_DIRTY, | ||
162 | MTDSWAP_SCANNED_BITFLIP, | ||
163 | MTDSWAP_SCANNED_BAD, | ||
164 | }; | ||
165 | |||
166 | /* | ||
167 | * In the worst case mtdswap_writesect() has allocated the last clean | ||
168 | * page from the current block and is then pre-empted by the GC | ||
169 | * thread. The thread can consume a full erase block when moving a | ||
170 | * block. | ||
171 | */ | ||
172 | #define MIN_SPARE_EBLOCKS 2 | ||
173 | #define MIN_ERASE_BLOCKS (MIN_SPARE_EBLOCKS + 1) | ||
174 | |||
175 | #define TREE_ROOT(d, name) (&d->trees[MTDSWAP_ ## name].root) | ||
176 | #define TREE_EMPTY(d, name) (TREE_ROOT(d, name)->rb_node == NULL) | ||
177 | #define TREE_NONEMPTY(d, name) (!TREE_EMPTY(d, name)) | ||
178 | #define TREE_COUNT(d, name) (d->trees[MTDSWAP_ ## name].count) | ||
179 | |||
180 | #define MTDSWAP_MBD_TO_MTDSWAP(dev) ((struct mtdswap_dev *)dev->priv) | ||
181 | |||
182 | static char partitions[128] = ""; | ||
183 | module_param_string(partitions, partitions, sizeof(partitions), 0444); | ||
184 | MODULE_PARM_DESC(partitions, "MTD partition numbers to use as swap " | ||
185 | "partitions=\"1,3,5\""); | ||
186 | |||
187 | static unsigned int spare_eblocks = 10; | ||
188 | module_param(spare_eblocks, uint, 0444); | ||
189 | MODULE_PARM_DESC(spare_eblocks, "Percentage of spare erase blocks for " | ||
190 | "garbage collection (default 10%)"); | ||
191 | |||
192 | static bool header; /* false */ | ||
193 | module_param(header, bool, 0444); | ||
194 | MODULE_PARM_DESC(header, | ||
195 | "Include builtin swap header (default 0, without header)"); | ||
196 | |||
197 | static int mtdswap_gc(struct mtdswap_dev *d, unsigned int background); | ||
198 | |||
199 | static loff_t mtdswap_eb_offset(struct mtdswap_dev *d, struct swap_eb *eb) | ||
200 | { | ||
201 | return (loff_t)(eb - d->eb_data) * d->mtd->erasesize; | ||
202 | } | ||
203 | |||
204 | static void mtdswap_eb_detach(struct mtdswap_dev *d, struct swap_eb *eb) | ||
205 | { | ||
206 | unsigned int oldidx; | ||
207 | struct mtdswap_tree *tp; | ||
208 | |||
209 | if (eb->root) { | ||
210 | tp = container_of(eb->root, struct mtdswap_tree, root); | ||
211 | oldidx = tp - &d->trees[0]; | ||
212 | |||
213 | d->trees[oldidx].count--; | ||
214 | rb_erase(&eb->rb, eb->root); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | static void __mtdswap_rb_add(struct rb_root *root, struct swap_eb *eb) | ||
219 | { | ||
220 | struct rb_node **p, *parent = NULL; | ||
221 | struct swap_eb *cur; | ||
222 | |||
223 | p = &root->rb_node; | ||
224 | while (*p) { | ||
225 | parent = *p; | ||
226 | cur = rb_entry(parent, struct swap_eb, rb); | ||
227 | if (eb->erase_count > cur->erase_count) | ||
228 | p = &(*p)->rb_right; | ||
229 | else | ||
230 | p = &(*p)->rb_left; | ||
231 | } | ||
232 | |||
233 | rb_link_node(&eb->rb, parent, p); | ||
234 | rb_insert_color(&eb->rb, root); | ||
235 | } | ||
236 | |||
237 | static void mtdswap_rb_add(struct mtdswap_dev *d, struct swap_eb *eb, int idx) | ||
238 | { | ||
239 | struct rb_root *root; | ||
240 | |||
241 | if (eb->root == &d->trees[idx].root) | ||
242 | return; | ||
243 | |||
244 | mtdswap_eb_detach(d, eb); | ||
245 | root = &d->trees[idx].root; | ||
246 | __mtdswap_rb_add(root, eb); | ||
247 | eb->root = root; | ||
248 | d->trees[idx].count++; | ||
249 | } | ||
250 | |||
251 | static struct rb_node *mtdswap_rb_index(struct rb_root *root, unsigned int idx) | ||
252 | { | ||
253 | struct rb_node *p; | ||
254 | unsigned int i; | ||
255 | |||
256 | p = rb_first(root); | ||
257 | i = 0; | ||
258 | while (i < idx && p) { | ||
259 | p = rb_next(p); | ||
260 | i++; | ||
261 | } | ||
262 | |||
263 | return p; | ||
264 | } | ||
265 | |||
266 | static int mtdswap_handle_badblock(struct mtdswap_dev *d, struct swap_eb *eb) | ||
267 | { | ||
268 | int ret; | ||
269 | loff_t offset; | ||
270 | |||
271 | d->spare_eblks--; | ||
272 | eb->flags |= EBLOCK_BAD; | ||
273 | mtdswap_eb_detach(d, eb); | ||
274 | eb->root = NULL; | ||
275 | |||
276 | /* badblocks not supported */ | ||
277 | if (!d->mtd->block_markbad) | ||
278 | return 1; | ||
279 | |||
280 | offset = mtdswap_eb_offset(d, eb); | ||
281 | dev_warn(d->dev, "Marking bad block at %08llx\n", offset); | ||
282 | ret = d->mtd->block_markbad(d->mtd, offset); | ||
283 | |||
284 | if (ret) { | ||
285 | dev_warn(d->dev, "Mark block bad failed for block at %08llx " | ||
286 | "error %d\n", offset, ret); | ||
287 | return ret; | ||
288 | } | ||
289 | |||
290 | return 1; | ||
291 | |||
292 | } | ||
293 | |||
294 | static int mtdswap_handle_write_error(struct mtdswap_dev *d, struct swap_eb *eb) | ||
295 | { | ||
296 | unsigned int marked = eb->flags & EBLOCK_FAILED; | ||
297 | struct swap_eb *curr_write = d->curr_write; | ||
298 | |||
299 | eb->flags |= EBLOCK_FAILED; | ||
300 | if (curr_write == eb) { | ||
301 | d->curr_write = NULL; | ||
302 | |||
303 | if (!marked && d->curr_write_pos != 0) { | ||
304 | mtdswap_rb_add(d, eb, MTDSWAP_FAILING); | ||
305 | return 0; | ||
306 | } | ||
307 | } | ||
308 | |||
309 | return mtdswap_handle_badblock(d, eb); | ||
310 | } | ||
311 | |||
312 | static int mtdswap_read_oob(struct mtdswap_dev *d, loff_t from, | ||
313 | struct mtd_oob_ops *ops) | ||
314 | { | ||
315 | int ret = d->mtd->read_oob(d->mtd, from, ops); | ||
316 | |||
317 | if (ret == -EUCLEAN) | ||
318 | return ret; | ||
319 | |||
320 | if (ret) { | ||
321 | dev_warn(d->dev, "Read OOB failed %d for block at %08llx\n", | ||
322 | ret, from); | ||
323 | return ret; | ||
324 | } | ||
325 | |||
326 | if (ops->oobretlen < ops->ooblen) { | ||
327 | dev_warn(d->dev, "Read OOB return short read (%zd bytes not " | ||
328 | "%zd) for block at %08llx\n", | ||
329 | ops->oobretlen, ops->ooblen, from); | ||
330 | return -EIO; | ||
331 | } | ||
332 | |||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb) | ||
337 | { | ||
338 | struct mtdswap_oobdata *data, *data2; | ||
339 | int ret; | ||
340 | loff_t offset; | ||
341 | struct mtd_oob_ops ops; | ||
342 | |||
343 | offset = mtdswap_eb_offset(d, eb); | ||
344 | |||
345 | /* Check first if the block is bad. */ | ||
346 | if (d->mtd->block_isbad && d->mtd->block_isbad(d->mtd, offset)) | ||
347 | return MTDSWAP_SCANNED_BAD; | ||
348 | |||
349 | ops.ooblen = 2 * d->mtd->ecclayout->oobavail; | ||
350 | ops.oobbuf = d->oob_buf; | ||
351 | ops.ooboffs = 0; | ||
352 | ops.datbuf = NULL; | ||
353 | ops.mode = MTD_OOB_AUTO; | ||
354 | |||
355 | ret = mtdswap_read_oob(d, offset, &ops); | ||
356 | |||
357 | if (ret && ret != -EUCLEAN) | ||
358 | return ret; | ||
359 | |||
360 | data = (struct mtdswap_oobdata *)d->oob_buf; | ||
361 | data2 = (struct mtdswap_oobdata *) | ||
362 | (d->oob_buf + d->mtd->ecclayout->oobavail); | ||
363 | |||
364 | if (le16_to_cpu(data->magic) == MTDSWAP_MAGIC_CLEAN) { | ||
365 | eb->erase_count = le32_to_cpu(data->count); | ||
366 | if (ret == -EUCLEAN) | ||
367 | ret = MTDSWAP_SCANNED_BITFLIP; | ||
368 | else { | ||
369 | if (le16_to_cpu(data2->magic) == MTDSWAP_MAGIC_DIRTY) | ||
370 | ret = MTDSWAP_SCANNED_DIRTY; | ||
371 | else | ||
372 | ret = MTDSWAP_SCANNED_CLEAN; | ||
373 | } | ||
374 | } else { | ||
375 | eb->flags |= EBLOCK_NOMAGIC; | ||
376 | ret = MTDSWAP_SCANNED_DIRTY; | ||
377 | } | ||
378 | |||
379 | return ret; | ||
380 | } | ||
381 | |||
382 | static int mtdswap_write_marker(struct mtdswap_dev *d, struct swap_eb *eb, | ||
383 | u16 marker) | ||
384 | { | ||
385 | struct mtdswap_oobdata n; | ||
386 | int ret; | ||
387 | loff_t offset; | ||
388 | struct mtd_oob_ops ops; | ||
389 | |||
390 | ops.ooboffs = 0; | ||
391 | ops.oobbuf = (uint8_t *)&n; | ||
392 | ops.mode = MTD_OOB_AUTO; | ||
393 | ops.datbuf = NULL; | ||
394 | |||
395 | if (marker == MTDSWAP_TYPE_CLEAN) { | ||
396 | n.magic = cpu_to_le16(MTDSWAP_MAGIC_CLEAN); | ||
397 | n.count = cpu_to_le32(eb->erase_count); | ||
398 | ops.ooblen = MTDSWAP_OOBSIZE; | ||
399 | offset = mtdswap_eb_offset(d, eb); | ||
400 | } else { | ||
401 | n.magic = cpu_to_le16(MTDSWAP_MAGIC_DIRTY); | ||
402 | ops.ooblen = sizeof(n.magic); | ||
403 | offset = mtdswap_eb_offset(d, eb) + d->mtd->writesize; | ||
404 | } | ||
405 | |||
406 | ret = d->mtd->write_oob(d->mtd, offset , &ops); | ||
407 | |||
408 | if (ret) { | ||
409 | dev_warn(d->dev, "Write OOB failed for block at %08llx " | ||
410 | "error %d\n", offset, ret); | ||
411 | if (ret == -EIO || ret == -EBADMSG) | ||
412 | mtdswap_handle_write_error(d, eb); | ||
413 | return ret; | ||
414 | } | ||
415 | |||
416 | if (ops.oobretlen != ops.ooblen) { | ||
417 | dev_warn(d->dev, "Short OOB write for block at %08llx: " | ||
418 | "%zd not %zd\n", | ||
419 | offset, ops.oobretlen, ops.ooblen); | ||
420 | return ret; | ||
421 | } | ||
422 | |||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | /* | ||
427 | * Are there any erase blocks without MAGIC_CLEAN header, presumably | ||
428 | * because power was cut off after erase but before header write? We | ||
429 | * need to guestimate the erase count. | ||
430 | */ | ||
431 | static void mtdswap_check_counts(struct mtdswap_dev *d) | ||
432 | { | ||
433 | struct rb_root hist_root = RB_ROOT; | ||
434 | struct rb_node *medrb; | ||
435 | struct swap_eb *eb; | ||
436 | unsigned int i, cnt, median; | ||
437 | |||
438 | cnt = 0; | ||
439 | for (i = 0; i < d->eblks; i++) { | ||
440 | eb = d->eb_data + i; | ||
441 | |||
442 | if (eb->flags & (EBLOCK_NOMAGIC | EBLOCK_BAD | EBLOCK_READERR)) | ||
443 | continue; | ||
444 | |||
445 | __mtdswap_rb_add(&hist_root, eb); | ||
446 | cnt++; | ||
447 | } | ||
448 | |||
449 | if (cnt == 0) | ||
450 | return; | ||
451 | |||
452 | medrb = mtdswap_rb_index(&hist_root, cnt / 2); | ||
453 | median = rb_entry(medrb, struct swap_eb, rb)->erase_count; | ||
454 | |||
455 | d->max_erase_count = MTDSWAP_ECNT_MAX(&hist_root); | ||
456 | |||
457 | for (i = 0; i < d->eblks; i++) { | ||
458 | eb = d->eb_data + i; | ||
459 | |||
460 | if (eb->flags & (EBLOCK_NOMAGIC | EBLOCK_READERR)) | ||
461 | eb->erase_count = median; | ||
462 | |||
463 | if (eb->flags & (EBLOCK_NOMAGIC | EBLOCK_BAD | EBLOCK_READERR)) | ||
464 | continue; | ||
465 | |||
466 | rb_erase(&eb->rb, &hist_root); | ||
467 | } | ||
468 | } | ||
469 | |||
470 | static void mtdswap_scan_eblks(struct mtdswap_dev *d) | ||
471 | { | ||
472 | int status; | ||
473 | unsigned int i, idx; | ||
474 | struct swap_eb *eb; | ||
475 | |||
476 | for (i = 0; i < d->eblks; i++) { | ||
477 | eb = d->eb_data + i; | ||
478 | |||
479 | status = mtdswap_read_markers(d, eb); | ||
480 | if (status < 0) | ||
481 | eb->flags |= EBLOCK_READERR; | ||
482 | else if (status == MTDSWAP_SCANNED_BAD) { | ||
483 | eb->flags |= EBLOCK_BAD; | ||
484 | continue; | ||
485 | } | ||
486 | |||
487 | switch (status) { | ||
488 | case MTDSWAP_SCANNED_CLEAN: | ||
489 | idx = MTDSWAP_CLEAN; | ||
490 | break; | ||
491 | case MTDSWAP_SCANNED_DIRTY: | ||
492 | case MTDSWAP_SCANNED_BITFLIP: | ||
493 | idx = MTDSWAP_DIRTY; | ||
494 | break; | ||
495 | default: | ||
496 | idx = MTDSWAP_FAILING; | ||
497 | } | ||
498 | |||
499 | eb->flags |= (idx << EBLOCK_IDX_SHIFT); | ||
500 | } | ||
501 | |||
502 | mtdswap_check_counts(d); | ||
503 | |||
504 | for (i = 0; i < d->eblks; i++) { | ||
505 | eb = d->eb_data + i; | ||
506 | |||
507 | if (eb->flags & EBLOCK_BAD) | ||
508 | continue; | ||
509 | |||
510 | idx = eb->flags >> EBLOCK_IDX_SHIFT; | ||
511 | mtdswap_rb_add(d, eb, idx); | ||
512 | } | ||
513 | } | ||
514 | |||
515 | /* | ||
516 | * Place eblk into a tree corresponding to its number of active blocks | ||
517 | * it contains. | ||
518 | */ | ||
519 | static void mtdswap_store_eb(struct mtdswap_dev *d, struct swap_eb *eb) | ||
520 | { | ||
521 | unsigned int weight = eb->active_count; | ||
522 | unsigned int maxweight = d->pages_per_eblk; | ||
523 | |||
524 | if (eb == d->curr_write) | ||
525 | return; | ||
526 | |||
527 | if (eb->flags & EBLOCK_BITFLIP) | ||
528 | mtdswap_rb_add(d, eb, MTDSWAP_BITFLIP); | ||
529 | else if (eb->flags & (EBLOCK_READERR | EBLOCK_FAILED)) | ||
530 | mtdswap_rb_add(d, eb, MTDSWAP_FAILING); | ||
531 | if (weight == maxweight) | ||
532 | mtdswap_rb_add(d, eb, MTDSWAP_USED); | ||
533 | else if (weight == 0) | ||
534 | mtdswap_rb_add(d, eb, MTDSWAP_DIRTY); | ||
535 | else if (weight > (maxweight/2)) | ||
536 | mtdswap_rb_add(d, eb, MTDSWAP_LOWFRAG); | ||
537 | else | ||
538 | mtdswap_rb_add(d, eb, MTDSWAP_HIFRAG); | ||
539 | } | ||
540 | |||
541 | |||
542 | static void mtdswap_erase_callback(struct erase_info *done) | ||
543 | { | ||
544 | wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; | ||
545 | wake_up(wait_q); | ||
546 | } | ||
547 | |||
548 | static int mtdswap_erase_block(struct mtdswap_dev *d, struct swap_eb *eb) | ||
549 | { | ||
550 | struct mtd_info *mtd = d->mtd; | ||
551 | struct erase_info erase; | ||
552 | wait_queue_head_t wq; | ||
553 | unsigned int retries = 0; | ||
554 | int ret; | ||
555 | |||
556 | eb->erase_count++; | ||
557 | if (eb->erase_count > d->max_erase_count) | ||
558 | d->max_erase_count = eb->erase_count; | ||
559 | |||
560 | retry: | ||
561 | init_waitqueue_head(&wq); | ||
562 | memset(&erase, 0, sizeof(struct erase_info)); | ||
563 | |||
564 | erase.mtd = mtd; | ||
565 | erase.callback = mtdswap_erase_callback; | ||
566 | erase.addr = mtdswap_eb_offset(d, eb); | ||
567 | erase.len = mtd->erasesize; | ||
568 | erase.priv = (u_long)&wq; | ||
569 | |||
570 | ret = mtd->erase(mtd, &erase); | ||
571 | if (ret) { | ||
572 | if (retries++ < MTDSWAP_ERASE_RETRIES) { | ||
573 | dev_warn(d->dev, | ||
574 | "erase of erase block %#llx on %s failed", | ||
575 | erase.addr, mtd->name); | ||
576 | yield(); | ||
577 | goto retry; | ||
578 | } | ||
579 | |||
580 | dev_err(d->dev, "Cannot erase erase block %#llx on %s\n", | ||
581 | erase.addr, mtd->name); | ||
582 | |||
583 | mtdswap_handle_badblock(d, eb); | ||
584 | return -EIO; | ||
585 | } | ||
586 | |||
587 | ret = wait_event_interruptible(wq, erase.state == MTD_ERASE_DONE || | ||
588 | erase.state == MTD_ERASE_FAILED); | ||
589 | if (ret) { | ||
590 | dev_err(d->dev, "Interrupted erase block %#llx erassure on %s", | ||
591 | erase.addr, mtd->name); | ||
592 | return -EINTR; | ||
593 | } | ||
594 | |||
595 | if (erase.state == MTD_ERASE_FAILED) { | ||
596 | if (retries++ < MTDSWAP_ERASE_RETRIES) { | ||
597 | dev_warn(d->dev, | ||
598 | "erase of erase block %#llx on %s failed", | ||
599 | erase.addr, mtd->name); | ||
600 | yield(); | ||
601 | goto retry; | ||
602 | } | ||
603 | |||
604 | mtdswap_handle_badblock(d, eb); | ||
605 | return -EIO; | ||
606 | } | ||
607 | |||
608 | return 0; | ||
609 | } | ||
610 | |||
611 | static int mtdswap_map_free_block(struct mtdswap_dev *d, unsigned int page, | ||
612 | unsigned int *block) | ||
613 | { | ||
614 | int ret; | ||
615 | struct swap_eb *old_eb = d->curr_write; | ||
616 | struct rb_root *clean_root; | ||
617 | struct swap_eb *eb; | ||
618 | |||
619 | if (old_eb == NULL || d->curr_write_pos >= d->pages_per_eblk) { | ||
620 | do { | ||
621 | if (TREE_EMPTY(d, CLEAN)) | ||
622 | return -ENOSPC; | ||
623 | |||
624 | clean_root = TREE_ROOT(d, CLEAN); | ||
625 | eb = rb_entry(rb_first(clean_root), struct swap_eb, rb); | ||
626 | rb_erase(&eb->rb, clean_root); | ||
627 | eb->root = NULL; | ||
628 | TREE_COUNT(d, CLEAN)--; | ||
629 | |||
630 | ret = mtdswap_write_marker(d, eb, MTDSWAP_TYPE_DIRTY); | ||
631 | } while (ret == -EIO || ret == -EBADMSG); | ||
632 | |||
633 | if (ret) | ||
634 | return ret; | ||
635 | |||
636 | d->curr_write_pos = 0; | ||
637 | d->curr_write = eb; | ||
638 | if (old_eb) | ||
639 | mtdswap_store_eb(d, old_eb); | ||
640 | } | ||
641 | |||
642 | *block = (d->curr_write - d->eb_data) * d->pages_per_eblk + | ||
643 | d->curr_write_pos; | ||
644 | |||
645 | d->curr_write->active_count++; | ||
646 | d->revmap[*block] = page; | ||
647 | d->curr_write_pos++; | ||
648 | |||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | static unsigned int mtdswap_free_page_cnt(struct mtdswap_dev *d) | ||
653 | { | ||
654 | return TREE_COUNT(d, CLEAN) * d->pages_per_eblk + | ||
655 | d->pages_per_eblk - d->curr_write_pos; | ||
656 | } | ||
657 | |||
658 | static unsigned int mtdswap_enough_free_pages(struct mtdswap_dev *d) | ||
659 | { | ||
660 | return mtdswap_free_page_cnt(d) > d->pages_per_eblk; | ||
661 | } | ||
662 | |||
663 | static int mtdswap_write_block(struct mtdswap_dev *d, char *buf, | ||
664 | unsigned int page, unsigned int *bp, int gc_context) | ||
665 | { | ||
666 | struct mtd_info *mtd = d->mtd; | ||
667 | struct swap_eb *eb; | ||
668 | size_t retlen; | ||
669 | loff_t writepos; | ||
670 | int ret; | ||
671 | |||
672 | retry: | ||
673 | if (!gc_context) | ||
674 | while (!mtdswap_enough_free_pages(d)) | ||
675 | if (mtdswap_gc(d, 0) > 0) | ||
676 | return -ENOSPC; | ||
677 | |||
678 | ret = mtdswap_map_free_block(d, page, bp); | ||
679 | eb = d->eb_data + (*bp / d->pages_per_eblk); | ||
680 | |||
681 | if (ret == -EIO || ret == -EBADMSG) { | ||
682 | d->curr_write = NULL; | ||
683 | eb->active_count--; | ||
684 | d->revmap[*bp] = PAGE_UNDEF; | ||
685 | goto retry; | ||
686 | } | ||
687 | |||
688 | if (ret < 0) | ||
689 | return ret; | ||
690 | |||
691 | writepos = (loff_t)*bp << PAGE_SHIFT; | ||
692 | ret = mtd->write(mtd, writepos, PAGE_SIZE, &retlen, buf); | ||
693 | if (ret == -EIO || ret == -EBADMSG) { | ||
694 | d->curr_write_pos--; | ||
695 | eb->active_count--; | ||
696 | d->revmap[*bp] = PAGE_UNDEF; | ||
697 | mtdswap_handle_write_error(d, eb); | ||
698 | goto retry; | ||
699 | } | ||
700 | |||
701 | if (ret < 0) { | ||
702 | dev_err(d->dev, "Write to MTD device failed: %d (%zd written)", | ||
703 | ret, retlen); | ||
704 | goto err; | ||
705 | } | ||
706 | |||
707 | if (retlen != PAGE_SIZE) { | ||
708 | dev_err(d->dev, "Short write to MTD device: %zd written", | ||
709 | retlen); | ||
710 | ret = -EIO; | ||
711 | goto err; | ||
712 | } | ||
713 | |||
714 | return ret; | ||
715 | |||
716 | err: | ||
717 | d->curr_write_pos--; | ||
718 | eb->active_count--; | ||
719 | d->revmap[*bp] = PAGE_UNDEF; | ||
720 | |||
721 | return ret; | ||
722 | } | ||
723 | |||
724 | static int mtdswap_move_block(struct mtdswap_dev *d, unsigned int oldblock, | ||
725 | unsigned int *newblock) | ||
726 | { | ||
727 | struct mtd_info *mtd = d->mtd; | ||
728 | struct swap_eb *eb, *oldeb; | ||
729 | int ret; | ||
730 | size_t retlen; | ||
731 | unsigned int page, retries; | ||
732 | loff_t readpos; | ||
733 | |||
734 | page = d->revmap[oldblock]; | ||
735 | readpos = (loff_t) oldblock << PAGE_SHIFT; | ||
736 | retries = 0; | ||
737 | |||
738 | retry: | ||
739 | ret = mtd->read(mtd, readpos, PAGE_SIZE, &retlen, d->page_buf); | ||
740 | |||
741 | if (ret < 0 && ret != -EUCLEAN) { | ||
742 | oldeb = d->eb_data + oldblock / d->pages_per_eblk; | ||
743 | oldeb->flags |= EBLOCK_READERR; | ||
744 | |||
745 | dev_err(d->dev, "Read Error: %d (block %u)\n", ret, | ||
746 | oldblock); | ||
747 | retries++; | ||
748 | if (retries < MTDSWAP_IO_RETRIES) | ||
749 | goto retry; | ||
750 | |||
751 | goto read_error; | ||
752 | } | ||
753 | |||
754 | if (retlen != PAGE_SIZE) { | ||
755 | dev_err(d->dev, "Short read: %zd (block %u)\n", retlen, | ||
756 | oldblock); | ||
757 | ret = -EIO; | ||
758 | goto read_error; | ||
759 | } | ||
760 | |||
761 | ret = mtdswap_write_block(d, d->page_buf, page, newblock, 1); | ||
762 | if (ret < 0) { | ||
763 | d->page_data[page] = BLOCK_ERROR; | ||
764 | dev_err(d->dev, "Write error: %d\n", ret); | ||
765 | return ret; | ||
766 | } | ||
767 | |||
768 | eb = d->eb_data + *newblock / d->pages_per_eblk; | ||
769 | d->page_data[page] = *newblock; | ||
770 | d->revmap[oldblock] = PAGE_UNDEF; | ||
771 | eb = d->eb_data + oldblock / d->pages_per_eblk; | ||
772 | eb->active_count--; | ||
773 | |||
774 | return 0; | ||
775 | |||
776 | read_error: | ||
777 | d->page_data[page] = BLOCK_ERROR; | ||
778 | d->revmap[oldblock] = PAGE_UNDEF; | ||
779 | return ret; | ||
780 | } | ||
781 | |||
782 | static int mtdswap_gc_eblock(struct mtdswap_dev *d, struct swap_eb *eb) | ||
783 | { | ||
784 | unsigned int i, block, eblk_base, newblock; | ||
785 | int ret, errcode; | ||
786 | |||
787 | errcode = 0; | ||
788 | eblk_base = (eb - d->eb_data) * d->pages_per_eblk; | ||
789 | |||
790 | for (i = 0; i < d->pages_per_eblk; i++) { | ||
791 | if (d->spare_eblks < MIN_SPARE_EBLOCKS) | ||
792 | return -ENOSPC; | ||
793 | |||
794 | block = eblk_base + i; | ||
795 | if (d->revmap[block] == PAGE_UNDEF) | ||
796 | continue; | ||
797 | |||
798 | ret = mtdswap_move_block(d, block, &newblock); | ||
799 | if (ret < 0 && !errcode) | ||
800 | errcode = ret; | ||
801 | } | ||
802 | |||
803 | return errcode; | ||
804 | } | ||
805 | |||
806 | static int __mtdswap_choose_gc_tree(struct mtdswap_dev *d) | ||
807 | { | ||
808 | int idx, stopat; | ||
809 | |||
810 | if (TREE_COUNT(d, CLEAN) < LOW_FRAG_GC_TRESHOLD) | ||
811 | stopat = MTDSWAP_LOWFRAG; | ||
812 | else | ||
813 | stopat = MTDSWAP_HIFRAG; | ||
814 | |||
815 | for (idx = MTDSWAP_BITFLIP; idx >= stopat; idx--) | ||
816 | if (d->trees[idx].root.rb_node != NULL) | ||
817 | return idx; | ||
818 | |||
819 | return -1; | ||
820 | } | ||
821 | |||
822 | static int mtdswap_wlfreq(unsigned int maxdiff) | ||
823 | { | ||
824 | unsigned int h, x, y, dist, base; | ||
825 | |||
826 | /* | ||
827 | * Calculate linear ramp down from f1 to f2 when maxdiff goes from | ||
828 | * MAX_ERASE_DIFF to MAX_ERASE_DIFF + COLLECT_NONDIRTY_BASE. Similar | ||
829 | * to triangle with height f1 - f1 and width COLLECT_NONDIRTY_BASE. | ||
830 | */ | ||
831 | |||
832 | dist = maxdiff - MAX_ERASE_DIFF; | ||
833 | if (dist > COLLECT_NONDIRTY_BASE) | ||
834 | dist = COLLECT_NONDIRTY_BASE; | ||
835 | |||
836 | /* | ||
837 | * Modelling the slop as right angular triangle with base | ||
838 | * COLLECT_NONDIRTY_BASE and height freq1 - freq2. The ratio y/x is | ||
839 | * equal to the ratio h/base. | ||
840 | */ | ||
841 | h = COLLECT_NONDIRTY_FREQ1 - COLLECT_NONDIRTY_FREQ2; | ||
842 | base = COLLECT_NONDIRTY_BASE; | ||
843 | |||
844 | x = dist - base; | ||
845 | y = (x * h + base / 2) / base; | ||
846 | |||
847 | return COLLECT_NONDIRTY_FREQ2 + y; | ||
848 | } | ||
849 | |||
850 | static int mtdswap_choose_wl_tree(struct mtdswap_dev *d) | ||
851 | { | ||
852 | static unsigned int pick_cnt; | ||
853 | unsigned int i, idx = -1, wear, max; | ||
854 | struct rb_root *root; | ||
855 | |||
856 | max = 0; | ||
857 | for (i = 0; i <= MTDSWAP_DIRTY; i++) { | ||
858 | root = &d->trees[i].root; | ||
859 | if (root->rb_node == NULL) | ||
860 | continue; | ||
861 | |||
862 | wear = d->max_erase_count - MTDSWAP_ECNT_MIN(root); | ||
863 | if (wear > max) { | ||
864 | max = wear; | ||
865 | idx = i; | ||
866 | } | ||
867 | } | ||
868 | |||
869 | if (max > MAX_ERASE_DIFF && pick_cnt >= mtdswap_wlfreq(max) - 1) { | ||
870 | pick_cnt = 0; | ||
871 | return idx; | ||
872 | } | ||
873 | |||
874 | pick_cnt++; | ||
875 | return -1; | ||
876 | } | ||
877 | |||
878 | static int mtdswap_choose_gc_tree(struct mtdswap_dev *d, | ||
879 | unsigned int background) | ||
880 | { | ||
881 | int idx; | ||
882 | |||
883 | if (TREE_NONEMPTY(d, FAILING) && | ||
884 | (background || (TREE_EMPTY(d, CLEAN) && TREE_EMPTY(d, DIRTY)))) | ||
885 | return MTDSWAP_FAILING; | ||
886 | |||
887 | idx = mtdswap_choose_wl_tree(d); | ||
888 | if (idx >= MTDSWAP_CLEAN) | ||
889 | return idx; | ||
890 | |||
891 | return __mtdswap_choose_gc_tree(d); | ||
892 | } | ||
893 | |||
894 | static struct swap_eb *mtdswap_pick_gc_eblk(struct mtdswap_dev *d, | ||
895 | unsigned int background) | ||
896 | { | ||
897 | struct rb_root *rp = NULL; | ||
898 | struct swap_eb *eb = NULL; | ||
899 | int idx; | ||
900 | |||
901 | if (background && TREE_COUNT(d, CLEAN) > CLEAN_BLOCK_THRESHOLD && | ||
902 | TREE_EMPTY(d, DIRTY) && TREE_EMPTY(d, FAILING)) | ||
903 | return NULL; | ||
904 | |||
905 | idx = mtdswap_choose_gc_tree(d, background); | ||
906 | if (idx < 0) | ||
907 | return NULL; | ||
908 | |||
909 | rp = &d->trees[idx].root; | ||
910 | eb = rb_entry(rb_first(rp), struct swap_eb, rb); | ||
911 | |||
912 | rb_erase(&eb->rb, rp); | ||
913 | eb->root = NULL; | ||
914 | d->trees[idx].count--; | ||
915 | return eb; | ||
916 | } | ||
917 | |||
918 | static unsigned int mtdswap_test_patt(unsigned int i) | ||
919 | { | ||
920 | return i % 2 ? 0x55555555 : 0xAAAAAAAA; | ||
921 | } | ||
922 | |||
923 | static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d, | ||
924 | struct swap_eb *eb) | ||
925 | { | ||
926 | struct mtd_info *mtd = d->mtd; | ||
927 | unsigned int test, i, j, patt, mtd_pages; | ||
928 | loff_t base, pos; | ||
929 | unsigned int *p1 = (unsigned int *)d->page_buf; | ||
930 | unsigned char *p2 = (unsigned char *)d->oob_buf; | ||
931 | struct mtd_oob_ops ops; | ||
932 | int ret; | ||
933 | |||
934 | ops.mode = MTD_OOB_AUTO; | ||
935 | ops.len = mtd->writesize; | ||
936 | ops.ooblen = mtd->ecclayout->oobavail; | ||
937 | ops.ooboffs = 0; | ||
938 | ops.datbuf = d->page_buf; | ||
939 | ops.oobbuf = d->oob_buf; | ||
940 | base = mtdswap_eb_offset(d, eb); | ||
941 | mtd_pages = d->pages_per_eblk * PAGE_SIZE / mtd->writesize; | ||
942 | |||
943 | for (test = 0; test < 2; test++) { | ||
944 | pos = base; | ||
945 | for (i = 0; i < mtd_pages; i++) { | ||
946 | patt = mtdswap_test_patt(test + i); | ||
947 | memset(d->page_buf, patt, mtd->writesize); | ||
948 | memset(d->oob_buf, patt, mtd->ecclayout->oobavail); | ||
949 | ret = mtd->write_oob(mtd, pos, &ops); | ||
950 | if (ret) | ||
951 | goto error; | ||
952 | |||
953 | pos += mtd->writesize; | ||
954 | } | ||
955 | |||
956 | pos = base; | ||
957 | for (i = 0; i < mtd_pages; i++) { | ||
958 | ret = mtd->read_oob(mtd, pos, &ops); | ||
959 | if (ret) | ||
960 | goto error; | ||
961 | |||
962 | patt = mtdswap_test_patt(test + i); | ||
963 | for (j = 0; j < mtd->writesize/sizeof(int); j++) | ||
964 | if (p1[j] != patt) | ||
965 | goto error; | ||
966 | |||
967 | for (j = 0; j < mtd->ecclayout->oobavail; j++) | ||
968 | if (p2[j] != (unsigned char)patt) | ||
969 | goto error; | ||
970 | |||
971 | pos += mtd->writesize; | ||
972 | } | ||
973 | |||
974 | ret = mtdswap_erase_block(d, eb); | ||
975 | if (ret) | ||
976 | goto error; | ||
977 | } | ||
978 | |||
979 | eb->flags &= ~EBLOCK_READERR; | ||
980 | return 1; | ||
981 | |||
982 | error: | ||
983 | mtdswap_handle_badblock(d, eb); | ||
984 | return 0; | ||
985 | } | ||
986 | |||
987 | static int mtdswap_gc(struct mtdswap_dev *d, unsigned int background) | ||
988 | { | ||
989 | struct swap_eb *eb; | ||
990 | int ret; | ||
991 | |||
992 | if (d->spare_eblks < MIN_SPARE_EBLOCKS) | ||
993 | return 1; | ||
994 | |||
995 | eb = mtdswap_pick_gc_eblk(d, background); | ||
996 | if (!eb) | ||
997 | return 1; | ||
998 | |||
999 | ret = mtdswap_gc_eblock(d, eb); | ||
1000 | if (ret == -ENOSPC) | ||
1001 | return 1; | ||
1002 | |||
1003 | if (eb->flags & EBLOCK_FAILED) { | ||
1004 | mtdswap_handle_badblock(d, eb); | ||
1005 | return 0; | ||
1006 | } | ||
1007 | |||
1008 | eb->flags &= ~EBLOCK_BITFLIP; | ||
1009 | ret = mtdswap_erase_block(d, eb); | ||
1010 | if ((eb->flags & EBLOCK_READERR) && | ||
1011 | (ret || !mtdswap_eblk_passes(d, eb))) | ||
1012 | return 0; | ||
1013 | |||
1014 | if (ret == 0) | ||
1015 | ret = mtdswap_write_marker(d, eb, MTDSWAP_TYPE_CLEAN); | ||
1016 | |||
1017 | if (ret == 0) | ||
1018 | mtdswap_rb_add(d, eb, MTDSWAP_CLEAN); | ||
1019 | else if (ret != -EIO && ret != -EBADMSG) | ||
1020 | mtdswap_rb_add(d, eb, MTDSWAP_DIRTY); | ||
1021 | |||
1022 | return 0; | ||
1023 | } | ||
1024 | |||
1025 | static void mtdswap_background(struct mtd_blktrans_dev *dev) | ||
1026 | { | ||
1027 | struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev); | ||
1028 | int ret; | ||
1029 | |||
1030 | while (1) { | ||
1031 | ret = mtdswap_gc(d, 1); | ||
1032 | if (ret || mtd_blktrans_cease_background(dev)) | ||
1033 | return; | ||
1034 | } | ||
1035 | } | ||
1036 | |||
1037 | static void mtdswap_cleanup(struct mtdswap_dev *d) | ||
1038 | { | ||
1039 | vfree(d->eb_data); | ||
1040 | vfree(d->revmap); | ||
1041 | vfree(d->page_data); | ||
1042 | kfree(d->oob_buf); | ||
1043 | kfree(d->page_buf); | ||
1044 | } | ||
1045 | |||
1046 | static int mtdswap_flush(struct mtd_blktrans_dev *dev) | ||
1047 | { | ||
1048 | struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev); | ||
1049 | |||
1050 | if (d->mtd->sync) | ||
1051 | d->mtd->sync(d->mtd); | ||
1052 | return 0; | ||
1053 | } | ||
1054 | |||
1055 | static unsigned int mtdswap_badblocks(struct mtd_info *mtd, uint64_t size) | ||
1056 | { | ||
1057 | loff_t offset; | ||
1058 | unsigned int badcnt; | ||
1059 | |||
1060 | badcnt = 0; | ||
1061 | |||
1062 | if (mtd->block_isbad) | ||
1063 | for (offset = 0; offset < size; offset += mtd->erasesize) | ||
1064 | if (mtd->block_isbad(mtd, offset)) | ||
1065 | badcnt++; | ||
1066 | |||
1067 | return badcnt; | ||
1068 | } | ||
1069 | |||
1070 | static int mtdswap_writesect(struct mtd_blktrans_dev *dev, | ||
1071 | unsigned long page, char *buf) | ||
1072 | { | ||
1073 | struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev); | ||
1074 | unsigned int newblock, mapped; | ||
1075 | struct swap_eb *eb; | ||
1076 | int ret; | ||
1077 | |||
1078 | d->sect_write_count++; | ||
1079 | |||
1080 | if (d->spare_eblks < MIN_SPARE_EBLOCKS) | ||
1081 | return -ENOSPC; | ||
1082 | |||
1083 | if (header) { | ||
1084 | /* Ignore writes to the header page */ | ||
1085 | if (unlikely(page == 0)) | ||
1086 | return 0; | ||
1087 | |||
1088 | page--; | ||
1089 | } | ||
1090 | |||
1091 | mapped = d->page_data[page]; | ||
1092 | if (mapped <= BLOCK_MAX) { | ||
1093 | eb = d->eb_data + (mapped / d->pages_per_eblk); | ||
1094 | eb->active_count--; | ||
1095 | mtdswap_store_eb(d, eb); | ||
1096 | d->page_data[page] = BLOCK_UNDEF; | ||
1097 | d->revmap[mapped] = PAGE_UNDEF; | ||
1098 | } | ||
1099 | |||
1100 | ret = mtdswap_write_block(d, buf, page, &newblock, 0); | ||
1101 | d->mtd_write_count++; | ||
1102 | |||
1103 | if (ret < 0) | ||
1104 | return ret; | ||
1105 | |||
1106 | eb = d->eb_data + (newblock / d->pages_per_eblk); | ||
1107 | d->page_data[page] = newblock; | ||
1108 | |||
1109 | return 0; | ||
1110 | } | ||
1111 | |||
1112 | /* Provide a dummy swap header for the kernel */ | ||
1113 | static int mtdswap_auto_header(struct mtdswap_dev *d, char *buf) | ||
1114 | { | ||
1115 | union swap_header *hd = (union swap_header *)(buf); | ||
1116 | |||
1117 | memset(buf, 0, PAGE_SIZE - 10); | ||
1118 | |||
1119 | hd->info.version = 1; | ||
1120 | hd->info.last_page = d->mbd_dev->size - 1; | ||
1121 | hd->info.nr_badpages = 0; | ||
1122 | |||
1123 | memcpy(buf + PAGE_SIZE - 10, "SWAPSPACE2", 10); | ||
1124 | |||
1125 | return 0; | ||
1126 | } | ||
1127 | |||
1128 | static int mtdswap_readsect(struct mtd_blktrans_dev *dev, | ||
1129 | unsigned long page, char *buf) | ||
1130 | { | ||
1131 | struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev); | ||
1132 | struct mtd_info *mtd = d->mtd; | ||
1133 | unsigned int realblock, retries; | ||
1134 | loff_t readpos; | ||
1135 | struct swap_eb *eb; | ||
1136 | size_t retlen; | ||
1137 | int ret; | ||
1138 | |||
1139 | d->sect_read_count++; | ||
1140 | |||
1141 | if (header) { | ||
1142 | if (unlikely(page == 0)) | ||
1143 | return mtdswap_auto_header(d, buf); | ||
1144 | |||
1145 | page--; | ||
1146 | } | ||
1147 | |||
1148 | realblock = d->page_data[page]; | ||
1149 | if (realblock > BLOCK_MAX) { | ||
1150 | memset(buf, 0x0, PAGE_SIZE); | ||
1151 | if (realblock == BLOCK_UNDEF) | ||
1152 | return 0; | ||
1153 | else | ||
1154 | return -EIO; | ||
1155 | } | ||
1156 | |||
1157 | eb = d->eb_data + (realblock / d->pages_per_eblk); | ||
1158 | BUG_ON(d->revmap[realblock] == PAGE_UNDEF); | ||
1159 | |||
1160 | readpos = (loff_t)realblock << PAGE_SHIFT; | ||
1161 | retries = 0; | ||
1162 | |||
1163 | retry: | ||
1164 | ret = mtd->read(mtd, readpos, PAGE_SIZE, &retlen, buf); | ||
1165 | |||
1166 | d->mtd_read_count++; | ||
1167 | if (ret == -EUCLEAN) { | ||
1168 | eb->flags |= EBLOCK_BITFLIP; | ||
1169 | mtdswap_rb_add(d, eb, MTDSWAP_BITFLIP); | ||
1170 | ret = 0; | ||
1171 | } | ||
1172 | |||
1173 | if (ret < 0) { | ||
1174 | dev_err(d->dev, "Read error %d\n", ret); | ||
1175 | eb->flags |= EBLOCK_READERR; | ||
1176 | mtdswap_rb_add(d, eb, MTDSWAP_FAILING); | ||
1177 | retries++; | ||
1178 | if (retries < MTDSWAP_IO_RETRIES) | ||
1179 | goto retry; | ||
1180 | |||
1181 | return ret; | ||
1182 | } | ||
1183 | |||
1184 | if (retlen != PAGE_SIZE) { | ||
1185 | dev_err(d->dev, "Short read %zd\n", retlen); | ||
1186 | return -EIO; | ||
1187 | } | ||
1188 | |||
1189 | return 0; | ||
1190 | } | ||
1191 | |||
1192 | static int mtdswap_discard(struct mtd_blktrans_dev *dev, unsigned long first, | ||
1193 | unsigned nr_pages) | ||
1194 | { | ||
1195 | struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev); | ||
1196 | unsigned long page; | ||
1197 | struct swap_eb *eb; | ||
1198 | unsigned int mapped; | ||
1199 | |||
1200 | d->discard_count++; | ||
1201 | |||
1202 | for (page = first; page < first + nr_pages; page++) { | ||
1203 | mapped = d->page_data[page]; | ||
1204 | if (mapped <= BLOCK_MAX) { | ||
1205 | eb = d->eb_data + (mapped / d->pages_per_eblk); | ||
1206 | eb->active_count--; | ||
1207 | mtdswap_store_eb(d, eb); | ||
1208 | d->page_data[page] = BLOCK_UNDEF; | ||
1209 | d->revmap[mapped] = PAGE_UNDEF; | ||
1210 | d->discard_page_count++; | ||
1211 | } else if (mapped == BLOCK_ERROR) { | ||
1212 | d->page_data[page] = BLOCK_UNDEF; | ||
1213 | d->discard_page_count++; | ||
1214 | } | ||
1215 | } | ||
1216 | |||
1217 | return 0; | ||
1218 | } | ||
1219 | |||
1220 | static int mtdswap_show(struct seq_file *s, void *data) | ||
1221 | { | ||
1222 | struct mtdswap_dev *d = (struct mtdswap_dev *) s->private; | ||
1223 | unsigned long sum; | ||
1224 | unsigned int count[MTDSWAP_TREE_CNT]; | ||
1225 | unsigned int min[MTDSWAP_TREE_CNT]; | ||
1226 | unsigned int max[MTDSWAP_TREE_CNT]; | ||
1227 | unsigned int i, cw = 0, cwp = 0, cwecount = 0, bb_cnt, mapped, pages; | ||
1228 | uint64_t use_size; | ||
1229 | char *name[] = {"clean", "used", "low", "high", "dirty", "bitflip", | ||
1230 | "failing"}; | ||
1231 | |||
1232 | mutex_lock(&d->mbd_dev->lock); | ||
1233 | |||
1234 | for (i = 0; i < MTDSWAP_TREE_CNT; i++) { | ||
1235 | struct rb_root *root = &d->trees[i].root; | ||
1236 | |||
1237 | if (root->rb_node) { | ||
1238 | count[i] = d->trees[i].count; | ||
1239 | min[i] = rb_entry(rb_first(root), struct swap_eb, | ||
1240 | rb)->erase_count; | ||
1241 | max[i] = rb_entry(rb_last(root), struct swap_eb, | ||
1242 | rb)->erase_count; | ||
1243 | } else | ||
1244 | count[i] = 0; | ||
1245 | } | ||
1246 | |||
1247 | if (d->curr_write) { | ||
1248 | cw = 1; | ||
1249 | cwp = d->curr_write_pos; | ||
1250 | cwecount = d->curr_write->erase_count; | ||
1251 | } | ||
1252 | |||
1253 | sum = 0; | ||
1254 | for (i = 0; i < d->eblks; i++) | ||
1255 | sum += d->eb_data[i].erase_count; | ||
1256 | |||
1257 | use_size = (uint64_t)d->eblks * d->mtd->erasesize; | ||
1258 | bb_cnt = mtdswap_badblocks(d->mtd, use_size); | ||
1259 | |||
1260 | mapped = 0; | ||
1261 | pages = d->mbd_dev->size; | ||
1262 | for (i = 0; i < pages; i++) | ||
1263 | if (d->page_data[i] != BLOCK_UNDEF) | ||
1264 | mapped++; | ||
1265 | |||
1266 | mutex_unlock(&d->mbd_dev->lock); | ||
1267 | |||
1268 | for (i = 0; i < MTDSWAP_TREE_CNT; i++) { | ||
1269 | if (!count[i]) | ||
1270 | continue; | ||
1271 | |||
1272 | if (min[i] != max[i]) | ||
1273 | seq_printf(s, "%s:\t%5d erase blocks, erased min %d, " | ||
1274 | "max %d times\n", | ||
1275 | name[i], count[i], min[i], max[i]); | ||
1276 | else | ||
1277 | seq_printf(s, "%s:\t%5d erase blocks, all erased %d " | ||
1278 | "times\n", name[i], count[i], min[i]); | ||
1279 | } | ||
1280 | |||
1281 | if (bb_cnt) | ||
1282 | seq_printf(s, "bad:\t%5u erase blocks\n", bb_cnt); | ||
1283 | |||
1284 | if (cw) | ||
1285 | seq_printf(s, "current erase block: %u pages used, %u free, " | ||
1286 | "erased %u times\n", | ||
1287 | cwp, d->pages_per_eblk - cwp, cwecount); | ||
1288 | |||
1289 | seq_printf(s, "total erasures: %lu\n", sum); | ||
1290 | |||
1291 | seq_printf(s, "\n"); | ||
1292 | |||
1293 | seq_printf(s, "mtdswap_readsect count: %llu\n", d->sect_read_count); | ||
1294 | seq_printf(s, "mtdswap_writesect count: %llu\n", d->sect_write_count); | ||
1295 | seq_printf(s, "mtdswap_discard count: %llu\n", d->discard_count); | ||
1296 | seq_printf(s, "mtd read count: %llu\n", d->mtd_read_count); | ||
1297 | seq_printf(s, "mtd write count: %llu\n", d->mtd_write_count); | ||
1298 | seq_printf(s, "discarded pages count: %llu\n", d->discard_page_count); | ||
1299 | |||
1300 | seq_printf(s, "\n"); | ||
1301 | seq_printf(s, "total pages: %u\n", pages); | ||
1302 | seq_printf(s, "pages mapped: %u\n", mapped); | ||
1303 | |||
1304 | return 0; | ||
1305 | } | ||
1306 | |||
1307 | static int mtdswap_open(struct inode *inode, struct file *file) | ||
1308 | { | ||
1309 | return single_open(file, mtdswap_show, inode->i_private); | ||
1310 | } | ||
1311 | |||
1312 | static const struct file_operations mtdswap_fops = { | ||
1313 | .open = mtdswap_open, | ||
1314 | .read = seq_read, | ||
1315 | .llseek = seq_lseek, | ||
1316 | .release = single_release, | ||
1317 | }; | ||
1318 | |||
1319 | static int mtdswap_add_debugfs(struct mtdswap_dev *d) | ||
1320 | { | ||
1321 | struct gendisk *gd = d->mbd_dev->disk; | ||
1322 | struct device *dev = disk_to_dev(gd); | ||
1323 | |||
1324 | struct dentry *root; | ||
1325 | struct dentry *dent; | ||
1326 | |||
1327 | root = debugfs_create_dir(gd->disk_name, NULL); | ||
1328 | if (IS_ERR(root)) | ||
1329 | return 0; | ||
1330 | |||
1331 | if (!root) { | ||
1332 | dev_err(dev, "failed to initialize debugfs\n"); | ||
1333 | return -1; | ||
1334 | } | ||
1335 | |||
1336 | d->debugfs_root = root; | ||
1337 | |||
1338 | dent = debugfs_create_file("stats", S_IRUSR, root, d, | ||
1339 | &mtdswap_fops); | ||
1340 | if (!dent) { | ||
1341 | dev_err(d->dev, "debugfs_create_file failed\n"); | ||
1342 | debugfs_remove_recursive(root); | ||
1343 | d->debugfs_root = NULL; | ||
1344 | return -1; | ||
1345 | } | ||
1346 | |||
1347 | return 0; | ||
1348 | } | ||
1349 | |||
1350 | static int mtdswap_init(struct mtdswap_dev *d, unsigned int eblocks, | ||
1351 | unsigned int spare_cnt) | ||
1352 | { | ||
1353 | struct mtd_info *mtd = d->mbd_dev->mtd; | ||
1354 | unsigned int i, eblk_bytes, pages, blocks; | ||
1355 | int ret = -ENOMEM; | ||
1356 | |||
1357 | d->mtd = mtd; | ||
1358 | d->eblks = eblocks; | ||
1359 | d->spare_eblks = spare_cnt; | ||
1360 | d->pages_per_eblk = mtd->erasesize >> PAGE_SHIFT; | ||
1361 | |||
1362 | pages = d->mbd_dev->size; | ||
1363 | blocks = eblocks * d->pages_per_eblk; | ||
1364 | |||
1365 | for (i = 0; i < MTDSWAP_TREE_CNT; i++) | ||
1366 | d->trees[i].root = RB_ROOT; | ||
1367 | |||
1368 | d->page_data = vmalloc(sizeof(int)*pages); | ||
1369 | if (!d->page_data) | ||
1370 | goto page_data_fail; | ||
1371 | |||
1372 | d->revmap = vmalloc(sizeof(int)*blocks); | ||
1373 | if (!d->revmap) | ||
1374 | goto revmap_fail; | ||
1375 | |||
1376 | eblk_bytes = sizeof(struct swap_eb)*d->eblks; | ||
1377 | d->eb_data = vmalloc(eblk_bytes); | ||
1378 | if (!d->eb_data) | ||
1379 | goto eb_data_fail; | ||
1380 | |||
1381 | memset(d->eb_data, 0, eblk_bytes); | ||
1382 | for (i = 0; i < pages; i++) | ||
1383 | d->page_data[i] = BLOCK_UNDEF; | ||
1384 | |||
1385 | for (i = 0; i < blocks; i++) | ||
1386 | d->revmap[i] = PAGE_UNDEF; | ||
1387 | |||
1388 | d->page_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
1389 | if (!d->page_buf) | ||
1390 | goto page_buf_fail; | ||
1391 | |||
1392 | d->oob_buf = kmalloc(2 * mtd->ecclayout->oobavail, GFP_KERNEL); | ||
1393 | if (!d->oob_buf) | ||
1394 | goto oob_buf_fail; | ||
1395 | |||
1396 | mtdswap_scan_eblks(d); | ||
1397 | |||
1398 | return 0; | ||
1399 | |||
1400 | oob_buf_fail: | ||
1401 | kfree(d->page_buf); | ||
1402 | page_buf_fail: | ||
1403 | vfree(d->eb_data); | ||
1404 | eb_data_fail: | ||
1405 | vfree(d->revmap); | ||
1406 | revmap_fail: | ||
1407 | vfree(d->page_data); | ||
1408 | page_data_fail: | ||
1409 | printk(KERN_ERR "%s: init failed (%d)\n", MTDSWAP_PREFIX, ret); | ||
1410 | return ret; | ||
1411 | } | ||
1412 | |||
1413 | static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) | ||
1414 | { | ||
1415 | struct mtdswap_dev *d; | ||
1416 | struct mtd_blktrans_dev *mbd_dev; | ||
1417 | char *parts; | ||
1418 | char *this_opt; | ||
1419 | unsigned long part; | ||
1420 | unsigned int eblocks, eavailable, bad_blocks, spare_cnt; | ||
1421 | uint64_t swap_size, use_size, size_limit; | ||
1422 | struct nand_ecclayout *oinfo; | ||
1423 | int ret; | ||
1424 | |||
1425 | parts = &partitions[0]; | ||
1426 | if (!*parts) | ||
1427 | return; | ||
1428 | |||
1429 | while ((this_opt = strsep(&parts, ",")) != NULL) { | ||
1430 | if (strict_strtoul(this_opt, 0, &part) < 0) | ||
1431 | return; | ||
1432 | |||
1433 | if (mtd->index == part) | ||
1434 | break; | ||
1435 | } | ||
1436 | |||
1437 | if (mtd->index != part) | ||
1438 | return; | ||
1439 | |||
1440 | if (mtd->erasesize < PAGE_SIZE || mtd->erasesize % PAGE_SIZE) { | ||
1441 | printk(KERN_ERR "%s: Erase size %u not multiple of PAGE_SIZE " | ||
1442 | "%lu\n", MTDSWAP_PREFIX, mtd->erasesize, PAGE_SIZE); | ||
1443 | return; | ||
1444 | } | ||
1445 | |||
1446 | if (PAGE_SIZE % mtd->writesize || mtd->writesize > PAGE_SIZE) { | ||
1447 | printk(KERN_ERR "%s: PAGE_SIZE %lu not multiple of write size" | ||
1448 | " %u\n", MTDSWAP_PREFIX, PAGE_SIZE, mtd->writesize); | ||
1449 | return; | ||
1450 | } | ||
1451 | |||
1452 | oinfo = mtd->ecclayout; | ||
1453 | if (!mtd->oobsize || !oinfo || oinfo->oobavail < MTDSWAP_OOBSIZE) { | ||
1454 | printk(KERN_ERR "%s: Not enough free bytes in OOB, " | ||
1455 | "%d available, %lu needed.\n", | ||
1456 | MTDSWAP_PREFIX, oinfo->oobavail, MTDSWAP_OOBSIZE); | ||
1457 | return; | ||
1458 | } | ||
1459 | |||
1460 | if (spare_eblocks > 100) | ||
1461 | spare_eblocks = 100; | ||
1462 | |||
1463 | use_size = mtd->size; | ||
1464 | size_limit = (uint64_t) BLOCK_MAX * PAGE_SIZE; | ||
1465 | |||
1466 | if (mtd->size > size_limit) { | ||
1467 | printk(KERN_WARNING "%s: Device too large. Limiting size to " | ||
1468 | "%llu bytes\n", MTDSWAP_PREFIX, size_limit); | ||
1469 | use_size = size_limit; | ||
1470 | } | ||
1471 | |||
1472 | eblocks = mtd_div_by_eb(use_size, mtd); | ||
1473 | use_size = eblocks * mtd->erasesize; | ||
1474 | bad_blocks = mtdswap_badblocks(mtd, use_size); | ||
1475 | eavailable = eblocks - bad_blocks; | ||
1476 | |||
1477 | if (eavailable < MIN_ERASE_BLOCKS) { | ||
1478 | printk(KERN_ERR "%s: Not enough erase blocks. %u available, " | ||
1479 | "%d needed\n", MTDSWAP_PREFIX, eavailable, | ||
1480 | MIN_ERASE_BLOCKS); | ||
1481 | return; | ||
1482 | } | ||
1483 | |||
1484 | spare_cnt = div_u64((uint64_t)eavailable * spare_eblocks, 100); | ||
1485 | |||
1486 | if (spare_cnt < MIN_SPARE_EBLOCKS) | ||
1487 | spare_cnt = MIN_SPARE_EBLOCKS; | ||
1488 | |||
1489 | if (spare_cnt > eavailable - 1) | ||
1490 | spare_cnt = eavailable - 1; | ||
1491 | |||
1492 | swap_size = (uint64_t)(eavailable - spare_cnt) * mtd->erasesize + | ||
1493 | (header ? PAGE_SIZE : 0); | ||
1494 | |||
1495 | printk(KERN_INFO "%s: Enabling MTD swap on device %lu, size %llu KB, " | ||
1496 | "%u spare, %u bad blocks\n", | ||
1497 | MTDSWAP_PREFIX, part, swap_size / 1024, spare_cnt, bad_blocks); | ||
1498 | |||
1499 | d = kzalloc(sizeof(struct mtdswap_dev), GFP_KERNEL); | ||
1500 | if (!d) | ||
1501 | return; | ||
1502 | |||
1503 | mbd_dev = kzalloc(sizeof(struct mtd_blktrans_dev), GFP_KERNEL); | ||
1504 | if (!mbd_dev) { | ||
1505 | kfree(d); | ||
1506 | return; | ||
1507 | } | ||
1508 | |||
1509 | d->mbd_dev = mbd_dev; | ||
1510 | mbd_dev->priv = d; | ||
1511 | |||
1512 | mbd_dev->mtd = mtd; | ||
1513 | mbd_dev->devnum = mtd->index; | ||
1514 | mbd_dev->size = swap_size >> PAGE_SHIFT; | ||
1515 | mbd_dev->tr = tr; | ||
1516 | |||
1517 | if (!(mtd->flags & MTD_WRITEABLE)) | ||
1518 | mbd_dev->readonly = 1; | ||
1519 | |||
1520 | if (mtdswap_init(d, eblocks, spare_cnt) < 0) | ||
1521 | goto init_failed; | ||
1522 | |||
1523 | if (add_mtd_blktrans_dev(mbd_dev) < 0) | ||
1524 | goto cleanup; | ||
1525 | |||
1526 | d->dev = disk_to_dev(mbd_dev->disk); | ||
1527 | |||
1528 | ret = mtdswap_add_debugfs(d); | ||
1529 | if (ret < 0) | ||
1530 | goto debugfs_failed; | ||
1531 | |||
1532 | return; | ||
1533 | |||
1534 | debugfs_failed: | ||
1535 | del_mtd_blktrans_dev(mbd_dev); | ||
1536 | |||
1537 | cleanup: | ||
1538 | mtdswap_cleanup(d); | ||
1539 | |||
1540 | init_failed: | ||
1541 | kfree(mbd_dev); | ||
1542 | kfree(d); | ||
1543 | } | ||
1544 | |||
1545 | static void mtdswap_remove_dev(struct mtd_blktrans_dev *dev) | ||
1546 | { | ||
1547 | struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev); | ||
1548 | |||
1549 | debugfs_remove_recursive(d->debugfs_root); | ||
1550 | del_mtd_blktrans_dev(dev); | ||
1551 | mtdswap_cleanup(d); | ||
1552 | kfree(d); | ||
1553 | } | ||
1554 | |||
1555 | static struct mtd_blktrans_ops mtdswap_ops = { | ||
1556 | .name = "mtdswap", | ||
1557 | .major = 0, | ||
1558 | .part_bits = 0, | ||
1559 | .blksize = PAGE_SIZE, | ||
1560 | .flush = mtdswap_flush, | ||
1561 | .readsect = mtdswap_readsect, | ||
1562 | .writesect = mtdswap_writesect, | ||
1563 | .discard = mtdswap_discard, | ||
1564 | .background = mtdswap_background, | ||
1565 | .add_mtd = mtdswap_add_mtd, | ||
1566 | .remove_dev = mtdswap_remove_dev, | ||
1567 | .owner = THIS_MODULE, | ||
1568 | }; | ||
1569 | |||
1570 | static int __init mtdswap_modinit(void) | ||
1571 | { | ||
1572 | return register_mtd_blktrans(&mtdswap_ops); | ||
1573 | } | ||
1574 | |||
1575 | static void __exit mtdswap_modexit(void) | ||
1576 | { | ||
1577 | deregister_mtd_blktrans(&mtdswap_ops); | ||
1578 | } | ||
1579 | |||
1580 | module_init(mtdswap_modinit); | ||
1581 | module_exit(mtdswap_modexit); | ||
1582 | |||
1583 | |||
1584 | MODULE_LICENSE("GPL"); | ||
1585 | MODULE_AUTHOR("Jarkko Lavinen <jarkko.lavinen@nokia.com>"); | ||
1586 | MODULE_DESCRIPTION("Block device access to an MTD suitable for using as " | ||
1587 | "swap space"); | ||
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 4f6c06f16328..a92054e945e1 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -31,6 +31,21 @@ config MTD_NAND_VERIFY_WRITE | |||
31 | device thinks the write was successful, a bit could have been | 31 | device thinks the write was successful, a bit could have been |
32 | flipped accidentally due to device wear or something else. | 32 | flipped accidentally due to device wear or something else. |
33 | 33 | ||
34 | config MTD_NAND_BCH | ||
35 | tristate | ||
36 | select BCH | ||
37 | depends on MTD_NAND_ECC_BCH | ||
38 | default MTD_NAND | ||
39 | |||
40 | config MTD_NAND_ECC_BCH | ||
41 | bool "Support software BCH ECC" | ||
42 | default n | ||
43 | help | ||
44 | This enables support for software BCH error correction. Binary BCH | ||
45 | codes are more powerful and cpu intensive than traditional Hamming | ||
46 | ECC codes. They are used with NAND devices requiring more than 1 bit | ||
47 | of error correction. | ||
48 | |||
34 | config MTD_SM_COMMON | 49 | config MTD_SM_COMMON |
35 | tristate | 50 | tristate |
36 | default n | 51 | default n |
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 8ad6faec72cb..5745d831168e 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_MTD_NAND) += nand.o | 5 | obj-$(CONFIG_MTD_NAND) += nand.o |
6 | obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o | 6 | obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o |
7 | obj-$(CONFIG_MTD_NAND_BCH) += nand_bch.o | ||
7 | obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o | 8 | obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o |
8 | obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o | 9 | obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o |
9 | 10 | ||
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index ccce0f03b5dc..6fae04b3fc6d 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c | |||
@@ -48,6 +48,9 @@ | |||
48 | #define no_ecc 0 | 48 | #define no_ecc 0 |
49 | #endif | 49 | #endif |
50 | 50 | ||
51 | static int use_dma = 1; | ||
52 | module_param(use_dma, int, 0); | ||
53 | |||
51 | static int on_flash_bbt = 0; | 54 | static int on_flash_bbt = 0; |
52 | module_param(on_flash_bbt, int, 0); | 55 | module_param(on_flash_bbt, int, 0); |
53 | 56 | ||
@@ -89,11 +92,20 @@ struct atmel_nand_host { | |||
89 | struct nand_chip nand_chip; | 92 | struct nand_chip nand_chip; |
90 | struct mtd_info mtd; | 93 | struct mtd_info mtd; |
91 | void __iomem *io_base; | 94 | void __iomem *io_base; |
95 | dma_addr_t io_phys; | ||
92 | struct atmel_nand_data *board; | 96 | struct atmel_nand_data *board; |
93 | struct device *dev; | 97 | struct device *dev; |
94 | void __iomem *ecc; | 98 | void __iomem *ecc; |
99 | |||
100 | struct completion comp; | ||
101 | struct dma_chan *dma_chan; | ||
95 | }; | 102 | }; |
96 | 103 | ||
104 | static int cpu_has_dma(void) | ||
105 | { | ||
106 | return cpu_is_at91sam9rl() || cpu_is_at91sam9g45(); | ||
107 | } | ||
108 | |||
97 | /* | 109 | /* |
98 | * Enable NAND. | 110 | * Enable NAND. |
99 | */ | 111 | */ |
@@ -150,7 +162,7 @@ static int atmel_nand_device_ready(struct mtd_info *mtd) | |||
150 | /* | 162 | /* |
151 | * Minimal-overhead PIO for data access. | 163 | * Minimal-overhead PIO for data access. |
152 | */ | 164 | */ |
153 | static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) | 165 | static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len) |
154 | { | 166 | { |
155 | struct nand_chip *nand_chip = mtd->priv; | 167 | struct nand_chip *nand_chip = mtd->priv; |
156 | 168 | ||
@@ -164,7 +176,7 @@ static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) | |||
164 | __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); | 176 | __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); |
165 | } | 177 | } |
166 | 178 | ||
167 | static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) | 179 | static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len) |
168 | { | 180 | { |
169 | struct nand_chip *nand_chip = mtd->priv; | 181 | struct nand_chip *nand_chip = mtd->priv; |
170 | 182 | ||
@@ -178,6 +190,121 @@ static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) | |||
178 | __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); | 190 | __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); |
179 | } | 191 | } |
180 | 192 | ||
193 | static void dma_complete_func(void *completion) | ||
194 | { | ||
195 | complete(completion); | ||
196 | } | ||
197 | |||
198 | static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len, | ||
199 | int is_read) | ||
200 | { | ||
201 | struct dma_device *dma_dev; | ||
202 | enum dma_ctrl_flags flags; | ||
203 | dma_addr_t dma_src_addr, dma_dst_addr, phys_addr; | ||
204 | struct dma_async_tx_descriptor *tx = NULL; | ||
205 | dma_cookie_t cookie; | ||
206 | struct nand_chip *chip = mtd->priv; | ||
207 | struct atmel_nand_host *host = chip->priv; | ||
208 | void *p = buf; | ||
209 | int err = -EIO; | ||
210 | enum dma_data_direction dir = is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; | ||
211 | |||
212 | if (buf >= high_memory) { | ||
213 | struct page *pg; | ||
214 | |||
215 | if (((size_t)buf & PAGE_MASK) != | ||
216 | ((size_t)(buf + len - 1) & PAGE_MASK)) { | ||
217 | dev_warn(host->dev, "Buffer not fit in one page\n"); | ||
218 | goto err_buf; | ||
219 | } | ||
220 | |||
221 | pg = vmalloc_to_page(buf); | ||
222 | if (pg == 0) { | ||
223 | dev_err(host->dev, "Failed to vmalloc_to_page\n"); | ||
224 | goto err_buf; | ||
225 | } | ||
226 | p = page_address(pg) + ((size_t)buf & ~PAGE_MASK); | ||
227 | } | ||
228 | |||
229 | dma_dev = host->dma_chan->device; | ||
230 | |||
231 | flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP | | ||
232 | DMA_COMPL_SKIP_DEST_UNMAP; | ||
233 | |||
234 | phys_addr = dma_map_single(dma_dev->dev, p, len, dir); | ||
235 | if (dma_mapping_error(dma_dev->dev, phys_addr)) { | ||
236 | dev_err(host->dev, "Failed to dma_map_single\n"); | ||
237 | goto err_buf; | ||
238 | } | ||
239 | |||
240 | if (is_read) { | ||
241 | dma_src_addr = host->io_phys; | ||
242 | dma_dst_addr = phys_addr; | ||
243 | } else { | ||
244 | dma_src_addr = phys_addr; | ||
245 | dma_dst_addr = host->io_phys; | ||
246 | } | ||
247 | |||
248 | tx = dma_dev->device_prep_dma_memcpy(host->dma_chan, dma_dst_addr, | ||
249 | dma_src_addr, len, flags); | ||
250 | if (!tx) { | ||
251 | dev_err(host->dev, "Failed to prepare DMA memcpy\n"); | ||
252 | goto err_dma; | ||
253 | } | ||
254 | |||
255 | init_completion(&host->comp); | ||
256 | tx->callback = dma_complete_func; | ||
257 | tx->callback_param = &host->comp; | ||
258 | |||
259 | cookie = tx->tx_submit(tx); | ||
260 | if (dma_submit_error(cookie)) { | ||
261 | dev_err(host->dev, "Failed to do DMA tx_submit\n"); | ||
262 | goto err_dma; | ||
263 | } | ||
264 | |||
265 | dma_async_issue_pending(host->dma_chan); | ||
266 | wait_for_completion(&host->comp); | ||
267 | |||
268 | err = 0; | ||
269 | |||
270 | err_dma: | ||
271 | dma_unmap_single(dma_dev->dev, phys_addr, len, dir); | ||
272 | err_buf: | ||
273 | if (err != 0) | ||
274 | dev_warn(host->dev, "Fall back to CPU I/O\n"); | ||
275 | return err; | ||
276 | } | ||
277 | |||
278 | static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) | ||
279 | { | ||
280 | struct nand_chip *chip = mtd->priv; | ||
281 | struct atmel_nand_host *host = chip->priv; | ||
282 | |||
283 | if (use_dma && len >= mtd->oobsize) | ||
284 | if (atmel_nand_dma_op(mtd, buf, len, 1) == 0) | ||
285 | return; | ||
286 | |||
287 | if (host->board->bus_width_16) | ||
288 | atmel_read_buf16(mtd, buf, len); | ||
289 | else | ||
290 | atmel_read_buf8(mtd, buf, len); | ||
291 | } | ||
292 | |||
293 | static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) | ||
294 | { | ||
295 | struct nand_chip *chip = mtd->priv; | ||
296 | struct atmel_nand_host *host = chip->priv; | ||
297 | |||
298 | if (use_dma && len >= mtd->oobsize) | ||
299 | if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0) | ||
300 | return; | ||
301 | |||
302 | if (host->board->bus_width_16) | ||
303 | atmel_write_buf16(mtd, buf, len); | ||
304 | else | ||
305 | atmel_write_buf8(mtd, buf, len); | ||
306 | } | ||
307 | |||
181 | /* | 308 | /* |
182 | * Calculate HW ECC | 309 | * Calculate HW ECC |
183 | * | 310 | * |
@@ -398,6 +525,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev) | |||
398 | return -ENOMEM; | 525 | return -ENOMEM; |
399 | } | 526 | } |
400 | 527 | ||
528 | host->io_phys = (dma_addr_t)mem->start; | ||
529 | |||
401 | host->io_base = ioremap(mem->start, mem->end - mem->start + 1); | 530 | host->io_base = ioremap(mem->start, mem->end - mem->start + 1); |
402 | if (host->io_base == NULL) { | 531 | if (host->io_base == NULL) { |
403 | printk(KERN_ERR "atmel_nand: ioremap failed\n"); | 532 | printk(KERN_ERR "atmel_nand: ioremap failed\n"); |
@@ -448,14 +577,11 @@ static int __init atmel_nand_probe(struct platform_device *pdev) | |||
448 | 577 | ||
449 | nand_chip->chip_delay = 20; /* 20us command delay time */ | 578 | nand_chip->chip_delay = 20; /* 20us command delay time */ |
450 | 579 | ||
451 | if (host->board->bus_width_16) { /* 16-bit bus width */ | 580 | if (host->board->bus_width_16) /* 16-bit bus width */ |
452 | nand_chip->options |= NAND_BUSWIDTH_16; | 581 | nand_chip->options |= NAND_BUSWIDTH_16; |
453 | nand_chip->read_buf = atmel_read_buf16; | 582 | |
454 | nand_chip->write_buf = atmel_write_buf16; | 583 | nand_chip->read_buf = atmel_read_buf; |
455 | } else { | 584 | nand_chip->write_buf = atmel_write_buf; |
456 | nand_chip->read_buf = atmel_read_buf; | ||
457 | nand_chip->write_buf = atmel_write_buf; | ||
458 | } | ||
459 | 585 | ||
460 | platform_set_drvdata(pdev, host); | 586 | platform_set_drvdata(pdev, host); |
461 | atmel_nand_enable(host); | 587 | atmel_nand_enable(host); |
@@ -473,6 +599,22 @@ static int __init atmel_nand_probe(struct platform_device *pdev) | |||
473 | nand_chip->options |= NAND_USE_FLASH_BBT; | 599 | nand_chip->options |= NAND_USE_FLASH_BBT; |
474 | } | 600 | } |
475 | 601 | ||
602 | if (cpu_has_dma() && use_dma) { | ||
603 | dma_cap_mask_t mask; | ||
604 | |||
605 | dma_cap_zero(mask); | ||
606 | dma_cap_set(DMA_MEMCPY, mask); | ||
607 | host->dma_chan = dma_request_channel(mask, 0, NULL); | ||
608 | if (!host->dma_chan) { | ||
609 | dev_err(host->dev, "Failed to request DMA channel\n"); | ||
610 | use_dma = 0; | ||
611 | } | ||
612 | } | ||
613 | if (use_dma) | ||
614 | dev_info(host->dev, "Using DMA for NAND access.\n"); | ||
615 | else | ||
616 | dev_info(host->dev, "No DMA support for NAND access.\n"); | ||
617 | |||
476 | /* first scan to find the device and get the page size */ | 618 | /* first scan to find the device and get the page size */ |
477 | if (nand_scan_ident(mtd, 1, NULL)) { | 619 | if (nand_scan_ident(mtd, 1, NULL)) { |
478 | res = -ENXIO; | 620 | res = -ENXIO; |
@@ -555,6 +697,8 @@ err_scan_ident: | |||
555 | err_no_card: | 697 | err_no_card: |
556 | atmel_nand_disable(host); | 698 | atmel_nand_disable(host); |
557 | platform_set_drvdata(pdev, NULL); | 699 | platform_set_drvdata(pdev, NULL); |
700 | if (host->dma_chan) | ||
701 | dma_release_channel(host->dma_chan); | ||
558 | if (host->ecc) | 702 | if (host->ecc) |
559 | iounmap(host->ecc); | 703 | iounmap(host->ecc); |
560 | err_ecc_ioremap: | 704 | err_ecc_ioremap: |
@@ -578,6 +722,10 @@ static int __exit atmel_nand_remove(struct platform_device *pdev) | |||
578 | 722 | ||
579 | if (host->ecc) | 723 | if (host->ecc) |
580 | iounmap(host->ecc); | 724 | iounmap(host->ecc); |
725 | |||
726 | if (host->dma_chan) | ||
727 | dma_release_channel(host->dma_chan); | ||
728 | |||
581 | iounmap(host->io_base); | 729 | iounmap(host->io_base); |
582 | kfree(host); | 730 | kfree(host); |
583 | 731 | ||
diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index a90fde3ede28..aff3468867ac 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c | |||
@@ -37,9 +37,6 @@ | |||
37 | #include <mach/nand.h> | 37 | #include <mach/nand.h> |
38 | #include <mach/aemif.h> | 38 | #include <mach/aemif.h> |
39 | 39 | ||
40 | #include <asm/mach-types.h> | ||
41 | |||
42 | |||
43 | /* | 40 | /* |
44 | * This is a device driver for the NAND flash controller found on the | 41 | * This is a device driver for the NAND flash controller found on the |
45 | * various DaVinci family chips. It handles up to four SoC chipselects, | 42 | * various DaVinci family chips. It handles up to four SoC chipselects, |
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index c2f95437e5e9..0b81b5b499d1 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/clk.h> | 29 | #include <linux/clk.h> |
30 | #include <linux/gfp.h> | 30 | #include <linux/gfp.h> |
31 | #include <linux/delay.h> | 31 | #include <linux/delay.h> |
32 | #include <linux/err.h> | ||
32 | #include <linux/init.h> | 33 | #include <linux/init.h> |
33 | #include <linux/interrupt.h> | 34 | #include <linux/interrupt.h> |
34 | #include <linux/io.h> | 35 | #include <linux/io.h> |
@@ -757,9 +758,9 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) | |||
757 | 758 | ||
758 | /* Enable NFC clock */ | 759 | /* Enable NFC clock */ |
759 | prv->clk = clk_get(dev, "nfc_clk"); | 760 | prv->clk = clk_get(dev, "nfc_clk"); |
760 | if (!prv->clk) { | 761 | if (IS_ERR(prv->clk)) { |
761 | dev_err(dev, "Unable to acquire NFC clock!\n"); | 762 | dev_err(dev, "Unable to acquire NFC clock!\n"); |
762 | retval = -ENODEV; | 763 | retval = PTR_ERR(prv->clk); |
763 | goto error; | 764 | goto error; |
764 | } | 765 | } |
765 | 766 | ||
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 5ae1d9ee2cf1..42a95fb41504 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
@@ -211,6 +211,31 @@ static struct nand_ecclayout nandv2_hw_eccoob_largepage = { | |||
211 | } | 211 | } |
212 | }; | 212 | }; |
213 | 213 | ||
214 | /* OOB description for 4096 byte pages with 128 byte OOB */ | ||
215 | static struct nand_ecclayout nandv2_hw_eccoob_4k = { | ||
216 | .eccbytes = 8 * 9, | ||
217 | .eccpos = { | ||
218 | 7, 8, 9, 10, 11, 12, 13, 14, 15, | ||
219 | 23, 24, 25, 26, 27, 28, 29, 30, 31, | ||
220 | 39, 40, 41, 42, 43, 44, 45, 46, 47, | ||
221 | 55, 56, 57, 58, 59, 60, 61, 62, 63, | ||
222 | 71, 72, 73, 74, 75, 76, 77, 78, 79, | ||
223 | 87, 88, 89, 90, 91, 92, 93, 94, 95, | ||
224 | 103, 104, 105, 106, 107, 108, 109, 110, 111, | ||
225 | 119, 120, 121, 122, 123, 124, 125, 126, 127, | ||
226 | }, | ||
227 | .oobfree = { | ||
228 | {.offset = 2, .length = 4}, | ||
229 | {.offset = 16, .length = 7}, | ||
230 | {.offset = 32, .length = 7}, | ||
231 | {.offset = 48, .length = 7}, | ||
232 | {.offset = 64, .length = 7}, | ||
233 | {.offset = 80, .length = 7}, | ||
234 | {.offset = 96, .length = 7}, | ||
235 | {.offset = 112, .length = 7}, | ||
236 | } | ||
237 | }; | ||
238 | |||
214 | #ifdef CONFIG_MTD_PARTITIONS | 239 | #ifdef CONFIG_MTD_PARTITIONS |
215 | static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; | 240 | static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; |
216 | #endif | 241 | #endif |
@@ -641,9 +666,9 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | |||
641 | 666 | ||
642 | n = min(n, len); | 667 | n = min(n, len); |
643 | 668 | ||
644 | memcpy(buf, host->data_buf + col, len); | 669 | memcpy(buf, host->data_buf + col, n); |
645 | 670 | ||
646 | host->buf_start += len; | 671 | host->buf_start += n; |
647 | } | 672 | } |
648 | 673 | ||
649 | /* Used by the upper layer to verify the data in NAND Flash | 674 | /* Used by the upper layer to verify the data in NAND Flash |
@@ -1185,6 +1210,8 @@ static int __init mxcnd_probe(struct platform_device *pdev) | |||
1185 | 1210 | ||
1186 | if (mtd->writesize == 2048) | 1211 | if (mtd->writesize == 2048) |
1187 | this->ecc.layout = oob_largepage; | 1212 | this->ecc.layout = oob_largepage; |
1213 | if (nfc_is_v21() && mtd->writesize == 4096) | ||
1214 | this->ecc.layout = &nandv2_hw_eccoob_4k; | ||
1188 | 1215 | ||
1189 | /* second phase scan */ | 1216 | /* second phase scan */ |
1190 | if (nand_scan_tail(mtd)) { | 1217 | if (nand_scan_tail(mtd)) { |
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index a9c6ce745767..85cfc061d41c 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/mtd/mtd.h> | 42 | #include <linux/mtd/mtd.h> |
43 | #include <linux/mtd/nand.h> | 43 | #include <linux/mtd/nand.h> |
44 | #include <linux/mtd/nand_ecc.h> | 44 | #include <linux/mtd/nand_ecc.h> |
45 | #include <linux/mtd/nand_bch.h> | ||
45 | #include <linux/interrupt.h> | 46 | #include <linux/interrupt.h> |
46 | #include <linux/bitops.h> | 47 | #include <linux/bitops.h> |
47 | #include <linux/leds.h> | 48 | #include <linux/leds.h> |
@@ -2377,7 +2378,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, | |||
2377 | return -EINVAL; | 2378 | return -EINVAL; |
2378 | } | 2379 | } |
2379 | 2380 | ||
2380 | /* Do not allow reads past end of device */ | 2381 | /* Do not allow write past end of device */ |
2381 | if (unlikely(to >= mtd->size || | 2382 | if (unlikely(to >= mtd->size || |
2382 | ops->ooboffs + ops->ooblen > | 2383 | ops->ooboffs + ops->ooblen > |
2383 | ((mtd->size >> chip->page_shift) - | 2384 | ((mtd->size >> chip->page_shift) - |
@@ -3248,7 +3249,7 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
3248 | /* | 3249 | /* |
3249 | * If no default placement scheme is given, select an appropriate one | 3250 | * If no default placement scheme is given, select an appropriate one |
3250 | */ | 3251 | */ |
3251 | if (!chip->ecc.layout) { | 3252 | if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) { |
3252 | switch (mtd->oobsize) { | 3253 | switch (mtd->oobsize) { |
3253 | case 8: | 3254 | case 8: |
3254 | chip->ecc.layout = &nand_oob_8; | 3255 | chip->ecc.layout = &nand_oob_8; |
@@ -3351,6 +3352,40 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
3351 | chip->ecc.bytes = 3; | 3352 | chip->ecc.bytes = 3; |
3352 | break; | 3353 | break; |
3353 | 3354 | ||
3355 | case NAND_ECC_SOFT_BCH: | ||
3356 | if (!mtd_nand_has_bch()) { | ||
3357 | printk(KERN_WARNING "CONFIG_MTD_ECC_BCH not enabled\n"); | ||
3358 | BUG(); | ||
3359 | } | ||
3360 | chip->ecc.calculate = nand_bch_calculate_ecc; | ||
3361 | chip->ecc.correct = nand_bch_correct_data; | ||
3362 | chip->ecc.read_page = nand_read_page_swecc; | ||
3363 | chip->ecc.read_subpage = nand_read_subpage; | ||
3364 | chip->ecc.write_page = nand_write_page_swecc; | ||
3365 | chip->ecc.read_page_raw = nand_read_page_raw; | ||
3366 | chip->ecc.write_page_raw = nand_write_page_raw; | ||
3367 | chip->ecc.read_oob = nand_read_oob_std; | ||
3368 | chip->ecc.write_oob = nand_write_oob_std; | ||
3369 | /* | ||
3370 | * Board driver should supply ecc.size and ecc.bytes values to | ||
3371 | * select how many bits are correctable; see nand_bch_init() | ||
3372 | * for details. | ||
3373 | * Otherwise, default to 4 bits for large page devices | ||
3374 | */ | ||
3375 | if (!chip->ecc.size && (mtd->oobsize >= 64)) { | ||
3376 | chip->ecc.size = 512; | ||
3377 | chip->ecc.bytes = 7; | ||
3378 | } | ||
3379 | chip->ecc.priv = nand_bch_init(mtd, | ||
3380 | chip->ecc.size, | ||
3381 | chip->ecc.bytes, | ||
3382 | &chip->ecc.layout); | ||
3383 | if (!chip->ecc.priv) { | ||
3384 | printk(KERN_WARNING "BCH ECC initialization failed!\n"); | ||
3385 | BUG(); | ||
3386 | } | ||
3387 | break; | ||
3388 | |||
3354 | case NAND_ECC_NONE: | 3389 | case NAND_ECC_NONE: |
3355 | printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " | 3390 | printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " |
3356 | "This is not recommended !!\n"); | 3391 | "This is not recommended !!\n"); |
@@ -3501,6 +3536,9 @@ void nand_release(struct mtd_info *mtd) | |||
3501 | { | 3536 | { |
3502 | struct nand_chip *chip = mtd->priv; | 3537 | struct nand_chip *chip = mtd->priv; |
3503 | 3538 | ||
3539 | if (chip->ecc.mode == NAND_ECC_SOFT_BCH) | ||
3540 | nand_bch_free((struct nand_bch_control *)chip->ecc.priv); | ||
3541 | |||
3504 | #ifdef CONFIG_MTD_PARTITIONS | 3542 | #ifdef CONFIG_MTD_PARTITIONS |
3505 | /* Deregister partitions */ | 3543 | /* Deregister partitions */ |
3506 | del_mtd_partitions(mtd); | 3544 | del_mtd_partitions(mtd); |
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 6ebd869993aa..a1e8b30078d9 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c | |||
@@ -1101,12 +1101,16 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) | |||
1101 | static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) | 1101 | static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) |
1102 | { | 1102 | { |
1103 | struct nand_chip *this = mtd->priv; | 1103 | struct nand_chip *this = mtd->priv; |
1104 | u32 pattern_len = bd->len; | 1104 | u32 pattern_len; |
1105 | u32 bits = bd->options & NAND_BBT_NRBITS_MSK; | 1105 | u32 bits; |
1106 | u32 table_size; | 1106 | u32 table_size; |
1107 | 1107 | ||
1108 | if (!bd) | 1108 | if (!bd) |
1109 | return; | 1109 | return; |
1110 | |||
1111 | pattern_len = bd->len; | ||
1112 | bits = bd->options & NAND_BBT_NRBITS_MSK; | ||
1113 | |||
1110 | BUG_ON((this->options & NAND_USE_FLASH_BBT_NO_OOB) && | 1114 | BUG_ON((this->options & NAND_USE_FLASH_BBT_NO_OOB) && |
1111 | !(this->options & NAND_USE_FLASH_BBT)); | 1115 | !(this->options & NAND_USE_FLASH_BBT)); |
1112 | BUG_ON(!bits); | 1116 | BUG_ON(!bits); |
diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c new file mode 100644 index 000000000000..0f931e757116 --- /dev/null +++ b/drivers/mtd/nand/nand_bch.c | |||
@@ -0,0 +1,243 @@ | |||
1 | /* | ||
2 | * This file provides ECC correction for more than 1 bit per block of data, | ||
3 | * using binary BCH codes. It relies on the generic BCH library lib/bch.c. | ||
4 | * | ||
5 | * Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com> | ||
6 | * | ||
7 | * This file is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 or (at your option) any | ||
10 | * later version. | ||
11 | * | ||
12 | * This file is distributed in the hope that it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
15 | * for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this file; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/types.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/bitops.h> | ||
27 | #include <linux/mtd/mtd.h> | ||
28 | #include <linux/mtd/nand.h> | ||
29 | #include <linux/mtd/nand_bch.h> | ||
30 | #include <linux/bch.h> | ||
31 | |||
32 | /** | ||
33 | * struct nand_bch_control - private NAND BCH control structure | ||
34 | * @bch: BCH control structure | ||
35 | * @ecclayout: private ecc layout for this BCH configuration | ||
36 | * @errloc: error location array | ||
37 | * @eccmask: XOR ecc mask, allows erased pages to be decoded as valid | ||
38 | */ | ||
39 | struct nand_bch_control { | ||
40 | struct bch_control *bch; | ||
41 | struct nand_ecclayout ecclayout; | ||
42 | unsigned int *errloc; | ||
43 | unsigned char *eccmask; | ||
44 | }; | ||
45 | |||
46 | /** | ||
47 | * nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block | ||
48 | * @mtd: MTD block structure | ||
49 | * @buf: input buffer with raw data | ||
50 | * @code: output buffer with ECC | ||
51 | */ | ||
52 | int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf, | ||
53 | unsigned char *code) | ||
54 | { | ||
55 | const struct nand_chip *chip = mtd->priv; | ||
56 | struct nand_bch_control *nbc = chip->ecc.priv; | ||
57 | unsigned int i; | ||
58 | |||
59 | memset(code, 0, chip->ecc.bytes); | ||
60 | encode_bch(nbc->bch, buf, chip->ecc.size, code); | ||
61 | |||
62 | /* apply mask so that an erased page is a valid codeword */ | ||
63 | for (i = 0; i < chip->ecc.bytes; i++) | ||
64 | code[i] ^= nbc->eccmask[i]; | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | EXPORT_SYMBOL(nand_bch_calculate_ecc); | ||
69 | |||
70 | /** | ||
71 | * nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s) | ||
72 | * @mtd: MTD block structure | ||
73 | * @buf: raw data read from the chip | ||
74 | * @read_ecc: ECC from the chip | ||
75 | * @calc_ecc: the ECC calculated from raw data | ||
76 | * | ||
77 | * Detect and correct bit errors for a data byte block | ||
78 | */ | ||
79 | int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, | ||
80 | unsigned char *read_ecc, unsigned char *calc_ecc) | ||
81 | { | ||
82 | const struct nand_chip *chip = mtd->priv; | ||
83 | struct nand_bch_control *nbc = chip->ecc.priv; | ||
84 | unsigned int *errloc = nbc->errloc; | ||
85 | int i, count; | ||
86 | |||
87 | count = decode_bch(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc, | ||
88 | NULL, errloc); | ||
89 | if (count > 0) { | ||
90 | for (i = 0; i < count; i++) { | ||
91 | if (errloc[i] < (chip->ecc.size*8)) | ||
92 | /* error is located in data, correct it */ | ||
93 | buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7)); | ||
94 | /* else error in ecc, no action needed */ | ||
95 | |||
96 | DEBUG(MTD_DEBUG_LEVEL0, "%s: corrected bitflip %u\n", | ||
97 | __func__, errloc[i]); | ||
98 | } | ||
99 | } else if (count < 0) { | ||
100 | printk(KERN_ERR "ecc unrecoverable error\n"); | ||
101 | count = -1; | ||
102 | } | ||
103 | return count; | ||
104 | } | ||
105 | EXPORT_SYMBOL(nand_bch_correct_data); | ||
106 | |||
107 | /** | ||
108 | * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction | ||
109 | * @mtd: MTD block structure | ||
110 | * @eccsize: ecc block size in bytes | ||
111 | * @eccbytes: ecc length in bytes | ||
112 | * @ecclayout: output default layout | ||
113 | * | ||
114 | * Returns: | ||
115 | * a pointer to a new NAND BCH control structure, or NULL upon failure | ||
116 | * | ||
117 | * Initialize NAND BCH error correction. Parameters @eccsize and @eccbytes | ||
118 | * are used to compute BCH parameters m (Galois field order) and t (error | ||
119 | * correction capability). @eccbytes should be equal to the number of bytes | ||
120 | * required to store m*t bits, where m is such that 2^m-1 > @eccsize*8. | ||
121 | * | ||
122 | * Example: to configure 4 bit correction per 512 bytes, you should pass | ||
123 | * @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8) | ||
124 | * @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits) | ||
125 | */ | ||
126 | struct nand_bch_control * | ||
127 | nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes, | ||
128 | struct nand_ecclayout **ecclayout) | ||
129 | { | ||
130 | unsigned int m, t, eccsteps, i; | ||
131 | struct nand_ecclayout *layout; | ||
132 | struct nand_bch_control *nbc = NULL; | ||
133 | unsigned char *erased_page; | ||
134 | |||
135 | if (!eccsize || !eccbytes) { | ||
136 | printk(KERN_WARNING "ecc parameters not supplied\n"); | ||
137 | goto fail; | ||
138 | } | ||
139 | |||
140 | m = fls(1+8*eccsize); | ||
141 | t = (eccbytes*8)/m; | ||
142 | |||
143 | nbc = kzalloc(sizeof(*nbc), GFP_KERNEL); | ||
144 | if (!nbc) | ||
145 | goto fail; | ||
146 | |||
147 | nbc->bch = init_bch(m, t, 0); | ||
148 | if (!nbc->bch) | ||
149 | goto fail; | ||
150 | |||
151 | /* verify that eccbytes has the expected value */ | ||
152 | if (nbc->bch->ecc_bytes != eccbytes) { | ||
153 | printk(KERN_WARNING "invalid eccbytes %u, should be %u\n", | ||
154 | eccbytes, nbc->bch->ecc_bytes); | ||
155 | goto fail; | ||
156 | } | ||
157 | |||
158 | eccsteps = mtd->writesize/eccsize; | ||
159 | |||
160 | /* if no ecc placement scheme was provided, build one */ | ||
161 | if (!*ecclayout) { | ||
162 | |||
163 | /* handle large page devices only */ | ||
164 | if (mtd->oobsize < 64) { | ||
165 | printk(KERN_WARNING "must provide an oob scheme for " | ||
166 | "oobsize %d\n", mtd->oobsize); | ||
167 | goto fail; | ||
168 | } | ||
169 | |||
170 | layout = &nbc->ecclayout; | ||
171 | layout->eccbytes = eccsteps*eccbytes; | ||
172 | |||
173 | /* reserve 2 bytes for bad block marker */ | ||
174 | if (layout->eccbytes+2 > mtd->oobsize) { | ||
175 | printk(KERN_WARNING "no suitable oob scheme available " | ||
176 | "for oobsize %d eccbytes %u\n", mtd->oobsize, | ||
177 | eccbytes); | ||
178 | goto fail; | ||
179 | } | ||
180 | /* put ecc bytes at oob tail */ | ||
181 | for (i = 0; i < layout->eccbytes; i++) | ||
182 | layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i; | ||
183 | |||
184 | layout->oobfree[0].offset = 2; | ||
185 | layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes; | ||
186 | |||
187 | *ecclayout = layout; | ||
188 | } | ||
189 | |||
190 | /* sanity checks */ | ||
191 | if (8*(eccsize+eccbytes) >= (1 << m)) { | ||
192 | printk(KERN_WARNING "eccsize %u is too large\n", eccsize); | ||
193 | goto fail; | ||
194 | } | ||
195 | if ((*ecclayout)->eccbytes != (eccsteps*eccbytes)) { | ||
196 | printk(KERN_WARNING "invalid ecc layout\n"); | ||
197 | goto fail; | ||
198 | } | ||
199 | |||
200 | nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL); | ||
201 | nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL); | ||
202 | if (!nbc->eccmask || !nbc->errloc) | ||
203 | goto fail; | ||
204 | /* | ||
205 | * compute and store the inverted ecc of an erased ecc block | ||
206 | */ | ||
207 | erased_page = kmalloc(eccsize, GFP_KERNEL); | ||
208 | if (!erased_page) | ||
209 | goto fail; | ||
210 | |||
211 | memset(erased_page, 0xff, eccsize); | ||
212 | memset(nbc->eccmask, 0, eccbytes); | ||
213 | encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask); | ||
214 | kfree(erased_page); | ||
215 | |||
216 | for (i = 0; i < eccbytes; i++) | ||
217 | nbc->eccmask[i] ^= 0xff; | ||
218 | |||
219 | return nbc; | ||
220 | fail: | ||
221 | nand_bch_free(nbc); | ||
222 | return NULL; | ||
223 | } | ||
224 | EXPORT_SYMBOL(nand_bch_init); | ||
225 | |||
226 | /** | ||
227 | * nand_bch_free - [NAND Interface] Release NAND BCH ECC resources | ||
228 | * @nbc: NAND BCH control structure | ||
229 | */ | ||
230 | void nand_bch_free(struct nand_bch_control *nbc) | ||
231 | { | ||
232 | if (nbc) { | ||
233 | free_bch(nbc->bch); | ||
234 | kfree(nbc->errloc); | ||
235 | kfree(nbc->eccmask); | ||
236 | kfree(nbc); | ||
237 | } | ||
238 | } | ||
239 | EXPORT_SYMBOL(nand_bch_free); | ||
240 | |||
241 | MODULE_LICENSE("GPL"); | ||
242 | MODULE_AUTHOR("Ivan Djelic <ivan.djelic@parrot.com>"); | ||
243 | MODULE_DESCRIPTION("NAND software BCH ECC support"); | ||
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index a5aa99f014ba..213181be0d9a 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/string.h> | 34 | #include <linux/string.h> |
35 | #include <linux/mtd/mtd.h> | 35 | #include <linux/mtd/mtd.h> |
36 | #include <linux/mtd/nand.h> | 36 | #include <linux/mtd/nand.h> |
37 | #include <linux/mtd/nand_bch.h> | ||
37 | #include <linux/mtd/partitions.h> | 38 | #include <linux/mtd/partitions.h> |
38 | #include <linux/delay.h> | 39 | #include <linux/delay.h> |
39 | #include <linux/list.h> | 40 | #include <linux/list.h> |
@@ -108,6 +109,7 @@ static unsigned int rptwear = 0; | |||
108 | static unsigned int overridesize = 0; | 109 | static unsigned int overridesize = 0; |
109 | static char *cache_file = NULL; | 110 | static char *cache_file = NULL; |
110 | static unsigned int bbt; | 111 | static unsigned int bbt; |
112 | static unsigned int bch; | ||
111 | 113 | ||
112 | module_param(first_id_byte, uint, 0400); | 114 | module_param(first_id_byte, uint, 0400); |
113 | module_param(second_id_byte, uint, 0400); | 115 | module_param(second_id_byte, uint, 0400); |
@@ -132,6 +134,7 @@ module_param(rptwear, uint, 0400); | |||
132 | module_param(overridesize, uint, 0400); | 134 | module_param(overridesize, uint, 0400); |
133 | module_param(cache_file, charp, 0400); | 135 | module_param(cache_file, charp, 0400); |
134 | module_param(bbt, uint, 0400); | 136 | module_param(bbt, uint, 0400); |
137 | module_param(bch, uint, 0400); | ||
135 | 138 | ||
136 | MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); | 139 | MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); |
137 | MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); | 140 | MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); |
@@ -165,6 +168,8 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I | |||
165 | " e.g. 5 means a size of 32 erase blocks"); | 168 | " e.g. 5 means a size of 32 erase blocks"); |
166 | MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory"); | 169 | MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory"); |
167 | MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in data area"); | 170 | MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in data area"); |
171 | MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should " | ||
172 | "be correctable in 512-byte blocks"); | ||
168 | 173 | ||
169 | /* The largest possible page size */ | 174 | /* The largest possible page size */ |
170 | #define NS_LARGEST_PAGE_SIZE 4096 | 175 | #define NS_LARGEST_PAGE_SIZE 4096 |
@@ -2309,7 +2314,43 @@ static int __init ns_init_module(void) | |||
2309 | if ((retval = parse_gravepages()) != 0) | 2314 | if ((retval = parse_gravepages()) != 0) |
2310 | goto error; | 2315 | goto error; |
2311 | 2316 | ||
2312 | if ((retval = nand_scan(nsmtd, 1)) != 0) { | 2317 | retval = nand_scan_ident(nsmtd, 1, NULL); |
2318 | if (retval) { | ||
2319 | NS_ERR("cannot scan NAND Simulator device\n"); | ||
2320 | if (retval > 0) | ||
2321 | retval = -ENXIO; | ||
2322 | goto error; | ||
2323 | } | ||
2324 | |||
2325 | if (bch) { | ||
2326 | unsigned int eccsteps, eccbytes; | ||
2327 | if (!mtd_nand_has_bch()) { | ||
2328 | NS_ERR("BCH ECC support is disabled\n"); | ||
2329 | retval = -EINVAL; | ||
2330 | goto error; | ||
2331 | } | ||
2332 | /* use 512-byte ecc blocks */ | ||
2333 | eccsteps = nsmtd->writesize/512; | ||
2334 | eccbytes = (bch*13+7)/8; | ||
2335 | /* do not bother supporting small page devices */ | ||
2336 | if ((nsmtd->oobsize < 64) || !eccsteps) { | ||
2337 | NS_ERR("bch not available on small page devices\n"); | ||
2338 | retval = -EINVAL; | ||
2339 | goto error; | ||
2340 | } | ||
2341 | if ((eccbytes*eccsteps+2) > nsmtd->oobsize) { | ||
2342 | NS_ERR("invalid bch value %u\n", bch); | ||
2343 | retval = -EINVAL; | ||
2344 | goto error; | ||
2345 | } | ||
2346 | chip->ecc.mode = NAND_ECC_SOFT_BCH; | ||
2347 | chip->ecc.size = 512; | ||
2348 | chip->ecc.bytes = eccbytes; | ||
2349 | NS_INFO("using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size); | ||
2350 | } | ||
2351 | |||
2352 | retval = nand_scan_tail(nsmtd); | ||
2353 | if (retval) { | ||
2313 | NS_ERR("can't register NAND Simulator\n"); | 2354 | NS_ERR("can't register NAND Simulator\n"); |
2314 | if (retval > 0) | 2355 | if (retval > 0) |
2315 | retval = -ENXIO; | 2356 | retval = -ENXIO; |
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 7b8f1fffc528..da9a351c9d79 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c | |||
@@ -668,6 +668,8 @@ static void gen_true_ecc(u8 *ecc_buf) | |||
668 | * | 668 | * |
669 | * This function compares two ECC's and indicates if there is an error. | 669 | * This function compares two ECC's and indicates if there is an error. |
670 | * If the error can be corrected it will be corrected to the buffer. | 670 | * If the error can be corrected it will be corrected to the buffer. |
671 | * If there is no error, %0 is returned. If there is an error but it | ||
672 | * was corrected, %1 is returned. Otherwise, %-1 is returned. | ||
671 | */ | 673 | */ |
672 | static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ | 674 | static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ |
673 | u8 *ecc_data2, /* read from register */ | 675 | u8 *ecc_data2, /* read from register */ |
@@ -773,7 +775,7 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ | |||
773 | 775 | ||
774 | page_data[find_byte] ^= (1 << find_bit); | 776 | page_data[find_byte] ^= (1 << find_bit); |
775 | 777 | ||
776 | return 0; | 778 | return 1; |
777 | default: | 779 | default: |
778 | if (isEccFF) { | 780 | if (isEccFF) { |
779 | if (ecc_data2[0] == 0 && | 781 | if (ecc_data2[0] == 0 && |
@@ -794,8 +796,11 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ | |||
794 | * @calc_ecc: ecc read from HW ECC registers | 796 | * @calc_ecc: ecc read from HW ECC registers |
795 | * | 797 | * |
796 | * Compares the ecc read from nand spare area with ECC registers values | 798 | * Compares the ecc read from nand spare area with ECC registers values |
797 | * and if ECC's mismached, it will call 'omap_compare_ecc' for error detection | 799 | * and if ECC's mismatched, it will call 'omap_compare_ecc' for error |
798 | * and correction. | 800 | * detection and correction. If there are no errors, %0 is returned. If |
801 | * there were errors and all of the errors were corrected, the number of | ||
802 | * corrected errors is returned. If uncorrectable errors exist, %-1 is | ||
803 | * returned. | ||
799 | */ | 804 | */ |
800 | static int omap_correct_data(struct mtd_info *mtd, u_char *dat, | 805 | static int omap_correct_data(struct mtd_info *mtd, u_char *dat, |
801 | u_char *read_ecc, u_char *calc_ecc) | 806 | u_char *read_ecc, u_char *calc_ecc) |
@@ -803,6 +808,7 @@ static int omap_correct_data(struct mtd_info *mtd, u_char *dat, | |||
803 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | 808 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, |
804 | mtd); | 809 | mtd); |
805 | int blockCnt = 0, i = 0, ret = 0; | 810 | int blockCnt = 0, i = 0, ret = 0; |
811 | int stat = 0; | ||
806 | 812 | ||
807 | /* Ex NAND_ECC_HW12_2048 */ | 813 | /* Ex NAND_ECC_HW12_2048 */ |
808 | if ((info->nand.ecc.mode == NAND_ECC_HW) && | 814 | if ((info->nand.ecc.mode == NAND_ECC_HW) && |
@@ -816,12 +822,14 @@ static int omap_correct_data(struct mtd_info *mtd, u_char *dat, | |||
816 | ret = omap_compare_ecc(read_ecc, calc_ecc, dat); | 822 | ret = omap_compare_ecc(read_ecc, calc_ecc, dat); |
817 | if (ret < 0) | 823 | if (ret < 0) |
818 | return ret; | 824 | return ret; |
825 | /* keep track of the number of corrected errors */ | ||
826 | stat += ret; | ||
819 | } | 827 | } |
820 | read_ecc += 3; | 828 | read_ecc += 3; |
821 | calc_ecc += 3; | 829 | calc_ecc += 3; |
822 | dat += 512; | 830 | dat += 512; |
823 | } | 831 | } |
824 | return 0; | 832 | return stat; |
825 | } | 833 | } |
826 | 834 | ||
827 | /** | 835 | /** |
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index ea2c288df3f6..ab7f4c33ced6 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c | |||
@@ -27,6 +27,8 @@ | |||
27 | #include <plat/pxa3xx_nand.h> | 27 | #include <plat/pxa3xx_nand.h> |
28 | 28 | ||
29 | #define CHIP_DELAY_TIMEOUT (2 * HZ/10) | 29 | #define CHIP_DELAY_TIMEOUT (2 * HZ/10) |
30 | #define NAND_STOP_DELAY (2 * HZ/50) | ||
31 | #define PAGE_CHUNK_SIZE (2048) | ||
30 | 32 | ||
31 | /* registers and bit definitions */ | 33 | /* registers and bit definitions */ |
32 | #define NDCR (0x00) /* Control register */ | 34 | #define NDCR (0x00) /* Control register */ |
@@ -52,16 +54,18 @@ | |||
52 | #define NDCR_ND_MODE (0x3 << 21) | 54 | #define NDCR_ND_MODE (0x3 << 21) |
53 | #define NDCR_NAND_MODE (0x0) | 55 | #define NDCR_NAND_MODE (0x0) |
54 | #define NDCR_CLR_PG_CNT (0x1 << 20) | 56 | #define NDCR_CLR_PG_CNT (0x1 << 20) |
55 | #define NDCR_CLR_ECC (0x1 << 19) | 57 | #define NDCR_STOP_ON_UNCOR (0x1 << 19) |
56 | #define NDCR_RD_ID_CNT_MASK (0x7 << 16) | 58 | #define NDCR_RD_ID_CNT_MASK (0x7 << 16) |
57 | #define NDCR_RD_ID_CNT(x) (((x) << 16) & NDCR_RD_ID_CNT_MASK) | 59 | #define NDCR_RD_ID_CNT(x) (((x) << 16) & NDCR_RD_ID_CNT_MASK) |
58 | 60 | ||
59 | #define NDCR_RA_START (0x1 << 15) | 61 | #define NDCR_RA_START (0x1 << 15) |
60 | #define NDCR_PG_PER_BLK (0x1 << 14) | 62 | #define NDCR_PG_PER_BLK (0x1 << 14) |
61 | #define NDCR_ND_ARB_EN (0x1 << 12) | 63 | #define NDCR_ND_ARB_EN (0x1 << 12) |
64 | #define NDCR_INT_MASK (0xFFF) | ||
62 | 65 | ||
63 | #define NDSR_MASK (0xfff) | 66 | #define NDSR_MASK (0xfff) |
64 | #define NDSR_RDY (0x1 << 11) | 67 | #define NDSR_RDY (0x1 << 12) |
68 | #define NDSR_FLASH_RDY (0x1 << 11) | ||
65 | #define NDSR_CS0_PAGED (0x1 << 10) | 69 | #define NDSR_CS0_PAGED (0x1 << 10) |
66 | #define NDSR_CS1_PAGED (0x1 << 9) | 70 | #define NDSR_CS1_PAGED (0x1 << 9) |
67 | #define NDSR_CS0_CMDD (0x1 << 8) | 71 | #define NDSR_CS0_CMDD (0x1 << 8) |
@@ -74,6 +78,7 @@ | |||
74 | #define NDSR_RDDREQ (0x1 << 1) | 78 | #define NDSR_RDDREQ (0x1 << 1) |
75 | #define NDSR_WRCMDREQ (0x1) | 79 | #define NDSR_WRCMDREQ (0x1) |
76 | 80 | ||
81 | #define NDCB0_ST_ROW_EN (0x1 << 26) | ||
77 | #define NDCB0_AUTO_RS (0x1 << 25) | 82 | #define NDCB0_AUTO_RS (0x1 << 25) |
78 | #define NDCB0_CSEL (0x1 << 24) | 83 | #define NDCB0_CSEL (0x1 << 24) |
79 | #define NDCB0_CMD_TYPE_MASK (0x7 << 21) | 84 | #define NDCB0_CMD_TYPE_MASK (0x7 << 21) |
@@ -104,18 +109,21 @@ enum { | |||
104 | }; | 109 | }; |
105 | 110 | ||
106 | enum { | 111 | enum { |
107 | STATE_READY = 0, | 112 | STATE_IDLE = 0, |
108 | STATE_CMD_HANDLE, | 113 | STATE_CMD_HANDLE, |
109 | STATE_DMA_READING, | 114 | STATE_DMA_READING, |
110 | STATE_DMA_WRITING, | 115 | STATE_DMA_WRITING, |
111 | STATE_DMA_DONE, | 116 | STATE_DMA_DONE, |
112 | STATE_PIO_READING, | 117 | STATE_PIO_READING, |
113 | STATE_PIO_WRITING, | 118 | STATE_PIO_WRITING, |
119 | STATE_CMD_DONE, | ||
120 | STATE_READY, | ||
114 | }; | 121 | }; |
115 | 122 | ||
116 | struct pxa3xx_nand_info { | 123 | struct pxa3xx_nand_info { |
117 | struct nand_chip nand_chip; | 124 | struct nand_chip nand_chip; |
118 | 125 | ||
126 | struct nand_hw_control controller; | ||
119 | struct platform_device *pdev; | 127 | struct platform_device *pdev; |
120 | struct pxa3xx_nand_cmdset *cmdset; | 128 | struct pxa3xx_nand_cmdset *cmdset; |
121 | 129 | ||
@@ -126,6 +134,7 @@ struct pxa3xx_nand_info { | |||
126 | unsigned int buf_start; | 134 | unsigned int buf_start; |
127 | unsigned int buf_count; | 135 | unsigned int buf_count; |
128 | 136 | ||
137 | struct mtd_info *mtd; | ||
129 | /* DMA information */ | 138 | /* DMA information */ |
130 | int drcmr_dat; | 139 | int drcmr_dat; |
131 | int drcmr_cmd; | 140 | int drcmr_cmd; |
@@ -149,6 +158,7 @@ struct pxa3xx_nand_info { | |||
149 | 158 | ||
150 | int use_ecc; /* use HW ECC ? */ | 159 | int use_ecc; /* use HW ECC ? */ |
151 | int use_dma; /* use DMA ? */ | 160 | int use_dma; /* use DMA ? */ |
161 | int is_ready; | ||
152 | 162 | ||
153 | unsigned int page_size; /* page size of attached chip */ | 163 | unsigned int page_size; /* page size of attached chip */ |
154 | unsigned int data_size; /* data size in FIFO */ | 164 | unsigned int data_size; /* data size in FIFO */ |
@@ -201,20 +211,22 @@ static struct pxa3xx_nand_timing timing[] = { | |||
201 | }; | 211 | }; |
202 | 212 | ||
203 | static struct pxa3xx_nand_flash builtin_flash_types[] = { | 213 | static struct pxa3xx_nand_flash builtin_flash_types[] = { |
204 | { 0, 0, 2048, 8, 8, 0, &default_cmdset, &timing[0] }, | 214 | { "DEFAULT FLASH", 0, 0, 2048, 8, 8, 0, &timing[0] }, |
205 | { 0x46ec, 32, 512, 16, 16, 4096, &default_cmdset, &timing[1] }, | 215 | { "64MiB 16-bit", 0x46ec, 32, 512, 16, 16, 4096, &timing[1] }, |
206 | { 0xdaec, 64, 2048, 8, 8, 2048, &default_cmdset, &timing[1] }, | 216 | { "256MiB 8-bit", 0xdaec, 64, 2048, 8, 8, 2048, &timing[1] }, |
207 | { 0xd7ec, 128, 4096, 8, 8, 8192, &default_cmdset, &timing[1] }, | 217 | { "4GiB 8-bit", 0xd7ec, 128, 4096, 8, 8, 8192, &timing[1] }, |
208 | { 0xa12c, 64, 2048, 8, 8, 1024, &default_cmdset, &timing[2] }, | 218 | { "128MiB 8-bit", 0xa12c, 64, 2048, 8, 8, 1024, &timing[2] }, |
209 | { 0xb12c, 64, 2048, 16, 16, 1024, &default_cmdset, &timing[2] }, | 219 | { "128MiB 16-bit", 0xb12c, 64, 2048, 16, 16, 1024, &timing[2] }, |
210 | { 0xdc2c, 64, 2048, 8, 8, 4096, &default_cmdset, &timing[2] }, | 220 | { "512MiB 8-bit", 0xdc2c, 64, 2048, 8, 8, 4096, &timing[2] }, |
211 | { 0xcc2c, 64, 2048, 16, 16, 4096, &default_cmdset, &timing[2] }, | 221 | { "512MiB 16-bit", 0xcc2c, 64, 2048, 16, 16, 4096, &timing[2] }, |
212 | { 0xba20, 64, 2048, 16, 16, 2048, &default_cmdset, &timing[3] }, | 222 | { "256MiB 16-bit", 0xba20, 64, 2048, 16, 16, 2048, &timing[3] }, |
213 | }; | 223 | }; |
214 | 224 | ||
215 | /* Define a default flash type setting serve as flash detecting only */ | 225 | /* Define a default flash type setting serve as flash detecting only */ |
216 | #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) | 226 | #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) |
217 | 227 | ||
228 | const char *mtd_names[] = {"pxa3xx_nand-0", NULL}; | ||
229 | |||
218 | #define NDTR0_tCH(c) (min((c), 7) << 19) | 230 | #define NDTR0_tCH(c) (min((c), 7) << 19) |
219 | #define NDTR0_tCS(c) (min((c), 7) << 16) | 231 | #define NDTR0_tCS(c) (min((c), 7) << 16) |
220 | #define NDTR0_tWH(c) (min((c), 7) << 11) | 232 | #define NDTR0_tWH(c) (min((c), 7) << 11) |
@@ -252,25 +264,6 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, | |||
252 | nand_writel(info, NDTR1CS0, ndtr1); | 264 | nand_writel(info, NDTR1CS0, ndtr1); |
253 | } | 265 | } |
254 | 266 | ||
255 | #define WAIT_EVENT_TIMEOUT 10 | ||
256 | |||
257 | static int wait_for_event(struct pxa3xx_nand_info *info, uint32_t event) | ||
258 | { | ||
259 | int timeout = WAIT_EVENT_TIMEOUT; | ||
260 | uint32_t ndsr; | ||
261 | |||
262 | while (timeout--) { | ||
263 | ndsr = nand_readl(info, NDSR) & NDSR_MASK; | ||
264 | if (ndsr & event) { | ||
265 | nand_writel(info, NDSR, ndsr); | ||
266 | return 0; | ||
267 | } | ||
268 | udelay(10); | ||
269 | } | ||
270 | |||
271 | return -ETIMEDOUT; | ||
272 | } | ||
273 | |||
274 | static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) | 267 | static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) |
275 | { | 268 | { |
276 | int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; | 269 | int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; |
@@ -291,69 +284,45 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) | |||
291 | } | 284 | } |
292 | } | 285 | } |
293 | 286 | ||
294 | static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info, | 287 | /** |
295 | uint16_t cmd, int column, int page_addr) | 288 | * NOTE: it is a must to set ND_RUN firstly, then write |
289 | * command buffer, otherwise, it does not work. | ||
290 | * We enable all the interrupt at the same time, and | ||
291 | * let pxa3xx_nand_irq to handle all logic. | ||
292 | */ | ||
293 | static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) | ||
296 | { | 294 | { |
297 | const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; | 295 | uint32_t ndcr; |
298 | pxa3xx_set_datasize(info); | ||
299 | |||
300 | /* generate values for NDCBx registers */ | ||
301 | info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); | ||
302 | info->ndcb1 = 0; | ||
303 | info->ndcb2 = 0; | ||
304 | info->ndcb0 |= NDCB0_ADDR_CYC(info->row_addr_cycles + info->col_addr_cycles); | ||
305 | |||
306 | if (info->col_addr_cycles == 2) { | ||
307 | /* large block, 2 cycles for column address | ||
308 | * row address starts from 3rd cycle | ||
309 | */ | ||
310 | info->ndcb1 |= page_addr << 16; | ||
311 | if (info->row_addr_cycles == 3) | ||
312 | info->ndcb2 = (page_addr >> 16) & 0xff; | ||
313 | } else | ||
314 | /* small block, 1 cycles for column address | ||
315 | * row address starts from 2nd cycle | ||
316 | */ | ||
317 | info->ndcb1 = page_addr << 8; | ||
318 | |||
319 | if (cmd == cmdset->program) | ||
320 | info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS; | ||
321 | 296 | ||
322 | return 0; | 297 | ndcr = info->reg_ndcr; |
323 | } | 298 | ndcr |= info->use_ecc ? NDCR_ECC_EN : 0; |
299 | ndcr |= info->use_dma ? NDCR_DMA_EN : 0; | ||
300 | ndcr |= NDCR_ND_RUN; | ||
324 | 301 | ||
325 | static int prepare_erase_cmd(struct pxa3xx_nand_info *info, | 302 | /* clear status bits and run */ |
326 | uint16_t cmd, int page_addr) | 303 | nand_writel(info, NDCR, 0); |
327 | { | 304 | nand_writel(info, NDSR, NDSR_MASK); |
328 | info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); | 305 | nand_writel(info, NDCR, ndcr); |
329 | info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3); | ||
330 | info->ndcb1 = page_addr; | ||
331 | info->ndcb2 = 0; | ||
332 | return 0; | ||
333 | } | 306 | } |
334 | 307 | ||
335 | static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd) | 308 | static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info) |
336 | { | 309 | { |
337 | const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; | 310 | uint32_t ndcr; |
338 | 311 | int timeout = NAND_STOP_DELAY; | |
339 | info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); | ||
340 | info->ndcb1 = 0; | ||
341 | info->ndcb2 = 0; | ||
342 | 312 | ||
343 | info->oob_size = 0; | 313 | /* wait RUN bit in NDCR become 0 */ |
344 | if (cmd == cmdset->read_id) { | 314 | ndcr = nand_readl(info, NDCR); |
345 | info->ndcb0 |= NDCB0_CMD_TYPE(3); | 315 | while ((ndcr & NDCR_ND_RUN) && (timeout-- > 0)) { |
346 | info->data_size = 8; | 316 | ndcr = nand_readl(info, NDCR); |
347 | } else if (cmd == cmdset->read_status) { | 317 | udelay(1); |
348 | info->ndcb0 |= NDCB0_CMD_TYPE(4); | 318 | } |
349 | info->data_size = 8; | ||
350 | } else if (cmd == cmdset->reset || cmd == cmdset->lock || | ||
351 | cmd == cmdset->unlock) { | ||
352 | info->ndcb0 |= NDCB0_CMD_TYPE(5); | ||
353 | } else | ||
354 | return -EINVAL; | ||
355 | 319 | ||
356 | return 0; | 320 | if (timeout <= 0) { |
321 | ndcr &= ~NDCR_ND_RUN; | ||
322 | nand_writel(info, NDCR, ndcr); | ||
323 | } | ||
324 | /* clear status bits */ | ||
325 | nand_writel(info, NDSR, NDSR_MASK); | ||
357 | } | 326 | } |
358 | 327 | ||
359 | static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) | 328 | static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) |
@@ -372,39 +341,8 @@ static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) | |||
372 | nand_writel(info, NDCR, ndcr | int_mask); | 341 | nand_writel(info, NDCR, ndcr | int_mask); |
373 | } | 342 | } |
374 | 343 | ||
375 | /* NOTE: it is a must to set ND_RUN firstly, then write command buffer | 344 | static void handle_data_pio(struct pxa3xx_nand_info *info) |
376 | * otherwise, it does not work | ||
377 | */ | ||
378 | static int write_cmd(struct pxa3xx_nand_info *info) | ||
379 | { | 345 | { |
380 | uint32_t ndcr; | ||
381 | |||
382 | /* clear status bits and run */ | ||
383 | nand_writel(info, NDSR, NDSR_MASK); | ||
384 | |||
385 | ndcr = info->reg_ndcr; | ||
386 | |||
387 | ndcr |= info->use_ecc ? NDCR_ECC_EN : 0; | ||
388 | ndcr |= info->use_dma ? NDCR_DMA_EN : 0; | ||
389 | ndcr |= NDCR_ND_RUN; | ||
390 | |||
391 | nand_writel(info, NDCR, ndcr); | ||
392 | |||
393 | if (wait_for_event(info, NDSR_WRCMDREQ)) { | ||
394 | printk(KERN_ERR "timed out writing command\n"); | ||
395 | return -ETIMEDOUT; | ||
396 | } | ||
397 | |||
398 | nand_writel(info, NDCB0, info->ndcb0); | ||
399 | nand_writel(info, NDCB0, info->ndcb1); | ||
400 | nand_writel(info, NDCB0, info->ndcb2); | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static int handle_data_pio(struct pxa3xx_nand_info *info) | ||
405 | { | ||
406 | int ret, timeout = CHIP_DELAY_TIMEOUT; | ||
407 | |||
408 | switch (info->state) { | 346 | switch (info->state) { |
409 | case STATE_PIO_WRITING: | 347 | case STATE_PIO_WRITING: |
410 | __raw_writesl(info->mmio_base + NDDB, info->data_buff, | 348 | __raw_writesl(info->mmio_base + NDDB, info->data_buff, |
@@ -412,14 +350,6 @@ static int handle_data_pio(struct pxa3xx_nand_info *info) | |||
412 | if (info->oob_size > 0) | 350 | if (info->oob_size > 0) |
413 | __raw_writesl(info->mmio_base + NDDB, info->oob_buff, | 351 | __raw_writesl(info->mmio_base + NDDB, info->oob_buff, |
414 | DIV_ROUND_UP(info->oob_size, 4)); | 352 | DIV_ROUND_UP(info->oob_size, 4)); |
415 | |||
416 | enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD); | ||
417 | |||
418 | ret = wait_for_completion_timeout(&info->cmd_complete, timeout); | ||
419 | if (!ret) { | ||
420 | printk(KERN_ERR "program command time out\n"); | ||
421 | return -1; | ||
422 | } | ||
423 | break; | 353 | break; |
424 | case STATE_PIO_READING: | 354 | case STATE_PIO_READING: |
425 | __raw_readsl(info->mmio_base + NDDB, info->data_buff, | 355 | __raw_readsl(info->mmio_base + NDDB, info->data_buff, |
@@ -431,14 +361,11 @@ static int handle_data_pio(struct pxa3xx_nand_info *info) | |||
431 | default: | 361 | default: |
432 | printk(KERN_ERR "%s: invalid state %d\n", __func__, | 362 | printk(KERN_ERR "%s: invalid state %d\n", __func__, |
433 | info->state); | 363 | info->state); |
434 | return -EINVAL; | 364 | BUG(); |
435 | } | 365 | } |
436 | |||
437 | info->state = STATE_READY; | ||
438 | return 0; | ||
439 | } | 366 | } |
440 | 367 | ||
441 | static void start_data_dma(struct pxa3xx_nand_info *info, int dir_out) | 368 | static void start_data_dma(struct pxa3xx_nand_info *info) |
442 | { | 369 | { |
443 | struct pxa_dma_desc *desc = info->data_desc; | 370 | struct pxa_dma_desc *desc = info->data_desc; |
444 | int dma_len = ALIGN(info->data_size + info->oob_size, 32); | 371 | int dma_len = ALIGN(info->data_size + info->oob_size, 32); |
@@ -446,14 +373,21 @@ static void start_data_dma(struct pxa3xx_nand_info *info, int dir_out) | |||
446 | desc->ddadr = DDADR_STOP; | 373 | desc->ddadr = DDADR_STOP; |
447 | desc->dcmd = DCMD_ENDIRQEN | DCMD_WIDTH4 | DCMD_BURST32 | dma_len; | 374 | desc->dcmd = DCMD_ENDIRQEN | DCMD_WIDTH4 | DCMD_BURST32 | dma_len; |
448 | 375 | ||
449 | if (dir_out) { | 376 | switch (info->state) { |
377 | case STATE_DMA_WRITING: | ||
450 | desc->dsadr = info->data_buff_phys; | 378 | desc->dsadr = info->data_buff_phys; |
451 | desc->dtadr = info->mmio_phys + NDDB; | 379 | desc->dtadr = info->mmio_phys + NDDB; |
452 | desc->dcmd |= DCMD_INCSRCADDR | DCMD_FLOWTRG; | 380 | desc->dcmd |= DCMD_INCSRCADDR | DCMD_FLOWTRG; |
453 | } else { | 381 | break; |
382 | case STATE_DMA_READING: | ||
454 | desc->dtadr = info->data_buff_phys; | 383 | desc->dtadr = info->data_buff_phys; |
455 | desc->dsadr = info->mmio_phys + NDDB; | 384 | desc->dsadr = info->mmio_phys + NDDB; |
456 | desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC; | 385 | desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC; |
386 | break; | ||
387 | default: | ||
388 | printk(KERN_ERR "%s: invalid state %d\n", __func__, | ||
389 | info->state); | ||
390 | BUG(); | ||
457 | } | 391 | } |
458 | 392 | ||
459 | DRCMR(info->drcmr_dat) = DRCMR_MAPVLD | info->data_dma_ch; | 393 | DRCMR(info->drcmr_dat) = DRCMR_MAPVLD | info->data_dma_ch; |
@@ -471,93 +405,62 @@ static void pxa3xx_nand_data_dma_irq(int channel, void *data) | |||
471 | 405 | ||
472 | if (dcsr & DCSR_BUSERR) { | 406 | if (dcsr & DCSR_BUSERR) { |
473 | info->retcode = ERR_DMABUSERR; | 407 | info->retcode = ERR_DMABUSERR; |
474 | complete(&info->cmd_complete); | ||
475 | } | 408 | } |
476 | 409 | ||
477 | if (info->state == STATE_DMA_WRITING) { | 410 | info->state = STATE_DMA_DONE; |
478 | info->state = STATE_DMA_DONE; | 411 | enable_int(info, NDCR_INT_MASK); |
479 | enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD); | 412 | nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ); |
480 | } else { | ||
481 | info->state = STATE_READY; | ||
482 | complete(&info->cmd_complete); | ||
483 | } | ||
484 | } | 413 | } |
485 | 414 | ||
486 | static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) | 415 | static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) |
487 | { | 416 | { |
488 | struct pxa3xx_nand_info *info = devid; | 417 | struct pxa3xx_nand_info *info = devid; |
489 | unsigned int status; | 418 | unsigned int status, is_completed = 0; |
490 | 419 | ||
491 | status = nand_readl(info, NDSR); | 420 | status = nand_readl(info, NDSR); |
492 | 421 | ||
493 | if (status & (NDSR_RDDREQ | NDSR_DBERR | NDSR_SBERR)) { | 422 | if (status & NDSR_DBERR) |
494 | if (status & NDSR_DBERR) | 423 | info->retcode = ERR_DBERR; |
495 | info->retcode = ERR_DBERR; | 424 | if (status & NDSR_SBERR) |
496 | else if (status & NDSR_SBERR) | 425 | info->retcode = ERR_SBERR; |
497 | info->retcode = ERR_SBERR; | 426 | if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) { |
498 | 427 | /* whether use dma to transfer data */ | |
499 | disable_int(info, NDSR_RDDREQ | NDSR_DBERR | NDSR_SBERR); | ||
500 | |||
501 | if (info->use_dma) { | ||
502 | info->state = STATE_DMA_READING; | ||
503 | start_data_dma(info, 0); | ||
504 | } else { | ||
505 | info->state = STATE_PIO_READING; | ||
506 | complete(&info->cmd_complete); | ||
507 | } | ||
508 | } else if (status & NDSR_WRDREQ) { | ||
509 | disable_int(info, NDSR_WRDREQ); | ||
510 | if (info->use_dma) { | 428 | if (info->use_dma) { |
511 | info->state = STATE_DMA_WRITING; | 429 | disable_int(info, NDCR_INT_MASK); |
512 | start_data_dma(info, 1); | 430 | info->state = (status & NDSR_RDDREQ) ? |
431 | STATE_DMA_READING : STATE_DMA_WRITING; | ||
432 | start_data_dma(info); | ||
433 | goto NORMAL_IRQ_EXIT; | ||
513 | } else { | 434 | } else { |
514 | info->state = STATE_PIO_WRITING; | 435 | info->state = (status & NDSR_RDDREQ) ? |
515 | complete(&info->cmd_complete); | 436 | STATE_PIO_READING : STATE_PIO_WRITING; |
437 | handle_data_pio(info); | ||
516 | } | 438 | } |
517 | } else if (status & (NDSR_CS0_BBD | NDSR_CS0_CMDD)) { | ||
518 | if (status & NDSR_CS0_BBD) | ||
519 | info->retcode = ERR_BBERR; | ||
520 | |||
521 | disable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD); | ||
522 | info->state = STATE_READY; | ||
523 | complete(&info->cmd_complete); | ||
524 | } | 439 | } |
525 | nand_writel(info, NDSR, status); | 440 | if (status & NDSR_CS0_CMDD) { |
526 | return IRQ_HANDLED; | 441 | info->state = STATE_CMD_DONE; |
527 | } | 442 | is_completed = 1; |
528 | |||
529 | static int pxa3xx_nand_do_cmd(struct pxa3xx_nand_info *info, uint32_t event) | ||
530 | { | ||
531 | uint32_t ndcr; | ||
532 | int ret, timeout = CHIP_DELAY_TIMEOUT; | ||
533 | |||
534 | if (write_cmd(info)) { | ||
535 | info->retcode = ERR_SENDCMD; | ||
536 | goto fail_stop; | ||
537 | } | 443 | } |
538 | 444 | if (status & NDSR_FLASH_RDY) { | |
539 | info->state = STATE_CMD_HANDLE; | 445 | info->is_ready = 1; |
540 | 446 | info->state = STATE_READY; | |
541 | enable_int(info, event); | ||
542 | |||
543 | ret = wait_for_completion_timeout(&info->cmd_complete, timeout); | ||
544 | if (!ret) { | ||
545 | printk(KERN_ERR "command execution timed out\n"); | ||
546 | info->retcode = ERR_SENDCMD; | ||
547 | goto fail_stop; | ||
548 | } | 447 | } |
549 | 448 | ||
550 | if (info->use_dma == 0 && info->data_size > 0) | 449 | if (status & NDSR_WRCMDREQ) { |
551 | if (handle_data_pio(info)) | 450 | nand_writel(info, NDSR, NDSR_WRCMDREQ); |
552 | goto fail_stop; | 451 | status &= ~NDSR_WRCMDREQ; |
553 | 452 | info->state = STATE_CMD_HANDLE; | |
554 | return 0; | 453 | nand_writel(info, NDCB0, info->ndcb0); |
454 | nand_writel(info, NDCB0, info->ndcb1); | ||
455 | nand_writel(info, NDCB0, info->ndcb2); | ||
456 | } | ||
555 | 457 | ||
556 | fail_stop: | 458 | /* clear NDSR to let the controller exit the IRQ */ |
557 | ndcr = nand_readl(info, NDCR); | 459 | nand_writel(info, NDSR, status); |
558 | nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN); | 460 | if (is_completed) |
559 | udelay(10); | 461 | complete(&info->cmd_complete); |
560 | return -ETIMEDOUT; | 462 | NORMAL_IRQ_EXIT: |
463 | return IRQ_HANDLED; | ||
561 | } | 464 | } |
562 | 465 | ||
563 | static int pxa3xx_nand_dev_ready(struct mtd_info *mtd) | 466 | static int pxa3xx_nand_dev_ready(struct mtd_info *mtd) |
@@ -574,125 +477,218 @@ static inline int is_buf_blank(uint8_t *buf, size_t len) | |||
574 | return 1; | 477 | return 1; |
575 | } | 478 | } |
576 | 479 | ||
577 | static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, | 480 | static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, |
578 | int column, int page_addr) | 481 | uint16_t column, int page_addr) |
579 | { | 482 | { |
580 | struct pxa3xx_nand_info *info = mtd->priv; | 483 | uint16_t cmd; |
581 | const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; | 484 | int addr_cycle, exec_cmd, ndcb0; |
582 | int ret; | 485 | struct mtd_info *mtd = info->mtd; |
486 | |||
487 | ndcb0 = 0; | ||
488 | addr_cycle = 0; | ||
489 | exec_cmd = 1; | ||
490 | |||
491 | /* reset data and oob column point to handle data */ | ||
492 | info->buf_start = 0; | ||
493 | info->buf_count = 0; | ||
494 | info->oob_size = 0; | ||
495 | info->use_ecc = 0; | ||
496 | info->is_ready = 0; | ||
497 | info->retcode = ERR_NONE; | ||
583 | 498 | ||
584 | info->use_dma = (use_dma) ? 1 : 0; | 499 | switch (command) { |
585 | info->use_ecc = 0; | 500 | case NAND_CMD_READ0: |
586 | info->data_size = 0; | 501 | case NAND_CMD_PAGEPROG: |
587 | info->state = STATE_READY; | 502 | info->use_ecc = 1; |
503 | case NAND_CMD_READOOB: | ||
504 | pxa3xx_set_datasize(info); | ||
505 | break; | ||
506 | case NAND_CMD_SEQIN: | ||
507 | exec_cmd = 0; | ||
508 | break; | ||
509 | default: | ||
510 | info->ndcb1 = 0; | ||
511 | info->ndcb2 = 0; | ||
512 | break; | ||
513 | } | ||
588 | 514 | ||
589 | init_completion(&info->cmd_complete); | 515 | info->ndcb0 = ndcb0; |
516 | addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles | ||
517 | + info->col_addr_cycles); | ||
590 | 518 | ||
591 | switch (command) { | 519 | switch (command) { |
592 | case NAND_CMD_READOOB: | 520 | case NAND_CMD_READOOB: |
593 | /* disable HW ECC to get all the OOB data */ | 521 | case NAND_CMD_READ0: |
594 | info->buf_count = mtd->writesize + mtd->oobsize; | 522 | cmd = info->cmdset->read1; |
595 | info->buf_start = mtd->writesize + column; | 523 | if (command == NAND_CMD_READOOB) |
596 | memset(info->data_buff, 0xFF, info->buf_count); | 524 | info->buf_start = mtd->writesize + column; |
525 | else | ||
526 | info->buf_start = column; | ||
597 | 527 | ||
598 | if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr)) | 528 | if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) |
599 | break; | 529 | info->ndcb0 |= NDCB0_CMD_TYPE(0) |
530 | | addr_cycle | ||
531 | | (cmd & NDCB0_CMD1_MASK); | ||
532 | else | ||
533 | info->ndcb0 |= NDCB0_CMD_TYPE(0) | ||
534 | | NDCB0_DBC | ||
535 | | addr_cycle | ||
536 | | cmd; | ||
600 | 537 | ||
601 | pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR | NDSR_SBERR); | 538 | case NAND_CMD_SEQIN: |
539 | /* small page addr setting */ | ||
540 | if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) { | ||
541 | info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) | ||
542 | | (column & 0xFF); | ||
602 | 543 | ||
603 | /* We only are OOB, so if the data has error, does not matter */ | 544 | info->ndcb2 = 0; |
604 | if (info->retcode == ERR_DBERR) | 545 | } else { |
605 | info->retcode = ERR_NONE; | 546 | info->ndcb1 = ((page_addr & 0xFFFF) << 16) |
606 | break; | 547 | | (column & 0xFFFF); |
548 | |||
549 | if (page_addr & 0xFF0000) | ||
550 | info->ndcb2 = (page_addr & 0xFF0000) >> 16; | ||
551 | else | ||
552 | info->ndcb2 = 0; | ||
553 | } | ||
607 | 554 | ||
608 | case NAND_CMD_READ0: | ||
609 | info->use_ecc = 1; | ||
610 | info->retcode = ERR_NONE; | ||
611 | info->buf_start = column; | ||
612 | info->buf_count = mtd->writesize + mtd->oobsize; | 555 | info->buf_count = mtd->writesize + mtd->oobsize; |
613 | memset(info->data_buff, 0xFF, info->buf_count); | 556 | memset(info->data_buff, 0xFF, info->buf_count); |
614 | 557 | ||
615 | if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr)) | 558 | break; |
559 | |||
560 | case NAND_CMD_PAGEPROG: | ||
561 | if (is_buf_blank(info->data_buff, | ||
562 | (mtd->writesize + mtd->oobsize))) { | ||
563 | exec_cmd = 0; | ||
616 | break; | 564 | break; |
565 | } | ||
617 | 566 | ||
618 | pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR | NDSR_SBERR); | 567 | cmd = info->cmdset->program; |
568 | info->ndcb0 |= NDCB0_CMD_TYPE(0x1) | ||
569 | | NDCB0_AUTO_RS | ||
570 | | NDCB0_ST_ROW_EN | ||
571 | | NDCB0_DBC | ||
572 | | cmd | ||
573 | | addr_cycle; | ||
574 | break; | ||
619 | 575 | ||
620 | if (info->retcode == ERR_DBERR) { | 576 | case NAND_CMD_READID: |
621 | /* for blank page (all 0xff), HW will calculate its ECC as | 577 | cmd = info->cmdset->read_id; |
622 | * 0, which is different from the ECC information within | 578 | info->buf_count = info->read_id_bytes; |
623 | * OOB, ignore such double bit errors | 579 | info->ndcb0 |= NDCB0_CMD_TYPE(3) |
624 | */ | 580 | | NDCB0_ADDR_CYC(1) |
625 | if (is_buf_blank(info->data_buff, mtd->writesize)) | 581 | | cmd; |
626 | info->retcode = ERR_NONE; | 582 | |
627 | } | 583 | info->data_size = 8; |
628 | break; | 584 | break; |
629 | case NAND_CMD_SEQIN: | 585 | case NAND_CMD_STATUS: |
630 | info->buf_start = column; | 586 | cmd = info->cmdset->read_status; |
631 | info->buf_count = mtd->writesize + mtd->oobsize; | 587 | info->buf_count = 1; |
632 | memset(info->data_buff, 0xff, info->buf_count); | 588 | info->ndcb0 |= NDCB0_CMD_TYPE(4) |
589 | | NDCB0_ADDR_CYC(1) | ||
590 | | cmd; | ||
633 | 591 | ||
634 | /* save column/page_addr for next CMD_PAGEPROG */ | 592 | info->data_size = 8; |
635 | info->seqin_column = column; | ||
636 | info->seqin_page_addr = page_addr; | ||
637 | break; | 593 | break; |
638 | case NAND_CMD_PAGEPROG: | ||
639 | info->use_ecc = (info->seqin_column >= mtd->writesize) ? 0 : 1; | ||
640 | 594 | ||
641 | if (prepare_read_prog_cmd(info, cmdset->program, | 595 | case NAND_CMD_ERASE1: |
642 | info->seqin_column, info->seqin_page_addr)) | 596 | cmd = info->cmdset->erase; |
643 | break; | 597 | info->ndcb0 |= NDCB0_CMD_TYPE(2) |
598 | | NDCB0_AUTO_RS | ||
599 | | NDCB0_ADDR_CYC(3) | ||
600 | | NDCB0_DBC | ||
601 | | cmd; | ||
602 | info->ndcb1 = page_addr; | ||
603 | info->ndcb2 = 0; | ||
644 | 604 | ||
645 | pxa3xx_nand_do_cmd(info, NDSR_WRDREQ); | ||
646 | break; | 605 | break; |
647 | case NAND_CMD_ERASE1: | 606 | case NAND_CMD_RESET: |
648 | if (prepare_erase_cmd(info, cmdset->erase, page_addr)) | 607 | cmd = info->cmdset->reset; |
649 | break; | 608 | info->ndcb0 |= NDCB0_CMD_TYPE(5) |
609 | | cmd; | ||
650 | 610 | ||
651 | pxa3xx_nand_do_cmd(info, NDSR_CS0_BBD | NDSR_CS0_CMDD); | ||
652 | break; | 611 | break; |
612 | |||
653 | case NAND_CMD_ERASE2: | 613 | case NAND_CMD_ERASE2: |
614 | exec_cmd = 0; | ||
654 | break; | 615 | break; |
655 | case NAND_CMD_READID: | ||
656 | case NAND_CMD_STATUS: | ||
657 | info->use_dma = 0; /* force PIO read */ | ||
658 | info->buf_start = 0; | ||
659 | info->buf_count = (command == NAND_CMD_READID) ? | ||
660 | info->read_id_bytes : 1; | ||
661 | |||
662 | if (prepare_other_cmd(info, (command == NAND_CMD_READID) ? | ||
663 | cmdset->read_id : cmdset->read_status)) | ||
664 | break; | ||
665 | 616 | ||
666 | pxa3xx_nand_do_cmd(info, NDSR_RDDREQ); | 617 | default: |
618 | exec_cmd = 0; | ||
619 | printk(KERN_ERR "pxa3xx-nand: non-supported" | ||
620 | " command %x\n", command); | ||
667 | break; | 621 | break; |
668 | case NAND_CMD_RESET: | 622 | } |
669 | if (prepare_other_cmd(info, cmdset->reset)) | ||
670 | break; | ||
671 | 623 | ||
672 | ret = pxa3xx_nand_do_cmd(info, NDSR_CS0_CMDD); | 624 | return exec_cmd; |
673 | if (ret == 0) { | 625 | } |
674 | int timeout = 2; | ||
675 | uint32_t ndcr; | ||
676 | 626 | ||
677 | while (timeout--) { | 627 | static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, |
678 | if (nand_readl(info, NDSR) & NDSR_RDY) | 628 | int column, int page_addr) |
679 | break; | 629 | { |
680 | msleep(10); | 630 | struct pxa3xx_nand_info *info = mtd->priv; |
681 | } | 631 | int ret, exec_cmd; |
682 | 632 | ||
683 | ndcr = nand_readl(info, NDCR); | 633 | /* |
684 | nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN); | 634 | * if this is a x16 device ,then convert the input |
635 | * "byte" address into a "word" address appropriate | ||
636 | * for indexing a word-oriented device | ||
637 | */ | ||
638 | if (info->reg_ndcr & NDCR_DWIDTH_M) | ||
639 | column /= 2; | ||
640 | |||
641 | exec_cmd = prepare_command_pool(info, command, column, page_addr); | ||
642 | if (exec_cmd) { | ||
643 | init_completion(&info->cmd_complete); | ||
644 | pxa3xx_nand_start(info); | ||
645 | |||
646 | ret = wait_for_completion_timeout(&info->cmd_complete, | ||
647 | CHIP_DELAY_TIMEOUT); | ||
648 | if (!ret) { | ||
649 | printk(KERN_ERR "Wait time out!!!\n"); | ||
650 | /* Stop State Machine for next command cycle */ | ||
651 | pxa3xx_nand_stop(info); | ||
685 | } | 652 | } |
686 | break; | 653 | info->state = STATE_IDLE; |
687 | default: | ||
688 | printk(KERN_ERR "non-supported command.\n"); | ||
689 | break; | ||
690 | } | 654 | } |
655 | } | ||
656 | |||
657 | static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, | ||
658 | struct nand_chip *chip, const uint8_t *buf) | ||
659 | { | ||
660 | chip->write_buf(mtd, buf, mtd->writesize); | ||
661 | chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
662 | } | ||
691 | 663 | ||
692 | if (info->retcode == ERR_DBERR) { | 664 | static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, |
693 | printk(KERN_ERR "double bit error @ page %08x\n", page_addr); | 665 | struct nand_chip *chip, uint8_t *buf, int page) |
694 | info->retcode = ERR_NONE; | 666 | { |
667 | struct pxa3xx_nand_info *info = mtd->priv; | ||
668 | |||
669 | chip->read_buf(mtd, buf, mtd->writesize); | ||
670 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
671 | |||
672 | if (info->retcode == ERR_SBERR) { | ||
673 | switch (info->use_ecc) { | ||
674 | case 1: | ||
675 | mtd->ecc_stats.corrected++; | ||
676 | break; | ||
677 | case 0: | ||
678 | default: | ||
679 | break; | ||
680 | } | ||
681 | } else if (info->retcode == ERR_DBERR) { | ||
682 | /* | ||
683 | * for blank page (all 0xff), HW will calculate its ECC as | ||
684 | * 0, which is different from the ECC information within | ||
685 | * OOB, ignore such double bit errors | ||
686 | */ | ||
687 | if (is_buf_blank(buf, mtd->writesize)) | ||
688 | mtd->ecc_stats.failed++; | ||
695 | } | 689 | } |
690 | |||
691 | return 0; | ||
696 | } | 692 | } |
697 | 693 | ||
698 | static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) | 694 | static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) |
@@ -769,73 +765,12 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) | |||
769 | return 0; | 765 | return 0; |
770 | } | 766 | } |
771 | 767 | ||
772 | static void pxa3xx_nand_ecc_hwctl(struct mtd_info *mtd, int mode) | ||
773 | { | ||
774 | return; | ||
775 | } | ||
776 | |||
777 | static int pxa3xx_nand_ecc_calculate(struct mtd_info *mtd, | ||
778 | const uint8_t *dat, uint8_t *ecc_code) | ||
779 | { | ||
780 | return 0; | ||
781 | } | ||
782 | |||
783 | static int pxa3xx_nand_ecc_correct(struct mtd_info *mtd, | ||
784 | uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc) | ||
785 | { | ||
786 | struct pxa3xx_nand_info *info = mtd->priv; | ||
787 | /* | ||
788 | * Any error include ERR_SEND_CMD, ERR_DBERR, ERR_BUSERR, we | ||
789 | * consider it as a ecc error which will tell the caller the | ||
790 | * read fail We have distinguish all the errors, but the | ||
791 | * nand_read_ecc only check this function return value | ||
792 | * | ||
793 | * Corrected (single-bit) errors must also be noted. | ||
794 | */ | ||
795 | if (info->retcode == ERR_SBERR) | ||
796 | return 1; | ||
797 | else if (info->retcode != ERR_NONE) | ||
798 | return -1; | ||
799 | |||
800 | return 0; | ||
801 | } | ||
802 | |||
803 | static int __readid(struct pxa3xx_nand_info *info, uint32_t *id) | ||
804 | { | ||
805 | const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; | ||
806 | uint32_t ndcr; | ||
807 | uint8_t id_buff[8]; | ||
808 | |||
809 | if (prepare_other_cmd(info, cmdset->read_id)) { | ||
810 | printk(KERN_ERR "failed to prepare command\n"); | ||
811 | return -EINVAL; | ||
812 | } | ||
813 | |||
814 | /* Send command */ | ||
815 | if (write_cmd(info)) | ||
816 | goto fail_timeout; | ||
817 | |||
818 | /* Wait for CMDDM(command done successfully) */ | ||
819 | if (wait_for_event(info, NDSR_RDDREQ)) | ||
820 | goto fail_timeout; | ||
821 | |||
822 | __raw_readsl(info->mmio_base + NDDB, id_buff, 2); | ||
823 | *id = id_buff[0] | (id_buff[1] << 8); | ||
824 | return 0; | ||
825 | |||
826 | fail_timeout: | ||
827 | ndcr = nand_readl(info, NDCR); | ||
828 | nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN); | ||
829 | udelay(10); | ||
830 | return -ETIMEDOUT; | ||
831 | } | ||
832 | |||
833 | static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, | 768 | static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, |
834 | const struct pxa3xx_nand_flash *f) | 769 | const struct pxa3xx_nand_flash *f) |
835 | { | 770 | { |
836 | struct platform_device *pdev = info->pdev; | 771 | struct platform_device *pdev = info->pdev; |
837 | struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; | 772 | struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; |
838 | uint32_t ndcr = 0x00000FFF; /* disable all interrupts */ | 773 | uint32_t ndcr = 0x0; /* enable all interrupts */ |
839 | 774 | ||
840 | if (f->page_size != 2048 && f->page_size != 512) | 775 | if (f->page_size != 2048 && f->page_size != 512) |
841 | return -EINVAL; | 776 | return -EINVAL; |
@@ -844,9 +779,8 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, | |||
844 | return -EINVAL; | 779 | return -EINVAL; |
845 | 780 | ||
846 | /* calculate flash information */ | 781 | /* calculate flash information */ |
847 | info->cmdset = f->cmdset; | 782 | info->cmdset = &default_cmdset; |
848 | info->page_size = f->page_size; | 783 | info->page_size = f->page_size; |
849 | info->oob_buff = info->data_buff + f->page_size; | ||
850 | info->read_id_bytes = (f->page_size == 2048) ? 4 : 2; | 784 | info->read_id_bytes = (f->page_size == 2048) ? 4 : 2; |
851 | 785 | ||
852 | /* calculate addressing information */ | 786 | /* calculate addressing information */ |
@@ -876,87 +810,18 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, | |||
876 | static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) | 810 | static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) |
877 | { | 811 | { |
878 | uint32_t ndcr = nand_readl(info, NDCR); | 812 | uint32_t ndcr = nand_readl(info, NDCR); |
879 | struct nand_flash_dev *type = NULL; | ||
880 | uint32_t id = -1, page_per_block, num_blocks; | ||
881 | int i; | ||
882 | |||
883 | page_per_block = ndcr & NDCR_PG_PER_BLK ? 64 : 32; | ||
884 | info->page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; | 813 | info->page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; |
885 | /* set info fields needed to __readid */ | 814 | /* set info fields needed to read id */ |
886 | info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; | 815 | info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; |
887 | info->reg_ndcr = ndcr; | 816 | info->reg_ndcr = ndcr; |
888 | info->cmdset = &default_cmdset; | 817 | info->cmdset = &default_cmdset; |
889 | 818 | ||
890 | if (__readid(info, &id)) | ||
891 | return -ENODEV; | ||
892 | |||
893 | /* Lookup the flash id */ | ||
894 | id = (id >> 8) & 0xff; /* device id is byte 2 */ | ||
895 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { | ||
896 | if (id == nand_flash_ids[i].id) { | ||
897 | type = &nand_flash_ids[i]; | ||
898 | break; | ||
899 | } | ||
900 | } | ||
901 | |||
902 | if (!type) | ||
903 | return -ENODEV; | ||
904 | |||
905 | /* fill the missing flash information */ | ||
906 | i = __ffs(page_per_block * info->page_size); | ||
907 | num_blocks = type->chipsize << (20 - i); | ||
908 | |||
909 | /* calculate addressing information */ | ||
910 | info->col_addr_cycles = (info->page_size == 2048) ? 2 : 1; | ||
911 | |||
912 | if (num_blocks * page_per_block > 65536) | ||
913 | info->row_addr_cycles = 3; | ||
914 | else | ||
915 | info->row_addr_cycles = 2; | ||
916 | |||
917 | info->ndtr0cs0 = nand_readl(info, NDTR0CS0); | 819 | info->ndtr0cs0 = nand_readl(info, NDTR0CS0); |
918 | info->ndtr1cs0 = nand_readl(info, NDTR1CS0); | 820 | info->ndtr1cs0 = nand_readl(info, NDTR1CS0); |
919 | 821 | ||
920 | return 0; | 822 | return 0; |
921 | } | 823 | } |
922 | 824 | ||
923 | static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info, | ||
924 | const struct pxa3xx_nand_platform_data *pdata) | ||
925 | { | ||
926 | const struct pxa3xx_nand_flash *f; | ||
927 | uint32_t id = -1; | ||
928 | int i; | ||
929 | |||
930 | if (pdata->keep_config) | ||
931 | if (pxa3xx_nand_detect_config(info) == 0) | ||
932 | return 0; | ||
933 | |||
934 | /* we use default timing to detect id */ | ||
935 | f = DEFAULT_FLASH_TYPE; | ||
936 | pxa3xx_nand_config_flash(info, f); | ||
937 | if (__readid(info, &id)) | ||
938 | goto fail_detect; | ||
939 | |||
940 | for (i=0; i<ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1; i++) { | ||
941 | /* we first choose the flash definition from platfrom */ | ||
942 | if (i < pdata->num_flash) | ||
943 | f = pdata->flash + i; | ||
944 | else | ||
945 | f = &builtin_flash_types[i - pdata->num_flash + 1]; | ||
946 | if (f->chip_id == id) { | ||
947 | dev_info(&info->pdev->dev, "detect chip id: 0x%x\n", id); | ||
948 | pxa3xx_nand_config_flash(info, f); | ||
949 | return 0; | ||
950 | } | ||
951 | } | ||
952 | |||
953 | dev_warn(&info->pdev->dev, | ||
954 | "failed to detect configured nand flash; found %04x instead of\n", | ||
955 | id); | ||
956 | fail_detect: | ||
957 | return -ENODEV; | ||
958 | } | ||
959 | |||
960 | /* the maximum possible buffer size for large page with OOB data | 825 | /* the maximum possible buffer size for large page with OOB data |
961 | * is: 2048 + 64 = 2112 bytes, allocate a page here for both the | 826 | * is: 2048 + 64 = 2112 bytes, allocate a page here for both the |
962 | * data buffer and the DMA descriptor | 827 | * data buffer and the DMA descriptor |
@@ -998,82 +863,144 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) | |||
998 | return 0; | 863 | return 0; |
999 | } | 864 | } |
1000 | 865 | ||
1001 | static struct nand_ecclayout hw_smallpage_ecclayout = { | 866 | static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) |
1002 | .eccbytes = 6, | 867 | { |
1003 | .eccpos = {8, 9, 10, 11, 12, 13 }, | 868 | struct mtd_info *mtd = info->mtd; |
1004 | .oobfree = { {2, 6} } | 869 | struct nand_chip *chip = mtd->priv; |
1005 | }; | ||
1006 | 870 | ||
1007 | static struct nand_ecclayout hw_largepage_ecclayout = { | 871 | /* use the common timing to make a try */ |
1008 | .eccbytes = 24, | 872 | pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); |
1009 | .eccpos = { | 873 | chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0); |
1010 | 40, 41, 42, 43, 44, 45, 46, 47, | 874 | if (info->is_ready) |
1011 | 48, 49, 50, 51, 52, 53, 54, 55, | 875 | return 1; |
1012 | 56, 57, 58, 59, 60, 61, 62, 63}, | 876 | else |
1013 | .oobfree = { {2, 38} } | 877 | return 0; |
1014 | }; | 878 | } |
1015 | 879 | ||
1016 | static void pxa3xx_nand_init_mtd(struct mtd_info *mtd, | 880 | static int pxa3xx_nand_scan(struct mtd_info *mtd) |
1017 | struct pxa3xx_nand_info *info) | ||
1018 | { | 881 | { |
1019 | struct nand_chip *this = &info->nand_chip; | 882 | struct pxa3xx_nand_info *info = mtd->priv; |
1020 | 883 | struct platform_device *pdev = info->pdev; | |
1021 | this->options = (info->reg_ndcr & NDCR_DWIDTH_C) ? NAND_BUSWIDTH_16: 0; | 884 | struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; |
1022 | 885 | struct nand_flash_dev pxa3xx_flash_ids[2] = { {NULL,}, {NULL,} }; | |
1023 | this->waitfunc = pxa3xx_nand_waitfunc; | 886 | const struct pxa3xx_nand_flash *f = NULL; |
1024 | this->select_chip = pxa3xx_nand_select_chip; | 887 | struct nand_chip *chip = mtd->priv; |
1025 | this->dev_ready = pxa3xx_nand_dev_ready; | 888 | uint32_t id = -1; |
1026 | this->cmdfunc = pxa3xx_nand_cmdfunc; | 889 | uint64_t chipsize; |
1027 | this->read_word = pxa3xx_nand_read_word; | 890 | int i, ret, num; |
1028 | this->read_byte = pxa3xx_nand_read_byte; | 891 | |
1029 | this->read_buf = pxa3xx_nand_read_buf; | 892 | if (pdata->keep_config && !pxa3xx_nand_detect_config(info)) |
1030 | this->write_buf = pxa3xx_nand_write_buf; | 893 | goto KEEP_CONFIG; |
1031 | this->verify_buf = pxa3xx_nand_verify_buf; | 894 | |
1032 | 895 | ret = pxa3xx_nand_sensing(info); | |
1033 | this->ecc.mode = NAND_ECC_HW; | 896 | if (!ret) { |
1034 | this->ecc.hwctl = pxa3xx_nand_ecc_hwctl; | 897 | kfree(mtd); |
1035 | this->ecc.calculate = pxa3xx_nand_ecc_calculate; | 898 | info->mtd = NULL; |
1036 | this->ecc.correct = pxa3xx_nand_ecc_correct; | 899 | printk(KERN_INFO "There is no nand chip on cs 0!\n"); |
1037 | this->ecc.size = info->page_size; | 900 | |
1038 | 901 | return -EINVAL; | |
1039 | if (info->page_size == 2048) | 902 | } |
1040 | this->ecc.layout = &hw_largepage_ecclayout; | 903 | |
904 | chip->cmdfunc(mtd, NAND_CMD_READID, 0, 0); | ||
905 | id = *((uint16_t *)(info->data_buff)); | ||
906 | if (id != 0) | ||
907 | printk(KERN_INFO "Detect a flash id %x\n", id); | ||
908 | else { | ||
909 | kfree(mtd); | ||
910 | info->mtd = NULL; | ||
911 | printk(KERN_WARNING "Read out ID 0, potential timing set wrong!!\n"); | ||
912 | |||
913 | return -EINVAL; | ||
914 | } | ||
915 | |||
916 | num = ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1; | ||
917 | for (i = 0; i < num; i++) { | ||
918 | if (i < pdata->num_flash) | ||
919 | f = pdata->flash + i; | ||
920 | else | ||
921 | f = &builtin_flash_types[i - pdata->num_flash + 1]; | ||
922 | |||
923 | /* find the chip in default list */ | ||
924 | if (f->chip_id == id) | ||
925 | break; | ||
926 | } | ||
927 | |||
928 | if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) { | ||
929 | kfree(mtd); | ||
930 | info->mtd = NULL; | ||
931 | printk(KERN_ERR "ERROR!! flash not defined!!!\n"); | ||
932 | |||
933 | return -EINVAL; | ||
934 | } | ||
935 | |||
936 | pxa3xx_nand_config_flash(info, f); | ||
937 | pxa3xx_flash_ids[0].name = f->name; | ||
938 | pxa3xx_flash_ids[0].id = (f->chip_id >> 8) & 0xffff; | ||
939 | pxa3xx_flash_ids[0].pagesize = f->page_size; | ||
940 | chipsize = (uint64_t)f->num_blocks * f->page_per_block * f->page_size; | ||
941 | pxa3xx_flash_ids[0].chipsize = chipsize >> 20; | ||
942 | pxa3xx_flash_ids[0].erasesize = f->page_size * f->page_per_block; | ||
943 | if (f->flash_width == 16) | ||
944 | pxa3xx_flash_ids[0].options = NAND_BUSWIDTH_16; | ||
945 | KEEP_CONFIG: | ||
946 | if (nand_scan_ident(mtd, 1, pxa3xx_flash_ids)) | ||
947 | return -ENODEV; | ||
948 | /* calculate addressing information */ | ||
949 | info->col_addr_cycles = (mtd->writesize >= 2048) ? 2 : 1; | ||
950 | info->oob_buff = info->data_buff + mtd->writesize; | ||
951 | if ((mtd->size >> chip->page_shift) > 65536) | ||
952 | info->row_addr_cycles = 3; | ||
1041 | else | 953 | else |
1042 | this->ecc.layout = &hw_smallpage_ecclayout; | 954 | info->row_addr_cycles = 2; |
955 | mtd->name = mtd_names[0]; | ||
956 | chip->ecc.mode = NAND_ECC_HW; | ||
957 | chip->ecc.size = f->page_size; | ||
958 | |||
959 | chip->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16 : 0; | ||
960 | chip->options |= NAND_NO_AUTOINCR; | ||
961 | chip->options |= NAND_NO_READRDY; | ||
1043 | 962 | ||
1044 | this->chip_delay = 25; | 963 | return nand_scan_tail(mtd); |
1045 | } | 964 | } |
1046 | 965 | ||
1047 | static int pxa3xx_nand_probe(struct platform_device *pdev) | 966 | static |
967 | struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) | ||
1048 | { | 968 | { |
1049 | struct pxa3xx_nand_platform_data *pdata; | ||
1050 | struct pxa3xx_nand_info *info; | 969 | struct pxa3xx_nand_info *info; |
1051 | struct nand_chip *this; | 970 | struct nand_chip *chip; |
1052 | struct mtd_info *mtd; | 971 | struct mtd_info *mtd; |
1053 | struct resource *r; | 972 | struct resource *r; |
1054 | int ret = 0, irq; | 973 | int ret, irq; |
1055 | |||
1056 | pdata = pdev->dev.platform_data; | ||
1057 | |||
1058 | if (!pdata) { | ||
1059 | dev_err(&pdev->dev, "no platform data defined\n"); | ||
1060 | return -ENODEV; | ||
1061 | } | ||
1062 | 974 | ||
1063 | mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct pxa3xx_nand_info), | 975 | mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct pxa3xx_nand_info), |
1064 | GFP_KERNEL); | 976 | GFP_KERNEL); |
1065 | if (!mtd) { | 977 | if (!mtd) { |
1066 | dev_err(&pdev->dev, "failed to allocate memory\n"); | 978 | dev_err(&pdev->dev, "failed to allocate memory\n"); |
1067 | return -ENOMEM; | 979 | return NULL; |
1068 | } | 980 | } |
1069 | 981 | ||
1070 | info = (struct pxa3xx_nand_info *)(&mtd[1]); | 982 | info = (struct pxa3xx_nand_info *)(&mtd[1]); |
983 | chip = (struct nand_chip *)(&mtd[1]); | ||
1071 | info->pdev = pdev; | 984 | info->pdev = pdev; |
1072 | 985 | info->mtd = mtd; | |
1073 | this = &info->nand_chip; | ||
1074 | mtd->priv = info; | 986 | mtd->priv = info; |
1075 | mtd->owner = THIS_MODULE; | 987 | mtd->owner = THIS_MODULE; |
1076 | 988 | ||
989 | chip->ecc.read_page = pxa3xx_nand_read_page_hwecc; | ||
990 | chip->ecc.write_page = pxa3xx_nand_write_page_hwecc; | ||
991 | chip->controller = &info->controller; | ||
992 | chip->waitfunc = pxa3xx_nand_waitfunc; | ||
993 | chip->select_chip = pxa3xx_nand_select_chip; | ||
994 | chip->dev_ready = pxa3xx_nand_dev_ready; | ||
995 | chip->cmdfunc = pxa3xx_nand_cmdfunc; | ||
996 | chip->read_word = pxa3xx_nand_read_word; | ||
997 | chip->read_byte = pxa3xx_nand_read_byte; | ||
998 | chip->read_buf = pxa3xx_nand_read_buf; | ||
999 | chip->write_buf = pxa3xx_nand_write_buf; | ||
1000 | chip->verify_buf = pxa3xx_nand_verify_buf; | ||
1001 | |||
1002 | spin_lock_init(&chip->controller->lock); | ||
1003 | init_waitqueue_head(&chip->controller->wq); | ||
1077 | info->clk = clk_get(&pdev->dev, NULL); | 1004 | info->clk = clk_get(&pdev->dev, NULL); |
1078 | if (IS_ERR(info->clk)) { | 1005 | if (IS_ERR(info->clk)) { |
1079 | dev_err(&pdev->dev, "failed to get nand clock\n"); | 1006 | dev_err(&pdev->dev, "failed to get nand clock\n"); |
@@ -1141,43 +1068,12 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) | |||
1141 | goto fail_free_buf; | 1068 | goto fail_free_buf; |
1142 | } | 1069 | } |
1143 | 1070 | ||
1144 | ret = pxa3xx_nand_detect_flash(info, pdata); | 1071 | platform_set_drvdata(pdev, info); |
1145 | if (ret) { | ||
1146 | dev_err(&pdev->dev, "failed to detect flash\n"); | ||
1147 | ret = -ENODEV; | ||
1148 | goto fail_free_irq; | ||
1149 | } | ||
1150 | |||
1151 | pxa3xx_nand_init_mtd(mtd, info); | ||
1152 | |||
1153 | platform_set_drvdata(pdev, mtd); | ||
1154 | |||
1155 | if (nand_scan(mtd, 1)) { | ||
1156 | dev_err(&pdev->dev, "failed to scan nand\n"); | ||
1157 | ret = -ENXIO; | ||
1158 | goto fail_free_irq; | ||
1159 | } | ||
1160 | |||
1161 | #ifdef CONFIG_MTD_PARTITIONS | ||
1162 | if (mtd_has_cmdlinepart()) { | ||
1163 | static const char *probes[] = { "cmdlinepart", NULL }; | ||
1164 | struct mtd_partition *parts; | ||
1165 | int nr_parts; | ||
1166 | |||
1167 | nr_parts = parse_mtd_partitions(mtd, probes, &parts, 0); | ||
1168 | |||
1169 | if (nr_parts) | ||
1170 | return add_mtd_partitions(mtd, parts, nr_parts); | ||
1171 | } | ||
1172 | 1072 | ||
1173 | return add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts); | 1073 | return info; |
1174 | #else | ||
1175 | return 0; | ||
1176 | #endif | ||
1177 | 1074 | ||
1178 | fail_free_irq: | ||
1179 | free_irq(irq, info); | ||
1180 | fail_free_buf: | 1075 | fail_free_buf: |
1076 | free_irq(irq, info); | ||
1181 | if (use_dma) { | 1077 | if (use_dma) { |
1182 | pxa_free_dma(info->data_dma_ch); | 1078 | pxa_free_dma(info->data_dma_ch); |
1183 | dma_free_coherent(&pdev->dev, info->data_buff_size, | 1079 | dma_free_coherent(&pdev->dev, info->data_buff_size, |
@@ -1193,22 +1089,18 @@ fail_put_clk: | |||
1193 | clk_put(info->clk); | 1089 | clk_put(info->clk); |
1194 | fail_free_mtd: | 1090 | fail_free_mtd: |
1195 | kfree(mtd); | 1091 | kfree(mtd); |
1196 | return ret; | 1092 | return NULL; |
1197 | } | 1093 | } |
1198 | 1094 | ||
1199 | static int pxa3xx_nand_remove(struct platform_device *pdev) | 1095 | static int pxa3xx_nand_remove(struct platform_device *pdev) |
1200 | { | 1096 | { |
1201 | struct mtd_info *mtd = platform_get_drvdata(pdev); | 1097 | struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); |
1202 | struct pxa3xx_nand_info *info = mtd->priv; | 1098 | struct mtd_info *mtd = info->mtd; |
1203 | struct resource *r; | 1099 | struct resource *r; |
1204 | int irq; | 1100 | int irq; |
1205 | 1101 | ||
1206 | platform_set_drvdata(pdev, NULL); | 1102 | platform_set_drvdata(pdev, NULL); |
1207 | 1103 | ||
1208 | del_mtd_device(mtd); | ||
1209 | #ifdef CONFIG_MTD_PARTITIONS | ||
1210 | del_mtd_partitions(mtd); | ||
1211 | #endif | ||
1212 | irq = platform_get_irq(pdev, 0); | 1104 | irq = platform_get_irq(pdev, 0); |
1213 | if (irq >= 0) | 1105 | if (irq >= 0) |
1214 | free_irq(irq, info); | 1106 | free_irq(irq, info); |
@@ -1226,17 +1118,62 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) | |||
1226 | clk_disable(info->clk); | 1118 | clk_disable(info->clk); |
1227 | clk_put(info->clk); | 1119 | clk_put(info->clk); |
1228 | 1120 | ||
1229 | kfree(mtd); | 1121 | if (mtd) { |
1122 | del_mtd_device(mtd); | ||
1123 | #ifdef CONFIG_MTD_PARTITIONS | ||
1124 | del_mtd_partitions(mtd); | ||
1125 | #endif | ||
1126 | kfree(mtd); | ||
1127 | } | ||
1230 | return 0; | 1128 | return 0; |
1231 | } | 1129 | } |
1232 | 1130 | ||
1131 | static int pxa3xx_nand_probe(struct platform_device *pdev) | ||
1132 | { | ||
1133 | struct pxa3xx_nand_platform_data *pdata; | ||
1134 | struct pxa3xx_nand_info *info; | ||
1135 | |||
1136 | pdata = pdev->dev.platform_data; | ||
1137 | if (!pdata) { | ||
1138 | dev_err(&pdev->dev, "no platform data defined\n"); | ||
1139 | return -ENODEV; | ||
1140 | } | ||
1141 | |||
1142 | info = alloc_nand_resource(pdev); | ||
1143 | if (info == NULL) | ||
1144 | return -ENOMEM; | ||
1145 | |||
1146 | if (pxa3xx_nand_scan(info->mtd)) { | ||
1147 | dev_err(&pdev->dev, "failed to scan nand\n"); | ||
1148 | pxa3xx_nand_remove(pdev); | ||
1149 | return -ENODEV; | ||
1150 | } | ||
1151 | |||
1152 | #ifdef CONFIG_MTD_PARTITIONS | ||
1153 | if (mtd_has_cmdlinepart()) { | ||
1154 | const char *probes[] = { "cmdlinepart", NULL }; | ||
1155 | struct mtd_partition *parts; | ||
1156 | int nr_parts; | ||
1157 | |||
1158 | nr_parts = parse_mtd_partitions(info->mtd, probes, &parts, 0); | ||
1159 | |||
1160 | if (nr_parts) | ||
1161 | return add_mtd_partitions(info->mtd, parts, nr_parts); | ||
1162 | } | ||
1163 | |||
1164 | return add_mtd_partitions(info->mtd, pdata->parts, pdata->nr_parts); | ||
1165 | #else | ||
1166 | return 0; | ||
1167 | #endif | ||
1168 | } | ||
1169 | |||
1233 | #ifdef CONFIG_PM | 1170 | #ifdef CONFIG_PM |
1234 | static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state) | 1171 | static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state) |
1235 | { | 1172 | { |
1236 | struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev); | 1173 | struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); |
1237 | struct pxa3xx_nand_info *info = mtd->priv; | 1174 | struct mtd_info *mtd = info->mtd; |
1238 | 1175 | ||
1239 | if (info->state != STATE_READY) { | 1176 | if (info->state) { |
1240 | dev_err(&pdev->dev, "driver busy, state = %d\n", info->state); | 1177 | dev_err(&pdev->dev, "driver busy, state = %d\n", info->state); |
1241 | return -EAGAIN; | 1178 | return -EAGAIN; |
1242 | } | 1179 | } |
@@ -1246,8 +1183,8 @@ static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state) | |||
1246 | 1183 | ||
1247 | static int pxa3xx_nand_resume(struct platform_device *pdev) | 1184 | static int pxa3xx_nand_resume(struct platform_device *pdev) |
1248 | { | 1185 | { |
1249 | struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev); | 1186 | struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); |
1250 | struct pxa3xx_nand_info *info = mtd->priv; | 1187 | struct mtd_info *mtd = info->mtd; |
1251 | 1188 | ||
1252 | nand_writel(info, NDTR0CS0, info->ndtr0cs0); | 1189 | nand_writel(info, NDTR0CS0, info->ndtr0cs0); |
1253 | nand_writel(info, NDTR1CS0, info->ndtr1cs0); | 1190 | nand_writel(info, NDTR1CS0, info->ndtr1cs0); |
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 14a49abe057e..f591f615d3f6 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c | |||
@@ -629,6 +629,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) | |||
629 | { | 629 | { |
630 | struct omap_onenand_platform_data *pdata; | 630 | struct omap_onenand_platform_data *pdata; |
631 | struct omap2_onenand *c; | 631 | struct omap2_onenand *c; |
632 | struct onenand_chip *this; | ||
632 | int r; | 633 | int r; |
633 | 634 | ||
634 | pdata = pdev->dev.platform_data; | 635 | pdata = pdev->dev.platform_data; |
@@ -726,9 +727,8 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) | |||
726 | 727 | ||
727 | c->mtd.dev.parent = &pdev->dev; | 728 | c->mtd.dev.parent = &pdev->dev; |
728 | 729 | ||
730 | this = &c->onenand; | ||
729 | if (c->dma_channel >= 0) { | 731 | if (c->dma_channel >= 0) { |
730 | struct onenand_chip *this = &c->onenand; | ||
731 | |||
732 | this->wait = omap2_onenand_wait; | 732 | this->wait = omap2_onenand_wait; |
733 | if (cpu_is_omap34xx()) { | 733 | if (cpu_is_omap34xx()) { |
734 | this->read_bufferram = omap3_onenand_read_bufferram; | 734 | this->read_bufferram = omap3_onenand_read_bufferram; |
@@ -749,6 +749,9 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) | |||
749 | c->onenand.disable = omap2_onenand_disable; | 749 | c->onenand.disable = omap2_onenand_disable; |
750 | } | 750 | } |
751 | 751 | ||
752 | if (pdata->skip_initial_unlocking) | ||
753 | this->options |= ONENAND_SKIP_INITIAL_UNLOCKING; | ||
754 | |||
752 | if ((r = onenand_scan(&c->mtd, 1)) < 0) | 755 | if ((r = onenand_scan(&c->mtd, 1)) < 0) |
753 | goto err_release_regulator; | 756 | goto err_release_regulator; |
754 | 757 | ||
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index bac41caa8df7..56a8b2005bda 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -1132,6 +1132,8 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from, | |||
1132 | onenand_update_bufferram(mtd, from, !ret); | 1132 | onenand_update_bufferram(mtd, from, !ret); |
1133 | if (ret == -EBADMSG) | 1133 | if (ret == -EBADMSG) |
1134 | ret = 0; | 1134 | ret = 0; |
1135 | if (ret) | ||
1136 | break; | ||
1135 | } | 1137 | } |
1136 | 1138 | ||
1137 | this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); | 1139 | this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); |
@@ -1646,11 +1648,10 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, | |||
1646 | int ret = 0; | 1648 | int ret = 0; |
1647 | int thislen, column; | 1649 | int thislen, column; |
1648 | 1650 | ||
1651 | column = addr & (this->writesize - 1); | ||
1652 | |||
1649 | while (len != 0) { | 1653 | while (len != 0) { |
1650 | thislen = min_t(int, this->writesize, len); | 1654 | thislen = min_t(int, this->writesize - column, len); |
1651 | column = addr & (this->writesize - 1); | ||
1652 | if (column + thislen > this->writesize) | ||
1653 | thislen = this->writesize - column; | ||
1654 | 1655 | ||
1655 | this->command(mtd, ONENAND_CMD_READ, addr, this->writesize); | 1656 | this->command(mtd, ONENAND_CMD_READ, addr, this->writesize); |
1656 | 1657 | ||
@@ -1664,12 +1665,13 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, | |||
1664 | 1665 | ||
1665 | this->read_bufferram(mtd, ONENAND_DATARAM, this->verify_buf, 0, mtd->writesize); | 1666 | this->read_bufferram(mtd, ONENAND_DATARAM, this->verify_buf, 0, mtd->writesize); |
1666 | 1667 | ||
1667 | if (memcmp(buf, this->verify_buf, thislen)) | 1668 | if (memcmp(buf, this->verify_buf + column, thislen)) |
1668 | return -EBADMSG; | 1669 | return -EBADMSG; |
1669 | 1670 | ||
1670 | len -= thislen; | 1671 | len -= thislen; |
1671 | buf += thislen; | 1672 | buf += thislen; |
1672 | addr += thislen; | 1673 | addr += thislen; |
1674 | column = 0; | ||
1673 | } | 1675 | } |
1674 | 1676 | ||
1675 | return 0; | 1677 | return 0; |
@@ -4083,7 +4085,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) | |||
4083 | mtd->writebufsize = mtd->writesize; | 4085 | mtd->writebufsize = mtd->writesize; |
4084 | 4086 | ||
4085 | /* Unlock whole block */ | 4087 | /* Unlock whole block */ |
4086 | this->unlock_all(mtd); | 4088 | if (!(this->options & ONENAND_SKIP_INITIAL_UNLOCKING)) |
4089 | this->unlock_all(mtd); | ||
4087 | 4090 | ||
4088 | ret = this->scan_bbt(mtd); | 4091 | ret = this->scan_bbt(mtd); |
4089 | if ((!FLEXONENAND(this)) || ret) | 4092 | if ((!FLEXONENAND(this)) || ret) |
diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index ac0d6a8613b5..2b0daae4018d 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c | |||
@@ -64,12 +64,16 @@ struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl) | |||
64 | SM_SMALL_PAGE - SM_CIS_VENDOR_OFFSET); | 64 | SM_SMALL_PAGE - SM_CIS_VENDOR_OFFSET); |
65 | 65 | ||
66 | char *vendor = kmalloc(vendor_len, GFP_KERNEL); | 66 | char *vendor = kmalloc(vendor_len, GFP_KERNEL); |
67 | if (!vendor) | ||
68 | goto error1; | ||
67 | memcpy(vendor, ftl->cis_buffer + SM_CIS_VENDOR_OFFSET, vendor_len); | 69 | memcpy(vendor, ftl->cis_buffer + SM_CIS_VENDOR_OFFSET, vendor_len); |
68 | vendor[vendor_len] = 0; | 70 | vendor[vendor_len] = 0; |
69 | 71 | ||
70 | /* Initialize sysfs attributes */ | 72 | /* Initialize sysfs attributes */ |
71 | vendor_attribute = | 73 | vendor_attribute = |
72 | kzalloc(sizeof(struct sm_sysfs_attribute), GFP_KERNEL); | 74 | kzalloc(sizeof(struct sm_sysfs_attribute), GFP_KERNEL); |
75 | if (!vendor_attribute) | ||
76 | goto error2; | ||
73 | 77 | ||
74 | sysfs_attr_init(&vendor_attribute->dev_attr.attr); | 78 | sysfs_attr_init(&vendor_attribute->dev_attr.attr); |
75 | 79 | ||
@@ -83,12 +87,24 @@ struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl) | |||
83 | /* Create array of pointers to the attributes */ | 87 | /* Create array of pointers to the attributes */ |
84 | attributes = kzalloc(sizeof(struct attribute *) * (NUM_ATTRIBUTES + 1), | 88 | attributes = kzalloc(sizeof(struct attribute *) * (NUM_ATTRIBUTES + 1), |
85 | GFP_KERNEL); | 89 | GFP_KERNEL); |
90 | if (!attributes) | ||
91 | goto error3; | ||
86 | attributes[0] = &vendor_attribute->dev_attr.attr; | 92 | attributes[0] = &vendor_attribute->dev_attr.attr; |
87 | 93 | ||
88 | /* Finally create the attribute group */ | 94 | /* Finally create the attribute group */ |
89 | attr_group = kzalloc(sizeof(struct attribute_group), GFP_KERNEL); | 95 | attr_group = kzalloc(sizeof(struct attribute_group), GFP_KERNEL); |
96 | if (!attr_group) | ||
97 | goto error4; | ||
90 | attr_group->attrs = attributes; | 98 | attr_group->attrs = attributes; |
91 | return attr_group; | 99 | return attr_group; |
100 | error4: | ||
101 | kfree(attributes); | ||
102 | error3: | ||
103 | kfree(vendor_attribute); | ||
104 | error2: | ||
105 | kfree(vendor); | ||
106 | error1: | ||
107 | return NULL; | ||
92 | } | 108 | } |
93 | 109 | ||
94 | void sm_delete_sysfs_attributes(struct sm_ftl *ftl) | 110 | void sm_delete_sysfs_attributes(struct sm_ftl *ftl) |
@@ -1178,6 +1194,8 @@ static void sm_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) | |||
1178 | } | 1194 | } |
1179 | 1195 | ||
1180 | ftl->disk_attributes = sm_create_sysfs_attributes(ftl); | 1196 | ftl->disk_attributes = sm_create_sysfs_attributes(ftl); |
1197 | if (!ftl->disk_attributes) | ||
1198 | goto error6; | ||
1181 | trans->disk_attributes = ftl->disk_attributes; | 1199 | trans->disk_attributes = ftl->disk_attributes; |
1182 | 1200 | ||
1183 | sm_printk("Found %d MiB xD/SmartMedia FTL on mtd%d", | 1201 | sm_printk("Found %d MiB xD/SmartMedia FTL on mtd%d", |
diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c index 161feeb7b8b9..627d4e2466a3 100644 --- a/drivers/mtd/tests/mtd_speedtest.c +++ b/drivers/mtd/tests/mtd_speedtest.c | |||
@@ -16,7 +16,7 @@ | |||
16 | * | 16 | * |
17 | * Test read and write speed of a MTD device. | 17 | * Test read and write speed of a MTD device. |
18 | * | 18 | * |
19 | * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> | 19 | * Author: Adrian Hunter <adrian.hunter@nokia.com> |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
@@ -33,6 +33,11 @@ static int dev; | |||
33 | module_param(dev, int, S_IRUGO); | 33 | module_param(dev, int, S_IRUGO); |
34 | MODULE_PARM_DESC(dev, "MTD device number to use"); | 34 | MODULE_PARM_DESC(dev, "MTD device number to use"); |
35 | 35 | ||
36 | static int count; | ||
37 | module_param(count, int, S_IRUGO); | ||
38 | MODULE_PARM_DESC(count, "Maximum number of eraseblocks to use " | ||
39 | "(0 means use all)"); | ||
40 | |||
36 | static struct mtd_info *mtd; | 41 | static struct mtd_info *mtd; |
37 | static unsigned char *iobuf; | 42 | static unsigned char *iobuf; |
38 | static unsigned char *bbt; | 43 | static unsigned char *bbt; |
@@ -89,6 +94,33 @@ static int erase_eraseblock(int ebnum) | |||
89 | return 0; | 94 | return 0; |
90 | } | 95 | } |
91 | 96 | ||
97 | static int multiblock_erase(int ebnum, int blocks) | ||
98 | { | ||
99 | int err; | ||
100 | struct erase_info ei; | ||
101 | loff_t addr = ebnum * mtd->erasesize; | ||
102 | |||
103 | memset(&ei, 0, sizeof(struct erase_info)); | ||
104 | ei.mtd = mtd; | ||
105 | ei.addr = addr; | ||
106 | ei.len = mtd->erasesize * blocks; | ||
107 | |||
108 | err = mtd->erase(mtd, &ei); | ||
109 | if (err) { | ||
110 | printk(PRINT_PREF "error %d while erasing EB %d, blocks %d\n", | ||
111 | err, ebnum, blocks); | ||
112 | return err; | ||
113 | } | ||
114 | |||
115 | if (ei.state == MTD_ERASE_FAILED) { | ||
116 | printk(PRINT_PREF "some erase error occurred at EB %d," | ||
117 | "blocks %d\n", ebnum, blocks); | ||
118 | return -EIO; | ||
119 | } | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||
92 | static int erase_whole_device(void) | 124 | static int erase_whole_device(void) |
93 | { | 125 | { |
94 | int err; | 126 | int err; |
@@ -282,13 +314,16 @@ static inline void stop_timing(void) | |||
282 | 314 | ||
283 | static long calc_speed(void) | 315 | static long calc_speed(void) |
284 | { | 316 | { |
285 | long ms, k, speed; | 317 | uint64_t k; |
318 | long ms; | ||
286 | 319 | ||
287 | ms = (finish.tv_sec - start.tv_sec) * 1000 + | 320 | ms = (finish.tv_sec - start.tv_sec) * 1000 + |
288 | (finish.tv_usec - start.tv_usec) / 1000; | 321 | (finish.tv_usec - start.tv_usec) / 1000; |
289 | k = goodebcnt * mtd->erasesize / 1024; | 322 | if (ms == 0) |
290 | speed = (k * 1000) / ms; | 323 | return 0; |
291 | return speed; | 324 | k = goodebcnt * (mtd->erasesize / 1024) * 1000; |
325 | do_div(k, ms); | ||
326 | return k; | ||
292 | } | 327 | } |
293 | 328 | ||
294 | static int scan_for_bad_eraseblocks(void) | 329 | static int scan_for_bad_eraseblocks(void) |
@@ -320,13 +355,16 @@ out: | |||
320 | 355 | ||
321 | static int __init mtd_speedtest_init(void) | 356 | static int __init mtd_speedtest_init(void) |
322 | { | 357 | { |
323 | int err, i; | 358 | int err, i, blocks, j, k; |
324 | long speed; | 359 | long speed; |
325 | uint64_t tmp; | 360 | uint64_t tmp; |
326 | 361 | ||
327 | printk(KERN_INFO "\n"); | 362 | printk(KERN_INFO "\n"); |
328 | printk(KERN_INFO "=================================================\n"); | 363 | printk(KERN_INFO "=================================================\n"); |
329 | printk(PRINT_PREF "MTD device: %d\n", dev); | 364 | if (count) |
365 | printk(PRINT_PREF "MTD device: %d count: %d\n", dev, count); | ||
366 | else | ||
367 | printk(PRINT_PREF "MTD device: %d\n", dev); | ||
330 | 368 | ||
331 | mtd = get_mtd_device(NULL, dev); | 369 | mtd = get_mtd_device(NULL, dev); |
332 | if (IS_ERR(mtd)) { | 370 | if (IS_ERR(mtd)) { |
@@ -353,6 +391,9 @@ static int __init mtd_speedtest_init(void) | |||
353 | (unsigned long long)mtd->size, mtd->erasesize, | 391 | (unsigned long long)mtd->size, mtd->erasesize, |
354 | pgsize, ebcnt, pgcnt, mtd->oobsize); | 392 | pgsize, ebcnt, pgcnt, mtd->oobsize); |
355 | 393 | ||
394 | if (count > 0 && count < ebcnt) | ||
395 | ebcnt = count; | ||
396 | |||
356 | err = -ENOMEM; | 397 | err = -ENOMEM; |
357 | iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); | 398 | iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); |
358 | if (!iobuf) { | 399 | if (!iobuf) { |
@@ -484,6 +525,31 @@ static int __init mtd_speedtest_init(void) | |||
484 | speed = calc_speed(); | 525 | speed = calc_speed(); |
485 | printk(PRINT_PREF "erase speed is %ld KiB/s\n", speed); | 526 | printk(PRINT_PREF "erase speed is %ld KiB/s\n", speed); |
486 | 527 | ||
528 | /* Multi-block erase all eraseblocks */ | ||
529 | for (k = 1; k < 7; k++) { | ||
530 | blocks = 1 << k; | ||
531 | printk(PRINT_PREF "Testing %dx multi-block erase speed\n", | ||
532 | blocks); | ||
533 | start_timing(); | ||
534 | for (i = 0; i < ebcnt; ) { | ||
535 | for (j = 0; j < blocks && (i + j) < ebcnt; j++) | ||
536 | if (bbt[i + j]) | ||
537 | break; | ||
538 | if (j < 1) { | ||
539 | i++; | ||
540 | continue; | ||
541 | } | ||
542 | err = multiblock_erase(i, j); | ||
543 | if (err) | ||
544 | goto out; | ||
545 | cond_resched(); | ||
546 | i += j; | ||
547 | } | ||
548 | stop_timing(); | ||
549 | speed = calc_speed(); | ||
550 | printk(PRINT_PREF "%dx multi-block erase speed is %ld KiB/s\n", | ||
551 | blocks, speed); | ||
552 | } | ||
487 | printk(PRINT_PREF "finished\n"); | 553 | printk(PRINT_PREF "finished\n"); |
488 | out: | 554 | out: |
489 | kfree(iobuf); | 555 | kfree(iobuf); |
diff --git a/drivers/mtd/tests/mtd_subpagetest.c b/drivers/mtd/tests/mtd_subpagetest.c index 11204e8aab5f..334eae53a3db 100644 --- a/drivers/mtd/tests/mtd_subpagetest.c +++ b/drivers/mtd/tests/mtd_subpagetest.c | |||
@@ -394,6 +394,11 @@ static int __init mtd_subpagetest_init(void) | |||
394 | } | 394 | } |
395 | 395 | ||
396 | subpgsize = mtd->writesize >> mtd->subpage_sft; | 396 | subpgsize = mtd->writesize >> mtd->subpage_sft; |
397 | tmp = mtd->size; | ||
398 | do_div(tmp, mtd->erasesize); | ||
399 | ebcnt = tmp; | ||
400 | pgcnt = mtd->erasesize / mtd->writesize; | ||
401 | |||
397 | printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " | 402 | printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " |
398 | "page size %u, subpage size %u, count of eraseblocks %u, " | 403 | "page size %u, subpage size %u, count of eraseblocks %u, " |
399 | "pages per eraseblock %u, OOB size %u\n", | 404 | "pages per eraseblock %u, OOB size %u\n", |
@@ -413,11 +418,6 @@ static int __init mtd_subpagetest_init(void) | |||
413 | goto out; | 418 | goto out; |
414 | } | 419 | } |
415 | 420 | ||
416 | tmp = mtd->size; | ||
417 | do_div(tmp, mtd->erasesize); | ||
418 | ebcnt = tmp; | ||
419 | pgcnt = mtd->erasesize / mtd->writesize; | ||
420 | |||
421 | err = scan_for_bad_eraseblocks(); | 421 | err = scan_for_bad_eraseblocks(); |
422 | if (err) | 422 | if (err) |
423 | goto out; | 423 | goto out; |
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index f142cc21e453..deaa8bc16cf8 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c | |||
@@ -711,14 +711,14 @@ static int __devinit a2065_init_one(struct zorro_dev *z, | |||
711 | return -EBUSY; | 711 | return -EBUSY; |
712 | r2 = request_mem_region(mem_start, A2065_RAM_SIZE, "RAM"); | 712 | r2 = request_mem_region(mem_start, A2065_RAM_SIZE, "RAM"); |
713 | if (!r2) { | 713 | if (!r2) { |
714 | release_resource(r1); | 714 | release_mem_region(base_addr, sizeof(struct lance_regs)); |
715 | return -EBUSY; | 715 | return -EBUSY; |
716 | } | 716 | } |
717 | 717 | ||
718 | dev = alloc_etherdev(sizeof(struct lance_private)); | 718 | dev = alloc_etherdev(sizeof(struct lance_private)); |
719 | if (dev == NULL) { | 719 | if (dev == NULL) { |
720 | release_resource(r1); | 720 | release_mem_region(base_addr, sizeof(struct lance_regs)); |
721 | release_resource(r2); | 721 | release_mem_region(mem_start, A2065_RAM_SIZE); |
722 | return -ENOMEM; | 722 | return -ENOMEM; |
723 | } | 723 | } |
724 | 724 | ||
@@ -764,8 +764,8 @@ static int __devinit a2065_init_one(struct zorro_dev *z, | |||
764 | 764 | ||
765 | err = register_netdev(dev); | 765 | err = register_netdev(dev); |
766 | if (err) { | 766 | if (err) { |
767 | release_resource(r1); | 767 | release_mem_region(base_addr, sizeof(struct lance_regs)); |
768 | release_resource(r2); | 768 | release_mem_region(mem_start, A2065_RAM_SIZE); |
769 | free_netdev(dev); | 769 | free_netdev(dev); |
770 | return err; | 770 | return err; |
771 | } | 771 | } |
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 7ca0eded2561..b7f45cd756a2 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c | |||
@@ -182,14 +182,14 @@ static int __devinit ariadne_init_one(struct zorro_dev *z, | |||
182 | return -EBUSY; | 182 | return -EBUSY; |
183 | r2 = request_mem_region(mem_start, ARIADNE_RAM_SIZE, "RAM"); | 183 | r2 = request_mem_region(mem_start, ARIADNE_RAM_SIZE, "RAM"); |
184 | if (!r2) { | 184 | if (!r2) { |
185 | release_resource(r1); | 185 | release_mem_region(base_addr, sizeof(struct Am79C960)); |
186 | return -EBUSY; | 186 | return -EBUSY; |
187 | } | 187 | } |
188 | 188 | ||
189 | dev = alloc_etherdev(sizeof(struct ariadne_private)); | 189 | dev = alloc_etherdev(sizeof(struct ariadne_private)); |
190 | if (dev == NULL) { | 190 | if (dev == NULL) { |
191 | release_resource(r1); | 191 | release_mem_region(base_addr, sizeof(struct Am79C960)); |
192 | release_resource(r2); | 192 | release_mem_region(mem_start, ARIADNE_RAM_SIZE); |
193 | return -ENOMEM; | 193 | return -ENOMEM; |
194 | } | 194 | } |
195 | 195 | ||
@@ -213,8 +213,8 @@ static int __devinit ariadne_init_one(struct zorro_dev *z, | |||
213 | 213 | ||
214 | err = register_netdev(dev); | 214 | err = register_netdev(dev); |
215 | if (err) { | 215 | if (err) { |
216 | release_resource(r1); | 216 | release_mem_region(base_addr, sizeof(struct Am79C960)); |
217 | release_resource(r2); | 217 | release_mem_region(mem_start, ARIADNE_RAM_SIZE); |
218 | free_netdev(dev); | 218 | free_netdev(dev); |
219 | return err; | 219 | return err; |
220 | } | 220 | } |
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 338bea147c64..16d6fe954695 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -1482,21 +1482,16 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) | |||
1482 | { | 1482 | { |
1483 | struct sk_buff *skb = *pskb; | 1483 | struct sk_buff *skb = *pskb; |
1484 | struct slave *slave; | 1484 | struct slave *slave; |
1485 | struct net_device *bond_dev; | ||
1486 | struct bonding *bond; | 1485 | struct bonding *bond; |
1487 | 1486 | ||
1488 | slave = bond_slave_get_rcu(skb->dev); | ||
1489 | bond_dev = ACCESS_ONCE(slave->dev->master); | ||
1490 | if (unlikely(!bond_dev)) | ||
1491 | return RX_HANDLER_PASS; | ||
1492 | |||
1493 | skb = skb_share_check(skb, GFP_ATOMIC); | 1487 | skb = skb_share_check(skb, GFP_ATOMIC); |
1494 | if (unlikely(!skb)) | 1488 | if (unlikely(!skb)) |
1495 | return RX_HANDLER_CONSUMED; | 1489 | return RX_HANDLER_CONSUMED; |
1496 | 1490 | ||
1497 | *pskb = skb; | 1491 | *pskb = skb; |
1498 | 1492 | ||
1499 | bond = netdev_priv(bond_dev); | 1493 | slave = bond_slave_get_rcu(skb->dev); |
1494 | bond = slave->bond; | ||
1500 | 1495 | ||
1501 | if (bond->params.arp_interval) | 1496 | if (bond->params.arp_interval) |
1502 | slave->dev->last_rx = jiffies; | 1497 | slave->dev->last_rx = jiffies; |
@@ -1505,10 +1500,10 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) | |||
1505 | return RX_HANDLER_EXACT; | 1500 | return RX_HANDLER_EXACT; |
1506 | } | 1501 | } |
1507 | 1502 | ||
1508 | skb->dev = bond_dev; | 1503 | skb->dev = bond->dev; |
1509 | 1504 | ||
1510 | if (bond->params.mode == BOND_MODE_ALB && | 1505 | if (bond->params.mode == BOND_MODE_ALB && |
1511 | bond_dev->priv_flags & IFF_BRIDGE_PORT && | 1506 | bond->dev->priv_flags & IFF_BRIDGE_PORT && |
1512 | skb->pkt_type == PACKET_HOST) { | 1507 | skb->pkt_type == PACKET_HOST) { |
1513 | 1508 | ||
1514 | if (unlikely(skb_cow_head(skb, | 1509 | if (unlikely(skb_cow_head(skb, |
@@ -1516,7 +1511,7 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) | |||
1516 | kfree_skb(skb); | 1511 | kfree_skb(skb); |
1517 | return RX_HANDLER_CONSUMED; | 1512 | return RX_HANDLER_CONSUMED; |
1518 | } | 1513 | } |
1519 | memcpy(eth_hdr(skb)->h_dest, bond_dev->dev_addr, ETH_ALEN); | 1514 | memcpy(eth_hdr(skb)->h_dest, bond->dev->dev_addr, ETH_ALEN); |
1520 | } | 1515 | } |
1521 | 1516 | ||
1522 | return RX_HANDLER_ANOTHER; | 1517 | return RX_HANDLER_ANOTHER; |
@@ -1698,20 +1693,15 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1698 | pr_debug("Error %d calling netdev_set_bond_master\n", res); | 1693 | pr_debug("Error %d calling netdev_set_bond_master\n", res); |
1699 | goto err_restore_mac; | 1694 | goto err_restore_mac; |
1700 | } | 1695 | } |
1701 | res = netdev_rx_handler_register(slave_dev, bond_handle_frame, | ||
1702 | new_slave); | ||
1703 | if (res) { | ||
1704 | pr_debug("Error %d calling netdev_rx_handler_register\n", res); | ||
1705 | goto err_unset_master; | ||
1706 | } | ||
1707 | 1696 | ||
1708 | /* open the slave since the application closed it */ | 1697 | /* open the slave since the application closed it */ |
1709 | res = dev_open(slave_dev); | 1698 | res = dev_open(slave_dev); |
1710 | if (res) { | 1699 | if (res) { |
1711 | pr_debug("Opening slave %s failed\n", slave_dev->name); | 1700 | pr_debug("Opening slave %s failed\n", slave_dev->name); |
1712 | goto err_unreg_rxhandler; | 1701 | goto err_unset_master; |
1713 | } | 1702 | } |
1714 | 1703 | ||
1704 | new_slave->bond = bond; | ||
1715 | new_slave->dev = slave_dev; | 1705 | new_slave->dev = slave_dev; |
1716 | slave_dev->priv_flags |= IFF_BONDING; | 1706 | slave_dev->priv_flags |= IFF_BONDING; |
1717 | 1707 | ||
@@ -1907,6 +1897,13 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1907 | if (res) | 1897 | if (res) |
1908 | goto err_close; | 1898 | goto err_close; |
1909 | 1899 | ||
1900 | res = netdev_rx_handler_register(slave_dev, bond_handle_frame, | ||
1901 | new_slave); | ||
1902 | if (res) { | ||
1903 | pr_debug("Error %d calling netdev_rx_handler_register\n", res); | ||
1904 | goto err_dest_symlinks; | ||
1905 | } | ||
1906 | |||
1910 | pr_info("%s: enslaving %s as a%s interface with a%s link.\n", | 1907 | pr_info("%s: enslaving %s as a%s interface with a%s link.\n", |
1911 | bond_dev->name, slave_dev->name, | 1908 | bond_dev->name, slave_dev->name, |
1912 | bond_is_active_slave(new_slave) ? "n active" : " backup", | 1909 | bond_is_active_slave(new_slave) ? "n active" : " backup", |
@@ -1916,13 +1913,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1916 | return 0; | 1913 | return 0; |
1917 | 1914 | ||
1918 | /* Undo stages on error */ | 1915 | /* Undo stages on error */ |
1916 | err_dest_symlinks: | ||
1917 | bond_destroy_slave_symlinks(bond_dev, slave_dev); | ||
1918 | |||
1919 | err_close: | 1919 | err_close: |
1920 | dev_close(slave_dev); | 1920 | dev_close(slave_dev); |
1921 | 1921 | ||
1922 | err_unreg_rxhandler: | ||
1923 | netdev_rx_handler_unregister(slave_dev); | ||
1924 | synchronize_net(); | ||
1925 | |||
1926 | err_unset_master: | 1922 | err_unset_master: |
1927 | netdev_set_bond_master(slave_dev, NULL); | 1923 | netdev_set_bond_master(slave_dev, NULL); |
1928 | 1924 | ||
@@ -1988,6 +1984,14 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1988 | return -EINVAL; | 1984 | return -EINVAL; |
1989 | } | 1985 | } |
1990 | 1986 | ||
1987 | /* unregister rx_handler early so bond_handle_frame wouldn't be called | ||
1988 | * for this slave anymore. | ||
1989 | */ | ||
1990 | netdev_rx_handler_unregister(slave_dev); | ||
1991 | write_unlock_bh(&bond->lock); | ||
1992 | synchronize_net(); | ||
1993 | write_lock_bh(&bond->lock); | ||
1994 | |||
1991 | if (!bond->params.fail_over_mac) { | 1995 | if (!bond->params.fail_over_mac) { |
1992 | if (!compare_ether_addr(bond_dev->dev_addr, slave->perm_hwaddr) && | 1996 | if (!compare_ether_addr(bond_dev->dev_addr, slave->perm_hwaddr) && |
1993 | bond->slave_cnt > 1) | 1997 | bond->slave_cnt > 1) |
@@ -2104,8 +2108,6 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) | |||
2104 | netif_addr_unlock_bh(bond_dev); | 2108 | netif_addr_unlock_bh(bond_dev); |
2105 | } | 2109 | } |
2106 | 2110 | ||
2107 | netdev_rx_handler_unregister(slave_dev); | ||
2108 | synchronize_net(); | ||
2109 | netdev_set_bond_master(slave_dev, NULL); | 2111 | netdev_set_bond_master(slave_dev, NULL); |
2110 | 2112 | ||
2111 | slave_disable_netpoll(slave); | 2113 | slave_disable_netpoll(slave); |
@@ -2186,6 +2188,12 @@ static int bond_release_all(struct net_device *bond_dev) | |||
2186 | */ | 2188 | */ |
2187 | write_unlock_bh(&bond->lock); | 2189 | write_unlock_bh(&bond->lock); |
2188 | 2190 | ||
2191 | /* unregister rx_handler early so bond_handle_frame wouldn't | ||
2192 | * be called for this slave anymore. | ||
2193 | */ | ||
2194 | netdev_rx_handler_unregister(slave_dev); | ||
2195 | synchronize_net(); | ||
2196 | |||
2189 | if (bond_is_lb(bond)) { | 2197 | if (bond_is_lb(bond)) { |
2190 | /* must be called only after the slave | 2198 | /* must be called only after the slave |
2191 | * has been detached from the list | 2199 | * has been detached from the list |
@@ -2217,8 +2225,6 @@ static int bond_release_all(struct net_device *bond_dev) | |||
2217 | netif_addr_unlock_bh(bond_dev); | 2225 | netif_addr_unlock_bh(bond_dev); |
2218 | } | 2226 | } |
2219 | 2227 | ||
2220 | netdev_rx_handler_unregister(slave_dev); | ||
2221 | synchronize_net(); | ||
2222 | netdev_set_bond_master(slave_dev, NULL); | 2228 | netdev_set_bond_master(slave_dev, NULL); |
2223 | 2229 | ||
2224 | slave_disable_netpoll(slave); | 2230 | slave_disable_netpoll(slave); |
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 6b26962fd0ec..90736cb4d975 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h | |||
@@ -187,6 +187,7 @@ struct slave { | |||
187 | struct net_device *dev; /* first - useful for panic debug */ | 187 | struct net_device *dev; /* first - useful for panic debug */ |
188 | struct slave *next; | 188 | struct slave *next; |
189 | struct slave *prev; | 189 | struct slave *prev; |
190 | struct bonding *bond; /* our master */ | ||
190 | int delay; | 191 | int delay; |
191 | unsigned long jiffies; | 192 | unsigned long jiffies; |
192 | unsigned long last_arp_rx; | 193 | unsigned long last_arp_rx; |
diff --git a/drivers/net/davinci_cpdma.c b/drivers/net/davinci_cpdma.c index e92b2b6cd8c4..ae47f23ba930 100644 --- a/drivers/net/davinci_cpdma.c +++ b/drivers/net/davinci_cpdma.c | |||
@@ -76,6 +76,7 @@ struct cpdma_desc { | |||
76 | 76 | ||
77 | struct cpdma_desc_pool { | 77 | struct cpdma_desc_pool { |
78 | u32 phys; | 78 | u32 phys; |
79 | u32 hw_addr; | ||
79 | void __iomem *iomap; /* ioremap map */ | 80 | void __iomem *iomap; /* ioremap map */ |
80 | void *cpumap; /* dma_alloc map */ | 81 | void *cpumap; /* dma_alloc map */ |
81 | int desc_size, mem_size; | 82 | int desc_size, mem_size; |
@@ -137,7 +138,8 @@ struct cpdma_chan { | |||
137 | * abstract out these details | 138 | * abstract out these details |
138 | */ | 139 | */ |
139 | static struct cpdma_desc_pool * | 140 | static struct cpdma_desc_pool * |
140 | cpdma_desc_pool_create(struct device *dev, u32 phys, int size, int align) | 141 | cpdma_desc_pool_create(struct device *dev, u32 phys, u32 hw_addr, |
142 | int size, int align) | ||
141 | { | 143 | { |
142 | int bitmap_size; | 144 | int bitmap_size; |
143 | struct cpdma_desc_pool *pool; | 145 | struct cpdma_desc_pool *pool; |
@@ -161,10 +163,12 @@ cpdma_desc_pool_create(struct device *dev, u32 phys, int size, int align) | |||
161 | if (phys) { | 163 | if (phys) { |
162 | pool->phys = phys; | 164 | pool->phys = phys; |
163 | pool->iomap = ioremap(phys, size); | 165 | pool->iomap = ioremap(phys, size); |
166 | pool->hw_addr = hw_addr; | ||
164 | } else { | 167 | } else { |
165 | pool->cpumap = dma_alloc_coherent(dev, size, &pool->phys, | 168 | pool->cpumap = dma_alloc_coherent(dev, size, &pool->phys, |
166 | GFP_KERNEL); | 169 | GFP_KERNEL); |
167 | pool->iomap = (void __force __iomem *)pool->cpumap; | 170 | pool->iomap = (void __force __iomem *)pool->cpumap; |
171 | pool->hw_addr = pool->phys; | ||
168 | } | 172 | } |
169 | 173 | ||
170 | if (pool->iomap) | 174 | if (pool->iomap) |
@@ -201,14 +205,14 @@ static inline dma_addr_t desc_phys(struct cpdma_desc_pool *pool, | |||
201 | { | 205 | { |
202 | if (!desc) | 206 | if (!desc) |
203 | return 0; | 207 | return 0; |
204 | return pool->phys + (__force dma_addr_t)desc - | 208 | return pool->hw_addr + (__force dma_addr_t)desc - |
205 | (__force dma_addr_t)pool->iomap; | 209 | (__force dma_addr_t)pool->iomap; |
206 | } | 210 | } |
207 | 211 | ||
208 | static inline struct cpdma_desc __iomem * | 212 | static inline struct cpdma_desc __iomem * |
209 | desc_from_phys(struct cpdma_desc_pool *pool, dma_addr_t dma) | 213 | desc_from_phys(struct cpdma_desc_pool *pool, dma_addr_t dma) |
210 | { | 214 | { |
211 | return dma ? pool->iomap + dma - pool->phys : NULL; | 215 | return dma ? pool->iomap + dma - pool->hw_addr : NULL; |
212 | } | 216 | } |
213 | 217 | ||
214 | static struct cpdma_desc __iomem * | 218 | static struct cpdma_desc __iomem * |
@@ -260,6 +264,7 @@ struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params) | |||
260 | 264 | ||
261 | ctlr->pool = cpdma_desc_pool_create(ctlr->dev, | 265 | ctlr->pool = cpdma_desc_pool_create(ctlr->dev, |
262 | ctlr->params.desc_mem_phys, | 266 | ctlr->params.desc_mem_phys, |
267 | ctlr->params.desc_hw_addr, | ||
263 | ctlr->params.desc_mem_size, | 268 | ctlr->params.desc_mem_size, |
264 | ctlr->params.desc_align); | 269 | ctlr->params.desc_align); |
265 | if (!ctlr->pool) { | 270 | if (!ctlr->pool) { |
diff --git a/drivers/net/davinci_cpdma.h b/drivers/net/davinci_cpdma.h index 868e50ebde45..afa19a0c0d81 100644 --- a/drivers/net/davinci_cpdma.h +++ b/drivers/net/davinci_cpdma.h | |||
@@ -33,6 +33,7 @@ struct cpdma_params { | |||
33 | bool has_soft_reset; | 33 | bool has_soft_reset; |
34 | int min_packet_size; | 34 | int min_packet_size; |
35 | u32 desc_mem_phys; | 35 | u32 desc_mem_phys; |
36 | u32 desc_hw_addr; | ||
36 | int desc_mem_size; | 37 | int desc_mem_size; |
37 | int desc_align; | 38 | int desc_align; |
38 | 39 | ||
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 082d6ea69920..baca6bfcb089 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c | |||
@@ -1854,10 +1854,13 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev) | |||
1854 | dma_params.rxcp = priv->emac_base + 0x660; | 1854 | dma_params.rxcp = priv->emac_base + 0x660; |
1855 | dma_params.num_chan = EMAC_MAX_TXRX_CHANNELS; | 1855 | dma_params.num_chan = EMAC_MAX_TXRX_CHANNELS; |
1856 | dma_params.min_packet_size = EMAC_DEF_MIN_ETHPKTSIZE; | 1856 | dma_params.min_packet_size = EMAC_DEF_MIN_ETHPKTSIZE; |
1857 | dma_params.desc_mem_phys = hw_ram_addr; | 1857 | dma_params.desc_hw_addr = hw_ram_addr; |
1858 | dma_params.desc_mem_size = pdata->ctrl_ram_size; | 1858 | dma_params.desc_mem_size = pdata->ctrl_ram_size; |
1859 | dma_params.desc_align = 16; | 1859 | dma_params.desc_align = 16; |
1860 | 1860 | ||
1861 | dma_params.desc_mem_phys = pdata->no_bd_ram ? 0 : | ||
1862 | (u32 __force)res->start + pdata->ctrl_ram_offset; | ||
1863 | |||
1861 | priv->dma = cpdma_ctlr_create(&dma_params); | 1864 | priv->dma = cpdma_ctlr_create(&dma_params); |
1862 | if (!priv->dma) { | 1865 | if (!priv->dma) { |
1863 | dev_err(emac_dev, "DaVinci EMAC: Error initializing DMA\n"); | 1866 | dev_err(emac_dev, "DaVinci EMAC: Error initializing DMA\n"); |
diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/mlx4/alloc.c index 3a4277f6fac4..116cae334dad 100644 --- a/drivers/net/mlx4/alloc.c +++ b/drivers/net/mlx4/alloc.c | |||
@@ -62,6 +62,9 @@ u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap) | |||
62 | } else | 62 | } else |
63 | obj = -1; | 63 | obj = -1; |
64 | 64 | ||
65 | if (obj != -1) | ||
66 | --bitmap->avail; | ||
67 | |||
65 | spin_unlock(&bitmap->lock); | 68 | spin_unlock(&bitmap->lock); |
66 | 69 | ||
67 | return obj; | 70 | return obj; |
@@ -101,11 +104,19 @@ u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align) | |||
101 | } else | 104 | } else |
102 | obj = -1; | 105 | obj = -1; |
103 | 106 | ||
107 | if (obj != -1) | ||
108 | bitmap->avail -= cnt; | ||
109 | |||
104 | spin_unlock(&bitmap->lock); | 110 | spin_unlock(&bitmap->lock); |
105 | 111 | ||
106 | return obj; | 112 | return obj; |
107 | } | 113 | } |
108 | 114 | ||
115 | u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap) | ||
116 | { | ||
117 | return bitmap->avail; | ||
118 | } | ||
119 | |||
109 | void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt) | 120 | void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt) |
110 | { | 121 | { |
111 | obj &= bitmap->max + bitmap->reserved_top - 1; | 122 | obj &= bitmap->max + bitmap->reserved_top - 1; |
@@ -115,6 +126,7 @@ void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt) | |||
115 | bitmap->last = min(bitmap->last, obj); | 126 | bitmap->last = min(bitmap->last, obj); |
116 | bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) | 127 | bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) |
117 | & bitmap->mask; | 128 | & bitmap->mask; |
129 | bitmap->avail += cnt; | ||
118 | spin_unlock(&bitmap->lock); | 130 | spin_unlock(&bitmap->lock); |
119 | } | 131 | } |
120 | 132 | ||
@@ -130,6 +142,7 @@ int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, | |||
130 | bitmap->max = num - reserved_top; | 142 | bitmap->max = num - reserved_top; |
131 | bitmap->mask = mask; | 143 | bitmap->mask = mask; |
132 | bitmap->reserved_top = reserved_top; | 144 | bitmap->reserved_top = reserved_top; |
145 | bitmap->avail = num - reserved_top - reserved_bot; | ||
133 | spin_lock_init(&bitmap->lock); | 146 | spin_lock_init(&bitmap->lock); |
134 | bitmap->table = kzalloc(BITS_TO_LONGS(bitmap->max) * | 147 | bitmap->table = kzalloc(BITS_TO_LONGS(bitmap->max) * |
135 | sizeof (long), GFP_KERNEL); | 148 | sizeof (long), GFP_KERNEL); |
diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c index 7cd34e9c7c7e..bd8ef9f2fa71 100644 --- a/drivers/net/mlx4/cq.c +++ b/drivers/net/mlx4/cq.c | |||
@@ -198,7 +198,7 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, | |||
198 | u64 mtt_addr; | 198 | u64 mtt_addr; |
199 | int err; | 199 | int err; |
200 | 200 | ||
201 | if (vector >= dev->caps.num_comp_vectors) | 201 | if (vector > dev->caps.num_comp_vectors + dev->caps.comp_pool) |
202 | return -EINVAL; | 202 | return -EINVAL; |
203 | 203 | ||
204 | cq->vector = vector; | 204 | cq->vector = vector; |
diff --git a/drivers/net/mlx4/en_cq.c b/drivers/net/mlx4/en_cq.c index 21786ad4455e..ec4b6d047fe0 100644 --- a/drivers/net/mlx4/en_cq.c +++ b/drivers/net/mlx4/en_cq.c | |||
@@ -51,13 +51,10 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv, | |||
51 | int err; | 51 | int err; |
52 | 52 | ||
53 | cq->size = entries; | 53 | cq->size = entries; |
54 | if (mode == RX) { | 54 | if (mode == RX) |
55 | cq->buf_size = cq->size * sizeof(struct mlx4_cqe); | 55 | cq->buf_size = cq->size * sizeof(struct mlx4_cqe); |
56 | cq->vector = ring % mdev->dev->caps.num_comp_vectors; | 56 | else |
57 | } else { | ||
58 | cq->buf_size = sizeof(struct mlx4_cqe); | 57 | cq->buf_size = sizeof(struct mlx4_cqe); |
59 | cq->vector = 0; | ||
60 | } | ||
61 | 58 | ||
62 | cq->ring = ring; | 59 | cq->ring = ring; |
63 | cq->is_tx = mode; | 60 | cq->is_tx = mode; |
@@ -80,7 +77,8 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv, | |||
80 | int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) | 77 | int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) |
81 | { | 78 | { |
82 | struct mlx4_en_dev *mdev = priv->mdev; | 79 | struct mlx4_en_dev *mdev = priv->mdev; |
83 | int err; | 80 | int err = 0; |
81 | char name[25]; | ||
84 | 82 | ||
85 | cq->dev = mdev->pndev[priv->port]; | 83 | cq->dev = mdev->pndev[priv->port]; |
86 | cq->mcq.set_ci_db = cq->wqres.db.db; | 84 | cq->mcq.set_ci_db = cq->wqres.db.db; |
@@ -89,6 +87,29 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) | |||
89 | *cq->mcq.arm_db = 0; | 87 | *cq->mcq.arm_db = 0; |
90 | memset(cq->buf, 0, cq->buf_size); | 88 | memset(cq->buf, 0, cq->buf_size); |
91 | 89 | ||
90 | if (cq->is_tx == RX) { | ||
91 | if (mdev->dev->caps.comp_pool) { | ||
92 | if (!cq->vector) { | ||
93 | sprintf(name , "%s-rx-%d", priv->dev->name, cq->ring); | ||
94 | if (mlx4_assign_eq(mdev->dev, name, &cq->vector)) { | ||
95 | cq->vector = (cq->ring + 1 + priv->port) % | ||
96 | mdev->dev->caps.num_comp_vectors; | ||
97 | mlx4_warn(mdev, "Failed Assigning an EQ to " | ||
98 | "%s_rx-%d ,Falling back to legacy EQ's\n", | ||
99 | priv->dev->name, cq->ring); | ||
100 | } | ||
101 | } | ||
102 | } else { | ||
103 | cq->vector = (cq->ring + 1 + priv->port) % | ||
104 | mdev->dev->caps.num_comp_vectors; | ||
105 | } | ||
106 | } else { | ||
107 | if (!cq->vector || !mdev->dev->caps.comp_pool) { | ||
108 | /*Fallback to legacy pool in case of error*/ | ||
109 | cq->vector = 0; | ||
110 | } | ||
111 | } | ||
112 | |||
92 | if (!cq->is_tx) | 113 | if (!cq->is_tx) |
93 | cq->size = priv->rx_ring[cq->ring].actual_size; | 114 | cq->size = priv->rx_ring[cq->ring].actual_size; |
94 | 115 | ||
@@ -112,12 +133,15 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) | |||
112 | return 0; | 133 | return 0; |
113 | } | 134 | } |
114 | 135 | ||
115 | void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) | 136 | void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, |
137 | bool reserve_vectors) | ||
116 | { | 138 | { |
117 | struct mlx4_en_dev *mdev = priv->mdev; | 139 | struct mlx4_en_dev *mdev = priv->mdev; |
118 | 140 | ||
119 | mlx4_en_unmap_buffer(&cq->wqres.buf); | 141 | mlx4_en_unmap_buffer(&cq->wqres.buf); |
120 | mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); | 142 | mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); |
143 | if (priv->mdev->dev->caps.comp_pool && cq->vector && !reserve_vectors) | ||
144 | mlx4_release_eq(priv->mdev->dev, cq->vector); | ||
121 | cq->buf_size = 0; | 145 | cq->buf_size = 0; |
122 | cq->buf = NULL; | 146 | cq->buf = NULL; |
123 | } | 147 | } |
diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c index 056152b3ff58..d54b7abf0225 100644 --- a/drivers/net/mlx4/en_ethtool.c +++ b/drivers/net/mlx4/en_ethtool.c | |||
@@ -45,7 +45,7 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) | |||
45 | struct mlx4_en_priv *priv = netdev_priv(dev); | 45 | struct mlx4_en_priv *priv = netdev_priv(dev); |
46 | struct mlx4_en_dev *mdev = priv->mdev; | 46 | struct mlx4_en_dev *mdev = priv->mdev; |
47 | 47 | ||
48 | sprintf(drvinfo->driver, DRV_NAME " (%s)", mdev->dev->board_id); | 48 | strncpy(drvinfo->driver, DRV_NAME, 32); |
49 | strncpy(drvinfo->version, DRV_VERSION " (" DRV_RELDATE ")", 32); | 49 | strncpy(drvinfo->version, DRV_VERSION " (" DRV_RELDATE ")", 32); |
50 | sprintf(drvinfo->fw_version, "%d.%d.%d", | 50 | sprintf(drvinfo->fw_version, "%d.%d.%d", |
51 | (u16) (mdev->dev->caps.fw_ver >> 32), | 51 | (u16) (mdev->dev->caps.fw_ver >> 32), |
@@ -131,8 +131,65 @@ static void mlx4_en_set_msglevel(struct net_device *dev, u32 val) | |||
131 | static void mlx4_en_get_wol(struct net_device *netdev, | 131 | static void mlx4_en_get_wol(struct net_device *netdev, |
132 | struct ethtool_wolinfo *wol) | 132 | struct ethtool_wolinfo *wol) |
133 | { | 133 | { |
134 | wol->supported = 0; | 134 | struct mlx4_en_priv *priv = netdev_priv(netdev); |
135 | wol->wolopts = 0; | 135 | int err = 0; |
136 | u64 config = 0; | ||
137 | |||
138 | if (!priv->mdev->dev->caps.wol) { | ||
139 | wol->supported = 0; | ||
140 | wol->wolopts = 0; | ||
141 | return; | ||
142 | } | ||
143 | |||
144 | err = mlx4_wol_read(priv->mdev->dev, &config, priv->port); | ||
145 | if (err) { | ||
146 | en_err(priv, "Failed to get WoL information\n"); | ||
147 | return; | ||
148 | } | ||
149 | |||
150 | if (config & MLX4_EN_WOL_MAGIC) | ||
151 | wol->supported = WAKE_MAGIC; | ||
152 | else | ||
153 | wol->supported = 0; | ||
154 | |||
155 | if (config & MLX4_EN_WOL_ENABLED) | ||
156 | wol->wolopts = WAKE_MAGIC; | ||
157 | else | ||
158 | wol->wolopts = 0; | ||
159 | } | ||
160 | |||
161 | static int mlx4_en_set_wol(struct net_device *netdev, | ||
162 | struct ethtool_wolinfo *wol) | ||
163 | { | ||
164 | struct mlx4_en_priv *priv = netdev_priv(netdev); | ||
165 | u64 config = 0; | ||
166 | int err = 0; | ||
167 | |||
168 | if (!priv->mdev->dev->caps.wol) | ||
169 | return -EOPNOTSUPP; | ||
170 | |||
171 | if (wol->supported & ~WAKE_MAGIC) | ||
172 | return -EINVAL; | ||
173 | |||
174 | err = mlx4_wol_read(priv->mdev->dev, &config, priv->port); | ||
175 | if (err) { | ||
176 | en_err(priv, "Failed to get WoL info, unable to modify\n"); | ||
177 | return err; | ||
178 | } | ||
179 | |||
180 | if (wol->wolopts & WAKE_MAGIC) { | ||
181 | config |= MLX4_EN_WOL_DO_MODIFY | MLX4_EN_WOL_ENABLED | | ||
182 | MLX4_EN_WOL_MAGIC; | ||
183 | } else { | ||
184 | config &= ~(MLX4_EN_WOL_ENABLED | MLX4_EN_WOL_MAGIC); | ||
185 | config |= MLX4_EN_WOL_DO_MODIFY; | ||
186 | } | ||
187 | |||
188 | err = mlx4_wol_write(priv->mdev->dev, config, priv->port); | ||
189 | if (err) | ||
190 | en_err(priv, "Failed to set WoL information\n"); | ||
191 | |||
192 | return err; | ||
136 | } | 193 | } |
137 | 194 | ||
138 | static int mlx4_en_get_sset_count(struct net_device *dev, int sset) | 195 | static int mlx4_en_get_sset_count(struct net_device *dev, int sset) |
@@ -388,7 +445,7 @@ static int mlx4_en_set_ringparam(struct net_device *dev, | |||
388 | mlx4_en_stop_port(dev); | 445 | mlx4_en_stop_port(dev); |
389 | } | 446 | } |
390 | 447 | ||
391 | mlx4_en_free_resources(priv); | 448 | mlx4_en_free_resources(priv, true); |
392 | 449 | ||
393 | priv->prof->tx_ring_size = tx_size; | 450 | priv->prof->tx_ring_size = tx_size; |
394 | priv->prof->rx_ring_size = rx_size; | 451 | priv->prof->rx_ring_size = rx_size; |
@@ -442,6 +499,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { | |||
442 | .get_ethtool_stats = mlx4_en_get_ethtool_stats, | 499 | .get_ethtool_stats = mlx4_en_get_ethtool_stats, |
443 | .self_test = mlx4_en_self_test, | 500 | .self_test = mlx4_en_self_test, |
444 | .get_wol = mlx4_en_get_wol, | 501 | .get_wol = mlx4_en_get_wol, |
502 | .set_wol = mlx4_en_set_wol, | ||
445 | .get_msglevel = mlx4_en_get_msglevel, | 503 | .get_msglevel = mlx4_en_get_msglevel, |
446 | .set_msglevel = mlx4_en_set_msglevel, | 504 | .set_msglevel = mlx4_en_set_msglevel, |
447 | .get_coalesce = mlx4_en_get_coalesce, | 505 | .get_coalesce = mlx4_en_get_coalesce, |
diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c index 1ff6ca6466ed..9317b61a75b8 100644 --- a/drivers/net/mlx4/en_main.c +++ b/drivers/net/mlx4/en_main.c | |||
@@ -241,16 +241,18 @@ static void *mlx4_en_add(struct mlx4_dev *dev) | |||
241 | mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) | 241 | mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) |
242 | mdev->port_cnt++; | 242 | mdev->port_cnt++; |
243 | 243 | ||
244 | /* If we did not receive an explicit number of Rx rings, default to | ||
245 | * the number of completion vectors populated by the mlx4_core */ | ||
246 | mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { | 244 | mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { |
247 | mlx4_info(mdev, "Using %d tx rings for port:%d\n", | 245 | if (!dev->caps.comp_pool) { |
248 | mdev->profile.prof[i].tx_ring_num, i); | 246 | mdev->profile.prof[i].rx_ring_num = |
249 | mdev->profile.prof[i].rx_ring_num = min_t(int, | 247 | rounddown_pow_of_two(max_t(int, MIN_RX_RINGS, |
250 | roundup_pow_of_two(dev->caps.num_comp_vectors), | 248 | min_t(int, |
251 | MAX_RX_RINGS); | 249 | dev->caps.num_comp_vectors, |
252 | mlx4_info(mdev, "Defaulting to %d rx rings for port:%d\n", | 250 | MAX_RX_RINGS))); |
253 | mdev->profile.prof[i].rx_ring_num, i); | 251 | } else { |
252 | mdev->profile.prof[i].rx_ring_num = rounddown_pow_of_two( | ||
253 | min_t(int, dev->caps.comp_pool/ | ||
254 | dev->caps.num_ports - 1 , MAX_MSIX_P_PORT - 1)); | ||
255 | } | ||
254 | } | 256 | } |
255 | 257 | ||
256 | /* Create our own workqueue for reset/multicast tasks | 258 | /* Create our own workqueue for reset/multicast tasks |
@@ -294,7 +296,7 @@ static struct mlx4_interface mlx4_en_interface = { | |||
294 | .remove = mlx4_en_remove, | 296 | .remove = mlx4_en_remove, |
295 | .event = mlx4_en_event, | 297 | .event = mlx4_en_event, |
296 | .get_dev = mlx4_en_get_netdev, | 298 | .get_dev = mlx4_en_get_netdev, |
297 | .protocol = MLX4_PROTOCOL_EN, | 299 | .protocol = MLX4_PROT_ETH, |
298 | }; | 300 | }; |
299 | 301 | ||
300 | static int __init mlx4_en_init(void) | 302 | static int __init mlx4_en_init(void) |
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 897f576b8b17..5762ebde4455 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c | |||
@@ -156,9 +156,8 @@ static void mlx4_en_do_set_mac(struct work_struct *work) | |||
156 | mutex_lock(&mdev->state_lock); | 156 | mutex_lock(&mdev->state_lock); |
157 | if (priv->port_up) { | 157 | if (priv->port_up) { |
158 | /* Remove old MAC and insert the new one */ | 158 | /* Remove old MAC and insert the new one */ |
159 | mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index); | 159 | err = mlx4_replace_mac(mdev->dev, priv->port, |
160 | err = mlx4_register_mac(mdev->dev, priv->port, | 160 | priv->base_qpn, priv->mac, 0); |
161 | priv->mac, &priv->mac_index); | ||
162 | if (err) | 161 | if (err) |
163 | en_err(priv, "Failed changing HW MAC address\n"); | 162 | en_err(priv, "Failed changing HW MAC address\n"); |
164 | } else | 163 | } else |
@@ -214,6 +213,7 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) | |||
214 | struct mlx4_en_dev *mdev = priv->mdev; | 213 | struct mlx4_en_dev *mdev = priv->mdev; |
215 | struct net_device *dev = priv->dev; | 214 | struct net_device *dev = priv->dev; |
216 | u64 mcast_addr = 0; | 215 | u64 mcast_addr = 0; |
216 | u8 mc_list[16] = {0}; | ||
217 | int err; | 217 | int err; |
218 | 218 | ||
219 | mutex_lock(&mdev->state_lock); | 219 | mutex_lock(&mdev->state_lock); |
@@ -239,8 +239,12 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) | |||
239 | priv->flags |= MLX4_EN_FLAG_PROMISC; | 239 | priv->flags |= MLX4_EN_FLAG_PROMISC; |
240 | 240 | ||
241 | /* Enable promiscouos mode */ | 241 | /* Enable promiscouos mode */ |
242 | err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, | 242 | if (!mdev->dev->caps.vep_uc_steering) |
243 | priv->base_qpn, 1); | 243 | err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, |
244 | priv->base_qpn, 1); | ||
245 | else | ||
246 | err = mlx4_unicast_promisc_add(mdev->dev, priv->base_qpn, | ||
247 | priv->port); | ||
244 | if (err) | 248 | if (err) |
245 | en_err(priv, "Failed enabling " | 249 | en_err(priv, "Failed enabling " |
246 | "promiscous mode\n"); | 250 | "promiscous mode\n"); |
@@ -252,10 +256,21 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) | |||
252 | en_err(priv, "Failed disabling " | 256 | en_err(priv, "Failed disabling " |
253 | "multicast filter\n"); | 257 | "multicast filter\n"); |
254 | 258 | ||
255 | /* Disable port VLAN filter */ | 259 | /* Add the default qp number as multicast promisc */ |
256 | err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, NULL); | 260 | if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) { |
257 | if (err) | 261 | err = mlx4_multicast_promisc_add(mdev->dev, priv->base_qpn, |
258 | en_err(priv, "Failed disabling VLAN filter\n"); | 262 | priv->port); |
263 | if (err) | ||
264 | en_err(priv, "Failed entering multicast promisc mode\n"); | ||
265 | priv->flags |= MLX4_EN_FLAG_MC_PROMISC; | ||
266 | } | ||
267 | |||
268 | if (priv->vlgrp) { | ||
269 | /* Disable port VLAN filter */ | ||
270 | err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, NULL); | ||
271 | if (err) | ||
272 | en_err(priv, "Failed disabling VLAN filter\n"); | ||
273 | } | ||
259 | } | 274 | } |
260 | goto out; | 275 | goto out; |
261 | } | 276 | } |
@@ -270,11 +285,24 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) | |||
270 | priv->flags &= ~MLX4_EN_FLAG_PROMISC; | 285 | priv->flags &= ~MLX4_EN_FLAG_PROMISC; |
271 | 286 | ||
272 | /* Disable promiscouos mode */ | 287 | /* Disable promiscouos mode */ |
273 | err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, | 288 | if (!mdev->dev->caps.vep_uc_steering) |
274 | priv->base_qpn, 0); | 289 | err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, |
290 | priv->base_qpn, 0); | ||
291 | else | ||
292 | err = mlx4_unicast_promisc_remove(mdev->dev, priv->base_qpn, | ||
293 | priv->port); | ||
275 | if (err) | 294 | if (err) |
276 | en_err(priv, "Failed disabling promiscous mode\n"); | 295 | en_err(priv, "Failed disabling promiscous mode\n"); |
277 | 296 | ||
297 | /* Disable Multicast promisc */ | ||
298 | if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { | ||
299 | err = mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn, | ||
300 | priv->port); | ||
301 | if (err) | ||
302 | en_err(priv, "Failed disabling multicast promiscous mode\n"); | ||
303 | priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; | ||
304 | } | ||
305 | |||
278 | /* Enable port VLAN filter */ | 306 | /* Enable port VLAN filter */ |
279 | err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp); | 307 | err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp); |
280 | if (err) | 308 | if (err) |
@@ -287,14 +315,38 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) | |||
287 | 0, MLX4_MCAST_DISABLE); | 315 | 0, MLX4_MCAST_DISABLE); |
288 | if (err) | 316 | if (err) |
289 | en_err(priv, "Failed disabling multicast filter\n"); | 317 | en_err(priv, "Failed disabling multicast filter\n"); |
318 | |||
319 | /* Add the default qp number as multicast promisc */ | ||
320 | if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) { | ||
321 | err = mlx4_multicast_promisc_add(mdev->dev, priv->base_qpn, | ||
322 | priv->port); | ||
323 | if (err) | ||
324 | en_err(priv, "Failed entering multicast promisc mode\n"); | ||
325 | priv->flags |= MLX4_EN_FLAG_MC_PROMISC; | ||
326 | } | ||
290 | } else { | 327 | } else { |
291 | int i; | 328 | int i; |
329 | /* Disable Multicast promisc */ | ||
330 | if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { | ||
331 | err = mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn, | ||
332 | priv->port); | ||
333 | if (err) | ||
334 | en_err(priv, "Failed disabling multicast promiscous mode\n"); | ||
335 | priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; | ||
336 | } | ||
292 | 337 | ||
293 | err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, | 338 | err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, |
294 | 0, MLX4_MCAST_DISABLE); | 339 | 0, MLX4_MCAST_DISABLE); |
295 | if (err) | 340 | if (err) |
296 | en_err(priv, "Failed disabling multicast filter\n"); | 341 | en_err(priv, "Failed disabling multicast filter\n"); |
297 | 342 | ||
343 | /* Detach our qp from all the multicast addresses */ | ||
344 | for (i = 0; i < priv->mc_addrs_cnt; i++) { | ||
345 | memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN); | ||
346 | mc_list[5] = priv->port; | ||
347 | mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, | ||
348 | mc_list, MLX4_PROT_ETH); | ||
349 | } | ||
298 | /* Flush mcast filter and init it with broadcast address */ | 350 | /* Flush mcast filter and init it with broadcast address */ |
299 | mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST, | 351 | mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST, |
300 | 1, MLX4_MCAST_CONFIG); | 352 | 1, MLX4_MCAST_CONFIG); |
@@ -307,6 +359,10 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) | |||
307 | for (i = 0; i < priv->mc_addrs_cnt; i++) { | 359 | for (i = 0; i < priv->mc_addrs_cnt; i++) { |
308 | mcast_addr = | 360 | mcast_addr = |
309 | mlx4_en_mac_to_u64(priv->mc_addrs + i * ETH_ALEN); | 361 | mlx4_en_mac_to_u64(priv->mc_addrs + i * ETH_ALEN); |
362 | memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN); | ||
363 | mc_list[5] = priv->port; | ||
364 | mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp, | ||
365 | mc_list, 0, MLX4_PROT_ETH); | ||
310 | mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, | 366 | mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, |
311 | mcast_addr, 0, MLX4_MCAST_CONFIG); | 367 | mcast_addr, 0, MLX4_MCAST_CONFIG); |
312 | } | 368 | } |
@@ -314,8 +370,6 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) | |||
314 | 0, MLX4_MCAST_ENABLE); | 370 | 0, MLX4_MCAST_ENABLE); |
315 | if (err) | 371 | if (err) |
316 | en_err(priv, "Failed enabling multicast filter\n"); | 372 | en_err(priv, "Failed enabling multicast filter\n"); |
317 | |||
318 | mlx4_en_clear_list(dev); | ||
319 | } | 373 | } |
320 | out: | 374 | out: |
321 | mutex_unlock(&mdev->state_lock); | 375 | mutex_unlock(&mdev->state_lock); |
@@ -417,7 +471,6 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) | |||
417 | unsigned long avg_pkt_size; | 471 | unsigned long avg_pkt_size; |
418 | unsigned long rx_packets; | 472 | unsigned long rx_packets; |
419 | unsigned long rx_bytes; | 473 | unsigned long rx_bytes; |
420 | unsigned long rx_byte_diff; | ||
421 | unsigned long tx_packets; | 474 | unsigned long tx_packets; |
422 | unsigned long tx_pkt_diff; | 475 | unsigned long tx_pkt_diff; |
423 | unsigned long rx_pkt_diff; | 476 | unsigned long rx_pkt_diff; |
@@ -441,25 +494,20 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) | |||
441 | rx_pkt_diff = ((unsigned long) (rx_packets - | 494 | rx_pkt_diff = ((unsigned long) (rx_packets - |
442 | priv->last_moder_packets)); | 495 | priv->last_moder_packets)); |
443 | packets = max(tx_pkt_diff, rx_pkt_diff); | 496 | packets = max(tx_pkt_diff, rx_pkt_diff); |
444 | rx_byte_diff = rx_bytes - priv->last_moder_bytes; | ||
445 | rx_byte_diff = rx_byte_diff ? rx_byte_diff : 1; | ||
446 | rate = packets * HZ / period; | 497 | rate = packets * HZ / period; |
447 | avg_pkt_size = packets ? ((unsigned long) (rx_bytes - | 498 | avg_pkt_size = packets ? ((unsigned long) (rx_bytes - |
448 | priv->last_moder_bytes)) / packets : 0; | 499 | priv->last_moder_bytes)) / packets : 0; |
449 | 500 | ||
450 | /* Apply auto-moderation only when packet rate exceeds a rate that | 501 | /* Apply auto-moderation only when packet rate exceeds a rate that |
451 | * it matters */ | 502 | * it matters */ |
452 | if (rate > MLX4_EN_RX_RATE_THRESH) { | 503 | if (rate > MLX4_EN_RX_RATE_THRESH && avg_pkt_size > MLX4_EN_AVG_PKT_SMALL) { |
453 | /* If tx and rx packet rates are not balanced, assume that | 504 | /* If tx and rx packet rates are not balanced, assume that |
454 | * traffic is mainly BW bound and apply maximum moderation. | 505 | * traffic is mainly BW bound and apply maximum moderation. |
455 | * Otherwise, moderate according to packet rate */ | 506 | * Otherwise, moderate according to packet rate */ |
456 | if (2 * tx_pkt_diff > 3 * rx_pkt_diff && | 507 | if (2 * tx_pkt_diff > 3 * rx_pkt_diff || |
457 | rx_pkt_diff / rx_byte_diff < | 508 | 2 * rx_pkt_diff > 3 * tx_pkt_diff) { |
458 | MLX4_EN_SMALL_PKT_SIZE) | ||
459 | moder_time = priv->rx_usecs_low; | ||
460 | else if (2 * rx_pkt_diff > 3 * tx_pkt_diff) | ||
461 | moder_time = priv->rx_usecs_high; | 509 | moder_time = priv->rx_usecs_high; |
462 | else { | 510 | } else { |
463 | if (rate < priv->pkt_rate_low) | 511 | if (rate < priv->pkt_rate_low) |
464 | moder_time = priv->rx_usecs_low; | 512 | moder_time = priv->rx_usecs_low; |
465 | else if (rate > priv->pkt_rate_high) | 513 | else if (rate > priv->pkt_rate_high) |
@@ -471,9 +519,7 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) | |||
471 | priv->rx_usecs_low; | 519 | priv->rx_usecs_low; |
472 | } | 520 | } |
473 | } else { | 521 | } else { |
474 | /* When packet rate is low, use default moderation rather than | 522 | moder_time = priv->rx_usecs_low; |
475 | * 0 to prevent interrupt storms if traffic suddenly increases */ | ||
476 | moder_time = priv->rx_usecs; | ||
477 | } | 523 | } |
478 | 524 | ||
479 | en_dbg(INTR, priv, "tx rate:%lu rx_rate:%lu\n", | 525 | en_dbg(INTR, priv, "tx rate:%lu rx_rate:%lu\n", |
@@ -565,6 +611,8 @@ int mlx4_en_start_port(struct net_device *dev) | |||
565 | int err = 0; | 611 | int err = 0; |
566 | int i; | 612 | int i; |
567 | int j; | 613 | int j; |
614 | u8 mc_list[16] = {0}; | ||
615 | char name[32]; | ||
568 | 616 | ||
569 | if (priv->port_up) { | 617 | if (priv->port_up) { |
570 | en_dbg(DRV, priv, "start port called while port already up\n"); | 618 | en_dbg(DRV, priv, "start port called while port already up\n"); |
@@ -603,16 +651,35 @@ int mlx4_en_start_port(struct net_device *dev) | |||
603 | ++rx_index; | 651 | ++rx_index; |
604 | } | 652 | } |
605 | 653 | ||
654 | /* Set port mac number */ | ||
655 | en_dbg(DRV, priv, "Setting mac for port %d\n", priv->port); | ||
656 | err = mlx4_register_mac(mdev->dev, priv->port, | ||
657 | priv->mac, &priv->base_qpn, 0); | ||
658 | if (err) { | ||
659 | en_err(priv, "Failed setting port mac\n"); | ||
660 | goto cq_err; | ||
661 | } | ||
662 | mdev->mac_removed[priv->port] = 0; | ||
663 | |||
606 | err = mlx4_en_config_rss_steer(priv); | 664 | err = mlx4_en_config_rss_steer(priv); |
607 | if (err) { | 665 | if (err) { |
608 | en_err(priv, "Failed configuring rss steering\n"); | 666 | en_err(priv, "Failed configuring rss steering\n"); |
609 | goto cq_err; | 667 | goto mac_err; |
610 | } | 668 | } |
611 | 669 | ||
670 | if (mdev->dev->caps.comp_pool && !priv->tx_vector) { | ||
671 | sprintf(name , "%s-tx", priv->dev->name); | ||
672 | if (mlx4_assign_eq(mdev->dev , name, &priv->tx_vector)) { | ||
673 | mlx4_warn(mdev, "Failed Assigning an EQ to " | ||
674 | "%s_tx ,Falling back to legacy " | ||
675 | "EQ's\n", priv->dev->name); | ||
676 | } | ||
677 | } | ||
612 | /* Configure tx cq's and rings */ | 678 | /* Configure tx cq's and rings */ |
613 | for (i = 0; i < priv->tx_ring_num; i++) { | 679 | for (i = 0; i < priv->tx_ring_num; i++) { |
614 | /* Configure cq */ | 680 | /* Configure cq */ |
615 | cq = &priv->tx_cq[i]; | 681 | cq = &priv->tx_cq[i]; |
682 | cq->vector = priv->tx_vector; | ||
616 | err = mlx4_en_activate_cq(priv, cq); | 683 | err = mlx4_en_activate_cq(priv, cq); |
617 | if (err) { | 684 | if (err) { |
618 | en_err(priv, "Failed allocating Tx CQ\n"); | 685 | en_err(priv, "Failed allocating Tx CQ\n"); |
@@ -659,24 +726,22 @@ int mlx4_en_start_port(struct net_device *dev) | |||
659 | en_err(priv, "Failed setting default qp numbers\n"); | 726 | en_err(priv, "Failed setting default qp numbers\n"); |
660 | goto tx_err; | 727 | goto tx_err; |
661 | } | 728 | } |
662 | /* Set port mac number */ | ||
663 | en_dbg(DRV, priv, "Setting mac for port %d\n", priv->port); | ||
664 | err = mlx4_register_mac(mdev->dev, priv->port, | ||
665 | priv->mac, &priv->mac_index); | ||
666 | if (err) { | ||
667 | en_err(priv, "Failed setting port mac\n"); | ||
668 | goto tx_err; | ||
669 | } | ||
670 | mdev->mac_removed[priv->port] = 0; | ||
671 | 729 | ||
672 | /* Init port */ | 730 | /* Init port */ |
673 | en_dbg(HW, priv, "Initializing port\n"); | 731 | en_dbg(HW, priv, "Initializing port\n"); |
674 | err = mlx4_INIT_PORT(mdev->dev, priv->port); | 732 | err = mlx4_INIT_PORT(mdev->dev, priv->port); |
675 | if (err) { | 733 | if (err) { |
676 | en_err(priv, "Failed Initializing port\n"); | 734 | en_err(priv, "Failed Initializing port\n"); |
677 | goto mac_err; | 735 | goto tx_err; |
678 | } | 736 | } |
679 | 737 | ||
738 | /* Attach rx QP to bradcast address */ | ||
739 | memset(&mc_list[10], 0xff, ETH_ALEN); | ||
740 | mc_list[5] = priv->port; | ||
741 | if (mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp, mc_list, | ||
742 | 0, MLX4_PROT_ETH)) | ||
743 | mlx4_warn(mdev, "Failed Attaching Broadcast\n"); | ||
744 | |||
680 | /* Schedule multicast task to populate multicast list */ | 745 | /* Schedule multicast task to populate multicast list */ |
681 | queue_work(mdev->workqueue, &priv->mcast_task); | 746 | queue_work(mdev->workqueue, &priv->mcast_task); |
682 | 747 | ||
@@ -684,8 +749,6 @@ int mlx4_en_start_port(struct net_device *dev) | |||
684 | netif_tx_start_all_queues(dev); | 749 | netif_tx_start_all_queues(dev); |
685 | return 0; | 750 | return 0; |
686 | 751 | ||
687 | mac_err: | ||
688 | mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index); | ||
689 | tx_err: | 752 | tx_err: |
690 | while (tx_index--) { | 753 | while (tx_index--) { |
691 | mlx4_en_deactivate_tx_ring(priv, &priv->tx_ring[tx_index]); | 754 | mlx4_en_deactivate_tx_ring(priv, &priv->tx_ring[tx_index]); |
@@ -693,6 +756,8 @@ tx_err: | |||
693 | } | 756 | } |
694 | 757 | ||
695 | mlx4_en_release_rss_steer(priv); | 758 | mlx4_en_release_rss_steer(priv); |
759 | mac_err: | ||
760 | mlx4_unregister_mac(mdev->dev, priv->port, priv->base_qpn); | ||
696 | cq_err: | 761 | cq_err: |
697 | while (rx_index--) | 762 | while (rx_index--) |
698 | mlx4_en_deactivate_cq(priv, &priv->rx_cq[rx_index]); | 763 | mlx4_en_deactivate_cq(priv, &priv->rx_cq[rx_index]); |
@@ -708,6 +773,7 @@ void mlx4_en_stop_port(struct net_device *dev) | |||
708 | struct mlx4_en_priv *priv = netdev_priv(dev); | 773 | struct mlx4_en_priv *priv = netdev_priv(dev); |
709 | struct mlx4_en_dev *mdev = priv->mdev; | 774 | struct mlx4_en_dev *mdev = priv->mdev; |
710 | int i; | 775 | int i; |
776 | u8 mc_list[16] = {0}; | ||
711 | 777 | ||
712 | if (!priv->port_up) { | 778 | if (!priv->port_up) { |
713 | en_dbg(DRV, priv, "stop port called while port already down\n"); | 779 | en_dbg(DRV, priv, "stop port called while port already down\n"); |
@@ -722,8 +788,23 @@ void mlx4_en_stop_port(struct net_device *dev) | |||
722 | /* Set port as not active */ | 788 | /* Set port as not active */ |
723 | priv->port_up = false; | 789 | priv->port_up = false; |
724 | 790 | ||
791 | /* Detach All multicasts */ | ||
792 | memset(&mc_list[10], 0xff, ETH_ALEN); | ||
793 | mc_list[5] = priv->port; | ||
794 | mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, mc_list, | ||
795 | MLX4_PROT_ETH); | ||
796 | for (i = 0; i < priv->mc_addrs_cnt; i++) { | ||
797 | memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN); | ||
798 | mc_list[5] = priv->port; | ||
799 | mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, | ||
800 | mc_list, MLX4_PROT_ETH); | ||
801 | } | ||
802 | mlx4_en_clear_list(dev); | ||
803 | /* Flush multicast filter */ | ||
804 | mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 1, MLX4_MCAST_CONFIG); | ||
805 | |||
725 | /* Unregister Mac address for the port */ | 806 | /* Unregister Mac address for the port */ |
726 | mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index); | 807 | mlx4_unregister_mac(mdev->dev, priv->port, priv->base_qpn); |
727 | mdev->mac_removed[priv->port] = 1; | 808 | mdev->mac_removed[priv->port] = 1; |
728 | 809 | ||
729 | /* Free TX Rings */ | 810 | /* Free TX Rings */ |
@@ -801,7 +882,6 @@ static int mlx4_en_open(struct net_device *dev) | |||
801 | priv->rx_ring[i].packets = 0; | 882 | priv->rx_ring[i].packets = 0; |
802 | } | 883 | } |
803 | 884 | ||
804 | mlx4_en_set_default_moderation(priv); | ||
805 | err = mlx4_en_start_port(dev); | 885 | err = mlx4_en_start_port(dev); |
806 | if (err) | 886 | if (err) |
807 | en_err(priv, "Failed starting port:%d\n", priv->port); | 887 | en_err(priv, "Failed starting port:%d\n", priv->port); |
@@ -828,7 +908,7 @@ static int mlx4_en_close(struct net_device *dev) | |||
828 | return 0; | 908 | return 0; |
829 | } | 909 | } |
830 | 910 | ||
831 | void mlx4_en_free_resources(struct mlx4_en_priv *priv) | 911 | void mlx4_en_free_resources(struct mlx4_en_priv *priv, bool reserve_vectors) |
832 | { | 912 | { |
833 | int i; | 913 | int i; |
834 | 914 | ||
@@ -836,14 +916,14 @@ void mlx4_en_free_resources(struct mlx4_en_priv *priv) | |||
836 | if (priv->tx_ring[i].tx_info) | 916 | if (priv->tx_ring[i].tx_info) |
837 | mlx4_en_destroy_tx_ring(priv, &priv->tx_ring[i]); | 917 | mlx4_en_destroy_tx_ring(priv, &priv->tx_ring[i]); |
838 | if (priv->tx_cq[i].buf) | 918 | if (priv->tx_cq[i].buf) |
839 | mlx4_en_destroy_cq(priv, &priv->tx_cq[i]); | 919 | mlx4_en_destroy_cq(priv, &priv->tx_cq[i], reserve_vectors); |
840 | } | 920 | } |
841 | 921 | ||
842 | for (i = 0; i < priv->rx_ring_num; i++) { | 922 | for (i = 0; i < priv->rx_ring_num; i++) { |
843 | if (priv->rx_ring[i].rx_info) | 923 | if (priv->rx_ring[i].rx_info) |
844 | mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i]); | 924 | mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i]); |
845 | if (priv->rx_cq[i].buf) | 925 | if (priv->rx_cq[i].buf) |
846 | mlx4_en_destroy_cq(priv, &priv->rx_cq[i]); | 926 | mlx4_en_destroy_cq(priv, &priv->rx_cq[i], reserve_vectors); |
847 | } | 927 | } |
848 | } | 928 | } |
849 | 929 | ||
@@ -851,6 +931,13 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) | |||
851 | { | 931 | { |
852 | struct mlx4_en_port_profile *prof = priv->prof; | 932 | struct mlx4_en_port_profile *prof = priv->prof; |
853 | int i; | 933 | int i; |
934 | int base_tx_qpn, err; | ||
935 | |||
936 | err = mlx4_qp_reserve_range(priv->mdev->dev, priv->tx_ring_num, 256, &base_tx_qpn); | ||
937 | if (err) { | ||
938 | en_err(priv, "failed reserving range for TX rings\n"); | ||
939 | return err; | ||
940 | } | ||
854 | 941 | ||
855 | /* Create tx Rings */ | 942 | /* Create tx Rings */ |
856 | for (i = 0; i < priv->tx_ring_num; i++) { | 943 | for (i = 0; i < priv->tx_ring_num; i++) { |
@@ -858,7 +945,7 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) | |||
858 | prof->tx_ring_size, i, TX)) | 945 | prof->tx_ring_size, i, TX)) |
859 | goto err; | 946 | goto err; |
860 | 947 | ||
861 | if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[i], | 948 | if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[i], base_tx_qpn + i, |
862 | prof->tx_ring_size, TXBB_SIZE)) | 949 | prof->tx_ring_size, TXBB_SIZE)) |
863 | goto err; | 950 | goto err; |
864 | } | 951 | } |
@@ -878,6 +965,7 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) | |||
878 | 965 | ||
879 | err: | 966 | err: |
880 | en_err(priv, "Failed to allocate NIC resources\n"); | 967 | en_err(priv, "Failed to allocate NIC resources\n"); |
968 | mlx4_qp_release_range(priv->mdev->dev, base_tx_qpn, priv->tx_ring_num); | ||
881 | return -ENOMEM; | 969 | return -ENOMEM; |
882 | } | 970 | } |
883 | 971 | ||
@@ -905,7 +993,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev) | |||
905 | mdev->pndev[priv->port] = NULL; | 993 | mdev->pndev[priv->port] = NULL; |
906 | mutex_unlock(&mdev->state_lock); | 994 | mutex_unlock(&mdev->state_lock); |
907 | 995 | ||
908 | mlx4_en_free_resources(priv); | 996 | mlx4_en_free_resources(priv, false); |
909 | free_netdev(dev); | 997 | free_netdev(dev); |
910 | } | 998 | } |
911 | 999 | ||
@@ -932,7 +1020,6 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) | |||
932 | en_dbg(DRV, priv, "Change MTU called with card down!?\n"); | 1020 | en_dbg(DRV, priv, "Change MTU called with card down!?\n"); |
933 | } else { | 1021 | } else { |
934 | mlx4_en_stop_port(dev); | 1022 | mlx4_en_stop_port(dev); |
935 | mlx4_en_set_default_moderation(priv); | ||
936 | err = mlx4_en_start_port(dev); | 1023 | err = mlx4_en_start_port(dev); |
937 | if (err) { | 1024 | if (err) { |
938 | en_err(priv, "Failed restarting port:%d\n", | 1025 | en_err(priv, "Failed restarting port:%d\n", |
@@ -1079,7 +1166,25 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, | |||
1079 | en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num); | 1166 | en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num); |
1080 | en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); | 1167 | en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); |
1081 | 1168 | ||
1169 | /* Configure port */ | ||
1170 | err = mlx4_SET_PORT_general(mdev->dev, priv->port, | ||
1171 | MLX4_EN_MIN_MTU, | ||
1172 | 0, 0, 0, 0); | ||
1173 | if (err) { | ||
1174 | en_err(priv, "Failed setting port general configurations " | ||
1175 | "for port %d, with error %d\n", priv->port, err); | ||
1176 | goto out; | ||
1177 | } | ||
1178 | |||
1179 | /* Init port */ | ||
1180 | en_warn(priv, "Initializing port\n"); | ||
1181 | err = mlx4_INIT_PORT(mdev->dev, priv->port); | ||
1182 | if (err) { | ||
1183 | en_err(priv, "Failed Initializing port\n"); | ||
1184 | goto out; | ||
1185 | } | ||
1082 | priv->registered = 1; | 1186 | priv->registered = 1; |
1187 | mlx4_en_set_default_moderation(priv); | ||
1083 | queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); | 1188 | queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); |
1084 | return 0; | 1189 | return 0; |
1085 | 1190 | ||
diff --git a/drivers/net/mlx4/en_port.c b/drivers/net/mlx4/en_port.c index 7f5a3221e0c1..f2a4f5dd313d 100644 --- a/drivers/net/mlx4/en_port.c +++ b/drivers/net/mlx4/en_port.c | |||
@@ -119,6 +119,10 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, | |||
119 | struct mlx4_set_port_rqp_calc_context *context; | 119 | struct mlx4_set_port_rqp_calc_context *context; |
120 | int err; | 120 | int err; |
121 | u32 in_mod; | 121 | u32 in_mod; |
122 | u32 m_promisc = (dev->caps.vep_mc_steering) ? MCAST_DIRECT : MCAST_DEFAULT; | ||
123 | |||
124 | if (dev->caps.vep_mc_steering && dev->caps.vep_uc_steering) | ||
125 | return 0; | ||
122 | 126 | ||
123 | mailbox = mlx4_alloc_cmd_mailbox(dev); | 127 | mailbox = mlx4_alloc_cmd_mailbox(dev); |
124 | if (IS_ERR(mailbox)) | 128 | if (IS_ERR(mailbox)) |
@@ -127,8 +131,11 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, | |||
127 | memset(context, 0, sizeof *context); | 131 | memset(context, 0, sizeof *context); |
128 | 132 | ||
129 | context->base_qpn = cpu_to_be32(base_qpn); | 133 | context->base_qpn = cpu_to_be32(base_qpn); |
130 | context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_EN_SHIFT | base_qpn); | 134 | context->n_mac = 0x7; |
131 | context->mcast = cpu_to_be32(1 << SET_PORT_PROMISC_MODE_SHIFT | base_qpn); | 135 | context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | |
136 | base_qpn); | ||
137 | context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT | | ||
138 | base_qpn); | ||
132 | context->intra_no_vlan = 0; | 139 | context->intra_no_vlan = 0; |
133 | context->no_vlan = MLX4_NO_VLAN_IDX; | 140 | context->no_vlan = MLX4_NO_VLAN_IDX; |
134 | context->intra_vlan_miss = 0; | 141 | context->intra_vlan_miss = 0; |
@@ -206,7 +213,7 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) | |||
206 | } | 213 | } |
207 | stats->tx_packets = 0; | 214 | stats->tx_packets = 0; |
208 | stats->tx_bytes = 0; | 215 | stats->tx_bytes = 0; |
209 | for (i = 0; i <= priv->tx_ring_num; i++) { | 216 | for (i = 0; i < priv->tx_ring_num; i++) { |
210 | stats->tx_packets += priv->tx_ring[i].packets; | 217 | stats->tx_packets += priv->tx_ring[i].packets; |
211 | stats->tx_bytes += priv->tx_ring[i].bytes; | 218 | stats->tx_bytes += priv->tx_ring[i].bytes; |
212 | } | 219 | } |
diff --git a/drivers/net/mlx4/en_port.h b/drivers/net/mlx4/en_port.h index 092e814b1981..e3d73e41c567 100644 --- a/drivers/net/mlx4/en_port.h +++ b/drivers/net/mlx4/en_port.h | |||
@@ -36,8 +36,8 @@ | |||
36 | 36 | ||
37 | 37 | ||
38 | #define SET_PORT_GEN_ALL_VALID 0x7 | 38 | #define SET_PORT_GEN_ALL_VALID 0x7 |
39 | #define SET_PORT_PROMISC_EN_SHIFT 31 | 39 | #define SET_PORT_PROMISC_SHIFT 31 |
40 | #define SET_PORT_PROMISC_MODE_SHIFT 30 | 40 | #define SET_PORT_MC_PROMISC_SHIFT 30 |
41 | 41 | ||
42 | enum { | 42 | enum { |
43 | MLX4_CMD_SET_VLAN_FLTR = 0x47, | 43 | MLX4_CMD_SET_VLAN_FLTR = 0x47, |
@@ -45,6 +45,12 @@ enum { | |||
45 | MLX4_CMD_DUMP_ETH_STATS = 0x49, | 45 | MLX4_CMD_DUMP_ETH_STATS = 0x49, |
46 | }; | 46 | }; |
47 | 47 | ||
48 | enum { | ||
49 | MCAST_DIRECT_ONLY = 0, | ||
50 | MCAST_DIRECT = 1, | ||
51 | MCAST_DEFAULT = 2 | ||
52 | }; | ||
53 | |||
48 | struct mlx4_set_port_general_context { | 54 | struct mlx4_set_port_general_context { |
49 | u8 reserved[3]; | 55 | u8 reserved[3]; |
50 | u8 flags; | 56 | u8 flags; |
@@ -60,14 +66,17 @@ struct mlx4_set_port_general_context { | |||
60 | 66 | ||
61 | struct mlx4_set_port_rqp_calc_context { | 67 | struct mlx4_set_port_rqp_calc_context { |
62 | __be32 base_qpn; | 68 | __be32 base_qpn; |
63 | __be32 flags; | 69 | u8 rererved; |
64 | u8 reserved[3]; | 70 | u8 n_mac; |
71 | u8 n_vlan; | ||
72 | u8 n_prio; | ||
73 | u8 reserved2[3]; | ||
65 | u8 mac_miss; | 74 | u8 mac_miss; |
66 | u8 intra_no_vlan; | 75 | u8 intra_no_vlan; |
67 | u8 no_vlan; | 76 | u8 no_vlan; |
68 | u8 intra_vlan_miss; | 77 | u8 intra_vlan_miss; |
69 | u8 vlan_miss; | 78 | u8 vlan_miss; |
70 | u8 reserved2[3]; | 79 | u8 reserved3[3]; |
71 | u8 no_vlan_prio; | 80 | u8 no_vlan_prio; |
72 | __be32 promisc; | 81 | __be32 promisc; |
73 | __be32 mcast; | 82 | __be32 mcast; |
diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 570f2508fb30..05998ee297c9 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c | |||
@@ -845,16 +845,10 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) | |||
845 | } | 845 | } |
846 | 846 | ||
847 | /* Configure RSS indirection qp */ | 847 | /* Configure RSS indirection qp */ |
848 | err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &priv->base_qpn); | ||
849 | if (err) { | ||
850 | en_err(priv, "Failed to reserve range for RSS " | ||
851 | "indirection qp\n"); | ||
852 | goto rss_err; | ||
853 | } | ||
854 | err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, &rss_map->indir_qp); | 848 | err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, &rss_map->indir_qp); |
855 | if (err) { | 849 | if (err) { |
856 | en_err(priv, "Failed to allocate RSS indirection QP\n"); | 850 | en_err(priv, "Failed to allocate RSS indirection QP\n"); |
857 | goto reserve_err; | 851 | goto rss_err; |
858 | } | 852 | } |
859 | rss_map->indir_qp.event = mlx4_en_sqp_event; | 853 | rss_map->indir_qp.event = mlx4_en_sqp_event; |
860 | mlx4_en_fill_qp_context(priv, 0, 0, 0, 1, priv->base_qpn, | 854 | mlx4_en_fill_qp_context(priv, 0, 0, 0, 1, priv->base_qpn, |
@@ -881,8 +875,6 @@ indir_err: | |||
881 | MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); | 875 | MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); |
882 | mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); | 876 | mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); |
883 | mlx4_qp_free(mdev->dev, &rss_map->indir_qp); | 877 | mlx4_qp_free(mdev->dev, &rss_map->indir_qp); |
884 | reserve_err: | ||
885 | mlx4_qp_release_range(mdev->dev, priv->base_qpn, 1); | ||
886 | rss_err: | 878 | rss_err: |
887 | for (i = 0; i < good_qps; i++) { | 879 | for (i = 0; i < good_qps; i++) { |
888 | mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], | 880 | mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], |
@@ -904,7 +896,6 @@ void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv) | |||
904 | MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); | 896 | MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); |
905 | mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); | 897 | mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); |
906 | mlx4_qp_free(mdev->dev, &rss_map->indir_qp); | 898 | mlx4_qp_free(mdev->dev, &rss_map->indir_qp); |
907 | mlx4_qp_release_range(mdev->dev, priv->base_qpn, 1); | ||
908 | 899 | ||
909 | for (i = 0; i < priv->rx_ring_num; i++) { | 900 | for (i = 0; i < priv->rx_ring_num; i++) { |
910 | mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], | 901 | mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], |
diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index a680cd4a5ab6..01feb8fd42ad 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c | |||
@@ -44,6 +44,7 @@ | |||
44 | 44 | ||
45 | enum { | 45 | enum { |
46 | MAX_INLINE = 104, /* 128 - 16 - 4 - 4 */ | 46 | MAX_INLINE = 104, /* 128 - 16 - 4 - 4 */ |
47 | MAX_BF = 256, | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | static int inline_thold __read_mostly = MAX_INLINE; | 50 | static int inline_thold __read_mostly = MAX_INLINE; |
@@ -52,7 +53,7 @@ module_param_named(inline_thold, inline_thold, int, 0444); | |||
52 | MODULE_PARM_DESC(inline_thold, "threshold for using inline data"); | 53 | MODULE_PARM_DESC(inline_thold, "threshold for using inline data"); |
53 | 54 | ||
54 | int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, | 55 | int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, |
55 | struct mlx4_en_tx_ring *ring, u32 size, | 56 | struct mlx4_en_tx_ring *ring, int qpn, u32 size, |
56 | u16 stride) | 57 | u16 stride) |
57 | { | 58 | { |
58 | struct mlx4_en_dev *mdev = priv->mdev; | 59 | struct mlx4_en_dev *mdev = priv->mdev; |
@@ -103,23 +104,25 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, | |||
103 | "buf_size:%d dma:%llx\n", ring, ring->buf, ring->size, | 104 | "buf_size:%d dma:%llx\n", ring, ring->buf, ring->size, |
104 | ring->buf_size, (unsigned long long) ring->wqres.buf.direct.map); | 105 | ring->buf_size, (unsigned long long) ring->wqres.buf.direct.map); |
105 | 106 | ||
106 | err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &ring->qpn); | 107 | ring->qpn = qpn; |
107 | if (err) { | ||
108 | en_err(priv, "Failed reserving qp for tx ring.\n"); | ||
109 | goto err_map; | ||
110 | } | ||
111 | |||
112 | err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->qp); | 108 | err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->qp); |
113 | if (err) { | 109 | if (err) { |
114 | en_err(priv, "Failed allocating qp %d\n", ring->qpn); | 110 | en_err(priv, "Failed allocating qp %d\n", ring->qpn); |
115 | goto err_reserve; | 111 | goto err_map; |
116 | } | 112 | } |
117 | ring->qp.event = mlx4_en_sqp_event; | 113 | ring->qp.event = mlx4_en_sqp_event; |
118 | 114 | ||
115 | err = mlx4_bf_alloc(mdev->dev, &ring->bf); | ||
116 | if (err) { | ||
117 | en_dbg(DRV, priv, "working without blueflame (%d)", err); | ||
118 | ring->bf.uar = &mdev->priv_uar; | ||
119 | ring->bf.uar->map = mdev->uar_map; | ||
120 | ring->bf_enabled = false; | ||
121 | } else | ||
122 | ring->bf_enabled = true; | ||
123 | |||
119 | return 0; | 124 | return 0; |
120 | 125 | ||
121 | err_reserve: | ||
122 | mlx4_qp_release_range(mdev->dev, ring->qpn, 1); | ||
123 | err_map: | 126 | err_map: |
124 | mlx4_en_unmap_buffer(&ring->wqres.buf); | 127 | mlx4_en_unmap_buffer(&ring->wqres.buf); |
125 | err_hwq_res: | 128 | err_hwq_res: |
@@ -139,6 +142,8 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, | |||
139 | struct mlx4_en_dev *mdev = priv->mdev; | 142 | struct mlx4_en_dev *mdev = priv->mdev; |
140 | en_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn); | 143 | en_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn); |
141 | 144 | ||
145 | if (ring->bf_enabled) | ||
146 | mlx4_bf_free(mdev->dev, &ring->bf); | ||
142 | mlx4_qp_remove(mdev->dev, &ring->qp); | 147 | mlx4_qp_remove(mdev->dev, &ring->qp); |
143 | mlx4_qp_free(mdev->dev, &ring->qp); | 148 | mlx4_qp_free(mdev->dev, &ring->qp); |
144 | mlx4_qp_release_range(mdev->dev, ring->qpn, 1); | 149 | mlx4_qp_release_range(mdev->dev, ring->qpn, 1); |
@@ -171,6 +176,8 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, | |||
171 | 176 | ||
172 | mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn, | 177 | mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn, |
173 | ring->cqn, &ring->context); | 178 | ring->cqn, &ring->context); |
179 | if (ring->bf_enabled) | ||
180 | ring->context.usr_page = cpu_to_be32(ring->bf.uar->index); | ||
174 | 181 | ||
175 | err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, &ring->context, | 182 | err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, &ring->context, |
176 | &ring->qp, &ring->qp_state); | 183 | &ring->qp, &ring->qp_state); |
@@ -591,6 +598,11 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb) | |||
591 | return skb_tx_hash(dev, skb); | 598 | return skb_tx_hash(dev, skb); |
592 | } | 599 | } |
593 | 600 | ||
601 | static void mlx4_bf_copy(unsigned long *dst, unsigned long *src, unsigned bytecnt) | ||
602 | { | ||
603 | __iowrite64_copy(dst, src, bytecnt / 8); | ||
604 | } | ||
605 | |||
594 | netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) | 606 | netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) |
595 | { | 607 | { |
596 | struct mlx4_en_priv *priv = netdev_priv(dev); | 608 | struct mlx4_en_priv *priv = netdev_priv(dev); |
@@ -609,12 +621,13 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) | |||
609 | int desc_size; | 621 | int desc_size; |
610 | int real_size; | 622 | int real_size; |
611 | dma_addr_t dma; | 623 | dma_addr_t dma; |
612 | u32 index; | 624 | u32 index, bf_index; |
613 | __be32 op_own; | 625 | __be32 op_own; |
614 | u16 vlan_tag = 0; | 626 | u16 vlan_tag = 0; |
615 | int i; | 627 | int i; |
616 | int lso_header_size; | 628 | int lso_header_size; |
617 | void *fragptr; | 629 | void *fragptr; |
630 | bool bounce = false; | ||
618 | 631 | ||
619 | if (!priv->port_up) | 632 | if (!priv->port_up) |
620 | goto tx_drop; | 633 | goto tx_drop; |
@@ -657,13 +670,16 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) | |||
657 | 670 | ||
658 | /* Packet is good - grab an index and transmit it */ | 671 | /* Packet is good - grab an index and transmit it */ |
659 | index = ring->prod & ring->size_mask; | 672 | index = ring->prod & ring->size_mask; |
673 | bf_index = ring->prod; | ||
660 | 674 | ||
661 | /* See if we have enough space for whole descriptor TXBB for setting | 675 | /* See if we have enough space for whole descriptor TXBB for setting |
662 | * SW ownership on next descriptor; if not, use a bounce buffer. */ | 676 | * SW ownership on next descriptor; if not, use a bounce buffer. */ |
663 | if (likely(index + nr_txbb <= ring->size)) | 677 | if (likely(index + nr_txbb <= ring->size)) |
664 | tx_desc = ring->buf + index * TXBB_SIZE; | 678 | tx_desc = ring->buf + index * TXBB_SIZE; |
665 | else | 679 | else { |
666 | tx_desc = (struct mlx4_en_tx_desc *) ring->bounce_buf; | 680 | tx_desc = (struct mlx4_en_tx_desc *) ring->bounce_buf; |
681 | bounce = true; | ||
682 | } | ||
667 | 683 | ||
668 | /* Save skb in tx_info ring */ | 684 | /* Save skb in tx_info ring */ |
669 | tx_info = &ring->tx_info[index]; | 685 | tx_info = &ring->tx_info[index]; |
@@ -768,21 +784,37 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) | |||
768 | ring->prod += nr_txbb; | 784 | ring->prod += nr_txbb; |
769 | 785 | ||
770 | /* If we used a bounce buffer then copy descriptor back into place */ | 786 | /* If we used a bounce buffer then copy descriptor back into place */ |
771 | if (tx_desc == (struct mlx4_en_tx_desc *) ring->bounce_buf) | 787 | if (bounce) |
772 | tx_desc = mlx4_en_bounce_to_desc(priv, ring, index, desc_size); | 788 | tx_desc = mlx4_en_bounce_to_desc(priv, ring, index, desc_size); |
773 | 789 | ||
774 | /* Run destructor before passing skb to HW */ | 790 | /* Run destructor before passing skb to HW */ |
775 | if (likely(!skb_shared(skb))) | 791 | if (likely(!skb_shared(skb))) |
776 | skb_orphan(skb); | 792 | skb_orphan(skb); |
777 | 793 | ||
778 | /* Ensure new descirptor hits memory | 794 | if (ring->bf_enabled && desc_size <= MAX_BF && !bounce && !vlan_tag) { |
779 | * before setting ownership of this descriptor to HW */ | 795 | *(u32 *) (&tx_desc->ctrl.vlan_tag) |= ring->doorbell_qpn; |
780 | wmb(); | 796 | op_own |= htonl((bf_index & 0xffff) << 8); |
781 | tx_desc->ctrl.owner_opcode = op_own; | 797 | /* Ensure new descirptor hits memory |
798 | * before setting ownership of this descriptor to HW */ | ||
799 | wmb(); | ||
800 | tx_desc->ctrl.owner_opcode = op_own; | ||
782 | 801 | ||
783 | /* Ring doorbell! */ | 802 | wmb(); |
784 | wmb(); | 803 | |
785 | writel(ring->doorbell_qpn, mdev->uar_map + MLX4_SEND_DOORBELL); | 804 | mlx4_bf_copy(ring->bf.reg + ring->bf.offset, (unsigned long *) &tx_desc->ctrl, |
805 | desc_size); | ||
806 | |||
807 | wmb(); | ||
808 | |||
809 | ring->bf.offset ^= ring->bf.buf_size; | ||
810 | } else { | ||
811 | /* Ensure new descirptor hits memory | ||
812 | * before setting ownership of this descriptor to HW */ | ||
813 | wmb(); | ||
814 | tx_desc->ctrl.owner_opcode = op_own; | ||
815 | wmb(); | ||
816 | writel(ring->doorbell_qpn, ring->bf.uar->map + MLX4_SEND_DOORBELL); | ||
817 | } | ||
786 | 818 | ||
787 | /* Poll CQ here */ | 819 | /* Poll CQ here */ |
788 | mlx4_en_xmit_poll(priv, tx_ind); | 820 | mlx4_en_xmit_poll(priv, tx_ind); |
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index 552d0fce6f67..506cfd0372ec 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c | |||
@@ -42,7 +42,7 @@ | |||
42 | #include "fw.h" | 42 | #include "fw.h" |
43 | 43 | ||
44 | enum { | 44 | enum { |
45 | MLX4_IRQNAME_SIZE = 64 | 45 | MLX4_IRQNAME_SIZE = 32 |
46 | }; | 46 | }; |
47 | 47 | ||
48 | enum { | 48 | enum { |
@@ -317,8 +317,8 @@ static int mlx4_num_eq_uar(struct mlx4_dev *dev) | |||
317 | * we need to map, take the difference of highest index and | 317 | * we need to map, take the difference of highest index and |
318 | * the lowest index we'll use and add 1. | 318 | * the lowest index we'll use and add 1. |
319 | */ | 319 | */ |
320 | return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs) / 4 - | 320 | return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs + |
321 | dev->caps.reserved_eqs / 4 + 1; | 321 | dev->caps.comp_pool)/4 - dev->caps.reserved_eqs/4 + 1; |
322 | } | 322 | } |
323 | 323 | ||
324 | static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq) | 324 | static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq) |
@@ -496,16 +496,32 @@ static void mlx4_free_eq(struct mlx4_dev *dev, | |||
496 | static void mlx4_free_irqs(struct mlx4_dev *dev) | 496 | static void mlx4_free_irqs(struct mlx4_dev *dev) |
497 | { | 497 | { |
498 | struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table; | 498 | struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table; |
499 | int i; | 499 | struct mlx4_priv *priv = mlx4_priv(dev); |
500 | int i, vec; | ||
500 | 501 | ||
501 | if (eq_table->have_irq) | 502 | if (eq_table->have_irq) |
502 | free_irq(dev->pdev->irq, dev); | 503 | free_irq(dev->pdev->irq, dev); |
504 | |||
503 | for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) | 505 | for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) |
504 | if (eq_table->eq[i].have_irq) { | 506 | if (eq_table->eq[i].have_irq) { |
505 | free_irq(eq_table->eq[i].irq, eq_table->eq + i); | 507 | free_irq(eq_table->eq[i].irq, eq_table->eq + i); |
506 | eq_table->eq[i].have_irq = 0; | 508 | eq_table->eq[i].have_irq = 0; |
507 | } | 509 | } |
508 | 510 | ||
511 | for (i = 0; i < dev->caps.comp_pool; i++) { | ||
512 | /* | ||
513 | * Freeing the assigned irq's | ||
514 | * all bits should be 0, but we need to validate | ||
515 | */ | ||
516 | if (priv->msix_ctl.pool_bm & 1ULL << i) { | ||
517 | /* NO need protecting*/ | ||
518 | vec = dev->caps.num_comp_vectors + 1 + i; | ||
519 | free_irq(priv->eq_table.eq[vec].irq, | ||
520 | &priv->eq_table.eq[vec]); | ||
521 | } | ||
522 | } | ||
523 | |||
524 | |||
509 | kfree(eq_table->irq_names); | 525 | kfree(eq_table->irq_names); |
510 | } | 526 | } |
511 | 527 | ||
@@ -578,7 +594,8 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) | |||
578 | (priv->eq_table.inta_pin < 32 ? 4 : 0); | 594 | (priv->eq_table.inta_pin < 32 ? 4 : 0); |
579 | 595 | ||
580 | priv->eq_table.irq_names = | 596 | priv->eq_table.irq_names = |
581 | kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1), | 597 | kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1 + |
598 | dev->caps.comp_pool), | ||
582 | GFP_KERNEL); | 599 | GFP_KERNEL); |
583 | if (!priv->eq_table.irq_names) { | 600 | if (!priv->eq_table.irq_names) { |
584 | err = -ENOMEM; | 601 | err = -ENOMEM; |
@@ -601,6 +618,22 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) | |||
601 | if (err) | 618 | if (err) |
602 | goto err_out_comp; | 619 | goto err_out_comp; |
603 | 620 | ||
621 | /*if additional completion vectors poolsize is 0 this loop will not run*/ | ||
622 | for (i = dev->caps.num_comp_vectors + 1; | ||
623 | i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) { | ||
624 | |||
625 | err = mlx4_create_eq(dev, dev->caps.num_cqs - | ||
626 | dev->caps.reserved_cqs + | ||
627 | MLX4_NUM_SPARE_EQE, | ||
628 | (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, | ||
629 | &priv->eq_table.eq[i]); | ||
630 | if (err) { | ||
631 | --i; | ||
632 | goto err_out_unmap; | ||
633 | } | ||
634 | } | ||
635 | |||
636 | |||
604 | if (dev->flags & MLX4_FLAG_MSI_X) { | 637 | if (dev->flags & MLX4_FLAG_MSI_X) { |
605 | const char *eq_name; | 638 | const char *eq_name; |
606 | 639 | ||
@@ -686,7 +719,7 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev) | |||
686 | 719 | ||
687 | mlx4_free_irqs(dev); | 720 | mlx4_free_irqs(dev); |
688 | 721 | ||
689 | for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) | 722 | for (i = 0; i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) |
690 | mlx4_free_eq(dev, &priv->eq_table.eq[i]); | 723 | mlx4_free_eq(dev, &priv->eq_table.eq[i]); |
691 | 724 | ||
692 | mlx4_unmap_clr_int(dev); | 725 | mlx4_unmap_clr_int(dev); |
@@ -743,3 +776,65 @@ int mlx4_test_interrupts(struct mlx4_dev *dev) | |||
743 | return err; | 776 | return err; |
744 | } | 777 | } |
745 | EXPORT_SYMBOL(mlx4_test_interrupts); | 778 | EXPORT_SYMBOL(mlx4_test_interrupts); |
779 | |||
780 | int mlx4_assign_eq(struct mlx4_dev *dev, char* name, int * vector) | ||
781 | { | ||
782 | |||
783 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
784 | int vec = 0, err = 0, i; | ||
785 | |||
786 | spin_lock(&priv->msix_ctl.pool_lock); | ||
787 | for (i = 0; !vec && i < dev->caps.comp_pool; i++) { | ||
788 | if (~priv->msix_ctl.pool_bm & 1ULL << i) { | ||
789 | priv->msix_ctl.pool_bm |= 1ULL << i; | ||
790 | vec = dev->caps.num_comp_vectors + 1 + i; | ||
791 | snprintf(priv->eq_table.irq_names + | ||
792 | vec * MLX4_IRQNAME_SIZE, | ||
793 | MLX4_IRQNAME_SIZE, "%s", name); | ||
794 | err = request_irq(priv->eq_table.eq[vec].irq, | ||
795 | mlx4_msi_x_interrupt, 0, | ||
796 | &priv->eq_table.irq_names[vec<<5], | ||
797 | priv->eq_table.eq + vec); | ||
798 | if (err) { | ||
799 | /*zero out bit by fliping it*/ | ||
800 | priv->msix_ctl.pool_bm ^= 1 << i; | ||
801 | vec = 0; | ||
802 | continue; | ||
803 | /*we dont want to break here*/ | ||
804 | } | ||
805 | eq_set_ci(&priv->eq_table.eq[vec], 1); | ||
806 | } | ||
807 | } | ||
808 | spin_unlock(&priv->msix_ctl.pool_lock); | ||
809 | |||
810 | if (vec) { | ||
811 | *vector = vec; | ||
812 | } else { | ||
813 | *vector = 0; | ||
814 | err = (i == dev->caps.comp_pool) ? -ENOSPC : err; | ||
815 | } | ||
816 | return err; | ||
817 | } | ||
818 | EXPORT_SYMBOL(mlx4_assign_eq); | ||
819 | |||
820 | void mlx4_release_eq(struct mlx4_dev *dev, int vec) | ||
821 | { | ||
822 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
823 | /*bm index*/ | ||
824 | int i = vec - dev->caps.num_comp_vectors - 1; | ||
825 | |||
826 | if (likely(i >= 0)) { | ||
827 | /*sanity check , making sure were not trying to free irq's | ||
828 | Belonging to a legacy EQ*/ | ||
829 | spin_lock(&priv->msix_ctl.pool_lock); | ||
830 | if (priv->msix_ctl.pool_bm & 1ULL << i) { | ||
831 | free_irq(priv->eq_table.eq[vec].irq, | ||
832 | &priv->eq_table.eq[vec]); | ||
833 | priv->msix_ctl.pool_bm &= ~(1ULL << i); | ||
834 | } | ||
835 | spin_unlock(&priv->msix_ctl.pool_lock); | ||
836 | } | ||
837 | |||
838 | } | ||
839 | EXPORT_SYMBOL(mlx4_release_eq); | ||
840 | |||
diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c index 5de1db897835..67a209ba939d 100644 --- a/drivers/net/mlx4/fw.c +++ b/drivers/net/mlx4/fw.c | |||
@@ -274,8 +274,11 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) | |||
274 | dev_cap->stat_rate_support = stat_rate; | 274 | dev_cap->stat_rate_support = stat_rate; |
275 | MLX4_GET(field, outbox, QUERY_DEV_CAP_UDP_RSS_OFFSET); | 275 | MLX4_GET(field, outbox, QUERY_DEV_CAP_UDP_RSS_OFFSET); |
276 | dev_cap->udp_rss = field & 0x1; | 276 | dev_cap->udp_rss = field & 0x1; |
277 | dev_cap->vep_uc_steering = field & 0x2; | ||
278 | dev_cap->vep_mc_steering = field & 0x4; | ||
277 | MLX4_GET(field, outbox, QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET); | 279 | MLX4_GET(field, outbox, QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET); |
278 | dev_cap->loopback_support = field & 0x1; | 280 | dev_cap->loopback_support = field & 0x1; |
281 | dev_cap->wol = field & 0x40; | ||
279 | MLX4_GET(dev_cap->flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET); | 282 | MLX4_GET(dev_cap->flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET); |
280 | MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET); | 283 | MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET); |
281 | dev_cap->reserved_uars = field >> 4; | 284 | dev_cap->reserved_uars = field >> 4; |
@@ -737,6 +740,7 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) | |||
737 | #define INIT_HCA_MC_BASE_OFFSET (INIT_HCA_MCAST_OFFSET + 0x00) | 740 | #define INIT_HCA_MC_BASE_OFFSET (INIT_HCA_MCAST_OFFSET + 0x00) |
738 | #define INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x12) | 741 | #define INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x12) |
739 | #define INIT_HCA_LOG_MC_HASH_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x16) | 742 | #define INIT_HCA_LOG_MC_HASH_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x16) |
743 | #define INIT_HCA_UC_STEERING_OFFSET (INIT_HCA_MCAST_OFFSET + 0x18) | ||
740 | #define INIT_HCA_LOG_MC_TABLE_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x1b) | 744 | #define INIT_HCA_LOG_MC_TABLE_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x1b) |
741 | #define INIT_HCA_TPT_OFFSET 0x0f0 | 745 | #define INIT_HCA_TPT_OFFSET 0x0f0 |
742 | #define INIT_HCA_DMPT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x00) | 746 | #define INIT_HCA_DMPT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x00) |
@@ -797,6 +801,8 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) | |||
797 | MLX4_PUT(inbox, param->mc_base, INIT_HCA_MC_BASE_OFFSET); | 801 | MLX4_PUT(inbox, param->mc_base, INIT_HCA_MC_BASE_OFFSET); |
798 | MLX4_PUT(inbox, param->log_mc_entry_sz, INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET); | 802 | MLX4_PUT(inbox, param->log_mc_entry_sz, INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET); |
799 | MLX4_PUT(inbox, param->log_mc_hash_sz, INIT_HCA_LOG_MC_HASH_SZ_OFFSET); | 803 | MLX4_PUT(inbox, param->log_mc_hash_sz, INIT_HCA_LOG_MC_HASH_SZ_OFFSET); |
804 | if (dev->caps.vep_mc_steering) | ||
805 | MLX4_PUT(inbox, (u8) (1 << 3), INIT_HCA_UC_STEERING_OFFSET); | ||
800 | MLX4_PUT(inbox, param->log_mc_table_sz, INIT_HCA_LOG_MC_TABLE_SZ_OFFSET); | 806 | MLX4_PUT(inbox, param->log_mc_table_sz, INIT_HCA_LOG_MC_TABLE_SZ_OFFSET); |
801 | 807 | ||
802 | /* TPT attributes */ | 808 | /* TPT attributes */ |
@@ -908,3 +914,22 @@ int mlx4_NOP(struct mlx4_dev *dev) | |||
908 | /* Input modifier of 0x1f means "finish as soon as possible." */ | 914 | /* Input modifier of 0x1f means "finish as soon as possible." */ |
909 | return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, 100); | 915 | return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, 100); |
910 | } | 916 | } |
917 | |||
918 | #define MLX4_WOL_SETUP_MODE (5 << 28) | ||
919 | int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port) | ||
920 | { | ||
921 | u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8; | ||
922 | |||
923 | return mlx4_cmd_imm(dev, 0, config, in_mod, 0x3, | ||
924 | MLX4_CMD_MOD_STAT_CFG, MLX4_CMD_TIME_CLASS_A); | ||
925 | } | ||
926 | EXPORT_SYMBOL_GPL(mlx4_wol_read); | ||
927 | |||
928 | int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port) | ||
929 | { | ||
930 | u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8; | ||
931 | |||
932 | return mlx4_cmd(dev, config, in_mod, 0x1, MLX4_CMD_MOD_STAT_CFG, | ||
933 | MLX4_CMD_TIME_CLASS_A); | ||
934 | } | ||
935 | EXPORT_SYMBOL_GPL(mlx4_wol_write); | ||
diff --git a/drivers/net/mlx4/fw.h b/drivers/net/mlx4/fw.h index 65cc72eb899d..88003ebc6185 100644 --- a/drivers/net/mlx4/fw.h +++ b/drivers/net/mlx4/fw.h | |||
@@ -80,6 +80,9 @@ struct mlx4_dev_cap { | |||
80 | u16 stat_rate_support; | 80 | u16 stat_rate_support; |
81 | int udp_rss; | 81 | int udp_rss; |
82 | int loopback_support; | 82 | int loopback_support; |
83 | int vep_uc_steering; | ||
84 | int vep_mc_steering; | ||
85 | int wol; | ||
83 | u32 flags; | 86 | u32 flags; |
84 | int reserved_uars; | 87 | int reserved_uars; |
85 | int uar_size; | 88 | int uar_size; |
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index c83501122d77..62fa7eec5f0c 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/pci.h> | 39 | #include <linux/pci.h> |
40 | #include <linux/dma-mapping.h> | 40 | #include <linux/dma-mapping.h> |
41 | #include <linux/slab.h> | 41 | #include <linux/slab.h> |
42 | #include <linux/io-mapping.h> | ||
42 | 43 | ||
43 | #include <linux/mlx4/device.h> | 44 | #include <linux/mlx4/device.h> |
44 | #include <linux/mlx4/doorbell.h> | 45 | #include <linux/mlx4/doorbell.h> |
@@ -227,6 +228,9 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) | |||
227 | dev->caps.stat_rate_support = dev_cap->stat_rate_support; | 228 | dev->caps.stat_rate_support = dev_cap->stat_rate_support; |
228 | dev->caps.udp_rss = dev_cap->udp_rss; | 229 | dev->caps.udp_rss = dev_cap->udp_rss; |
229 | dev->caps.loopback_support = dev_cap->loopback_support; | 230 | dev->caps.loopback_support = dev_cap->loopback_support; |
231 | dev->caps.vep_uc_steering = dev_cap->vep_uc_steering; | ||
232 | dev->caps.vep_mc_steering = dev_cap->vep_mc_steering; | ||
233 | dev->caps.wol = dev_cap->wol; | ||
230 | dev->caps.max_gso_sz = dev_cap->max_gso_sz; | 234 | dev->caps.max_gso_sz = dev_cap->max_gso_sz; |
231 | 235 | ||
232 | dev->caps.log_num_macs = log_num_mac; | 236 | dev->caps.log_num_macs = log_num_mac; |
@@ -718,8 +722,31 @@ static void mlx4_free_icms(struct mlx4_dev *dev) | |||
718 | mlx4_free_icm(dev, priv->fw.aux_icm, 0); | 722 | mlx4_free_icm(dev, priv->fw.aux_icm, 0); |
719 | } | 723 | } |
720 | 724 | ||
725 | static int map_bf_area(struct mlx4_dev *dev) | ||
726 | { | ||
727 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
728 | resource_size_t bf_start; | ||
729 | resource_size_t bf_len; | ||
730 | int err = 0; | ||
731 | |||
732 | bf_start = pci_resource_start(dev->pdev, 2) + (dev->caps.num_uars << PAGE_SHIFT); | ||
733 | bf_len = pci_resource_len(dev->pdev, 2) - (dev->caps.num_uars << PAGE_SHIFT); | ||
734 | priv->bf_mapping = io_mapping_create_wc(bf_start, bf_len); | ||
735 | if (!priv->bf_mapping) | ||
736 | err = -ENOMEM; | ||
737 | |||
738 | return err; | ||
739 | } | ||
740 | |||
741 | static void unmap_bf_area(struct mlx4_dev *dev) | ||
742 | { | ||
743 | if (mlx4_priv(dev)->bf_mapping) | ||
744 | io_mapping_free(mlx4_priv(dev)->bf_mapping); | ||
745 | } | ||
746 | |||
721 | static void mlx4_close_hca(struct mlx4_dev *dev) | 747 | static void mlx4_close_hca(struct mlx4_dev *dev) |
722 | { | 748 | { |
749 | unmap_bf_area(dev); | ||
723 | mlx4_CLOSE_HCA(dev, 0); | 750 | mlx4_CLOSE_HCA(dev, 0); |
724 | mlx4_free_icms(dev); | 751 | mlx4_free_icms(dev); |
725 | mlx4_UNMAP_FA(dev); | 752 | mlx4_UNMAP_FA(dev); |
@@ -772,6 +799,9 @@ static int mlx4_init_hca(struct mlx4_dev *dev) | |||
772 | goto err_stop_fw; | 799 | goto err_stop_fw; |
773 | } | 800 | } |
774 | 801 | ||
802 | if (map_bf_area(dev)) | ||
803 | mlx4_dbg(dev, "Failed to map blue flame area\n"); | ||
804 | |||
775 | init_hca.log_uar_sz = ilog2(dev->caps.num_uars); | 805 | init_hca.log_uar_sz = ilog2(dev->caps.num_uars); |
776 | 806 | ||
777 | err = mlx4_init_icm(dev, &dev_cap, &init_hca, icm_size); | 807 | err = mlx4_init_icm(dev, &dev_cap, &init_hca, icm_size); |
@@ -802,6 +832,7 @@ err_free_icm: | |||
802 | mlx4_free_icms(dev); | 832 | mlx4_free_icms(dev); |
803 | 833 | ||
804 | err_stop_fw: | 834 | err_stop_fw: |
835 | unmap_bf_area(dev); | ||
805 | mlx4_UNMAP_FA(dev); | 836 | mlx4_UNMAP_FA(dev); |
806 | mlx4_free_icm(dev, priv->fw.fw_icm, 0); | 837 | mlx4_free_icm(dev, priv->fw.fw_icm, 0); |
807 | 838 | ||
@@ -969,13 +1000,15 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) | |||
969 | { | 1000 | { |
970 | struct mlx4_priv *priv = mlx4_priv(dev); | 1001 | struct mlx4_priv *priv = mlx4_priv(dev); |
971 | struct msix_entry *entries; | 1002 | struct msix_entry *entries; |
972 | int nreq; | 1003 | int nreq = min_t(int, dev->caps.num_ports * |
1004 | min_t(int, num_online_cpus() + 1, MAX_MSIX_P_PORT) | ||
1005 | + MSIX_LEGACY_SZ, MAX_MSIX); | ||
973 | int err; | 1006 | int err; |
974 | int i; | 1007 | int i; |
975 | 1008 | ||
976 | if (msi_x) { | 1009 | if (msi_x) { |
977 | nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs, | 1010 | nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs, |
978 | num_possible_cpus() + 1); | 1011 | nreq); |
979 | entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL); | 1012 | entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL); |
980 | if (!entries) | 1013 | if (!entries) |
981 | goto no_msi; | 1014 | goto no_msi; |
@@ -998,7 +1031,15 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) | |||
998 | goto no_msi; | 1031 | goto no_msi; |
999 | } | 1032 | } |
1000 | 1033 | ||
1001 | dev->caps.num_comp_vectors = nreq - 1; | 1034 | if (nreq < |
1035 | MSIX_LEGACY_SZ + dev->caps.num_ports * MIN_MSIX_P_PORT) { | ||
1036 | /*Working in legacy mode , all EQ's shared*/ | ||
1037 | dev->caps.comp_pool = 0; | ||
1038 | dev->caps.num_comp_vectors = nreq - 1; | ||
1039 | } else { | ||
1040 | dev->caps.comp_pool = nreq - MSIX_LEGACY_SZ; | ||
1041 | dev->caps.num_comp_vectors = MSIX_LEGACY_SZ - 1; | ||
1042 | } | ||
1002 | for (i = 0; i < nreq; ++i) | 1043 | for (i = 0; i < nreq; ++i) |
1003 | priv->eq_table.eq[i].irq = entries[i].vector; | 1044 | priv->eq_table.eq[i].irq = entries[i].vector; |
1004 | 1045 | ||
@@ -1010,6 +1051,7 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) | |||
1010 | 1051 | ||
1011 | no_msi: | 1052 | no_msi: |
1012 | dev->caps.num_comp_vectors = 1; | 1053 | dev->caps.num_comp_vectors = 1; |
1054 | dev->caps.comp_pool = 0; | ||
1013 | 1055 | ||
1014 | for (i = 0; i < 2; ++i) | 1056 | for (i = 0; i < 2; ++i) |
1015 | priv->eq_table.eq[i].irq = dev->pdev->irq; | 1057 | priv->eq_table.eq[i].irq = dev->pdev->irq; |
@@ -1049,6 +1091,59 @@ static void mlx4_cleanup_port_info(struct mlx4_port_info *info) | |||
1049 | device_remove_file(&info->dev->pdev->dev, &info->port_attr); | 1091 | device_remove_file(&info->dev->pdev->dev, &info->port_attr); |
1050 | } | 1092 | } |
1051 | 1093 | ||
1094 | static int mlx4_init_steering(struct mlx4_dev *dev) | ||
1095 | { | ||
1096 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
1097 | int num_entries = dev->caps.num_ports; | ||
1098 | int i, j; | ||
1099 | |||
1100 | priv->steer = kzalloc(sizeof(struct mlx4_steer) * num_entries, GFP_KERNEL); | ||
1101 | if (!priv->steer) | ||
1102 | return -ENOMEM; | ||
1103 | |||
1104 | for (i = 0; i < num_entries; i++) { | ||
1105 | for (j = 0; j < MLX4_NUM_STEERS; j++) { | ||
1106 | INIT_LIST_HEAD(&priv->steer[i].promisc_qps[j]); | ||
1107 | INIT_LIST_HEAD(&priv->steer[i].steer_entries[j]); | ||
1108 | } | ||
1109 | INIT_LIST_HEAD(&priv->steer[i].high_prios); | ||
1110 | } | ||
1111 | return 0; | ||
1112 | } | ||
1113 | |||
1114 | static void mlx4_clear_steering(struct mlx4_dev *dev) | ||
1115 | { | ||
1116 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
1117 | struct mlx4_steer_index *entry, *tmp_entry; | ||
1118 | struct mlx4_promisc_qp *pqp, *tmp_pqp; | ||
1119 | int num_entries = dev->caps.num_ports; | ||
1120 | int i, j; | ||
1121 | |||
1122 | for (i = 0; i < num_entries; i++) { | ||
1123 | for (j = 0; j < MLX4_NUM_STEERS; j++) { | ||
1124 | list_for_each_entry_safe(pqp, tmp_pqp, | ||
1125 | &priv->steer[i].promisc_qps[j], | ||
1126 | list) { | ||
1127 | list_del(&pqp->list); | ||
1128 | kfree(pqp); | ||
1129 | } | ||
1130 | list_for_each_entry_safe(entry, tmp_entry, | ||
1131 | &priv->steer[i].steer_entries[j], | ||
1132 | list) { | ||
1133 | list_del(&entry->list); | ||
1134 | list_for_each_entry_safe(pqp, tmp_pqp, | ||
1135 | &entry->duplicates, | ||
1136 | list) { | ||
1137 | list_del(&pqp->list); | ||
1138 | kfree(pqp); | ||
1139 | } | ||
1140 | kfree(entry); | ||
1141 | } | ||
1142 | } | ||
1143 | } | ||
1144 | kfree(priv->steer); | ||
1145 | } | ||
1146 | |||
1052 | static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | 1147 | static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) |
1053 | { | 1148 | { |
1054 | struct mlx4_priv *priv; | 1149 | struct mlx4_priv *priv; |
@@ -1130,6 +1225,11 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1130 | INIT_LIST_HEAD(&priv->pgdir_list); | 1225 | INIT_LIST_HEAD(&priv->pgdir_list); |
1131 | mutex_init(&priv->pgdir_mutex); | 1226 | mutex_init(&priv->pgdir_mutex); |
1132 | 1227 | ||
1228 | pci_read_config_byte(pdev, PCI_REVISION_ID, &dev->rev_id); | ||
1229 | |||
1230 | INIT_LIST_HEAD(&priv->bf_list); | ||
1231 | mutex_init(&priv->bf_mutex); | ||
1232 | |||
1133 | /* | 1233 | /* |
1134 | * Now reset the HCA before we touch the PCI capabilities or | 1234 | * Now reset the HCA before we touch the PCI capabilities or |
1135 | * attempt a firmware command, since a boot ROM may have left | 1235 | * attempt a firmware command, since a boot ROM may have left |
@@ -1154,8 +1254,15 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1154 | if (err) | 1254 | if (err) |
1155 | goto err_close; | 1255 | goto err_close; |
1156 | 1256 | ||
1257 | priv->msix_ctl.pool_bm = 0; | ||
1258 | spin_lock_init(&priv->msix_ctl.pool_lock); | ||
1259 | |||
1157 | mlx4_enable_msi_x(dev); | 1260 | mlx4_enable_msi_x(dev); |
1158 | 1261 | ||
1262 | err = mlx4_init_steering(dev); | ||
1263 | if (err) | ||
1264 | goto err_free_eq; | ||
1265 | |||
1159 | err = mlx4_setup_hca(dev); | 1266 | err = mlx4_setup_hca(dev); |
1160 | if (err == -EBUSY && (dev->flags & MLX4_FLAG_MSI_X)) { | 1267 | if (err == -EBUSY && (dev->flags & MLX4_FLAG_MSI_X)) { |
1161 | dev->flags &= ~MLX4_FLAG_MSI_X; | 1268 | dev->flags &= ~MLX4_FLAG_MSI_X; |
@@ -1164,7 +1271,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1164 | } | 1271 | } |
1165 | 1272 | ||
1166 | if (err) | 1273 | if (err) |
1167 | goto err_free_eq; | 1274 | goto err_steer; |
1168 | 1275 | ||
1169 | for (port = 1; port <= dev->caps.num_ports; port++) { | 1276 | for (port = 1; port <= dev->caps.num_ports; port++) { |
1170 | err = mlx4_init_port_info(dev, port); | 1277 | err = mlx4_init_port_info(dev, port); |
@@ -1197,6 +1304,9 @@ err_port: | |||
1197 | mlx4_cleanup_pd_table(dev); | 1304 | mlx4_cleanup_pd_table(dev); |
1198 | mlx4_cleanup_uar_table(dev); | 1305 | mlx4_cleanup_uar_table(dev); |
1199 | 1306 | ||
1307 | err_steer: | ||
1308 | mlx4_clear_steering(dev); | ||
1309 | |||
1200 | err_free_eq: | 1310 | err_free_eq: |
1201 | mlx4_free_eq_table(dev); | 1311 | mlx4_free_eq_table(dev); |
1202 | 1312 | ||
@@ -1256,6 +1366,7 @@ static void mlx4_remove_one(struct pci_dev *pdev) | |||
1256 | iounmap(priv->kar); | 1366 | iounmap(priv->kar); |
1257 | mlx4_uar_free(dev, &priv->driver_uar); | 1367 | mlx4_uar_free(dev, &priv->driver_uar); |
1258 | mlx4_cleanup_uar_table(dev); | 1368 | mlx4_cleanup_uar_table(dev); |
1369 | mlx4_clear_steering(dev); | ||
1259 | mlx4_free_eq_table(dev); | 1370 | mlx4_free_eq_table(dev); |
1260 | mlx4_close_hca(dev); | 1371 | mlx4_close_hca(dev); |
1261 | mlx4_cmd_cleanup(dev); | 1372 | mlx4_cmd_cleanup(dev); |
diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c index 79cf42db2ea9..e71372aa9cc4 100644 --- a/drivers/net/mlx4/mcg.c +++ b/drivers/net/mlx4/mcg.c | |||
@@ -32,6 +32,7 @@ | |||
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <linux/string.h> | 34 | #include <linux/string.h> |
35 | #include <linux/etherdevice.h> | ||
35 | 36 | ||
36 | #include <linux/mlx4/cmd.h> | 37 | #include <linux/mlx4/cmd.h> |
37 | 38 | ||
@@ -40,38 +41,40 @@ | |||
40 | #define MGM_QPN_MASK 0x00FFFFFF | 41 | #define MGM_QPN_MASK 0x00FFFFFF |
41 | #define MGM_BLCK_LB_BIT 30 | 42 | #define MGM_BLCK_LB_BIT 30 |
42 | 43 | ||
43 | struct mlx4_mgm { | ||
44 | __be32 next_gid_index; | ||
45 | __be32 members_count; | ||
46 | u32 reserved[2]; | ||
47 | u8 gid[16]; | ||
48 | __be32 qp[MLX4_QP_PER_MGM]; | ||
49 | }; | ||
50 | |||
51 | static const u8 zero_gid[16]; /* automatically initialized to 0 */ | 44 | static const u8 zero_gid[16]; /* automatically initialized to 0 */ |
52 | 45 | ||
53 | static int mlx4_READ_MCG(struct mlx4_dev *dev, int index, | 46 | static int mlx4_READ_ENTRY(struct mlx4_dev *dev, int index, |
54 | struct mlx4_cmd_mailbox *mailbox) | 47 | struct mlx4_cmd_mailbox *mailbox) |
55 | { | 48 | { |
56 | return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG, | 49 | return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG, |
57 | MLX4_CMD_TIME_CLASS_A); | 50 | MLX4_CMD_TIME_CLASS_A); |
58 | } | 51 | } |
59 | 52 | ||
60 | static int mlx4_WRITE_MCG(struct mlx4_dev *dev, int index, | 53 | static int mlx4_WRITE_ENTRY(struct mlx4_dev *dev, int index, |
61 | struct mlx4_cmd_mailbox *mailbox) | 54 | struct mlx4_cmd_mailbox *mailbox) |
62 | { | 55 | { |
63 | return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG, | 56 | return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG, |
64 | MLX4_CMD_TIME_CLASS_A); | 57 | MLX4_CMD_TIME_CLASS_A); |
65 | } | 58 | } |
66 | 59 | ||
67 | static int mlx4_MGID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, | 60 | static int mlx4_WRITE_PROMISC(struct mlx4_dev *dev, u8 vep_num, u8 port, u8 steer, |
68 | u16 *hash) | 61 | struct mlx4_cmd_mailbox *mailbox) |
62 | { | ||
63 | u32 in_mod; | ||
64 | |||
65 | in_mod = (u32) vep_num << 24 | (u32) port << 16 | steer << 1; | ||
66 | return mlx4_cmd(dev, mailbox->dma, in_mod, 0x1, | ||
67 | MLX4_CMD_WRITE_MCG, MLX4_CMD_TIME_CLASS_A); | ||
68 | } | ||
69 | |||
70 | static int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, | ||
71 | u16 *hash, u8 op_mod) | ||
69 | { | 72 | { |
70 | u64 imm; | 73 | u64 imm; |
71 | int err; | 74 | int err; |
72 | 75 | ||
73 | err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, 0, MLX4_CMD_MGID_HASH, | 76 | err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, op_mod, |
74 | MLX4_CMD_TIME_CLASS_A); | 77 | MLX4_CMD_MGID_HASH, MLX4_CMD_TIME_CLASS_A); |
75 | 78 | ||
76 | if (!err) | 79 | if (!err) |
77 | *hash = imm; | 80 | *hash = imm; |
@@ -79,6 +82,457 @@ static int mlx4_MGID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox | |||
79 | return err; | 82 | return err; |
80 | } | 83 | } |
81 | 84 | ||
85 | static struct mlx4_promisc_qp *get_promisc_qp(struct mlx4_dev *dev, u8 pf_num, | ||
86 | enum mlx4_steer_type steer, | ||
87 | u32 qpn) | ||
88 | { | ||
89 | struct mlx4_steer *s_steer = &mlx4_priv(dev)->steer[pf_num]; | ||
90 | struct mlx4_promisc_qp *pqp; | ||
91 | |||
92 | list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) { | ||
93 | if (pqp->qpn == qpn) | ||
94 | return pqp; | ||
95 | } | ||
96 | /* not found */ | ||
97 | return NULL; | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * Add new entry to steering data structure. | ||
102 | * All promisc QPs should be added as well | ||
103 | */ | ||
104 | static int new_steering_entry(struct mlx4_dev *dev, u8 vep_num, u8 port, | ||
105 | enum mlx4_steer_type steer, | ||
106 | unsigned int index, u32 qpn) | ||
107 | { | ||
108 | struct mlx4_steer *s_steer; | ||
109 | struct mlx4_cmd_mailbox *mailbox; | ||
110 | struct mlx4_mgm *mgm; | ||
111 | u32 members_count; | ||
112 | struct mlx4_steer_index *new_entry; | ||
113 | struct mlx4_promisc_qp *pqp; | ||
114 | struct mlx4_promisc_qp *dqp; | ||
115 | u32 prot; | ||
116 | int err; | ||
117 | u8 pf_num; | ||
118 | |||
119 | pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1); | ||
120 | s_steer = &mlx4_priv(dev)->steer[pf_num]; | ||
121 | new_entry = kzalloc(sizeof *new_entry, GFP_KERNEL); | ||
122 | if (!new_entry) | ||
123 | return -ENOMEM; | ||
124 | |||
125 | INIT_LIST_HEAD(&new_entry->duplicates); | ||
126 | new_entry->index = index; | ||
127 | list_add_tail(&new_entry->list, &s_steer->steer_entries[steer]); | ||
128 | |||
129 | /* If the given qpn is also a promisc qp, | ||
130 | * it should be inserted to duplicates list | ||
131 | */ | ||
132 | pqp = get_promisc_qp(dev, pf_num, steer, qpn); | ||
133 | if (pqp) { | ||
134 | dqp = kmalloc(sizeof *dqp, GFP_KERNEL); | ||
135 | if (!dqp) { | ||
136 | err = -ENOMEM; | ||
137 | goto out_alloc; | ||
138 | } | ||
139 | dqp->qpn = qpn; | ||
140 | list_add_tail(&dqp->list, &new_entry->duplicates); | ||
141 | } | ||
142 | |||
143 | /* if no promisc qps for this vep, we are done */ | ||
144 | if (list_empty(&s_steer->promisc_qps[steer])) | ||
145 | return 0; | ||
146 | |||
147 | /* now need to add all the promisc qps to the new | ||
148 | * steering entry, as they should also receive the packets | ||
149 | * destined to this address */ | ||
150 | mailbox = mlx4_alloc_cmd_mailbox(dev); | ||
151 | if (IS_ERR(mailbox)) { | ||
152 | err = -ENOMEM; | ||
153 | goto out_alloc; | ||
154 | } | ||
155 | mgm = mailbox->buf; | ||
156 | |||
157 | err = mlx4_READ_ENTRY(dev, index, mailbox); | ||
158 | if (err) | ||
159 | goto out_mailbox; | ||
160 | |||
161 | members_count = be32_to_cpu(mgm->members_count) & 0xffffff; | ||
162 | prot = be32_to_cpu(mgm->members_count) >> 30; | ||
163 | list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) { | ||
164 | /* don't add already existing qpn */ | ||
165 | if (pqp->qpn == qpn) | ||
166 | continue; | ||
167 | if (members_count == MLX4_QP_PER_MGM) { | ||
168 | /* out of space */ | ||
169 | err = -ENOMEM; | ||
170 | goto out_mailbox; | ||
171 | } | ||
172 | |||
173 | /* add the qpn */ | ||
174 | mgm->qp[members_count++] = cpu_to_be32(pqp->qpn & MGM_QPN_MASK); | ||
175 | } | ||
176 | /* update the qps count and update the entry with all the promisc qps*/ | ||
177 | mgm->members_count = cpu_to_be32(members_count | (prot << 30)); | ||
178 | err = mlx4_WRITE_ENTRY(dev, index, mailbox); | ||
179 | |||
180 | out_mailbox: | ||
181 | mlx4_free_cmd_mailbox(dev, mailbox); | ||
182 | if (!err) | ||
183 | return 0; | ||
184 | out_alloc: | ||
185 | if (dqp) { | ||
186 | list_del(&dqp->list); | ||
187 | kfree(&dqp); | ||
188 | } | ||
189 | list_del(&new_entry->list); | ||
190 | kfree(new_entry); | ||
191 | return err; | ||
192 | } | ||
193 | |||
194 | /* update the data structures with existing steering entry */ | ||
195 | static int existing_steering_entry(struct mlx4_dev *dev, u8 vep_num, u8 port, | ||
196 | enum mlx4_steer_type steer, | ||
197 | unsigned int index, u32 qpn) | ||
198 | { | ||
199 | struct mlx4_steer *s_steer; | ||
200 | struct mlx4_steer_index *tmp_entry, *entry = NULL; | ||
201 | struct mlx4_promisc_qp *pqp; | ||
202 | struct mlx4_promisc_qp *dqp; | ||
203 | u8 pf_num; | ||
204 | |||
205 | pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1); | ||
206 | s_steer = &mlx4_priv(dev)->steer[pf_num]; | ||
207 | |||
208 | pqp = get_promisc_qp(dev, pf_num, steer, qpn); | ||
209 | if (!pqp) | ||
210 | return 0; /* nothing to do */ | ||
211 | |||
212 | list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) { | ||
213 | if (tmp_entry->index == index) { | ||
214 | entry = tmp_entry; | ||
215 | break; | ||
216 | } | ||
217 | } | ||
218 | if (unlikely(!entry)) { | ||
219 | mlx4_warn(dev, "Steering entry at index %x is not registered\n", index); | ||
220 | return -EINVAL; | ||
221 | } | ||
222 | |||
223 | /* the given qpn is listed as a promisc qpn | ||
224 | * we need to add it as a duplicate to this entry | ||
225 | * for future refernce */ | ||
226 | list_for_each_entry(dqp, &entry->duplicates, list) { | ||
227 | if (qpn == dqp->qpn) | ||
228 | return 0; /* qp is already duplicated */ | ||
229 | } | ||
230 | |||
231 | /* add the qp as a duplicate on this index */ | ||
232 | dqp = kmalloc(sizeof *dqp, GFP_KERNEL); | ||
233 | if (!dqp) | ||
234 | return -ENOMEM; | ||
235 | dqp->qpn = qpn; | ||
236 | list_add_tail(&dqp->list, &entry->duplicates); | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | /* Check whether a qpn is a duplicate on steering entry | ||
242 | * If so, it should not be removed from mgm */ | ||
243 | static bool check_duplicate_entry(struct mlx4_dev *dev, u8 vep_num, u8 port, | ||
244 | enum mlx4_steer_type steer, | ||
245 | unsigned int index, u32 qpn) | ||
246 | { | ||
247 | struct mlx4_steer *s_steer; | ||
248 | struct mlx4_steer_index *tmp_entry, *entry = NULL; | ||
249 | struct mlx4_promisc_qp *dqp, *tmp_dqp; | ||
250 | u8 pf_num; | ||
251 | |||
252 | pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1); | ||
253 | s_steer = &mlx4_priv(dev)->steer[pf_num]; | ||
254 | |||
255 | /* if qp is not promisc, it cannot be duplicated */ | ||
256 | if (!get_promisc_qp(dev, pf_num, steer, qpn)) | ||
257 | return false; | ||
258 | |||
259 | /* The qp is promisc qp so it is a duplicate on this index | ||
260 | * Find the index entry, and remove the duplicate */ | ||
261 | list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) { | ||
262 | if (tmp_entry->index == index) { | ||
263 | entry = tmp_entry; | ||
264 | break; | ||
265 | } | ||
266 | } | ||
267 | if (unlikely(!entry)) { | ||
268 | mlx4_warn(dev, "Steering entry for index %x is not registered\n", index); | ||
269 | return false; | ||
270 | } | ||
271 | list_for_each_entry_safe(dqp, tmp_dqp, &entry->duplicates, list) { | ||
272 | if (dqp->qpn == qpn) { | ||
273 | list_del(&dqp->list); | ||
274 | kfree(dqp); | ||
275 | } | ||
276 | } | ||
277 | return true; | ||
278 | } | ||
279 | |||
280 | /* I a steering entry contains only promisc QPs, it can be removed. */ | ||
281 | static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 vep_num, u8 port, | ||
282 | enum mlx4_steer_type steer, | ||
283 | unsigned int index, u32 tqpn) | ||
284 | { | ||
285 | struct mlx4_steer *s_steer; | ||
286 | struct mlx4_cmd_mailbox *mailbox; | ||
287 | struct mlx4_mgm *mgm; | ||
288 | struct mlx4_steer_index *entry = NULL, *tmp_entry; | ||
289 | u32 qpn; | ||
290 | u32 members_count; | ||
291 | bool ret = false; | ||
292 | int i; | ||
293 | u8 pf_num; | ||
294 | |||
295 | pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1); | ||
296 | s_steer = &mlx4_priv(dev)->steer[pf_num]; | ||
297 | |||
298 | mailbox = mlx4_alloc_cmd_mailbox(dev); | ||
299 | if (IS_ERR(mailbox)) | ||
300 | return false; | ||
301 | mgm = mailbox->buf; | ||
302 | |||
303 | if (mlx4_READ_ENTRY(dev, index, mailbox)) | ||
304 | goto out; | ||
305 | members_count = be32_to_cpu(mgm->members_count) & 0xffffff; | ||
306 | for (i = 0; i < members_count; i++) { | ||
307 | qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK; | ||
308 | if (!get_promisc_qp(dev, pf_num, steer, qpn) && qpn != tqpn) { | ||
309 | /* the qp is not promisc, the entry can't be removed */ | ||
310 | goto out; | ||
311 | } | ||
312 | } | ||
313 | /* All the qps currently registered for this entry are promiscuous, | ||
314 | * Checking for duplicates */ | ||
315 | ret = true; | ||
316 | list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) { | ||
317 | if (entry->index == index) { | ||
318 | if (list_empty(&entry->duplicates)) { | ||
319 | list_del(&entry->list); | ||
320 | kfree(entry); | ||
321 | } else { | ||
322 | /* This entry contains duplicates so it shouldn't be removed */ | ||
323 | ret = false; | ||
324 | goto out; | ||
325 | } | ||
326 | } | ||
327 | } | ||
328 | |||
329 | out: | ||
330 | mlx4_free_cmd_mailbox(dev, mailbox); | ||
331 | return ret; | ||
332 | } | ||
333 | |||
334 | static int add_promisc_qp(struct mlx4_dev *dev, u8 vep_num, u8 port, | ||
335 | enum mlx4_steer_type steer, u32 qpn) | ||
336 | { | ||
337 | struct mlx4_steer *s_steer; | ||
338 | struct mlx4_cmd_mailbox *mailbox; | ||
339 | struct mlx4_mgm *mgm; | ||
340 | struct mlx4_steer_index *entry; | ||
341 | struct mlx4_promisc_qp *pqp; | ||
342 | struct mlx4_promisc_qp *dqp; | ||
343 | u32 members_count; | ||
344 | u32 prot; | ||
345 | int i; | ||
346 | bool found; | ||
347 | int last_index; | ||
348 | int err; | ||
349 | u8 pf_num; | ||
350 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
351 | pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1); | ||
352 | s_steer = &mlx4_priv(dev)->steer[pf_num]; | ||
353 | |||
354 | mutex_lock(&priv->mcg_table.mutex); | ||
355 | |||
356 | if (get_promisc_qp(dev, pf_num, steer, qpn)) { | ||
357 | err = 0; /* Noting to do, already exists */ | ||
358 | goto out_mutex; | ||
359 | } | ||
360 | |||
361 | pqp = kmalloc(sizeof *pqp, GFP_KERNEL); | ||
362 | if (!pqp) { | ||
363 | err = -ENOMEM; | ||
364 | goto out_mutex; | ||
365 | } | ||
366 | pqp->qpn = qpn; | ||
367 | |||
368 | mailbox = mlx4_alloc_cmd_mailbox(dev); | ||
369 | if (IS_ERR(mailbox)) { | ||
370 | err = -ENOMEM; | ||
371 | goto out_alloc; | ||
372 | } | ||
373 | mgm = mailbox->buf; | ||
374 | |||
375 | /* the promisc qp needs to be added for each one of the steering | ||
376 | * entries, if it already exists, needs to be added as a duplicate | ||
377 | * for this entry */ | ||
378 | list_for_each_entry(entry, &s_steer->steer_entries[steer], list) { | ||
379 | err = mlx4_READ_ENTRY(dev, entry->index, mailbox); | ||
380 | if (err) | ||
381 | goto out_mailbox; | ||
382 | |||
383 | members_count = be32_to_cpu(mgm->members_count) & 0xffffff; | ||
384 | prot = be32_to_cpu(mgm->members_count) >> 30; | ||
385 | found = false; | ||
386 | for (i = 0; i < members_count; i++) { | ||
387 | if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) { | ||
388 | /* Entry already exists, add to duplicates */ | ||
389 | dqp = kmalloc(sizeof *dqp, GFP_KERNEL); | ||
390 | if (!dqp) | ||
391 | goto out_mailbox; | ||
392 | dqp->qpn = qpn; | ||
393 | list_add_tail(&dqp->list, &entry->duplicates); | ||
394 | found = true; | ||
395 | } | ||
396 | } | ||
397 | if (!found) { | ||
398 | /* Need to add the qpn to mgm */ | ||
399 | if (members_count == MLX4_QP_PER_MGM) { | ||
400 | /* entry is full */ | ||
401 | err = -ENOMEM; | ||
402 | goto out_mailbox; | ||
403 | } | ||
404 | mgm->qp[members_count++] = cpu_to_be32(qpn & MGM_QPN_MASK); | ||
405 | mgm->members_count = cpu_to_be32(members_count | (prot << 30)); | ||
406 | err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); | ||
407 | if (err) | ||
408 | goto out_mailbox; | ||
409 | } | ||
410 | last_index = entry->index; | ||
411 | } | ||
412 | |||
413 | /* add the new qpn to list of promisc qps */ | ||
414 | list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); | ||
415 | /* now need to add all the promisc qps to default entry */ | ||
416 | memset(mgm, 0, sizeof *mgm); | ||
417 | members_count = 0; | ||
418 | list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) | ||
419 | mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); | ||
420 | mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); | ||
421 | |||
422 | err = mlx4_WRITE_PROMISC(dev, vep_num, port, steer, mailbox); | ||
423 | if (err) | ||
424 | goto out_list; | ||
425 | |||
426 | mlx4_free_cmd_mailbox(dev, mailbox); | ||
427 | mutex_unlock(&priv->mcg_table.mutex); | ||
428 | return 0; | ||
429 | |||
430 | out_list: | ||
431 | list_del(&pqp->list); | ||
432 | out_mailbox: | ||
433 | mlx4_free_cmd_mailbox(dev, mailbox); | ||
434 | out_alloc: | ||
435 | kfree(pqp); | ||
436 | out_mutex: | ||
437 | mutex_unlock(&priv->mcg_table.mutex); | ||
438 | return err; | ||
439 | } | ||
440 | |||
441 | static int remove_promisc_qp(struct mlx4_dev *dev, u8 vep_num, u8 port, | ||
442 | enum mlx4_steer_type steer, u32 qpn) | ||
443 | { | ||
444 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
445 | struct mlx4_steer *s_steer; | ||
446 | struct mlx4_cmd_mailbox *mailbox; | ||
447 | struct mlx4_mgm *mgm; | ||
448 | struct mlx4_steer_index *entry; | ||
449 | struct mlx4_promisc_qp *pqp; | ||
450 | struct mlx4_promisc_qp *dqp; | ||
451 | u32 members_count; | ||
452 | bool found; | ||
453 | bool back_to_list = false; | ||
454 | int loc, i; | ||
455 | int err; | ||
456 | u8 pf_num; | ||
457 | |||
458 | pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1); | ||
459 | s_steer = &mlx4_priv(dev)->steer[pf_num]; | ||
460 | mutex_lock(&priv->mcg_table.mutex); | ||
461 | |||
462 | pqp = get_promisc_qp(dev, pf_num, steer, qpn); | ||
463 | if (unlikely(!pqp)) { | ||
464 | mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn); | ||
465 | /* nothing to do */ | ||
466 | err = 0; | ||
467 | goto out_mutex; | ||
468 | } | ||
469 | |||
470 | /*remove from list of promisc qps */ | ||
471 | list_del(&pqp->list); | ||
472 | kfree(pqp); | ||
473 | |||
474 | /* set the default entry not to include the removed one */ | ||
475 | mailbox = mlx4_alloc_cmd_mailbox(dev); | ||
476 | if (IS_ERR(mailbox)) { | ||
477 | err = -ENOMEM; | ||
478 | back_to_list = true; | ||
479 | goto out_list; | ||
480 | } | ||
481 | mgm = mailbox->buf; | ||
482 | members_count = 0; | ||
483 | list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) | ||
484 | mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); | ||
485 | mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); | ||
486 | |||
487 | err = mlx4_WRITE_PROMISC(dev, vep_num, port, steer, mailbox); | ||
488 | if (err) | ||
489 | goto out_mailbox; | ||
490 | |||
491 | /* remove the qp from all the steering entries*/ | ||
492 | list_for_each_entry(entry, &s_steer->steer_entries[steer], list) { | ||
493 | found = false; | ||
494 | list_for_each_entry(dqp, &entry->duplicates, list) { | ||
495 | if (dqp->qpn == qpn) { | ||
496 | found = true; | ||
497 | break; | ||
498 | } | ||
499 | } | ||
500 | if (found) { | ||
501 | /* a duplicate, no need to change the mgm, | ||
502 | * only update the duplicates list */ | ||
503 | list_del(&dqp->list); | ||
504 | kfree(dqp); | ||
505 | } else { | ||
506 | err = mlx4_READ_ENTRY(dev, entry->index, mailbox); | ||
507 | if (err) | ||
508 | goto out_mailbox; | ||
509 | members_count = be32_to_cpu(mgm->members_count) & 0xffffff; | ||
510 | for (loc = -1, i = 0; i < members_count; ++i) | ||
511 | if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) | ||
512 | loc = i; | ||
513 | |||
514 | mgm->members_count = cpu_to_be32(--members_count | | ||
515 | (MLX4_PROT_ETH << 30)); | ||
516 | mgm->qp[loc] = mgm->qp[i - 1]; | ||
517 | mgm->qp[i - 1] = 0; | ||
518 | |||
519 | err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); | ||
520 | if (err) | ||
521 | goto out_mailbox; | ||
522 | } | ||
523 | |||
524 | } | ||
525 | |||
526 | out_mailbox: | ||
527 | mlx4_free_cmd_mailbox(dev, mailbox); | ||
528 | out_list: | ||
529 | if (back_to_list) | ||
530 | list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); | ||
531 | out_mutex: | ||
532 | mutex_unlock(&priv->mcg_table.mutex); | ||
533 | return err; | ||
534 | } | ||
535 | |||
82 | /* | 536 | /* |
83 | * Caller must hold MCG table semaphore. gid and mgm parameters must | 537 | * Caller must hold MCG table semaphore. gid and mgm parameters must |
84 | * be properly aligned for command interface. | 538 | * be properly aligned for command interface. |
@@ -94,15 +548,17 @@ static int mlx4_MGID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox | |||
94 | * If no AMGM exists for given gid, *index = -1, *prev = index of last | 548 | * If no AMGM exists for given gid, *index = -1, *prev = index of last |
95 | * entry in hash chain and *mgm holds end of hash chain. | 549 | * entry in hash chain and *mgm holds end of hash chain. |
96 | */ | 550 | */ |
97 | static int find_mgm(struct mlx4_dev *dev, | 551 | static int find_entry(struct mlx4_dev *dev, u8 port, |
98 | u8 *gid, enum mlx4_protocol protocol, | 552 | u8 *gid, enum mlx4_protocol prot, |
99 | struct mlx4_cmd_mailbox *mgm_mailbox, | 553 | enum mlx4_steer_type steer, |
100 | u16 *hash, int *prev, int *index) | 554 | struct mlx4_cmd_mailbox *mgm_mailbox, |
555 | u16 *hash, int *prev, int *index) | ||
101 | { | 556 | { |
102 | struct mlx4_cmd_mailbox *mailbox; | 557 | struct mlx4_cmd_mailbox *mailbox; |
103 | struct mlx4_mgm *mgm = mgm_mailbox->buf; | 558 | struct mlx4_mgm *mgm = mgm_mailbox->buf; |
104 | u8 *mgid; | 559 | u8 *mgid; |
105 | int err; | 560 | int err; |
561 | u8 op_mod = (prot == MLX4_PROT_ETH) ? !!(dev->caps.vep_mc_steering) : 0; | ||
106 | 562 | ||
107 | mailbox = mlx4_alloc_cmd_mailbox(dev); | 563 | mailbox = mlx4_alloc_cmd_mailbox(dev); |
108 | if (IS_ERR(mailbox)) | 564 | if (IS_ERR(mailbox)) |
@@ -111,7 +567,7 @@ static int find_mgm(struct mlx4_dev *dev, | |||
111 | 567 | ||
112 | memcpy(mgid, gid, 16); | 568 | memcpy(mgid, gid, 16); |
113 | 569 | ||
114 | err = mlx4_MGID_HASH(dev, mailbox, hash); | 570 | err = mlx4_GID_HASH(dev, mailbox, hash, op_mod); |
115 | mlx4_free_cmd_mailbox(dev, mailbox); | 571 | mlx4_free_cmd_mailbox(dev, mailbox); |
116 | if (err) | 572 | if (err) |
117 | return err; | 573 | return err; |
@@ -123,11 +579,11 @@ static int find_mgm(struct mlx4_dev *dev, | |||
123 | *prev = -1; | 579 | *prev = -1; |
124 | 580 | ||
125 | do { | 581 | do { |
126 | err = mlx4_READ_MCG(dev, *index, mgm_mailbox); | 582 | err = mlx4_READ_ENTRY(dev, *index, mgm_mailbox); |
127 | if (err) | 583 | if (err) |
128 | return err; | 584 | return err; |
129 | 585 | ||
130 | if (!memcmp(mgm->gid, zero_gid, 16)) { | 586 | if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) { |
131 | if (*index != *hash) { | 587 | if (*index != *hash) { |
132 | mlx4_err(dev, "Found zero MGID in AMGM.\n"); | 588 | mlx4_err(dev, "Found zero MGID in AMGM.\n"); |
133 | err = -EINVAL; | 589 | err = -EINVAL; |
@@ -136,7 +592,7 @@ static int find_mgm(struct mlx4_dev *dev, | |||
136 | } | 592 | } |
137 | 593 | ||
138 | if (!memcmp(mgm->gid, gid, 16) && | 594 | if (!memcmp(mgm->gid, gid, 16) && |
139 | be32_to_cpu(mgm->members_count) >> 30 == protocol) | 595 | be32_to_cpu(mgm->members_count) >> 30 == prot) |
140 | return err; | 596 | return err; |
141 | 597 | ||
142 | *prev = *index; | 598 | *prev = *index; |
@@ -147,8 +603,9 @@ static int find_mgm(struct mlx4_dev *dev, | |||
147 | return err; | 603 | return err; |
148 | } | 604 | } |
149 | 605 | ||
150 | int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], | 606 | int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], |
151 | int block_mcast_loopback, enum mlx4_protocol protocol) | 607 | int block_mcast_loopback, enum mlx4_protocol prot, |
608 | enum mlx4_steer_type steer) | ||
152 | { | 609 | { |
153 | struct mlx4_priv *priv = mlx4_priv(dev); | 610 | struct mlx4_priv *priv = mlx4_priv(dev); |
154 | struct mlx4_cmd_mailbox *mailbox; | 611 | struct mlx4_cmd_mailbox *mailbox; |
@@ -159,6 +616,8 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], | |||
159 | int link = 0; | 616 | int link = 0; |
160 | int i; | 617 | int i; |
161 | int err; | 618 | int err; |
619 | u8 port = gid[5]; | ||
620 | u8 new_entry = 0; | ||
162 | 621 | ||
163 | mailbox = mlx4_alloc_cmd_mailbox(dev); | 622 | mailbox = mlx4_alloc_cmd_mailbox(dev); |
164 | if (IS_ERR(mailbox)) | 623 | if (IS_ERR(mailbox)) |
@@ -166,14 +625,16 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], | |||
166 | mgm = mailbox->buf; | 625 | mgm = mailbox->buf; |
167 | 626 | ||
168 | mutex_lock(&priv->mcg_table.mutex); | 627 | mutex_lock(&priv->mcg_table.mutex); |
169 | 628 | err = find_entry(dev, port, gid, prot, steer, | |
170 | err = find_mgm(dev, gid, protocol, mailbox, &hash, &prev, &index); | 629 | mailbox, &hash, &prev, &index); |
171 | if (err) | 630 | if (err) |
172 | goto out; | 631 | goto out; |
173 | 632 | ||
174 | if (index != -1) { | 633 | if (index != -1) { |
175 | if (!memcmp(mgm->gid, zero_gid, 16)) | 634 | if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) { |
635 | new_entry = 1; | ||
176 | memcpy(mgm->gid, gid, 16); | 636 | memcpy(mgm->gid, gid, 16); |
637 | } | ||
177 | } else { | 638 | } else { |
178 | link = 1; | 639 | link = 1; |
179 | 640 | ||
@@ -209,26 +670,34 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], | |||
209 | else | 670 | else |
210 | mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK); | 671 | mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK); |
211 | 672 | ||
212 | mgm->members_count = cpu_to_be32(members_count | (u32) protocol << 30); | 673 | mgm->members_count = cpu_to_be32(members_count | (u32) prot << 30); |
213 | 674 | ||
214 | err = mlx4_WRITE_MCG(dev, index, mailbox); | 675 | err = mlx4_WRITE_ENTRY(dev, index, mailbox); |
215 | if (err) | 676 | if (err) |
216 | goto out; | 677 | goto out; |
217 | 678 | ||
218 | if (!link) | 679 | if (!link) |
219 | goto out; | 680 | goto out; |
220 | 681 | ||
221 | err = mlx4_READ_MCG(dev, prev, mailbox); | 682 | err = mlx4_READ_ENTRY(dev, prev, mailbox); |
222 | if (err) | 683 | if (err) |
223 | goto out; | 684 | goto out; |
224 | 685 | ||
225 | mgm->next_gid_index = cpu_to_be32(index << 6); | 686 | mgm->next_gid_index = cpu_to_be32(index << 6); |
226 | 687 | ||
227 | err = mlx4_WRITE_MCG(dev, prev, mailbox); | 688 | err = mlx4_WRITE_ENTRY(dev, prev, mailbox); |
228 | if (err) | 689 | if (err) |
229 | goto out; | 690 | goto out; |
230 | 691 | ||
231 | out: | 692 | out: |
693 | if (prot == MLX4_PROT_ETH) { | ||
694 | /* manage the steering entry for promisc mode */ | ||
695 | if (new_entry) | ||
696 | new_steering_entry(dev, 0, port, steer, index, qp->qpn); | ||
697 | else | ||
698 | existing_steering_entry(dev, 0, port, steer, | ||
699 | index, qp->qpn); | ||
700 | } | ||
232 | if (err && link && index != -1) { | 701 | if (err && link && index != -1) { |
233 | if (index < dev->caps.num_mgms) | 702 | if (index < dev->caps.num_mgms) |
234 | mlx4_warn(dev, "Got AMGM index %d < %d", | 703 | mlx4_warn(dev, "Got AMGM index %d < %d", |
@@ -242,10 +711,9 @@ out: | |||
242 | mlx4_free_cmd_mailbox(dev, mailbox); | 711 | mlx4_free_cmd_mailbox(dev, mailbox); |
243 | return err; | 712 | return err; |
244 | } | 713 | } |
245 | EXPORT_SYMBOL_GPL(mlx4_multicast_attach); | ||
246 | 714 | ||
247 | int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], | 715 | int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], |
248 | enum mlx4_protocol protocol) | 716 | enum mlx4_protocol prot, enum mlx4_steer_type steer) |
249 | { | 717 | { |
250 | struct mlx4_priv *priv = mlx4_priv(dev); | 718 | struct mlx4_priv *priv = mlx4_priv(dev); |
251 | struct mlx4_cmd_mailbox *mailbox; | 719 | struct mlx4_cmd_mailbox *mailbox; |
@@ -255,6 +723,8 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], | |||
255 | int prev, index; | 723 | int prev, index; |
256 | int i, loc; | 724 | int i, loc; |
257 | int err; | 725 | int err; |
726 | u8 port = gid[5]; | ||
727 | bool removed_entry = false; | ||
258 | 728 | ||
259 | mailbox = mlx4_alloc_cmd_mailbox(dev); | 729 | mailbox = mlx4_alloc_cmd_mailbox(dev); |
260 | if (IS_ERR(mailbox)) | 730 | if (IS_ERR(mailbox)) |
@@ -263,7 +733,8 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], | |||
263 | 733 | ||
264 | mutex_lock(&priv->mcg_table.mutex); | 734 | mutex_lock(&priv->mcg_table.mutex); |
265 | 735 | ||
266 | err = find_mgm(dev, gid, protocol, mailbox, &hash, &prev, &index); | 736 | err = find_entry(dev, port, gid, prot, steer, |
737 | mailbox, &hash, &prev, &index); | ||
267 | if (err) | 738 | if (err) |
268 | goto out; | 739 | goto out; |
269 | 740 | ||
@@ -273,6 +744,11 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], | |||
273 | goto out; | 744 | goto out; |
274 | } | 745 | } |
275 | 746 | ||
747 | /* if this pq is also a promisc qp, it shouldn't be removed */ | ||
748 | if (prot == MLX4_PROT_ETH && | ||
749 | check_duplicate_entry(dev, 0, port, steer, index, qp->qpn)) | ||
750 | goto out; | ||
751 | |||
276 | members_count = be32_to_cpu(mgm->members_count) & 0xffffff; | 752 | members_count = be32_to_cpu(mgm->members_count) & 0xffffff; |
277 | for (loc = -1, i = 0; i < members_count; ++i) | 753 | for (loc = -1, i = 0; i < members_count; ++i) |
278 | if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) | 754 | if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) |
@@ -285,26 +761,31 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], | |||
285 | } | 761 | } |
286 | 762 | ||
287 | 763 | ||
288 | mgm->members_count = cpu_to_be32(--members_count | (u32) protocol << 30); | 764 | mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30); |
289 | mgm->qp[loc] = mgm->qp[i - 1]; | 765 | mgm->qp[loc] = mgm->qp[i - 1]; |
290 | mgm->qp[i - 1] = 0; | 766 | mgm->qp[i - 1] = 0; |
291 | 767 | ||
292 | if (i != 1) { | 768 | if (prot == MLX4_PROT_ETH) |
293 | err = mlx4_WRITE_MCG(dev, index, mailbox); | 769 | removed_entry = can_remove_steering_entry(dev, 0, port, steer, index, qp->qpn); |
770 | if (i != 1 && (prot != MLX4_PROT_ETH || !removed_entry)) { | ||
771 | err = mlx4_WRITE_ENTRY(dev, index, mailbox); | ||
294 | goto out; | 772 | goto out; |
295 | } | 773 | } |
296 | 774 | ||
775 | /* We are going to delete the entry, members count should be 0 */ | ||
776 | mgm->members_count = cpu_to_be32((u32) prot << 30); | ||
777 | |||
297 | if (prev == -1) { | 778 | if (prev == -1) { |
298 | /* Remove entry from MGM */ | 779 | /* Remove entry from MGM */ |
299 | int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6; | 780 | int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6; |
300 | if (amgm_index) { | 781 | if (amgm_index) { |
301 | err = mlx4_READ_MCG(dev, amgm_index, mailbox); | 782 | err = mlx4_READ_ENTRY(dev, amgm_index, mailbox); |
302 | if (err) | 783 | if (err) |
303 | goto out; | 784 | goto out; |
304 | } else | 785 | } else |
305 | memset(mgm->gid, 0, 16); | 786 | memset(mgm->gid, 0, 16); |
306 | 787 | ||
307 | err = mlx4_WRITE_MCG(dev, index, mailbox); | 788 | err = mlx4_WRITE_ENTRY(dev, index, mailbox); |
308 | if (err) | 789 | if (err) |
309 | goto out; | 790 | goto out; |
310 | 791 | ||
@@ -319,13 +800,13 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], | |||
319 | } else { | 800 | } else { |
320 | /* Remove entry from AMGM */ | 801 | /* Remove entry from AMGM */ |
321 | int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; | 802 | int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; |
322 | err = mlx4_READ_MCG(dev, prev, mailbox); | 803 | err = mlx4_READ_ENTRY(dev, prev, mailbox); |
323 | if (err) | 804 | if (err) |
324 | goto out; | 805 | goto out; |
325 | 806 | ||
326 | mgm->next_gid_index = cpu_to_be32(cur_next_index << 6); | 807 | mgm->next_gid_index = cpu_to_be32(cur_next_index << 6); |
327 | 808 | ||
328 | err = mlx4_WRITE_MCG(dev, prev, mailbox); | 809 | err = mlx4_WRITE_ENTRY(dev, prev, mailbox); |
329 | if (err) | 810 | if (err) |
330 | goto out; | 811 | goto out; |
331 | 812 | ||
@@ -343,8 +824,85 @@ out: | |||
343 | mlx4_free_cmd_mailbox(dev, mailbox); | 824 | mlx4_free_cmd_mailbox(dev, mailbox); |
344 | return err; | 825 | return err; |
345 | } | 826 | } |
827 | |||
828 | |||
829 | int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], | ||
830 | int block_mcast_loopback, enum mlx4_protocol prot) | ||
831 | { | ||
832 | enum mlx4_steer_type steer; | ||
833 | |||
834 | steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER; | ||
835 | |||
836 | if (prot == MLX4_PROT_ETH && !dev->caps.vep_mc_steering) | ||
837 | return 0; | ||
838 | |||
839 | if (prot == MLX4_PROT_ETH) | ||
840 | gid[7] |= (steer << 1); | ||
841 | |||
842 | return mlx4_qp_attach_common(dev, qp, gid, | ||
843 | block_mcast_loopback, prot, | ||
844 | steer); | ||
845 | } | ||
846 | EXPORT_SYMBOL_GPL(mlx4_multicast_attach); | ||
847 | |||
848 | int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], | ||
849 | enum mlx4_protocol prot) | ||
850 | { | ||
851 | enum mlx4_steer_type steer; | ||
852 | |||
853 | steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER; | ||
854 | |||
855 | if (prot == MLX4_PROT_ETH && !dev->caps.vep_mc_steering) | ||
856 | return 0; | ||
857 | |||
858 | if (prot == MLX4_PROT_ETH) { | ||
859 | gid[7] |= (steer << 1); | ||
860 | } | ||
861 | |||
862 | return mlx4_qp_detach_common(dev, qp, gid, prot, steer); | ||
863 | } | ||
346 | EXPORT_SYMBOL_GPL(mlx4_multicast_detach); | 864 | EXPORT_SYMBOL_GPL(mlx4_multicast_detach); |
347 | 865 | ||
866 | |||
867 | int mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port) | ||
868 | { | ||
869 | if (!dev->caps.vep_mc_steering) | ||
870 | return 0; | ||
871 | |||
872 | |||
873 | return add_promisc_qp(dev, 0, port, MLX4_MC_STEER, qpn); | ||
874 | } | ||
875 | EXPORT_SYMBOL_GPL(mlx4_multicast_promisc_add); | ||
876 | |||
877 | int mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port) | ||
878 | { | ||
879 | if (!dev->caps.vep_mc_steering) | ||
880 | return 0; | ||
881 | |||
882 | |||
883 | return remove_promisc_qp(dev, 0, port, MLX4_MC_STEER, qpn); | ||
884 | } | ||
885 | EXPORT_SYMBOL_GPL(mlx4_multicast_promisc_remove); | ||
886 | |||
887 | int mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port) | ||
888 | { | ||
889 | if (!dev->caps.vep_mc_steering) | ||
890 | return 0; | ||
891 | |||
892 | |||
893 | return add_promisc_qp(dev, 0, port, MLX4_UC_STEER, qpn); | ||
894 | } | ||
895 | EXPORT_SYMBOL_GPL(mlx4_unicast_promisc_add); | ||
896 | |||
897 | int mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port) | ||
898 | { | ||
899 | if (!dev->caps.vep_mc_steering) | ||
900 | return 0; | ||
901 | |||
902 | return remove_promisc_qp(dev, 0, port, MLX4_UC_STEER, qpn); | ||
903 | } | ||
904 | EXPORT_SYMBOL_GPL(mlx4_unicast_promisc_remove); | ||
905 | |||
348 | int mlx4_init_mcg_table(struct mlx4_dev *dev) | 906 | int mlx4_init_mcg_table(struct mlx4_dev *dev) |
349 | { | 907 | { |
350 | struct mlx4_priv *priv = mlx4_priv(dev); | 908 | struct mlx4_priv *priv = mlx4_priv(dev); |
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index 0da5bb7285b4..c1e0e5f1bcdb 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h | |||
@@ -105,6 +105,7 @@ struct mlx4_bitmap { | |||
105 | u32 max; | 105 | u32 max; |
106 | u32 reserved_top; | 106 | u32 reserved_top; |
107 | u32 mask; | 107 | u32 mask; |
108 | u32 avail; | ||
108 | spinlock_t lock; | 109 | spinlock_t lock; |
109 | unsigned long *table; | 110 | unsigned long *table; |
110 | }; | 111 | }; |
@@ -162,6 +163,27 @@ struct mlx4_fw { | |||
162 | u8 catas_bar; | 163 | u8 catas_bar; |
163 | }; | 164 | }; |
164 | 165 | ||
166 | #define MGM_QPN_MASK 0x00FFFFFF | ||
167 | #define MGM_BLCK_LB_BIT 30 | ||
168 | |||
169 | struct mlx4_promisc_qp { | ||
170 | struct list_head list; | ||
171 | u32 qpn; | ||
172 | }; | ||
173 | |||
174 | struct mlx4_steer_index { | ||
175 | struct list_head list; | ||
176 | unsigned int index; | ||
177 | struct list_head duplicates; | ||
178 | }; | ||
179 | |||
180 | struct mlx4_mgm { | ||
181 | __be32 next_gid_index; | ||
182 | __be32 members_count; | ||
183 | u32 reserved[2]; | ||
184 | u8 gid[16]; | ||
185 | __be32 qp[MLX4_QP_PER_MGM]; | ||
186 | }; | ||
165 | struct mlx4_cmd { | 187 | struct mlx4_cmd { |
166 | struct pci_pool *pool; | 188 | struct pci_pool *pool; |
167 | void __iomem *hcr; | 189 | void __iomem *hcr; |
@@ -265,6 +287,10 @@ struct mlx4_vlan_table { | |||
265 | int max; | 287 | int max; |
266 | }; | 288 | }; |
267 | 289 | ||
290 | struct mlx4_mac_entry { | ||
291 | u64 mac; | ||
292 | }; | ||
293 | |||
268 | struct mlx4_port_info { | 294 | struct mlx4_port_info { |
269 | struct mlx4_dev *dev; | 295 | struct mlx4_dev *dev; |
270 | int port; | 296 | int port; |
@@ -272,7 +298,9 @@ struct mlx4_port_info { | |||
272 | struct device_attribute port_attr; | 298 | struct device_attribute port_attr; |
273 | enum mlx4_port_type tmp_type; | 299 | enum mlx4_port_type tmp_type; |
274 | struct mlx4_mac_table mac_table; | 300 | struct mlx4_mac_table mac_table; |
301 | struct radix_tree_root mac_tree; | ||
275 | struct mlx4_vlan_table vlan_table; | 302 | struct mlx4_vlan_table vlan_table; |
303 | int base_qpn; | ||
276 | }; | 304 | }; |
277 | 305 | ||
278 | struct mlx4_sense { | 306 | struct mlx4_sense { |
@@ -282,6 +310,17 @@ struct mlx4_sense { | |||
282 | struct delayed_work sense_poll; | 310 | struct delayed_work sense_poll; |
283 | }; | 311 | }; |
284 | 312 | ||
313 | struct mlx4_msix_ctl { | ||
314 | u64 pool_bm; | ||
315 | spinlock_t pool_lock; | ||
316 | }; | ||
317 | |||
318 | struct mlx4_steer { | ||
319 | struct list_head promisc_qps[MLX4_NUM_STEERS]; | ||
320 | struct list_head steer_entries[MLX4_NUM_STEERS]; | ||
321 | struct list_head high_prios; | ||
322 | }; | ||
323 | |||
285 | struct mlx4_priv { | 324 | struct mlx4_priv { |
286 | struct mlx4_dev dev; | 325 | struct mlx4_dev dev; |
287 | 326 | ||
@@ -313,6 +352,11 @@ struct mlx4_priv { | |||
313 | struct mlx4_port_info port[MLX4_MAX_PORTS + 1]; | 352 | struct mlx4_port_info port[MLX4_MAX_PORTS + 1]; |
314 | struct mlx4_sense sense; | 353 | struct mlx4_sense sense; |
315 | struct mutex port_mutex; | 354 | struct mutex port_mutex; |
355 | struct mlx4_msix_ctl msix_ctl; | ||
356 | struct mlx4_steer *steer; | ||
357 | struct list_head bf_list; | ||
358 | struct mutex bf_mutex; | ||
359 | struct io_mapping *bf_mapping; | ||
316 | }; | 360 | }; |
317 | 361 | ||
318 | static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev) | 362 | static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev) |
@@ -328,6 +372,7 @@ u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap); | |||
328 | void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj); | 372 | void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj); |
329 | u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align); | 373 | u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align); |
330 | void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt); | 374 | void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt); |
375 | u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap); | ||
331 | int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, | 376 | int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, |
332 | u32 reserved_bot, u32 resetrved_top); | 377 | u32 reserved_bot, u32 resetrved_top); |
333 | void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap); | 378 | void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap); |
@@ -403,4 +448,9 @@ void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table); | |||
403 | int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port); | 448 | int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port); |
404 | int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps); | 449 | int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps); |
405 | 450 | ||
451 | int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], | ||
452 | enum mlx4_protocol prot, enum mlx4_steer_type steer); | ||
453 | int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], | ||
454 | int block_mcast_loopback, enum mlx4_protocol prot, | ||
455 | enum mlx4_steer_type steer); | ||
406 | #endif /* MLX4_H */ | 456 | #endif /* MLX4_H */ |
diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index dfed6a07c2d7..e30f6099c0de 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h | |||
@@ -49,8 +49,8 @@ | |||
49 | #include "en_port.h" | 49 | #include "en_port.h" |
50 | 50 | ||
51 | #define DRV_NAME "mlx4_en" | 51 | #define DRV_NAME "mlx4_en" |
52 | #define DRV_VERSION "1.5.1.6" | 52 | #define DRV_VERSION "1.5.4.1" |
53 | #define DRV_RELDATE "August 2010" | 53 | #define DRV_RELDATE "March 2011" |
54 | 54 | ||
55 | #define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN) | 55 | #define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN) |
56 | 56 | ||
@@ -62,6 +62,7 @@ | |||
62 | #define MLX4_EN_PAGE_SHIFT 12 | 62 | #define MLX4_EN_PAGE_SHIFT 12 |
63 | #define MLX4_EN_PAGE_SIZE (1 << MLX4_EN_PAGE_SHIFT) | 63 | #define MLX4_EN_PAGE_SIZE (1 << MLX4_EN_PAGE_SHIFT) |
64 | #define MAX_RX_RINGS 16 | 64 | #define MAX_RX_RINGS 16 |
65 | #define MIN_RX_RINGS 4 | ||
65 | #define TXBB_SIZE 64 | 66 | #define TXBB_SIZE 64 |
66 | #define HEADROOM (2048 / TXBB_SIZE + 1) | 67 | #define HEADROOM (2048 / TXBB_SIZE + 1) |
67 | #define STAMP_STRIDE 64 | 68 | #define STAMP_STRIDE 64 |
@@ -124,6 +125,7 @@ enum { | |||
124 | #define MLX4_EN_RX_SIZE_THRESH 1024 | 125 | #define MLX4_EN_RX_SIZE_THRESH 1024 |
125 | #define MLX4_EN_RX_RATE_THRESH (1000000 / MLX4_EN_RX_COAL_TIME_HIGH) | 126 | #define MLX4_EN_RX_RATE_THRESH (1000000 / MLX4_EN_RX_COAL_TIME_HIGH) |
126 | #define MLX4_EN_SAMPLE_INTERVAL 0 | 127 | #define MLX4_EN_SAMPLE_INTERVAL 0 |
128 | #define MLX4_EN_AVG_PKT_SMALL 256 | ||
127 | 129 | ||
128 | #define MLX4_EN_AUTO_CONF 0xffff | 130 | #define MLX4_EN_AUTO_CONF 0xffff |
129 | 131 | ||
@@ -214,6 +216,9 @@ struct mlx4_en_tx_desc { | |||
214 | 216 | ||
215 | #define MLX4_EN_USE_SRQ 0x01000000 | 217 | #define MLX4_EN_USE_SRQ 0x01000000 |
216 | 218 | ||
219 | #define MLX4_EN_CX3_LOW_ID 0x1000 | ||
220 | #define MLX4_EN_CX3_HIGH_ID 0x1005 | ||
221 | |||
217 | struct mlx4_en_rx_alloc { | 222 | struct mlx4_en_rx_alloc { |
218 | struct page *page; | 223 | struct page *page; |
219 | u16 offset; | 224 | u16 offset; |
@@ -243,6 +248,8 @@ struct mlx4_en_tx_ring { | |||
243 | unsigned long bytes; | 248 | unsigned long bytes; |
244 | unsigned long packets; | 249 | unsigned long packets; |
245 | spinlock_t comp_lock; | 250 | spinlock_t comp_lock; |
251 | struct mlx4_bf bf; | ||
252 | bool bf_enabled; | ||
246 | }; | 253 | }; |
247 | 254 | ||
248 | struct mlx4_en_rx_desc { | 255 | struct mlx4_en_rx_desc { |
@@ -453,6 +460,7 @@ struct mlx4_en_priv { | |||
453 | struct mlx4_en_rss_map rss_map; | 460 | struct mlx4_en_rss_map rss_map; |
454 | u32 flags; | 461 | u32 flags; |
455 | #define MLX4_EN_FLAG_PROMISC 0x1 | 462 | #define MLX4_EN_FLAG_PROMISC 0x1 |
463 | #define MLX4_EN_FLAG_MC_PROMISC 0x2 | ||
456 | u32 tx_ring_num; | 464 | u32 tx_ring_num; |
457 | u32 rx_ring_num; | 465 | u32 rx_ring_num; |
458 | u32 rx_skb_size; | 466 | u32 rx_skb_size; |
@@ -461,6 +469,7 @@ struct mlx4_en_priv { | |||
461 | u16 log_rx_info; | 469 | u16 log_rx_info; |
462 | 470 | ||
463 | struct mlx4_en_tx_ring tx_ring[MAX_TX_RINGS]; | 471 | struct mlx4_en_tx_ring tx_ring[MAX_TX_RINGS]; |
472 | int tx_vector; | ||
464 | struct mlx4_en_rx_ring rx_ring[MAX_RX_RINGS]; | 473 | struct mlx4_en_rx_ring rx_ring[MAX_RX_RINGS]; |
465 | struct mlx4_en_cq tx_cq[MAX_TX_RINGS]; | 474 | struct mlx4_en_cq tx_cq[MAX_TX_RINGS]; |
466 | struct mlx4_en_cq rx_cq[MAX_RX_RINGS]; | 475 | struct mlx4_en_cq rx_cq[MAX_RX_RINGS]; |
@@ -476,6 +485,13 @@ struct mlx4_en_priv { | |||
476 | int mc_addrs_cnt; | 485 | int mc_addrs_cnt; |
477 | struct mlx4_en_stat_out_mbox hw_stats; | 486 | struct mlx4_en_stat_out_mbox hw_stats; |
478 | int vids[128]; | 487 | int vids[128]; |
488 | bool wol; | ||
489 | }; | ||
490 | |||
491 | enum mlx4_en_wol { | ||
492 | MLX4_EN_WOL_MAGIC = (1ULL << 61), | ||
493 | MLX4_EN_WOL_ENABLED = (1ULL << 62), | ||
494 | MLX4_EN_WOL_DO_MODIFY = (1ULL << 63), | ||
479 | }; | 495 | }; |
480 | 496 | ||
481 | 497 | ||
@@ -486,12 +502,13 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, | |||
486 | int mlx4_en_start_port(struct net_device *dev); | 502 | int mlx4_en_start_port(struct net_device *dev); |
487 | void mlx4_en_stop_port(struct net_device *dev); | 503 | void mlx4_en_stop_port(struct net_device *dev); |
488 | 504 | ||
489 | void mlx4_en_free_resources(struct mlx4_en_priv *priv); | 505 | void mlx4_en_free_resources(struct mlx4_en_priv *priv, bool reserve_vectors); |
490 | int mlx4_en_alloc_resources(struct mlx4_en_priv *priv); | 506 | int mlx4_en_alloc_resources(struct mlx4_en_priv *priv); |
491 | 507 | ||
492 | int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, | 508 | int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, |
493 | int entries, int ring, enum cq_type mode); | 509 | int entries, int ring, enum cq_type mode); |
494 | void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); | 510 | void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, |
511 | bool reserve_vectors); | ||
495 | int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); | 512 | int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); |
496 | void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); | 513 | void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); |
497 | int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); | 514 | int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); |
@@ -503,7 +520,7 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb); | |||
503 | netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev); | 520 | netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev); |
504 | 521 | ||
505 | int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, | 522 | int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, |
506 | u32 size, u16 stride); | 523 | int qpn, u32 size, u16 stride); |
507 | void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring); | 524 | void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring); |
508 | int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, | 525 | int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, |
509 | struct mlx4_en_tx_ring *ring, | 526 | struct mlx4_en_tx_ring *ring, |
diff --git a/drivers/net/mlx4/pd.c b/drivers/net/mlx4/pd.c index c4988d6bd5b2..1286b886dcea 100644 --- a/drivers/net/mlx4/pd.c +++ b/drivers/net/mlx4/pd.c | |||
@@ -32,12 +32,17 @@ | |||
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <linux/errno.h> | 34 | #include <linux/errno.h> |
35 | #include <linux/io-mapping.h> | ||
35 | 36 | ||
36 | #include <asm/page.h> | 37 | #include <asm/page.h> |
37 | 38 | ||
38 | #include "mlx4.h" | 39 | #include "mlx4.h" |
39 | #include "icm.h" | 40 | #include "icm.h" |
40 | 41 | ||
42 | enum { | ||
43 | MLX4_NUM_RESERVED_UARS = 8 | ||
44 | }; | ||
45 | |||
41 | int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn) | 46 | int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn) |
42 | { | 47 | { |
43 | struct mlx4_priv *priv = mlx4_priv(dev); | 48 | struct mlx4_priv *priv = mlx4_priv(dev); |
@@ -77,6 +82,7 @@ int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar) | |||
77 | return -ENOMEM; | 82 | return -ENOMEM; |
78 | 83 | ||
79 | uar->pfn = (pci_resource_start(dev->pdev, 2) >> PAGE_SHIFT) + uar->index; | 84 | uar->pfn = (pci_resource_start(dev->pdev, 2) >> PAGE_SHIFT) + uar->index; |
85 | uar->map = NULL; | ||
80 | 86 | ||
81 | return 0; | 87 | return 0; |
82 | } | 88 | } |
@@ -88,6 +94,102 @@ void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar) | |||
88 | } | 94 | } |
89 | EXPORT_SYMBOL_GPL(mlx4_uar_free); | 95 | EXPORT_SYMBOL_GPL(mlx4_uar_free); |
90 | 96 | ||
97 | int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf) | ||
98 | { | ||
99 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
100 | struct mlx4_uar *uar; | ||
101 | int err = 0; | ||
102 | int idx; | ||
103 | |||
104 | if (!priv->bf_mapping) | ||
105 | return -ENOMEM; | ||
106 | |||
107 | mutex_lock(&priv->bf_mutex); | ||
108 | if (!list_empty(&priv->bf_list)) | ||
109 | uar = list_entry(priv->bf_list.next, struct mlx4_uar, bf_list); | ||
110 | else { | ||
111 | if (mlx4_bitmap_avail(&priv->uar_table.bitmap) < MLX4_NUM_RESERVED_UARS) { | ||
112 | err = -ENOMEM; | ||
113 | goto out; | ||
114 | } | ||
115 | uar = kmalloc(sizeof *uar, GFP_KERNEL); | ||
116 | if (!uar) { | ||
117 | err = -ENOMEM; | ||
118 | goto out; | ||
119 | } | ||
120 | err = mlx4_uar_alloc(dev, uar); | ||
121 | if (err) | ||
122 | goto free_kmalloc; | ||
123 | |||
124 | uar->map = ioremap(uar->pfn << PAGE_SHIFT, PAGE_SIZE); | ||
125 | if (!uar->map) { | ||
126 | err = -ENOMEM; | ||
127 | goto free_uar; | ||
128 | } | ||
129 | |||
130 | uar->bf_map = io_mapping_map_wc(priv->bf_mapping, uar->index << PAGE_SHIFT); | ||
131 | if (!uar->bf_map) { | ||
132 | err = -ENOMEM; | ||
133 | goto unamp_uar; | ||
134 | } | ||
135 | uar->free_bf_bmap = 0; | ||
136 | list_add(&uar->bf_list, &priv->bf_list); | ||
137 | } | ||
138 | |||
139 | bf->uar = uar; | ||
140 | idx = ffz(uar->free_bf_bmap); | ||
141 | uar->free_bf_bmap |= 1 << idx; | ||
142 | bf->uar = uar; | ||
143 | bf->offset = 0; | ||
144 | bf->buf_size = dev->caps.bf_reg_size / 2; | ||
145 | bf->reg = uar->bf_map + idx * dev->caps.bf_reg_size; | ||
146 | if (uar->free_bf_bmap == (1 << dev->caps.bf_regs_per_page) - 1) | ||
147 | list_del_init(&uar->bf_list); | ||
148 | |||
149 | goto out; | ||
150 | |||
151 | unamp_uar: | ||
152 | bf->uar = NULL; | ||
153 | iounmap(uar->map); | ||
154 | |||
155 | free_uar: | ||
156 | mlx4_uar_free(dev, uar); | ||
157 | |||
158 | free_kmalloc: | ||
159 | kfree(uar); | ||
160 | |||
161 | out: | ||
162 | mutex_unlock(&priv->bf_mutex); | ||
163 | return err; | ||
164 | } | ||
165 | EXPORT_SYMBOL_GPL(mlx4_bf_alloc); | ||
166 | |||
167 | void mlx4_bf_free(struct mlx4_dev *dev, struct mlx4_bf *bf) | ||
168 | { | ||
169 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
170 | int idx; | ||
171 | |||
172 | if (!bf->uar || !bf->uar->bf_map) | ||
173 | return; | ||
174 | |||
175 | mutex_lock(&priv->bf_mutex); | ||
176 | idx = (bf->reg - bf->uar->bf_map) / dev->caps.bf_reg_size; | ||
177 | bf->uar->free_bf_bmap &= ~(1 << idx); | ||
178 | if (!bf->uar->free_bf_bmap) { | ||
179 | if (!list_empty(&bf->uar->bf_list)) | ||
180 | list_del(&bf->uar->bf_list); | ||
181 | |||
182 | io_mapping_unmap(bf->uar->bf_map); | ||
183 | iounmap(bf->uar->map); | ||
184 | mlx4_uar_free(dev, bf->uar); | ||
185 | kfree(bf->uar); | ||
186 | } else if (list_empty(&bf->uar->bf_list)) | ||
187 | list_add(&bf->uar->bf_list, &priv->bf_list); | ||
188 | |||
189 | mutex_unlock(&priv->bf_mutex); | ||
190 | } | ||
191 | EXPORT_SYMBOL_GPL(mlx4_bf_free); | ||
192 | |||
91 | int mlx4_init_uar_table(struct mlx4_dev *dev) | 193 | int mlx4_init_uar_table(struct mlx4_dev *dev) |
92 | { | 194 | { |
93 | if (dev->caps.num_uars <= 128) { | 195 | if (dev->caps.num_uars <= 128) { |
diff --git a/drivers/net/mlx4/port.c b/drivers/net/mlx4/port.c index 451339559bdc..eca7d8596f87 100644 --- a/drivers/net/mlx4/port.c +++ b/drivers/net/mlx4/port.c | |||
@@ -90,12 +90,79 @@ static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port, | |||
90 | return err; | 90 | return err; |
91 | } | 91 | } |
92 | 92 | ||
93 | int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index) | 93 | static int mlx4_uc_steer_add(struct mlx4_dev *dev, u8 port, |
94 | u64 mac, int *qpn, u8 reserve) | ||
94 | { | 95 | { |
95 | struct mlx4_mac_table *table = &mlx4_priv(dev)->port[port].mac_table; | 96 | struct mlx4_qp qp; |
97 | u8 gid[16] = {0}; | ||
98 | int err; | ||
99 | |||
100 | if (reserve) { | ||
101 | err = mlx4_qp_reserve_range(dev, 1, 1, qpn); | ||
102 | if (err) { | ||
103 | mlx4_err(dev, "Failed to reserve qp for mac registration\n"); | ||
104 | return err; | ||
105 | } | ||
106 | } | ||
107 | qp.qpn = *qpn; | ||
108 | |||
109 | mac &= 0xffffffffffffULL; | ||
110 | mac = cpu_to_be64(mac << 16); | ||
111 | memcpy(&gid[10], &mac, ETH_ALEN); | ||
112 | gid[5] = port; | ||
113 | gid[7] = MLX4_UC_STEER << 1; | ||
114 | |||
115 | err = mlx4_qp_attach_common(dev, &qp, gid, 0, | ||
116 | MLX4_PROT_ETH, MLX4_UC_STEER); | ||
117 | if (err && reserve) | ||
118 | mlx4_qp_release_range(dev, *qpn, 1); | ||
119 | |||
120 | return err; | ||
121 | } | ||
122 | |||
123 | static void mlx4_uc_steer_release(struct mlx4_dev *dev, u8 port, | ||
124 | u64 mac, int qpn, u8 free) | ||
125 | { | ||
126 | struct mlx4_qp qp; | ||
127 | u8 gid[16] = {0}; | ||
128 | |||
129 | qp.qpn = qpn; | ||
130 | mac &= 0xffffffffffffULL; | ||
131 | mac = cpu_to_be64(mac << 16); | ||
132 | memcpy(&gid[10], &mac, ETH_ALEN); | ||
133 | gid[5] = port; | ||
134 | gid[7] = MLX4_UC_STEER << 1; | ||
135 | |||
136 | mlx4_qp_detach_common(dev, &qp, gid, MLX4_PROT_ETH, MLX4_UC_STEER); | ||
137 | if (free) | ||
138 | mlx4_qp_release_range(dev, qpn, 1); | ||
139 | } | ||
140 | |||
141 | int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *qpn, u8 wrap) | ||
142 | { | ||
143 | struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; | ||
144 | struct mlx4_mac_table *table = &info->mac_table; | ||
145 | struct mlx4_mac_entry *entry; | ||
96 | int i, err = 0; | 146 | int i, err = 0; |
97 | int free = -1; | 147 | int free = -1; |
98 | 148 | ||
149 | if (dev->caps.vep_uc_steering) { | ||
150 | err = mlx4_uc_steer_add(dev, port, mac, qpn, 1); | ||
151 | if (!err) { | ||
152 | entry = kmalloc(sizeof *entry, GFP_KERNEL); | ||
153 | if (!entry) { | ||
154 | mlx4_uc_steer_release(dev, port, mac, *qpn, 1); | ||
155 | return -ENOMEM; | ||
156 | } | ||
157 | entry->mac = mac; | ||
158 | err = radix_tree_insert(&info->mac_tree, *qpn, entry); | ||
159 | if (err) { | ||
160 | mlx4_uc_steer_release(dev, port, mac, *qpn, 1); | ||
161 | return err; | ||
162 | } | ||
163 | } else | ||
164 | return err; | ||
165 | } | ||
99 | mlx4_dbg(dev, "Registering MAC: 0x%llx\n", (unsigned long long) mac); | 166 | mlx4_dbg(dev, "Registering MAC: 0x%llx\n", (unsigned long long) mac); |
100 | mutex_lock(&table->mutex); | 167 | mutex_lock(&table->mutex); |
101 | for (i = 0; i < MLX4_MAX_MAC_NUM - 1; i++) { | 168 | for (i = 0; i < MLX4_MAX_MAC_NUM - 1; i++) { |
@@ -106,7 +173,6 @@ int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index) | |||
106 | 173 | ||
107 | if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { | 174 | if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { |
108 | /* MAC already registered, increase refernce count */ | 175 | /* MAC already registered, increase refernce count */ |
109 | *index = i; | ||
110 | ++table->refs[i]; | 176 | ++table->refs[i]; |
111 | goto out; | 177 | goto out; |
112 | } | 178 | } |
@@ -137,7 +203,8 @@ int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index) | |||
137 | goto out; | 203 | goto out; |
138 | } | 204 | } |
139 | 205 | ||
140 | *index = free; | 206 | if (!dev->caps.vep_uc_steering) |
207 | *qpn = info->base_qpn + free; | ||
141 | ++table->total; | 208 | ++table->total; |
142 | out: | 209 | out: |
143 | mutex_unlock(&table->mutex); | 210 | mutex_unlock(&table->mutex); |
@@ -145,20 +212,52 @@ out: | |||
145 | } | 212 | } |
146 | EXPORT_SYMBOL_GPL(mlx4_register_mac); | 213 | EXPORT_SYMBOL_GPL(mlx4_register_mac); |
147 | 214 | ||
148 | void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int index) | 215 | static int validate_index(struct mlx4_dev *dev, |
216 | struct mlx4_mac_table *table, int index) | ||
149 | { | 217 | { |
150 | struct mlx4_mac_table *table = &mlx4_priv(dev)->port[port].mac_table; | 218 | int err = 0; |
151 | 219 | ||
152 | mutex_lock(&table->mutex); | 220 | if (index < 0 || index >= table->max || !table->entries[index]) { |
153 | if (!table->refs[index]) { | 221 | mlx4_warn(dev, "No valid Mac entry for the given index\n"); |
154 | mlx4_warn(dev, "No MAC entry for index %d\n", index); | 222 | err = -EINVAL; |
155 | goto out; | ||
156 | } | 223 | } |
157 | if (--table->refs[index]) { | 224 | return err; |
158 | mlx4_warn(dev, "Have more references for index %d," | 225 | } |
159 | "no need to modify MAC table\n", index); | 226 | |
160 | goto out; | 227 | static int find_index(struct mlx4_dev *dev, |
228 | struct mlx4_mac_table *table, u64 mac) | ||
229 | { | ||
230 | int i; | ||
231 | for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { | ||
232 | if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) | ||
233 | return i; | ||
161 | } | 234 | } |
235 | /* Mac not found */ | ||
236 | return -EINVAL; | ||
237 | } | ||
238 | |||
239 | void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int qpn) | ||
240 | { | ||
241 | struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; | ||
242 | struct mlx4_mac_table *table = &info->mac_table; | ||
243 | int index = qpn - info->base_qpn; | ||
244 | struct mlx4_mac_entry *entry; | ||
245 | |||
246 | if (dev->caps.vep_uc_steering) { | ||
247 | entry = radix_tree_lookup(&info->mac_tree, qpn); | ||
248 | if (entry) { | ||
249 | mlx4_uc_steer_release(dev, port, entry->mac, qpn, 1); | ||
250 | radix_tree_delete(&info->mac_tree, qpn); | ||
251 | index = find_index(dev, table, entry->mac); | ||
252 | kfree(entry); | ||
253 | } | ||
254 | } | ||
255 | |||
256 | mutex_lock(&table->mutex); | ||
257 | |||
258 | if (validate_index(dev, table, index)) | ||
259 | goto out; | ||
260 | |||
162 | table->entries[index] = 0; | 261 | table->entries[index] = 0; |
163 | mlx4_set_port_mac_table(dev, port, table->entries); | 262 | mlx4_set_port_mac_table(dev, port, table->entries); |
164 | --table->total; | 263 | --table->total; |
@@ -167,6 +266,44 @@ out: | |||
167 | } | 266 | } |
168 | EXPORT_SYMBOL_GPL(mlx4_unregister_mac); | 267 | EXPORT_SYMBOL_GPL(mlx4_unregister_mac); |
169 | 268 | ||
269 | int mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac, u8 wrap) | ||
270 | { | ||
271 | struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; | ||
272 | struct mlx4_mac_table *table = &info->mac_table; | ||
273 | int index = qpn - info->base_qpn; | ||
274 | struct mlx4_mac_entry *entry; | ||
275 | int err; | ||
276 | |||
277 | if (dev->caps.vep_uc_steering) { | ||
278 | entry = radix_tree_lookup(&info->mac_tree, qpn); | ||
279 | if (!entry) | ||
280 | return -EINVAL; | ||
281 | index = find_index(dev, table, entry->mac); | ||
282 | mlx4_uc_steer_release(dev, port, entry->mac, qpn, 0); | ||
283 | entry->mac = new_mac; | ||
284 | err = mlx4_uc_steer_add(dev, port, entry->mac, &qpn, 0); | ||
285 | if (err || index < 0) | ||
286 | return err; | ||
287 | } | ||
288 | |||
289 | mutex_lock(&table->mutex); | ||
290 | |||
291 | err = validate_index(dev, table, index); | ||
292 | if (err) | ||
293 | goto out; | ||
294 | |||
295 | table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID); | ||
296 | |||
297 | err = mlx4_set_port_mac_table(dev, port, table->entries); | ||
298 | if (unlikely(err)) { | ||
299 | mlx4_err(dev, "Failed adding MAC: 0x%llx\n", (unsigned long long) new_mac); | ||
300 | table->entries[index] = 0; | ||
301 | } | ||
302 | out: | ||
303 | mutex_unlock(&table->mutex); | ||
304 | return err; | ||
305 | } | ||
306 | EXPORT_SYMBOL_GPL(mlx4_replace_mac); | ||
170 | static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, | 307 | static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, |
171 | __be32 *entries) | 308 | __be32 *entries) |
172 | { | 309 | { |
diff --git a/drivers/net/mlx4/profile.c b/drivers/net/mlx4/profile.c index e749f82865fe..b967647d0c76 100644 --- a/drivers/net/mlx4/profile.c +++ b/drivers/net/mlx4/profile.c | |||
@@ -107,9 +107,7 @@ u64 mlx4_make_profile(struct mlx4_dev *dev, | |||
107 | profile[MLX4_RES_AUXC].num = request->num_qp; | 107 | profile[MLX4_RES_AUXC].num = request->num_qp; |
108 | profile[MLX4_RES_SRQ].num = request->num_srq; | 108 | profile[MLX4_RES_SRQ].num = request->num_srq; |
109 | profile[MLX4_RES_CQ].num = request->num_cq; | 109 | profile[MLX4_RES_CQ].num = request->num_cq; |
110 | profile[MLX4_RES_EQ].num = min_t(unsigned, dev_cap->max_eqs, | 110 | profile[MLX4_RES_EQ].num = min_t(unsigned, dev_cap->max_eqs, MAX_MSIX); |
111 | dev_cap->reserved_eqs + | ||
112 | num_possible_cpus() + 1); | ||
113 | profile[MLX4_RES_DMPT].num = request->num_mpt; | 111 | profile[MLX4_RES_DMPT].num = request->num_mpt; |
114 | profile[MLX4_RES_CMPT].num = MLX4_NUM_CMPTS; | 112 | profile[MLX4_RES_CMPT].num = MLX4_NUM_CMPTS; |
115 | profile[MLX4_RES_MTT].num = request->num_mtt; | 113 | profile[MLX4_RES_MTT].num = request->num_mtt; |
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index a7f2eed9a08a..1f4e8680a96a 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c | |||
@@ -3645,6 +3645,7 @@ static void myri10ge_free_slices(struct myri10ge_priv *mgp) | |||
3645 | dma_free_coherent(&pdev->dev, bytes, | 3645 | dma_free_coherent(&pdev->dev, bytes, |
3646 | ss->fw_stats, ss->fw_stats_bus); | 3646 | ss->fw_stats, ss->fw_stats_bus); |
3647 | ss->fw_stats = NULL; | 3647 | ss->fw_stats = NULL; |
3648 | netif_napi_del(&ss->napi); | ||
3648 | } | 3649 | } |
3649 | } | 3650 | } |
3650 | kfree(mgp->ss); | 3651 | kfree(mgp->ss); |
diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 8c66e22c3a0a..50986840c99c 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c | |||
@@ -2441,7 +2441,7 @@ static struct pci_error_handlers pch_gbe_err_handler = { | |||
2441 | .resume = pch_gbe_io_resume | 2441 | .resume = pch_gbe_io_resume |
2442 | }; | 2442 | }; |
2443 | 2443 | ||
2444 | static struct pci_driver pch_gbe_pcidev = { | 2444 | static struct pci_driver pch_gbe_driver = { |
2445 | .name = KBUILD_MODNAME, | 2445 | .name = KBUILD_MODNAME, |
2446 | .id_table = pch_gbe_pcidev_id, | 2446 | .id_table = pch_gbe_pcidev_id, |
2447 | .probe = pch_gbe_probe, | 2447 | .probe = pch_gbe_probe, |
@@ -2458,7 +2458,7 @@ static int __init pch_gbe_init_module(void) | |||
2458 | { | 2458 | { |
2459 | int ret; | 2459 | int ret; |
2460 | 2460 | ||
2461 | ret = pci_register_driver(&pch_gbe_pcidev); | 2461 | ret = pci_register_driver(&pch_gbe_driver); |
2462 | if (copybreak != PCH_GBE_COPYBREAK_DEFAULT) { | 2462 | if (copybreak != PCH_GBE_COPYBREAK_DEFAULT) { |
2463 | if (copybreak == 0) { | 2463 | if (copybreak == 0) { |
2464 | pr_info("copybreak disabled\n"); | 2464 | pr_info("copybreak disabled\n"); |
@@ -2472,7 +2472,7 @@ static int __init pch_gbe_init_module(void) | |||
2472 | 2472 | ||
2473 | static void __exit pch_gbe_exit_module(void) | 2473 | static void __exit pch_gbe_exit_module(void) |
2474 | { | 2474 | { |
2475 | pci_unregister_driver(&pch_gbe_pcidev); | 2475 | pci_unregister_driver(&pch_gbe_driver); |
2476 | } | 2476 | } |
2477 | 2477 | ||
2478 | module_init(pch_gbe_init_module); | 2478 | module_init(pch_gbe_init_module); |
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index b8bd936374f2..d890679e4c4d 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c | |||
@@ -1054,6 +1054,7 @@ static int efx_init_io(struct efx_nic *efx) | |||
1054 | { | 1054 | { |
1055 | struct pci_dev *pci_dev = efx->pci_dev; | 1055 | struct pci_dev *pci_dev = efx->pci_dev; |
1056 | dma_addr_t dma_mask = efx->type->max_dma_mask; | 1056 | dma_addr_t dma_mask = efx->type->max_dma_mask; |
1057 | bool use_wc; | ||
1057 | int rc; | 1058 | int rc; |
1058 | 1059 | ||
1059 | netif_dbg(efx, probe, efx->net_dev, "initialising I/O\n"); | 1060 | netif_dbg(efx, probe, efx->net_dev, "initialising I/O\n"); |
@@ -1104,8 +1105,21 @@ static int efx_init_io(struct efx_nic *efx) | |||
1104 | rc = -EIO; | 1105 | rc = -EIO; |
1105 | goto fail3; | 1106 | goto fail3; |
1106 | } | 1107 | } |
1107 | efx->membase = ioremap_wc(efx->membase_phys, | 1108 | |
1108 | efx->type->mem_map_size); | 1109 | /* bug22643: If SR-IOV is enabled then tx push over a write combined |
1110 | * mapping is unsafe. We need to disable write combining in this case. | ||
1111 | * MSI is unsupported when SR-IOV is enabled, and the firmware will | ||
1112 | * have removed the MSI capability. So write combining is safe if | ||
1113 | * there is an MSI capability. | ||
1114 | */ | ||
1115 | use_wc = (!EFX_WORKAROUND_22643(efx) || | ||
1116 | pci_find_capability(pci_dev, PCI_CAP_ID_MSI)); | ||
1117 | if (use_wc) | ||
1118 | efx->membase = ioremap_wc(efx->membase_phys, | ||
1119 | efx->type->mem_map_size); | ||
1120 | else | ||
1121 | efx->membase = ioremap_nocache(efx->membase_phys, | ||
1122 | efx->type->mem_map_size); | ||
1109 | if (!efx->membase) { | 1123 | if (!efx->membase) { |
1110 | netif_err(efx, probe, efx->net_dev, | 1124 | netif_err(efx, probe, efx->net_dev, |
1111 | "could not map memory BAR at %llx+%x\n", | 1125 | "could not map memory BAR at %llx+%x\n", |
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h index e4dd3a7f304b..99ff11400cef 100644 --- a/drivers/net/sfc/workarounds.h +++ b/drivers/net/sfc/workarounds.h | |||
@@ -38,6 +38,8 @@ | |||
38 | #define EFX_WORKAROUND_15783 EFX_WORKAROUND_ALWAYS | 38 | #define EFX_WORKAROUND_15783 EFX_WORKAROUND_ALWAYS |
39 | /* Legacy interrupt storm when interrupt fifo fills */ | 39 | /* Legacy interrupt storm when interrupt fifo fills */ |
40 | #define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA | 40 | #define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA |
41 | /* Write combining and sriov=enabled are incompatible */ | ||
42 | #define EFX_WORKAROUND_22643 EFX_WORKAROUND_SIENA | ||
41 | 43 | ||
42 | /* Spurious parity errors in TSORT buffers */ | 44 | /* Spurious parity errors in TSORT buffers */ |
43 | #define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A | 45 | #define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A |
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index bc86f4b6ecc2..727874d9deb6 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c | |||
@@ -49,6 +49,8 @@ | |||
49 | 49 | ||
50 | struct smsc95xx_priv { | 50 | struct smsc95xx_priv { |
51 | u32 mac_cr; | 51 | u32 mac_cr; |
52 | u32 hash_hi; | ||
53 | u32 hash_lo; | ||
52 | spinlock_t mac_cr_lock; | 54 | spinlock_t mac_cr_lock; |
53 | bool use_tx_csum; | 55 | bool use_tx_csum; |
54 | bool use_rx_csum; | 56 | bool use_rx_csum; |
@@ -370,10 +372,11 @@ static void smsc95xx_set_multicast(struct net_device *netdev) | |||
370 | { | 372 | { |
371 | struct usbnet *dev = netdev_priv(netdev); | 373 | struct usbnet *dev = netdev_priv(netdev); |
372 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | 374 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); |
373 | u32 hash_hi = 0; | ||
374 | u32 hash_lo = 0; | ||
375 | unsigned long flags; | 375 | unsigned long flags; |
376 | 376 | ||
377 | pdata->hash_hi = 0; | ||
378 | pdata->hash_lo = 0; | ||
379 | |||
377 | spin_lock_irqsave(&pdata->mac_cr_lock, flags); | 380 | spin_lock_irqsave(&pdata->mac_cr_lock, flags); |
378 | 381 | ||
379 | if (dev->net->flags & IFF_PROMISC) { | 382 | if (dev->net->flags & IFF_PROMISC) { |
@@ -394,13 +397,13 @@ static void smsc95xx_set_multicast(struct net_device *netdev) | |||
394 | u32 bitnum = smsc95xx_hash(ha->addr); | 397 | u32 bitnum = smsc95xx_hash(ha->addr); |
395 | u32 mask = 0x01 << (bitnum & 0x1F); | 398 | u32 mask = 0x01 << (bitnum & 0x1F); |
396 | if (bitnum & 0x20) | 399 | if (bitnum & 0x20) |
397 | hash_hi |= mask; | 400 | pdata->hash_hi |= mask; |
398 | else | 401 | else |
399 | hash_lo |= mask; | 402 | pdata->hash_lo |= mask; |
400 | } | 403 | } |
401 | 404 | ||
402 | netif_dbg(dev, drv, dev->net, "HASHH=0x%08X, HASHL=0x%08X\n", | 405 | netif_dbg(dev, drv, dev->net, "HASHH=0x%08X, HASHL=0x%08X\n", |
403 | hash_hi, hash_lo); | 406 | pdata->hash_hi, pdata->hash_lo); |
404 | } else { | 407 | } else { |
405 | netif_dbg(dev, drv, dev->net, "receive own packets only\n"); | 408 | netif_dbg(dev, drv, dev->net, "receive own packets only\n"); |
406 | pdata->mac_cr &= | 409 | pdata->mac_cr &= |
@@ -410,8 +413,8 @@ static void smsc95xx_set_multicast(struct net_device *netdev) | |||
410 | spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); | 413 | spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); |
411 | 414 | ||
412 | /* Initiate async writes, as we can't wait for completion here */ | 415 | /* Initiate async writes, as we can't wait for completion here */ |
413 | smsc95xx_write_reg_async(dev, HASHH, &hash_hi); | 416 | smsc95xx_write_reg_async(dev, HASHH, &pdata->hash_hi); |
414 | smsc95xx_write_reg_async(dev, HASHL, &hash_lo); | 417 | smsc95xx_write_reg_async(dev, HASHL, &pdata->hash_lo); |
415 | smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr); | 418 | smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr); |
416 | } | 419 | } |
417 | 420 | ||
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 115f162c617a..524825720a09 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -2160,6 +2160,8 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) | |||
2160 | if (!ath_drain_all_txq(sc, false)) | 2160 | if (!ath_drain_all_txq(sc, false)) |
2161 | ath_reset(sc, false); | 2161 | ath_reset(sc, false); |
2162 | 2162 | ||
2163 | ieee80211_wake_queues(hw); | ||
2164 | |||
2163 | out: | 2165 | out: |
2164 | ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); | 2166 | ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); |
2165 | mutex_unlock(&sc->mutex); | 2167 | mutex_unlock(&sc->mutex); |
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 960d717ca7c2..a3241cd089b1 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c | |||
@@ -1328,7 +1328,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
1328 | 1328 | ||
1329 | hdr = (struct ieee80211_hdr *)skb->data; | 1329 | hdr = (struct ieee80211_hdr *)skb->data; |
1330 | fc = hdr->frame_control; | 1330 | fc = hdr->frame_control; |
1331 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 1331 | for (i = 0; i < sc->hw->max_rates; i++) { |
1332 | struct ieee80211_tx_rate *rate = &tx_info->status.rates[i]; | 1332 | struct ieee80211_tx_rate *rate = &tx_info->status.rates[i]; |
1333 | if (!rate->count) | 1333 | if (!rate->count) |
1334 | break; | 1334 | break; |
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index ef22096d40c9..26734e53b37f 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -1725,8 +1725,8 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, | |||
1725 | u8 tidno; | 1725 | u8 tidno; |
1726 | 1726 | ||
1727 | spin_lock_bh(&txctl->txq->axq_lock); | 1727 | spin_lock_bh(&txctl->txq->axq_lock); |
1728 | 1728 | if ((sc->sc_flags & SC_OP_TXAGGR) && txctl->an && | |
1729 | if (ieee80211_is_data_qos(hdr->frame_control) && txctl->an) { | 1729 | ieee80211_is_data_qos(hdr->frame_control)) { |
1730 | tidno = ieee80211_get_qos_ctl(hdr)[0] & | 1730 | tidno = ieee80211_get_qos_ctl(hdr)[0] & |
1731 | IEEE80211_QOS_CTL_TID_MASK; | 1731 | IEEE80211_QOS_CTL_TID_MASK; |
1732 | tid = ATH_AN_2_TID(txctl->an, tidno); | 1732 | tid = ATH_AN_2_TID(txctl->an, tidno); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 2003c1d4295f..08ccb9496f76 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c | |||
@@ -2265,7 +2265,7 @@ signed long iwlagn_wait_notification(struct iwl_priv *priv, | |||
2265 | int ret; | 2265 | int ret; |
2266 | 2266 | ||
2267 | ret = wait_event_timeout(priv->_agn.notif_waitq, | 2267 | ret = wait_event_timeout(priv->_agn.notif_waitq, |
2268 | &wait_entry->triggered, | 2268 | wait_entry->triggered, |
2269 | timeout); | 2269 | timeout); |
2270 | 2270 | ||
2271 | spin_lock_bh(&priv->_agn.notif_wait_lock); | 2271 | spin_lock_bh(&priv->_agn.notif_wait_lock); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 581dc9f10273..321b18b59135 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -3009,14 +3009,17 @@ static int iwl_mac_offchannel_tx_cancel_wait(struct ieee80211_hw *hw) | |||
3009 | 3009 | ||
3010 | mutex_lock(&priv->mutex); | 3010 | mutex_lock(&priv->mutex); |
3011 | 3011 | ||
3012 | if (!priv->_agn.offchan_tx_skb) | 3012 | if (!priv->_agn.offchan_tx_skb) { |
3013 | return -EINVAL; | 3013 | ret = -EINVAL; |
3014 | goto unlock; | ||
3015 | } | ||
3014 | 3016 | ||
3015 | priv->_agn.offchan_tx_skb = NULL; | 3017 | priv->_agn.offchan_tx_skb = NULL; |
3016 | 3018 | ||
3017 | ret = iwl_scan_cancel_timeout(priv, 200); | 3019 | ret = iwl_scan_cancel_timeout(priv, 200); |
3018 | if (ret) | 3020 | if (ret) |
3019 | ret = -EIO; | 3021 | ret = -EIO; |
3022 | unlock: | ||
3020 | mutex_unlock(&priv->mutex); | 3023 | mutex_unlock(&priv->mutex); |
3021 | 3024 | ||
3022 | return ret; | 3025 | return ret; |
diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c index 09fae2f0ea08..736bbb9bd1d0 100644 --- a/drivers/net/wireless/orinoco/cfg.c +++ b/drivers/net/wireless/orinoco/cfg.c | |||
@@ -153,6 +153,9 @@ static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev, | |||
153 | priv->scan_request = request; | 153 | priv->scan_request = request; |
154 | 154 | ||
155 | err = orinoco_hw_trigger_scan(priv, request->ssids); | 155 | err = orinoco_hw_trigger_scan(priv, request->ssids); |
156 | /* On error the we aren't processing the request */ | ||
157 | if (err) | ||
158 | priv->scan_request = NULL; | ||
156 | 159 | ||
157 | return err; | 160 | return err; |
158 | } | 161 | } |
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index f3d396e7544b..62c6b2b37dbe 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c | |||
@@ -1376,13 +1376,13 @@ static void orinoco_process_scan_results(struct work_struct *work) | |||
1376 | 1376 | ||
1377 | spin_lock_irqsave(&priv->scan_lock, flags); | 1377 | spin_lock_irqsave(&priv->scan_lock, flags); |
1378 | list_for_each_entry_safe(sd, temp, &priv->scan_list, list) { | 1378 | list_for_each_entry_safe(sd, temp, &priv->scan_list, list) { |
1379 | spin_unlock_irqrestore(&priv->scan_lock, flags); | ||
1380 | 1379 | ||
1381 | buf = sd->buf; | 1380 | buf = sd->buf; |
1382 | len = sd->len; | 1381 | len = sd->len; |
1383 | type = sd->type; | 1382 | type = sd->type; |
1384 | 1383 | ||
1385 | list_del(&sd->list); | 1384 | list_del(&sd->list); |
1385 | spin_unlock_irqrestore(&priv->scan_lock, flags); | ||
1386 | kfree(sd); | 1386 | kfree(sd); |
1387 | 1387 | ||
1388 | if (len > 0) { | 1388 | if (len > 0) { |
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index f1a92144996f..4e368657a83c 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
@@ -719,6 +719,7 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
719 | { USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) }, | 719 | { USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) }, |
720 | { USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) }, | 720 | { USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) }, |
721 | { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) }, | 721 | { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) }, |
722 | { USB_DEVICE(0x1761, 0x0b05), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
722 | /* AzureWave */ | 723 | /* AzureWave */ |
723 | { USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) }, | 724 | { USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) }, |
724 | { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) }, | 725 | { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) }, |
@@ -913,7 +914,6 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
913 | { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) }, | 914 | { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) }, |
914 | { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) }, | 915 | { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) }, |
915 | { USB_DEVICE(0x0b05, 0x1790), USB_DEVICE_DATA(&rt2800usb_ops) }, | 916 | { USB_DEVICE(0x0b05, 0x1790), USB_DEVICE_DATA(&rt2800usb_ops) }, |
916 | { USB_DEVICE(0x1761, 0x0b05), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
917 | /* AzureWave */ | 917 | /* AzureWave */ |
918 | { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) }, | 918 | { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) }, |
919 | { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) }, | 919 | { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) }, |
@@ -937,6 +937,8 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
937 | { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, | 937 | { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, |
938 | { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) }, | 938 | { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) }, |
939 | { USB_DEVICE(0x07d1, 0x3c17), USB_DEVICE_DATA(&rt2800usb_ops) }, | 939 | { USB_DEVICE(0x07d1, 0x3c17), USB_DEVICE_DATA(&rt2800usb_ops) }, |
940 | /* Edimax */ | ||
941 | { USB_DEVICE(0x7392, 0x4085), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
940 | /* Encore */ | 942 | /* Encore */ |
941 | { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) }, | 943 | { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) }, |
942 | /* Gemtek */ | 944 | /* Gemtek */ |
@@ -961,6 +963,7 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
961 | { USB_DEVICE(0x1d4d, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, | 963 | { USB_DEVICE(0x1d4d, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, |
962 | { USB_DEVICE(0x1d4d, 0x0011), USB_DEVICE_DATA(&rt2800usb_ops) }, | 964 | { USB_DEVICE(0x1d4d, 0x0011), USB_DEVICE_DATA(&rt2800usb_ops) }, |
963 | /* Planex */ | 965 | /* Planex */ |
966 | { USB_DEVICE(0x2019, 0x5201), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
964 | { USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) }, | 967 | { USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) }, |
965 | /* Qcom */ | 968 | /* Qcom */ |
966 | { USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) }, | 969 | { USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) }, |
@@ -972,6 +975,8 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
972 | /* Sweex */ | 975 | /* Sweex */ |
973 | { USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) }, | 976 | { USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) }, |
974 | { USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) }, | 977 | { USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) }, |
978 | /* Toshiba */ | ||
979 | { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
975 | /* Zyxel */ | 980 | /* Zyxel */ |
976 | { USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) }, | 981 | { USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) }, |
977 | #endif | 982 | #endif |
diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c index 4f92cba6810a..f74a8701c67d 100644 --- a/drivers/net/wireless/rtlwifi/efuse.c +++ b/drivers/net/wireless/rtlwifi/efuse.c | |||
@@ -410,8 +410,8 @@ bool efuse_shadow_update(struct ieee80211_hw *hw) | |||
410 | 410 | ||
411 | if (!efuse_shadow_update_chk(hw)) { | 411 | if (!efuse_shadow_update_chk(hw)) { |
412 | efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); | 412 | efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); |
413 | memcpy((void *)&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], | 413 | memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], |
414 | (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], | 414 | &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], |
415 | rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); | 415 | rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); |
416 | 416 | ||
417 | RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, | 417 | RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, |
@@ -446,9 +446,9 @@ bool efuse_shadow_update(struct ieee80211_hw *hw) | |||
446 | 446 | ||
447 | if (word_en != 0x0F) { | 447 | if (word_en != 0x0F) { |
448 | u8 tmpdata[8]; | 448 | u8 tmpdata[8]; |
449 | memcpy((void *)tmpdata, | 449 | memcpy(tmpdata, |
450 | (void *)(&rtlefuse-> | 450 | &rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base], |
451 | efuse_map[EFUSE_MODIFY_MAP][base]), 8); | 451 | 8); |
452 | RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, | 452 | RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, |
453 | ("U-efuse\n"), tmpdata, 8); | 453 | ("U-efuse\n"), tmpdata, 8); |
454 | 454 | ||
@@ -465,8 +465,8 @@ bool efuse_shadow_update(struct ieee80211_hw *hw) | |||
465 | efuse_power_switch(hw, true, false); | 465 | efuse_power_switch(hw, true, false); |
466 | efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); | 466 | efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); |
467 | 467 | ||
468 | memcpy((void *)&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], | 468 | memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], |
469 | (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], | 469 | &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], |
470 | rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); | 470 | rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); |
471 | 471 | ||
472 | RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("<---\n")); | 472 | RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("<---\n")); |
@@ -479,13 +479,12 @@ void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw) | |||
479 | struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); | 479 | struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); |
480 | 480 | ||
481 | if (rtlefuse->autoload_failflag == true) { | 481 | if (rtlefuse->autoload_failflag == true) { |
482 | memset((void *)(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0]), 128, | 482 | memset(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 0xFF, 128); |
483 | 0xFF); | ||
484 | } else | 483 | } else |
485 | efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); | 484 | efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); |
486 | 485 | ||
487 | memcpy((void *)&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], | 486 | memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], |
488 | (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], | 487 | &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], |
489 | rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); | 488 | rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); |
490 | 489 | ||
491 | } | 490 | } |
@@ -694,8 +693,8 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) | |||
694 | if (offset > 15) | 693 | if (offset > 15) |
695 | return false; | 694 | return false; |
696 | 695 | ||
697 | memset((void *)data, PGPKT_DATA_SIZE * sizeof(u8), 0xff); | 696 | memset(data, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); |
698 | memset((void *)tmpdata, PGPKT_DATA_SIZE * sizeof(u8), 0xff); | 697 | memset(tmpdata, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); |
699 | 698 | ||
700 | while (bcontinual && (efuse_addr < EFUSE_MAX_SIZE)) { | 699 | while (bcontinual && (efuse_addr < EFUSE_MAX_SIZE)) { |
701 | if (readstate & PG_STATE_HEADER) { | 700 | if (readstate & PG_STATE_HEADER) { |
@@ -862,7 +861,7 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, | |||
862 | 861 | ||
863 | tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en); | 862 | tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en); |
864 | 863 | ||
865 | memset((void *)originaldata, 8 * sizeof(u8), 0xff); | 864 | memset(originaldata, 0xff, 8 * sizeof(u8)); |
866 | 865 | ||
867 | if (efuse_pg_packet_read(hw, tmp_pkt.offset, originaldata)) { | 866 | if (efuse_pg_packet_read(hw, tmp_pkt.offset, originaldata)) { |
868 | badworden = efuse_word_enable_data_write(hw, | 867 | badworden = efuse_word_enable_data_write(hw, |
@@ -917,7 +916,7 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, | |||
917 | target_pkt.offset = offset; | 916 | target_pkt.offset = offset; |
918 | target_pkt.word_en = word_en; | 917 | target_pkt.word_en = word_en; |
919 | 918 | ||
920 | memset((void *)target_pkt.data, 8 * sizeof(u8), 0xFF); | 919 | memset(target_pkt.data, 0xFF, 8 * sizeof(u8)); |
921 | 920 | ||
922 | efuse_word_enable_data_read(word_en, data, target_pkt.data); | 921 | efuse_word_enable_data_read(word_en, data, target_pkt.data); |
923 | target_word_cnts = efuse_calculate_word_cnts(target_pkt.word_en); | 922 | target_word_cnts = efuse_calculate_word_cnts(target_pkt.word_en); |
@@ -1022,7 +1021,7 @@ static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw, | |||
1022 | u8 badworden = 0x0F; | 1021 | u8 badworden = 0x0F; |
1023 | u8 tmpdata[8]; | 1022 | u8 tmpdata[8]; |
1024 | 1023 | ||
1025 | memset((void *)tmpdata, PGPKT_DATA_SIZE, 0xff); | 1024 | memset(tmpdata, 0xff, PGPKT_DATA_SIZE); |
1026 | RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, | 1025 | RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, |
1027 | ("word_en = %x efuse_addr=%x\n", word_en, efuse_addr)); | 1026 | ("word_en = %x efuse_addr=%x\n", word_en, efuse_addr)); |
1028 | 1027 | ||
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 81e80489a052..58236e6d0921 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c | |||
@@ -60,6 +60,7 @@ static struct usb_device_id usb_ids[] = { | |||
60 | { USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 }, | 60 | { USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 }, |
61 | { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 }, | 61 | { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 }, |
62 | { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 }, | 62 | { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 }, |
63 | { USB_DEVICE(0x157e, 0x3207), .driver_info = DEVICE_ZD1211 }, | ||
63 | { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 }, | 64 | { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 }, |
64 | { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 }, | 65 | { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 }, |
65 | /* ZD1211B */ | 66 | /* ZD1211B */ |
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 4789f8e8bf7a..a4115f1afe1f 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c | |||
@@ -36,7 +36,7 @@ | |||
36 | #include <linux/iova.h> | 36 | #include <linux/iova.h> |
37 | #include <linux/iommu.h> | 37 | #include <linux/iommu.h> |
38 | #include <linux/intel-iommu.h> | 38 | #include <linux/intel-iommu.h> |
39 | #include <linux/sysdev.h> | 39 | #include <linux/syscore_ops.h> |
40 | #include <linux/tboot.h> | 40 | #include <linux/tboot.h> |
41 | #include <linux/dmi.h> | 41 | #include <linux/dmi.h> |
42 | #include <asm/cacheflush.h> | 42 | #include <asm/cacheflush.h> |
@@ -3135,7 +3135,7 @@ static void iommu_flush_all(void) | |||
3135 | } | 3135 | } |
3136 | } | 3136 | } |
3137 | 3137 | ||
3138 | static int iommu_suspend(struct sys_device *dev, pm_message_t state) | 3138 | static int iommu_suspend(void) |
3139 | { | 3139 | { |
3140 | struct dmar_drhd_unit *drhd; | 3140 | struct dmar_drhd_unit *drhd; |
3141 | struct intel_iommu *iommu = NULL; | 3141 | struct intel_iommu *iommu = NULL; |
@@ -3175,7 +3175,7 @@ nomem: | |||
3175 | return -ENOMEM; | 3175 | return -ENOMEM; |
3176 | } | 3176 | } |
3177 | 3177 | ||
3178 | static int iommu_resume(struct sys_device *dev) | 3178 | static void iommu_resume(void) |
3179 | { | 3179 | { |
3180 | struct dmar_drhd_unit *drhd; | 3180 | struct dmar_drhd_unit *drhd; |
3181 | struct intel_iommu *iommu = NULL; | 3181 | struct intel_iommu *iommu = NULL; |
@@ -3183,7 +3183,7 @@ static int iommu_resume(struct sys_device *dev) | |||
3183 | 3183 | ||
3184 | if (init_iommu_hw()) { | 3184 | if (init_iommu_hw()) { |
3185 | WARN(1, "IOMMU setup failed, DMAR can not resume!\n"); | 3185 | WARN(1, "IOMMU setup failed, DMAR can not resume!\n"); |
3186 | return -EIO; | 3186 | return; |
3187 | } | 3187 | } |
3188 | 3188 | ||
3189 | for_each_active_iommu(iommu, drhd) { | 3189 | for_each_active_iommu(iommu, drhd) { |
@@ -3204,40 +3204,20 @@ static int iommu_resume(struct sys_device *dev) | |||
3204 | 3204 | ||
3205 | for_each_active_iommu(iommu, drhd) | 3205 | for_each_active_iommu(iommu, drhd) |
3206 | kfree(iommu->iommu_state); | 3206 | kfree(iommu->iommu_state); |
3207 | |||
3208 | return 0; | ||
3209 | } | 3207 | } |
3210 | 3208 | ||
3211 | static struct sysdev_class iommu_sysclass = { | 3209 | static struct syscore_ops iommu_syscore_ops = { |
3212 | .name = "iommu", | ||
3213 | .resume = iommu_resume, | 3210 | .resume = iommu_resume, |
3214 | .suspend = iommu_suspend, | 3211 | .suspend = iommu_suspend, |
3215 | }; | 3212 | }; |
3216 | 3213 | ||
3217 | static struct sys_device device_iommu = { | 3214 | static void __init init_iommu_pm_ops(void) |
3218 | .cls = &iommu_sysclass, | ||
3219 | }; | ||
3220 | |||
3221 | static int __init init_iommu_sysfs(void) | ||
3222 | { | 3215 | { |
3223 | int error; | 3216 | register_syscore_ops(&iommu_syscore_ops); |
3224 | |||
3225 | error = sysdev_class_register(&iommu_sysclass); | ||
3226 | if (error) | ||
3227 | return error; | ||
3228 | |||
3229 | error = sysdev_register(&device_iommu); | ||
3230 | if (error) | ||
3231 | sysdev_class_unregister(&iommu_sysclass); | ||
3232 | |||
3233 | return error; | ||
3234 | } | 3217 | } |
3235 | 3218 | ||
3236 | #else | 3219 | #else |
3237 | static int __init init_iommu_sysfs(void) | 3220 | static inline int init_iommu_pm_ops(void) { } |
3238 | { | ||
3239 | return 0; | ||
3240 | } | ||
3241 | #endif /* CONFIG_PM */ | 3221 | #endif /* CONFIG_PM */ |
3242 | 3222 | ||
3243 | /* | 3223 | /* |
@@ -3320,7 +3300,7 @@ int __init intel_iommu_init(void) | |||
3320 | #endif | 3300 | #endif |
3321 | dma_ops = &intel_dma_ops; | 3301 | dma_ops = &intel_dma_ops; |
3322 | 3302 | ||
3323 | init_iommu_sysfs(); | 3303 | init_iommu_pm_ops(); |
3324 | 3304 | ||
3325 | register_iommu(&intel_iommu_ops); | 3305 | register_iommu(&intel_iommu_ops); |
3326 | 3306 | ||
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b714d787bddd..2472e7177b4b 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -740,6 +740,12 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
740 | 740 | ||
741 | if (!__pci_complete_power_transition(dev, state)) | 741 | if (!__pci_complete_power_transition(dev, state)) |
742 | error = 0; | 742 | error = 0; |
743 | /* | ||
744 | * When aspm_policy is "powersave" this call ensures | ||
745 | * that ASPM is configured. | ||
746 | */ | ||
747 | if (!error && dev->bus->self) | ||
748 | pcie_aspm_powersave_config_link(dev->bus->self); | ||
743 | 749 | ||
744 | return error; | 750 | return error; |
745 | } | 751 | } |
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 3188cd96b338..eee09f756ec9 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c | |||
@@ -69,6 +69,7 @@ struct pcie_link_state { | |||
69 | }; | 69 | }; |
70 | 70 | ||
71 | static int aspm_disabled, aspm_force, aspm_clear_state; | 71 | static int aspm_disabled, aspm_force, aspm_clear_state; |
72 | static bool aspm_support_enabled = true; | ||
72 | static DEFINE_MUTEX(aspm_lock); | 73 | static DEFINE_MUTEX(aspm_lock); |
73 | static LIST_HEAD(link_list); | 74 | static LIST_HEAD(link_list); |
74 | 75 | ||
@@ -707,6 +708,28 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev) | |||
707 | up_read(&pci_bus_sem); | 708 | up_read(&pci_bus_sem); |
708 | } | 709 | } |
709 | 710 | ||
711 | void pcie_aspm_powersave_config_link(struct pci_dev *pdev) | ||
712 | { | ||
713 | struct pcie_link_state *link = pdev->link_state; | ||
714 | |||
715 | if (aspm_disabled || !pci_is_pcie(pdev) || !link) | ||
716 | return; | ||
717 | |||
718 | if (aspm_policy != POLICY_POWERSAVE) | ||
719 | return; | ||
720 | |||
721 | if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && | ||
722 | (pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) | ||
723 | return; | ||
724 | |||
725 | down_read(&pci_bus_sem); | ||
726 | mutex_lock(&aspm_lock); | ||
727 | pcie_config_aspm_path(link); | ||
728 | pcie_set_clkpm(link, policy_to_clkpm_state(link)); | ||
729 | mutex_unlock(&aspm_lock); | ||
730 | up_read(&pci_bus_sem); | ||
731 | } | ||
732 | |||
710 | /* | 733 | /* |
711 | * pci_disable_link_state - disable pci device's link state, so the link will | 734 | * pci_disable_link_state - disable pci device's link state, so the link will |
712 | * never enter specific states | 735 | * never enter specific states |
@@ -747,6 +770,8 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) | |||
747 | int i; | 770 | int i; |
748 | struct pcie_link_state *link; | 771 | struct pcie_link_state *link; |
749 | 772 | ||
773 | if (aspm_disabled) | ||
774 | return -EPERM; | ||
750 | for (i = 0; i < ARRAY_SIZE(policy_str); i++) | 775 | for (i = 0; i < ARRAY_SIZE(policy_str); i++) |
751 | if (!strncmp(val, policy_str[i], strlen(policy_str[i]))) | 776 | if (!strncmp(val, policy_str[i], strlen(policy_str[i]))) |
752 | break; | 777 | break; |
@@ -801,6 +826,8 @@ static ssize_t link_state_store(struct device *dev, | |||
801 | struct pcie_link_state *link, *root = pdev->link_state->root; | 826 | struct pcie_link_state *link, *root = pdev->link_state->root; |
802 | u32 val = buf[0] - '0', state = 0; | 827 | u32 val = buf[0] - '0', state = 0; |
803 | 828 | ||
829 | if (aspm_disabled) | ||
830 | return -EPERM; | ||
804 | if (n < 1 || val > 3) | 831 | if (n < 1 || val > 3) |
805 | return -EINVAL; | 832 | return -EINVAL; |
806 | 833 | ||
@@ -896,6 +923,7 @@ static int __init pcie_aspm_disable(char *str) | |||
896 | { | 923 | { |
897 | if (!strcmp(str, "off")) { | 924 | if (!strcmp(str, "off")) { |
898 | aspm_disabled = 1; | 925 | aspm_disabled = 1; |
926 | aspm_support_enabled = false; | ||
899 | printk(KERN_INFO "PCIe ASPM is disabled\n"); | 927 | printk(KERN_INFO "PCIe ASPM is disabled\n"); |
900 | } else if (!strcmp(str, "force")) { | 928 | } else if (!strcmp(str, "force")) { |
901 | aspm_force = 1; | 929 | aspm_force = 1; |
@@ -930,3 +958,8 @@ int pcie_aspm_enabled(void) | |||
930 | } | 958 | } |
931 | EXPORT_SYMBOL(pcie_aspm_enabled); | 959 | EXPORT_SYMBOL(pcie_aspm_enabled); |
932 | 960 | ||
961 | bool pcie_aspm_support_enabled(void) | ||
962 | { | ||
963 | return aspm_support_enabled; | ||
964 | } | ||
965 | EXPORT_SYMBOL(pcie_aspm_support_enabled); | ||
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 5130d0d22390..595654a1a6a6 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c | |||
@@ -15,7 +15,6 @@ | |||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/pcieport_if.h> | 16 | #include <linux/pcieport_if.h> |
17 | #include <linux/aer.h> | 17 | #include <linux/aer.h> |
18 | #include <linux/pci-aspm.h> | ||
19 | 18 | ||
20 | #include "../pci.h" | 19 | #include "../pci.h" |
21 | #include "portdrv.h" | 20 | #include "portdrv.h" |
@@ -356,10 +355,8 @@ int pcie_port_device_register(struct pci_dev *dev) | |||
356 | 355 | ||
357 | /* Get and check PCI Express port services */ | 356 | /* Get and check PCI Express port services */ |
358 | capabilities = get_port_device_capability(dev); | 357 | capabilities = get_port_device_capability(dev); |
359 | if (!capabilities) { | 358 | if (!capabilities) |
360 | pcie_no_aspm(); | ||
361 | return 0; | 359 | return 0; |
362 | } | ||
363 | 360 | ||
364 | pci_set_master(dev); | 361 | pci_set_master(dev); |
365 | /* | 362 | /* |
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 61bf5d724139..52a462fc6b84 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig | |||
@@ -117,10 +117,24 @@ config BATTERY_BQ20Z75 | |||
117 | 117 | ||
118 | config BATTERY_BQ27x00 | 118 | config BATTERY_BQ27x00 |
119 | tristate "BQ27x00 battery driver" | 119 | tristate "BQ27x00 battery driver" |
120 | help | ||
121 | Say Y here to enable support for batteries with BQ27x00 (I2C/HDQ) chips. | ||
122 | |||
123 | config BATTERY_BQ27X00_I2C | ||
124 | bool "BQ27200/BQ27500 support" | ||
125 | depends on BATTERY_BQ27x00 | ||
120 | depends on I2C | 126 | depends on I2C |
127 | default y | ||
121 | help | 128 | help |
122 | Say Y here to enable support for batteries with BQ27x00 (I2C) chips. | 129 | Say Y here to enable support for batteries with BQ27x00 (I2C) chips. |
123 | 130 | ||
131 | config BATTERY_BQ27X00_PLATFORM | ||
132 | bool "BQ27000 support" | ||
133 | depends on BATTERY_BQ27x00 | ||
134 | default y | ||
135 | help | ||
136 | Say Y here to enable support for batteries with BQ27000 (HDQ) chips. | ||
137 | |||
124 | config BATTERY_DA9030 | 138 | config BATTERY_DA9030 |
125 | tristate "DA9030 battery driver" | 139 | tristate "DA9030 battery driver" |
126 | depends on PMIC_DA903X | 140 | depends on PMIC_DA903X |
diff --git a/drivers/power/bq20z75.c b/drivers/power/bq20z75.c index 492da27e1a47..506585e31a5b 100644 --- a/drivers/power/bq20z75.c +++ b/drivers/power/bq20z75.c | |||
@@ -25,6 +25,10 @@ | |||
25 | #include <linux/power_supply.h> | 25 | #include <linux/power_supply.h> |
26 | #include <linux/i2c.h> | 26 | #include <linux/i2c.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/gpio.h> | ||
30 | |||
31 | #include <linux/power/bq20z75.h> | ||
28 | 32 | ||
29 | enum { | 33 | enum { |
30 | REG_MANUFACTURER_DATA, | 34 | REG_MANUFACTURER_DATA, |
@@ -38,11 +42,22 @@ enum { | |||
38 | REG_CYCLE_COUNT, | 42 | REG_CYCLE_COUNT, |
39 | REG_SERIAL_NUMBER, | 43 | REG_SERIAL_NUMBER, |
40 | REG_REMAINING_CAPACITY, | 44 | REG_REMAINING_CAPACITY, |
45 | REG_REMAINING_CAPACITY_CHARGE, | ||
41 | REG_FULL_CHARGE_CAPACITY, | 46 | REG_FULL_CHARGE_CAPACITY, |
47 | REG_FULL_CHARGE_CAPACITY_CHARGE, | ||
42 | REG_DESIGN_CAPACITY, | 48 | REG_DESIGN_CAPACITY, |
49 | REG_DESIGN_CAPACITY_CHARGE, | ||
43 | REG_DESIGN_VOLTAGE, | 50 | REG_DESIGN_VOLTAGE, |
44 | }; | 51 | }; |
45 | 52 | ||
53 | /* Battery Mode defines */ | ||
54 | #define BATTERY_MODE_OFFSET 0x03 | ||
55 | #define BATTERY_MODE_MASK 0x8000 | ||
56 | enum bq20z75_battery_mode { | ||
57 | BATTERY_MODE_AMPS, | ||
58 | BATTERY_MODE_WATTS | ||
59 | }; | ||
60 | |||
46 | /* manufacturer access defines */ | 61 | /* manufacturer access defines */ |
47 | #define MANUFACTURER_ACCESS_STATUS 0x0006 | 62 | #define MANUFACTURER_ACCESS_STATUS 0x0006 |
48 | #define MANUFACTURER_ACCESS_SLEEP 0x0011 | 63 | #define MANUFACTURER_ACCESS_SLEEP 0x0011 |
@@ -78,8 +93,12 @@ static const struct bq20z75_device_data { | |||
78 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100), | 93 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100), |
79 | [REG_REMAINING_CAPACITY] = | 94 | [REG_REMAINING_CAPACITY] = |
80 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535), | 95 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535), |
96 | [REG_REMAINING_CAPACITY_CHARGE] = | ||
97 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_NOW, 0x0F, 0, 65535), | ||
81 | [REG_FULL_CHARGE_CAPACITY] = | 98 | [REG_FULL_CHARGE_CAPACITY] = |
82 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535), | 99 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535), |
100 | [REG_FULL_CHARGE_CAPACITY_CHARGE] = | ||
101 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL, 0x10, 0, 65535), | ||
83 | [REG_TIME_TO_EMPTY] = | 102 | [REG_TIME_TO_EMPTY] = |
84 | BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0, | 103 | BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0, |
85 | 65535), | 104 | 65535), |
@@ -93,6 +112,9 @@ static const struct bq20z75_device_data { | |||
93 | [REG_DESIGN_CAPACITY] = | 112 | [REG_DESIGN_CAPACITY] = |
94 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0, | 113 | BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0, |
95 | 65535), | 114 | 65535), |
115 | [REG_DESIGN_CAPACITY_CHARGE] = | ||
116 | BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 0x18, 0, | ||
117 | 65535), | ||
96 | [REG_DESIGN_VOLTAGE] = | 118 | [REG_DESIGN_VOLTAGE] = |
97 | BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0, | 119 | BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0, |
98 | 65535), | 120 | 65535), |
@@ -117,39 +139,72 @@ static enum power_supply_property bq20z75_properties[] = { | |||
117 | POWER_SUPPLY_PROP_ENERGY_NOW, | 139 | POWER_SUPPLY_PROP_ENERGY_NOW, |
118 | POWER_SUPPLY_PROP_ENERGY_FULL, | 140 | POWER_SUPPLY_PROP_ENERGY_FULL, |
119 | POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, | 141 | POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, |
142 | POWER_SUPPLY_PROP_CHARGE_NOW, | ||
143 | POWER_SUPPLY_PROP_CHARGE_FULL, | ||
144 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | ||
120 | }; | 145 | }; |
121 | 146 | ||
122 | struct bq20z75_info { | 147 | struct bq20z75_info { |
123 | struct i2c_client *client; | 148 | struct i2c_client *client; |
124 | struct power_supply power_supply; | 149 | struct power_supply power_supply; |
150 | struct bq20z75_platform_data *pdata; | ||
151 | bool is_present; | ||
152 | bool gpio_detect; | ||
153 | bool enable_detection; | ||
154 | int irq; | ||
125 | }; | 155 | }; |
126 | 156 | ||
127 | static int bq20z75_read_word_data(struct i2c_client *client, u8 address) | 157 | static int bq20z75_read_word_data(struct i2c_client *client, u8 address) |
128 | { | 158 | { |
129 | s32 ret; | 159 | struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); |
160 | s32 ret = 0; | ||
161 | int retries = 1; | ||
162 | |||
163 | if (bq20z75_device->pdata) | ||
164 | retries = max(bq20z75_device->pdata->i2c_retry_count + 1, 1); | ||
165 | |||
166 | while (retries > 0) { | ||
167 | ret = i2c_smbus_read_word_data(client, address); | ||
168 | if (ret >= 0) | ||
169 | break; | ||
170 | retries--; | ||
171 | } | ||
130 | 172 | ||
131 | ret = i2c_smbus_read_word_data(client, address); | ||
132 | if (ret < 0) { | 173 | if (ret < 0) { |
133 | dev_err(&client->dev, | 174 | dev_dbg(&client->dev, |
134 | "%s: i2c read at address 0x%x failed\n", | 175 | "%s: i2c read at address 0x%x failed\n", |
135 | __func__, address); | 176 | __func__, address); |
136 | return ret; | 177 | return ret; |
137 | } | 178 | } |
179 | |||
138 | return le16_to_cpu(ret); | 180 | return le16_to_cpu(ret); |
139 | } | 181 | } |
140 | 182 | ||
141 | static int bq20z75_write_word_data(struct i2c_client *client, u8 address, | 183 | static int bq20z75_write_word_data(struct i2c_client *client, u8 address, |
142 | u16 value) | 184 | u16 value) |
143 | { | 185 | { |
144 | s32 ret; | 186 | struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); |
187 | s32 ret = 0; | ||
188 | int retries = 1; | ||
189 | |||
190 | if (bq20z75_device->pdata) | ||
191 | retries = max(bq20z75_device->pdata->i2c_retry_count + 1, 1); | ||
192 | |||
193 | while (retries > 0) { | ||
194 | ret = i2c_smbus_write_word_data(client, address, | ||
195 | le16_to_cpu(value)); | ||
196 | if (ret >= 0) | ||
197 | break; | ||
198 | retries--; | ||
199 | } | ||
145 | 200 | ||
146 | ret = i2c_smbus_write_word_data(client, address, le16_to_cpu(value)); | ||
147 | if (ret < 0) { | 201 | if (ret < 0) { |
148 | dev_err(&client->dev, | 202 | dev_dbg(&client->dev, |
149 | "%s: i2c write to address 0x%x failed\n", | 203 | "%s: i2c write to address 0x%x failed\n", |
150 | __func__, address); | 204 | __func__, address); |
151 | return ret; | 205 | return ret; |
152 | } | 206 | } |
207 | |||
153 | return 0; | 208 | return 0; |
154 | } | 209 | } |
155 | 210 | ||
@@ -158,6 +213,19 @@ static int bq20z75_get_battery_presence_and_health( | |||
158 | union power_supply_propval *val) | 213 | union power_supply_propval *val) |
159 | { | 214 | { |
160 | s32 ret; | 215 | s32 ret; |
216 | struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); | ||
217 | |||
218 | if (psp == POWER_SUPPLY_PROP_PRESENT && | ||
219 | bq20z75_device->gpio_detect) { | ||
220 | ret = gpio_get_value( | ||
221 | bq20z75_device->pdata->battery_detect); | ||
222 | if (ret == bq20z75_device->pdata->battery_detect_present) | ||
223 | val->intval = 1; | ||
224 | else | ||
225 | val->intval = 0; | ||
226 | bq20z75_device->is_present = val->intval; | ||
227 | return ret; | ||
228 | } | ||
161 | 229 | ||
162 | /* Write to ManufacturerAccess with | 230 | /* Write to ManufacturerAccess with |
163 | * ManufacturerAccess command and then | 231 | * ManufacturerAccess command and then |
@@ -165,9 +233,11 @@ static int bq20z75_get_battery_presence_and_health( | |||
165 | ret = bq20z75_write_word_data(client, | 233 | ret = bq20z75_write_word_data(client, |
166 | bq20z75_data[REG_MANUFACTURER_DATA].addr, | 234 | bq20z75_data[REG_MANUFACTURER_DATA].addr, |
167 | MANUFACTURER_ACCESS_STATUS); | 235 | MANUFACTURER_ACCESS_STATUS); |
168 | if (ret < 0) | 236 | if (ret < 0) { |
237 | if (psp == POWER_SUPPLY_PROP_PRESENT) | ||
238 | val->intval = 0; /* battery removed */ | ||
169 | return ret; | 239 | return ret; |
170 | 240 | } | |
171 | 241 | ||
172 | ret = bq20z75_read_word_data(client, | 242 | ret = bq20z75_read_word_data(client, |
173 | bq20z75_data[REG_MANUFACTURER_DATA].addr); | 243 | bq20z75_data[REG_MANUFACTURER_DATA].addr); |
@@ -248,30 +318,39 @@ static void bq20z75_unit_adjustment(struct i2c_client *client, | |||
248 | { | 318 | { |
249 | #define BASE_UNIT_CONVERSION 1000 | 319 | #define BASE_UNIT_CONVERSION 1000 |
250 | #define BATTERY_MODE_CAP_MULT_WATT (10 * BASE_UNIT_CONVERSION) | 320 | #define BATTERY_MODE_CAP_MULT_WATT (10 * BASE_UNIT_CONVERSION) |
251 | #define TIME_UNIT_CONVERSION 600 | 321 | #define TIME_UNIT_CONVERSION 60 |
252 | #define TEMP_KELVIN_TO_CELCIUS 2731 | 322 | #define TEMP_KELVIN_TO_CELSIUS 2731 |
253 | switch (psp) { | 323 | switch (psp) { |
254 | case POWER_SUPPLY_PROP_ENERGY_NOW: | 324 | case POWER_SUPPLY_PROP_ENERGY_NOW: |
255 | case POWER_SUPPLY_PROP_ENERGY_FULL: | 325 | case POWER_SUPPLY_PROP_ENERGY_FULL: |
256 | case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: | 326 | case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: |
327 | /* bq20z75 provides energy in units of 10mWh. | ||
328 | * Convert to µWh | ||
329 | */ | ||
257 | val->intval *= BATTERY_MODE_CAP_MULT_WATT; | 330 | val->intval *= BATTERY_MODE_CAP_MULT_WATT; |
258 | break; | 331 | break; |
259 | 332 | ||
260 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | 333 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: |
261 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: | 334 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: |
262 | case POWER_SUPPLY_PROP_CURRENT_NOW: | 335 | case POWER_SUPPLY_PROP_CURRENT_NOW: |
336 | case POWER_SUPPLY_PROP_CHARGE_NOW: | ||
337 | case POWER_SUPPLY_PROP_CHARGE_FULL: | ||
338 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | ||
263 | val->intval *= BASE_UNIT_CONVERSION; | 339 | val->intval *= BASE_UNIT_CONVERSION; |
264 | break; | 340 | break; |
265 | 341 | ||
266 | case POWER_SUPPLY_PROP_TEMP: | 342 | case POWER_SUPPLY_PROP_TEMP: |
267 | /* bq20z75 provides battery tempreture in 0.1°K | 343 | /* bq20z75 provides battery temperature in 0.1K |
268 | * so convert it to 0.1°C */ | 344 | * so convert it to 0.1°C |
269 | val->intval -= TEMP_KELVIN_TO_CELCIUS; | 345 | */ |
270 | val->intval *= 10; | 346 | val->intval -= TEMP_KELVIN_TO_CELSIUS; |
271 | break; | 347 | break; |
272 | 348 | ||
273 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: | 349 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: |
274 | case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: | 350 | case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: |
351 | /* bq20z75 provides time to empty and time to full in minutes. | ||
352 | * Convert to seconds | ||
353 | */ | ||
275 | val->intval *= TIME_UNIT_CONVERSION; | 354 | val->intval *= TIME_UNIT_CONVERSION; |
276 | break; | 355 | break; |
277 | 356 | ||
@@ -281,11 +360,44 @@ static void bq20z75_unit_adjustment(struct i2c_client *client, | |||
281 | } | 360 | } |
282 | } | 361 | } |
283 | 362 | ||
363 | static enum bq20z75_battery_mode | ||
364 | bq20z75_set_battery_mode(struct i2c_client *client, | ||
365 | enum bq20z75_battery_mode mode) | ||
366 | { | ||
367 | int ret, original_val; | ||
368 | |||
369 | original_val = bq20z75_read_word_data(client, BATTERY_MODE_OFFSET); | ||
370 | if (original_val < 0) | ||
371 | return original_val; | ||
372 | |||
373 | if ((original_val & BATTERY_MODE_MASK) == mode) | ||
374 | return mode; | ||
375 | |||
376 | if (mode == BATTERY_MODE_AMPS) | ||
377 | ret = original_val & ~BATTERY_MODE_MASK; | ||
378 | else | ||
379 | ret = original_val | BATTERY_MODE_MASK; | ||
380 | |||
381 | ret = bq20z75_write_word_data(client, BATTERY_MODE_OFFSET, ret); | ||
382 | if (ret < 0) | ||
383 | return ret; | ||
384 | |||
385 | return original_val & BATTERY_MODE_MASK; | ||
386 | } | ||
387 | |||
284 | static int bq20z75_get_battery_capacity(struct i2c_client *client, | 388 | static int bq20z75_get_battery_capacity(struct i2c_client *client, |
285 | int reg_offset, enum power_supply_property psp, | 389 | int reg_offset, enum power_supply_property psp, |
286 | union power_supply_propval *val) | 390 | union power_supply_propval *val) |
287 | { | 391 | { |
288 | s32 ret; | 392 | s32 ret; |
393 | enum bq20z75_battery_mode mode = BATTERY_MODE_WATTS; | ||
394 | |||
395 | if (power_supply_is_amp_property(psp)) | ||
396 | mode = BATTERY_MODE_AMPS; | ||
397 | |||
398 | mode = bq20z75_set_battery_mode(client, mode); | ||
399 | if (mode < 0) | ||
400 | return mode; | ||
289 | 401 | ||
290 | ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr); | 402 | ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr); |
291 | if (ret < 0) | 403 | if (ret < 0) |
@@ -298,6 +410,10 @@ static int bq20z75_get_battery_capacity(struct i2c_client *client, | |||
298 | } else | 410 | } else |
299 | val->intval = ret; | 411 | val->intval = ret; |
300 | 412 | ||
413 | ret = bq20z75_set_battery_mode(client, mode); | ||
414 | if (ret < 0) | ||
415 | return ret; | ||
416 | |||
301 | return 0; | 417 | return 0; |
302 | } | 418 | } |
303 | 419 | ||
@@ -318,12 +434,25 @@ static int bq20z75_get_battery_serial_number(struct i2c_client *client, | |||
318 | return 0; | 434 | return 0; |
319 | } | 435 | } |
320 | 436 | ||
437 | static int bq20z75_get_property_index(struct i2c_client *client, | ||
438 | enum power_supply_property psp) | ||
439 | { | ||
440 | int count; | ||
441 | for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) | ||
442 | if (psp == bq20z75_data[count].psp) | ||
443 | return count; | ||
444 | |||
445 | dev_warn(&client->dev, | ||
446 | "%s: Invalid Property - %d\n", __func__, psp); | ||
447 | |||
448 | return -EINVAL; | ||
449 | } | ||
450 | |||
321 | static int bq20z75_get_property(struct power_supply *psy, | 451 | static int bq20z75_get_property(struct power_supply *psy, |
322 | enum power_supply_property psp, | 452 | enum power_supply_property psp, |
323 | union power_supply_propval *val) | 453 | union power_supply_propval *val) |
324 | { | 454 | { |
325 | int count; | 455 | int ret = 0; |
326 | int ret; | ||
327 | struct bq20z75_info *bq20z75_device = container_of(psy, | 456 | struct bq20z75_info *bq20z75_device = container_of(psy, |
328 | struct bq20z75_info, power_supply); | 457 | struct bq20z75_info, power_supply); |
329 | struct i2c_client *client = bq20z75_device->client; | 458 | struct i2c_client *client = bq20z75_device->client; |
@@ -332,8 +461,8 @@ static int bq20z75_get_property(struct power_supply *psy, | |||
332 | case POWER_SUPPLY_PROP_PRESENT: | 461 | case POWER_SUPPLY_PROP_PRESENT: |
333 | case POWER_SUPPLY_PROP_HEALTH: | 462 | case POWER_SUPPLY_PROP_HEALTH: |
334 | ret = bq20z75_get_battery_presence_and_health(client, psp, val); | 463 | ret = bq20z75_get_battery_presence_and_health(client, psp, val); |
335 | if (ret) | 464 | if (psp == POWER_SUPPLY_PROP_PRESENT) |
336 | return ret; | 465 | return 0; |
337 | break; | 466 | break; |
338 | 467 | ||
339 | case POWER_SUPPLY_PROP_TECHNOLOGY: | 468 | case POWER_SUPPLY_PROP_TECHNOLOGY: |
@@ -343,22 +472,19 @@ static int bq20z75_get_property(struct power_supply *psy, | |||
343 | case POWER_SUPPLY_PROP_ENERGY_NOW: | 472 | case POWER_SUPPLY_PROP_ENERGY_NOW: |
344 | case POWER_SUPPLY_PROP_ENERGY_FULL: | 473 | case POWER_SUPPLY_PROP_ENERGY_FULL: |
345 | case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: | 474 | case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: |
475 | case POWER_SUPPLY_PROP_CHARGE_NOW: | ||
476 | case POWER_SUPPLY_PROP_CHARGE_FULL: | ||
477 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | ||
346 | case POWER_SUPPLY_PROP_CAPACITY: | 478 | case POWER_SUPPLY_PROP_CAPACITY: |
347 | for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) { | 479 | ret = bq20z75_get_property_index(client, psp); |
348 | if (psp == bq20z75_data[count].psp) | 480 | if (ret < 0) |
349 | break; | 481 | break; |
350 | } | ||
351 | |||
352 | ret = bq20z75_get_battery_capacity(client, count, psp, val); | ||
353 | if (ret) | ||
354 | return ret; | ||
355 | 482 | ||
483 | ret = bq20z75_get_battery_capacity(client, ret, psp, val); | ||
356 | break; | 484 | break; |
357 | 485 | ||
358 | case POWER_SUPPLY_PROP_SERIAL_NUMBER: | 486 | case POWER_SUPPLY_PROP_SERIAL_NUMBER: |
359 | ret = bq20z75_get_battery_serial_number(client, val); | 487 | ret = bq20z75_get_battery_serial_number(client, val); |
360 | if (ret) | ||
361 | return ret; | ||
362 | break; | 488 | break; |
363 | 489 | ||
364 | case POWER_SUPPLY_PROP_STATUS: | 490 | case POWER_SUPPLY_PROP_STATUS: |
@@ -369,15 +495,11 @@ static int bq20z75_get_property(struct power_supply *psy, | |||
369 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: | 495 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: |
370 | case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: | 496 | case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: |
371 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: | 497 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: |
372 | for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) { | 498 | ret = bq20z75_get_property_index(client, psp); |
373 | if (psp == bq20z75_data[count].psp) | 499 | if (ret < 0) |
374 | break; | 500 | break; |
375 | } | ||
376 | |||
377 | ret = bq20z75_get_battery_property(client, count, psp, val); | ||
378 | if (ret) | ||
379 | return ret; | ||
380 | 501 | ||
502 | ret = bq20z75_get_battery_property(client, ret, psp, val); | ||
381 | break; | 503 | break; |
382 | 504 | ||
383 | default: | 505 | default: |
@@ -386,26 +508,58 @@ static int bq20z75_get_property(struct power_supply *psy, | |||
386 | return -EINVAL; | 508 | return -EINVAL; |
387 | } | 509 | } |
388 | 510 | ||
389 | /* Convert units to match requirements for power supply class */ | 511 | if (!bq20z75_device->enable_detection) |
390 | bq20z75_unit_adjustment(client, psp, val); | 512 | goto done; |
513 | |||
514 | if (!bq20z75_device->gpio_detect && | ||
515 | bq20z75_device->is_present != (ret >= 0)) { | ||
516 | bq20z75_device->is_present = (ret >= 0); | ||
517 | power_supply_changed(&bq20z75_device->power_supply); | ||
518 | } | ||
519 | |||
520 | done: | ||
521 | if (!ret) { | ||
522 | /* Convert units to match requirements for power supply class */ | ||
523 | bq20z75_unit_adjustment(client, psp, val); | ||
524 | } | ||
391 | 525 | ||
392 | dev_dbg(&client->dev, | 526 | dev_dbg(&client->dev, |
393 | "%s: property = %d, value = %d\n", __func__, psp, val->intval); | 527 | "%s: property = %d, value = %x\n", __func__, psp, val->intval); |
528 | |||
529 | if (ret && bq20z75_device->is_present) | ||
530 | return ret; | ||
531 | |||
532 | /* battery not present, so return NODATA for properties */ | ||
533 | if (ret) | ||
534 | return -ENODATA; | ||
394 | 535 | ||
395 | return 0; | 536 | return 0; |
396 | } | 537 | } |
397 | 538 | ||
398 | static int bq20z75_probe(struct i2c_client *client, | 539 | static irqreturn_t bq20z75_irq(int irq, void *devid) |
540 | { | ||
541 | struct power_supply *battery = devid; | ||
542 | |||
543 | power_supply_changed(battery); | ||
544 | |||
545 | return IRQ_HANDLED; | ||
546 | } | ||
547 | |||
548 | static int __devinit bq20z75_probe(struct i2c_client *client, | ||
399 | const struct i2c_device_id *id) | 549 | const struct i2c_device_id *id) |
400 | { | 550 | { |
401 | struct bq20z75_info *bq20z75_device; | 551 | struct bq20z75_info *bq20z75_device; |
552 | struct bq20z75_platform_data *pdata = client->dev.platform_data; | ||
402 | int rc; | 553 | int rc; |
554 | int irq; | ||
403 | 555 | ||
404 | bq20z75_device = kzalloc(sizeof(struct bq20z75_info), GFP_KERNEL); | 556 | bq20z75_device = kzalloc(sizeof(struct bq20z75_info), GFP_KERNEL); |
405 | if (!bq20z75_device) | 557 | if (!bq20z75_device) |
406 | return -ENOMEM; | 558 | return -ENOMEM; |
407 | 559 | ||
408 | bq20z75_device->client = client; | 560 | bq20z75_device->client = client; |
561 | bq20z75_device->enable_detection = false; | ||
562 | bq20z75_device->gpio_detect = false; | ||
409 | bq20z75_device->power_supply.name = "battery"; | 563 | bq20z75_device->power_supply.name = "battery"; |
410 | bq20z75_device->power_supply.type = POWER_SUPPLY_TYPE_BATTERY; | 564 | bq20z75_device->power_supply.type = POWER_SUPPLY_TYPE_BATTERY; |
411 | bq20z75_device->power_supply.properties = bq20z75_properties; | 565 | bq20z75_device->power_supply.properties = bq20z75_properties; |
@@ -413,26 +567,86 @@ static int bq20z75_probe(struct i2c_client *client, | |||
413 | ARRAY_SIZE(bq20z75_properties); | 567 | ARRAY_SIZE(bq20z75_properties); |
414 | bq20z75_device->power_supply.get_property = bq20z75_get_property; | 568 | bq20z75_device->power_supply.get_property = bq20z75_get_property; |
415 | 569 | ||
570 | if (pdata) { | ||
571 | bq20z75_device->gpio_detect = | ||
572 | gpio_is_valid(pdata->battery_detect); | ||
573 | bq20z75_device->pdata = pdata; | ||
574 | } | ||
575 | |||
416 | i2c_set_clientdata(client, bq20z75_device); | 576 | i2c_set_clientdata(client, bq20z75_device); |
417 | 577 | ||
578 | if (!bq20z75_device->gpio_detect) | ||
579 | goto skip_gpio; | ||
580 | |||
581 | rc = gpio_request(pdata->battery_detect, dev_name(&client->dev)); | ||
582 | if (rc) { | ||
583 | dev_warn(&client->dev, "Failed to request gpio: %d\n", rc); | ||
584 | bq20z75_device->gpio_detect = false; | ||
585 | goto skip_gpio; | ||
586 | } | ||
587 | |||
588 | rc = gpio_direction_input(pdata->battery_detect); | ||
589 | if (rc) { | ||
590 | dev_warn(&client->dev, "Failed to get gpio as input: %d\n", rc); | ||
591 | gpio_free(pdata->battery_detect); | ||
592 | bq20z75_device->gpio_detect = false; | ||
593 | goto skip_gpio; | ||
594 | } | ||
595 | |||
596 | irq = gpio_to_irq(pdata->battery_detect); | ||
597 | if (irq <= 0) { | ||
598 | dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); | ||
599 | gpio_free(pdata->battery_detect); | ||
600 | bq20z75_device->gpio_detect = false; | ||
601 | goto skip_gpio; | ||
602 | } | ||
603 | |||
604 | rc = request_irq(irq, bq20z75_irq, | ||
605 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | ||
606 | dev_name(&client->dev), &bq20z75_device->power_supply); | ||
607 | if (rc) { | ||
608 | dev_warn(&client->dev, "Failed to request irq: %d\n", rc); | ||
609 | gpio_free(pdata->battery_detect); | ||
610 | bq20z75_device->gpio_detect = false; | ||
611 | goto skip_gpio; | ||
612 | } | ||
613 | |||
614 | bq20z75_device->irq = irq; | ||
615 | |||
616 | skip_gpio: | ||
617 | |||
418 | rc = power_supply_register(&client->dev, &bq20z75_device->power_supply); | 618 | rc = power_supply_register(&client->dev, &bq20z75_device->power_supply); |
419 | if (rc) { | 619 | if (rc) { |
420 | dev_err(&client->dev, | 620 | dev_err(&client->dev, |
421 | "%s: Failed to register power supply\n", __func__); | 621 | "%s: Failed to register power supply\n", __func__); |
422 | kfree(bq20z75_device); | 622 | goto exit_psupply; |
423 | return rc; | ||
424 | } | 623 | } |
425 | 624 | ||
426 | dev_info(&client->dev, | 625 | dev_info(&client->dev, |
427 | "%s: battery gas gauge device registered\n", client->name); | 626 | "%s: battery gas gauge device registered\n", client->name); |
428 | 627 | ||
429 | return 0; | 628 | return 0; |
629 | |||
630 | exit_psupply: | ||
631 | if (bq20z75_device->irq) | ||
632 | free_irq(bq20z75_device->irq, &bq20z75_device->power_supply); | ||
633 | if (bq20z75_device->gpio_detect) | ||
634 | gpio_free(pdata->battery_detect); | ||
635 | |||
636 | kfree(bq20z75_device); | ||
637 | |||
638 | return rc; | ||
430 | } | 639 | } |
431 | 640 | ||
432 | static int bq20z75_remove(struct i2c_client *client) | 641 | static int __devexit bq20z75_remove(struct i2c_client *client) |
433 | { | 642 | { |
434 | struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); | 643 | struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); |
435 | 644 | ||
645 | if (bq20z75_device->irq) | ||
646 | free_irq(bq20z75_device->irq, &bq20z75_device->power_supply); | ||
647 | if (bq20z75_device->gpio_detect) | ||
648 | gpio_free(bq20z75_device->pdata->battery_detect); | ||
649 | |||
436 | power_supply_unregister(&bq20z75_device->power_supply); | 650 | power_supply_unregister(&bq20z75_device->power_supply); |
437 | kfree(bq20z75_device); | 651 | kfree(bq20z75_device); |
438 | bq20z75_device = NULL; | 652 | bq20z75_device = NULL; |
@@ -444,13 +658,14 @@ static int bq20z75_remove(struct i2c_client *client) | |||
444 | static int bq20z75_suspend(struct i2c_client *client, | 658 | static int bq20z75_suspend(struct i2c_client *client, |
445 | pm_message_t state) | 659 | pm_message_t state) |
446 | { | 660 | { |
661 | struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); | ||
447 | s32 ret; | 662 | s32 ret; |
448 | 663 | ||
449 | /* write to manufacturer access with sleep command */ | 664 | /* write to manufacturer access with sleep command */ |
450 | ret = bq20z75_write_word_data(client, | 665 | ret = bq20z75_write_word_data(client, |
451 | bq20z75_data[REG_MANUFACTURER_DATA].addr, | 666 | bq20z75_data[REG_MANUFACTURER_DATA].addr, |
452 | MANUFACTURER_ACCESS_SLEEP); | 667 | MANUFACTURER_ACCESS_SLEEP); |
453 | if (ret < 0) | 668 | if (bq20z75_device->is_present && ret < 0) |
454 | return ret; | 669 | return ret; |
455 | 670 | ||
456 | return 0; | 671 | return 0; |
@@ -465,10 +680,11 @@ static const struct i2c_device_id bq20z75_id[] = { | |||
465 | { "bq20z75", 0 }, | 680 | { "bq20z75", 0 }, |
466 | {} | 681 | {} |
467 | }; | 682 | }; |
683 | MODULE_DEVICE_TABLE(i2c, bq20z75_id); | ||
468 | 684 | ||
469 | static struct i2c_driver bq20z75_battery_driver = { | 685 | static struct i2c_driver bq20z75_battery_driver = { |
470 | .probe = bq20z75_probe, | 686 | .probe = bq20z75_probe, |
471 | .remove = bq20z75_remove, | 687 | .remove = __devexit_p(bq20z75_remove), |
472 | .suspend = bq20z75_suspend, | 688 | .suspend = bq20z75_suspend, |
473 | .resume = bq20z75_resume, | 689 | .resume = bq20z75_resume, |
474 | .id_table = bq20z75_id, | 690 | .id_table = bq20z75_id, |
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index eff0273d4030..59e68dbd028b 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it> | 4 | * Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it> |
5 | * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it> | 5 | * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it> |
6 | * Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de> | ||
6 | * | 7 | * |
7 | * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc. | 8 | * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc. |
8 | * | 9 | * |
@@ -15,6 +16,13 @@ | |||
15 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | 16 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
16 | * | 17 | * |
17 | */ | 18 | */ |
19 | |||
20 | /* | ||
21 | * Datasheets: | ||
22 | * http://focus.ti.com/docs/prod/folders/print/bq27000.html | ||
23 | * http://focus.ti.com/docs/prod/folders/print/bq27500.html | ||
24 | */ | ||
25 | |||
18 | #include <linux/module.h> | 26 | #include <linux/module.h> |
19 | #include <linux/param.h> | 27 | #include <linux/param.h> |
20 | #include <linux/jiffies.h> | 28 | #include <linux/jiffies.h> |
@@ -27,7 +35,9 @@ | |||
27 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
28 | #include <asm/unaligned.h> | 36 | #include <asm/unaligned.h> |
29 | 37 | ||
30 | #define DRIVER_VERSION "1.1.0" | 38 | #include <linux/power/bq27x00_battery.h> |
39 | |||
40 | #define DRIVER_VERSION "1.2.0" | ||
31 | 41 | ||
32 | #define BQ27x00_REG_TEMP 0x06 | 42 | #define BQ27x00_REG_TEMP 0x06 |
33 | #define BQ27x00_REG_VOLT 0x08 | 43 | #define BQ27x00_REG_VOLT 0x08 |
@@ -36,36 +46,59 @@ | |||
36 | #define BQ27x00_REG_TTE 0x16 | 46 | #define BQ27x00_REG_TTE 0x16 |
37 | #define BQ27x00_REG_TTF 0x18 | 47 | #define BQ27x00_REG_TTF 0x18 |
38 | #define BQ27x00_REG_TTECP 0x26 | 48 | #define BQ27x00_REG_TTECP 0x26 |
49 | #define BQ27x00_REG_NAC 0x0C /* Nominal available capaciy */ | ||
50 | #define BQ27x00_REG_LMD 0x12 /* Last measured discharge */ | ||
51 | #define BQ27x00_REG_CYCT 0x2A /* Cycle count total */ | ||
52 | #define BQ27x00_REG_AE 0x22 /* Available enery */ | ||
39 | 53 | ||
40 | #define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */ | 54 | #define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */ |
55 | #define BQ27000_REG_ILMD 0x76 /* Initial last measured discharge */ | ||
41 | #define BQ27000_FLAG_CHGS BIT(7) | 56 | #define BQ27000_FLAG_CHGS BIT(7) |
57 | #define BQ27000_FLAG_FC BIT(5) | ||
42 | 58 | ||
43 | #define BQ27500_REG_SOC 0x2c | 59 | #define BQ27500_REG_SOC 0x2C |
60 | #define BQ27500_REG_DCAP 0x3C /* Design capacity */ | ||
44 | #define BQ27500_FLAG_DSC BIT(0) | 61 | #define BQ27500_FLAG_DSC BIT(0) |
45 | #define BQ27500_FLAG_FC BIT(9) | 62 | #define BQ27500_FLAG_FC BIT(9) |
46 | 63 | ||
47 | /* If the system has several batteries we need a different name for each | 64 | #define BQ27000_RS 20 /* Resistor sense */ |
48 | * of them... | ||
49 | */ | ||
50 | static DEFINE_IDR(battery_id); | ||
51 | static DEFINE_MUTEX(battery_mutex); | ||
52 | 65 | ||
53 | struct bq27x00_device_info; | 66 | struct bq27x00_device_info; |
54 | struct bq27x00_access_methods { | 67 | struct bq27x00_access_methods { |
55 | int (*read)(u8 reg, int *rt_value, int b_single, | 68 | int (*read)(struct bq27x00_device_info *di, u8 reg, bool single); |
56 | struct bq27x00_device_info *di); | ||
57 | }; | 69 | }; |
58 | 70 | ||
59 | enum bq27x00_chip { BQ27000, BQ27500 }; | 71 | enum bq27x00_chip { BQ27000, BQ27500 }; |
60 | 72 | ||
73 | struct bq27x00_reg_cache { | ||
74 | int temperature; | ||
75 | int time_to_empty; | ||
76 | int time_to_empty_avg; | ||
77 | int time_to_full; | ||
78 | int charge_full; | ||
79 | int charge_counter; | ||
80 | int capacity; | ||
81 | int flags; | ||
82 | |||
83 | int current_now; | ||
84 | }; | ||
85 | |||
61 | struct bq27x00_device_info { | 86 | struct bq27x00_device_info { |
62 | struct device *dev; | 87 | struct device *dev; |
63 | int id; | 88 | int id; |
64 | struct bq27x00_access_methods *bus; | ||
65 | struct power_supply bat; | ||
66 | enum bq27x00_chip chip; | 89 | enum bq27x00_chip chip; |
67 | 90 | ||
68 | struct i2c_client *client; | 91 | struct bq27x00_reg_cache cache; |
92 | int charge_design_full; | ||
93 | |||
94 | unsigned long last_update; | ||
95 | struct delayed_work work; | ||
96 | |||
97 | struct power_supply bat; | ||
98 | |||
99 | struct bq27x00_access_methods bus; | ||
100 | |||
101 | struct mutex lock; | ||
69 | }; | 102 | }; |
70 | 103 | ||
71 | static enum power_supply_property bq27x00_battery_props[] = { | 104 | static enum power_supply_property bq27x00_battery_props[] = { |
@@ -78,164 +111,328 @@ static enum power_supply_property bq27x00_battery_props[] = { | |||
78 | POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, | 111 | POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, |
79 | POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, | 112 | POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, |
80 | POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, | 113 | POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, |
114 | POWER_SUPPLY_PROP_TECHNOLOGY, | ||
115 | POWER_SUPPLY_PROP_CHARGE_FULL, | ||
116 | POWER_SUPPLY_PROP_CHARGE_NOW, | ||
117 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | ||
118 | POWER_SUPPLY_PROP_CHARGE_COUNTER, | ||
119 | POWER_SUPPLY_PROP_ENERGY_NOW, | ||
81 | }; | 120 | }; |
82 | 121 | ||
122 | static unsigned int poll_interval = 360; | ||
123 | module_param(poll_interval, uint, 0644); | ||
124 | MODULE_PARM_DESC(poll_interval, "battery poll interval in seconds - " \ | ||
125 | "0 disables polling"); | ||
126 | |||
83 | /* | 127 | /* |
84 | * Common code for BQ27x00 devices | 128 | * Common code for BQ27x00 devices |
85 | */ | 129 | */ |
86 | 130 | ||
87 | static int bq27x00_read(u8 reg, int *rt_value, int b_single, | 131 | static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg, |
88 | struct bq27x00_device_info *di) | 132 | bool single) |
89 | { | 133 | { |
90 | return di->bus->read(reg, rt_value, b_single, di); | 134 | return di->bus.read(di, reg, single); |
91 | } | 135 | } |
92 | 136 | ||
93 | /* | 137 | /* |
94 | * Return the battery temperature in tenths of degree Celsius | 138 | * Return the battery Relative State-of-Charge |
95 | * Or < 0 if something fails. | 139 | * Or < 0 if something fails. |
96 | */ | 140 | */ |
97 | static int bq27x00_battery_temperature(struct bq27x00_device_info *di) | 141 | static int bq27x00_battery_read_rsoc(struct bq27x00_device_info *di) |
98 | { | 142 | { |
99 | int ret; | 143 | int rsoc; |
100 | int temp = 0; | ||
101 | 144 | ||
102 | ret = bq27x00_read(BQ27x00_REG_TEMP, &temp, 0, di); | 145 | if (di->chip == BQ27500) |
103 | if (ret) { | 146 | rsoc = bq27x00_read(di, BQ27500_REG_SOC, false); |
104 | dev_err(di->dev, "error reading temperature\n"); | 147 | else |
105 | return ret; | 148 | rsoc = bq27x00_read(di, BQ27000_REG_RSOC, true); |
149 | |||
150 | if (rsoc < 0) | ||
151 | dev_err(di->dev, "error reading relative State-of-Charge\n"); | ||
152 | |||
153 | return rsoc; | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | * Return a battery charge value in µAh | ||
158 | * Or < 0 if something fails. | ||
159 | */ | ||
160 | static int bq27x00_battery_read_charge(struct bq27x00_device_info *di, u8 reg) | ||
161 | { | ||
162 | int charge; | ||
163 | |||
164 | charge = bq27x00_read(di, reg, false); | ||
165 | if (charge < 0) { | ||
166 | dev_err(di->dev, "error reading nominal available capacity\n"); | ||
167 | return charge; | ||
106 | } | 168 | } |
107 | 169 | ||
108 | if (di->chip == BQ27500) | 170 | if (di->chip == BQ27500) |
109 | return temp - 2731; | 171 | charge *= 1000; |
110 | else | 172 | else |
111 | return ((temp >> 2) - 273) * 10; | 173 | charge = charge * 3570 / BQ27000_RS; |
174 | |||
175 | return charge; | ||
112 | } | 176 | } |
113 | 177 | ||
114 | /* | 178 | /* |
115 | * Return the battery Voltage in milivolts | 179 | * Return the battery Nominal available capaciy in µAh |
116 | * Or < 0 if something fails. | 180 | * Or < 0 if something fails. |
117 | */ | 181 | */ |
118 | static int bq27x00_battery_voltage(struct bq27x00_device_info *di) | 182 | static inline int bq27x00_battery_read_nac(struct bq27x00_device_info *di) |
119 | { | 183 | { |
120 | int ret; | 184 | return bq27x00_battery_read_charge(di, BQ27x00_REG_NAC); |
121 | int volt = 0; | 185 | } |
122 | 186 | ||
123 | ret = bq27x00_read(BQ27x00_REG_VOLT, &volt, 0, di); | 187 | /* |
124 | if (ret) { | 188 | * Return the battery Last measured discharge in µAh |
125 | dev_err(di->dev, "error reading voltage\n"); | 189 | * Or < 0 if something fails. |
126 | return ret; | 190 | */ |
191 | static inline int bq27x00_battery_read_lmd(struct bq27x00_device_info *di) | ||
192 | { | ||
193 | return bq27x00_battery_read_charge(di, BQ27x00_REG_LMD); | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * Return the battery Initial last measured discharge in µAh | ||
198 | * Or < 0 if something fails. | ||
199 | */ | ||
200 | static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di) | ||
201 | { | ||
202 | int ilmd; | ||
203 | |||
204 | if (di->chip == BQ27500) | ||
205 | ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false); | ||
206 | else | ||
207 | ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true); | ||
208 | |||
209 | if (ilmd < 0) { | ||
210 | dev_err(di->dev, "error reading initial last measured discharge\n"); | ||
211 | return ilmd; | ||
127 | } | 212 | } |
128 | 213 | ||
129 | return volt * 1000; | 214 | if (di->chip == BQ27500) |
215 | ilmd *= 1000; | ||
216 | else | ||
217 | ilmd = ilmd * 256 * 3570 / BQ27000_RS; | ||
218 | |||
219 | return ilmd; | ||
130 | } | 220 | } |
131 | 221 | ||
132 | /* | 222 | /* |
133 | * Return the battery average current | 223 | * Return the battery Cycle count total |
134 | * Note that current can be negative signed as well | 224 | * Or < 0 if something fails. |
135 | * Or 0 if something fails. | ||
136 | */ | 225 | */ |
137 | static int bq27x00_battery_current(struct bq27x00_device_info *di) | 226 | static int bq27x00_battery_read_cyct(struct bq27x00_device_info *di) |
138 | { | 227 | { |
139 | int ret; | 228 | int cyct; |
140 | int curr = 0; | ||
141 | int flags = 0; | ||
142 | 229 | ||
143 | ret = bq27x00_read(BQ27x00_REG_AI, &curr, 0, di); | 230 | cyct = bq27x00_read(di, BQ27x00_REG_CYCT, false); |
144 | if (ret) { | 231 | if (cyct < 0) |
145 | dev_err(di->dev, "error reading current\n"); | 232 | dev_err(di->dev, "error reading cycle count total\n"); |
146 | return 0; | 233 | |
234 | return cyct; | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * Read a time register. | ||
239 | * Return < 0 if something fails. | ||
240 | */ | ||
241 | static int bq27x00_battery_read_time(struct bq27x00_device_info *di, u8 reg) | ||
242 | { | ||
243 | int tval; | ||
244 | |||
245 | tval = bq27x00_read(di, reg, false); | ||
246 | if (tval < 0) { | ||
247 | dev_err(di->dev, "error reading register %02x: %d\n", reg, tval); | ||
248 | return tval; | ||
147 | } | 249 | } |
148 | 250 | ||
149 | if (di->chip == BQ27500) { | 251 | if (tval == 65535) |
150 | /* bq27500 returns signed value */ | 252 | return -ENODATA; |
151 | curr = (int)(s16)curr; | 253 | |
152 | } else { | 254 | return tval * 60; |
153 | ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di); | 255 | } |
154 | if (ret < 0) { | 256 | |
155 | dev_err(di->dev, "error reading flags\n"); | 257 | static void bq27x00_update(struct bq27x00_device_info *di) |
156 | return 0; | 258 | { |
157 | } | 259 | struct bq27x00_reg_cache cache = {0, }; |
158 | if (flags & BQ27000_FLAG_CHGS) { | 260 | bool is_bq27500 = di->chip == BQ27500; |
159 | dev_dbg(di->dev, "negative current!\n"); | 261 | |
160 | curr = -curr; | 262 | cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, is_bq27500); |
161 | } | 263 | if (cache.flags >= 0) { |
264 | cache.capacity = bq27x00_battery_read_rsoc(di); | ||
265 | cache.temperature = bq27x00_read(di, BQ27x00_REG_TEMP, false); | ||
266 | cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE); | ||
267 | cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP); | ||
268 | cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF); | ||
269 | cache.charge_full = bq27x00_battery_read_lmd(di); | ||
270 | cache.charge_counter = bq27x00_battery_read_cyct(di); | ||
271 | |||
272 | if (!is_bq27500) | ||
273 | cache.current_now = bq27x00_read(di, BQ27x00_REG_AI, false); | ||
274 | |||
275 | /* We only have to read charge design full once */ | ||
276 | if (di->charge_design_full <= 0) | ||
277 | di->charge_design_full = bq27x00_battery_read_ilmd(di); | ||
278 | } | ||
279 | |||
280 | /* Ignore current_now which is a snapshot of the current battery state | ||
281 | * and is likely to be different even between two consecutive reads */ | ||
282 | if (memcmp(&di->cache, &cache, sizeof(cache) - sizeof(int)) != 0) { | ||
283 | di->cache = cache; | ||
284 | power_supply_changed(&di->bat); | ||
162 | } | 285 | } |
163 | 286 | ||
164 | return curr * 1000; | 287 | di->last_update = jiffies; |
288 | } | ||
289 | |||
290 | static void bq27x00_battery_poll(struct work_struct *work) | ||
291 | { | ||
292 | struct bq27x00_device_info *di = | ||
293 | container_of(work, struct bq27x00_device_info, work.work); | ||
294 | |||
295 | bq27x00_update(di); | ||
296 | |||
297 | if (poll_interval > 0) { | ||
298 | /* The timer does not have to be accurate. */ | ||
299 | set_timer_slack(&di->work.timer, poll_interval * HZ / 4); | ||
300 | schedule_delayed_work(&di->work, poll_interval * HZ); | ||
301 | } | ||
165 | } | 302 | } |
166 | 303 | ||
304 | |||
167 | /* | 305 | /* |
168 | * Return the battery Relative State-of-Charge | 306 | * Return the battery temperature in tenths of degree Celsius |
169 | * Or < 0 if something fails. | 307 | * Or < 0 if something fails. |
170 | */ | 308 | */ |
171 | static int bq27x00_battery_rsoc(struct bq27x00_device_info *di) | 309 | static int bq27x00_battery_temperature(struct bq27x00_device_info *di, |
310 | union power_supply_propval *val) | ||
172 | { | 311 | { |
173 | int ret; | 312 | if (di->cache.temperature < 0) |
174 | int rsoc = 0; | 313 | return di->cache.temperature; |
175 | 314 | ||
176 | if (di->chip == BQ27500) | 315 | if (di->chip == BQ27500) |
177 | ret = bq27x00_read(BQ27500_REG_SOC, &rsoc, 0, di); | 316 | val->intval = di->cache.temperature - 2731; |
178 | else | 317 | else |
179 | ret = bq27x00_read(BQ27000_REG_RSOC, &rsoc, 1, di); | 318 | val->intval = ((di->cache.temperature * 5) - 5463) / 2; |
180 | if (ret) { | 319 | |
181 | dev_err(di->dev, "error reading relative State-of-Charge\n"); | 320 | return 0; |
182 | return ret; | 321 | } |
322 | |||
323 | /* | ||
324 | * Return the battery average current in µA | ||
325 | * Note that current can be negative signed as well | ||
326 | * Or 0 if something fails. | ||
327 | */ | ||
328 | static int bq27x00_battery_current(struct bq27x00_device_info *di, | ||
329 | union power_supply_propval *val) | ||
330 | { | ||
331 | int curr; | ||
332 | |||
333 | if (di->chip == BQ27500) | ||
334 | curr = bq27x00_read(di, BQ27x00_REG_AI, false); | ||
335 | else | ||
336 | curr = di->cache.current_now; | ||
337 | |||
338 | if (curr < 0) | ||
339 | return curr; | ||
340 | |||
341 | if (di->chip == BQ27500) { | ||
342 | /* bq27500 returns signed value */ | ||
343 | val->intval = (int)((s16)curr) * 1000; | ||
344 | } else { | ||
345 | if (di->cache.flags & BQ27000_FLAG_CHGS) { | ||
346 | dev_dbg(di->dev, "negative current!\n"); | ||
347 | curr = -curr; | ||
348 | } | ||
349 | |||
350 | val->intval = curr * 3570 / BQ27000_RS; | ||
183 | } | 351 | } |
184 | 352 | ||
185 | return rsoc; | 353 | return 0; |
186 | } | 354 | } |
187 | 355 | ||
188 | static int bq27x00_battery_status(struct bq27x00_device_info *di, | 356 | static int bq27x00_battery_status(struct bq27x00_device_info *di, |
189 | union power_supply_propval *val) | 357 | union power_supply_propval *val) |
190 | { | 358 | { |
191 | int flags = 0; | ||
192 | int status; | 359 | int status; |
193 | int ret; | ||
194 | |||
195 | ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di); | ||
196 | if (ret < 0) { | ||
197 | dev_err(di->dev, "error reading flags\n"); | ||
198 | return ret; | ||
199 | } | ||
200 | 360 | ||
201 | if (di->chip == BQ27500) { | 361 | if (di->chip == BQ27500) { |
202 | if (flags & BQ27500_FLAG_FC) | 362 | if (di->cache.flags & BQ27500_FLAG_FC) |
203 | status = POWER_SUPPLY_STATUS_FULL; | 363 | status = POWER_SUPPLY_STATUS_FULL; |
204 | else if (flags & BQ27500_FLAG_DSC) | 364 | else if (di->cache.flags & BQ27500_FLAG_DSC) |
205 | status = POWER_SUPPLY_STATUS_DISCHARGING; | 365 | status = POWER_SUPPLY_STATUS_DISCHARGING; |
206 | else | 366 | else |
207 | status = POWER_SUPPLY_STATUS_CHARGING; | 367 | status = POWER_SUPPLY_STATUS_CHARGING; |
208 | } else { | 368 | } else { |
209 | if (flags & BQ27000_FLAG_CHGS) | 369 | if (di->cache.flags & BQ27000_FLAG_FC) |
370 | status = POWER_SUPPLY_STATUS_FULL; | ||
371 | else if (di->cache.flags & BQ27000_FLAG_CHGS) | ||
210 | status = POWER_SUPPLY_STATUS_CHARGING; | 372 | status = POWER_SUPPLY_STATUS_CHARGING; |
373 | else if (power_supply_am_i_supplied(&di->bat)) | ||
374 | status = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
211 | else | 375 | else |
212 | status = POWER_SUPPLY_STATUS_DISCHARGING; | 376 | status = POWER_SUPPLY_STATUS_DISCHARGING; |
213 | } | 377 | } |
214 | 378 | ||
215 | val->intval = status; | 379 | val->intval = status; |
380 | |||
216 | return 0; | 381 | return 0; |
217 | } | 382 | } |
218 | 383 | ||
219 | /* | 384 | /* |
220 | * Read a time register. | 385 | * Return the battery Voltage in milivolts |
221 | * Return < 0 if something fails. | 386 | * Or < 0 if something fails. |
222 | */ | 387 | */ |
223 | static int bq27x00_battery_time(struct bq27x00_device_info *di, int reg, | 388 | static int bq27x00_battery_voltage(struct bq27x00_device_info *di, |
224 | union power_supply_propval *val) | 389 | union power_supply_propval *val) |
225 | { | 390 | { |
226 | int tval = 0; | 391 | int volt; |
227 | int ret; | ||
228 | 392 | ||
229 | ret = bq27x00_read(reg, &tval, 0, di); | 393 | volt = bq27x00_read(di, BQ27x00_REG_VOLT, false); |
230 | if (ret) { | 394 | if (volt < 0) |
231 | dev_err(di->dev, "error reading register %02x\n", reg); | 395 | return volt; |
232 | return ret; | 396 | |
397 | val->intval = volt * 1000; | ||
398 | |||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * Return the battery Available energy in µWh | ||
404 | * Or < 0 if something fails. | ||
405 | */ | ||
406 | static int bq27x00_battery_energy(struct bq27x00_device_info *di, | ||
407 | union power_supply_propval *val) | ||
408 | { | ||
409 | int ae; | ||
410 | |||
411 | ae = bq27x00_read(di, BQ27x00_REG_AE, false); | ||
412 | if (ae < 0) { | ||
413 | dev_err(di->dev, "error reading available energy\n"); | ||
414 | return ae; | ||
233 | } | 415 | } |
234 | 416 | ||
235 | if (tval == 65535) | 417 | if (di->chip == BQ27500) |
236 | return -ENODATA; | 418 | ae *= 1000; |
419 | else | ||
420 | ae = ae * 29200 / BQ27000_RS; | ||
421 | |||
422 | val->intval = ae; | ||
423 | |||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | |||
428 | static int bq27x00_simple_value(int value, | ||
429 | union power_supply_propval *val) | ||
430 | { | ||
431 | if (value < 0) | ||
432 | return value; | ||
433 | |||
434 | val->intval = value; | ||
237 | 435 | ||
238 | val->intval = tval * 60; | ||
239 | return 0; | 436 | return 0; |
240 | } | 437 | } |
241 | 438 | ||
@@ -249,33 +446,61 @@ static int bq27x00_battery_get_property(struct power_supply *psy, | |||
249 | int ret = 0; | 446 | int ret = 0; |
250 | struct bq27x00_device_info *di = to_bq27x00_device_info(psy); | 447 | struct bq27x00_device_info *di = to_bq27x00_device_info(psy); |
251 | 448 | ||
449 | mutex_lock(&di->lock); | ||
450 | if (time_is_before_jiffies(di->last_update + 5 * HZ)) { | ||
451 | cancel_delayed_work_sync(&di->work); | ||
452 | bq27x00_battery_poll(&di->work.work); | ||
453 | } | ||
454 | mutex_unlock(&di->lock); | ||
455 | |||
456 | if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0) | ||
457 | return -ENODEV; | ||
458 | |||
252 | switch (psp) { | 459 | switch (psp) { |
253 | case POWER_SUPPLY_PROP_STATUS: | 460 | case POWER_SUPPLY_PROP_STATUS: |
254 | ret = bq27x00_battery_status(di, val); | 461 | ret = bq27x00_battery_status(di, val); |
255 | break; | 462 | break; |
256 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | 463 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: |
464 | ret = bq27x00_battery_voltage(di, val); | ||
465 | break; | ||
257 | case POWER_SUPPLY_PROP_PRESENT: | 466 | case POWER_SUPPLY_PROP_PRESENT: |
258 | val->intval = bq27x00_battery_voltage(di); | 467 | val->intval = di->cache.flags < 0 ? 0 : 1; |
259 | if (psp == POWER_SUPPLY_PROP_PRESENT) | ||
260 | val->intval = val->intval <= 0 ? 0 : 1; | ||
261 | break; | 468 | break; |
262 | case POWER_SUPPLY_PROP_CURRENT_NOW: | 469 | case POWER_SUPPLY_PROP_CURRENT_NOW: |
263 | val->intval = bq27x00_battery_current(di); | 470 | ret = bq27x00_battery_current(di, val); |
264 | break; | 471 | break; |
265 | case POWER_SUPPLY_PROP_CAPACITY: | 472 | case POWER_SUPPLY_PROP_CAPACITY: |
266 | val->intval = bq27x00_battery_rsoc(di); | 473 | ret = bq27x00_simple_value(di->cache.capacity, val); |
267 | break; | 474 | break; |
268 | case POWER_SUPPLY_PROP_TEMP: | 475 | case POWER_SUPPLY_PROP_TEMP: |
269 | val->intval = bq27x00_battery_temperature(di); | 476 | ret = bq27x00_battery_temperature(di, val); |
270 | break; | 477 | break; |
271 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: | 478 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: |
272 | ret = bq27x00_battery_time(di, BQ27x00_REG_TTE, val); | 479 | ret = bq27x00_simple_value(di->cache.time_to_empty, val); |
273 | break; | 480 | break; |
274 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: | 481 | case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: |
275 | ret = bq27x00_battery_time(di, BQ27x00_REG_TTECP, val); | 482 | ret = bq27x00_simple_value(di->cache.time_to_empty_avg, val); |
276 | break; | 483 | break; |
277 | case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: | 484 | case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: |
278 | ret = bq27x00_battery_time(di, BQ27x00_REG_TTF, val); | 485 | ret = bq27x00_simple_value(di->cache.time_to_full, val); |
486 | break; | ||
487 | case POWER_SUPPLY_PROP_TECHNOLOGY: | ||
488 | val->intval = POWER_SUPPLY_TECHNOLOGY_LION; | ||
489 | break; | ||
490 | case POWER_SUPPLY_PROP_CHARGE_NOW: | ||
491 | ret = bq27x00_simple_value(bq27x00_battery_read_nac(di), val); | ||
492 | break; | ||
493 | case POWER_SUPPLY_PROP_CHARGE_FULL: | ||
494 | ret = bq27x00_simple_value(di->cache.charge_full, val); | ||
495 | break; | ||
496 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | ||
497 | ret = bq27x00_simple_value(di->charge_design_full, val); | ||
498 | break; | ||
499 | case POWER_SUPPLY_PROP_CHARGE_COUNTER: | ||
500 | ret = bq27x00_simple_value(di->cache.charge_counter, val); | ||
501 | break; | ||
502 | case POWER_SUPPLY_PROP_ENERGY_NOW: | ||
503 | ret = bq27x00_battery_energy(di, val); | ||
279 | break; | 504 | break; |
280 | default: | 505 | default: |
281 | return -EINVAL; | 506 | return -EINVAL; |
@@ -284,56 +509,91 @@ static int bq27x00_battery_get_property(struct power_supply *psy, | |||
284 | return ret; | 509 | return ret; |
285 | } | 510 | } |
286 | 511 | ||
287 | static void bq27x00_powersupply_init(struct bq27x00_device_info *di) | 512 | static void bq27x00_external_power_changed(struct power_supply *psy) |
288 | { | 513 | { |
514 | struct bq27x00_device_info *di = to_bq27x00_device_info(psy); | ||
515 | |||
516 | cancel_delayed_work_sync(&di->work); | ||
517 | schedule_delayed_work(&di->work, 0); | ||
518 | } | ||
519 | |||
520 | static int bq27x00_powersupply_init(struct bq27x00_device_info *di) | ||
521 | { | ||
522 | int ret; | ||
523 | |||
289 | di->bat.type = POWER_SUPPLY_TYPE_BATTERY; | 524 | di->bat.type = POWER_SUPPLY_TYPE_BATTERY; |
290 | di->bat.properties = bq27x00_battery_props; | 525 | di->bat.properties = bq27x00_battery_props; |
291 | di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props); | 526 | di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props); |
292 | di->bat.get_property = bq27x00_battery_get_property; | 527 | di->bat.get_property = bq27x00_battery_get_property; |
293 | di->bat.external_power_changed = NULL; | 528 | di->bat.external_power_changed = bq27x00_external_power_changed; |
529 | |||
530 | INIT_DELAYED_WORK(&di->work, bq27x00_battery_poll); | ||
531 | mutex_init(&di->lock); | ||
532 | |||
533 | ret = power_supply_register(di->dev, &di->bat); | ||
534 | if (ret) { | ||
535 | dev_err(di->dev, "failed to register battery: %d\n", ret); | ||
536 | return ret; | ||
537 | } | ||
538 | |||
539 | dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION); | ||
540 | |||
541 | bq27x00_update(di); | ||
542 | |||
543 | return 0; | ||
294 | } | 544 | } |
295 | 545 | ||
296 | /* | 546 | static void bq27x00_powersupply_unregister(struct bq27x00_device_info *di) |
297 | * i2c specific code | 547 | { |
548 | cancel_delayed_work_sync(&di->work); | ||
549 | |||
550 | power_supply_unregister(&di->bat); | ||
551 | |||
552 | mutex_destroy(&di->lock); | ||
553 | } | ||
554 | |||
555 | |||
556 | /* i2c specific code */ | ||
557 | #ifdef CONFIG_BATTERY_BQ27X00_I2C | ||
558 | |||
559 | /* If the system has several batteries we need a different name for each | ||
560 | * of them... | ||
298 | */ | 561 | */ |
562 | static DEFINE_IDR(battery_id); | ||
563 | static DEFINE_MUTEX(battery_mutex); | ||
299 | 564 | ||
300 | static int bq27x00_read_i2c(u8 reg, int *rt_value, int b_single, | 565 | static int bq27x00_read_i2c(struct bq27x00_device_info *di, u8 reg, bool single) |
301 | struct bq27x00_device_info *di) | ||
302 | { | 566 | { |
303 | struct i2c_client *client = di->client; | 567 | struct i2c_client *client = to_i2c_client(di->dev); |
304 | struct i2c_msg msg[1]; | 568 | struct i2c_msg msg[2]; |
305 | unsigned char data[2]; | 569 | unsigned char data[2]; |
306 | int err; | 570 | int ret; |
307 | 571 | ||
308 | if (!client->adapter) | 572 | if (!client->adapter) |
309 | return -ENODEV; | 573 | return -ENODEV; |
310 | 574 | ||
311 | msg->addr = client->addr; | 575 | msg[0].addr = client->addr; |
312 | msg->flags = 0; | 576 | msg[0].flags = 0; |
313 | msg->len = 1; | 577 | msg[0].buf = ® |
314 | msg->buf = data; | 578 | msg[0].len = sizeof(reg); |
315 | 579 | msg[1].addr = client->addr; | |
316 | data[0] = reg; | 580 | msg[1].flags = I2C_M_RD; |
317 | err = i2c_transfer(client->adapter, msg, 1); | 581 | msg[1].buf = data; |
582 | if (single) | ||
583 | msg[1].len = 1; | ||
584 | else | ||
585 | msg[1].len = 2; | ||
318 | 586 | ||
319 | if (err >= 0) { | 587 | ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); |
320 | if (!b_single) | 588 | if (ret < 0) |
321 | msg->len = 2; | 589 | return ret; |
322 | else | ||
323 | msg->len = 1; | ||
324 | 590 | ||
325 | msg->flags = I2C_M_RD; | 591 | if (!single) |
326 | err = i2c_transfer(client->adapter, msg, 1); | 592 | ret = get_unaligned_le16(data); |
327 | if (err >= 0) { | 593 | else |
328 | if (!b_single) | 594 | ret = data[0]; |
329 | *rt_value = get_unaligned_le16(data); | ||
330 | else | ||
331 | *rt_value = data[0]; | ||
332 | 595 | ||
333 | return 0; | 596 | return ret; |
334 | } | ||
335 | } | ||
336 | return err; | ||
337 | } | 597 | } |
338 | 598 | ||
339 | static int bq27x00_battery_probe(struct i2c_client *client, | 599 | static int bq27x00_battery_probe(struct i2c_client *client, |
@@ -341,7 +601,6 @@ static int bq27x00_battery_probe(struct i2c_client *client, | |||
341 | { | 601 | { |
342 | char *name; | 602 | char *name; |
343 | struct bq27x00_device_info *di; | 603 | struct bq27x00_device_info *di; |
344 | struct bq27x00_access_methods *bus; | ||
345 | int num; | 604 | int num; |
346 | int retval = 0; | 605 | int retval = 0; |
347 | 606 | ||
@@ -368,38 +627,20 @@ static int bq27x00_battery_probe(struct i2c_client *client, | |||
368 | retval = -ENOMEM; | 627 | retval = -ENOMEM; |
369 | goto batt_failed_2; | 628 | goto batt_failed_2; |
370 | } | 629 | } |
630 | |||
371 | di->id = num; | 631 | di->id = num; |
632 | di->dev = &client->dev; | ||
372 | di->chip = id->driver_data; | 633 | di->chip = id->driver_data; |
634 | di->bat.name = name; | ||
635 | di->bus.read = &bq27x00_read_i2c; | ||
373 | 636 | ||
374 | bus = kzalloc(sizeof(*bus), GFP_KERNEL); | 637 | if (bq27x00_powersupply_init(di)) |
375 | if (!bus) { | ||
376 | dev_err(&client->dev, "failed to allocate access method " | ||
377 | "data\n"); | ||
378 | retval = -ENOMEM; | ||
379 | goto batt_failed_3; | 638 | goto batt_failed_3; |
380 | } | ||
381 | 639 | ||
382 | i2c_set_clientdata(client, di); | 640 | i2c_set_clientdata(client, di); |
383 | di->dev = &client->dev; | ||
384 | di->bat.name = name; | ||
385 | bus->read = &bq27x00_read_i2c; | ||
386 | di->bus = bus; | ||
387 | di->client = client; | ||
388 | |||
389 | bq27x00_powersupply_init(di); | ||
390 | |||
391 | retval = power_supply_register(&client->dev, &di->bat); | ||
392 | if (retval) { | ||
393 | dev_err(&client->dev, "failed to register battery\n"); | ||
394 | goto batt_failed_4; | ||
395 | } | ||
396 | |||
397 | dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION); | ||
398 | 641 | ||
399 | return 0; | 642 | return 0; |
400 | 643 | ||
401 | batt_failed_4: | ||
402 | kfree(bus); | ||
403 | batt_failed_3: | 644 | batt_failed_3: |
404 | kfree(di); | 645 | kfree(di); |
405 | batt_failed_2: | 646 | batt_failed_2: |
@@ -416,9 +657,8 @@ static int bq27x00_battery_remove(struct i2c_client *client) | |||
416 | { | 657 | { |
417 | struct bq27x00_device_info *di = i2c_get_clientdata(client); | 658 | struct bq27x00_device_info *di = i2c_get_clientdata(client); |
418 | 659 | ||
419 | power_supply_unregister(&di->bat); | 660 | bq27x00_powersupply_unregister(di); |
420 | 661 | ||
421 | kfree(di->bus); | ||
422 | kfree(di->bat.name); | 662 | kfree(di->bat.name); |
423 | 663 | ||
424 | mutex_lock(&battery_mutex); | 664 | mutex_lock(&battery_mutex); |
@@ -430,15 +670,12 @@ static int bq27x00_battery_remove(struct i2c_client *client) | |||
430 | return 0; | 670 | return 0; |
431 | } | 671 | } |
432 | 672 | ||
433 | /* | ||
434 | * Module stuff | ||
435 | */ | ||
436 | |||
437 | static const struct i2c_device_id bq27x00_id[] = { | 673 | static const struct i2c_device_id bq27x00_id[] = { |
438 | { "bq27200", BQ27000 }, /* bq27200 is same as bq27000, but with i2c */ | 674 | { "bq27200", BQ27000 }, /* bq27200 is same as bq27000, but with i2c */ |
439 | { "bq27500", BQ27500 }, | 675 | { "bq27500", BQ27500 }, |
440 | {}, | 676 | {}, |
441 | }; | 677 | }; |
678 | MODULE_DEVICE_TABLE(i2c, bq27x00_id); | ||
442 | 679 | ||
443 | static struct i2c_driver bq27x00_battery_driver = { | 680 | static struct i2c_driver bq27x00_battery_driver = { |
444 | .driver = { | 681 | .driver = { |
@@ -449,13 +686,164 @@ static struct i2c_driver bq27x00_battery_driver = { | |||
449 | .id_table = bq27x00_id, | 686 | .id_table = bq27x00_id, |
450 | }; | 687 | }; |
451 | 688 | ||
689 | static inline int bq27x00_battery_i2c_init(void) | ||
690 | { | ||
691 | int ret = i2c_add_driver(&bq27x00_battery_driver); | ||
692 | if (ret) | ||
693 | printk(KERN_ERR "Unable to register BQ27x00 i2c driver\n"); | ||
694 | |||
695 | return ret; | ||
696 | } | ||
697 | |||
698 | static inline void bq27x00_battery_i2c_exit(void) | ||
699 | { | ||
700 | i2c_del_driver(&bq27x00_battery_driver); | ||
701 | } | ||
702 | |||
703 | #else | ||
704 | |||
705 | static inline int bq27x00_battery_i2c_init(void) { return 0; } | ||
706 | static inline void bq27x00_battery_i2c_exit(void) {}; | ||
707 | |||
708 | #endif | ||
709 | |||
710 | /* platform specific code */ | ||
711 | #ifdef CONFIG_BATTERY_BQ27X00_PLATFORM | ||
712 | |||
713 | static int bq27000_read_platform(struct bq27x00_device_info *di, u8 reg, | ||
714 | bool single) | ||
715 | { | ||
716 | struct device *dev = di->dev; | ||
717 | struct bq27000_platform_data *pdata = dev->platform_data; | ||
718 | unsigned int timeout = 3; | ||
719 | int upper, lower; | ||
720 | int temp; | ||
721 | |||
722 | if (!single) { | ||
723 | /* Make sure the value has not changed in between reading the | ||
724 | * lower and the upper part */ | ||
725 | upper = pdata->read(dev, reg + 1); | ||
726 | do { | ||
727 | temp = upper; | ||
728 | if (upper < 0) | ||
729 | return upper; | ||
730 | |||
731 | lower = pdata->read(dev, reg); | ||
732 | if (lower < 0) | ||
733 | return lower; | ||
734 | |||
735 | upper = pdata->read(dev, reg + 1); | ||
736 | } while (temp != upper && --timeout); | ||
737 | |||
738 | if (timeout == 0) | ||
739 | return -EIO; | ||
740 | |||
741 | return (upper << 8) | lower; | ||
742 | } | ||
743 | |||
744 | return pdata->read(dev, reg); | ||
745 | } | ||
746 | |||
747 | static int __devinit bq27000_battery_probe(struct platform_device *pdev) | ||
748 | { | ||
749 | struct bq27x00_device_info *di; | ||
750 | struct bq27000_platform_data *pdata = pdev->dev.platform_data; | ||
751 | int ret; | ||
752 | |||
753 | if (!pdata) { | ||
754 | dev_err(&pdev->dev, "no platform_data supplied\n"); | ||
755 | return -EINVAL; | ||
756 | } | ||
757 | |||
758 | if (!pdata->read) { | ||
759 | dev_err(&pdev->dev, "no hdq read callback supplied\n"); | ||
760 | return -EINVAL; | ||
761 | } | ||
762 | |||
763 | di = kzalloc(sizeof(*di), GFP_KERNEL); | ||
764 | if (!di) { | ||
765 | dev_err(&pdev->dev, "failed to allocate device info data\n"); | ||
766 | return -ENOMEM; | ||
767 | } | ||
768 | |||
769 | platform_set_drvdata(pdev, di); | ||
770 | |||
771 | di->dev = &pdev->dev; | ||
772 | di->chip = BQ27000; | ||
773 | |||
774 | di->bat.name = pdata->name ?: dev_name(&pdev->dev); | ||
775 | di->bus.read = &bq27000_read_platform; | ||
776 | |||
777 | ret = bq27x00_powersupply_init(di); | ||
778 | if (ret) | ||
779 | goto err_free; | ||
780 | |||
781 | return 0; | ||
782 | |||
783 | err_free: | ||
784 | platform_set_drvdata(pdev, NULL); | ||
785 | kfree(di); | ||
786 | |||
787 | return ret; | ||
788 | } | ||
789 | |||
790 | static int __devexit bq27000_battery_remove(struct platform_device *pdev) | ||
791 | { | ||
792 | struct bq27x00_device_info *di = platform_get_drvdata(pdev); | ||
793 | |||
794 | bq27x00_powersupply_unregister(di); | ||
795 | |||
796 | platform_set_drvdata(pdev, NULL); | ||
797 | kfree(di); | ||
798 | |||
799 | return 0; | ||
800 | } | ||
801 | |||
802 | static struct platform_driver bq27000_battery_driver = { | ||
803 | .probe = bq27000_battery_probe, | ||
804 | .remove = __devexit_p(bq27000_battery_remove), | ||
805 | .driver = { | ||
806 | .name = "bq27000-battery", | ||
807 | .owner = THIS_MODULE, | ||
808 | }, | ||
809 | }; | ||
810 | |||
811 | static inline int bq27x00_battery_platform_init(void) | ||
812 | { | ||
813 | int ret = platform_driver_register(&bq27000_battery_driver); | ||
814 | if (ret) | ||
815 | printk(KERN_ERR "Unable to register BQ27000 platform driver\n"); | ||
816 | |||
817 | return ret; | ||
818 | } | ||
819 | |||
820 | static inline void bq27x00_battery_platform_exit(void) | ||
821 | { | ||
822 | platform_driver_unregister(&bq27000_battery_driver); | ||
823 | } | ||
824 | |||
825 | #else | ||
826 | |||
827 | static inline int bq27x00_battery_platform_init(void) { return 0; } | ||
828 | static inline void bq27x00_battery_platform_exit(void) {}; | ||
829 | |||
830 | #endif | ||
831 | |||
832 | /* | ||
833 | * Module stuff | ||
834 | */ | ||
835 | |||
452 | static int __init bq27x00_battery_init(void) | 836 | static int __init bq27x00_battery_init(void) |
453 | { | 837 | { |
454 | int ret; | 838 | int ret; |
455 | 839 | ||
456 | ret = i2c_add_driver(&bq27x00_battery_driver); | 840 | ret = bq27x00_battery_i2c_init(); |
457 | if (ret) | 841 | if (ret) |
458 | printk(KERN_ERR "Unable to register BQ27x00 driver\n"); | 842 | return ret; |
843 | |||
844 | ret = bq27x00_battery_platform_init(); | ||
845 | if (ret) | ||
846 | bq27x00_battery_i2c_exit(); | ||
459 | 847 | ||
460 | return ret; | 848 | return ret; |
461 | } | 849 | } |
@@ -463,7 +851,8 @@ module_init(bq27x00_battery_init); | |||
463 | 851 | ||
464 | static void __exit bq27x00_battery_exit(void) | 852 | static void __exit bq27x00_battery_exit(void) |
465 | { | 853 | { |
466 | i2c_del_driver(&bq27x00_battery_driver); | 854 | bq27x00_battery_platform_exit(); |
855 | bq27x00_battery_i2c_exit(); | ||
467 | } | 856 | } |
468 | module_exit(bq27x00_battery_exit); | 857 | module_exit(bq27x00_battery_exit); |
469 | 858 | ||
diff --git a/drivers/power/ds2782_battery.c b/drivers/power/ds2782_battery.c index 6957e8af6449..4d2dc4fa2888 100644 --- a/drivers/power/ds2782_battery.c +++ b/drivers/power/ds2782_battery.c | |||
@@ -393,6 +393,7 @@ static const struct i2c_device_id ds278x_id[] = { | |||
393 | {"ds2786", DS2786}, | 393 | {"ds2786", DS2786}, |
394 | {}, | 394 | {}, |
395 | }; | 395 | }; |
396 | MODULE_DEVICE_TABLE(i2c, ds278x_id); | ||
396 | 397 | ||
397 | static struct i2c_driver ds278x_battery_driver = { | 398 | static struct i2c_driver ds278x_battery_driver = { |
398 | .driver = { | 399 | .driver = { |
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 970f7335d3a7..329b46b2327d 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c | |||
@@ -171,6 +171,8 @@ int power_supply_register(struct device *parent, struct power_supply *psy) | |||
171 | dev_set_drvdata(dev, psy); | 171 | dev_set_drvdata(dev, psy); |
172 | psy->dev = dev; | 172 | psy->dev = dev; |
173 | 173 | ||
174 | INIT_WORK(&psy->changed_work, power_supply_changed_work); | ||
175 | |||
174 | rc = kobject_set_name(&dev->kobj, "%s", psy->name); | 176 | rc = kobject_set_name(&dev->kobj, "%s", psy->name); |
175 | if (rc) | 177 | if (rc) |
176 | goto kobject_set_name_failed; | 178 | goto kobject_set_name_failed; |
@@ -179,8 +181,6 @@ int power_supply_register(struct device *parent, struct power_supply *psy) | |||
179 | if (rc) | 181 | if (rc) |
180 | goto device_add_failed; | 182 | goto device_add_failed; |
181 | 183 | ||
182 | INIT_WORK(&psy->changed_work, power_supply_changed_work); | ||
183 | |||
184 | rc = power_supply_create_triggers(psy); | 184 | rc = power_supply_create_triggers(psy); |
185 | if (rc) | 185 | if (rc) |
186 | goto create_triggers_failed; | 186 | goto create_triggers_failed; |
diff --git a/drivers/power/power_supply_leds.c b/drivers/power/power_supply_leds.c index 031a554837f7..da25eb94e5c6 100644 --- a/drivers/power/power_supply_leds.c +++ b/drivers/power/power_supply_leds.c | |||
@@ -21,6 +21,8 @@ | |||
21 | static void power_supply_update_bat_leds(struct power_supply *psy) | 21 | static void power_supply_update_bat_leds(struct power_supply *psy) |
22 | { | 22 | { |
23 | union power_supply_propval status; | 23 | union power_supply_propval status; |
24 | unsigned long delay_on = 0; | ||
25 | unsigned long delay_off = 0; | ||
24 | 26 | ||
25 | if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status)) | 27 | if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status)) |
26 | return; | 28 | return; |
@@ -32,16 +34,22 @@ static void power_supply_update_bat_leds(struct power_supply *psy) | |||
32 | led_trigger_event(psy->charging_full_trig, LED_FULL); | 34 | led_trigger_event(psy->charging_full_trig, LED_FULL); |
33 | led_trigger_event(psy->charging_trig, LED_OFF); | 35 | led_trigger_event(psy->charging_trig, LED_OFF); |
34 | led_trigger_event(psy->full_trig, LED_FULL); | 36 | led_trigger_event(psy->full_trig, LED_FULL); |
37 | led_trigger_event(psy->charging_blink_full_solid_trig, | ||
38 | LED_FULL); | ||
35 | break; | 39 | break; |
36 | case POWER_SUPPLY_STATUS_CHARGING: | 40 | case POWER_SUPPLY_STATUS_CHARGING: |
37 | led_trigger_event(psy->charging_full_trig, LED_FULL); | 41 | led_trigger_event(psy->charging_full_trig, LED_FULL); |
38 | led_trigger_event(psy->charging_trig, LED_FULL); | 42 | led_trigger_event(psy->charging_trig, LED_FULL); |
39 | led_trigger_event(psy->full_trig, LED_OFF); | 43 | led_trigger_event(psy->full_trig, LED_OFF); |
44 | led_trigger_blink(psy->charging_blink_full_solid_trig, | ||
45 | &delay_on, &delay_off); | ||
40 | break; | 46 | break; |
41 | default: | 47 | default: |
42 | led_trigger_event(psy->charging_full_trig, LED_OFF); | 48 | led_trigger_event(psy->charging_full_trig, LED_OFF); |
43 | led_trigger_event(psy->charging_trig, LED_OFF); | 49 | led_trigger_event(psy->charging_trig, LED_OFF); |
44 | led_trigger_event(psy->full_trig, LED_OFF); | 50 | led_trigger_event(psy->full_trig, LED_OFF); |
51 | led_trigger_event(psy->charging_blink_full_solid_trig, | ||
52 | LED_OFF); | ||
45 | break; | 53 | break; |
46 | } | 54 | } |
47 | } | 55 | } |
@@ -64,15 +72,24 @@ static int power_supply_create_bat_triggers(struct power_supply *psy) | |||
64 | if (!psy->full_trig_name) | 72 | if (!psy->full_trig_name) |
65 | goto full_failed; | 73 | goto full_failed; |
66 | 74 | ||
75 | psy->charging_blink_full_solid_trig_name = kasprintf(GFP_KERNEL, | ||
76 | "%s-charging-blink-full-solid", psy->name); | ||
77 | if (!psy->charging_blink_full_solid_trig_name) | ||
78 | goto charging_blink_full_solid_failed; | ||
79 | |||
67 | led_trigger_register_simple(psy->charging_full_trig_name, | 80 | led_trigger_register_simple(psy->charging_full_trig_name, |
68 | &psy->charging_full_trig); | 81 | &psy->charging_full_trig); |
69 | led_trigger_register_simple(psy->charging_trig_name, | 82 | led_trigger_register_simple(psy->charging_trig_name, |
70 | &psy->charging_trig); | 83 | &psy->charging_trig); |
71 | led_trigger_register_simple(psy->full_trig_name, | 84 | led_trigger_register_simple(psy->full_trig_name, |
72 | &psy->full_trig); | 85 | &psy->full_trig); |
86 | led_trigger_register_simple(psy->charging_blink_full_solid_trig_name, | ||
87 | &psy->charging_blink_full_solid_trig); | ||
73 | 88 | ||
74 | goto success; | 89 | goto success; |
75 | 90 | ||
91 | charging_blink_full_solid_failed: | ||
92 | kfree(psy->full_trig_name); | ||
76 | full_failed: | 93 | full_failed: |
77 | kfree(psy->charging_trig_name); | 94 | kfree(psy->charging_trig_name); |
78 | charging_failed: | 95 | charging_failed: |
@@ -88,6 +105,8 @@ static void power_supply_remove_bat_triggers(struct power_supply *psy) | |||
88 | led_trigger_unregister_simple(psy->charging_full_trig); | 105 | led_trigger_unregister_simple(psy->charging_full_trig); |
89 | led_trigger_unregister_simple(psy->charging_trig); | 106 | led_trigger_unregister_simple(psy->charging_trig); |
90 | led_trigger_unregister_simple(psy->full_trig); | 107 | led_trigger_unregister_simple(psy->full_trig); |
108 | led_trigger_unregister_simple(psy->charging_blink_full_solid_trig); | ||
109 | kfree(psy->charging_blink_full_solid_trig_name); | ||
91 | kfree(psy->full_trig_name); | 110 | kfree(psy->full_trig_name); |
92 | kfree(psy->charging_trig_name); | 111 | kfree(psy->charging_trig_name); |
93 | kfree(psy->charging_full_trig_name); | 112 | kfree(psy->charging_full_trig_name); |
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index cd1f90754a3a..605514afc29f 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c | |||
@@ -270,7 +270,7 @@ int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
270 | attr = &power_supply_attrs[psy->properties[j]]; | 270 | attr = &power_supply_attrs[psy->properties[j]]; |
271 | 271 | ||
272 | ret = power_supply_show_property(dev, attr, prop_buf); | 272 | ret = power_supply_show_property(dev, attr, prop_buf); |
273 | if (ret == -ENODEV) { | 273 | if (ret == -ENODEV || ret == -ENODATA) { |
274 | /* When a battery is absent, we expect -ENODEV. Don't abort; | 274 | /* When a battery is absent, we expect -ENODEV. Don't abort; |
275 | send the uevent with at least the the PRESENT=0 property */ | 275 | send the uevent with at least the the PRESENT=0 property */ |
276 | ret = 0; | 276 | ret = 0; |
diff --git a/drivers/power/s3c_adc_battery.c b/drivers/power/s3c_adc_battery.c index 4255f2358b13..d36c289aaef5 100644 --- a/drivers/power/s3c_adc_battery.c +++ b/drivers/power/s3c_adc_battery.c | |||
@@ -406,8 +406,8 @@ static int s3c_adc_bat_resume(struct platform_device *pdev) | |||
406 | return 0; | 406 | return 0; |
407 | } | 407 | } |
408 | #else | 408 | #else |
409 | #define s3c_adc_battery_suspend NULL | 409 | #define s3c_adc_bat_suspend NULL |
410 | #define s3c_adc_battery_resume NULL | 410 | #define s3c_adc_bat_resume NULL |
411 | #endif | 411 | #endif |
412 | 412 | ||
413 | static struct platform_driver s3c_adc_bat_driver = { | 413 | static struct platform_driver s3c_adc_bat_driver = { |
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index ff1f42398a2e..92c16e1677bd 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c | |||
@@ -71,8 +71,11 @@ struct twl4030_bci { | |||
71 | struct power_supply usb; | 71 | struct power_supply usb; |
72 | struct otg_transceiver *transceiver; | 72 | struct otg_transceiver *transceiver; |
73 | struct notifier_block otg_nb; | 73 | struct notifier_block otg_nb; |
74 | struct work_struct work; | ||
74 | int irq_chg; | 75 | int irq_chg; |
75 | int irq_bci; | 76 | int irq_bci; |
77 | |||
78 | unsigned long event; | ||
76 | }; | 79 | }; |
77 | 80 | ||
78 | /* | 81 | /* |
@@ -258,14 +261,11 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void *arg) | |||
258 | return IRQ_HANDLED; | 261 | return IRQ_HANDLED; |
259 | } | 262 | } |
260 | 263 | ||
261 | static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, | 264 | static void twl4030_bci_usb_work(struct work_struct *data) |
262 | void *priv) | ||
263 | { | 265 | { |
264 | struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb); | 266 | struct twl4030_bci *bci = container_of(data, struct twl4030_bci, work); |
265 | 267 | ||
266 | dev_dbg(bci->dev, "OTG notify %lu\n", val); | 268 | switch (bci->event) { |
267 | |||
268 | switch (val) { | ||
269 | case USB_EVENT_VBUS: | 269 | case USB_EVENT_VBUS: |
270 | case USB_EVENT_CHARGER: | 270 | case USB_EVENT_CHARGER: |
271 | twl4030_charger_enable_usb(bci, true); | 271 | twl4030_charger_enable_usb(bci, true); |
@@ -274,6 +274,17 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, | |||
274 | twl4030_charger_enable_usb(bci, false); | 274 | twl4030_charger_enable_usb(bci, false); |
275 | break; | 275 | break; |
276 | } | 276 | } |
277 | } | ||
278 | |||
279 | static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, | ||
280 | void *priv) | ||
281 | { | ||
282 | struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb); | ||
283 | |||
284 | dev_dbg(bci->dev, "OTG notify %lu\n", val); | ||
285 | |||
286 | bci->event = val; | ||
287 | schedule_work(&bci->work); | ||
277 | 288 | ||
278 | return NOTIFY_OK; | 289 | return NOTIFY_OK; |
279 | } | 290 | } |
@@ -466,6 +477,8 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) | |||
466 | goto fail_bci_irq; | 477 | goto fail_bci_irq; |
467 | } | 478 | } |
468 | 479 | ||
480 | INIT_WORK(&bci->work, twl4030_bci_usb_work); | ||
481 | |||
469 | bci->transceiver = otg_get_transceiver(); | 482 | bci->transceiver = otg_get_transceiver(); |
470 | if (bci->transceiver != NULL) { | 483 | if (bci->transceiver != NULL) { |
471 | bci->otg_nb.notifier_call = twl4030_bci_usb_ncb; | 484 | bci->otg_nb.notifier_call = twl4030_bci_usb_ncb; |
diff --git a/drivers/power/z2_battery.c b/drivers/power/z2_battery.c index e5ed52d71937..2a9ab89f83b8 100644 --- a/drivers/power/z2_battery.c +++ b/drivers/power/z2_battery.c | |||
@@ -134,6 +134,8 @@ static int z2_batt_ps_init(struct z2_charger *charger, int props) | |||
134 | enum power_supply_property *prop; | 134 | enum power_supply_property *prop; |
135 | struct z2_battery_info *info = charger->info; | 135 | struct z2_battery_info *info = charger->info; |
136 | 136 | ||
137 | if (info->charge_gpio >= 0) | ||
138 | props++; /* POWER_SUPPLY_PROP_STATUS */ | ||
137 | if (info->batt_tech >= 0) | 139 | if (info->batt_tech >= 0) |
138 | props++; /* POWER_SUPPLY_PROP_TECHNOLOGY */ | 140 | props++; /* POWER_SUPPLY_PROP_TECHNOLOGY */ |
139 | if (info->batt_I2C_reg >= 0) | 141 | if (info->batt_I2C_reg >= 0) |
@@ -293,6 +295,7 @@ static const struct i2c_device_id z2_batt_id[] = { | |||
293 | { "aer915", 0 }, | 295 | { "aer915", 0 }, |
294 | { } | 296 | { } |
295 | }; | 297 | }; |
298 | MODULE_DEVICE_TABLE(i2c, z2_batt_id); | ||
296 | 299 | ||
297 | static struct i2c_driver z2_batt_driver = { | 300 | static struct i2c_driver z2_batt_driver = { |
298 | .driver = { | 301 | .driver = { |
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index de75f67f4cc3..b9f29e0d4295 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig | |||
@@ -126,7 +126,7 @@ config REGULATOR_MAX8998 | |||
126 | and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages. | 126 | and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages. |
127 | 127 | ||
128 | config REGULATOR_TWL4030 | 128 | config REGULATOR_TWL4030 |
129 | bool "TI TWL4030/TWL5030/TWL6030/TPS695x0 PMIC" | 129 | bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC" |
130 | depends on TWL4030_CORE | 130 | depends on TWL4030_CORE |
131 | help | 131 | help |
132 | This driver supports the voltage regulators provided by | 132 | This driver supports the voltage regulators provided by |
diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index 2dec589a8908..b1d77946e9c6 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c | |||
@@ -206,29 +206,6 @@ static int ab3100_enable_regulator(struct regulator_dev *reg) | |||
206 | return err; | 206 | return err; |
207 | } | 207 | } |
208 | 208 | ||
209 | /* Per-regulator power on delay from spec */ | ||
210 | switch (abreg->regreg) { | ||
211 | case AB3100_LDO_A: /* Fallthrough */ | ||
212 | case AB3100_LDO_C: /* Fallthrough */ | ||
213 | case AB3100_LDO_D: /* Fallthrough */ | ||
214 | case AB3100_LDO_E: /* Fallthrough */ | ||
215 | case AB3100_LDO_H: /* Fallthrough */ | ||
216 | case AB3100_LDO_K: | ||
217 | udelay(200); | ||
218 | break; | ||
219 | case AB3100_LDO_F: | ||
220 | udelay(600); | ||
221 | break; | ||
222 | case AB3100_LDO_G: | ||
223 | udelay(400); | ||
224 | break; | ||
225 | case AB3100_BUCK: | ||
226 | mdelay(1); | ||
227 | break; | ||
228 | default: | ||
229 | break; | ||
230 | } | ||
231 | |||
232 | return 0; | 209 | return 0; |
233 | } | 210 | } |
234 | 211 | ||
@@ -450,11 +427,37 @@ static int ab3100_get_voltage_regulator_external(struct regulator_dev *reg) | |||
450 | return abreg->plfdata->external_voltage; | 427 | return abreg->plfdata->external_voltage; |
451 | } | 428 | } |
452 | 429 | ||
430 | static int ab3100_enable_time_regulator(struct regulator_dev *reg) | ||
431 | { | ||
432 | struct ab3100_regulator *abreg = reg->reg_data; | ||
433 | |||
434 | /* Per-regulator power on delay from spec */ | ||
435 | switch (abreg->regreg) { | ||
436 | case AB3100_LDO_A: /* Fallthrough */ | ||
437 | case AB3100_LDO_C: /* Fallthrough */ | ||
438 | case AB3100_LDO_D: /* Fallthrough */ | ||
439 | case AB3100_LDO_E: /* Fallthrough */ | ||
440 | case AB3100_LDO_H: /* Fallthrough */ | ||
441 | case AB3100_LDO_K: | ||
442 | return 200; | ||
443 | case AB3100_LDO_F: | ||
444 | return 600; | ||
445 | case AB3100_LDO_G: | ||
446 | return 400; | ||
447 | case AB3100_BUCK: | ||
448 | return 1000; | ||
449 | default: | ||
450 | break; | ||
451 | } | ||
452 | return 0; | ||
453 | } | ||
454 | |||
453 | static struct regulator_ops regulator_ops_fixed = { | 455 | static struct regulator_ops regulator_ops_fixed = { |
454 | .enable = ab3100_enable_regulator, | 456 | .enable = ab3100_enable_regulator, |
455 | .disable = ab3100_disable_regulator, | 457 | .disable = ab3100_disable_regulator, |
456 | .is_enabled = ab3100_is_enabled_regulator, | 458 | .is_enabled = ab3100_is_enabled_regulator, |
457 | .get_voltage = ab3100_get_voltage_regulator, | 459 | .get_voltage = ab3100_get_voltage_regulator, |
460 | .enable_time = ab3100_enable_time_regulator, | ||
458 | }; | 461 | }; |
459 | 462 | ||
460 | static struct regulator_ops regulator_ops_variable = { | 463 | static struct regulator_ops regulator_ops_variable = { |
@@ -464,6 +467,7 @@ static struct regulator_ops regulator_ops_variable = { | |||
464 | .get_voltage = ab3100_get_voltage_regulator, | 467 | .get_voltage = ab3100_get_voltage_regulator, |
465 | .set_voltage = ab3100_set_voltage_regulator, | 468 | .set_voltage = ab3100_set_voltage_regulator, |
466 | .list_voltage = ab3100_list_voltage_regulator, | 469 | .list_voltage = ab3100_list_voltage_regulator, |
470 | .enable_time = ab3100_enable_time_regulator, | ||
467 | }; | 471 | }; |
468 | 472 | ||
469 | static struct regulator_ops regulator_ops_variable_sleepable = { | 473 | static struct regulator_ops regulator_ops_variable_sleepable = { |
@@ -474,6 +478,7 @@ static struct regulator_ops regulator_ops_variable_sleepable = { | |||
474 | .set_voltage = ab3100_set_voltage_regulator, | 478 | .set_voltage = ab3100_set_voltage_regulator, |
475 | .set_suspend_voltage = ab3100_set_suspend_voltage_regulator, | 479 | .set_suspend_voltage = ab3100_set_suspend_voltage_regulator, |
476 | .list_voltage = ab3100_list_voltage_regulator, | 480 | .list_voltage = ab3100_list_voltage_regulator, |
481 | .enable_time = ab3100_enable_time_regulator, | ||
477 | }; | 482 | }; |
478 | 483 | ||
479 | /* | 484 | /* |
diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index d9a052c53aec..02f3c2333c83 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c | |||
@@ -9,7 +9,7 @@ | |||
9 | * AB8500 peripheral regulators | 9 | * AB8500 peripheral regulators |
10 | * | 10 | * |
11 | * AB8500 supports the following regulators: | 11 | * AB8500 supports the following regulators: |
12 | * VAUX1/2/3, VINTCORE, VTVOUT, VAUDIO, VAMIC1/2, VDMIC, VANA | 12 | * VAUX1/2/3, VINTCORE, VTVOUT, VUSB, VAUDIO, VAMIC1/2, VDMIC, VANA |
13 | */ | 13 | */ |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
@@ -38,6 +38,7 @@ | |||
38 | * @voltage_mask: mask to control regulator voltage | 38 | * @voltage_mask: mask to control regulator voltage |
39 | * @voltages: supported voltage table | 39 | * @voltages: supported voltage table |
40 | * @voltages_len: number of supported voltages for the regulator | 40 | * @voltages_len: number of supported voltages for the regulator |
41 | * @delay: startup/set voltage delay in us | ||
41 | */ | 42 | */ |
42 | struct ab8500_regulator_info { | 43 | struct ab8500_regulator_info { |
43 | struct device *dev; | 44 | struct device *dev; |
@@ -55,6 +56,7 @@ struct ab8500_regulator_info { | |||
55 | u8 voltage_mask; | 56 | u8 voltage_mask; |
56 | int const *voltages; | 57 | int const *voltages; |
57 | int voltages_len; | 58 | int voltages_len; |
59 | unsigned int delay; | ||
58 | }; | 60 | }; |
59 | 61 | ||
60 | /* voltage tables for the vauxn/vintcore supplies */ | 62 | /* voltage tables for the vauxn/vintcore supplies */ |
@@ -290,6 +292,29 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, | |||
290 | return ret; | 292 | return ret; |
291 | } | 293 | } |
292 | 294 | ||
295 | static int ab8500_regulator_enable_time(struct regulator_dev *rdev) | ||
296 | { | ||
297 | struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); | ||
298 | |||
299 | return info->delay; | ||
300 | } | ||
301 | |||
302 | static int ab8500_regulator_set_voltage_time_sel(struct regulator_dev *rdev, | ||
303 | unsigned int old_sel, | ||
304 | unsigned int new_sel) | ||
305 | { | ||
306 | struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); | ||
307 | int ret; | ||
308 | |||
309 | /* If the regulator isn't on, it won't take time here */ | ||
310 | ret = ab8500_regulator_is_enabled(rdev); | ||
311 | if (ret < 0) | ||
312 | return ret; | ||
313 | if (!ret) | ||
314 | return 0; | ||
315 | return info->delay; | ||
316 | } | ||
317 | |||
293 | static struct regulator_ops ab8500_regulator_ops = { | 318 | static struct regulator_ops ab8500_regulator_ops = { |
294 | .enable = ab8500_regulator_enable, | 319 | .enable = ab8500_regulator_enable, |
295 | .disable = ab8500_regulator_disable, | 320 | .disable = ab8500_regulator_disable, |
@@ -297,6 +322,8 @@ static struct regulator_ops ab8500_regulator_ops = { | |||
297 | .get_voltage = ab8500_regulator_get_voltage, | 322 | .get_voltage = ab8500_regulator_get_voltage, |
298 | .set_voltage = ab8500_regulator_set_voltage, | 323 | .set_voltage = ab8500_regulator_set_voltage, |
299 | .list_voltage = ab8500_list_voltage, | 324 | .list_voltage = ab8500_list_voltage, |
325 | .enable_time = ab8500_regulator_enable_time, | ||
326 | .set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel, | ||
300 | }; | 327 | }; |
301 | 328 | ||
302 | static int ab8500_fixed_get_voltage(struct regulator_dev *rdev) | 329 | static int ab8500_fixed_get_voltage(struct regulator_dev *rdev) |
@@ -317,6 +344,8 @@ static struct regulator_ops ab8500_regulator_fixed_ops = { | |||
317 | .is_enabled = ab8500_regulator_is_enabled, | 344 | .is_enabled = ab8500_regulator_is_enabled, |
318 | .get_voltage = ab8500_fixed_get_voltage, | 345 | .get_voltage = ab8500_fixed_get_voltage, |
319 | .list_voltage = ab8500_list_voltage, | 346 | .list_voltage = ab8500_list_voltage, |
347 | .enable_time = ab8500_regulator_enable_time, | ||
348 | .set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel, | ||
320 | }; | 349 | }; |
321 | 350 | ||
322 | static struct ab8500_regulator_info | 351 | static struct ab8500_regulator_info |
@@ -426,12 +455,28 @@ static struct ab8500_regulator_info | |||
426 | .owner = THIS_MODULE, | 455 | .owner = THIS_MODULE, |
427 | .n_voltages = 1, | 456 | .n_voltages = 1, |
428 | }, | 457 | }, |
458 | .delay = 10000, | ||
429 | .fixed_uV = 2000000, | 459 | .fixed_uV = 2000000, |
430 | .update_bank = 0x03, | 460 | .update_bank = 0x03, |
431 | .update_reg = 0x80, | 461 | .update_reg = 0x80, |
432 | .update_mask = 0x82, | 462 | .update_mask = 0x82, |
433 | .update_val_enable = 0x02, | 463 | .update_val_enable = 0x02, |
434 | }, | 464 | }, |
465 | [AB8500_LDO_USB] = { | ||
466 | .desc = { | ||
467 | .name = "LDO-USB", | ||
468 | .ops = &ab8500_regulator_fixed_ops, | ||
469 | .type = REGULATOR_VOLTAGE, | ||
470 | .id = AB8500_LDO_USB, | ||
471 | .owner = THIS_MODULE, | ||
472 | .n_voltages = 1, | ||
473 | }, | ||
474 | .fixed_uV = 3300000, | ||
475 | .update_bank = 0x03, | ||
476 | .update_reg = 0x82, | ||
477 | .update_mask = 0x03, | ||
478 | .update_val_enable = 0x01, | ||
479 | }, | ||
435 | [AB8500_LDO_AUDIO] = { | 480 | [AB8500_LDO_AUDIO] = { |
436 | .desc = { | 481 | .desc = { |
437 | .name = "LDO-AUDIO", | 482 | .name = "LDO-AUDIO", |
@@ -511,6 +556,186 @@ static struct ab8500_regulator_info | |||
511 | 556 | ||
512 | }; | 557 | }; |
513 | 558 | ||
559 | struct ab8500_reg_init { | ||
560 | u8 bank; | ||
561 | u8 addr; | ||
562 | u8 mask; | ||
563 | }; | ||
564 | |||
565 | #define REG_INIT(_id, _bank, _addr, _mask) \ | ||
566 | [_id] = { \ | ||
567 | .bank = _bank, \ | ||
568 | .addr = _addr, \ | ||
569 | .mask = _mask, \ | ||
570 | } | ||
571 | |||
572 | static struct ab8500_reg_init ab8500_reg_init[] = { | ||
573 | /* | ||
574 | * 0x30, VanaRequestCtrl | ||
575 | * 0x0C, VpllRequestCtrl | ||
576 | * 0xc0, VextSupply1RequestCtrl | ||
577 | */ | ||
578 | REG_INIT(AB8500_REGUREQUESTCTRL2, 0x03, 0x04, 0xfc), | ||
579 | /* | ||
580 | * 0x03, VextSupply2RequestCtrl | ||
581 | * 0x0c, VextSupply3RequestCtrl | ||
582 | * 0x30, Vaux1RequestCtrl | ||
583 | * 0xc0, Vaux2RequestCtrl | ||
584 | */ | ||
585 | REG_INIT(AB8500_REGUREQUESTCTRL3, 0x03, 0x05, 0xff), | ||
586 | /* | ||
587 | * 0x03, Vaux3RequestCtrl | ||
588 | * 0x04, SwHPReq | ||
589 | */ | ||
590 | REG_INIT(AB8500_REGUREQUESTCTRL4, 0x03, 0x06, 0x07), | ||
591 | /* | ||
592 | * 0x08, VanaSysClkReq1HPValid | ||
593 | * 0x20, Vaux1SysClkReq1HPValid | ||
594 | * 0x40, Vaux2SysClkReq1HPValid | ||
595 | * 0x80, Vaux3SysClkReq1HPValid | ||
596 | */ | ||
597 | REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xe8), | ||
598 | /* | ||
599 | * 0x10, VextSupply1SysClkReq1HPValid | ||
600 | * 0x20, VextSupply2SysClkReq1HPValid | ||
601 | * 0x40, VextSupply3SysClkReq1HPValid | ||
602 | */ | ||
603 | REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x70), | ||
604 | /* | ||
605 | * 0x08, VanaHwHPReq1Valid | ||
606 | * 0x20, Vaux1HwHPReq1Valid | ||
607 | * 0x40, Vaux2HwHPReq1Valid | ||
608 | * 0x80, Vaux3HwHPReq1Valid | ||
609 | */ | ||
610 | REG_INIT(AB8500_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xe8), | ||
611 | /* | ||
612 | * 0x01, VextSupply1HwHPReq1Valid | ||
613 | * 0x02, VextSupply2HwHPReq1Valid | ||
614 | * 0x04, VextSupply3HwHPReq1Valid | ||
615 | */ | ||
616 | REG_INIT(AB8500_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x07), | ||
617 | /* | ||
618 | * 0x08, VanaHwHPReq2Valid | ||
619 | * 0x20, Vaux1HwHPReq2Valid | ||
620 | * 0x40, Vaux2HwHPReq2Valid | ||
621 | * 0x80, Vaux3HwHPReq2Valid | ||
622 | */ | ||
623 | REG_INIT(AB8500_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xe8), | ||
624 | /* | ||
625 | * 0x01, VextSupply1HwHPReq2Valid | ||
626 | * 0x02, VextSupply2HwHPReq2Valid | ||
627 | * 0x04, VextSupply3HwHPReq2Valid | ||
628 | */ | ||
629 | REG_INIT(AB8500_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x07), | ||
630 | /* | ||
631 | * 0x20, VanaSwHPReqValid | ||
632 | * 0x80, Vaux1SwHPReqValid | ||
633 | */ | ||
634 | REG_INIT(AB8500_REGUSWHPREQVALID1, 0x03, 0x0d, 0xa0), | ||
635 | /* | ||
636 | * 0x01, Vaux2SwHPReqValid | ||
637 | * 0x02, Vaux3SwHPReqValid | ||
638 | * 0x04, VextSupply1SwHPReqValid | ||
639 | * 0x08, VextSupply2SwHPReqValid | ||
640 | * 0x10, VextSupply3SwHPReqValid | ||
641 | */ | ||
642 | REG_INIT(AB8500_REGUSWHPREQVALID2, 0x03, 0x0e, 0x1f), | ||
643 | /* | ||
644 | * 0x02, SysClkReq2Valid1 | ||
645 | * ... | ||
646 | * 0x80, SysClkReq8Valid1 | ||
647 | */ | ||
648 | REG_INIT(AB8500_REGUSYSCLKREQVALID1, 0x03, 0x0f, 0xfe), | ||
649 | /* | ||
650 | * 0x02, SysClkReq2Valid2 | ||
651 | * ... | ||
652 | * 0x80, SysClkReq8Valid2 | ||
653 | */ | ||
654 | REG_INIT(AB8500_REGUSYSCLKREQVALID2, 0x03, 0x10, 0xfe), | ||
655 | /* | ||
656 | * 0x02, VTVoutEna | ||
657 | * 0x04, Vintcore12Ena | ||
658 | * 0x38, Vintcore12Sel | ||
659 | * 0x40, Vintcore12LP | ||
660 | * 0x80, VTVoutLP | ||
661 | */ | ||
662 | REG_INIT(AB8500_REGUMISC1, 0x03, 0x80, 0xfe), | ||
663 | /* | ||
664 | * 0x02, VaudioEna | ||
665 | * 0x04, VdmicEna | ||
666 | * 0x08, Vamic1Ena | ||
667 | * 0x10, Vamic2Ena | ||
668 | */ | ||
669 | REG_INIT(AB8500_VAUDIOSUPPLY, 0x03, 0x83, 0x1e), | ||
670 | /* | ||
671 | * 0x01, Vamic1_dzout | ||
672 | * 0x02, Vamic2_dzout | ||
673 | */ | ||
674 | REG_INIT(AB8500_REGUCTRL1VAMIC, 0x03, 0x84, 0x03), | ||
675 | /* | ||
676 | * 0x0c, VanaRegu | ||
677 | * 0x03, VpllRegu | ||
678 | */ | ||
679 | REG_INIT(AB8500_VPLLVANAREGU, 0x04, 0x06, 0x0f), | ||
680 | /* | ||
681 | * 0x01, VrefDDREna | ||
682 | * 0x02, VrefDDRSleepMode | ||
683 | */ | ||
684 | REG_INIT(AB8500_VREFDDR, 0x04, 0x07, 0x03), | ||
685 | /* | ||
686 | * 0x03, VextSupply1Regu | ||
687 | * 0x0c, VextSupply2Regu | ||
688 | * 0x30, VextSupply3Regu | ||
689 | * 0x40, ExtSupply2Bypass | ||
690 | * 0x80, ExtSupply3Bypass | ||
691 | */ | ||
692 | REG_INIT(AB8500_EXTSUPPLYREGU, 0x04, 0x08, 0xff), | ||
693 | /* | ||
694 | * 0x03, Vaux1Regu | ||
695 | * 0x0c, Vaux2Regu | ||
696 | */ | ||
697 | REG_INIT(AB8500_VAUX12REGU, 0x04, 0x09, 0x0f), | ||
698 | /* | ||
699 | * 0x03, Vaux3Regu | ||
700 | */ | ||
701 | REG_INIT(AB8500_VRF1VAUX3REGU, 0x04, 0x0a, 0x03), | ||
702 | /* | ||
703 | * 0x3f, Vsmps1Sel1 | ||
704 | */ | ||
705 | REG_INIT(AB8500_VSMPS1SEL1, 0x04, 0x13, 0x3f), | ||
706 | /* | ||
707 | * 0x0f, Vaux1Sel | ||
708 | */ | ||
709 | REG_INIT(AB8500_VAUX1SEL, 0x04, 0x1f, 0x0f), | ||
710 | /* | ||
711 | * 0x0f, Vaux2Sel | ||
712 | */ | ||
713 | REG_INIT(AB8500_VAUX2SEL, 0x04, 0x20, 0x0f), | ||
714 | /* | ||
715 | * 0x07, Vaux3Sel | ||
716 | */ | ||
717 | REG_INIT(AB8500_VRF1VAUX3SEL, 0x04, 0x21, 0x07), | ||
718 | /* | ||
719 | * 0x01, VextSupply12LP | ||
720 | */ | ||
721 | REG_INIT(AB8500_REGUCTRL2SPARE, 0x04, 0x22, 0x01), | ||
722 | /* | ||
723 | * 0x04, Vaux1Disch | ||
724 | * 0x08, Vaux2Disch | ||
725 | * 0x10, Vaux3Disch | ||
726 | * 0x20, Vintcore12Disch | ||
727 | * 0x40, VTVoutDisch | ||
728 | * 0x80, VaudioDisch | ||
729 | */ | ||
730 | REG_INIT(AB8500_REGUCTRLDISCH, 0x04, 0x43, 0xfc), | ||
731 | /* | ||
732 | * 0x02, VanaDisch | ||
733 | * 0x04, VdmicPullDownEna | ||
734 | * 0x10, VdmicDisch | ||
735 | */ | ||
736 | REG_INIT(AB8500_REGUCTRLDISCH2, 0x04, 0x44, 0x16), | ||
737 | }; | ||
738 | |||
514 | static __devinit int ab8500_regulator_probe(struct platform_device *pdev) | 739 | static __devinit int ab8500_regulator_probe(struct platform_device *pdev) |
515 | { | 740 | { |
516 | struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); | 741 | struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); |
@@ -529,10 +754,51 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) | |||
529 | 754 | ||
530 | /* make sure the platform data has the correct size */ | 755 | /* make sure the platform data has the correct size */ |
531 | if (pdata->num_regulator != ARRAY_SIZE(ab8500_regulator_info)) { | 756 | if (pdata->num_regulator != ARRAY_SIZE(ab8500_regulator_info)) { |
532 | dev_err(&pdev->dev, "platform configuration error\n"); | 757 | dev_err(&pdev->dev, "Configuration error: size mismatch.\n"); |
533 | return -EINVAL; | 758 | return -EINVAL; |
534 | } | 759 | } |
535 | 760 | ||
761 | /* initialize registers */ | ||
762 | for (i = 0; i < pdata->num_regulator_reg_init; i++) { | ||
763 | int id; | ||
764 | u8 value; | ||
765 | |||
766 | id = pdata->regulator_reg_init[i].id; | ||
767 | value = pdata->regulator_reg_init[i].value; | ||
768 | |||
769 | /* check for configuration errors */ | ||
770 | if (id >= AB8500_NUM_REGULATOR_REGISTERS) { | ||
771 | dev_err(&pdev->dev, | ||
772 | "Configuration error: id outside range.\n"); | ||
773 | return -EINVAL; | ||
774 | } | ||
775 | if (value & ~ab8500_reg_init[id].mask) { | ||
776 | dev_err(&pdev->dev, | ||
777 | "Configuration error: value outside mask.\n"); | ||
778 | return -EINVAL; | ||
779 | } | ||
780 | |||
781 | /* initialize register */ | ||
782 | err = abx500_mask_and_set_register_interruptible(&pdev->dev, | ||
783 | ab8500_reg_init[id].bank, | ||
784 | ab8500_reg_init[id].addr, | ||
785 | ab8500_reg_init[id].mask, | ||
786 | value); | ||
787 | if (err < 0) { | ||
788 | dev_err(&pdev->dev, | ||
789 | "Failed to initialize 0x%02x, 0x%02x.\n", | ||
790 | ab8500_reg_init[id].bank, | ||
791 | ab8500_reg_init[id].addr); | ||
792 | return err; | ||
793 | } | ||
794 | dev_vdbg(&pdev->dev, | ||
795 | " init: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", | ||
796 | ab8500_reg_init[id].bank, | ||
797 | ab8500_reg_init[id].addr, | ||
798 | ab8500_reg_init[id].mask, | ||
799 | value); | ||
800 | } | ||
801 | |||
536 | /* register all regulators */ | 802 | /* register all regulators */ |
537 | for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { | 803 | for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { |
538 | struct ab8500_regulator_info *info = NULL; | 804 | struct ab8500_regulator_info *info = NULL; |
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 9fa20957847d..3ffc6979d164 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c | |||
@@ -1629,6 +1629,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, | |||
1629 | int min_uV, int max_uV) | 1629 | int min_uV, int max_uV) |
1630 | { | 1630 | { |
1631 | int ret; | 1631 | int ret; |
1632 | int delay = 0; | ||
1632 | unsigned int selector; | 1633 | unsigned int selector; |
1633 | 1634 | ||
1634 | trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); | 1635 | trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); |
@@ -1662,6 +1663,22 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, | |||
1662 | } | 1663 | } |
1663 | } | 1664 | } |
1664 | 1665 | ||
1666 | /* | ||
1667 | * If we can't obtain the old selector there is not enough | ||
1668 | * info to call set_voltage_time_sel(). | ||
1669 | */ | ||
1670 | if (rdev->desc->ops->set_voltage_time_sel && | ||
1671 | rdev->desc->ops->get_voltage_sel) { | ||
1672 | unsigned int old_selector = 0; | ||
1673 | |||
1674 | ret = rdev->desc->ops->get_voltage_sel(rdev); | ||
1675 | if (ret < 0) | ||
1676 | return ret; | ||
1677 | old_selector = ret; | ||
1678 | delay = rdev->desc->ops->set_voltage_time_sel(rdev, | ||
1679 | old_selector, selector); | ||
1680 | } | ||
1681 | |||
1665 | if (best_val != INT_MAX) { | 1682 | if (best_val != INT_MAX) { |
1666 | ret = rdev->desc->ops->set_voltage_sel(rdev, selector); | 1683 | ret = rdev->desc->ops->set_voltage_sel(rdev, selector); |
1667 | selector = best_val; | 1684 | selector = best_val; |
@@ -1672,6 +1689,14 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, | |||
1672 | ret = -EINVAL; | 1689 | ret = -EINVAL; |
1673 | } | 1690 | } |
1674 | 1691 | ||
1692 | /* Insert any necessary delays */ | ||
1693 | if (delay >= 1000) { | ||
1694 | mdelay(delay / 1000); | ||
1695 | udelay(delay % 1000); | ||
1696 | } else if (delay) { | ||
1697 | udelay(delay); | ||
1698 | } | ||
1699 | |||
1675 | if (ret == 0) | 1700 | if (ret == 0) |
1676 | _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, | 1701 | _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, |
1677 | NULL); | 1702 | NULL); |
@@ -1740,6 +1765,51 @@ out: | |||
1740 | EXPORT_SYMBOL_GPL(regulator_set_voltage); | 1765 | EXPORT_SYMBOL_GPL(regulator_set_voltage); |
1741 | 1766 | ||
1742 | /** | 1767 | /** |
1768 | * regulator_set_voltage_time - get raise/fall time | ||
1769 | * @regulator: regulator source | ||
1770 | * @old_uV: starting voltage in microvolts | ||
1771 | * @new_uV: target voltage in microvolts | ||
1772 | * | ||
1773 | * Provided with the starting and ending voltage, this function attempts to | ||
1774 | * calculate the time in microseconds required to rise or fall to this new | ||
1775 | * voltage. | ||
1776 | */ | ||
1777 | int regulator_set_voltage_time(struct regulator *regulator, | ||
1778 | int old_uV, int new_uV) | ||
1779 | { | ||
1780 | struct regulator_dev *rdev = regulator->rdev; | ||
1781 | struct regulator_ops *ops = rdev->desc->ops; | ||
1782 | int old_sel = -1; | ||
1783 | int new_sel = -1; | ||
1784 | int voltage; | ||
1785 | int i; | ||
1786 | |||
1787 | /* Currently requires operations to do this */ | ||
1788 | if (!ops->list_voltage || !ops->set_voltage_time_sel | ||
1789 | || !rdev->desc->n_voltages) | ||
1790 | return -EINVAL; | ||
1791 | |||
1792 | for (i = 0; i < rdev->desc->n_voltages; i++) { | ||
1793 | /* We only look for exact voltage matches here */ | ||
1794 | voltage = regulator_list_voltage(regulator, i); | ||
1795 | if (voltage < 0) | ||
1796 | return -EINVAL; | ||
1797 | if (voltage == 0) | ||
1798 | continue; | ||
1799 | if (voltage == old_uV) | ||
1800 | old_sel = i; | ||
1801 | if (voltage == new_uV) | ||
1802 | new_sel = i; | ||
1803 | } | ||
1804 | |||
1805 | if (old_sel < 0 || new_sel < 0) | ||
1806 | return -EINVAL; | ||
1807 | |||
1808 | return ops->set_voltage_time_sel(rdev, old_sel, new_sel); | ||
1809 | } | ||
1810 | EXPORT_SYMBOL_GPL(regulator_set_voltage_time); | ||
1811 | |||
1812 | /** | ||
1743 | * regulator_sync_voltage - re-apply last regulator output voltage | 1813 | * regulator_sync_voltage - re-apply last regulator output voltage |
1744 | * @regulator: regulator source | 1814 | * @regulator: regulator source |
1745 | * | 1815 | * |
@@ -2565,8 +2635,11 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, | |||
2565 | init_data->consumer_supplies[i].dev, | 2635 | init_data->consumer_supplies[i].dev, |
2566 | init_data->consumer_supplies[i].dev_name, | 2636 | init_data->consumer_supplies[i].dev_name, |
2567 | init_data->consumer_supplies[i].supply); | 2637 | init_data->consumer_supplies[i].supply); |
2568 | if (ret < 0) | 2638 | if (ret < 0) { |
2639 | dev_err(dev, "Failed to set supply %s\n", | ||
2640 | init_data->consumer_supplies[i].supply); | ||
2569 | goto unset_supplies; | 2641 | goto unset_supplies; |
2642 | } | ||
2570 | } | 2643 | } |
2571 | 2644 | ||
2572 | list_add(&rdev->list, ®ulator_list); | 2645 | list_add(&rdev->list, ®ulator_list); |
@@ -2653,6 +2726,47 @@ out: | |||
2653 | EXPORT_SYMBOL_GPL(regulator_suspend_prepare); | 2726 | EXPORT_SYMBOL_GPL(regulator_suspend_prepare); |
2654 | 2727 | ||
2655 | /** | 2728 | /** |
2729 | * regulator_suspend_finish - resume regulators from system wide suspend | ||
2730 | * | ||
2731 | * Turn on regulators that might be turned off by regulator_suspend_prepare | ||
2732 | * and that should be turned on according to the regulators properties. | ||
2733 | */ | ||
2734 | int regulator_suspend_finish(void) | ||
2735 | { | ||
2736 | struct regulator_dev *rdev; | ||
2737 | int ret = 0, error; | ||
2738 | |||
2739 | mutex_lock(®ulator_list_mutex); | ||
2740 | list_for_each_entry(rdev, ®ulator_list, list) { | ||
2741 | struct regulator_ops *ops = rdev->desc->ops; | ||
2742 | |||
2743 | mutex_lock(&rdev->mutex); | ||
2744 | if ((rdev->use_count > 0 || rdev->constraints->always_on) && | ||
2745 | ops->enable) { | ||
2746 | error = ops->enable(rdev); | ||
2747 | if (error) | ||
2748 | ret = error; | ||
2749 | } else { | ||
2750 | if (!has_full_constraints) | ||
2751 | goto unlock; | ||
2752 | if (!ops->disable) | ||
2753 | goto unlock; | ||
2754 | if (ops->is_enabled && !ops->is_enabled(rdev)) | ||
2755 | goto unlock; | ||
2756 | |||
2757 | error = ops->disable(rdev); | ||
2758 | if (error) | ||
2759 | ret = error; | ||
2760 | } | ||
2761 | unlock: | ||
2762 | mutex_unlock(&rdev->mutex); | ||
2763 | } | ||
2764 | mutex_unlock(®ulator_list_mutex); | ||
2765 | return ret; | ||
2766 | } | ||
2767 | EXPORT_SYMBOL_GPL(regulator_suspend_finish); | ||
2768 | |||
2769 | /** | ||
2656 | * regulator_has_full_constraints - the system has fully specified constraints | 2770 | * regulator_has_full_constraints - the system has fully specified constraints |
2657 | * | 2771 | * |
2658 | * Calling this function will cause the regulator API to disable all | 2772 | * Calling this function will cause the regulator API to disable all |
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index 01ef7e9903bb..77e0cfb30b23 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c | |||
@@ -1185,6 +1185,7 @@ static const struct platform_device_id max8997_pmic_id[] = { | |||
1185 | { "max8997-pmic", 0}, | 1185 | { "max8997-pmic", 0}, |
1186 | { }, | 1186 | { }, |
1187 | }; | 1187 | }; |
1188 | MODULE_DEVICE_TABLE(platform, max8997_pmic_id); | ||
1188 | 1189 | ||
1189 | static struct platform_driver max8997_pmic_driver = { | 1190 | static struct platform_driver max8997_pmic_driver = { |
1190 | .driver = { | 1191 | .driver = { |
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 0ec49ca527a8..43410266f993 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c | |||
@@ -887,6 +887,7 @@ static const struct platform_device_id max8998_pmic_id[] = { | |||
887 | { "lp3974-pmic", TYPE_LP3974 }, | 887 | { "lp3974-pmic", TYPE_LP3974 }, |
888 | { } | 888 | { } |
889 | }; | 889 | }; |
890 | MODULE_DEVICE_TABLE(platform, max8998_pmic_id); | ||
890 | 891 | ||
891 | static struct platform_driver max8998_pmic_driver = { | 892 | static struct platform_driver max8998_pmic_driver = { |
892 | .driver = { | 893 | .driver = { |
diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c index 176a6be5a8ce..9166aa0a9df7 100644 --- a/drivers/regulator/tps6524x-regulator.c +++ b/drivers/regulator/tps6524x-regulator.c | |||
@@ -596,7 +596,7 @@ static struct regulator_ops regulator_ops = { | |||
596 | .get_current_limit = get_current_limit, | 596 | .get_current_limit = get_current_limit, |
597 | }; | 597 | }; |
598 | 598 | ||
599 | static int __devexit pmic_remove(struct spi_device *spi) | 599 | static int pmic_remove(struct spi_device *spi) |
600 | { | 600 | { |
601 | struct tps6524x *hw = spi_get_drvdata(spi); | 601 | struct tps6524x *hw = spi_get_drvdata(spi); |
602 | int i; | 602 | int i; |
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 06df898842c0..e93453b1b978 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c | |||
@@ -565,9 +565,8 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev) | |||
565 | } | 565 | } |
566 | 566 | ||
567 | irq = platform_get_irq_byname(pdev, "UV"); | 567 | irq = platform_get_irq_byname(pdev, "UV"); |
568 | ret = wm831x_request_irq(wm831x, irq, wm831x_dcdc_uv_irq, | 568 | ret = request_threaded_irq(irq, NULL, wm831x_dcdc_uv_irq, |
569 | IRQF_TRIGGER_RISING, dcdc->name, | 569 | IRQF_TRIGGER_RISING, dcdc->name, dcdc); |
570 | dcdc); | ||
571 | if (ret != 0) { | 570 | if (ret != 0) { |
572 | dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", | 571 | dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", |
573 | irq, ret); | 572 | irq, ret); |
@@ -575,9 +574,8 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev) | |||
575 | } | 574 | } |
576 | 575 | ||
577 | irq = platform_get_irq_byname(pdev, "HC"); | 576 | irq = platform_get_irq_byname(pdev, "HC"); |
578 | ret = wm831x_request_irq(wm831x, irq, wm831x_dcdc_oc_irq, | 577 | ret = request_threaded_irq(irq, NULL, wm831x_dcdc_oc_irq, |
579 | IRQF_TRIGGER_RISING, dcdc->name, | 578 | IRQF_TRIGGER_RISING, dcdc->name, dcdc); |
580 | dcdc); | ||
581 | if (ret != 0) { | 579 | if (ret != 0) { |
582 | dev_err(&pdev->dev, "Failed to request HC IRQ %d: %d\n", | 580 | dev_err(&pdev->dev, "Failed to request HC IRQ %d: %d\n", |
583 | irq, ret); | 581 | irq, ret); |
@@ -589,7 +587,7 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev) | |||
589 | return 0; | 587 | return 0; |
590 | 588 | ||
591 | err_uv: | 589 | err_uv: |
592 | wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc); | 590 | free_irq(platform_get_irq_byname(pdev, "UV"), dcdc); |
593 | err_regulator: | 591 | err_regulator: |
594 | regulator_unregister(dcdc->regulator); | 592 | regulator_unregister(dcdc->regulator); |
595 | err: | 593 | err: |
@@ -606,8 +604,8 @@ static __devexit int wm831x_buckv_remove(struct platform_device *pdev) | |||
606 | 604 | ||
607 | platform_set_drvdata(pdev, NULL); | 605 | platform_set_drvdata(pdev, NULL); |
608 | 606 | ||
609 | wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "HC"), dcdc); | 607 | free_irq(platform_get_irq_byname(pdev, "HC"), dcdc); |
610 | wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc); | 608 | free_irq(platform_get_irq_byname(pdev, "UV"), dcdc); |
611 | regulator_unregister(dcdc->regulator); | 609 | regulator_unregister(dcdc->regulator); |
612 | if (dcdc->dvs_gpio) | 610 | if (dcdc->dvs_gpio) |
613 | gpio_free(dcdc->dvs_gpio); | 611 | gpio_free(dcdc->dvs_gpio); |
@@ -756,9 +754,8 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev) | |||
756 | } | 754 | } |
757 | 755 | ||
758 | irq = platform_get_irq_byname(pdev, "UV"); | 756 | irq = platform_get_irq_byname(pdev, "UV"); |
759 | ret = wm831x_request_irq(wm831x, irq, wm831x_dcdc_uv_irq, | 757 | ret = request_threaded_irq(irq, NULL, wm831x_dcdc_uv_irq, |
760 | IRQF_TRIGGER_RISING, dcdc->name, | 758 | IRQF_TRIGGER_RISING, dcdc->name, dcdc); |
761 | dcdc); | ||
762 | if (ret != 0) { | 759 | if (ret != 0) { |
763 | dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", | 760 | dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", |
764 | irq, ret); | 761 | irq, ret); |
@@ -783,7 +780,7 @@ static __devexit int wm831x_buckp_remove(struct platform_device *pdev) | |||
783 | 780 | ||
784 | platform_set_drvdata(pdev, NULL); | 781 | platform_set_drvdata(pdev, NULL); |
785 | 782 | ||
786 | wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc); | 783 | free_irq(platform_get_irq_byname(pdev, "UV"), dcdc); |
787 | regulator_unregister(dcdc->regulator); | 784 | regulator_unregister(dcdc->regulator); |
788 | kfree(dcdc); | 785 | kfree(dcdc); |
789 | 786 | ||
@@ -885,9 +882,9 @@ static __devinit int wm831x_boostp_probe(struct platform_device *pdev) | |||
885 | } | 882 | } |
886 | 883 | ||
887 | irq = platform_get_irq_byname(pdev, "UV"); | 884 | irq = platform_get_irq_byname(pdev, "UV"); |
888 | ret = wm831x_request_irq(wm831x, irq, wm831x_dcdc_uv_irq, | 885 | ret = request_threaded_irq(irq, NULL, wm831x_dcdc_uv_irq, |
889 | IRQF_TRIGGER_RISING, dcdc->name, | 886 | IRQF_TRIGGER_RISING, dcdc->name, |
890 | dcdc); | 887 | dcdc); |
891 | if (ret != 0) { | 888 | if (ret != 0) { |
892 | dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", | 889 | dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", |
893 | irq, ret); | 890 | irq, ret); |
@@ -908,11 +905,10 @@ err: | |||
908 | static __devexit int wm831x_boostp_remove(struct platform_device *pdev) | 905 | static __devexit int wm831x_boostp_remove(struct platform_device *pdev) |
909 | { | 906 | { |
910 | struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); | 907 | struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); |
911 | struct wm831x *wm831x = dcdc->wm831x; | ||
912 | 908 | ||
913 | platform_set_drvdata(pdev, NULL); | 909 | platform_set_drvdata(pdev, NULL); |
914 | 910 | ||
915 | wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc); | 911 | free_irq(platform_get_irq_byname(pdev, "UV"), dcdc); |
916 | regulator_unregister(dcdc->regulator); | 912 | regulator_unregister(dcdc->regulator); |
917 | kfree(dcdc); | 913 | kfree(dcdc); |
918 | 914 | ||
diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c index 6c446cd6ad54..01f27c7f4236 100644 --- a/drivers/regulator/wm831x-isink.c +++ b/drivers/regulator/wm831x-isink.c | |||
@@ -198,9 +198,8 @@ static __devinit int wm831x_isink_probe(struct platform_device *pdev) | |||
198 | } | 198 | } |
199 | 199 | ||
200 | irq = platform_get_irq(pdev, 0); | 200 | irq = platform_get_irq(pdev, 0); |
201 | ret = wm831x_request_irq(wm831x, irq, wm831x_isink_irq, | 201 | ret = request_threaded_irq(irq, NULL, wm831x_isink_irq, |
202 | IRQF_TRIGGER_RISING, isink->name, | 202 | IRQF_TRIGGER_RISING, isink->name, isink); |
203 | isink); | ||
204 | if (ret != 0) { | 203 | if (ret != 0) { |
205 | dev_err(&pdev->dev, "Failed to request ISINK IRQ %d: %d\n", | 204 | dev_err(&pdev->dev, "Failed to request ISINK IRQ %d: %d\n", |
206 | irq, ret); | 205 | irq, ret); |
@@ -221,11 +220,10 @@ err: | |||
221 | static __devexit int wm831x_isink_remove(struct platform_device *pdev) | 220 | static __devexit int wm831x_isink_remove(struct platform_device *pdev) |
222 | { | 221 | { |
223 | struct wm831x_isink *isink = platform_get_drvdata(pdev); | 222 | struct wm831x_isink *isink = platform_get_drvdata(pdev); |
224 | struct wm831x *wm831x = isink->wm831x; | ||
225 | 223 | ||
226 | platform_set_drvdata(pdev, NULL); | 224 | platform_set_drvdata(pdev, NULL); |
227 | 225 | ||
228 | wm831x_free_irq(wm831x, platform_get_irq(pdev, 0), isink); | 226 | free_irq(platform_get_irq(pdev, 0), isink); |
229 | 227 | ||
230 | regulator_unregister(isink->regulator); | 228 | regulator_unregister(isink->regulator); |
231 | kfree(isink); | 229 | kfree(isink); |
diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index c94fc5b7cd5b..2220cf8defb1 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c | |||
@@ -354,9 +354,9 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev) | |||
354 | } | 354 | } |
355 | 355 | ||
356 | irq = platform_get_irq_byname(pdev, "UV"); | 356 | irq = platform_get_irq_byname(pdev, "UV"); |
357 | ret = wm831x_request_irq(wm831x, irq, wm831x_ldo_uv_irq, | 357 | ret = request_threaded_irq(irq, NULL, wm831x_ldo_uv_irq, |
358 | IRQF_TRIGGER_RISING, ldo->name, | 358 | IRQF_TRIGGER_RISING, ldo->name, |
359 | ldo); | 359 | ldo); |
360 | if (ret != 0) { | 360 | if (ret != 0) { |
361 | dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", | 361 | dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", |
362 | irq, ret); | 362 | irq, ret); |
@@ -377,11 +377,10 @@ err: | |||
377 | static __devexit int wm831x_gp_ldo_remove(struct platform_device *pdev) | 377 | static __devexit int wm831x_gp_ldo_remove(struct platform_device *pdev) |
378 | { | 378 | { |
379 | struct wm831x_ldo *ldo = platform_get_drvdata(pdev); | 379 | struct wm831x_ldo *ldo = platform_get_drvdata(pdev); |
380 | struct wm831x *wm831x = ldo->wm831x; | ||
381 | 380 | ||
382 | platform_set_drvdata(pdev, NULL); | 381 | platform_set_drvdata(pdev, NULL); |
383 | 382 | ||
384 | wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), ldo); | 383 | free_irq(platform_get_irq_byname(pdev, "UV"), ldo); |
385 | regulator_unregister(ldo->regulator); | 384 | regulator_unregister(ldo->regulator); |
386 | kfree(ldo); | 385 | kfree(ldo); |
387 | 386 | ||
@@ -619,9 +618,8 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev) | |||
619 | } | 618 | } |
620 | 619 | ||
621 | irq = platform_get_irq_byname(pdev, "UV"); | 620 | irq = platform_get_irq_byname(pdev, "UV"); |
622 | ret = wm831x_request_irq(wm831x, irq, wm831x_ldo_uv_irq, | 621 | ret = request_threaded_irq(irq, NULL, wm831x_ldo_uv_irq, |
623 | IRQF_TRIGGER_RISING, ldo->name, | 622 | IRQF_TRIGGER_RISING, ldo->name, ldo); |
624 | ldo); | ||
625 | if (ret != 0) { | 623 | if (ret != 0) { |
626 | dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", | 624 | dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", |
627 | irq, ret); | 625 | irq, ret); |
@@ -642,9 +640,8 @@ err: | |||
642 | static __devexit int wm831x_aldo_remove(struct platform_device *pdev) | 640 | static __devexit int wm831x_aldo_remove(struct platform_device *pdev) |
643 | { | 641 | { |
644 | struct wm831x_ldo *ldo = platform_get_drvdata(pdev); | 642 | struct wm831x_ldo *ldo = platform_get_drvdata(pdev); |
645 | struct wm831x *wm831x = ldo->wm831x; | ||
646 | 643 | ||
647 | wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), ldo); | 644 | free_irq(platform_get_irq_byname(pdev, "UV"), ldo); |
648 | regulator_unregister(ldo->regulator); | 645 | regulator_unregister(ldo->regulator); |
649 | kfree(ldo); | 646 | kfree(ldo); |
650 | 647 | ||
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 379d8592bc6e..459f2cbe80fc 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -3982,8 +3982,10 @@ out_err: | |||
3982 | } | 3982 | } |
3983 | 3983 | ||
3984 | static struct ccw_driver dasd_eckd_driver = { | 3984 | static struct ccw_driver dasd_eckd_driver = { |
3985 | .name = "dasd-eckd", | 3985 | .driver = { |
3986 | .owner = THIS_MODULE, | 3986 | .name = "dasd-eckd", |
3987 | .owner = THIS_MODULE, | ||
3988 | }, | ||
3987 | .ids = dasd_eckd_ids, | 3989 | .ids = dasd_eckd_ids, |
3988 | .probe = dasd_eckd_probe, | 3990 | .probe = dasd_eckd_probe, |
3989 | .remove = dasd_generic_remove, | 3991 | .remove = dasd_generic_remove, |
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index be89b3a893da..4b71b1164868 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c | |||
@@ -65,8 +65,10 @@ dasd_fba_set_online(struct ccw_device *cdev) | |||
65 | } | 65 | } |
66 | 66 | ||
67 | static struct ccw_driver dasd_fba_driver = { | 67 | static struct ccw_driver dasd_fba_driver = { |
68 | .name = "dasd-fba", | 68 | .driver = { |
69 | .owner = THIS_MODULE, | 69 | .name = "dasd-fba", |
70 | .owner = THIS_MODULE, | ||
71 | }, | ||
70 | .ids = dasd_fba_ids, | 72 | .ids = dasd_fba_ids, |
71 | .probe = dasd_fba_probe, | 73 | .probe = dasd_fba_probe, |
72 | .remove = dasd_generic_remove, | 74 | .remove = dasd_generic_remove, |
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 3fb4335d491d..694464c65fcd 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c | |||
@@ -764,8 +764,10 @@ static struct ccw_device_id raw3215_id[] = { | |||
764 | }; | 764 | }; |
765 | 765 | ||
766 | static struct ccw_driver raw3215_ccw_driver = { | 766 | static struct ccw_driver raw3215_ccw_driver = { |
767 | .name = "3215", | 767 | .driver = { |
768 | .owner = THIS_MODULE, | 768 | .name = "3215", |
769 | .owner = THIS_MODULE, | ||
770 | }, | ||
769 | .ids = raw3215_id, | 771 | .ids = raw3215_id, |
770 | .probe = &raw3215_probe, | 772 | .probe = &raw3215_probe, |
771 | .remove = &raw3215_remove, | 773 | .remove = &raw3215_remove, |
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 96ba2fd1c8ad..4c023761946f 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c | |||
@@ -1388,8 +1388,10 @@ static struct ccw_device_id raw3270_id[] = { | |||
1388 | }; | 1388 | }; |
1389 | 1389 | ||
1390 | static struct ccw_driver raw3270_ccw_driver = { | 1390 | static struct ccw_driver raw3270_ccw_driver = { |
1391 | .name = "3270", | 1391 | .driver = { |
1392 | .owner = THIS_MODULE, | 1392 | .name = "3270", |
1393 | .owner = THIS_MODULE, | ||
1394 | }, | ||
1393 | .ids = raw3270_id, | 1395 | .ids = raw3270_id, |
1394 | .probe = &raw3270_probe, | 1396 | .probe = &raw3270_probe, |
1395 | .remove = &raw3270_remove, | 1397 | .remove = &raw3270_remove, |
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index c26511171ffe..9eff2df70ddb 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c | |||
@@ -1320,8 +1320,10 @@ tape_34xx_online(struct ccw_device *cdev) | |||
1320 | } | 1320 | } |
1321 | 1321 | ||
1322 | static struct ccw_driver tape_34xx_driver = { | 1322 | static struct ccw_driver tape_34xx_driver = { |
1323 | .name = "tape_34xx", | 1323 | .driver = { |
1324 | .owner = THIS_MODULE, | 1324 | .name = "tape_34xx", |
1325 | .owner = THIS_MODULE, | ||
1326 | }, | ||
1325 | .ids = tape_34xx_ids, | 1327 | .ids = tape_34xx_ids, |
1326 | .probe = tape_generic_probe, | 1328 | .probe = tape_generic_probe, |
1327 | .remove = tape_generic_remove, | 1329 | .remove = tape_generic_remove, |
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index de2e99e0a71b..b98dcbd16711 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c | |||
@@ -1761,8 +1761,10 @@ tape_3590_online(struct ccw_device *cdev) | |||
1761 | } | 1761 | } |
1762 | 1762 | ||
1763 | static struct ccw_driver tape_3590_driver = { | 1763 | static struct ccw_driver tape_3590_driver = { |
1764 | .name = "tape_3590", | 1764 | .driver = { |
1765 | .owner = THIS_MODULE, | 1765 | .name = "tape_3590", |
1766 | .owner = THIS_MODULE, | ||
1767 | }, | ||
1766 | .ids = tape_3590_ids, | 1768 | .ids = tape_3590_ids, |
1767 | .probe = tape_generic_probe, | 1769 | .probe = tape_generic_probe, |
1768 | .remove = tape_generic_remove, | 1770 | .remove = tape_generic_remove, |
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index caef1757341d..f6b00c3df425 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c | |||
@@ -64,8 +64,10 @@ static int ur_set_offline(struct ccw_device *cdev); | |||
64 | static int ur_pm_suspend(struct ccw_device *cdev); | 64 | static int ur_pm_suspend(struct ccw_device *cdev); |
65 | 65 | ||
66 | static struct ccw_driver ur_driver = { | 66 | static struct ccw_driver ur_driver = { |
67 | .name = "vmur", | 67 | .driver = { |
68 | .owner = THIS_MODULE, | 68 | .name = "vmur", |
69 | .owner = THIS_MODULE, | ||
70 | }, | ||
69 | .ids = ur_ids, | 71 | .ids = ur_ids, |
70 | .probe = ur_probe, | 72 | .probe = ur_probe, |
71 | .remove = ur_remove, | 73 | .remove = ur_remove, |
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 2864581d8ecb..5c567414c4bb 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c | |||
@@ -428,7 +428,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const | |||
428 | gdev = to_ccwgroupdev(dev); | 428 | gdev = to_ccwgroupdev(dev); |
429 | gdrv = to_ccwgroupdrv(dev->driver); | 429 | gdrv = to_ccwgroupdrv(dev->driver); |
430 | 430 | ||
431 | if (!try_module_get(gdrv->owner)) | 431 | if (!try_module_get(gdrv->driver.owner)) |
432 | return -EINVAL; | 432 | return -EINVAL; |
433 | 433 | ||
434 | ret = strict_strtoul(buf, 0, &value); | 434 | ret = strict_strtoul(buf, 0, &value); |
@@ -442,7 +442,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const | |||
442 | else | 442 | else |
443 | ret = -EINVAL; | 443 | ret = -EINVAL; |
444 | out: | 444 | out: |
445 | module_put(gdrv->owner); | 445 | module_put(gdrv->driver.owner); |
446 | return (ret == 0) ? count : ret; | 446 | return (ret == 0) ? count : ret; |
447 | } | 447 | } |
448 | 448 | ||
@@ -616,8 +616,6 @@ int ccwgroup_driver_register(struct ccwgroup_driver *cdriver) | |||
616 | { | 616 | { |
617 | /* register our new driver with the core */ | 617 | /* register our new driver with the core */ |
618 | cdriver->driver.bus = &ccwgroup_bus_type; | 618 | cdriver->driver.bus = &ccwgroup_bus_type; |
619 | cdriver->driver.name = cdriver->name; | ||
620 | cdriver->driver.owner = cdriver->owner; | ||
621 | 619 | ||
622 | return driver_register(&cdriver->driver); | 620 | return driver_register(&cdriver->driver); |
623 | } | 621 | } |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index e50b12163afe..df14c51f6532 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -127,7 +127,7 @@ static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
127 | return ret; | 127 | return ret; |
128 | } | 128 | } |
129 | 129 | ||
130 | struct bus_type ccw_bus_type; | 130 | static struct bus_type ccw_bus_type; |
131 | 131 | ||
132 | static void io_subchannel_irq(struct subchannel *); | 132 | static void io_subchannel_irq(struct subchannel *); |
133 | static int io_subchannel_probe(struct subchannel *); | 133 | static int io_subchannel_probe(struct subchannel *); |
@@ -547,7 +547,7 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, | |||
547 | if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0) | 547 | if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0) |
548 | return -EAGAIN; | 548 | return -EAGAIN; |
549 | 549 | ||
550 | if (cdev->drv && !try_module_get(cdev->drv->owner)) { | 550 | if (cdev->drv && !try_module_get(cdev->drv->driver.owner)) { |
551 | atomic_set(&cdev->private->onoff, 0); | 551 | atomic_set(&cdev->private->onoff, 0); |
552 | return -EINVAL; | 552 | return -EINVAL; |
553 | } | 553 | } |
@@ -573,7 +573,7 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, | |||
573 | } | 573 | } |
574 | out: | 574 | out: |
575 | if (cdev->drv) | 575 | if (cdev->drv) |
576 | module_put(cdev->drv->owner); | 576 | module_put(cdev->drv->driver.owner); |
577 | atomic_set(&cdev->private->onoff, 0); | 577 | atomic_set(&cdev->private->onoff, 0); |
578 | return (ret < 0) ? ret : count; | 578 | return (ret < 0) ? ret : count; |
579 | } | 579 | } |
@@ -1970,7 +1970,7 @@ static const struct dev_pm_ops ccw_pm_ops = { | |||
1970 | .restore = ccw_device_pm_restore, | 1970 | .restore = ccw_device_pm_restore, |
1971 | }; | 1971 | }; |
1972 | 1972 | ||
1973 | struct bus_type ccw_bus_type = { | 1973 | static struct bus_type ccw_bus_type = { |
1974 | .name = "ccw", | 1974 | .name = "ccw", |
1975 | .match = ccw_bus_match, | 1975 | .match = ccw_bus_match, |
1976 | .uevent = ccw_uevent, | 1976 | .uevent = ccw_uevent, |
@@ -1993,8 +1993,6 @@ int ccw_driver_register(struct ccw_driver *cdriver) | |||
1993 | struct device_driver *drv = &cdriver->driver; | 1993 | struct device_driver *drv = &cdriver->driver; |
1994 | 1994 | ||
1995 | drv->bus = &ccw_bus_type; | 1995 | drv->bus = &ccw_bus_type; |
1996 | drv->name = cdriver->name; | ||
1997 | drv->owner = cdriver->owner; | ||
1998 | 1996 | ||
1999 | return driver_register(drv); | 1997 | return driver_register(drv); |
2000 | } | 1998 | } |
@@ -2112,5 +2110,4 @@ EXPORT_SYMBOL(ccw_device_set_offline); | |||
2112 | EXPORT_SYMBOL(ccw_driver_register); | 2110 | EXPORT_SYMBOL(ccw_driver_register); |
2113 | EXPORT_SYMBOL(ccw_driver_unregister); | 2111 | EXPORT_SYMBOL(ccw_driver_unregister); |
2114 | EXPORT_SYMBOL(get_ccwdev_by_busid); | 2112 | EXPORT_SYMBOL(get_ccwdev_by_busid); |
2115 | EXPORT_SYMBOL(ccw_bus_type); | ||
2116 | EXPORT_SYMBOL_GPL(ccw_device_get_subchannel_id); | 2113 | EXPORT_SYMBOL_GPL(ccw_device_get_subchannel_id); |
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 379de2d1ec49..7e297c7bb5ff 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h | |||
@@ -133,7 +133,6 @@ void ccw_device_set_notoper(struct ccw_device *cdev); | |||
133 | /* qdio needs this. */ | 133 | /* qdio needs this. */ |
134 | void ccw_device_set_timeout(struct ccw_device *, int); | 134 | void ccw_device_set_timeout(struct ccw_device *, int); |
135 | extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *); | 135 | extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *); |
136 | extern struct bus_type ccw_bus_type; | ||
137 | 136 | ||
138 | /* Channel measurement facility related */ | 137 | /* Channel measurement facility related */ |
139 | void retry_set_schib(struct ccw_device *cdev); | 138 | void retry_set_schib(struct ccw_device *cdev); |
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 5640c89cd9de..479c665e9e7c 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
@@ -1508,7 +1508,8 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, | |||
1508 | 1508 | ||
1509 | if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE) | 1509 | if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE) |
1510 | return -EBUSY; | 1510 | return -EBUSY; |
1511 | 1511 | if (!count) | |
1512 | return 0; | ||
1512 | if (callflags & QDIO_FLAG_SYNC_INPUT) | 1513 | if (callflags & QDIO_FLAG_SYNC_INPUT) |
1513 | return handle_inbound(irq_ptr->input_qs[q_nr], | 1514 | return handle_inbound(irq_ptr->input_qs[q_nr], |
1514 | callflags, bufnr, count); | 1515 | callflags, bufnr, count); |
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index ce3a5c13ce0b..9feb62febb3d 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c | |||
@@ -264,8 +264,10 @@ static struct device *claw_root_dev; | |||
264 | /* ccwgroup table */ | 264 | /* ccwgroup table */ |
265 | 265 | ||
266 | static struct ccwgroup_driver claw_group_driver = { | 266 | static struct ccwgroup_driver claw_group_driver = { |
267 | .owner = THIS_MODULE, | 267 | .driver = { |
268 | .name = "claw", | 268 | .owner = THIS_MODULE, |
269 | .name = "claw", | ||
270 | }, | ||
269 | .max_slaves = 2, | 271 | .max_slaves = 2, |
270 | .driver_id = 0xC3D3C1E6, | 272 | .driver_id = 0xC3D3C1E6, |
271 | .probe = claw_probe, | 273 | .probe = claw_probe, |
@@ -282,8 +284,10 @@ static struct ccw_device_id claw_ids[] = { | |||
282 | MODULE_DEVICE_TABLE(ccw, claw_ids); | 284 | MODULE_DEVICE_TABLE(ccw, claw_ids); |
283 | 285 | ||
284 | static struct ccw_driver claw_ccw_driver = { | 286 | static struct ccw_driver claw_ccw_driver = { |
285 | .owner = THIS_MODULE, | 287 | .driver = { |
286 | .name = "claw", | 288 | .owner = THIS_MODULE, |
289 | .name = "claw", | ||
290 | }, | ||
287 | .ids = claw_ids, | 291 | .ids = claw_ids, |
288 | .probe = ccwgroup_probe_ccwdev, | 292 | .probe = ccwgroup_probe_ccwdev, |
289 | .remove = ccwgroup_remove_ccwdev, | 293 | .remove = ccwgroup_remove_ccwdev, |
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 4c2845985927..c189296763a4 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c | |||
@@ -1764,16 +1764,20 @@ static struct ccw_device_id ctcm_ids[] = { | |||
1764 | MODULE_DEVICE_TABLE(ccw, ctcm_ids); | 1764 | MODULE_DEVICE_TABLE(ccw, ctcm_ids); |
1765 | 1765 | ||
1766 | static struct ccw_driver ctcm_ccw_driver = { | 1766 | static struct ccw_driver ctcm_ccw_driver = { |
1767 | .owner = THIS_MODULE, | 1767 | .driver = { |
1768 | .name = "ctcm", | 1768 | .owner = THIS_MODULE, |
1769 | .name = "ctcm", | ||
1770 | }, | ||
1769 | .ids = ctcm_ids, | 1771 | .ids = ctcm_ids, |
1770 | .probe = ccwgroup_probe_ccwdev, | 1772 | .probe = ccwgroup_probe_ccwdev, |
1771 | .remove = ccwgroup_remove_ccwdev, | 1773 | .remove = ccwgroup_remove_ccwdev, |
1772 | }; | 1774 | }; |
1773 | 1775 | ||
1774 | static struct ccwgroup_driver ctcm_group_driver = { | 1776 | static struct ccwgroup_driver ctcm_group_driver = { |
1775 | .owner = THIS_MODULE, | 1777 | .driver = { |
1776 | .name = CTC_DRIVER_NAME, | 1778 | .owner = THIS_MODULE, |
1779 | .name = CTC_DRIVER_NAME, | ||
1780 | }, | ||
1777 | .max_slaves = 2, | 1781 | .max_slaves = 2, |
1778 | .driver_id = 0xC3E3C3D4, /* CTCM */ | 1782 | .driver_id = 0xC3E3C3D4, /* CTCM */ |
1779 | .probe = ctcm_probe_device, | 1783 | .probe = ctcm_probe_device, |
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 30b2a820e670..7fbc4adbb6d5 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c | |||
@@ -2396,8 +2396,10 @@ static struct ccw_device_id lcs_ids[] = { | |||
2396 | MODULE_DEVICE_TABLE(ccw, lcs_ids); | 2396 | MODULE_DEVICE_TABLE(ccw, lcs_ids); |
2397 | 2397 | ||
2398 | static struct ccw_driver lcs_ccw_driver = { | 2398 | static struct ccw_driver lcs_ccw_driver = { |
2399 | .owner = THIS_MODULE, | 2399 | .driver = { |
2400 | .name = "lcs", | 2400 | .owner = THIS_MODULE, |
2401 | .name = "lcs", | ||
2402 | }, | ||
2401 | .ids = lcs_ids, | 2403 | .ids = lcs_ids, |
2402 | .probe = ccwgroup_probe_ccwdev, | 2404 | .probe = ccwgroup_probe_ccwdev, |
2403 | .remove = ccwgroup_remove_ccwdev, | 2405 | .remove = ccwgroup_remove_ccwdev, |
@@ -2407,8 +2409,10 @@ static struct ccw_driver lcs_ccw_driver = { | |||
2407 | * LCS ccwgroup driver registration | 2409 | * LCS ccwgroup driver registration |
2408 | */ | 2410 | */ |
2409 | static struct ccwgroup_driver lcs_group_driver = { | 2411 | static struct ccwgroup_driver lcs_group_driver = { |
2410 | .owner = THIS_MODULE, | 2412 | .driver = { |
2411 | .name = "lcs", | 2413 | .owner = THIS_MODULE, |
2414 | .name = "lcs", | ||
2415 | }, | ||
2412 | .max_slaves = 2, | 2416 | .max_slaves = 2, |
2413 | .driver_id = 0xD3C3E2, | 2417 | .driver_id = 0xD3C3E2, |
2414 | .probe = lcs_probe_device, | 2418 | .probe = lcs_probe_device, |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 25eef304bd47..10a3a3b4dd3e 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -3902,7 +3902,9 @@ static struct ccw_device_id qeth_ids[] = { | |||
3902 | MODULE_DEVICE_TABLE(ccw, qeth_ids); | 3902 | MODULE_DEVICE_TABLE(ccw, qeth_ids); |
3903 | 3903 | ||
3904 | static struct ccw_driver qeth_ccw_driver = { | 3904 | static struct ccw_driver qeth_ccw_driver = { |
3905 | .name = "qeth", | 3905 | .driver = { |
3906 | .name = "qeth", | ||
3907 | }, | ||
3906 | .ids = qeth_ids, | 3908 | .ids = qeth_ids, |
3907 | .probe = ccwgroup_probe_ccwdev, | 3909 | .probe = ccwgroup_probe_ccwdev, |
3908 | .remove = ccwgroup_remove_ccwdev, | 3910 | .remove = ccwgroup_remove_ccwdev, |
@@ -4428,8 +4430,10 @@ static int qeth_core_restore(struct ccwgroup_device *gdev) | |||
4428 | } | 4430 | } |
4429 | 4431 | ||
4430 | static struct ccwgroup_driver qeth_core_ccwgroup_driver = { | 4432 | static struct ccwgroup_driver qeth_core_ccwgroup_driver = { |
4431 | .owner = THIS_MODULE, | 4433 | .driver = { |
4432 | .name = "qeth", | 4434 | .owner = THIS_MODULE, |
4435 | .name = "qeth", | ||
4436 | }, | ||
4433 | .driver_id = 0xD8C5E3C8, | 4437 | .driver_id = 0xD8C5E3C8, |
4434 | .probe = qeth_core_probe_device, | 4438 | .probe = qeth_core_probe_device, |
4435 | .remove = qeth_core_remove_device, | 4439 | .remove = qeth_core_remove_device, |
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 4f7852dd30c7..e8b7cee62046 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c | |||
@@ -251,8 +251,10 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev) | |||
251 | } | 251 | } |
252 | 252 | ||
253 | struct ccw_driver zfcp_ccw_driver = { | 253 | struct ccw_driver zfcp_ccw_driver = { |
254 | .owner = THIS_MODULE, | 254 | .driver = { |
255 | .name = "zfcp", | 255 | .owner = THIS_MODULE, |
256 | .name = "zfcp", | ||
257 | }, | ||
256 | .ids = zfcp_ccw_device_id, | 258 | .ids = zfcp_ccw_device_id, |
257 | .probe = zfcp_ccw_probe, | 259 | .probe = zfcp_ccw_probe, |
258 | .remove = zfcp_ccw_remove, | 260 | .remove = zfcp_ccw_remove, |
diff --git a/drivers/scsi/aacraid/Makefile b/drivers/scsi/aacraid/Makefile index 92df4d6b6147..1bd9fd18f7f3 100644 --- a/drivers/scsi/aacraid/Makefile +++ b/drivers/scsi/aacraid/Makefile | |||
@@ -3,6 +3,6 @@ | |||
3 | obj-$(CONFIG_SCSI_AACRAID) := aacraid.o | 3 | obj-$(CONFIG_SCSI_AACRAID) := aacraid.o |
4 | 4 | ||
5 | aacraid-objs := linit.o aachba.o commctrl.o comminit.o commsup.o \ | 5 | aacraid-objs := linit.o aachba.o commctrl.o comminit.o commsup.o \ |
6 | dpcsup.o rx.o sa.o rkt.o nark.o | 6 | dpcsup.o rx.o sa.o rkt.o nark.o src.o |
7 | 7 | ||
8 | ccflags-y := -Idrivers/scsi | 8 | ccflags-y := -Idrivers/scsi |
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 7df2dd1d2c6f..118ce83a737c 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c | |||
@@ -5,7 +5,8 @@ | |||
5 | * based on the old aacraid driver that is.. | 5 | * based on the old aacraid driver that is.. |
6 | * Adaptec aacraid device driver for Linux. | 6 | * Adaptec aacraid device driver for Linux. |
7 | * | 7 | * |
8 | * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) | 8 | * Copyright (c) 2000-2010 Adaptec, Inc. |
9 | * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) | ||
9 | * | 10 | * |
10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
@@ -1486,7 +1487,9 @@ int aac_get_adapter_info(struct aac_dev* dev) | |||
1486 | dev->a_ops.adapter_write = aac_write_block; | 1487 | dev->a_ops.adapter_write = aac_write_block; |
1487 | } | 1488 | } |
1488 | dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT; | 1489 | dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT; |
1489 | if(!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) { | 1490 | if (dev->adapter_info.options & AAC_OPT_NEW_COMM_TYPE1) |
1491 | dev->adapter_info.options |= AAC_OPT_NEW_COMM; | ||
1492 | if (!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) { | ||
1490 | /* | 1493 | /* |
1491 | * Worst case size that could cause sg overflow when | 1494 | * Worst case size that could cause sg overflow when |
1492 | * we break up SG elements that are larger than 64KB. | 1495 | * we break up SG elements that are larger than 64KB. |
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 4dbcc055ac78..29ab00016b78 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h | |||
@@ -12,7 +12,7 @@ | |||
12 | *----------------------------------------------------------------------------*/ | 12 | *----------------------------------------------------------------------------*/ |
13 | 13 | ||
14 | #ifndef AAC_DRIVER_BUILD | 14 | #ifndef AAC_DRIVER_BUILD |
15 | # define AAC_DRIVER_BUILD 26400 | 15 | # define AAC_DRIVER_BUILD 28000 |
16 | # define AAC_DRIVER_BRANCH "-ms" | 16 | # define AAC_DRIVER_BRANCH "-ms" |
17 | #endif | 17 | #endif |
18 | #define MAXIMUM_NUM_CONTAINERS 32 | 18 | #define MAXIMUM_NUM_CONTAINERS 32 |
@@ -277,6 +277,16 @@ enum aac_queue_types { | |||
277 | 277 | ||
278 | #define FsaNormal 1 | 278 | #define FsaNormal 1 |
279 | 279 | ||
280 | /* transport FIB header (PMC) */ | ||
281 | struct aac_fib_xporthdr { | ||
282 | u64 HostAddress; /* FIB host address w/o xport header */ | ||
283 | u32 Size; /* FIB size excluding xport header */ | ||
284 | u32 Handle; /* driver handle to reference the FIB */ | ||
285 | u64 Reserved[2]; | ||
286 | }; | ||
287 | |||
288 | #define ALIGN32 32 | ||
289 | |||
280 | /* | 290 | /* |
281 | * Define the FIB. The FIB is the where all the requested data and | 291 | * Define the FIB. The FIB is the where all the requested data and |
282 | * command information are put to the application on the FSA adapter. | 292 | * command information are put to the application on the FSA adapter. |
@@ -394,7 +404,9 @@ enum fib_xfer_state { | |||
394 | AdapterMicroFib = (1<<17), | 404 | AdapterMicroFib = (1<<17), |
395 | BIOSFibPath = (1<<18), | 405 | BIOSFibPath = (1<<18), |
396 | FastResponseCapable = (1<<19), | 406 | FastResponseCapable = (1<<19), |
397 | ApiFib = (1<<20) // Its an API Fib. | 407 | ApiFib = (1<<20), /* Its an API Fib */ |
408 | /* PMC NEW COMM: There is no more AIF data pending */ | ||
409 | NoMoreAifDataAvailable = (1<<21) | ||
398 | }; | 410 | }; |
399 | 411 | ||
400 | /* | 412 | /* |
@@ -404,6 +416,7 @@ enum fib_xfer_state { | |||
404 | 416 | ||
405 | #define ADAPTER_INIT_STRUCT_REVISION 3 | 417 | #define ADAPTER_INIT_STRUCT_REVISION 3 |
406 | #define ADAPTER_INIT_STRUCT_REVISION_4 4 // rocket science | 418 | #define ADAPTER_INIT_STRUCT_REVISION_4 4 // rocket science |
419 | #define ADAPTER_INIT_STRUCT_REVISION_6 6 /* PMC src */ | ||
407 | 420 | ||
408 | struct aac_init | 421 | struct aac_init |
409 | { | 422 | { |
@@ -428,9 +441,15 @@ struct aac_init | |||
428 | #define INITFLAGS_NEW_COMM_SUPPORTED 0x00000001 | 441 | #define INITFLAGS_NEW_COMM_SUPPORTED 0x00000001 |
429 | #define INITFLAGS_DRIVER_USES_UTC_TIME 0x00000010 | 442 | #define INITFLAGS_DRIVER_USES_UTC_TIME 0x00000010 |
430 | #define INITFLAGS_DRIVER_SUPPORTS_PM 0x00000020 | 443 | #define INITFLAGS_DRIVER_SUPPORTS_PM 0x00000020 |
444 | #define INITFLAGS_NEW_COMM_TYPE1_SUPPORTED 0x00000041 | ||
431 | __le32 MaxIoCommands; /* max outstanding commands */ | 445 | __le32 MaxIoCommands; /* max outstanding commands */ |
432 | __le32 MaxIoSize; /* largest I/O command */ | 446 | __le32 MaxIoSize; /* largest I/O command */ |
433 | __le32 MaxFibSize; /* largest FIB to adapter */ | 447 | __le32 MaxFibSize; /* largest FIB to adapter */ |
448 | /* ADAPTER_INIT_STRUCT_REVISION_5 begins here */ | ||
449 | __le32 MaxNumAif; /* max number of aif */ | ||
450 | /* ADAPTER_INIT_STRUCT_REVISION_6 begins here */ | ||
451 | __le32 HostRRQ_AddrLow; | ||
452 | __le32 HostRRQ_AddrHigh; /* Host RRQ (response queue) for SRC */ | ||
434 | }; | 453 | }; |
435 | 454 | ||
436 | enum aac_log_level { | 455 | enum aac_log_level { |
@@ -685,7 +704,7 @@ struct rx_inbound { | |||
685 | #define OutboundDoorbellReg MUnit.ODR | 704 | #define OutboundDoorbellReg MUnit.ODR |
686 | 705 | ||
687 | struct rx_registers { | 706 | struct rx_registers { |
688 | struct rx_mu_registers MUnit; /* 1300h - 1344h */ | 707 | struct rx_mu_registers MUnit; /* 1300h - 1347h */ |
689 | __le32 reserved1[2]; /* 1348h - 134ch */ | 708 | __le32 reserved1[2]; /* 1348h - 134ch */ |
690 | struct rx_inbound IndexRegs; | 709 | struct rx_inbound IndexRegs; |
691 | }; | 710 | }; |
@@ -703,7 +722,7 @@ struct rx_registers { | |||
703 | #define rkt_inbound rx_inbound | 722 | #define rkt_inbound rx_inbound |
704 | 723 | ||
705 | struct rkt_registers { | 724 | struct rkt_registers { |
706 | struct rkt_mu_registers MUnit; /* 1300h - 1344h */ | 725 | struct rkt_mu_registers MUnit; /* 1300h - 1347h */ |
707 | __le32 reserved1[1006]; /* 1348h - 22fch */ | 726 | __le32 reserved1[1006]; /* 1348h - 22fch */ |
708 | struct rkt_inbound IndexRegs; /* 2300h - */ | 727 | struct rkt_inbound IndexRegs; /* 2300h - */ |
709 | }; | 728 | }; |
@@ -713,6 +732,44 @@ struct rkt_registers { | |||
713 | #define rkt_writeb(AEP, CSR, value) writeb(value, &((AEP)->regs.rkt->CSR)) | 732 | #define rkt_writeb(AEP, CSR, value) writeb(value, &((AEP)->regs.rkt->CSR)) |
714 | #define rkt_writel(AEP, CSR, value) writel(value, &((AEP)->regs.rkt->CSR)) | 733 | #define rkt_writel(AEP, CSR, value) writel(value, &((AEP)->regs.rkt->CSR)) |
715 | 734 | ||
735 | /* | ||
736 | * PMC SRC message unit registers | ||
737 | */ | ||
738 | |||
739 | #define src_inbound rx_inbound | ||
740 | |||
741 | struct src_mu_registers { | ||
742 | /* PCI*| Name */ | ||
743 | __le32 reserved0[8]; /* 00h | Reserved */ | ||
744 | __le32 IDR; /* 20h | Inbound Doorbell Register */ | ||
745 | __le32 IISR; /* 24h | Inbound Int. Status Register */ | ||
746 | __le32 reserved1[3]; /* 28h | Reserved */ | ||
747 | __le32 OIMR; /* 34h | Outbound Int. Mask Register */ | ||
748 | __le32 reserved2[25]; /* 38h | Reserved */ | ||
749 | __le32 ODR_R; /* 9ch | Outbound Doorbell Read */ | ||
750 | __le32 ODR_C; /* a0h | Outbound Doorbell Clear */ | ||
751 | __le32 reserved3[6]; /* a4h | Reserved */ | ||
752 | __le32 OMR; /* bch | Outbound Message Register */ | ||
753 | __le32 IQ_L; /* c0h | Inbound Queue (Low address) */ | ||
754 | __le32 IQ_H; /* c4h | Inbound Queue (High address) */ | ||
755 | }; | ||
756 | |||
757 | struct src_registers { | ||
758 | struct src_mu_registers MUnit; /* 00h - c7h */ | ||
759 | __le32 reserved1[130790]; /* c8h - 7fc5fh */ | ||
760 | struct src_inbound IndexRegs; /* 7fc60h */ | ||
761 | }; | ||
762 | |||
763 | #define src_readb(AEP, CSR) readb(&((AEP)->regs.src.bar0->CSR)) | ||
764 | #define src_readl(AEP, CSR) readl(&((AEP)->regs.src.bar0->CSR)) | ||
765 | #define src_writeb(AEP, CSR, value) writeb(value, \ | ||
766 | &((AEP)->regs.src.bar0->CSR)) | ||
767 | #define src_writel(AEP, CSR, value) writel(value, \ | ||
768 | &((AEP)->regs.src.bar0->CSR)) | ||
769 | |||
770 | #define SRC_ODR_SHIFT 12 | ||
771 | #define SRC_IDR_SHIFT 9 | ||
772 | |||
716 | typedef void (*fib_callback)(void *ctxt, struct fib *fibctx); | 773 | typedef void (*fib_callback)(void *ctxt, struct fib *fibctx); |
717 | 774 | ||
718 | struct aac_fib_context { | 775 | struct aac_fib_context { |
@@ -879,6 +936,7 @@ struct aac_supplement_adapter_info | |||
879 | #define AAC_OPTION_MU_RESET cpu_to_le32(0x00000001) | 936 | #define AAC_OPTION_MU_RESET cpu_to_le32(0x00000001) |
880 | #define AAC_OPTION_IGNORE_RESET cpu_to_le32(0x00000002) | 937 | #define AAC_OPTION_IGNORE_RESET cpu_to_le32(0x00000002) |
881 | #define AAC_OPTION_POWER_MANAGEMENT cpu_to_le32(0x00000004) | 938 | #define AAC_OPTION_POWER_MANAGEMENT cpu_to_le32(0x00000004) |
939 | #define AAC_OPTION_DOORBELL_RESET cpu_to_le32(0x00004000) | ||
882 | #define AAC_SIS_VERSION_V3 3 | 940 | #define AAC_SIS_VERSION_V3 3 |
883 | #define AAC_SIS_SLOT_UNKNOWN 0xFF | 941 | #define AAC_SIS_SLOT_UNKNOWN 0xFF |
884 | 942 | ||
@@ -940,6 +998,7 @@ struct aac_bus_info_response { | |||
940 | #define AAC_OPT_SUPPLEMENT_ADAPTER_INFO cpu_to_le32(1<<16) | 998 | #define AAC_OPT_SUPPLEMENT_ADAPTER_INFO cpu_to_le32(1<<16) |
941 | #define AAC_OPT_NEW_COMM cpu_to_le32(1<<17) | 999 | #define AAC_OPT_NEW_COMM cpu_to_le32(1<<17) |
942 | #define AAC_OPT_NEW_COMM_64 cpu_to_le32(1<<18) | 1000 | #define AAC_OPT_NEW_COMM_64 cpu_to_le32(1<<18) |
1001 | #define AAC_OPT_NEW_COMM_TYPE1 cpu_to_le32(1<<28) | ||
943 | 1002 | ||
944 | struct aac_dev | 1003 | struct aac_dev |
945 | { | 1004 | { |
@@ -952,6 +1011,7 @@ struct aac_dev | |||
952 | */ | 1011 | */ |
953 | unsigned max_fib_size; | 1012 | unsigned max_fib_size; |
954 | unsigned sg_tablesize; | 1013 | unsigned sg_tablesize; |
1014 | unsigned max_num_aif; | ||
955 | 1015 | ||
956 | /* | 1016 | /* |
957 | * Map for 128 fib objects (64k) | 1017 | * Map for 128 fib objects (64k) |
@@ -980,10 +1040,21 @@ struct aac_dev | |||
980 | struct adapter_ops a_ops; | 1040 | struct adapter_ops a_ops; |
981 | unsigned long fsrev; /* Main driver's revision number */ | 1041 | unsigned long fsrev; /* Main driver's revision number */ |
982 | 1042 | ||
983 | unsigned base_size; /* Size of mapped in region */ | 1043 | unsigned long dbg_base; /* address of UART |
1044 | * debug buffer */ | ||
1045 | |||
1046 | unsigned base_size, dbg_size; /* Size of | ||
1047 | * mapped in region */ | ||
1048 | |||
984 | struct aac_init *init; /* Holds initialization info to communicate with adapter */ | 1049 | struct aac_init *init; /* Holds initialization info to communicate with adapter */ |
985 | dma_addr_t init_pa; /* Holds physical address of the init struct */ | 1050 | dma_addr_t init_pa; /* Holds physical address of the init struct */ |
986 | 1051 | ||
1052 | u32 *host_rrq; /* response queue | ||
1053 | * if AAC_COMM_MESSAGE_TYPE1 */ | ||
1054 | |||
1055 | dma_addr_t host_rrq_pa; /* phys. address */ | ||
1056 | u32 host_rrq_idx; /* index into rrq buffer */ | ||
1057 | |||
987 | struct pci_dev *pdev; /* Our PCI interface */ | 1058 | struct pci_dev *pdev; /* Our PCI interface */ |
988 | void * printfbuf; /* pointer to buffer used for printf's from the adapter */ | 1059 | void * printfbuf; /* pointer to buffer used for printf's from the adapter */ |
989 | void * comm_addr; /* Base address of Comm area */ | 1060 | void * comm_addr; /* Base address of Comm area */ |
@@ -1003,14 +1074,20 @@ struct aac_dev | |||
1003 | */ | 1074 | */ |
1004 | #ifndef AAC_MIN_FOOTPRINT_SIZE | 1075 | #ifndef AAC_MIN_FOOTPRINT_SIZE |
1005 | # define AAC_MIN_FOOTPRINT_SIZE 8192 | 1076 | # define AAC_MIN_FOOTPRINT_SIZE 8192 |
1077 | # define AAC_MIN_SRC_BAR0_SIZE 0x400000 | ||
1078 | # define AAC_MIN_SRC_BAR1_SIZE 0x800 | ||
1006 | #endif | 1079 | #endif |
1007 | union | 1080 | union |
1008 | { | 1081 | { |
1009 | struct sa_registers __iomem *sa; | 1082 | struct sa_registers __iomem *sa; |
1010 | struct rx_registers __iomem *rx; | 1083 | struct rx_registers __iomem *rx; |
1011 | struct rkt_registers __iomem *rkt; | 1084 | struct rkt_registers __iomem *rkt; |
1085 | struct { | ||
1086 | struct src_registers __iomem *bar0; | ||
1087 | char __iomem *bar1; | ||
1088 | } src; | ||
1012 | } regs; | 1089 | } regs; |
1013 | volatile void __iomem *base; | 1090 | volatile void __iomem *base, *dbg_base_mapped; |
1014 | volatile struct rx_inbound __iomem *IndexRegs; | 1091 | volatile struct rx_inbound __iomem *IndexRegs; |
1015 | u32 OIMR; /* Mask Register Cache */ | 1092 | u32 OIMR; /* Mask Register Cache */ |
1016 | /* | 1093 | /* |
@@ -1031,9 +1108,8 @@ struct aac_dev | |||
1031 | u8 comm_interface; | 1108 | u8 comm_interface; |
1032 | # define AAC_COMM_PRODUCER 0 | 1109 | # define AAC_COMM_PRODUCER 0 |
1033 | # define AAC_COMM_MESSAGE 1 | 1110 | # define AAC_COMM_MESSAGE 1 |
1034 | /* macro side-effects BEWARE */ | 1111 | # define AAC_COMM_MESSAGE_TYPE1 3 |
1035 | # define raw_io_interface \ | 1112 | u8 raw_io_interface; |
1036 | init->InitStructRevision==cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4) | ||
1037 | u8 raw_io_64; | 1113 | u8 raw_io_64; |
1038 | u8 printf_enabled; | 1114 | u8 printf_enabled; |
1039 | u8 in_reset; | 1115 | u8 in_reset; |
@@ -1789,6 +1865,10 @@ extern struct aac_common aac_config; | |||
1789 | #define DoorBellAdapterNormCmdNotFull (1<<3) /* Adapter -> Host */ | 1865 | #define DoorBellAdapterNormCmdNotFull (1<<3) /* Adapter -> Host */ |
1790 | #define DoorBellAdapterNormRespNotFull (1<<4) /* Adapter -> Host */ | 1866 | #define DoorBellAdapterNormRespNotFull (1<<4) /* Adapter -> Host */ |
1791 | #define DoorBellPrintfReady (1<<5) /* Adapter -> Host */ | 1867 | #define DoorBellPrintfReady (1<<5) /* Adapter -> Host */ |
1868 | #define DoorBellAifPending (1<<6) /* Adapter -> Host */ | ||
1869 | |||
1870 | /* PMC specific outbound doorbell bits */ | ||
1871 | #define PmDoorBellResponseSent (1<<1) /* Adapter -> Host */ | ||
1792 | 1872 | ||
1793 | /* | 1873 | /* |
1794 | * For FIB communication, we need all of the following things | 1874 | * For FIB communication, we need all of the following things |
@@ -1831,6 +1911,9 @@ extern struct aac_common aac_config; | |||
1831 | #define AifReqAPIJobUpdate 109 /* Update a job report from the API */ | 1911 | #define AifReqAPIJobUpdate 109 /* Update a job report from the API */ |
1832 | #define AifReqAPIJobFinish 110 /* Finish a job from the API */ | 1912 | #define AifReqAPIJobFinish 110 /* Finish a job from the API */ |
1833 | 1913 | ||
1914 | /* PMC NEW COMM: Request the event data */ | ||
1915 | #define AifReqEvent 200 | ||
1916 | |||
1834 | /* | 1917 | /* |
1835 | * Adapter Initiated FIB command structures. Start with the adapter | 1918 | * Adapter Initiated FIB command structures. Start with the adapter |
1836 | * initiated FIBs that really come from the adapter, and get responded | 1919 | * initiated FIBs that really come from the adapter, and get responded |
@@ -1886,10 +1969,13 @@ int aac_rx_init(struct aac_dev *dev); | |||
1886 | int aac_rkt_init(struct aac_dev *dev); | 1969 | int aac_rkt_init(struct aac_dev *dev); |
1887 | int aac_nark_init(struct aac_dev *dev); | 1970 | int aac_nark_init(struct aac_dev *dev); |
1888 | int aac_sa_init(struct aac_dev *dev); | 1971 | int aac_sa_init(struct aac_dev *dev); |
1972 | int aac_src_init(struct aac_dev *dev); | ||
1889 | int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify); | 1973 | int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify); |
1890 | unsigned int aac_response_normal(struct aac_queue * q); | 1974 | unsigned int aac_response_normal(struct aac_queue * q); |
1891 | unsigned int aac_command_normal(struct aac_queue * q); | 1975 | unsigned int aac_command_normal(struct aac_queue * q); |
1892 | unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index); | 1976 | unsigned int aac_intr_normal(struct aac_dev *dev, u32 Index, |
1977 | int isAif, int isFastResponse, | ||
1978 | struct hw_fib *aif_fib); | ||
1893 | int aac_reset_adapter(struct aac_dev * dev, int forced); | 1979 | int aac_reset_adapter(struct aac_dev * dev, int forced); |
1894 | int aac_check_health(struct aac_dev * dev); | 1980 | int aac_check_health(struct aac_dev * dev); |
1895 | int aac_command_thread(void *data); | 1981 | int aac_command_thread(void *data); |
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 645ddd9d9b9e..8a0b33033177 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c | |||
@@ -5,7 +5,8 @@ | |||
5 | * based on the old aacraid driver that is.. | 5 | * based on the old aacraid driver that is.. |
6 | * Adaptec aacraid device driver for Linux. | 6 | * Adaptec aacraid device driver for Linux. |
7 | * | 7 | * |
8 | * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) | 8 | * Copyright (c) 2000-2010 Adaptec, Inc. |
9 | * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) | ||
9 | * | 10 | * |
10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index a7261486ccd4..7ac8fdb5577b 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c | |||
@@ -5,7 +5,8 @@ | |||
5 | * based on the old aacraid driver that is.. | 5 | * based on the old aacraid driver that is.. |
6 | * Adaptec aacraid device driver for Linux. | 6 | * Adaptec aacraid device driver for Linux. |
7 | * | 7 | * |
8 | * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) | 8 | * Copyright (c) 2000-2010 Adaptec, Inc. |
9 | * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) | ||
9 | * | 10 | * |
10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
@@ -52,12 +53,16 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co | |||
52 | unsigned long size, align; | 53 | unsigned long size, align; |
53 | const unsigned long fibsize = 4096; | 54 | const unsigned long fibsize = 4096; |
54 | const unsigned long printfbufsiz = 256; | 55 | const unsigned long printfbufsiz = 256; |
56 | unsigned long host_rrq_size = 0; | ||
55 | struct aac_init *init; | 57 | struct aac_init *init; |
56 | dma_addr_t phys; | 58 | dma_addr_t phys; |
57 | unsigned long aac_max_hostphysmempages; | 59 | unsigned long aac_max_hostphysmempages; |
58 | 60 | ||
59 | size = fibsize + sizeof(struct aac_init) + commsize + commalign + printfbufsiz; | 61 | if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) |
60 | 62 | host_rrq_size = (dev->scsi_host_ptr->can_queue | |
63 | + AAC_NUM_MGT_FIB) * sizeof(u32); | ||
64 | size = fibsize + sizeof(struct aac_init) + commsize + | ||
65 | commalign + printfbufsiz + host_rrq_size; | ||
61 | 66 | ||
62 | base = pci_alloc_consistent(dev->pdev, size, &phys); | 67 | base = pci_alloc_consistent(dev->pdev, size, &phys); |
63 | 68 | ||
@@ -70,8 +75,14 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co | |||
70 | dev->comm_phys = phys; | 75 | dev->comm_phys = phys; |
71 | dev->comm_size = size; | 76 | dev->comm_size = size; |
72 | 77 | ||
73 | dev->init = (struct aac_init *)(base + fibsize); | 78 | if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) { |
74 | dev->init_pa = phys + fibsize; | 79 | dev->host_rrq = (u32 *)(base + fibsize); |
80 | dev->host_rrq_pa = phys + fibsize; | ||
81 | memset(dev->host_rrq, 0, host_rrq_size); | ||
82 | } | ||
83 | |||
84 | dev->init = (struct aac_init *)(base + fibsize + host_rrq_size); | ||
85 | dev->init_pa = phys + fibsize + host_rrq_size; | ||
75 | 86 | ||
76 | init = dev->init; | 87 | init = dev->init; |
77 | 88 | ||
@@ -106,8 +117,13 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co | |||
106 | 117 | ||
107 | init->InitFlags = 0; | 118 | init->InitFlags = 0; |
108 | if (dev->comm_interface == AAC_COMM_MESSAGE) { | 119 | if (dev->comm_interface == AAC_COMM_MESSAGE) { |
109 | init->InitFlags = cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED); | 120 | init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED); |
110 | dprintk((KERN_WARNING"aacraid: New Comm Interface enabled\n")); | 121 | dprintk((KERN_WARNING"aacraid: New Comm Interface enabled\n")); |
122 | } else if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) { | ||
123 | init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_6); | ||
124 | init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_TYPE1_SUPPORTED); | ||
125 | dprintk((KERN_WARNING | ||
126 | "aacraid: New Comm Interface type1 enabled\n")); | ||
111 | } | 127 | } |
112 | init->InitFlags |= cpu_to_le32(INITFLAGS_DRIVER_USES_UTC_TIME | | 128 | init->InitFlags |= cpu_to_le32(INITFLAGS_DRIVER_USES_UTC_TIME | |
113 | INITFLAGS_DRIVER_SUPPORTS_PM); | 129 | INITFLAGS_DRIVER_SUPPORTS_PM); |
@@ -115,11 +131,18 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co | |||
115 | init->MaxIoSize = cpu_to_le32(dev->scsi_host_ptr->max_sectors << 9); | 131 | init->MaxIoSize = cpu_to_le32(dev->scsi_host_ptr->max_sectors << 9); |
116 | init->MaxFibSize = cpu_to_le32(dev->max_fib_size); | 132 | init->MaxFibSize = cpu_to_le32(dev->max_fib_size); |
117 | 133 | ||
134 | init->MaxNumAif = cpu_to_le32(dev->max_num_aif); | ||
135 | init->HostRRQ_AddrHigh = (u32)((u64)dev->host_rrq_pa >> 32); | ||
136 | init->HostRRQ_AddrLow = (u32)(dev->host_rrq_pa & 0xffffffff); | ||
137 | |||
138 | |||
118 | /* | 139 | /* |
119 | * Increment the base address by the amount already used | 140 | * Increment the base address by the amount already used |
120 | */ | 141 | */ |
121 | base = base + fibsize + sizeof(struct aac_init); | 142 | base = base + fibsize + host_rrq_size + sizeof(struct aac_init); |
122 | phys = (dma_addr_t)((ulong)phys + fibsize + sizeof(struct aac_init)); | 143 | phys = (dma_addr_t)((ulong)phys + fibsize + host_rrq_size + |
144 | sizeof(struct aac_init)); | ||
145 | |||
123 | /* | 146 | /* |
124 | * Align the beginning of Headers to commalign | 147 | * Align the beginning of Headers to commalign |
125 | */ | 148 | */ |
@@ -314,15 +337,22 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) | |||
314 | - sizeof(struct aac_write) + sizeof(struct sgentry)) | 337 | - sizeof(struct aac_write) + sizeof(struct sgentry)) |
315 | / sizeof(struct sgentry); | 338 | / sizeof(struct sgentry); |
316 | dev->comm_interface = AAC_COMM_PRODUCER; | 339 | dev->comm_interface = AAC_COMM_PRODUCER; |
317 | dev->raw_io_64 = 0; | 340 | dev->raw_io_interface = dev->raw_io_64 = 0; |
341 | |||
318 | if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES, | 342 | if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES, |
319 | 0, 0, 0, 0, 0, 0, status+0, status+1, status+2, NULL, NULL)) && | 343 | 0, 0, 0, 0, 0, 0, status+0, status+1, status+2, NULL, NULL)) && |
320 | (status[0] == 0x00000001)) { | 344 | (status[0] == 0x00000001)) { |
321 | if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_64)) | 345 | if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_64)) |
322 | dev->raw_io_64 = 1; | 346 | dev->raw_io_64 = 1; |
323 | if (dev->a_ops.adapter_comm && | 347 | if (dev->a_ops.adapter_comm) { |
324 | (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM))) | 348 | if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE1)) { |
325 | dev->comm_interface = AAC_COMM_MESSAGE; | 349 | dev->comm_interface = AAC_COMM_MESSAGE_TYPE1; |
350 | dev->raw_io_interface = 1; | ||
351 | } else if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM)) { | ||
352 | dev->comm_interface = AAC_COMM_MESSAGE; | ||
353 | dev->raw_io_interface = 1; | ||
354 | } | ||
355 | } | ||
326 | if ((dev->comm_interface == AAC_COMM_MESSAGE) && | 356 | if ((dev->comm_interface == AAC_COMM_MESSAGE) && |
327 | (status[2] > dev->base_size)) { | 357 | (status[2] > dev->base_size)) { |
328 | aac_adapter_ioremap(dev, 0); | 358 | aac_adapter_ioremap(dev, 0); |
@@ -350,10 +380,12 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) | |||
350 | * status[3] & 0xFFFF maximum number FIBs outstanding | 380 | * status[3] & 0xFFFF maximum number FIBs outstanding |
351 | */ | 381 | */ |
352 | host->max_sectors = (status[1] >> 16) << 1; | 382 | host->max_sectors = (status[1] >> 16) << 1; |
353 | dev->max_fib_size = status[1] & 0xFFFF; | 383 | /* Multiple of 32 for PMC */ |
384 | dev->max_fib_size = status[1] & 0xFFE0; | ||
354 | host->sg_tablesize = status[2] >> 16; | 385 | host->sg_tablesize = status[2] >> 16; |
355 | dev->sg_tablesize = status[2] & 0xFFFF; | 386 | dev->sg_tablesize = status[2] & 0xFFFF; |
356 | host->can_queue = (status[3] & 0xFFFF) - AAC_NUM_MGT_FIB; | 387 | host->can_queue = (status[3] & 0xFFFF) - AAC_NUM_MGT_FIB; |
388 | dev->max_num_aif = status[4] & 0xFFFF; | ||
357 | /* | 389 | /* |
358 | * NOTE: | 390 | * NOTE: |
359 | * All these overrides are based on a fixed internal | 391 | * All these overrides are based on a fixed internal |
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 060ac4bd5a14..dd7ad3ba2dad 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c | |||
@@ -5,7 +5,8 @@ | |||
5 | * based on the old aacraid driver that is.. | 5 | * based on the old aacraid driver that is.. |
6 | * Adaptec aacraid device driver for Linux. | 6 | * Adaptec aacraid device driver for Linux. |
7 | * | 7 | * |
8 | * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) | 8 | * Copyright (c) 2000-2010 Adaptec, Inc. |
9 | * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) | ||
9 | * | 10 | * |
10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
@@ -63,9 +64,11 @@ static int fib_map_alloc(struct aac_dev *dev) | |||
63 | "allocate hardware fibs pci_alloc_consistent(%p, %d * (%d + %d), %p)\n", | 64 | "allocate hardware fibs pci_alloc_consistent(%p, %d * (%d + %d), %p)\n", |
64 | dev->pdev, dev->max_fib_size, dev->scsi_host_ptr->can_queue, | 65 | dev->pdev, dev->max_fib_size, dev->scsi_host_ptr->can_queue, |
65 | AAC_NUM_MGT_FIB, &dev->hw_fib_pa)); | 66 | AAC_NUM_MGT_FIB, &dev->hw_fib_pa)); |
66 | if((dev->hw_fib_va = pci_alloc_consistent(dev->pdev, dev->max_fib_size | 67 | dev->hw_fib_va = pci_alloc_consistent(dev->pdev, |
67 | * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB), | 68 | (dev->max_fib_size + sizeof(struct aac_fib_xporthdr)) |
68 | &dev->hw_fib_pa))==NULL) | 69 | * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) + (ALIGN32 - 1), |
70 | &dev->hw_fib_pa); | ||
71 | if (dev->hw_fib_va == NULL) | ||
69 | return -ENOMEM; | 72 | return -ENOMEM; |
70 | return 0; | 73 | return 0; |
71 | } | 74 | } |
@@ -110,9 +113,22 @@ int aac_fib_setup(struct aac_dev * dev) | |||
110 | if (i<0) | 113 | if (i<0) |
111 | return -ENOMEM; | 114 | return -ENOMEM; |
112 | 115 | ||
116 | /* 32 byte alignment for PMC */ | ||
117 | hw_fib_pa = (dev->hw_fib_pa + (ALIGN32 - 1)) & ~(ALIGN32 - 1); | ||
118 | dev->hw_fib_va = (struct hw_fib *)((unsigned char *)dev->hw_fib_va + | ||
119 | (hw_fib_pa - dev->hw_fib_pa)); | ||
120 | dev->hw_fib_pa = hw_fib_pa; | ||
121 | memset(dev->hw_fib_va, 0, | ||
122 | (dev->max_fib_size + sizeof(struct aac_fib_xporthdr)) * | ||
123 | (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)); | ||
124 | |||
125 | /* add Xport header */ | ||
126 | dev->hw_fib_va = (struct hw_fib *)((unsigned char *)dev->hw_fib_va + | ||
127 | sizeof(struct aac_fib_xporthdr)); | ||
128 | dev->hw_fib_pa += sizeof(struct aac_fib_xporthdr); | ||
129 | |||
113 | hw_fib = dev->hw_fib_va; | 130 | hw_fib = dev->hw_fib_va; |
114 | hw_fib_pa = dev->hw_fib_pa; | 131 | hw_fib_pa = dev->hw_fib_pa; |
115 | memset(hw_fib, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)); | ||
116 | /* | 132 | /* |
117 | * Initialise the fibs | 133 | * Initialise the fibs |
118 | */ | 134 | */ |
@@ -129,8 +145,10 @@ int aac_fib_setup(struct aac_dev * dev) | |||
129 | hw_fib->header.XferState = cpu_to_le32(0xffffffff); | 145 | hw_fib->header.XferState = cpu_to_le32(0xffffffff); |
130 | hw_fib->header.SenderSize = cpu_to_le16(dev->max_fib_size); | 146 | hw_fib->header.SenderSize = cpu_to_le16(dev->max_fib_size); |
131 | fibptr->hw_fib_pa = hw_fib_pa; | 147 | fibptr->hw_fib_pa = hw_fib_pa; |
132 | hw_fib = (struct hw_fib *)((unsigned char *)hw_fib + dev->max_fib_size); | 148 | hw_fib = (struct hw_fib *)((unsigned char *)hw_fib + |
133 | hw_fib_pa = hw_fib_pa + dev->max_fib_size; | 149 | dev->max_fib_size + sizeof(struct aac_fib_xporthdr)); |
150 | hw_fib_pa = hw_fib_pa + | ||
151 | dev->max_fib_size + sizeof(struct aac_fib_xporthdr); | ||
134 | } | 152 | } |
135 | /* | 153 | /* |
136 | * Add the fib chain to the free list | 154 | * Add the fib chain to the free list |
@@ -664,9 +682,14 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size) | |||
664 | unsigned long nointr = 0; | 682 | unsigned long nointr = 0; |
665 | unsigned long qflags; | 683 | unsigned long qflags; |
666 | 684 | ||
685 | if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) { | ||
686 | kfree(hw_fib); | ||
687 | return 0; | ||
688 | } | ||
689 | |||
667 | if (hw_fib->header.XferState == 0) { | 690 | if (hw_fib->header.XferState == 0) { |
668 | if (dev->comm_interface == AAC_COMM_MESSAGE) | 691 | if (dev->comm_interface == AAC_COMM_MESSAGE) |
669 | kfree (hw_fib); | 692 | kfree(hw_fib); |
670 | return 0; | 693 | return 0; |
671 | } | 694 | } |
672 | /* | 695 | /* |
@@ -674,7 +697,7 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size) | |||
674 | */ | 697 | */ |
675 | if (hw_fib->header.StructType != FIB_MAGIC) { | 698 | if (hw_fib->header.StructType != FIB_MAGIC) { |
676 | if (dev->comm_interface == AAC_COMM_MESSAGE) | 699 | if (dev->comm_interface == AAC_COMM_MESSAGE) |
677 | kfree (hw_fib); | 700 | kfree(hw_fib); |
678 | return -EINVAL; | 701 | return -EINVAL; |
679 | } | 702 | } |
680 | /* | 703 | /* |
diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c index 9c7408fe8c7d..f0c66a80ad13 100644 --- a/drivers/scsi/aacraid/dpcsup.c +++ b/drivers/scsi/aacraid/dpcsup.c | |||
@@ -5,7 +5,8 @@ | |||
5 | * based on the old aacraid driver that is.. | 5 | * based on the old aacraid driver that is.. |
6 | * Adaptec aacraid device driver for Linux. | 6 | * Adaptec aacraid device driver for Linux. |
7 | * | 7 | * |
8 | * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) | 8 | * Copyright (c) 2000-2010 Adaptec, Inc. |
9 | * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) | ||
9 | * | 10 | * |
10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
@@ -228,6 +229,48 @@ unsigned int aac_command_normal(struct aac_queue *q) | |||
228 | return 0; | 229 | return 0; |
229 | } | 230 | } |
230 | 231 | ||
232 | /* | ||
233 | * | ||
234 | * aac_aif_callback | ||
235 | * @context: the context set in the fib - here it is scsi cmd | ||
236 | * @fibptr: pointer to the fib | ||
237 | * | ||
238 | * Handles the AIFs - new method (SRC) | ||
239 | * | ||
240 | */ | ||
241 | |||
242 | static void aac_aif_callback(void *context, struct fib * fibptr) | ||
243 | { | ||
244 | struct fib *fibctx; | ||
245 | struct aac_dev *dev; | ||
246 | struct aac_aifcmd *cmd; | ||
247 | int status; | ||
248 | |||
249 | fibctx = (struct fib *)context; | ||
250 | BUG_ON(fibptr == NULL); | ||
251 | dev = fibptr->dev; | ||
252 | |||
253 | if (fibptr->hw_fib_va->header.XferState & | ||
254 | cpu_to_le32(NoMoreAifDataAvailable)) { | ||
255 | aac_fib_complete(fibptr); | ||
256 | aac_fib_free(fibptr); | ||
257 | return; | ||
258 | } | ||
259 | |||
260 | aac_intr_normal(dev, 0, 1, 0, fibptr->hw_fib_va); | ||
261 | |||
262 | aac_fib_init(fibctx); | ||
263 | cmd = (struct aac_aifcmd *) fib_data(fibctx); | ||
264 | cmd->command = cpu_to_le32(AifReqEvent); | ||
265 | |||
266 | status = aac_fib_send(AifRequest, | ||
267 | fibctx, | ||
268 | sizeof(struct hw_fib)-sizeof(struct aac_fibhdr), | ||
269 | FsaNormal, | ||
270 | 0, 1, | ||
271 | (fib_callback)aac_aif_callback, fibctx); | ||
272 | } | ||
273 | |||
231 | 274 | ||
232 | /** | 275 | /** |
233 | * aac_intr_normal - Handle command replies | 276 | * aac_intr_normal - Handle command replies |
@@ -238,19 +281,17 @@ unsigned int aac_command_normal(struct aac_queue *q) | |||
238 | * know there is a response on our normal priority queue. We will pull off | 281 | * know there is a response on our normal priority queue. We will pull off |
239 | * all QE there are and wake up all the waiters before exiting. | 282 | * all QE there are and wake up all the waiters before exiting. |
240 | */ | 283 | */ |
241 | 284 | unsigned int aac_intr_normal(struct aac_dev *dev, u32 index, | |
242 | unsigned int aac_intr_normal(struct aac_dev * dev, u32 index) | 285 | int isAif, int isFastResponse, struct hw_fib *aif_fib) |
243 | { | 286 | { |
244 | unsigned long mflags; | 287 | unsigned long mflags; |
245 | dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, index)); | 288 | dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, index)); |
246 | if ((index & 0x00000002L)) { | 289 | if (isAif == 1) { /* AIF - common */ |
247 | struct hw_fib * hw_fib; | 290 | struct hw_fib * hw_fib; |
248 | struct fib * fib; | 291 | struct fib * fib; |
249 | struct aac_queue *q = &dev->queues->queue[HostNormCmdQueue]; | 292 | struct aac_queue *q = &dev->queues->queue[HostNormCmdQueue]; |
250 | unsigned long flags; | 293 | unsigned long flags; |
251 | 294 | ||
252 | if (index == 0xFFFFFFFEL) /* Special Case */ | ||
253 | return 0; /* Do nothing */ | ||
254 | /* | 295 | /* |
255 | * Allocate a FIB. For non queued stuff we can just use | 296 | * Allocate a FIB. For non queued stuff we can just use |
256 | * the stack so we are happy. We need a fib object in order to | 297 | * the stack so we are happy. We need a fib object in order to |
@@ -263,8 +304,13 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 index) | |||
263 | kfree (fib); | 304 | kfree (fib); |
264 | return 1; | 305 | return 1; |
265 | } | 306 | } |
266 | memcpy(hw_fib, (struct hw_fib *)(((uintptr_t)(dev->regs.sa)) + | 307 | if (aif_fib != NULL) { |
267 | (index & ~0x00000002L)), sizeof(struct hw_fib)); | 308 | memcpy(hw_fib, aif_fib, sizeof(struct hw_fib)); |
309 | } else { | ||
310 | memcpy(hw_fib, | ||
311 | (struct hw_fib *)(((uintptr_t)(dev->regs.sa)) + | ||
312 | index), sizeof(struct hw_fib)); | ||
313 | } | ||
268 | INIT_LIST_HEAD(&fib->fiblink); | 314 | INIT_LIST_HEAD(&fib->fiblink); |
269 | fib->type = FSAFS_NTC_FIB_CONTEXT; | 315 | fib->type = FSAFS_NTC_FIB_CONTEXT; |
270 | fib->size = sizeof(struct fib); | 316 | fib->size = sizeof(struct fib); |
@@ -277,9 +323,26 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 index) | |||
277 | wake_up_interruptible(&q->cmdready); | 323 | wake_up_interruptible(&q->cmdready); |
278 | spin_unlock_irqrestore(q->lock, flags); | 324 | spin_unlock_irqrestore(q->lock, flags); |
279 | return 1; | 325 | return 1; |
326 | } else if (isAif == 2) { /* AIF - new (SRC) */ | ||
327 | struct fib *fibctx; | ||
328 | struct aac_aifcmd *cmd; | ||
329 | |||
330 | fibctx = aac_fib_alloc(dev); | ||
331 | if (!fibctx) | ||
332 | return 1; | ||
333 | aac_fib_init(fibctx); | ||
334 | |||
335 | cmd = (struct aac_aifcmd *) fib_data(fibctx); | ||
336 | cmd->command = cpu_to_le32(AifReqEvent); | ||
337 | |||
338 | return aac_fib_send(AifRequest, | ||
339 | fibctx, | ||
340 | sizeof(struct hw_fib)-sizeof(struct aac_fibhdr), | ||
341 | FsaNormal, | ||
342 | 0, 1, | ||
343 | (fib_callback)aac_aif_callback, fibctx); | ||
280 | } else { | 344 | } else { |
281 | int fast = index & 0x01; | 345 | struct fib *fib = &dev->fibs[index]; |
282 | struct fib * fib = &dev->fibs[index >> 2]; | ||
283 | struct hw_fib * hwfib = fib->hw_fib_va; | 346 | struct hw_fib * hwfib = fib->hw_fib_va; |
284 | 347 | ||
285 | /* | 348 | /* |
@@ -298,7 +361,7 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 index) | |||
298 | return 0; | 361 | return 0; |
299 | } | 362 | } |
300 | 363 | ||
301 | if (fast) { | 364 | if (isFastResponse) { |
302 | /* | 365 | /* |
303 | * Doctor the fib | 366 | * Doctor the fib |
304 | */ | 367 | */ |
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 2c93d9496d62..4ff26521d75f 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c | |||
@@ -5,7 +5,8 @@ | |||
5 | * based on the old aacraid driver that is.. | 5 | * based on the old aacraid driver that is.. |
6 | * Adaptec aacraid device driver for Linux. | 6 | * Adaptec aacraid device driver for Linux. |
7 | * | 7 | * |
8 | * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) | 8 | * Copyright (c) 2000-2010 Adaptec, Inc. |
9 | * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) | ||
9 | * | 10 | * |
10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
@@ -54,7 +55,7 @@ | |||
54 | 55 | ||
55 | #include "aacraid.h" | 56 | #include "aacraid.h" |
56 | 57 | ||
57 | #define AAC_DRIVER_VERSION "1.1-5" | 58 | #define AAC_DRIVER_VERSION "1.1-7" |
58 | #ifndef AAC_DRIVER_BRANCH | 59 | #ifndef AAC_DRIVER_BRANCH |
59 | #define AAC_DRIVER_BRANCH "" | 60 | #define AAC_DRIVER_BRANCH "" |
60 | #endif | 61 | #endif |
@@ -161,6 +162,7 @@ static const struct pci_device_id aac_pci_tbl[] __devinitdata = { | |||
161 | { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 59 }, /* Adaptec Catch All */ | 162 | { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 59 }, /* Adaptec Catch All */ |
162 | { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 60 }, /* Adaptec Rocket Catch All */ | 163 | { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 60 }, /* Adaptec Rocket Catch All */ |
163 | { 0x9005, 0x0288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 61 }, /* Adaptec NEMER/ARK Catch All */ | 164 | { 0x9005, 0x0288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 61 }, /* Adaptec NEMER/ARK Catch All */ |
165 | { 0x9005, 0x028b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 62 }, /* Adaptec PMC Catch All */ | ||
164 | { 0,} | 166 | { 0,} |
165 | }; | 167 | }; |
166 | MODULE_DEVICE_TABLE(pci, aac_pci_tbl); | 168 | MODULE_DEVICE_TABLE(pci, aac_pci_tbl); |
@@ -235,7 +237,8 @@ static struct aac_driver_ident aac_drivers[] = { | |||
235 | { aac_rx_init, "aacraid", "Legend ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend Catchall */ | 237 | { aac_rx_init, "aacraid", "Legend ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend Catchall */ |
236 | { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Catch All */ | 238 | { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Catch All */ |
237 | { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Rocket Catch All */ | 239 | { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Rocket Catch All */ |
238 | { aac_nark_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec NEMER/ARK Catch All */ | 240 | { aac_nark_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec NEMER/ARK Catch All */ |
241 | { aac_src_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec PMC Catch All */ | ||
239 | }; | 242 | }; |
240 | 243 | ||
241 | /** | 244 | /** |
@@ -653,8 +656,10 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) | |||
653 | * This adapter needs a blind reset, only do so for Adapters that | 656 | * This adapter needs a blind reset, only do so for Adapters that |
654 | * support a register, instead of a commanded, reset. | 657 | * support a register, instead of a commanded, reset. |
655 | */ | 658 | */ |
656 | if ((aac->supplement_adapter_info.SupportedOptions2 & | 659 | if (((aac->supplement_adapter_info.SupportedOptions2 & |
657 | AAC_OPTION_MU_RESET) && | 660 | AAC_OPTION_MU_RESET) || |
661 | (aac->supplement_adapter_info.SupportedOptions2 & | ||
662 | AAC_OPTION_DOORBELL_RESET)) && | ||
658 | aac_check_reset && | 663 | aac_check_reset && |
659 | ((aac_check_reset != 1) || | 664 | ((aac_check_reset != 1) || |
660 | !(aac->supplement_adapter_info.SupportedOptions2 & | 665 | !(aac->supplement_adapter_info.SupportedOptions2 & |
diff --git a/drivers/scsi/aacraid/nark.c b/drivers/scsi/aacraid/nark.c index c55f7c862f0e..f397d21a0c06 100644 --- a/drivers/scsi/aacraid/nark.c +++ b/drivers/scsi/aacraid/nark.c | |||
@@ -4,7 +4,8 @@ | |||
4 | * based on the old aacraid driver that is.. | 4 | * based on the old aacraid driver that is.. |
5 | * Adaptec aacraid device driver for Linux. | 5 | * Adaptec aacraid device driver for Linux. |
6 | * | 6 | * |
7 | * Copyright (c) 2006-2007 Adaptec, Inc. (aacraid@adaptec.com) | 7 | * Copyright (c) 2000-2010 Adaptec, Inc. |
8 | * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) | ||
8 | * | 9 | * |
9 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c index 16d8db550027..be44de92429a 100644 --- a/drivers/scsi/aacraid/rkt.c +++ b/drivers/scsi/aacraid/rkt.c | |||
@@ -5,7 +5,8 @@ | |||
5 | * based on the old aacraid driver that is.. | 5 | * based on the old aacraid driver that is.. |
6 | * Adaptec aacraid device driver for Linux. | 6 | * Adaptec aacraid device driver for Linux. |
7 | * | 7 | * |
8 | * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) | 8 | * Copyright (c) 2000-2010 Adaptec, Inc. |
9 | * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) | ||
9 | * | 10 | * |
10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index 84d77fd86e5b..ce530f113fdb 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c | |||
@@ -5,7 +5,8 @@ | |||
5 | * based on the old aacraid driver that is.. | 5 | * based on the old aacraid driver that is.. |
6 | * Adaptec aacraid device driver for Linux. | 6 | * Adaptec aacraid device driver for Linux. |
7 | * | 7 | * |
8 | * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) | 8 | * Copyright (c) 2000-2010 Adaptec, Inc. |
9 | * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) | ||
9 | * | 10 | * |
10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
@@ -84,15 +85,35 @@ static irqreturn_t aac_rx_intr_producer(int irq, void *dev_id) | |||
84 | 85 | ||
85 | static irqreturn_t aac_rx_intr_message(int irq, void *dev_id) | 86 | static irqreturn_t aac_rx_intr_message(int irq, void *dev_id) |
86 | { | 87 | { |
88 | int isAif, isFastResponse, isSpecial; | ||
87 | struct aac_dev *dev = dev_id; | 89 | struct aac_dev *dev = dev_id; |
88 | u32 Index = rx_readl(dev, MUnit.OutboundQueue); | 90 | u32 Index = rx_readl(dev, MUnit.OutboundQueue); |
89 | if (unlikely(Index == 0xFFFFFFFFL)) | 91 | if (unlikely(Index == 0xFFFFFFFFL)) |
90 | Index = rx_readl(dev, MUnit.OutboundQueue); | 92 | Index = rx_readl(dev, MUnit.OutboundQueue); |
91 | if (likely(Index != 0xFFFFFFFFL)) { | 93 | if (likely(Index != 0xFFFFFFFFL)) { |
92 | do { | 94 | do { |
93 | if (unlikely(aac_intr_normal(dev, Index))) { | 95 | isAif = isFastResponse = isSpecial = 0; |
94 | rx_writel(dev, MUnit.OutboundQueue, Index); | 96 | if (Index & 0x00000002L) { |
95 | rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady); | 97 | isAif = 1; |
98 | if (Index == 0xFFFFFFFEL) | ||
99 | isSpecial = 1; | ||
100 | Index &= ~0x00000002L; | ||
101 | } else { | ||
102 | if (Index & 0x00000001L) | ||
103 | isFastResponse = 1; | ||
104 | Index >>= 2; | ||
105 | } | ||
106 | if (!isSpecial) { | ||
107 | if (unlikely(aac_intr_normal(dev, | ||
108 | Index, isAif, | ||
109 | isFastResponse, NULL))) { | ||
110 | rx_writel(dev, | ||
111 | MUnit.OutboundQueue, | ||
112 | Index); | ||
113 | rx_writel(dev, | ||
114 | MUnit.ODR, | ||
115 | DoorBellAdapterNormRespReady); | ||
116 | } | ||
96 | } | 117 | } |
97 | Index = rx_readl(dev, MUnit.OutboundQueue); | 118 | Index = rx_readl(dev, MUnit.OutboundQueue); |
98 | } while (Index != 0xFFFFFFFFL); | 119 | } while (Index != 0xFFFFFFFFL); |
@@ -631,6 +652,10 @@ int _aac_rx_init(struct aac_dev *dev) | |||
631 | name, instance); | 652 | name, instance); |
632 | goto error_iounmap; | 653 | goto error_iounmap; |
633 | } | 654 | } |
655 | dev->dbg_base = dev->scsi_host_ptr->base; | ||
656 | dev->dbg_base_mapped = dev->base; | ||
657 | dev->dbg_size = dev->base_size; | ||
658 | |||
634 | aac_adapter_enable_int(dev); | 659 | aac_adapter_enable_int(dev); |
635 | /* | 660 | /* |
636 | * Tell the adapter that all is configured, and it can | 661 | * Tell the adapter that all is configured, and it can |
diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c index 622c21c68e65..e5d4457121ea 100644 --- a/drivers/scsi/aacraid/sa.c +++ b/drivers/scsi/aacraid/sa.c | |||
@@ -5,7 +5,8 @@ | |||
5 | * based on the old aacraid driver that is.. | 5 | * based on the old aacraid driver that is.. |
6 | * Adaptec aacraid device driver for Linux. | 6 | * Adaptec aacraid device driver for Linux. |
7 | * | 7 | * |
8 | * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) | 8 | * Copyright (c) 2000-2010 Adaptec, Inc. |
9 | * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) | ||
9 | * | 10 | * |
10 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
@@ -391,6 +392,10 @@ int aac_sa_init(struct aac_dev *dev) | |||
391 | name, instance); | 392 | name, instance); |
392 | goto error_iounmap; | 393 | goto error_iounmap; |
393 | } | 394 | } |
395 | dev->dbg_base = dev->scsi_host_ptr->base; | ||
396 | dev->dbg_base_mapped = dev->base; | ||
397 | dev->dbg_size = dev->base_size; | ||
398 | |||
394 | aac_adapter_enable_int(dev); | 399 | aac_adapter_enable_int(dev); |
395 | 400 | ||
396 | /* | 401 | /* |
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c new file mode 100644 index 000000000000..c20494660603 --- /dev/null +++ b/drivers/scsi/aacraid/src.c | |||
@@ -0,0 +1,594 @@ | |||
1 | /* | ||
2 | * Adaptec AAC series RAID controller driver | ||
3 | * (c) Copyright 2001 Red Hat Inc. | ||
4 | * | ||
5 | * based on the old aacraid driver that is.. | ||
6 | * Adaptec aacraid device driver for Linux. | ||
7 | * | ||
8 | * Copyright (c) 2000-2010 Adaptec, Inc. | ||
9 | * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2, or (at your option) | ||
14 | * any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; see the file COPYING. If not, write to | ||
23 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | * | ||
25 | * Module Name: | ||
26 | * src.c | ||
27 | * | ||
28 | * Abstract: Hardware Device Interface for PMC SRC based controllers | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/init.h> | ||
34 | #include <linux/types.h> | ||
35 | #include <linux/pci.h> | ||
36 | #include <linux/spinlock.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/blkdev.h> | ||
39 | #include <linux/delay.h> | ||
40 | #include <linux/version.h> | ||
41 | #include <linux/completion.h> | ||
42 | #include <linux/time.h> | ||
43 | #include <linux/interrupt.h> | ||
44 | #include <scsi/scsi_host.h> | ||
45 | |||
46 | #include "aacraid.h" | ||
47 | |||
48 | static irqreturn_t aac_src_intr_message(int irq, void *dev_id) | ||
49 | { | ||
50 | struct aac_dev *dev = dev_id; | ||
51 | unsigned long bellbits, bellbits_shifted; | ||
52 | int our_interrupt = 0; | ||
53 | int isFastResponse; | ||
54 | u32 index, handle; | ||
55 | |||
56 | bellbits = src_readl(dev, MUnit.ODR_R); | ||
57 | if (bellbits & PmDoorBellResponseSent) { | ||
58 | bellbits = PmDoorBellResponseSent; | ||
59 | /* handle async. status */ | ||
60 | our_interrupt = 1; | ||
61 | index = dev->host_rrq_idx; | ||
62 | if (dev->host_rrq[index] == 0) { | ||
63 | u32 old_index = index; | ||
64 | /* adjust index */ | ||
65 | do { | ||
66 | index++; | ||
67 | if (index == dev->scsi_host_ptr->can_queue + | ||
68 | AAC_NUM_MGT_FIB) | ||
69 | index = 0; | ||
70 | if (dev->host_rrq[index] != 0) | ||
71 | break; | ||
72 | } while (index != old_index); | ||
73 | dev->host_rrq_idx = index; | ||
74 | } | ||
75 | for (;;) { | ||
76 | isFastResponse = 0; | ||
77 | /* remove toggle bit (31) */ | ||
78 | handle = (dev->host_rrq[index] & 0x7fffffff); | ||
79 | /* check fast response bit (30) */ | ||
80 | if (handle & 0x40000000) | ||
81 | isFastResponse = 1; | ||
82 | handle &= 0x0000ffff; | ||
83 | if (handle == 0) | ||
84 | break; | ||
85 | |||
86 | aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL); | ||
87 | |||
88 | dev->host_rrq[index++] = 0; | ||
89 | if (index == dev->scsi_host_ptr->can_queue + | ||
90 | AAC_NUM_MGT_FIB) | ||
91 | index = 0; | ||
92 | dev->host_rrq_idx = index; | ||
93 | } | ||
94 | } else { | ||
95 | bellbits_shifted = (bellbits >> SRC_ODR_SHIFT); | ||
96 | if (bellbits_shifted & DoorBellAifPending) { | ||
97 | our_interrupt = 1; | ||
98 | /* handle AIF */ | ||
99 | aac_intr_normal(dev, 0, 2, 0, NULL); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | if (our_interrupt) { | ||
104 | src_writel(dev, MUnit.ODR_C, bellbits); | ||
105 | return IRQ_HANDLED; | ||
106 | } | ||
107 | return IRQ_NONE; | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * aac_src_disable_interrupt - Disable interrupts | ||
112 | * @dev: Adapter | ||
113 | */ | ||
114 | |||
115 | static void aac_src_disable_interrupt(struct aac_dev *dev) | ||
116 | { | ||
117 | src_writel(dev, MUnit.OIMR, dev->OIMR = 0xffffffff); | ||
118 | } | ||
119 | |||
120 | /** | ||
121 | * aac_src_enable_interrupt_message - Enable interrupts | ||
122 | * @dev: Adapter | ||
123 | */ | ||
124 | |||
125 | static void aac_src_enable_interrupt_message(struct aac_dev *dev) | ||
126 | { | ||
127 | src_writel(dev, MUnit.OIMR, dev->OIMR = 0xfffffff8); | ||
128 | } | ||
129 | |||
130 | /** | ||
131 | * src_sync_cmd - send a command and wait | ||
132 | * @dev: Adapter | ||
133 | * @command: Command to execute | ||
134 | * @p1: first parameter | ||
135 | * @ret: adapter status | ||
136 | * | ||
137 | * This routine will send a synchronous command to the adapter and wait | ||
138 | * for its completion. | ||
139 | */ | ||
140 | |||
141 | static int src_sync_cmd(struct aac_dev *dev, u32 command, | ||
142 | u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, | ||
143 | u32 *status, u32 * r1, u32 * r2, u32 * r3, u32 * r4) | ||
144 | { | ||
145 | unsigned long start; | ||
146 | int ok; | ||
147 | |||
148 | /* | ||
149 | * Write the command into Mailbox 0 | ||
150 | */ | ||
151 | writel(command, &dev->IndexRegs->Mailbox[0]); | ||
152 | /* | ||
153 | * Write the parameters into Mailboxes 1 - 6 | ||
154 | */ | ||
155 | writel(p1, &dev->IndexRegs->Mailbox[1]); | ||
156 | writel(p2, &dev->IndexRegs->Mailbox[2]); | ||
157 | writel(p3, &dev->IndexRegs->Mailbox[3]); | ||
158 | writel(p4, &dev->IndexRegs->Mailbox[4]); | ||
159 | |||
160 | /* | ||
161 | * Clear the synch command doorbell to start on a clean slate. | ||
162 | */ | ||
163 | src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); | ||
164 | |||
165 | /* | ||
166 | * Disable doorbell interrupts | ||
167 | */ | ||
168 | src_writel(dev, MUnit.OIMR, dev->OIMR = 0xffffffff); | ||
169 | |||
170 | /* | ||
171 | * Force the completion of the mask register write before issuing | ||
172 | * the interrupt. | ||
173 | */ | ||
174 | src_readl(dev, MUnit.OIMR); | ||
175 | |||
176 | /* | ||
177 | * Signal that there is a new synch command | ||
178 | */ | ||
179 | src_writel(dev, MUnit.IDR, INBOUNDDOORBELL_0 << SRC_IDR_SHIFT); | ||
180 | |||
181 | ok = 0; | ||
182 | start = jiffies; | ||
183 | |||
184 | /* | ||
185 | * Wait up to 30 seconds | ||
186 | */ | ||
187 | while (time_before(jiffies, start+30*HZ)) { | ||
188 | /* Delay 5 microseconds to let Mon960 get info. */ | ||
189 | udelay(5); | ||
190 | |||
191 | /* Mon960 will set doorbell0 bit | ||
192 | * when it has completed the command | ||
193 | */ | ||
194 | if ((src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT) & OUTBOUNDDOORBELL_0) { | ||
195 | /* Clear the doorbell */ | ||
196 | src_writel(dev, | ||
197 | MUnit.ODR_C, | ||
198 | OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); | ||
199 | ok = 1; | ||
200 | break; | ||
201 | } | ||
202 | |||
203 | /* Yield the processor in case we are slow */ | ||
204 | msleep(1); | ||
205 | } | ||
206 | if (unlikely(ok != 1)) { | ||
207 | /* Restore interrupt mask even though we timed out */ | ||
208 | aac_adapter_enable_int(dev); | ||
209 | return -ETIMEDOUT; | ||
210 | } | ||
211 | |||
212 | /* Pull the synch status from Mailbox 0 */ | ||
213 | if (status) | ||
214 | *status = readl(&dev->IndexRegs->Mailbox[0]); | ||
215 | if (r1) | ||
216 | *r1 = readl(&dev->IndexRegs->Mailbox[1]); | ||
217 | if (r2) | ||
218 | *r2 = readl(&dev->IndexRegs->Mailbox[2]); | ||
219 | if (r3) | ||
220 | *r3 = readl(&dev->IndexRegs->Mailbox[3]); | ||
221 | if (r4) | ||
222 | *r4 = readl(&dev->IndexRegs->Mailbox[4]); | ||
223 | |||
224 | /* Clear the synch command doorbell */ | ||
225 | src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); | ||
226 | |||
227 | /* Restore interrupt mask */ | ||
228 | aac_adapter_enable_int(dev); | ||
229 | return 0; | ||
230 | |||
231 | } | ||
232 | |||
233 | /** | ||
234 | * aac_src_interrupt_adapter - interrupt adapter | ||
235 | * @dev: Adapter | ||
236 | * | ||
237 | * Send an interrupt to the i960 and breakpoint it. | ||
238 | */ | ||
239 | |||
240 | static void aac_src_interrupt_adapter(struct aac_dev *dev) | ||
241 | { | ||
242 | src_sync_cmd(dev, BREAKPOINT_REQUEST, | ||
243 | 0, 0, 0, 0, 0, 0, | ||
244 | NULL, NULL, NULL, NULL, NULL); | ||
245 | } | ||
246 | |||
247 | /** | ||
248 | * aac_src_notify_adapter - send an event to the adapter | ||
249 | * @dev: Adapter | ||
250 | * @event: Event to send | ||
251 | * | ||
252 | * Notify the i960 that something it probably cares about has | ||
253 | * happened. | ||
254 | */ | ||
255 | |||
256 | static void aac_src_notify_adapter(struct aac_dev *dev, u32 event) | ||
257 | { | ||
258 | switch (event) { | ||
259 | |||
260 | case AdapNormCmdQue: | ||
261 | src_writel(dev, MUnit.ODR_C, | ||
262 | INBOUNDDOORBELL_1 << SRC_ODR_SHIFT); | ||
263 | break; | ||
264 | case HostNormRespNotFull: | ||
265 | src_writel(dev, MUnit.ODR_C, | ||
266 | INBOUNDDOORBELL_4 << SRC_ODR_SHIFT); | ||
267 | break; | ||
268 | case AdapNormRespQue: | ||
269 | src_writel(dev, MUnit.ODR_C, | ||
270 | INBOUNDDOORBELL_2 << SRC_ODR_SHIFT); | ||
271 | break; | ||
272 | case HostNormCmdNotFull: | ||
273 | src_writel(dev, MUnit.ODR_C, | ||
274 | INBOUNDDOORBELL_3 << SRC_ODR_SHIFT); | ||
275 | break; | ||
276 | case FastIo: | ||
277 | src_writel(dev, MUnit.ODR_C, | ||
278 | INBOUNDDOORBELL_6 << SRC_ODR_SHIFT); | ||
279 | break; | ||
280 | case AdapPrintfDone: | ||
281 | src_writel(dev, MUnit.ODR_C, | ||
282 | INBOUNDDOORBELL_5 << SRC_ODR_SHIFT); | ||
283 | break; | ||
284 | default: | ||
285 | BUG(); | ||
286 | break; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | /** | ||
291 | * aac_src_start_adapter - activate adapter | ||
292 | * @dev: Adapter | ||
293 | * | ||
294 | * Start up processing on an i960 based AAC adapter | ||
295 | */ | ||
296 | |||
297 | static void aac_src_start_adapter(struct aac_dev *dev) | ||
298 | { | ||
299 | struct aac_init *init; | ||
300 | |||
301 | init = dev->init; | ||
302 | init->HostElapsedSeconds = cpu_to_le32(get_seconds()); | ||
303 | |||
304 | /* We can only use a 32 bit address here */ | ||
305 | src_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, | ||
306 | 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); | ||
307 | } | ||
308 | |||
309 | /** | ||
310 | * aac_src_check_health | ||
311 | * @dev: device to check if healthy | ||
312 | * | ||
313 | * Will attempt to determine if the specified adapter is alive and | ||
314 | * capable of handling requests, returning 0 if alive. | ||
315 | */ | ||
316 | static int aac_src_check_health(struct aac_dev *dev) | ||
317 | { | ||
318 | u32 status = src_readl(dev, MUnit.OMR); | ||
319 | |||
320 | /* | ||
321 | * Check to see if the board failed any self tests. | ||
322 | */ | ||
323 | if (unlikely(status & SELF_TEST_FAILED)) | ||
324 | return -1; | ||
325 | |||
326 | /* | ||
327 | * Check to see if the board panic'd. | ||
328 | */ | ||
329 | if (unlikely(status & KERNEL_PANIC)) | ||
330 | return (status >> 16) & 0xFF; | ||
331 | /* | ||
332 | * Wait for the adapter to be up and running. | ||
333 | */ | ||
334 | if (unlikely(!(status & KERNEL_UP_AND_RUNNING))) | ||
335 | return -3; | ||
336 | /* | ||
337 | * Everything is OK | ||
338 | */ | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | /** | ||
343 | * aac_src_deliver_message | ||
344 | * @fib: fib to issue | ||
345 | * | ||
346 | * Will send a fib, returning 0 if successful. | ||
347 | */ | ||
348 | static int aac_src_deliver_message(struct fib *fib) | ||
349 | { | ||
350 | struct aac_dev *dev = fib->dev; | ||
351 | struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue]; | ||
352 | unsigned long qflags; | ||
353 | u32 fibsize; | ||
354 | u64 address; | ||
355 | struct aac_fib_xporthdr *pFibX; | ||
356 | |||
357 | spin_lock_irqsave(q->lock, qflags); | ||
358 | q->numpending++; | ||
359 | spin_unlock_irqrestore(q->lock, qflags); | ||
360 | |||
361 | /* Calculate the amount to the fibsize bits */ | ||
362 | fibsize = (sizeof(struct aac_fib_xporthdr) + | ||
363 | fib->hw_fib_va->header.Size + 127) / 128 - 1; | ||
364 | if (fibsize > (ALIGN32 - 1)) | ||
365 | fibsize = ALIGN32 - 1; | ||
366 | |||
367 | /* Fill XPORT header */ | ||
368 | pFibX = (struct aac_fib_xporthdr *) | ||
369 | ((unsigned char *)fib->hw_fib_va - | ||
370 | sizeof(struct aac_fib_xporthdr)); | ||
371 | pFibX->Handle = fib->hw_fib_va->header.SenderData + 1; | ||
372 | pFibX->HostAddress = fib->hw_fib_pa; | ||
373 | pFibX->Size = fib->hw_fib_va->header.Size; | ||
374 | address = fib->hw_fib_pa - (u64)sizeof(struct aac_fib_xporthdr); | ||
375 | |||
376 | src_writel(dev, MUnit.IQ_H, (u32)(address >> 32)); | ||
377 | src_writel(dev, MUnit.IQ_L, (u32)(address & 0xffffffff) + fibsize); | ||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | /** | ||
382 | * aac_src_ioremap | ||
383 | * @size: mapping resize request | ||
384 | * | ||
385 | */ | ||
386 | static int aac_src_ioremap(struct aac_dev *dev, u32 size) | ||
387 | { | ||
388 | if (!size) { | ||
389 | iounmap(dev->regs.src.bar0); | ||
390 | dev->regs.src.bar0 = NULL; | ||
391 | iounmap(dev->base); | ||
392 | dev->base = NULL; | ||
393 | return 0; | ||
394 | } | ||
395 | dev->regs.src.bar1 = ioremap(pci_resource_start(dev->pdev, 2), | ||
396 | AAC_MIN_SRC_BAR1_SIZE); | ||
397 | dev->base = NULL; | ||
398 | if (dev->regs.src.bar1 == NULL) | ||
399 | return -1; | ||
400 | dev->base = dev->regs.src.bar0 = ioremap(dev->scsi_host_ptr->base, | ||
401 | size); | ||
402 | if (dev->base == NULL) { | ||
403 | iounmap(dev->regs.src.bar1); | ||
404 | dev->regs.src.bar1 = NULL; | ||
405 | return -1; | ||
406 | } | ||
407 | dev->IndexRegs = &((struct src_registers __iomem *) | ||
408 | dev->base)->IndexRegs; | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | static int aac_src_restart_adapter(struct aac_dev *dev, int bled) | ||
413 | { | ||
414 | u32 var, reset_mask; | ||
415 | |||
416 | if (bled >= 0) { | ||
417 | if (bled) | ||
418 | printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n", | ||
419 | dev->name, dev->id, bled); | ||
420 | bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS, | ||
421 | 0, 0, 0, 0, 0, 0, &var, &reset_mask, NULL, NULL, NULL); | ||
422 | if (bled || (var != 0x00000001)) | ||
423 | bled = -EINVAL; | ||
424 | if (dev->supplement_adapter_info.SupportedOptions2 & | ||
425 | AAC_OPTION_DOORBELL_RESET) { | ||
426 | src_writel(dev, MUnit.IDR, reset_mask); | ||
427 | msleep(5000); /* Delay 5 seconds */ | ||
428 | } | ||
429 | } | ||
430 | |||
431 | if (src_readl(dev, MUnit.OMR) & KERNEL_PANIC) | ||
432 | return -ENODEV; | ||
433 | |||
434 | if (startup_timeout < 300) | ||
435 | startup_timeout = 300; | ||
436 | |||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | /** | ||
441 | * aac_src_select_comm - Select communications method | ||
442 | * @dev: Adapter | ||
443 | * @comm: communications method | ||
444 | */ | ||
445 | int aac_src_select_comm(struct aac_dev *dev, int comm) | ||
446 | { | ||
447 | switch (comm) { | ||
448 | case AAC_COMM_MESSAGE: | ||
449 | dev->a_ops.adapter_enable_int = aac_src_enable_interrupt_message; | ||
450 | dev->a_ops.adapter_intr = aac_src_intr_message; | ||
451 | dev->a_ops.adapter_deliver = aac_src_deliver_message; | ||
452 | break; | ||
453 | default: | ||
454 | return 1; | ||
455 | } | ||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | /** | ||
460 | * aac_src_init - initialize an Cardinal Frey Bar card | ||
461 | * @dev: device to configure | ||
462 | * | ||
463 | */ | ||
464 | |||
465 | int aac_src_init(struct aac_dev *dev) | ||
466 | { | ||
467 | unsigned long start; | ||
468 | unsigned long status; | ||
469 | int restart = 0; | ||
470 | int instance = dev->id; | ||
471 | const char *name = dev->name; | ||
472 | |||
473 | dev->a_ops.adapter_ioremap = aac_src_ioremap; | ||
474 | dev->a_ops.adapter_comm = aac_src_select_comm; | ||
475 | |||
476 | dev->base_size = AAC_MIN_SRC_BAR0_SIZE; | ||
477 | if (aac_adapter_ioremap(dev, dev->base_size)) { | ||
478 | printk(KERN_WARNING "%s: unable to map adapter.\n", name); | ||
479 | goto error_iounmap; | ||
480 | } | ||
481 | |||
482 | /* Failure to reset here is an option ... */ | ||
483 | dev->a_ops.adapter_sync_cmd = src_sync_cmd; | ||
484 | dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; | ||
485 | if ((aac_reset_devices || reset_devices) && | ||
486 | !aac_src_restart_adapter(dev, 0)) | ||
487 | ++restart; | ||
488 | /* | ||
489 | * Check to see if the board panic'd while booting. | ||
490 | */ | ||
491 | status = src_readl(dev, MUnit.OMR); | ||
492 | if (status & KERNEL_PANIC) { | ||
493 | if (aac_src_restart_adapter(dev, aac_src_check_health(dev))) | ||
494 | goto error_iounmap; | ||
495 | ++restart; | ||
496 | } | ||
497 | /* | ||
498 | * Check to see if the board failed any self tests. | ||
499 | */ | ||
500 | status = src_readl(dev, MUnit.OMR); | ||
501 | if (status & SELF_TEST_FAILED) { | ||
502 | printk(KERN_ERR "%s%d: adapter self-test failed.\n", | ||
503 | dev->name, instance); | ||
504 | goto error_iounmap; | ||
505 | } | ||
506 | /* | ||
507 | * Check to see if the monitor panic'd while booting. | ||
508 | */ | ||
509 | if (status & MONITOR_PANIC) { | ||
510 | printk(KERN_ERR "%s%d: adapter monitor panic.\n", | ||
511 | dev->name, instance); | ||
512 | goto error_iounmap; | ||
513 | } | ||
514 | start = jiffies; | ||
515 | /* | ||
516 | * Wait for the adapter to be up and running. Wait up to 3 minutes | ||
517 | */ | ||
518 | while (!((status = src_readl(dev, MUnit.OMR)) & | ||
519 | KERNEL_UP_AND_RUNNING)) { | ||
520 | if ((restart && | ||
521 | (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) || | ||
522 | time_after(jiffies, start+HZ*startup_timeout)) { | ||
523 | printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", | ||
524 | dev->name, instance, status); | ||
525 | goto error_iounmap; | ||
526 | } | ||
527 | if (!restart && | ||
528 | ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) || | ||
529 | time_after(jiffies, start + HZ * | ||
530 | ((startup_timeout > 60) | ||
531 | ? (startup_timeout - 60) | ||
532 | : (startup_timeout / 2))))) { | ||
533 | if (likely(!aac_src_restart_adapter(dev, | ||
534 | aac_src_check_health(dev)))) | ||
535 | start = jiffies; | ||
536 | ++restart; | ||
537 | } | ||
538 | msleep(1); | ||
539 | } | ||
540 | if (restart && aac_commit) | ||
541 | aac_commit = 1; | ||
542 | /* | ||
543 | * Fill in the common function dispatch table. | ||
544 | */ | ||
545 | dev->a_ops.adapter_interrupt = aac_src_interrupt_adapter; | ||
546 | dev->a_ops.adapter_disable_int = aac_src_disable_interrupt; | ||
547 | dev->a_ops.adapter_notify = aac_src_notify_adapter; | ||
548 | dev->a_ops.adapter_sync_cmd = src_sync_cmd; | ||
549 | dev->a_ops.adapter_check_health = aac_src_check_health; | ||
550 | dev->a_ops.adapter_restart = aac_src_restart_adapter; | ||
551 | |||
552 | /* | ||
553 | * First clear out all interrupts. Then enable the one's that we | ||
554 | * can handle. | ||
555 | */ | ||
556 | aac_adapter_comm(dev, AAC_COMM_MESSAGE); | ||
557 | aac_adapter_disable_int(dev); | ||
558 | src_writel(dev, MUnit.ODR_C, 0xffffffff); | ||
559 | aac_adapter_enable_int(dev); | ||
560 | |||
561 | if (aac_init_adapter(dev) == NULL) | ||
562 | goto error_iounmap; | ||
563 | if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE1) | ||
564 | goto error_iounmap; | ||
565 | |||
566 | dev->msi = aac_msi && !pci_enable_msi(dev->pdev); | ||
567 | |||
568 | if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, | ||
569 | IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) { | ||
570 | |||
571 | if (dev->msi) | ||
572 | pci_disable_msi(dev->pdev); | ||
573 | |||
574 | printk(KERN_ERR "%s%d: Interrupt unavailable.\n", | ||
575 | name, instance); | ||
576 | goto error_iounmap; | ||
577 | } | ||
578 | dev->dbg_base = pci_resource_start(dev->pdev, 2); | ||
579 | dev->dbg_base_mapped = dev->regs.src.bar1; | ||
580 | dev->dbg_size = AAC_MIN_SRC_BAR1_SIZE; | ||
581 | |||
582 | aac_adapter_enable_int(dev); | ||
583 | /* | ||
584 | * Tell the adapter that all is configured, and it can | ||
585 | * start accepting requests | ||
586 | */ | ||
587 | aac_src_start_adapter(dev); | ||
588 | |||
589 | return 0; | ||
590 | |||
591 | error_iounmap: | ||
592 | |||
593 | return -1; | ||
594 | } | ||
diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index df2fc09ba479..b6d350ac4288 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h | |||
@@ -62,7 +62,7 @@ | |||
62 | #include "bnx2fc_constants.h" | 62 | #include "bnx2fc_constants.h" |
63 | 63 | ||
64 | #define BNX2FC_NAME "bnx2fc" | 64 | #define BNX2FC_NAME "bnx2fc" |
65 | #define BNX2FC_VERSION "1.0.0" | 65 | #define BNX2FC_VERSION "1.0.1" |
66 | 66 | ||
67 | #define PFX "bnx2fc: " | 67 | #define PFX "bnx2fc: " |
68 | 68 | ||
@@ -84,9 +84,15 @@ | |||
84 | #define BNX2FC_NUM_MAX_SESS 128 | 84 | #define BNX2FC_NUM_MAX_SESS 128 |
85 | #define BNX2FC_NUM_MAX_SESS_LOG (ilog2(BNX2FC_NUM_MAX_SESS)) | 85 | #define BNX2FC_NUM_MAX_SESS_LOG (ilog2(BNX2FC_NUM_MAX_SESS)) |
86 | 86 | ||
87 | #define BNX2FC_MAX_OUTSTANDING_CMNDS 4096 | 87 | #define BNX2FC_MAX_OUTSTANDING_CMNDS 2048 |
88 | #define BNX2FC_CAN_QUEUE BNX2FC_MAX_OUTSTANDING_CMNDS | ||
89 | #define BNX2FC_ELSTM_XIDS BNX2FC_CAN_QUEUE | ||
88 | #define BNX2FC_MIN_PAYLOAD 256 | 90 | #define BNX2FC_MIN_PAYLOAD 256 |
89 | #define BNX2FC_MAX_PAYLOAD 2048 | 91 | #define BNX2FC_MAX_PAYLOAD 2048 |
92 | #define BNX2FC_MFS \ | ||
93 | (BNX2FC_MAX_PAYLOAD + sizeof(struct fc_frame_header)) | ||
94 | #define BNX2FC_MINI_JUMBO_MTU 2500 | ||
95 | |||
90 | 96 | ||
91 | #define BNX2FC_RQ_BUF_SZ 256 | 97 | #define BNX2FC_RQ_BUF_SZ 256 |
92 | #define BNX2FC_RQ_BUF_LOG_SZ (ilog2(BNX2FC_RQ_BUF_SZ)) | 98 | #define BNX2FC_RQ_BUF_LOG_SZ (ilog2(BNX2FC_RQ_BUF_SZ)) |
@@ -98,7 +104,8 @@ | |||
98 | #define BNX2FC_CONFQ_WQE_SIZE (sizeof(struct fcoe_confqe)) | 104 | #define BNX2FC_CONFQ_WQE_SIZE (sizeof(struct fcoe_confqe)) |
99 | #define BNX2FC_5771X_DB_PAGE_SIZE 128 | 105 | #define BNX2FC_5771X_DB_PAGE_SIZE 128 |
100 | 106 | ||
101 | #define BNX2FC_MAX_TASKS BNX2FC_MAX_OUTSTANDING_CMNDS | 107 | #define BNX2FC_MAX_TASKS \ |
108 | (BNX2FC_MAX_OUTSTANDING_CMNDS + BNX2FC_ELSTM_XIDS) | ||
102 | #define BNX2FC_TASK_SIZE 128 | 109 | #define BNX2FC_TASK_SIZE 128 |
103 | #define BNX2FC_TASKS_PER_PAGE (PAGE_SIZE/BNX2FC_TASK_SIZE) | 110 | #define BNX2FC_TASKS_PER_PAGE (PAGE_SIZE/BNX2FC_TASK_SIZE) |
104 | #define BNX2FC_TASK_CTX_ARR_SZ (BNX2FC_MAX_TASKS/BNX2FC_TASKS_PER_PAGE) | 111 | #define BNX2FC_TASK_CTX_ARR_SZ (BNX2FC_MAX_TASKS/BNX2FC_TASKS_PER_PAGE) |
@@ -112,10 +119,10 @@ | |||
112 | #define BNX2FC_WRITE (1 << 0) | 119 | #define BNX2FC_WRITE (1 << 0) |
113 | 120 | ||
114 | #define BNX2FC_MIN_XID 0 | 121 | #define BNX2FC_MIN_XID 0 |
115 | #define BNX2FC_MAX_XID (BNX2FC_MAX_OUTSTANDING_CMNDS - 1) | 122 | #define BNX2FC_MAX_XID \ |
116 | #define FCOE_MIN_XID (BNX2FC_MAX_OUTSTANDING_CMNDS) | 123 | (BNX2FC_MAX_OUTSTANDING_CMNDS + BNX2FC_ELSTM_XIDS - 1) |
117 | #define FCOE_MAX_XID \ | 124 | #define FCOE_MIN_XID (BNX2FC_MAX_XID + 1) |
118 | (BNX2FC_MAX_OUTSTANDING_CMNDS + (nr_cpu_ids * 256)) | 125 | #define FCOE_MAX_XID (FCOE_MIN_XID + 4095) |
119 | #define BNX2FC_MAX_LUN 0xFFFF | 126 | #define BNX2FC_MAX_LUN 0xFFFF |
120 | #define BNX2FC_MAX_FCP_TGT 256 | 127 | #define BNX2FC_MAX_FCP_TGT 256 |
121 | #define BNX2FC_MAX_CMD_LEN 16 | 128 | #define BNX2FC_MAX_CMD_LEN 16 |
@@ -125,7 +132,6 @@ | |||
125 | 132 | ||
126 | #define BNX2FC_WAIT_CNT 120 | 133 | #define BNX2FC_WAIT_CNT 120 |
127 | #define BNX2FC_FW_TIMEOUT (3 * HZ) | 134 | #define BNX2FC_FW_TIMEOUT (3 * HZ) |
128 | |||
129 | #define PORT_MAX 2 | 135 | #define PORT_MAX 2 |
130 | 136 | ||
131 | #define CMD_SCSI_STATUS(Cmnd) ((Cmnd)->SCp.Status) | 137 | #define CMD_SCSI_STATUS(Cmnd) ((Cmnd)->SCp.Status) |
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index e476e8753079..e2e647509a73 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c | |||
@@ -21,7 +21,7 @@ DEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu); | |||
21 | 21 | ||
22 | #define DRV_MODULE_NAME "bnx2fc" | 22 | #define DRV_MODULE_NAME "bnx2fc" |
23 | #define DRV_MODULE_VERSION BNX2FC_VERSION | 23 | #define DRV_MODULE_VERSION BNX2FC_VERSION |
24 | #define DRV_MODULE_RELDATE "Jan 25, 2011" | 24 | #define DRV_MODULE_RELDATE "Mar 17, 2011" |
25 | 25 | ||
26 | 26 | ||
27 | static char version[] __devinitdata = | 27 | static char version[] __devinitdata = |
@@ -437,17 +437,16 @@ static int bnx2fc_l2_rcv_thread(void *arg) | |||
437 | set_current_state(TASK_INTERRUPTIBLE); | 437 | set_current_state(TASK_INTERRUPTIBLE); |
438 | while (!kthread_should_stop()) { | 438 | while (!kthread_should_stop()) { |
439 | schedule(); | 439 | schedule(); |
440 | set_current_state(TASK_RUNNING); | ||
441 | spin_lock_bh(&bg->fcoe_rx_list.lock); | 440 | spin_lock_bh(&bg->fcoe_rx_list.lock); |
442 | while ((skb = __skb_dequeue(&bg->fcoe_rx_list)) != NULL) { | 441 | while ((skb = __skb_dequeue(&bg->fcoe_rx_list)) != NULL) { |
443 | spin_unlock_bh(&bg->fcoe_rx_list.lock); | 442 | spin_unlock_bh(&bg->fcoe_rx_list.lock); |
444 | bnx2fc_recv_frame(skb); | 443 | bnx2fc_recv_frame(skb); |
445 | spin_lock_bh(&bg->fcoe_rx_list.lock); | 444 | spin_lock_bh(&bg->fcoe_rx_list.lock); |
446 | } | 445 | } |
446 | __set_current_state(TASK_INTERRUPTIBLE); | ||
447 | spin_unlock_bh(&bg->fcoe_rx_list.lock); | 447 | spin_unlock_bh(&bg->fcoe_rx_list.lock); |
448 | set_current_state(TASK_INTERRUPTIBLE); | ||
449 | } | 448 | } |
450 | set_current_state(TASK_RUNNING); | 449 | __set_current_state(TASK_RUNNING); |
451 | return 0; | 450 | return 0; |
452 | } | 451 | } |
453 | 452 | ||
@@ -569,7 +568,6 @@ int bnx2fc_percpu_io_thread(void *arg) | |||
569 | set_current_state(TASK_INTERRUPTIBLE); | 568 | set_current_state(TASK_INTERRUPTIBLE); |
570 | while (!kthread_should_stop()) { | 569 | while (!kthread_should_stop()) { |
571 | schedule(); | 570 | schedule(); |
572 | set_current_state(TASK_RUNNING); | ||
573 | spin_lock_bh(&p->fp_work_lock); | 571 | spin_lock_bh(&p->fp_work_lock); |
574 | while (!list_empty(&p->work_list)) { | 572 | while (!list_empty(&p->work_list)) { |
575 | list_splice_init(&p->work_list, &work_list); | 573 | list_splice_init(&p->work_list, &work_list); |
@@ -583,10 +581,10 @@ int bnx2fc_percpu_io_thread(void *arg) | |||
583 | 581 | ||
584 | spin_lock_bh(&p->fp_work_lock); | 582 | spin_lock_bh(&p->fp_work_lock); |
585 | } | 583 | } |
584 | __set_current_state(TASK_INTERRUPTIBLE); | ||
586 | spin_unlock_bh(&p->fp_work_lock); | 585 | spin_unlock_bh(&p->fp_work_lock); |
587 | set_current_state(TASK_INTERRUPTIBLE); | ||
588 | } | 586 | } |
589 | set_current_state(TASK_RUNNING); | 587 | __set_current_state(TASK_RUNNING); |
590 | 588 | ||
591 | return 0; | 589 | return 0; |
592 | } | 590 | } |
@@ -661,31 +659,6 @@ static int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev) | |||
661 | return 0; | 659 | return 0; |
662 | } | 660 | } |
663 | 661 | ||
664 | static int bnx2fc_mfs_update(struct fc_lport *lport) | ||
665 | { | ||
666 | struct fcoe_port *port = lport_priv(lport); | ||
667 | struct bnx2fc_hba *hba = port->priv; | ||
668 | struct net_device *netdev = hba->netdev; | ||
669 | u32 mfs; | ||
670 | u32 max_mfs; | ||
671 | |||
672 | mfs = netdev->mtu - (sizeof(struct fcoe_hdr) + | ||
673 | sizeof(struct fcoe_crc_eof)); | ||
674 | max_mfs = BNX2FC_MAX_PAYLOAD + sizeof(struct fc_frame_header); | ||
675 | BNX2FC_HBA_DBG(lport, "mfs = %d, max_mfs = %d\n", mfs, max_mfs); | ||
676 | if (mfs > max_mfs) | ||
677 | mfs = max_mfs; | ||
678 | |||
679 | /* Adjust mfs to be a multiple of 256 bytes */ | ||
680 | mfs = (((mfs - sizeof(struct fc_frame_header)) / BNX2FC_MIN_PAYLOAD) * | ||
681 | BNX2FC_MIN_PAYLOAD); | ||
682 | mfs = mfs + sizeof(struct fc_frame_header); | ||
683 | |||
684 | BNX2FC_HBA_DBG(lport, "Set MFS = %d\n", mfs); | ||
685 | if (fc_set_mfs(lport, mfs)) | ||
686 | return -EINVAL; | ||
687 | return 0; | ||
688 | } | ||
689 | static void bnx2fc_link_speed_update(struct fc_lport *lport) | 662 | static void bnx2fc_link_speed_update(struct fc_lport *lport) |
690 | { | 663 | { |
691 | struct fcoe_port *port = lport_priv(lport); | 664 | struct fcoe_port *port = lport_priv(lport); |
@@ -754,7 +727,7 @@ static int bnx2fc_net_config(struct fc_lport *lport) | |||
754 | !hba->phys_dev->ethtool_ops->get_pauseparam) | 727 | !hba->phys_dev->ethtool_ops->get_pauseparam) |
755 | return -EOPNOTSUPP; | 728 | return -EOPNOTSUPP; |
756 | 729 | ||
757 | if (bnx2fc_mfs_update(lport)) | 730 | if (fc_set_mfs(lport, BNX2FC_MFS)) |
758 | return -EINVAL; | 731 | return -EINVAL; |
759 | 732 | ||
760 | skb_queue_head_init(&port->fcoe_pending_queue); | 733 | skb_queue_head_init(&port->fcoe_pending_queue); |
@@ -825,14 +798,6 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event) | |||
825 | if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state)) | 798 | if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state)) |
826 | printk(KERN_ERR "indicate_netevent: "\ | 799 | printk(KERN_ERR "indicate_netevent: "\ |
827 | "adapter is not UP!!\n"); | 800 | "adapter is not UP!!\n"); |
828 | /* fall thru to update mfs if MTU has changed */ | ||
829 | case NETDEV_CHANGEMTU: | ||
830 | BNX2FC_HBA_DBG(lport, "NETDEV_CHANGEMTU event\n"); | ||
831 | bnx2fc_mfs_update(lport); | ||
832 | mutex_lock(&lport->lp_mutex); | ||
833 | list_for_each_entry(vport, &lport->vports, list) | ||
834 | bnx2fc_mfs_update(vport); | ||
835 | mutex_unlock(&lport->lp_mutex); | ||
836 | break; | 801 | break; |
837 | 802 | ||
838 | case NETDEV_DOWN: | 803 | case NETDEV_DOWN: |
@@ -1095,13 +1060,6 @@ static int bnx2fc_netdev_setup(struct bnx2fc_hba *hba) | |||
1095 | struct netdev_hw_addr *ha; | 1060 | struct netdev_hw_addr *ha; |
1096 | int sel_san_mac = 0; | 1061 | int sel_san_mac = 0; |
1097 | 1062 | ||
1098 | /* Do not support for bonding device */ | ||
1099 | if ((netdev->priv_flags & IFF_MASTER_ALB) || | ||
1100 | (netdev->priv_flags & IFF_SLAVE_INACTIVE) || | ||
1101 | (netdev->priv_flags & IFF_MASTER_8023AD)) { | ||
1102 | return -EOPNOTSUPP; | ||
1103 | } | ||
1104 | |||
1105 | /* setup Source MAC Address */ | 1063 | /* setup Source MAC Address */ |
1106 | rcu_read_lock(); | 1064 | rcu_read_lock(); |
1107 | for_each_dev_addr(physdev, ha) { | 1065 | for_each_dev_addr(physdev, ha) { |
@@ -1432,16 +1390,9 @@ static int bnx2fc_destroy(struct net_device *netdev) | |||
1432 | struct net_device *phys_dev; | 1390 | struct net_device *phys_dev; |
1433 | int rc = 0; | 1391 | int rc = 0; |
1434 | 1392 | ||
1435 | if (!rtnl_trylock()) | 1393 | rtnl_lock(); |
1436 | return restart_syscall(); | ||
1437 | 1394 | ||
1438 | mutex_lock(&bnx2fc_dev_lock); | 1395 | mutex_lock(&bnx2fc_dev_lock); |
1439 | #ifdef CONFIG_SCSI_BNX2X_FCOE_MODULE | ||
1440 | if (THIS_MODULE->state != MODULE_STATE_LIVE) { | ||
1441 | rc = -ENODEV; | ||
1442 | goto netdev_err; | ||
1443 | } | ||
1444 | #endif | ||
1445 | /* obtain physical netdev */ | 1396 | /* obtain physical netdev */ |
1446 | if (netdev->priv_flags & IFF_802_1Q_VLAN) | 1397 | if (netdev->priv_flags & IFF_802_1Q_VLAN) |
1447 | phys_dev = vlan_dev_real_dev(netdev); | 1398 | phys_dev = vlan_dev_real_dev(netdev); |
@@ -1805,18 +1756,10 @@ static int bnx2fc_disable(struct net_device *netdev) | |||
1805 | struct ethtool_drvinfo drvinfo; | 1756 | struct ethtool_drvinfo drvinfo; |
1806 | int rc = 0; | 1757 | int rc = 0; |
1807 | 1758 | ||
1808 | if (!rtnl_trylock()) { | 1759 | rtnl_lock(); |
1809 | printk(KERN_ERR PFX "retrying for rtnl_lock\n"); | ||
1810 | return -EIO; | ||
1811 | } | ||
1812 | 1760 | ||
1813 | mutex_lock(&bnx2fc_dev_lock); | 1761 | mutex_lock(&bnx2fc_dev_lock); |
1814 | 1762 | ||
1815 | if (THIS_MODULE->state != MODULE_STATE_LIVE) { | ||
1816 | rc = -ENODEV; | ||
1817 | goto nodev; | ||
1818 | } | ||
1819 | |||
1820 | /* obtain physical netdev */ | 1763 | /* obtain physical netdev */ |
1821 | if (netdev->priv_flags & IFF_802_1Q_VLAN) | 1764 | if (netdev->priv_flags & IFF_802_1Q_VLAN) |
1822 | phys_dev = vlan_dev_real_dev(netdev); | 1765 | phys_dev = vlan_dev_real_dev(netdev); |
@@ -1867,19 +1810,11 @@ static int bnx2fc_enable(struct net_device *netdev) | |||
1867 | struct ethtool_drvinfo drvinfo; | 1810 | struct ethtool_drvinfo drvinfo; |
1868 | int rc = 0; | 1811 | int rc = 0; |
1869 | 1812 | ||
1870 | if (!rtnl_trylock()) { | 1813 | rtnl_lock(); |
1871 | printk(KERN_ERR PFX "retrying for rtnl_lock\n"); | ||
1872 | return -EIO; | ||
1873 | } | ||
1874 | 1814 | ||
1875 | BNX2FC_MISC_DBG("Entered %s\n", __func__); | 1815 | BNX2FC_MISC_DBG("Entered %s\n", __func__); |
1876 | mutex_lock(&bnx2fc_dev_lock); | 1816 | mutex_lock(&bnx2fc_dev_lock); |
1877 | 1817 | ||
1878 | if (THIS_MODULE->state != MODULE_STATE_LIVE) { | ||
1879 | rc = -ENODEV; | ||
1880 | goto nodev; | ||
1881 | } | ||
1882 | |||
1883 | /* obtain physical netdev */ | 1818 | /* obtain physical netdev */ |
1884 | if (netdev->priv_flags & IFF_802_1Q_VLAN) | 1819 | if (netdev->priv_flags & IFF_802_1Q_VLAN) |
1885 | phys_dev = vlan_dev_real_dev(netdev); | 1820 | phys_dev = vlan_dev_real_dev(netdev); |
@@ -1942,18 +1877,9 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode) | |||
1942 | return -EIO; | 1877 | return -EIO; |
1943 | } | 1878 | } |
1944 | 1879 | ||
1945 | if (!rtnl_trylock()) { | 1880 | rtnl_lock(); |
1946 | printk(KERN_ERR "trying for rtnl_lock\n"); | ||
1947 | return -EIO; | ||
1948 | } | ||
1949 | mutex_lock(&bnx2fc_dev_lock); | ||
1950 | 1881 | ||
1951 | #ifdef CONFIG_SCSI_BNX2X_FCOE_MODULE | 1882 | mutex_lock(&bnx2fc_dev_lock); |
1952 | if (THIS_MODULE->state != MODULE_STATE_LIVE) { | ||
1953 | rc = -ENODEV; | ||
1954 | goto mod_err; | ||
1955 | } | ||
1956 | #endif | ||
1957 | 1883 | ||
1958 | if (!try_module_get(THIS_MODULE)) { | 1884 | if (!try_module_get(THIS_MODULE)) { |
1959 | rc = -EINVAL; | 1885 | rc = -EINVAL; |
@@ -2506,7 +2432,7 @@ static struct scsi_host_template bnx2fc_shost_template = { | |||
2506 | .change_queue_type = fc_change_queue_type, | 2432 | .change_queue_type = fc_change_queue_type, |
2507 | .this_id = -1, | 2433 | .this_id = -1, |
2508 | .cmd_per_lun = 3, | 2434 | .cmd_per_lun = 3, |
2509 | .can_queue = (BNX2FC_MAX_OUTSTANDING_CMNDS/2), | 2435 | .can_queue = BNX2FC_CAN_QUEUE, |
2510 | .use_clustering = ENABLE_CLUSTERING, | 2436 | .use_clustering = ENABLE_CLUSTERING, |
2511 | .sg_tablesize = BNX2FC_MAX_BDS_PER_CMD, | 2437 | .sg_tablesize = BNX2FC_MAX_BDS_PER_CMD, |
2512 | .max_sectors = 512, | 2438 | .max_sectors = 512, |
diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c index 4f4096836742..1b680e288c56 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c | |||
@@ -87,7 +87,7 @@ int bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba) | |||
87 | fcoe_init1.task_list_pbl_addr_lo = (u32) hba->task_ctx_bd_dma; | 87 | fcoe_init1.task_list_pbl_addr_lo = (u32) hba->task_ctx_bd_dma; |
88 | fcoe_init1.task_list_pbl_addr_hi = | 88 | fcoe_init1.task_list_pbl_addr_hi = |
89 | (u32) ((u64) hba->task_ctx_bd_dma >> 32); | 89 | (u32) ((u64) hba->task_ctx_bd_dma >> 32); |
90 | fcoe_init1.mtu = hba->netdev->mtu; | 90 | fcoe_init1.mtu = BNX2FC_MINI_JUMBO_MTU; |
91 | 91 | ||
92 | fcoe_init1.flags = (PAGE_SHIFT << | 92 | fcoe_init1.flags = (PAGE_SHIFT << |
93 | FCOE_KWQE_INIT1_LOG_PAGE_SIZE_SHIFT); | 93 | FCOE_KWQE_INIT1_LOG_PAGE_SIZE_SHIFT); |
@@ -590,7 +590,10 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) | |||
590 | 590 | ||
591 | num_rq = (frame_len + BNX2FC_RQ_BUF_SZ - 1) / BNX2FC_RQ_BUF_SZ; | 591 | num_rq = (frame_len + BNX2FC_RQ_BUF_SZ - 1) / BNX2FC_RQ_BUF_SZ; |
592 | 592 | ||
593 | spin_lock_bh(&tgt->tgt_lock); | ||
593 | rq_data = (unsigned char *)bnx2fc_get_next_rqe(tgt, num_rq); | 594 | rq_data = (unsigned char *)bnx2fc_get_next_rqe(tgt, num_rq); |
595 | spin_unlock_bh(&tgt->tgt_lock); | ||
596 | |||
594 | if (rq_data) { | 597 | if (rq_data) { |
595 | buf = rq_data; | 598 | buf = rq_data; |
596 | } else { | 599 | } else { |
@@ -603,8 +606,10 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) | |||
603 | } | 606 | } |
604 | 607 | ||
605 | for (i = 0; i < num_rq; i++) { | 608 | for (i = 0; i < num_rq; i++) { |
609 | spin_lock_bh(&tgt->tgt_lock); | ||
606 | rq_data = (unsigned char *) | 610 | rq_data = (unsigned char *) |
607 | bnx2fc_get_next_rqe(tgt, 1); | 611 | bnx2fc_get_next_rqe(tgt, 1); |
612 | spin_unlock_bh(&tgt->tgt_lock); | ||
608 | len = BNX2FC_RQ_BUF_SZ; | 613 | len = BNX2FC_RQ_BUF_SZ; |
609 | memcpy(buf1, rq_data, len); | 614 | memcpy(buf1, rq_data, len); |
610 | buf1 += len; | 615 | buf1 += len; |
@@ -615,13 +620,15 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) | |||
615 | 620 | ||
616 | if (buf != rq_data) | 621 | if (buf != rq_data) |
617 | kfree(buf); | 622 | kfree(buf); |
623 | spin_lock_bh(&tgt->tgt_lock); | ||
618 | bnx2fc_return_rqe(tgt, num_rq); | 624 | bnx2fc_return_rqe(tgt, num_rq); |
625 | spin_unlock_bh(&tgt->tgt_lock); | ||
619 | break; | 626 | break; |
620 | 627 | ||
621 | case FCOE_ERROR_DETECTION_CQE_TYPE: | 628 | case FCOE_ERROR_DETECTION_CQE_TYPE: |
622 | /* | 629 | /* |
623 | *In case of error reporting CQE a single RQ entry | 630 | * In case of error reporting CQE a single RQ entry |
624 | * is consumes. | 631 | * is consumed. |
625 | */ | 632 | */ |
626 | spin_lock_bh(&tgt->tgt_lock); | 633 | spin_lock_bh(&tgt->tgt_lock); |
627 | num_rq = 1; | 634 | num_rq = 1; |
@@ -705,6 +712,7 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) | |||
705 | *In case of warning reporting CQE a single RQ entry | 712 | *In case of warning reporting CQE a single RQ entry |
706 | * is consumes. | 713 | * is consumes. |
707 | */ | 714 | */ |
715 | spin_lock_bh(&tgt->tgt_lock); | ||
708 | num_rq = 1; | 716 | num_rq = 1; |
709 | err_entry = (struct fcoe_err_report_entry *) | 717 | err_entry = (struct fcoe_err_report_entry *) |
710 | bnx2fc_get_next_rqe(tgt, 1); | 718 | bnx2fc_get_next_rqe(tgt, 1); |
@@ -717,6 +725,7 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) | |||
717 | err_entry->tx_buf_off, err_entry->rx_buf_off); | 725 | err_entry->tx_buf_off, err_entry->rx_buf_off); |
718 | 726 | ||
719 | bnx2fc_return_rqe(tgt, 1); | 727 | bnx2fc_return_rqe(tgt, 1); |
728 | spin_unlock_bh(&tgt->tgt_lock); | ||
720 | break; | 729 | break; |
721 | 730 | ||
722 | default: | 731 | default: |
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 0f1dd23730db..d3fc302c241a 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c | |||
@@ -11,6 +11,9 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include "bnx2fc.h" | 13 | #include "bnx2fc.h" |
14 | |||
15 | #define RESERVE_FREE_LIST_INDEX num_possible_cpus() | ||
16 | |||
14 | static int bnx2fc_split_bd(struct bnx2fc_cmd *io_req, u64 addr, int sg_len, | 17 | static int bnx2fc_split_bd(struct bnx2fc_cmd *io_req, u64 addr, int sg_len, |
15 | int bd_index); | 18 | int bd_index); |
16 | static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req); | 19 | static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req); |
@@ -242,8 +245,9 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba, | |||
242 | u32 mem_size; | 245 | u32 mem_size; |
243 | u16 xid; | 246 | u16 xid; |
244 | int i; | 247 | int i; |
245 | int num_ios; | 248 | int num_ios, num_pri_ios; |
246 | size_t bd_tbl_sz; | 249 | size_t bd_tbl_sz; |
250 | int arr_sz = num_possible_cpus() + 1; | ||
247 | 251 | ||
248 | if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN) { | 252 | if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN) { |
249 | printk(KERN_ERR PFX "cmd_mgr_alloc: Invalid min_xid 0x%x \ | 253 | printk(KERN_ERR PFX "cmd_mgr_alloc: Invalid min_xid 0x%x \ |
@@ -263,14 +267,14 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba, | |||
263 | } | 267 | } |
264 | 268 | ||
265 | cmgr->free_list = kzalloc(sizeof(*cmgr->free_list) * | 269 | cmgr->free_list = kzalloc(sizeof(*cmgr->free_list) * |
266 | num_possible_cpus(), GFP_KERNEL); | 270 | arr_sz, GFP_KERNEL); |
267 | if (!cmgr->free_list) { | 271 | if (!cmgr->free_list) { |
268 | printk(KERN_ERR PFX "failed to alloc free_list\n"); | 272 | printk(KERN_ERR PFX "failed to alloc free_list\n"); |
269 | goto mem_err; | 273 | goto mem_err; |
270 | } | 274 | } |
271 | 275 | ||
272 | cmgr->free_list_lock = kzalloc(sizeof(*cmgr->free_list_lock) * | 276 | cmgr->free_list_lock = kzalloc(sizeof(*cmgr->free_list_lock) * |
273 | num_possible_cpus(), GFP_KERNEL); | 277 | arr_sz, GFP_KERNEL); |
274 | if (!cmgr->free_list_lock) { | 278 | if (!cmgr->free_list_lock) { |
275 | printk(KERN_ERR PFX "failed to alloc free_list_lock\n"); | 279 | printk(KERN_ERR PFX "failed to alloc free_list_lock\n"); |
276 | goto mem_err; | 280 | goto mem_err; |
@@ -279,13 +283,18 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba, | |||
279 | cmgr->hba = hba; | 283 | cmgr->hba = hba; |
280 | cmgr->cmds = (struct bnx2fc_cmd **)(cmgr + 1); | 284 | cmgr->cmds = (struct bnx2fc_cmd **)(cmgr + 1); |
281 | 285 | ||
282 | for (i = 0; i < num_possible_cpus(); i++) { | 286 | for (i = 0; i < arr_sz; i++) { |
283 | INIT_LIST_HEAD(&cmgr->free_list[i]); | 287 | INIT_LIST_HEAD(&cmgr->free_list[i]); |
284 | spin_lock_init(&cmgr->free_list_lock[i]); | 288 | spin_lock_init(&cmgr->free_list_lock[i]); |
285 | } | 289 | } |
286 | 290 | ||
287 | /* Pre-allocated pool of bnx2fc_cmds */ | 291 | /* |
292 | * Pre-allocated pool of bnx2fc_cmds. | ||
293 | * Last entry in the free list array is the free list | ||
294 | * of slow path requests. | ||
295 | */ | ||
288 | xid = BNX2FC_MIN_XID; | 296 | xid = BNX2FC_MIN_XID; |
297 | num_pri_ios = num_ios - BNX2FC_ELSTM_XIDS; | ||
289 | for (i = 0; i < num_ios; i++) { | 298 | for (i = 0; i < num_ios; i++) { |
290 | io_req = kzalloc(sizeof(*io_req), GFP_KERNEL); | 299 | io_req = kzalloc(sizeof(*io_req), GFP_KERNEL); |
291 | 300 | ||
@@ -298,11 +307,13 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba, | |||
298 | INIT_DELAYED_WORK(&io_req->timeout_work, bnx2fc_cmd_timeout); | 307 | INIT_DELAYED_WORK(&io_req->timeout_work, bnx2fc_cmd_timeout); |
299 | 308 | ||
300 | io_req->xid = xid++; | 309 | io_req->xid = xid++; |
301 | if (io_req->xid >= BNX2FC_MAX_OUTSTANDING_CMNDS) | 310 | if (i < num_pri_ios) |
302 | printk(KERN_ERR PFX "ERROR allocating xids - 0x%x\n", | 311 | list_add_tail(&io_req->link, |
303 | io_req->xid); | 312 | &cmgr->free_list[io_req->xid % |
304 | list_add_tail(&io_req->link, | 313 | num_possible_cpus()]); |
305 | &cmgr->free_list[io_req->xid % num_possible_cpus()]); | 314 | else |
315 | list_add_tail(&io_req->link, | ||
316 | &cmgr->free_list[num_possible_cpus()]); | ||
306 | io_req++; | 317 | io_req++; |
307 | } | 318 | } |
308 | 319 | ||
@@ -389,7 +400,7 @@ free_cmd_pool: | |||
389 | if (!cmgr->free_list) | 400 | if (!cmgr->free_list) |
390 | goto free_cmgr; | 401 | goto free_cmgr; |
391 | 402 | ||
392 | for (i = 0; i < num_possible_cpus(); i++) { | 403 | for (i = 0; i < num_possible_cpus() + 1; i++) { |
393 | struct list_head *list; | 404 | struct list_head *list; |
394 | struct list_head *tmp; | 405 | struct list_head *tmp; |
395 | 406 | ||
@@ -413,6 +424,7 @@ struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type) | |||
413 | struct bnx2fc_cmd *io_req; | 424 | struct bnx2fc_cmd *io_req; |
414 | struct list_head *listp; | 425 | struct list_head *listp; |
415 | struct io_bdt *bd_tbl; | 426 | struct io_bdt *bd_tbl; |
427 | int index = RESERVE_FREE_LIST_INDEX; | ||
416 | u32 max_sqes; | 428 | u32 max_sqes; |
417 | u16 xid; | 429 | u16 xid; |
418 | 430 | ||
@@ -432,26 +444,26 @@ struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type) | |||
432 | * NOTE: Free list insertions and deletions are protected with | 444 | * NOTE: Free list insertions and deletions are protected with |
433 | * cmgr lock | 445 | * cmgr lock |
434 | */ | 446 | */ |
435 | spin_lock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]); | 447 | spin_lock_bh(&cmd_mgr->free_list_lock[index]); |
436 | if ((list_empty(&(cmd_mgr->free_list[smp_processor_id()]))) || | 448 | if ((list_empty(&(cmd_mgr->free_list[index]))) || |
437 | (tgt->num_active_ios.counter >= max_sqes)) { | 449 | (tgt->num_active_ios.counter >= max_sqes)) { |
438 | BNX2FC_TGT_DBG(tgt, "No free els_tm cmds available " | 450 | BNX2FC_TGT_DBG(tgt, "No free els_tm cmds available " |
439 | "ios(%d):sqes(%d)\n", | 451 | "ios(%d):sqes(%d)\n", |
440 | tgt->num_active_ios.counter, tgt->max_sqes); | 452 | tgt->num_active_ios.counter, tgt->max_sqes); |
441 | if (list_empty(&(cmd_mgr->free_list[smp_processor_id()]))) | 453 | if (list_empty(&(cmd_mgr->free_list[index]))) |
442 | printk(KERN_ERR PFX "elstm_alloc: list_empty\n"); | 454 | printk(KERN_ERR PFX "elstm_alloc: list_empty\n"); |
443 | spin_unlock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]); | 455 | spin_unlock_bh(&cmd_mgr->free_list_lock[index]); |
444 | return NULL; | 456 | return NULL; |
445 | } | 457 | } |
446 | 458 | ||
447 | listp = (struct list_head *) | 459 | listp = (struct list_head *) |
448 | cmd_mgr->free_list[smp_processor_id()].next; | 460 | cmd_mgr->free_list[index].next; |
449 | list_del_init(listp); | 461 | list_del_init(listp); |
450 | io_req = (struct bnx2fc_cmd *) listp; | 462 | io_req = (struct bnx2fc_cmd *) listp; |
451 | xid = io_req->xid; | 463 | xid = io_req->xid; |
452 | cmd_mgr->cmds[xid] = io_req; | 464 | cmd_mgr->cmds[xid] = io_req; |
453 | atomic_inc(&tgt->num_active_ios); | 465 | atomic_inc(&tgt->num_active_ios); |
454 | spin_unlock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]); | 466 | spin_unlock_bh(&cmd_mgr->free_list_lock[index]); |
455 | 467 | ||
456 | INIT_LIST_HEAD(&io_req->link); | 468 | INIT_LIST_HEAD(&io_req->link); |
457 | 469 | ||
@@ -479,27 +491,30 @@ static struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt) | |||
479 | struct io_bdt *bd_tbl; | 491 | struct io_bdt *bd_tbl; |
480 | u32 max_sqes; | 492 | u32 max_sqes; |
481 | u16 xid; | 493 | u16 xid; |
494 | int index = get_cpu(); | ||
482 | 495 | ||
483 | max_sqes = BNX2FC_SCSI_MAX_SQES; | 496 | max_sqes = BNX2FC_SCSI_MAX_SQES; |
484 | /* | 497 | /* |
485 | * NOTE: Free list insertions and deletions are protected with | 498 | * NOTE: Free list insertions and deletions are protected with |
486 | * cmgr lock | 499 | * cmgr lock |
487 | */ | 500 | */ |
488 | spin_lock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]); | 501 | spin_lock_bh(&cmd_mgr->free_list_lock[index]); |
489 | if ((list_empty(&cmd_mgr->free_list[smp_processor_id()])) || | 502 | if ((list_empty(&cmd_mgr->free_list[index])) || |
490 | (tgt->num_active_ios.counter >= max_sqes)) { | 503 | (tgt->num_active_ios.counter >= max_sqes)) { |
491 | spin_unlock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]); | 504 | spin_unlock_bh(&cmd_mgr->free_list_lock[index]); |
505 | put_cpu(); | ||
492 | return NULL; | 506 | return NULL; |
493 | } | 507 | } |
494 | 508 | ||
495 | listp = (struct list_head *) | 509 | listp = (struct list_head *) |
496 | cmd_mgr->free_list[smp_processor_id()].next; | 510 | cmd_mgr->free_list[index].next; |
497 | list_del_init(listp); | 511 | list_del_init(listp); |
498 | io_req = (struct bnx2fc_cmd *) listp; | 512 | io_req = (struct bnx2fc_cmd *) listp; |
499 | xid = io_req->xid; | 513 | xid = io_req->xid; |
500 | cmd_mgr->cmds[xid] = io_req; | 514 | cmd_mgr->cmds[xid] = io_req; |
501 | atomic_inc(&tgt->num_active_ios); | 515 | atomic_inc(&tgt->num_active_ios); |
502 | spin_unlock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]); | 516 | spin_unlock_bh(&cmd_mgr->free_list_lock[index]); |
517 | put_cpu(); | ||
503 | 518 | ||
504 | INIT_LIST_HEAD(&io_req->link); | 519 | INIT_LIST_HEAD(&io_req->link); |
505 | 520 | ||
@@ -522,8 +537,15 @@ void bnx2fc_cmd_release(struct kref *ref) | |||
522 | struct bnx2fc_cmd *io_req = container_of(ref, | 537 | struct bnx2fc_cmd *io_req = container_of(ref, |
523 | struct bnx2fc_cmd, refcount); | 538 | struct bnx2fc_cmd, refcount); |
524 | struct bnx2fc_cmd_mgr *cmd_mgr = io_req->cmd_mgr; | 539 | struct bnx2fc_cmd_mgr *cmd_mgr = io_req->cmd_mgr; |
540 | int index; | ||
541 | |||
542 | if (io_req->cmd_type == BNX2FC_SCSI_CMD) | ||
543 | index = io_req->xid % num_possible_cpus(); | ||
544 | else | ||
545 | index = RESERVE_FREE_LIST_INDEX; | ||
525 | 546 | ||
526 | spin_lock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]); | 547 | |
548 | spin_lock_bh(&cmd_mgr->free_list_lock[index]); | ||
527 | if (io_req->cmd_type != BNX2FC_SCSI_CMD) | 549 | if (io_req->cmd_type != BNX2FC_SCSI_CMD) |
528 | bnx2fc_free_mp_resc(io_req); | 550 | bnx2fc_free_mp_resc(io_req); |
529 | cmd_mgr->cmds[io_req->xid] = NULL; | 551 | cmd_mgr->cmds[io_req->xid] = NULL; |
@@ -531,9 +553,10 @@ void bnx2fc_cmd_release(struct kref *ref) | |||
531 | list_del_init(&io_req->link); | 553 | list_del_init(&io_req->link); |
532 | /* Add it to the free list */ | 554 | /* Add it to the free list */ |
533 | list_add(&io_req->link, | 555 | list_add(&io_req->link, |
534 | &cmd_mgr->free_list[smp_processor_id()]); | 556 | &cmd_mgr->free_list[index]); |
535 | atomic_dec(&io_req->tgt->num_active_ios); | 557 | atomic_dec(&io_req->tgt->num_active_ios); |
536 | spin_unlock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]); | 558 | spin_unlock_bh(&cmd_mgr->free_list_lock[index]); |
559 | |||
537 | } | 560 | } |
538 | 561 | ||
539 | static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req) | 562 | static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req) |
diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c index 7ea93af60260..7cc05e4e82d5 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c +++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c | |||
@@ -304,10 +304,8 @@ static void bnx2fc_upload_session(struct fcoe_port *port, | |||
304 | " not sent to FW\n"); | 304 | " not sent to FW\n"); |
305 | 305 | ||
306 | /* Free session resources */ | 306 | /* Free session resources */ |
307 | spin_lock_bh(&tgt->cq_lock); | ||
308 | bnx2fc_free_session_resc(hba, tgt); | 307 | bnx2fc_free_session_resc(hba, tgt); |
309 | bnx2fc_free_conn_id(hba, tgt->fcoe_conn_id); | 308 | bnx2fc_free_conn_id(hba, tgt->fcoe_conn_id); |
310 | spin_unlock_bh(&tgt->cq_lock); | ||
311 | } | 309 | } |
312 | 310 | ||
313 | static int bnx2fc_init_tgt(struct bnx2fc_rport *tgt, | 311 | static int bnx2fc_init_tgt(struct bnx2fc_rport *tgt, |
@@ -830,11 +828,13 @@ static void bnx2fc_free_session_resc(struct bnx2fc_hba *hba, | |||
830 | tgt->rq = NULL; | 828 | tgt->rq = NULL; |
831 | } | 829 | } |
832 | /* Free CQ */ | 830 | /* Free CQ */ |
831 | spin_lock_bh(&tgt->cq_lock); | ||
833 | if (tgt->cq) { | 832 | if (tgt->cq) { |
834 | dma_free_coherent(&hba->pcidev->dev, tgt->cq_mem_size, | 833 | dma_free_coherent(&hba->pcidev->dev, tgt->cq_mem_size, |
835 | tgt->cq, tgt->cq_dma); | 834 | tgt->cq, tgt->cq_dma); |
836 | tgt->cq = NULL; | 835 | tgt->cq = NULL; |
837 | } | 836 | } |
837 | spin_unlock_bh(&tgt->cq_lock); | ||
838 | /* Free SQ */ | 838 | /* Free SQ */ |
839 | if (tgt->sq) { | 839 | if (tgt->sq) { |
840 | dma_free_coherent(&hba->pcidev->dev, tgt->sq_mem_size, | 840 | dma_free_coherent(&hba->pcidev->dev, tgt->sq_mem_size, |
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index 8eeb39ffa37f..e98ae33f1295 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c | |||
@@ -132,14 +132,25 @@ static void iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv) | |||
132 | if (page_count(sg_page(sg)) >= 1 && !recv) | 132 | if (page_count(sg_page(sg)) >= 1 && !recv) |
133 | return; | 133 | return; |
134 | 134 | ||
135 | segment->sg_mapped = kmap_atomic(sg_page(sg), KM_SOFTIRQ0); | 135 | if (recv) { |
136 | segment->atomic_mapped = true; | ||
137 | segment->sg_mapped = kmap_atomic(sg_page(sg), KM_SOFTIRQ0); | ||
138 | } else { | ||
139 | segment->atomic_mapped = false; | ||
140 | /* the xmit path can sleep with the page mapped so use kmap */ | ||
141 | segment->sg_mapped = kmap(sg_page(sg)); | ||
142 | } | ||
143 | |||
136 | segment->data = segment->sg_mapped + sg->offset + segment->sg_offset; | 144 | segment->data = segment->sg_mapped + sg->offset + segment->sg_offset; |
137 | } | 145 | } |
138 | 146 | ||
139 | void iscsi_tcp_segment_unmap(struct iscsi_segment *segment) | 147 | void iscsi_tcp_segment_unmap(struct iscsi_segment *segment) |
140 | { | 148 | { |
141 | if (segment->sg_mapped) { | 149 | if (segment->sg_mapped) { |
142 | kunmap_atomic(segment->sg_mapped, KM_SOFTIRQ0); | 150 | if (segment->atomic_mapped) |
151 | kunmap_atomic(segment->sg_mapped, KM_SOFTIRQ0); | ||
152 | else | ||
153 | kunmap(sg_page(segment->sg)); | ||
143 | segment->sg_mapped = NULL; | 154 | segment->sg_mapped = NULL; |
144 | segment->data = NULL; | 155 | segment->data = NULL; |
145 | } | 156 | } |
diff --git a/drivers/scsi/lpfc/Makefile b/drivers/scsi/lpfc/Makefile index 14de249917f8..88928f00aa2d 100644 --- a/drivers/scsi/lpfc/Makefile +++ b/drivers/scsi/lpfc/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | #/******************************************************************* | 1 | #/******************************************************************* |
2 | # * This file is part of the Emulex Linux Device Driver for * | 2 | # * This file is part of the Emulex Linux Device Driver for * |
3 | # * Fibre Channel Host Bus Adapters. * | 3 | # * Fibre Channel Host Bus Adapters. * |
4 | # * Copyright (C) 2004-2006 Emulex. All rights reserved. * | 4 | # * Copyright (C) 2004-2011 Emulex. All rights reserved. * |
5 | # * EMULEX and SLI are trademarks of Emulex. * | 5 | # * EMULEX and SLI are trademarks of Emulex. * |
6 | # * www.emulex.com * | 6 | # * www.emulex.com * |
7 | # * * | 7 | # * * |
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index b64c6da870d3..60e98a62f308 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h | |||
@@ -539,6 +539,8 @@ struct lpfc_hba { | |||
539 | (struct lpfc_hba *, uint32_t); | 539 | (struct lpfc_hba *, uint32_t); |
540 | int (*lpfc_hba_down_link) | 540 | int (*lpfc_hba_down_link) |
541 | (struct lpfc_hba *, uint32_t); | 541 | (struct lpfc_hba *, uint32_t); |
542 | int (*lpfc_selective_reset) | ||
543 | (struct lpfc_hba *); | ||
542 | 544 | ||
543 | /* SLI4 specific HBA data structure */ | 545 | /* SLI4 specific HBA data structure */ |
544 | struct lpfc_sli4_hba sli4_hba; | 546 | struct lpfc_sli4_hba sli4_hba; |
@@ -895,7 +897,18 @@ lpfc_worker_wake_up(struct lpfc_hba *phba) | |||
895 | return; | 897 | return; |
896 | } | 898 | } |
897 | 899 | ||
898 | static inline void | 900 | static inline int |
901 | lpfc_readl(void __iomem *addr, uint32_t *data) | ||
902 | { | ||
903 | uint32_t temp; | ||
904 | temp = readl(addr); | ||
905 | if (temp == 0xffffffff) | ||
906 | return -EIO; | ||
907 | *data = temp; | ||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | static inline int | ||
899 | lpfc_sli_read_hs(struct lpfc_hba *phba) | 912 | lpfc_sli_read_hs(struct lpfc_hba *phba) |
900 | { | 913 | { |
901 | /* | 914 | /* |
@@ -904,15 +917,17 @@ lpfc_sli_read_hs(struct lpfc_hba *phba) | |||
904 | */ | 917 | */ |
905 | phba->sli.slistat.err_attn_event++; | 918 | phba->sli.slistat.err_attn_event++; |
906 | 919 | ||
907 | /* Save status info */ | 920 | /* Save status info and check for unplug error */ |
908 | phba->work_hs = readl(phba->HSregaddr); | 921 | if (lpfc_readl(phba->HSregaddr, &phba->work_hs) || |
909 | phba->work_status[0] = readl(phba->MBslimaddr + 0xa8); | 922 | lpfc_readl(phba->MBslimaddr + 0xa8, &phba->work_status[0]) || |
910 | phba->work_status[1] = readl(phba->MBslimaddr + 0xac); | 923 | lpfc_readl(phba->MBslimaddr + 0xac, &phba->work_status[1])) { |
924 | return -EIO; | ||
925 | } | ||
911 | 926 | ||
912 | /* Clear chip Host Attention error bit */ | 927 | /* Clear chip Host Attention error bit */ |
913 | writel(HA_ERATT, phba->HAregaddr); | 928 | writel(HA_ERATT, phba->HAregaddr); |
914 | readl(phba->HAregaddr); /* flush */ | 929 | readl(phba->HAregaddr); /* flush */ |
915 | phba->pport->stopped = 1; | 930 | phba->pport->stopped = 1; |
916 | 931 | ||
917 | return; | 932 | return 0; |
918 | } | 933 | } |
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index e7c020df12fa..4e0faa00b96f 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c | |||
@@ -685,7 +685,7 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type) | |||
685 | * -EIO reset not configured or error posting the event | 685 | * -EIO reset not configured or error posting the event |
686 | * zero for success | 686 | * zero for success |
687 | **/ | 687 | **/ |
688 | static int | 688 | int |
689 | lpfc_selective_reset(struct lpfc_hba *phba) | 689 | lpfc_selective_reset(struct lpfc_hba *phba) |
690 | { | 690 | { |
691 | struct completion online_compl; | 691 | struct completion online_compl; |
@@ -746,7 +746,7 @@ lpfc_issue_reset(struct device *dev, struct device_attribute *attr, | |||
746 | int status = -EINVAL; | 746 | int status = -EINVAL; |
747 | 747 | ||
748 | if (strncmp(buf, "selective", sizeof("selective") - 1) == 0) | 748 | if (strncmp(buf, "selective", sizeof("selective") - 1) == 0) |
749 | status = lpfc_selective_reset(phba); | 749 | status = phba->lpfc_selective_reset(phba); |
750 | 750 | ||
751 | if (status == 0) | 751 | if (status == 0) |
752 | return strlen(buf); | 752 | return strlen(buf); |
@@ -1224,7 +1224,10 @@ lpfc_poll_store(struct device *dev, struct device_attribute *attr, | |||
1224 | if (val & ENABLE_FCP_RING_POLLING) { | 1224 | if (val & ENABLE_FCP_RING_POLLING) { |
1225 | if ((val & DISABLE_FCP_RING_INT) && | 1225 | if ((val & DISABLE_FCP_RING_INT) && |
1226 | !(old_val & DISABLE_FCP_RING_INT)) { | 1226 | !(old_val & DISABLE_FCP_RING_INT)) { |
1227 | creg_val = readl(phba->HCregaddr); | 1227 | if (lpfc_readl(phba->HCregaddr, &creg_val)) { |
1228 | spin_unlock_irq(&phba->hbalock); | ||
1229 | return -EINVAL; | ||
1230 | } | ||
1228 | creg_val &= ~(HC_R0INT_ENA << LPFC_FCP_RING); | 1231 | creg_val &= ~(HC_R0INT_ENA << LPFC_FCP_RING); |
1229 | writel(creg_val, phba->HCregaddr); | 1232 | writel(creg_val, phba->HCregaddr); |
1230 | readl(phba->HCregaddr); /* flush */ | 1233 | readl(phba->HCregaddr); /* flush */ |
@@ -1242,7 +1245,10 @@ lpfc_poll_store(struct device *dev, struct device_attribute *attr, | |||
1242 | spin_unlock_irq(&phba->hbalock); | 1245 | spin_unlock_irq(&phba->hbalock); |
1243 | del_timer(&phba->fcp_poll_timer); | 1246 | del_timer(&phba->fcp_poll_timer); |
1244 | spin_lock_irq(&phba->hbalock); | 1247 | spin_lock_irq(&phba->hbalock); |
1245 | creg_val = readl(phba->HCregaddr); | 1248 | if (lpfc_readl(phba->HCregaddr, &creg_val)) { |
1249 | spin_unlock_irq(&phba->hbalock); | ||
1250 | return -EINVAL; | ||
1251 | } | ||
1246 | creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); | 1252 | creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); |
1247 | writel(creg_val, phba->HCregaddr); | 1253 | writel(creg_val, phba->HCregaddr); |
1248 | readl(phba->HCregaddr); /* flush */ | 1254 | readl(phba->HCregaddr); /* flush */ |
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 0dd43bb91618..793b9f1131fb 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /******************************************************************* | 1 | /******************************************************************* |
2 | * This file is part of the Emulex Linux Device Driver for * | 2 | * This file is part of the Emulex Linux Device Driver for * |
3 | * Fibre Channel Host Bus Adapters. * | 3 | * Fibre Channel Host Bus Adapters. * |
4 | * Copyright (C) 2009-2010 Emulex. All rights reserved. * | 4 | * Copyright (C) 2009-2011 Emulex. All rights reserved. * |
5 | * EMULEX and SLI are trademarks of Emulex. * | 5 | * EMULEX and SLI are trademarks of Emulex. * |
6 | * www.emulex.com * | 6 | * www.emulex.com * |
7 | * * | 7 | * * |
@@ -348,7 +348,10 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job) | |||
348 | dd_data->context_un.iocb.bmp = bmp; | 348 | dd_data->context_un.iocb.bmp = bmp; |
349 | 349 | ||
350 | if (phba->cfg_poll & DISABLE_FCP_RING_INT) { | 350 | if (phba->cfg_poll & DISABLE_FCP_RING_INT) { |
351 | creg_val = readl(phba->HCregaddr); | 351 | if (lpfc_readl(phba->HCregaddr, &creg_val)) { |
352 | rc = -EIO ; | ||
353 | goto free_cmdiocbq; | ||
354 | } | ||
352 | creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); | 355 | creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); |
353 | writel(creg_val, phba->HCregaddr); | 356 | writel(creg_val, phba->HCregaddr); |
354 | readl(phba->HCregaddr); /* flush */ | 357 | readl(phba->HCregaddr); /* flush */ |
@@ -599,7 +602,10 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) | |||
599 | dd_data->context_un.iocb.ndlp = ndlp; | 602 | dd_data->context_un.iocb.ndlp = ndlp; |
600 | 603 | ||
601 | if (phba->cfg_poll & DISABLE_FCP_RING_INT) { | 604 | if (phba->cfg_poll & DISABLE_FCP_RING_INT) { |
602 | creg_val = readl(phba->HCregaddr); | 605 | if (lpfc_readl(phba->HCregaddr, &creg_val)) { |
606 | rc = -EIO; | ||
607 | goto linkdown_err; | ||
608 | } | ||
603 | creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); | 609 | creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); |
604 | writel(creg_val, phba->HCregaddr); | 610 | writel(creg_val, phba->HCregaddr); |
605 | readl(phba->HCregaddr); /* flush */ | 611 | readl(phba->HCregaddr); /* flush */ |
@@ -613,6 +619,7 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) | |||
613 | else | 619 | else |
614 | rc = -EIO; | 620 | rc = -EIO; |
615 | 621 | ||
622 | linkdown_err: | ||
616 | pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, | 623 | pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, |
617 | job->request_payload.sg_cnt, DMA_TO_DEVICE); | 624 | job->request_payload.sg_cnt, DMA_TO_DEVICE); |
618 | pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, | 625 | pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, |
@@ -1357,7 +1364,10 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag, | |||
1357 | dd_data->context_un.iocb.ndlp = ndlp; | 1364 | dd_data->context_un.iocb.ndlp = ndlp; |
1358 | 1365 | ||
1359 | if (phba->cfg_poll & DISABLE_FCP_RING_INT) { | 1366 | if (phba->cfg_poll & DISABLE_FCP_RING_INT) { |
1360 | creg_val = readl(phba->HCregaddr); | 1367 | if (lpfc_readl(phba->HCregaddr, &creg_val)) { |
1368 | rc = -IOCB_ERROR; | ||
1369 | goto issue_ct_rsp_exit; | ||
1370 | } | ||
1361 | creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); | 1371 | creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); |
1362 | writel(creg_val, phba->HCregaddr); | 1372 | writel(creg_val, phba->HCregaddr); |
1363 | readl(phba->HCregaddr); /* flush */ | 1373 | readl(phba->HCregaddr); /* flush */ |
@@ -2479,16 +2489,18 @@ lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) | |||
2479 | 2489 | ||
2480 | from = (uint8_t *)dd_data->context_un.mbox.mb; | 2490 | from = (uint8_t *)dd_data->context_un.mbox.mb; |
2481 | job = dd_data->context_un.mbox.set_job; | 2491 | job = dd_data->context_un.mbox.set_job; |
2482 | size = job->reply_payload.payload_len; | 2492 | if (job) { |
2483 | job->reply->reply_payload_rcv_len = | 2493 | size = job->reply_payload.payload_len; |
2484 | sg_copy_from_buffer(job->reply_payload.sg_list, | 2494 | job->reply->reply_payload_rcv_len = |
2485 | job->reply_payload.sg_cnt, | 2495 | sg_copy_from_buffer(job->reply_payload.sg_list, |
2486 | from, size); | 2496 | job->reply_payload.sg_cnt, |
2487 | job->reply->result = 0; | 2497 | from, size); |
2498 | job->reply->result = 0; | ||
2488 | 2499 | ||
2500 | job->dd_data = NULL; | ||
2501 | job->job_done(job); | ||
2502 | } | ||
2489 | dd_data->context_un.mbox.set_job = NULL; | 2503 | dd_data->context_un.mbox.set_job = NULL; |
2490 | job->dd_data = NULL; | ||
2491 | job->job_done(job); | ||
2492 | /* need to hold the lock until we call job done to hold off | 2504 | /* need to hold the lock until we call job done to hold off |
2493 | * the timeout handler returning to the midlayer while | 2505 | * the timeout handler returning to the midlayer while |
2494 | * we are stillprocessing the job | 2506 | * we are stillprocessing the job |
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 3d40023f4804..f0b332f4eedb 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /******************************************************************* | 1 | /******************************************************************* |
2 | * This file is part of the Emulex Linux Device Driver for * | 2 | * This file is part of the Emulex Linux Device Driver for * |
3 | * Fibre Channel Host Bus Adapters. * | 3 | * Fibre Channel Host Bus Adapters. * |
4 | * Copyright (C) 2004-2010 Emulex. All rights reserved. * | 4 | * Copyright (C) 2004-2011 Emulex. All rights reserved. * |
5 | * EMULEX and SLI are trademarks of Emulex. * | 5 | * EMULEX and SLI are trademarks of Emulex. * |
6 | * www.emulex.com * | 6 | * www.emulex.com * |
7 | * * | 7 | * * |
@@ -254,8 +254,8 @@ uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *); | |||
254 | void lpfc_sli_cancel_iocbs(struct lpfc_hba *, struct list_head *, uint32_t, | 254 | void lpfc_sli_cancel_iocbs(struct lpfc_hba *, struct list_head *, uint32_t, |
255 | uint32_t); | 255 | uint32_t); |
256 | void lpfc_sli_wake_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *); | 256 | void lpfc_sli_wake_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *); |
257 | 257 | int lpfc_selective_reset(struct lpfc_hba *); | |
258 | void lpfc_reset_barrier(struct lpfc_hba * phba); | 258 | void lpfc_reset_barrier(struct lpfc_hba *); |
259 | int lpfc_sli_brdready(struct lpfc_hba *, uint32_t); | 259 | int lpfc_sli_brdready(struct lpfc_hba *, uint32_t); |
260 | int lpfc_sli_brdkill(struct lpfc_hba *); | 260 | int lpfc_sli_brdkill(struct lpfc_hba *); |
261 | int lpfc_sli_brdreset(struct lpfc_hba *); | 261 | int lpfc_sli_brdreset(struct lpfc_hba *); |
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 8e28edf9801e..735028fedda5 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c | |||
@@ -89,7 +89,8 @@ lpfc_els_chk_latt(struct lpfc_vport *vport) | |||
89 | return 0; | 89 | return 0; |
90 | 90 | ||
91 | /* Read the HBA Host Attention Register */ | 91 | /* Read the HBA Host Attention Register */ |
92 | ha_copy = readl(phba->HAregaddr); | 92 | if (lpfc_readl(phba->HAregaddr, &ha_copy)) |
93 | return 1; | ||
93 | 94 | ||
94 | if (!(ha_copy & HA_LATT)) | 95 | if (!(ha_copy & HA_LATT)) |
95 | return 0; | 96 | return 0; |
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 94ae37c5111a..95f11ed79463 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h | |||
@@ -1344,7 +1344,7 @@ typedef struct { /* FireFly BIU registers */ | |||
1344 | #define HS_FFER1 0x80000000 /* Bit 31 */ | 1344 | #define HS_FFER1 0x80000000 /* Bit 31 */ |
1345 | #define HS_CRIT_TEMP 0x00000100 /* Bit 8 */ | 1345 | #define HS_CRIT_TEMP 0x00000100 /* Bit 8 */ |
1346 | #define HS_FFERM 0xFF000100 /* Mask for error bits 31:24 and 8 */ | 1346 | #define HS_FFERM 0xFF000100 /* Mask for error bits 31:24 and 8 */ |
1347 | 1347 | #define UNPLUG_ERR 0x00000001 /* Indicate pci hot unplug */ | |
1348 | /* Host Control Register */ | 1348 | /* Host Control Register */ |
1349 | 1349 | ||
1350 | #define HC_REG_OFFSET 12 /* Byte offset from register base address */ | 1350 | #define HC_REG_OFFSET 12 /* Byte offset from register base address */ |
@@ -1713,6 +1713,17 @@ struct lpfc_pde6 { | |||
1713 | #define pde6_apptagval_WORD word2 | 1713 | #define pde6_apptagval_WORD word2 |
1714 | }; | 1714 | }; |
1715 | 1715 | ||
1716 | struct lpfc_pde7 { | ||
1717 | uint32_t word0; | ||
1718 | #define pde7_type_SHIFT 24 | ||
1719 | #define pde7_type_MASK 0x000000ff | ||
1720 | #define pde7_type_WORD word0 | ||
1721 | #define pde7_rsvd0_SHIFT 0 | ||
1722 | #define pde7_rsvd0_MASK 0x00ffffff | ||
1723 | #define pde7_rsvd0_WORD word0 | ||
1724 | uint32_t addrHigh; | ||
1725 | uint32_t addrLow; | ||
1726 | }; | ||
1716 | 1727 | ||
1717 | /* Structure for MB Command LOAD_SM and DOWN_LOAD */ | 1728 | /* Structure for MB Command LOAD_SM and DOWN_LOAD */ |
1718 | 1729 | ||
@@ -3621,7 +3632,7 @@ typedef struct _IOCB { /* IOCB structure */ | |||
3621 | ASYNCSTAT_FIELDS asyncstat; /* async_status iocb */ | 3632 | ASYNCSTAT_FIELDS asyncstat; /* async_status iocb */ |
3622 | QUE_XRI64_CX_FIELDS quexri64cx; /* que_xri64_cx fields */ | 3633 | QUE_XRI64_CX_FIELDS quexri64cx; /* que_xri64_cx fields */ |
3623 | struct rcv_seq64 rcvseq64; /* RCV_SEQ64 and RCV_CONT64 */ | 3634 | struct rcv_seq64 rcvseq64; /* RCV_SEQ64 and RCV_CONT64 */ |
3624 | struct sli4_bls_acc bls_acc; /* UNSOL ABTS BLS_ACC params */ | 3635 | struct sli4_bls_rsp bls_rsp; /* UNSOL ABTS BLS_RSP params */ |
3625 | uint32_t ulpWord[IOCB_WORD_SZ - 2]; /* generic 6 'words' */ | 3636 | uint32_t ulpWord[IOCB_WORD_SZ - 2]; /* generic 6 'words' */ |
3626 | } un; | 3637 | } un; |
3627 | union { | 3638 | union { |
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index c7178d60c7bf..8433ac0d9fb4 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h | |||
@@ -215,7 +215,7 @@ struct lpfc_sli4_flags { | |||
215 | #define lpfc_fip_flag_WORD word0 | 215 | #define lpfc_fip_flag_WORD word0 |
216 | }; | 216 | }; |
217 | 217 | ||
218 | struct sli4_bls_acc { | 218 | struct sli4_bls_rsp { |
219 | uint32_t word0_rsvd; /* Word0 must be reserved */ | 219 | uint32_t word0_rsvd; /* Word0 must be reserved */ |
220 | uint32_t word1; | 220 | uint32_t word1; |
221 | #define lpfc_abts_orig_SHIFT 0 | 221 | #define lpfc_abts_orig_SHIFT 0 |
@@ -231,6 +231,16 @@ struct sli4_bls_acc { | |||
231 | #define lpfc_abts_oxid_MASK 0x0000FFFF | 231 | #define lpfc_abts_oxid_MASK 0x0000FFFF |
232 | #define lpfc_abts_oxid_WORD word2 | 232 | #define lpfc_abts_oxid_WORD word2 |
233 | uint32_t word3; | 233 | uint32_t word3; |
234 | #define lpfc_vndr_code_SHIFT 0 | ||
235 | #define lpfc_vndr_code_MASK 0x000000FF | ||
236 | #define lpfc_vndr_code_WORD word3 | ||
237 | #define lpfc_rsn_expln_SHIFT 8 | ||
238 | #define lpfc_rsn_expln_MASK 0x000000FF | ||
239 | #define lpfc_rsn_expln_WORD word3 | ||
240 | #define lpfc_rsn_code_SHIFT 16 | ||
241 | #define lpfc_rsn_code_MASK 0x000000FF | ||
242 | #define lpfc_rsn_code_WORD word3 | ||
243 | |||
234 | uint32_t word4; | 244 | uint32_t word4; |
235 | uint32_t word5_rsvd; /* Word5 must be reserved */ | 245 | uint32_t word5_rsvd; /* Word5 must be reserved */ |
236 | }; | 246 | }; |
@@ -711,21 +721,27 @@ struct lpfc_sli4_cfg_mhdr { | |||
711 | union lpfc_sli4_cfg_shdr { | 721 | union lpfc_sli4_cfg_shdr { |
712 | struct { | 722 | struct { |
713 | uint32_t word6; | 723 | uint32_t word6; |
714 | #define lpfc_mbox_hdr_opcode_SHIFT 0 | 724 | #define lpfc_mbox_hdr_opcode_SHIFT 0 |
715 | #define lpfc_mbox_hdr_opcode_MASK 0x000000FF | 725 | #define lpfc_mbox_hdr_opcode_MASK 0x000000FF |
716 | #define lpfc_mbox_hdr_opcode_WORD word6 | 726 | #define lpfc_mbox_hdr_opcode_WORD word6 |
717 | #define lpfc_mbox_hdr_subsystem_SHIFT 8 | 727 | #define lpfc_mbox_hdr_subsystem_SHIFT 8 |
718 | #define lpfc_mbox_hdr_subsystem_MASK 0x000000FF | 728 | #define lpfc_mbox_hdr_subsystem_MASK 0x000000FF |
719 | #define lpfc_mbox_hdr_subsystem_WORD word6 | 729 | #define lpfc_mbox_hdr_subsystem_WORD word6 |
720 | #define lpfc_mbox_hdr_port_number_SHIFT 16 | 730 | #define lpfc_mbox_hdr_port_number_SHIFT 16 |
721 | #define lpfc_mbox_hdr_port_number_MASK 0x000000FF | 731 | #define lpfc_mbox_hdr_port_number_MASK 0x000000FF |
722 | #define lpfc_mbox_hdr_port_number_WORD word6 | 732 | #define lpfc_mbox_hdr_port_number_WORD word6 |
723 | #define lpfc_mbox_hdr_domain_SHIFT 24 | 733 | #define lpfc_mbox_hdr_domain_SHIFT 24 |
724 | #define lpfc_mbox_hdr_domain_MASK 0x000000FF | 734 | #define lpfc_mbox_hdr_domain_MASK 0x000000FF |
725 | #define lpfc_mbox_hdr_domain_WORD word6 | 735 | #define lpfc_mbox_hdr_domain_WORD word6 |
726 | uint32_t timeout; | 736 | uint32_t timeout; |
727 | uint32_t request_length; | 737 | uint32_t request_length; |
728 | uint32_t reserved9; | 738 | uint32_t word9; |
739 | #define lpfc_mbox_hdr_version_SHIFT 0 | ||
740 | #define lpfc_mbox_hdr_version_MASK 0x000000FF | ||
741 | #define lpfc_mbox_hdr_version_WORD word9 | ||
742 | #define LPFC_Q_CREATE_VERSION_2 2 | ||
743 | #define LPFC_Q_CREATE_VERSION_1 1 | ||
744 | #define LPFC_Q_CREATE_VERSION_0 0 | ||
729 | } request; | 745 | } request; |
730 | struct { | 746 | struct { |
731 | uint32_t word6; | 747 | uint32_t word6; |
@@ -917,9 +933,12 @@ struct cq_context { | |||
917 | #define LPFC_CQ_CNT_512 0x1 | 933 | #define LPFC_CQ_CNT_512 0x1 |
918 | #define LPFC_CQ_CNT_1024 0x2 | 934 | #define LPFC_CQ_CNT_1024 0x2 |
919 | uint32_t word1; | 935 | uint32_t word1; |
920 | #define lpfc_cq_eq_id_SHIFT 22 | 936 | #define lpfc_cq_eq_id_SHIFT 22 /* Version 0 Only */ |
921 | #define lpfc_cq_eq_id_MASK 0x000000FF | 937 | #define lpfc_cq_eq_id_MASK 0x000000FF |
922 | #define lpfc_cq_eq_id_WORD word1 | 938 | #define lpfc_cq_eq_id_WORD word1 |
939 | #define lpfc_cq_eq_id_2_SHIFT 0 /* Version 2 Only */ | ||
940 | #define lpfc_cq_eq_id_2_MASK 0x0000FFFF | ||
941 | #define lpfc_cq_eq_id_2_WORD word1 | ||
923 | uint32_t reserved0; | 942 | uint32_t reserved0; |
924 | uint32_t reserved1; | 943 | uint32_t reserved1; |
925 | }; | 944 | }; |
@@ -929,6 +948,9 @@ struct lpfc_mbx_cq_create { | |||
929 | union { | 948 | union { |
930 | struct { | 949 | struct { |
931 | uint32_t word0; | 950 | uint32_t word0; |
951 | #define lpfc_mbx_cq_create_page_size_SHIFT 16 /* Version 2 Only */ | ||
952 | #define lpfc_mbx_cq_create_page_size_MASK 0x000000FF | ||
953 | #define lpfc_mbx_cq_create_page_size_WORD word0 | ||
932 | #define lpfc_mbx_cq_create_num_pages_SHIFT 0 | 954 | #define lpfc_mbx_cq_create_num_pages_SHIFT 0 |
933 | #define lpfc_mbx_cq_create_num_pages_MASK 0x0000FFFF | 955 | #define lpfc_mbx_cq_create_num_pages_MASK 0x0000FFFF |
934 | #define lpfc_mbx_cq_create_num_pages_WORD word0 | 956 | #define lpfc_mbx_cq_create_num_pages_WORD word0 |
@@ -969,7 +991,7 @@ struct wq_context { | |||
969 | struct lpfc_mbx_wq_create { | 991 | struct lpfc_mbx_wq_create { |
970 | struct mbox_header header; | 992 | struct mbox_header header; |
971 | union { | 993 | union { |
972 | struct { | 994 | struct { /* Version 0 Request */ |
973 | uint32_t word0; | 995 | uint32_t word0; |
974 | #define lpfc_mbx_wq_create_num_pages_SHIFT 0 | 996 | #define lpfc_mbx_wq_create_num_pages_SHIFT 0 |
975 | #define lpfc_mbx_wq_create_num_pages_MASK 0x0000FFFF | 997 | #define lpfc_mbx_wq_create_num_pages_MASK 0x0000FFFF |
@@ -979,6 +1001,23 @@ struct lpfc_mbx_wq_create { | |||
979 | #define lpfc_mbx_wq_create_cq_id_WORD word0 | 1001 | #define lpfc_mbx_wq_create_cq_id_WORD word0 |
980 | struct dma_address page[LPFC_MAX_WQ_PAGE]; | 1002 | struct dma_address page[LPFC_MAX_WQ_PAGE]; |
981 | } request; | 1003 | } request; |
1004 | struct { /* Version 1 Request */ | ||
1005 | uint32_t word0; /* Word 0 is the same as in v0 */ | ||
1006 | uint32_t word1; | ||
1007 | #define lpfc_mbx_wq_create_page_size_SHIFT 0 | ||
1008 | #define lpfc_mbx_wq_create_page_size_MASK 0x000000FF | ||
1009 | #define lpfc_mbx_wq_create_page_size_WORD word1 | ||
1010 | #define lpfc_mbx_wq_create_wqe_size_SHIFT 8 | ||
1011 | #define lpfc_mbx_wq_create_wqe_size_MASK 0x0000000F | ||
1012 | #define lpfc_mbx_wq_create_wqe_size_WORD word1 | ||
1013 | #define LPFC_WQ_WQE_SIZE_64 0x5 | ||
1014 | #define LPFC_WQ_WQE_SIZE_128 0x6 | ||
1015 | #define lpfc_mbx_wq_create_wqe_count_SHIFT 16 | ||
1016 | #define lpfc_mbx_wq_create_wqe_count_MASK 0x0000FFFF | ||
1017 | #define lpfc_mbx_wq_create_wqe_count_WORD word1 | ||
1018 | uint32_t word2; | ||
1019 | struct dma_address page[LPFC_MAX_WQ_PAGE-1]; | ||
1020 | } request_1; | ||
982 | struct { | 1021 | struct { |
983 | uint32_t word0; | 1022 | uint32_t word0; |
984 | #define lpfc_mbx_wq_create_q_id_SHIFT 0 | 1023 | #define lpfc_mbx_wq_create_q_id_SHIFT 0 |
@@ -1007,13 +1046,22 @@ struct lpfc_mbx_wq_destroy { | |||
1007 | #define LPFC_DATA_BUF_SIZE 2048 | 1046 | #define LPFC_DATA_BUF_SIZE 2048 |
1008 | struct rq_context { | 1047 | struct rq_context { |
1009 | uint32_t word0; | 1048 | uint32_t word0; |
1010 | #define lpfc_rq_context_rq_size_SHIFT 16 | 1049 | #define lpfc_rq_context_rqe_count_SHIFT 16 /* Version 0 Only */ |
1011 | #define lpfc_rq_context_rq_size_MASK 0x0000000F | 1050 | #define lpfc_rq_context_rqe_count_MASK 0x0000000F |
1012 | #define lpfc_rq_context_rq_size_WORD word0 | 1051 | #define lpfc_rq_context_rqe_count_WORD word0 |
1013 | #define LPFC_RQ_RING_SIZE_512 9 /* 512 entries */ | 1052 | #define LPFC_RQ_RING_SIZE_512 9 /* 512 entries */ |
1014 | #define LPFC_RQ_RING_SIZE_1024 10 /* 1024 entries */ | 1053 | #define LPFC_RQ_RING_SIZE_1024 10 /* 1024 entries */ |
1015 | #define LPFC_RQ_RING_SIZE_2048 11 /* 2048 entries */ | 1054 | #define LPFC_RQ_RING_SIZE_2048 11 /* 2048 entries */ |
1016 | #define LPFC_RQ_RING_SIZE_4096 12 /* 4096 entries */ | 1055 | #define LPFC_RQ_RING_SIZE_4096 12 /* 4096 entries */ |
1056 | #define lpfc_rq_context_rqe_count_1_SHIFT 16 /* Version 1 Only */ | ||
1057 | #define lpfc_rq_context_rqe_count_1_MASK 0x0000FFFF | ||
1058 | #define lpfc_rq_context_rqe_count_1_WORD word0 | ||
1059 | #define lpfc_rq_context_rqe_size_SHIFT 8 /* Version 1 Only */ | ||
1060 | #define lpfc_rq_context_rqe_size_MASK 0x0000000F | ||
1061 | #define lpfc_rq_context_rqe_size_WORD word0 | ||
1062 | #define lpfc_rq_context_page_size_SHIFT 0 /* Version 1 Only */ | ||
1063 | #define lpfc_rq_context_page_size_MASK 0x000000FF | ||
1064 | #define lpfc_rq_context_page_size_WORD word0 | ||
1017 | uint32_t reserved1; | 1065 | uint32_t reserved1; |
1018 | uint32_t word2; | 1066 | uint32_t word2; |
1019 | #define lpfc_rq_context_cq_id_SHIFT 16 | 1067 | #define lpfc_rq_context_cq_id_SHIFT 16 |
@@ -1022,7 +1070,7 @@ struct rq_context { | |||
1022 | #define lpfc_rq_context_buf_size_SHIFT 0 | 1070 | #define lpfc_rq_context_buf_size_SHIFT 0 |
1023 | #define lpfc_rq_context_buf_size_MASK 0x0000FFFF | 1071 | #define lpfc_rq_context_buf_size_MASK 0x0000FFFF |
1024 | #define lpfc_rq_context_buf_size_WORD word2 | 1072 | #define lpfc_rq_context_buf_size_WORD word2 |
1025 | uint32_t reserved3; | 1073 | uint32_t buffer_size; /* Version 1 Only */ |
1026 | }; | 1074 | }; |
1027 | 1075 | ||
1028 | struct lpfc_mbx_rq_create { | 1076 | struct lpfc_mbx_rq_create { |
@@ -1062,16 +1110,16 @@ struct lpfc_mbx_rq_destroy { | |||
1062 | 1110 | ||
1063 | struct mq_context { | 1111 | struct mq_context { |
1064 | uint32_t word0; | 1112 | uint32_t word0; |
1065 | #define lpfc_mq_context_cq_id_SHIFT 22 | 1113 | #define lpfc_mq_context_cq_id_SHIFT 22 /* Version 0 Only */ |
1066 | #define lpfc_mq_context_cq_id_MASK 0x000003FF | 1114 | #define lpfc_mq_context_cq_id_MASK 0x000003FF |
1067 | #define lpfc_mq_context_cq_id_WORD word0 | 1115 | #define lpfc_mq_context_cq_id_WORD word0 |
1068 | #define lpfc_mq_context_count_SHIFT 16 | 1116 | #define lpfc_mq_context_ring_size_SHIFT 16 |
1069 | #define lpfc_mq_context_count_MASK 0x0000000F | 1117 | #define lpfc_mq_context_ring_size_MASK 0x0000000F |
1070 | #define lpfc_mq_context_count_WORD word0 | 1118 | #define lpfc_mq_context_ring_size_WORD word0 |
1071 | #define LPFC_MQ_CNT_16 0x5 | 1119 | #define LPFC_MQ_RING_SIZE_16 0x5 |
1072 | #define LPFC_MQ_CNT_32 0x6 | 1120 | #define LPFC_MQ_RING_SIZE_32 0x6 |
1073 | #define LPFC_MQ_CNT_64 0x7 | 1121 | #define LPFC_MQ_RING_SIZE_64 0x7 |
1074 | #define LPFC_MQ_CNT_128 0x8 | 1122 | #define LPFC_MQ_RING_SIZE_128 0x8 |
1075 | uint32_t word1; | 1123 | uint32_t word1; |
1076 | #define lpfc_mq_context_valid_SHIFT 31 | 1124 | #define lpfc_mq_context_valid_SHIFT 31 |
1077 | #define lpfc_mq_context_valid_MASK 0x00000001 | 1125 | #define lpfc_mq_context_valid_MASK 0x00000001 |
@@ -1105,9 +1153,12 @@ struct lpfc_mbx_mq_create_ext { | |||
1105 | union { | 1153 | union { |
1106 | struct { | 1154 | struct { |
1107 | uint32_t word0; | 1155 | uint32_t word0; |
1108 | #define lpfc_mbx_mq_create_ext_num_pages_SHIFT 0 | 1156 | #define lpfc_mbx_mq_create_ext_num_pages_SHIFT 0 |
1109 | #define lpfc_mbx_mq_create_ext_num_pages_MASK 0x0000FFFF | 1157 | #define lpfc_mbx_mq_create_ext_num_pages_MASK 0x0000FFFF |
1110 | #define lpfc_mbx_mq_create_ext_num_pages_WORD word0 | 1158 | #define lpfc_mbx_mq_create_ext_num_pages_WORD word0 |
1159 | #define lpfc_mbx_mq_create_ext_cq_id_SHIFT 16 /* Version 1 Only */ | ||
1160 | #define lpfc_mbx_mq_create_ext_cq_id_MASK 0x0000FFFF | ||
1161 | #define lpfc_mbx_mq_create_ext_cq_id_WORD word0 | ||
1111 | uint32_t async_evt_bmap; | 1162 | uint32_t async_evt_bmap; |
1112 | #define lpfc_mbx_mq_create_ext_async_evt_link_SHIFT LPFC_TRAILER_CODE_LINK | 1163 | #define lpfc_mbx_mq_create_ext_async_evt_link_SHIFT LPFC_TRAILER_CODE_LINK |
1113 | #define lpfc_mbx_mq_create_ext_async_evt_link_MASK 0x00000001 | 1164 | #define lpfc_mbx_mq_create_ext_async_evt_link_MASK 0x00000001 |
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 35665cfb5689..e6ebe516cfbb 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /******************************************************************* | 1 | /******************************************************************* |
2 | * This file is part of the Emulex Linux Device Driver for * | 2 | * This file is part of the Emulex Linux Device Driver for * |
3 | * Fibre Channel Host Bus Adapters. * | 3 | * Fibre Channel Host Bus Adapters. * |
4 | * Copyright (C) 2004-2010 Emulex. All rights reserved. * | 4 | * Copyright (C) 2004-2011 Emulex. All rights reserved. * |
5 | * EMULEX and SLI are trademarks of Emulex. * | 5 | * EMULEX and SLI are trademarks of Emulex. * |
6 | * www.emulex.com * | 6 | * www.emulex.com * |
7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * | 7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * |
@@ -507,7 +507,10 @@ lpfc_config_port_post(struct lpfc_hba *phba) | |||
507 | phba->hba_flag &= ~HBA_ERATT_HANDLED; | 507 | phba->hba_flag &= ~HBA_ERATT_HANDLED; |
508 | 508 | ||
509 | /* Enable appropriate host interrupts */ | 509 | /* Enable appropriate host interrupts */ |
510 | status = readl(phba->HCregaddr); | 510 | if (lpfc_readl(phba->HCregaddr, &status)) { |
511 | spin_unlock_irq(&phba->hbalock); | ||
512 | return -EIO; | ||
513 | } | ||
511 | status |= HC_MBINT_ENA | HC_ERINT_ENA | HC_LAINT_ENA; | 514 | status |= HC_MBINT_ENA | HC_ERINT_ENA | HC_LAINT_ENA; |
512 | if (psli->num_rings > 0) | 515 | if (psli->num_rings > 0) |
513 | status |= HC_R0INT_ENA; | 516 | status |= HC_R0INT_ENA; |
@@ -1222,7 +1225,10 @@ lpfc_handle_deferred_eratt(struct lpfc_hba *phba) | |||
1222 | /* Wait for the ER1 bit to clear.*/ | 1225 | /* Wait for the ER1 bit to clear.*/ |
1223 | while (phba->work_hs & HS_FFER1) { | 1226 | while (phba->work_hs & HS_FFER1) { |
1224 | msleep(100); | 1227 | msleep(100); |
1225 | phba->work_hs = readl(phba->HSregaddr); | 1228 | if (lpfc_readl(phba->HSregaddr, &phba->work_hs)) { |
1229 | phba->work_hs = UNPLUG_ERR ; | ||
1230 | break; | ||
1231 | } | ||
1226 | /* If driver is unloading let the worker thread continue */ | 1232 | /* If driver is unloading let the worker thread continue */ |
1227 | if (phba->pport->load_flag & FC_UNLOADING) { | 1233 | if (phba->pport->load_flag & FC_UNLOADING) { |
1228 | phba->work_hs = 0; | 1234 | phba->work_hs = 0; |
@@ -4474,6 +4480,7 @@ lpfc_init_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) | |||
4474 | { | 4480 | { |
4475 | phba->lpfc_hba_init_link = lpfc_hba_init_link; | 4481 | phba->lpfc_hba_init_link = lpfc_hba_init_link; |
4476 | phba->lpfc_hba_down_link = lpfc_hba_down_link; | 4482 | phba->lpfc_hba_down_link = lpfc_hba_down_link; |
4483 | phba->lpfc_selective_reset = lpfc_selective_reset; | ||
4477 | switch (dev_grp) { | 4484 | switch (dev_grp) { |
4478 | case LPFC_PCI_DEV_LP: | 4485 | case LPFC_PCI_DEV_LP: |
4479 | phba->lpfc_hba_down_post = lpfc_hba_down_post_s3; | 4486 | phba->lpfc_hba_down_post = lpfc_hba_down_post_s3; |
@@ -5385,13 +5392,16 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba) | |||
5385 | int i, port_error = 0; | 5392 | int i, port_error = 0; |
5386 | uint32_t if_type; | 5393 | uint32_t if_type; |
5387 | 5394 | ||
5395 | memset(&portsmphr_reg, 0, sizeof(portsmphr_reg)); | ||
5396 | memset(®_data, 0, sizeof(reg_data)); | ||
5388 | if (!phba->sli4_hba.PSMPHRregaddr) | 5397 | if (!phba->sli4_hba.PSMPHRregaddr) |
5389 | return -ENODEV; | 5398 | return -ENODEV; |
5390 | 5399 | ||
5391 | /* Wait up to 30 seconds for the SLI Port POST done and ready */ | 5400 | /* Wait up to 30 seconds for the SLI Port POST done and ready */ |
5392 | for (i = 0; i < 3000; i++) { | 5401 | for (i = 0; i < 3000; i++) { |
5393 | portsmphr_reg.word0 = readl(phba->sli4_hba.PSMPHRregaddr); | 5402 | if (lpfc_readl(phba->sli4_hba.PSMPHRregaddr, |
5394 | if (bf_get(lpfc_port_smphr_perr, &portsmphr_reg)) { | 5403 | &portsmphr_reg.word0) || |
5404 | (bf_get(lpfc_port_smphr_perr, &portsmphr_reg))) { | ||
5395 | /* Port has a fatal POST error, break out */ | 5405 | /* Port has a fatal POST error, break out */ |
5396 | port_error = -ENODEV; | 5406 | port_error = -ENODEV; |
5397 | break; | 5407 | break; |
@@ -5472,9 +5482,9 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba) | |||
5472 | break; | 5482 | break; |
5473 | case LPFC_SLI_INTF_IF_TYPE_2: | 5483 | case LPFC_SLI_INTF_IF_TYPE_2: |
5474 | /* Final checks. The port status should be clean. */ | 5484 | /* Final checks. The port status should be clean. */ |
5475 | reg_data.word0 = | 5485 | if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, |
5476 | readl(phba->sli4_hba.u.if_type2.STATUSregaddr); | 5486 | ®_data.word0) || |
5477 | if (bf_get(lpfc_sliport_status_err, ®_data)) { | 5487 | bf_get(lpfc_sliport_status_err, ®_data)) { |
5478 | phba->work_status[0] = | 5488 | phba->work_status[0] = |
5479 | readl(phba->sli4_hba.u.if_type2. | 5489 | readl(phba->sli4_hba.u.if_type2. |
5480 | ERR1regaddr); | 5490 | ERR1regaddr); |
@@ -6760,9 +6770,11 @@ lpfc_pci_function_reset(struct lpfc_hba *phba) | |||
6760 | * the loop again. | 6770 | * the loop again. |
6761 | */ | 6771 | */ |
6762 | for (rdy_chk = 0; rdy_chk < 1000; rdy_chk++) { | 6772 | for (rdy_chk = 0; rdy_chk < 1000; rdy_chk++) { |
6763 | reg_data.word0 = | 6773 | if (lpfc_readl(phba->sli4_hba.u.if_type2. |
6764 | readl(phba->sli4_hba.u.if_type2. | 6774 | STATUSregaddr, ®_data.word0)) { |
6765 | STATUSregaddr); | 6775 | rc = -ENODEV; |
6776 | break; | ||
6777 | } | ||
6766 | if (bf_get(lpfc_sliport_status_rdy, ®_data)) | 6778 | if (bf_get(lpfc_sliport_status_rdy, ®_data)) |
6767 | break; | 6779 | break; |
6768 | if (bf_get(lpfc_sliport_status_rn, ®_data)) { | 6780 | if (bf_get(lpfc_sliport_status_rn, ®_data)) { |
@@ -6783,8 +6795,11 @@ lpfc_pci_function_reset(struct lpfc_hba *phba) | |||
6783 | } | 6795 | } |
6784 | 6796 | ||
6785 | /* Detect any port errors. */ | 6797 | /* Detect any port errors. */ |
6786 | reg_data.word0 = readl(phba->sli4_hba.u.if_type2. | 6798 | if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, |
6787 | STATUSregaddr); | 6799 | ®_data.word0)) { |
6800 | rc = -ENODEV; | ||
6801 | break; | ||
6802 | } | ||
6788 | if ((bf_get(lpfc_sliport_status_err, ®_data)) || | 6803 | if ((bf_get(lpfc_sliport_status_err, ®_data)) || |
6789 | (rdy_chk >= 1000)) { | 6804 | (rdy_chk >= 1000)) { |
6790 | phba->work_status[0] = readl( | 6805 | phba->work_status[0] = readl( |
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index bf34178b80bf..2b962b020cfb 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /******************************************************************* | 1 | /******************************************************************* |
2 | * This file is part of the Emulex Linux Device Driver for * | 2 | * This file is part of the Emulex Linux Device Driver for * |
3 | * Fibre Channel Host Bus Adapters. * | 3 | * Fibre Channel Host Bus Adapters. * |
4 | * Copyright (C) 2004-2009 Emulex. All rights reserved. * | 4 | * Copyright (C) 2004-2011 Emulex. All rights reserved. * |
5 | * EMULEX and SLI are trademarks of Emulex. * | 5 | * EMULEX and SLI are trademarks of Emulex. * |
6 | * www.emulex.com * | 6 | * www.emulex.com * |
7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * | 7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * |
@@ -1514,10 +1514,11 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, | |||
1514 | struct scatterlist *sgpe = NULL; /* s/g prot entry */ | 1514 | struct scatterlist *sgpe = NULL; /* s/g prot entry */ |
1515 | struct lpfc_pde5 *pde5 = NULL; | 1515 | struct lpfc_pde5 *pde5 = NULL; |
1516 | struct lpfc_pde6 *pde6 = NULL; | 1516 | struct lpfc_pde6 *pde6 = NULL; |
1517 | struct ulp_bde64 *prot_bde = NULL; | 1517 | struct lpfc_pde7 *pde7 = NULL; |
1518 | dma_addr_t dataphysaddr, protphysaddr; | 1518 | dma_addr_t dataphysaddr, protphysaddr; |
1519 | unsigned short curr_data = 0, curr_prot = 0; | 1519 | unsigned short curr_data = 0, curr_prot = 0; |
1520 | unsigned int split_offset, protgroup_len; | 1520 | unsigned int split_offset; |
1521 | unsigned int protgroup_len, protgroup_offset = 0, protgroup_remainder; | ||
1521 | unsigned int protgrp_blks, protgrp_bytes; | 1522 | unsigned int protgrp_blks, protgrp_bytes; |
1522 | unsigned int remainder, subtotal; | 1523 | unsigned int remainder, subtotal; |
1523 | int status; | 1524 | int status; |
@@ -1585,23 +1586,33 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, | |||
1585 | bpl++; | 1586 | bpl++; |
1586 | 1587 | ||
1587 | /* setup the first BDE that points to protection buffer */ | 1588 | /* setup the first BDE that points to protection buffer */ |
1588 | prot_bde = (struct ulp_bde64 *) bpl; | 1589 | protphysaddr = sg_dma_address(sgpe) + protgroup_offset; |
1589 | protphysaddr = sg_dma_address(sgpe); | 1590 | protgroup_len = sg_dma_len(sgpe) - protgroup_offset; |
1590 | prot_bde->addrHigh = le32_to_cpu(putPaddrLow(protphysaddr)); | ||
1591 | prot_bde->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr)); | ||
1592 | protgroup_len = sg_dma_len(sgpe); | ||
1593 | 1591 | ||
1594 | /* must be integer multiple of the DIF block length */ | 1592 | /* must be integer multiple of the DIF block length */ |
1595 | BUG_ON(protgroup_len % 8); | 1593 | BUG_ON(protgroup_len % 8); |
1596 | 1594 | ||
1595 | pde7 = (struct lpfc_pde7 *) bpl; | ||
1596 | memset(pde7, 0, sizeof(struct lpfc_pde7)); | ||
1597 | bf_set(pde7_type, pde7, LPFC_PDE7_DESCRIPTOR); | ||
1598 | |||
1599 | pde7->addrHigh = le32_to_cpu(putPaddrLow(protphysaddr)); | ||
1600 | pde7->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr)); | ||
1601 | |||
1597 | protgrp_blks = protgroup_len / 8; | 1602 | protgrp_blks = protgroup_len / 8; |
1598 | protgrp_bytes = protgrp_blks * blksize; | 1603 | protgrp_bytes = protgrp_blks * blksize; |
1599 | 1604 | ||
1600 | prot_bde->tus.f.bdeSize = protgroup_len; | 1605 | /* check if this pde is crossing the 4K boundary; if so split */ |
1601 | prot_bde->tus.f.bdeFlags = LPFC_PDE7_DESCRIPTOR; | 1606 | if ((pde7->addrLow & 0xfff) + protgroup_len > 0x1000) { |
1602 | prot_bde->tus.w = le32_to_cpu(bpl->tus.w); | 1607 | protgroup_remainder = 0x1000 - (pde7->addrLow & 0xfff); |
1608 | protgroup_offset += protgroup_remainder; | ||
1609 | protgrp_blks = protgroup_remainder / 8; | ||
1610 | protgrp_bytes = protgroup_remainder * blksize; | ||
1611 | } else { | ||
1612 | protgroup_offset = 0; | ||
1613 | curr_prot++; | ||
1614 | } | ||
1603 | 1615 | ||
1604 | curr_prot++; | ||
1605 | num_bde++; | 1616 | num_bde++; |
1606 | 1617 | ||
1607 | /* setup BDE's for data blocks associated with DIF data */ | 1618 | /* setup BDE's for data blocks associated with DIF data */ |
@@ -1653,6 +1664,13 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, | |||
1653 | 1664 | ||
1654 | } | 1665 | } |
1655 | 1666 | ||
1667 | if (protgroup_offset) { | ||
1668 | /* update the reference tag */ | ||
1669 | reftag += protgrp_blks; | ||
1670 | bpl++; | ||
1671 | continue; | ||
1672 | } | ||
1673 | |||
1656 | /* are we done ? */ | 1674 | /* are we done ? */ |
1657 | if (curr_prot == protcnt) { | 1675 | if (curr_prot == protcnt) { |
1658 | alldone = 1; | 1676 | alldone = 1; |
@@ -1675,6 +1693,7 @@ out: | |||
1675 | 1693 | ||
1676 | return num_bde; | 1694 | return num_bde; |
1677 | } | 1695 | } |
1696 | |||
1678 | /* | 1697 | /* |
1679 | * Given a SCSI command that supports DIF, determine composition of protection | 1698 | * Given a SCSI command that supports DIF, determine composition of protection |
1680 | * groups involved in setting up buffer lists | 1699 | * groups involved in setting up buffer lists |
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 2ee0374a9908..4746dcd756dd 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /******************************************************************* | 1 | /******************************************************************* |
2 | * This file is part of the Emulex Linux Device Driver for * | 2 | * This file is part of the Emulex Linux Device Driver for * |
3 | * Fibre Channel Host Bus Adapters. * | 3 | * Fibre Channel Host Bus Adapters. * |
4 | * Copyright (C) 2004-2009 Emulex. All rights reserved. * | 4 | * Copyright (C) 2004-2011 Emulex. All rights reserved. * |
5 | * EMULEX and SLI are trademarks of Emulex. * | 5 | * EMULEX and SLI are trademarks of Emulex. * |
6 | * www.emulex.com * | 6 | * www.emulex.com * |
7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * | 7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * |
@@ -3477,7 +3477,8 @@ lpfc_sli_brdready_s3(struct lpfc_hba *phba, uint32_t mask) | |||
3477 | int retval = 0; | 3477 | int retval = 0; |
3478 | 3478 | ||
3479 | /* Read the HBA Host Status Register */ | 3479 | /* Read the HBA Host Status Register */ |
3480 | status = readl(phba->HSregaddr); | 3480 | if (lpfc_readl(phba->HSregaddr, &status)) |
3481 | return 1; | ||
3481 | 3482 | ||
3482 | /* | 3483 | /* |
3483 | * Check status register every 100ms for 5 retries, then every | 3484 | * Check status register every 100ms for 5 retries, then every |
@@ -3502,7 +3503,10 @@ lpfc_sli_brdready_s3(struct lpfc_hba *phba, uint32_t mask) | |||
3502 | lpfc_sli_brdrestart(phba); | 3503 | lpfc_sli_brdrestart(phba); |
3503 | } | 3504 | } |
3504 | /* Read the HBA Host Status Register */ | 3505 | /* Read the HBA Host Status Register */ |
3505 | status = readl(phba->HSregaddr); | 3506 | if (lpfc_readl(phba->HSregaddr, &status)) { |
3507 | retval = 1; | ||
3508 | break; | ||
3509 | } | ||
3506 | } | 3510 | } |
3507 | 3511 | ||
3508 | /* Check to see if any errors occurred during init */ | 3512 | /* Check to see if any errors occurred during init */ |
@@ -3584,7 +3588,7 @@ void lpfc_reset_barrier(struct lpfc_hba *phba) | |||
3584 | uint32_t __iomem *resp_buf; | 3588 | uint32_t __iomem *resp_buf; |
3585 | uint32_t __iomem *mbox_buf; | 3589 | uint32_t __iomem *mbox_buf; |
3586 | volatile uint32_t mbox; | 3590 | volatile uint32_t mbox; |
3587 | uint32_t hc_copy; | 3591 | uint32_t hc_copy, ha_copy, resp_data; |
3588 | int i; | 3592 | int i; |
3589 | uint8_t hdrtype; | 3593 | uint8_t hdrtype; |
3590 | 3594 | ||
@@ -3601,12 +3605,15 @@ void lpfc_reset_barrier(struct lpfc_hba *phba) | |||
3601 | resp_buf = phba->MBslimaddr; | 3605 | resp_buf = phba->MBslimaddr; |
3602 | 3606 | ||
3603 | /* Disable the error attention */ | 3607 | /* Disable the error attention */ |
3604 | hc_copy = readl(phba->HCregaddr); | 3608 | if (lpfc_readl(phba->HCregaddr, &hc_copy)) |
3609 | return; | ||
3605 | writel((hc_copy & ~HC_ERINT_ENA), phba->HCregaddr); | 3610 | writel((hc_copy & ~HC_ERINT_ENA), phba->HCregaddr); |
3606 | readl(phba->HCregaddr); /* flush */ | 3611 | readl(phba->HCregaddr); /* flush */ |
3607 | phba->link_flag |= LS_IGNORE_ERATT; | 3612 | phba->link_flag |= LS_IGNORE_ERATT; |
3608 | 3613 | ||
3609 | if (readl(phba->HAregaddr) & HA_ERATT) { | 3614 | if (lpfc_readl(phba->HAregaddr, &ha_copy)) |
3615 | return; | ||
3616 | if (ha_copy & HA_ERATT) { | ||
3610 | /* Clear Chip error bit */ | 3617 | /* Clear Chip error bit */ |
3611 | writel(HA_ERATT, phba->HAregaddr); | 3618 | writel(HA_ERATT, phba->HAregaddr); |
3612 | phba->pport->stopped = 1; | 3619 | phba->pport->stopped = 1; |
@@ -3620,11 +3627,18 @@ void lpfc_reset_barrier(struct lpfc_hba *phba) | |||
3620 | mbox_buf = phba->MBslimaddr; | 3627 | mbox_buf = phba->MBslimaddr; |
3621 | writel(mbox, mbox_buf); | 3628 | writel(mbox, mbox_buf); |
3622 | 3629 | ||
3623 | for (i = 0; | 3630 | for (i = 0; i < 50; i++) { |
3624 | readl(resp_buf + 1) != ~(BARRIER_TEST_PATTERN) && i < 50; i++) | 3631 | if (lpfc_readl((resp_buf + 1), &resp_data)) |
3625 | mdelay(1); | 3632 | return; |
3626 | 3633 | if (resp_data != ~(BARRIER_TEST_PATTERN)) | |
3627 | if (readl(resp_buf + 1) != ~(BARRIER_TEST_PATTERN)) { | 3634 | mdelay(1); |
3635 | else | ||
3636 | break; | ||
3637 | } | ||
3638 | resp_data = 0; | ||
3639 | if (lpfc_readl((resp_buf + 1), &resp_data)) | ||
3640 | return; | ||
3641 | if (resp_data != ~(BARRIER_TEST_PATTERN)) { | ||
3628 | if (phba->sli.sli_flag & LPFC_SLI_ACTIVE || | 3642 | if (phba->sli.sli_flag & LPFC_SLI_ACTIVE || |
3629 | phba->pport->stopped) | 3643 | phba->pport->stopped) |
3630 | goto restore_hc; | 3644 | goto restore_hc; |
@@ -3633,13 +3647,26 @@ void lpfc_reset_barrier(struct lpfc_hba *phba) | |||
3633 | } | 3647 | } |
3634 | 3648 | ||
3635 | ((MAILBOX_t *)&mbox)->mbxOwner = OWN_HOST; | 3649 | ((MAILBOX_t *)&mbox)->mbxOwner = OWN_HOST; |
3636 | for (i = 0; readl(resp_buf) != mbox && i < 500; i++) | 3650 | resp_data = 0; |
3637 | mdelay(1); | 3651 | for (i = 0; i < 500; i++) { |
3652 | if (lpfc_readl(resp_buf, &resp_data)) | ||
3653 | return; | ||
3654 | if (resp_data != mbox) | ||
3655 | mdelay(1); | ||
3656 | else | ||
3657 | break; | ||
3658 | } | ||
3638 | 3659 | ||
3639 | clear_errat: | 3660 | clear_errat: |
3640 | 3661 | ||
3641 | while (!(readl(phba->HAregaddr) & HA_ERATT) && ++i < 500) | 3662 | while (++i < 500) { |
3642 | mdelay(1); | 3663 | if (lpfc_readl(phba->HAregaddr, &ha_copy)) |
3664 | return; | ||
3665 | if (!(ha_copy & HA_ERATT)) | ||
3666 | mdelay(1); | ||
3667 | else | ||
3668 | break; | ||
3669 | } | ||
3643 | 3670 | ||
3644 | if (readl(phba->HAregaddr) & HA_ERATT) { | 3671 | if (readl(phba->HAregaddr) & HA_ERATT) { |
3645 | writel(HA_ERATT, phba->HAregaddr); | 3672 | writel(HA_ERATT, phba->HAregaddr); |
@@ -3686,7 +3713,11 @@ lpfc_sli_brdkill(struct lpfc_hba *phba) | |||
3686 | 3713 | ||
3687 | /* Disable the error attention */ | 3714 | /* Disable the error attention */ |
3688 | spin_lock_irq(&phba->hbalock); | 3715 | spin_lock_irq(&phba->hbalock); |
3689 | status = readl(phba->HCregaddr); | 3716 | if (lpfc_readl(phba->HCregaddr, &status)) { |
3717 | spin_unlock_irq(&phba->hbalock); | ||
3718 | mempool_free(pmb, phba->mbox_mem_pool); | ||
3719 | return 1; | ||
3720 | } | ||
3690 | status &= ~HC_ERINT_ENA; | 3721 | status &= ~HC_ERINT_ENA; |
3691 | writel(status, phba->HCregaddr); | 3722 | writel(status, phba->HCregaddr); |
3692 | readl(phba->HCregaddr); /* flush */ | 3723 | readl(phba->HCregaddr); /* flush */ |
@@ -3720,11 +3751,12 @@ lpfc_sli_brdkill(struct lpfc_hba *phba) | |||
3720 | * 3 seconds we still set HBA_ERROR state because the status of the | 3751 | * 3 seconds we still set HBA_ERROR state because the status of the |
3721 | * board is now undefined. | 3752 | * board is now undefined. |
3722 | */ | 3753 | */ |
3723 | ha_copy = readl(phba->HAregaddr); | 3754 | if (lpfc_readl(phba->HAregaddr, &ha_copy)) |
3724 | 3755 | return 1; | |
3725 | while ((i++ < 30) && !(ha_copy & HA_ERATT)) { | 3756 | while ((i++ < 30) && !(ha_copy & HA_ERATT)) { |
3726 | mdelay(100); | 3757 | mdelay(100); |
3727 | ha_copy = readl(phba->HAregaddr); | 3758 | if (lpfc_readl(phba->HAregaddr, &ha_copy)) |
3759 | return 1; | ||
3728 | } | 3760 | } |
3729 | 3761 | ||
3730 | del_timer_sync(&psli->mbox_tmo); | 3762 | del_timer_sync(&psli->mbox_tmo); |
@@ -4018,7 +4050,8 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) | |||
4018 | uint32_t status, i = 0; | 4050 | uint32_t status, i = 0; |
4019 | 4051 | ||
4020 | /* Read the HBA Host Status Register */ | 4052 | /* Read the HBA Host Status Register */ |
4021 | status = readl(phba->HSregaddr); | 4053 | if (lpfc_readl(phba->HSregaddr, &status)) |
4054 | return -EIO; | ||
4022 | 4055 | ||
4023 | /* Check status register to see what current state is */ | 4056 | /* Check status register to see what current state is */ |
4024 | i = 0; | 4057 | i = 0; |
@@ -4073,7 +4106,8 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) | |||
4073 | lpfc_sli_brdrestart(phba); | 4106 | lpfc_sli_brdrestart(phba); |
4074 | } | 4107 | } |
4075 | /* Read the HBA Host Status Register */ | 4108 | /* Read the HBA Host Status Register */ |
4076 | status = readl(phba->HSregaddr); | 4109 | if (lpfc_readl(phba->HSregaddr, &status)) |
4110 | return -EIO; | ||
4077 | } | 4111 | } |
4078 | 4112 | ||
4079 | /* Check to see if any errors occurred during init */ | 4113 | /* Check to see if any errors occurred during init */ |
@@ -5136,7 +5170,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, | |||
5136 | MAILBOX_t *mb; | 5170 | MAILBOX_t *mb; |
5137 | struct lpfc_sli *psli = &phba->sli; | 5171 | struct lpfc_sli *psli = &phba->sli; |
5138 | uint32_t status, evtctr; | 5172 | uint32_t status, evtctr; |
5139 | uint32_t ha_copy; | 5173 | uint32_t ha_copy, hc_copy; |
5140 | int i; | 5174 | int i; |
5141 | unsigned long timeout; | 5175 | unsigned long timeout; |
5142 | unsigned long drvr_flag = 0; | 5176 | unsigned long drvr_flag = 0; |
@@ -5202,15 +5236,17 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, | |||
5202 | goto out_not_finished; | 5236 | goto out_not_finished; |
5203 | } | 5237 | } |
5204 | 5238 | ||
5205 | if (mb->mbxCommand != MBX_KILL_BOARD && flag & MBX_NOWAIT && | 5239 | if (mb->mbxCommand != MBX_KILL_BOARD && flag & MBX_NOWAIT) { |
5206 | !(readl(phba->HCregaddr) & HC_MBINT_ENA)) { | 5240 | if (lpfc_readl(phba->HCregaddr, &hc_copy) || |
5207 | spin_unlock_irqrestore(&phba->hbalock, drvr_flag); | 5241 | !(hc_copy & HC_MBINT_ENA)) { |
5208 | lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, | 5242 | spin_unlock_irqrestore(&phba->hbalock, drvr_flag); |
5243 | lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, | ||
5209 | "(%d):2528 Mailbox command x%x cannot " | 5244 | "(%d):2528 Mailbox command x%x cannot " |
5210 | "issue Data: x%x x%x\n", | 5245 | "issue Data: x%x x%x\n", |
5211 | pmbox->vport ? pmbox->vport->vpi : 0, | 5246 | pmbox->vport ? pmbox->vport->vpi : 0, |
5212 | pmbox->u.mb.mbxCommand, psli->sli_flag, flag); | 5247 | pmbox->u.mb.mbxCommand, psli->sli_flag, flag); |
5213 | goto out_not_finished; | 5248 | goto out_not_finished; |
5249 | } | ||
5214 | } | 5250 | } |
5215 | 5251 | ||
5216 | if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) { | 5252 | if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) { |
@@ -5408,11 +5444,19 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, | |||
5408 | word0 = le32_to_cpu(word0); | 5444 | word0 = le32_to_cpu(word0); |
5409 | } else { | 5445 | } else { |
5410 | /* First read mbox status word */ | 5446 | /* First read mbox status word */ |
5411 | word0 = readl(phba->MBslimaddr); | 5447 | if (lpfc_readl(phba->MBslimaddr, &word0)) { |
5448 | spin_unlock_irqrestore(&phba->hbalock, | ||
5449 | drvr_flag); | ||
5450 | goto out_not_finished; | ||
5451 | } | ||
5412 | } | 5452 | } |
5413 | 5453 | ||
5414 | /* Read the HBA Host Attention Register */ | 5454 | /* Read the HBA Host Attention Register */ |
5415 | ha_copy = readl(phba->HAregaddr); | 5455 | if (lpfc_readl(phba->HAregaddr, &ha_copy)) { |
5456 | spin_unlock_irqrestore(&phba->hbalock, | ||
5457 | drvr_flag); | ||
5458 | goto out_not_finished; | ||
5459 | } | ||
5416 | timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, | 5460 | timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, |
5417 | mb->mbxCommand) * | 5461 | mb->mbxCommand) * |
5418 | 1000) + jiffies; | 5462 | 1000) + jiffies; |
@@ -5463,7 +5507,11 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, | |||
5463 | word0 = readl(phba->MBslimaddr); | 5507 | word0 = readl(phba->MBslimaddr); |
5464 | } | 5508 | } |
5465 | /* Read the HBA Host Attention Register */ | 5509 | /* Read the HBA Host Attention Register */ |
5466 | ha_copy = readl(phba->HAregaddr); | 5510 | if (lpfc_readl(phba->HAregaddr, &ha_copy)) { |
5511 | spin_unlock_irqrestore(&phba->hbalock, | ||
5512 | drvr_flag); | ||
5513 | goto out_not_finished; | ||
5514 | } | ||
5467 | } | 5515 | } |
5468 | 5516 | ||
5469 | if (psli->sli_flag & LPFC_SLI_ACTIVE) { | 5517 | if (psli->sli_flag & LPFC_SLI_ACTIVE) { |
@@ -6263,7 +6311,6 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, | |||
6263 | bf_set(lpfc_sli4_sge_last, sgl, 1); | 6311 | bf_set(lpfc_sli4_sge_last, sgl, 1); |
6264 | else | 6312 | else |
6265 | bf_set(lpfc_sli4_sge_last, sgl, 0); | 6313 | bf_set(lpfc_sli4_sge_last, sgl, 0); |
6266 | sgl->word2 = cpu_to_le32(sgl->word2); | ||
6267 | /* swap the size field back to the cpu so we | 6314 | /* swap the size field back to the cpu so we |
6268 | * can assign it to the sgl. | 6315 | * can assign it to the sgl. |
6269 | */ | 6316 | */ |
@@ -6283,6 +6330,7 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, | |||
6283 | bf_set(lpfc_sli4_sge_offset, sgl, offset); | 6330 | bf_set(lpfc_sli4_sge_offset, sgl, offset); |
6284 | offset += bde.tus.f.bdeSize; | 6331 | offset += bde.tus.f.bdeSize; |
6285 | } | 6332 | } |
6333 | sgl->word2 = cpu_to_le32(sgl->word2); | ||
6286 | bpl++; | 6334 | bpl++; |
6287 | sgl++; | 6335 | sgl++; |
6288 | } | 6336 | } |
@@ -6528,9 +6576,9 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, | |||
6528 | numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize / | 6576 | numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize / |
6529 | sizeof(struct ulp_bde64); | 6577 | sizeof(struct ulp_bde64); |
6530 | for (i = 0; i < numBdes; i++) { | 6578 | for (i = 0; i < numBdes; i++) { |
6531 | if (bpl[i].tus.f.bdeFlags != BUFF_TYPE_BDE_64) | ||
6532 | break; | ||
6533 | bde.tus.w = le32_to_cpu(bpl[i].tus.w); | 6579 | bde.tus.w = le32_to_cpu(bpl[i].tus.w); |
6580 | if (bde.tus.f.bdeFlags != BUFF_TYPE_BDE_64) | ||
6581 | break; | ||
6534 | xmit_len += bde.tus.f.bdeSize; | 6582 | xmit_len += bde.tus.f.bdeSize; |
6535 | } | 6583 | } |
6536 | /* word3 iocb=IO_TAG wqe=request_payload_len */ | 6584 | /* word3 iocb=IO_TAG wqe=request_payload_len */ |
@@ -6620,15 +6668,15 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, | |||
6620 | xritag = 0; | 6668 | xritag = 0; |
6621 | break; | 6669 | break; |
6622 | case CMD_XMIT_BLS_RSP64_CX: | 6670 | case CMD_XMIT_BLS_RSP64_CX: |
6623 | /* As BLS ABTS-ACC WQE is very different from other WQEs, | 6671 | /* As BLS ABTS RSP WQE is very different from other WQEs, |
6624 | * we re-construct this WQE here based on information in | 6672 | * we re-construct this WQE here based on information in |
6625 | * iocbq from scratch. | 6673 | * iocbq from scratch. |
6626 | */ | 6674 | */ |
6627 | memset(wqe, 0, sizeof(union lpfc_wqe)); | 6675 | memset(wqe, 0, sizeof(union lpfc_wqe)); |
6628 | /* OX_ID is invariable to who sent ABTS to CT exchange */ | 6676 | /* OX_ID is invariable to who sent ABTS to CT exchange */ |
6629 | bf_set(xmit_bls_rsp64_oxid, &wqe->xmit_bls_rsp, | 6677 | bf_set(xmit_bls_rsp64_oxid, &wqe->xmit_bls_rsp, |
6630 | bf_get(lpfc_abts_oxid, &iocbq->iocb.un.bls_acc)); | 6678 | bf_get(lpfc_abts_oxid, &iocbq->iocb.un.bls_rsp)); |
6631 | if (bf_get(lpfc_abts_orig, &iocbq->iocb.un.bls_acc) == | 6679 | if (bf_get(lpfc_abts_orig, &iocbq->iocb.un.bls_rsp) == |
6632 | LPFC_ABTS_UNSOL_INT) { | 6680 | LPFC_ABTS_UNSOL_INT) { |
6633 | /* ABTS sent by initiator to CT exchange, the | 6681 | /* ABTS sent by initiator to CT exchange, the |
6634 | * RX_ID field will be filled with the newly | 6682 | * RX_ID field will be filled with the newly |
@@ -6642,7 +6690,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, | |||
6642 | * RX_ID from ABTS. | 6690 | * RX_ID from ABTS. |
6643 | */ | 6691 | */ |
6644 | bf_set(xmit_bls_rsp64_rxid, &wqe->xmit_bls_rsp, | 6692 | bf_set(xmit_bls_rsp64_rxid, &wqe->xmit_bls_rsp, |
6645 | bf_get(lpfc_abts_rxid, &iocbq->iocb.un.bls_acc)); | 6693 | bf_get(lpfc_abts_rxid, &iocbq->iocb.un.bls_rsp)); |
6646 | } | 6694 | } |
6647 | bf_set(xmit_bls_rsp64_seqcnthi, &wqe->xmit_bls_rsp, 0xffff); | 6695 | bf_set(xmit_bls_rsp64_seqcnthi, &wqe->xmit_bls_rsp, 0xffff); |
6648 | bf_set(wqe_xmit_bls_pt, &wqe->xmit_bls_rsp.wqe_dest, 0x1); | 6696 | bf_set(wqe_xmit_bls_pt, &wqe->xmit_bls_rsp.wqe_dest, 0x1); |
@@ -6653,6 +6701,15 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, | |||
6653 | LPFC_WQE_LENLOC_NONE); | 6701 | LPFC_WQE_LENLOC_NONE); |
6654 | /* Overwrite the pre-set comnd type with OTHER_COMMAND */ | 6702 | /* Overwrite the pre-set comnd type with OTHER_COMMAND */ |
6655 | command_type = OTHER_COMMAND; | 6703 | command_type = OTHER_COMMAND; |
6704 | if (iocbq->iocb.un.xseq64.w5.hcsw.Rctl == FC_RCTL_BA_RJT) { | ||
6705 | bf_set(xmit_bls_rsp64_rjt_vspec, &wqe->xmit_bls_rsp, | ||
6706 | bf_get(lpfc_vndr_code, &iocbq->iocb.un.bls_rsp)); | ||
6707 | bf_set(xmit_bls_rsp64_rjt_expc, &wqe->xmit_bls_rsp, | ||
6708 | bf_get(lpfc_rsn_expln, &iocbq->iocb.un.bls_rsp)); | ||
6709 | bf_set(xmit_bls_rsp64_rjt_rsnc, &wqe->xmit_bls_rsp, | ||
6710 | bf_get(lpfc_rsn_code, &iocbq->iocb.un.bls_rsp)); | ||
6711 | } | ||
6712 | |||
6656 | break; | 6713 | break; |
6657 | case CMD_XRI_ABORTED_CX: | 6714 | case CMD_XRI_ABORTED_CX: |
6658 | case CMD_CREATE_XRI_CR: /* Do we expect to use this? */ | 6715 | case CMD_CREATE_XRI_CR: /* Do we expect to use this? */ |
@@ -6701,7 +6758,8 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, | |||
6701 | 6758 | ||
6702 | if (piocb->sli4_xritag == NO_XRI) { | 6759 | if (piocb->sli4_xritag == NO_XRI) { |
6703 | if (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN || | 6760 | if (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN || |
6704 | piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN) | 6761 | piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN || |
6762 | piocb->iocb.ulpCommand == CMD_XMIT_BLS_RSP64_CX) | ||
6705 | sglq = NULL; | 6763 | sglq = NULL; |
6706 | else { | 6764 | else { |
6707 | if (pring->txq_cnt) { | 6765 | if (pring->txq_cnt) { |
@@ -8194,7 +8252,8 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, | |||
8194 | piocb->iocb_flag &= ~LPFC_IO_WAKE; | 8252 | piocb->iocb_flag &= ~LPFC_IO_WAKE; |
8195 | 8253 | ||
8196 | if (phba->cfg_poll & DISABLE_FCP_RING_INT) { | 8254 | if (phba->cfg_poll & DISABLE_FCP_RING_INT) { |
8197 | creg_val = readl(phba->HCregaddr); | 8255 | if (lpfc_readl(phba->HCregaddr, &creg_val)) |
8256 | return IOCB_ERROR; | ||
8198 | creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); | 8257 | creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); |
8199 | writel(creg_val, phba->HCregaddr); | 8258 | writel(creg_val, phba->HCregaddr); |
8200 | readl(phba->HCregaddr); /* flush */ | 8259 | readl(phba->HCregaddr); /* flush */ |
@@ -8236,7 +8295,8 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, | |||
8236 | } | 8295 | } |
8237 | 8296 | ||
8238 | if (phba->cfg_poll & DISABLE_FCP_RING_INT) { | 8297 | if (phba->cfg_poll & DISABLE_FCP_RING_INT) { |
8239 | creg_val = readl(phba->HCregaddr); | 8298 | if (lpfc_readl(phba->HCregaddr, &creg_val)) |
8299 | return IOCB_ERROR; | ||
8240 | creg_val &= ~(HC_R0INT_ENA << LPFC_FCP_RING); | 8300 | creg_val &= ~(HC_R0INT_ENA << LPFC_FCP_RING); |
8241 | writel(creg_val, phba->HCregaddr); | 8301 | writel(creg_val, phba->HCregaddr); |
8242 | readl(phba->HCregaddr); /* flush */ | 8302 | readl(phba->HCregaddr); /* flush */ |
@@ -8387,10 +8447,13 @@ lpfc_sli_eratt_read(struct lpfc_hba *phba) | |||
8387 | uint32_t ha_copy; | 8447 | uint32_t ha_copy; |
8388 | 8448 | ||
8389 | /* Read chip Host Attention (HA) register */ | 8449 | /* Read chip Host Attention (HA) register */ |
8390 | ha_copy = readl(phba->HAregaddr); | 8450 | if (lpfc_readl(phba->HAregaddr, &ha_copy)) |
8451 | goto unplug_err; | ||
8452 | |||
8391 | if (ha_copy & HA_ERATT) { | 8453 | if (ha_copy & HA_ERATT) { |
8392 | /* Read host status register to retrieve error event */ | 8454 | /* Read host status register to retrieve error event */ |
8393 | lpfc_sli_read_hs(phba); | 8455 | if (lpfc_sli_read_hs(phba)) |
8456 | goto unplug_err; | ||
8394 | 8457 | ||
8395 | /* Check if there is a deferred error condition is active */ | 8458 | /* Check if there is a deferred error condition is active */ |
8396 | if ((HS_FFER1 & phba->work_hs) && | 8459 | if ((HS_FFER1 & phba->work_hs) && |
@@ -8409,6 +8472,15 @@ lpfc_sli_eratt_read(struct lpfc_hba *phba) | |||
8409 | return 1; | 8472 | return 1; |
8410 | } | 8473 | } |
8411 | return 0; | 8474 | return 0; |
8475 | |||
8476 | unplug_err: | ||
8477 | /* Set the driver HS work bitmap */ | ||
8478 | phba->work_hs |= UNPLUG_ERR; | ||
8479 | /* Set the driver HA work bitmap */ | ||
8480 | phba->work_ha |= HA_ERATT; | ||
8481 | /* Indicate polling handles this ERATT */ | ||
8482 | phba->hba_flag |= HBA_ERATT_HANDLED; | ||
8483 | return 1; | ||
8412 | } | 8484 | } |
8413 | 8485 | ||
8414 | /** | 8486 | /** |
@@ -8436,8 +8508,15 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba) | |||
8436 | if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); | 8508 | if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); |
8437 | switch (if_type) { | 8509 | switch (if_type) { |
8438 | case LPFC_SLI_INTF_IF_TYPE_0: | 8510 | case LPFC_SLI_INTF_IF_TYPE_0: |
8439 | uerr_sta_lo = readl(phba->sli4_hba.u.if_type0.UERRLOregaddr); | 8511 | if (lpfc_readl(phba->sli4_hba.u.if_type0.UERRLOregaddr, |
8440 | uerr_sta_hi = readl(phba->sli4_hba.u.if_type0.UERRHIregaddr); | 8512 | &uerr_sta_lo) || |
8513 | lpfc_readl(phba->sli4_hba.u.if_type0.UERRHIregaddr, | ||
8514 | &uerr_sta_hi)) { | ||
8515 | phba->work_hs |= UNPLUG_ERR; | ||
8516 | phba->work_ha |= HA_ERATT; | ||
8517 | phba->hba_flag |= HBA_ERATT_HANDLED; | ||
8518 | return 1; | ||
8519 | } | ||
8441 | if ((~phba->sli4_hba.ue_mask_lo & uerr_sta_lo) || | 8520 | if ((~phba->sli4_hba.ue_mask_lo & uerr_sta_lo) || |
8442 | (~phba->sli4_hba.ue_mask_hi & uerr_sta_hi)) { | 8521 | (~phba->sli4_hba.ue_mask_hi & uerr_sta_hi)) { |
8443 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | 8522 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, |
@@ -8456,9 +8535,15 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba) | |||
8456 | } | 8535 | } |
8457 | break; | 8536 | break; |
8458 | case LPFC_SLI_INTF_IF_TYPE_2: | 8537 | case LPFC_SLI_INTF_IF_TYPE_2: |
8459 | portstat_reg.word0 = | 8538 | if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, |
8460 | readl(phba->sli4_hba.u.if_type2.STATUSregaddr); | 8539 | &portstat_reg.word0) || |
8461 | portsmphr = readl(phba->sli4_hba.PSMPHRregaddr); | 8540 | lpfc_readl(phba->sli4_hba.PSMPHRregaddr, |
8541 | &portsmphr)){ | ||
8542 | phba->work_hs |= UNPLUG_ERR; | ||
8543 | phba->work_ha |= HA_ERATT; | ||
8544 | phba->hba_flag |= HBA_ERATT_HANDLED; | ||
8545 | return 1; | ||
8546 | } | ||
8462 | if (bf_get(lpfc_sliport_status_err, &portstat_reg)) { | 8547 | if (bf_get(lpfc_sliport_status_err, &portstat_reg)) { |
8463 | phba->work_status[0] = | 8548 | phba->work_status[0] = |
8464 | readl(phba->sli4_hba.u.if_type2.ERR1regaddr); | 8549 | readl(phba->sli4_hba.u.if_type2.ERR1regaddr); |
@@ -8639,7 +8724,8 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) | |||
8639 | return IRQ_NONE; | 8724 | return IRQ_NONE; |
8640 | /* Need to read HA REG for slow-path events */ | 8725 | /* Need to read HA REG for slow-path events */ |
8641 | spin_lock_irqsave(&phba->hbalock, iflag); | 8726 | spin_lock_irqsave(&phba->hbalock, iflag); |
8642 | ha_copy = readl(phba->HAregaddr); | 8727 | if (lpfc_readl(phba->HAregaddr, &ha_copy)) |
8728 | goto unplug_error; | ||
8643 | /* If somebody is waiting to handle an eratt don't process it | 8729 | /* If somebody is waiting to handle an eratt don't process it |
8644 | * here. The brdkill function will do this. | 8730 | * here. The brdkill function will do this. |
8645 | */ | 8731 | */ |
@@ -8665,7 +8751,9 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) | |||
8665 | } | 8751 | } |
8666 | 8752 | ||
8667 | /* Clear up only attention source related to slow-path */ | 8753 | /* Clear up only attention source related to slow-path */ |
8668 | hc_copy = readl(phba->HCregaddr); | 8754 | if (lpfc_readl(phba->HCregaddr, &hc_copy)) |
8755 | goto unplug_error; | ||
8756 | |||
8669 | writel(hc_copy & ~(HC_MBINT_ENA | HC_R2INT_ENA | | 8757 | writel(hc_copy & ~(HC_MBINT_ENA | HC_R2INT_ENA | |
8670 | HC_LAINT_ENA | HC_ERINT_ENA), | 8758 | HC_LAINT_ENA | HC_ERINT_ENA), |
8671 | phba->HCregaddr); | 8759 | phba->HCregaddr); |
@@ -8688,7 +8776,8 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) | |||
8688 | */ | 8776 | */ |
8689 | spin_lock_irqsave(&phba->hbalock, iflag); | 8777 | spin_lock_irqsave(&phba->hbalock, iflag); |
8690 | phba->sli.sli_flag &= ~LPFC_PROCESS_LA; | 8778 | phba->sli.sli_flag &= ~LPFC_PROCESS_LA; |
8691 | control = readl(phba->HCregaddr); | 8779 | if (lpfc_readl(phba->HCregaddr, &control)) |
8780 | goto unplug_error; | ||
8692 | control &= ~HC_LAINT_ENA; | 8781 | control &= ~HC_LAINT_ENA; |
8693 | writel(control, phba->HCregaddr); | 8782 | writel(control, phba->HCregaddr); |
8694 | readl(phba->HCregaddr); /* flush */ | 8783 | readl(phba->HCregaddr); /* flush */ |
@@ -8708,7 +8797,8 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) | |||
8708 | status >>= (4*LPFC_ELS_RING); | 8797 | status >>= (4*LPFC_ELS_RING); |
8709 | if (status & HA_RXMASK) { | 8798 | if (status & HA_RXMASK) { |
8710 | spin_lock_irqsave(&phba->hbalock, iflag); | 8799 | spin_lock_irqsave(&phba->hbalock, iflag); |
8711 | control = readl(phba->HCregaddr); | 8800 | if (lpfc_readl(phba->HCregaddr, &control)) |
8801 | goto unplug_error; | ||
8712 | 8802 | ||
8713 | lpfc_debugfs_slow_ring_trc(phba, | 8803 | lpfc_debugfs_slow_ring_trc(phba, |
8714 | "ISR slow ring: ctl:x%x stat:x%x isrcnt:x%x", | 8804 | "ISR slow ring: ctl:x%x stat:x%x isrcnt:x%x", |
@@ -8741,7 +8831,8 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) | |||
8741 | } | 8831 | } |
8742 | spin_lock_irqsave(&phba->hbalock, iflag); | 8832 | spin_lock_irqsave(&phba->hbalock, iflag); |
8743 | if (work_ha_copy & HA_ERATT) { | 8833 | if (work_ha_copy & HA_ERATT) { |
8744 | lpfc_sli_read_hs(phba); | 8834 | if (lpfc_sli_read_hs(phba)) |
8835 | goto unplug_error; | ||
8745 | /* | 8836 | /* |
8746 | * Check if there is a deferred error condition | 8837 | * Check if there is a deferred error condition |
8747 | * is active | 8838 | * is active |
@@ -8872,6 +8963,9 @@ send_current_mbox: | |||
8872 | lpfc_worker_wake_up(phba); | 8963 | lpfc_worker_wake_up(phba); |
8873 | } | 8964 | } |
8874 | return IRQ_HANDLED; | 8965 | return IRQ_HANDLED; |
8966 | unplug_error: | ||
8967 | spin_unlock_irqrestore(&phba->hbalock, iflag); | ||
8968 | return IRQ_HANDLED; | ||
8875 | 8969 | ||
8876 | } /* lpfc_sli_sp_intr_handler */ | 8970 | } /* lpfc_sli_sp_intr_handler */ |
8877 | 8971 | ||
@@ -8919,7 +9013,8 @@ lpfc_sli_fp_intr_handler(int irq, void *dev_id) | |||
8919 | if (lpfc_intr_state_check(phba)) | 9013 | if (lpfc_intr_state_check(phba)) |
8920 | return IRQ_NONE; | 9014 | return IRQ_NONE; |
8921 | /* Need to read HA REG for FCP ring and other ring events */ | 9015 | /* Need to read HA REG for FCP ring and other ring events */ |
8922 | ha_copy = readl(phba->HAregaddr); | 9016 | if (lpfc_readl(phba->HAregaddr, &ha_copy)) |
9017 | return IRQ_HANDLED; | ||
8923 | /* Clear up only attention source related to fast-path */ | 9018 | /* Clear up only attention source related to fast-path */ |
8924 | spin_lock_irqsave(&phba->hbalock, iflag); | 9019 | spin_lock_irqsave(&phba->hbalock, iflag); |
8925 | /* | 9020 | /* |
@@ -9004,7 +9099,11 @@ lpfc_sli_intr_handler(int irq, void *dev_id) | |||
9004 | return IRQ_NONE; | 9099 | return IRQ_NONE; |
9005 | 9100 | ||
9006 | spin_lock(&phba->hbalock); | 9101 | spin_lock(&phba->hbalock); |
9007 | phba->ha_copy = readl(phba->HAregaddr); | 9102 | if (lpfc_readl(phba->HAregaddr, &phba->ha_copy)) { |
9103 | spin_unlock(&phba->hbalock); | ||
9104 | return IRQ_HANDLED; | ||
9105 | } | ||
9106 | |||
9008 | if (unlikely(!phba->ha_copy)) { | 9107 | if (unlikely(!phba->ha_copy)) { |
9009 | spin_unlock(&phba->hbalock); | 9108 | spin_unlock(&phba->hbalock); |
9010 | return IRQ_NONE; | 9109 | return IRQ_NONE; |
@@ -9026,7 +9125,10 @@ lpfc_sli_intr_handler(int irq, void *dev_id) | |||
9026 | } | 9125 | } |
9027 | 9126 | ||
9028 | /* Clear attention sources except link and error attentions */ | 9127 | /* Clear attention sources except link and error attentions */ |
9029 | hc_copy = readl(phba->HCregaddr); | 9128 | if (lpfc_readl(phba->HCregaddr, &hc_copy)) { |
9129 | spin_unlock(&phba->hbalock); | ||
9130 | return IRQ_HANDLED; | ||
9131 | } | ||
9030 | writel(hc_copy & ~(HC_MBINT_ENA | HC_R0INT_ENA | HC_R1INT_ENA | 9132 | writel(hc_copy & ~(HC_MBINT_ENA | HC_R0INT_ENA | HC_R1INT_ENA |
9031 | | HC_R2INT_ENA | HC_LAINT_ENA | HC_ERINT_ENA), | 9133 | | HC_R2INT_ENA | HC_LAINT_ENA | HC_ERINT_ENA), |
9032 | phba->HCregaddr); | 9134 | phba->HCregaddr); |
@@ -10403,7 +10505,6 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, | |||
10403 | if (!phba->sli4_hba.pc_sli4_params.supported) | 10505 | if (!phba->sli4_hba.pc_sli4_params.supported) |
10404 | hw_page_size = SLI4_PAGE_SIZE; | 10506 | hw_page_size = SLI4_PAGE_SIZE; |
10405 | 10507 | ||
10406 | |||
10407 | mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | 10508 | mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); |
10408 | if (!mbox) | 10509 | if (!mbox) |
10409 | return -ENOMEM; | 10510 | return -ENOMEM; |
@@ -10413,11 +10514,22 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, | |||
10413 | LPFC_MBOX_OPCODE_CQ_CREATE, | 10514 | LPFC_MBOX_OPCODE_CQ_CREATE, |
10414 | length, LPFC_SLI4_MBX_EMBED); | 10515 | length, LPFC_SLI4_MBX_EMBED); |
10415 | cq_create = &mbox->u.mqe.un.cq_create; | 10516 | cq_create = &mbox->u.mqe.un.cq_create; |
10517 | shdr = (union lpfc_sli4_cfg_shdr *) &cq_create->header.cfg_shdr; | ||
10416 | bf_set(lpfc_mbx_cq_create_num_pages, &cq_create->u.request, | 10518 | bf_set(lpfc_mbx_cq_create_num_pages, &cq_create->u.request, |
10417 | cq->page_count); | 10519 | cq->page_count); |
10418 | bf_set(lpfc_cq_context_event, &cq_create->u.request.context, 1); | 10520 | bf_set(lpfc_cq_context_event, &cq_create->u.request.context, 1); |
10419 | bf_set(lpfc_cq_context_valid, &cq_create->u.request.context, 1); | 10521 | bf_set(lpfc_cq_context_valid, &cq_create->u.request.context, 1); |
10420 | bf_set(lpfc_cq_eq_id, &cq_create->u.request.context, eq->queue_id); | 10522 | bf_set(lpfc_mbox_hdr_version, &shdr->request, |
10523 | phba->sli4_hba.pc_sli4_params.cqv); | ||
10524 | if (phba->sli4_hba.pc_sli4_params.cqv == LPFC_Q_CREATE_VERSION_2) { | ||
10525 | bf_set(lpfc_mbx_cq_create_page_size, &cq_create->u.request, | ||
10526 | (PAGE_SIZE/SLI4_PAGE_SIZE)); | ||
10527 | bf_set(lpfc_cq_eq_id_2, &cq_create->u.request.context, | ||
10528 | eq->queue_id); | ||
10529 | } else { | ||
10530 | bf_set(lpfc_cq_eq_id, &cq_create->u.request.context, | ||
10531 | eq->queue_id); | ||
10532 | } | ||
10421 | switch (cq->entry_count) { | 10533 | switch (cq->entry_count) { |
10422 | default: | 10534 | default: |
10423 | lpfc_printf_log(phba, KERN_ERR, LOG_SLI, | 10535 | lpfc_printf_log(phba, KERN_ERR, LOG_SLI, |
@@ -10449,7 +10561,6 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, | |||
10449 | rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); | 10561 | rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); |
10450 | 10562 | ||
10451 | /* The IOCTL status is embedded in the mailbox subheader. */ | 10563 | /* The IOCTL status is embedded in the mailbox subheader. */ |
10452 | shdr = (union lpfc_sli4_cfg_shdr *) &cq_create->header.cfg_shdr; | ||
10453 | shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); | 10564 | shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); |
10454 | shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); | 10565 | shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); |
10455 | if (shdr_status || shdr_add_status || rc) { | 10566 | if (shdr_status || shdr_add_status || rc) { |
@@ -10515,20 +10626,20 @@ lpfc_mq_create_fb_init(struct lpfc_hba *phba, struct lpfc_queue *mq, | |||
10515 | bf_set(lpfc_mq_context_valid, &mq_create->u.request.context, 1); | 10626 | bf_set(lpfc_mq_context_valid, &mq_create->u.request.context, 1); |
10516 | switch (mq->entry_count) { | 10627 | switch (mq->entry_count) { |
10517 | case 16: | 10628 | case 16: |
10518 | bf_set(lpfc_mq_context_count, &mq_create->u.request.context, | 10629 | bf_set(lpfc_mq_context_ring_size, &mq_create->u.request.context, |
10519 | LPFC_MQ_CNT_16); | 10630 | LPFC_MQ_RING_SIZE_16); |
10520 | break; | 10631 | break; |
10521 | case 32: | 10632 | case 32: |
10522 | bf_set(lpfc_mq_context_count, &mq_create->u.request.context, | 10633 | bf_set(lpfc_mq_context_ring_size, &mq_create->u.request.context, |
10523 | LPFC_MQ_CNT_32); | 10634 | LPFC_MQ_RING_SIZE_32); |
10524 | break; | 10635 | break; |
10525 | case 64: | 10636 | case 64: |
10526 | bf_set(lpfc_mq_context_count, &mq_create->u.request.context, | 10637 | bf_set(lpfc_mq_context_ring_size, &mq_create->u.request.context, |
10527 | LPFC_MQ_CNT_64); | 10638 | LPFC_MQ_RING_SIZE_64); |
10528 | break; | 10639 | break; |
10529 | case 128: | 10640 | case 128: |
10530 | bf_set(lpfc_mq_context_count, &mq_create->u.request.context, | 10641 | bf_set(lpfc_mq_context_ring_size, &mq_create->u.request.context, |
10531 | LPFC_MQ_CNT_128); | 10642 | LPFC_MQ_RING_SIZE_128); |
10532 | break; | 10643 | break; |
10533 | } | 10644 | } |
10534 | list_for_each_entry(dmabuf, &mq->page_list, list) { | 10645 | list_for_each_entry(dmabuf, &mq->page_list, list) { |
@@ -10586,6 +10697,7 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, | |||
10586 | length, LPFC_SLI4_MBX_EMBED); | 10697 | length, LPFC_SLI4_MBX_EMBED); |
10587 | 10698 | ||
10588 | mq_create_ext = &mbox->u.mqe.un.mq_create_ext; | 10699 | mq_create_ext = &mbox->u.mqe.un.mq_create_ext; |
10700 | shdr = (union lpfc_sli4_cfg_shdr *) &mq_create_ext->header.cfg_shdr; | ||
10589 | bf_set(lpfc_mbx_mq_create_ext_num_pages, | 10701 | bf_set(lpfc_mbx_mq_create_ext_num_pages, |
10590 | &mq_create_ext->u.request, mq->page_count); | 10702 | &mq_create_ext->u.request, mq->page_count); |
10591 | bf_set(lpfc_mbx_mq_create_ext_async_evt_link, | 10703 | bf_set(lpfc_mbx_mq_create_ext_async_evt_link, |
@@ -10598,9 +10710,15 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, | |||
10598 | &mq_create_ext->u.request, 1); | 10710 | &mq_create_ext->u.request, 1); |
10599 | bf_set(lpfc_mbx_mq_create_ext_async_evt_sli, | 10711 | bf_set(lpfc_mbx_mq_create_ext_async_evt_sli, |
10600 | &mq_create_ext->u.request, 1); | 10712 | &mq_create_ext->u.request, 1); |
10601 | bf_set(lpfc_mq_context_cq_id, | ||
10602 | &mq_create_ext->u.request.context, cq->queue_id); | ||
10603 | bf_set(lpfc_mq_context_valid, &mq_create_ext->u.request.context, 1); | 10713 | bf_set(lpfc_mq_context_valid, &mq_create_ext->u.request.context, 1); |
10714 | bf_set(lpfc_mbox_hdr_version, &shdr->request, | ||
10715 | phba->sli4_hba.pc_sli4_params.mqv); | ||
10716 | if (phba->sli4_hba.pc_sli4_params.mqv == LPFC_Q_CREATE_VERSION_1) | ||
10717 | bf_set(lpfc_mbx_mq_create_ext_cq_id, &mq_create_ext->u.request, | ||
10718 | cq->queue_id); | ||
10719 | else | ||
10720 | bf_set(lpfc_mq_context_cq_id, &mq_create_ext->u.request.context, | ||
10721 | cq->queue_id); | ||
10604 | switch (mq->entry_count) { | 10722 | switch (mq->entry_count) { |
10605 | default: | 10723 | default: |
10606 | lpfc_printf_log(phba, KERN_ERR, LOG_SLI, | 10724 | lpfc_printf_log(phba, KERN_ERR, LOG_SLI, |
@@ -10610,20 +10728,24 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, | |||
10610 | return -EINVAL; | 10728 | return -EINVAL; |
10611 | /* otherwise default to smallest count (drop through) */ | 10729 | /* otherwise default to smallest count (drop through) */ |
10612 | case 16: | 10730 | case 16: |
10613 | bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context, | 10731 | bf_set(lpfc_mq_context_ring_size, |
10614 | LPFC_MQ_CNT_16); | 10732 | &mq_create_ext->u.request.context, |
10733 | LPFC_MQ_RING_SIZE_16); | ||
10615 | break; | 10734 | break; |
10616 | case 32: | 10735 | case 32: |
10617 | bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context, | 10736 | bf_set(lpfc_mq_context_ring_size, |
10618 | LPFC_MQ_CNT_32); | 10737 | &mq_create_ext->u.request.context, |
10738 | LPFC_MQ_RING_SIZE_32); | ||
10619 | break; | 10739 | break; |
10620 | case 64: | 10740 | case 64: |
10621 | bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context, | 10741 | bf_set(lpfc_mq_context_ring_size, |
10622 | LPFC_MQ_CNT_64); | 10742 | &mq_create_ext->u.request.context, |
10743 | LPFC_MQ_RING_SIZE_64); | ||
10623 | break; | 10744 | break; |
10624 | case 128: | 10745 | case 128: |
10625 | bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context, | 10746 | bf_set(lpfc_mq_context_ring_size, |
10626 | LPFC_MQ_CNT_128); | 10747 | &mq_create_ext->u.request.context, |
10748 | LPFC_MQ_RING_SIZE_128); | ||
10627 | break; | 10749 | break; |
10628 | } | 10750 | } |
10629 | list_for_each_entry(dmabuf, &mq->page_list, list) { | 10751 | list_for_each_entry(dmabuf, &mq->page_list, list) { |
@@ -10634,7 +10756,6 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, | |||
10634 | putPaddrHigh(dmabuf->phys); | 10756 | putPaddrHigh(dmabuf->phys); |
10635 | } | 10757 | } |
10636 | rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); | 10758 | rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); |
10637 | shdr = (union lpfc_sli4_cfg_shdr *) &mq_create_ext->header.cfg_shdr; | ||
10638 | mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id, | 10759 | mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id, |
10639 | &mq_create_ext->u.response); | 10760 | &mq_create_ext->u.response); |
10640 | if (rc != MBX_SUCCESS) { | 10761 | if (rc != MBX_SUCCESS) { |
@@ -10711,6 +10832,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, | |||
10711 | uint32_t shdr_status, shdr_add_status; | 10832 | uint32_t shdr_status, shdr_add_status; |
10712 | union lpfc_sli4_cfg_shdr *shdr; | 10833 | union lpfc_sli4_cfg_shdr *shdr; |
10713 | uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; | 10834 | uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; |
10835 | struct dma_address *page; | ||
10714 | 10836 | ||
10715 | if (!phba->sli4_hba.pc_sli4_params.supported) | 10837 | if (!phba->sli4_hba.pc_sli4_params.supported) |
10716 | hw_page_size = SLI4_PAGE_SIZE; | 10838 | hw_page_size = SLI4_PAGE_SIZE; |
@@ -10724,20 +10846,42 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, | |||
10724 | LPFC_MBOX_OPCODE_FCOE_WQ_CREATE, | 10846 | LPFC_MBOX_OPCODE_FCOE_WQ_CREATE, |
10725 | length, LPFC_SLI4_MBX_EMBED); | 10847 | length, LPFC_SLI4_MBX_EMBED); |
10726 | wq_create = &mbox->u.mqe.un.wq_create; | 10848 | wq_create = &mbox->u.mqe.un.wq_create; |
10849 | shdr = (union lpfc_sli4_cfg_shdr *) &wq_create->header.cfg_shdr; | ||
10727 | bf_set(lpfc_mbx_wq_create_num_pages, &wq_create->u.request, | 10850 | bf_set(lpfc_mbx_wq_create_num_pages, &wq_create->u.request, |
10728 | wq->page_count); | 10851 | wq->page_count); |
10729 | bf_set(lpfc_mbx_wq_create_cq_id, &wq_create->u.request, | 10852 | bf_set(lpfc_mbx_wq_create_cq_id, &wq_create->u.request, |
10730 | cq->queue_id); | 10853 | cq->queue_id); |
10854 | bf_set(lpfc_mbox_hdr_version, &shdr->request, | ||
10855 | phba->sli4_hba.pc_sli4_params.wqv); | ||
10856 | if (phba->sli4_hba.pc_sli4_params.wqv == LPFC_Q_CREATE_VERSION_1) { | ||
10857 | bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1, | ||
10858 | wq->entry_count); | ||
10859 | switch (wq->entry_size) { | ||
10860 | default: | ||
10861 | case 64: | ||
10862 | bf_set(lpfc_mbx_wq_create_wqe_size, | ||
10863 | &wq_create->u.request_1, | ||
10864 | LPFC_WQ_WQE_SIZE_64); | ||
10865 | break; | ||
10866 | case 128: | ||
10867 | bf_set(lpfc_mbx_wq_create_wqe_size, | ||
10868 | &wq_create->u.request_1, | ||
10869 | LPFC_WQ_WQE_SIZE_128); | ||
10870 | break; | ||
10871 | } | ||
10872 | bf_set(lpfc_mbx_wq_create_page_size, &wq_create->u.request_1, | ||
10873 | (PAGE_SIZE/SLI4_PAGE_SIZE)); | ||
10874 | page = wq_create->u.request_1.page; | ||
10875 | } else { | ||
10876 | page = wq_create->u.request.page; | ||
10877 | } | ||
10731 | list_for_each_entry(dmabuf, &wq->page_list, list) { | 10878 | list_for_each_entry(dmabuf, &wq->page_list, list) { |
10732 | memset(dmabuf->virt, 0, hw_page_size); | 10879 | memset(dmabuf->virt, 0, hw_page_size); |
10733 | wq_create->u.request.page[dmabuf->buffer_tag].addr_lo = | 10880 | page[dmabuf->buffer_tag].addr_lo = putPaddrLow(dmabuf->phys); |
10734 | putPaddrLow(dmabuf->phys); | 10881 | page[dmabuf->buffer_tag].addr_hi = putPaddrHigh(dmabuf->phys); |
10735 | wq_create->u.request.page[dmabuf->buffer_tag].addr_hi = | ||
10736 | putPaddrHigh(dmabuf->phys); | ||
10737 | } | 10882 | } |
10738 | rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); | 10883 | rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); |
10739 | /* The IOCTL status is embedded in the mailbox subheader. */ | 10884 | /* The IOCTL status is embedded in the mailbox subheader. */ |
10740 | shdr = (union lpfc_sli4_cfg_shdr *) &wq_create->header.cfg_shdr; | ||
10741 | shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); | 10885 | shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); |
10742 | shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); | 10886 | shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); |
10743 | if (shdr_status || shdr_add_status || rc) { | 10887 | if (shdr_status || shdr_add_status || rc) { |
@@ -10815,37 +10959,51 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, | |||
10815 | LPFC_MBOX_OPCODE_FCOE_RQ_CREATE, | 10959 | LPFC_MBOX_OPCODE_FCOE_RQ_CREATE, |
10816 | length, LPFC_SLI4_MBX_EMBED); | 10960 | length, LPFC_SLI4_MBX_EMBED); |
10817 | rq_create = &mbox->u.mqe.un.rq_create; | 10961 | rq_create = &mbox->u.mqe.un.rq_create; |
10818 | switch (hrq->entry_count) { | 10962 | shdr = (union lpfc_sli4_cfg_shdr *) &rq_create->header.cfg_shdr; |
10819 | default: | 10963 | bf_set(lpfc_mbox_hdr_version, &shdr->request, |
10820 | lpfc_printf_log(phba, KERN_ERR, LOG_SLI, | 10964 | phba->sli4_hba.pc_sli4_params.rqv); |
10821 | "2535 Unsupported RQ count. (%d)\n", | 10965 | if (phba->sli4_hba.pc_sli4_params.rqv == LPFC_Q_CREATE_VERSION_1) { |
10822 | hrq->entry_count); | 10966 | bf_set(lpfc_rq_context_rqe_count_1, |
10823 | if (hrq->entry_count < 512) | 10967 | &rq_create->u.request.context, |
10824 | return -EINVAL; | 10968 | hrq->entry_count); |
10825 | /* otherwise default to smallest count (drop through) */ | 10969 | rq_create->u.request.context.buffer_size = LPFC_HDR_BUF_SIZE; |
10826 | case 512: | 10970 | } else { |
10827 | bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, | 10971 | switch (hrq->entry_count) { |
10828 | LPFC_RQ_RING_SIZE_512); | 10972 | default: |
10829 | break; | 10973 | lpfc_printf_log(phba, KERN_ERR, LOG_SLI, |
10830 | case 1024: | 10974 | "2535 Unsupported RQ count. (%d)\n", |
10831 | bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, | 10975 | hrq->entry_count); |
10832 | LPFC_RQ_RING_SIZE_1024); | 10976 | if (hrq->entry_count < 512) |
10833 | break; | 10977 | return -EINVAL; |
10834 | case 2048: | 10978 | /* otherwise default to smallest count (drop through) */ |
10835 | bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, | 10979 | case 512: |
10836 | LPFC_RQ_RING_SIZE_2048); | 10980 | bf_set(lpfc_rq_context_rqe_count, |
10837 | break; | 10981 | &rq_create->u.request.context, |
10838 | case 4096: | 10982 | LPFC_RQ_RING_SIZE_512); |
10839 | bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, | 10983 | break; |
10840 | LPFC_RQ_RING_SIZE_4096); | 10984 | case 1024: |
10841 | break; | 10985 | bf_set(lpfc_rq_context_rqe_count, |
10986 | &rq_create->u.request.context, | ||
10987 | LPFC_RQ_RING_SIZE_1024); | ||
10988 | break; | ||
10989 | case 2048: | ||
10990 | bf_set(lpfc_rq_context_rqe_count, | ||
10991 | &rq_create->u.request.context, | ||
10992 | LPFC_RQ_RING_SIZE_2048); | ||
10993 | break; | ||
10994 | case 4096: | ||
10995 | bf_set(lpfc_rq_context_rqe_count, | ||
10996 | &rq_create->u.request.context, | ||
10997 | LPFC_RQ_RING_SIZE_4096); | ||
10998 | break; | ||
10999 | } | ||
11000 | bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context, | ||
11001 | LPFC_HDR_BUF_SIZE); | ||
10842 | } | 11002 | } |
10843 | bf_set(lpfc_rq_context_cq_id, &rq_create->u.request.context, | 11003 | bf_set(lpfc_rq_context_cq_id, &rq_create->u.request.context, |
10844 | cq->queue_id); | 11004 | cq->queue_id); |
10845 | bf_set(lpfc_mbx_rq_create_num_pages, &rq_create->u.request, | 11005 | bf_set(lpfc_mbx_rq_create_num_pages, &rq_create->u.request, |
10846 | hrq->page_count); | 11006 | hrq->page_count); |
10847 | bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context, | ||
10848 | LPFC_HDR_BUF_SIZE); | ||
10849 | list_for_each_entry(dmabuf, &hrq->page_list, list) { | 11007 | list_for_each_entry(dmabuf, &hrq->page_list, list) { |
10850 | memset(dmabuf->virt, 0, hw_page_size); | 11008 | memset(dmabuf->virt, 0, hw_page_size); |
10851 | rq_create->u.request.page[dmabuf->buffer_tag].addr_lo = | 11009 | rq_create->u.request.page[dmabuf->buffer_tag].addr_lo = |
@@ -10855,7 +11013,6 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, | |||
10855 | } | 11013 | } |
10856 | rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); | 11014 | rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); |
10857 | /* The IOCTL status is embedded in the mailbox subheader. */ | 11015 | /* The IOCTL status is embedded in the mailbox subheader. */ |
10858 | shdr = (union lpfc_sli4_cfg_shdr *) &rq_create->header.cfg_shdr; | ||
10859 | shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); | 11016 | shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); |
10860 | shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); | 11017 | shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); |
10861 | if (shdr_status || shdr_add_status || rc) { | 11018 | if (shdr_status || shdr_add_status || rc) { |
@@ -10881,37 +11038,50 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, | |||
10881 | lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, | 11038 | lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, |
10882 | LPFC_MBOX_OPCODE_FCOE_RQ_CREATE, | 11039 | LPFC_MBOX_OPCODE_FCOE_RQ_CREATE, |
10883 | length, LPFC_SLI4_MBX_EMBED); | 11040 | length, LPFC_SLI4_MBX_EMBED); |
10884 | switch (drq->entry_count) { | 11041 | bf_set(lpfc_mbox_hdr_version, &shdr->request, |
10885 | default: | 11042 | phba->sli4_hba.pc_sli4_params.rqv); |
10886 | lpfc_printf_log(phba, KERN_ERR, LOG_SLI, | 11043 | if (phba->sli4_hba.pc_sli4_params.rqv == LPFC_Q_CREATE_VERSION_1) { |
10887 | "2536 Unsupported RQ count. (%d)\n", | 11044 | bf_set(lpfc_rq_context_rqe_count_1, |
10888 | drq->entry_count); | 11045 | &rq_create->u.request.context, |
10889 | if (drq->entry_count < 512) | 11046 | hrq->entry_count); |
10890 | return -EINVAL; | 11047 | rq_create->u.request.context.buffer_size = LPFC_DATA_BUF_SIZE; |
10891 | /* otherwise default to smallest count (drop through) */ | 11048 | } else { |
10892 | case 512: | 11049 | switch (drq->entry_count) { |
10893 | bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, | 11050 | default: |
10894 | LPFC_RQ_RING_SIZE_512); | 11051 | lpfc_printf_log(phba, KERN_ERR, LOG_SLI, |
10895 | break; | 11052 | "2536 Unsupported RQ count. (%d)\n", |
10896 | case 1024: | 11053 | drq->entry_count); |
10897 | bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, | 11054 | if (drq->entry_count < 512) |
10898 | LPFC_RQ_RING_SIZE_1024); | 11055 | return -EINVAL; |
10899 | break; | 11056 | /* otherwise default to smallest count (drop through) */ |
10900 | case 2048: | 11057 | case 512: |
10901 | bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, | 11058 | bf_set(lpfc_rq_context_rqe_count, |
10902 | LPFC_RQ_RING_SIZE_2048); | 11059 | &rq_create->u.request.context, |
10903 | break; | 11060 | LPFC_RQ_RING_SIZE_512); |
10904 | case 4096: | 11061 | break; |
10905 | bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, | 11062 | case 1024: |
10906 | LPFC_RQ_RING_SIZE_4096); | 11063 | bf_set(lpfc_rq_context_rqe_count, |
10907 | break; | 11064 | &rq_create->u.request.context, |
11065 | LPFC_RQ_RING_SIZE_1024); | ||
11066 | break; | ||
11067 | case 2048: | ||
11068 | bf_set(lpfc_rq_context_rqe_count, | ||
11069 | &rq_create->u.request.context, | ||
11070 | LPFC_RQ_RING_SIZE_2048); | ||
11071 | break; | ||
11072 | case 4096: | ||
11073 | bf_set(lpfc_rq_context_rqe_count, | ||
11074 | &rq_create->u.request.context, | ||
11075 | LPFC_RQ_RING_SIZE_4096); | ||
11076 | break; | ||
11077 | } | ||
11078 | bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context, | ||
11079 | LPFC_DATA_BUF_SIZE); | ||
10908 | } | 11080 | } |
10909 | bf_set(lpfc_rq_context_cq_id, &rq_create->u.request.context, | 11081 | bf_set(lpfc_rq_context_cq_id, &rq_create->u.request.context, |
10910 | cq->queue_id); | 11082 | cq->queue_id); |
10911 | bf_set(lpfc_mbx_rq_create_num_pages, &rq_create->u.request, | 11083 | bf_set(lpfc_mbx_rq_create_num_pages, &rq_create->u.request, |
10912 | drq->page_count); | 11084 | drq->page_count); |
10913 | bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context, | ||
10914 | LPFC_DATA_BUF_SIZE); | ||
10915 | list_for_each_entry(dmabuf, &drq->page_list, list) { | 11085 | list_for_each_entry(dmabuf, &drq->page_list, list) { |
10916 | rq_create->u.request.page[dmabuf->buffer_tag].addr_lo = | 11086 | rq_create->u.request.page[dmabuf->buffer_tag].addr_lo = |
10917 | putPaddrLow(dmabuf->phys); | 11087 | putPaddrLow(dmabuf->phys); |
@@ -11580,6 +11750,7 @@ lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr) | |||
11580 | static char *rctl_names[] = FC_RCTL_NAMES_INIT; | 11750 | static char *rctl_names[] = FC_RCTL_NAMES_INIT; |
11581 | char *type_names[] = FC_TYPE_NAMES_INIT; | 11751 | char *type_names[] = FC_TYPE_NAMES_INIT; |
11582 | struct fc_vft_header *fc_vft_hdr; | 11752 | struct fc_vft_header *fc_vft_hdr; |
11753 | uint32_t *header = (uint32_t *) fc_hdr; | ||
11583 | 11754 | ||
11584 | switch (fc_hdr->fh_r_ctl) { | 11755 | switch (fc_hdr->fh_r_ctl) { |
11585 | case FC_RCTL_DD_UNCAT: /* uncategorized information */ | 11756 | case FC_RCTL_DD_UNCAT: /* uncategorized information */ |
@@ -11628,10 +11799,15 @@ lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr) | |||
11628 | default: | 11799 | default: |
11629 | goto drop; | 11800 | goto drop; |
11630 | } | 11801 | } |
11802 | |||
11631 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | 11803 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, |
11632 | "2538 Received frame rctl:%s type:%s\n", | 11804 | "2538 Received frame rctl:%s type:%s " |
11805 | "Frame Data:%08x %08x %08x %08x %08x %08x\n", | ||
11633 | rctl_names[fc_hdr->fh_r_ctl], | 11806 | rctl_names[fc_hdr->fh_r_ctl], |
11634 | type_names[fc_hdr->fh_type]); | 11807 | type_names[fc_hdr->fh_type], |
11808 | be32_to_cpu(header[0]), be32_to_cpu(header[1]), | ||
11809 | be32_to_cpu(header[2]), be32_to_cpu(header[3]), | ||
11810 | be32_to_cpu(header[4]), be32_to_cpu(header[5])); | ||
11635 | return 0; | 11811 | return 0; |
11636 | drop: | 11812 | drop: |
11637 | lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, | 11813 | lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, |
@@ -11928,17 +12104,17 @@ lpfc_sli4_abort_partial_seq(struct lpfc_vport *vport, | |||
11928 | } | 12104 | } |
11929 | 12105 | ||
11930 | /** | 12106 | /** |
11931 | * lpfc_sli4_seq_abort_acc_cmpl - Accept seq abort iocb complete handler | 12107 | * lpfc_sli4_seq_abort_rsp_cmpl - BLS ABORT RSP seq abort iocb complete handler |
11932 | * @phba: Pointer to HBA context object. | 12108 | * @phba: Pointer to HBA context object. |
11933 | * @cmd_iocbq: pointer to the command iocbq structure. | 12109 | * @cmd_iocbq: pointer to the command iocbq structure. |
11934 | * @rsp_iocbq: pointer to the response iocbq structure. | 12110 | * @rsp_iocbq: pointer to the response iocbq structure. |
11935 | * | 12111 | * |
11936 | * This function handles the sequence abort accept iocb command complete | 12112 | * This function handles the sequence abort response iocb command complete |
11937 | * event. It properly releases the memory allocated to the sequence abort | 12113 | * event. It properly releases the memory allocated to the sequence abort |
11938 | * accept iocb. | 12114 | * accept iocb. |
11939 | **/ | 12115 | **/ |
11940 | static void | 12116 | static void |
11941 | lpfc_sli4_seq_abort_acc_cmpl(struct lpfc_hba *phba, | 12117 | lpfc_sli4_seq_abort_rsp_cmpl(struct lpfc_hba *phba, |
11942 | struct lpfc_iocbq *cmd_iocbq, | 12118 | struct lpfc_iocbq *cmd_iocbq, |
11943 | struct lpfc_iocbq *rsp_iocbq) | 12119 | struct lpfc_iocbq *rsp_iocbq) |
11944 | { | 12120 | { |
@@ -11947,15 +12123,15 @@ lpfc_sli4_seq_abort_acc_cmpl(struct lpfc_hba *phba, | |||
11947 | } | 12123 | } |
11948 | 12124 | ||
11949 | /** | 12125 | /** |
11950 | * lpfc_sli4_seq_abort_acc - Accept sequence abort | 12126 | * lpfc_sli4_seq_abort_rsp - bls rsp to sequence abort |
11951 | * @phba: Pointer to HBA context object. | 12127 | * @phba: Pointer to HBA context object. |
11952 | * @fc_hdr: pointer to a FC frame header. | 12128 | * @fc_hdr: pointer to a FC frame header. |
11953 | * | 12129 | * |
11954 | * This function sends a basic accept to a previous unsol sequence abort | 12130 | * This function sends a basic response to a previous unsol sequence abort |
11955 | * event after aborting the sequence handling. | 12131 | * event after aborting the sequence handling. |
11956 | **/ | 12132 | **/ |
11957 | static void | 12133 | static void |
11958 | lpfc_sli4_seq_abort_acc(struct lpfc_hba *phba, | 12134 | lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba, |
11959 | struct fc_frame_header *fc_hdr) | 12135 | struct fc_frame_header *fc_hdr) |
11960 | { | 12136 | { |
11961 | struct lpfc_iocbq *ctiocb = NULL; | 12137 | struct lpfc_iocbq *ctiocb = NULL; |
@@ -11963,6 +12139,7 @@ lpfc_sli4_seq_abort_acc(struct lpfc_hba *phba, | |||
11963 | uint16_t oxid, rxid; | 12139 | uint16_t oxid, rxid; |
11964 | uint32_t sid, fctl; | 12140 | uint32_t sid, fctl; |
11965 | IOCB_t *icmd; | 12141 | IOCB_t *icmd; |
12142 | int rc; | ||
11966 | 12143 | ||
11967 | if (!lpfc_is_link_up(phba)) | 12144 | if (!lpfc_is_link_up(phba)) |
11968 | return; | 12145 | return; |
@@ -11983,7 +12160,7 @@ lpfc_sli4_seq_abort_acc(struct lpfc_hba *phba, | |||
11983 | + phba->sli4_hba.max_cfg_param.xri_base)) | 12160 | + phba->sli4_hba.max_cfg_param.xri_base)) |
11984 | lpfc_set_rrq_active(phba, ndlp, rxid, oxid, 0); | 12161 | lpfc_set_rrq_active(phba, ndlp, rxid, oxid, 0); |
11985 | 12162 | ||
11986 | /* Allocate buffer for acc iocb */ | 12163 | /* Allocate buffer for rsp iocb */ |
11987 | ctiocb = lpfc_sli_get_iocbq(phba); | 12164 | ctiocb = lpfc_sli_get_iocbq(phba); |
11988 | if (!ctiocb) | 12165 | if (!ctiocb) |
11989 | return; | 12166 | return; |
@@ -12008,32 +12185,54 @@ lpfc_sli4_seq_abort_acc(struct lpfc_hba *phba, | |||
12008 | 12185 | ||
12009 | ctiocb->iocb_cmpl = NULL; | 12186 | ctiocb->iocb_cmpl = NULL; |
12010 | ctiocb->vport = phba->pport; | 12187 | ctiocb->vport = phba->pport; |
12011 | ctiocb->iocb_cmpl = lpfc_sli4_seq_abort_acc_cmpl; | 12188 | ctiocb->iocb_cmpl = lpfc_sli4_seq_abort_rsp_cmpl; |
12189 | ctiocb->sli4_xritag = NO_XRI; | ||
12190 | |||
12191 | /* If the oxid maps to the FCP XRI range or if it is out of range, | ||
12192 | * send a BLS_RJT. The driver no longer has that exchange. | ||
12193 | * Override the IOCB for a BA_RJT. | ||
12194 | */ | ||
12195 | if (oxid > (phba->sli4_hba.max_cfg_param.max_xri + | ||
12196 | phba->sli4_hba.max_cfg_param.xri_base) || | ||
12197 | oxid > (lpfc_sli4_get_els_iocb_cnt(phba) + | ||
12198 | phba->sli4_hba.max_cfg_param.xri_base)) { | ||
12199 | icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_RJT; | ||
12200 | bf_set(lpfc_vndr_code, &icmd->un.bls_rsp, 0); | ||
12201 | bf_set(lpfc_rsn_expln, &icmd->un.bls_rsp, FC_BA_RJT_INV_XID); | ||
12202 | bf_set(lpfc_rsn_code, &icmd->un.bls_rsp, FC_BA_RJT_UNABLE); | ||
12203 | } | ||
12012 | 12204 | ||
12013 | if (fctl & FC_FC_EX_CTX) { | 12205 | if (fctl & FC_FC_EX_CTX) { |
12014 | /* ABTS sent by responder to CT exchange, construction | 12206 | /* ABTS sent by responder to CT exchange, construction |
12015 | * of BA_ACC will use OX_ID from ABTS for the XRI_TAG | 12207 | * of BA_ACC will use OX_ID from ABTS for the XRI_TAG |
12016 | * field and RX_ID from ABTS for RX_ID field. | 12208 | * field and RX_ID from ABTS for RX_ID field. |
12017 | */ | 12209 | */ |
12018 | bf_set(lpfc_abts_orig, &icmd->un.bls_acc, LPFC_ABTS_UNSOL_RSP); | 12210 | bf_set(lpfc_abts_orig, &icmd->un.bls_rsp, LPFC_ABTS_UNSOL_RSP); |
12019 | bf_set(lpfc_abts_rxid, &icmd->un.bls_acc, rxid); | 12211 | bf_set(lpfc_abts_rxid, &icmd->un.bls_rsp, rxid); |
12020 | ctiocb->sli4_xritag = oxid; | ||
12021 | } else { | 12212 | } else { |
12022 | /* ABTS sent by initiator to CT exchange, construction | 12213 | /* ABTS sent by initiator to CT exchange, construction |
12023 | * of BA_ACC will need to allocate a new XRI as for the | 12214 | * of BA_ACC will need to allocate a new XRI as for the |
12024 | * XRI_TAG and RX_ID fields. | 12215 | * XRI_TAG and RX_ID fields. |
12025 | */ | 12216 | */ |
12026 | bf_set(lpfc_abts_orig, &icmd->un.bls_acc, LPFC_ABTS_UNSOL_INT); | 12217 | bf_set(lpfc_abts_orig, &icmd->un.bls_rsp, LPFC_ABTS_UNSOL_INT); |
12027 | bf_set(lpfc_abts_rxid, &icmd->un.bls_acc, NO_XRI); | 12218 | bf_set(lpfc_abts_rxid, &icmd->un.bls_rsp, NO_XRI); |
12028 | ctiocb->sli4_xritag = NO_XRI; | ||
12029 | } | 12219 | } |
12030 | bf_set(lpfc_abts_oxid, &icmd->un.bls_acc, oxid); | 12220 | bf_set(lpfc_abts_oxid, &icmd->un.bls_rsp, oxid); |
12031 | 12221 | ||
12032 | /* Xmit CT abts accept on exchange <xid> */ | 12222 | /* Xmit CT abts response on exchange <xid> */ |
12033 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | 12223 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, |
12034 | "1200 Xmit CT ABTS ACC on exchange x%x Data: x%x\n", | 12224 | "1200 Send BLS cmd x%x on oxid x%x Data: x%x\n", |
12035 | CMD_XMIT_BLS_RSP64_CX, phba->link_state); | 12225 | icmd->un.xseq64.w5.hcsw.Rctl, oxid, phba->link_state); |
12036 | lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); | 12226 | |
12227 | rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); | ||
12228 | if (rc == IOCB_ERROR) { | ||
12229 | lpfc_printf_log(phba, KERN_ERR, LOG_ELS, | ||
12230 | "2925 Failed to issue CT ABTS RSP x%x on " | ||
12231 | "xri x%x, Data x%x\n", | ||
12232 | icmd->un.xseq64.w5.hcsw.Rctl, oxid, | ||
12233 | phba->link_state); | ||
12234 | lpfc_sli_release_iocbq(phba, ctiocb); | ||
12235 | } | ||
12037 | } | 12236 | } |
12038 | 12237 | ||
12039 | /** | 12238 | /** |
@@ -12081,7 +12280,7 @@ lpfc_sli4_handle_unsol_abort(struct lpfc_vport *vport, | |||
12081 | lpfc_in_buf_free(phba, &dmabuf->dbuf); | 12280 | lpfc_in_buf_free(phba, &dmabuf->dbuf); |
12082 | } | 12281 | } |
12083 | /* Send basic accept (BA_ACC) to the abort requester */ | 12282 | /* Send basic accept (BA_ACC) to the abort requester */ |
12084 | lpfc_sli4_seq_abort_acc(phba, &fc_hdr); | 12283 | lpfc_sli4_seq_abort_rsp(phba, &fc_hdr); |
12085 | } | 12284 | } |
12086 | 12285 | ||
12087 | /** | 12286 | /** |
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 595056b89608..1a3cbf88f2ce 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /******************************************************************* | 1 | /******************************************************************* |
2 | * This file is part of the Emulex Linux Device Driver for * | 2 | * This file is part of the Emulex Linux Device Driver for * |
3 | * Fibre Channel Host Bus Adapters. * | 3 | * Fibre Channel Host Bus Adapters. * |
4 | * Copyright (C) 2009 Emulex. All rights reserved. * | 4 | * Copyright (C) 2009-2011 Emulex. All rights reserved. * |
5 | * EMULEX and SLI are trademarks of Emulex. * | 5 | * EMULEX and SLI are trademarks of Emulex. * |
6 | * www.emulex.com * | 6 | * www.emulex.com * |
7 | * * | 7 | * * |
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 0a4d376dbca5..2404d1d65563 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h | |||
@@ -18,7 +18,7 @@ | |||
18 | * included with this package. * | 18 | * included with this package. * |
19 | *******************************************************************/ | 19 | *******************************************************************/ |
20 | 20 | ||
21 | #define LPFC_DRIVER_VERSION "8.3.21" | 21 | #define LPFC_DRIVER_VERSION "8.3.22" |
22 | #define LPFC_DRIVER_NAME "lpfc" | 22 | #define LPFC_DRIVER_NAME "lpfc" |
23 | #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" | 23 | #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" |
24 | #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" | 24 | #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index e8a6f1cf1e4b..5e001ffd4c13 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c | |||
@@ -1748,6 +1748,54 @@ _base_display_intel_branding(struct MPT2SAS_ADAPTER *ioc) | |||
1748 | } | 1748 | } |
1749 | 1749 | ||
1750 | /** | 1750 | /** |
1751 | * _base_display_hp_branding - Display branding string | ||
1752 | * @ioc: per adapter object | ||
1753 | * | ||
1754 | * Return nothing. | ||
1755 | */ | ||
1756 | static void | ||
1757 | _base_display_hp_branding(struct MPT2SAS_ADAPTER *ioc) | ||
1758 | { | ||
1759 | if (ioc->pdev->subsystem_vendor != MPT2SAS_HP_3PAR_SSVID) | ||
1760 | return; | ||
1761 | |||
1762 | switch (ioc->pdev->device) { | ||
1763 | case MPI2_MFGPAGE_DEVID_SAS2004: | ||
1764 | switch (ioc->pdev->subsystem_device) { | ||
1765 | case MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID: | ||
1766 | printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, | ||
1767 | MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING); | ||
1768 | break; | ||
1769 | default: | ||
1770 | break; | ||
1771 | } | ||
1772 | case MPI2_MFGPAGE_DEVID_SAS2308_2: | ||
1773 | switch (ioc->pdev->subsystem_device) { | ||
1774 | case MPT2SAS_HP_2_4_INTERNAL_SSDID: | ||
1775 | printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, | ||
1776 | MPT2SAS_HP_2_4_INTERNAL_BRANDING); | ||
1777 | break; | ||
1778 | case MPT2SAS_HP_2_4_EXTERNAL_SSDID: | ||
1779 | printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, | ||
1780 | MPT2SAS_HP_2_4_EXTERNAL_BRANDING); | ||
1781 | break; | ||
1782 | case MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID: | ||
1783 | printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, | ||
1784 | MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING); | ||
1785 | break; | ||
1786 | case MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID: | ||
1787 | printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, | ||
1788 | MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING); | ||
1789 | break; | ||
1790 | default: | ||
1791 | break; | ||
1792 | } | ||
1793 | default: | ||
1794 | break; | ||
1795 | } | ||
1796 | } | ||
1797 | |||
1798 | /** | ||
1751 | * _base_display_ioc_capabilities - Disply IOC's capabilities. | 1799 | * _base_display_ioc_capabilities - Disply IOC's capabilities. |
1752 | * @ioc: per adapter object | 1800 | * @ioc: per adapter object |
1753 | * | 1801 | * |
@@ -1778,6 +1826,7 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) | |||
1778 | 1826 | ||
1779 | _base_display_dell_branding(ioc); | 1827 | _base_display_dell_branding(ioc); |
1780 | _base_display_intel_branding(ioc); | 1828 | _base_display_intel_branding(ioc); |
1829 | _base_display_hp_branding(ioc); | ||
1781 | 1830 | ||
1782 | printk(MPT2SAS_INFO_FMT "Protocol=(", ioc->name); | 1831 | printk(MPT2SAS_INFO_FMT "Protocol=(", ioc->name); |
1783 | 1832 | ||
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index a3f8aa9baea4..500328245f61 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h | |||
@@ -168,6 +168,26 @@ | |||
168 | #define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E | 168 | #define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E |
169 | #define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F | 169 | #define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F |
170 | 170 | ||
171 | |||
172 | /* | ||
173 | * HP HBA branding | ||
174 | */ | ||
175 | #define MPT2SAS_HP_3PAR_SSVID 0x1590 | ||
176 | #define MPT2SAS_HP_2_4_INTERNAL_BRANDING "HP H220 Host Bus Adapter" | ||
177 | #define MPT2SAS_HP_2_4_EXTERNAL_BRANDING "HP H221 Host Bus Adapter" | ||
178 | #define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING "HP H222 Host Bus Adapter" | ||
179 | #define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING "HP H220i Host Bus Adapter" | ||
180 | #define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING "HP H210i Host Bus Adapter" | ||
181 | |||
182 | /* | ||
183 | * HO HBA SSDIDs | ||
184 | */ | ||
185 | #define MPT2SAS_HP_2_4_INTERNAL_SSDID 0x0041 | ||
186 | #define MPT2SAS_HP_2_4_EXTERNAL_SSDID 0x0042 | ||
187 | #define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID 0x0043 | ||
188 | #define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID 0x0044 | ||
189 | #define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID 0x0046 | ||
190 | |||
171 | /* | 191 | /* |
172 | * per target private data | 192 | * per target private data |
173 | */ | 193 | */ |
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 19ad34f381a5..938d045e4180 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c | |||
@@ -663,6 +663,13 @@ static struct pci_device_id __devinitdata mvs_pci_table[] = { | |||
663 | { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1300), chip_1300 }, | 663 | { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1300), chip_1300 }, |
664 | { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1320), chip_1320 }, | 664 | { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1320), chip_1320 }, |
665 | { PCI_VDEVICE(ADAPTEC2, 0x0450), chip_6440 }, | 665 | { PCI_VDEVICE(ADAPTEC2, 0x0450), chip_6440 }, |
666 | { PCI_VDEVICE(TTI, 0x2710), chip_9480 }, | ||
667 | { PCI_VDEVICE(TTI, 0x2720), chip_9480 }, | ||
668 | { PCI_VDEVICE(TTI, 0x2721), chip_9480 }, | ||
669 | { PCI_VDEVICE(TTI, 0x2722), chip_9480 }, | ||
670 | { PCI_VDEVICE(TTI, 0x2740), chip_9480 }, | ||
671 | { PCI_VDEVICE(TTI, 0x2744), chip_9480 }, | ||
672 | { PCI_VDEVICE(TTI, 0x2760), chip_9480 }, | ||
666 | 673 | ||
667 | { } /* terminate list */ | 674 | { } /* terminate list */ |
668 | }; | 675 | }; |
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index 2fc0045b1a52..c1f8d1b150f7 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h | |||
@@ -53,6 +53,9 @@ | |||
53 | #define PCI_DEVICE_ID_QLOGIC_ISP8022 0x8022 | 53 | #define PCI_DEVICE_ID_QLOGIC_ISP8022 0x8022 |
54 | #endif | 54 | #endif |
55 | 55 | ||
56 | #define ISP4XXX_PCI_FN_1 0x1 | ||
57 | #define ISP4XXX_PCI_FN_2 0x3 | ||
58 | |||
56 | #define QLA_SUCCESS 0 | 59 | #define QLA_SUCCESS 0 |
57 | #define QLA_ERROR 1 | 60 | #define QLA_ERROR 1 |
58 | 61 | ||
@@ -233,9 +236,6 @@ struct ddb_entry { | |||
233 | 236 | ||
234 | unsigned long flags; /* DDB Flags */ | 237 | unsigned long flags; /* DDB Flags */ |
235 | 238 | ||
236 | unsigned long dev_scan_wait_to_start_relogin; | ||
237 | unsigned long dev_scan_wait_to_complete_relogin; | ||
238 | |||
239 | uint16_t fw_ddb_index; /* DDB firmware index */ | 239 | uint16_t fw_ddb_index; /* DDB firmware index */ |
240 | uint16_t options; | 240 | uint16_t options; |
241 | uint32_t fw_ddb_device_state; /* F/W Device State -- see ql4_fw.h */ | 241 | uint32_t fw_ddb_device_state; /* F/W Device State -- see ql4_fw.h */ |
@@ -289,8 +289,6 @@ struct ddb_entry { | |||
289 | * DDB flags. | 289 | * DDB flags. |
290 | */ | 290 | */ |
291 | #define DF_RELOGIN 0 /* Relogin to device */ | 291 | #define DF_RELOGIN 0 /* Relogin to device */ |
292 | #define DF_NO_RELOGIN 1 /* Do not relogin if IOCTL | ||
293 | * logged it out */ | ||
294 | #define DF_ISNS_DISCOVERED 2 /* Device was discovered via iSNS */ | 292 | #define DF_ISNS_DISCOVERED 2 /* Device was discovered via iSNS */ |
295 | #define DF_FO_MASKED 3 | 293 | #define DF_FO_MASKED 3 |
296 | 294 | ||
@@ -376,7 +374,7 @@ struct scsi_qla_host { | |||
376 | #define AF_LINK_UP 8 /* 0x00000100 */ | 374 | #define AF_LINK_UP 8 /* 0x00000100 */ |
377 | #define AF_IRQ_ATTACHED 10 /* 0x00000400 */ | 375 | #define AF_IRQ_ATTACHED 10 /* 0x00000400 */ |
378 | #define AF_DISABLE_ACB_COMPLETE 11 /* 0x00000800 */ | 376 | #define AF_DISABLE_ACB_COMPLETE 11 /* 0x00000800 */ |
379 | #define AF_HBA_GOING_AWAY 12 /* 0x00001000 */ | 377 | #define AF_HA_REMOVAL 12 /* 0x00001000 */ |
380 | #define AF_INTx_ENABLED 15 /* 0x00008000 */ | 378 | #define AF_INTx_ENABLED 15 /* 0x00008000 */ |
381 | #define AF_MSI_ENABLED 16 /* 0x00010000 */ | 379 | #define AF_MSI_ENABLED 16 /* 0x00010000 */ |
382 | #define AF_MSIX_ENABLED 17 /* 0x00020000 */ | 380 | #define AF_MSIX_ENABLED 17 /* 0x00020000 */ |
@@ -479,7 +477,6 @@ struct scsi_qla_host { | |||
479 | uint32_t timer_active; | 477 | uint32_t timer_active; |
480 | 478 | ||
481 | /* Recovery Timers */ | 479 | /* Recovery Timers */ |
482 | uint32_t discovery_wait; | ||
483 | atomic_t check_relogin_timeouts; | 480 | atomic_t check_relogin_timeouts; |
484 | uint32_t retry_reset_ha_cnt; | 481 | uint32_t retry_reset_ha_cnt; |
485 | uint32_t isp_reset_timer; /* reset test timer */ | 482 | uint32_t isp_reset_timer; /* reset test timer */ |
@@ -765,6 +762,5 @@ static inline void ql4xxx_unlock_drvr(struct scsi_qla_host *a) | |||
765 | /* Defines for process_aen() */ | 762 | /* Defines for process_aen() */ |
766 | #define PROCESS_ALL_AENS 0 | 763 | #define PROCESS_ALL_AENS 0 |
767 | #define FLUSH_DDB_CHANGED_AENS 1 | 764 | #define FLUSH_DDB_CHANGED_AENS 1 |
768 | #define RELOGIN_DDB_CHANGED_AENS 2 | ||
769 | 765 | ||
770 | #endif /*_QLA4XXX_H */ | 766 | #endif /*_QLA4XXX_H */ |
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index c1985792f034..31e2bf97198c 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h | |||
@@ -455,6 +455,7 @@ struct addr_ctrl_blk { | |||
455 | uint8_t res0; /* 07 */ | 455 | uint8_t res0; /* 07 */ |
456 | uint16_t eth_mtu_size; /* 08-09 */ | 456 | uint16_t eth_mtu_size; /* 08-09 */ |
457 | uint16_t add_fw_options; /* 0A-0B */ | 457 | uint16_t add_fw_options; /* 0A-0B */ |
458 | #define SERIALIZE_TASK_MGMT 0x0400 | ||
458 | 459 | ||
459 | uint8_t hb_interval; /* 0C */ | 460 | uint8_t hb_interval; /* 0C */ |
460 | uint8_t inst_num; /* 0D */ | 461 | uint8_t inst_num; /* 0D */ |
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 8fad99b7eef4..cc53e3fbd78c 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h | |||
@@ -136,7 +136,6 @@ void qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha); | |||
136 | void qla4_8xxx_set_drv_active(struct scsi_qla_host *ha); | 136 | void qla4_8xxx_set_drv_active(struct scsi_qla_host *ha); |
137 | 137 | ||
138 | extern int ql4xextended_error_logging; | 138 | extern int ql4xextended_error_logging; |
139 | extern int ql4xdiscoverywait; | ||
140 | extern int ql4xdontresethba; | 139 | extern int ql4xdontresethba; |
141 | extern int ql4xenablemsix; | 140 | extern int ql4xenablemsix; |
142 | 141 | ||
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 1629c48c35ef..bbb2e903d38a 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c | |||
@@ -723,13 +723,38 @@ int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err) | |||
723 | return relogin; | 723 | return relogin; |
724 | } | 724 | } |
725 | 725 | ||
726 | static void qla4xxx_flush_AENS(struct scsi_qla_host *ha) | ||
727 | { | ||
728 | unsigned long wtime; | ||
729 | |||
730 | /* Flush the 0x8014 AEN from the firmware as a result of | ||
731 | * Auto connect. We are basically doing get_firmware_ddb() | ||
732 | * to determine whether we need to log back in or not. | ||
733 | * Trying to do a set ddb before we have processed 0x8014 | ||
734 | * will result in another set_ddb() for the same ddb. In other | ||
735 | * words there will be stale entries in the aen_q. | ||
736 | */ | ||
737 | wtime = jiffies + (2 * HZ); | ||
738 | do { | ||
739 | if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS) | ||
740 | if (ha->firmware_state & (BIT_2 | BIT_0)) | ||
741 | return; | ||
742 | |||
743 | if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) | ||
744 | qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); | ||
745 | |||
746 | msleep(1000); | ||
747 | } while (!time_after_eq(jiffies, wtime)); | ||
748 | } | ||
749 | |||
726 | /** | 750 | /** |
727 | * qla4xxx_configure_ddbs - builds driver ddb list | 751 | * qla4xxx_build_ddb_list - builds driver ddb list |
728 | * @ha: Pointer to host adapter structure. | 752 | * @ha: Pointer to host adapter structure. |
729 | * | 753 | * |
730 | * This routine searches for all valid firmware ddb entries and builds | 754 | * This routine searches for all valid firmware ddb entries and builds |
731 | * an internal ddb list. Ddbs that are considered valid are those with | 755 | * an internal ddb list. Ddbs that are considered valid are those with |
732 | * a device state of SESSION_ACTIVE. | 756 | * a device state of SESSION_ACTIVE. |
757 | * A relogin (set_ddb) is issued for DDBs that are not online. | ||
733 | **/ | 758 | **/ |
734 | static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) | 759 | static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) |
735 | { | 760 | { |
@@ -744,6 +769,8 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) | |||
744 | uint32_t ipv6_device; | 769 | uint32_t ipv6_device; |
745 | uint32_t new_tgt; | 770 | uint32_t new_tgt; |
746 | 771 | ||
772 | qla4xxx_flush_AENS(ha); | ||
773 | |||
747 | fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), | 774 | fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), |
748 | &fw_ddb_entry_dma, GFP_KERNEL); | 775 | &fw_ddb_entry_dma, GFP_KERNEL); |
749 | if (fw_ddb_entry == NULL) { | 776 | if (fw_ddb_entry == NULL) { |
@@ -847,144 +874,6 @@ exit_build_ddb_list_no_free: | |||
847 | return status; | 874 | return status; |
848 | } | 875 | } |
849 | 876 | ||
850 | struct qla4_relog_scan { | ||
851 | int halt_wait; | ||
852 | uint32_t conn_err; | ||
853 | uint32_t fw_ddb_index; | ||
854 | uint32_t next_fw_ddb_index; | ||
855 | uint32_t fw_ddb_device_state; | ||
856 | }; | ||
857 | |||
858 | static int qla4_test_rdy(struct scsi_qla_host *ha, struct qla4_relog_scan *rs) | ||
859 | { | ||
860 | struct ddb_entry *ddb_entry; | ||
861 | |||
862 | if (qla4_is_relogin_allowed(ha, rs->conn_err)) { | ||
863 | /* We either have a device that is in | ||
864 | * the process of relogging in or a | ||
865 | * device that is waiting to be | ||
866 | * relogged in */ | ||
867 | rs->halt_wait = 0; | ||
868 | |||
869 | ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, | ||
870 | rs->fw_ddb_index); | ||
871 | if (ddb_entry == NULL) | ||
872 | return QLA_ERROR; | ||
873 | |||
874 | if (ddb_entry->dev_scan_wait_to_start_relogin != 0 | ||
875 | && time_after_eq(jiffies, | ||
876 | ddb_entry-> | ||
877 | dev_scan_wait_to_start_relogin)) | ||
878 | { | ||
879 | ddb_entry->dev_scan_wait_to_start_relogin = 0; | ||
880 | qla4xxx_set_ddb_entry(ha, rs->fw_ddb_index, 0); | ||
881 | } | ||
882 | } | ||
883 | return QLA_SUCCESS; | ||
884 | } | ||
885 | |||
886 | static int qla4_scan_for_relogin(struct scsi_qla_host *ha, | ||
887 | struct qla4_relog_scan *rs) | ||
888 | { | ||
889 | int error; | ||
890 | |||
891 | /* scan for relogins | ||
892 | * ----------------- */ | ||
893 | for (rs->fw_ddb_index = 0; rs->fw_ddb_index < MAX_DDB_ENTRIES; | ||
894 | rs->fw_ddb_index = rs->next_fw_ddb_index) { | ||
895 | if (qla4xxx_get_fwddb_entry(ha, rs->fw_ddb_index, NULL, 0, | ||
896 | NULL, &rs->next_fw_ddb_index, | ||
897 | &rs->fw_ddb_device_state, | ||
898 | &rs->conn_err, NULL, NULL) | ||
899 | == QLA_ERROR) | ||
900 | return QLA_ERROR; | ||
901 | |||
902 | if (rs->fw_ddb_device_state == DDB_DS_LOGIN_IN_PROCESS) | ||
903 | rs->halt_wait = 0; | ||
904 | |||
905 | if (rs->fw_ddb_device_state == DDB_DS_SESSION_FAILED || | ||
906 | rs->fw_ddb_device_state == DDB_DS_NO_CONNECTION_ACTIVE) { | ||
907 | error = qla4_test_rdy(ha, rs); | ||
908 | if (error) | ||
909 | return error; | ||
910 | } | ||
911 | |||
912 | /* We know we've reached the last device when | ||
913 | * next_fw_ddb_index is 0 */ | ||
914 | if (rs->next_fw_ddb_index == 0) | ||
915 | break; | ||
916 | } | ||
917 | return QLA_SUCCESS; | ||
918 | } | ||
919 | |||
920 | /** | ||
921 | * qla4xxx_devices_ready - wait for target devices to be logged in | ||
922 | * @ha: pointer to adapter structure | ||
923 | * | ||
924 | * This routine waits up to ql4xdiscoverywait seconds | ||
925 | * F/W database during driver load time. | ||
926 | **/ | ||
927 | static int qla4xxx_devices_ready(struct scsi_qla_host *ha) | ||
928 | { | ||
929 | int error; | ||
930 | unsigned long discovery_wtime; | ||
931 | struct qla4_relog_scan rs; | ||
932 | |||
933 | discovery_wtime = jiffies + (ql4xdiscoverywait * HZ); | ||
934 | |||
935 | DEBUG(printk("Waiting (%d) for devices ...\n", ql4xdiscoverywait)); | ||
936 | do { | ||
937 | /* poll for AEN. */ | ||
938 | qla4xxx_get_firmware_state(ha); | ||
939 | if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) { | ||
940 | /* Set time-between-relogin timer */ | ||
941 | qla4xxx_process_aen(ha, RELOGIN_DDB_CHANGED_AENS); | ||
942 | } | ||
943 | |||
944 | /* if no relogins active or needed, halt discvery wait */ | ||
945 | rs.halt_wait = 1; | ||
946 | |||
947 | error = qla4_scan_for_relogin(ha, &rs); | ||
948 | |||
949 | if (rs.halt_wait) { | ||
950 | DEBUG2(printk("scsi%ld: %s: Delay halted. Devices " | ||
951 | "Ready.\n", ha->host_no, __func__)); | ||
952 | return QLA_SUCCESS; | ||
953 | } | ||
954 | |||
955 | msleep(2000); | ||
956 | } while (!time_after_eq(jiffies, discovery_wtime)); | ||
957 | |||
958 | DEBUG3(qla4xxx_get_conn_event_log(ha)); | ||
959 | |||
960 | return QLA_SUCCESS; | ||
961 | } | ||
962 | |||
963 | static void qla4xxx_flush_AENS(struct scsi_qla_host *ha) | ||
964 | { | ||
965 | unsigned long wtime; | ||
966 | |||
967 | /* Flush the 0x8014 AEN from the firmware as a result of | ||
968 | * Auto connect. We are basically doing get_firmware_ddb() | ||
969 | * to determine whether we need to log back in or not. | ||
970 | * Trying to do a set ddb before we have processed 0x8014 | ||
971 | * will result in another set_ddb() for the same ddb. In other | ||
972 | * words there will be stale entries in the aen_q. | ||
973 | */ | ||
974 | wtime = jiffies + (2 * HZ); | ||
975 | do { | ||
976 | if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS) | ||
977 | if (ha->firmware_state & (BIT_2 | BIT_0)) | ||
978 | return; | ||
979 | |||
980 | if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) | ||
981 | qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); | ||
982 | |||
983 | msleep(1000); | ||
984 | } while (!time_after_eq(jiffies, wtime)); | ||
985 | |||
986 | } | ||
987 | |||
988 | static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha) | 877 | static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha) |
989 | { | 878 | { |
990 | uint16_t fw_ddb_index; | 879 | uint16_t fw_ddb_index; |
@@ -996,29 +885,12 @@ static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha) | |||
996 | 885 | ||
997 | for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES; fw_ddb_index++) | 886 | for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES; fw_ddb_index++) |
998 | ha->fw_ddb_index_map[fw_ddb_index] = | 887 | ha->fw_ddb_index_map[fw_ddb_index] = |
999 | (struct ddb_entry *)INVALID_ENTRY; | 888 | (struct ddb_entry *)INVALID_ENTRY; |
1000 | 889 | ||
1001 | ha->tot_ddbs = 0; | 890 | ha->tot_ddbs = 0; |
1002 | 891 | ||
1003 | qla4xxx_flush_AENS(ha); | 892 | /* Perform device discovery and build ddb list. */ |
1004 | 893 | status = qla4xxx_build_ddb_list(ha); | |
1005 | /* Wait for an AEN */ | ||
1006 | qla4xxx_devices_ready(ha); | ||
1007 | |||
1008 | /* | ||
1009 | * First perform device discovery for active | ||
1010 | * fw ddb indexes and build | ||
1011 | * ddb list. | ||
1012 | */ | ||
1013 | if ((status = qla4xxx_build_ddb_list(ha)) == QLA_ERROR) | ||
1014 | return status; | ||
1015 | |||
1016 | /* | ||
1017 | * Targets can come online after the inital discovery, so processing | ||
1018 | * the aens here will catch them. | ||
1019 | */ | ||
1020 | if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) | ||
1021 | qla4xxx_process_aen(ha, PROCESS_ALL_AENS); | ||
1022 | 894 | ||
1023 | return status; | 895 | return status; |
1024 | } | 896 | } |
@@ -1537,7 +1409,6 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, | |||
1537 | uint32_t state, uint32_t conn_err) | 1409 | uint32_t state, uint32_t conn_err) |
1538 | { | 1410 | { |
1539 | struct ddb_entry * ddb_entry; | 1411 | struct ddb_entry * ddb_entry; |
1540 | uint32_t old_fw_ddb_device_state; | ||
1541 | 1412 | ||
1542 | /* check for out of range index */ | 1413 | /* check for out of range index */ |
1543 | if (fw_ddb_index >= MAX_DDB_ENTRIES) | 1414 | if (fw_ddb_index >= MAX_DDB_ENTRIES) |
@@ -1553,27 +1424,18 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, | |||
1553 | } | 1424 | } |
1554 | 1425 | ||
1555 | /* Device already exists in our database. */ | 1426 | /* Device already exists in our database. */ |
1556 | old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; | ||
1557 | DEBUG2(printk("scsi%ld: %s DDB - old state= 0x%x, new state=0x%x for " | 1427 | DEBUG2(printk("scsi%ld: %s DDB - old state= 0x%x, new state=0x%x for " |
1558 | "index [%d]\n", ha->host_no, __func__, | 1428 | "index [%d]\n", ha->host_no, __func__, |
1559 | ddb_entry->fw_ddb_device_state, state, fw_ddb_index)); | 1429 | ddb_entry->fw_ddb_device_state, state, fw_ddb_index)); |
1560 | if (old_fw_ddb_device_state == state && | ||
1561 | state == DDB_DS_SESSION_ACTIVE) { | ||
1562 | if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { | ||
1563 | atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); | ||
1564 | iscsi_unblock_session(ddb_entry->sess); | ||
1565 | } | ||
1566 | return QLA_SUCCESS; | ||
1567 | } | ||
1568 | 1430 | ||
1569 | ddb_entry->fw_ddb_device_state = state; | 1431 | ddb_entry->fw_ddb_device_state = state; |
1570 | /* Device is back online. */ | 1432 | /* Device is back online. */ |
1571 | if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { | 1433 | if ((ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) && |
1434 | (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE)) { | ||
1572 | atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); | 1435 | atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); |
1573 | atomic_set(&ddb_entry->relogin_retry_count, 0); | 1436 | atomic_set(&ddb_entry->relogin_retry_count, 0); |
1574 | atomic_set(&ddb_entry->relogin_timer, 0); | 1437 | atomic_set(&ddb_entry->relogin_timer, 0); |
1575 | clear_bit(DF_RELOGIN, &ddb_entry->flags); | 1438 | clear_bit(DF_RELOGIN, &ddb_entry->flags); |
1576 | clear_bit(DF_NO_RELOGIN, &ddb_entry->flags); | ||
1577 | iscsi_unblock_session(ddb_entry->sess); | 1439 | iscsi_unblock_session(ddb_entry->sess); |
1578 | iscsi_session_event(ddb_entry->sess, | 1440 | iscsi_session_event(ddb_entry->sess, |
1579 | ISCSI_KEVENT_CREATE_SESSION); | 1441 | ISCSI_KEVENT_CREATE_SESSION); |
@@ -1581,7 +1443,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, | |||
1581 | * Change the lun state to READY in case the lun TIMEOUT before | 1443 | * Change the lun state to READY in case the lun TIMEOUT before |
1582 | * the device came back. | 1444 | * the device came back. |
1583 | */ | 1445 | */ |
1584 | } else { | 1446 | } else if (ddb_entry->fw_ddb_device_state != DDB_DS_SESSION_ACTIVE) { |
1585 | /* Device went away, mark device missing */ | 1447 | /* Device went away, mark device missing */ |
1586 | if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) { | 1448 | if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) { |
1587 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s mark missing " | 1449 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s mark missing " |
@@ -1598,7 +1460,6 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, | |||
1598 | */ | 1460 | */ |
1599 | if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_FAILED && | 1461 | if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_FAILED && |
1600 | !test_bit(DF_RELOGIN, &ddb_entry->flags) && | 1462 | !test_bit(DF_RELOGIN, &ddb_entry->flags) && |
1601 | !test_bit(DF_NO_RELOGIN, &ddb_entry->flags) && | ||
1602 | qla4_is_relogin_allowed(ha, conn_err)) { | 1463 | qla4_is_relogin_allowed(ha, conn_err)) { |
1603 | /* | 1464 | /* |
1604 | * This triggers a relogin. After the relogin_timer | 1465 | * This triggers a relogin. After the relogin_timer |
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index 03e028e6e809..2f40ac761cd4 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c | |||
@@ -801,7 +801,7 @@ irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id) | |||
801 | &ha->reg->ctrl_status); | 801 | &ha->reg->ctrl_status); |
802 | readl(&ha->reg->ctrl_status); | 802 | readl(&ha->reg->ctrl_status); |
803 | 803 | ||
804 | if (!test_bit(AF_HBA_GOING_AWAY, &ha->flags)) | 804 | if (!test_bit(AF_HA_REMOVAL, &ha->flags)) |
805 | set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); | 805 | set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); |
806 | 806 | ||
807 | break; | 807 | break; |
@@ -1008,34 +1008,9 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen) | |||
1008 | mbox_sts[0], mbox_sts[2], | 1008 | mbox_sts[0], mbox_sts[2], |
1009 | mbox_sts[3])); | 1009 | mbox_sts[3])); |
1010 | break; | 1010 | break; |
1011 | } else if (process_aen == RELOGIN_DDB_CHANGED_AENS) { | ||
1012 | /* for use during init time, we only want to | ||
1013 | * relogin non-active ddbs */ | ||
1014 | struct ddb_entry *ddb_entry; | ||
1015 | |||
1016 | ddb_entry = | ||
1017 | /* FIXME: name length? */ | ||
1018 | qla4xxx_lookup_ddb_by_fw_index(ha, | ||
1019 | mbox_sts[2]); | ||
1020 | if (!ddb_entry) | ||
1021 | break; | ||
1022 | |||
1023 | ddb_entry->dev_scan_wait_to_complete_relogin = | ||
1024 | 0; | ||
1025 | ddb_entry->dev_scan_wait_to_start_relogin = | ||
1026 | jiffies + | ||
1027 | ((ddb_entry->default_time2wait + | ||
1028 | 4) * HZ); | ||
1029 | |||
1030 | DEBUG2(printk("scsi%ld: ddb [%d] initiate" | ||
1031 | " RELOGIN after %d seconds\n", | ||
1032 | ha->host_no, | ||
1033 | ddb_entry->fw_ddb_index, | ||
1034 | ddb_entry->default_time2wait + | ||
1035 | 4)); | ||
1036 | break; | ||
1037 | } | 1011 | } |
1038 | 1012 | case PROCESS_ALL_AENS: | |
1013 | default: | ||
1039 | if (mbox_sts[1] == 0) { /* Global DB change. */ | 1014 | if (mbox_sts[1] == 0) { /* Global DB change. */ |
1040 | qla4xxx_reinitialize_ddb_list(ha); | 1015 | qla4xxx_reinitialize_ddb_list(ha); |
1041 | } else if (mbox_sts[1] == 1) { /* Specific device. */ | 1016 | } else if (mbox_sts[1] == 1) { /* Specific device. */ |
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index f65626aec7c1..f9d81c8372c3 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c | |||
@@ -32,6 +32,7 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, | |||
32 | u_long wait_count; | 32 | u_long wait_count; |
33 | uint32_t intr_status; | 33 | uint32_t intr_status; |
34 | unsigned long flags = 0; | 34 | unsigned long flags = 0; |
35 | uint32_t dev_state; | ||
35 | 36 | ||
36 | /* Make sure that pointers are valid */ | 37 | /* Make sure that pointers are valid */ |
37 | if (!mbx_cmd || !mbx_sts) { | 38 | if (!mbx_cmd || !mbx_sts) { |
@@ -40,12 +41,23 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, | |||
40 | return status; | 41 | return status; |
41 | } | 42 | } |
42 | 43 | ||
43 | if (is_qla8022(ha) && | 44 | if (is_qla8022(ha)) { |
44 | test_bit(AF_FW_RECOVERY, &ha->flags)) { | 45 | if (test_bit(AF_FW_RECOVERY, &ha->flags)) { |
45 | DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: prematurely " | 46 | DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: " |
46 | "completing mbx cmd as firmware recovery detected\n", | 47 | "prematurely completing mbx cmd as firmware " |
47 | ha->host_no, __func__)); | 48 | "recovery detected\n", ha->host_no, __func__)); |
48 | return status; | 49 | return status; |
50 | } | ||
51 | /* Do not send any mbx cmd if h/w is in failed state*/ | ||
52 | qla4_8xxx_idc_lock(ha); | ||
53 | dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); | ||
54 | qla4_8xxx_idc_unlock(ha); | ||
55 | if (dev_state == QLA82XX_DEV_FAILED) { | ||
56 | ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: H/W is in " | ||
57 | "failed state, do not send any mailbox commands\n", | ||
58 | ha->host_no, __func__); | ||
59 | return status; | ||
60 | } | ||
49 | } | 61 | } |
50 | 62 | ||
51 | if ((is_aer_supported(ha)) && | 63 | if ((is_aer_supported(ha)) && |
@@ -139,7 +151,7 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, | |||
139 | if (test_bit(AF_IRQ_ATTACHED, &ha->flags) && | 151 | if (test_bit(AF_IRQ_ATTACHED, &ha->flags) && |
140 | test_bit(AF_INTERRUPTS_ON, &ha->flags) && | 152 | test_bit(AF_INTERRUPTS_ON, &ha->flags) && |
141 | test_bit(AF_ONLINE, &ha->flags) && | 153 | test_bit(AF_ONLINE, &ha->flags) && |
142 | !test_bit(AF_HBA_GOING_AWAY, &ha->flags)) { | 154 | !test_bit(AF_HA_REMOVAL, &ha->flags)) { |
143 | /* Do not poll for completion. Use completion queue */ | 155 | /* Do not poll for completion. Use completion queue */ |
144 | set_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags); | 156 | set_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags); |
145 | wait_for_completion_timeout(&ha->mbx_intr_comp, MBOX_TOV * HZ); | 157 | wait_for_completion_timeout(&ha->mbx_intr_comp, MBOX_TOV * HZ); |
@@ -395,9 +407,6 @@ qla4xxx_update_local_ifcb(struct scsi_qla_host *ha, | |||
395 | /*memcpy(ha->alias, init_fw_cb->Alias, | 407 | /*memcpy(ha->alias, init_fw_cb->Alias, |
396 | min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/ | 408 | min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/ |
397 | 409 | ||
398 | /* Save Command Line Paramater info */ | ||
399 | ha->discovery_wait = ql4xdiscoverywait; | ||
400 | |||
401 | if (ha->acb_version == ACB_SUPPORTED) { | 410 | if (ha->acb_version == ACB_SUPPORTED) { |
402 | ha->ipv6_options = init_fw_cb->ipv6_opts; | 411 | ha->ipv6_options = init_fw_cb->ipv6_opts; |
403 | ha->ipv6_addl_options = init_fw_cb->ipv6_addtl_opts; | 412 | ha->ipv6_addl_options = init_fw_cb->ipv6_addtl_opts; |
@@ -467,6 +476,11 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha) | |||
467 | 476 | ||
468 | init_fw_cb->fw_options &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE); | 477 | init_fw_cb->fw_options &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE); |
469 | 478 | ||
479 | /* Set bit for "serialize task mgmt" all other bits need to be zero */ | ||
480 | init_fw_cb->add_fw_options = 0; | ||
481 | init_fw_cb->add_fw_options |= | ||
482 | __constant_cpu_to_le16(SERIALIZE_TASK_MGMT); | ||
483 | |||
470 | if (qla4xxx_set_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) | 484 | if (qla4xxx_set_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) |
471 | != QLA_SUCCESS) { | 485 | != QLA_SUCCESS) { |
472 | DEBUG2(printk(KERN_WARNING | 486 | DEBUG2(printk(KERN_WARNING |
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index 3d5ef2df4134..35381cb0936e 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c | |||
@@ -2304,14 +2304,13 @@ qla4_8xxx_enable_intrs(struct scsi_qla_host *ha) | |||
2304 | void | 2304 | void |
2305 | qla4_8xxx_disable_intrs(struct scsi_qla_host *ha) | 2305 | qla4_8xxx_disable_intrs(struct scsi_qla_host *ha) |
2306 | { | 2306 | { |
2307 | if (test_bit(AF_INTERRUPTS_ON, &ha->flags)) | 2307 | if (test_and_clear_bit(AF_INTERRUPTS_ON, &ha->flags)) |
2308 | qla4_8xxx_mbx_intr_disable(ha); | 2308 | qla4_8xxx_mbx_intr_disable(ha); |
2309 | 2309 | ||
2310 | spin_lock_irq(&ha->hardware_lock); | 2310 | spin_lock_irq(&ha->hardware_lock); |
2311 | /* BIT 10 - set */ | 2311 | /* BIT 10 - set */ |
2312 | qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400); | 2312 | qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400); |
2313 | spin_unlock_irq(&ha->hardware_lock); | 2313 | spin_unlock_irq(&ha->hardware_lock); |
2314 | clear_bit(AF_INTERRUPTS_ON, &ha->flags); | ||
2315 | } | 2314 | } |
2316 | 2315 | ||
2317 | struct ql4_init_msix_entry { | 2316 | struct ql4_init_msix_entry { |
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 967836ef5ab2..a4acb0dd7beb 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c | |||
@@ -29,10 +29,6 @@ static struct kmem_cache *srb_cachep; | |||
29 | /* | 29 | /* |
30 | * Module parameter information and variables | 30 | * Module parameter information and variables |
31 | */ | 31 | */ |
32 | int ql4xdiscoverywait = 60; | ||
33 | module_param(ql4xdiscoverywait, int, S_IRUGO | S_IWUSR); | ||
34 | MODULE_PARM_DESC(ql4xdiscoverywait, "Discovery wait time"); | ||
35 | |||
36 | int ql4xdontresethba = 0; | 32 | int ql4xdontresethba = 0; |
37 | module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR); | 33 | module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR); |
38 | MODULE_PARM_DESC(ql4xdontresethba, | 34 | MODULE_PARM_DESC(ql4xdontresethba, |
@@ -55,6 +51,17 @@ MODULE_PARM_DESC(ql4xenablemsix, | |||
55 | " 2 = enable MSI interrupt mechanism."); | 51 | " 2 = enable MSI interrupt mechanism."); |
56 | 52 | ||
57 | #define QL4_DEF_QDEPTH 32 | 53 | #define QL4_DEF_QDEPTH 32 |
54 | static int ql4xmaxqdepth = QL4_DEF_QDEPTH; | ||
55 | module_param(ql4xmaxqdepth, int, S_IRUGO | S_IWUSR); | ||
56 | MODULE_PARM_DESC(ql4xmaxqdepth, | ||
57 | "Maximum queue depth to report for target devices.\n" | ||
58 | " Default: 32."); | ||
59 | |||
60 | static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO; | ||
61 | module_param(ql4xsess_recovery_tmo, int, S_IRUGO); | ||
62 | MODULE_PARM_DESC(ql4xsess_recovery_tmo, | ||
63 | "Target Session Recovery Timeout.\n" | ||
64 | " Default: 30 sec."); | ||
58 | 65 | ||
59 | /* | 66 | /* |
60 | * SCSI host template entry points | 67 | * SCSI host template entry points |
@@ -165,7 +172,7 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session) | |||
165 | DEBUG2(printk("scsi%ld: %s: ddb [%d] session recovery timeout " | 172 | DEBUG2(printk("scsi%ld: %s: ddb [%d] session recovery timeout " |
166 | "of (%d) secs exhausted, marking device DEAD.\n", | 173 | "of (%d) secs exhausted, marking device DEAD.\n", |
167 | ha->host_no, __func__, ddb_entry->fw_ddb_index, | 174 | ha->host_no, __func__, ddb_entry->fw_ddb_index, |
168 | QL4_SESS_RECOVERY_TMO)); | 175 | ddb_entry->sess->recovery_tmo)); |
169 | } | 176 | } |
170 | } | 177 | } |
171 | 178 | ||
@@ -295,7 +302,7 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry) | |||
295 | { | 302 | { |
296 | int err; | 303 | int err; |
297 | 304 | ||
298 | ddb_entry->sess->recovery_tmo = QL4_SESS_RECOVERY_TMO; | 305 | ddb_entry->sess->recovery_tmo = ql4xsess_recovery_tmo; |
299 | 306 | ||
300 | err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index); | 307 | err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index); |
301 | if (err) { | 308 | if (err) { |
@@ -753,12 +760,6 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) | |||
753 | if (!pci_channel_offline(ha->pdev)) | 760 | if (!pci_channel_offline(ha->pdev)) |
754 | pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); | 761 | pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); |
755 | 762 | ||
756 | if (test_bit(AF_HBA_GOING_AWAY, &ha->flags)) { | ||
757 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s exited. HBA GOING AWAY\n", | ||
758 | __func__)); | ||
759 | return; | ||
760 | } | ||
761 | |||
762 | if (is_qla8022(ha)) { | 763 | if (is_qla8022(ha)) { |
763 | qla4_8xxx_watchdog(ha); | 764 | qla4_8xxx_watchdog(ha); |
764 | } | 765 | } |
@@ -1067,7 +1068,6 @@ void qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha) | |||
1067 | 1068 | ||
1068 | /* Disable the board */ | 1069 | /* Disable the board */ |
1069 | ql4_printk(KERN_INFO, ha, "Disabling the board\n"); | 1070 | ql4_printk(KERN_INFO, ha, "Disabling the board\n"); |
1070 | set_bit(AF_HBA_GOING_AWAY, &ha->flags); | ||
1071 | 1071 | ||
1072 | qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); | 1072 | qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); |
1073 | qla4xxx_mark_all_devices_missing(ha); | 1073 | qla4xxx_mark_all_devices_missing(ha); |
@@ -1218,6 +1218,27 @@ recover_ha_init_adapter: | |||
1218 | return status; | 1218 | return status; |
1219 | } | 1219 | } |
1220 | 1220 | ||
1221 | static void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha) | ||
1222 | { | ||
1223 | struct ddb_entry *ddb_entry, *dtemp; | ||
1224 | |||
1225 | list_for_each_entry_safe(ddb_entry, dtemp, &ha->ddb_list, list) { | ||
1226 | if ((atomic_read(&ddb_entry->state) == DDB_STATE_MISSING) || | ||
1227 | (atomic_read(&ddb_entry->state) == DDB_STATE_DEAD)) { | ||
1228 | if (ddb_entry->fw_ddb_device_state == | ||
1229 | DDB_DS_SESSION_ACTIVE) { | ||
1230 | atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); | ||
1231 | ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" | ||
1232 | " marked ONLINE\n", ha->host_no, __func__, | ||
1233 | ddb_entry->fw_ddb_index); | ||
1234 | |||
1235 | iscsi_unblock_session(ddb_entry->sess); | ||
1236 | } else | ||
1237 | qla4xxx_relogin_device(ha, ddb_entry); | ||
1238 | } | ||
1239 | } | ||
1240 | } | ||
1241 | |||
1221 | void qla4xxx_wake_dpc(struct scsi_qla_host *ha) | 1242 | void qla4xxx_wake_dpc(struct scsi_qla_host *ha) |
1222 | { | 1243 | { |
1223 | if (ha->dpc_thread && | 1244 | if (ha->dpc_thread && |
@@ -1259,11 +1280,6 @@ static void qla4xxx_do_dpc(struct work_struct *work) | |||
1259 | goto do_dpc_exit; | 1280 | goto do_dpc_exit; |
1260 | } | 1281 | } |
1261 | 1282 | ||
1262 | /* HBA is in the process of being permanently disabled. | ||
1263 | * Don't process anything */ | ||
1264 | if (test_bit(AF_HBA_GOING_AWAY, &ha->flags)) | ||
1265 | return; | ||
1266 | |||
1267 | if (is_qla8022(ha)) { | 1283 | if (is_qla8022(ha)) { |
1268 | if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) { | 1284 | if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) { |
1269 | qla4_8xxx_idc_lock(ha); | 1285 | qla4_8xxx_idc_lock(ha); |
@@ -1331,13 +1347,7 @@ dpc_post_reset_ha: | |||
1331 | if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) { | 1347 | if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) { |
1332 | if (!test_bit(AF_LINK_UP, &ha->flags)) { | 1348 | if (!test_bit(AF_LINK_UP, &ha->flags)) { |
1333 | /* ---- link down? --- */ | 1349 | /* ---- link down? --- */ |
1334 | list_for_each_entry_safe(ddb_entry, dtemp, | 1350 | qla4xxx_mark_all_devices_missing(ha); |
1335 | &ha->ddb_list, list) { | ||
1336 | if (atomic_read(&ddb_entry->state) == | ||
1337 | DDB_STATE_ONLINE) | ||
1338 | qla4xxx_mark_device_missing(ha, | ||
1339 | ddb_entry); | ||
1340 | } | ||
1341 | } else { | 1351 | } else { |
1342 | /* ---- link up? --- * | 1352 | /* ---- link up? --- * |
1343 | * F/W will auto login to all devices ONLY ONCE after | 1353 | * F/W will auto login to all devices ONLY ONCE after |
@@ -1346,30 +1356,7 @@ dpc_post_reset_ha: | |||
1346 | * manually relogin to devices when recovering from | 1356 | * manually relogin to devices when recovering from |
1347 | * connection failures, logouts, expired KATO, etc. */ | 1357 | * connection failures, logouts, expired KATO, etc. */ |
1348 | 1358 | ||
1349 | list_for_each_entry_safe(ddb_entry, dtemp, | 1359 | qla4xxx_relogin_all_devices(ha); |
1350 | &ha->ddb_list, list) { | ||
1351 | if ((atomic_read(&ddb_entry->state) == | ||
1352 | DDB_STATE_MISSING) || | ||
1353 | (atomic_read(&ddb_entry->state) == | ||
1354 | DDB_STATE_DEAD)) { | ||
1355 | if (ddb_entry->fw_ddb_device_state == | ||
1356 | DDB_DS_SESSION_ACTIVE) { | ||
1357 | atomic_set(&ddb_entry->state, | ||
1358 | DDB_STATE_ONLINE); | ||
1359 | ql4_printk(KERN_INFO, ha, | ||
1360 | "scsi%ld: %s: ddb[%d]" | ||
1361 | " marked ONLINE\n", | ||
1362 | ha->host_no, __func__, | ||
1363 | ddb_entry->fw_ddb_index); | ||
1364 | |||
1365 | iscsi_unblock_session( | ||
1366 | ddb_entry->sess); | ||
1367 | } else | ||
1368 | qla4xxx_relogin_device( | ||
1369 | ha, ddb_entry); | ||
1370 | } | ||
1371 | |||
1372 | } | ||
1373 | } | 1360 | } |
1374 | } | 1361 | } |
1375 | 1362 | ||
@@ -1630,6 +1617,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, | |||
1630 | uint8_t init_retry_count = 0; | 1617 | uint8_t init_retry_count = 0; |
1631 | char buf[34]; | 1618 | char buf[34]; |
1632 | struct qla4_8xxx_legacy_intr_set *nx_legacy_intr; | 1619 | struct qla4_8xxx_legacy_intr_set *nx_legacy_intr; |
1620 | uint32_t dev_state; | ||
1633 | 1621 | ||
1634 | if (pci_enable_device(pdev)) | 1622 | if (pci_enable_device(pdev)) |
1635 | return -1; | 1623 | return -1; |
@@ -1713,6 +1701,18 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, | |||
1713 | status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST); | 1701 | status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST); |
1714 | while ((!test_bit(AF_ONLINE, &ha->flags)) && | 1702 | while ((!test_bit(AF_ONLINE, &ha->flags)) && |
1715 | init_retry_count++ < MAX_INIT_RETRIES) { | 1703 | init_retry_count++ < MAX_INIT_RETRIES) { |
1704 | |||
1705 | if (is_qla8022(ha)) { | ||
1706 | qla4_8xxx_idc_lock(ha); | ||
1707 | dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); | ||
1708 | qla4_8xxx_idc_unlock(ha); | ||
1709 | if (dev_state == QLA82XX_DEV_FAILED) { | ||
1710 | ql4_printk(KERN_WARNING, ha, "%s: don't retry " | ||
1711 | "initialize adapter. H/W is in failed state\n", | ||
1712 | __func__); | ||
1713 | break; | ||
1714 | } | ||
1715 | } | ||
1716 | DEBUG2(printk("scsi: %s: retrying adapter initialization " | 1716 | DEBUG2(printk("scsi: %s: retrying adapter initialization " |
1717 | "(%d)\n", __func__, init_retry_count)); | 1717 | "(%d)\n", __func__, init_retry_count)); |
1718 | 1718 | ||
@@ -1815,6 +1815,44 @@ probe_disable_device: | |||
1815 | } | 1815 | } |
1816 | 1816 | ||
1817 | /** | 1817 | /** |
1818 | * qla4xxx_prevent_other_port_reinit - prevent other port from re-initialize | ||
1819 | * @ha: pointer to adapter structure | ||
1820 | * | ||
1821 | * Mark the other ISP-4xxx port to indicate that the driver is being removed, | ||
1822 | * so that the other port will not re-initialize while in the process of | ||
1823 | * removing the ha due to driver unload or hba hotplug. | ||
1824 | **/ | ||
1825 | static void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha) | ||
1826 | { | ||
1827 | struct scsi_qla_host *other_ha = NULL; | ||
1828 | struct pci_dev *other_pdev = NULL; | ||
1829 | int fn = ISP4XXX_PCI_FN_2; | ||
1830 | |||
1831 | /*iscsi function numbers for ISP4xxx is 1 and 3*/ | ||
1832 | if (PCI_FUNC(ha->pdev->devfn) & BIT_1) | ||
1833 | fn = ISP4XXX_PCI_FN_1; | ||
1834 | |||
1835 | other_pdev = | ||
1836 | pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), | ||
1837 | ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), | ||
1838 | fn)); | ||
1839 | |||
1840 | /* Get other_ha if other_pdev is valid and state is enable*/ | ||
1841 | if (other_pdev) { | ||
1842 | if (atomic_read(&other_pdev->enable_cnt)) { | ||
1843 | other_ha = pci_get_drvdata(other_pdev); | ||
1844 | if (other_ha) { | ||
1845 | set_bit(AF_HA_REMOVAL, &other_ha->flags); | ||
1846 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: " | ||
1847 | "Prevent %s reinit\n", __func__, | ||
1848 | dev_name(&other_ha->pdev->dev))); | ||
1849 | } | ||
1850 | } | ||
1851 | pci_dev_put(other_pdev); | ||
1852 | } | ||
1853 | } | ||
1854 | |||
1855 | /** | ||
1818 | * qla4xxx_remove_adapter - calback function to remove adapter. | 1856 | * qla4xxx_remove_adapter - calback function to remove adapter. |
1819 | * @pci_dev: PCI device pointer | 1857 | * @pci_dev: PCI device pointer |
1820 | **/ | 1858 | **/ |
@@ -1824,7 +1862,8 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) | |||
1824 | 1862 | ||
1825 | ha = pci_get_drvdata(pdev); | 1863 | ha = pci_get_drvdata(pdev); |
1826 | 1864 | ||
1827 | set_bit(AF_HBA_GOING_AWAY, &ha->flags); | 1865 | if (!is_qla8022(ha)) |
1866 | qla4xxx_prevent_other_port_reinit(ha); | ||
1828 | 1867 | ||
1829 | /* remove devs from iscsi_sessions to scsi_devices */ | 1868 | /* remove devs from iscsi_sessions to scsi_devices */ |
1830 | qla4xxx_free_ddb_list(ha); | 1869 | qla4xxx_free_ddb_list(ha); |
@@ -1868,10 +1907,15 @@ static int qla4xxx_slave_alloc(struct scsi_device *sdev) | |||
1868 | { | 1907 | { |
1869 | struct iscsi_cls_session *sess = starget_to_session(sdev->sdev_target); | 1908 | struct iscsi_cls_session *sess = starget_to_session(sdev->sdev_target); |
1870 | struct ddb_entry *ddb = sess->dd_data; | 1909 | struct ddb_entry *ddb = sess->dd_data; |
1910 | int queue_depth = QL4_DEF_QDEPTH; | ||
1871 | 1911 | ||
1872 | sdev->hostdata = ddb; | 1912 | sdev->hostdata = ddb; |
1873 | sdev->tagged_supported = 1; | 1913 | sdev->tagged_supported = 1; |
1874 | scsi_activate_tcq(sdev, QL4_DEF_QDEPTH); | 1914 | |
1915 | if (ql4xmaxqdepth != 0 && ql4xmaxqdepth <= 0xffffU) | ||
1916 | queue_depth = ql4xmaxqdepth; | ||
1917 | |||
1918 | scsi_activate_tcq(sdev, queue_depth); | ||
1875 | return 0; | 1919 | return 0; |
1876 | } | 1920 | } |
1877 | 1921 | ||
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index 8475b308e01b..603155769407 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h | |||
@@ -5,4 +5,4 @@ | |||
5 | * See LICENSE.qla4xxx for copyright and licensing details. | 5 | * See LICENSE.qla4xxx for copyright and licensing details. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #define QLA4XXX_DRIVER_VERSION "5.02.00-k5" | 8 | #define QLA4XXX_DRIVER_VERSION "5.02.00-k6" |
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index b4218390941e..3fd16d7212de 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c | |||
@@ -1917,7 +1917,7 @@ store_priv_session_##field(struct device *dev, \ | |||
1917 | #define iscsi_priv_session_rw_attr(field, format) \ | 1917 | #define iscsi_priv_session_rw_attr(field, format) \ |
1918 | iscsi_priv_session_attr_show(field, format) \ | 1918 | iscsi_priv_session_attr_show(field, format) \ |
1919 | iscsi_priv_session_attr_store(field) \ | 1919 | iscsi_priv_session_attr_store(field) \ |
1920 | static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO | S_IWUGO, \ | 1920 | static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO | S_IWUSR, \ |
1921 | show_priv_session_##field, \ | 1921 | show_priv_session_##field, \ |
1922 | store_priv_session_##field) | 1922 | store_priv_session_##field) |
1923 | iscsi_priv_session_rw_attr(recovery_tmo, "%d"); | 1923 | iscsi_priv_session_rw_attr(recovery_tmo, "%d"); |
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 7ff61d76b4c5..b61ebec6bca7 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
@@ -2027,14 +2027,10 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) | |||
2027 | int old_rcd = sdkp->RCD; | 2027 | int old_rcd = sdkp->RCD; |
2028 | int old_dpofua = sdkp->DPOFUA; | 2028 | int old_dpofua = sdkp->DPOFUA; |
2029 | 2029 | ||
2030 | if (sdp->skip_ms_page_8) { | 2030 | if (sdp->skip_ms_page_8) |
2031 | if (sdp->type == TYPE_RBC) | 2031 | goto defaults; |
2032 | goto defaults; | 2032 | |
2033 | else { | 2033 | if (sdp->type == TYPE_RBC) { |
2034 | modepage = 0x3F; | ||
2035 | dbd = 0; | ||
2036 | } | ||
2037 | } else if (sdp->type == TYPE_RBC) { | ||
2038 | modepage = 6; | 2034 | modepage = 6; |
2039 | dbd = 8; | 2035 | dbd = 8; |
2040 | } else { | 2036 | } else { |
@@ -2062,11 +2058,13 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) | |||
2062 | */ | 2058 | */ |
2063 | if (len < 3) | 2059 | if (len < 3) |
2064 | goto bad_sense; | 2060 | goto bad_sense; |
2065 | else if (len > SD_BUF_SIZE) { | 2061 | if (len > 20) |
2066 | sd_printk(KERN_NOTICE, sdkp, "Truncating mode parameter " | 2062 | len = 20; |
2067 | "data from %d to %d bytes\n", len, SD_BUF_SIZE); | 2063 | |
2068 | len = SD_BUF_SIZE; | 2064 | /* Take headers and block descriptors into account */ |
2069 | } | 2065 | len += data.header_length + data.block_descriptor_length; |
2066 | if (len > SD_BUF_SIZE) | ||
2067 | goto bad_sense; | ||
2070 | 2068 | ||
2071 | /* Get the data */ | 2069 | /* Get the data */ |
2072 | res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr); | 2070 | res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr); |
@@ -2074,45 +2072,16 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) | |||
2074 | if (scsi_status_is_good(res)) { | 2072 | if (scsi_status_is_good(res)) { |
2075 | int offset = data.header_length + data.block_descriptor_length; | 2073 | int offset = data.header_length + data.block_descriptor_length; |
2076 | 2074 | ||
2077 | while (offset < len) { | 2075 | if (offset >= SD_BUF_SIZE - 2) { |
2078 | u8 page_code = buffer[offset] & 0x3F; | 2076 | sd_printk(KERN_ERR, sdkp, "Malformed MODE SENSE response\n"); |
2079 | u8 spf = buffer[offset] & 0x40; | 2077 | goto defaults; |
2080 | |||
2081 | if (page_code == 8 || page_code == 6) { | ||
2082 | /* We're interested only in the first 3 bytes. | ||
2083 | */ | ||
2084 | if (len - offset <= 2) { | ||
2085 | sd_printk(KERN_ERR, sdkp, "Incomplete " | ||
2086 | "mode parameter data\n"); | ||
2087 | goto defaults; | ||
2088 | } else { | ||
2089 | modepage = page_code; | ||
2090 | goto Page_found; | ||
2091 | } | ||
2092 | } else { | ||
2093 | /* Go to the next page */ | ||
2094 | if (spf && len - offset > 3) | ||
2095 | offset += 4 + (buffer[offset+2] << 8) + | ||
2096 | buffer[offset+3]; | ||
2097 | else if (!spf && len - offset > 1) | ||
2098 | offset += 2 + buffer[offset+1]; | ||
2099 | else { | ||
2100 | sd_printk(KERN_ERR, sdkp, "Incomplete " | ||
2101 | "mode parameter data\n"); | ||
2102 | goto defaults; | ||
2103 | } | ||
2104 | } | ||
2105 | } | 2078 | } |
2106 | 2079 | ||
2107 | if (modepage == 0x3F) { | 2080 | if ((buffer[offset] & 0x3f) != modepage) { |
2108 | sd_printk(KERN_ERR, sdkp, "No Caching mode page " | ||
2109 | "present\n"); | ||
2110 | goto defaults; | ||
2111 | } else if ((buffer[offset] & 0x3f) != modepage) { | ||
2112 | sd_printk(KERN_ERR, sdkp, "Got wrong page\n"); | 2081 | sd_printk(KERN_ERR, sdkp, "Got wrong page\n"); |
2113 | goto defaults; | 2082 | goto defaults; |
2114 | } | 2083 | } |
2115 | Page_found: | 2084 | |
2116 | if (modepage == 8) { | 2085 | if (modepage == 8) { |
2117 | sdkp->WCE = ((buffer[offset + 2] & 0x04) != 0); | 2086 | sdkp->WCE = ((buffer[offset + 2] & 0x04) != 0); |
2118 | sdkp->RCD = ((buffer[offset + 2] & 0x01) != 0); | 2087 | sdkp->RCD = ((buffer[offset + 2] & 0x01) != 0); |
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 7f5a6a86f820..eb7a3e85304f 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c | |||
@@ -35,9 +35,11 @@ | |||
35 | 35 | ||
36 | struct ses_device { | 36 | struct ses_device { |
37 | unsigned char *page1; | 37 | unsigned char *page1; |
38 | unsigned char *page1_types; | ||
38 | unsigned char *page2; | 39 | unsigned char *page2; |
39 | unsigned char *page10; | 40 | unsigned char *page10; |
40 | short page1_len; | 41 | short page1_len; |
42 | short page1_num_types; | ||
41 | short page2_len; | 43 | short page2_len; |
42 | short page10_len; | 44 | short page10_len; |
43 | }; | 45 | }; |
@@ -110,12 +112,12 @@ static int ses_set_page2_descriptor(struct enclosure_device *edev, | |||
110 | int i, j, count = 0, descriptor = ecomp->number; | 112 | int i, j, count = 0, descriptor = ecomp->number; |
111 | struct scsi_device *sdev = to_scsi_device(edev->edev.parent); | 113 | struct scsi_device *sdev = to_scsi_device(edev->edev.parent); |
112 | struct ses_device *ses_dev = edev->scratch; | 114 | struct ses_device *ses_dev = edev->scratch; |
113 | unsigned char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; | 115 | unsigned char *type_ptr = ses_dev->page1_types; |
114 | unsigned char *desc_ptr = ses_dev->page2 + 8; | 116 | unsigned char *desc_ptr = ses_dev->page2 + 8; |
115 | 117 | ||
116 | /* Clear everything */ | 118 | /* Clear everything */ |
117 | memset(desc_ptr, 0, ses_dev->page2_len - 8); | 119 | memset(desc_ptr, 0, ses_dev->page2_len - 8); |
118 | for (i = 0; i < ses_dev->page1[10]; i++, type_ptr += 4) { | 120 | for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) { |
119 | for (j = 0; j < type_ptr[1]; j++) { | 121 | for (j = 0; j < type_ptr[1]; j++) { |
120 | desc_ptr += 4; | 122 | desc_ptr += 4; |
121 | if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && | 123 | if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && |
@@ -140,12 +142,12 @@ static unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev, | |||
140 | int i, j, count = 0, descriptor = ecomp->number; | 142 | int i, j, count = 0, descriptor = ecomp->number; |
141 | struct scsi_device *sdev = to_scsi_device(edev->edev.parent); | 143 | struct scsi_device *sdev = to_scsi_device(edev->edev.parent); |
142 | struct ses_device *ses_dev = edev->scratch; | 144 | struct ses_device *ses_dev = edev->scratch; |
143 | unsigned char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; | 145 | unsigned char *type_ptr = ses_dev->page1_types; |
144 | unsigned char *desc_ptr = ses_dev->page2 + 8; | 146 | unsigned char *desc_ptr = ses_dev->page2 + 8; |
145 | 147 | ||
146 | ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); | 148 | ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); |
147 | 149 | ||
148 | for (i = 0; i < ses_dev->page1[10]; i++, type_ptr += 4) { | 150 | for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) { |
149 | for (j = 0; j < type_ptr[1]; j++) { | 151 | for (j = 0; j < type_ptr[1]; j++) { |
150 | desc_ptr += 4; | 152 | desc_ptr += 4; |
151 | if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && | 153 | if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && |
@@ -358,7 +360,7 @@ static void ses_enclosure_data_process(struct enclosure_device *edev, | |||
358 | unsigned char *buf = NULL, *type_ptr, *desc_ptr, *addl_desc_ptr = NULL; | 360 | unsigned char *buf = NULL, *type_ptr, *desc_ptr, *addl_desc_ptr = NULL; |
359 | int i, j, page7_len, len, components; | 361 | int i, j, page7_len, len, components; |
360 | struct ses_device *ses_dev = edev->scratch; | 362 | struct ses_device *ses_dev = edev->scratch; |
361 | int types = ses_dev->page1[10]; | 363 | int types = ses_dev->page1_num_types; |
362 | unsigned char *hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL); | 364 | unsigned char *hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL); |
363 | 365 | ||
364 | if (!hdr_buf) | 366 | if (!hdr_buf) |
@@ -390,10 +392,10 @@ static void ses_enclosure_data_process(struct enclosure_device *edev, | |||
390 | len = (desc_ptr[2] << 8) + desc_ptr[3]; | 392 | len = (desc_ptr[2] << 8) + desc_ptr[3]; |
391 | /* skip past overall descriptor */ | 393 | /* skip past overall descriptor */ |
392 | desc_ptr += len + 4; | 394 | desc_ptr += len + 4; |
393 | if (ses_dev->page10) | ||
394 | addl_desc_ptr = ses_dev->page10 + 8; | ||
395 | } | 395 | } |
396 | type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; | 396 | if (ses_dev->page10) |
397 | addl_desc_ptr = ses_dev->page10 + 8; | ||
398 | type_ptr = ses_dev->page1_types; | ||
397 | components = 0; | 399 | components = 0; |
398 | for (i = 0; i < types; i++, type_ptr += 4) { | 400 | for (i = 0; i < types; i++, type_ptr += 4) { |
399 | for (j = 0; j < type_ptr[1]; j++) { | 401 | for (j = 0; j < type_ptr[1]; j++) { |
@@ -503,6 +505,7 @@ static int ses_intf_add(struct device *cdev, | |||
503 | u32 result; | 505 | u32 result; |
504 | int i, types, len, components = 0; | 506 | int i, types, len, components = 0; |
505 | int err = -ENOMEM; | 507 | int err = -ENOMEM; |
508 | int num_enclosures; | ||
506 | struct enclosure_device *edev; | 509 | struct enclosure_device *edev; |
507 | struct ses_component *scomp = NULL; | 510 | struct ses_component *scomp = NULL; |
508 | 511 | ||
@@ -530,16 +533,6 @@ static int ses_intf_add(struct device *cdev, | |||
530 | if (result) | 533 | if (result) |
531 | goto recv_failed; | 534 | goto recv_failed; |
532 | 535 | ||
533 | if (hdr_buf[1] != 0) { | ||
534 | /* FIXME: need subenclosure support; I've just never | ||
535 | * seen a device with subenclosures and it makes the | ||
536 | * traversal routines more complex */ | ||
537 | sdev_printk(KERN_ERR, sdev, | ||
538 | "FIXME driver has no support for subenclosures (%d)\n", | ||
539 | hdr_buf[1]); | ||
540 | goto err_free; | ||
541 | } | ||
542 | |||
543 | len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; | 536 | len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; |
544 | buf = kzalloc(len, GFP_KERNEL); | 537 | buf = kzalloc(len, GFP_KERNEL); |
545 | if (!buf) | 538 | if (!buf) |
@@ -549,11 +542,24 @@ static int ses_intf_add(struct device *cdev, | |||
549 | if (result) | 542 | if (result) |
550 | goto recv_failed; | 543 | goto recv_failed; |
551 | 544 | ||
552 | types = buf[10]; | 545 | types = 0; |
553 | 546 | ||
554 | type_ptr = buf + 12 + buf[11]; | 547 | /* we always have one main enclosure and the rest are referred |
548 | * to as secondary subenclosures */ | ||
549 | num_enclosures = buf[1] + 1; | ||
555 | 550 | ||
556 | for (i = 0; i < types; i++, type_ptr += 4) { | 551 | /* begin at the enclosure descriptor */ |
552 | type_ptr = buf + 8; | ||
553 | /* skip all the enclosure descriptors */ | ||
554 | for (i = 0; i < num_enclosures && type_ptr < buf + len; i++) { | ||
555 | types += type_ptr[2]; | ||
556 | type_ptr += type_ptr[3] + 4; | ||
557 | } | ||
558 | |||
559 | ses_dev->page1_types = type_ptr; | ||
560 | ses_dev->page1_num_types = types; | ||
561 | |||
562 | for (i = 0; i < types && type_ptr < buf + len; i++, type_ptr += 4) { | ||
557 | if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || | 563 | if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || |
558 | type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) | 564 | type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) |
559 | components += type_ptr[1]; | 565 | components += type_ptr[1]; |
diff --git a/drivers/staging/westbridge/astoria/block/cyasblkdev_block.c b/drivers/staging/westbridge/astoria/block/cyasblkdev_block.c index 842cd9214a5e..289729daba80 100644 --- a/drivers/staging/westbridge/astoria/block/cyasblkdev_block.c +++ b/drivers/staging/westbridge/astoria/block/cyasblkdev_block.c | |||
@@ -1191,7 +1191,7 @@ static int cyasblkdev_add_disks(int bus_num, | |||
1191 | bd->user_disk_1->first_minor = (devidx + 1) << CYASBLKDEV_SHIFT; | 1191 | bd->user_disk_1->first_minor = (devidx + 1) << CYASBLKDEV_SHIFT; |
1192 | bd->user_disk_1->minors = 8; | 1192 | bd->user_disk_1->minors = 8; |
1193 | bd->user_disk_1->fops = &cyasblkdev_bdops; | 1193 | bd->user_disk_1->fops = &cyasblkdev_bdops; |
1194 | bd->user_disk_0->events = DISK_EVENT_MEDIA_CHANGE; | 1194 | bd->user_disk_1->events = DISK_EVENT_MEDIA_CHANGE; |
1195 | bd->user_disk_1->private_data = bd; | 1195 | bd->user_disk_1->private_data = bd; |
1196 | bd->user_disk_1->queue = bd->queue.queue; | 1196 | bd->user_disk_1->queue = bd->queue.queue; |
1197 | bd->dbgprn_flags = DBGPRN_RD_RQ; | 1197 | bd->dbgprn_flags = DBGPRN_RD_RQ; |
diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig index 2fac3be209ac..9ef2dbbfa62b 100644 --- a/drivers/target/Kconfig +++ b/drivers/target/Kconfig | |||
@@ -29,4 +29,6 @@ config TCM_PSCSI | |||
29 | Say Y here to enable the TCM/pSCSI subsystem plugin for non-buffered | 29 | Say Y here to enable the TCM/pSCSI subsystem plugin for non-buffered |
30 | passthrough access to Linux/SCSI device | 30 | passthrough access to Linux/SCSI device |
31 | 31 | ||
32 | source "drivers/target/loopback/Kconfig" | ||
33 | |||
32 | endif | 34 | endif |
diff --git a/drivers/target/Makefile b/drivers/target/Makefile index 973bb190ef57..1178bbfc68fe 100644 --- a/drivers/target/Makefile +++ b/drivers/target/Makefile | |||
@@ -1,4 +1,3 @@ | |||
1 | EXTRA_CFLAGS += -I$(srctree)/drivers/target/ -I$(srctree)/drivers/scsi/ | ||
2 | 1 | ||
3 | target_core_mod-y := target_core_configfs.o \ | 2 | target_core_mod-y := target_core_configfs.o \ |
4 | target_core_device.o \ | 3 | target_core_device.o \ |
@@ -13,7 +12,8 @@ target_core_mod-y := target_core_configfs.o \ | |||
13 | target_core_transport.o \ | 12 | target_core_transport.o \ |
14 | target_core_cdb.o \ | 13 | target_core_cdb.o \ |
15 | target_core_ua.o \ | 14 | target_core_ua.o \ |
16 | target_core_rd.o | 15 | target_core_rd.o \ |
16 | target_core_stat.o | ||
17 | 17 | ||
18 | obj-$(CONFIG_TARGET_CORE) += target_core_mod.o | 18 | obj-$(CONFIG_TARGET_CORE) += target_core_mod.o |
19 | 19 | ||
@@ -21,3 +21,6 @@ obj-$(CONFIG_TARGET_CORE) += target_core_mod.o | |||
21 | obj-$(CONFIG_TCM_IBLOCK) += target_core_iblock.o | 21 | obj-$(CONFIG_TCM_IBLOCK) += target_core_iblock.o |
22 | obj-$(CONFIG_TCM_FILEIO) += target_core_file.o | 22 | obj-$(CONFIG_TCM_FILEIO) += target_core_file.o |
23 | obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.o | 23 | obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.o |
24 | |||
25 | # Fabric modules | ||
26 | obj-$(CONFIG_LOOPBACK_TARGET) += loopback/ | ||
diff --git a/drivers/target/loopback/Kconfig b/drivers/target/loopback/Kconfig new file mode 100644 index 000000000000..57dcbc2d711b --- /dev/null +++ b/drivers/target/loopback/Kconfig | |||
@@ -0,0 +1,11 @@ | |||
1 | config LOOPBACK_TARGET | ||
2 | tristate "TCM Virtual SAS target and Linux/SCSI LDD fabric loopback module" | ||
3 | help | ||
4 | Say Y here to enable the TCM Virtual SAS target and Linux/SCSI LLD | ||
5 | fabric loopback module. | ||
6 | |||
7 | config LOOPBACK_TARGET_CDB_DEBUG | ||
8 | bool "TCM loopback fabric module CDB debug code" | ||
9 | depends on LOOPBACK_TARGET | ||
10 | help | ||
11 | Say Y here to enable the TCM loopback fabric module CDB debug code | ||
diff --git a/drivers/target/loopback/Makefile b/drivers/target/loopback/Makefile new file mode 100644 index 000000000000..6abebdf95659 --- /dev/null +++ b/drivers/target/loopback/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_LOOPBACK_TARGET) += tcm_loop.o | |||
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c new file mode 100644 index 000000000000..aed4e464d31c --- /dev/null +++ b/drivers/target/loopback/tcm_loop.c | |||
@@ -0,0 +1,1579 @@ | |||
1 | /******************************************************************************* | ||
2 | * | ||
3 | * This file contains the Linux/SCSI LLD virtual SCSI initiator driver | ||
4 | * for emulated SAS initiator ports | ||
5 | * | ||
6 | * © Copyright 2011 RisingTide Systems LLC. | ||
7 | * | ||
8 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
9 | * | ||
10 | * Author: Nicholas A. Bellinger <nab@risingtidesystems.com> | ||
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 as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | ****************************************************************************/ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/moduleparam.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/types.h> | ||
28 | #include <linux/configfs.h> | ||
29 | #include <scsi/scsi.h> | ||
30 | #include <scsi/scsi_tcq.h> | ||
31 | #include <scsi/scsi_host.h> | ||
32 | #include <scsi/scsi_device.h> | ||
33 | #include <scsi/scsi_cmnd.h> | ||
34 | #include <scsi/libsas.h> /* For TASK_ATTR_* */ | ||
35 | |||
36 | #include <target/target_core_base.h> | ||
37 | #include <target/target_core_transport.h> | ||
38 | #include <target/target_core_fabric_ops.h> | ||
39 | #include <target/target_core_fabric_configfs.h> | ||
40 | #include <target/target_core_fabric_lib.h> | ||
41 | #include <target/target_core_configfs.h> | ||
42 | #include <target/target_core_device.h> | ||
43 | #include <target/target_core_tpg.h> | ||
44 | #include <target/target_core_tmr.h> | ||
45 | |||
46 | #include "tcm_loop.h" | ||
47 | |||
48 | #define to_tcm_loop_hba(hba) container_of(hba, struct tcm_loop_hba, dev) | ||
49 | |||
50 | /* Local pointer to allocated TCM configfs fabric module */ | ||
51 | static struct target_fabric_configfs *tcm_loop_fabric_configfs; | ||
52 | |||
53 | static struct kmem_cache *tcm_loop_cmd_cache; | ||
54 | |||
55 | static int tcm_loop_hba_no_cnt; | ||
56 | |||
57 | /* | ||
58 | * Allocate a tcm_loop cmd descriptor from target_core_mod code | ||
59 | * | ||
60 | * Can be called from interrupt context in tcm_loop_queuecommand() below | ||
61 | */ | ||
62 | static struct se_cmd *tcm_loop_allocate_core_cmd( | ||
63 | struct tcm_loop_hba *tl_hba, | ||
64 | struct se_portal_group *se_tpg, | ||
65 | struct scsi_cmnd *sc) | ||
66 | { | ||
67 | struct se_cmd *se_cmd; | ||
68 | struct se_session *se_sess; | ||
69 | struct tcm_loop_nexus *tl_nexus = tl_hba->tl_nexus; | ||
70 | struct tcm_loop_cmd *tl_cmd; | ||
71 | int sam_task_attr; | ||
72 | |||
73 | if (!tl_nexus) { | ||
74 | scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus" | ||
75 | " does not exist\n"); | ||
76 | set_host_byte(sc, DID_ERROR); | ||
77 | return NULL; | ||
78 | } | ||
79 | se_sess = tl_nexus->se_sess; | ||
80 | |||
81 | tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_ATOMIC); | ||
82 | if (!tl_cmd) { | ||
83 | printk(KERN_ERR "Unable to allocate struct tcm_loop_cmd\n"); | ||
84 | set_host_byte(sc, DID_ERROR); | ||
85 | return NULL; | ||
86 | } | ||
87 | se_cmd = &tl_cmd->tl_se_cmd; | ||
88 | /* | ||
89 | * Save the pointer to struct scsi_cmnd *sc | ||
90 | */ | ||
91 | tl_cmd->sc = sc; | ||
92 | /* | ||
93 | * Locate the SAM Task Attr from struct scsi_cmnd * | ||
94 | */ | ||
95 | if (sc->device->tagged_supported) { | ||
96 | switch (sc->tag) { | ||
97 | case HEAD_OF_QUEUE_TAG: | ||
98 | sam_task_attr = TASK_ATTR_HOQ; | ||
99 | break; | ||
100 | case ORDERED_QUEUE_TAG: | ||
101 | sam_task_attr = TASK_ATTR_ORDERED; | ||
102 | break; | ||
103 | default: | ||
104 | sam_task_attr = TASK_ATTR_SIMPLE; | ||
105 | break; | ||
106 | } | ||
107 | } else | ||
108 | sam_task_attr = TASK_ATTR_SIMPLE; | ||
109 | |||
110 | /* | ||
111 | * Initialize struct se_cmd descriptor from target_core_mod infrastructure | ||
112 | */ | ||
113 | transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, | ||
114 | scsi_bufflen(sc), sc->sc_data_direction, sam_task_attr, | ||
115 | &tl_cmd->tl_sense_buf[0]); | ||
116 | |||
117 | /* | ||
118 | * Signal BIDI usage with T_TASK(cmd)->t_tasks_bidi | ||
119 | */ | ||
120 | if (scsi_bidi_cmnd(sc)) | ||
121 | T_TASK(se_cmd)->t_tasks_bidi = 1; | ||
122 | /* | ||
123 | * Locate the struct se_lun pointer and attach it to struct se_cmd | ||
124 | */ | ||
125 | if (transport_get_lun_for_cmd(se_cmd, NULL, tl_cmd->sc->device->lun) < 0) { | ||
126 | kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); | ||
127 | set_host_byte(sc, DID_NO_CONNECT); | ||
128 | return NULL; | ||
129 | } | ||
130 | |||
131 | transport_device_setup_cmd(se_cmd); | ||
132 | return se_cmd; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * Called by struct target_core_fabric_ops->new_cmd_map() | ||
137 | * | ||
138 | * Always called in process context. A non zero return value | ||
139 | * here will signal to handle an exception based on the return code. | ||
140 | */ | ||
141 | static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd) | ||
142 | { | ||
143 | struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, | ||
144 | struct tcm_loop_cmd, tl_se_cmd); | ||
145 | struct scsi_cmnd *sc = tl_cmd->sc; | ||
146 | void *mem_ptr, *mem_bidi_ptr = NULL; | ||
147 | u32 sg_no_bidi = 0; | ||
148 | int ret; | ||
149 | /* | ||
150 | * Allocate the necessary tasks to complete the received CDB+data | ||
151 | */ | ||
152 | ret = transport_generic_allocate_tasks(se_cmd, tl_cmd->sc->cmnd); | ||
153 | if (ret == -1) { | ||
154 | /* Out of Resources */ | ||
155 | return PYX_TRANSPORT_LU_COMM_FAILURE; | ||
156 | } else if (ret == -2) { | ||
157 | /* | ||
158 | * Handle case for SAM_STAT_RESERVATION_CONFLICT | ||
159 | */ | ||
160 | if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) | ||
161 | return PYX_TRANSPORT_RESERVATION_CONFLICT; | ||
162 | /* | ||
163 | * Otherwise, return SAM_STAT_CHECK_CONDITION and return | ||
164 | * sense data. | ||
165 | */ | ||
166 | return PYX_TRANSPORT_USE_SENSE_REASON; | ||
167 | } | ||
168 | /* | ||
169 | * Setup the struct scatterlist memory from the received | ||
170 | * struct scsi_cmnd. | ||
171 | */ | ||
172 | if (scsi_sg_count(sc)) { | ||
173 | se_cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM; | ||
174 | mem_ptr = (void *)scsi_sglist(sc); | ||
175 | /* | ||
176 | * For BIDI commands, pass in the extra READ buffer | ||
177 | * to transport_generic_map_mem_to_cmd() below.. | ||
178 | */ | ||
179 | if (T_TASK(se_cmd)->t_tasks_bidi) { | ||
180 | struct scsi_data_buffer *sdb = scsi_in(sc); | ||
181 | |||
182 | mem_bidi_ptr = (void *)sdb->table.sgl; | ||
183 | sg_no_bidi = sdb->table.nents; | ||
184 | } | ||
185 | } else { | ||
186 | /* | ||
187 | * Used for DMA_NONE | ||
188 | */ | ||
189 | mem_ptr = NULL; | ||
190 | } | ||
191 | /* | ||
192 | * Map the SG memory into struct se_mem->page linked list using the same | ||
193 | * physical memory at sg->page_link. | ||
194 | */ | ||
195 | ret = transport_generic_map_mem_to_cmd(se_cmd, mem_ptr, | ||
196 | scsi_sg_count(sc), mem_bidi_ptr, sg_no_bidi); | ||
197 | if (ret < 0) | ||
198 | return PYX_TRANSPORT_LU_COMM_FAILURE; | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * Called from struct target_core_fabric_ops->check_stop_free() | ||
205 | */ | ||
206 | static void tcm_loop_check_stop_free(struct se_cmd *se_cmd) | ||
207 | { | ||
208 | /* | ||
209 | * Do not release struct se_cmd's containing a valid TMR | ||
210 | * pointer. These will be released directly in tcm_loop_device_reset() | ||
211 | * with transport_generic_free_cmd(). | ||
212 | */ | ||
213 | if (se_cmd->se_tmr_req) | ||
214 | return; | ||
215 | /* | ||
216 | * Release the struct se_cmd, which will make a callback to release | ||
217 | * struct tcm_loop_cmd * in tcm_loop_deallocate_core_cmd() | ||
218 | */ | ||
219 | transport_generic_free_cmd(se_cmd, 0, 1, 0); | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * Called from struct target_core_fabric_ops->release_cmd_to_pool() | ||
224 | */ | ||
225 | static void tcm_loop_deallocate_core_cmd(struct se_cmd *se_cmd) | ||
226 | { | ||
227 | struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, | ||
228 | struct tcm_loop_cmd, tl_se_cmd); | ||
229 | |||
230 | kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); | ||
231 | } | ||
232 | |||
233 | static int tcm_loop_proc_info(struct Scsi_Host *host, char *buffer, | ||
234 | char **start, off_t offset, | ||
235 | int length, int inout) | ||
236 | { | ||
237 | return sprintf(buffer, "tcm_loop_proc_info()\n"); | ||
238 | } | ||
239 | |||
240 | static int tcm_loop_driver_probe(struct device *); | ||
241 | static int tcm_loop_driver_remove(struct device *); | ||
242 | |||
243 | static int pseudo_lld_bus_match(struct device *dev, | ||
244 | struct device_driver *dev_driver) | ||
245 | { | ||
246 | return 1; | ||
247 | } | ||
248 | |||
249 | static struct bus_type tcm_loop_lld_bus = { | ||
250 | .name = "tcm_loop_bus", | ||
251 | .match = pseudo_lld_bus_match, | ||
252 | .probe = tcm_loop_driver_probe, | ||
253 | .remove = tcm_loop_driver_remove, | ||
254 | }; | ||
255 | |||
256 | static struct device_driver tcm_loop_driverfs = { | ||
257 | .name = "tcm_loop", | ||
258 | .bus = &tcm_loop_lld_bus, | ||
259 | }; | ||
260 | /* | ||
261 | * Used with root_device_register() in tcm_loop_alloc_core_bus() below | ||
262 | */ | ||
263 | struct device *tcm_loop_primary; | ||
264 | |||
265 | /* | ||
266 | * Copied from drivers/scsi/libfc/fc_fcp.c:fc_change_queue_depth() and | ||
267 | * drivers/scsi/libiscsi.c:iscsi_change_queue_depth() | ||
268 | */ | ||
269 | static int tcm_loop_change_queue_depth( | ||
270 | struct scsi_device *sdev, | ||
271 | int depth, | ||
272 | int reason) | ||
273 | { | ||
274 | switch (reason) { | ||
275 | case SCSI_QDEPTH_DEFAULT: | ||
276 | scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); | ||
277 | break; | ||
278 | case SCSI_QDEPTH_QFULL: | ||
279 | scsi_track_queue_full(sdev, depth); | ||
280 | break; | ||
281 | case SCSI_QDEPTH_RAMP_UP: | ||
282 | scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); | ||
283 | break; | ||
284 | default: | ||
285 | return -EOPNOTSUPP; | ||
286 | } | ||
287 | return sdev->queue_depth; | ||
288 | } | ||
289 | |||
290 | /* | ||
291 | * Main entry point from struct scsi_host_template for incoming SCSI CDB+Data | ||
292 | * from Linux/SCSI subsystem for SCSI low level device drivers (LLDs) | ||
293 | */ | ||
294 | static int tcm_loop_queuecommand( | ||
295 | struct Scsi_Host *sh, | ||
296 | struct scsi_cmnd *sc) | ||
297 | { | ||
298 | struct se_cmd *se_cmd; | ||
299 | struct se_portal_group *se_tpg; | ||
300 | struct tcm_loop_hba *tl_hba; | ||
301 | struct tcm_loop_tpg *tl_tpg; | ||
302 | |||
303 | TL_CDB_DEBUG("tcm_loop_queuecommand() %d:%d:%d:%d got CDB: 0x%02x" | ||
304 | " scsi_buf_len: %u\n", sc->device->host->host_no, | ||
305 | sc->device->id, sc->device->channel, sc->device->lun, | ||
306 | sc->cmnd[0], scsi_bufflen(sc)); | ||
307 | /* | ||
308 | * Locate the tcm_loop_hba_t pointer | ||
309 | */ | ||
310 | tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); | ||
311 | tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; | ||
312 | se_tpg = &tl_tpg->tl_se_tpg; | ||
313 | /* | ||
314 | * Determine the SAM Task Attribute and allocate tl_cmd and | ||
315 | * tl_cmd->tl_se_cmd from TCM infrastructure | ||
316 | */ | ||
317 | se_cmd = tcm_loop_allocate_core_cmd(tl_hba, se_tpg, sc); | ||
318 | if (!se_cmd) { | ||
319 | sc->scsi_done(sc); | ||
320 | return 0; | ||
321 | } | ||
322 | /* | ||
323 | * Queue up the newly allocated to be processed in TCM thread context. | ||
324 | */ | ||
325 | transport_generic_handle_cdb_map(se_cmd); | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | /* | ||
330 | * Called from SCSI EH process context to issue a LUN_RESET TMR | ||
331 | * to struct scsi_device | ||
332 | */ | ||
333 | static int tcm_loop_device_reset(struct scsi_cmnd *sc) | ||
334 | { | ||
335 | struct se_cmd *se_cmd = NULL; | ||
336 | struct se_portal_group *se_tpg; | ||
337 | struct se_session *se_sess; | ||
338 | struct tcm_loop_cmd *tl_cmd = NULL; | ||
339 | struct tcm_loop_hba *tl_hba; | ||
340 | struct tcm_loop_nexus *tl_nexus; | ||
341 | struct tcm_loop_tmr *tl_tmr = NULL; | ||
342 | struct tcm_loop_tpg *tl_tpg; | ||
343 | int ret = FAILED; | ||
344 | /* | ||
345 | * Locate the tcm_loop_hba_t pointer | ||
346 | */ | ||
347 | tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); | ||
348 | /* | ||
349 | * Locate the tl_nexus and se_sess pointers | ||
350 | */ | ||
351 | tl_nexus = tl_hba->tl_nexus; | ||
352 | if (!tl_nexus) { | ||
353 | printk(KERN_ERR "Unable to perform device reset without" | ||
354 | " active I_T Nexus\n"); | ||
355 | return FAILED; | ||
356 | } | ||
357 | se_sess = tl_nexus->se_sess; | ||
358 | /* | ||
359 | * Locate the tl_tpg and se_tpg pointers from TargetID in sc->device->id | ||
360 | */ | ||
361 | tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; | ||
362 | se_tpg = &tl_tpg->tl_se_tpg; | ||
363 | |||
364 | tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_KERNEL); | ||
365 | if (!tl_cmd) { | ||
366 | printk(KERN_ERR "Unable to allocate memory for tl_cmd\n"); | ||
367 | return FAILED; | ||
368 | } | ||
369 | |||
370 | tl_tmr = kzalloc(sizeof(struct tcm_loop_tmr), GFP_KERNEL); | ||
371 | if (!tl_tmr) { | ||
372 | printk(KERN_ERR "Unable to allocate memory for tl_tmr\n"); | ||
373 | goto release; | ||
374 | } | ||
375 | init_waitqueue_head(&tl_tmr->tl_tmr_wait); | ||
376 | |||
377 | se_cmd = &tl_cmd->tl_se_cmd; | ||
378 | /* | ||
379 | * Initialize struct se_cmd descriptor from target_core_mod infrastructure | ||
380 | */ | ||
381 | transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, 0, | ||
382 | DMA_NONE, TASK_ATTR_SIMPLE, | ||
383 | &tl_cmd->tl_sense_buf[0]); | ||
384 | /* | ||
385 | * Allocate the LUN_RESET TMR | ||
386 | */ | ||
387 | se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd, (void *)tl_tmr, | ||
388 | TMR_LUN_RESET); | ||
389 | if (!se_cmd->se_tmr_req) | ||
390 | goto release; | ||
391 | /* | ||
392 | * Locate the underlying TCM struct se_lun from sc->device->lun | ||
393 | */ | ||
394 | if (transport_get_lun_for_tmr(se_cmd, sc->device->lun) < 0) | ||
395 | goto release; | ||
396 | /* | ||
397 | * Queue the TMR to TCM Core and sleep waiting for tcm_loop_queue_tm_rsp() | ||
398 | * to wake us up. | ||
399 | */ | ||
400 | transport_generic_handle_tmr(se_cmd); | ||
401 | wait_event(tl_tmr->tl_tmr_wait, atomic_read(&tl_tmr->tmr_complete)); | ||
402 | /* | ||
403 | * The TMR LUN_RESET has completed, check the response status and | ||
404 | * then release allocations. | ||
405 | */ | ||
406 | ret = (se_cmd->se_tmr_req->response == TMR_FUNCTION_COMPLETE) ? | ||
407 | SUCCESS : FAILED; | ||
408 | release: | ||
409 | if (se_cmd) | ||
410 | transport_generic_free_cmd(se_cmd, 1, 1, 0); | ||
411 | else | ||
412 | kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); | ||
413 | kfree(tl_tmr); | ||
414 | return ret; | ||
415 | } | ||
416 | |||
417 | static int tcm_loop_slave_alloc(struct scsi_device *sd) | ||
418 | { | ||
419 | set_bit(QUEUE_FLAG_BIDI, &sd->request_queue->queue_flags); | ||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | static int tcm_loop_slave_configure(struct scsi_device *sd) | ||
424 | { | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | static struct scsi_host_template tcm_loop_driver_template = { | ||
429 | .proc_info = tcm_loop_proc_info, | ||
430 | .proc_name = "tcm_loopback", | ||
431 | .name = "TCM_Loopback", | ||
432 | .queuecommand = tcm_loop_queuecommand, | ||
433 | .change_queue_depth = tcm_loop_change_queue_depth, | ||
434 | .eh_device_reset_handler = tcm_loop_device_reset, | ||
435 | .can_queue = TL_SCSI_CAN_QUEUE, | ||
436 | .this_id = -1, | ||
437 | .sg_tablesize = TL_SCSI_SG_TABLESIZE, | ||
438 | .cmd_per_lun = TL_SCSI_CMD_PER_LUN, | ||
439 | .max_sectors = TL_SCSI_MAX_SECTORS, | ||
440 | .use_clustering = DISABLE_CLUSTERING, | ||
441 | .slave_alloc = tcm_loop_slave_alloc, | ||
442 | .slave_configure = tcm_loop_slave_configure, | ||
443 | .module = THIS_MODULE, | ||
444 | }; | ||
445 | |||
446 | static int tcm_loop_driver_probe(struct device *dev) | ||
447 | { | ||
448 | struct tcm_loop_hba *tl_hba; | ||
449 | struct Scsi_Host *sh; | ||
450 | int error; | ||
451 | |||
452 | tl_hba = to_tcm_loop_hba(dev); | ||
453 | |||
454 | sh = scsi_host_alloc(&tcm_loop_driver_template, | ||
455 | sizeof(struct tcm_loop_hba)); | ||
456 | if (!sh) { | ||
457 | printk(KERN_ERR "Unable to allocate struct scsi_host\n"); | ||
458 | return -ENODEV; | ||
459 | } | ||
460 | tl_hba->sh = sh; | ||
461 | |||
462 | /* | ||
463 | * Assign the struct tcm_loop_hba pointer to struct Scsi_Host->hostdata | ||
464 | */ | ||
465 | *((struct tcm_loop_hba **)sh->hostdata) = tl_hba; | ||
466 | /* | ||
467 | * Setup single ID, Channel and LUN for now.. | ||
468 | */ | ||
469 | sh->max_id = 2; | ||
470 | sh->max_lun = 0; | ||
471 | sh->max_channel = 0; | ||
472 | sh->max_cmd_len = TL_SCSI_MAX_CMD_LEN; | ||
473 | |||
474 | error = scsi_add_host(sh, &tl_hba->dev); | ||
475 | if (error) { | ||
476 | printk(KERN_ERR "%s: scsi_add_host failed\n", __func__); | ||
477 | scsi_host_put(sh); | ||
478 | return -ENODEV; | ||
479 | } | ||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static int tcm_loop_driver_remove(struct device *dev) | ||
484 | { | ||
485 | struct tcm_loop_hba *tl_hba; | ||
486 | struct Scsi_Host *sh; | ||
487 | |||
488 | tl_hba = to_tcm_loop_hba(dev); | ||
489 | sh = tl_hba->sh; | ||
490 | |||
491 | scsi_remove_host(sh); | ||
492 | scsi_host_put(sh); | ||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | static void tcm_loop_release_adapter(struct device *dev) | ||
497 | { | ||
498 | struct tcm_loop_hba *tl_hba = to_tcm_loop_hba(dev); | ||
499 | |||
500 | kfree(tl_hba); | ||
501 | } | ||
502 | |||
503 | /* | ||
504 | * Called from tcm_loop_make_scsi_hba() in tcm_loop_configfs.c | ||
505 | */ | ||
506 | static int tcm_loop_setup_hba_bus(struct tcm_loop_hba *tl_hba, int tcm_loop_host_id) | ||
507 | { | ||
508 | int ret; | ||
509 | |||
510 | tl_hba->dev.bus = &tcm_loop_lld_bus; | ||
511 | tl_hba->dev.parent = tcm_loop_primary; | ||
512 | tl_hba->dev.release = &tcm_loop_release_adapter; | ||
513 | dev_set_name(&tl_hba->dev, "tcm_loop_adapter_%d", tcm_loop_host_id); | ||
514 | |||
515 | ret = device_register(&tl_hba->dev); | ||
516 | if (ret) { | ||
517 | printk(KERN_ERR "device_register() failed for" | ||
518 | " tl_hba->dev: %d\n", ret); | ||
519 | return -ENODEV; | ||
520 | } | ||
521 | |||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | /* | ||
526 | * Called from tcm_loop_fabric_init() in tcl_loop_fabric.c to load the emulated | ||
527 | * tcm_loop SCSI bus. | ||
528 | */ | ||
529 | static int tcm_loop_alloc_core_bus(void) | ||
530 | { | ||
531 | int ret; | ||
532 | |||
533 | tcm_loop_primary = root_device_register("tcm_loop_0"); | ||
534 | if (IS_ERR(tcm_loop_primary)) { | ||
535 | printk(KERN_ERR "Unable to allocate tcm_loop_primary\n"); | ||
536 | return PTR_ERR(tcm_loop_primary); | ||
537 | } | ||
538 | |||
539 | ret = bus_register(&tcm_loop_lld_bus); | ||
540 | if (ret) { | ||
541 | printk(KERN_ERR "bus_register() failed for tcm_loop_lld_bus\n"); | ||
542 | goto dev_unreg; | ||
543 | } | ||
544 | |||
545 | ret = driver_register(&tcm_loop_driverfs); | ||
546 | if (ret) { | ||
547 | printk(KERN_ERR "driver_register() failed for" | ||
548 | "tcm_loop_driverfs\n"); | ||
549 | goto bus_unreg; | ||
550 | } | ||
551 | |||
552 | printk(KERN_INFO "Initialized TCM Loop Core Bus\n"); | ||
553 | return ret; | ||
554 | |||
555 | bus_unreg: | ||
556 | bus_unregister(&tcm_loop_lld_bus); | ||
557 | dev_unreg: | ||
558 | root_device_unregister(tcm_loop_primary); | ||
559 | return ret; | ||
560 | } | ||
561 | |||
562 | static void tcm_loop_release_core_bus(void) | ||
563 | { | ||
564 | driver_unregister(&tcm_loop_driverfs); | ||
565 | bus_unregister(&tcm_loop_lld_bus); | ||
566 | root_device_unregister(tcm_loop_primary); | ||
567 | |||
568 | printk(KERN_INFO "Releasing TCM Loop Core BUS\n"); | ||
569 | } | ||
570 | |||
571 | static char *tcm_loop_get_fabric_name(void) | ||
572 | { | ||
573 | return "loopback"; | ||
574 | } | ||
575 | |||
576 | static u8 tcm_loop_get_fabric_proto_ident(struct se_portal_group *se_tpg) | ||
577 | { | ||
578 | struct tcm_loop_tpg *tl_tpg = | ||
579 | (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; | ||
580 | struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; | ||
581 | /* | ||
582 | * tl_proto_id is set at tcm_loop_configfs.c:tcm_loop_make_scsi_hba() | ||
583 | * time based on the protocol dependent prefix of the passed configfs group. | ||
584 | * | ||
585 | * Based upon tl_proto_id, TCM_Loop emulates the requested fabric | ||
586 | * ProtocolID using target_core_fabric_lib.c symbols. | ||
587 | */ | ||
588 | switch (tl_hba->tl_proto_id) { | ||
589 | case SCSI_PROTOCOL_SAS: | ||
590 | return sas_get_fabric_proto_ident(se_tpg); | ||
591 | case SCSI_PROTOCOL_FCP: | ||
592 | return fc_get_fabric_proto_ident(se_tpg); | ||
593 | case SCSI_PROTOCOL_ISCSI: | ||
594 | return iscsi_get_fabric_proto_ident(se_tpg); | ||
595 | default: | ||
596 | printk(KERN_ERR "Unknown tl_proto_id: 0x%02x, using" | ||
597 | " SAS emulation\n", tl_hba->tl_proto_id); | ||
598 | break; | ||
599 | } | ||
600 | |||
601 | return sas_get_fabric_proto_ident(se_tpg); | ||
602 | } | ||
603 | |||
604 | static char *tcm_loop_get_endpoint_wwn(struct se_portal_group *se_tpg) | ||
605 | { | ||
606 | struct tcm_loop_tpg *tl_tpg = | ||
607 | (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; | ||
608 | /* | ||
609 | * Return the passed NAA identifier for the SAS Target Port | ||
610 | */ | ||
611 | return &tl_tpg->tl_hba->tl_wwn_address[0]; | ||
612 | } | ||
613 | |||
614 | static u16 tcm_loop_get_tag(struct se_portal_group *se_tpg) | ||
615 | { | ||
616 | struct tcm_loop_tpg *tl_tpg = | ||
617 | (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; | ||
618 | /* | ||
619 | * This Tag is used when forming SCSI Name identifier in EVPD=1 0x83 | ||
620 | * to represent the SCSI Target Port. | ||
621 | */ | ||
622 | return tl_tpg->tl_tpgt; | ||
623 | } | ||
624 | |||
625 | static u32 tcm_loop_get_default_depth(struct se_portal_group *se_tpg) | ||
626 | { | ||
627 | return 1; | ||
628 | } | ||
629 | |||
630 | static u32 tcm_loop_get_pr_transport_id( | ||
631 | struct se_portal_group *se_tpg, | ||
632 | struct se_node_acl *se_nacl, | ||
633 | struct t10_pr_registration *pr_reg, | ||
634 | int *format_code, | ||
635 | unsigned char *buf) | ||
636 | { | ||
637 | struct tcm_loop_tpg *tl_tpg = | ||
638 | (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; | ||
639 | struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; | ||
640 | |||
641 | switch (tl_hba->tl_proto_id) { | ||
642 | case SCSI_PROTOCOL_SAS: | ||
643 | return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, | ||
644 | format_code, buf); | ||
645 | case SCSI_PROTOCOL_FCP: | ||
646 | return fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg, | ||
647 | format_code, buf); | ||
648 | case SCSI_PROTOCOL_ISCSI: | ||
649 | return iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg, | ||
650 | format_code, buf); | ||
651 | default: | ||
652 | printk(KERN_ERR "Unknown tl_proto_id: 0x%02x, using" | ||
653 | " SAS emulation\n", tl_hba->tl_proto_id); | ||
654 | break; | ||
655 | } | ||
656 | |||
657 | return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, | ||
658 | format_code, buf); | ||
659 | } | ||
660 | |||
661 | static u32 tcm_loop_get_pr_transport_id_len( | ||
662 | struct se_portal_group *se_tpg, | ||
663 | struct se_node_acl *se_nacl, | ||
664 | struct t10_pr_registration *pr_reg, | ||
665 | int *format_code) | ||
666 | { | ||
667 | struct tcm_loop_tpg *tl_tpg = | ||
668 | (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; | ||
669 | struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; | ||
670 | |||
671 | switch (tl_hba->tl_proto_id) { | ||
672 | case SCSI_PROTOCOL_SAS: | ||
673 | return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, | ||
674 | format_code); | ||
675 | case SCSI_PROTOCOL_FCP: | ||
676 | return fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, | ||
677 | format_code); | ||
678 | case SCSI_PROTOCOL_ISCSI: | ||
679 | return iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, | ||
680 | format_code); | ||
681 | default: | ||
682 | printk(KERN_ERR "Unknown tl_proto_id: 0x%02x, using" | ||
683 | " SAS emulation\n", tl_hba->tl_proto_id); | ||
684 | break; | ||
685 | } | ||
686 | |||
687 | return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, | ||
688 | format_code); | ||
689 | } | ||
690 | |||
691 | /* | ||
692 | * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above | ||
693 | * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations. | ||
694 | */ | ||
695 | static char *tcm_loop_parse_pr_out_transport_id( | ||
696 | struct se_portal_group *se_tpg, | ||
697 | const char *buf, | ||
698 | u32 *out_tid_len, | ||
699 | char **port_nexus_ptr) | ||
700 | { | ||
701 | struct tcm_loop_tpg *tl_tpg = | ||
702 | (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; | ||
703 | struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; | ||
704 | |||
705 | switch (tl_hba->tl_proto_id) { | ||
706 | case SCSI_PROTOCOL_SAS: | ||
707 | return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, | ||
708 | port_nexus_ptr); | ||
709 | case SCSI_PROTOCOL_FCP: | ||
710 | return fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, | ||
711 | port_nexus_ptr); | ||
712 | case SCSI_PROTOCOL_ISCSI: | ||
713 | return iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, | ||
714 | port_nexus_ptr); | ||
715 | default: | ||
716 | printk(KERN_ERR "Unknown tl_proto_id: 0x%02x, using" | ||
717 | " SAS emulation\n", tl_hba->tl_proto_id); | ||
718 | break; | ||
719 | } | ||
720 | |||
721 | return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, | ||
722 | port_nexus_ptr); | ||
723 | } | ||
724 | |||
725 | /* | ||
726 | * Returning (1) here allows for target_core_mod struct se_node_acl to be generated | ||
727 | * based upon the incoming fabric dependent SCSI Initiator Port | ||
728 | */ | ||
729 | static int tcm_loop_check_demo_mode(struct se_portal_group *se_tpg) | ||
730 | { | ||
731 | return 1; | ||
732 | } | ||
733 | |||
734 | static int tcm_loop_check_demo_mode_cache(struct se_portal_group *se_tpg) | ||
735 | { | ||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | /* | ||
740 | * Allow I_T Nexus full READ-WRITE access without explict Initiator Node ACLs for | ||
741 | * local virtual Linux/SCSI LLD passthrough into VM hypervisor guest | ||
742 | */ | ||
743 | static int tcm_loop_check_demo_mode_write_protect(struct se_portal_group *se_tpg) | ||
744 | { | ||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | /* | ||
749 | * Because TCM_Loop does not use explict ACLs and MappedLUNs, this will | ||
750 | * never be called for TCM_Loop by target_core_fabric_configfs.c code. | ||
751 | * It has been added here as a nop for target_fabric_tf_ops_check() | ||
752 | */ | ||
753 | static int tcm_loop_check_prod_mode_write_protect(struct se_portal_group *se_tpg) | ||
754 | { | ||
755 | return 0; | ||
756 | } | ||
757 | |||
758 | static struct se_node_acl *tcm_loop_tpg_alloc_fabric_acl( | ||
759 | struct se_portal_group *se_tpg) | ||
760 | { | ||
761 | struct tcm_loop_nacl *tl_nacl; | ||
762 | |||
763 | tl_nacl = kzalloc(sizeof(struct tcm_loop_nacl), GFP_KERNEL); | ||
764 | if (!tl_nacl) { | ||
765 | printk(KERN_ERR "Unable to allocate struct tcm_loop_nacl\n"); | ||
766 | return NULL; | ||
767 | } | ||
768 | |||
769 | return &tl_nacl->se_node_acl; | ||
770 | } | ||
771 | |||
772 | static void tcm_loop_tpg_release_fabric_acl( | ||
773 | struct se_portal_group *se_tpg, | ||
774 | struct se_node_acl *se_nacl) | ||
775 | { | ||
776 | struct tcm_loop_nacl *tl_nacl = container_of(se_nacl, | ||
777 | struct tcm_loop_nacl, se_node_acl); | ||
778 | |||
779 | kfree(tl_nacl); | ||
780 | } | ||
781 | |||
782 | static u32 tcm_loop_get_inst_index(struct se_portal_group *se_tpg) | ||
783 | { | ||
784 | return 1; | ||
785 | } | ||
786 | |||
787 | static void tcm_loop_new_cmd_failure(struct se_cmd *se_cmd) | ||
788 | { | ||
789 | /* | ||
790 | * Since TCM_loop is already passing struct scatterlist data from | ||
791 | * struct scsi_cmnd, no more Linux/SCSI failure dependent state need | ||
792 | * to be handled here. | ||
793 | */ | ||
794 | return; | ||
795 | } | ||
796 | |||
797 | static int tcm_loop_is_state_remove(struct se_cmd *se_cmd) | ||
798 | { | ||
799 | /* | ||
800 | * Assume struct scsi_cmnd is not in remove state.. | ||
801 | */ | ||
802 | return 0; | ||
803 | } | ||
804 | |||
805 | static int tcm_loop_sess_logged_in(struct se_session *se_sess) | ||
806 | { | ||
807 | /* | ||
808 | * Assume that TL Nexus is always active | ||
809 | */ | ||
810 | return 1; | ||
811 | } | ||
812 | |||
813 | static u32 tcm_loop_sess_get_index(struct se_session *se_sess) | ||
814 | { | ||
815 | return 1; | ||
816 | } | ||
817 | |||
818 | static void tcm_loop_set_default_node_attributes(struct se_node_acl *se_acl) | ||
819 | { | ||
820 | return; | ||
821 | } | ||
822 | |||
823 | static u32 tcm_loop_get_task_tag(struct se_cmd *se_cmd) | ||
824 | { | ||
825 | return 1; | ||
826 | } | ||
827 | |||
828 | static int tcm_loop_get_cmd_state(struct se_cmd *se_cmd) | ||
829 | { | ||
830 | struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, | ||
831 | struct tcm_loop_cmd, tl_se_cmd); | ||
832 | |||
833 | return tl_cmd->sc_cmd_state; | ||
834 | } | ||
835 | |||
836 | static int tcm_loop_shutdown_session(struct se_session *se_sess) | ||
837 | { | ||
838 | return 0; | ||
839 | } | ||
840 | |||
841 | static void tcm_loop_close_session(struct se_session *se_sess) | ||
842 | { | ||
843 | return; | ||
844 | }; | ||
845 | |||
846 | static void tcm_loop_stop_session( | ||
847 | struct se_session *se_sess, | ||
848 | int sess_sleep, | ||
849 | int conn_sleep) | ||
850 | { | ||
851 | return; | ||
852 | } | ||
853 | |||
854 | static void tcm_loop_fall_back_to_erl0(struct se_session *se_sess) | ||
855 | { | ||
856 | return; | ||
857 | } | ||
858 | |||
859 | static int tcm_loop_write_pending(struct se_cmd *se_cmd) | ||
860 | { | ||
861 | /* | ||
862 | * Since Linux/SCSI has already sent down a struct scsi_cmnd | ||
863 | * sc->sc_data_direction of DMA_TO_DEVICE with struct scatterlist array | ||
864 | * memory, and memory has already been mapped to struct se_cmd->t_mem_list | ||
865 | * format with transport_generic_map_mem_to_cmd(). | ||
866 | * | ||
867 | * We now tell TCM to add this WRITE CDB directly into the TCM storage | ||
868 | * object execution queue. | ||
869 | */ | ||
870 | transport_generic_process_write(se_cmd); | ||
871 | return 0; | ||
872 | } | ||
873 | |||
874 | static int tcm_loop_write_pending_status(struct se_cmd *se_cmd) | ||
875 | { | ||
876 | return 0; | ||
877 | } | ||
878 | |||
879 | static int tcm_loop_queue_data_in(struct se_cmd *se_cmd) | ||
880 | { | ||
881 | struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, | ||
882 | struct tcm_loop_cmd, tl_se_cmd); | ||
883 | struct scsi_cmnd *sc = tl_cmd->sc; | ||
884 | |||
885 | TL_CDB_DEBUG("tcm_loop_queue_data_in() called for scsi_cmnd: %p" | ||
886 | " cdb: 0x%02x\n", sc, sc->cmnd[0]); | ||
887 | |||
888 | sc->result = SAM_STAT_GOOD; | ||
889 | set_host_byte(sc, DID_OK); | ||
890 | sc->scsi_done(sc); | ||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | static int tcm_loop_queue_status(struct se_cmd *se_cmd) | ||
895 | { | ||
896 | struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, | ||
897 | struct tcm_loop_cmd, tl_se_cmd); | ||
898 | struct scsi_cmnd *sc = tl_cmd->sc; | ||
899 | |||
900 | TL_CDB_DEBUG("tcm_loop_queue_status() called for scsi_cmnd: %p" | ||
901 | " cdb: 0x%02x\n", sc, sc->cmnd[0]); | ||
902 | |||
903 | if (se_cmd->sense_buffer && | ||
904 | ((se_cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) || | ||
905 | (se_cmd->se_cmd_flags & SCF_EMULATED_TASK_SENSE))) { | ||
906 | |||
907 | memcpy((void *)sc->sense_buffer, (void *)se_cmd->sense_buffer, | ||
908 | SCSI_SENSE_BUFFERSIZE); | ||
909 | sc->result = SAM_STAT_CHECK_CONDITION; | ||
910 | set_driver_byte(sc, DRIVER_SENSE); | ||
911 | } else | ||
912 | sc->result = se_cmd->scsi_status; | ||
913 | |||
914 | set_host_byte(sc, DID_OK); | ||
915 | sc->scsi_done(sc); | ||
916 | return 0; | ||
917 | } | ||
918 | |||
919 | static int tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd) | ||
920 | { | ||
921 | struct se_tmr_req *se_tmr = se_cmd->se_tmr_req; | ||
922 | struct tcm_loop_tmr *tl_tmr = se_tmr->fabric_tmr_ptr; | ||
923 | /* | ||
924 | * The SCSI EH thread will be sleeping on se_tmr->tl_tmr_wait, go ahead | ||
925 | * and wake up the wait_queue_head_t in tcm_loop_device_reset() | ||
926 | */ | ||
927 | atomic_set(&tl_tmr->tmr_complete, 1); | ||
928 | wake_up(&tl_tmr->tl_tmr_wait); | ||
929 | return 0; | ||
930 | } | ||
931 | |||
932 | static u16 tcm_loop_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length) | ||
933 | { | ||
934 | return 0; | ||
935 | } | ||
936 | |||
937 | static u16 tcm_loop_get_fabric_sense_len(void) | ||
938 | { | ||
939 | return 0; | ||
940 | } | ||
941 | |||
942 | static u64 tcm_loop_pack_lun(unsigned int lun) | ||
943 | { | ||
944 | u64 result; | ||
945 | |||
946 | /* LSB of lun into byte 1 big-endian */ | ||
947 | result = ((lun & 0xff) << 8); | ||
948 | /* use flat space addressing method */ | ||
949 | result |= 0x40 | ((lun >> 8) & 0x3f); | ||
950 | |||
951 | return cpu_to_le64(result); | ||
952 | } | ||
953 | |||
954 | static char *tcm_loop_dump_proto_id(struct tcm_loop_hba *tl_hba) | ||
955 | { | ||
956 | switch (tl_hba->tl_proto_id) { | ||
957 | case SCSI_PROTOCOL_SAS: | ||
958 | return "SAS"; | ||
959 | case SCSI_PROTOCOL_FCP: | ||
960 | return "FCP"; | ||
961 | case SCSI_PROTOCOL_ISCSI: | ||
962 | return "iSCSI"; | ||
963 | default: | ||
964 | break; | ||
965 | } | ||
966 | |||
967 | return "Unknown"; | ||
968 | } | ||
969 | |||
970 | /* Start items for tcm_loop_port_cit */ | ||
971 | |||
972 | static int tcm_loop_port_link( | ||
973 | struct se_portal_group *se_tpg, | ||
974 | struct se_lun *lun) | ||
975 | { | ||
976 | struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, | ||
977 | struct tcm_loop_tpg, tl_se_tpg); | ||
978 | struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; | ||
979 | |||
980 | atomic_inc(&tl_tpg->tl_tpg_port_count); | ||
981 | smp_mb__after_atomic_inc(); | ||
982 | /* | ||
983 | * Add Linux/SCSI struct scsi_device by HCTL | ||
984 | */ | ||
985 | scsi_add_device(tl_hba->sh, 0, tl_tpg->tl_tpgt, lun->unpacked_lun); | ||
986 | |||
987 | printk(KERN_INFO "TCM_Loop_ConfigFS: Port Link Successful\n"); | ||
988 | return 0; | ||
989 | } | ||
990 | |||
991 | static void tcm_loop_port_unlink( | ||
992 | struct se_portal_group *se_tpg, | ||
993 | struct se_lun *se_lun) | ||
994 | { | ||
995 | struct scsi_device *sd; | ||
996 | struct tcm_loop_hba *tl_hba; | ||
997 | struct tcm_loop_tpg *tl_tpg; | ||
998 | |||
999 | tl_tpg = container_of(se_tpg, struct tcm_loop_tpg, tl_se_tpg); | ||
1000 | tl_hba = tl_tpg->tl_hba; | ||
1001 | |||
1002 | sd = scsi_device_lookup(tl_hba->sh, 0, tl_tpg->tl_tpgt, | ||
1003 | se_lun->unpacked_lun); | ||
1004 | if (!sd) { | ||
1005 | printk(KERN_ERR "Unable to locate struct scsi_device for %d:%d:" | ||
1006 | "%d\n", 0, tl_tpg->tl_tpgt, se_lun->unpacked_lun); | ||
1007 | return; | ||
1008 | } | ||
1009 | /* | ||
1010 | * Remove Linux/SCSI struct scsi_device by HCTL | ||
1011 | */ | ||
1012 | scsi_remove_device(sd); | ||
1013 | scsi_device_put(sd); | ||
1014 | |||
1015 | atomic_dec(&tl_tpg->tl_tpg_port_count); | ||
1016 | smp_mb__after_atomic_dec(); | ||
1017 | |||
1018 | printk(KERN_INFO "TCM_Loop_ConfigFS: Port Unlink Successful\n"); | ||
1019 | } | ||
1020 | |||
1021 | /* End items for tcm_loop_port_cit */ | ||
1022 | |||
1023 | /* Start items for tcm_loop_nexus_cit */ | ||
1024 | |||
1025 | static int tcm_loop_make_nexus( | ||
1026 | struct tcm_loop_tpg *tl_tpg, | ||
1027 | const char *name) | ||
1028 | { | ||
1029 | struct se_portal_group *se_tpg; | ||
1030 | struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; | ||
1031 | struct tcm_loop_nexus *tl_nexus; | ||
1032 | |||
1033 | if (tl_tpg->tl_hba->tl_nexus) { | ||
1034 | printk(KERN_INFO "tl_tpg->tl_hba->tl_nexus already exists\n"); | ||
1035 | return -EEXIST; | ||
1036 | } | ||
1037 | se_tpg = &tl_tpg->tl_se_tpg; | ||
1038 | |||
1039 | tl_nexus = kzalloc(sizeof(struct tcm_loop_nexus), GFP_KERNEL); | ||
1040 | if (!tl_nexus) { | ||
1041 | printk(KERN_ERR "Unable to allocate struct tcm_loop_nexus\n"); | ||
1042 | return -ENOMEM; | ||
1043 | } | ||
1044 | /* | ||
1045 | * Initialize the struct se_session pointer | ||
1046 | */ | ||
1047 | tl_nexus->se_sess = transport_init_session(); | ||
1048 | if (!tl_nexus->se_sess) | ||
1049 | goto out; | ||
1050 | /* | ||
1051 | * Since we are running in 'demo mode' this call with generate a | ||
1052 | * struct se_node_acl for the tcm_loop struct se_portal_group with the SCSI | ||
1053 | * Initiator port name of the passed configfs group 'name'. | ||
1054 | */ | ||
1055 | tl_nexus->se_sess->se_node_acl = core_tpg_check_initiator_node_acl( | ||
1056 | se_tpg, (unsigned char *)name); | ||
1057 | if (!tl_nexus->se_sess->se_node_acl) { | ||
1058 | transport_free_session(tl_nexus->se_sess); | ||
1059 | goto out; | ||
1060 | } | ||
1061 | /* | ||
1062 | * Now, register the SAS I_T Nexus as active with the call to | ||
1063 | * transport_register_session() | ||
1064 | */ | ||
1065 | __transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl, | ||
1066 | tl_nexus->se_sess, (void *)tl_nexus); | ||
1067 | tl_tpg->tl_hba->tl_nexus = tl_nexus; | ||
1068 | printk(KERN_INFO "TCM_Loop_ConfigFS: Established I_T Nexus to emulated" | ||
1069 | " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tl_hba), | ||
1070 | name); | ||
1071 | return 0; | ||
1072 | |||
1073 | out: | ||
1074 | kfree(tl_nexus); | ||
1075 | return -ENOMEM; | ||
1076 | } | ||
1077 | |||
1078 | static int tcm_loop_drop_nexus( | ||
1079 | struct tcm_loop_tpg *tpg) | ||
1080 | { | ||
1081 | struct se_session *se_sess; | ||
1082 | struct tcm_loop_nexus *tl_nexus; | ||
1083 | struct tcm_loop_hba *tl_hba = tpg->tl_hba; | ||
1084 | |||
1085 | tl_nexus = tpg->tl_hba->tl_nexus; | ||
1086 | if (!tl_nexus) | ||
1087 | return -ENODEV; | ||
1088 | |||
1089 | se_sess = tl_nexus->se_sess; | ||
1090 | if (!se_sess) | ||
1091 | return -ENODEV; | ||
1092 | |||
1093 | if (atomic_read(&tpg->tl_tpg_port_count)) { | ||
1094 | printk(KERN_ERR "Unable to remove TCM_Loop I_T Nexus with" | ||
1095 | " active TPG port count: %d\n", | ||
1096 | atomic_read(&tpg->tl_tpg_port_count)); | ||
1097 | return -EPERM; | ||
1098 | } | ||
1099 | |||
1100 | printk(KERN_INFO "TCM_Loop_ConfigFS: Removing I_T Nexus to emulated" | ||
1101 | " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tl_hba), | ||
1102 | tl_nexus->se_sess->se_node_acl->initiatorname); | ||
1103 | /* | ||
1104 | * Release the SCSI I_T Nexus to the emulated SAS Target Port | ||
1105 | */ | ||
1106 | transport_deregister_session(tl_nexus->se_sess); | ||
1107 | tpg->tl_hba->tl_nexus = NULL; | ||
1108 | kfree(tl_nexus); | ||
1109 | return 0; | ||
1110 | } | ||
1111 | |||
1112 | /* End items for tcm_loop_nexus_cit */ | ||
1113 | |||
1114 | static ssize_t tcm_loop_tpg_show_nexus( | ||
1115 | struct se_portal_group *se_tpg, | ||
1116 | char *page) | ||
1117 | { | ||
1118 | struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, | ||
1119 | struct tcm_loop_tpg, tl_se_tpg); | ||
1120 | struct tcm_loop_nexus *tl_nexus; | ||
1121 | ssize_t ret; | ||
1122 | |||
1123 | tl_nexus = tl_tpg->tl_hba->tl_nexus; | ||
1124 | if (!tl_nexus) | ||
1125 | return -ENODEV; | ||
1126 | |||
1127 | ret = snprintf(page, PAGE_SIZE, "%s\n", | ||
1128 | tl_nexus->se_sess->se_node_acl->initiatorname); | ||
1129 | |||
1130 | return ret; | ||
1131 | } | ||
1132 | |||
1133 | static ssize_t tcm_loop_tpg_store_nexus( | ||
1134 | struct se_portal_group *se_tpg, | ||
1135 | const char *page, | ||
1136 | size_t count) | ||
1137 | { | ||
1138 | struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, | ||
1139 | struct tcm_loop_tpg, tl_se_tpg); | ||
1140 | struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; | ||
1141 | unsigned char i_port[TL_WWN_ADDR_LEN], *ptr, *port_ptr; | ||
1142 | int ret; | ||
1143 | /* | ||
1144 | * Shutdown the active I_T nexus if 'NULL' is passed.. | ||
1145 | */ | ||
1146 | if (!strncmp(page, "NULL", 4)) { | ||
1147 | ret = tcm_loop_drop_nexus(tl_tpg); | ||
1148 | return (!ret) ? count : ret; | ||
1149 | } | ||
1150 | /* | ||
1151 | * Otherwise make sure the passed virtual Initiator port WWN matches | ||
1152 | * the fabric protocol_id set in tcm_loop_make_scsi_hba(), and call | ||
1153 | * tcm_loop_make_nexus() | ||
1154 | */ | ||
1155 | if (strlen(page) > TL_WWN_ADDR_LEN) { | ||
1156 | printk(KERN_ERR "Emulated NAA Sas Address: %s, exceeds" | ||
1157 | " max: %d\n", page, TL_WWN_ADDR_LEN); | ||
1158 | return -EINVAL; | ||
1159 | } | ||
1160 | snprintf(&i_port[0], TL_WWN_ADDR_LEN, "%s", page); | ||
1161 | |||
1162 | ptr = strstr(i_port, "naa."); | ||
1163 | if (ptr) { | ||
1164 | if (tl_hba->tl_proto_id != SCSI_PROTOCOL_SAS) { | ||
1165 | printk(KERN_ERR "Passed SAS Initiator Port %s does not" | ||
1166 | " match target port protoid: %s\n", i_port, | ||
1167 | tcm_loop_dump_proto_id(tl_hba)); | ||
1168 | return -EINVAL; | ||
1169 | } | ||
1170 | port_ptr = &i_port[0]; | ||
1171 | goto check_newline; | ||
1172 | } | ||
1173 | ptr = strstr(i_port, "fc."); | ||
1174 | if (ptr) { | ||
1175 | if (tl_hba->tl_proto_id != SCSI_PROTOCOL_FCP) { | ||
1176 | printk(KERN_ERR "Passed FCP Initiator Port %s does not" | ||
1177 | " match target port protoid: %s\n", i_port, | ||
1178 | tcm_loop_dump_proto_id(tl_hba)); | ||
1179 | return -EINVAL; | ||
1180 | } | ||
1181 | port_ptr = &i_port[3]; /* Skip over "fc." */ | ||
1182 | goto check_newline; | ||
1183 | } | ||
1184 | ptr = strstr(i_port, "iqn."); | ||
1185 | if (ptr) { | ||
1186 | if (tl_hba->tl_proto_id != SCSI_PROTOCOL_ISCSI) { | ||
1187 | printk(KERN_ERR "Passed iSCSI Initiator Port %s does not" | ||
1188 | " match target port protoid: %s\n", i_port, | ||
1189 | tcm_loop_dump_proto_id(tl_hba)); | ||
1190 | return -EINVAL; | ||
1191 | } | ||
1192 | port_ptr = &i_port[0]; | ||
1193 | goto check_newline; | ||
1194 | } | ||
1195 | printk(KERN_ERR "Unable to locate prefix for emulated Initiator Port:" | ||
1196 | " %s\n", i_port); | ||
1197 | return -EINVAL; | ||
1198 | /* | ||
1199 | * Clear any trailing newline for the NAA WWN | ||
1200 | */ | ||
1201 | check_newline: | ||
1202 | if (i_port[strlen(i_port)-1] == '\n') | ||
1203 | i_port[strlen(i_port)-1] = '\0'; | ||
1204 | |||
1205 | ret = tcm_loop_make_nexus(tl_tpg, port_ptr); | ||
1206 | if (ret < 0) | ||
1207 | return ret; | ||
1208 | |||
1209 | return count; | ||
1210 | } | ||
1211 | |||
1212 | TF_TPG_BASE_ATTR(tcm_loop, nexus, S_IRUGO | S_IWUSR); | ||
1213 | |||
1214 | static struct configfs_attribute *tcm_loop_tpg_attrs[] = { | ||
1215 | &tcm_loop_tpg_nexus.attr, | ||
1216 | NULL, | ||
1217 | }; | ||
1218 | |||
1219 | /* Start items for tcm_loop_naa_cit */ | ||
1220 | |||
1221 | struct se_portal_group *tcm_loop_make_naa_tpg( | ||
1222 | struct se_wwn *wwn, | ||
1223 | struct config_group *group, | ||
1224 | const char *name) | ||
1225 | { | ||
1226 | struct tcm_loop_hba *tl_hba = container_of(wwn, | ||
1227 | struct tcm_loop_hba, tl_hba_wwn); | ||
1228 | struct tcm_loop_tpg *tl_tpg; | ||
1229 | char *tpgt_str, *end_ptr; | ||
1230 | int ret; | ||
1231 | unsigned short int tpgt; | ||
1232 | |||
1233 | tpgt_str = strstr(name, "tpgt_"); | ||
1234 | if (!tpgt_str) { | ||
1235 | printk(KERN_ERR "Unable to locate \"tpgt_#\" directory" | ||
1236 | " group\n"); | ||
1237 | return ERR_PTR(-EINVAL); | ||
1238 | } | ||
1239 | tpgt_str += 5; /* Skip ahead of "tpgt_" */ | ||
1240 | tpgt = (unsigned short int) simple_strtoul(tpgt_str, &end_ptr, 0); | ||
1241 | |||
1242 | if (tpgt > TL_TPGS_PER_HBA) { | ||
1243 | printk(KERN_ERR "Passed tpgt: %hu exceeds TL_TPGS_PER_HBA:" | ||
1244 | " %u\n", tpgt, TL_TPGS_PER_HBA); | ||
1245 | return ERR_PTR(-EINVAL); | ||
1246 | } | ||
1247 | tl_tpg = &tl_hba->tl_hba_tpgs[tpgt]; | ||
1248 | tl_tpg->tl_hba = tl_hba; | ||
1249 | tl_tpg->tl_tpgt = tpgt; | ||
1250 | /* | ||
1251 | * Register the tl_tpg as a emulated SAS TCM Target Endpoint | ||
1252 | */ | ||
1253 | ret = core_tpg_register(&tcm_loop_fabric_configfs->tf_ops, | ||
1254 | wwn, &tl_tpg->tl_se_tpg, (void *)tl_tpg, | ||
1255 | TRANSPORT_TPG_TYPE_NORMAL); | ||
1256 | if (ret < 0) | ||
1257 | return ERR_PTR(-ENOMEM); | ||
1258 | |||
1259 | printk(KERN_INFO "TCM_Loop_ConfigFS: Allocated Emulated %s" | ||
1260 | " Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba), | ||
1261 | config_item_name(&wwn->wwn_group.cg_item), tpgt); | ||
1262 | |||
1263 | return &tl_tpg->tl_se_tpg; | ||
1264 | } | ||
1265 | |||
1266 | void tcm_loop_drop_naa_tpg( | ||
1267 | struct se_portal_group *se_tpg) | ||
1268 | { | ||
1269 | struct se_wwn *wwn = se_tpg->se_tpg_wwn; | ||
1270 | struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, | ||
1271 | struct tcm_loop_tpg, tl_se_tpg); | ||
1272 | struct tcm_loop_hba *tl_hba; | ||
1273 | unsigned short tpgt; | ||
1274 | |||
1275 | tl_hba = tl_tpg->tl_hba; | ||
1276 | tpgt = tl_tpg->tl_tpgt; | ||
1277 | /* | ||
1278 | * Release the I_T Nexus for the Virtual SAS link if present | ||
1279 | */ | ||
1280 | tcm_loop_drop_nexus(tl_tpg); | ||
1281 | /* | ||
1282 | * Deregister the tl_tpg as a emulated SAS TCM Target Endpoint | ||
1283 | */ | ||
1284 | core_tpg_deregister(se_tpg); | ||
1285 | |||
1286 | printk(KERN_INFO "TCM_Loop_ConfigFS: Deallocated Emulated %s" | ||
1287 | " Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba), | ||
1288 | config_item_name(&wwn->wwn_group.cg_item), tpgt); | ||
1289 | } | ||
1290 | |||
1291 | /* End items for tcm_loop_naa_cit */ | ||
1292 | |||
1293 | /* Start items for tcm_loop_cit */ | ||
1294 | |||
1295 | struct se_wwn *tcm_loop_make_scsi_hba( | ||
1296 | struct target_fabric_configfs *tf, | ||
1297 | struct config_group *group, | ||
1298 | const char *name) | ||
1299 | { | ||
1300 | struct tcm_loop_hba *tl_hba; | ||
1301 | struct Scsi_Host *sh; | ||
1302 | char *ptr; | ||
1303 | int ret, off = 0; | ||
1304 | |||
1305 | tl_hba = kzalloc(sizeof(struct tcm_loop_hba), GFP_KERNEL); | ||
1306 | if (!tl_hba) { | ||
1307 | printk(KERN_ERR "Unable to allocate struct tcm_loop_hba\n"); | ||
1308 | return ERR_PTR(-ENOMEM); | ||
1309 | } | ||
1310 | /* | ||
1311 | * Determine the emulated Protocol Identifier and Target Port Name | ||
1312 | * based on the incoming configfs directory name. | ||
1313 | */ | ||
1314 | ptr = strstr(name, "naa."); | ||
1315 | if (ptr) { | ||
1316 | tl_hba->tl_proto_id = SCSI_PROTOCOL_SAS; | ||
1317 | goto check_len; | ||
1318 | } | ||
1319 | ptr = strstr(name, "fc."); | ||
1320 | if (ptr) { | ||
1321 | tl_hba->tl_proto_id = SCSI_PROTOCOL_FCP; | ||
1322 | off = 3; /* Skip over "fc." */ | ||
1323 | goto check_len; | ||
1324 | } | ||
1325 | ptr = strstr(name, "iqn."); | ||
1326 | if (ptr) { | ||
1327 | tl_hba->tl_proto_id = SCSI_PROTOCOL_ISCSI; | ||
1328 | goto check_len; | ||
1329 | } | ||
1330 | |||
1331 | printk(KERN_ERR "Unable to locate prefix for emulated Target Port:" | ||
1332 | " %s\n", name); | ||
1333 | return ERR_PTR(-EINVAL); | ||
1334 | |||
1335 | check_len: | ||
1336 | if (strlen(name) > TL_WWN_ADDR_LEN) { | ||
1337 | printk(KERN_ERR "Emulated NAA %s Address: %s, exceeds" | ||
1338 | " max: %d\n", name, tcm_loop_dump_proto_id(tl_hba), | ||
1339 | TL_WWN_ADDR_LEN); | ||
1340 | kfree(tl_hba); | ||
1341 | return ERR_PTR(-EINVAL); | ||
1342 | } | ||
1343 | snprintf(&tl_hba->tl_wwn_address[0], TL_WWN_ADDR_LEN, "%s", &name[off]); | ||
1344 | |||
1345 | /* | ||
1346 | * Call device_register(tl_hba->dev) to register the emulated | ||
1347 | * Linux/SCSI LLD of type struct Scsi_Host at tl_hba->sh after | ||
1348 | * device_register() callbacks in tcm_loop_driver_probe() | ||
1349 | */ | ||
1350 | ret = tcm_loop_setup_hba_bus(tl_hba, tcm_loop_hba_no_cnt); | ||
1351 | if (ret) | ||
1352 | goto out; | ||
1353 | |||
1354 | sh = tl_hba->sh; | ||
1355 | tcm_loop_hba_no_cnt++; | ||
1356 | printk(KERN_INFO "TCM_Loop_ConfigFS: Allocated emulated Target" | ||
1357 | " %s Address: %s at Linux/SCSI Host ID: %d\n", | ||
1358 | tcm_loop_dump_proto_id(tl_hba), name, sh->host_no); | ||
1359 | |||
1360 | return &tl_hba->tl_hba_wwn; | ||
1361 | out: | ||
1362 | kfree(tl_hba); | ||
1363 | return ERR_PTR(ret); | ||
1364 | } | ||
1365 | |||
1366 | void tcm_loop_drop_scsi_hba( | ||
1367 | struct se_wwn *wwn) | ||
1368 | { | ||
1369 | struct tcm_loop_hba *tl_hba = container_of(wwn, | ||
1370 | struct tcm_loop_hba, tl_hba_wwn); | ||
1371 | int host_no = tl_hba->sh->host_no; | ||
1372 | /* | ||
1373 | * Call device_unregister() on the original tl_hba->dev. | ||
1374 | * tcm_loop_fabric_scsi.c:tcm_loop_release_adapter() will | ||
1375 | * release *tl_hba; | ||
1376 | */ | ||
1377 | device_unregister(&tl_hba->dev); | ||
1378 | |||
1379 | printk(KERN_INFO "TCM_Loop_ConfigFS: Deallocated emulated Target" | ||
1380 | " SAS Address: %s at Linux/SCSI Host ID: %d\n", | ||
1381 | config_item_name(&wwn->wwn_group.cg_item), host_no); | ||
1382 | } | ||
1383 | |||
1384 | /* Start items for tcm_loop_cit */ | ||
1385 | static ssize_t tcm_loop_wwn_show_attr_version( | ||
1386 | struct target_fabric_configfs *tf, | ||
1387 | char *page) | ||
1388 | { | ||
1389 | return sprintf(page, "TCM Loopback Fabric module %s\n", TCM_LOOP_VERSION); | ||
1390 | } | ||
1391 | |||
1392 | TF_WWN_ATTR_RO(tcm_loop, version); | ||
1393 | |||
1394 | static struct configfs_attribute *tcm_loop_wwn_attrs[] = { | ||
1395 | &tcm_loop_wwn_version.attr, | ||
1396 | NULL, | ||
1397 | }; | ||
1398 | |||
1399 | /* End items for tcm_loop_cit */ | ||
1400 | |||
1401 | static int tcm_loop_register_configfs(void) | ||
1402 | { | ||
1403 | struct target_fabric_configfs *fabric; | ||
1404 | struct config_group *tf_cg; | ||
1405 | int ret; | ||
1406 | /* | ||
1407 | * Set the TCM Loop HBA counter to zero | ||
1408 | */ | ||
1409 | tcm_loop_hba_no_cnt = 0; | ||
1410 | /* | ||
1411 | * Register the top level struct config_item_type with TCM core | ||
1412 | */ | ||
1413 | fabric = target_fabric_configfs_init(THIS_MODULE, "loopback"); | ||
1414 | if (!fabric) { | ||
1415 | printk(KERN_ERR "tcm_loop_register_configfs() failed!\n"); | ||
1416 | return -1; | ||
1417 | } | ||
1418 | /* | ||
1419 | * Setup the fabric API of function pointers used by target_core_mod | ||
1420 | */ | ||
1421 | fabric->tf_ops.get_fabric_name = &tcm_loop_get_fabric_name; | ||
1422 | fabric->tf_ops.get_fabric_proto_ident = &tcm_loop_get_fabric_proto_ident; | ||
1423 | fabric->tf_ops.tpg_get_wwn = &tcm_loop_get_endpoint_wwn; | ||
1424 | fabric->tf_ops.tpg_get_tag = &tcm_loop_get_tag; | ||
1425 | fabric->tf_ops.tpg_get_default_depth = &tcm_loop_get_default_depth; | ||
1426 | fabric->tf_ops.tpg_get_pr_transport_id = &tcm_loop_get_pr_transport_id; | ||
1427 | fabric->tf_ops.tpg_get_pr_transport_id_len = | ||
1428 | &tcm_loop_get_pr_transport_id_len; | ||
1429 | fabric->tf_ops.tpg_parse_pr_out_transport_id = | ||
1430 | &tcm_loop_parse_pr_out_transport_id; | ||
1431 | fabric->tf_ops.tpg_check_demo_mode = &tcm_loop_check_demo_mode; | ||
1432 | fabric->tf_ops.tpg_check_demo_mode_cache = | ||
1433 | &tcm_loop_check_demo_mode_cache; | ||
1434 | fabric->tf_ops.tpg_check_demo_mode_write_protect = | ||
1435 | &tcm_loop_check_demo_mode_write_protect; | ||
1436 | fabric->tf_ops.tpg_check_prod_mode_write_protect = | ||
1437 | &tcm_loop_check_prod_mode_write_protect; | ||
1438 | /* | ||
1439 | * The TCM loopback fabric module runs in demo-mode to a local | ||
1440 | * virtual SCSI device, so fabric dependent initator ACLs are | ||
1441 | * not required. | ||
1442 | */ | ||
1443 | fabric->tf_ops.tpg_alloc_fabric_acl = &tcm_loop_tpg_alloc_fabric_acl; | ||
1444 | fabric->tf_ops.tpg_release_fabric_acl = | ||
1445 | &tcm_loop_tpg_release_fabric_acl; | ||
1446 | fabric->tf_ops.tpg_get_inst_index = &tcm_loop_get_inst_index; | ||
1447 | /* | ||
1448 | * Since tcm_loop is mapping physical memory from Linux/SCSI | ||
1449 | * struct scatterlist arrays for each struct scsi_cmnd I/O, | ||
1450 | * we do not need TCM to allocate a iovec array for | ||
1451 | * virtual memory address mappings | ||
1452 | */ | ||
1453 | fabric->tf_ops.alloc_cmd_iovecs = NULL; | ||
1454 | /* | ||
1455 | * Used for setting up remaining TCM resources in process context | ||
1456 | */ | ||
1457 | fabric->tf_ops.new_cmd_map = &tcm_loop_new_cmd_map; | ||
1458 | fabric->tf_ops.check_stop_free = &tcm_loop_check_stop_free; | ||
1459 | fabric->tf_ops.release_cmd_to_pool = &tcm_loop_deallocate_core_cmd; | ||
1460 | fabric->tf_ops.release_cmd_direct = &tcm_loop_deallocate_core_cmd; | ||
1461 | fabric->tf_ops.shutdown_session = &tcm_loop_shutdown_session; | ||
1462 | fabric->tf_ops.close_session = &tcm_loop_close_session; | ||
1463 | fabric->tf_ops.stop_session = &tcm_loop_stop_session; | ||
1464 | fabric->tf_ops.fall_back_to_erl0 = &tcm_loop_fall_back_to_erl0; | ||
1465 | fabric->tf_ops.sess_logged_in = &tcm_loop_sess_logged_in; | ||
1466 | fabric->tf_ops.sess_get_index = &tcm_loop_sess_get_index; | ||
1467 | fabric->tf_ops.sess_get_initiator_sid = NULL; | ||
1468 | fabric->tf_ops.write_pending = &tcm_loop_write_pending; | ||
1469 | fabric->tf_ops.write_pending_status = &tcm_loop_write_pending_status; | ||
1470 | /* | ||
1471 | * Not used for TCM loopback | ||
1472 | */ | ||
1473 | fabric->tf_ops.set_default_node_attributes = | ||
1474 | &tcm_loop_set_default_node_attributes; | ||
1475 | fabric->tf_ops.get_task_tag = &tcm_loop_get_task_tag; | ||
1476 | fabric->tf_ops.get_cmd_state = &tcm_loop_get_cmd_state; | ||
1477 | fabric->tf_ops.new_cmd_failure = &tcm_loop_new_cmd_failure; | ||
1478 | fabric->tf_ops.queue_data_in = &tcm_loop_queue_data_in; | ||
1479 | fabric->tf_ops.queue_status = &tcm_loop_queue_status; | ||
1480 | fabric->tf_ops.queue_tm_rsp = &tcm_loop_queue_tm_rsp; | ||
1481 | fabric->tf_ops.set_fabric_sense_len = &tcm_loop_set_fabric_sense_len; | ||
1482 | fabric->tf_ops.get_fabric_sense_len = &tcm_loop_get_fabric_sense_len; | ||
1483 | fabric->tf_ops.is_state_remove = &tcm_loop_is_state_remove; | ||
1484 | fabric->tf_ops.pack_lun = &tcm_loop_pack_lun; | ||
1485 | |||
1486 | tf_cg = &fabric->tf_group; | ||
1487 | /* | ||
1488 | * Setup function pointers for generic logic in target_core_fabric_configfs.c | ||
1489 | */ | ||
1490 | fabric->tf_ops.fabric_make_wwn = &tcm_loop_make_scsi_hba; | ||
1491 | fabric->tf_ops.fabric_drop_wwn = &tcm_loop_drop_scsi_hba; | ||
1492 | fabric->tf_ops.fabric_make_tpg = &tcm_loop_make_naa_tpg; | ||
1493 | fabric->tf_ops.fabric_drop_tpg = &tcm_loop_drop_naa_tpg; | ||
1494 | /* | ||
1495 | * fabric_post_link() and fabric_pre_unlink() are used for | ||
1496 | * registration and release of TCM Loop Virtual SCSI LUNs. | ||
1497 | */ | ||
1498 | fabric->tf_ops.fabric_post_link = &tcm_loop_port_link; | ||
1499 | fabric->tf_ops.fabric_pre_unlink = &tcm_loop_port_unlink; | ||
1500 | fabric->tf_ops.fabric_make_np = NULL; | ||
1501 | fabric->tf_ops.fabric_drop_np = NULL; | ||
1502 | /* | ||
1503 | * Setup default attribute lists for various fabric->tf_cit_tmpl | ||
1504 | */ | ||
1505 | TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = tcm_loop_wwn_attrs; | ||
1506 | TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = tcm_loop_tpg_attrs; | ||
1507 | TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL; | ||
1508 | TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL; | ||
1509 | TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL; | ||
1510 | /* | ||
1511 | * Once fabric->tf_ops has been setup, now register the fabric for | ||
1512 | * use within TCM | ||
1513 | */ | ||
1514 | ret = target_fabric_configfs_register(fabric); | ||
1515 | if (ret < 0) { | ||
1516 | printk(KERN_ERR "target_fabric_configfs_register() for" | ||
1517 | " TCM_Loop failed!\n"); | ||
1518 | target_fabric_configfs_free(fabric); | ||
1519 | return -1; | ||
1520 | } | ||
1521 | /* | ||
1522 | * Setup our local pointer to *fabric. | ||
1523 | */ | ||
1524 | tcm_loop_fabric_configfs = fabric; | ||
1525 | printk(KERN_INFO "TCM_LOOP[0] - Set fabric ->" | ||
1526 | " tcm_loop_fabric_configfs\n"); | ||
1527 | return 0; | ||
1528 | } | ||
1529 | |||
1530 | static void tcm_loop_deregister_configfs(void) | ||
1531 | { | ||
1532 | if (!tcm_loop_fabric_configfs) | ||
1533 | return; | ||
1534 | |||
1535 | target_fabric_configfs_deregister(tcm_loop_fabric_configfs); | ||
1536 | tcm_loop_fabric_configfs = NULL; | ||
1537 | printk(KERN_INFO "TCM_LOOP[0] - Cleared" | ||
1538 | " tcm_loop_fabric_configfs\n"); | ||
1539 | } | ||
1540 | |||
1541 | static int __init tcm_loop_fabric_init(void) | ||
1542 | { | ||
1543 | int ret; | ||
1544 | |||
1545 | tcm_loop_cmd_cache = kmem_cache_create("tcm_loop_cmd_cache", | ||
1546 | sizeof(struct tcm_loop_cmd), | ||
1547 | __alignof__(struct tcm_loop_cmd), | ||
1548 | 0, NULL); | ||
1549 | if (!tcm_loop_cmd_cache) { | ||
1550 | printk(KERN_ERR "kmem_cache_create() for" | ||
1551 | " tcm_loop_cmd_cache failed\n"); | ||
1552 | return -ENOMEM; | ||
1553 | } | ||
1554 | |||
1555 | ret = tcm_loop_alloc_core_bus(); | ||
1556 | if (ret) | ||
1557 | return ret; | ||
1558 | |||
1559 | ret = tcm_loop_register_configfs(); | ||
1560 | if (ret) { | ||
1561 | tcm_loop_release_core_bus(); | ||
1562 | return ret; | ||
1563 | } | ||
1564 | |||
1565 | return 0; | ||
1566 | } | ||
1567 | |||
1568 | static void __exit tcm_loop_fabric_exit(void) | ||
1569 | { | ||
1570 | tcm_loop_deregister_configfs(); | ||
1571 | tcm_loop_release_core_bus(); | ||
1572 | kmem_cache_destroy(tcm_loop_cmd_cache); | ||
1573 | } | ||
1574 | |||
1575 | MODULE_DESCRIPTION("TCM loopback virtual Linux/SCSI fabric module"); | ||
1576 | MODULE_AUTHOR("Nicholas A. Bellinger <nab@risingtidesystems.com>"); | ||
1577 | MODULE_LICENSE("GPL"); | ||
1578 | module_init(tcm_loop_fabric_init); | ||
1579 | module_exit(tcm_loop_fabric_exit); | ||
diff --git a/drivers/target/loopback/tcm_loop.h b/drivers/target/loopback/tcm_loop.h new file mode 100644 index 000000000000..7e9f7ab45548 --- /dev/null +++ b/drivers/target/loopback/tcm_loop.h | |||
@@ -0,0 +1,77 @@ | |||
1 | #define TCM_LOOP_VERSION "v2.1-rc1" | ||
2 | #define TL_WWN_ADDR_LEN 256 | ||
3 | #define TL_TPGS_PER_HBA 32 | ||
4 | /* | ||
5 | * Defaults for struct scsi_host_template tcm_loop_driver_template | ||
6 | * | ||
7 | * We use large can_queue and cmd_per_lun here and let TCM enforce | ||
8 | * the underlying se_device_t->queue_depth. | ||
9 | */ | ||
10 | #define TL_SCSI_CAN_QUEUE 1024 | ||
11 | #define TL_SCSI_CMD_PER_LUN 1024 | ||
12 | #define TL_SCSI_MAX_SECTORS 1024 | ||
13 | #define TL_SCSI_SG_TABLESIZE 256 | ||
14 | /* | ||
15 | * Used in tcm_loop_driver_probe() for struct Scsi_Host->max_cmd_len | ||
16 | */ | ||
17 | #define TL_SCSI_MAX_CMD_LEN 32 | ||
18 | |||
19 | #ifdef CONFIG_LOOPBACK_TARGET_CDB_DEBUG | ||
20 | # define TL_CDB_DEBUG(x...) printk(KERN_INFO x) | ||
21 | #else | ||
22 | # define TL_CDB_DEBUG(x...) | ||
23 | #endif | ||
24 | |||
25 | struct tcm_loop_cmd { | ||
26 | /* State of Linux/SCSI CDB+Data descriptor */ | ||
27 | u32 sc_cmd_state; | ||
28 | /* Pointer to the CDB+Data descriptor from Linux/SCSI subsystem */ | ||
29 | struct scsi_cmnd *sc; | ||
30 | struct list_head *tl_cmd_list; | ||
31 | /* The TCM I/O descriptor that is accessed via container_of() */ | ||
32 | struct se_cmd tl_se_cmd; | ||
33 | /* Sense buffer that will be mapped into outgoing status */ | ||
34 | unsigned char tl_sense_buf[TRANSPORT_SENSE_BUFFER]; | ||
35 | }; | ||
36 | |||
37 | struct tcm_loop_tmr { | ||
38 | atomic_t tmr_complete; | ||
39 | wait_queue_head_t tl_tmr_wait; | ||
40 | }; | ||
41 | |||
42 | struct tcm_loop_nexus { | ||
43 | int it_nexus_active; | ||
44 | /* | ||
45 | * Pointer to Linux/SCSI HBA from linux/include/scsi_host.h | ||
46 | */ | ||
47 | struct scsi_host *sh; | ||
48 | /* | ||
49 | * Pointer to TCM session for I_T Nexus | ||
50 | */ | ||
51 | struct se_session *se_sess; | ||
52 | }; | ||
53 | |||
54 | struct tcm_loop_nacl { | ||
55 | struct se_node_acl se_node_acl; | ||
56 | }; | ||
57 | |||
58 | struct tcm_loop_tpg { | ||
59 | unsigned short tl_tpgt; | ||
60 | atomic_t tl_tpg_port_count; | ||
61 | struct se_portal_group tl_se_tpg; | ||
62 | struct tcm_loop_hba *tl_hba; | ||
63 | }; | ||
64 | |||
65 | struct tcm_loop_hba { | ||
66 | u8 tl_proto_id; | ||
67 | unsigned char tl_wwn_address[TL_WWN_ADDR_LEN]; | ||
68 | struct se_hba_s *se_hba; | ||
69 | struct se_lun *tl_hba_lun; | ||
70 | struct se_port *tl_hba_lun_sep; | ||
71 | struct se_device_s *se_dev_hba_ptr; | ||
72 | struct tcm_loop_nexus *tl_nexus; | ||
73 | struct device dev; | ||
74 | struct Scsi_Host *sh; | ||
75 | struct tcm_loop_tpg tl_hba_tpgs[TL_TPGS_PER_HBA]; | ||
76 | struct se_wwn tl_hba_wwn; | ||
77 | }; | ||
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index caf8dc18ee0a..a5f44a6e6e1d 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c | |||
@@ -3,8 +3,8 @@ | |||
3 | * | 3 | * |
4 | * This file contains ConfigFS logic for the Generic Target Engine project. | 4 | * This file contains ConfigFS logic for the Generic Target Engine project. |
5 | * | 5 | * |
6 | * Copyright (c) 2008-2010 Rising Tide Systems | 6 | * Copyright (c) 2008-2011 Rising Tide Systems |
7 | * Copyright (c) 2008-2010 Linux-iSCSI.org | 7 | * Copyright (c) 2008-2011 Linux-iSCSI.org |
8 | * | 8 | * |
9 | * Nicholas A. Bellinger <nab@kernel.org> | 9 | * Nicholas A. Bellinger <nab@kernel.org> |
10 | * | 10 | * |
@@ -50,6 +50,7 @@ | |||
50 | #include "target_core_hba.h" | 50 | #include "target_core_hba.h" |
51 | #include "target_core_pr.h" | 51 | #include "target_core_pr.h" |
52 | #include "target_core_rd.h" | 52 | #include "target_core_rd.h" |
53 | #include "target_core_stat.h" | ||
53 | 54 | ||
54 | static struct list_head g_tf_list; | 55 | static struct list_head g_tf_list; |
55 | static struct mutex g_tf_lock; | 56 | static struct mutex g_tf_lock; |
@@ -1451,8 +1452,8 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( | |||
1451 | size_t count) | 1452 | size_t count) |
1452 | { | 1453 | { |
1453 | struct se_device *dev; | 1454 | struct se_device *dev; |
1454 | unsigned char *i_fabric, *t_fabric, *i_port = NULL, *t_port = NULL; | 1455 | unsigned char *i_fabric = NULL, *i_port = NULL, *isid = NULL; |
1455 | unsigned char *isid = NULL; | 1456 | unsigned char *t_fabric = NULL, *t_port = NULL; |
1456 | char *orig, *ptr, *arg_p, *opts; | 1457 | char *orig, *ptr, *arg_p, *opts; |
1457 | substring_t args[MAX_OPT_ARGS]; | 1458 | substring_t args[MAX_OPT_ARGS]; |
1458 | unsigned long long tmp_ll; | 1459 | unsigned long long tmp_ll; |
@@ -1488,9 +1489,17 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( | |||
1488 | switch (token) { | 1489 | switch (token) { |
1489 | case Opt_initiator_fabric: | 1490 | case Opt_initiator_fabric: |
1490 | i_fabric = match_strdup(&args[0]); | 1491 | i_fabric = match_strdup(&args[0]); |
1492 | if (!i_fabric) { | ||
1493 | ret = -ENOMEM; | ||
1494 | goto out; | ||
1495 | } | ||
1491 | break; | 1496 | break; |
1492 | case Opt_initiator_node: | 1497 | case Opt_initiator_node: |
1493 | i_port = match_strdup(&args[0]); | 1498 | i_port = match_strdup(&args[0]); |
1499 | if (!i_port) { | ||
1500 | ret = -ENOMEM; | ||
1501 | goto out; | ||
1502 | } | ||
1494 | if (strlen(i_port) > PR_APTPL_MAX_IPORT_LEN) { | 1503 | if (strlen(i_port) > PR_APTPL_MAX_IPORT_LEN) { |
1495 | printk(KERN_ERR "APTPL metadata initiator_node=" | 1504 | printk(KERN_ERR "APTPL metadata initiator_node=" |
1496 | " exceeds PR_APTPL_MAX_IPORT_LEN: %d\n", | 1505 | " exceeds PR_APTPL_MAX_IPORT_LEN: %d\n", |
@@ -1501,6 +1510,10 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( | |||
1501 | break; | 1510 | break; |
1502 | case Opt_initiator_sid: | 1511 | case Opt_initiator_sid: |
1503 | isid = match_strdup(&args[0]); | 1512 | isid = match_strdup(&args[0]); |
1513 | if (!isid) { | ||
1514 | ret = -ENOMEM; | ||
1515 | goto out; | ||
1516 | } | ||
1504 | if (strlen(isid) > PR_REG_ISID_LEN) { | 1517 | if (strlen(isid) > PR_REG_ISID_LEN) { |
1505 | printk(KERN_ERR "APTPL metadata initiator_isid" | 1518 | printk(KERN_ERR "APTPL metadata initiator_isid" |
1506 | "= exceeds PR_REG_ISID_LEN: %d\n", | 1519 | "= exceeds PR_REG_ISID_LEN: %d\n", |
@@ -1511,6 +1524,10 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( | |||
1511 | break; | 1524 | break; |
1512 | case Opt_sa_res_key: | 1525 | case Opt_sa_res_key: |
1513 | arg_p = match_strdup(&args[0]); | 1526 | arg_p = match_strdup(&args[0]); |
1527 | if (!arg_p) { | ||
1528 | ret = -ENOMEM; | ||
1529 | goto out; | ||
1530 | } | ||
1514 | ret = strict_strtoull(arg_p, 0, &tmp_ll); | 1531 | ret = strict_strtoull(arg_p, 0, &tmp_ll); |
1515 | if (ret < 0) { | 1532 | if (ret < 0) { |
1516 | printk(KERN_ERR "strict_strtoull() failed for" | 1533 | printk(KERN_ERR "strict_strtoull() failed for" |
@@ -1547,9 +1564,17 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( | |||
1547 | */ | 1564 | */ |
1548 | case Opt_target_fabric: | 1565 | case Opt_target_fabric: |
1549 | t_fabric = match_strdup(&args[0]); | 1566 | t_fabric = match_strdup(&args[0]); |
1567 | if (!t_fabric) { | ||
1568 | ret = -ENOMEM; | ||
1569 | goto out; | ||
1570 | } | ||
1550 | break; | 1571 | break; |
1551 | case Opt_target_node: | 1572 | case Opt_target_node: |
1552 | t_port = match_strdup(&args[0]); | 1573 | t_port = match_strdup(&args[0]); |
1574 | if (!t_port) { | ||
1575 | ret = -ENOMEM; | ||
1576 | goto out; | ||
1577 | } | ||
1553 | if (strlen(t_port) > PR_APTPL_MAX_TPORT_LEN) { | 1578 | if (strlen(t_port) > PR_APTPL_MAX_TPORT_LEN) { |
1554 | printk(KERN_ERR "APTPL metadata target_node=" | 1579 | printk(KERN_ERR "APTPL metadata target_node=" |
1555 | " exceeds PR_APTPL_MAX_TPORT_LEN: %d\n", | 1580 | " exceeds PR_APTPL_MAX_TPORT_LEN: %d\n", |
@@ -1592,6 +1617,11 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( | |||
1592 | i_port, isid, mapped_lun, t_port, tpgt, target_lun, | 1617 | i_port, isid, mapped_lun, t_port, tpgt, target_lun, |
1593 | res_holder, all_tg_pt, type); | 1618 | res_holder, all_tg_pt, type); |
1594 | out: | 1619 | out: |
1620 | kfree(i_fabric); | ||
1621 | kfree(i_port); | ||
1622 | kfree(isid); | ||
1623 | kfree(t_fabric); | ||
1624 | kfree(t_port); | ||
1595 | kfree(orig); | 1625 | kfree(orig); |
1596 | return (ret == 0) ? count : ret; | 1626 | return (ret == 0) ? count : ret; |
1597 | } | 1627 | } |
@@ -1798,7 +1828,9 @@ static ssize_t target_core_store_dev_enable( | |||
1798 | return -EINVAL; | 1828 | return -EINVAL; |
1799 | 1829 | ||
1800 | dev = t->create_virtdevice(hba, se_dev, se_dev->se_dev_su_ptr); | 1830 | dev = t->create_virtdevice(hba, se_dev, se_dev->se_dev_su_ptr); |
1801 | if (!(dev) || IS_ERR(dev)) | 1831 | if (IS_ERR(dev)) |
1832 | return PTR_ERR(dev); | ||
1833 | else if (!dev) | ||
1802 | return -EINVAL; | 1834 | return -EINVAL; |
1803 | 1835 | ||
1804 | se_dev->se_dev_ptr = dev; | 1836 | se_dev->se_dev_ptr = dev; |
@@ -2678,6 +2710,34 @@ static struct config_item_type target_core_alua_cit = { | |||
2678 | 2710 | ||
2679 | /* End functions for struct config_item_type target_core_alua_cit */ | 2711 | /* End functions for struct config_item_type target_core_alua_cit */ |
2680 | 2712 | ||
2713 | /* Start functions for struct config_item_type target_core_stat_cit */ | ||
2714 | |||
2715 | static struct config_group *target_core_stat_mkdir( | ||
2716 | struct config_group *group, | ||
2717 | const char *name) | ||
2718 | { | ||
2719 | return ERR_PTR(-ENOSYS); | ||
2720 | } | ||
2721 | |||
2722 | static void target_core_stat_rmdir( | ||
2723 | struct config_group *group, | ||
2724 | struct config_item *item) | ||
2725 | { | ||
2726 | return; | ||
2727 | } | ||
2728 | |||
2729 | static struct configfs_group_operations target_core_stat_group_ops = { | ||
2730 | .make_group = &target_core_stat_mkdir, | ||
2731 | .drop_item = &target_core_stat_rmdir, | ||
2732 | }; | ||
2733 | |||
2734 | static struct config_item_type target_core_stat_cit = { | ||
2735 | .ct_group_ops = &target_core_stat_group_ops, | ||
2736 | .ct_owner = THIS_MODULE, | ||
2737 | }; | ||
2738 | |||
2739 | /* End functions for struct config_item_type target_core_stat_cit */ | ||
2740 | |||
2681 | /* Start functions for struct config_item_type target_core_hba_cit */ | 2741 | /* Start functions for struct config_item_type target_core_hba_cit */ |
2682 | 2742 | ||
2683 | static struct config_group *target_core_make_subdev( | 2743 | static struct config_group *target_core_make_subdev( |
@@ -2690,10 +2750,12 @@ static struct config_group *target_core_make_subdev( | |||
2690 | struct config_item *hba_ci = &group->cg_item; | 2750 | struct config_item *hba_ci = &group->cg_item; |
2691 | struct se_hba *hba = item_to_hba(hba_ci); | 2751 | struct se_hba *hba = item_to_hba(hba_ci); |
2692 | struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL; | 2752 | struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL; |
2753 | struct config_group *dev_stat_grp = NULL; | ||
2754 | int errno = -ENOMEM, ret; | ||
2693 | 2755 | ||
2694 | if (mutex_lock_interruptible(&hba->hba_access_mutex)) | 2756 | ret = mutex_lock_interruptible(&hba->hba_access_mutex); |
2695 | return NULL; | 2757 | if (ret) |
2696 | 2758 | return ERR_PTR(ret); | |
2697 | /* | 2759 | /* |
2698 | * Locate the struct se_subsystem_api from parent's struct se_hba. | 2760 | * Locate the struct se_subsystem_api from parent's struct se_hba. |
2699 | */ | 2761 | */ |
@@ -2723,7 +2785,7 @@ static struct config_group *target_core_make_subdev( | |||
2723 | se_dev->se_dev_hba = hba; | 2785 | se_dev->se_dev_hba = hba; |
2724 | dev_cg = &se_dev->se_dev_group; | 2786 | dev_cg = &se_dev->se_dev_group; |
2725 | 2787 | ||
2726 | dev_cg->default_groups = kzalloc(sizeof(struct config_group) * 6, | 2788 | dev_cg->default_groups = kzalloc(sizeof(struct config_group) * 7, |
2727 | GFP_KERNEL); | 2789 | GFP_KERNEL); |
2728 | if (!(dev_cg->default_groups)) | 2790 | if (!(dev_cg->default_groups)) |
2729 | goto out; | 2791 | goto out; |
@@ -2755,13 +2817,17 @@ static struct config_group *target_core_make_subdev( | |||
2755 | &target_core_dev_wwn_cit); | 2817 | &target_core_dev_wwn_cit); |
2756 | config_group_init_type_name(&se_dev->t10_alua.alua_tg_pt_gps_group, | 2818 | config_group_init_type_name(&se_dev->t10_alua.alua_tg_pt_gps_group, |
2757 | "alua", &target_core_alua_tg_pt_gps_cit); | 2819 | "alua", &target_core_alua_tg_pt_gps_cit); |
2820 | config_group_init_type_name(&se_dev->dev_stat_grps.stat_group, | ||
2821 | "statistics", &target_core_stat_cit); | ||
2822 | |||
2758 | dev_cg->default_groups[0] = &se_dev->se_dev_attrib.da_group; | 2823 | dev_cg->default_groups[0] = &se_dev->se_dev_attrib.da_group; |
2759 | dev_cg->default_groups[1] = &se_dev->se_dev_pr_group; | 2824 | dev_cg->default_groups[1] = &se_dev->se_dev_pr_group; |
2760 | dev_cg->default_groups[2] = &se_dev->t10_wwn.t10_wwn_group; | 2825 | dev_cg->default_groups[2] = &se_dev->t10_wwn.t10_wwn_group; |
2761 | dev_cg->default_groups[3] = &se_dev->t10_alua.alua_tg_pt_gps_group; | 2826 | dev_cg->default_groups[3] = &se_dev->t10_alua.alua_tg_pt_gps_group; |
2762 | dev_cg->default_groups[4] = NULL; | 2827 | dev_cg->default_groups[4] = &se_dev->dev_stat_grps.stat_group; |
2828 | dev_cg->default_groups[5] = NULL; | ||
2763 | /* | 2829 | /* |
2764 | * Add core/$HBA/$DEV/alua/tg_pt_gps/default_tg_pt_gp | 2830 | * Add core/$HBA/$DEV/alua/default_tg_pt_gp |
2765 | */ | 2831 | */ |
2766 | tg_pt_gp = core_alua_allocate_tg_pt_gp(se_dev, "default_tg_pt_gp", 1); | 2832 | tg_pt_gp = core_alua_allocate_tg_pt_gp(se_dev, "default_tg_pt_gp", 1); |
2767 | if (!(tg_pt_gp)) | 2833 | if (!(tg_pt_gp)) |
@@ -2781,6 +2847,17 @@ static struct config_group *target_core_make_subdev( | |||
2781 | tg_pt_gp_cg->default_groups[0] = &tg_pt_gp->tg_pt_gp_group; | 2847 | tg_pt_gp_cg->default_groups[0] = &tg_pt_gp->tg_pt_gp_group; |
2782 | tg_pt_gp_cg->default_groups[1] = NULL; | 2848 | tg_pt_gp_cg->default_groups[1] = NULL; |
2783 | T10_ALUA(se_dev)->default_tg_pt_gp = tg_pt_gp; | 2849 | T10_ALUA(se_dev)->default_tg_pt_gp = tg_pt_gp; |
2850 | /* | ||
2851 | * Add core/$HBA/$DEV/statistics/ default groups | ||
2852 | */ | ||
2853 | dev_stat_grp = &DEV_STAT_GRP(se_dev)->stat_group; | ||
2854 | dev_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 4, | ||
2855 | GFP_KERNEL); | ||
2856 | if (!dev_stat_grp->default_groups) { | ||
2857 | printk(KERN_ERR "Unable to allocate dev_stat_grp->default_groups\n"); | ||
2858 | goto out; | ||
2859 | } | ||
2860 | target_stat_setup_dev_default_groups(se_dev); | ||
2784 | 2861 | ||
2785 | printk(KERN_INFO "Target_Core_ConfigFS: Allocated struct se_subsystem_dev:" | 2862 | printk(KERN_INFO "Target_Core_ConfigFS: Allocated struct se_subsystem_dev:" |
2786 | " %p se_dev_su_ptr: %p\n", se_dev, se_dev->se_dev_su_ptr); | 2863 | " %p se_dev_su_ptr: %p\n", se_dev, se_dev->se_dev_su_ptr); |
@@ -2792,6 +2869,8 @@ out: | |||
2792 | core_alua_free_tg_pt_gp(T10_ALUA(se_dev)->default_tg_pt_gp); | 2869 | core_alua_free_tg_pt_gp(T10_ALUA(se_dev)->default_tg_pt_gp); |
2793 | T10_ALUA(se_dev)->default_tg_pt_gp = NULL; | 2870 | T10_ALUA(se_dev)->default_tg_pt_gp = NULL; |
2794 | } | 2871 | } |
2872 | if (dev_stat_grp) | ||
2873 | kfree(dev_stat_grp->default_groups); | ||
2795 | if (tg_pt_gp_cg) | 2874 | if (tg_pt_gp_cg) |
2796 | kfree(tg_pt_gp_cg->default_groups); | 2875 | kfree(tg_pt_gp_cg->default_groups); |
2797 | if (dev_cg) | 2876 | if (dev_cg) |
@@ -2801,7 +2880,7 @@ out: | |||
2801 | kfree(se_dev); | 2880 | kfree(se_dev); |
2802 | unlock: | 2881 | unlock: |
2803 | mutex_unlock(&hba->hba_access_mutex); | 2882 | mutex_unlock(&hba->hba_access_mutex); |
2804 | return NULL; | 2883 | return ERR_PTR(errno); |
2805 | } | 2884 | } |
2806 | 2885 | ||
2807 | static void target_core_drop_subdev( | 2886 | static void target_core_drop_subdev( |
@@ -2813,7 +2892,7 @@ static void target_core_drop_subdev( | |||
2813 | struct se_hba *hba; | 2892 | struct se_hba *hba; |
2814 | struct se_subsystem_api *t; | 2893 | struct se_subsystem_api *t; |
2815 | struct config_item *df_item; | 2894 | struct config_item *df_item; |
2816 | struct config_group *dev_cg, *tg_pt_gp_cg; | 2895 | struct config_group *dev_cg, *tg_pt_gp_cg, *dev_stat_grp; |
2817 | int i; | 2896 | int i; |
2818 | 2897 | ||
2819 | hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); | 2898 | hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); |
@@ -2825,6 +2904,14 @@ static void target_core_drop_subdev( | |||
2825 | list_del(&se_dev->g_se_dev_list); | 2904 | list_del(&se_dev->g_se_dev_list); |
2826 | spin_unlock(&se_global->g_device_lock); | 2905 | spin_unlock(&se_global->g_device_lock); |
2827 | 2906 | ||
2907 | dev_stat_grp = &DEV_STAT_GRP(se_dev)->stat_group; | ||
2908 | for (i = 0; dev_stat_grp->default_groups[i]; i++) { | ||
2909 | df_item = &dev_stat_grp->default_groups[i]->cg_item; | ||
2910 | dev_stat_grp->default_groups[i] = NULL; | ||
2911 | config_item_put(df_item); | ||
2912 | } | ||
2913 | kfree(dev_stat_grp->default_groups); | ||
2914 | |||
2828 | tg_pt_gp_cg = &T10_ALUA(se_dev)->alua_tg_pt_gps_group; | 2915 | tg_pt_gp_cg = &T10_ALUA(se_dev)->alua_tg_pt_gps_group; |
2829 | for (i = 0; tg_pt_gp_cg->default_groups[i]; i++) { | 2916 | for (i = 0; tg_pt_gp_cg->default_groups[i]; i++) { |
2830 | df_item = &tg_pt_gp_cg->default_groups[i]->cg_item; | 2917 | df_item = &tg_pt_gp_cg->default_groups[i]->cg_item; |
@@ -3044,7 +3131,7 @@ static struct config_item_type target_core_cit = { | |||
3044 | 3131 | ||
3045 | /* Stop functions for struct config_item_type target_core_hba_cit */ | 3132 | /* Stop functions for struct config_item_type target_core_hba_cit */ |
3046 | 3133 | ||
3047 | static int target_core_init_configfs(void) | 3134 | static int __init target_core_init_configfs(void) |
3048 | { | 3135 | { |
3049 | struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL; | 3136 | struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL; |
3050 | struct config_group *lu_gp_cg = NULL; | 3137 | struct config_group *lu_gp_cg = NULL; |
@@ -3176,7 +3263,7 @@ out_global: | |||
3176 | return -1; | 3263 | return -1; |
3177 | } | 3264 | } |
3178 | 3265 | ||
3179 | static void target_core_exit_configfs(void) | 3266 | static void __exit target_core_exit_configfs(void) |
3180 | { | 3267 | { |
3181 | struct configfs_subsystem *subsys; | 3268 | struct configfs_subsystem *subsys; |
3182 | struct config_group *hba_cg, *alua_cg, *lu_gp_cg; | 3269 | struct config_group *hba_cg, *alua_cg, *lu_gp_cg; |
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 350ed401544e..3fb8e32506ed 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c | |||
@@ -589,6 +589,7 @@ static void core_export_port( | |||
589 | * Called with struct se_device->se_port_lock spinlock held. | 589 | * Called with struct se_device->se_port_lock spinlock held. |
590 | */ | 590 | */ |
591 | static void core_release_port(struct se_device *dev, struct se_port *port) | 591 | static void core_release_port(struct se_device *dev, struct se_port *port) |
592 | __releases(&dev->se_port_lock) __acquires(&dev->se_port_lock) | ||
592 | { | 593 | { |
593 | /* | 594 | /* |
594 | * Wait for any port reference for PR ALL_TG_PT=1 operation | 595 | * Wait for any port reference for PR ALL_TG_PT=1 operation |
@@ -779,49 +780,14 @@ void se_release_vpd_for_dev(struct se_device *dev) | |||
779 | return; | 780 | return; |
780 | } | 781 | } |
781 | 782 | ||
782 | /* | ||
783 | * Called with struct se_hba->device_lock held. | ||
784 | */ | ||
785 | void se_clear_dev_ports(struct se_device *dev) | ||
786 | { | ||
787 | struct se_hba *hba = dev->se_hba; | ||
788 | struct se_lun *lun; | ||
789 | struct se_portal_group *tpg; | ||
790 | struct se_port *sep, *sep_tmp; | ||
791 | |||
792 | spin_lock(&dev->se_port_lock); | ||
793 | list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) { | ||
794 | spin_unlock(&dev->se_port_lock); | ||
795 | spin_unlock(&hba->device_lock); | ||
796 | |||
797 | lun = sep->sep_lun; | ||
798 | tpg = sep->sep_tpg; | ||
799 | spin_lock(&lun->lun_sep_lock); | ||
800 | if (lun->lun_se_dev == NULL) { | ||
801 | spin_unlock(&lun->lun_sep_lock); | ||
802 | continue; | ||
803 | } | ||
804 | spin_unlock(&lun->lun_sep_lock); | ||
805 | |||
806 | core_dev_del_lun(tpg, lun->unpacked_lun); | ||
807 | |||
808 | spin_lock(&hba->device_lock); | ||
809 | spin_lock(&dev->se_port_lock); | ||
810 | } | ||
811 | spin_unlock(&dev->se_port_lock); | ||
812 | |||
813 | return; | ||
814 | } | ||
815 | |||
816 | /* se_free_virtual_device(): | 783 | /* se_free_virtual_device(): |
817 | * | 784 | * |
818 | * Used for IBLOCK, RAMDISK, and FILEIO Transport Drivers. | 785 | * Used for IBLOCK, RAMDISK, and FILEIO Transport Drivers. |
819 | */ | 786 | */ |
820 | int se_free_virtual_device(struct se_device *dev, struct se_hba *hba) | 787 | int se_free_virtual_device(struct se_device *dev, struct se_hba *hba) |
821 | { | 788 | { |
822 | spin_lock(&hba->device_lock); | 789 | if (!list_empty(&dev->dev_sep_list)) |
823 | se_clear_dev_ports(dev); | 790 | dump_stack(); |
824 | spin_unlock(&hba->device_lock); | ||
825 | 791 | ||
826 | core_alua_free_lu_gp_mem(dev); | 792 | core_alua_free_lu_gp_mem(dev); |
827 | se_release_device_for_hba(dev); | 793 | se_release_device_for_hba(dev); |
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index b65d1c8e7740..07ab5a3bb8e8 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c | |||
@@ -4,10 +4,10 @@ | |||
4 | * This file contains generic fabric module configfs infrastructure for | 4 | * This file contains generic fabric module configfs infrastructure for |
5 | * TCM v4.x code | 5 | * TCM v4.x code |
6 | * | 6 | * |
7 | * Copyright (c) 2010 Rising Tide Systems | 7 | * Copyright (c) 2010,2011 Rising Tide Systems |
8 | * Copyright (c) 2010 Linux-iSCSI.org | 8 | * Copyright (c) 2010,2011 Linux-iSCSI.org |
9 | * | 9 | * |
10 | * Copyright (c) 2010 Nicholas A. Bellinger <nab@linux-iscsi.org> | 10 | * Copyright (c) Nicholas A. Bellinger <nab@linux-iscsi.org> |
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 as published by |
@@ -48,6 +48,7 @@ | |||
48 | #include "target_core_alua.h" | 48 | #include "target_core_alua.h" |
49 | #include "target_core_hba.h" | 49 | #include "target_core_hba.h" |
50 | #include "target_core_pr.h" | 50 | #include "target_core_pr.h" |
51 | #include "target_core_stat.h" | ||
51 | 52 | ||
52 | #define TF_CIT_SETUP(_name, _item_ops, _group_ops, _attrs) \ | 53 | #define TF_CIT_SETUP(_name, _item_ops, _group_ops, _attrs) \ |
53 | static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \ | 54 | static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \ |
@@ -241,6 +242,32 @@ TF_CIT_SETUP(tpg_mappedlun, &target_fabric_mappedlun_item_ops, NULL, | |||
241 | 242 | ||
242 | /* End of tfc_tpg_mappedlun_cit */ | 243 | /* End of tfc_tpg_mappedlun_cit */ |
243 | 244 | ||
245 | /* Start of tfc_tpg_mappedlun_port_cit */ | ||
246 | |||
247 | static struct config_group *target_core_mappedlun_stat_mkdir( | ||
248 | struct config_group *group, | ||
249 | const char *name) | ||
250 | { | ||
251 | return ERR_PTR(-ENOSYS); | ||
252 | } | ||
253 | |||
254 | static void target_core_mappedlun_stat_rmdir( | ||
255 | struct config_group *group, | ||
256 | struct config_item *item) | ||
257 | { | ||
258 | return; | ||
259 | } | ||
260 | |||
261 | static struct configfs_group_operations target_fabric_mappedlun_stat_group_ops = { | ||
262 | .make_group = target_core_mappedlun_stat_mkdir, | ||
263 | .drop_item = target_core_mappedlun_stat_rmdir, | ||
264 | }; | ||
265 | |||
266 | TF_CIT_SETUP(tpg_mappedlun_stat, NULL, &target_fabric_mappedlun_stat_group_ops, | ||
267 | NULL); | ||
268 | |||
269 | /* End of tfc_tpg_mappedlun_port_cit */ | ||
270 | |||
244 | /* Start of tfc_tpg_nacl_attrib_cit */ | 271 | /* Start of tfc_tpg_nacl_attrib_cit */ |
245 | 272 | ||
246 | CONFIGFS_EATTR_OPS(target_fabric_nacl_attrib, se_node_acl, acl_attrib_group); | 273 | CONFIGFS_EATTR_OPS(target_fabric_nacl_attrib, se_node_acl, acl_attrib_group); |
@@ -294,6 +321,7 @@ static struct config_group *target_fabric_make_mappedlun( | |||
294 | struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; | 321 | struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; |
295 | struct se_lun_acl *lacl; | 322 | struct se_lun_acl *lacl; |
296 | struct config_item *acl_ci; | 323 | struct config_item *acl_ci; |
324 | struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL; | ||
297 | char *buf; | 325 | char *buf; |
298 | unsigned long mapped_lun; | 326 | unsigned long mapped_lun; |
299 | int ret = 0; | 327 | int ret = 0; |
@@ -330,15 +358,42 @@ static struct config_group *target_fabric_make_mappedlun( | |||
330 | 358 | ||
331 | lacl = core_dev_init_initiator_node_lun_acl(se_tpg, mapped_lun, | 359 | lacl = core_dev_init_initiator_node_lun_acl(se_tpg, mapped_lun, |
332 | config_item_name(acl_ci), &ret); | 360 | config_item_name(acl_ci), &ret); |
333 | if (!(lacl)) | 361 | if (!(lacl)) { |
362 | ret = -EINVAL; | ||
334 | goto out; | 363 | goto out; |
364 | } | ||
365 | |||
366 | lacl_cg = &lacl->se_lun_group; | ||
367 | lacl_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, | ||
368 | GFP_KERNEL); | ||
369 | if (!lacl_cg->default_groups) { | ||
370 | printk(KERN_ERR "Unable to allocate lacl_cg->default_groups\n"); | ||
371 | ret = -ENOMEM; | ||
372 | goto out; | ||
373 | } | ||
335 | 374 | ||
336 | config_group_init_type_name(&lacl->se_lun_group, name, | 375 | config_group_init_type_name(&lacl->se_lun_group, name, |
337 | &TF_CIT_TMPL(tf)->tfc_tpg_mappedlun_cit); | 376 | &TF_CIT_TMPL(tf)->tfc_tpg_mappedlun_cit); |
377 | config_group_init_type_name(&lacl->ml_stat_grps.stat_group, | ||
378 | "statistics", &TF_CIT_TMPL(tf)->tfc_tpg_mappedlun_stat_cit); | ||
379 | lacl_cg->default_groups[0] = &lacl->ml_stat_grps.stat_group; | ||
380 | lacl_cg->default_groups[1] = NULL; | ||
381 | |||
382 | ml_stat_grp = &ML_STAT_GRPS(lacl)->stat_group; | ||
383 | ml_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 3, | ||
384 | GFP_KERNEL); | ||
385 | if (!ml_stat_grp->default_groups) { | ||
386 | printk(KERN_ERR "Unable to allocate ml_stat_grp->default_groups\n"); | ||
387 | ret = -ENOMEM; | ||
388 | goto out; | ||
389 | } | ||
390 | target_stat_setup_mappedlun_default_groups(lacl); | ||
338 | 391 | ||
339 | kfree(buf); | 392 | kfree(buf); |
340 | return &lacl->se_lun_group; | 393 | return &lacl->se_lun_group; |
341 | out: | 394 | out: |
395 | if (lacl_cg) | ||
396 | kfree(lacl_cg->default_groups); | ||
342 | kfree(buf); | 397 | kfree(buf); |
343 | return ERR_PTR(ret); | 398 | return ERR_PTR(ret); |
344 | } | 399 | } |
@@ -347,6 +402,28 @@ static void target_fabric_drop_mappedlun( | |||
347 | struct config_group *group, | 402 | struct config_group *group, |
348 | struct config_item *item) | 403 | struct config_item *item) |
349 | { | 404 | { |
405 | struct se_lun_acl *lacl = container_of(to_config_group(item), | ||
406 | struct se_lun_acl, se_lun_group); | ||
407 | struct config_item *df_item; | ||
408 | struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL; | ||
409 | int i; | ||
410 | |||
411 | ml_stat_grp = &ML_STAT_GRPS(lacl)->stat_group; | ||
412 | for (i = 0; ml_stat_grp->default_groups[i]; i++) { | ||
413 | df_item = &ml_stat_grp->default_groups[i]->cg_item; | ||
414 | ml_stat_grp->default_groups[i] = NULL; | ||
415 | config_item_put(df_item); | ||
416 | } | ||
417 | kfree(ml_stat_grp->default_groups); | ||
418 | |||
419 | lacl_cg = &lacl->se_lun_group; | ||
420 | for (i = 0; lacl_cg->default_groups[i]; i++) { | ||
421 | df_item = &lacl_cg->default_groups[i]->cg_item; | ||
422 | lacl_cg->default_groups[i] = NULL; | ||
423 | config_item_put(df_item); | ||
424 | } | ||
425 | kfree(lacl_cg->default_groups); | ||
426 | |||
350 | config_item_put(item); | 427 | config_item_put(item); |
351 | } | 428 | } |
352 | 429 | ||
@@ -376,6 +453,15 @@ TF_CIT_SETUP(tpg_nacl_base, &target_fabric_nacl_base_item_ops, | |||
376 | 453 | ||
377 | /* End of tfc_tpg_nacl_base_cit */ | 454 | /* End of tfc_tpg_nacl_base_cit */ |
378 | 455 | ||
456 | /* Start of tfc_node_fabric_stats_cit */ | ||
457 | /* | ||
458 | * This is used as a placeholder for struct se_node_acl->acl_fabric_stat_group | ||
459 | * to allow fabrics access to ->acl_fabric_stat_group->default_groups[] | ||
460 | */ | ||
461 | TF_CIT_SETUP(tpg_nacl_stat, NULL, NULL, NULL); | ||
462 | |||
463 | /* End of tfc_wwn_fabric_stats_cit */ | ||
464 | |||
379 | /* Start of tfc_tpg_nacl_cit */ | 465 | /* Start of tfc_tpg_nacl_cit */ |
380 | 466 | ||
381 | static struct config_group *target_fabric_make_nodeacl( | 467 | static struct config_group *target_fabric_make_nodeacl( |
@@ -402,7 +488,8 @@ static struct config_group *target_fabric_make_nodeacl( | |||
402 | nacl_cg->default_groups[0] = &se_nacl->acl_attrib_group; | 488 | nacl_cg->default_groups[0] = &se_nacl->acl_attrib_group; |
403 | nacl_cg->default_groups[1] = &se_nacl->acl_auth_group; | 489 | nacl_cg->default_groups[1] = &se_nacl->acl_auth_group; |
404 | nacl_cg->default_groups[2] = &se_nacl->acl_param_group; | 490 | nacl_cg->default_groups[2] = &se_nacl->acl_param_group; |
405 | nacl_cg->default_groups[3] = NULL; | 491 | nacl_cg->default_groups[3] = &se_nacl->acl_fabric_stat_group; |
492 | nacl_cg->default_groups[4] = NULL; | ||
406 | 493 | ||
407 | config_group_init_type_name(&se_nacl->acl_group, name, | 494 | config_group_init_type_name(&se_nacl->acl_group, name, |
408 | &TF_CIT_TMPL(tf)->tfc_tpg_nacl_base_cit); | 495 | &TF_CIT_TMPL(tf)->tfc_tpg_nacl_base_cit); |
@@ -412,6 +499,9 @@ static struct config_group *target_fabric_make_nodeacl( | |||
412 | &TF_CIT_TMPL(tf)->tfc_tpg_nacl_auth_cit); | 499 | &TF_CIT_TMPL(tf)->tfc_tpg_nacl_auth_cit); |
413 | config_group_init_type_name(&se_nacl->acl_param_group, "param", | 500 | config_group_init_type_name(&se_nacl->acl_param_group, "param", |
414 | &TF_CIT_TMPL(tf)->tfc_tpg_nacl_param_cit); | 501 | &TF_CIT_TMPL(tf)->tfc_tpg_nacl_param_cit); |
502 | config_group_init_type_name(&se_nacl->acl_fabric_stat_group, | ||
503 | "fabric_statistics", | ||
504 | &TF_CIT_TMPL(tf)->tfc_tpg_nacl_stat_cit); | ||
415 | 505 | ||
416 | return &se_nacl->acl_group; | 506 | return &se_nacl->acl_group; |
417 | } | 507 | } |
@@ -758,6 +848,31 @@ TF_CIT_SETUP(tpg_port, &target_fabric_port_item_ops, NULL, target_fabric_port_at | |||
758 | 848 | ||
759 | /* End of tfc_tpg_port_cit */ | 849 | /* End of tfc_tpg_port_cit */ |
760 | 850 | ||
851 | /* Start of tfc_tpg_port_stat_cit */ | ||
852 | |||
853 | static struct config_group *target_core_port_stat_mkdir( | ||
854 | struct config_group *group, | ||
855 | const char *name) | ||
856 | { | ||
857 | return ERR_PTR(-ENOSYS); | ||
858 | } | ||
859 | |||
860 | static void target_core_port_stat_rmdir( | ||
861 | struct config_group *group, | ||
862 | struct config_item *item) | ||
863 | { | ||
864 | return; | ||
865 | } | ||
866 | |||
867 | static struct configfs_group_operations target_fabric_port_stat_group_ops = { | ||
868 | .make_group = target_core_port_stat_mkdir, | ||
869 | .drop_item = target_core_port_stat_rmdir, | ||
870 | }; | ||
871 | |||
872 | TF_CIT_SETUP(tpg_port_stat, NULL, &target_fabric_port_stat_group_ops, NULL); | ||
873 | |||
874 | /* End of tfc_tpg_port_stat_cit */ | ||
875 | |||
761 | /* Start of tfc_tpg_lun_cit */ | 876 | /* Start of tfc_tpg_lun_cit */ |
762 | 877 | ||
763 | static struct config_group *target_fabric_make_lun( | 878 | static struct config_group *target_fabric_make_lun( |
@@ -768,7 +883,9 @@ static struct config_group *target_fabric_make_lun( | |||
768 | struct se_portal_group *se_tpg = container_of(group, | 883 | struct se_portal_group *se_tpg = container_of(group, |
769 | struct se_portal_group, tpg_lun_group); | 884 | struct se_portal_group, tpg_lun_group); |
770 | struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; | 885 | struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; |
886 | struct config_group *lun_cg = NULL, *port_stat_grp = NULL; | ||
771 | unsigned long unpacked_lun; | 887 | unsigned long unpacked_lun; |
888 | int errno; | ||
772 | 889 | ||
773 | if (strstr(name, "lun_") != name) { | 890 | if (strstr(name, "lun_") != name) { |
774 | printk(KERN_ERR "Unable to locate \'_\" in" | 891 | printk(KERN_ERR "Unable to locate \'_\" in" |
@@ -782,16 +899,64 @@ static struct config_group *target_fabric_make_lun( | |||
782 | if (!(lun)) | 899 | if (!(lun)) |
783 | return ERR_PTR(-EINVAL); | 900 | return ERR_PTR(-EINVAL); |
784 | 901 | ||
902 | lun_cg = &lun->lun_group; | ||
903 | lun_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, | ||
904 | GFP_KERNEL); | ||
905 | if (!lun_cg->default_groups) { | ||
906 | printk(KERN_ERR "Unable to allocate lun_cg->default_groups\n"); | ||
907 | return ERR_PTR(-ENOMEM); | ||
908 | } | ||
909 | |||
785 | config_group_init_type_name(&lun->lun_group, name, | 910 | config_group_init_type_name(&lun->lun_group, name, |
786 | &TF_CIT_TMPL(tf)->tfc_tpg_port_cit); | 911 | &TF_CIT_TMPL(tf)->tfc_tpg_port_cit); |
912 | config_group_init_type_name(&lun->port_stat_grps.stat_group, | ||
913 | "statistics", &TF_CIT_TMPL(tf)->tfc_tpg_port_stat_cit); | ||
914 | lun_cg->default_groups[0] = &lun->port_stat_grps.stat_group; | ||
915 | lun_cg->default_groups[1] = NULL; | ||
916 | |||
917 | port_stat_grp = &PORT_STAT_GRP(lun)->stat_group; | ||
918 | port_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 3, | ||
919 | GFP_KERNEL); | ||
920 | if (!port_stat_grp->default_groups) { | ||
921 | printk(KERN_ERR "Unable to allocate port_stat_grp->default_groups\n"); | ||
922 | errno = -ENOMEM; | ||
923 | goto out; | ||
924 | } | ||
925 | target_stat_setup_port_default_groups(lun); | ||
787 | 926 | ||
788 | return &lun->lun_group; | 927 | return &lun->lun_group; |
928 | out: | ||
929 | if (lun_cg) | ||
930 | kfree(lun_cg->default_groups); | ||
931 | return ERR_PTR(errno); | ||
789 | } | 932 | } |
790 | 933 | ||
791 | static void target_fabric_drop_lun( | 934 | static void target_fabric_drop_lun( |
792 | struct config_group *group, | 935 | struct config_group *group, |
793 | struct config_item *item) | 936 | struct config_item *item) |
794 | { | 937 | { |
938 | struct se_lun *lun = container_of(to_config_group(item), | ||
939 | struct se_lun, lun_group); | ||
940 | struct config_item *df_item; | ||
941 | struct config_group *lun_cg, *port_stat_grp; | ||
942 | int i; | ||
943 | |||
944 | port_stat_grp = &PORT_STAT_GRP(lun)->stat_group; | ||
945 | for (i = 0; port_stat_grp->default_groups[i]; i++) { | ||
946 | df_item = &port_stat_grp->default_groups[i]->cg_item; | ||
947 | port_stat_grp->default_groups[i] = NULL; | ||
948 | config_item_put(df_item); | ||
949 | } | ||
950 | kfree(port_stat_grp->default_groups); | ||
951 | |||
952 | lun_cg = &lun->lun_group; | ||
953 | for (i = 0; lun_cg->default_groups[i]; i++) { | ||
954 | df_item = &lun_cg->default_groups[i]->cg_item; | ||
955 | lun_cg->default_groups[i] = NULL; | ||
956 | config_item_put(df_item); | ||
957 | } | ||
958 | kfree(lun_cg->default_groups); | ||
959 | |||
795 | config_item_put(item); | 960 | config_item_put(item); |
796 | } | 961 | } |
797 | 962 | ||
@@ -946,6 +1111,15 @@ TF_CIT_SETUP(tpg, &target_fabric_tpg_item_ops, &target_fabric_tpg_group_ops, | |||
946 | 1111 | ||
947 | /* End of tfc_tpg_cit */ | 1112 | /* End of tfc_tpg_cit */ |
948 | 1113 | ||
1114 | /* Start of tfc_wwn_fabric_stats_cit */ | ||
1115 | /* | ||
1116 | * This is used as a placeholder for struct se_wwn->fabric_stat_group | ||
1117 | * to allow fabrics access to ->fabric_stat_group->default_groups[] | ||
1118 | */ | ||
1119 | TF_CIT_SETUP(wwn_fabric_stats, NULL, NULL, NULL); | ||
1120 | |||
1121 | /* End of tfc_wwn_fabric_stats_cit */ | ||
1122 | |||
949 | /* Start of tfc_wwn_cit */ | 1123 | /* Start of tfc_wwn_cit */ |
950 | 1124 | ||
951 | static struct config_group *target_fabric_make_wwn( | 1125 | static struct config_group *target_fabric_make_wwn( |
@@ -966,8 +1140,17 @@ static struct config_group *target_fabric_make_wwn( | |||
966 | return ERR_PTR(-EINVAL); | 1140 | return ERR_PTR(-EINVAL); |
967 | 1141 | ||
968 | wwn->wwn_tf = tf; | 1142 | wwn->wwn_tf = tf; |
1143 | /* | ||
1144 | * Setup default groups from pre-allocated wwn->wwn_default_groups | ||
1145 | */ | ||
1146 | wwn->wwn_group.default_groups = wwn->wwn_default_groups; | ||
1147 | wwn->wwn_group.default_groups[0] = &wwn->fabric_stat_group; | ||
1148 | wwn->wwn_group.default_groups[1] = NULL; | ||
1149 | |||
969 | config_group_init_type_name(&wwn->wwn_group, name, | 1150 | config_group_init_type_name(&wwn->wwn_group, name, |
970 | &TF_CIT_TMPL(tf)->tfc_tpg_cit); | 1151 | &TF_CIT_TMPL(tf)->tfc_tpg_cit); |
1152 | config_group_init_type_name(&wwn->fabric_stat_group, "fabric_statistics", | ||
1153 | &TF_CIT_TMPL(tf)->tfc_wwn_fabric_stats_cit); | ||
971 | 1154 | ||
972 | return &wwn->wwn_group; | 1155 | return &wwn->wwn_group; |
973 | } | 1156 | } |
@@ -976,6 +1159,18 @@ static void target_fabric_drop_wwn( | |||
976 | struct config_group *group, | 1159 | struct config_group *group, |
977 | struct config_item *item) | 1160 | struct config_item *item) |
978 | { | 1161 | { |
1162 | struct se_wwn *wwn = container_of(to_config_group(item), | ||
1163 | struct se_wwn, wwn_group); | ||
1164 | struct config_item *df_item; | ||
1165 | struct config_group *cg = &wwn->wwn_group; | ||
1166 | int i; | ||
1167 | |||
1168 | for (i = 0; cg->default_groups[i]; i++) { | ||
1169 | df_item = &cg->default_groups[i]->cg_item; | ||
1170 | cg->default_groups[i] = NULL; | ||
1171 | config_item_put(df_item); | ||
1172 | } | ||
1173 | |||
979 | config_item_put(item); | 1174 | config_item_put(item); |
980 | } | 1175 | } |
981 | 1176 | ||
@@ -1015,9 +1210,11 @@ int target_fabric_setup_cits(struct target_fabric_configfs *tf) | |||
1015 | { | 1210 | { |
1016 | target_fabric_setup_discovery_cit(tf); | 1211 | target_fabric_setup_discovery_cit(tf); |
1017 | target_fabric_setup_wwn_cit(tf); | 1212 | target_fabric_setup_wwn_cit(tf); |
1213 | target_fabric_setup_wwn_fabric_stats_cit(tf); | ||
1018 | target_fabric_setup_tpg_cit(tf); | 1214 | target_fabric_setup_tpg_cit(tf); |
1019 | target_fabric_setup_tpg_base_cit(tf); | 1215 | target_fabric_setup_tpg_base_cit(tf); |
1020 | target_fabric_setup_tpg_port_cit(tf); | 1216 | target_fabric_setup_tpg_port_cit(tf); |
1217 | target_fabric_setup_tpg_port_stat_cit(tf); | ||
1021 | target_fabric_setup_tpg_lun_cit(tf); | 1218 | target_fabric_setup_tpg_lun_cit(tf); |
1022 | target_fabric_setup_tpg_np_cit(tf); | 1219 | target_fabric_setup_tpg_np_cit(tf); |
1023 | target_fabric_setup_tpg_np_base_cit(tf); | 1220 | target_fabric_setup_tpg_np_base_cit(tf); |
@@ -1028,7 +1225,9 @@ int target_fabric_setup_cits(struct target_fabric_configfs *tf) | |||
1028 | target_fabric_setup_tpg_nacl_attrib_cit(tf); | 1225 | target_fabric_setup_tpg_nacl_attrib_cit(tf); |
1029 | target_fabric_setup_tpg_nacl_auth_cit(tf); | 1226 | target_fabric_setup_tpg_nacl_auth_cit(tf); |
1030 | target_fabric_setup_tpg_nacl_param_cit(tf); | 1227 | target_fabric_setup_tpg_nacl_param_cit(tf); |
1228 | target_fabric_setup_tpg_nacl_stat_cit(tf); | ||
1031 | target_fabric_setup_tpg_mappedlun_cit(tf); | 1229 | target_fabric_setup_tpg_mappedlun_cit(tf); |
1230 | target_fabric_setup_tpg_mappedlun_stat_cit(tf); | ||
1032 | 1231 | ||
1033 | return 0; | 1232 | return 0; |
1034 | } | 1233 | } |
diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index a3c695adabec..d57ad672677f 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <target/target_core_base.h> | 34 | #include <target/target_core_base.h> |
35 | #include <target/target_core_device.h> | 35 | #include <target/target_core_device.h> |
36 | #include <target/target_core_transport.h> | 36 | #include <target/target_core_transport.h> |
37 | #include <target/target_core_fabric_lib.h> | ||
37 | #include <target/target_core_fabric_ops.h> | 38 | #include <target/target_core_fabric_ops.h> |
38 | #include <target/target_core_configfs.h> | 39 | #include <target/target_core_configfs.h> |
39 | 40 | ||
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 190ca8ac2498..02f553aef43d 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c | |||
@@ -134,7 +134,7 @@ static struct se_device *fd_create_virtdevice( | |||
134 | mm_segment_t old_fs; | 134 | mm_segment_t old_fs; |
135 | struct file *file; | 135 | struct file *file; |
136 | struct inode *inode = NULL; | 136 | struct inode *inode = NULL; |
137 | int dev_flags = 0, flags; | 137 | int dev_flags = 0, flags, ret = -EINVAL; |
138 | 138 | ||
139 | memset(&dev_limits, 0, sizeof(struct se_dev_limits)); | 139 | memset(&dev_limits, 0, sizeof(struct se_dev_limits)); |
140 | 140 | ||
@@ -146,6 +146,7 @@ static struct se_device *fd_create_virtdevice( | |||
146 | if (IS_ERR(dev_p)) { | 146 | if (IS_ERR(dev_p)) { |
147 | printk(KERN_ERR "getname(%s) failed: %lu\n", | 147 | printk(KERN_ERR "getname(%s) failed: %lu\n", |
148 | fd_dev->fd_dev_name, IS_ERR(dev_p)); | 148 | fd_dev->fd_dev_name, IS_ERR(dev_p)); |
149 | ret = PTR_ERR(dev_p); | ||
149 | goto fail; | 150 | goto fail; |
150 | } | 151 | } |
151 | #if 0 | 152 | #if 0 |
@@ -165,8 +166,12 @@ static struct se_device *fd_create_virtdevice( | |||
165 | flags |= O_SYNC; | 166 | flags |= O_SYNC; |
166 | 167 | ||
167 | file = filp_open(dev_p, flags, 0600); | 168 | file = filp_open(dev_p, flags, 0600); |
168 | 169 | if (IS_ERR(file)) { | |
169 | if (IS_ERR(file) || !file || !file->f_dentry) { | 170 | printk(KERN_ERR "filp_open(%s) failed\n", dev_p); |
171 | ret = PTR_ERR(file); | ||
172 | goto fail; | ||
173 | } | ||
174 | if (!file || !file->f_dentry) { | ||
170 | printk(KERN_ERR "filp_open(%s) failed\n", dev_p); | 175 | printk(KERN_ERR "filp_open(%s) failed\n", dev_p); |
171 | goto fail; | 176 | goto fail; |
172 | } | 177 | } |
@@ -241,7 +246,7 @@ fail: | |||
241 | fd_dev->fd_file = NULL; | 246 | fd_dev->fd_file = NULL; |
242 | } | 247 | } |
243 | putname(dev_p); | 248 | putname(dev_p); |
244 | return NULL; | 249 | return ERR_PTR(ret); |
245 | } | 250 | } |
246 | 251 | ||
247 | /* fd_free_device(): (Part of se_subsystem_api_t template) | 252 | /* fd_free_device(): (Part of se_subsystem_api_t template) |
@@ -509,7 +514,7 @@ enum { | |||
509 | static match_table_t tokens = { | 514 | static match_table_t tokens = { |
510 | {Opt_fd_dev_name, "fd_dev_name=%s"}, | 515 | {Opt_fd_dev_name, "fd_dev_name=%s"}, |
511 | {Opt_fd_dev_size, "fd_dev_size=%s"}, | 516 | {Opt_fd_dev_size, "fd_dev_size=%s"}, |
512 | {Opt_fd_buffered_io, "fd_buffered_id=%d"}, | 517 | {Opt_fd_buffered_io, "fd_buffered_io=%d"}, |
513 | {Opt_err, NULL} | 518 | {Opt_err, NULL} |
514 | }; | 519 | }; |
515 | 520 | ||
@@ -536,15 +541,26 @@ static ssize_t fd_set_configfs_dev_params( | |||
536 | token = match_token(ptr, tokens, args); | 541 | token = match_token(ptr, tokens, args); |
537 | switch (token) { | 542 | switch (token) { |
538 | case Opt_fd_dev_name: | 543 | case Opt_fd_dev_name: |
544 | arg_p = match_strdup(&args[0]); | ||
545 | if (!arg_p) { | ||
546 | ret = -ENOMEM; | ||
547 | break; | ||
548 | } | ||
539 | snprintf(fd_dev->fd_dev_name, FD_MAX_DEV_NAME, | 549 | snprintf(fd_dev->fd_dev_name, FD_MAX_DEV_NAME, |
540 | "%s", match_strdup(&args[0])); | 550 | "%s", arg_p); |
551 | kfree(arg_p); | ||
541 | printk(KERN_INFO "FILEIO: Referencing Path: %s\n", | 552 | printk(KERN_INFO "FILEIO: Referencing Path: %s\n", |
542 | fd_dev->fd_dev_name); | 553 | fd_dev->fd_dev_name); |
543 | fd_dev->fbd_flags |= FBDF_HAS_PATH; | 554 | fd_dev->fbd_flags |= FBDF_HAS_PATH; |
544 | break; | 555 | break; |
545 | case Opt_fd_dev_size: | 556 | case Opt_fd_dev_size: |
546 | arg_p = match_strdup(&args[0]); | 557 | arg_p = match_strdup(&args[0]); |
558 | if (!arg_p) { | ||
559 | ret = -ENOMEM; | ||
560 | break; | ||
561 | } | ||
547 | ret = strict_strtoull(arg_p, 0, &fd_dev->fd_dev_size); | 562 | ret = strict_strtoull(arg_p, 0, &fd_dev->fd_dev_size); |
563 | kfree(arg_p); | ||
548 | if (ret < 0) { | 564 | if (ret < 0) { |
549 | printk(KERN_ERR "strict_strtoull() failed for" | 565 | printk(KERN_ERR "strict_strtoull() failed for" |
550 | " fd_dev_size=\n"); | 566 | " fd_dev_size=\n"); |
diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c index 6ec51cbc018e..0b8f8da89019 100644 --- a/drivers/target/target_core_hba.c +++ b/drivers/target/target_core_hba.c | |||
@@ -151,19 +151,8 @@ out_free_hba: | |||
151 | int | 151 | int |
152 | core_delete_hba(struct se_hba *hba) | 152 | core_delete_hba(struct se_hba *hba) |
153 | { | 153 | { |
154 | struct se_device *dev, *dev_tmp; | 154 | if (!list_empty(&hba->hba_dev_list)) |
155 | 155 | dump_stack(); | |
156 | spin_lock(&hba->device_lock); | ||
157 | list_for_each_entry_safe(dev, dev_tmp, &hba->hba_dev_list, dev_list) { | ||
158 | |||
159 | se_clear_dev_ports(dev); | ||
160 | spin_unlock(&hba->device_lock); | ||
161 | |||
162 | se_release_device_for_hba(dev); | ||
163 | |||
164 | spin_lock(&hba->device_lock); | ||
165 | } | ||
166 | spin_unlock(&hba->device_lock); | ||
167 | 156 | ||
168 | hba->transport->detach_hba(hba); | 157 | hba->transport->detach_hba(hba); |
169 | 158 | ||
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index eb0afec046e1..86639004af9e 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c | |||
@@ -129,10 +129,11 @@ static struct se_device *iblock_create_virtdevice( | |||
129 | struct request_queue *q; | 129 | struct request_queue *q; |
130 | struct queue_limits *limits; | 130 | struct queue_limits *limits; |
131 | u32 dev_flags = 0; | 131 | u32 dev_flags = 0; |
132 | int ret = -EINVAL; | ||
132 | 133 | ||
133 | if (!(ib_dev)) { | 134 | if (!(ib_dev)) { |
134 | printk(KERN_ERR "Unable to locate struct iblock_dev parameter\n"); | 135 | printk(KERN_ERR "Unable to locate struct iblock_dev parameter\n"); |
135 | return 0; | 136 | return ERR_PTR(ret); |
136 | } | 137 | } |
137 | memset(&dev_limits, 0, sizeof(struct se_dev_limits)); | 138 | memset(&dev_limits, 0, sizeof(struct se_dev_limits)); |
138 | /* | 139 | /* |
@@ -141,7 +142,7 @@ static struct se_device *iblock_create_virtdevice( | |||
141 | ib_dev->ibd_bio_set = bioset_create(32, 64); | 142 | ib_dev->ibd_bio_set = bioset_create(32, 64); |
142 | if (!(ib_dev->ibd_bio_set)) { | 143 | if (!(ib_dev->ibd_bio_set)) { |
143 | printk(KERN_ERR "IBLOCK: Unable to create bioset()\n"); | 144 | printk(KERN_ERR "IBLOCK: Unable to create bioset()\n"); |
144 | return 0; | 145 | return ERR_PTR(-ENOMEM); |
145 | } | 146 | } |
146 | printk(KERN_INFO "IBLOCK: Created bio_set()\n"); | 147 | printk(KERN_INFO "IBLOCK: Created bio_set()\n"); |
147 | /* | 148 | /* |
@@ -153,8 +154,10 @@ static struct se_device *iblock_create_virtdevice( | |||
153 | 154 | ||
154 | bd = blkdev_get_by_path(ib_dev->ibd_udev_path, | 155 | bd = blkdev_get_by_path(ib_dev->ibd_udev_path, |
155 | FMODE_WRITE|FMODE_READ|FMODE_EXCL, ib_dev); | 156 | FMODE_WRITE|FMODE_READ|FMODE_EXCL, ib_dev); |
156 | if (IS_ERR(bd)) | 157 | if (IS_ERR(bd)) { |
158 | ret = PTR_ERR(bd); | ||
157 | goto failed; | 159 | goto failed; |
160 | } | ||
158 | /* | 161 | /* |
159 | * Setup the local scope queue_limits from struct request_queue->limits | 162 | * Setup the local scope queue_limits from struct request_queue->limits |
160 | * to pass into transport_add_device_to_core_hba() as struct se_dev_limits. | 163 | * to pass into transport_add_device_to_core_hba() as struct se_dev_limits. |
@@ -184,9 +187,7 @@ static struct se_device *iblock_create_virtdevice( | |||
184 | * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM | 187 | * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM |
185 | * in ATA and we need to set TPE=1 | 188 | * in ATA and we need to set TPE=1 |
186 | */ | 189 | */ |
187 | if (blk_queue_discard(bdev_get_queue(bd))) { | 190 | if (blk_queue_discard(q)) { |
188 | struct request_queue *q = bdev_get_queue(bd); | ||
189 | |||
190 | DEV_ATTRIB(dev)->max_unmap_lba_count = | 191 | DEV_ATTRIB(dev)->max_unmap_lba_count = |
191 | q->limits.max_discard_sectors; | 192 | q->limits.max_discard_sectors; |
192 | /* | 193 | /* |
@@ -212,7 +213,7 @@ failed: | |||
212 | ib_dev->ibd_bd = NULL; | 213 | ib_dev->ibd_bd = NULL; |
213 | ib_dev->ibd_major = 0; | 214 | ib_dev->ibd_major = 0; |
214 | ib_dev->ibd_minor = 0; | 215 | ib_dev->ibd_minor = 0; |
215 | return NULL; | 216 | return ERR_PTR(ret); |
216 | } | 217 | } |
217 | 218 | ||
218 | static void iblock_free_device(void *p) | 219 | static void iblock_free_device(void *p) |
@@ -467,7 +468,7 @@ static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba, | |||
467 | const char *page, ssize_t count) | 468 | const char *page, ssize_t count) |
468 | { | 469 | { |
469 | struct iblock_dev *ib_dev = se_dev->se_dev_su_ptr; | 470 | struct iblock_dev *ib_dev = se_dev->se_dev_su_ptr; |
470 | char *orig, *ptr, *opts; | 471 | char *orig, *ptr, *arg_p, *opts; |
471 | substring_t args[MAX_OPT_ARGS]; | 472 | substring_t args[MAX_OPT_ARGS]; |
472 | int ret = 0, arg, token; | 473 | int ret = 0, arg, token; |
473 | 474 | ||
@@ -490,9 +491,14 @@ static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba, | |||
490 | ret = -EEXIST; | 491 | ret = -EEXIST; |
491 | goto out; | 492 | goto out; |
492 | } | 493 | } |
493 | 494 | arg_p = match_strdup(&args[0]); | |
494 | ret = snprintf(ib_dev->ibd_udev_path, SE_UDEV_PATH_LEN, | 495 | if (!arg_p) { |
495 | "%s", match_strdup(&args[0])); | 496 | ret = -ENOMEM; |
497 | break; | ||
498 | } | ||
499 | snprintf(ib_dev->ibd_udev_path, SE_UDEV_PATH_LEN, | ||
500 | "%s", arg_p); | ||
501 | kfree(arg_p); | ||
496 | printk(KERN_INFO "IBLOCK: Referencing UDEV path: %s\n", | 502 | printk(KERN_INFO "IBLOCK: Referencing UDEV path: %s\n", |
497 | ib_dev->ibd_udev_path); | 503 | ib_dev->ibd_udev_path); |
498 | ib_dev->ibd_flags |= IBDF_HAS_UDEV_PATH; | 504 | ib_dev->ibd_flags |= IBDF_HAS_UDEV_PATH; |
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 5a9d2ba4b609..7ff6a35f26ac 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c | |||
@@ -441,6 +441,7 @@ static struct se_device *pscsi_create_type_disk( | |||
441 | struct pscsi_dev_virt *pdv, | 441 | struct pscsi_dev_virt *pdv, |
442 | struct se_subsystem_dev *se_dev, | 442 | struct se_subsystem_dev *se_dev, |
443 | struct se_hba *hba) | 443 | struct se_hba *hba) |
444 | __releases(sh->host_lock) | ||
444 | { | 445 | { |
445 | struct se_device *dev; | 446 | struct se_device *dev; |
446 | struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; | 447 | struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; |
@@ -488,6 +489,7 @@ static struct se_device *pscsi_create_type_rom( | |||
488 | struct pscsi_dev_virt *pdv, | 489 | struct pscsi_dev_virt *pdv, |
489 | struct se_subsystem_dev *se_dev, | 490 | struct se_subsystem_dev *se_dev, |
490 | struct se_hba *hba) | 491 | struct se_hba *hba) |
492 | __releases(sh->host_lock) | ||
491 | { | 493 | { |
492 | struct se_device *dev; | 494 | struct se_device *dev; |
493 | struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; | 495 | struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; |
@@ -522,6 +524,7 @@ static struct se_device *pscsi_create_type_other( | |||
522 | struct pscsi_dev_virt *pdv, | 524 | struct pscsi_dev_virt *pdv, |
523 | struct se_subsystem_dev *se_dev, | 525 | struct se_subsystem_dev *se_dev, |
524 | struct se_hba *hba) | 526 | struct se_hba *hba) |
527 | __releases(sh->host_lock) | ||
525 | { | 528 | { |
526 | struct se_device *dev; | 529 | struct se_device *dev; |
527 | struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; | 530 | struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; |
@@ -555,7 +558,7 @@ static struct se_device *pscsi_create_virtdevice( | |||
555 | if (!(pdv)) { | 558 | if (!(pdv)) { |
556 | printk(KERN_ERR "Unable to locate struct pscsi_dev_virt" | 559 | printk(KERN_ERR "Unable to locate struct pscsi_dev_virt" |
557 | " parameter\n"); | 560 | " parameter\n"); |
558 | return NULL; | 561 | return ERR_PTR(-EINVAL); |
559 | } | 562 | } |
560 | /* | 563 | /* |
561 | * If not running in PHV_LLD_SCSI_HOST_NO mode, locate the | 564 | * If not running in PHV_LLD_SCSI_HOST_NO mode, locate the |
@@ -565,7 +568,7 @@ static struct se_device *pscsi_create_virtdevice( | |||
565 | if (phv->phv_mode == PHV_LLD_SCSI_HOST_NO) { | 568 | if (phv->phv_mode == PHV_LLD_SCSI_HOST_NO) { |
566 | printk(KERN_ERR "pSCSI: Unable to locate struct" | 569 | printk(KERN_ERR "pSCSI: Unable to locate struct" |
567 | " Scsi_Host for PHV_LLD_SCSI_HOST_NO\n"); | 570 | " Scsi_Host for PHV_LLD_SCSI_HOST_NO\n"); |
568 | return NULL; | 571 | return ERR_PTR(-ENODEV); |
569 | } | 572 | } |
570 | /* | 573 | /* |
571 | * For the newer PHV_VIRUTAL_HOST_ID struct scsi_device | 574 | * For the newer PHV_VIRUTAL_HOST_ID struct scsi_device |
@@ -574,7 +577,7 @@ static struct se_device *pscsi_create_virtdevice( | |||
574 | if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH)) { | 577 | if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH)) { |
575 | printk(KERN_ERR "pSCSI: udev_path attribute has not" | 578 | printk(KERN_ERR "pSCSI: udev_path attribute has not" |
576 | " been set before ENABLE=1\n"); | 579 | " been set before ENABLE=1\n"); |
577 | return NULL; | 580 | return ERR_PTR(-EINVAL); |
578 | } | 581 | } |
579 | /* | 582 | /* |
580 | * If no scsi_host_id= was passed for PHV_VIRUTAL_HOST_ID, | 583 | * If no scsi_host_id= was passed for PHV_VIRUTAL_HOST_ID, |
@@ -587,12 +590,12 @@ static struct se_device *pscsi_create_virtdevice( | |||
587 | printk(KERN_ERR "pSCSI: Unable to set hba_mode" | 590 | printk(KERN_ERR "pSCSI: Unable to set hba_mode" |
588 | " with active devices\n"); | 591 | " with active devices\n"); |
589 | spin_unlock(&hba->device_lock); | 592 | spin_unlock(&hba->device_lock); |
590 | return NULL; | 593 | return ERR_PTR(-EEXIST); |
591 | } | 594 | } |
592 | spin_unlock(&hba->device_lock); | 595 | spin_unlock(&hba->device_lock); |
593 | 596 | ||
594 | if (pscsi_pmode_enable_hba(hba, 1) != 1) | 597 | if (pscsi_pmode_enable_hba(hba, 1) != 1) |
595 | return NULL; | 598 | return ERR_PTR(-ENODEV); |
596 | 599 | ||
597 | legacy_mode_enable = 1; | 600 | legacy_mode_enable = 1; |
598 | hba->hba_flags |= HBA_FLAGS_PSCSI_MODE; | 601 | hba->hba_flags |= HBA_FLAGS_PSCSI_MODE; |
@@ -602,14 +605,14 @@ static struct se_device *pscsi_create_virtdevice( | |||
602 | if (!(sh)) { | 605 | if (!(sh)) { |
603 | printk(KERN_ERR "pSCSI: Unable to locate" | 606 | printk(KERN_ERR "pSCSI: Unable to locate" |
604 | " pdv_host_id: %d\n", pdv->pdv_host_id); | 607 | " pdv_host_id: %d\n", pdv->pdv_host_id); |
605 | return NULL; | 608 | return ERR_PTR(-ENODEV); |
606 | } | 609 | } |
607 | } | 610 | } |
608 | } else { | 611 | } else { |
609 | if (phv->phv_mode == PHV_VIRUTAL_HOST_ID) { | 612 | if (phv->phv_mode == PHV_VIRUTAL_HOST_ID) { |
610 | printk(KERN_ERR "pSCSI: PHV_VIRUTAL_HOST_ID set while" | 613 | printk(KERN_ERR "pSCSI: PHV_VIRUTAL_HOST_ID set while" |
611 | " struct Scsi_Host exists\n"); | 614 | " struct Scsi_Host exists\n"); |
612 | return NULL; | 615 | return ERR_PTR(-EEXIST); |
613 | } | 616 | } |
614 | } | 617 | } |
615 | 618 | ||
@@ -644,7 +647,7 @@ static struct se_device *pscsi_create_virtdevice( | |||
644 | hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE; | 647 | hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE; |
645 | } | 648 | } |
646 | pdv->pdv_sd = NULL; | 649 | pdv->pdv_sd = NULL; |
647 | return NULL; | 650 | return ERR_PTR(-ENODEV); |
648 | } | 651 | } |
649 | return dev; | 652 | return dev; |
650 | } | 653 | } |
@@ -660,7 +663,7 @@ static struct se_device *pscsi_create_virtdevice( | |||
660 | hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE; | 663 | hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE; |
661 | } | 664 | } |
662 | 665 | ||
663 | return NULL; | 666 | return ERR_PTR(-ENODEV); |
664 | } | 667 | } |
665 | 668 | ||
666 | /* pscsi_free_device(): (Part of se_subsystem_api_t template) | 669 | /* pscsi_free_device(): (Part of se_subsystem_api_t template) |
@@ -816,6 +819,7 @@ pscsi_alloc_task(struct se_cmd *cmd) | |||
816 | if (!(pt->pscsi_cdb)) { | 819 | if (!(pt->pscsi_cdb)) { |
817 | printk(KERN_ERR "pSCSI: Unable to allocate extended" | 820 | printk(KERN_ERR "pSCSI: Unable to allocate extended" |
818 | " pt->pscsi_cdb\n"); | 821 | " pt->pscsi_cdb\n"); |
822 | kfree(pt); | ||
819 | return NULL; | 823 | return NULL; |
820 | } | 824 | } |
821 | } else | 825 | } else |
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index 8dc6d74c1d40..7837dd365a9d 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c | |||
@@ -150,7 +150,7 @@ static int rd_build_device_space(struct rd_dev *rd_dev) | |||
150 | if (rd_dev->rd_page_count <= 0) { | 150 | if (rd_dev->rd_page_count <= 0) { |
151 | printk(KERN_ERR "Illegal page count: %u for Ramdisk device\n", | 151 | printk(KERN_ERR "Illegal page count: %u for Ramdisk device\n", |
152 | rd_dev->rd_page_count); | 152 | rd_dev->rd_page_count); |
153 | return -1; | 153 | return -EINVAL; |
154 | } | 154 | } |
155 | total_sg_needed = rd_dev->rd_page_count; | 155 | total_sg_needed = rd_dev->rd_page_count; |
156 | 156 | ||
@@ -160,7 +160,7 @@ static int rd_build_device_space(struct rd_dev *rd_dev) | |||
160 | if (!(sg_table)) { | 160 | if (!(sg_table)) { |
161 | printk(KERN_ERR "Unable to allocate memory for Ramdisk" | 161 | printk(KERN_ERR "Unable to allocate memory for Ramdisk" |
162 | " scatterlist tables\n"); | 162 | " scatterlist tables\n"); |
163 | return -1; | 163 | return -ENOMEM; |
164 | } | 164 | } |
165 | 165 | ||
166 | rd_dev->sg_table_array = sg_table; | 166 | rd_dev->sg_table_array = sg_table; |
@@ -175,7 +175,7 @@ static int rd_build_device_space(struct rd_dev *rd_dev) | |||
175 | if (!(sg)) { | 175 | if (!(sg)) { |
176 | printk(KERN_ERR "Unable to allocate scatterlist array" | 176 | printk(KERN_ERR "Unable to allocate scatterlist array" |
177 | " for struct rd_dev\n"); | 177 | " for struct rd_dev\n"); |
178 | return -1; | 178 | return -ENOMEM; |
179 | } | 179 | } |
180 | 180 | ||
181 | sg_init_table((struct scatterlist *)&sg[0], sg_per_table); | 181 | sg_init_table((struct scatterlist *)&sg[0], sg_per_table); |
@@ -191,7 +191,7 @@ static int rd_build_device_space(struct rd_dev *rd_dev) | |||
191 | if (!(pg)) { | 191 | if (!(pg)) { |
192 | printk(KERN_ERR "Unable to allocate scatterlist" | 192 | printk(KERN_ERR "Unable to allocate scatterlist" |
193 | " pages for struct rd_dev_sg_table\n"); | 193 | " pages for struct rd_dev_sg_table\n"); |
194 | return -1; | 194 | return -ENOMEM; |
195 | } | 195 | } |
196 | sg_assign_page(&sg[j], pg); | 196 | sg_assign_page(&sg[j], pg); |
197 | sg[j].length = PAGE_SIZE; | 197 | sg[j].length = PAGE_SIZE; |
@@ -253,12 +253,13 @@ static struct se_device *rd_create_virtdevice( | |||
253 | struct se_dev_limits dev_limits; | 253 | struct se_dev_limits dev_limits; |
254 | struct rd_dev *rd_dev = p; | 254 | struct rd_dev *rd_dev = p; |
255 | struct rd_host *rd_host = hba->hba_ptr; | 255 | struct rd_host *rd_host = hba->hba_ptr; |
256 | int dev_flags = 0; | 256 | int dev_flags = 0, ret; |
257 | char prod[16], rev[4]; | 257 | char prod[16], rev[4]; |
258 | 258 | ||
259 | memset(&dev_limits, 0, sizeof(struct se_dev_limits)); | 259 | memset(&dev_limits, 0, sizeof(struct se_dev_limits)); |
260 | 260 | ||
261 | if (rd_build_device_space(rd_dev) < 0) | 261 | ret = rd_build_device_space(rd_dev); |
262 | if (ret < 0) | ||
262 | goto fail; | 263 | goto fail; |
263 | 264 | ||
264 | snprintf(prod, 16, "RAMDISK-%s", (rd_dev->rd_direct) ? "DR" : "MCP"); | 265 | snprintf(prod, 16, "RAMDISK-%s", (rd_dev->rd_direct) ? "DR" : "MCP"); |
@@ -292,7 +293,7 @@ static struct se_device *rd_create_virtdevice( | |||
292 | 293 | ||
293 | fail: | 294 | fail: |
294 | rd_release_device_space(rd_dev); | 295 | rd_release_device_space(rd_dev); |
295 | return NULL; | 296 | return ERR_PTR(ret); |
296 | } | 297 | } |
297 | 298 | ||
298 | static struct se_device *rd_DIRECT_create_virtdevice( | 299 | static struct se_device *rd_DIRECT_create_virtdevice( |
diff --git a/drivers/target/target_core_rd.h b/drivers/target/target_core_rd.h index 13badfbaf9c0..3ea19e29d8ec 100644 --- a/drivers/target/target_core_rd.h +++ b/drivers/target/target_core_rd.h | |||
@@ -14,8 +14,6 @@ | |||
14 | #define RD_BLOCKSIZE 512 | 14 | #define RD_BLOCKSIZE 512 |
15 | #define RD_MAX_SECTORS 1024 | 15 | #define RD_MAX_SECTORS 1024 |
16 | 16 | ||
17 | extern struct kmem_cache *se_mem_cache; | ||
18 | |||
19 | /* Used in target_core_init_configfs() for virtual LUN 0 access */ | 17 | /* Used in target_core_init_configfs() for virtual LUN 0 access */ |
20 | int __init rd_module_init(void); | 18 | int __init rd_module_init(void); |
21 | void rd_module_exit(void); | 19 | void rd_module_exit(void); |
diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c new file mode 100644 index 000000000000..5e3a067a7475 --- /dev/null +++ b/drivers/target/target_core_stat.c | |||
@@ -0,0 +1,1810 @@ | |||
1 | /******************************************************************************* | ||
2 | * Filename: target_core_stat.c | ||
3 | * | ||
4 | * Copyright (c) 2011 Rising Tide Systems | ||
5 | * Copyright (c) 2011 Linux-iSCSI.org | ||
6 | * | ||
7 | * Modern ConfigFS group context specific statistics based on original | ||
8 | * target_core_mib.c code | ||
9 | * | ||
10 | * Copyright (c) 2006-2007 SBE, Inc. All Rights Reserved. | ||
11 | * | ||
12 | * Nicholas A. Bellinger <nab@linux-iscsi.org> | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
27 | * | ||
28 | ******************************************************************************/ | ||
29 | |||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/timer.h> | ||
34 | #include <linux/string.h> | ||
35 | #include <linux/version.h> | ||
36 | #include <generated/utsrelease.h> | ||
37 | #include <linux/utsname.h> | ||
38 | #include <linux/proc_fs.h> | ||
39 | #include <linux/seq_file.h> | ||
40 | #include <linux/blkdev.h> | ||
41 | #include <linux/configfs.h> | ||
42 | #include <scsi/scsi.h> | ||
43 | #include <scsi/scsi_device.h> | ||
44 | #include <scsi/scsi_host.h> | ||
45 | |||
46 | #include <target/target_core_base.h> | ||
47 | #include <target/target_core_transport.h> | ||
48 | #include <target/target_core_fabric_ops.h> | ||
49 | #include <target/target_core_configfs.h> | ||
50 | #include <target/configfs_macros.h> | ||
51 | |||
52 | #include "target_core_hba.h" | ||
53 | |||
54 | #ifndef INITIAL_JIFFIES | ||
55 | #define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) | ||
56 | #endif | ||
57 | |||
58 | #define NONE "None" | ||
59 | #define ISPRINT(a) ((a >= ' ') && (a <= '~')) | ||
60 | |||
61 | #define SCSI_LU_INDEX 1 | ||
62 | #define LU_COUNT 1 | ||
63 | |||
64 | /* | ||
65 | * SCSI Device Table | ||
66 | */ | ||
67 | |||
68 | CONFIGFS_EATTR_STRUCT(target_stat_scsi_dev, se_dev_stat_grps); | ||
69 | #define DEV_STAT_SCSI_DEV_ATTR(_name, _mode) \ | ||
70 | static struct target_stat_scsi_dev_attribute \ | ||
71 | target_stat_scsi_dev_##_name = \ | ||
72 | __CONFIGFS_EATTR(_name, _mode, \ | ||
73 | target_stat_scsi_dev_show_attr_##_name, \ | ||
74 | target_stat_scsi_dev_store_attr_##_name); | ||
75 | |||
76 | #define DEV_STAT_SCSI_DEV_ATTR_RO(_name) \ | ||
77 | static struct target_stat_scsi_dev_attribute \ | ||
78 | target_stat_scsi_dev_##_name = \ | ||
79 | __CONFIGFS_EATTR_RO(_name, \ | ||
80 | target_stat_scsi_dev_show_attr_##_name); | ||
81 | |||
82 | static ssize_t target_stat_scsi_dev_show_attr_inst( | ||
83 | struct se_dev_stat_grps *sgrps, char *page) | ||
84 | { | ||
85 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
86 | struct se_subsystem_dev, dev_stat_grps); | ||
87 | struct se_hba *hba = se_subdev->se_dev_hba; | ||
88 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
89 | |||
90 | if (!dev) | ||
91 | return -ENODEV; | ||
92 | |||
93 | return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); | ||
94 | } | ||
95 | DEV_STAT_SCSI_DEV_ATTR_RO(inst); | ||
96 | |||
97 | static ssize_t target_stat_scsi_dev_show_attr_indx( | ||
98 | struct se_dev_stat_grps *sgrps, char *page) | ||
99 | { | ||
100 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
101 | struct se_subsystem_dev, dev_stat_grps); | ||
102 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
103 | |||
104 | if (!dev) | ||
105 | return -ENODEV; | ||
106 | |||
107 | return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); | ||
108 | } | ||
109 | DEV_STAT_SCSI_DEV_ATTR_RO(indx); | ||
110 | |||
111 | static ssize_t target_stat_scsi_dev_show_attr_role( | ||
112 | struct se_dev_stat_grps *sgrps, char *page) | ||
113 | { | ||
114 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
115 | struct se_subsystem_dev, dev_stat_grps); | ||
116 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
117 | |||
118 | if (!dev) | ||
119 | return -ENODEV; | ||
120 | |||
121 | return snprintf(page, PAGE_SIZE, "Target\n"); | ||
122 | } | ||
123 | DEV_STAT_SCSI_DEV_ATTR_RO(role); | ||
124 | |||
125 | static ssize_t target_stat_scsi_dev_show_attr_ports( | ||
126 | struct se_dev_stat_grps *sgrps, char *page) | ||
127 | { | ||
128 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
129 | struct se_subsystem_dev, dev_stat_grps); | ||
130 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
131 | |||
132 | if (!dev) | ||
133 | return -ENODEV; | ||
134 | |||
135 | return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_port_count); | ||
136 | } | ||
137 | DEV_STAT_SCSI_DEV_ATTR_RO(ports); | ||
138 | |||
139 | CONFIGFS_EATTR_OPS(target_stat_scsi_dev, se_dev_stat_grps, scsi_dev_group); | ||
140 | |||
141 | static struct configfs_attribute *target_stat_scsi_dev_attrs[] = { | ||
142 | &target_stat_scsi_dev_inst.attr, | ||
143 | &target_stat_scsi_dev_indx.attr, | ||
144 | &target_stat_scsi_dev_role.attr, | ||
145 | &target_stat_scsi_dev_ports.attr, | ||
146 | NULL, | ||
147 | }; | ||
148 | |||
149 | static struct configfs_item_operations target_stat_scsi_dev_attrib_ops = { | ||
150 | .show_attribute = target_stat_scsi_dev_attr_show, | ||
151 | .store_attribute = target_stat_scsi_dev_attr_store, | ||
152 | }; | ||
153 | |||
154 | static struct config_item_type target_stat_scsi_dev_cit = { | ||
155 | .ct_item_ops = &target_stat_scsi_dev_attrib_ops, | ||
156 | .ct_attrs = target_stat_scsi_dev_attrs, | ||
157 | .ct_owner = THIS_MODULE, | ||
158 | }; | ||
159 | |||
160 | /* | ||
161 | * SCSI Target Device Table | ||
162 | */ | ||
163 | |||
164 | CONFIGFS_EATTR_STRUCT(target_stat_scsi_tgt_dev, se_dev_stat_grps); | ||
165 | #define DEV_STAT_SCSI_TGT_DEV_ATTR(_name, _mode) \ | ||
166 | static struct target_stat_scsi_tgt_dev_attribute \ | ||
167 | target_stat_scsi_tgt_dev_##_name = \ | ||
168 | __CONFIGFS_EATTR(_name, _mode, \ | ||
169 | target_stat_scsi_tgt_dev_show_attr_##_name, \ | ||
170 | target_stat_scsi_tgt_dev_store_attr_##_name); | ||
171 | |||
172 | #define DEV_STAT_SCSI_TGT_DEV_ATTR_RO(_name) \ | ||
173 | static struct target_stat_scsi_tgt_dev_attribute \ | ||
174 | target_stat_scsi_tgt_dev_##_name = \ | ||
175 | __CONFIGFS_EATTR_RO(_name, \ | ||
176 | target_stat_scsi_tgt_dev_show_attr_##_name); | ||
177 | |||
178 | static ssize_t target_stat_scsi_tgt_dev_show_attr_inst( | ||
179 | struct se_dev_stat_grps *sgrps, char *page) | ||
180 | { | ||
181 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
182 | struct se_subsystem_dev, dev_stat_grps); | ||
183 | struct se_hba *hba = se_subdev->se_dev_hba; | ||
184 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
185 | |||
186 | if (!dev) | ||
187 | return -ENODEV; | ||
188 | |||
189 | return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); | ||
190 | } | ||
191 | DEV_STAT_SCSI_TGT_DEV_ATTR_RO(inst); | ||
192 | |||
193 | static ssize_t target_stat_scsi_tgt_dev_show_attr_indx( | ||
194 | struct se_dev_stat_grps *sgrps, char *page) | ||
195 | { | ||
196 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
197 | struct se_subsystem_dev, dev_stat_grps); | ||
198 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
199 | |||
200 | if (!dev) | ||
201 | return -ENODEV; | ||
202 | |||
203 | return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); | ||
204 | } | ||
205 | DEV_STAT_SCSI_TGT_DEV_ATTR_RO(indx); | ||
206 | |||
207 | static ssize_t target_stat_scsi_tgt_dev_show_attr_num_lus( | ||
208 | struct se_dev_stat_grps *sgrps, char *page) | ||
209 | { | ||
210 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
211 | struct se_subsystem_dev, dev_stat_grps); | ||
212 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
213 | |||
214 | if (!dev) | ||
215 | return -ENODEV; | ||
216 | |||
217 | return snprintf(page, PAGE_SIZE, "%u\n", LU_COUNT); | ||
218 | } | ||
219 | DEV_STAT_SCSI_TGT_DEV_ATTR_RO(num_lus); | ||
220 | |||
221 | static ssize_t target_stat_scsi_tgt_dev_show_attr_status( | ||
222 | struct se_dev_stat_grps *sgrps, char *page) | ||
223 | { | ||
224 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
225 | struct se_subsystem_dev, dev_stat_grps); | ||
226 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
227 | char status[16]; | ||
228 | |||
229 | if (!dev) | ||
230 | return -ENODEV; | ||
231 | |||
232 | switch (dev->dev_status) { | ||
233 | case TRANSPORT_DEVICE_ACTIVATED: | ||
234 | strcpy(status, "activated"); | ||
235 | break; | ||
236 | case TRANSPORT_DEVICE_DEACTIVATED: | ||
237 | strcpy(status, "deactivated"); | ||
238 | break; | ||
239 | case TRANSPORT_DEVICE_SHUTDOWN: | ||
240 | strcpy(status, "shutdown"); | ||
241 | break; | ||
242 | case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: | ||
243 | case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: | ||
244 | strcpy(status, "offline"); | ||
245 | break; | ||
246 | default: | ||
247 | sprintf(status, "unknown(%d)", dev->dev_status); | ||
248 | break; | ||
249 | } | ||
250 | |||
251 | return snprintf(page, PAGE_SIZE, "%s\n", status); | ||
252 | } | ||
253 | DEV_STAT_SCSI_TGT_DEV_ATTR_RO(status); | ||
254 | |||
255 | static ssize_t target_stat_scsi_tgt_dev_show_attr_non_access_lus( | ||
256 | struct se_dev_stat_grps *sgrps, char *page) | ||
257 | { | ||
258 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
259 | struct se_subsystem_dev, dev_stat_grps); | ||
260 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
261 | int non_accessible_lus; | ||
262 | |||
263 | if (!dev) | ||
264 | return -ENODEV; | ||
265 | |||
266 | switch (dev->dev_status) { | ||
267 | case TRANSPORT_DEVICE_ACTIVATED: | ||
268 | non_accessible_lus = 0; | ||
269 | break; | ||
270 | case TRANSPORT_DEVICE_DEACTIVATED: | ||
271 | case TRANSPORT_DEVICE_SHUTDOWN: | ||
272 | case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: | ||
273 | case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: | ||
274 | default: | ||
275 | non_accessible_lus = 1; | ||
276 | break; | ||
277 | } | ||
278 | |||
279 | return snprintf(page, PAGE_SIZE, "%u\n", non_accessible_lus); | ||
280 | } | ||
281 | DEV_STAT_SCSI_TGT_DEV_ATTR_RO(non_access_lus); | ||
282 | |||
283 | static ssize_t target_stat_scsi_tgt_dev_show_attr_resets( | ||
284 | struct se_dev_stat_grps *sgrps, char *page) | ||
285 | { | ||
286 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
287 | struct se_subsystem_dev, dev_stat_grps); | ||
288 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
289 | |||
290 | if (!dev) | ||
291 | return -ENODEV; | ||
292 | |||
293 | return snprintf(page, PAGE_SIZE, "%u\n", dev->num_resets); | ||
294 | } | ||
295 | DEV_STAT_SCSI_TGT_DEV_ATTR_RO(resets); | ||
296 | |||
297 | |||
298 | CONFIGFS_EATTR_OPS(target_stat_scsi_tgt_dev, se_dev_stat_grps, scsi_tgt_dev_group); | ||
299 | |||
300 | static struct configfs_attribute *target_stat_scsi_tgt_dev_attrs[] = { | ||
301 | &target_stat_scsi_tgt_dev_inst.attr, | ||
302 | &target_stat_scsi_tgt_dev_indx.attr, | ||
303 | &target_stat_scsi_tgt_dev_num_lus.attr, | ||
304 | &target_stat_scsi_tgt_dev_status.attr, | ||
305 | &target_stat_scsi_tgt_dev_non_access_lus.attr, | ||
306 | &target_stat_scsi_tgt_dev_resets.attr, | ||
307 | NULL, | ||
308 | }; | ||
309 | |||
310 | static struct configfs_item_operations target_stat_scsi_tgt_dev_attrib_ops = { | ||
311 | .show_attribute = target_stat_scsi_tgt_dev_attr_show, | ||
312 | .store_attribute = target_stat_scsi_tgt_dev_attr_store, | ||
313 | }; | ||
314 | |||
315 | static struct config_item_type target_stat_scsi_tgt_dev_cit = { | ||
316 | .ct_item_ops = &target_stat_scsi_tgt_dev_attrib_ops, | ||
317 | .ct_attrs = target_stat_scsi_tgt_dev_attrs, | ||
318 | .ct_owner = THIS_MODULE, | ||
319 | }; | ||
320 | |||
321 | /* | ||
322 | * SCSI Logical Unit Table | ||
323 | */ | ||
324 | |||
325 | CONFIGFS_EATTR_STRUCT(target_stat_scsi_lu, se_dev_stat_grps); | ||
326 | #define DEV_STAT_SCSI_LU_ATTR(_name, _mode) \ | ||
327 | static struct target_stat_scsi_lu_attribute target_stat_scsi_lu_##_name = \ | ||
328 | __CONFIGFS_EATTR(_name, _mode, \ | ||
329 | target_stat_scsi_lu_show_attr_##_name, \ | ||
330 | target_stat_scsi_lu_store_attr_##_name); | ||
331 | |||
332 | #define DEV_STAT_SCSI_LU_ATTR_RO(_name) \ | ||
333 | static struct target_stat_scsi_lu_attribute target_stat_scsi_lu_##_name = \ | ||
334 | __CONFIGFS_EATTR_RO(_name, \ | ||
335 | target_stat_scsi_lu_show_attr_##_name); | ||
336 | |||
337 | static ssize_t target_stat_scsi_lu_show_attr_inst( | ||
338 | struct se_dev_stat_grps *sgrps, char *page) | ||
339 | { | ||
340 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
341 | struct se_subsystem_dev, dev_stat_grps); | ||
342 | struct se_hba *hba = se_subdev->se_dev_hba; | ||
343 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
344 | |||
345 | if (!dev) | ||
346 | return -ENODEV; | ||
347 | |||
348 | return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); | ||
349 | } | ||
350 | DEV_STAT_SCSI_LU_ATTR_RO(inst); | ||
351 | |||
352 | static ssize_t target_stat_scsi_lu_show_attr_dev( | ||
353 | struct se_dev_stat_grps *sgrps, char *page) | ||
354 | { | ||
355 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
356 | struct se_subsystem_dev, dev_stat_grps); | ||
357 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
358 | |||
359 | if (!dev) | ||
360 | return -ENODEV; | ||
361 | |||
362 | return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); | ||
363 | } | ||
364 | DEV_STAT_SCSI_LU_ATTR_RO(dev); | ||
365 | |||
366 | static ssize_t target_stat_scsi_lu_show_attr_indx( | ||
367 | struct se_dev_stat_grps *sgrps, char *page) | ||
368 | { | ||
369 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
370 | struct se_subsystem_dev, dev_stat_grps); | ||
371 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
372 | |||
373 | if (!dev) | ||
374 | return -ENODEV; | ||
375 | |||
376 | return snprintf(page, PAGE_SIZE, "%u\n", SCSI_LU_INDEX); | ||
377 | } | ||
378 | DEV_STAT_SCSI_LU_ATTR_RO(indx); | ||
379 | |||
380 | static ssize_t target_stat_scsi_lu_show_attr_lun( | ||
381 | struct se_dev_stat_grps *sgrps, char *page) | ||
382 | { | ||
383 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
384 | struct se_subsystem_dev, dev_stat_grps); | ||
385 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
386 | |||
387 | if (!dev) | ||
388 | return -ENODEV; | ||
389 | /* FIXME: scsiLuDefaultLun */ | ||
390 | return snprintf(page, PAGE_SIZE, "%llu\n", (unsigned long long)0); | ||
391 | } | ||
392 | DEV_STAT_SCSI_LU_ATTR_RO(lun); | ||
393 | |||
394 | static ssize_t target_stat_scsi_lu_show_attr_lu_name( | ||
395 | struct se_dev_stat_grps *sgrps, char *page) | ||
396 | { | ||
397 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
398 | struct se_subsystem_dev, dev_stat_grps); | ||
399 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
400 | |||
401 | if (!dev) | ||
402 | return -ENODEV; | ||
403 | /* scsiLuWwnName */ | ||
404 | return snprintf(page, PAGE_SIZE, "%s\n", | ||
405 | (strlen(DEV_T10_WWN(dev)->unit_serial)) ? | ||
406 | (char *)&DEV_T10_WWN(dev)->unit_serial[0] : "None"); | ||
407 | } | ||
408 | DEV_STAT_SCSI_LU_ATTR_RO(lu_name); | ||
409 | |||
410 | static ssize_t target_stat_scsi_lu_show_attr_vend( | ||
411 | struct se_dev_stat_grps *sgrps, char *page) | ||
412 | { | ||
413 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
414 | struct se_subsystem_dev, dev_stat_grps); | ||
415 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
416 | int j; | ||
417 | char str[28]; | ||
418 | |||
419 | if (!dev) | ||
420 | return -ENODEV; | ||
421 | /* scsiLuVendorId */ | ||
422 | memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); | ||
423 | for (j = 0; j < 8; j++) | ||
424 | str[j] = ISPRINT(DEV_T10_WWN(dev)->vendor[j]) ? | ||
425 | DEV_T10_WWN(dev)->vendor[j] : 0x20; | ||
426 | str[8] = 0; | ||
427 | return snprintf(page, PAGE_SIZE, "%s\n", str); | ||
428 | } | ||
429 | DEV_STAT_SCSI_LU_ATTR_RO(vend); | ||
430 | |||
431 | static ssize_t target_stat_scsi_lu_show_attr_prod( | ||
432 | struct se_dev_stat_grps *sgrps, char *page) | ||
433 | { | ||
434 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
435 | struct se_subsystem_dev, dev_stat_grps); | ||
436 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
437 | int j; | ||
438 | char str[28]; | ||
439 | |||
440 | if (!dev) | ||
441 | return -ENODEV; | ||
442 | |||
443 | /* scsiLuProductId */ | ||
444 | memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); | ||
445 | for (j = 0; j < 16; j++) | ||
446 | str[j] = ISPRINT(DEV_T10_WWN(dev)->model[j]) ? | ||
447 | DEV_T10_WWN(dev)->model[j] : 0x20; | ||
448 | str[16] = 0; | ||
449 | return snprintf(page, PAGE_SIZE, "%s\n", str); | ||
450 | } | ||
451 | DEV_STAT_SCSI_LU_ATTR_RO(prod); | ||
452 | |||
453 | static ssize_t target_stat_scsi_lu_show_attr_rev( | ||
454 | struct se_dev_stat_grps *sgrps, char *page) | ||
455 | { | ||
456 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
457 | struct se_subsystem_dev, dev_stat_grps); | ||
458 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
459 | int j; | ||
460 | char str[28]; | ||
461 | |||
462 | if (!dev) | ||
463 | return -ENODEV; | ||
464 | |||
465 | /* scsiLuRevisionId */ | ||
466 | memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); | ||
467 | for (j = 0; j < 4; j++) | ||
468 | str[j] = ISPRINT(DEV_T10_WWN(dev)->revision[j]) ? | ||
469 | DEV_T10_WWN(dev)->revision[j] : 0x20; | ||
470 | str[4] = 0; | ||
471 | return snprintf(page, PAGE_SIZE, "%s\n", str); | ||
472 | } | ||
473 | DEV_STAT_SCSI_LU_ATTR_RO(rev); | ||
474 | |||
475 | static ssize_t target_stat_scsi_lu_show_attr_dev_type( | ||
476 | struct se_dev_stat_grps *sgrps, char *page) | ||
477 | { | ||
478 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
479 | struct se_subsystem_dev, dev_stat_grps); | ||
480 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
481 | |||
482 | if (!dev) | ||
483 | return -ENODEV; | ||
484 | |||
485 | /* scsiLuPeripheralType */ | ||
486 | return snprintf(page, PAGE_SIZE, "%u\n", | ||
487 | TRANSPORT(dev)->get_device_type(dev)); | ||
488 | } | ||
489 | DEV_STAT_SCSI_LU_ATTR_RO(dev_type); | ||
490 | |||
491 | static ssize_t target_stat_scsi_lu_show_attr_status( | ||
492 | struct se_dev_stat_grps *sgrps, char *page) | ||
493 | { | ||
494 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
495 | struct se_subsystem_dev, dev_stat_grps); | ||
496 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
497 | |||
498 | if (!dev) | ||
499 | return -ENODEV; | ||
500 | |||
501 | /* scsiLuStatus */ | ||
502 | return snprintf(page, PAGE_SIZE, "%s\n", | ||
503 | (dev->dev_status == TRANSPORT_DEVICE_ACTIVATED) ? | ||
504 | "available" : "notavailable"); | ||
505 | } | ||
506 | DEV_STAT_SCSI_LU_ATTR_RO(status); | ||
507 | |||
508 | static ssize_t target_stat_scsi_lu_show_attr_state_bit( | ||
509 | struct se_dev_stat_grps *sgrps, char *page) | ||
510 | { | ||
511 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
512 | struct se_subsystem_dev, dev_stat_grps); | ||
513 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
514 | |||
515 | if (!dev) | ||
516 | return -ENODEV; | ||
517 | |||
518 | /* scsiLuState */ | ||
519 | return snprintf(page, PAGE_SIZE, "exposed\n"); | ||
520 | } | ||
521 | DEV_STAT_SCSI_LU_ATTR_RO(state_bit); | ||
522 | |||
523 | static ssize_t target_stat_scsi_lu_show_attr_num_cmds( | ||
524 | struct se_dev_stat_grps *sgrps, char *page) | ||
525 | { | ||
526 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
527 | struct se_subsystem_dev, dev_stat_grps); | ||
528 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
529 | |||
530 | if (!dev) | ||
531 | return -ENODEV; | ||
532 | |||
533 | /* scsiLuNumCommands */ | ||
534 | return snprintf(page, PAGE_SIZE, "%llu\n", | ||
535 | (unsigned long long)dev->num_cmds); | ||
536 | } | ||
537 | DEV_STAT_SCSI_LU_ATTR_RO(num_cmds); | ||
538 | |||
539 | static ssize_t target_stat_scsi_lu_show_attr_read_mbytes( | ||
540 | struct se_dev_stat_grps *sgrps, char *page) | ||
541 | { | ||
542 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
543 | struct se_subsystem_dev, dev_stat_grps); | ||
544 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
545 | |||
546 | if (!dev) | ||
547 | return -ENODEV; | ||
548 | |||
549 | /* scsiLuReadMegaBytes */ | ||
550 | return snprintf(page, PAGE_SIZE, "%u\n", (u32)(dev->read_bytes >> 20)); | ||
551 | } | ||
552 | DEV_STAT_SCSI_LU_ATTR_RO(read_mbytes); | ||
553 | |||
554 | static ssize_t target_stat_scsi_lu_show_attr_write_mbytes( | ||
555 | struct se_dev_stat_grps *sgrps, char *page) | ||
556 | { | ||
557 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
558 | struct se_subsystem_dev, dev_stat_grps); | ||
559 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
560 | |||
561 | if (!dev) | ||
562 | return -ENODEV; | ||
563 | |||
564 | /* scsiLuWrittenMegaBytes */ | ||
565 | return snprintf(page, PAGE_SIZE, "%u\n", (u32)(dev->write_bytes >> 20)); | ||
566 | } | ||
567 | DEV_STAT_SCSI_LU_ATTR_RO(write_mbytes); | ||
568 | |||
569 | static ssize_t target_stat_scsi_lu_show_attr_resets( | ||
570 | struct se_dev_stat_grps *sgrps, char *page) | ||
571 | { | ||
572 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
573 | struct se_subsystem_dev, dev_stat_grps); | ||
574 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
575 | |||
576 | if (!dev) | ||
577 | return -ENODEV; | ||
578 | |||
579 | /* scsiLuInResets */ | ||
580 | return snprintf(page, PAGE_SIZE, "%u\n", dev->num_resets); | ||
581 | } | ||
582 | DEV_STAT_SCSI_LU_ATTR_RO(resets); | ||
583 | |||
584 | static ssize_t target_stat_scsi_lu_show_attr_full_stat( | ||
585 | struct se_dev_stat_grps *sgrps, char *page) | ||
586 | { | ||
587 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
588 | struct se_subsystem_dev, dev_stat_grps); | ||
589 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
590 | |||
591 | if (!dev) | ||
592 | return -ENODEV; | ||
593 | |||
594 | /* FIXME: scsiLuOutTaskSetFullStatus */ | ||
595 | return snprintf(page, PAGE_SIZE, "%u\n", 0); | ||
596 | } | ||
597 | DEV_STAT_SCSI_LU_ATTR_RO(full_stat); | ||
598 | |||
599 | static ssize_t target_stat_scsi_lu_show_attr_hs_num_cmds( | ||
600 | struct se_dev_stat_grps *sgrps, char *page) | ||
601 | { | ||
602 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
603 | struct se_subsystem_dev, dev_stat_grps); | ||
604 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
605 | |||
606 | if (!dev) | ||
607 | return -ENODEV; | ||
608 | |||
609 | /* FIXME: scsiLuHSInCommands */ | ||
610 | return snprintf(page, PAGE_SIZE, "%u\n", 0); | ||
611 | } | ||
612 | DEV_STAT_SCSI_LU_ATTR_RO(hs_num_cmds); | ||
613 | |||
614 | static ssize_t target_stat_scsi_lu_show_attr_creation_time( | ||
615 | struct se_dev_stat_grps *sgrps, char *page) | ||
616 | { | ||
617 | struct se_subsystem_dev *se_subdev = container_of(sgrps, | ||
618 | struct se_subsystem_dev, dev_stat_grps); | ||
619 | struct se_device *dev = se_subdev->se_dev_ptr; | ||
620 | |||
621 | if (!dev) | ||
622 | return -ENODEV; | ||
623 | |||
624 | /* scsiLuCreationTime */ | ||
625 | return snprintf(page, PAGE_SIZE, "%u\n", (u32)(((u32)dev->creation_time - | ||
626 | INITIAL_JIFFIES) * 100 / HZ)); | ||
627 | } | ||
628 | DEV_STAT_SCSI_LU_ATTR_RO(creation_time); | ||
629 | |||
630 | CONFIGFS_EATTR_OPS(target_stat_scsi_lu, se_dev_stat_grps, scsi_lu_group); | ||
631 | |||
632 | static struct configfs_attribute *target_stat_scsi_lu_attrs[] = { | ||
633 | &target_stat_scsi_lu_inst.attr, | ||
634 | &target_stat_scsi_lu_dev.attr, | ||
635 | &target_stat_scsi_lu_indx.attr, | ||
636 | &target_stat_scsi_lu_lun.attr, | ||
637 | &target_stat_scsi_lu_lu_name.attr, | ||
638 | &target_stat_scsi_lu_vend.attr, | ||
639 | &target_stat_scsi_lu_prod.attr, | ||
640 | &target_stat_scsi_lu_rev.attr, | ||
641 | &target_stat_scsi_lu_dev_type.attr, | ||
642 | &target_stat_scsi_lu_status.attr, | ||
643 | &target_stat_scsi_lu_state_bit.attr, | ||
644 | &target_stat_scsi_lu_num_cmds.attr, | ||
645 | &target_stat_scsi_lu_read_mbytes.attr, | ||
646 | &target_stat_scsi_lu_write_mbytes.attr, | ||
647 | &target_stat_scsi_lu_resets.attr, | ||
648 | &target_stat_scsi_lu_full_stat.attr, | ||
649 | &target_stat_scsi_lu_hs_num_cmds.attr, | ||
650 | &target_stat_scsi_lu_creation_time.attr, | ||
651 | NULL, | ||
652 | }; | ||
653 | |||
654 | static struct configfs_item_operations target_stat_scsi_lu_attrib_ops = { | ||
655 | .show_attribute = target_stat_scsi_lu_attr_show, | ||
656 | .store_attribute = target_stat_scsi_lu_attr_store, | ||
657 | }; | ||
658 | |||
659 | static struct config_item_type target_stat_scsi_lu_cit = { | ||
660 | .ct_item_ops = &target_stat_scsi_lu_attrib_ops, | ||
661 | .ct_attrs = target_stat_scsi_lu_attrs, | ||
662 | .ct_owner = THIS_MODULE, | ||
663 | }; | ||
664 | |||
665 | /* | ||
666 | * Called from target_core_configfs.c:target_core_make_subdev() to setup | ||
667 | * the target statistics groups + configfs CITs located in target_core_stat.c | ||
668 | */ | ||
669 | void target_stat_setup_dev_default_groups(struct se_subsystem_dev *se_subdev) | ||
670 | { | ||
671 | struct config_group *dev_stat_grp = &DEV_STAT_GRP(se_subdev)->stat_group; | ||
672 | |||
673 | config_group_init_type_name(&DEV_STAT_GRP(se_subdev)->scsi_dev_group, | ||
674 | "scsi_dev", &target_stat_scsi_dev_cit); | ||
675 | config_group_init_type_name(&DEV_STAT_GRP(se_subdev)->scsi_tgt_dev_group, | ||
676 | "scsi_tgt_dev", &target_stat_scsi_tgt_dev_cit); | ||
677 | config_group_init_type_name(&DEV_STAT_GRP(se_subdev)->scsi_lu_group, | ||
678 | "scsi_lu", &target_stat_scsi_lu_cit); | ||
679 | |||
680 | dev_stat_grp->default_groups[0] = &DEV_STAT_GRP(se_subdev)->scsi_dev_group; | ||
681 | dev_stat_grp->default_groups[1] = &DEV_STAT_GRP(se_subdev)->scsi_tgt_dev_group; | ||
682 | dev_stat_grp->default_groups[2] = &DEV_STAT_GRP(se_subdev)->scsi_lu_group; | ||
683 | dev_stat_grp->default_groups[3] = NULL; | ||
684 | } | ||
685 | |||
686 | /* | ||
687 | * SCSI Port Table | ||
688 | */ | ||
689 | |||
690 | CONFIGFS_EATTR_STRUCT(target_stat_scsi_port, se_port_stat_grps); | ||
691 | #define DEV_STAT_SCSI_PORT_ATTR(_name, _mode) \ | ||
692 | static struct target_stat_scsi_port_attribute \ | ||
693 | target_stat_scsi_port_##_name = \ | ||
694 | __CONFIGFS_EATTR(_name, _mode, \ | ||
695 | target_stat_scsi_port_show_attr_##_name, \ | ||
696 | target_stat_scsi_port_store_attr_##_name); | ||
697 | |||
698 | #define DEV_STAT_SCSI_PORT_ATTR_RO(_name) \ | ||
699 | static struct target_stat_scsi_port_attribute \ | ||
700 | target_stat_scsi_port_##_name = \ | ||
701 | __CONFIGFS_EATTR_RO(_name, \ | ||
702 | target_stat_scsi_port_show_attr_##_name); | ||
703 | |||
704 | static ssize_t target_stat_scsi_port_show_attr_inst( | ||
705 | struct se_port_stat_grps *pgrps, char *page) | ||
706 | { | ||
707 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
708 | struct se_port *sep; | ||
709 | struct se_device *dev = lun->lun_se_dev; | ||
710 | struct se_hba *hba; | ||
711 | ssize_t ret; | ||
712 | |||
713 | spin_lock(&lun->lun_sep_lock); | ||
714 | sep = lun->lun_sep; | ||
715 | if (!sep) { | ||
716 | spin_unlock(&lun->lun_sep_lock); | ||
717 | return -ENODEV; | ||
718 | } | ||
719 | hba = dev->se_hba; | ||
720 | ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); | ||
721 | spin_unlock(&lun->lun_sep_lock); | ||
722 | return ret; | ||
723 | } | ||
724 | DEV_STAT_SCSI_PORT_ATTR_RO(inst); | ||
725 | |||
726 | static ssize_t target_stat_scsi_port_show_attr_dev( | ||
727 | struct se_port_stat_grps *pgrps, char *page) | ||
728 | { | ||
729 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
730 | struct se_port *sep; | ||
731 | struct se_device *dev = lun->lun_se_dev; | ||
732 | ssize_t ret; | ||
733 | |||
734 | spin_lock(&lun->lun_sep_lock); | ||
735 | sep = lun->lun_sep; | ||
736 | if (!sep) { | ||
737 | spin_unlock(&lun->lun_sep_lock); | ||
738 | return -ENODEV; | ||
739 | } | ||
740 | ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); | ||
741 | spin_unlock(&lun->lun_sep_lock); | ||
742 | return ret; | ||
743 | } | ||
744 | DEV_STAT_SCSI_PORT_ATTR_RO(dev); | ||
745 | |||
746 | static ssize_t target_stat_scsi_port_show_attr_indx( | ||
747 | struct se_port_stat_grps *pgrps, char *page) | ||
748 | { | ||
749 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
750 | struct se_port *sep; | ||
751 | ssize_t ret; | ||
752 | |||
753 | spin_lock(&lun->lun_sep_lock); | ||
754 | sep = lun->lun_sep; | ||
755 | if (!sep) { | ||
756 | spin_unlock(&lun->lun_sep_lock); | ||
757 | return -ENODEV; | ||
758 | } | ||
759 | ret = snprintf(page, PAGE_SIZE, "%u\n", sep->sep_index); | ||
760 | spin_unlock(&lun->lun_sep_lock); | ||
761 | return ret; | ||
762 | } | ||
763 | DEV_STAT_SCSI_PORT_ATTR_RO(indx); | ||
764 | |||
765 | static ssize_t target_stat_scsi_port_show_attr_role( | ||
766 | struct se_port_stat_grps *pgrps, char *page) | ||
767 | { | ||
768 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
769 | struct se_device *dev = lun->lun_se_dev; | ||
770 | struct se_port *sep; | ||
771 | ssize_t ret; | ||
772 | |||
773 | if (!dev) | ||
774 | return -ENODEV; | ||
775 | |||
776 | spin_lock(&lun->lun_sep_lock); | ||
777 | sep = lun->lun_sep; | ||
778 | if (!sep) { | ||
779 | spin_unlock(&lun->lun_sep_lock); | ||
780 | return -ENODEV; | ||
781 | } | ||
782 | ret = snprintf(page, PAGE_SIZE, "%s%u\n", "Device", dev->dev_index); | ||
783 | spin_unlock(&lun->lun_sep_lock); | ||
784 | return ret; | ||
785 | } | ||
786 | DEV_STAT_SCSI_PORT_ATTR_RO(role); | ||
787 | |||
788 | static ssize_t target_stat_scsi_port_show_attr_busy_count( | ||
789 | struct se_port_stat_grps *pgrps, char *page) | ||
790 | { | ||
791 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
792 | struct se_port *sep; | ||
793 | ssize_t ret; | ||
794 | |||
795 | spin_lock(&lun->lun_sep_lock); | ||
796 | sep = lun->lun_sep; | ||
797 | if (!sep) { | ||
798 | spin_unlock(&lun->lun_sep_lock); | ||
799 | return -ENODEV; | ||
800 | } | ||
801 | /* FIXME: scsiPortBusyStatuses */ | ||
802 | ret = snprintf(page, PAGE_SIZE, "%u\n", 0); | ||
803 | spin_unlock(&lun->lun_sep_lock); | ||
804 | return ret; | ||
805 | } | ||
806 | DEV_STAT_SCSI_PORT_ATTR_RO(busy_count); | ||
807 | |||
808 | CONFIGFS_EATTR_OPS(target_stat_scsi_port, se_port_stat_grps, scsi_port_group); | ||
809 | |||
810 | static struct configfs_attribute *target_stat_scsi_port_attrs[] = { | ||
811 | &target_stat_scsi_port_inst.attr, | ||
812 | &target_stat_scsi_port_dev.attr, | ||
813 | &target_stat_scsi_port_indx.attr, | ||
814 | &target_stat_scsi_port_role.attr, | ||
815 | &target_stat_scsi_port_busy_count.attr, | ||
816 | NULL, | ||
817 | }; | ||
818 | |||
819 | static struct configfs_item_operations target_stat_scsi_port_attrib_ops = { | ||
820 | .show_attribute = target_stat_scsi_port_attr_show, | ||
821 | .store_attribute = target_stat_scsi_port_attr_store, | ||
822 | }; | ||
823 | |||
824 | static struct config_item_type target_stat_scsi_port_cit = { | ||
825 | .ct_item_ops = &target_stat_scsi_port_attrib_ops, | ||
826 | .ct_attrs = target_stat_scsi_port_attrs, | ||
827 | .ct_owner = THIS_MODULE, | ||
828 | }; | ||
829 | |||
830 | /* | ||
831 | * SCSI Target Port Table | ||
832 | */ | ||
833 | CONFIGFS_EATTR_STRUCT(target_stat_scsi_tgt_port, se_port_stat_grps); | ||
834 | #define DEV_STAT_SCSI_TGT_PORT_ATTR(_name, _mode) \ | ||
835 | static struct target_stat_scsi_tgt_port_attribute \ | ||
836 | target_stat_scsi_tgt_port_##_name = \ | ||
837 | __CONFIGFS_EATTR(_name, _mode, \ | ||
838 | target_stat_scsi_tgt_port_show_attr_##_name, \ | ||
839 | target_stat_scsi_tgt_port_store_attr_##_name); | ||
840 | |||
841 | #define DEV_STAT_SCSI_TGT_PORT_ATTR_RO(_name) \ | ||
842 | static struct target_stat_scsi_tgt_port_attribute \ | ||
843 | target_stat_scsi_tgt_port_##_name = \ | ||
844 | __CONFIGFS_EATTR_RO(_name, \ | ||
845 | target_stat_scsi_tgt_port_show_attr_##_name); | ||
846 | |||
847 | static ssize_t target_stat_scsi_tgt_port_show_attr_inst( | ||
848 | struct se_port_stat_grps *pgrps, char *page) | ||
849 | { | ||
850 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
851 | struct se_device *dev = lun->lun_se_dev; | ||
852 | struct se_port *sep; | ||
853 | struct se_hba *hba; | ||
854 | ssize_t ret; | ||
855 | |||
856 | spin_lock(&lun->lun_sep_lock); | ||
857 | sep = lun->lun_sep; | ||
858 | if (!sep) { | ||
859 | spin_unlock(&lun->lun_sep_lock); | ||
860 | return -ENODEV; | ||
861 | } | ||
862 | hba = dev->se_hba; | ||
863 | ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); | ||
864 | spin_unlock(&lun->lun_sep_lock); | ||
865 | return ret; | ||
866 | } | ||
867 | DEV_STAT_SCSI_TGT_PORT_ATTR_RO(inst); | ||
868 | |||
869 | static ssize_t target_stat_scsi_tgt_port_show_attr_dev( | ||
870 | struct se_port_stat_grps *pgrps, char *page) | ||
871 | { | ||
872 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
873 | struct se_device *dev = lun->lun_se_dev; | ||
874 | struct se_port *sep; | ||
875 | ssize_t ret; | ||
876 | |||
877 | spin_lock(&lun->lun_sep_lock); | ||
878 | sep = lun->lun_sep; | ||
879 | if (!sep) { | ||
880 | spin_unlock(&lun->lun_sep_lock); | ||
881 | return -ENODEV; | ||
882 | } | ||
883 | ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); | ||
884 | spin_unlock(&lun->lun_sep_lock); | ||
885 | return ret; | ||
886 | } | ||
887 | DEV_STAT_SCSI_TGT_PORT_ATTR_RO(dev); | ||
888 | |||
889 | static ssize_t target_stat_scsi_tgt_port_show_attr_indx( | ||
890 | struct se_port_stat_grps *pgrps, char *page) | ||
891 | { | ||
892 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
893 | struct se_port *sep; | ||
894 | ssize_t ret; | ||
895 | |||
896 | spin_lock(&lun->lun_sep_lock); | ||
897 | sep = lun->lun_sep; | ||
898 | if (!sep) { | ||
899 | spin_unlock(&lun->lun_sep_lock); | ||
900 | return -ENODEV; | ||
901 | } | ||
902 | ret = snprintf(page, PAGE_SIZE, "%u\n", sep->sep_index); | ||
903 | spin_unlock(&lun->lun_sep_lock); | ||
904 | return ret; | ||
905 | } | ||
906 | DEV_STAT_SCSI_TGT_PORT_ATTR_RO(indx); | ||
907 | |||
908 | static ssize_t target_stat_scsi_tgt_port_show_attr_name( | ||
909 | struct se_port_stat_grps *pgrps, char *page) | ||
910 | { | ||
911 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
912 | struct se_port *sep; | ||
913 | struct se_portal_group *tpg; | ||
914 | ssize_t ret; | ||
915 | |||
916 | spin_lock(&lun->lun_sep_lock); | ||
917 | sep = lun->lun_sep; | ||
918 | if (!sep) { | ||
919 | spin_unlock(&lun->lun_sep_lock); | ||
920 | return -ENODEV; | ||
921 | } | ||
922 | tpg = sep->sep_tpg; | ||
923 | |||
924 | ret = snprintf(page, PAGE_SIZE, "%sPort#%u\n", | ||
925 | TPG_TFO(tpg)->get_fabric_name(), sep->sep_index); | ||
926 | spin_unlock(&lun->lun_sep_lock); | ||
927 | return ret; | ||
928 | } | ||
929 | DEV_STAT_SCSI_TGT_PORT_ATTR_RO(name); | ||
930 | |||
931 | static ssize_t target_stat_scsi_tgt_port_show_attr_port_index( | ||
932 | struct se_port_stat_grps *pgrps, char *page) | ||
933 | { | ||
934 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
935 | struct se_port *sep; | ||
936 | struct se_portal_group *tpg; | ||
937 | ssize_t ret; | ||
938 | |||
939 | spin_lock(&lun->lun_sep_lock); | ||
940 | sep = lun->lun_sep; | ||
941 | if (!sep) { | ||
942 | spin_unlock(&lun->lun_sep_lock); | ||
943 | return -ENODEV; | ||
944 | } | ||
945 | tpg = sep->sep_tpg; | ||
946 | |||
947 | ret = snprintf(page, PAGE_SIZE, "%s%s%d\n", | ||
948 | TPG_TFO(tpg)->tpg_get_wwn(tpg), "+t+", | ||
949 | TPG_TFO(tpg)->tpg_get_tag(tpg)); | ||
950 | spin_unlock(&lun->lun_sep_lock); | ||
951 | return ret; | ||
952 | } | ||
953 | DEV_STAT_SCSI_TGT_PORT_ATTR_RO(port_index); | ||
954 | |||
955 | static ssize_t target_stat_scsi_tgt_port_show_attr_in_cmds( | ||
956 | struct se_port_stat_grps *pgrps, char *page) | ||
957 | { | ||
958 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
959 | struct se_port *sep; | ||
960 | struct se_portal_group *tpg; | ||
961 | ssize_t ret; | ||
962 | |||
963 | spin_lock(&lun->lun_sep_lock); | ||
964 | sep = lun->lun_sep; | ||
965 | if (!sep) { | ||
966 | spin_unlock(&lun->lun_sep_lock); | ||
967 | return -ENODEV; | ||
968 | } | ||
969 | tpg = sep->sep_tpg; | ||
970 | |||
971 | ret = snprintf(page, PAGE_SIZE, "%llu\n", sep->sep_stats.cmd_pdus); | ||
972 | spin_unlock(&lun->lun_sep_lock); | ||
973 | return ret; | ||
974 | } | ||
975 | DEV_STAT_SCSI_TGT_PORT_ATTR_RO(in_cmds); | ||
976 | |||
977 | static ssize_t target_stat_scsi_tgt_port_show_attr_write_mbytes( | ||
978 | struct se_port_stat_grps *pgrps, char *page) | ||
979 | { | ||
980 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
981 | struct se_port *sep; | ||
982 | struct se_portal_group *tpg; | ||
983 | ssize_t ret; | ||
984 | |||
985 | spin_lock(&lun->lun_sep_lock); | ||
986 | sep = lun->lun_sep; | ||
987 | if (!sep) { | ||
988 | spin_unlock(&lun->lun_sep_lock); | ||
989 | return -ENODEV; | ||
990 | } | ||
991 | tpg = sep->sep_tpg; | ||
992 | |||
993 | ret = snprintf(page, PAGE_SIZE, "%u\n", | ||
994 | (u32)(sep->sep_stats.rx_data_octets >> 20)); | ||
995 | spin_unlock(&lun->lun_sep_lock); | ||
996 | return ret; | ||
997 | } | ||
998 | DEV_STAT_SCSI_TGT_PORT_ATTR_RO(write_mbytes); | ||
999 | |||
1000 | static ssize_t target_stat_scsi_tgt_port_show_attr_read_mbytes( | ||
1001 | struct se_port_stat_grps *pgrps, char *page) | ||
1002 | { | ||
1003 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
1004 | struct se_port *sep; | ||
1005 | struct se_portal_group *tpg; | ||
1006 | ssize_t ret; | ||
1007 | |||
1008 | spin_lock(&lun->lun_sep_lock); | ||
1009 | sep = lun->lun_sep; | ||
1010 | if (!sep) { | ||
1011 | spin_unlock(&lun->lun_sep_lock); | ||
1012 | return -ENODEV; | ||
1013 | } | ||
1014 | tpg = sep->sep_tpg; | ||
1015 | |||
1016 | ret = snprintf(page, PAGE_SIZE, "%u\n", | ||
1017 | (u32)(sep->sep_stats.tx_data_octets >> 20)); | ||
1018 | spin_unlock(&lun->lun_sep_lock); | ||
1019 | return ret; | ||
1020 | } | ||
1021 | DEV_STAT_SCSI_TGT_PORT_ATTR_RO(read_mbytes); | ||
1022 | |||
1023 | static ssize_t target_stat_scsi_tgt_port_show_attr_hs_in_cmds( | ||
1024 | struct se_port_stat_grps *pgrps, char *page) | ||
1025 | { | ||
1026 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
1027 | struct se_port *sep; | ||
1028 | struct se_portal_group *tpg; | ||
1029 | ssize_t ret; | ||
1030 | |||
1031 | spin_lock(&lun->lun_sep_lock); | ||
1032 | sep = lun->lun_sep; | ||
1033 | if (!sep) { | ||
1034 | spin_unlock(&lun->lun_sep_lock); | ||
1035 | return -ENODEV; | ||
1036 | } | ||
1037 | tpg = sep->sep_tpg; | ||
1038 | |||
1039 | /* FIXME: scsiTgtPortHsInCommands */ | ||
1040 | ret = snprintf(page, PAGE_SIZE, "%u\n", 0); | ||
1041 | spin_unlock(&lun->lun_sep_lock); | ||
1042 | return ret; | ||
1043 | } | ||
1044 | DEV_STAT_SCSI_TGT_PORT_ATTR_RO(hs_in_cmds); | ||
1045 | |||
1046 | CONFIGFS_EATTR_OPS(target_stat_scsi_tgt_port, se_port_stat_grps, | ||
1047 | scsi_tgt_port_group); | ||
1048 | |||
1049 | static struct configfs_attribute *target_stat_scsi_tgt_port_attrs[] = { | ||
1050 | &target_stat_scsi_tgt_port_inst.attr, | ||
1051 | &target_stat_scsi_tgt_port_dev.attr, | ||
1052 | &target_stat_scsi_tgt_port_indx.attr, | ||
1053 | &target_stat_scsi_tgt_port_name.attr, | ||
1054 | &target_stat_scsi_tgt_port_port_index.attr, | ||
1055 | &target_stat_scsi_tgt_port_in_cmds.attr, | ||
1056 | &target_stat_scsi_tgt_port_write_mbytes.attr, | ||
1057 | &target_stat_scsi_tgt_port_read_mbytes.attr, | ||
1058 | &target_stat_scsi_tgt_port_hs_in_cmds.attr, | ||
1059 | NULL, | ||
1060 | }; | ||
1061 | |||
1062 | static struct configfs_item_operations target_stat_scsi_tgt_port_attrib_ops = { | ||
1063 | .show_attribute = target_stat_scsi_tgt_port_attr_show, | ||
1064 | .store_attribute = target_stat_scsi_tgt_port_attr_store, | ||
1065 | }; | ||
1066 | |||
1067 | static struct config_item_type target_stat_scsi_tgt_port_cit = { | ||
1068 | .ct_item_ops = &target_stat_scsi_tgt_port_attrib_ops, | ||
1069 | .ct_attrs = target_stat_scsi_tgt_port_attrs, | ||
1070 | .ct_owner = THIS_MODULE, | ||
1071 | }; | ||
1072 | |||
1073 | /* | ||
1074 | * SCSI Transport Table | ||
1075 | o */ | ||
1076 | |||
1077 | CONFIGFS_EATTR_STRUCT(target_stat_scsi_transport, se_port_stat_grps); | ||
1078 | #define DEV_STAT_SCSI_TRANSPORT_ATTR(_name, _mode) \ | ||
1079 | static struct target_stat_scsi_transport_attribute \ | ||
1080 | target_stat_scsi_transport_##_name = \ | ||
1081 | __CONFIGFS_EATTR(_name, _mode, \ | ||
1082 | target_stat_scsi_transport_show_attr_##_name, \ | ||
1083 | target_stat_scsi_transport_store_attr_##_name); | ||
1084 | |||
1085 | #define DEV_STAT_SCSI_TRANSPORT_ATTR_RO(_name) \ | ||
1086 | static struct target_stat_scsi_transport_attribute \ | ||
1087 | target_stat_scsi_transport_##_name = \ | ||
1088 | __CONFIGFS_EATTR_RO(_name, \ | ||
1089 | target_stat_scsi_transport_show_attr_##_name); | ||
1090 | |||
1091 | static ssize_t target_stat_scsi_transport_show_attr_inst( | ||
1092 | struct se_port_stat_grps *pgrps, char *page) | ||
1093 | { | ||
1094 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
1095 | struct se_device *dev = lun->lun_se_dev; | ||
1096 | struct se_port *sep; | ||
1097 | struct se_hba *hba; | ||
1098 | ssize_t ret; | ||
1099 | |||
1100 | spin_lock(&lun->lun_sep_lock); | ||
1101 | sep = lun->lun_sep; | ||
1102 | if (!sep) { | ||
1103 | spin_unlock(&lun->lun_sep_lock); | ||
1104 | return -ENODEV; | ||
1105 | } | ||
1106 | |||
1107 | hba = dev->se_hba; | ||
1108 | ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); | ||
1109 | spin_unlock(&lun->lun_sep_lock); | ||
1110 | return ret; | ||
1111 | } | ||
1112 | DEV_STAT_SCSI_TRANSPORT_ATTR_RO(inst); | ||
1113 | |||
1114 | static ssize_t target_stat_scsi_transport_show_attr_device( | ||
1115 | struct se_port_stat_grps *pgrps, char *page) | ||
1116 | { | ||
1117 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
1118 | struct se_port *sep; | ||
1119 | struct se_portal_group *tpg; | ||
1120 | ssize_t ret; | ||
1121 | |||
1122 | spin_lock(&lun->lun_sep_lock); | ||
1123 | sep = lun->lun_sep; | ||
1124 | if (!sep) { | ||
1125 | spin_unlock(&lun->lun_sep_lock); | ||
1126 | return -ENODEV; | ||
1127 | } | ||
1128 | tpg = sep->sep_tpg; | ||
1129 | /* scsiTransportType */ | ||
1130 | ret = snprintf(page, PAGE_SIZE, "scsiTransport%s\n", | ||
1131 | TPG_TFO(tpg)->get_fabric_name()); | ||
1132 | spin_unlock(&lun->lun_sep_lock); | ||
1133 | return ret; | ||
1134 | } | ||
1135 | DEV_STAT_SCSI_TRANSPORT_ATTR_RO(device); | ||
1136 | |||
1137 | static ssize_t target_stat_scsi_transport_show_attr_indx( | ||
1138 | struct se_port_stat_grps *pgrps, char *page) | ||
1139 | { | ||
1140 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
1141 | struct se_port *sep; | ||
1142 | struct se_portal_group *tpg; | ||
1143 | ssize_t ret; | ||
1144 | |||
1145 | spin_lock(&lun->lun_sep_lock); | ||
1146 | sep = lun->lun_sep; | ||
1147 | if (!sep) { | ||
1148 | spin_unlock(&lun->lun_sep_lock); | ||
1149 | return -ENODEV; | ||
1150 | } | ||
1151 | tpg = sep->sep_tpg; | ||
1152 | ret = snprintf(page, PAGE_SIZE, "%u\n", | ||
1153 | TPG_TFO(tpg)->tpg_get_inst_index(tpg)); | ||
1154 | spin_unlock(&lun->lun_sep_lock); | ||
1155 | return ret; | ||
1156 | } | ||
1157 | DEV_STAT_SCSI_TRANSPORT_ATTR_RO(indx); | ||
1158 | |||
1159 | static ssize_t target_stat_scsi_transport_show_attr_dev_name( | ||
1160 | struct se_port_stat_grps *pgrps, char *page) | ||
1161 | { | ||
1162 | struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); | ||
1163 | struct se_device *dev = lun->lun_se_dev; | ||
1164 | struct se_port *sep; | ||
1165 | struct se_portal_group *tpg; | ||
1166 | struct t10_wwn *wwn; | ||
1167 | ssize_t ret; | ||
1168 | |||
1169 | spin_lock(&lun->lun_sep_lock); | ||
1170 | sep = lun->lun_sep; | ||
1171 | if (!sep) { | ||
1172 | spin_unlock(&lun->lun_sep_lock); | ||
1173 | return -ENODEV; | ||
1174 | } | ||
1175 | tpg = sep->sep_tpg; | ||
1176 | wwn = DEV_T10_WWN(dev); | ||
1177 | /* scsiTransportDevName */ | ||
1178 | ret = snprintf(page, PAGE_SIZE, "%s+%s\n", | ||
1179 | TPG_TFO(tpg)->tpg_get_wwn(tpg), | ||
1180 | (strlen(wwn->unit_serial)) ? wwn->unit_serial : | ||
1181 | wwn->vendor); | ||
1182 | spin_unlock(&lun->lun_sep_lock); | ||
1183 | return ret; | ||
1184 | } | ||
1185 | DEV_STAT_SCSI_TRANSPORT_ATTR_RO(dev_name); | ||
1186 | |||
1187 | CONFIGFS_EATTR_OPS(target_stat_scsi_transport, se_port_stat_grps, | ||
1188 | scsi_transport_group); | ||
1189 | |||
1190 | static struct configfs_attribute *target_stat_scsi_transport_attrs[] = { | ||
1191 | &target_stat_scsi_transport_inst.attr, | ||
1192 | &target_stat_scsi_transport_device.attr, | ||
1193 | &target_stat_scsi_transport_indx.attr, | ||
1194 | &target_stat_scsi_transport_dev_name.attr, | ||
1195 | NULL, | ||
1196 | }; | ||
1197 | |||
1198 | static struct configfs_item_operations target_stat_scsi_transport_attrib_ops = { | ||
1199 | .show_attribute = target_stat_scsi_transport_attr_show, | ||
1200 | .store_attribute = target_stat_scsi_transport_attr_store, | ||
1201 | }; | ||
1202 | |||
1203 | static struct config_item_type target_stat_scsi_transport_cit = { | ||
1204 | .ct_item_ops = &target_stat_scsi_transport_attrib_ops, | ||
1205 | .ct_attrs = target_stat_scsi_transport_attrs, | ||
1206 | .ct_owner = THIS_MODULE, | ||
1207 | }; | ||
1208 | |||
1209 | /* | ||
1210 | * Called from target_core_fabric_configfs.c:target_fabric_make_lun() to setup | ||
1211 | * the target port statistics groups + configfs CITs located in target_core_stat.c | ||
1212 | */ | ||
1213 | void target_stat_setup_port_default_groups(struct se_lun *lun) | ||
1214 | { | ||
1215 | struct config_group *port_stat_grp = &PORT_STAT_GRP(lun)->stat_group; | ||
1216 | |||
1217 | config_group_init_type_name(&PORT_STAT_GRP(lun)->scsi_port_group, | ||
1218 | "scsi_port", &target_stat_scsi_port_cit); | ||
1219 | config_group_init_type_name(&PORT_STAT_GRP(lun)->scsi_tgt_port_group, | ||
1220 | "scsi_tgt_port", &target_stat_scsi_tgt_port_cit); | ||
1221 | config_group_init_type_name(&PORT_STAT_GRP(lun)->scsi_transport_group, | ||
1222 | "scsi_transport", &target_stat_scsi_transport_cit); | ||
1223 | |||
1224 | port_stat_grp->default_groups[0] = &PORT_STAT_GRP(lun)->scsi_port_group; | ||
1225 | port_stat_grp->default_groups[1] = &PORT_STAT_GRP(lun)->scsi_tgt_port_group; | ||
1226 | port_stat_grp->default_groups[2] = &PORT_STAT_GRP(lun)->scsi_transport_group; | ||
1227 | port_stat_grp->default_groups[3] = NULL; | ||
1228 | } | ||
1229 | |||
1230 | /* | ||
1231 | * SCSI Authorized Initiator Table | ||
1232 | */ | ||
1233 | |||
1234 | CONFIGFS_EATTR_STRUCT(target_stat_scsi_auth_intr, se_ml_stat_grps); | ||
1235 | #define DEV_STAT_SCSI_AUTH_INTR_ATTR(_name, _mode) \ | ||
1236 | static struct target_stat_scsi_auth_intr_attribute \ | ||
1237 | target_stat_scsi_auth_intr_##_name = \ | ||
1238 | __CONFIGFS_EATTR(_name, _mode, \ | ||
1239 | target_stat_scsi_auth_intr_show_attr_##_name, \ | ||
1240 | target_stat_scsi_auth_intr_store_attr_##_name); | ||
1241 | |||
1242 | #define DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(_name) \ | ||
1243 | static struct target_stat_scsi_auth_intr_attribute \ | ||
1244 | target_stat_scsi_auth_intr_##_name = \ | ||
1245 | __CONFIGFS_EATTR_RO(_name, \ | ||
1246 | target_stat_scsi_auth_intr_show_attr_##_name); | ||
1247 | |||
1248 | static ssize_t target_stat_scsi_auth_intr_show_attr_inst( | ||
1249 | struct se_ml_stat_grps *lgrps, char *page) | ||
1250 | { | ||
1251 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1252 | struct se_lun_acl, ml_stat_grps); | ||
1253 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1254 | struct se_dev_entry *deve; | ||
1255 | struct se_portal_group *tpg; | ||
1256 | ssize_t ret; | ||
1257 | |||
1258 | spin_lock_irq(&nacl->device_list_lock); | ||
1259 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1260 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1261 | spin_unlock_irq(&nacl->device_list_lock); | ||
1262 | return -ENODEV; | ||
1263 | } | ||
1264 | tpg = nacl->se_tpg; | ||
1265 | /* scsiInstIndex */ | ||
1266 | ret = snprintf(page, PAGE_SIZE, "%u\n", | ||
1267 | TPG_TFO(tpg)->tpg_get_inst_index(tpg)); | ||
1268 | spin_unlock_irq(&nacl->device_list_lock); | ||
1269 | return ret; | ||
1270 | } | ||
1271 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(inst); | ||
1272 | |||
1273 | static ssize_t target_stat_scsi_auth_intr_show_attr_dev( | ||
1274 | struct se_ml_stat_grps *lgrps, char *page) | ||
1275 | { | ||
1276 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1277 | struct se_lun_acl, ml_stat_grps); | ||
1278 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1279 | struct se_dev_entry *deve; | ||
1280 | struct se_lun *lun; | ||
1281 | struct se_portal_group *tpg; | ||
1282 | ssize_t ret; | ||
1283 | |||
1284 | spin_lock_irq(&nacl->device_list_lock); | ||
1285 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1286 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1287 | spin_unlock_irq(&nacl->device_list_lock); | ||
1288 | return -ENODEV; | ||
1289 | } | ||
1290 | tpg = nacl->se_tpg; | ||
1291 | lun = deve->se_lun; | ||
1292 | /* scsiDeviceIndex */ | ||
1293 | ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_se_dev->dev_index); | ||
1294 | spin_unlock_irq(&nacl->device_list_lock); | ||
1295 | return ret; | ||
1296 | } | ||
1297 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(dev); | ||
1298 | |||
1299 | static ssize_t target_stat_scsi_auth_intr_show_attr_port( | ||
1300 | struct se_ml_stat_grps *lgrps, char *page) | ||
1301 | { | ||
1302 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1303 | struct se_lun_acl, ml_stat_grps); | ||
1304 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1305 | struct se_dev_entry *deve; | ||
1306 | struct se_portal_group *tpg; | ||
1307 | ssize_t ret; | ||
1308 | |||
1309 | spin_lock_irq(&nacl->device_list_lock); | ||
1310 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1311 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1312 | spin_unlock_irq(&nacl->device_list_lock); | ||
1313 | return -ENODEV; | ||
1314 | } | ||
1315 | tpg = nacl->se_tpg; | ||
1316 | /* scsiAuthIntrTgtPortIndex */ | ||
1317 | ret = snprintf(page, PAGE_SIZE, "%u\n", TPG_TFO(tpg)->tpg_get_tag(tpg)); | ||
1318 | spin_unlock_irq(&nacl->device_list_lock); | ||
1319 | return ret; | ||
1320 | } | ||
1321 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(port); | ||
1322 | |||
1323 | static ssize_t target_stat_scsi_auth_intr_show_attr_indx( | ||
1324 | struct se_ml_stat_grps *lgrps, char *page) | ||
1325 | { | ||
1326 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1327 | struct se_lun_acl, ml_stat_grps); | ||
1328 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1329 | struct se_dev_entry *deve; | ||
1330 | ssize_t ret; | ||
1331 | |||
1332 | spin_lock_irq(&nacl->device_list_lock); | ||
1333 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1334 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1335 | spin_unlock_irq(&nacl->device_list_lock); | ||
1336 | return -ENODEV; | ||
1337 | } | ||
1338 | /* scsiAuthIntrIndex */ | ||
1339 | ret = snprintf(page, PAGE_SIZE, "%u\n", nacl->acl_index); | ||
1340 | spin_unlock_irq(&nacl->device_list_lock); | ||
1341 | return ret; | ||
1342 | } | ||
1343 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(indx); | ||
1344 | |||
1345 | static ssize_t target_stat_scsi_auth_intr_show_attr_dev_or_port( | ||
1346 | struct se_ml_stat_grps *lgrps, char *page) | ||
1347 | { | ||
1348 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1349 | struct se_lun_acl, ml_stat_grps); | ||
1350 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1351 | struct se_dev_entry *deve; | ||
1352 | ssize_t ret; | ||
1353 | |||
1354 | spin_lock_irq(&nacl->device_list_lock); | ||
1355 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1356 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1357 | spin_unlock_irq(&nacl->device_list_lock); | ||
1358 | return -ENODEV; | ||
1359 | } | ||
1360 | /* scsiAuthIntrDevOrPort */ | ||
1361 | ret = snprintf(page, PAGE_SIZE, "%u\n", 1); | ||
1362 | spin_unlock_irq(&nacl->device_list_lock); | ||
1363 | return ret; | ||
1364 | } | ||
1365 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(dev_or_port); | ||
1366 | |||
1367 | static ssize_t target_stat_scsi_auth_intr_show_attr_intr_name( | ||
1368 | struct se_ml_stat_grps *lgrps, char *page) | ||
1369 | { | ||
1370 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1371 | struct se_lun_acl, ml_stat_grps); | ||
1372 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1373 | struct se_dev_entry *deve; | ||
1374 | ssize_t ret; | ||
1375 | |||
1376 | spin_lock_irq(&nacl->device_list_lock); | ||
1377 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1378 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1379 | spin_unlock_irq(&nacl->device_list_lock); | ||
1380 | return -ENODEV; | ||
1381 | } | ||
1382 | /* scsiAuthIntrName */ | ||
1383 | ret = snprintf(page, PAGE_SIZE, "%s\n", nacl->initiatorname); | ||
1384 | spin_unlock_irq(&nacl->device_list_lock); | ||
1385 | return ret; | ||
1386 | } | ||
1387 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(intr_name); | ||
1388 | |||
1389 | static ssize_t target_stat_scsi_auth_intr_show_attr_map_indx( | ||
1390 | struct se_ml_stat_grps *lgrps, char *page) | ||
1391 | { | ||
1392 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1393 | struct se_lun_acl, ml_stat_grps); | ||
1394 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1395 | struct se_dev_entry *deve; | ||
1396 | ssize_t ret; | ||
1397 | |||
1398 | spin_lock_irq(&nacl->device_list_lock); | ||
1399 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1400 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1401 | spin_unlock_irq(&nacl->device_list_lock); | ||
1402 | return -ENODEV; | ||
1403 | } | ||
1404 | /* FIXME: scsiAuthIntrLunMapIndex */ | ||
1405 | ret = snprintf(page, PAGE_SIZE, "%u\n", 0); | ||
1406 | spin_unlock_irq(&nacl->device_list_lock); | ||
1407 | return ret; | ||
1408 | } | ||
1409 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(map_indx); | ||
1410 | |||
1411 | static ssize_t target_stat_scsi_auth_intr_show_attr_att_count( | ||
1412 | struct se_ml_stat_grps *lgrps, char *page) | ||
1413 | { | ||
1414 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1415 | struct se_lun_acl, ml_stat_grps); | ||
1416 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1417 | struct se_dev_entry *deve; | ||
1418 | ssize_t ret; | ||
1419 | |||
1420 | spin_lock_irq(&nacl->device_list_lock); | ||
1421 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1422 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1423 | spin_unlock_irq(&nacl->device_list_lock); | ||
1424 | return -ENODEV; | ||
1425 | } | ||
1426 | /* scsiAuthIntrAttachedTimes */ | ||
1427 | ret = snprintf(page, PAGE_SIZE, "%u\n", deve->attach_count); | ||
1428 | spin_unlock_irq(&nacl->device_list_lock); | ||
1429 | return ret; | ||
1430 | } | ||
1431 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(att_count); | ||
1432 | |||
1433 | static ssize_t target_stat_scsi_auth_intr_show_attr_num_cmds( | ||
1434 | struct se_ml_stat_grps *lgrps, char *page) | ||
1435 | { | ||
1436 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1437 | struct se_lun_acl, ml_stat_grps); | ||
1438 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1439 | struct se_dev_entry *deve; | ||
1440 | ssize_t ret; | ||
1441 | |||
1442 | spin_lock_irq(&nacl->device_list_lock); | ||
1443 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1444 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1445 | spin_unlock_irq(&nacl->device_list_lock); | ||
1446 | return -ENODEV; | ||
1447 | } | ||
1448 | /* scsiAuthIntrOutCommands */ | ||
1449 | ret = snprintf(page, PAGE_SIZE, "%u\n", deve->total_cmds); | ||
1450 | spin_unlock_irq(&nacl->device_list_lock); | ||
1451 | return ret; | ||
1452 | } | ||
1453 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(num_cmds); | ||
1454 | |||
1455 | static ssize_t target_stat_scsi_auth_intr_show_attr_read_mbytes( | ||
1456 | struct se_ml_stat_grps *lgrps, char *page) | ||
1457 | { | ||
1458 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1459 | struct se_lun_acl, ml_stat_grps); | ||
1460 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1461 | struct se_dev_entry *deve; | ||
1462 | ssize_t ret; | ||
1463 | |||
1464 | spin_lock_irq(&nacl->device_list_lock); | ||
1465 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1466 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1467 | spin_unlock_irq(&nacl->device_list_lock); | ||
1468 | return -ENODEV; | ||
1469 | } | ||
1470 | /* scsiAuthIntrReadMegaBytes */ | ||
1471 | ret = snprintf(page, PAGE_SIZE, "%u\n", (u32)(deve->read_bytes >> 20)); | ||
1472 | spin_unlock_irq(&nacl->device_list_lock); | ||
1473 | return ret; | ||
1474 | } | ||
1475 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(read_mbytes); | ||
1476 | |||
1477 | static ssize_t target_stat_scsi_auth_intr_show_attr_write_mbytes( | ||
1478 | struct se_ml_stat_grps *lgrps, char *page) | ||
1479 | { | ||
1480 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1481 | struct se_lun_acl, ml_stat_grps); | ||
1482 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1483 | struct se_dev_entry *deve; | ||
1484 | ssize_t ret; | ||
1485 | |||
1486 | spin_lock_irq(&nacl->device_list_lock); | ||
1487 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1488 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1489 | spin_unlock_irq(&nacl->device_list_lock); | ||
1490 | return -ENODEV; | ||
1491 | } | ||
1492 | /* scsiAuthIntrWrittenMegaBytes */ | ||
1493 | ret = snprintf(page, PAGE_SIZE, "%u\n", (u32)(deve->write_bytes >> 20)); | ||
1494 | spin_unlock_irq(&nacl->device_list_lock); | ||
1495 | return ret; | ||
1496 | } | ||
1497 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(write_mbytes); | ||
1498 | |||
1499 | static ssize_t target_stat_scsi_auth_intr_show_attr_hs_num_cmds( | ||
1500 | struct se_ml_stat_grps *lgrps, char *page) | ||
1501 | { | ||
1502 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1503 | struct se_lun_acl, ml_stat_grps); | ||
1504 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1505 | struct se_dev_entry *deve; | ||
1506 | ssize_t ret; | ||
1507 | |||
1508 | spin_lock_irq(&nacl->device_list_lock); | ||
1509 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1510 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1511 | spin_unlock_irq(&nacl->device_list_lock); | ||
1512 | return -ENODEV; | ||
1513 | } | ||
1514 | /* FIXME: scsiAuthIntrHSOutCommands */ | ||
1515 | ret = snprintf(page, PAGE_SIZE, "%u\n", 0); | ||
1516 | spin_unlock_irq(&nacl->device_list_lock); | ||
1517 | return ret; | ||
1518 | } | ||
1519 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(hs_num_cmds); | ||
1520 | |||
1521 | static ssize_t target_stat_scsi_auth_intr_show_attr_creation_time( | ||
1522 | struct se_ml_stat_grps *lgrps, char *page) | ||
1523 | { | ||
1524 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1525 | struct se_lun_acl, ml_stat_grps); | ||
1526 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1527 | struct se_dev_entry *deve; | ||
1528 | ssize_t ret; | ||
1529 | |||
1530 | spin_lock_irq(&nacl->device_list_lock); | ||
1531 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1532 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1533 | spin_unlock_irq(&nacl->device_list_lock); | ||
1534 | return -ENODEV; | ||
1535 | } | ||
1536 | /* scsiAuthIntrLastCreation */ | ||
1537 | ret = snprintf(page, PAGE_SIZE, "%u\n", (u32)(((u32)deve->creation_time - | ||
1538 | INITIAL_JIFFIES) * 100 / HZ)); | ||
1539 | spin_unlock_irq(&nacl->device_list_lock); | ||
1540 | return ret; | ||
1541 | } | ||
1542 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(creation_time); | ||
1543 | |||
1544 | static ssize_t target_stat_scsi_auth_intr_show_attr_row_status( | ||
1545 | struct se_ml_stat_grps *lgrps, char *page) | ||
1546 | { | ||
1547 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1548 | struct se_lun_acl, ml_stat_grps); | ||
1549 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1550 | struct se_dev_entry *deve; | ||
1551 | ssize_t ret; | ||
1552 | |||
1553 | spin_lock_irq(&nacl->device_list_lock); | ||
1554 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1555 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1556 | spin_unlock_irq(&nacl->device_list_lock); | ||
1557 | return -ENODEV; | ||
1558 | } | ||
1559 | /* FIXME: scsiAuthIntrRowStatus */ | ||
1560 | ret = snprintf(page, PAGE_SIZE, "Ready\n"); | ||
1561 | spin_unlock_irq(&nacl->device_list_lock); | ||
1562 | return ret; | ||
1563 | } | ||
1564 | DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(row_status); | ||
1565 | |||
1566 | CONFIGFS_EATTR_OPS(target_stat_scsi_auth_intr, se_ml_stat_grps, | ||
1567 | scsi_auth_intr_group); | ||
1568 | |||
1569 | static struct configfs_attribute *target_stat_scsi_auth_intr_attrs[] = { | ||
1570 | &target_stat_scsi_auth_intr_inst.attr, | ||
1571 | &target_stat_scsi_auth_intr_dev.attr, | ||
1572 | &target_stat_scsi_auth_intr_port.attr, | ||
1573 | &target_stat_scsi_auth_intr_indx.attr, | ||
1574 | &target_stat_scsi_auth_intr_dev_or_port.attr, | ||
1575 | &target_stat_scsi_auth_intr_intr_name.attr, | ||
1576 | &target_stat_scsi_auth_intr_map_indx.attr, | ||
1577 | &target_stat_scsi_auth_intr_att_count.attr, | ||
1578 | &target_stat_scsi_auth_intr_num_cmds.attr, | ||
1579 | &target_stat_scsi_auth_intr_read_mbytes.attr, | ||
1580 | &target_stat_scsi_auth_intr_write_mbytes.attr, | ||
1581 | &target_stat_scsi_auth_intr_hs_num_cmds.attr, | ||
1582 | &target_stat_scsi_auth_intr_creation_time.attr, | ||
1583 | &target_stat_scsi_auth_intr_row_status.attr, | ||
1584 | NULL, | ||
1585 | }; | ||
1586 | |||
1587 | static struct configfs_item_operations target_stat_scsi_auth_intr_attrib_ops = { | ||
1588 | .show_attribute = target_stat_scsi_auth_intr_attr_show, | ||
1589 | .store_attribute = target_stat_scsi_auth_intr_attr_store, | ||
1590 | }; | ||
1591 | |||
1592 | static struct config_item_type target_stat_scsi_auth_intr_cit = { | ||
1593 | .ct_item_ops = &target_stat_scsi_auth_intr_attrib_ops, | ||
1594 | .ct_attrs = target_stat_scsi_auth_intr_attrs, | ||
1595 | .ct_owner = THIS_MODULE, | ||
1596 | }; | ||
1597 | |||
1598 | /* | ||
1599 | * SCSI Attached Initiator Port Table | ||
1600 | */ | ||
1601 | |||
1602 | CONFIGFS_EATTR_STRUCT(target_stat_scsi_att_intr_port, se_ml_stat_grps); | ||
1603 | #define DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR(_name, _mode) \ | ||
1604 | static struct target_stat_scsi_att_intr_port_attribute \ | ||
1605 | target_stat_scsi_att_intr_port_##_name = \ | ||
1606 | __CONFIGFS_EATTR(_name, _mode, \ | ||
1607 | target_stat_scsi_att_intr_port_show_attr_##_name, \ | ||
1608 | target_stat_scsi_att_intr_port_store_attr_##_name); | ||
1609 | |||
1610 | #define DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(_name) \ | ||
1611 | static struct target_stat_scsi_att_intr_port_attribute \ | ||
1612 | target_stat_scsi_att_intr_port_##_name = \ | ||
1613 | __CONFIGFS_EATTR_RO(_name, \ | ||
1614 | target_stat_scsi_att_intr_port_show_attr_##_name); | ||
1615 | |||
1616 | static ssize_t target_stat_scsi_att_intr_port_show_attr_inst( | ||
1617 | struct se_ml_stat_grps *lgrps, char *page) | ||
1618 | { | ||
1619 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1620 | struct se_lun_acl, ml_stat_grps); | ||
1621 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1622 | struct se_dev_entry *deve; | ||
1623 | struct se_portal_group *tpg; | ||
1624 | ssize_t ret; | ||
1625 | |||
1626 | spin_lock_irq(&nacl->device_list_lock); | ||
1627 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1628 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1629 | spin_unlock_irq(&nacl->device_list_lock); | ||
1630 | return -ENODEV; | ||
1631 | } | ||
1632 | tpg = nacl->se_tpg; | ||
1633 | /* scsiInstIndex */ | ||
1634 | ret = snprintf(page, PAGE_SIZE, "%u\n", | ||
1635 | TPG_TFO(tpg)->tpg_get_inst_index(tpg)); | ||
1636 | spin_unlock_irq(&nacl->device_list_lock); | ||
1637 | return ret; | ||
1638 | } | ||
1639 | DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(inst); | ||
1640 | |||
1641 | static ssize_t target_stat_scsi_att_intr_port_show_attr_dev( | ||
1642 | struct se_ml_stat_grps *lgrps, char *page) | ||
1643 | { | ||
1644 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1645 | struct se_lun_acl, ml_stat_grps); | ||
1646 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1647 | struct se_dev_entry *deve; | ||
1648 | struct se_lun *lun; | ||
1649 | struct se_portal_group *tpg; | ||
1650 | ssize_t ret; | ||
1651 | |||
1652 | spin_lock_irq(&nacl->device_list_lock); | ||
1653 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1654 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1655 | spin_unlock_irq(&nacl->device_list_lock); | ||
1656 | return -ENODEV; | ||
1657 | } | ||
1658 | tpg = nacl->se_tpg; | ||
1659 | lun = deve->se_lun; | ||
1660 | /* scsiDeviceIndex */ | ||
1661 | ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_se_dev->dev_index); | ||
1662 | spin_unlock_irq(&nacl->device_list_lock); | ||
1663 | return ret; | ||
1664 | } | ||
1665 | DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(dev); | ||
1666 | |||
1667 | static ssize_t target_stat_scsi_att_intr_port_show_attr_port( | ||
1668 | struct se_ml_stat_grps *lgrps, char *page) | ||
1669 | { | ||
1670 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1671 | struct se_lun_acl, ml_stat_grps); | ||
1672 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1673 | struct se_dev_entry *deve; | ||
1674 | struct se_portal_group *tpg; | ||
1675 | ssize_t ret; | ||
1676 | |||
1677 | spin_lock_irq(&nacl->device_list_lock); | ||
1678 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1679 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1680 | spin_unlock_irq(&nacl->device_list_lock); | ||
1681 | return -ENODEV; | ||
1682 | } | ||
1683 | tpg = nacl->se_tpg; | ||
1684 | /* scsiPortIndex */ | ||
1685 | ret = snprintf(page, PAGE_SIZE, "%u\n", TPG_TFO(tpg)->tpg_get_tag(tpg)); | ||
1686 | spin_unlock_irq(&nacl->device_list_lock); | ||
1687 | return ret; | ||
1688 | } | ||
1689 | DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port); | ||
1690 | |||
1691 | static ssize_t target_stat_scsi_att_intr_port_show_attr_indx( | ||
1692 | struct se_ml_stat_grps *lgrps, char *page) | ||
1693 | { | ||
1694 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1695 | struct se_lun_acl, ml_stat_grps); | ||
1696 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1697 | struct se_session *se_sess; | ||
1698 | struct se_portal_group *tpg; | ||
1699 | ssize_t ret; | ||
1700 | |||
1701 | spin_lock_irq(&nacl->nacl_sess_lock); | ||
1702 | se_sess = nacl->nacl_sess; | ||
1703 | if (!se_sess) { | ||
1704 | spin_unlock_irq(&nacl->nacl_sess_lock); | ||
1705 | return -ENODEV; | ||
1706 | } | ||
1707 | |||
1708 | tpg = nacl->se_tpg; | ||
1709 | /* scsiAttIntrPortIndex */ | ||
1710 | ret = snprintf(page, PAGE_SIZE, "%u\n", | ||
1711 | TPG_TFO(tpg)->sess_get_index(se_sess)); | ||
1712 | spin_unlock_irq(&nacl->nacl_sess_lock); | ||
1713 | return ret; | ||
1714 | } | ||
1715 | DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(indx); | ||
1716 | |||
1717 | static ssize_t target_stat_scsi_att_intr_port_show_attr_port_auth_indx( | ||
1718 | struct se_ml_stat_grps *lgrps, char *page) | ||
1719 | { | ||
1720 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1721 | struct se_lun_acl, ml_stat_grps); | ||
1722 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1723 | struct se_dev_entry *deve; | ||
1724 | ssize_t ret; | ||
1725 | |||
1726 | spin_lock_irq(&nacl->device_list_lock); | ||
1727 | deve = &nacl->device_list[lacl->mapped_lun]; | ||
1728 | if (!deve->se_lun || !deve->se_lun_acl) { | ||
1729 | spin_unlock_irq(&nacl->device_list_lock); | ||
1730 | return -ENODEV; | ||
1731 | } | ||
1732 | /* scsiAttIntrPortAuthIntrIdx */ | ||
1733 | ret = snprintf(page, PAGE_SIZE, "%u\n", nacl->acl_index); | ||
1734 | spin_unlock_irq(&nacl->device_list_lock); | ||
1735 | return ret; | ||
1736 | } | ||
1737 | DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port_auth_indx); | ||
1738 | |||
1739 | static ssize_t target_stat_scsi_att_intr_port_show_attr_port_ident( | ||
1740 | struct se_ml_stat_grps *lgrps, char *page) | ||
1741 | { | ||
1742 | struct se_lun_acl *lacl = container_of(lgrps, | ||
1743 | struct se_lun_acl, ml_stat_grps); | ||
1744 | struct se_node_acl *nacl = lacl->se_lun_nacl; | ||
1745 | struct se_session *se_sess; | ||
1746 | struct se_portal_group *tpg; | ||
1747 | ssize_t ret; | ||
1748 | unsigned char buf[64]; | ||
1749 | |||
1750 | spin_lock_irq(&nacl->nacl_sess_lock); | ||
1751 | se_sess = nacl->nacl_sess; | ||
1752 | if (!se_sess) { | ||
1753 | spin_unlock_irq(&nacl->nacl_sess_lock); | ||
1754 | return -ENODEV; | ||
1755 | } | ||
1756 | |||
1757 | tpg = nacl->se_tpg; | ||
1758 | /* scsiAttIntrPortName+scsiAttIntrPortIdentifier */ | ||
1759 | memset(buf, 0, 64); | ||
1760 | if (TPG_TFO(tpg)->sess_get_initiator_sid != NULL) | ||
1761 | TPG_TFO(tpg)->sess_get_initiator_sid(se_sess, | ||
1762 | (unsigned char *)&buf[0], 64); | ||
1763 | |||
1764 | ret = snprintf(page, PAGE_SIZE, "%s+i+%s\n", nacl->initiatorname, buf); | ||
1765 | spin_unlock_irq(&nacl->nacl_sess_lock); | ||
1766 | return ret; | ||
1767 | } | ||
1768 | DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port_ident); | ||
1769 | |||
1770 | CONFIGFS_EATTR_OPS(target_stat_scsi_att_intr_port, se_ml_stat_grps, | ||
1771 | scsi_att_intr_port_group); | ||
1772 | |||
1773 | static struct configfs_attribute *target_stat_scsi_ath_intr_port_attrs[] = { | ||
1774 | &target_stat_scsi_att_intr_port_inst.attr, | ||
1775 | &target_stat_scsi_att_intr_port_dev.attr, | ||
1776 | &target_stat_scsi_att_intr_port_port.attr, | ||
1777 | &target_stat_scsi_att_intr_port_indx.attr, | ||
1778 | &target_stat_scsi_att_intr_port_port_auth_indx.attr, | ||
1779 | &target_stat_scsi_att_intr_port_port_ident.attr, | ||
1780 | NULL, | ||
1781 | }; | ||
1782 | |||
1783 | static struct configfs_item_operations target_stat_scsi_att_intr_port_attrib_ops = { | ||
1784 | .show_attribute = target_stat_scsi_att_intr_port_attr_show, | ||
1785 | .store_attribute = target_stat_scsi_att_intr_port_attr_store, | ||
1786 | }; | ||
1787 | |||
1788 | static struct config_item_type target_stat_scsi_att_intr_port_cit = { | ||
1789 | .ct_item_ops = &target_stat_scsi_att_intr_port_attrib_ops, | ||
1790 | .ct_attrs = target_stat_scsi_ath_intr_port_attrs, | ||
1791 | .ct_owner = THIS_MODULE, | ||
1792 | }; | ||
1793 | |||
1794 | /* | ||
1795 | * Called from target_core_fabric_configfs.c:target_fabric_make_mappedlun() to setup | ||
1796 | * the target MappedLUN statistics groups + configfs CITs located in target_core_stat.c | ||
1797 | */ | ||
1798 | void target_stat_setup_mappedlun_default_groups(struct se_lun_acl *lacl) | ||
1799 | { | ||
1800 | struct config_group *ml_stat_grp = &ML_STAT_GRPS(lacl)->stat_group; | ||
1801 | |||
1802 | config_group_init_type_name(&ML_STAT_GRPS(lacl)->scsi_auth_intr_group, | ||
1803 | "scsi_auth_intr", &target_stat_scsi_auth_intr_cit); | ||
1804 | config_group_init_type_name(&ML_STAT_GRPS(lacl)->scsi_att_intr_port_group, | ||
1805 | "scsi_att_intr_port", &target_stat_scsi_att_intr_port_cit); | ||
1806 | |||
1807 | ml_stat_grp->default_groups[0] = &ML_STAT_GRPS(lacl)->scsi_auth_intr_group; | ||
1808 | ml_stat_grp->default_groups[1] = &ML_STAT_GRPS(lacl)->scsi_att_intr_port_group; | ||
1809 | ml_stat_grp->default_groups[2] = NULL; | ||
1810 | } | ||
diff --git a/drivers/target/target_core_stat.h b/drivers/target/target_core_stat.h new file mode 100644 index 000000000000..86c252f9ea47 --- /dev/null +++ b/drivers/target/target_core_stat.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifndef TARGET_CORE_STAT_H | ||
2 | #define TARGET_CORE_STAT_H | ||
3 | |||
4 | extern void target_stat_setup_dev_default_groups(struct se_subsystem_dev *); | ||
5 | extern void target_stat_setup_port_default_groups(struct se_lun *); | ||
6 | extern void target_stat_setup_mappedlun_default_groups(struct se_lun_acl *); | ||
7 | |||
8 | #endif /*** TARGET_CORE_STAT_H ***/ | ||
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index ff9ace01e27a..bf6aa8a9f1d8 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -227,8 +227,6 @@ static void transport_remove_cmd_from_queue(struct se_cmd *cmd, | |||
227 | static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); | 227 | static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); |
228 | static void transport_stop_all_task_timers(struct se_cmd *cmd); | 228 | static void transport_stop_all_task_timers(struct se_cmd *cmd); |
229 | 229 | ||
230 | int transport_emulate_control_cdb(struct se_task *task); | ||
231 | |||
232 | int init_se_global(void) | 230 | int init_se_global(void) |
233 | { | 231 | { |
234 | struct se_global *global; | 232 | struct se_global *global; |
@@ -1622,7 +1620,7 @@ struct se_device *transport_add_device_to_core_hba( | |||
1622 | const char *inquiry_prod, | 1620 | const char *inquiry_prod, |
1623 | const char *inquiry_rev) | 1621 | const char *inquiry_rev) |
1624 | { | 1622 | { |
1625 | int ret = 0, force_pt; | 1623 | int force_pt; |
1626 | struct se_device *dev; | 1624 | struct se_device *dev; |
1627 | 1625 | ||
1628 | dev = kzalloc(sizeof(struct se_device), GFP_KERNEL); | 1626 | dev = kzalloc(sizeof(struct se_device), GFP_KERNEL); |
@@ -1739,9 +1737,8 @@ struct se_device *transport_add_device_to_core_hba( | |||
1739 | } | 1737 | } |
1740 | scsi_dump_inquiry(dev); | 1738 | scsi_dump_inquiry(dev); |
1741 | 1739 | ||
1740 | return dev; | ||
1742 | out: | 1741 | out: |
1743 | if (!ret) | ||
1744 | return dev; | ||
1745 | kthread_stop(dev->process_thread); | 1742 | kthread_stop(dev->process_thread); |
1746 | 1743 | ||
1747 | spin_lock(&hba->device_lock); | 1744 | spin_lock(&hba->device_lock); |
@@ -4359,11 +4356,9 @@ transport_generic_get_mem(struct se_cmd *cmd, u32 length, u32 dma_size) | |||
4359 | printk(KERN_ERR "Unable to allocate struct se_mem\n"); | 4356 | printk(KERN_ERR "Unable to allocate struct se_mem\n"); |
4360 | goto out; | 4357 | goto out; |
4361 | } | 4358 | } |
4362 | INIT_LIST_HEAD(&se_mem->se_list); | ||
4363 | se_mem->se_len = (length > dma_size) ? dma_size : length; | ||
4364 | 4359 | ||
4365 | /* #warning FIXME Allocate contigous pages for struct se_mem elements */ | 4360 | /* #warning FIXME Allocate contigous pages for struct se_mem elements */ |
4366 | se_mem->se_page = (struct page *) alloc_pages(GFP_KERNEL, 0); | 4361 | se_mem->se_page = alloc_pages(GFP_KERNEL, 0); |
4367 | if (!(se_mem->se_page)) { | 4362 | if (!(se_mem->se_page)) { |
4368 | printk(KERN_ERR "alloc_pages() failed\n"); | 4363 | printk(KERN_ERR "alloc_pages() failed\n"); |
4369 | goto out; | 4364 | goto out; |
@@ -4374,6 +4369,8 @@ transport_generic_get_mem(struct se_cmd *cmd, u32 length, u32 dma_size) | |||
4374 | printk(KERN_ERR "kmap_atomic() failed\n"); | 4369 | printk(KERN_ERR "kmap_atomic() failed\n"); |
4375 | goto out; | 4370 | goto out; |
4376 | } | 4371 | } |
4372 | INIT_LIST_HEAD(&se_mem->se_list); | ||
4373 | se_mem->se_len = (length > dma_size) ? dma_size : length; | ||
4377 | memset(buf, 0, se_mem->se_len); | 4374 | memset(buf, 0, se_mem->se_len); |
4378 | kunmap_atomic(buf, KM_IRQ0); | 4375 | kunmap_atomic(buf, KM_IRQ0); |
4379 | 4376 | ||
@@ -4392,10 +4389,13 @@ transport_generic_get_mem(struct se_cmd *cmd, u32 length, u32 dma_size) | |||
4392 | 4389 | ||
4393 | return 0; | 4390 | return 0; |
4394 | out: | 4391 | out: |
4392 | if (se_mem) | ||
4393 | __free_pages(se_mem->se_page, 0); | ||
4394 | kmem_cache_free(se_mem_cache, se_mem); | ||
4395 | return -1; | 4395 | return -1; |
4396 | } | 4396 | } |
4397 | 4397 | ||
4398 | extern u32 transport_calc_sg_num( | 4398 | u32 transport_calc_sg_num( |
4399 | struct se_task *task, | 4399 | struct se_task *task, |
4400 | struct se_mem *in_se_mem, | 4400 | struct se_mem *in_se_mem, |
4401 | u32 task_offset) | 4401 | u32 task_offset) |
@@ -5834,31 +5834,26 @@ int transport_generic_do_tmr(struct se_cmd *cmd) | |||
5834 | int ret; | 5834 | int ret; |
5835 | 5835 | ||
5836 | switch (tmr->function) { | 5836 | switch (tmr->function) { |
5837 | case ABORT_TASK: | 5837 | case TMR_ABORT_TASK: |
5838 | ref_cmd = tmr->ref_cmd; | 5838 | ref_cmd = tmr->ref_cmd; |
5839 | tmr->response = TMR_FUNCTION_REJECTED; | 5839 | tmr->response = TMR_FUNCTION_REJECTED; |
5840 | break; | 5840 | break; |
5841 | case ABORT_TASK_SET: | 5841 | case TMR_ABORT_TASK_SET: |
5842 | case CLEAR_ACA: | 5842 | case TMR_CLEAR_ACA: |
5843 | case CLEAR_TASK_SET: | 5843 | case TMR_CLEAR_TASK_SET: |
5844 | tmr->response = TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED; | 5844 | tmr->response = TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED; |
5845 | break; | 5845 | break; |
5846 | case LUN_RESET: | 5846 | case TMR_LUN_RESET: |
5847 | ret = core_tmr_lun_reset(dev, tmr, NULL, NULL); | 5847 | ret = core_tmr_lun_reset(dev, tmr, NULL, NULL); |
5848 | tmr->response = (!ret) ? TMR_FUNCTION_COMPLETE : | 5848 | tmr->response = (!ret) ? TMR_FUNCTION_COMPLETE : |
5849 | TMR_FUNCTION_REJECTED; | 5849 | TMR_FUNCTION_REJECTED; |
5850 | break; | 5850 | break; |
5851 | #if 0 | 5851 | case TMR_TARGET_WARM_RESET: |
5852 | case TARGET_WARM_RESET: | ||
5853 | transport_generic_host_reset(dev->se_hba); | ||
5854 | tmr->response = TMR_FUNCTION_REJECTED; | 5852 | tmr->response = TMR_FUNCTION_REJECTED; |
5855 | break; | 5853 | break; |
5856 | case TARGET_COLD_RESET: | 5854 | case TMR_TARGET_COLD_RESET: |
5857 | transport_generic_host_reset(dev->se_hba); | ||
5858 | transport_generic_cold_reset(dev->se_hba); | ||
5859 | tmr->response = TMR_FUNCTION_REJECTED; | 5855 | tmr->response = TMR_FUNCTION_REJECTED; |
5860 | break; | 5856 | break; |
5861 | #endif | ||
5862 | default: | 5857 | default: |
5863 | printk(KERN_ERR "Uknown TMR function: 0x%02x.\n", | 5858 | printk(KERN_ERR "Uknown TMR function: 0x%02x.\n", |
5864 | tmr->function); | 5859 | tmr->function); |
diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index 25a8bc565f40..87e7e6c876d4 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c | |||
@@ -131,7 +131,7 @@ static void kgdboc_unregister_kbd(void) | |||
131 | 131 | ||
132 | static int kgdboc_option_setup(char *opt) | 132 | static int kgdboc_option_setup(char *opt) |
133 | { | 133 | { |
134 | if (strlen(opt) > MAX_CONFIG_LEN) { | 134 | if (strlen(opt) >= MAX_CONFIG_LEN) { |
135 | printk(KERN_ERR "kgdboc: config string too long\n"); | 135 | printk(KERN_ERR "kgdboc: config string too long\n"); |
136 | return -ENOSPC; | 136 | return -ENOSPC; |
137 | } | 137 | } |
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 81f13958e751..43db715f1502 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c | |||
@@ -306,7 +306,7 @@ static struct sysrq_key_op sysrq_ftrace_dump_op = { | |||
306 | 306 | ||
307 | static void sysrq_handle_showmem(int key) | 307 | static void sysrq_handle_showmem(int key) |
308 | { | 308 | { |
309 | show_mem(); | 309 | show_mem(0); |
310 | } | 310 | } |
311 | static struct sysrq_key_op sysrq_showmem_op = { | 311 | static struct sysrq_key_op sysrq_showmem_op = { |
312 | .handler = sysrq_handle_showmem, | 312 | .handler = sysrq_handle_showmem, |
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 6dd3c68c13ad..d6b342b5b423 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c | |||
@@ -600,7 +600,7 @@ static void fn_scroll_back(struct vc_data *vc) | |||
600 | 600 | ||
601 | static void fn_show_mem(struct vc_data *vc) | 601 | static void fn_show_mem(struct vc_data *vc) |
602 | { | 602 | { |
603 | show_mem(); | 603 | show_mem(0); |
604 | } | 604 | } |
605 | 605 | ||
606 | static void fn_show_state(struct vc_data *vc) | 606 | static void fn_show_state(struct vc_data *vc) |
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 54f923792728..475f9c597cb7 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h | |||
@@ -61,8 +61,6 @@ do { \ | |||
61 | current->pid, __func__, ##args); \ | 61 | current->pid, __func__, ##args); \ |
62 | } while (0) | 62 | } while (0) |
63 | 63 | ||
64 | extern spinlock_t autofs4_lock; | ||
65 | |||
66 | /* Unified info structure. This is pointed to by both the dentry and | 64 | /* Unified info structure. This is pointed to by both the dentry and |
67 | inode structures. Each file in the filesystem has an instance of this | 65 | inode structures. Each file in the filesystem has an instance of this |
68 | structure. It holds a reference to the dentry, so dentries are never | 66 | structure. It holds a reference to the dentry, so dentries are never |
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c index 1442da4860e5..509fe1eb66ae 100644 --- a/fs/autofs4/dev-ioctl.c +++ b/fs/autofs4/dev-ioctl.c | |||
@@ -372,6 +372,10 @@ static int autofs_dev_ioctl_setpipefd(struct file *fp, | |||
372 | return -EBUSY; | 372 | return -EBUSY; |
373 | } else { | 373 | } else { |
374 | struct file *pipe = fget(pipefd); | 374 | struct file *pipe = fget(pipefd); |
375 | if (!pipe) { | ||
376 | err = -EBADF; | ||
377 | goto out; | ||
378 | } | ||
375 | if (!pipe->f_op || !pipe->f_op->write) { | 379 | if (!pipe->f_op || !pipe->f_op->write) { |
376 | err = -EPIPE; | 380 | err = -EPIPE; |
377 | fput(pipe); | 381 | fput(pipe); |
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index f43100b9662b..450f529a4eae 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -87,18 +87,70 @@ done: | |||
87 | } | 87 | } |
88 | 88 | ||
89 | /* | 89 | /* |
90 | * Calculate and dget next entry in the subdirs list under root. | ||
91 | */ | ||
92 | static struct dentry *get_next_positive_subdir(struct dentry *prev, | ||
93 | struct dentry *root) | ||
94 | { | ||
95 | struct autofs_sb_info *sbi = autofs4_sbi(root->d_sb); | ||
96 | struct list_head *next; | ||
97 | struct dentry *p, *q; | ||
98 | |||
99 | spin_lock(&sbi->lookup_lock); | ||
100 | |||
101 | if (prev == NULL) { | ||
102 | spin_lock(&root->d_lock); | ||
103 | prev = dget_dlock(root); | ||
104 | next = prev->d_subdirs.next; | ||
105 | p = prev; | ||
106 | goto start; | ||
107 | } | ||
108 | |||
109 | p = prev; | ||
110 | spin_lock(&p->d_lock); | ||
111 | again: | ||
112 | next = p->d_u.d_child.next; | ||
113 | start: | ||
114 | if (next == &root->d_subdirs) { | ||
115 | spin_unlock(&p->d_lock); | ||
116 | spin_unlock(&sbi->lookup_lock); | ||
117 | dput(prev); | ||
118 | return NULL; | ||
119 | } | ||
120 | |||
121 | q = list_entry(next, struct dentry, d_u.d_child); | ||
122 | |||
123 | spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED); | ||
124 | /* Negative dentry - try next */ | ||
125 | if (!simple_positive(q)) { | ||
126 | spin_unlock(&p->d_lock); | ||
127 | p = q; | ||
128 | goto again; | ||
129 | } | ||
130 | dget_dlock(q); | ||
131 | spin_unlock(&q->d_lock); | ||
132 | spin_unlock(&p->d_lock); | ||
133 | spin_unlock(&sbi->lookup_lock); | ||
134 | |||
135 | dput(prev); | ||
136 | |||
137 | return q; | ||
138 | } | ||
139 | |||
140 | /* | ||
90 | * Calculate and dget next entry in top down tree traversal. | 141 | * Calculate and dget next entry in top down tree traversal. |
91 | */ | 142 | */ |
92 | static struct dentry *get_next_positive_dentry(struct dentry *prev, | 143 | static struct dentry *get_next_positive_dentry(struct dentry *prev, |
93 | struct dentry *root) | 144 | struct dentry *root) |
94 | { | 145 | { |
146 | struct autofs_sb_info *sbi = autofs4_sbi(root->d_sb); | ||
95 | struct list_head *next; | 147 | struct list_head *next; |
96 | struct dentry *p, *ret; | 148 | struct dentry *p, *ret; |
97 | 149 | ||
98 | if (prev == NULL) | 150 | if (prev == NULL) |
99 | return dget(root); | 151 | return dget(root); |
100 | 152 | ||
101 | spin_lock(&autofs4_lock); | 153 | spin_lock(&sbi->lookup_lock); |
102 | relock: | 154 | relock: |
103 | p = prev; | 155 | p = prev; |
104 | spin_lock(&p->d_lock); | 156 | spin_lock(&p->d_lock); |
@@ -110,7 +162,7 @@ again: | |||
110 | 162 | ||
111 | if (p == root) { | 163 | if (p == root) { |
112 | spin_unlock(&p->d_lock); | 164 | spin_unlock(&p->d_lock); |
113 | spin_unlock(&autofs4_lock); | 165 | spin_unlock(&sbi->lookup_lock); |
114 | dput(prev); | 166 | dput(prev); |
115 | return NULL; | 167 | return NULL; |
116 | } | 168 | } |
@@ -140,7 +192,7 @@ again: | |||
140 | dget_dlock(ret); | 192 | dget_dlock(ret); |
141 | spin_unlock(&ret->d_lock); | 193 | spin_unlock(&ret->d_lock); |
142 | spin_unlock(&p->d_lock); | 194 | spin_unlock(&p->d_lock); |
143 | spin_unlock(&autofs4_lock); | 195 | spin_unlock(&sbi->lookup_lock); |
144 | 196 | ||
145 | dput(prev); | 197 | dput(prev); |
146 | 198 | ||
@@ -290,11 +342,8 @@ struct dentry *autofs4_expire_direct(struct super_block *sb, | |||
290 | spin_lock(&sbi->fs_lock); | 342 | spin_lock(&sbi->fs_lock); |
291 | ino = autofs4_dentry_ino(root); | 343 | ino = autofs4_dentry_ino(root); |
292 | /* No point expiring a pending mount */ | 344 | /* No point expiring a pending mount */ |
293 | if (ino->flags & AUTOFS_INF_PENDING) { | 345 | if (ino->flags & AUTOFS_INF_PENDING) |
294 | spin_unlock(&sbi->fs_lock); | 346 | goto out; |
295 | return NULL; | ||
296 | } | ||
297 | managed_dentry_set_transit(root); | ||
298 | if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { | 347 | if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { |
299 | struct autofs_info *ino = autofs4_dentry_ino(root); | 348 | struct autofs_info *ino = autofs4_dentry_ino(root); |
300 | ino->flags |= AUTOFS_INF_EXPIRING; | 349 | ino->flags |= AUTOFS_INF_EXPIRING; |
@@ -302,7 +351,7 @@ struct dentry *autofs4_expire_direct(struct super_block *sb, | |||
302 | spin_unlock(&sbi->fs_lock); | 351 | spin_unlock(&sbi->fs_lock); |
303 | return root; | 352 | return root; |
304 | } | 353 | } |
305 | managed_dentry_clear_transit(root); | 354 | out: |
306 | spin_unlock(&sbi->fs_lock); | 355 | spin_unlock(&sbi->fs_lock); |
307 | dput(root); | 356 | dput(root); |
308 | 357 | ||
@@ -336,13 +385,12 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
336 | timeout = sbi->exp_timeout; | 385 | timeout = sbi->exp_timeout; |
337 | 386 | ||
338 | dentry = NULL; | 387 | dentry = NULL; |
339 | while ((dentry = get_next_positive_dentry(dentry, root))) { | 388 | while ((dentry = get_next_positive_subdir(dentry, root))) { |
340 | spin_lock(&sbi->fs_lock); | 389 | spin_lock(&sbi->fs_lock); |
341 | ino = autofs4_dentry_ino(dentry); | 390 | ino = autofs4_dentry_ino(dentry); |
342 | /* No point expiring a pending mount */ | 391 | /* No point expiring a pending mount */ |
343 | if (ino->flags & AUTOFS_INF_PENDING) | 392 | if (ino->flags & AUTOFS_INF_PENDING) |
344 | goto cont; | 393 | goto next; |
345 | managed_dentry_set_transit(dentry); | ||
346 | 394 | ||
347 | /* | 395 | /* |
348 | * Case 1: (i) indirect mount or top level pseudo direct mount | 396 | * Case 1: (i) indirect mount or top level pseudo direct mount |
@@ -402,8 +450,6 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
402 | } | 450 | } |
403 | } | 451 | } |
404 | next: | 452 | next: |
405 | managed_dentry_clear_transit(dentry); | ||
406 | cont: | ||
407 | spin_unlock(&sbi->fs_lock); | 453 | spin_unlock(&sbi->fs_lock); |
408 | } | 454 | } |
409 | return NULL; | 455 | return NULL; |
@@ -415,13 +461,13 @@ found: | |||
415 | ino->flags |= AUTOFS_INF_EXPIRING; | 461 | ino->flags |= AUTOFS_INF_EXPIRING; |
416 | init_completion(&ino->expire_complete); | 462 | init_completion(&ino->expire_complete); |
417 | spin_unlock(&sbi->fs_lock); | 463 | spin_unlock(&sbi->fs_lock); |
418 | spin_lock(&autofs4_lock); | 464 | spin_lock(&sbi->lookup_lock); |
419 | spin_lock(&expired->d_parent->d_lock); | 465 | spin_lock(&expired->d_parent->d_lock); |
420 | spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED); | 466 | spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED); |
421 | list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); | 467 | list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); |
422 | spin_unlock(&expired->d_lock); | 468 | spin_unlock(&expired->d_lock); |
423 | spin_unlock(&expired->d_parent->d_lock); | 469 | spin_unlock(&expired->d_parent->d_lock); |
424 | spin_unlock(&autofs4_lock); | 470 | spin_unlock(&sbi->lookup_lock); |
425 | return expired; | 471 | return expired; |
426 | } | 472 | } |
427 | 473 | ||
@@ -484,8 +530,6 @@ int autofs4_expire_run(struct super_block *sb, | |||
484 | spin_lock(&sbi->fs_lock); | 530 | spin_lock(&sbi->fs_lock); |
485 | ino = autofs4_dentry_ino(dentry); | 531 | ino = autofs4_dentry_ino(dentry); |
486 | ino->flags &= ~AUTOFS_INF_EXPIRING; | 532 | ino->flags &= ~AUTOFS_INF_EXPIRING; |
487 | if (!d_unhashed(dentry)) | ||
488 | managed_dentry_clear_transit(dentry); | ||
489 | complete_all(&ino->expire_complete); | 533 | complete_all(&ino->expire_complete); |
490 | spin_unlock(&sbi->fs_lock); | 534 | spin_unlock(&sbi->fs_lock); |
491 | 535 | ||
@@ -513,9 +557,7 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt, | |||
513 | spin_lock(&sbi->fs_lock); | 557 | spin_lock(&sbi->fs_lock); |
514 | ino->flags &= ~AUTOFS_INF_EXPIRING; | 558 | ino->flags &= ~AUTOFS_INF_EXPIRING; |
515 | spin_lock(&dentry->d_lock); | 559 | spin_lock(&dentry->d_lock); |
516 | if (ret) | 560 | if (!ret) { |
517 | __managed_dentry_clear_transit(dentry); | ||
518 | else { | ||
519 | if ((IS_ROOT(dentry) || | 561 | if ((IS_ROOT(dentry) || |
520 | (autofs_type_indirect(sbi->type) && | 562 | (autofs_type_indirect(sbi->type) && |
521 | IS_ROOT(dentry->d_parent))) && | 563 | IS_ROOT(dentry->d_parent))) && |
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index e6f84d26f4cf..96804a17bbd0 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -23,8 +23,6 @@ | |||
23 | 23 | ||
24 | #include "autofs_i.h" | 24 | #include "autofs_i.h" |
25 | 25 | ||
26 | DEFINE_SPINLOCK(autofs4_lock); | ||
27 | |||
28 | static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *); | 26 | static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *); |
29 | static int autofs4_dir_unlink(struct inode *,struct dentry *); | 27 | static int autofs4_dir_unlink(struct inode *,struct dentry *); |
30 | static int autofs4_dir_rmdir(struct inode *,struct dentry *); | 28 | static int autofs4_dir_rmdir(struct inode *,struct dentry *); |
@@ -125,15 +123,15 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) | |||
125 | * autofs file system so just let the libfs routines handle | 123 | * autofs file system so just let the libfs routines handle |
126 | * it. | 124 | * it. |
127 | */ | 125 | */ |
128 | spin_lock(&autofs4_lock); | 126 | spin_lock(&sbi->lookup_lock); |
129 | spin_lock(&dentry->d_lock); | 127 | spin_lock(&dentry->d_lock); |
130 | if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { | 128 | if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { |
131 | spin_unlock(&dentry->d_lock); | 129 | spin_unlock(&dentry->d_lock); |
132 | spin_unlock(&autofs4_lock); | 130 | spin_unlock(&sbi->lookup_lock); |
133 | return -ENOENT; | 131 | return -ENOENT; |
134 | } | 132 | } |
135 | spin_unlock(&dentry->d_lock); | 133 | spin_unlock(&dentry->d_lock); |
136 | spin_unlock(&autofs4_lock); | 134 | spin_unlock(&sbi->lookup_lock); |
137 | 135 | ||
138 | out: | 136 | out: |
139 | return dcache_dir_open(inode, file); | 137 | return dcache_dir_open(inode, file); |
@@ -171,7 +169,6 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry) | |||
171 | const unsigned char *str = name->name; | 169 | const unsigned char *str = name->name; |
172 | struct list_head *p, *head; | 170 | struct list_head *p, *head; |
173 | 171 | ||
174 | spin_lock(&autofs4_lock); | ||
175 | spin_lock(&sbi->lookup_lock); | 172 | spin_lock(&sbi->lookup_lock); |
176 | head = &sbi->active_list; | 173 | head = &sbi->active_list; |
177 | list_for_each(p, head) { | 174 | list_for_each(p, head) { |
@@ -204,14 +201,12 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry) | |||
204 | dget_dlock(active); | 201 | dget_dlock(active); |
205 | spin_unlock(&active->d_lock); | 202 | spin_unlock(&active->d_lock); |
206 | spin_unlock(&sbi->lookup_lock); | 203 | spin_unlock(&sbi->lookup_lock); |
207 | spin_unlock(&autofs4_lock); | ||
208 | return active; | 204 | return active; |
209 | } | 205 | } |
210 | next: | 206 | next: |
211 | spin_unlock(&active->d_lock); | 207 | spin_unlock(&active->d_lock); |
212 | } | 208 | } |
213 | spin_unlock(&sbi->lookup_lock); | 209 | spin_unlock(&sbi->lookup_lock); |
214 | spin_unlock(&autofs4_lock); | ||
215 | 210 | ||
216 | return NULL; | 211 | return NULL; |
217 | } | 212 | } |
@@ -226,7 +221,6 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry) | |||
226 | const unsigned char *str = name->name; | 221 | const unsigned char *str = name->name; |
227 | struct list_head *p, *head; | 222 | struct list_head *p, *head; |
228 | 223 | ||
229 | spin_lock(&autofs4_lock); | ||
230 | spin_lock(&sbi->lookup_lock); | 224 | spin_lock(&sbi->lookup_lock); |
231 | head = &sbi->expiring_list; | 225 | head = &sbi->expiring_list; |
232 | list_for_each(p, head) { | 226 | list_for_each(p, head) { |
@@ -259,14 +253,12 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry) | |||
259 | dget_dlock(expiring); | 253 | dget_dlock(expiring); |
260 | spin_unlock(&expiring->d_lock); | 254 | spin_unlock(&expiring->d_lock); |
261 | spin_unlock(&sbi->lookup_lock); | 255 | spin_unlock(&sbi->lookup_lock); |
262 | spin_unlock(&autofs4_lock); | ||
263 | return expiring; | 256 | return expiring; |
264 | } | 257 | } |
265 | next: | 258 | next: |
266 | spin_unlock(&expiring->d_lock); | 259 | spin_unlock(&expiring->d_lock); |
267 | } | 260 | } |
268 | spin_unlock(&sbi->lookup_lock); | 261 | spin_unlock(&sbi->lookup_lock); |
269 | spin_unlock(&autofs4_lock); | ||
270 | 262 | ||
271 | return NULL; | 263 | return NULL; |
272 | } | 264 | } |
@@ -275,17 +267,16 @@ static int autofs4_mount_wait(struct dentry *dentry) | |||
275 | { | 267 | { |
276 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | 268 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); |
277 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | 269 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
278 | int status; | 270 | int status = 0; |
279 | 271 | ||
280 | if (ino->flags & AUTOFS_INF_PENDING) { | 272 | if (ino->flags & AUTOFS_INF_PENDING) { |
281 | DPRINTK("waiting for mount name=%.*s", | 273 | DPRINTK("waiting for mount name=%.*s", |
282 | dentry->d_name.len, dentry->d_name.name); | 274 | dentry->d_name.len, dentry->d_name.name); |
283 | status = autofs4_wait(sbi, dentry, NFY_MOUNT); | 275 | status = autofs4_wait(sbi, dentry, NFY_MOUNT); |
284 | DPRINTK("mount wait done status=%d", status); | 276 | DPRINTK("mount wait done status=%d", status); |
285 | ino->last_used = jiffies; | ||
286 | return status; | ||
287 | } | 277 | } |
288 | return 0; | 278 | ino->last_used = jiffies; |
279 | return status; | ||
289 | } | 280 | } |
290 | 281 | ||
291 | static int do_expire_wait(struct dentry *dentry) | 282 | static int do_expire_wait(struct dentry *dentry) |
@@ -319,9 +310,12 @@ static struct dentry *autofs4_mountpoint_changed(struct path *path) | |||
319 | */ | 310 | */ |
320 | if (autofs_type_indirect(sbi->type) && d_unhashed(dentry)) { | 311 | if (autofs_type_indirect(sbi->type) && d_unhashed(dentry)) { |
321 | struct dentry *parent = dentry->d_parent; | 312 | struct dentry *parent = dentry->d_parent; |
313 | struct autofs_info *ino; | ||
322 | struct dentry *new = d_lookup(parent, &dentry->d_name); | 314 | struct dentry *new = d_lookup(parent, &dentry->d_name); |
323 | if (!new) | 315 | if (!new) |
324 | return NULL; | 316 | return NULL; |
317 | ino = autofs4_dentry_ino(new); | ||
318 | ino->last_used = jiffies; | ||
325 | dput(path->dentry); | 319 | dput(path->dentry); |
326 | path->dentry = new; | 320 | path->dentry = new; |
327 | } | 321 | } |
@@ -338,18 +332,6 @@ static struct vfsmount *autofs4_d_automount(struct path *path) | |||
338 | DPRINTK("dentry=%p %.*s", | 332 | DPRINTK("dentry=%p %.*s", |
339 | dentry, dentry->d_name.len, dentry->d_name.name); | 333 | dentry, dentry->d_name.len, dentry->d_name.name); |
340 | 334 | ||
341 | /* | ||
342 | * Someone may have manually umounted this or it was a submount | ||
343 | * that has gone away. | ||
344 | */ | ||
345 | spin_lock(&dentry->d_lock); | ||
346 | if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { | ||
347 | if (!(dentry->d_flags & DCACHE_MANAGE_TRANSIT) && | ||
348 | (dentry->d_flags & DCACHE_NEED_AUTOMOUNT)) | ||
349 | __managed_dentry_set_transit(path->dentry); | ||
350 | } | ||
351 | spin_unlock(&dentry->d_lock); | ||
352 | |||
353 | /* The daemon never triggers a mount. */ | 335 | /* The daemon never triggers a mount. */ |
354 | if (autofs4_oz_mode(sbi)) | 336 | if (autofs4_oz_mode(sbi)) |
355 | return NULL; | 337 | return NULL; |
@@ -418,18 +400,17 @@ static struct vfsmount *autofs4_d_automount(struct path *path) | |||
418 | done: | 400 | done: |
419 | if (!(ino->flags & AUTOFS_INF_EXPIRING)) { | 401 | if (!(ino->flags & AUTOFS_INF_EXPIRING)) { |
420 | /* | 402 | /* |
421 | * Any needed mounting has been completed and the path updated | 403 | * Any needed mounting has been completed and the path |
422 | * so turn this into a normal dentry so we don't continually | 404 | * updated so clear DCACHE_NEED_AUTOMOUNT so we don't |
423 | * call ->d_automount() and ->d_manage(). | 405 | * call ->d_automount() on rootless multi-mounts since |
424 | */ | 406 | * it can lead to an incorrect ELOOP error return. |
425 | spin_lock(&dentry->d_lock); | 407 | * |
426 | __managed_dentry_clear_transit(dentry); | ||
427 | /* | ||
428 | * Only clear DMANAGED_AUTOMOUNT for rootless multi-mounts and | 408 | * Only clear DMANAGED_AUTOMOUNT for rootless multi-mounts and |
429 | * symlinks as in all other cases the dentry will be covered by | 409 | * symlinks as in all other cases the dentry will be covered by |
430 | * an actual mount so ->d_automount() won't be called during | 410 | * an actual mount so ->d_automount() won't be called during |
431 | * the follow. | 411 | * the follow. |
432 | */ | 412 | */ |
413 | spin_lock(&dentry->d_lock); | ||
433 | if ((!d_mountpoint(dentry) && | 414 | if ((!d_mountpoint(dentry) && |
434 | !list_empty(&dentry->d_subdirs)) || | 415 | !list_empty(&dentry->d_subdirs)) || |
435 | (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode))) | 416 | (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode))) |
@@ -455,6 +436,8 @@ int autofs4_d_manage(struct dentry *dentry, bool rcu_walk) | |||
455 | 436 | ||
456 | /* The daemon never waits. */ | 437 | /* The daemon never waits. */ |
457 | if (autofs4_oz_mode(sbi)) { | 438 | if (autofs4_oz_mode(sbi)) { |
439 | if (rcu_walk) | ||
440 | return 0; | ||
458 | if (!d_mountpoint(dentry)) | 441 | if (!d_mountpoint(dentry)) |
459 | return -EISDIR; | 442 | return -EISDIR; |
460 | return 0; | 443 | return 0; |
@@ -612,12 +595,12 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) | |||
612 | 595 | ||
613 | dir->i_mtime = CURRENT_TIME; | 596 | dir->i_mtime = CURRENT_TIME; |
614 | 597 | ||
615 | spin_lock(&autofs4_lock); | 598 | spin_lock(&sbi->lookup_lock); |
616 | autofs4_add_expiring(dentry); | 599 | __autofs4_add_expiring(dentry); |
617 | spin_lock(&dentry->d_lock); | 600 | spin_lock(&dentry->d_lock); |
618 | __d_drop(dentry); | 601 | __d_drop(dentry); |
619 | spin_unlock(&dentry->d_lock); | 602 | spin_unlock(&dentry->d_lock); |
620 | spin_unlock(&autofs4_lock); | 603 | spin_unlock(&sbi->lookup_lock); |
621 | 604 | ||
622 | return 0; | 605 | return 0; |
623 | } | 606 | } |
@@ -686,20 +669,17 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | |||
686 | if (!autofs4_oz_mode(sbi)) | 669 | if (!autofs4_oz_mode(sbi)) |
687 | return -EACCES; | 670 | return -EACCES; |
688 | 671 | ||
689 | spin_lock(&autofs4_lock); | ||
690 | spin_lock(&sbi->lookup_lock); | 672 | spin_lock(&sbi->lookup_lock); |
691 | spin_lock(&dentry->d_lock); | 673 | spin_lock(&dentry->d_lock); |
692 | if (!list_empty(&dentry->d_subdirs)) { | 674 | if (!list_empty(&dentry->d_subdirs)) { |
693 | spin_unlock(&dentry->d_lock); | 675 | spin_unlock(&dentry->d_lock); |
694 | spin_unlock(&sbi->lookup_lock); | 676 | spin_unlock(&sbi->lookup_lock); |
695 | spin_unlock(&autofs4_lock); | ||
696 | return -ENOTEMPTY; | 677 | return -ENOTEMPTY; |
697 | } | 678 | } |
698 | __autofs4_add_expiring(dentry); | 679 | __autofs4_add_expiring(dentry); |
699 | spin_unlock(&sbi->lookup_lock); | ||
700 | __d_drop(dentry); | 680 | __d_drop(dentry); |
701 | spin_unlock(&dentry->d_lock); | 681 | spin_unlock(&dentry->d_lock); |
702 | spin_unlock(&autofs4_lock); | 682 | spin_unlock(&sbi->lookup_lock); |
703 | 683 | ||
704 | if (sbi->version < 5) | 684 | if (sbi->version < 5) |
705 | autofs_clear_leaf_automount_flags(dentry); | 685 | autofs_clear_leaf_automount_flags(dentry); |
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 56010056b2e6..25435987d6ae 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c | |||
@@ -197,12 +197,12 @@ rename_retry: | |||
197 | 197 | ||
198 | seq = read_seqbegin(&rename_lock); | 198 | seq = read_seqbegin(&rename_lock); |
199 | rcu_read_lock(); | 199 | rcu_read_lock(); |
200 | spin_lock(&autofs4_lock); | 200 | spin_lock(&sbi->fs_lock); |
201 | for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent) | 201 | for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent) |
202 | len += tmp->d_name.len + 1; | 202 | len += tmp->d_name.len + 1; |
203 | 203 | ||
204 | if (!len || --len > NAME_MAX) { | 204 | if (!len || --len > NAME_MAX) { |
205 | spin_unlock(&autofs4_lock); | 205 | spin_unlock(&sbi->fs_lock); |
206 | rcu_read_unlock(); | 206 | rcu_read_unlock(); |
207 | if (read_seqretry(&rename_lock, seq)) | 207 | if (read_seqretry(&rename_lock, seq)) |
208 | goto rename_retry; | 208 | goto rename_retry; |
@@ -218,7 +218,7 @@ rename_retry: | |||
218 | p -= tmp->d_name.len; | 218 | p -= tmp->d_name.len; |
219 | strncpy(p, tmp->d_name.name, tmp->d_name.len); | 219 | strncpy(p, tmp->d_name.name, tmp->d_name.len); |
220 | } | 220 | } |
221 | spin_unlock(&autofs4_lock); | 221 | spin_unlock(&sbi->fs_lock); |
222 | rcu_read_unlock(); | 222 | rcu_read_unlock(); |
223 | if (read_seqretry(&rename_lock, seq)) | 223 | if (read_seqretry(&rename_lock, seq)) |
224 | goto rename_retry; | 224 | goto rename_retry; |
diff --git a/fs/block_dev.c b/fs/block_dev.c index 7d02afb2b7f4..c1511c674f53 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -55,11 +55,13 @@ EXPORT_SYMBOL(I_BDEV); | |||
55 | static void bdev_inode_switch_bdi(struct inode *inode, | 55 | static void bdev_inode_switch_bdi(struct inode *inode, |
56 | struct backing_dev_info *dst) | 56 | struct backing_dev_info *dst) |
57 | { | 57 | { |
58 | spin_lock(&inode_lock); | 58 | spin_lock(&inode_wb_list_lock); |
59 | spin_lock(&inode->i_lock); | ||
59 | inode->i_data.backing_dev_info = dst; | 60 | inode->i_data.backing_dev_info = dst; |
60 | if (inode->i_state & I_DIRTY) | 61 | if (inode->i_state & I_DIRTY) |
61 | list_move(&inode->i_wb_list, &dst->wb.b_dirty); | 62 | list_move(&inode->i_wb_list, &dst->wb.b_dirty); |
62 | spin_unlock(&inode_lock); | 63 | spin_unlock(&inode->i_lock); |
64 | spin_unlock(&inode_wb_list_lock); | ||
63 | } | 65 | } |
64 | 66 | ||
65 | static sector_t max_block(struct block_device *bdev) | 67 | static sector_t max_block(struct block_device *bdev) |
diff --git a/fs/buffer.c b/fs/buffer.c index 2e6b1a387b7e..a08bb8e61c6f 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -1138,7 +1138,7 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size) | |||
1138 | * inode list. | 1138 | * inode list. |
1139 | * | 1139 | * |
1140 | * mark_buffer_dirty() is atomic. It takes bh->b_page->mapping->private_lock, | 1140 | * mark_buffer_dirty() is atomic. It takes bh->b_page->mapping->private_lock, |
1141 | * mapping->tree_lock and the global inode_lock. | 1141 | * mapping->tree_lock and mapping->host->i_lock. |
1142 | */ | 1142 | */ |
1143 | void mark_buffer_dirty(struct buffer_head *bh) | 1143 | void mark_buffer_dirty(struct buffer_head *bh) |
1144 | { | 1144 | { |
diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c index 06d27a41807f..af56ad56a89a 100644 --- a/fs/coda/sysctl.c +++ b/fs/coda/sysctl.c | |||
@@ -61,4 +61,13 @@ void coda_sysctl_clean(void) | |||
61 | fs_table_header = NULL; | 61 | fs_table_header = NULL; |
62 | } | 62 | } |
63 | } | 63 | } |
64 | |||
65 | #else | ||
66 | void coda_sysctl_init(void) | ||
67 | { | ||
68 | } | ||
69 | |||
70 | void coda_sysctl_clean(void) | ||
71 | { | ||
72 | } | ||
64 | #endif | 73 | #endif |
diff --git a/fs/drop_caches.c b/fs/drop_caches.c index 816f88e6b9ce..98b77c89494c 100644 --- a/fs/drop_caches.c +++ b/fs/drop_caches.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/writeback.h> | 8 | #include <linux/writeback.h> |
9 | #include <linux/sysctl.h> | 9 | #include <linux/sysctl.h> |
10 | #include <linux/gfp.h> | 10 | #include <linux/gfp.h> |
11 | #include "internal.h" | ||
11 | 12 | ||
12 | /* A global variable is a bit ugly, but it keeps the code simple */ | 13 | /* A global variable is a bit ugly, but it keeps the code simple */ |
13 | int sysctl_drop_caches; | 14 | int sysctl_drop_caches; |
@@ -16,20 +17,23 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused) | |||
16 | { | 17 | { |
17 | struct inode *inode, *toput_inode = NULL; | 18 | struct inode *inode, *toput_inode = NULL; |
18 | 19 | ||
19 | spin_lock(&inode_lock); | 20 | spin_lock(&inode_sb_list_lock); |
20 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | 21 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { |
21 | if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) | 22 | spin_lock(&inode->i_lock); |
22 | continue; | 23 | if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) || |
23 | if (inode->i_mapping->nrpages == 0) | 24 | (inode->i_mapping->nrpages == 0)) { |
25 | spin_unlock(&inode->i_lock); | ||
24 | continue; | 26 | continue; |
27 | } | ||
25 | __iget(inode); | 28 | __iget(inode); |
26 | spin_unlock(&inode_lock); | 29 | spin_unlock(&inode->i_lock); |
30 | spin_unlock(&inode_sb_list_lock); | ||
27 | invalidate_mapping_pages(inode->i_mapping, 0, -1); | 31 | invalidate_mapping_pages(inode->i_mapping, 0, -1); |
28 | iput(toput_inode); | 32 | iput(toput_inode); |
29 | toput_inode = inode; | 33 | toput_inode = inode; |
30 | spin_lock(&inode_lock); | 34 | spin_lock(&inode_sb_list_lock); |
31 | } | 35 | } |
32 | spin_unlock(&inode_lock); | 36 | spin_unlock(&inode_sb_list_lock); |
33 | iput(toput_inode); | 37 | iput(toput_inode); |
34 | } | 38 | } |
35 | 39 | ||
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index adf96b822781..97b970e7dd13 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include "ext4_jbd2.h" | 21 | #include "ext4_jbd2.h" |
22 | #include "mballoc.h" | 22 | #include "mballoc.h" |
23 | 23 | ||
24 | #include <trace/events/ext4.h> | ||
25 | |||
24 | /* | 26 | /* |
25 | * balloc.c contains the blocks allocation and deallocation routines | 27 | * balloc.c contains the blocks allocation and deallocation routines |
26 | */ | 28 | */ |
@@ -342,6 +344,7 @@ ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group) | |||
342 | * We do it here so the bitmap uptodate bit | 344 | * We do it here so the bitmap uptodate bit |
343 | * get set with buffer lock held. | 345 | * get set with buffer lock held. |
344 | */ | 346 | */ |
347 | trace_ext4_read_block_bitmap_load(sb, block_group); | ||
345 | set_bitmap_uptodate(bh); | 348 | set_bitmap_uptodate(bh); |
346 | if (bh_submit_read(bh) < 0) { | 349 | if (bh_submit_read(bh) < 0) { |
347 | put_bh(bh); | 350 | put_bh(bh); |
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h index d8b992e658c1..e25e99bf7ee1 100644 --- a/fs/ext4/ext4_jbd2.h +++ b/fs/ext4/ext4_jbd2.h | |||
@@ -202,13 +202,6 @@ static inline int ext4_handle_has_enough_credits(handle_t *handle, int needed) | |||
202 | return 1; | 202 | return 1; |
203 | } | 203 | } |
204 | 204 | ||
205 | static inline void ext4_journal_release_buffer(handle_t *handle, | ||
206 | struct buffer_head *bh) | ||
207 | { | ||
208 | if (ext4_handle_valid(handle)) | ||
209 | jbd2_journal_release_buffer(handle, bh); | ||
210 | } | ||
211 | |||
212 | static inline handle_t *ext4_journal_start(struct inode *inode, int nblocks) | 205 | static inline handle_t *ext4_journal_start(struct inode *inode, int nblocks) |
213 | { | 206 | { |
214 | return ext4_journal_start_sb(inode->i_sb, nblocks); | 207 | return ext4_journal_start_sb(inode->i_sb, nblocks); |
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 7516fb9c0bd5..dd2cb5076ff9 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -44,6 +44,8 @@ | |||
44 | #include "ext4_jbd2.h" | 44 | #include "ext4_jbd2.h" |
45 | #include "ext4_extents.h" | 45 | #include "ext4_extents.h" |
46 | 46 | ||
47 | #include <trace/events/ext4.h> | ||
48 | |||
47 | static int ext4_ext_truncate_extend_restart(handle_t *handle, | 49 | static int ext4_ext_truncate_extend_restart(handle_t *handle, |
48 | struct inode *inode, | 50 | struct inode *inode, |
49 | int needed) | 51 | int needed) |
@@ -664,6 +666,8 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block, | |||
664 | if (unlikely(!bh)) | 666 | if (unlikely(!bh)) |
665 | goto err; | 667 | goto err; |
666 | if (!bh_uptodate_or_lock(bh)) { | 668 | if (!bh_uptodate_or_lock(bh)) { |
669 | trace_ext4_ext_load_extent(inode, block, | ||
670 | path[ppos].p_block); | ||
667 | if (bh_submit_read(bh) < 0) { | 671 | if (bh_submit_read(bh) < 0) { |
668 | put_bh(bh); | 672 | put_bh(bh); |
669 | goto err; | 673 | goto err; |
@@ -1034,7 +1038,7 @@ cleanup: | |||
1034 | for (i = 0; i < depth; i++) { | 1038 | for (i = 0; i < depth; i++) { |
1035 | if (!ablocks[i]) | 1039 | if (!ablocks[i]) |
1036 | continue; | 1040 | continue; |
1037 | ext4_free_blocks(handle, inode, 0, ablocks[i], 1, | 1041 | ext4_free_blocks(handle, inode, NULL, ablocks[i], 1, |
1038 | EXT4_FREE_BLOCKS_METADATA); | 1042 | EXT4_FREE_BLOCKS_METADATA); |
1039 | } | 1043 | } |
1040 | } | 1044 | } |
@@ -2059,7 +2063,7 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, | |||
2059 | if (err) | 2063 | if (err) |
2060 | return err; | 2064 | return err; |
2061 | ext_debug("index is empty, remove it, free block %llu\n", leaf); | 2065 | ext_debug("index is empty, remove it, free block %llu\n", leaf); |
2062 | ext4_free_blocks(handle, inode, 0, leaf, 1, | 2066 | ext4_free_blocks(handle, inode, NULL, leaf, 1, |
2063 | EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET); | 2067 | EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET); |
2064 | return err; | 2068 | return err; |
2065 | } | 2069 | } |
@@ -2156,7 +2160,7 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode, | |||
2156 | num = le32_to_cpu(ex->ee_block) + ee_len - from; | 2160 | num = le32_to_cpu(ex->ee_block) + ee_len - from; |
2157 | start = ext4_ext_pblock(ex) + ee_len - num; | 2161 | start = ext4_ext_pblock(ex) + ee_len - num; |
2158 | ext_debug("free last %u blocks starting %llu\n", num, start); | 2162 | ext_debug("free last %u blocks starting %llu\n", num, start); |
2159 | ext4_free_blocks(handle, inode, 0, start, num, flags); | 2163 | ext4_free_blocks(handle, inode, NULL, start, num, flags); |
2160 | } else if (from == le32_to_cpu(ex->ee_block) | 2164 | } else if (from == le32_to_cpu(ex->ee_block) |
2161 | && to <= le32_to_cpu(ex->ee_block) + ee_len - 1) { | 2165 | && to <= le32_to_cpu(ex->ee_block) + ee_len - 1) { |
2162 | printk(KERN_INFO "strange request: removal %u-%u from %u:%u\n", | 2166 | printk(KERN_INFO "strange request: removal %u-%u from %u:%u\n", |
@@ -3108,14 +3112,13 @@ static int check_eofblocks_fl(handle_t *handle, struct inode *inode, | |||
3108 | { | 3112 | { |
3109 | int i, depth; | 3113 | int i, depth; |
3110 | struct ext4_extent_header *eh; | 3114 | struct ext4_extent_header *eh; |
3111 | struct ext4_extent *ex, *last_ex; | 3115 | struct ext4_extent *last_ex; |
3112 | 3116 | ||
3113 | if (!ext4_test_inode_flag(inode, EXT4_INODE_EOFBLOCKS)) | 3117 | if (!ext4_test_inode_flag(inode, EXT4_INODE_EOFBLOCKS)) |
3114 | return 0; | 3118 | return 0; |
3115 | 3119 | ||
3116 | depth = ext_depth(inode); | 3120 | depth = ext_depth(inode); |
3117 | eh = path[depth].p_hdr; | 3121 | eh = path[depth].p_hdr; |
3118 | ex = path[depth].p_ext; | ||
3119 | 3122 | ||
3120 | if (unlikely(!eh->eh_entries)) { | 3123 | if (unlikely(!eh->eh_entries)) { |
3121 | EXT4_ERROR_INODE(inode, "eh->eh_entries == 0 and " | 3124 | EXT4_ERROR_INODE(inode, "eh->eh_entries == 0 and " |
@@ -3295,9 +3298,8 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, | |||
3295 | struct ext4_map_blocks *map, int flags) | 3298 | struct ext4_map_blocks *map, int flags) |
3296 | { | 3299 | { |
3297 | struct ext4_ext_path *path = NULL; | 3300 | struct ext4_ext_path *path = NULL; |
3298 | struct ext4_extent_header *eh; | ||
3299 | struct ext4_extent newex, *ex; | 3301 | struct ext4_extent newex, *ex; |
3300 | ext4_fsblk_t newblock; | 3302 | ext4_fsblk_t newblock = 0; |
3301 | int err = 0, depth, ret; | 3303 | int err = 0, depth, ret; |
3302 | unsigned int allocated = 0; | 3304 | unsigned int allocated = 0; |
3303 | struct ext4_allocation_request ar; | 3305 | struct ext4_allocation_request ar; |
@@ -3305,6 +3307,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, | |||
3305 | 3307 | ||
3306 | ext_debug("blocks %u/%u requested for inode %lu\n", | 3308 | ext_debug("blocks %u/%u requested for inode %lu\n", |
3307 | map->m_lblk, map->m_len, inode->i_ino); | 3309 | map->m_lblk, map->m_len, inode->i_ino); |
3310 | trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags); | ||
3308 | 3311 | ||
3309 | /* check in cache */ | 3312 | /* check in cache */ |
3310 | if (ext4_ext_in_cache(inode, map->m_lblk, &newex)) { | 3313 | if (ext4_ext_in_cache(inode, map->m_lblk, &newex)) { |
@@ -3352,7 +3355,6 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, | |||
3352 | err = -EIO; | 3355 | err = -EIO; |
3353 | goto out2; | 3356 | goto out2; |
3354 | } | 3357 | } |
3355 | eh = path[depth].p_hdr; | ||
3356 | 3358 | ||
3357 | ex = path[depth].p_ext; | 3359 | ex = path[depth].p_ext; |
3358 | if (ex) { | 3360 | if (ex) { |
@@ -3485,7 +3487,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, | |||
3485 | /* not a good idea to call discard here directly, | 3487 | /* not a good idea to call discard here directly, |
3486 | * but otherwise we'd need to call it every free() */ | 3488 | * but otherwise we'd need to call it every free() */ |
3487 | ext4_discard_preallocations(inode); | 3489 | ext4_discard_preallocations(inode); |
3488 | ext4_free_blocks(handle, inode, 0, ext4_ext_pblock(&newex), | 3490 | ext4_free_blocks(handle, inode, NULL, ext4_ext_pblock(&newex), |
3489 | ext4_ext_get_actual_len(&newex), 0); | 3491 | ext4_ext_get_actual_len(&newex), 0); |
3490 | goto out2; | 3492 | goto out2; |
3491 | } | 3493 | } |
@@ -3525,6 +3527,8 @@ out2: | |||
3525 | ext4_ext_drop_refs(path); | 3527 | ext4_ext_drop_refs(path); |
3526 | kfree(path); | 3528 | kfree(path); |
3527 | } | 3529 | } |
3530 | trace_ext4_ext_map_blocks_exit(inode, map->m_lblk, | ||
3531 | newblock, map->m_len, err ? err : allocated); | ||
3528 | return err ? err : allocated; | 3532 | return err ? err : allocated; |
3529 | } | 3533 | } |
3530 | 3534 | ||
@@ -3658,6 +3662,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | |||
3658 | if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) | 3662 | if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) |
3659 | return -EOPNOTSUPP; | 3663 | return -EOPNOTSUPP; |
3660 | 3664 | ||
3665 | trace_ext4_fallocate_enter(inode, offset, len, mode); | ||
3661 | map.m_lblk = offset >> blkbits; | 3666 | map.m_lblk = offset >> blkbits; |
3662 | /* | 3667 | /* |
3663 | * We can't just convert len to max_blocks because | 3668 | * We can't just convert len to max_blocks because |
@@ -3673,6 +3678,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | |||
3673 | ret = inode_newsize_ok(inode, (len + offset)); | 3678 | ret = inode_newsize_ok(inode, (len + offset)); |
3674 | if (ret) { | 3679 | if (ret) { |
3675 | mutex_unlock(&inode->i_mutex); | 3680 | mutex_unlock(&inode->i_mutex); |
3681 | trace_ext4_fallocate_exit(inode, offset, max_blocks, ret); | ||
3676 | return ret; | 3682 | return ret; |
3677 | } | 3683 | } |
3678 | retry: | 3684 | retry: |
@@ -3717,6 +3723,8 @@ retry: | |||
3717 | goto retry; | 3723 | goto retry; |
3718 | } | 3724 | } |
3719 | mutex_unlock(&inode->i_mutex); | 3725 | mutex_unlock(&inode->i_mutex); |
3726 | trace_ext4_fallocate_exit(inode, offset, max_blocks, | ||
3727 | ret > 0 ? ret2 : ret); | ||
3720 | return ret > 0 ? ret2 : ret; | 3728 | return ret > 0 ? ret2 : ret; |
3721 | } | 3729 | } |
3722 | 3730 | ||
@@ -3775,6 +3783,7 @@ int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset, | |||
3775 | } | 3783 | } |
3776 | return ret > 0 ? ret2 : ret; | 3784 | return ret > 0 ? ret2 : ret; |
3777 | } | 3785 | } |
3786 | |||
3778 | /* | 3787 | /* |
3779 | * Callback function called for each extent to gather FIEMAP information. | 3788 | * Callback function called for each extent to gather FIEMAP information. |
3780 | */ | 3789 | */ |
@@ -3782,38 +3791,162 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path, | |||
3782 | struct ext4_ext_cache *newex, struct ext4_extent *ex, | 3791 | struct ext4_ext_cache *newex, struct ext4_extent *ex, |
3783 | void *data) | 3792 | void *data) |
3784 | { | 3793 | { |
3785 | struct fiemap_extent_info *fieinfo = data; | ||
3786 | unsigned char blksize_bits = inode->i_sb->s_blocksize_bits; | ||
3787 | __u64 logical; | 3794 | __u64 logical; |
3788 | __u64 physical; | 3795 | __u64 physical; |
3789 | __u64 length; | 3796 | __u64 length; |
3797 | loff_t size; | ||
3790 | __u32 flags = 0; | 3798 | __u32 flags = 0; |
3791 | int error; | 3799 | int ret = 0; |
3800 | struct fiemap_extent_info *fieinfo = data; | ||
3801 | unsigned char blksize_bits; | ||
3792 | 3802 | ||
3793 | logical = (__u64)newex->ec_block << blksize_bits; | 3803 | blksize_bits = inode->i_sb->s_blocksize_bits; |
3804 | logical = (__u64)newex->ec_block << blksize_bits; | ||
3794 | 3805 | ||
3795 | if (newex->ec_start == 0) { | 3806 | if (newex->ec_start == 0) { |
3796 | pgoff_t offset; | 3807 | /* |
3797 | struct page *page; | 3808 | * No extent in extent-tree contains block @newex->ec_start, |
3809 | * then the block may stay in 1)a hole or 2)delayed-extent. | ||
3810 | * | ||
3811 | * Holes or delayed-extents are processed as follows. | ||
3812 | * 1. lookup dirty pages with specified range in pagecache. | ||
3813 | * If no page is got, then there is no delayed-extent and | ||
3814 | * return with EXT_CONTINUE. | ||
3815 | * 2. find the 1st mapped buffer, | ||
3816 | * 3. check if the mapped buffer is both in the request range | ||
3817 | * and a delayed buffer. If not, there is no delayed-extent, | ||
3818 | * then return. | ||
3819 | * 4. a delayed-extent is found, the extent will be collected. | ||
3820 | */ | ||
3821 | ext4_lblk_t end = 0; | ||
3822 | pgoff_t last_offset; | ||
3823 | pgoff_t offset; | ||
3824 | pgoff_t index; | ||
3825 | struct page **pages = NULL; | ||
3798 | struct buffer_head *bh = NULL; | 3826 | struct buffer_head *bh = NULL; |
3827 | struct buffer_head *head = NULL; | ||
3828 | unsigned int nr_pages = PAGE_SIZE / sizeof(struct page *); | ||
3829 | |||
3830 | pages = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
3831 | if (pages == NULL) | ||
3832 | return -ENOMEM; | ||
3799 | 3833 | ||
3800 | offset = logical >> PAGE_SHIFT; | 3834 | offset = logical >> PAGE_SHIFT; |
3801 | page = find_get_page(inode->i_mapping, offset); | 3835 | repeat: |
3802 | if (!page || !page_has_buffers(page)) | 3836 | last_offset = offset; |
3803 | return EXT_CONTINUE; | 3837 | head = NULL; |
3838 | ret = find_get_pages_tag(inode->i_mapping, &offset, | ||
3839 | PAGECACHE_TAG_DIRTY, nr_pages, pages); | ||
3840 | |||
3841 | if (!(flags & FIEMAP_EXTENT_DELALLOC)) { | ||
3842 | /* First time, try to find a mapped buffer. */ | ||
3843 | if (ret == 0) { | ||
3844 | out: | ||
3845 | for (index = 0; index < ret; index++) | ||
3846 | page_cache_release(pages[index]); | ||
3847 | /* just a hole. */ | ||
3848 | kfree(pages); | ||
3849 | return EXT_CONTINUE; | ||
3850 | } | ||
3804 | 3851 | ||
3805 | bh = page_buffers(page); | 3852 | /* Try to find the 1st mapped buffer. */ |
3853 | end = ((__u64)pages[0]->index << PAGE_SHIFT) >> | ||
3854 | blksize_bits; | ||
3855 | if (!page_has_buffers(pages[0])) | ||
3856 | goto out; | ||
3857 | head = page_buffers(pages[0]); | ||
3858 | if (!head) | ||
3859 | goto out; | ||
3806 | 3860 | ||
3807 | if (!bh) | 3861 | bh = head; |
3808 | return EXT_CONTINUE; | 3862 | do { |
3863 | if (buffer_mapped(bh)) { | ||
3864 | /* get the 1st mapped buffer. */ | ||
3865 | if (end > newex->ec_block + | ||
3866 | newex->ec_len) | ||
3867 | /* The buffer is out of | ||
3868 | * the request range. | ||
3869 | */ | ||
3870 | goto out; | ||
3871 | goto found_mapped_buffer; | ||
3872 | } | ||
3873 | bh = bh->b_this_page; | ||
3874 | end++; | ||
3875 | } while (bh != head); | ||
3809 | 3876 | ||
3810 | if (buffer_delay(bh)) { | 3877 | /* No mapped buffer found. */ |
3811 | flags |= FIEMAP_EXTENT_DELALLOC; | 3878 | goto out; |
3812 | page_cache_release(page); | ||
3813 | } else { | 3879 | } else { |
3814 | page_cache_release(page); | 3880 | /*Find contiguous delayed buffers. */ |
3815 | return EXT_CONTINUE; | 3881 | if (ret > 0 && pages[0]->index == last_offset) |
3882 | head = page_buffers(pages[0]); | ||
3883 | bh = head; | ||
3816 | } | 3884 | } |
3885 | |||
3886 | found_mapped_buffer: | ||
3887 | if (bh != NULL && buffer_delay(bh)) { | ||
3888 | /* 1st or contiguous delayed buffer found. */ | ||
3889 | if (!(flags & FIEMAP_EXTENT_DELALLOC)) { | ||
3890 | /* | ||
3891 | * 1st delayed buffer found, record | ||
3892 | * the start of extent. | ||
3893 | */ | ||
3894 | flags |= FIEMAP_EXTENT_DELALLOC; | ||
3895 | newex->ec_block = end; | ||
3896 | logical = (__u64)end << blksize_bits; | ||
3897 | } | ||
3898 | /* Find contiguous delayed buffers. */ | ||
3899 | do { | ||
3900 | if (!buffer_delay(bh)) | ||
3901 | goto found_delayed_extent; | ||
3902 | bh = bh->b_this_page; | ||
3903 | end++; | ||
3904 | } while (bh != head); | ||
3905 | |||
3906 | for (index = 1; index < ret; index++) { | ||
3907 | if (!page_has_buffers(pages[index])) { | ||
3908 | bh = NULL; | ||
3909 | break; | ||
3910 | } | ||
3911 | head = page_buffers(pages[index]); | ||
3912 | if (!head) { | ||
3913 | bh = NULL; | ||
3914 | break; | ||
3915 | } | ||
3916 | if (pages[index]->index != | ||
3917 | pages[0]->index + index) { | ||
3918 | /* Blocks are not contiguous. */ | ||
3919 | bh = NULL; | ||
3920 | break; | ||
3921 | } | ||
3922 | bh = head; | ||
3923 | do { | ||
3924 | if (!buffer_delay(bh)) | ||
3925 | /* Delayed-extent ends. */ | ||
3926 | goto found_delayed_extent; | ||
3927 | bh = bh->b_this_page; | ||
3928 | end++; | ||
3929 | } while (bh != head); | ||
3930 | } | ||
3931 | } else if (!(flags & FIEMAP_EXTENT_DELALLOC)) | ||
3932 | /* a hole found. */ | ||
3933 | goto out; | ||
3934 | |||
3935 | found_delayed_extent: | ||
3936 | newex->ec_len = min(end - newex->ec_block, | ||
3937 | (ext4_lblk_t)EXT_INIT_MAX_LEN); | ||
3938 | if (ret == nr_pages && bh != NULL && | ||
3939 | newex->ec_len < EXT_INIT_MAX_LEN && | ||
3940 | buffer_delay(bh)) { | ||
3941 | /* Have not collected an extent and continue. */ | ||
3942 | for (index = 0; index < ret; index++) | ||
3943 | page_cache_release(pages[index]); | ||
3944 | goto repeat; | ||
3945 | } | ||
3946 | |||
3947 | for (index = 0; index < ret; index++) | ||
3948 | page_cache_release(pages[index]); | ||
3949 | kfree(pages); | ||
3817 | } | 3950 | } |
3818 | 3951 | ||
3819 | physical = (__u64)newex->ec_start << blksize_bits; | 3952 | physical = (__u64)newex->ec_start << blksize_bits; |
@@ -3822,32 +3955,16 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path, | |||
3822 | if (ex && ext4_ext_is_uninitialized(ex)) | 3955 | if (ex && ext4_ext_is_uninitialized(ex)) |
3823 | flags |= FIEMAP_EXTENT_UNWRITTEN; | 3956 | flags |= FIEMAP_EXTENT_UNWRITTEN; |
3824 | 3957 | ||
3825 | /* | 3958 | size = i_size_read(inode); |
3826 | * If this extent reaches EXT_MAX_BLOCK, it must be last. | 3959 | if (logical + length >= size) |
3827 | * | ||
3828 | * Or if ext4_ext_next_allocated_block is EXT_MAX_BLOCK, | ||
3829 | * this also indicates no more allocated blocks. | ||
3830 | * | ||
3831 | * XXX this might miss a single-block extent at EXT_MAX_BLOCK | ||
3832 | */ | ||
3833 | if (ext4_ext_next_allocated_block(path) == EXT_MAX_BLOCK || | ||
3834 | newex->ec_block + newex->ec_len - 1 == EXT_MAX_BLOCK) { | ||
3835 | loff_t size = i_size_read(inode); | ||
3836 | loff_t bs = EXT4_BLOCK_SIZE(inode->i_sb); | ||
3837 | |||
3838 | flags |= FIEMAP_EXTENT_LAST; | 3960 | flags |= FIEMAP_EXTENT_LAST; |
3839 | if ((flags & FIEMAP_EXTENT_DELALLOC) && | ||
3840 | logical+length > size) | ||
3841 | length = (size - logical + bs - 1) & ~(bs-1); | ||
3842 | } | ||
3843 | 3961 | ||
3844 | error = fiemap_fill_next_extent(fieinfo, logical, physical, | 3962 | ret = fiemap_fill_next_extent(fieinfo, logical, physical, |
3845 | length, flags); | 3963 | length, flags); |
3846 | if (error < 0) | 3964 | if (ret < 0) |
3847 | return error; | 3965 | return ret; |
3848 | if (error == 1) | 3966 | if (ret == 1) |
3849 | return EXT_BREAK; | 3967 | return EXT_BREAK; |
3850 | |||
3851 | return EXT_CONTINUE; | 3968 | return EXT_CONTINUE; |
3852 | } | 3969 | } |
3853 | 3970 | ||
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index 7829b287822a..7f74019d6d77 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c | |||
@@ -164,20 +164,20 @@ int ext4_sync_file(struct file *file, int datasync) | |||
164 | 164 | ||
165 | J_ASSERT(ext4_journal_current_handle() == NULL); | 165 | J_ASSERT(ext4_journal_current_handle() == NULL); |
166 | 166 | ||
167 | trace_ext4_sync_file(file, datasync); | 167 | trace_ext4_sync_file_enter(file, datasync); |
168 | 168 | ||
169 | if (inode->i_sb->s_flags & MS_RDONLY) | 169 | if (inode->i_sb->s_flags & MS_RDONLY) |
170 | return 0; | 170 | return 0; |
171 | 171 | ||
172 | ret = ext4_flush_completed_IO(inode); | 172 | ret = ext4_flush_completed_IO(inode); |
173 | if (ret < 0) | 173 | if (ret < 0) |
174 | return ret; | 174 | goto out; |
175 | 175 | ||
176 | if (!journal) { | 176 | if (!journal) { |
177 | ret = generic_file_fsync(file, datasync); | 177 | ret = generic_file_fsync(file, datasync); |
178 | if (!ret && !list_empty(&inode->i_dentry)) | 178 | if (!ret && !list_empty(&inode->i_dentry)) |
179 | ext4_sync_parent(inode); | 179 | ext4_sync_parent(inode); |
180 | return ret; | 180 | goto out; |
181 | } | 181 | } |
182 | 182 | ||
183 | /* | 183 | /* |
@@ -194,8 +194,10 @@ int ext4_sync_file(struct file *file, int datasync) | |||
194 | * (they were dirtied by commit). But that's OK - the blocks are | 194 | * (they were dirtied by commit). But that's OK - the blocks are |
195 | * safe in-journal, which is all fsync() needs to ensure. | 195 | * safe in-journal, which is all fsync() needs to ensure. |
196 | */ | 196 | */ |
197 | if (ext4_should_journal_data(inode)) | 197 | if (ext4_should_journal_data(inode)) { |
198 | return ext4_force_commit(inode->i_sb); | 198 | ret = ext4_force_commit(inode->i_sb); |
199 | goto out; | ||
200 | } | ||
199 | 201 | ||
200 | commit_tid = datasync ? ei->i_datasync_tid : ei->i_sync_tid; | 202 | commit_tid = datasync ? ei->i_datasync_tid : ei->i_sync_tid; |
201 | if (jbd2_log_start_commit(journal, commit_tid)) { | 203 | if (jbd2_log_start_commit(journal, commit_tid)) { |
@@ -215,5 +217,7 @@ int ext4_sync_file(struct file *file, int datasync) | |||
215 | ret = jbd2_log_wait_commit(journal, commit_tid); | 217 | ret = jbd2_log_wait_commit(journal, commit_tid); |
216 | } else if (journal->j_flags & JBD2_BARRIER) | 218 | } else if (journal->j_flags & JBD2_BARRIER) |
217 | blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); | 219 | blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); |
220 | out: | ||
221 | trace_ext4_sync_file_exit(inode, ret); | ||
218 | return ret; | 222 | return ret; |
219 | } | 223 | } |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 78b79e1bd7ed..21bb2f61e502 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -152,6 +152,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) | |||
152 | * We do it here so the bitmap uptodate bit | 152 | * We do it here so the bitmap uptodate bit |
153 | * get set with buffer lock held. | 153 | * get set with buffer lock held. |
154 | */ | 154 | */ |
155 | trace_ext4_load_inode_bitmap(sb, block_group); | ||
155 | set_bitmap_uptodate(bh); | 156 | set_bitmap_uptodate(bh); |
156 | if (bh_submit_read(bh) < 0) { | 157 | if (bh_submit_read(bh) < 0) { |
157 | put_bh(bh); | 158 | put_bh(bh); |
@@ -649,7 +650,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent, | |||
649 | *group = parent_group + flex_size; | 650 | *group = parent_group + flex_size; |
650 | if (*group > ngroups) | 651 | if (*group > ngroups) |
651 | *group = 0; | 652 | *group = 0; |
652 | return find_group_orlov(sb, parent, group, mode, 0); | 653 | return find_group_orlov(sb, parent, group, mode, NULL); |
653 | } | 654 | } |
654 | 655 | ||
655 | /* | 656 | /* |
@@ -1054,6 +1055,11 @@ got: | |||
1054 | } | 1055 | } |
1055 | } | 1056 | } |
1056 | 1057 | ||
1058 | if (ext4_handle_valid(handle)) { | ||
1059 | ei->i_sync_tid = handle->h_transaction->t_tid; | ||
1060 | ei->i_datasync_tid = handle->h_transaction->t_tid; | ||
1061 | } | ||
1062 | |||
1057 | err = ext4_mark_inode_dirty(handle, inode); | 1063 | err = ext4_mark_inode_dirty(handle, inode); |
1058 | if (err) { | 1064 | if (err) { |
1059 | ext4_std_error(sb, err); | 1065 | ext4_std_error(sb, err); |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 9297ad46c465..1a86282b9024 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -173,7 +173,7 @@ int ext4_truncate_restart_trans(handle_t *handle, struct inode *inode, | |||
173 | BUG_ON(EXT4_JOURNAL(inode) == NULL); | 173 | BUG_ON(EXT4_JOURNAL(inode) == NULL); |
174 | jbd_debug(2, "restarting handle %p\n", handle); | 174 | jbd_debug(2, "restarting handle %p\n", handle); |
175 | up_write(&EXT4_I(inode)->i_data_sem); | 175 | up_write(&EXT4_I(inode)->i_data_sem); |
176 | ret = ext4_journal_restart(handle, blocks_for_truncate(inode)); | 176 | ret = ext4_journal_restart(handle, nblocks); |
177 | down_write(&EXT4_I(inode)->i_data_sem); | 177 | down_write(&EXT4_I(inode)->i_data_sem); |
178 | ext4_discard_preallocations(inode); | 178 | ext4_discard_preallocations(inode); |
179 | 179 | ||
@@ -720,7 +720,7 @@ allocated: | |||
720 | return ret; | 720 | return ret; |
721 | failed_out: | 721 | failed_out: |
722 | for (i = 0; i < index; i++) | 722 | for (i = 0; i < index; i++) |
723 | ext4_free_blocks(handle, inode, 0, new_blocks[i], 1, 0); | 723 | ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1, 0); |
724 | return ret; | 724 | return ret; |
725 | } | 725 | } |
726 | 726 | ||
@@ -823,20 +823,20 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode, | |||
823 | return err; | 823 | return err; |
824 | failed: | 824 | failed: |
825 | /* Allocation failed, free what we already allocated */ | 825 | /* Allocation failed, free what we already allocated */ |
826 | ext4_free_blocks(handle, inode, 0, new_blocks[0], 1, 0); | 826 | ext4_free_blocks(handle, inode, NULL, new_blocks[0], 1, 0); |
827 | for (i = 1; i <= n ; i++) { | 827 | for (i = 1; i <= n ; i++) { |
828 | /* | 828 | /* |
829 | * branch[i].bh is newly allocated, so there is no | 829 | * branch[i].bh is newly allocated, so there is no |
830 | * need to revoke the block, which is why we don't | 830 | * need to revoke the block, which is why we don't |
831 | * need to set EXT4_FREE_BLOCKS_METADATA. | 831 | * need to set EXT4_FREE_BLOCKS_METADATA. |
832 | */ | 832 | */ |
833 | ext4_free_blocks(handle, inode, 0, new_blocks[i], 1, | 833 | ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1, |
834 | EXT4_FREE_BLOCKS_FORGET); | 834 | EXT4_FREE_BLOCKS_FORGET); |
835 | } | 835 | } |
836 | for (i = n+1; i < indirect_blks; i++) | 836 | for (i = n+1; i < indirect_blks; i++) |
837 | ext4_free_blocks(handle, inode, 0, new_blocks[i], 1, 0); | 837 | ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1, 0); |
838 | 838 | ||
839 | ext4_free_blocks(handle, inode, 0, new_blocks[i], num, 0); | 839 | ext4_free_blocks(handle, inode, NULL, new_blocks[i], num, 0); |
840 | 840 | ||
841 | return err; | 841 | return err; |
842 | } | 842 | } |
@@ -924,7 +924,7 @@ err_out: | |||
924 | ext4_free_blocks(handle, inode, where[i].bh, 0, 1, | 924 | ext4_free_blocks(handle, inode, where[i].bh, 0, 1, |
925 | EXT4_FREE_BLOCKS_FORGET); | 925 | EXT4_FREE_BLOCKS_FORGET); |
926 | } | 926 | } |
927 | ext4_free_blocks(handle, inode, 0, le32_to_cpu(where[num].key), | 927 | ext4_free_blocks(handle, inode, NULL, le32_to_cpu(where[num].key), |
928 | blks, 0); | 928 | blks, 0); |
929 | 929 | ||
930 | return err; | 930 | return err; |
@@ -973,6 +973,7 @@ static int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, | |||
973 | int count = 0; | 973 | int count = 0; |
974 | ext4_fsblk_t first_block = 0; | 974 | ext4_fsblk_t first_block = 0; |
975 | 975 | ||
976 | trace_ext4_ind_map_blocks_enter(inode, map->m_lblk, map->m_len, flags); | ||
976 | J_ASSERT(!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))); | 977 | J_ASSERT(!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))); |
977 | J_ASSERT(handle != NULL || (flags & EXT4_GET_BLOCKS_CREATE) == 0); | 978 | J_ASSERT(handle != NULL || (flags & EXT4_GET_BLOCKS_CREATE) == 0); |
978 | depth = ext4_block_to_path(inode, map->m_lblk, offsets, | 979 | depth = ext4_block_to_path(inode, map->m_lblk, offsets, |
@@ -1058,6 +1059,8 @@ cleanup: | |||
1058 | partial--; | 1059 | partial--; |
1059 | } | 1060 | } |
1060 | out: | 1061 | out: |
1062 | trace_ext4_ind_map_blocks_exit(inode, map->m_lblk, | ||
1063 | map->m_pblk, map->m_len, err); | ||
1061 | return err; | 1064 | return err; |
1062 | } | 1065 | } |
1063 | 1066 | ||
@@ -2060,7 +2063,7 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd, | |||
2060 | if (nr_pages == 0) | 2063 | if (nr_pages == 0) |
2061 | break; | 2064 | break; |
2062 | for (i = 0; i < nr_pages; i++) { | 2065 | for (i = 0; i < nr_pages; i++) { |
2063 | int commit_write = 0, redirty_page = 0; | 2066 | int commit_write = 0, skip_page = 0; |
2064 | struct page *page = pvec.pages[i]; | 2067 | struct page *page = pvec.pages[i]; |
2065 | 2068 | ||
2066 | index = page->index; | 2069 | index = page->index; |
@@ -2086,14 +2089,12 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd, | |||
2086 | * If the page does not have buffers (for | 2089 | * If the page does not have buffers (for |
2087 | * whatever reason), try to create them using | 2090 | * whatever reason), try to create them using |
2088 | * __block_write_begin. If this fails, | 2091 | * __block_write_begin. If this fails, |
2089 | * redirty the page and move on. | 2092 | * skip the page and move on. |
2090 | */ | 2093 | */ |
2091 | if (!page_has_buffers(page)) { | 2094 | if (!page_has_buffers(page)) { |
2092 | if (__block_write_begin(page, 0, len, | 2095 | if (__block_write_begin(page, 0, len, |
2093 | noalloc_get_block_write)) { | 2096 | noalloc_get_block_write)) { |
2094 | redirty_page: | 2097 | skip_page: |
2095 | redirty_page_for_writepage(mpd->wbc, | ||
2096 | page); | ||
2097 | unlock_page(page); | 2098 | unlock_page(page); |
2098 | continue; | 2099 | continue; |
2099 | } | 2100 | } |
@@ -2104,7 +2105,7 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd, | |||
2104 | block_start = 0; | 2105 | block_start = 0; |
2105 | do { | 2106 | do { |
2106 | if (!bh) | 2107 | if (!bh) |
2107 | goto redirty_page; | 2108 | goto skip_page; |
2108 | if (map && (cur_logical >= map->m_lblk) && | 2109 | if (map && (cur_logical >= map->m_lblk) && |
2109 | (cur_logical <= (map->m_lblk + | 2110 | (cur_logical <= (map->m_lblk + |
2110 | (map->m_len - 1)))) { | 2111 | (map->m_len - 1)))) { |
@@ -2120,22 +2121,23 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd, | |||
2120 | clear_buffer_unwritten(bh); | 2121 | clear_buffer_unwritten(bh); |
2121 | } | 2122 | } |
2122 | 2123 | ||
2123 | /* redirty page if block allocation undone */ | 2124 | /* skip page if block allocation undone */ |
2124 | if (buffer_delay(bh) || buffer_unwritten(bh)) | 2125 | if (buffer_delay(bh) || buffer_unwritten(bh)) |
2125 | redirty_page = 1; | 2126 | skip_page = 1; |
2126 | bh = bh->b_this_page; | 2127 | bh = bh->b_this_page; |
2127 | block_start += bh->b_size; | 2128 | block_start += bh->b_size; |
2128 | cur_logical++; | 2129 | cur_logical++; |
2129 | pblock++; | 2130 | pblock++; |
2130 | } while (bh != page_bufs); | 2131 | } while (bh != page_bufs); |
2131 | 2132 | ||
2132 | if (redirty_page) | 2133 | if (skip_page) |
2133 | goto redirty_page; | 2134 | goto skip_page; |
2134 | 2135 | ||
2135 | if (commit_write) | 2136 | if (commit_write) |
2136 | /* mark the buffer_heads as dirty & uptodate */ | 2137 | /* mark the buffer_heads as dirty & uptodate */ |
2137 | block_commit_write(page, 0, len); | 2138 | block_commit_write(page, 0, len); |
2138 | 2139 | ||
2140 | clear_page_dirty_for_io(page); | ||
2139 | /* | 2141 | /* |
2140 | * Delalloc doesn't support data journalling, | 2142 | * Delalloc doesn't support data journalling, |
2141 | * but eventually maybe we'll lift this | 2143 | * but eventually maybe we'll lift this |
@@ -2165,8 +2167,7 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd, | |||
2165 | return ret; | 2167 | return ret; |
2166 | } | 2168 | } |
2167 | 2169 | ||
2168 | static void ext4_da_block_invalidatepages(struct mpage_da_data *mpd, | 2170 | static void ext4_da_block_invalidatepages(struct mpage_da_data *mpd) |
2169 | sector_t logical, long blk_cnt) | ||
2170 | { | 2171 | { |
2171 | int nr_pages, i; | 2172 | int nr_pages, i; |
2172 | pgoff_t index, end; | 2173 | pgoff_t index, end; |
@@ -2174,9 +2175,8 @@ static void ext4_da_block_invalidatepages(struct mpage_da_data *mpd, | |||
2174 | struct inode *inode = mpd->inode; | 2175 | struct inode *inode = mpd->inode; |
2175 | struct address_space *mapping = inode->i_mapping; | 2176 | struct address_space *mapping = inode->i_mapping; |
2176 | 2177 | ||
2177 | index = logical >> (PAGE_CACHE_SHIFT - inode->i_blkbits); | 2178 | index = mpd->first_page; |
2178 | end = (logical + blk_cnt - 1) >> | 2179 | end = mpd->next_page - 1; |
2179 | (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
2180 | while (index <= end) { | 2180 | while (index <= end) { |
2181 | nr_pages = pagevec_lookup(&pvec, mapping, index, PAGEVEC_SIZE); | 2181 | nr_pages = pagevec_lookup(&pvec, mapping, index, PAGEVEC_SIZE); |
2182 | if (nr_pages == 0) | 2182 | if (nr_pages == 0) |
@@ -2279,9 +2279,8 @@ static void mpage_da_map_and_submit(struct mpage_da_data *mpd) | |||
2279 | err = blks; | 2279 | err = blks; |
2280 | /* | 2280 | /* |
2281 | * If get block returns EAGAIN or ENOSPC and there | 2281 | * If get block returns EAGAIN or ENOSPC and there |
2282 | * appears to be free blocks we will call | 2282 | * appears to be free blocks we will just let |
2283 | * ext4_writepage() for all of the pages which will | 2283 | * mpage_da_submit_io() unlock all of the pages. |
2284 | * just redirty the pages. | ||
2285 | */ | 2284 | */ |
2286 | if (err == -EAGAIN) | 2285 | if (err == -EAGAIN) |
2287 | goto submit_io; | 2286 | goto submit_io; |
@@ -2312,8 +2311,10 @@ static void mpage_da_map_and_submit(struct mpage_da_data *mpd) | |||
2312 | ext4_print_free_blocks(mpd->inode); | 2311 | ext4_print_free_blocks(mpd->inode); |
2313 | } | 2312 | } |
2314 | /* invalidate all the pages */ | 2313 | /* invalidate all the pages */ |
2315 | ext4_da_block_invalidatepages(mpd, next, | 2314 | ext4_da_block_invalidatepages(mpd); |
2316 | mpd->b_size >> mpd->inode->i_blkbits); | 2315 | |
2316 | /* Mark this page range as having been completed */ | ||
2317 | mpd->io_done = 1; | ||
2317 | return; | 2318 | return; |
2318 | } | 2319 | } |
2319 | BUG_ON(blks == 0); | 2320 | BUG_ON(blks == 0); |
@@ -2438,102 +2439,6 @@ static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh) | |||
2438 | } | 2439 | } |
2439 | 2440 | ||
2440 | /* | 2441 | /* |
2441 | * __mpage_da_writepage - finds extent of pages and blocks | ||
2442 | * | ||
2443 | * @page: page to consider | ||
2444 | * @wbc: not used, we just follow rules | ||
2445 | * @data: context | ||
2446 | * | ||
2447 | * The function finds extents of pages and scan them for all blocks. | ||
2448 | */ | ||
2449 | static int __mpage_da_writepage(struct page *page, | ||
2450 | struct writeback_control *wbc, | ||
2451 | struct mpage_da_data *mpd) | ||
2452 | { | ||
2453 | struct inode *inode = mpd->inode; | ||
2454 | struct buffer_head *bh, *head; | ||
2455 | sector_t logical; | ||
2456 | |||
2457 | /* | ||
2458 | * Can we merge this page to current extent? | ||
2459 | */ | ||
2460 | if (mpd->next_page != page->index) { | ||
2461 | /* | ||
2462 | * Nope, we can't. So, we map non-allocated blocks | ||
2463 | * and start IO on them | ||
2464 | */ | ||
2465 | if (mpd->next_page != mpd->first_page) { | ||
2466 | mpage_da_map_and_submit(mpd); | ||
2467 | /* | ||
2468 | * skip rest of the page in the page_vec | ||
2469 | */ | ||
2470 | redirty_page_for_writepage(wbc, page); | ||
2471 | unlock_page(page); | ||
2472 | return MPAGE_DA_EXTENT_TAIL; | ||
2473 | } | ||
2474 | |||
2475 | /* | ||
2476 | * Start next extent of pages ... | ||
2477 | */ | ||
2478 | mpd->first_page = page->index; | ||
2479 | |||
2480 | /* | ||
2481 | * ... and blocks | ||
2482 | */ | ||
2483 | mpd->b_size = 0; | ||
2484 | mpd->b_state = 0; | ||
2485 | mpd->b_blocknr = 0; | ||
2486 | } | ||
2487 | |||
2488 | mpd->next_page = page->index + 1; | ||
2489 | logical = (sector_t) page->index << | ||
2490 | (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
2491 | |||
2492 | if (!page_has_buffers(page)) { | ||
2493 | mpage_add_bh_to_extent(mpd, logical, PAGE_CACHE_SIZE, | ||
2494 | (1 << BH_Dirty) | (1 << BH_Uptodate)); | ||
2495 | if (mpd->io_done) | ||
2496 | return MPAGE_DA_EXTENT_TAIL; | ||
2497 | } else { | ||
2498 | /* | ||
2499 | * Page with regular buffer heads, just add all dirty ones | ||
2500 | */ | ||
2501 | head = page_buffers(page); | ||
2502 | bh = head; | ||
2503 | do { | ||
2504 | BUG_ON(buffer_locked(bh)); | ||
2505 | /* | ||
2506 | * We need to try to allocate | ||
2507 | * unmapped blocks in the same page. | ||
2508 | * Otherwise we won't make progress | ||
2509 | * with the page in ext4_writepage | ||
2510 | */ | ||
2511 | if (ext4_bh_delay_or_unwritten(NULL, bh)) { | ||
2512 | mpage_add_bh_to_extent(mpd, logical, | ||
2513 | bh->b_size, | ||
2514 | bh->b_state); | ||
2515 | if (mpd->io_done) | ||
2516 | return MPAGE_DA_EXTENT_TAIL; | ||
2517 | } else if (buffer_dirty(bh) && (buffer_mapped(bh))) { | ||
2518 | /* | ||
2519 | * mapped dirty buffer. We need to update | ||
2520 | * the b_state because we look at | ||
2521 | * b_state in mpage_da_map_blocks. We don't | ||
2522 | * update b_size because if we find an | ||
2523 | * unmapped buffer_head later we need to | ||
2524 | * use the b_state flag of that buffer_head. | ||
2525 | */ | ||
2526 | if (mpd->b_size == 0) | ||
2527 | mpd->b_state = bh->b_state & BH_FLAGS; | ||
2528 | } | ||
2529 | logical++; | ||
2530 | } while ((bh = bh->b_this_page) != head); | ||
2531 | } | ||
2532 | |||
2533 | return 0; | ||
2534 | } | ||
2535 | |||
2536 | /* | ||
2537 | * This is a special get_blocks_t callback which is used by | 2442 | * This is a special get_blocks_t callback which is used by |
2538 | * ext4_da_write_begin(). It will either return mapped block or | 2443 | * ext4_da_write_begin(). It will either return mapped block or |
2539 | * reserve space for a single block. | 2444 | * reserve space for a single block. |
@@ -2597,7 +2502,6 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock, | |||
2597 | * for partial write. | 2502 | * for partial write. |
2598 | */ | 2503 | */ |
2599 | set_buffer_new(bh); | 2504 | set_buffer_new(bh); |
2600 | set_buffer_mapped(bh); | ||
2601 | } | 2505 | } |
2602 | return 0; | 2506 | return 0; |
2603 | } | 2507 | } |
@@ -2811,27 +2715,27 @@ static int ext4_da_writepages_trans_blocks(struct inode *inode) | |||
2811 | 2715 | ||
2812 | /* | 2716 | /* |
2813 | * write_cache_pages_da - walk the list of dirty pages of the given | 2717 | * write_cache_pages_da - walk the list of dirty pages of the given |
2814 | * address space and call the callback function (which usually writes | 2718 | * address space and accumulate pages that need writing, and call |
2815 | * the pages). | 2719 | * mpage_da_map_and_submit to map a single contiguous memory region |
2816 | * | 2720 | * and then write them. |
2817 | * This is a forked version of write_cache_pages(). Differences: | ||
2818 | * Range cyclic is ignored. | ||
2819 | * no_nrwrite_index_update is always presumed true | ||
2820 | */ | 2721 | */ |
2821 | static int write_cache_pages_da(struct address_space *mapping, | 2722 | static int write_cache_pages_da(struct address_space *mapping, |
2822 | struct writeback_control *wbc, | 2723 | struct writeback_control *wbc, |
2823 | struct mpage_da_data *mpd, | 2724 | struct mpage_da_data *mpd, |
2824 | pgoff_t *done_index) | 2725 | pgoff_t *done_index) |
2825 | { | 2726 | { |
2826 | int ret = 0; | 2727 | struct buffer_head *bh, *head; |
2827 | int done = 0; | 2728 | struct inode *inode = mapping->host; |
2828 | struct pagevec pvec; | 2729 | struct pagevec pvec; |
2829 | unsigned nr_pages; | 2730 | unsigned int nr_pages; |
2830 | pgoff_t index; | 2731 | sector_t logical; |
2831 | pgoff_t end; /* Inclusive */ | 2732 | pgoff_t index, end; |
2832 | long nr_to_write = wbc->nr_to_write; | 2733 | long nr_to_write = wbc->nr_to_write; |
2833 | int tag; | 2734 | int i, tag, ret = 0; |
2834 | 2735 | ||
2736 | memset(mpd, 0, sizeof(struct mpage_da_data)); | ||
2737 | mpd->wbc = wbc; | ||
2738 | mpd->inode = inode; | ||
2835 | pagevec_init(&pvec, 0); | 2739 | pagevec_init(&pvec, 0); |
2836 | index = wbc->range_start >> PAGE_CACHE_SHIFT; | 2740 | index = wbc->range_start >> PAGE_CACHE_SHIFT; |
2837 | end = wbc->range_end >> PAGE_CACHE_SHIFT; | 2741 | end = wbc->range_end >> PAGE_CACHE_SHIFT; |
@@ -2842,13 +2746,11 @@ static int write_cache_pages_da(struct address_space *mapping, | |||
2842 | tag = PAGECACHE_TAG_DIRTY; | 2746 | tag = PAGECACHE_TAG_DIRTY; |
2843 | 2747 | ||
2844 | *done_index = index; | 2748 | *done_index = index; |
2845 | while (!done && (index <= end)) { | 2749 | while (index <= end) { |
2846 | int i; | ||
2847 | |||
2848 | nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag, | 2750 | nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag, |
2849 | min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1); | 2751 | min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1); |
2850 | if (nr_pages == 0) | 2752 | if (nr_pages == 0) |
2851 | break; | 2753 | return 0; |
2852 | 2754 | ||
2853 | for (i = 0; i < nr_pages; i++) { | 2755 | for (i = 0; i < nr_pages; i++) { |
2854 | struct page *page = pvec.pages[i]; | 2756 | struct page *page = pvec.pages[i]; |
@@ -2860,60 +2762,100 @@ static int write_cache_pages_da(struct address_space *mapping, | |||
2860 | * mapping. However, page->index will not change | 2762 | * mapping. However, page->index will not change |
2861 | * because we have a reference on the page. | 2763 | * because we have a reference on the page. |
2862 | */ | 2764 | */ |
2863 | if (page->index > end) { | 2765 | if (page->index > end) |
2864 | done = 1; | 2766 | goto out; |
2865 | break; | ||
2866 | } | ||
2867 | 2767 | ||
2868 | *done_index = page->index + 1; | 2768 | *done_index = page->index + 1; |
2869 | 2769 | ||
2770 | /* | ||
2771 | * If we can't merge this page, and we have | ||
2772 | * accumulated an contiguous region, write it | ||
2773 | */ | ||
2774 | if ((mpd->next_page != page->index) && | ||
2775 | (mpd->next_page != mpd->first_page)) { | ||
2776 | mpage_da_map_and_submit(mpd); | ||
2777 | goto ret_extent_tail; | ||
2778 | } | ||
2779 | |||
2870 | lock_page(page); | 2780 | lock_page(page); |
2871 | 2781 | ||
2872 | /* | 2782 | /* |
2873 | * Page truncated or invalidated. We can freely skip it | 2783 | * If the page is no longer dirty, or its |
2874 | * then, even for data integrity operations: the page | 2784 | * mapping no longer corresponds to inode we |
2875 | * has disappeared concurrently, so there could be no | 2785 | * are writing (which means it has been |
2876 | * real expectation of this data interity operation | 2786 | * truncated or invalidated), or the page is |
2877 | * even if there is now a new, dirty page at the same | 2787 | * already under writeback and we are not |
2878 | * pagecache address. | 2788 | * doing a data integrity writeback, skip the page |
2879 | */ | 2789 | */ |
2880 | if (unlikely(page->mapping != mapping)) { | 2790 | if (!PageDirty(page) || |
2881 | continue_unlock: | 2791 | (PageWriteback(page) && |
2792 | (wbc->sync_mode == WB_SYNC_NONE)) || | ||
2793 | unlikely(page->mapping != mapping)) { | ||
2882 | unlock_page(page); | 2794 | unlock_page(page); |
2883 | continue; | 2795 | continue; |
2884 | } | 2796 | } |
2885 | 2797 | ||
2886 | if (!PageDirty(page)) { | 2798 | if (PageWriteback(page)) |
2887 | /* someone wrote it for us */ | 2799 | wait_on_page_writeback(page); |
2888 | goto continue_unlock; | ||
2889 | } | ||
2890 | |||
2891 | if (PageWriteback(page)) { | ||
2892 | if (wbc->sync_mode != WB_SYNC_NONE) | ||
2893 | wait_on_page_writeback(page); | ||
2894 | else | ||
2895 | goto continue_unlock; | ||
2896 | } | ||
2897 | 2800 | ||
2898 | BUG_ON(PageWriteback(page)); | 2801 | BUG_ON(PageWriteback(page)); |
2899 | if (!clear_page_dirty_for_io(page)) | ||
2900 | goto continue_unlock; | ||
2901 | 2802 | ||
2902 | ret = __mpage_da_writepage(page, wbc, mpd); | 2803 | if (mpd->next_page != page->index) |
2903 | if (unlikely(ret)) { | 2804 | mpd->first_page = page->index; |
2904 | if (ret == AOP_WRITEPAGE_ACTIVATE) { | 2805 | mpd->next_page = page->index + 1; |
2905 | unlock_page(page); | 2806 | logical = (sector_t) page->index << |
2906 | ret = 0; | 2807 | (PAGE_CACHE_SHIFT - inode->i_blkbits); |
2907 | } else { | 2808 | |
2908 | done = 1; | 2809 | if (!page_has_buffers(page)) { |
2909 | break; | 2810 | mpage_add_bh_to_extent(mpd, logical, |
2910 | } | 2811 | PAGE_CACHE_SIZE, |
2812 | (1 << BH_Dirty) | (1 << BH_Uptodate)); | ||
2813 | if (mpd->io_done) | ||
2814 | goto ret_extent_tail; | ||
2815 | } else { | ||
2816 | /* | ||
2817 | * Page with regular buffer heads, | ||
2818 | * just add all dirty ones | ||
2819 | */ | ||
2820 | head = page_buffers(page); | ||
2821 | bh = head; | ||
2822 | do { | ||
2823 | BUG_ON(buffer_locked(bh)); | ||
2824 | /* | ||
2825 | * We need to try to allocate | ||
2826 | * unmapped blocks in the same page. | ||
2827 | * Otherwise we won't make progress | ||
2828 | * with the page in ext4_writepage | ||
2829 | */ | ||
2830 | if (ext4_bh_delay_or_unwritten(NULL, bh)) { | ||
2831 | mpage_add_bh_to_extent(mpd, logical, | ||
2832 | bh->b_size, | ||
2833 | bh->b_state); | ||
2834 | if (mpd->io_done) | ||
2835 | goto ret_extent_tail; | ||
2836 | } else if (buffer_dirty(bh) && (buffer_mapped(bh))) { | ||
2837 | /* | ||
2838 | * mapped dirty buffer. We need | ||
2839 | * to update the b_state | ||
2840 | * because we look at b_state | ||
2841 | * in mpage_da_map_blocks. We | ||
2842 | * don't update b_size because | ||
2843 | * if we find an unmapped | ||
2844 | * buffer_head later we need to | ||
2845 | * use the b_state flag of that | ||
2846 | * buffer_head. | ||
2847 | */ | ||
2848 | if (mpd->b_size == 0) | ||
2849 | mpd->b_state = bh->b_state & BH_FLAGS; | ||
2850 | } | ||
2851 | logical++; | ||
2852 | } while ((bh = bh->b_this_page) != head); | ||
2911 | } | 2853 | } |
2912 | 2854 | ||
2913 | if (nr_to_write > 0) { | 2855 | if (nr_to_write > 0) { |
2914 | nr_to_write--; | 2856 | nr_to_write--; |
2915 | if (nr_to_write == 0 && | 2857 | if (nr_to_write == 0 && |
2916 | wbc->sync_mode == WB_SYNC_NONE) { | 2858 | wbc->sync_mode == WB_SYNC_NONE) |
2917 | /* | 2859 | /* |
2918 | * We stop writing back only if we are | 2860 | * We stop writing back only if we are |
2919 | * not doing integrity sync. In case of | 2861 | * not doing integrity sync. In case of |
@@ -2924,14 +2866,18 @@ continue_unlock: | |||
2924 | * pages, but have not synced all of the | 2866 | * pages, but have not synced all of the |
2925 | * old dirty pages. | 2867 | * old dirty pages. |
2926 | */ | 2868 | */ |
2927 | done = 1; | 2869 | goto out; |
2928 | break; | ||
2929 | } | ||
2930 | } | 2870 | } |
2931 | } | 2871 | } |
2932 | pagevec_release(&pvec); | 2872 | pagevec_release(&pvec); |
2933 | cond_resched(); | 2873 | cond_resched(); |
2934 | } | 2874 | } |
2875 | return 0; | ||
2876 | ret_extent_tail: | ||
2877 | ret = MPAGE_DA_EXTENT_TAIL; | ||
2878 | out: | ||
2879 | pagevec_release(&pvec); | ||
2880 | cond_resched(); | ||
2935 | return ret; | 2881 | return ret; |
2936 | } | 2882 | } |
2937 | 2883 | ||
@@ -2945,7 +2891,6 @@ static int ext4_da_writepages(struct address_space *mapping, | |||
2945 | struct mpage_da_data mpd; | 2891 | struct mpage_da_data mpd; |
2946 | struct inode *inode = mapping->host; | 2892 | struct inode *inode = mapping->host; |
2947 | int pages_written = 0; | 2893 | int pages_written = 0; |
2948 | long pages_skipped; | ||
2949 | unsigned int max_pages; | 2894 | unsigned int max_pages; |
2950 | int range_cyclic, cycled = 1, io_done = 0; | 2895 | int range_cyclic, cycled = 1, io_done = 0; |
2951 | int needed_blocks, ret = 0; | 2896 | int needed_blocks, ret = 0; |
@@ -3028,11 +2973,6 @@ static int ext4_da_writepages(struct address_space *mapping, | |||
3028 | wbc->nr_to_write = desired_nr_to_write; | 2973 | wbc->nr_to_write = desired_nr_to_write; |
3029 | } | 2974 | } |
3030 | 2975 | ||
3031 | mpd.wbc = wbc; | ||
3032 | mpd.inode = mapping->host; | ||
3033 | |||
3034 | pages_skipped = wbc->pages_skipped; | ||
3035 | |||
3036 | retry: | 2976 | retry: |
3037 | if (wbc->sync_mode == WB_SYNC_ALL) | 2977 | if (wbc->sync_mode == WB_SYNC_ALL) |
3038 | tag_pages_for_writeback(mapping, index, end); | 2978 | tag_pages_for_writeback(mapping, index, end); |
@@ -3059,22 +2999,10 @@ retry: | |||
3059 | } | 2999 | } |
3060 | 3000 | ||
3061 | /* | 3001 | /* |
3062 | * Now call __mpage_da_writepage to find the next | 3002 | * Now call write_cache_pages_da() to find the next |
3063 | * contiguous region of logical blocks that need | 3003 | * contiguous region of logical blocks that need |
3064 | * blocks to be allocated by ext4. We don't actually | 3004 | * blocks to be allocated by ext4 and submit them. |
3065 | * submit the blocks for I/O here, even though | ||
3066 | * write_cache_pages thinks it will, and will set the | ||
3067 | * pages as clean for write before calling | ||
3068 | * __mpage_da_writepage(). | ||
3069 | */ | 3005 | */ |
3070 | mpd.b_size = 0; | ||
3071 | mpd.b_state = 0; | ||
3072 | mpd.b_blocknr = 0; | ||
3073 | mpd.first_page = 0; | ||
3074 | mpd.next_page = 0; | ||
3075 | mpd.io_done = 0; | ||
3076 | mpd.pages_written = 0; | ||
3077 | mpd.retval = 0; | ||
3078 | ret = write_cache_pages_da(mapping, wbc, &mpd, &done_index); | 3006 | ret = write_cache_pages_da(mapping, wbc, &mpd, &done_index); |
3079 | /* | 3007 | /* |
3080 | * If we have a contiguous extent of pages and we | 3008 | * If we have a contiguous extent of pages and we |
@@ -3096,7 +3024,6 @@ retry: | |||
3096 | * and try again | 3024 | * and try again |
3097 | */ | 3025 | */ |
3098 | jbd2_journal_force_commit_nested(sbi->s_journal); | 3026 | jbd2_journal_force_commit_nested(sbi->s_journal); |
3099 | wbc->pages_skipped = pages_skipped; | ||
3100 | ret = 0; | 3027 | ret = 0; |
3101 | } else if (ret == MPAGE_DA_EXTENT_TAIL) { | 3028 | } else if (ret == MPAGE_DA_EXTENT_TAIL) { |
3102 | /* | 3029 | /* |
@@ -3104,7 +3031,6 @@ retry: | |||
3104 | * rest of the pages | 3031 | * rest of the pages |
3105 | */ | 3032 | */ |
3106 | pages_written += mpd.pages_written; | 3033 | pages_written += mpd.pages_written; |
3107 | wbc->pages_skipped = pages_skipped; | ||
3108 | ret = 0; | 3034 | ret = 0; |
3109 | io_done = 1; | 3035 | io_done = 1; |
3110 | } else if (wbc->nr_to_write) | 3036 | } else if (wbc->nr_to_write) |
@@ -3122,11 +3048,6 @@ retry: | |||
3122 | wbc->range_end = mapping->writeback_index - 1; | 3048 | wbc->range_end = mapping->writeback_index - 1; |
3123 | goto retry; | 3049 | goto retry; |
3124 | } | 3050 | } |
3125 | if (pages_skipped != wbc->pages_skipped) | ||
3126 | ext4_msg(inode->i_sb, KERN_CRIT, | ||
3127 | "This should not happen leaving %s " | ||
3128 | "with nr_to_write = %ld ret = %d", | ||
3129 | __func__, wbc->nr_to_write, ret); | ||
3130 | 3051 | ||
3131 | /* Update index */ | 3052 | /* Update index */ |
3132 | wbc->range_cyclic = range_cyclic; | 3053 | wbc->range_cyclic = range_cyclic; |
@@ -3460,6 +3381,7 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block) | |||
3460 | 3381 | ||
3461 | static int ext4_readpage(struct file *file, struct page *page) | 3382 | static int ext4_readpage(struct file *file, struct page *page) |
3462 | { | 3383 | { |
3384 | trace_ext4_readpage(page); | ||
3463 | return mpage_readpage(page, ext4_get_block); | 3385 | return mpage_readpage(page, ext4_get_block); |
3464 | } | 3386 | } |
3465 | 3387 | ||
@@ -3494,6 +3416,8 @@ static void ext4_invalidatepage(struct page *page, unsigned long offset) | |||
3494 | { | 3416 | { |
3495 | journal_t *journal = EXT4_JOURNAL(page->mapping->host); | 3417 | journal_t *journal = EXT4_JOURNAL(page->mapping->host); |
3496 | 3418 | ||
3419 | trace_ext4_invalidatepage(page, offset); | ||
3420 | |||
3497 | /* | 3421 | /* |
3498 | * free any io_end structure allocated for buffers to be discarded | 3422 | * free any io_end structure allocated for buffers to be discarded |
3499 | */ | 3423 | */ |
@@ -3515,6 +3439,8 @@ static int ext4_releasepage(struct page *page, gfp_t wait) | |||
3515 | { | 3439 | { |
3516 | journal_t *journal = EXT4_JOURNAL(page->mapping->host); | 3440 | journal_t *journal = EXT4_JOURNAL(page->mapping->host); |
3517 | 3441 | ||
3442 | trace_ext4_releasepage(page); | ||
3443 | |||
3518 | WARN_ON(PageChecked(page)); | 3444 | WARN_ON(PageChecked(page)); |
3519 | if (!page_has_buffers(page)) | 3445 | if (!page_has_buffers(page)) |
3520 | return 0; | 3446 | return 0; |
@@ -3873,11 +3799,16 @@ static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb, | |||
3873 | { | 3799 | { |
3874 | struct file *file = iocb->ki_filp; | 3800 | struct file *file = iocb->ki_filp; |
3875 | struct inode *inode = file->f_mapping->host; | 3801 | struct inode *inode = file->f_mapping->host; |
3802 | ssize_t ret; | ||
3876 | 3803 | ||
3804 | trace_ext4_direct_IO_enter(inode, offset, iov_length(iov, nr_segs), rw); | ||
3877 | if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) | 3805 | if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) |
3878 | return ext4_ext_direct_IO(rw, iocb, iov, offset, nr_segs); | 3806 | ret = ext4_ext_direct_IO(rw, iocb, iov, offset, nr_segs); |
3879 | 3807 | else | |
3880 | return ext4_ind_direct_IO(rw, iocb, iov, offset, nr_segs); | 3808 | ret = ext4_ind_direct_IO(rw, iocb, iov, offset, nr_segs); |
3809 | trace_ext4_direct_IO_exit(inode, offset, | ||
3810 | iov_length(iov, nr_segs), rw, ret); | ||
3811 | return ret; | ||
3881 | } | 3812 | } |
3882 | 3813 | ||
3883 | /* | 3814 | /* |
@@ -4173,6 +4104,9 @@ no_top: | |||
4173 | * | 4104 | * |
4174 | * We release `count' blocks on disk, but (last - first) may be greater | 4105 | * We release `count' blocks on disk, but (last - first) may be greater |
4175 | * than `count' because there can be holes in there. | 4106 | * than `count' because there can be holes in there. |
4107 | * | ||
4108 | * Return 0 on success, 1 on invalid block range | ||
4109 | * and < 0 on fatal error. | ||
4176 | */ | 4110 | */ |
4177 | static int ext4_clear_blocks(handle_t *handle, struct inode *inode, | 4111 | static int ext4_clear_blocks(handle_t *handle, struct inode *inode, |
4178 | struct buffer_head *bh, | 4112 | struct buffer_head *bh, |
@@ -4199,33 +4133,32 @@ static int ext4_clear_blocks(handle_t *handle, struct inode *inode, | |||
4199 | if (bh) { | 4133 | if (bh) { |
4200 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); | 4134 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); |
4201 | err = ext4_handle_dirty_metadata(handle, inode, bh); | 4135 | err = ext4_handle_dirty_metadata(handle, inode, bh); |
4202 | if (unlikely(err)) { | 4136 | if (unlikely(err)) |
4203 | ext4_std_error(inode->i_sb, err); | 4137 | goto out_err; |
4204 | return 1; | ||
4205 | } | ||
4206 | } | 4138 | } |
4207 | err = ext4_mark_inode_dirty(handle, inode); | 4139 | err = ext4_mark_inode_dirty(handle, inode); |
4208 | if (unlikely(err)) { | 4140 | if (unlikely(err)) |
4209 | ext4_std_error(inode->i_sb, err); | 4141 | goto out_err; |
4210 | return 1; | ||
4211 | } | ||
4212 | err = ext4_truncate_restart_trans(handle, inode, | 4142 | err = ext4_truncate_restart_trans(handle, inode, |
4213 | blocks_for_truncate(inode)); | 4143 | blocks_for_truncate(inode)); |
4214 | if (unlikely(err)) { | 4144 | if (unlikely(err)) |
4215 | ext4_std_error(inode->i_sb, err); | 4145 | goto out_err; |
4216 | return 1; | ||
4217 | } | ||
4218 | if (bh) { | 4146 | if (bh) { |
4219 | BUFFER_TRACE(bh, "retaking write access"); | 4147 | BUFFER_TRACE(bh, "retaking write access"); |
4220 | ext4_journal_get_write_access(handle, bh); | 4148 | err = ext4_journal_get_write_access(handle, bh); |
4149 | if (unlikely(err)) | ||
4150 | goto out_err; | ||
4221 | } | 4151 | } |
4222 | } | 4152 | } |
4223 | 4153 | ||
4224 | for (p = first; p < last; p++) | 4154 | for (p = first; p < last; p++) |
4225 | *p = 0; | 4155 | *p = 0; |
4226 | 4156 | ||
4227 | ext4_free_blocks(handle, inode, 0, block_to_free, count, flags); | 4157 | ext4_free_blocks(handle, inode, NULL, block_to_free, count, flags); |
4228 | return 0; | 4158 | return 0; |
4159 | out_err: | ||
4160 | ext4_std_error(inode->i_sb, err); | ||
4161 | return err; | ||
4229 | } | 4162 | } |
4230 | 4163 | ||
4231 | /** | 4164 | /** |
@@ -4259,7 +4192,7 @@ static void ext4_free_data(handle_t *handle, struct inode *inode, | |||
4259 | ext4_fsblk_t nr; /* Current block # */ | 4192 | ext4_fsblk_t nr; /* Current block # */ |
4260 | __le32 *p; /* Pointer into inode/ind | 4193 | __le32 *p; /* Pointer into inode/ind |
4261 | for current block */ | 4194 | for current block */ |
4262 | int err; | 4195 | int err = 0; |
4263 | 4196 | ||
4264 | if (this_bh) { /* For indirect block */ | 4197 | if (this_bh) { /* For indirect block */ |
4265 | BUFFER_TRACE(this_bh, "get_write_access"); | 4198 | BUFFER_TRACE(this_bh, "get_write_access"); |
@@ -4281,9 +4214,10 @@ static void ext4_free_data(handle_t *handle, struct inode *inode, | |||
4281 | } else if (nr == block_to_free + count) { | 4214 | } else if (nr == block_to_free + count) { |
4282 | count++; | 4215 | count++; |
4283 | } else { | 4216 | } else { |
4284 | if (ext4_clear_blocks(handle, inode, this_bh, | 4217 | err = ext4_clear_blocks(handle, inode, this_bh, |
4285 | block_to_free, count, | 4218 | block_to_free, count, |
4286 | block_to_free_p, p)) | 4219 | block_to_free_p, p); |
4220 | if (err) | ||
4287 | break; | 4221 | break; |
4288 | block_to_free = nr; | 4222 | block_to_free = nr; |
4289 | block_to_free_p = p; | 4223 | block_to_free_p = p; |
@@ -4292,9 +4226,12 @@ static void ext4_free_data(handle_t *handle, struct inode *inode, | |||
4292 | } | 4226 | } |
4293 | } | 4227 | } |
4294 | 4228 | ||
4295 | if (count > 0) | 4229 | if (!err && count > 0) |
4296 | ext4_clear_blocks(handle, inode, this_bh, block_to_free, | 4230 | err = ext4_clear_blocks(handle, inode, this_bh, block_to_free, |
4297 | count, block_to_free_p, p); | 4231 | count, block_to_free_p, p); |
4232 | if (err < 0) | ||
4233 | /* fatal error */ | ||
4234 | return; | ||
4298 | 4235 | ||
4299 | if (this_bh) { | 4236 | if (this_bh) { |
4300 | BUFFER_TRACE(this_bh, "call ext4_handle_dirty_metadata"); | 4237 | BUFFER_TRACE(this_bh, "call ext4_handle_dirty_metadata"); |
@@ -4412,7 +4349,7 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode, | |||
4412 | * transaction where the data blocks are | 4349 | * transaction where the data blocks are |
4413 | * actually freed. | 4350 | * actually freed. |
4414 | */ | 4351 | */ |
4415 | ext4_free_blocks(handle, inode, 0, nr, 1, | 4352 | ext4_free_blocks(handle, inode, NULL, nr, 1, |
4416 | EXT4_FREE_BLOCKS_METADATA| | 4353 | EXT4_FREE_BLOCKS_METADATA| |
4417 | EXT4_FREE_BLOCKS_FORGET); | 4354 | EXT4_FREE_BLOCKS_FORGET); |
4418 | 4355 | ||
@@ -4496,6 +4433,8 @@ void ext4_truncate(struct inode *inode) | |||
4496 | ext4_lblk_t last_block; | 4433 | ext4_lblk_t last_block; |
4497 | unsigned blocksize = inode->i_sb->s_blocksize; | 4434 | unsigned blocksize = inode->i_sb->s_blocksize; |
4498 | 4435 | ||
4436 | trace_ext4_truncate_enter(inode); | ||
4437 | |||
4499 | if (!ext4_can_truncate(inode)) | 4438 | if (!ext4_can_truncate(inode)) |
4500 | return; | 4439 | return; |
4501 | 4440 | ||
@@ -4506,6 +4445,7 @@ void ext4_truncate(struct inode *inode) | |||
4506 | 4445 | ||
4507 | if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) { | 4446 | if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) { |
4508 | ext4_ext_truncate(inode); | 4447 | ext4_ext_truncate(inode); |
4448 | trace_ext4_truncate_exit(inode); | ||
4509 | return; | 4449 | return; |
4510 | } | 4450 | } |
4511 | 4451 | ||
@@ -4635,6 +4575,7 @@ out_stop: | |||
4635 | ext4_orphan_del(handle, inode); | 4575 | ext4_orphan_del(handle, inode); |
4636 | 4576 | ||
4637 | ext4_journal_stop(handle); | 4577 | ext4_journal_stop(handle); |
4578 | trace_ext4_truncate_exit(inode); | ||
4638 | } | 4579 | } |
4639 | 4580 | ||
4640 | /* | 4581 | /* |
@@ -4766,6 +4707,7 @@ make_io: | |||
4766 | * has in-inode xattrs, or we don't have this inode in memory. | 4707 | * has in-inode xattrs, or we don't have this inode in memory. |
4767 | * Read the block from disk. | 4708 | * Read the block from disk. |
4768 | */ | 4709 | */ |
4710 | trace_ext4_load_inode(inode); | ||
4769 | get_bh(bh); | 4711 | get_bh(bh); |
4770 | bh->b_end_io = end_buffer_read_sync; | 4712 | bh->b_end_io = end_buffer_read_sync; |
4771 | submit_bh(READ_META, bh); | 4713 | submit_bh(READ_META, bh); |
@@ -4871,7 +4813,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4871 | return inode; | 4813 | return inode; |
4872 | 4814 | ||
4873 | ei = EXT4_I(inode); | 4815 | ei = EXT4_I(inode); |
4874 | iloc.bh = 0; | 4816 | iloc.bh = NULL; |
4875 | 4817 | ||
4876 | ret = __ext4_get_inode_loc(inode, &iloc, 0); | 4818 | ret = __ext4_get_inode_loc(inode, &iloc, 0); |
4877 | if (ret < 0) | 4819 | if (ret < 0) |
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index a84faa110bcd..808c554e773f 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c | |||
@@ -334,16 +334,22 @@ mext_out: | |||
334 | case FITRIM: | 334 | case FITRIM: |
335 | { | 335 | { |
336 | struct super_block *sb = inode->i_sb; | 336 | struct super_block *sb = inode->i_sb; |
337 | struct request_queue *q = bdev_get_queue(sb->s_bdev); | ||
337 | struct fstrim_range range; | 338 | struct fstrim_range range; |
338 | int ret = 0; | 339 | int ret = 0; |
339 | 340 | ||
340 | if (!capable(CAP_SYS_ADMIN)) | 341 | if (!capable(CAP_SYS_ADMIN)) |
341 | return -EPERM; | 342 | return -EPERM; |
342 | 343 | ||
344 | if (!blk_queue_discard(q)) | ||
345 | return -EOPNOTSUPP; | ||
346 | |||
343 | if (copy_from_user(&range, (struct fstrim_range *)arg, | 347 | if (copy_from_user(&range, (struct fstrim_range *)arg, |
344 | sizeof(range))) | 348 | sizeof(range))) |
345 | return -EFAULT; | 349 | return -EFAULT; |
346 | 350 | ||
351 | range.minlen = max((unsigned int)range.minlen, | ||
352 | q->limits.discard_granularity); | ||
347 | ret = ext4_trim_fs(sb, &range); | 353 | ret = ext4_trim_fs(sb, &range); |
348 | if (ret < 0) | 354 | if (ret < 0) |
349 | return ret; | 355 | return ret; |
@@ -421,6 +427,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
421 | return err; | 427 | return err; |
422 | } | 428 | } |
423 | case EXT4_IOC_MOVE_EXT: | 429 | case EXT4_IOC_MOVE_EXT: |
430 | case FITRIM: | ||
424 | break; | 431 | break; |
425 | default: | 432 | default: |
426 | return -ENOIOCTLCMD; | 433 | return -ENOIOCTLCMD; |
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index d1fe09aea73d..a5837a837a8b 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -432,9 +432,10 @@ static void *mb_find_buddy(struct ext4_buddy *e4b, int order, int *max) | |||
432 | } | 432 | } |
433 | 433 | ||
434 | /* at order 0 we see each particular block */ | 434 | /* at order 0 we see each particular block */ |
435 | *max = 1 << (e4b->bd_blkbits + 3); | 435 | if (order == 0) { |
436 | if (order == 0) | 436 | *max = 1 << (e4b->bd_blkbits + 3); |
437 | return EXT4_MB_BITMAP(e4b); | 437 | return EXT4_MB_BITMAP(e4b); |
438 | } | ||
438 | 439 | ||
439 | bb = EXT4_MB_BUDDY(e4b) + EXT4_SB(e4b->bd_sb)->s_mb_offsets[order]; | 440 | bb = EXT4_MB_BUDDY(e4b) + EXT4_SB(e4b->bd_sb)->s_mb_offsets[order]; |
440 | *max = EXT4_SB(e4b->bd_sb)->s_mb_maxs[order]; | 441 | *max = EXT4_SB(e4b->bd_sb)->s_mb_maxs[order]; |
@@ -616,7 +617,6 @@ static int __mb_check_buddy(struct ext4_buddy *e4b, char *file, | |||
616 | MB_CHECK_ASSERT(e4b->bd_info->bb_fragments == fragments); | 617 | MB_CHECK_ASSERT(e4b->bd_info->bb_fragments == fragments); |
617 | 618 | ||
618 | grp = ext4_get_group_info(sb, e4b->bd_group); | 619 | grp = ext4_get_group_info(sb, e4b->bd_group); |
619 | buddy = mb_find_buddy(e4b, 0, &max); | ||
620 | list_for_each(cur, &grp->bb_prealloc_list) { | 620 | list_for_each(cur, &grp->bb_prealloc_list) { |
621 | ext4_group_t groupnr; | 621 | ext4_group_t groupnr; |
622 | struct ext4_prealloc_space *pa; | 622 | struct ext4_prealloc_space *pa; |
@@ -635,7 +635,12 @@ static int __mb_check_buddy(struct ext4_buddy *e4b, char *file, | |||
635 | #define mb_check_buddy(e4b) | 635 | #define mb_check_buddy(e4b) |
636 | #endif | 636 | #endif |
637 | 637 | ||
638 | /* FIXME!! need more doc */ | 638 | /* |
639 | * Divide blocks started from @first with length @len into | ||
640 | * smaller chunks with power of 2 blocks. | ||
641 | * Clear the bits in bitmap which the blocks of the chunk(s) covered, | ||
642 | * then increase bb_counters[] for corresponded chunk size. | ||
643 | */ | ||
639 | static void ext4_mb_mark_free_simple(struct super_block *sb, | 644 | static void ext4_mb_mark_free_simple(struct super_block *sb, |
640 | void *buddy, ext4_grpblk_t first, ext4_grpblk_t len, | 645 | void *buddy, ext4_grpblk_t first, ext4_grpblk_t len, |
641 | struct ext4_group_info *grp) | 646 | struct ext4_group_info *grp) |
@@ -2381,7 +2386,7 @@ static int ext4_mb_init_backend(struct super_block *sb) | |||
2381 | /* An 8TB filesystem with 64-bit pointers requires a 4096 byte | 2386 | /* An 8TB filesystem with 64-bit pointers requires a 4096 byte |
2382 | * kmalloc. A 128kb malloc should suffice for a 256TB filesystem. | 2387 | * kmalloc. A 128kb malloc should suffice for a 256TB filesystem. |
2383 | * So a two level scheme suffices for now. */ | 2388 | * So a two level scheme suffices for now. */ |
2384 | sbi->s_group_info = kmalloc(array_size, GFP_KERNEL); | 2389 | sbi->s_group_info = kzalloc(array_size, GFP_KERNEL); |
2385 | if (sbi->s_group_info == NULL) { | 2390 | if (sbi->s_group_info == NULL) { |
2386 | printk(KERN_ERR "EXT4-fs: can't allocate buddy meta group\n"); | 2391 | printk(KERN_ERR "EXT4-fs: can't allocate buddy meta group\n"); |
2387 | return -ENOMEM; | 2392 | return -ENOMEM; |
@@ -3208,7 +3213,7 @@ ext4_mb_check_group_pa(ext4_fsblk_t goal_block, | |||
3208 | cur_distance = abs(goal_block - cpa->pa_pstart); | 3213 | cur_distance = abs(goal_block - cpa->pa_pstart); |
3209 | new_distance = abs(goal_block - pa->pa_pstart); | 3214 | new_distance = abs(goal_block - pa->pa_pstart); |
3210 | 3215 | ||
3211 | if (cur_distance < new_distance) | 3216 | if (cur_distance <= new_distance) |
3212 | return cpa; | 3217 | return cpa; |
3213 | 3218 | ||
3214 | /* drop the previous reference */ | 3219 | /* drop the previous reference */ |
@@ -3907,7 +3912,8 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac) | |||
3907 | struct super_block *sb = ac->ac_sb; | 3912 | struct super_block *sb = ac->ac_sb; |
3908 | ext4_group_t ngroups, i; | 3913 | ext4_group_t ngroups, i; |
3909 | 3914 | ||
3910 | if (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED) | 3915 | if (!mb_enable_debug || |
3916 | (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)) | ||
3911 | return; | 3917 | return; |
3912 | 3918 | ||
3913 | printk(KERN_ERR "EXT4-fs: Can't allocate:" | 3919 | printk(KERN_ERR "EXT4-fs: Can't allocate:" |
@@ -4753,7 +4759,8 @@ static int ext4_trim_extent(struct super_block *sb, int start, int count, | |||
4753 | * bitmap. Then issue a TRIM command on this extent and free the extent in | 4759 | * bitmap. Then issue a TRIM command on this extent and free the extent in |
4754 | * the group buddy bitmap. This is done until whole group is scanned. | 4760 | * the group buddy bitmap. This is done until whole group is scanned. |
4755 | */ | 4761 | */ |
4756 | ext4_grpblk_t ext4_trim_all_free(struct super_block *sb, struct ext4_buddy *e4b, | 4762 | static ext4_grpblk_t |
4763 | ext4_trim_all_free(struct super_block *sb, struct ext4_buddy *e4b, | ||
4757 | ext4_grpblk_t start, ext4_grpblk_t max, ext4_grpblk_t minblocks) | 4764 | ext4_grpblk_t start, ext4_grpblk_t max, ext4_grpblk_t minblocks) |
4758 | { | 4765 | { |
4759 | void *bitmap; | 4766 | void *bitmap; |
@@ -4863,10 +4870,15 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) | |||
4863 | break; | 4870 | break; |
4864 | } | 4871 | } |
4865 | 4872 | ||
4866 | if (len >= EXT4_BLOCKS_PER_GROUP(sb)) | 4873 | /* |
4867 | len -= (EXT4_BLOCKS_PER_GROUP(sb) - first_block); | 4874 | * For all the groups except the last one, last block will |
4868 | else | 4875 | * always be EXT4_BLOCKS_PER_GROUP(sb), so we only need to |
4876 | * change it for the last group in which case start + | ||
4877 | * len < EXT4_BLOCKS_PER_GROUP(sb). | ||
4878 | */ | ||
4879 | if (first_block + len < EXT4_BLOCKS_PER_GROUP(sb)) | ||
4869 | last_block = first_block + len; | 4880 | last_block = first_block + len; |
4881 | len -= last_block - first_block; | ||
4870 | 4882 | ||
4871 | if (e4b.bd_info->bb_free >= minlen) { | 4883 | if (e4b.bd_info->bb_free >= minlen) { |
4872 | cnt = ext4_trim_all_free(sb, &e4b, first_block, | 4884 | cnt = ext4_trim_all_free(sb, &e4b, first_block, |
diff --git a/fs/ext4/mballoc.h b/fs/ext4/mballoc.h index b619322c76f0..22bd4d7f289b 100644 --- a/fs/ext4/mballoc.h +++ b/fs/ext4/mballoc.h | |||
@@ -169,7 +169,7 @@ struct ext4_allocation_context { | |||
169 | /* original request */ | 169 | /* original request */ |
170 | struct ext4_free_extent ac_o_ex; | 170 | struct ext4_free_extent ac_o_ex; |
171 | 171 | ||
172 | /* goal request (after normalization) */ | 172 | /* goal request (normalized ac_o_ex) */ |
173 | struct ext4_free_extent ac_g_ex; | 173 | struct ext4_free_extent ac_g_ex; |
174 | 174 | ||
175 | /* the best found extent */ | 175 | /* the best found extent */ |
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c index b0a126f23c20..d1bafa57f483 100644 --- a/fs/ext4/migrate.c +++ b/fs/ext4/migrate.c | |||
@@ -263,7 +263,7 @@ static int free_dind_blocks(handle_t *handle, | |||
263 | for (i = 0; i < max_entries; i++) { | 263 | for (i = 0; i < max_entries; i++) { |
264 | if (tmp_idata[i]) { | 264 | if (tmp_idata[i]) { |
265 | extend_credit_for_blkdel(handle, inode); | 265 | extend_credit_for_blkdel(handle, inode); |
266 | ext4_free_blocks(handle, inode, 0, | 266 | ext4_free_blocks(handle, inode, NULL, |
267 | le32_to_cpu(tmp_idata[i]), 1, | 267 | le32_to_cpu(tmp_idata[i]), 1, |
268 | EXT4_FREE_BLOCKS_METADATA | | 268 | EXT4_FREE_BLOCKS_METADATA | |
269 | EXT4_FREE_BLOCKS_FORGET); | 269 | EXT4_FREE_BLOCKS_FORGET); |
@@ -271,7 +271,7 @@ static int free_dind_blocks(handle_t *handle, | |||
271 | } | 271 | } |
272 | put_bh(bh); | 272 | put_bh(bh); |
273 | extend_credit_for_blkdel(handle, inode); | 273 | extend_credit_for_blkdel(handle, inode); |
274 | ext4_free_blocks(handle, inode, 0, le32_to_cpu(i_data), 1, | 274 | ext4_free_blocks(handle, inode, NULL, le32_to_cpu(i_data), 1, |
275 | EXT4_FREE_BLOCKS_METADATA | | 275 | EXT4_FREE_BLOCKS_METADATA | |
276 | EXT4_FREE_BLOCKS_FORGET); | 276 | EXT4_FREE_BLOCKS_FORGET); |
277 | return 0; | 277 | return 0; |
@@ -302,7 +302,7 @@ static int free_tind_blocks(handle_t *handle, | |||
302 | } | 302 | } |
303 | put_bh(bh); | 303 | put_bh(bh); |
304 | extend_credit_for_blkdel(handle, inode); | 304 | extend_credit_for_blkdel(handle, inode); |
305 | ext4_free_blocks(handle, inode, 0, le32_to_cpu(i_data), 1, | 305 | ext4_free_blocks(handle, inode, NULL, le32_to_cpu(i_data), 1, |
306 | EXT4_FREE_BLOCKS_METADATA | | 306 | EXT4_FREE_BLOCKS_METADATA | |
307 | EXT4_FREE_BLOCKS_FORGET); | 307 | EXT4_FREE_BLOCKS_FORGET); |
308 | return 0; | 308 | return 0; |
@@ -315,7 +315,7 @@ static int free_ind_block(handle_t *handle, struct inode *inode, __le32 *i_data) | |||
315 | /* ei->i_data[EXT4_IND_BLOCK] */ | 315 | /* ei->i_data[EXT4_IND_BLOCK] */ |
316 | if (i_data[0]) { | 316 | if (i_data[0]) { |
317 | extend_credit_for_blkdel(handle, inode); | 317 | extend_credit_for_blkdel(handle, inode); |
318 | ext4_free_blocks(handle, inode, 0, | 318 | ext4_free_blocks(handle, inode, NULL, |
319 | le32_to_cpu(i_data[0]), 1, | 319 | le32_to_cpu(i_data[0]), 1, |
320 | EXT4_FREE_BLOCKS_METADATA | | 320 | EXT4_FREE_BLOCKS_METADATA | |
321 | EXT4_FREE_BLOCKS_FORGET); | 321 | EXT4_FREE_BLOCKS_FORGET); |
@@ -428,7 +428,7 @@ static int free_ext_idx(handle_t *handle, struct inode *inode, | |||
428 | } | 428 | } |
429 | put_bh(bh); | 429 | put_bh(bh); |
430 | extend_credit_for_blkdel(handle, inode); | 430 | extend_credit_for_blkdel(handle, inode); |
431 | ext4_free_blocks(handle, inode, 0, block, 1, | 431 | ext4_free_blocks(handle, inode, NULL, block, 1, |
432 | EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET); | 432 | EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET); |
433 | return retval; | 433 | return retval; |
434 | } | 434 | } |
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index e781b7ea5630..67fd0b025858 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include "xattr.h" | 40 | #include "xattr.h" |
41 | #include "acl.h" | 41 | #include "acl.h" |
42 | 42 | ||
43 | #include <trace/events/ext4.h> | ||
43 | /* | 44 | /* |
44 | * define how far ahead to read directories while searching them. | 45 | * define how far ahead to read directories while searching them. |
45 | */ | 46 | */ |
@@ -2183,6 +2184,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry) | |||
2183 | struct ext4_dir_entry_2 *de; | 2184 | struct ext4_dir_entry_2 *de; |
2184 | handle_t *handle; | 2185 | handle_t *handle; |
2185 | 2186 | ||
2187 | trace_ext4_unlink_enter(dir, dentry); | ||
2186 | /* Initialize quotas before so that eventual writes go | 2188 | /* Initialize quotas before so that eventual writes go |
2187 | * in separate transaction */ | 2189 | * in separate transaction */ |
2188 | dquot_initialize(dir); | 2190 | dquot_initialize(dir); |
@@ -2228,6 +2230,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry) | |||
2228 | end_unlink: | 2230 | end_unlink: |
2229 | ext4_journal_stop(handle); | 2231 | ext4_journal_stop(handle); |
2230 | brelse(bh); | 2232 | brelse(bh); |
2233 | trace_ext4_unlink_exit(dentry, retval); | ||
2231 | return retval; | 2234 | return retval; |
2232 | } | 2235 | } |
2233 | 2236 | ||
@@ -2402,6 +2405,10 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2402 | if (!new_inode && new_dir != old_dir && | 2405 | if (!new_inode && new_dir != old_dir && |
2403 | EXT4_DIR_LINK_MAX(new_dir)) | 2406 | EXT4_DIR_LINK_MAX(new_dir)) |
2404 | goto end_rename; | 2407 | goto end_rename; |
2408 | BUFFER_TRACE(dir_bh, "get_write_access"); | ||
2409 | retval = ext4_journal_get_write_access(handle, dir_bh); | ||
2410 | if (retval) | ||
2411 | goto end_rename; | ||
2405 | } | 2412 | } |
2406 | if (!new_bh) { | 2413 | if (!new_bh) { |
2407 | retval = ext4_add_entry(handle, new_dentry, old_inode); | 2414 | retval = ext4_add_entry(handle, new_dentry, old_inode); |
@@ -2409,7 +2416,9 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2409 | goto end_rename; | 2416 | goto end_rename; |
2410 | } else { | 2417 | } else { |
2411 | BUFFER_TRACE(new_bh, "get write access"); | 2418 | BUFFER_TRACE(new_bh, "get write access"); |
2412 | ext4_journal_get_write_access(handle, new_bh); | 2419 | retval = ext4_journal_get_write_access(handle, new_bh); |
2420 | if (retval) | ||
2421 | goto end_rename; | ||
2413 | new_de->inode = cpu_to_le32(old_inode->i_ino); | 2422 | new_de->inode = cpu_to_le32(old_inode->i_ino); |
2414 | if (EXT4_HAS_INCOMPAT_FEATURE(new_dir->i_sb, | 2423 | if (EXT4_HAS_INCOMPAT_FEATURE(new_dir->i_sb, |
2415 | EXT4_FEATURE_INCOMPAT_FILETYPE)) | 2424 | EXT4_FEATURE_INCOMPAT_FILETYPE)) |
@@ -2470,8 +2479,6 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2470 | old_dir->i_ctime = old_dir->i_mtime = ext4_current_time(old_dir); | 2479 | old_dir->i_ctime = old_dir->i_mtime = ext4_current_time(old_dir); |
2471 | ext4_update_dx_flag(old_dir); | 2480 | ext4_update_dx_flag(old_dir); |
2472 | if (dir_bh) { | 2481 | if (dir_bh) { |
2473 | BUFFER_TRACE(dir_bh, "get_write_access"); | ||
2474 | ext4_journal_get_write_access(handle, dir_bh); | ||
2475 | PARENT_INO(dir_bh->b_data, new_dir->i_sb->s_blocksize) = | 2482 | PARENT_INO(dir_bh->b_data, new_dir->i_sb->s_blocksize) = |
2476 | cpu_to_le32(new_dir->i_ino); | 2483 | cpu_to_le32(new_dir->i_ino); |
2477 | BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata"); | 2484 | BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata"); |
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index e2cd90e4bb7c..b6dbd056fcb1 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c | |||
@@ -259,6 +259,11 @@ static void ext4_end_bio(struct bio *bio, int error) | |||
259 | bi_sector >> (inode->i_blkbits - 9)); | 259 | bi_sector >> (inode->i_blkbits - 9)); |
260 | } | 260 | } |
261 | 261 | ||
262 | if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) { | ||
263 | ext4_free_io_end(io_end); | ||
264 | return; | ||
265 | } | ||
266 | |||
262 | /* Add the io_end to per-inode completed io list*/ | 267 | /* Add the io_end to per-inode completed io list*/ |
263 | spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags); | 268 | spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags); |
264 | list_add_tail(&io_end->list, &EXT4_I(inode)->i_completed_io_list); | 269 | list_add_tail(&io_end->list, &EXT4_I(inode)->i_completed_io_list); |
@@ -279,9 +284,9 @@ void ext4_io_submit(struct ext4_io_submit *io) | |||
279 | BUG_ON(bio_flagged(io->io_bio, BIO_EOPNOTSUPP)); | 284 | BUG_ON(bio_flagged(io->io_bio, BIO_EOPNOTSUPP)); |
280 | bio_put(io->io_bio); | 285 | bio_put(io->io_bio); |
281 | } | 286 | } |
282 | io->io_bio = 0; | 287 | io->io_bio = NULL; |
283 | io->io_op = 0; | 288 | io->io_op = 0; |
284 | io->io_end = 0; | 289 | io->io_end = NULL; |
285 | } | 290 | } |
286 | 291 | ||
287 | static int io_submit_init(struct ext4_io_submit *io, | 292 | static int io_submit_init(struct ext4_io_submit *io, |
@@ -380,8 +385,6 @@ int ext4_bio_write_page(struct ext4_io_submit *io, | |||
380 | 385 | ||
381 | BUG_ON(!PageLocked(page)); | 386 | BUG_ON(!PageLocked(page)); |
382 | BUG_ON(PageWriteback(page)); | 387 | BUG_ON(PageWriteback(page)); |
383 | set_page_writeback(page); | ||
384 | ClearPageError(page); | ||
385 | 388 | ||
386 | io_page = kmem_cache_alloc(io_page_cachep, GFP_NOFS); | 389 | io_page = kmem_cache_alloc(io_page_cachep, GFP_NOFS); |
387 | if (!io_page) { | 390 | if (!io_page) { |
@@ -392,6 +395,8 @@ int ext4_bio_write_page(struct ext4_io_submit *io, | |||
392 | io_page->p_page = page; | 395 | io_page->p_page = page; |
393 | atomic_set(&io_page->p_count, 1); | 396 | atomic_set(&io_page->p_count, 1); |
394 | get_page(page); | 397 | get_page(page); |
398 | set_page_writeback(page); | ||
399 | ClearPageError(page); | ||
395 | 400 | ||
396 | for (bh = head = page_buffers(page), block_start = 0; | 401 | for (bh = head = page_buffers(page), block_start = 0; |
397 | bh != head || !block_start; | 402 | bh != head || !block_start; |
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 3ecc6e45d2f9..80bbc9c60c24 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c | |||
@@ -230,7 +230,7 @@ static int setup_new_group_blocks(struct super_block *sb, | |||
230 | } | 230 | } |
231 | 231 | ||
232 | /* Zero out all of the reserved backup group descriptor table blocks */ | 232 | /* Zero out all of the reserved backup group descriptor table blocks */ |
233 | ext4_debug("clear inode table blocks %#04llx -> %#04llx\n", | 233 | ext4_debug("clear inode table blocks %#04llx -> %#04lx\n", |
234 | block, sbi->s_itb_per_group); | 234 | block, sbi->s_itb_per_group); |
235 | err = sb_issue_zeroout(sb, gdblocks + start + 1, reserved_gdb, | 235 | err = sb_issue_zeroout(sb, gdblocks + start + 1, reserved_gdb, |
236 | GFP_NOFS); | 236 | GFP_NOFS); |
@@ -248,7 +248,7 @@ static int setup_new_group_blocks(struct super_block *sb, | |||
248 | 248 | ||
249 | /* Zero out all of the inode table blocks */ | 249 | /* Zero out all of the inode table blocks */ |
250 | block = input->inode_table; | 250 | block = input->inode_table; |
251 | ext4_debug("clear inode table blocks %#04llx -> %#04llx\n", | 251 | ext4_debug("clear inode table blocks %#04llx -> %#04lx\n", |
252 | block, sbi->s_itb_per_group); | 252 | block, sbi->s_itb_per_group); |
253 | err = sb_issue_zeroout(sb, block, sbi->s_itb_per_group, GFP_NOFS); | 253 | err = sb_issue_zeroout(sb, block, sbi->s_itb_per_group, GFP_NOFS); |
254 | if (err) | 254 | if (err) |
@@ -499,12 +499,12 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, | |||
499 | return err; | 499 | return err; |
500 | 500 | ||
501 | exit_inode: | 501 | exit_inode: |
502 | /* ext4_journal_release_buffer(handle, iloc.bh); */ | 502 | /* ext4_handle_release_buffer(handle, iloc.bh); */ |
503 | brelse(iloc.bh); | 503 | brelse(iloc.bh); |
504 | exit_dindj: | 504 | exit_dindj: |
505 | /* ext4_journal_release_buffer(handle, dind); */ | 505 | /* ext4_handle_release_buffer(handle, dind); */ |
506 | exit_sbh: | 506 | exit_sbh: |
507 | /* ext4_journal_release_buffer(handle, EXT4_SB(sb)->s_sbh); */ | 507 | /* ext4_handle_release_buffer(handle, EXT4_SB(sb)->s_sbh); */ |
508 | exit_dind: | 508 | exit_dind: |
509 | brelse(dind); | 509 | brelse(dind); |
510 | exit_bh: | 510 | exit_bh: |
@@ -586,7 +586,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, | |||
586 | /* | 586 | /* |
587 | int j; | 587 | int j; |
588 | for (j = 0; j < i; j++) | 588 | for (j = 0; j < i; j++) |
589 | ext4_journal_release_buffer(handle, primary[j]); | 589 | ext4_handle_release_buffer(handle, primary[j]); |
590 | */ | 590 | */ |
591 | goto exit_bh; | 591 | goto exit_bh; |
592 | } | 592 | } |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 203f9e4a70be..22546ad7f0ae 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -54,9 +54,9 @@ | |||
54 | 54 | ||
55 | static struct proc_dir_entry *ext4_proc_root; | 55 | static struct proc_dir_entry *ext4_proc_root; |
56 | static struct kset *ext4_kset; | 56 | static struct kset *ext4_kset; |
57 | struct ext4_lazy_init *ext4_li_info; | 57 | static struct ext4_lazy_init *ext4_li_info; |
58 | struct mutex ext4_li_mtx; | 58 | static struct mutex ext4_li_mtx; |
59 | struct ext4_features *ext4_feat; | 59 | static struct ext4_features *ext4_feat; |
60 | 60 | ||
61 | static int ext4_load_journal(struct super_block *, struct ext4_super_block *, | 61 | static int ext4_load_journal(struct super_block *, struct ext4_super_block *, |
62 | unsigned long journal_devnum); | 62 | unsigned long journal_devnum); |
@@ -75,6 +75,7 @@ static void ext4_write_super(struct super_block *sb); | |||
75 | static int ext4_freeze(struct super_block *sb); | 75 | static int ext4_freeze(struct super_block *sb); |
76 | static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags, | 76 | static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags, |
77 | const char *dev_name, void *data); | 77 | const char *dev_name, void *data); |
78 | static int ext4_feature_set_ok(struct super_block *sb, int readonly); | ||
78 | static void ext4_destroy_lazyinit_thread(void); | 79 | static void ext4_destroy_lazyinit_thread(void); |
79 | static void ext4_unregister_li_request(struct super_block *sb); | 80 | static void ext4_unregister_li_request(struct super_block *sb); |
80 | static void ext4_clear_request_list(void); | 81 | static void ext4_clear_request_list(void); |
@@ -594,7 +595,7 @@ __acquires(bitlock) | |||
594 | 595 | ||
595 | vaf.fmt = fmt; | 596 | vaf.fmt = fmt; |
596 | vaf.va = &args; | 597 | vaf.va = &args; |
597 | printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: group %u", | 598 | printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: group %u, ", |
598 | sb->s_id, function, line, grp); | 599 | sb->s_id, function, line, grp); |
599 | if (ino) | 600 | if (ino) |
600 | printk(KERN_CONT "inode %lu: ", ino); | 601 | printk(KERN_CONT "inode %lu: ", ino); |
@@ -997,13 +998,10 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
997 | if (test_opt(sb, OLDALLOC)) | 998 | if (test_opt(sb, OLDALLOC)) |
998 | seq_puts(seq, ",oldalloc"); | 999 | seq_puts(seq, ",oldalloc"); |
999 | #ifdef CONFIG_EXT4_FS_XATTR | 1000 | #ifdef CONFIG_EXT4_FS_XATTR |
1000 | if (test_opt(sb, XATTR_USER) && | 1001 | if (test_opt(sb, XATTR_USER)) |
1001 | !(def_mount_opts & EXT4_DEFM_XATTR_USER)) | ||
1002 | seq_puts(seq, ",user_xattr"); | 1002 | seq_puts(seq, ",user_xattr"); |
1003 | if (!test_opt(sb, XATTR_USER) && | 1003 | if (!test_opt(sb, XATTR_USER)) |
1004 | (def_mount_opts & EXT4_DEFM_XATTR_USER)) { | ||
1005 | seq_puts(seq, ",nouser_xattr"); | 1004 | seq_puts(seq, ",nouser_xattr"); |
1006 | } | ||
1007 | #endif | 1005 | #endif |
1008 | #ifdef CONFIG_EXT4_FS_POSIX_ACL | 1006 | #ifdef CONFIG_EXT4_FS_POSIX_ACL |
1009 | if (test_opt(sb, POSIX_ACL) && !(def_mount_opts & EXT4_DEFM_ACL)) | 1007 | if (test_opt(sb, POSIX_ACL) && !(def_mount_opts & EXT4_DEFM_ACL)) |
@@ -1041,8 +1039,8 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
1041 | !(def_mount_opts & EXT4_DEFM_NODELALLOC)) | 1039 | !(def_mount_opts & EXT4_DEFM_NODELALLOC)) |
1042 | seq_puts(seq, ",nodelalloc"); | 1040 | seq_puts(seq, ",nodelalloc"); |
1043 | 1041 | ||
1044 | if (test_opt(sb, MBLK_IO_SUBMIT)) | 1042 | if (!test_opt(sb, MBLK_IO_SUBMIT)) |
1045 | seq_puts(seq, ",mblk_io_submit"); | 1043 | seq_puts(seq, ",nomblk_io_submit"); |
1046 | if (sbi->s_stripe) | 1044 | if (sbi->s_stripe) |
1047 | seq_printf(seq, ",stripe=%lu", sbi->s_stripe); | 1045 | seq_printf(seq, ",stripe=%lu", sbi->s_stripe); |
1048 | /* | 1046 | /* |
@@ -1451,7 +1449,7 @@ static int parse_options(char *options, struct super_block *sb, | |||
1451 | * Initialize args struct so we know whether arg was | 1449 | * Initialize args struct so we know whether arg was |
1452 | * found; some options take optional arguments. | 1450 | * found; some options take optional arguments. |
1453 | */ | 1451 | */ |
1454 | args[0].to = args[0].from = 0; | 1452 | args[0].to = args[0].from = NULL; |
1455 | token = match_token(p, tokens, args); | 1453 | token = match_token(p, tokens, args); |
1456 | switch (token) { | 1454 | switch (token) { |
1457 | case Opt_bsd_df: | 1455 | case Opt_bsd_df: |
@@ -1771,7 +1769,7 @@ set_qf_format: | |||
1771 | return 0; | 1769 | return 0; |
1772 | if (option < 0 || option > (1 << 30)) | 1770 | if (option < 0 || option > (1 << 30)) |
1773 | return 0; | 1771 | return 0; |
1774 | if (!is_power_of_2(option)) { | 1772 | if (option && !is_power_of_2(option)) { |
1775 | ext4_msg(sb, KERN_ERR, | 1773 | ext4_msg(sb, KERN_ERR, |
1776 | "EXT4-fs: inode_readahead_blks" | 1774 | "EXT4-fs: inode_readahead_blks" |
1777 | " must be a power of 2"); | 1775 | " must be a power of 2"); |
@@ -2120,6 +2118,13 @@ static void ext4_orphan_cleanup(struct super_block *sb, | |||
2120 | return; | 2118 | return; |
2121 | } | 2119 | } |
2122 | 2120 | ||
2121 | /* Check if feature set would not allow a r/w mount */ | ||
2122 | if (!ext4_feature_set_ok(sb, 0)) { | ||
2123 | ext4_msg(sb, KERN_INFO, "Skipping orphan cleanup due to " | ||
2124 | "unknown ROCOMPAT features"); | ||
2125 | return; | ||
2126 | } | ||
2127 | |||
2123 | if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) { | 2128 | if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) { |
2124 | if (es->s_last_orphan) | 2129 | if (es->s_last_orphan) |
2125 | jbd_debug(1, "Errors on filesystem, " | 2130 | jbd_debug(1, "Errors on filesystem, " |
@@ -2412,7 +2417,7 @@ static ssize_t inode_readahead_blks_store(struct ext4_attr *a, | |||
2412 | if (parse_strtoul(buf, 0x40000000, &t)) | 2417 | if (parse_strtoul(buf, 0x40000000, &t)) |
2413 | return -EINVAL; | 2418 | return -EINVAL; |
2414 | 2419 | ||
2415 | if (!is_power_of_2(t)) | 2420 | if (t && !is_power_of_2(t)) |
2416 | return -EINVAL; | 2421 | return -EINVAL; |
2417 | 2422 | ||
2418 | sbi->s_inode_readahead_blks = t; | 2423 | sbi->s_inode_readahead_blks = t; |
@@ -3095,14 +3100,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
3095 | } | 3100 | } |
3096 | if (def_mount_opts & EXT4_DEFM_UID16) | 3101 | if (def_mount_opts & EXT4_DEFM_UID16) |
3097 | set_opt(sb, NO_UID32); | 3102 | set_opt(sb, NO_UID32); |
3103 | /* xattr user namespace & acls are now defaulted on */ | ||
3098 | #ifdef CONFIG_EXT4_FS_XATTR | 3104 | #ifdef CONFIG_EXT4_FS_XATTR |
3099 | if (def_mount_opts & EXT4_DEFM_XATTR_USER) | 3105 | set_opt(sb, XATTR_USER); |
3100 | set_opt(sb, XATTR_USER); | ||
3101 | #endif | 3106 | #endif |
3102 | #ifdef CONFIG_EXT4_FS_POSIX_ACL | 3107 | #ifdef CONFIG_EXT4_FS_POSIX_ACL |
3103 | if (def_mount_opts & EXT4_DEFM_ACL) | 3108 | set_opt(sb, POSIX_ACL); |
3104 | set_opt(sb, POSIX_ACL); | ||
3105 | #endif | 3109 | #endif |
3110 | set_opt(sb, MBLK_IO_SUBMIT); | ||
3106 | if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_DATA) | 3111 | if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_DATA) |
3107 | set_opt(sb, JOURNAL_DATA); | 3112 | set_opt(sb, JOURNAL_DATA); |
3108 | else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_ORDERED) | 3113 | else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_ORDERED) |
@@ -3516,7 +3521,7 @@ no_journal: | |||
3516 | * concurrency isn't really necessary. Limit it to 1. | 3521 | * concurrency isn't really necessary. Limit it to 1. |
3517 | */ | 3522 | */ |
3518 | EXT4_SB(sb)->dio_unwritten_wq = | 3523 | EXT4_SB(sb)->dio_unwritten_wq = |
3519 | alloc_workqueue("ext4-dio-unwritten", WQ_MEM_RECLAIM, 1); | 3524 | alloc_workqueue("ext4-dio-unwritten", WQ_MEM_RECLAIM | WQ_UNBOUND, 1); |
3520 | if (!EXT4_SB(sb)->dio_unwritten_wq) { | 3525 | if (!EXT4_SB(sb)->dio_unwritten_wq) { |
3521 | printk(KERN_ERR "EXT4-fs: failed to create DIO workqueue\n"); | 3526 | printk(KERN_ERR "EXT4-fs: failed to create DIO workqueue\n"); |
3522 | goto failed_mount_wq; | 3527 | goto failed_mount_wq; |
@@ -3531,17 +3536,16 @@ no_journal: | |||
3531 | if (IS_ERR(root)) { | 3536 | if (IS_ERR(root)) { |
3532 | ext4_msg(sb, KERN_ERR, "get root inode failed"); | 3537 | ext4_msg(sb, KERN_ERR, "get root inode failed"); |
3533 | ret = PTR_ERR(root); | 3538 | ret = PTR_ERR(root); |
3539 | root = NULL; | ||
3534 | goto failed_mount4; | 3540 | goto failed_mount4; |
3535 | } | 3541 | } |
3536 | if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { | 3542 | if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { |
3537 | iput(root); | ||
3538 | ext4_msg(sb, KERN_ERR, "corrupt root inode, run e2fsck"); | 3543 | ext4_msg(sb, KERN_ERR, "corrupt root inode, run e2fsck"); |
3539 | goto failed_mount4; | 3544 | goto failed_mount4; |
3540 | } | 3545 | } |
3541 | sb->s_root = d_alloc_root(root); | 3546 | sb->s_root = d_alloc_root(root); |
3542 | if (!sb->s_root) { | 3547 | if (!sb->s_root) { |
3543 | ext4_msg(sb, KERN_ERR, "get root dentry failed"); | 3548 | ext4_msg(sb, KERN_ERR, "get root dentry failed"); |
3544 | iput(root); | ||
3545 | ret = -ENOMEM; | 3549 | ret = -ENOMEM; |
3546 | goto failed_mount4; | 3550 | goto failed_mount4; |
3547 | } | 3551 | } |
@@ -3657,6 +3661,8 @@ cantfind_ext4: | |||
3657 | goto failed_mount; | 3661 | goto failed_mount; |
3658 | 3662 | ||
3659 | failed_mount4: | 3663 | failed_mount4: |
3664 | iput(root); | ||
3665 | sb->s_root = NULL; | ||
3660 | ext4_msg(sb, KERN_ERR, "mount failed"); | 3666 | ext4_msg(sb, KERN_ERR, "mount failed"); |
3661 | destroy_workqueue(EXT4_SB(sb)->dio_unwritten_wq); | 3667 | destroy_workqueue(EXT4_SB(sb)->dio_unwritten_wq); |
3662 | failed_mount_wq: | 3668 | failed_mount_wq: |
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index fc32176eee39..b545ca1c459c 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c | |||
@@ -735,7 +735,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, | |||
735 | int offset = (char *)s->here - bs->bh->b_data; | 735 | int offset = (char *)s->here - bs->bh->b_data; |
736 | 736 | ||
737 | unlock_buffer(bs->bh); | 737 | unlock_buffer(bs->bh); |
738 | jbd2_journal_release_buffer(handle, bs->bh); | 738 | ext4_handle_release_buffer(handle, bs->bh); |
739 | if (ce) { | 739 | if (ce) { |
740 | mb_cache_entry_release(ce); | 740 | mb_cache_entry_release(ce); |
741 | ce = NULL; | 741 | ce = NULL; |
@@ -833,7 +833,7 @@ inserted: | |||
833 | new_bh = sb_getblk(sb, block); | 833 | new_bh = sb_getblk(sb, block); |
834 | if (!new_bh) { | 834 | if (!new_bh) { |
835 | getblk_failed: | 835 | getblk_failed: |
836 | ext4_free_blocks(handle, inode, 0, block, 1, | 836 | ext4_free_blocks(handle, inode, NULL, block, 1, |
837 | EXT4_FREE_BLOCKS_METADATA); | 837 | EXT4_FREE_BLOCKS_METADATA); |
838 | error = -EIO; | 838 | error = -EIO; |
839 | goto cleanup; | 839 | goto cleanup; |
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 59c6e4956786..b5ed541fb137 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -176,6 +176,17 @@ void bdi_start_background_writeback(struct backing_dev_info *bdi) | |||
176 | } | 176 | } |
177 | 177 | ||
178 | /* | 178 | /* |
179 | * Remove the inode from the writeback list it is on. | ||
180 | */ | ||
181 | void inode_wb_list_del(struct inode *inode) | ||
182 | { | ||
183 | spin_lock(&inode_wb_list_lock); | ||
184 | list_del_init(&inode->i_wb_list); | ||
185 | spin_unlock(&inode_wb_list_lock); | ||
186 | } | ||
187 | |||
188 | |||
189 | /* | ||
179 | * Redirty an inode: set its when-it-was dirtied timestamp and move it to the | 190 | * Redirty an inode: set its when-it-was dirtied timestamp and move it to the |
180 | * furthest end of its superblock's dirty-inode list. | 191 | * furthest end of its superblock's dirty-inode list. |
181 | * | 192 | * |
@@ -188,6 +199,7 @@ static void redirty_tail(struct inode *inode) | |||
188 | { | 199 | { |
189 | struct bdi_writeback *wb = &inode_to_bdi(inode)->wb; | 200 | struct bdi_writeback *wb = &inode_to_bdi(inode)->wb; |
190 | 201 | ||
202 | assert_spin_locked(&inode_wb_list_lock); | ||
191 | if (!list_empty(&wb->b_dirty)) { | 203 | if (!list_empty(&wb->b_dirty)) { |
192 | struct inode *tail; | 204 | struct inode *tail; |
193 | 205 | ||
@@ -205,14 +217,17 @@ static void requeue_io(struct inode *inode) | |||
205 | { | 217 | { |
206 | struct bdi_writeback *wb = &inode_to_bdi(inode)->wb; | 218 | struct bdi_writeback *wb = &inode_to_bdi(inode)->wb; |
207 | 219 | ||
220 | assert_spin_locked(&inode_wb_list_lock); | ||
208 | list_move(&inode->i_wb_list, &wb->b_more_io); | 221 | list_move(&inode->i_wb_list, &wb->b_more_io); |
209 | } | 222 | } |
210 | 223 | ||
211 | static void inode_sync_complete(struct inode *inode) | 224 | static void inode_sync_complete(struct inode *inode) |
212 | { | 225 | { |
213 | /* | 226 | /* |
214 | * Prevent speculative execution through spin_unlock(&inode_lock); | 227 | * Prevent speculative execution through |
228 | * spin_unlock(&inode_wb_list_lock); | ||
215 | */ | 229 | */ |
230 | |||
216 | smp_mb(); | 231 | smp_mb(); |
217 | wake_up_bit(&inode->i_state, __I_SYNC); | 232 | wake_up_bit(&inode->i_state, __I_SYNC); |
218 | } | 233 | } |
@@ -286,6 +301,7 @@ static void move_expired_inodes(struct list_head *delaying_queue, | |||
286 | */ | 301 | */ |
287 | static void queue_io(struct bdi_writeback *wb, unsigned long *older_than_this) | 302 | static void queue_io(struct bdi_writeback *wb, unsigned long *older_than_this) |
288 | { | 303 | { |
304 | assert_spin_locked(&inode_wb_list_lock); | ||
289 | list_splice_init(&wb->b_more_io, &wb->b_io); | 305 | list_splice_init(&wb->b_more_io, &wb->b_io); |
290 | move_expired_inodes(&wb->b_dirty, &wb->b_io, older_than_this); | 306 | move_expired_inodes(&wb->b_dirty, &wb->b_io, older_than_this); |
291 | } | 307 | } |
@@ -306,25 +322,25 @@ static void inode_wait_for_writeback(struct inode *inode) | |||
306 | wait_queue_head_t *wqh; | 322 | wait_queue_head_t *wqh; |
307 | 323 | ||
308 | wqh = bit_waitqueue(&inode->i_state, __I_SYNC); | 324 | wqh = bit_waitqueue(&inode->i_state, __I_SYNC); |
309 | while (inode->i_state & I_SYNC) { | 325 | while (inode->i_state & I_SYNC) { |
310 | spin_unlock(&inode_lock); | 326 | spin_unlock(&inode->i_lock); |
327 | spin_unlock(&inode_wb_list_lock); | ||
311 | __wait_on_bit(wqh, &wq, inode_wait, TASK_UNINTERRUPTIBLE); | 328 | __wait_on_bit(wqh, &wq, inode_wait, TASK_UNINTERRUPTIBLE); |
312 | spin_lock(&inode_lock); | 329 | spin_lock(&inode_wb_list_lock); |
330 | spin_lock(&inode->i_lock); | ||
313 | } | 331 | } |
314 | } | 332 | } |
315 | 333 | ||
316 | /* | 334 | /* |
317 | * Write out an inode's dirty pages. Called under inode_lock. Either the | 335 | * Write out an inode's dirty pages. Called under inode_wb_list_lock and |
318 | * caller has ref on the inode (either via __iget or via syscall against an fd) | 336 | * inode->i_lock. Either the caller has an active reference on the inode or |
319 | * or the inode has I_WILL_FREE set (via generic_forget_inode) | 337 | * the inode has I_WILL_FREE set. |
320 | * | 338 | * |
321 | * If `wait' is set, wait on the writeout. | 339 | * If `wait' is set, wait on the writeout. |
322 | * | 340 | * |
323 | * The whole writeout design is quite complex and fragile. We want to avoid | 341 | * The whole writeout design is quite complex and fragile. We want to avoid |
324 | * starvation of particular inodes when others are being redirtied, prevent | 342 | * starvation of particular inodes when others are being redirtied, prevent |
325 | * livelocks, etc. | 343 | * livelocks, etc. |
326 | * | ||
327 | * Called under inode_lock. | ||
328 | */ | 344 | */ |
329 | static int | 345 | static int |
330 | writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | 346 | writeback_single_inode(struct inode *inode, struct writeback_control *wbc) |
@@ -333,6 +349,9 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
333 | unsigned dirty; | 349 | unsigned dirty; |
334 | int ret; | 350 | int ret; |
335 | 351 | ||
352 | assert_spin_locked(&inode_wb_list_lock); | ||
353 | assert_spin_locked(&inode->i_lock); | ||
354 | |||
336 | if (!atomic_read(&inode->i_count)) | 355 | if (!atomic_read(&inode->i_count)) |
337 | WARN_ON(!(inode->i_state & (I_WILL_FREE|I_FREEING))); | 356 | WARN_ON(!(inode->i_state & (I_WILL_FREE|I_FREEING))); |
338 | else | 357 | else |
@@ -363,7 +382,8 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
363 | /* Set I_SYNC, reset I_DIRTY_PAGES */ | 382 | /* Set I_SYNC, reset I_DIRTY_PAGES */ |
364 | inode->i_state |= I_SYNC; | 383 | inode->i_state |= I_SYNC; |
365 | inode->i_state &= ~I_DIRTY_PAGES; | 384 | inode->i_state &= ~I_DIRTY_PAGES; |
366 | spin_unlock(&inode_lock); | 385 | spin_unlock(&inode->i_lock); |
386 | spin_unlock(&inode_wb_list_lock); | ||
367 | 387 | ||
368 | ret = do_writepages(mapping, wbc); | 388 | ret = do_writepages(mapping, wbc); |
369 | 389 | ||
@@ -383,10 +403,10 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
383 | * due to delalloc, clear dirty metadata flags right before | 403 | * due to delalloc, clear dirty metadata flags right before |
384 | * write_inode() | 404 | * write_inode() |
385 | */ | 405 | */ |
386 | spin_lock(&inode_lock); | 406 | spin_lock(&inode->i_lock); |
387 | dirty = inode->i_state & I_DIRTY; | 407 | dirty = inode->i_state & I_DIRTY; |
388 | inode->i_state &= ~(I_DIRTY_SYNC | I_DIRTY_DATASYNC); | 408 | inode->i_state &= ~(I_DIRTY_SYNC | I_DIRTY_DATASYNC); |
389 | spin_unlock(&inode_lock); | 409 | spin_unlock(&inode->i_lock); |
390 | /* Don't write the inode if only I_DIRTY_PAGES was set */ | 410 | /* Don't write the inode if only I_DIRTY_PAGES was set */ |
391 | if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) { | 411 | if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) { |
392 | int err = write_inode(inode, wbc); | 412 | int err = write_inode(inode, wbc); |
@@ -394,7 +414,8 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
394 | ret = err; | 414 | ret = err; |
395 | } | 415 | } |
396 | 416 | ||
397 | spin_lock(&inode_lock); | 417 | spin_lock(&inode_wb_list_lock); |
418 | spin_lock(&inode->i_lock); | ||
398 | inode->i_state &= ~I_SYNC; | 419 | inode->i_state &= ~I_SYNC; |
399 | if (!(inode->i_state & I_FREEING)) { | 420 | if (!(inode->i_state & I_FREEING)) { |
400 | if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { | 421 | if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { |
@@ -506,7 +527,9 @@ static int writeback_sb_inodes(struct super_block *sb, struct bdi_writeback *wb, | |||
506 | * kind does not need peridic writeout yet, and for the latter | 527 | * kind does not need peridic writeout yet, and for the latter |
507 | * kind writeout is handled by the freer. | 528 | * kind writeout is handled by the freer. |
508 | */ | 529 | */ |
530 | spin_lock(&inode->i_lock); | ||
509 | if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) { | 531 | if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) { |
532 | spin_unlock(&inode->i_lock); | ||
510 | requeue_io(inode); | 533 | requeue_io(inode); |
511 | continue; | 534 | continue; |
512 | } | 535 | } |
@@ -515,10 +538,13 @@ static int writeback_sb_inodes(struct super_block *sb, struct bdi_writeback *wb, | |||
515 | * Was this inode dirtied after sync_sb_inodes was called? | 538 | * Was this inode dirtied after sync_sb_inodes was called? |
516 | * This keeps sync from extra jobs and livelock. | 539 | * This keeps sync from extra jobs and livelock. |
517 | */ | 540 | */ |
518 | if (inode_dirtied_after(inode, wbc->wb_start)) | 541 | if (inode_dirtied_after(inode, wbc->wb_start)) { |
542 | spin_unlock(&inode->i_lock); | ||
519 | return 1; | 543 | return 1; |
544 | } | ||
520 | 545 | ||
521 | __iget(inode); | 546 | __iget(inode); |
547 | |||
522 | pages_skipped = wbc->pages_skipped; | 548 | pages_skipped = wbc->pages_skipped; |
523 | writeback_single_inode(inode, wbc); | 549 | writeback_single_inode(inode, wbc); |
524 | if (wbc->pages_skipped != pages_skipped) { | 550 | if (wbc->pages_skipped != pages_skipped) { |
@@ -528,10 +554,11 @@ static int writeback_sb_inodes(struct super_block *sb, struct bdi_writeback *wb, | |||
528 | */ | 554 | */ |
529 | redirty_tail(inode); | 555 | redirty_tail(inode); |
530 | } | 556 | } |
531 | spin_unlock(&inode_lock); | 557 | spin_unlock(&inode->i_lock); |
558 | spin_unlock(&inode_wb_list_lock); | ||
532 | iput(inode); | 559 | iput(inode); |
533 | cond_resched(); | 560 | cond_resched(); |
534 | spin_lock(&inode_lock); | 561 | spin_lock(&inode_wb_list_lock); |
535 | if (wbc->nr_to_write <= 0) { | 562 | if (wbc->nr_to_write <= 0) { |
536 | wbc->more_io = 1; | 563 | wbc->more_io = 1; |
537 | return 1; | 564 | return 1; |
@@ -550,7 +577,7 @@ void writeback_inodes_wb(struct bdi_writeback *wb, | |||
550 | 577 | ||
551 | if (!wbc->wb_start) | 578 | if (!wbc->wb_start) |
552 | wbc->wb_start = jiffies; /* livelock avoidance */ | 579 | wbc->wb_start = jiffies; /* livelock avoidance */ |
553 | spin_lock(&inode_lock); | 580 | spin_lock(&inode_wb_list_lock); |
554 | if (!wbc->for_kupdate || list_empty(&wb->b_io)) | 581 | if (!wbc->for_kupdate || list_empty(&wb->b_io)) |
555 | queue_io(wb, wbc->older_than_this); | 582 | queue_io(wb, wbc->older_than_this); |
556 | 583 | ||
@@ -568,7 +595,7 @@ void writeback_inodes_wb(struct bdi_writeback *wb, | |||
568 | if (ret) | 595 | if (ret) |
569 | break; | 596 | break; |
570 | } | 597 | } |
571 | spin_unlock(&inode_lock); | 598 | spin_unlock(&inode_wb_list_lock); |
572 | /* Leave any unwritten inodes on b_io */ | 599 | /* Leave any unwritten inodes on b_io */ |
573 | } | 600 | } |
574 | 601 | ||
@@ -577,11 +604,11 @@ static void __writeback_inodes_sb(struct super_block *sb, | |||
577 | { | 604 | { |
578 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); | 605 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); |
579 | 606 | ||
580 | spin_lock(&inode_lock); | 607 | spin_lock(&inode_wb_list_lock); |
581 | if (!wbc->for_kupdate || list_empty(&wb->b_io)) | 608 | if (!wbc->for_kupdate || list_empty(&wb->b_io)) |
582 | queue_io(wb, wbc->older_than_this); | 609 | queue_io(wb, wbc->older_than_this); |
583 | writeback_sb_inodes(sb, wb, wbc, true); | 610 | writeback_sb_inodes(sb, wb, wbc, true); |
584 | spin_unlock(&inode_lock); | 611 | spin_unlock(&inode_wb_list_lock); |
585 | } | 612 | } |
586 | 613 | ||
587 | /* | 614 | /* |
@@ -720,13 +747,15 @@ static long wb_writeback(struct bdi_writeback *wb, | |||
720 | * become available for writeback. Otherwise | 747 | * become available for writeback. Otherwise |
721 | * we'll just busyloop. | 748 | * we'll just busyloop. |
722 | */ | 749 | */ |
723 | spin_lock(&inode_lock); | 750 | spin_lock(&inode_wb_list_lock); |
724 | if (!list_empty(&wb->b_more_io)) { | 751 | if (!list_empty(&wb->b_more_io)) { |
725 | inode = wb_inode(wb->b_more_io.prev); | 752 | inode = wb_inode(wb->b_more_io.prev); |
726 | trace_wbc_writeback_wait(&wbc, wb->bdi); | 753 | trace_wbc_writeback_wait(&wbc, wb->bdi); |
754 | spin_lock(&inode->i_lock); | ||
727 | inode_wait_for_writeback(inode); | 755 | inode_wait_for_writeback(inode); |
756 | spin_unlock(&inode->i_lock); | ||
728 | } | 757 | } |
729 | spin_unlock(&inode_lock); | 758 | spin_unlock(&inode_wb_list_lock); |
730 | } | 759 | } |
731 | 760 | ||
732 | return wrote; | 761 | return wrote; |
@@ -992,7 +1021,6 @@ void __mark_inode_dirty(struct inode *inode, int flags) | |||
992 | { | 1021 | { |
993 | struct super_block *sb = inode->i_sb; | 1022 | struct super_block *sb = inode->i_sb; |
994 | struct backing_dev_info *bdi = NULL; | 1023 | struct backing_dev_info *bdi = NULL; |
995 | bool wakeup_bdi = false; | ||
996 | 1024 | ||
997 | /* | 1025 | /* |
998 | * Don't do this for I_DIRTY_PAGES - that doesn't actually | 1026 | * Don't do this for I_DIRTY_PAGES - that doesn't actually |
@@ -1016,7 +1044,7 @@ void __mark_inode_dirty(struct inode *inode, int flags) | |||
1016 | if (unlikely(block_dump)) | 1044 | if (unlikely(block_dump)) |
1017 | block_dump___mark_inode_dirty(inode); | 1045 | block_dump___mark_inode_dirty(inode); |
1018 | 1046 | ||
1019 | spin_lock(&inode_lock); | 1047 | spin_lock(&inode->i_lock); |
1020 | if ((inode->i_state & flags) != flags) { | 1048 | if ((inode->i_state & flags) != flags) { |
1021 | const int was_dirty = inode->i_state & I_DIRTY; | 1049 | const int was_dirty = inode->i_state & I_DIRTY; |
1022 | 1050 | ||
@@ -1028,7 +1056,7 @@ void __mark_inode_dirty(struct inode *inode, int flags) | |||
1028 | * superblock list, based upon its state. | 1056 | * superblock list, based upon its state. |
1029 | */ | 1057 | */ |
1030 | if (inode->i_state & I_SYNC) | 1058 | if (inode->i_state & I_SYNC) |
1031 | goto out; | 1059 | goto out_unlock_inode; |
1032 | 1060 | ||
1033 | /* | 1061 | /* |
1034 | * Only add valid (hashed) inodes to the superblock's | 1062 | * Only add valid (hashed) inodes to the superblock's |
@@ -1036,16 +1064,17 @@ void __mark_inode_dirty(struct inode *inode, int flags) | |||
1036 | */ | 1064 | */ |
1037 | if (!S_ISBLK(inode->i_mode)) { | 1065 | if (!S_ISBLK(inode->i_mode)) { |
1038 | if (inode_unhashed(inode)) | 1066 | if (inode_unhashed(inode)) |
1039 | goto out; | 1067 | goto out_unlock_inode; |
1040 | } | 1068 | } |
1041 | if (inode->i_state & I_FREEING) | 1069 | if (inode->i_state & I_FREEING) |
1042 | goto out; | 1070 | goto out_unlock_inode; |
1043 | 1071 | ||
1044 | /* | 1072 | /* |
1045 | * If the inode was already on b_dirty/b_io/b_more_io, don't | 1073 | * If the inode was already on b_dirty/b_io/b_more_io, don't |
1046 | * reposition it (that would break b_dirty time-ordering). | 1074 | * reposition it (that would break b_dirty time-ordering). |
1047 | */ | 1075 | */ |
1048 | if (!was_dirty) { | 1076 | if (!was_dirty) { |
1077 | bool wakeup_bdi = false; | ||
1049 | bdi = inode_to_bdi(inode); | 1078 | bdi = inode_to_bdi(inode); |
1050 | 1079 | ||
1051 | if (bdi_cap_writeback_dirty(bdi)) { | 1080 | if (bdi_cap_writeback_dirty(bdi)) { |
@@ -1062,15 +1091,20 @@ void __mark_inode_dirty(struct inode *inode, int flags) | |||
1062 | wakeup_bdi = true; | 1091 | wakeup_bdi = true; |
1063 | } | 1092 | } |
1064 | 1093 | ||
1094 | spin_unlock(&inode->i_lock); | ||
1095 | spin_lock(&inode_wb_list_lock); | ||
1065 | inode->dirtied_when = jiffies; | 1096 | inode->dirtied_when = jiffies; |
1066 | list_move(&inode->i_wb_list, &bdi->wb.b_dirty); | 1097 | list_move(&inode->i_wb_list, &bdi->wb.b_dirty); |
1098 | spin_unlock(&inode_wb_list_lock); | ||
1099 | |||
1100 | if (wakeup_bdi) | ||
1101 | bdi_wakeup_thread_delayed(bdi); | ||
1102 | return; | ||
1067 | } | 1103 | } |
1068 | } | 1104 | } |
1069 | out: | 1105 | out_unlock_inode: |
1070 | spin_unlock(&inode_lock); | 1106 | spin_unlock(&inode->i_lock); |
1071 | 1107 | ||
1072 | if (wakeup_bdi) | ||
1073 | bdi_wakeup_thread_delayed(bdi); | ||
1074 | } | 1108 | } |
1075 | EXPORT_SYMBOL(__mark_inode_dirty); | 1109 | EXPORT_SYMBOL(__mark_inode_dirty); |
1076 | 1110 | ||
@@ -1101,7 +1135,7 @@ static void wait_sb_inodes(struct super_block *sb) | |||
1101 | */ | 1135 | */ |
1102 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); | 1136 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); |
1103 | 1137 | ||
1104 | spin_lock(&inode_lock); | 1138 | spin_lock(&inode_sb_list_lock); |
1105 | 1139 | ||
1106 | /* | 1140 | /* |
1107 | * Data integrity sync. Must wait for all pages under writeback, | 1141 | * Data integrity sync. Must wait for all pages under writeback, |
@@ -1111,22 +1145,25 @@ static void wait_sb_inodes(struct super_block *sb) | |||
1111 | * we still have to wait for that writeout. | 1145 | * we still have to wait for that writeout. |
1112 | */ | 1146 | */ |
1113 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | 1147 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { |
1114 | struct address_space *mapping; | 1148 | struct address_space *mapping = inode->i_mapping; |
1115 | 1149 | ||
1116 | if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) | 1150 | spin_lock(&inode->i_lock); |
1117 | continue; | 1151 | if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) || |
1118 | mapping = inode->i_mapping; | 1152 | (mapping->nrpages == 0)) { |
1119 | if (mapping->nrpages == 0) | 1153 | spin_unlock(&inode->i_lock); |
1120 | continue; | 1154 | continue; |
1155 | } | ||
1121 | __iget(inode); | 1156 | __iget(inode); |
1122 | spin_unlock(&inode_lock); | 1157 | spin_unlock(&inode->i_lock); |
1158 | spin_unlock(&inode_sb_list_lock); | ||
1159 | |||
1123 | /* | 1160 | /* |
1124 | * We hold a reference to 'inode' so it couldn't have | 1161 | * We hold a reference to 'inode' so it couldn't have been |
1125 | * been removed from s_inodes list while we dropped the | 1162 | * removed from s_inodes list while we dropped the |
1126 | * inode_lock. We cannot iput the inode now as we can | 1163 | * inode_sb_list_lock. We cannot iput the inode now as we can |
1127 | * be holding the last reference and we cannot iput it | 1164 | * be holding the last reference and we cannot iput it under |
1128 | * under inode_lock. So we keep the reference and iput | 1165 | * inode_sb_list_lock. So we keep the reference and iput it |
1129 | * it later. | 1166 | * later. |
1130 | */ | 1167 | */ |
1131 | iput(old_inode); | 1168 | iput(old_inode); |
1132 | old_inode = inode; | 1169 | old_inode = inode; |
@@ -1135,9 +1172,9 @@ static void wait_sb_inodes(struct super_block *sb) | |||
1135 | 1172 | ||
1136 | cond_resched(); | 1173 | cond_resched(); |
1137 | 1174 | ||
1138 | spin_lock(&inode_lock); | 1175 | spin_lock(&inode_sb_list_lock); |
1139 | } | 1176 | } |
1140 | spin_unlock(&inode_lock); | 1177 | spin_unlock(&inode_sb_list_lock); |
1141 | iput(old_inode); | 1178 | iput(old_inode); |
1142 | } | 1179 | } |
1143 | 1180 | ||
@@ -1271,9 +1308,11 @@ int write_inode_now(struct inode *inode, int sync) | |||
1271 | wbc.nr_to_write = 0; | 1308 | wbc.nr_to_write = 0; |
1272 | 1309 | ||
1273 | might_sleep(); | 1310 | might_sleep(); |
1274 | spin_lock(&inode_lock); | 1311 | spin_lock(&inode_wb_list_lock); |
1312 | spin_lock(&inode->i_lock); | ||
1275 | ret = writeback_single_inode(inode, &wbc); | 1313 | ret = writeback_single_inode(inode, &wbc); |
1276 | spin_unlock(&inode_lock); | 1314 | spin_unlock(&inode->i_lock); |
1315 | spin_unlock(&inode_wb_list_lock); | ||
1277 | if (sync) | 1316 | if (sync) |
1278 | inode_sync_wait(inode); | 1317 | inode_sync_wait(inode); |
1279 | return ret; | 1318 | return ret; |
@@ -1295,9 +1334,11 @@ int sync_inode(struct inode *inode, struct writeback_control *wbc) | |||
1295 | { | 1334 | { |
1296 | int ret; | 1335 | int ret; |
1297 | 1336 | ||
1298 | spin_lock(&inode_lock); | 1337 | spin_lock(&inode_wb_list_lock); |
1338 | spin_lock(&inode->i_lock); | ||
1299 | ret = writeback_single_inode(inode, wbc); | 1339 | ret = writeback_single_inode(inode, wbc); |
1300 | spin_unlock(&inode_lock); | 1340 | spin_unlock(&inode->i_lock); |
1341 | spin_unlock(&inode_wb_list_lock); | ||
1301 | return ret; | 1342 | return ret; |
1302 | } | 1343 | } |
1303 | EXPORT_SYMBOL(sync_inode); | 1344 | EXPORT_SYMBOL(sync_inode); |
diff --git a/fs/inode.c b/fs/inode.c index 0b3da4a77704..5f4e11aaeb5c 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -26,6 +26,38 @@ | |||
26 | #include <linux/posix_acl.h> | 26 | #include <linux/posix_acl.h> |
27 | #include <linux/ima.h> | 27 | #include <linux/ima.h> |
28 | #include <linux/cred.h> | 28 | #include <linux/cred.h> |
29 | #include "internal.h" | ||
30 | |||
31 | /* | ||
32 | * inode locking rules. | ||
33 | * | ||
34 | * inode->i_lock protects: | ||
35 | * inode->i_state, inode->i_hash, __iget() | ||
36 | * inode_lru_lock protects: | ||
37 | * inode_lru, inode->i_lru | ||
38 | * inode_sb_list_lock protects: | ||
39 | * sb->s_inodes, inode->i_sb_list | ||
40 | * inode_wb_list_lock protects: | ||
41 | * bdi->wb.b_{dirty,io,more_io}, inode->i_wb_list | ||
42 | * inode_hash_lock protects: | ||
43 | * inode_hashtable, inode->i_hash | ||
44 | * | ||
45 | * Lock ordering: | ||
46 | * | ||
47 | * inode_sb_list_lock | ||
48 | * inode->i_lock | ||
49 | * inode_lru_lock | ||
50 | * | ||
51 | * inode_wb_list_lock | ||
52 | * inode->i_lock | ||
53 | * | ||
54 | * inode_hash_lock | ||
55 | * inode_sb_list_lock | ||
56 | * inode->i_lock | ||
57 | * | ||
58 | * iunique_lock | ||
59 | * inode_hash_lock | ||
60 | */ | ||
29 | 61 | ||
30 | /* | 62 | /* |
31 | * This is needed for the following functions: | 63 | * This is needed for the following functions: |
@@ -60,6 +92,8 @@ | |||
60 | 92 | ||
61 | static unsigned int i_hash_mask __read_mostly; | 93 | static unsigned int i_hash_mask __read_mostly; |
62 | static unsigned int i_hash_shift __read_mostly; | 94 | static unsigned int i_hash_shift __read_mostly; |
95 | static struct hlist_head *inode_hashtable __read_mostly; | ||
96 | static __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_hash_lock); | ||
63 | 97 | ||
64 | /* | 98 | /* |
65 | * Each inode can be on two separate lists. One is | 99 | * Each inode can be on two separate lists. One is |
@@ -74,15 +108,10 @@ static unsigned int i_hash_shift __read_mostly; | |||
74 | */ | 108 | */ |
75 | 109 | ||
76 | static LIST_HEAD(inode_lru); | 110 | static LIST_HEAD(inode_lru); |
77 | static struct hlist_head *inode_hashtable __read_mostly; | 111 | static DEFINE_SPINLOCK(inode_lru_lock); |
78 | 112 | ||
79 | /* | 113 | __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_sb_list_lock); |
80 | * A simple spinlock to protect the list manipulations. | 114 | __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_wb_list_lock); |
81 | * | ||
82 | * NOTE! You also have to own the lock if you change | ||
83 | * the i_state of an inode while it is in use.. | ||
84 | */ | ||
85 | DEFINE_SPINLOCK(inode_lock); | ||
86 | 115 | ||
87 | /* | 116 | /* |
88 | * iprune_sem provides exclusion between the icache shrinking and the | 117 | * iprune_sem provides exclusion between the icache shrinking and the |
@@ -137,15 +166,6 @@ int proc_nr_inodes(ctl_table *table, int write, | |||
137 | } | 166 | } |
138 | #endif | 167 | #endif |
139 | 168 | ||
140 | static void wake_up_inode(struct inode *inode) | ||
141 | { | ||
142 | /* | ||
143 | * Prevent speculative execution through spin_unlock(&inode_lock); | ||
144 | */ | ||
145 | smp_mb(); | ||
146 | wake_up_bit(&inode->i_state, __I_NEW); | ||
147 | } | ||
148 | |||
149 | /** | 169 | /** |
150 | * inode_init_always - perform inode structure intialisation | 170 | * inode_init_always - perform inode structure intialisation |
151 | * @sb: superblock inode belongs to | 171 | * @sb: superblock inode belongs to |
@@ -336,7 +356,7 @@ static void init_once(void *foo) | |||
336 | } | 356 | } |
337 | 357 | ||
338 | /* | 358 | /* |
339 | * inode_lock must be held | 359 | * inode->i_lock must be held |
340 | */ | 360 | */ |
341 | void __iget(struct inode *inode) | 361 | void __iget(struct inode *inode) |
342 | { | 362 | { |
@@ -354,23 +374,22 @@ EXPORT_SYMBOL(ihold); | |||
354 | 374 | ||
355 | static void inode_lru_list_add(struct inode *inode) | 375 | static void inode_lru_list_add(struct inode *inode) |
356 | { | 376 | { |
377 | spin_lock(&inode_lru_lock); | ||
357 | if (list_empty(&inode->i_lru)) { | 378 | if (list_empty(&inode->i_lru)) { |
358 | list_add(&inode->i_lru, &inode_lru); | 379 | list_add(&inode->i_lru, &inode_lru); |
359 | inodes_stat.nr_unused++; | 380 | inodes_stat.nr_unused++; |
360 | } | 381 | } |
382 | spin_unlock(&inode_lru_lock); | ||
361 | } | 383 | } |
362 | 384 | ||
363 | static void inode_lru_list_del(struct inode *inode) | 385 | static void inode_lru_list_del(struct inode *inode) |
364 | { | 386 | { |
387 | spin_lock(&inode_lru_lock); | ||
365 | if (!list_empty(&inode->i_lru)) { | 388 | if (!list_empty(&inode->i_lru)) { |
366 | list_del_init(&inode->i_lru); | 389 | list_del_init(&inode->i_lru); |
367 | inodes_stat.nr_unused--; | 390 | inodes_stat.nr_unused--; |
368 | } | 391 | } |
369 | } | 392 | spin_unlock(&inode_lru_lock); |
370 | |||
371 | static inline void __inode_sb_list_add(struct inode *inode) | ||
372 | { | ||
373 | list_add(&inode->i_sb_list, &inode->i_sb->s_inodes); | ||
374 | } | 393 | } |
375 | 394 | ||
376 | /** | 395 | /** |
@@ -379,15 +398,17 @@ static inline void __inode_sb_list_add(struct inode *inode) | |||
379 | */ | 398 | */ |
380 | void inode_sb_list_add(struct inode *inode) | 399 | void inode_sb_list_add(struct inode *inode) |
381 | { | 400 | { |
382 | spin_lock(&inode_lock); | 401 | spin_lock(&inode_sb_list_lock); |
383 | __inode_sb_list_add(inode); | 402 | list_add(&inode->i_sb_list, &inode->i_sb->s_inodes); |
384 | spin_unlock(&inode_lock); | 403 | spin_unlock(&inode_sb_list_lock); |
385 | } | 404 | } |
386 | EXPORT_SYMBOL_GPL(inode_sb_list_add); | 405 | EXPORT_SYMBOL_GPL(inode_sb_list_add); |
387 | 406 | ||
388 | static inline void __inode_sb_list_del(struct inode *inode) | 407 | static inline void inode_sb_list_del(struct inode *inode) |
389 | { | 408 | { |
409 | spin_lock(&inode_sb_list_lock); | ||
390 | list_del_init(&inode->i_sb_list); | 410 | list_del_init(&inode->i_sb_list); |
411 | spin_unlock(&inode_sb_list_lock); | ||
391 | } | 412 | } |
392 | 413 | ||
393 | static unsigned long hash(struct super_block *sb, unsigned long hashval) | 414 | static unsigned long hash(struct super_block *sb, unsigned long hashval) |
@@ -412,24 +433,15 @@ void __insert_inode_hash(struct inode *inode, unsigned long hashval) | |||
412 | { | 433 | { |
413 | struct hlist_head *b = inode_hashtable + hash(inode->i_sb, hashval); | 434 | struct hlist_head *b = inode_hashtable + hash(inode->i_sb, hashval); |
414 | 435 | ||
415 | spin_lock(&inode_lock); | 436 | spin_lock(&inode_hash_lock); |
437 | spin_lock(&inode->i_lock); | ||
416 | hlist_add_head(&inode->i_hash, b); | 438 | hlist_add_head(&inode->i_hash, b); |
417 | spin_unlock(&inode_lock); | 439 | spin_unlock(&inode->i_lock); |
440 | spin_unlock(&inode_hash_lock); | ||
418 | } | 441 | } |
419 | EXPORT_SYMBOL(__insert_inode_hash); | 442 | EXPORT_SYMBOL(__insert_inode_hash); |
420 | 443 | ||
421 | /** | 444 | /** |
422 | * __remove_inode_hash - remove an inode from the hash | ||
423 | * @inode: inode to unhash | ||
424 | * | ||
425 | * Remove an inode from the superblock. | ||
426 | */ | ||
427 | static void __remove_inode_hash(struct inode *inode) | ||
428 | { | ||
429 | hlist_del_init(&inode->i_hash); | ||
430 | } | ||
431 | |||
432 | /** | ||
433 | * remove_inode_hash - remove an inode from the hash | 445 | * remove_inode_hash - remove an inode from the hash |
434 | * @inode: inode to unhash | 446 | * @inode: inode to unhash |
435 | * | 447 | * |
@@ -437,9 +449,11 @@ static void __remove_inode_hash(struct inode *inode) | |||
437 | */ | 449 | */ |
438 | void remove_inode_hash(struct inode *inode) | 450 | void remove_inode_hash(struct inode *inode) |
439 | { | 451 | { |
440 | spin_lock(&inode_lock); | 452 | spin_lock(&inode_hash_lock); |
453 | spin_lock(&inode->i_lock); | ||
441 | hlist_del_init(&inode->i_hash); | 454 | hlist_del_init(&inode->i_hash); |
442 | spin_unlock(&inode_lock); | 455 | spin_unlock(&inode->i_lock); |
456 | spin_unlock(&inode_hash_lock); | ||
443 | } | 457 | } |
444 | EXPORT_SYMBOL(remove_inode_hash); | 458 | EXPORT_SYMBOL(remove_inode_hash); |
445 | 459 | ||
@@ -456,10 +470,29 @@ void end_writeback(struct inode *inode) | |||
456 | } | 470 | } |
457 | EXPORT_SYMBOL(end_writeback); | 471 | EXPORT_SYMBOL(end_writeback); |
458 | 472 | ||
473 | /* | ||
474 | * Free the inode passed in, removing it from the lists it is still connected | ||
475 | * to. We remove any pages still attached to the inode and wait for any IO that | ||
476 | * is still in progress before finally destroying the inode. | ||
477 | * | ||
478 | * An inode must already be marked I_FREEING so that we avoid the inode being | ||
479 | * moved back onto lists if we race with other code that manipulates the lists | ||
480 | * (e.g. writeback_single_inode). The caller is responsible for setting this. | ||
481 | * | ||
482 | * An inode must already be removed from the LRU list before being evicted from | ||
483 | * the cache. This should occur atomically with setting the I_FREEING state | ||
484 | * flag, so no inodes here should ever be on the LRU when being evicted. | ||
485 | */ | ||
459 | static void evict(struct inode *inode) | 486 | static void evict(struct inode *inode) |
460 | { | 487 | { |
461 | const struct super_operations *op = inode->i_sb->s_op; | 488 | const struct super_operations *op = inode->i_sb->s_op; |
462 | 489 | ||
490 | BUG_ON(!(inode->i_state & I_FREEING)); | ||
491 | BUG_ON(!list_empty(&inode->i_lru)); | ||
492 | |||
493 | inode_wb_list_del(inode); | ||
494 | inode_sb_list_del(inode); | ||
495 | |||
463 | if (op->evict_inode) { | 496 | if (op->evict_inode) { |
464 | op->evict_inode(inode); | 497 | op->evict_inode(inode); |
465 | } else { | 498 | } else { |
@@ -471,6 +504,15 @@ static void evict(struct inode *inode) | |||
471 | bd_forget(inode); | 504 | bd_forget(inode); |
472 | if (S_ISCHR(inode->i_mode) && inode->i_cdev) | 505 | if (S_ISCHR(inode->i_mode) && inode->i_cdev) |
473 | cd_forget(inode); | 506 | cd_forget(inode); |
507 | |||
508 | remove_inode_hash(inode); | ||
509 | |||
510 | spin_lock(&inode->i_lock); | ||
511 | wake_up_bit(&inode->i_state, __I_NEW); | ||
512 | BUG_ON(inode->i_state != (I_FREEING | I_CLEAR)); | ||
513 | spin_unlock(&inode->i_lock); | ||
514 | |||
515 | destroy_inode(inode); | ||
474 | } | 516 | } |
475 | 517 | ||
476 | /* | 518 | /* |
@@ -489,14 +531,6 @@ static void dispose_list(struct list_head *head) | |||
489 | list_del_init(&inode->i_lru); | 531 | list_del_init(&inode->i_lru); |
490 | 532 | ||
491 | evict(inode); | 533 | evict(inode); |
492 | |||
493 | spin_lock(&inode_lock); | ||
494 | __remove_inode_hash(inode); | ||
495 | __inode_sb_list_del(inode); | ||
496 | spin_unlock(&inode_lock); | ||
497 | |||
498 | wake_up_inode(inode); | ||
499 | destroy_inode(inode); | ||
500 | } | 534 | } |
501 | } | 535 | } |
502 | 536 | ||
@@ -514,25 +548,23 @@ void evict_inodes(struct super_block *sb) | |||
514 | struct inode *inode, *next; | 548 | struct inode *inode, *next; |
515 | LIST_HEAD(dispose); | 549 | LIST_HEAD(dispose); |
516 | 550 | ||
517 | spin_lock(&inode_lock); | 551 | spin_lock(&inode_sb_list_lock); |
518 | list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { | 552 | list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { |
519 | if (atomic_read(&inode->i_count)) | 553 | if (atomic_read(&inode->i_count)) |
520 | continue; | 554 | continue; |
521 | if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) | 555 | |
556 | spin_lock(&inode->i_lock); | ||
557 | if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) { | ||
558 | spin_unlock(&inode->i_lock); | ||
522 | continue; | 559 | continue; |
560 | } | ||
523 | 561 | ||
524 | inode->i_state |= I_FREEING; | 562 | inode->i_state |= I_FREEING; |
525 | 563 | inode_lru_list_del(inode); | |
526 | /* | 564 | spin_unlock(&inode->i_lock); |
527 | * Move the inode off the IO lists and LRU once I_FREEING is | 565 | list_add(&inode->i_lru, &dispose); |
528 | * set so that it won't get moved back on there if it is dirty. | ||
529 | */ | ||
530 | list_move(&inode->i_lru, &dispose); | ||
531 | list_del_init(&inode->i_wb_list); | ||
532 | if (!(inode->i_state & (I_DIRTY | I_SYNC))) | ||
533 | inodes_stat.nr_unused--; | ||
534 | } | 566 | } |
535 | spin_unlock(&inode_lock); | 567 | spin_unlock(&inode_sb_list_lock); |
536 | 568 | ||
537 | dispose_list(&dispose); | 569 | dispose_list(&dispose); |
538 | 570 | ||
@@ -561,31 +593,30 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty) | |||
561 | struct inode *inode, *next; | 593 | struct inode *inode, *next; |
562 | LIST_HEAD(dispose); | 594 | LIST_HEAD(dispose); |
563 | 595 | ||
564 | spin_lock(&inode_lock); | 596 | spin_lock(&inode_sb_list_lock); |
565 | list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { | 597 | list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { |
566 | if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) | 598 | spin_lock(&inode->i_lock); |
599 | if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) { | ||
600 | spin_unlock(&inode->i_lock); | ||
567 | continue; | 601 | continue; |
602 | } | ||
568 | if (inode->i_state & I_DIRTY && !kill_dirty) { | 603 | if (inode->i_state & I_DIRTY && !kill_dirty) { |
604 | spin_unlock(&inode->i_lock); | ||
569 | busy = 1; | 605 | busy = 1; |
570 | continue; | 606 | continue; |
571 | } | 607 | } |
572 | if (atomic_read(&inode->i_count)) { | 608 | if (atomic_read(&inode->i_count)) { |
609 | spin_unlock(&inode->i_lock); | ||
573 | busy = 1; | 610 | busy = 1; |
574 | continue; | 611 | continue; |
575 | } | 612 | } |
576 | 613 | ||
577 | inode->i_state |= I_FREEING; | 614 | inode->i_state |= I_FREEING; |
578 | 615 | inode_lru_list_del(inode); | |
579 | /* | 616 | spin_unlock(&inode->i_lock); |
580 | * Move the inode off the IO lists and LRU once I_FREEING is | 617 | list_add(&inode->i_lru, &dispose); |
581 | * set so that it won't get moved back on there if it is dirty. | ||
582 | */ | ||
583 | list_move(&inode->i_lru, &dispose); | ||
584 | list_del_init(&inode->i_wb_list); | ||
585 | if (!(inode->i_state & (I_DIRTY | I_SYNC))) | ||
586 | inodes_stat.nr_unused--; | ||
587 | } | 618 | } |
588 | spin_unlock(&inode_lock); | 619 | spin_unlock(&inode_sb_list_lock); |
589 | 620 | ||
590 | dispose_list(&dispose); | 621 | dispose_list(&dispose); |
591 | 622 | ||
@@ -607,7 +638,7 @@ static int can_unuse(struct inode *inode) | |||
607 | 638 | ||
608 | /* | 639 | /* |
609 | * Scan `goal' inodes on the unused list for freeable ones. They are moved to a | 640 | * Scan `goal' inodes on the unused list for freeable ones. They are moved to a |
610 | * temporary list and then are freed outside inode_lock by dispose_list(). | 641 | * temporary list and then are freed outside inode_lru_lock by dispose_list(). |
611 | * | 642 | * |
612 | * Any inodes which are pinned purely because of attached pagecache have their | 643 | * Any inodes which are pinned purely because of attached pagecache have their |
613 | * pagecache removed. If the inode has metadata buffers attached to | 644 | * pagecache removed. If the inode has metadata buffers attached to |
@@ -628,7 +659,7 @@ static void prune_icache(int nr_to_scan) | |||
628 | unsigned long reap = 0; | 659 | unsigned long reap = 0; |
629 | 660 | ||
630 | down_read(&iprune_sem); | 661 | down_read(&iprune_sem); |
631 | spin_lock(&inode_lock); | 662 | spin_lock(&inode_lru_lock); |
632 | for (nr_scanned = 0; nr_scanned < nr_to_scan; nr_scanned++) { | 663 | for (nr_scanned = 0; nr_scanned < nr_to_scan; nr_scanned++) { |
633 | struct inode *inode; | 664 | struct inode *inode; |
634 | 665 | ||
@@ -638,53 +669,67 @@ static void prune_icache(int nr_to_scan) | |||
638 | inode = list_entry(inode_lru.prev, struct inode, i_lru); | 669 | inode = list_entry(inode_lru.prev, struct inode, i_lru); |
639 | 670 | ||
640 | /* | 671 | /* |
672 | * we are inverting the inode_lru_lock/inode->i_lock here, | ||
673 | * so use a trylock. If we fail to get the lock, just move the | ||
674 | * inode to the back of the list so we don't spin on it. | ||
675 | */ | ||
676 | if (!spin_trylock(&inode->i_lock)) { | ||
677 | list_move(&inode->i_lru, &inode_lru); | ||
678 | continue; | ||
679 | } | ||
680 | |||
681 | /* | ||
641 | * Referenced or dirty inodes are still in use. Give them | 682 | * Referenced or dirty inodes are still in use. Give them |
642 | * another pass through the LRU as we canot reclaim them now. | 683 | * another pass through the LRU as we canot reclaim them now. |
643 | */ | 684 | */ |
644 | if (atomic_read(&inode->i_count) || | 685 | if (atomic_read(&inode->i_count) || |
645 | (inode->i_state & ~I_REFERENCED)) { | 686 | (inode->i_state & ~I_REFERENCED)) { |
646 | list_del_init(&inode->i_lru); | 687 | list_del_init(&inode->i_lru); |
688 | spin_unlock(&inode->i_lock); | ||
647 | inodes_stat.nr_unused--; | 689 | inodes_stat.nr_unused--; |
648 | continue; | 690 | continue; |
649 | } | 691 | } |
650 | 692 | ||
651 | /* recently referenced inodes get one more pass */ | 693 | /* recently referenced inodes get one more pass */ |
652 | if (inode->i_state & I_REFERENCED) { | 694 | if (inode->i_state & I_REFERENCED) { |
653 | list_move(&inode->i_lru, &inode_lru); | ||
654 | inode->i_state &= ~I_REFERENCED; | 695 | inode->i_state &= ~I_REFERENCED; |
696 | list_move(&inode->i_lru, &inode_lru); | ||
697 | spin_unlock(&inode->i_lock); | ||
655 | continue; | 698 | continue; |
656 | } | 699 | } |
657 | if (inode_has_buffers(inode) || inode->i_data.nrpages) { | 700 | if (inode_has_buffers(inode) || inode->i_data.nrpages) { |
658 | __iget(inode); | 701 | __iget(inode); |
659 | spin_unlock(&inode_lock); | 702 | spin_unlock(&inode->i_lock); |
703 | spin_unlock(&inode_lru_lock); | ||
660 | if (remove_inode_buffers(inode)) | 704 | if (remove_inode_buffers(inode)) |
661 | reap += invalidate_mapping_pages(&inode->i_data, | 705 | reap += invalidate_mapping_pages(&inode->i_data, |
662 | 0, -1); | 706 | 0, -1); |
663 | iput(inode); | 707 | iput(inode); |
664 | spin_lock(&inode_lock); | 708 | spin_lock(&inode_lru_lock); |
665 | 709 | ||
666 | if (inode != list_entry(inode_lru.next, | 710 | if (inode != list_entry(inode_lru.next, |
667 | struct inode, i_lru)) | 711 | struct inode, i_lru)) |
668 | continue; /* wrong inode or list_empty */ | 712 | continue; /* wrong inode or list_empty */ |
669 | if (!can_unuse(inode)) | 713 | /* avoid lock inversions with trylock */ |
714 | if (!spin_trylock(&inode->i_lock)) | ||
715 | continue; | ||
716 | if (!can_unuse(inode)) { | ||
717 | spin_unlock(&inode->i_lock); | ||
670 | continue; | 718 | continue; |
719 | } | ||
671 | } | 720 | } |
672 | WARN_ON(inode->i_state & I_NEW); | 721 | WARN_ON(inode->i_state & I_NEW); |
673 | inode->i_state |= I_FREEING; | 722 | inode->i_state |= I_FREEING; |
723 | spin_unlock(&inode->i_lock); | ||
674 | 724 | ||
675 | /* | ||
676 | * Move the inode off the IO lists and LRU once I_FREEING is | ||
677 | * set so that it won't get moved back on there if it is dirty. | ||
678 | */ | ||
679 | list_move(&inode->i_lru, &freeable); | 725 | list_move(&inode->i_lru, &freeable); |
680 | list_del_init(&inode->i_wb_list); | ||
681 | inodes_stat.nr_unused--; | 726 | inodes_stat.nr_unused--; |
682 | } | 727 | } |
683 | if (current_is_kswapd()) | 728 | if (current_is_kswapd()) |
684 | __count_vm_events(KSWAPD_INODESTEAL, reap); | 729 | __count_vm_events(KSWAPD_INODESTEAL, reap); |
685 | else | 730 | else |
686 | __count_vm_events(PGINODESTEAL, reap); | 731 | __count_vm_events(PGINODESTEAL, reap); |
687 | spin_unlock(&inode_lock); | 732 | spin_unlock(&inode_lru_lock); |
688 | 733 | ||
689 | dispose_list(&freeable); | 734 | dispose_list(&freeable); |
690 | up_read(&iprune_sem); | 735 | up_read(&iprune_sem); |
@@ -733,15 +778,21 @@ static struct inode *find_inode(struct super_block *sb, | |||
733 | 778 | ||
734 | repeat: | 779 | repeat: |
735 | hlist_for_each_entry(inode, node, head, i_hash) { | 780 | hlist_for_each_entry(inode, node, head, i_hash) { |
736 | if (inode->i_sb != sb) | 781 | spin_lock(&inode->i_lock); |
782 | if (inode->i_sb != sb) { | ||
783 | spin_unlock(&inode->i_lock); | ||
737 | continue; | 784 | continue; |
738 | if (!test(inode, data)) | 785 | } |
786 | if (!test(inode, data)) { | ||
787 | spin_unlock(&inode->i_lock); | ||
739 | continue; | 788 | continue; |
789 | } | ||
740 | if (inode->i_state & (I_FREEING|I_WILL_FREE)) { | 790 | if (inode->i_state & (I_FREEING|I_WILL_FREE)) { |
741 | __wait_on_freeing_inode(inode); | 791 | __wait_on_freeing_inode(inode); |
742 | goto repeat; | 792 | goto repeat; |
743 | } | 793 | } |
744 | __iget(inode); | 794 | __iget(inode); |
795 | spin_unlock(&inode->i_lock); | ||
745 | return inode; | 796 | return inode; |
746 | } | 797 | } |
747 | return NULL; | 798 | return NULL; |
@@ -759,15 +810,21 @@ static struct inode *find_inode_fast(struct super_block *sb, | |||
759 | 810 | ||
760 | repeat: | 811 | repeat: |
761 | hlist_for_each_entry(inode, node, head, i_hash) { | 812 | hlist_for_each_entry(inode, node, head, i_hash) { |
762 | if (inode->i_ino != ino) | 813 | spin_lock(&inode->i_lock); |
814 | if (inode->i_ino != ino) { | ||
815 | spin_unlock(&inode->i_lock); | ||
763 | continue; | 816 | continue; |
764 | if (inode->i_sb != sb) | 817 | } |
818 | if (inode->i_sb != sb) { | ||
819 | spin_unlock(&inode->i_lock); | ||
765 | continue; | 820 | continue; |
821 | } | ||
766 | if (inode->i_state & (I_FREEING|I_WILL_FREE)) { | 822 | if (inode->i_state & (I_FREEING|I_WILL_FREE)) { |
767 | __wait_on_freeing_inode(inode); | 823 | __wait_on_freeing_inode(inode); |
768 | goto repeat; | 824 | goto repeat; |
769 | } | 825 | } |
770 | __iget(inode); | 826 | __iget(inode); |
827 | spin_unlock(&inode->i_lock); | ||
771 | return inode; | 828 | return inode; |
772 | } | 829 | } |
773 | return NULL; | 830 | return NULL; |
@@ -827,19 +884,26 @@ struct inode *new_inode(struct super_block *sb) | |||
827 | { | 884 | { |
828 | struct inode *inode; | 885 | struct inode *inode; |
829 | 886 | ||
830 | spin_lock_prefetch(&inode_lock); | 887 | spin_lock_prefetch(&inode_sb_list_lock); |
831 | 888 | ||
832 | inode = alloc_inode(sb); | 889 | inode = alloc_inode(sb); |
833 | if (inode) { | 890 | if (inode) { |
834 | spin_lock(&inode_lock); | 891 | spin_lock(&inode->i_lock); |
835 | __inode_sb_list_add(inode); | ||
836 | inode->i_state = 0; | 892 | inode->i_state = 0; |
837 | spin_unlock(&inode_lock); | 893 | spin_unlock(&inode->i_lock); |
894 | inode_sb_list_add(inode); | ||
838 | } | 895 | } |
839 | return inode; | 896 | return inode; |
840 | } | 897 | } |
841 | EXPORT_SYMBOL(new_inode); | 898 | EXPORT_SYMBOL(new_inode); |
842 | 899 | ||
900 | /** | ||
901 | * unlock_new_inode - clear the I_NEW state and wake up any waiters | ||
902 | * @inode: new inode to unlock | ||
903 | * | ||
904 | * Called when the inode is fully initialised to clear the new state of the | ||
905 | * inode and wake up anyone waiting for the inode to finish initialisation. | ||
906 | */ | ||
843 | void unlock_new_inode(struct inode *inode) | 907 | void unlock_new_inode(struct inode *inode) |
844 | { | 908 | { |
845 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | 909 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
@@ -859,51 +923,67 @@ void unlock_new_inode(struct inode *inode) | |||
859 | } | 923 | } |
860 | } | 924 | } |
861 | #endif | 925 | #endif |
862 | /* | 926 | spin_lock(&inode->i_lock); |
863 | * This is special! We do not need the spinlock when clearing I_NEW, | ||
864 | * because we're guaranteed that nobody else tries to do anything about | ||
865 | * the state of the inode when it is locked, as we just created it (so | ||
866 | * there can be no old holders that haven't tested I_NEW). | ||
867 | * However we must emit the memory barrier so that other CPUs reliably | ||
868 | * see the clearing of I_NEW after the other inode initialisation has | ||
869 | * completed. | ||
870 | */ | ||
871 | smp_mb(); | ||
872 | WARN_ON(!(inode->i_state & I_NEW)); | 927 | WARN_ON(!(inode->i_state & I_NEW)); |
873 | inode->i_state &= ~I_NEW; | 928 | inode->i_state &= ~I_NEW; |
874 | wake_up_inode(inode); | 929 | wake_up_bit(&inode->i_state, __I_NEW); |
930 | spin_unlock(&inode->i_lock); | ||
875 | } | 931 | } |
876 | EXPORT_SYMBOL(unlock_new_inode); | 932 | EXPORT_SYMBOL(unlock_new_inode); |
877 | 933 | ||
878 | /* | 934 | /** |
879 | * This is called without the inode lock held.. Be careful. | 935 | * iget5_locked - obtain an inode from a mounted file system |
936 | * @sb: super block of file system | ||
937 | * @hashval: hash value (usually inode number) to get | ||
938 | * @test: callback used for comparisons between inodes | ||
939 | * @set: callback used to initialize a new struct inode | ||
940 | * @data: opaque data pointer to pass to @test and @set | ||
941 | * | ||
942 | * Search for the inode specified by @hashval and @data in the inode cache, | ||
943 | * and if present it is return it with an increased reference count. This is | ||
944 | * a generalized version of iget_locked() for file systems where the inode | ||
945 | * number is not sufficient for unique identification of an inode. | ||
880 | * | 946 | * |
881 | * We no longer cache the sb_flags in i_flags - see fs.h | 947 | * If the inode is not in cache, allocate a new inode and return it locked, |
882 | * -- rmk@arm.uk.linux.org | 948 | * hashed, and with the I_NEW flag set. The file system gets to fill it in |
949 | * before unlocking it via unlock_new_inode(). | ||
950 | * | ||
951 | * Note both @test and @set are called with the inode_hash_lock held, so can't | ||
952 | * sleep. | ||
883 | */ | 953 | */ |
884 | static struct inode *get_new_inode(struct super_block *sb, | 954 | struct inode *iget5_locked(struct super_block *sb, unsigned long hashval, |
885 | struct hlist_head *head, | 955 | int (*test)(struct inode *, void *), |
886 | int (*test)(struct inode *, void *), | 956 | int (*set)(struct inode *, void *), void *data) |
887 | int (*set)(struct inode *, void *), | ||
888 | void *data) | ||
889 | { | 957 | { |
958 | struct hlist_head *head = inode_hashtable + hash(sb, hashval); | ||
890 | struct inode *inode; | 959 | struct inode *inode; |
891 | 960 | ||
961 | spin_lock(&inode_hash_lock); | ||
962 | inode = find_inode(sb, head, test, data); | ||
963 | spin_unlock(&inode_hash_lock); | ||
964 | |||
965 | if (inode) { | ||
966 | wait_on_inode(inode); | ||
967 | return inode; | ||
968 | } | ||
969 | |||
892 | inode = alloc_inode(sb); | 970 | inode = alloc_inode(sb); |
893 | if (inode) { | 971 | if (inode) { |
894 | struct inode *old; | 972 | struct inode *old; |
895 | 973 | ||
896 | spin_lock(&inode_lock); | 974 | spin_lock(&inode_hash_lock); |
897 | /* We released the lock, so.. */ | 975 | /* We released the lock, so.. */ |
898 | old = find_inode(sb, head, test, data); | 976 | old = find_inode(sb, head, test, data); |
899 | if (!old) { | 977 | if (!old) { |
900 | if (set(inode, data)) | 978 | if (set(inode, data)) |
901 | goto set_failed; | 979 | goto set_failed; |
902 | 980 | ||
903 | hlist_add_head(&inode->i_hash, head); | 981 | spin_lock(&inode->i_lock); |
904 | __inode_sb_list_add(inode); | ||
905 | inode->i_state = I_NEW; | 982 | inode->i_state = I_NEW; |
906 | spin_unlock(&inode_lock); | 983 | hlist_add_head(&inode->i_hash, head); |
984 | spin_unlock(&inode->i_lock); | ||
985 | inode_sb_list_add(inode); | ||
986 | spin_unlock(&inode_hash_lock); | ||
907 | 987 | ||
908 | /* Return the locked inode with I_NEW set, the | 988 | /* Return the locked inode with I_NEW set, the |
909 | * caller is responsible for filling in the contents | 989 | * caller is responsible for filling in the contents |
@@ -916,7 +996,7 @@ static struct inode *get_new_inode(struct super_block *sb, | |||
916 | * us. Use the old inode instead of the one we just | 996 | * us. Use the old inode instead of the one we just |
917 | * allocated. | 997 | * allocated. |
918 | */ | 998 | */ |
919 | spin_unlock(&inode_lock); | 999 | spin_unlock(&inode_hash_lock); |
920 | destroy_inode(inode); | 1000 | destroy_inode(inode); |
921 | inode = old; | 1001 | inode = old; |
922 | wait_on_inode(inode); | 1002 | wait_on_inode(inode); |
@@ -924,33 +1004,53 @@ static struct inode *get_new_inode(struct super_block *sb, | |||
924 | return inode; | 1004 | return inode; |
925 | 1005 | ||
926 | set_failed: | 1006 | set_failed: |
927 | spin_unlock(&inode_lock); | 1007 | spin_unlock(&inode_hash_lock); |
928 | destroy_inode(inode); | 1008 | destroy_inode(inode); |
929 | return NULL; | 1009 | return NULL; |
930 | } | 1010 | } |
1011 | EXPORT_SYMBOL(iget5_locked); | ||
931 | 1012 | ||
932 | /* | 1013 | /** |
933 | * get_new_inode_fast is the fast path version of get_new_inode, see the | 1014 | * iget_locked - obtain an inode from a mounted file system |
934 | * comment at iget_locked for details. | 1015 | * @sb: super block of file system |
1016 | * @ino: inode number to get | ||
1017 | * | ||
1018 | * Search for the inode specified by @ino in the inode cache and if present | ||
1019 | * return it with an increased reference count. This is for file systems | ||
1020 | * where the inode number is sufficient for unique identification of an inode. | ||
1021 | * | ||
1022 | * If the inode is not in cache, allocate a new inode and return it locked, | ||
1023 | * hashed, and with the I_NEW flag set. The file system gets to fill it in | ||
1024 | * before unlocking it via unlock_new_inode(). | ||
935 | */ | 1025 | */ |
936 | static struct inode *get_new_inode_fast(struct super_block *sb, | 1026 | struct inode *iget_locked(struct super_block *sb, unsigned long ino) |
937 | struct hlist_head *head, unsigned long ino) | ||
938 | { | 1027 | { |
1028 | struct hlist_head *head = inode_hashtable + hash(sb, ino); | ||
939 | struct inode *inode; | 1029 | struct inode *inode; |
940 | 1030 | ||
1031 | spin_lock(&inode_hash_lock); | ||
1032 | inode = find_inode_fast(sb, head, ino); | ||
1033 | spin_unlock(&inode_hash_lock); | ||
1034 | if (inode) { | ||
1035 | wait_on_inode(inode); | ||
1036 | return inode; | ||
1037 | } | ||
1038 | |||
941 | inode = alloc_inode(sb); | 1039 | inode = alloc_inode(sb); |
942 | if (inode) { | 1040 | if (inode) { |
943 | struct inode *old; | 1041 | struct inode *old; |
944 | 1042 | ||
945 | spin_lock(&inode_lock); | 1043 | spin_lock(&inode_hash_lock); |
946 | /* We released the lock, so.. */ | 1044 | /* We released the lock, so.. */ |
947 | old = find_inode_fast(sb, head, ino); | 1045 | old = find_inode_fast(sb, head, ino); |
948 | if (!old) { | 1046 | if (!old) { |
949 | inode->i_ino = ino; | 1047 | inode->i_ino = ino; |
950 | hlist_add_head(&inode->i_hash, head); | 1048 | spin_lock(&inode->i_lock); |
951 | __inode_sb_list_add(inode); | ||
952 | inode->i_state = I_NEW; | 1049 | inode->i_state = I_NEW; |
953 | spin_unlock(&inode_lock); | 1050 | hlist_add_head(&inode->i_hash, head); |
1051 | spin_unlock(&inode->i_lock); | ||
1052 | inode_sb_list_add(inode); | ||
1053 | spin_unlock(&inode_hash_lock); | ||
954 | 1054 | ||
955 | /* Return the locked inode with I_NEW set, the | 1055 | /* Return the locked inode with I_NEW set, the |
956 | * caller is responsible for filling in the contents | 1056 | * caller is responsible for filling in the contents |
@@ -963,13 +1063,14 @@ static struct inode *get_new_inode_fast(struct super_block *sb, | |||
963 | * us. Use the old inode instead of the one we just | 1063 | * us. Use the old inode instead of the one we just |
964 | * allocated. | 1064 | * allocated. |
965 | */ | 1065 | */ |
966 | spin_unlock(&inode_lock); | 1066 | spin_unlock(&inode_hash_lock); |
967 | destroy_inode(inode); | 1067 | destroy_inode(inode); |
968 | inode = old; | 1068 | inode = old; |
969 | wait_on_inode(inode); | 1069 | wait_on_inode(inode); |
970 | } | 1070 | } |
971 | return inode; | 1071 | return inode; |
972 | } | 1072 | } |
1073 | EXPORT_SYMBOL(iget_locked); | ||
973 | 1074 | ||
974 | /* | 1075 | /* |
975 | * search the inode cache for a matching inode number. | 1076 | * search the inode cache for a matching inode number. |
@@ -984,10 +1085,14 @@ static int test_inode_iunique(struct super_block *sb, unsigned long ino) | |||
984 | struct hlist_node *node; | 1085 | struct hlist_node *node; |
985 | struct inode *inode; | 1086 | struct inode *inode; |
986 | 1087 | ||
1088 | spin_lock(&inode_hash_lock); | ||
987 | hlist_for_each_entry(inode, node, b, i_hash) { | 1089 | hlist_for_each_entry(inode, node, b, i_hash) { |
988 | if (inode->i_ino == ino && inode->i_sb == sb) | 1090 | if (inode->i_ino == ino && inode->i_sb == sb) { |
1091 | spin_unlock(&inode_hash_lock); | ||
989 | return 0; | 1092 | return 0; |
1093 | } | ||
990 | } | 1094 | } |
1095 | spin_unlock(&inode_hash_lock); | ||
991 | 1096 | ||
992 | return 1; | 1097 | return 1; |
993 | } | 1098 | } |
@@ -1017,7 +1122,6 @@ ino_t iunique(struct super_block *sb, ino_t max_reserved) | |||
1017 | static unsigned int counter; | 1122 | static unsigned int counter; |
1018 | ino_t res; | 1123 | ino_t res; |
1019 | 1124 | ||
1020 | spin_lock(&inode_lock); | ||
1021 | spin_lock(&iunique_lock); | 1125 | spin_lock(&iunique_lock); |
1022 | do { | 1126 | do { |
1023 | if (counter <= max_reserved) | 1127 | if (counter <= max_reserved) |
@@ -1025,7 +1129,6 @@ ino_t iunique(struct super_block *sb, ino_t max_reserved) | |||
1025 | res = counter++; | 1129 | res = counter++; |
1026 | } while (!test_inode_iunique(sb, res)); | 1130 | } while (!test_inode_iunique(sb, res)); |
1027 | spin_unlock(&iunique_lock); | 1131 | spin_unlock(&iunique_lock); |
1028 | spin_unlock(&inode_lock); | ||
1029 | 1132 | ||
1030 | return res; | 1133 | return res; |
1031 | } | 1134 | } |
@@ -1033,116 +1136,50 @@ EXPORT_SYMBOL(iunique); | |||
1033 | 1136 | ||
1034 | struct inode *igrab(struct inode *inode) | 1137 | struct inode *igrab(struct inode *inode) |
1035 | { | 1138 | { |
1036 | spin_lock(&inode_lock); | 1139 | spin_lock(&inode->i_lock); |
1037 | if (!(inode->i_state & (I_FREEING|I_WILL_FREE))) | 1140 | if (!(inode->i_state & (I_FREEING|I_WILL_FREE))) { |
1038 | __iget(inode); | 1141 | __iget(inode); |
1039 | else | 1142 | spin_unlock(&inode->i_lock); |
1143 | } else { | ||
1144 | spin_unlock(&inode->i_lock); | ||
1040 | /* | 1145 | /* |
1041 | * Handle the case where s_op->clear_inode is not been | 1146 | * Handle the case where s_op->clear_inode is not been |
1042 | * called yet, and somebody is calling igrab | 1147 | * called yet, and somebody is calling igrab |
1043 | * while the inode is getting freed. | 1148 | * while the inode is getting freed. |
1044 | */ | 1149 | */ |
1045 | inode = NULL; | 1150 | inode = NULL; |
1046 | spin_unlock(&inode_lock); | 1151 | } |
1047 | return inode; | 1152 | return inode; |
1048 | } | 1153 | } |
1049 | EXPORT_SYMBOL(igrab); | 1154 | EXPORT_SYMBOL(igrab); |
1050 | 1155 | ||
1051 | /** | 1156 | /** |
1052 | * ifind - internal function, you want ilookup5() or iget5(). | ||
1053 | * @sb: super block of file system to search | ||
1054 | * @head: the head of the list to search | ||
1055 | * @test: callback used for comparisons between inodes | ||
1056 | * @data: opaque data pointer to pass to @test | ||
1057 | * @wait: if true wait for the inode to be unlocked, if false do not | ||
1058 | * | ||
1059 | * ifind() searches for the inode specified by @data in the inode | ||
1060 | * cache. This is a generalized version of ifind_fast() for file systems where | ||
1061 | * the inode number is not sufficient for unique identification of an inode. | ||
1062 | * | ||
1063 | * If the inode is in the cache, the inode is returned with an incremented | ||
1064 | * reference count. | ||
1065 | * | ||
1066 | * Otherwise NULL is returned. | ||
1067 | * | ||
1068 | * Note, @test is called with the inode_lock held, so can't sleep. | ||
1069 | */ | ||
1070 | static struct inode *ifind(struct super_block *sb, | ||
1071 | struct hlist_head *head, int (*test)(struct inode *, void *), | ||
1072 | void *data, const int wait) | ||
1073 | { | ||
1074 | struct inode *inode; | ||
1075 | |||
1076 | spin_lock(&inode_lock); | ||
1077 | inode = find_inode(sb, head, test, data); | ||
1078 | if (inode) { | ||
1079 | spin_unlock(&inode_lock); | ||
1080 | if (likely(wait)) | ||
1081 | wait_on_inode(inode); | ||
1082 | return inode; | ||
1083 | } | ||
1084 | spin_unlock(&inode_lock); | ||
1085 | return NULL; | ||
1086 | } | ||
1087 | |||
1088 | /** | ||
1089 | * ifind_fast - internal function, you want ilookup() or iget(). | ||
1090 | * @sb: super block of file system to search | ||
1091 | * @head: head of the list to search | ||
1092 | * @ino: inode number to search for | ||
1093 | * | ||
1094 | * ifind_fast() searches for the inode @ino in the inode cache. This is for | ||
1095 | * file systems where the inode number is sufficient for unique identification | ||
1096 | * of an inode. | ||
1097 | * | ||
1098 | * If the inode is in the cache, the inode is returned with an incremented | ||
1099 | * reference count. | ||
1100 | * | ||
1101 | * Otherwise NULL is returned. | ||
1102 | */ | ||
1103 | static struct inode *ifind_fast(struct super_block *sb, | ||
1104 | struct hlist_head *head, unsigned long ino) | ||
1105 | { | ||
1106 | struct inode *inode; | ||
1107 | |||
1108 | spin_lock(&inode_lock); | ||
1109 | inode = find_inode_fast(sb, head, ino); | ||
1110 | if (inode) { | ||
1111 | spin_unlock(&inode_lock); | ||
1112 | wait_on_inode(inode); | ||
1113 | return inode; | ||
1114 | } | ||
1115 | spin_unlock(&inode_lock); | ||
1116 | return NULL; | ||
1117 | } | ||
1118 | |||
1119 | /** | ||
1120 | * ilookup5_nowait - search for an inode in the inode cache | 1157 | * ilookup5_nowait - search for an inode in the inode cache |
1121 | * @sb: super block of file system to search | 1158 | * @sb: super block of file system to search |
1122 | * @hashval: hash value (usually inode number) to search for | 1159 | * @hashval: hash value (usually inode number) to search for |
1123 | * @test: callback used for comparisons between inodes | 1160 | * @test: callback used for comparisons between inodes |
1124 | * @data: opaque data pointer to pass to @test | 1161 | * @data: opaque data pointer to pass to @test |
1125 | * | 1162 | * |
1126 | * ilookup5() uses ifind() to search for the inode specified by @hashval and | 1163 | * Search for the inode specified by @hashval and @data in the inode cache. |
1127 | * @data in the inode cache. This is a generalized version of ilookup() for | ||
1128 | * file systems where the inode number is not sufficient for unique | ||
1129 | * identification of an inode. | ||
1130 | * | ||
1131 | * If the inode is in the cache, the inode is returned with an incremented | 1164 | * If the inode is in the cache, the inode is returned with an incremented |
1132 | * reference count. Note, the inode lock is not waited upon so you have to be | 1165 | * reference count. |
1133 | * very careful what you do with the returned inode. You probably should be | ||
1134 | * using ilookup5() instead. | ||
1135 | * | 1166 | * |
1136 | * Otherwise NULL is returned. | 1167 | * Note: I_NEW is not waited upon so you have to be very careful what you do |
1168 | * with the returned inode. You probably should be using ilookup5() instead. | ||
1137 | * | 1169 | * |
1138 | * Note, @test is called with the inode_lock held, so can't sleep. | 1170 | * Note2: @test is called with the inode_hash_lock held, so can't sleep. |
1139 | */ | 1171 | */ |
1140 | struct inode *ilookup5_nowait(struct super_block *sb, unsigned long hashval, | 1172 | struct inode *ilookup5_nowait(struct super_block *sb, unsigned long hashval, |
1141 | int (*test)(struct inode *, void *), void *data) | 1173 | int (*test)(struct inode *, void *), void *data) |
1142 | { | 1174 | { |
1143 | struct hlist_head *head = inode_hashtable + hash(sb, hashval); | 1175 | struct hlist_head *head = inode_hashtable + hash(sb, hashval); |
1176 | struct inode *inode; | ||
1177 | |||
1178 | spin_lock(&inode_hash_lock); | ||
1179 | inode = find_inode(sb, head, test, data); | ||
1180 | spin_unlock(&inode_hash_lock); | ||
1144 | 1181 | ||
1145 | return ifind(sb, head, test, data, 0); | 1182 | return inode; |
1146 | } | 1183 | } |
1147 | EXPORT_SYMBOL(ilookup5_nowait); | 1184 | EXPORT_SYMBOL(ilookup5_nowait); |
1148 | 1185 | ||
@@ -1153,24 +1190,24 @@ EXPORT_SYMBOL(ilookup5_nowait); | |||
1153 | * @test: callback used for comparisons between inodes | 1190 | * @test: callback used for comparisons between inodes |
1154 | * @data: opaque data pointer to pass to @test | 1191 | * @data: opaque data pointer to pass to @test |
1155 | * | 1192 | * |
1156 | * ilookup5() uses ifind() to search for the inode specified by @hashval and | 1193 | * Search for the inode specified by @hashval and @data in the inode cache, |
1157 | * @data in the inode cache. This is a generalized version of ilookup() for | 1194 | * and if the inode is in the cache, return the inode with an incremented |
1158 | * file systems where the inode number is not sufficient for unique | 1195 | * reference count. Waits on I_NEW before returning the inode. |
1159 | * identification of an inode. | ||
1160 | * | ||
1161 | * If the inode is in the cache, the inode lock is waited upon and the inode is | ||
1162 | * returned with an incremented reference count. | 1196 | * returned with an incremented reference count. |
1163 | * | 1197 | * |
1164 | * Otherwise NULL is returned. | 1198 | * This is a generalized version of ilookup() for file systems where the |
1199 | * inode number is not sufficient for unique identification of an inode. | ||
1165 | * | 1200 | * |
1166 | * Note, @test is called with the inode_lock held, so can't sleep. | 1201 | * Note: @test is called with the inode_hash_lock held, so can't sleep. |
1167 | */ | 1202 | */ |
1168 | struct inode *ilookup5(struct super_block *sb, unsigned long hashval, | 1203 | struct inode *ilookup5(struct super_block *sb, unsigned long hashval, |
1169 | int (*test)(struct inode *, void *), void *data) | 1204 | int (*test)(struct inode *, void *), void *data) |
1170 | { | 1205 | { |
1171 | struct hlist_head *head = inode_hashtable + hash(sb, hashval); | 1206 | struct inode *inode = ilookup5_nowait(sb, hashval, test, data); |
1172 | 1207 | ||
1173 | return ifind(sb, head, test, data, 1); | 1208 | if (inode) |
1209 | wait_on_inode(inode); | ||
1210 | return inode; | ||
1174 | } | 1211 | } |
1175 | EXPORT_SYMBOL(ilookup5); | 1212 | EXPORT_SYMBOL(ilookup5); |
1176 | 1213 | ||
@@ -1179,91 +1216,23 @@ EXPORT_SYMBOL(ilookup5); | |||
1179 | * @sb: super block of file system to search | 1216 | * @sb: super block of file system to search |
1180 | * @ino: inode number to search for | 1217 | * @ino: inode number to search for |
1181 | * | 1218 | * |
1182 | * ilookup() uses ifind_fast() to search for the inode @ino in the inode cache. | 1219 | * Search for the inode @ino in the inode cache, and if the inode is in the |
1183 | * This is for file systems where the inode number is sufficient for unique | 1220 | * cache, the inode is returned with an incremented reference count. |
1184 | * identification of an inode. | ||
1185 | * | ||
1186 | * If the inode is in the cache, the inode is returned with an incremented | ||
1187 | * reference count. | ||
1188 | * | ||
1189 | * Otherwise NULL is returned. | ||
1190 | */ | 1221 | */ |
1191 | struct inode *ilookup(struct super_block *sb, unsigned long ino) | 1222 | struct inode *ilookup(struct super_block *sb, unsigned long ino) |
1192 | { | 1223 | { |
1193 | struct hlist_head *head = inode_hashtable + hash(sb, ino); | 1224 | struct hlist_head *head = inode_hashtable + hash(sb, ino); |
1194 | |||
1195 | return ifind_fast(sb, head, ino); | ||
1196 | } | ||
1197 | EXPORT_SYMBOL(ilookup); | ||
1198 | |||
1199 | /** | ||
1200 | * iget5_locked - obtain an inode from a mounted file system | ||
1201 | * @sb: super block of file system | ||
1202 | * @hashval: hash value (usually inode number) to get | ||
1203 | * @test: callback used for comparisons between inodes | ||
1204 | * @set: callback used to initialize a new struct inode | ||
1205 | * @data: opaque data pointer to pass to @test and @set | ||
1206 | * | ||
1207 | * iget5_locked() uses ifind() to search for the inode specified by @hashval | ||
1208 | * and @data in the inode cache and if present it is returned with an increased | ||
1209 | * reference count. This is a generalized version of iget_locked() for file | ||
1210 | * systems where the inode number is not sufficient for unique identification | ||
1211 | * of an inode. | ||
1212 | * | ||
1213 | * If the inode is not in cache, get_new_inode() is called to allocate a new | ||
1214 | * inode and this is returned locked, hashed, and with the I_NEW flag set. The | ||
1215 | * file system gets to fill it in before unlocking it via unlock_new_inode(). | ||
1216 | * | ||
1217 | * Note both @test and @set are called with the inode_lock held, so can't sleep. | ||
1218 | */ | ||
1219 | struct inode *iget5_locked(struct super_block *sb, unsigned long hashval, | ||
1220 | int (*test)(struct inode *, void *), | ||
1221 | int (*set)(struct inode *, void *), void *data) | ||
1222 | { | ||
1223 | struct hlist_head *head = inode_hashtable + hash(sb, hashval); | ||
1224 | struct inode *inode; | 1225 | struct inode *inode; |
1225 | 1226 | ||
1226 | inode = ifind(sb, head, test, data, 1); | 1227 | spin_lock(&inode_hash_lock); |
1227 | if (inode) | 1228 | inode = find_inode_fast(sb, head, ino); |
1228 | return inode; | 1229 | spin_unlock(&inode_hash_lock); |
1229 | /* | ||
1230 | * get_new_inode() will do the right thing, re-trying the search | ||
1231 | * in case it had to block at any point. | ||
1232 | */ | ||
1233 | return get_new_inode(sb, head, test, set, data); | ||
1234 | } | ||
1235 | EXPORT_SYMBOL(iget5_locked); | ||
1236 | |||
1237 | /** | ||
1238 | * iget_locked - obtain an inode from a mounted file system | ||
1239 | * @sb: super block of file system | ||
1240 | * @ino: inode number to get | ||
1241 | * | ||
1242 | * iget_locked() uses ifind_fast() to search for the inode specified by @ino in | ||
1243 | * the inode cache and if present it is returned with an increased reference | ||
1244 | * count. This is for file systems where the inode number is sufficient for | ||
1245 | * unique identification of an inode. | ||
1246 | * | ||
1247 | * If the inode is not in cache, get_new_inode_fast() is called to allocate a | ||
1248 | * new inode and this is returned locked, hashed, and with the I_NEW flag set. | ||
1249 | * The file system gets to fill it in before unlocking it via | ||
1250 | * unlock_new_inode(). | ||
1251 | */ | ||
1252 | struct inode *iget_locked(struct super_block *sb, unsigned long ino) | ||
1253 | { | ||
1254 | struct hlist_head *head = inode_hashtable + hash(sb, ino); | ||
1255 | struct inode *inode; | ||
1256 | 1230 | ||
1257 | inode = ifind_fast(sb, head, ino); | ||
1258 | if (inode) | 1231 | if (inode) |
1259 | return inode; | 1232 | wait_on_inode(inode); |
1260 | /* | 1233 | return inode; |
1261 | * get_new_inode_fast() will do the right thing, re-trying the search | ||
1262 | * in case it had to block at any point. | ||
1263 | */ | ||
1264 | return get_new_inode_fast(sb, head, ino); | ||
1265 | } | 1234 | } |
1266 | EXPORT_SYMBOL(iget_locked); | 1235 | EXPORT_SYMBOL(ilookup); |
1267 | 1236 | ||
1268 | int insert_inode_locked(struct inode *inode) | 1237 | int insert_inode_locked(struct inode *inode) |
1269 | { | 1238 | { |
@@ -1271,27 +1240,33 @@ int insert_inode_locked(struct inode *inode) | |||
1271 | ino_t ino = inode->i_ino; | 1240 | ino_t ino = inode->i_ino; |
1272 | struct hlist_head *head = inode_hashtable + hash(sb, ino); | 1241 | struct hlist_head *head = inode_hashtable + hash(sb, ino); |
1273 | 1242 | ||
1274 | inode->i_state |= I_NEW; | ||
1275 | while (1) { | 1243 | while (1) { |
1276 | struct hlist_node *node; | 1244 | struct hlist_node *node; |
1277 | struct inode *old = NULL; | 1245 | struct inode *old = NULL; |
1278 | spin_lock(&inode_lock); | 1246 | spin_lock(&inode_hash_lock); |
1279 | hlist_for_each_entry(old, node, head, i_hash) { | 1247 | hlist_for_each_entry(old, node, head, i_hash) { |
1280 | if (old->i_ino != ino) | 1248 | if (old->i_ino != ino) |
1281 | continue; | 1249 | continue; |
1282 | if (old->i_sb != sb) | 1250 | if (old->i_sb != sb) |
1283 | continue; | 1251 | continue; |
1284 | if (old->i_state & (I_FREEING|I_WILL_FREE)) | 1252 | spin_lock(&old->i_lock); |
1253 | if (old->i_state & (I_FREEING|I_WILL_FREE)) { | ||
1254 | spin_unlock(&old->i_lock); | ||
1285 | continue; | 1255 | continue; |
1256 | } | ||
1286 | break; | 1257 | break; |
1287 | } | 1258 | } |
1288 | if (likely(!node)) { | 1259 | if (likely(!node)) { |
1260 | spin_lock(&inode->i_lock); | ||
1261 | inode->i_state |= I_NEW; | ||
1289 | hlist_add_head(&inode->i_hash, head); | 1262 | hlist_add_head(&inode->i_hash, head); |
1290 | spin_unlock(&inode_lock); | 1263 | spin_unlock(&inode->i_lock); |
1264 | spin_unlock(&inode_hash_lock); | ||
1291 | return 0; | 1265 | return 0; |
1292 | } | 1266 | } |
1293 | __iget(old); | 1267 | __iget(old); |
1294 | spin_unlock(&inode_lock); | 1268 | spin_unlock(&old->i_lock); |
1269 | spin_unlock(&inode_hash_lock); | ||
1295 | wait_on_inode(old); | 1270 | wait_on_inode(old); |
1296 | if (unlikely(!inode_unhashed(old))) { | 1271 | if (unlikely(!inode_unhashed(old))) { |
1297 | iput(old); | 1272 | iput(old); |
@@ -1308,29 +1283,34 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval, | |||
1308 | struct super_block *sb = inode->i_sb; | 1283 | struct super_block *sb = inode->i_sb; |
1309 | struct hlist_head *head = inode_hashtable + hash(sb, hashval); | 1284 | struct hlist_head *head = inode_hashtable + hash(sb, hashval); |
1310 | 1285 | ||
1311 | inode->i_state |= I_NEW; | ||
1312 | |||
1313 | while (1) { | 1286 | while (1) { |
1314 | struct hlist_node *node; | 1287 | struct hlist_node *node; |
1315 | struct inode *old = NULL; | 1288 | struct inode *old = NULL; |
1316 | 1289 | ||
1317 | spin_lock(&inode_lock); | 1290 | spin_lock(&inode_hash_lock); |
1318 | hlist_for_each_entry(old, node, head, i_hash) { | 1291 | hlist_for_each_entry(old, node, head, i_hash) { |
1319 | if (old->i_sb != sb) | 1292 | if (old->i_sb != sb) |
1320 | continue; | 1293 | continue; |
1321 | if (!test(old, data)) | 1294 | if (!test(old, data)) |
1322 | continue; | 1295 | continue; |
1323 | if (old->i_state & (I_FREEING|I_WILL_FREE)) | 1296 | spin_lock(&old->i_lock); |
1297 | if (old->i_state & (I_FREEING|I_WILL_FREE)) { | ||
1298 | spin_unlock(&old->i_lock); | ||
1324 | continue; | 1299 | continue; |
1300 | } | ||
1325 | break; | 1301 | break; |
1326 | } | 1302 | } |
1327 | if (likely(!node)) { | 1303 | if (likely(!node)) { |
1304 | spin_lock(&inode->i_lock); | ||
1305 | inode->i_state |= I_NEW; | ||
1328 | hlist_add_head(&inode->i_hash, head); | 1306 | hlist_add_head(&inode->i_hash, head); |
1329 | spin_unlock(&inode_lock); | 1307 | spin_unlock(&inode->i_lock); |
1308 | spin_unlock(&inode_hash_lock); | ||
1330 | return 0; | 1309 | return 0; |
1331 | } | 1310 | } |
1332 | __iget(old); | 1311 | __iget(old); |
1333 | spin_unlock(&inode_lock); | 1312 | spin_unlock(&old->i_lock); |
1313 | spin_unlock(&inode_hash_lock); | ||
1334 | wait_on_inode(old); | 1314 | wait_on_inode(old); |
1335 | if (unlikely(!inode_unhashed(old))) { | 1315 | if (unlikely(!inode_unhashed(old))) { |
1336 | iput(old); | 1316 | iput(old); |
@@ -1375,47 +1355,35 @@ static void iput_final(struct inode *inode) | |||
1375 | const struct super_operations *op = inode->i_sb->s_op; | 1355 | const struct super_operations *op = inode->i_sb->s_op; |
1376 | int drop; | 1356 | int drop; |
1377 | 1357 | ||
1358 | WARN_ON(inode->i_state & I_NEW); | ||
1359 | |||
1378 | if (op && op->drop_inode) | 1360 | if (op && op->drop_inode) |
1379 | drop = op->drop_inode(inode); | 1361 | drop = op->drop_inode(inode); |
1380 | else | 1362 | else |
1381 | drop = generic_drop_inode(inode); | 1363 | drop = generic_drop_inode(inode); |
1382 | 1364 | ||
1365 | if (!drop && (sb->s_flags & MS_ACTIVE)) { | ||
1366 | inode->i_state |= I_REFERENCED; | ||
1367 | if (!(inode->i_state & (I_DIRTY|I_SYNC))) | ||
1368 | inode_lru_list_add(inode); | ||
1369 | spin_unlock(&inode->i_lock); | ||
1370 | return; | ||
1371 | } | ||
1372 | |||
1383 | if (!drop) { | 1373 | if (!drop) { |
1384 | if (sb->s_flags & MS_ACTIVE) { | ||
1385 | inode->i_state |= I_REFERENCED; | ||
1386 | if (!(inode->i_state & (I_DIRTY|I_SYNC))) { | ||
1387 | inode_lru_list_add(inode); | ||
1388 | } | ||
1389 | spin_unlock(&inode_lock); | ||
1390 | return; | ||
1391 | } | ||
1392 | WARN_ON(inode->i_state & I_NEW); | ||
1393 | inode->i_state |= I_WILL_FREE; | 1374 | inode->i_state |= I_WILL_FREE; |
1394 | spin_unlock(&inode_lock); | 1375 | spin_unlock(&inode->i_lock); |
1395 | write_inode_now(inode, 1); | 1376 | write_inode_now(inode, 1); |
1396 | spin_lock(&inode_lock); | 1377 | spin_lock(&inode->i_lock); |
1397 | WARN_ON(inode->i_state & I_NEW); | 1378 | WARN_ON(inode->i_state & I_NEW); |
1398 | inode->i_state &= ~I_WILL_FREE; | 1379 | inode->i_state &= ~I_WILL_FREE; |
1399 | __remove_inode_hash(inode); | ||
1400 | } | 1380 | } |
1401 | 1381 | ||
1402 | WARN_ON(inode->i_state & I_NEW); | ||
1403 | inode->i_state |= I_FREEING; | 1382 | inode->i_state |= I_FREEING; |
1404 | |||
1405 | /* | ||
1406 | * Move the inode off the IO lists and LRU once I_FREEING is | ||
1407 | * set so that it won't get moved back on there if it is dirty. | ||
1408 | */ | ||
1409 | inode_lru_list_del(inode); | 1383 | inode_lru_list_del(inode); |
1410 | list_del_init(&inode->i_wb_list); | 1384 | spin_unlock(&inode->i_lock); |
1411 | 1385 | ||
1412 | __inode_sb_list_del(inode); | ||
1413 | spin_unlock(&inode_lock); | ||
1414 | evict(inode); | 1386 | evict(inode); |
1415 | remove_inode_hash(inode); | ||
1416 | wake_up_inode(inode); | ||
1417 | BUG_ON(inode->i_state != (I_FREEING | I_CLEAR)); | ||
1418 | destroy_inode(inode); | ||
1419 | } | 1387 | } |
1420 | 1388 | ||
1421 | /** | 1389 | /** |
@@ -1432,7 +1400,7 @@ void iput(struct inode *inode) | |||
1432 | if (inode) { | 1400 | if (inode) { |
1433 | BUG_ON(inode->i_state & I_CLEAR); | 1401 | BUG_ON(inode->i_state & I_CLEAR); |
1434 | 1402 | ||
1435 | if (atomic_dec_and_lock(&inode->i_count, &inode_lock)) | 1403 | if (atomic_dec_and_lock(&inode->i_count, &inode->i_lock)) |
1436 | iput_final(inode); | 1404 | iput_final(inode); |
1437 | } | 1405 | } |
1438 | } | 1406 | } |
@@ -1611,9 +1579,8 @@ EXPORT_SYMBOL(inode_wait); | |||
1611 | * to recheck inode state. | 1579 | * to recheck inode state. |
1612 | * | 1580 | * |
1613 | * It doesn't matter if I_NEW is not set initially, a call to | 1581 | * It doesn't matter if I_NEW is not set initially, a call to |
1614 | * wake_up_inode() after removing from the hash list will DTRT. | 1582 | * wake_up_bit(&inode->i_state, __I_NEW) after removing from the hash list |
1615 | * | 1583 | * will DTRT. |
1616 | * This is called with inode_lock held. | ||
1617 | */ | 1584 | */ |
1618 | static void __wait_on_freeing_inode(struct inode *inode) | 1585 | static void __wait_on_freeing_inode(struct inode *inode) |
1619 | { | 1586 | { |
@@ -1621,10 +1588,11 @@ static void __wait_on_freeing_inode(struct inode *inode) | |||
1621 | DEFINE_WAIT_BIT(wait, &inode->i_state, __I_NEW); | 1588 | DEFINE_WAIT_BIT(wait, &inode->i_state, __I_NEW); |
1622 | wq = bit_waitqueue(&inode->i_state, __I_NEW); | 1589 | wq = bit_waitqueue(&inode->i_state, __I_NEW); |
1623 | prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE); | 1590 | prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE); |
1624 | spin_unlock(&inode_lock); | 1591 | spin_unlock(&inode->i_lock); |
1592 | spin_unlock(&inode_hash_lock); | ||
1625 | schedule(); | 1593 | schedule(); |
1626 | finish_wait(wq, &wait.wait); | 1594 | finish_wait(wq, &wait.wait); |
1627 | spin_lock(&inode_lock); | 1595 | spin_lock(&inode_hash_lock); |
1628 | } | 1596 | } |
1629 | 1597 | ||
1630 | static __initdata unsigned long ihash_entries; | 1598 | static __initdata unsigned long ihash_entries; |
diff --git a/fs/internal.h b/fs/internal.h index 8318059b42c6..b29c46e4e32f 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -125,6 +125,13 @@ extern long do_handle_open(int mountdirfd, | |||
125 | /* | 125 | /* |
126 | * inode.c | 126 | * inode.c |
127 | */ | 127 | */ |
128 | extern spinlock_t inode_sb_list_lock; | ||
129 | |||
130 | /* | ||
131 | * fs-writeback.c | ||
132 | */ | ||
133 | extern void inode_wb_list_del(struct inode *inode); | ||
134 | |||
128 | extern int get_nr_dirty_inodes(void); | 135 | extern int get_nr_dirty_inodes(void); |
129 | extern void evict_inodes(struct super_block *); | 136 | extern void evict_inodes(struct super_block *); |
130 | extern int invalidate_inodes(struct super_block *, bool); | 137 | extern int invalidate_inodes(struct super_block *, bool); |
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index 4f9cc0482949..3e93cdd19005 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c | |||
@@ -31,7 +31,7 @@ | |||
31 | * is used to release xattr name/value pair and detach from c->xattrindex. | 31 | * is used to release xattr name/value pair and detach from c->xattrindex. |
32 | * reclaim_xattr_datum(c) | 32 | * reclaim_xattr_datum(c) |
33 | * is used to reclaim xattr name/value pairs on the xattr name/value pair cache when | 33 | * is used to reclaim xattr name/value pairs on the xattr name/value pair cache when |
34 | * memory usage by cache is over c->xdatum_mem_threshold. Currently, this threshold | 34 | * memory usage by cache is over c->xdatum_mem_threshold. Currently, this threshold |
35 | * is hard coded as 32KiB. | 35 | * is hard coded as 32KiB. |
36 | * do_verify_xattr_datum(c, xd) | 36 | * do_verify_xattr_datum(c, xd) |
37 | * is used to load the xdatum informations without name/value pair from the medium. | 37 | * is used to load the xdatum informations without name/value pair from the medium. |
diff --git a/fs/logfs/inode.c b/fs/logfs/inode.c index 03b8c240aeda..edfea7a3a747 100644 --- a/fs/logfs/inode.c +++ b/fs/logfs/inode.c | |||
@@ -293,7 +293,7 @@ static int logfs_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
293 | return ret; | 293 | return ret; |
294 | } | 294 | } |
295 | 295 | ||
296 | /* called with inode_lock held */ | 296 | /* called with inode->i_lock held */ |
297 | static int logfs_drop_inode(struct inode *inode) | 297 | static int logfs_drop_inode(struct inode *inode) |
298 | { | 298 | { |
299 | struct logfs_super *super = logfs_super(inode->i_sb); | 299 | struct logfs_super *super = logfs_super(inode->i_sb); |
diff --git a/fs/namei.c b/fs/namei.c index d0066e17d45d..3cb616d38d9c 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -992,6 +992,12 @@ int follow_down_one(struct path *path) | |||
992 | return 0; | 992 | return 0; |
993 | } | 993 | } |
994 | 994 | ||
995 | static inline bool managed_dentry_might_block(struct dentry *dentry) | ||
996 | { | ||
997 | return (dentry->d_flags & DCACHE_MANAGE_TRANSIT && | ||
998 | dentry->d_op->d_manage(dentry, true) < 0); | ||
999 | } | ||
1000 | |||
995 | /* | 1001 | /* |
996 | * Skip to top of mountpoint pile in rcuwalk mode. We abort the rcu-walk if we | 1002 | * Skip to top of mountpoint pile in rcuwalk mode. We abort the rcu-walk if we |
997 | * meet a managed dentry and we're not walking to "..". True is returned to | 1003 | * meet a managed dentry and we're not walking to "..". True is returned to |
@@ -1000,19 +1006,26 @@ int follow_down_one(struct path *path) | |||
1000 | static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, | 1006 | static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, |
1001 | struct inode **inode, bool reverse_transit) | 1007 | struct inode **inode, bool reverse_transit) |
1002 | { | 1008 | { |
1003 | while (d_mountpoint(path->dentry)) { | 1009 | for (;;) { |
1004 | struct vfsmount *mounted; | 1010 | struct vfsmount *mounted; |
1005 | if (unlikely(path->dentry->d_flags & DCACHE_MANAGE_TRANSIT) && | 1011 | /* |
1006 | !reverse_transit && | 1012 | * Don't forget we might have a non-mountpoint managed dentry |
1007 | path->dentry->d_op->d_manage(path->dentry, true) < 0) | 1013 | * that wants to block transit. |
1014 | */ | ||
1015 | *inode = path->dentry->d_inode; | ||
1016 | if (!reverse_transit && | ||
1017 | unlikely(managed_dentry_might_block(path->dentry))) | ||
1008 | return false; | 1018 | return false; |
1019 | |||
1020 | if (!d_mountpoint(path->dentry)) | ||
1021 | break; | ||
1022 | |||
1009 | mounted = __lookup_mnt(path->mnt, path->dentry, 1); | 1023 | mounted = __lookup_mnt(path->mnt, path->dentry, 1); |
1010 | if (!mounted) | 1024 | if (!mounted) |
1011 | break; | 1025 | break; |
1012 | path->mnt = mounted; | 1026 | path->mnt = mounted; |
1013 | path->dentry = mounted->mnt_root; | 1027 | path->dentry = mounted->mnt_root; |
1014 | nd->seq = read_seqcount_begin(&path->dentry->d_seq); | 1028 | nd->seq = read_seqcount_begin(&path->dentry->d_seq); |
1015 | *inode = path->dentry->d_inode; | ||
1016 | } | 1029 | } |
1017 | 1030 | ||
1018 | if (unlikely(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT)) | 1031 | if (unlikely(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT)) |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index abdf38d5971d..7237672216c8 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -44,6 +44,7 @@ | |||
44 | /* #define NFS_DEBUG_VERBOSE 1 */ | 44 | /* #define NFS_DEBUG_VERBOSE 1 */ |
45 | 45 | ||
46 | static int nfs_opendir(struct inode *, struct file *); | 46 | static int nfs_opendir(struct inode *, struct file *); |
47 | static int nfs_closedir(struct inode *, struct file *); | ||
47 | static int nfs_readdir(struct file *, void *, filldir_t); | 48 | static int nfs_readdir(struct file *, void *, filldir_t); |
48 | static struct dentry *nfs_lookup(struct inode *, struct dentry *, struct nameidata *); | 49 | static struct dentry *nfs_lookup(struct inode *, struct dentry *, struct nameidata *); |
49 | static int nfs_create(struct inode *, struct dentry *, int, struct nameidata *); | 50 | static int nfs_create(struct inode *, struct dentry *, int, struct nameidata *); |
@@ -64,7 +65,7 @@ const struct file_operations nfs_dir_operations = { | |||
64 | .read = generic_read_dir, | 65 | .read = generic_read_dir, |
65 | .readdir = nfs_readdir, | 66 | .readdir = nfs_readdir, |
66 | .open = nfs_opendir, | 67 | .open = nfs_opendir, |
67 | .release = nfs_release, | 68 | .release = nfs_closedir, |
68 | .fsync = nfs_fsync_dir, | 69 | .fsync = nfs_fsync_dir, |
69 | }; | 70 | }; |
70 | 71 | ||
@@ -133,13 +134,35 @@ const struct inode_operations nfs4_dir_inode_operations = { | |||
133 | 134 | ||
134 | #endif /* CONFIG_NFS_V4 */ | 135 | #endif /* CONFIG_NFS_V4 */ |
135 | 136 | ||
137 | static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct rpc_cred *cred) | ||
138 | { | ||
139 | struct nfs_open_dir_context *ctx; | ||
140 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); | ||
141 | if (ctx != NULL) { | ||
142 | ctx->duped = 0; | ||
143 | ctx->dir_cookie = 0; | ||
144 | ctx->dup_cookie = 0; | ||
145 | ctx->cred = get_rpccred(cred); | ||
146 | } else | ||
147 | ctx = ERR_PTR(-ENOMEM); | ||
148 | return ctx; | ||
149 | } | ||
150 | |||
151 | static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx) | ||
152 | { | ||
153 | put_rpccred(ctx->cred); | ||
154 | kfree(ctx); | ||
155 | } | ||
156 | |||
136 | /* | 157 | /* |
137 | * Open file | 158 | * Open file |
138 | */ | 159 | */ |
139 | static int | 160 | static int |
140 | nfs_opendir(struct inode *inode, struct file *filp) | 161 | nfs_opendir(struct inode *inode, struct file *filp) |
141 | { | 162 | { |
142 | int res; | 163 | int res = 0; |
164 | struct nfs_open_dir_context *ctx; | ||
165 | struct rpc_cred *cred; | ||
143 | 166 | ||
144 | dfprintk(FILE, "NFS: open dir(%s/%s)\n", | 167 | dfprintk(FILE, "NFS: open dir(%s/%s)\n", |
145 | filp->f_path.dentry->d_parent->d_name.name, | 168 | filp->f_path.dentry->d_parent->d_name.name, |
@@ -147,8 +170,15 @@ nfs_opendir(struct inode *inode, struct file *filp) | |||
147 | 170 | ||
148 | nfs_inc_stats(inode, NFSIOS_VFSOPEN); | 171 | nfs_inc_stats(inode, NFSIOS_VFSOPEN); |
149 | 172 | ||
150 | /* Call generic open code in order to cache credentials */ | 173 | cred = rpc_lookup_cred(); |
151 | res = nfs_open(inode, filp); | 174 | if (IS_ERR(cred)) |
175 | return PTR_ERR(cred); | ||
176 | ctx = alloc_nfs_open_dir_context(cred); | ||
177 | if (IS_ERR(ctx)) { | ||
178 | res = PTR_ERR(ctx); | ||
179 | goto out; | ||
180 | } | ||
181 | filp->private_data = ctx; | ||
152 | if (filp->f_path.dentry == filp->f_path.mnt->mnt_root) { | 182 | if (filp->f_path.dentry == filp->f_path.mnt->mnt_root) { |
153 | /* This is a mountpoint, so d_revalidate will never | 183 | /* This is a mountpoint, so d_revalidate will never |
154 | * have been called, so we need to refresh the | 184 | * have been called, so we need to refresh the |
@@ -156,9 +186,18 @@ nfs_opendir(struct inode *inode, struct file *filp) | |||
156 | */ | 186 | */ |
157 | __nfs_revalidate_inode(NFS_SERVER(inode), inode); | 187 | __nfs_revalidate_inode(NFS_SERVER(inode), inode); |
158 | } | 188 | } |
189 | out: | ||
190 | put_rpccred(cred); | ||
159 | return res; | 191 | return res; |
160 | } | 192 | } |
161 | 193 | ||
194 | static int | ||
195 | nfs_closedir(struct inode *inode, struct file *filp) | ||
196 | { | ||
197 | put_nfs_open_dir_context(filp->private_data); | ||
198 | return 0; | ||
199 | } | ||
200 | |||
162 | struct nfs_cache_array_entry { | 201 | struct nfs_cache_array_entry { |
163 | u64 cookie; | 202 | u64 cookie; |
164 | u64 ino; | 203 | u64 ino; |
@@ -284,19 +323,20 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri | |||
284 | { | 323 | { |
285 | loff_t diff = desc->file->f_pos - desc->current_index; | 324 | loff_t diff = desc->file->f_pos - desc->current_index; |
286 | unsigned int index; | 325 | unsigned int index; |
326 | struct nfs_open_dir_context *ctx = desc->file->private_data; | ||
287 | 327 | ||
288 | if (diff < 0) | 328 | if (diff < 0) |
289 | goto out_eof; | 329 | goto out_eof; |
290 | if (diff >= array->size) { | 330 | if (diff >= array->size) { |
291 | if (array->eof_index >= 0) | 331 | if (array->eof_index >= 0) |
292 | goto out_eof; | 332 | goto out_eof; |
293 | desc->current_index += array->size; | ||
294 | return -EAGAIN; | 333 | return -EAGAIN; |
295 | } | 334 | } |
296 | 335 | ||
297 | index = (unsigned int)diff; | 336 | index = (unsigned int)diff; |
298 | *desc->dir_cookie = array->array[index].cookie; | 337 | *desc->dir_cookie = array->array[index].cookie; |
299 | desc->cache_entry_index = index; | 338 | desc->cache_entry_index = index; |
339 | ctx->duped = 0; | ||
300 | return 0; | 340 | return 0; |
301 | out_eof: | 341 | out_eof: |
302 | desc->eof = 1; | 342 | desc->eof = 1; |
@@ -307,10 +347,18 @@ static | |||
307 | int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc) | 347 | int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc) |
308 | { | 348 | { |
309 | int i; | 349 | int i; |
350 | loff_t new_pos; | ||
310 | int status = -EAGAIN; | 351 | int status = -EAGAIN; |
352 | struct nfs_open_dir_context *ctx = desc->file->private_data; | ||
311 | 353 | ||
312 | for (i = 0; i < array->size; i++) { | 354 | for (i = 0; i < array->size; i++) { |
313 | if (array->array[i].cookie == *desc->dir_cookie) { | 355 | if (array->array[i].cookie == *desc->dir_cookie) { |
356 | new_pos = desc->current_index + i; | ||
357 | if (new_pos < desc->file->f_pos) { | ||
358 | ctx->dup_cookie = *desc->dir_cookie; | ||
359 | ctx->duped = 1; | ||
360 | } | ||
361 | desc->file->f_pos = new_pos; | ||
314 | desc->cache_entry_index = i; | 362 | desc->cache_entry_index = i; |
315 | return 0; | 363 | return 0; |
316 | } | 364 | } |
@@ -342,6 +390,7 @@ int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc) | |||
342 | 390 | ||
343 | if (status == -EAGAIN) { | 391 | if (status == -EAGAIN) { |
344 | desc->last_cookie = array->last_cookie; | 392 | desc->last_cookie = array->last_cookie; |
393 | desc->current_index += array->size; | ||
345 | desc->page_index++; | 394 | desc->page_index++; |
346 | } | 395 | } |
347 | nfs_readdir_release_array(desc->page); | 396 | nfs_readdir_release_array(desc->page); |
@@ -354,7 +403,8 @@ static | |||
354 | int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc, | 403 | int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc, |
355 | struct nfs_entry *entry, struct file *file, struct inode *inode) | 404 | struct nfs_entry *entry, struct file *file, struct inode *inode) |
356 | { | 405 | { |
357 | struct rpc_cred *cred = nfs_file_cred(file); | 406 | struct nfs_open_dir_context *ctx = file->private_data; |
407 | struct rpc_cred *cred = ctx->cred; | ||
358 | unsigned long timestamp, gencount; | 408 | unsigned long timestamp, gencount; |
359 | int error; | 409 | int error; |
360 | 410 | ||
@@ -693,6 +743,20 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
693 | int i = 0; | 743 | int i = 0; |
694 | int res = 0; | 744 | int res = 0; |
695 | struct nfs_cache_array *array = NULL; | 745 | struct nfs_cache_array *array = NULL; |
746 | struct nfs_open_dir_context *ctx = file->private_data; | ||
747 | |||
748 | if (ctx->duped != 0 && ctx->dup_cookie == *desc->dir_cookie) { | ||
749 | if (printk_ratelimit()) { | ||
750 | pr_notice("NFS: directory %s/%s contains a readdir loop. " | ||
751 | "Please contact your server vendor. " | ||
752 | "Offending cookie: %llu\n", | ||
753 | file->f_dentry->d_parent->d_name.name, | ||
754 | file->f_dentry->d_name.name, | ||
755 | *desc->dir_cookie); | ||
756 | } | ||
757 | res = -ELOOP; | ||
758 | goto out; | ||
759 | } | ||
696 | 760 | ||
697 | array = nfs_readdir_get_array(desc->page); | 761 | array = nfs_readdir_get_array(desc->page); |
698 | if (IS_ERR(array)) { | 762 | if (IS_ERR(array)) { |
@@ -785,6 +849,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
785 | struct inode *inode = dentry->d_inode; | 849 | struct inode *inode = dentry->d_inode; |
786 | nfs_readdir_descriptor_t my_desc, | 850 | nfs_readdir_descriptor_t my_desc, |
787 | *desc = &my_desc; | 851 | *desc = &my_desc; |
852 | struct nfs_open_dir_context *dir_ctx = filp->private_data; | ||
788 | int res; | 853 | int res; |
789 | 854 | ||
790 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", | 855 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", |
@@ -801,7 +866,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
801 | memset(desc, 0, sizeof(*desc)); | 866 | memset(desc, 0, sizeof(*desc)); |
802 | 867 | ||
803 | desc->file = filp; | 868 | desc->file = filp; |
804 | desc->dir_cookie = &nfs_file_open_context(filp)->dir_cookie; | 869 | desc->dir_cookie = &dir_ctx->dir_cookie; |
805 | desc->decode = NFS_PROTO(inode)->decode_dirent; | 870 | desc->decode = NFS_PROTO(inode)->decode_dirent; |
806 | desc->plus = NFS_USE_READDIRPLUS(inode); | 871 | desc->plus = NFS_USE_READDIRPLUS(inode); |
807 | 872 | ||
@@ -853,6 +918,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) | |||
853 | { | 918 | { |
854 | struct dentry *dentry = filp->f_path.dentry; | 919 | struct dentry *dentry = filp->f_path.dentry; |
855 | struct inode *inode = dentry->d_inode; | 920 | struct inode *inode = dentry->d_inode; |
921 | struct nfs_open_dir_context *dir_ctx = filp->private_data; | ||
856 | 922 | ||
857 | dfprintk(FILE, "NFS: llseek dir(%s/%s, %lld, %d)\n", | 923 | dfprintk(FILE, "NFS: llseek dir(%s/%s, %lld, %d)\n", |
858 | dentry->d_parent->d_name.name, | 924 | dentry->d_parent->d_name.name, |
@@ -872,7 +938,8 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin) | |||
872 | } | 938 | } |
873 | if (offset != filp->f_pos) { | 939 | if (offset != filp->f_pos) { |
874 | filp->f_pos = offset; | 940 | filp->f_pos = offset; |
875 | nfs_file_open_context(filp)->dir_cookie = 0; | 941 | dir_ctx->dir_cookie = 0; |
942 | dir_ctx->duped = 0; | ||
876 | } | 943 | } |
877 | out: | 944 | out: |
878 | mutex_unlock(&inode->i_mutex); | 945 | mutex_unlock(&inode->i_mutex); |
@@ -1068,7 +1135,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
1068 | if (fhandle == NULL || fattr == NULL) | 1135 | if (fhandle == NULL || fattr == NULL) |
1069 | goto out_error; | 1136 | goto out_error; |
1070 | 1137 | ||
1071 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); | 1138 | error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr); |
1072 | if (error) | 1139 | if (error) |
1073 | goto out_bad; | 1140 | goto out_bad; |
1074 | if (nfs_compare_fh(NFS_FH(inode), fhandle)) | 1141 | if (nfs_compare_fh(NFS_FH(inode), fhandle)) |
@@ -1224,7 +1291,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
1224 | parent = dentry->d_parent; | 1291 | parent = dentry->d_parent; |
1225 | /* Protect against concurrent sillydeletes */ | 1292 | /* Protect against concurrent sillydeletes */ |
1226 | nfs_block_sillyrename(parent); | 1293 | nfs_block_sillyrename(parent); |
1227 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); | 1294 | error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr); |
1228 | if (error == -ENOENT) | 1295 | if (error == -ENOENT) |
1229 | goto no_entry; | 1296 | goto no_entry; |
1230 | if (error < 0) { | 1297 | if (error < 0) { |
@@ -1562,7 +1629,7 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, | |||
1562 | if (dentry->d_inode) | 1629 | if (dentry->d_inode) |
1563 | goto out; | 1630 | goto out; |
1564 | if (fhandle->size == 0) { | 1631 | if (fhandle->size == 0) { |
1565 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); | 1632 | error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr); |
1566 | if (error) | 1633 | if (error) |
1567 | goto out_error; | 1634 | goto out_error; |
1568 | } | 1635 | } |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index d85a534b15cd..3ac5bd695e5e 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -326,6 +326,9 @@ nfs_file_fsync(struct file *file, int datasync) | |||
326 | ret = xchg(&ctx->error, 0); | 326 | ret = xchg(&ctx->error, 0); |
327 | if (!ret && status < 0) | 327 | if (!ret && status < 0) |
328 | ret = status; | 328 | ret = status; |
329 | if (!ret && !datasync) | ||
330 | /* application has asked for meta-data sync */ | ||
331 | ret = pnfs_layoutcommit_inode(inode, true); | ||
329 | return ret; | 332 | return ret; |
330 | } | 333 | } |
331 | 334 | ||
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 1084792bc0fe..dcb61548887f 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c | |||
@@ -222,6 +222,10 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh, | |||
222 | goto out; | 222 | goto out; |
223 | } | 223 | } |
224 | 224 | ||
225 | if (fattr->valid & NFS_ATTR_FATTR_FSID && | ||
226 | !nfs_fsid_equal(&server->fsid, &fattr->fsid)) | ||
227 | memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid)); | ||
228 | |||
225 | inode = nfs_fhget(sb, mntfh, fattr); | 229 | inode = nfs_fhget(sb, mntfh, fattr); |
226 | if (IS_ERR(inode)) { | 230 | if (IS_ERR(inode)) { |
227 | dprintk("nfs_get_root: get root inode failed\n"); | 231 | dprintk("nfs_get_root: get root inode failed\n"); |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 01768e5e2c9b..57bb31ad7a5e 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -254,7 +254,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
254 | struct inode *inode = ERR_PTR(-ENOENT); | 254 | struct inode *inode = ERR_PTR(-ENOENT); |
255 | unsigned long hash; | 255 | unsigned long hash; |
256 | 256 | ||
257 | if ((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0) | 257 | nfs_attr_check_mountpoint(sb, fattr); |
258 | |||
259 | if ((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0 && (fattr->valid & NFS_ATTR_FATTR_MOUNTPOINT) == 0) | ||
258 | goto out_no_inode; | 260 | goto out_no_inode; |
259 | if ((fattr->valid & NFS_ATTR_FATTR_TYPE) == 0) | 261 | if ((fattr->valid & NFS_ATTR_FATTR_TYPE) == 0) |
260 | goto out_no_inode; | 262 | goto out_no_inode; |
@@ -298,8 +300,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
298 | if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)) | 300 | if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)) |
299 | set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); | 301 | set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); |
300 | /* Deal with crossing mountpoints */ | 302 | /* Deal with crossing mountpoints */ |
301 | if ((fattr->valid & NFS_ATTR_FATTR_FSID) | 303 | if (fattr->valid & NFS_ATTR_FATTR_MOUNTPOINT || |
302 | && !nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) { | 304 | fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) { |
303 | if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) | 305 | if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) |
304 | inode->i_op = &nfs_referral_inode_operations; | 306 | inode->i_op = &nfs_referral_inode_operations; |
305 | else | 307 | else |
@@ -639,7 +641,6 @@ struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cr | |||
639 | ctx->mode = f_mode; | 641 | ctx->mode = f_mode; |
640 | ctx->flags = 0; | 642 | ctx->flags = 0; |
641 | ctx->error = 0; | 643 | ctx->error = 0; |
642 | ctx->dir_cookie = 0; | ||
643 | nfs_init_lock_context(&ctx->lock_context); | 644 | nfs_init_lock_context(&ctx->lock_context); |
644 | ctx->lock_context.open_context = ctx; | 645 | ctx->lock_context.open_context = ctx; |
645 | INIT_LIST_HEAD(&ctx->list); | 646 | INIT_LIST_HEAD(&ctx->list); |
@@ -1471,6 +1472,7 @@ static inline void nfs4_init_once(struct nfs_inode *nfsi) | |||
1471 | nfsi->delegation_state = 0; | 1472 | nfsi->delegation_state = 0; |
1472 | init_rwsem(&nfsi->rwsem); | 1473 | init_rwsem(&nfsi->rwsem); |
1473 | nfsi->layout = NULL; | 1474 | nfsi->layout = NULL; |
1475 | atomic_set(&nfsi->commits_outstanding, 0); | ||
1474 | #endif | 1476 | #endif |
1475 | } | 1477 | } |
1476 | 1478 | ||
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 72e0bddf7a2f..ce118ce885dd 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -39,6 +39,12 @@ static inline int nfs4_has_persistent_session(const struct nfs_client *clp) | |||
39 | return 0; | 39 | return 0; |
40 | } | 40 | } |
41 | 41 | ||
42 | static inline void nfs_attr_check_mountpoint(struct super_block *parent, struct nfs_fattr *fattr) | ||
43 | { | ||
44 | if (!nfs_fsid_equal(&NFS_SB(parent)->fsid, &fattr->fsid)) | ||
45 | fattr->valid |= NFS_ATTR_FATTR_MOUNTPOINT; | ||
46 | } | ||
47 | |||
42 | struct nfs_clone_mount { | 48 | struct nfs_clone_mount { |
43 | const struct super_block *sb; | 49 | const struct super_block *sb; |
44 | const struct dentry *dentry; | 50 | const struct dentry *dentry; |
@@ -214,6 +220,7 @@ extern const u32 nfs41_maxwrite_overhead; | |||
214 | /* nfs4proc.c */ | 220 | /* nfs4proc.c */ |
215 | #ifdef CONFIG_NFS_V4 | 221 | #ifdef CONFIG_NFS_V4 |
216 | extern struct rpc_procinfo nfs4_procedures[]; | 222 | extern struct rpc_procinfo nfs4_procedures[]; |
223 | void nfs_fixup_secinfo_attributes(struct nfs_fattr *, struct nfs_fh *); | ||
217 | #endif | 224 | #endif |
218 | 225 | ||
219 | extern int nfs4_init_ds_session(struct nfs_client *clp); | 226 | extern int nfs4_init_ds_session(struct nfs_client *clp); |
@@ -276,11 +283,25 @@ extern int nfs_initiate_read(struct nfs_read_data *data, struct rpc_clnt *clnt, | |||
276 | extern void nfs_read_prepare(struct rpc_task *task, void *calldata); | 283 | extern void nfs_read_prepare(struct rpc_task *task, void *calldata); |
277 | 284 | ||
278 | /* write.c */ | 285 | /* write.c */ |
286 | extern void nfs_commit_free(struct nfs_write_data *p); | ||
279 | extern int nfs_initiate_write(struct nfs_write_data *data, | 287 | extern int nfs_initiate_write(struct nfs_write_data *data, |
280 | struct rpc_clnt *clnt, | 288 | struct rpc_clnt *clnt, |
281 | const struct rpc_call_ops *call_ops, | 289 | const struct rpc_call_ops *call_ops, |
282 | int how); | 290 | int how); |
283 | extern void nfs_write_prepare(struct rpc_task *task, void *calldata); | 291 | extern void nfs_write_prepare(struct rpc_task *task, void *calldata); |
292 | extern int nfs_initiate_commit(struct nfs_write_data *data, | ||
293 | struct rpc_clnt *clnt, | ||
294 | const struct rpc_call_ops *call_ops, | ||
295 | int how); | ||
296 | extern void nfs_init_commit(struct nfs_write_data *data, | ||
297 | struct list_head *head, | ||
298 | struct pnfs_layout_segment *lseg); | ||
299 | void nfs_retry_commit(struct list_head *page_list, | ||
300 | struct pnfs_layout_segment *lseg); | ||
301 | void nfs_commit_clear_lock(struct nfs_inode *nfsi); | ||
302 | void nfs_commitdata_release(void *data); | ||
303 | void nfs_commit_release_pages(struct nfs_write_data *data); | ||
304 | |||
284 | #ifdef CONFIG_MIGRATION | 305 | #ifdef CONFIG_MIGRATION |
285 | extern int nfs_migrate_page(struct address_space *, | 306 | extern int nfs_migrate_page(struct address_space *, |
286 | struct page *, struct page *); | 307 | struct page *, struct page *); |
@@ -296,12 +317,14 @@ extern int nfs4_init_client(struct nfs_client *clp, | |||
296 | rpc_authflavor_t authflavour, | 317 | rpc_authflavor_t authflavour, |
297 | int noresvport); | 318 | int noresvport); |
298 | extern void nfs4_reset_write(struct rpc_task *task, struct nfs_write_data *data); | 319 | extern void nfs4_reset_write(struct rpc_task *task, struct nfs_write_data *data); |
299 | extern int _nfs4_call_sync(struct nfs_server *server, | 320 | extern int _nfs4_call_sync(struct rpc_clnt *clnt, |
321 | struct nfs_server *server, | ||
300 | struct rpc_message *msg, | 322 | struct rpc_message *msg, |
301 | struct nfs4_sequence_args *args, | 323 | struct nfs4_sequence_args *args, |
302 | struct nfs4_sequence_res *res, | 324 | struct nfs4_sequence_res *res, |
303 | int cache_reply); | 325 | int cache_reply); |
304 | extern int _nfs4_call_sync_session(struct nfs_server *server, | 326 | extern int _nfs4_call_sync_session(struct rpc_clnt *clnt, |
327 | struct nfs_server *server, | ||
305 | struct rpc_message *msg, | 328 | struct rpc_message *msg, |
306 | struct nfs4_sequence_args *args, | 329 | struct nfs4_sequence_args *args, |
307 | struct nfs4_sequence_res *res, | 330 | struct nfs4_sequence_res *res, |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index bf1c68009ffd..ad92bf731ff5 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/string.h> | 15 | #include <linux/string.h> |
16 | #include <linux/sunrpc/clnt.h> | 16 | #include <linux/sunrpc/clnt.h> |
17 | #include <linux/vfs.h> | 17 | #include <linux/vfs.h> |
18 | #include <linux/sunrpc/gss_api.h> | ||
18 | #include "internal.h" | 19 | #include "internal.h" |
19 | 20 | ||
20 | #define NFSDBG_FACILITY NFSDBG_VFS | 21 | #define NFSDBG_FACILITY NFSDBG_VFS |
@@ -27,7 +28,8 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ; | |||
27 | 28 | ||
28 | static struct vfsmount *nfs_do_submount(struct dentry *dentry, | 29 | static struct vfsmount *nfs_do_submount(struct dentry *dentry, |
29 | struct nfs_fh *fh, | 30 | struct nfs_fh *fh, |
30 | struct nfs_fattr *fattr); | 31 | struct nfs_fattr *fattr, |
32 | rpc_authflavor_t authflavor); | ||
31 | 33 | ||
32 | /* | 34 | /* |
33 | * nfs_path - reconstruct the path given an arbitrary dentry | 35 | * nfs_path - reconstruct the path given an arbitrary dentry |
@@ -116,6 +118,100 @@ Elong: | |||
116 | return ERR_PTR(-ENAMETOOLONG); | 118 | return ERR_PTR(-ENAMETOOLONG); |
117 | } | 119 | } |
118 | 120 | ||
121 | #ifdef CONFIG_NFS_V4 | ||
122 | static rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors, struct inode *inode) | ||
123 | { | ||
124 | struct gss_api_mech *mech; | ||
125 | struct xdr_netobj oid; | ||
126 | int i; | ||
127 | rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX; | ||
128 | |||
129 | for (i = 0; i < flavors->num_flavors; i++) { | ||
130 | struct nfs4_secinfo_flavor *flavor; | ||
131 | flavor = &flavors->flavors[i]; | ||
132 | |||
133 | if (flavor->flavor == RPC_AUTH_NULL || flavor->flavor == RPC_AUTH_UNIX) { | ||
134 | pseudoflavor = flavor->flavor; | ||
135 | break; | ||
136 | } else if (flavor->flavor == RPC_AUTH_GSS) { | ||
137 | oid.len = flavor->gss.sec_oid4.len; | ||
138 | oid.data = flavor->gss.sec_oid4.data; | ||
139 | mech = gss_mech_get_by_OID(&oid); | ||
140 | if (!mech) | ||
141 | continue; | ||
142 | pseudoflavor = gss_svc_to_pseudoflavor(mech, flavor->gss.service); | ||
143 | gss_mech_put(mech); | ||
144 | break; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | return pseudoflavor; | ||
149 | } | ||
150 | |||
151 | static rpc_authflavor_t nfs_negotiate_security(const struct dentry *parent, const struct dentry *dentry) | ||
152 | { | ||
153 | int status = 0; | ||
154 | struct page *page; | ||
155 | struct nfs4_secinfo_flavors *flavors; | ||
156 | int (*secinfo)(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); | ||
157 | rpc_authflavor_t flavor = RPC_AUTH_UNIX; | ||
158 | |||
159 | secinfo = NFS_PROTO(parent->d_inode)->secinfo; | ||
160 | if (secinfo != NULL) { | ||
161 | page = alloc_page(GFP_KERNEL); | ||
162 | if (!page) { | ||
163 | status = -ENOMEM; | ||
164 | goto out; | ||
165 | } | ||
166 | flavors = page_address(page); | ||
167 | status = secinfo(parent->d_inode, &dentry->d_name, flavors); | ||
168 | flavor = nfs_find_best_sec(flavors, dentry->d_inode); | ||
169 | put_page(page); | ||
170 | } | ||
171 | |||
172 | return flavor; | ||
173 | |||
174 | out: | ||
175 | status = -ENOMEM; | ||
176 | return status; | ||
177 | } | ||
178 | |||
179 | static rpc_authflavor_t nfs_lookup_with_sec(struct nfs_server *server, struct dentry *parent, | ||
180 | struct dentry *dentry, struct path *path, | ||
181 | struct nfs_fh *fh, struct nfs_fattr *fattr) | ||
182 | { | ||
183 | rpc_authflavor_t flavor; | ||
184 | struct rpc_clnt *clone; | ||
185 | struct rpc_auth *auth; | ||
186 | int err; | ||
187 | |||
188 | flavor = nfs_negotiate_security(parent, path->dentry); | ||
189 | if (flavor < 0) | ||
190 | goto out; | ||
191 | clone = rpc_clone_client(server->client); | ||
192 | auth = rpcauth_create(flavor, clone); | ||
193 | if (!auth) { | ||
194 | flavor = -EIO; | ||
195 | goto out; | ||
196 | } | ||
197 | err = server->nfs_client->rpc_ops->lookup(clone, parent->d_inode, | ||
198 | &path->dentry->d_name, | ||
199 | fh, fattr); | ||
200 | if (err < 0) | ||
201 | flavor = err; | ||
202 | out: | ||
203 | return flavor; | ||
204 | } | ||
205 | #else /* CONFIG_NFS_V4 */ | ||
206 | static inline rpc_authflavor_t nfs_lookup_with_sec(struct nfs_server *server, | ||
207 | struct dentry *parent, struct dentry *dentry, | ||
208 | struct path *path, struct nfs_fh *fh, | ||
209 | struct nfs_fattr *fattr) | ||
210 | { | ||
211 | return -EPERM; | ||
212 | } | ||
213 | #endif /* CONFIG_NFS_V4 */ | ||
214 | |||
119 | /* | 215 | /* |
120 | * nfs_d_automount - Handle crossing a mountpoint on the server | 216 | * nfs_d_automount - Handle crossing a mountpoint on the server |
121 | * @path - The mountpoint | 217 | * @path - The mountpoint |
@@ -136,6 +232,7 @@ struct vfsmount *nfs_d_automount(struct path *path) | |||
136 | struct nfs_fh *fh = NULL; | 232 | struct nfs_fh *fh = NULL; |
137 | struct nfs_fattr *fattr = NULL; | 233 | struct nfs_fattr *fattr = NULL; |
138 | int err; | 234 | int err; |
235 | rpc_authflavor_t flavor = 1; | ||
139 | 236 | ||
140 | dprintk("--> nfs_d_automount()\n"); | 237 | dprintk("--> nfs_d_automount()\n"); |
141 | 238 | ||
@@ -153,9 +250,16 @@ struct vfsmount *nfs_d_automount(struct path *path) | |||
153 | 250 | ||
154 | /* Look it up again to get its attributes */ | 251 | /* Look it up again to get its attributes */ |
155 | parent = dget_parent(path->dentry); | 252 | parent = dget_parent(path->dentry); |
156 | err = server->nfs_client->rpc_ops->lookup(parent->d_inode, | 253 | err = server->nfs_client->rpc_ops->lookup(server->client, parent->d_inode, |
157 | &path->dentry->d_name, | 254 | &path->dentry->d_name, |
158 | fh, fattr); | 255 | fh, fattr); |
256 | if (err == -EPERM) { | ||
257 | flavor = nfs_lookup_with_sec(server, parent, path->dentry, path, fh, fattr); | ||
258 | if (flavor < 0) | ||
259 | err = flavor; | ||
260 | else | ||
261 | err = 0; | ||
262 | } | ||
159 | dput(parent); | 263 | dput(parent); |
160 | if (err != 0) { | 264 | if (err != 0) { |
161 | mnt = ERR_PTR(err); | 265 | mnt = ERR_PTR(err); |
@@ -165,7 +269,7 @@ struct vfsmount *nfs_d_automount(struct path *path) | |||
165 | if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) | 269 | if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) |
166 | mnt = nfs_do_refmount(path->dentry); | 270 | mnt = nfs_do_refmount(path->dentry); |
167 | else | 271 | else |
168 | mnt = nfs_do_submount(path->dentry, fh, fattr); | 272 | mnt = nfs_do_submount(path->dentry, fh, fattr, flavor); |
169 | if (IS_ERR(mnt)) | 273 | if (IS_ERR(mnt)) |
170 | goto out; | 274 | goto out; |
171 | 275 | ||
@@ -232,17 +336,20 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, | |||
232 | * @dentry - parent directory | 336 | * @dentry - parent directory |
233 | * @fh - filehandle for new root dentry | 337 | * @fh - filehandle for new root dentry |
234 | * @fattr - attributes for new root inode | 338 | * @fattr - attributes for new root inode |
339 | * @authflavor - security flavor to use when performing the mount | ||
235 | * | 340 | * |
236 | */ | 341 | */ |
237 | static struct vfsmount *nfs_do_submount(struct dentry *dentry, | 342 | static struct vfsmount *nfs_do_submount(struct dentry *dentry, |
238 | struct nfs_fh *fh, | 343 | struct nfs_fh *fh, |
239 | struct nfs_fattr *fattr) | 344 | struct nfs_fattr *fattr, |
345 | rpc_authflavor_t authflavor) | ||
240 | { | 346 | { |
241 | struct nfs_clone_mount mountdata = { | 347 | struct nfs_clone_mount mountdata = { |
242 | .sb = dentry->d_sb, | 348 | .sb = dentry->d_sb, |
243 | .dentry = dentry, | 349 | .dentry = dentry, |
244 | .fh = fh, | 350 | .fh = fh, |
245 | .fattr = fattr, | 351 | .fattr = fattr, |
352 | .authflavor = authflavor, | ||
246 | }; | 353 | }; |
247 | struct vfsmount *mnt = ERR_PTR(-ENOMEM); | 354 | struct vfsmount *mnt = ERR_PTR(-ENOMEM); |
248 | char *page = (char *) __get_free_page(GFP_USER); | 355 | char *page = (char *) __get_free_page(GFP_USER); |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index d0c80d8b3f96..38053d823eb0 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -141,7 +141,7 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
141 | } | 141 | } |
142 | 142 | ||
143 | static int | 143 | static int |
144 | nfs3_proc_lookup(struct inode *dir, struct qstr *name, | 144 | nfs3_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qstr *name, |
145 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 145 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
146 | { | 146 | { |
147 | struct nfs3_diropargs arg = { | 147 | struct nfs3_diropargs arg = { |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index c64be1cff080..e1c261ddd65d 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -57,7 +57,8 @@ enum nfs4_session_state { | |||
57 | struct nfs4_minor_version_ops { | 57 | struct nfs4_minor_version_ops { |
58 | u32 minor_version; | 58 | u32 minor_version; |
59 | 59 | ||
60 | int (*call_sync)(struct nfs_server *server, | 60 | int (*call_sync)(struct rpc_clnt *clnt, |
61 | struct nfs_server *server, | ||
61 | struct rpc_message *msg, | 62 | struct rpc_message *msg, |
62 | struct nfs4_sequence_args *args, | 63 | struct nfs4_sequence_args *args, |
63 | struct nfs4_sequence_res *res, | 64 | struct nfs4_sequence_res *res, |
@@ -262,6 +263,8 @@ extern int nfs4_proc_destroy_session(struct nfs4_session *); | |||
262 | extern int nfs4_init_session(struct nfs_server *server); | 263 | extern int nfs4_init_session(struct nfs_server *server); |
263 | extern int nfs4_proc_get_lease_time(struct nfs_client *clp, | 264 | extern int nfs4_proc_get_lease_time(struct nfs_client *clp, |
264 | struct nfs_fsinfo *fsinfo); | 265 | struct nfs_fsinfo *fsinfo); |
266 | extern int nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, | ||
267 | bool sync); | ||
265 | 268 | ||
266 | static inline bool | 269 | static inline bool |
267 | is_ds_only_client(struct nfs_client *clp) | 270 | is_ds_only_client(struct nfs_client *clp) |
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 428558464817..6f8192f4cfc7 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c | |||
@@ -154,6 +154,23 @@ static int filelayout_read_done_cb(struct rpc_task *task, | |||
154 | } | 154 | } |
155 | 155 | ||
156 | /* | 156 | /* |
157 | * We reference the rpc_cred of the first WRITE that triggers the need for | ||
158 | * a LAYOUTCOMMIT, and use it to send the layoutcommit compound. | ||
159 | * rfc5661 is not clear about which credential should be used. | ||
160 | */ | ||
161 | static void | ||
162 | filelayout_set_layoutcommit(struct nfs_write_data *wdata) | ||
163 | { | ||
164 | if (FILELAYOUT_LSEG(wdata->lseg)->commit_through_mds || | ||
165 | wdata->res.verf->committed == NFS_FILE_SYNC) | ||
166 | return; | ||
167 | |||
168 | pnfs_set_layoutcommit(wdata); | ||
169 | dprintk("%s ionde %lu pls_end_pos %lu\n", __func__, wdata->inode->i_ino, | ||
170 | (unsigned long) wdata->lseg->pls_end_pos); | ||
171 | } | ||
172 | |||
173 | /* | ||
157 | * Call ops for the async read/write cases | 174 | * Call ops for the async read/write cases |
158 | * In the case of dense layouts, the offset needs to be reset to its | 175 | * In the case of dense layouts, the offset needs to be reset to its |
159 | * original value. | 176 | * original value. |
@@ -210,6 +227,38 @@ static int filelayout_write_done_cb(struct rpc_task *task, | |||
210 | return -EAGAIN; | 227 | return -EAGAIN; |
211 | } | 228 | } |
212 | 229 | ||
230 | filelayout_set_layoutcommit(data); | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | /* Fake up some data that will cause nfs_commit_release to retry the writes. */ | ||
235 | static void prepare_to_resend_writes(struct nfs_write_data *data) | ||
236 | { | ||
237 | struct nfs_page *first = nfs_list_entry(data->pages.next); | ||
238 | |||
239 | data->task.tk_status = 0; | ||
240 | memcpy(data->verf.verifier, first->wb_verf.verifier, | ||
241 | sizeof(first->wb_verf.verifier)); | ||
242 | data->verf.verifier[0]++; /* ensure verifier mismatch */ | ||
243 | } | ||
244 | |||
245 | static int filelayout_commit_done_cb(struct rpc_task *task, | ||
246 | struct nfs_write_data *data) | ||
247 | { | ||
248 | int reset = 0; | ||
249 | |||
250 | if (filelayout_async_handle_error(task, data->args.context->state, | ||
251 | data->ds_clp, &reset) == -EAGAIN) { | ||
252 | dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n", | ||
253 | __func__, data->ds_clp, data->ds_clp->cl_session); | ||
254 | if (reset) { | ||
255 | prepare_to_resend_writes(data); | ||
256 | filelayout_set_lo_fail(data->lseg); | ||
257 | } else | ||
258 | nfs_restart_rpc(task, data->ds_clp); | ||
259 | return -EAGAIN; | ||
260 | } | ||
261 | |||
213 | return 0; | 262 | return 0; |
214 | } | 263 | } |
215 | 264 | ||
@@ -240,6 +289,16 @@ static void filelayout_write_release(void *data) | |||
240 | wdata->mds_ops->rpc_release(data); | 289 | wdata->mds_ops->rpc_release(data); |
241 | } | 290 | } |
242 | 291 | ||
292 | static void filelayout_commit_release(void *data) | ||
293 | { | ||
294 | struct nfs_write_data *wdata = (struct nfs_write_data *)data; | ||
295 | |||
296 | nfs_commit_release_pages(wdata); | ||
297 | if (atomic_dec_and_test(&NFS_I(wdata->inode)->commits_outstanding)) | ||
298 | nfs_commit_clear_lock(NFS_I(wdata->inode)); | ||
299 | nfs_commitdata_release(wdata); | ||
300 | } | ||
301 | |||
243 | struct rpc_call_ops filelayout_read_call_ops = { | 302 | struct rpc_call_ops filelayout_read_call_ops = { |
244 | .rpc_call_prepare = filelayout_read_prepare, | 303 | .rpc_call_prepare = filelayout_read_prepare, |
245 | .rpc_call_done = filelayout_read_call_done, | 304 | .rpc_call_done = filelayout_read_call_done, |
@@ -252,6 +311,12 @@ struct rpc_call_ops filelayout_write_call_ops = { | |||
252 | .rpc_release = filelayout_write_release, | 311 | .rpc_release = filelayout_write_release, |
253 | }; | 312 | }; |
254 | 313 | ||
314 | struct rpc_call_ops filelayout_commit_call_ops = { | ||
315 | .rpc_call_prepare = filelayout_write_prepare, | ||
316 | .rpc_call_done = filelayout_write_call_done, | ||
317 | .rpc_release = filelayout_commit_release, | ||
318 | }; | ||
319 | |||
255 | static enum pnfs_try_status | 320 | static enum pnfs_try_status |
256 | filelayout_read_pagelist(struct nfs_read_data *data) | 321 | filelayout_read_pagelist(struct nfs_read_data *data) |
257 | { | 322 | { |
@@ -320,10 +385,6 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync) | |||
320 | data->inode->i_ino, sync, (size_t) data->args.count, offset, | 385 | data->inode->i_ino, sync, (size_t) data->args.count, offset, |
321 | ntohl(ds->ds_ip_addr), ntohs(ds->ds_port)); | 386 | ntohl(ds->ds_ip_addr), ntohs(ds->ds_port)); |
322 | 387 | ||
323 | /* We can't handle commit to ds yet */ | ||
324 | if (!FILELAYOUT_LSEG(lseg)->commit_through_mds) | ||
325 | data->args.stable = NFS_FILE_SYNC; | ||
326 | |||
327 | data->write_done_cb = filelayout_write_done_cb; | 388 | data->write_done_cb = filelayout_write_done_cb; |
328 | data->ds_clp = ds->ds_clp; | 389 | data->ds_clp = ds->ds_clp; |
329 | fh = nfs4_fl_select_ds_fh(lseg, j); | 390 | fh = nfs4_fl_select_ds_fh(lseg, j); |
@@ -441,12 +502,33 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo, | |||
441 | struct nfs4_layoutget_res *lgr, | 502 | struct nfs4_layoutget_res *lgr, |
442 | struct nfs4_deviceid *id) | 503 | struct nfs4_deviceid *id) |
443 | { | 504 | { |
444 | uint32_t *p = (uint32_t *)lgr->layout.buf; | 505 | struct xdr_stream stream; |
506 | struct xdr_buf buf = { | ||
507 | .pages = lgr->layoutp->pages, | ||
508 | .page_len = lgr->layoutp->len, | ||
509 | .buflen = lgr->layoutp->len, | ||
510 | .len = lgr->layoutp->len, | ||
511 | }; | ||
512 | struct page *scratch; | ||
513 | __be32 *p; | ||
445 | uint32_t nfl_util; | 514 | uint32_t nfl_util; |
446 | int i; | 515 | int i; |
447 | 516 | ||
448 | dprintk("%s: set_layout_map Begin\n", __func__); | 517 | dprintk("%s: set_layout_map Begin\n", __func__); |
449 | 518 | ||
519 | scratch = alloc_page(GFP_KERNEL); | ||
520 | if (!scratch) | ||
521 | return -ENOMEM; | ||
522 | |||
523 | xdr_init_decode(&stream, &buf, NULL); | ||
524 | xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE); | ||
525 | |||
526 | /* 20 = ufl_util (4), first_stripe_index (4), pattern_offset (8), | ||
527 | * num_fh (4) */ | ||
528 | p = xdr_inline_decode(&stream, NFS4_DEVICEID4_SIZE + 20); | ||
529 | if (unlikely(!p)) | ||
530 | goto out_err; | ||
531 | |||
450 | memcpy(id, p, sizeof(*id)); | 532 | memcpy(id, p, sizeof(*id)); |
451 | p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE); | 533 | p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE); |
452 | print_deviceid(id); | 534 | print_deviceid(id); |
@@ -468,32 +550,57 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo, | |||
468 | __func__, nfl_util, fl->num_fh, fl->first_stripe_index, | 550 | __func__, nfl_util, fl->num_fh, fl->first_stripe_index, |
469 | fl->pattern_offset); | 551 | fl->pattern_offset); |
470 | 552 | ||
553 | if (!fl->num_fh) | ||
554 | goto out_err; | ||
555 | |||
471 | fl->fh_array = kzalloc(fl->num_fh * sizeof(struct nfs_fh *), | 556 | fl->fh_array = kzalloc(fl->num_fh * sizeof(struct nfs_fh *), |
472 | GFP_KERNEL); | 557 | GFP_KERNEL); |
473 | if (!fl->fh_array) | 558 | if (!fl->fh_array) |
474 | return -ENOMEM; | 559 | goto out_err; |
475 | 560 | ||
476 | for (i = 0; i < fl->num_fh; i++) { | 561 | for (i = 0; i < fl->num_fh; i++) { |
477 | /* Do we want to use a mempool here? */ | 562 | /* Do we want to use a mempool here? */ |
478 | fl->fh_array[i] = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL); | 563 | fl->fh_array[i] = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL); |
479 | if (!fl->fh_array[i]) { | 564 | if (!fl->fh_array[i]) |
480 | filelayout_free_fh_array(fl); | 565 | goto out_err_free; |
481 | return -ENOMEM; | 566 | |
482 | } | 567 | p = xdr_inline_decode(&stream, 4); |
568 | if (unlikely(!p)) | ||
569 | goto out_err_free; | ||
483 | fl->fh_array[i]->size = be32_to_cpup(p++); | 570 | fl->fh_array[i]->size = be32_to_cpup(p++); |
484 | if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) { | 571 | if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) { |
485 | printk(KERN_ERR "Too big fh %d received %d\n", | 572 | printk(KERN_ERR "Too big fh %d received %d\n", |
486 | i, fl->fh_array[i]->size); | 573 | i, fl->fh_array[i]->size); |
487 | filelayout_free_fh_array(fl); | 574 | goto out_err_free; |
488 | return -EIO; | ||
489 | } | 575 | } |
576 | |||
577 | p = xdr_inline_decode(&stream, fl->fh_array[i]->size); | ||
578 | if (unlikely(!p)) | ||
579 | goto out_err_free; | ||
490 | memcpy(fl->fh_array[i]->data, p, fl->fh_array[i]->size); | 580 | memcpy(fl->fh_array[i]->data, p, fl->fh_array[i]->size); |
491 | p += XDR_QUADLEN(fl->fh_array[i]->size); | ||
492 | dprintk("DEBUG: %s: fh len %d\n", __func__, | 581 | dprintk("DEBUG: %s: fh len %d\n", __func__, |
493 | fl->fh_array[i]->size); | 582 | fl->fh_array[i]->size); |
494 | } | 583 | } |
495 | 584 | ||
585 | __free_page(scratch); | ||
496 | return 0; | 586 | return 0; |
587 | |||
588 | out_err_free: | ||
589 | filelayout_free_fh_array(fl); | ||
590 | out_err: | ||
591 | __free_page(scratch); | ||
592 | return -EIO; | ||
593 | } | ||
594 | |||
595 | static void | ||
596 | filelayout_free_lseg(struct pnfs_layout_segment *lseg) | ||
597 | { | ||
598 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); | ||
599 | |||
600 | dprintk("--> %s\n", __func__); | ||
601 | nfs4_fl_put_deviceid(fl->dsaddr); | ||
602 | kfree(fl->commit_buckets); | ||
603 | _filelayout_free_lseg(fl); | ||
497 | } | 604 | } |
498 | 605 | ||
499 | static struct pnfs_layout_segment * | 606 | static struct pnfs_layout_segment * |
@@ -514,17 +621,28 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid, | |||
514 | _filelayout_free_lseg(fl); | 621 | _filelayout_free_lseg(fl); |
515 | return NULL; | 622 | return NULL; |
516 | } | 623 | } |
517 | return &fl->generic_hdr; | ||
518 | } | ||
519 | 624 | ||
520 | static void | 625 | /* This assumes there is only one IOMODE_RW lseg. What |
521 | filelayout_free_lseg(struct pnfs_layout_segment *lseg) | 626 | * we really want to do is have a layout_hdr level |
522 | { | 627 | * dictionary of <multipath_list4, fh> keys, each |
523 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); | 628 | * associated with a struct list_head, populated by calls |
524 | 629 | * to filelayout_write_pagelist(). | |
525 | dprintk("--> %s\n", __func__); | 630 | * */ |
526 | nfs4_fl_put_deviceid(fl->dsaddr); | 631 | if ((!fl->commit_through_mds) && (lgr->range.iomode == IOMODE_RW)) { |
527 | _filelayout_free_lseg(fl); | 632 | int i; |
633 | int size = (fl->stripe_type == STRIPE_SPARSE) ? | ||
634 | fl->dsaddr->ds_num : fl->dsaddr->stripe_count; | ||
635 | |||
636 | fl->commit_buckets = kcalloc(size, sizeof(struct list_head), GFP_KERNEL); | ||
637 | if (!fl->commit_buckets) { | ||
638 | filelayout_free_lseg(&fl->generic_hdr); | ||
639 | return NULL; | ||
640 | } | ||
641 | fl->number_of_buckets = size; | ||
642 | for (i = 0; i < size; i++) | ||
643 | INIT_LIST_HEAD(&fl->commit_buckets[i]); | ||
644 | } | ||
645 | return &fl->generic_hdr; | ||
528 | } | 646 | } |
529 | 647 | ||
530 | /* | 648 | /* |
@@ -552,6 +670,191 @@ filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, | |||
552 | return (p_stripe == r_stripe); | 670 | return (p_stripe == r_stripe); |
553 | } | 671 | } |
554 | 672 | ||
673 | static bool filelayout_mark_pnfs_commit(struct pnfs_layout_segment *lseg) | ||
674 | { | ||
675 | return !FILELAYOUT_LSEG(lseg)->commit_through_mds; | ||
676 | } | ||
677 | |||
678 | static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j) | ||
679 | { | ||
680 | if (fl->stripe_type == STRIPE_SPARSE) | ||
681 | return nfs4_fl_calc_ds_index(&fl->generic_hdr, j); | ||
682 | else | ||
683 | return j; | ||
684 | } | ||
685 | |||
686 | struct list_head *filelayout_choose_commit_list(struct nfs_page *req) | ||
687 | { | ||
688 | struct pnfs_layout_segment *lseg = req->wb_commit_lseg; | ||
689 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); | ||
690 | u32 i, j; | ||
691 | struct list_head *list; | ||
692 | |||
693 | /* Note that we are calling nfs4_fl_calc_j_index on each page | ||
694 | * that ends up being committed to a data server. An attractive | ||
695 | * alternative is to add a field to nfs_write_data and nfs_page | ||
696 | * to store the value calculated in filelayout_write_pagelist | ||
697 | * and just use that here. | ||
698 | */ | ||
699 | j = nfs4_fl_calc_j_index(lseg, | ||
700 | (loff_t)req->wb_index << PAGE_CACHE_SHIFT); | ||
701 | i = select_bucket_index(fl, j); | ||
702 | list = &fl->commit_buckets[i]; | ||
703 | if (list_empty(list)) { | ||
704 | /* Non-empty buckets hold a reference on the lseg */ | ||
705 | get_lseg(lseg); | ||
706 | } | ||
707 | return list; | ||
708 | } | ||
709 | |||
710 | static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i) | ||
711 | { | ||
712 | struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg); | ||
713 | |||
714 | if (flseg->stripe_type == STRIPE_SPARSE) | ||
715 | return i; | ||
716 | else | ||
717 | return nfs4_fl_calc_ds_index(lseg, i); | ||
718 | } | ||
719 | |||
720 | static struct nfs_fh * | ||
721 | select_ds_fh_from_commit(struct pnfs_layout_segment *lseg, u32 i) | ||
722 | { | ||
723 | struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg); | ||
724 | |||
725 | if (flseg->stripe_type == STRIPE_SPARSE) { | ||
726 | if (flseg->num_fh == 1) | ||
727 | i = 0; | ||
728 | else if (flseg->num_fh == 0) | ||
729 | /* Use the MDS OPEN fh set in nfs_read_rpcsetup */ | ||
730 | return NULL; | ||
731 | } | ||
732 | return flseg->fh_array[i]; | ||
733 | } | ||
734 | |||
735 | static int filelayout_initiate_commit(struct nfs_write_data *data, int how) | ||
736 | { | ||
737 | struct pnfs_layout_segment *lseg = data->lseg; | ||
738 | struct nfs4_pnfs_ds *ds; | ||
739 | u32 idx; | ||
740 | struct nfs_fh *fh; | ||
741 | |||
742 | idx = calc_ds_index_from_commit(lseg, data->ds_commit_index); | ||
743 | ds = nfs4_fl_prepare_ds(lseg, idx); | ||
744 | if (!ds) { | ||
745 | printk(KERN_ERR "%s: prepare_ds failed, use MDS\n", __func__); | ||
746 | set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags); | ||
747 | set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags); | ||
748 | prepare_to_resend_writes(data); | ||
749 | data->mds_ops->rpc_release(data); | ||
750 | return -EAGAIN; | ||
751 | } | ||
752 | dprintk("%s ino %lu, how %d\n", __func__, data->inode->i_ino, how); | ||
753 | data->write_done_cb = filelayout_commit_done_cb; | ||
754 | data->ds_clp = ds->ds_clp; | ||
755 | fh = select_ds_fh_from_commit(lseg, data->ds_commit_index); | ||
756 | if (fh) | ||
757 | data->args.fh = fh; | ||
758 | return nfs_initiate_commit(data, ds->ds_clp->cl_rpcclient, | ||
759 | &filelayout_commit_call_ops, how); | ||
760 | } | ||
761 | |||
762 | /* | ||
763 | * This is only useful while we are using whole file layouts. | ||
764 | */ | ||
765 | static struct pnfs_layout_segment *find_only_write_lseg(struct inode *inode) | ||
766 | { | ||
767 | struct pnfs_layout_segment *lseg, *rv = NULL; | ||
768 | |||
769 | spin_lock(&inode->i_lock); | ||
770 | list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) | ||
771 | if (lseg->pls_range.iomode == IOMODE_RW) | ||
772 | rv = get_lseg(lseg); | ||
773 | spin_unlock(&inode->i_lock); | ||
774 | return rv; | ||
775 | } | ||
776 | |||
777 | static int alloc_ds_commits(struct inode *inode, struct list_head *list) | ||
778 | { | ||
779 | struct pnfs_layout_segment *lseg; | ||
780 | struct nfs4_filelayout_segment *fl; | ||
781 | struct nfs_write_data *data; | ||
782 | int i, j; | ||
783 | |||
784 | /* Won't need this when non-whole file layout segments are supported | ||
785 | * instead we will use a pnfs_layout_hdr structure */ | ||
786 | lseg = find_only_write_lseg(inode); | ||
787 | if (!lseg) | ||
788 | return 0; | ||
789 | fl = FILELAYOUT_LSEG(lseg); | ||
790 | for (i = 0; i < fl->number_of_buckets; i++) { | ||
791 | if (list_empty(&fl->commit_buckets[i])) | ||
792 | continue; | ||
793 | data = nfs_commitdata_alloc(); | ||
794 | if (!data) | ||
795 | goto out_bad; | ||
796 | data->ds_commit_index = i; | ||
797 | data->lseg = lseg; | ||
798 | list_add(&data->pages, list); | ||
799 | } | ||
800 | put_lseg(lseg); | ||
801 | return 0; | ||
802 | |||
803 | out_bad: | ||
804 | for (j = i; j < fl->number_of_buckets; j++) { | ||
805 | if (list_empty(&fl->commit_buckets[i])) | ||
806 | continue; | ||
807 | nfs_retry_commit(&fl->commit_buckets[i], lseg); | ||
808 | put_lseg(lseg); /* associated with emptying bucket */ | ||
809 | } | ||
810 | put_lseg(lseg); | ||
811 | /* Caller will clean up entries put on list */ | ||
812 | return -ENOMEM; | ||
813 | } | ||
814 | |||
815 | /* This follows nfs_commit_list pretty closely */ | ||
816 | static int | ||
817 | filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages, | ||
818 | int how) | ||
819 | { | ||
820 | struct nfs_write_data *data, *tmp; | ||
821 | LIST_HEAD(list); | ||
822 | |||
823 | if (!list_empty(mds_pages)) { | ||
824 | data = nfs_commitdata_alloc(); | ||
825 | if (!data) | ||
826 | goto out_bad; | ||
827 | data->lseg = NULL; | ||
828 | list_add(&data->pages, &list); | ||
829 | } | ||
830 | |||
831 | if (alloc_ds_commits(inode, &list)) | ||
832 | goto out_bad; | ||
833 | |||
834 | list_for_each_entry_safe(data, tmp, &list, pages) { | ||
835 | list_del_init(&data->pages); | ||
836 | atomic_inc(&NFS_I(inode)->commits_outstanding); | ||
837 | if (!data->lseg) { | ||
838 | nfs_init_commit(data, mds_pages, NULL); | ||
839 | nfs_initiate_commit(data, NFS_CLIENT(inode), | ||
840 | data->mds_ops, how); | ||
841 | } else { | ||
842 | nfs_init_commit(data, &FILELAYOUT_LSEG(data->lseg)->commit_buckets[data->ds_commit_index], data->lseg); | ||
843 | filelayout_initiate_commit(data, how); | ||
844 | } | ||
845 | } | ||
846 | return 0; | ||
847 | out_bad: | ||
848 | list_for_each_entry_safe(data, tmp, &list, pages) { | ||
849 | nfs_retry_commit(&data->pages, data->lseg); | ||
850 | list_del_init(&data->pages); | ||
851 | nfs_commit_free(data); | ||
852 | } | ||
853 | nfs_retry_commit(mds_pages, NULL); | ||
854 | nfs_commit_clear_lock(NFS_I(inode)); | ||
855 | return -ENOMEM; | ||
856 | } | ||
857 | |||
555 | static struct pnfs_layoutdriver_type filelayout_type = { | 858 | static struct pnfs_layoutdriver_type filelayout_type = { |
556 | .id = LAYOUT_NFSV4_1_FILES, | 859 | .id = LAYOUT_NFSV4_1_FILES, |
557 | .name = "LAYOUT_NFSV4_1_FILES", | 860 | .name = "LAYOUT_NFSV4_1_FILES", |
@@ -559,6 +862,9 @@ static struct pnfs_layoutdriver_type filelayout_type = { | |||
559 | .alloc_lseg = filelayout_alloc_lseg, | 862 | .alloc_lseg = filelayout_alloc_lseg, |
560 | .free_lseg = filelayout_free_lseg, | 863 | .free_lseg = filelayout_free_lseg, |
561 | .pg_test = filelayout_pg_test, | 864 | .pg_test = filelayout_pg_test, |
865 | .mark_pnfs_commit = filelayout_mark_pnfs_commit, | ||
866 | .choose_commit_list = filelayout_choose_commit_list, | ||
867 | .commit_pagelist = filelayout_commit_pagelist, | ||
562 | .read_pagelist = filelayout_read_pagelist, | 868 | .read_pagelist = filelayout_read_pagelist, |
563 | .write_pagelist = filelayout_write_pagelist, | 869 | .write_pagelist = filelayout_write_pagelist, |
564 | }; | 870 | }; |
diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h index ee0c907742b5..085a354e0f08 100644 --- a/fs/nfs/nfs4filelayout.h +++ b/fs/nfs/nfs4filelayout.h | |||
@@ -79,6 +79,8 @@ struct nfs4_filelayout_segment { | |||
79 | struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */ | 79 | struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */ |
80 | unsigned int num_fh; | 80 | unsigned int num_fh; |
81 | struct nfs_fh **fh_array; | 81 | struct nfs_fh **fh_array; |
82 | struct list_head *commit_buckets; /* Sort commits to ds */ | ||
83 | int number_of_buckets; | ||
82 | }; | 84 | }; |
83 | 85 | ||
84 | static inline struct nfs4_filelayout_segment * | 86 | static inline struct nfs4_filelayout_segment * |
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index 68143c162e3b..de5350f2b249 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c | |||
@@ -261,7 +261,7 @@ out: | |||
261 | * Currently only support ipv4, and one multi-path address. | 261 | * Currently only support ipv4, and one multi-path address. |
262 | */ | 262 | */ |
263 | static struct nfs4_pnfs_ds * | 263 | static struct nfs4_pnfs_ds * |
264 | decode_and_add_ds(__be32 **pp, struct inode *inode) | 264 | decode_and_add_ds(struct xdr_stream *streamp, struct inode *inode) |
265 | { | 265 | { |
266 | struct nfs4_pnfs_ds *ds = NULL; | 266 | struct nfs4_pnfs_ds *ds = NULL; |
267 | char *buf; | 267 | char *buf; |
@@ -269,25 +269,34 @@ decode_and_add_ds(__be32 **pp, struct inode *inode) | |||
269 | u32 ip_addr, port; | 269 | u32 ip_addr, port; |
270 | int nlen, rlen, i; | 270 | int nlen, rlen, i; |
271 | int tmp[2]; | 271 | int tmp[2]; |
272 | __be32 *r_netid, *r_addr, *p = *pp; | 272 | __be32 *p; |
273 | 273 | ||
274 | /* r_netid */ | 274 | /* r_netid */ |
275 | p = xdr_inline_decode(streamp, 4); | ||
276 | if (unlikely(!p)) | ||
277 | goto out_err; | ||
275 | nlen = be32_to_cpup(p++); | 278 | nlen = be32_to_cpup(p++); |
276 | r_netid = p; | ||
277 | p += XDR_QUADLEN(nlen); | ||
278 | 279 | ||
279 | /* r_addr */ | 280 | p = xdr_inline_decode(streamp, nlen); |
280 | rlen = be32_to_cpup(p++); | 281 | if (unlikely(!p)) |
281 | r_addr = p; | 282 | goto out_err; |
282 | p += XDR_QUADLEN(rlen); | ||
283 | *pp = p; | ||
284 | 283 | ||
285 | /* Check that netid is "tcp" */ | 284 | /* Check that netid is "tcp" */ |
286 | if (nlen != 3 || memcmp((char *)r_netid, "tcp", 3)) { | 285 | if (nlen != 3 || memcmp((char *)p, "tcp", 3)) { |
287 | dprintk("%s: ERROR: non ipv4 TCP r_netid\n", __func__); | 286 | dprintk("%s: ERROR: non ipv4 TCP r_netid\n", __func__); |
288 | goto out_err; | 287 | goto out_err; |
289 | } | 288 | } |
290 | 289 | ||
290 | /* r_addr */ | ||
291 | p = xdr_inline_decode(streamp, 4); | ||
292 | if (unlikely(!p)) | ||
293 | goto out_err; | ||
294 | rlen = be32_to_cpup(p); | ||
295 | |||
296 | p = xdr_inline_decode(streamp, rlen); | ||
297 | if (unlikely(!p)) | ||
298 | goto out_err; | ||
299 | |||
291 | /* ipv6 length plus port is legal */ | 300 | /* ipv6 length plus port is legal */ |
292 | if (rlen > INET6_ADDRSTRLEN + 8) { | 301 | if (rlen > INET6_ADDRSTRLEN + 8) { |
293 | dprintk("%s: Invalid address, length %d\n", __func__, | 302 | dprintk("%s: Invalid address, length %d\n", __func__, |
@@ -300,7 +309,7 @@ decode_and_add_ds(__be32 **pp, struct inode *inode) | |||
300 | goto out_err; | 309 | goto out_err; |
301 | } | 310 | } |
302 | buf[rlen] = '\0'; | 311 | buf[rlen] = '\0'; |
303 | memcpy(buf, r_addr, rlen); | 312 | memcpy(buf, p, rlen); |
304 | 313 | ||
305 | /* replace the port dots with dashes for the in4_pton() delimiter*/ | 314 | /* replace the port dots with dashes for the in4_pton() delimiter*/ |
306 | for (i = 0; i < 2; i++) { | 315 | for (i = 0; i < 2; i++) { |
@@ -336,90 +345,154 @@ out_err: | |||
336 | static struct nfs4_file_layout_dsaddr* | 345 | static struct nfs4_file_layout_dsaddr* |
337 | decode_device(struct inode *ino, struct pnfs_device *pdev) | 346 | decode_device(struct inode *ino, struct pnfs_device *pdev) |
338 | { | 347 | { |
339 | int i, dummy; | 348 | int i; |
340 | u32 cnt, num; | 349 | u32 cnt, num; |
341 | u8 *indexp; | 350 | u8 *indexp; |
342 | __be32 *p = (__be32 *)pdev->area, *indicesp; | 351 | __be32 *p; |
343 | struct nfs4_file_layout_dsaddr *dsaddr; | 352 | u8 *stripe_indices; |
353 | u8 max_stripe_index; | ||
354 | struct nfs4_file_layout_dsaddr *dsaddr = NULL; | ||
355 | struct xdr_stream stream; | ||
356 | struct xdr_buf buf = { | ||
357 | .pages = pdev->pages, | ||
358 | .page_len = pdev->pglen, | ||
359 | .buflen = pdev->pglen, | ||
360 | .len = pdev->pglen, | ||
361 | }; | ||
362 | struct page *scratch; | ||
363 | |||
364 | /* set up xdr stream */ | ||
365 | scratch = alloc_page(GFP_KERNEL); | ||
366 | if (!scratch) | ||
367 | goto out_err; | ||
368 | |||
369 | xdr_init_decode(&stream, &buf, NULL); | ||
370 | xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE); | ||
344 | 371 | ||
345 | /* Get the stripe count (number of stripe index) */ | 372 | /* Get the stripe count (number of stripe index) */ |
346 | cnt = be32_to_cpup(p++); | 373 | p = xdr_inline_decode(&stream, 4); |
374 | if (unlikely(!p)) | ||
375 | goto out_err_free_scratch; | ||
376 | |||
377 | cnt = be32_to_cpup(p); | ||
347 | dprintk("%s stripe count %d\n", __func__, cnt); | 378 | dprintk("%s stripe count %d\n", __func__, cnt); |
348 | if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) { | 379 | if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) { |
349 | printk(KERN_WARNING "%s: stripe count %d greater than " | 380 | printk(KERN_WARNING "%s: stripe count %d greater than " |
350 | "supported maximum %d\n", __func__, | 381 | "supported maximum %d\n", __func__, |
351 | cnt, NFS4_PNFS_MAX_STRIPE_CNT); | 382 | cnt, NFS4_PNFS_MAX_STRIPE_CNT); |
352 | goto out_err; | 383 | goto out_err_free_scratch; |
384 | } | ||
385 | |||
386 | /* read stripe indices */ | ||
387 | stripe_indices = kcalloc(cnt, sizeof(u8), GFP_KERNEL); | ||
388 | if (!stripe_indices) | ||
389 | goto out_err_free_scratch; | ||
390 | |||
391 | p = xdr_inline_decode(&stream, cnt << 2); | ||
392 | if (unlikely(!p)) | ||
393 | goto out_err_free_stripe_indices; | ||
394 | |||
395 | indexp = &stripe_indices[0]; | ||
396 | max_stripe_index = 0; | ||
397 | for (i = 0; i < cnt; i++) { | ||
398 | *indexp = be32_to_cpup(p++); | ||
399 | max_stripe_index = max(max_stripe_index, *indexp); | ||
400 | indexp++; | ||
353 | } | 401 | } |
354 | 402 | ||
355 | /* Check the multipath list count */ | 403 | /* Check the multipath list count */ |
356 | indicesp = p; | 404 | p = xdr_inline_decode(&stream, 4); |
357 | p += XDR_QUADLEN(cnt << 2); | 405 | if (unlikely(!p)) |
358 | num = be32_to_cpup(p++); | 406 | goto out_err_free_stripe_indices; |
407 | |||
408 | num = be32_to_cpup(p); | ||
359 | dprintk("%s ds_num %u\n", __func__, num); | 409 | dprintk("%s ds_num %u\n", __func__, num); |
360 | if (num > NFS4_PNFS_MAX_MULTI_CNT) { | 410 | if (num > NFS4_PNFS_MAX_MULTI_CNT) { |
361 | printk(KERN_WARNING "%s: multipath count %d greater than " | 411 | printk(KERN_WARNING "%s: multipath count %d greater than " |
362 | "supported maximum %d\n", __func__, | 412 | "supported maximum %d\n", __func__, |
363 | num, NFS4_PNFS_MAX_MULTI_CNT); | 413 | num, NFS4_PNFS_MAX_MULTI_CNT); |
364 | goto out_err; | 414 | goto out_err_free_stripe_indices; |
365 | } | 415 | } |
416 | |||
417 | /* validate stripe indices are all < num */ | ||
418 | if (max_stripe_index >= num) { | ||
419 | printk(KERN_WARNING "%s: stripe index %u >= num ds %u\n", | ||
420 | __func__, max_stripe_index, num); | ||
421 | goto out_err_free_stripe_indices; | ||
422 | } | ||
423 | |||
366 | dsaddr = kzalloc(sizeof(*dsaddr) + | 424 | dsaddr = kzalloc(sizeof(*dsaddr) + |
367 | (sizeof(struct nfs4_pnfs_ds *) * (num - 1)), | 425 | (sizeof(struct nfs4_pnfs_ds *) * (num - 1)), |
368 | GFP_KERNEL); | 426 | GFP_KERNEL); |
369 | if (!dsaddr) | 427 | if (!dsaddr) |
370 | goto out_err; | 428 | goto out_err_free_stripe_indices; |
371 | |||
372 | dsaddr->stripe_indices = kzalloc(sizeof(u8) * cnt, GFP_KERNEL); | ||
373 | if (!dsaddr->stripe_indices) | ||
374 | goto out_err_free; | ||
375 | 429 | ||
376 | dsaddr->stripe_count = cnt; | 430 | dsaddr->stripe_count = cnt; |
431 | dsaddr->stripe_indices = stripe_indices; | ||
432 | stripe_indices = NULL; | ||
377 | dsaddr->ds_num = num; | 433 | dsaddr->ds_num = num; |
378 | 434 | ||
379 | memcpy(&dsaddr->deviceid, &pdev->dev_id, sizeof(pdev->dev_id)); | 435 | memcpy(&dsaddr->deviceid, &pdev->dev_id, sizeof(pdev->dev_id)); |
380 | 436 | ||
381 | /* Go back an read stripe indices */ | ||
382 | p = indicesp; | ||
383 | indexp = &dsaddr->stripe_indices[0]; | ||
384 | for (i = 0; i < dsaddr->stripe_count; i++) { | ||
385 | *indexp = be32_to_cpup(p++); | ||
386 | if (*indexp >= num) | ||
387 | goto out_err_free; | ||
388 | indexp++; | ||
389 | } | ||
390 | /* Skip already read multipath list count */ | ||
391 | p++; | ||
392 | |||
393 | for (i = 0; i < dsaddr->ds_num; i++) { | 437 | for (i = 0; i < dsaddr->ds_num; i++) { |
394 | int j; | 438 | int j; |
439 | u32 mp_count; | ||
440 | |||
441 | p = xdr_inline_decode(&stream, 4); | ||
442 | if (unlikely(!p)) | ||
443 | goto out_err_free_deviceid; | ||
395 | 444 | ||
396 | dummy = be32_to_cpup(p++); /* multipath count */ | 445 | mp_count = be32_to_cpup(p); /* multipath count */ |
397 | if (dummy > 1) { | 446 | if (mp_count > 1) { |
398 | printk(KERN_WARNING | 447 | printk(KERN_WARNING |
399 | "%s: Multipath count %d not supported, " | 448 | "%s: Multipath count %d not supported, " |
400 | "skipping all greater than 1\n", __func__, | 449 | "skipping all greater than 1\n", __func__, |
401 | dummy); | 450 | mp_count); |
402 | } | 451 | } |
403 | for (j = 0; j < dummy; j++) { | 452 | for (j = 0; j < mp_count; j++) { |
404 | if (j == 0) { | 453 | if (j == 0) { |
405 | dsaddr->ds_list[i] = decode_and_add_ds(&p, ino); | 454 | dsaddr->ds_list[i] = decode_and_add_ds(&stream, |
455 | ino); | ||
406 | if (dsaddr->ds_list[i] == NULL) | 456 | if (dsaddr->ds_list[i] == NULL) |
407 | goto out_err_free; | 457 | goto out_err_free_deviceid; |
408 | } else { | 458 | } else { |
409 | u32 len; | 459 | u32 len; |
410 | /* skip extra multipath */ | 460 | /* skip extra multipath */ |
411 | len = be32_to_cpup(p++); | 461 | |
412 | p += XDR_QUADLEN(len); | 462 | /* read len, skip */ |
413 | len = be32_to_cpup(p++); | 463 | p = xdr_inline_decode(&stream, 4); |
414 | p += XDR_QUADLEN(len); | 464 | if (unlikely(!p)) |
415 | continue; | 465 | goto out_err_free_deviceid; |
466 | len = be32_to_cpup(p); | ||
467 | |||
468 | p = xdr_inline_decode(&stream, len); | ||
469 | if (unlikely(!p)) | ||
470 | goto out_err_free_deviceid; | ||
471 | |||
472 | /* read len, skip */ | ||
473 | p = xdr_inline_decode(&stream, 4); | ||
474 | if (unlikely(!p)) | ||
475 | goto out_err_free_deviceid; | ||
476 | len = be32_to_cpup(p); | ||
477 | |||
478 | p = xdr_inline_decode(&stream, len); | ||
479 | if (unlikely(!p)) | ||
480 | goto out_err_free_deviceid; | ||
416 | } | 481 | } |
417 | } | 482 | } |
418 | } | 483 | } |
484 | |||
485 | __free_page(scratch); | ||
419 | return dsaddr; | 486 | return dsaddr; |
420 | 487 | ||
421 | out_err_free: | 488 | out_err_free_deviceid: |
422 | nfs4_fl_free_deviceid(dsaddr); | 489 | nfs4_fl_free_deviceid(dsaddr); |
490 | /* stripe_indicies was part of dsaddr */ | ||
491 | goto out_err_free_scratch; | ||
492 | out_err_free_stripe_indices: | ||
493 | kfree(stripe_indices); | ||
494 | out_err_free_scratch: | ||
495 | __free_page(scratch); | ||
423 | out_err: | 496 | out_err: |
424 | dprintk("%s ERROR: returning NULL\n", __func__); | 497 | dprintk("%s ERROR: returning NULL\n", __func__); |
425 | return NULL; | 498 | return NULL; |
@@ -498,11 +571,6 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id) | |||
498 | goto out_free; | 571 | goto out_free; |
499 | } | 572 | } |
500 | 573 | ||
501 | /* set pdev->area */ | ||
502 | pdev->area = vmap(pages, max_pages, VM_MAP, PAGE_KERNEL); | ||
503 | if (!pdev->area) | ||
504 | goto out_free; | ||
505 | |||
506 | memcpy(&pdev->dev_id, dev_id, sizeof(*dev_id)); | 574 | memcpy(&pdev->dev_id, dev_id, sizeof(*dev_id)); |
507 | pdev->layout_type = LAYOUT_NFSV4_1_FILES; | 575 | pdev->layout_type = LAYOUT_NFSV4_1_FILES; |
508 | pdev->pages = pages; | 576 | pdev->pages = pages; |
@@ -521,8 +589,6 @@ get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id) | |||
521 | */ | 589 | */ |
522 | dsaddr = decode_and_add_device(inode, pdev); | 590 | dsaddr = decode_and_add_device(inode, pdev); |
523 | out_free: | 591 | out_free: |
524 | if (pdev->area != NULL) | ||
525 | vunmap(pdev->area); | ||
526 | for (i = 0; i < max_pages; i++) | 592 | for (i = 0; i < max_pages; i++) |
527 | __free_page(pages[i]); | 593 | __free_page(pages[i]); |
528 | kfree(pages); | 594 | kfree(pages); |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 1d84e7088af9..dfd1e6d7e6c3 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/string.h> | 41 | #include <linux/string.h> |
42 | #include <linux/slab.h> | 42 | #include <linux/slab.h> |
43 | #include <linux/sunrpc/clnt.h> | 43 | #include <linux/sunrpc/clnt.h> |
44 | #include <linux/sunrpc/gss_api.h> | ||
44 | #include <linux/nfs.h> | 45 | #include <linux/nfs.h> |
45 | #include <linux/nfs4.h> | 46 | #include <linux/nfs4.h> |
46 | #include <linux/nfs_fs.h> | 47 | #include <linux/nfs_fs.h> |
@@ -71,7 +72,9 @@ static int _nfs4_proc_open(struct nfs4_opendata *data); | |||
71 | static int _nfs4_recover_proc_open(struct nfs4_opendata *data); | 72 | static int _nfs4_recover_proc_open(struct nfs4_opendata *data); |
72 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 73 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
73 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); | 74 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); |
74 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 75 | static int _nfs4_proc_lookup(struct rpc_clnt *client, struct inode *dir, |
76 | const struct qstr *name, struct nfs_fh *fhandle, | ||
77 | struct nfs_fattr *fattr); | ||
75 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 78 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
76 | static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | 79 | static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, |
77 | struct nfs_fattr *fattr, struct iattr *sattr, | 80 | struct nfs_fattr *fattr, struct iattr *sattr, |
@@ -85,6 +88,8 @@ static int nfs4_map_errors(int err) | |||
85 | switch (err) { | 88 | switch (err) { |
86 | case -NFS4ERR_RESOURCE: | 89 | case -NFS4ERR_RESOURCE: |
87 | return -EREMOTEIO; | 90 | return -EREMOTEIO; |
91 | case -NFS4ERR_WRONGSEC: | ||
92 | return -EPERM; | ||
88 | case -NFS4ERR_BADOWNER: | 93 | case -NFS4ERR_BADOWNER: |
89 | case -NFS4ERR_BADNAME: | 94 | case -NFS4ERR_BADNAME: |
90 | return -EINVAL; | 95 | return -EINVAL; |
@@ -657,7 +662,8 @@ struct rpc_call_ops nfs41_call_priv_sync_ops = { | |||
657 | .rpc_call_done = nfs41_call_sync_done, | 662 | .rpc_call_done = nfs41_call_sync_done, |
658 | }; | 663 | }; |
659 | 664 | ||
660 | static int nfs4_call_sync_sequence(struct nfs_server *server, | 665 | static int nfs4_call_sync_sequence(struct rpc_clnt *clnt, |
666 | struct nfs_server *server, | ||
661 | struct rpc_message *msg, | 667 | struct rpc_message *msg, |
662 | struct nfs4_sequence_args *args, | 668 | struct nfs4_sequence_args *args, |
663 | struct nfs4_sequence_res *res, | 669 | struct nfs4_sequence_res *res, |
@@ -673,7 +679,7 @@ static int nfs4_call_sync_sequence(struct nfs_server *server, | |||
673 | .cache_reply = cache_reply, | 679 | .cache_reply = cache_reply, |
674 | }; | 680 | }; |
675 | struct rpc_task_setup task_setup = { | 681 | struct rpc_task_setup task_setup = { |
676 | .rpc_client = server->client, | 682 | .rpc_client = clnt, |
677 | .rpc_message = msg, | 683 | .rpc_message = msg, |
678 | .callback_ops = &nfs41_call_sync_ops, | 684 | .callback_ops = &nfs41_call_sync_ops, |
679 | .callback_data = &data | 685 | .callback_data = &data |
@@ -692,13 +698,14 @@ static int nfs4_call_sync_sequence(struct nfs_server *server, | |||
692 | return ret; | 698 | return ret; |
693 | } | 699 | } |
694 | 700 | ||
695 | int _nfs4_call_sync_session(struct nfs_server *server, | 701 | int _nfs4_call_sync_session(struct rpc_clnt *clnt, |
702 | struct nfs_server *server, | ||
696 | struct rpc_message *msg, | 703 | struct rpc_message *msg, |
697 | struct nfs4_sequence_args *args, | 704 | struct nfs4_sequence_args *args, |
698 | struct nfs4_sequence_res *res, | 705 | struct nfs4_sequence_res *res, |
699 | int cache_reply) | 706 | int cache_reply) |
700 | { | 707 | { |
701 | return nfs4_call_sync_sequence(server, msg, args, res, cache_reply, 0); | 708 | return nfs4_call_sync_sequence(clnt, server, msg, args, res, cache_reply, 0); |
702 | } | 709 | } |
703 | 710 | ||
704 | #else | 711 | #else |
@@ -709,19 +716,28 @@ static int nfs4_sequence_done(struct rpc_task *task, | |||
709 | } | 716 | } |
710 | #endif /* CONFIG_NFS_V4_1 */ | 717 | #endif /* CONFIG_NFS_V4_1 */ |
711 | 718 | ||
712 | int _nfs4_call_sync(struct nfs_server *server, | 719 | int _nfs4_call_sync(struct rpc_clnt *clnt, |
720 | struct nfs_server *server, | ||
713 | struct rpc_message *msg, | 721 | struct rpc_message *msg, |
714 | struct nfs4_sequence_args *args, | 722 | struct nfs4_sequence_args *args, |
715 | struct nfs4_sequence_res *res, | 723 | struct nfs4_sequence_res *res, |
716 | int cache_reply) | 724 | int cache_reply) |
717 | { | 725 | { |
718 | args->sa_session = res->sr_session = NULL; | 726 | args->sa_session = res->sr_session = NULL; |
719 | return rpc_call_sync(server->client, msg, 0); | 727 | return rpc_call_sync(clnt, msg, 0); |
720 | } | 728 | } |
721 | 729 | ||
722 | #define nfs4_call_sync(server, msg, args, res, cache_reply) \ | 730 | static inline |
723 | (server)->nfs_client->cl_mvops->call_sync((server), (msg), &(args)->seq_args, \ | 731 | int nfs4_call_sync(struct rpc_clnt *clnt, |
724 | &(res)->seq_res, (cache_reply)) | 732 | struct nfs_server *server, |
733 | struct rpc_message *msg, | ||
734 | struct nfs4_sequence_args *args, | ||
735 | struct nfs4_sequence_res *res, | ||
736 | int cache_reply) | ||
737 | { | ||
738 | return server->nfs_client->cl_mvops->call_sync(clnt, server, msg, | ||
739 | args, res, cache_reply); | ||
740 | } | ||
725 | 741 | ||
726 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | 742 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) |
727 | { | 743 | { |
@@ -1831,7 +1847,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
1831 | } else | 1847 | } else |
1832 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 1848 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
1833 | 1849 | ||
1834 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); | 1850 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); |
1835 | if (status == 0 && state != NULL) | 1851 | if (status == 0 && state != NULL) |
1836 | renew_lease(server, timestamp); | 1852 | renew_lease(server, timestamp); |
1837 | return status; | 1853 | return status; |
@@ -2090,7 +2106,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f | |||
2090 | }; | 2106 | }; |
2091 | int status; | 2107 | int status; |
2092 | 2108 | ||
2093 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | 2109 | status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
2094 | if (status == 0) { | 2110 | if (status == 0) { |
2095 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); | 2111 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); |
2096 | server->caps &= ~(NFS_CAP_ACLS|NFS_CAP_HARDLINKS| | 2112 | server->caps &= ~(NFS_CAP_ACLS|NFS_CAP_HARDLINKS| |
@@ -2160,7 +2176,7 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2160 | }; | 2176 | }; |
2161 | 2177 | ||
2162 | nfs_fattr_init(info->fattr); | 2178 | nfs_fattr_init(info->fattr); |
2163 | return nfs4_call_sync(server, &msg, &args, &res, 0); | 2179 | return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
2164 | } | 2180 | } |
2165 | 2181 | ||
2166 | static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | 2182 | static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, |
@@ -2176,15 +2192,43 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2176 | return err; | 2192 | return err; |
2177 | } | 2193 | } |
2178 | 2194 | ||
2195 | static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, | ||
2196 | struct nfs_fsinfo *info, rpc_authflavor_t flavor) | ||
2197 | { | ||
2198 | struct rpc_auth *auth; | ||
2199 | int ret; | ||
2200 | |||
2201 | auth = rpcauth_create(flavor, server->client); | ||
2202 | if (!auth) { | ||
2203 | ret = -EIO; | ||
2204 | goto out; | ||
2205 | } | ||
2206 | ret = nfs4_lookup_root(server, fhandle, info); | ||
2207 | if (ret < 0) | ||
2208 | ret = -EAGAIN; | ||
2209 | out: | ||
2210 | return ret; | ||
2211 | } | ||
2212 | |||
2179 | /* | 2213 | /* |
2180 | * get the file handle for the "/" directory on the server | 2214 | * get the file handle for the "/" directory on the server |
2181 | */ | 2215 | */ |
2182 | static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | 2216 | static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, |
2183 | struct nfs_fsinfo *info) | 2217 | struct nfs_fsinfo *info) |
2184 | { | 2218 | { |
2185 | int status; | 2219 | int i, len, status = 0; |
2220 | rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS + 2]; | ||
2221 | |||
2222 | flav_array[0] = RPC_AUTH_UNIX; | ||
2223 | len = gss_mech_list_pseudoflavors(&flav_array[1]); | ||
2224 | flav_array[1+len] = RPC_AUTH_NULL; | ||
2225 | len += 2; | ||
2186 | 2226 | ||
2187 | status = nfs4_lookup_root(server, fhandle, info); | 2227 | for (i = 0; i < len; i++) { |
2228 | status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]); | ||
2229 | if (status == 0) | ||
2230 | break; | ||
2231 | } | ||
2188 | if (status == 0) | 2232 | if (status == 0) |
2189 | status = nfs4_server_capabilities(server, fhandle); | 2233 | status = nfs4_server_capabilities(server, fhandle); |
2190 | if (status == 0) | 2234 | if (status == 0) |
@@ -2249,7 +2293,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2249 | }; | 2293 | }; |
2250 | 2294 | ||
2251 | nfs_fattr_init(fattr); | 2295 | nfs_fattr_init(fattr); |
2252 | return nfs4_call_sync(server, &msg, &args, &res, 0); | 2296 | return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
2253 | } | 2297 | } |
2254 | 2298 | ||
2255 | static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 2299 | static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
@@ -2309,9 +2353,9 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
2309 | return status; | 2353 | return status; |
2310 | } | 2354 | } |
2311 | 2355 | ||
2312 | static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *dirfh, | 2356 | static int _nfs4_proc_lookupfh(struct rpc_clnt *clnt, struct nfs_server *server, |
2313 | const struct qstr *name, struct nfs_fh *fhandle, | 2357 | const struct nfs_fh *dirfh, const struct qstr *name, |
2314 | struct nfs_fattr *fattr) | 2358 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
2315 | { | 2359 | { |
2316 | int status; | 2360 | int status; |
2317 | struct nfs4_lookup_arg args = { | 2361 | struct nfs4_lookup_arg args = { |
@@ -2333,7 +2377,7 @@ static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *d | |||
2333 | nfs_fattr_init(fattr); | 2377 | nfs_fattr_init(fattr); |
2334 | 2378 | ||
2335 | dprintk("NFS call lookupfh %s\n", name->name); | 2379 | dprintk("NFS call lookupfh %s\n", name->name); |
2336 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | 2380 | status = nfs4_call_sync(clnt, server, &msg, &args.seq_args, &res.seq_res, 0); |
2337 | dprintk("NFS reply lookupfh: %d\n", status); | 2381 | dprintk("NFS reply lookupfh: %d\n", status); |
2338 | return status; | 2382 | return status; |
2339 | } | 2383 | } |
@@ -2345,7 +2389,7 @@ static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | |||
2345 | struct nfs4_exception exception = { }; | 2389 | struct nfs4_exception exception = { }; |
2346 | int err; | 2390 | int err; |
2347 | do { | 2391 | do { |
2348 | err = _nfs4_proc_lookupfh(server, dirfh, name, fhandle, fattr); | 2392 | err = _nfs4_proc_lookupfh(server->client, server, dirfh, name, fhandle, fattr); |
2349 | /* FIXME: !!!! */ | 2393 | /* FIXME: !!!! */ |
2350 | if (err == -NFS4ERR_MOVED) { | 2394 | if (err == -NFS4ERR_MOVED) { |
2351 | err = -EREMOTE; | 2395 | err = -EREMOTE; |
@@ -2356,27 +2400,41 @@ static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | |||
2356 | return err; | 2400 | return err; |
2357 | } | 2401 | } |
2358 | 2402 | ||
2359 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, | 2403 | static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, |
2360 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 2404 | const struct qstr *name, struct nfs_fh *fhandle, |
2405 | struct nfs_fattr *fattr) | ||
2361 | { | 2406 | { |
2362 | int status; | 2407 | int status; |
2363 | 2408 | ||
2364 | dprintk("NFS call lookup %s\n", name->name); | 2409 | dprintk("NFS call lookup %s\n", name->name); |
2365 | status = _nfs4_proc_lookupfh(NFS_SERVER(dir), NFS_FH(dir), name, fhandle, fattr); | 2410 | status = _nfs4_proc_lookupfh(clnt, NFS_SERVER(dir), NFS_FH(dir), name, fhandle, fattr); |
2366 | if (status == -NFS4ERR_MOVED) | 2411 | if (status == -NFS4ERR_MOVED) |
2367 | status = nfs4_get_referral(dir, name, fattr, fhandle); | 2412 | status = nfs4_get_referral(dir, name, fattr, fhandle); |
2368 | dprintk("NFS reply lookup: %d\n", status); | 2413 | dprintk("NFS reply lookup: %d\n", status); |
2369 | return status; | 2414 | return status; |
2370 | } | 2415 | } |
2371 | 2416 | ||
2372 | static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 2417 | void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr, struct nfs_fh *fh) |
2418 | { | ||
2419 | memset(fh, 0, sizeof(struct nfs_fh)); | ||
2420 | fattr->fsid.major = 1; | ||
2421 | fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE | | ||
2422 | NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_FSID | NFS_ATTR_FATTR_MOUNTPOINT; | ||
2423 | fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO; | ||
2424 | fattr->nlink = 2; | ||
2425 | } | ||
2426 | |||
2427 | static int nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qstr *name, | ||
2428 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | ||
2373 | { | 2429 | { |
2374 | struct nfs4_exception exception = { }; | 2430 | struct nfs4_exception exception = { }; |
2375 | int err; | 2431 | int err; |
2376 | do { | 2432 | do { |
2377 | err = nfs4_handle_exception(NFS_SERVER(dir), | 2433 | err = nfs4_handle_exception(NFS_SERVER(dir), |
2378 | _nfs4_proc_lookup(dir, name, fhandle, fattr), | 2434 | _nfs4_proc_lookup(clnt, dir, name, fhandle, fattr), |
2379 | &exception); | 2435 | &exception); |
2436 | if (err == -EPERM) | ||
2437 | nfs_fixup_secinfo_attributes(fattr, fhandle); | ||
2380 | } while (exception.retry); | 2438 | } while (exception.retry); |
2381 | return err; | 2439 | return err; |
2382 | } | 2440 | } |
@@ -2421,7 +2479,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
2421 | if (res.fattr == NULL) | 2479 | if (res.fattr == NULL) |
2422 | return -ENOMEM; | 2480 | return -ENOMEM; |
2423 | 2481 | ||
2424 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | 2482 | status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
2425 | if (!status) { | 2483 | if (!status) { |
2426 | entry->mask = 0; | 2484 | entry->mask = 0; |
2427 | if (res.access & NFS4_ACCESS_READ) | 2485 | if (res.access & NFS4_ACCESS_READ) |
@@ -2488,7 +2546,7 @@ static int _nfs4_proc_readlink(struct inode *inode, struct page *page, | |||
2488 | .rpc_resp = &res, | 2546 | .rpc_resp = &res, |
2489 | }; | 2547 | }; |
2490 | 2548 | ||
2491 | return nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0); | 2549 | return nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), &msg, &args.seq_args, &res.seq_res, 0); |
2492 | } | 2550 | } |
2493 | 2551 | ||
2494 | static int nfs4_proc_readlink(struct inode *inode, struct page *page, | 2552 | static int nfs4_proc_readlink(struct inode *inode, struct page *page, |
@@ -2577,7 +2635,7 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) | |||
2577 | if (res.dir_attr == NULL) | 2635 | if (res.dir_attr == NULL) |
2578 | goto out; | 2636 | goto out; |
2579 | 2637 | ||
2580 | status = nfs4_call_sync(server, &msg, &args, &res, 1); | 2638 | status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1); |
2581 | if (status == 0) { | 2639 | if (status == 0) { |
2582 | update_changeattr(dir, &res.cinfo); | 2640 | update_changeattr(dir, &res.cinfo); |
2583 | nfs_post_op_update_inode(dir, res.dir_attr); | 2641 | nfs_post_op_update_inode(dir, res.dir_attr); |
@@ -2678,7 +2736,7 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
2678 | if (res.old_fattr == NULL || res.new_fattr == NULL) | 2736 | if (res.old_fattr == NULL || res.new_fattr == NULL) |
2679 | goto out; | 2737 | goto out; |
2680 | 2738 | ||
2681 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); | 2739 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); |
2682 | if (!status) { | 2740 | if (!status) { |
2683 | update_changeattr(old_dir, &res.old_cinfo); | 2741 | update_changeattr(old_dir, &res.old_cinfo); |
2684 | nfs_post_op_update_inode(old_dir, res.old_fattr); | 2742 | nfs_post_op_update_inode(old_dir, res.old_fattr); |
@@ -2729,7 +2787,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr * | |||
2729 | if (res.fattr == NULL || res.dir_attr == NULL) | 2787 | if (res.fattr == NULL || res.dir_attr == NULL) |
2730 | goto out; | 2788 | goto out; |
2731 | 2789 | ||
2732 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); | 2790 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); |
2733 | if (!status) { | 2791 | if (!status) { |
2734 | update_changeattr(dir, &res.cinfo); | 2792 | update_changeattr(dir, &res.cinfo); |
2735 | nfs_post_op_update_inode(dir, res.dir_attr); | 2793 | nfs_post_op_update_inode(dir, res.dir_attr); |
@@ -2792,8 +2850,8 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir, | |||
2792 | 2850 | ||
2793 | static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) | 2851 | static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) |
2794 | { | 2852 | { |
2795 | int status = nfs4_call_sync(NFS_SERVER(dir), &data->msg, | 2853 | int status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &data->msg, |
2796 | &data->arg, &data->res, 1); | 2854 | &data->arg.seq_args, &data->res.seq_res, 1); |
2797 | if (status == 0) { | 2855 | if (status == 0) { |
2798 | update_changeattr(dir, &data->res.dir_cinfo); | 2856 | update_changeattr(dir, &data->res.dir_cinfo); |
2799 | nfs_post_op_update_inode(dir, data->res.dir_fattr); | 2857 | nfs_post_op_update_inode(dir, data->res.dir_fattr); |
@@ -2905,7 +2963,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
2905 | (unsigned long long)cookie); | 2963 | (unsigned long long)cookie); |
2906 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); | 2964 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); |
2907 | res.pgbase = args.pgbase; | 2965 | res.pgbase = args.pgbase; |
2908 | status = nfs4_call_sync(NFS_SERVER(dir), &msg, &args, &res, 0); | 2966 | status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0); |
2909 | if (status >= 0) { | 2967 | if (status >= 0) { |
2910 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); | 2968 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); |
2911 | status += args.pgbase; | 2969 | status += args.pgbase; |
@@ -2997,7 +3055,7 @@ static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2997 | }; | 3055 | }; |
2998 | 3056 | ||
2999 | nfs_fattr_init(fsstat->fattr); | 3057 | nfs_fattr_init(fsstat->fattr); |
3000 | return nfs4_call_sync(server, &msg, &args, &res, 0); | 3058 | return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
3001 | } | 3059 | } |
3002 | 3060 | ||
3003 | static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) | 3061 | static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) |
@@ -3028,7 +3086,7 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, | |||
3028 | .rpc_resp = &res, | 3086 | .rpc_resp = &res, |
3029 | }; | 3087 | }; |
3030 | 3088 | ||
3031 | return nfs4_call_sync(server, &msg, &args, &res, 0); | 3089 | return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
3032 | } | 3090 | } |
3033 | 3091 | ||
3034 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) | 3092 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) |
@@ -3073,7 +3131,7 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle | |||
3073 | } | 3131 | } |
3074 | 3132 | ||
3075 | nfs_fattr_init(pathconf->fattr); | 3133 | nfs_fattr_init(pathconf->fattr); |
3076 | return nfs4_call_sync(server, &msg, &args, &res, 0); | 3134 | return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
3077 | } | 3135 | } |
3078 | 3136 | ||
3079 | static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | 3137 | static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, |
@@ -3195,12 +3253,9 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag | |||
3195 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE]; | 3253 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE]; |
3196 | } | 3254 | } |
3197 | 3255 | ||
3198 | static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | 3256 | static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_write_data *data) |
3199 | { | 3257 | { |
3200 | struct inode *inode = data->inode; | 3258 | struct inode *inode = data->inode; |
3201 | |||
3202 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | ||
3203 | return -EAGAIN; | ||
3204 | 3259 | ||
3205 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { | 3260 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
3206 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3261 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
@@ -3210,11 +3265,24 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
3210 | return 0; | 3265 | return 0; |
3211 | } | 3266 | } |
3212 | 3267 | ||
3268 | static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | ||
3269 | { | ||
3270 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | ||
3271 | return -EAGAIN; | ||
3272 | return data->write_done_cb(task, data); | ||
3273 | } | ||
3274 | |||
3213 | static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg) | 3275 | static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg) |
3214 | { | 3276 | { |
3215 | struct nfs_server *server = NFS_SERVER(data->inode); | 3277 | struct nfs_server *server = NFS_SERVER(data->inode); |
3216 | 3278 | ||
3217 | data->args.bitmask = server->cache_consistency_bitmask; | 3279 | if (data->lseg) { |
3280 | data->args.bitmask = NULL; | ||
3281 | data->res.fattr = NULL; | ||
3282 | } else | ||
3283 | data->args.bitmask = server->cache_consistency_bitmask; | ||
3284 | if (!data->write_done_cb) | ||
3285 | data->write_done_cb = nfs4_commit_done_cb; | ||
3218 | data->res.server = server; | 3286 | data->res.server = server; |
3219 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT]; | 3287 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT]; |
3220 | } | 3288 | } |
@@ -3452,7 +3520,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
3452 | resp_buf = buf; | 3520 | resp_buf = buf; |
3453 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); | 3521 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); |
3454 | } | 3522 | } |
3455 | ret = nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0); | 3523 | ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), &msg, &args.seq_args, &res.seq_res, 0); |
3456 | if (ret) | 3524 | if (ret) |
3457 | goto out_free; | 3525 | goto out_free; |
3458 | if (res.acl_len > args.acl_len) | 3526 | if (res.acl_len > args.acl_len) |
@@ -3527,7 +3595,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
3527 | if (i < 0) | 3595 | if (i < 0) |
3528 | return i; | 3596 | return i; |
3529 | nfs_inode_return_delegation(inode); | 3597 | nfs_inode_return_delegation(inode); |
3530 | ret = nfs4_call_sync(server, &msg, &arg, &res, 1); | 3598 | ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); |
3531 | 3599 | ||
3532 | /* | 3600 | /* |
3533 | * Free each page after tx, so the only ref left is | 3601 | * Free each page after tx, so the only ref left is |
@@ -3890,7 +3958,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
3890 | lsp = request->fl_u.nfs4_fl.owner; | 3958 | lsp = request->fl_u.nfs4_fl.owner; |
3891 | arg.lock_owner.id = lsp->ls_id.id; | 3959 | arg.lock_owner.id = lsp->ls_id.id; |
3892 | arg.lock_owner.s_dev = server->s_dev; | 3960 | arg.lock_owner.s_dev = server->s_dev; |
3893 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); | 3961 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); |
3894 | switch (status) { | 3962 | switch (status) { |
3895 | case 0: | 3963 | case 0: |
3896 | request->fl_type = F_UNLCK; | 3964 | request->fl_type = F_UNLCK; |
@@ -4618,12 +4686,46 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
4618 | nfs_fattr_init(&fs_locations->fattr); | 4686 | nfs_fattr_init(&fs_locations->fattr); |
4619 | fs_locations->server = server; | 4687 | fs_locations->server = server; |
4620 | fs_locations->nlocations = 0; | 4688 | fs_locations->nlocations = 0; |
4621 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | 4689 | status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
4622 | nfs_fixup_referral_attributes(&fs_locations->fattr); | 4690 | nfs_fixup_referral_attributes(&fs_locations->fattr); |
4623 | dprintk("%s: returned status = %d\n", __func__, status); | 4691 | dprintk("%s: returned status = %d\n", __func__, status); |
4624 | return status; | 4692 | return status; |
4625 | } | 4693 | } |
4626 | 4694 | ||
4695 | static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors) | ||
4696 | { | ||
4697 | int status; | ||
4698 | struct nfs4_secinfo_arg args = { | ||
4699 | .dir_fh = NFS_FH(dir), | ||
4700 | .name = name, | ||
4701 | }; | ||
4702 | struct nfs4_secinfo_res res = { | ||
4703 | .flavors = flavors, | ||
4704 | }; | ||
4705 | struct rpc_message msg = { | ||
4706 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO], | ||
4707 | .rpc_argp = &args, | ||
4708 | .rpc_resp = &res, | ||
4709 | }; | ||
4710 | |||
4711 | dprintk("NFS call secinfo %s\n", name->name); | ||
4712 | status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0); | ||
4713 | dprintk("NFS reply secinfo: %d\n", status); | ||
4714 | return status; | ||
4715 | } | ||
4716 | |||
4717 | int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors) | ||
4718 | { | ||
4719 | struct nfs4_exception exception = { }; | ||
4720 | int err; | ||
4721 | do { | ||
4722 | err = nfs4_handle_exception(NFS_SERVER(dir), | ||
4723 | _nfs4_proc_secinfo(dir, name, flavors), | ||
4724 | &exception); | ||
4725 | } while (exception.retry); | ||
4726 | return err; | ||
4727 | } | ||
4728 | |||
4627 | #ifdef CONFIG_NFS_V4_1 | 4729 | #ifdef CONFIG_NFS_V4_1 |
4628 | /* | 4730 | /* |
4629 | * Check the exchange flags returned by the server for invalid flags, having | 4731 | * Check the exchange flags returned by the server for invalid flags, having |
@@ -5516,8 +5618,6 @@ static void nfs4_layoutget_release(void *calldata) | |||
5516 | struct nfs4_layoutget *lgp = calldata; | 5618 | struct nfs4_layoutget *lgp = calldata; |
5517 | 5619 | ||
5518 | dprintk("--> %s\n", __func__); | 5620 | dprintk("--> %s\n", __func__); |
5519 | if (lgp->res.layout.buf != NULL) | ||
5520 | free_page((unsigned long) lgp->res.layout.buf); | ||
5521 | put_nfs_open_context(lgp->args.ctx); | 5621 | put_nfs_open_context(lgp->args.ctx); |
5522 | kfree(calldata); | 5622 | kfree(calldata); |
5523 | dprintk("<-- %s\n", __func__); | 5623 | dprintk("<-- %s\n", __func__); |
@@ -5549,12 +5649,7 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp) | |||
5549 | 5649 | ||
5550 | dprintk("--> %s\n", __func__); | 5650 | dprintk("--> %s\n", __func__); |
5551 | 5651 | ||
5552 | lgp->res.layout.buf = (void *)__get_free_page(GFP_NOFS); | 5652 | lgp->res.layoutp = &lgp->args.layout; |
5553 | if (lgp->res.layout.buf == NULL) { | ||
5554 | nfs4_layoutget_release(lgp); | ||
5555 | return -ENOMEM; | ||
5556 | } | ||
5557 | |||
5558 | lgp->res.seq_res.sr_slot = NULL; | 5653 | lgp->res.seq_res.sr_slot = NULL; |
5559 | task = rpc_run_task(&task_setup_data); | 5654 | task = rpc_run_task(&task_setup_data); |
5560 | if (IS_ERR(task)) | 5655 | if (IS_ERR(task)) |
@@ -5586,7 +5681,7 @@ _nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev) | |||
5586 | int status; | 5681 | int status; |
5587 | 5682 | ||
5588 | dprintk("--> %s\n", __func__); | 5683 | dprintk("--> %s\n", __func__); |
5589 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | 5684 | status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); |
5590 | dprintk("<-- %s status=%d\n", __func__, status); | 5685 | dprintk("<-- %s status=%d\n", __func__, status); |
5591 | 5686 | ||
5592 | return status; | 5687 | return status; |
@@ -5606,6 +5701,100 @@ int nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev) | |||
5606 | } | 5701 | } |
5607 | EXPORT_SYMBOL_GPL(nfs4_proc_getdeviceinfo); | 5702 | EXPORT_SYMBOL_GPL(nfs4_proc_getdeviceinfo); |
5608 | 5703 | ||
5704 | static void nfs4_layoutcommit_prepare(struct rpc_task *task, void *calldata) | ||
5705 | { | ||
5706 | struct nfs4_layoutcommit_data *data = calldata; | ||
5707 | struct nfs_server *server = NFS_SERVER(data->args.inode); | ||
5708 | |||
5709 | if (nfs4_setup_sequence(server, &data->args.seq_args, | ||
5710 | &data->res.seq_res, 1, task)) | ||
5711 | return; | ||
5712 | rpc_call_start(task); | ||
5713 | } | ||
5714 | |||
5715 | static void | ||
5716 | nfs4_layoutcommit_done(struct rpc_task *task, void *calldata) | ||
5717 | { | ||
5718 | struct nfs4_layoutcommit_data *data = calldata; | ||
5719 | struct nfs_server *server = NFS_SERVER(data->args.inode); | ||
5720 | |||
5721 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | ||
5722 | return; | ||
5723 | |||
5724 | switch (task->tk_status) { /* Just ignore these failures */ | ||
5725 | case NFS4ERR_DELEG_REVOKED: /* layout was recalled */ | ||
5726 | case NFS4ERR_BADIOMODE: /* no IOMODE_RW layout for range */ | ||
5727 | case NFS4ERR_BADLAYOUT: /* no layout */ | ||
5728 | case NFS4ERR_GRACE: /* loca_recalim always false */ | ||
5729 | task->tk_status = 0; | ||
5730 | } | ||
5731 | |||
5732 | if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) { | ||
5733 | nfs_restart_rpc(task, server->nfs_client); | ||
5734 | return; | ||
5735 | } | ||
5736 | |||
5737 | if (task->tk_status == 0) | ||
5738 | nfs_post_op_update_inode_force_wcc(data->args.inode, | ||
5739 | data->res.fattr); | ||
5740 | } | ||
5741 | |||
5742 | static void nfs4_layoutcommit_release(void *calldata) | ||
5743 | { | ||
5744 | struct nfs4_layoutcommit_data *data = calldata; | ||
5745 | |||
5746 | /* Matched by references in pnfs_set_layoutcommit */ | ||
5747 | put_lseg(data->lseg); | ||
5748 | put_rpccred(data->cred); | ||
5749 | kfree(data); | ||
5750 | } | ||
5751 | |||
5752 | static const struct rpc_call_ops nfs4_layoutcommit_ops = { | ||
5753 | .rpc_call_prepare = nfs4_layoutcommit_prepare, | ||
5754 | .rpc_call_done = nfs4_layoutcommit_done, | ||
5755 | .rpc_release = nfs4_layoutcommit_release, | ||
5756 | }; | ||
5757 | |||
5758 | int | ||
5759 | nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync) | ||
5760 | { | ||
5761 | struct rpc_message msg = { | ||
5762 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTCOMMIT], | ||
5763 | .rpc_argp = &data->args, | ||
5764 | .rpc_resp = &data->res, | ||
5765 | .rpc_cred = data->cred, | ||
5766 | }; | ||
5767 | struct rpc_task_setup task_setup_data = { | ||
5768 | .task = &data->task, | ||
5769 | .rpc_client = NFS_CLIENT(data->args.inode), | ||
5770 | .rpc_message = &msg, | ||
5771 | .callback_ops = &nfs4_layoutcommit_ops, | ||
5772 | .callback_data = data, | ||
5773 | .flags = RPC_TASK_ASYNC, | ||
5774 | }; | ||
5775 | struct rpc_task *task; | ||
5776 | int status = 0; | ||
5777 | |||
5778 | dprintk("NFS: %4d initiating layoutcommit call. sync %d " | ||
5779 | "lbw: %llu inode %lu\n", | ||
5780 | data->task.tk_pid, sync, | ||
5781 | data->args.lastbytewritten, | ||
5782 | data->args.inode->i_ino); | ||
5783 | |||
5784 | task = rpc_run_task(&task_setup_data); | ||
5785 | if (IS_ERR(task)) | ||
5786 | return PTR_ERR(task); | ||
5787 | if (sync == false) | ||
5788 | goto out; | ||
5789 | status = nfs4_wait_for_completion_rpc_task(task); | ||
5790 | if (status != 0) | ||
5791 | goto out; | ||
5792 | status = task->tk_status; | ||
5793 | out: | ||
5794 | dprintk("%s: status %d\n", __func__, status); | ||
5795 | rpc_put_task(task); | ||
5796 | return status; | ||
5797 | } | ||
5609 | #endif /* CONFIG_NFS_V4_1 */ | 5798 | #endif /* CONFIG_NFS_V4_1 */ |
5610 | 5799 | ||
5611 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | 5800 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { |
@@ -5741,6 +5930,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = { | |||
5741 | .close_context = nfs4_close_context, | 5930 | .close_context = nfs4_close_context, |
5742 | .open_context = nfs4_atomic_open, | 5931 | .open_context = nfs4_atomic_open, |
5743 | .init_client = nfs4_init_client, | 5932 | .init_client = nfs4_init_client, |
5933 | .secinfo = nfs4_proc_secinfo, | ||
5744 | }; | 5934 | }; |
5745 | 5935 | ||
5746 | static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = { | 5936 | static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = { |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 0cf560f77884..dddfb5795d7b 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/kdev_t.h> | 46 | #include <linux/kdev_t.h> |
47 | #include <linux/sunrpc/clnt.h> | 47 | #include <linux/sunrpc/clnt.h> |
48 | #include <linux/sunrpc/msg_prot.h> | 48 | #include <linux/sunrpc/msg_prot.h> |
49 | #include <linux/sunrpc/gss_api.h> | ||
49 | #include <linux/nfs.h> | 50 | #include <linux/nfs.h> |
50 | #include <linux/nfs4.h> | 51 | #include <linux/nfs4.h> |
51 | #include <linux/nfs_fs.h> | 52 | #include <linux/nfs_fs.h> |
@@ -112,7 +113,7 @@ static int nfs4_stat_to_errno(int); | |||
112 | #define encode_restorefh_maxsz (op_encode_hdr_maxsz) | 113 | #define encode_restorefh_maxsz (op_encode_hdr_maxsz) |
113 | #define decode_restorefh_maxsz (op_decode_hdr_maxsz) | 114 | #define decode_restorefh_maxsz (op_decode_hdr_maxsz) |
114 | #define encode_fsinfo_maxsz (encode_getattr_maxsz) | 115 | #define encode_fsinfo_maxsz (encode_getattr_maxsz) |
115 | #define decode_fsinfo_maxsz (op_decode_hdr_maxsz + 11) | 116 | #define decode_fsinfo_maxsz (op_decode_hdr_maxsz + 15) |
116 | #define encode_renew_maxsz (op_encode_hdr_maxsz + 3) | 117 | #define encode_renew_maxsz (op_encode_hdr_maxsz + 3) |
117 | #define decode_renew_maxsz (op_decode_hdr_maxsz) | 118 | #define decode_renew_maxsz (op_decode_hdr_maxsz) |
118 | #define encode_setclientid_maxsz \ | 119 | #define encode_setclientid_maxsz \ |
@@ -253,6 +254,8 @@ static int nfs4_stat_to_errno(int); | |||
253 | (encode_getattr_maxsz) | 254 | (encode_getattr_maxsz) |
254 | #define decode_fs_locations_maxsz \ | 255 | #define decode_fs_locations_maxsz \ |
255 | (0) | 256 | (0) |
257 | #define encode_secinfo_maxsz (op_encode_hdr_maxsz + nfs4_name_maxsz) | ||
258 | #define decode_secinfo_maxsz (op_decode_hdr_maxsz + 4 + (NFS_MAX_SECFLAVORS * (16 + GSS_OID_MAX_LEN))) | ||
256 | 259 | ||
257 | #if defined(CONFIG_NFS_V4_1) | 260 | #if defined(CONFIG_NFS_V4_1) |
258 | #define NFS4_MAX_MACHINE_NAME_LEN (64) | 261 | #define NFS4_MAX_MACHINE_NAME_LEN (64) |
@@ -324,6 +327,18 @@ static int nfs4_stat_to_errno(int); | |||
324 | #define decode_layoutget_maxsz (op_decode_hdr_maxsz + 8 + \ | 327 | #define decode_layoutget_maxsz (op_decode_hdr_maxsz + 8 + \ |
325 | decode_stateid_maxsz + \ | 328 | decode_stateid_maxsz + \ |
326 | XDR_QUADLEN(PNFS_LAYOUT_MAXSIZE)) | 329 | XDR_QUADLEN(PNFS_LAYOUT_MAXSIZE)) |
330 | #define encode_layoutcommit_maxsz (op_encode_hdr_maxsz + \ | ||
331 | 2 /* offset */ + \ | ||
332 | 2 /* length */ + \ | ||
333 | 1 /* reclaim */ + \ | ||
334 | encode_stateid_maxsz + \ | ||
335 | 1 /* new offset (true) */ + \ | ||
336 | 2 /* last byte written */ + \ | ||
337 | 1 /* nt_timechanged (false) */ + \ | ||
338 | 1 /* layoutupdate4 layout type */ + \ | ||
339 | 1 /* NULL filelayout layoutupdate4 payload */) | ||
340 | #define decode_layoutcommit_maxsz (op_decode_hdr_maxsz + 3) | ||
341 | |||
327 | #else /* CONFIG_NFS_V4_1 */ | 342 | #else /* CONFIG_NFS_V4_1 */ |
328 | #define encode_sequence_maxsz 0 | 343 | #define encode_sequence_maxsz 0 |
329 | #define decode_sequence_maxsz 0 | 344 | #define decode_sequence_maxsz 0 |
@@ -676,6 +691,14 @@ static int nfs4_stat_to_errno(int); | |||
676 | decode_putfh_maxsz + \ | 691 | decode_putfh_maxsz + \ |
677 | decode_lookup_maxsz + \ | 692 | decode_lookup_maxsz + \ |
678 | decode_fs_locations_maxsz) | 693 | decode_fs_locations_maxsz) |
694 | #define NFS4_enc_secinfo_sz (compound_encode_hdr_maxsz + \ | ||
695 | encode_sequence_maxsz + \ | ||
696 | encode_putfh_maxsz + \ | ||
697 | encode_secinfo_maxsz) | ||
698 | #define NFS4_dec_secinfo_sz (compound_decode_hdr_maxsz + \ | ||
699 | decode_sequence_maxsz + \ | ||
700 | decode_putfh_maxsz + \ | ||
701 | decode_secinfo_maxsz) | ||
679 | #if defined(CONFIG_NFS_V4_1) | 702 | #if defined(CONFIG_NFS_V4_1) |
680 | #define NFS4_enc_exchange_id_sz \ | 703 | #define NFS4_enc_exchange_id_sz \ |
681 | (compound_encode_hdr_maxsz + \ | 704 | (compound_encode_hdr_maxsz + \ |
@@ -727,6 +750,17 @@ static int nfs4_stat_to_errno(int); | |||
727 | decode_sequence_maxsz + \ | 750 | decode_sequence_maxsz + \ |
728 | decode_putfh_maxsz + \ | 751 | decode_putfh_maxsz + \ |
729 | decode_layoutget_maxsz) | 752 | decode_layoutget_maxsz) |
753 | #define NFS4_enc_layoutcommit_sz (compound_encode_hdr_maxsz + \ | ||
754 | encode_sequence_maxsz +\ | ||
755 | encode_putfh_maxsz + \ | ||
756 | encode_layoutcommit_maxsz + \ | ||
757 | encode_getattr_maxsz) | ||
758 | #define NFS4_dec_layoutcommit_sz (compound_decode_hdr_maxsz + \ | ||
759 | decode_sequence_maxsz + \ | ||
760 | decode_putfh_maxsz + \ | ||
761 | decode_layoutcommit_maxsz + \ | ||
762 | decode_getattr_maxsz) | ||
763 | |||
730 | 764 | ||
731 | const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH + | 765 | const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH + |
732 | compound_encode_hdr_maxsz + | 766 | compound_encode_hdr_maxsz + |
@@ -1620,6 +1654,18 @@ static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *state | |||
1620 | hdr->replen += decode_delegreturn_maxsz; | 1654 | hdr->replen += decode_delegreturn_maxsz; |
1621 | } | 1655 | } |
1622 | 1656 | ||
1657 | static void encode_secinfo(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | ||
1658 | { | ||
1659 | int len = name->len; | ||
1660 | __be32 *p; | ||
1661 | |||
1662 | p = reserve_space(xdr, 8 + len); | ||
1663 | *p++ = cpu_to_be32(OP_SECINFO); | ||
1664 | xdr_encode_opaque(p, name->name, len); | ||
1665 | hdr->nops++; | ||
1666 | hdr->replen += decode_secinfo_maxsz; | ||
1667 | } | ||
1668 | |||
1623 | #if defined(CONFIG_NFS_V4_1) | 1669 | #if defined(CONFIG_NFS_V4_1) |
1624 | /* NFSv4.1 operations */ | 1670 | /* NFSv4.1 operations */ |
1625 | static void encode_exchange_id(struct xdr_stream *xdr, | 1671 | static void encode_exchange_id(struct xdr_stream *xdr, |
@@ -1816,6 +1862,34 @@ encode_layoutget(struct xdr_stream *xdr, | |||
1816 | hdr->nops++; | 1862 | hdr->nops++; |
1817 | hdr->replen += decode_layoutget_maxsz; | 1863 | hdr->replen += decode_layoutget_maxsz; |
1818 | } | 1864 | } |
1865 | |||
1866 | static int | ||
1867 | encode_layoutcommit(struct xdr_stream *xdr, | ||
1868 | const struct nfs4_layoutcommit_args *args, | ||
1869 | struct compound_hdr *hdr) | ||
1870 | { | ||
1871 | __be32 *p; | ||
1872 | |||
1873 | dprintk("%s: lbw: %llu type: %d\n", __func__, args->lastbytewritten, | ||
1874 | NFS_SERVER(args->inode)->pnfs_curr_ld->id); | ||
1875 | |||
1876 | p = reserve_space(xdr, 48 + NFS4_STATEID_SIZE); | ||
1877 | *p++ = cpu_to_be32(OP_LAYOUTCOMMIT); | ||
1878 | /* Only whole file layouts */ | ||
1879 | p = xdr_encode_hyper(p, 0); /* offset */ | ||
1880 | p = xdr_encode_hyper(p, NFS4_MAX_UINT64); /* length */ | ||
1881 | *p++ = cpu_to_be32(0); /* reclaim */ | ||
1882 | p = xdr_encode_opaque_fixed(p, args->stateid.data, NFS4_STATEID_SIZE); | ||
1883 | *p++ = cpu_to_be32(1); /* newoffset = TRUE */ | ||
1884 | p = xdr_encode_hyper(p, args->lastbytewritten); | ||
1885 | *p++ = cpu_to_be32(0); /* Never send time_modify_changed */ | ||
1886 | *p++ = cpu_to_be32(NFS_SERVER(args->inode)->pnfs_curr_ld->id);/* type */ | ||
1887 | *p++ = cpu_to_be32(0); /* no file layout payload */ | ||
1888 | |||
1889 | hdr->nops++; | ||
1890 | hdr->replen += decode_layoutcommit_maxsz; | ||
1891 | return 0; | ||
1892 | } | ||
1819 | #endif /* CONFIG_NFS_V4_1 */ | 1893 | #endif /* CONFIG_NFS_V4_1 */ |
1820 | 1894 | ||
1821 | /* | 1895 | /* |
@@ -2294,7 +2368,8 @@ static void nfs4_xdr_enc_commit(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
2294 | encode_sequence(xdr, &args->seq_args, &hdr); | 2368 | encode_sequence(xdr, &args->seq_args, &hdr); |
2295 | encode_putfh(xdr, args->fh, &hdr); | 2369 | encode_putfh(xdr, args->fh, &hdr); |
2296 | encode_commit(xdr, args, &hdr); | 2370 | encode_commit(xdr, args, &hdr); |
2297 | encode_getfattr(xdr, args->bitmask, &hdr); | 2371 | if (args->bitmask) |
2372 | encode_getfattr(xdr, args->bitmask, &hdr); | ||
2298 | encode_nops(&hdr); | 2373 | encode_nops(&hdr); |
2299 | } | 2374 | } |
2300 | 2375 | ||
@@ -2465,6 +2540,24 @@ static void nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, | |||
2465 | encode_nops(&hdr); | 2540 | encode_nops(&hdr); |
2466 | } | 2541 | } |
2467 | 2542 | ||
2543 | /* | ||
2544 | * Encode SECINFO request | ||
2545 | */ | ||
2546 | static void nfs4_xdr_enc_secinfo(struct rpc_rqst *req, | ||
2547 | struct xdr_stream *xdr, | ||
2548 | struct nfs4_secinfo_arg *args) | ||
2549 | { | ||
2550 | struct compound_hdr hdr = { | ||
2551 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), | ||
2552 | }; | ||
2553 | |||
2554 | encode_compound_hdr(xdr, req, &hdr); | ||
2555 | encode_sequence(xdr, &args->seq_args, &hdr); | ||
2556 | encode_putfh(xdr, args->dir_fh, &hdr); | ||
2557 | encode_secinfo(xdr, args->name, &hdr); | ||
2558 | encode_nops(&hdr); | ||
2559 | } | ||
2560 | |||
2468 | #if defined(CONFIG_NFS_V4_1) | 2561 | #if defined(CONFIG_NFS_V4_1) |
2469 | /* | 2562 | /* |
2470 | * EXCHANGE_ID request | 2563 | * EXCHANGE_ID request |
@@ -2604,8 +2697,32 @@ static void nfs4_xdr_enc_layoutget(struct rpc_rqst *req, | |||
2604 | encode_sequence(xdr, &args->seq_args, &hdr); | 2697 | encode_sequence(xdr, &args->seq_args, &hdr); |
2605 | encode_putfh(xdr, NFS_FH(args->inode), &hdr); | 2698 | encode_putfh(xdr, NFS_FH(args->inode), &hdr); |
2606 | encode_layoutget(xdr, args, &hdr); | 2699 | encode_layoutget(xdr, args, &hdr); |
2700 | |||
2701 | xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, | ||
2702 | args->layout.pages, 0, args->layout.pglen); | ||
2703 | |||
2607 | encode_nops(&hdr); | 2704 | encode_nops(&hdr); |
2608 | } | 2705 | } |
2706 | |||
2707 | /* | ||
2708 | * Encode LAYOUTCOMMIT request | ||
2709 | */ | ||
2710 | static int nfs4_xdr_enc_layoutcommit(struct rpc_rqst *req, | ||
2711 | struct xdr_stream *xdr, | ||
2712 | struct nfs4_layoutcommit_args *args) | ||
2713 | { | ||
2714 | struct compound_hdr hdr = { | ||
2715 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), | ||
2716 | }; | ||
2717 | |||
2718 | encode_compound_hdr(xdr, req, &hdr); | ||
2719 | encode_sequence(xdr, &args->seq_args, &hdr); | ||
2720 | encode_putfh(xdr, NFS_FH(args->inode), &hdr); | ||
2721 | encode_layoutcommit(xdr, args, &hdr); | ||
2722 | encode_getfattr(xdr, args->bitmask, &hdr); | ||
2723 | encode_nops(&hdr); | ||
2724 | return 0; | ||
2725 | } | ||
2609 | #endif /* CONFIG_NFS_V4_1 */ | 2726 | #endif /* CONFIG_NFS_V4_1 */ |
2610 | 2727 | ||
2611 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) | 2728 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) |
@@ -2925,6 +3042,7 @@ static int decode_attr_error(struct xdr_stream *xdr, uint32_t *bitmap) | |||
2925 | if (unlikely(!p)) | 3042 | if (unlikely(!p)) |
2926 | goto out_overflow; | 3043 | goto out_overflow; |
2927 | bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR; | 3044 | bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR; |
3045 | return -be32_to_cpup(p); | ||
2928 | } | 3046 | } |
2929 | return 0; | 3047 | return 0; |
2930 | out_overflow: | 3048 | out_overflow: |
@@ -3912,6 +4030,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, | |||
3912 | fattr->valid |= status; | 4030 | fattr->valid |= status; |
3913 | 4031 | ||
3914 | status = decode_attr_error(xdr, bitmap); | 4032 | status = decode_attr_error(xdr, bitmap); |
4033 | if (status == -NFS4ERR_WRONGSEC) { | ||
4034 | nfs_fixup_secinfo_attributes(fattr, fh); | ||
4035 | status = 0; | ||
4036 | } | ||
3915 | if (status < 0) | 4037 | if (status < 0) |
3916 | goto xdr_error; | 4038 | goto xdr_error; |
3917 | 4039 | ||
@@ -4680,6 +4802,73 @@ static int decode_delegreturn(struct xdr_stream *xdr) | |||
4680 | return decode_op_hdr(xdr, OP_DELEGRETURN); | 4802 | return decode_op_hdr(xdr, OP_DELEGRETURN); |
4681 | } | 4803 | } |
4682 | 4804 | ||
4805 | static int decode_secinfo_gss(struct xdr_stream *xdr, struct nfs4_secinfo_flavor *flavor) | ||
4806 | { | ||
4807 | __be32 *p; | ||
4808 | |||
4809 | p = xdr_inline_decode(xdr, 4); | ||
4810 | if (unlikely(!p)) | ||
4811 | goto out_overflow; | ||
4812 | flavor->gss.sec_oid4.len = be32_to_cpup(p); | ||
4813 | if (flavor->gss.sec_oid4.len > GSS_OID_MAX_LEN) | ||
4814 | goto out_err; | ||
4815 | |||
4816 | p = xdr_inline_decode(xdr, flavor->gss.sec_oid4.len); | ||
4817 | if (unlikely(!p)) | ||
4818 | goto out_overflow; | ||
4819 | memcpy(flavor->gss.sec_oid4.data, p, flavor->gss.sec_oid4.len); | ||
4820 | |||
4821 | p = xdr_inline_decode(xdr, 8); | ||
4822 | if (unlikely(!p)) | ||
4823 | goto out_overflow; | ||
4824 | flavor->gss.qop4 = be32_to_cpup(p++); | ||
4825 | flavor->gss.service = be32_to_cpup(p); | ||
4826 | |||
4827 | return 0; | ||
4828 | |||
4829 | out_overflow: | ||
4830 | print_overflow_msg(__func__, xdr); | ||
4831 | return -EIO; | ||
4832 | out_err: | ||
4833 | return -EINVAL; | ||
4834 | } | ||
4835 | |||
4836 | static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) | ||
4837 | { | ||
4838 | struct nfs4_secinfo_flavor *sec_flavor; | ||
4839 | int status; | ||
4840 | __be32 *p; | ||
4841 | int i; | ||
4842 | |||
4843 | status = decode_op_hdr(xdr, OP_SECINFO); | ||
4844 | p = xdr_inline_decode(xdr, 4); | ||
4845 | if (unlikely(!p)) | ||
4846 | goto out_overflow; | ||
4847 | res->flavors->num_flavors = be32_to_cpup(p); | ||
4848 | |||
4849 | for (i = 0; i < res->flavors->num_flavors; i++) { | ||
4850 | sec_flavor = &res->flavors->flavors[i]; | ||
4851 | if ((char *)&sec_flavor[1] - (char *)res > PAGE_SIZE) | ||
4852 | break; | ||
4853 | |||
4854 | p = xdr_inline_decode(xdr, 4); | ||
4855 | if (unlikely(!p)) | ||
4856 | goto out_overflow; | ||
4857 | sec_flavor->flavor = be32_to_cpup(p); | ||
4858 | |||
4859 | if (sec_flavor->flavor == RPC_AUTH_GSS) { | ||
4860 | if (decode_secinfo_gss(xdr, sec_flavor)) | ||
4861 | break; | ||
4862 | } | ||
4863 | } | ||
4864 | |||
4865 | return 0; | ||
4866 | |||
4867 | out_overflow: | ||
4868 | print_overflow_msg(__func__, xdr); | ||
4869 | return -EIO; | ||
4870 | } | ||
4871 | |||
4683 | #if defined(CONFIG_NFS_V4_1) | 4872 | #if defined(CONFIG_NFS_V4_1) |
4684 | static int decode_exchange_id(struct xdr_stream *xdr, | 4873 | static int decode_exchange_id(struct xdr_stream *xdr, |
4685 | struct nfs41_exchange_id_res *res) | 4874 | struct nfs41_exchange_id_res *res) |
@@ -4950,6 +5139,9 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
4950 | __be32 *p; | 5139 | __be32 *p; |
4951 | int status; | 5140 | int status; |
4952 | u32 layout_count; | 5141 | u32 layout_count; |
5142 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | ||
5143 | struct kvec *iov = rcvbuf->head; | ||
5144 | u32 hdrlen, recvd; | ||
4953 | 5145 | ||
4954 | status = decode_op_hdr(xdr, OP_LAYOUTGET); | 5146 | status = decode_op_hdr(xdr, OP_LAYOUTGET); |
4955 | if (status) | 5147 | if (status) |
@@ -4966,17 +5158,14 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
4966 | return -EINVAL; | 5158 | return -EINVAL; |
4967 | } | 5159 | } |
4968 | 5160 | ||
4969 | p = xdr_inline_decode(xdr, 24); | 5161 | p = xdr_inline_decode(xdr, 28); |
4970 | if (unlikely(!p)) | 5162 | if (unlikely(!p)) |
4971 | goto out_overflow; | 5163 | goto out_overflow; |
4972 | p = xdr_decode_hyper(p, &res->range.offset); | 5164 | p = xdr_decode_hyper(p, &res->range.offset); |
4973 | p = xdr_decode_hyper(p, &res->range.length); | 5165 | p = xdr_decode_hyper(p, &res->range.length); |
4974 | res->range.iomode = be32_to_cpup(p++); | 5166 | res->range.iomode = be32_to_cpup(p++); |
4975 | res->type = be32_to_cpup(p++); | 5167 | res->type = be32_to_cpup(p++); |
4976 | 5168 | res->layoutp->len = be32_to_cpup(p); | |
4977 | status = decode_opaque_inline(xdr, &res->layout.len, (char **)&p); | ||
4978 | if (unlikely(status)) | ||
4979 | return status; | ||
4980 | 5169 | ||
4981 | dprintk("%s roff:%lu rlen:%lu riomode:%d, lo_type:0x%x, lo.len:%d\n", | 5170 | dprintk("%s roff:%lu rlen:%lu riomode:%d, lo_type:0x%x, lo.len:%d\n", |
4982 | __func__, | 5171 | __func__, |
@@ -4984,12 +5173,18 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
4984 | (unsigned long)res->range.length, | 5173 | (unsigned long)res->range.length, |
4985 | res->range.iomode, | 5174 | res->range.iomode, |
4986 | res->type, | 5175 | res->type, |
4987 | res->layout.len); | 5176 | res->layoutp->len); |
4988 | 5177 | ||
4989 | /* nfs4_proc_layoutget allocated a single page */ | 5178 | hdrlen = (u8 *) xdr->p - (u8 *) iov->iov_base; |
4990 | if (res->layout.len > PAGE_SIZE) | 5179 | recvd = req->rq_rcv_buf.len - hdrlen; |
4991 | return -ENOMEM; | 5180 | if (res->layoutp->len > recvd) { |
4992 | memcpy(res->layout.buf, p, res->layout.len); | 5181 | dprintk("NFS: server cheating in layoutget reply: " |
5182 | "layout len %u > recvd %u\n", | ||
5183 | res->layoutp->len, recvd); | ||
5184 | return -EINVAL; | ||
5185 | } | ||
5186 | |||
5187 | xdr_read_pages(xdr, res->layoutp->len); | ||
4993 | 5188 | ||
4994 | if (layout_count > 1) { | 5189 | if (layout_count > 1) { |
4995 | /* We only handle a length one array at the moment. Any | 5190 | /* We only handle a length one array at the moment. Any |
@@ -5006,6 +5201,35 @@ out_overflow: | |||
5006 | print_overflow_msg(__func__, xdr); | 5201 | print_overflow_msg(__func__, xdr); |
5007 | return -EIO; | 5202 | return -EIO; |
5008 | } | 5203 | } |
5204 | |||
5205 | static int decode_layoutcommit(struct xdr_stream *xdr, | ||
5206 | struct rpc_rqst *req, | ||
5207 | struct nfs4_layoutcommit_res *res) | ||
5208 | { | ||
5209 | __be32 *p; | ||
5210 | __u32 sizechanged; | ||
5211 | int status; | ||
5212 | |||
5213 | status = decode_op_hdr(xdr, OP_LAYOUTCOMMIT); | ||
5214 | if (status) | ||
5215 | return status; | ||
5216 | |||
5217 | p = xdr_inline_decode(xdr, 4); | ||
5218 | if (unlikely(!p)) | ||
5219 | goto out_overflow; | ||
5220 | sizechanged = be32_to_cpup(p); | ||
5221 | |||
5222 | if (sizechanged) { | ||
5223 | /* throw away new size */ | ||
5224 | p = xdr_inline_decode(xdr, 8); | ||
5225 | if (unlikely(!p)) | ||
5226 | goto out_overflow; | ||
5227 | } | ||
5228 | return 0; | ||
5229 | out_overflow: | ||
5230 | print_overflow_msg(__func__, xdr); | ||
5231 | return -EIO; | ||
5232 | } | ||
5009 | #endif /* CONFIG_NFS_V4_1 */ | 5233 | #endif /* CONFIG_NFS_V4_1 */ |
5010 | 5234 | ||
5011 | /* | 5235 | /* |
@@ -5723,8 +5947,9 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
5723 | status = decode_commit(xdr, res); | 5947 | status = decode_commit(xdr, res); |
5724 | if (status) | 5948 | if (status) |
5725 | goto out; | 5949 | goto out; |
5726 | decode_getfattr(xdr, res->fattr, res->server, | 5950 | if (res->fattr) |
5727 | !RPC_IS_ASYNC(rqstp->rq_task)); | 5951 | decode_getfattr(xdr, res->fattr, res->server, |
5952 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
5728 | out: | 5953 | out: |
5729 | return status; | 5954 | return status; |
5730 | } | 5955 | } |
@@ -5919,6 +6144,32 @@ out: | |||
5919 | return status; | 6144 | return status; |
5920 | } | 6145 | } |
5921 | 6146 | ||
6147 | /* | ||
6148 | * Decode SECINFO response | ||
6149 | */ | ||
6150 | static int nfs4_xdr_dec_secinfo(struct rpc_rqst *rqstp, | ||
6151 | struct xdr_stream *xdr, | ||
6152 | struct nfs4_secinfo_res *res) | ||
6153 | { | ||
6154 | struct compound_hdr hdr; | ||
6155 | int status; | ||
6156 | |||
6157 | status = decode_compound_hdr(xdr, &hdr); | ||
6158 | if (status) | ||
6159 | goto out; | ||
6160 | status = decode_sequence(xdr, &res->seq_res, rqstp); | ||
6161 | if (status) | ||
6162 | goto out; | ||
6163 | status = decode_putfh(xdr); | ||
6164 | if (status) | ||
6165 | goto out; | ||
6166 | status = decode_secinfo(xdr, res); | ||
6167 | if (status) | ||
6168 | goto out; | ||
6169 | out: | ||
6170 | return status; | ||
6171 | } | ||
6172 | |||
5922 | #if defined(CONFIG_NFS_V4_1) | 6173 | #if defined(CONFIG_NFS_V4_1) |
5923 | /* | 6174 | /* |
5924 | * Decode EXCHANGE_ID response | 6175 | * Decode EXCHANGE_ID response |
@@ -6066,6 +6317,34 @@ static int nfs4_xdr_dec_layoutget(struct rpc_rqst *rqstp, | |||
6066 | out: | 6317 | out: |
6067 | return status; | 6318 | return status; |
6068 | } | 6319 | } |
6320 | |||
6321 | /* | ||
6322 | * Decode LAYOUTCOMMIT response | ||
6323 | */ | ||
6324 | static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp, | ||
6325 | struct xdr_stream *xdr, | ||
6326 | struct nfs4_layoutcommit_res *res) | ||
6327 | { | ||
6328 | struct compound_hdr hdr; | ||
6329 | int status; | ||
6330 | |||
6331 | status = decode_compound_hdr(xdr, &hdr); | ||
6332 | if (status) | ||
6333 | goto out; | ||
6334 | status = decode_sequence(xdr, &res->seq_res, rqstp); | ||
6335 | if (status) | ||
6336 | goto out; | ||
6337 | status = decode_putfh(xdr); | ||
6338 | if (status) | ||
6339 | goto out; | ||
6340 | status = decode_layoutcommit(xdr, rqstp, res); | ||
6341 | if (status) | ||
6342 | goto out; | ||
6343 | decode_getfattr(xdr, res->fattr, res->server, | ||
6344 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
6345 | out: | ||
6346 | return status; | ||
6347 | } | ||
6069 | #endif /* CONFIG_NFS_V4_1 */ | 6348 | #endif /* CONFIG_NFS_V4_1 */ |
6070 | 6349 | ||
6071 | /** | 6350 | /** |
@@ -6180,10 +6459,6 @@ static struct { | |||
6180 | { NFS4ERR_SYMLINK, -ELOOP }, | 6459 | { NFS4ERR_SYMLINK, -ELOOP }, |
6181 | { NFS4ERR_OP_ILLEGAL, -EOPNOTSUPP }, | 6460 | { NFS4ERR_OP_ILLEGAL, -EOPNOTSUPP }, |
6182 | { NFS4ERR_DEADLOCK, -EDEADLK }, | 6461 | { NFS4ERR_DEADLOCK, -EDEADLK }, |
6183 | { NFS4ERR_WRONGSEC, -EPERM }, /* FIXME: this needs | ||
6184 | * to be handled by a | ||
6185 | * middle-layer. | ||
6186 | */ | ||
6187 | { -1, -EIO } | 6462 | { -1, -EIO } |
6188 | }; | 6463 | }; |
6189 | 6464 | ||
@@ -6258,6 +6533,7 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
6258 | PROC(SETACL, enc_setacl, dec_setacl), | 6533 | PROC(SETACL, enc_setacl, dec_setacl), |
6259 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), | 6534 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), |
6260 | PROC(RELEASE_LOCKOWNER, enc_release_lockowner, dec_release_lockowner), | 6535 | PROC(RELEASE_LOCKOWNER, enc_release_lockowner, dec_release_lockowner), |
6536 | PROC(SECINFO, enc_secinfo, dec_secinfo), | ||
6261 | #if defined(CONFIG_NFS_V4_1) | 6537 | #if defined(CONFIG_NFS_V4_1) |
6262 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), | 6538 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), |
6263 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), | 6539 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), |
@@ -6267,6 +6543,7 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
6267 | PROC(RECLAIM_COMPLETE, enc_reclaim_complete, dec_reclaim_complete), | 6543 | PROC(RECLAIM_COMPLETE, enc_reclaim_complete, dec_reclaim_complete), |
6268 | PROC(GETDEVICEINFO, enc_getdeviceinfo, dec_getdeviceinfo), | 6544 | PROC(GETDEVICEINFO, enc_getdeviceinfo, dec_getdeviceinfo), |
6269 | PROC(LAYOUTGET, enc_layoutget, dec_layoutget), | 6545 | PROC(LAYOUTGET, enc_layoutget, dec_layoutget), |
6546 | PROC(LAYOUTCOMMIT, enc_layoutcommit, dec_layoutcommit), | ||
6270 | #endif /* CONFIG_NFS_V4_1 */ | 6547 | #endif /* CONFIG_NFS_V4_1 */ |
6271 | }; | 6548 | }; |
6272 | 6549 | ||
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 23e794410669..87a593c2b055 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -223,6 +223,7 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc, | |||
223 | desc->pg_count = 0; | 223 | desc->pg_count = 0; |
224 | desc->pg_bsize = bsize; | 224 | desc->pg_bsize = bsize; |
225 | desc->pg_base = 0; | 225 | desc->pg_base = 0; |
226 | desc->pg_moreio = 0; | ||
226 | desc->pg_inode = inode; | 227 | desc->pg_inode = inode; |
227 | desc->pg_doio = doio; | 228 | desc->pg_doio = doio; |
228 | desc->pg_ioflags = io_flags; | 229 | desc->pg_ioflags = io_flags; |
@@ -335,9 +336,11 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | |||
335 | struct nfs_page *req) | 336 | struct nfs_page *req) |
336 | { | 337 | { |
337 | while (!nfs_pageio_do_add_request(desc, req)) { | 338 | while (!nfs_pageio_do_add_request(desc, req)) { |
339 | desc->pg_moreio = 1; | ||
338 | nfs_pageio_doio(desc); | 340 | nfs_pageio_doio(desc); |
339 | if (desc->pg_error < 0) | 341 | if (desc->pg_error < 0) |
340 | return 0; | 342 | return 0; |
343 | desc->pg_moreio = 0; | ||
341 | } | 344 | } |
342 | return 1; | 345 | return 1; |
343 | } | 346 | } |
@@ -395,6 +398,7 @@ int nfs_scan_list(struct nfs_inode *nfsi, | |||
395 | pgoff_t idx_end; | 398 | pgoff_t idx_end; |
396 | int found, i; | 399 | int found, i; |
397 | int res; | 400 | int res; |
401 | struct list_head *list; | ||
398 | 402 | ||
399 | res = 0; | 403 | res = 0; |
400 | if (npages == 0) | 404 | if (npages == 0) |
@@ -415,10 +419,10 @@ int nfs_scan_list(struct nfs_inode *nfsi, | |||
415 | idx_start = req->wb_index + 1; | 419 | idx_start = req->wb_index + 1; |
416 | if (nfs_set_page_tag_locked(req)) { | 420 | if (nfs_set_page_tag_locked(req)) { |
417 | kref_get(&req->wb_kref); | 421 | kref_get(&req->wb_kref); |
418 | nfs_list_remove_request(req); | ||
419 | radix_tree_tag_clear(&nfsi->nfs_page_tree, | 422 | radix_tree_tag_clear(&nfsi->nfs_page_tree, |
420 | req->wb_index, tag); | 423 | req->wb_index, tag); |
421 | nfs_list_add_request(req, dst); | 424 | list = pnfs_choose_commit_list(req, dst); |
425 | nfs_list_add_request(req, list); | ||
422 | res++; | 426 | res++; |
423 | if (res == INT_MAX) | 427 | if (res == INT_MAX) |
424 | goto out; | 428 | goto out; |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index f38813a0a295..d9ab97269ce6 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -259,6 +259,7 @@ put_lseg(struct pnfs_layout_segment *lseg) | |||
259 | pnfs_free_lseg_list(&free_me); | 259 | pnfs_free_lseg_list(&free_me); |
260 | } | 260 | } |
261 | } | 261 | } |
262 | EXPORT_SYMBOL_GPL(put_lseg); | ||
262 | 263 | ||
263 | static bool | 264 | static bool |
264 | should_free_lseg(u32 lseg_iomode, u32 recall_iomode) | 265 | should_free_lseg(u32 lseg_iomode, u32 recall_iomode) |
@@ -471,6 +472,9 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
471 | struct nfs_server *server = NFS_SERVER(ino); | 472 | struct nfs_server *server = NFS_SERVER(ino); |
472 | struct nfs4_layoutget *lgp; | 473 | struct nfs4_layoutget *lgp; |
473 | struct pnfs_layout_segment *lseg = NULL; | 474 | struct pnfs_layout_segment *lseg = NULL; |
475 | struct page **pages = NULL; | ||
476 | int i; | ||
477 | u32 max_resp_sz, max_pages; | ||
474 | 478 | ||
475 | dprintk("--> %s\n", __func__); | 479 | dprintk("--> %s\n", __func__); |
476 | 480 | ||
@@ -478,6 +482,21 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
478 | lgp = kzalloc(sizeof(*lgp), GFP_KERNEL); | 482 | lgp = kzalloc(sizeof(*lgp), GFP_KERNEL); |
479 | if (lgp == NULL) | 483 | if (lgp == NULL) |
480 | return NULL; | 484 | return NULL; |
485 | |||
486 | /* allocate pages for xdr post processing */ | ||
487 | max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; | ||
488 | max_pages = max_resp_sz >> PAGE_SHIFT; | ||
489 | |||
490 | pages = kzalloc(max_pages * sizeof(struct page *), GFP_KERNEL); | ||
491 | if (!pages) | ||
492 | goto out_err_free; | ||
493 | |||
494 | for (i = 0; i < max_pages; i++) { | ||
495 | pages[i] = alloc_page(GFP_KERNEL); | ||
496 | if (!pages[i]) | ||
497 | goto out_err_free; | ||
498 | } | ||
499 | |||
481 | lgp->args.minlength = NFS4_MAX_UINT64; | 500 | lgp->args.minlength = NFS4_MAX_UINT64; |
482 | lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE; | 501 | lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE; |
483 | lgp->args.range.iomode = iomode; | 502 | lgp->args.range.iomode = iomode; |
@@ -486,6 +505,8 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
486 | lgp->args.type = server->pnfs_curr_ld->id; | 505 | lgp->args.type = server->pnfs_curr_ld->id; |
487 | lgp->args.inode = ino; | 506 | lgp->args.inode = ino; |
488 | lgp->args.ctx = get_nfs_open_context(ctx); | 507 | lgp->args.ctx = get_nfs_open_context(ctx); |
508 | lgp->args.layout.pages = pages; | ||
509 | lgp->args.layout.pglen = max_pages * PAGE_SIZE; | ||
489 | lgp->lsegpp = &lseg; | 510 | lgp->lsegpp = &lseg; |
490 | 511 | ||
491 | /* Synchronously retrieve layout information from server and | 512 | /* Synchronously retrieve layout information from server and |
@@ -496,7 +517,26 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
496 | /* remember that LAYOUTGET failed and suspend trying */ | 517 | /* remember that LAYOUTGET failed and suspend trying */ |
497 | set_bit(lo_fail_bit(iomode), &lo->plh_flags); | 518 | set_bit(lo_fail_bit(iomode), &lo->plh_flags); |
498 | } | 519 | } |
520 | |||
521 | /* free xdr pages */ | ||
522 | for (i = 0; i < max_pages; i++) | ||
523 | __free_page(pages[i]); | ||
524 | kfree(pages); | ||
525 | |||
499 | return lseg; | 526 | return lseg; |
527 | |||
528 | out_err_free: | ||
529 | /* free any allocated xdr pages, lgp as it's not used */ | ||
530 | if (pages) { | ||
531 | for (i = 0; i < max_pages; i++) { | ||
532 | if (!pages[i]) | ||
533 | break; | ||
534 | __free_page(pages[i]); | ||
535 | } | ||
536 | kfree(pages); | ||
537 | } | ||
538 | kfree(lgp); | ||
539 | return NULL; | ||
500 | } | 540 | } |
501 | 541 | ||
502 | bool pnfs_roc(struct inode *ino) | 542 | bool pnfs_roc(struct inode *ino) |
@@ -945,3 +985,105 @@ pnfs_try_to_read_data(struct nfs_read_data *rdata, | |||
945 | dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); | 985 | dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); |
946 | return trypnfs; | 986 | return trypnfs; |
947 | } | 987 | } |
988 | |||
989 | /* | ||
990 | * Currently there is only one (whole file) write lseg. | ||
991 | */ | ||
992 | static struct pnfs_layout_segment *pnfs_list_write_lseg(struct inode *inode) | ||
993 | { | ||
994 | struct pnfs_layout_segment *lseg, *rv = NULL; | ||
995 | |||
996 | list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) | ||
997 | if (lseg->pls_range.iomode == IOMODE_RW) | ||
998 | rv = lseg; | ||
999 | return rv; | ||
1000 | } | ||
1001 | |||
1002 | void | ||
1003 | pnfs_set_layoutcommit(struct nfs_write_data *wdata) | ||
1004 | { | ||
1005 | struct nfs_inode *nfsi = NFS_I(wdata->inode); | ||
1006 | loff_t end_pos = wdata->args.offset + wdata->res.count; | ||
1007 | |||
1008 | spin_lock(&nfsi->vfs_inode.i_lock); | ||
1009 | if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) { | ||
1010 | /* references matched in nfs4_layoutcommit_release */ | ||
1011 | get_lseg(wdata->lseg); | ||
1012 | wdata->lseg->pls_lc_cred = | ||
1013 | get_rpccred(wdata->args.context->state->owner->so_cred); | ||
1014 | mark_inode_dirty_sync(wdata->inode); | ||
1015 | dprintk("%s: Set layoutcommit for inode %lu ", | ||
1016 | __func__, wdata->inode->i_ino); | ||
1017 | } | ||
1018 | if (end_pos > wdata->lseg->pls_end_pos) | ||
1019 | wdata->lseg->pls_end_pos = end_pos; | ||
1020 | spin_unlock(&nfsi->vfs_inode.i_lock); | ||
1021 | } | ||
1022 | EXPORT_SYMBOL_GPL(pnfs_set_layoutcommit); | ||
1023 | |||
1024 | /* | ||
1025 | * For the LAYOUT4_NFSV4_1_FILES layout type, NFS_DATA_SYNC WRITEs and | ||
1026 | * NFS_UNSTABLE WRITEs with a COMMIT to data servers must store enough | ||
1027 | * data to disk to allow the server to recover the data if it crashes. | ||
1028 | * LAYOUTCOMMIT is only needed when the NFL4_UFLG_COMMIT_THRU_MDS flag | ||
1029 | * is off, and a COMMIT is sent to a data server, or | ||
1030 | * if WRITEs to a data server return NFS_DATA_SYNC. | ||
1031 | */ | ||
1032 | int | ||
1033 | pnfs_layoutcommit_inode(struct inode *inode, bool sync) | ||
1034 | { | ||
1035 | struct nfs4_layoutcommit_data *data; | ||
1036 | struct nfs_inode *nfsi = NFS_I(inode); | ||
1037 | struct pnfs_layout_segment *lseg; | ||
1038 | struct rpc_cred *cred; | ||
1039 | loff_t end_pos; | ||
1040 | int status = 0; | ||
1041 | |||
1042 | dprintk("--> %s inode %lu\n", __func__, inode->i_ino); | ||
1043 | |||
1044 | if (!test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) | ||
1045 | return 0; | ||
1046 | |||
1047 | /* Note kzalloc ensures data->res.seq_res.sr_slot == NULL */ | ||
1048 | data = kzalloc(sizeof(*data), GFP_NOFS); | ||
1049 | if (!data) { | ||
1050 | mark_inode_dirty_sync(inode); | ||
1051 | status = -ENOMEM; | ||
1052 | goto out; | ||
1053 | } | ||
1054 | |||
1055 | spin_lock(&inode->i_lock); | ||
1056 | if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) { | ||
1057 | spin_unlock(&inode->i_lock); | ||
1058 | kfree(data); | ||
1059 | goto out; | ||
1060 | } | ||
1061 | /* | ||
1062 | * Currently only one (whole file) write lseg which is referenced | ||
1063 | * in pnfs_set_layoutcommit and will be found. | ||
1064 | */ | ||
1065 | lseg = pnfs_list_write_lseg(inode); | ||
1066 | |||
1067 | end_pos = lseg->pls_end_pos; | ||
1068 | cred = lseg->pls_lc_cred; | ||
1069 | lseg->pls_end_pos = 0; | ||
1070 | lseg->pls_lc_cred = NULL; | ||
1071 | |||
1072 | memcpy(&data->args.stateid.data, nfsi->layout->plh_stateid.data, | ||
1073 | sizeof(nfsi->layout->plh_stateid.data)); | ||
1074 | spin_unlock(&inode->i_lock); | ||
1075 | |||
1076 | data->args.inode = inode; | ||
1077 | data->lseg = lseg; | ||
1078 | data->cred = cred; | ||
1079 | nfs_fattr_init(&data->fattr); | ||
1080 | data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask; | ||
1081 | data->res.fattr = &data->fattr; | ||
1082 | data->args.lastbytewritten = end_pos - 1; | ||
1083 | data->res.server = NFS_SERVER(inode); | ||
1084 | |||
1085 | status = nfs4_proc_layoutcommit(data, sync); | ||
1086 | out: | ||
1087 | dprintk("<-- %s status %d\n", __func__, status); | ||
1088 | return status; | ||
1089 | } | ||
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 6380b9405bcd..bc4827202e7a 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
@@ -43,6 +43,8 @@ struct pnfs_layout_segment { | |||
43 | atomic_t pls_refcount; | 43 | atomic_t pls_refcount; |
44 | unsigned long pls_flags; | 44 | unsigned long pls_flags; |
45 | struct pnfs_layout_hdr *pls_layout; | 45 | struct pnfs_layout_hdr *pls_layout; |
46 | struct rpc_cred *pls_lc_cred; /* LAYOUTCOMMIT credential */ | ||
47 | loff_t pls_end_pos; /* LAYOUTCOMMIT write end */ | ||
46 | }; | 48 | }; |
47 | 49 | ||
48 | enum pnfs_try_status { | 50 | enum pnfs_try_status { |
@@ -74,6 +76,13 @@ struct pnfs_layoutdriver_type { | |||
74 | /* test for nfs page cache coalescing */ | 76 | /* test for nfs page cache coalescing */ |
75 | int (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *); | 77 | int (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *); |
76 | 78 | ||
79 | /* Returns true if layoutdriver wants to divert this request to | ||
80 | * driver's commit routine. | ||
81 | */ | ||
82 | bool (*mark_pnfs_commit)(struct pnfs_layout_segment *lseg); | ||
83 | struct list_head * (*choose_commit_list) (struct nfs_page *req); | ||
84 | int (*commit_pagelist)(struct inode *inode, struct list_head *mds_pages, int how); | ||
85 | |||
77 | /* | 86 | /* |
78 | * Return PNFS_ATTEMPTED to indicate the layout code has attempted | 87 | * Return PNFS_ATTEMPTED to indicate the layout code has attempted |
79 | * I/O, else return PNFS_NOT_ATTEMPTED to fall back to normal NFS | 88 | * I/O, else return PNFS_NOT_ATTEMPTED to fall back to normal NFS |
@@ -100,7 +109,6 @@ struct pnfs_device { | |||
100 | unsigned int layout_type; | 109 | unsigned int layout_type; |
101 | unsigned int mincount; | 110 | unsigned int mincount; |
102 | struct page **pages; | 111 | struct page **pages; |
103 | void *area; | ||
104 | unsigned int pgbase; | 112 | unsigned int pgbase; |
105 | unsigned int pglen; | 113 | unsigned int pglen; |
106 | }; | 114 | }; |
@@ -145,7 +153,8 @@ bool pnfs_roc(struct inode *ino); | |||
145 | void pnfs_roc_release(struct inode *ino); | 153 | void pnfs_roc_release(struct inode *ino); |
146 | void pnfs_roc_set_barrier(struct inode *ino, u32 barrier); | 154 | void pnfs_roc_set_barrier(struct inode *ino, u32 barrier); |
147 | bool pnfs_roc_drain(struct inode *ino, u32 *barrier); | 155 | bool pnfs_roc_drain(struct inode *ino, u32 *barrier); |
148 | 156 | void pnfs_set_layoutcommit(struct nfs_write_data *wdata); | |
157 | int pnfs_layoutcommit_inode(struct inode *inode, bool sync); | ||
149 | 158 | ||
150 | static inline int lo_fail_bit(u32 iomode) | 159 | static inline int lo_fail_bit(u32 iomode) |
151 | { | 160 | { |
@@ -169,6 +178,51 @@ static inline int pnfs_enabled_sb(struct nfs_server *nfss) | |||
169 | return nfss->pnfs_curr_ld != NULL; | 178 | return nfss->pnfs_curr_ld != NULL; |
170 | } | 179 | } |
171 | 180 | ||
181 | static inline void | ||
182 | pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) | ||
183 | { | ||
184 | if (lseg) { | ||
185 | struct pnfs_layoutdriver_type *ld; | ||
186 | |||
187 | ld = NFS_SERVER(req->wb_page->mapping->host)->pnfs_curr_ld; | ||
188 | if (ld->mark_pnfs_commit && ld->mark_pnfs_commit(lseg)) { | ||
189 | set_bit(PG_PNFS_COMMIT, &req->wb_flags); | ||
190 | req->wb_commit_lseg = get_lseg(lseg); | ||
191 | } | ||
192 | } | ||
193 | } | ||
194 | |||
195 | static inline int | ||
196 | pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how) | ||
197 | { | ||
198 | if (!test_and_clear_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags)) | ||
199 | return PNFS_NOT_ATTEMPTED; | ||
200 | return NFS_SERVER(inode)->pnfs_curr_ld->commit_pagelist(inode, mds_pages, how); | ||
201 | } | ||
202 | |||
203 | static inline struct list_head * | ||
204 | pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds) | ||
205 | { | ||
206 | struct list_head *rv; | ||
207 | |||
208 | if (test_and_clear_bit(PG_PNFS_COMMIT, &req->wb_flags)) { | ||
209 | struct inode *inode = req->wb_commit_lseg->pls_layout->plh_inode; | ||
210 | |||
211 | set_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags); | ||
212 | rv = NFS_SERVER(inode)->pnfs_curr_ld->choose_commit_list(req); | ||
213 | /* matched by ref taken when PG_PNFS_COMMIT is set */ | ||
214 | put_lseg(req->wb_commit_lseg); | ||
215 | } else | ||
216 | rv = mds; | ||
217 | return rv; | ||
218 | } | ||
219 | |||
220 | static inline void pnfs_clear_request_commit(struct nfs_page *req) | ||
221 | { | ||
222 | if (test_and_clear_bit(PG_PNFS_COMMIT, &req->wb_flags)) | ||
223 | put_lseg(req->wb_commit_lseg); | ||
224 | } | ||
225 | |||
172 | #else /* CONFIG_NFS_V4_1 */ | 226 | #else /* CONFIG_NFS_V4_1 */ |
173 | 227 | ||
174 | static inline void pnfs_destroy_all_layouts(struct nfs_client *clp) | 228 | static inline void pnfs_destroy_all_layouts(struct nfs_client *clp) |
@@ -252,6 +306,31 @@ pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *ino) | |||
252 | pgio->pg_test = NULL; | 306 | pgio->pg_test = NULL; |
253 | } | 307 | } |
254 | 308 | ||
309 | static inline void | ||
310 | pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) | ||
311 | { | ||
312 | } | ||
313 | |||
314 | static inline int | ||
315 | pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how) | ||
316 | { | ||
317 | return PNFS_NOT_ATTEMPTED; | ||
318 | } | ||
319 | |||
320 | static inline struct list_head * | ||
321 | pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds) | ||
322 | { | ||
323 | return mds; | ||
324 | } | ||
325 | |||
326 | static inline void pnfs_clear_request_commit(struct nfs_page *req) | ||
327 | { | ||
328 | } | ||
329 | |||
330 | static inline int pnfs_layoutcommit_inode(struct inode *inode, bool sync) | ||
331 | { | ||
332 | return 0; | ||
333 | } | ||
255 | #endif /* CONFIG_NFS_V4_1 */ | 334 | #endif /* CONFIG_NFS_V4_1 */ |
256 | 335 | ||
257 | #endif /* FS_NFS_PNFS_H */ | 336 | #endif /* FS_NFS_PNFS_H */ |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index b8ec170f2a0f..ac40b8535d7e 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -177,7 +177,7 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
177 | } | 177 | } |
178 | 178 | ||
179 | static int | 179 | static int |
180 | nfs_proc_lookup(struct inode *dir, struct qstr *name, | 180 | nfs_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qstr *name, |
181 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 181 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
182 | { | 182 | { |
183 | struct nfs_diropargs arg = { | 183 | struct nfs_diropargs arg = { |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 47a3ad63e0d5..85d75254328e 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -59,6 +59,7 @@ struct nfs_write_data *nfs_commitdata_alloc(void) | |||
59 | } | 59 | } |
60 | return p; | 60 | return p; |
61 | } | 61 | } |
62 | EXPORT_SYMBOL_GPL(nfs_commitdata_alloc); | ||
62 | 63 | ||
63 | void nfs_commit_free(struct nfs_write_data *p) | 64 | void nfs_commit_free(struct nfs_write_data *p) |
64 | { | 65 | { |
@@ -66,6 +67,7 @@ void nfs_commit_free(struct nfs_write_data *p) | |||
66 | kfree(p->pagevec); | 67 | kfree(p->pagevec); |
67 | mempool_free(p, nfs_commit_mempool); | 68 | mempool_free(p, nfs_commit_mempool); |
68 | } | 69 | } |
70 | EXPORT_SYMBOL_GPL(nfs_commit_free); | ||
69 | 71 | ||
70 | struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | 72 | struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) |
71 | { | 73 | { |
@@ -179,8 +181,8 @@ static int wb_priority(struct writeback_control *wbc) | |||
179 | if (wbc->for_reclaim) | 181 | if (wbc->for_reclaim) |
180 | return FLUSH_HIGHPRI | FLUSH_STABLE; | 182 | return FLUSH_HIGHPRI | FLUSH_STABLE; |
181 | if (wbc->for_kupdate || wbc->for_background) | 183 | if (wbc->for_kupdate || wbc->for_background) |
182 | return FLUSH_LOWPRI; | 184 | return FLUSH_LOWPRI | FLUSH_COND_STABLE; |
183 | return 0; | 185 | return FLUSH_COND_STABLE; |
184 | } | 186 | } |
185 | 187 | ||
186 | /* | 188 | /* |
@@ -441,7 +443,7 @@ nfs_mark_request_dirty(struct nfs_page *req) | |||
441 | * Add a request to the inode's commit list. | 443 | * Add a request to the inode's commit list. |
442 | */ | 444 | */ |
443 | static void | 445 | static void |
444 | nfs_mark_request_commit(struct nfs_page *req) | 446 | nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) |
445 | { | 447 | { |
446 | struct inode *inode = req->wb_context->path.dentry->d_inode; | 448 | struct inode *inode = req->wb_context->path.dentry->d_inode; |
447 | struct nfs_inode *nfsi = NFS_I(inode); | 449 | struct nfs_inode *nfsi = NFS_I(inode); |
@@ -453,6 +455,7 @@ nfs_mark_request_commit(struct nfs_page *req) | |||
453 | NFS_PAGE_TAG_COMMIT); | 455 | NFS_PAGE_TAG_COMMIT); |
454 | nfsi->ncommit++; | 456 | nfsi->ncommit++; |
455 | spin_unlock(&inode->i_lock); | 457 | spin_unlock(&inode->i_lock); |
458 | pnfs_mark_request_commit(req, lseg); | ||
456 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 459 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
457 | inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE); | 460 | inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE); |
458 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | 461 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); |
@@ -474,14 +477,18 @@ nfs_clear_request_commit(struct nfs_page *req) | |||
474 | static inline | 477 | static inline |
475 | int nfs_write_need_commit(struct nfs_write_data *data) | 478 | int nfs_write_need_commit(struct nfs_write_data *data) |
476 | { | 479 | { |
477 | return data->verf.committed != NFS_FILE_SYNC; | 480 | if (data->verf.committed == NFS_DATA_SYNC) |
481 | return data->lseg == NULL; | ||
482 | else | ||
483 | return data->verf.committed != NFS_FILE_SYNC; | ||
478 | } | 484 | } |
479 | 485 | ||
480 | static inline | 486 | static inline |
481 | int nfs_reschedule_unstable_write(struct nfs_page *req) | 487 | int nfs_reschedule_unstable_write(struct nfs_page *req, |
488 | struct nfs_write_data *data) | ||
482 | { | 489 | { |
483 | if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) { | 490 | if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) { |
484 | nfs_mark_request_commit(req); | 491 | nfs_mark_request_commit(req, data->lseg); |
485 | return 1; | 492 | return 1; |
486 | } | 493 | } |
487 | if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { | 494 | if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { |
@@ -492,7 +499,7 @@ int nfs_reschedule_unstable_write(struct nfs_page *req) | |||
492 | } | 499 | } |
493 | #else | 500 | #else |
494 | static inline void | 501 | static inline void |
495 | nfs_mark_request_commit(struct nfs_page *req) | 502 | nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) |
496 | { | 503 | { |
497 | } | 504 | } |
498 | 505 | ||
@@ -509,7 +516,8 @@ int nfs_write_need_commit(struct nfs_write_data *data) | |||
509 | } | 516 | } |
510 | 517 | ||
511 | static inline | 518 | static inline |
512 | int nfs_reschedule_unstable_write(struct nfs_page *req) | 519 | int nfs_reschedule_unstable_write(struct nfs_page *req, |
520 | struct nfs_write_data *data) | ||
513 | { | 521 | { |
514 | return 0; | 522 | return 0; |
515 | } | 523 | } |
@@ -612,9 +620,11 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode, | |||
612 | } | 620 | } |
613 | 621 | ||
614 | if (nfs_clear_request_commit(req) && | 622 | if (nfs_clear_request_commit(req) && |
615 | radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree, | 623 | radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree, |
616 | req->wb_index, NFS_PAGE_TAG_COMMIT) != NULL) | 624 | req->wb_index, NFS_PAGE_TAG_COMMIT) != NULL) { |
617 | NFS_I(inode)->ncommit--; | 625 | NFS_I(inode)->ncommit--; |
626 | pnfs_clear_request_commit(req); | ||
627 | } | ||
618 | 628 | ||
619 | /* Okay, the request matches. Update the region */ | 629 | /* Okay, the request matches. Update the region */ |
620 | if (offset < req->wb_offset) { | 630 | if (offset < req->wb_offset) { |
@@ -762,11 +772,12 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
762 | return status; | 772 | return status; |
763 | } | 773 | } |
764 | 774 | ||
765 | static void nfs_writepage_release(struct nfs_page *req) | 775 | static void nfs_writepage_release(struct nfs_page *req, |
776 | struct nfs_write_data *data) | ||
766 | { | 777 | { |
767 | struct page *page = req->wb_page; | 778 | struct page *page = req->wb_page; |
768 | 779 | ||
769 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) | 780 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req, data)) |
770 | nfs_inode_remove_request(req); | 781 | nfs_inode_remove_request(req); |
771 | nfs_clear_page_tag_locked(req); | 782 | nfs_clear_page_tag_locked(req); |
772 | nfs_end_page_writeback(page); | 783 | nfs_end_page_writeback(page); |
@@ -863,7 +874,7 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
863 | data->args.context = get_nfs_open_context(req->wb_context); | 874 | data->args.context = get_nfs_open_context(req->wb_context); |
864 | data->args.lock_context = req->wb_lock_context; | 875 | data->args.lock_context = req->wb_lock_context; |
865 | data->args.stable = NFS_UNSTABLE; | 876 | data->args.stable = NFS_UNSTABLE; |
866 | if (how & FLUSH_STABLE) { | 877 | if (how & (FLUSH_STABLE | FLUSH_COND_STABLE)) { |
867 | data->args.stable = NFS_DATA_SYNC; | 878 | data->args.stable = NFS_DATA_SYNC; |
868 | if (!nfs_need_commit(NFS_I(inode))) | 879 | if (!nfs_need_commit(NFS_I(inode))) |
869 | data->args.stable = NFS_FILE_SYNC; | 880 | data->args.stable = NFS_FILE_SYNC; |
@@ -912,6 +923,12 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc) | |||
912 | 923 | ||
913 | nfs_list_remove_request(req); | 924 | nfs_list_remove_request(req); |
914 | 925 | ||
926 | if ((desc->pg_ioflags & FLUSH_COND_STABLE) && | ||
927 | (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit || | ||
928 | desc->pg_count > wsize)) | ||
929 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; | ||
930 | |||
931 | |||
915 | nbytes = desc->pg_count; | 932 | nbytes = desc->pg_count; |
916 | do { | 933 | do { |
917 | size_t len = min(nbytes, wsize); | 934 | size_t len = min(nbytes, wsize); |
@@ -1002,6 +1019,10 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc) | |||
1002 | if ((!lseg) && list_is_singular(&data->pages)) | 1019 | if ((!lseg) && list_is_singular(&data->pages)) |
1003 | lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW); | 1020 | lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW); |
1004 | 1021 | ||
1022 | if ((desc->pg_ioflags & FLUSH_COND_STABLE) && | ||
1023 | (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit)) | ||
1024 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; | ||
1025 | |||
1005 | /* Set up the argument struct */ | 1026 | /* Set up the argument struct */ |
1006 | ret = nfs_write_rpcsetup(req, data, &nfs_write_full_ops, desc->pg_count, 0, lseg, desc->pg_ioflags); | 1027 | ret = nfs_write_rpcsetup(req, data, &nfs_write_full_ops, desc->pg_count, 0, lseg, desc->pg_ioflags); |
1007 | out: | 1028 | out: |
@@ -1074,7 +1095,7 @@ static void nfs_writeback_release_partial(void *calldata) | |||
1074 | 1095 | ||
1075 | out: | 1096 | out: |
1076 | if (atomic_dec_and_test(&req->wb_complete)) | 1097 | if (atomic_dec_and_test(&req->wb_complete)) |
1077 | nfs_writepage_release(req); | 1098 | nfs_writepage_release(req, data); |
1078 | nfs_writedata_release(calldata); | 1099 | nfs_writedata_release(calldata); |
1079 | } | 1100 | } |
1080 | 1101 | ||
@@ -1141,7 +1162,7 @@ static void nfs_writeback_release_full(void *calldata) | |||
1141 | 1162 | ||
1142 | if (nfs_write_need_commit(data)) { | 1163 | if (nfs_write_need_commit(data)) { |
1143 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); | 1164 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); |
1144 | nfs_mark_request_commit(req); | 1165 | nfs_mark_request_commit(req, data->lseg); |
1145 | dprintk(" marked for commit\n"); | 1166 | dprintk(" marked for commit\n"); |
1146 | goto next; | 1167 | goto next; |
1147 | } | 1168 | } |
@@ -1251,57 +1272,82 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1251 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1272 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1252 | static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait) | 1273 | static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait) |
1253 | { | 1274 | { |
1275 | int ret; | ||
1276 | |||
1254 | if (!test_and_set_bit(NFS_INO_COMMIT, &nfsi->flags)) | 1277 | if (!test_and_set_bit(NFS_INO_COMMIT, &nfsi->flags)) |
1255 | return 1; | 1278 | return 1; |
1256 | if (may_wait && !out_of_line_wait_on_bit_lock(&nfsi->flags, | 1279 | if (!may_wait) |
1257 | NFS_INO_COMMIT, nfs_wait_bit_killable, | 1280 | return 0; |
1258 | TASK_KILLABLE)) | 1281 | ret = out_of_line_wait_on_bit_lock(&nfsi->flags, |
1259 | return 1; | 1282 | NFS_INO_COMMIT, |
1260 | return 0; | 1283 | nfs_wait_bit_killable, |
1284 | TASK_KILLABLE); | ||
1285 | return (ret < 0) ? ret : 1; | ||
1261 | } | 1286 | } |
1262 | 1287 | ||
1263 | static void nfs_commit_clear_lock(struct nfs_inode *nfsi) | 1288 | void nfs_commit_clear_lock(struct nfs_inode *nfsi) |
1264 | { | 1289 | { |
1265 | clear_bit(NFS_INO_COMMIT, &nfsi->flags); | 1290 | clear_bit(NFS_INO_COMMIT, &nfsi->flags); |
1266 | smp_mb__after_clear_bit(); | 1291 | smp_mb__after_clear_bit(); |
1267 | wake_up_bit(&nfsi->flags, NFS_INO_COMMIT); | 1292 | wake_up_bit(&nfsi->flags, NFS_INO_COMMIT); |
1268 | } | 1293 | } |
1294 | EXPORT_SYMBOL_GPL(nfs_commit_clear_lock); | ||
1269 | 1295 | ||
1270 | 1296 | void nfs_commitdata_release(void *data) | |
1271 | static void nfs_commitdata_release(void *data) | ||
1272 | { | 1297 | { |
1273 | struct nfs_write_data *wdata = data; | 1298 | struct nfs_write_data *wdata = data; |
1274 | 1299 | ||
1300 | put_lseg(wdata->lseg); | ||
1275 | put_nfs_open_context(wdata->args.context); | 1301 | put_nfs_open_context(wdata->args.context); |
1276 | nfs_commit_free(wdata); | 1302 | nfs_commit_free(wdata); |
1277 | } | 1303 | } |
1304 | EXPORT_SYMBOL_GPL(nfs_commitdata_release); | ||
1278 | 1305 | ||
1279 | /* | 1306 | int nfs_initiate_commit(struct nfs_write_data *data, struct rpc_clnt *clnt, |
1280 | * Set up the argument/result storage required for the RPC call. | 1307 | const struct rpc_call_ops *call_ops, |
1281 | */ | 1308 | int how) |
1282 | static int nfs_commit_rpcsetup(struct list_head *head, | ||
1283 | struct nfs_write_data *data, | ||
1284 | int how) | ||
1285 | { | 1309 | { |
1286 | struct nfs_page *first = nfs_list_entry(head->next); | ||
1287 | struct inode *inode = first->wb_context->path.dentry->d_inode; | ||
1288 | int priority = flush_task_priority(how); | ||
1289 | struct rpc_task *task; | 1310 | struct rpc_task *task; |
1311 | int priority = flush_task_priority(how); | ||
1290 | struct rpc_message msg = { | 1312 | struct rpc_message msg = { |
1291 | .rpc_argp = &data->args, | 1313 | .rpc_argp = &data->args, |
1292 | .rpc_resp = &data->res, | 1314 | .rpc_resp = &data->res, |
1293 | .rpc_cred = first->wb_context->cred, | 1315 | .rpc_cred = data->cred, |
1294 | }; | 1316 | }; |
1295 | struct rpc_task_setup task_setup_data = { | 1317 | struct rpc_task_setup task_setup_data = { |
1296 | .task = &data->task, | 1318 | .task = &data->task, |
1297 | .rpc_client = NFS_CLIENT(inode), | 1319 | .rpc_client = clnt, |
1298 | .rpc_message = &msg, | 1320 | .rpc_message = &msg, |
1299 | .callback_ops = &nfs_commit_ops, | 1321 | .callback_ops = call_ops, |
1300 | .callback_data = data, | 1322 | .callback_data = data, |
1301 | .workqueue = nfsiod_workqueue, | 1323 | .workqueue = nfsiod_workqueue, |
1302 | .flags = RPC_TASK_ASYNC, | 1324 | .flags = RPC_TASK_ASYNC, |
1303 | .priority = priority, | 1325 | .priority = priority, |
1304 | }; | 1326 | }; |
1327 | /* Set up the initial task struct. */ | ||
1328 | NFS_PROTO(data->inode)->commit_setup(data, &msg); | ||
1329 | |||
1330 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); | ||
1331 | |||
1332 | task = rpc_run_task(&task_setup_data); | ||
1333 | if (IS_ERR(task)) | ||
1334 | return PTR_ERR(task); | ||
1335 | if (how & FLUSH_SYNC) | ||
1336 | rpc_wait_for_completion_task(task); | ||
1337 | rpc_put_task(task); | ||
1338 | return 0; | ||
1339 | } | ||
1340 | EXPORT_SYMBOL_GPL(nfs_initiate_commit); | ||
1341 | |||
1342 | /* | ||
1343 | * Set up the argument/result storage required for the RPC call. | ||
1344 | */ | ||
1345 | void nfs_init_commit(struct nfs_write_data *data, | ||
1346 | struct list_head *head, | ||
1347 | struct pnfs_layout_segment *lseg) | ||
1348 | { | ||
1349 | struct nfs_page *first = nfs_list_entry(head->next); | ||
1350 | struct inode *inode = first->wb_context->path.dentry->d_inode; | ||
1305 | 1351 | ||
1306 | /* Set up the RPC argument and reply structs | 1352 | /* Set up the RPC argument and reply structs |
1307 | * NB: take care not to mess about with data->commit et al. */ | 1353 | * NB: take care not to mess about with data->commit et al. */ |
@@ -1309,7 +1355,9 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
1309 | list_splice_init(head, &data->pages); | 1355 | list_splice_init(head, &data->pages); |
1310 | 1356 | ||
1311 | data->inode = inode; | 1357 | data->inode = inode; |
1312 | data->cred = msg.rpc_cred; | 1358 | data->cred = first->wb_context->cred; |
1359 | data->lseg = lseg; /* reference transferred */ | ||
1360 | data->mds_ops = &nfs_commit_ops; | ||
1313 | 1361 | ||
1314 | data->args.fh = NFS_FH(data->inode); | 1362 | data->args.fh = NFS_FH(data->inode); |
1315 | /* Note: we always request a commit of the entire inode */ | 1363 | /* Note: we always request a commit of the entire inode */ |
@@ -1320,20 +1368,25 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
1320 | data->res.fattr = &data->fattr; | 1368 | data->res.fattr = &data->fattr; |
1321 | data->res.verf = &data->verf; | 1369 | data->res.verf = &data->verf; |
1322 | nfs_fattr_init(&data->fattr); | 1370 | nfs_fattr_init(&data->fattr); |
1371 | } | ||
1372 | EXPORT_SYMBOL_GPL(nfs_init_commit); | ||
1323 | 1373 | ||
1324 | /* Set up the initial task struct. */ | 1374 | void nfs_retry_commit(struct list_head *page_list, |
1325 | NFS_PROTO(inode)->commit_setup(data, &msg); | 1375 | struct pnfs_layout_segment *lseg) |
1326 | 1376 | { | |
1327 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); | 1377 | struct nfs_page *req; |
1328 | 1378 | ||
1329 | task = rpc_run_task(&task_setup_data); | 1379 | while (!list_empty(page_list)) { |
1330 | if (IS_ERR(task)) | 1380 | req = nfs_list_entry(page_list->next); |
1331 | return PTR_ERR(task); | 1381 | nfs_list_remove_request(req); |
1332 | if (how & FLUSH_SYNC) | 1382 | nfs_mark_request_commit(req, lseg); |
1333 | rpc_wait_for_completion_task(task); | 1383 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
1334 | rpc_put_task(task); | 1384 | dec_bdi_stat(req->wb_page->mapping->backing_dev_info, |
1335 | return 0; | 1385 | BDI_RECLAIMABLE); |
1386 | nfs_clear_page_tag_locked(req); | ||
1387 | } | ||
1336 | } | 1388 | } |
1389 | EXPORT_SYMBOL_GPL(nfs_retry_commit); | ||
1337 | 1390 | ||
1338 | /* | 1391 | /* |
1339 | * Commit dirty pages | 1392 | * Commit dirty pages |
@@ -1342,7 +1395,6 @@ static int | |||
1342 | nfs_commit_list(struct inode *inode, struct list_head *head, int how) | 1395 | nfs_commit_list(struct inode *inode, struct list_head *head, int how) |
1343 | { | 1396 | { |
1344 | struct nfs_write_data *data; | 1397 | struct nfs_write_data *data; |
1345 | struct nfs_page *req; | ||
1346 | 1398 | ||
1347 | data = nfs_commitdata_alloc(); | 1399 | data = nfs_commitdata_alloc(); |
1348 | 1400 | ||
@@ -1350,17 +1402,10 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
1350 | goto out_bad; | 1402 | goto out_bad; |
1351 | 1403 | ||
1352 | /* Set up the argument struct */ | 1404 | /* Set up the argument struct */ |
1353 | return nfs_commit_rpcsetup(head, data, how); | 1405 | nfs_init_commit(data, head, NULL); |
1406 | return nfs_initiate_commit(data, NFS_CLIENT(inode), data->mds_ops, how); | ||
1354 | out_bad: | 1407 | out_bad: |
1355 | while (!list_empty(head)) { | 1408 | nfs_retry_commit(head, NULL); |
1356 | req = nfs_list_entry(head->next); | ||
1357 | nfs_list_remove_request(req); | ||
1358 | nfs_mark_request_commit(req); | ||
1359 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | ||
1360 | dec_bdi_stat(req->wb_page->mapping->backing_dev_info, | ||
1361 | BDI_RECLAIMABLE); | ||
1362 | nfs_clear_page_tag_locked(req); | ||
1363 | } | ||
1364 | nfs_commit_clear_lock(NFS_I(inode)); | 1409 | nfs_commit_clear_lock(NFS_I(inode)); |
1365 | return -ENOMEM; | 1410 | return -ENOMEM; |
1366 | } | 1411 | } |
@@ -1380,10 +1425,9 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1380 | return; | 1425 | return; |
1381 | } | 1426 | } |
1382 | 1427 | ||
1383 | static void nfs_commit_release(void *calldata) | 1428 | void nfs_commit_release_pages(struct nfs_write_data *data) |
1384 | { | 1429 | { |
1385 | struct nfs_write_data *data = calldata; | 1430 | struct nfs_page *req; |
1386 | struct nfs_page *req; | ||
1387 | int status = data->task.tk_status; | 1431 | int status = data->task.tk_status; |
1388 | 1432 | ||
1389 | while (!list_empty(&data->pages)) { | 1433 | while (!list_empty(&data->pages)) { |
@@ -1417,6 +1461,14 @@ static void nfs_commit_release(void *calldata) | |||
1417 | next: | 1461 | next: |
1418 | nfs_clear_page_tag_locked(req); | 1462 | nfs_clear_page_tag_locked(req); |
1419 | } | 1463 | } |
1464 | } | ||
1465 | EXPORT_SYMBOL_GPL(nfs_commit_release_pages); | ||
1466 | |||
1467 | static void nfs_commit_release(void *calldata) | ||
1468 | { | ||
1469 | struct nfs_write_data *data = calldata; | ||
1470 | |||
1471 | nfs_commit_release_pages(data); | ||
1420 | nfs_commit_clear_lock(NFS_I(data->inode)); | 1472 | nfs_commit_clear_lock(NFS_I(data->inode)); |
1421 | nfs_commitdata_release(calldata); | 1473 | nfs_commitdata_release(calldata); |
1422 | } | 1474 | } |
@@ -1433,23 +1485,30 @@ int nfs_commit_inode(struct inode *inode, int how) | |||
1433 | { | 1485 | { |
1434 | LIST_HEAD(head); | 1486 | LIST_HEAD(head); |
1435 | int may_wait = how & FLUSH_SYNC; | 1487 | int may_wait = how & FLUSH_SYNC; |
1436 | int res = 0; | 1488 | int res; |
1437 | 1489 | ||
1438 | if (!nfs_commit_set_lock(NFS_I(inode), may_wait)) | 1490 | res = nfs_commit_set_lock(NFS_I(inode), may_wait); |
1491 | if (res <= 0) | ||
1439 | goto out_mark_dirty; | 1492 | goto out_mark_dirty; |
1440 | spin_lock(&inode->i_lock); | 1493 | spin_lock(&inode->i_lock); |
1441 | res = nfs_scan_commit(inode, &head, 0, 0); | 1494 | res = nfs_scan_commit(inode, &head, 0, 0); |
1442 | spin_unlock(&inode->i_lock); | 1495 | spin_unlock(&inode->i_lock); |
1443 | if (res) { | 1496 | if (res) { |
1444 | int error = nfs_commit_list(inode, &head, how); | 1497 | int error; |
1498 | |||
1499 | error = pnfs_commit_list(inode, &head, how); | ||
1500 | if (error == PNFS_NOT_ATTEMPTED) | ||
1501 | error = nfs_commit_list(inode, &head, how); | ||
1445 | if (error < 0) | 1502 | if (error < 0) |
1446 | return error; | 1503 | return error; |
1447 | if (may_wait) | 1504 | if (!may_wait) |
1448 | wait_on_bit(&NFS_I(inode)->flags, NFS_INO_COMMIT, | ||
1449 | nfs_wait_bit_killable, | ||
1450 | TASK_KILLABLE); | ||
1451 | else | ||
1452 | goto out_mark_dirty; | 1505 | goto out_mark_dirty; |
1506 | error = wait_on_bit(&NFS_I(inode)->flags, | ||
1507 | NFS_INO_COMMIT, | ||
1508 | nfs_wait_bit_killable, | ||
1509 | TASK_KILLABLE); | ||
1510 | if (error < 0) | ||
1511 | return error; | ||
1453 | } else | 1512 | } else |
1454 | nfs_commit_clear_lock(NFS_I(inode)); | 1513 | nfs_commit_clear_lock(NFS_I(inode)); |
1455 | return res; | 1514 | return res; |
@@ -1503,7 +1562,22 @@ static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_contr | |||
1503 | 1562 | ||
1504 | int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) | 1563 | int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) |
1505 | { | 1564 | { |
1506 | return nfs_commit_unstable_pages(inode, wbc); | 1565 | int ret; |
1566 | |||
1567 | ret = nfs_commit_unstable_pages(inode, wbc); | ||
1568 | if (ret >= 0 && test_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags)) { | ||
1569 | int status; | ||
1570 | bool sync = true; | ||
1571 | |||
1572 | if (wbc->sync_mode == WB_SYNC_NONE || wbc->nonblocking || | ||
1573 | wbc->for_background) | ||
1574 | sync = false; | ||
1575 | |||
1576 | status = pnfs_layoutcommit_inode(inode, sync); | ||
1577 | if (status < 0) | ||
1578 | return status; | ||
1579 | } | ||
1580 | return ret; | ||
1507 | } | 1581 | } |
1508 | 1582 | ||
1509 | /* | 1583 | /* |
diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c index 84c27d69d421..ec0f277be7f5 100644 --- a/fs/nfs_common/nfsacl.c +++ b/fs/nfs_common/nfsacl.c | |||
@@ -117,7 +117,6 @@ int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, | |||
117 | * invoked in contexts where a memory allocation failure is | 117 | * invoked in contexts where a memory allocation failure is |
118 | * fatal. Fortunately this fake ACL is small enough to | 118 | * fatal. Fortunately this fake ACL is small enough to |
119 | * construct on the stack. */ | 119 | * construct on the stack. */ |
120 | memset(acl2, 0, sizeof(acl2)); | ||
121 | posix_acl_init(acl2, 4); | 120 | posix_acl_init(acl2, 4); |
122 | 121 | ||
123 | /* Insert entries in canonical order: other orders seem | 122 | /* Insert entries in canonical order: other orders seem |
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c index 4c29fcf557d1..07ea8d3e6ea2 100644 --- a/fs/notify/inode_mark.c +++ b/fs/notify/inode_mark.c | |||
@@ -22,13 +22,14 @@ | |||
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
24 | #include <linux/spinlock.h> | 24 | #include <linux/spinlock.h> |
25 | #include <linux/writeback.h> /* for inode_lock */ | ||
26 | 25 | ||
27 | #include <asm/atomic.h> | 26 | #include <asm/atomic.h> |
28 | 27 | ||
29 | #include <linux/fsnotify_backend.h> | 28 | #include <linux/fsnotify_backend.h> |
30 | #include "fsnotify.h" | 29 | #include "fsnotify.h" |
31 | 30 | ||
31 | #include "../internal.h" | ||
32 | |||
32 | /* | 33 | /* |
33 | * Recalculate the mask of events relevant to a given inode locked. | 34 | * Recalculate the mask of events relevant to a given inode locked. |
34 | */ | 35 | */ |
@@ -237,15 +238,14 @@ out: | |||
237 | * fsnotify_unmount_inodes - an sb is unmounting. handle any watched inodes. | 238 | * fsnotify_unmount_inodes - an sb is unmounting. handle any watched inodes. |
238 | * @list: list of inodes being unmounted (sb->s_inodes) | 239 | * @list: list of inodes being unmounted (sb->s_inodes) |
239 | * | 240 | * |
240 | * Called with inode_lock held, protecting the unmounting super block's list | 241 | * Called during unmount with no locks held, so needs to be safe against |
241 | * of inodes, and with iprune_mutex held, keeping shrink_icache_memory() at bay. | 242 | * concurrent modifiers. We temporarily drop inode_sb_list_lock and CAN block. |
242 | * We temporarily drop inode_lock, however, and CAN block. | ||
243 | */ | 243 | */ |
244 | void fsnotify_unmount_inodes(struct list_head *list) | 244 | void fsnotify_unmount_inodes(struct list_head *list) |
245 | { | 245 | { |
246 | struct inode *inode, *next_i, *need_iput = NULL; | 246 | struct inode *inode, *next_i, *need_iput = NULL; |
247 | 247 | ||
248 | spin_lock(&inode_lock); | 248 | spin_lock(&inode_sb_list_lock); |
249 | list_for_each_entry_safe(inode, next_i, list, i_sb_list) { | 249 | list_for_each_entry_safe(inode, next_i, list, i_sb_list) { |
250 | struct inode *need_iput_tmp; | 250 | struct inode *need_iput_tmp; |
251 | 251 | ||
@@ -254,8 +254,11 @@ void fsnotify_unmount_inodes(struct list_head *list) | |||
254 | * I_WILL_FREE, or I_NEW which is fine because by that point | 254 | * I_WILL_FREE, or I_NEW which is fine because by that point |
255 | * the inode cannot have any associated watches. | 255 | * the inode cannot have any associated watches. |
256 | */ | 256 | */ |
257 | if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) | 257 | spin_lock(&inode->i_lock); |
258 | if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) { | ||
259 | spin_unlock(&inode->i_lock); | ||
258 | continue; | 260 | continue; |
261 | } | ||
259 | 262 | ||
260 | /* | 263 | /* |
261 | * If i_count is zero, the inode cannot have any watches and | 264 | * If i_count is zero, the inode cannot have any watches and |
@@ -263,8 +266,10 @@ void fsnotify_unmount_inodes(struct list_head *list) | |||
263 | * evict all inodes with zero i_count from icache which is | 266 | * evict all inodes with zero i_count from icache which is |
264 | * unnecessarily violent and may in fact be illegal to do. | 267 | * unnecessarily violent and may in fact be illegal to do. |
265 | */ | 268 | */ |
266 | if (!atomic_read(&inode->i_count)) | 269 | if (!atomic_read(&inode->i_count)) { |
270 | spin_unlock(&inode->i_lock); | ||
267 | continue; | 271 | continue; |
272 | } | ||
268 | 273 | ||
269 | need_iput_tmp = need_iput; | 274 | need_iput_tmp = need_iput; |
270 | need_iput = NULL; | 275 | need_iput = NULL; |
@@ -274,22 +279,25 @@ void fsnotify_unmount_inodes(struct list_head *list) | |||
274 | __iget(inode); | 279 | __iget(inode); |
275 | else | 280 | else |
276 | need_iput_tmp = NULL; | 281 | need_iput_tmp = NULL; |
282 | spin_unlock(&inode->i_lock); | ||
277 | 283 | ||
278 | /* In case the dropping of a reference would nuke next_i. */ | 284 | /* In case the dropping of a reference would nuke next_i. */ |
279 | if ((&next_i->i_sb_list != list) && | 285 | if ((&next_i->i_sb_list != list) && |
280 | atomic_read(&next_i->i_count) && | 286 | atomic_read(&next_i->i_count)) { |
281 | !(next_i->i_state & (I_FREEING | I_WILL_FREE))) { | 287 | spin_lock(&next_i->i_lock); |
282 | __iget(next_i); | 288 | if (!(next_i->i_state & (I_FREEING | I_WILL_FREE))) { |
283 | need_iput = next_i; | 289 | __iget(next_i); |
290 | need_iput = next_i; | ||
291 | } | ||
292 | spin_unlock(&next_i->i_lock); | ||
284 | } | 293 | } |
285 | 294 | ||
286 | /* | 295 | /* |
287 | * We can safely drop inode_lock here because we hold | 296 | * We can safely drop inode_sb_list_lock here because we hold |
288 | * references on both inode and next_i. Also no new inodes | 297 | * references on both inode and next_i. Also no new inodes |
289 | * will be added since the umount has begun. Finally, | 298 | * will be added since the umount has begun. |
290 | * iprune_mutex keeps shrink_icache_memory() away. | ||
291 | */ | 299 | */ |
292 | spin_unlock(&inode_lock); | 300 | spin_unlock(&inode_sb_list_lock); |
293 | 301 | ||
294 | if (need_iput_tmp) | 302 | if (need_iput_tmp) |
295 | iput(need_iput_tmp); | 303 | iput(need_iput_tmp); |
@@ -301,7 +309,7 @@ void fsnotify_unmount_inodes(struct list_head *list) | |||
301 | 309 | ||
302 | iput(inode); | 310 | iput(inode); |
303 | 311 | ||
304 | spin_lock(&inode_lock); | 312 | spin_lock(&inode_sb_list_lock); |
305 | } | 313 | } |
306 | spin_unlock(&inode_lock); | 314 | spin_unlock(&inode_sb_list_lock); |
307 | } | 315 | } |
diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 325185e514bb..50c00856f730 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c | |||
@@ -91,7 +91,6 @@ | |||
91 | #include <linux/slab.h> | 91 | #include <linux/slab.h> |
92 | #include <linux/spinlock.h> | 92 | #include <linux/spinlock.h> |
93 | #include <linux/srcu.h> | 93 | #include <linux/srcu.h> |
94 | #include <linux/writeback.h> /* for inode_lock */ | ||
95 | 94 | ||
96 | #include <asm/atomic.h> | 95 | #include <asm/atomic.h> |
97 | 96 | ||
diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c index 85eebff6d0d7..e86577d6c5c3 100644 --- a/fs/notify/vfsmount_mark.c +++ b/fs/notify/vfsmount_mark.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/mount.h> | 23 | #include <linux/mount.h> |
24 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
25 | #include <linux/spinlock.h> | 25 | #include <linux/spinlock.h> |
26 | #include <linux/writeback.h> /* for inode_lock */ | ||
27 | 26 | ||
28 | #include <asm/atomic.h> | 27 | #include <asm/atomic.h> |
29 | 28 | ||
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index a627ed82c0a3..0b56c6b7ec01 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c | |||
@@ -54,7 +54,7 @@ | |||
54 | * | 54 | * |
55 | * Return 1 if the attributes match and 0 if not. | 55 | * Return 1 if the attributes match and 0 if not. |
56 | * | 56 | * |
57 | * NOTE: This function runs with the inode_lock spin lock held so it is not | 57 | * NOTE: This function runs with the inode->i_lock spin lock held so it is not |
58 | * allowed to sleep. | 58 | * allowed to sleep. |
59 | */ | 59 | */ |
60 | int ntfs_test_inode(struct inode *vi, ntfs_attr *na) | 60 | int ntfs_test_inode(struct inode *vi, ntfs_attr *na) |
@@ -98,7 +98,7 @@ int ntfs_test_inode(struct inode *vi, ntfs_attr *na) | |||
98 | * | 98 | * |
99 | * Return 0 on success and -errno on error. | 99 | * Return 0 on success and -errno on error. |
100 | * | 100 | * |
101 | * NOTE: This function runs with the inode_lock spin lock held so it is not | 101 | * NOTE: This function runs with the inode->i_lock spin lock held so it is not |
102 | * allowed to sleep. (Hence the GFP_ATOMIC allocation.) | 102 | * allowed to sleep. (Hence the GFP_ATOMIC allocation.) |
103 | */ | 103 | */ |
104 | static int ntfs_init_locked_inode(struct inode *vi, ntfs_attr *na) | 104 | static int ntfs_init_locked_inode(struct inode *vi, ntfs_attr *na) |
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 7c708a418acc..2e7addfd9803 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -182,7 +182,8 @@ static void m_stop(struct seq_file *m, void *v) | |||
182 | struct proc_maps_private *priv = m->private; | 182 | struct proc_maps_private *priv = m->private; |
183 | struct vm_area_struct *vma = v; | 183 | struct vm_area_struct *vma = v; |
184 | 184 | ||
185 | vma_stop(priv, vma); | 185 | if (!IS_ERR(vma)) |
186 | vma_stop(priv, vma); | ||
186 | if (priv->task) | 187 | if (priv->task) |
187 | put_task_struct(priv->task); | 188 | put_task_struct(priv->task); |
188 | } | 189 | } |
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index a2a622e079f0..fcc8ae75d874 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c | |||
@@ -76,7 +76,7 @@ | |||
76 | #include <linux/buffer_head.h> | 76 | #include <linux/buffer_head.h> |
77 | #include <linux/capability.h> | 77 | #include <linux/capability.h> |
78 | #include <linux/quotaops.h> | 78 | #include <linux/quotaops.h> |
79 | #include <linux/writeback.h> /* for inode_lock, oddly enough.. */ | 79 | #include "../internal.h" /* ugh */ |
80 | 80 | ||
81 | #include <asm/uaccess.h> | 81 | #include <asm/uaccess.h> |
82 | 82 | ||
@@ -900,33 +900,38 @@ static void add_dquot_ref(struct super_block *sb, int type) | |||
900 | int reserved = 0; | 900 | int reserved = 0; |
901 | #endif | 901 | #endif |
902 | 902 | ||
903 | spin_lock(&inode_lock); | 903 | spin_lock(&inode_sb_list_lock); |
904 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | 904 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { |
905 | if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) | 905 | spin_lock(&inode->i_lock); |
906 | if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) || | ||
907 | !atomic_read(&inode->i_writecount) || | ||
908 | !dqinit_needed(inode, type)) { | ||
909 | spin_unlock(&inode->i_lock); | ||
906 | continue; | 910 | continue; |
911 | } | ||
907 | #ifdef CONFIG_QUOTA_DEBUG | 912 | #ifdef CONFIG_QUOTA_DEBUG |
908 | if (unlikely(inode_get_rsv_space(inode) > 0)) | 913 | if (unlikely(inode_get_rsv_space(inode) > 0)) |
909 | reserved = 1; | 914 | reserved = 1; |
910 | #endif | 915 | #endif |
911 | if (!atomic_read(&inode->i_writecount)) | ||
912 | continue; | ||
913 | if (!dqinit_needed(inode, type)) | ||
914 | continue; | ||
915 | |||
916 | __iget(inode); | 916 | __iget(inode); |
917 | spin_unlock(&inode_lock); | 917 | spin_unlock(&inode->i_lock); |
918 | spin_unlock(&inode_sb_list_lock); | ||
918 | 919 | ||
919 | iput(old_inode); | 920 | iput(old_inode); |
920 | __dquot_initialize(inode, type); | 921 | __dquot_initialize(inode, type); |
921 | /* We hold a reference to 'inode' so it couldn't have been | 922 | |
922 | * removed from s_inodes list while we dropped the inode_lock. | 923 | /* |
923 | * We cannot iput the inode now as we can be holding the last | 924 | * We hold a reference to 'inode' so it couldn't have been |
924 | * reference and we cannot iput it under inode_lock. So we | 925 | * removed from s_inodes list while we dropped the |
925 | * keep the reference and iput it later. */ | 926 | * inode_sb_list_lock We cannot iput the inode now as we can be |
927 | * holding the last reference and we cannot iput it under | ||
928 | * inode_sb_list_lock. So we keep the reference and iput it | ||
929 | * later. | ||
930 | */ | ||
926 | old_inode = inode; | 931 | old_inode = inode; |
927 | spin_lock(&inode_lock); | 932 | spin_lock(&inode_sb_list_lock); |
928 | } | 933 | } |
929 | spin_unlock(&inode_lock); | 934 | spin_unlock(&inode_sb_list_lock); |
930 | iput(old_inode); | 935 | iput(old_inode); |
931 | 936 | ||
932 | #ifdef CONFIG_QUOTA_DEBUG | 937 | #ifdef CONFIG_QUOTA_DEBUG |
@@ -1007,7 +1012,7 @@ static void remove_dquot_ref(struct super_block *sb, int type, | |||
1007 | struct inode *inode; | 1012 | struct inode *inode; |
1008 | int reserved = 0; | 1013 | int reserved = 0; |
1009 | 1014 | ||
1010 | spin_lock(&inode_lock); | 1015 | spin_lock(&inode_sb_list_lock); |
1011 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | 1016 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { |
1012 | /* | 1017 | /* |
1013 | * We have to scan also I_NEW inodes because they can already | 1018 | * We have to scan also I_NEW inodes because they can already |
@@ -1021,7 +1026,7 @@ static void remove_dquot_ref(struct super_block *sb, int type, | |||
1021 | remove_inode_dquot_ref(inode, type, tofree_head); | 1026 | remove_inode_dquot_ref(inode, type, tofree_head); |
1022 | } | 1027 | } |
1023 | } | 1028 | } |
1024 | spin_unlock(&inode_lock); | 1029 | spin_unlock(&inode_sb_list_lock); |
1025 | #ifdef CONFIG_QUOTA_DEBUG | 1030 | #ifdef CONFIG_QUOTA_DEBUG |
1026 | if (reserved) { | 1031 | if (reserved) { |
1027 | printk(KERN_WARNING "VFS (%s): Writes happened after quota" | 1032 | printk(KERN_WARNING "VFS (%s): Writes happened after quota" |
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h index c2c9ba032d46..f2d2faf4d9ae 100644 --- a/include/asm-generic/bug.h +++ b/include/asm-generic/bug.h | |||
@@ -165,10 +165,36 @@ extern void warn_slowpath_null(const char *file, const int line); | |||
165 | #define WARN_ON_RATELIMIT(condition, state) \ | 165 | #define WARN_ON_RATELIMIT(condition, state) \ |
166 | WARN_ON((condition) && __ratelimit(state)) | 166 | WARN_ON((condition) && __ratelimit(state)) |
167 | 167 | ||
168 | /* | ||
169 | * WARN_ON_SMP() is for cases that the warning is either | ||
170 | * meaningless for !SMP or may even cause failures. | ||
171 | * This is usually used for cases that we have | ||
172 | * WARN_ON(!spin_is_locked(&lock)) checks, as spin_is_locked() | ||
173 | * returns 0 for uniprocessor settings. | ||
174 | * It can also be used with values that are only defined | ||
175 | * on SMP: | ||
176 | * | ||
177 | * struct foo { | ||
178 | * [...] | ||
179 | * #ifdef CONFIG_SMP | ||
180 | * int bar; | ||
181 | * #endif | ||
182 | * }; | ||
183 | * | ||
184 | * void func(struct foo *zoot) | ||
185 | * { | ||
186 | * WARN_ON_SMP(!zoot->bar); | ||
187 | * | ||
188 | * For CONFIG_SMP, WARN_ON_SMP() should act the same as WARN_ON(), | ||
189 | * and should be a nop and return false for uniprocessor. | ||
190 | * | ||
191 | * if (WARN_ON_SMP(x)) returns true only when CONFIG_SMP is set | ||
192 | * and x is true. | ||
193 | */ | ||
168 | #ifdef CONFIG_SMP | 194 | #ifdef CONFIG_SMP |
169 | # define WARN_ON_SMP(x) WARN_ON(x) | 195 | # define WARN_ON_SMP(x) WARN_ON(x) |
170 | #else | 196 | #else |
171 | # define WARN_ON_SMP(x) do { } while (0) | 197 | # define WARN_ON_SMP(x) ({0;}) |
172 | #endif | 198 | #endif |
173 | 199 | ||
174 | #endif | 200 | #endif |
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index f301cea5ca2d..ebdaafa866a7 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h | |||
@@ -688,6 +688,28 @@ | |||
688 | } | 688 | } |
689 | 689 | ||
690 | /** | 690 | /** |
691 | * PERCPU_INPUT - the percpu input sections | ||
692 | * @cacheline: cacheline size | ||
693 | * | ||
694 | * The core percpu section names and core symbols which do not rely | ||
695 | * directly upon load addresses. | ||
696 | * | ||
697 | * @cacheline is used to align subsections to avoid false cacheline | ||
698 | * sharing between subsections for different purposes. | ||
699 | */ | ||
700 | #define PERCPU_INPUT(cacheline) \ | ||
701 | VMLINUX_SYMBOL(__per_cpu_start) = .; \ | ||
702 | *(.data..percpu..first) \ | ||
703 | . = ALIGN(PAGE_SIZE); \ | ||
704 | *(.data..percpu..page_aligned) \ | ||
705 | . = ALIGN(cacheline); \ | ||
706 | *(.data..percpu..readmostly) \ | ||
707 | . = ALIGN(cacheline); \ | ||
708 | *(.data..percpu) \ | ||
709 | *(.data..percpu..shared_aligned) \ | ||
710 | VMLINUX_SYMBOL(__per_cpu_end) = .; | ||
711 | |||
712 | /** | ||
691 | * PERCPU_VADDR - define output section for percpu area | 713 | * PERCPU_VADDR - define output section for percpu area |
692 | * @cacheline: cacheline size | 714 | * @cacheline: cacheline size |
693 | * @vaddr: explicit base address (optional) | 715 | * @vaddr: explicit base address (optional) |
@@ -715,16 +737,7 @@ | |||
715 | VMLINUX_SYMBOL(__per_cpu_load) = .; \ | 737 | VMLINUX_SYMBOL(__per_cpu_load) = .; \ |
716 | .data..percpu vaddr : AT(VMLINUX_SYMBOL(__per_cpu_load) \ | 738 | .data..percpu vaddr : AT(VMLINUX_SYMBOL(__per_cpu_load) \ |
717 | - LOAD_OFFSET) { \ | 739 | - LOAD_OFFSET) { \ |
718 | VMLINUX_SYMBOL(__per_cpu_start) = .; \ | 740 | PERCPU_INPUT(cacheline) \ |
719 | *(.data..percpu..first) \ | ||
720 | . = ALIGN(PAGE_SIZE); \ | ||
721 | *(.data..percpu..page_aligned) \ | ||
722 | . = ALIGN(cacheline); \ | ||
723 | *(.data..percpu..readmostly) \ | ||
724 | . = ALIGN(cacheline); \ | ||
725 | *(.data..percpu) \ | ||
726 | *(.data..percpu..shared_aligned) \ | ||
727 | VMLINUX_SYMBOL(__per_cpu_end) = .; \ | ||
728 | } phdr \ | 741 | } phdr \ |
729 | . = VMLINUX_SYMBOL(__per_cpu_load) + SIZEOF(.data..percpu); | 742 | . = VMLINUX_SYMBOL(__per_cpu_load) + SIZEOF(.data..percpu); |
730 | 743 | ||
@@ -744,16 +757,7 @@ | |||
744 | . = ALIGN(PAGE_SIZE); \ | 757 | . = ALIGN(PAGE_SIZE); \ |
745 | .data..percpu : AT(ADDR(.data..percpu) - LOAD_OFFSET) { \ | 758 | .data..percpu : AT(ADDR(.data..percpu) - LOAD_OFFSET) { \ |
746 | VMLINUX_SYMBOL(__per_cpu_load) = .; \ | 759 | VMLINUX_SYMBOL(__per_cpu_load) = .; \ |
747 | VMLINUX_SYMBOL(__per_cpu_start) = .; \ | 760 | PERCPU_INPUT(cacheline) \ |
748 | *(.data..percpu..first) \ | ||
749 | . = ALIGN(PAGE_SIZE); \ | ||
750 | *(.data..percpu..page_aligned) \ | ||
751 | . = ALIGN(cacheline); \ | ||
752 | *(.data..percpu..readmostly) \ | ||
753 | . = ALIGN(cacheline); \ | ||
754 | *(.data..percpu) \ | ||
755 | *(.data..percpu..shared_aligned) \ | ||
756 | VMLINUX_SYMBOL(__per_cpu_end) = .; \ | ||
757 | } | 761 | } |
758 | 762 | ||
759 | 763 | ||
diff --git a/include/drm/drm.h b/include/drm/drm.h index 9ac431396176..4be33b4ca2f8 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h | |||
@@ -463,12 +463,15 @@ struct drm_irq_busid { | |||
463 | enum drm_vblank_seq_type { | 463 | enum drm_vblank_seq_type { |
464 | _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ | 464 | _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ |
465 | _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ | 465 | _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ |
466 | /* bits 1-6 are reserved for high crtcs */ | ||
467 | _DRM_VBLANK_HIGH_CRTC_MASK = 0x0000003e, | ||
466 | _DRM_VBLANK_EVENT = 0x4000000, /**< Send event instead of blocking */ | 468 | _DRM_VBLANK_EVENT = 0x4000000, /**< Send event instead of blocking */ |
467 | _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ | 469 | _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ |
468 | _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ | 470 | _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ |
469 | _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ | 471 | _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ |
470 | _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking, unsupported */ | 472 | _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking, unsupported */ |
471 | }; | 473 | }; |
474 | #define _DRM_VBLANK_HIGH_CRTC_SHIFT 1 | ||
472 | 475 | ||
473 | #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE) | 476 | #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE) |
474 | #define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_EVENT | _DRM_VBLANK_SIGNAL | \ | 477 | #define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_EVENT | _DRM_VBLANK_SIGNAL | \ |
@@ -753,6 +756,7 @@ struct drm_event_vblank { | |||
753 | }; | 756 | }; |
754 | 757 | ||
755 | #define DRM_CAP_DUMB_BUFFER 0x1 | 758 | #define DRM_CAP_DUMB_BUFFER 0x1 |
759 | #define DRM_CAP_VBLANK_HIGH_CRTC 0x2 | ||
756 | 760 | ||
757 | /* typedef area */ | 761 | /* typedef area */ |
758 | #ifndef __KERNEL__ | 762 | #ifndef __KERNEL__ |
diff --git a/include/linux/bch.h b/include/linux/bch.h new file mode 100644 index 000000000000..295b4ef153bb --- /dev/null +++ b/include/linux/bch.h | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * Generic binary BCH encoding/decoding library | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License version 2 as published by | ||
6 | * the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., 51 | ||
15 | * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Copyright © 2011 Parrot S.A. | ||
18 | * | ||
19 | * Author: Ivan Djelic <ivan.djelic@parrot.com> | ||
20 | * | ||
21 | * Description: | ||
22 | * | ||
23 | * This library provides runtime configurable encoding/decoding of binary | ||
24 | * Bose-Chaudhuri-Hocquenghem (BCH) codes. | ||
25 | */ | ||
26 | #ifndef _BCH_H | ||
27 | #define _BCH_H | ||
28 | |||
29 | #include <linux/types.h> | ||
30 | |||
31 | /** | ||
32 | * struct bch_control - BCH control structure | ||
33 | * @m: Galois field order | ||
34 | * @n: maximum codeword size in bits (= 2^m-1) | ||
35 | * @t: error correction capability in bits | ||
36 | * @ecc_bits: ecc exact size in bits, i.e. generator polynomial degree (<=m*t) | ||
37 | * @ecc_bytes: ecc max size (m*t bits) in bytes | ||
38 | * @a_pow_tab: Galois field GF(2^m) exponentiation lookup table | ||
39 | * @a_log_tab: Galois field GF(2^m) log lookup table | ||
40 | * @mod8_tab: remainder generator polynomial lookup tables | ||
41 | * @ecc_buf: ecc parity words buffer | ||
42 | * @ecc_buf2: ecc parity words buffer | ||
43 | * @xi_tab: GF(2^m) base for solving degree 2 polynomial roots | ||
44 | * @syn: syndrome buffer | ||
45 | * @cache: log-based polynomial representation buffer | ||
46 | * @elp: error locator polynomial | ||
47 | * @poly_2t: temporary polynomials of degree 2t | ||
48 | */ | ||
49 | struct bch_control { | ||
50 | unsigned int m; | ||
51 | unsigned int n; | ||
52 | unsigned int t; | ||
53 | unsigned int ecc_bits; | ||
54 | unsigned int ecc_bytes; | ||
55 | /* private: */ | ||
56 | uint16_t *a_pow_tab; | ||
57 | uint16_t *a_log_tab; | ||
58 | uint32_t *mod8_tab; | ||
59 | uint32_t *ecc_buf; | ||
60 | uint32_t *ecc_buf2; | ||
61 | unsigned int *xi_tab; | ||
62 | unsigned int *syn; | ||
63 | int *cache; | ||
64 | struct gf_poly *elp; | ||
65 | struct gf_poly *poly_2t[4]; | ||
66 | }; | ||
67 | |||
68 | struct bch_control *init_bch(int m, int t, unsigned int prim_poly); | ||
69 | |||
70 | void free_bch(struct bch_control *bch); | ||
71 | |||
72 | void encode_bch(struct bch_control *bch, const uint8_t *data, | ||
73 | unsigned int len, uint8_t *ecc); | ||
74 | |||
75 | int decode_bch(struct bch_control *bch, const uint8_t *data, unsigned int len, | ||
76 | const uint8_t *recv_ecc, const uint8_t *calc_ecc, | ||
77 | const unsigned int *syn, unsigned int *errloc); | ||
78 | |||
79 | #endif /* _BCH_H */ | ||
diff --git a/include/linux/davinci_emac.h b/include/linux/davinci_emac.h index 5dd428532f79..542888504994 100644 --- a/include/linux/davinci_emac.h +++ b/include/linux/davinci_emac.h | |||
@@ -36,6 +36,7 @@ struct emac_platform_data { | |||
36 | 36 | ||
37 | u8 rmii_en; | 37 | u8 rmii_en; |
38 | u8 version; | 38 | u8 version; |
39 | bool no_bd_ram; | ||
39 | void (*interrupt_enable) (void); | 40 | void (*interrupt_enable) (void); |
40 | void (*interrupt_disable) (void); | 41 | void (*interrupt_disable) (void); |
41 | }; | 42 | }; |
diff --git a/include/linux/device.h b/include/linux/device.h index 144ec135875f..ab8dfc095709 100644 --- a/include/linux/device.h +++ b/include/linux/device.h | |||
@@ -633,8 +633,12 @@ static inline int devtmpfs_mount(const char *mountpoint) { return 0; } | |||
633 | /* drivers/base/power/shutdown.c */ | 633 | /* drivers/base/power/shutdown.c */ |
634 | extern void device_shutdown(void); | 634 | extern void device_shutdown(void); |
635 | 635 | ||
636 | #ifndef CONFIG_ARCH_NO_SYSDEV_OPS | ||
636 | /* drivers/base/sys.c */ | 637 | /* drivers/base/sys.c */ |
637 | extern void sysdev_shutdown(void); | 638 | extern void sysdev_shutdown(void); |
639 | #else | ||
640 | static inline void sysdev_shutdown(void) { } | ||
641 | #endif | ||
638 | 642 | ||
639 | /* debugging and troubleshooting/diagnostic helpers. */ | 643 | /* debugging and troubleshooting/diagnostic helpers. */ |
640 | extern const char *dev_driver_string(const struct device *dev); | 644 | extern const char *dev_driver_string(const struct device *dev); |
diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h index 78bbf47bbb96..3708455ee6c3 100644 --- a/include/linux/dm-ioctl.h +++ b/include/linux/dm-ioctl.h | |||
@@ -267,9 +267,9 @@ enum { | |||
267 | #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) | 267 | #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) |
268 | 268 | ||
269 | #define DM_VERSION_MAJOR 4 | 269 | #define DM_VERSION_MAJOR 4 |
270 | #define DM_VERSION_MINOR 19 | 270 | #define DM_VERSION_MINOR 20 |
271 | #define DM_VERSION_PATCHLEVEL 1 | 271 | #define DM_VERSION_PATCHLEVEL 0 |
272 | #define DM_VERSION_EXTRA "-ioctl (2011-01-07)" | 272 | #define DM_VERSION_EXTRA "-ioctl (2011-02-02)" |
273 | 273 | ||
274 | /* Status bits */ | 274 | /* Status bits */ |
275 | #define DM_READONLY_FLAG (1 << 0) /* In/Out */ | 275 | #define DM_READONLY_FLAG (1 << 0) /* In/Out */ |
@@ -328,4 +328,10 @@ enum { | |||
328 | */ | 328 | */ |
329 | #define DM_UUID_FLAG (1 << 14) /* In */ | 329 | #define DM_UUID_FLAG (1 << 14) /* In */ |
330 | 330 | ||
331 | /* | ||
332 | * If set, all buffers are wiped after use. Use when sending | ||
333 | * or requesting sensitive data such as an encryption key. | ||
334 | */ | ||
335 | #define DM_SECURE_DATA_FLAG (1 << 15) /* In */ | ||
336 | |||
331 | #endif /* _LINUX_DM_IOCTL_H */ | 337 | #endif /* _LINUX_DM_IOCTL_H */ |
diff --git a/include/linux/drbd.h b/include/linux/drbd.h index ef44c7a0638c..d18d673ebc78 100644 --- a/include/linux/drbd.h +++ b/include/linux/drbd.h | |||
@@ -53,10 +53,10 @@ | |||
53 | 53 | ||
54 | 54 | ||
55 | extern const char *drbd_buildtag(void); | 55 | extern const char *drbd_buildtag(void); |
56 | #define REL_VERSION "8.3.9" | 56 | #define REL_VERSION "8.3.10" |
57 | #define API_VERSION 88 | 57 | #define API_VERSION 88 |
58 | #define PRO_VERSION_MIN 86 | 58 | #define PRO_VERSION_MIN 86 |
59 | #define PRO_VERSION_MAX 95 | 59 | #define PRO_VERSION_MAX 96 |
60 | 60 | ||
61 | 61 | ||
62 | enum drbd_io_error_p { | 62 | enum drbd_io_error_p { |
@@ -96,8 +96,14 @@ enum drbd_on_no_data { | |||
96 | OND_SUSPEND_IO | 96 | OND_SUSPEND_IO |
97 | }; | 97 | }; |
98 | 98 | ||
99 | enum drbd_on_congestion { | ||
100 | OC_BLOCK, | ||
101 | OC_PULL_AHEAD, | ||
102 | OC_DISCONNECT, | ||
103 | }; | ||
104 | |||
99 | /* KEEP the order, do not delete or insert. Only append. */ | 105 | /* KEEP the order, do not delete or insert. Only append. */ |
100 | enum drbd_ret_codes { | 106 | enum drbd_ret_code { |
101 | ERR_CODE_BASE = 100, | 107 | ERR_CODE_BASE = 100, |
102 | NO_ERROR = 101, | 108 | NO_ERROR = 101, |
103 | ERR_LOCAL_ADDR = 102, | 109 | ERR_LOCAL_ADDR = 102, |
@@ -146,6 +152,9 @@ enum drbd_ret_codes { | |||
146 | ERR_PERM = 152, | 152 | ERR_PERM = 152, |
147 | ERR_NEED_APV_93 = 153, | 153 | ERR_NEED_APV_93 = 153, |
148 | ERR_STONITH_AND_PROT_A = 154, | 154 | ERR_STONITH_AND_PROT_A = 154, |
155 | ERR_CONG_NOT_PROTO_A = 155, | ||
156 | ERR_PIC_AFTER_DEP = 156, | ||
157 | ERR_PIC_PEER_DEP = 157, | ||
149 | 158 | ||
150 | /* insert new ones above this line */ | 159 | /* insert new ones above this line */ |
151 | AFTER_LAST_ERR_CODE | 160 | AFTER_LAST_ERR_CODE |
@@ -199,6 +208,10 @@ enum drbd_conns { | |||
199 | C_VERIFY_T, | 208 | C_VERIFY_T, |
200 | C_PAUSED_SYNC_S, | 209 | C_PAUSED_SYNC_S, |
201 | C_PAUSED_SYNC_T, | 210 | C_PAUSED_SYNC_T, |
211 | |||
212 | C_AHEAD, | ||
213 | C_BEHIND, | ||
214 | |||
202 | C_MASK = 31 | 215 | C_MASK = 31 |
203 | }; | 216 | }; |
204 | 217 | ||
@@ -259,7 +272,7 @@ union drbd_state { | |||
259 | unsigned int i; | 272 | unsigned int i; |
260 | }; | 273 | }; |
261 | 274 | ||
262 | enum drbd_state_ret_codes { | 275 | enum drbd_state_rv { |
263 | SS_CW_NO_NEED = 4, | 276 | SS_CW_NO_NEED = 4, |
264 | SS_CW_SUCCESS = 3, | 277 | SS_CW_SUCCESS = 3, |
265 | SS_NOTHING_TO_DO = 2, | 278 | SS_NOTHING_TO_DO = 2, |
@@ -290,7 +303,7 @@ enum drbd_state_ret_codes { | |||
290 | extern const char *drbd_conn_str(enum drbd_conns); | 303 | extern const char *drbd_conn_str(enum drbd_conns); |
291 | extern const char *drbd_role_str(enum drbd_role); | 304 | extern const char *drbd_role_str(enum drbd_role); |
292 | extern const char *drbd_disk_str(enum drbd_disk_state); | 305 | extern const char *drbd_disk_str(enum drbd_disk_state); |
293 | extern const char *drbd_set_st_err_str(enum drbd_state_ret_codes); | 306 | extern const char *drbd_set_st_err_str(enum drbd_state_rv); |
294 | 307 | ||
295 | #define SHARED_SECRET_MAX 64 | 308 | #define SHARED_SECRET_MAX 64 |
296 | 309 | ||
diff --git a/include/linux/drbd_limits.h b/include/linux/drbd_limits.h index 4ac33f34b77e..bb264a5732de 100644 --- a/include/linux/drbd_limits.h +++ b/include/linux/drbd_limits.h | |||
@@ -16,7 +16,8 @@ | |||
16 | #define DEBUG_RANGE_CHECK 0 | 16 | #define DEBUG_RANGE_CHECK 0 |
17 | 17 | ||
18 | #define DRBD_MINOR_COUNT_MIN 1 | 18 | #define DRBD_MINOR_COUNT_MIN 1 |
19 | #define DRBD_MINOR_COUNT_MAX 255 | 19 | #define DRBD_MINOR_COUNT_MAX 256 |
20 | #define DRBD_MINOR_COUNT_DEF 32 | ||
20 | 21 | ||
21 | #define DRBD_DIALOG_REFRESH_MIN 0 | 22 | #define DRBD_DIALOG_REFRESH_MIN 0 |
22 | #define DRBD_DIALOG_REFRESH_MAX 600 | 23 | #define DRBD_DIALOG_REFRESH_MAX 600 |
@@ -129,6 +130,7 @@ | |||
129 | #define DRBD_AFTER_SB_2P_DEF ASB_DISCONNECT | 130 | #define DRBD_AFTER_SB_2P_DEF ASB_DISCONNECT |
130 | #define DRBD_RR_CONFLICT_DEF ASB_DISCONNECT | 131 | #define DRBD_RR_CONFLICT_DEF ASB_DISCONNECT |
131 | #define DRBD_ON_NO_DATA_DEF OND_IO_ERROR | 132 | #define DRBD_ON_NO_DATA_DEF OND_IO_ERROR |
133 | #define DRBD_ON_CONGESTION_DEF OC_BLOCK | ||
132 | 134 | ||
133 | #define DRBD_MAX_BIO_BVECS_MIN 0 | 135 | #define DRBD_MAX_BIO_BVECS_MIN 0 |
134 | #define DRBD_MAX_BIO_BVECS_MAX 128 | 136 | #define DRBD_MAX_BIO_BVECS_MAX 128 |
@@ -154,5 +156,13 @@ | |||
154 | #define DRBD_C_MIN_RATE_MAX (4 << 20) | 156 | #define DRBD_C_MIN_RATE_MAX (4 << 20) |
155 | #define DRBD_C_MIN_RATE_DEF 4096 | 157 | #define DRBD_C_MIN_RATE_DEF 4096 |
156 | 158 | ||
159 | #define DRBD_CONG_FILL_MIN 0 | ||
160 | #define DRBD_CONG_FILL_MAX (10<<21) /* 10GByte in sectors */ | ||
161 | #define DRBD_CONG_FILL_DEF 0 | ||
162 | |||
163 | #define DRBD_CONG_EXTENTS_MIN DRBD_AL_EXTENTS_MIN | ||
164 | #define DRBD_CONG_EXTENTS_MAX DRBD_AL_EXTENTS_MAX | ||
165 | #define DRBD_CONG_EXTENTS_DEF DRBD_AL_EXTENTS_DEF | ||
166 | |||
157 | #undef RANGE | 167 | #undef RANGE |
158 | #endif | 168 | #endif |
diff --git a/include/linux/drbd_nl.h b/include/linux/drbd_nl.h index ade91107c9a5..ab6159e4fcf0 100644 --- a/include/linux/drbd_nl.h +++ b/include/linux/drbd_nl.h | |||
@@ -56,6 +56,9 @@ NL_PACKET(net_conf, 5, | |||
56 | NL_INTEGER( 39, T_MAY_IGNORE, rr_conflict) | 56 | NL_INTEGER( 39, T_MAY_IGNORE, rr_conflict) |
57 | NL_INTEGER( 40, T_MAY_IGNORE, ping_timeo) | 57 | NL_INTEGER( 40, T_MAY_IGNORE, ping_timeo) |
58 | NL_INTEGER( 67, T_MAY_IGNORE, rcvbuf_size) | 58 | NL_INTEGER( 67, T_MAY_IGNORE, rcvbuf_size) |
59 | NL_INTEGER( 81, T_MAY_IGNORE, on_congestion) | ||
60 | NL_INTEGER( 82, T_MAY_IGNORE, cong_fill) | ||
61 | NL_INTEGER( 83, T_MAY_IGNORE, cong_extents) | ||
59 | /* 59 addr_family was available in GIT, never released */ | 62 | /* 59 addr_family was available in GIT, never released */ |
60 | NL_BIT( 60, T_MANDATORY, mind_af) | 63 | NL_BIT( 60, T_MANDATORY, mind_af) |
61 | NL_BIT( 27, T_MAY_IGNORE, want_lose) | 64 | NL_BIT( 27, T_MAY_IGNORE, want_lose) |
@@ -66,7 +69,9 @@ NL_PACKET(net_conf, 5, | |||
66 | NL_BIT( 70, T_MANDATORY, dry_run) | 69 | NL_BIT( 70, T_MANDATORY, dry_run) |
67 | ) | 70 | ) |
68 | 71 | ||
69 | NL_PACKET(disconnect, 6, ) | 72 | NL_PACKET(disconnect, 6, |
73 | NL_BIT( 84, T_MAY_IGNORE, force) | ||
74 | ) | ||
70 | 75 | ||
71 | NL_PACKET(resize, 7, | 76 | NL_PACKET(resize, 7, |
72 | NL_INT64( 29, T_MAY_IGNORE, resize_size) | 77 | NL_INT64( 29, T_MAY_IGNORE, resize_size) |
@@ -143,9 +148,13 @@ NL_PACKET(new_c_uuid, 26, | |||
143 | NL_BIT( 63, T_MANDATORY, clear_bm) | 148 | NL_BIT( 63, T_MANDATORY, clear_bm) |
144 | ) | 149 | ) |
145 | 150 | ||
151 | #ifdef NL_RESPONSE | ||
152 | NL_RESPONSE(return_code_only, 27) | ||
153 | #endif | ||
154 | |||
146 | #undef NL_PACKET | 155 | #undef NL_PACKET |
147 | #undef NL_INTEGER | 156 | #undef NL_INTEGER |
148 | #undef NL_INT64 | 157 | #undef NL_INT64 |
149 | #undef NL_BIT | 158 | #undef NL_BIT |
150 | #undef NL_STRING | 159 | #undef NL_STRING |
151 | 160 | #undef NL_RESPONSE | |
diff --git a/include/linux/drbd_tag_magic.h b/include/linux/drbd_tag_magic.h index fcdff8410e99..f14a165e82dc 100644 --- a/include/linux/drbd_tag_magic.h +++ b/include/linux/drbd_tag_magic.h | |||
@@ -7,6 +7,7 @@ | |||
7 | /* declare packet_type enums */ | 7 | /* declare packet_type enums */ |
8 | enum packet_types { | 8 | enum packet_types { |
9 | #define NL_PACKET(name, number, fields) P_ ## name = number, | 9 | #define NL_PACKET(name, number, fields) P_ ## name = number, |
10 | #define NL_RESPONSE(name, number) P_ ## name = number, | ||
10 | #define NL_INTEGER(pn, pr, member) | 11 | #define NL_INTEGER(pn, pr, member) |
11 | #define NL_INT64(pn, pr, member) | 12 | #define NL_INT64(pn, pr, member) |
12 | #define NL_BIT(pn, pr, member) | 13 | #define NL_BIT(pn, pr, member) |
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index b297f288f6eb..ae757bcf1280 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h | |||
@@ -648,6 +648,9 @@ enum ethtool_sfeatures_retval_bits { | |||
648 | 648 | ||
649 | #include <linux/rculist.h> | 649 | #include <linux/rculist.h> |
650 | 650 | ||
651 | /* needed by dev_disable_lro() */ | ||
652 | extern int __ethtool_set_flags(struct net_device *dev, u32 flags); | ||
653 | |||
651 | struct ethtool_rx_ntuple_flow_spec_container { | 654 | struct ethtool_rx_ntuple_flow_spec_container { |
652 | struct ethtool_rx_ntuple_flow_spec fs; | 655 | struct ethtool_rx_ntuple_flow_spec fs; |
653 | struct list_head list; | 656 | struct list_head list; |
diff --git a/include/linux/fs.h b/include/linux/fs.h index ce7e18555197..b677bd77f2d6 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1636,7 +1636,7 @@ struct super_operations { | |||
1636 | }; | 1636 | }; |
1637 | 1637 | ||
1638 | /* | 1638 | /* |
1639 | * Inode state bits. Protected by inode_lock. | 1639 | * Inode state bits. Protected by inode->i_lock |
1640 | * | 1640 | * |
1641 | * Three bits determine the dirty state of the inode, I_DIRTY_SYNC, | 1641 | * Three bits determine the dirty state of the inode, I_DIRTY_SYNC, |
1642 | * I_DIRTY_DATASYNC and I_DIRTY_PAGES. | 1642 | * I_DIRTY_DATASYNC and I_DIRTY_PAGES. |
diff --git a/include/linux/irq.h b/include/linux/irq.h index 1d3577f30d45..5d876c9b3a3d 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <asm/ptrace.h> | 28 | #include <asm/ptrace.h> |
29 | #include <asm/irq_regs.h> | 29 | #include <asm/irq_regs.h> |
30 | 30 | ||
31 | struct seq_file; | ||
31 | struct irq_desc; | 32 | struct irq_desc; |
32 | struct irq_data; | 33 | struct irq_data; |
33 | typedef void (*irq_flow_handler_t)(unsigned int irq, | 34 | typedef void (*irq_flow_handler_t)(unsigned int irq, |
@@ -270,6 +271,7 @@ static inline bool irqd_can_move_in_process_context(struct irq_data *d) | |||
270 | * @irq_set_wake: enable/disable power-management wake-on of an IRQ | 271 | * @irq_set_wake: enable/disable power-management wake-on of an IRQ |
271 | * @irq_bus_lock: function to lock access to slow bus (i2c) chips | 272 | * @irq_bus_lock: function to lock access to slow bus (i2c) chips |
272 | * @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips | 273 | * @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips |
274 | * @irq_print_chip: optional to print special chip info in show_interrupts | ||
273 | * @flags: chip specific flags | 275 | * @flags: chip specific flags |
274 | * | 276 | * |
275 | * @release: release function solely used by UML | 277 | * @release: release function solely used by UML |
@@ -317,6 +319,8 @@ struct irq_chip { | |||
317 | void (*irq_bus_lock)(struct irq_data *data); | 319 | void (*irq_bus_lock)(struct irq_data *data); |
318 | void (*irq_bus_sync_unlock)(struct irq_data *data); | 320 | void (*irq_bus_sync_unlock)(struct irq_data *data); |
319 | 321 | ||
322 | void (*irq_print_chip)(struct irq_data *data, struct seq_file *p); | ||
323 | |||
320 | unsigned long flags; | 324 | unsigned long flags; |
321 | 325 | ||
322 | /* Currently used only by UML, might disappear one day.*/ | 326 | /* Currently used only by UML, might disappear one day.*/ |
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index 00218371518b..15e6c3905f41 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h | |||
@@ -100,13 +100,6 @@ struct irq_desc { | |||
100 | extern struct irq_desc irq_desc[NR_IRQS]; | 100 | extern struct irq_desc irq_desc[NR_IRQS]; |
101 | #endif | 101 | #endif |
102 | 102 | ||
103 | /* Will be removed once the last users in power and sh are gone */ | ||
104 | extern struct irq_desc *irq_to_desc_alloc_node(unsigned int irq, int node); | ||
105 | static inline struct irq_desc *move_irq_desc(struct irq_desc *desc, int node) | ||
106 | { | ||
107 | return desc; | ||
108 | } | ||
109 | |||
110 | #ifdef CONFIG_GENERIC_HARDIRQS | 103 | #ifdef CONFIG_GENERIC_HARDIRQS |
111 | 104 | ||
112 | static inline struct irq_data *irq_desc_get_irq_data(struct irq_desc *desc) | 105 | static inline struct irq_data *irq_desc_get_irq_data(struct irq_desc *desc) |
@@ -178,24 +171,52 @@ static inline int irq_has_action(unsigned int irq) | |||
178 | return desc->action != NULL; | 171 | return desc->action != NULL; |
179 | } | 172 | } |
180 | 173 | ||
181 | #ifndef CONFIG_GENERIC_HARDIRQS_NO_COMPAT | 174 | /* caller has locked the irq_desc and both params are valid */ |
182 | static inline int irq_balancing_disabled(unsigned int irq) | 175 | static inline void __irq_set_handler_locked(unsigned int irq, |
176 | irq_flow_handler_t handler) | ||
183 | { | 177 | { |
184 | struct irq_desc *desc; | 178 | struct irq_desc *desc; |
185 | 179 | ||
186 | desc = irq_to_desc(irq); | 180 | desc = irq_to_desc(irq); |
187 | return desc->status & IRQ_NO_BALANCING_MASK; | 181 | desc->handle_irq = handler; |
188 | } | 182 | } |
189 | #endif | ||
190 | 183 | ||
191 | /* caller has locked the irq_desc and both params are valid */ | 184 | /* caller has locked the irq_desc and both params are valid */ |
185 | static inline void | ||
186 | __irq_set_chip_handler_name_locked(unsigned int irq, struct irq_chip *chip, | ||
187 | irq_flow_handler_t handler, const char *name) | ||
188 | { | ||
189 | struct irq_desc *desc; | ||
190 | |||
191 | desc = irq_to_desc(irq); | ||
192 | irq_desc_get_irq_data(desc)->chip = chip; | ||
193 | desc->handle_irq = handler; | ||
194 | desc->name = name; | ||
195 | } | ||
196 | |||
197 | #ifndef CONFIG_GENERIC_HARDIRQS_NO_COMPAT | ||
192 | static inline void __set_irq_handler_unlocked(int irq, | 198 | static inline void __set_irq_handler_unlocked(int irq, |
193 | irq_flow_handler_t handler) | 199 | irq_flow_handler_t handler) |
194 | { | 200 | { |
201 | __irq_set_handler_locked(irq, handler); | ||
202 | } | ||
203 | |||
204 | static inline int irq_balancing_disabled(unsigned int irq) | ||
205 | { | ||
195 | struct irq_desc *desc; | 206 | struct irq_desc *desc; |
196 | 207 | ||
197 | desc = irq_to_desc(irq); | 208 | desc = irq_to_desc(irq); |
198 | desc->handle_irq = handler; | 209 | return desc->status & IRQ_NO_BALANCING_MASK; |
210 | } | ||
211 | #endif | ||
212 | |||
213 | static inline void | ||
214 | irq_set_lockdep_class(unsigned int irq, struct lock_class_key *class) | ||
215 | { | ||
216 | struct irq_desc *desc = irq_to_desc(irq); | ||
217 | |||
218 | if (desc) | ||
219 | lockdep_set_class(&desc->lock, class); | ||
199 | } | 220 | } |
200 | 221 | ||
201 | #ifdef CONFIG_IRQ_PREFLOW_FASTEOI | 222 | #ifdef CONFIG_IRQ_PREFLOW_FASTEOI |
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 27e79c27ba08..a32dcaec04e1 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h | |||
@@ -432,13 +432,35 @@ struct jbd2_journal_handle | |||
432 | int h_err; | 432 | int h_err; |
433 | 433 | ||
434 | /* Flags [no locking] */ | 434 | /* Flags [no locking] */ |
435 | unsigned int h_sync: 1; /* sync-on-close */ | 435 | unsigned int h_sync:1; /* sync-on-close */ |
436 | unsigned int h_jdata: 1; /* force data journaling */ | 436 | unsigned int h_jdata:1; /* force data journaling */ |
437 | unsigned int h_aborted: 1; /* fatal error on handle */ | 437 | unsigned int h_aborted:1; /* fatal error on handle */ |
438 | unsigned int h_cowing:1; /* COWing block to snapshot */ | ||
439 | |||
440 | /* Number of buffers requested by user: | ||
441 | * (before adding the COW credits factor) */ | ||
442 | unsigned int h_base_credits:14; | ||
443 | |||
444 | /* Number of buffers the user is allowed to dirty: | ||
445 | * (counts only buffers dirtied when !h_cowing) */ | ||
446 | unsigned int h_user_credits:14; | ||
447 | |||
438 | 448 | ||
439 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | 449 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
440 | struct lockdep_map h_lockdep_map; | 450 | struct lockdep_map h_lockdep_map; |
441 | #endif | 451 | #endif |
452 | |||
453 | #ifdef CONFIG_JBD2_DEBUG | ||
454 | /* COW debugging counters: */ | ||
455 | unsigned int h_cow_moved; /* blocks moved to snapshot */ | ||
456 | unsigned int h_cow_copied; /* blocks copied to snapshot */ | ||
457 | unsigned int h_cow_ok_jh; /* blocks already COWed during current | ||
458 | transaction */ | ||
459 | unsigned int h_cow_ok_bitmap; /* blocks not set in COW bitmap */ | ||
460 | unsigned int h_cow_ok_mapped;/* blocks already mapped in snapshot */ | ||
461 | unsigned int h_cow_bitmaps; /* COW bitmaps created */ | ||
462 | unsigned int h_cow_excluded; /* blocks set in exclude bitmap */ | ||
463 | #endif | ||
442 | }; | 464 | }; |
443 | 465 | ||
444 | 466 | ||
diff --git a/include/linux/journal-head.h b/include/linux/journal-head.h index 525aac3c97df..44e95d0a721f 100644 --- a/include/linux/journal-head.h +++ b/include/linux/journal-head.h | |||
@@ -41,6 +41,13 @@ struct journal_head { | |||
41 | unsigned b_modified; | 41 | unsigned b_modified; |
42 | 42 | ||
43 | /* | 43 | /* |
44 | * This feild tracks the last transaction id in which this buffer | ||
45 | * has been cowed | ||
46 | * [jbd_lock_bh_state()] | ||
47 | */ | ||
48 | unsigned b_cow_tid; | ||
49 | |||
50 | /* | ||
44 | * Copy of the buffer data frozen for writing to the log. | 51 | * Copy of the buffer data frozen for writing to the log. |
45 | * [jbd_lock_bh_state()] | 52 | * [jbd_lock_bh_state()] |
46 | */ | 53 | */ |
diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h index d8e9b3d1c23c..0df513b7a9f8 100644 --- a/include/linux/kallsyms.h +++ b/include/linux/kallsyms.h | |||
@@ -36,6 +36,7 @@ const char *kallsyms_lookup(unsigned long addr, | |||
36 | 36 | ||
37 | /* Look up a kernel symbol and return it in a text buffer. */ | 37 | /* Look up a kernel symbol and return it in a text buffer. */ |
38 | extern int sprint_symbol(char *buffer, unsigned long address); | 38 | extern int sprint_symbol(char *buffer, unsigned long address); |
39 | extern int sprint_backtrace(char *buffer, unsigned long address); | ||
39 | 40 | ||
40 | /* Look up a kernel symbol and print it to the kernel messages. */ | 41 | /* Look up a kernel symbol and print it to the kernel messages. */ |
41 | extern void __print_symbol(const char *fmt, unsigned long address); | 42 | extern void __print_symbol(const char *fmt, unsigned long address); |
@@ -79,6 +80,12 @@ static inline int sprint_symbol(char *buffer, unsigned long addr) | |||
79 | return 0; | 80 | return 0; |
80 | } | 81 | } |
81 | 82 | ||
83 | static inline int sprint_backtrace(char *buffer, unsigned long addr) | ||
84 | { | ||
85 | *buffer = '\0'; | ||
86 | return 0; | ||
87 | } | ||
88 | |||
82 | static inline int lookup_symbol_name(unsigned long addr, char *symname) | 89 | static inline int lookup_symbol_name(unsigned long addr, char *symname) |
83 | { | 90 | { |
84 | return -ERANGE; | 91 | return -ERANGE; |
diff --git a/include/linux/leds.h b/include/linux/leds.h index 383811d9af83..61e0340a4b77 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h | |||
@@ -145,6 +145,9 @@ extern void led_trigger_register_simple(const char *name, | |||
145 | extern void led_trigger_unregister_simple(struct led_trigger *trigger); | 145 | extern void led_trigger_unregister_simple(struct led_trigger *trigger); |
146 | extern void led_trigger_event(struct led_trigger *trigger, | 146 | extern void led_trigger_event(struct led_trigger *trigger, |
147 | enum led_brightness event); | 147 | enum led_brightness event); |
148 | extern void led_trigger_blink(struct led_trigger *trigger, | ||
149 | unsigned long *delay_on, | ||
150 | unsigned long *delay_off); | ||
148 | 151 | ||
149 | #else | 152 | #else |
150 | 153 | ||
diff --git a/include/linux/mfd/ab8500.h b/include/linux/mfd/ab8500.h index 56f8dea72152..6e4f77ef4d20 100644 --- a/include/linux/mfd/ab8500.h +++ b/include/linux/mfd/ab8500.h | |||
@@ -139,17 +139,23 @@ struct ab8500 { | |||
139 | u8 oldmask[AB8500_NUM_IRQ_REGS]; | 139 | u8 oldmask[AB8500_NUM_IRQ_REGS]; |
140 | }; | 140 | }; |
141 | 141 | ||
142 | struct regulator_reg_init; | ||
142 | struct regulator_init_data; | 143 | struct regulator_init_data; |
143 | 144 | ||
144 | /** | 145 | /** |
145 | * struct ab8500_platform_data - AB8500 platform data | 146 | * struct ab8500_platform_data - AB8500 platform data |
146 | * @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used | 147 | * @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used |
147 | * @init: board-specific initialization after detection of ab8500 | 148 | * @init: board-specific initialization after detection of ab8500 |
149 | * @num_regulator_reg_init: number of regulator init registers | ||
150 | * @regulator_reg_init: regulator init registers | ||
151 | * @num_regulator: number of regulators | ||
148 | * @regulator: machine-specific constraints for regulators | 152 | * @regulator: machine-specific constraints for regulators |
149 | */ | 153 | */ |
150 | struct ab8500_platform_data { | 154 | struct ab8500_platform_data { |
151 | int irq_base; | 155 | int irq_base; |
152 | void (*init) (struct ab8500 *); | 156 | void (*init) (struct ab8500 *); |
157 | int num_regulator_reg_init; | ||
158 | struct ab8500_regulator_reg_init *regulator_reg_init; | ||
153 | int num_regulator; | 159 | int num_regulator; |
154 | struct regulator_init_data *regulator; | 160 | struct regulator_init_data *regulator; |
155 | }; | 161 | }; |
diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h index 1408bf8eed5f..ad1b19aa6508 100644 --- a/include/linux/mfd/core.h +++ b/include/linux/mfd/core.h | |||
@@ -63,6 +63,24 @@ extern int mfd_cell_enable(struct platform_device *pdev); | |||
63 | extern int mfd_cell_disable(struct platform_device *pdev); | 63 | extern int mfd_cell_disable(struct platform_device *pdev); |
64 | 64 | ||
65 | /* | 65 | /* |
66 | * "Clone" multiple platform devices for a single cell. This is to be used | ||
67 | * for devices that have multiple users of a cell. For example, if an mfd | ||
68 | * driver wants the cell "foo" to be used by a GPIO driver, an MTD driver, | ||
69 | * and a platform driver, the following bit of code would be use after first | ||
70 | * calling mfd_add_devices(): | ||
71 | * | ||
72 | * const char *fclones[] = { "foo-gpio", "foo-mtd" }; | ||
73 | * err = mfd_clone_cells("foo", fclones, ARRAY_SIZE(fclones)); | ||
74 | * | ||
75 | * Each driver (MTD, GPIO, and platform driver) would then register | ||
76 | * platform_drivers for "foo-mtd", "foo-gpio", and "foo", respectively. | ||
77 | * The cell's .enable/.disable hooks should be used to deal with hardware | ||
78 | * resource contention. | ||
79 | */ | ||
80 | extern int mfd_clone_cell(const char *cell, const char **clones, | ||
81 | size_t n_clones); | ||
82 | |||
83 | /* | ||
66 | * Given a platform device that's been created by mfd_add_devices(), fetch | 84 | * Given a platform device that's been created by mfd_add_devices(), fetch |
67 | * the mfd_cell that created it. | 85 | * the mfd_cell that created it. |
68 | */ | 86 | */ |
@@ -87,13 +105,4 @@ extern int mfd_add_devices(struct device *parent, int id, | |||
87 | 105 | ||
88 | extern void mfd_remove_devices(struct device *parent); | 106 | extern void mfd_remove_devices(struct device *parent); |
89 | 107 | ||
90 | /* | ||
91 | * For MFD drivers with clients sharing access to resources, these create | ||
92 | * multiple platform devices per cell. Contention handling must still be | ||
93 | * handled via drivers (ie, with enable/disable hooks). | ||
94 | */ | ||
95 | extern int mfd_shared_platform_driver_register(struct platform_driver *drv, | ||
96 | const char *cellname); | ||
97 | extern void mfd_shared_platform_driver_unregister(struct platform_driver *drv); | ||
98 | |||
99 | #endif | 108 | #endif |
diff --git a/include/linux/mfd/max8997-private.h b/include/linux/mfd/max8997-private.h index 93a9477e075f..69d1010e2e51 100644 --- a/include/linux/mfd/max8997-private.h +++ b/include/linux/mfd/max8997-private.h | |||
@@ -24,6 +24,8 @@ | |||
24 | 24 | ||
25 | #include <linux/i2c.h> | 25 | #include <linux/i2c.h> |
26 | 26 | ||
27 | #define MAX8997_REG_INVALID (0xff) | ||
28 | |||
27 | enum max8997_pmic_reg { | 29 | enum max8997_pmic_reg { |
28 | MAX8997_REG_PMIC_ID0 = 0x00, | 30 | MAX8997_REG_PMIC_ID0 = 0x00, |
29 | MAX8997_REG_PMIC_ID1 = 0x01, | 31 | MAX8997_REG_PMIC_ID1 = 0x01, |
@@ -313,6 +315,7 @@ enum max8997_irq { | |||
313 | #define MAX8997_REG_BUCK2DVS(x) (MAX8997_REG_BUCK2DVS1 + (x) - 1) | 315 | #define MAX8997_REG_BUCK2DVS(x) (MAX8997_REG_BUCK2DVS1 + (x) - 1) |
314 | #define MAX8997_REG_BUCK5DVS(x) (MAX8997_REG_BUCK5DVS1 + (x) - 1) | 316 | #define MAX8997_REG_BUCK5DVS(x) (MAX8997_REG_BUCK5DVS1 + (x) - 1) |
315 | 317 | ||
318 | #define MAX8997_NUM_GPIO 12 | ||
316 | struct max8997_dev { | 319 | struct max8997_dev { |
317 | struct device *dev; | 320 | struct device *dev; |
318 | struct i2c_client *i2c; /* 0xcc / PMIC, Battery Control, and FLASH */ | 321 | struct i2c_client *i2c; /* 0xcc / PMIC, Battery Control, and FLASH */ |
@@ -324,11 +327,19 @@ struct max8997_dev { | |||
324 | int type; | 327 | int type; |
325 | struct platform_device *battery; /* battery control (not fuel gauge) */ | 328 | struct platform_device *battery; /* battery control (not fuel gauge) */ |
326 | 329 | ||
330 | int irq; | ||
331 | int ono; | ||
332 | int irq_base; | ||
327 | bool wakeup; | 333 | bool wakeup; |
334 | struct mutex irqlock; | ||
335 | int irq_masks_cur[MAX8997_IRQ_GROUP_NR]; | ||
336 | int irq_masks_cache[MAX8997_IRQ_GROUP_NR]; | ||
328 | 337 | ||
329 | /* For hibernation */ | 338 | /* For hibernation */ |
330 | u8 reg_dump[MAX8997_REG_PMIC_END + MAX8997_MUIC_REG_END + | 339 | u8 reg_dump[MAX8997_REG_PMIC_END + MAX8997_MUIC_REG_END + |
331 | MAX8997_HAPTIC_REG_END]; | 340 | MAX8997_HAPTIC_REG_END]; |
341 | |||
342 | bool gpio_status[MAX8997_NUM_GPIO]; | ||
332 | }; | 343 | }; |
333 | 344 | ||
334 | enum max8997_types { | 345 | enum max8997_types { |
@@ -336,6 +347,10 @@ enum max8997_types { | |||
336 | TYPE_MAX8966, | 347 | TYPE_MAX8966, |
337 | }; | 348 | }; |
338 | 349 | ||
350 | extern int max8997_irq_init(struct max8997_dev *max8997); | ||
351 | extern void max8997_irq_exit(struct max8997_dev *max8997); | ||
352 | extern int max8997_irq_resume(struct max8997_dev *max8997); | ||
353 | |||
339 | extern int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest); | 354 | extern int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest); |
340 | extern int max8997_bulk_read(struct i2c_client *i2c, u8 reg, int count, | 355 | extern int max8997_bulk_read(struct i2c_client *i2c, u8 reg, int count, |
341 | u8 *buf); | 356 | u8 *buf); |
@@ -344,4 +359,10 @@ extern int max8997_bulk_write(struct i2c_client *i2c, u8 reg, int count, | |||
344 | u8 *buf); | 359 | u8 *buf); |
345 | extern int max8997_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask); | 360 | extern int max8997_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask); |
346 | 361 | ||
362 | #define MAX8997_GPIO_INT_BOTH (0x3 << 4) | ||
363 | #define MAX8997_GPIO_INT_RISE (0x2 << 4) | ||
364 | #define MAX8997_GPIO_INT_FALL (0x1 << 4) | ||
365 | |||
366 | #define MAX8997_GPIO_INT_MASK (0x3 << 4) | ||
367 | #define MAX8997_GPIO_DATA_MASK (0x1 << 2) | ||
347 | #endif /* __LINUX_MFD_MAX8997_PRIV_H */ | 368 | #endif /* __LINUX_MFD_MAX8997_PRIV_H */ |
diff --git a/include/linux/mfd/max8997.h b/include/linux/mfd/max8997.h index cb671b3451bf..60931d089422 100644 --- a/include/linux/mfd/max8997.h +++ b/include/linux/mfd/max8997.h | |||
@@ -78,8 +78,11 @@ struct max8997_regulator_data { | |||
78 | }; | 78 | }; |
79 | 79 | ||
80 | struct max8997_platform_data { | 80 | struct max8997_platform_data { |
81 | bool wakeup; | 81 | /* IRQ */ |
82 | /* IRQ: Not implemented */ | 82 | int irq_base; |
83 | int ono; | ||
84 | int wakeup; | ||
85 | |||
83 | /* ---- PMIC ---- */ | 86 | /* ---- PMIC ---- */ |
84 | struct max8997_regulator_data *regulators; | 87 | struct max8997_regulator_data *regulators; |
85 | int num_regulators; | 88 | int num_regulators; |
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 049214642036..8985768e2c0d 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h | |||
@@ -39,6 +39,11 @@ | |||
39 | 39 | ||
40 | #include <asm/atomic.h> | 40 | #include <asm/atomic.h> |
41 | 41 | ||
42 | #define MAX_MSIX_P_PORT 17 | ||
43 | #define MAX_MSIX 64 | ||
44 | #define MSIX_LEGACY_SZ 4 | ||
45 | #define MIN_MSIX_P_PORT 5 | ||
46 | |||
42 | enum { | 47 | enum { |
43 | MLX4_FLAG_MSI_X = 1 << 0, | 48 | MLX4_FLAG_MSI_X = 1 << 0, |
44 | MLX4_FLAG_OLD_PORT_CMDS = 1 << 1, | 49 | MLX4_FLAG_OLD_PORT_CMDS = 1 << 1, |
@@ -145,8 +150,10 @@ enum { | |||
145 | }; | 150 | }; |
146 | 151 | ||
147 | enum mlx4_protocol { | 152 | enum mlx4_protocol { |
148 | MLX4_PROTOCOL_IB, | 153 | MLX4_PROT_IB_IPV6 = 0, |
149 | MLX4_PROTOCOL_EN, | 154 | MLX4_PROT_ETH, |
155 | MLX4_PROT_IB_IPV4, | ||
156 | MLX4_PROT_FCOE | ||
150 | }; | 157 | }; |
151 | 158 | ||
152 | enum { | 159 | enum { |
@@ -173,6 +180,12 @@ enum mlx4_special_vlan_idx { | |||
173 | MLX4_VLAN_REGULAR | 180 | MLX4_VLAN_REGULAR |
174 | }; | 181 | }; |
175 | 182 | ||
183 | enum mlx4_steer_type { | ||
184 | MLX4_MC_STEER = 0, | ||
185 | MLX4_UC_STEER, | ||
186 | MLX4_NUM_STEERS | ||
187 | }; | ||
188 | |||
176 | enum { | 189 | enum { |
177 | MLX4_NUM_FEXCH = 64 * 1024, | 190 | MLX4_NUM_FEXCH = 64 * 1024, |
178 | }; | 191 | }; |
@@ -223,6 +236,7 @@ struct mlx4_caps { | |||
223 | int num_eqs; | 236 | int num_eqs; |
224 | int reserved_eqs; | 237 | int reserved_eqs; |
225 | int num_comp_vectors; | 238 | int num_comp_vectors; |
239 | int comp_pool; | ||
226 | int num_mpts; | 240 | int num_mpts; |
227 | int num_mtt_segs; | 241 | int num_mtt_segs; |
228 | int mtts_per_seg; | 242 | int mtts_per_seg; |
@@ -245,6 +259,9 @@ struct mlx4_caps { | |||
245 | u16 stat_rate_support; | 259 | u16 stat_rate_support; |
246 | int udp_rss; | 260 | int udp_rss; |
247 | int loopback_support; | 261 | int loopback_support; |
262 | int vep_uc_steering; | ||
263 | int vep_mc_steering; | ||
264 | int wol; | ||
248 | u8 port_width_cap[MLX4_MAX_PORTS + 1]; | 265 | u8 port_width_cap[MLX4_MAX_PORTS + 1]; |
249 | int max_gso_sz; | 266 | int max_gso_sz; |
250 | int reserved_qps_cnt[MLX4_NUM_QP_REGION]; | 267 | int reserved_qps_cnt[MLX4_NUM_QP_REGION]; |
@@ -334,6 +351,17 @@ struct mlx4_fmr { | |||
334 | struct mlx4_uar { | 351 | struct mlx4_uar { |
335 | unsigned long pfn; | 352 | unsigned long pfn; |
336 | int index; | 353 | int index; |
354 | struct list_head bf_list; | ||
355 | unsigned free_bf_bmap; | ||
356 | void __iomem *map; | ||
357 | void __iomem *bf_map; | ||
358 | }; | ||
359 | |||
360 | struct mlx4_bf { | ||
361 | unsigned long offset; | ||
362 | int buf_size; | ||
363 | struct mlx4_uar *uar; | ||
364 | void __iomem *reg; | ||
337 | }; | 365 | }; |
338 | 366 | ||
339 | struct mlx4_cq { | 367 | struct mlx4_cq { |
@@ -415,7 +443,7 @@ struct mlx4_dev { | |||
415 | unsigned long flags; | 443 | unsigned long flags; |
416 | struct mlx4_caps caps; | 444 | struct mlx4_caps caps; |
417 | struct radix_tree_root qp_table_tree; | 445 | struct radix_tree_root qp_table_tree; |
418 | u32 rev_id; | 446 | u8 rev_id; |
419 | char board_id[MLX4_BOARD_ID_LEN]; | 447 | char board_id[MLX4_BOARD_ID_LEN]; |
420 | }; | 448 | }; |
421 | 449 | ||
@@ -461,6 +489,8 @@ void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn); | |||
461 | 489 | ||
462 | int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar); | 490 | int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar); |
463 | void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar); | 491 | void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar); |
492 | int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf); | ||
493 | void mlx4_bf_free(struct mlx4_dev *dev, struct mlx4_bf *bf); | ||
464 | 494 | ||
465 | int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift, | 495 | int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift, |
466 | struct mlx4_mtt *mtt); | 496 | struct mlx4_mtt *mtt); |
@@ -508,9 +538,15 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], | |||
508 | int block_mcast_loopback, enum mlx4_protocol protocol); | 538 | int block_mcast_loopback, enum mlx4_protocol protocol); |
509 | int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], | 539 | int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], |
510 | enum mlx4_protocol protocol); | 540 | enum mlx4_protocol protocol); |
541 | int mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port); | ||
542 | int mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port); | ||
543 | int mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port); | ||
544 | int mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port); | ||
545 | int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, u64 mac, u64 clear, u8 mode); | ||
511 | 546 | ||
512 | int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index); | 547 | int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *qpn, u8 wrap); |
513 | void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int index); | 548 | void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int qpn); |
549 | int mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac, u8 wrap); | ||
514 | 550 | ||
515 | int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx); | 551 | int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx); |
516 | int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index); | 552 | int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index); |
@@ -526,5 +562,10 @@ void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, | |||
526 | int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr); | 562 | int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr); |
527 | int mlx4_SYNC_TPT(struct mlx4_dev *dev); | 563 | int mlx4_SYNC_TPT(struct mlx4_dev *dev); |
528 | int mlx4_test_interrupts(struct mlx4_dev *dev); | 564 | int mlx4_test_interrupts(struct mlx4_dev *dev); |
565 | int mlx4_assign_eq(struct mlx4_dev *dev, char* name , int* vector); | ||
566 | void mlx4_release_eq(struct mlx4_dev *dev, int vec); | ||
567 | |||
568 | int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port); | ||
569 | int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port); | ||
529 | 570 | ||
530 | #endif /* MLX4_DEVICE_H */ | 571 | #endif /* MLX4_DEVICE_H */ |
diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h index 0eeb2a1a867c..9e9eb21056ca 100644 --- a/include/linux/mlx4/qp.h +++ b/include/linux/mlx4/qp.h | |||
@@ -303,6 +303,7 @@ struct mlx4_wqe_data_seg { | |||
303 | 303 | ||
304 | enum { | 304 | enum { |
305 | MLX4_INLINE_ALIGN = 64, | 305 | MLX4_INLINE_ALIGN = 64, |
306 | MLX4_INLINE_SEG = 1 << 31, | ||
306 | }; | 307 | }; |
307 | 308 | ||
308 | struct mlx4_wqe_inline_seg { | 309 | struct mlx4_wqe_inline_seg { |
diff --git a/include/linux/mm.h b/include/linux/mm.h index f9535b2c9558..7606d7db96c9 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -861,7 +861,7 @@ extern void pagefault_out_of_memory(void); | |||
861 | #define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK) | 861 | #define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK) |
862 | 862 | ||
863 | /* | 863 | /* |
864 | * Flags passed to __show_mem() and __show_free_areas() to suppress output in | 864 | * Flags passed to show_mem() and __show_free_areas() to suppress output in |
865 | * various contexts. | 865 | * various contexts. |
866 | */ | 866 | */ |
867 | #define SHOW_MEM_FILTER_NODES (0x0001u) /* filter disallowed nodes */ | 867 | #define SHOW_MEM_FILTER_NODES (0x0001u) /* filter disallowed nodes */ |
@@ -1360,8 +1360,7 @@ extern void setup_per_zone_wmarks(void); | |||
1360 | extern void calculate_zone_inactive_ratio(struct zone *zone); | 1360 | extern void calculate_zone_inactive_ratio(struct zone *zone); |
1361 | extern void mem_init(void); | 1361 | extern void mem_init(void); |
1362 | extern void __init mmap_init(void); | 1362 | extern void __init mmap_init(void); |
1363 | extern void show_mem(void); | 1363 | extern void show_mem(unsigned int flags); |
1364 | extern void __show_mem(unsigned int flags); | ||
1365 | extern void si_meminfo(struct sysinfo * val); | 1364 | extern void si_meminfo(struct sysinfo * val); |
1366 | extern void si_meminfo_node(struct sysinfo *val, int nid); | 1365 | extern void si_meminfo_node(struct sysinfo *val, int nid); |
1367 | extern int after_bootmem; | 1366 | extern int after_bootmem; |
diff --git a/include/linux/mtd/blktrans.h b/include/linux/mtd/blktrans.h index 26529ebd59cc..1bbd9f289245 100644 --- a/include/linux/mtd/blktrans.h +++ b/include/linux/mtd/blktrans.h | |||
@@ -36,6 +36,7 @@ struct mtd_blktrans_dev { | |||
36 | struct mtd_info *mtd; | 36 | struct mtd_info *mtd; |
37 | struct mutex lock; | 37 | struct mutex lock; |
38 | int devnum; | 38 | int devnum; |
39 | bool bg_stop; | ||
39 | unsigned long size; | 40 | unsigned long size; |
40 | int readonly; | 41 | int readonly; |
41 | int open; | 42 | int open; |
@@ -62,6 +63,7 @@ struct mtd_blktrans_ops { | |||
62 | unsigned long block, char *buffer); | 63 | unsigned long block, char *buffer); |
63 | int (*discard)(struct mtd_blktrans_dev *dev, | 64 | int (*discard)(struct mtd_blktrans_dev *dev, |
64 | unsigned long block, unsigned nr_blocks); | 65 | unsigned long block, unsigned nr_blocks); |
66 | void (*background)(struct mtd_blktrans_dev *dev); | ||
65 | 67 | ||
66 | /* Block layer ioctls */ | 68 | /* Block layer ioctls */ |
67 | int (*getgeo)(struct mtd_blktrans_dev *dev, struct hd_geometry *geo); | 69 | int (*getgeo)(struct mtd_blktrans_dev *dev, struct hd_geometry *geo); |
@@ -85,6 +87,7 @@ extern int register_mtd_blktrans(struct mtd_blktrans_ops *tr); | |||
85 | extern int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr); | 87 | extern int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr); |
86 | extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); | 88 | extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); |
87 | extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); | 89 | extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); |
90 | extern int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev); | ||
88 | 91 | ||
89 | 92 | ||
90 | #endif /* __MTD_TRANS_H__ */ | 93 | #endif /* __MTD_TRANS_H__ */ |
diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index a9baee6864af..0d823f2dd667 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h | |||
@@ -535,6 +535,7 @@ struct cfi_fixup { | |||
535 | #define CFI_MFR_CONTINUATION 0x007F | 535 | #define CFI_MFR_CONTINUATION 0x007F |
536 | 536 | ||
537 | #define CFI_MFR_AMD 0x0001 | 537 | #define CFI_MFR_AMD 0x0001 |
538 | #define CFI_MFR_AMIC 0x0037 | ||
538 | #define CFI_MFR_ATMEL 0x001F | 539 | #define CFI_MFR_ATMEL 0x001F |
539 | #define CFI_MFR_EON 0x001C | 540 | #define CFI_MFR_EON 0x001C |
540 | #define CFI_MFR_FUJITSU 0x0004 | 541 | #define CFI_MFR_FUJITSU 0x0004 |
diff --git a/include/linux/mtd/latch-addr-flash.h b/include/linux/mtd/latch-addr-flash.h new file mode 100644 index 000000000000..e94b8e128074 --- /dev/null +++ b/include/linux/mtd/latch-addr-flash.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * Interface for NOR flash driver whose high address lines are latched | ||
3 | * | ||
4 | * Copyright © 2008 MontaVista Software, Inc. <source@mvista.com> | ||
5 | * | ||
6 | * This file is licensed under the terms of the GNU General Public License | ||
7 | * version 2. This program is licensed "as is" without any warranty of any | ||
8 | * kind, whether express or implied. | ||
9 | */ | ||
10 | #ifndef __LATCH_ADDR_FLASH__ | ||
11 | #define __LATCH_ADDR_FLASH__ | ||
12 | |||
13 | struct map_info; | ||
14 | struct mtd_partition; | ||
15 | |||
16 | struct latch_addr_flash_data { | ||
17 | unsigned int width; | ||
18 | unsigned int size; | ||
19 | |||
20 | int (*init)(void *data, int cs); | ||
21 | void (*done)(void *data); | ||
22 | void (*set_window)(unsigned long offset, void *data); | ||
23 | void *data; | ||
24 | |||
25 | unsigned int nr_parts; | ||
26 | struct mtd_partition *parts; | ||
27 | }; | ||
28 | |||
29 | #endif | ||
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 1f489b247a29..ae67ef56a8f5 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h | |||
@@ -140,6 +140,7 @@ typedef enum { | |||
140 | NAND_ECC_HW, | 140 | NAND_ECC_HW, |
141 | NAND_ECC_HW_SYNDROME, | 141 | NAND_ECC_HW_SYNDROME, |
142 | NAND_ECC_HW_OOB_FIRST, | 142 | NAND_ECC_HW_OOB_FIRST, |
143 | NAND_ECC_SOFT_BCH, | ||
143 | } nand_ecc_modes_t; | 144 | } nand_ecc_modes_t; |
144 | 145 | ||
145 | /* | 146 | /* |
@@ -339,6 +340,7 @@ struct nand_hw_control { | |||
339 | * @prepad: padding information for syndrome based ecc generators | 340 | * @prepad: padding information for syndrome based ecc generators |
340 | * @postpad: padding information for syndrome based ecc generators | 341 | * @postpad: padding information for syndrome based ecc generators |
341 | * @layout: ECC layout control struct pointer | 342 | * @layout: ECC layout control struct pointer |
343 | * @priv: pointer to private ecc control data | ||
342 | * @hwctl: function to control hardware ecc generator. Must only | 344 | * @hwctl: function to control hardware ecc generator. Must only |
343 | * be provided if an hardware ECC is available | 345 | * be provided if an hardware ECC is available |
344 | * @calculate: function for ecc calculation or readback from ecc hardware | 346 | * @calculate: function for ecc calculation or readback from ecc hardware |
@@ -362,6 +364,7 @@ struct nand_ecc_ctrl { | |||
362 | int prepad; | 364 | int prepad; |
363 | int postpad; | 365 | int postpad; |
364 | struct nand_ecclayout *layout; | 366 | struct nand_ecclayout *layout; |
367 | void *priv; | ||
365 | void (*hwctl)(struct mtd_info *mtd, int mode); | 368 | void (*hwctl)(struct mtd_info *mtd, int mode); |
366 | int (*calculate)(struct mtd_info *mtd, const uint8_t *dat, | 369 | int (*calculate)(struct mtd_info *mtd, const uint8_t *dat, |
367 | uint8_t *ecc_code); | 370 | uint8_t *ecc_code); |
diff --git a/include/linux/mtd/nand_bch.h b/include/linux/mtd/nand_bch.h new file mode 100644 index 000000000000..74acf5367556 --- /dev/null +++ b/include/linux/mtd/nand_bch.h | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This file is the header for the NAND BCH ECC implementation. | ||
9 | */ | ||
10 | |||
11 | #ifndef __MTD_NAND_BCH_H__ | ||
12 | #define __MTD_NAND_BCH_H__ | ||
13 | |||
14 | struct mtd_info; | ||
15 | struct nand_bch_control; | ||
16 | |||
17 | #if defined(CONFIG_MTD_NAND_ECC_BCH) | ||
18 | |||
19 | static inline int mtd_nand_has_bch(void) { return 1; } | ||
20 | |||
21 | /* | ||
22 | * Calculate BCH ecc code | ||
23 | */ | ||
24 | int nand_bch_calculate_ecc(struct mtd_info *mtd, const u_char *dat, | ||
25 | u_char *ecc_code); | ||
26 | |||
27 | /* | ||
28 | * Detect and correct bit errors | ||
29 | */ | ||
30 | int nand_bch_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, | ||
31 | u_char *calc_ecc); | ||
32 | /* | ||
33 | * Initialize BCH encoder/decoder | ||
34 | */ | ||
35 | struct nand_bch_control * | ||
36 | nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, | ||
37 | unsigned int eccbytes, struct nand_ecclayout **ecclayout); | ||
38 | /* | ||
39 | * Release BCH encoder/decoder resources | ||
40 | */ | ||
41 | void nand_bch_free(struct nand_bch_control *nbc); | ||
42 | |||
43 | #else /* !CONFIG_MTD_NAND_ECC_BCH */ | ||
44 | |||
45 | static inline int mtd_nand_has_bch(void) { return 0; } | ||
46 | |||
47 | static inline int | ||
48 | nand_bch_calculate_ecc(struct mtd_info *mtd, const u_char *dat, | ||
49 | u_char *ecc_code) | ||
50 | { | ||
51 | return -1; | ||
52 | } | ||
53 | |||
54 | static inline int | ||
55 | nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, | ||
56 | unsigned char *read_ecc, unsigned char *calc_ecc) | ||
57 | { | ||
58 | return -1; | ||
59 | } | ||
60 | |||
61 | static inline struct nand_bch_control * | ||
62 | nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, | ||
63 | unsigned int eccbytes, struct nand_ecclayout **ecclayout) | ||
64 | { | ||
65 | return NULL; | ||
66 | } | ||
67 | |||
68 | static inline void nand_bch_free(struct nand_bch_control *nbc) {} | ||
69 | |||
70 | #endif /* CONFIG_MTD_NAND_ECC_BCH */ | ||
71 | |||
72 | #endif /* __MTD_NAND_BCH_H__ */ | ||
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h index ae418e41d8f5..52b6f187bf49 100644 --- a/include/linux/mtd/onenand.h +++ b/include/linux/mtd/onenand.h | |||
@@ -198,6 +198,7 @@ struct onenand_chip { | |||
198 | #define ONENAND_SKIP_UNLOCK_CHECK (0x0100) | 198 | #define ONENAND_SKIP_UNLOCK_CHECK (0x0100) |
199 | #define ONENAND_PAGEBUF_ALLOC (0x1000) | 199 | #define ONENAND_PAGEBUF_ALLOC (0x1000) |
200 | #define ONENAND_OOBBUF_ALLOC (0x2000) | 200 | #define ONENAND_OOBBUF_ALLOC (0x2000) |
201 | #define ONENAND_SKIP_INITIAL_UNLOCKING (0x4000) | ||
201 | 202 | ||
202 | #define ONENAND_IS_4KB_PAGE(this) \ | 203 | #define ONENAND_IS_4KB_PAGE(this) \ |
203 | (this->options & ONENAND_HAS_4KB_PAGE) | 204 | (this->options & ONENAND_HAS_4KB_PAGE) |
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 134716e5e350..b528f6d4b860 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h | |||
@@ -550,6 +550,7 @@ enum { | |||
550 | NFSPROC4_CLNT_SETACL, | 550 | NFSPROC4_CLNT_SETACL, |
551 | NFSPROC4_CLNT_FS_LOCATIONS, | 551 | NFSPROC4_CLNT_FS_LOCATIONS, |
552 | NFSPROC4_CLNT_RELEASE_LOCKOWNER, | 552 | NFSPROC4_CLNT_RELEASE_LOCKOWNER, |
553 | NFSPROC4_CLNT_SECINFO, | ||
553 | 554 | ||
554 | /* nfs41 */ | 555 | /* nfs41 */ |
555 | NFSPROC4_CLNT_EXCHANGE_ID, | 556 | NFSPROC4_CLNT_EXCHANGE_ID, |
@@ -560,6 +561,7 @@ enum { | |||
560 | NFSPROC4_CLNT_RECLAIM_COMPLETE, | 561 | NFSPROC4_CLNT_RECLAIM_COMPLETE, |
561 | NFSPROC4_CLNT_LAYOUTGET, | 562 | NFSPROC4_CLNT_LAYOUTGET, |
562 | NFSPROC4_CLNT_GETDEVICEINFO, | 563 | NFSPROC4_CLNT_GETDEVICEINFO, |
564 | NFSPROC4_CLNT_LAYOUTCOMMIT, | ||
563 | }; | 565 | }; |
564 | 566 | ||
565 | /* nfs41 types */ | 567 | /* nfs41 types */ |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index f88522b10a38..1b93b9c60e55 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -33,6 +33,8 @@ | |||
33 | #define FLUSH_STABLE 4 /* commit to stable storage */ | 33 | #define FLUSH_STABLE 4 /* commit to stable storage */ |
34 | #define FLUSH_LOWPRI 8 /* low priority background flush */ | 34 | #define FLUSH_LOWPRI 8 /* low priority background flush */ |
35 | #define FLUSH_HIGHPRI 16 /* high priority memory reclaim flush */ | 35 | #define FLUSH_HIGHPRI 16 /* high priority memory reclaim flush */ |
36 | #define FLUSH_COND_STABLE 32 /* conditional stable write - only stable | ||
37 | * if everything fits in one RPC */ | ||
36 | 38 | ||
37 | #ifdef __KERNEL__ | 39 | #ifdef __KERNEL__ |
38 | 40 | ||
@@ -93,8 +95,13 @@ struct nfs_open_context { | |||
93 | int error; | 95 | int error; |
94 | 96 | ||
95 | struct list_head list; | 97 | struct list_head list; |
98 | }; | ||
96 | 99 | ||
100 | struct nfs_open_dir_context { | ||
101 | struct rpc_cred *cred; | ||
97 | __u64 dir_cookie; | 102 | __u64 dir_cookie; |
103 | __u64 dup_cookie; | ||
104 | int duped; | ||
98 | }; | 105 | }; |
99 | 106 | ||
100 | /* | 107 | /* |
@@ -191,6 +198,7 @@ struct nfs_inode { | |||
191 | 198 | ||
192 | /* pNFS layout information */ | 199 | /* pNFS layout information */ |
193 | struct pnfs_layout_hdr *layout; | 200 | struct pnfs_layout_hdr *layout; |
201 | atomic_t commits_outstanding; | ||
194 | #endif /* CONFIG_NFS_V4*/ | 202 | #endif /* CONFIG_NFS_V4*/ |
195 | #ifdef CONFIG_NFS_FSCACHE | 203 | #ifdef CONFIG_NFS_FSCACHE |
196 | struct fscache_cookie *fscache; | 204 | struct fscache_cookie *fscache; |
@@ -219,6 +227,8 @@ struct nfs_inode { | |||
219 | #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ | 227 | #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ |
220 | #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ | 228 | #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ |
221 | #define NFS_INO_COMMIT (7) /* inode is committing unstable writes */ | 229 | #define NFS_INO_COMMIT (7) /* inode is committing unstable writes */ |
230 | #define NFS_INO_PNFS_COMMIT (8) /* use pnfs code for commit */ | ||
231 | #define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */ | ||
222 | 232 | ||
223 | static inline struct nfs_inode *NFS_I(const struct inode *inode) | 233 | static inline struct nfs_inode *NFS_I(const struct inode *inode) |
224 | { | 234 | { |
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 90907ada6d52..8023e4e25133 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h | |||
@@ -33,11 +33,15 @@ enum { | |||
33 | PG_CLEAN, | 33 | PG_CLEAN, |
34 | PG_NEED_COMMIT, | 34 | PG_NEED_COMMIT, |
35 | PG_NEED_RESCHED, | 35 | PG_NEED_RESCHED, |
36 | PG_PNFS_COMMIT, | ||
36 | }; | 37 | }; |
37 | 38 | ||
38 | struct nfs_inode; | 39 | struct nfs_inode; |
39 | struct nfs_page { | 40 | struct nfs_page { |
40 | struct list_head wb_list; /* Defines state of page: */ | 41 | union { |
42 | struct list_head wb_list; /* Defines state of page: */ | ||
43 | struct pnfs_layout_segment *wb_commit_lseg; /* Used when PG_PNFS_COMMIT set */ | ||
44 | }; | ||
41 | struct page *wb_page; /* page to read in/write out */ | 45 | struct page *wb_page; /* page to read in/write out */ |
42 | struct nfs_open_context *wb_context; /* File state context info */ | 46 | struct nfs_open_context *wb_context; /* File state context info */ |
43 | struct nfs_lock_context *wb_lock_context; /* lock context info */ | 47 | struct nfs_lock_context *wb_lock_context; /* lock context info */ |
@@ -57,6 +61,7 @@ struct nfs_pageio_descriptor { | |||
57 | size_t pg_count; | 61 | size_t pg_count; |
58 | size_t pg_bsize; | 62 | size_t pg_bsize; |
59 | unsigned int pg_base; | 63 | unsigned int pg_base; |
64 | char pg_moreio; | ||
60 | 65 | ||
61 | struct inode *pg_inode; | 66 | struct inode *pg_inode; |
62 | int (*pg_doio)(struct nfs_pageio_descriptor *); | 67 | int (*pg_doio)(struct nfs_pageio_descriptor *); |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 2c2c67d2eb42..78b101e487ea 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #include <linux/nfsacl.h> | 4 | #include <linux/nfsacl.h> |
5 | #include <linux/nfs3.h> | 5 | #include <linux/nfs3.h> |
6 | #include <linux/sunrpc/gss_api.h> | ||
6 | 7 | ||
7 | /* | 8 | /* |
8 | * To change the maximum rsize and wsize supported by the NFS client, adjust | 9 | * To change the maximum rsize and wsize supported by the NFS client, adjust |
@@ -14,6 +15,9 @@ | |||
14 | #define NFS_DEF_FILE_IO_SIZE (4096U) | 15 | #define NFS_DEF_FILE_IO_SIZE (4096U) |
15 | #define NFS_MIN_FILE_IO_SIZE (1024U) | 16 | #define NFS_MIN_FILE_IO_SIZE (1024U) |
16 | 17 | ||
18 | /* Forward declaration for NFS v3 */ | ||
19 | struct nfs4_secinfo_flavors; | ||
20 | |||
17 | struct nfs_fsid { | 21 | struct nfs_fsid { |
18 | uint64_t major; | 22 | uint64_t major; |
19 | uint64_t minor; | 23 | uint64_t minor; |
@@ -78,6 +82,7 @@ struct nfs_fattr { | |||
78 | #define NFS_ATTR_FATTR_CHANGE (1U << 17) | 82 | #define NFS_ATTR_FATTR_CHANGE (1U << 17) |
79 | #define NFS_ATTR_FATTR_PRECHANGE (1U << 18) | 83 | #define NFS_ATTR_FATTR_PRECHANGE (1U << 18) |
80 | #define NFS_ATTR_FATTR_V4_REFERRAL (1U << 19) /* NFSv4 referral */ | 84 | #define NFS_ATTR_FATTR_V4_REFERRAL (1U << 19) /* NFSv4 referral */ |
85 | #define NFS_ATTR_FATTR_MOUNTPOINT (1U << 20) /* Treat as mountpoint */ | ||
81 | 86 | ||
82 | #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \ | 87 | #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \ |
83 | | NFS_ATTR_FATTR_MODE \ | 88 | | NFS_ATTR_FATTR_MODE \ |
@@ -190,8 +195,9 @@ struct nfs4_get_lease_time_res { | |||
190 | #define PNFS_LAYOUT_MAXSIZE 4096 | 195 | #define PNFS_LAYOUT_MAXSIZE 4096 |
191 | 196 | ||
192 | struct nfs4_layoutdriver_data { | 197 | struct nfs4_layoutdriver_data { |
198 | struct page **pages; | ||
199 | __u32 pglen; | ||
193 | __u32 len; | 200 | __u32 len; |
194 | void *buf; | ||
195 | }; | 201 | }; |
196 | 202 | ||
197 | struct pnfs_layout_range { | 203 | struct pnfs_layout_range { |
@@ -209,6 +215,7 @@ struct nfs4_layoutget_args { | |||
209 | struct nfs_open_context *ctx; | 215 | struct nfs_open_context *ctx; |
210 | struct nfs4_sequence_args seq_args; | 216 | struct nfs4_sequence_args seq_args; |
211 | nfs4_stateid stateid; | 217 | nfs4_stateid stateid; |
218 | struct nfs4_layoutdriver_data layout; | ||
212 | }; | 219 | }; |
213 | 220 | ||
214 | struct nfs4_layoutget_res { | 221 | struct nfs4_layoutget_res { |
@@ -216,8 +223,8 @@ struct nfs4_layoutget_res { | |||
216 | struct pnfs_layout_range range; | 223 | struct pnfs_layout_range range; |
217 | __u32 type; | 224 | __u32 type; |
218 | nfs4_stateid stateid; | 225 | nfs4_stateid stateid; |
219 | struct nfs4_layoutdriver_data layout; | ||
220 | struct nfs4_sequence_res seq_res; | 226 | struct nfs4_sequence_res seq_res; |
227 | struct nfs4_layoutdriver_data *layoutp; | ||
221 | }; | 228 | }; |
222 | 229 | ||
223 | struct nfs4_layoutget { | 230 | struct nfs4_layoutget { |
@@ -236,6 +243,29 @@ struct nfs4_getdeviceinfo_res { | |||
236 | struct nfs4_sequence_res seq_res; | 243 | struct nfs4_sequence_res seq_res; |
237 | }; | 244 | }; |
238 | 245 | ||
246 | struct nfs4_layoutcommit_args { | ||
247 | nfs4_stateid stateid; | ||
248 | __u64 lastbytewritten; | ||
249 | struct inode *inode; | ||
250 | const u32 *bitmask; | ||
251 | struct nfs4_sequence_args seq_args; | ||
252 | }; | ||
253 | |||
254 | struct nfs4_layoutcommit_res { | ||
255 | struct nfs_fattr *fattr; | ||
256 | const struct nfs_server *server; | ||
257 | struct nfs4_sequence_res seq_res; | ||
258 | }; | ||
259 | |||
260 | struct nfs4_layoutcommit_data { | ||
261 | struct rpc_task task; | ||
262 | struct nfs_fattr fattr; | ||
263 | struct pnfs_layout_segment *lseg; | ||
264 | struct rpc_cred *cred; | ||
265 | struct nfs4_layoutcommit_args args; | ||
266 | struct nfs4_layoutcommit_res res; | ||
267 | }; | ||
268 | |||
239 | /* | 269 | /* |
240 | * Arguments to the open call. | 270 | * Arguments to the open call. |
241 | */ | 271 | */ |
@@ -936,6 +966,38 @@ struct nfs4_fs_locations_res { | |||
936 | struct nfs4_sequence_res seq_res; | 966 | struct nfs4_sequence_res seq_res; |
937 | }; | 967 | }; |
938 | 968 | ||
969 | struct nfs4_secinfo_oid { | ||
970 | unsigned int len; | ||
971 | char data[GSS_OID_MAX_LEN]; | ||
972 | }; | ||
973 | |||
974 | struct nfs4_secinfo_gss { | ||
975 | struct nfs4_secinfo_oid sec_oid4; | ||
976 | unsigned int qop4; | ||
977 | unsigned int service; | ||
978 | }; | ||
979 | |||
980 | struct nfs4_secinfo_flavor { | ||
981 | unsigned int flavor; | ||
982 | struct nfs4_secinfo_gss gss; | ||
983 | }; | ||
984 | |||
985 | struct nfs4_secinfo_flavors { | ||
986 | unsigned int num_flavors; | ||
987 | struct nfs4_secinfo_flavor flavors[0]; | ||
988 | }; | ||
989 | |||
990 | struct nfs4_secinfo_arg { | ||
991 | const struct nfs_fh *dir_fh; | ||
992 | const struct qstr *name; | ||
993 | struct nfs4_sequence_args seq_args; | ||
994 | }; | ||
995 | |||
996 | struct nfs4_secinfo_res { | ||
997 | struct nfs4_secinfo_flavors *flavors; | ||
998 | struct nfs4_sequence_res seq_res; | ||
999 | }; | ||
1000 | |||
939 | #endif /* CONFIG_NFS_V4 */ | 1001 | #endif /* CONFIG_NFS_V4 */ |
940 | 1002 | ||
941 | struct nfstime4 { | 1003 | struct nfstime4 { |
@@ -1040,6 +1102,7 @@ struct nfs_write_data { | |||
1040 | struct nfs_writeres res; /* result struct */ | 1102 | struct nfs_writeres res; /* result struct */ |
1041 | struct pnfs_layout_segment *lseg; | 1103 | struct pnfs_layout_segment *lseg; |
1042 | struct nfs_client *ds_clp; /* pNFS data server */ | 1104 | struct nfs_client *ds_clp; /* pNFS data server */ |
1105 | int ds_commit_index; | ||
1043 | const struct rpc_call_ops *mds_ops; | 1106 | const struct rpc_call_ops *mds_ops; |
1044 | int (*write_done_cb) (struct rpc_task *task, struct nfs_write_data *data); | 1107 | int (*write_done_cb) (struct rpc_task *task, struct nfs_write_data *data); |
1045 | #ifdef CONFIG_NFS_V4 | 1108 | #ifdef CONFIG_NFS_V4 |
@@ -1071,7 +1134,7 @@ struct nfs_rpc_ops { | |||
1071 | struct nfs_fattr *); | 1134 | struct nfs_fattr *); |
1072 | int (*setattr) (struct dentry *, struct nfs_fattr *, | 1135 | int (*setattr) (struct dentry *, struct nfs_fattr *, |
1073 | struct iattr *); | 1136 | struct iattr *); |
1074 | int (*lookup) (struct inode *, struct qstr *, | 1137 | int (*lookup) (struct rpc_clnt *clnt, struct inode *, struct qstr *, |
1075 | struct nfs_fh *, struct nfs_fattr *); | 1138 | struct nfs_fh *, struct nfs_fattr *); |
1076 | int (*access) (struct inode *, struct nfs_access_entry *); | 1139 | int (*access) (struct inode *, struct nfs_access_entry *); |
1077 | int (*readlink)(struct inode *, struct page *, unsigned int, | 1140 | int (*readlink)(struct inode *, struct page *, unsigned int, |
@@ -1118,6 +1181,7 @@ struct nfs_rpc_ops { | |||
1118 | struct iattr *iattr); | 1181 | struct iattr *iattr); |
1119 | int (*init_client) (struct nfs_client *, const struct rpc_timeout *, | 1182 | int (*init_client) (struct nfs_client *, const struct rpc_timeout *, |
1120 | const char *, rpc_authflavor_t, int); | 1183 | const char *, rpc_authflavor_t, int); |
1184 | int (*secinfo)(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); | ||
1121 | }; | 1185 | }; |
1122 | 1186 | ||
1123 | /* | 1187 | /* |
diff --git a/include/linux/pci-aspm.h b/include/linux/pci-aspm.h index ce6810512c66..67cb3ae38016 100644 --- a/include/linux/pci-aspm.h +++ b/include/linux/pci-aspm.h | |||
@@ -26,6 +26,7 @@ | |||
26 | extern void pcie_aspm_init_link_state(struct pci_dev *pdev); | 26 | extern void pcie_aspm_init_link_state(struct pci_dev *pdev); |
27 | extern void pcie_aspm_exit_link_state(struct pci_dev *pdev); | 27 | extern void pcie_aspm_exit_link_state(struct pci_dev *pdev); |
28 | extern void pcie_aspm_pm_state_change(struct pci_dev *pdev); | 28 | extern void pcie_aspm_pm_state_change(struct pci_dev *pdev); |
29 | extern void pcie_aspm_powersave_config_link(struct pci_dev *pdev); | ||
29 | extern void pci_disable_link_state(struct pci_dev *pdev, int state); | 30 | extern void pci_disable_link_state(struct pci_dev *pdev, int state); |
30 | extern void pcie_clear_aspm(void); | 31 | extern void pcie_clear_aspm(void); |
31 | extern void pcie_no_aspm(void); | 32 | extern void pcie_no_aspm(void); |
@@ -39,6 +40,9 @@ static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev) | |||
39 | static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) | 40 | static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) |
40 | { | 41 | { |
41 | } | 42 | } |
43 | static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) | ||
44 | { | ||
45 | } | ||
42 | static inline void pci_disable_link_state(struct pci_dev *pdev, int state) | 46 | static inline void pci_disable_link_state(struct pci_dev *pdev, int state) |
43 | { | 47 | { |
44 | } | 48 | } |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 16c9f2e61977..96f70d7e058d 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -1002,12 +1002,11 @@ extern bool pcie_ports_auto; | |||
1002 | #endif | 1002 | #endif |
1003 | 1003 | ||
1004 | #ifndef CONFIG_PCIEASPM | 1004 | #ifndef CONFIG_PCIEASPM |
1005 | static inline int pcie_aspm_enabled(void) | 1005 | static inline int pcie_aspm_enabled(void) { return 0; } |
1006 | { | 1006 | static inline bool pcie_aspm_support_enabled(void) { return false; } |
1007 | return 0; | ||
1008 | } | ||
1009 | #else | 1007 | #else |
1010 | extern int pcie_aspm_enabled(void); | 1008 | extern int pcie_aspm_enabled(void); |
1009 | extern bool pcie_aspm_support_enabled(void); | ||
1011 | #endif | 1010 | #endif |
1012 | 1011 | ||
1013 | #ifdef CONFIG_PCIEAER | 1012 | #ifdef CONFIG_PCIEAER |
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index f495c0147240..311b4dc785a1 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -938,9 +938,7 @@ struct perf_cpu_context { | |||
938 | struct list_head rotation_list; | 938 | struct list_head rotation_list; |
939 | int jiffies_interval; | 939 | int jiffies_interval; |
940 | struct pmu *active_pmu; | 940 | struct pmu *active_pmu; |
941 | #ifdef CONFIG_CGROUP_PERF | ||
942 | struct perf_cgroup *cgrp; | 941 | struct perf_cgroup *cgrp; |
943 | #endif | ||
944 | }; | 942 | }; |
945 | 943 | ||
946 | struct perf_output_handle { | 944 | struct perf_output_handle { |
diff --git a/include/linux/pm.h b/include/linux/pm.h index 6618216bb973..512e09177e57 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h | |||
@@ -529,13 +529,19 @@ struct dev_power_domain { | |||
529 | */ | 529 | */ |
530 | 530 | ||
531 | #ifdef CONFIG_PM_SLEEP | 531 | #ifdef CONFIG_PM_SLEEP |
532 | extern void device_pm_lock(void); | 532 | #ifndef CONFIG_ARCH_NO_SYSDEV_OPS |
533 | extern int sysdev_suspend(pm_message_t state); | ||
533 | extern int sysdev_resume(void); | 534 | extern int sysdev_resume(void); |
535 | #else | ||
536 | static inline int sysdev_suspend(pm_message_t state) { return 0; } | ||
537 | static inline int sysdev_resume(void) { return 0; } | ||
538 | #endif | ||
539 | |||
540 | extern void device_pm_lock(void); | ||
534 | extern void dpm_resume_noirq(pm_message_t state); | 541 | extern void dpm_resume_noirq(pm_message_t state); |
535 | extern void dpm_resume_end(pm_message_t state); | 542 | extern void dpm_resume_end(pm_message_t state); |
536 | 543 | ||
537 | extern void device_pm_unlock(void); | 544 | extern void device_pm_unlock(void); |
538 | extern int sysdev_suspend(pm_message_t state); | ||
539 | extern int dpm_suspend_noirq(pm_message_t state); | 545 | extern int dpm_suspend_noirq(pm_message_t state); |
540 | extern int dpm_suspend_start(pm_message_t state); | 546 | extern int dpm_suspend_start(pm_message_t state); |
541 | 547 | ||
diff --git a/include/linux/power/bq20z75.h b/include/linux/power/bq20z75.h new file mode 100644 index 000000000000..b0843b68af92 --- /dev/null +++ b/include/linux/power/bq20z75.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * Gas Gauge driver for TI's BQ20Z75 | ||
3 | * | ||
4 | * Copyright (c) 2010, NVIDIA Corporation. | ||
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 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef __LINUX_POWER_BQ20Z75_H_ | ||
22 | #define __LINUX_POWER_BQ20Z75_H_ | ||
23 | |||
24 | #include <linux/power_supply.h> | ||
25 | #include <linux/types.h> | ||
26 | |||
27 | /** | ||
28 | * struct bq20z75_platform_data - platform data for bq20z75 devices | ||
29 | * @battery_detect: GPIO which is used to detect battery presence | ||
30 | * @battery_detect_present: gpio state when battery is present (0 / 1) | ||
31 | * @i2c_retry_count: # of times to retry on i2c IO failure | ||
32 | */ | ||
33 | struct bq20z75_platform_data { | ||
34 | int battery_detect; | ||
35 | int battery_detect_present; | ||
36 | int i2c_retry_count; | ||
37 | }; | ||
38 | |||
39 | #endif | ||
diff --git a/include/linux/power/bq27x00_battery.h b/include/linux/power/bq27x00_battery.h new file mode 100644 index 000000000000..a857f719bf40 --- /dev/null +++ b/include/linux/power/bq27x00_battery.h | |||
@@ -0,0 +1,19 @@ | |||
1 | #ifndef __LINUX_BQ27X00_BATTERY_H__ | ||
2 | #define __LINUX_BQ27X00_BATTERY_H__ | ||
3 | |||
4 | /** | ||
5 | * struct bq27000_plaform_data - Platform data for bq27000 devices | ||
6 | * @name: Name of the battery. If NULL the driver will fallback to "bq27000". | ||
7 | * @read: HDQ read callback. | ||
8 | * This function should provide access to the HDQ bus the battery is | ||
9 | * connected to. | ||
10 | * The first parameter is a pointer to the battery device, the second the | ||
11 | * register to be read. The return value should either be the content of | ||
12 | * the passed register or an error value. | ||
13 | */ | ||
14 | struct bq27000_platform_data { | ||
15 | const char *name; | ||
16 | int (*read)(struct device *dev, unsigned int); | ||
17 | }; | ||
18 | |||
19 | #endif | ||
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 7d7325685c42..204c18dfdc9e 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h | |||
@@ -173,6 +173,8 @@ struct power_supply { | |||
173 | char *full_trig_name; | 173 | char *full_trig_name; |
174 | struct led_trigger *online_trig; | 174 | struct led_trigger *online_trig; |
175 | char *online_trig_name; | 175 | char *online_trig_name; |
176 | struct led_trigger *charging_blink_full_solid_trig; | ||
177 | char *charging_blink_full_solid_trig_name; | ||
176 | #endif | 178 | #endif |
177 | }; | 179 | }; |
178 | 180 | ||
@@ -213,4 +215,49 @@ extern void power_supply_unregister(struct power_supply *psy); | |||
213 | /* For APM emulation, think legacy userspace. */ | 215 | /* For APM emulation, think legacy userspace. */ |
214 | extern struct class *power_supply_class; | 216 | extern struct class *power_supply_class; |
215 | 217 | ||
218 | static inline bool power_supply_is_amp_property(enum power_supply_property psp) | ||
219 | { | ||
220 | switch (psp) { | ||
221 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | ||
222 | case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN: | ||
223 | case POWER_SUPPLY_PROP_CHARGE_FULL: | ||
224 | case POWER_SUPPLY_PROP_CHARGE_EMPTY: | ||
225 | case POWER_SUPPLY_PROP_CHARGE_NOW: | ||
226 | case POWER_SUPPLY_PROP_CHARGE_AVG: | ||
227 | case POWER_SUPPLY_PROP_CHARGE_COUNTER: | ||
228 | case POWER_SUPPLY_PROP_CURRENT_MAX: | ||
229 | case POWER_SUPPLY_PROP_CURRENT_NOW: | ||
230 | case POWER_SUPPLY_PROP_CURRENT_AVG: | ||
231 | return 1; | ||
232 | default: | ||
233 | break; | ||
234 | } | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static inline bool power_supply_is_watt_property(enum power_supply_property psp) | ||
240 | { | ||
241 | switch (psp) { | ||
242 | case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: | ||
243 | case POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN: | ||
244 | case POWER_SUPPLY_PROP_ENERGY_FULL: | ||
245 | case POWER_SUPPLY_PROP_ENERGY_EMPTY: | ||
246 | case POWER_SUPPLY_PROP_ENERGY_NOW: | ||
247 | case POWER_SUPPLY_PROP_ENERGY_AVG: | ||
248 | case POWER_SUPPLY_PROP_VOLTAGE_MAX: | ||
249 | case POWER_SUPPLY_PROP_VOLTAGE_MIN: | ||
250 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: | ||
251 | case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: | ||
252 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
253 | case POWER_SUPPLY_PROP_VOLTAGE_AVG: | ||
254 | case POWER_SUPPLY_PROP_POWER_NOW: | ||
255 | return 1; | ||
256 | default: | ||
257 | break; | ||
258 | } | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
216 | #endif /* __LINUX_POWER_SUPPLY_H__ */ | 263 | #endif /* __LINUX_POWER_SUPPLY_H__ */ |
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index eb354f6f26b3..26f9e3612e0f 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h | |||
@@ -277,7 +277,7 @@ static inline int dquot_alloc_space(struct inode *inode, qsize_t nr) | |||
277 | /* | 277 | /* |
278 | * Mark inode fully dirty. Since we are allocating blocks, inode | 278 | * Mark inode fully dirty. Since we are allocating blocks, inode |
279 | * would become fully dirty soon anyway and it reportedly | 279 | * would become fully dirty soon anyway and it reportedly |
280 | * reduces inode_lock contention. | 280 | * reduces lock contention. |
281 | */ | 281 | */ |
282 | mark_inode_dirty(inode); | 282 | mark_inode_dirty(inode); |
283 | } | 283 | } |
diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index 6a210f1511fc..76579f964a29 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h | |||
@@ -3,8 +3,8 @@ | |||
3 | * | 3 | * |
4 | * License Terms: GNU General Public License v2 | 4 | * License Terms: GNU General Public License v2 |
5 | * | 5 | * |
6 | * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson | 6 | * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson |
7 | * | 7 | * Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #ifndef __LINUX_MFD_AB8500_REGULATOR_H | 10 | #ifndef __LINUX_MFD_AB8500_REGULATOR_H |
@@ -17,6 +17,7 @@ enum ab8500_regulator_id { | |||
17 | AB8500_LDO_AUX3, | 17 | AB8500_LDO_AUX3, |
18 | AB8500_LDO_INTCORE, | 18 | AB8500_LDO_INTCORE, |
19 | AB8500_LDO_TVOUT, | 19 | AB8500_LDO_TVOUT, |
20 | AB8500_LDO_USB, | ||
20 | AB8500_LDO_AUDIO, | 21 | AB8500_LDO_AUDIO, |
21 | AB8500_LDO_ANAMIC1, | 22 | AB8500_LDO_ANAMIC1, |
22 | AB8500_LDO_ANAMIC2, | 23 | AB8500_LDO_ANAMIC2, |
@@ -24,4 +25,50 @@ enum ab8500_regulator_id { | |||
24 | AB8500_LDO_ANA, | 25 | AB8500_LDO_ANA, |
25 | AB8500_NUM_REGULATORS, | 26 | AB8500_NUM_REGULATORS, |
26 | }; | 27 | }; |
28 | |||
29 | /* AB8500 register initialization */ | ||
30 | struct ab8500_regulator_reg_init { | ||
31 | int id; | ||
32 | u8 value; | ||
33 | }; | ||
34 | |||
35 | #define INIT_REGULATOR_REGISTER(_id, _value) \ | ||
36 | { \ | ||
37 | .id = _id, \ | ||
38 | .value = _value, \ | ||
39 | } | ||
40 | |||
41 | /* AB8500 registers */ | ||
42 | enum ab8500_regulator_reg { | ||
43 | AB8500_REGUREQUESTCTRL2, | ||
44 | AB8500_REGUREQUESTCTRL3, | ||
45 | AB8500_REGUREQUESTCTRL4, | ||
46 | AB8500_REGUSYSCLKREQ1HPVALID1, | ||
47 | AB8500_REGUSYSCLKREQ1HPVALID2, | ||
48 | AB8500_REGUHWHPREQ1VALID1, | ||
49 | AB8500_REGUHWHPREQ1VALID2, | ||
50 | AB8500_REGUHWHPREQ2VALID1, | ||
51 | AB8500_REGUHWHPREQ2VALID2, | ||
52 | AB8500_REGUSWHPREQVALID1, | ||
53 | AB8500_REGUSWHPREQVALID2, | ||
54 | AB8500_REGUSYSCLKREQVALID1, | ||
55 | AB8500_REGUSYSCLKREQVALID2, | ||
56 | AB8500_REGUMISC1, | ||
57 | AB8500_VAUDIOSUPPLY, | ||
58 | AB8500_REGUCTRL1VAMIC, | ||
59 | AB8500_VPLLVANAREGU, | ||
60 | AB8500_VREFDDR, | ||
61 | AB8500_EXTSUPPLYREGU, | ||
62 | AB8500_VAUX12REGU, | ||
63 | AB8500_VRF1VAUX3REGU, | ||
64 | AB8500_VAUX1SEL, | ||
65 | AB8500_VAUX2SEL, | ||
66 | AB8500_VRF1VAUX3SEL, | ||
67 | AB8500_REGUCTRL2SPARE, | ||
68 | AB8500_REGUCTRLDISCH, | ||
69 | AB8500_REGUCTRLDISCH2, | ||
70 | AB8500_VSMPS1SEL1, | ||
71 | AB8500_NUM_REGULATOR_REGISTERS, | ||
72 | }; | ||
73 | |||
27 | #endif | 74 | #endif |
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index 7954f6bd7edb..9e87c1cb7270 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h | |||
@@ -153,6 +153,8 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector); | |||
153 | int regulator_is_supported_voltage(struct regulator *regulator, | 153 | int regulator_is_supported_voltage(struct regulator *regulator, |
154 | int min_uV, int max_uV); | 154 | int min_uV, int max_uV); |
155 | int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV); | 155 | int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV); |
156 | int regulator_set_voltage_time(struct regulator *regulator, | ||
157 | int old_uV, int new_uV); | ||
156 | int regulator_get_voltage(struct regulator *regulator); | 158 | int regulator_get_voltage(struct regulator *regulator); |
157 | int regulator_sync_voltage(struct regulator *regulator); | 159 | int regulator_sync_voltage(struct regulator *regulator); |
158 | int regulator_set_current_limit(struct regulator *regulator, | 160 | int regulator_set_current_limit(struct regulator *regulator, |
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index b8ed16a33c47..6c433b89c80d 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h | |||
@@ -63,7 +63,11 @@ enum regulator_status { | |||
63 | * when running with the specified parameters. | 63 | * when running with the specified parameters. |
64 | * | 64 | * |
65 | * @enable_time: Time taken for the regulator voltage output voltage to | 65 | * @enable_time: Time taken for the regulator voltage output voltage to |
66 | * stabalise after being enabled, in microseconds. | 66 | * stabilise after being enabled, in microseconds. |
67 | * @set_voltage_time_sel: Time taken for the regulator voltage output voltage | ||
68 | * to stabilise after being set to a new value, in microseconds. | ||
69 | * The function provides the from and to voltage selector, the | ||
70 | * function should return the worst case. | ||
67 | * | 71 | * |
68 | * @set_suspend_voltage: Set the voltage for the regulator when the system | 72 | * @set_suspend_voltage: Set the voltage for the regulator when the system |
69 | * is suspended. | 73 | * is suspended. |
@@ -103,8 +107,11 @@ struct regulator_ops { | |||
103 | int (*set_mode) (struct regulator_dev *, unsigned int mode); | 107 | int (*set_mode) (struct regulator_dev *, unsigned int mode); |
104 | unsigned int (*get_mode) (struct regulator_dev *); | 108 | unsigned int (*get_mode) (struct regulator_dev *); |
105 | 109 | ||
106 | /* Time taken to enable the regulator */ | 110 | /* Time taken to enable or set voltage on the regulator */ |
107 | int (*enable_time) (struct regulator_dev *); | 111 | int (*enable_time) (struct regulator_dev *); |
112 | int (*set_voltage_time_sel) (struct regulator_dev *, | ||
113 | unsigned int old_selector, | ||
114 | unsigned int new_selector); | ||
108 | 115 | ||
109 | /* report regulator status ... most other accessors report | 116 | /* report regulator status ... most other accessors report |
110 | * control inputs, this reports results of combining inputs | 117 | * control inputs, this reports results of combining inputs |
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h index 761c745b9c24..c4c4fc45f856 100644 --- a/include/linux/regulator/machine.h +++ b/include/linux/regulator/machine.h | |||
@@ -186,6 +186,7 @@ struct regulator_init_data { | |||
186 | }; | 186 | }; |
187 | 187 | ||
188 | int regulator_suspend_prepare(suspend_state_t state); | 188 | int regulator_suspend_prepare(suspend_state_t state); |
189 | int regulator_suspend_finish(void); | ||
189 | 190 | ||
190 | #ifdef CONFIG_REGULATOR | 191 | #ifdef CONFIG_REGULATOR |
191 | void regulator_has_full_constraints(void); | 192 | void regulator_has_full_constraints(void); |
diff --git a/include/linux/sched.h b/include/linux/sched.h index b8369d522bf8..83bd2e2982fc 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -517,7 +517,7 @@ struct thread_group_cputimer { | |||
517 | struct autogroup; | 517 | struct autogroup; |
518 | 518 | ||
519 | /* | 519 | /* |
520 | * NOTE! "signal_struct" does not have it's own | 520 | * NOTE! "signal_struct" does not have its own |
521 | * locking, because a shared signal_struct always | 521 | * locking, because a shared signal_struct always |
522 | * implies a shared sighand_struct, so locking | 522 | * implies a shared sighand_struct, so locking |
523 | * sighand_struct is always a proper superset of | 523 | * sighand_struct is always a proper superset of |
diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h index 5d8048beb051..332da61cf8b7 100644 --- a/include/linux/sunrpc/gss_api.h +++ b/include/linux/sunrpc/gss_api.h | |||
@@ -126,6 +126,9 @@ struct gss_api_mech *gss_mech_get_by_name(const char *); | |||
126 | /* Similar, but get by pseudoflavor. */ | 126 | /* Similar, but get by pseudoflavor. */ |
127 | struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32); | 127 | struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32); |
128 | 128 | ||
129 | /* Fill in an array with a list of supported pseudoflavors */ | ||
130 | int gss_mech_list_pseudoflavors(u32 *); | ||
131 | |||
129 | /* Just increments the mechanism's reference count and returns its input: */ | 132 | /* Just increments the mechanism's reference count and returns its input: */ |
130 | struct gss_api_mech * gss_mech_get(struct gss_api_mech *); | 133 | struct gss_api_mech * gss_mech_get(struct gss_api_mech *); |
131 | 134 | ||
diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h index 1154c29f4101..8a75da551e4e 100644 --- a/include/linux/sysdev.h +++ b/include/linux/sysdev.h | |||
@@ -33,12 +33,13 @@ struct sysdev_class { | |||
33 | const char *name; | 33 | const char *name; |
34 | struct list_head drivers; | 34 | struct list_head drivers; |
35 | struct sysdev_class_attribute **attrs; | 35 | struct sysdev_class_attribute **attrs; |
36 | 36 | struct kset kset; | |
37 | #ifndef CONFIG_ARCH_NO_SYSDEV_OPS | ||
37 | /* Default operations for these types of devices */ | 38 | /* Default operations for these types of devices */ |
38 | int (*shutdown)(struct sys_device *); | 39 | int (*shutdown)(struct sys_device *); |
39 | int (*suspend)(struct sys_device *, pm_message_t state); | 40 | int (*suspend)(struct sys_device *, pm_message_t state); |
40 | int (*resume)(struct sys_device *); | 41 | int (*resume)(struct sys_device *); |
41 | struct kset kset; | 42 | #endif |
42 | }; | 43 | }; |
43 | 44 | ||
44 | struct sysdev_class_attribute { | 45 | struct sysdev_class_attribute { |
@@ -76,9 +77,11 @@ struct sysdev_driver { | |||
76 | struct list_head entry; | 77 | struct list_head entry; |
77 | int (*add)(struct sys_device *); | 78 | int (*add)(struct sys_device *); |
78 | int (*remove)(struct sys_device *); | 79 | int (*remove)(struct sys_device *); |
80 | #ifndef CONFIG_ARCH_NO_SYSDEV_OPS | ||
79 | int (*shutdown)(struct sys_device *); | 81 | int (*shutdown)(struct sys_device *); |
80 | int (*suspend)(struct sys_device *, pm_message_t state); | 82 | int (*suspend)(struct sys_device *, pm_message_t state); |
81 | int (*resume)(struct sys_device *); | 83 | int (*resume)(struct sys_device *); |
84 | #endif | ||
82 | }; | 85 | }; |
83 | 86 | ||
84 | 87 | ||
diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 0ead399e08b5..17e7ccc322a5 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h | |||
@@ -9,7 +9,7 @@ | |||
9 | 9 | ||
10 | struct backing_dev_info; | 10 | struct backing_dev_info; |
11 | 11 | ||
12 | extern spinlock_t inode_lock; | 12 | extern spinlock_t inode_wb_list_lock; |
13 | 13 | ||
14 | /* | 14 | /* |
15 | * fs/fs-writeback.c | 15 | * fs/fs-writeback.c |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 60f7876b6da8..b2b9d28cb4ab 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -486,7 +486,8 @@ struct rate_info { | |||
486 | * @plink_state: mesh peer link state | 486 | * @plink_state: mesh peer link state |
487 | * @signal: signal strength of last received packet in dBm | 487 | * @signal: signal strength of last received packet in dBm |
488 | * @signal_avg: signal strength average in dBm | 488 | * @signal_avg: signal strength average in dBm |
489 | * @txrate: current unicast bitrate to this station | 489 | * @txrate: current unicast bitrate from this station |
490 | * @rxrate: current unicast bitrate to this station | ||
490 | * @rx_packets: packets received from this station | 491 | * @rx_packets: packets received from this station |
491 | * @tx_packets: packets transmitted to this station | 492 | * @tx_packets: packets transmitted to this station |
492 | * @tx_retries: cumulative retry counts | 493 | * @tx_retries: cumulative retry counts |
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 642a80bb42cf..c850e5fb967c 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h | |||
@@ -70,7 +70,7 @@ static inline struct inet_peer *rt6_get_peer(struct rt6_info *rt) | |||
70 | extern void ip6_route_input(struct sk_buff *skb); | 70 | extern void ip6_route_input(struct sk_buff *skb); |
71 | 71 | ||
72 | extern struct dst_entry * ip6_route_output(struct net *net, | 72 | extern struct dst_entry * ip6_route_output(struct net *net, |
73 | struct sock *sk, | 73 | const struct sock *sk, |
74 | struct flowi6 *fl6); | 74 | struct flowi6 *fl6); |
75 | 75 | ||
76 | extern int ip6_route_init(void); | 76 | extern int ip6_route_init(void); |
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index a1a858035913..e5d66ec88cf6 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h | |||
@@ -51,7 +51,6 @@ struct fib_nh { | |||
51 | struct fib_info *nh_parent; | 51 | struct fib_info *nh_parent; |
52 | unsigned nh_flags; | 52 | unsigned nh_flags; |
53 | unsigned char nh_scope; | 53 | unsigned char nh_scope; |
54 | unsigned char nh_cfg_scope; | ||
55 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 54 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
56 | int nh_weight; | 55 | int nh_weight; |
57 | int nh_power; | 56 | int nh_power; |
@@ -62,6 +61,7 @@ struct fib_nh { | |||
62 | int nh_oif; | 61 | int nh_oif; |
63 | __be32 nh_gw; | 62 | __be32 nh_gw; |
64 | __be32 nh_saddr; | 63 | __be32 nh_saddr; |
64 | int nh_saddr_genid; | ||
65 | }; | 65 | }; |
66 | 66 | ||
67 | /* | 67 | /* |
@@ -74,9 +74,10 @@ struct fib_info { | |||
74 | struct net *fib_net; | 74 | struct net *fib_net; |
75 | int fib_treeref; | 75 | int fib_treeref; |
76 | atomic_t fib_clntref; | 76 | atomic_t fib_clntref; |
77 | int fib_dead; | ||
78 | unsigned fib_flags; | 77 | unsigned fib_flags; |
79 | int fib_protocol; | 78 | unsigned char fib_dead; |
79 | unsigned char fib_protocol; | ||
80 | unsigned char fib_scope; | ||
80 | __be32 fib_prefsrc; | 81 | __be32 fib_prefsrc; |
81 | u32 fib_priority; | 82 | u32 fib_priority; |
82 | u32 *fib_metrics; | 83 | u32 *fib_metrics; |
@@ -141,12 +142,19 @@ struct fib_result_nl { | |||
141 | 142 | ||
142 | #endif /* CONFIG_IP_ROUTE_MULTIPATH */ | 143 | #endif /* CONFIG_IP_ROUTE_MULTIPATH */ |
143 | 144 | ||
144 | #define FIB_RES_SADDR(res) (FIB_RES_NH(res).nh_saddr) | 145 | extern __be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh); |
146 | |||
147 | #define FIB_RES_SADDR(net, res) \ | ||
148 | ((FIB_RES_NH(res).nh_saddr_genid == \ | ||
149 | atomic_read(&(net)->ipv4.dev_addr_genid)) ? \ | ||
150 | FIB_RES_NH(res).nh_saddr : \ | ||
151 | fib_info_update_nh_saddr((net), &FIB_RES_NH(res))) | ||
145 | #define FIB_RES_GW(res) (FIB_RES_NH(res).nh_gw) | 152 | #define FIB_RES_GW(res) (FIB_RES_NH(res).nh_gw) |
146 | #define FIB_RES_DEV(res) (FIB_RES_NH(res).nh_dev) | 153 | #define FIB_RES_DEV(res) (FIB_RES_NH(res).nh_dev) |
147 | #define FIB_RES_OIF(res) (FIB_RES_NH(res).nh_oif) | 154 | #define FIB_RES_OIF(res) (FIB_RES_NH(res).nh_oif) |
148 | 155 | ||
149 | #define FIB_RES_PREFSRC(res) ((res).fi->fib_prefsrc ? : FIB_RES_SADDR(res)) | 156 | #define FIB_RES_PREFSRC(net, res) ((res).fi->fib_prefsrc ? : \ |
157 | FIB_RES_SADDR(net, res)) | ||
150 | 158 | ||
151 | struct fib_table { | 159 | struct fib_table { |
152 | struct hlist_node tb_hlist; | 160 | struct hlist_node tb_hlist; |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 8650e7bf2ed0..cefe1b37c493 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -1160,7 +1160,7 @@ enum ieee80211_hw_flags { | |||
1160 | * @napi_weight: weight used for NAPI polling. You must specify an | 1160 | * @napi_weight: weight used for NAPI polling. You must specify an |
1161 | * appropriate value here if a napi_poll operation is provided | 1161 | * appropriate value here if a napi_poll operation is provided |
1162 | * by your driver. | 1162 | * by your driver. |
1163 | 1163 | * | |
1164 | * @max_rx_aggregation_subframes: maximum buffer size (number of | 1164 | * @max_rx_aggregation_subframes: maximum buffer size (number of |
1165 | * sub-frames) to be used for A-MPDU block ack receiver | 1165 | * sub-frames) to be used for A-MPDU block ack receiver |
1166 | * aggregation. | 1166 | * aggregation. |
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index e2e2ef57eca2..542195d9469e 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h | |||
@@ -55,6 +55,7 @@ struct netns_ipv4 { | |||
55 | int current_rt_cache_rebuild_count; | 55 | int current_rt_cache_rebuild_count; |
56 | 56 | ||
57 | atomic_t rt_genid; | 57 | atomic_t rt_genid; |
58 | atomic_t dev_addr_genid; | ||
58 | 59 | ||
59 | #ifdef CONFIG_IP_MROUTE | 60 | #ifdef CONFIG_IP_MROUTE |
60 | #ifndef CONFIG_IP_MROUTE_MULTIPLE_TABLES | 61 | #ifndef CONFIG_IP_MROUTE_MULTIPLE_TABLES |
diff --git a/include/net/route.h b/include/net/route.h index 30d6cae3841a..f88429cad52a 100644 --- a/include/net/route.h +++ b/include/net/route.h | |||
@@ -207,6 +207,7 @@ extern int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb); | |||
207 | 207 | ||
208 | struct in_ifaddr; | 208 | struct in_ifaddr; |
209 | extern void fib_add_ifaddr(struct in_ifaddr *); | 209 | extern void fib_add_ifaddr(struct in_ifaddr *); |
210 | extern void fib_del_ifaddr(struct in_ifaddr *, struct in_ifaddr *); | ||
210 | 211 | ||
211 | static inline void ip_rt_put(struct rtable * rt) | 212 | static inline void ip_rt_put(struct rtable * rt) |
212 | { | 213 | { |
@@ -269,8 +270,8 @@ static inline struct rtable *ip_route_newports(struct rtable *rt, | |||
269 | struct flowi4 fl4 = { | 270 | struct flowi4 fl4 = { |
270 | .flowi4_oif = rt->rt_oif, | 271 | .flowi4_oif = rt->rt_oif, |
271 | .flowi4_mark = rt->rt_mark, | 272 | .flowi4_mark = rt->rt_mark, |
272 | .daddr = rt->rt_key_dst, | 273 | .daddr = rt->rt_dst, |
273 | .saddr = rt->rt_key_src, | 274 | .saddr = rt->rt_src, |
274 | .flowi4_tos = rt->rt_tos, | 275 | .flowi4_tos = rt->rt_tos, |
275 | .flowi4_proto = protocol, | 276 | .flowi4_proto = protocol, |
276 | .fl4_sport = sport, | 277 | .fl4_sport = sport, |
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index a9505b6a18e3..b931f021d7ab 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h | |||
@@ -25,6 +25,7 @@ struct qdisc_rate_table { | |||
25 | enum qdisc_state_t { | 25 | enum qdisc_state_t { |
26 | __QDISC_STATE_SCHED, | 26 | __QDISC_STATE_SCHED, |
27 | __QDISC_STATE_DEACTIVATED, | 27 | __QDISC_STATE_DEACTIVATED, |
28 | __QDISC_STATE_THROTTLED, | ||
28 | }; | 29 | }; |
29 | 30 | ||
30 | /* | 31 | /* |
@@ -32,7 +33,6 @@ enum qdisc_state_t { | |||
32 | */ | 33 | */ |
33 | enum qdisc___state_t { | 34 | enum qdisc___state_t { |
34 | __QDISC___STATE_RUNNING = 1, | 35 | __QDISC___STATE_RUNNING = 1, |
35 | __QDISC___STATE_THROTTLED = 2, | ||
36 | }; | 36 | }; |
37 | 37 | ||
38 | struct qdisc_size_table { | 38 | struct qdisc_size_table { |
@@ -106,17 +106,17 @@ static inline void qdisc_run_end(struct Qdisc *qdisc) | |||
106 | 106 | ||
107 | static inline bool qdisc_is_throttled(const struct Qdisc *qdisc) | 107 | static inline bool qdisc_is_throttled(const struct Qdisc *qdisc) |
108 | { | 108 | { |
109 | return (qdisc->__state & __QDISC___STATE_THROTTLED) ? true : false; | 109 | return test_bit(__QDISC_STATE_THROTTLED, &qdisc->state) ? true : false; |
110 | } | 110 | } |
111 | 111 | ||
112 | static inline void qdisc_throttled(struct Qdisc *qdisc) | 112 | static inline void qdisc_throttled(struct Qdisc *qdisc) |
113 | { | 113 | { |
114 | qdisc->__state |= __QDISC___STATE_THROTTLED; | 114 | set_bit(__QDISC_STATE_THROTTLED, &qdisc->state); |
115 | } | 115 | } |
116 | 116 | ||
117 | static inline void qdisc_unthrottled(struct Qdisc *qdisc) | 117 | static inline void qdisc_unthrottled(struct Qdisc *qdisc) |
118 | { | 118 | { |
119 | qdisc->__state &= ~__QDISC___STATE_THROTTLED; | 119 | clear_bit(__QDISC_STATE_THROTTLED, &qdisc->state); |
120 | } | 120 | } |
121 | 121 | ||
122 | struct Qdisc_class_ops { | 122 | struct Qdisc_class_ops { |
diff --git a/include/scsi/libiscsi_tcp.h b/include/scsi/libiscsi_tcp.h index 741ae7ed4394..e6b9fd2eea34 100644 --- a/include/scsi/libiscsi_tcp.h +++ b/include/scsi/libiscsi_tcp.h | |||
@@ -47,6 +47,7 @@ struct iscsi_segment { | |||
47 | struct scatterlist *sg; | 47 | struct scatterlist *sg; |
48 | void *sg_mapped; | 48 | void *sg_mapped; |
49 | unsigned int sg_offset; | 49 | unsigned int sg_offset; |
50 | bool atomic_mapped; | ||
50 | 51 | ||
51 | iscsi_segment_done_fn_t *done; | 52 | iscsi_segment_done_fn_t *done; |
52 | }; | 53 | }; |
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index f171c65dc5a8..2d3ec5094685 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h | |||
@@ -462,7 +462,7 @@ static inline int scsi_device_qas(struct scsi_device *sdev) | |||
462 | } | 462 | } |
463 | static inline int scsi_device_enclosure(struct scsi_device *sdev) | 463 | static inline int scsi_device_enclosure(struct scsi_device *sdev) |
464 | { | 464 | { |
465 | return sdev->inquiry[6] & (1<<6); | 465 | return sdev->inquiry ? (sdev->inquiry[6] & (1<<6)) : 1; |
466 | } | 466 | } |
467 | 467 | ||
468 | static inline int scsi_device_protection(struct scsi_device *sdev) | 468 | static inline int scsi_device_protection(struct scsi_device *sdev) |
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 430a9cc045e2..e1bad1130616 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h | |||
@@ -1031,9 +1031,7 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_s | |||
1031 | #define snd_pcm_lib_mmap_iomem NULL | 1031 | #define snd_pcm_lib_mmap_iomem NULL |
1032 | #endif | 1032 | #endif |
1033 | 1033 | ||
1034 | int snd_pcm_lib_mmap_noncached(struct snd_pcm_substream *substream, | 1034 | #define snd_pcm_lib_mmap_vmalloc NULL |
1035 | struct vm_area_struct *area); | ||
1036 | #define snd_pcm_lib_mmap_vmalloc snd_pcm_lib_mmap_noncached | ||
1037 | 1035 | ||
1038 | static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max) | 1036 | static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max) |
1039 | { | 1037 | { |
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 0828b6c8610a..c15ed5026fb5 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h | |||
@@ -9,7 +9,7 @@ | |||
9 | #include <net/sock.h> | 9 | #include <net/sock.h> |
10 | #include <net/tcp.h> | 10 | #include <net/tcp.h> |
11 | 11 | ||
12 | #define TARGET_CORE_MOD_VERSION "v4.0.0-rc6" | 12 | #define TARGET_CORE_MOD_VERSION "v4.0.0-rc7-ml" |
13 | #define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGABRT)) | 13 | #define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGABRT)) |
14 | 14 | ||
15 | /* Used by transport_generic_allocate_iovecs() */ | 15 | /* Used by transport_generic_allocate_iovecs() */ |
@@ -239,7 +239,7 @@ struct t10_alua_lu_gp { | |||
239 | } ____cacheline_aligned; | 239 | } ____cacheline_aligned; |
240 | 240 | ||
241 | struct t10_alua_lu_gp_member { | 241 | struct t10_alua_lu_gp_member { |
242 | int lu_gp_assoc:1; | 242 | bool lu_gp_assoc; |
243 | atomic_t lu_gp_mem_ref_cnt; | 243 | atomic_t lu_gp_mem_ref_cnt; |
244 | spinlock_t lu_gp_mem_lock; | 244 | spinlock_t lu_gp_mem_lock; |
245 | struct t10_alua_lu_gp *lu_gp; | 245 | struct t10_alua_lu_gp *lu_gp; |
@@ -271,7 +271,7 @@ struct t10_alua_tg_pt_gp { | |||
271 | } ____cacheline_aligned; | 271 | } ____cacheline_aligned; |
272 | 272 | ||
273 | struct t10_alua_tg_pt_gp_member { | 273 | struct t10_alua_tg_pt_gp_member { |
274 | int tg_pt_gp_assoc:1; | 274 | bool tg_pt_gp_assoc; |
275 | atomic_t tg_pt_gp_mem_ref_cnt; | 275 | atomic_t tg_pt_gp_mem_ref_cnt; |
276 | spinlock_t tg_pt_gp_mem_lock; | 276 | spinlock_t tg_pt_gp_mem_lock; |
277 | struct t10_alua_tg_pt_gp *tg_pt_gp; | 277 | struct t10_alua_tg_pt_gp *tg_pt_gp; |
@@ -336,7 +336,7 @@ struct t10_pr_registration { | |||
336 | int pr_res_type; | 336 | int pr_res_type; |
337 | int pr_res_scope; | 337 | int pr_res_scope; |
338 | /* Used for fabric initiator WWPNs using a ISID */ | 338 | /* Used for fabric initiator WWPNs using a ISID */ |
339 | int isid_present_at_reg:1; | 339 | bool isid_present_at_reg; |
340 | u32 pr_res_mapped_lun; | 340 | u32 pr_res_mapped_lun; |
341 | u32 pr_aptpl_target_lun; | 341 | u32 pr_aptpl_target_lun; |
342 | u32 pr_res_generation; | 342 | u32 pr_res_generation; |
@@ -418,7 +418,7 @@ struct se_transport_task { | |||
418 | unsigned long long t_task_lba; | 418 | unsigned long long t_task_lba; |
419 | int t_tasks_failed; | 419 | int t_tasks_failed; |
420 | int t_tasks_fua; | 420 | int t_tasks_fua; |
421 | int t_tasks_bidi:1; | 421 | bool t_tasks_bidi; |
422 | u32 t_task_cdbs; | 422 | u32 t_task_cdbs; |
423 | u32 t_tasks_check; | 423 | u32 t_tasks_check; |
424 | u32 t_tasks_no; | 424 | u32 t_tasks_no; |
@@ -470,7 +470,7 @@ struct se_task { | |||
470 | u8 task_flags; | 470 | u8 task_flags; |
471 | int task_error_status; | 471 | int task_error_status; |
472 | int task_state_flags; | 472 | int task_state_flags; |
473 | int task_padded_sg:1; | 473 | bool task_padded_sg; |
474 | unsigned long long task_lba; | 474 | unsigned long long task_lba; |
475 | u32 task_no; | 475 | u32 task_no; |
476 | u32 task_sectors; | 476 | u32 task_sectors; |
@@ -494,8 +494,8 @@ struct se_task { | |||
494 | struct list_head t_state_list; | 494 | struct list_head t_state_list; |
495 | } ____cacheline_aligned; | 495 | } ____cacheline_aligned; |
496 | 496 | ||
497 | #define TASK_CMD(task) ((struct se_cmd *)task->task_se_cmd) | 497 | #define TASK_CMD(task) ((task)->task_se_cmd) |
498 | #define TASK_DEV(task) ((struct se_device *)task->se_dev) | 498 | #define TASK_DEV(task) ((task)->se_dev) |
499 | 499 | ||
500 | struct se_cmd { | 500 | struct se_cmd { |
501 | /* SAM response code being sent to initiator */ | 501 | /* SAM response code being sent to initiator */ |
@@ -551,8 +551,8 @@ struct se_cmd { | |||
551 | void (*transport_complete_callback)(struct se_cmd *); | 551 | void (*transport_complete_callback)(struct se_cmd *); |
552 | } ____cacheline_aligned; | 552 | } ____cacheline_aligned; |
553 | 553 | ||
554 | #define T_TASK(cmd) ((struct se_transport_task *)(cmd->t_task)) | 554 | #define T_TASK(cmd) ((cmd)->t_task) |
555 | #define CMD_TFO(cmd) ((struct target_core_fabric_ops *)cmd->se_tfo) | 555 | #define CMD_TFO(cmd) ((cmd)->se_tfo) |
556 | 556 | ||
557 | struct se_tmr_req { | 557 | struct se_tmr_req { |
558 | /* Task Management function to be preformed */ | 558 | /* Task Management function to be preformed */ |
@@ -583,7 +583,7 @@ struct se_ua { | |||
583 | struct se_node_acl { | 583 | struct se_node_acl { |
584 | char initiatorname[TRANSPORT_IQN_LEN]; | 584 | char initiatorname[TRANSPORT_IQN_LEN]; |
585 | /* Used to signal demo mode created ACL, disabled by default */ | 585 | /* Used to signal demo mode created ACL, disabled by default */ |
586 | int dynamic_node_acl:1; | 586 | bool dynamic_node_acl; |
587 | u32 queue_depth; | 587 | u32 queue_depth; |
588 | u32 acl_index; | 588 | u32 acl_index; |
589 | u64 num_cmds; | 589 | u64 num_cmds; |
@@ -601,7 +601,8 @@ struct se_node_acl { | |||
601 | struct config_group acl_attrib_group; | 601 | struct config_group acl_attrib_group; |
602 | struct config_group acl_auth_group; | 602 | struct config_group acl_auth_group; |
603 | struct config_group acl_param_group; | 603 | struct config_group acl_param_group; |
604 | struct config_group *acl_default_groups[4]; | 604 | struct config_group acl_fabric_stat_group; |
605 | struct config_group *acl_default_groups[5]; | ||
605 | struct list_head acl_list; | 606 | struct list_head acl_list; |
606 | struct list_head acl_sess_list; | 607 | struct list_head acl_sess_list; |
607 | } ____cacheline_aligned; | 608 | } ____cacheline_aligned; |
@@ -615,13 +616,19 @@ struct se_session { | |||
615 | struct list_head sess_acl_list; | 616 | struct list_head sess_acl_list; |
616 | } ____cacheline_aligned; | 617 | } ____cacheline_aligned; |
617 | 618 | ||
618 | #define SE_SESS(cmd) ((struct se_session *)(cmd)->se_sess) | 619 | #define SE_SESS(cmd) ((cmd)->se_sess) |
619 | #define SE_NODE_ACL(sess) ((struct se_node_acl *)(sess)->se_node_acl) | 620 | #define SE_NODE_ACL(sess) ((sess)->se_node_acl) |
620 | 621 | ||
621 | struct se_device; | 622 | struct se_device; |
622 | struct se_transform_info; | 623 | struct se_transform_info; |
623 | struct scatterlist; | 624 | struct scatterlist; |
624 | 625 | ||
626 | struct se_ml_stat_grps { | ||
627 | struct config_group stat_group; | ||
628 | struct config_group scsi_auth_intr_group; | ||
629 | struct config_group scsi_att_intr_port_group; | ||
630 | }; | ||
631 | |||
625 | struct se_lun_acl { | 632 | struct se_lun_acl { |
626 | char initiatorname[TRANSPORT_IQN_LEN]; | 633 | char initiatorname[TRANSPORT_IQN_LEN]; |
627 | u32 mapped_lun; | 634 | u32 mapped_lun; |
@@ -629,10 +636,13 @@ struct se_lun_acl { | |||
629 | struct se_lun *se_lun; | 636 | struct se_lun *se_lun; |
630 | struct list_head lacl_list; | 637 | struct list_head lacl_list; |
631 | struct config_group se_lun_group; | 638 | struct config_group se_lun_group; |
639 | struct se_ml_stat_grps ml_stat_grps; | ||
632 | } ____cacheline_aligned; | 640 | } ____cacheline_aligned; |
633 | 641 | ||
642 | #define ML_STAT_GRPS(lacl) (&(lacl)->ml_stat_grps) | ||
643 | |||
634 | struct se_dev_entry { | 644 | struct se_dev_entry { |
635 | int def_pr_registered:1; | 645 | bool def_pr_registered; |
636 | /* See transport_lunflags_table */ | 646 | /* See transport_lunflags_table */ |
637 | u32 lun_flags; | 647 | u32 lun_flags; |
638 | u32 deve_cmds; | 648 | u32 deve_cmds; |
@@ -693,6 +703,13 @@ struct se_dev_attrib { | |||
693 | struct config_group da_group; | 703 | struct config_group da_group; |
694 | } ____cacheline_aligned; | 704 | } ____cacheline_aligned; |
695 | 705 | ||
706 | struct se_dev_stat_grps { | ||
707 | struct config_group stat_group; | ||
708 | struct config_group scsi_dev_group; | ||
709 | struct config_group scsi_tgt_dev_group; | ||
710 | struct config_group scsi_lu_group; | ||
711 | }; | ||
712 | |||
696 | struct se_subsystem_dev { | 713 | struct se_subsystem_dev { |
697 | /* Used for struct se_subsystem_dev-->se_dev_alias, must be less than PAGE_SIZE */ | 714 | /* Used for struct se_subsystem_dev-->se_dev_alias, must be less than PAGE_SIZE */ |
698 | #define SE_DEV_ALIAS_LEN 512 | 715 | #define SE_DEV_ALIAS_LEN 512 |
@@ -716,11 +733,14 @@ struct se_subsystem_dev { | |||
716 | struct config_group se_dev_group; | 733 | struct config_group se_dev_group; |
717 | /* For T10 Reservations */ | 734 | /* For T10 Reservations */ |
718 | struct config_group se_dev_pr_group; | 735 | struct config_group se_dev_pr_group; |
736 | /* For target_core_stat.c groups */ | ||
737 | struct se_dev_stat_grps dev_stat_grps; | ||
719 | } ____cacheline_aligned; | 738 | } ____cacheline_aligned; |
720 | 739 | ||
721 | #define T10_ALUA(su_dev) (&(su_dev)->t10_alua) | 740 | #define T10_ALUA(su_dev) (&(su_dev)->t10_alua) |
722 | #define T10_RES(su_dev) (&(su_dev)->t10_reservation) | 741 | #define T10_RES(su_dev) (&(su_dev)->t10_reservation) |
723 | #define T10_PR_OPS(su_dev) (&(su_dev)->t10_reservation.pr_ops) | 742 | #define T10_PR_OPS(su_dev) (&(su_dev)->t10_reservation.pr_ops) |
743 | #define DEV_STAT_GRP(dev) (&(dev)->dev_stat_grps) | ||
724 | 744 | ||
725 | struct se_device { | 745 | struct se_device { |
726 | /* Set to 1 if thread is NOT sleeping on thread_sem */ | 746 | /* Set to 1 if thread is NOT sleeping on thread_sem */ |
@@ -803,8 +823,8 @@ struct se_device { | |||
803 | struct list_head g_se_dev_list; | 823 | struct list_head g_se_dev_list; |
804 | } ____cacheline_aligned; | 824 | } ____cacheline_aligned; |
805 | 825 | ||
806 | #define SE_DEV(cmd) ((struct se_device *)(cmd)->se_lun->lun_se_dev) | 826 | #define SE_DEV(cmd) ((cmd)->se_lun->lun_se_dev) |
807 | #define SU_DEV(dev) ((struct se_subsystem_dev *)(dev)->se_sub_dev) | 827 | #define SU_DEV(dev) ((dev)->se_sub_dev) |
808 | #define DEV_ATTRIB(dev) (&(dev)->se_sub_dev->se_dev_attrib) | 828 | #define DEV_ATTRIB(dev) (&(dev)->se_sub_dev->se_dev_attrib) |
809 | #define DEV_T10_WWN(dev) (&(dev)->se_sub_dev->t10_wwn) | 829 | #define DEV_T10_WWN(dev) (&(dev)->se_sub_dev->t10_wwn) |
810 | 830 | ||
@@ -832,7 +852,14 @@ struct se_hba { | |||
832 | struct se_subsystem_api *transport; | 852 | struct se_subsystem_api *transport; |
833 | } ____cacheline_aligned; | 853 | } ____cacheline_aligned; |
834 | 854 | ||
835 | #define SE_HBA(d) ((struct se_hba *)(d)->se_hba) | 855 | #define SE_HBA(dev) ((dev)->se_hba) |
856 | |||
857 | struct se_port_stat_grps { | ||
858 | struct config_group stat_group; | ||
859 | struct config_group scsi_port_group; | ||
860 | struct config_group scsi_tgt_port_group; | ||
861 | struct config_group scsi_transport_group; | ||
862 | }; | ||
836 | 863 | ||
837 | struct se_lun { | 864 | struct se_lun { |
838 | /* See transport_lun_status_table */ | 865 | /* See transport_lun_status_table */ |
@@ -848,11 +875,13 @@ struct se_lun { | |||
848 | struct list_head lun_cmd_list; | 875 | struct list_head lun_cmd_list; |
849 | struct list_head lun_acl_list; | 876 | struct list_head lun_acl_list; |
850 | struct se_device *lun_se_dev; | 877 | struct se_device *lun_se_dev; |
878 | struct se_port *lun_sep; | ||
851 | struct config_group lun_group; | 879 | struct config_group lun_group; |
852 | struct se_port *lun_sep; | 880 | struct se_port_stat_grps port_stat_grps; |
853 | } ____cacheline_aligned; | 881 | } ____cacheline_aligned; |
854 | 882 | ||
855 | #define SE_LUN(c) ((struct se_lun *)(c)->se_lun) | 883 | #define SE_LUN(cmd) ((cmd)->se_lun) |
884 | #define PORT_STAT_GRP(lun) (&(lun)->port_stat_grps) | ||
856 | 885 | ||
857 | struct scsi_port_stats { | 886 | struct scsi_port_stats { |
858 | u64 cmd_pdus; | 887 | u64 cmd_pdus; |
@@ -919,11 +948,13 @@ struct se_portal_group { | |||
919 | struct config_group tpg_param_group; | 948 | struct config_group tpg_param_group; |
920 | } ____cacheline_aligned; | 949 | } ____cacheline_aligned; |
921 | 950 | ||
922 | #define TPG_TFO(se_tpg) ((struct target_core_fabric_ops *)(se_tpg)->se_tpg_tfo) | 951 | #define TPG_TFO(se_tpg) ((se_tpg)->se_tpg_tfo) |
923 | 952 | ||
924 | struct se_wwn { | 953 | struct se_wwn { |
925 | struct target_fabric_configfs *wwn_tf; | 954 | struct target_fabric_configfs *wwn_tf; |
926 | struct config_group wwn_group; | 955 | struct config_group wwn_group; |
956 | struct config_group *wwn_default_groups[2]; | ||
957 | struct config_group fabric_stat_group; | ||
927 | } ____cacheline_aligned; | 958 | } ____cacheline_aligned; |
928 | 959 | ||
929 | struct se_global { | 960 | struct se_global { |
diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h index 40e6e740527c..612509592ffd 100644 --- a/include/target/target_core_configfs.h +++ b/include/target/target_core_configfs.h | |||
@@ -14,10 +14,12 @@ extern void target_fabric_configfs_deregister(struct target_fabric_configfs *); | |||
14 | struct target_fabric_configfs_template { | 14 | struct target_fabric_configfs_template { |
15 | struct config_item_type tfc_discovery_cit; | 15 | struct config_item_type tfc_discovery_cit; |
16 | struct config_item_type tfc_wwn_cit; | 16 | struct config_item_type tfc_wwn_cit; |
17 | struct config_item_type tfc_wwn_fabric_stats_cit; | ||
17 | struct config_item_type tfc_tpg_cit; | 18 | struct config_item_type tfc_tpg_cit; |
18 | struct config_item_type tfc_tpg_base_cit; | 19 | struct config_item_type tfc_tpg_base_cit; |
19 | struct config_item_type tfc_tpg_lun_cit; | 20 | struct config_item_type tfc_tpg_lun_cit; |
20 | struct config_item_type tfc_tpg_port_cit; | 21 | struct config_item_type tfc_tpg_port_cit; |
22 | struct config_item_type tfc_tpg_port_stat_cit; | ||
21 | struct config_item_type tfc_tpg_np_cit; | 23 | struct config_item_type tfc_tpg_np_cit; |
22 | struct config_item_type tfc_tpg_np_base_cit; | 24 | struct config_item_type tfc_tpg_np_base_cit; |
23 | struct config_item_type tfc_tpg_attrib_cit; | 25 | struct config_item_type tfc_tpg_attrib_cit; |
@@ -27,7 +29,9 @@ struct target_fabric_configfs_template { | |||
27 | struct config_item_type tfc_tpg_nacl_attrib_cit; | 29 | struct config_item_type tfc_tpg_nacl_attrib_cit; |
28 | struct config_item_type tfc_tpg_nacl_auth_cit; | 30 | struct config_item_type tfc_tpg_nacl_auth_cit; |
29 | struct config_item_type tfc_tpg_nacl_param_cit; | 31 | struct config_item_type tfc_tpg_nacl_param_cit; |
32 | struct config_item_type tfc_tpg_nacl_stat_cit; | ||
30 | struct config_item_type tfc_tpg_mappedlun_cit; | 33 | struct config_item_type tfc_tpg_mappedlun_cit; |
34 | struct config_item_type tfc_tpg_mappedlun_stat_cit; | ||
31 | }; | 35 | }; |
32 | 36 | ||
33 | struct target_fabric_configfs { | 37 | struct target_fabric_configfs { |
diff --git a/include/target/target_core_fabric_ops.h b/include/target/target_core_fabric_ops.h index f3ac12b019c2..5eb8b1ae59d1 100644 --- a/include/target/target_core_fabric_ops.h +++ b/include/target/target_core_fabric_ops.h | |||
@@ -8,7 +8,7 @@ struct target_core_fabric_ops { | |||
8 | * for scatterlist chaining using transport_do_task_sg_link(), | 8 | * for scatterlist chaining using transport_do_task_sg_link(), |
9 | * disabled by default | 9 | * disabled by default |
10 | */ | 10 | */ |
11 | int task_sg_chaining:1; | 11 | bool task_sg_chaining; |
12 | char *(*get_fabric_name)(void); | 12 | char *(*get_fabric_name)(void); |
13 | u8 (*get_fabric_proto_ident)(struct se_portal_group *); | 13 | u8 (*get_fabric_proto_ident)(struct se_portal_group *); |
14 | char *(*tpg_get_wwn)(struct se_portal_group *); | 14 | char *(*tpg_get_wwn)(struct se_portal_group *); |
diff --git a/include/target/target_core_tmr.h b/include/target/target_core_tmr.h index 6c8248bc2c66..bd5596807478 100644 --- a/include/target/target_core_tmr.h +++ b/include/target/target_core_tmr.h | |||
@@ -1,37 +1,29 @@ | |||
1 | #ifndef TARGET_CORE_TMR_H | 1 | #ifndef TARGET_CORE_TMR_H |
2 | #define TARGET_CORE_TMR_H | 2 | #define TARGET_CORE_TMR_H |
3 | 3 | ||
4 | /* task management function values */ | 4 | /* fabric independent task management function values */ |
5 | #ifdef ABORT_TASK | 5 | enum tcm_tmreq_table { |
6 | #undef ABORT_TASK | 6 | TMR_ABORT_TASK = 1, |
7 | #endif /* ABORT_TASK */ | 7 | TMR_ABORT_TASK_SET = 2, |
8 | #define ABORT_TASK 1 | 8 | TMR_CLEAR_ACA = 3, |
9 | #ifdef ABORT_TASK_SET | 9 | TMR_CLEAR_TASK_SET = 4, |
10 | #undef ABORT_TASK_SET | 10 | TMR_LUN_RESET = 5, |
11 | #endif /* ABORT_TASK_SET */ | 11 | TMR_TARGET_WARM_RESET = 6, |
12 | #define ABORT_TASK_SET 2 | 12 | TMR_TARGET_COLD_RESET = 7, |
13 | #ifdef CLEAR_ACA | 13 | TMR_FABRIC_TMR = 255, |
14 | #undef CLEAR_ACA | 14 | }; |
15 | #endif /* CLEAR_ACA */ | ||
16 | #define CLEAR_ACA 3 | ||
17 | #ifdef CLEAR_TASK_SET | ||
18 | #undef CLEAR_TASK_SET | ||
19 | #endif /* CLEAR_TASK_SET */ | ||
20 | #define CLEAR_TASK_SET 4 | ||
21 | #define LUN_RESET 5 | ||
22 | #define TARGET_WARM_RESET 6 | ||
23 | #define TARGET_COLD_RESET 7 | ||
24 | #define TASK_REASSIGN 8 | ||
25 | 15 | ||
26 | /* task management response values */ | 16 | /* fabric independent task management response values */ |
27 | #define TMR_FUNCTION_COMPLETE 0 | 17 | enum tcm_tmrsp_table { |
28 | #define TMR_TASK_DOES_NOT_EXIST 1 | 18 | TMR_FUNCTION_COMPLETE = 0, |
29 | #define TMR_LUN_DOES_NOT_EXIST 2 | 19 | TMR_TASK_DOES_NOT_EXIST = 1, |
30 | #define TMR_TASK_STILL_ALLEGIANT 3 | 20 | TMR_LUN_DOES_NOT_EXIST = 2, |
31 | #define TMR_TASK_FAILOVER_NOT_SUPPORTED 4 | 21 | TMR_TASK_STILL_ALLEGIANT = 3, |
32 | #define TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED 5 | 22 | TMR_TASK_FAILOVER_NOT_SUPPORTED = 4, |
33 | #define TMR_FUNCTION_AUTHORIZATION_FAILED 6 | 23 | TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED = 5, |
34 | #define TMR_FUNCTION_REJECTED 255 | 24 | TMR_FUNCTION_AUTHORIZATION_FAILED = 6, |
25 | TMR_FUNCTION_REJECTED = 255, | ||
26 | }; | ||
35 | 27 | ||
36 | extern struct kmem_cache *se_tmr_req_cache; | 28 | extern struct kmem_cache *se_tmr_req_cache; |
37 | 29 | ||
diff --git a/include/target/target_core_transport.h b/include/target/target_core_transport.h index 2e8ec51f0615..59aa464f6ee2 100644 --- a/include/target/target_core_transport.h +++ b/include/target/target_core_transport.h | |||
@@ -109,6 +109,8 @@ | |||
109 | struct se_mem; | 109 | struct se_mem; |
110 | struct se_subsystem_api; | 110 | struct se_subsystem_api; |
111 | 111 | ||
112 | extern struct kmem_cache *se_mem_cache; | ||
113 | |||
112 | extern int init_se_global(void); | 114 | extern int init_se_global(void); |
113 | extern void release_se_global(void); | 115 | extern void release_se_global(void); |
114 | extern void init_scsi_index_table(void); | 116 | extern void init_scsi_index_table(void); |
@@ -190,6 +192,8 @@ extern void transport_generic_process_write(struct se_cmd *); | |||
190 | extern int transport_generic_do_tmr(struct se_cmd *); | 192 | extern int transport_generic_do_tmr(struct se_cmd *); |
191 | /* From target_core_alua.c */ | 193 | /* From target_core_alua.c */ |
192 | extern int core_alua_check_nonop_delay(struct se_cmd *); | 194 | extern int core_alua_check_nonop_delay(struct se_cmd *); |
195 | /* From target_core_cdb.c */ | ||
196 | extern int transport_emulate_control_cdb(struct se_task *); | ||
193 | 197 | ||
194 | /* | 198 | /* |
195 | * Each se_transport_task_t can have N number of possible struct se_task's | 199 | * Each se_transport_task_t can have N number of possible struct se_task's |
diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h index e5e345fb2a5c..e09592d2f916 100644 --- a/include/trace/events/ext4.h +++ b/include/trace/events/ext4.h | |||
@@ -21,8 +21,7 @@ TRACE_EVENT(ext4_free_inode, | |||
21 | TP_ARGS(inode), | 21 | TP_ARGS(inode), |
22 | 22 | ||
23 | TP_STRUCT__entry( | 23 | TP_STRUCT__entry( |
24 | __field( int, dev_major ) | 24 | __field( dev_t, dev ) |
25 | __field( int, dev_minor ) | ||
26 | __field( ino_t, ino ) | 25 | __field( ino_t, ino ) |
27 | __field( umode_t, mode ) | 26 | __field( umode_t, mode ) |
28 | __field( uid_t, uid ) | 27 | __field( uid_t, uid ) |
@@ -31,8 +30,7 @@ TRACE_EVENT(ext4_free_inode, | |||
31 | ), | 30 | ), |
32 | 31 | ||
33 | TP_fast_assign( | 32 | TP_fast_assign( |
34 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 33 | __entry->dev = inode->i_sb->s_dev; |
35 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
36 | __entry->ino = inode->i_ino; | 34 | __entry->ino = inode->i_ino; |
37 | __entry->mode = inode->i_mode; | 35 | __entry->mode = inode->i_mode; |
38 | __entry->uid = inode->i_uid; | 36 | __entry->uid = inode->i_uid; |
@@ -41,9 +39,9 @@ TRACE_EVENT(ext4_free_inode, | |||
41 | ), | 39 | ), |
42 | 40 | ||
43 | TP_printk("dev %d,%d ino %lu mode 0%o uid %u gid %u blocks %llu", | 41 | TP_printk("dev %d,%d ino %lu mode 0%o uid %u gid %u blocks %llu", |
44 | __entry->dev_major, __entry->dev_minor, | 42 | MAJOR(__entry->dev), MINOR(__entry->dev), |
45 | (unsigned long) __entry->ino, __entry->mode, | 43 | (unsigned long) __entry->ino, |
46 | __entry->uid, __entry->gid, | 44 | __entry->mode, __entry->uid, __entry->gid, |
47 | (unsigned long long) __entry->blocks) | 45 | (unsigned long long) __entry->blocks) |
48 | ); | 46 | ); |
49 | 47 | ||
@@ -53,21 +51,19 @@ TRACE_EVENT(ext4_request_inode, | |||
53 | TP_ARGS(dir, mode), | 51 | TP_ARGS(dir, mode), |
54 | 52 | ||
55 | TP_STRUCT__entry( | 53 | TP_STRUCT__entry( |
56 | __field( int, dev_major ) | 54 | __field( dev_t, dev ) |
57 | __field( int, dev_minor ) | ||
58 | __field( ino_t, dir ) | 55 | __field( ino_t, dir ) |
59 | __field( umode_t, mode ) | 56 | __field( umode_t, mode ) |
60 | ), | 57 | ), |
61 | 58 | ||
62 | TP_fast_assign( | 59 | TP_fast_assign( |
63 | __entry->dev_major = MAJOR(dir->i_sb->s_dev); | 60 | __entry->dev = dir->i_sb->s_dev; |
64 | __entry->dev_minor = MINOR(dir->i_sb->s_dev); | ||
65 | __entry->dir = dir->i_ino; | 61 | __entry->dir = dir->i_ino; |
66 | __entry->mode = mode; | 62 | __entry->mode = mode; |
67 | ), | 63 | ), |
68 | 64 | ||
69 | TP_printk("dev %d,%d dir %lu mode 0%o", | 65 | TP_printk("dev %d,%d dir %lu mode 0%o", |
70 | __entry->dev_major, __entry->dev_minor, | 66 | MAJOR(__entry->dev), MINOR(__entry->dev), |
71 | (unsigned long) __entry->dir, __entry->mode) | 67 | (unsigned long) __entry->dir, __entry->mode) |
72 | ); | 68 | ); |
73 | 69 | ||
@@ -77,23 +73,21 @@ TRACE_EVENT(ext4_allocate_inode, | |||
77 | TP_ARGS(inode, dir, mode), | 73 | TP_ARGS(inode, dir, mode), |
78 | 74 | ||
79 | TP_STRUCT__entry( | 75 | TP_STRUCT__entry( |
80 | __field( int, dev_major ) | 76 | __field( dev_t, dev ) |
81 | __field( int, dev_minor ) | ||
82 | __field( ino_t, ino ) | 77 | __field( ino_t, ino ) |
83 | __field( ino_t, dir ) | 78 | __field( ino_t, dir ) |
84 | __field( umode_t, mode ) | 79 | __field( umode_t, mode ) |
85 | ), | 80 | ), |
86 | 81 | ||
87 | TP_fast_assign( | 82 | TP_fast_assign( |
88 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 83 | __entry->dev = inode->i_sb->s_dev; |
89 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
90 | __entry->ino = inode->i_ino; | 84 | __entry->ino = inode->i_ino; |
91 | __entry->dir = dir->i_ino; | 85 | __entry->dir = dir->i_ino; |
92 | __entry->mode = mode; | 86 | __entry->mode = mode; |
93 | ), | 87 | ), |
94 | 88 | ||
95 | TP_printk("dev %d,%d ino %lu dir %lu mode 0%o", | 89 | TP_printk("dev %d,%d ino %lu dir %lu mode 0%o", |
96 | __entry->dev_major, __entry->dev_minor, | 90 | MAJOR(__entry->dev), MINOR(__entry->dev), |
97 | (unsigned long) __entry->ino, | 91 | (unsigned long) __entry->ino, |
98 | (unsigned long) __entry->dir, __entry->mode) | 92 | (unsigned long) __entry->dir, __entry->mode) |
99 | ); | 93 | ); |
@@ -104,21 +98,19 @@ TRACE_EVENT(ext4_evict_inode, | |||
104 | TP_ARGS(inode), | 98 | TP_ARGS(inode), |
105 | 99 | ||
106 | TP_STRUCT__entry( | 100 | TP_STRUCT__entry( |
107 | __field( int, dev_major ) | 101 | __field( dev_t, dev ) |
108 | __field( int, dev_minor ) | ||
109 | __field( ino_t, ino ) | 102 | __field( ino_t, ino ) |
110 | __field( int, nlink ) | 103 | __field( int, nlink ) |
111 | ), | 104 | ), |
112 | 105 | ||
113 | TP_fast_assign( | 106 | TP_fast_assign( |
114 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 107 | __entry->dev = inode->i_sb->s_dev; |
115 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
116 | __entry->ino = inode->i_ino; | 108 | __entry->ino = inode->i_ino; |
117 | __entry->nlink = inode->i_nlink; | 109 | __entry->nlink = inode->i_nlink; |
118 | ), | 110 | ), |
119 | 111 | ||
120 | TP_printk("dev %d,%d ino %lu nlink %d", | 112 | TP_printk("dev %d,%d ino %lu nlink %d", |
121 | __entry->dev_major, __entry->dev_minor, | 113 | MAJOR(__entry->dev), MINOR(__entry->dev), |
122 | (unsigned long) __entry->ino, __entry->nlink) | 114 | (unsigned long) __entry->ino, __entry->nlink) |
123 | ); | 115 | ); |
124 | 116 | ||
@@ -128,21 +120,19 @@ TRACE_EVENT(ext4_drop_inode, | |||
128 | TP_ARGS(inode, drop), | 120 | TP_ARGS(inode, drop), |
129 | 121 | ||
130 | TP_STRUCT__entry( | 122 | TP_STRUCT__entry( |
131 | __field( int, dev_major ) | 123 | __field( dev_t, dev ) |
132 | __field( int, dev_minor ) | ||
133 | __field( ino_t, ino ) | 124 | __field( ino_t, ino ) |
134 | __field( int, drop ) | 125 | __field( int, drop ) |
135 | ), | 126 | ), |
136 | 127 | ||
137 | TP_fast_assign( | 128 | TP_fast_assign( |
138 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 129 | __entry->dev = inode->i_sb->s_dev; |
139 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
140 | __entry->ino = inode->i_ino; | 130 | __entry->ino = inode->i_ino; |
141 | __entry->drop = drop; | 131 | __entry->drop = drop; |
142 | ), | 132 | ), |
143 | 133 | ||
144 | TP_printk("dev %d,%d ino %lu drop %d", | 134 | TP_printk("dev %d,%d ino %lu drop %d", |
145 | __entry->dev_major, __entry->dev_minor, | 135 | MAJOR(__entry->dev), MINOR(__entry->dev), |
146 | (unsigned long) __entry->ino, __entry->drop) | 136 | (unsigned long) __entry->ino, __entry->drop) |
147 | ); | 137 | ); |
148 | 138 | ||
@@ -152,21 +142,19 @@ TRACE_EVENT(ext4_mark_inode_dirty, | |||
152 | TP_ARGS(inode, IP), | 142 | TP_ARGS(inode, IP), |
153 | 143 | ||
154 | TP_STRUCT__entry( | 144 | TP_STRUCT__entry( |
155 | __field( int, dev_major ) | 145 | __field( dev_t, dev ) |
156 | __field( int, dev_minor ) | ||
157 | __field( ino_t, ino ) | 146 | __field( ino_t, ino ) |
158 | __field(unsigned long, ip ) | 147 | __field(unsigned long, ip ) |
159 | ), | 148 | ), |
160 | 149 | ||
161 | TP_fast_assign( | 150 | TP_fast_assign( |
162 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 151 | __entry->dev = inode->i_sb->s_dev; |
163 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
164 | __entry->ino = inode->i_ino; | 152 | __entry->ino = inode->i_ino; |
165 | __entry->ip = IP; | 153 | __entry->ip = IP; |
166 | ), | 154 | ), |
167 | 155 | ||
168 | TP_printk("dev %d,%d ino %lu caller %pF", | 156 | TP_printk("dev %d,%d ino %lu caller %pF", |
169 | __entry->dev_major, __entry->dev_minor, | 157 | MAJOR(__entry->dev), MINOR(__entry->dev), |
170 | (unsigned long) __entry->ino, (void *)__entry->ip) | 158 | (unsigned long) __entry->ino, (void *)__entry->ip) |
171 | ); | 159 | ); |
172 | 160 | ||
@@ -176,21 +164,19 @@ TRACE_EVENT(ext4_begin_ordered_truncate, | |||
176 | TP_ARGS(inode, new_size), | 164 | TP_ARGS(inode, new_size), |
177 | 165 | ||
178 | TP_STRUCT__entry( | 166 | TP_STRUCT__entry( |
179 | __field( int, dev_major ) | 167 | __field( dev_t, dev ) |
180 | __field( int, dev_minor ) | ||
181 | __field( ino_t, ino ) | 168 | __field( ino_t, ino ) |
182 | __field( loff_t, new_size ) | 169 | __field( loff_t, new_size ) |
183 | ), | 170 | ), |
184 | 171 | ||
185 | TP_fast_assign( | 172 | TP_fast_assign( |
186 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 173 | __entry->dev = inode->i_sb->s_dev; |
187 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
188 | __entry->ino = inode->i_ino; | 174 | __entry->ino = inode->i_ino; |
189 | __entry->new_size = new_size; | 175 | __entry->new_size = new_size; |
190 | ), | 176 | ), |
191 | 177 | ||
192 | TP_printk("dev %d,%d ino %lu new_size %lld", | 178 | TP_printk("dev %d,%d ino %lu new_size %lld", |
193 | __entry->dev_major, __entry->dev_minor, | 179 | MAJOR(__entry->dev), MINOR(__entry->dev), |
194 | (unsigned long) __entry->ino, | 180 | (unsigned long) __entry->ino, |
195 | (long long) __entry->new_size) | 181 | (long long) __entry->new_size) |
196 | ); | 182 | ); |
@@ -203,8 +189,7 @@ DECLARE_EVENT_CLASS(ext4__write_begin, | |||
203 | TP_ARGS(inode, pos, len, flags), | 189 | TP_ARGS(inode, pos, len, flags), |
204 | 190 | ||
205 | TP_STRUCT__entry( | 191 | TP_STRUCT__entry( |
206 | __field( int, dev_major ) | 192 | __field( dev_t, dev ) |
207 | __field( int, dev_minor ) | ||
208 | __field( ino_t, ino ) | 193 | __field( ino_t, ino ) |
209 | __field( loff_t, pos ) | 194 | __field( loff_t, pos ) |
210 | __field( unsigned int, len ) | 195 | __field( unsigned int, len ) |
@@ -212,8 +197,7 @@ DECLARE_EVENT_CLASS(ext4__write_begin, | |||
212 | ), | 197 | ), |
213 | 198 | ||
214 | TP_fast_assign( | 199 | TP_fast_assign( |
215 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 200 | __entry->dev = inode->i_sb->s_dev; |
216 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
217 | __entry->ino = inode->i_ino; | 201 | __entry->ino = inode->i_ino; |
218 | __entry->pos = pos; | 202 | __entry->pos = pos; |
219 | __entry->len = len; | 203 | __entry->len = len; |
@@ -221,7 +205,7 @@ DECLARE_EVENT_CLASS(ext4__write_begin, | |||
221 | ), | 205 | ), |
222 | 206 | ||
223 | TP_printk("dev %d,%d ino %lu pos %llu len %u flags %u", | 207 | TP_printk("dev %d,%d ino %lu pos %llu len %u flags %u", |
224 | __entry->dev_major, __entry->dev_minor, | 208 | MAJOR(__entry->dev), MINOR(__entry->dev), |
225 | (unsigned long) __entry->ino, | 209 | (unsigned long) __entry->ino, |
226 | __entry->pos, __entry->len, __entry->flags) | 210 | __entry->pos, __entry->len, __entry->flags) |
227 | ); | 211 | ); |
@@ -249,8 +233,7 @@ DECLARE_EVENT_CLASS(ext4__write_end, | |||
249 | TP_ARGS(inode, pos, len, copied), | 233 | TP_ARGS(inode, pos, len, copied), |
250 | 234 | ||
251 | TP_STRUCT__entry( | 235 | TP_STRUCT__entry( |
252 | __field( int, dev_major ) | 236 | __field( dev_t, dev ) |
253 | __field( int, dev_minor ) | ||
254 | __field( ino_t, ino ) | 237 | __field( ino_t, ino ) |
255 | __field( loff_t, pos ) | 238 | __field( loff_t, pos ) |
256 | __field( unsigned int, len ) | 239 | __field( unsigned int, len ) |
@@ -258,8 +241,7 @@ DECLARE_EVENT_CLASS(ext4__write_end, | |||
258 | ), | 241 | ), |
259 | 242 | ||
260 | TP_fast_assign( | 243 | TP_fast_assign( |
261 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 244 | __entry->dev = inode->i_sb->s_dev; |
262 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
263 | __entry->ino = inode->i_ino; | 245 | __entry->ino = inode->i_ino; |
264 | __entry->pos = pos; | 246 | __entry->pos = pos; |
265 | __entry->len = len; | 247 | __entry->len = len; |
@@ -267,9 +249,9 @@ DECLARE_EVENT_CLASS(ext4__write_end, | |||
267 | ), | 249 | ), |
268 | 250 | ||
269 | TP_printk("dev %d,%d ino %lu pos %llu len %u copied %u", | 251 | TP_printk("dev %d,%d ino %lu pos %llu len %u copied %u", |
270 | __entry->dev_major, __entry->dev_minor, | 252 | MAJOR(__entry->dev), MINOR(__entry->dev), |
271 | (unsigned long) __entry->ino, __entry->pos, | 253 | (unsigned long) __entry->ino, |
272 | __entry->len, __entry->copied) | 254 | __entry->pos, __entry->len, __entry->copied) |
273 | ); | 255 | ); |
274 | 256 | ||
275 | DEFINE_EVENT(ext4__write_end, ext4_ordered_write_end, | 257 | DEFINE_EVENT(ext4__write_end, ext4_ordered_write_end, |
@@ -310,22 +292,20 @@ TRACE_EVENT(ext4_writepage, | |||
310 | TP_ARGS(inode, page), | 292 | TP_ARGS(inode, page), |
311 | 293 | ||
312 | TP_STRUCT__entry( | 294 | TP_STRUCT__entry( |
313 | __field( int, dev_major ) | 295 | __field( dev_t, dev ) |
314 | __field( int, dev_minor ) | ||
315 | __field( ino_t, ino ) | 296 | __field( ino_t, ino ) |
316 | __field( pgoff_t, index ) | 297 | __field( pgoff_t, index ) |
317 | 298 | ||
318 | ), | 299 | ), |
319 | 300 | ||
320 | TP_fast_assign( | 301 | TP_fast_assign( |
321 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 302 | __entry->dev = inode->i_sb->s_dev; |
322 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
323 | __entry->ino = inode->i_ino; | 303 | __entry->ino = inode->i_ino; |
324 | __entry->index = page->index; | 304 | __entry->index = page->index; |
325 | ), | 305 | ), |
326 | 306 | ||
327 | TP_printk("dev %d,%d ino %lu page_index %lu", | 307 | TP_printk("dev %d,%d ino %lu page_index %lu", |
328 | __entry->dev_major, __entry->dev_minor, | 308 | MAJOR(__entry->dev), MINOR(__entry->dev), |
329 | (unsigned long) __entry->ino, __entry->index) | 309 | (unsigned long) __entry->ino, __entry->index) |
330 | ); | 310 | ); |
331 | 311 | ||
@@ -335,43 +315,39 @@ TRACE_EVENT(ext4_da_writepages, | |||
335 | TP_ARGS(inode, wbc), | 315 | TP_ARGS(inode, wbc), |
336 | 316 | ||
337 | TP_STRUCT__entry( | 317 | TP_STRUCT__entry( |
338 | __field( int, dev_major ) | 318 | __field( dev_t, dev ) |
339 | __field( int, dev_minor ) | ||
340 | __field( ino_t, ino ) | 319 | __field( ino_t, ino ) |
341 | __field( long, nr_to_write ) | 320 | __field( long, nr_to_write ) |
342 | __field( long, pages_skipped ) | 321 | __field( long, pages_skipped ) |
343 | __field( loff_t, range_start ) | 322 | __field( loff_t, range_start ) |
344 | __field( loff_t, range_end ) | 323 | __field( loff_t, range_end ) |
324 | __field( int, sync_mode ) | ||
345 | __field( char, for_kupdate ) | 325 | __field( char, for_kupdate ) |
346 | __field( char, for_reclaim ) | ||
347 | __field( char, range_cyclic ) | 326 | __field( char, range_cyclic ) |
348 | __field( pgoff_t, writeback_index ) | 327 | __field( pgoff_t, writeback_index ) |
349 | ), | 328 | ), |
350 | 329 | ||
351 | TP_fast_assign( | 330 | TP_fast_assign( |
352 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 331 | __entry->dev = inode->i_sb->s_dev; |
353 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
354 | __entry->ino = inode->i_ino; | 332 | __entry->ino = inode->i_ino; |
355 | __entry->nr_to_write = wbc->nr_to_write; | 333 | __entry->nr_to_write = wbc->nr_to_write; |
356 | __entry->pages_skipped = wbc->pages_skipped; | 334 | __entry->pages_skipped = wbc->pages_skipped; |
357 | __entry->range_start = wbc->range_start; | 335 | __entry->range_start = wbc->range_start; |
358 | __entry->range_end = wbc->range_end; | 336 | __entry->range_end = wbc->range_end; |
337 | __entry->sync_mode = wbc->sync_mode; | ||
359 | __entry->for_kupdate = wbc->for_kupdate; | 338 | __entry->for_kupdate = wbc->for_kupdate; |
360 | __entry->for_reclaim = wbc->for_reclaim; | ||
361 | __entry->range_cyclic = wbc->range_cyclic; | 339 | __entry->range_cyclic = wbc->range_cyclic; |
362 | __entry->writeback_index = inode->i_mapping->writeback_index; | 340 | __entry->writeback_index = inode->i_mapping->writeback_index; |
363 | ), | 341 | ), |
364 | 342 | ||
365 | TP_printk("dev %d,%d ino %lu nr_to_write %ld pages_skipped %ld " | 343 | TP_printk("dev %d,%d ino %lu nr_to_write %ld pages_skipped %ld " |
366 | "range_start %llu range_end %llu " | 344 | "range_start %llu range_end %llu sync_mode %d" |
367 | "for_kupdate %d for_reclaim %d " | 345 | "for_kupdate %d range_cyclic %d writeback_index %lu", |
368 | "range_cyclic %d writeback_index %lu", | 346 | MAJOR(__entry->dev), MINOR(__entry->dev), |
369 | __entry->dev_major, __entry->dev_minor, | ||
370 | (unsigned long) __entry->ino, __entry->nr_to_write, | 347 | (unsigned long) __entry->ino, __entry->nr_to_write, |
371 | __entry->pages_skipped, __entry->range_start, | 348 | __entry->pages_skipped, __entry->range_start, |
372 | __entry->range_end, | 349 | __entry->range_end, __entry->sync_mode, |
373 | __entry->for_kupdate, __entry->for_reclaim, | 350 | __entry->for_kupdate, __entry->range_cyclic, |
374 | __entry->range_cyclic, | ||
375 | (unsigned long) __entry->writeback_index) | 351 | (unsigned long) __entry->writeback_index) |
376 | ); | 352 | ); |
377 | 353 | ||
@@ -381,8 +357,7 @@ TRACE_EVENT(ext4_da_write_pages, | |||
381 | TP_ARGS(inode, mpd), | 357 | TP_ARGS(inode, mpd), |
382 | 358 | ||
383 | TP_STRUCT__entry( | 359 | TP_STRUCT__entry( |
384 | __field( int, dev_major ) | 360 | __field( dev_t, dev ) |
385 | __field( int, dev_minor ) | ||
386 | __field( ino_t, ino ) | 361 | __field( ino_t, ino ) |
387 | __field( __u64, b_blocknr ) | 362 | __field( __u64, b_blocknr ) |
388 | __field( __u32, b_size ) | 363 | __field( __u32, b_size ) |
@@ -390,11 +365,11 @@ TRACE_EVENT(ext4_da_write_pages, | |||
390 | __field( unsigned long, first_page ) | 365 | __field( unsigned long, first_page ) |
391 | __field( int, io_done ) | 366 | __field( int, io_done ) |
392 | __field( int, pages_written ) | 367 | __field( int, pages_written ) |
368 | __field( int, sync_mode ) | ||
393 | ), | 369 | ), |
394 | 370 | ||
395 | TP_fast_assign( | 371 | TP_fast_assign( |
396 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 372 | __entry->dev = inode->i_sb->s_dev; |
397 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
398 | __entry->ino = inode->i_ino; | 373 | __entry->ino = inode->i_ino; |
399 | __entry->b_blocknr = mpd->b_blocknr; | 374 | __entry->b_blocknr = mpd->b_blocknr; |
400 | __entry->b_size = mpd->b_size; | 375 | __entry->b_size = mpd->b_size; |
@@ -402,14 +377,18 @@ TRACE_EVENT(ext4_da_write_pages, | |||
402 | __entry->first_page = mpd->first_page; | 377 | __entry->first_page = mpd->first_page; |
403 | __entry->io_done = mpd->io_done; | 378 | __entry->io_done = mpd->io_done; |
404 | __entry->pages_written = mpd->pages_written; | 379 | __entry->pages_written = mpd->pages_written; |
380 | __entry->sync_mode = mpd->wbc->sync_mode; | ||
405 | ), | 381 | ), |
406 | 382 | ||
407 | TP_printk("dev %d,%d ino %lu b_blocknr %llu b_size %u b_state 0x%04x first_page %lu io_done %d pages_written %d", | 383 | TP_printk("dev %d,%d ino %lu b_blocknr %llu b_size %u b_state 0x%04x " |
408 | __entry->dev_major, __entry->dev_minor, | 384 | "first_page %lu io_done %d pages_written %d sync_mode %d", |
385 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
409 | (unsigned long) __entry->ino, | 386 | (unsigned long) __entry->ino, |
410 | __entry->b_blocknr, __entry->b_size, | 387 | __entry->b_blocknr, __entry->b_size, |
411 | __entry->b_state, __entry->first_page, | 388 | __entry->b_state, __entry->first_page, |
412 | __entry->io_done, __entry->pages_written) | 389 | __entry->io_done, __entry->pages_written, |
390 | __entry->sync_mode | ||
391 | ) | ||
413 | ); | 392 | ); |
414 | 393 | ||
415 | TRACE_EVENT(ext4_da_writepages_result, | 394 | TRACE_EVENT(ext4_da_writepages_result, |
@@ -419,35 +398,100 @@ TRACE_EVENT(ext4_da_writepages_result, | |||
419 | TP_ARGS(inode, wbc, ret, pages_written), | 398 | TP_ARGS(inode, wbc, ret, pages_written), |
420 | 399 | ||
421 | TP_STRUCT__entry( | 400 | TP_STRUCT__entry( |
422 | __field( int, dev_major ) | 401 | __field( dev_t, dev ) |
423 | __field( int, dev_minor ) | ||
424 | __field( ino_t, ino ) | 402 | __field( ino_t, ino ) |
425 | __field( int, ret ) | 403 | __field( int, ret ) |
426 | __field( int, pages_written ) | 404 | __field( int, pages_written ) |
427 | __field( long, pages_skipped ) | 405 | __field( long, pages_skipped ) |
406 | __field( int, sync_mode ) | ||
428 | __field( char, more_io ) | 407 | __field( char, more_io ) |
429 | __field( pgoff_t, writeback_index ) | 408 | __field( pgoff_t, writeback_index ) |
430 | ), | 409 | ), |
431 | 410 | ||
432 | TP_fast_assign( | 411 | TP_fast_assign( |
433 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 412 | __entry->dev = inode->i_sb->s_dev; |
434 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
435 | __entry->ino = inode->i_ino; | 413 | __entry->ino = inode->i_ino; |
436 | __entry->ret = ret; | 414 | __entry->ret = ret; |
437 | __entry->pages_written = pages_written; | 415 | __entry->pages_written = pages_written; |
438 | __entry->pages_skipped = wbc->pages_skipped; | 416 | __entry->pages_skipped = wbc->pages_skipped; |
417 | __entry->sync_mode = wbc->sync_mode; | ||
439 | __entry->more_io = wbc->more_io; | 418 | __entry->more_io = wbc->more_io; |
440 | __entry->writeback_index = inode->i_mapping->writeback_index; | 419 | __entry->writeback_index = inode->i_mapping->writeback_index; |
441 | ), | 420 | ), |
442 | 421 | ||
443 | TP_printk("dev %d,%d ino %lu ret %d pages_written %d pages_skipped %ld more_io %d writeback_index %lu", | 422 | TP_printk("dev %d,%d ino %lu ret %d pages_written %d pages_skipped %ld " |
444 | __entry->dev_major, __entry->dev_minor, | 423 | " more_io %d sync_mode %d writeback_index %lu", |
424 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
445 | (unsigned long) __entry->ino, __entry->ret, | 425 | (unsigned long) __entry->ino, __entry->ret, |
446 | __entry->pages_written, __entry->pages_skipped, | 426 | __entry->pages_written, __entry->pages_skipped, |
447 | __entry->more_io, | 427 | __entry->more_io, __entry->sync_mode, |
448 | (unsigned long) __entry->writeback_index) | 428 | (unsigned long) __entry->writeback_index) |
449 | ); | 429 | ); |
450 | 430 | ||
431 | DECLARE_EVENT_CLASS(ext4__page_op, | ||
432 | TP_PROTO(struct page *page), | ||
433 | |||
434 | TP_ARGS(page), | ||
435 | |||
436 | TP_STRUCT__entry( | ||
437 | __field( pgoff_t, index ) | ||
438 | __field( ino_t, ino ) | ||
439 | __field( dev_t, dev ) | ||
440 | |||
441 | ), | ||
442 | |||
443 | TP_fast_assign( | ||
444 | __entry->index = page->index; | ||
445 | __entry->ino = page->mapping->host->i_ino; | ||
446 | __entry->dev = page->mapping->host->i_sb->s_dev; | ||
447 | ), | ||
448 | |||
449 | TP_printk("dev %d,%d ino %lu page_index %lu", | ||
450 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
451 | (unsigned long) __entry->ino, | ||
452 | __entry->index) | ||
453 | ); | ||
454 | |||
455 | DEFINE_EVENT(ext4__page_op, ext4_readpage, | ||
456 | |||
457 | TP_PROTO(struct page *page), | ||
458 | |||
459 | TP_ARGS(page) | ||
460 | ); | ||
461 | |||
462 | DEFINE_EVENT(ext4__page_op, ext4_releasepage, | ||
463 | |||
464 | TP_PROTO(struct page *page), | ||
465 | |||
466 | TP_ARGS(page) | ||
467 | ); | ||
468 | |||
469 | TRACE_EVENT(ext4_invalidatepage, | ||
470 | TP_PROTO(struct page *page, unsigned long offset), | ||
471 | |||
472 | TP_ARGS(page, offset), | ||
473 | |||
474 | TP_STRUCT__entry( | ||
475 | __field( pgoff_t, index ) | ||
476 | __field( unsigned long, offset ) | ||
477 | __field( ino_t, ino ) | ||
478 | __field( dev_t, dev ) | ||
479 | |||
480 | ), | ||
481 | |||
482 | TP_fast_assign( | ||
483 | __entry->index = page->index; | ||
484 | __entry->offset = offset; | ||
485 | __entry->ino = page->mapping->host->i_ino; | ||
486 | __entry->dev = page->mapping->host->i_sb->s_dev; | ||
487 | ), | ||
488 | |||
489 | TP_printk("dev %d,%d ino %lu page_index %lu offset %lu", | ||
490 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
491 | (unsigned long) __entry->ino, | ||
492 | __entry->index, __entry->offset) | ||
493 | ); | ||
494 | |||
451 | TRACE_EVENT(ext4_discard_blocks, | 495 | TRACE_EVENT(ext4_discard_blocks, |
452 | TP_PROTO(struct super_block *sb, unsigned long long blk, | 496 | TP_PROTO(struct super_block *sb, unsigned long long blk, |
453 | unsigned long long count), | 497 | unsigned long long count), |
@@ -455,22 +499,20 @@ TRACE_EVENT(ext4_discard_blocks, | |||
455 | TP_ARGS(sb, blk, count), | 499 | TP_ARGS(sb, blk, count), |
456 | 500 | ||
457 | TP_STRUCT__entry( | 501 | TP_STRUCT__entry( |
458 | __field( int, dev_major ) | 502 | __field( dev_t, dev ) |
459 | __field( int, dev_minor ) | ||
460 | __field( __u64, blk ) | 503 | __field( __u64, blk ) |
461 | __field( __u64, count ) | 504 | __field( __u64, count ) |
462 | 505 | ||
463 | ), | 506 | ), |
464 | 507 | ||
465 | TP_fast_assign( | 508 | TP_fast_assign( |
466 | __entry->dev_major = MAJOR(sb->s_dev); | 509 | __entry->dev = sb->s_dev; |
467 | __entry->dev_minor = MINOR(sb->s_dev); | ||
468 | __entry->blk = blk; | 510 | __entry->blk = blk; |
469 | __entry->count = count; | 511 | __entry->count = count; |
470 | ), | 512 | ), |
471 | 513 | ||
472 | TP_printk("dev %d,%d blk %llu count %llu", | 514 | TP_printk("dev %d,%d blk %llu count %llu", |
473 | __entry->dev_major, __entry->dev_minor, | 515 | MAJOR(__entry->dev), MINOR(__entry->dev), |
474 | __entry->blk, __entry->count) | 516 | __entry->blk, __entry->count) |
475 | ); | 517 | ); |
476 | 518 | ||
@@ -481,8 +523,7 @@ DECLARE_EVENT_CLASS(ext4__mb_new_pa, | |||
481 | TP_ARGS(ac, pa), | 523 | TP_ARGS(ac, pa), |
482 | 524 | ||
483 | TP_STRUCT__entry( | 525 | TP_STRUCT__entry( |
484 | __field( int, dev_major ) | 526 | __field( dev_t, dev ) |
485 | __field( int, dev_minor ) | ||
486 | __field( ino_t, ino ) | 527 | __field( ino_t, ino ) |
487 | __field( __u64, pa_pstart ) | 528 | __field( __u64, pa_pstart ) |
488 | __field( __u32, pa_len ) | 529 | __field( __u32, pa_len ) |
@@ -491,8 +532,7 @@ DECLARE_EVENT_CLASS(ext4__mb_new_pa, | |||
491 | ), | 532 | ), |
492 | 533 | ||
493 | TP_fast_assign( | 534 | TP_fast_assign( |
494 | __entry->dev_major = MAJOR(ac->ac_sb->s_dev); | 535 | __entry->dev = ac->ac_sb->s_dev; |
495 | __entry->dev_minor = MINOR(ac->ac_sb->s_dev); | ||
496 | __entry->ino = ac->ac_inode->i_ino; | 536 | __entry->ino = ac->ac_inode->i_ino; |
497 | __entry->pa_pstart = pa->pa_pstart; | 537 | __entry->pa_pstart = pa->pa_pstart; |
498 | __entry->pa_len = pa->pa_len; | 538 | __entry->pa_len = pa->pa_len; |
@@ -500,9 +540,9 @@ DECLARE_EVENT_CLASS(ext4__mb_new_pa, | |||
500 | ), | 540 | ), |
501 | 541 | ||
502 | TP_printk("dev %d,%d ino %lu pstart %llu len %u lstart %llu", | 542 | TP_printk("dev %d,%d ino %lu pstart %llu len %u lstart %llu", |
503 | __entry->dev_major, __entry->dev_minor, | 543 | MAJOR(__entry->dev), MINOR(__entry->dev), |
504 | (unsigned long) __entry->ino, __entry->pa_pstart, | 544 | (unsigned long) __entry->ino, |
505 | __entry->pa_len, __entry->pa_lstart) | 545 | __entry->pa_pstart, __entry->pa_len, __entry->pa_lstart) |
506 | ); | 546 | ); |
507 | 547 | ||
508 | DEFINE_EVENT(ext4__mb_new_pa, ext4_mb_new_inode_pa, | 548 | DEFINE_EVENT(ext4__mb_new_pa, ext4_mb_new_inode_pa, |
@@ -530,8 +570,7 @@ TRACE_EVENT(ext4_mb_release_inode_pa, | |||
530 | TP_ARGS(sb, inode, pa, block, count), | 570 | TP_ARGS(sb, inode, pa, block, count), |
531 | 571 | ||
532 | TP_STRUCT__entry( | 572 | TP_STRUCT__entry( |
533 | __field( int, dev_major ) | 573 | __field( dev_t, dev ) |
534 | __field( int, dev_minor ) | ||
535 | __field( ino_t, ino ) | 574 | __field( ino_t, ino ) |
536 | __field( __u64, block ) | 575 | __field( __u64, block ) |
537 | __field( __u32, count ) | 576 | __field( __u32, count ) |
@@ -539,16 +578,16 @@ TRACE_EVENT(ext4_mb_release_inode_pa, | |||
539 | ), | 578 | ), |
540 | 579 | ||
541 | TP_fast_assign( | 580 | TP_fast_assign( |
542 | __entry->dev_major = MAJOR(sb->s_dev); | 581 | __entry->dev = sb->s_dev; |
543 | __entry->dev_minor = MINOR(sb->s_dev); | ||
544 | __entry->ino = inode->i_ino; | 582 | __entry->ino = inode->i_ino; |
545 | __entry->block = block; | 583 | __entry->block = block; |
546 | __entry->count = count; | 584 | __entry->count = count; |
547 | ), | 585 | ), |
548 | 586 | ||
549 | TP_printk("dev %d,%d ino %lu block %llu count %u", | 587 | TP_printk("dev %d,%d ino %lu block %llu count %u", |
550 | __entry->dev_major, __entry->dev_minor, | 588 | MAJOR(__entry->dev), MINOR(__entry->dev), |
551 | (unsigned long) __entry->ino, __entry->block, __entry->count) | 589 | (unsigned long) __entry->ino, |
590 | __entry->block, __entry->count) | ||
552 | ); | 591 | ); |
553 | 592 | ||
554 | TRACE_EVENT(ext4_mb_release_group_pa, | 593 | TRACE_EVENT(ext4_mb_release_group_pa, |
@@ -558,22 +597,20 @@ TRACE_EVENT(ext4_mb_release_group_pa, | |||
558 | TP_ARGS(sb, pa), | 597 | TP_ARGS(sb, pa), |
559 | 598 | ||
560 | TP_STRUCT__entry( | 599 | TP_STRUCT__entry( |
561 | __field( int, dev_major ) | 600 | __field( dev_t, dev ) |
562 | __field( int, dev_minor ) | ||
563 | __field( __u64, pa_pstart ) | 601 | __field( __u64, pa_pstart ) |
564 | __field( __u32, pa_len ) | 602 | __field( __u32, pa_len ) |
565 | 603 | ||
566 | ), | 604 | ), |
567 | 605 | ||
568 | TP_fast_assign( | 606 | TP_fast_assign( |
569 | __entry->dev_major = MAJOR(sb->s_dev); | 607 | __entry->dev = sb->s_dev; |
570 | __entry->dev_minor = MINOR(sb->s_dev); | ||
571 | __entry->pa_pstart = pa->pa_pstart; | 608 | __entry->pa_pstart = pa->pa_pstart; |
572 | __entry->pa_len = pa->pa_len; | 609 | __entry->pa_len = pa->pa_len; |
573 | ), | 610 | ), |
574 | 611 | ||
575 | TP_printk("dev %d,%d pstart %llu len %u", | 612 | TP_printk("dev %d,%d pstart %llu len %u", |
576 | __entry->dev_major, __entry->dev_minor, | 613 | MAJOR(__entry->dev), MINOR(__entry->dev), |
577 | __entry->pa_pstart, __entry->pa_len) | 614 | __entry->pa_pstart, __entry->pa_len) |
578 | ); | 615 | ); |
579 | 616 | ||
@@ -583,20 +620,18 @@ TRACE_EVENT(ext4_discard_preallocations, | |||
583 | TP_ARGS(inode), | 620 | TP_ARGS(inode), |
584 | 621 | ||
585 | TP_STRUCT__entry( | 622 | TP_STRUCT__entry( |
586 | __field( int, dev_major ) | 623 | __field( dev_t, dev ) |
587 | __field( int, dev_minor ) | ||
588 | __field( ino_t, ino ) | 624 | __field( ino_t, ino ) |
589 | 625 | ||
590 | ), | 626 | ), |
591 | 627 | ||
592 | TP_fast_assign( | 628 | TP_fast_assign( |
593 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 629 | __entry->dev = inode->i_sb->s_dev; |
594 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
595 | __entry->ino = inode->i_ino; | 630 | __entry->ino = inode->i_ino; |
596 | ), | 631 | ), |
597 | 632 | ||
598 | TP_printk("dev %d,%d ino %lu", | 633 | TP_printk("dev %d,%d ino %lu", |
599 | __entry->dev_major, __entry->dev_minor, | 634 | MAJOR(__entry->dev), MINOR(__entry->dev), |
600 | (unsigned long) __entry->ino) | 635 | (unsigned long) __entry->ino) |
601 | ); | 636 | ); |
602 | 637 | ||
@@ -606,20 +641,19 @@ TRACE_EVENT(ext4_mb_discard_preallocations, | |||
606 | TP_ARGS(sb, needed), | 641 | TP_ARGS(sb, needed), |
607 | 642 | ||
608 | TP_STRUCT__entry( | 643 | TP_STRUCT__entry( |
609 | __field( int, dev_major ) | 644 | __field( dev_t, dev ) |
610 | __field( int, dev_minor ) | ||
611 | __field( int, needed ) | 645 | __field( int, needed ) |
612 | 646 | ||
613 | ), | 647 | ), |
614 | 648 | ||
615 | TP_fast_assign( | 649 | TP_fast_assign( |
616 | __entry->dev_major = MAJOR(sb->s_dev); | 650 | __entry->dev = sb->s_dev; |
617 | __entry->dev_minor = MINOR(sb->s_dev); | ||
618 | __entry->needed = needed; | 651 | __entry->needed = needed; |
619 | ), | 652 | ), |
620 | 653 | ||
621 | TP_printk("dev %d,%d needed %d", | 654 | TP_printk("dev %d,%d needed %d", |
622 | __entry->dev_major, __entry->dev_minor, __entry->needed) | 655 | MAJOR(__entry->dev), MINOR(__entry->dev), |
656 | __entry->needed) | ||
623 | ); | 657 | ); |
624 | 658 | ||
625 | TRACE_EVENT(ext4_request_blocks, | 659 | TRACE_EVENT(ext4_request_blocks, |
@@ -628,8 +662,7 @@ TRACE_EVENT(ext4_request_blocks, | |||
628 | TP_ARGS(ar), | 662 | TP_ARGS(ar), |
629 | 663 | ||
630 | TP_STRUCT__entry( | 664 | TP_STRUCT__entry( |
631 | __field( int, dev_major ) | 665 | __field( dev_t, dev ) |
632 | __field( int, dev_minor ) | ||
633 | __field( ino_t, ino ) | 666 | __field( ino_t, ino ) |
634 | __field( unsigned int, flags ) | 667 | __field( unsigned int, flags ) |
635 | __field( unsigned int, len ) | 668 | __field( unsigned int, len ) |
@@ -642,8 +675,7 @@ TRACE_EVENT(ext4_request_blocks, | |||
642 | ), | 675 | ), |
643 | 676 | ||
644 | TP_fast_assign( | 677 | TP_fast_assign( |
645 | __entry->dev_major = MAJOR(ar->inode->i_sb->s_dev); | 678 | __entry->dev = ar->inode->i_sb->s_dev; |
646 | __entry->dev_minor = MINOR(ar->inode->i_sb->s_dev); | ||
647 | __entry->ino = ar->inode->i_ino; | 679 | __entry->ino = ar->inode->i_ino; |
648 | __entry->flags = ar->flags; | 680 | __entry->flags = ar->flags; |
649 | __entry->len = ar->len; | 681 | __entry->len = ar->len; |
@@ -655,8 +687,9 @@ TRACE_EVENT(ext4_request_blocks, | |||
655 | __entry->pright = ar->pright; | 687 | __entry->pright = ar->pright; |
656 | ), | 688 | ), |
657 | 689 | ||
658 | TP_printk("dev %d,%d ino %lu flags %u len %u lblk %llu goal %llu lleft %llu lright %llu pleft %llu pright %llu ", | 690 | TP_printk("dev %d,%d ino %lu flags %u len %u lblk %llu goal %llu " |
659 | __entry->dev_major, __entry->dev_minor, | 691 | "lleft %llu lright %llu pleft %llu pright %llu ", |
692 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
660 | (unsigned long) __entry->ino, | 693 | (unsigned long) __entry->ino, |
661 | __entry->flags, __entry->len, | 694 | __entry->flags, __entry->len, |
662 | (unsigned long long) __entry->logical, | 695 | (unsigned long long) __entry->logical, |
@@ -673,8 +706,7 @@ TRACE_EVENT(ext4_allocate_blocks, | |||
673 | TP_ARGS(ar, block), | 706 | TP_ARGS(ar, block), |
674 | 707 | ||
675 | TP_STRUCT__entry( | 708 | TP_STRUCT__entry( |
676 | __field( int, dev_major ) | 709 | __field( dev_t, dev ) |
677 | __field( int, dev_minor ) | ||
678 | __field( ino_t, ino ) | 710 | __field( ino_t, ino ) |
679 | __field( __u64, block ) | 711 | __field( __u64, block ) |
680 | __field( unsigned int, flags ) | 712 | __field( unsigned int, flags ) |
@@ -688,8 +720,7 @@ TRACE_EVENT(ext4_allocate_blocks, | |||
688 | ), | 720 | ), |
689 | 721 | ||
690 | TP_fast_assign( | 722 | TP_fast_assign( |
691 | __entry->dev_major = MAJOR(ar->inode->i_sb->s_dev); | 723 | __entry->dev = ar->inode->i_sb->s_dev; |
692 | __entry->dev_minor = MINOR(ar->inode->i_sb->s_dev); | ||
693 | __entry->ino = ar->inode->i_ino; | 724 | __entry->ino = ar->inode->i_ino; |
694 | __entry->block = block; | 725 | __entry->block = block; |
695 | __entry->flags = ar->flags; | 726 | __entry->flags = ar->flags; |
@@ -702,10 +733,11 @@ TRACE_EVENT(ext4_allocate_blocks, | |||
702 | __entry->pright = ar->pright; | 733 | __entry->pright = ar->pright; |
703 | ), | 734 | ), |
704 | 735 | ||
705 | TP_printk("dev %d,%d ino %lu flags %u len %u block %llu lblk %llu goal %llu lleft %llu lright %llu pleft %llu pright %llu ", | 736 | TP_printk("dev %d,%d ino %lu flags %u len %u block %llu lblk %llu " |
706 | __entry->dev_major, __entry->dev_minor, | 737 | "goal %llu lleft %llu lright %llu pleft %llu pright %llu", |
707 | (unsigned long) __entry->ino, __entry->flags, | 738 | MAJOR(__entry->dev), MINOR(__entry->dev), |
708 | __entry->len, __entry->block, | 739 | (unsigned long) __entry->ino, |
740 | __entry->flags, __entry->len, __entry->block, | ||
709 | (unsigned long long) __entry->logical, | 741 | (unsigned long long) __entry->logical, |
710 | (unsigned long long) __entry->goal, | 742 | (unsigned long long) __entry->goal, |
711 | (unsigned long long) __entry->lleft, | 743 | (unsigned long long) __entry->lleft, |
@@ -721,8 +753,7 @@ TRACE_EVENT(ext4_free_blocks, | |||
721 | TP_ARGS(inode, block, count, flags), | 753 | TP_ARGS(inode, block, count, flags), |
722 | 754 | ||
723 | TP_STRUCT__entry( | 755 | TP_STRUCT__entry( |
724 | __field( int, dev_major ) | 756 | __field( dev_t, dev ) |
725 | __field( int, dev_minor ) | ||
726 | __field( ino_t, ino ) | 757 | __field( ino_t, ino ) |
727 | __field( umode_t, mode ) | 758 | __field( umode_t, mode ) |
728 | __field( __u64, block ) | 759 | __field( __u64, block ) |
@@ -731,8 +762,7 @@ TRACE_EVENT(ext4_free_blocks, | |||
731 | ), | 762 | ), |
732 | 763 | ||
733 | TP_fast_assign( | 764 | TP_fast_assign( |
734 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 765 | __entry->dev = inode->i_sb->s_dev; |
735 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
736 | __entry->ino = inode->i_ino; | 766 | __entry->ino = inode->i_ino; |
737 | __entry->mode = inode->i_mode; | 767 | __entry->mode = inode->i_mode; |
738 | __entry->block = block; | 768 | __entry->block = block; |
@@ -741,20 +771,19 @@ TRACE_EVENT(ext4_free_blocks, | |||
741 | ), | 771 | ), |
742 | 772 | ||
743 | TP_printk("dev %d,%d ino %lu mode 0%o block %llu count %lu flags %d", | 773 | TP_printk("dev %d,%d ino %lu mode 0%o block %llu count %lu flags %d", |
744 | __entry->dev_major, __entry->dev_minor, | 774 | MAJOR(__entry->dev), MINOR(__entry->dev), |
745 | (unsigned long) __entry->ino, | 775 | (unsigned long) __entry->ino, |
746 | __entry->mode, __entry->block, __entry->count, | 776 | __entry->mode, __entry->block, __entry->count, |
747 | __entry->flags) | 777 | __entry->flags) |
748 | ); | 778 | ); |
749 | 779 | ||
750 | TRACE_EVENT(ext4_sync_file, | 780 | TRACE_EVENT(ext4_sync_file_enter, |
751 | TP_PROTO(struct file *file, int datasync), | 781 | TP_PROTO(struct file *file, int datasync), |
752 | 782 | ||
753 | TP_ARGS(file, datasync), | 783 | TP_ARGS(file, datasync), |
754 | 784 | ||
755 | TP_STRUCT__entry( | 785 | TP_STRUCT__entry( |
756 | __field( int, dev_major ) | 786 | __field( dev_t, dev ) |
757 | __field( int, dev_minor ) | ||
758 | __field( ino_t, ino ) | 787 | __field( ino_t, ino ) |
759 | __field( ino_t, parent ) | 788 | __field( ino_t, parent ) |
760 | __field( int, datasync ) | 789 | __field( int, datasync ) |
@@ -763,39 +792,60 @@ TRACE_EVENT(ext4_sync_file, | |||
763 | TP_fast_assign( | 792 | TP_fast_assign( |
764 | struct dentry *dentry = file->f_path.dentry; | 793 | struct dentry *dentry = file->f_path.dentry; |
765 | 794 | ||
766 | __entry->dev_major = MAJOR(dentry->d_inode->i_sb->s_dev); | 795 | __entry->dev = dentry->d_inode->i_sb->s_dev; |
767 | __entry->dev_minor = MINOR(dentry->d_inode->i_sb->s_dev); | ||
768 | __entry->ino = dentry->d_inode->i_ino; | 796 | __entry->ino = dentry->d_inode->i_ino; |
769 | __entry->datasync = datasync; | 797 | __entry->datasync = datasync; |
770 | __entry->parent = dentry->d_parent->d_inode->i_ino; | 798 | __entry->parent = dentry->d_parent->d_inode->i_ino; |
771 | ), | 799 | ), |
772 | 800 | ||
773 | TP_printk("dev %d,%d ino %ld parent %ld datasync %d ", | 801 | TP_printk("dev %d,%d ino %ld parent %ld datasync %d ", |
774 | __entry->dev_major, __entry->dev_minor, | 802 | MAJOR(__entry->dev), MINOR(__entry->dev), |
775 | (unsigned long) __entry->ino, | 803 | (unsigned long) __entry->ino, |
776 | (unsigned long) __entry->parent, __entry->datasync) | 804 | (unsigned long) __entry->parent, __entry->datasync) |
777 | ); | 805 | ); |
778 | 806 | ||
807 | TRACE_EVENT(ext4_sync_file_exit, | ||
808 | TP_PROTO(struct inode *inode, int ret), | ||
809 | |||
810 | TP_ARGS(inode, ret), | ||
811 | |||
812 | TP_STRUCT__entry( | ||
813 | __field( int, ret ) | ||
814 | __field( ino_t, ino ) | ||
815 | __field( dev_t, dev ) | ||
816 | ), | ||
817 | |||
818 | TP_fast_assign( | ||
819 | __entry->ret = ret; | ||
820 | __entry->ino = inode->i_ino; | ||
821 | __entry->dev = inode->i_sb->s_dev; | ||
822 | ), | ||
823 | |||
824 | TP_printk("dev %d,%d ino %ld ret %d", | ||
825 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
826 | (unsigned long) __entry->ino, | ||
827 | __entry->ret) | ||
828 | ); | ||
829 | |||
779 | TRACE_EVENT(ext4_sync_fs, | 830 | TRACE_EVENT(ext4_sync_fs, |
780 | TP_PROTO(struct super_block *sb, int wait), | 831 | TP_PROTO(struct super_block *sb, int wait), |
781 | 832 | ||
782 | TP_ARGS(sb, wait), | 833 | TP_ARGS(sb, wait), |
783 | 834 | ||
784 | TP_STRUCT__entry( | 835 | TP_STRUCT__entry( |
785 | __field( int, dev_major ) | 836 | __field( dev_t, dev ) |
786 | __field( int, dev_minor ) | ||
787 | __field( int, wait ) | 837 | __field( int, wait ) |
788 | 838 | ||
789 | ), | 839 | ), |
790 | 840 | ||
791 | TP_fast_assign( | 841 | TP_fast_assign( |
792 | __entry->dev_major = MAJOR(sb->s_dev); | 842 | __entry->dev = sb->s_dev; |
793 | __entry->dev_minor = MINOR(sb->s_dev); | ||
794 | __entry->wait = wait; | 843 | __entry->wait = wait; |
795 | ), | 844 | ), |
796 | 845 | ||
797 | TP_printk("dev %d,%d wait %d", __entry->dev_major, | 846 | TP_printk("dev %d,%d wait %d", |
798 | __entry->dev_minor, __entry->wait) | 847 | MAJOR(__entry->dev), MINOR(__entry->dev), |
848 | __entry->wait) | ||
799 | ); | 849 | ); |
800 | 850 | ||
801 | TRACE_EVENT(ext4_alloc_da_blocks, | 851 | TRACE_EVENT(ext4_alloc_da_blocks, |
@@ -804,23 +854,21 @@ TRACE_EVENT(ext4_alloc_da_blocks, | |||
804 | TP_ARGS(inode), | 854 | TP_ARGS(inode), |
805 | 855 | ||
806 | TP_STRUCT__entry( | 856 | TP_STRUCT__entry( |
807 | __field( int, dev_major ) | 857 | __field( dev_t, dev ) |
808 | __field( int, dev_minor ) | ||
809 | __field( ino_t, ino ) | 858 | __field( ino_t, ino ) |
810 | __field( unsigned int, data_blocks ) | 859 | __field( unsigned int, data_blocks ) |
811 | __field( unsigned int, meta_blocks ) | 860 | __field( unsigned int, meta_blocks ) |
812 | ), | 861 | ), |
813 | 862 | ||
814 | TP_fast_assign( | 863 | TP_fast_assign( |
815 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 864 | __entry->dev = inode->i_sb->s_dev; |
816 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
817 | __entry->ino = inode->i_ino; | 865 | __entry->ino = inode->i_ino; |
818 | __entry->data_blocks = EXT4_I(inode)->i_reserved_data_blocks; | 866 | __entry->data_blocks = EXT4_I(inode)->i_reserved_data_blocks; |
819 | __entry->meta_blocks = EXT4_I(inode)->i_reserved_meta_blocks; | 867 | __entry->meta_blocks = EXT4_I(inode)->i_reserved_meta_blocks; |
820 | ), | 868 | ), |
821 | 869 | ||
822 | TP_printk("dev %d,%d ino %lu data_blocks %u meta_blocks %u", | 870 | TP_printk("dev %d,%d ino %lu data_blocks %u meta_blocks %u", |
823 | __entry->dev_major, __entry->dev_minor, | 871 | MAJOR(__entry->dev), MINOR(__entry->dev), |
824 | (unsigned long) __entry->ino, | 872 | (unsigned long) __entry->ino, |
825 | __entry->data_blocks, __entry->meta_blocks) | 873 | __entry->data_blocks, __entry->meta_blocks) |
826 | ); | 874 | ); |
@@ -831,8 +879,7 @@ TRACE_EVENT(ext4_mballoc_alloc, | |||
831 | TP_ARGS(ac), | 879 | TP_ARGS(ac), |
832 | 880 | ||
833 | TP_STRUCT__entry( | 881 | TP_STRUCT__entry( |
834 | __field( int, dev_major ) | 882 | __field( dev_t, dev ) |
835 | __field( int, dev_minor ) | ||
836 | __field( ino_t, ino ) | 883 | __field( ino_t, ino ) |
837 | __field( __u16, found ) | 884 | __field( __u16, found ) |
838 | __field( __u16, groups ) | 885 | __field( __u16, groups ) |
@@ -855,8 +902,7 @@ TRACE_EVENT(ext4_mballoc_alloc, | |||
855 | ), | 902 | ), |
856 | 903 | ||
857 | TP_fast_assign( | 904 | TP_fast_assign( |
858 | __entry->dev_major = MAJOR(ac->ac_inode->i_sb->s_dev); | 905 | __entry->dev = ac->ac_inode->i_sb->s_dev; |
859 | __entry->dev_minor = MINOR(ac->ac_inode->i_sb->s_dev); | ||
860 | __entry->ino = ac->ac_inode->i_ino; | 906 | __entry->ino = ac->ac_inode->i_ino; |
861 | __entry->found = ac->ac_found; | 907 | __entry->found = ac->ac_found; |
862 | __entry->flags = ac->ac_flags; | 908 | __entry->flags = ac->ac_flags; |
@@ -881,7 +927,7 @@ TRACE_EVENT(ext4_mballoc_alloc, | |||
881 | TP_printk("dev %d,%d inode %lu orig %u/%d/%u@%u goal %u/%d/%u@%u " | 927 | TP_printk("dev %d,%d inode %lu orig %u/%d/%u@%u goal %u/%d/%u@%u " |
882 | "result %u/%d/%u@%u blks %u grps %u cr %u flags 0x%04x " | 928 | "result %u/%d/%u@%u blks %u grps %u cr %u flags 0x%04x " |
883 | "tail %u broken %u", | 929 | "tail %u broken %u", |
884 | __entry->dev_major, __entry->dev_minor, | 930 | MAJOR(__entry->dev), MINOR(__entry->dev), |
885 | (unsigned long) __entry->ino, | 931 | (unsigned long) __entry->ino, |
886 | __entry->orig_group, __entry->orig_start, | 932 | __entry->orig_group, __entry->orig_start, |
887 | __entry->orig_len, __entry->orig_logical, | 933 | __entry->orig_len, __entry->orig_logical, |
@@ -900,8 +946,7 @@ TRACE_EVENT(ext4_mballoc_prealloc, | |||
900 | TP_ARGS(ac), | 946 | TP_ARGS(ac), |
901 | 947 | ||
902 | TP_STRUCT__entry( | 948 | TP_STRUCT__entry( |
903 | __field( int, dev_major ) | 949 | __field( dev_t, dev ) |
904 | __field( int, dev_minor ) | ||
905 | __field( ino_t, ino ) | 950 | __field( ino_t, ino ) |
906 | __field( __u32, orig_logical ) | 951 | __field( __u32, orig_logical ) |
907 | __field( int, orig_start ) | 952 | __field( int, orig_start ) |
@@ -914,8 +959,7 @@ TRACE_EVENT(ext4_mballoc_prealloc, | |||
914 | ), | 959 | ), |
915 | 960 | ||
916 | TP_fast_assign( | 961 | TP_fast_assign( |
917 | __entry->dev_major = MAJOR(ac->ac_inode->i_sb->s_dev); | 962 | __entry->dev = ac->ac_inode->i_sb->s_dev; |
918 | __entry->dev_minor = MINOR(ac->ac_inode->i_sb->s_dev); | ||
919 | __entry->ino = ac->ac_inode->i_ino; | 963 | __entry->ino = ac->ac_inode->i_ino; |
920 | __entry->orig_logical = ac->ac_o_ex.fe_logical; | 964 | __entry->orig_logical = ac->ac_o_ex.fe_logical; |
921 | __entry->orig_start = ac->ac_o_ex.fe_start; | 965 | __entry->orig_start = ac->ac_o_ex.fe_start; |
@@ -928,7 +972,7 @@ TRACE_EVENT(ext4_mballoc_prealloc, | |||
928 | ), | 972 | ), |
929 | 973 | ||
930 | TP_printk("dev %d,%d inode %lu orig %u/%d/%u@%u result %u/%d/%u@%u", | 974 | TP_printk("dev %d,%d inode %lu orig %u/%d/%u@%u result %u/%d/%u@%u", |
931 | __entry->dev_major, __entry->dev_minor, | 975 | MAJOR(__entry->dev), MINOR(__entry->dev), |
932 | (unsigned long) __entry->ino, | 976 | (unsigned long) __entry->ino, |
933 | __entry->orig_group, __entry->orig_start, | 977 | __entry->orig_group, __entry->orig_start, |
934 | __entry->orig_len, __entry->orig_logical, | 978 | __entry->orig_len, __entry->orig_logical, |
@@ -946,8 +990,7 @@ DECLARE_EVENT_CLASS(ext4__mballoc, | |||
946 | TP_ARGS(sb, inode, group, start, len), | 990 | TP_ARGS(sb, inode, group, start, len), |
947 | 991 | ||
948 | TP_STRUCT__entry( | 992 | TP_STRUCT__entry( |
949 | __field( int, dev_major ) | 993 | __field( dev_t, dev ) |
950 | __field( int, dev_minor ) | ||
951 | __field( ino_t, ino ) | 994 | __field( ino_t, ino ) |
952 | __field( int, result_start ) | 995 | __field( int, result_start ) |
953 | __field( __u32, result_group ) | 996 | __field( __u32, result_group ) |
@@ -955,8 +998,7 @@ DECLARE_EVENT_CLASS(ext4__mballoc, | |||
955 | ), | 998 | ), |
956 | 999 | ||
957 | TP_fast_assign( | 1000 | TP_fast_assign( |
958 | __entry->dev_major = MAJOR(sb->s_dev); | 1001 | __entry->dev = sb->s_dev; |
959 | __entry->dev_minor = MINOR(sb->s_dev); | ||
960 | __entry->ino = inode ? inode->i_ino : 0; | 1002 | __entry->ino = inode ? inode->i_ino : 0; |
961 | __entry->result_start = start; | 1003 | __entry->result_start = start; |
962 | __entry->result_group = group; | 1004 | __entry->result_group = group; |
@@ -964,7 +1006,7 @@ DECLARE_EVENT_CLASS(ext4__mballoc, | |||
964 | ), | 1006 | ), |
965 | 1007 | ||
966 | TP_printk("dev %d,%d inode %lu extent %u/%d/%u ", | 1008 | TP_printk("dev %d,%d inode %lu extent %u/%d/%u ", |
967 | __entry->dev_major, __entry->dev_minor, | 1009 | MAJOR(__entry->dev), MINOR(__entry->dev), |
968 | (unsigned long) __entry->ino, | 1010 | (unsigned long) __entry->ino, |
969 | __entry->result_group, __entry->result_start, | 1011 | __entry->result_group, __entry->result_start, |
970 | __entry->result_len) | 1012 | __entry->result_len) |
@@ -998,8 +1040,7 @@ TRACE_EVENT(ext4_forget, | |||
998 | TP_ARGS(inode, is_metadata, block), | 1040 | TP_ARGS(inode, is_metadata, block), |
999 | 1041 | ||
1000 | TP_STRUCT__entry( | 1042 | TP_STRUCT__entry( |
1001 | __field( int, dev_major ) | 1043 | __field( dev_t, dev ) |
1002 | __field( int, dev_minor ) | ||
1003 | __field( ino_t, ino ) | 1044 | __field( ino_t, ino ) |
1004 | __field( umode_t, mode ) | 1045 | __field( umode_t, mode ) |
1005 | __field( int, is_metadata ) | 1046 | __field( int, is_metadata ) |
@@ -1007,8 +1048,7 @@ TRACE_EVENT(ext4_forget, | |||
1007 | ), | 1048 | ), |
1008 | 1049 | ||
1009 | TP_fast_assign( | 1050 | TP_fast_assign( |
1010 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 1051 | __entry->dev = inode->i_sb->s_dev; |
1011 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
1012 | __entry->ino = inode->i_ino; | 1052 | __entry->ino = inode->i_ino; |
1013 | __entry->mode = inode->i_mode; | 1053 | __entry->mode = inode->i_mode; |
1014 | __entry->is_metadata = is_metadata; | 1054 | __entry->is_metadata = is_metadata; |
@@ -1016,9 +1056,9 @@ TRACE_EVENT(ext4_forget, | |||
1016 | ), | 1056 | ), |
1017 | 1057 | ||
1018 | TP_printk("dev %d,%d ino %lu mode 0%o is_metadata %d block %llu", | 1058 | TP_printk("dev %d,%d ino %lu mode 0%o is_metadata %d block %llu", |
1019 | __entry->dev_major, __entry->dev_minor, | 1059 | MAJOR(__entry->dev), MINOR(__entry->dev), |
1020 | (unsigned long) __entry->ino, __entry->mode, | 1060 | (unsigned long) __entry->ino, |
1021 | __entry->is_metadata, __entry->block) | 1061 | __entry->mode, __entry->is_metadata, __entry->block) |
1022 | ); | 1062 | ); |
1023 | 1063 | ||
1024 | TRACE_EVENT(ext4_da_update_reserve_space, | 1064 | TRACE_EVENT(ext4_da_update_reserve_space, |
@@ -1027,8 +1067,7 @@ TRACE_EVENT(ext4_da_update_reserve_space, | |||
1027 | TP_ARGS(inode, used_blocks), | 1067 | TP_ARGS(inode, used_blocks), |
1028 | 1068 | ||
1029 | TP_STRUCT__entry( | 1069 | TP_STRUCT__entry( |
1030 | __field( int, dev_major ) | 1070 | __field( dev_t, dev ) |
1031 | __field( int, dev_minor ) | ||
1032 | __field( ino_t, ino ) | 1071 | __field( ino_t, ino ) |
1033 | __field( umode_t, mode ) | 1072 | __field( umode_t, mode ) |
1034 | __field( __u64, i_blocks ) | 1073 | __field( __u64, i_blocks ) |
@@ -1039,8 +1078,7 @@ TRACE_EVENT(ext4_da_update_reserve_space, | |||
1039 | ), | 1078 | ), |
1040 | 1079 | ||
1041 | TP_fast_assign( | 1080 | TP_fast_assign( |
1042 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 1081 | __entry->dev = inode->i_sb->s_dev; |
1043 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
1044 | __entry->ino = inode->i_ino; | 1082 | __entry->ino = inode->i_ino; |
1045 | __entry->mode = inode->i_mode; | 1083 | __entry->mode = inode->i_mode; |
1046 | __entry->i_blocks = inode->i_blocks; | 1084 | __entry->i_blocks = inode->i_blocks; |
@@ -1050,10 +1088,12 @@ TRACE_EVENT(ext4_da_update_reserve_space, | |||
1050 | __entry->allocated_meta_blocks = EXT4_I(inode)->i_allocated_meta_blocks; | 1088 | __entry->allocated_meta_blocks = EXT4_I(inode)->i_allocated_meta_blocks; |
1051 | ), | 1089 | ), |
1052 | 1090 | ||
1053 | TP_printk("dev %d,%d ino %lu mode 0%o i_blocks %llu used_blocks %d reserved_data_blocks %d reserved_meta_blocks %d allocated_meta_blocks %d", | 1091 | TP_printk("dev %d,%d ino %lu mode 0%o i_blocks %llu used_blocks %d " |
1054 | __entry->dev_major, __entry->dev_minor, | 1092 | "reserved_data_blocks %d reserved_meta_blocks %d " |
1055 | (unsigned long) __entry->ino, __entry->mode, | 1093 | "allocated_meta_blocks %d", |
1056 | (unsigned long long) __entry->i_blocks, | 1094 | MAJOR(__entry->dev), MINOR(__entry->dev), |
1095 | (unsigned long) __entry->ino, | ||
1096 | __entry->mode, (unsigned long long) __entry->i_blocks, | ||
1057 | __entry->used_blocks, __entry->reserved_data_blocks, | 1097 | __entry->used_blocks, __entry->reserved_data_blocks, |
1058 | __entry->reserved_meta_blocks, __entry->allocated_meta_blocks) | 1098 | __entry->reserved_meta_blocks, __entry->allocated_meta_blocks) |
1059 | ); | 1099 | ); |
@@ -1064,8 +1104,7 @@ TRACE_EVENT(ext4_da_reserve_space, | |||
1064 | TP_ARGS(inode, md_needed), | 1104 | TP_ARGS(inode, md_needed), |
1065 | 1105 | ||
1066 | TP_STRUCT__entry( | 1106 | TP_STRUCT__entry( |
1067 | __field( int, dev_major ) | 1107 | __field( dev_t, dev ) |
1068 | __field( int, dev_minor ) | ||
1069 | __field( ino_t, ino ) | 1108 | __field( ino_t, ino ) |
1070 | __field( umode_t, mode ) | 1109 | __field( umode_t, mode ) |
1071 | __field( __u64, i_blocks ) | 1110 | __field( __u64, i_blocks ) |
@@ -1075,8 +1114,7 @@ TRACE_EVENT(ext4_da_reserve_space, | |||
1075 | ), | 1114 | ), |
1076 | 1115 | ||
1077 | TP_fast_assign( | 1116 | TP_fast_assign( |
1078 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 1117 | __entry->dev = inode->i_sb->s_dev; |
1079 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
1080 | __entry->ino = inode->i_ino; | 1118 | __entry->ino = inode->i_ino; |
1081 | __entry->mode = inode->i_mode; | 1119 | __entry->mode = inode->i_mode; |
1082 | __entry->i_blocks = inode->i_blocks; | 1120 | __entry->i_blocks = inode->i_blocks; |
@@ -1085,8 +1123,9 @@ TRACE_EVENT(ext4_da_reserve_space, | |||
1085 | __entry->reserved_meta_blocks = EXT4_I(inode)->i_reserved_meta_blocks; | 1123 | __entry->reserved_meta_blocks = EXT4_I(inode)->i_reserved_meta_blocks; |
1086 | ), | 1124 | ), |
1087 | 1125 | ||
1088 | TP_printk("dev %d,%d ino %lu mode 0%o i_blocks %llu md_needed %d reserved_data_blocks %d reserved_meta_blocks %d", | 1126 | TP_printk("dev %d,%d ino %lu mode 0%o i_blocks %llu md_needed %d " |
1089 | __entry->dev_major, __entry->dev_minor, | 1127 | "reserved_data_blocks %d reserved_meta_blocks %d", |
1128 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
1090 | (unsigned long) __entry->ino, | 1129 | (unsigned long) __entry->ino, |
1091 | __entry->mode, (unsigned long long) __entry->i_blocks, | 1130 | __entry->mode, (unsigned long long) __entry->i_blocks, |
1092 | __entry->md_needed, __entry->reserved_data_blocks, | 1131 | __entry->md_needed, __entry->reserved_data_blocks, |
@@ -1099,8 +1138,7 @@ TRACE_EVENT(ext4_da_release_space, | |||
1099 | TP_ARGS(inode, freed_blocks), | 1138 | TP_ARGS(inode, freed_blocks), |
1100 | 1139 | ||
1101 | TP_STRUCT__entry( | 1140 | TP_STRUCT__entry( |
1102 | __field( int, dev_major ) | 1141 | __field( dev_t, dev ) |
1103 | __field( int, dev_minor ) | ||
1104 | __field( ino_t, ino ) | 1142 | __field( ino_t, ino ) |
1105 | __field( umode_t, mode ) | 1143 | __field( umode_t, mode ) |
1106 | __field( __u64, i_blocks ) | 1144 | __field( __u64, i_blocks ) |
@@ -1111,8 +1149,7 @@ TRACE_EVENT(ext4_da_release_space, | |||
1111 | ), | 1149 | ), |
1112 | 1150 | ||
1113 | TP_fast_assign( | 1151 | TP_fast_assign( |
1114 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 1152 | __entry->dev = inode->i_sb->s_dev; |
1115 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
1116 | __entry->ino = inode->i_ino; | 1153 | __entry->ino = inode->i_ino; |
1117 | __entry->mode = inode->i_mode; | 1154 | __entry->mode = inode->i_mode; |
1118 | __entry->i_blocks = inode->i_blocks; | 1155 | __entry->i_blocks = inode->i_blocks; |
@@ -1122,8 +1159,10 @@ TRACE_EVENT(ext4_da_release_space, | |||
1122 | __entry->allocated_meta_blocks = EXT4_I(inode)->i_allocated_meta_blocks; | 1159 | __entry->allocated_meta_blocks = EXT4_I(inode)->i_allocated_meta_blocks; |
1123 | ), | 1160 | ), |
1124 | 1161 | ||
1125 | TP_printk("dev %d,%d ino %lu mode 0%o i_blocks %llu freed_blocks %d reserved_data_blocks %d reserved_meta_blocks %d allocated_meta_blocks %d", | 1162 | TP_printk("dev %d,%d ino %lu mode 0%o i_blocks %llu freed_blocks %d " |
1126 | __entry->dev_major, __entry->dev_minor, | 1163 | "reserved_data_blocks %d reserved_meta_blocks %d " |
1164 | "allocated_meta_blocks %d", | ||
1165 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
1127 | (unsigned long) __entry->ino, | 1166 | (unsigned long) __entry->ino, |
1128 | __entry->mode, (unsigned long long) __entry->i_blocks, | 1167 | __entry->mode, (unsigned long long) __entry->i_blocks, |
1129 | __entry->freed_blocks, __entry->reserved_data_blocks, | 1168 | __entry->freed_blocks, __entry->reserved_data_blocks, |
@@ -1136,20 +1175,19 @@ DECLARE_EVENT_CLASS(ext4__bitmap_load, | |||
1136 | TP_ARGS(sb, group), | 1175 | TP_ARGS(sb, group), |
1137 | 1176 | ||
1138 | TP_STRUCT__entry( | 1177 | TP_STRUCT__entry( |
1139 | __field( int, dev_major ) | 1178 | __field( dev_t, dev ) |
1140 | __field( int, dev_minor ) | ||
1141 | __field( __u32, group ) | 1179 | __field( __u32, group ) |
1142 | 1180 | ||
1143 | ), | 1181 | ), |
1144 | 1182 | ||
1145 | TP_fast_assign( | 1183 | TP_fast_assign( |
1146 | __entry->dev_major = MAJOR(sb->s_dev); | 1184 | __entry->dev = sb->s_dev; |
1147 | __entry->dev_minor = MINOR(sb->s_dev); | ||
1148 | __entry->group = group; | 1185 | __entry->group = group; |
1149 | ), | 1186 | ), |
1150 | 1187 | ||
1151 | TP_printk("dev %d,%d group %u", | 1188 | TP_printk("dev %d,%d group %u", |
1152 | __entry->dev_major, __entry->dev_minor, __entry->group) | 1189 | MAJOR(__entry->dev), MINOR(__entry->dev), |
1190 | __entry->group) | ||
1153 | ); | 1191 | ); |
1154 | 1192 | ||
1155 | DEFINE_EVENT(ext4__bitmap_load, ext4_mb_bitmap_load, | 1193 | DEFINE_EVENT(ext4__bitmap_load, ext4_mb_bitmap_load, |
@@ -1166,6 +1204,349 @@ DEFINE_EVENT(ext4__bitmap_load, ext4_mb_buddy_bitmap_load, | |||
1166 | TP_ARGS(sb, group) | 1204 | TP_ARGS(sb, group) |
1167 | ); | 1205 | ); |
1168 | 1206 | ||
1207 | DEFINE_EVENT(ext4__bitmap_load, ext4_read_block_bitmap_load, | ||
1208 | |||
1209 | TP_PROTO(struct super_block *sb, unsigned long group), | ||
1210 | |||
1211 | TP_ARGS(sb, group) | ||
1212 | ); | ||
1213 | |||
1214 | DEFINE_EVENT(ext4__bitmap_load, ext4_load_inode_bitmap, | ||
1215 | |||
1216 | TP_PROTO(struct super_block *sb, unsigned long group), | ||
1217 | |||
1218 | TP_ARGS(sb, group) | ||
1219 | ); | ||
1220 | |||
1221 | TRACE_EVENT(ext4_direct_IO_enter, | ||
1222 | TP_PROTO(struct inode *inode, loff_t offset, unsigned long len, int rw), | ||
1223 | |||
1224 | TP_ARGS(inode, offset, len, rw), | ||
1225 | |||
1226 | TP_STRUCT__entry( | ||
1227 | __field( ino_t, ino ) | ||
1228 | __field( dev_t, dev ) | ||
1229 | __field( loff_t, pos ) | ||
1230 | __field( unsigned long, len ) | ||
1231 | __field( int, rw ) | ||
1232 | ), | ||
1233 | |||
1234 | TP_fast_assign( | ||
1235 | __entry->ino = inode->i_ino; | ||
1236 | __entry->dev = inode->i_sb->s_dev; | ||
1237 | __entry->pos = offset; | ||
1238 | __entry->len = len; | ||
1239 | __entry->rw = rw; | ||
1240 | ), | ||
1241 | |||
1242 | TP_printk("dev %d,%d ino %lu pos %llu len %lu rw %d", | ||
1243 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
1244 | (unsigned long) __entry->ino, | ||
1245 | (unsigned long long) __entry->pos, __entry->len, __entry->rw) | ||
1246 | ); | ||
1247 | |||
1248 | TRACE_EVENT(ext4_direct_IO_exit, | ||
1249 | TP_PROTO(struct inode *inode, loff_t offset, unsigned long len, int rw, int ret), | ||
1250 | |||
1251 | TP_ARGS(inode, offset, len, rw, ret), | ||
1252 | |||
1253 | TP_STRUCT__entry( | ||
1254 | __field( ino_t, ino ) | ||
1255 | __field( dev_t, dev ) | ||
1256 | __field( loff_t, pos ) | ||
1257 | __field( unsigned long, len ) | ||
1258 | __field( int, rw ) | ||
1259 | __field( int, ret ) | ||
1260 | ), | ||
1261 | |||
1262 | TP_fast_assign( | ||
1263 | __entry->ino = inode->i_ino; | ||
1264 | __entry->dev = inode->i_sb->s_dev; | ||
1265 | __entry->pos = offset; | ||
1266 | __entry->len = len; | ||
1267 | __entry->rw = rw; | ||
1268 | __entry->ret = ret; | ||
1269 | ), | ||
1270 | |||
1271 | TP_printk("dev %d,%d ino %lu pos %llu len %lu rw %d ret %d", | ||
1272 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
1273 | (unsigned long) __entry->ino, | ||
1274 | (unsigned long long) __entry->pos, __entry->len, | ||
1275 | __entry->rw, __entry->ret) | ||
1276 | ); | ||
1277 | |||
1278 | TRACE_EVENT(ext4_fallocate_enter, | ||
1279 | TP_PROTO(struct inode *inode, loff_t offset, loff_t len, int mode), | ||
1280 | |||
1281 | TP_ARGS(inode, offset, len, mode), | ||
1282 | |||
1283 | TP_STRUCT__entry( | ||
1284 | __field( ino_t, ino ) | ||
1285 | __field( dev_t, dev ) | ||
1286 | __field( loff_t, pos ) | ||
1287 | __field( loff_t, len ) | ||
1288 | __field( int, mode ) | ||
1289 | ), | ||
1290 | |||
1291 | TP_fast_assign( | ||
1292 | __entry->ino = inode->i_ino; | ||
1293 | __entry->dev = inode->i_sb->s_dev; | ||
1294 | __entry->pos = offset; | ||
1295 | __entry->len = len; | ||
1296 | __entry->mode = mode; | ||
1297 | ), | ||
1298 | |||
1299 | TP_printk("dev %d,%d ino %ld pos %llu len %llu mode %d", | ||
1300 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
1301 | (unsigned long) __entry->ino, | ||
1302 | (unsigned long long) __entry->pos, | ||
1303 | (unsigned long long) __entry->len, __entry->mode) | ||
1304 | ); | ||
1305 | |||
1306 | TRACE_EVENT(ext4_fallocate_exit, | ||
1307 | TP_PROTO(struct inode *inode, loff_t offset, unsigned int max_blocks, int ret), | ||
1308 | |||
1309 | TP_ARGS(inode, offset, max_blocks, ret), | ||
1310 | |||
1311 | TP_STRUCT__entry( | ||
1312 | __field( ino_t, ino ) | ||
1313 | __field( dev_t, dev ) | ||
1314 | __field( loff_t, pos ) | ||
1315 | __field( unsigned, blocks ) | ||
1316 | __field( int, ret ) | ||
1317 | ), | ||
1318 | |||
1319 | TP_fast_assign( | ||
1320 | __entry->ino = inode->i_ino; | ||
1321 | __entry->dev = inode->i_sb->s_dev; | ||
1322 | __entry->pos = offset; | ||
1323 | __entry->blocks = max_blocks; | ||
1324 | __entry->ret = ret; | ||
1325 | ), | ||
1326 | |||
1327 | TP_printk("dev %d,%d ino %ld pos %llu blocks %d ret %d", | ||
1328 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
1329 | (unsigned long) __entry->ino, | ||
1330 | (unsigned long long) __entry->pos, __entry->blocks, | ||
1331 | __entry->ret) | ||
1332 | ); | ||
1333 | |||
1334 | TRACE_EVENT(ext4_unlink_enter, | ||
1335 | TP_PROTO(struct inode *parent, struct dentry *dentry), | ||
1336 | |||
1337 | TP_ARGS(parent, dentry), | ||
1338 | |||
1339 | TP_STRUCT__entry( | ||
1340 | __field( ino_t, parent ) | ||
1341 | __field( ino_t, ino ) | ||
1342 | __field( loff_t, size ) | ||
1343 | __field( dev_t, dev ) | ||
1344 | ), | ||
1345 | |||
1346 | TP_fast_assign( | ||
1347 | __entry->parent = parent->i_ino; | ||
1348 | __entry->ino = dentry->d_inode->i_ino; | ||
1349 | __entry->size = dentry->d_inode->i_size; | ||
1350 | __entry->dev = dentry->d_inode->i_sb->s_dev; | ||
1351 | ), | ||
1352 | |||
1353 | TP_printk("dev %d,%d ino %ld size %lld parent %ld", | ||
1354 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
1355 | (unsigned long) __entry->ino, __entry->size, | ||
1356 | (unsigned long) __entry->parent) | ||
1357 | ); | ||
1358 | |||
1359 | TRACE_EVENT(ext4_unlink_exit, | ||
1360 | TP_PROTO(struct dentry *dentry, int ret), | ||
1361 | |||
1362 | TP_ARGS(dentry, ret), | ||
1363 | |||
1364 | TP_STRUCT__entry( | ||
1365 | __field( ino_t, ino ) | ||
1366 | __field( dev_t, dev ) | ||
1367 | __field( int, ret ) | ||
1368 | ), | ||
1369 | |||
1370 | TP_fast_assign( | ||
1371 | __entry->ino = dentry->d_inode->i_ino; | ||
1372 | __entry->dev = dentry->d_inode->i_sb->s_dev; | ||
1373 | __entry->ret = ret; | ||
1374 | ), | ||
1375 | |||
1376 | TP_printk("dev %d,%d ino %ld ret %d", | ||
1377 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
1378 | (unsigned long) __entry->ino, | ||
1379 | __entry->ret) | ||
1380 | ); | ||
1381 | |||
1382 | DECLARE_EVENT_CLASS(ext4__truncate, | ||
1383 | TP_PROTO(struct inode *inode), | ||
1384 | |||
1385 | TP_ARGS(inode), | ||
1386 | |||
1387 | TP_STRUCT__entry( | ||
1388 | __field( ino_t, ino ) | ||
1389 | __field( dev_t, dev ) | ||
1390 | __field( blkcnt_t, blocks ) | ||
1391 | ), | ||
1392 | |||
1393 | TP_fast_assign( | ||
1394 | __entry->ino = inode->i_ino; | ||
1395 | __entry->dev = inode->i_sb->s_dev; | ||
1396 | __entry->blocks = inode->i_blocks; | ||
1397 | ), | ||
1398 | |||
1399 | TP_printk("dev %d,%d ino %lu blocks %lu", | ||
1400 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
1401 | (unsigned long) __entry->ino, (unsigned long) __entry->blocks) | ||
1402 | ); | ||
1403 | |||
1404 | DEFINE_EVENT(ext4__truncate, ext4_truncate_enter, | ||
1405 | |||
1406 | TP_PROTO(struct inode *inode), | ||
1407 | |||
1408 | TP_ARGS(inode) | ||
1409 | ); | ||
1410 | |||
1411 | DEFINE_EVENT(ext4__truncate, ext4_truncate_exit, | ||
1412 | |||
1413 | TP_PROTO(struct inode *inode), | ||
1414 | |||
1415 | TP_ARGS(inode) | ||
1416 | ); | ||
1417 | |||
1418 | DECLARE_EVENT_CLASS(ext4__map_blocks_enter, | ||
1419 | TP_PROTO(struct inode *inode, ext4_lblk_t lblk, | ||
1420 | unsigned len, unsigned flags), | ||
1421 | |||
1422 | TP_ARGS(inode, lblk, len, flags), | ||
1423 | |||
1424 | TP_STRUCT__entry( | ||
1425 | __field( ino_t, ino ) | ||
1426 | __field( dev_t, dev ) | ||
1427 | __field( ext4_lblk_t, lblk ) | ||
1428 | __field( unsigned, len ) | ||
1429 | __field( unsigned, flags ) | ||
1430 | ), | ||
1431 | |||
1432 | TP_fast_assign( | ||
1433 | __entry->ino = inode->i_ino; | ||
1434 | __entry->dev = inode->i_sb->s_dev; | ||
1435 | __entry->lblk = lblk; | ||
1436 | __entry->len = len; | ||
1437 | __entry->flags = flags; | ||
1438 | ), | ||
1439 | |||
1440 | TP_printk("dev %d,%d ino %lu lblk %u len %u flags %u", | ||
1441 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
1442 | (unsigned long) __entry->ino, | ||
1443 | (unsigned) __entry->lblk, __entry->len, __entry->flags) | ||
1444 | ); | ||
1445 | |||
1446 | DEFINE_EVENT(ext4__map_blocks_enter, ext4_ext_map_blocks_enter, | ||
1447 | TP_PROTO(struct inode *inode, ext4_lblk_t lblk, | ||
1448 | unsigned len, unsigned flags), | ||
1449 | |||
1450 | TP_ARGS(inode, lblk, len, flags) | ||
1451 | ); | ||
1452 | |||
1453 | DEFINE_EVENT(ext4__map_blocks_enter, ext4_ind_map_blocks_enter, | ||
1454 | TP_PROTO(struct inode *inode, ext4_lblk_t lblk, | ||
1455 | unsigned len, unsigned flags), | ||
1456 | |||
1457 | TP_ARGS(inode, lblk, len, flags) | ||
1458 | ); | ||
1459 | |||
1460 | DECLARE_EVENT_CLASS(ext4__map_blocks_exit, | ||
1461 | TP_PROTO(struct inode *inode, ext4_lblk_t lblk, | ||
1462 | ext4_fsblk_t pblk, unsigned len, int ret), | ||
1463 | |||
1464 | TP_ARGS(inode, lblk, pblk, len, ret), | ||
1465 | |||
1466 | TP_STRUCT__entry( | ||
1467 | __field( ino_t, ino ) | ||
1468 | __field( dev_t, dev ) | ||
1469 | __field( ext4_lblk_t, lblk ) | ||
1470 | __field( ext4_fsblk_t, pblk ) | ||
1471 | __field( unsigned, len ) | ||
1472 | __field( int, ret ) | ||
1473 | ), | ||
1474 | |||
1475 | TP_fast_assign( | ||
1476 | __entry->ino = inode->i_ino; | ||
1477 | __entry->dev = inode->i_sb->s_dev; | ||
1478 | __entry->lblk = lblk; | ||
1479 | __entry->pblk = pblk; | ||
1480 | __entry->len = len; | ||
1481 | __entry->ret = ret; | ||
1482 | ), | ||
1483 | |||
1484 | TP_printk("dev %d,%d ino %lu lblk %u pblk %llu len %u ret %d", | ||
1485 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
1486 | (unsigned long) __entry->ino, | ||
1487 | (unsigned) __entry->lblk, (unsigned long long) __entry->pblk, | ||
1488 | __entry->len, __entry->ret) | ||
1489 | ); | ||
1490 | |||
1491 | DEFINE_EVENT(ext4__map_blocks_exit, ext4_ext_map_blocks_exit, | ||
1492 | TP_PROTO(struct inode *inode, ext4_lblk_t lblk, | ||
1493 | ext4_fsblk_t pblk, unsigned len, int ret), | ||
1494 | |||
1495 | TP_ARGS(inode, lblk, pblk, len, ret) | ||
1496 | ); | ||
1497 | |||
1498 | DEFINE_EVENT(ext4__map_blocks_exit, ext4_ind_map_blocks_exit, | ||
1499 | TP_PROTO(struct inode *inode, ext4_lblk_t lblk, | ||
1500 | ext4_fsblk_t pblk, unsigned len, int ret), | ||
1501 | |||
1502 | TP_ARGS(inode, lblk, pblk, len, ret) | ||
1503 | ); | ||
1504 | |||
1505 | TRACE_EVENT(ext4_ext_load_extent, | ||
1506 | TP_PROTO(struct inode *inode, ext4_lblk_t lblk, ext4_fsblk_t pblk), | ||
1507 | |||
1508 | TP_ARGS(inode, lblk, pblk), | ||
1509 | |||
1510 | TP_STRUCT__entry( | ||
1511 | __field( ino_t, ino ) | ||
1512 | __field( dev_t, dev ) | ||
1513 | __field( ext4_lblk_t, lblk ) | ||
1514 | __field( ext4_fsblk_t, pblk ) | ||
1515 | ), | ||
1516 | |||
1517 | TP_fast_assign( | ||
1518 | __entry->ino = inode->i_ino; | ||
1519 | __entry->dev = inode->i_sb->s_dev; | ||
1520 | __entry->lblk = lblk; | ||
1521 | __entry->pblk = pblk; | ||
1522 | ), | ||
1523 | |||
1524 | TP_printk("dev %d,%d ino %lu lblk %u pblk %llu", | ||
1525 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
1526 | (unsigned long) __entry->ino, | ||
1527 | (unsigned) __entry->lblk, (unsigned long long) __entry->pblk) | ||
1528 | ); | ||
1529 | |||
1530 | TRACE_EVENT(ext4_load_inode, | ||
1531 | TP_PROTO(struct inode *inode), | ||
1532 | |||
1533 | TP_ARGS(inode), | ||
1534 | |||
1535 | TP_STRUCT__entry( | ||
1536 | __field( ino_t, ino ) | ||
1537 | __field( dev_t, dev ) | ||
1538 | ), | ||
1539 | |||
1540 | TP_fast_assign( | ||
1541 | __entry->ino = inode->i_ino; | ||
1542 | __entry->dev = inode->i_sb->s_dev; | ||
1543 | ), | ||
1544 | |||
1545 | TP_printk("dev %d,%d ino %ld", | ||
1546 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
1547 | (unsigned long) __entry->ino) | ||
1548 | ); | ||
1549 | |||
1169 | #endif /* _TRACE_EXT4_H */ | 1550 | #endif /* _TRACE_EXT4_H */ |
1170 | 1551 | ||
1171 | /* This part must be outside protection */ | 1552 | /* This part must be outside protection */ |
diff --git a/include/trace/events/jbd2.h b/include/trace/events/jbd2.h index 7447ea9305b5..bf16545cc977 100644 --- a/include/trace/events/jbd2.h +++ b/include/trace/events/jbd2.h | |||
@@ -17,19 +17,17 @@ TRACE_EVENT(jbd2_checkpoint, | |||
17 | TP_ARGS(journal, result), | 17 | TP_ARGS(journal, result), |
18 | 18 | ||
19 | TP_STRUCT__entry( | 19 | TP_STRUCT__entry( |
20 | __field( int, dev_major ) | 20 | __field( dev_t, dev ) |
21 | __field( int, dev_minor ) | ||
22 | __field( int, result ) | 21 | __field( int, result ) |
23 | ), | 22 | ), |
24 | 23 | ||
25 | TP_fast_assign( | 24 | TP_fast_assign( |
26 | __entry->dev_major = MAJOR(journal->j_fs_dev->bd_dev); | 25 | __entry->dev = journal->j_fs_dev->bd_dev; |
27 | __entry->dev_minor = MINOR(journal->j_fs_dev->bd_dev); | ||
28 | __entry->result = result; | 26 | __entry->result = result; |
29 | ), | 27 | ), |
30 | 28 | ||
31 | TP_printk("dev %d,%d result %d", | 29 | TP_printk("dev %s result %d", |
32 | __entry->dev_major, __entry->dev_minor, __entry->result) | 30 | jbd2_dev_to_name(__entry->dev), __entry->result) |
33 | ); | 31 | ); |
34 | 32 | ||
35 | DECLARE_EVENT_CLASS(jbd2_commit, | 33 | DECLARE_EVENT_CLASS(jbd2_commit, |
@@ -39,22 +37,20 @@ DECLARE_EVENT_CLASS(jbd2_commit, | |||
39 | TP_ARGS(journal, commit_transaction), | 37 | TP_ARGS(journal, commit_transaction), |
40 | 38 | ||
41 | TP_STRUCT__entry( | 39 | TP_STRUCT__entry( |
42 | __field( int, dev_major ) | 40 | __field( dev_t, dev ) |
43 | __field( int, dev_minor ) | ||
44 | __field( char, sync_commit ) | 41 | __field( char, sync_commit ) |
45 | __field( int, transaction ) | 42 | __field( int, transaction ) |
46 | ), | 43 | ), |
47 | 44 | ||
48 | TP_fast_assign( | 45 | TP_fast_assign( |
49 | __entry->dev_major = MAJOR(journal->j_fs_dev->bd_dev); | 46 | __entry->dev = journal->j_fs_dev->bd_dev; |
50 | __entry->dev_minor = MINOR(journal->j_fs_dev->bd_dev); | ||
51 | __entry->sync_commit = commit_transaction->t_synchronous_commit; | 47 | __entry->sync_commit = commit_transaction->t_synchronous_commit; |
52 | __entry->transaction = commit_transaction->t_tid; | 48 | __entry->transaction = commit_transaction->t_tid; |
53 | ), | 49 | ), |
54 | 50 | ||
55 | TP_printk("dev %d,%d transaction %d sync %d", | 51 | TP_printk("dev %s transaction %d sync %d", |
56 | __entry->dev_major, __entry->dev_minor, | 52 | jbd2_dev_to_name(__entry->dev), __entry->transaction, |
57 | __entry->transaction, __entry->sync_commit) | 53 | __entry->sync_commit) |
58 | ); | 54 | ); |
59 | 55 | ||
60 | DEFINE_EVENT(jbd2_commit, jbd2_start_commit, | 56 | DEFINE_EVENT(jbd2_commit, jbd2_start_commit, |
@@ -91,24 +87,22 @@ TRACE_EVENT(jbd2_end_commit, | |||
91 | TP_ARGS(journal, commit_transaction), | 87 | TP_ARGS(journal, commit_transaction), |
92 | 88 | ||
93 | TP_STRUCT__entry( | 89 | TP_STRUCT__entry( |
94 | __field( int, dev_major ) | 90 | __field( dev_t, dev ) |
95 | __field( int, dev_minor ) | ||
96 | __field( char, sync_commit ) | 91 | __field( char, sync_commit ) |
97 | __field( int, transaction ) | 92 | __field( int, transaction ) |
98 | __field( int, head ) | 93 | __field( int, head ) |
99 | ), | 94 | ), |
100 | 95 | ||
101 | TP_fast_assign( | 96 | TP_fast_assign( |
102 | __entry->dev_major = MAJOR(journal->j_fs_dev->bd_dev); | 97 | __entry->dev = journal->j_fs_dev->bd_dev; |
103 | __entry->dev_minor = MINOR(journal->j_fs_dev->bd_dev); | ||
104 | __entry->sync_commit = commit_transaction->t_synchronous_commit; | 98 | __entry->sync_commit = commit_transaction->t_synchronous_commit; |
105 | __entry->transaction = commit_transaction->t_tid; | 99 | __entry->transaction = commit_transaction->t_tid; |
106 | __entry->head = journal->j_tail_sequence; | 100 | __entry->head = journal->j_tail_sequence; |
107 | ), | 101 | ), |
108 | 102 | ||
109 | TP_printk("dev %d,%d transaction %d sync %d head %d", | 103 | TP_printk("dev %s transaction %d sync %d head %d", |
110 | __entry->dev_major, __entry->dev_minor, | 104 | jbd2_dev_to_name(__entry->dev), __entry->transaction, |
111 | __entry->transaction, __entry->sync_commit, __entry->head) | 105 | __entry->sync_commit, __entry->head) |
112 | ); | 106 | ); |
113 | 107 | ||
114 | TRACE_EVENT(jbd2_submit_inode_data, | 108 | TRACE_EVENT(jbd2_submit_inode_data, |
@@ -117,20 +111,17 @@ TRACE_EVENT(jbd2_submit_inode_data, | |||
117 | TP_ARGS(inode), | 111 | TP_ARGS(inode), |
118 | 112 | ||
119 | TP_STRUCT__entry( | 113 | TP_STRUCT__entry( |
120 | __field( int, dev_major ) | 114 | __field( dev_t, dev ) |
121 | __field( int, dev_minor ) | ||
122 | __field( ino_t, ino ) | 115 | __field( ino_t, ino ) |
123 | ), | 116 | ), |
124 | 117 | ||
125 | TP_fast_assign( | 118 | TP_fast_assign( |
126 | __entry->dev_major = MAJOR(inode->i_sb->s_dev); | 119 | __entry->dev = inode->i_sb->s_dev; |
127 | __entry->dev_minor = MINOR(inode->i_sb->s_dev); | ||
128 | __entry->ino = inode->i_ino; | 120 | __entry->ino = inode->i_ino; |
129 | ), | 121 | ), |
130 | 122 | ||
131 | TP_printk("dev %d,%d ino %lu", | 123 | TP_printk("dev %s ino %lu", |
132 | __entry->dev_major, __entry->dev_minor, | 124 | jbd2_dev_to_name(__entry->dev), (unsigned long) __entry->ino) |
133 | (unsigned long) __entry->ino) | ||
134 | ); | 125 | ); |
135 | 126 | ||
136 | TRACE_EVENT(jbd2_run_stats, | 127 | TRACE_EVENT(jbd2_run_stats, |
@@ -140,8 +131,7 @@ TRACE_EVENT(jbd2_run_stats, | |||
140 | TP_ARGS(dev, tid, stats), | 131 | TP_ARGS(dev, tid, stats), |
141 | 132 | ||
142 | TP_STRUCT__entry( | 133 | TP_STRUCT__entry( |
143 | __field( int, dev_major ) | 134 | __field( dev_t, dev ) |
144 | __field( int, dev_minor ) | ||
145 | __field( unsigned long, tid ) | 135 | __field( unsigned long, tid ) |
146 | __field( unsigned long, wait ) | 136 | __field( unsigned long, wait ) |
147 | __field( unsigned long, running ) | 137 | __field( unsigned long, running ) |
@@ -154,8 +144,7 @@ TRACE_EVENT(jbd2_run_stats, | |||
154 | ), | 144 | ), |
155 | 145 | ||
156 | TP_fast_assign( | 146 | TP_fast_assign( |
157 | __entry->dev_major = MAJOR(dev); | 147 | __entry->dev = dev; |
158 | __entry->dev_minor = MINOR(dev); | ||
159 | __entry->tid = tid; | 148 | __entry->tid = tid; |
160 | __entry->wait = stats->rs_wait; | 149 | __entry->wait = stats->rs_wait; |
161 | __entry->running = stats->rs_running; | 150 | __entry->running = stats->rs_running; |
@@ -167,9 +156,9 @@ TRACE_EVENT(jbd2_run_stats, | |||
167 | __entry->blocks_logged = stats->rs_blocks_logged; | 156 | __entry->blocks_logged = stats->rs_blocks_logged; |
168 | ), | 157 | ), |
169 | 158 | ||
170 | TP_printk("dev %d,%d tid %lu wait %u running %u locked %u flushing %u " | 159 | TP_printk("dev %s tid %lu wait %u running %u locked %u flushing %u " |
171 | "logging %u handle_count %u blocks %u blocks_logged %u", | 160 | "logging %u handle_count %u blocks %u blocks_logged %u", |
172 | __entry->dev_major, __entry->dev_minor, __entry->tid, | 161 | jbd2_dev_to_name(__entry->dev), __entry->tid, |
173 | jiffies_to_msecs(__entry->wait), | 162 | jiffies_to_msecs(__entry->wait), |
174 | jiffies_to_msecs(__entry->running), | 163 | jiffies_to_msecs(__entry->running), |
175 | jiffies_to_msecs(__entry->locked), | 164 | jiffies_to_msecs(__entry->locked), |
@@ -186,8 +175,7 @@ TRACE_EVENT(jbd2_checkpoint_stats, | |||
186 | TP_ARGS(dev, tid, stats), | 175 | TP_ARGS(dev, tid, stats), |
187 | 176 | ||
188 | TP_STRUCT__entry( | 177 | TP_STRUCT__entry( |
189 | __field( int, dev_major ) | 178 | __field( dev_t, dev ) |
190 | __field( int, dev_minor ) | ||
191 | __field( unsigned long, tid ) | 179 | __field( unsigned long, tid ) |
192 | __field( unsigned long, chp_time ) | 180 | __field( unsigned long, chp_time ) |
193 | __field( __u32, forced_to_close ) | 181 | __field( __u32, forced_to_close ) |
@@ -196,8 +184,7 @@ TRACE_EVENT(jbd2_checkpoint_stats, | |||
196 | ), | 184 | ), |
197 | 185 | ||
198 | TP_fast_assign( | 186 | TP_fast_assign( |
199 | __entry->dev_major = MAJOR(dev); | 187 | __entry->dev = dev; |
200 | __entry->dev_minor = MINOR(dev); | ||
201 | __entry->tid = tid; | 188 | __entry->tid = tid; |
202 | __entry->chp_time = stats->cs_chp_time; | 189 | __entry->chp_time = stats->cs_chp_time; |
203 | __entry->forced_to_close= stats->cs_forced_to_close; | 190 | __entry->forced_to_close= stats->cs_forced_to_close; |
@@ -205,9 +192,9 @@ TRACE_EVENT(jbd2_checkpoint_stats, | |||
205 | __entry->dropped = stats->cs_dropped; | 192 | __entry->dropped = stats->cs_dropped; |
206 | ), | 193 | ), |
207 | 194 | ||
208 | TP_printk("dev %d,%d tid %lu chp_time %u forced_to_close %u " | 195 | TP_printk("dev %s tid %lu chp_time %u forced_to_close %u " |
209 | "written %u dropped %u", | 196 | "written %u dropped %u", |
210 | __entry->dev_major, __entry->dev_minor, __entry->tid, | 197 | jbd2_dev_to_name(__entry->dev), __entry->tid, |
211 | jiffies_to_msecs(__entry->chp_time), | 198 | jiffies_to_msecs(__entry->chp_time), |
212 | __entry->forced_to_close, __entry->written, __entry->dropped) | 199 | __entry->forced_to_close, __entry->written, __entry->dropped) |
213 | ); | 200 | ); |
@@ -220,8 +207,7 @@ TRACE_EVENT(jbd2_cleanup_journal_tail, | |||
220 | TP_ARGS(journal, first_tid, block_nr, freed), | 207 | TP_ARGS(journal, first_tid, block_nr, freed), |
221 | 208 | ||
222 | TP_STRUCT__entry( | 209 | TP_STRUCT__entry( |
223 | __field( int, dev_major ) | 210 | __field( dev_t, dev ) |
224 | __field( int, dev_minor ) | ||
225 | __field( tid_t, tail_sequence ) | 211 | __field( tid_t, tail_sequence ) |
226 | __field( tid_t, first_tid ) | 212 | __field( tid_t, first_tid ) |
227 | __field(unsigned long, block_nr ) | 213 | __field(unsigned long, block_nr ) |
@@ -229,18 +215,16 @@ TRACE_EVENT(jbd2_cleanup_journal_tail, | |||
229 | ), | 215 | ), |
230 | 216 | ||
231 | TP_fast_assign( | 217 | TP_fast_assign( |
232 | __entry->dev_major = MAJOR(journal->j_fs_dev->bd_dev); | 218 | __entry->dev = journal->j_fs_dev->bd_dev; |
233 | __entry->dev_minor = MINOR(journal->j_fs_dev->bd_dev); | ||
234 | __entry->tail_sequence = journal->j_tail_sequence; | 219 | __entry->tail_sequence = journal->j_tail_sequence; |
235 | __entry->first_tid = first_tid; | 220 | __entry->first_tid = first_tid; |
236 | __entry->block_nr = block_nr; | 221 | __entry->block_nr = block_nr; |
237 | __entry->freed = freed; | 222 | __entry->freed = freed; |
238 | ), | 223 | ), |
239 | 224 | ||
240 | TP_printk("dev %d,%d from %u to %u offset %lu freed %lu", | 225 | TP_printk("dev %s from %u to %u offset %lu freed %lu", |
241 | __entry->dev_major, __entry->dev_minor, | 226 | jbd2_dev_to_name(__entry->dev), __entry->tail_sequence, |
242 | __entry->tail_sequence, __entry->first_tid, | 227 | __entry->first_tid, __entry->block_nr, __entry->freed) |
243 | __entry->block_nr, __entry->freed) | ||
244 | ); | 228 | ); |
245 | 229 | ||
246 | #endif /* _TRACE_JBD2_H */ | 230 | #endif /* _TRACE_JBD2_H */ |
diff --git a/ipc/namespace.c b/ipc/namespace.c index 3c3e5223e7e5..8054c8e5faf1 100644 --- a/ipc/namespace.c +++ b/ipc/namespace.c | |||
@@ -104,7 +104,6 @@ static void free_ipc_ns(struct ipc_namespace *ns) | |||
104 | sem_exit_ns(ns); | 104 | sem_exit_ns(ns); |
105 | msg_exit_ns(ns); | 105 | msg_exit_ns(ns); |
106 | shm_exit_ns(ns); | 106 | shm_exit_ns(ns); |
107 | kfree(ns); | ||
108 | atomic_dec(&nr_ipc_ns); | 107 | atomic_dec(&nr_ipc_ns); |
109 | 108 | ||
110 | /* | 109 | /* |
@@ -113,6 +112,7 @@ static void free_ipc_ns(struct ipc_namespace *ns) | |||
113 | */ | 112 | */ |
114 | ipcns_notify(IPCNS_REMOVED); | 113 | ipcns_notify(IPCNS_REMOVED); |
115 | put_user_ns(ns->user_ns); | 114 | put_user_ns(ns->user_ns); |
115 | kfree(ns); | ||
116 | } | 116 | } |
117 | 117 | ||
118 | /* | 118 | /* |
diff --git a/ipc/util.c b/ipc/util.c index 8fd1b891ec0c..5c0d28921ba8 100644 --- a/ipc/util.c +++ b/ipc/util.c | |||
@@ -317,6 +317,7 @@ retry: | |||
317 | 317 | ||
318 | /** | 318 | /** |
319 | * ipc_check_perms - check security and permissions for an IPC | 319 | * ipc_check_perms - check security and permissions for an IPC |
320 | * @ns: IPC namespace | ||
320 | * @ipcp: ipc permission set | 321 | * @ipcp: ipc permission set |
321 | * @ops: the actual security routine to call | 322 | * @ops: the actual security routine to call |
322 | * @params: its parameters | 323 | * @params: its parameters |
@@ -607,6 +608,7 @@ void ipc_rcu_putref(void *ptr) | |||
607 | 608 | ||
608 | /** | 609 | /** |
609 | * ipcperms - check IPC permissions | 610 | * ipcperms - check IPC permissions |
611 | * @ns: IPC namespace | ||
610 | * @ipcp: IPC permission set | 612 | * @ipcp: IPC permission set |
611 | * @flag: desired permission set. | 613 | * @flag: desired permission set. |
612 | * | 614 | * |
@@ -769,7 +771,7 @@ void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out) | |||
769 | 771 | ||
770 | /** | 772 | /** |
771 | * ipcctl_pre_down - retrieve an ipc and check permissions for some IPC_XXX cmd | 773 | * ipcctl_pre_down - retrieve an ipc and check permissions for some IPC_XXX cmd |
772 | * @ids: the ipc namespace | 774 | * @ns: the ipc namespace |
773 | * @ids: the table of ids where to look for the ipc | 775 | * @ids: the table of ids where to look for the ipc |
774 | * @id: the id of the ipc to retrieve | 776 | * @id: the id of the ipc to retrieve |
775 | * @cmd: the cmd to check | 777 | * @cmd: the cmd to check |
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index bd3e8e29caa3..6bc6e3bc4f9c 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c | |||
@@ -78,7 +78,7 @@ static unsigned int kdb_continue_catastrophic; | |||
78 | static kdbtab_t *kdb_commands; | 78 | static kdbtab_t *kdb_commands; |
79 | #define KDB_BASE_CMD_MAX 50 | 79 | #define KDB_BASE_CMD_MAX 50 |
80 | static int kdb_max_commands = KDB_BASE_CMD_MAX; | 80 | static int kdb_max_commands = KDB_BASE_CMD_MAX; |
81 | static kdbtab_t kdb_base_commands[50]; | 81 | static kdbtab_t kdb_base_commands[KDB_BASE_CMD_MAX]; |
82 | #define for_each_kdbcmd(cmd, num) \ | 82 | #define for_each_kdbcmd(cmd, num) \ |
83 | for ((cmd) = kdb_base_commands, (num) = 0; \ | 83 | for ((cmd) = kdb_base_commands, (num) = 0; \ |
84 | num < kdb_max_commands; \ | 84 | num < kdb_max_commands; \ |
@@ -2892,7 +2892,7 @@ static void __init kdb_inittab(void) | |||
2892 | "Send a signal to a process", 0, KDB_REPEAT_NONE); | 2892 | "Send a signal to a process", 0, KDB_REPEAT_NONE); |
2893 | kdb_register_repeat("summary", kdb_summary, "", | 2893 | kdb_register_repeat("summary", kdb_summary, "", |
2894 | "Summarize the system", 4, KDB_REPEAT_NONE); | 2894 | "Summarize the system", 4, KDB_REPEAT_NONE); |
2895 | kdb_register_repeat("per_cpu", kdb_per_cpu, "", | 2895 | kdb_register_repeat("per_cpu", kdb_per_cpu, "<sym> [<bytes>] [<cpu>]", |
2896 | "Display per_cpu variables", 3, KDB_REPEAT_NONE); | 2896 | "Display per_cpu variables", 3, KDB_REPEAT_NONE); |
2897 | kdb_register_repeat("grephelp", kdb_grep_help, "", | 2897 | kdb_register_repeat("grephelp", kdb_grep_help, "", |
2898 | "Display help on | grep", 0, KDB_REPEAT_NONE); | 2898 | "Display help on | grep", 0, KDB_REPEAT_NONE); |
diff --git a/kernel/futex.c b/kernel/futex.c index 6570c459f31c..dfb924ffe65b 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -782,8 +782,8 @@ static void __unqueue_futex(struct futex_q *q) | |||
782 | { | 782 | { |
783 | struct futex_hash_bucket *hb; | 783 | struct futex_hash_bucket *hb; |
784 | 784 | ||
785 | if (WARN_ON(!q->lock_ptr || !spin_is_locked(q->lock_ptr) | 785 | if (WARN_ON_SMP(!q->lock_ptr || !spin_is_locked(q->lock_ptr)) |
786 | || plist_node_empty(&q->list))) | 786 | || WARN_ON(plist_node_empty(&q->list))) |
787 | return; | 787 | return; |
788 | 788 | ||
789 | hb = container_of(q->lock_ptr, struct futex_hash_bucket, lock); | 789 | hb = container_of(q->lock_ptr, struct futex_hash_bucket, lock); |
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig index 09bef82d74cb..00f2c037267a 100644 --- a/kernel/irq/Kconfig +++ b/kernel/irq/Kconfig | |||
@@ -31,6 +31,10 @@ config GENERIC_IRQ_PROBE | |||
31 | config GENERIC_IRQ_SHOW | 31 | config GENERIC_IRQ_SHOW |
32 | bool | 32 | bool |
33 | 33 | ||
34 | # Print level/edge extra information | ||
35 | config GENERIC_IRQ_SHOW_LEVEL | ||
36 | bool | ||
37 | |||
34 | # Support for delayed migration from interrupt context | 38 | # Support for delayed migration from interrupt context |
35 | config GENERIC_PENDING_IRQ | 39 | config GENERIC_PENDING_IRQ |
36 | bool | 40 | bool |
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index dbccc799407f..6fb014f172f7 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c | |||
@@ -198,15 +198,6 @@ err: | |||
198 | return -ENOMEM; | 198 | return -ENOMEM; |
199 | } | 199 | } |
200 | 200 | ||
201 | struct irq_desc * __ref irq_to_desc_alloc_node(unsigned int irq, int node) | ||
202 | { | ||
203 | int res = irq_alloc_descs(irq, irq, 1, node); | ||
204 | |||
205 | if (res == -EEXIST || res == irq) | ||
206 | return irq_to_desc(irq); | ||
207 | return NULL; | ||
208 | } | ||
209 | |||
210 | static int irq_expand_nr_irqs(unsigned int nr) | 201 | static int irq_expand_nr_irqs(unsigned int nr) |
211 | { | 202 | { |
212 | if (nr > IRQ_BITMAP_BITS) | 203 | if (nr > IRQ_BITMAP_BITS) |
@@ -283,11 +274,6 @@ struct irq_desc *irq_to_desc(unsigned int irq) | |||
283 | return (irq < NR_IRQS) ? irq_desc + irq : NULL; | 274 | return (irq < NR_IRQS) ? irq_desc + irq : NULL; |
284 | } | 275 | } |
285 | 276 | ||
286 | struct irq_desc *irq_to_desc_alloc_node(unsigned int irq, int node) | ||
287 | { | ||
288 | return irq_to_desc(irq); | ||
289 | } | ||
290 | |||
291 | static void free_desc(unsigned int irq) | 277 | static void free_desc(unsigned int irq) |
292 | { | 278 | { |
293 | dynamic_irq_cleanup(irq); | 279 | dynamic_irq_cleanup(irq); |
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 760248de109d..626d092eed9a 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c | |||
@@ -404,7 +404,20 @@ int show_interrupts(struct seq_file *p, void *v) | |||
404 | seq_printf(p, "%*d: ", prec, i); | 404 | seq_printf(p, "%*d: ", prec, i); |
405 | for_each_online_cpu(j) | 405 | for_each_online_cpu(j) |
406 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); | 406 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); |
407 | seq_printf(p, " %8s", desc->irq_data.chip->name); | 407 | |
408 | if (desc->irq_data.chip) { | ||
409 | if (desc->irq_data.chip->irq_print_chip) | ||
410 | desc->irq_data.chip->irq_print_chip(&desc->irq_data, p); | ||
411 | else if (desc->irq_data.chip->name) | ||
412 | seq_printf(p, " %8s", desc->irq_data.chip->name); | ||
413 | else | ||
414 | seq_printf(p, " %8s", "-"); | ||
415 | } else { | ||
416 | seq_printf(p, " %8s", "None"); | ||
417 | } | ||
418 | #ifdef CONFIG_GENIRC_IRQ_SHOW_LEVEL | ||
419 | seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge"); | ||
420 | #endif | ||
408 | if (desc->name) | 421 | if (desc->name) |
409 | seq_printf(p, "-%-8s", desc->name); | 422 | seq_printf(p, "-%-8s", desc->name); |
410 | 423 | ||
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index a56aa58b9cb0..079f1d39a8b8 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c | |||
@@ -342,13 +342,15 @@ int lookup_symbol_attrs(unsigned long addr, unsigned long *size, | |||
342 | } | 342 | } |
343 | 343 | ||
344 | /* Look up a kernel symbol and return it in a text buffer. */ | 344 | /* Look up a kernel symbol and return it in a text buffer. */ |
345 | int sprint_symbol(char *buffer, unsigned long address) | 345 | static int __sprint_symbol(char *buffer, unsigned long address, |
346 | int symbol_offset) | ||
346 | { | 347 | { |
347 | char *modname; | 348 | char *modname; |
348 | const char *name; | 349 | const char *name; |
349 | unsigned long offset, size; | 350 | unsigned long offset, size; |
350 | int len; | 351 | int len; |
351 | 352 | ||
353 | address += symbol_offset; | ||
352 | name = kallsyms_lookup(address, &size, &offset, &modname, buffer); | 354 | name = kallsyms_lookup(address, &size, &offset, &modname, buffer); |
353 | if (!name) | 355 | if (!name) |
354 | return sprintf(buffer, "0x%lx", address); | 356 | return sprintf(buffer, "0x%lx", address); |
@@ -357,17 +359,53 @@ int sprint_symbol(char *buffer, unsigned long address) | |||
357 | strcpy(buffer, name); | 359 | strcpy(buffer, name); |
358 | len = strlen(buffer); | 360 | len = strlen(buffer); |
359 | buffer += len; | 361 | buffer += len; |
362 | offset -= symbol_offset; | ||
360 | 363 | ||
361 | if (modname) | 364 | if (modname) |
362 | len += sprintf(buffer, "+%#lx/%#lx [%s]", | 365 | len += sprintf(buffer, "+%#lx/%#lx [%s]", offset, size, modname); |
363 | offset, size, modname); | ||
364 | else | 366 | else |
365 | len += sprintf(buffer, "+%#lx/%#lx", offset, size); | 367 | len += sprintf(buffer, "+%#lx/%#lx", offset, size); |
366 | 368 | ||
367 | return len; | 369 | return len; |
368 | } | 370 | } |
371 | |||
372 | /** | ||
373 | * sprint_symbol - Look up a kernel symbol and return it in a text buffer | ||
374 | * @buffer: buffer to be stored | ||
375 | * @address: address to lookup | ||
376 | * | ||
377 | * This function looks up a kernel symbol with @address and stores its name, | ||
378 | * offset, size and module name to @buffer if possible. If no symbol was found, | ||
379 | * just saves its @address as is. | ||
380 | * | ||
381 | * This function returns the number of bytes stored in @buffer. | ||
382 | */ | ||
383 | int sprint_symbol(char *buffer, unsigned long address) | ||
384 | { | ||
385 | return __sprint_symbol(buffer, address, 0); | ||
386 | } | ||
387 | |||
369 | EXPORT_SYMBOL_GPL(sprint_symbol); | 388 | EXPORT_SYMBOL_GPL(sprint_symbol); |
370 | 389 | ||
390 | /** | ||
391 | * sprint_backtrace - Look up a backtrace symbol and return it in a text buffer | ||
392 | * @buffer: buffer to be stored | ||
393 | * @address: address to lookup | ||
394 | * | ||
395 | * This function is for stack backtrace and does the same thing as | ||
396 | * sprint_symbol() but with modified/decreased @address. If there is a | ||
397 | * tail-call to the function marked "noreturn", gcc optimized out code after | ||
398 | * the call so that the stack-saved return address could point outside of the | ||
399 | * caller. This function ensures that kallsyms will find the original caller | ||
400 | * by decreasing @address. | ||
401 | * | ||
402 | * This function returns the number of bytes stored in @buffer. | ||
403 | */ | ||
404 | int sprint_backtrace(char *buffer, unsigned long address) | ||
405 | { | ||
406 | return __sprint_symbol(buffer, address, -1); | ||
407 | } | ||
408 | |||
371 | /* Look up a kernel symbol and print it to the kernel messages. */ | 409 | /* Look up a kernel symbol and print it to the kernel messages. */ |
372 | void __print_symbol(const char *fmt, unsigned long address) | 410 | void __print_symbol(const char *fmt, unsigned long address) |
373 | { | 411 | { |
diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c index 1969d2fc4b36..71edd2f60c02 100644 --- a/kernel/lockdep_proc.c +++ b/kernel/lockdep_proc.c | |||
@@ -225,7 +225,7 @@ static int lockdep_stats_show(struct seq_file *m, void *v) | |||
225 | nr_irq_read_safe = 0, nr_irq_read_unsafe = 0, | 225 | nr_irq_read_safe = 0, nr_irq_read_unsafe = 0, |
226 | nr_softirq_read_safe = 0, nr_softirq_read_unsafe = 0, | 226 | nr_softirq_read_safe = 0, nr_softirq_read_unsafe = 0, |
227 | nr_hardirq_read_safe = 0, nr_hardirq_read_unsafe = 0, | 227 | nr_hardirq_read_safe = 0, nr_hardirq_read_unsafe = 0, |
228 | sum_forward_deps = 0, factor = 0; | 228 | sum_forward_deps = 0; |
229 | 229 | ||
230 | list_for_each_entry(class, &all_lock_classes, lock_entry) { | 230 | list_for_each_entry(class, &all_lock_classes, lock_entry) { |
231 | 231 | ||
@@ -283,13 +283,6 @@ static int lockdep_stats_show(struct seq_file *m, void *v) | |||
283 | nr_hardirq_unsafe * nr_hardirq_safe + | 283 | nr_hardirq_unsafe * nr_hardirq_safe + |
284 | nr_list_entries); | 284 | nr_list_entries); |
285 | 285 | ||
286 | /* | ||
287 | * Estimated factor between direct and indirect | ||
288 | * dependencies: | ||
289 | */ | ||
290 | if (nr_list_entries) | ||
291 | factor = sum_forward_deps / nr_list_entries; | ||
292 | |||
293 | #ifdef CONFIG_PROVE_LOCKING | 286 | #ifdef CONFIG_PROVE_LOCKING |
294 | seq_printf(m, " dependency chains: %11lu [max: %lu]\n", | 287 | seq_printf(m, " dependency chains: %11lu [max: %lu]\n", |
295 | nr_lock_chains, MAX_LOCKDEP_CHAINS); | 288 | nr_lock_chains, MAX_LOCKDEP_CHAINS); |
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 3472bb1a070c..c75925c4d1e2 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -145,7 +145,8 @@ static struct srcu_struct pmus_srcu; | |||
145 | */ | 145 | */ |
146 | int sysctl_perf_event_paranoid __read_mostly = 1; | 146 | int sysctl_perf_event_paranoid __read_mostly = 1; |
147 | 147 | ||
148 | int sysctl_perf_event_mlock __read_mostly = 512; /* 'free' kb per user */ | 148 | /* Minimum for 128 pages + 1 for the user control page */ |
149 | int sysctl_perf_event_mlock __read_mostly = 516; /* 'free' kb per user */ | ||
149 | 150 | ||
150 | /* | 151 | /* |
151 | * max perf event sample rate | 152 | * max perf event sample rate |
@@ -941,6 +942,7 @@ static void perf_group_attach(struct perf_event *event) | |||
941 | static void | 942 | static void |
942 | list_del_event(struct perf_event *event, struct perf_event_context *ctx) | 943 | list_del_event(struct perf_event *event, struct perf_event_context *ctx) |
943 | { | 944 | { |
945 | struct perf_cpu_context *cpuctx; | ||
944 | /* | 946 | /* |
945 | * We can have double detach due to exit/hot-unplug + close. | 947 | * We can have double detach due to exit/hot-unplug + close. |
946 | */ | 948 | */ |
@@ -949,8 +951,17 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx) | |||
949 | 951 | ||
950 | event->attach_state &= ~PERF_ATTACH_CONTEXT; | 952 | event->attach_state &= ~PERF_ATTACH_CONTEXT; |
951 | 953 | ||
952 | if (is_cgroup_event(event)) | 954 | if (is_cgroup_event(event)) { |
953 | ctx->nr_cgroups--; | 955 | ctx->nr_cgroups--; |
956 | cpuctx = __get_cpu_context(ctx); | ||
957 | /* | ||
958 | * if there are no more cgroup events | ||
959 | * then cler cgrp to avoid stale pointer | ||
960 | * in update_cgrp_time_from_cpuctx() | ||
961 | */ | ||
962 | if (!ctx->nr_cgroups) | ||
963 | cpuctx->cgrp = NULL; | ||
964 | } | ||
954 | 965 | ||
955 | ctx->nr_events--; | 966 | ctx->nr_events--; |
956 | if (event->attr.inherit_stat) | 967 | if (event->attr.inherit_stat) |
diff --git a/kernel/sched.c b/kernel/sched.c index ae659b99ce73..f592ce6f8616 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -5473,6 +5473,8 @@ EXPORT_SYMBOL(yield); | |||
5473 | * yield_to - yield the current processor to another thread in | 5473 | * yield_to - yield the current processor to another thread in |
5474 | * your thread group, or accelerate that thread toward the | 5474 | * your thread group, or accelerate that thread toward the |
5475 | * processor it's on. | 5475 | * processor it's on. |
5476 | * @p: target task | ||
5477 | * @preempt: whether task preemption is allowed or not | ||
5476 | * | 5478 | * |
5477 | * It's the caller's job to ensure that the target task struct | 5479 | * It's the caller's job to ensure that the target task struct |
5478 | * can't go away on us before we can do any checks. | 5480 | * can't go away on us before we can do any checks. |
@@ -8449,7 +8451,6 @@ int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent) | |||
8449 | { | 8451 | { |
8450 | struct cfs_rq *cfs_rq; | 8452 | struct cfs_rq *cfs_rq; |
8451 | struct sched_entity *se; | 8453 | struct sched_entity *se; |
8452 | struct rq *rq; | ||
8453 | int i; | 8454 | int i; |
8454 | 8455 | ||
8455 | tg->cfs_rq = kzalloc(sizeof(cfs_rq) * nr_cpu_ids, GFP_KERNEL); | 8456 | tg->cfs_rq = kzalloc(sizeof(cfs_rq) * nr_cpu_ids, GFP_KERNEL); |
@@ -8462,8 +8463,6 @@ int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent) | |||
8462 | tg->shares = NICE_0_LOAD; | 8463 | tg->shares = NICE_0_LOAD; |
8463 | 8464 | ||
8464 | for_each_possible_cpu(i) { | 8465 | for_each_possible_cpu(i) { |
8465 | rq = cpu_rq(i); | ||
8466 | |||
8467 | cfs_rq = kzalloc_node(sizeof(struct cfs_rq), | 8466 | cfs_rq = kzalloc_node(sizeof(struct cfs_rq), |
8468 | GFP_KERNEL, cpu_to_node(i)); | 8467 | GFP_KERNEL, cpu_to_node(i)); |
8469 | if (!cfs_rq) | 8468 | if (!cfs_rq) |
diff --git a/kernel/sched_idletask.c b/kernel/sched_idletask.c index c82f26c1b7c3..a776a6396427 100644 --- a/kernel/sched_idletask.c +++ b/kernel/sched_idletask.c | |||
@@ -94,6 +94,4 @@ static const struct sched_class idle_sched_class = { | |||
94 | 94 | ||
95 | .prio_changed = prio_changed_idle, | 95 | .prio_changed = prio_changed_idle, |
96 | .switched_to = switched_to_idle, | 96 | .switched_to = switched_to_idle, |
97 | |||
98 | /* no .task_new for idle tasks */ | ||
99 | }; | 97 | }; |
diff --git a/kernel/sched_stoptask.c b/kernel/sched_stoptask.c index 84ec9bcf82d9..1ba2bd40fdac 100644 --- a/kernel/sched_stoptask.c +++ b/kernel/sched_stoptask.c | |||
@@ -102,6 +102,4 @@ static const struct sched_class stop_sched_class = { | |||
102 | 102 | ||
103 | .prio_changed = prio_changed_stop, | 103 | .prio_changed = prio_changed_stop, |
104 | .switched_to = switched_to_stop, | 104 | .switched_to = switched_to_stop, |
105 | |||
106 | /* no .task_new for stop tasks */ | ||
107 | }; | 105 | }; |
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 3bd7e3d5c632..8ad5d576755e 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -14,7 +14,7 @@ | |||
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/mm.h> | 15 | #include <linux/mm.h> |
16 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
17 | #include <linux/sysdev.h> | 17 | #include <linux/syscore_ops.h> |
18 | #include <linux/clocksource.h> | 18 | #include <linux/clocksource.h> |
19 | #include <linux/jiffies.h> | 19 | #include <linux/jiffies.h> |
20 | #include <linux/time.h> | 20 | #include <linux/time.h> |
@@ -597,13 +597,12 @@ static struct timespec timekeeping_suspend_time; | |||
597 | 597 | ||
598 | /** | 598 | /** |
599 | * timekeeping_resume - Resumes the generic timekeeping subsystem. | 599 | * timekeeping_resume - Resumes the generic timekeeping subsystem. |
600 | * @dev: unused | ||
601 | * | 600 | * |
602 | * This is for the generic clocksource timekeeping. | 601 | * This is for the generic clocksource timekeeping. |
603 | * xtime/wall_to_monotonic/jiffies/etc are | 602 | * xtime/wall_to_monotonic/jiffies/etc are |
604 | * still managed by arch specific suspend/resume code. | 603 | * still managed by arch specific suspend/resume code. |
605 | */ | 604 | */ |
606 | static int timekeeping_resume(struct sys_device *dev) | 605 | static void timekeeping_resume(void) |
607 | { | 606 | { |
608 | unsigned long flags; | 607 | unsigned long flags; |
609 | struct timespec ts; | 608 | struct timespec ts; |
@@ -632,11 +631,9 @@ static int timekeeping_resume(struct sys_device *dev) | |||
632 | 631 | ||
633 | /* Resume hrtimers */ | 632 | /* Resume hrtimers */ |
634 | hres_timers_resume(); | 633 | hres_timers_resume(); |
635 | |||
636 | return 0; | ||
637 | } | 634 | } |
638 | 635 | ||
639 | static int timekeeping_suspend(struct sys_device *dev, pm_message_t state) | 636 | static int timekeeping_suspend(void) |
640 | { | 637 | { |
641 | unsigned long flags; | 638 | unsigned long flags; |
642 | 639 | ||
@@ -654,26 +651,18 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state) | |||
654 | } | 651 | } |
655 | 652 | ||
656 | /* sysfs resume/suspend bits for timekeeping */ | 653 | /* sysfs resume/suspend bits for timekeeping */ |
657 | static struct sysdev_class timekeeping_sysclass = { | 654 | static struct syscore_ops timekeeping_syscore_ops = { |
658 | .name = "timekeeping", | ||
659 | .resume = timekeeping_resume, | 655 | .resume = timekeeping_resume, |
660 | .suspend = timekeeping_suspend, | 656 | .suspend = timekeeping_suspend, |
661 | }; | 657 | }; |
662 | 658 | ||
663 | static struct sys_device device_timer = { | 659 | static int __init timekeeping_init_ops(void) |
664 | .id = 0, | ||
665 | .cls = &timekeeping_sysclass, | ||
666 | }; | ||
667 | |||
668 | static int __init timekeeping_init_device(void) | ||
669 | { | 660 | { |
670 | int error = sysdev_class_register(&timekeeping_sysclass); | 661 | register_syscore_ops(&timekeeping_syscore_ops); |
671 | if (!error) | 662 | return 0; |
672 | error = sysdev_register(&device_timer); | ||
673 | return error; | ||
674 | } | 663 | } |
675 | 664 | ||
676 | device_initcall(timekeeping_init_device); | 665 | device_initcall(timekeeping_init_ops); |
677 | 666 | ||
678 | /* | 667 | /* |
679 | * If the error is already larger, we look ahead even further | 668 | * If the error is already larger, we look ahead even further |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 888b611897d3..c075f4ea6b94 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -1467,7 +1467,7 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
1467 | return t_hash_next(m, pos); | 1467 | return t_hash_next(m, pos); |
1468 | 1468 | ||
1469 | (*pos)++; | 1469 | (*pos)++; |
1470 | iter->pos = *pos; | 1470 | iter->pos = iter->func_pos = *pos; |
1471 | 1471 | ||
1472 | if (iter->flags & FTRACE_ITER_PRINTALL) | 1472 | if (iter->flags & FTRACE_ITER_PRINTALL) |
1473 | return t_hash_start(m, pos); | 1473 | return t_hash_start(m, pos); |
@@ -1502,7 +1502,6 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
1502 | if (!rec) | 1502 | if (!rec) |
1503 | return t_hash_start(m, pos); | 1503 | return t_hash_start(m, pos); |
1504 | 1504 | ||
1505 | iter->func_pos = *pos; | ||
1506 | iter->func = rec; | 1505 | iter->func = rec; |
1507 | 1506 | ||
1508 | return iter; | 1507 | return iter; |
diff --git a/lib/Kconfig b/lib/Kconfig index 23fa7a359db7..9c10e38fc609 100644 --- a/lib/Kconfig +++ b/lib/Kconfig | |||
@@ -158,6 +158,45 @@ config REED_SOLOMON_DEC16 | |||
158 | boolean | 158 | boolean |
159 | 159 | ||
160 | # | 160 | # |
161 | # BCH support is selected if needed | ||
162 | # | ||
163 | config BCH | ||
164 | tristate | ||
165 | |||
166 | config BCH_CONST_PARAMS | ||
167 | boolean | ||
168 | help | ||
169 | Drivers may select this option to force specific constant | ||
170 | values for parameters 'm' (Galois field order) and 't' | ||
171 | (error correction capability). Those specific values must | ||
172 | be set by declaring default values for symbols BCH_CONST_M | ||
173 | and BCH_CONST_T. | ||
174 | Doing so will enable extra compiler optimizations, | ||
175 | improving encoding and decoding performance up to 2x for | ||
176 | usual (m,t) values (typically such that m*t < 200). | ||
177 | When this option is selected, the BCH library supports | ||
178 | only a single (m,t) configuration. This is mainly useful | ||
179 | for NAND flash board drivers requiring known, fixed BCH | ||
180 | parameters. | ||
181 | |||
182 | config BCH_CONST_M | ||
183 | int | ||
184 | range 5 15 | ||
185 | help | ||
186 | Constant value for Galois field order 'm'. If 'k' is the | ||
187 | number of data bits to protect, 'm' should be chosen such | ||
188 | that (k + m*t) <= 2**m - 1. | ||
189 | Drivers should declare a default value for this symbol if | ||
190 | they select option BCH_CONST_PARAMS. | ||
191 | |||
192 | config BCH_CONST_T | ||
193 | int | ||
194 | help | ||
195 | Constant value for error correction capability in bits 't'. | ||
196 | Drivers should declare a default value for this symbol if | ||
197 | they select option BCH_CONST_PARAMS. | ||
198 | |||
199 | # | ||
161 | # Textsearch support is select'ed if needed | 200 | # Textsearch support is select'ed if needed |
162 | # | 201 | # |
163 | config TEXTSEARCH | 202 | config TEXTSEARCH |
diff --git a/lib/Makefile b/lib/Makefile index d7872b5c4c1c..ef0f28571156 100644 --- a/lib/Makefile +++ b/lib/Makefile | |||
@@ -69,6 +69,7 @@ obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o | |||
69 | obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/ | 69 | obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/ |
70 | obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/ | 70 | obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/ |
71 | obj-$(CONFIG_REED_SOLOMON) += reed_solomon/ | 71 | obj-$(CONFIG_REED_SOLOMON) += reed_solomon/ |
72 | obj-$(CONFIG_BCH) += bch.o | ||
72 | obj-$(CONFIG_LZO_COMPRESS) += lzo/ | 73 | obj-$(CONFIG_LZO_COMPRESS) += lzo/ |
73 | obj-$(CONFIG_LZO_DECOMPRESS) += lzo/ | 74 | obj-$(CONFIG_LZO_DECOMPRESS) += lzo/ |
74 | obj-$(CONFIG_XZ_DEC) += xz/ | 75 | obj-$(CONFIG_XZ_DEC) += xz/ |
diff --git a/lib/bch.c b/lib/bch.c new file mode 100644 index 000000000000..bc89dfe4d1b3 --- /dev/null +++ b/lib/bch.c | |||
@@ -0,0 +1,1368 @@ | |||
1 | /* | ||
2 | * Generic binary BCH encoding/decoding library | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License version 2 as published by | ||
6 | * the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., 51 | ||
15 | * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Copyright © 2011 Parrot S.A. | ||
18 | * | ||
19 | * Author: Ivan Djelic <ivan.djelic@parrot.com> | ||
20 | * | ||
21 | * Description: | ||
22 | * | ||
23 | * This library provides runtime configurable encoding/decoding of binary | ||
24 | * Bose-Chaudhuri-Hocquenghem (BCH) codes. | ||
25 | * | ||
26 | * Call init_bch to get a pointer to a newly allocated bch_control structure for | ||
27 | * the given m (Galois field order), t (error correction capability) and | ||
28 | * (optional) primitive polynomial parameters. | ||
29 | * | ||
30 | * Call encode_bch to compute and store ecc parity bytes to a given buffer. | ||
31 | * Call decode_bch to detect and locate errors in received data. | ||
32 | * | ||
33 | * On systems supporting hw BCH features, intermediate results may be provided | ||
34 | * to decode_bch in order to skip certain steps. See decode_bch() documentation | ||
35 | * for details. | ||
36 | * | ||
37 | * Option CONFIG_BCH_CONST_PARAMS can be used to force fixed values of | ||
38 | * parameters m and t; thus allowing extra compiler optimizations and providing | ||
39 | * better (up to 2x) encoding performance. Using this option makes sense when | ||
40 | * (m,t) are fixed and known in advance, e.g. when using BCH error correction | ||
41 | * on a particular NAND flash device. | ||
42 | * | ||
43 | * Algorithmic details: | ||
44 | * | ||
45 | * Encoding is performed by processing 32 input bits in parallel, using 4 | ||
46 | * remainder lookup tables. | ||
47 | * | ||
48 | * The final stage of decoding involves the following internal steps: | ||
49 | * a. Syndrome computation | ||
50 | * b. Error locator polynomial computation using Berlekamp-Massey algorithm | ||
51 | * c. Error locator root finding (by far the most expensive step) | ||
52 | * | ||
53 | * In this implementation, step c is not performed using the usual Chien search. | ||
54 | * Instead, an alternative approach described in [1] is used. It consists in | ||
55 | * factoring the error locator polynomial using the Berlekamp Trace algorithm | ||
56 | * (BTA) down to a certain degree (4), after which ad hoc low-degree polynomial | ||
57 | * solving techniques [2] are used. The resulting algorithm, called BTZ, yields | ||
58 | * much better performance than Chien search for usual (m,t) values (typically | ||
59 | * m >= 13, t < 32, see [1]). | ||
60 | * | ||
61 | * [1] B. Biswas, V. Herbert. Efficient root finding of polynomials over fields | ||
62 | * of characteristic 2, in: Western European Workshop on Research in Cryptology | ||
63 | * - WEWoRC 2009, Graz, Austria, LNCS, Springer, July 2009, to appear. | ||
64 | * [2] [Zin96] V.A. Zinoviev. On the solution of equations of degree 10 over | ||
65 | * finite fields GF(2^q). In Rapport de recherche INRIA no 2829, 1996. | ||
66 | */ | ||
67 | |||
68 | #include <linux/kernel.h> | ||
69 | #include <linux/errno.h> | ||
70 | #include <linux/init.h> | ||
71 | #include <linux/module.h> | ||
72 | #include <linux/slab.h> | ||
73 | #include <linux/bitops.h> | ||
74 | #include <asm/byteorder.h> | ||
75 | #include <linux/bch.h> | ||
76 | |||
77 | #if defined(CONFIG_BCH_CONST_PARAMS) | ||
78 | #define GF_M(_p) (CONFIG_BCH_CONST_M) | ||
79 | #define GF_T(_p) (CONFIG_BCH_CONST_T) | ||
80 | #define GF_N(_p) ((1 << (CONFIG_BCH_CONST_M))-1) | ||
81 | #else | ||
82 | #define GF_M(_p) ((_p)->m) | ||
83 | #define GF_T(_p) ((_p)->t) | ||
84 | #define GF_N(_p) ((_p)->n) | ||
85 | #endif | ||
86 | |||
87 | #define BCH_ECC_WORDS(_p) DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 32) | ||
88 | #define BCH_ECC_BYTES(_p) DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 8) | ||
89 | |||
90 | #ifndef dbg | ||
91 | #define dbg(_fmt, args...) do {} while (0) | ||
92 | #endif | ||
93 | |||
94 | /* | ||
95 | * represent a polynomial over GF(2^m) | ||
96 | */ | ||
97 | struct gf_poly { | ||
98 | unsigned int deg; /* polynomial degree */ | ||
99 | unsigned int c[0]; /* polynomial terms */ | ||
100 | }; | ||
101 | |||
102 | /* given its degree, compute a polynomial size in bytes */ | ||
103 | #define GF_POLY_SZ(_d) (sizeof(struct gf_poly)+((_d)+1)*sizeof(unsigned int)) | ||
104 | |||
105 | /* polynomial of degree 1 */ | ||
106 | struct gf_poly_deg1 { | ||
107 | struct gf_poly poly; | ||
108 | unsigned int c[2]; | ||
109 | }; | ||
110 | |||
111 | /* | ||
112 | * same as encode_bch(), but process input data one byte at a time | ||
113 | */ | ||
114 | static void encode_bch_unaligned(struct bch_control *bch, | ||
115 | const unsigned char *data, unsigned int len, | ||
116 | uint32_t *ecc) | ||
117 | { | ||
118 | int i; | ||
119 | const uint32_t *p; | ||
120 | const int l = BCH_ECC_WORDS(bch)-1; | ||
121 | |||
122 | while (len--) { | ||
123 | p = bch->mod8_tab + (l+1)*(((ecc[0] >> 24)^(*data++)) & 0xff); | ||
124 | |||
125 | for (i = 0; i < l; i++) | ||
126 | ecc[i] = ((ecc[i] << 8)|(ecc[i+1] >> 24))^(*p++); | ||
127 | |||
128 | ecc[l] = (ecc[l] << 8)^(*p); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | * convert ecc bytes to aligned, zero-padded 32-bit ecc words | ||
134 | */ | ||
135 | static void load_ecc8(struct bch_control *bch, uint32_t *dst, | ||
136 | const uint8_t *src) | ||
137 | { | ||
138 | uint8_t pad[4] = {0, 0, 0, 0}; | ||
139 | unsigned int i, nwords = BCH_ECC_WORDS(bch)-1; | ||
140 | |||
141 | for (i = 0; i < nwords; i++, src += 4) | ||
142 | dst[i] = (src[0] << 24)|(src[1] << 16)|(src[2] << 8)|src[3]; | ||
143 | |||
144 | memcpy(pad, src, BCH_ECC_BYTES(bch)-4*nwords); | ||
145 | dst[nwords] = (pad[0] << 24)|(pad[1] << 16)|(pad[2] << 8)|pad[3]; | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * convert 32-bit ecc words to ecc bytes | ||
150 | */ | ||
151 | static void store_ecc8(struct bch_control *bch, uint8_t *dst, | ||
152 | const uint32_t *src) | ||
153 | { | ||
154 | uint8_t pad[4]; | ||
155 | unsigned int i, nwords = BCH_ECC_WORDS(bch)-1; | ||
156 | |||
157 | for (i = 0; i < nwords; i++) { | ||
158 | *dst++ = (src[i] >> 24); | ||
159 | *dst++ = (src[i] >> 16) & 0xff; | ||
160 | *dst++ = (src[i] >> 8) & 0xff; | ||
161 | *dst++ = (src[i] >> 0) & 0xff; | ||
162 | } | ||
163 | pad[0] = (src[nwords] >> 24); | ||
164 | pad[1] = (src[nwords] >> 16) & 0xff; | ||
165 | pad[2] = (src[nwords] >> 8) & 0xff; | ||
166 | pad[3] = (src[nwords] >> 0) & 0xff; | ||
167 | memcpy(dst, pad, BCH_ECC_BYTES(bch)-4*nwords); | ||
168 | } | ||
169 | |||
170 | /** | ||
171 | * encode_bch - calculate BCH ecc parity of data | ||
172 | * @bch: BCH control structure | ||
173 | * @data: data to encode | ||
174 | * @len: data length in bytes | ||
175 | * @ecc: ecc parity data, must be initialized by caller | ||
176 | * | ||
177 | * The @ecc parity array is used both as input and output parameter, in order to | ||
178 | * allow incremental computations. It should be of the size indicated by member | ||
179 | * @ecc_bytes of @bch, and should be initialized to 0 before the first call. | ||
180 | * | ||
181 | * The exact number of computed ecc parity bits is given by member @ecc_bits of | ||
182 | * @bch; it may be less than m*t for large values of t. | ||
183 | */ | ||
184 | void encode_bch(struct bch_control *bch, const uint8_t *data, | ||
185 | unsigned int len, uint8_t *ecc) | ||
186 | { | ||
187 | const unsigned int l = BCH_ECC_WORDS(bch)-1; | ||
188 | unsigned int i, mlen; | ||
189 | unsigned long m; | ||
190 | uint32_t w, r[l+1]; | ||
191 | const uint32_t * const tab0 = bch->mod8_tab; | ||
192 | const uint32_t * const tab1 = tab0 + 256*(l+1); | ||
193 | const uint32_t * const tab2 = tab1 + 256*(l+1); | ||
194 | const uint32_t * const tab3 = tab2 + 256*(l+1); | ||
195 | const uint32_t *pdata, *p0, *p1, *p2, *p3; | ||
196 | |||
197 | if (ecc) { | ||
198 | /* load ecc parity bytes into internal 32-bit buffer */ | ||
199 | load_ecc8(bch, bch->ecc_buf, ecc); | ||
200 | } else { | ||
201 | memset(bch->ecc_buf, 0, sizeof(r)); | ||
202 | } | ||
203 | |||
204 | /* process first unaligned data bytes */ | ||
205 | m = ((unsigned long)data) & 3; | ||
206 | if (m) { | ||
207 | mlen = (len < (4-m)) ? len : 4-m; | ||
208 | encode_bch_unaligned(bch, data, mlen, bch->ecc_buf); | ||
209 | data += mlen; | ||
210 | len -= mlen; | ||
211 | } | ||
212 | |||
213 | /* process 32-bit aligned data words */ | ||
214 | pdata = (uint32_t *)data; | ||
215 | mlen = len/4; | ||
216 | data += 4*mlen; | ||
217 | len -= 4*mlen; | ||
218 | memcpy(r, bch->ecc_buf, sizeof(r)); | ||
219 | |||
220 | /* | ||
221 | * split each 32-bit word into 4 polynomials of weight 8 as follows: | ||
222 | * | ||
223 | * 31 ...24 23 ...16 15 ... 8 7 ... 0 | ||
224 | * xxxxxxxx yyyyyyyy zzzzzzzz tttttttt | ||
225 | * tttttttt mod g = r0 (precomputed) | ||
226 | * zzzzzzzz 00000000 mod g = r1 (precomputed) | ||
227 | * yyyyyyyy 00000000 00000000 mod g = r2 (precomputed) | ||
228 | * xxxxxxxx 00000000 00000000 00000000 mod g = r3 (precomputed) | ||
229 | * xxxxxxxx yyyyyyyy zzzzzzzz tttttttt mod g = r0^r1^r2^r3 | ||
230 | */ | ||
231 | while (mlen--) { | ||
232 | /* input data is read in big-endian format */ | ||
233 | w = r[0]^cpu_to_be32(*pdata++); | ||
234 | p0 = tab0 + (l+1)*((w >> 0) & 0xff); | ||
235 | p1 = tab1 + (l+1)*((w >> 8) & 0xff); | ||
236 | p2 = tab2 + (l+1)*((w >> 16) & 0xff); | ||
237 | p3 = tab3 + (l+1)*((w >> 24) & 0xff); | ||
238 | |||
239 | for (i = 0; i < l; i++) | ||
240 | r[i] = r[i+1]^p0[i]^p1[i]^p2[i]^p3[i]; | ||
241 | |||
242 | r[l] = p0[l]^p1[l]^p2[l]^p3[l]; | ||
243 | } | ||
244 | memcpy(bch->ecc_buf, r, sizeof(r)); | ||
245 | |||
246 | /* process last unaligned bytes */ | ||
247 | if (len) | ||
248 | encode_bch_unaligned(bch, data, len, bch->ecc_buf); | ||
249 | |||
250 | /* store ecc parity bytes into original parity buffer */ | ||
251 | if (ecc) | ||
252 | store_ecc8(bch, ecc, bch->ecc_buf); | ||
253 | } | ||
254 | EXPORT_SYMBOL_GPL(encode_bch); | ||
255 | |||
256 | static inline int modulo(struct bch_control *bch, unsigned int v) | ||
257 | { | ||
258 | const unsigned int n = GF_N(bch); | ||
259 | while (v >= n) { | ||
260 | v -= n; | ||
261 | v = (v & n) + (v >> GF_M(bch)); | ||
262 | } | ||
263 | return v; | ||
264 | } | ||
265 | |||
266 | /* | ||
267 | * shorter and faster modulo function, only works when v < 2N. | ||
268 | */ | ||
269 | static inline int mod_s(struct bch_control *bch, unsigned int v) | ||
270 | { | ||
271 | const unsigned int n = GF_N(bch); | ||
272 | return (v < n) ? v : v-n; | ||
273 | } | ||
274 | |||
275 | static inline int deg(unsigned int poly) | ||
276 | { | ||
277 | /* polynomial degree is the most-significant bit index */ | ||
278 | return fls(poly)-1; | ||
279 | } | ||
280 | |||
281 | static inline int parity(unsigned int x) | ||
282 | { | ||
283 | /* | ||
284 | * public domain code snippet, lifted from | ||
285 | * http://www-graphics.stanford.edu/~seander/bithacks.html | ||
286 | */ | ||
287 | x ^= x >> 1; | ||
288 | x ^= x >> 2; | ||
289 | x = (x & 0x11111111U) * 0x11111111U; | ||
290 | return (x >> 28) & 1; | ||
291 | } | ||
292 | |||
293 | /* Galois field basic operations: multiply, divide, inverse, etc. */ | ||
294 | |||
295 | static inline unsigned int gf_mul(struct bch_control *bch, unsigned int a, | ||
296 | unsigned int b) | ||
297 | { | ||
298 | return (a && b) ? bch->a_pow_tab[mod_s(bch, bch->a_log_tab[a]+ | ||
299 | bch->a_log_tab[b])] : 0; | ||
300 | } | ||
301 | |||
302 | static inline unsigned int gf_sqr(struct bch_control *bch, unsigned int a) | ||
303 | { | ||
304 | return a ? bch->a_pow_tab[mod_s(bch, 2*bch->a_log_tab[a])] : 0; | ||
305 | } | ||
306 | |||
307 | static inline unsigned int gf_div(struct bch_control *bch, unsigned int a, | ||
308 | unsigned int b) | ||
309 | { | ||
310 | return a ? bch->a_pow_tab[mod_s(bch, bch->a_log_tab[a]+ | ||
311 | GF_N(bch)-bch->a_log_tab[b])] : 0; | ||
312 | } | ||
313 | |||
314 | static inline unsigned int gf_inv(struct bch_control *bch, unsigned int a) | ||
315 | { | ||
316 | return bch->a_pow_tab[GF_N(bch)-bch->a_log_tab[a]]; | ||
317 | } | ||
318 | |||
319 | static inline unsigned int a_pow(struct bch_control *bch, int i) | ||
320 | { | ||
321 | return bch->a_pow_tab[modulo(bch, i)]; | ||
322 | } | ||
323 | |||
324 | static inline int a_log(struct bch_control *bch, unsigned int x) | ||
325 | { | ||
326 | return bch->a_log_tab[x]; | ||
327 | } | ||
328 | |||
329 | static inline int a_ilog(struct bch_control *bch, unsigned int x) | ||
330 | { | ||
331 | return mod_s(bch, GF_N(bch)-bch->a_log_tab[x]); | ||
332 | } | ||
333 | |||
334 | /* | ||
335 | * compute 2t syndromes of ecc polynomial, i.e. ecc(a^j) for j=1..2t | ||
336 | */ | ||
337 | static void compute_syndromes(struct bch_control *bch, uint32_t *ecc, | ||
338 | unsigned int *syn) | ||
339 | { | ||
340 | int i, j, s; | ||
341 | unsigned int m; | ||
342 | uint32_t poly; | ||
343 | const int t = GF_T(bch); | ||
344 | |||
345 | s = bch->ecc_bits; | ||
346 | |||
347 | /* make sure extra bits in last ecc word are cleared */ | ||
348 | m = ((unsigned int)s) & 31; | ||
349 | if (m) | ||
350 | ecc[s/32] &= ~((1u << (32-m))-1); | ||
351 | memset(syn, 0, 2*t*sizeof(*syn)); | ||
352 | |||
353 | /* compute v(a^j) for j=1 .. 2t-1 */ | ||
354 | do { | ||
355 | poly = *ecc++; | ||
356 | s -= 32; | ||
357 | while (poly) { | ||
358 | i = deg(poly); | ||
359 | for (j = 0; j < 2*t; j += 2) | ||
360 | syn[j] ^= a_pow(bch, (j+1)*(i+s)); | ||
361 | |||
362 | poly ^= (1 << i); | ||
363 | } | ||
364 | } while (s > 0); | ||
365 | |||
366 | /* v(a^(2j)) = v(a^j)^2 */ | ||
367 | for (j = 0; j < t; j++) | ||
368 | syn[2*j+1] = gf_sqr(bch, syn[j]); | ||
369 | } | ||
370 | |||
371 | static void gf_poly_copy(struct gf_poly *dst, struct gf_poly *src) | ||
372 | { | ||
373 | memcpy(dst, src, GF_POLY_SZ(src->deg)); | ||
374 | } | ||
375 | |||
376 | static int compute_error_locator_polynomial(struct bch_control *bch, | ||
377 | const unsigned int *syn) | ||
378 | { | ||
379 | const unsigned int t = GF_T(bch); | ||
380 | const unsigned int n = GF_N(bch); | ||
381 | unsigned int i, j, tmp, l, pd = 1, d = syn[0]; | ||
382 | struct gf_poly *elp = bch->elp; | ||
383 | struct gf_poly *pelp = bch->poly_2t[0]; | ||
384 | struct gf_poly *elp_copy = bch->poly_2t[1]; | ||
385 | int k, pp = -1; | ||
386 | |||
387 | memset(pelp, 0, GF_POLY_SZ(2*t)); | ||
388 | memset(elp, 0, GF_POLY_SZ(2*t)); | ||
389 | |||
390 | pelp->deg = 0; | ||
391 | pelp->c[0] = 1; | ||
392 | elp->deg = 0; | ||
393 | elp->c[0] = 1; | ||
394 | |||
395 | /* use simplified binary Berlekamp-Massey algorithm */ | ||
396 | for (i = 0; (i < t) && (elp->deg <= t); i++) { | ||
397 | if (d) { | ||
398 | k = 2*i-pp; | ||
399 | gf_poly_copy(elp_copy, elp); | ||
400 | /* e[i+1](X) = e[i](X)+di*dp^-1*X^2(i-p)*e[p](X) */ | ||
401 | tmp = a_log(bch, d)+n-a_log(bch, pd); | ||
402 | for (j = 0; j <= pelp->deg; j++) { | ||
403 | if (pelp->c[j]) { | ||
404 | l = a_log(bch, pelp->c[j]); | ||
405 | elp->c[j+k] ^= a_pow(bch, tmp+l); | ||
406 | } | ||
407 | } | ||
408 | /* compute l[i+1] = max(l[i]->c[l[p]+2*(i-p]) */ | ||
409 | tmp = pelp->deg+k; | ||
410 | if (tmp > elp->deg) { | ||
411 | elp->deg = tmp; | ||
412 | gf_poly_copy(pelp, elp_copy); | ||
413 | pd = d; | ||
414 | pp = 2*i; | ||
415 | } | ||
416 | } | ||
417 | /* di+1 = S(2i+3)+elp[i+1].1*S(2i+2)+...+elp[i+1].lS(2i+3-l) */ | ||
418 | if (i < t-1) { | ||
419 | d = syn[2*i+2]; | ||
420 | for (j = 1; j <= elp->deg; j++) | ||
421 | d ^= gf_mul(bch, elp->c[j], syn[2*i+2-j]); | ||
422 | } | ||
423 | } | ||
424 | dbg("elp=%s\n", gf_poly_str(elp)); | ||
425 | return (elp->deg > t) ? -1 : (int)elp->deg; | ||
426 | } | ||
427 | |||
428 | /* | ||
429 | * solve a m x m linear system in GF(2) with an expected number of solutions, | ||
430 | * and return the number of found solutions | ||
431 | */ | ||
432 | static int solve_linear_system(struct bch_control *bch, unsigned int *rows, | ||
433 | unsigned int *sol, int nsol) | ||
434 | { | ||
435 | const int m = GF_M(bch); | ||
436 | unsigned int tmp, mask; | ||
437 | int rem, c, r, p, k, param[m]; | ||
438 | |||
439 | k = 0; | ||
440 | mask = 1 << m; | ||
441 | |||
442 | /* Gaussian elimination */ | ||
443 | for (c = 0; c < m; c++) { | ||
444 | rem = 0; | ||
445 | p = c-k; | ||
446 | /* find suitable row for elimination */ | ||
447 | for (r = p; r < m; r++) { | ||
448 | if (rows[r] & mask) { | ||
449 | if (r != p) { | ||
450 | tmp = rows[r]; | ||
451 | rows[r] = rows[p]; | ||
452 | rows[p] = tmp; | ||
453 | } | ||
454 | rem = r+1; | ||
455 | break; | ||
456 | } | ||
457 | } | ||
458 | if (rem) { | ||
459 | /* perform elimination on remaining rows */ | ||
460 | tmp = rows[p]; | ||
461 | for (r = rem; r < m; r++) { | ||
462 | if (rows[r] & mask) | ||
463 | rows[r] ^= tmp; | ||
464 | } | ||
465 | } else { | ||
466 | /* elimination not needed, store defective row index */ | ||
467 | param[k++] = c; | ||
468 | } | ||
469 | mask >>= 1; | ||
470 | } | ||
471 | /* rewrite system, inserting fake parameter rows */ | ||
472 | if (k > 0) { | ||
473 | p = k; | ||
474 | for (r = m-1; r >= 0; r--) { | ||
475 | if ((r > m-1-k) && rows[r]) | ||
476 | /* system has no solution */ | ||
477 | return 0; | ||
478 | |||
479 | rows[r] = (p && (r == param[p-1])) ? | ||
480 | p--, 1u << (m-r) : rows[r-p]; | ||
481 | } | ||
482 | } | ||
483 | |||
484 | if (nsol != (1 << k)) | ||
485 | /* unexpected number of solutions */ | ||
486 | return 0; | ||
487 | |||
488 | for (p = 0; p < nsol; p++) { | ||
489 | /* set parameters for p-th solution */ | ||
490 | for (c = 0; c < k; c++) | ||
491 | rows[param[c]] = (rows[param[c]] & ~1)|((p >> c) & 1); | ||
492 | |||
493 | /* compute unique solution */ | ||
494 | tmp = 0; | ||
495 | for (r = m-1; r >= 0; r--) { | ||
496 | mask = rows[r] & (tmp|1); | ||
497 | tmp |= parity(mask) << (m-r); | ||
498 | } | ||
499 | sol[p] = tmp >> 1; | ||
500 | } | ||
501 | return nsol; | ||
502 | } | ||
503 | |||
504 | /* | ||
505 | * this function builds and solves a linear system for finding roots of a degree | ||
506 | * 4 affine monic polynomial X^4+aX^2+bX+c over GF(2^m). | ||
507 | */ | ||
508 | static int find_affine4_roots(struct bch_control *bch, unsigned int a, | ||
509 | unsigned int b, unsigned int c, | ||
510 | unsigned int *roots) | ||
511 | { | ||
512 | int i, j, k; | ||
513 | const int m = GF_M(bch); | ||
514 | unsigned int mask = 0xff, t, rows[16] = {0,}; | ||
515 | |||
516 | j = a_log(bch, b); | ||
517 | k = a_log(bch, a); | ||
518 | rows[0] = c; | ||
519 | |||
520 | /* buid linear system to solve X^4+aX^2+bX+c = 0 */ | ||
521 | for (i = 0; i < m; i++) { | ||
522 | rows[i+1] = bch->a_pow_tab[4*i]^ | ||
523 | (a ? bch->a_pow_tab[mod_s(bch, k)] : 0)^ | ||
524 | (b ? bch->a_pow_tab[mod_s(bch, j)] : 0); | ||
525 | j++; | ||
526 | k += 2; | ||
527 | } | ||
528 | /* | ||
529 | * transpose 16x16 matrix before passing it to linear solver | ||
530 | * warning: this code assumes m < 16 | ||
531 | */ | ||
532 | for (j = 8; j != 0; j >>= 1, mask ^= (mask << j)) { | ||
533 | for (k = 0; k < 16; k = (k+j+1) & ~j) { | ||
534 | t = ((rows[k] >> j)^rows[k+j]) & mask; | ||
535 | rows[k] ^= (t << j); | ||
536 | rows[k+j] ^= t; | ||
537 | } | ||
538 | } | ||
539 | return solve_linear_system(bch, rows, roots, 4); | ||
540 | } | ||
541 | |||
542 | /* | ||
543 | * compute root r of a degree 1 polynomial over GF(2^m) (returned as log(1/r)) | ||
544 | */ | ||
545 | static int find_poly_deg1_roots(struct bch_control *bch, struct gf_poly *poly, | ||
546 | unsigned int *roots) | ||
547 | { | ||
548 | int n = 0; | ||
549 | |||
550 | if (poly->c[0]) | ||
551 | /* poly[X] = bX+c with c!=0, root=c/b */ | ||
552 | roots[n++] = mod_s(bch, GF_N(bch)-bch->a_log_tab[poly->c[0]]+ | ||
553 | bch->a_log_tab[poly->c[1]]); | ||
554 | return n; | ||
555 | } | ||
556 | |||
557 | /* | ||
558 | * compute roots of a degree 2 polynomial over GF(2^m) | ||
559 | */ | ||
560 | static int find_poly_deg2_roots(struct bch_control *bch, struct gf_poly *poly, | ||
561 | unsigned int *roots) | ||
562 | { | ||
563 | int n = 0, i, l0, l1, l2; | ||
564 | unsigned int u, v, r; | ||
565 | |||
566 | if (poly->c[0] && poly->c[1]) { | ||
567 | |||
568 | l0 = bch->a_log_tab[poly->c[0]]; | ||
569 | l1 = bch->a_log_tab[poly->c[1]]; | ||
570 | l2 = bch->a_log_tab[poly->c[2]]; | ||
571 | |||
572 | /* using z=a/bX, transform aX^2+bX+c into z^2+z+u (u=ac/b^2) */ | ||
573 | u = a_pow(bch, l0+l2+2*(GF_N(bch)-l1)); | ||
574 | /* | ||
575 | * let u = sum(li.a^i) i=0..m-1; then compute r = sum(li.xi): | ||
576 | * r^2+r = sum(li.(xi^2+xi)) = sum(li.(a^i+Tr(a^i).a^k)) = | ||
577 | * u + sum(li.Tr(a^i).a^k) = u+a^k.Tr(sum(li.a^i)) = u+a^k.Tr(u) | ||
578 | * i.e. r and r+1 are roots iff Tr(u)=0 | ||
579 | */ | ||
580 | r = 0; | ||
581 | v = u; | ||
582 | while (v) { | ||
583 | i = deg(v); | ||
584 | r ^= bch->xi_tab[i]; | ||
585 | v ^= (1 << i); | ||
586 | } | ||
587 | /* verify root */ | ||
588 | if ((gf_sqr(bch, r)^r) == u) { | ||
589 | /* reverse z=a/bX transformation and compute log(1/r) */ | ||
590 | roots[n++] = modulo(bch, 2*GF_N(bch)-l1- | ||
591 | bch->a_log_tab[r]+l2); | ||
592 | roots[n++] = modulo(bch, 2*GF_N(bch)-l1- | ||
593 | bch->a_log_tab[r^1]+l2); | ||
594 | } | ||
595 | } | ||
596 | return n; | ||
597 | } | ||
598 | |||
599 | /* | ||
600 | * compute roots of a degree 3 polynomial over GF(2^m) | ||
601 | */ | ||
602 | static int find_poly_deg3_roots(struct bch_control *bch, struct gf_poly *poly, | ||
603 | unsigned int *roots) | ||
604 | { | ||
605 | int i, n = 0; | ||
606 | unsigned int a, b, c, a2, b2, c2, e3, tmp[4]; | ||
607 | |||
608 | if (poly->c[0]) { | ||
609 | /* transform polynomial into monic X^3 + a2X^2 + b2X + c2 */ | ||
610 | e3 = poly->c[3]; | ||
611 | c2 = gf_div(bch, poly->c[0], e3); | ||
612 | b2 = gf_div(bch, poly->c[1], e3); | ||
613 | a2 = gf_div(bch, poly->c[2], e3); | ||
614 | |||
615 | /* (X+a2)(X^3+a2X^2+b2X+c2) = X^4+aX^2+bX+c (affine) */ | ||
616 | c = gf_mul(bch, a2, c2); /* c = a2c2 */ | ||
617 | b = gf_mul(bch, a2, b2)^c2; /* b = a2b2 + c2 */ | ||
618 | a = gf_sqr(bch, a2)^b2; /* a = a2^2 + b2 */ | ||
619 | |||
620 | /* find the 4 roots of this affine polynomial */ | ||
621 | if (find_affine4_roots(bch, a, b, c, tmp) == 4) { | ||
622 | /* remove a2 from final list of roots */ | ||
623 | for (i = 0; i < 4; i++) { | ||
624 | if (tmp[i] != a2) | ||
625 | roots[n++] = a_ilog(bch, tmp[i]); | ||
626 | } | ||
627 | } | ||
628 | } | ||
629 | return n; | ||
630 | } | ||
631 | |||
632 | /* | ||
633 | * compute roots of a degree 4 polynomial over GF(2^m) | ||
634 | */ | ||
635 | static int find_poly_deg4_roots(struct bch_control *bch, struct gf_poly *poly, | ||
636 | unsigned int *roots) | ||
637 | { | ||
638 | int i, l, n = 0; | ||
639 | unsigned int a, b, c, d, e = 0, f, a2, b2, c2, e4; | ||
640 | |||
641 | if (poly->c[0] == 0) | ||
642 | return 0; | ||
643 | |||
644 | /* transform polynomial into monic X^4 + aX^3 + bX^2 + cX + d */ | ||
645 | e4 = poly->c[4]; | ||
646 | d = gf_div(bch, poly->c[0], e4); | ||
647 | c = gf_div(bch, poly->c[1], e4); | ||
648 | b = gf_div(bch, poly->c[2], e4); | ||
649 | a = gf_div(bch, poly->c[3], e4); | ||
650 | |||
651 | /* use Y=1/X transformation to get an affine polynomial */ | ||
652 | if (a) { | ||
653 | /* first, eliminate cX by using z=X+e with ae^2+c=0 */ | ||
654 | if (c) { | ||
655 | /* compute e such that e^2 = c/a */ | ||
656 | f = gf_div(bch, c, a); | ||
657 | l = a_log(bch, f); | ||
658 | l += (l & 1) ? GF_N(bch) : 0; | ||
659 | e = a_pow(bch, l/2); | ||
660 | /* | ||
661 | * use transformation z=X+e: | ||
662 | * z^4+e^4 + a(z^3+ez^2+e^2z+e^3) + b(z^2+e^2) +cz+ce+d | ||
663 | * z^4 + az^3 + (ae+b)z^2 + (ae^2+c)z+e^4+be^2+ae^3+ce+d | ||
664 | * z^4 + az^3 + (ae+b)z^2 + e^4+be^2+d | ||
665 | * z^4 + az^3 + b'z^2 + d' | ||
666 | */ | ||
667 | d = a_pow(bch, 2*l)^gf_mul(bch, b, f)^d; | ||
668 | b = gf_mul(bch, a, e)^b; | ||
669 | } | ||
670 | /* now, use Y=1/X to get Y^4 + b/dY^2 + a/dY + 1/d */ | ||
671 | if (d == 0) | ||
672 | /* assume all roots have multiplicity 1 */ | ||
673 | return 0; | ||
674 | |||
675 | c2 = gf_inv(bch, d); | ||
676 | b2 = gf_div(bch, a, d); | ||
677 | a2 = gf_div(bch, b, d); | ||
678 | } else { | ||
679 | /* polynomial is already affine */ | ||
680 | c2 = d; | ||
681 | b2 = c; | ||
682 | a2 = b; | ||
683 | } | ||
684 | /* find the 4 roots of this affine polynomial */ | ||
685 | if (find_affine4_roots(bch, a2, b2, c2, roots) == 4) { | ||
686 | for (i = 0; i < 4; i++) { | ||
687 | /* post-process roots (reverse transformations) */ | ||
688 | f = a ? gf_inv(bch, roots[i]) : roots[i]; | ||
689 | roots[i] = a_ilog(bch, f^e); | ||
690 | } | ||
691 | n = 4; | ||
692 | } | ||
693 | return n; | ||
694 | } | ||
695 | |||
696 | /* | ||
697 | * build monic, log-based representation of a polynomial | ||
698 | */ | ||
699 | static void gf_poly_logrep(struct bch_control *bch, | ||
700 | const struct gf_poly *a, int *rep) | ||
701 | { | ||
702 | int i, d = a->deg, l = GF_N(bch)-a_log(bch, a->c[a->deg]); | ||
703 | |||
704 | /* represent 0 values with -1; warning, rep[d] is not set to 1 */ | ||
705 | for (i = 0; i < d; i++) | ||
706 | rep[i] = a->c[i] ? mod_s(bch, a_log(bch, a->c[i])+l) : -1; | ||
707 | } | ||
708 | |||
709 | /* | ||
710 | * compute polynomial Euclidean division remainder in GF(2^m)[X] | ||
711 | */ | ||
712 | static void gf_poly_mod(struct bch_control *bch, struct gf_poly *a, | ||
713 | const struct gf_poly *b, int *rep) | ||
714 | { | ||
715 | int la, p, m; | ||
716 | unsigned int i, j, *c = a->c; | ||
717 | const unsigned int d = b->deg; | ||
718 | |||
719 | if (a->deg < d) | ||
720 | return; | ||
721 | |||
722 | /* reuse or compute log representation of denominator */ | ||
723 | if (!rep) { | ||
724 | rep = bch->cache; | ||
725 | gf_poly_logrep(bch, b, rep); | ||
726 | } | ||
727 | |||
728 | for (j = a->deg; j >= d; j--) { | ||
729 | if (c[j]) { | ||
730 | la = a_log(bch, c[j]); | ||
731 | p = j-d; | ||
732 | for (i = 0; i < d; i++, p++) { | ||
733 | m = rep[i]; | ||
734 | if (m >= 0) | ||
735 | c[p] ^= bch->a_pow_tab[mod_s(bch, | ||
736 | m+la)]; | ||
737 | } | ||
738 | } | ||
739 | } | ||
740 | a->deg = d-1; | ||
741 | while (!c[a->deg] && a->deg) | ||
742 | a->deg--; | ||
743 | } | ||
744 | |||
745 | /* | ||
746 | * compute polynomial Euclidean division quotient in GF(2^m)[X] | ||
747 | */ | ||
748 | static void gf_poly_div(struct bch_control *bch, struct gf_poly *a, | ||
749 | const struct gf_poly *b, struct gf_poly *q) | ||
750 | { | ||
751 | if (a->deg >= b->deg) { | ||
752 | q->deg = a->deg-b->deg; | ||
753 | /* compute a mod b (modifies a) */ | ||
754 | gf_poly_mod(bch, a, b, NULL); | ||
755 | /* quotient is stored in upper part of polynomial a */ | ||
756 | memcpy(q->c, &a->c[b->deg], (1+q->deg)*sizeof(unsigned int)); | ||
757 | } else { | ||
758 | q->deg = 0; | ||
759 | q->c[0] = 0; | ||
760 | } | ||
761 | } | ||
762 | |||
763 | /* | ||
764 | * compute polynomial GCD (Greatest Common Divisor) in GF(2^m)[X] | ||
765 | */ | ||
766 | static struct gf_poly *gf_poly_gcd(struct bch_control *bch, struct gf_poly *a, | ||
767 | struct gf_poly *b) | ||
768 | { | ||
769 | struct gf_poly *tmp; | ||
770 | |||
771 | dbg("gcd(%s,%s)=", gf_poly_str(a), gf_poly_str(b)); | ||
772 | |||
773 | if (a->deg < b->deg) { | ||
774 | tmp = b; | ||
775 | b = a; | ||
776 | a = tmp; | ||
777 | } | ||
778 | |||
779 | while (b->deg > 0) { | ||
780 | gf_poly_mod(bch, a, b, NULL); | ||
781 | tmp = b; | ||
782 | b = a; | ||
783 | a = tmp; | ||
784 | } | ||
785 | |||
786 | dbg("%s\n", gf_poly_str(a)); | ||
787 | |||
788 | return a; | ||
789 | } | ||
790 | |||
791 | /* | ||
792 | * Given a polynomial f and an integer k, compute Tr(a^kX) mod f | ||
793 | * This is used in Berlekamp Trace algorithm for splitting polynomials | ||
794 | */ | ||
795 | static void compute_trace_bk_mod(struct bch_control *bch, int k, | ||
796 | const struct gf_poly *f, struct gf_poly *z, | ||
797 | struct gf_poly *out) | ||
798 | { | ||
799 | const int m = GF_M(bch); | ||
800 | int i, j; | ||
801 | |||
802 | /* z contains z^2j mod f */ | ||
803 | z->deg = 1; | ||
804 | z->c[0] = 0; | ||
805 | z->c[1] = bch->a_pow_tab[k]; | ||
806 | |||
807 | out->deg = 0; | ||
808 | memset(out, 0, GF_POLY_SZ(f->deg)); | ||
809 | |||
810 | /* compute f log representation only once */ | ||
811 | gf_poly_logrep(bch, f, bch->cache); | ||
812 | |||
813 | for (i = 0; i < m; i++) { | ||
814 | /* add a^(k*2^i)(z^(2^i) mod f) and compute (z^(2^i) mod f)^2 */ | ||
815 | for (j = z->deg; j >= 0; j--) { | ||
816 | out->c[j] ^= z->c[j]; | ||
817 | z->c[2*j] = gf_sqr(bch, z->c[j]); | ||
818 | z->c[2*j+1] = 0; | ||
819 | } | ||
820 | if (z->deg > out->deg) | ||
821 | out->deg = z->deg; | ||
822 | |||
823 | if (i < m-1) { | ||
824 | z->deg *= 2; | ||
825 | /* z^(2(i+1)) mod f = (z^(2^i) mod f)^2 mod f */ | ||
826 | gf_poly_mod(bch, z, f, bch->cache); | ||
827 | } | ||
828 | } | ||
829 | while (!out->c[out->deg] && out->deg) | ||
830 | out->deg--; | ||
831 | |||
832 | dbg("Tr(a^%d.X) mod f = %s\n", k, gf_poly_str(out)); | ||
833 | } | ||
834 | |||
835 | /* | ||
836 | * factor a polynomial using Berlekamp Trace algorithm (BTA) | ||
837 | */ | ||
838 | static void factor_polynomial(struct bch_control *bch, int k, struct gf_poly *f, | ||
839 | struct gf_poly **g, struct gf_poly **h) | ||
840 | { | ||
841 | struct gf_poly *f2 = bch->poly_2t[0]; | ||
842 | struct gf_poly *q = bch->poly_2t[1]; | ||
843 | struct gf_poly *tk = bch->poly_2t[2]; | ||
844 | struct gf_poly *z = bch->poly_2t[3]; | ||
845 | struct gf_poly *gcd; | ||
846 | |||
847 | dbg("factoring %s...\n", gf_poly_str(f)); | ||
848 | |||
849 | *g = f; | ||
850 | *h = NULL; | ||
851 | |||
852 | /* tk = Tr(a^k.X) mod f */ | ||
853 | compute_trace_bk_mod(bch, k, f, z, tk); | ||
854 | |||
855 | if (tk->deg > 0) { | ||
856 | /* compute g = gcd(f, tk) (destructive operation) */ | ||
857 | gf_poly_copy(f2, f); | ||
858 | gcd = gf_poly_gcd(bch, f2, tk); | ||
859 | if (gcd->deg < f->deg) { | ||
860 | /* compute h=f/gcd(f,tk); this will modify f and q */ | ||
861 | gf_poly_div(bch, f, gcd, q); | ||
862 | /* store g and h in-place (clobbering f) */ | ||
863 | *h = &((struct gf_poly_deg1 *)f)[gcd->deg].poly; | ||
864 | gf_poly_copy(*g, gcd); | ||
865 | gf_poly_copy(*h, q); | ||
866 | } | ||
867 | } | ||
868 | } | ||
869 | |||
870 | /* | ||
871 | * find roots of a polynomial, using BTZ algorithm; see the beginning of this | ||
872 | * file for details | ||
873 | */ | ||
874 | static int find_poly_roots(struct bch_control *bch, unsigned int k, | ||
875 | struct gf_poly *poly, unsigned int *roots) | ||
876 | { | ||
877 | int cnt; | ||
878 | struct gf_poly *f1, *f2; | ||
879 | |||
880 | switch (poly->deg) { | ||
881 | /* handle low degree polynomials with ad hoc techniques */ | ||
882 | case 1: | ||
883 | cnt = find_poly_deg1_roots(bch, poly, roots); | ||
884 | break; | ||
885 | case 2: | ||
886 | cnt = find_poly_deg2_roots(bch, poly, roots); | ||
887 | break; | ||
888 | case 3: | ||
889 | cnt = find_poly_deg3_roots(bch, poly, roots); | ||
890 | break; | ||
891 | case 4: | ||
892 | cnt = find_poly_deg4_roots(bch, poly, roots); | ||
893 | break; | ||
894 | default: | ||
895 | /* factor polynomial using Berlekamp Trace Algorithm (BTA) */ | ||
896 | cnt = 0; | ||
897 | if (poly->deg && (k <= GF_M(bch))) { | ||
898 | factor_polynomial(bch, k, poly, &f1, &f2); | ||
899 | if (f1) | ||
900 | cnt += find_poly_roots(bch, k+1, f1, roots); | ||
901 | if (f2) | ||
902 | cnt += find_poly_roots(bch, k+1, f2, roots+cnt); | ||
903 | } | ||
904 | break; | ||
905 | } | ||
906 | return cnt; | ||
907 | } | ||
908 | |||
909 | #if defined(USE_CHIEN_SEARCH) | ||
910 | /* | ||
911 | * exhaustive root search (Chien) implementation - not used, included only for | ||
912 | * reference/comparison tests | ||
913 | */ | ||
914 | static int chien_search(struct bch_control *bch, unsigned int len, | ||
915 | struct gf_poly *p, unsigned int *roots) | ||
916 | { | ||
917 | int m; | ||
918 | unsigned int i, j, syn, syn0, count = 0; | ||
919 | const unsigned int k = 8*len+bch->ecc_bits; | ||
920 | |||
921 | /* use a log-based representation of polynomial */ | ||
922 | gf_poly_logrep(bch, p, bch->cache); | ||
923 | bch->cache[p->deg] = 0; | ||
924 | syn0 = gf_div(bch, p->c[0], p->c[p->deg]); | ||
925 | |||
926 | for (i = GF_N(bch)-k+1; i <= GF_N(bch); i++) { | ||
927 | /* compute elp(a^i) */ | ||
928 | for (j = 1, syn = syn0; j <= p->deg; j++) { | ||
929 | m = bch->cache[j]; | ||
930 | if (m >= 0) | ||
931 | syn ^= a_pow(bch, m+j*i); | ||
932 | } | ||
933 | if (syn == 0) { | ||
934 | roots[count++] = GF_N(bch)-i; | ||
935 | if (count == p->deg) | ||
936 | break; | ||
937 | } | ||
938 | } | ||
939 | return (count == p->deg) ? count : 0; | ||
940 | } | ||
941 | #define find_poly_roots(_p, _k, _elp, _loc) chien_search(_p, len, _elp, _loc) | ||
942 | #endif /* USE_CHIEN_SEARCH */ | ||
943 | |||
944 | /** | ||
945 | * decode_bch - decode received codeword and find bit error locations | ||
946 | * @bch: BCH control structure | ||
947 | * @data: received data, ignored if @calc_ecc is provided | ||
948 | * @len: data length in bytes, must always be provided | ||
949 | * @recv_ecc: received ecc, if NULL then assume it was XORed in @calc_ecc | ||
950 | * @calc_ecc: calculated ecc, if NULL then calc_ecc is computed from @data | ||
951 | * @syn: hw computed syndrome data (if NULL, syndrome is calculated) | ||
952 | * @errloc: output array of error locations | ||
953 | * | ||
954 | * Returns: | ||
955 | * The number of errors found, or -EBADMSG if decoding failed, or -EINVAL if | ||
956 | * invalid parameters were provided | ||
957 | * | ||
958 | * Depending on the available hw BCH support and the need to compute @calc_ecc | ||
959 | * separately (using encode_bch()), this function should be called with one of | ||
960 | * the following parameter configurations - | ||
961 | * | ||
962 | * by providing @data and @recv_ecc only: | ||
963 | * decode_bch(@bch, @data, @len, @recv_ecc, NULL, NULL, @errloc) | ||
964 | * | ||
965 | * by providing @recv_ecc and @calc_ecc: | ||
966 | * decode_bch(@bch, NULL, @len, @recv_ecc, @calc_ecc, NULL, @errloc) | ||
967 | * | ||
968 | * by providing ecc = recv_ecc XOR calc_ecc: | ||
969 | * decode_bch(@bch, NULL, @len, NULL, ecc, NULL, @errloc) | ||
970 | * | ||
971 | * by providing syndrome results @syn: | ||
972 | * decode_bch(@bch, NULL, @len, NULL, NULL, @syn, @errloc) | ||
973 | * | ||
974 | * Once decode_bch() has successfully returned with a positive value, error | ||
975 | * locations returned in array @errloc should be interpreted as follows - | ||
976 | * | ||
977 | * if (errloc[n] >= 8*len), then n-th error is located in ecc (no need for | ||
978 | * data correction) | ||
979 | * | ||
980 | * if (errloc[n] < 8*len), then n-th error is located in data and can be | ||
981 | * corrected with statement data[errloc[n]/8] ^= 1 << (errloc[n] % 8); | ||
982 | * | ||
983 | * Note that this function does not perform any data correction by itself, it | ||
984 | * merely indicates error locations. | ||
985 | */ | ||
986 | int decode_bch(struct bch_control *bch, const uint8_t *data, unsigned int len, | ||
987 | const uint8_t *recv_ecc, const uint8_t *calc_ecc, | ||
988 | const unsigned int *syn, unsigned int *errloc) | ||
989 | { | ||
990 | const unsigned int ecc_words = BCH_ECC_WORDS(bch); | ||
991 | unsigned int nbits; | ||
992 | int i, err, nroots; | ||
993 | uint32_t sum; | ||
994 | |||
995 | /* sanity check: make sure data length can be handled */ | ||
996 | if (8*len > (bch->n-bch->ecc_bits)) | ||
997 | return -EINVAL; | ||
998 | |||
999 | /* if caller does not provide syndromes, compute them */ | ||
1000 | if (!syn) { | ||
1001 | if (!calc_ecc) { | ||
1002 | /* compute received data ecc into an internal buffer */ | ||
1003 | if (!data || !recv_ecc) | ||
1004 | return -EINVAL; | ||
1005 | encode_bch(bch, data, len, NULL); | ||
1006 | } else { | ||
1007 | /* load provided calculated ecc */ | ||
1008 | load_ecc8(bch, bch->ecc_buf, calc_ecc); | ||
1009 | } | ||
1010 | /* load received ecc or assume it was XORed in calc_ecc */ | ||
1011 | if (recv_ecc) { | ||
1012 | load_ecc8(bch, bch->ecc_buf2, recv_ecc); | ||
1013 | /* XOR received and calculated ecc */ | ||
1014 | for (i = 0, sum = 0; i < (int)ecc_words; i++) { | ||
1015 | bch->ecc_buf[i] ^= bch->ecc_buf2[i]; | ||
1016 | sum |= bch->ecc_buf[i]; | ||
1017 | } | ||
1018 | if (!sum) | ||
1019 | /* no error found */ | ||
1020 | return 0; | ||
1021 | } | ||
1022 | compute_syndromes(bch, bch->ecc_buf, bch->syn); | ||
1023 | syn = bch->syn; | ||
1024 | } | ||
1025 | |||
1026 | err = compute_error_locator_polynomial(bch, syn); | ||
1027 | if (err > 0) { | ||
1028 | nroots = find_poly_roots(bch, 1, bch->elp, errloc); | ||
1029 | if (err != nroots) | ||
1030 | err = -1; | ||
1031 | } | ||
1032 | if (err > 0) { | ||
1033 | /* post-process raw error locations for easier correction */ | ||
1034 | nbits = (len*8)+bch->ecc_bits; | ||
1035 | for (i = 0; i < err; i++) { | ||
1036 | if (errloc[i] >= nbits) { | ||
1037 | err = -1; | ||
1038 | break; | ||
1039 | } | ||
1040 | errloc[i] = nbits-1-errloc[i]; | ||
1041 | errloc[i] = (errloc[i] & ~7)|(7-(errloc[i] & 7)); | ||
1042 | } | ||
1043 | } | ||
1044 | return (err >= 0) ? err : -EBADMSG; | ||
1045 | } | ||
1046 | EXPORT_SYMBOL_GPL(decode_bch); | ||
1047 | |||
1048 | /* | ||
1049 | * generate Galois field lookup tables | ||
1050 | */ | ||
1051 | static int build_gf_tables(struct bch_control *bch, unsigned int poly) | ||
1052 | { | ||
1053 | unsigned int i, x = 1; | ||
1054 | const unsigned int k = 1 << deg(poly); | ||
1055 | |||
1056 | /* primitive polynomial must be of degree m */ | ||
1057 | if (k != (1u << GF_M(bch))) | ||
1058 | return -1; | ||
1059 | |||
1060 | for (i = 0; i < GF_N(bch); i++) { | ||
1061 | bch->a_pow_tab[i] = x; | ||
1062 | bch->a_log_tab[x] = i; | ||
1063 | if (i && (x == 1)) | ||
1064 | /* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */ | ||
1065 | return -1; | ||
1066 | x <<= 1; | ||
1067 | if (x & k) | ||
1068 | x ^= poly; | ||
1069 | } | ||
1070 | bch->a_pow_tab[GF_N(bch)] = 1; | ||
1071 | bch->a_log_tab[0] = 0; | ||
1072 | |||
1073 | return 0; | ||
1074 | } | ||
1075 | |||
1076 | /* | ||
1077 | * compute generator polynomial remainder tables for fast encoding | ||
1078 | */ | ||
1079 | static void build_mod8_tables(struct bch_control *bch, const uint32_t *g) | ||
1080 | { | ||
1081 | int i, j, b, d; | ||
1082 | uint32_t data, hi, lo, *tab; | ||
1083 | const int l = BCH_ECC_WORDS(bch); | ||
1084 | const int plen = DIV_ROUND_UP(bch->ecc_bits+1, 32); | ||
1085 | const int ecclen = DIV_ROUND_UP(bch->ecc_bits, 32); | ||
1086 | |||
1087 | memset(bch->mod8_tab, 0, 4*256*l*sizeof(*bch->mod8_tab)); | ||
1088 | |||
1089 | for (i = 0; i < 256; i++) { | ||
1090 | /* p(X)=i is a small polynomial of weight <= 8 */ | ||
1091 | for (b = 0; b < 4; b++) { | ||
1092 | /* we want to compute (p(X).X^(8*b+deg(g))) mod g(X) */ | ||
1093 | tab = bch->mod8_tab + (b*256+i)*l; | ||
1094 | data = i << (8*b); | ||
1095 | while (data) { | ||
1096 | d = deg(data); | ||
1097 | /* subtract X^d.g(X) from p(X).X^(8*b+deg(g)) */ | ||
1098 | data ^= g[0] >> (31-d); | ||
1099 | for (j = 0; j < ecclen; j++) { | ||
1100 | hi = (d < 31) ? g[j] << (d+1) : 0; | ||
1101 | lo = (j+1 < plen) ? | ||
1102 | g[j+1] >> (31-d) : 0; | ||
1103 | tab[j] ^= hi|lo; | ||
1104 | } | ||
1105 | } | ||
1106 | } | ||
1107 | } | ||
1108 | } | ||
1109 | |||
1110 | /* | ||
1111 | * build a base for factoring degree 2 polynomials | ||
1112 | */ | ||
1113 | static int build_deg2_base(struct bch_control *bch) | ||
1114 | { | ||
1115 | const int m = GF_M(bch); | ||
1116 | int i, j, r; | ||
1117 | unsigned int sum, x, y, remaining, ak = 0, xi[m]; | ||
1118 | |||
1119 | /* find k s.t. Tr(a^k) = 1 and 0 <= k < m */ | ||
1120 | for (i = 0; i < m; i++) { | ||
1121 | for (j = 0, sum = 0; j < m; j++) | ||
1122 | sum ^= a_pow(bch, i*(1 << j)); | ||
1123 | |||
1124 | if (sum) { | ||
1125 | ak = bch->a_pow_tab[i]; | ||
1126 | break; | ||
1127 | } | ||
1128 | } | ||
1129 | /* find xi, i=0..m-1 such that xi^2+xi = a^i+Tr(a^i).a^k */ | ||
1130 | remaining = m; | ||
1131 | memset(xi, 0, sizeof(xi)); | ||
1132 | |||
1133 | for (x = 0; (x <= GF_N(bch)) && remaining; x++) { | ||
1134 | y = gf_sqr(bch, x)^x; | ||
1135 | for (i = 0; i < 2; i++) { | ||
1136 | r = a_log(bch, y); | ||
1137 | if (y && (r < m) && !xi[r]) { | ||
1138 | bch->xi_tab[r] = x; | ||
1139 | xi[r] = 1; | ||
1140 | remaining--; | ||
1141 | dbg("x%d = %x\n", r, x); | ||
1142 | break; | ||
1143 | } | ||
1144 | y ^= ak; | ||
1145 | } | ||
1146 | } | ||
1147 | /* should not happen but check anyway */ | ||
1148 | return remaining ? -1 : 0; | ||
1149 | } | ||
1150 | |||
1151 | static void *bch_alloc(size_t size, int *err) | ||
1152 | { | ||
1153 | void *ptr; | ||
1154 | |||
1155 | ptr = kmalloc(size, GFP_KERNEL); | ||
1156 | if (ptr == NULL) | ||
1157 | *err = 1; | ||
1158 | return ptr; | ||
1159 | } | ||
1160 | |||
1161 | /* | ||
1162 | * compute generator polynomial for given (m,t) parameters. | ||
1163 | */ | ||
1164 | static uint32_t *compute_generator_polynomial(struct bch_control *bch) | ||
1165 | { | ||
1166 | const unsigned int m = GF_M(bch); | ||
1167 | const unsigned int t = GF_T(bch); | ||
1168 | int n, err = 0; | ||
1169 | unsigned int i, j, nbits, r, word, *roots; | ||
1170 | struct gf_poly *g; | ||
1171 | uint32_t *genpoly; | ||
1172 | |||
1173 | g = bch_alloc(GF_POLY_SZ(m*t), &err); | ||
1174 | roots = bch_alloc((bch->n+1)*sizeof(*roots), &err); | ||
1175 | genpoly = bch_alloc(DIV_ROUND_UP(m*t+1, 32)*sizeof(*genpoly), &err); | ||
1176 | |||
1177 | if (err) { | ||
1178 | kfree(genpoly); | ||
1179 | genpoly = NULL; | ||
1180 | goto finish; | ||
1181 | } | ||
1182 | |||
1183 | /* enumerate all roots of g(X) */ | ||
1184 | memset(roots , 0, (bch->n+1)*sizeof(*roots)); | ||
1185 | for (i = 0; i < t; i++) { | ||
1186 | for (j = 0, r = 2*i+1; j < m; j++) { | ||
1187 | roots[r] = 1; | ||
1188 | r = mod_s(bch, 2*r); | ||
1189 | } | ||
1190 | } | ||
1191 | /* build generator polynomial g(X) */ | ||
1192 | g->deg = 0; | ||
1193 | g->c[0] = 1; | ||
1194 | for (i = 0; i < GF_N(bch); i++) { | ||
1195 | if (roots[i]) { | ||
1196 | /* multiply g(X) by (X+root) */ | ||
1197 | r = bch->a_pow_tab[i]; | ||
1198 | g->c[g->deg+1] = 1; | ||
1199 | for (j = g->deg; j > 0; j--) | ||
1200 | g->c[j] = gf_mul(bch, g->c[j], r)^g->c[j-1]; | ||
1201 | |||
1202 | g->c[0] = gf_mul(bch, g->c[0], r); | ||
1203 | g->deg++; | ||
1204 | } | ||
1205 | } | ||
1206 | /* store left-justified binary representation of g(X) */ | ||
1207 | n = g->deg+1; | ||
1208 | i = 0; | ||
1209 | |||
1210 | while (n > 0) { | ||
1211 | nbits = (n > 32) ? 32 : n; | ||
1212 | for (j = 0, word = 0; j < nbits; j++) { | ||
1213 | if (g->c[n-1-j]) | ||
1214 | word |= 1u << (31-j); | ||
1215 | } | ||
1216 | genpoly[i++] = word; | ||
1217 | n -= nbits; | ||
1218 | } | ||
1219 | bch->ecc_bits = g->deg; | ||
1220 | |||
1221 | finish: | ||
1222 | kfree(g); | ||
1223 | kfree(roots); | ||
1224 | |||
1225 | return genpoly; | ||
1226 | } | ||
1227 | |||
1228 | /** | ||
1229 | * init_bch - initialize a BCH encoder/decoder | ||
1230 | * @m: Galois field order, should be in the range 5-15 | ||
1231 | * @t: maximum error correction capability, in bits | ||
1232 | * @prim_poly: user-provided primitive polynomial (or 0 to use default) | ||
1233 | * | ||
1234 | * Returns: | ||
1235 | * a newly allocated BCH control structure if successful, NULL otherwise | ||
1236 | * | ||
1237 | * This initialization can take some time, as lookup tables are built for fast | ||
1238 | * encoding/decoding; make sure not to call this function from a time critical | ||
1239 | * path. Usually, init_bch() should be called on module/driver init and | ||
1240 | * free_bch() should be called to release memory on exit. | ||
1241 | * | ||
1242 | * You may provide your own primitive polynomial of degree @m in argument | ||
1243 | * @prim_poly, or let init_bch() use its default polynomial. | ||
1244 | * | ||
1245 | * Once init_bch() has successfully returned a pointer to a newly allocated | ||
1246 | * BCH control structure, ecc length in bytes is given by member @ecc_bytes of | ||
1247 | * the structure. | ||
1248 | */ | ||
1249 | struct bch_control *init_bch(int m, int t, unsigned int prim_poly) | ||
1250 | { | ||
1251 | int err = 0; | ||
1252 | unsigned int i, words; | ||
1253 | uint32_t *genpoly; | ||
1254 | struct bch_control *bch = NULL; | ||
1255 | |||
1256 | const int min_m = 5; | ||
1257 | const int max_m = 15; | ||
1258 | |||
1259 | /* default primitive polynomials */ | ||
1260 | static const unsigned int prim_poly_tab[] = { | ||
1261 | 0x25, 0x43, 0x83, 0x11d, 0x211, 0x409, 0x805, 0x1053, 0x201b, | ||
1262 | 0x402b, 0x8003, | ||
1263 | }; | ||
1264 | |||
1265 | #if defined(CONFIG_BCH_CONST_PARAMS) | ||
1266 | if ((m != (CONFIG_BCH_CONST_M)) || (t != (CONFIG_BCH_CONST_T))) { | ||
1267 | printk(KERN_ERR "bch encoder/decoder was configured to support " | ||
1268 | "parameters m=%d, t=%d only!\n", | ||
1269 | CONFIG_BCH_CONST_M, CONFIG_BCH_CONST_T); | ||
1270 | goto fail; | ||
1271 | } | ||
1272 | #endif | ||
1273 | if ((m < min_m) || (m > max_m)) | ||
1274 | /* | ||
1275 | * values of m greater than 15 are not currently supported; | ||
1276 | * supporting m > 15 would require changing table base type | ||
1277 | * (uint16_t) and a small patch in matrix transposition | ||
1278 | */ | ||
1279 | goto fail; | ||
1280 | |||
1281 | /* sanity checks */ | ||
1282 | if ((t < 1) || (m*t >= ((1 << m)-1))) | ||
1283 | /* invalid t value */ | ||
1284 | goto fail; | ||
1285 | |||
1286 | /* select a primitive polynomial for generating GF(2^m) */ | ||
1287 | if (prim_poly == 0) | ||
1288 | prim_poly = prim_poly_tab[m-min_m]; | ||
1289 | |||
1290 | bch = kzalloc(sizeof(*bch), GFP_KERNEL); | ||
1291 | if (bch == NULL) | ||
1292 | goto fail; | ||
1293 | |||
1294 | bch->m = m; | ||
1295 | bch->t = t; | ||
1296 | bch->n = (1 << m)-1; | ||
1297 | words = DIV_ROUND_UP(m*t, 32); | ||
1298 | bch->ecc_bytes = DIV_ROUND_UP(m*t, 8); | ||
1299 | bch->a_pow_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_pow_tab), &err); | ||
1300 | bch->a_log_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_log_tab), &err); | ||
1301 | bch->mod8_tab = bch_alloc(words*1024*sizeof(*bch->mod8_tab), &err); | ||
1302 | bch->ecc_buf = bch_alloc(words*sizeof(*bch->ecc_buf), &err); | ||
1303 | bch->ecc_buf2 = bch_alloc(words*sizeof(*bch->ecc_buf2), &err); | ||
1304 | bch->xi_tab = bch_alloc(m*sizeof(*bch->xi_tab), &err); | ||
1305 | bch->syn = bch_alloc(2*t*sizeof(*bch->syn), &err); | ||
1306 | bch->cache = bch_alloc(2*t*sizeof(*bch->cache), &err); | ||
1307 | bch->elp = bch_alloc((t+1)*sizeof(struct gf_poly_deg1), &err); | ||
1308 | |||
1309 | for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++) | ||
1310 | bch->poly_2t[i] = bch_alloc(GF_POLY_SZ(2*t), &err); | ||
1311 | |||
1312 | if (err) | ||
1313 | goto fail; | ||
1314 | |||
1315 | err = build_gf_tables(bch, prim_poly); | ||
1316 | if (err) | ||
1317 | goto fail; | ||
1318 | |||
1319 | /* use generator polynomial for computing encoding tables */ | ||
1320 | genpoly = compute_generator_polynomial(bch); | ||
1321 | if (genpoly == NULL) | ||
1322 | goto fail; | ||
1323 | |||
1324 | build_mod8_tables(bch, genpoly); | ||
1325 | kfree(genpoly); | ||
1326 | |||
1327 | err = build_deg2_base(bch); | ||
1328 | if (err) | ||
1329 | goto fail; | ||
1330 | |||
1331 | return bch; | ||
1332 | |||
1333 | fail: | ||
1334 | free_bch(bch); | ||
1335 | return NULL; | ||
1336 | } | ||
1337 | EXPORT_SYMBOL_GPL(init_bch); | ||
1338 | |||
1339 | /** | ||
1340 | * free_bch - free the BCH control structure | ||
1341 | * @bch: BCH control structure to release | ||
1342 | */ | ||
1343 | void free_bch(struct bch_control *bch) | ||
1344 | { | ||
1345 | unsigned int i; | ||
1346 | |||
1347 | if (bch) { | ||
1348 | kfree(bch->a_pow_tab); | ||
1349 | kfree(bch->a_log_tab); | ||
1350 | kfree(bch->mod8_tab); | ||
1351 | kfree(bch->ecc_buf); | ||
1352 | kfree(bch->ecc_buf2); | ||
1353 | kfree(bch->xi_tab); | ||
1354 | kfree(bch->syn); | ||
1355 | kfree(bch->cache); | ||
1356 | kfree(bch->elp); | ||
1357 | |||
1358 | for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++) | ||
1359 | kfree(bch->poly_2t[i]); | ||
1360 | |||
1361 | kfree(bch); | ||
1362 | } | ||
1363 | } | ||
1364 | EXPORT_SYMBOL_GPL(free_bch); | ||
1365 | |||
1366 | MODULE_LICENSE("GPL"); | ||
1367 | MODULE_AUTHOR("Ivan Djelic <ivan.djelic@parrot.com>"); | ||
1368 | MODULE_DESCRIPTION("Binary BCH encoder/decoder"); | ||
diff --git a/lib/show_mem.c b/lib/show_mem.c index d8d602b58c31..90cbe4bb5960 100644 --- a/lib/show_mem.c +++ b/lib/show_mem.c | |||
@@ -9,7 +9,7 @@ | |||
9 | #include <linux/nmi.h> | 9 | #include <linux/nmi.h> |
10 | #include <linux/quicklist.h> | 10 | #include <linux/quicklist.h> |
11 | 11 | ||
12 | void __show_mem(unsigned int filter) | 12 | void show_mem(unsigned int filter) |
13 | { | 13 | { |
14 | pg_data_t *pgdat; | 14 | pg_data_t *pgdat; |
15 | unsigned long total = 0, reserved = 0, shared = 0, | 15 | unsigned long total = 0, reserved = 0, shared = 0, |
@@ -61,8 +61,3 @@ void __show_mem(unsigned int filter) | |||
61 | quicklist_total_size()); | 61 | quicklist_total_size()); |
62 | #endif | 62 | #endif |
63 | } | 63 | } |
64 | |||
65 | void show_mem(void) | ||
66 | { | ||
67 | __show_mem(0); | ||
68 | } | ||
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 02bcdd5feac4..bc0ac6b333dc 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
@@ -433,7 +433,9 @@ char *symbol_string(char *buf, char *end, void *ptr, | |||
433 | unsigned long value = (unsigned long) ptr; | 433 | unsigned long value = (unsigned long) ptr; |
434 | #ifdef CONFIG_KALLSYMS | 434 | #ifdef CONFIG_KALLSYMS |
435 | char sym[KSYM_SYMBOL_LEN]; | 435 | char sym[KSYM_SYMBOL_LEN]; |
436 | if (ext != 'f' && ext != 's') | 436 | if (ext == 'B') |
437 | sprint_backtrace(sym, value); | ||
438 | else if (ext != 'f' && ext != 's') | ||
437 | sprint_symbol(sym, value); | 439 | sprint_symbol(sym, value); |
438 | else | 440 | else |
439 | kallsyms_lookup(value, NULL, NULL, NULL, sym); | 441 | kallsyms_lookup(value, NULL, NULL, NULL, sym); |
@@ -808,6 +810,7 @@ int kptr_restrict = 1; | |||
808 | * - 'f' For simple symbolic function names without offset | 810 | * - 'f' For simple symbolic function names without offset |
809 | * - 'S' For symbolic direct pointers with offset | 811 | * - 'S' For symbolic direct pointers with offset |
810 | * - 's' For symbolic direct pointers without offset | 812 | * - 's' For symbolic direct pointers without offset |
813 | * - 'B' For backtraced symbolic direct pointers with offset | ||
811 | * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref] | 814 | * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref] |
812 | * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201] | 815 | * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201] |
813 | * - 'M' For a 6-byte MAC address, it prints the address in the | 816 | * - 'M' For a 6-byte MAC address, it prints the address in the |
@@ -867,6 +870,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, | |||
867 | /* Fallthrough */ | 870 | /* Fallthrough */ |
868 | case 'S': | 871 | case 'S': |
869 | case 's': | 872 | case 's': |
873 | case 'B': | ||
870 | return symbol_string(buf, end, ptr, spec, *fmt); | 874 | return symbol_string(buf, end, ptr, spec, *fmt); |
871 | case 'R': | 875 | case 'R': |
872 | case 'r': | 876 | case 'r': |
@@ -1134,6 +1138,7 @@ qualifier: | |||
1134 | * %ps output the name of a text symbol without offset | 1138 | * %ps output the name of a text symbol without offset |
1135 | * %pF output the name of a function pointer with its offset | 1139 | * %pF output the name of a function pointer with its offset |
1136 | * %pf output the name of a function pointer without its offset | 1140 | * %pf output the name of a function pointer without its offset |
1141 | * %pB output the name of a backtrace symbol with its offset | ||
1137 | * %pR output the address range in a struct resource with decoded flags | 1142 | * %pR output the address range in a struct resource with decoded flags |
1138 | * %pr output the address range in a struct resource with raw flags | 1143 | * %pr output the address range in a struct resource with raw flags |
1139 | * %pM output a 6-byte MAC address with colons | 1144 | * %pM output a 6-byte MAC address with colons |
diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 8fe9d3407921..0d9a036ada66 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c | |||
@@ -67,14 +67,14 @@ static int bdi_debug_stats_show(struct seq_file *m, void *v) | |||
67 | struct inode *inode; | 67 | struct inode *inode; |
68 | 68 | ||
69 | nr_wb = nr_dirty = nr_io = nr_more_io = 0; | 69 | nr_wb = nr_dirty = nr_io = nr_more_io = 0; |
70 | spin_lock(&inode_lock); | 70 | spin_lock(&inode_wb_list_lock); |
71 | list_for_each_entry(inode, &wb->b_dirty, i_wb_list) | 71 | list_for_each_entry(inode, &wb->b_dirty, i_wb_list) |
72 | nr_dirty++; | 72 | nr_dirty++; |
73 | list_for_each_entry(inode, &wb->b_io, i_wb_list) | 73 | list_for_each_entry(inode, &wb->b_io, i_wb_list) |
74 | nr_io++; | 74 | nr_io++; |
75 | list_for_each_entry(inode, &wb->b_more_io, i_wb_list) | 75 | list_for_each_entry(inode, &wb->b_more_io, i_wb_list) |
76 | nr_more_io++; | 76 | nr_more_io++; |
77 | spin_unlock(&inode_lock); | 77 | spin_unlock(&inode_wb_list_lock); |
78 | 78 | ||
79 | global_dirty_limits(&background_thresh, &dirty_thresh); | 79 | global_dirty_limits(&background_thresh, &dirty_thresh); |
80 | bdi_thresh = bdi_dirty_limit(bdi, dirty_thresh); | 80 | bdi_thresh = bdi_dirty_limit(bdi, dirty_thresh); |
@@ -676,11 +676,11 @@ void bdi_destroy(struct backing_dev_info *bdi) | |||
676 | if (bdi_has_dirty_io(bdi)) { | 676 | if (bdi_has_dirty_io(bdi)) { |
677 | struct bdi_writeback *dst = &default_backing_dev_info.wb; | 677 | struct bdi_writeback *dst = &default_backing_dev_info.wb; |
678 | 678 | ||
679 | spin_lock(&inode_lock); | 679 | spin_lock(&inode_wb_list_lock); |
680 | list_splice(&bdi->wb.b_dirty, &dst->b_dirty); | 680 | list_splice(&bdi->wb.b_dirty, &dst->b_dirty); |
681 | list_splice(&bdi->wb.b_io, &dst->b_io); | 681 | list_splice(&bdi->wb.b_io, &dst->b_io); |
682 | list_splice(&bdi->wb.b_more_io, &dst->b_more_io); | 682 | list_splice(&bdi->wb.b_more_io, &dst->b_more_io); |
683 | spin_unlock(&inode_lock); | 683 | spin_unlock(&inode_wb_list_lock); |
684 | } | 684 | } |
685 | 685 | ||
686 | bdi_unregister(bdi); | 686 | bdi_unregister(bdi); |
diff --git a/mm/filemap.c b/mm/filemap.c index 04d1992fd86b..c641edf553a9 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -80,8 +80,8 @@ | |||
80 | * ->i_mutex | 80 | * ->i_mutex |
81 | * ->i_alloc_sem (various) | 81 | * ->i_alloc_sem (various) |
82 | * | 82 | * |
83 | * ->inode_lock | 83 | * inode_wb_list_lock |
84 | * ->sb_lock (fs/fs-writeback.c) | 84 | * sb_lock (fs/fs-writeback.c) |
85 | * ->mapping->tree_lock (__sync_single_inode) | 85 | * ->mapping->tree_lock (__sync_single_inode) |
86 | * | 86 | * |
87 | * ->i_mmap_lock | 87 | * ->i_mmap_lock |
@@ -98,8 +98,10 @@ | |||
98 | * ->zone.lru_lock (check_pte_range->isolate_lru_page) | 98 | * ->zone.lru_lock (check_pte_range->isolate_lru_page) |
99 | * ->private_lock (page_remove_rmap->set_page_dirty) | 99 | * ->private_lock (page_remove_rmap->set_page_dirty) |
100 | * ->tree_lock (page_remove_rmap->set_page_dirty) | 100 | * ->tree_lock (page_remove_rmap->set_page_dirty) |
101 | * ->inode_lock (page_remove_rmap->set_page_dirty) | 101 | * inode_wb_list_lock (page_remove_rmap->set_page_dirty) |
102 | * ->inode_lock (zap_pte_range->set_page_dirty) | 102 | * ->inode->i_lock (page_remove_rmap->set_page_dirty) |
103 | * inode_wb_list_lock (zap_pte_range->set_page_dirty) | ||
104 | * ->inode->i_lock (zap_pte_range->set_page_dirty) | ||
103 | * ->private_lock (zap_pte_range->__set_page_dirty_buffers) | 105 | * ->private_lock (zap_pte_range->__set_page_dirty_buffers) |
104 | * | 106 | * |
105 | * (code doesn't rely on that order, so you could switch it around) | 107 | * (code doesn't rely on that order, so you could switch it around) |
diff --git a/mm/memory.c b/mm/memory.c index 51a5c23704af..9da8cab1b1b0 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -3715,7 +3715,7 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, | |||
3715 | } | 3715 | } |
3716 | 3716 | ||
3717 | /** | 3717 | /** |
3718 | * @access_remote_vm - access another process' address space | 3718 | * access_remote_vm - access another process' address space |
3719 | * @mm: the mm_struct of the target address space | 3719 | * @mm: the mm_struct of the target address space |
3720 | * @addr: start address to access | 3720 | * @addr: start address to access |
3721 | * @buf: source or destination buffer | 3721 | * @buf: source or destination buffer |
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 62a5cec08a17..6a819d1b2c7d 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
@@ -406,7 +406,7 @@ static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order, | |||
406 | task_unlock(current); | 406 | task_unlock(current); |
407 | dump_stack(); | 407 | dump_stack(); |
408 | mem_cgroup_print_oom_info(mem, p); | 408 | mem_cgroup_print_oom_info(mem, p); |
409 | __show_mem(SHOW_MEM_FILTER_NODES); | 409 | show_mem(SHOW_MEM_FILTER_NODES); |
410 | if (sysctl_oom_dump_tasks) | 410 | if (sysctl_oom_dump_tasks) |
411 | dump_tasks(mem, nodemask); | 411 | dump_tasks(mem, nodemask); |
412 | } | 412 | } |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 8e5726ab0d85..d6e7ba7373be 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -2195,7 +2195,7 @@ nopage: | |||
2195 | current->comm, order, gfp_mask); | 2195 | current->comm, order, gfp_mask); |
2196 | dump_stack(); | 2196 | dump_stack(); |
2197 | if (!should_suppress_show_mem()) | 2197 | if (!should_suppress_show_mem()) |
2198 | __show_mem(filter); | 2198 | show_mem(filter); |
2199 | } | 2199 | } |
2200 | return page; | 2200 | return page; |
2201 | got_pg: | 2201 | got_pg: |
diff --git a/mm/percpu.c b/mm/percpu.c index c5feb79f5995..8eb536645f68 100644 --- a/mm/percpu.c +++ b/mm/percpu.c | |||
@@ -1648,8 +1648,8 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size, | |||
1648 | /* warn if maximum distance is further than 75% of vmalloc space */ | 1648 | /* warn if maximum distance is further than 75% of vmalloc space */ |
1649 | if (max_distance > (VMALLOC_END - VMALLOC_START) * 3 / 4) { | 1649 | if (max_distance > (VMALLOC_END - VMALLOC_START) * 3 / 4) { |
1650 | pr_warning("PERCPU: max_distance=0x%zx too large for vmalloc " | 1650 | pr_warning("PERCPU: max_distance=0x%zx too large for vmalloc " |
1651 | "space 0x%lx\n", | 1651 | "space 0x%lx\n", max_distance, |
1652 | max_distance, VMALLOC_END - VMALLOC_START); | 1652 | (unsigned long)(VMALLOC_END - VMALLOC_START)); |
1653 | #ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK | 1653 | #ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK |
1654 | /* and fail if we have fallback */ | 1654 | /* and fail if we have fallback */ |
1655 | rc = -EINVAL; | 1655 | rc = -EINVAL; |
@@ -31,11 +31,12 @@ | |||
31 | * swap_lock (in swap_duplicate, swap_info_get) | 31 | * swap_lock (in swap_duplicate, swap_info_get) |
32 | * mmlist_lock (in mmput, drain_mmlist and others) | 32 | * mmlist_lock (in mmput, drain_mmlist and others) |
33 | * mapping->private_lock (in __set_page_dirty_buffers) | 33 | * mapping->private_lock (in __set_page_dirty_buffers) |
34 | * inode_lock (in set_page_dirty's __mark_inode_dirty) | 34 | * inode->i_lock (in set_page_dirty's __mark_inode_dirty) |
35 | * inode_wb_list_lock (in set_page_dirty's __mark_inode_dirty) | ||
35 | * sb_lock (within inode_lock in fs/fs-writeback.c) | 36 | * sb_lock (within inode_lock in fs/fs-writeback.c) |
36 | * mapping->tree_lock (widely used, in set_page_dirty, | 37 | * mapping->tree_lock (widely used, in set_page_dirty, |
37 | * in arch-dependent flush_dcache_mmap_lock, | 38 | * in arch-dependent flush_dcache_mmap_lock, |
38 | * within inode_lock in __sync_single_inode) | 39 | * within inode_wb_list_lock in __sync_single_inode) |
39 | * | 40 | * |
40 | * (code doesn't rely on that order so it could be switched around) | 41 | * (code doesn't rely on that order so it could be switched around) |
41 | * ->tasklist_lock | 42 | * ->tasklist_lock |
@@ -849,11 +849,11 @@ static inline void slab_free_hook(struct kmem_cache *s, void *x) | |||
849 | local_irq_save(flags); | 849 | local_irq_save(flags); |
850 | kmemcheck_slab_free(s, x, s->objsize); | 850 | kmemcheck_slab_free(s, x, s->objsize); |
851 | debug_check_no_locks_freed(x, s->objsize); | 851 | debug_check_no_locks_freed(x, s->objsize); |
852 | if (!(s->flags & SLAB_DEBUG_OBJECTS)) | ||
853 | debug_check_no_obj_freed(x, s->objsize); | ||
854 | local_irq_restore(flags); | 852 | local_irq_restore(flags); |
855 | } | 853 | } |
856 | #endif | 854 | #endif |
855 | if (!(s->flags & SLAB_DEBUG_OBJECTS)) | ||
856 | debug_check_no_obj_freed(x, s->objsize); | ||
857 | } | 857 | } |
858 | 858 | ||
859 | /* | 859 | /* |
@@ -1604,7 +1604,7 @@ static inline void note_cmpxchg_failure(const char *n, | |||
1604 | 1604 | ||
1605 | void init_kmem_cache_cpus(struct kmem_cache *s) | 1605 | void init_kmem_cache_cpus(struct kmem_cache *s) |
1606 | { | 1606 | { |
1607 | #if defined(CONFIG_CMPXCHG_LOCAL) && defined(CONFIG_PREEMPT) | 1607 | #ifdef CONFIG_CMPXCHG_LOCAL |
1608 | int cpu; | 1608 | int cpu; |
1609 | 1609 | ||
1610 | for_each_possible_cpu(cpu) | 1610 | for_each_possible_cpu(cpu) |
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 030a002ff8ee..f61eb2eff3fd 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c | |||
@@ -445,9 +445,9 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br, | |||
445 | ip6h->payload_len = htons(8 + sizeof(*mldq)); | 445 | ip6h->payload_len = htons(8 + sizeof(*mldq)); |
446 | ip6h->nexthdr = IPPROTO_HOPOPTS; | 446 | ip6h->nexthdr = IPPROTO_HOPOPTS; |
447 | ip6h->hop_limit = 1; | 447 | ip6h->hop_limit = 1; |
448 | ipv6_addr_set(&ip6h->daddr, htonl(0xff020000), 0, 0, htonl(1)); | ||
448 | ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0, | 449 | ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0, |
449 | &ip6h->saddr); | 450 | &ip6h->saddr); |
450 | ipv6_addr_set(&ip6h->daddr, htonl(0xff020000), 0, 0, htonl(1)); | ||
451 | ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest); | 451 | ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest); |
452 | 452 | ||
453 | hopopt = (u8 *)(ip6h + 1); | 453 | hopopt = (u8 *)(ip6h + 1); |
diff --git a/net/core/dev.c b/net/core/dev.c index 0b88eba97dab..f453370131a0 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -1353,14 +1353,17 @@ EXPORT_SYMBOL(dev_close); | |||
1353 | */ | 1353 | */ |
1354 | void dev_disable_lro(struct net_device *dev) | 1354 | void dev_disable_lro(struct net_device *dev) |
1355 | { | 1355 | { |
1356 | if (dev->ethtool_ops && dev->ethtool_ops->get_flags && | 1356 | u32 flags; |
1357 | dev->ethtool_ops->set_flags) { | 1357 | |
1358 | u32 flags = dev->ethtool_ops->get_flags(dev); | 1358 | if (dev->ethtool_ops && dev->ethtool_ops->get_flags) |
1359 | if (flags & ETH_FLAG_LRO) { | 1359 | flags = dev->ethtool_ops->get_flags(dev); |
1360 | flags &= ~ETH_FLAG_LRO; | 1360 | else |
1361 | dev->ethtool_ops->set_flags(dev, flags); | 1361 | flags = ethtool_op_get_flags(dev); |
1362 | } | 1362 | |
1363 | } | 1363 | if (!(flags & ETH_FLAG_LRO)) |
1364 | return; | ||
1365 | |||
1366 | __ethtool_set_flags(dev, flags & ~ETH_FLAG_LRO); | ||
1364 | WARN_ON(dev->features & NETIF_F_LRO); | 1367 | WARN_ON(dev->features & NETIF_F_LRO); |
1365 | } | 1368 | } |
1366 | EXPORT_SYMBOL(dev_disable_lro); | 1369 | EXPORT_SYMBOL(dev_disable_lro); |
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index a1086fb0c0c7..24bd57493c0d 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -513,7 +513,7 @@ static int ethtool_set_one_feature(struct net_device *dev, | |||
513 | } | 513 | } |
514 | } | 514 | } |
515 | 515 | ||
516 | static int __ethtool_set_flags(struct net_device *dev, u32 data) | 516 | int __ethtool_set_flags(struct net_device *dev, u32 data) |
517 | { | 517 | { |
518 | u32 changed; | 518 | u32 changed; |
519 | 519 | ||
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 6d85800daeb7..5345b0bee6df 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -64,6 +64,8 @@ | |||
64 | #include <net/rtnetlink.h> | 64 | #include <net/rtnetlink.h> |
65 | #include <net/net_namespace.h> | 65 | #include <net/net_namespace.h> |
66 | 66 | ||
67 | #include "fib_lookup.h" | ||
68 | |||
67 | static struct ipv4_devconf ipv4_devconf = { | 69 | static struct ipv4_devconf ipv4_devconf = { |
68 | .data = { | 70 | .data = { |
69 | [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1, | 71 | [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1, |
@@ -151,6 +153,20 @@ struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref) | |||
151 | break; | 153 | break; |
152 | } | 154 | } |
153 | } | 155 | } |
156 | if (!result) { | ||
157 | struct flowi4 fl4 = { .daddr = addr }; | ||
158 | struct fib_result res = { 0 }; | ||
159 | struct fib_table *local; | ||
160 | |||
161 | /* Fallback to FIB local table so that communication | ||
162 | * over loopback subnets work. | ||
163 | */ | ||
164 | local = fib_get_table(net, RT_TABLE_LOCAL); | ||
165 | if (local && | ||
166 | !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) && | ||
167 | res.type == RTN_LOCAL) | ||
168 | result = FIB_RES_DEV(res); | ||
169 | } | ||
154 | if (result && devref) | 170 | if (result && devref) |
155 | dev_hold(result); | 171 | dev_hold(result); |
156 | rcu_read_unlock(); | 172 | rcu_read_unlock(); |
@@ -345,6 +361,17 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
345 | } | 361 | } |
346 | } | 362 | } |
347 | 363 | ||
364 | /* On promotion all secondaries from subnet are changing | ||
365 | * the primary IP, we must remove all their routes silently | ||
366 | * and later to add them back with new prefsrc. Do this | ||
367 | * while all addresses are on the device list. | ||
368 | */ | ||
369 | for (ifa = promote; ifa; ifa = ifa->ifa_next) { | ||
370 | if (ifa1->ifa_mask == ifa->ifa_mask && | ||
371 | inet_ifa_match(ifa1->ifa_address, ifa)) | ||
372 | fib_del_ifaddr(ifa, ifa1); | ||
373 | } | ||
374 | |||
348 | /* 2. Unlink it */ | 375 | /* 2. Unlink it */ |
349 | 376 | ||
350 | *ifap = ifa1->ifa_next; | 377 | *ifap = ifa1->ifa_next; |
@@ -364,6 +391,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
364 | blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); | 391 | blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); |
365 | 392 | ||
366 | if (promote) { | 393 | if (promote) { |
394 | struct in_ifaddr *next_sec = promote->ifa_next; | ||
367 | 395 | ||
368 | if (prev_prom) { | 396 | if (prev_prom) { |
369 | prev_prom->ifa_next = promote->ifa_next; | 397 | prev_prom->ifa_next = promote->ifa_next; |
@@ -375,7 +403,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
375 | rtmsg_ifa(RTM_NEWADDR, promote, nlh, pid); | 403 | rtmsg_ifa(RTM_NEWADDR, promote, nlh, pid); |
376 | blocking_notifier_call_chain(&inetaddr_chain, | 404 | blocking_notifier_call_chain(&inetaddr_chain, |
377 | NETDEV_UP, promote); | 405 | NETDEV_UP, promote); |
378 | for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) { | 406 | for (ifa = next_sec; ifa; ifa = ifa->ifa_next) { |
379 | if (ifa1->ifa_mask != ifa->ifa_mask || | 407 | if (ifa1->ifa_mask != ifa->ifa_mask || |
380 | !inet_ifa_match(ifa1->ifa_address, ifa)) | 408 | !inet_ifa_match(ifa1->ifa_address, ifa)) |
381 | continue; | 409 | continue; |
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index a373a259253c..f116ce8f1b46 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
@@ -228,7 +228,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, | |||
228 | if (res.type != RTN_LOCAL || !accept_local) | 228 | if (res.type != RTN_LOCAL || !accept_local) |
229 | goto e_inval; | 229 | goto e_inval; |
230 | } | 230 | } |
231 | *spec_dst = FIB_RES_PREFSRC(res); | 231 | *spec_dst = FIB_RES_PREFSRC(net, res); |
232 | fib_combine_itag(itag, &res); | 232 | fib_combine_itag(itag, &res); |
233 | dev_match = false; | 233 | dev_match = false; |
234 | 234 | ||
@@ -258,7 +258,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, | |||
258 | ret = 0; | 258 | ret = 0; |
259 | if (fib_lookup(net, &fl4, &res) == 0) { | 259 | if (fib_lookup(net, &fl4, &res) == 0) { |
260 | if (res.type == RTN_UNICAST) { | 260 | if (res.type == RTN_UNICAST) { |
261 | *spec_dst = FIB_RES_PREFSRC(res); | 261 | *spec_dst = FIB_RES_PREFSRC(net, res); |
262 | ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; | 262 | ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; |
263 | } | 263 | } |
264 | } | 264 | } |
@@ -722,12 +722,17 @@ void fib_add_ifaddr(struct in_ifaddr *ifa) | |||
722 | } | 722 | } |
723 | } | 723 | } |
724 | 724 | ||
725 | static void fib_del_ifaddr(struct in_ifaddr *ifa) | 725 | /* Delete primary or secondary address. |
726 | * Optionally, on secondary address promotion consider the addresses | ||
727 | * from subnet iprim as deleted, even if they are in device list. | ||
728 | * In this case the secondary ifa can be in device list. | ||
729 | */ | ||
730 | void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim) | ||
726 | { | 731 | { |
727 | struct in_device *in_dev = ifa->ifa_dev; | 732 | struct in_device *in_dev = ifa->ifa_dev; |
728 | struct net_device *dev = in_dev->dev; | 733 | struct net_device *dev = in_dev->dev; |
729 | struct in_ifaddr *ifa1; | 734 | struct in_ifaddr *ifa1; |
730 | struct in_ifaddr *prim = ifa; | 735 | struct in_ifaddr *prim = ifa, *prim1 = NULL; |
731 | __be32 brd = ifa->ifa_address | ~ifa->ifa_mask; | 736 | __be32 brd = ifa->ifa_address | ~ifa->ifa_mask; |
732 | __be32 any = ifa->ifa_address & ifa->ifa_mask; | 737 | __be32 any = ifa->ifa_address & ifa->ifa_mask; |
733 | #define LOCAL_OK 1 | 738 | #define LOCAL_OK 1 |
@@ -735,17 +740,26 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa) | |||
735 | #define BRD0_OK 4 | 740 | #define BRD0_OK 4 |
736 | #define BRD1_OK 8 | 741 | #define BRD1_OK 8 |
737 | unsigned ok = 0; | 742 | unsigned ok = 0; |
743 | int subnet = 0; /* Primary network */ | ||
744 | int gone = 1; /* Address is missing */ | ||
745 | int same_prefsrc = 0; /* Another primary with same IP */ | ||
738 | 746 | ||
739 | if (!(ifa->ifa_flags & IFA_F_SECONDARY)) | 747 | if (ifa->ifa_flags & IFA_F_SECONDARY) { |
740 | fib_magic(RTM_DELROUTE, | ||
741 | dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST, | ||
742 | any, ifa->ifa_prefixlen, prim); | ||
743 | else { | ||
744 | prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask); | 748 | prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask); |
745 | if (prim == NULL) { | 749 | if (prim == NULL) { |
746 | printk(KERN_WARNING "fib_del_ifaddr: bug: prim == NULL\n"); | 750 | printk(KERN_WARNING "fib_del_ifaddr: bug: prim == NULL\n"); |
747 | return; | 751 | return; |
748 | } | 752 | } |
753 | if (iprim && iprim != prim) { | ||
754 | printk(KERN_WARNING "fib_del_ifaddr: bug: iprim != prim\n"); | ||
755 | return; | ||
756 | } | ||
757 | } else if (!ipv4_is_zeronet(any) && | ||
758 | (any != ifa->ifa_local || ifa->ifa_prefixlen < 32)) { | ||
759 | fib_magic(RTM_DELROUTE, | ||
760 | dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST, | ||
761 | any, ifa->ifa_prefixlen, prim); | ||
762 | subnet = 1; | ||
749 | } | 763 | } |
750 | 764 | ||
751 | /* Deletion is more complicated than add. | 765 | /* Deletion is more complicated than add. |
@@ -755,6 +769,49 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa) | |||
755 | */ | 769 | */ |
756 | 770 | ||
757 | for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) { | 771 | for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) { |
772 | if (ifa1 == ifa) { | ||
773 | /* promotion, keep the IP */ | ||
774 | gone = 0; | ||
775 | continue; | ||
776 | } | ||
777 | /* Ignore IFAs from our subnet */ | ||
778 | if (iprim && ifa1->ifa_mask == iprim->ifa_mask && | ||
779 | inet_ifa_match(ifa1->ifa_address, iprim)) | ||
780 | continue; | ||
781 | |||
782 | /* Ignore ifa1 if it uses different primary IP (prefsrc) */ | ||
783 | if (ifa1->ifa_flags & IFA_F_SECONDARY) { | ||
784 | /* Another address from our subnet? */ | ||
785 | if (ifa1->ifa_mask == prim->ifa_mask && | ||
786 | inet_ifa_match(ifa1->ifa_address, prim)) | ||
787 | prim1 = prim; | ||
788 | else { | ||
789 | /* We reached the secondaries, so | ||
790 | * same_prefsrc should be determined. | ||
791 | */ | ||
792 | if (!same_prefsrc) | ||
793 | continue; | ||
794 | /* Search new prim1 if ifa1 is not | ||
795 | * using the current prim1 | ||
796 | */ | ||
797 | if (!prim1 || | ||
798 | ifa1->ifa_mask != prim1->ifa_mask || | ||
799 | !inet_ifa_match(ifa1->ifa_address, prim1)) | ||
800 | prim1 = inet_ifa_byprefix(in_dev, | ||
801 | ifa1->ifa_address, | ||
802 | ifa1->ifa_mask); | ||
803 | if (!prim1) | ||
804 | continue; | ||
805 | if (prim1->ifa_local != prim->ifa_local) | ||
806 | continue; | ||
807 | } | ||
808 | } else { | ||
809 | if (prim->ifa_local != ifa1->ifa_local) | ||
810 | continue; | ||
811 | prim1 = ifa1; | ||
812 | if (prim != prim1) | ||
813 | same_prefsrc = 1; | ||
814 | } | ||
758 | if (ifa->ifa_local == ifa1->ifa_local) | 815 | if (ifa->ifa_local == ifa1->ifa_local) |
759 | ok |= LOCAL_OK; | 816 | ok |= LOCAL_OK; |
760 | if (ifa->ifa_broadcast == ifa1->ifa_broadcast) | 817 | if (ifa->ifa_broadcast == ifa1->ifa_broadcast) |
@@ -763,19 +820,37 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa) | |||
763 | ok |= BRD1_OK; | 820 | ok |= BRD1_OK; |
764 | if (any == ifa1->ifa_broadcast) | 821 | if (any == ifa1->ifa_broadcast) |
765 | ok |= BRD0_OK; | 822 | ok |= BRD0_OK; |
823 | /* primary has network specific broadcasts */ | ||
824 | if (prim1 == ifa1 && ifa1->ifa_prefixlen < 31) { | ||
825 | __be32 brd1 = ifa1->ifa_address | ~ifa1->ifa_mask; | ||
826 | __be32 any1 = ifa1->ifa_address & ifa1->ifa_mask; | ||
827 | |||
828 | if (!ipv4_is_zeronet(any1)) { | ||
829 | if (ifa->ifa_broadcast == brd1 || | ||
830 | ifa->ifa_broadcast == any1) | ||
831 | ok |= BRD_OK; | ||
832 | if (brd == brd1 || brd == any1) | ||
833 | ok |= BRD1_OK; | ||
834 | if (any == brd1 || any == any1) | ||
835 | ok |= BRD0_OK; | ||
836 | } | ||
837 | } | ||
766 | } | 838 | } |
767 | 839 | ||
768 | if (!(ok & BRD_OK)) | 840 | if (!(ok & BRD_OK)) |
769 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); | 841 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); |
770 | if (!(ok & BRD1_OK)) | 842 | if (subnet && ifa->ifa_prefixlen < 31) { |
771 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim); | 843 | if (!(ok & BRD1_OK)) |
772 | if (!(ok & BRD0_OK)) | 844 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim); |
773 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim); | 845 | if (!(ok & BRD0_OK)) |
846 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim); | ||
847 | } | ||
774 | if (!(ok & LOCAL_OK)) { | 848 | if (!(ok & LOCAL_OK)) { |
775 | fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim); | 849 | fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim); |
776 | 850 | ||
777 | /* Check, that this local address finally disappeared. */ | 851 | /* Check, that this local address finally disappeared. */ |
778 | if (inet_addr_type(dev_net(dev), ifa->ifa_local) != RTN_LOCAL) { | 852 | if (gone && |
853 | inet_addr_type(dev_net(dev), ifa->ifa_local) != RTN_LOCAL) { | ||
779 | /* And the last, but not the least thing. | 854 | /* And the last, but not the least thing. |
780 | * We must flush stray FIB entries. | 855 | * We must flush stray FIB entries. |
781 | * | 856 | * |
@@ -885,6 +960,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, | |||
885 | { | 960 | { |
886 | struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; | 961 | struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; |
887 | struct net_device *dev = ifa->ifa_dev->dev; | 962 | struct net_device *dev = ifa->ifa_dev->dev; |
963 | struct net *net = dev_net(dev); | ||
888 | 964 | ||
889 | switch (event) { | 965 | switch (event) { |
890 | case NETDEV_UP: | 966 | case NETDEV_UP: |
@@ -892,12 +968,12 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, | |||
892 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 968 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
893 | fib_sync_up(dev); | 969 | fib_sync_up(dev); |
894 | #endif | 970 | #endif |
895 | fib_update_nh_saddrs(dev); | 971 | atomic_inc(&net->ipv4.dev_addr_genid); |
896 | rt_cache_flush(dev_net(dev), -1); | 972 | rt_cache_flush(dev_net(dev), -1); |
897 | break; | 973 | break; |
898 | case NETDEV_DOWN: | 974 | case NETDEV_DOWN: |
899 | fib_del_ifaddr(ifa); | 975 | fib_del_ifaddr(ifa, NULL); |
900 | fib_update_nh_saddrs(dev); | 976 | atomic_inc(&net->ipv4.dev_addr_genid); |
901 | if (ifa->ifa_dev->ifa_list == NULL) { | 977 | if (ifa->ifa_dev->ifa_list == NULL) { |
902 | /* Last address was deleted from this interface. | 978 | /* Last address was deleted from this interface. |
903 | * Disable IP. | 979 | * Disable IP. |
@@ -915,6 +991,7 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo | |||
915 | { | 991 | { |
916 | struct net_device *dev = ptr; | 992 | struct net_device *dev = ptr; |
917 | struct in_device *in_dev = __in_dev_get_rtnl(dev); | 993 | struct in_device *in_dev = __in_dev_get_rtnl(dev); |
994 | struct net *net = dev_net(dev); | ||
918 | 995 | ||
919 | if (event == NETDEV_UNREGISTER) { | 996 | if (event == NETDEV_UNREGISTER) { |
920 | fib_disable_ip(dev, 2, -1); | 997 | fib_disable_ip(dev, 2, -1); |
@@ -932,6 +1009,7 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo | |||
932 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 1009 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
933 | fib_sync_up(dev); | 1010 | fib_sync_up(dev); |
934 | #endif | 1011 | #endif |
1012 | atomic_inc(&net->ipv4.dev_addr_genid); | ||
935 | rt_cache_flush(dev_net(dev), -1); | 1013 | rt_cache_flush(dev_net(dev), -1); |
936 | break; | 1014 | break; |
937 | case NETDEV_DOWN: | 1015 | case NETDEV_DOWN: |
diff --git a/net/ipv4/fib_lookup.h b/net/ipv4/fib_lookup.h index 4ec323875a02..af0f14aba169 100644 --- a/net/ipv4/fib_lookup.h +++ b/net/ipv4/fib_lookup.h | |||
@@ -10,7 +10,6 @@ struct fib_alias { | |||
10 | struct fib_info *fa_info; | 10 | struct fib_info *fa_info; |
11 | u8 fa_tos; | 11 | u8 fa_tos; |
12 | u8 fa_type; | 12 | u8 fa_type; |
13 | u8 fa_scope; | ||
14 | u8 fa_state; | 13 | u8 fa_state; |
15 | struct rcu_head rcu; | 14 | struct rcu_head rcu; |
16 | }; | 15 | }; |
@@ -29,7 +28,7 @@ extern void fib_release_info(struct fib_info *); | |||
29 | extern struct fib_info *fib_create_info(struct fib_config *cfg); | 28 | extern struct fib_info *fib_create_info(struct fib_config *cfg); |
30 | extern int fib_nh_match(struct fib_config *cfg, struct fib_info *fi); | 29 | extern int fib_nh_match(struct fib_config *cfg, struct fib_info *fi); |
31 | extern int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | 30 | extern int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, |
32 | u32 tb_id, u8 type, u8 scope, __be32 dst, | 31 | u32 tb_id, u8 type, __be32 dst, |
33 | int dst_len, u8 tos, struct fib_info *fi, | 32 | int dst_len, u8 tos, struct fib_info *fi, |
34 | unsigned int); | 33 | unsigned int); |
35 | extern void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, | 34 | extern void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, |
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 622ac4c95026..641a5a2a9f9c 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c | |||
@@ -222,7 +222,7 @@ static inline unsigned int fib_info_hashfn(const struct fib_info *fi) | |||
222 | unsigned int mask = (fib_info_hash_size - 1); | 222 | unsigned int mask = (fib_info_hash_size - 1); |
223 | unsigned int val = fi->fib_nhs; | 223 | unsigned int val = fi->fib_nhs; |
224 | 224 | ||
225 | val ^= fi->fib_protocol; | 225 | val ^= (fi->fib_protocol << 8) | fi->fib_scope; |
226 | val ^= (__force u32)fi->fib_prefsrc; | 226 | val ^= (__force u32)fi->fib_prefsrc; |
227 | val ^= fi->fib_priority; | 227 | val ^= fi->fib_priority; |
228 | for_nexthops(fi) { | 228 | for_nexthops(fi) { |
@@ -248,10 +248,11 @@ static struct fib_info *fib_find_info(const struct fib_info *nfi) | |||
248 | if (fi->fib_nhs != nfi->fib_nhs) | 248 | if (fi->fib_nhs != nfi->fib_nhs) |
249 | continue; | 249 | continue; |
250 | if (nfi->fib_protocol == fi->fib_protocol && | 250 | if (nfi->fib_protocol == fi->fib_protocol && |
251 | nfi->fib_scope == fi->fib_scope && | ||
251 | nfi->fib_prefsrc == fi->fib_prefsrc && | 252 | nfi->fib_prefsrc == fi->fib_prefsrc && |
252 | nfi->fib_priority == fi->fib_priority && | 253 | nfi->fib_priority == fi->fib_priority && |
253 | memcmp(nfi->fib_metrics, fi->fib_metrics, | 254 | memcmp(nfi->fib_metrics, fi->fib_metrics, |
254 | sizeof(fi->fib_metrics)) == 0 && | 255 | sizeof(u32) * RTAX_MAX) == 0 && |
255 | ((nfi->fib_flags ^ fi->fib_flags) & ~RTNH_F_DEAD) == 0 && | 256 | ((nfi->fib_flags ^ fi->fib_flags) & ~RTNH_F_DEAD) == 0 && |
256 | (nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0)) | 257 | (nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0)) |
257 | return fi; | 258 | return fi; |
@@ -328,7 +329,7 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, | |||
328 | goto errout; | 329 | goto errout; |
329 | 330 | ||
330 | err = fib_dump_info(skb, info->pid, seq, event, tb_id, | 331 | err = fib_dump_info(skb, info->pid, seq, event, tb_id, |
331 | fa->fa_type, fa->fa_scope, key, dst_len, | 332 | fa->fa_type, key, dst_len, |
332 | fa->fa_tos, fa->fa_info, nlm_flags); | 333 | fa->fa_tos, fa->fa_info, nlm_flags); |
333 | if (err < 0) { | 334 | if (err < 0) { |
334 | /* -EMSGSIZE implies BUG in fib_nlmsg_size() */ | 335 | /* -EMSGSIZE implies BUG in fib_nlmsg_size() */ |
@@ -695,6 +696,16 @@ static void fib_info_hash_move(struct hlist_head *new_info_hash, | |||
695 | fib_info_hash_free(old_laddrhash, bytes); | 696 | fib_info_hash_free(old_laddrhash, bytes); |
696 | } | 697 | } |
697 | 698 | ||
699 | __be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh) | ||
700 | { | ||
701 | nh->nh_saddr = inet_select_addr(nh->nh_dev, | ||
702 | nh->nh_gw, | ||
703 | nh->nh_parent->fib_scope); | ||
704 | nh->nh_saddr_genid = atomic_read(&net->ipv4.dev_addr_genid); | ||
705 | |||
706 | return nh->nh_saddr; | ||
707 | } | ||
708 | |||
698 | struct fib_info *fib_create_info(struct fib_config *cfg) | 709 | struct fib_info *fib_create_info(struct fib_config *cfg) |
699 | { | 710 | { |
700 | int err; | 711 | int err; |
@@ -753,6 +764,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg) | |||
753 | 764 | ||
754 | fi->fib_net = hold_net(net); | 765 | fi->fib_net = hold_net(net); |
755 | fi->fib_protocol = cfg->fc_protocol; | 766 | fi->fib_protocol = cfg->fc_protocol; |
767 | fi->fib_scope = cfg->fc_scope; | ||
756 | fi->fib_flags = cfg->fc_flags; | 768 | fi->fib_flags = cfg->fc_flags; |
757 | fi->fib_priority = cfg->fc_priority; | 769 | fi->fib_priority = cfg->fc_priority; |
758 | fi->fib_prefsrc = cfg->fc_prefsrc; | 770 | fi->fib_prefsrc = cfg->fc_prefsrc; |
@@ -854,10 +866,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg) | |||
854 | } | 866 | } |
855 | 867 | ||
856 | change_nexthops(fi) { | 868 | change_nexthops(fi) { |
857 | nexthop_nh->nh_cfg_scope = cfg->fc_scope; | 869 | fib_info_update_nh_saddr(net, nexthop_nh); |
858 | nexthop_nh->nh_saddr = inet_select_addr(nexthop_nh->nh_dev, | ||
859 | nexthop_nh->nh_gw, | ||
860 | nexthop_nh->nh_cfg_scope); | ||
861 | } endfor_nexthops(fi) | 870 | } endfor_nexthops(fi) |
862 | 871 | ||
863 | link_it: | 872 | link_it: |
@@ -906,7 +915,7 @@ failure: | |||
906 | } | 915 | } |
907 | 916 | ||
908 | int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | 917 | int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, |
909 | u32 tb_id, u8 type, u8 scope, __be32 dst, int dst_len, u8 tos, | 918 | u32 tb_id, u8 type, __be32 dst, int dst_len, u8 tos, |
910 | struct fib_info *fi, unsigned int flags) | 919 | struct fib_info *fi, unsigned int flags) |
911 | { | 920 | { |
912 | struct nlmsghdr *nlh; | 921 | struct nlmsghdr *nlh; |
@@ -928,7 +937,7 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | |||
928 | NLA_PUT_U32(skb, RTA_TABLE, tb_id); | 937 | NLA_PUT_U32(skb, RTA_TABLE, tb_id); |
929 | rtm->rtm_type = type; | 938 | rtm->rtm_type = type; |
930 | rtm->rtm_flags = fi->fib_flags; | 939 | rtm->rtm_flags = fi->fib_flags; |
931 | rtm->rtm_scope = scope; | 940 | rtm->rtm_scope = fi->fib_scope; |
932 | rtm->rtm_protocol = fi->fib_protocol; | 941 | rtm->rtm_protocol = fi->fib_protocol; |
933 | 942 | ||
934 | if (rtm->rtm_dst_len) | 943 | if (rtm->rtm_dst_len) |
@@ -1084,7 +1093,7 @@ void fib_select_default(struct fib_result *res) | |||
1084 | list_for_each_entry_rcu(fa, fa_head, fa_list) { | 1093 | list_for_each_entry_rcu(fa, fa_head, fa_list) { |
1085 | struct fib_info *next_fi = fa->fa_info; | 1094 | struct fib_info *next_fi = fa->fa_info; |
1086 | 1095 | ||
1087 | if (fa->fa_scope != res->scope || | 1096 | if (next_fi->fib_scope != res->scope || |
1088 | fa->fa_type != RTN_UNICAST) | 1097 | fa->fa_type != RTN_UNICAST) |
1089 | continue; | 1098 | continue; |
1090 | 1099 | ||
@@ -1128,24 +1137,6 @@ out: | |||
1128 | return; | 1137 | return; |
1129 | } | 1138 | } |
1130 | 1139 | ||
1131 | void fib_update_nh_saddrs(struct net_device *dev) | ||
1132 | { | ||
1133 | struct hlist_head *head; | ||
1134 | struct hlist_node *node; | ||
1135 | struct fib_nh *nh; | ||
1136 | unsigned int hash; | ||
1137 | |||
1138 | hash = fib_devindex_hashfn(dev->ifindex); | ||
1139 | head = &fib_info_devhash[hash]; | ||
1140 | hlist_for_each_entry(nh, node, head, nh_hash) { | ||
1141 | if (nh->nh_dev != dev) | ||
1142 | continue; | ||
1143 | nh->nh_saddr = inet_select_addr(nh->nh_dev, | ||
1144 | nh->nh_gw, | ||
1145 | nh->nh_cfg_scope); | ||
1146 | } | ||
1147 | } | ||
1148 | |||
1149 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 1140 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
1150 | 1141 | ||
1151 | /* | 1142 | /* |
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 3d28a35c2e1a..90a3ff605591 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
@@ -1245,7 +1245,6 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg) | |||
1245 | if (fa->fa_info->fib_priority != fi->fib_priority) | 1245 | if (fa->fa_info->fib_priority != fi->fib_priority) |
1246 | break; | 1246 | break; |
1247 | if (fa->fa_type == cfg->fc_type && | 1247 | if (fa->fa_type == cfg->fc_type && |
1248 | fa->fa_scope == cfg->fc_scope && | ||
1249 | fa->fa_info == fi) { | 1248 | fa->fa_info == fi) { |
1250 | fa_match = fa; | 1249 | fa_match = fa; |
1251 | break; | 1250 | break; |
@@ -1271,7 +1270,6 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg) | |||
1271 | new_fa->fa_tos = fa->fa_tos; | 1270 | new_fa->fa_tos = fa->fa_tos; |
1272 | new_fa->fa_info = fi; | 1271 | new_fa->fa_info = fi; |
1273 | new_fa->fa_type = cfg->fc_type; | 1272 | new_fa->fa_type = cfg->fc_type; |
1274 | new_fa->fa_scope = cfg->fc_scope; | ||
1275 | state = fa->fa_state; | 1273 | state = fa->fa_state; |
1276 | new_fa->fa_state = state & ~FA_S_ACCESSED; | 1274 | new_fa->fa_state = state & ~FA_S_ACCESSED; |
1277 | 1275 | ||
@@ -1308,7 +1306,6 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg) | |||
1308 | new_fa->fa_info = fi; | 1306 | new_fa->fa_info = fi; |
1309 | new_fa->fa_tos = tos; | 1307 | new_fa->fa_tos = tos; |
1310 | new_fa->fa_type = cfg->fc_type; | 1308 | new_fa->fa_type = cfg->fc_type; |
1311 | new_fa->fa_scope = cfg->fc_scope; | ||
1312 | new_fa->fa_state = 0; | 1309 | new_fa->fa_state = 0; |
1313 | /* | 1310 | /* |
1314 | * Insert new entry to the list. | 1311 | * Insert new entry to the list. |
@@ -1362,7 +1359,7 @@ static int check_leaf(struct fib_table *tb, struct trie *t, struct leaf *l, | |||
1362 | 1359 | ||
1363 | if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos) | 1360 | if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos) |
1364 | continue; | 1361 | continue; |
1365 | if (fa->fa_scope < flp->flowi4_scope) | 1362 | if (fa->fa_info->fib_scope < flp->flowi4_scope) |
1366 | continue; | 1363 | continue; |
1367 | fib_alias_accessed(fa); | 1364 | fib_alias_accessed(fa); |
1368 | err = fib_props[fa->fa_type].error; | 1365 | err = fib_props[fa->fa_type].error; |
@@ -1388,7 +1385,7 @@ static int check_leaf(struct fib_table *tb, struct trie *t, struct leaf *l, | |||
1388 | res->prefixlen = plen; | 1385 | res->prefixlen = plen; |
1389 | res->nh_sel = nhsel; | 1386 | res->nh_sel = nhsel; |
1390 | res->type = fa->fa_type; | 1387 | res->type = fa->fa_type; |
1391 | res->scope = fa->fa_scope; | 1388 | res->scope = fa->fa_info->fib_scope; |
1392 | res->fi = fi; | 1389 | res->fi = fi; |
1393 | res->table = tb; | 1390 | res->table = tb; |
1394 | res->fa_head = &li->falh; | 1391 | res->fa_head = &li->falh; |
@@ -1664,7 +1661,9 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg) | |||
1664 | 1661 | ||
1665 | if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) && | 1662 | if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) && |
1666 | (cfg->fc_scope == RT_SCOPE_NOWHERE || | 1663 | (cfg->fc_scope == RT_SCOPE_NOWHERE || |
1667 | fa->fa_scope == cfg->fc_scope) && | 1664 | fa->fa_info->fib_scope == cfg->fc_scope) && |
1665 | (!cfg->fc_prefsrc || | ||
1666 | fi->fib_prefsrc == cfg->fc_prefsrc) && | ||
1668 | (!cfg->fc_protocol || | 1667 | (!cfg->fc_protocol || |
1669 | fi->fib_protocol == cfg->fc_protocol) && | 1668 | fi->fib_protocol == cfg->fc_protocol) && |
1670 | fib_nh_match(cfg, fi) == 0) { | 1669 | fib_nh_match(cfg, fi) == 0) { |
@@ -1861,7 +1860,6 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, | |||
1861 | RTM_NEWROUTE, | 1860 | RTM_NEWROUTE, |
1862 | tb->tb_id, | 1861 | tb->tb_id, |
1863 | fa->fa_type, | 1862 | fa->fa_type, |
1864 | fa->fa_scope, | ||
1865 | xkey, | 1863 | xkey, |
1866 | plen, | 1864 | plen, |
1867 | fa->fa_tos, | 1865 | fa->fa_tos, |
@@ -2382,7 +2380,7 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v) | |||
2382 | seq_indent(seq, iter->depth+1); | 2380 | seq_indent(seq, iter->depth+1); |
2383 | seq_printf(seq, " /%d %s %s", li->plen, | 2381 | seq_printf(seq, " /%d %s %s", li->plen, |
2384 | rtn_scope(buf1, sizeof(buf1), | 2382 | rtn_scope(buf1, sizeof(buf1), |
2385 | fa->fa_scope), | 2383 | fa->fa_info->fib_scope), |
2386 | rtn_type(buf2, sizeof(buf2), | 2384 | rtn_type(buf2, sizeof(buf2), |
2387 | fa->fa_type)); | 2385 | fa->fa_type)); |
2388 | if (fa->fa_tos) | 2386 | if (fa->fa_tos) |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 870b5182ddd8..4b0c81180804 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -1593,8 +1593,6 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
1593 | rt->rt_peer_genid = rt_peer_genid(); | 1593 | rt->rt_peer_genid = rt_peer_genid(); |
1594 | } | 1594 | } |
1595 | check_peer_pmtu(dst, peer); | 1595 | check_peer_pmtu(dst, peer); |
1596 | |||
1597 | inet_putpeer(peer); | ||
1598 | } | 1596 | } |
1599 | } | 1597 | } |
1600 | 1598 | ||
@@ -1720,7 +1718,7 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt) | |||
1720 | 1718 | ||
1721 | rcu_read_lock(); | 1719 | rcu_read_lock(); |
1722 | if (fib_lookup(dev_net(rt->dst.dev), &fl4, &res) == 0) | 1720 | if (fib_lookup(dev_net(rt->dst.dev), &fl4, &res) == 0) |
1723 | src = FIB_RES_PREFSRC(res); | 1721 | src = FIB_RES_PREFSRC(dev_net(rt->dst.dev), res); |
1724 | else | 1722 | else |
1725 | src = inet_select_addr(rt->dst.dev, rt->rt_gateway, | 1723 | src = inet_select_addr(rt->dst.dev, rt->rt_gateway, |
1726 | RT_SCOPE_UNIVERSE); | 1724 | RT_SCOPE_UNIVERSE); |
@@ -2617,7 +2615,7 @@ static struct rtable *ip_route_output_slow(struct net *net, | |||
2617 | fib_select_default(&res); | 2615 | fib_select_default(&res); |
2618 | 2616 | ||
2619 | if (!fl4.saddr) | 2617 | if (!fl4.saddr) |
2620 | fl4.saddr = FIB_RES_PREFSRC(res); | 2618 | fl4.saddr = FIB_RES_PREFSRC(net, res); |
2621 | 2619 | ||
2622 | dev_out = FIB_RES_DEV(res); | 2620 | dev_out = FIB_RES_DEV(res); |
2623 | fl4.flowi4_oif = dev_out->ifindex; | 2621 | fl4.flowi4_oif = dev_out->ifindex; |
@@ -3221,6 +3219,8 @@ static __net_init int rt_genid_init(struct net *net) | |||
3221 | { | 3219 | { |
3222 | get_random_bytes(&net->ipv4.rt_genid, | 3220 | get_random_bytes(&net->ipv4.rt_genid, |
3223 | sizeof(net->ipv4.rt_genid)); | 3221 | sizeof(net->ipv4.rt_genid)); |
3222 | get_random_bytes(&net->ipv4.dev_addr_genid, | ||
3223 | sizeof(net->ipv4.dev_addr_genid)); | ||
3224 | return 0; | 3224 | return 0; |
3225 | } | 3225 | } |
3226 | 3226 | ||
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index da782e7ab16d..bef9f04c22ba 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -2659,7 +2659,7 @@ static void DBGUNDO(struct sock *sk, const char *msg) | |||
2659 | #define DBGUNDO(x...) do { } while (0) | 2659 | #define DBGUNDO(x...) do { } while (0) |
2660 | #endif | 2660 | #endif |
2661 | 2661 | ||
2662 | static void tcp_undo_cwr(struct sock *sk, const int undo) | 2662 | static void tcp_undo_cwr(struct sock *sk, const bool undo_ssthresh) |
2663 | { | 2663 | { |
2664 | struct tcp_sock *tp = tcp_sk(sk); | 2664 | struct tcp_sock *tp = tcp_sk(sk); |
2665 | 2665 | ||
@@ -2671,14 +2671,13 @@ static void tcp_undo_cwr(struct sock *sk, const int undo) | |||
2671 | else | 2671 | else |
2672 | tp->snd_cwnd = max(tp->snd_cwnd, tp->snd_ssthresh << 1); | 2672 | tp->snd_cwnd = max(tp->snd_cwnd, tp->snd_ssthresh << 1); |
2673 | 2673 | ||
2674 | if (undo && tp->prior_ssthresh > tp->snd_ssthresh) { | 2674 | if (undo_ssthresh && tp->prior_ssthresh > tp->snd_ssthresh) { |
2675 | tp->snd_ssthresh = tp->prior_ssthresh; | 2675 | tp->snd_ssthresh = tp->prior_ssthresh; |
2676 | TCP_ECN_withdraw_cwr(tp); | 2676 | TCP_ECN_withdraw_cwr(tp); |
2677 | } | 2677 | } |
2678 | } else { | 2678 | } else { |
2679 | tp->snd_cwnd = max(tp->snd_cwnd, tp->snd_ssthresh); | 2679 | tp->snd_cwnd = max(tp->snd_cwnd, tp->snd_ssthresh); |
2680 | } | 2680 | } |
2681 | tcp_moderate_cwnd(tp); | ||
2682 | tp->snd_cwnd_stamp = tcp_time_stamp; | 2681 | tp->snd_cwnd_stamp = tcp_time_stamp; |
2683 | } | 2682 | } |
2684 | 2683 | ||
@@ -2699,7 +2698,7 @@ static int tcp_try_undo_recovery(struct sock *sk) | |||
2699 | * or our original transmission succeeded. | 2698 | * or our original transmission succeeded. |
2700 | */ | 2699 | */ |
2701 | DBGUNDO(sk, inet_csk(sk)->icsk_ca_state == TCP_CA_Loss ? "loss" : "retrans"); | 2700 | DBGUNDO(sk, inet_csk(sk)->icsk_ca_state == TCP_CA_Loss ? "loss" : "retrans"); |
2702 | tcp_undo_cwr(sk, 1); | 2701 | tcp_undo_cwr(sk, true); |
2703 | if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss) | 2702 | if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss) |
2704 | mib_idx = LINUX_MIB_TCPLOSSUNDO; | 2703 | mib_idx = LINUX_MIB_TCPLOSSUNDO; |
2705 | else | 2704 | else |
@@ -2726,7 +2725,7 @@ static void tcp_try_undo_dsack(struct sock *sk) | |||
2726 | 2725 | ||
2727 | if (tp->undo_marker && !tp->undo_retrans) { | 2726 | if (tp->undo_marker && !tp->undo_retrans) { |
2728 | DBGUNDO(sk, "D-SACK"); | 2727 | DBGUNDO(sk, "D-SACK"); |
2729 | tcp_undo_cwr(sk, 1); | 2728 | tcp_undo_cwr(sk, true); |
2730 | tp->undo_marker = 0; | 2729 | tp->undo_marker = 0; |
2731 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPDSACKUNDO); | 2730 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPDSACKUNDO); |
2732 | } | 2731 | } |
@@ -2779,7 +2778,7 @@ static int tcp_try_undo_partial(struct sock *sk, int acked) | |||
2779 | tcp_update_reordering(sk, tcp_fackets_out(tp) + acked, 1); | 2778 | tcp_update_reordering(sk, tcp_fackets_out(tp) + acked, 1); |
2780 | 2779 | ||
2781 | DBGUNDO(sk, "Hoe"); | 2780 | DBGUNDO(sk, "Hoe"); |
2782 | tcp_undo_cwr(sk, 0); | 2781 | tcp_undo_cwr(sk, false); |
2783 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPPARTIALUNDO); | 2782 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPPARTIALUNDO); |
2784 | 2783 | ||
2785 | /* So... Do not make Hoe's retransmit yet. | 2784 | /* So... Do not make Hoe's retransmit yet. |
@@ -2808,7 +2807,7 @@ static int tcp_try_undo_loss(struct sock *sk) | |||
2808 | 2807 | ||
2809 | DBGUNDO(sk, "partial loss"); | 2808 | DBGUNDO(sk, "partial loss"); |
2810 | tp->lost_out = 0; | 2809 | tp->lost_out = 0; |
2811 | tcp_undo_cwr(sk, 1); | 2810 | tcp_undo_cwr(sk, true); |
2812 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPLOSSUNDO); | 2811 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPLOSSUNDO); |
2813 | inet_csk(sk)->icsk_retransmits = 0; | 2812 | inet_csk(sk)->icsk_retransmits = 0; |
2814 | tp->undo_marker = 0; | 2813 | tp->undo_marker = 0; |
@@ -2822,8 +2821,11 @@ static int tcp_try_undo_loss(struct sock *sk) | |||
2822 | static inline void tcp_complete_cwr(struct sock *sk) | 2821 | static inline void tcp_complete_cwr(struct sock *sk) |
2823 | { | 2822 | { |
2824 | struct tcp_sock *tp = tcp_sk(sk); | 2823 | struct tcp_sock *tp = tcp_sk(sk); |
2825 | tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh); | 2824 | /* Do not moderate cwnd if it's already undone in cwr or recovery */ |
2826 | tp->snd_cwnd_stamp = tcp_time_stamp; | 2825 | if (tp->undo_marker && tp->snd_cwnd > tp->snd_ssthresh) { |
2826 | tp->snd_cwnd = tp->snd_ssthresh; | ||
2827 | tp->snd_cwnd_stamp = tcp_time_stamp; | ||
2828 | } | ||
2827 | tcp_ca_event(sk, CA_EVENT_COMPLETE_CWR); | 2829 | tcp_ca_event(sk, CA_EVENT_COMPLETE_CWR); |
2828 | } | 2830 | } |
2829 | 2831 | ||
@@ -3494,7 +3496,7 @@ static void tcp_undo_spur_to_response(struct sock *sk, int flag) | |||
3494 | if (flag & FLAG_ECE) | 3496 | if (flag & FLAG_ECE) |
3495 | tcp_ratehalving_spur_to_response(sk); | 3497 | tcp_ratehalving_spur_to_response(sk); |
3496 | else | 3498 | else |
3497 | tcp_undo_cwr(sk, 1); | 3499 | tcp_undo_cwr(sk, true); |
3498 | } | 3500 | } |
3499 | 3501 | ||
3500 | /* F-RTO spurious RTO detection algorithm (RFC4138) | 3502 | /* F-RTO spurious RTO detection algorithm (RFC4138) |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 6814c8722fa7..843406f14d7b 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -854,7 +854,7 @@ static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table | |||
854 | return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags); | 854 | return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags); |
855 | } | 855 | } |
856 | 856 | ||
857 | struct dst_entry * ip6_route_output(struct net *net, struct sock *sk, | 857 | struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk, |
858 | struct flowi6 *fl6) | 858 | struct flowi6 *fl6) |
859 | { | 859 | { |
860 | int flags = 0; | 860 | int flags = 0; |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 5a11078827ab..d0311a322ddd 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -243,6 +243,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
243 | memcpy(sta->sta.addr, addr, ETH_ALEN); | 243 | memcpy(sta->sta.addr, addr, ETH_ALEN); |
244 | sta->local = local; | 244 | sta->local = local; |
245 | sta->sdata = sdata; | 245 | sta->sdata = sdata; |
246 | sta->last_rx = jiffies; | ||
246 | 247 | ||
247 | ewma_init(&sta->avg_signal, 1024, 8); | 248 | ewma_init(&sta->avg_signal, 1024, 8); |
248 | 249 | ||
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index 8b4061049d76..e3c36a274412 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c | |||
@@ -160,6 +160,28 @@ gss_mech_get_by_name(const char *name) | |||
160 | 160 | ||
161 | EXPORT_SYMBOL_GPL(gss_mech_get_by_name); | 161 | EXPORT_SYMBOL_GPL(gss_mech_get_by_name); |
162 | 162 | ||
163 | struct gss_api_mech * | ||
164 | gss_mech_get_by_OID(struct xdr_netobj *obj) | ||
165 | { | ||
166 | struct gss_api_mech *pos, *gm = NULL; | ||
167 | |||
168 | spin_lock(®istered_mechs_lock); | ||
169 | list_for_each_entry(pos, ®istered_mechs, gm_list) { | ||
170 | if (obj->len == pos->gm_oid.len) { | ||
171 | if (0 == memcmp(obj->data, pos->gm_oid.data, obj->len)) { | ||
172 | if (try_module_get(pos->gm_owner)) | ||
173 | gm = pos; | ||
174 | break; | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | spin_unlock(®istered_mechs_lock); | ||
179 | return gm; | ||
180 | |||
181 | } | ||
182 | |||
183 | EXPORT_SYMBOL_GPL(gss_mech_get_by_OID); | ||
184 | |||
163 | static inline int | 185 | static inline int |
164 | mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor) | 186 | mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor) |
165 | { | 187 | { |
@@ -193,6 +215,22 @@ gss_mech_get_by_pseudoflavor(u32 pseudoflavor) | |||
193 | 215 | ||
194 | EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor); | 216 | EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor); |
195 | 217 | ||
218 | int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr) | ||
219 | { | ||
220 | struct gss_api_mech *pos = NULL; | ||
221 | int i = 0; | ||
222 | |||
223 | spin_lock(®istered_mechs_lock); | ||
224 | list_for_each_entry(pos, ®istered_mechs, gm_list) { | ||
225 | array_ptr[i] = pos->gm_pfs->pseudoflavor; | ||
226 | i++; | ||
227 | } | ||
228 | spin_unlock(®istered_mechs_lock); | ||
229 | return i; | ||
230 | } | ||
231 | |||
232 | EXPORT_SYMBOL_GPL(gss_mech_list_pseudoflavors); | ||
233 | |||
196 | u32 | 234 | u32 |
197 | gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service) | 235 | gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service) |
198 | { | 236 | { |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index be96d429b475..1e336a06d3e6 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -710,6 +710,8 @@ static void xs_reset_transport(struct sock_xprt *transport) | |||
710 | if (sk == NULL) | 710 | if (sk == NULL) |
711 | return; | 711 | return; |
712 | 712 | ||
713 | transport->srcport = 0; | ||
714 | |||
713 | write_lock_bh(&sk->sk_callback_lock); | 715 | write_lock_bh(&sk->sk_callback_lock); |
714 | transport->inet = NULL; | 716 | transport->inet = NULL; |
715 | transport->sock = NULL; | 717 | transport->sock = NULL; |
diff --git a/sound/core/init.c b/sound/core/init.c index 3e65da21a08c..a0080aa45ae9 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
@@ -848,6 +848,7 @@ int snd_card_file_add(struct snd_card *card, struct file *file) | |||
848 | return -ENOMEM; | 848 | return -ENOMEM; |
849 | mfile->file = file; | 849 | mfile->file = file; |
850 | mfile->disconnected_f_op = NULL; | 850 | mfile->disconnected_f_op = NULL; |
851 | INIT_LIST_HEAD(&mfile->shutdown_list); | ||
851 | spin_lock(&card->files_lock); | 852 | spin_lock(&card->files_lock); |
852 | if (card->shutdown) { | 853 | if (card->shutdown) { |
853 | spin_unlock(&card->files_lock); | 854 | spin_unlock(&card->files_lock); |
@@ -883,6 +884,9 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) | |||
883 | list_for_each_entry(mfile, &card->files_list, list) { | 884 | list_for_each_entry(mfile, &card->files_list, list) { |
884 | if (mfile->file == file) { | 885 | if (mfile->file == file) { |
885 | list_del(&mfile->list); | 886 | list_del(&mfile->list); |
887 | spin_lock(&shutdown_lock); | ||
888 | list_del(&mfile->shutdown_list); | ||
889 | spin_unlock(&shutdown_lock); | ||
886 | if (mfile->disconnected_f_op) | 890 | if (mfile->disconnected_f_op) |
887 | fops_put(mfile->disconnected_f_op); | 891 | fops_put(mfile->disconnected_f_op); |
888 | found = mfile; | 892 | found = mfile; |
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index ae42b6509ce4..fe5c8036beba 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -3201,15 +3201,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, | |||
3201 | EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); | 3201 | EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); |
3202 | #endif /* SNDRV_PCM_INFO_MMAP */ | 3202 | #endif /* SNDRV_PCM_INFO_MMAP */ |
3203 | 3203 | ||
3204 | /* mmap callback with pgprot_noncached */ | ||
3205 | int snd_pcm_lib_mmap_noncached(struct snd_pcm_substream *substream, | ||
3206 | struct vm_area_struct *area) | ||
3207 | { | ||
3208 | area->vm_page_prot = pgprot_noncached(area->vm_page_prot); | ||
3209 | return snd_pcm_default_mmap(substream, area); | ||
3210 | } | ||
3211 | EXPORT_SYMBOL(snd_pcm_lib_mmap_noncached); | ||
3212 | |||
3213 | /* | 3204 | /* |
3214 | * mmap DMA buffer | 3205 | * mmap DMA buffer |
3215 | */ | 3206 | */ |
diff --git a/sound/oss/dev_table.h b/sound/oss/dev_table.h index b7617bee6388..0199a317c5a9 100644 --- a/sound/oss/dev_table.h +++ b/sound/oss/dev_table.h | |||
@@ -271,7 +271,7 @@ struct synth_operations | |||
271 | void (*reset) (int dev); | 271 | void (*reset) (int dev); |
272 | void (*hw_control) (int dev, unsigned char *event); | 272 | void (*hw_control) (int dev, unsigned char *event); |
273 | int (*load_patch) (int dev, int format, const char __user *addr, | 273 | int (*load_patch) (int dev, int format, const char __user *addr, |
274 | int offs, int count, int pmgr_flag); | 274 | int count, int pmgr_flag); |
275 | void (*aftertouch) (int dev, int voice, int pressure); | 275 | void (*aftertouch) (int dev, int voice, int pressure); |
276 | void (*controller) (int dev, int voice, int ctrl_num, int value); | 276 | void (*controller) (int dev, int voice, int ctrl_num, int value); |
277 | void (*panning) (int dev, int voice, int value); | 277 | void (*panning) (int dev, int voice, int value); |
diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c index 3c09374ea5bf..2292c230d7e6 100644 --- a/sound/oss/midi_synth.c +++ b/sound/oss/midi_synth.c | |||
@@ -476,7 +476,7 @@ EXPORT_SYMBOL(midi_synth_hw_control); | |||
476 | 476 | ||
477 | int | 477 | int |
478 | midi_synth_load_patch(int dev, int format, const char __user *addr, | 478 | midi_synth_load_patch(int dev, int format, const char __user *addr, |
479 | int offs, int count, int pmgr_flag) | 479 | int count, int pmgr_flag) |
480 | { | 480 | { |
481 | int orig_dev = synth_devs[dev]->midi_dev; | 481 | int orig_dev = synth_devs[dev]->midi_dev; |
482 | 482 | ||
@@ -491,33 +491,29 @@ midi_synth_load_patch(int dev, int format, const char __user *addr, | |||
491 | if (!prefix_cmd(orig_dev, 0xf0)) | 491 | if (!prefix_cmd(orig_dev, 0xf0)) |
492 | return 0; | 492 | return 0; |
493 | 493 | ||
494 | /* Invalid patch format */ | ||
494 | if (format != SYSEX_PATCH) | 495 | if (format != SYSEX_PATCH) |
495 | { | ||
496 | /* printk("MIDI Error: Invalid patch format (key) 0x%x\n", format);*/ | ||
497 | return -EINVAL; | 496 | return -EINVAL; |
498 | } | 497 | |
498 | /* Patch header too short */ | ||
499 | if (count < hdr_size) | 499 | if (count < hdr_size) |
500 | { | ||
501 | /* printk("MIDI Error: Patch header too short\n");*/ | ||
502 | return -EINVAL; | 500 | return -EINVAL; |
503 | } | 501 | |
504 | count -= hdr_size; | 502 | count -= hdr_size; |
505 | 503 | ||
506 | /* | 504 | /* |
507 | * Copy the header from user space but ignore the first bytes which have | 505 | * Copy the header from user space |
508 | * been transferred already. | ||
509 | */ | 506 | */ |
510 | 507 | ||
511 | if(copy_from_user(&((char *) &sysex)[offs], &(addr)[offs], hdr_size - offs)) | 508 | if (copy_from_user(&sysex, addr, hdr_size)) |
512 | return -EFAULT; | 509 | return -EFAULT; |
513 | 510 | ||
514 | if (count < sysex.len) | 511 | /* Sysex record too short */ |
515 | { | 512 | if ((unsigned)count < (unsigned)sysex.len) |
516 | /* printk(KERN_WARNING "MIDI Warning: Sysex record too short (%d<%d)\n", count, (int) sysex.len);*/ | ||
517 | sysex.len = count; | 513 | sysex.len = count; |
518 | } | 514 | |
519 | left = sysex.len; | 515 | left = sysex.len; |
520 | src_offs = 0; | 516 | src_offs = 0; |
521 | 517 | ||
522 | for (i = 0; i < left && !signal_pending(current); i++) | 518 | for (i = 0; i < left && !signal_pending(current); i++) |
523 | { | 519 | { |
diff --git a/sound/oss/midi_synth.h b/sound/oss/midi_synth.h index 6bc9d00bc77c..b64ddd6c4abc 100644 --- a/sound/oss/midi_synth.h +++ b/sound/oss/midi_synth.h | |||
@@ -8,7 +8,7 @@ int midi_synth_open (int dev, int mode); | |||
8 | void midi_synth_close (int dev); | 8 | void midi_synth_close (int dev); |
9 | void midi_synth_hw_control (int dev, unsigned char *event); | 9 | void midi_synth_hw_control (int dev, unsigned char *event); |
10 | int midi_synth_load_patch (int dev, int format, const char __user * addr, | 10 | int midi_synth_load_patch (int dev, int format, const char __user * addr, |
11 | int offs, int count, int pmgr_flag); | 11 | int count, int pmgr_flag); |
12 | void midi_synth_panning (int dev, int channel, int pressure); | 12 | void midi_synth_panning (int dev, int channel, int pressure); |
13 | void midi_synth_aftertouch (int dev, int channel, int pressure); | 13 | void midi_synth_aftertouch (int dev, int channel, int pressure); |
14 | void midi_synth_controller (int dev, int channel, int ctrl_num, int value); | 14 | void midi_synth_controller (int dev, int channel, int ctrl_num, int value); |
diff --git a/sound/oss/opl3.c b/sound/oss/opl3.c index 938c48c43585..407cd677950b 100644 --- a/sound/oss/opl3.c +++ b/sound/oss/opl3.c | |||
@@ -820,7 +820,7 @@ static void opl3_hw_control(int dev, unsigned char *event) | |||
820 | } | 820 | } |
821 | 821 | ||
822 | static int opl3_load_patch(int dev, int format, const char __user *addr, | 822 | static int opl3_load_patch(int dev, int format, const char __user *addr, |
823 | int offs, int count, int pmgr_flag) | 823 | int count, int pmgr_flag) |
824 | { | 824 | { |
825 | struct sbi_instrument ins; | 825 | struct sbi_instrument ins; |
826 | 826 | ||
@@ -830,11 +830,7 @@ static int opl3_load_patch(int dev, int format, const char __user *addr, | |||
830 | return -EINVAL; | 830 | return -EINVAL; |
831 | } | 831 | } |
832 | 832 | ||
833 | /* | 833 | if (copy_from_user(&ins, addr, sizeof(ins))) |
834 | * What the fuck is going on here? We leave junk in the beginning | ||
835 | * of ins and then check the field pretty close to that beginning? | ||
836 | */ | ||
837 | if(copy_from_user(&((char *) &ins)[offs], addr + offs, sizeof(ins) - offs)) | ||
838 | return -EFAULT; | 834 | return -EFAULT; |
839 | 835 | ||
840 | if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) | 836 | if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) |
@@ -849,6 +845,10 @@ static int opl3_load_patch(int dev, int format, const char __user *addr, | |||
849 | 845 | ||
850 | static void opl3_panning(int dev, int voice, int value) | 846 | static void opl3_panning(int dev, int voice, int value) |
851 | { | 847 | { |
848 | |||
849 | if (voice < 0 || voice >= devc->nr_voice) | ||
850 | return; | ||
851 | |||
852 | devc->voc[voice].panning = value; | 852 | devc->voc[voice].panning = value; |
853 | } | 853 | } |
854 | 854 | ||
@@ -1066,8 +1066,15 @@ static int opl3_alloc_voice(int dev, int chn, int note, struct voice_alloc_info | |||
1066 | 1066 | ||
1067 | static void opl3_setup_voice(int dev, int voice, int chn) | 1067 | static void opl3_setup_voice(int dev, int voice, int chn) |
1068 | { | 1068 | { |
1069 | struct channel_info *info = | 1069 | struct channel_info *info; |
1070 | &synth_devs[dev]->chn_info[chn]; | 1070 | |
1071 | if (voice < 0 || voice >= devc->nr_voice) | ||
1072 | return; | ||
1073 | |||
1074 | if (chn < 0 || chn > 15) | ||
1075 | return; | ||
1076 | |||
1077 | info = &synth_devs[dev]->chn_info[chn]; | ||
1071 | 1078 | ||
1072 | opl3_set_instr(dev, voice, info->pgm_num); | 1079 | opl3_set_instr(dev, voice, info->pgm_num); |
1073 | 1080 | ||
diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c index 5ea1098ac427..30bcfe470f83 100644 --- a/sound/oss/sequencer.c +++ b/sound/oss/sequencer.c | |||
@@ -241,7 +241,7 @@ int sequencer_write(int dev, struct file *file, const char __user *buf, int coun | |||
241 | return -ENXIO; | 241 | return -ENXIO; |
242 | 242 | ||
243 | fmt = (*(short *) &event_rec[0]) & 0xffff; | 243 | fmt = (*(short *) &event_rec[0]) & 0xffff; |
244 | err = synth_devs[dev]->load_patch(dev, fmt, buf, p + 4, c, 0); | 244 | err = synth_devs[dev]->load_patch(dev, fmt, buf + p, c, 0); |
245 | if (err < 0) | 245 | if (err < 0) |
246 | return err; | 246 | return err; |
247 | 247 | ||
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index 0ac1f98d91a1..f53a31e939c1 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c | |||
@@ -22,21 +22,6 @@ | |||
22 | * for any purpose including commercial applications. | 22 | * for any purpose including commercial applications. |
23 | */ | 23 | */ |
24 | 24 | ||
25 | /* >0: print Hw params, timer vars. >1: print stream write/copy sizes */ | ||
26 | #define REALLY_VERBOSE_LOGGING 0 | ||
27 | |||
28 | #if REALLY_VERBOSE_LOGGING | ||
29 | #define VPRINTK1 snd_printd | ||
30 | #else | ||
31 | #define VPRINTK1(...) | ||
32 | #endif | ||
33 | |||
34 | #if REALLY_VERBOSE_LOGGING > 1 | ||
35 | #define VPRINTK2 snd_printd | ||
36 | #else | ||
37 | #define VPRINTK2(...) | ||
38 | #endif | ||
39 | |||
40 | #include "hpi_internal.h" | 25 | #include "hpi_internal.h" |
41 | #include "hpimsginit.h" | 26 | #include "hpimsginit.h" |
42 | #include "hpioctl.h" | 27 | #include "hpioctl.h" |
@@ -57,11 +42,25 @@ | |||
57 | #include <sound/tlv.h> | 42 | #include <sound/tlv.h> |
58 | #include <sound/hwdep.h> | 43 | #include <sound/hwdep.h> |
59 | 44 | ||
60 | |||
61 | MODULE_LICENSE("GPL"); | 45 | MODULE_LICENSE("GPL"); |
62 | MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>"); | 46 | MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>"); |
63 | MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx"); | 47 | MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx"); |
64 | 48 | ||
49 | #if defined CONFIG_SND_DEBUG_VERBOSE | ||
50 | /** | ||
51 | * snd_printddd - very verbose debug printk | ||
52 | * @format: format string | ||
53 | * | ||
54 | * Works like snd_printk() for debugging purposes. | ||
55 | * Ignored when CONFIG_SND_DEBUG_VERBOSE is not set. | ||
56 | * Must set snd module debug parameter to 3 to enable at runtime. | ||
57 | */ | ||
58 | #define snd_printddd(format, args...) \ | ||
59 | __snd_printk(3, __FILE__, __LINE__, format, ##args) | ||
60 | #else | ||
61 | #define snd_printddd(format, args...) do { } while (0) | ||
62 | #endif | ||
63 | |||
65 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* index 0-MAX */ | 64 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* index 0-MAX */ |
66 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | 65 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ |
67 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | 66 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; |
@@ -289,7 +288,6 @@ static u16 handle_error(u16 err, int line, char *filename) | |||
289 | #define hpi_handle_error(x) handle_error(x, __LINE__, __FILE__) | 288 | #define hpi_handle_error(x) handle_error(x, __LINE__, __FILE__) |
290 | 289 | ||
291 | /***************************** GENERAL PCM ****************/ | 290 | /***************************** GENERAL PCM ****************/ |
292 | #if REALLY_VERBOSE_LOGGING | ||
293 | static void print_hwparams(struct snd_pcm_hw_params *p) | 291 | static void print_hwparams(struct snd_pcm_hw_params *p) |
294 | { | 292 | { |
295 | snd_printd("HWPARAMS \n"); | 293 | snd_printd("HWPARAMS \n"); |
@@ -304,9 +302,6 @@ static void print_hwparams(struct snd_pcm_hw_params *p) | |||
304 | snd_printd("periods %d \n", params_periods(p)); | 302 | snd_printd("periods %d \n", params_periods(p)); |
305 | snd_printd("buffer_size %d \n", params_buffer_size(p)); | 303 | snd_printd("buffer_size %d \n", params_buffer_size(p)); |
306 | } | 304 | } |
307 | #else | ||
308 | #define print_hwparams(x) | ||
309 | #endif | ||
310 | 305 | ||
311 | static snd_pcm_format_t hpi_to_alsa_formats[] = { | 306 | static snd_pcm_format_t hpi_to_alsa_formats[] = { |
312 | -1, /* INVALID */ | 307 | -1, /* INVALID */ |
@@ -381,13 +376,13 @@ static void snd_card_asihpi_pcm_samplerates(struct snd_card_asihpi *asihpi, | |||
381 | "No local sampleclock, err %d\n", err); | 376 | "No local sampleclock, err %d\n", err); |
382 | } | 377 | } |
383 | 378 | ||
384 | for (idx = 0; idx < 100; idx++) { | 379 | for (idx = -1; idx < 100; idx++) { |
385 | if (hpi_sample_clock_query_local_rate( | 380 | if (idx == -1) { |
386 | h_control, idx, &sample_rate)) { | 381 | if (hpi_sample_clock_get_sample_rate(h_control, |
387 | if (!idx) | 382 | &sample_rate)) |
388 | snd_printk(KERN_ERR | 383 | continue; |
389 | "Local rate query failed\n"); | 384 | } else if (hpi_sample_clock_query_local_rate(h_control, |
390 | 385 | idx, &sample_rate)) { | |
391 | break; | 386 | break; |
392 | } | 387 | } |
393 | 388 | ||
@@ -440,8 +435,6 @@ static void snd_card_asihpi_pcm_samplerates(struct snd_card_asihpi *asihpi, | |||
440 | } | 435 | } |
441 | } | 436 | } |
442 | 437 | ||
443 | /* printk(KERN_INFO "Supported rates %X %d %d\n", | ||
444 | rates, rate_min, rate_max); */ | ||
445 | pcmhw->rates = rates; | 438 | pcmhw->rates = rates; |
446 | pcmhw->rate_min = rate_min; | 439 | pcmhw->rate_min = rate_min; |
447 | pcmhw->rate_max = rate_max; | 440 | pcmhw->rate_max = rate_max; |
@@ -466,7 +459,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, | |||
466 | if (err) | 459 | if (err) |
467 | return err; | 460 | return err; |
468 | 461 | ||
469 | VPRINTK1(KERN_INFO "format %d, %d chans, %d_hz\n", | 462 | snd_printdd("format %d, %d chans, %d_hz\n", |
470 | format, params_channels(params), | 463 | format, params_channels(params), |
471 | params_rate(params)); | 464 | params_rate(params)); |
472 | 465 | ||
@@ -489,13 +482,12 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, | |||
489 | err = hpi_stream_host_buffer_attach(dpcm->h_stream, | 482 | err = hpi_stream_host_buffer_attach(dpcm->h_stream, |
490 | params_buffer_bytes(params), runtime->dma_addr); | 483 | params_buffer_bytes(params), runtime->dma_addr); |
491 | if (err == 0) { | 484 | if (err == 0) { |
492 | VPRINTK1(KERN_INFO | 485 | snd_printdd( |
493 | "stream_host_buffer_attach succeeded %u %lu\n", | 486 | "stream_host_buffer_attach succeeded %u %lu\n", |
494 | params_buffer_bytes(params), | 487 | params_buffer_bytes(params), |
495 | (unsigned long)runtime->dma_addr); | 488 | (unsigned long)runtime->dma_addr); |
496 | } else { | 489 | } else { |
497 | snd_printd(KERN_INFO | 490 | snd_printd("stream_host_buffer_attach error %d\n", |
498 | "stream_host_buffer_attach error %d\n", | ||
499 | err); | 491 | err); |
500 | return -ENOMEM; | 492 | return -ENOMEM; |
501 | } | 493 | } |
@@ -504,7 +496,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, | |||
504 | &dpcm->hpi_buffer_attached, | 496 | &dpcm->hpi_buffer_attached, |
505 | NULL, NULL, NULL); | 497 | NULL, NULL, NULL); |
506 | 498 | ||
507 | VPRINTK1(KERN_INFO "stream_host_buffer_attach status 0x%x\n", | 499 | snd_printdd("stream_host_buffer_attach status 0x%x\n", |
508 | dpcm->hpi_buffer_attached); | 500 | dpcm->hpi_buffer_attached); |
509 | } | 501 | } |
510 | bytes_per_sec = params_rate(params) * params_channels(params); | 502 | bytes_per_sec = params_rate(params) * params_channels(params); |
@@ -517,7 +509,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, | |||
517 | dpcm->bytes_per_sec = bytes_per_sec; | 509 | dpcm->bytes_per_sec = bytes_per_sec; |
518 | dpcm->buffer_bytes = params_buffer_bytes(params); | 510 | dpcm->buffer_bytes = params_buffer_bytes(params); |
519 | dpcm->period_bytes = params_period_bytes(params); | 511 | dpcm->period_bytes = params_period_bytes(params); |
520 | VPRINTK1(KERN_INFO "buffer_bytes=%d, period_bytes=%d, bps=%d\n", | 512 | snd_printdd("buffer_bytes=%d, period_bytes=%d, bps=%d\n", |
521 | dpcm->buffer_bytes, dpcm->period_bytes, bytes_per_sec); | 513 | dpcm->buffer_bytes, dpcm->period_bytes, bytes_per_sec); |
522 | 514 | ||
523 | return 0; | 515 | return 0; |
@@ -573,7 +565,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, | |||
573 | struct snd_pcm_substream *s; | 565 | struct snd_pcm_substream *s; |
574 | u16 e; | 566 | u16 e; |
575 | 567 | ||
576 | VPRINTK1(KERN_INFO "%c%d trigger\n", | 568 | snd_printdd("%c%d trigger\n", |
577 | SCHR(substream->stream), substream->number); | 569 | SCHR(substream->stream), substream->number); |
578 | switch (cmd) { | 570 | switch (cmd) { |
579 | case SNDRV_PCM_TRIGGER_START: | 571 | case SNDRV_PCM_TRIGGER_START: |
@@ -597,7 +589,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, | |||
597 | * data?? | 589 | * data?? |
598 | */ | 590 | */ |
599 | unsigned int preload = ds->period_bytes * 1; | 591 | unsigned int preload = ds->period_bytes * 1; |
600 | VPRINTK2(KERN_INFO "%d preload x%x\n", s->number, preload); | 592 | snd_printddd("%d preload x%x\n", s->number, preload); |
601 | hpi_handle_error(hpi_outstream_write_buf( | 593 | hpi_handle_error(hpi_outstream_write_buf( |
602 | ds->h_stream, | 594 | ds->h_stream, |
603 | &runtime->dma_area[0], | 595 | &runtime->dma_area[0], |
@@ -607,7 +599,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, | |||
607 | } | 599 | } |
608 | 600 | ||
609 | if (card->support_grouping) { | 601 | if (card->support_grouping) { |
610 | VPRINTK1(KERN_INFO "\t%c%d group\n", | 602 | snd_printdd("\t%c%d group\n", |
611 | SCHR(s->stream), | 603 | SCHR(s->stream), |
612 | s->number); | 604 | s->number); |
613 | e = hpi_stream_group_add( | 605 | e = hpi_stream_group_add( |
@@ -622,7 +614,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, | |||
622 | } else | 614 | } else |
623 | break; | 615 | break; |
624 | } | 616 | } |
625 | VPRINTK1(KERN_INFO "start\n"); | 617 | snd_printdd("start\n"); |
626 | /* start the master stream */ | 618 | /* start the master stream */ |
627 | snd_card_asihpi_pcm_timer_start(substream); | 619 | snd_card_asihpi_pcm_timer_start(substream); |
628 | if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) || | 620 | if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) || |
@@ -644,14 +636,14 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, | |||
644 | s->runtime->status->state = SNDRV_PCM_STATE_SETUP; | 636 | s->runtime->status->state = SNDRV_PCM_STATE_SETUP; |
645 | 637 | ||
646 | if (card->support_grouping) { | 638 | if (card->support_grouping) { |
647 | VPRINTK1(KERN_INFO "\t%c%d group\n", | 639 | snd_printdd("\t%c%d group\n", |
648 | SCHR(s->stream), | 640 | SCHR(s->stream), |
649 | s->number); | 641 | s->number); |
650 | snd_pcm_trigger_done(s, substream); | 642 | snd_pcm_trigger_done(s, substream); |
651 | } else | 643 | } else |
652 | break; | 644 | break; |
653 | } | 645 | } |
654 | VPRINTK1(KERN_INFO "stop\n"); | 646 | snd_printdd("stop\n"); |
655 | 647 | ||
656 | /* _prepare and _hwparams reset the stream */ | 648 | /* _prepare and _hwparams reset the stream */ |
657 | hpi_handle_error(hpi_stream_stop(dpcm->h_stream)); | 649 | hpi_handle_error(hpi_stream_stop(dpcm->h_stream)); |
@@ -664,12 +656,12 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, | |||
664 | break; | 656 | break; |
665 | 657 | ||
666 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 658 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
667 | VPRINTK1(KERN_INFO "pause release\n"); | 659 | snd_printdd("pause release\n"); |
668 | hpi_handle_error(hpi_stream_start(dpcm->h_stream)); | 660 | hpi_handle_error(hpi_stream_start(dpcm->h_stream)); |
669 | snd_card_asihpi_pcm_timer_start(substream); | 661 | snd_card_asihpi_pcm_timer_start(substream); |
670 | break; | 662 | break; |
671 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 663 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
672 | VPRINTK1(KERN_INFO "pause\n"); | 664 | snd_printdd("pause\n"); |
673 | snd_card_asihpi_pcm_timer_stop(substream); | 665 | snd_card_asihpi_pcm_timer_stop(substream); |
674 | hpi_handle_error(hpi_stream_stop(dpcm->h_stream)); | 666 | hpi_handle_error(hpi_stream_stop(dpcm->h_stream)); |
675 | break; | 667 | break; |
@@ -741,7 +733,7 @@ static void snd_card_asihpi_timer_function(unsigned long data) | |||
741 | u16 state; | 733 | u16 state; |
742 | u32 buffer_size, bytes_avail, samples_played, on_card_bytes; | 734 | u32 buffer_size, bytes_avail, samples_played, on_card_bytes; |
743 | 735 | ||
744 | VPRINTK1(KERN_INFO "%c%d snd_card_asihpi_timer_function\n", | 736 | snd_printdd("%c%d snd_card_asihpi_timer_function\n", |
745 | SCHR(substream->stream), substream->number); | 737 | SCHR(substream->stream), substream->number); |
746 | 738 | ||
747 | /* find minimum newdata and buffer pos in group */ | 739 | /* find minimum newdata and buffer pos in group */ |
@@ -770,10 +762,10 @@ static void snd_card_asihpi_timer_function(unsigned long data) | |||
770 | if ((bytes_avail == 0) && | 762 | if ((bytes_avail == 0) && |
771 | (on_card_bytes < ds->pcm_buf_host_rw_ofs)) { | 763 | (on_card_bytes < ds->pcm_buf_host_rw_ofs)) { |
772 | hpi_handle_error(hpi_stream_start(ds->h_stream)); | 764 | hpi_handle_error(hpi_stream_start(ds->h_stream)); |
773 | VPRINTK1(KERN_INFO "P%d start\n", s->number); | 765 | snd_printdd("P%d start\n", s->number); |
774 | } | 766 | } |
775 | } else if (state == HPI_STATE_DRAINED) { | 767 | } else if (state == HPI_STATE_DRAINED) { |
776 | VPRINTK1(KERN_WARNING "P%d drained\n", | 768 | snd_printd(KERN_WARNING "P%d drained\n", |
777 | s->number); | 769 | s->number); |
778 | /*snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN); | 770 | /*snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN); |
779 | continue; */ | 771 | continue; */ |
@@ -794,13 +786,13 @@ static void snd_card_asihpi_timer_function(unsigned long data) | |||
794 | newdata); | 786 | newdata); |
795 | } | 787 | } |
796 | 788 | ||
797 | VPRINTK1(KERN_INFO "PB timer hw_ptr x%04lX, appl_ptr x%04lX\n", | 789 | snd_printdd("hw_ptr x%04lX, appl_ptr x%04lX\n", |
798 | (unsigned long)frames_to_bytes(runtime, | 790 | (unsigned long)frames_to_bytes(runtime, |
799 | runtime->status->hw_ptr), | 791 | runtime->status->hw_ptr), |
800 | (unsigned long)frames_to_bytes(runtime, | 792 | (unsigned long)frames_to_bytes(runtime, |
801 | runtime->control->appl_ptr)); | 793 | runtime->control->appl_ptr)); |
802 | 794 | ||
803 | VPRINTK1(KERN_INFO "%d %c%d S=%d, rw=%04X, dma=x%04X, left=x%04X," | 795 | snd_printdd("%d %c%d S=%d, rw=%04X, dma=x%04X, left=x%04X," |
804 | " aux=x%04X space=x%04X\n", | 796 | " aux=x%04X space=x%04X\n", |
805 | loops, SCHR(s->stream), s->number, | 797 | loops, SCHR(s->stream), s->number, |
806 | state, ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs, (int)bytes_avail, | 798 | state, ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs, (int)bytes_avail, |
@@ -822,7 +814,7 @@ static void snd_card_asihpi_timer_function(unsigned long data) | |||
822 | 814 | ||
823 | next_jiffies = max(next_jiffies, 1U); | 815 | next_jiffies = max(next_jiffies, 1U); |
824 | dpcm->timer.expires = jiffies + next_jiffies; | 816 | dpcm->timer.expires = jiffies + next_jiffies; |
825 | VPRINTK1(KERN_INFO "jif %d buf pos x%04X newdata x%04X xfer x%04X\n", | 817 | snd_printdd("jif %d buf pos x%04X newdata x%04X xfer x%04X\n", |
826 | next_jiffies, pcm_buf_dma_ofs, newdata, xfercount); | 818 | next_jiffies, pcm_buf_dma_ofs, newdata, xfercount); |
827 | 819 | ||
828 | snd_pcm_group_for_each_entry(s, substream) { | 820 | snd_pcm_group_for_each_entry(s, substream) { |
@@ -837,7 +829,7 @@ static void snd_card_asihpi_timer_function(unsigned long data) | |||
837 | if (xfercount && (on_card_bytes <= ds->period_bytes)) { | 829 | if (xfercount && (on_card_bytes <= ds->period_bytes)) { |
838 | if (card->support_mmap) { | 830 | if (card->support_mmap) { |
839 | if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 831 | if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
840 | VPRINTK2(KERN_INFO "P%d write x%04x\n", | 832 | snd_printddd("P%d write x%04x\n", |
841 | s->number, | 833 | s->number, |
842 | ds->period_bytes); | 834 | ds->period_bytes); |
843 | hpi_handle_error( | 835 | hpi_handle_error( |
@@ -848,7 +840,7 @@ static void snd_card_asihpi_timer_function(unsigned long data) | |||
848 | xfercount, | 840 | xfercount, |
849 | &ds->format)); | 841 | &ds->format)); |
850 | } else { | 842 | } else { |
851 | VPRINTK2(KERN_INFO "C%d read x%04x\n", | 843 | snd_printddd("C%d read x%04x\n", |
852 | s->number, | 844 | s->number, |
853 | xfercount); | 845 | xfercount); |
854 | hpi_handle_error( | 846 | hpi_handle_error( |
@@ -871,7 +863,7 @@ static void snd_card_asihpi_timer_function(unsigned long data) | |||
871 | static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream, | 863 | static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream, |
872 | unsigned int cmd, void *arg) | 864 | unsigned int cmd, void *arg) |
873 | { | 865 | { |
874 | /* snd_printd(KERN_INFO "Playback ioctl %d\n", cmd); */ | 866 | snd_printdd(KERN_INFO "Playback ioctl %d\n", cmd); |
875 | return snd_pcm_lib_ioctl(substream, cmd, arg); | 867 | return snd_pcm_lib_ioctl(substream, cmd, arg); |
876 | } | 868 | } |
877 | 869 | ||
@@ -881,7 +873,7 @@ static int snd_card_asihpi_playback_prepare(struct snd_pcm_substream * | |||
881 | struct snd_pcm_runtime *runtime = substream->runtime; | 873 | struct snd_pcm_runtime *runtime = substream->runtime; |
882 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; | 874 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; |
883 | 875 | ||
884 | VPRINTK1(KERN_INFO "playback prepare %d\n", substream->number); | 876 | snd_printdd("playback prepare %d\n", substream->number); |
885 | 877 | ||
886 | hpi_handle_error(hpi_outstream_reset(dpcm->h_stream)); | 878 | hpi_handle_error(hpi_outstream_reset(dpcm->h_stream)); |
887 | dpcm->pcm_buf_host_rw_ofs = 0; | 879 | dpcm->pcm_buf_host_rw_ofs = 0; |
@@ -898,7 +890,7 @@ snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream) | |||
898 | snd_pcm_uframes_t ptr; | 890 | snd_pcm_uframes_t ptr; |
899 | 891 | ||
900 | ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes); | 892 | ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes); |
901 | /* VPRINTK2(KERN_INFO "playback_pointer=x%04lx\n", (unsigned long)ptr); */ | 893 | snd_printddd("playback_pointer=x%04lx\n", (unsigned long)ptr); |
902 | return ptr; | 894 | return ptr; |
903 | } | 895 | } |
904 | 896 | ||
@@ -1014,12 +1006,13 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) | |||
1014 | 1006 | ||
1015 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | 1007 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, |
1016 | card->update_interval_frames); | 1008 | card->update_interval_frames); |
1009 | |||
1017 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | 1010 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, |
1018 | card->update_interval_frames * 2, UINT_MAX); | 1011 | card->update_interval_frames * 2, UINT_MAX); |
1019 | 1012 | ||
1020 | snd_pcm_set_sync(substream); | 1013 | snd_pcm_set_sync(substream); |
1021 | 1014 | ||
1022 | VPRINTK1(KERN_INFO "playback open\n"); | 1015 | snd_printdd("playback open\n"); |
1023 | 1016 | ||
1024 | return 0; | 1017 | return 0; |
1025 | } | 1018 | } |
@@ -1030,7 +1023,7 @@ static int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream) | |||
1030 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; | 1023 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; |
1031 | 1024 | ||
1032 | hpi_handle_error(hpi_outstream_close(dpcm->h_stream)); | 1025 | hpi_handle_error(hpi_outstream_close(dpcm->h_stream)); |
1033 | VPRINTK1(KERN_INFO "playback close\n"); | 1026 | snd_printdd("playback close\n"); |
1034 | 1027 | ||
1035 | return 0; | 1028 | return 0; |
1036 | } | 1029 | } |
@@ -1050,13 +1043,13 @@ static int snd_card_asihpi_playback_copy(struct snd_pcm_substream *substream, | |||
1050 | if (copy_from_user(runtime->dma_area, src, len)) | 1043 | if (copy_from_user(runtime->dma_area, src, len)) |
1051 | return -EFAULT; | 1044 | return -EFAULT; |
1052 | 1045 | ||
1053 | VPRINTK2(KERN_DEBUG "playback copy%d %u bytes\n", | 1046 | snd_printddd("playback copy%d %u bytes\n", |
1054 | substream->number, len); | 1047 | substream->number, len); |
1055 | 1048 | ||
1056 | hpi_handle_error(hpi_outstream_write_buf(dpcm->h_stream, | 1049 | hpi_handle_error(hpi_outstream_write_buf(dpcm->h_stream, |
1057 | runtime->dma_area, len, &dpcm->format)); | 1050 | runtime->dma_area, len, &dpcm->format)); |
1058 | 1051 | ||
1059 | dpcm->pcm_buf_host_rw_ofs = dpcm->pcm_buf_host_rw_ofs + len; | 1052 | dpcm->pcm_buf_host_rw_ofs += len; |
1060 | 1053 | ||
1061 | return 0; | 1054 | return 0; |
1062 | } | 1055 | } |
@@ -1066,16 +1059,11 @@ static int snd_card_asihpi_playback_silence(struct snd_pcm_substream * | |||
1066 | snd_pcm_uframes_t pos, | 1059 | snd_pcm_uframes_t pos, |
1067 | snd_pcm_uframes_t count) | 1060 | snd_pcm_uframes_t count) |
1068 | { | 1061 | { |
1069 | unsigned int len; | 1062 | /* Usually writes silence to DMA buffer, which should be overwritten |
1070 | struct snd_pcm_runtime *runtime = substream->runtime; | 1063 | by real audio later. Our fifos cannot be overwritten, and are not |
1071 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; | 1064 | free-running DMAs. Silence is output on fifo underflow. |
1072 | 1065 | This callback is still required to allow the copy callback to be used. | |
1073 | len = frames_to_bytes(runtime, count); | 1066 | */ |
1074 | VPRINTK1(KERN_INFO "playback silence %u bytes\n", len); | ||
1075 | |||
1076 | memset(runtime->dma_area, 0, len); | ||
1077 | hpi_handle_error(hpi_outstream_write_buf(dpcm->h_stream, | ||
1078 | runtime->dma_area, len, &dpcm->format)); | ||
1079 | return 0; | 1067 | return 0; |
1080 | } | 1068 | } |
1081 | 1069 | ||
@@ -1110,7 +1098,7 @@ snd_card_asihpi_capture_pointer(struct snd_pcm_substream *substream) | |||
1110 | struct snd_pcm_runtime *runtime = substream->runtime; | 1098 | struct snd_pcm_runtime *runtime = substream->runtime; |
1111 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; | 1099 | struct snd_card_asihpi_pcm *dpcm = runtime->private_data; |
1112 | 1100 | ||
1113 | VPRINTK2(KERN_INFO "capture pointer %d=%d\n", | 1101 | snd_printddd("capture pointer %d=%d\n", |
1114 | substream->number, dpcm->pcm_buf_dma_ofs); | 1102 | substream->number, dpcm->pcm_buf_dma_ofs); |
1115 | /* NOTE Unlike playback can't use actual samples_played | 1103 | /* NOTE Unlike playback can't use actual samples_played |
1116 | for the capture position, because those samples aren't yet in | 1104 | for the capture position, because those samples aren't yet in |
@@ -1135,7 +1123,7 @@ static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream) | |||
1135 | dpcm->pcm_buf_dma_ofs = 0; | 1123 | dpcm->pcm_buf_dma_ofs = 0; |
1136 | dpcm->pcm_buf_elapsed_dma_ofs = 0; | 1124 | dpcm->pcm_buf_elapsed_dma_ofs = 0; |
1137 | 1125 | ||
1138 | VPRINTK1("Capture Prepare %d\n", substream->number); | 1126 | snd_printdd("Capture Prepare %d\n", substream->number); |
1139 | return 0; | 1127 | return 0; |
1140 | } | 1128 | } |
1141 | 1129 | ||
@@ -1198,7 +1186,7 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream) | |||
1198 | if (dpcm == NULL) | 1186 | if (dpcm == NULL) |
1199 | return -ENOMEM; | 1187 | return -ENOMEM; |
1200 | 1188 | ||
1201 | VPRINTK1("hpi_instream_open adapter %d stream %d\n", | 1189 | snd_printdd("capture open adapter %d stream %d\n", |
1202 | card->adapter_index, substream->number); | 1190 | card->adapter_index, substream->number); |
1203 | 1191 | ||
1204 | err = hpi_handle_error( | 1192 | err = hpi_handle_error( |
@@ -1268,7 +1256,7 @@ static int snd_card_asihpi_capture_copy(struct snd_pcm_substream *substream, | |||
1268 | 1256 | ||
1269 | len = frames_to_bytes(runtime, count); | 1257 | len = frames_to_bytes(runtime, count); |
1270 | 1258 | ||
1271 | VPRINTK2(KERN_INFO "capture copy%d %d bytes\n", substream->number, len); | 1259 | snd_printddd("capture copy%d %d bytes\n", substream->number, len); |
1272 | hpi_handle_error(hpi_instream_read_buf(dpcm->h_stream, | 1260 | hpi_handle_error(hpi_instream_read_buf(dpcm->h_stream, |
1273 | runtime->dma_area, len)); | 1261 | runtime->dma_area, len)); |
1274 | 1262 | ||
@@ -2887,6 +2875,9 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, | |||
2887 | if (err) | 2875 | if (err) |
2888 | asihpi->update_interval_frames = 512; | 2876 | asihpi->update_interval_frames = 512; |
2889 | 2877 | ||
2878 | if (!asihpi->support_mmap) | ||
2879 | asihpi->update_interval_frames *= 2; | ||
2880 | |||
2890 | hpi_handle_error(hpi_instream_open(asihpi->adapter_index, | 2881 | hpi_handle_error(hpi_instream_open(asihpi->adapter_index, |
2891 | 0, &h_stream)); | 2882 | 0, &h_stream)); |
2892 | 2883 | ||
@@ -2909,7 +2900,6 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, | |||
2909 | asihpi->support_mrx | 2900 | asihpi->support_mrx |
2910 | ); | 2901 | ); |
2911 | 2902 | ||
2912 | |||
2913 | err = snd_card_asihpi_pcm_new(asihpi, 0, pcm_substreams); | 2903 | err = snd_card_asihpi_pcm_new(asihpi, 0, pcm_substreams); |
2914 | if (err < 0) { | 2904 | if (err < 0) { |
2915 | snd_printk(KERN_ERR "pcm_new failed\n"); | 2905 | snd_printk(KERN_ERR "pcm_new failed\n"); |
@@ -2944,6 +2934,7 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, | |||
2944 | sprintf(card->longname, "%s %i", | 2934 | sprintf(card->longname, "%s %i", |
2945 | card->shortname, asihpi->adapter_index); | 2935 | card->shortname, asihpi->adapter_index); |
2946 | err = snd_card_register(card); | 2936 | err = snd_card_register(card); |
2937 | |||
2947 | if (!err) { | 2938 | if (!err) { |
2948 | hpi_card->snd_card_asihpi = card; | 2939 | hpi_card->snd_card_asihpi = card; |
2949 | dev++; | 2940 | dev++; |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 734c6ee55d8a..2942d2a9ea10 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -4256,6 +4256,84 @@ static int ad1984a_thinkpad_init(struct hda_codec *codec) | |||
4256 | } | 4256 | } |
4257 | 4257 | ||
4258 | /* | 4258 | /* |
4259 | * Precision R5500 | ||
4260 | * 0x12 - HP/line-out | ||
4261 | * 0x13 - speaker (mono) | ||
4262 | * 0x15 - mic-in | ||
4263 | */ | ||
4264 | |||
4265 | static struct hda_verb ad1984a_precision_verbs[] = { | ||
4266 | /* Unmute main output path */ | ||
4267 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ | ||
4268 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */ | ||
4269 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) + 0x17}, /* 0dB */ | ||
4270 | /* Analog mixer; mute as default */ | ||
4271 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
4272 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
4273 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
4274 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
4275 | {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
4276 | /* Select mic as input */ | ||
4277 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
4278 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x27}, /* 0dB */ | ||
4279 | /* Configure as mic */ | ||
4280 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
4281 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ | ||
4282 | /* HP unmute */ | ||
4283 | {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
4284 | /* turn on EAPD */ | ||
4285 | {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, | ||
4286 | /* unsolicited event for pin-sense */ | ||
4287 | {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, | ||
4288 | { } /* end */ | ||
4289 | }; | ||
4290 | |||
4291 | static struct snd_kcontrol_new ad1984a_precision_mixers[] = { | ||
4292 | HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||
4293 | HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
4294 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||
4295 | HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||
4296 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
4297 | HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
4298 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT), | ||
4299 | HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
4300 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
4301 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
4302 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
4303 | { } /* end */ | ||
4304 | }; | ||
4305 | |||
4306 | |||
4307 | /* mute internal speaker if HP is plugged */ | ||
4308 | static void ad1984a_precision_automute(struct hda_codec *codec) | ||
4309 | { | ||
4310 | unsigned int present; | ||
4311 | |||
4312 | present = snd_hda_jack_detect(codec, 0x12); | ||
4313 | snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0, | ||
4314 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
4315 | } | ||
4316 | |||
4317 | |||
4318 | /* unsolicited event for HP jack sensing */ | ||
4319 | static void ad1984a_precision_unsol_event(struct hda_codec *codec, | ||
4320 | unsigned int res) | ||
4321 | { | ||
4322 | if ((res >> 26) != AD1884A_HP_EVENT) | ||
4323 | return; | ||
4324 | ad1984a_precision_automute(codec); | ||
4325 | } | ||
4326 | |||
4327 | /* initialize jack-sensing, too */ | ||
4328 | static int ad1984a_precision_init(struct hda_codec *codec) | ||
4329 | { | ||
4330 | ad198x_init(codec); | ||
4331 | ad1984a_precision_automute(codec); | ||
4332 | return 0; | ||
4333 | } | ||
4334 | |||
4335 | |||
4336 | /* | ||
4259 | * HP Touchsmart | 4337 | * HP Touchsmart |
4260 | * port-A (0x11) - front hp-out | 4338 | * port-A (0x11) - front hp-out |
4261 | * port-B (0x14) - unused | 4339 | * port-B (0x14) - unused |
@@ -4384,6 +4462,7 @@ enum { | |||
4384 | AD1884A_MOBILE, | 4462 | AD1884A_MOBILE, |
4385 | AD1884A_THINKPAD, | 4463 | AD1884A_THINKPAD, |
4386 | AD1984A_TOUCHSMART, | 4464 | AD1984A_TOUCHSMART, |
4465 | AD1984A_PRECISION, | ||
4387 | AD1884A_MODELS | 4466 | AD1884A_MODELS |
4388 | }; | 4467 | }; |
4389 | 4468 | ||
@@ -4393,9 +4472,11 @@ static const char * const ad1884a_models[AD1884A_MODELS] = { | |||
4393 | [AD1884A_MOBILE] = "mobile", | 4472 | [AD1884A_MOBILE] = "mobile", |
4394 | [AD1884A_THINKPAD] = "thinkpad", | 4473 | [AD1884A_THINKPAD] = "thinkpad", |
4395 | [AD1984A_TOUCHSMART] = "touchsmart", | 4474 | [AD1984A_TOUCHSMART] = "touchsmart", |
4475 | [AD1984A_PRECISION] = "precision", | ||
4396 | }; | 4476 | }; |
4397 | 4477 | ||
4398 | static struct snd_pci_quirk ad1884a_cfg_tbl[] = { | 4478 | static struct snd_pci_quirk ad1884a_cfg_tbl[] = { |
4479 | SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION), | ||
4399 | SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), | 4480 | SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), |
4400 | SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP), | 4481 | SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP), |
4401 | SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE), | 4482 | SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE), |
@@ -4489,6 +4570,14 @@ static int patch_ad1884a(struct hda_codec *codec) | |||
4489 | codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event; | 4570 | codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event; |
4490 | codec->patch_ops.init = ad1984a_thinkpad_init; | 4571 | codec->patch_ops.init = ad1984a_thinkpad_init; |
4491 | break; | 4572 | break; |
4573 | case AD1984A_PRECISION: | ||
4574 | spec->mixers[0] = ad1984a_precision_mixers; | ||
4575 | spec->init_verbs[spec->num_init_verbs++] = | ||
4576 | ad1984a_precision_verbs; | ||
4577 | spec->multiout.dig_out_nid = 0; | ||
4578 | codec->patch_ops.unsol_event = ad1984a_precision_unsol_event; | ||
4579 | codec->patch_ops.init = ad1984a_precision_init; | ||
4580 | break; | ||
4492 | case AD1984A_TOUCHSMART: | 4581 | case AD1984A_TOUCHSMART: |
4493 | spec->mixers[0] = ad1984a_touchsmart_mixers; | 4582 | spec->mixers[0] = ad1984a_touchsmart_mixers; |
4494 | spec->init_verbs[0] = ad1984a_touchsmart_verbs; | 4583 | spec->init_verbs[0] = ad1984a_touchsmart_verbs; |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5d582de91c19..0ef0035fe99f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -1290,7 +1290,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) | |||
1290 | case 0x10ec0883: | 1290 | case 0x10ec0883: |
1291 | case 0x10ec0885: | 1291 | case 0x10ec0885: |
1292 | case 0x10ec0887: | 1292 | case 0x10ec0887: |
1293 | case 0x10ec0889: | 1293 | /*case 0x10ec0889:*/ /* this causes an SPDIF problem */ |
1294 | alc889_coef_init(codec); | 1294 | alc889_coef_init(codec); |
1295 | break; | 1295 | break; |
1296 | case 0x10ec0888: | 1296 | case 0x10ec0888: |
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index c0dcfca9b5b5..c66d3f64dcf8 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h | |||
@@ -1568,6 +1568,46 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
1568 | } | 1568 | } |
1569 | }, | 1569 | }, |
1570 | { | 1570 | { |
1571 | USB_DEVICE_VENDOR_SPEC(0x0582, 0x0104), | ||
1572 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
1573 | /* .vendor_name = "Roland", */ | ||
1574 | /* .product_name = "UM-1G", */ | ||
1575 | .ifnum = 0, | ||
1576 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
1577 | .data = & (const struct snd_usb_midi_endpoint_info) { | ||
1578 | .out_cables = 0x0001, | ||
1579 | .in_cables = 0x0001 | ||
1580 | } | ||
1581 | } | ||
1582 | }, | ||
1583 | { | ||
1584 | /* Boss JS-8 Jam Station */ | ||
1585 | USB_DEVICE(0x0582, 0x0109), | ||
1586 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
1587 | /* .vendor_name = "BOSS", */ | ||
1588 | /* .product_name = "JS-8", */ | ||
1589 | .ifnum = QUIRK_ANY_INTERFACE, | ||
1590 | .type = QUIRK_COMPOSITE, | ||
1591 | .data = (const struct snd_usb_audio_quirk[]) { | ||
1592 | { | ||
1593 | .ifnum = 0, | ||
1594 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
1595 | }, | ||
1596 | { | ||
1597 | .ifnum = 1, | ||
1598 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
1599 | }, | ||
1600 | { | ||
1601 | .ifnum = 2, | ||
1602 | .type = QUIRK_MIDI_STANDARD_INTERFACE | ||
1603 | }, | ||
1604 | { | ||
1605 | .ifnum = -1 | ||
1606 | } | ||
1607 | } | ||
1608 | } | ||
1609 | }, | ||
1610 | { | ||
1571 | /* has ID 0x0110 when not in Advanced Driver mode */ | 1611 | /* has ID 0x0110 when not in Advanced Driver mode */ |
1572 | USB_DEVICE_VENDOR_SPEC(0x0582, 0x010f), | 1612 | USB_DEVICE_VENDOR_SPEC(0x0582, 0x010f), |
1573 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | 1613 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { |
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 695de4b5ae63..e18eb7ed30ae 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -42,9 +42,9 @@ static const char *sym_hist_filter; | |||
42 | 42 | ||
43 | static int perf_evlist__add_sample(struct perf_evlist *evlist, | 43 | static int perf_evlist__add_sample(struct perf_evlist *evlist, |
44 | struct perf_sample *sample, | 44 | struct perf_sample *sample, |
45 | struct perf_evsel *evsel, | ||
45 | struct addr_location *al) | 46 | struct addr_location *al) |
46 | { | 47 | { |
47 | struct perf_evsel *evsel; | ||
48 | struct hist_entry *he; | 48 | struct hist_entry *he; |
49 | int ret; | 49 | int ret; |
50 | 50 | ||
@@ -59,18 +59,6 @@ static int perf_evlist__add_sample(struct perf_evlist *evlist, | |||
59 | return 0; | 59 | return 0; |
60 | } | 60 | } |
61 | 61 | ||
62 | evsel = perf_evlist__id2evsel(evlist, sample->id); | ||
63 | if (evsel == NULL) { | ||
64 | /* | ||
65 | * FIXME: Propagate this back, but at least we're in a builtin, | ||
66 | * where exit() is allowed. ;-) | ||
67 | */ | ||
68 | ui__warning("Invalid %s file, contains samples with id not in " | ||
69 | "its header!\n", input_name); | ||
70 | exit_browser(0); | ||
71 | exit(1); | ||
72 | } | ||
73 | |||
74 | he = __hists__add_entry(&evsel->hists, al, NULL, 1); | 62 | he = __hists__add_entry(&evsel->hists, al, NULL, 1); |
75 | if (he == NULL) | 63 | if (he == NULL) |
76 | return -ENOMEM; | 64 | return -ENOMEM; |
@@ -92,6 +80,7 @@ static int perf_evlist__add_sample(struct perf_evlist *evlist, | |||
92 | 80 | ||
93 | static int process_sample_event(union perf_event *event, | 81 | static int process_sample_event(union perf_event *event, |
94 | struct perf_sample *sample, | 82 | struct perf_sample *sample, |
83 | struct perf_evsel *evsel, | ||
95 | struct perf_session *session) | 84 | struct perf_session *session) |
96 | { | 85 | { |
97 | struct addr_location al; | 86 | struct addr_location al; |
@@ -103,7 +92,8 @@ static int process_sample_event(union perf_event *event, | |||
103 | return -1; | 92 | return -1; |
104 | } | 93 | } |
105 | 94 | ||
106 | if (!al.filtered && perf_evlist__add_sample(session->evlist, sample, &al)) { | 95 | if (!al.filtered && |
96 | perf_evlist__add_sample(session->evlist, sample, evsel, &al)) { | ||
107 | pr_warning("problem incrementing symbol count, " | 97 | pr_warning("problem incrementing symbol count, " |
108 | "skipping event\n"); | 98 | "skipping event\n"); |
109 | return -1; | 99 | return -1; |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 6b7d91160ecb..e8219990f8b8 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -32,6 +32,7 @@ static int hists__add_entry(struct hists *self, | |||
32 | 32 | ||
33 | static int diff__process_sample_event(union perf_event *event, | 33 | static int diff__process_sample_event(union perf_event *event, |
34 | struct perf_sample *sample, | 34 | struct perf_sample *sample, |
35 | struct perf_evsel *evsel __used, | ||
35 | struct perf_session *session) | 36 | struct perf_session *session) |
36 | { | 37 | { |
37 | struct addr_location al; | 38 | struct addr_location al; |
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index e29f04ed3396..8dfc12bb119b 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
@@ -43,6 +43,14 @@ static int perf_event__repipe(union perf_event *event, | |||
43 | return perf_event__repipe_synth(event, session); | 43 | return perf_event__repipe_synth(event, session); |
44 | } | 44 | } |
45 | 45 | ||
46 | static int perf_event__repipe_sample(union perf_event *event, | ||
47 | struct perf_sample *sample __used, | ||
48 | struct perf_evsel *evsel __used, | ||
49 | struct perf_session *session) | ||
50 | { | ||
51 | return perf_event__repipe_synth(event, session); | ||
52 | } | ||
53 | |||
46 | static int perf_event__repipe_mmap(union perf_event *event, | 54 | static int perf_event__repipe_mmap(union perf_event *event, |
47 | struct perf_sample *sample, | 55 | struct perf_sample *sample, |
48 | struct perf_session *session) | 56 | struct perf_session *session) |
@@ -124,6 +132,7 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session) | |||
124 | 132 | ||
125 | static int perf_event__inject_buildid(union perf_event *event, | 133 | static int perf_event__inject_buildid(union perf_event *event, |
126 | struct perf_sample *sample, | 134 | struct perf_sample *sample, |
135 | struct perf_evsel *evsel __used, | ||
127 | struct perf_session *session) | 136 | struct perf_session *session) |
128 | { | 137 | { |
129 | struct addr_location al; | 138 | struct addr_location al; |
@@ -164,7 +173,7 @@ repipe: | |||
164 | } | 173 | } |
165 | 174 | ||
166 | struct perf_event_ops inject_ops = { | 175 | struct perf_event_ops inject_ops = { |
167 | .sample = perf_event__repipe, | 176 | .sample = perf_event__repipe_sample, |
168 | .mmap = perf_event__repipe, | 177 | .mmap = perf_event__repipe, |
169 | .comm = perf_event__repipe, | 178 | .comm = perf_event__repipe, |
170 | .fork = perf_event__repipe, | 179 | .fork = perf_event__repipe, |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 7f618f4e7b79..225e963df105 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
@@ -305,6 +305,7 @@ static void process_raw_event(union perf_event *raw_event __used, void *data, | |||
305 | 305 | ||
306 | static int process_sample_event(union perf_event *event, | 306 | static int process_sample_event(union perf_event *event, |
307 | struct perf_sample *sample, | 307 | struct perf_sample *sample, |
308 | struct perf_evsel *evsel __used, | ||
308 | struct perf_session *session) | 309 | struct perf_session *session) |
309 | { | 310 | { |
310 | struct thread *thread = perf_session__findnew(session, event->ip.pid); | 311 | struct thread *thread = perf_session__findnew(session, event->ip.pid); |
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 7a2a79d2cf2c..9ac05aafd9b2 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c | |||
@@ -845,7 +845,9 @@ static void dump_info(void) | |||
845 | die("Unknown type of information\n"); | 845 | die("Unknown type of information\n"); |
846 | } | 846 | } |
847 | 847 | ||
848 | static int process_sample_event(union perf_event *event, struct perf_sample *sample, | 848 | static int process_sample_event(union perf_event *event, |
849 | struct perf_sample *sample, | ||
850 | struct perf_evsel *evsel __used, | ||
849 | struct perf_session *s) | 851 | struct perf_session *s) |
850 | { | 852 | { |
851 | struct thread *thread = perf_session__findnew(s, sample->tid); | 853 | struct thread *thread = perf_session__findnew(s, sample->tid); |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index b1b82009ab9b..498c6f70a747 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -50,12 +50,12 @@ static symbol_filter_t annotate_init; | |||
50 | 50 | ||
51 | static int perf_session__add_hist_entry(struct perf_session *session, | 51 | static int perf_session__add_hist_entry(struct perf_session *session, |
52 | struct addr_location *al, | 52 | struct addr_location *al, |
53 | struct perf_sample *sample) | 53 | struct perf_sample *sample, |
54 | struct perf_evsel *evsel) | ||
54 | { | 55 | { |
55 | struct symbol *parent = NULL; | 56 | struct symbol *parent = NULL; |
56 | int err = 0; | 57 | int err = 0; |
57 | struct hist_entry *he; | 58 | struct hist_entry *he; |
58 | struct perf_evsel *evsel; | ||
59 | 59 | ||
60 | if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { | 60 | if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { |
61 | err = perf_session__resolve_callchain(session, al->thread, | 61 | err = perf_session__resolve_callchain(session, al->thread, |
@@ -64,18 +64,6 @@ static int perf_session__add_hist_entry(struct perf_session *session, | |||
64 | return err; | 64 | return err; |
65 | } | 65 | } |
66 | 66 | ||
67 | evsel = perf_evlist__id2evsel(session->evlist, sample->id); | ||
68 | if (evsel == NULL) { | ||
69 | /* | ||
70 | * FIXME: Propagate this back, but at least we're in a builtin, | ||
71 | * where exit() is allowed. ;-) | ||
72 | */ | ||
73 | ui__warning("Invalid %s file, contains samples with id %" PRIu64 " not in " | ||
74 | "its header!\n", input_name, sample->id); | ||
75 | exit_browser(0); | ||
76 | exit(1); | ||
77 | } | ||
78 | |||
79 | he = __hists__add_entry(&evsel->hists, al, parent, sample->period); | 67 | he = __hists__add_entry(&evsel->hists, al, parent, sample->period); |
80 | if (he == NULL) | 68 | if (he == NULL) |
81 | return -ENOMEM; | 69 | return -ENOMEM; |
@@ -113,6 +101,7 @@ out: | |||
113 | 101 | ||
114 | static int process_sample_event(union perf_event *event, | 102 | static int process_sample_event(union perf_event *event, |
115 | struct perf_sample *sample, | 103 | struct perf_sample *sample, |
104 | struct perf_evsel *evsel, | ||
116 | struct perf_session *session) | 105 | struct perf_session *session) |
117 | { | 106 | { |
118 | struct addr_location al; | 107 | struct addr_location al; |
@@ -127,7 +116,7 @@ static int process_sample_event(union perf_event *event, | |||
127 | if (al.filtered || (hide_unresolved && al.sym == NULL)) | 116 | if (al.filtered || (hide_unresolved && al.sym == NULL)) |
128 | return 0; | 117 | return 0; |
129 | 118 | ||
130 | if (perf_session__add_hist_entry(session, &al, sample)) { | 119 | if (perf_session__add_hist_entry(session, &al, sample, evsel)) { |
131 | pr_debug("problem incrementing symbol period, skipping event\n"); | 120 | pr_debug("problem incrementing symbol period, skipping event\n"); |
132 | return -1; | 121 | return -1; |
133 | } | 122 | } |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index a32f411faeac..dcfe8873c9a1 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -1603,6 +1603,7 @@ static void process_raw_event(union perf_event *raw_event __used, | |||
1603 | 1603 | ||
1604 | static int process_sample_event(union perf_event *event, | 1604 | static int process_sample_event(union perf_event *event, |
1605 | struct perf_sample *sample, | 1605 | struct perf_sample *sample, |
1606 | struct perf_evsel *evsel __used, | ||
1606 | struct perf_session *session) | 1607 | struct perf_session *session) |
1607 | { | 1608 | { |
1608 | struct thread *thread; | 1609 | struct thread *thread; |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 9f5fc5492141..ac574ea23917 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -162,19 +162,11 @@ static void print_sample_start(struct perf_sample *sample, | |||
162 | 162 | ||
163 | static void process_event(union perf_event *event __unused, | 163 | static void process_event(union perf_event *event __unused, |
164 | struct perf_sample *sample, | 164 | struct perf_sample *sample, |
165 | struct perf_evsel *evsel, | ||
165 | struct perf_session *session, | 166 | struct perf_session *session, |
166 | struct thread *thread) | 167 | struct thread *thread) |
167 | { | 168 | { |
168 | struct perf_event_attr *attr; | 169 | struct perf_event_attr *attr = &evsel->attr; |
169 | struct perf_evsel *evsel; | ||
170 | |||
171 | evsel = perf_evlist__id2evsel(session->evlist, sample->id); | ||
172 | if (evsel == NULL) { | ||
173 | pr_err("Invalid data. Contains samples with id not in " | ||
174 | "its header!\n"); | ||
175 | return; | ||
176 | } | ||
177 | attr = &evsel->attr; | ||
178 | 170 | ||
179 | if (output_fields[attr->type] == 0) | 171 | if (output_fields[attr->type] == 0) |
180 | return; | 172 | return; |
@@ -244,6 +236,7 @@ static char const *input_name = "perf.data"; | |||
244 | 236 | ||
245 | static int process_sample_event(union perf_event *event, | 237 | static int process_sample_event(union perf_event *event, |
246 | struct perf_sample *sample, | 238 | struct perf_sample *sample, |
239 | struct perf_evsel *evsel, | ||
247 | struct perf_session *session) | 240 | struct perf_session *session) |
248 | { | 241 | { |
249 | struct thread *thread = perf_session__findnew(session, event->ip.pid); | 242 | struct thread *thread = perf_session__findnew(session, event->ip.pid); |
@@ -264,7 +257,7 @@ static int process_sample_event(union perf_event *event, | |||
264 | last_timestamp = sample->time; | 257 | last_timestamp = sample->time; |
265 | return 0; | 258 | return 0; |
266 | } | 259 | } |
267 | scripting_ops->process_event(event, sample, session, thread); | 260 | scripting_ops->process_event(event, sample, evsel, session, thread); |
268 | 261 | ||
269 | session->hists.stats.total_period += sample->period; | 262 | session->hists.stats.total_period += sample->period; |
270 | return 0; | 263 | return 0; |
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 67c0459dc325..aa26f4d66d10 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
@@ -488,6 +488,7 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) | |||
488 | 488 | ||
489 | static int process_sample_event(union perf_event *event __used, | 489 | static int process_sample_event(union perf_event *event __used, |
490 | struct perf_sample *sample, | 490 | struct perf_sample *sample, |
491 | struct perf_evsel *evsel __used, | ||
491 | struct perf_session *session) | 492 | struct perf_session *session) |
492 | { | 493 | { |
493 | struct trace_entry *te; | 494 | struct trace_entry *te; |
@@ -506,6 +507,16 @@ static int process_sample_event(union perf_event *event __used, | |||
506 | struct power_entry_old *peo; | 507 | struct power_entry_old *peo; |
507 | peo = (void *)te; | 508 | peo = (void *)te; |
508 | #endif | 509 | #endif |
510 | /* | ||
511 | * FIXME: use evsel, its already mapped from id to perf_evsel, | ||
512 | * remove perf_header__find_event infrastructure bits. | ||
513 | * Mapping all these "power:cpu_idle" strings to the tracepoint | ||
514 | * ID and then just comparing against evsel->attr.config. | ||
515 | * | ||
516 | * e.g.: | ||
517 | * | ||
518 | * if (evsel->attr.config == power_cpu_idle_id) | ||
519 | */ | ||
509 | event_str = perf_header__find_event(te->type); | 520 | event_str = perf_header__find_event(te->type); |
510 | 521 | ||
511 | if (!event_str) | 522 | if (!event_str) |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 70f1075cc5b0..676b4fb0070f 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -515,7 +515,9 @@ static void handle_keypress(struct perf_session *session, int c) | |||
515 | break; | 515 | break; |
516 | case 'E': | 516 | case 'E': |
517 | if (top.evlist->nr_entries > 1) { | 517 | if (top.evlist->nr_entries > 1) { |
518 | int counter; | 518 | /* Select 0 as the default event: */ |
519 | int counter = 0; | ||
520 | |||
519 | fprintf(stderr, "\nAvailable events:"); | 521 | fprintf(stderr, "\nAvailable events:"); |
520 | 522 | ||
521 | list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) | 523 | list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) |
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 31f934af9861..a91cd99f26ea 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | static int build_id__mark_dso_hit(union perf_event *event, | 17 | static int build_id__mark_dso_hit(union perf_event *event, |
18 | struct perf_sample *sample __used, | 18 | struct perf_sample *sample __used, |
19 | struct perf_evsel *evsel __used, | ||
19 | struct perf_session *session) | 20 | struct perf_session *session) |
20 | { | 21 | { |
21 | struct addr_location al; | 22 | struct addr_location al; |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index e5230c0ef95b..93862a8027ea 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -695,13 +695,50 @@ out: | |||
695 | return err; | 695 | return err; |
696 | } | 696 | } |
697 | 697 | ||
698 | static int perf_header__read_build_ids_abi_quirk(struct perf_header *header, | ||
699 | int input, u64 offset, u64 size) | ||
700 | { | ||
701 | struct perf_session *session = container_of(header, struct perf_session, header); | ||
702 | struct { | ||
703 | struct perf_event_header header; | ||
704 | u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))]; | ||
705 | char filename[0]; | ||
706 | } old_bev; | ||
707 | struct build_id_event bev; | ||
708 | char filename[PATH_MAX]; | ||
709 | u64 limit = offset + size; | ||
710 | |||
711 | while (offset < limit) { | ||
712 | ssize_t len; | ||
713 | |||
714 | if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) | ||
715 | return -1; | ||
716 | |||
717 | if (header->needs_swap) | ||
718 | perf_event_header__bswap(&old_bev.header); | ||
719 | |||
720 | len = old_bev.header.size - sizeof(old_bev); | ||
721 | if (read(input, filename, len) != len) | ||
722 | return -1; | ||
723 | |||
724 | bev.header = old_bev.header; | ||
725 | bev.pid = 0; | ||
726 | memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id)); | ||
727 | __event_process_build_id(&bev, filename, session); | ||
728 | |||
729 | offset += bev.header.size; | ||
730 | } | ||
731 | |||
732 | return 0; | ||
733 | } | ||
734 | |||
698 | static int perf_header__read_build_ids(struct perf_header *header, | 735 | static int perf_header__read_build_ids(struct perf_header *header, |
699 | int input, u64 offset, u64 size) | 736 | int input, u64 offset, u64 size) |
700 | { | 737 | { |
701 | struct perf_session *session = container_of(header, struct perf_session, header); | 738 | struct perf_session *session = container_of(header, struct perf_session, header); |
702 | struct build_id_event bev; | 739 | struct build_id_event bev; |
703 | char filename[PATH_MAX]; | 740 | char filename[PATH_MAX]; |
704 | u64 limit = offset + size; | 741 | u64 limit = offset + size, orig_offset = offset; |
705 | int err = -1; | 742 | int err = -1; |
706 | 743 | ||
707 | while (offset < limit) { | 744 | while (offset < limit) { |
@@ -716,6 +753,24 @@ static int perf_header__read_build_ids(struct perf_header *header, | |||
716 | len = bev.header.size - sizeof(bev); | 753 | len = bev.header.size - sizeof(bev); |
717 | if (read(input, filename, len) != len) | 754 | if (read(input, filename, len) != len) |
718 | goto out; | 755 | goto out; |
756 | /* | ||
757 | * The a1645ce1 changeset: | ||
758 | * | ||
759 | * "perf: 'perf kvm' tool for monitoring guest performance from host" | ||
760 | * | ||
761 | * Added a field to struct build_id_event that broke the file | ||
762 | * format. | ||
763 | * | ||
764 | * Since the kernel build-id is the first entry, process the | ||
765 | * table using the old format if the well known | ||
766 | * '[kernel.kallsyms]' string for the kernel build-id has the | ||
767 | * first 4 characters chopped off (where the pid_t sits). | ||
768 | */ | ||
769 | if (memcmp(filename, "nel.kallsyms]", 13) == 0) { | ||
770 | if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1) | ||
771 | return -1; | ||
772 | return perf_header__read_build_ids_abi_quirk(header, input, offset, size); | ||
773 | } | ||
719 | 774 | ||
720 | __event_process_build_id(&bev, filename, session); | 775 | __event_process_build_id(&bev, filename, session); |
721 | 776 | ||
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index cb6858a2f9a3..3beb97c4d822 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -29,6 +29,7 @@ struct events_stats { | |||
29 | u32 nr_events[PERF_RECORD_HEADER_MAX]; | 29 | u32 nr_events[PERF_RECORD_HEADER_MAX]; |
30 | u32 nr_unknown_events; | 30 | u32 nr_unknown_events; |
31 | u32 nr_invalid_chains; | 31 | u32 nr_invalid_chains; |
32 | u32 nr_unknown_id; | ||
32 | }; | 33 | }; |
33 | 34 | ||
34 | enum hist_column { | 35 | enum hist_column { |
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index 621427212e86..74350ffb57fe 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c | |||
@@ -247,6 +247,7 @@ static inline struct event *find_cache_event(int type) | |||
247 | 247 | ||
248 | static void perl_process_event(union perf_event *pevent __unused, | 248 | static void perl_process_event(union perf_event *pevent __unused, |
249 | struct perf_sample *sample, | 249 | struct perf_sample *sample, |
250 | struct perf_evsel *evsel, | ||
250 | struct perf_session *session __unused, | 251 | struct perf_session *session __unused, |
251 | struct thread *thread) | 252 | struct thread *thread) |
252 | { | 253 | { |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 1b85d6055159..6ccf70e8d8f2 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -206,6 +206,7 @@ static inline struct event *find_cache_event(int type) | |||
206 | 206 | ||
207 | static void python_process_event(union perf_event *pevent __unused, | 207 | static void python_process_event(union perf_event *pevent __unused, |
208 | struct perf_sample *sample, | 208 | struct perf_sample *sample, |
209 | struct perf_evsel *evsel __unused, | ||
209 | struct perf_session *session __unused, | 210 | struct perf_session *session __unused, |
210 | struct thread *thread) | 211 | struct thread *thread) |
211 | { | 212 | { |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index c68cf40764f9..caa224522fea 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -280,6 +280,15 @@ static int process_event_synth_stub(union perf_event *event __used, | |||
280 | return 0; | 280 | return 0; |
281 | } | 281 | } |
282 | 282 | ||
283 | static int process_event_sample_stub(union perf_event *event __used, | ||
284 | struct perf_sample *sample __used, | ||
285 | struct perf_evsel *evsel __used, | ||
286 | struct perf_session *session __used) | ||
287 | { | ||
288 | dump_printf(": unhandled!\n"); | ||
289 | return 0; | ||
290 | } | ||
291 | |||
283 | static int process_event_stub(union perf_event *event __used, | 292 | static int process_event_stub(union perf_event *event __used, |
284 | struct perf_sample *sample __used, | 293 | struct perf_sample *sample __used, |
285 | struct perf_session *session __used) | 294 | struct perf_session *session __used) |
@@ -303,7 +312,7 @@ static int process_finished_round(union perf_event *event, | |||
303 | static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) | 312 | static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) |
304 | { | 313 | { |
305 | if (handler->sample == NULL) | 314 | if (handler->sample == NULL) |
306 | handler->sample = process_event_stub; | 315 | handler->sample = process_event_sample_stub; |
307 | if (handler->mmap == NULL) | 316 | if (handler->mmap == NULL) |
308 | handler->mmap = process_event_stub; | 317 | handler->mmap = process_event_stub; |
309 | if (handler->comm == NULL) | 318 | if (handler->comm == NULL) |
@@ -698,12 +707,19 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
698 | struct perf_event_ops *ops, | 707 | struct perf_event_ops *ops, |
699 | u64 file_offset) | 708 | u64 file_offset) |
700 | { | 709 | { |
710 | struct perf_evsel *evsel; | ||
711 | |||
701 | dump_event(session, event, file_offset, sample); | 712 | dump_event(session, event, file_offset, sample); |
702 | 713 | ||
703 | switch (event->header.type) { | 714 | switch (event->header.type) { |
704 | case PERF_RECORD_SAMPLE: | 715 | case PERF_RECORD_SAMPLE: |
705 | dump_sample(session, event, sample); | 716 | dump_sample(session, event, sample); |
706 | return ops->sample(event, sample, session); | 717 | evsel = perf_evlist__id2evsel(session->evlist, sample->id); |
718 | if (evsel == NULL) { | ||
719 | ++session->hists.stats.nr_unknown_id; | ||
720 | return -1; | ||
721 | } | ||
722 | return ops->sample(event, sample, evsel, session); | ||
707 | case PERF_RECORD_MMAP: | 723 | case PERF_RECORD_MMAP: |
708 | return ops->mmap(event, sample, session); | 724 | return ops->mmap(event, sample, session); |
709 | case PERF_RECORD_COMM: | 725 | case PERF_RECORD_COMM: |
@@ -845,6 +861,11 @@ static void perf_session__warn_about_errors(const struct perf_session *session, | |||
845 | session->hists.stats.nr_unknown_events); | 861 | session->hists.stats.nr_unknown_events); |
846 | } | 862 | } |
847 | 863 | ||
864 | if (session->hists.stats.nr_unknown_id != 0) { | ||
865 | ui__warning("%u samples with id not present in the header\n", | ||
866 | session->hists.stats.nr_unknown_id); | ||
867 | } | ||
868 | |||
848 | if (session->hists.stats.nr_invalid_chains != 0) { | 869 | if (session->hists.stats.nr_invalid_chains != 0) { |
849 | ui__warning("Found invalid callchains!\n\n" | 870 | ui__warning("Found invalid callchains!\n\n" |
850 | "%u out of %u events were discarded for this reason.\n\n" | 871 | "%u out of %u events were discarded for this reason.\n\n" |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 0b3c9afecaa9..1ac481fc1100 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -55,8 +55,11 @@ struct perf_session { | |||
55 | char filename[0]; | 55 | char filename[0]; |
56 | }; | 56 | }; |
57 | 57 | ||
58 | struct perf_evsel; | ||
58 | struct perf_event_ops; | 59 | struct perf_event_ops; |
59 | 60 | ||
61 | typedef int (*event_sample)(union perf_event *event, struct perf_sample *sample, | ||
62 | struct perf_evsel *evsel, struct perf_session *session); | ||
60 | typedef int (*event_op)(union perf_event *self, struct perf_sample *sample, | 63 | typedef int (*event_op)(union perf_event *self, struct perf_sample *sample, |
61 | struct perf_session *session); | 64 | struct perf_session *session); |
62 | typedef int (*event_synth_op)(union perf_event *self, | 65 | typedef int (*event_synth_op)(union perf_event *self, |
@@ -65,8 +68,8 @@ typedef int (*event_op2)(union perf_event *self, struct perf_session *session, | |||
65 | struct perf_event_ops *ops); | 68 | struct perf_event_ops *ops); |
66 | 69 | ||
67 | struct perf_event_ops { | 70 | struct perf_event_ops { |
68 | event_op sample, | 71 | event_sample sample; |
69 | mmap, | 72 | event_op mmap, |
70 | comm, | 73 | comm, |
71 | fork, | 74 | fork, |
72 | exit, | 75 | exit, |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 651dbfe7f4f3..17df793c8924 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -1486,7 +1486,9 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) | |||
1486 | * On the first pass, only load images if they have a full symtab. | 1486 | * On the first pass, only load images if they have a full symtab. |
1487 | * Failing that, do a second pass where we accept .dynsym also | 1487 | * Failing that, do a second pass where we accept .dynsym also |
1488 | */ | 1488 | */ |
1489 | for (self->symtab_type = SYMTAB__BUILD_ID_CACHE, want_symtab = 1; | 1489 | want_symtab = 1; |
1490 | restart: | ||
1491 | for (self->symtab_type = SYMTAB__BUILD_ID_CACHE; | ||
1490 | self->symtab_type != SYMTAB__NOT_FOUND; | 1492 | self->symtab_type != SYMTAB__NOT_FOUND; |
1491 | self->symtab_type++) { | 1493 | self->symtab_type++) { |
1492 | switch (self->symtab_type) { | 1494 | switch (self->symtab_type) { |
@@ -1536,17 +1538,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) | |||
1536 | snprintf(name, size, "%s%s", symbol_conf.symfs, | 1538 | snprintf(name, size, "%s%s", symbol_conf.symfs, |
1537 | self->long_name); | 1539 | self->long_name); |
1538 | break; | 1540 | break; |
1539 | 1541 | default:; | |
1540 | default: | ||
1541 | /* | ||
1542 | * If we wanted a full symtab but no image had one, | ||
1543 | * relax our requirements and repeat the search. | ||
1544 | */ | ||
1545 | if (want_symtab) { | ||
1546 | want_symtab = 0; | ||
1547 | self->symtab_type = SYMTAB__BUILD_ID_CACHE; | ||
1548 | } else | ||
1549 | continue; | ||
1550 | } | 1542 | } |
1551 | 1543 | ||
1552 | /* Name is now the name of the next image to try */ | 1544 | /* Name is now the name of the next image to try */ |
@@ -1573,6 +1565,15 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) | |||
1573 | } | 1565 | } |
1574 | } | 1566 | } |
1575 | 1567 | ||
1568 | /* | ||
1569 | * If we wanted a full symtab but no image had one, | ||
1570 | * relax our requirements and repeat the search. | ||
1571 | */ | ||
1572 | if (ret <= 0 && want_symtab) { | ||
1573 | want_symtab = 0; | ||
1574 | goto restart; | ||
1575 | } | ||
1576 | |||
1576 | free(name); | 1577 | free(name); |
1577 | if (ret < 0 && strstr(self->name, " (deleted)") != NULL) | 1578 | if (ret < 0 && strstr(self->name, " (deleted)") != NULL) |
1578 | return 0; | 1579 | return 0; |
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index 66f4b78737ab..c9dcbec7d800 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c | |||
@@ -38,6 +38,7 @@ static int stop_script_unsupported(void) | |||
38 | 38 | ||
39 | static void process_event_unsupported(union perf_event *event __unused, | 39 | static void process_event_unsupported(union perf_event *event __unused, |
40 | struct perf_sample *sample __unused, | 40 | struct perf_sample *sample __unused, |
41 | struct perf_evsel *evsel __unused, | ||
41 | struct perf_session *session __unused, | 42 | struct perf_session *session __unused, |
42 | struct thread *thread __unused) | 43 | struct thread *thread __unused) |
43 | { | 44 | { |
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index b04da5722437..f674dda3363b 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h | |||
@@ -280,6 +280,7 @@ struct scripting_ops { | |||
280 | int (*stop_script) (void); | 280 | int (*stop_script) (void); |
281 | void (*process_event) (union perf_event *event, | 281 | void (*process_event) (union perf_event *event, |
282 | struct perf_sample *sample, | 282 | struct perf_sample *sample, |
283 | struct perf_evsel *evsel, | ||
283 | struct perf_session *session, | 284 | struct perf_session *session, |
284 | struct thread *thread); | 285 | struct thread *thread); |
285 | int (*generate_script) (const char *outfile); | 286 | int (*generate_script) (const char *outfile); |
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 7bee6dc8cdb2..556e3efe5325 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -30,7 +30,7 @@ | |||
30 | #include <linux/debugfs.h> | 30 | #include <linux/debugfs.h> |
31 | #include <linux/highmem.h> | 31 | #include <linux/highmem.h> |
32 | #include <linux/file.h> | 32 | #include <linux/file.h> |
33 | #include <linux/sysdev.h> | 33 | #include <linux/syscore_ops.h> |
34 | #include <linux/cpu.h> | 34 | #include <linux/cpu.h> |
35 | #include <linux/sched.h> | 35 | #include <linux/sched.h> |
36 | #include <linux/cpumask.h> | 36 | #include <linux/cpumask.h> |
@@ -2446,33 +2446,26 @@ static void kvm_exit_debug(void) | |||
2446 | debugfs_remove(kvm_debugfs_dir); | 2446 | debugfs_remove(kvm_debugfs_dir); |
2447 | } | 2447 | } |
2448 | 2448 | ||
2449 | static int kvm_suspend(struct sys_device *dev, pm_message_t state) | 2449 | static int kvm_suspend(void) |
2450 | { | 2450 | { |
2451 | if (kvm_usage_count) | 2451 | if (kvm_usage_count) |
2452 | hardware_disable_nolock(NULL); | 2452 | hardware_disable_nolock(NULL); |
2453 | return 0; | 2453 | return 0; |
2454 | } | 2454 | } |
2455 | 2455 | ||
2456 | static int kvm_resume(struct sys_device *dev) | 2456 | static void kvm_resume(void) |
2457 | { | 2457 | { |
2458 | if (kvm_usage_count) { | 2458 | if (kvm_usage_count) { |
2459 | WARN_ON(raw_spin_is_locked(&kvm_lock)); | 2459 | WARN_ON(raw_spin_is_locked(&kvm_lock)); |
2460 | hardware_enable_nolock(NULL); | 2460 | hardware_enable_nolock(NULL); |
2461 | } | 2461 | } |
2462 | return 0; | ||
2463 | } | 2462 | } |
2464 | 2463 | ||
2465 | static struct sysdev_class kvm_sysdev_class = { | 2464 | static struct syscore_ops kvm_syscore_ops = { |
2466 | .name = "kvm", | ||
2467 | .suspend = kvm_suspend, | 2465 | .suspend = kvm_suspend, |
2468 | .resume = kvm_resume, | 2466 | .resume = kvm_resume, |
2469 | }; | 2467 | }; |
2470 | 2468 | ||
2471 | static struct sys_device kvm_sysdev = { | ||
2472 | .id = 0, | ||
2473 | .cls = &kvm_sysdev_class, | ||
2474 | }; | ||
2475 | |||
2476 | struct page *bad_page; | 2469 | struct page *bad_page; |
2477 | pfn_t bad_pfn; | 2470 | pfn_t bad_pfn; |
2478 | 2471 | ||
@@ -2556,14 +2549,6 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, | |||
2556 | goto out_free_2; | 2549 | goto out_free_2; |
2557 | register_reboot_notifier(&kvm_reboot_notifier); | 2550 | register_reboot_notifier(&kvm_reboot_notifier); |
2558 | 2551 | ||
2559 | r = sysdev_class_register(&kvm_sysdev_class); | ||
2560 | if (r) | ||
2561 | goto out_free_3; | ||
2562 | |||
2563 | r = sysdev_register(&kvm_sysdev); | ||
2564 | if (r) | ||
2565 | goto out_free_4; | ||
2566 | |||
2567 | /* A kmem cache lets us meet the alignment requirements of fx_save. */ | 2552 | /* A kmem cache lets us meet the alignment requirements of fx_save. */ |
2568 | if (!vcpu_align) | 2553 | if (!vcpu_align) |
2569 | vcpu_align = __alignof__(struct kvm_vcpu); | 2554 | vcpu_align = __alignof__(struct kvm_vcpu); |
@@ -2571,7 +2556,7 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, | |||
2571 | 0, NULL); | 2556 | 0, NULL); |
2572 | if (!kvm_vcpu_cache) { | 2557 | if (!kvm_vcpu_cache) { |
2573 | r = -ENOMEM; | 2558 | r = -ENOMEM; |
2574 | goto out_free_5; | 2559 | goto out_free_3; |
2575 | } | 2560 | } |
2576 | 2561 | ||
2577 | r = kvm_async_pf_init(); | 2562 | r = kvm_async_pf_init(); |
@@ -2588,6 +2573,8 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, | |||
2588 | goto out_unreg; | 2573 | goto out_unreg; |
2589 | } | 2574 | } |
2590 | 2575 | ||
2576 | register_syscore_ops(&kvm_syscore_ops); | ||
2577 | |||
2591 | kvm_preempt_ops.sched_in = kvm_sched_in; | 2578 | kvm_preempt_ops.sched_in = kvm_sched_in; |
2592 | kvm_preempt_ops.sched_out = kvm_sched_out; | 2579 | kvm_preempt_ops.sched_out = kvm_sched_out; |
2593 | 2580 | ||
@@ -2599,10 +2586,6 @@ out_unreg: | |||
2599 | kvm_async_pf_deinit(); | 2586 | kvm_async_pf_deinit(); |
2600 | out_free: | 2587 | out_free: |
2601 | kmem_cache_destroy(kvm_vcpu_cache); | 2588 | kmem_cache_destroy(kvm_vcpu_cache); |
2602 | out_free_5: | ||
2603 | sysdev_unregister(&kvm_sysdev); | ||
2604 | out_free_4: | ||
2605 | sysdev_class_unregister(&kvm_sysdev_class); | ||
2606 | out_free_3: | 2589 | out_free_3: |
2607 | unregister_reboot_notifier(&kvm_reboot_notifier); | 2590 | unregister_reboot_notifier(&kvm_reboot_notifier); |
2608 | unregister_cpu_notifier(&kvm_cpu_notifier); | 2591 | unregister_cpu_notifier(&kvm_cpu_notifier); |
@@ -2630,8 +2613,7 @@ void kvm_exit(void) | |||
2630 | misc_deregister(&kvm_dev); | 2613 | misc_deregister(&kvm_dev); |
2631 | kmem_cache_destroy(kvm_vcpu_cache); | 2614 | kmem_cache_destroy(kvm_vcpu_cache); |
2632 | kvm_async_pf_deinit(); | 2615 | kvm_async_pf_deinit(); |
2633 | sysdev_unregister(&kvm_sysdev); | 2616 | unregister_syscore_ops(&kvm_syscore_ops); |
2634 | sysdev_class_unregister(&kvm_sysdev_class); | ||
2635 | unregister_reboot_notifier(&kvm_reboot_notifier); | 2617 | unregister_reboot_notifier(&kvm_reboot_notifier); |
2636 | unregister_cpu_notifier(&kvm_cpu_notifier); | 2618 | unregister_cpu_notifier(&kvm_cpu_notifier); |
2637 | on_each_cpu(hardware_disable_nolock, NULL, 1); | 2619 | on_each_cpu(hardware_disable_nolock, NULL, 1); |