diff options
268 files changed, 9591 insertions, 2854 deletions
diff --git a/.gitignore b/.gitignore index fdcce40226d7..3016ed30526d 100644 --- a/.gitignore +++ b/.gitignore | |||
@@ -27,6 +27,7 @@ TAGS | |||
27 | vmlinux* | 27 | vmlinux* |
28 | !vmlinux.lds.S | 28 | !vmlinux.lds.S |
29 | System.map | 29 | System.map |
30 | Module.markers | ||
30 | Module.symvers | 31 | Module.symvers |
31 | !.gitignore | 32 | !.gitignore |
32 | 33 | ||
diff --git a/Documentation/ABI/stable/sysfs-class-ubi b/Documentation/ABI/stable/sysfs-class-ubi new file mode 100644 index 000000000000..18d471d9faea --- /dev/null +++ b/Documentation/ABI/stable/sysfs-class-ubi | |||
@@ -0,0 +1,212 @@ | |||
1 | What: /sys/class/ubi/ | ||
2 | Date: July 2006 | ||
3 | KernelVersion: 2.6.22 | ||
4 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
5 | Description: | ||
6 | The ubi/ class sub-directory belongs to the UBI subsystem and | ||
7 | provides general UBI information, per-UBI device information | ||
8 | and per-UBI volume information. | ||
9 | |||
10 | What: /sys/class/ubi/version | ||
11 | Date: July 2006 | ||
12 | KernelVersion: 2.6.22 | ||
13 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
14 | Description: | ||
15 | This file contains version of the latest supported UBI on-media | ||
16 | format. Currently it is 1, and there is no plan to change this. | ||
17 | However, if in the future UBI needs on-flash format changes | ||
18 | which cannot be done in a compatible manner, a new format | ||
19 | version will be added. So this is a mechanism for possible | ||
20 | future backward-compatible (but forward-incompatible) | ||
21 | improvements. | ||
22 | |||
23 | What: /sys/class/ubiX/ | ||
24 | Date: July 2006 | ||
25 | KernelVersion: 2.6.22 | ||
26 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
27 | Description: | ||
28 | The /sys/class/ubi0, /sys/class/ubi1, etc directories describe | ||
29 | UBI devices (UBI device 0, 1, etc). They contain general UBI | ||
30 | device information and per UBI volume information (each UBI | ||
31 | device may have many UBI volumes) | ||
32 | |||
33 | What: /sys/class/ubi/ubiX/avail_eraseblocks | ||
34 | Date: July 2006 | ||
35 | KernelVersion: 2.6.22 | ||
36 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
37 | Description: | ||
38 | Amount of available logical eraseblock. For example, one may | ||
39 | create a new UBI volume which has this amount of logical | ||
40 | eraseblocks. | ||
41 | |||
42 | What: /sys/class/ubi/ubiX/bad_peb_count | ||
43 | Date: July 2006 | ||
44 | KernelVersion: 2.6.22 | ||
45 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
46 | Description: | ||
47 | Count of bad physical eraseblocks on the underlying MTD device. | ||
48 | |||
49 | What: /sys/class/ubi/ubiX/bgt_enabled | ||
50 | Date: July 2006 | ||
51 | KernelVersion: 2.6.22 | ||
52 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
53 | Description: | ||
54 | Contains ASCII "0\n" if the UBI background thread is disabled, | ||
55 | and ASCII "1\n" if it is enabled. | ||
56 | |||
57 | What: /sys/class/ubi/ubiX/dev | ||
58 | Date: July 2006 | ||
59 | KernelVersion: 2.6.22 | ||
60 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
61 | Description: | ||
62 | Major and minor numbers of the character device corresponding | ||
63 | to this UBI device (in <major>:<minor> format). | ||
64 | |||
65 | What: /sys/class/ubi/ubiX/eraseblock_size | ||
66 | Date: July 2006 | ||
67 | KernelVersion: 2.6.22 | ||
68 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
69 | Description: | ||
70 | Maximum logical eraseblock size this UBI device may provide. UBI | ||
71 | volumes may have smaller logical eraseblock size because of their | ||
72 | alignment. | ||
73 | |||
74 | What: /sys/class/ubi/ubiX/max_ec | ||
75 | Date: July 2006 | ||
76 | KernelVersion: 2.6.22 | ||
77 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
78 | Description: | ||
79 | Maximum physical eraseblock erase counter value. | ||
80 | |||
81 | What: /sys/class/ubi/ubiX/max_vol_count | ||
82 | Date: July 2006 | ||
83 | KernelVersion: 2.6.22 | ||
84 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
85 | Description: | ||
86 | Maximum number of volumes which this UBI device may have. | ||
87 | |||
88 | What: /sys/class/ubi/ubiX/min_io_size | ||
89 | Date: July 2006 | ||
90 | KernelVersion: 2.6.22 | ||
91 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
92 | Description: | ||
93 | Minimum input/output unit size. All the I/O may only be done | ||
94 | in fractions of the contained number. | ||
95 | |||
96 | What: /sys/class/ubi/ubiX/mtd_num | ||
97 | Date: January 2008 | ||
98 | KernelVersion: 2.6.25 | ||
99 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
100 | Description: | ||
101 | Number of the underlying MTD device. | ||
102 | |||
103 | What: /sys/class/ubi/ubiX/reserved_for_bad | ||
104 | Date: July 2006 | ||
105 | KernelVersion: 2.6.22 | ||
106 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
107 | Description: | ||
108 | Number of physical eraseblocks reserved for bad block handling. | ||
109 | |||
110 | What: /sys/class/ubi/ubiX/total_eraseblocks | ||
111 | Date: July 2006 | ||
112 | KernelVersion: 2.6.22 | ||
113 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
114 | Description: | ||
115 | Total number of good (not marked as bad) physical eraseblocks on | ||
116 | the underlying MTD device. | ||
117 | |||
118 | What: /sys/class/ubi/ubiX/volumes_count | ||
119 | Date: July 2006 | ||
120 | KernelVersion: 2.6.22 | ||
121 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
122 | Description: | ||
123 | Count of volumes on this UBI device. | ||
124 | |||
125 | What: /sys/class/ubi/ubiX/ubiX_Y/ | ||
126 | Date: July 2006 | ||
127 | KernelVersion: 2.6.22 | ||
128 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
129 | Description: | ||
130 | The /sys/class/ubi/ubiX/ubiX_0/, /sys/class/ubi/ubiX/ubiX_1/, | ||
131 | etc directories describe UBI volumes on UBI device X (volumes | ||
132 | 0, 1, etc). | ||
133 | |||
134 | What: /sys/class/ubi/ubiX/ubiX_Y/alignment | ||
135 | Date: July 2006 | ||
136 | KernelVersion: 2.6.22 | ||
137 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
138 | Description: | ||
139 | Volume alignment - the value the logical eraseblock size of | ||
140 | this volume has to be aligned on. For example, 2048 means that | ||
141 | logical eraseblock size is multiple of 2048. In other words, | ||
142 | volume logical eraseblock size is UBI device logical eraseblock | ||
143 | size aligned to the alignment value. | ||
144 | |||
145 | What: /sys/class/ubi/ubiX/ubiX_Y/corrupted | ||
146 | Date: July 2006 | ||
147 | KernelVersion: 2.6.22 | ||
148 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
149 | Description: | ||
150 | Contains ASCII "0\n" if the UBI volume is OK, and ASCII "1\n" | ||
151 | if it is corrupted (e.g., due to an interrupted volume update). | ||
152 | |||
153 | What: /sys/class/ubi/ubiX/ubiX_Y/data_bytes | ||
154 | Date: July 2006 | ||
155 | KernelVersion: 2.6.22 | ||
156 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
157 | Description: | ||
158 | The amount of data this volume contains. This value makes sense | ||
159 | only for static volumes, and for dynamic volume it equivalent | ||
160 | to the total volume size in bytes. | ||
161 | |||
162 | What: /sys/class/ubi/ubiX/ubiX_Y/dev | ||
163 | Date: July 2006 | ||
164 | KernelVersion: 2.6.22 | ||
165 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
166 | Description: | ||
167 | Major and minor numbers of the character device corresponding | ||
168 | to this UBI volume (in <major>:<minor> format). | ||
169 | |||
170 | What: /sys/class/ubi/ubiX/ubiX_Y/name | ||
171 | Date: July 2006 | ||
172 | KernelVersion: 2.6.22 | ||
173 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
174 | Description: | ||
175 | Volume name. | ||
176 | |||
177 | What: /sys/class/ubi/ubiX/ubiX_Y/reserved_ebs | ||
178 | Date: July 2006 | ||
179 | KernelVersion: 2.6.22 | ||
180 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
181 | Description: | ||
182 | Count of physical eraseblock reserved for this volume. | ||
183 | Equivalent to the volume size in logical eraseblocks. | ||
184 | |||
185 | What: /sys/class/ubi/ubiX/ubiX_Y/type | ||
186 | Date: July 2006 | ||
187 | KernelVersion: 2.6.22 | ||
188 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
189 | Description: | ||
190 | Volume type. Contains ASCII "dynamic\n" for dynamic volumes and | ||
191 | "static\n" for static volumes. | ||
192 | |||
193 | What: /sys/class/ubi/ubiX/ubiX_Y/upd_marker | ||
194 | Date: July 2006 | ||
195 | KernelVersion: 2.6.22 | ||
196 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
197 | Description: | ||
198 | Contains ASCII "0\n" if the update marker is not set for this | ||
199 | volume, and "1\n" if it is set. The update marker is set when | ||
200 | volume update starts, and cleaned when it ends. So the presence | ||
201 | of the update marker indicates that the volume is being updated | ||
202 | at the moment of the update was interrupted. The later may be | ||
203 | checked using the "corrupted" sysfs file. | ||
204 | |||
205 | What: /sys/class/ubi/ubiX/ubiX_Y/usable_eb_size | ||
206 | Date: July 2006 | ||
207 | KernelVersion: 2.6.22 | ||
208 | Contact: Artem Bityutskiy <dedekind@infradead.org> | ||
209 | Description: | ||
210 | Logical eraseblock size of this volume. Equivalent to logical | ||
211 | eraseblock size of the device aligned on the volume alignment | ||
212 | value. | ||
diff --git a/Documentation/HOWTO b/Documentation/HOWTO index 54835610b3d6..0291ade44c17 100644 --- a/Documentation/HOWTO +++ b/Documentation/HOWTO | |||
@@ -249,9 +249,11 @@ process is as follows: | |||
249 | release a new -rc kernel every week. | 249 | release a new -rc kernel every week. |
250 | - Process continues until the kernel is considered "ready", the | 250 | - Process continues until the kernel is considered "ready", the |
251 | process should last around 6 weeks. | 251 | process should last around 6 weeks. |
252 | - A list of known regressions present in each -rc release is | 252 | - Known regressions in each release are periodically posted to the |
253 | tracked at the following URI: | 253 | linux-kernel mailing list. The goal is to reduce the length of |
254 | http://kernelnewbies.org/known_regressions | 254 | that list to zero before declaring the kernel to be "ready," but, in |
255 | the real world, a small number of regressions often remain at | ||
256 | release time. | ||
255 | 257 | ||
256 | It is worth mentioning what Andrew Morton wrote on the linux-kernel | 258 | It is worth mentioning what Andrew Morton wrote on the linux-kernel |
257 | mailing list about kernel releases: | 259 | mailing list about kernel releases: |
@@ -261,7 +263,7 @@ mailing list about kernel releases: | |||
261 | 263 | ||
262 | 2.6.x.y -stable kernel tree | 264 | 2.6.x.y -stable kernel tree |
263 | --------------------------- | 265 | --------------------------- |
264 | Kernels with 4 digit versions are -stable kernels. They contain | 266 | Kernels with 4-part versions are -stable kernels. They contain |
265 | relatively small and critical fixes for security problems or significant | 267 | relatively small and critical fixes for security problems or significant |
266 | regressions discovered in a given 2.6.x kernel. | 268 | regressions discovered in a given 2.6.x kernel. |
267 | 269 | ||
@@ -273,7 +275,10 @@ If no 2.6.x.y kernel is available, then the highest numbered 2.6.x | |||
273 | kernel is the current stable kernel. | 275 | kernel is the current stable kernel. |
274 | 276 | ||
275 | 2.6.x.y are maintained by the "stable" team <stable@kernel.org>, and are | 277 | 2.6.x.y are maintained by the "stable" team <stable@kernel.org>, and are |
276 | released almost every other week. | 278 | released as needs dictate. The normal release period is approximately |
279 | two weeks, but it can be longer if there are no pressing problems. A | ||
280 | security-related problem, instead, can cause a release to happen almost | ||
281 | instantly. | ||
277 | 282 | ||
278 | The file Documentation/stable_kernel_rules.txt in the kernel tree | 283 | The file Documentation/stable_kernel_rules.txt in the kernel tree |
279 | documents what kinds of changes are acceptable for the -stable tree, and | 284 | documents what kinds of changes are acceptable for the -stable tree, and |
@@ -298,7 +303,9 @@ a while Andrew or the subsystem maintainer pushes it on to Linus for | |||
298 | inclusion in mainline. | 303 | inclusion in mainline. |
299 | 304 | ||
300 | It is heavily encouraged that all new patches get tested in the -mm tree | 305 | It is heavily encouraged that all new patches get tested in the -mm tree |
301 | before they are sent to Linus for inclusion in the main kernel tree. | 306 | before they are sent to Linus for inclusion in the main kernel tree. Code |
307 | which does not make an appearance in -mm before the opening of the merge | ||
308 | window will prove hard to merge into the mainline. | ||
302 | 309 | ||
303 | These kernels are not appropriate for use on systems that are supposed | 310 | These kernels are not appropriate for use on systems that are supposed |
304 | to be stable and they are more risky to run than any of the other | 311 | to be stable and they are more risky to run than any of the other |
@@ -354,11 +361,12 @@ Here is a list of some of the different kernel trees available: | |||
354 | - SCSI, James Bottomley <James.Bottomley@SteelEye.com> | 361 | - SCSI, James Bottomley <James.Bottomley@SteelEye.com> |
355 | git.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git | 362 | git.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git |
356 | 363 | ||
364 | - x86, Ingo Molnar <mingo@elte.hu> | ||
365 | git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git | ||
366 | |||
357 | quilt trees: | 367 | quilt trees: |
358 | - USB, PCI, Driver Core, and I2C, Greg Kroah-Hartman <gregkh@suse.de> | 368 | - USB, Driver Core, and I2C, Greg Kroah-Hartman <gregkh@suse.de> |
359 | kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/ | 369 | kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/ |
360 | - x86-64, partly i386, Andi Kleen <ak@suse.de> | ||
361 | ftp.firstfloor.org:/pub/ak/x86_64/quilt/ | ||
362 | 370 | ||
363 | Other kernel trees can be found listed at http://git.kernel.org/ and in | 371 | Other kernel trees can be found listed at http://git.kernel.org/ and in |
364 | the MAINTAINERS file. | 372 | the MAINTAINERS file. |
@@ -392,8 +400,8 @@ If you want to be advised of the future bug reports, you can subscribe to the | |||
392 | bugme-new mailing list (only new bug reports are mailed here) or to the | 400 | bugme-new mailing list (only new bug reports are mailed here) or to the |
393 | bugme-janitor mailing list (every change in the bugzilla is mailed here) | 401 | bugme-janitor mailing list (every change in the bugzilla is mailed here) |
394 | 402 | ||
395 | http://lists.osdl.org/mailman/listinfo/bugme-new | 403 | http://lists.linux-foundation.org/mailman/listinfo/bugme-new |
396 | http://lists.osdl.org/mailman/listinfo/bugme-janitors | 404 | http://lists.linux-foundation.org/mailman/listinfo/bugme-janitors |
397 | 405 | ||
398 | 406 | ||
399 | 407 | ||
diff --git a/Documentation/arm/Samsung-S3C24XX/NAND.txt b/Documentation/arm/Samsung-S3C24XX/NAND.txt new file mode 100644 index 000000000000..bc478a3409b8 --- /dev/null +++ b/Documentation/arm/Samsung-S3C24XX/NAND.txt | |||
@@ -0,0 +1,30 @@ | |||
1 | S3C24XX NAND Support | ||
2 | ==================== | ||
3 | |||
4 | Introduction | ||
5 | ------------ | ||
6 | |||
7 | Small Page NAND | ||
8 | --------------- | ||
9 | |||
10 | The driver uses a 512 byte (1 page) ECC code for this setup. The | ||
11 | ECC code is not directly compatible with the default kernel ECC | ||
12 | code, so the driver enforces its own OOB layout and ECC parameters | ||
13 | |||
14 | Large Page NAND | ||
15 | --------------- | ||
16 | |||
17 | The driver is capable of handling NAND flash with a 2KiB page | ||
18 | size, with support for hardware ECC generation and correction. | ||
19 | |||
20 | Unlike the 512byte page mode, the driver generates ECC data for | ||
21 | each 256 byte block in an 2KiB page. This means that more than | ||
22 | one error in a page can be rectified. It also means that the | ||
23 | OOB layout remains the default kernel layout for these flashes. | ||
24 | |||
25 | |||
26 | Document Author | ||
27 | --------------- | ||
28 | |||
29 | Ben Dooks, Copyright 2007 Simtec Electronics | ||
30 | |||
diff --git a/Documentation/arm/Samsung-S3C24XX/Overview.txt b/Documentation/arm/Samsung-S3C24XX/Overview.txt index c31b76fa66c4..d04e1e30c47f 100644 --- a/Documentation/arm/Samsung-S3C24XX/Overview.txt +++ b/Documentation/arm/Samsung-S3C24XX/Overview.txt | |||
@@ -156,6 +156,8 @@ NAND | |||
156 | controller. If there are any problems the latest linux-mtd | 156 | controller. If there are any problems the latest linux-mtd |
157 | code can be found from http://www.linux-mtd.infradead.org/ | 157 | code can be found from http://www.linux-mtd.infradead.org/ |
158 | 158 | ||
159 | For more information see Documentation/arm/Samsung-S3C24XX/NAND.txt | ||
160 | |||
159 | 161 | ||
160 | Serial | 162 | Serial |
161 | ------ | 163 | ------ |
diff --git a/Documentation/device-mapper/dm-crypt.txt b/Documentation/device-mapper/dm-crypt.txt new file mode 100644 index 000000000000..6680cab2c705 --- /dev/null +++ b/Documentation/device-mapper/dm-crypt.txt | |||
@@ -0,0 +1,52 @@ | |||
1 | dm-crypt | ||
2 | ========= | ||
3 | |||
4 | Device-Mapper's "crypt" target provides transparent encryption of block devices | ||
5 | using the kernel crypto API. | ||
6 | |||
7 | Parameters: <cipher> <key> <iv_offset> <device path> <offset> | ||
8 | |||
9 | <cipher> | ||
10 | Encryption cipher and an optional IV generation mode. | ||
11 | (In format cipher-chainmode-ivopts:ivmode). | ||
12 | Examples: | ||
13 | des | ||
14 | aes-cbc-essiv:sha256 | ||
15 | twofish-ecb | ||
16 | |||
17 | /proc/crypto contains supported crypto modes | ||
18 | |||
19 | <key> | ||
20 | Key used for encryption. It is encoded as a hexadecimal number. | ||
21 | You can only use key sizes that are valid for the selected cipher. | ||
22 | |||
23 | <iv_offset> | ||
24 | The IV offset is a sector count that is added to the sector number | ||
25 | before creating the IV. | ||
26 | |||
27 | <device path> | ||
28 | This is the device that is going to be used as backend and contains the | ||
29 | encrypted data. You can specify it as a path like /dev/xxx or a device | ||
30 | number <major>:<minor>. | ||
31 | |||
32 | <offset> | ||
33 | Starting sector within the device where the encrypted data begins. | ||
34 | |||
35 | Example scripts | ||
36 | =============== | ||
37 | LUKS (Linux Unified Key Setup) is now the preferred way to set up disk | ||
38 | encryption with dm-crypt using the 'cryptsetup' utility, see | ||
39 | http://luks.endorphin.org/ | ||
40 | |||
41 | [[ | ||
42 | #!/bin/sh | ||
43 | # Create a crypt device using dmsetup | ||
44 | dmsetup create crypt1 --table "0 `blockdev --getsize $1` crypt aes-cbc-essiv:sha256 babebabebabebabebabebabebabebabe 0 $1 0" | ||
45 | ]] | ||
46 | |||
47 | [[ | ||
48 | #!/bin/sh | ||
49 | # Create a crypt device using cryptsetup and LUKS header with default cipher | ||
50 | cryptsetup luksFormat $1 | ||
51 | cryptsetup luksOpen $1 crypt1 | ||
52 | ]] | ||
diff --git a/Documentation/filesystems/nfs-rdma.txt b/Documentation/filesystems/nfs-rdma.txt index 1ae34879574b..d0ec45ae4e7d 100644 --- a/Documentation/filesystems/nfs-rdma.txt +++ b/Documentation/filesystems/nfs-rdma.txt | |||
@@ -5,7 +5,7 @@ | |||
5 | ################################################################################ | 5 | ################################################################################ |
6 | 6 | ||
7 | Author: NetApp and Open Grid Computing | 7 | Author: NetApp and Open Grid Computing |
8 | Date: February 25, 2008 | 8 | Date: April 15, 2008 |
9 | 9 | ||
10 | Table of Contents | 10 | Table of Contents |
11 | ~~~~~~~~~~~~~~~~~ | 11 | ~~~~~~~~~~~~~~~~~ |
@@ -197,12 +197,16 @@ NFS/RDMA Setup | |||
197 | - On the server system, configure the /etc/exports file and | 197 | - On the server system, configure the /etc/exports file and |
198 | start the NFS/RDMA server. | 198 | start the NFS/RDMA server. |
199 | 199 | ||
200 | Exports entries with the following format have been tested: | 200 | Exports entries with the following formats have been tested: |
201 | 201 | ||
202 | /vol0 10.97.103.47(rw,async) 192.168.0.47(rw,async,insecure,no_root_squash) | 202 | /vol0 192.168.0.47(fsid=0,rw,async,insecure,no_root_squash) |
203 | /vol0 192.168.0.0/255.255.255.0(fsid=0,rw,async,insecure,no_root_squash) | ||
203 | 204 | ||
204 | Here the first IP address is the client's Ethernet address and the second | 205 | The IP address(es) is(are) the client's IPoIB address for an InfiniBand HCA or the |
205 | IP address is the clients IPoIB address. | 206 | cleint's iWARP address(es) for an RNIC. |
207 | |||
208 | NOTE: The "insecure" option must be used because the NFS/RDMA client does not | ||
209 | use a reserved port. | ||
206 | 210 | ||
207 | Each time a machine boots: | 211 | Each time a machine boots: |
208 | 212 | ||
diff --git a/Documentation/filesystems/seq_file.txt b/Documentation/filesystems/seq_file.txt index 7fb8e6dc62bf..b843743aa0b5 100644 --- a/Documentation/filesystems/seq_file.txt +++ b/Documentation/filesystems/seq_file.txt | |||
@@ -122,8 +122,7 @@ stop() is the place to free it. | |||
122 | } | 122 | } |
123 | 123 | ||
124 | Finally, the show() function should format the object currently pointed to | 124 | Finally, the show() function should format the object currently pointed to |
125 | by the iterator for output. It should return zero, or an error code if | 125 | by the iterator for output. The example module's show() function is: |
126 | something goes wrong. The example module's show() function is: | ||
127 | 126 | ||
128 | static int ct_seq_show(struct seq_file *s, void *v) | 127 | static int ct_seq_show(struct seq_file *s, void *v) |
129 | { | 128 | { |
@@ -132,6 +131,12 @@ something goes wrong. The example module's show() function is: | |||
132 | return 0; | 131 | return 0; |
133 | } | 132 | } |
134 | 133 | ||
134 | If all is well, the show() function should return zero. A negative error | ||
135 | code in the usual manner indicates that something went wrong; it will be | ||
136 | passed back to user space. This function can also return SEQ_SKIP, which | ||
137 | causes the current item to be skipped; if the show() function has already | ||
138 | generated output before returning SEQ_SKIP, that output will be dropped. | ||
139 | |||
135 | We will look at seq_printf() in a moment. But first, the definition of the | 140 | We will look at seq_printf() in a moment. But first, the definition of the |
136 | seq_file iterator is finished by creating a seq_operations structure with | 141 | seq_file iterator is finished by creating a seq_operations structure with |
137 | the four functions we have just defined: | 142 | the four functions we have just defined: |
@@ -182,12 +187,18 @@ The first two output a single character and a string, just like one would | |||
182 | expect. seq_escape() is like seq_puts(), except that any character in s | 187 | expect. seq_escape() is like seq_puts(), except that any character in s |
183 | which is in the string esc will be represented in octal form in the output. | 188 | which is in the string esc will be represented in octal form in the output. |
184 | 189 | ||
185 | There is also a function for printing filenames: | 190 | There is also a pair of functions for printing filenames: |
186 | 191 | ||
187 | int seq_path(struct seq_file *m, struct path *path, char *esc); | 192 | int seq_path(struct seq_file *m, struct path *path, char *esc); |
193 | int seq_path_root(struct seq_file *m, struct path *path, | ||
194 | struct path *root, char *esc) | ||
188 | 195 | ||
189 | Here, path indicates the file of interest, and esc is a set of characters | 196 | Here, path indicates the file of interest, and esc is a set of characters |
190 | which should be escaped in the output. | 197 | which should be escaped in the output. A call to seq_path() will output |
198 | the path relative to the current process's filesystem root. If a different | ||
199 | root is desired, it can be used with seq_path_root(). Note that, if it | ||
200 | turns out that path cannot be reached from root, the value of root will be | ||
201 | changed in seq_file_root() to a root which *does* work. | ||
191 | 202 | ||
192 | 203 | ||
193 | Making it all work | 204 | Making it all work |
diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt index 0bc95eab1512..8df6a7b0e66c 100644 --- a/Documentation/networking/phy.txt +++ b/Documentation/networking/phy.txt | |||
@@ -1,7 +1,7 @@ | |||
1 | 1 | ||
2 | ------- | 2 | ------- |
3 | PHY Abstraction Layer | 3 | PHY Abstraction Layer |
4 | (Updated 2006-11-30) | 4 | (Updated 2008-04-08) |
5 | 5 | ||
6 | Purpose | 6 | Purpose |
7 | 7 | ||
@@ -291,3 +291,39 @@ Writing a PHY driver | |||
291 | Feel free to look at the Marvell, Cicada, and Davicom drivers in | 291 | Feel free to look at the Marvell, Cicada, and Davicom drivers in |
292 | drivers/net/phy/ for examples (the lxt and qsemi drivers have | 292 | drivers/net/phy/ for examples (the lxt and qsemi drivers have |
293 | not been tested as of this writing) | 293 | not been tested as of this writing) |
294 | |||
295 | Board Fixups | ||
296 | |||
297 | Sometimes the specific interaction between the platform and the PHY requires | ||
298 | special handling. For instance, to change where the PHY's clock input is, | ||
299 | or to add a delay to account for latency issues in the data path. In order | ||
300 | to support such contingencies, the PHY Layer allows platform code to register | ||
301 | fixups to be run when the PHY is brought up (or subsequently reset). | ||
302 | |||
303 | When the PHY Layer brings up a PHY it checks to see if there are any fixups | ||
304 | registered for it, matching based on UID (contained in the PHY device's phy_id | ||
305 | field) and the bus identifier (contained in phydev->dev.bus_id). Both must | ||
306 | match, however two constants, PHY_ANY_ID and PHY_ANY_UID, are provided as | ||
307 | wildcards for the bus ID and UID, respectively. | ||
308 | |||
309 | When a match is found, the PHY layer will invoke the run function associated | ||
310 | with the fixup. This function is passed a pointer to the phy_device of | ||
311 | interest. It should therefore only operate on that PHY. | ||
312 | |||
313 | The platform code can either register the fixup using phy_register_fixup(): | ||
314 | |||
315 | int phy_register_fixup(const char *phy_id, | ||
316 | u32 phy_uid, u32 phy_uid_mask, | ||
317 | int (*run)(struct phy_device *)); | ||
318 | |||
319 | Or using one of the two stubs, phy_register_fixup_for_uid() and | ||
320 | phy_register_fixup_for_id(): | ||
321 | |||
322 | int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask, | ||
323 | int (*run)(struct phy_device *)); | ||
324 | int phy_register_fixup_for_id(const char *phy_id, | ||
325 | int (*run)(struct phy_device *)); | ||
326 | |||
327 | The stubs set one of the two matching criteria, and set the other one to | ||
328 | match anything. | ||
329 | |||
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 524b88920947..409dd71f2738 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c | |||
@@ -866,14 +866,21 @@ void smp_call_function_client(int irq, struct pt_regs *regs) | |||
866 | void *info = call_data->info; | 866 | void *info = call_data->info; |
867 | 867 | ||
868 | clear_softint(1 << irq); | 868 | clear_softint(1 << irq); |
869 | |||
870 | irq_enter(); | ||
871 | |||
872 | if (!call_data->wait) { | ||
873 | /* let initiator proceed after getting data */ | ||
874 | atomic_inc(&call_data->finished); | ||
875 | } | ||
876 | |||
877 | func(info); | ||
878 | |||
879 | irq_exit(); | ||
880 | |||
869 | if (call_data->wait) { | 881 | if (call_data->wait) { |
870 | /* let initiator proceed only after completion */ | 882 | /* let initiator proceed only after completion */ |
871 | func(info); | ||
872 | atomic_inc(&call_data->finished); | 883 | atomic_inc(&call_data->finished); |
873 | } else { | ||
874 | /* let initiator proceed after getting data */ | ||
875 | atomic_inc(&call_data->finished); | ||
876 | func(info); | ||
877 | } | 884 | } |
878 | } | 885 | } |
879 | 886 | ||
@@ -1032,7 +1039,9 @@ void smp_receive_signal(int cpu) | |||
1032 | 1039 | ||
1033 | void smp_receive_signal_client(int irq, struct pt_regs *regs) | 1040 | void smp_receive_signal_client(int irq, struct pt_regs *regs) |
1034 | { | 1041 | { |
1042 | irq_enter(); | ||
1035 | clear_softint(1 << irq); | 1043 | clear_softint(1 << irq); |
1044 | irq_exit(); | ||
1036 | } | 1045 | } |
1037 | 1046 | ||
1038 | void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs) | 1047 | void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs) |
@@ -1040,6 +1049,8 @@ void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs) | |||
1040 | struct mm_struct *mm; | 1049 | struct mm_struct *mm; |
1041 | unsigned long flags; | 1050 | unsigned long flags; |
1042 | 1051 | ||
1052 | irq_enter(); | ||
1053 | |||
1043 | clear_softint(1 << irq); | 1054 | clear_softint(1 << irq); |
1044 | 1055 | ||
1045 | /* See if we need to allocate a new TLB context because | 1056 | /* See if we need to allocate a new TLB context because |
@@ -1059,6 +1070,8 @@ void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs) | |||
1059 | load_secondary_context(mm); | 1070 | load_secondary_context(mm); |
1060 | __flush_tlb_mm(CTX_HWBITS(mm->context), | 1071 | __flush_tlb_mm(CTX_HWBITS(mm->context), |
1061 | SECONDARY_CONTEXT); | 1072 | SECONDARY_CONTEXT); |
1073 | |||
1074 | irq_exit(); | ||
1062 | } | 1075 | } |
1063 | 1076 | ||
1064 | void smp_new_mmu_context_version(void) | 1077 | void smp_new_mmu_context_version(void) |
@@ -1217,6 +1230,8 @@ void smp_penguin_jailcell(int irq, struct pt_regs *regs) | |||
1217 | { | 1230 | { |
1218 | clear_softint(1 << irq); | 1231 | clear_softint(1 << irq); |
1219 | 1232 | ||
1233 | irq_enter(); | ||
1234 | |||
1220 | preempt_disable(); | 1235 | preempt_disable(); |
1221 | 1236 | ||
1222 | __asm__ __volatile__("flushw"); | 1237 | __asm__ __volatile__("flushw"); |
@@ -1229,6 +1244,8 @@ void smp_penguin_jailcell(int irq, struct pt_regs *regs) | |||
1229 | prom_world(0); | 1244 | prom_world(0); |
1230 | 1245 | ||
1231 | preempt_enable(); | 1246 | preempt_enable(); |
1247 | |||
1248 | irq_exit(); | ||
1232 | } | 1249 | } |
1233 | 1250 | ||
1234 | /* /proc/profile writes can call this, don't __init it please. */ | 1251 | /* /proc/profile writes can call this, don't __init it please. */ |
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index 73ed01ba40dc..8d4761f15fa9 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c | |||
@@ -454,8 +454,8 @@ asmlinkage long sys_ipc(unsigned int call, int first, unsigned long second, | |||
454 | err = sys_semget(first, (int)second, (int)third); | 454 | err = sys_semget(first, (int)second, (int)third); |
455 | goto out; | 455 | goto out; |
456 | case SEMCTL: { | 456 | case SEMCTL: { |
457 | err = sys_semctl(first, third, | 457 | err = sys_semctl(first, second, |
458 | (int)second | IPC_64, | 458 | (int)third | IPC_64, |
459 | (union semun) ptr); | 459 | (union semun) ptr); |
460 | goto out; | 460 | goto out; |
461 | } | 461 | } |
diff --git a/arch/x86/boot/.gitignore b/arch/x86/boot/.gitignore index b1bdc4c6f9f2..172cf8a98bdd 100644 --- a/arch/x86/boot/.gitignore +++ b/arch/x86/boot/.gitignore | |||
@@ -1,7 +1,8 @@ | |||
1 | bootsect | 1 | bootsect |
2 | bzImage | 2 | bzImage |
3 | cpustr.h | ||
4 | mkcpustr | ||
5 | offsets.h | ||
3 | setup | 6 | setup |
4 | setup.bin | 7 | setup.bin |
5 | setup.elf | 8 | setup.elf |
6 | cpustr.h | ||
7 | mkcpustr | ||
diff --git a/arch/x86/kernel/acpi/realmode/.gitignore b/arch/x86/kernel/acpi/realmode/.gitignore new file mode 100644 index 000000000000..58f1f48a58f8 --- /dev/null +++ b/arch/x86/kernel/acpi/realmode/.gitignore | |||
@@ -0,0 +1,3 @@ | |||
1 | wakeup.bin | ||
2 | wakeup.elf | ||
3 | wakeup.lds | ||
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index df4099dc1c68..65c7857a90dd 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c | |||
@@ -511,31 +511,30 @@ void *__kprobes text_poke(void *addr, const void *opcode, size_t len) | |||
511 | unsigned long flags; | 511 | unsigned long flags; |
512 | char *vaddr; | 512 | char *vaddr; |
513 | int nr_pages = 2; | 513 | int nr_pages = 2; |
514 | struct page *pages[2]; | ||
515 | int i; | ||
514 | 516 | ||
515 | BUG_ON(len > sizeof(long)); | 517 | if (!core_kernel_text((unsigned long)addr)) { |
516 | BUG_ON((((long)addr + len - 1) & ~(sizeof(long) - 1)) | 518 | pages[0] = vmalloc_to_page(addr); |
517 | - ((long)addr & ~(sizeof(long) - 1))); | 519 | pages[1] = vmalloc_to_page(addr + PAGE_SIZE); |
518 | if (kernel_text_address((unsigned long)addr)) { | ||
519 | struct page *pages[2] = { virt_to_page(addr), | ||
520 | virt_to_page(addr + PAGE_SIZE) }; | ||
521 | if (!pages[1]) | ||
522 | nr_pages = 1; | ||
523 | vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL); | ||
524 | BUG_ON(!vaddr); | ||
525 | local_irq_save(flags); | ||
526 | memcpy(&vaddr[(unsigned long)addr & ~PAGE_MASK], opcode, len); | ||
527 | local_irq_restore(flags); | ||
528 | vunmap(vaddr); | ||
529 | } else { | 520 | } else { |
530 | /* | 521 | pages[0] = virt_to_page(addr); |
531 | * modules are in vmalloc'ed memory, always writable. | 522 | WARN_ON(!PageReserved(pages[0])); |
532 | */ | 523 | pages[1] = virt_to_page(addr + PAGE_SIZE); |
533 | local_irq_save(flags); | ||
534 | memcpy(addr, opcode, len); | ||
535 | local_irq_restore(flags); | ||
536 | } | 524 | } |
525 | BUG_ON(!pages[0]); | ||
526 | if (!pages[1]) | ||
527 | nr_pages = 1; | ||
528 | vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL); | ||
529 | BUG_ON(!vaddr); | ||
530 | local_irq_save(flags); | ||
531 | memcpy(&vaddr[(unsigned long)addr & ~PAGE_MASK], opcode, len); | ||
532 | local_irq_restore(flags); | ||
533 | vunmap(vaddr); | ||
537 | sync_core(); | 534 | sync_core(); |
538 | /* Could also do a CLFLUSH here to speed up CPU recovery; but | 535 | /* Could also do a CLFLUSH here to speed up CPU recovery; but |
539 | that causes hangs on some VIA CPUs. */ | 536 | that causes hangs on some VIA CPUs. */ |
537 | for (i = 0; i < len; i++) | ||
538 | BUG_ON(((char *)addr)[i] != ((char *)opcode)[i]); | ||
540 | return addr; | 539 | return addr; |
541 | } | 540 | } |
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index f0f8934fc303..2a609dc3271c 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S | |||
@@ -409,7 +409,7 @@ restore_nocheck_notrace: | |||
409 | irq_return: | 409 | irq_return: |
410 | INTERRUPT_RETURN | 410 | INTERRUPT_RETURN |
411 | .section .fixup,"ax" | 411 | .section .fixup,"ax" |
412 | iret_exc: | 412 | ENTRY(iret_exc) |
413 | pushl $0 # no error code | 413 | pushl $0 # no error code |
414 | pushl $do_iret_error | 414 | pushl $do_iret_error |
415 | jmp error_code | 415 | jmp error_code |
@@ -1017,6 +1017,13 @@ ENTRY(kernel_thread_helper) | |||
1017 | ENDPROC(kernel_thread_helper) | 1017 | ENDPROC(kernel_thread_helper) |
1018 | 1018 | ||
1019 | #ifdef CONFIG_XEN | 1019 | #ifdef CONFIG_XEN |
1020 | /* Xen doesn't set %esp to be precisely what the normal sysenter | ||
1021 | entrypoint expects, so fix it up before using the normal path. */ | ||
1022 | ENTRY(xen_sysenter_target) | ||
1023 | RING0_INT_FRAME | ||
1024 | addl $5*4, %esp /* remove xen-provided frame */ | ||
1025 | jmp sysenter_past_esp | ||
1026 | |||
1020 | ENTRY(xen_hypervisor_callback) | 1027 | ENTRY(xen_hypervisor_callback) |
1021 | CFI_STARTPROC | 1028 | CFI_STARTPROC |
1022 | pushl $0 | 1029 | pushl $0 |
@@ -1035,8 +1042,9 @@ ENTRY(xen_hypervisor_callback) | |||
1035 | cmpl $xen_iret_end_crit,%eax | 1042 | cmpl $xen_iret_end_crit,%eax |
1036 | jae 1f | 1043 | jae 1f |
1037 | 1044 | ||
1038 | call xen_iret_crit_fixup | 1045 | jmp xen_iret_crit_fixup |
1039 | 1046 | ||
1047 | ENTRY(xen_do_upcall) | ||
1040 | 1: mov %esp, %eax | 1048 | 1: mov %esp, %eax |
1041 | call xen_evtchn_do_upcall | 1049 | call xen_evtchn_do_upcall |
1042 | jmp ret_from_intr | 1050 | jmp ret_from_intr |
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index 3733412d1357..74f0c5ea2a03 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c | |||
@@ -366,11 +366,13 @@ struct pv_mmu_ops pv_mmu_ops = { | |||
366 | .flush_tlb_single = native_flush_tlb_single, | 366 | .flush_tlb_single = native_flush_tlb_single, |
367 | .flush_tlb_others = native_flush_tlb_others, | 367 | .flush_tlb_others = native_flush_tlb_others, |
368 | 368 | ||
369 | .alloc_pt = paravirt_nop, | 369 | .alloc_pte = paravirt_nop, |
370 | .alloc_pd = paravirt_nop, | 370 | .alloc_pmd = paravirt_nop, |
371 | .alloc_pd_clone = paravirt_nop, | 371 | .alloc_pmd_clone = paravirt_nop, |
372 | .release_pt = paravirt_nop, | 372 | .alloc_pud = paravirt_nop, |
373 | .release_pd = paravirt_nop, | 373 | .release_pte = paravirt_nop, |
374 | .release_pmd = paravirt_nop, | ||
375 | .release_pud = paravirt_nop, | ||
374 | 376 | ||
375 | .set_pte = native_set_pte, | 377 | .set_pte = native_set_pte, |
376 | .set_pte_at = native_set_pte_at, | 378 | .set_pte_at = native_set_pte_at, |
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 19c9386ac118..1791a751a772 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <asm/apic.h> | 8 | #include <asm/apic.h> |
9 | #include <asm/desc.h> | 9 | #include <asm/desc.h> |
10 | #include <asm/hpet.h> | 10 | #include <asm/hpet.h> |
11 | #include <asm/pgtable.h> | ||
11 | #include <asm/reboot_fixups.h> | 12 | #include <asm/reboot_fixups.h> |
12 | #include <asm/reboot.h> | 13 | #include <asm/reboot.h> |
13 | 14 | ||
@@ -15,7 +16,6 @@ | |||
15 | # include <linux/dmi.h> | 16 | # include <linux/dmi.h> |
16 | # include <linux/ctype.h> | 17 | # include <linux/ctype.h> |
17 | # include <linux/mc146818rtc.h> | 18 | # include <linux/mc146818rtc.h> |
18 | # include <asm/pgtable.h> | ||
19 | #else | 19 | #else |
20 | # include <asm/iommu.h> | 20 | # include <asm/iommu.h> |
21 | #endif | 21 | #endif |
@@ -275,7 +275,7 @@ void machine_real_restart(unsigned char *code, int length) | |||
275 | /* Remap the kernel at virtual address zero, as well as offset zero | 275 | /* Remap the kernel at virtual address zero, as well as offset zero |
276 | from the kernel segment. This assumes the kernel segment starts at | 276 | from the kernel segment. This assumes the kernel segment starts at |
277 | virtual address PAGE_OFFSET. */ | 277 | virtual address PAGE_OFFSET. */ |
278 | memcpy(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, | 278 | memcpy(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY, |
279 | sizeof(swapper_pg_dir [0]) * KERNEL_PGD_PTRS); | 279 | sizeof(swapper_pg_dir [0]) * KERNEL_PGD_PTRS); |
280 | 280 | ||
281 | /* | 281 | /* |
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index ade371f9663a..eef79e84145f 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c | |||
@@ -1039,8 +1039,8 @@ int __cpuinit native_cpu_up(unsigned int cpu) | |||
1039 | 1039 | ||
1040 | #ifdef CONFIG_X86_32 | 1040 | #ifdef CONFIG_X86_32 |
1041 | /* init low mem mapping */ | 1041 | /* init low mem mapping */ |
1042 | clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, | 1042 | clone_pgd_range(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY, |
1043 | min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS)); | 1043 | min_t(unsigned long, KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY)); |
1044 | flush_tlb_all(); | 1044 | flush_tlb_all(); |
1045 | #endif | 1045 | #endif |
1046 | 1046 | ||
diff --git a/arch/x86/kernel/vmi_32.c b/arch/x86/kernel/vmi_32.c index 12affe1f9bce..956f38927aa7 100644 --- a/arch/x86/kernel/vmi_32.c +++ b/arch/x86/kernel/vmi_32.c | |||
@@ -320,7 +320,7 @@ static void check_zeroed_page(u32 pfn, int type, struct page *page) | |||
320 | * pdes need to be zeroed. | 320 | * pdes need to be zeroed. |
321 | */ | 321 | */ |
322 | if (type & VMI_PAGE_CLONE) | 322 | if (type & VMI_PAGE_CLONE) |
323 | limit = USER_PTRS_PER_PGD; | 323 | limit = KERNEL_PGD_BOUNDARY; |
324 | for (i = 0; i < limit; i++) | 324 | for (i = 0; i < limit; i++) |
325 | BUG_ON(ptr[i]); | 325 | BUG_ON(ptr[i]); |
326 | } | 326 | } |
@@ -392,13 +392,13 @@ static void *vmi_kmap_atomic_pte(struct page *page, enum km_type type) | |||
392 | } | 392 | } |
393 | #endif | 393 | #endif |
394 | 394 | ||
395 | static void vmi_allocate_pt(struct mm_struct *mm, u32 pfn) | 395 | static void vmi_allocate_pte(struct mm_struct *mm, u32 pfn) |
396 | { | 396 | { |
397 | vmi_set_page_type(pfn, VMI_PAGE_L1); | 397 | vmi_set_page_type(pfn, VMI_PAGE_L1); |
398 | vmi_ops.allocate_page(pfn, VMI_PAGE_L1, 0, 0, 0); | 398 | vmi_ops.allocate_page(pfn, VMI_PAGE_L1, 0, 0, 0); |
399 | } | 399 | } |
400 | 400 | ||
401 | static void vmi_allocate_pd(struct mm_struct *mm, u32 pfn) | 401 | static void vmi_allocate_pmd(struct mm_struct *mm, u32 pfn) |
402 | { | 402 | { |
403 | /* | 403 | /* |
404 | * This call comes in very early, before mem_map is setup. | 404 | * This call comes in very early, before mem_map is setup. |
@@ -409,20 +409,20 @@ static void vmi_allocate_pd(struct mm_struct *mm, u32 pfn) | |||
409 | vmi_ops.allocate_page(pfn, VMI_PAGE_L2, 0, 0, 0); | 409 | vmi_ops.allocate_page(pfn, VMI_PAGE_L2, 0, 0, 0); |
410 | } | 410 | } |
411 | 411 | ||
412 | static void vmi_allocate_pd_clone(u32 pfn, u32 clonepfn, u32 start, u32 count) | 412 | static void vmi_allocate_pmd_clone(u32 pfn, u32 clonepfn, u32 start, u32 count) |
413 | { | 413 | { |
414 | vmi_set_page_type(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE); | 414 | vmi_set_page_type(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE); |
415 | vmi_check_page_type(clonepfn, VMI_PAGE_L2); | 415 | vmi_check_page_type(clonepfn, VMI_PAGE_L2); |
416 | vmi_ops.allocate_page(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE, clonepfn, start, count); | 416 | vmi_ops.allocate_page(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE, clonepfn, start, count); |
417 | } | 417 | } |
418 | 418 | ||
419 | static void vmi_release_pt(u32 pfn) | 419 | static void vmi_release_pte(u32 pfn) |
420 | { | 420 | { |
421 | vmi_ops.release_page(pfn, VMI_PAGE_L1); | 421 | vmi_ops.release_page(pfn, VMI_PAGE_L1); |
422 | vmi_set_page_type(pfn, VMI_PAGE_NORMAL); | 422 | vmi_set_page_type(pfn, VMI_PAGE_NORMAL); |
423 | } | 423 | } |
424 | 424 | ||
425 | static void vmi_release_pd(u32 pfn) | 425 | static void vmi_release_pmd(u32 pfn) |
426 | { | 426 | { |
427 | vmi_ops.release_page(pfn, VMI_PAGE_L2); | 427 | vmi_ops.release_page(pfn, VMI_PAGE_L2); |
428 | vmi_set_page_type(pfn, VMI_PAGE_NORMAL); | 428 | vmi_set_page_type(pfn, VMI_PAGE_NORMAL); |
@@ -871,15 +871,15 @@ static inline int __init activate_vmi(void) | |||
871 | 871 | ||
872 | vmi_ops.allocate_page = vmi_get_function(VMI_CALL_AllocatePage); | 872 | vmi_ops.allocate_page = vmi_get_function(VMI_CALL_AllocatePage); |
873 | if (vmi_ops.allocate_page) { | 873 | if (vmi_ops.allocate_page) { |
874 | pv_mmu_ops.alloc_pt = vmi_allocate_pt; | 874 | pv_mmu_ops.alloc_pte = vmi_allocate_pte; |
875 | pv_mmu_ops.alloc_pd = vmi_allocate_pd; | 875 | pv_mmu_ops.alloc_pmd = vmi_allocate_pmd; |
876 | pv_mmu_ops.alloc_pd_clone = vmi_allocate_pd_clone; | 876 | pv_mmu_ops.alloc_pmd_clone = vmi_allocate_pmd_clone; |
877 | } | 877 | } |
878 | 878 | ||
879 | vmi_ops.release_page = vmi_get_function(VMI_CALL_ReleasePage); | 879 | vmi_ops.release_page = vmi_get_function(VMI_CALL_ReleasePage); |
880 | if (vmi_ops.release_page) { | 880 | if (vmi_ops.release_page) { |
881 | pv_mmu_ops.release_pt = vmi_release_pt; | 881 | pv_mmu_ops.release_pte = vmi_release_pte; |
882 | pv_mmu_ops.release_pd = vmi_release_pd; | 882 | pv_mmu_ops.release_pmd = vmi_release_pmd; |
883 | } | 883 | } |
884 | 884 | ||
885 | /* Set linear is needed in all cases */ | 885 | /* Set linear is needed in all cases */ |
diff --git a/arch/x86/mach-voyager/voyager_smp.c b/arch/x86/mach-voyager/voyager_smp.c index d05722121d24..6e2c4efce0ef 100644 --- a/arch/x86/mach-voyager/voyager_smp.c +++ b/arch/x86/mach-voyager/voyager_smp.c | |||
@@ -543,8 +543,8 @@ static void __init do_boot_cpu(__u8 cpu) | |||
543 | hijack_source.idt.Offset, stack_start.sp)); | 543 | hijack_source.idt.Offset, stack_start.sp)); |
544 | 544 | ||
545 | /* init lowmem identity mapping */ | 545 | /* init lowmem identity mapping */ |
546 | clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, | 546 | clone_pgd_range(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY, |
547 | min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS)); | 547 | min_t(unsigned long, KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY)); |
548 | flush_tlb_all(); | 548 | flush_tlb_all(); |
549 | 549 | ||
550 | if (quad_boot) { | 550 | if (quad_boot) { |
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index 20941d2954e2..b7b3e4c7cfc9 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | obj-y := init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \ | 1 | obj-y := init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \ |
2 | pat.o | 2 | pat.o pgtable.o |
3 | 3 | ||
4 | obj-$(CONFIG_X86_32) += pgtable_32.o | 4 | obj-$(CONFIG_X86_32) += pgtable_32.o |
5 | 5 | ||
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 9ec62da85fd7..08aa1878fad4 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c | |||
@@ -71,7 +71,7 @@ static pmd_t * __init one_md_table_init(pgd_t *pgd) | |||
71 | if (!(pgd_val(*pgd) & _PAGE_PRESENT)) { | 71 | if (!(pgd_val(*pgd) & _PAGE_PRESENT)) { |
72 | pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); | 72 | pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); |
73 | 73 | ||
74 | paravirt_alloc_pd(&init_mm, __pa(pmd_table) >> PAGE_SHIFT); | 74 | paravirt_alloc_pmd(&init_mm, __pa(pmd_table) >> PAGE_SHIFT); |
75 | set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); | 75 | set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); |
76 | pud = pud_offset(pgd, 0); | 76 | pud = pud_offset(pgd, 0); |
77 | BUG_ON(pmd_table != pmd_offset(pud, 0)); | 77 | BUG_ON(pmd_table != pmd_offset(pud, 0)); |
@@ -100,7 +100,7 @@ static pte_t * __init one_page_table_init(pmd_t *pmd) | |||
100 | (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE); | 100 | (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE); |
101 | } | 101 | } |
102 | 102 | ||
103 | paravirt_alloc_pt(&init_mm, __pa(page_table) >> PAGE_SHIFT); | 103 | paravirt_alloc_pte(&init_mm, __pa(page_table) >> PAGE_SHIFT); |
104 | set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); | 104 | set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); |
105 | BUG_ON(page_table != pte_offset_kernel(pmd, 0)); | 105 | BUG_ON(page_table != pte_offset_kernel(pmd, 0)); |
106 | } | 106 | } |
@@ -365,7 +365,7 @@ void __init native_pagetable_setup_start(pgd_t *base) | |||
365 | 365 | ||
366 | pte_clear(NULL, va, pte); | 366 | pte_clear(NULL, va, pte); |
367 | } | 367 | } |
368 | paravirt_alloc_pd(&init_mm, __pa(base) >> PAGE_SHIFT); | 368 | paravirt_alloc_pmd(&init_mm, __pa(base) >> PAGE_SHIFT); |
369 | } | 369 | } |
370 | 370 | ||
371 | void __init native_pagetable_setup_done(pgd_t *base) | 371 | void __init native_pagetable_setup_done(pgd_t *base) |
@@ -457,7 +457,7 @@ void zap_low_mappings(void) | |||
457 | * Note that "pgd_clear()" doesn't do it for | 457 | * Note that "pgd_clear()" doesn't do it for |
458 | * us, because pgd_clear() is a no-op on i386. | 458 | * us, because pgd_clear() is a no-op on i386. |
459 | */ | 459 | */ |
460 | for (i = 0; i < USER_PTRS_PER_PGD; i++) { | 460 | for (i = 0; i < KERNEL_PGD_BOUNDARY; i++) { |
461 | #ifdef CONFIG_X86_PAE | 461 | #ifdef CONFIG_X86_PAE |
462 | set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page))); | 462 | set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page))); |
463 | #else | 463 | #else |
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 1ff7906a9a4d..b798e7b92b17 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c | |||
@@ -135,7 +135,7 @@ static __init void *spp_getpage(void) | |||
135 | return ptr; | 135 | return ptr; |
136 | } | 136 | } |
137 | 137 | ||
138 | static __init void | 138 | static void |
139 | set_pte_phys(unsigned long vaddr, unsigned long phys, pgprot_t prot) | 139 | set_pte_phys(unsigned long vaddr, unsigned long phys, pgprot_t prot) |
140 | { | 140 | { |
141 | pgd_t *pgd; | 141 | pgd_t *pgd; |
@@ -173,7 +173,7 @@ set_pte_phys(unsigned long vaddr, unsigned long phys, pgprot_t prot) | |||
173 | new_pte = pfn_pte(phys >> PAGE_SHIFT, prot); | 173 | new_pte = pfn_pte(phys >> PAGE_SHIFT, prot); |
174 | 174 | ||
175 | pte = pte_offset_kernel(pmd, vaddr); | 175 | pte = pte_offset_kernel(pmd, vaddr); |
176 | if (!pte_none(*pte) && | 176 | if (!pte_none(*pte) && pte_val(new_pte) && |
177 | pte_val(*pte) != (pte_val(new_pte) & __supported_pte_mask)) | 177 | pte_val(*pte) != (pte_val(new_pte) & __supported_pte_mask)) |
178 | pte_ERROR(*pte); | 178 | pte_ERROR(*pte); |
179 | set_pte(pte, new_pte); | 179 | set_pte(pte, new_pte); |
@@ -214,8 +214,7 @@ void __init cleanup_highmap(void) | |||
214 | } | 214 | } |
215 | 215 | ||
216 | /* NOTE: this is meant to be run only at boot */ | 216 | /* NOTE: this is meant to be run only at boot */ |
217 | void __init | 217 | void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot) |
218 | __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot) | ||
219 | { | 218 | { |
220 | unsigned long address = __fix_to_virt(idx); | 219 | unsigned long address = __fix_to_virt(idx); |
221 | 220 | ||
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 3a4baf95e24d..36a3f7ded626 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c | |||
@@ -407,7 +407,7 @@ void __init early_ioremap_clear(void) | |||
407 | 407 | ||
408 | pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)); | 408 | pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)); |
409 | pmd_clear(pmd); | 409 | pmd_clear(pmd); |
410 | paravirt_release_pt(__pa(bm_pte) >> PAGE_SHIFT); | 410 | paravirt_release_pte(__pa(bm_pte) >> PAGE_SHIFT); |
411 | __flush_tlb_all(); | 411 | __flush_tlb_all(); |
412 | } | 412 | } |
413 | 413 | ||
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index c29ebd037254..bd5e05c654dc 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -483,9 +483,7 @@ static int split_large_page(pte_t *kpte, unsigned long address) | |||
483 | goto out_unlock; | 483 | goto out_unlock; |
484 | 484 | ||
485 | pbase = (pte_t *)page_address(base); | 485 | pbase = (pte_t *)page_address(base); |
486 | #ifdef CONFIG_X86_32 | 486 | paravirt_alloc_pte(&init_mm, page_to_pfn(base)); |
487 | paravirt_alloc_pt(&init_mm, page_to_pfn(base)); | ||
488 | #endif | ||
489 | ref_prot = pte_pgprot(pte_clrhuge(*kpte)); | 487 | ref_prot = pte_pgprot(pte_clrhuge(*kpte)); |
490 | 488 | ||
491 | #ifdef CONFIG_X86_64 | 489 | #ifdef CONFIG_X86_64 |
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c new file mode 100644 index 000000000000..50159764f694 --- /dev/null +++ b/arch/x86/mm/pgtable.c | |||
@@ -0,0 +1,276 @@ | |||
1 | #include <linux/mm.h> | ||
2 | #include <asm/pgalloc.h> | ||
3 | #include <asm/pgtable.h> | ||
4 | #include <asm/tlb.h> | ||
5 | |||
6 | pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) | ||
7 | { | ||
8 | return (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO); | ||
9 | } | ||
10 | |||
11 | pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address) | ||
12 | { | ||
13 | struct page *pte; | ||
14 | |||
15 | #ifdef CONFIG_HIGHPTE | ||
16 | pte = alloc_pages(GFP_KERNEL|__GFP_HIGHMEM|__GFP_REPEAT|__GFP_ZERO, 0); | ||
17 | #else | ||
18 | pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0); | ||
19 | #endif | ||
20 | if (pte) | ||
21 | pgtable_page_ctor(pte); | ||
22 | return pte; | ||
23 | } | ||
24 | |||
25 | void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte) | ||
26 | { | ||
27 | pgtable_page_dtor(pte); | ||
28 | paravirt_release_pte(page_to_pfn(pte)); | ||
29 | tlb_remove_page(tlb, pte); | ||
30 | } | ||
31 | |||
32 | #if PAGETABLE_LEVELS > 2 | ||
33 | void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd) | ||
34 | { | ||
35 | paravirt_release_pmd(__pa(pmd) >> PAGE_SHIFT); | ||
36 | tlb_remove_page(tlb, virt_to_page(pmd)); | ||
37 | } | ||
38 | |||
39 | #if PAGETABLE_LEVELS > 3 | ||
40 | void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pud) | ||
41 | { | ||
42 | paravirt_release_pud(__pa(pud) >> PAGE_SHIFT); | ||
43 | tlb_remove_page(tlb, virt_to_page(pud)); | ||
44 | } | ||
45 | #endif /* PAGETABLE_LEVELS > 3 */ | ||
46 | #endif /* PAGETABLE_LEVELS > 2 */ | ||
47 | |||
48 | static inline void pgd_list_add(pgd_t *pgd) | ||
49 | { | ||
50 | struct page *page = virt_to_page(pgd); | ||
51 | |||
52 | list_add(&page->lru, &pgd_list); | ||
53 | } | ||
54 | |||
55 | static inline void pgd_list_del(pgd_t *pgd) | ||
56 | { | ||
57 | struct page *page = virt_to_page(pgd); | ||
58 | |||
59 | list_del(&page->lru); | ||
60 | } | ||
61 | |||
62 | #define UNSHARED_PTRS_PER_PGD \ | ||
63 | (SHARED_KERNEL_PMD ? KERNEL_PGD_BOUNDARY : PTRS_PER_PGD) | ||
64 | |||
65 | static void pgd_ctor(void *p) | ||
66 | { | ||
67 | pgd_t *pgd = p; | ||
68 | unsigned long flags; | ||
69 | |||
70 | /* Clear usermode parts of PGD */ | ||
71 | memset(pgd, 0, KERNEL_PGD_BOUNDARY*sizeof(pgd_t)); | ||
72 | |||
73 | spin_lock_irqsave(&pgd_lock, flags); | ||
74 | |||
75 | /* If the pgd points to a shared pagetable level (either the | ||
76 | ptes in non-PAE, or shared PMD in PAE), then just copy the | ||
77 | references from swapper_pg_dir. */ | ||
78 | if (PAGETABLE_LEVELS == 2 || | ||
79 | (PAGETABLE_LEVELS == 3 && SHARED_KERNEL_PMD) || | ||
80 | PAGETABLE_LEVELS == 4) { | ||
81 | clone_pgd_range(pgd + KERNEL_PGD_BOUNDARY, | ||
82 | swapper_pg_dir + KERNEL_PGD_BOUNDARY, | ||
83 | KERNEL_PGD_PTRS); | ||
84 | paravirt_alloc_pmd_clone(__pa(pgd) >> PAGE_SHIFT, | ||
85 | __pa(swapper_pg_dir) >> PAGE_SHIFT, | ||
86 | KERNEL_PGD_BOUNDARY, | ||
87 | KERNEL_PGD_PTRS); | ||
88 | } | ||
89 | |||
90 | /* list required to sync kernel mapping updates */ | ||
91 | if (!SHARED_KERNEL_PMD) | ||
92 | pgd_list_add(pgd); | ||
93 | |||
94 | spin_unlock_irqrestore(&pgd_lock, flags); | ||
95 | } | ||
96 | |||
97 | static void pgd_dtor(void *pgd) | ||
98 | { | ||
99 | unsigned long flags; /* can be called from interrupt context */ | ||
100 | |||
101 | if (SHARED_KERNEL_PMD) | ||
102 | return; | ||
103 | |||
104 | spin_lock_irqsave(&pgd_lock, flags); | ||
105 | pgd_list_del(pgd); | ||
106 | spin_unlock_irqrestore(&pgd_lock, flags); | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * List of all pgd's needed for non-PAE so it can invalidate entries | ||
111 | * in both cached and uncached pgd's; not needed for PAE since the | ||
112 | * kernel pmd is shared. If PAE were not to share the pmd a similar | ||
113 | * tactic would be needed. This is essentially codepath-based locking | ||
114 | * against pageattr.c; it is the unique case in which a valid change | ||
115 | * of kernel pagetables can't be lazily synchronized by vmalloc faults. | ||
116 | * vmalloc faults work because attached pagetables are never freed. | ||
117 | * -- wli | ||
118 | */ | ||
119 | |||
120 | #ifdef CONFIG_X86_PAE | ||
121 | /* | ||
122 | * Mop up any pmd pages which may still be attached to the pgd. | ||
123 | * Normally they will be freed by munmap/exit_mmap, but any pmd we | ||
124 | * preallocate which never got a corresponding vma will need to be | ||
125 | * freed manually. | ||
126 | */ | ||
127 | static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp) | ||
128 | { | ||
129 | int i; | ||
130 | |||
131 | for(i = 0; i < UNSHARED_PTRS_PER_PGD; i++) { | ||
132 | pgd_t pgd = pgdp[i]; | ||
133 | |||
134 | if (pgd_val(pgd) != 0) { | ||
135 | pmd_t *pmd = (pmd_t *)pgd_page_vaddr(pgd); | ||
136 | |||
137 | pgdp[i] = native_make_pgd(0); | ||
138 | |||
139 | paravirt_release_pmd(pgd_val(pgd) >> PAGE_SHIFT); | ||
140 | pmd_free(mm, pmd); | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * In PAE mode, we need to do a cr3 reload (=tlb flush) when | ||
147 | * updating the top-level pagetable entries to guarantee the | ||
148 | * processor notices the update. Since this is expensive, and | ||
149 | * all 4 top-level entries are used almost immediately in a | ||
150 | * new process's life, we just pre-populate them here. | ||
151 | * | ||
152 | * Also, if we're in a paravirt environment where the kernel pmd is | ||
153 | * not shared between pagetables (!SHARED_KERNEL_PMDS), we allocate | ||
154 | * and initialize the kernel pmds here. | ||
155 | */ | ||
156 | static int pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd) | ||
157 | { | ||
158 | pud_t *pud; | ||
159 | unsigned long addr; | ||
160 | int i; | ||
161 | |||
162 | pud = pud_offset(pgd, 0); | ||
163 | for (addr = i = 0; i < UNSHARED_PTRS_PER_PGD; | ||
164 | i++, pud++, addr += PUD_SIZE) { | ||
165 | pmd_t *pmd = pmd_alloc_one(mm, addr); | ||
166 | |||
167 | if (!pmd) { | ||
168 | pgd_mop_up_pmds(mm, pgd); | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | if (i >= KERNEL_PGD_BOUNDARY) | ||
173 | memcpy(pmd, (pmd_t *)pgd_page_vaddr(swapper_pg_dir[i]), | ||
174 | sizeof(pmd_t) * PTRS_PER_PMD); | ||
175 | |||
176 | pud_populate(mm, pud, pmd); | ||
177 | } | ||
178 | |||
179 | return 1; | ||
180 | } | ||
181 | |||
182 | void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd) | ||
183 | { | ||
184 | paravirt_alloc_pmd(mm, __pa(pmd) >> PAGE_SHIFT); | ||
185 | |||
186 | /* Note: almost everything apart from _PAGE_PRESENT is | ||
187 | reserved at the pmd (PDPT) level. */ | ||
188 | set_pud(pudp, __pud(__pa(pmd) | _PAGE_PRESENT)); | ||
189 | |||
190 | /* | ||
191 | * According to Intel App note "TLBs, Paging-Structure Caches, | ||
192 | * and Their Invalidation", April 2007, document 317080-001, | ||
193 | * section 8.1: in PAE mode we explicitly have to flush the | ||
194 | * TLB via cr3 if the top-level pgd is changed... | ||
195 | */ | ||
196 | if (mm == current->active_mm) | ||
197 | write_cr3(read_cr3()); | ||
198 | } | ||
199 | #else /* !CONFIG_X86_PAE */ | ||
200 | /* No need to prepopulate any pagetable entries in non-PAE modes. */ | ||
201 | static int pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd) | ||
202 | { | ||
203 | return 1; | ||
204 | } | ||
205 | |||
206 | static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgd) | ||
207 | { | ||
208 | } | ||
209 | #endif /* CONFIG_X86_PAE */ | ||
210 | |||
211 | pgd_t *pgd_alloc(struct mm_struct *mm) | ||
212 | { | ||
213 | pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_ZERO); | ||
214 | |||
215 | /* so that alloc_pmd can use it */ | ||
216 | mm->pgd = pgd; | ||
217 | if (pgd) | ||
218 | pgd_ctor(pgd); | ||
219 | |||
220 | if (pgd && !pgd_prepopulate_pmd(mm, pgd)) { | ||
221 | pgd_dtor(pgd); | ||
222 | free_page((unsigned long)pgd); | ||
223 | pgd = NULL; | ||
224 | } | ||
225 | |||
226 | return pgd; | ||
227 | } | ||
228 | |||
229 | void pgd_free(struct mm_struct *mm, pgd_t *pgd) | ||
230 | { | ||
231 | pgd_mop_up_pmds(mm, pgd); | ||
232 | pgd_dtor(pgd); | ||
233 | free_page((unsigned long)pgd); | ||
234 | } | ||
235 | |||
236 | int ptep_set_access_flags(struct vm_area_struct *vma, | ||
237 | unsigned long address, pte_t *ptep, | ||
238 | pte_t entry, int dirty) | ||
239 | { | ||
240 | int changed = !pte_same(*ptep, entry); | ||
241 | |||
242 | if (changed && dirty) { | ||
243 | *ptep = entry; | ||
244 | pte_update_defer(vma->vm_mm, address, ptep); | ||
245 | flush_tlb_page(vma, address); | ||
246 | } | ||
247 | |||
248 | return changed; | ||
249 | } | ||
250 | |||
251 | int ptep_test_and_clear_young(struct vm_area_struct *vma, | ||
252 | unsigned long addr, pte_t *ptep) | ||
253 | { | ||
254 | int ret = 0; | ||
255 | |||
256 | if (pte_young(*ptep)) | ||
257 | ret = test_and_clear_bit(_PAGE_BIT_ACCESSED, | ||
258 | &ptep->pte); | ||
259 | |||
260 | if (ret) | ||
261 | pte_update(vma->vm_mm, addr, ptep); | ||
262 | |||
263 | return ret; | ||
264 | } | ||
265 | |||
266 | int ptep_clear_flush_young(struct vm_area_struct *vma, | ||
267 | unsigned long address, pte_t *ptep) | ||
268 | { | ||
269 | int young; | ||
270 | |||
271 | young = ptep_test_and_clear_young(vma, address, ptep); | ||
272 | if (young) | ||
273 | flush_tlb_page(vma, address); | ||
274 | |||
275 | return young; | ||
276 | } | ||
diff --git a/arch/x86/mm/pgtable_32.c b/arch/x86/mm/pgtable_32.c index 6fb9e7c6893f..9ee007be9142 100644 --- a/arch/x86/mm/pgtable_32.c +++ b/arch/x86/mm/pgtable_32.c | |||
@@ -173,210 +173,6 @@ void reserve_top_address(unsigned long reserve) | |||
173 | __VMALLOC_RESERVE += reserve; | 173 | __VMALLOC_RESERVE += reserve; |
174 | } | 174 | } |
175 | 175 | ||
176 | pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) | ||
177 | { | ||
178 | return (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO); | ||
179 | } | ||
180 | |||
181 | pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address) | ||
182 | { | ||
183 | struct page *pte; | ||
184 | |||
185 | #ifdef CONFIG_HIGHPTE | ||
186 | pte = alloc_pages(GFP_KERNEL|__GFP_HIGHMEM|__GFP_REPEAT|__GFP_ZERO, 0); | ||
187 | #else | ||
188 | pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0); | ||
189 | #endif | ||
190 | if (pte) | ||
191 | pgtable_page_ctor(pte); | ||
192 | return pte; | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * List of all pgd's needed for non-PAE so it can invalidate entries | ||
197 | * in both cached and uncached pgd's; not needed for PAE since the | ||
198 | * kernel pmd is shared. If PAE were not to share the pmd a similar | ||
199 | * tactic would be needed. This is essentially codepath-based locking | ||
200 | * against pageattr.c; it is the unique case in which a valid change | ||
201 | * of kernel pagetables can't be lazily synchronized by vmalloc faults. | ||
202 | * vmalloc faults work because attached pagetables are never freed. | ||
203 | * -- wli | ||
204 | */ | ||
205 | static inline void pgd_list_add(pgd_t *pgd) | ||
206 | { | ||
207 | struct page *page = virt_to_page(pgd); | ||
208 | |||
209 | list_add(&page->lru, &pgd_list); | ||
210 | } | ||
211 | |||
212 | static inline void pgd_list_del(pgd_t *pgd) | ||
213 | { | ||
214 | struct page *page = virt_to_page(pgd); | ||
215 | |||
216 | list_del(&page->lru); | ||
217 | } | ||
218 | |||
219 | #define UNSHARED_PTRS_PER_PGD \ | ||
220 | (SHARED_KERNEL_PMD ? USER_PTRS_PER_PGD : PTRS_PER_PGD) | ||
221 | |||
222 | static void pgd_ctor(void *p) | ||
223 | { | ||
224 | pgd_t *pgd = p; | ||
225 | unsigned long flags; | ||
226 | |||
227 | /* Clear usermode parts of PGD */ | ||
228 | memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); | ||
229 | |||
230 | spin_lock_irqsave(&pgd_lock, flags); | ||
231 | |||
232 | /* If the pgd points to a shared pagetable level (either the | ||
233 | ptes in non-PAE, or shared PMD in PAE), then just copy the | ||
234 | references from swapper_pg_dir. */ | ||
235 | if (PAGETABLE_LEVELS == 2 || | ||
236 | (PAGETABLE_LEVELS == 3 && SHARED_KERNEL_PMD)) { | ||
237 | clone_pgd_range(pgd + USER_PTRS_PER_PGD, | ||
238 | swapper_pg_dir + USER_PTRS_PER_PGD, | ||
239 | KERNEL_PGD_PTRS); | ||
240 | paravirt_alloc_pd_clone(__pa(pgd) >> PAGE_SHIFT, | ||
241 | __pa(swapper_pg_dir) >> PAGE_SHIFT, | ||
242 | USER_PTRS_PER_PGD, | ||
243 | KERNEL_PGD_PTRS); | ||
244 | } | ||
245 | |||
246 | /* list required to sync kernel mapping updates */ | ||
247 | if (!SHARED_KERNEL_PMD) | ||
248 | pgd_list_add(pgd); | ||
249 | |||
250 | spin_unlock_irqrestore(&pgd_lock, flags); | ||
251 | } | ||
252 | |||
253 | static void pgd_dtor(void *pgd) | ||
254 | { | ||
255 | unsigned long flags; /* can be called from interrupt context */ | ||
256 | |||
257 | if (SHARED_KERNEL_PMD) | ||
258 | return; | ||
259 | |||
260 | spin_lock_irqsave(&pgd_lock, flags); | ||
261 | pgd_list_del(pgd); | ||
262 | spin_unlock_irqrestore(&pgd_lock, flags); | ||
263 | } | ||
264 | |||
265 | #ifdef CONFIG_X86_PAE | ||
266 | /* | ||
267 | * Mop up any pmd pages which may still be attached to the pgd. | ||
268 | * Normally they will be freed by munmap/exit_mmap, but any pmd we | ||
269 | * preallocate which never got a corresponding vma will need to be | ||
270 | * freed manually. | ||
271 | */ | ||
272 | static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp) | ||
273 | { | ||
274 | int i; | ||
275 | |||
276 | for(i = 0; i < UNSHARED_PTRS_PER_PGD; i++) { | ||
277 | pgd_t pgd = pgdp[i]; | ||
278 | |||
279 | if (pgd_val(pgd) != 0) { | ||
280 | pmd_t *pmd = (pmd_t *)pgd_page_vaddr(pgd); | ||
281 | |||
282 | pgdp[i] = native_make_pgd(0); | ||
283 | |||
284 | paravirt_release_pd(pgd_val(pgd) >> PAGE_SHIFT); | ||
285 | pmd_free(mm, pmd); | ||
286 | } | ||
287 | } | ||
288 | } | ||
289 | |||
290 | /* | ||
291 | * In PAE mode, we need to do a cr3 reload (=tlb flush) when | ||
292 | * updating the top-level pagetable entries to guarantee the | ||
293 | * processor notices the update. Since this is expensive, and | ||
294 | * all 4 top-level entries are used almost immediately in a | ||
295 | * new process's life, we just pre-populate them here. | ||
296 | * | ||
297 | * Also, if we're in a paravirt environment where the kernel pmd is | ||
298 | * not shared between pagetables (!SHARED_KERNEL_PMDS), we allocate | ||
299 | * and initialize the kernel pmds here. | ||
300 | */ | ||
301 | static int pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd) | ||
302 | { | ||
303 | pud_t *pud; | ||
304 | unsigned long addr; | ||
305 | int i; | ||
306 | |||
307 | pud = pud_offset(pgd, 0); | ||
308 | for (addr = i = 0; i < UNSHARED_PTRS_PER_PGD; | ||
309 | i++, pud++, addr += PUD_SIZE) { | ||
310 | pmd_t *pmd = pmd_alloc_one(mm, addr); | ||
311 | |||
312 | if (!pmd) { | ||
313 | pgd_mop_up_pmds(mm, pgd); | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | if (i >= USER_PTRS_PER_PGD) | ||
318 | memcpy(pmd, (pmd_t *)pgd_page_vaddr(swapper_pg_dir[i]), | ||
319 | sizeof(pmd_t) * PTRS_PER_PMD); | ||
320 | |||
321 | pud_populate(mm, pud, pmd); | ||
322 | } | ||
323 | |||
324 | return 1; | ||
325 | } | ||
326 | #else /* !CONFIG_X86_PAE */ | ||
327 | /* No need to prepopulate any pagetable entries in non-PAE modes. */ | ||
328 | static int pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd) | ||
329 | { | ||
330 | return 1; | ||
331 | } | ||
332 | |||
333 | static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp) | ||
334 | { | ||
335 | } | ||
336 | #endif /* CONFIG_X86_PAE */ | ||
337 | |||
338 | pgd_t *pgd_alloc(struct mm_struct *mm) | ||
339 | { | ||
340 | pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_ZERO); | ||
341 | |||
342 | /* so that alloc_pd can use it */ | ||
343 | mm->pgd = pgd; | ||
344 | if (pgd) | ||
345 | pgd_ctor(pgd); | ||
346 | |||
347 | if (pgd && !pgd_prepopulate_pmd(mm, pgd)) { | ||
348 | pgd_dtor(pgd); | ||
349 | free_page((unsigned long)pgd); | ||
350 | pgd = NULL; | ||
351 | } | ||
352 | |||
353 | return pgd; | ||
354 | } | ||
355 | |||
356 | void pgd_free(struct mm_struct *mm, pgd_t *pgd) | ||
357 | { | ||
358 | pgd_mop_up_pmds(mm, pgd); | ||
359 | pgd_dtor(pgd); | ||
360 | free_page((unsigned long)pgd); | ||
361 | } | ||
362 | |||
363 | void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte) | ||
364 | { | ||
365 | pgtable_page_dtor(pte); | ||
366 | paravirt_release_pt(page_to_pfn(pte)); | ||
367 | tlb_remove_page(tlb, pte); | ||
368 | } | ||
369 | |||
370 | #ifdef CONFIG_X86_PAE | ||
371 | |||
372 | void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd) | ||
373 | { | ||
374 | paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT); | ||
375 | tlb_remove_page(tlb, virt_to_page(pmd)); | ||
376 | } | ||
377 | |||
378 | #endif | ||
379 | |||
380 | int pmd_bad(pmd_t pmd) | 176 | int pmd_bad(pmd_t pmd) |
381 | { | 177 | { |
382 | WARN_ON_ONCE(pmd_bad_v1(pmd) != pmd_bad_v2(pmd)); | 178 | WARN_ON_ONCE(pmd_bad_v1(pmd) != pmd_bad_v2(pmd)); |
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig index 4d5f2649bee4..2e641be2737e 100644 --- a/arch/x86/xen/Kconfig +++ b/arch/x86/xen/Kconfig | |||
@@ -6,7 +6,7 @@ config XEN | |||
6 | bool "Xen guest support" | 6 | bool "Xen guest support" |
7 | select PARAVIRT | 7 | select PARAVIRT |
8 | depends on X86_32 | 8 | depends on X86_32 |
9 | depends on X86_CMPXCHG && X86_TSC && !NEED_MULTIPLE_NODES && !(X86_VISWS || X86_VOYAGER) | 9 | depends on X86_CMPXCHG && X86_TSC && !(X86_VISWS || X86_VOYAGER) |
10 | help | 10 | help |
11 | This is the Linux Xen port. Enabling this will allow the | 11 | This is the Linux Xen port. Enabling this will allow the |
12 | kernel to boot in a paravirtualized environment under the | 12 | kernel to boot in a paravirtualized environment under the |
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile index 343df246bd3e..3d8df981d5fd 100644 --- a/arch/x86/xen/Makefile +++ b/arch/x86/xen/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | obj-y := enlighten.o setup.o features.o multicalls.o mmu.o \ | 1 | obj-y := enlighten.o setup.o multicalls.o mmu.o \ |
2 | events.o time.o manage.o xen-asm.o | 2 | time.o manage.o xen-asm.o grant-table.o |
3 | 3 | ||
4 | obj-$(CONFIG_SMP) += smp.o | 4 | obj-$(CONFIG_SMP) += smp.o |
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index c0388220cf97..c8a56e457d61 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -155,7 +155,8 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx, | |||
155 | if (*ax == 1) | 155 | if (*ax == 1) |
156 | maskedx = ~((1 << X86_FEATURE_APIC) | /* disable APIC */ | 156 | maskedx = ~((1 << X86_FEATURE_APIC) | /* disable APIC */ |
157 | (1 << X86_FEATURE_ACPI) | /* disable ACPI */ | 157 | (1 << X86_FEATURE_ACPI) | /* disable ACPI */ |
158 | (1 << X86_FEATURE_SEP) | /* disable SEP */ | 158 | (1 << X86_FEATURE_MCE) | /* disable MCE */ |
159 | (1 << X86_FEATURE_MCA) | /* disable MCA */ | ||
159 | (1 << X86_FEATURE_ACC)); /* thermal monitoring */ | 160 | (1 << X86_FEATURE_ACC)); /* thermal monitoring */ |
160 | 161 | ||
161 | asm(XEN_EMULATE_PREFIX "cpuid" | 162 | asm(XEN_EMULATE_PREFIX "cpuid" |
@@ -531,26 +532,37 @@ static void xen_apic_write(unsigned long reg, u32 val) | |||
531 | static void xen_flush_tlb(void) | 532 | static void xen_flush_tlb(void) |
532 | { | 533 | { |
533 | struct mmuext_op *op; | 534 | struct mmuext_op *op; |
534 | struct multicall_space mcs = xen_mc_entry(sizeof(*op)); | 535 | struct multicall_space mcs; |
536 | |||
537 | preempt_disable(); | ||
538 | |||
539 | mcs = xen_mc_entry(sizeof(*op)); | ||
535 | 540 | ||
536 | op = mcs.args; | 541 | op = mcs.args; |
537 | op->cmd = MMUEXT_TLB_FLUSH_LOCAL; | 542 | op->cmd = MMUEXT_TLB_FLUSH_LOCAL; |
538 | MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF); | 543 | MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF); |
539 | 544 | ||
540 | xen_mc_issue(PARAVIRT_LAZY_MMU); | 545 | xen_mc_issue(PARAVIRT_LAZY_MMU); |
546 | |||
547 | preempt_enable(); | ||
541 | } | 548 | } |
542 | 549 | ||
543 | static void xen_flush_tlb_single(unsigned long addr) | 550 | static void xen_flush_tlb_single(unsigned long addr) |
544 | { | 551 | { |
545 | struct mmuext_op *op; | 552 | struct mmuext_op *op; |
546 | struct multicall_space mcs = xen_mc_entry(sizeof(*op)); | 553 | struct multicall_space mcs; |
554 | |||
555 | preempt_disable(); | ||
547 | 556 | ||
557 | mcs = xen_mc_entry(sizeof(*op)); | ||
548 | op = mcs.args; | 558 | op = mcs.args; |
549 | op->cmd = MMUEXT_INVLPG_LOCAL; | 559 | op->cmd = MMUEXT_INVLPG_LOCAL; |
550 | op->arg1.linear_addr = addr & PAGE_MASK; | 560 | op->arg1.linear_addr = addr & PAGE_MASK; |
551 | MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF); | 561 | MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF); |
552 | 562 | ||
553 | xen_mc_issue(PARAVIRT_LAZY_MMU); | 563 | xen_mc_issue(PARAVIRT_LAZY_MMU); |
564 | |||
565 | preempt_enable(); | ||
554 | } | 566 | } |
555 | 567 | ||
556 | static void xen_flush_tlb_others(const cpumask_t *cpus, struct mm_struct *mm, | 568 | static void xen_flush_tlb_others(const cpumask_t *cpus, struct mm_struct *mm, |
@@ -655,15 +667,17 @@ static void xen_write_cr3(unsigned long cr3) | |||
655 | 667 | ||
656 | /* Early in boot, while setting up the initial pagetable, assume | 668 | /* Early in boot, while setting up the initial pagetable, assume |
657 | everything is pinned. */ | 669 | everything is pinned. */ |
658 | static __init void xen_alloc_pt_init(struct mm_struct *mm, u32 pfn) | 670 | static __init void xen_alloc_pte_init(struct mm_struct *mm, u32 pfn) |
659 | { | 671 | { |
672 | #ifdef CONFIG_FLATMEM | ||
660 | BUG_ON(mem_map); /* should only be used early */ | 673 | BUG_ON(mem_map); /* should only be used early */ |
674 | #endif | ||
661 | make_lowmem_page_readonly(__va(PFN_PHYS(pfn))); | 675 | make_lowmem_page_readonly(__va(PFN_PHYS(pfn))); |
662 | } | 676 | } |
663 | 677 | ||
664 | /* Early release_pt assumes that all pts are pinned, since there's | 678 | /* Early release_pte assumes that all pts are pinned, since there's |
665 | only init_mm and anything attached to that is pinned. */ | 679 | only init_mm and anything attached to that is pinned. */ |
666 | static void xen_release_pt_init(u32 pfn) | 680 | static void xen_release_pte_init(u32 pfn) |
667 | { | 681 | { |
668 | make_lowmem_page_readwrite(__va(PFN_PHYS(pfn))); | 682 | make_lowmem_page_readwrite(__va(PFN_PHYS(pfn))); |
669 | } | 683 | } |
@@ -697,12 +711,12 @@ static void xen_alloc_ptpage(struct mm_struct *mm, u32 pfn, unsigned level) | |||
697 | } | 711 | } |
698 | } | 712 | } |
699 | 713 | ||
700 | static void xen_alloc_pt(struct mm_struct *mm, u32 pfn) | 714 | static void xen_alloc_pte(struct mm_struct *mm, u32 pfn) |
701 | { | 715 | { |
702 | xen_alloc_ptpage(mm, pfn, PT_PTE); | 716 | xen_alloc_ptpage(mm, pfn, PT_PTE); |
703 | } | 717 | } |
704 | 718 | ||
705 | static void xen_alloc_pd(struct mm_struct *mm, u32 pfn) | 719 | static void xen_alloc_pmd(struct mm_struct *mm, u32 pfn) |
706 | { | 720 | { |
707 | xen_alloc_ptpage(mm, pfn, PT_PMD); | 721 | xen_alloc_ptpage(mm, pfn, PT_PMD); |
708 | } | 722 | } |
@@ -722,12 +736,12 @@ static void xen_release_ptpage(u32 pfn, unsigned level) | |||
722 | } | 736 | } |
723 | } | 737 | } |
724 | 738 | ||
725 | static void xen_release_pt(u32 pfn) | 739 | static void xen_release_pte(u32 pfn) |
726 | { | 740 | { |
727 | xen_release_ptpage(pfn, PT_PTE); | 741 | xen_release_ptpage(pfn, PT_PTE); |
728 | } | 742 | } |
729 | 743 | ||
730 | static void xen_release_pd(u32 pfn) | 744 | static void xen_release_pmd(u32 pfn) |
731 | { | 745 | { |
732 | xen_release_ptpage(pfn, PT_PMD); | 746 | xen_release_ptpage(pfn, PT_PMD); |
733 | } | 747 | } |
@@ -849,10 +863,10 @@ static __init void xen_pagetable_setup_done(pgd_t *base) | |||
849 | { | 863 | { |
850 | /* This will work as long as patching hasn't happened yet | 864 | /* This will work as long as patching hasn't happened yet |
851 | (which it hasn't) */ | 865 | (which it hasn't) */ |
852 | pv_mmu_ops.alloc_pt = xen_alloc_pt; | 866 | pv_mmu_ops.alloc_pte = xen_alloc_pte; |
853 | pv_mmu_ops.alloc_pd = xen_alloc_pd; | 867 | pv_mmu_ops.alloc_pmd = xen_alloc_pmd; |
854 | pv_mmu_ops.release_pt = xen_release_pt; | 868 | pv_mmu_ops.release_pte = xen_release_pte; |
855 | pv_mmu_ops.release_pd = xen_release_pd; | 869 | pv_mmu_ops.release_pmd = xen_release_pmd; |
856 | pv_mmu_ops.set_pte = xen_set_pte; | 870 | pv_mmu_ops.set_pte = xen_set_pte; |
857 | 871 | ||
858 | setup_shared_info(); | 872 | setup_shared_info(); |
@@ -994,7 +1008,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = { | |||
994 | .read_pmc = native_read_pmc, | 1008 | .read_pmc = native_read_pmc, |
995 | 1009 | ||
996 | .iret = xen_iret, | 1010 | .iret = xen_iret, |
997 | .irq_enable_syscall_ret = NULL, /* never called */ | 1011 | .irq_enable_syscall_ret = xen_sysexit, |
998 | 1012 | ||
999 | .load_tr_desc = paravirt_nop, | 1013 | .load_tr_desc = paravirt_nop, |
1000 | .set_ldt = xen_set_ldt, | 1014 | .set_ldt = xen_set_ldt, |
@@ -1059,11 +1073,11 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = { | |||
1059 | .pte_update = paravirt_nop, | 1073 | .pte_update = paravirt_nop, |
1060 | .pte_update_defer = paravirt_nop, | 1074 | .pte_update_defer = paravirt_nop, |
1061 | 1075 | ||
1062 | .alloc_pt = xen_alloc_pt_init, | 1076 | .alloc_pte = xen_alloc_pte_init, |
1063 | .release_pt = xen_release_pt_init, | 1077 | .release_pte = xen_release_pte_init, |
1064 | .alloc_pd = xen_alloc_pt_init, | 1078 | .alloc_pmd = xen_alloc_pte_init, |
1065 | .alloc_pd_clone = paravirt_nop, | 1079 | .alloc_pmd_clone = paravirt_nop, |
1066 | .release_pd = xen_release_pt_init, | 1080 | .release_pmd = xen_release_pte_init, |
1067 | 1081 | ||
1068 | #ifdef CONFIG_HIGHPTE | 1082 | #ifdef CONFIG_HIGHPTE |
1069 | .kmap_atomic_pte = xen_kmap_atomic_pte, | 1083 | .kmap_atomic_pte = xen_kmap_atomic_pte, |
diff --git a/arch/x86/xen/grant-table.c b/arch/x86/xen/grant-table.c new file mode 100644 index 000000000000..49ba9b5224d1 --- /dev/null +++ b/arch/x86/xen/grant-table.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /****************************************************************************** | ||
2 | * grant_table.c | ||
3 | * x86 specific part | ||
4 | * | ||
5 | * Granting foreign access to our memory reservation. | ||
6 | * | ||
7 | * Copyright (c) 2005-2006, Christopher Clark | ||
8 | * Copyright (c) 2004-2005, K A Fraser | ||
9 | * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp> | ||
10 | * VA Linux Systems Japan. Split out x86 specific part. | ||
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 version 2 | ||
14 | * as published by the Free Software Foundation; or, when distributed | ||
15 | * separately from the Linux kernel or incorporated into other | ||
16 | * software packages, subject to the following license: | ||
17 | * | ||
18 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
19 | * of this source file (the "Software"), to deal in the Software without | ||
20 | * restriction, including without limitation the rights to use, copy, modify, | ||
21 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, | ||
22 | * and to permit persons to whom the Software is furnished to do so, subject to | ||
23 | * the following conditions: | ||
24 | * | ||
25 | * The above copyright notice and this permission notice shall be included in | ||
26 | * all copies or substantial portions of the Software. | ||
27 | * | ||
28 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
29 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
30 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
31 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
32 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
33 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
34 | * IN THE SOFTWARE. | ||
35 | */ | ||
36 | |||
37 | #include <linux/sched.h> | ||
38 | #include <linux/mm.h> | ||
39 | #include <linux/vmalloc.h> | ||
40 | |||
41 | #include <xen/interface/xen.h> | ||
42 | #include <xen/page.h> | ||
43 | #include <xen/grant_table.h> | ||
44 | |||
45 | #include <asm/pgtable.h> | ||
46 | |||
47 | static int map_pte_fn(pte_t *pte, struct page *pmd_page, | ||
48 | unsigned long addr, void *data) | ||
49 | { | ||
50 | unsigned long **frames = (unsigned long **)data; | ||
51 | |||
52 | set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL)); | ||
53 | (*frames)++; | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static int unmap_pte_fn(pte_t *pte, struct page *pmd_page, | ||
58 | unsigned long addr, void *data) | ||
59 | { | ||
60 | |||
61 | set_pte_at(&init_mm, addr, pte, __pte(0)); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes, | ||
66 | unsigned long max_nr_gframes, | ||
67 | struct grant_entry **__shared) | ||
68 | { | ||
69 | int rc; | ||
70 | struct grant_entry *shared = *__shared; | ||
71 | |||
72 | if (shared == NULL) { | ||
73 | struct vm_struct *area = | ||
74 | xen_alloc_vm_area(PAGE_SIZE * max_nr_gframes); | ||
75 | BUG_ON(area == NULL); | ||
76 | shared = area->addr; | ||
77 | *__shared = shared; | ||
78 | } | ||
79 | |||
80 | rc = apply_to_page_range(&init_mm, (unsigned long)shared, | ||
81 | PAGE_SIZE * nr_gframes, | ||
82 | map_pte_fn, &frames); | ||
83 | return rc; | ||
84 | } | ||
85 | |||
86 | void arch_gnttab_unmap_shared(struct grant_entry *shared, | ||
87 | unsigned long nr_gframes) | ||
88 | { | ||
89 | apply_to_page_range(&init_mm, (unsigned long)shared, | ||
90 | PAGE_SIZE * nr_gframes, unmap_pte_fn, NULL); | ||
91 | } | ||
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 2a054ef2a3da..6cbcf65609ad 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
@@ -156,6 +156,10 @@ void set_pte_mfn(unsigned long vaddr, unsigned long mfn, pgprot_t flags) | |||
156 | void xen_set_pte_at(struct mm_struct *mm, unsigned long addr, | 156 | void xen_set_pte_at(struct mm_struct *mm, unsigned long addr, |
157 | pte_t *ptep, pte_t pteval) | 157 | pte_t *ptep, pte_t pteval) |
158 | { | 158 | { |
159 | /* updates to init_mm may be done without lock */ | ||
160 | if (mm == &init_mm) | ||
161 | preempt_disable(); | ||
162 | |||
159 | if (mm == current->mm || mm == &init_mm) { | 163 | if (mm == current->mm || mm == &init_mm) { |
160 | if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) { | 164 | if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) { |
161 | struct multicall_space mcs; | 165 | struct multicall_space mcs; |
@@ -163,14 +167,61 @@ void xen_set_pte_at(struct mm_struct *mm, unsigned long addr, | |||
163 | 167 | ||
164 | MULTI_update_va_mapping(mcs.mc, addr, pteval, 0); | 168 | MULTI_update_va_mapping(mcs.mc, addr, pteval, 0); |
165 | xen_mc_issue(PARAVIRT_LAZY_MMU); | 169 | xen_mc_issue(PARAVIRT_LAZY_MMU); |
166 | return; | 170 | goto out; |
167 | } else | 171 | } else |
168 | if (HYPERVISOR_update_va_mapping(addr, pteval, 0) == 0) | 172 | if (HYPERVISOR_update_va_mapping(addr, pteval, 0) == 0) |
169 | return; | 173 | goto out; |
170 | } | 174 | } |
171 | xen_set_pte(ptep, pteval); | 175 | xen_set_pte(ptep, pteval); |
176 | |||
177 | out: | ||
178 | if (mm == &init_mm) | ||
179 | preempt_enable(); | ||
180 | } | ||
181 | |||
182 | pteval_t xen_pte_val(pte_t pte) | ||
183 | { | ||
184 | pteval_t ret = pte.pte; | ||
185 | |||
186 | if (ret & _PAGE_PRESENT) | ||
187 | ret = machine_to_phys(XMADDR(ret)).paddr | _PAGE_PRESENT; | ||
188 | |||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | pgdval_t xen_pgd_val(pgd_t pgd) | ||
193 | { | ||
194 | pgdval_t ret = pgd.pgd; | ||
195 | if (ret & _PAGE_PRESENT) | ||
196 | ret = machine_to_phys(XMADDR(ret)).paddr | _PAGE_PRESENT; | ||
197 | return ret; | ||
198 | } | ||
199 | |||
200 | pte_t xen_make_pte(pteval_t pte) | ||
201 | { | ||
202 | if (pte & _PAGE_PRESENT) { | ||
203 | pte = phys_to_machine(XPADDR(pte)).maddr; | ||
204 | pte &= ~(_PAGE_PCD | _PAGE_PWT); | ||
205 | } | ||
206 | |||
207 | return (pte_t){ .pte = pte }; | ||
172 | } | 208 | } |
173 | 209 | ||
210 | pgd_t xen_make_pgd(pgdval_t pgd) | ||
211 | { | ||
212 | if (pgd & _PAGE_PRESENT) | ||
213 | pgd = phys_to_machine(XPADDR(pgd)).maddr; | ||
214 | |||
215 | return (pgd_t){ pgd }; | ||
216 | } | ||
217 | |||
218 | pmdval_t xen_pmd_val(pmd_t pmd) | ||
219 | { | ||
220 | pmdval_t ret = native_pmd_val(pmd); | ||
221 | if (ret & _PAGE_PRESENT) | ||
222 | ret = machine_to_phys(XMADDR(ret)).paddr | _PAGE_PRESENT; | ||
223 | return ret; | ||
224 | } | ||
174 | #ifdef CONFIG_X86_PAE | 225 | #ifdef CONFIG_X86_PAE |
175 | void xen_set_pud(pud_t *ptr, pud_t val) | 226 | void xen_set_pud(pud_t *ptr, pud_t val) |
176 | { | 227 | { |
@@ -214,100 +265,18 @@ void xen_pmd_clear(pmd_t *pmdp) | |||
214 | xen_set_pmd(pmdp, __pmd(0)); | 265 | xen_set_pmd(pmdp, __pmd(0)); |
215 | } | 266 | } |
216 | 267 | ||
217 | unsigned long long xen_pte_val(pte_t pte) | 268 | pmd_t xen_make_pmd(pmdval_t pmd) |
218 | { | 269 | { |
219 | unsigned long long ret = 0; | 270 | if (pmd & _PAGE_PRESENT) |
220 | |||
221 | if (pte.pte_low) { | ||
222 | ret = ((unsigned long long)pte.pte_high << 32) | pte.pte_low; | ||
223 | ret = machine_to_phys(XMADDR(ret)).paddr | 1; | ||
224 | } | ||
225 | |||
226 | return ret; | ||
227 | } | ||
228 | |||
229 | unsigned long long xen_pmd_val(pmd_t pmd) | ||
230 | { | ||
231 | unsigned long long ret = pmd.pmd; | ||
232 | if (ret) | ||
233 | ret = machine_to_phys(XMADDR(ret)).paddr | 1; | ||
234 | return ret; | ||
235 | } | ||
236 | |||
237 | unsigned long long xen_pgd_val(pgd_t pgd) | ||
238 | { | ||
239 | unsigned long long ret = pgd.pgd; | ||
240 | if (ret) | ||
241 | ret = machine_to_phys(XMADDR(ret)).paddr | 1; | ||
242 | return ret; | ||
243 | } | ||
244 | |||
245 | pte_t xen_make_pte(unsigned long long pte) | ||
246 | { | ||
247 | if (pte & _PAGE_PRESENT) { | ||
248 | pte = phys_to_machine(XPADDR(pte)).maddr; | ||
249 | pte &= ~(_PAGE_PCD | _PAGE_PWT); | ||
250 | } | ||
251 | |||
252 | return (pte_t){ .pte = pte }; | ||
253 | } | ||
254 | |||
255 | pmd_t xen_make_pmd(unsigned long long pmd) | ||
256 | { | ||
257 | if (pmd & 1) | ||
258 | pmd = phys_to_machine(XPADDR(pmd)).maddr; | 271 | pmd = phys_to_machine(XPADDR(pmd)).maddr; |
259 | 272 | ||
260 | return (pmd_t){ pmd }; | 273 | return native_make_pmd(pmd); |
261 | } | ||
262 | |||
263 | pgd_t xen_make_pgd(unsigned long long pgd) | ||
264 | { | ||
265 | if (pgd & _PAGE_PRESENT) | ||
266 | pgd = phys_to_machine(XPADDR(pgd)).maddr; | ||
267 | |||
268 | return (pgd_t){ pgd }; | ||
269 | } | 274 | } |
270 | #else /* !PAE */ | 275 | #else /* !PAE */ |
271 | void xen_set_pte(pte_t *ptep, pte_t pte) | 276 | void xen_set_pte(pte_t *ptep, pte_t pte) |
272 | { | 277 | { |
273 | *ptep = pte; | 278 | *ptep = pte; |
274 | } | 279 | } |
275 | |||
276 | unsigned long xen_pte_val(pte_t pte) | ||
277 | { | ||
278 | unsigned long ret = pte.pte_low; | ||
279 | |||
280 | if (ret & _PAGE_PRESENT) | ||
281 | ret = machine_to_phys(XMADDR(ret)).paddr; | ||
282 | |||
283 | return ret; | ||
284 | } | ||
285 | |||
286 | unsigned long xen_pgd_val(pgd_t pgd) | ||
287 | { | ||
288 | unsigned long ret = pgd.pgd; | ||
289 | if (ret) | ||
290 | ret = machine_to_phys(XMADDR(ret)).paddr | 1; | ||
291 | return ret; | ||
292 | } | ||
293 | |||
294 | pte_t xen_make_pte(unsigned long pte) | ||
295 | { | ||
296 | if (pte & _PAGE_PRESENT) { | ||
297 | pte = phys_to_machine(XPADDR(pte)).maddr; | ||
298 | pte &= ~(_PAGE_PCD | _PAGE_PWT); | ||
299 | } | ||
300 | |||
301 | return (pte_t){ pte }; | ||
302 | } | ||
303 | |||
304 | pgd_t xen_make_pgd(unsigned long pgd) | ||
305 | { | ||
306 | if (pgd & _PAGE_PRESENT) | ||
307 | pgd = phys_to_machine(XPADDR(pgd)).maddr; | ||
308 | |||
309 | return (pgd_t){ pgd }; | ||
310 | } | ||
311 | #endif /* CONFIG_X86_PAE */ | 280 | #endif /* CONFIG_X86_PAE */ |
312 | 281 | ||
313 | /* | 282 | /* |
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 2341492bf7a0..82517e4a752a 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <asm/xen/hypervisor.h> | 16 | #include <asm/xen/hypervisor.h> |
17 | #include <asm/xen/hypercall.h> | 17 | #include <asm/xen/hypercall.h> |
18 | 18 | ||
19 | #include <xen/interface/callback.h> | ||
19 | #include <xen/interface/physdev.h> | 20 | #include <xen/interface/physdev.h> |
20 | #include <xen/features.h> | 21 | #include <xen/features.h> |
21 | 22 | ||
@@ -68,6 +69,24 @@ static void __init fiddle_vdso(void) | |||
68 | *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT; | 69 | *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT; |
69 | } | 70 | } |
70 | 71 | ||
72 | void xen_enable_sysenter(void) | ||
73 | { | ||
74 | int cpu = smp_processor_id(); | ||
75 | extern void xen_sysenter_target(void); | ||
76 | /* Mask events on entry, even though they get enabled immediately */ | ||
77 | static struct callback_register sysenter = { | ||
78 | .type = CALLBACKTYPE_sysenter, | ||
79 | .address = { __KERNEL_CS, (unsigned long)xen_sysenter_target }, | ||
80 | .flags = CALLBACKF_mask_events, | ||
81 | }; | ||
82 | |||
83 | if (!boot_cpu_has(X86_FEATURE_SEP) || | ||
84 | HYPERVISOR_callback_op(CALLBACKOP_register, &sysenter) != 0) { | ||
85 | clear_cpu_cap(&cpu_data(cpu), X86_FEATURE_SEP); | ||
86 | clear_cpu_cap(&boot_cpu_data, X86_FEATURE_SEP); | ||
87 | } | ||
88 | } | ||
89 | |||
71 | void __init xen_arch_setup(void) | 90 | void __init xen_arch_setup(void) |
72 | { | 91 | { |
73 | struct physdev_set_iopl set_iopl; | 92 | struct physdev_set_iopl set_iopl; |
@@ -82,6 +101,8 @@ void __init xen_arch_setup(void) | |||
82 | HYPERVISOR_set_callbacks(__KERNEL_CS, (unsigned long)xen_hypervisor_callback, | 101 | HYPERVISOR_set_callbacks(__KERNEL_CS, (unsigned long)xen_hypervisor_callback, |
83 | __KERNEL_CS, (unsigned long)xen_failsafe_callback); | 102 | __KERNEL_CS, (unsigned long)xen_failsafe_callback); |
84 | 103 | ||
104 | xen_enable_sysenter(); | ||
105 | |||
85 | set_iopl.iopl = 1; | 106 | set_iopl.iopl = 1; |
86 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl); | 107 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl); |
87 | if (rc != 0) | 108 | if (rc != 0) |
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index e340ff92f6b6..92dd3dbf3ffb 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c | |||
@@ -36,8 +36,9 @@ | |||
36 | #include "mmu.h" | 36 | #include "mmu.h" |
37 | 37 | ||
38 | static cpumask_t xen_cpu_initialized_map; | 38 | static cpumask_t xen_cpu_initialized_map; |
39 | static DEFINE_PER_CPU(int, resched_irq); | 39 | static DEFINE_PER_CPU(int, resched_irq) = -1; |
40 | static DEFINE_PER_CPU(int, callfunc_irq); | 40 | static DEFINE_PER_CPU(int, callfunc_irq) = -1; |
41 | static DEFINE_PER_CPU(int, debug_irq) = -1; | ||
41 | 42 | ||
42 | /* | 43 | /* |
43 | * Structure and data for smp_call_function(). This is designed to minimise | 44 | * Structure and data for smp_call_function(). This is designed to minimise |
@@ -72,6 +73,7 @@ static __cpuinit void cpu_bringup_and_idle(void) | |||
72 | int cpu = smp_processor_id(); | 73 | int cpu = smp_processor_id(); |
73 | 74 | ||
74 | cpu_init(); | 75 | cpu_init(); |
76 | xen_enable_sysenter(); | ||
75 | 77 | ||
76 | preempt_disable(); | 78 | preempt_disable(); |
77 | per_cpu(cpu_state, cpu) = CPU_ONLINE; | 79 | per_cpu(cpu_state, cpu) = CPU_ONLINE; |
@@ -88,9 +90,7 @@ static __cpuinit void cpu_bringup_and_idle(void) | |||
88 | static int xen_smp_intr_init(unsigned int cpu) | 90 | static int xen_smp_intr_init(unsigned int cpu) |
89 | { | 91 | { |
90 | int rc; | 92 | int rc; |
91 | const char *resched_name, *callfunc_name; | 93 | const char *resched_name, *callfunc_name, *debug_name; |
92 | |||
93 | per_cpu(resched_irq, cpu) = per_cpu(callfunc_irq, cpu) = -1; | ||
94 | 94 | ||
95 | resched_name = kasprintf(GFP_KERNEL, "resched%d", cpu); | 95 | resched_name = kasprintf(GFP_KERNEL, "resched%d", cpu); |
96 | rc = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR, | 96 | rc = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR, |
@@ -114,6 +114,14 @@ static int xen_smp_intr_init(unsigned int cpu) | |||
114 | goto fail; | 114 | goto fail; |
115 | per_cpu(callfunc_irq, cpu) = rc; | 115 | per_cpu(callfunc_irq, cpu) = rc; |
116 | 116 | ||
117 | debug_name = kasprintf(GFP_KERNEL, "debug%d", cpu); | ||
118 | rc = bind_virq_to_irqhandler(VIRQ_DEBUG, cpu, xen_debug_interrupt, | ||
119 | IRQF_DISABLED | IRQF_PERCPU | IRQF_NOBALANCING, | ||
120 | debug_name, NULL); | ||
121 | if (rc < 0) | ||
122 | goto fail; | ||
123 | per_cpu(debug_irq, cpu) = rc; | ||
124 | |||
117 | return 0; | 125 | return 0; |
118 | 126 | ||
119 | fail: | 127 | fail: |
@@ -121,6 +129,8 @@ static int xen_smp_intr_init(unsigned int cpu) | |||
121 | unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL); | 129 | unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL); |
122 | if (per_cpu(callfunc_irq, cpu) >= 0) | 130 | if (per_cpu(callfunc_irq, cpu) >= 0) |
123 | unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL); | 131 | unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL); |
132 | if (per_cpu(debug_irq, cpu) >= 0) | ||
133 | unbind_from_irqhandler(per_cpu(debug_irq, cpu), NULL); | ||
124 | return rc; | 134 | return rc; |
125 | } | 135 | } |
126 | 136 | ||
diff --git a/arch/x86/xen/xen-asm.S b/arch/x86/xen/xen-asm.S index fe161ed4b01e..2497a30f41de 100644 --- a/arch/x86/xen/xen-asm.S +++ b/arch/x86/xen/xen-asm.S | |||
@@ -108,6 +108,20 @@ ENDPATCH(xen_restore_fl_direct) | |||
108 | RELOC(xen_restore_fl_direct, 2b+1) | 108 | RELOC(xen_restore_fl_direct, 2b+1) |
109 | 109 | ||
110 | /* | 110 | /* |
111 | We can't use sysexit directly, because we're not running in ring0. | ||
112 | But we can easily fake it up using iret. Assuming xen_sysexit | ||
113 | is jumped to with a standard stack frame, we can just strip it | ||
114 | back to a standard iret frame and use iret. | ||
115 | */ | ||
116 | ENTRY(xen_sysexit) | ||
117 | movl PT_EAX(%esp), %eax /* Shouldn't be necessary? */ | ||
118 | orl $X86_EFLAGS_IF, PT_EFLAGS(%esp) | ||
119 | lea PT_EIP(%esp), %esp | ||
120 | |||
121 | jmp xen_iret | ||
122 | ENDPROC(xen_sysexit) | ||
123 | |||
124 | /* | ||
111 | This is run where a normal iret would be run, with the same stack setup: | 125 | This is run where a normal iret would be run, with the same stack setup: |
112 | 8: eflags | 126 | 8: eflags |
113 | 4: cs | 127 | 4: cs |
@@ -184,8 +198,12 @@ iret_restore_end: | |||
184 | region is OK. */ | 198 | region is OK. */ |
185 | je xen_hypervisor_callback | 199 | je xen_hypervisor_callback |
186 | 200 | ||
187 | iret | 201 | 1: iret |
188 | xen_iret_end_crit: | 202 | xen_iret_end_crit: |
203 | .section __ex_table,"a" | ||
204 | .align 4 | ||
205 | .long 1b,iret_exc | ||
206 | .previous | ||
189 | 207 | ||
190 | hyper_iret: | 208 | hyper_iret: |
191 | /* put this out of line since its very rarely used */ | 209 | /* put this out of line since its very rarely used */ |
@@ -219,9 +237,7 @@ hyper_iret: | |||
219 | ds } SAVE_ALL state | 237 | ds } SAVE_ALL state |
220 | eax } | 238 | eax } |
221 | : : | 239 | : : |
222 | ebx } | 240 | ebx }<- esp |
223 | ---------------- | ||
224 | return addr <- esp | ||
225 | ---------------- | 241 | ---------------- |
226 | 242 | ||
227 | In order to deliver the nested exception properly, we need to shift | 243 | In order to deliver the nested exception properly, we need to shift |
@@ -236,10 +252,8 @@ hyper_iret: | |||
236 | it's usermode state which we eventually need to restore. | 252 | it's usermode state which we eventually need to restore. |
237 | */ | 253 | */ |
238 | ENTRY(xen_iret_crit_fixup) | 254 | ENTRY(xen_iret_crit_fixup) |
239 | /* offsets +4 for return address */ | ||
240 | |||
241 | /* | 255 | /* |
242 | Paranoia: Make sure we're really coming from userspace. | 256 | Paranoia: Make sure we're really coming from kernel space. |
243 | One could imagine a case where userspace jumps into the | 257 | One could imagine a case where userspace jumps into the |
244 | critical range address, but just before the CPU delivers a GP, | 258 | critical range address, but just before the CPU delivers a GP, |
245 | it decides to deliver an interrupt instead. Unlikely? | 259 | it decides to deliver an interrupt instead. Unlikely? |
@@ -248,32 +262,32 @@ ENTRY(xen_iret_crit_fixup) | |||
248 | jump instruction itself, not the destination, but some virtual | 262 | jump instruction itself, not the destination, but some virtual |
249 | environments get this wrong. | 263 | environments get this wrong. |
250 | */ | 264 | */ |
251 | movl PT_CS+4(%esp), %ecx | 265 | movl PT_CS(%esp), %ecx |
252 | andl $SEGMENT_RPL_MASK, %ecx | 266 | andl $SEGMENT_RPL_MASK, %ecx |
253 | cmpl $USER_RPL, %ecx | 267 | cmpl $USER_RPL, %ecx |
254 | je 2f | 268 | je 2f |
255 | 269 | ||
256 | lea PT_ORIG_EAX+4(%esp), %esi | 270 | lea PT_ORIG_EAX(%esp), %esi |
257 | lea PT_EFLAGS+4(%esp), %edi | 271 | lea PT_EFLAGS(%esp), %edi |
258 | 272 | ||
259 | /* If eip is before iret_restore_end then stack | 273 | /* If eip is before iret_restore_end then stack |
260 | hasn't been restored yet. */ | 274 | hasn't been restored yet. */ |
261 | cmp $iret_restore_end, %eax | 275 | cmp $iret_restore_end, %eax |
262 | jae 1f | 276 | jae 1f |
263 | 277 | ||
264 | movl 0+4(%edi),%eax /* copy EAX */ | 278 | movl 0+4(%edi),%eax /* copy EAX (just above top of frame) */ |
265 | movl %eax, PT_EAX+4(%esp) | 279 | movl %eax, PT_EAX(%esp) |
266 | 280 | ||
267 | lea ESP_OFFSET(%edi),%edi /* move dest up over saved regs */ | 281 | lea ESP_OFFSET(%edi),%edi /* move dest up over saved regs */ |
268 | 282 | ||
269 | /* set up the copy */ | 283 | /* set up the copy */ |
270 | 1: std | 284 | 1: std |
271 | mov $(PT_EIP+4) / 4, %ecx /* copy ret+saved regs up to orig_eax */ | 285 | mov $PT_EIP / 4, %ecx /* saved regs up to orig_eax */ |
272 | rep movsl | 286 | rep movsl |
273 | cld | 287 | cld |
274 | 288 | ||
275 | lea 4(%edi),%esp /* point esp to new frame */ | 289 | lea 4(%edi),%esp /* point esp to new frame */ |
276 | 2: ret | 290 | 2: jmp xen_do_upcall |
277 | 291 | ||
278 | 292 | ||
279 | /* | 293 | /* |
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index 956a491ea998..f1063ae08037 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h | |||
@@ -2,6 +2,8 @@ | |||
2 | #define XEN_OPS_H | 2 | #define XEN_OPS_H |
3 | 3 | ||
4 | #include <linux/init.h> | 4 | #include <linux/init.h> |
5 | #include <linux/irqreturn.h> | ||
6 | #include <xen/xen-ops.h> | ||
5 | 7 | ||
6 | /* These are code, but not functions. Defined in entry.S */ | 8 | /* These are code, but not functions. Defined in entry.S */ |
7 | extern const char xen_hypervisor_callback[]; | 9 | extern const char xen_hypervisor_callback[]; |
@@ -9,7 +11,6 @@ extern const char xen_failsafe_callback[]; | |||
9 | 11 | ||
10 | void xen_copy_trap_info(struct trap_info *traps); | 12 | void xen_copy_trap_info(struct trap_info *traps); |
11 | 13 | ||
12 | DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu); | ||
13 | DECLARE_PER_CPU(unsigned long, xen_cr3); | 14 | DECLARE_PER_CPU(unsigned long, xen_cr3); |
14 | DECLARE_PER_CPU(unsigned long, xen_current_cr3); | 15 | DECLARE_PER_CPU(unsigned long, xen_current_cr3); |
15 | 16 | ||
@@ -19,6 +20,7 @@ extern struct shared_info *HYPERVISOR_shared_info; | |||
19 | char * __init xen_memory_setup(void); | 20 | char * __init xen_memory_setup(void); |
20 | void __init xen_arch_setup(void); | 21 | void __init xen_arch_setup(void); |
21 | void __init xen_init_IRQ(void); | 22 | void __init xen_init_IRQ(void); |
23 | void xen_enable_sysenter(void); | ||
22 | 24 | ||
23 | void xen_setup_timer(int cpu); | 25 | void xen_setup_timer(int cpu); |
24 | void xen_setup_cpu_clockevents(void); | 26 | void xen_setup_cpu_clockevents(void); |
@@ -28,6 +30,8 @@ unsigned long xen_get_wallclock(void); | |||
28 | int xen_set_wallclock(unsigned long time); | 30 | int xen_set_wallclock(unsigned long time); |
29 | unsigned long long xen_sched_clock(void); | 31 | unsigned long long xen_sched_clock(void); |
30 | 32 | ||
33 | irqreturn_t xen_debug_interrupt(int irq, void *dev_id); | ||
34 | |||
31 | bool xen_vcpu_stolen(int vcpu); | 35 | bool xen_vcpu_stolen(int vcpu); |
32 | 36 | ||
33 | void xen_mark_init_mm_pinned(void); | 37 | void xen_mark_init_mm_pinned(void); |
@@ -64,4 +68,6 @@ DECL_ASM(unsigned long, xen_save_fl_direct, void); | |||
64 | DECL_ASM(void, xen_restore_fl_direct, unsigned long); | 68 | DECL_ASM(void, xen_restore_fl_direct, unsigned long); |
65 | 69 | ||
66 | void xen_iret(void); | 70 | void xen_iret(void); |
71 | void xen_sysexit(void); | ||
72 | |||
67 | #endif /* XEN_OPS_H */ | 73 | #endif /* XEN_OPS_H */ |
diff --git a/drivers/Kconfig b/drivers/Kconfig index 3a0e3549739f..80f0ec91e2cf 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig | |||
@@ -97,4 +97,6 @@ source "drivers/dca/Kconfig" | |||
97 | source "drivers/auxdisplay/Kconfig" | 97 | source "drivers/auxdisplay/Kconfig" |
98 | 98 | ||
99 | source "drivers/uio/Kconfig" | 99 | source "drivers/uio/Kconfig" |
100 | |||
101 | source "drivers/xen/Kconfig" | ||
100 | endmenu | 102 | endmenu |
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 9c6f3f99208d..d771da816d95 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c | |||
@@ -47,6 +47,7 @@ | |||
47 | 47 | ||
48 | #include <xen/interface/grant_table.h> | 48 | #include <xen/interface/grant_table.h> |
49 | #include <xen/interface/io/blkif.h> | 49 | #include <xen/interface/io/blkif.h> |
50 | #include <xen/interface/io/protocols.h> | ||
50 | 51 | ||
51 | #include <asm/xen/hypervisor.h> | 52 | #include <asm/xen/hypervisor.h> |
52 | 53 | ||
@@ -74,7 +75,6 @@ static struct block_device_operations xlvbd_block_fops; | |||
74 | struct blkfront_info | 75 | struct blkfront_info |
75 | { | 76 | { |
76 | struct xenbus_device *xbdev; | 77 | struct xenbus_device *xbdev; |
77 | dev_t dev; | ||
78 | struct gendisk *gd; | 78 | struct gendisk *gd; |
79 | int vdevice; | 79 | int vdevice; |
80 | blkif_vdev_t handle; | 80 | blkif_vdev_t handle; |
@@ -88,6 +88,7 @@ struct blkfront_info | |||
88 | struct blk_shadow shadow[BLK_RING_SIZE]; | 88 | struct blk_shadow shadow[BLK_RING_SIZE]; |
89 | unsigned long shadow_free; | 89 | unsigned long shadow_free; |
90 | int feature_barrier; | 90 | int feature_barrier; |
91 | int is_ready; | ||
91 | 92 | ||
92 | /** | 93 | /** |
93 | * The number of people holding this device open. We won't allow a | 94 | * The number of people holding this device open. We won't allow a |
@@ -614,6 +615,12 @@ again: | |||
614 | message = "writing event-channel"; | 615 | message = "writing event-channel"; |
615 | goto abort_transaction; | 616 | goto abort_transaction; |
616 | } | 617 | } |
618 | err = xenbus_printf(xbt, dev->nodename, "protocol", "%s", | ||
619 | XEN_IO_PROTO_ABI_NATIVE); | ||
620 | if (err) { | ||
621 | message = "writing protocol"; | ||
622 | goto abort_transaction; | ||
623 | } | ||
617 | 624 | ||
618 | err = xenbus_transaction_end(xbt, 0); | 625 | err = xenbus_transaction_end(xbt, 0); |
619 | if (err) { | 626 | if (err) { |
@@ -833,6 +840,8 @@ static void blkfront_connect(struct blkfront_info *info) | |||
833 | spin_unlock_irq(&blkif_io_lock); | 840 | spin_unlock_irq(&blkif_io_lock); |
834 | 841 | ||
835 | add_disk(info->gd); | 842 | add_disk(info->gd); |
843 | |||
844 | info->is_ready = 1; | ||
836 | } | 845 | } |
837 | 846 | ||
838 | /** | 847 | /** |
@@ -896,7 +905,7 @@ static void backend_changed(struct xenbus_device *dev, | |||
896 | break; | 905 | break; |
897 | 906 | ||
898 | case XenbusStateClosing: | 907 | case XenbusStateClosing: |
899 | bd = bdget(info->dev); | 908 | bd = bdget_disk(info->gd, 0); |
900 | if (bd == NULL) | 909 | if (bd == NULL) |
901 | xenbus_dev_fatal(dev, -ENODEV, "bdget failed"); | 910 | xenbus_dev_fatal(dev, -ENODEV, "bdget failed"); |
902 | 911 | ||
@@ -925,6 +934,13 @@ static int blkfront_remove(struct xenbus_device *dev) | |||
925 | return 0; | 934 | return 0; |
926 | } | 935 | } |
927 | 936 | ||
937 | static int blkfront_is_ready(struct xenbus_device *dev) | ||
938 | { | ||
939 | struct blkfront_info *info = dev->dev.driver_data; | ||
940 | |||
941 | return info->is_ready; | ||
942 | } | ||
943 | |||
928 | static int blkif_open(struct inode *inode, struct file *filep) | 944 | static int blkif_open(struct inode *inode, struct file *filep) |
929 | { | 945 | { |
930 | struct blkfront_info *info = inode->i_bdev->bd_disk->private_data; | 946 | struct blkfront_info *info = inode->i_bdev->bd_disk->private_data; |
@@ -971,6 +987,7 @@ static struct xenbus_driver blkfront = { | |||
971 | .remove = blkfront_remove, | 987 | .remove = blkfront_remove, |
972 | .resume = blkfront_resume, | 988 | .resume = blkfront_resume, |
973 | .otherend_changed = backend_changed, | 989 | .otherend_changed = backend_changed, |
990 | .is_ready = blkfront_is_ready, | ||
974 | }; | 991 | }; |
975 | 992 | ||
976 | static int __init xlblk_init(void) | 993 | static int __init xlblk_init(void) |
@@ -998,3 +1015,5 @@ module_exit(xlblk_exit); | |||
998 | MODULE_DESCRIPTION("Xen virtual block device frontend"); | 1015 | MODULE_DESCRIPTION("Xen virtual block device frontend"); |
999 | MODULE_LICENSE("GPL"); | 1016 | MODULE_LICENSE("GPL"); |
1000 | MODULE_ALIAS_BLOCKDEV_MAJOR(XENVBD_MAJOR); | 1017 | MODULE_ALIAS_BLOCKDEV_MAJOR(XENVBD_MAJOR); |
1018 | MODULE_ALIAS("xen:vbd"); | ||
1019 | MODULE_ALIAS("xenblk"); | ||
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c index 6228fadacd38..9d19aec5820a 100644 --- a/drivers/ieee1394/dv1394.c +++ b/drivers/ieee1394/dv1394.c | |||
@@ -2167,6 +2167,7 @@ static const struct file_operations dv1394_fops= | |||
2167 | /* | 2167 | /* |
2168 | * Export information about protocols/devices supported by this driver. | 2168 | * Export information about protocols/devices supported by this driver. |
2169 | */ | 2169 | */ |
2170 | #ifdef MODULE | ||
2170 | static struct ieee1394_device_id dv1394_id_table[] = { | 2171 | static struct ieee1394_device_id dv1394_id_table[] = { |
2171 | { | 2172 | { |
2172 | .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, | 2173 | .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, |
@@ -2177,6 +2178,7 @@ static struct ieee1394_device_id dv1394_id_table[] = { | |||
2177 | }; | 2178 | }; |
2178 | 2179 | ||
2179 | MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table); | 2180 | MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table); |
2181 | #endif /* MODULE */ | ||
2180 | 2182 | ||
2181 | static struct hpsb_protocol_driver dv1394_driver = { | 2183 | static struct hpsb_protocol_driver dv1394_driver = { |
2182 | .name = "dv1394", | 2184 | .name = "dv1394", |
diff --git a/drivers/ieee1394/iso.h b/drivers/ieee1394/iso.h index b94e55e6eaa5..b5de5f21ef78 100644 --- a/drivers/ieee1394/iso.h +++ b/drivers/ieee1394/iso.h | |||
@@ -123,6 +123,8 @@ struct hpsb_iso { | |||
123 | 123 | ||
124 | /* how many times the buffer has overflowed or underflowed */ | 124 | /* how many times the buffer has overflowed or underflowed */ |
125 | atomic_t overflows; | 125 | atomic_t overflows; |
126 | /* how many cycles were skipped for a given context */ | ||
127 | atomic_t skips; | ||
126 | 128 | ||
127 | /* Current number of bytes lost in discarded packets */ | 129 | /* Current number of bytes lost in discarded packets */ |
128 | int bytes_discarded; | 130 | int bytes_discarded; |
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 0690469fcecf..e509e13cb7a7 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c | |||
@@ -1723,6 +1723,8 @@ struct ohci_iso_xmit { | |||
1723 | struct dma_prog_region prog; | 1723 | struct dma_prog_region prog; |
1724 | struct ohci1394_iso_tasklet task; | 1724 | struct ohci1394_iso_tasklet task; |
1725 | int task_active; | 1725 | int task_active; |
1726 | int last_cycle; | ||
1727 | atomic_t skips; | ||
1726 | 1728 | ||
1727 | u32 ContextControlSet; | 1729 | u32 ContextControlSet; |
1728 | u32 ContextControlClear; | 1730 | u32 ContextControlClear; |
@@ -1759,6 +1761,8 @@ static int ohci_iso_xmit_init(struct hpsb_iso *iso) | |||
1759 | iso->hostdata = xmit; | 1761 | iso->hostdata = xmit; |
1760 | xmit->ohci = iso->host->hostdata; | 1762 | xmit->ohci = iso->host->hostdata; |
1761 | xmit->task_active = 0; | 1763 | xmit->task_active = 0; |
1764 | xmit->last_cycle = -1; | ||
1765 | atomic_set(&iso->skips, 0); | ||
1762 | 1766 | ||
1763 | dma_prog_region_init(&xmit->prog); | 1767 | dma_prog_region_init(&xmit->prog); |
1764 | 1768 | ||
@@ -1856,6 +1860,26 @@ static void ohci_iso_xmit_task(unsigned long data) | |||
1856 | /* parse cycle */ | 1860 | /* parse cycle */ |
1857 | cycle = le32_to_cpu(cmd->output_last.status) & 0x1FFF; | 1861 | cycle = le32_to_cpu(cmd->output_last.status) & 0x1FFF; |
1858 | 1862 | ||
1863 | if (xmit->last_cycle > -1) { | ||
1864 | int cycle_diff = cycle - xmit->last_cycle; | ||
1865 | int skip; | ||
1866 | |||
1867 | /* unwrap */ | ||
1868 | if (cycle_diff < 0) { | ||
1869 | cycle_diff += 8000; | ||
1870 | if (cycle_diff < 0) | ||
1871 | PRINT(KERN_ERR, "bogus cycle diff %d\n", | ||
1872 | cycle_diff); | ||
1873 | } | ||
1874 | |||
1875 | skip = cycle_diff - 1; | ||
1876 | if (skip > 0) { | ||
1877 | DBGMSG("skipped %d cycles without packet loss", skip); | ||
1878 | atomic_add(skip, &iso->skips); | ||
1879 | } | ||
1880 | } | ||
1881 | xmit->last_cycle = cycle; | ||
1882 | |||
1859 | /* tell the subsystem the packet has gone out */ | 1883 | /* tell the subsystem the packet has gone out */ |
1860 | hpsb_iso_packet_sent(iso, cycle, event != 0x11); | 1884 | hpsb_iso_packet_sent(iso, cycle, event != 0x11); |
1861 | 1885 | ||
@@ -1943,6 +1967,16 @@ static int ohci_iso_xmit_queue(struct hpsb_iso *iso, struct hpsb_iso_packet_info | |||
1943 | prev->output_last.branchAddress = cpu_to_le32( | 1967 | prev->output_last.branchAddress = cpu_to_le32( |
1944 | dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3); | 1968 | dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3); |
1945 | 1969 | ||
1970 | /* | ||
1971 | * Link the skip address to this descriptor itself. This causes a | ||
1972 | * context to skip a cycle whenever lost cycles or FIFO overruns occur, | ||
1973 | * without dropping the data at that point the application should then | ||
1974 | * decide whether this is an error condition or not. Some protocols | ||
1975 | * can deal with this by dropping some rate-matching padding packets. | ||
1976 | */ | ||
1977 | next->output_more_immediate.branchAddress = | ||
1978 | prev->output_last.branchAddress; | ||
1979 | |||
1946 | /* disable interrupt, unless required by the IRQ interval */ | 1980 | /* disable interrupt, unless required by the IRQ interval */ |
1947 | if (prev_i % iso->irq_interval) { | 1981 | if (prev_i % iso->irq_interval) { |
1948 | prev->output_last.control &= cpu_to_le32(~(3 << 20)); /* no interrupt */ | 1982 | prev->output_last.control &= cpu_to_le32(~(3 << 20)); /* no interrupt */ |
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index 04e96ba56e09..ec2a0adbedb2 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c | |||
@@ -2356,13 +2356,16 @@ static void rawiso_activity_cb(struct hpsb_iso *iso) | |||
2356 | static void raw1394_iso_fill_status(struct hpsb_iso *iso, | 2356 | static void raw1394_iso_fill_status(struct hpsb_iso *iso, |
2357 | struct raw1394_iso_status *stat) | 2357 | struct raw1394_iso_status *stat) |
2358 | { | 2358 | { |
2359 | int overflows = atomic_read(&iso->overflows); | ||
2360 | int skips = atomic_read(&iso->skips); | ||
2361 | |||
2359 | stat->config.data_buf_size = iso->buf_size; | 2362 | stat->config.data_buf_size = iso->buf_size; |
2360 | stat->config.buf_packets = iso->buf_packets; | 2363 | stat->config.buf_packets = iso->buf_packets; |
2361 | stat->config.channel = iso->channel; | 2364 | stat->config.channel = iso->channel; |
2362 | stat->config.speed = iso->speed; | 2365 | stat->config.speed = iso->speed; |
2363 | stat->config.irq_interval = iso->irq_interval; | 2366 | stat->config.irq_interval = iso->irq_interval; |
2364 | stat->n_packets = hpsb_iso_n_ready(iso); | 2367 | stat->n_packets = hpsb_iso_n_ready(iso); |
2365 | stat->overflows = atomic_read(&iso->overflows); | 2368 | stat->overflows = ((skips & 0xFFFF) << 16) | ((overflows & 0xFFFF)); |
2366 | stat->xmit_cycle = iso->xmit_cycle; | 2369 | stat->xmit_cycle = iso->xmit_cycle; |
2367 | } | 2370 | } |
2368 | 2371 | ||
@@ -2437,6 +2440,8 @@ static int raw1394_iso_get_status(struct file_info *fi, void __user * uaddr) | |||
2437 | 2440 | ||
2438 | /* reset overflow counter */ | 2441 | /* reset overflow counter */ |
2439 | atomic_set(&iso->overflows, 0); | 2442 | atomic_set(&iso->overflows, 0); |
2443 | /* reset skip counter */ | ||
2444 | atomic_set(&iso->skips, 0); | ||
2440 | 2445 | ||
2441 | return 0; | 2446 | return 0; |
2442 | } | 2447 | } |
@@ -2935,6 +2940,7 @@ static int raw1394_release(struct inode *inode, struct file *file) | |||
2935 | /* | 2940 | /* |
2936 | * Export information about protocols/devices supported by this driver. | 2941 | * Export information about protocols/devices supported by this driver. |
2937 | */ | 2942 | */ |
2943 | #ifdef MODULE | ||
2938 | static struct ieee1394_device_id raw1394_id_table[] = { | 2944 | static struct ieee1394_device_id raw1394_id_table[] = { |
2939 | { | 2945 | { |
2940 | .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, | 2946 | .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, |
@@ -2956,6 +2962,7 @@ static struct ieee1394_device_id raw1394_id_table[] = { | |||
2956 | }; | 2962 | }; |
2957 | 2963 | ||
2958 | MODULE_DEVICE_TABLE(ieee1394, raw1394_id_table); | 2964 | MODULE_DEVICE_TABLE(ieee1394, raw1394_id_table); |
2965 | #endif /* MODULE */ | ||
2959 | 2966 | ||
2960 | static struct hpsb_protocol_driver raw1394_driver = { | 2967 | static struct hpsb_protocol_driver raw1394_driver = { |
2961 | .name = "raw1394", | 2968 | .name = "raw1394", |
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c index e03024eeeac1..e24772d336e1 100644 --- a/drivers/ieee1394/video1394.c +++ b/drivers/ieee1394/video1394.c | |||
@@ -1293,6 +1293,7 @@ static const struct file_operations video1394_fops= | |||
1293 | /* | 1293 | /* |
1294 | * Export information about protocols/devices supported by this driver. | 1294 | * Export information about protocols/devices supported by this driver. |
1295 | */ | 1295 | */ |
1296 | #ifdef MODULE | ||
1296 | static struct ieee1394_device_id video1394_id_table[] = { | 1297 | static struct ieee1394_device_id video1394_id_table[] = { |
1297 | { | 1298 | { |
1298 | .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, | 1299 | .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, |
@@ -1313,6 +1314,7 @@ static struct ieee1394_device_id video1394_id_table[] = { | |||
1313 | }; | 1314 | }; |
1314 | 1315 | ||
1315 | MODULE_DEVICE_TABLE(ieee1394, video1394_id_table); | 1316 | MODULE_DEVICE_TABLE(ieee1394, video1394_id_table); |
1317 | #endif /* MODULE */ | ||
1316 | 1318 | ||
1317 | static struct hpsb_protocol_driver video1394_driver = { | 1319 | static struct hpsb_protocol_driver video1394_driver = { |
1318 | .name = VIDEO1394_DRIVER_NAME, | 1320 | .name = VIDEO1394_DRIVER_NAME, |
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 9dea14db724c..5f9d860925a1 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig | |||
@@ -149,6 +149,15 @@ config INPUT_APMPOWER | |||
149 | To compile this driver as a module, choose M here: the | 149 | To compile this driver as a module, choose M here: the |
150 | module will be called apm-power. | 150 | module will be called apm-power. |
151 | 151 | ||
152 | config XEN_KBDDEV_FRONTEND | ||
153 | tristate "Xen virtual keyboard and mouse support" | ||
154 | depends on XEN_FBDEV_FRONTEND | ||
155 | default y | ||
156 | help | ||
157 | This driver implements the front-end of the Xen virtual | ||
158 | keyboard and mouse device driver. It communicates with a back-end | ||
159 | in another domain. | ||
160 | |||
152 | comment "Input Device Drivers" | 161 | comment "Input Device Drivers" |
153 | 162 | ||
154 | source "drivers/input/keyboard/Kconfig" | 163 | source "drivers/input/keyboard/Kconfig" |
diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 2ae87b19caa8..98c4f9a77876 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile | |||
@@ -23,3 +23,5 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ | |||
23 | obj-$(CONFIG_INPUT_MISC) += misc/ | 23 | obj-$(CONFIG_INPUT_MISC) += misc/ |
24 | 24 | ||
25 | obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o | 25 | obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o |
26 | |||
27 | obj-$(CONFIG_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o | ||
diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c new file mode 100644 index 000000000000..0f47f4697cdf --- /dev/null +++ b/drivers/input/xen-kbdfront.c | |||
@@ -0,0 +1,340 @@ | |||
1 | /* | ||
2 | * Xen para-virtual input device | ||
3 | * | ||
4 | * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> | ||
5 | * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> | ||
6 | * | ||
7 | * Based on linux/drivers/input/mouse/sermouse.c | ||
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 for | ||
11 | * more details. | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * TODO: | ||
16 | * | ||
17 | * Switch to grant tables together with xen-fbfront.c. | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/input.h> | ||
24 | #include <asm/xen/hypervisor.h> | ||
25 | #include <xen/events.h> | ||
26 | #include <xen/page.h> | ||
27 | #include <xen/interface/io/fbif.h> | ||
28 | #include <xen/interface/io/kbdif.h> | ||
29 | #include <xen/xenbus.h> | ||
30 | |||
31 | struct xenkbd_info { | ||
32 | struct input_dev *kbd; | ||
33 | struct input_dev *ptr; | ||
34 | struct xenkbd_page *page; | ||
35 | int irq; | ||
36 | struct xenbus_device *xbdev; | ||
37 | char phys[32]; | ||
38 | }; | ||
39 | |||
40 | static int xenkbd_remove(struct xenbus_device *); | ||
41 | static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *); | ||
42 | static void xenkbd_disconnect_backend(struct xenkbd_info *); | ||
43 | |||
44 | /* | ||
45 | * Note: if you need to send out events, see xenfb_do_update() for how | ||
46 | * to do that. | ||
47 | */ | ||
48 | |||
49 | static irqreturn_t input_handler(int rq, void *dev_id) | ||
50 | { | ||
51 | struct xenkbd_info *info = dev_id; | ||
52 | struct xenkbd_page *page = info->page; | ||
53 | __u32 cons, prod; | ||
54 | |||
55 | prod = page->in_prod; | ||
56 | if (prod == page->in_cons) | ||
57 | return IRQ_HANDLED; | ||
58 | rmb(); /* ensure we see ring contents up to prod */ | ||
59 | for (cons = page->in_cons; cons != prod; cons++) { | ||
60 | union xenkbd_in_event *event; | ||
61 | struct input_dev *dev; | ||
62 | event = &XENKBD_IN_RING_REF(page, cons); | ||
63 | |||
64 | dev = info->ptr; | ||
65 | switch (event->type) { | ||
66 | case XENKBD_TYPE_MOTION: | ||
67 | input_report_rel(dev, REL_X, event->motion.rel_x); | ||
68 | input_report_rel(dev, REL_Y, event->motion.rel_y); | ||
69 | break; | ||
70 | case XENKBD_TYPE_KEY: | ||
71 | dev = NULL; | ||
72 | if (test_bit(event->key.keycode, info->kbd->keybit)) | ||
73 | dev = info->kbd; | ||
74 | if (test_bit(event->key.keycode, info->ptr->keybit)) | ||
75 | dev = info->ptr; | ||
76 | if (dev) | ||
77 | input_report_key(dev, event->key.keycode, | ||
78 | event->key.pressed); | ||
79 | else | ||
80 | printk(KERN_WARNING | ||
81 | "xenkbd: unhandled keycode 0x%x\n", | ||
82 | event->key.keycode); | ||
83 | break; | ||
84 | case XENKBD_TYPE_POS: | ||
85 | input_report_abs(dev, ABS_X, event->pos.abs_x); | ||
86 | input_report_abs(dev, ABS_Y, event->pos.abs_y); | ||
87 | break; | ||
88 | } | ||
89 | if (dev) | ||
90 | input_sync(dev); | ||
91 | } | ||
92 | mb(); /* ensure we got ring contents */ | ||
93 | page->in_cons = cons; | ||
94 | notify_remote_via_irq(info->irq); | ||
95 | |||
96 | return IRQ_HANDLED; | ||
97 | } | ||
98 | |||
99 | static int __devinit xenkbd_probe(struct xenbus_device *dev, | ||
100 | const struct xenbus_device_id *id) | ||
101 | { | ||
102 | int ret, i; | ||
103 | struct xenkbd_info *info; | ||
104 | struct input_dev *kbd, *ptr; | ||
105 | |||
106 | info = kzalloc(sizeof(*info), GFP_KERNEL); | ||
107 | if (!info) { | ||
108 | xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); | ||
109 | return -ENOMEM; | ||
110 | } | ||
111 | dev->dev.driver_data = info; | ||
112 | info->xbdev = dev; | ||
113 | info->irq = -1; | ||
114 | snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename); | ||
115 | |||
116 | info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); | ||
117 | if (!info->page) | ||
118 | goto error_nomem; | ||
119 | |||
120 | /* keyboard */ | ||
121 | kbd = input_allocate_device(); | ||
122 | if (!kbd) | ||
123 | goto error_nomem; | ||
124 | kbd->name = "Xen Virtual Keyboard"; | ||
125 | kbd->phys = info->phys; | ||
126 | kbd->id.bustype = BUS_PCI; | ||
127 | kbd->id.vendor = 0x5853; | ||
128 | kbd->id.product = 0xffff; | ||
129 | kbd->evbit[0] = BIT(EV_KEY); | ||
130 | for (i = KEY_ESC; i < KEY_UNKNOWN; i++) | ||
131 | set_bit(i, kbd->keybit); | ||
132 | for (i = KEY_OK; i < KEY_MAX; i++) | ||
133 | set_bit(i, kbd->keybit); | ||
134 | |||
135 | ret = input_register_device(kbd); | ||
136 | if (ret) { | ||
137 | input_free_device(kbd); | ||
138 | xenbus_dev_fatal(dev, ret, "input_register_device(kbd)"); | ||
139 | goto error; | ||
140 | } | ||
141 | info->kbd = kbd; | ||
142 | |||
143 | /* pointing device */ | ||
144 | ptr = input_allocate_device(); | ||
145 | if (!ptr) | ||
146 | goto error_nomem; | ||
147 | ptr->name = "Xen Virtual Pointer"; | ||
148 | ptr->phys = info->phys; | ||
149 | ptr->id.bustype = BUS_PCI; | ||
150 | ptr->id.vendor = 0x5853; | ||
151 | ptr->id.product = 0xfffe; | ||
152 | ptr->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); | ||
153 | for (i = BTN_LEFT; i <= BTN_TASK; i++) | ||
154 | set_bit(i, ptr->keybit); | ||
155 | ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y); | ||
156 | input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0); | ||
157 | input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0); | ||
158 | |||
159 | ret = input_register_device(ptr); | ||
160 | if (ret) { | ||
161 | input_free_device(ptr); | ||
162 | xenbus_dev_fatal(dev, ret, "input_register_device(ptr)"); | ||
163 | goto error; | ||
164 | } | ||
165 | info->ptr = ptr; | ||
166 | |||
167 | ret = xenkbd_connect_backend(dev, info); | ||
168 | if (ret < 0) | ||
169 | goto error; | ||
170 | |||
171 | return 0; | ||
172 | |||
173 | error_nomem: | ||
174 | ret = -ENOMEM; | ||
175 | xenbus_dev_fatal(dev, ret, "allocating device memory"); | ||
176 | error: | ||
177 | xenkbd_remove(dev); | ||
178 | return ret; | ||
179 | } | ||
180 | |||
181 | static int xenkbd_resume(struct xenbus_device *dev) | ||
182 | { | ||
183 | struct xenkbd_info *info = dev->dev.driver_data; | ||
184 | |||
185 | xenkbd_disconnect_backend(info); | ||
186 | memset(info->page, 0, PAGE_SIZE); | ||
187 | return xenkbd_connect_backend(dev, info); | ||
188 | } | ||
189 | |||
190 | static int xenkbd_remove(struct xenbus_device *dev) | ||
191 | { | ||
192 | struct xenkbd_info *info = dev->dev.driver_data; | ||
193 | |||
194 | xenkbd_disconnect_backend(info); | ||
195 | if (info->kbd) | ||
196 | input_unregister_device(info->kbd); | ||
197 | if (info->ptr) | ||
198 | input_unregister_device(info->ptr); | ||
199 | free_page((unsigned long)info->page); | ||
200 | kfree(info); | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static int xenkbd_connect_backend(struct xenbus_device *dev, | ||
205 | struct xenkbd_info *info) | ||
206 | { | ||
207 | int ret, evtchn; | ||
208 | struct xenbus_transaction xbt; | ||
209 | |||
210 | ret = xenbus_alloc_evtchn(dev, &evtchn); | ||
211 | if (ret) | ||
212 | return ret; | ||
213 | ret = bind_evtchn_to_irqhandler(evtchn, input_handler, | ||
214 | 0, dev->devicetype, info); | ||
215 | if (ret < 0) { | ||
216 | xenbus_free_evtchn(dev, evtchn); | ||
217 | xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); | ||
218 | return ret; | ||
219 | } | ||
220 | info->irq = ret; | ||
221 | |||
222 | again: | ||
223 | ret = xenbus_transaction_start(&xbt); | ||
224 | if (ret) { | ||
225 | xenbus_dev_fatal(dev, ret, "starting transaction"); | ||
226 | return ret; | ||
227 | } | ||
228 | ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", | ||
229 | virt_to_mfn(info->page)); | ||
230 | if (ret) | ||
231 | goto error_xenbus; | ||
232 | ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", | ||
233 | evtchn); | ||
234 | if (ret) | ||
235 | goto error_xenbus; | ||
236 | ret = xenbus_transaction_end(xbt, 0); | ||
237 | if (ret) { | ||
238 | if (ret == -EAGAIN) | ||
239 | goto again; | ||
240 | xenbus_dev_fatal(dev, ret, "completing transaction"); | ||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | xenbus_switch_state(dev, XenbusStateInitialised); | ||
245 | return 0; | ||
246 | |||
247 | error_xenbus: | ||
248 | xenbus_transaction_end(xbt, 1); | ||
249 | xenbus_dev_fatal(dev, ret, "writing xenstore"); | ||
250 | return ret; | ||
251 | } | ||
252 | |||
253 | static void xenkbd_disconnect_backend(struct xenkbd_info *info) | ||
254 | { | ||
255 | if (info->irq >= 0) | ||
256 | unbind_from_irqhandler(info->irq, info); | ||
257 | info->irq = -1; | ||
258 | } | ||
259 | |||
260 | static void xenkbd_backend_changed(struct xenbus_device *dev, | ||
261 | enum xenbus_state backend_state) | ||
262 | { | ||
263 | struct xenkbd_info *info = dev->dev.driver_data; | ||
264 | int ret, val; | ||
265 | |||
266 | switch (backend_state) { | ||
267 | case XenbusStateInitialising: | ||
268 | case XenbusStateInitialised: | ||
269 | case XenbusStateUnknown: | ||
270 | case XenbusStateClosed: | ||
271 | break; | ||
272 | |||
273 | case XenbusStateInitWait: | ||
274 | InitWait: | ||
275 | ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, | ||
276 | "feature-abs-pointer", "%d", &val); | ||
277 | if (ret < 0) | ||
278 | val = 0; | ||
279 | if (val) { | ||
280 | ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, | ||
281 | "request-abs-pointer", "1"); | ||
282 | if (ret) | ||
283 | printk(KERN_WARNING | ||
284 | "xenkbd: can't request abs-pointer"); | ||
285 | } | ||
286 | xenbus_switch_state(dev, XenbusStateConnected); | ||
287 | break; | ||
288 | |||
289 | case XenbusStateConnected: | ||
290 | /* | ||
291 | * Work around xenbus race condition: If backend goes | ||
292 | * through InitWait to Connected fast enough, we can | ||
293 | * get Connected twice here. | ||
294 | */ | ||
295 | if (dev->state != XenbusStateConnected) | ||
296 | goto InitWait; /* no InitWait seen yet, fudge it */ | ||
297 | break; | ||
298 | |||
299 | case XenbusStateClosing: | ||
300 | xenbus_frontend_closed(dev); | ||
301 | break; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | static struct xenbus_device_id xenkbd_ids[] = { | ||
306 | { "vkbd" }, | ||
307 | { "" } | ||
308 | }; | ||
309 | |||
310 | static struct xenbus_driver xenkbd = { | ||
311 | .name = "vkbd", | ||
312 | .owner = THIS_MODULE, | ||
313 | .ids = xenkbd_ids, | ||
314 | .probe = xenkbd_probe, | ||
315 | .remove = xenkbd_remove, | ||
316 | .resume = xenkbd_resume, | ||
317 | .otherend_changed = xenkbd_backend_changed, | ||
318 | }; | ||
319 | |||
320 | static int __init xenkbd_init(void) | ||
321 | { | ||
322 | if (!is_running_on_xen()) | ||
323 | return -ENODEV; | ||
324 | |||
325 | /* Nothing to do if running in dom0. */ | ||
326 | if (is_initial_xendomain()) | ||
327 | return -ENODEV; | ||
328 | |||
329 | return xenbus_register_frontend(&xenkbd); | ||
330 | } | ||
331 | |||
332 | static void __exit xenkbd_cleanup(void) | ||
333 | { | ||
334 | xenbus_unregister_driver(&xenkbd); | ||
335 | } | ||
336 | |||
337 | module_init(xenkbd_init); | ||
338 | module_exit(xenkbd_cleanup); | ||
339 | |||
340 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/md/Makefile b/drivers/md/Makefile index d9aa7edb8780..7be09eeea293 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile | |||
@@ -3,10 +3,10 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | dm-mod-objs := dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \ | 5 | dm-mod-objs := dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \ |
6 | dm-ioctl.o dm-io.o kcopyd.o | 6 | dm-ioctl.o dm-io.o dm-kcopyd.o |
7 | dm-multipath-objs := dm-hw-handler.o dm-path-selector.o dm-mpath.o | 7 | dm-multipath-objs := dm-hw-handler.o dm-path-selector.o dm-mpath.o |
8 | dm-snapshot-objs := dm-snap.o dm-exception-store.o | 8 | dm-snapshot-objs := dm-snap.o dm-exception-store.o |
9 | dm-mirror-objs := dm-log.o dm-raid1.o | 9 | dm-mirror-objs := dm-raid1.o |
10 | dm-rdac-objs := dm-mpath-rdac.o | 10 | dm-rdac-objs := dm-mpath-rdac.o |
11 | dm-hp-sw-objs := dm-mpath-hp-sw.o | 11 | dm-hp-sw-objs := dm-mpath-hp-sw.o |
12 | md-mod-objs := md.o bitmap.o | 12 | md-mod-objs := md.o bitmap.o |
@@ -39,7 +39,7 @@ obj-$(CONFIG_DM_MULTIPATH_EMC) += dm-emc.o | |||
39 | obj-$(CONFIG_DM_MULTIPATH_HP) += dm-hp-sw.o | 39 | obj-$(CONFIG_DM_MULTIPATH_HP) += dm-hp-sw.o |
40 | obj-$(CONFIG_DM_MULTIPATH_RDAC) += dm-rdac.o | 40 | obj-$(CONFIG_DM_MULTIPATH_RDAC) += dm-rdac.o |
41 | obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o | 41 | obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o |
42 | obj-$(CONFIG_DM_MIRROR) += dm-mirror.o | 42 | obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o |
43 | obj-$(CONFIG_DM_ZERO) += dm-zero.o | 43 | obj-$(CONFIG_DM_ZERO) += dm-zero.o |
44 | 44 | ||
45 | quiet_cmd_unroll = UNROLL $@ | 45 | quiet_cmd_unroll = UNROLL $@ |
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c index 5bbce29f143a..41f408068a7c 100644 --- a/drivers/md/dm-exception-store.c +++ b/drivers/md/dm-exception-store.c | |||
@@ -9,13 +9,13 @@ | |||
9 | 9 | ||
10 | #include "dm.h" | 10 | #include "dm.h" |
11 | #include "dm-snap.h" | 11 | #include "dm-snap.h" |
12 | #include "dm-io.h" | ||
13 | #include "kcopyd.h" | ||
14 | 12 | ||
15 | #include <linux/mm.h> | 13 | #include <linux/mm.h> |
16 | #include <linux/pagemap.h> | 14 | #include <linux/pagemap.h> |
17 | #include <linux/vmalloc.h> | 15 | #include <linux/vmalloc.h> |
18 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/dm-io.h> | ||
18 | #include <linux/dm-kcopyd.h> | ||
19 | 19 | ||
20 | #define DM_MSG_PREFIX "snapshots" | 20 | #define DM_MSG_PREFIX "snapshots" |
21 | #define DM_CHUNK_SIZE_DEFAULT_SECTORS 32 /* 16KB */ | 21 | #define DM_CHUNK_SIZE_DEFAULT_SECTORS 32 /* 16KB */ |
@@ -131,7 +131,7 @@ struct pstore { | |||
131 | 131 | ||
132 | static unsigned sectors_to_pages(unsigned sectors) | 132 | static unsigned sectors_to_pages(unsigned sectors) |
133 | { | 133 | { |
134 | return sectors / (PAGE_SIZE >> 9); | 134 | return DIV_ROUND_UP(sectors, PAGE_SIZE >> 9); |
135 | } | 135 | } |
136 | 136 | ||
137 | static int alloc_area(struct pstore *ps) | 137 | static int alloc_area(struct pstore *ps) |
@@ -159,7 +159,7 @@ static void free_area(struct pstore *ps) | |||
159 | } | 159 | } |
160 | 160 | ||
161 | struct mdata_req { | 161 | struct mdata_req { |
162 | struct io_region *where; | 162 | struct dm_io_region *where; |
163 | struct dm_io_request *io_req; | 163 | struct dm_io_request *io_req; |
164 | struct work_struct work; | 164 | struct work_struct work; |
165 | int result; | 165 | int result; |
@@ -177,7 +177,7 @@ static void do_metadata(struct work_struct *work) | |||
177 | */ | 177 | */ |
178 | static int chunk_io(struct pstore *ps, uint32_t chunk, int rw, int metadata) | 178 | static int chunk_io(struct pstore *ps, uint32_t chunk, int rw, int metadata) |
179 | { | 179 | { |
180 | struct io_region where = { | 180 | struct dm_io_region where = { |
181 | .bdev = ps->snap->cow->bdev, | 181 | .bdev = ps->snap->cow->bdev, |
182 | .sector = ps->snap->chunk_size * chunk, | 182 | .sector = ps->snap->chunk_size * chunk, |
183 | .count = ps->snap->chunk_size, | 183 | .count = ps->snap->chunk_size, |
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 8f25f628ef16..4789c42d9a3a 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c | |||
@@ -5,13 +5,14 @@ | |||
5 | * This file is released under the GPL. | 5 | * This file is released under the GPL. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include "dm-io.h" | 8 | #include "dm.h" |
9 | 9 | ||
10 | #include <linux/bio.h> | 10 | #include <linux/bio.h> |
11 | #include <linux/mempool.h> | 11 | #include <linux/mempool.h> |
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | #include <linux/dm-io.h> | ||
15 | 16 | ||
16 | struct dm_io_client { | 17 | struct dm_io_client { |
17 | mempool_t *pool; | 18 | mempool_t *pool; |
@@ -20,7 +21,7 @@ struct dm_io_client { | |||
20 | 21 | ||
21 | /* FIXME: can we shrink this ? */ | 22 | /* FIXME: can we shrink this ? */ |
22 | struct io { | 23 | struct io { |
23 | unsigned long error; | 24 | unsigned long error_bits; |
24 | atomic_t count; | 25 | atomic_t count; |
25 | struct task_struct *sleeper; | 26 | struct task_struct *sleeper; |
26 | struct dm_io_client *client; | 27 | struct dm_io_client *client; |
@@ -107,14 +108,14 @@ static inline unsigned bio_get_region(struct bio *bio) | |||
107 | static void dec_count(struct io *io, unsigned int region, int error) | 108 | static void dec_count(struct io *io, unsigned int region, int error) |
108 | { | 109 | { |
109 | if (error) | 110 | if (error) |
110 | set_bit(region, &io->error); | 111 | set_bit(region, &io->error_bits); |
111 | 112 | ||
112 | if (atomic_dec_and_test(&io->count)) { | 113 | if (atomic_dec_and_test(&io->count)) { |
113 | if (io->sleeper) | 114 | if (io->sleeper) |
114 | wake_up_process(io->sleeper); | 115 | wake_up_process(io->sleeper); |
115 | 116 | ||
116 | else { | 117 | else { |
117 | unsigned long r = io->error; | 118 | unsigned long r = io->error_bits; |
118 | io_notify_fn fn = io->callback; | 119 | io_notify_fn fn = io->callback; |
119 | void *context = io->context; | 120 | void *context = io->context; |
120 | 121 | ||
@@ -271,7 +272,7 @@ static void km_dp_init(struct dpages *dp, void *data) | |||
271 | /*----------------------------------------------------------------- | 272 | /*----------------------------------------------------------------- |
272 | * IO routines that accept a list of pages. | 273 | * IO routines that accept a list of pages. |
273 | *---------------------------------------------------------------*/ | 274 | *---------------------------------------------------------------*/ |
274 | static void do_region(int rw, unsigned int region, struct io_region *where, | 275 | static void do_region(int rw, unsigned region, struct dm_io_region *where, |
275 | struct dpages *dp, struct io *io) | 276 | struct dpages *dp, struct io *io) |
276 | { | 277 | { |
277 | struct bio *bio; | 278 | struct bio *bio; |
@@ -320,7 +321,7 @@ static void do_region(int rw, unsigned int region, struct io_region *where, | |||
320 | } | 321 | } |
321 | 322 | ||
322 | static void dispatch_io(int rw, unsigned int num_regions, | 323 | static void dispatch_io(int rw, unsigned int num_regions, |
323 | struct io_region *where, struct dpages *dp, | 324 | struct dm_io_region *where, struct dpages *dp, |
324 | struct io *io, int sync) | 325 | struct io *io, int sync) |
325 | { | 326 | { |
326 | int i; | 327 | int i; |
@@ -347,17 +348,17 @@ static void dispatch_io(int rw, unsigned int num_regions, | |||
347 | } | 348 | } |
348 | 349 | ||
349 | static int sync_io(struct dm_io_client *client, unsigned int num_regions, | 350 | static int sync_io(struct dm_io_client *client, unsigned int num_regions, |
350 | struct io_region *where, int rw, struct dpages *dp, | 351 | struct dm_io_region *where, int rw, struct dpages *dp, |
351 | unsigned long *error_bits) | 352 | unsigned long *error_bits) |
352 | { | 353 | { |
353 | struct io io; | 354 | struct io io; |
354 | 355 | ||
355 | if (num_regions > 1 && rw != WRITE) { | 356 | if (num_regions > 1 && (rw & RW_MASK) != WRITE) { |
356 | WARN_ON(1); | 357 | WARN_ON(1); |
357 | return -EIO; | 358 | return -EIO; |
358 | } | 359 | } |
359 | 360 | ||
360 | io.error = 0; | 361 | io.error_bits = 0; |
361 | atomic_set(&io.count, 1); /* see dispatch_io() */ | 362 | atomic_set(&io.count, 1); /* see dispatch_io() */ |
362 | io.sleeper = current; | 363 | io.sleeper = current; |
363 | io.client = client; | 364 | io.client = client; |
@@ -378,25 +379,25 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions, | |||
378 | return -EINTR; | 379 | return -EINTR; |
379 | 380 | ||
380 | if (error_bits) | 381 | if (error_bits) |
381 | *error_bits = io.error; | 382 | *error_bits = io.error_bits; |
382 | 383 | ||
383 | return io.error ? -EIO : 0; | 384 | return io.error_bits ? -EIO : 0; |
384 | } | 385 | } |
385 | 386 | ||
386 | static int async_io(struct dm_io_client *client, unsigned int num_regions, | 387 | static int async_io(struct dm_io_client *client, unsigned int num_regions, |
387 | struct io_region *where, int rw, struct dpages *dp, | 388 | struct dm_io_region *where, int rw, struct dpages *dp, |
388 | io_notify_fn fn, void *context) | 389 | io_notify_fn fn, void *context) |
389 | { | 390 | { |
390 | struct io *io; | 391 | struct io *io; |
391 | 392 | ||
392 | if (num_regions > 1 && rw != WRITE) { | 393 | if (num_regions > 1 && (rw & RW_MASK) != WRITE) { |
393 | WARN_ON(1); | 394 | WARN_ON(1); |
394 | fn(1, context); | 395 | fn(1, context); |
395 | return -EIO; | 396 | return -EIO; |
396 | } | 397 | } |
397 | 398 | ||
398 | io = mempool_alloc(client->pool, GFP_NOIO); | 399 | io = mempool_alloc(client->pool, GFP_NOIO); |
399 | io->error = 0; | 400 | io->error_bits = 0; |
400 | atomic_set(&io->count, 1); /* see dispatch_io() */ | 401 | atomic_set(&io->count, 1); /* see dispatch_io() */ |
401 | io->sleeper = NULL; | 402 | io->sleeper = NULL; |
402 | io->client = client; | 403 | io->client = client; |
@@ -435,10 +436,15 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp) | |||
435 | } | 436 | } |
436 | 437 | ||
437 | /* | 438 | /* |
438 | * New collapsed (a)synchronous interface | 439 | * New collapsed (a)synchronous interface. |
440 | * | ||
441 | * If the IO is asynchronous (i.e. it has notify.fn), you must either unplug | ||
442 | * the queue with blk_unplug() some time later or set the BIO_RW_SYNC bit in | ||
443 | * io_req->bi_rw. If you fail to do one of these, the IO will be submitted to | ||
444 | * the disk after q->unplug_delay, which defaults to 3ms in blk-settings.c. | ||
439 | */ | 445 | */ |
440 | int dm_io(struct dm_io_request *io_req, unsigned num_regions, | 446 | int dm_io(struct dm_io_request *io_req, unsigned num_regions, |
441 | struct io_region *where, unsigned long *sync_error_bits) | 447 | struct dm_io_region *where, unsigned long *sync_error_bits) |
442 | { | 448 | { |
443 | int r; | 449 | int r; |
444 | struct dpages dp; | 450 | struct dpages dp; |
diff --git a/drivers/md/kcopyd.c b/drivers/md/dm-kcopyd.c index e76b52ade690..996802b8a452 100644 --- a/drivers/md/kcopyd.c +++ b/drivers/md/dm-kcopyd.c | |||
@@ -9,9 +9,8 @@ | |||
9 | * completion notification. | 9 | * completion notification. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <asm/types.h> | 12 | #include <linux/types.h> |
13 | #include <asm/atomic.h> | 13 | #include <asm/atomic.h> |
14 | |||
15 | #include <linux/blkdev.h> | 14 | #include <linux/blkdev.h> |
16 | #include <linux/fs.h> | 15 | #include <linux/fs.h> |
17 | #include <linux/init.h> | 16 | #include <linux/init.h> |
@@ -23,24 +22,15 @@ | |||
23 | #include <linux/vmalloc.h> | 22 | #include <linux/vmalloc.h> |
24 | #include <linux/workqueue.h> | 23 | #include <linux/workqueue.h> |
25 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
25 | #include <linux/dm-kcopyd.h> | ||
26 | 26 | ||
27 | #include "kcopyd.h" | 27 | #include "dm.h" |
28 | |||
29 | static struct workqueue_struct *_kcopyd_wq; | ||
30 | static struct work_struct _kcopyd_work; | ||
31 | |||
32 | static void wake(void) | ||
33 | { | ||
34 | queue_work(_kcopyd_wq, &_kcopyd_work); | ||
35 | } | ||
36 | 28 | ||
37 | /*----------------------------------------------------------------- | 29 | /*----------------------------------------------------------------- |
38 | * Each kcopyd client has its own little pool of preallocated | 30 | * Each kcopyd client has its own little pool of preallocated |
39 | * pages for kcopyd io. | 31 | * pages for kcopyd io. |
40 | *---------------------------------------------------------------*/ | 32 | *---------------------------------------------------------------*/ |
41 | struct kcopyd_client { | 33 | struct dm_kcopyd_client { |
42 | struct list_head list; | ||
43 | |||
44 | spinlock_t lock; | 34 | spinlock_t lock; |
45 | struct page_list *pages; | 35 | struct page_list *pages; |
46 | unsigned int nr_pages; | 36 | unsigned int nr_pages; |
@@ -50,8 +40,32 @@ struct kcopyd_client { | |||
50 | 40 | ||
51 | wait_queue_head_t destroyq; | 41 | wait_queue_head_t destroyq; |
52 | atomic_t nr_jobs; | 42 | atomic_t nr_jobs; |
43 | |||
44 | mempool_t *job_pool; | ||
45 | |||
46 | struct workqueue_struct *kcopyd_wq; | ||
47 | struct work_struct kcopyd_work; | ||
48 | |||
49 | /* | ||
50 | * We maintain three lists of jobs: | ||
51 | * | ||
52 | * i) jobs waiting for pages | ||
53 | * ii) jobs that have pages, and are waiting for the io to be issued. | ||
54 | * iii) jobs that have completed. | ||
55 | * | ||
56 | * All three of these are protected by job_lock. | ||
57 | */ | ||
58 | spinlock_t job_lock; | ||
59 | struct list_head complete_jobs; | ||
60 | struct list_head io_jobs; | ||
61 | struct list_head pages_jobs; | ||
53 | }; | 62 | }; |
54 | 63 | ||
64 | static void wake(struct dm_kcopyd_client *kc) | ||
65 | { | ||
66 | queue_work(kc->kcopyd_wq, &kc->kcopyd_work); | ||
67 | } | ||
68 | |||
55 | static struct page_list *alloc_pl(void) | 69 | static struct page_list *alloc_pl(void) |
56 | { | 70 | { |
57 | struct page_list *pl; | 71 | struct page_list *pl; |
@@ -75,7 +89,7 @@ static void free_pl(struct page_list *pl) | |||
75 | kfree(pl); | 89 | kfree(pl); |
76 | } | 90 | } |
77 | 91 | ||
78 | static int kcopyd_get_pages(struct kcopyd_client *kc, | 92 | static int kcopyd_get_pages(struct dm_kcopyd_client *kc, |
79 | unsigned int nr, struct page_list **pages) | 93 | unsigned int nr, struct page_list **pages) |
80 | { | 94 | { |
81 | struct page_list *pl; | 95 | struct page_list *pl; |
@@ -98,7 +112,7 @@ static int kcopyd_get_pages(struct kcopyd_client *kc, | |||
98 | return 0; | 112 | return 0; |
99 | } | 113 | } |
100 | 114 | ||
101 | static void kcopyd_put_pages(struct kcopyd_client *kc, struct page_list *pl) | 115 | static void kcopyd_put_pages(struct dm_kcopyd_client *kc, struct page_list *pl) |
102 | { | 116 | { |
103 | struct page_list *cursor; | 117 | struct page_list *cursor; |
104 | 118 | ||
@@ -126,7 +140,7 @@ static void drop_pages(struct page_list *pl) | |||
126 | } | 140 | } |
127 | } | 141 | } |
128 | 142 | ||
129 | static int client_alloc_pages(struct kcopyd_client *kc, unsigned int nr) | 143 | static int client_alloc_pages(struct dm_kcopyd_client *kc, unsigned int nr) |
130 | { | 144 | { |
131 | unsigned int i; | 145 | unsigned int i; |
132 | struct page_list *pl = NULL, *next; | 146 | struct page_list *pl = NULL, *next; |
@@ -147,7 +161,7 @@ static int client_alloc_pages(struct kcopyd_client *kc, unsigned int nr) | |||
147 | return 0; | 161 | return 0; |
148 | } | 162 | } |
149 | 163 | ||
150 | static void client_free_pages(struct kcopyd_client *kc) | 164 | static void client_free_pages(struct dm_kcopyd_client *kc) |
151 | { | 165 | { |
152 | BUG_ON(kc->nr_free_pages != kc->nr_pages); | 166 | BUG_ON(kc->nr_free_pages != kc->nr_pages); |
153 | drop_pages(kc->pages); | 167 | drop_pages(kc->pages); |
@@ -161,7 +175,7 @@ static void client_free_pages(struct kcopyd_client *kc) | |||
161 | * ever having to do io (which could cause a deadlock). | 175 | * ever having to do io (which could cause a deadlock). |
162 | *---------------------------------------------------------------*/ | 176 | *---------------------------------------------------------------*/ |
163 | struct kcopyd_job { | 177 | struct kcopyd_job { |
164 | struct kcopyd_client *kc; | 178 | struct dm_kcopyd_client *kc; |
165 | struct list_head list; | 179 | struct list_head list; |
166 | unsigned long flags; | 180 | unsigned long flags; |
167 | 181 | ||
@@ -175,13 +189,13 @@ struct kcopyd_job { | |||
175 | * Either READ or WRITE | 189 | * Either READ or WRITE |
176 | */ | 190 | */ |
177 | int rw; | 191 | int rw; |
178 | struct io_region source; | 192 | struct dm_io_region source; |
179 | 193 | ||
180 | /* | 194 | /* |
181 | * The destinations for the transfer. | 195 | * The destinations for the transfer. |
182 | */ | 196 | */ |
183 | unsigned int num_dests; | 197 | unsigned int num_dests; |
184 | struct io_region dests[KCOPYD_MAX_REGIONS]; | 198 | struct dm_io_region dests[DM_KCOPYD_MAX_REGIONS]; |
185 | 199 | ||
186 | sector_t offset; | 200 | sector_t offset; |
187 | unsigned int nr_pages; | 201 | unsigned int nr_pages; |
@@ -191,7 +205,7 @@ struct kcopyd_job { | |||
191 | * Set this to ensure you are notified when the job has | 205 | * Set this to ensure you are notified when the job has |
192 | * completed. 'context' is for callback to use. | 206 | * completed. 'context' is for callback to use. |
193 | */ | 207 | */ |
194 | kcopyd_notify_fn fn; | 208 | dm_kcopyd_notify_fn fn; |
195 | void *context; | 209 | void *context; |
196 | 210 | ||
197 | /* | 211 | /* |
@@ -207,47 +221,19 @@ struct kcopyd_job { | |||
207 | #define MIN_JOBS 512 | 221 | #define MIN_JOBS 512 |
208 | 222 | ||
209 | static struct kmem_cache *_job_cache; | 223 | static struct kmem_cache *_job_cache; |
210 | static mempool_t *_job_pool; | ||
211 | 224 | ||
212 | /* | 225 | int __init dm_kcopyd_init(void) |
213 | * We maintain three lists of jobs: | ||
214 | * | ||
215 | * i) jobs waiting for pages | ||
216 | * ii) jobs that have pages, and are waiting for the io to be issued. | ||
217 | * iii) jobs that have completed. | ||
218 | * | ||
219 | * All three of these are protected by job_lock. | ||
220 | */ | ||
221 | static DEFINE_SPINLOCK(_job_lock); | ||
222 | |||
223 | static LIST_HEAD(_complete_jobs); | ||
224 | static LIST_HEAD(_io_jobs); | ||
225 | static LIST_HEAD(_pages_jobs); | ||
226 | |||
227 | static int jobs_init(void) | ||
228 | { | 226 | { |
229 | _job_cache = KMEM_CACHE(kcopyd_job, 0); | 227 | _job_cache = KMEM_CACHE(kcopyd_job, 0); |
230 | if (!_job_cache) | 228 | if (!_job_cache) |
231 | return -ENOMEM; | 229 | return -ENOMEM; |
232 | 230 | ||
233 | _job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache); | ||
234 | if (!_job_pool) { | ||
235 | kmem_cache_destroy(_job_cache); | ||
236 | return -ENOMEM; | ||
237 | } | ||
238 | |||
239 | return 0; | 231 | return 0; |
240 | } | 232 | } |
241 | 233 | ||
242 | static void jobs_exit(void) | 234 | void dm_kcopyd_exit(void) |
243 | { | 235 | { |
244 | BUG_ON(!list_empty(&_complete_jobs)); | ||
245 | BUG_ON(!list_empty(&_io_jobs)); | ||
246 | BUG_ON(!list_empty(&_pages_jobs)); | ||
247 | |||
248 | mempool_destroy(_job_pool); | ||
249 | kmem_cache_destroy(_job_cache); | 236 | kmem_cache_destroy(_job_cache); |
250 | _job_pool = NULL; | ||
251 | _job_cache = NULL; | 237 | _job_cache = NULL; |
252 | } | 238 | } |
253 | 239 | ||
@@ -255,18 +241,19 @@ static void jobs_exit(void) | |||
255 | * Functions to push and pop a job onto the head of a given job | 241 | * Functions to push and pop a job onto the head of a given job |
256 | * list. | 242 | * list. |
257 | */ | 243 | */ |
258 | static struct kcopyd_job *pop(struct list_head *jobs) | 244 | static struct kcopyd_job *pop(struct list_head *jobs, |
245 | struct dm_kcopyd_client *kc) | ||
259 | { | 246 | { |
260 | struct kcopyd_job *job = NULL; | 247 | struct kcopyd_job *job = NULL; |
261 | unsigned long flags; | 248 | unsigned long flags; |
262 | 249 | ||
263 | spin_lock_irqsave(&_job_lock, flags); | 250 | spin_lock_irqsave(&kc->job_lock, flags); |
264 | 251 | ||
265 | if (!list_empty(jobs)) { | 252 | if (!list_empty(jobs)) { |
266 | job = list_entry(jobs->next, struct kcopyd_job, list); | 253 | job = list_entry(jobs->next, struct kcopyd_job, list); |
267 | list_del(&job->list); | 254 | list_del(&job->list); |
268 | } | 255 | } |
269 | spin_unlock_irqrestore(&_job_lock, flags); | 256 | spin_unlock_irqrestore(&kc->job_lock, flags); |
270 | 257 | ||
271 | return job; | 258 | return job; |
272 | } | 259 | } |
@@ -274,10 +261,11 @@ static struct kcopyd_job *pop(struct list_head *jobs) | |||
274 | static void push(struct list_head *jobs, struct kcopyd_job *job) | 261 | static void push(struct list_head *jobs, struct kcopyd_job *job) |
275 | { | 262 | { |
276 | unsigned long flags; | 263 | unsigned long flags; |
264 | struct dm_kcopyd_client *kc = job->kc; | ||
277 | 265 | ||
278 | spin_lock_irqsave(&_job_lock, flags); | 266 | spin_lock_irqsave(&kc->job_lock, flags); |
279 | list_add_tail(&job->list, jobs); | 267 | list_add_tail(&job->list, jobs); |
280 | spin_unlock_irqrestore(&_job_lock, flags); | 268 | spin_unlock_irqrestore(&kc->job_lock, flags); |
281 | } | 269 | } |
282 | 270 | ||
283 | /* | 271 | /* |
@@ -294,11 +282,11 @@ static int run_complete_job(struct kcopyd_job *job) | |||
294 | void *context = job->context; | 282 | void *context = job->context; |
295 | int read_err = job->read_err; | 283 | int read_err = job->read_err; |
296 | unsigned long write_err = job->write_err; | 284 | unsigned long write_err = job->write_err; |
297 | kcopyd_notify_fn fn = job->fn; | 285 | dm_kcopyd_notify_fn fn = job->fn; |
298 | struct kcopyd_client *kc = job->kc; | 286 | struct dm_kcopyd_client *kc = job->kc; |
299 | 287 | ||
300 | kcopyd_put_pages(kc, job->pages); | 288 | kcopyd_put_pages(kc, job->pages); |
301 | mempool_free(job, _job_pool); | 289 | mempool_free(job, kc->job_pool); |
302 | fn(read_err, write_err, context); | 290 | fn(read_err, write_err, context); |
303 | 291 | ||
304 | if (atomic_dec_and_test(&kc->nr_jobs)) | 292 | if (atomic_dec_and_test(&kc->nr_jobs)) |
@@ -310,6 +298,7 @@ static int run_complete_job(struct kcopyd_job *job) | |||
310 | static void complete_io(unsigned long error, void *context) | 298 | static void complete_io(unsigned long error, void *context) |
311 | { | 299 | { |
312 | struct kcopyd_job *job = (struct kcopyd_job *) context; | 300 | struct kcopyd_job *job = (struct kcopyd_job *) context; |
301 | struct dm_kcopyd_client *kc = job->kc; | ||
313 | 302 | ||
314 | if (error) { | 303 | if (error) { |
315 | if (job->rw == WRITE) | 304 | if (job->rw == WRITE) |
@@ -317,22 +306,22 @@ static void complete_io(unsigned long error, void *context) | |||
317 | else | 306 | else |
318 | job->read_err = 1; | 307 | job->read_err = 1; |
319 | 308 | ||
320 | if (!test_bit(KCOPYD_IGNORE_ERROR, &job->flags)) { | 309 | if (!test_bit(DM_KCOPYD_IGNORE_ERROR, &job->flags)) { |
321 | push(&_complete_jobs, job); | 310 | push(&kc->complete_jobs, job); |
322 | wake(); | 311 | wake(kc); |
323 | return; | 312 | return; |
324 | } | 313 | } |
325 | } | 314 | } |
326 | 315 | ||
327 | if (job->rw == WRITE) | 316 | if (job->rw == WRITE) |
328 | push(&_complete_jobs, job); | 317 | push(&kc->complete_jobs, job); |
329 | 318 | ||
330 | else { | 319 | else { |
331 | job->rw = WRITE; | 320 | job->rw = WRITE; |
332 | push(&_io_jobs, job); | 321 | push(&kc->io_jobs, job); |
333 | } | 322 | } |
334 | 323 | ||
335 | wake(); | 324 | wake(kc); |
336 | } | 325 | } |
337 | 326 | ||
338 | /* | 327 | /* |
@@ -343,7 +332,7 @@ static int run_io_job(struct kcopyd_job *job) | |||
343 | { | 332 | { |
344 | int r; | 333 | int r; |
345 | struct dm_io_request io_req = { | 334 | struct dm_io_request io_req = { |
346 | .bi_rw = job->rw, | 335 | .bi_rw = job->rw | (1 << BIO_RW_SYNC), |
347 | .mem.type = DM_IO_PAGE_LIST, | 336 | .mem.type = DM_IO_PAGE_LIST, |
348 | .mem.ptr.pl = job->pages, | 337 | .mem.ptr.pl = job->pages, |
349 | .mem.offset = job->offset, | 338 | .mem.offset = job->offset, |
@@ -369,7 +358,7 @@ static int run_pages_job(struct kcopyd_job *job) | |||
369 | r = kcopyd_get_pages(job->kc, job->nr_pages, &job->pages); | 358 | r = kcopyd_get_pages(job->kc, job->nr_pages, &job->pages); |
370 | if (!r) { | 359 | if (!r) { |
371 | /* this job is ready for io */ | 360 | /* this job is ready for io */ |
372 | push(&_io_jobs, job); | 361 | push(&job->kc->io_jobs, job); |
373 | return 0; | 362 | return 0; |
374 | } | 363 | } |
375 | 364 | ||
@@ -384,12 +373,13 @@ static int run_pages_job(struct kcopyd_job *job) | |||
384 | * Run through a list for as long as possible. Returns the count | 373 | * Run through a list for as long as possible. Returns the count |
385 | * of successful jobs. | 374 | * of successful jobs. |
386 | */ | 375 | */ |
387 | static int process_jobs(struct list_head *jobs, int (*fn) (struct kcopyd_job *)) | 376 | static int process_jobs(struct list_head *jobs, struct dm_kcopyd_client *kc, |
377 | int (*fn) (struct kcopyd_job *)) | ||
388 | { | 378 | { |
389 | struct kcopyd_job *job; | 379 | struct kcopyd_job *job; |
390 | int r, count = 0; | 380 | int r, count = 0; |
391 | 381 | ||
392 | while ((job = pop(jobs))) { | 382 | while ((job = pop(jobs, kc))) { |
393 | 383 | ||
394 | r = fn(job); | 384 | r = fn(job); |
395 | 385 | ||
@@ -399,7 +389,7 @@ static int process_jobs(struct list_head *jobs, int (*fn) (struct kcopyd_job *)) | |||
399 | job->write_err = (unsigned long) -1L; | 389 | job->write_err = (unsigned long) -1L; |
400 | else | 390 | else |
401 | job->read_err = 1; | 391 | job->read_err = 1; |
402 | push(&_complete_jobs, job); | 392 | push(&kc->complete_jobs, job); |
403 | break; | 393 | break; |
404 | } | 394 | } |
405 | 395 | ||
@@ -421,8 +411,11 @@ static int process_jobs(struct list_head *jobs, int (*fn) (struct kcopyd_job *)) | |||
421 | /* | 411 | /* |
422 | * kcopyd does this every time it's woken up. | 412 | * kcopyd does this every time it's woken up. |
423 | */ | 413 | */ |
424 | static void do_work(struct work_struct *ignored) | 414 | static void do_work(struct work_struct *work) |
425 | { | 415 | { |
416 | struct dm_kcopyd_client *kc = container_of(work, | ||
417 | struct dm_kcopyd_client, kcopyd_work); | ||
418 | |||
426 | /* | 419 | /* |
427 | * The order that these are called is *very* important. | 420 | * The order that these are called is *very* important. |
428 | * complete jobs can free some pages for pages jobs. | 421 | * complete jobs can free some pages for pages jobs. |
@@ -430,9 +423,9 @@ static void do_work(struct work_struct *ignored) | |||
430 | * list. io jobs call wake when they complete and it all | 423 | * list. io jobs call wake when they complete and it all |
431 | * starts again. | 424 | * starts again. |
432 | */ | 425 | */ |
433 | process_jobs(&_complete_jobs, run_complete_job); | 426 | process_jobs(&kc->complete_jobs, kc, run_complete_job); |
434 | process_jobs(&_pages_jobs, run_pages_job); | 427 | process_jobs(&kc->pages_jobs, kc, run_pages_job); |
435 | process_jobs(&_io_jobs, run_io_job); | 428 | process_jobs(&kc->io_jobs, kc, run_io_job); |
436 | } | 429 | } |
437 | 430 | ||
438 | /* | 431 | /* |
@@ -442,9 +435,10 @@ static void do_work(struct work_struct *ignored) | |||
442 | */ | 435 | */ |
443 | static void dispatch_job(struct kcopyd_job *job) | 436 | static void dispatch_job(struct kcopyd_job *job) |
444 | { | 437 | { |
445 | atomic_inc(&job->kc->nr_jobs); | 438 | struct dm_kcopyd_client *kc = job->kc; |
446 | push(&_pages_jobs, job); | 439 | atomic_inc(&kc->nr_jobs); |
447 | wake(); | 440 | push(&kc->pages_jobs, job); |
441 | wake(kc); | ||
448 | } | 442 | } |
449 | 443 | ||
450 | #define SUB_JOB_SIZE 128 | 444 | #define SUB_JOB_SIZE 128 |
@@ -469,7 +463,7 @@ static void segment_complete(int read_err, unsigned long write_err, | |||
469 | * Only dispatch more work if there hasn't been an error. | 463 | * Only dispatch more work if there hasn't been an error. |
470 | */ | 464 | */ |
471 | if ((!job->read_err && !job->write_err) || | 465 | if ((!job->read_err && !job->write_err) || |
472 | test_bit(KCOPYD_IGNORE_ERROR, &job->flags)) { | 466 | test_bit(DM_KCOPYD_IGNORE_ERROR, &job->flags)) { |
473 | /* get the next chunk of work */ | 467 | /* get the next chunk of work */ |
474 | progress = job->progress; | 468 | progress = job->progress; |
475 | count = job->source.count - progress; | 469 | count = job->source.count - progress; |
@@ -484,7 +478,8 @@ static void segment_complete(int read_err, unsigned long write_err, | |||
484 | 478 | ||
485 | if (count) { | 479 | if (count) { |
486 | int i; | 480 | int i; |
487 | struct kcopyd_job *sub_job = mempool_alloc(_job_pool, GFP_NOIO); | 481 | struct kcopyd_job *sub_job = mempool_alloc(job->kc->job_pool, |
482 | GFP_NOIO); | ||
488 | 483 | ||
489 | *sub_job = *job; | 484 | *sub_job = *job; |
490 | sub_job->source.sector += progress; | 485 | sub_job->source.sector += progress; |
@@ -508,7 +503,7 @@ static void segment_complete(int read_err, unsigned long write_err, | |||
508 | * after we've completed. | 503 | * after we've completed. |
509 | */ | 504 | */ |
510 | job->fn(read_err, write_err, job->context); | 505 | job->fn(read_err, write_err, job->context); |
511 | mempool_free(job, _job_pool); | 506 | mempool_free(job, job->kc->job_pool); |
512 | } | 507 | } |
513 | } | 508 | } |
514 | 509 | ||
@@ -526,16 +521,16 @@ static void split_job(struct kcopyd_job *job) | |||
526 | segment_complete(0, 0u, job); | 521 | segment_complete(0, 0u, job); |
527 | } | 522 | } |
528 | 523 | ||
529 | int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from, | 524 | int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from, |
530 | unsigned int num_dests, struct io_region *dests, | 525 | unsigned int num_dests, struct dm_io_region *dests, |
531 | unsigned int flags, kcopyd_notify_fn fn, void *context) | 526 | unsigned int flags, dm_kcopyd_notify_fn fn, void *context) |
532 | { | 527 | { |
533 | struct kcopyd_job *job; | 528 | struct kcopyd_job *job; |
534 | 529 | ||
535 | /* | 530 | /* |
536 | * Allocate a new job. | 531 | * Allocate a new job. |
537 | */ | 532 | */ |
538 | job = mempool_alloc(_job_pool, GFP_NOIO); | 533 | job = mempool_alloc(kc->job_pool, GFP_NOIO); |
539 | 534 | ||
540 | /* | 535 | /* |
541 | * set up for the read. | 536 | * set up for the read. |
@@ -569,6 +564,7 @@ int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from, | |||
569 | 564 | ||
570 | return 0; | 565 | return 0; |
571 | } | 566 | } |
567 | EXPORT_SYMBOL(dm_kcopyd_copy); | ||
572 | 568 | ||
573 | /* | 569 | /* |
574 | * Cancels a kcopyd job, eg. someone might be deactivating a | 570 | * Cancels a kcopyd job, eg. someone might be deactivating a |
@@ -583,126 +579,76 @@ int kcopyd_cancel(struct kcopyd_job *job, int block) | |||
583 | #endif /* 0 */ | 579 | #endif /* 0 */ |
584 | 580 | ||
585 | /*----------------------------------------------------------------- | 581 | /*----------------------------------------------------------------- |
586 | * Unit setup | 582 | * Client setup |
587 | *---------------------------------------------------------------*/ | 583 | *---------------------------------------------------------------*/ |
588 | static DEFINE_MUTEX(_client_lock); | 584 | int dm_kcopyd_client_create(unsigned int nr_pages, |
589 | static LIST_HEAD(_clients); | 585 | struct dm_kcopyd_client **result) |
590 | |||
591 | static void client_add(struct kcopyd_client *kc) | ||
592 | { | 586 | { |
593 | mutex_lock(&_client_lock); | 587 | int r = -ENOMEM; |
594 | list_add(&kc->list, &_clients); | 588 | struct dm_kcopyd_client *kc; |
595 | mutex_unlock(&_client_lock); | ||
596 | } | ||
597 | |||
598 | static void client_del(struct kcopyd_client *kc) | ||
599 | { | ||
600 | mutex_lock(&_client_lock); | ||
601 | list_del(&kc->list); | ||
602 | mutex_unlock(&_client_lock); | ||
603 | } | ||
604 | |||
605 | static DEFINE_MUTEX(kcopyd_init_lock); | ||
606 | static int kcopyd_clients = 0; | ||
607 | 589 | ||
608 | static int kcopyd_init(void) | 590 | kc = kmalloc(sizeof(*kc), GFP_KERNEL); |
609 | { | 591 | if (!kc) |
610 | int r; | ||
611 | |||
612 | mutex_lock(&kcopyd_init_lock); | ||
613 | |||
614 | if (kcopyd_clients) { | ||
615 | /* Already initialized. */ | ||
616 | kcopyd_clients++; | ||
617 | mutex_unlock(&kcopyd_init_lock); | ||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | r = jobs_init(); | ||
622 | if (r) { | ||
623 | mutex_unlock(&kcopyd_init_lock); | ||
624 | return r; | ||
625 | } | ||
626 | |||
627 | _kcopyd_wq = create_singlethread_workqueue("kcopyd"); | ||
628 | if (!_kcopyd_wq) { | ||
629 | jobs_exit(); | ||
630 | mutex_unlock(&kcopyd_init_lock); | ||
631 | return -ENOMEM; | 592 | return -ENOMEM; |
632 | } | ||
633 | |||
634 | kcopyd_clients++; | ||
635 | INIT_WORK(&_kcopyd_work, do_work); | ||
636 | mutex_unlock(&kcopyd_init_lock); | ||
637 | return 0; | ||
638 | } | ||
639 | 593 | ||
640 | static void kcopyd_exit(void) | 594 | spin_lock_init(&kc->lock); |
641 | { | 595 | spin_lock_init(&kc->job_lock); |
642 | mutex_lock(&kcopyd_init_lock); | 596 | INIT_LIST_HEAD(&kc->complete_jobs); |
643 | kcopyd_clients--; | 597 | INIT_LIST_HEAD(&kc->io_jobs); |
644 | if (!kcopyd_clients) { | 598 | INIT_LIST_HEAD(&kc->pages_jobs); |
645 | jobs_exit(); | ||
646 | destroy_workqueue(_kcopyd_wq); | ||
647 | _kcopyd_wq = NULL; | ||
648 | } | ||
649 | mutex_unlock(&kcopyd_init_lock); | ||
650 | } | ||
651 | |||
652 | int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result) | ||
653 | { | ||
654 | int r = 0; | ||
655 | struct kcopyd_client *kc; | ||
656 | 599 | ||
657 | r = kcopyd_init(); | 600 | kc->job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache); |
658 | if (r) | 601 | if (!kc->job_pool) |
659 | return r; | 602 | goto bad_slab; |
660 | 603 | ||
661 | kc = kmalloc(sizeof(*kc), GFP_KERNEL); | 604 | INIT_WORK(&kc->kcopyd_work, do_work); |
662 | if (!kc) { | 605 | kc->kcopyd_wq = create_singlethread_workqueue("kcopyd"); |
663 | kcopyd_exit(); | 606 | if (!kc->kcopyd_wq) |
664 | return -ENOMEM; | 607 | goto bad_workqueue; |
665 | } | ||
666 | 608 | ||
667 | spin_lock_init(&kc->lock); | ||
668 | kc->pages = NULL; | 609 | kc->pages = NULL; |
669 | kc->nr_pages = kc->nr_free_pages = 0; | 610 | kc->nr_pages = kc->nr_free_pages = 0; |
670 | r = client_alloc_pages(kc, nr_pages); | 611 | r = client_alloc_pages(kc, nr_pages); |
671 | if (r) { | 612 | if (r) |
672 | kfree(kc); | 613 | goto bad_client_pages; |
673 | kcopyd_exit(); | ||
674 | return r; | ||
675 | } | ||
676 | 614 | ||
677 | kc->io_client = dm_io_client_create(nr_pages); | 615 | kc->io_client = dm_io_client_create(nr_pages); |
678 | if (IS_ERR(kc->io_client)) { | 616 | if (IS_ERR(kc->io_client)) { |
679 | r = PTR_ERR(kc->io_client); | 617 | r = PTR_ERR(kc->io_client); |
680 | client_free_pages(kc); | 618 | goto bad_io_client; |
681 | kfree(kc); | ||
682 | kcopyd_exit(); | ||
683 | return r; | ||
684 | } | 619 | } |
685 | 620 | ||
686 | init_waitqueue_head(&kc->destroyq); | 621 | init_waitqueue_head(&kc->destroyq); |
687 | atomic_set(&kc->nr_jobs, 0); | 622 | atomic_set(&kc->nr_jobs, 0); |
688 | 623 | ||
689 | client_add(kc); | ||
690 | *result = kc; | 624 | *result = kc; |
691 | return 0; | 625 | return 0; |
626 | |||
627 | bad_io_client: | ||
628 | client_free_pages(kc); | ||
629 | bad_client_pages: | ||
630 | destroy_workqueue(kc->kcopyd_wq); | ||
631 | bad_workqueue: | ||
632 | mempool_destroy(kc->job_pool); | ||
633 | bad_slab: | ||
634 | kfree(kc); | ||
635 | |||
636 | return r; | ||
692 | } | 637 | } |
638 | EXPORT_SYMBOL(dm_kcopyd_client_create); | ||
693 | 639 | ||
694 | void kcopyd_client_destroy(struct kcopyd_client *kc) | 640 | void dm_kcopyd_client_destroy(struct dm_kcopyd_client *kc) |
695 | { | 641 | { |
696 | /* Wait for completion of all jobs submitted by this client. */ | 642 | /* Wait for completion of all jobs submitted by this client. */ |
697 | wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs)); | 643 | wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs)); |
698 | 644 | ||
645 | BUG_ON(!list_empty(&kc->complete_jobs)); | ||
646 | BUG_ON(!list_empty(&kc->io_jobs)); | ||
647 | BUG_ON(!list_empty(&kc->pages_jobs)); | ||
648 | destroy_workqueue(kc->kcopyd_wq); | ||
699 | dm_io_client_destroy(kc->io_client); | 649 | dm_io_client_destroy(kc->io_client); |
700 | client_free_pages(kc); | 650 | client_free_pages(kc); |
701 | client_del(kc); | 651 | mempool_destroy(kc->job_pool); |
702 | kfree(kc); | 652 | kfree(kc); |
703 | kcopyd_exit(); | ||
704 | } | 653 | } |
705 | 654 | EXPORT_SYMBOL(dm_kcopyd_client_destroy); | |
706 | EXPORT_SYMBOL(kcopyd_client_create); | ||
707 | EXPORT_SYMBOL(kcopyd_client_destroy); | ||
708 | EXPORT_SYMBOL(kcopyd_copy); | ||
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index 2a74b2142f50..67a6f31b7fc3 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2003 Sistina Software | 2 | * Copyright (C) 2003 Sistina Software |
3 | * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. | ||
3 | * | 4 | * |
4 | * This file is released under the LGPL. | 5 | * This file is released under the LGPL. |
5 | */ | 6 | */ |
@@ -8,64 +9,58 @@ | |||
8 | #include <linux/slab.h> | 9 | #include <linux/slab.h> |
9 | #include <linux/module.h> | 10 | #include <linux/module.h> |
10 | #include <linux/vmalloc.h> | 11 | #include <linux/vmalloc.h> |
12 | #include <linux/dm-io.h> | ||
13 | #include <linux/dm-dirty-log.h> | ||
11 | 14 | ||
12 | #include "dm-log.h" | 15 | #include "dm.h" |
13 | #include "dm-io.h" | ||
14 | 16 | ||
15 | #define DM_MSG_PREFIX "mirror log" | 17 | #define DM_MSG_PREFIX "dirty region log" |
16 | 18 | ||
17 | static LIST_HEAD(_log_types); | 19 | struct dm_dirty_log_internal { |
18 | static DEFINE_SPINLOCK(_lock); | 20 | struct dm_dirty_log_type *type; |
19 | 21 | ||
20 | int dm_register_dirty_log_type(struct dirty_log_type *type) | 22 | struct list_head list; |
21 | { | 23 | long use; |
22 | spin_lock(&_lock); | 24 | }; |
23 | type->use_count = 0; | ||
24 | list_add(&type->list, &_log_types); | ||
25 | spin_unlock(&_lock); | ||
26 | 25 | ||
27 | return 0; | 26 | static LIST_HEAD(_log_types); |
28 | } | 27 | static DEFINE_SPINLOCK(_lock); |
29 | 28 | ||
30 | int dm_unregister_dirty_log_type(struct dirty_log_type *type) | 29 | static struct dm_dirty_log_internal *__find_dirty_log_type(const char *name) |
31 | { | 30 | { |
32 | spin_lock(&_lock); | 31 | struct dm_dirty_log_internal *log_type; |
33 | |||
34 | if (type->use_count) | ||
35 | DMWARN("Attempt to unregister a log type that is still in use"); | ||
36 | else | ||
37 | list_del(&type->list); | ||
38 | 32 | ||
39 | spin_unlock(&_lock); | 33 | list_for_each_entry(log_type, &_log_types, list) |
34 | if (!strcmp(name, log_type->type->name)) | ||
35 | return log_type; | ||
40 | 36 | ||
41 | return 0; | 37 | return NULL; |
42 | } | 38 | } |
43 | 39 | ||
44 | static struct dirty_log_type *_get_type(const char *type_name) | 40 | static struct dm_dirty_log_internal *_get_dirty_log_type(const char *name) |
45 | { | 41 | { |
46 | struct dirty_log_type *type; | 42 | struct dm_dirty_log_internal *log_type; |
47 | 43 | ||
48 | spin_lock(&_lock); | 44 | spin_lock(&_lock); |
49 | list_for_each_entry (type, &_log_types, list) | 45 | |
50 | if (!strcmp(type_name, type->name)) { | 46 | log_type = __find_dirty_log_type(name); |
51 | if (!type->use_count && !try_module_get(type->module)){ | 47 | if (log_type) { |
52 | spin_unlock(&_lock); | 48 | if (!log_type->use && !try_module_get(log_type->type->module)) |
53 | return NULL; | 49 | log_type = NULL; |
54 | } | 50 | else |
55 | type->use_count++; | 51 | log_type->use++; |
56 | spin_unlock(&_lock); | 52 | } |
57 | return type; | ||
58 | } | ||
59 | 53 | ||
60 | spin_unlock(&_lock); | 54 | spin_unlock(&_lock); |
61 | return NULL; | 55 | |
56 | return log_type; | ||
62 | } | 57 | } |
63 | 58 | ||
64 | /* | 59 | /* |
65 | * get_type | 60 | * get_type |
66 | * @type_name | 61 | * @type_name |
67 | * | 62 | * |
68 | * Attempt to retrieve the dirty_log_type by name. If not already | 63 | * Attempt to retrieve the dm_dirty_log_type by name. If not already |
69 | * available, attempt to load the appropriate module. | 64 | * available, attempt to load the appropriate module. |
70 | * | 65 | * |
71 | * Log modules are named "dm-log-" followed by the 'type_name'. | 66 | * Log modules are named "dm-log-" followed by the 'type_name'. |
@@ -78,14 +73,17 @@ static struct dirty_log_type *_get_type(const char *type_name) | |||
78 | * | 73 | * |
79 | * Returns: dirty_log_type* on success, NULL on failure | 74 | * Returns: dirty_log_type* on success, NULL on failure |
80 | */ | 75 | */ |
81 | static struct dirty_log_type *get_type(const char *type_name) | 76 | static struct dm_dirty_log_type *get_type(const char *type_name) |
82 | { | 77 | { |
83 | char *p, *type_name_dup; | 78 | char *p, *type_name_dup; |
84 | struct dirty_log_type *type; | 79 | struct dm_dirty_log_internal *log_type; |
80 | |||
81 | if (!type_name) | ||
82 | return NULL; | ||
85 | 83 | ||
86 | type = _get_type(type_name); | 84 | log_type = _get_dirty_log_type(type_name); |
87 | if (type) | 85 | if (log_type) |
88 | return type; | 86 | return log_type->type; |
89 | 87 | ||
90 | type_name_dup = kstrdup(type_name, GFP_KERNEL); | 88 | type_name_dup = kstrdup(type_name, GFP_KERNEL); |
91 | if (!type_name_dup) { | 89 | if (!type_name_dup) { |
@@ -95,34 +93,106 @@ static struct dirty_log_type *get_type(const char *type_name) | |||
95 | } | 93 | } |
96 | 94 | ||
97 | while (request_module("dm-log-%s", type_name_dup) || | 95 | while (request_module("dm-log-%s", type_name_dup) || |
98 | !(type = _get_type(type_name))) { | 96 | !(log_type = _get_dirty_log_type(type_name))) { |
99 | p = strrchr(type_name_dup, '-'); | 97 | p = strrchr(type_name_dup, '-'); |
100 | if (!p) | 98 | if (!p) |
101 | break; | 99 | break; |
102 | p[0] = '\0'; | 100 | p[0] = '\0'; |
103 | } | 101 | } |
104 | 102 | ||
105 | if (!type) | 103 | if (!log_type) |
106 | DMWARN("Module for logging type \"%s\" not found.", type_name); | 104 | DMWARN("Module for logging type \"%s\" not found.", type_name); |
107 | 105 | ||
108 | kfree(type_name_dup); | 106 | kfree(type_name_dup); |
109 | 107 | ||
110 | return type; | 108 | return log_type ? log_type->type : NULL; |
111 | } | 109 | } |
112 | 110 | ||
113 | static void put_type(struct dirty_log_type *type) | 111 | static void put_type(struct dm_dirty_log_type *type) |
114 | { | 112 | { |
113 | struct dm_dirty_log_internal *log_type; | ||
114 | |||
115 | if (!type) | ||
116 | return; | ||
117 | |||
115 | spin_lock(&_lock); | 118 | spin_lock(&_lock); |
116 | if (!--type->use_count) | 119 | log_type = __find_dirty_log_type(type->name); |
120 | if (!log_type) | ||
121 | goto out; | ||
122 | |||
123 | if (!--log_type->use) | ||
117 | module_put(type->module); | 124 | module_put(type->module); |
125 | |||
126 | BUG_ON(log_type->use < 0); | ||
127 | |||
128 | out: | ||
118 | spin_unlock(&_lock); | 129 | spin_unlock(&_lock); |
119 | } | 130 | } |
120 | 131 | ||
121 | struct dirty_log *dm_create_dirty_log(const char *type_name, struct dm_target *ti, | 132 | static struct dm_dirty_log_internal *_alloc_dirty_log_type(struct dm_dirty_log_type *type) |
122 | unsigned int argc, char **argv) | ||
123 | { | 133 | { |
124 | struct dirty_log_type *type; | 134 | struct dm_dirty_log_internal *log_type = kzalloc(sizeof(*log_type), |
125 | struct dirty_log *log; | 135 | GFP_KERNEL); |
136 | |||
137 | if (log_type) | ||
138 | log_type->type = type; | ||
139 | |||
140 | return log_type; | ||
141 | } | ||
142 | |||
143 | int dm_dirty_log_type_register(struct dm_dirty_log_type *type) | ||
144 | { | ||
145 | struct dm_dirty_log_internal *log_type = _alloc_dirty_log_type(type); | ||
146 | int r = 0; | ||
147 | |||
148 | if (!log_type) | ||
149 | return -ENOMEM; | ||
150 | |||
151 | spin_lock(&_lock); | ||
152 | if (!__find_dirty_log_type(type->name)) | ||
153 | list_add(&log_type->list, &_log_types); | ||
154 | else { | ||
155 | kfree(log_type); | ||
156 | r = -EEXIST; | ||
157 | } | ||
158 | spin_unlock(&_lock); | ||
159 | |||
160 | return r; | ||
161 | } | ||
162 | EXPORT_SYMBOL(dm_dirty_log_type_register); | ||
163 | |||
164 | int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type) | ||
165 | { | ||
166 | struct dm_dirty_log_internal *log_type; | ||
167 | |||
168 | spin_lock(&_lock); | ||
169 | |||
170 | log_type = __find_dirty_log_type(type->name); | ||
171 | if (!log_type) { | ||
172 | spin_unlock(&_lock); | ||
173 | return -EINVAL; | ||
174 | } | ||
175 | |||
176 | if (log_type->use) { | ||
177 | spin_unlock(&_lock); | ||
178 | return -ETXTBSY; | ||
179 | } | ||
180 | |||
181 | list_del(&log_type->list); | ||
182 | |||
183 | spin_unlock(&_lock); | ||
184 | kfree(log_type); | ||
185 | |||
186 | return 0; | ||
187 | } | ||
188 | EXPORT_SYMBOL(dm_dirty_log_type_unregister); | ||
189 | |||
190 | struct dm_dirty_log *dm_dirty_log_create(const char *type_name, | ||
191 | struct dm_target *ti, | ||
192 | unsigned int argc, char **argv) | ||
193 | { | ||
194 | struct dm_dirty_log_type *type; | ||
195 | struct dm_dirty_log *log; | ||
126 | 196 | ||
127 | log = kmalloc(sizeof(*log), GFP_KERNEL); | 197 | log = kmalloc(sizeof(*log), GFP_KERNEL); |
128 | if (!log) | 198 | if (!log) |
@@ -143,13 +213,15 @@ struct dirty_log *dm_create_dirty_log(const char *type_name, struct dm_target *t | |||
143 | 213 | ||
144 | return log; | 214 | return log; |
145 | } | 215 | } |
216 | EXPORT_SYMBOL(dm_dirty_log_create); | ||
146 | 217 | ||
147 | void dm_destroy_dirty_log(struct dirty_log *log) | 218 | void dm_dirty_log_destroy(struct dm_dirty_log *log) |
148 | { | 219 | { |
149 | log->type->dtr(log); | 220 | log->type->dtr(log); |
150 | put_type(log->type); | 221 | put_type(log->type); |
151 | kfree(log); | 222 | kfree(log); |
152 | } | 223 | } |
224 | EXPORT_SYMBOL(dm_dirty_log_destroy); | ||
153 | 225 | ||
154 | /*----------------------------------------------------------------- | 226 | /*----------------------------------------------------------------- |
155 | * Persistent and core logs share a lot of their implementation. | 227 | * Persistent and core logs share a lot of their implementation. |
@@ -207,7 +279,7 @@ struct log_c { | |||
207 | struct dm_dev *log_dev; | 279 | struct dm_dev *log_dev; |
208 | struct log_header header; | 280 | struct log_header header; |
209 | 281 | ||
210 | struct io_region header_location; | 282 | struct dm_io_region header_location; |
211 | struct log_header *disk_header; | 283 | struct log_header *disk_header; |
212 | }; | 284 | }; |
213 | 285 | ||
@@ -215,7 +287,7 @@ struct log_c { | |||
215 | * The touched member needs to be updated every time we access | 287 | * The touched member needs to be updated every time we access |
216 | * one of the bitsets. | 288 | * one of the bitsets. |
217 | */ | 289 | */ |
218 | static inline int log_test_bit(uint32_t *bs, unsigned bit) | 290 | static inline int log_test_bit(uint32_t *bs, unsigned bit) |
219 | { | 291 | { |
220 | return ext2_test_bit(bit, (unsigned long *) bs) ? 1 : 0; | 292 | return ext2_test_bit(bit, (unsigned long *) bs) ? 1 : 0; |
221 | } | 293 | } |
@@ -302,7 +374,7 @@ static inline int write_header(struct log_c *log) | |||
302 | * argv contains region_size followed optionally by [no]sync | 374 | * argv contains region_size followed optionally by [no]sync |
303 | *--------------------------------------------------------------*/ | 375 | *--------------------------------------------------------------*/ |
304 | #define BYTE_SHIFT 3 | 376 | #define BYTE_SHIFT 3 |
305 | static int create_log_context(struct dirty_log *log, struct dm_target *ti, | 377 | static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti, |
306 | unsigned int argc, char **argv, | 378 | unsigned int argc, char **argv, |
307 | struct dm_dev *dev) | 379 | struct dm_dev *dev) |
308 | { | 380 | { |
@@ -315,7 +387,7 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti, | |||
315 | int r; | 387 | int r; |
316 | 388 | ||
317 | if (argc < 1 || argc > 2) { | 389 | if (argc < 1 || argc > 2) { |
318 | DMWARN("wrong number of arguments to mirror log"); | 390 | DMWARN("wrong number of arguments to dirty region log"); |
319 | return -EINVAL; | 391 | return -EINVAL; |
320 | } | 392 | } |
321 | 393 | ||
@@ -325,8 +397,8 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti, | |||
325 | else if (!strcmp(argv[1], "nosync")) | 397 | else if (!strcmp(argv[1], "nosync")) |
326 | sync = NOSYNC; | 398 | sync = NOSYNC; |
327 | else { | 399 | else { |
328 | DMWARN("unrecognised sync argument to mirror log: %s", | 400 | DMWARN("unrecognised sync argument to " |
329 | argv[1]); | 401 | "dirty region log: %s", argv[1]); |
330 | return -EINVAL; | 402 | return -EINVAL; |
331 | } | 403 | } |
332 | } | 404 | } |
@@ -434,7 +506,7 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti, | |||
434 | return 0; | 506 | return 0; |
435 | } | 507 | } |
436 | 508 | ||
437 | static int core_ctr(struct dirty_log *log, struct dm_target *ti, | 509 | static int core_ctr(struct dm_dirty_log *log, struct dm_target *ti, |
438 | unsigned int argc, char **argv) | 510 | unsigned int argc, char **argv) |
439 | { | 511 | { |
440 | return create_log_context(log, ti, argc, argv, NULL); | 512 | return create_log_context(log, ti, argc, argv, NULL); |
@@ -447,7 +519,7 @@ static void destroy_log_context(struct log_c *lc) | |||
447 | kfree(lc); | 519 | kfree(lc); |
448 | } | 520 | } |
449 | 521 | ||
450 | static void core_dtr(struct dirty_log *log) | 522 | static void core_dtr(struct dm_dirty_log *log) |
451 | { | 523 | { |
452 | struct log_c *lc = (struct log_c *) log->context; | 524 | struct log_c *lc = (struct log_c *) log->context; |
453 | 525 | ||
@@ -460,14 +532,14 @@ static void core_dtr(struct dirty_log *log) | |||
460 | * | 532 | * |
461 | * argv contains log_device region_size followed optionally by [no]sync | 533 | * argv contains log_device region_size followed optionally by [no]sync |
462 | *--------------------------------------------------------------*/ | 534 | *--------------------------------------------------------------*/ |
463 | static int disk_ctr(struct dirty_log *log, struct dm_target *ti, | 535 | static int disk_ctr(struct dm_dirty_log *log, struct dm_target *ti, |
464 | unsigned int argc, char **argv) | 536 | unsigned int argc, char **argv) |
465 | { | 537 | { |
466 | int r; | 538 | int r; |
467 | struct dm_dev *dev; | 539 | struct dm_dev *dev; |
468 | 540 | ||
469 | if (argc < 2 || argc > 3) { | 541 | if (argc < 2 || argc > 3) { |
470 | DMWARN("wrong number of arguments to disk mirror log"); | 542 | DMWARN("wrong number of arguments to disk dirty region log"); |
471 | return -EINVAL; | 543 | return -EINVAL; |
472 | } | 544 | } |
473 | 545 | ||
@@ -485,7 +557,7 @@ static int disk_ctr(struct dirty_log *log, struct dm_target *ti, | |||
485 | return 0; | 557 | return 0; |
486 | } | 558 | } |
487 | 559 | ||
488 | static void disk_dtr(struct dirty_log *log) | 560 | static void disk_dtr(struct dm_dirty_log *log) |
489 | { | 561 | { |
490 | struct log_c *lc = (struct log_c *) log->context; | 562 | struct log_c *lc = (struct log_c *) log->context; |
491 | 563 | ||
@@ -514,7 +586,7 @@ static void fail_log_device(struct log_c *lc) | |||
514 | dm_table_event(lc->ti->table); | 586 | dm_table_event(lc->ti->table); |
515 | } | 587 | } |
516 | 588 | ||
517 | static int disk_resume(struct dirty_log *log) | 589 | static int disk_resume(struct dm_dirty_log *log) |
518 | { | 590 | { |
519 | int r; | 591 | int r; |
520 | unsigned i; | 592 | unsigned i; |
@@ -524,7 +596,7 @@ static int disk_resume(struct dirty_log *log) | |||
524 | /* read the disk header */ | 596 | /* read the disk header */ |
525 | r = read_header(lc); | 597 | r = read_header(lc); |
526 | if (r) { | 598 | if (r) { |
527 | DMWARN("%s: Failed to read header on mirror log device", | 599 | DMWARN("%s: Failed to read header on dirty region log device", |
528 | lc->log_dev->name); | 600 | lc->log_dev->name); |
529 | fail_log_device(lc); | 601 | fail_log_device(lc); |
530 | /* | 602 | /* |
@@ -562,7 +634,7 @@ static int disk_resume(struct dirty_log *log) | |||
562 | /* write the new header */ | 634 | /* write the new header */ |
563 | r = write_header(lc); | 635 | r = write_header(lc); |
564 | if (r) { | 636 | if (r) { |
565 | DMWARN("%s: Failed to write header on mirror log device", | 637 | DMWARN("%s: Failed to write header on dirty region log device", |
566 | lc->log_dev->name); | 638 | lc->log_dev->name); |
567 | fail_log_device(lc); | 639 | fail_log_device(lc); |
568 | } | 640 | } |
@@ -570,38 +642,38 @@ static int disk_resume(struct dirty_log *log) | |||
570 | return r; | 642 | return r; |
571 | } | 643 | } |
572 | 644 | ||
573 | static uint32_t core_get_region_size(struct dirty_log *log) | 645 | static uint32_t core_get_region_size(struct dm_dirty_log *log) |
574 | { | 646 | { |
575 | struct log_c *lc = (struct log_c *) log->context; | 647 | struct log_c *lc = (struct log_c *) log->context; |
576 | return lc->region_size; | 648 | return lc->region_size; |
577 | } | 649 | } |
578 | 650 | ||
579 | static int core_resume(struct dirty_log *log) | 651 | static int core_resume(struct dm_dirty_log *log) |
580 | { | 652 | { |
581 | struct log_c *lc = (struct log_c *) log->context; | 653 | struct log_c *lc = (struct log_c *) log->context; |
582 | lc->sync_search = 0; | 654 | lc->sync_search = 0; |
583 | return 0; | 655 | return 0; |
584 | } | 656 | } |
585 | 657 | ||
586 | static int core_is_clean(struct dirty_log *log, region_t region) | 658 | static int core_is_clean(struct dm_dirty_log *log, region_t region) |
587 | { | 659 | { |
588 | struct log_c *lc = (struct log_c *) log->context; | 660 | struct log_c *lc = (struct log_c *) log->context; |
589 | return log_test_bit(lc->clean_bits, region); | 661 | return log_test_bit(lc->clean_bits, region); |
590 | } | 662 | } |
591 | 663 | ||
592 | static int core_in_sync(struct dirty_log *log, region_t region, int block) | 664 | static int core_in_sync(struct dm_dirty_log *log, region_t region, int block) |
593 | { | 665 | { |
594 | struct log_c *lc = (struct log_c *) log->context; | 666 | struct log_c *lc = (struct log_c *) log->context; |
595 | return log_test_bit(lc->sync_bits, region); | 667 | return log_test_bit(lc->sync_bits, region); |
596 | } | 668 | } |
597 | 669 | ||
598 | static int core_flush(struct dirty_log *log) | 670 | static int core_flush(struct dm_dirty_log *log) |
599 | { | 671 | { |
600 | /* no op */ | 672 | /* no op */ |
601 | return 0; | 673 | return 0; |
602 | } | 674 | } |
603 | 675 | ||
604 | static int disk_flush(struct dirty_log *log) | 676 | static int disk_flush(struct dm_dirty_log *log) |
605 | { | 677 | { |
606 | int r; | 678 | int r; |
607 | struct log_c *lc = (struct log_c *) log->context; | 679 | struct log_c *lc = (struct log_c *) log->context; |
@@ -619,19 +691,19 @@ static int disk_flush(struct dirty_log *log) | |||
619 | return r; | 691 | return r; |
620 | } | 692 | } |
621 | 693 | ||
622 | static void core_mark_region(struct dirty_log *log, region_t region) | 694 | static void core_mark_region(struct dm_dirty_log *log, region_t region) |
623 | { | 695 | { |
624 | struct log_c *lc = (struct log_c *) log->context; | 696 | struct log_c *lc = (struct log_c *) log->context; |
625 | log_clear_bit(lc, lc->clean_bits, region); | 697 | log_clear_bit(lc, lc->clean_bits, region); |
626 | } | 698 | } |
627 | 699 | ||
628 | static void core_clear_region(struct dirty_log *log, region_t region) | 700 | static void core_clear_region(struct dm_dirty_log *log, region_t region) |
629 | { | 701 | { |
630 | struct log_c *lc = (struct log_c *) log->context; | 702 | struct log_c *lc = (struct log_c *) log->context; |
631 | log_set_bit(lc, lc->clean_bits, region); | 703 | log_set_bit(lc, lc->clean_bits, region); |
632 | } | 704 | } |
633 | 705 | ||
634 | static int core_get_resync_work(struct dirty_log *log, region_t *region) | 706 | static int core_get_resync_work(struct dm_dirty_log *log, region_t *region) |
635 | { | 707 | { |
636 | struct log_c *lc = (struct log_c *) log->context; | 708 | struct log_c *lc = (struct log_c *) log->context; |
637 | 709 | ||
@@ -654,7 +726,7 @@ static int core_get_resync_work(struct dirty_log *log, region_t *region) | |||
654 | return 1; | 726 | return 1; |
655 | } | 727 | } |
656 | 728 | ||
657 | static void core_set_region_sync(struct dirty_log *log, region_t region, | 729 | static void core_set_region_sync(struct dm_dirty_log *log, region_t region, |
658 | int in_sync) | 730 | int in_sync) |
659 | { | 731 | { |
660 | struct log_c *lc = (struct log_c *) log->context; | 732 | struct log_c *lc = (struct log_c *) log->context; |
@@ -669,7 +741,7 @@ static void core_set_region_sync(struct dirty_log *log, region_t region, | |||
669 | } | 741 | } |
670 | } | 742 | } |
671 | 743 | ||
672 | static region_t core_get_sync_count(struct dirty_log *log) | 744 | static region_t core_get_sync_count(struct dm_dirty_log *log) |
673 | { | 745 | { |
674 | struct log_c *lc = (struct log_c *) log->context; | 746 | struct log_c *lc = (struct log_c *) log->context; |
675 | 747 | ||
@@ -680,7 +752,7 @@ static region_t core_get_sync_count(struct dirty_log *log) | |||
680 | if (lc->sync != DEFAULTSYNC) \ | 752 | if (lc->sync != DEFAULTSYNC) \ |
681 | DMEMIT("%ssync ", lc->sync == NOSYNC ? "no" : "") | 753 | DMEMIT("%ssync ", lc->sync == NOSYNC ? "no" : "") |
682 | 754 | ||
683 | static int core_status(struct dirty_log *log, status_type_t status, | 755 | static int core_status(struct dm_dirty_log *log, status_type_t status, |
684 | char *result, unsigned int maxlen) | 756 | char *result, unsigned int maxlen) |
685 | { | 757 | { |
686 | int sz = 0; | 758 | int sz = 0; |
@@ -700,7 +772,7 @@ static int core_status(struct dirty_log *log, status_type_t status, | |||
700 | return sz; | 772 | return sz; |
701 | } | 773 | } |
702 | 774 | ||
703 | static int disk_status(struct dirty_log *log, status_type_t status, | 775 | static int disk_status(struct dm_dirty_log *log, status_type_t status, |
704 | char *result, unsigned int maxlen) | 776 | char *result, unsigned int maxlen) |
705 | { | 777 | { |
706 | int sz = 0; | 778 | int sz = 0; |
@@ -722,7 +794,7 @@ static int disk_status(struct dirty_log *log, status_type_t status, | |||
722 | return sz; | 794 | return sz; |
723 | } | 795 | } |
724 | 796 | ||
725 | static struct dirty_log_type _core_type = { | 797 | static struct dm_dirty_log_type _core_type = { |
726 | .name = "core", | 798 | .name = "core", |
727 | .module = THIS_MODULE, | 799 | .module = THIS_MODULE, |
728 | .ctr = core_ctr, | 800 | .ctr = core_ctr, |
@@ -740,7 +812,7 @@ static struct dirty_log_type _core_type = { | |||
740 | .status = core_status, | 812 | .status = core_status, |
741 | }; | 813 | }; |
742 | 814 | ||
743 | static struct dirty_log_type _disk_type = { | 815 | static struct dm_dirty_log_type _disk_type = { |
744 | .name = "disk", | 816 | .name = "disk", |
745 | .module = THIS_MODULE, | 817 | .module = THIS_MODULE, |
746 | .ctr = disk_ctr, | 818 | .ctr = disk_ctr, |
@@ -763,26 +835,28 @@ int __init dm_dirty_log_init(void) | |||
763 | { | 835 | { |
764 | int r; | 836 | int r; |
765 | 837 | ||
766 | r = dm_register_dirty_log_type(&_core_type); | 838 | r = dm_dirty_log_type_register(&_core_type); |
767 | if (r) | 839 | if (r) |
768 | DMWARN("couldn't register core log"); | 840 | DMWARN("couldn't register core log"); |
769 | 841 | ||
770 | r = dm_register_dirty_log_type(&_disk_type); | 842 | r = dm_dirty_log_type_register(&_disk_type); |
771 | if (r) { | 843 | if (r) { |
772 | DMWARN("couldn't register disk type"); | 844 | DMWARN("couldn't register disk type"); |
773 | dm_unregister_dirty_log_type(&_core_type); | 845 | dm_dirty_log_type_unregister(&_core_type); |
774 | } | 846 | } |
775 | 847 | ||
776 | return r; | 848 | return r; |
777 | } | 849 | } |
778 | 850 | ||
779 | void dm_dirty_log_exit(void) | 851 | void __exit dm_dirty_log_exit(void) |
780 | { | 852 | { |
781 | dm_unregister_dirty_log_type(&_disk_type); | 853 | dm_dirty_log_type_unregister(&_disk_type); |
782 | dm_unregister_dirty_log_type(&_core_type); | 854 | dm_dirty_log_type_unregister(&_core_type); |
783 | } | 855 | } |
784 | 856 | ||
785 | EXPORT_SYMBOL(dm_register_dirty_log_type); | 857 | module_init(dm_dirty_log_init); |
786 | EXPORT_SYMBOL(dm_unregister_dirty_log_type); | 858 | module_exit(dm_dirty_log_exit); |
787 | EXPORT_SYMBOL(dm_create_dirty_log); | 859 | |
788 | EXPORT_SYMBOL(dm_destroy_dirty_log); | 860 | MODULE_DESCRIPTION(DM_NAME " dirty region log"); |
861 | MODULE_AUTHOR("Joe Thornber, Heinz Mauelshagen <dm-devel@redhat.com>"); | ||
862 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 762cb086bb7f..ff05fe893083 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c | |||
@@ -7,9 +7,6 @@ | |||
7 | #include "dm.h" | 7 | #include "dm.h" |
8 | #include "dm-bio-list.h" | 8 | #include "dm-bio-list.h" |
9 | #include "dm-bio-record.h" | 9 | #include "dm-bio-record.h" |
10 | #include "dm-io.h" | ||
11 | #include "dm-log.h" | ||
12 | #include "kcopyd.h" | ||
13 | 10 | ||
14 | #include <linux/ctype.h> | 11 | #include <linux/ctype.h> |
15 | #include <linux/init.h> | 12 | #include <linux/init.h> |
@@ -22,6 +19,9 @@ | |||
22 | #include <linux/workqueue.h> | 19 | #include <linux/workqueue.h> |
23 | #include <linux/log2.h> | 20 | #include <linux/log2.h> |
24 | #include <linux/hardirq.h> | 21 | #include <linux/hardirq.h> |
22 | #include <linux/dm-io.h> | ||
23 | #include <linux/dm-dirty-log.h> | ||
24 | #include <linux/dm-kcopyd.h> | ||
25 | 25 | ||
26 | #define DM_MSG_PREFIX "raid1" | 26 | #define DM_MSG_PREFIX "raid1" |
27 | #define DM_IO_PAGES 64 | 27 | #define DM_IO_PAGES 64 |
@@ -74,7 +74,7 @@ struct region_hash { | |||
74 | unsigned region_shift; | 74 | unsigned region_shift; |
75 | 75 | ||
76 | /* holds persistent region state */ | 76 | /* holds persistent region state */ |
77 | struct dirty_log *log; | 77 | struct dm_dirty_log *log; |
78 | 78 | ||
79 | /* hash table */ | 79 | /* hash table */ |
80 | rwlock_t hash_lock; | 80 | rwlock_t hash_lock; |
@@ -133,7 +133,7 @@ struct mirror_set { | |||
133 | struct dm_target *ti; | 133 | struct dm_target *ti; |
134 | struct list_head list; | 134 | struct list_head list; |
135 | struct region_hash rh; | 135 | struct region_hash rh; |
136 | struct kcopyd_client *kcopyd_client; | 136 | struct dm_kcopyd_client *kcopyd_client; |
137 | uint64_t features; | 137 | uint64_t features; |
138 | 138 | ||
139 | spinlock_t lock; /* protects the lists */ | 139 | spinlock_t lock; /* protects the lists */ |
@@ -154,6 +154,9 @@ struct mirror_set { | |||
154 | 154 | ||
155 | struct workqueue_struct *kmirrord_wq; | 155 | struct workqueue_struct *kmirrord_wq; |
156 | struct work_struct kmirrord_work; | 156 | struct work_struct kmirrord_work; |
157 | struct timer_list timer; | ||
158 | unsigned long timer_pending; | ||
159 | |||
157 | struct work_struct trigger_event; | 160 | struct work_struct trigger_event; |
158 | 161 | ||
159 | unsigned int nr_mirrors; | 162 | unsigned int nr_mirrors; |
@@ -178,13 +181,32 @@ static void wake(struct mirror_set *ms) | |||
178 | queue_work(ms->kmirrord_wq, &ms->kmirrord_work); | 181 | queue_work(ms->kmirrord_wq, &ms->kmirrord_work); |
179 | } | 182 | } |
180 | 183 | ||
184 | static void delayed_wake_fn(unsigned long data) | ||
185 | { | ||
186 | struct mirror_set *ms = (struct mirror_set *) data; | ||
187 | |||
188 | clear_bit(0, &ms->timer_pending); | ||
189 | wake(ms); | ||
190 | } | ||
191 | |||
192 | static void delayed_wake(struct mirror_set *ms) | ||
193 | { | ||
194 | if (test_and_set_bit(0, &ms->timer_pending)) | ||
195 | return; | ||
196 | |||
197 | ms->timer.expires = jiffies + HZ / 5; | ||
198 | ms->timer.data = (unsigned long) ms; | ||
199 | ms->timer.function = delayed_wake_fn; | ||
200 | add_timer(&ms->timer); | ||
201 | } | ||
202 | |||
181 | /* FIXME move this */ | 203 | /* FIXME move this */ |
182 | static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw); | 204 | static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw); |
183 | 205 | ||
184 | #define MIN_REGIONS 64 | 206 | #define MIN_REGIONS 64 |
185 | #define MAX_RECOVERY 1 | 207 | #define MAX_RECOVERY 1 |
186 | static int rh_init(struct region_hash *rh, struct mirror_set *ms, | 208 | static int rh_init(struct region_hash *rh, struct mirror_set *ms, |
187 | struct dirty_log *log, uint32_t region_size, | 209 | struct dm_dirty_log *log, uint32_t region_size, |
188 | region_t nr_regions) | 210 | region_t nr_regions) |
189 | { | 211 | { |
190 | unsigned int nr_buckets, max_buckets; | 212 | unsigned int nr_buckets, max_buckets; |
@@ -249,7 +271,7 @@ static void rh_exit(struct region_hash *rh) | |||
249 | } | 271 | } |
250 | 272 | ||
251 | if (rh->log) | 273 | if (rh->log) |
252 | dm_destroy_dirty_log(rh->log); | 274 | dm_dirty_log_destroy(rh->log); |
253 | if (rh->region_pool) | 275 | if (rh->region_pool) |
254 | mempool_destroy(rh->region_pool); | 276 | mempool_destroy(rh->region_pool); |
255 | vfree(rh->buckets); | 277 | vfree(rh->buckets); |
@@ -405,24 +427,22 @@ static void rh_update_states(struct region_hash *rh) | |||
405 | write_lock_irq(&rh->hash_lock); | 427 | write_lock_irq(&rh->hash_lock); |
406 | spin_lock(&rh->region_lock); | 428 | spin_lock(&rh->region_lock); |
407 | if (!list_empty(&rh->clean_regions)) { | 429 | if (!list_empty(&rh->clean_regions)) { |
408 | list_splice(&rh->clean_regions, &clean); | 430 | list_splice_init(&rh->clean_regions, &clean); |
409 | INIT_LIST_HEAD(&rh->clean_regions); | ||
410 | 431 | ||
411 | list_for_each_entry(reg, &clean, list) | 432 | list_for_each_entry(reg, &clean, list) |
412 | list_del(®->hash_list); | 433 | list_del(®->hash_list); |
413 | } | 434 | } |
414 | 435 | ||
415 | if (!list_empty(&rh->recovered_regions)) { | 436 | if (!list_empty(&rh->recovered_regions)) { |
416 | list_splice(&rh->recovered_regions, &recovered); | 437 | list_splice_init(&rh->recovered_regions, &recovered); |
417 | INIT_LIST_HEAD(&rh->recovered_regions); | ||
418 | 438 | ||
419 | list_for_each_entry (reg, &recovered, list) | 439 | list_for_each_entry (reg, &recovered, list) |
420 | list_del(®->hash_list); | 440 | list_del(®->hash_list); |
421 | } | 441 | } |
422 | 442 | ||
423 | if (!list_empty(&rh->failed_recovered_regions)) { | 443 | if (!list_empty(&rh->failed_recovered_regions)) { |
424 | list_splice(&rh->failed_recovered_regions, &failed_recovered); | 444 | list_splice_init(&rh->failed_recovered_regions, |
425 | INIT_LIST_HEAD(&rh->failed_recovered_regions); | 445 | &failed_recovered); |
426 | 446 | ||
427 | list_for_each_entry(reg, &failed_recovered, list) | 447 | list_for_each_entry(reg, &failed_recovered, list) |
428 | list_del(®->hash_list); | 448 | list_del(®->hash_list); |
@@ -790,7 +810,7 @@ static int recover(struct mirror_set *ms, struct region *reg) | |||
790 | { | 810 | { |
791 | int r; | 811 | int r; |
792 | unsigned int i; | 812 | unsigned int i; |
793 | struct io_region from, to[KCOPYD_MAX_REGIONS], *dest; | 813 | struct dm_io_region from, to[DM_KCOPYD_MAX_REGIONS], *dest; |
794 | struct mirror *m; | 814 | struct mirror *m; |
795 | unsigned long flags = 0; | 815 | unsigned long flags = 0; |
796 | 816 | ||
@@ -822,9 +842,9 @@ static int recover(struct mirror_set *ms, struct region *reg) | |||
822 | } | 842 | } |
823 | 843 | ||
824 | /* hand to kcopyd */ | 844 | /* hand to kcopyd */ |
825 | set_bit(KCOPYD_IGNORE_ERROR, &flags); | 845 | set_bit(DM_KCOPYD_IGNORE_ERROR, &flags); |
826 | r = kcopyd_copy(ms->kcopyd_client, &from, ms->nr_mirrors - 1, to, flags, | 846 | r = dm_kcopyd_copy(ms->kcopyd_client, &from, ms->nr_mirrors - 1, to, |
827 | recovery_complete, reg); | 847 | flags, recovery_complete, reg); |
828 | 848 | ||
829 | return r; | 849 | return r; |
830 | } | 850 | } |
@@ -833,7 +853,7 @@ static void do_recovery(struct mirror_set *ms) | |||
833 | { | 853 | { |
834 | int r; | 854 | int r; |
835 | struct region *reg; | 855 | struct region *reg; |
836 | struct dirty_log *log = ms->rh.log; | 856 | struct dm_dirty_log *log = ms->rh.log; |
837 | 857 | ||
838 | /* | 858 | /* |
839 | * Start quiescing some regions. | 859 | * Start quiescing some regions. |
@@ -909,7 +929,7 @@ static void map_bio(struct mirror *m, struct bio *bio) | |||
909 | bio->bi_sector = map_sector(m, bio); | 929 | bio->bi_sector = map_sector(m, bio); |
910 | } | 930 | } |
911 | 931 | ||
912 | static void map_region(struct io_region *io, struct mirror *m, | 932 | static void map_region(struct dm_io_region *io, struct mirror *m, |
913 | struct bio *bio) | 933 | struct bio *bio) |
914 | { | 934 | { |
915 | io->bdev = m->dev->bdev; | 935 | io->bdev = m->dev->bdev; |
@@ -951,7 +971,7 @@ static void read_callback(unsigned long error, void *context) | |||
951 | /* Asynchronous read. */ | 971 | /* Asynchronous read. */ |
952 | static void read_async_bio(struct mirror *m, struct bio *bio) | 972 | static void read_async_bio(struct mirror *m, struct bio *bio) |
953 | { | 973 | { |
954 | struct io_region io; | 974 | struct dm_io_region io; |
955 | struct dm_io_request io_req = { | 975 | struct dm_io_request io_req = { |
956 | .bi_rw = READ, | 976 | .bi_rw = READ, |
957 | .mem.type = DM_IO_BVEC, | 977 | .mem.type = DM_IO_BVEC, |
@@ -1019,7 +1039,7 @@ static void __bio_mark_nosync(struct mirror_set *ms, | |||
1019 | { | 1039 | { |
1020 | unsigned long flags; | 1040 | unsigned long flags; |
1021 | struct region_hash *rh = &ms->rh; | 1041 | struct region_hash *rh = &ms->rh; |
1022 | struct dirty_log *log = ms->rh.log; | 1042 | struct dm_dirty_log *log = ms->rh.log; |
1023 | struct region *reg; | 1043 | struct region *reg; |
1024 | region_t region = bio_to_region(rh, bio); | 1044 | region_t region = bio_to_region(rh, bio); |
1025 | int recovering = 0; | 1045 | int recovering = 0; |
@@ -1107,7 +1127,7 @@ out: | |||
1107 | static void do_write(struct mirror_set *ms, struct bio *bio) | 1127 | static void do_write(struct mirror_set *ms, struct bio *bio) |
1108 | { | 1128 | { |
1109 | unsigned int i; | 1129 | unsigned int i; |
1110 | struct io_region io[ms->nr_mirrors], *dest = io; | 1130 | struct dm_io_region io[ms->nr_mirrors], *dest = io; |
1111 | struct mirror *m; | 1131 | struct mirror *m; |
1112 | struct dm_io_request io_req = { | 1132 | struct dm_io_request io_req = { |
1113 | .bi_rw = WRITE, | 1133 | .bi_rw = WRITE, |
@@ -1182,6 +1202,7 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) | |||
1182 | spin_lock_irq(&ms->lock); | 1202 | spin_lock_irq(&ms->lock); |
1183 | bio_list_merge(&ms->failures, &sync); | 1203 | bio_list_merge(&ms->failures, &sync); |
1184 | spin_unlock_irq(&ms->lock); | 1204 | spin_unlock_irq(&ms->lock); |
1205 | wake(ms); | ||
1185 | } else | 1206 | } else |
1186 | while ((bio = bio_list_pop(&sync))) | 1207 | while ((bio = bio_list_pop(&sync))) |
1187 | do_write(ms, bio); | 1208 | do_write(ms, bio); |
@@ -1241,7 +1262,7 @@ static void do_failures(struct mirror_set *ms, struct bio_list *failures) | |||
1241 | bio_list_merge(&ms->failures, failures); | 1262 | bio_list_merge(&ms->failures, failures); |
1242 | spin_unlock_irq(&ms->lock); | 1263 | spin_unlock_irq(&ms->lock); |
1243 | 1264 | ||
1244 | wake(ms); | 1265 | delayed_wake(ms); |
1245 | } | 1266 | } |
1246 | 1267 | ||
1247 | static void trigger_event(struct work_struct *work) | 1268 | static void trigger_event(struct work_struct *work) |
@@ -1255,7 +1276,7 @@ static void trigger_event(struct work_struct *work) | |||
1255 | /*----------------------------------------------------------------- | 1276 | /*----------------------------------------------------------------- |
1256 | * kmirrord | 1277 | * kmirrord |
1257 | *---------------------------------------------------------------*/ | 1278 | *---------------------------------------------------------------*/ |
1258 | static int _do_mirror(struct work_struct *work) | 1279 | static void do_mirror(struct work_struct *work) |
1259 | { | 1280 | { |
1260 | struct mirror_set *ms =container_of(work, struct mirror_set, | 1281 | struct mirror_set *ms =container_of(work, struct mirror_set, |
1261 | kmirrord_work); | 1282 | kmirrord_work); |
@@ -1277,23 +1298,7 @@ static int _do_mirror(struct work_struct *work) | |||
1277 | do_writes(ms, &writes); | 1298 | do_writes(ms, &writes); |
1278 | do_failures(ms, &failures); | 1299 | do_failures(ms, &failures); |
1279 | 1300 | ||
1280 | return (ms->failures.head) ? 1 : 0; | 1301 | dm_table_unplug_all(ms->ti->table); |
1281 | } | ||
1282 | |||
1283 | static void do_mirror(struct work_struct *work) | ||
1284 | { | ||
1285 | /* | ||
1286 | * If _do_mirror returns 1, we give it | ||
1287 | * another shot. This helps for cases like | ||
1288 | * 'suspend' where we call flush_workqueue | ||
1289 | * and expect all work to be finished. If | ||
1290 | * a failure happens during a suspend, we | ||
1291 | * couldn't issue a 'wake' because it would | ||
1292 | * not be honored. Therefore, we return '1' | ||
1293 | * from _do_mirror, and retry here. | ||
1294 | */ | ||
1295 | while (_do_mirror(work)) | ||
1296 | schedule(); | ||
1297 | } | 1302 | } |
1298 | 1303 | ||
1299 | 1304 | ||
@@ -1303,7 +1308,7 @@ static void do_mirror(struct work_struct *work) | |||
1303 | static struct mirror_set *alloc_context(unsigned int nr_mirrors, | 1308 | static struct mirror_set *alloc_context(unsigned int nr_mirrors, |
1304 | uint32_t region_size, | 1309 | uint32_t region_size, |
1305 | struct dm_target *ti, | 1310 | struct dm_target *ti, |
1306 | struct dirty_log *dl) | 1311 | struct dm_dirty_log *dl) |
1307 | { | 1312 | { |
1308 | size_t len; | 1313 | size_t len; |
1309 | struct mirror_set *ms = NULL; | 1314 | struct mirror_set *ms = NULL; |
@@ -1403,12 +1408,12 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti, | |||
1403 | /* | 1408 | /* |
1404 | * Create dirty log: log_type #log_params <log_params> | 1409 | * Create dirty log: log_type #log_params <log_params> |
1405 | */ | 1410 | */ |
1406 | static struct dirty_log *create_dirty_log(struct dm_target *ti, | 1411 | static struct dm_dirty_log *create_dirty_log(struct dm_target *ti, |
1407 | unsigned int argc, char **argv, | 1412 | unsigned int argc, char **argv, |
1408 | unsigned int *args_used) | 1413 | unsigned int *args_used) |
1409 | { | 1414 | { |
1410 | unsigned int param_count; | 1415 | unsigned int param_count; |
1411 | struct dirty_log *dl; | 1416 | struct dm_dirty_log *dl; |
1412 | 1417 | ||
1413 | if (argc < 2) { | 1418 | if (argc < 2) { |
1414 | ti->error = "Insufficient mirror log arguments"; | 1419 | ti->error = "Insufficient mirror log arguments"; |
@@ -1427,7 +1432,7 @@ static struct dirty_log *create_dirty_log(struct dm_target *ti, | |||
1427 | return NULL; | 1432 | return NULL; |
1428 | } | 1433 | } |
1429 | 1434 | ||
1430 | dl = dm_create_dirty_log(argv[0], ti, param_count, argv + 2); | 1435 | dl = dm_dirty_log_create(argv[0], ti, param_count, argv + 2); |
1431 | if (!dl) { | 1436 | if (!dl) { |
1432 | ti->error = "Error creating mirror dirty log"; | 1437 | ti->error = "Error creating mirror dirty log"; |
1433 | return NULL; | 1438 | return NULL; |
@@ -1435,7 +1440,7 @@ static struct dirty_log *create_dirty_log(struct dm_target *ti, | |||
1435 | 1440 | ||
1436 | if (!_check_region_size(ti, dl->type->get_region_size(dl))) { | 1441 | if (!_check_region_size(ti, dl->type->get_region_size(dl))) { |
1437 | ti->error = "Invalid region size"; | 1442 | ti->error = "Invalid region size"; |
1438 | dm_destroy_dirty_log(dl); | 1443 | dm_dirty_log_destroy(dl); |
1439 | return NULL; | 1444 | return NULL; |
1440 | } | 1445 | } |
1441 | 1446 | ||
@@ -1496,7 +1501,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1496 | int r; | 1501 | int r; |
1497 | unsigned int nr_mirrors, m, args_used; | 1502 | unsigned int nr_mirrors, m, args_used; |
1498 | struct mirror_set *ms; | 1503 | struct mirror_set *ms; |
1499 | struct dirty_log *dl; | 1504 | struct dm_dirty_log *dl; |
1500 | 1505 | ||
1501 | dl = create_dirty_log(ti, argc, argv, &args_used); | 1506 | dl = create_dirty_log(ti, argc, argv, &args_used); |
1502 | if (!dl) | 1507 | if (!dl) |
@@ -1506,9 +1511,9 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1506 | argc -= args_used; | 1511 | argc -= args_used; |
1507 | 1512 | ||
1508 | if (!argc || sscanf(argv[0], "%u", &nr_mirrors) != 1 || | 1513 | if (!argc || sscanf(argv[0], "%u", &nr_mirrors) != 1 || |
1509 | nr_mirrors < 2 || nr_mirrors > KCOPYD_MAX_REGIONS + 1) { | 1514 | nr_mirrors < 2 || nr_mirrors > DM_KCOPYD_MAX_REGIONS + 1) { |
1510 | ti->error = "Invalid number of mirrors"; | 1515 | ti->error = "Invalid number of mirrors"; |
1511 | dm_destroy_dirty_log(dl); | 1516 | dm_dirty_log_destroy(dl); |
1512 | return -EINVAL; | 1517 | return -EINVAL; |
1513 | } | 1518 | } |
1514 | 1519 | ||
@@ -1516,13 +1521,13 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1516 | 1521 | ||
1517 | if (argc < nr_mirrors * 2) { | 1522 | if (argc < nr_mirrors * 2) { |
1518 | ti->error = "Too few mirror arguments"; | 1523 | ti->error = "Too few mirror arguments"; |
1519 | dm_destroy_dirty_log(dl); | 1524 | dm_dirty_log_destroy(dl); |
1520 | return -EINVAL; | 1525 | return -EINVAL; |
1521 | } | 1526 | } |
1522 | 1527 | ||
1523 | ms = alloc_context(nr_mirrors, dl->type->get_region_size(dl), ti, dl); | 1528 | ms = alloc_context(nr_mirrors, dl->type->get_region_size(dl), ti, dl); |
1524 | if (!ms) { | 1529 | if (!ms) { |
1525 | dm_destroy_dirty_log(dl); | 1530 | dm_dirty_log_destroy(dl); |
1526 | return -ENOMEM; | 1531 | return -ENOMEM; |
1527 | } | 1532 | } |
1528 | 1533 | ||
@@ -1547,6 +1552,8 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1547 | goto err_free_context; | 1552 | goto err_free_context; |
1548 | } | 1553 | } |
1549 | INIT_WORK(&ms->kmirrord_work, do_mirror); | 1554 | INIT_WORK(&ms->kmirrord_work, do_mirror); |
1555 | init_timer(&ms->timer); | ||
1556 | ms->timer_pending = 0; | ||
1550 | INIT_WORK(&ms->trigger_event, trigger_event); | 1557 | INIT_WORK(&ms->trigger_event, trigger_event); |
1551 | 1558 | ||
1552 | r = parse_features(ms, argc, argv, &args_used); | 1559 | r = parse_features(ms, argc, argv, &args_used); |
@@ -1571,7 +1578,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1571 | goto err_destroy_wq; | 1578 | goto err_destroy_wq; |
1572 | } | 1579 | } |
1573 | 1580 | ||
1574 | r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client); | 1581 | r = dm_kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client); |
1575 | if (r) | 1582 | if (r) |
1576 | goto err_destroy_wq; | 1583 | goto err_destroy_wq; |
1577 | 1584 | ||
@@ -1589,8 +1596,9 @@ static void mirror_dtr(struct dm_target *ti) | |||
1589 | { | 1596 | { |
1590 | struct mirror_set *ms = (struct mirror_set *) ti->private; | 1597 | struct mirror_set *ms = (struct mirror_set *) ti->private; |
1591 | 1598 | ||
1599 | del_timer_sync(&ms->timer); | ||
1592 | flush_workqueue(ms->kmirrord_wq); | 1600 | flush_workqueue(ms->kmirrord_wq); |
1593 | kcopyd_client_destroy(ms->kcopyd_client); | 1601 | dm_kcopyd_client_destroy(ms->kcopyd_client); |
1594 | destroy_workqueue(ms->kmirrord_wq); | 1602 | destroy_workqueue(ms->kmirrord_wq); |
1595 | free_context(ms, ti, ms->nr_mirrors); | 1603 | free_context(ms, ti, ms->nr_mirrors); |
1596 | } | 1604 | } |
@@ -1734,7 +1742,7 @@ out: | |||
1734 | static void mirror_presuspend(struct dm_target *ti) | 1742 | static void mirror_presuspend(struct dm_target *ti) |
1735 | { | 1743 | { |
1736 | struct mirror_set *ms = (struct mirror_set *) ti->private; | 1744 | struct mirror_set *ms = (struct mirror_set *) ti->private; |
1737 | struct dirty_log *log = ms->rh.log; | 1745 | struct dm_dirty_log *log = ms->rh.log; |
1738 | 1746 | ||
1739 | atomic_set(&ms->suspend, 1); | 1747 | atomic_set(&ms->suspend, 1); |
1740 | 1748 | ||
@@ -1763,7 +1771,7 @@ static void mirror_presuspend(struct dm_target *ti) | |||
1763 | static void mirror_postsuspend(struct dm_target *ti) | 1771 | static void mirror_postsuspend(struct dm_target *ti) |
1764 | { | 1772 | { |
1765 | struct mirror_set *ms = ti->private; | 1773 | struct mirror_set *ms = ti->private; |
1766 | struct dirty_log *log = ms->rh.log; | 1774 | struct dm_dirty_log *log = ms->rh.log; |
1767 | 1775 | ||
1768 | if (log->type->postsuspend && log->type->postsuspend(log)) | 1776 | if (log->type->postsuspend && log->type->postsuspend(log)) |
1769 | /* FIXME: need better error handling */ | 1777 | /* FIXME: need better error handling */ |
@@ -1773,7 +1781,7 @@ static void mirror_postsuspend(struct dm_target *ti) | |||
1773 | static void mirror_resume(struct dm_target *ti) | 1781 | static void mirror_resume(struct dm_target *ti) |
1774 | { | 1782 | { |
1775 | struct mirror_set *ms = ti->private; | 1783 | struct mirror_set *ms = ti->private; |
1776 | struct dirty_log *log = ms->rh.log; | 1784 | struct dm_dirty_log *log = ms->rh.log; |
1777 | 1785 | ||
1778 | atomic_set(&ms->suspend, 0); | 1786 | atomic_set(&ms->suspend, 0); |
1779 | if (log->type->resume && log->type->resume(log)) | 1787 | if (log->type->resume && log->type->resume(log)) |
@@ -1811,7 +1819,7 @@ static int mirror_status(struct dm_target *ti, status_type_t type, | |||
1811 | { | 1819 | { |
1812 | unsigned int m, sz = 0; | 1820 | unsigned int m, sz = 0; |
1813 | struct mirror_set *ms = (struct mirror_set *) ti->private; | 1821 | struct mirror_set *ms = (struct mirror_set *) ti->private; |
1814 | struct dirty_log *log = ms->rh.log; | 1822 | struct dm_dirty_log *log = ms->rh.log; |
1815 | char buffer[ms->nr_mirrors + 1]; | 1823 | char buffer[ms->nr_mirrors + 1]; |
1816 | 1824 | ||
1817 | switch (type) { | 1825 | switch (type) { |
@@ -1864,15 +1872,9 @@ static int __init dm_mirror_init(void) | |||
1864 | { | 1872 | { |
1865 | int r; | 1873 | int r; |
1866 | 1874 | ||
1867 | r = dm_dirty_log_init(); | ||
1868 | if (r) | ||
1869 | return r; | ||
1870 | |||
1871 | r = dm_register_target(&mirror_target); | 1875 | r = dm_register_target(&mirror_target); |
1872 | if (r < 0) { | 1876 | if (r < 0) |
1873 | DMERR("Failed to register mirror target"); | 1877 | DMERR("Failed to register mirror target"); |
1874 | dm_dirty_log_exit(); | ||
1875 | } | ||
1876 | 1878 | ||
1877 | return r; | 1879 | return r; |
1878 | } | 1880 | } |
@@ -1884,8 +1886,6 @@ static void __exit dm_mirror_exit(void) | |||
1884 | r = dm_unregister_target(&mirror_target); | 1886 | r = dm_unregister_target(&mirror_target); |
1885 | if (r < 0) | 1887 | if (r < 0) |
1886 | DMERR("unregister failed %d", r); | 1888 | DMERR("unregister failed %d", r); |
1887 | |||
1888 | dm_dirty_log_exit(); | ||
1889 | } | 1889 | } |
1890 | 1890 | ||
1891 | /* Module hooks */ | 1891 | /* Module hooks */ |
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 4dc8a43c034b..1ba8a47d61b1 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -18,10 +18,10 @@ | |||
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/vmalloc.h> | 19 | #include <linux/vmalloc.h> |
20 | #include <linux/log2.h> | 20 | #include <linux/log2.h> |
21 | #include <linux/dm-kcopyd.h> | ||
21 | 22 | ||
22 | #include "dm-snap.h" | 23 | #include "dm-snap.h" |
23 | #include "dm-bio-list.h" | 24 | #include "dm-bio-list.h" |
24 | #include "kcopyd.h" | ||
25 | 25 | ||
26 | #define DM_MSG_PREFIX "snapshots" | 26 | #define DM_MSG_PREFIX "snapshots" |
27 | 27 | ||
@@ -36,9 +36,9 @@ | |||
36 | #define SNAPSHOT_COPY_PRIORITY 2 | 36 | #define SNAPSHOT_COPY_PRIORITY 2 |
37 | 37 | ||
38 | /* | 38 | /* |
39 | * Each snapshot reserves this many pages for io | 39 | * Reserve 1MB for each snapshot initially (with minimum of 1 page). |
40 | */ | 40 | */ |
41 | #define SNAPSHOT_PAGES 256 | 41 | #define SNAPSHOT_PAGES (((1UL << 20) >> PAGE_SHIFT) ? : 1) |
42 | 42 | ||
43 | static struct workqueue_struct *ksnapd; | 43 | static struct workqueue_struct *ksnapd; |
44 | static void flush_queued_bios(struct work_struct *work); | 44 | static void flush_queued_bios(struct work_struct *work); |
@@ -536,7 +536,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
536 | s->last_percent = 0; | 536 | s->last_percent = 0; |
537 | init_rwsem(&s->lock); | 537 | init_rwsem(&s->lock); |
538 | spin_lock_init(&s->pe_lock); | 538 | spin_lock_init(&s->pe_lock); |
539 | s->table = ti->table; | 539 | s->ti = ti; |
540 | 540 | ||
541 | /* Allocate hash table for COW data */ | 541 | /* Allocate hash table for COW data */ |
542 | if (init_hash_tables(s)) { | 542 | if (init_hash_tables(s)) { |
@@ -558,7 +558,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
558 | goto bad4; | 558 | goto bad4; |
559 | } | 559 | } |
560 | 560 | ||
561 | r = kcopyd_client_create(SNAPSHOT_PAGES, &s->kcopyd_client); | 561 | r = dm_kcopyd_client_create(SNAPSHOT_PAGES, &s->kcopyd_client); |
562 | if (r) { | 562 | if (r) { |
563 | ti->error = "Could not create kcopyd client"; | 563 | ti->error = "Could not create kcopyd client"; |
564 | goto bad5; | 564 | goto bad5; |
@@ -591,7 +591,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
591 | return 0; | 591 | return 0; |
592 | 592 | ||
593 | bad6: | 593 | bad6: |
594 | kcopyd_client_destroy(s->kcopyd_client); | 594 | dm_kcopyd_client_destroy(s->kcopyd_client); |
595 | 595 | ||
596 | bad5: | 596 | bad5: |
597 | s->store.destroy(&s->store); | 597 | s->store.destroy(&s->store); |
@@ -613,7 +613,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
613 | 613 | ||
614 | static void __free_exceptions(struct dm_snapshot *s) | 614 | static void __free_exceptions(struct dm_snapshot *s) |
615 | { | 615 | { |
616 | kcopyd_client_destroy(s->kcopyd_client); | 616 | dm_kcopyd_client_destroy(s->kcopyd_client); |
617 | s->kcopyd_client = NULL; | 617 | s->kcopyd_client = NULL; |
618 | 618 | ||
619 | exit_exception_table(&s->pending, pending_cache); | 619 | exit_exception_table(&s->pending, pending_cache); |
@@ -699,7 +699,7 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err) | |||
699 | 699 | ||
700 | s->valid = 0; | 700 | s->valid = 0; |
701 | 701 | ||
702 | dm_table_event(s->table); | 702 | dm_table_event(s->ti->table); |
703 | } | 703 | } |
704 | 704 | ||
705 | static void get_pending_exception(struct dm_snap_pending_exception *pe) | 705 | static void get_pending_exception(struct dm_snap_pending_exception *pe) |
@@ -824,7 +824,7 @@ static void copy_callback(int read_err, unsigned long write_err, void *context) | |||
824 | static void start_copy(struct dm_snap_pending_exception *pe) | 824 | static void start_copy(struct dm_snap_pending_exception *pe) |
825 | { | 825 | { |
826 | struct dm_snapshot *s = pe->snap; | 826 | struct dm_snapshot *s = pe->snap; |
827 | struct io_region src, dest; | 827 | struct dm_io_region src, dest; |
828 | struct block_device *bdev = s->origin->bdev; | 828 | struct block_device *bdev = s->origin->bdev; |
829 | sector_t dev_size; | 829 | sector_t dev_size; |
830 | 830 | ||
@@ -839,7 +839,7 @@ static void start_copy(struct dm_snap_pending_exception *pe) | |||
839 | dest.count = src.count; | 839 | dest.count = src.count; |
840 | 840 | ||
841 | /* Hand over to kcopyd */ | 841 | /* Hand over to kcopyd */ |
842 | kcopyd_copy(s->kcopyd_client, | 842 | dm_kcopyd_copy(s->kcopyd_client, |
843 | &src, 1, &dest, 0, copy_callback, pe); | 843 | &src, 1, &dest, 0, copy_callback, pe); |
844 | } | 844 | } |
845 | 845 | ||
@@ -1060,7 +1060,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) | |||
1060 | goto next_snapshot; | 1060 | goto next_snapshot; |
1061 | 1061 | ||
1062 | /* Nothing to do if writing beyond end of snapshot */ | 1062 | /* Nothing to do if writing beyond end of snapshot */ |
1063 | if (bio->bi_sector >= dm_table_get_size(snap->table)) | 1063 | if (bio->bi_sector >= dm_table_get_size(snap->ti->table)) |
1064 | goto next_snapshot; | 1064 | goto next_snapshot; |
1065 | 1065 | ||
1066 | /* | 1066 | /* |
diff --git a/drivers/md/dm-snap.h b/drivers/md/dm-snap.h index 93bce5d49742..24f9fb73b982 100644 --- a/drivers/md/dm-snap.h +++ b/drivers/md/dm-snap.h | |||
@@ -132,7 +132,7 @@ struct exception_store { | |||
132 | 132 | ||
133 | struct dm_snapshot { | 133 | struct dm_snapshot { |
134 | struct rw_semaphore lock; | 134 | struct rw_semaphore lock; |
135 | struct dm_table *table; | 135 | struct dm_target *ti; |
136 | 136 | ||
137 | struct dm_dev *origin; | 137 | struct dm_dev *origin; |
138 | struct dm_dev *cow; | 138 | struct dm_dev *cow; |
@@ -169,7 +169,7 @@ struct dm_snapshot { | |||
169 | /* The on disk metadata handler */ | 169 | /* The on disk metadata handler */ |
170 | struct exception_store store; | 170 | struct exception_store store; |
171 | 171 | ||
172 | struct kcopyd_client *kcopyd_client; | 172 | struct dm_kcopyd_client *kcopyd_client; |
173 | 173 | ||
174 | /* Queue of snapshot writes for ksnapd to flush */ | 174 | /* Queue of snapshot writes for ksnapd to flush */ |
175 | struct bio_list queued_bios; | 175 | struct bio_list queued_bios; |
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index e75b1437b58b..51be53344214 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c | |||
@@ -245,44 +245,6 @@ int dm_table_create(struct dm_table **result, int mode, | |||
245 | return 0; | 245 | return 0; |
246 | } | 246 | } |
247 | 247 | ||
248 | int dm_create_error_table(struct dm_table **result, struct mapped_device *md) | ||
249 | { | ||
250 | struct dm_table *t; | ||
251 | sector_t dev_size = 1; | ||
252 | int r; | ||
253 | |||
254 | /* | ||
255 | * Find current size of device. | ||
256 | * Default to 1 sector if inactive. | ||
257 | */ | ||
258 | t = dm_get_table(md); | ||
259 | if (t) { | ||
260 | dev_size = dm_table_get_size(t); | ||
261 | dm_table_put(t); | ||
262 | } | ||
263 | |||
264 | r = dm_table_create(&t, FMODE_READ, 1, md); | ||
265 | if (r) | ||
266 | return r; | ||
267 | |||
268 | r = dm_table_add_target(t, "error", 0, dev_size, NULL); | ||
269 | if (r) | ||
270 | goto out; | ||
271 | |||
272 | r = dm_table_complete(t); | ||
273 | if (r) | ||
274 | goto out; | ||
275 | |||
276 | *result = t; | ||
277 | |||
278 | out: | ||
279 | if (r) | ||
280 | dm_table_put(t); | ||
281 | |||
282 | return r; | ||
283 | } | ||
284 | EXPORT_SYMBOL_GPL(dm_create_error_table); | ||
285 | |||
286 | static void free_devices(struct list_head *devices) | 248 | static void free_devices(struct list_head *devices) |
287 | { | 249 | { |
288 | struct list_head *tmp, *next; | 250 | struct list_head *tmp, *next; |
@@ -954,7 +916,7 @@ void dm_table_presuspend_targets(struct dm_table *t) | |||
954 | if (!t) | 916 | if (!t) |
955 | return; | 917 | return; |
956 | 918 | ||
957 | return suspend_targets(t, 0); | 919 | suspend_targets(t, 0); |
958 | } | 920 | } |
959 | 921 | ||
960 | void dm_table_postsuspend_targets(struct dm_table *t) | 922 | void dm_table_postsuspend_targets(struct dm_table *t) |
@@ -962,7 +924,7 @@ void dm_table_postsuspend_targets(struct dm_table *t) | |||
962 | if (!t) | 924 | if (!t) |
963 | return; | 925 | return; |
964 | 926 | ||
965 | return suspend_targets(t, 1); | 927 | suspend_targets(t, 1); |
966 | } | 928 | } |
967 | 929 | ||
968 | int dm_table_resume_targets(struct dm_table *t) | 930 | int dm_table_resume_targets(struct dm_table *t) |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 6617ce4af095..372369b1cc20 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -204,6 +204,7 @@ static int (*_inits[])(void) __initdata = { | |||
204 | dm_target_init, | 204 | dm_target_init, |
205 | dm_linear_init, | 205 | dm_linear_init, |
206 | dm_stripe_init, | 206 | dm_stripe_init, |
207 | dm_kcopyd_init, | ||
207 | dm_interface_init, | 208 | dm_interface_init, |
208 | }; | 209 | }; |
209 | 210 | ||
@@ -212,6 +213,7 @@ static void (*_exits[])(void) = { | |||
212 | dm_target_exit, | 213 | dm_target_exit, |
213 | dm_linear_exit, | 214 | dm_linear_exit, |
214 | dm_stripe_exit, | 215 | dm_stripe_exit, |
216 | dm_kcopyd_exit, | ||
215 | dm_interface_exit, | 217 | dm_interface_exit, |
216 | }; | 218 | }; |
217 | 219 | ||
@@ -922,7 +924,7 @@ static void free_minor(int minor) | |||
922 | /* | 924 | /* |
923 | * See if the device with a specific minor # is free. | 925 | * See if the device with a specific minor # is free. |
924 | */ | 926 | */ |
925 | static int specific_minor(struct mapped_device *md, int minor) | 927 | static int specific_minor(int minor) |
926 | { | 928 | { |
927 | int r, m; | 929 | int r, m; |
928 | 930 | ||
@@ -955,7 +957,7 @@ out: | |||
955 | return r; | 957 | return r; |
956 | } | 958 | } |
957 | 959 | ||
958 | static int next_free_minor(struct mapped_device *md, int *minor) | 960 | static int next_free_minor(int *minor) |
959 | { | 961 | { |
960 | int r, m; | 962 | int r, m; |
961 | 963 | ||
@@ -966,9 +968,8 @@ static int next_free_minor(struct mapped_device *md, int *minor) | |||
966 | spin_lock(&_minor_lock); | 968 | spin_lock(&_minor_lock); |
967 | 969 | ||
968 | r = idr_get_new(&_minor_idr, MINOR_ALLOCED, &m); | 970 | r = idr_get_new(&_minor_idr, MINOR_ALLOCED, &m); |
969 | if (r) { | 971 | if (r) |
970 | goto out; | 972 | goto out; |
971 | } | ||
972 | 973 | ||
973 | if (m >= (1 << MINORBITS)) { | 974 | if (m >= (1 << MINORBITS)) { |
974 | idr_remove(&_minor_idr, m); | 975 | idr_remove(&_minor_idr, m); |
@@ -991,7 +992,7 @@ static struct block_device_operations dm_blk_dops; | |||
991 | static struct mapped_device *alloc_dev(int minor) | 992 | static struct mapped_device *alloc_dev(int minor) |
992 | { | 993 | { |
993 | int r; | 994 | int r; |
994 | struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL); | 995 | struct mapped_device *md = kzalloc(sizeof(*md), GFP_KERNEL); |
995 | void *old_md; | 996 | void *old_md; |
996 | 997 | ||
997 | if (!md) { | 998 | if (!md) { |
@@ -1004,13 +1005,12 @@ static struct mapped_device *alloc_dev(int minor) | |||
1004 | 1005 | ||
1005 | /* get a minor number for the dev */ | 1006 | /* get a minor number for the dev */ |
1006 | if (minor == DM_ANY_MINOR) | 1007 | if (minor == DM_ANY_MINOR) |
1007 | r = next_free_minor(md, &minor); | 1008 | r = next_free_minor(&minor); |
1008 | else | 1009 | else |
1009 | r = specific_minor(md, minor); | 1010 | r = specific_minor(minor); |
1010 | if (r < 0) | 1011 | if (r < 0) |
1011 | goto bad_minor; | 1012 | goto bad_minor; |
1012 | 1013 | ||
1013 | memset(md, 0, sizeof(*md)); | ||
1014 | init_rwsem(&md->io_lock); | 1014 | init_rwsem(&md->io_lock); |
1015 | mutex_init(&md->suspend_lock); | 1015 | mutex_init(&md->suspend_lock); |
1016 | spin_lock_init(&md->pushback_lock); | 1016 | spin_lock_init(&md->pushback_lock); |
diff --git a/drivers/md/dm.h b/drivers/md/dm.h index b4584a39383b..8c03b634e62e 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h | |||
@@ -16,67 +16,6 @@ | |||
16 | #include <linux/blkdev.h> | 16 | #include <linux/blkdev.h> |
17 | #include <linux/hdreg.h> | 17 | #include <linux/hdreg.h> |
18 | 18 | ||
19 | #define DM_NAME "device-mapper" | ||
20 | |||
21 | #define DMERR(f, arg...) \ | ||
22 | printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg) | ||
23 | #define DMERR_LIMIT(f, arg...) \ | ||
24 | do { \ | ||
25 | if (printk_ratelimit()) \ | ||
26 | printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " \ | ||
27 | f "\n", ## arg); \ | ||
28 | } while (0) | ||
29 | |||
30 | #define DMWARN(f, arg...) \ | ||
31 | printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg) | ||
32 | #define DMWARN_LIMIT(f, arg...) \ | ||
33 | do { \ | ||
34 | if (printk_ratelimit()) \ | ||
35 | printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " \ | ||
36 | f "\n", ## arg); \ | ||
37 | } while (0) | ||
38 | |||
39 | #define DMINFO(f, arg...) \ | ||
40 | printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg) | ||
41 | #define DMINFO_LIMIT(f, arg...) \ | ||
42 | do { \ | ||
43 | if (printk_ratelimit()) \ | ||
44 | printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f \ | ||
45 | "\n", ## arg); \ | ||
46 | } while (0) | ||
47 | |||
48 | #ifdef CONFIG_DM_DEBUG | ||
49 | # define DMDEBUG(f, arg...) \ | ||
50 | printk(KERN_DEBUG DM_NAME ": " DM_MSG_PREFIX " DEBUG: " f "\n", ## arg) | ||
51 | # define DMDEBUG_LIMIT(f, arg...) \ | ||
52 | do { \ | ||
53 | if (printk_ratelimit()) \ | ||
54 | printk(KERN_DEBUG DM_NAME ": " DM_MSG_PREFIX ": " f \ | ||
55 | "\n", ## arg); \ | ||
56 | } while (0) | ||
57 | #else | ||
58 | # define DMDEBUG(f, arg...) do {} while (0) | ||
59 | # define DMDEBUG_LIMIT(f, arg...) do {} while (0) | ||
60 | #endif | ||
61 | |||
62 | #define DMEMIT(x...) sz += ((sz >= maxlen) ? \ | ||
63 | 0 : scnprintf(result + sz, maxlen - sz, x)) | ||
64 | |||
65 | #define SECTOR_SHIFT 9 | ||
66 | |||
67 | /* | ||
68 | * Definitions of return values from target end_io function. | ||
69 | */ | ||
70 | #define DM_ENDIO_INCOMPLETE 1 | ||
71 | #define DM_ENDIO_REQUEUE 2 | ||
72 | |||
73 | /* | ||
74 | * Definitions of return values from target map function. | ||
75 | */ | ||
76 | #define DM_MAPIO_SUBMITTED 0 | ||
77 | #define DM_MAPIO_REMAPPED 1 | ||
78 | #define DM_MAPIO_REQUEUE DM_ENDIO_REQUEUE | ||
79 | |||
80 | /* | 19 | /* |
81 | * Suspend feature flags | 20 | * Suspend feature flags |
82 | */ | 21 | */ |
@@ -136,34 +75,6 @@ static inline int array_too_big(unsigned long fixed, unsigned long obj, | |||
136 | return (num > (ULONG_MAX - fixed) / obj); | 75 | return (num > (ULONG_MAX - fixed) / obj); |
137 | } | 76 | } |
138 | 77 | ||
139 | /* | ||
140 | * Ceiling(n / sz) | ||
141 | */ | ||
142 | #define dm_div_up(n, sz) (((n) + (sz) - 1) / (sz)) | ||
143 | |||
144 | #define dm_sector_div_up(n, sz) ( \ | ||
145 | { \ | ||
146 | sector_t _r = ((n) + (sz) - 1); \ | ||
147 | sector_div(_r, (sz)); \ | ||
148 | _r; \ | ||
149 | } \ | ||
150 | ) | ||
151 | |||
152 | /* | ||
153 | * ceiling(n / size) * size | ||
154 | */ | ||
155 | #define dm_round_up(n, sz) (dm_div_up((n), (sz)) * (sz)) | ||
156 | |||
157 | static inline sector_t to_sector(unsigned long n) | ||
158 | { | ||
159 | return (n >> 9); | ||
160 | } | ||
161 | |||
162 | static inline unsigned long to_bytes(sector_t n) | ||
163 | { | ||
164 | return (n << 9); | ||
165 | } | ||
166 | |||
167 | int dm_split_args(int *argc, char ***argvp, char *input); | 78 | int dm_split_args(int *argc, char ***argvp, char *input); |
168 | 79 | ||
169 | /* | 80 | /* |
@@ -189,4 +100,13 @@ int dm_lock_for_deletion(struct mapped_device *md); | |||
189 | 100 | ||
190 | void dm_kobject_uevent(struct mapped_device *md); | 101 | void dm_kobject_uevent(struct mapped_device *md); |
191 | 102 | ||
103 | /* | ||
104 | * Dirty log | ||
105 | */ | ||
106 | int dm_dirty_log_init(void); | ||
107 | void dm_dirty_log_exit(void); | ||
108 | |||
109 | int dm_kcopyd_init(void); | ||
110 | void dm_kcopyd_exit(void); | ||
111 | |||
192 | #endif | 112 | #endif |
diff --git a/drivers/md/kcopyd.h b/drivers/md/kcopyd.h deleted file mode 100644 index 4845f2a0c676..000000000000 --- a/drivers/md/kcopyd.h +++ /dev/null | |||
@@ -1,42 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Sistina Software | ||
3 | * | ||
4 | * This file is released under the GPL. | ||
5 | * | ||
6 | * Kcopyd provides a simple interface for copying an area of one | ||
7 | * block-device to one or more other block-devices, with an asynchronous | ||
8 | * completion notification. | ||
9 | */ | ||
10 | |||
11 | #ifndef DM_KCOPYD_H | ||
12 | #define DM_KCOPYD_H | ||
13 | |||
14 | #include "dm-io.h" | ||
15 | |||
16 | /* FIXME: make this configurable */ | ||
17 | #define KCOPYD_MAX_REGIONS 8 | ||
18 | |||
19 | #define KCOPYD_IGNORE_ERROR 1 | ||
20 | |||
21 | /* | ||
22 | * To use kcopyd you must first create a kcopyd client object. | ||
23 | */ | ||
24 | struct kcopyd_client; | ||
25 | int kcopyd_client_create(unsigned int num_pages, struct kcopyd_client **result); | ||
26 | void kcopyd_client_destroy(struct kcopyd_client *kc); | ||
27 | |||
28 | /* | ||
29 | * Submit a copy job to kcopyd. This is built on top of the | ||
30 | * previous three fns. | ||
31 | * | ||
32 | * read_err is a boolean, | ||
33 | * write_err is a bitset, with 1 bit for each destination region | ||
34 | */ | ||
35 | typedef void (*kcopyd_notify_fn)(int read_err, unsigned long write_err, | ||
36 | void *context); | ||
37 | |||
38 | int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from, | ||
39 | unsigned int num_dests, struct io_region *dests, | ||
40 | unsigned int flags, kcopyd_notify_fn fn, void *context); | ||
41 | |||
42 | #endif | ||
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index e8503341e3b1..eed06d068fd1 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig | |||
@@ -158,6 +158,12 @@ config MTD_OF_PARTS | |||
158 | the partition map from the children of the flash node, | 158 | the partition map from the children of the flash node, |
159 | as described in Documentation/powerpc/booting-without-of.txt. | 159 | as described in Documentation/powerpc/booting-without-of.txt. |
160 | 160 | ||
161 | config MTD_AR7_PARTS | ||
162 | tristate "TI AR7 partitioning support" | ||
163 | depends on MTD_PARTITIONS | ||
164 | ---help--- | ||
165 | TI AR7 partitioning support | ||
166 | |||
161 | comment "User Modules And Translation Layers" | 167 | comment "User Modules And Translation Layers" |
162 | 168 | ||
163 | config MTD_CHAR | 169 | config MTD_CHAR |
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 538e33d11d46..4b77335715f0 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile | |||
@@ -11,6 +11,7 @@ obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o | |||
11 | obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o | 11 | obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o |
12 | obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o | 12 | obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o |
13 | obj-$(CONFIG_MTD_AFS_PARTS) += afs.o | 13 | obj-$(CONFIG_MTD_AFS_PARTS) += afs.o |
14 | obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o | ||
14 | obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o | 15 | obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o |
15 | 16 | ||
16 | # 'Users' - code which presents functionality to userspace. | 17 | # 'Users' - code which presents functionality to userspace. |
diff --git a/drivers/mtd/ar7part.c b/drivers/mtd/ar7part.c new file mode 100644 index 000000000000..ecf170b55c32 --- /dev/null +++ b/drivers/mtd/ar7part.c | |||
@@ -0,0 +1,151 @@ | |||
1 | /* | ||
2 | * Copyright © 2007 Eugene Konev <ejka@openwrt.org> | ||
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 as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
17 | * | ||
18 | * TI AR7 flash partition table. | ||
19 | * Based on ar7 map by Felix Fietkau <nbd@openwrt.org> | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/slab.h> | ||
25 | |||
26 | #include <linux/mtd/mtd.h> | ||
27 | #include <linux/mtd/partitions.h> | ||
28 | #include <linux/bootmem.h> | ||
29 | #include <linux/magic.h> | ||
30 | |||
31 | #define AR7_PARTS 4 | ||
32 | #define ROOT_OFFSET 0xe0000 | ||
33 | |||
34 | #define LOADER_MAGIC1 le32_to_cpu(0xfeedfa42) | ||
35 | #define LOADER_MAGIC2 le32_to_cpu(0xfeed1281) | ||
36 | |||
37 | #ifndef SQUASHFS_MAGIC | ||
38 | #define SQUASHFS_MAGIC 0x73717368 | ||
39 | #endif | ||
40 | |||
41 | struct ar7_bin_rec { | ||
42 | unsigned int checksum; | ||
43 | unsigned int length; | ||
44 | unsigned int address; | ||
45 | }; | ||
46 | |||
47 | static struct mtd_partition ar7_parts[AR7_PARTS]; | ||
48 | |||
49 | static int create_mtd_partitions(struct mtd_info *master, | ||
50 | struct mtd_partition **pparts, | ||
51 | unsigned long origin) | ||
52 | { | ||
53 | struct ar7_bin_rec header; | ||
54 | unsigned int offset; | ||
55 | size_t len; | ||
56 | unsigned int pre_size = master->erasesize, post_size = 0; | ||
57 | unsigned int root_offset = ROOT_OFFSET; | ||
58 | |||
59 | int retries = 10; | ||
60 | |||
61 | ar7_parts[0].name = "loader"; | ||
62 | ar7_parts[0].offset = 0; | ||
63 | ar7_parts[0].size = master->erasesize; | ||
64 | ar7_parts[0].mask_flags = MTD_WRITEABLE; | ||
65 | |||
66 | ar7_parts[1].name = "config"; | ||
67 | ar7_parts[1].offset = 0; | ||
68 | ar7_parts[1].size = master->erasesize; | ||
69 | ar7_parts[1].mask_flags = 0; | ||
70 | |||
71 | do { /* Try 10 blocks starting from master->erasesize */ | ||
72 | offset = pre_size; | ||
73 | master->read(master, offset, | ||
74 | sizeof(header), &len, (uint8_t *)&header); | ||
75 | if (!strncmp((char *)&header, "TIENV0.8", 8)) | ||
76 | ar7_parts[1].offset = pre_size; | ||
77 | if (header.checksum == LOADER_MAGIC1) | ||
78 | break; | ||
79 | if (header.checksum == LOADER_MAGIC2) | ||
80 | break; | ||
81 | pre_size += master->erasesize; | ||
82 | } while (retries--); | ||
83 | |||
84 | pre_size = offset; | ||
85 | |||
86 | if (!ar7_parts[1].offset) { | ||
87 | ar7_parts[1].offset = master->size - master->erasesize; | ||
88 | post_size = master->erasesize; | ||
89 | } | ||
90 | |||
91 | switch (header.checksum) { | ||
92 | case LOADER_MAGIC1: | ||
93 | while (header.length) { | ||
94 | offset += sizeof(header) + header.length; | ||
95 | master->read(master, offset, sizeof(header), | ||
96 | &len, (uint8_t *)&header); | ||
97 | } | ||
98 | root_offset = offset + sizeof(header) + 4; | ||
99 | break; | ||
100 | case LOADER_MAGIC2: | ||
101 | while (header.length) { | ||
102 | offset += sizeof(header) + header.length; | ||
103 | master->read(master, offset, sizeof(header), | ||
104 | &len, (uint8_t *)&header); | ||
105 | } | ||
106 | root_offset = offset + sizeof(header) + 4 + 0xff; | ||
107 | root_offset &= ~(uint32_t)0xff; | ||
108 | break; | ||
109 | default: | ||
110 | printk(KERN_WARNING "Unknown magic: %08x\n", header.checksum); | ||
111 | break; | ||
112 | } | ||
113 | |||
114 | master->read(master, root_offset, | ||
115 | sizeof(header), &len, (u8 *)&header); | ||
116 | if (header.checksum != SQUASHFS_MAGIC) { | ||
117 | root_offset += master->erasesize - 1; | ||
118 | root_offset &= ~(master->erasesize - 1); | ||
119 | } | ||
120 | |||
121 | ar7_parts[2].name = "linux"; | ||
122 | ar7_parts[2].offset = pre_size; | ||
123 | ar7_parts[2].size = master->size - pre_size - post_size; | ||
124 | ar7_parts[2].mask_flags = 0; | ||
125 | |||
126 | ar7_parts[3].name = "rootfs"; | ||
127 | ar7_parts[3].offset = root_offset; | ||
128 | ar7_parts[3].size = master->size - root_offset - post_size; | ||
129 | ar7_parts[3].mask_flags = 0; | ||
130 | |||
131 | *pparts = ar7_parts; | ||
132 | return AR7_PARTS; | ||
133 | } | ||
134 | |||
135 | static struct mtd_part_parser ar7_parser = { | ||
136 | .owner = THIS_MODULE, | ||
137 | .parse_fn = create_mtd_partitions, | ||
138 | .name = "ar7part", | ||
139 | }; | ||
140 | |||
141 | static int __init ar7_parser_init(void) | ||
142 | { | ||
143 | return register_mtd_parser(&ar7_parser); | ||
144 | } | ||
145 | |||
146 | module_init(ar7_parser_init); | ||
147 | |||
148 | MODULE_LICENSE("GPL"); | ||
149 | MODULE_AUTHOR( "Felix Fietkau <nbd@openwrt.org>, " | ||
150 | "Eugene Konev <ejka@openwrt.org>"); | ||
151 | MODULE_DESCRIPTION("MTD partitioning for TI AR7"); | ||
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 0080452531d6..e812df607a5c 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c | |||
@@ -384,7 +384,7 @@ read_pri_intelext(struct map_info *map, __u16 adr) | |||
384 | if (extp_size > 4096) { | 384 | if (extp_size > 4096) { |
385 | printk(KERN_ERR | 385 | printk(KERN_ERR |
386 | "%s: cfi_pri_intelext is too fat\n", | 386 | "%s: cfi_pri_intelext is too fat\n", |
387 | __FUNCTION__); | 387 | __func__); |
388 | return NULL; | 388 | return NULL; |
389 | } | 389 | } |
390 | goto again; | 390 | goto again; |
@@ -619,6 +619,9 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, | |||
619 | sizeof(struct cfi_intelext_blockinfo); | 619 | sizeof(struct cfi_intelext_blockinfo); |
620 | } | 620 | } |
621 | 621 | ||
622 | if (!numparts) | ||
623 | numparts = 1; | ||
624 | |||
622 | /* Programming Region info */ | 625 | /* Programming Region info */ |
623 | if (extp->MinorVersion >= '4') { | 626 | if (extp->MinorVersion >= '4') { |
624 | struct cfi_intelext_programming_regioninfo *prinfo; | 627 | struct cfi_intelext_programming_regioninfo *prinfo; |
@@ -641,7 +644,7 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, | |||
641 | if ((1 << partshift) < mtd->erasesize) { | 644 | if ((1 << partshift) < mtd->erasesize) { |
642 | printk( KERN_ERR | 645 | printk( KERN_ERR |
643 | "%s: bad number of hw partitions (%d)\n", | 646 | "%s: bad number of hw partitions (%d)\n", |
644 | __FUNCTION__, numparts); | 647 | __func__, numparts); |
645 | return -EINVAL; | 648 | return -EINVAL; |
646 | } | 649 | } |
647 | 650 | ||
@@ -1071,10 +1074,10 @@ static int __xipram xip_wait_for_operation( | |||
1071 | chip->state = newstate; | 1074 | chip->state = newstate; |
1072 | map_write(map, CMD(0xff), adr); | 1075 | map_write(map, CMD(0xff), adr); |
1073 | (void) map_read(map, adr); | 1076 | (void) map_read(map, adr); |
1074 | asm volatile (".rep 8; nop; .endr"); | 1077 | xip_iprefetch(); |
1075 | local_irq_enable(); | 1078 | local_irq_enable(); |
1076 | spin_unlock(chip->mutex); | 1079 | spin_unlock(chip->mutex); |
1077 | asm volatile (".rep 8; nop; .endr"); | 1080 | xip_iprefetch(); |
1078 | cond_resched(); | 1081 | cond_resched(); |
1079 | 1082 | ||
1080 | /* | 1083 | /* |
@@ -2013,7 +2016,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
2013 | 2016 | ||
2014 | #ifdef DEBUG_LOCK_BITS | 2017 | #ifdef DEBUG_LOCK_BITS |
2015 | printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n", | 2018 | printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n", |
2016 | __FUNCTION__, ofs, len); | 2019 | __func__, ofs, len); |
2017 | cfi_varsize_frob(mtd, do_printlockstatus_oneblock, | 2020 | cfi_varsize_frob(mtd, do_printlockstatus_oneblock, |
2018 | ofs, len, NULL); | 2021 | ofs, len, NULL); |
2019 | #endif | 2022 | #endif |
@@ -2023,7 +2026,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
2023 | 2026 | ||
2024 | #ifdef DEBUG_LOCK_BITS | 2027 | #ifdef DEBUG_LOCK_BITS |
2025 | printk(KERN_DEBUG "%s: lock status after, ret=%d\n", | 2028 | printk(KERN_DEBUG "%s: lock status after, ret=%d\n", |
2026 | __FUNCTION__, ret); | 2029 | __func__, ret); |
2027 | cfi_varsize_frob(mtd, do_printlockstatus_oneblock, | 2030 | cfi_varsize_frob(mtd, do_printlockstatus_oneblock, |
2028 | ofs, len, NULL); | 2031 | ofs, len, NULL); |
2029 | #endif | 2032 | #endif |
@@ -2037,7 +2040,7 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
2037 | 2040 | ||
2038 | #ifdef DEBUG_LOCK_BITS | 2041 | #ifdef DEBUG_LOCK_BITS |
2039 | printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n", | 2042 | printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n", |
2040 | __FUNCTION__, ofs, len); | 2043 | __func__, ofs, len); |
2041 | cfi_varsize_frob(mtd, do_printlockstatus_oneblock, | 2044 | cfi_varsize_frob(mtd, do_printlockstatus_oneblock, |
2042 | ofs, len, NULL); | 2045 | ofs, len, NULL); |
2043 | #endif | 2046 | #endif |
@@ -2047,7 +2050,7 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
2047 | 2050 | ||
2048 | #ifdef DEBUG_LOCK_BITS | 2051 | #ifdef DEBUG_LOCK_BITS |
2049 | printk(KERN_DEBUG "%s: lock status after, ret=%d\n", | 2052 | printk(KERN_DEBUG "%s: lock status after, ret=%d\n", |
2050 | __FUNCTION__, ret); | 2053 | __func__, ret); |
2051 | cfi_varsize_frob(mtd, do_printlockstatus_oneblock, | 2054 | cfi_varsize_frob(mtd, do_printlockstatus_oneblock, |
2052 | ofs, len, NULL); | 2055 | ofs, len, NULL); |
2053 | #endif | 2056 | #endif |
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 458d477614d6..f7fcc6389533 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c | |||
@@ -220,6 +220,28 @@ static void fixup_use_atmel_lock(struct mtd_info *mtd, void *param) | |||
220 | mtd->flags |= MTD_POWERUP_LOCK; | 220 | mtd->flags |= MTD_POWERUP_LOCK; |
221 | } | 221 | } |
222 | 222 | ||
223 | static void fixup_s29gl064n_sectors(struct mtd_info *mtd, void *param) | ||
224 | { | ||
225 | struct map_info *map = mtd->priv; | ||
226 | struct cfi_private *cfi = map->fldrv_priv; | ||
227 | |||
228 | if ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0x003f) { | ||
229 | cfi->cfiq->EraseRegionInfo[0] |= 0x0040; | ||
230 | pr_warning("%s: Bad S29GL064N CFI data, adjust from 64 to 128 sectors\n", mtd->name); | ||
231 | } | ||
232 | } | ||
233 | |||
234 | static void fixup_s29gl032n_sectors(struct mtd_info *mtd, void *param) | ||
235 | { | ||
236 | struct map_info *map = mtd->priv; | ||
237 | struct cfi_private *cfi = map->fldrv_priv; | ||
238 | |||
239 | if ((cfi->cfiq->EraseRegionInfo[1] & 0xffff) == 0x007e) { | ||
240 | cfi->cfiq->EraseRegionInfo[1] &= ~0x0040; | ||
241 | pr_warning("%s: Bad S29GL032N CFI data, adjust from 127 to 63 sectors\n", mtd->name); | ||
242 | } | ||
243 | } | ||
244 | |||
223 | static struct cfi_fixup cfi_fixup_table[] = { | 245 | static struct cfi_fixup cfi_fixup_table[] = { |
224 | { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, | 246 | { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, |
225 | #ifdef AMD_BOOTLOC_BUG | 247 | #ifdef AMD_BOOTLOC_BUG |
@@ -231,6 +253,10 @@ static struct cfi_fixup cfi_fixup_table[] = { | |||
231 | { CFI_MFR_AMD, 0x0056, fixup_use_secsi, NULL, }, | 253 | { CFI_MFR_AMD, 0x0056, fixup_use_secsi, NULL, }, |
232 | { CFI_MFR_AMD, 0x005C, fixup_use_secsi, NULL, }, | 254 | { CFI_MFR_AMD, 0x005C, fixup_use_secsi, NULL, }, |
233 | { CFI_MFR_AMD, 0x005F, fixup_use_secsi, NULL, }, | 255 | { CFI_MFR_AMD, 0x005F, fixup_use_secsi, NULL, }, |
256 | { CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors, NULL, }, | ||
257 | { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors, NULL, }, | ||
258 | { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors, NULL, }, | ||
259 | { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors, NULL, }, | ||
234 | #if !FORCE_WORD_WRITE | 260 | #if !FORCE_WORD_WRITE |
235 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, }, | 261 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, }, |
236 | #endif | 262 | #endif |
@@ -723,10 +749,10 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, | |||
723 | chip->erase_suspended = 1; | 749 | chip->erase_suspended = 1; |
724 | map_write(map, CMD(0xf0), adr); | 750 | map_write(map, CMD(0xf0), adr); |
725 | (void) map_read(map, adr); | 751 | (void) map_read(map, adr); |
726 | asm volatile (".rep 8; nop; .endr"); | 752 | xip_iprefetch(); |
727 | local_irq_enable(); | 753 | local_irq_enable(); |
728 | spin_unlock(chip->mutex); | 754 | spin_unlock(chip->mutex); |
729 | asm volatile (".rep 8; nop; .endr"); | 755 | xip_iprefetch(); |
730 | cond_resched(); | 756 | cond_resched(); |
731 | 757 | ||
732 | /* | 758 | /* |
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 492e2ab27420..1b720cc571f3 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c | |||
@@ -445,7 +445,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
445 | retry: | 445 | retry: |
446 | 446 | ||
447 | #ifdef DEBUG_CFI_FEATURES | 447 | #ifdef DEBUG_CFI_FEATURES |
448 | printk("%s: chip->state[%d]\n", __FUNCTION__, chip->state); | 448 | printk("%s: chip->state[%d]\n", __func__, chip->state); |
449 | #endif | 449 | #endif |
450 | spin_lock_bh(chip->mutex); | 450 | spin_lock_bh(chip->mutex); |
451 | 451 | ||
@@ -463,7 +463,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
463 | map_write(map, CMD(0x70), cmd_adr); | 463 | map_write(map, CMD(0x70), cmd_adr); |
464 | chip->state = FL_STATUS; | 464 | chip->state = FL_STATUS; |
465 | #ifdef DEBUG_CFI_FEATURES | 465 | #ifdef DEBUG_CFI_FEATURES |
466 | printk("%s: 1 status[%x]\n", __FUNCTION__, map_read(map, cmd_adr)); | 466 | printk("%s: 1 status[%x]\n", __func__, map_read(map, cmd_adr)); |
467 | #endif | 467 | #endif |
468 | 468 | ||
469 | case FL_STATUS: | 469 | case FL_STATUS: |
@@ -591,7 +591,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
591 | /* check for errors: 'lock bit', 'VPP', 'dead cell'/'unerased cell' or 'incorrect cmd' -- saw */ | 591 | /* check for errors: 'lock bit', 'VPP', 'dead cell'/'unerased cell' or 'incorrect cmd' -- saw */ |
592 | if (map_word_bitsset(map, status, CMD(0x3a))) { | 592 | if (map_word_bitsset(map, status, CMD(0x3a))) { |
593 | #ifdef DEBUG_CFI_FEATURES | 593 | #ifdef DEBUG_CFI_FEATURES |
594 | printk("%s: 2 status[%lx]\n", __FUNCTION__, status.x[0]); | 594 | printk("%s: 2 status[%lx]\n", __func__, status.x[0]); |
595 | #endif | 595 | #endif |
596 | /* clear status */ | 596 | /* clear status */ |
597 | map_write(map, CMD(0x50), cmd_adr); | 597 | map_write(map, CMD(0x50), cmd_adr); |
@@ -625,9 +625,9 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, | |||
625 | ofs = to - (chipnum << cfi->chipshift); | 625 | ofs = to - (chipnum << cfi->chipshift); |
626 | 626 | ||
627 | #ifdef DEBUG_CFI_FEATURES | 627 | #ifdef DEBUG_CFI_FEATURES |
628 | printk("%s: map_bankwidth(map)[%x]\n", __FUNCTION__, map_bankwidth(map)); | 628 | printk("%s: map_bankwidth(map)[%x]\n", __func__, map_bankwidth(map)); |
629 | printk("%s: chipnum[%x] wbufsize[%x]\n", __FUNCTION__, chipnum, wbufsize); | 629 | printk("%s: chipnum[%x] wbufsize[%x]\n", __func__, chipnum, wbufsize); |
630 | printk("%s: ofs[%x] len[%x]\n", __FUNCTION__, ofs, len); | 630 | printk("%s: ofs[%x] len[%x]\n", __func__, ofs, len); |
631 | #endif | 631 | #endif |
632 | 632 | ||
633 | /* Write buffer is worth it only if more than one word to write... */ | 633 | /* Write buffer is worth it only if more than one word to write... */ |
@@ -893,7 +893,8 @@ retry: | |||
893 | return ret; | 893 | return ret; |
894 | } | 894 | } |
895 | 895 | ||
896 | int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) | 896 | static int cfi_staa_erase_varsize(struct mtd_info *mtd, |
897 | struct erase_info *instr) | ||
897 | { struct map_info *map = mtd->priv; | 898 | { struct map_info *map = mtd->priv; |
898 | struct cfi_private *cfi = map->fldrv_priv; | 899 | struct cfi_private *cfi = map->fldrv_priv; |
899 | unsigned long adr, len; | 900 | unsigned long adr, len; |
diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c index f651b6ef1c5d..a4463a91ce31 100644 --- a/drivers/mtd/chips/cfi_probe.c +++ b/drivers/mtd/chips/cfi_probe.c | |||
@@ -39,7 +39,7 @@ struct mtd_info *cfi_probe(struct map_info *map); | |||
39 | #define xip_allowed(base, map) \ | 39 | #define xip_allowed(base, map) \ |
40 | do { \ | 40 | do { \ |
41 | (void) map_read(map, base); \ | 41 | (void) map_read(map, base); \ |
42 | asm volatile (".rep 8; nop; .endr"); \ | 42 | xip_iprefetch(); \ |
43 | local_irq_enable(); \ | 43 | local_irq_enable(); \ |
44 | } while (0) | 44 | } while (0) |
45 | 45 | ||
@@ -232,6 +232,11 @@ static int __xipram cfi_chip_setup(struct map_info *map, | |||
232 | cfi->mfr = cfi_read_query16(map, base); | 232 | cfi->mfr = cfi_read_query16(map, base); |
233 | cfi->id = cfi_read_query16(map, base + ofs_factor); | 233 | cfi->id = cfi_read_query16(map, base + ofs_factor); |
234 | 234 | ||
235 | /* Get AMD/Spansion extended JEDEC ID */ | ||
236 | if (cfi->mfr == CFI_MFR_AMD && (cfi->id & 0xff) == 0x7e) | ||
237 | cfi->id = cfi_read_query(map, base + 0xe * ofs_factor) << 8 | | ||
238 | cfi_read_query(map, base + 0xf * ofs_factor); | ||
239 | |||
235 | /* Put it back into Read Mode */ | 240 | /* Put it back into Read Mode */ |
236 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | 241 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); |
237 | /* ... even if it's an Intel chip */ | 242 | /* ... even if it's an Intel chip */ |
diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index 2e51496c248e..72e0022a47bf 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c | |||
@@ -65,7 +65,7 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n | |||
65 | 65 | ||
66 | #ifdef CONFIG_MTD_XIP | 66 | #ifdef CONFIG_MTD_XIP |
67 | (void) map_read(map, base); | 67 | (void) map_read(map, base); |
68 | asm volatile (".rep 8; nop; .endr"); | 68 | xip_iprefetch(); |
69 | local_irq_enable(); | 69 | local_irq_enable(); |
70 | #endif | 70 | #endif |
71 | 71 | ||
diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index 4be51a86a85c..aa07575eb288 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c | |||
@@ -132,6 +132,8 @@ | |||
132 | #define M29F800AB 0x0058 | 132 | #define M29F800AB 0x0058 |
133 | #define M29W800DT 0x00D7 | 133 | #define M29W800DT 0x00D7 |
134 | #define M29W800DB 0x005B | 134 | #define M29W800DB 0x005B |
135 | #define M29W400DT 0x00EE | ||
136 | #define M29W400DB 0x00EF | ||
135 | #define M29W160DT 0x22C4 | 137 | #define M29W160DT 0x22C4 |
136 | #define M29W160DB 0x2249 | 138 | #define M29W160DB 0x2249 |
137 | #define M29W040B 0x00E3 | 139 | #define M29W040B 0x00E3 |
@@ -160,6 +162,7 @@ | |||
160 | #define SST49LF030A 0x001C | 162 | #define SST49LF030A 0x001C |
161 | #define SST49LF040A 0x0051 | 163 | #define SST49LF040A 0x0051 |
162 | #define SST49LF080A 0x005B | 164 | #define SST49LF080A 0x005B |
165 | #define SST36VF3203 0x7354 | ||
163 | 166 | ||
164 | /* Toshiba */ | 167 | /* Toshiba */ |
165 | #define TC58FVT160 0x00C2 | 168 | #define TC58FVT160 0x00C2 |
@@ -1113,7 +1116,7 @@ static const struct amd_flash_info jedec_table[] = { | |||
1113 | .regions = { | 1116 | .regions = { |
1114 | ERASEINFO(0x10000,8), | 1117 | ERASEINFO(0x10000,8), |
1115 | } | 1118 | } |
1116 | }, { | 1119 | }, { |
1117 | .mfr_id = MANUFACTURER_MACRONIX, | 1120 | .mfr_id = MANUFACTURER_MACRONIX, |
1118 | .dev_id = MX29F016, | 1121 | .dev_id = MX29F016, |
1119 | .name = "Macronix MX29F016", | 1122 | .name = "Macronix MX29F016", |
@@ -1125,7 +1128,7 @@ static const struct amd_flash_info jedec_table[] = { | |||
1125 | .regions = { | 1128 | .regions = { |
1126 | ERASEINFO(0x10000,32), | 1129 | ERASEINFO(0x10000,32), |
1127 | } | 1130 | } |
1128 | }, { | 1131 | }, { |
1129 | .mfr_id = MANUFACTURER_MACRONIX, | 1132 | .mfr_id = MANUFACTURER_MACRONIX, |
1130 | .dev_id = MX29F004T, | 1133 | .dev_id = MX29F004T, |
1131 | .name = "Macronix MX29F004T", | 1134 | .name = "Macronix MX29F004T", |
@@ -1140,7 +1143,7 @@ static const struct amd_flash_info jedec_table[] = { | |||
1140 | ERASEINFO(0x02000,2), | 1143 | ERASEINFO(0x02000,2), |
1141 | ERASEINFO(0x04000,1), | 1144 | ERASEINFO(0x04000,1), |
1142 | } | 1145 | } |
1143 | }, { | 1146 | }, { |
1144 | .mfr_id = MANUFACTURER_MACRONIX, | 1147 | .mfr_id = MANUFACTURER_MACRONIX, |
1145 | .dev_id = MX29F004B, | 1148 | .dev_id = MX29F004B, |
1146 | .name = "Macronix MX29F004B", | 1149 | .name = "Macronix MX29F004B", |
@@ -1218,7 +1221,7 @@ static const struct amd_flash_info jedec_table[] = { | |||
1218 | .regions = { | 1221 | .regions = { |
1219 | ERASEINFO(0x40000,16), | 1222 | ERASEINFO(0x40000,16), |
1220 | } | 1223 | } |
1221 | }, { | 1224 | }, { |
1222 | .mfr_id = MANUFACTURER_SST, | 1225 | .mfr_id = MANUFACTURER_SST, |
1223 | .dev_id = SST39LF512, | 1226 | .dev_id = SST39LF512, |
1224 | .name = "SST 39LF512", | 1227 | .name = "SST 39LF512", |
@@ -1230,7 +1233,7 @@ static const struct amd_flash_info jedec_table[] = { | |||
1230 | .regions = { | 1233 | .regions = { |
1231 | ERASEINFO(0x01000,16), | 1234 | ERASEINFO(0x01000,16), |
1232 | } | 1235 | } |
1233 | }, { | 1236 | }, { |
1234 | .mfr_id = MANUFACTURER_SST, | 1237 | .mfr_id = MANUFACTURER_SST, |
1235 | .dev_id = SST39LF010, | 1238 | .dev_id = SST39LF010, |
1236 | .name = "SST 39LF010", | 1239 | .name = "SST 39LF010", |
@@ -1242,7 +1245,7 @@ static const struct amd_flash_info jedec_table[] = { | |||
1242 | .regions = { | 1245 | .regions = { |
1243 | ERASEINFO(0x01000,32), | 1246 | ERASEINFO(0x01000,32), |
1244 | } | 1247 | } |
1245 | }, { | 1248 | }, { |
1246 | .mfr_id = MANUFACTURER_SST, | 1249 | .mfr_id = MANUFACTURER_SST, |
1247 | .dev_id = SST29EE020, | 1250 | .dev_id = SST29EE020, |
1248 | .name = "SST 29EE020", | 1251 | .name = "SST 29EE020", |
@@ -1276,7 +1279,7 @@ static const struct amd_flash_info jedec_table[] = { | |||
1276 | .regions = { | 1279 | .regions = { |
1277 | ERASEINFO(0x01000,64), | 1280 | ERASEINFO(0x01000,64), |
1278 | } | 1281 | } |
1279 | }, { | 1282 | }, { |
1280 | .mfr_id = MANUFACTURER_SST, | 1283 | .mfr_id = MANUFACTURER_SST, |
1281 | .dev_id = SST39LF040, | 1284 | .dev_id = SST39LF040, |
1282 | .name = "SST 39LF040", | 1285 | .name = "SST 39LF040", |
@@ -1288,7 +1291,7 @@ static const struct amd_flash_info jedec_table[] = { | |||
1288 | .regions = { | 1291 | .regions = { |
1289 | ERASEINFO(0x01000,128), | 1292 | ERASEINFO(0x01000,128), |
1290 | } | 1293 | } |
1291 | }, { | 1294 | }, { |
1292 | .mfr_id = MANUFACTURER_SST, | 1295 | .mfr_id = MANUFACTURER_SST, |
1293 | .dev_id = SST39SF010A, | 1296 | .dev_id = SST39SF010A, |
1294 | .name = "SST 39SF010A", | 1297 | .name = "SST 39SF010A", |
@@ -1300,7 +1303,7 @@ static const struct amd_flash_info jedec_table[] = { | |||
1300 | .regions = { | 1303 | .regions = { |
1301 | ERASEINFO(0x01000,32), | 1304 | ERASEINFO(0x01000,32), |
1302 | } | 1305 | } |
1303 | }, { | 1306 | }, { |
1304 | .mfr_id = MANUFACTURER_SST, | 1307 | .mfr_id = MANUFACTURER_SST, |
1305 | .dev_id = SST39SF020A, | 1308 | .dev_id = SST39SF020A, |
1306 | .name = "SST 39SF020A", | 1309 | .name = "SST 39SF020A", |
@@ -1412,6 +1415,18 @@ static const struct amd_flash_info jedec_table[] = { | |||
1412 | ERASEINFO(0x1000,256) | 1415 | ERASEINFO(0x1000,256) |
1413 | } | 1416 | } |
1414 | }, { | 1417 | }, { |
1418 | .mfr_id = MANUFACTURER_SST, | ||
1419 | .dev_id = SST36VF3203, | ||
1420 | .name = "SST 36VF3203", | ||
1421 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, | ||
1422 | .uaddr = MTD_UADDR_0x0AAA_0x0555, | ||
1423 | .dev_size = SIZE_4MiB, | ||
1424 | .cmd_set = P_ID_AMD_STD, | ||
1425 | .nr_regions = 1, | ||
1426 | .regions = { | ||
1427 | ERASEINFO(0x10000,64), | ||
1428 | } | ||
1429 | }, { | ||
1415 | .mfr_id = MANUFACTURER_ST, | 1430 | .mfr_id = MANUFACTURER_ST, |
1416 | .dev_id = M29F800AB, | 1431 | .dev_id = M29F800AB, |
1417 | .name = "ST M29F800AB", | 1432 | .name = "ST M29F800AB", |
@@ -1426,7 +1441,7 @@ static const struct amd_flash_info jedec_table[] = { | |||
1426 | ERASEINFO(0x08000,1), | 1441 | ERASEINFO(0x08000,1), |
1427 | ERASEINFO(0x10000,15), | 1442 | ERASEINFO(0x10000,15), |
1428 | } | 1443 | } |
1429 | }, { | 1444 | }, { |
1430 | .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ | 1445 | .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ |
1431 | .dev_id = M29W800DT, | 1446 | .dev_id = M29W800DT, |
1432 | .name = "ST M29W800DT", | 1447 | .name = "ST M29W800DT", |
@@ -1456,6 +1471,36 @@ static const struct amd_flash_info jedec_table[] = { | |||
1456 | ERASEINFO(0x08000,1), | 1471 | ERASEINFO(0x08000,1), |
1457 | ERASEINFO(0x10000,15) | 1472 | ERASEINFO(0x10000,15) |
1458 | } | 1473 | } |
1474 | }, { | ||
1475 | .mfr_id = MANUFACTURER_ST, | ||
1476 | .dev_id = M29W400DT, | ||
1477 | .name = "ST M29W400DT", | ||
1478 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, | ||
1479 | .uaddr = MTD_UADDR_0x0AAA_0x0555, | ||
1480 | .dev_size = SIZE_512KiB, | ||
1481 | .cmd_set = P_ID_AMD_STD, | ||
1482 | .nr_regions = 4, | ||
1483 | .regions = { | ||
1484 | ERASEINFO(0x04000,7), | ||
1485 | ERASEINFO(0x02000,1), | ||
1486 | ERASEINFO(0x08000,2), | ||
1487 | ERASEINFO(0x10000,1) | ||
1488 | } | ||
1489 | }, { | ||
1490 | .mfr_id = MANUFACTURER_ST, | ||
1491 | .dev_id = M29W400DB, | ||
1492 | .name = "ST M29W400DB", | ||
1493 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, | ||
1494 | .uaddr = MTD_UADDR_0x0AAA_0x0555, | ||
1495 | .dev_size = SIZE_512KiB, | ||
1496 | .cmd_set = P_ID_AMD_STD, | ||
1497 | .nr_regions = 4, | ||
1498 | .regions = { | ||
1499 | ERASEINFO(0x04000,1), | ||
1500 | ERASEINFO(0x02000,2), | ||
1501 | ERASEINFO(0x08000,1), | ||
1502 | ERASEINFO(0x10000,7) | ||
1503 | } | ||
1459 | }, { | 1504 | }, { |
1460 | .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ | 1505 | .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ |
1461 | .dev_id = M29W160DT, | 1506 | .dev_id = M29W160DT, |
@@ -1486,7 +1531,7 @@ static const struct amd_flash_info jedec_table[] = { | |||
1486 | ERASEINFO(0x08000,1), | 1531 | ERASEINFO(0x08000,1), |
1487 | ERASEINFO(0x10000,31) | 1532 | ERASEINFO(0x10000,31) |
1488 | } | 1533 | } |
1489 | }, { | 1534 | }, { |
1490 | .mfr_id = MANUFACTURER_ST, | 1535 | .mfr_id = MANUFACTURER_ST, |
1491 | .dev_id = M29W040B, | 1536 | .dev_id = M29W040B, |
1492 | .name = "ST M29W040B", | 1537 | .name = "ST M29W040B", |
@@ -1498,7 +1543,7 @@ static const struct amd_flash_info jedec_table[] = { | |||
1498 | .regions = { | 1543 | .regions = { |
1499 | ERASEINFO(0x10000,8), | 1544 | ERASEINFO(0x10000,8), |
1500 | } | 1545 | } |
1501 | }, { | 1546 | }, { |
1502 | .mfr_id = MANUFACTURER_ST, | 1547 | .mfr_id = MANUFACTURER_ST, |
1503 | .dev_id = M50FW040, | 1548 | .dev_id = M50FW040, |
1504 | .name = "ST M50FW040", | 1549 | .name = "ST M50FW040", |
@@ -1510,7 +1555,7 @@ static const struct amd_flash_info jedec_table[] = { | |||
1510 | .regions = { | 1555 | .regions = { |
1511 | ERASEINFO(0x10000,8), | 1556 | ERASEINFO(0x10000,8), |
1512 | } | 1557 | } |
1513 | }, { | 1558 | }, { |
1514 | .mfr_id = MANUFACTURER_ST, | 1559 | .mfr_id = MANUFACTURER_ST, |
1515 | .dev_id = M50FW080, | 1560 | .dev_id = M50FW080, |
1516 | .name = "ST M50FW080", | 1561 | .name = "ST M50FW080", |
@@ -1522,7 +1567,7 @@ static const struct amd_flash_info jedec_table[] = { | |||
1522 | .regions = { | 1567 | .regions = { |
1523 | ERASEINFO(0x10000,16), | 1568 | ERASEINFO(0x10000,16), |
1524 | } | 1569 | } |
1525 | }, { | 1570 | }, { |
1526 | .mfr_id = MANUFACTURER_ST, | 1571 | .mfr_id = MANUFACTURER_ST, |
1527 | .dev_id = M50FW016, | 1572 | .dev_id = M50FW016, |
1528 | .name = "ST M50FW016", | 1573 | .name = "ST M50FW016", |
diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index b44292abd9f7..e472a0e9de9d 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c | |||
@@ -119,7 +119,8 @@ static struct mtd_partition * newpart(char *s, | |||
119 | char *p; | 119 | char *p; |
120 | 120 | ||
121 | name = ++s; | 121 | name = ++s; |
122 | if ((p = strchr(name, delim)) == 0) | 122 | p = strchr(name, delim); |
123 | if (!p) | ||
123 | { | 124 | { |
124 | printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim); | 125 | printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim); |
125 | return NULL; | 126 | return NULL; |
@@ -159,9 +160,10 @@ static struct mtd_partition * newpart(char *s, | |||
159 | return NULL; | 160 | return NULL; |
160 | } | 161 | } |
161 | /* more partitions follow, parse them */ | 162 | /* more partitions follow, parse them */ |
162 | if ((parts = newpart(s + 1, &s, num_parts, | 163 | parts = newpart(s + 1, &s, num_parts, this_part + 1, |
163 | this_part + 1, &extra_mem, extra_mem_size)) == 0) | 164 | &extra_mem, extra_mem_size); |
164 | return NULL; | 165 | if (!parts) |
166 | return NULL; | ||
165 | } | 167 | } |
166 | else | 168 | else |
167 | { /* this is the last partition: allocate space for all */ | 169 | { /* this is the last partition: allocate space for all */ |
@@ -308,9 +310,6 @@ static int parse_cmdline_partitions(struct mtd_info *master, | |||
308 | struct cmdline_mtd_partition *part; | 310 | struct cmdline_mtd_partition *part; |
309 | char *mtd_id = master->name; | 311 | char *mtd_id = master->name; |
310 | 312 | ||
311 | if(!cmdline) | ||
312 | return -EINVAL; | ||
313 | |||
314 | /* parse command line */ | 313 | /* parse command line */ |
315 | if (!cmdline_parsed) | 314 | if (!cmdline_parsed) |
316 | mtdpart_setup_real(cmdline); | 315 | mtdpart_setup_real(cmdline); |
@@ -341,7 +340,7 @@ static int parse_cmdline_partitions(struct mtd_info *master, | |||
341 | return part->num_parts; | 340 | return part->num_parts; |
342 | } | 341 | } |
343 | } | 342 | } |
344 | return -EINVAL; | 343 | return 0; |
345 | } | 344 | } |
346 | 345 | ||
347 | 346 | ||
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 811d56fd890f..35ed1103dbb2 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig | |||
@@ -77,6 +77,13 @@ config MTD_M25P80 | |||
77 | if you want to specify device partitioning or to use a device which | 77 | if you want to specify device partitioning or to use a device which |
78 | doesn't support the JEDEC ID instruction. | 78 | doesn't support the JEDEC ID instruction. |
79 | 79 | ||
80 | config M25PXX_USE_FAST_READ | ||
81 | bool "Use FAST_READ OPCode allowing SPI CLK <= 50MHz" | ||
82 | depends on MTD_M25P80 | ||
83 | default y | ||
84 | help | ||
85 | This option enables FAST_READ access supported by ST M25Pxx. | ||
86 | |||
80 | config MTD_SLRAM | 87 | config MTD_SLRAM |
81 | tristate "Uncached system RAM" | 88 | tristate "Uncached system RAM" |
82 | help | 89 | help |
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index ad1880c67518..519d942e7940 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c | |||
@@ -305,7 +305,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) | |||
305 | } | 305 | } |
306 | list_add(&dev->list, &blkmtd_device_list); | 306 | list_add(&dev->list, &blkmtd_device_list); |
307 | INFO("mtd%d: [%s] erase_size = %dKiB [%d]", dev->mtd.index, | 307 | INFO("mtd%d: [%s] erase_size = %dKiB [%d]", dev->mtd.index, |
308 | dev->mtd.name + strlen("blkmtd: "), | 308 | dev->mtd.name + strlen("block2mtd: "), |
309 | dev->mtd.erasesize >> 10, dev->mtd.erasesize); | 309 | dev->mtd.erasesize >> 10, dev->mtd.erasesize); |
310 | return dev; | 310 | return dev; |
311 | 311 | ||
@@ -366,9 +366,9 @@ static inline void kill_final_newline(char *str) | |||
366 | } | 366 | } |
367 | 367 | ||
368 | 368 | ||
369 | #define parse_err(fmt, args...) do { \ | 369 | #define parse_err(fmt, args...) do { \ |
370 | ERROR("block2mtd: " fmt "\n", ## args); \ | 370 | ERROR(fmt, ## args); \ |
371 | return 0; \ | 371 | return 0; \ |
372 | } while (0) | 372 | } while (0) |
373 | 373 | ||
374 | #ifndef MODULE | 374 | #ifndef MODULE |
@@ -473,7 +473,7 @@ static void __devexit block2mtd_exit(void) | |||
473 | block2mtd_sync(&dev->mtd); | 473 | block2mtd_sync(&dev->mtd); |
474 | del_mtd_device(&dev->mtd); | 474 | del_mtd_device(&dev->mtd); |
475 | INFO("mtd%d: [%s] removed", dev->mtd.index, | 475 | INFO("mtd%d: [%s] removed", dev->mtd.index, |
476 | dev->mtd.name + strlen("blkmtd: ")); | 476 | dev->mtd.name + strlen("block2mtd: ")); |
477 | list_del(&dev->list); | 477 | list_del(&dev->list); |
478 | block2mtd_free_device(dev); | 478 | block2mtd_free_device(dev); |
479 | } | 479 | } |
diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index 99fd210feaec..1d324e5c412d 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c | |||
@@ -275,7 +275,7 @@ static __u8 read8 (__u32 offset) | |||
275 | { | 275 | { |
276 | volatile __u8 *data = (__u8 *) (FLASH_OFFSET + offset); | 276 | volatile __u8 *data = (__u8 *) (FLASH_OFFSET + offset); |
277 | #ifdef LART_DEBUG | 277 | #ifdef LART_DEBUG |
278 | printk (KERN_DEBUG "%s(): 0x%.8x -> 0x%.2x\n",__FUNCTION__,offset,*data); | 278 | printk (KERN_DEBUG "%s(): 0x%.8x -> 0x%.2x\n", __func__, offset, *data); |
279 | #endif | 279 | #endif |
280 | return (*data); | 280 | return (*data); |
281 | } | 281 | } |
@@ -284,7 +284,7 @@ static __u32 read32 (__u32 offset) | |||
284 | { | 284 | { |
285 | volatile __u32 *data = (__u32 *) (FLASH_OFFSET + offset); | 285 | volatile __u32 *data = (__u32 *) (FLASH_OFFSET + offset); |
286 | #ifdef LART_DEBUG | 286 | #ifdef LART_DEBUG |
287 | printk (KERN_DEBUG "%s(): 0x%.8x -> 0x%.8x\n",__FUNCTION__,offset,*data); | 287 | printk (KERN_DEBUG "%s(): 0x%.8x -> 0x%.8x\n", __func__, offset, *data); |
288 | #endif | 288 | #endif |
289 | return (*data); | 289 | return (*data); |
290 | } | 290 | } |
@@ -294,7 +294,7 @@ static void write32 (__u32 x,__u32 offset) | |||
294 | volatile __u32 *data = (__u32 *) (FLASH_OFFSET + offset); | 294 | volatile __u32 *data = (__u32 *) (FLASH_OFFSET + offset); |
295 | *data = x; | 295 | *data = x; |
296 | #ifdef LART_DEBUG | 296 | #ifdef LART_DEBUG |
297 | printk (KERN_DEBUG "%s(): 0x%.8x <- 0x%.8x\n",__FUNCTION__,offset,*data); | 297 | printk (KERN_DEBUG "%s(): 0x%.8x <- 0x%.8x\n", __func__, offset, *data); |
298 | #endif | 298 | #endif |
299 | } | 299 | } |
300 | 300 | ||
@@ -337,7 +337,7 @@ static inline int erase_block (__u32 offset) | |||
337 | __u32 status; | 337 | __u32 status; |
338 | 338 | ||
339 | #ifdef LART_DEBUG | 339 | #ifdef LART_DEBUG |
340 | printk (KERN_DEBUG "%s(): 0x%.8x\n",__FUNCTION__,offset); | 340 | printk (KERN_DEBUG "%s(): 0x%.8x\n", __func__, offset); |
341 | #endif | 341 | #endif |
342 | 342 | ||
343 | /* erase and confirm */ | 343 | /* erase and confirm */ |
@@ -371,7 +371,7 @@ static int flash_erase (struct mtd_info *mtd,struct erase_info *instr) | |||
371 | int i,first; | 371 | int i,first; |
372 | 372 | ||
373 | #ifdef LART_DEBUG | 373 | #ifdef LART_DEBUG |
374 | printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n",__FUNCTION__,instr->addr,instr->len); | 374 | printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n", __func__, instr->addr, instr->len); |
375 | #endif | 375 | #endif |
376 | 376 | ||
377 | /* sanity checks */ | 377 | /* sanity checks */ |
@@ -442,7 +442,7 @@ static int flash_erase (struct mtd_info *mtd,struct erase_info *instr) | |||
442 | static int flash_read (struct mtd_info *mtd,loff_t from,size_t len,size_t *retlen,u_char *buf) | 442 | static int flash_read (struct mtd_info *mtd,loff_t from,size_t len,size_t *retlen,u_char *buf) |
443 | { | 443 | { |
444 | #ifdef LART_DEBUG | 444 | #ifdef LART_DEBUG |
445 | printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n",__FUNCTION__,(__u32) from,len); | 445 | printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n", __func__, (__u32)from, len); |
446 | #endif | 446 | #endif |
447 | 447 | ||
448 | /* sanity checks */ | 448 | /* sanity checks */ |
@@ -488,7 +488,7 @@ static inline int write_dword (__u32 offset,__u32 x) | |||
488 | __u32 status; | 488 | __u32 status; |
489 | 489 | ||
490 | #ifdef LART_DEBUG | 490 | #ifdef LART_DEBUG |
491 | printk (KERN_DEBUG "%s(): 0x%.8x <- 0x%.8x\n",__FUNCTION__,offset,x); | 491 | printk (KERN_DEBUG "%s(): 0x%.8x <- 0x%.8x\n", __func__, offset, x); |
492 | #endif | 492 | #endif |
493 | 493 | ||
494 | /* setup writing */ | 494 | /* setup writing */ |
@@ -524,7 +524,7 @@ static int flash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen | |||
524 | int i,n; | 524 | int i,n; |
525 | 525 | ||
526 | #ifdef LART_DEBUG | 526 | #ifdef LART_DEBUG |
527 | printk (KERN_DEBUG "%s(to = 0x%.8x, len = %d)\n",__FUNCTION__,(__u32) to,len); | 527 | printk (KERN_DEBUG "%s(to = 0x%.8x, len = %d)\n", __func__, (__u32)to, len); |
528 | #endif | 528 | #endif |
529 | 529 | ||
530 | *retlen = 0; | 530 | *retlen = 0; |
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 98df5bcc02f3..25efd331ef28 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c | |||
@@ -33,7 +33,7 @@ | |||
33 | /* Flash opcodes. */ | 33 | /* Flash opcodes. */ |
34 | #define OPCODE_WREN 0x06 /* Write enable */ | 34 | #define OPCODE_WREN 0x06 /* Write enable */ |
35 | #define OPCODE_RDSR 0x05 /* Read status register */ | 35 | #define OPCODE_RDSR 0x05 /* Read status register */ |
36 | #define OPCODE_READ 0x03 /* Read data bytes (low frequency) */ | 36 | #define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */ |
37 | #define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ | 37 | #define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ |
38 | #define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ | 38 | #define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ |
39 | #define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ | 39 | #define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ |
@@ -52,7 +52,15 @@ | |||
52 | 52 | ||
53 | /* Define max times to check status register before we give up. */ | 53 | /* Define max times to check status register before we give up. */ |
54 | #define MAX_READY_WAIT_COUNT 100000 | 54 | #define MAX_READY_WAIT_COUNT 100000 |
55 | #define CMD_SIZE 4 | ||
55 | 56 | ||
57 | #ifdef CONFIG_M25PXX_USE_FAST_READ | ||
58 | #define OPCODE_READ OPCODE_FAST_READ | ||
59 | #define FAST_READ_DUMMY_BYTE 1 | ||
60 | #else | ||
61 | #define OPCODE_READ OPCODE_NORM_READ | ||
62 | #define FAST_READ_DUMMY_BYTE 0 | ||
63 | #endif | ||
56 | 64 | ||
57 | #ifdef CONFIG_MTD_PARTITIONS | 65 | #ifdef CONFIG_MTD_PARTITIONS |
58 | #define mtd_has_partitions() (1) | 66 | #define mtd_has_partitions() (1) |
@@ -68,7 +76,7 @@ struct m25p { | |||
68 | struct mtd_info mtd; | 76 | struct mtd_info mtd; |
69 | unsigned partitioned:1; | 77 | unsigned partitioned:1; |
70 | u8 erase_opcode; | 78 | u8 erase_opcode; |
71 | u8 command[4]; | 79 | u8 command[CMD_SIZE + FAST_READ_DUMMY_BYTE]; |
72 | }; | 80 | }; |
73 | 81 | ||
74 | static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd) | 82 | static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd) |
@@ -151,7 +159,7 @@ static int wait_till_ready(struct m25p *flash) | |||
151 | static int erase_sector(struct m25p *flash, u32 offset) | 159 | static int erase_sector(struct m25p *flash, u32 offset) |
152 | { | 160 | { |
153 | DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB at 0x%08x\n", | 161 | DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB at 0x%08x\n", |
154 | flash->spi->dev.bus_id, __FUNCTION__, | 162 | flash->spi->dev.bus_id, __func__, |
155 | flash->mtd.erasesize / 1024, offset); | 163 | flash->mtd.erasesize / 1024, offset); |
156 | 164 | ||
157 | /* Wait until finished previous write command. */ | 165 | /* Wait until finished previous write command. */ |
@@ -167,7 +175,7 @@ static int erase_sector(struct m25p *flash, u32 offset) | |||
167 | flash->command[2] = offset >> 8; | 175 | flash->command[2] = offset >> 8; |
168 | flash->command[3] = offset; | 176 | flash->command[3] = offset; |
169 | 177 | ||
170 | spi_write(flash->spi, flash->command, sizeof(flash->command)); | 178 | spi_write(flash->spi, flash->command, CMD_SIZE); |
171 | 179 | ||
172 | return 0; | 180 | return 0; |
173 | } | 181 | } |
@@ -188,7 +196,7 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
188 | u32 addr,len; | 196 | u32 addr,len; |
189 | 197 | ||
190 | DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n", | 198 | DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n", |
191 | flash->spi->dev.bus_id, __FUNCTION__, "at", | 199 | flash->spi->dev.bus_id, __func__, "at", |
192 | (u32)instr->addr, instr->len); | 200 | (u32)instr->addr, instr->len); |
193 | 201 | ||
194 | /* sanity checks */ | 202 | /* sanity checks */ |
@@ -240,7 +248,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
240 | struct spi_message m; | 248 | struct spi_message m; |
241 | 249 | ||
242 | DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", | 250 | DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", |
243 | flash->spi->dev.bus_id, __FUNCTION__, "from", | 251 | flash->spi->dev.bus_id, __func__, "from", |
244 | (u32)from, len); | 252 | (u32)from, len); |
245 | 253 | ||
246 | /* sanity checks */ | 254 | /* sanity checks */ |
@@ -253,8 +261,12 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
253 | spi_message_init(&m); | 261 | spi_message_init(&m); |
254 | memset(t, 0, (sizeof t)); | 262 | memset(t, 0, (sizeof t)); |
255 | 263 | ||
264 | /* NOTE: | ||
265 | * OPCODE_FAST_READ (if available) is faster. | ||
266 | * Should add 1 byte DUMMY_BYTE. | ||
267 | */ | ||
256 | t[0].tx_buf = flash->command; | 268 | t[0].tx_buf = flash->command; |
257 | t[0].len = sizeof(flash->command); | 269 | t[0].len = CMD_SIZE + FAST_READ_DUMMY_BYTE; |
258 | spi_message_add_tail(&t[0], &m); | 270 | spi_message_add_tail(&t[0], &m); |
259 | 271 | ||
260 | t[1].rx_buf = buf; | 272 | t[1].rx_buf = buf; |
@@ -287,7 +299,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
287 | 299 | ||
288 | spi_sync(flash->spi, &m); | 300 | spi_sync(flash->spi, &m); |
289 | 301 | ||
290 | *retlen = m.actual_length - sizeof(flash->command); | 302 | *retlen = m.actual_length - CMD_SIZE - FAST_READ_DUMMY_BYTE; |
291 | 303 | ||
292 | mutex_unlock(&flash->lock); | 304 | mutex_unlock(&flash->lock); |
293 | 305 | ||
@@ -308,7 +320,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
308 | struct spi_message m; | 320 | struct spi_message m; |
309 | 321 | ||
310 | DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", | 322 | DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", |
311 | flash->spi->dev.bus_id, __FUNCTION__, "to", | 323 | flash->spi->dev.bus_id, __func__, "to", |
312 | (u32)to, len); | 324 | (u32)to, len); |
313 | 325 | ||
314 | if (retlen) | 326 | if (retlen) |
@@ -325,7 +337,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
325 | memset(t, 0, (sizeof t)); | 337 | memset(t, 0, (sizeof t)); |
326 | 338 | ||
327 | t[0].tx_buf = flash->command; | 339 | t[0].tx_buf = flash->command; |
328 | t[0].len = sizeof(flash->command); | 340 | t[0].len = CMD_SIZE; |
329 | spi_message_add_tail(&t[0], &m); | 341 | spi_message_add_tail(&t[0], &m); |
330 | 342 | ||
331 | t[1].tx_buf = buf; | 343 | t[1].tx_buf = buf; |
@@ -354,7 +366,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
354 | 366 | ||
355 | spi_sync(flash->spi, &m); | 367 | spi_sync(flash->spi, &m); |
356 | 368 | ||
357 | *retlen = m.actual_length - sizeof(flash->command); | 369 | *retlen = m.actual_length - CMD_SIZE; |
358 | } else { | 370 | } else { |
359 | u32 i; | 371 | u32 i; |
360 | 372 | ||
@@ -364,7 +376,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
364 | t[1].len = page_size; | 376 | t[1].len = page_size; |
365 | spi_sync(flash->spi, &m); | 377 | spi_sync(flash->spi, &m); |
366 | 378 | ||
367 | *retlen = m.actual_length - sizeof(flash->command); | 379 | *retlen = m.actual_length - CMD_SIZE; |
368 | 380 | ||
369 | /* write everything in PAGESIZE chunks */ | 381 | /* write everything in PAGESIZE chunks */ |
370 | for (i = page_size; i < len; i += page_size) { | 382 | for (i = page_size; i < len; i += page_size) { |
@@ -387,8 +399,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
387 | spi_sync(flash->spi, &m); | 399 | spi_sync(flash->spi, &m); |
388 | 400 | ||
389 | if (retlen) | 401 | if (retlen) |
390 | *retlen += m.actual_length | 402 | *retlen += m.actual_length - CMD_SIZE; |
391 | - sizeof(flash->command); | ||
392 | } | 403 | } |
393 | } | 404 | } |
394 | 405 | ||
@@ -435,6 +446,7 @@ static struct flash_info __devinitdata m25p_data [] = { | |||
435 | { "at25fs040", 0x1f6604, 64 * 1024, 8, SECT_4K, }, | 446 | { "at25fs040", 0x1f6604, 64 * 1024, 8, SECT_4K, }, |
436 | 447 | ||
437 | { "at25df041a", 0x1f4401, 64 * 1024, 8, SECT_4K, }, | 448 | { "at25df041a", 0x1f4401, 64 * 1024, 8, SECT_4K, }, |
449 | { "at25df641", 0x1f4800, 64 * 1024, 128, SECT_4K, }, | ||
438 | 450 | ||
439 | { "at26f004", 0x1f0400, 64 * 1024, 8, SECT_4K, }, | 451 | { "at26f004", 0x1f0400, 64 * 1024, 8, SECT_4K, }, |
440 | { "at26df081a", 0x1f4501, 64 * 1024, 16, SECT_4K, }, | 452 | { "at26df081a", 0x1f4501, 64 * 1024, 16, SECT_4K, }, |
diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index e427c82d5f4c..bf485ff49457 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/mtd/compatmac.h> | 18 | #include <linux/mtd/compatmac.h> |
19 | #include <linux/mtd/mtd.h> | 19 | #include <linux/mtd/mtd.h> |
20 | #include <linux/mtd/mtdram.h> | ||
20 | 21 | ||
21 | static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE; | 22 | static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE; |
22 | static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE; | 23 | static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE; |
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 180298b92a7a..5f960182da95 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c | |||
@@ -282,7 +282,7 @@ static int phram_setup(const char *val, struct kernel_param *kp) | |||
282 | } | 282 | } |
283 | 283 | ||
284 | module_param_call(phram, phram_setup, NULL, NULL, 000); | 284 | module_param_call(phram, phram_setup, NULL, NULL, 000); |
285 | MODULE_PARM_DESC(phram,"Memory region to map. \"map=<name>,<start>,<length>\""); | 285 | MODULE_PARM_DESC(phram, "Memory region to map. \"phram=<name>,<start>,<length>\""); |
286 | 286 | ||
287 | 287 | ||
288 | static int __init init_phram(void) | 288 | static int __init init_phram(void) |
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index c815d0f38577..4a79b187b568 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c | |||
@@ -136,8 +136,6 @@ typedef struct partition_t { | |||
136 | #endif | 136 | #endif |
137 | } partition_t; | 137 | } partition_t; |
138 | 138 | ||
139 | void ftl_freepart(partition_t *part); | ||
140 | |||
141 | /* Partition state flags */ | 139 | /* Partition state flags */ |
142 | #define FTL_FORMATTED 0x01 | 140 | #define FTL_FORMATTED 0x01 |
143 | 141 | ||
@@ -1014,7 +1012,7 @@ static int ftl_writesect(struct mtd_blktrans_dev *dev, | |||
1014 | 1012 | ||
1015 | /*====================================================================*/ | 1013 | /*====================================================================*/ |
1016 | 1014 | ||
1017 | void ftl_freepart(partition_t *part) | 1015 | static void ftl_freepart(partition_t *part) |
1018 | { | 1016 | { |
1019 | vfree(part->VirtualBlockMap); | 1017 | vfree(part->VirtualBlockMap); |
1020 | part->VirtualBlockMap = NULL; | 1018 | part->VirtualBlockMap = NULL; |
@@ -1069,7 +1067,7 @@ static void ftl_remove_dev(struct mtd_blktrans_dev *dev) | |||
1069 | kfree(dev); | 1067 | kfree(dev); |
1070 | } | 1068 | } |
1071 | 1069 | ||
1072 | struct mtd_blktrans_ops ftl_tr = { | 1070 | static struct mtd_blktrans_ops ftl_tr = { |
1073 | .name = "ftl", | 1071 | .name = "ftl", |
1074 | .major = FTL_MAJOR, | 1072 | .major = FTL_MAJOR, |
1075 | .part_bits = PART_BITS, | 1073 | .part_bits = PART_BITS, |
diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index b8917beeb650..c551d2f0779c 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c | |||
@@ -41,11 +41,6 @@ | |||
41 | 41 | ||
42 | char inftlmountrev[]="$Revision: 1.18 $"; | 42 | char inftlmountrev[]="$Revision: 1.18 $"; |
43 | 43 | ||
44 | extern int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, | ||
45 | size_t *retlen, uint8_t *buf); | ||
46 | extern int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, | ||
47 | size_t *retlen, uint8_t *buf); | ||
48 | |||
49 | /* | 44 | /* |
50 | * find_boot_record: Find the INFTL Media Header and its Spare copy which | 45 | * find_boot_record: Find the INFTL Media Header and its Spare copy which |
51 | * contains the various device information of the INFTL partition and | 46 | * contains the various device information of the INFTL partition and |
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 12c253664eb2..1bd69aa9e22a 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig | |||
@@ -21,6 +21,9 @@ config MTD_PHYSMAP | |||
21 | particular board as well as the bus width, either statically | 21 | particular board as well as the bus width, either statically |
22 | with config options or at run-time. | 22 | with config options or at run-time. |
23 | 23 | ||
24 | To compile this driver as a module, choose M here: the | ||
25 | module will be called physmap. | ||
26 | |||
24 | config MTD_PHYSMAP_START | 27 | config MTD_PHYSMAP_START |
25 | hex "Physical start address of flash mapping" | 28 | hex "Physical start address of flash mapping" |
26 | depends on MTD_PHYSMAP | 29 | depends on MTD_PHYSMAP |
diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c index fc3b2672d1e2..1f492062f8ca 100644 --- a/drivers/mtd/maps/bast-flash.c +++ b/drivers/mtd/maps/bast-flash.c | |||
@@ -137,7 +137,7 @@ static int bast_flash_probe(struct platform_device *pdev) | |||
137 | if (info->map.size > AREA_MAXSIZE) | 137 | if (info->map.size > AREA_MAXSIZE) |
138 | info->map.size = AREA_MAXSIZE; | 138 | info->map.size = AREA_MAXSIZE; |
139 | 139 | ||
140 | pr_debug("%s: area %08lx, size %ld\n", __FUNCTION__, | 140 | pr_debug("%s: area %08lx, size %ld\n", __func__, |
141 | info->map.phys, info->map.size); | 141 | info->map.phys, info->map.size); |
142 | 142 | ||
143 | info->area = request_mem_region(res->start, info->map.size, | 143 | info->area = request_mem_region(res->start, info->map.size, |
@@ -149,7 +149,7 @@ static int bast_flash_probe(struct platform_device *pdev) | |||
149 | } | 149 | } |
150 | 150 | ||
151 | info->map.virt = ioremap(res->start, info->map.size); | 151 | info->map.virt = ioremap(res->start, info->map.size); |
152 | pr_debug("%s: virt at %08x\n", __FUNCTION__, (int)info->map.virt); | 152 | pr_debug("%s: virt at %08x\n", __func__, (int)info->map.virt); |
153 | 153 | ||
154 | if (info->map.virt == 0) { | 154 | if (info->map.virt == 0) { |
155 | printk(KERN_ERR PFX "failed to ioremap() region\n"); | 155 | printk(KERN_ERR PFX "failed to ioremap() region\n"); |
@@ -223,3 +223,4 @@ module_exit(bast_flash_exit); | |||
223 | MODULE_LICENSE("GPL"); | 223 | MODULE_LICENSE("GPL"); |
224 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | 224 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); |
225 | MODULE_DESCRIPTION("BAST MTD Map driver"); | 225 | MODULE_DESCRIPTION("BAST MTD Map driver"); |
226 | MODULE_ALIAS("platform:bast-nor"); | ||
diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c index 688ef495888a..59d8fb49270a 100644 --- a/drivers/mtd/maps/ck804xrom.c +++ b/drivers/mtd/maps/ck804xrom.c | |||
@@ -28,6 +28,9 @@ | |||
28 | 28 | ||
29 | #define ROM_PROBE_STEP_SIZE (64*1024) | 29 | #define ROM_PROBE_STEP_SIZE (64*1024) |
30 | 30 | ||
31 | #define DEV_CK804 1 | ||
32 | #define DEV_MCP55 2 | ||
33 | |||
31 | struct ck804xrom_window { | 34 | struct ck804xrom_window { |
32 | void __iomem *virt; | 35 | void __iomem *virt; |
33 | unsigned long phys; | 36 | unsigned long phys; |
@@ -45,8 +48,9 @@ struct ck804xrom_map_info { | |||
45 | char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN]; | 48 | char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN]; |
46 | }; | 49 | }; |
47 | 50 | ||
48 | 51 | /* | |
49 | /* The 2 bits controlling the window size are often set to allow reading | 52 | * The following applies to ck804 only: |
53 | * The 2 bits controlling the window size are often set to allow reading | ||
50 | * the BIOS, but too small to allow writing, since the lock registers are | 54 | * the BIOS, but too small to allow writing, since the lock registers are |
51 | * 4MiB lower in the address space than the data. | 55 | * 4MiB lower in the address space than the data. |
52 | * | 56 | * |
@@ -58,10 +62,17 @@ struct ck804xrom_map_info { | |||
58 | * If only the 7 Bit is set, it is a 4MiB window. Otherwise, a | 62 | * If only the 7 Bit is set, it is a 4MiB window. Otherwise, a |
59 | * 64KiB window. | 63 | * 64KiB window. |
60 | * | 64 | * |
65 | * The following applies to mcp55 only: | ||
66 | * The 15 bits controlling the window size are distributed as follows: | ||
67 | * byte @0x88: bit 0..7 | ||
68 | * byte @0x8c: bit 8..15 | ||
69 | * word @0x90: bit 16..30 | ||
70 | * If all bits are enabled, we have a 16? MiB window | ||
71 | * Please set win_size_bits to 0x7fffffff if you actually want to do something | ||
61 | */ | 72 | */ |
62 | static uint win_size_bits = 0; | 73 | static uint win_size_bits = 0; |
63 | module_param(win_size_bits, uint, 0); | 74 | module_param(win_size_bits, uint, 0); |
64 | MODULE_PARM_DESC(win_size_bits, "ROM window size bits override for 0x88 byte, normally set by BIOS."); | 75 | MODULE_PARM_DESC(win_size_bits, "ROM window size bits override, normally set by BIOS."); |
65 | 76 | ||
66 | static struct ck804xrom_window ck804xrom_window = { | 77 | static struct ck804xrom_window ck804xrom_window = { |
67 | .maps = LIST_HEAD_INIT(ck804xrom_window.maps), | 78 | .maps = LIST_HEAD_INIT(ck804xrom_window.maps), |
@@ -102,10 +113,11 @@ static void ck804xrom_cleanup(struct ck804xrom_window *window) | |||
102 | 113 | ||
103 | 114 | ||
104 | static int __devinit ck804xrom_init_one (struct pci_dev *pdev, | 115 | static int __devinit ck804xrom_init_one (struct pci_dev *pdev, |
105 | const struct pci_device_id *ent) | 116 | const struct pci_device_id *ent) |
106 | { | 117 | { |
107 | static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; | 118 | static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; |
108 | u8 byte; | 119 | u8 byte; |
120 | u16 word; | ||
109 | struct ck804xrom_window *window = &ck804xrom_window; | 121 | struct ck804xrom_window *window = &ck804xrom_window; |
110 | struct ck804xrom_map_info *map = NULL; | 122 | struct ck804xrom_map_info *map = NULL; |
111 | unsigned long map_top; | 123 | unsigned long map_top; |
@@ -113,26 +125,42 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev, | |||
113 | /* Remember the pci dev I find the window in */ | 125 | /* Remember the pci dev I find the window in */ |
114 | window->pdev = pci_dev_get(pdev); | 126 | window->pdev = pci_dev_get(pdev); |
115 | 127 | ||
116 | /* Enable the selected rom window. This is often incorrectly | 128 | switch (ent->driver_data) { |
117 | * set up by the BIOS, and the 4MiB offset for the lock registers | 129 | case DEV_CK804: |
118 | * requires the full 5MiB of window space. | 130 | /* Enable the selected rom window. This is often incorrectly |
119 | * | 131 | * set up by the BIOS, and the 4MiB offset for the lock registers |
120 | * This 'write, then read' approach leaves the bits for | 132 | * requires the full 5MiB of window space. |
121 | * other uses of the hardware info. | 133 | * |
122 | */ | 134 | * This 'write, then read' approach leaves the bits for |
123 | pci_read_config_byte(pdev, 0x88, &byte); | 135 | * other uses of the hardware info. |
124 | pci_write_config_byte(pdev, 0x88, byte | win_size_bits ); | 136 | */ |
125 | 137 | pci_read_config_byte(pdev, 0x88, &byte); | |
126 | 138 | pci_write_config_byte(pdev, 0x88, byte | win_size_bits ); | |
127 | /* Assume the rom window is properly setup, and find it's size */ | 139 | |
128 | pci_read_config_byte(pdev, 0x88, &byte); | 140 | /* Assume the rom window is properly setup, and find it's size */ |
129 | 141 | pci_read_config_byte(pdev, 0x88, &byte); | |
130 | if ((byte & ((1<<7)|(1<<6))) == ((1<<7)|(1<<6))) | 142 | |
131 | window->phys = 0xffb00000; /* 5MiB */ | 143 | if ((byte & ((1<<7)|(1<<6))) == ((1<<7)|(1<<6))) |
132 | else if ((byte & (1<<7)) == (1<<7)) | 144 | window->phys = 0xffb00000; /* 5MiB */ |
133 | window->phys = 0xffc00000; /* 4MiB */ | 145 | else if ((byte & (1<<7)) == (1<<7)) |
134 | else | 146 | window->phys = 0xffc00000; /* 4MiB */ |
135 | window->phys = 0xffff0000; /* 64KiB */ | 147 | else |
148 | window->phys = 0xffff0000; /* 64KiB */ | ||
149 | break; | ||
150 | |||
151 | case DEV_MCP55: | ||
152 | pci_read_config_byte(pdev, 0x88, &byte); | ||
153 | pci_write_config_byte(pdev, 0x88, byte | (win_size_bits & 0xff)); | ||
154 | |||
155 | pci_read_config_byte(pdev, 0x8c, &byte); | ||
156 | pci_write_config_byte(pdev, 0x8c, byte | ((win_size_bits & 0xff00) >> 8)); | ||
157 | |||
158 | pci_read_config_word(pdev, 0x90, &word); | ||
159 | pci_write_config_word(pdev, 0x90, word | ((win_size_bits & 0x7fff0000) >> 16)); | ||
160 | |||
161 | window->phys = 0xff000000; /* 16MiB, hardcoded for now */ | ||
162 | break; | ||
163 | } | ||
136 | 164 | ||
137 | window->size = 0xffffffffUL - window->phys + 1UL; | 165 | window->size = 0xffffffffUL - window->phys + 1UL; |
138 | 166 | ||
@@ -303,8 +331,15 @@ static void __devexit ck804xrom_remove_one (struct pci_dev *pdev) | |||
303 | } | 331 | } |
304 | 332 | ||
305 | static struct pci_device_id ck804xrom_pci_tbl[] = { | 333 | static struct pci_device_id ck804xrom_pci_tbl[] = { |
306 | { PCI_VENDOR_ID_NVIDIA, 0x0051, | 334 | { PCI_VENDOR_ID_NVIDIA, 0x0051, PCI_ANY_ID, PCI_ANY_ID, DEV_CK804 }, |
307 | PCI_ANY_ID, PCI_ANY_ID, }, /* nvidia ck804 */ | 335 | { PCI_VENDOR_ID_NVIDIA, 0x0360, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 }, |
336 | { PCI_VENDOR_ID_NVIDIA, 0x0361, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 }, | ||
337 | { PCI_VENDOR_ID_NVIDIA, 0x0362, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 }, | ||
338 | { PCI_VENDOR_ID_NVIDIA, 0x0363, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 }, | ||
339 | { PCI_VENDOR_ID_NVIDIA, 0x0364, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 }, | ||
340 | { PCI_VENDOR_ID_NVIDIA, 0x0365, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 }, | ||
341 | { PCI_VENDOR_ID_NVIDIA, 0x0366, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 }, | ||
342 | { PCI_VENDOR_ID_NVIDIA, 0x0367, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 }, | ||
308 | { 0, } | 343 | { 0, } |
309 | }; | 344 | }; |
310 | 345 | ||
@@ -332,7 +367,7 @@ static int __init init_ck804xrom(void) | |||
332 | break; | 367 | break; |
333 | } | 368 | } |
334 | if (pdev) { | 369 | if (pdev) { |
335 | retVal = ck804xrom_init_one(pdev, &ck804xrom_pci_tbl[0]); | 370 | retVal = ck804xrom_init_one(pdev, id); |
336 | pci_dev_put(pdev); | 371 | pci_dev_put(pdev); |
337 | return retVal; | 372 | return retVal; |
338 | } | 373 | } |
diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c index 6946d802e6f6..325c8880c437 100644 --- a/drivers/mtd/maps/integrator-flash.c +++ b/drivers/mtd/maps/integrator-flash.c | |||
@@ -190,6 +190,7 @@ static struct platform_driver armflash_driver = { | |||
190 | .remove = armflash_remove, | 190 | .remove = armflash_remove, |
191 | .driver = { | 191 | .driver = { |
192 | .name = "armflash", | 192 | .name = "armflash", |
193 | .owner = THIS_MODULE, | ||
193 | }, | 194 | }, |
194 | }; | 195 | }; |
195 | 196 | ||
@@ -209,3 +210,4 @@ module_exit(armflash_exit); | |||
209 | MODULE_AUTHOR("ARM Ltd"); | 210 | MODULE_AUTHOR("ARM Ltd"); |
210 | MODULE_DESCRIPTION("ARM Integrator CFI map driver"); | 211 | MODULE_DESCRIPTION("ARM Integrator CFI map driver"); |
211 | MODULE_LICENSE("GPL"); | 212 | MODULE_LICENSE("GPL"); |
213 | MODULE_ALIAS("platform:armflash"); | ||
diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c index c26488a1793a..c8396b8574c4 100644 --- a/drivers/mtd/maps/ixp2000.c +++ b/drivers/mtd/maps/ixp2000.c | |||
@@ -253,6 +253,7 @@ static struct platform_driver ixp2000_flash_driver = { | |||
253 | .remove = ixp2000_flash_remove, | 253 | .remove = ixp2000_flash_remove, |
254 | .driver = { | 254 | .driver = { |
255 | .name = "IXP2000-Flash", | 255 | .name = "IXP2000-Flash", |
256 | .owner = THIS_MODULE, | ||
256 | }, | 257 | }, |
257 | }; | 258 | }; |
258 | 259 | ||
@@ -270,4 +271,4 @@ module_init(ixp2000_flash_init); | |||
270 | module_exit(ixp2000_flash_exit); | 271 | module_exit(ixp2000_flash_exit); |
271 | MODULE_LICENSE("GPL"); | 272 | MODULE_LICENSE("GPL"); |
272 | MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>"); | 273 | MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>"); |
273 | 274 | MODULE_ALIAS("platform:IXP2000-Flash"); | |
diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index 7a828e3e6446..01f19a4714b5 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c | |||
@@ -275,6 +275,7 @@ static struct platform_driver ixp4xx_flash_driver = { | |||
275 | .remove = ixp4xx_flash_remove, | 275 | .remove = ixp4xx_flash_remove, |
276 | .driver = { | 276 | .driver = { |
277 | .name = "IXP4XX-Flash", | 277 | .name = "IXP4XX-Flash", |
278 | .owner = THIS_MODULE, | ||
278 | }, | 279 | }, |
279 | }; | 280 | }; |
280 | 281 | ||
@@ -295,3 +296,4 @@ module_exit(ixp4xx_flash_exit); | |||
295 | MODULE_LICENSE("GPL"); | 296 | MODULE_LICENSE("GPL"); |
296 | MODULE_DESCRIPTION("MTD map driver for Intel IXP4xx systems"); | 297 | MODULE_DESCRIPTION("MTD map driver for Intel IXP4xx systems"); |
297 | MODULE_AUTHOR("Deepak Saxena"); | 298 | MODULE_AUTHOR("Deepak Saxena"); |
299 | MODULE_ALIAS("platform:IXP4XX-Flash"); | ||
diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c index e8d9ae535673..240b0e2d095d 100644 --- a/drivers/mtd/maps/omap_nor.c +++ b/drivers/mtd/maps/omap_nor.c | |||
@@ -70,7 +70,7 @@ static void omap_set_vpp(struct map_info *map, int enable) | |||
70 | } | 70 | } |
71 | } | 71 | } |
72 | 72 | ||
73 | static int __devinit omapflash_probe(struct platform_device *pdev) | 73 | static int __init omapflash_probe(struct platform_device *pdev) |
74 | { | 74 | { |
75 | int err; | 75 | int err; |
76 | struct omapflash_info *info; | 76 | struct omapflash_info *info; |
@@ -130,7 +130,7 @@ out_free_info: | |||
130 | return err; | 130 | return err; |
131 | } | 131 | } |
132 | 132 | ||
133 | static int __devexit omapflash_remove(struct platform_device *pdev) | 133 | static int __exit omapflash_remove(struct platform_device *pdev) |
134 | { | 134 | { |
135 | struct omapflash_info *info = platform_get_drvdata(pdev); | 135 | struct omapflash_info *info = platform_get_drvdata(pdev); |
136 | 136 | ||
@@ -152,16 +152,16 @@ static int __devexit omapflash_remove(struct platform_device *pdev) | |||
152 | } | 152 | } |
153 | 153 | ||
154 | static struct platform_driver omapflash_driver = { | 154 | static struct platform_driver omapflash_driver = { |
155 | .probe = omapflash_probe, | 155 | .remove = __exit_p(omapflash_remove), |
156 | .remove = __devexit_p(omapflash_remove), | ||
157 | .driver = { | 156 | .driver = { |
158 | .name = "omapflash", | 157 | .name = "omapflash", |
158 | .owner = THIS_MODULE, | ||
159 | }, | 159 | }, |
160 | }; | 160 | }; |
161 | 161 | ||
162 | static int __init omapflash_init(void) | 162 | static int __init omapflash_init(void) |
163 | { | 163 | { |
164 | return platform_driver_register(&omapflash_driver); | 164 | return platform_driver_probe(&omapflash_driver, omapflash_probe); |
165 | } | 165 | } |
166 | 166 | ||
167 | static void __exit omapflash_exit(void) | 167 | static void __exit omapflash_exit(void) |
@@ -174,4 +174,4 @@ module_exit(omapflash_exit); | |||
174 | 174 | ||
175 | MODULE_LICENSE("GPL"); | 175 | MODULE_LICENSE("GPL"); |
176 | MODULE_DESCRIPTION("MTD NOR map driver for TI OMAP boards"); | 176 | MODULE_DESCRIPTION("MTD NOR map driver for TI OMAP boards"); |
177 | 177 | MODULE_ALIAS("platform:omapflash"); | |
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index eaeb56a4070a..1912d968718b 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c | |||
@@ -33,7 +33,7 @@ MODULE_PARM_DESC(debug, "Set Debug Level 0=quiet, 5=noisy"); | |||
33 | #undef DEBUG | 33 | #undef DEBUG |
34 | #define DEBUG(n, format, arg...) \ | 34 | #define DEBUG(n, format, arg...) \ |
35 | if (n <= debug) { \ | 35 | if (n <= debug) { \ |
36 | printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \ | 36 | printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \ |
37 | } | 37 | } |
38 | 38 | ||
39 | #else | 39 | #else |
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index bc4649a17b9d..183255fcfdcb 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c | |||
@@ -242,6 +242,7 @@ static struct platform_driver physmap_flash_driver = { | |||
242 | .shutdown = physmap_flash_shutdown, | 242 | .shutdown = physmap_flash_shutdown, |
243 | .driver = { | 243 | .driver = { |
244 | .name = "physmap-flash", | 244 | .name = "physmap-flash", |
245 | .owner = THIS_MODULE, | ||
245 | }, | 246 | }, |
246 | }; | 247 | }; |
247 | 248 | ||
@@ -319,3 +320,10 @@ module_exit(physmap_exit); | |||
319 | MODULE_LICENSE("GPL"); | 320 | MODULE_LICENSE("GPL"); |
320 | MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); | 321 | MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); |
321 | MODULE_DESCRIPTION("Generic configurable MTD map driver"); | 322 | MODULE_DESCRIPTION("Generic configurable MTD map driver"); |
323 | |||
324 | /* legacy platform drivers can't hotplug or coldplg */ | ||
325 | #ifndef PHYSMAP_COMPAT | ||
326 | /* work with hotplug and coldplug */ | ||
327 | MODULE_ALIAS("platform:physmap-flash"); | ||
328 | #endif | ||
329 | |||
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 894c0b271289..f0b10ca05029 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c | |||
@@ -47,6 +47,7 @@ struct platram_info { | |||
47 | struct mtd_info *mtd; | 47 | struct mtd_info *mtd; |
48 | struct map_info map; | 48 | struct map_info map; |
49 | struct mtd_partition *partitions; | 49 | struct mtd_partition *partitions; |
50 | bool free_partitions; | ||
50 | struct resource *area; | 51 | struct resource *area; |
51 | struct platdata_mtd_ram *pdata; | 52 | struct platdata_mtd_ram *pdata; |
52 | }; | 53 | }; |
@@ -98,7 +99,8 @@ static int platram_remove(struct platform_device *pdev) | |||
98 | #ifdef CONFIG_MTD_PARTITIONS | 99 | #ifdef CONFIG_MTD_PARTITIONS |
99 | if (info->partitions) { | 100 | if (info->partitions) { |
100 | del_mtd_partitions(info->mtd); | 101 | del_mtd_partitions(info->mtd); |
101 | kfree(info->partitions); | 102 | if (info->free_partitions) |
103 | kfree(info->partitions); | ||
102 | } | 104 | } |
103 | #endif | 105 | #endif |
104 | del_mtd_device(info->mtd); | 106 | del_mtd_device(info->mtd); |
@@ -176,7 +178,8 @@ static int platram_probe(struct platform_device *pdev) | |||
176 | 178 | ||
177 | info->map.phys = res->start; | 179 | info->map.phys = res->start; |
178 | info->map.size = (res->end - res->start) + 1; | 180 | info->map.size = (res->end - res->start) + 1; |
179 | info->map.name = pdata->mapname != NULL ? pdata->mapname : (char *)pdev->name; | 181 | info->map.name = pdata->mapname != NULL ? |
182 | (char *)pdata->mapname : (char *)pdev->name; | ||
180 | info->map.bankwidth = pdata->bankwidth; | 183 | info->map.bankwidth = pdata->bankwidth; |
181 | 184 | ||
182 | /* register our usage of the memory area */ | 185 | /* register our usage of the memory area */ |
@@ -203,9 +206,19 @@ static int platram_probe(struct platform_device *pdev) | |||
203 | 206 | ||
204 | dev_dbg(&pdev->dev, "initialised map, probing for mtd\n"); | 207 | dev_dbg(&pdev->dev, "initialised map, probing for mtd\n"); |
205 | 208 | ||
206 | /* probe for the right mtd map driver */ | 209 | /* probe for the right mtd map driver |
210 | * supplied by the platform_data struct */ | ||
211 | |||
212 | if (pdata->map_probes != 0) { | ||
213 | const char **map_probes = pdata->map_probes; | ||
214 | |||
215 | for ( ; !info->mtd && *map_probes; map_probes++) | ||
216 | info->mtd = do_map_probe(*map_probes , &info->map); | ||
217 | } | ||
218 | /* fallback to map_ram */ | ||
219 | else | ||
220 | info->mtd = do_map_probe("map_ram", &info->map); | ||
207 | 221 | ||
208 | info->mtd = do_map_probe("map_ram" , &info->map); | ||
209 | if (info->mtd == NULL) { | 222 | if (info->mtd == NULL) { |
210 | dev_err(&pdev->dev, "failed to probe for map_ram\n"); | 223 | dev_err(&pdev->dev, "failed to probe for map_ram\n"); |
211 | err = -ENOMEM; | 224 | err = -ENOMEM; |
@@ -220,19 +233,21 @@ static int platram_probe(struct platform_device *pdev) | |||
220 | * to add this device whole */ | 233 | * to add this device whole */ |
221 | 234 | ||
222 | #ifdef CONFIG_MTD_PARTITIONS | 235 | #ifdef CONFIG_MTD_PARTITIONS |
223 | if (pdata->nr_partitions > 0) { | 236 | if (!pdata->nr_partitions) { |
224 | const char **probes = { NULL }; | 237 | /* try to probe using the supplied probe type */ |
225 | 238 | if (pdata->probes) { | |
226 | if (pdata->probes) | 239 | err = parse_mtd_partitions(info->mtd, pdata->probes, |
227 | probes = (const char **)pdata->probes; | ||
228 | |||
229 | err = parse_mtd_partitions(info->mtd, probes, | ||
230 | &info->partitions, 0); | 240 | &info->partitions, 0); |
231 | if (err > 0) { | 241 | info->free_partitions = 1; |
232 | err = add_mtd_partitions(info->mtd, info->partitions, | 242 | if (err > 0) |
233 | err); | 243 | err = add_mtd_partitions(info->mtd, |
244 | info->partitions, err); | ||
234 | } | 245 | } |
235 | } | 246 | } |
247 | /* use the static mapping */ | ||
248 | else | ||
249 | err = add_mtd_partitions(info->mtd, pdata->partitions, | ||
250 | pdata->nr_partitions); | ||
236 | #endif /* CONFIG_MTD_PARTITIONS */ | 251 | #endif /* CONFIG_MTD_PARTITIONS */ |
237 | 252 | ||
238 | if (add_mtd_device(info->mtd)) { | 253 | if (add_mtd_device(info->mtd)) { |
@@ -240,7 +255,9 @@ static int platram_probe(struct platform_device *pdev) | |||
240 | err = -ENOMEM; | 255 | err = -ENOMEM; |
241 | } | 256 | } |
242 | 257 | ||
243 | dev_info(&pdev->dev, "registered mtd device\n"); | 258 | if (!err) |
259 | dev_info(&pdev->dev, "registered mtd device\n"); | ||
260 | |||
244 | return err; | 261 | return err; |
245 | 262 | ||
246 | exit_free: | 263 | exit_free: |
@@ -251,6 +268,9 @@ static int platram_probe(struct platform_device *pdev) | |||
251 | 268 | ||
252 | /* device driver info */ | 269 | /* device driver info */ |
253 | 270 | ||
271 | /* work with hotplug and coldplug */ | ||
272 | MODULE_ALIAS("platform:mtd-ram"); | ||
273 | |||
254 | static struct platform_driver platram_driver = { | 274 | static struct platform_driver platram_driver = { |
255 | .probe = platram_probe, | 275 | .probe = platram_probe, |
256 | .remove = platram_remove, | 276 | .remove = platram_remove, |
diff --git a/drivers/mtd/maps/pmcmsp-flash.c b/drivers/mtd/maps/pmcmsp-flash.c index 02bde8c982ec..f43ba2815cbb 100644 --- a/drivers/mtd/maps/pmcmsp-flash.c +++ b/drivers/mtd/maps/pmcmsp-flash.c | |||
@@ -46,7 +46,7 @@ static struct mtd_partition **msp_parts; | |||
46 | static struct map_info *msp_maps; | 46 | static struct map_info *msp_maps; |
47 | static int fcnt; | 47 | static int fcnt; |
48 | 48 | ||
49 | #define DEBUG_MARKER printk(KERN_NOTICE "%s[%d]\n",__FUNCTION__,__LINE__) | 49 | #define DEBUG_MARKER printk(KERN_NOTICE "%s[%d]\n", __func__, __LINE__) |
50 | 50 | ||
51 | int __init init_msp_flash(void) | 51 | int __init init_msp_flash(void) |
52 | { | 52 | { |
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index f904e6bd02e0..c7d5a52a2d55 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c | |||
@@ -456,6 +456,7 @@ static struct platform_driver sa1100_mtd_driver = { | |||
456 | .shutdown = sa1100_mtd_shutdown, | 456 | .shutdown = sa1100_mtd_shutdown, |
457 | .driver = { | 457 | .driver = { |
458 | .name = "flash", | 458 | .name = "flash", |
459 | .owner = THIS_MODULE, | ||
459 | }, | 460 | }, |
460 | }; | 461 | }; |
461 | 462 | ||
@@ -475,3 +476,4 @@ module_exit(sa1100_mtd_exit); | |||
475 | MODULE_AUTHOR("Nicolas Pitre"); | 476 | MODULE_AUTHOR("Nicolas Pitre"); |
476 | MODULE_DESCRIPTION("SA1100 CFI map driver"); | 477 | MODULE_DESCRIPTION("SA1100 CFI map driver"); |
477 | MODULE_LICENSE("GPL"); | 478 | MODULE_LICENSE("GPL"); |
479 | MODULE_ALIAS("platform:flash"); | ||
diff --git a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c index 12fe53c0d2fc..917dc778f24e 100644 --- a/drivers/mtd/maps/sharpsl-flash.c +++ b/drivers/mtd/maps/sharpsl-flash.c | |||
@@ -92,7 +92,7 @@ int __init init_sharpsl(void) | |||
92 | parts = sharpsl_partitions; | 92 | parts = sharpsl_partitions; |
93 | nb_parts = ARRAY_SIZE(sharpsl_partitions); | 93 | nb_parts = ARRAY_SIZE(sharpsl_partitions); |
94 | 94 | ||
95 | printk(KERN_NOTICE "Using %s partision definition\n", part_type); | 95 | printk(KERN_NOTICE "Using %s partition definition\n", part_type); |
96 | add_mtd_partitions(mymtd, parts, nb_parts); | 96 | add_mtd_partitions(mymtd, parts, nb_parts); |
97 | 97 | ||
98 | return 0; | 98 | return 0; |
diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c index 37e4ded9b600..521734057314 100644 --- a/drivers/mtd/maps/tqm8xxl.c +++ b/drivers/mtd/maps/tqm8xxl.c | |||
@@ -124,7 +124,7 @@ int __init init_tqm_mtd(void) | |||
124 | //request maximum flash size address space | 124 | //request maximum flash size address space |
125 | start_scan_addr = ioremap(flash_addr, flash_size); | 125 | start_scan_addr = ioremap(flash_addr, flash_size); |
126 | if (!start_scan_addr) { | 126 | if (!start_scan_addr) { |
127 | printk(KERN_WARNING "%s:Failed to ioremap address:0x%x\n", __FUNCTION__, flash_addr); | 127 | printk(KERN_WARNING "%s:Failed to ioremap address:0x%x\n", __func__, flash_addr); |
128 | return -EIO; | 128 | return -EIO; |
129 | } | 129 | } |
130 | 130 | ||
@@ -132,7 +132,7 @@ int __init init_tqm_mtd(void) | |||
132 | if(mtd_size >= flash_size) | 132 | if(mtd_size >= flash_size) |
133 | break; | 133 | break; |
134 | 134 | ||
135 | printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx); | 135 | printk(KERN_INFO "%s: chip probing count %d\n", __func__, idx); |
136 | 136 | ||
137 | map_banks[idx] = kzalloc(sizeof(struct map_info), GFP_KERNEL); | 137 | map_banks[idx] = kzalloc(sizeof(struct map_info), GFP_KERNEL); |
138 | if(map_banks[idx] == NULL) { | 138 | if(map_banks[idx] == NULL) { |
@@ -178,7 +178,7 @@ int __init init_tqm_mtd(void) | |||
178 | mtd_size += mtd_banks[idx]->size; | 178 | mtd_size += mtd_banks[idx]->size; |
179 | num_banks++; | 179 | num_banks++; |
180 | 180 | ||
181 | printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks, | 181 | printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __func__, num_banks, |
182 | mtd_banks[idx]->name, mtd_banks[idx]->size); | 182 | mtd_banks[idx]->name, mtd_banks[idx]->size); |
183 | } | 183 | } |
184 | } | 184 | } |
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index d3cf05012b46..5a680e1e61f1 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c | |||
@@ -35,7 +35,7 @@ | |||
35 | 35 | ||
36 | #define OOPS_PAGE_SIZE 4096 | 36 | #define OOPS_PAGE_SIZE 4096 |
37 | 37 | ||
38 | struct mtdoops_context { | 38 | static struct mtdoops_context { |
39 | int mtd_index; | 39 | int mtd_index; |
40 | struct work_struct work_erase; | 40 | struct work_struct work_erase; |
41 | struct work_struct work_write; | 41 | struct work_struct work_write; |
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 959fb86cda01..5076faf9ca66 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -278,6 +278,54 @@ config MTD_NAND_AT91 | |||
278 | help | 278 | help |
279 | Enables support for NAND Flash / Smart Media Card interface | 279 | Enables support for NAND Flash / Smart Media Card interface |
280 | on Atmel AT91 processors. | 280 | on Atmel AT91 processors. |
281 | choice | ||
282 | prompt "ECC management for NAND Flash / SmartMedia on AT91" | ||
283 | depends on MTD_NAND_AT91 | ||
284 | |||
285 | config MTD_NAND_AT91_ECC_HW | ||
286 | bool "Hardware ECC" | ||
287 | depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 | ||
288 | help | ||
289 | Uses hardware ECC provided by the at91sam9260/at91sam9263 chip | ||
290 | instead of software ECC. | ||
291 | The hardware ECC controller is capable of single bit error | ||
292 | correction and 2-bit random detection per page. | ||
293 | |||
294 | NB : hardware and software ECC schemes are incompatible. | ||
295 | If you switch from one to another, you'll have to erase your | ||
296 | mtd partition. | ||
297 | |||
298 | If unsure, say Y | ||
299 | |||
300 | config MTD_NAND_AT91_ECC_SOFT | ||
301 | bool "Software ECC" | ||
302 | help | ||
303 | Uses software ECC. | ||
304 | |||
305 | NB : hardware and software ECC schemes are incompatible. | ||
306 | If you switch from one to another, you'll have to erase your | ||
307 | mtd partition. | ||
308 | |||
309 | config MTD_NAND_AT91_ECC_NONE | ||
310 | bool "No ECC (testing only, DANGEROUS)" | ||
311 | depends on DEBUG_KERNEL | ||
312 | help | ||
313 | No ECC will be used. | ||
314 | It's not a good idea and it should be reserved for testing | ||
315 | purpose only. | ||
316 | |||
317 | If unsure, say N | ||
318 | |||
319 | endchoice | ||
320 | |||
321 | endchoice | ||
322 | |||
323 | config MTD_NAND_PXA3xx | ||
324 | bool "Support for NAND flash devices on PXA3xx" | ||
325 | depends on MTD_NAND && PXA3xx | ||
326 | help | ||
327 | This enables the driver for the NAND flash device found on | ||
328 | PXA3xx processors | ||
281 | 329 | ||
282 | config MTD_NAND_CM_X270 | 330 | config MTD_NAND_CM_X270 |
283 | tristate "Support for NAND Flash on CM-X270 modules" | 331 | tristate "Support for NAND Flash on CM-X270 modules" |
@@ -330,4 +378,12 @@ config MTD_NAND_FSL_ELBC | |||
330 | Enabling this option will enable you to use this to control | 378 | Enabling this option will enable you to use this to control |
331 | external NAND devices. | 379 | external NAND devices. |
332 | 380 | ||
381 | config MTD_NAND_FSL_UPM | ||
382 | tristate "Support for NAND on Freescale UPM" | ||
383 | depends on MTD_NAND && OF_GPIO && (PPC_83xx || PPC_85xx) | ||
384 | select FSL_LBC | ||
385 | help | ||
386 | Enables support for NAND Flash chips wired onto Freescale PowerPC | ||
387 | processor localbus with User-Programmable Machine support. | ||
388 | |||
333 | endif # MTD_NAND | 389 | endif # MTD_NAND |
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 80d575eeee96..a6e74a46992a 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile | |||
@@ -27,10 +27,12 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o | |||
27 | obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o | 27 | obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o |
28 | obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o | 28 | obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o |
29 | obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o | 29 | obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o |
30 | obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o | ||
30 | obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o | 31 | obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o |
31 | obj-$(CONFIG_MTD_ALAUDA) += alauda.o | 32 | obj-$(CONFIG_MTD_ALAUDA) += alauda.o |
32 | obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o | 33 | obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o |
33 | obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o | 34 | obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o |
34 | obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o | 35 | obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o |
36 | obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o | ||
35 | 37 | ||
36 | nand-objs := nand_base.o nand_bbt.o | 38 | nand-objs := nand_base.o nand_bbt.o |
diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c index c9fb2acf4056..414ceaecdb3a 100644 --- a/drivers/mtd/nand/at91_nand.c +++ b/drivers/mtd/nand/at91_nand.c | |||
@@ -9,6 +9,15 @@ | |||
9 | * Derived from drivers/mtd/spia.c | 9 | * Derived from drivers/mtd/spia.c |
10 | * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) | 10 | * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) |
11 | * | 11 | * |
12 | * | ||
13 | * Add Hardware ECC support for AT91SAM9260 / AT91SAM9263 | ||
14 | * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright (C) 2007 | ||
15 | * | ||
16 | * Derived from Das U-Boot source code | ||
17 | * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c) | ||
18 | * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas | ||
19 | * | ||
20 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | 21 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License version 2 as | 22 | * it under the terms of the GNU General Public License version 2 as |
14 | * published by the Free Software Foundation. | 23 | * published by the Free Software Foundation. |
@@ -29,11 +38,59 @@ | |||
29 | #include <asm/arch/board.h> | 38 | #include <asm/arch/board.h> |
30 | #include <asm/arch/gpio.h> | 39 | #include <asm/arch/gpio.h> |
31 | 40 | ||
41 | #ifdef CONFIG_MTD_NAND_AT91_ECC_HW | ||
42 | #define hard_ecc 1 | ||
43 | #else | ||
44 | #define hard_ecc 0 | ||
45 | #endif | ||
46 | |||
47 | #ifdef CONFIG_MTD_NAND_AT91_ECC_NONE | ||
48 | #define no_ecc 1 | ||
49 | #else | ||
50 | #define no_ecc 0 | ||
51 | #endif | ||
52 | |||
53 | /* Register access macros */ | ||
54 | #define ecc_readl(add, reg) \ | ||
55 | __raw_readl(add + AT91_ECC_##reg) | ||
56 | #define ecc_writel(add, reg, value) \ | ||
57 | __raw_writel((value), add + AT91_ECC_##reg) | ||
58 | |||
59 | #include <asm/arch/at91_ecc.h> /* AT91SAM9260/3 ECC registers */ | ||
60 | |||
61 | /* oob layout for large page size | ||
62 | * bad block info is on bytes 0 and 1 | ||
63 | * the bytes have to be consecutives to avoid | ||
64 | * several NAND_CMD_RNDOUT during read | ||
65 | */ | ||
66 | static struct nand_ecclayout at91_oobinfo_large = { | ||
67 | .eccbytes = 4, | ||
68 | .eccpos = {60, 61, 62, 63}, | ||
69 | .oobfree = { | ||
70 | {2, 58} | ||
71 | }, | ||
72 | }; | ||
73 | |||
74 | /* oob layout for small page size | ||
75 | * bad block info is on bytes 4 and 5 | ||
76 | * the bytes have to be consecutives to avoid | ||
77 | * several NAND_CMD_RNDOUT during read | ||
78 | */ | ||
79 | static struct nand_ecclayout at91_oobinfo_small = { | ||
80 | .eccbytes = 4, | ||
81 | .eccpos = {0, 1, 2, 3}, | ||
82 | .oobfree = { | ||
83 | {6, 10} | ||
84 | }, | ||
85 | }; | ||
86 | |||
32 | struct at91_nand_host { | 87 | struct at91_nand_host { |
33 | struct nand_chip nand_chip; | 88 | struct nand_chip nand_chip; |
34 | struct mtd_info mtd; | 89 | struct mtd_info mtd; |
35 | void __iomem *io_base; | 90 | void __iomem *io_base; |
36 | struct at91_nand_data *board; | 91 | struct at91_nand_data *board; |
92 | struct device *dev; | ||
93 | void __iomem *ecc; | ||
37 | }; | 94 | }; |
38 | 95 | ||
39 | /* | 96 | /* |
@@ -44,6 +101,12 @@ static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | |||
44 | struct nand_chip *nand_chip = mtd->priv; | 101 | struct nand_chip *nand_chip = mtd->priv; |
45 | struct at91_nand_host *host = nand_chip->priv; | 102 | struct at91_nand_host *host = nand_chip->priv; |
46 | 103 | ||
104 | if (host->board->enable_pin && (ctrl & NAND_CTRL_CHANGE)) { | ||
105 | if (ctrl & NAND_NCE) | ||
106 | at91_set_gpio_value(host->board->enable_pin, 0); | ||
107 | else | ||
108 | at91_set_gpio_value(host->board->enable_pin, 1); | ||
109 | } | ||
47 | if (cmd == NAND_CMD_NONE) | 110 | if (cmd == NAND_CMD_NONE) |
48 | return; | 111 | return; |
49 | 112 | ||
@@ -82,8 +145,217 @@ static void at91_nand_disable(struct at91_nand_host *host) | |||
82 | at91_set_gpio_value(host->board->enable_pin, 1); | 145 | at91_set_gpio_value(host->board->enable_pin, 1); |
83 | } | 146 | } |
84 | 147 | ||
148 | /* | ||
149 | * write oob for small pages | ||
150 | */ | ||
151 | static int at91_nand_write_oob_512(struct mtd_info *mtd, | ||
152 | struct nand_chip *chip, int page) | ||
153 | { | ||
154 | int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; | ||
155 | int eccsize = chip->ecc.size, length = mtd->oobsize; | ||
156 | int len, pos, status = 0; | ||
157 | const uint8_t *bufpoi = chip->oob_poi; | ||
158 | |||
159 | pos = eccsize + chunk; | ||
160 | |||
161 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); | ||
162 | len = min_t(int, length, chunk); | ||
163 | chip->write_buf(mtd, bufpoi, len); | ||
164 | bufpoi += len; | ||
165 | length -= len; | ||
166 | if (length > 0) | ||
167 | chip->write_buf(mtd, bufpoi, length); | ||
168 | |||
169 | chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); | ||
170 | status = chip->waitfunc(mtd, chip); | ||
171 | |||
172 | return status & NAND_STATUS_FAIL ? -EIO : 0; | ||
173 | |||
174 | } | ||
175 | |||
176 | /* | ||
177 | * read oob for small pages | ||
178 | */ | ||
179 | static int at91_nand_read_oob_512(struct mtd_info *mtd, | ||
180 | struct nand_chip *chip, int page, int sndcmd) | ||
181 | { | ||
182 | if (sndcmd) { | ||
183 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); | ||
184 | sndcmd = 0; | ||
185 | } | ||
186 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
187 | return sndcmd; | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * Calculate HW ECC | ||
192 | * | ||
193 | * function called after a write | ||
194 | * | ||
195 | * mtd: MTD block structure | ||
196 | * dat: raw data (unused) | ||
197 | * ecc_code: buffer for ECC | ||
198 | */ | ||
199 | static int at91_nand_calculate(struct mtd_info *mtd, | ||
200 | const u_char *dat, unsigned char *ecc_code) | ||
201 | { | ||
202 | struct nand_chip *nand_chip = mtd->priv; | ||
203 | struct at91_nand_host *host = nand_chip->priv; | ||
204 | uint32_t *eccpos = nand_chip->ecc.layout->eccpos; | ||
205 | unsigned int ecc_value; | ||
206 | |||
207 | /* get the first 2 ECC bytes */ | ||
208 | ecc_value = ecc_readl(host->ecc, PR); | ||
209 | |||
210 | ecc_code[eccpos[0]] = ecc_value & 0xFF; | ||
211 | ecc_code[eccpos[1]] = (ecc_value >> 8) & 0xFF; | ||
212 | |||
213 | /* get the last 2 ECC bytes */ | ||
214 | ecc_value = ecc_readl(host->ecc, NPR) & AT91_ECC_NPARITY; | ||
215 | |||
216 | ecc_code[eccpos[2]] = ecc_value & 0xFF; | ||
217 | ecc_code[eccpos[3]] = (ecc_value >> 8) & 0xFF; | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * HW ECC read page function | ||
224 | * | ||
225 | * mtd: mtd info structure | ||
226 | * chip: nand chip info structure | ||
227 | * buf: buffer to store read data | ||
228 | */ | ||
229 | static int at91_nand_read_page(struct mtd_info *mtd, | ||
230 | struct nand_chip *chip, uint8_t *buf) | ||
231 | { | ||
232 | int eccsize = chip->ecc.size; | ||
233 | int eccbytes = chip->ecc.bytes; | ||
234 | uint32_t *eccpos = chip->ecc.layout->eccpos; | ||
235 | uint8_t *p = buf; | ||
236 | uint8_t *oob = chip->oob_poi; | ||
237 | uint8_t *ecc_pos; | ||
238 | int stat; | ||
239 | |||
240 | /* read the page */ | ||
241 | chip->read_buf(mtd, p, eccsize); | ||
242 | |||
243 | /* move to ECC position if needed */ | ||
244 | if (eccpos[0] != 0) { | ||
245 | /* This only works on large pages | ||
246 | * because the ECC controller waits for | ||
247 | * NAND_CMD_RNDOUTSTART after the | ||
248 | * NAND_CMD_RNDOUT. | ||
249 | * anyway, for small pages, the eccpos[0] == 0 | ||
250 | */ | ||
251 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, | ||
252 | mtd->writesize + eccpos[0], -1); | ||
253 | } | ||
254 | |||
255 | /* the ECC controller needs to read the ECC just after the data */ | ||
256 | ecc_pos = oob + eccpos[0]; | ||
257 | chip->read_buf(mtd, ecc_pos, eccbytes); | ||
258 | |||
259 | /* check if there's an error */ | ||
260 | stat = chip->ecc.correct(mtd, p, oob, NULL); | ||
261 | |||
262 | if (stat < 0) | ||
263 | mtd->ecc_stats.failed++; | ||
264 | else | ||
265 | mtd->ecc_stats.corrected += stat; | ||
266 | |||
267 | /* get back to oob start (end of page) */ | ||
268 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); | ||
269 | |||
270 | /* read the oob */ | ||
271 | chip->read_buf(mtd, oob, mtd->oobsize); | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | /* | ||
277 | * HW ECC Correction | ||
278 | * | ||
279 | * function called after a read | ||
280 | * | ||
281 | * mtd: MTD block structure | ||
282 | * dat: raw data read from the chip | ||
283 | * read_ecc: ECC from the chip (unused) | ||
284 | * isnull: unused | ||
285 | * | ||
286 | * Detect and correct a 1 bit error for a page | ||
287 | */ | ||
288 | static int at91_nand_correct(struct mtd_info *mtd, u_char *dat, | ||
289 | u_char *read_ecc, u_char *isnull) | ||
290 | { | ||
291 | struct nand_chip *nand_chip = mtd->priv; | ||
292 | struct at91_nand_host *host = nand_chip->priv; | ||
293 | unsigned int ecc_status; | ||
294 | unsigned int ecc_word, ecc_bit; | ||
295 | |||
296 | /* get the status from the Status Register */ | ||
297 | ecc_status = ecc_readl(host->ecc, SR); | ||
298 | |||
299 | /* if there's no error */ | ||
300 | if (likely(!(ecc_status & AT91_ECC_RECERR))) | ||
301 | return 0; | ||
302 | |||
303 | /* get error bit offset (4 bits) */ | ||
304 | ecc_bit = ecc_readl(host->ecc, PR) & AT91_ECC_BITADDR; | ||
305 | /* get word address (12 bits) */ | ||
306 | ecc_word = ecc_readl(host->ecc, PR) & AT91_ECC_WORDADDR; | ||
307 | ecc_word >>= 4; | ||
308 | |||
309 | /* if there are multiple errors */ | ||
310 | if (ecc_status & AT91_ECC_MULERR) { | ||
311 | /* check if it is a freshly erased block | ||
312 | * (filled with 0xff) */ | ||
313 | if ((ecc_bit == AT91_ECC_BITADDR) | ||
314 | && (ecc_word == (AT91_ECC_WORDADDR >> 4))) { | ||
315 | /* the block has just been erased, return OK */ | ||
316 | return 0; | ||
317 | } | ||
318 | /* it doesn't seems to be a freshly | ||
319 | * erased block. | ||
320 | * We can't correct so many errors */ | ||
321 | dev_dbg(host->dev, "at91_nand : multiple errors detected." | ||
322 | " Unable to correct.\n"); | ||
323 | return -EIO; | ||
324 | } | ||
325 | |||
326 | /* if there's a single bit error : we can correct it */ | ||
327 | if (ecc_status & AT91_ECC_ECCERR) { | ||
328 | /* there's nothing much to do here. | ||
329 | * the bit error is on the ECC itself. | ||
330 | */ | ||
331 | dev_dbg(host->dev, "at91_nand : one bit error on ECC code." | ||
332 | " Nothing to correct\n"); | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | dev_dbg(host->dev, "at91_nand : one bit error on data." | ||
337 | " (word offset in the page :" | ||
338 | " 0x%x bit offset : 0x%x)\n", | ||
339 | ecc_word, ecc_bit); | ||
340 | /* correct the error */ | ||
341 | if (nand_chip->options & NAND_BUSWIDTH_16) { | ||
342 | /* 16 bits words */ | ||
343 | ((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit); | ||
344 | } else { | ||
345 | /* 8 bits words */ | ||
346 | dat[ecc_word] ^= (1 << ecc_bit); | ||
347 | } | ||
348 | dev_dbg(host->dev, "at91_nand : error corrected\n"); | ||
349 | return 1; | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * Enable HW ECC : unsused | ||
354 | */ | ||
355 | static void at91_nand_hwctl(struct mtd_info *mtd, int mode) { ; } | ||
356 | |||
85 | #ifdef CONFIG_MTD_PARTITIONS | 357 | #ifdef CONFIG_MTD_PARTITIONS |
86 | const char *part_probes[] = { "cmdlinepart", NULL }; | 358 | static const char *part_probes[] = { "cmdlinepart", NULL }; |
87 | #endif | 359 | #endif |
88 | 360 | ||
89 | /* | 361 | /* |
@@ -94,6 +366,8 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
94 | struct at91_nand_host *host; | 366 | struct at91_nand_host *host; |
95 | struct mtd_info *mtd; | 367 | struct mtd_info *mtd; |
96 | struct nand_chip *nand_chip; | 368 | struct nand_chip *nand_chip; |
369 | struct resource *regs; | ||
370 | struct resource *mem; | ||
97 | int res; | 371 | int res; |
98 | 372 | ||
99 | #ifdef CONFIG_MTD_PARTITIONS | 373 | #ifdef CONFIG_MTD_PARTITIONS |
@@ -108,8 +382,13 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
108 | return -ENOMEM; | 382 | return -ENOMEM; |
109 | } | 383 | } |
110 | 384 | ||
111 | host->io_base = ioremap(pdev->resource[0].start, | 385 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
112 | pdev->resource[0].end - pdev->resource[0].start + 1); | 386 | if (!mem) { |
387 | printk(KERN_ERR "at91_nand: can't get I/O resource mem\n"); | ||
388 | return -ENXIO; | ||
389 | } | ||
390 | |||
391 | host->io_base = ioremap(mem->start, mem->end - mem->start + 1); | ||
113 | if (host->io_base == NULL) { | 392 | if (host->io_base == NULL) { |
114 | printk(KERN_ERR "at91_nand: ioremap failed\n"); | 393 | printk(KERN_ERR "at91_nand: ioremap failed\n"); |
115 | kfree(host); | 394 | kfree(host); |
@@ -119,6 +398,7 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
119 | mtd = &host->mtd; | 398 | mtd = &host->mtd; |
120 | nand_chip = &host->nand_chip; | 399 | nand_chip = &host->nand_chip; |
121 | host->board = pdev->dev.platform_data; | 400 | host->board = pdev->dev.platform_data; |
401 | host->dev = &pdev->dev; | ||
122 | 402 | ||
123 | nand_chip->priv = host; /* link the private data structures */ | 403 | nand_chip->priv = host; /* link the private data structures */ |
124 | mtd->priv = nand_chip; | 404 | mtd->priv = nand_chip; |
@@ -132,7 +412,32 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
132 | if (host->board->rdy_pin) | 412 | if (host->board->rdy_pin) |
133 | nand_chip->dev_ready = at91_nand_device_ready; | 413 | nand_chip->dev_ready = at91_nand_device_ready; |
134 | 414 | ||
415 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
416 | if (!regs && hard_ecc) { | ||
417 | printk(KERN_ERR "at91_nand: can't get I/O resource " | ||
418 | "regs\nFalling back on software ECC\n"); | ||
419 | } | ||
420 | |||
135 | nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ | 421 | nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ |
422 | if (no_ecc) | ||
423 | nand_chip->ecc.mode = NAND_ECC_NONE; | ||
424 | if (hard_ecc && regs) { | ||
425 | host->ecc = ioremap(regs->start, regs->end - regs->start + 1); | ||
426 | if (host->ecc == NULL) { | ||
427 | printk(KERN_ERR "at91_nand: ioremap failed\n"); | ||
428 | res = -EIO; | ||
429 | goto err_ecc_ioremap; | ||
430 | } | ||
431 | nand_chip->ecc.mode = NAND_ECC_HW_SYNDROME; | ||
432 | nand_chip->ecc.calculate = at91_nand_calculate; | ||
433 | nand_chip->ecc.correct = at91_nand_correct; | ||
434 | nand_chip->ecc.hwctl = at91_nand_hwctl; | ||
435 | nand_chip->ecc.read_page = at91_nand_read_page; | ||
436 | nand_chip->ecc.bytes = 4; | ||
437 | nand_chip->ecc.prepad = 0; | ||
438 | nand_chip->ecc.postpad = 0; | ||
439 | } | ||
440 | |||
136 | nand_chip->chip_delay = 20; /* 20us command delay time */ | 441 | nand_chip->chip_delay = 20; /* 20us command delay time */ |
137 | 442 | ||
138 | if (host->board->bus_width_16) /* 16-bit bus width */ | 443 | if (host->board->bus_width_16) /* 16-bit bus width */ |
@@ -149,8 +454,53 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
149 | } | 454 | } |
150 | } | 455 | } |
151 | 456 | ||
152 | /* Scan to find existance of the device */ | 457 | /* first scan to find the device and get the page size */ |
153 | if (nand_scan(mtd, 1)) { | 458 | if (nand_scan_ident(mtd, 1)) { |
459 | res = -ENXIO; | ||
460 | goto out; | ||
461 | } | ||
462 | |||
463 | if (nand_chip->ecc.mode == NAND_ECC_HW_SYNDROME) { | ||
464 | /* ECC is calculated for the whole page (1 step) */ | ||
465 | nand_chip->ecc.size = mtd->writesize; | ||
466 | |||
467 | /* set ECC page size and oob layout */ | ||
468 | switch (mtd->writesize) { | ||
469 | case 512: | ||
470 | nand_chip->ecc.layout = &at91_oobinfo_small; | ||
471 | nand_chip->ecc.read_oob = at91_nand_read_oob_512; | ||
472 | nand_chip->ecc.write_oob = at91_nand_write_oob_512; | ||
473 | ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_528); | ||
474 | break; | ||
475 | case 1024: | ||
476 | nand_chip->ecc.layout = &at91_oobinfo_large; | ||
477 | ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_1056); | ||
478 | break; | ||
479 | case 2048: | ||
480 | nand_chip->ecc.layout = &at91_oobinfo_large; | ||
481 | ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_2112); | ||
482 | break; | ||
483 | case 4096: | ||
484 | nand_chip->ecc.layout = &at91_oobinfo_large; | ||
485 | ecc_writel(host->ecc, MR, AT91_ECC_PAGESIZE_4224); | ||
486 | break; | ||
487 | default: | ||
488 | /* page size not handled by HW ECC */ | ||
489 | /* switching back to soft ECC */ | ||
490 | nand_chip->ecc.mode = NAND_ECC_SOFT; | ||
491 | nand_chip->ecc.calculate = NULL; | ||
492 | nand_chip->ecc.correct = NULL; | ||
493 | nand_chip->ecc.hwctl = NULL; | ||
494 | nand_chip->ecc.read_page = NULL; | ||
495 | nand_chip->ecc.postpad = 0; | ||
496 | nand_chip->ecc.prepad = 0; | ||
497 | nand_chip->ecc.bytes = 0; | ||
498 | break; | ||
499 | } | ||
500 | } | ||
501 | |||
502 | /* second phase scan */ | ||
503 | if (nand_scan_tail(mtd)) { | ||
154 | res = -ENXIO; | 504 | res = -ENXIO; |
155 | goto out; | 505 | goto out; |
156 | } | 506 | } |
@@ -179,9 +529,15 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
179 | if (!res) | 529 | if (!res) |
180 | return res; | 530 | return res; |
181 | 531 | ||
532 | #ifdef CONFIG_MTD_PARTITIONS | ||
182 | release: | 533 | release: |
534 | #endif | ||
183 | nand_release(mtd); | 535 | nand_release(mtd); |
536 | |||
184 | out: | 537 | out: |
538 | iounmap(host->ecc); | ||
539 | |||
540 | err_ecc_ioremap: | ||
185 | at91_nand_disable(host); | 541 | at91_nand_disable(host); |
186 | platform_set_drvdata(pdev, NULL); | 542 | platform_set_drvdata(pdev, NULL); |
187 | iounmap(host->io_base); | 543 | iounmap(host->io_base); |
@@ -202,6 +558,7 @@ static int __devexit at91_nand_remove(struct platform_device *pdev) | |||
202 | at91_nand_disable(host); | 558 | at91_nand_disable(host); |
203 | 559 | ||
204 | iounmap(host->io_base); | 560 | iounmap(host->io_base); |
561 | iounmap(host->ecc); | ||
205 | kfree(host); | 562 | kfree(host); |
206 | 563 | ||
207 | return 0; | 564 | return 0; |
@@ -233,4 +590,5 @@ module_exit(at91_nand_exit); | |||
233 | 590 | ||
234 | MODULE_LICENSE("GPL"); | 591 | MODULE_LICENSE("GPL"); |
235 | MODULE_AUTHOR("Rick Bronson"); | 592 | MODULE_AUTHOR("Rick Bronson"); |
236 | MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200"); | 593 | MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200 / AT91SAM9"); |
594 | MODULE_ALIAS("platform:at91_nand"); | ||
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 747042ab094a..e87a57297328 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* linux/drivers/mtd/nand/bf5xx_nand.c | 1 | /* linux/drivers/mtd/nand/bf5xx_nand.c |
2 | * | 2 | * |
3 | * Copyright 2006-2007 Analog Devices Inc. | 3 | * Copyright 2006-2008 Analog Devices Inc. |
4 | * http://blackfin.uclinux.org/ | 4 | * http://blackfin.uclinux.org/ |
5 | * Bryan Wu <bryan.wu@analog.com> | 5 | * Bryan Wu <bryan.wu@analog.com> |
6 | * | 6 | * |
@@ -74,7 +74,7 @@ static int hardware_ecc = 1; | |||
74 | static int hardware_ecc; | 74 | static int hardware_ecc; |
75 | #endif | 75 | #endif |
76 | 76 | ||
77 | static unsigned short bfin_nfc_pin_req[] = | 77 | static const unsigned short bfin_nfc_pin_req[] = |
78 | {P_NAND_CE, | 78 | {P_NAND_CE, |
79 | P_NAND_RB, | 79 | P_NAND_RB, |
80 | P_NAND_D0, | 80 | P_NAND_D0, |
@@ -581,12 +581,6 @@ static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info) | |||
581 | bfin_write_NFC_IRQSTAT(val); | 581 | bfin_write_NFC_IRQSTAT(val); |
582 | SSYNC(); | 582 | SSYNC(); |
583 | 583 | ||
584 | if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) { | ||
585 | printk(KERN_ERR DRV_NAME | ||
586 | ": Requesting Peripherals failed\n"); | ||
587 | return -EFAULT; | ||
588 | } | ||
589 | |||
590 | /* DMA initialization */ | 584 | /* DMA initialization */ |
591 | if (bf5xx_nand_dma_init(info)) | 585 | if (bf5xx_nand_dma_init(info)) |
592 | err = -ENXIO; | 586 | err = -ENXIO; |
@@ -654,6 +648,12 @@ static int bf5xx_nand_probe(struct platform_device *pdev) | |||
654 | 648 | ||
655 | dev_dbg(&pdev->dev, "(%p)\n", pdev); | 649 | dev_dbg(&pdev->dev, "(%p)\n", pdev); |
656 | 650 | ||
651 | if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) { | ||
652 | printk(KERN_ERR DRV_NAME | ||
653 | ": Requesting Peripherals failed\n"); | ||
654 | return -EFAULT; | ||
655 | } | ||
656 | |||
657 | if (!plat) { | 657 | if (!plat) { |
658 | dev_err(&pdev->dev, "no platform specific information\n"); | 658 | dev_err(&pdev->dev, "no platform specific information\n"); |
659 | goto exit_error; | 659 | goto exit_error; |
@@ -803,3 +803,4 @@ module_exit(bf5xx_nand_exit); | |||
803 | MODULE_LICENSE("GPL"); | 803 | MODULE_LICENSE("GPL"); |
804 | MODULE_AUTHOR(DRV_AUTHOR); | 804 | MODULE_AUTHOR(DRV_AUTHOR); |
805 | MODULE_DESCRIPTION(DRV_DESC); | 805 | MODULE_DESCRIPTION(DRV_DESC); |
806 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index 8dab69657b19..3370a800fd36 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c | |||
@@ -279,7 +279,7 @@ static int is_geode(void) | |||
279 | 279 | ||
280 | 280 | ||
281 | #ifdef CONFIG_MTD_PARTITIONS | 281 | #ifdef CONFIG_MTD_PARTITIONS |
282 | const char *part_probes[] = { "cmdlinepart", NULL }; | 282 | static const char *part_probes[] = { "cmdlinepart", NULL }; |
283 | #endif | 283 | #endif |
284 | 284 | ||
285 | 285 | ||
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 378b7aa63812..4b69aacdf5ca 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c | |||
@@ -184,11 +184,11 @@ static int fsl_elbc_run_command(struct mtd_info *mtd) | |||
184 | in_be32(&lbc->fbar), in_be32(&lbc->fpar), | 184 | in_be32(&lbc->fbar), in_be32(&lbc->fpar), |
185 | in_be32(&lbc->fbcr), priv->bank); | 185 | in_be32(&lbc->fbcr), priv->bank); |
186 | 186 | ||
187 | ctrl->irq_status = 0; | ||
187 | /* execute special operation */ | 188 | /* execute special operation */ |
188 | out_be32(&lbc->lsor, priv->bank); | 189 | out_be32(&lbc->lsor, priv->bank); |
189 | 190 | ||
190 | /* wait for FCM complete flag or timeout */ | 191 | /* wait for FCM complete flag or timeout */ |
191 | ctrl->irq_status = 0; | ||
192 | wait_event_timeout(ctrl->irq_wait, ctrl->irq_status, | 192 | wait_event_timeout(ctrl->irq_wait, ctrl->irq_status, |
193 | FCM_TIMEOUT_MSECS * HZ/1000); | 193 | FCM_TIMEOUT_MSECS * HZ/1000); |
194 | ctrl->status = ctrl->irq_status; | 194 | ctrl->status = ctrl->irq_status; |
@@ -346,19 +346,20 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | |||
346 | ctrl->column = column; | 346 | ctrl->column = column; |
347 | ctrl->oob = 0; | 347 | ctrl->oob = 0; |
348 | 348 | ||
349 | fcr = (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT) | | ||
350 | (NAND_CMD_SEQIN << FCR_CMD2_SHIFT); | ||
351 | |||
352 | if (priv->page_size) { | 349 | if (priv->page_size) { |
350 | fcr = (NAND_CMD_SEQIN << FCR_CMD0_SHIFT) | | ||
351 | (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT); | ||
352 | |||
353 | out_be32(&lbc->fir, | 353 | out_be32(&lbc->fir, |
354 | (FIR_OP_CW0 << FIR_OP0_SHIFT) | | 354 | (FIR_OP_CW0 << FIR_OP0_SHIFT) | |
355 | (FIR_OP_CA << FIR_OP1_SHIFT) | | 355 | (FIR_OP_CA << FIR_OP1_SHIFT) | |
356 | (FIR_OP_PA << FIR_OP2_SHIFT) | | 356 | (FIR_OP_PA << FIR_OP2_SHIFT) | |
357 | (FIR_OP_WB << FIR_OP3_SHIFT) | | 357 | (FIR_OP_WB << FIR_OP3_SHIFT) | |
358 | (FIR_OP_CW1 << FIR_OP4_SHIFT)); | 358 | (FIR_OP_CW1 << FIR_OP4_SHIFT)); |
359 | |||
360 | fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT; | ||
361 | } else { | 359 | } else { |
360 | fcr = (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT) | | ||
361 | (NAND_CMD_SEQIN << FCR_CMD2_SHIFT); | ||
362 | |||
362 | out_be32(&lbc->fir, | 363 | out_be32(&lbc->fir, |
363 | (FIR_OP_CW0 << FIR_OP0_SHIFT) | | 364 | (FIR_OP_CW0 << FIR_OP0_SHIFT) | |
364 | (FIR_OP_CM2 << FIR_OP1_SHIFT) | | 365 | (FIR_OP_CM2 << FIR_OP1_SHIFT) | |
@@ -480,7 +481,7 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) | |||
480 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | 481 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; |
481 | unsigned int bufsize = mtd->writesize + mtd->oobsize; | 482 | unsigned int bufsize = mtd->writesize + mtd->oobsize; |
482 | 483 | ||
483 | if (len < 0) { | 484 | if (len <= 0) { |
484 | dev_err(ctrl->dev, "write_buf of %d bytes", len); | 485 | dev_err(ctrl->dev, "write_buf of %d bytes", len); |
485 | ctrl->status = 0; | 486 | ctrl->status = 0; |
486 | return; | 487 | return; |
@@ -495,6 +496,15 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) | |||
495 | } | 496 | } |
496 | 497 | ||
497 | memcpy_toio(&ctrl->addr[ctrl->index], buf, len); | 498 | memcpy_toio(&ctrl->addr[ctrl->index], buf, len); |
499 | /* | ||
500 | * This is workaround for the weird elbc hangs during nand write, | ||
501 | * Scott Wood says: "...perhaps difference in how long it takes a | ||
502 | * write to make it through the localbus compared to a write to IMMR | ||
503 | * is causing problems, and sync isn't helping for some reason." | ||
504 | * Reading back the last byte helps though. | ||
505 | */ | ||
506 | in_8(&ctrl->addr[ctrl->index] + len - 1); | ||
507 | |||
498 | ctrl->index += len; | 508 | ctrl->index += len; |
499 | } | 509 | } |
500 | 510 | ||
@@ -666,7 +676,7 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) | |||
666 | /* adjust Option Register and ECC to match Flash page size */ | 676 | /* adjust Option Register and ECC to match Flash page size */ |
667 | if (mtd->writesize == 512) { | 677 | if (mtd->writesize == 512) { |
668 | priv->page_size = 0; | 678 | priv->page_size = 0; |
669 | clrbits32(&lbc->bank[priv->bank].or, ~OR_FCM_PGS); | 679 | clrbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS); |
670 | } else if (mtd->writesize == 2048) { | 680 | } else if (mtd->writesize == 2048) { |
671 | priv->page_size = 1; | 681 | priv->page_size = 1; |
672 | setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS); | 682 | setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS); |
@@ -687,11 +697,6 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) | |||
687 | return -1; | 697 | return -1; |
688 | } | 698 | } |
689 | 699 | ||
690 | /* The default u-boot configuration on MPC8313ERDB causes errors; | ||
691 | * more delay is needed. This should be safe for other boards | ||
692 | * as well. | ||
693 | */ | ||
694 | setbits32(&lbc->bank[priv->bank].or, 0x70); | ||
695 | return 0; | 700 | return 0; |
696 | } | 701 | } |
697 | 702 | ||
@@ -779,6 +784,8 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) | |||
779 | 784 | ||
780 | nand_release(&priv->mtd); | 785 | nand_release(&priv->mtd); |
781 | 786 | ||
787 | kfree(priv->mtd.name); | ||
788 | |||
782 | if (priv->vbase) | 789 | if (priv->vbase) |
783 | iounmap(priv->vbase); | 790 | iounmap(priv->vbase); |
784 | 791 | ||
@@ -839,6 +846,12 @@ static int fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, | |||
839 | goto err; | 846 | goto err; |
840 | } | 847 | } |
841 | 848 | ||
849 | priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", res.start); | ||
850 | if (!priv->mtd.name) { | ||
851 | ret = -ENOMEM; | ||
852 | goto err; | ||
853 | } | ||
854 | |||
842 | ret = fsl_elbc_chip_init(priv); | 855 | ret = fsl_elbc_chip_init(priv); |
843 | if (ret) | 856 | if (ret) |
844 | goto err; | 857 | goto err; |
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c new file mode 100644 index 000000000000..1ebfd87f00b4 --- /dev/null +++ b/drivers/mtd/nand/fsl_upm.c | |||
@@ -0,0 +1,291 @@ | |||
1 | /* | ||
2 | * Freescale UPM NAND driver. | ||
3 | * | ||
4 | * Copyright © 2007-2008 MontaVista Software, Inc. | ||
5 | * | ||
6 | * Author: Anton Vorontsov <avorontsov@ru.mvista.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/mtd/nand.h> | ||
17 | #include <linux/mtd/nand_ecc.h> | ||
18 | #include <linux/mtd/partitions.h> | ||
19 | #include <linux/mtd/mtd.h> | ||
20 | #include <linux/of_platform.h> | ||
21 | #include <linux/of_gpio.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <asm/fsl_lbc.h> | ||
24 | |||
25 | struct fsl_upm_nand { | ||
26 | struct device *dev; | ||
27 | struct mtd_info mtd; | ||
28 | struct nand_chip chip; | ||
29 | int last_ctrl; | ||
30 | #ifdef CONFIG_MTD_PARTITIONS | ||
31 | struct mtd_partition *parts; | ||
32 | #endif | ||
33 | |||
34 | struct fsl_upm upm; | ||
35 | uint8_t upm_addr_offset; | ||
36 | uint8_t upm_cmd_offset; | ||
37 | void __iomem *io_base; | ||
38 | int rnb_gpio; | ||
39 | const uint32_t *wait_pattern; | ||
40 | const uint32_t *wait_write; | ||
41 | int chip_delay; | ||
42 | }; | ||
43 | |||
44 | #define to_fsl_upm_nand(mtd) container_of(mtd, struct fsl_upm_nand, mtd) | ||
45 | |||
46 | static int fun_chip_ready(struct mtd_info *mtd) | ||
47 | { | ||
48 | struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); | ||
49 | |||
50 | if (gpio_get_value(fun->rnb_gpio)) | ||
51 | return 1; | ||
52 | |||
53 | dev_vdbg(fun->dev, "busy\n"); | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static void fun_wait_rnb(struct fsl_upm_nand *fun) | ||
58 | { | ||
59 | int cnt = 1000000; | ||
60 | |||
61 | if (fun->rnb_gpio >= 0) { | ||
62 | while (--cnt && !fun_chip_ready(&fun->mtd)) | ||
63 | cpu_relax(); | ||
64 | } | ||
65 | |||
66 | if (!cnt) | ||
67 | dev_err(fun->dev, "tired waiting for RNB\n"); | ||
68 | } | ||
69 | |||
70 | static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | ||
71 | { | ||
72 | struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); | ||
73 | |||
74 | if (!(ctrl & fun->last_ctrl)) { | ||
75 | fsl_upm_end_pattern(&fun->upm); | ||
76 | |||
77 | if (cmd == NAND_CMD_NONE) | ||
78 | return; | ||
79 | |||
80 | fun->last_ctrl = ctrl & (NAND_ALE | NAND_CLE); | ||
81 | } | ||
82 | |||
83 | if (ctrl & NAND_CTRL_CHANGE) { | ||
84 | if (ctrl & NAND_ALE) | ||
85 | fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset); | ||
86 | else if (ctrl & NAND_CLE) | ||
87 | fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset); | ||
88 | } | ||
89 | |||
90 | fsl_upm_run_pattern(&fun->upm, fun->io_base, cmd); | ||
91 | |||
92 | if (fun->wait_pattern) | ||
93 | fun_wait_rnb(fun); | ||
94 | } | ||
95 | |||
96 | static uint8_t fun_read_byte(struct mtd_info *mtd) | ||
97 | { | ||
98 | struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); | ||
99 | |||
100 | return in_8(fun->chip.IO_ADDR_R); | ||
101 | } | ||
102 | |||
103 | static void fun_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) | ||
104 | { | ||
105 | struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); | ||
106 | int i; | ||
107 | |||
108 | for (i = 0; i < len; i++) | ||
109 | buf[i] = in_8(fun->chip.IO_ADDR_R); | ||
110 | } | ||
111 | |||
112 | static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | ||
113 | { | ||
114 | struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); | ||
115 | int i; | ||
116 | |||
117 | for (i = 0; i < len; i++) { | ||
118 | out_8(fun->chip.IO_ADDR_W, buf[i]); | ||
119 | if (fun->wait_write) | ||
120 | fun_wait_rnb(fun); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | static int __devinit fun_chip_init(struct fsl_upm_nand *fun) | ||
125 | { | ||
126 | int ret; | ||
127 | #ifdef CONFIG_MTD_PARTITIONS | ||
128 | static const char *part_types[] = { "cmdlinepart", NULL, }; | ||
129 | #endif | ||
130 | |||
131 | fun->chip.IO_ADDR_R = fun->io_base; | ||
132 | fun->chip.IO_ADDR_W = fun->io_base; | ||
133 | fun->chip.cmd_ctrl = fun_cmd_ctrl; | ||
134 | fun->chip.chip_delay = fun->chip_delay; | ||
135 | fun->chip.read_byte = fun_read_byte; | ||
136 | fun->chip.read_buf = fun_read_buf; | ||
137 | fun->chip.write_buf = fun_write_buf; | ||
138 | fun->chip.ecc.mode = NAND_ECC_SOFT; | ||
139 | |||
140 | if (fun->rnb_gpio >= 0) | ||
141 | fun->chip.dev_ready = fun_chip_ready; | ||
142 | |||
143 | fun->mtd.priv = &fun->chip; | ||
144 | fun->mtd.owner = THIS_MODULE; | ||
145 | |||
146 | ret = nand_scan(&fun->mtd, 1); | ||
147 | if (ret) | ||
148 | return ret; | ||
149 | |||
150 | fun->mtd.name = fun->dev->bus_id; | ||
151 | |||
152 | #ifdef CONFIG_MTD_PARTITIONS | ||
153 | ret = parse_mtd_partitions(&fun->mtd, part_types, &fun->parts, 0); | ||
154 | if (ret > 0) | ||
155 | return add_mtd_partitions(&fun->mtd, fun->parts, ret); | ||
156 | #endif | ||
157 | return add_mtd_device(&fun->mtd); | ||
158 | } | ||
159 | |||
160 | static int __devinit fun_probe(struct of_device *ofdev, | ||
161 | const struct of_device_id *ofid) | ||
162 | { | ||
163 | struct fsl_upm_nand *fun; | ||
164 | struct resource io_res; | ||
165 | const uint32_t *prop; | ||
166 | int ret; | ||
167 | int size; | ||
168 | |||
169 | fun = kzalloc(sizeof(*fun), GFP_KERNEL); | ||
170 | if (!fun) | ||
171 | return -ENOMEM; | ||
172 | |||
173 | ret = of_address_to_resource(ofdev->node, 0, &io_res); | ||
174 | if (ret) { | ||
175 | dev_err(&ofdev->dev, "can't get IO base\n"); | ||
176 | goto err1; | ||
177 | } | ||
178 | |||
179 | ret = fsl_upm_find(io_res.start, &fun->upm); | ||
180 | if (ret) { | ||
181 | dev_err(&ofdev->dev, "can't find UPM\n"); | ||
182 | goto err1; | ||
183 | } | ||
184 | |||
185 | prop = of_get_property(ofdev->node, "fsl,upm-addr-offset", &size); | ||
186 | if (!prop || size != sizeof(uint32_t)) { | ||
187 | dev_err(&ofdev->dev, "can't get UPM address offset\n"); | ||
188 | ret = -EINVAL; | ||
189 | goto err2; | ||
190 | } | ||
191 | fun->upm_addr_offset = *prop; | ||
192 | |||
193 | prop = of_get_property(ofdev->node, "fsl,upm-cmd-offset", &size); | ||
194 | if (!prop || size != sizeof(uint32_t)) { | ||
195 | dev_err(&ofdev->dev, "can't get UPM command offset\n"); | ||
196 | ret = -EINVAL; | ||
197 | goto err2; | ||
198 | } | ||
199 | fun->upm_cmd_offset = *prop; | ||
200 | |||
201 | fun->rnb_gpio = of_get_gpio(ofdev->node, 0); | ||
202 | if (fun->rnb_gpio >= 0) { | ||
203 | ret = gpio_request(fun->rnb_gpio, ofdev->dev.bus_id); | ||
204 | if (ret) { | ||
205 | dev_err(&ofdev->dev, "can't request RNB gpio\n"); | ||
206 | goto err2; | ||
207 | } | ||
208 | gpio_direction_input(fun->rnb_gpio); | ||
209 | } else if (fun->rnb_gpio == -EINVAL) { | ||
210 | dev_err(&ofdev->dev, "specified RNB gpio is invalid\n"); | ||
211 | goto err2; | ||
212 | } | ||
213 | |||
214 | fun->io_base = devm_ioremap_nocache(&ofdev->dev, io_res.start, | ||
215 | io_res.end - io_res.start + 1); | ||
216 | if (!fun->io_base) { | ||
217 | ret = -ENOMEM; | ||
218 | goto err2; | ||
219 | } | ||
220 | |||
221 | fun->dev = &ofdev->dev; | ||
222 | fun->last_ctrl = NAND_CLE; | ||
223 | fun->wait_pattern = of_get_property(ofdev->node, "fsl,wait-pattern", | ||
224 | NULL); | ||
225 | fun->wait_write = of_get_property(ofdev->node, "fsl,wait-write", NULL); | ||
226 | |||
227 | prop = of_get_property(ofdev->node, "chip-delay", NULL); | ||
228 | if (prop) | ||
229 | fun->chip_delay = *prop; | ||
230 | else | ||
231 | fun->chip_delay = 50; | ||
232 | |||
233 | ret = fun_chip_init(fun); | ||
234 | if (ret) | ||
235 | goto err2; | ||
236 | |||
237 | dev_set_drvdata(&ofdev->dev, fun); | ||
238 | |||
239 | return 0; | ||
240 | err2: | ||
241 | if (fun->rnb_gpio >= 0) | ||
242 | gpio_free(fun->rnb_gpio); | ||
243 | err1: | ||
244 | kfree(fun); | ||
245 | |||
246 | return ret; | ||
247 | } | ||
248 | |||
249 | static int __devexit fun_remove(struct of_device *ofdev) | ||
250 | { | ||
251 | struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev); | ||
252 | |||
253 | nand_release(&fun->mtd); | ||
254 | |||
255 | if (fun->rnb_gpio >= 0) | ||
256 | gpio_free(fun->rnb_gpio); | ||
257 | |||
258 | kfree(fun); | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static struct of_device_id of_fun_match[] = { | ||
264 | { .compatible = "fsl,upm-nand" }, | ||
265 | {}, | ||
266 | }; | ||
267 | MODULE_DEVICE_TABLE(of, of_fun_match); | ||
268 | |||
269 | static struct of_platform_driver of_fun_driver = { | ||
270 | .name = "fsl,upm-nand", | ||
271 | .match_table = of_fun_match, | ||
272 | .probe = fun_probe, | ||
273 | .remove = __devexit_p(fun_remove), | ||
274 | }; | ||
275 | |||
276 | static int __init fun_module_init(void) | ||
277 | { | ||
278 | return of_register_platform_driver(&of_fun_driver); | ||
279 | } | ||
280 | module_init(fun_module_init); | ||
281 | |||
282 | static void __exit fun_module_exit(void) | ||
283 | { | ||
284 | of_unregister_platform_driver(&of_fun_driver); | ||
285 | } | ||
286 | module_exit(fun_module_exit); | ||
287 | |||
288 | MODULE_LICENSE("GPL"); | ||
289 | MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>"); | ||
290 | MODULE_DESCRIPTION("Driver for NAND chips working through Freescale " | ||
291 | "LocalBus User-Programmable Machine"); | ||
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 7acb1a0e7409..ba1bdf787323 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -2229,6 +2229,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
2229 | { | 2229 | { |
2230 | struct nand_flash_dev *type = NULL; | 2230 | struct nand_flash_dev *type = NULL; |
2231 | int i, dev_id, maf_idx; | 2231 | int i, dev_id, maf_idx; |
2232 | int tmp_id, tmp_manf; | ||
2232 | 2233 | ||
2233 | /* Select the device */ | 2234 | /* Select the device */ |
2234 | chip->select_chip(mtd, 0); | 2235 | chip->select_chip(mtd, 0); |
@@ -2240,6 +2241,26 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
2240 | *maf_id = chip->read_byte(mtd); | 2241 | *maf_id = chip->read_byte(mtd); |
2241 | dev_id = chip->read_byte(mtd); | 2242 | dev_id = chip->read_byte(mtd); |
2242 | 2243 | ||
2244 | /* Try again to make sure, as some systems the bus-hold or other | ||
2245 | * interface concerns can cause random data which looks like a | ||
2246 | * possibly credible NAND flash to appear. If the two results do | ||
2247 | * not match, ignore the device completely. | ||
2248 | */ | ||
2249 | |||
2250 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); | ||
2251 | |||
2252 | /* Read manufacturer and device IDs */ | ||
2253 | |||
2254 | tmp_manf = chip->read_byte(mtd); | ||
2255 | tmp_id = chip->read_byte(mtd); | ||
2256 | |||
2257 | if (tmp_manf != *maf_id || tmp_id != dev_id) { | ||
2258 | printk(KERN_INFO "%s: second ID read did not match " | ||
2259 | "%02x,%02x against %02x,%02x\n", __func__, | ||
2260 | *maf_id, dev_id, tmp_manf, tmp_id); | ||
2261 | return ERR_PTR(-ENODEV); | ||
2262 | } | ||
2263 | |||
2243 | /* Lookup the flash id */ | 2264 | /* Lookup the flash id */ |
2244 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { | 2265 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { |
2245 | if (dev_id == nand_flash_ids[i].id) { | 2266 | if (dev_id == nand_flash_ids[i].id) { |
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 1c0e89f00e8d..955959eb02d4 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c | |||
@@ -317,3 +317,5 @@ module_exit(ndfc_nand_exit); | |||
317 | MODULE_LICENSE("GPL"); | 317 | MODULE_LICENSE("GPL"); |
318 | MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); | 318 | MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); |
319 | MODULE_DESCRIPTION("Platform driver for NDFC"); | 319 | MODULE_DESCRIPTION("Platform driver for NDFC"); |
320 | MODULE_ALIAS("platform:ndfc-chip"); | ||
321 | MODULE_ALIAS("platform:ndfc-nand"); | ||
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index ec5ad28b237e..59e05a1c50cf 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c | |||
@@ -169,3 +169,4 @@ module_exit(orion_nand_exit); | |||
169 | MODULE_LICENSE("GPL"); | 169 | MODULE_LICENSE("GPL"); |
170 | MODULE_AUTHOR("Tzachi Perelstein"); | 170 | MODULE_AUTHOR("Tzachi Perelstein"); |
171 | MODULE_DESCRIPTION("NAND glue for Orion platforms"); | 171 | MODULE_DESCRIPTION("NAND glue for Orion platforms"); |
172 | MODULE_ALIAS("platform:orion_nand"); | ||
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index f6d5c2adc4fd..f674c5427b17 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c | |||
@@ -54,6 +54,7 @@ static int __init plat_nand_probe(struct platform_device *pdev) | |||
54 | data->chip.priv = &data; | 54 | data->chip.priv = &data; |
55 | data->mtd.priv = &data->chip; | 55 | data->mtd.priv = &data->chip; |
56 | data->mtd.owner = THIS_MODULE; | 56 | data->mtd.owner = THIS_MODULE; |
57 | data->mtd.name = pdev->dev.bus_id; | ||
57 | 58 | ||
58 | data->chip.IO_ADDR_R = data->io_base; | 59 | data->chip.IO_ADDR_R = data->io_base; |
59 | data->chip.IO_ADDR_W = data->io_base; | 60 | data->chip.IO_ADDR_W = data->io_base; |
@@ -150,3 +151,4 @@ module_exit(plat_nand_exit); | |||
150 | MODULE_LICENSE("GPL"); | 151 | MODULE_LICENSE("GPL"); |
151 | MODULE_AUTHOR("Vitaly Wool"); | 152 | MODULE_AUTHOR("Vitaly Wool"); |
152 | MODULE_DESCRIPTION("Simple generic NAND driver"); | 153 | MODULE_DESCRIPTION("Simple generic NAND driver"); |
154 | MODULE_ALIAS("platform:gen_nand"); | ||
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c new file mode 100644 index 000000000000..fceb468ccdec --- /dev/null +++ b/drivers/mtd/nand/pxa3xx_nand.c | |||
@@ -0,0 +1,1249 @@ | |||
1 | /* | ||
2 | * drivers/mtd/nand/pxa3xx_nand.c | ||
3 | * | ||
4 | * Copyright © 2005 Intel Corporation | ||
5 | * Copyright © 2006 Marvell International Ltd. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/dma-mapping.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/clk.h> | ||
18 | #include <linux/mtd/mtd.h> | ||
19 | #include <linux/mtd/nand.h> | ||
20 | #include <linux/mtd/partitions.h> | ||
21 | #include <linux/io.h> | ||
22 | #include <linux/irq.h> | ||
23 | #include <asm/dma.h> | ||
24 | |||
25 | #include <asm/arch/pxa-regs.h> | ||
26 | #include <asm/arch/pxa3xx_nand.h> | ||
27 | |||
28 | #define CHIP_DELAY_TIMEOUT (2 * HZ/10) | ||
29 | |||
30 | /* registers and bit definitions */ | ||
31 | #define NDCR (0x00) /* Control register */ | ||
32 | #define NDTR0CS0 (0x04) /* Timing Parameter 0 for CS0 */ | ||
33 | #define NDTR1CS0 (0x0C) /* Timing Parameter 1 for CS0 */ | ||
34 | #define NDSR (0x14) /* Status Register */ | ||
35 | #define NDPCR (0x18) /* Page Count Register */ | ||
36 | #define NDBDR0 (0x1C) /* Bad Block Register 0 */ | ||
37 | #define NDBDR1 (0x20) /* Bad Block Register 1 */ | ||
38 | #define NDDB (0x40) /* Data Buffer */ | ||
39 | #define NDCB0 (0x48) /* Command Buffer0 */ | ||
40 | #define NDCB1 (0x4C) /* Command Buffer1 */ | ||
41 | #define NDCB2 (0x50) /* Command Buffer2 */ | ||
42 | |||
43 | #define NDCR_SPARE_EN (0x1 << 31) | ||
44 | #define NDCR_ECC_EN (0x1 << 30) | ||
45 | #define NDCR_DMA_EN (0x1 << 29) | ||
46 | #define NDCR_ND_RUN (0x1 << 28) | ||
47 | #define NDCR_DWIDTH_C (0x1 << 27) | ||
48 | #define NDCR_DWIDTH_M (0x1 << 26) | ||
49 | #define NDCR_PAGE_SZ (0x1 << 24) | ||
50 | #define NDCR_NCSX (0x1 << 23) | ||
51 | #define NDCR_ND_MODE (0x3 << 21) | ||
52 | #define NDCR_NAND_MODE (0x0) | ||
53 | #define NDCR_CLR_PG_CNT (0x1 << 20) | ||
54 | #define NDCR_CLR_ECC (0x1 << 19) | ||
55 | #define NDCR_RD_ID_CNT_MASK (0x7 << 16) | ||
56 | #define NDCR_RD_ID_CNT(x) (((x) << 16) & NDCR_RD_ID_CNT_MASK) | ||
57 | |||
58 | #define NDCR_RA_START (0x1 << 15) | ||
59 | #define NDCR_PG_PER_BLK (0x1 << 14) | ||
60 | #define NDCR_ND_ARB_EN (0x1 << 12) | ||
61 | |||
62 | #define NDSR_MASK (0xfff) | ||
63 | #define NDSR_RDY (0x1 << 11) | ||
64 | #define NDSR_CS0_PAGED (0x1 << 10) | ||
65 | #define NDSR_CS1_PAGED (0x1 << 9) | ||
66 | #define NDSR_CS0_CMDD (0x1 << 8) | ||
67 | #define NDSR_CS1_CMDD (0x1 << 7) | ||
68 | #define NDSR_CS0_BBD (0x1 << 6) | ||
69 | #define NDSR_CS1_BBD (0x1 << 5) | ||
70 | #define NDSR_DBERR (0x1 << 4) | ||
71 | #define NDSR_SBERR (0x1 << 3) | ||
72 | #define NDSR_WRDREQ (0x1 << 2) | ||
73 | #define NDSR_RDDREQ (0x1 << 1) | ||
74 | #define NDSR_WRCMDREQ (0x1) | ||
75 | |||
76 | #define NDCB0_AUTO_RS (0x1 << 25) | ||
77 | #define NDCB0_CSEL (0x1 << 24) | ||
78 | #define NDCB0_CMD_TYPE_MASK (0x7 << 21) | ||
79 | #define NDCB0_CMD_TYPE(x) (((x) << 21) & NDCB0_CMD_TYPE_MASK) | ||
80 | #define NDCB0_NC (0x1 << 20) | ||
81 | #define NDCB0_DBC (0x1 << 19) | ||
82 | #define NDCB0_ADDR_CYC_MASK (0x7 << 16) | ||
83 | #define NDCB0_ADDR_CYC(x) (((x) << 16) & NDCB0_ADDR_CYC_MASK) | ||
84 | #define NDCB0_CMD2_MASK (0xff << 8) | ||
85 | #define NDCB0_CMD1_MASK (0xff) | ||
86 | #define NDCB0_ADDR_CYC_SHIFT (16) | ||
87 | |||
88 | /* dma-able I/O address for the NAND data and commands */ | ||
89 | #define NDCB0_DMA_ADDR (0x43100048) | ||
90 | #define NDDB_DMA_ADDR (0x43100040) | ||
91 | |||
92 | /* macros for registers read/write */ | ||
93 | #define nand_writel(info, off, val) \ | ||
94 | __raw_writel((val), (info)->mmio_base + (off)) | ||
95 | |||
96 | #define nand_readl(info, off) \ | ||
97 | __raw_readl((info)->mmio_base + (off)) | ||
98 | |||
99 | /* error code and state */ | ||
100 | enum { | ||
101 | ERR_NONE = 0, | ||
102 | ERR_DMABUSERR = -1, | ||
103 | ERR_SENDCMD = -2, | ||
104 | ERR_DBERR = -3, | ||
105 | ERR_BBERR = -4, | ||
106 | }; | ||
107 | |||
108 | enum { | ||
109 | STATE_READY = 0, | ||
110 | STATE_CMD_HANDLE, | ||
111 | STATE_DMA_READING, | ||
112 | STATE_DMA_WRITING, | ||
113 | STATE_DMA_DONE, | ||
114 | STATE_PIO_READING, | ||
115 | STATE_PIO_WRITING, | ||
116 | }; | ||
117 | |||
118 | struct pxa3xx_nand_timing { | ||
119 | unsigned int tCH; /* Enable signal hold time */ | ||
120 | unsigned int tCS; /* Enable signal setup time */ | ||
121 | unsigned int tWH; /* ND_nWE high duration */ | ||
122 | unsigned int tWP; /* ND_nWE pulse time */ | ||
123 | unsigned int tRH; /* ND_nRE high duration */ | ||
124 | unsigned int tRP; /* ND_nRE pulse width */ | ||
125 | unsigned int tR; /* ND_nWE high to ND_nRE low for read */ | ||
126 | unsigned int tWHR; /* ND_nWE high to ND_nRE low for status read */ | ||
127 | unsigned int tAR; /* ND_ALE low to ND_nRE low delay */ | ||
128 | }; | ||
129 | |||
130 | struct pxa3xx_nand_cmdset { | ||
131 | uint16_t read1; | ||
132 | uint16_t read2; | ||
133 | uint16_t program; | ||
134 | uint16_t read_status; | ||
135 | uint16_t read_id; | ||
136 | uint16_t erase; | ||
137 | uint16_t reset; | ||
138 | uint16_t lock; | ||
139 | uint16_t unlock; | ||
140 | uint16_t lock_status; | ||
141 | }; | ||
142 | |||
143 | struct pxa3xx_nand_flash { | ||
144 | struct pxa3xx_nand_timing *timing; /* NAND Flash timing */ | ||
145 | struct pxa3xx_nand_cmdset *cmdset; | ||
146 | |||
147 | uint32_t page_per_block;/* Pages per block (PG_PER_BLK) */ | ||
148 | uint32_t page_size; /* Page size in bytes (PAGE_SZ) */ | ||
149 | uint32_t flash_width; /* Width of Flash memory (DWIDTH_M) */ | ||
150 | uint32_t dfc_width; /* Width of flash controller(DWIDTH_C) */ | ||
151 | uint32_t num_blocks; /* Number of physical blocks in Flash */ | ||
152 | uint32_t chip_id; | ||
153 | |||
154 | /* NOTE: these are automatically calculated, do not define */ | ||
155 | size_t oob_size; | ||
156 | size_t read_id_bytes; | ||
157 | |||
158 | unsigned int col_addr_cycles; | ||
159 | unsigned int row_addr_cycles; | ||
160 | }; | ||
161 | |||
162 | struct pxa3xx_nand_info { | ||
163 | struct nand_chip nand_chip; | ||
164 | |||
165 | struct platform_device *pdev; | ||
166 | struct pxa3xx_nand_flash *flash_info; | ||
167 | |||
168 | struct clk *clk; | ||
169 | void __iomem *mmio_base; | ||
170 | |||
171 | unsigned int buf_start; | ||
172 | unsigned int buf_count; | ||
173 | |||
174 | /* DMA information */ | ||
175 | int drcmr_dat; | ||
176 | int drcmr_cmd; | ||
177 | |||
178 | unsigned char *data_buff; | ||
179 | dma_addr_t data_buff_phys; | ||
180 | size_t data_buff_size; | ||
181 | int data_dma_ch; | ||
182 | struct pxa_dma_desc *data_desc; | ||
183 | dma_addr_t data_desc_addr; | ||
184 | |||
185 | uint32_t reg_ndcr; | ||
186 | |||
187 | /* saved column/page_addr during CMD_SEQIN */ | ||
188 | int seqin_column; | ||
189 | int seqin_page_addr; | ||
190 | |||
191 | /* relate to the command */ | ||
192 | unsigned int state; | ||
193 | |||
194 | int use_ecc; /* use HW ECC ? */ | ||
195 | int use_dma; /* use DMA ? */ | ||
196 | |||
197 | size_t data_size; /* data size in FIFO */ | ||
198 | int retcode; | ||
199 | struct completion cmd_complete; | ||
200 | |||
201 | /* generated NDCBx register values */ | ||
202 | uint32_t ndcb0; | ||
203 | uint32_t ndcb1; | ||
204 | uint32_t ndcb2; | ||
205 | }; | ||
206 | |||
207 | static int use_dma = 1; | ||
208 | module_param(use_dma, bool, 0444); | ||
209 | MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND HW"); | ||
210 | |||
211 | static struct pxa3xx_nand_cmdset smallpage_cmdset = { | ||
212 | .read1 = 0x0000, | ||
213 | .read2 = 0x0050, | ||
214 | .program = 0x1080, | ||
215 | .read_status = 0x0070, | ||
216 | .read_id = 0x0090, | ||
217 | .erase = 0xD060, | ||
218 | .reset = 0x00FF, | ||
219 | .lock = 0x002A, | ||
220 | .unlock = 0x2423, | ||
221 | .lock_status = 0x007A, | ||
222 | }; | ||
223 | |||
224 | static struct pxa3xx_nand_cmdset largepage_cmdset = { | ||
225 | .read1 = 0x3000, | ||
226 | .read2 = 0x0050, | ||
227 | .program = 0x1080, | ||
228 | .read_status = 0x0070, | ||
229 | .read_id = 0x0090, | ||
230 | .erase = 0xD060, | ||
231 | .reset = 0x00FF, | ||
232 | .lock = 0x002A, | ||
233 | .unlock = 0x2423, | ||
234 | .lock_status = 0x007A, | ||
235 | }; | ||
236 | |||
237 | static struct pxa3xx_nand_timing samsung512MbX16_timing = { | ||
238 | .tCH = 10, | ||
239 | .tCS = 0, | ||
240 | .tWH = 20, | ||
241 | .tWP = 40, | ||
242 | .tRH = 30, | ||
243 | .tRP = 40, | ||
244 | .tR = 11123, | ||
245 | .tWHR = 110, | ||
246 | .tAR = 10, | ||
247 | }; | ||
248 | |||
249 | static struct pxa3xx_nand_flash samsung512MbX16 = { | ||
250 | .timing = &samsung512MbX16_timing, | ||
251 | .cmdset = &smallpage_cmdset, | ||
252 | .page_per_block = 32, | ||
253 | .page_size = 512, | ||
254 | .flash_width = 16, | ||
255 | .dfc_width = 16, | ||
256 | .num_blocks = 4096, | ||
257 | .chip_id = 0x46ec, | ||
258 | }; | ||
259 | |||
260 | static struct pxa3xx_nand_timing micron_timing = { | ||
261 | .tCH = 10, | ||
262 | .tCS = 25, | ||
263 | .tWH = 15, | ||
264 | .tWP = 25, | ||
265 | .tRH = 15, | ||
266 | .tRP = 25, | ||
267 | .tR = 25000, | ||
268 | .tWHR = 60, | ||
269 | .tAR = 10, | ||
270 | }; | ||
271 | |||
272 | static struct pxa3xx_nand_flash micron1GbX8 = { | ||
273 | .timing = µn_timing, | ||
274 | .cmdset = &largepage_cmdset, | ||
275 | .page_per_block = 64, | ||
276 | .page_size = 2048, | ||
277 | .flash_width = 8, | ||
278 | .dfc_width = 8, | ||
279 | .num_blocks = 1024, | ||
280 | .chip_id = 0xa12c, | ||
281 | }; | ||
282 | |||
283 | static struct pxa3xx_nand_flash micron1GbX16 = { | ||
284 | .timing = µn_timing, | ||
285 | .cmdset = &largepage_cmdset, | ||
286 | .page_per_block = 64, | ||
287 | .page_size = 2048, | ||
288 | .flash_width = 16, | ||
289 | .dfc_width = 16, | ||
290 | .num_blocks = 1024, | ||
291 | .chip_id = 0xb12c, | ||
292 | }; | ||
293 | |||
294 | static struct pxa3xx_nand_flash *builtin_flash_types[] = { | ||
295 | &samsung512MbX16, | ||
296 | µn1GbX8, | ||
297 | µn1GbX16, | ||
298 | }; | ||
299 | |||
300 | #define NDTR0_tCH(c) (min((c), 7) << 19) | ||
301 | #define NDTR0_tCS(c) (min((c), 7) << 16) | ||
302 | #define NDTR0_tWH(c) (min((c), 7) << 11) | ||
303 | #define NDTR0_tWP(c) (min((c), 7) << 8) | ||
304 | #define NDTR0_tRH(c) (min((c), 7) << 3) | ||
305 | #define NDTR0_tRP(c) (min((c), 7) << 0) | ||
306 | |||
307 | #define NDTR1_tR(c) (min((c), 65535) << 16) | ||
308 | #define NDTR1_tWHR(c) (min((c), 15) << 4) | ||
309 | #define NDTR1_tAR(c) (min((c), 15) << 0) | ||
310 | |||
311 | /* convert nano-seconds to nand flash controller clock cycles */ | ||
312 | #define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) + 1) | ||
313 | |||
314 | static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, | ||
315 | struct pxa3xx_nand_timing *t) | ||
316 | { | ||
317 | unsigned long nand_clk = clk_get_rate(info->clk); | ||
318 | uint32_t ndtr0, ndtr1; | ||
319 | |||
320 | ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) | | ||
321 | NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) | | ||
322 | NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) | | ||
323 | NDTR0_tWP(ns2cycle(t->tWP, nand_clk)) | | ||
324 | NDTR0_tRH(ns2cycle(t->tRH, nand_clk)) | | ||
325 | NDTR0_tRP(ns2cycle(t->tRP, nand_clk)); | ||
326 | |||
327 | ndtr1 = NDTR1_tR(ns2cycle(t->tR, nand_clk)) | | ||
328 | NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) | | ||
329 | NDTR1_tAR(ns2cycle(t->tAR, nand_clk)); | ||
330 | |||
331 | nand_writel(info, NDTR0CS0, ndtr0); | ||
332 | nand_writel(info, NDTR1CS0, ndtr1); | ||
333 | } | ||
334 | |||
335 | #define WAIT_EVENT_TIMEOUT 10 | ||
336 | |||
337 | static int wait_for_event(struct pxa3xx_nand_info *info, uint32_t event) | ||
338 | { | ||
339 | int timeout = WAIT_EVENT_TIMEOUT; | ||
340 | uint32_t ndsr; | ||
341 | |||
342 | while (timeout--) { | ||
343 | ndsr = nand_readl(info, NDSR) & NDSR_MASK; | ||
344 | if (ndsr & event) { | ||
345 | nand_writel(info, NDSR, ndsr); | ||
346 | return 0; | ||
347 | } | ||
348 | udelay(10); | ||
349 | } | ||
350 | |||
351 | return -ETIMEDOUT; | ||
352 | } | ||
353 | |||
354 | static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info, | ||
355 | uint16_t cmd, int column, int page_addr) | ||
356 | { | ||
357 | struct pxa3xx_nand_flash *f = info->flash_info; | ||
358 | struct pxa3xx_nand_cmdset *cmdset = f->cmdset; | ||
359 | |||
360 | /* calculate data size */ | ||
361 | switch (f->page_size) { | ||
362 | case 2048: | ||
363 | info->data_size = (info->use_ecc) ? 2088 : 2112; | ||
364 | break; | ||
365 | case 512: | ||
366 | info->data_size = (info->use_ecc) ? 520 : 528; | ||
367 | break; | ||
368 | default: | ||
369 | return -EINVAL; | ||
370 | } | ||
371 | |||
372 | /* generate values for NDCBx registers */ | ||
373 | info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); | ||
374 | info->ndcb1 = 0; | ||
375 | info->ndcb2 = 0; | ||
376 | info->ndcb0 |= NDCB0_ADDR_CYC(f->row_addr_cycles + f->col_addr_cycles); | ||
377 | |||
378 | if (f->col_addr_cycles == 2) { | ||
379 | /* large block, 2 cycles for column address | ||
380 | * row address starts from 3rd cycle | ||
381 | */ | ||
382 | info->ndcb1 |= (page_addr << 16) | (column & 0xffff); | ||
383 | if (f->row_addr_cycles == 3) | ||
384 | info->ndcb2 = (page_addr >> 16) & 0xff; | ||
385 | } else | ||
386 | /* small block, 1 cycles for column address | ||
387 | * row address starts from 2nd cycle | ||
388 | */ | ||
389 | info->ndcb1 = (page_addr << 8) | (column & 0xff); | ||
390 | |||
391 | if (cmd == cmdset->program) | ||
392 | info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS; | ||
393 | |||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static int prepare_erase_cmd(struct pxa3xx_nand_info *info, | ||
398 | uint16_t cmd, int page_addr) | ||
399 | { | ||
400 | info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); | ||
401 | info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3); | ||
402 | info->ndcb1 = page_addr; | ||
403 | info->ndcb2 = 0; | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd) | ||
408 | { | ||
409 | struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset; | ||
410 | |||
411 | info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); | ||
412 | info->ndcb1 = 0; | ||
413 | info->ndcb2 = 0; | ||
414 | |||
415 | if (cmd == cmdset->read_id) { | ||
416 | info->ndcb0 |= NDCB0_CMD_TYPE(3); | ||
417 | info->data_size = 8; | ||
418 | } else if (cmd == cmdset->read_status) { | ||
419 | info->ndcb0 |= NDCB0_CMD_TYPE(4); | ||
420 | info->data_size = 8; | ||
421 | } else if (cmd == cmdset->reset || cmd == cmdset->lock || | ||
422 | cmd == cmdset->unlock) { | ||
423 | info->ndcb0 |= NDCB0_CMD_TYPE(5); | ||
424 | } else | ||
425 | return -EINVAL; | ||
426 | |||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) | ||
431 | { | ||
432 | uint32_t ndcr; | ||
433 | |||
434 | ndcr = nand_readl(info, NDCR); | ||
435 | nand_writel(info, NDCR, ndcr & ~int_mask); | ||
436 | } | ||
437 | |||
438 | static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) | ||
439 | { | ||
440 | uint32_t ndcr; | ||
441 | |||
442 | ndcr = nand_readl(info, NDCR); | ||
443 | nand_writel(info, NDCR, ndcr | int_mask); | ||
444 | } | ||
445 | |||
446 | /* NOTE: it is a must to set ND_RUN firstly, then write command buffer | ||
447 | * otherwise, it does not work | ||
448 | */ | ||
449 | static int write_cmd(struct pxa3xx_nand_info *info) | ||
450 | { | ||
451 | uint32_t ndcr; | ||
452 | |||
453 | /* clear status bits and run */ | ||
454 | nand_writel(info, NDSR, NDSR_MASK); | ||
455 | |||
456 | ndcr = info->reg_ndcr; | ||
457 | |||
458 | ndcr |= info->use_ecc ? NDCR_ECC_EN : 0; | ||
459 | ndcr |= info->use_dma ? NDCR_DMA_EN : 0; | ||
460 | ndcr |= NDCR_ND_RUN; | ||
461 | |||
462 | nand_writel(info, NDCR, ndcr); | ||
463 | |||
464 | if (wait_for_event(info, NDSR_WRCMDREQ)) { | ||
465 | printk(KERN_ERR "timed out writing command\n"); | ||
466 | return -ETIMEDOUT; | ||
467 | } | ||
468 | |||
469 | nand_writel(info, NDCB0, info->ndcb0); | ||
470 | nand_writel(info, NDCB0, info->ndcb1); | ||
471 | nand_writel(info, NDCB0, info->ndcb2); | ||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | static int handle_data_pio(struct pxa3xx_nand_info *info) | ||
476 | { | ||
477 | int ret, timeout = CHIP_DELAY_TIMEOUT; | ||
478 | |||
479 | switch (info->state) { | ||
480 | case STATE_PIO_WRITING: | ||
481 | __raw_writesl(info->mmio_base + NDDB, info->data_buff, | ||
482 | info->data_size << 2); | ||
483 | |||
484 | enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD); | ||
485 | |||
486 | ret = wait_for_completion_timeout(&info->cmd_complete, timeout); | ||
487 | if (!ret) { | ||
488 | printk(KERN_ERR "program command time out\n"); | ||
489 | return -1; | ||
490 | } | ||
491 | break; | ||
492 | case STATE_PIO_READING: | ||
493 | __raw_readsl(info->mmio_base + NDDB, info->data_buff, | ||
494 | info->data_size << 2); | ||
495 | break; | ||
496 | default: | ||
497 | printk(KERN_ERR "%s: invalid state %d\n", __func__, | ||
498 | info->state); | ||
499 | return -EINVAL; | ||
500 | } | ||
501 | |||
502 | info->state = STATE_READY; | ||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | static void start_data_dma(struct pxa3xx_nand_info *info, int dir_out) | ||
507 | { | ||
508 | struct pxa_dma_desc *desc = info->data_desc; | ||
509 | int dma_len = ALIGN(info->data_size, 32); | ||
510 | |||
511 | desc->ddadr = DDADR_STOP; | ||
512 | desc->dcmd = DCMD_ENDIRQEN | DCMD_WIDTH4 | DCMD_BURST32 | dma_len; | ||
513 | |||
514 | if (dir_out) { | ||
515 | desc->dsadr = info->data_buff_phys; | ||
516 | desc->dtadr = NDDB_DMA_ADDR; | ||
517 | desc->dcmd |= DCMD_INCSRCADDR | DCMD_FLOWTRG; | ||
518 | } else { | ||
519 | desc->dtadr = info->data_buff_phys; | ||
520 | desc->dsadr = NDDB_DMA_ADDR; | ||
521 | desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC; | ||
522 | } | ||
523 | |||
524 | DRCMR(info->drcmr_dat) = DRCMR_MAPVLD | info->data_dma_ch; | ||
525 | DDADR(info->data_dma_ch) = info->data_desc_addr; | ||
526 | DCSR(info->data_dma_ch) |= DCSR_RUN; | ||
527 | } | ||
528 | |||
529 | static void pxa3xx_nand_data_dma_irq(int channel, void *data) | ||
530 | { | ||
531 | struct pxa3xx_nand_info *info = data; | ||
532 | uint32_t dcsr; | ||
533 | |||
534 | dcsr = DCSR(channel); | ||
535 | DCSR(channel) = dcsr; | ||
536 | |||
537 | if (dcsr & DCSR_BUSERR) { | ||
538 | info->retcode = ERR_DMABUSERR; | ||
539 | complete(&info->cmd_complete); | ||
540 | } | ||
541 | |||
542 | if (info->state == STATE_DMA_WRITING) { | ||
543 | info->state = STATE_DMA_DONE; | ||
544 | enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD); | ||
545 | } else { | ||
546 | info->state = STATE_READY; | ||
547 | complete(&info->cmd_complete); | ||
548 | } | ||
549 | } | ||
550 | |||
551 | static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) | ||
552 | { | ||
553 | struct pxa3xx_nand_info *info = devid; | ||
554 | unsigned int status; | ||
555 | |||
556 | status = nand_readl(info, NDSR); | ||
557 | |||
558 | if (status & (NDSR_RDDREQ | NDSR_DBERR)) { | ||
559 | if (status & NDSR_DBERR) | ||
560 | info->retcode = ERR_DBERR; | ||
561 | |||
562 | disable_int(info, NDSR_RDDREQ | NDSR_DBERR); | ||
563 | |||
564 | if (info->use_dma) { | ||
565 | info->state = STATE_DMA_READING; | ||
566 | start_data_dma(info, 0); | ||
567 | } else { | ||
568 | info->state = STATE_PIO_READING; | ||
569 | complete(&info->cmd_complete); | ||
570 | } | ||
571 | } else if (status & NDSR_WRDREQ) { | ||
572 | disable_int(info, NDSR_WRDREQ); | ||
573 | if (info->use_dma) { | ||
574 | info->state = STATE_DMA_WRITING; | ||
575 | start_data_dma(info, 1); | ||
576 | } else { | ||
577 | info->state = STATE_PIO_WRITING; | ||
578 | complete(&info->cmd_complete); | ||
579 | } | ||
580 | } else if (status & (NDSR_CS0_BBD | NDSR_CS0_CMDD)) { | ||
581 | if (status & NDSR_CS0_BBD) | ||
582 | info->retcode = ERR_BBERR; | ||
583 | |||
584 | disable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD); | ||
585 | info->state = STATE_READY; | ||
586 | complete(&info->cmd_complete); | ||
587 | } | ||
588 | nand_writel(info, NDSR, status); | ||
589 | return IRQ_HANDLED; | ||
590 | } | ||
591 | |||
592 | static int pxa3xx_nand_do_cmd(struct pxa3xx_nand_info *info, uint32_t event) | ||
593 | { | ||
594 | uint32_t ndcr; | ||
595 | int ret, timeout = CHIP_DELAY_TIMEOUT; | ||
596 | |||
597 | if (write_cmd(info)) { | ||
598 | info->retcode = ERR_SENDCMD; | ||
599 | goto fail_stop; | ||
600 | } | ||
601 | |||
602 | info->state = STATE_CMD_HANDLE; | ||
603 | |||
604 | enable_int(info, event); | ||
605 | |||
606 | ret = wait_for_completion_timeout(&info->cmd_complete, timeout); | ||
607 | if (!ret) { | ||
608 | printk(KERN_ERR "command execution timed out\n"); | ||
609 | info->retcode = ERR_SENDCMD; | ||
610 | goto fail_stop; | ||
611 | } | ||
612 | |||
613 | if (info->use_dma == 0 && info->data_size > 0) | ||
614 | if (handle_data_pio(info)) | ||
615 | goto fail_stop; | ||
616 | |||
617 | return 0; | ||
618 | |||
619 | fail_stop: | ||
620 | ndcr = nand_readl(info, NDCR); | ||
621 | nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN); | ||
622 | udelay(10); | ||
623 | return -ETIMEDOUT; | ||
624 | } | ||
625 | |||
626 | static int pxa3xx_nand_dev_ready(struct mtd_info *mtd) | ||
627 | { | ||
628 | struct pxa3xx_nand_info *info = mtd->priv; | ||
629 | return (nand_readl(info, NDSR) & NDSR_RDY) ? 1 : 0; | ||
630 | } | ||
631 | |||
632 | static inline int is_buf_blank(uint8_t *buf, size_t len) | ||
633 | { | ||
634 | for (; len > 0; len--) | ||
635 | if (*buf++ != 0xff) | ||
636 | return 0; | ||
637 | return 1; | ||
638 | } | ||
639 | |||
640 | static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, | ||
641 | int column, int page_addr) | ||
642 | { | ||
643 | struct pxa3xx_nand_info *info = mtd->priv; | ||
644 | struct pxa3xx_nand_flash *flash_info = info->flash_info; | ||
645 | struct pxa3xx_nand_cmdset *cmdset = flash_info->cmdset; | ||
646 | int ret; | ||
647 | |||
648 | info->use_dma = (use_dma) ? 1 : 0; | ||
649 | info->use_ecc = 0; | ||
650 | info->data_size = 0; | ||
651 | info->state = STATE_READY; | ||
652 | |||
653 | init_completion(&info->cmd_complete); | ||
654 | |||
655 | switch (command) { | ||
656 | case NAND_CMD_READOOB: | ||
657 | /* disable HW ECC to get all the OOB data */ | ||
658 | info->buf_count = mtd->writesize + mtd->oobsize; | ||
659 | info->buf_start = mtd->writesize + column; | ||
660 | |||
661 | if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr)) | ||
662 | break; | ||
663 | |||
664 | pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR); | ||
665 | |||
666 | /* We only are OOB, so if the data has error, does not matter */ | ||
667 | if (info->retcode == ERR_DBERR) | ||
668 | info->retcode = ERR_NONE; | ||
669 | break; | ||
670 | |||
671 | case NAND_CMD_READ0: | ||
672 | info->use_ecc = 1; | ||
673 | info->retcode = ERR_NONE; | ||
674 | info->buf_start = column; | ||
675 | info->buf_count = mtd->writesize + mtd->oobsize; | ||
676 | memset(info->data_buff, 0xFF, info->buf_count); | ||
677 | |||
678 | if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr)) | ||
679 | break; | ||
680 | |||
681 | pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR); | ||
682 | |||
683 | if (info->retcode == ERR_DBERR) { | ||
684 | /* for blank page (all 0xff), HW will calculate its ECC as | ||
685 | * 0, which is different from the ECC information within | ||
686 | * OOB, ignore such double bit errors | ||
687 | */ | ||
688 | if (is_buf_blank(info->data_buff, mtd->writesize)) | ||
689 | info->retcode = ERR_NONE; | ||
690 | } | ||
691 | break; | ||
692 | case NAND_CMD_SEQIN: | ||
693 | info->buf_start = column; | ||
694 | info->buf_count = mtd->writesize + mtd->oobsize; | ||
695 | memset(info->data_buff, 0xff, info->buf_count); | ||
696 | |||
697 | /* save column/page_addr for next CMD_PAGEPROG */ | ||
698 | info->seqin_column = column; | ||
699 | info->seqin_page_addr = page_addr; | ||
700 | break; | ||
701 | case NAND_CMD_PAGEPROG: | ||
702 | info->use_ecc = (info->seqin_column >= mtd->writesize) ? 0 : 1; | ||
703 | |||
704 | if (prepare_read_prog_cmd(info, cmdset->program, | ||
705 | info->seqin_column, info->seqin_page_addr)) | ||
706 | break; | ||
707 | |||
708 | pxa3xx_nand_do_cmd(info, NDSR_WRDREQ); | ||
709 | break; | ||
710 | case NAND_CMD_ERASE1: | ||
711 | if (prepare_erase_cmd(info, cmdset->erase, page_addr)) | ||
712 | break; | ||
713 | |||
714 | pxa3xx_nand_do_cmd(info, NDSR_CS0_BBD | NDSR_CS0_CMDD); | ||
715 | break; | ||
716 | case NAND_CMD_ERASE2: | ||
717 | break; | ||
718 | case NAND_CMD_READID: | ||
719 | case NAND_CMD_STATUS: | ||
720 | info->use_dma = 0; /* force PIO read */ | ||
721 | info->buf_start = 0; | ||
722 | info->buf_count = (command == NAND_CMD_READID) ? | ||
723 | flash_info->read_id_bytes : 1; | ||
724 | |||
725 | if (prepare_other_cmd(info, (command == NAND_CMD_READID) ? | ||
726 | cmdset->read_id : cmdset->read_status)) | ||
727 | break; | ||
728 | |||
729 | pxa3xx_nand_do_cmd(info, NDSR_RDDREQ); | ||
730 | break; | ||
731 | case NAND_CMD_RESET: | ||
732 | if (prepare_other_cmd(info, cmdset->reset)) | ||
733 | break; | ||
734 | |||
735 | ret = pxa3xx_nand_do_cmd(info, NDSR_CS0_CMDD); | ||
736 | if (ret == 0) { | ||
737 | int timeout = 2; | ||
738 | uint32_t ndcr; | ||
739 | |||
740 | while (timeout--) { | ||
741 | if (nand_readl(info, NDSR) & NDSR_RDY) | ||
742 | break; | ||
743 | msleep(10); | ||
744 | } | ||
745 | |||
746 | ndcr = nand_readl(info, NDCR); | ||
747 | nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN); | ||
748 | } | ||
749 | break; | ||
750 | default: | ||
751 | printk(KERN_ERR "non-supported command.\n"); | ||
752 | break; | ||
753 | } | ||
754 | |||
755 | if (info->retcode == ERR_DBERR) { | ||
756 | printk(KERN_ERR "double bit error @ page %08x\n", page_addr); | ||
757 | info->retcode = ERR_NONE; | ||
758 | } | ||
759 | } | ||
760 | |||
761 | static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) | ||
762 | { | ||
763 | struct pxa3xx_nand_info *info = mtd->priv; | ||
764 | char retval = 0xFF; | ||
765 | |||
766 | if (info->buf_start < info->buf_count) | ||
767 | /* Has just send a new command? */ | ||
768 | retval = info->data_buff[info->buf_start++]; | ||
769 | |||
770 | return retval; | ||
771 | } | ||
772 | |||
773 | static u16 pxa3xx_nand_read_word(struct mtd_info *mtd) | ||
774 | { | ||
775 | struct pxa3xx_nand_info *info = mtd->priv; | ||
776 | u16 retval = 0xFFFF; | ||
777 | |||
778 | if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) { | ||
779 | retval = *((u16 *)(info->data_buff+info->buf_start)); | ||
780 | info->buf_start += 2; | ||
781 | } | ||
782 | return retval; | ||
783 | } | ||
784 | |||
785 | static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) | ||
786 | { | ||
787 | struct pxa3xx_nand_info *info = mtd->priv; | ||
788 | int real_len = min_t(size_t, len, info->buf_count - info->buf_start); | ||
789 | |||
790 | memcpy(buf, info->data_buff + info->buf_start, real_len); | ||
791 | info->buf_start += real_len; | ||
792 | } | ||
793 | |||
794 | static void pxa3xx_nand_write_buf(struct mtd_info *mtd, | ||
795 | const uint8_t *buf, int len) | ||
796 | { | ||
797 | struct pxa3xx_nand_info *info = mtd->priv; | ||
798 | int real_len = min_t(size_t, len, info->buf_count - info->buf_start); | ||
799 | |||
800 | memcpy(info->data_buff + info->buf_start, buf, real_len); | ||
801 | info->buf_start += real_len; | ||
802 | } | ||
803 | |||
804 | static int pxa3xx_nand_verify_buf(struct mtd_info *mtd, | ||
805 | const uint8_t *buf, int len) | ||
806 | { | ||
807 | return 0; | ||
808 | } | ||
809 | |||
810 | static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip) | ||
811 | { | ||
812 | return; | ||
813 | } | ||
814 | |||
815 | static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) | ||
816 | { | ||
817 | struct pxa3xx_nand_info *info = mtd->priv; | ||
818 | |||
819 | /* pxa3xx_nand_send_command has waited for command complete */ | ||
820 | if (this->state == FL_WRITING || this->state == FL_ERASING) { | ||
821 | if (info->retcode == ERR_NONE) | ||
822 | return 0; | ||
823 | else { | ||
824 | /* | ||
825 | * any error make it return 0x01 which will tell | ||
826 | * the caller the erase and write fail | ||
827 | */ | ||
828 | return 0x01; | ||
829 | } | ||
830 | } | ||
831 | |||
832 | return 0; | ||
833 | } | ||
834 | |||
835 | static void pxa3xx_nand_ecc_hwctl(struct mtd_info *mtd, int mode) | ||
836 | { | ||
837 | return; | ||
838 | } | ||
839 | |||
840 | static int pxa3xx_nand_ecc_calculate(struct mtd_info *mtd, | ||
841 | const uint8_t *dat, uint8_t *ecc_code) | ||
842 | { | ||
843 | return 0; | ||
844 | } | ||
845 | |||
846 | static int pxa3xx_nand_ecc_correct(struct mtd_info *mtd, | ||
847 | uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc) | ||
848 | { | ||
849 | struct pxa3xx_nand_info *info = mtd->priv; | ||
850 | /* | ||
851 | * Any error include ERR_SEND_CMD, ERR_DBERR, ERR_BUSERR, we | ||
852 | * consider it as a ecc error which will tell the caller the | ||
853 | * read fail We have distinguish all the errors, but the | ||
854 | * nand_read_ecc only check this function return value | ||
855 | */ | ||
856 | if (info->retcode != ERR_NONE) | ||
857 | return -1; | ||
858 | |||
859 | return 0; | ||
860 | } | ||
861 | |||
862 | static int __readid(struct pxa3xx_nand_info *info, uint32_t *id) | ||
863 | { | ||
864 | struct pxa3xx_nand_flash *f = info->flash_info; | ||
865 | struct pxa3xx_nand_cmdset *cmdset = f->cmdset; | ||
866 | uint32_t ndcr; | ||
867 | uint8_t id_buff[8]; | ||
868 | |||
869 | if (prepare_other_cmd(info, cmdset->read_id)) { | ||
870 | printk(KERN_ERR "failed to prepare command\n"); | ||
871 | return -EINVAL; | ||
872 | } | ||
873 | |||
874 | /* Send command */ | ||
875 | if (write_cmd(info)) | ||
876 | goto fail_timeout; | ||
877 | |||
878 | /* Wait for CMDDM(command done successfully) */ | ||
879 | if (wait_for_event(info, NDSR_RDDREQ)) | ||
880 | goto fail_timeout; | ||
881 | |||
882 | __raw_readsl(info->mmio_base + NDDB, id_buff, 2); | ||
883 | *id = id_buff[0] | (id_buff[1] << 8); | ||
884 | return 0; | ||
885 | |||
886 | fail_timeout: | ||
887 | ndcr = nand_readl(info, NDCR); | ||
888 | nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN); | ||
889 | udelay(10); | ||
890 | return -ETIMEDOUT; | ||
891 | } | ||
892 | |||
893 | static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, | ||
894 | struct pxa3xx_nand_flash *f) | ||
895 | { | ||
896 | struct platform_device *pdev = info->pdev; | ||
897 | struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; | ||
898 | uint32_t ndcr = 0x00000FFF; /* disable all interrupts */ | ||
899 | |||
900 | if (f->page_size != 2048 && f->page_size != 512) | ||
901 | return -EINVAL; | ||
902 | |||
903 | if (f->flash_width != 16 && f->flash_width != 8) | ||
904 | return -EINVAL; | ||
905 | |||
906 | /* calculate flash information */ | ||
907 | f->oob_size = (f->page_size == 2048) ? 64 : 16; | ||
908 | f->read_id_bytes = (f->page_size == 2048) ? 4 : 2; | ||
909 | |||
910 | /* calculate addressing information */ | ||
911 | f->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; | ||
912 | |||
913 | if (f->num_blocks * f->page_per_block > 65536) | ||
914 | f->row_addr_cycles = 3; | ||
915 | else | ||
916 | f->row_addr_cycles = 2; | ||
917 | |||
918 | ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; | ||
919 | ndcr |= (f->col_addr_cycles == 2) ? NDCR_RA_START : 0; | ||
920 | ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0; | ||
921 | ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0; | ||
922 | ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0; | ||
923 | ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0; | ||
924 | |||
925 | ndcr |= NDCR_RD_ID_CNT(f->read_id_bytes); | ||
926 | ndcr |= NDCR_SPARE_EN; /* enable spare by default */ | ||
927 | |||
928 | info->reg_ndcr = ndcr; | ||
929 | |||
930 | pxa3xx_nand_set_timing(info, f->timing); | ||
931 | info->flash_info = f; | ||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info) | ||
936 | { | ||
937 | struct pxa3xx_nand_flash *f; | ||
938 | uint32_t id; | ||
939 | int i; | ||
940 | |||
941 | for (i = 0; i < ARRAY_SIZE(builtin_flash_types); i++) { | ||
942 | |||
943 | f = builtin_flash_types[i]; | ||
944 | |||
945 | if (pxa3xx_nand_config_flash(info, f)) | ||
946 | continue; | ||
947 | |||
948 | if (__readid(info, &id)) | ||
949 | continue; | ||
950 | |||
951 | if (id == f->chip_id) | ||
952 | return 0; | ||
953 | } | ||
954 | |||
955 | return -ENODEV; | ||
956 | } | ||
957 | |||
958 | /* the maximum possible buffer size for large page with OOB data | ||
959 | * is: 2048 + 64 = 2112 bytes, allocate a page here for both the | ||
960 | * data buffer and the DMA descriptor | ||
961 | */ | ||
962 | #define MAX_BUFF_SIZE PAGE_SIZE | ||
963 | |||
964 | static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) | ||
965 | { | ||
966 | struct platform_device *pdev = info->pdev; | ||
967 | int data_desc_offset = MAX_BUFF_SIZE - sizeof(struct pxa_dma_desc); | ||
968 | |||
969 | if (use_dma == 0) { | ||
970 | info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL); | ||
971 | if (info->data_buff == NULL) | ||
972 | return -ENOMEM; | ||
973 | return 0; | ||
974 | } | ||
975 | |||
976 | info->data_buff = dma_alloc_coherent(&pdev->dev, MAX_BUFF_SIZE, | ||
977 | &info->data_buff_phys, GFP_KERNEL); | ||
978 | if (info->data_buff == NULL) { | ||
979 | dev_err(&pdev->dev, "failed to allocate dma buffer\n"); | ||
980 | return -ENOMEM; | ||
981 | } | ||
982 | |||
983 | info->data_buff_size = MAX_BUFF_SIZE; | ||
984 | info->data_desc = (void *)info->data_buff + data_desc_offset; | ||
985 | info->data_desc_addr = info->data_buff_phys + data_desc_offset; | ||
986 | |||
987 | info->data_dma_ch = pxa_request_dma("nand-data", DMA_PRIO_LOW, | ||
988 | pxa3xx_nand_data_dma_irq, info); | ||
989 | if (info->data_dma_ch < 0) { | ||
990 | dev_err(&pdev->dev, "failed to request data dma\n"); | ||
991 | dma_free_coherent(&pdev->dev, info->data_buff_size, | ||
992 | info->data_buff, info->data_buff_phys); | ||
993 | return info->data_dma_ch; | ||
994 | } | ||
995 | |||
996 | return 0; | ||
997 | } | ||
998 | |||
999 | static struct nand_ecclayout hw_smallpage_ecclayout = { | ||
1000 | .eccbytes = 6, | ||
1001 | .eccpos = {8, 9, 10, 11, 12, 13 }, | ||
1002 | .oobfree = { {2, 6} } | ||
1003 | }; | ||
1004 | |||
1005 | static struct nand_ecclayout hw_largepage_ecclayout = { | ||
1006 | .eccbytes = 24, | ||
1007 | .eccpos = { | ||
1008 | 40, 41, 42, 43, 44, 45, 46, 47, | ||
1009 | 48, 49, 50, 51, 52, 53, 54, 55, | ||
1010 | 56, 57, 58, 59, 60, 61, 62, 63}, | ||
1011 | .oobfree = { {2, 38} } | ||
1012 | }; | ||
1013 | |||
1014 | static void pxa3xx_nand_init_mtd(struct mtd_info *mtd, | ||
1015 | struct pxa3xx_nand_info *info) | ||
1016 | { | ||
1017 | struct pxa3xx_nand_flash *f = info->flash_info; | ||
1018 | struct nand_chip *this = &info->nand_chip; | ||
1019 | |||
1020 | this->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16: 0; | ||
1021 | |||
1022 | this->waitfunc = pxa3xx_nand_waitfunc; | ||
1023 | this->select_chip = pxa3xx_nand_select_chip; | ||
1024 | this->dev_ready = pxa3xx_nand_dev_ready; | ||
1025 | this->cmdfunc = pxa3xx_nand_cmdfunc; | ||
1026 | this->read_word = pxa3xx_nand_read_word; | ||
1027 | this->read_byte = pxa3xx_nand_read_byte; | ||
1028 | this->read_buf = pxa3xx_nand_read_buf; | ||
1029 | this->write_buf = pxa3xx_nand_write_buf; | ||
1030 | this->verify_buf = pxa3xx_nand_verify_buf; | ||
1031 | |||
1032 | this->ecc.mode = NAND_ECC_HW; | ||
1033 | this->ecc.hwctl = pxa3xx_nand_ecc_hwctl; | ||
1034 | this->ecc.calculate = pxa3xx_nand_ecc_calculate; | ||
1035 | this->ecc.correct = pxa3xx_nand_ecc_correct; | ||
1036 | this->ecc.size = f->page_size; | ||
1037 | |||
1038 | if (f->page_size == 2048) | ||
1039 | this->ecc.layout = &hw_largepage_ecclayout; | ||
1040 | else | ||
1041 | this->ecc.layout = &hw_smallpage_ecclayout; | ||
1042 | |||
1043 | this->chip_delay = 25; | ||
1044 | } | ||
1045 | |||
1046 | static int pxa3xx_nand_probe(struct platform_device *pdev) | ||
1047 | { | ||
1048 | struct pxa3xx_nand_platform_data *pdata; | ||
1049 | struct pxa3xx_nand_info *info; | ||
1050 | struct nand_chip *this; | ||
1051 | struct mtd_info *mtd; | ||
1052 | struct resource *r; | ||
1053 | int ret = 0, irq; | ||
1054 | |||
1055 | pdata = pdev->dev.platform_data; | ||
1056 | |||
1057 | if (!pdata) { | ||
1058 | dev_err(&pdev->dev, "no platform data defined\n"); | ||
1059 | return -ENODEV; | ||
1060 | } | ||
1061 | |||
1062 | mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct pxa3xx_nand_info), | ||
1063 | GFP_KERNEL); | ||
1064 | if (!mtd) { | ||
1065 | dev_err(&pdev->dev, "failed to allocate memory\n"); | ||
1066 | return -ENOMEM; | ||
1067 | } | ||
1068 | |||
1069 | info = (struct pxa3xx_nand_info *)(&mtd[1]); | ||
1070 | info->pdev = pdev; | ||
1071 | |||
1072 | this = &info->nand_chip; | ||
1073 | mtd->priv = info; | ||
1074 | |||
1075 | info->clk = clk_get(&pdev->dev, "NANDCLK"); | ||
1076 | if (IS_ERR(info->clk)) { | ||
1077 | dev_err(&pdev->dev, "failed to get nand clock\n"); | ||
1078 | ret = PTR_ERR(info->clk); | ||
1079 | goto fail_free_mtd; | ||
1080 | } | ||
1081 | clk_enable(info->clk); | ||
1082 | |||
1083 | r = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
1084 | if (r == NULL) { | ||
1085 | dev_err(&pdev->dev, "no resource defined for data DMA\n"); | ||
1086 | ret = -ENXIO; | ||
1087 | goto fail_put_clk; | ||
1088 | } | ||
1089 | info->drcmr_dat = r->start; | ||
1090 | |||
1091 | r = platform_get_resource(pdev, IORESOURCE_DMA, 1); | ||
1092 | if (r == NULL) { | ||
1093 | dev_err(&pdev->dev, "no resource defined for command DMA\n"); | ||
1094 | ret = -ENXIO; | ||
1095 | goto fail_put_clk; | ||
1096 | } | ||
1097 | info->drcmr_cmd = r->start; | ||
1098 | |||
1099 | irq = platform_get_irq(pdev, 0); | ||
1100 | if (irq < 0) { | ||
1101 | dev_err(&pdev->dev, "no IRQ resource defined\n"); | ||
1102 | ret = -ENXIO; | ||
1103 | goto fail_put_clk; | ||
1104 | } | ||
1105 | |||
1106 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1107 | if (r == NULL) { | ||
1108 | dev_err(&pdev->dev, "no IO memory resource defined\n"); | ||
1109 | ret = -ENODEV; | ||
1110 | goto fail_put_clk; | ||
1111 | } | ||
1112 | |||
1113 | r = request_mem_region(r->start, r->end - r->start + 1, pdev->name); | ||
1114 | if (r == NULL) { | ||
1115 | dev_err(&pdev->dev, "failed to request memory resource\n"); | ||
1116 | ret = -EBUSY; | ||
1117 | goto fail_put_clk; | ||
1118 | } | ||
1119 | |||
1120 | info->mmio_base = ioremap(r->start, r->end - r->start + 1); | ||
1121 | if (info->mmio_base == NULL) { | ||
1122 | dev_err(&pdev->dev, "ioremap() failed\n"); | ||
1123 | ret = -ENODEV; | ||
1124 | goto fail_free_res; | ||
1125 | } | ||
1126 | |||
1127 | ret = pxa3xx_nand_init_buff(info); | ||
1128 | if (ret) | ||
1129 | goto fail_free_io; | ||
1130 | |||
1131 | ret = request_irq(IRQ_NAND, pxa3xx_nand_irq, IRQF_DISABLED, | ||
1132 | pdev->name, info); | ||
1133 | if (ret < 0) { | ||
1134 | dev_err(&pdev->dev, "failed to request IRQ\n"); | ||
1135 | goto fail_free_buf; | ||
1136 | } | ||
1137 | |||
1138 | ret = pxa3xx_nand_detect_flash(info); | ||
1139 | if (ret) { | ||
1140 | dev_err(&pdev->dev, "failed to detect flash\n"); | ||
1141 | ret = -ENODEV; | ||
1142 | goto fail_free_irq; | ||
1143 | } | ||
1144 | |||
1145 | pxa3xx_nand_init_mtd(mtd, info); | ||
1146 | |||
1147 | platform_set_drvdata(pdev, mtd); | ||
1148 | |||
1149 | if (nand_scan(mtd, 1)) { | ||
1150 | dev_err(&pdev->dev, "failed to scan nand\n"); | ||
1151 | ret = -ENXIO; | ||
1152 | goto fail_free_irq; | ||
1153 | } | ||
1154 | |||
1155 | return add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts); | ||
1156 | |||
1157 | fail_free_irq: | ||
1158 | free_irq(IRQ_NAND, info); | ||
1159 | fail_free_buf: | ||
1160 | if (use_dma) { | ||
1161 | pxa_free_dma(info->data_dma_ch); | ||
1162 | dma_free_coherent(&pdev->dev, info->data_buff_size, | ||
1163 | info->data_buff, info->data_buff_phys); | ||
1164 | } else | ||
1165 | kfree(info->data_buff); | ||
1166 | fail_free_io: | ||
1167 | iounmap(info->mmio_base); | ||
1168 | fail_free_res: | ||
1169 | release_mem_region(r->start, r->end - r->start + 1); | ||
1170 | fail_put_clk: | ||
1171 | clk_disable(info->clk); | ||
1172 | clk_put(info->clk); | ||
1173 | fail_free_mtd: | ||
1174 | kfree(mtd); | ||
1175 | return ret; | ||
1176 | } | ||
1177 | |||
1178 | static int pxa3xx_nand_remove(struct platform_device *pdev) | ||
1179 | { | ||
1180 | struct mtd_info *mtd = platform_get_drvdata(pdev); | ||
1181 | struct pxa3xx_nand_info *info = mtd->priv; | ||
1182 | |||
1183 | platform_set_drvdata(pdev, NULL); | ||
1184 | |||
1185 | del_mtd_device(mtd); | ||
1186 | del_mtd_partitions(mtd); | ||
1187 | free_irq(IRQ_NAND, info); | ||
1188 | if (use_dma) { | ||
1189 | pxa_free_dma(info->data_dma_ch); | ||
1190 | dma_free_writecombine(&pdev->dev, info->data_buff_size, | ||
1191 | info->data_buff, info->data_buff_phys); | ||
1192 | } else | ||
1193 | kfree(info->data_buff); | ||
1194 | kfree(mtd); | ||
1195 | return 0; | ||
1196 | } | ||
1197 | |||
1198 | #ifdef CONFIG_PM | ||
1199 | static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state) | ||
1200 | { | ||
1201 | struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev); | ||
1202 | struct pxa3xx_nand_info *info = mtd->priv; | ||
1203 | |||
1204 | if (info->state != STATE_READY) { | ||
1205 | dev_err(&pdev->dev, "driver busy, state = %d\n", info->state); | ||
1206 | return -EAGAIN; | ||
1207 | } | ||
1208 | |||
1209 | return 0; | ||
1210 | } | ||
1211 | |||
1212 | static int pxa3xx_nand_resume(struct platform_device *pdev) | ||
1213 | { | ||
1214 | struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev); | ||
1215 | struct pxa3xx_nand_info *info = mtd->priv; | ||
1216 | |||
1217 | clk_enable(info->clk); | ||
1218 | |||
1219 | return pxa3xx_nand_config_flash(info); | ||
1220 | } | ||
1221 | #else | ||
1222 | #define pxa3xx_nand_suspend NULL | ||
1223 | #define pxa3xx_nand_resume NULL | ||
1224 | #endif | ||
1225 | |||
1226 | static struct platform_driver pxa3xx_nand_driver = { | ||
1227 | .driver = { | ||
1228 | .name = "pxa3xx-nand", | ||
1229 | }, | ||
1230 | .probe = pxa3xx_nand_probe, | ||
1231 | .remove = pxa3xx_nand_remove, | ||
1232 | .suspend = pxa3xx_nand_suspend, | ||
1233 | .resume = pxa3xx_nand_resume, | ||
1234 | }; | ||
1235 | |||
1236 | static int __init pxa3xx_nand_init(void) | ||
1237 | { | ||
1238 | return platform_driver_register(&pxa3xx_nand_driver); | ||
1239 | } | ||
1240 | module_init(pxa3xx_nand_init); | ||
1241 | |||
1242 | static void __exit pxa3xx_nand_exit(void) | ||
1243 | { | ||
1244 | platform_driver_unregister(&pxa3xx_nand_driver); | ||
1245 | } | ||
1246 | module_exit(pxa3xx_nand_exit); | ||
1247 | |||
1248 | MODULE_LICENSE("GPL"); | ||
1249 | MODULE_DESCRIPTION("PXA3xx NAND controller driver"); | ||
diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index 0f6ac250f434..26f88215bc47 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c | |||
@@ -478,6 +478,7 @@ static int __init rtc_from4_init(void) | |||
478 | struct nand_chip *this; | 478 | struct nand_chip *this; |
479 | unsigned short bcr1, bcr2, wcr2; | 479 | unsigned short bcr1, bcr2, wcr2; |
480 | int i; | 480 | int i; |
481 | int ret; | ||
481 | 482 | ||
482 | /* Allocate memory for MTD device structure and private data */ | 483 | /* Allocate memory for MTD device structure and private data */ |
483 | rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); | 484 | rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); |
@@ -537,6 +538,22 @@ static int __init rtc_from4_init(void) | |||
537 | this->ecc.hwctl = rtc_from4_enable_hwecc; | 538 | this->ecc.hwctl = rtc_from4_enable_hwecc; |
538 | this->ecc.calculate = rtc_from4_calculate_ecc; | 539 | this->ecc.calculate = rtc_from4_calculate_ecc; |
539 | this->ecc.correct = rtc_from4_correct_data; | 540 | this->ecc.correct = rtc_from4_correct_data; |
541 | |||
542 | /* We could create the decoder on demand, if memory is a concern. | ||
543 | * This way we have it handy, if an error happens | ||
544 | * | ||
545 | * Symbolsize is 10 (bits) | ||
546 | * Primitve polynomial is x^10+x^3+1 | ||
547 | * first consecutive root is 0 | ||
548 | * primitve element to generate roots = 1 | ||
549 | * generator polinomial degree = 6 | ||
550 | */ | ||
551 | rs_decoder = init_rs(10, 0x409, 0, 1, 6); | ||
552 | if (!rs_decoder) { | ||
553 | printk(KERN_ERR "Could not create a RS decoder\n"); | ||
554 | ret = -ENOMEM; | ||
555 | goto err_1; | ||
556 | } | ||
540 | #else | 557 | #else |
541 | printk(KERN_INFO "rtc_from4_init: using software ECC detection.\n"); | 558 | printk(KERN_INFO "rtc_from4_init: using software ECC detection.\n"); |
542 | 559 | ||
@@ -549,8 +566,8 @@ static int __init rtc_from4_init(void) | |||
549 | 566 | ||
550 | /* Scan to find existence of the device */ | 567 | /* Scan to find existence of the device */ |
551 | if (nand_scan(rtc_from4_mtd, RTC_FROM4_MAX_CHIPS)) { | 568 | if (nand_scan(rtc_from4_mtd, RTC_FROM4_MAX_CHIPS)) { |
552 | kfree(rtc_from4_mtd); | 569 | ret = -ENXIO; |
553 | return -ENXIO; | 570 | goto err_2; |
554 | } | 571 | } |
555 | 572 | ||
556 | /* Perform 'device recovery' for each chip in case there was a power loss. */ | 573 | /* Perform 'device recovery' for each chip in case there was a power loss. */ |
@@ -566,28 +583,19 @@ static int __init rtc_from4_init(void) | |||
566 | #endif | 583 | #endif |
567 | 584 | ||
568 | /* Register the partitions */ | 585 | /* Register the partitions */ |
569 | add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS); | 586 | ret = add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS); |
587 | if (ret) | ||
588 | goto err_3; | ||
570 | 589 | ||
571 | #ifdef RTC_FROM4_HWECC | ||
572 | /* We could create the decoder on demand, if memory is a concern. | ||
573 | * This way we have it handy, if an error happens | ||
574 | * | ||
575 | * Symbolsize is 10 (bits) | ||
576 | * Primitve polynomial is x^10+x^3+1 | ||
577 | * first consecutive root is 0 | ||
578 | * primitve element to generate roots = 1 | ||
579 | * generator polinomial degree = 6 | ||
580 | */ | ||
581 | rs_decoder = init_rs(10, 0x409, 0, 1, 6); | ||
582 | if (!rs_decoder) { | ||
583 | printk(KERN_ERR "Could not create a RS decoder\n"); | ||
584 | nand_release(rtc_from4_mtd); | ||
585 | kfree(rtc_from4_mtd); | ||
586 | return -ENOMEM; | ||
587 | } | ||
588 | #endif | ||
589 | /* Return happy */ | 590 | /* Return happy */ |
590 | return 0; | 591 | return 0; |
592 | err_3: | ||
593 | nand_release(rtc_from4_mtd); | ||
594 | err_2: | ||
595 | free_rs(rs_decoder); | ||
596 | err_1: | ||
597 | kfree(rtc_from4_mtd); | ||
598 | return ret; | ||
591 | } | 599 | } |
592 | 600 | ||
593 | module_init(rtc_from4_init); | 601 | module_init(rtc_from4_init); |
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 9260ad947524..b34a460ab679 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c | |||
@@ -119,8 +119,7 @@ struct s3c2410_nand_info { | |||
119 | void __iomem *sel_reg; | 119 | void __iomem *sel_reg; |
120 | int sel_bit; | 120 | int sel_bit; |
121 | int mtd_count; | 121 | int mtd_count; |
122 | 122 | unsigned long save_sel; | |
123 | unsigned long save_nfconf; | ||
124 | 123 | ||
125 | enum s3c_cpu_type cpu_type; | 124 | enum s3c_cpu_type cpu_type; |
126 | }; | 125 | }; |
@@ -358,6 +357,14 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, | |||
358 | if (diff0 == 0 && diff1 == 0 && diff2 == 0) | 357 | if (diff0 == 0 && diff1 == 0 && diff2 == 0) |
359 | return 0; /* ECC is ok */ | 358 | return 0; /* ECC is ok */ |
360 | 359 | ||
360 | /* sometimes people do not think about using the ECC, so check | ||
361 | * to see if we have an 0xff,0xff,0xff read ECC and then ignore | ||
362 | * the error, on the assumption that this is an un-eccd page. | ||
363 | */ | ||
364 | if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff | ||
365 | && info->platform->ignore_unset_ecc) | ||
366 | return 0; | ||
367 | |||
361 | /* Can we correct this ECC (ie, one row and column change). | 368 | /* Can we correct this ECC (ie, one row and column change). |
362 | * Note, this is similar to the 256 error code on smartmedia */ | 369 | * Note, this is similar to the 256 error code on smartmedia */ |
363 | 370 | ||
@@ -473,7 +480,7 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u | |||
473 | ecc_code[1] = ecc >> 8; | 480 | ecc_code[1] = ecc >> 8; |
474 | ecc_code[2] = ecc >> 16; | 481 | ecc_code[2] = ecc >> 16; |
475 | 482 | ||
476 | pr_debug("%s: returning ecc %06lx\n", __func__, ecc); | 483 | pr_debug("%s: returning ecc %06lx\n", __func__, ecc & 0xffffff); |
477 | 484 | ||
478 | return 0; | 485 | return 0; |
479 | } | 486 | } |
@@ -644,9 +651,6 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, | |||
644 | chip->ecc.calculate = s3c2410_nand_calculate_ecc; | 651 | chip->ecc.calculate = s3c2410_nand_calculate_ecc; |
645 | chip->ecc.correct = s3c2410_nand_correct_data; | 652 | chip->ecc.correct = s3c2410_nand_correct_data; |
646 | chip->ecc.mode = NAND_ECC_HW; | 653 | chip->ecc.mode = NAND_ECC_HW; |
647 | chip->ecc.size = 512; | ||
648 | chip->ecc.bytes = 3; | ||
649 | chip->ecc.layout = &nand_hw_eccoob; | ||
650 | 654 | ||
651 | switch (info->cpu_type) { | 655 | switch (info->cpu_type) { |
652 | case TYPE_S3C2410: | 656 | case TYPE_S3C2410: |
@@ -668,6 +672,40 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, | |||
668 | } else { | 672 | } else { |
669 | chip->ecc.mode = NAND_ECC_SOFT; | 673 | chip->ecc.mode = NAND_ECC_SOFT; |
670 | } | 674 | } |
675 | |||
676 | if (set->ecc_layout != NULL) | ||
677 | chip->ecc.layout = set->ecc_layout; | ||
678 | |||
679 | if (set->disable_ecc) | ||
680 | chip->ecc.mode = NAND_ECC_NONE; | ||
681 | } | ||
682 | |||
683 | /* s3c2410_nand_update_chip | ||
684 | * | ||
685 | * post-probe chip update, to change any items, such as the | ||
686 | * layout for large page nand | ||
687 | */ | ||
688 | |||
689 | static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info, | ||
690 | struct s3c2410_nand_mtd *nmtd) | ||
691 | { | ||
692 | struct nand_chip *chip = &nmtd->chip; | ||
693 | |||
694 | printk("%s: chip %p: %d\n", __func__, chip, chip->page_shift); | ||
695 | |||
696 | if (hardware_ecc) { | ||
697 | /* change the behaviour depending on wether we are using | ||
698 | * the large or small page nand device */ | ||
699 | |||
700 | if (chip->page_shift > 10) { | ||
701 | chip->ecc.size = 256; | ||
702 | chip->ecc.bytes = 3; | ||
703 | } else { | ||
704 | chip->ecc.size = 512; | ||
705 | chip->ecc.bytes = 3; | ||
706 | chip->ecc.layout = &nand_hw_eccoob; | ||
707 | } | ||
708 | } | ||
671 | } | 709 | } |
672 | 710 | ||
673 | /* s3c2410_nand_probe | 711 | /* s3c2410_nand_probe |
@@ -776,9 +814,12 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, | |||
776 | 814 | ||
777 | s3c2410_nand_init_chip(info, nmtd, sets); | 815 | s3c2410_nand_init_chip(info, nmtd, sets); |
778 | 816 | ||
779 | nmtd->scan_res = nand_scan(&nmtd->mtd, (sets) ? sets->nr_chips : 1); | 817 | nmtd->scan_res = nand_scan_ident(&nmtd->mtd, |
818 | (sets) ? sets->nr_chips : 1); | ||
780 | 819 | ||
781 | if (nmtd->scan_res == 0) { | 820 | if (nmtd->scan_res == 0) { |
821 | s3c2410_nand_update_chip(info, nmtd); | ||
822 | nand_scan_tail(&nmtd->mtd); | ||
782 | s3c2410_nand_add_partition(info, nmtd, sets); | 823 | s3c2410_nand_add_partition(info, nmtd, sets); |
783 | } | 824 | } |
784 | 825 | ||
@@ -810,15 +851,14 @@ static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm) | |||
810 | struct s3c2410_nand_info *info = platform_get_drvdata(dev); | 851 | struct s3c2410_nand_info *info = platform_get_drvdata(dev); |
811 | 852 | ||
812 | if (info) { | 853 | if (info) { |
813 | info->save_nfconf = readl(info->regs + S3C2410_NFCONF); | 854 | info->save_sel = readl(info->sel_reg); |
814 | 855 | ||
815 | /* For the moment, we must ensure nFCE is high during | 856 | /* For the moment, we must ensure nFCE is high during |
816 | * the time we are suspended. This really should be | 857 | * the time we are suspended. This really should be |
817 | * handled by suspending the MTDs we are using, but | 858 | * handled by suspending the MTDs we are using, but |
818 | * that is currently not the case. */ | 859 | * that is currently not the case. */ |
819 | 860 | ||
820 | writel(info->save_nfconf | info->sel_bit, | 861 | writel(info->save_sel | info->sel_bit, info->sel_reg); |
821 | info->regs + S3C2410_NFCONF); | ||
822 | 862 | ||
823 | if (!allow_clk_stop(info)) | 863 | if (!allow_clk_stop(info)) |
824 | clk_disable(info->clk); | 864 | clk_disable(info->clk); |
@@ -830,7 +870,7 @@ static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm) | |||
830 | static int s3c24xx_nand_resume(struct platform_device *dev) | 870 | static int s3c24xx_nand_resume(struct platform_device *dev) |
831 | { | 871 | { |
832 | struct s3c2410_nand_info *info = platform_get_drvdata(dev); | 872 | struct s3c2410_nand_info *info = platform_get_drvdata(dev); |
833 | unsigned long nfconf; | 873 | unsigned long sel; |
834 | 874 | ||
835 | if (info) { | 875 | if (info) { |
836 | clk_enable(info->clk); | 876 | clk_enable(info->clk); |
@@ -838,10 +878,10 @@ static int s3c24xx_nand_resume(struct platform_device *dev) | |||
838 | 878 | ||
839 | /* Restore the state of the nFCE line. */ | 879 | /* Restore the state of the nFCE line. */ |
840 | 880 | ||
841 | nfconf = readl(info->regs + S3C2410_NFCONF); | 881 | sel = readl(info->sel_reg); |
842 | nfconf &= ~info->sel_bit; | 882 | sel &= ~info->sel_bit; |
843 | nfconf |= info->save_nfconf & info->sel_bit; | 883 | sel |= info->save_sel & info->sel_bit; |
844 | writel(nfconf, info->regs + S3C2410_NFCONF); | 884 | writel(sel, info->sel_reg); |
845 | 885 | ||
846 | if (allow_clk_stop(info)) | 886 | if (allow_clk_stop(info)) |
847 | clk_disable(info->clk); | 887 | clk_disable(info->clk); |
@@ -927,3 +967,6 @@ module_exit(s3c2410_nand_exit); | |||
927 | MODULE_LICENSE("GPL"); | 967 | MODULE_LICENSE("GPL"); |
928 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | 968 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); |
929 | MODULE_DESCRIPTION("S3C24XX MTD NAND driver"); | 969 | MODULE_DESCRIPTION("S3C24XX MTD NAND driver"); |
970 | MODULE_ALIAS("platform:s3c2410-nand"); | ||
971 | MODULE_ALIAS("platform:s3c2412-nand"); | ||
972 | MODULE_ALIAS("platform:s3c2440-nand"); | ||
diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index 0513cbc8834d..345e6eff89ce 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c | |||
@@ -33,11 +33,6 @@ | |||
33 | 33 | ||
34 | char nftlmountrev[]="$Revision: 1.41 $"; | 34 | char nftlmountrev[]="$Revision: 1.41 $"; |
35 | 35 | ||
36 | extern int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, | ||
37 | size_t *retlen, uint8_t *buf); | ||
38 | extern int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, | ||
39 | size_t *retlen, uint8_t *buf); | ||
40 | |||
41 | /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the | 36 | /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the |
42 | * various device information of the NFTL partition and Bad Unit Table. Update | 37 | * various device information of the NFTL partition and Bad Unit Table. Update |
43 | * the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[] | 38 | * the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[] |
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index f86e06934cd8..4f80c2fd89af 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c | |||
@@ -72,3 +72,5 @@ int __devinit of_mtd_parse_partitions(struct device *dev, | |||
72 | return nr_parts; | 72 | return nr_parts; |
73 | } | 73 | } |
74 | EXPORT_SYMBOL(of_mtd_parse_partitions); | 74 | EXPORT_SYMBOL(of_mtd_parse_partitions); |
75 | |||
76 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 8d7d21be1541..5d7965f7e9ce 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -329,6 +329,21 @@ static int onenand_wait(struct mtd_info *mtd, int state) | |||
329 | printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", ctrl); | 329 | printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", ctrl); |
330 | if (ctrl & ONENAND_CTRL_LOCK) | 330 | if (ctrl & ONENAND_CTRL_LOCK) |
331 | printk(KERN_ERR "onenand_wait: it's locked error.\n"); | 331 | printk(KERN_ERR "onenand_wait: it's locked error.\n"); |
332 | if (state == FL_READING) { | ||
333 | /* | ||
334 | * A power loss while writing can result in a page | ||
335 | * becoming unreadable. When the device is mounted | ||
336 | * again, reading that page gives controller errors. | ||
337 | * Upper level software like JFFS2 treat -EIO as fatal, | ||
338 | * refusing to mount at all. That means it is necessary | ||
339 | * to treat the error as an ECC error to allow recovery. | ||
340 | * Note that typically in this case, the eraseblock can | ||
341 | * still be erased and rewritten i.e. it has not become | ||
342 | * a bad block. | ||
343 | */ | ||
344 | mtd->ecc_stats.failed++; | ||
345 | return -EBADMSG; | ||
346 | } | ||
332 | return -EIO; | 347 | return -EIO; |
333 | } | 348 | } |
334 | 349 | ||
@@ -1336,7 +1351,7 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
1336 | } | 1351 | } |
1337 | 1352 | ||
1338 | /* Reject writes, which are not page aligned */ | 1353 | /* Reject writes, which are not page aligned */ |
1339 | if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { | 1354 | if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) { |
1340 | printk(KERN_ERR "onenand_panic_write: Attempt to write not page aligned data\n"); | 1355 | printk(KERN_ERR "onenand_panic_write: Attempt to write not page aligned data\n"); |
1341 | return -EINVAL; | 1356 | return -EINVAL; |
1342 | } | 1357 | } |
@@ -1466,7 +1481,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, | |||
1466 | } | 1481 | } |
1467 | 1482 | ||
1468 | /* Reject writes, which are not page aligned */ | 1483 | /* Reject writes, which are not page aligned */ |
1469 | if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { | 1484 | if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) { |
1470 | printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n"); | 1485 | printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n"); |
1471 | return -EINVAL; | 1486 | return -EINVAL; |
1472 | } | 1487 | } |
@@ -2052,7 +2067,7 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
2052 | * | 2067 | * |
2053 | * Check lock status | 2068 | * Check lock status |
2054 | */ | 2069 | */ |
2055 | static void onenand_check_lock_status(struct onenand_chip *this) | 2070 | static int onenand_check_lock_status(struct onenand_chip *this) |
2056 | { | 2071 | { |
2057 | unsigned int value, block, status; | 2072 | unsigned int value, block, status; |
2058 | unsigned int end; | 2073 | unsigned int end; |
@@ -2070,9 +2085,13 @@ static void onenand_check_lock_status(struct onenand_chip *this) | |||
2070 | 2085 | ||
2071 | /* Check lock status */ | 2086 | /* Check lock status */ |
2072 | status = this->read_word(this->base + ONENAND_REG_WP_STATUS); | 2087 | status = this->read_word(this->base + ONENAND_REG_WP_STATUS); |
2073 | if (!(status & ONENAND_WP_US)) | 2088 | if (!(status & ONENAND_WP_US)) { |
2074 | printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status); | 2089 | printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status); |
2090 | return 0; | ||
2091 | } | ||
2075 | } | 2092 | } |
2093 | |||
2094 | return 1; | ||
2076 | } | 2095 | } |
2077 | 2096 | ||
2078 | /** | 2097 | /** |
@@ -2081,9 +2100,11 @@ static void onenand_check_lock_status(struct onenand_chip *this) | |||
2081 | * | 2100 | * |
2082 | * Unlock all blocks | 2101 | * Unlock all blocks |
2083 | */ | 2102 | */ |
2084 | static int onenand_unlock_all(struct mtd_info *mtd) | 2103 | static void onenand_unlock_all(struct mtd_info *mtd) |
2085 | { | 2104 | { |
2086 | struct onenand_chip *this = mtd->priv; | 2105 | struct onenand_chip *this = mtd->priv; |
2106 | loff_t ofs = 0; | ||
2107 | size_t len = this->chipsize; | ||
2087 | 2108 | ||
2088 | if (this->options & ONENAND_HAS_UNLOCK_ALL) { | 2109 | if (this->options & ONENAND_HAS_UNLOCK_ALL) { |
2089 | /* Set start block address */ | 2110 | /* Set start block address */ |
@@ -2099,23 +2120,19 @@ static int onenand_unlock_all(struct mtd_info *mtd) | |||
2099 | & ONENAND_CTRL_ONGO) | 2120 | & ONENAND_CTRL_ONGO) |
2100 | continue; | 2121 | continue; |
2101 | 2122 | ||
2123 | /* Check lock status */ | ||
2124 | if (onenand_check_lock_status(this)) | ||
2125 | return; | ||
2126 | |||
2102 | /* Workaround for all block unlock in DDP */ | 2127 | /* Workaround for all block unlock in DDP */ |
2103 | if (ONENAND_IS_DDP(this)) { | 2128 | if (ONENAND_IS_DDP(this)) { |
2104 | /* 1st block on another chip */ | 2129 | /* All blocks on another chip */ |
2105 | loff_t ofs = this->chipsize >> 1; | 2130 | ofs = this->chipsize >> 1; |
2106 | size_t len = mtd->erasesize; | 2131 | len = this->chipsize >> 1; |
2107 | |||
2108 | onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK); | ||
2109 | } | 2132 | } |
2110 | |||
2111 | onenand_check_lock_status(this); | ||
2112 | |||
2113 | return 0; | ||
2114 | } | 2133 | } |
2115 | 2134 | ||
2116 | onenand_do_lock_cmd(mtd, 0x0, this->chipsize, ONENAND_CMD_UNLOCK); | 2135 | onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK); |
2117 | |||
2118 | return 0; | ||
2119 | } | 2136 | } |
2120 | 2137 | ||
2121 | #ifdef CONFIG_MTD_ONENAND_OTP | 2138 | #ifdef CONFIG_MTD_ONENAND_OTP |
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index aecdd50a1781..2f53b51c6805 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c | |||
@@ -17,9 +17,6 @@ | |||
17 | #include <linux/mtd/onenand.h> | 17 | #include <linux/mtd/onenand.h> |
18 | #include <linux/mtd/compatmac.h> | 18 | #include <linux/mtd/compatmac.h> |
19 | 19 | ||
20 | extern int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, | ||
21 | struct mtd_oob_ops *ops); | ||
22 | |||
23 | /** | 20 | /** |
24 | * check_short_pattern - [GENERIC] check if a pattern is in the buffer | 21 | * check_short_pattern - [GENERIC] check if a pattern is in the buffer |
25 | * @param buf the buffer to search | 22 | * @param buf the buffer to search |
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index 823fba4e6d2f..c84e45465499 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c | |||
@@ -823,7 +823,7 @@ static void rfd_ftl_remove_dev(struct mtd_blktrans_dev *dev) | |||
823 | kfree(part); | 823 | kfree(part); |
824 | } | 824 | } |
825 | 825 | ||
826 | struct mtd_blktrans_ops rfd_ftl_tr = { | 826 | static struct mtd_blktrans_ops rfd_ftl_tr = { |
827 | .name = "rfd", | 827 | .name = "rfd", |
828 | .major = RFD_FTL_MAJOR, | 828 | .major = RFD_FTL_MAJOR, |
829 | .part_bits = PART_BITS, | 829 | .part_bits = PART_BITS, |
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig index b9daf159a4a7..3f063108e95f 100644 --- a/drivers/mtd/ubi/Kconfig +++ b/drivers/mtd/ubi/Kconfig | |||
@@ -24,8 +24,13 @@ config MTD_UBI_WL_THRESHOLD | |||
24 | erase counter value and the lowest erase counter value of eraseblocks | 24 | erase counter value and the lowest erase counter value of eraseblocks |
25 | of UBI devices. When this threshold is exceeded, UBI starts performing | 25 | of UBI devices. When this threshold is exceeded, UBI starts performing |
26 | wear leveling by means of moving data from eraseblock with low erase | 26 | wear leveling by means of moving data from eraseblock with low erase |
27 | counter to eraseblocks with high erase counter. Leave the default | 27 | counter to eraseblocks with high erase counter. |
28 | value if unsure. | 28 | |
29 | The default value should be OK for SLC NAND flashes, NOR flashes and | ||
30 | other flashes which have eraseblock life-cycle 100000 or more. | ||
31 | However, in case of MLC NAND flashes which typically have eraseblock | ||
32 | life-cycle less then 10000, the threshold should be lessened (e.g., | ||
33 | to 128 or 256, although it does not have to be power of 2). | ||
29 | 34 | ||
30 | config MTD_UBI_BEB_RESERVE | 35 | config MTD_UBI_BEB_RESERVE |
31 | int "Percentage of reserved eraseblocks for bad eraseblocks handling" | 36 | int "Percentage of reserved eraseblocks for bad eraseblocks handling" |
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 275960462970..961416ac0616 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c | |||
@@ -606,8 +606,16 @@ static int io_init(struct ubi_device *ubi) | |||
606 | ubi->ro_mode = 1; | 606 | ubi->ro_mode = 1; |
607 | } | 607 | } |
608 | 608 | ||
609 | dbg_msg("leb_size %d", ubi->leb_size); | 609 | ubi_msg("physical eraseblock size: %d bytes (%d KiB)", |
610 | dbg_msg("ro_mode %d", ubi->ro_mode); | 610 | ubi->peb_size, ubi->peb_size >> 10); |
611 | ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size); | ||
612 | ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size); | ||
613 | if (ubi->hdrs_min_io_size != ubi->min_io_size) | ||
614 | ubi_msg("sub-page size: %d", | ||
615 | ubi->hdrs_min_io_size); | ||
616 | ubi_msg("VID header offset: %d (aligned %d)", | ||
617 | ubi->vid_hdr_offset, ubi->vid_hdr_aloffset); | ||
618 | ubi_msg("data offset: %d", ubi->leb_start); | ||
611 | 619 | ||
612 | /* | 620 | /* |
613 | * Note, ideally, we have to initialize ubi->bad_peb_count here. But | 621 | * Note, ideally, we have to initialize ubi->bad_peb_count here. But |
@@ -755,8 +763,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) | |||
755 | mutex_init(&ubi->volumes_mutex); | 763 | mutex_init(&ubi->volumes_mutex); |
756 | spin_lock_init(&ubi->volumes_lock); | 764 | spin_lock_init(&ubi->volumes_lock); |
757 | 765 | ||
758 | dbg_msg("attaching mtd%d to ubi%d: VID header offset %d", | 766 | ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num); |
759 | mtd->index, ubi_num, vid_hdr_offset); | ||
760 | 767 | ||
761 | err = io_init(ubi); | 768 | err = io_init(ubi); |
762 | if (err) | 769 | if (err) |
@@ -804,15 +811,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) | |||
804 | ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num); | 811 | ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num); |
805 | ubi_msg("MTD device name: \"%s\"", mtd->name); | 812 | ubi_msg("MTD device name: \"%s\"", mtd->name); |
806 | ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); | 813 | ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); |
807 | ubi_msg("physical eraseblock size: %d bytes (%d KiB)", | ||
808 | ubi->peb_size, ubi->peb_size >> 10); | ||
809 | ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size); | ||
810 | ubi_msg("number of good PEBs: %d", ubi->good_peb_count); | 814 | ubi_msg("number of good PEBs: %d", ubi->good_peb_count); |
811 | ubi_msg("number of bad PEBs: %d", ubi->bad_peb_count); | 815 | ubi_msg("number of bad PEBs: %d", ubi->bad_peb_count); |
812 | ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size); | ||
813 | ubi_msg("VID header offset: %d (aligned %d)", | ||
814 | ubi->vid_hdr_offset, ubi->vid_hdr_aloffset); | ||
815 | ubi_msg("data offset: %d", ubi->leb_start); | ||
816 | ubi_msg("max. allowed volumes: %d", ubi->vtbl_slots); | 816 | ubi_msg("max. allowed volumes: %d", ubi->vtbl_slots); |
817 | ubi_msg("wear-leveling threshold: %d", CONFIG_MTD_UBI_WL_THRESHOLD); | 817 | ubi_msg("wear-leveling threshold: %d", CONFIG_MTD_UBI_WL_THRESHOLD); |
818 | ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT); | 818 | ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT); |
@@ -950,8 +950,7 @@ static int __init ubi_init(void) | |||
950 | BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64); | 950 | BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64); |
951 | 951 | ||
952 | if (mtd_devs > UBI_MAX_DEVICES) { | 952 | if (mtd_devs > UBI_MAX_DEVICES) { |
953 | printk(KERN_ERR "UBI error: too many MTD devices, " | 953 | ubi_err("too many MTD devices, maximum is %d", UBI_MAX_DEVICES); |
954 | "maximum is %d\n", UBI_MAX_DEVICES); | ||
955 | return -EINVAL; | 954 | return -EINVAL; |
956 | } | 955 | } |
957 | 956 | ||
@@ -959,25 +958,25 @@ static int __init ubi_init(void) | |||
959 | ubi_class = class_create(THIS_MODULE, UBI_NAME_STR); | 958 | ubi_class = class_create(THIS_MODULE, UBI_NAME_STR); |
960 | if (IS_ERR(ubi_class)) { | 959 | if (IS_ERR(ubi_class)) { |
961 | err = PTR_ERR(ubi_class); | 960 | err = PTR_ERR(ubi_class); |
962 | printk(KERN_ERR "UBI error: cannot create UBI class\n"); | 961 | ubi_err("cannot create UBI class"); |
963 | goto out; | 962 | goto out; |
964 | } | 963 | } |
965 | 964 | ||
966 | err = class_create_file(ubi_class, &ubi_version); | 965 | err = class_create_file(ubi_class, &ubi_version); |
967 | if (err) { | 966 | if (err) { |
968 | printk(KERN_ERR "UBI error: cannot create sysfs file\n"); | 967 | ubi_err("cannot create sysfs file"); |
969 | goto out_class; | 968 | goto out_class; |
970 | } | 969 | } |
971 | 970 | ||
972 | err = misc_register(&ubi_ctrl_cdev); | 971 | err = misc_register(&ubi_ctrl_cdev); |
973 | if (err) { | 972 | if (err) { |
974 | printk(KERN_ERR "UBI error: cannot register device\n"); | 973 | ubi_err("cannot register device"); |
975 | goto out_version; | 974 | goto out_version; |
976 | } | 975 | } |
977 | 976 | ||
978 | ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab", | 977 | ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab", |
979 | sizeof(struct ubi_wl_entry), | 978 | sizeof(struct ubi_wl_entry), |
980 | 0, 0, NULL); | 979 | 0, 0, NULL); |
981 | if (!ubi_wl_entry_slab) | 980 | if (!ubi_wl_entry_slab) |
982 | goto out_dev_unreg; | 981 | goto out_dev_unreg; |
983 | 982 | ||
@@ -1000,8 +999,7 @@ static int __init ubi_init(void) | |||
1000 | mutex_unlock(&ubi_devices_mutex); | 999 | mutex_unlock(&ubi_devices_mutex); |
1001 | if (err < 0) { | 1000 | if (err < 0) { |
1002 | put_mtd_device(mtd); | 1001 | put_mtd_device(mtd); |
1003 | printk(KERN_ERR "UBI error: cannot attach mtd%d\n", | 1002 | ubi_err("cannot attach mtd%d", mtd->index); |
1004 | mtd->index); | ||
1005 | goto out_detach; | 1003 | goto out_detach; |
1006 | } | 1004 | } |
1007 | } | 1005 | } |
@@ -1023,7 +1021,7 @@ out_version: | |||
1023 | out_class: | 1021 | out_class: |
1024 | class_destroy(ubi_class); | 1022 | class_destroy(ubi_class); |
1025 | out: | 1023 | out: |
1026 | printk(KERN_ERR "UBI error: cannot initialize UBI, error %d\n", err); | 1024 | ubi_err("UBI error: cannot initialize UBI, error %d", err); |
1027 | return err; | 1025 | return err; |
1028 | } | 1026 | } |
1029 | module_init(ubi_init); | 1027 | module_init(ubi_init); |
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h index 51c40b17f1ec..8ea99d8c9e1f 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h | |||
@@ -41,7 +41,7 @@ | |||
41 | /* Generic debugging message */ | 41 | /* Generic debugging message */ |
42 | #define dbg_msg(fmt, ...) \ | 42 | #define dbg_msg(fmt, ...) \ |
43 | printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \ | 43 | printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \ |
44 | current->pid, __FUNCTION__, ##__VA_ARGS__) | 44 | current->pid, __func__, ##__VA_ARGS__) |
45 | 45 | ||
46 | #define ubi_dbg_dump_stack() dump_stack() | 46 | #define ubi_dbg_dump_stack() dump_stack() |
47 | 47 | ||
@@ -99,8 +99,10 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req); | |||
99 | #ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD | 99 | #ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD |
100 | /* Initialization and build messages */ | 100 | /* Initialization and build messages */ |
101 | #define dbg_bld(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) | 101 | #define dbg_bld(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) |
102 | #define UBI_IO_DEBUG 1 | ||
102 | #else | 103 | #else |
103 | #define dbg_bld(fmt, ...) ({}) | 104 | #define dbg_bld(fmt, ...) ({}) |
105 | #define UBI_IO_DEBUG 0 | ||
104 | #endif | 106 | #endif |
105 | 107 | ||
106 | #ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_BITFLIPS | 108 | #ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_BITFLIPS |
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c index d397219238d3..e909b390069a 100644 --- a/drivers/mtd/ubi/gluebi.c +++ b/drivers/mtd/ubi/gluebi.c | |||
@@ -291,11 +291,12 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol) | |||
291 | /* | 291 | /* |
292 | * In case of dynamic volume, MTD device size is just volume size. In | 292 | * In case of dynamic volume, MTD device size is just volume size. In |
293 | * case of a static volume the size is equivalent to the amount of data | 293 | * case of a static volume the size is equivalent to the amount of data |
294 | * bytes, which is zero at this moment and will be changed after volume | 294 | * bytes. |
295 | * update. | ||
296 | */ | 295 | */ |
297 | if (vol->vol_type == UBI_DYNAMIC_VOLUME) | 296 | if (vol->vol_type == UBI_DYNAMIC_VOLUME) |
298 | mtd->size = vol->usable_leb_size * vol->reserved_pebs; | 297 | mtd->size = vol->usable_leb_size * vol->reserved_pebs; |
298 | else | ||
299 | mtd->size = vol->used_bytes; | ||
299 | 300 | ||
300 | if (add_mtd_device(mtd)) { | 301 | if (add_mtd_device(mtd)) { |
301 | ubi_err("cannot not add MTD device\n"); | 302 | ubi_err("cannot not add MTD device\n"); |
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index db3efdef2433..4ac11df7b048 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c | |||
@@ -631,6 +631,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, | |||
631 | 631 | ||
632 | dbg_io("read EC header from PEB %d", pnum); | 632 | dbg_io("read EC header from PEB %d", pnum); |
633 | ubi_assert(pnum >= 0 && pnum < ubi->peb_count); | 633 | ubi_assert(pnum >= 0 && pnum < ubi->peb_count); |
634 | if (UBI_IO_DEBUG) | ||
635 | verbose = 1; | ||
634 | 636 | ||
635 | err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE); | 637 | err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE); |
636 | if (err) { | 638 | if (err) { |
@@ -904,6 +906,8 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, | |||
904 | 906 | ||
905 | dbg_io("read VID header from PEB %d", pnum); | 907 | dbg_io("read VID header from PEB %d", pnum); |
906 | ubi_assert(pnum >= 0 && pnum < ubi->peb_count); | 908 | ubi_assert(pnum >= 0 && pnum < ubi->peb_count); |
909 | if (UBI_IO_DEBUG) | ||
910 | verbose = 1; | ||
907 | 911 | ||
908 | p = (char *)vid_hdr - ubi->vid_hdr_shift; | 912 | p = (char *)vid_hdr - ubi->vid_hdr_shift; |
909 | err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, | 913 | err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, |
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index 05aa3e7daba1..96d410e106ab 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c | |||
@@ -42,6 +42,7 @@ | |||
42 | 42 | ||
43 | #include <linux/err.h> | 43 | #include <linux/err.h> |
44 | #include <linux/crc32.h> | 44 | #include <linux/crc32.h> |
45 | #include <asm/div64.h> | ||
45 | #include "ubi.h" | 46 | #include "ubi.h" |
46 | 47 | ||
47 | #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID | 48 | #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID |
@@ -92,27 +93,6 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, | |||
92 | } | 93 | } |
93 | 94 | ||
94 | /** | 95 | /** |
95 | * commit_to_mean_value - commit intermediate results to the final mean erase | ||
96 | * counter value. | ||
97 | * @si: scanning information | ||
98 | * | ||
99 | * This is a helper function which calculates partial mean erase counter mean | ||
100 | * value and adds it to the resulting mean value. As we can work only in | ||
101 | * integer arithmetic and we want to calculate the mean value of erase counter | ||
102 | * accurately, we first sum erase counter values in @si->ec_sum variable and | ||
103 | * count these components in @si->ec_count. If this temporary @si->ec_sum is | ||
104 | * going to overflow, we calculate the partial mean value | ||
105 | * (@si->ec_sum/@si->ec_count) and add it to @si->mean_ec. | ||
106 | */ | ||
107 | static void commit_to_mean_value(struct ubi_scan_info *si) | ||
108 | { | ||
109 | si->ec_sum /= si->ec_count; | ||
110 | if (si->ec_sum % si->ec_count >= si->ec_count / 2) | ||
111 | si->mean_ec += 1; | ||
112 | si->mean_ec += si->ec_sum; | ||
113 | } | ||
114 | |||
115 | /** | ||
116 | * validate_vid_hdr - check that volume identifier header is correct and | 96 | * validate_vid_hdr - check that volume identifier header is correct and |
117 | * consistent. | 97 | * consistent. |
118 | * @vid_hdr: the volume identifier header to check | 98 | * @vid_hdr: the volume identifier header to check |
@@ -901,15 +881,8 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum | |||
901 | 881 | ||
902 | adjust_mean_ec: | 882 | adjust_mean_ec: |
903 | if (!ec_corr) { | 883 | if (!ec_corr) { |
904 | if (si->ec_sum + ec < ec) { | 884 | si->ec_sum += ec; |
905 | commit_to_mean_value(si); | 885 | si->ec_count += 1; |
906 | si->ec_sum = 0; | ||
907 | si->ec_count = 0; | ||
908 | } else { | ||
909 | si->ec_sum += ec; | ||
910 | si->ec_count += 1; | ||
911 | } | ||
912 | |||
913 | if (ec > si->max_ec) | 886 | if (ec > si->max_ec) |
914 | si->max_ec = ec; | 887 | si->max_ec = ec; |
915 | if (ec < si->min_ec) | 888 | if (ec < si->min_ec) |
@@ -965,9 +938,11 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) | |||
965 | 938 | ||
966 | dbg_msg("scanning is finished"); | 939 | dbg_msg("scanning is finished"); |
967 | 940 | ||
968 | /* Finish mean erase counter calculations */ | 941 | /* Calculate mean erase counter */ |
969 | if (si->ec_count) | 942 | if (si->ec_count) { |
970 | commit_to_mean_value(si); | 943 | do_div(si->ec_sum, si->ec_count); |
944 | si->mean_ec = si->ec_sum; | ||
945 | } | ||
971 | 946 | ||
972 | if (si->is_empty) | 947 | if (si->is_empty) |
973 | ubi_msg("empty MTD device detected"); | 948 | ubi_msg("empty MTD device detected"); |
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h index 46d444af471a..966b9b682a42 100644 --- a/drivers/mtd/ubi/scan.h +++ b/drivers/mtd/ubi/scan.h | |||
@@ -124,7 +124,7 @@ struct ubi_scan_info { | |||
124 | int max_ec; | 124 | int max_ec; |
125 | unsigned long long max_sqnum; | 125 | unsigned long long max_sqnum; |
126 | int mean_ec; | 126 | int mean_ec; |
127 | int ec_sum; | 127 | uint64_t ec_sum; |
128 | int ec_count; | 128 | int ec_count; |
129 | }; | 129 | }; |
130 | 130 | ||
diff --git a/include/mtd/ubi-header.h b/drivers/mtd/ubi/ubi-media.h index 292f916ea564..c3185d9fd048 100644 --- a/include/mtd/ubi-header.h +++ b/drivers/mtd/ubi/ubi-media.h | |||
@@ -24,11 +24,11 @@ | |||
24 | 24 | ||
25 | /* | 25 | /* |
26 | * This file defines the layout of UBI headers and all the other UBI on-flash | 26 | * This file defines the layout of UBI headers and all the other UBI on-flash |
27 | * data structures. May be included by user-space. | 27 | * data structures. |
28 | */ | 28 | */ |
29 | 29 | ||
30 | #ifndef __UBI_HEADER_H__ | 30 | #ifndef __UBI_MEDIA_H__ |
31 | #define __UBI_HEADER_H__ | 31 | #define __UBI_MEDIA_H__ |
32 | 32 | ||
33 | #include <asm/byteorder.h> | 33 | #include <asm/byteorder.h> |
34 | 34 | ||
@@ -369,4 +369,4 @@ struct ubi_vtbl_record { | |||
369 | __be32 crc; | 369 | __be32 crc; |
370 | } __attribute__ ((packed)); | 370 | } __attribute__ ((packed)); |
371 | 371 | ||
372 | #endif /* !__UBI_HEADER_H__ */ | 372 | #endif /* !__UBI_MEDIA_H__ */ |
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index a548c1d28fa8..67dcbd11c15c 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h | |||
@@ -37,10 +37,9 @@ | |||
37 | #include <linux/string.h> | 37 | #include <linux/string.h> |
38 | #include <linux/vmalloc.h> | 38 | #include <linux/vmalloc.h> |
39 | #include <linux/mtd/mtd.h> | 39 | #include <linux/mtd/mtd.h> |
40 | |||
41 | #include <mtd/ubi-header.h> | ||
42 | #include <linux/mtd/ubi.h> | 40 | #include <linux/mtd/ubi.h> |
43 | 41 | ||
42 | #include "ubi-media.h" | ||
44 | #include "scan.h" | 43 | #include "scan.h" |
45 | #include "debug.h" | 44 | #include "debug.h" |
46 | 45 | ||
@@ -54,10 +53,10 @@ | |||
54 | #define ubi_msg(fmt, ...) printk(KERN_NOTICE "UBI: " fmt "\n", ##__VA_ARGS__) | 53 | #define ubi_msg(fmt, ...) printk(KERN_NOTICE "UBI: " fmt "\n", ##__VA_ARGS__) |
55 | /* UBI warning messages */ | 54 | /* UBI warning messages */ |
56 | #define ubi_warn(fmt, ...) printk(KERN_WARNING "UBI warning: %s: " fmt "\n", \ | 55 | #define ubi_warn(fmt, ...) printk(KERN_WARNING "UBI warning: %s: " fmt "\n", \ |
57 | __FUNCTION__, ##__VA_ARGS__) | 56 | __func__, ##__VA_ARGS__) |
58 | /* UBI error messages */ | 57 | /* UBI error messages */ |
59 | #define ubi_err(fmt, ...) printk(KERN_ERR "UBI error: %s: " fmt "\n", \ | 58 | #define ubi_err(fmt, ...) printk(KERN_ERR "UBI error: %s: " fmt "\n", \ |
60 | __FUNCTION__, ##__VA_ARGS__) | 59 | __func__, ##__VA_ARGS__) |
61 | 60 | ||
62 | /* Lowest number PEBs reserved for bad PEB handling */ | 61 | /* Lowest number PEBs reserved for bad PEB handling */ |
63 | #define MIN_RESEVED_PEBS 2 | 62 | #define MIN_RESEVED_PEBS 2 |
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index 978e20a1791b..1e39e78f1778 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c | |||
@@ -1248,3 +1248,4 @@ module_exit(at91ether_exit) | |||
1248 | MODULE_LICENSE("GPL"); | 1248 | MODULE_LICENSE("GPL"); |
1249 | MODULE_DESCRIPTION("AT91RM9200 EMAC Ethernet driver"); | 1249 | MODULE_DESCRIPTION("AT91RM9200 EMAC Ethernet driver"); |
1250 | MODULE_AUTHOR("Andrew Victor"); | 1250 | MODULE_AUTHOR("Andrew Victor"); |
1251 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index 91a6590d107b..ecd8fc6146e9 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c | |||
@@ -897,6 +897,7 @@ static struct platform_driver ep93xx_eth_driver = { | |||
897 | .remove = ep93xx_eth_remove, | 897 | .remove = ep93xx_eth_remove, |
898 | .driver = { | 898 | .driver = { |
899 | .name = "ep93xx-eth", | 899 | .name = "ep93xx-eth", |
900 | .owner = THIS_MODULE, | ||
900 | }, | 901 | }, |
901 | }; | 902 | }; |
902 | 903 | ||
@@ -914,3 +915,4 @@ static void __exit ep93xx_eth_cleanup_module(void) | |||
914 | module_init(ep93xx_eth_init_module); | 915 | module_init(ep93xx_eth_init_module); |
915 | module_exit(ep93xx_eth_cleanup_module); | 916 | module_exit(ep93xx_eth_cleanup_module); |
916 | MODULE_LICENSE("GPL"); | 917 | MODULE_LICENSE("GPL"); |
918 | MODULE_ALIAS("platform:ep93xx-eth"); | ||
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 5586fc624688..0afe522b8f7b 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c | |||
@@ -91,6 +91,144 @@ | |||
91 | #include "atlx.c" | 91 | #include "atlx.c" |
92 | 92 | ||
93 | /* | 93 | /* |
94 | * This is the only thing that needs to be changed to adjust the | ||
95 | * maximum number of ports that the driver can manage. | ||
96 | */ | ||
97 | #define ATL1_MAX_NIC 4 | ||
98 | |||
99 | #define OPTION_UNSET -1 | ||
100 | #define OPTION_DISABLED 0 | ||
101 | #define OPTION_ENABLED 1 | ||
102 | |||
103 | #define ATL1_PARAM_INIT { [0 ... ATL1_MAX_NIC] = OPTION_UNSET } | ||
104 | |||
105 | /* | ||
106 | * Interrupt Moderate Timer in units of 2 us | ||
107 | * | ||
108 | * Valid Range: 10-65535 | ||
109 | * | ||
110 | * Default Value: 100 (200us) | ||
111 | */ | ||
112 | static int __devinitdata int_mod_timer[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT; | ||
113 | static int num_int_mod_timer; | ||
114 | module_param_array_named(int_mod_timer, int_mod_timer, int, | ||
115 | &num_int_mod_timer, 0); | ||
116 | MODULE_PARM_DESC(int_mod_timer, "Interrupt moderator timer"); | ||
117 | |||
118 | #define DEFAULT_INT_MOD_CNT 100 /* 200us */ | ||
119 | #define MAX_INT_MOD_CNT 65000 | ||
120 | #define MIN_INT_MOD_CNT 50 | ||
121 | |||
122 | struct atl1_option { | ||
123 | enum { enable_option, range_option, list_option } type; | ||
124 | char *name; | ||
125 | char *err; | ||
126 | int def; | ||
127 | union { | ||
128 | struct { /* range_option info */ | ||
129 | int min; | ||
130 | int max; | ||
131 | } r; | ||
132 | struct { /* list_option info */ | ||
133 | int nr; | ||
134 | struct atl1_opt_list { | ||
135 | int i; | ||
136 | char *str; | ||
137 | } *p; | ||
138 | } l; | ||
139 | } arg; | ||
140 | }; | ||
141 | |||
142 | static int __devinit atl1_validate_option(int *value, struct atl1_option *opt, | ||
143 | struct pci_dev *pdev) | ||
144 | { | ||
145 | if (*value == OPTION_UNSET) { | ||
146 | *value = opt->def; | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | switch (opt->type) { | ||
151 | case enable_option: | ||
152 | switch (*value) { | ||
153 | case OPTION_ENABLED: | ||
154 | dev_info(&pdev->dev, "%s enabled\n", opt->name); | ||
155 | return 0; | ||
156 | case OPTION_DISABLED: | ||
157 | dev_info(&pdev->dev, "%s disabled\n", opt->name); | ||
158 | return 0; | ||
159 | } | ||
160 | break; | ||
161 | case range_option: | ||
162 | if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) { | ||
163 | dev_info(&pdev->dev, "%s set to %i\n", opt->name, | ||
164 | *value); | ||
165 | return 0; | ||
166 | } | ||
167 | break; | ||
168 | case list_option:{ | ||
169 | int i; | ||
170 | struct atl1_opt_list *ent; | ||
171 | |||
172 | for (i = 0; i < opt->arg.l.nr; i++) { | ||
173 | ent = &opt->arg.l.p[i]; | ||
174 | if (*value == ent->i) { | ||
175 | if (ent->str[0] != '\0') | ||
176 | dev_info(&pdev->dev, "%s\n", | ||
177 | ent->str); | ||
178 | return 0; | ||
179 | } | ||
180 | } | ||
181 | } | ||
182 | break; | ||
183 | |||
184 | default: | ||
185 | break; | ||
186 | } | ||
187 | |||
188 | dev_info(&pdev->dev, "invalid %s specified (%i) %s\n", | ||
189 | opt->name, *value, opt->err); | ||
190 | *value = opt->def; | ||
191 | return -1; | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * atl1_check_options - Range Checking for Command Line Parameters | ||
196 | * @adapter: board private structure | ||
197 | * | ||
198 | * This routine checks all command line parameters for valid user | ||
199 | * input. If an invalid value is given, or if no user specified | ||
200 | * value exists, a default value is used. The final value is stored | ||
201 | * in a variable in the adapter structure. | ||
202 | */ | ||
203 | void __devinit atl1_check_options(struct atl1_adapter *adapter) | ||
204 | { | ||
205 | struct pci_dev *pdev = adapter->pdev; | ||
206 | int bd = adapter->bd_number; | ||
207 | if (bd >= ATL1_MAX_NIC) { | ||
208 | dev_notice(&pdev->dev, "no configuration for board#%i\n", bd); | ||
209 | dev_notice(&pdev->dev, "using defaults for all values\n"); | ||
210 | } | ||
211 | { /* Interrupt Moderate Timer */ | ||
212 | struct atl1_option opt = { | ||
213 | .type = range_option, | ||
214 | .name = "Interrupt Moderator Timer", | ||
215 | .err = "using default of " | ||
216 | __MODULE_STRING(DEFAULT_INT_MOD_CNT), | ||
217 | .def = DEFAULT_INT_MOD_CNT, | ||
218 | .arg = {.r = {.min = MIN_INT_MOD_CNT, | ||
219 | .max = MAX_INT_MOD_CNT} } | ||
220 | }; | ||
221 | int val; | ||
222 | if (num_int_mod_timer > bd) { | ||
223 | val = int_mod_timer[bd]; | ||
224 | atl1_validate_option(&val, &opt, pdev); | ||
225 | adapter->imt = (u16) val; | ||
226 | } else | ||
227 | adapter->imt = (u16) (opt.def); | ||
228 | } | ||
229 | } | ||
230 | |||
231 | /* | ||
94 | * atl1_pci_tbl - PCI Device ID Table | 232 | * atl1_pci_tbl - PCI Device ID Table |
95 | */ | 233 | */ |
96 | static const struct pci_device_id atl1_pci_tbl[] = { | 234 | static const struct pci_device_id atl1_pci_tbl[] = { |
diff --git a/drivers/net/atlx/atlx.c b/drivers/net/atlx/atlx.c index 4186326d1b94..f06b854e2501 100644 --- a/drivers/net/atlx/atlx.c +++ b/drivers/net/atlx/atlx.c | |||
@@ -253,181 +253,4 @@ static void atlx_restore_vlan(struct atlx_adapter *adapter) | |||
253 | atlx_vlan_rx_register(adapter->netdev, adapter->vlgrp); | 253 | atlx_vlan_rx_register(adapter->netdev, adapter->vlgrp); |
254 | } | 254 | } |
255 | 255 | ||
256 | /* | ||
257 | * This is the only thing that needs to be changed to adjust the | ||
258 | * maximum number of ports that the driver can manage. | ||
259 | */ | ||
260 | #define ATL1_MAX_NIC 4 | ||
261 | |||
262 | #define OPTION_UNSET -1 | ||
263 | #define OPTION_DISABLED 0 | ||
264 | #define OPTION_ENABLED 1 | ||
265 | |||
266 | #define ATL1_PARAM_INIT { [0 ... ATL1_MAX_NIC] = OPTION_UNSET } | ||
267 | |||
268 | /* | ||
269 | * Interrupt Moderate Timer in units of 2 us | ||
270 | * | ||
271 | * Valid Range: 10-65535 | ||
272 | * | ||
273 | * Default Value: 100 (200us) | ||
274 | */ | ||
275 | static int __devinitdata int_mod_timer[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT; | ||
276 | static int num_int_mod_timer; | ||
277 | module_param_array_named(int_mod_timer, int_mod_timer, int, | ||
278 | &num_int_mod_timer, 0); | ||
279 | MODULE_PARM_DESC(int_mod_timer, "Interrupt moderator timer"); | ||
280 | |||
281 | /* | ||
282 | * flash_vendor | ||
283 | * | ||
284 | * Valid Range: 0-2 | ||
285 | * | ||
286 | * 0 - Atmel | ||
287 | * 1 - SST | ||
288 | * 2 - ST | ||
289 | * | ||
290 | * Default Value: 0 | ||
291 | */ | ||
292 | static int __devinitdata flash_vendor[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT; | ||
293 | static int num_flash_vendor; | ||
294 | module_param_array_named(flash_vendor, flash_vendor, int, &num_flash_vendor, 0); | ||
295 | MODULE_PARM_DESC(flash_vendor, "SPI flash vendor"); | ||
296 | |||
297 | #define DEFAULT_INT_MOD_CNT 100 /* 200us */ | ||
298 | #define MAX_INT_MOD_CNT 65000 | ||
299 | #define MIN_INT_MOD_CNT 50 | ||
300 | |||
301 | #define FLASH_VENDOR_DEFAULT 0 | ||
302 | #define FLASH_VENDOR_MIN 0 | ||
303 | #define FLASH_VENDOR_MAX 2 | ||
304 | |||
305 | struct atl1_option { | ||
306 | enum { enable_option, range_option, list_option } type; | ||
307 | char *name; | ||
308 | char *err; | ||
309 | int def; | ||
310 | union { | ||
311 | struct { /* range_option info */ | ||
312 | int min; | ||
313 | int max; | ||
314 | } r; | ||
315 | struct { /* list_option info */ | ||
316 | int nr; | ||
317 | struct atl1_opt_list { | ||
318 | int i; | ||
319 | char *str; | ||
320 | } *p; | ||
321 | } l; | ||
322 | } arg; | ||
323 | }; | ||
324 | |||
325 | static int __devinit atl1_validate_option(int *value, struct atl1_option *opt, | ||
326 | struct pci_dev *pdev) | ||
327 | { | ||
328 | if (*value == OPTION_UNSET) { | ||
329 | *value = opt->def; | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | switch (opt->type) { | ||
334 | case enable_option: | ||
335 | switch (*value) { | ||
336 | case OPTION_ENABLED: | ||
337 | dev_info(&pdev->dev, "%s enabled\n", opt->name); | ||
338 | return 0; | ||
339 | case OPTION_DISABLED: | ||
340 | dev_info(&pdev->dev, "%s disabled\n", opt->name); | ||
341 | return 0; | ||
342 | } | ||
343 | break; | ||
344 | case range_option: | ||
345 | if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) { | ||
346 | dev_info(&pdev->dev, "%s set to %i\n", opt->name, | ||
347 | *value); | ||
348 | return 0; | ||
349 | } | ||
350 | break; | ||
351 | case list_option:{ | ||
352 | int i; | ||
353 | struct atl1_opt_list *ent; | ||
354 | |||
355 | for (i = 0; i < opt->arg.l.nr; i++) { | ||
356 | ent = &opt->arg.l.p[i]; | ||
357 | if (*value == ent->i) { | ||
358 | if (ent->str[0] != '\0') | ||
359 | dev_info(&pdev->dev, "%s\n", | ||
360 | ent->str); | ||
361 | return 0; | ||
362 | } | ||
363 | } | ||
364 | } | ||
365 | break; | ||
366 | |||
367 | default: | ||
368 | break; | ||
369 | } | ||
370 | |||
371 | dev_info(&pdev->dev, "invalid %s specified (%i) %s\n", | ||
372 | opt->name, *value, opt->err); | ||
373 | *value = opt->def; | ||
374 | return -1; | ||
375 | } | ||
376 | |||
377 | /* | ||
378 | * atl1_check_options - Range Checking for Command Line Parameters | ||
379 | * @adapter: board private structure | ||
380 | * | ||
381 | * This routine checks all command line parameters for valid user | ||
382 | * input. If an invalid value is given, or if no user specified | ||
383 | * value exists, a default value is used. The final value is stored | ||
384 | * in a variable in the adapter structure. | ||
385 | */ | ||
386 | void __devinit atl1_check_options(struct atl1_adapter *adapter) | ||
387 | { | ||
388 | struct pci_dev *pdev = adapter->pdev; | ||
389 | int bd = adapter->bd_number; | ||
390 | if (bd >= ATL1_MAX_NIC) { | ||
391 | dev_notice(&pdev->dev, "no configuration for board#%i\n", bd); | ||
392 | dev_notice(&pdev->dev, "using defaults for all values\n"); | ||
393 | } | ||
394 | { /* Interrupt Moderate Timer */ | ||
395 | struct atl1_option opt = { | ||
396 | .type = range_option, | ||
397 | .name = "Interrupt Moderator Timer", | ||
398 | .err = "using default of " | ||
399 | __MODULE_STRING(DEFAULT_INT_MOD_CNT), | ||
400 | .def = DEFAULT_INT_MOD_CNT, | ||
401 | .arg = {.r = {.min = MIN_INT_MOD_CNT, | ||
402 | .max = MAX_INT_MOD_CNT} } | ||
403 | }; | ||
404 | int val; | ||
405 | if (num_int_mod_timer > bd) { | ||
406 | val = int_mod_timer[bd]; | ||
407 | atl1_validate_option(&val, &opt, pdev); | ||
408 | adapter->imt = (u16) val; | ||
409 | } else | ||
410 | adapter->imt = (u16) (opt.def); | ||
411 | } | ||
412 | |||
413 | { /* Flash Vendor */ | ||
414 | struct atl1_option opt = { | ||
415 | .type = range_option, | ||
416 | .name = "SPI Flash Vendor", | ||
417 | .err = "using default of " | ||
418 | __MODULE_STRING(FLASH_VENDOR_DEFAULT), | ||
419 | .def = DEFAULT_INT_MOD_CNT, | ||
420 | .arg = {.r = {.min = FLASH_VENDOR_MIN, | ||
421 | .max = FLASH_VENDOR_MAX} } | ||
422 | }; | ||
423 | int val; | ||
424 | if (num_flash_vendor > bd) { | ||
425 | val = flash_vendor[bd]; | ||
426 | atl1_validate_option(&val, &opt, pdev); | ||
427 | adapter->hw.flash_vendor = (u8) val; | ||
428 | } else | ||
429 | adapter->hw.flash_vendor = (u8) (opt.def); | ||
430 | } | ||
431 | } | ||
432 | |||
433 | #endif /* ATLX_C */ | 256 | #endif /* ATLX_C */ |
diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c index 194949afacd0..0b4adf4a0f7d 100644 --- a/drivers/net/ax88796.c +++ b/drivers/net/ax88796.c | |||
@@ -1005,3 +1005,4 @@ module_exit(axdrv_exit); | |||
1005 | MODULE_DESCRIPTION("AX88796 10/100 Ethernet platform driver"); | 1005 | MODULE_DESCRIPTION("AX88796 10/100 Ethernet platform driver"); |
1006 | MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); | 1006 | MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); |
1007 | MODULE_LICENSE("GPL v2"); | 1007 | MODULE_LICENSE("GPL v2"); |
1008 | MODULE_ALIAS("platform:ax88796"); | ||
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 717dcc1aa1e9..4fec8581bfd7 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c | |||
@@ -47,6 +47,7 @@ | |||
47 | MODULE_AUTHOR(DRV_AUTHOR); | 47 | MODULE_AUTHOR(DRV_AUTHOR); |
48 | MODULE_LICENSE("GPL"); | 48 | MODULE_LICENSE("GPL"); |
49 | MODULE_DESCRIPTION(DRV_DESC); | 49 | MODULE_DESCRIPTION(DRV_DESC); |
50 | MODULE_ALIAS("platform:bfin_mac"); | ||
50 | 51 | ||
51 | #if defined(CONFIG_BFIN_MAC_USE_L1) | 52 | #if defined(CONFIG_BFIN_MAC_USE_L1) |
52 | # define bfin_mac_alloc(dma_handle, size) l1_data_sram_zalloc(size) | 53 | # define bfin_mac_alloc(dma_handle, size) l1_data_sram_zalloc(size) |
@@ -1089,8 +1090,9 @@ static struct platform_driver bfin_mac_driver = { | |||
1089 | .resume = bfin_mac_resume, | 1090 | .resume = bfin_mac_resume, |
1090 | .suspend = bfin_mac_suspend, | 1091 | .suspend = bfin_mac_suspend, |
1091 | .driver = { | 1092 | .driver = { |
1092 | .name = DRV_NAME, | 1093 | .name = DRV_NAME, |
1093 | }, | 1094 | .owner = THIS_MODULE, |
1095 | }, | ||
1094 | }; | 1096 | }; |
1095 | 1097 | ||
1096 | static int __init bfin_mac_init(void) | 1098 | static int __init bfin_mac_init(void) |
@@ -1106,3 +1108,4 @@ static void __exit bfin_mac_cleanup(void) | |||
1106 | } | 1108 | } |
1107 | 1109 | ||
1108 | module_exit(bfin_mac_cleanup); | 1110 | module_exit(bfin_mac_cleanup); |
1111 | |||
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 9da7ff437031..2b5740b3d182 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c | |||
@@ -42,6 +42,7 @@ | |||
42 | MODULE_AUTHOR("Eugene Konev <ejka@imfi.kspu.ru>"); | 42 | MODULE_AUTHOR("Eugene Konev <ejka@imfi.kspu.ru>"); |
43 | MODULE_DESCRIPTION("TI AR7 ethernet driver (CPMAC)"); | 43 | MODULE_DESCRIPTION("TI AR7 ethernet driver (CPMAC)"); |
44 | MODULE_LICENSE("GPL"); | 44 | MODULE_LICENSE("GPL"); |
45 | MODULE_ALIAS("platform:cpmac"); | ||
45 | 46 | ||
46 | static int debug_level = 8; | 47 | static int debug_level = 8; |
47 | static int dumb_switch; | 48 | static int dumb_switch; |
@@ -1103,6 +1104,7 @@ static int __devexit cpmac_remove(struct platform_device *pdev) | |||
1103 | 1104 | ||
1104 | static struct platform_driver cpmac_driver = { | 1105 | static struct platform_driver cpmac_driver = { |
1105 | .driver.name = "cpmac", | 1106 | .driver.name = "cpmac", |
1107 | .driver.owner = THIS_MODULE, | ||
1106 | .probe = cpmac_probe, | 1108 | .probe = cpmac_probe, |
1107 | .remove = __devexit_p(cpmac_remove), | 1109 | .remove = __devexit_p(cpmac_remove), |
1108 | }; | 1110 | }; |
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index d63cc93f055d..e6fe2614ea6d 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c | |||
@@ -1418,3 +1418,4 @@ module_exit(dm9000_cleanup); | |||
1418 | MODULE_AUTHOR("Sascha Hauer, Ben Dooks"); | 1418 | MODULE_AUTHOR("Sascha Hauer, Ben Dooks"); |
1419 | MODULE_DESCRIPTION("Davicom DM9000 network driver"); | 1419 | MODULE_DESCRIPTION("Davicom DM9000 network driver"); |
1420 | MODULE_LICENSE("GPL"); | 1420 | MODULE_LICENSE("GPL"); |
1421 | MODULE_ALIAS("platform:dm9000"); | ||
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index 01c88664bad3..462351ca2c81 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c | |||
@@ -1326,12 +1326,10 @@ struct e1000_info e1000_82571_info = { | |||
1326 | .mac = e1000_82571, | 1326 | .mac = e1000_82571, |
1327 | .flags = FLAG_HAS_HW_VLAN_FILTER | 1327 | .flags = FLAG_HAS_HW_VLAN_FILTER |
1328 | | FLAG_HAS_JUMBO_FRAMES | 1328 | | FLAG_HAS_JUMBO_FRAMES |
1329 | | FLAG_HAS_STATS_PTC_PRC | ||
1330 | | FLAG_HAS_WOL | 1329 | | FLAG_HAS_WOL |
1331 | | FLAG_APME_IN_CTRL3 | 1330 | | FLAG_APME_IN_CTRL3 |
1332 | | FLAG_RX_CSUM_ENABLED | 1331 | | FLAG_RX_CSUM_ENABLED |
1333 | | FLAG_HAS_CTRLEXT_ON_LOAD | 1332 | | FLAG_HAS_CTRLEXT_ON_LOAD |
1334 | | FLAG_HAS_STATS_ICR_ICT | ||
1335 | | FLAG_HAS_SMART_POWER_DOWN | 1333 | | FLAG_HAS_SMART_POWER_DOWN |
1336 | | FLAG_RESET_OVERWRITES_LAA /* errata */ | 1334 | | FLAG_RESET_OVERWRITES_LAA /* errata */ |
1337 | | FLAG_TARC_SPEED_MODE_BIT /* errata */ | 1335 | | FLAG_TARC_SPEED_MODE_BIT /* errata */ |
@@ -1347,12 +1345,10 @@ struct e1000_info e1000_82572_info = { | |||
1347 | .mac = e1000_82572, | 1345 | .mac = e1000_82572, |
1348 | .flags = FLAG_HAS_HW_VLAN_FILTER | 1346 | .flags = FLAG_HAS_HW_VLAN_FILTER |
1349 | | FLAG_HAS_JUMBO_FRAMES | 1347 | | FLAG_HAS_JUMBO_FRAMES |
1350 | | FLAG_HAS_STATS_PTC_PRC | ||
1351 | | FLAG_HAS_WOL | 1348 | | FLAG_HAS_WOL |
1352 | | FLAG_APME_IN_CTRL3 | 1349 | | FLAG_APME_IN_CTRL3 |
1353 | | FLAG_RX_CSUM_ENABLED | 1350 | | FLAG_RX_CSUM_ENABLED |
1354 | | FLAG_HAS_CTRLEXT_ON_LOAD | 1351 | | FLAG_HAS_CTRLEXT_ON_LOAD |
1355 | | FLAG_HAS_STATS_ICR_ICT | ||
1356 | | FLAG_TARC_SPEED_MODE_BIT, /* errata */ | 1352 | | FLAG_TARC_SPEED_MODE_BIT, /* errata */ |
1357 | .pba = 38, | 1353 | .pba = 38, |
1358 | .get_variants = e1000_get_variants_82571, | 1354 | .get_variants = e1000_get_variants_82571, |
@@ -1365,11 +1361,9 @@ struct e1000_info e1000_82573_info = { | |||
1365 | .mac = e1000_82573, | 1361 | .mac = e1000_82573, |
1366 | .flags = FLAG_HAS_HW_VLAN_FILTER | 1362 | .flags = FLAG_HAS_HW_VLAN_FILTER |
1367 | | FLAG_HAS_JUMBO_FRAMES | 1363 | | FLAG_HAS_JUMBO_FRAMES |
1368 | | FLAG_HAS_STATS_PTC_PRC | ||
1369 | | FLAG_HAS_WOL | 1364 | | FLAG_HAS_WOL |
1370 | | FLAG_APME_IN_CTRL3 | 1365 | | FLAG_APME_IN_CTRL3 |
1371 | | FLAG_RX_CSUM_ENABLED | 1366 | | FLAG_RX_CSUM_ENABLED |
1372 | | FLAG_HAS_STATS_ICR_ICT | ||
1373 | | FLAG_HAS_SMART_POWER_DOWN | 1367 | | FLAG_HAS_SMART_POWER_DOWN |
1374 | | FLAG_HAS_AMT | 1368 | | FLAG_HAS_AMT |
1375 | | FLAG_HAS_ERT | 1369 | | FLAG_HAS_ERT |
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index 572cfd44397a..2a53875cddbf 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h | |||
@@ -184,6 +184,7 @@ | |||
184 | #define E1000_SWFW_EEP_SM 0x1 | 184 | #define E1000_SWFW_EEP_SM 0x1 |
185 | #define E1000_SWFW_PHY0_SM 0x2 | 185 | #define E1000_SWFW_PHY0_SM 0x2 |
186 | #define E1000_SWFW_PHY1_SM 0x4 | 186 | #define E1000_SWFW_PHY1_SM 0x4 |
187 | #define E1000_SWFW_CSR_SM 0x8 | ||
187 | 188 | ||
188 | /* Device Control */ | 189 | /* Device Control */ |
189 | #define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ | 190 | #define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ |
@@ -527,8 +528,10 @@ | |||
527 | #define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ | 528 | #define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ |
528 | #define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ | 529 | #define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ |
529 | #define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ | 530 | #define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ |
531 | #define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */ | ||
530 | #define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ | 532 | #define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ |
531 | #define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ | 533 | #define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ |
534 | #define PHY_EXT_STATUS 0x0F /* Extended Status Reg */ | ||
532 | 535 | ||
533 | /* NVM Control */ | 536 | /* NVM Control */ |
534 | #define E1000_EECD_SK 0x00000001 /* NVM Clock */ | 537 | #define E1000_EECD_SK 0x00000001 /* NVM Clock */ |
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index 5a89dff52264..38bfd0d261fe 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h | |||
@@ -64,11 +64,14 @@ struct e1000_info; | |||
64 | /* Tx/Rx descriptor defines */ | 64 | /* Tx/Rx descriptor defines */ |
65 | #define E1000_DEFAULT_TXD 256 | 65 | #define E1000_DEFAULT_TXD 256 |
66 | #define E1000_MAX_TXD 4096 | 66 | #define E1000_MAX_TXD 4096 |
67 | #define E1000_MIN_TXD 80 | 67 | #define E1000_MIN_TXD 64 |
68 | 68 | ||
69 | #define E1000_DEFAULT_RXD 256 | 69 | #define E1000_DEFAULT_RXD 256 |
70 | #define E1000_MAX_RXD 4096 | 70 | #define E1000_MAX_RXD 4096 |
71 | #define E1000_MIN_RXD 80 | 71 | #define E1000_MIN_RXD 64 |
72 | |||
73 | #define E1000_MIN_ITR_USECS 10 /* 100000 irq/sec */ | ||
74 | #define E1000_MAX_ITR_USECS 10000 /* 100 irq/sec */ | ||
72 | 75 | ||
73 | /* Early Receive defines */ | 76 | /* Early Receive defines */ |
74 | #define E1000_ERT_2048 0x100 | 77 | #define E1000_ERT_2048 0x100 |
@@ -147,6 +150,18 @@ struct e1000_ring { | |||
147 | struct e1000_queue_stats stats; | 150 | struct e1000_queue_stats stats; |
148 | }; | 151 | }; |
149 | 152 | ||
153 | /* PHY register snapshot values */ | ||
154 | struct e1000_phy_regs { | ||
155 | u16 bmcr; /* basic mode control register */ | ||
156 | u16 bmsr; /* basic mode status register */ | ||
157 | u16 advertise; /* auto-negotiation advertisement */ | ||
158 | u16 lpa; /* link partner ability register */ | ||
159 | u16 expansion; /* auto-negotiation expansion reg */ | ||
160 | u16 ctrl1000; /* 1000BASE-T control register */ | ||
161 | u16 stat1000; /* 1000BASE-T status register */ | ||
162 | u16 estatus; /* extended status register */ | ||
163 | }; | ||
164 | |||
150 | /* board specific private data structure */ | 165 | /* board specific private data structure */ |
151 | struct e1000_adapter { | 166 | struct e1000_adapter { |
152 | struct timer_list watchdog_timer; | 167 | struct timer_list watchdog_timer; |
@@ -202,8 +217,8 @@ struct e1000_adapter { | |||
202 | /* Tx stats */ | 217 | /* Tx stats */ |
203 | u64 tpt_old; | 218 | u64 tpt_old; |
204 | u64 colc_old; | 219 | u64 colc_old; |
205 | u64 gotcl_old; | 220 | u32 gotc; |
206 | u32 gotcl; | 221 | u64 gotc_old; |
207 | u32 tx_timeout_count; | 222 | u32 tx_timeout_count; |
208 | u32 tx_fifo_head; | 223 | u32 tx_fifo_head; |
209 | u32 tx_head_addr; | 224 | u32 tx_head_addr; |
@@ -227,8 +242,8 @@ struct e1000_adapter { | |||
227 | u64 hw_csum_err; | 242 | u64 hw_csum_err; |
228 | u64 hw_csum_good; | 243 | u64 hw_csum_good; |
229 | u64 rx_hdr_split; | 244 | u64 rx_hdr_split; |
230 | u64 gorcl_old; | 245 | u32 gorc; |
231 | u32 gorcl; | 246 | u64 gorc_old; |
232 | u32 alloc_rx_buff_failed; | 247 | u32 alloc_rx_buff_failed; |
233 | u32 rx_dma_failed; | 248 | u32 rx_dma_failed; |
234 | 249 | ||
@@ -250,6 +265,9 @@ struct e1000_adapter { | |||
250 | struct e1000_phy_info phy_info; | 265 | struct e1000_phy_info phy_info; |
251 | struct e1000_phy_stats phy_stats; | 266 | struct e1000_phy_stats phy_stats; |
252 | 267 | ||
268 | /* Snapshot of PHY registers */ | ||
269 | struct e1000_phy_regs phy_regs; | ||
270 | |||
253 | struct e1000_ring test_tx_ring; | 271 | struct e1000_ring test_tx_ring; |
254 | struct e1000_ring test_rx_ring; | 272 | struct e1000_ring test_rx_ring; |
255 | u32 test_icr; | 273 | u32 test_icr; |
@@ -286,8 +304,6 @@ struct e1000_info { | |||
286 | #define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5) | 304 | #define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5) |
287 | #define FLAG_HAS_SWSM_ON_LOAD (1 << 6) | 305 | #define FLAG_HAS_SWSM_ON_LOAD (1 << 6) |
288 | #define FLAG_HAS_JUMBO_FRAMES (1 << 7) | 306 | #define FLAG_HAS_JUMBO_FRAMES (1 << 7) |
289 | #define FLAG_HAS_STATS_ICR_ICT (1 << 9) | ||
290 | #define FLAG_HAS_STATS_PTC_PRC (1 << 10) | ||
291 | #define FLAG_HAS_SMART_POWER_DOWN (1 << 11) | 307 | #define FLAG_HAS_SMART_POWER_DOWN (1 << 11) |
292 | #define FLAG_IS_QUAD_PORT_A (1 << 12) | 308 | #define FLAG_IS_QUAD_PORT_A (1 << 12) |
293 | #define FLAG_IS_QUAD_PORT (1 << 13) | 309 | #define FLAG_IS_QUAD_PORT (1 << 13) |
@@ -433,6 +449,8 @@ extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data); | |||
433 | extern s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, | 449 | extern s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, |
434 | u32 usec_interval, bool *success); | 450 | u32 usec_interval, bool *success); |
435 | extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw); | 451 | extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw); |
452 | extern s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); | ||
453 | extern s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); | ||
436 | extern s32 e1000e_check_downshift(struct e1000_hw *hw); | 454 | extern s32 e1000e_check_downshift(struct e1000_hw *hw); |
437 | 455 | ||
438 | static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw) | 456 | static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw) |
diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c index d59a99ae44be..dc552d7d6fac 100644 --- a/drivers/net/e1000e/es2lan.c +++ b/drivers/net/e1000e/es2lan.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL 0x00 | 41 | #define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL 0x00 |
42 | #define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL 0x02 | 42 | #define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL 0x02 |
43 | #define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL 0x10 | 43 | #define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL 0x10 |
44 | #define E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE 0x1F | ||
44 | 45 | ||
45 | #define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS 0x0008 | 46 | #define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS 0x0008 |
46 | #define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS 0x0800 | 47 | #define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS 0x0800 |
@@ -48,6 +49,7 @@ | |||
48 | 49 | ||
49 | #define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004 | 50 | #define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004 |
50 | #define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000 | 51 | #define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000 |
52 | #define E1000_KMRNCTRLSTA_OPMODE_E_IDLE 0x2000 | ||
51 | 53 | ||
52 | #define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */ | 54 | #define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */ |
53 | #define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000 | 55 | #define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000 |
@@ -85,6 +87,9 @@ | |||
85 | /* Kumeran Mode Control Register (Page 193, Register 16) */ | 87 | /* Kumeran Mode Control Register (Page 193, Register 16) */ |
86 | #define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800 | 88 | #define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800 |
87 | 89 | ||
90 | /* Max number of times Kumeran read/write should be validated */ | ||
91 | #define GG82563_MAX_KMRN_RETRY 0x5 | ||
92 | |||
88 | /* Power Management Control Register (Page 193, Register 20) */ | 93 | /* Power Management Control Register (Page 193, Register 20) */ |
89 | #define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001 | 94 | #define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001 |
90 | /* 1=Enable SERDES Electrical Idle */ | 95 | /* 1=Enable SERDES Electrical Idle */ |
@@ -270,6 +275,7 @@ static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw) | |||
270 | u16 mask; | 275 | u16 mask; |
271 | 276 | ||
272 | mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; | 277 | mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; |
278 | mask |= E1000_SWFW_CSR_SM; | ||
273 | 279 | ||
274 | return e1000_acquire_swfw_sync_80003es2lan(hw, mask); | 280 | return e1000_acquire_swfw_sync_80003es2lan(hw, mask); |
275 | } | 281 | } |
@@ -286,6 +292,8 @@ static void e1000_release_phy_80003es2lan(struct e1000_hw *hw) | |||
286 | u16 mask; | 292 | u16 mask; |
287 | 293 | ||
288 | mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; | 294 | mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; |
295 | mask |= E1000_SWFW_CSR_SM; | ||
296 | |||
289 | e1000_release_swfw_sync_80003es2lan(hw, mask); | 297 | e1000_release_swfw_sync_80003es2lan(hw, mask); |
290 | } | 298 | } |
291 | 299 | ||
@@ -410,20 +418,27 @@ static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, | |||
410 | u32 page_select; | 418 | u32 page_select; |
411 | u16 temp; | 419 | u16 temp; |
412 | 420 | ||
421 | ret_val = e1000_acquire_phy_80003es2lan(hw); | ||
422 | if (ret_val) | ||
423 | return ret_val; | ||
424 | |||
413 | /* Select Configuration Page */ | 425 | /* Select Configuration Page */ |
414 | if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) | 426 | if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) { |
415 | page_select = GG82563_PHY_PAGE_SELECT; | 427 | page_select = GG82563_PHY_PAGE_SELECT; |
416 | else | 428 | } else { |
417 | /* | 429 | /* |
418 | * Use Alternative Page Select register to access | 430 | * Use Alternative Page Select register to access |
419 | * registers 30 and 31 | 431 | * registers 30 and 31 |
420 | */ | 432 | */ |
421 | page_select = GG82563_PHY_PAGE_SELECT_ALT; | 433 | page_select = GG82563_PHY_PAGE_SELECT_ALT; |
434 | } | ||
422 | 435 | ||
423 | temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT); | 436 | temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT); |
424 | ret_val = e1000e_write_phy_reg_m88(hw, page_select, temp); | 437 | ret_val = e1000e_write_phy_reg_mdic(hw, page_select, temp); |
425 | if (ret_val) | 438 | if (ret_val) { |
439 | e1000_release_phy_80003es2lan(hw); | ||
426 | return ret_val; | 440 | return ret_val; |
441 | } | ||
427 | 442 | ||
428 | /* | 443 | /* |
429 | * The "ready" bit in the MDIC register may be incorrectly set | 444 | * The "ready" bit in the MDIC register may be incorrectly set |
@@ -433,20 +448,21 @@ static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, | |||
433 | udelay(200); | 448 | udelay(200); |
434 | 449 | ||
435 | /* ...and verify the command was successful. */ | 450 | /* ...and verify the command was successful. */ |
436 | ret_val = e1000e_read_phy_reg_m88(hw, page_select, &temp); | 451 | ret_val = e1000e_read_phy_reg_mdic(hw, page_select, &temp); |
437 | 452 | ||
438 | if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { | 453 | if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { |
439 | ret_val = -E1000_ERR_PHY; | 454 | ret_val = -E1000_ERR_PHY; |
455 | e1000_release_phy_80003es2lan(hw); | ||
440 | return ret_val; | 456 | return ret_val; |
441 | } | 457 | } |
442 | 458 | ||
443 | udelay(200); | 459 | udelay(200); |
444 | 460 | ||
445 | ret_val = e1000e_read_phy_reg_m88(hw, | 461 | ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, |
446 | MAX_PHY_REG_ADDRESS & offset, | 462 | data); |
447 | data); | ||
448 | 463 | ||
449 | udelay(200); | 464 | udelay(200); |
465 | e1000_release_phy_80003es2lan(hw); | ||
450 | 466 | ||
451 | return ret_val; | 467 | return ret_val; |
452 | } | 468 | } |
@@ -467,20 +483,27 @@ static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, | |||
467 | u32 page_select; | 483 | u32 page_select; |
468 | u16 temp; | 484 | u16 temp; |
469 | 485 | ||
486 | ret_val = e1000_acquire_phy_80003es2lan(hw); | ||
487 | if (ret_val) | ||
488 | return ret_val; | ||
489 | |||
470 | /* Select Configuration Page */ | 490 | /* Select Configuration Page */ |
471 | if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) | 491 | if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) { |
472 | page_select = GG82563_PHY_PAGE_SELECT; | 492 | page_select = GG82563_PHY_PAGE_SELECT; |
473 | else | 493 | } else { |
474 | /* | 494 | /* |
475 | * Use Alternative Page Select register to access | 495 | * Use Alternative Page Select register to access |
476 | * registers 30 and 31 | 496 | * registers 30 and 31 |
477 | */ | 497 | */ |
478 | page_select = GG82563_PHY_PAGE_SELECT_ALT; | 498 | page_select = GG82563_PHY_PAGE_SELECT_ALT; |
499 | } | ||
479 | 500 | ||
480 | temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT); | 501 | temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT); |
481 | ret_val = e1000e_write_phy_reg_m88(hw, page_select, temp); | 502 | ret_val = e1000e_write_phy_reg_mdic(hw, page_select, temp); |
482 | if (ret_val) | 503 | if (ret_val) { |
504 | e1000_release_phy_80003es2lan(hw); | ||
483 | return ret_val; | 505 | return ret_val; |
506 | } | ||
484 | 507 | ||
485 | 508 | ||
486 | /* | 509 | /* |
@@ -491,18 +514,20 @@ static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, | |||
491 | udelay(200); | 514 | udelay(200); |
492 | 515 | ||
493 | /* ...and verify the command was successful. */ | 516 | /* ...and verify the command was successful. */ |
494 | ret_val = e1000e_read_phy_reg_m88(hw, page_select, &temp); | 517 | ret_val = e1000e_read_phy_reg_mdic(hw, page_select, &temp); |
495 | 518 | ||
496 | if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) | 519 | if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { |
520 | e1000_release_phy_80003es2lan(hw); | ||
497 | return -E1000_ERR_PHY; | 521 | return -E1000_ERR_PHY; |
522 | } | ||
498 | 523 | ||
499 | udelay(200); | 524 | udelay(200); |
500 | 525 | ||
501 | ret_val = e1000e_write_phy_reg_m88(hw, | 526 | ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, |
502 | MAX_PHY_REG_ADDRESS & offset, | 527 | data); |
503 | data); | ||
504 | 528 | ||
505 | udelay(200); | 529 | udelay(200); |
530 | e1000_release_phy_80003es2lan(hw); | ||
506 | 531 | ||
507 | return ret_val; | 532 | return ret_val; |
508 | } | 533 | } |
@@ -882,10 +907,10 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw) | |||
882 | struct e1000_phy_info *phy = &hw->phy; | 907 | struct e1000_phy_info *phy = &hw->phy; |
883 | s32 ret_val; | 908 | s32 ret_val; |
884 | u32 ctrl_ext; | 909 | u32 ctrl_ext; |
885 | u16 data; | 910 | u32 i = 0; |
911 | u16 data, data2; | ||
886 | 912 | ||
887 | ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, | 913 | ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, &data); |
888 | &data); | ||
889 | if (ret_val) | 914 | if (ret_val) |
890 | return ret_val; | 915 | return ret_val; |
891 | 916 | ||
@@ -893,8 +918,7 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw) | |||
893 | /* Use 25MHz for both link down and 1000Base-T for Tx clock. */ | 918 | /* Use 25MHz for both link down and 1000Base-T for Tx clock. */ |
894 | data |= GG82563_MSCR_TX_CLK_1000MBPS_25; | 919 | data |= GG82563_MSCR_TX_CLK_1000MBPS_25; |
895 | 920 | ||
896 | ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL, | 921 | ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL, data); |
897 | data); | ||
898 | if (ret_val) | 922 | if (ret_val) |
899 | return ret_val; | 923 | return ret_val; |
900 | 924 | ||
@@ -954,6 +978,18 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw) | |||
954 | if (ret_val) | 978 | if (ret_val) |
955 | return ret_val; | 979 | return ret_val; |
956 | 980 | ||
981 | ret_val = e1000e_read_kmrn_reg(hw, | ||
982 | E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE, | ||
983 | &data); | ||
984 | if (ret_val) | ||
985 | return ret_val; | ||
986 | data |= E1000_KMRNCTRLSTA_OPMODE_E_IDLE; | ||
987 | ret_val = e1000e_write_kmrn_reg(hw, | ||
988 | E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE, | ||
989 | data); | ||
990 | if (ret_val) | ||
991 | return ret_val; | ||
992 | |||
957 | ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL_2, &data); | 993 | ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL_2, &data); |
958 | if (ret_val) | 994 | if (ret_val) |
959 | return ret_val; | 995 | return ret_val; |
@@ -983,9 +1019,18 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw) | |||
983 | if (ret_val) | 1019 | if (ret_val) |
984 | return ret_val; | 1020 | return ret_val; |
985 | 1021 | ||
986 | ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &data); | 1022 | do { |
987 | if (ret_val) | 1023 | ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, |
988 | return ret_val; | 1024 | &data); |
1025 | if (ret_val) | ||
1026 | return ret_val; | ||
1027 | |||
1028 | ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, | ||
1029 | &data2); | ||
1030 | if (ret_val) | ||
1031 | return ret_val; | ||
1032 | i++; | ||
1033 | } while ((data != data2) && (i < GG82563_MAX_KMRN_RETRY)); | ||
989 | 1034 | ||
990 | data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; | 1035 | data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; |
991 | ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, data); | 1036 | ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, data); |
@@ -1074,7 +1119,8 @@ static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex) | |||
1074 | { | 1119 | { |
1075 | s32 ret_val; | 1120 | s32 ret_val; |
1076 | u32 tipg; | 1121 | u32 tipg; |
1077 | u16 reg_data; | 1122 | u32 i = 0; |
1123 | u16 reg_data, reg_data2; | ||
1078 | 1124 | ||
1079 | reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT; | 1125 | reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT; |
1080 | ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, | 1126 | ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, |
@@ -1088,9 +1134,16 @@ static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex) | |||
1088 | tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN; | 1134 | tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN; |
1089 | ew32(TIPG, tipg); | 1135 | ew32(TIPG, tipg); |
1090 | 1136 | ||
1091 | ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, ®_data); | 1137 | do { |
1092 | if (ret_val) | 1138 | ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, ®_data); |
1093 | return ret_val; | 1139 | if (ret_val) |
1140 | return ret_val; | ||
1141 | |||
1142 | ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, ®_data2); | ||
1143 | if (ret_val) | ||
1144 | return ret_val; | ||
1145 | i++; | ||
1146 | } while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY)); | ||
1094 | 1147 | ||
1095 | if (duplex == HALF_DUPLEX) | 1148 | if (duplex == HALF_DUPLEX) |
1096 | reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER; | 1149 | reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER; |
@@ -1112,8 +1165,9 @@ static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex) | |||
1112 | static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw) | 1165 | static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw) |
1113 | { | 1166 | { |
1114 | s32 ret_val; | 1167 | s32 ret_val; |
1115 | u16 reg_data; | 1168 | u16 reg_data, reg_data2; |
1116 | u32 tipg; | 1169 | u32 tipg; |
1170 | u32 i = 0; | ||
1117 | 1171 | ||
1118 | reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT; | 1172 | reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT; |
1119 | ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, | 1173 | ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, |
@@ -1127,9 +1181,16 @@ static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw) | |||
1127 | tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN; | 1181 | tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN; |
1128 | ew32(TIPG, tipg); | 1182 | ew32(TIPG, tipg); |
1129 | 1183 | ||
1130 | ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, ®_data); | 1184 | do { |
1131 | if (ret_val) | 1185 | ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, ®_data); |
1132 | return ret_val; | 1186 | if (ret_val) |
1187 | return ret_val; | ||
1188 | |||
1189 | ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, ®_data2); | ||
1190 | if (ret_val) | ||
1191 | return ret_val; | ||
1192 | i++; | ||
1193 | } while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY)); | ||
1133 | 1194 | ||
1134 | reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; | 1195 | reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; |
1135 | ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data); | 1196 | ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data); |
@@ -1231,12 +1292,10 @@ struct e1000_info e1000_es2_info = { | |||
1231 | .mac = e1000_80003es2lan, | 1292 | .mac = e1000_80003es2lan, |
1232 | .flags = FLAG_HAS_HW_VLAN_FILTER | 1293 | .flags = FLAG_HAS_HW_VLAN_FILTER |
1233 | | FLAG_HAS_JUMBO_FRAMES | 1294 | | FLAG_HAS_JUMBO_FRAMES |
1234 | | FLAG_HAS_STATS_PTC_PRC | ||
1235 | | FLAG_HAS_WOL | 1295 | | FLAG_HAS_WOL |
1236 | | FLAG_APME_IN_CTRL3 | 1296 | | FLAG_APME_IN_CTRL3 |
1237 | | FLAG_RX_CSUM_ENABLED | 1297 | | FLAG_RX_CSUM_ENABLED |
1238 | | FLAG_HAS_CTRLEXT_ON_LOAD | 1298 | | FLAG_HAS_CTRLEXT_ON_LOAD |
1239 | | FLAG_HAS_STATS_ICR_ICT | ||
1240 | | FLAG_RX_NEEDS_RESTART /* errata */ | 1299 | | FLAG_RX_NEEDS_RESTART /* errata */ |
1241 | | FLAG_TARC_SET_BIT_ZERO /* errata */ | 1300 | | FLAG_TARC_SET_BIT_ZERO /* errata */ |
1242 | | FLAG_APME_CHECK_PORT_B | 1301 | | FLAG_APME_CHECK_PORT_B |
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 6d1b257bbda6..ce045acce63e 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c | |||
@@ -46,8 +46,8 @@ struct e1000_stats { | |||
46 | static const struct e1000_stats e1000_gstrings_stats[] = { | 46 | static const struct e1000_stats e1000_gstrings_stats[] = { |
47 | { "rx_packets", E1000_STAT(stats.gprc) }, | 47 | { "rx_packets", E1000_STAT(stats.gprc) }, |
48 | { "tx_packets", E1000_STAT(stats.gptc) }, | 48 | { "tx_packets", E1000_STAT(stats.gptc) }, |
49 | { "rx_bytes", E1000_STAT(stats.gorcl) }, | 49 | { "rx_bytes", E1000_STAT(stats.gorc) }, |
50 | { "tx_bytes", E1000_STAT(stats.gotcl) }, | 50 | { "tx_bytes", E1000_STAT(stats.gotc) }, |
51 | { "rx_broadcast", E1000_STAT(stats.bprc) }, | 51 | { "rx_broadcast", E1000_STAT(stats.bprc) }, |
52 | { "tx_broadcast", E1000_STAT(stats.bptc) }, | 52 | { "tx_broadcast", E1000_STAT(stats.bptc) }, |
53 | { "rx_multicast", E1000_STAT(stats.mprc) }, | 53 | { "rx_multicast", E1000_STAT(stats.mprc) }, |
@@ -83,7 +83,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = { | |||
83 | { "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) }, | 83 | { "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) }, |
84 | { "tx_flow_control_xon", E1000_STAT(stats.xontxc) }, | 84 | { "tx_flow_control_xon", E1000_STAT(stats.xontxc) }, |
85 | { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) }, | 85 | { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) }, |
86 | { "rx_long_byte_count", E1000_STAT(stats.gorcl) }, | 86 | { "rx_long_byte_count", E1000_STAT(stats.gorc) }, |
87 | { "rx_csum_offload_good", E1000_STAT(hw_csum_good) }, | 87 | { "rx_csum_offload_good", E1000_STAT(hw_csum_good) }, |
88 | { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }, | 88 | { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }, |
89 | { "rx_header_split", E1000_STAT(rx_hdr_split) }, | 89 | { "rx_header_split", E1000_STAT(rx_hdr_split) }, |
@@ -1770,6 +1770,47 @@ static int e1000_phys_id(struct net_device *netdev, u32 data) | |||
1770 | return 0; | 1770 | return 0; |
1771 | } | 1771 | } |
1772 | 1772 | ||
1773 | static int e1000_get_coalesce(struct net_device *netdev, | ||
1774 | struct ethtool_coalesce *ec) | ||
1775 | { | ||
1776 | struct e1000_adapter *adapter = netdev_priv(netdev); | ||
1777 | |||
1778 | if (adapter->itr_setting <= 3) | ||
1779 | ec->rx_coalesce_usecs = adapter->itr_setting; | ||
1780 | else | ||
1781 | ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting; | ||
1782 | |||
1783 | return 0; | ||
1784 | } | ||
1785 | |||
1786 | static int e1000_set_coalesce(struct net_device *netdev, | ||
1787 | struct ethtool_coalesce *ec) | ||
1788 | { | ||
1789 | struct e1000_adapter *adapter = netdev_priv(netdev); | ||
1790 | struct e1000_hw *hw = &adapter->hw; | ||
1791 | |||
1792 | if ((ec->rx_coalesce_usecs > E1000_MAX_ITR_USECS) || | ||
1793 | ((ec->rx_coalesce_usecs > 3) && | ||
1794 | (ec->rx_coalesce_usecs < E1000_MIN_ITR_USECS)) || | ||
1795 | (ec->rx_coalesce_usecs == 2)) | ||
1796 | return -EINVAL; | ||
1797 | |||
1798 | if (ec->rx_coalesce_usecs <= 3) { | ||
1799 | adapter->itr = 20000; | ||
1800 | adapter->itr_setting = ec->rx_coalesce_usecs; | ||
1801 | } else { | ||
1802 | adapter->itr = (1000000 / ec->rx_coalesce_usecs); | ||
1803 | adapter->itr_setting = adapter->itr & ~3; | ||
1804 | } | ||
1805 | |||
1806 | if (adapter->itr_setting != 0) | ||
1807 | ew32(ITR, 1000000000 / (adapter->itr * 256)); | ||
1808 | else | ||
1809 | ew32(ITR, 0); | ||
1810 | |||
1811 | return 0; | ||
1812 | } | ||
1813 | |||
1773 | static int e1000_nway_reset(struct net_device *netdev) | 1814 | static int e1000_nway_reset(struct net_device *netdev) |
1774 | { | 1815 | { |
1775 | struct e1000_adapter *adapter = netdev_priv(netdev); | 1816 | struct e1000_adapter *adapter = netdev_priv(netdev); |
@@ -1845,6 +1886,8 @@ static const struct ethtool_ops e1000_ethtool_ops = { | |||
1845 | .phys_id = e1000_phys_id, | 1886 | .phys_id = e1000_phys_id, |
1846 | .get_ethtool_stats = e1000_get_ethtool_stats, | 1887 | .get_ethtool_stats = e1000_get_ethtool_stats, |
1847 | .get_sset_count = e1000e_get_sset_count, | 1888 | .get_sset_count = e1000e_get_sset_count, |
1889 | .get_coalesce = e1000_get_coalesce, | ||
1890 | .set_coalesce = e1000_set_coalesce, | ||
1848 | }; | 1891 | }; |
1849 | 1892 | ||
1850 | void e1000e_set_ethtool_ops(struct net_device *netdev) | 1893 | void e1000e_set_ethtool_ops(struct net_device *netdev) |
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index 53f1ac6327fa..a930e6d9cf02 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h | |||
@@ -592,10 +592,8 @@ struct e1000_hw_stats { | |||
592 | u64 bprc; | 592 | u64 bprc; |
593 | u64 mprc; | 593 | u64 mprc; |
594 | u64 gptc; | 594 | u64 gptc; |
595 | u64 gorcl; | 595 | u64 gorc; |
596 | u64 gorch; | 596 | u64 gotc; |
597 | u64 gotcl; | ||
598 | u64 gotch; | ||
599 | u64 rnbc; | 597 | u64 rnbc; |
600 | u64 ruc; | 598 | u64 ruc; |
601 | u64 rfc; | 599 | u64 rfc; |
@@ -604,10 +602,8 @@ struct e1000_hw_stats { | |||
604 | u64 mgprc; | 602 | u64 mgprc; |
605 | u64 mgpdc; | 603 | u64 mgpdc; |
606 | u64 mgptc; | 604 | u64 mgptc; |
607 | u64 torl; | 605 | u64 tor; |
608 | u64 torh; | 606 | u64 tot; |
609 | u64 totl; | ||
610 | u64 toth; | ||
611 | u64 tpr; | 607 | u64 tpr; |
612 | u64 tpt; | 608 | u64 tpt; |
613 | u64 ptc64; | 609 | u64 ptc64; |
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index c8dc47fd132a..8991ab8911e2 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c | |||
@@ -46,7 +46,7 @@ | |||
46 | 46 | ||
47 | #include "e1000.h" | 47 | #include "e1000.h" |
48 | 48 | ||
49 | #define DRV_VERSION "0.2.0" | 49 | #define DRV_VERSION "0.2.1" |
50 | char e1000e_driver_name[] = "e1000e"; | 50 | char e1000e_driver_name[] = "e1000e"; |
51 | const char e1000e_driver_version[] = DRV_VERSION; | 51 | const char e1000e_driver_version[] = DRV_VERSION; |
52 | 52 | ||
@@ -466,10 +466,10 @@ next_desc: | |||
466 | if (cleaned_count) | 466 | if (cleaned_count) |
467 | adapter->alloc_rx_buf(adapter, cleaned_count); | 467 | adapter->alloc_rx_buf(adapter, cleaned_count); |
468 | 468 | ||
469 | adapter->total_rx_packets += total_rx_packets; | ||
470 | adapter->total_rx_bytes += total_rx_bytes; | 469 | adapter->total_rx_bytes += total_rx_bytes; |
471 | adapter->net_stats.rx_packets += total_rx_packets; | 470 | adapter->total_rx_packets += total_rx_packets; |
472 | adapter->net_stats.rx_bytes += total_rx_bytes; | 471 | adapter->net_stats.rx_bytes += total_rx_bytes; |
472 | adapter->net_stats.rx_packets += total_rx_packets; | ||
473 | return cleaned; | 473 | return cleaned; |
474 | } | 474 | } |
475 | 475 | ||
@@ -606,8 +606,8 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter) | |||
606 | } | 606 | } |
607 | adapter->total_tx_bytes += total_tx_bytes; | 607 | adapter->total_tx_bytes += total_tx_bytes; |
608 | adapter->total_tx_packets += total_tx_packets; | 608 | adapter->total_tx_packets += total_tx_packets; |
609 | adapter->net_stats.tx_packets += total_tx_packets; | ||
610 | adapter->net_stats.tx_bytes += total_tx_bytes; | 609 | adapter->net_stats.tx_bytes += total_tx_bytes; |
610 | adapter->net_stats.tx_packets += total_tx_packets; | ||
611 | return cleaned; | 611 | return cleaned; |
612 | } | 612 | } |
613 | 613 | ||
@@ -775,10 +775,10 @@ next_desc: | |||
775 | if (cleaned_count) | 775 | if (cleaned_count) |
776 | adapter->alloc_rx_buf(adapter, cleaned_count); | 776 | adapter->alloc_rx_buf(adapter, cleaned_count); |
777 | 777 | ||
778 | adapter->total_rx_packets += total_rx_packets; | ||
779 | adapter->total_rx_bytes += total_rx_bytes; | 778 | adapter->total_rx_bytes += total_rx_bytes; |
780 | adapter->net_stats.rx_packets += total_rx_packets; | 779 | adapter->total_rx_packets += total_rx_packets; |
781 | adapter->net_stats.rx_bytes += total_rx_bytes; | 780 | adapter->net_stats.rx_bytes += total_rx_bytes; |
781 | adapter->net_stats.rx_packets += total_rx_packets; | ||
782 | return cleaned; | 782 | return cleaned; |
783 | } | 783 | } |
784 | 784 | ||
@@ -2506,56 +2506,27 @@ void e1000e_update_stats(struct e1000_adapter *adapter) | |||
2506 | 2506 | ||
2507 | adapter->stats.crcerrs += er32(CRCERRS); | 2507 | adapter->stats.crcerrs += er32(CRCERRS); |
2508 | adapter->stats.gprc += er32(GPRC); | 2508 | adapter->stats.gprc += er32(GPRC); |
2509 | adapter->stats.gorcl += er32(GORCL); | 2509 | adapter->stats.gorc += er32(GORCL); |
2510 | adapter->stats.gorch += er32(GORCH); | 2510 | er32(GORCH); /* Clear gorc */ |
2511 | adapter->stats.bprc += er32(BPRC); | 2511 | adapter->stats.bprc += er32(BPRC); |
2512 | adapter->stats.mprc += er32(MPRC); | 2512 | adapter->stats.mprc += er32(MPRC); |
2513 | adapter->stats.roc += er32(ROC); | 2513 | adapter->stats.roc += er32(ROC); |
2514 | 2514 | ||
2515 | if (adapter->flags & FLAG_HAS_STATS_PTC_PRC) { | ||
2516 | adapter->stats.prc64 += er32(PRC64); | ||
2517 | adapter->stats.prc127 += er32(PRC127); | ||
2518 | adapter->stats.prc255 += er32(PRC255); | ||
2519 | adapter->stats.prc511 += er32(PRC511); | ||
2520 | adapter->stats.prc1023 += er32(PRC1023); | ||
2521 | adapter->stats.prc1522 += er32(PRC1522); | ||
2522 | adapter->stats.symerrs += er32(SYMERRS); | ||
2523 | adapter->stats.sec += er32(SEC); | ||
2524 | } | ||
2525 | |||
2526 | adapter->stats.mpc += er32(MPC); | 2515 | adapter->stats.mpc += er32(MPC); |
2527 | adapter->stats.scc += er32(SCC); | 2516 | adapter->stats.scc += er32(SCC); |
2528 | adapter->stats.ecol += er32(ECOL); | 2517 | adapter->stats.ecol += er32(ECOL); |
2529 | adapter->stats.mcc += er32(MCC); | 2518 | adapter->stats.mcc += er32(MCC); |
2530 | adapter->stats.latecol += er32(LATECOL); | 2519 | adapter->stats.latecol += er32(LATECOL); |
2531 | adapter->stats.dc += er32(DC); | 2520 | adapter->stats.dc += er32(DC); |
2532 | adapter->stats.rlec += er32(RLEC); | ||
2533 | adapter->stats.xonrxc += er32(XONRXC); | 2521 | adapter->stats.xonrxc += er32(XONRXC); |
2534 | adapter->stats.xontxc += er32(XONTXC); | 2522 | adapter->stats.xontxc += er32(XONTXC); |
2535 | adapter->stats.xoffrxc += er32(XOFFRXC); | 2523 | adapter->stats.xoffrxc += er32(XOFFRXC); |
2536 | adapter->stats.xofftxc += er32(XOFFTXC); | 2524 | adapter->stats.xofftxc += er32(XOFFTXC); |
2537 | adapter->stats.fcruc += er32(FCRUC); | ||
2538 | adapter->stats.gptc += er32(GPTC); | 2525 | adapter->stats.gptc += er32(GPTC); |
2539 | adapter->stats.gotcl += er32(GOTCL); | 2526 | adapter->stats.gotc += er32(GOTCL); |
2540 | adapter->stats.gotch += er32(GOTCH); | 2527 | er32(GOTCH); /* Clear gotc */ |
2541 | adapter->stats.rnbc += er32(RNBC); | 2528 | adapter->stats.rnbc += er32(RNBC); |
2542 | adapter->stats.ruc += er32(RUC); | 2529 | adapter->stats.ruc += er32(RUC); |
2543 | adapter->stats.rfc += er32(RFC); | ||
2544 | adapter->stats.rjc += er32(RJC); | ||
2545 | adapter->stats.torl += er32(TORL); | ||
2546 | adapter->stats.torh += er32(TORH); | ||
2547 | adapter->stats.totl += er32(TOTL); | ||
2548 | adapter->stats.toth += er32(TOTH); | ||
2549 | adapter->stats.tpr += er32(TPR); | ||
2550 | |||
2551 | if (adapter->flags & FLAG_HAS_STATS_PTC_PRC) { | ||
2552 | adapter->stats.ptc64 += er32(PTC64); | ||
2553 | adapter->stats.ptc127 += er32(PTC127); | ||
2554 | adapter->stats.ptc255 += er32(PTC255); | ||
2555 | adapter->stats.ptc511 += er32(PTC511); | ||
2556 | adapter->stats.ptc1023 += er32(PTC1023); | ||
2557 | adapter->stats.ptc1522 += er32(PTC1522); | ||
2558 | } | ||
2559 | 2530 | ||
2560 | adapter->stats.mptc += er32(MPTC); | 2531 | adapter->stats.mptc += er32(MPTC); |
2561 | adapter->stats.bptc += er32(BPTC); | 2532 | adapter->stats.bptc += er32(BPTC); |
@@ -2574,19 +2545,6 @@ void e1000e_update_stats(struct e1000_adapter *adapter) | |||
2574 | adapter->stats.tsctc += er32(TSCTC); | 2545 | adapter->stats.tsctc += er32(TSCTC); |
2575 | adapter->stats.tsctfc += er32(TSCTFC); | 2546 | adapter->stats.tsctfc += er32(TSCTFC); |
2576 | 2547 | ||
2577 | adapter->stats.iac += er32(IAC); | ||
2578 | |||
2579 | if (adapter->flags & FLAG_HAS_STATS_ICR_ICT) { | ||
2580 | adapter->stats.icrxoc += er32(ICRXOC); | ||
2581 | adapter->stats.icrxptc += er32(ICRXPTC); | ||
2582 | adapter->stats.icrxatc += er32(ICRXATC); | ||
2583 | adapter->stats.ictxptc += er32(ICTXPTC); | ||
2584 | adapter->stats.ictxatc += er32(ICTXATC); | ||
2585 | adapter->stats.ictxqec += er32(ICTXQEC); | ||
2586 | adapter->stats.ictxqmtc += er32(ICTXQMTC); | ||
2587 | adapter->stats.icrxdmtc += er32(ICRXDMTC); | ||
2588 | } | ||
2589 | |||
2590 | /* Fill out the OS statistics structure */ | 2548 | /* Fill out the OS statistics structure */ |
2591 | adapter->net_stats.multicast = adapter->stats.mprc; | 2549 | adapter->net_stats.multicast = adapter->stats.mprc; |
2592 | adapter->net_stats.collisions = adapter->stats.colc; | 2550 | adapter->net_stats.collisions = adapter->stats.colc; |
@@ -2633,6 +2591,54 @@ void e1000e_update_stats(struct e1000_adapter *adapter) | |||
2633 | spin_unlock_irqrestore(&adapter->stats_lock, irq_flags); | 2591 | spin_unlock_irqrestore(&adapter->stats_lock, irq_flags); |
2634 | } | 2592 | } |
2635 | 2593 | ||
2594 | /** | ||
2595 | * e1000_phy_read_status - Update the PHY register status snapshot | ||
2596 | * @adapter: board private structure | ||
2597 | **/ | ||
2598 | static void e1000_phy_read_status(struct e1000_adapter *adapter) | ||
2599 | { | ||
2600 | struct e1000_hw *hw = &adapter->hw; | ||
2601 | struct e1000_phy_regs *phy = &adapter->phy_regs; | ||
2602 | int ret_val; | ||
2603 | unsigned long irq_flags; | ||
2604 | |||
2605 | |||
2606 | spin_lock_irqsave(&adapter->stats_lock, irq_flags); | ||
2607 | |||
2608 | if ((er32(STATUS) & E1000_STATUS_LU) && | ||
2609 | (adapter->hw.phy.media_type == e1000_media_type_copper)) { | ||
2610 | ret_val = e1e_rphy(hw, PHY_CONTROL, &phy->bmcr); | ||
2611 | ret_val |= e1e_rphy(hw, PHY_STATUS, &phy->bmsr); | ||
2612 | ret_val |= e1e_rphy(hw, PHY_AUTONEG_ADV, &phy->advertise); | ||
2613 | ret_val |= e1e_rphy(hw, PHY_LP_ABILITY, &phy->lpa); | ||
2614 | ret_val |= e1e_rphy(hw, PHY_AUTONEG_EXP, &phy->expansion); | ||
2615 | ret_val |= e1e_rphy(hw, PHY_1000T_CTRL, &phy->ctrl1000); | ||
2616 | ret_val |= e1e_rphy(hw, PHY_1000T_STATUS, &phy->stat1000); | ||
2617 | ret_val |= e1e_rphy(hw, PHY_EXT_STATUS, &phy->estatus); | ||
2618 | if (ret_val) | ||
2619 | ndev_warn(adapter->netdev, | ||
2620 | "Error reading PHY register\n"); | ||
2621 | } else { | ||
2622 | /* | ||
2623 | * Do not read PHY registers if link is not up | ||
2624 | * Set values to typical power-on defaults | ||
2625 | */ | ||
2626 | phy->bmcr = (BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_FULLDPLX); | ||
2627 | phy->bmsr = (BMSR_100FULL | BMSR_100HALF | BMSR_10FULL | | ||
2628 | BMSR_10HALF | BMSR_ESTATEN | BMSR_ANEGCAPABLE | | ||
2629 | BMSR_ERCAP); | ||
2630 | phy->advertise = (ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP | | ||
2631 | ADVERTISE_ALL | ADVERTISE_CSMA); | ||
2632 | phy->lpa = 0; | ||
2633 | phy->expansion = EXPANSION_ENABLENPAGE; | ||
2634 | phy->ctrl1000 = ADVERTISE_1000FULL; | ||
2635 | phy->stat1000 = 0; | ||
2636 | phy->estatus = (ESTATUS_1000_TFULL | ESTATUS_1000_THALF); | ||
2637 | } | ||
2638 | |||
2639 | spin_unlock_irqrestore(&adapter->stats_lock, irq_flags); | ||
2640 | } | ||
2641 | |||
2636 | static void e1000_print_link_info(struct e1000_adapter *adapter) | 2642 | static void e1000_print_link_info(struct e1000_adapter *adapter) |
2637 | { | 2643 | { |
2638 | struct e1000_hw *hw = &adapter->hw; | 2644 | struct e1000_hw *hw = &adapter->hw; |
@@ -2745,6 +2751,7 @@ static void e1000_watchdog_task(struct work_struct *work) | |||
2745 | if (!netif_carrier_ok(netdev)) { | 2751 | if (!netif_carrier_ok(netdev)) { |
2746 | bool txb2b = 1; | 2752 | bool txb2b = 1; |
2747 | /* update snapshot of PHY registers on LSC */ | 2753 | /* update snapshot of PHY registers on LSC */ |
2754 | e1000_phy_read_status(adapter); | ||
2748 | mac->ops.get_link_up_info(&adapter->hw, | 2755 | mac->ops.get_link_up_info(&adapter->hw, |
2749 | &adapter->link_speed, | 2756 | &adapter->link_speed, |
2750 | &adapter->link_duplex); | 2757 | &adapter->link_duplex); |
@@ -2842,10 +2849,10 @@ link_up: | |||
2842 | mac->collision_delta = adapter->stats.colc - adapter->colc_old; | 2849 | mac->collision_delta = adapter->stats.colc - adapter->colc_old; |
2843 | adapter->colc_old = adapter->stats.colc; | 2850 | adapter->colc_old = adapter->stats.colc; |
2844 | 2851 | ||
2845 | adapter->gorcl = adapter->stats.gorcl - adapter->gorcl_old; | 2852 | adapter->gorc = adapter->stats.gorc - adapter->gorc_old; |
2846 | adapter->gorcl_old = adapter->stats.gorcl; | 2853 | adapter->gorc_old = adapter->stats.gorc; |
2847 | adapter->gotcl = adapter->stats.gotcl - adapter->gotcl_old; | 2854 | adapter->gotc = adapter->stats.gotc - adapter->gotc_old; |
2848 | adapter->gotcl_old = adapter->stats.gotcl; | 2855 | adapter->gotc_old = adapter->stats.gotc; |
2849 | 2856 | ||
2850 | e1000e_update_adaptive(&adapter->hw); | 2857 | e1000e_update_adaptive(&adapter->hw); |
2851 | 2858 | ||
@@ -3500,7 +3507,6 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, | |||
3500 | { | 3507 | { |
3501 | struct e1000_adapter *adapter = netdev_priv(netdev); | 3508 | struct e1000_adapter *adapter = netdev_priv(netdev); |
3502 | struct mii_ioctl_data *data = if_mii(ifr); | 3509 | struct mii_ioctl_data *data = if_mii(ifr); |
3503 | unsigned long irq_flags; | ||
3504 | 3510 | ||
3505 | if (adapter->hw.phy.media_type != e1000_media_type_copper) | 3511 | if (adapter->hw.phy.media_type != e1000_media_type_copper) |
3506 | return -EOPNOTSUPP; | 3512 | return -EOPNOTSUPP; |
@@ -3512,13 +3518,40 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, | |||
3512 | case SIOCGMIIREG: | 3518 | case SIOCGMIIREG: |
3513 | if (!capable(CAP_NET_ADMIN)) | 3519 | if (!capable(CAP_NET_ADMIN)) |
3514 | return -EPERM; | 3520 | return -EPERM; |
3515 | spin_lock_irqsave(&adapter->stats_lock, irq_flags); | 3521 | switch (data->reg_num & 0x1F) { |
3516 | if (e1e_rphy(&adapter->hw, data->reg_num & 0x1F, | 3522 | case MII_BMCR: |
3517 | &data->val_out)) { | 3523 | data->val_out = adapter->phy_regs.bmcr; |
3518 | spin_unlock_irqrestore(&adapter->stats_lock, irq_flags); | 3524 | break; |
3525 | case MII_BMSR: | ||
3526 | data->val_out = adapter->phy_regs.bmsr; | ||
3527 | break; | ||
3528 | case MII_PHYSID1: | ||
3529 | data->val_out = (adapter->hw.phy.id >> 16); | ||
3530 | break; | ||
3531 | case MII_PHYSID2: | ||
3532 | data->val_out = (adapter->hw.phy.id & 0xFFFF); | ||
3533 | break; | ||
3534 | case MII_ADVERTISE: | ||
3535 | data->val_out = adapter->phy_regs.advertise; | ||
3536 | break; | ||
3537 | case MII_LPA: | ||
3538 | data->val_out = adapter->phy_regs.lpa; | ||
3539 | break; | ||
3540 | case MII_EXPANSION: | ||
3541 | data->val_out = adapter->phy_regs.expansion; | ||
3542 | break; | ||
3543 | case MII_CTRL1000: | ||
3544 | data->val_out = adapter->phy_regs.ctrl1000; | ||
3545 | break; | ||
3546 | case MII_STAT1000: | ||
3547 | data->val_out = adapter->phy_regs.stat1000; | ||
3548 | break; | ||
3549 | case MII_ESTATUS: | ||
3550 | data->val_out = adapter->phy_regs.estatus; | ||
3551 | break; | ||
3552 | default: | ||
3519 | return -EIO; | 3553 | return -EIO; |
3520 | } | 3554 | } |
3521 | spin_unlock_irqrestore(&adapter->stats_lock, irq_flags); | ||
3522 | break; | 3555 | break; |
3523 | case SIOCSMIIREG: | 3556 | case SIOCSMIIREG: |
3524 | default: | 3557 | default: |
@@ -3774,6 +3807,7 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) | |||
3774 | return PCI_ERS_RESULT_DISCONNECT; | 3807 | return PCI_ERS_RESULT_DISCONNECT; |
3775 | } | 3808 | } |
3776 | pci_set_master(pdev); | 3809 | pci_set_master(pdev); |
3810 | pci_restore_state(pdev); | ||
3777 | 3811 | ||
3778 | pci_enable_wake(pdev, PCI_D3hot, 0); | 3812 | pci_enable_wake(pdev, PCI_D3hot, 0); |
3779 | pci_enable_wake(pdev, PCI_D3cold, 0); | 3813 | pci_enable_wake(pdev, PCI_D3cold, 0); |
@@ -3900,6 +3934,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, | |||
3900 | goto err_pci_reg; | 3934 | goto err_pci_reg; |
3901 | 3935 | ||
3902 | pci_set_master(pdev); | 3936 | pci_set_master(pdev); |
3937 | pci_save_state(pdev); | ||
3903 | 3938 | ||
3904 | err = -ENOMEM; | 3939 | err = -ENOMEM; |
3905 | netdev = alloc_etherdev(sizeof(struct e1000_adapter)); | 3940 | netdev = alloc_etherdev(sizeof(struct e1000_adapter)); |
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index 3a4574caa75b..e102332a6bee 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c | |||
@@ -116,7 +116,7 @@ s32 e1000e_phy_reset_dsp(struct e1000_hw *hw) | |||
116 | } | 116 | } |
117 | 117 | ||
118 | /** | 118 | /** |
119 | * e1000_read_phy_reg_mdic - Read MDI control register | 119 | * e1000e_read_phy_reg_mdic - Read MDI control register |
120 | * @hw: pointer to the HW structure | 120 | * @hw: pointer to the HW structure |
121 | * @offset: register offset to be read | 121 | * @offset: register offset to be read |
122 | * @data: pointer to the read data | 122 | * @data: pointer to the read data |
@@ -124,7 +124,7 @@ s32 e1000e_phy_reset_dsp(struct e1000_hw *hw) | |||
124 | * Reads the MDI control register in the PHY at offset and stores the | 124 | * Reads the MDI control register in the PHY at offset and stores the |
125 | * information read to data. | 125 | * information read to data. |
126 | **/ | 126 | **/ |
127 | static s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) | 127 | s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) |
128 | { | 128 | { |
129 | struct e1000_phy_info *phy = &hw->phy; | 129 | struct e1000_phy_info *phy = &hw->phy; |
130 | u32 i, mdic = 0; | 130 | u32 i, mdic = 0; |
@@ -150,7 +150,7 @@ static s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) | |||
150 | * Increasing the time out as testing showed failures with | 150 | * Increasing the time out as testing showed failures with |
151 | * the lower time out | 151 | * the lower time out |
152 | */ | 152 | */ |
153 | for (i = 0; i < 64; i++) { | 153 | for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) { |
154 | udelay(50); | 154 | udelay(50); |
155 | mdic = er32(MDIC); | 155 | mdic = er32(MDIC); |
156 | if (mdic & E1000_MDIC_READY) | 156 | if (mdic & E1000_MDIC_READY) |
@@ -170,14 +170,14 @@ static s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) | |||
170 | } | 170 | } |
171 | 171 | ||
172 | /** | 172 | /** |
173 | * e1000_write_phy_reg_mdic - Write MDI control register | 173 | * e1000e_write_phy_reg_mdic - Write MDI control register |
174 | * @hw: pointer to the HW structure | 174 | * @hw: pointer to the HW structure |
175 | * @offset: register offset to write to | 175 | * @offset: register offset to write to |
176 | * @data: data to write to register at offset | 176 | * @data: data to write to register at offset |
177 | * | 177 | * |
178 | * Writes data to MDI control register in the PHY at offset. | 178 | * Writes data to MDI control register in the PHY at offset. |
179 | **/ | 179 | **/ |
180 | static s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) | 180 | s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) |
181 | { | 181 | { |
182 | struct e1000_phy_info *phy = &hw->phy; | 182 | struct e1000_phy_info *phy = &hw->phy; |
183 | u32 i, mdic = 0; | 183 | u32 i, mdic = 0; |
@@ -199,9 +199,13 @@ static s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) | |||
199 | 199 | ||
200 | ew32(MDIC, mdic); | 200 | ew32(MDIC, mdic); |
201 | 201 | ||
202 | /* Poll the ready bit to see if the MDI read completed */ | 202 | /* |
203 | for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) { | 203 | * Poll the ready bit to see if the MDI read completed |
204 | udelay(5); | 204 | * Increasing the time out as testing showed failures with |
205 | * the lower time out | ||
206 | */ | ||
207 | for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) { | ||
208 | udelay(50); | ||
205 | mdic = er32(MDIC); | 209 | mdic = er32(MDIC); |
206 | if (mdic & E1000_MDIC_READY) | 210 | if (mdic & E1000_MDIC_READY) |
207 | break; | 211 | break; |
@@ -210,6 +214,10 @@ static s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) | |||
210 | hw_dbg(hw, "MDI Write did not complete\n"); | 214 | hw_dbg(hw, "MDI Write did not complete\n"); |
211 | return -E1000_ERR_PHY; | 215 | return -E1000_ERR_PHY; |
212 | } | 216 | } |
217 | if (mdic & E1000_MDIC_ERROR) { | ||
218 | hw_dbg(hw, "MDI Error\n"); | ||
219 | return -E1000_ERR_PHY; | ||
220 | } | ||
213 | 221 | ||
214 | return 0; | 222 | return 0; |
215 | } | 223 | } |
@@ -232,9 +240,8 @@ s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data) | |||
232 | if (ret_val) | 240 | if (ret_val) |
233 | return ret_val; | 241 | return ret_val; |
234 | 242 | ||
235 | ret_val = e1000_read_phy_reg_mdic(hw, | 243 | ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, |
236 | MAX_PHY_REG_ADDRESS & offset, | 244 | data); |
237 | data); | ||
238 | 245 | ||
239 | hw->phy.ops.release_phy(hw); | 246 | hw->phy.ops.release_phy(hw); |
240 | 247 | ||
@@ -258,9 +265,8 @@ s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data) | |||
258 | if (ret_val) | 265 | if (ret_val) |
259 | return ret_val; | 266 | return ret_val; |
260 | 267 | ||
261 | ret_val = e1000_write_phy_reg_mdic(hw, | 268 | ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, |
262 | MAX_PHY_REG_ADDRESS & offset, | 269 | data); |
263 | data); | ||
264 | 270 | ||
265 | hw->phy.ops.release_phy(hw); | 271 | hw->phy.ops.release_phy(hw); |
266 | 272 | ||
@@ -286,18 +292,17 @@ s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data) | |||
286 | return ret_val; | 292 | return ret_val; |
287 | 293 | ||
288 | if (offset > MAX_PHY_MULTI_PAGE_REG) { | 294 | if (offset > MAX_PHY_MULTI_PAGE_REG) { |
289 | ret_val = e1000_write_phy_reg_mdic(hw, | 295 | ret_val = e1000e_write_phy_reg_mdic(hw, |
290 | IGP01E1000_PHY_PAGE_SELECT, | 296 | IGP01E1000_PHY_PAGE_SELECT, |
291 | (u16)offset); | 297 | (u16)offset); |
292 | if (ret_val) { | 298 | if (ret_val) { |
293 | hw->phy.ops.release_phy(hw); | 299 | hw->phy.ops.release_phy(hw); |
294 | return ret_val; | 300 | return ret_val; |
295 | } | 301 | } |
296 | } | 302 | } |
297 | 303 | ||
298 | ret_val = e1000_read_phy_reg_mdic(hw, | 304 | ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, |
299 | MAX_PHY_REG_ADDRESS & offset, | 305 | data); |
300 | data); | ||
301 | 306 | ||
302 | hw->phy.ops.release_phy(hw); | 307 | hw->phy.ops.release_phy(hw); |
303 | 308 | ||
@@ -322,18 +327,17 @@ s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data) | |||
322 | return ret_val; | 327 | return ret_val; |
323 | 328 | ||
324 | if (offset > MAX_PHY_MULTI_PAGE_REG) { | 329 | if (offset > MAX_PHY_MULTI_PAGE_REG) { |
325 | ret_val = e1000_write_phy_reg_mdic(hw, | 330 | ret_val = e1000e_write_phy_reg_mdic(hw, |
326 | IGP01E1000_PHY_PAGE_SELECT, | 331 | IGP01E1000_PHY_PAGE_SELECT, |
327 | (u16)offset); | 332 | (u16)offset); |
328 | if (ret_val) { | 333 | if (ret_val) { |
329 | hw->phy.ops.release_phy(hw); | 334 | hw->phy.ops.release_phy(hw); |
330 | return ret_val; | 335 | return ret_val; |
331 | } | 336 | } |
332 | } | 337 | } |
333 | 338 | ||
334 | ret_val = e1000_write_phy_reg_mdic(hw, | 339 | ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, |
335 | MAX_PHY_REG_ADDRESS & offset, | 340 | data); |
336 | data); | ||
337 | 341 | ||
338 | hw->phy.ops.release_phy(hw); | 342 | hw->phy.ops.release_phy(hw); |
339 | 343 | ||
@@ -420,7 +424,9 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw) | |||
420 | if (ret_val) | 424 | if (ret_val) |
421 | return ret_val; | 425 | return ret_val; |
422 | 426 | ||
423 | phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; | 427 | /* For newer PHYs this bit is downshift enable */ |
428 | if (phy->type == e1000_phy_m88) | ||
429 | phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; | ||
424 | 430 | ||
425 | /* | 431 | /* |
426 | * Options: | 432 | * Options: |
@@ -463,7 +469,7 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw) | |||
463 | if (ret_val) | 469 | if (ret_val) |
464 | return ret_val; | 470 | return ret_val; |
465 | 471 | ||
466 | if (phy->revision < 4) { | 472 | if ((phy->type == e1000_phy_m88) && (phy->revision < 4)) { |
467 | /* | 473 | /* |
468 | * Force TX_CLK in the Extended PHY Specific Control Register | 474 | * Force TX_CLK in the Extended PHY Specific Control Register |
469 | * to 25MHz clock. | 475 | * to 25MHz clock. |
@@ -518,8 +524,11 @@ s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw) | |||
518 | return ret_val; | 524 | return ret_val; |
519 | } | 525 | } |
520 | 526 | ||
521 | /* Wait 15ms for MAC to configure PHY from NVM settings. */ | 527 | /* |
522 | msleep(15); | 528 | * Wait 100ms for MAC to configure PHY from NVM settings, to avoid |
529 | * timeout issues when LFS is enabled. | ||
530 | */ | ||
531 | msleep(100); | ||
523 | 532 | ||
524 | /* disable lplu d0 during driver init */ | 533 | /* disable lplu d0 during driver init */ |
525 | ret_val = e1000_set_d0_lplu_state(hw, 0); | 534 | ret_val = e1000_set_d0_lplu_state(hw, 0); |
@@ -1152,9 +1161,7 @@ s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active) | |||
1152 | 1161 | ||
1153 | if (!active) { | 1162 | if (!active) { |
1154 | data &= ~IGP02E1000_PM_D3_LPLU; | 1163 | data &= ~IGP02E1000_PM_D3_LPLU; |
1155 | ret_val = e1e_wphy(hw, | 1164 | ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data); |
1156 | IGP02E1000_PHY_POWER_MGMT, | ||
1157 | data); | ||
1158 | if (ret_val) | 1165 | if (ret_val) |
1159 | return ret_val; | 1166 | return ret_val; |
1160 | /* | 1167 | /* |
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 9ff7538b7595..f9bc21c74b59 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c | |||
@@ -2611,7 +2611,7 @@ static int ehea_stop(struct net_device *dev) | |||
2611 | return ret; | 2611 | return ret; |
2612 | } | 2612 | } |
2613 | 2613 | ||
2614 | void ehea_purge_sq(struct ehea_qp *orig_qp) | 2614 | static void ehea_purge_sq(struct ehea_qp *orig_qp) |
2615 | { | 2615 | { |
2616 | struct ehea_qp qp = *orig_qp; | 2616 | struct ehea_qp qp = *orig_qp; |
2617 | struct ehea_qp_init_attr *init_attr = &qp.init_attr; | 2617 | struct ehea_qp_init_attr *init_attr = &qp.init_attr; |
@@ -2625,7 +2625,7 @@ void ehea_purge_sq(struct ehea_qp *orig_qp) | |||
2625 | } | 2625 | } |
2626 | } | 2626 | } |
2627 | 2627 | ||
2628 | void ehea_flush_sq(struct ehea_port *port) | 2628 | static void ehea_flush_sq(struct ehea_port *port) |
2629 | { | 2629 | { |
2630 | int i; | 2630 | int i; |
2631 | 2631 | ||
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 8c4214b0ee1f..35f66d4a4595 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c | |||
@@ -96,6 +96,7 @@ | |||
96 | #define DEV_HAS_PAUSEFRAME_TX_V2 0x10000 /* device supports tx pause frames version 2 */ | 96 | #define DEV_HAS_PAUSEFRAME_TX_V2 0x10000 /* device supports tx pause frames version 2 */ |
97 | #define DEV_HAS_PAUSEFRAME_TX_V3 0x20000 /* device supports tx pause frames version 3 */ | 97 | #define DEV_HAS_PAUSEFRAME_TX_V3 0x20000 /* device supports tx pause frames version 3 */ |
98 | #define DEV_NEED_TX_LIMIT 0x40000 /* device needs to limit tx */ | 98 | #define DEV_NEED_TX_LIMIT 0x40000 /* device needs to limit tx */ |
99 | #define DEV_HAS_GEAR_MODE 0x80000 /* device supports gear mode */ | ||
99 | 100 | ||
100 | enum { | 101 | enum { |
101 | NvRegIrqStatus = 0x000, | 102 | NvRegIrqStatus = 0x000, |
@@ -174,11 +175,13 @@ enum { | |||
174 | NvRegReceiverStatus = 0x98, | 175 | NvRegReceiverStatus = 0x98, |
175 | #define NVREG_RCVSTAT_BUSY 0x01 | 176 | #define NVREG_RCVSTAT_BUSY 0x01 |
176 | 177 | ||
177 | NvRegRandomSeed = 0x9c, | 178 | NvRegSlotTime = 0x9c, |
178 | #define NVREG_RNDSEED_MASK 0x00ff | 179 | #define NVREG_SLOTTIME_LEGBF_ENABLED 0x80000000 |
179 | #define NVREG_RNDSEED_FORCE 0x7f00 | 180 | #define NVREG_SLOTTIME_10_100_FULL 0x00007f00 |
180 | #define NVREG_RNDSEED_FORCE2 0x2d00 | 181 | #define NVREG_SLOTTIME_1000_FULL 0x0003ff00 |
181 | #define NVREG_RNDSEED_FORCE3 0x7400 | 182 | #define NVREG_SLOTTIME_HALF 0x0000ff00 |
183 | #define NVREG_SLOTTIME_DEFAULT 0x00007f00 | ||
184 | #define NVREG_SLOTTIME_MASK 0x000000ff | ||
182 | 185 | ||
183 | NvRegTxDeferral = 0xA0, | 186 | NvRegTxDeferral = 0xA0, |
184 | #define NVREG_TX_DEFERRAL_DEFAULT 0x15050f | 187 | #define NVREG_TX_DEFERRAL_DEFAULT 0x15050f |
@@ -201,6 +204,11 @@ enum { | |||
201 | 204 | ||
202 | NvRegPhyInterface = 0xC0, | 205 | NvRegPhyInterface = 0xC0, |
203 | #define PHY_RGMII 0x10000000 | 206 | #define PHY_RGMII 0x10000000 |
207 | NvRegBackOffControl = 0xC4, | ||
208 | #define NVREG_BKOFFCTRL_DEFAULT 0x70000000 | ||
209 | #define NVREG_BKOFFCTRL_SEED_MASK 0x000003ff | ||
210 | #define NVREG_BKOFFCTRL_SELECT 24 | ||
211 | #define NVREG_BKOFFCTRL_GEAR 12 | ||
204 | 212 | ||
205 | NvRegTxRingPhysAddr = 0x100, | 213 | NvRegTxRingPhysAddr = 0x100, |
206 | NvRegRxRingPhysAddr = 0x104, | 214 | NvRegRxRingPhysAddr = 0x104, |
@@ -352,6 +360,7 @@ union ring_type { | |||
352 | 360 | ||
353 | #define NV_TX_LASTPACKET (1<<16) | 361 | #define NV_TX_LASTPACKET (1<<16) |
354 | #define NV_TX_RETRYERROR (1<<19) | 362 | #define NV_TX_RETRYERROR (1<<19) |
363 | #define NV_TX_RETRYCOUNT_MASK (0xF<<20) | ||
355 | #define NV_TX_FORCED_INTERRUPT (1<<24) | 364 | #define NV_TX_FORCED_INTERRUPT (1<<24) |
356 | #define NV_TX_DEFERRED (1<<26) | 365 | #define NV_TX_DEFERRED (1<<26) |
357 | #define NV_TX_CARRIERLOST (1<<27) | 366 | #define NV_TX_CARRIERLOST (1<<27) |
@@ -362,6 +371,7 @@ union ring_type { | |||
362 | 371 | ||
363 | #define NV_TX2_LASTPACKET (1<<29) | 372 | #define NV_TX2_LASTPACKET (1<<29) |
364 | #define NV_TX2_RETRYERROR (1<<18) | 373 | #define NV_TX2_RETRYERROR (1<<18) |
374 | #define NV_TX2_RETRYCOUNT_MASK (0xF<<19) | ||
365 | #define NV_TX2_FORCED_INTERRUPT (1<<30) | 375 | #define NV_TX2_FORCED_INTERRUPT (1<<30) |
366 | #define NV_TX2_DEFERRED (1<<25) | 376 | #define NV_TX2_DEFERRED (1<<25) |
367 | #define NV_TX2_CARRIERLOST (1<<26) | 377 | #define NV_TX2_CARRIERLOST (1<<26) |
@@ -473,16 +483,22 @@ union ring_type { | |||
473 | #define DESC_VER_3 3 | 483 | #define DESC_VER_3 3 |
474 | 484 | ||
475 | /* PHY defines */ | 485 | /* PHY defines */ |
476 | #define PHY_OUI_MARVELL 0x5043 | 486 | #define PHY_OUI_MARVELL 0x5043 |
477 | #define PHY_OUI_CICADA 0x03f1 | 487 | #define PHY_OUI_CICADA 0x03f1 |
478 | #define PHY_OUI_VITESSE 0x01c1 | 488 | #define PHY_OUI_VITESSE 0x01c1 |
479 | #define PHY_OUI_REALTEK 0x0732 | 489 | #define PHY_OUI_REALTEK 0x0732 |
490 | #define PHY_OUI_REALTEK2 0x0020 | ||
480 | #define PHYID1_OUI_MASK 0x03ff | 491 | #define PHYID1_OUI_MASK 0x03ff |
481 | #define PHYID1_OUI_SHFT 6 | 492 | #define PHYID1_OUI_SHFT 6 |
482 | #define PHYID2_OUI_MASK 0xfc00 | 493 | #define PHYID2_OUI_MASK 0xfc00 |
483 | #define PHYID2_OUI_SHFT 10 | 494 | #define PHYID2_OUI_SHFT 10 |
484 | #define PHYID2_MODEL_MASK 0x03f0 | 495 | #define PHYID2_MODEL_MASK 0x03f0 |
485 | #define PHY_MODEL_MARVELL_E3016 0x220 | 496 | #define PHY_MODEL_REALTEK_8211 0x0110 |
497 | #define PHY_REV_MASK 0x0001 | ||
498 | #define PHY_REV_REALTEK_8211B 0x0000 | ||
499 | #define PHY_REV_REALTEK_8211C 0x0001 | ||
500 | #define PHY_MODEL_REALTEK_8201 0x0200 | ||
501 | #define PHY_MODEL_MARVELL_E3016 0x0220 | ||
486 | #define PHY_MARVELL_E3016_INITMASK 0x0300 | 502 | #define PHY_MARVELL_E3016_INITMASK 0x0300 |
487 | #define PHY_CICADA_INIT1 0x0f000 | 503 | #define PHY_CICADA_INIT1 0x0f000 |
488 | #define PHY_CICADA_INIT2 0x0e00 | 504 | #define PHY_CICADA_INIT2 0x0e00 |
@@ -509,10 +525,18 @@ union ring_type { | |||
509 | #define PHY_REALTEK_INIT_REG1 0x1f | 525 | #define PHY_REALTEK_INIT_REG1 0x1f |
510 | #define PHY_REALTEK_INIT_REG2 0x19 | 526 | #define PHY_REALTEK_INIT_REG2 0x19 |
511 | #define PHY_REALTEK_INIT_REG3 0x13 | 527 | #define PHY_REALTEK_INIT_REG3 0x13 |
528 | #define PHY_REALTEK_INIT_REG4 0x14 | ||
529 | #define PHY_REALTEK_INIT_REG5 0x18 | ||
530 | #define PHY_REALTEK_INIT_REG6 0x11 | ||
512 | #define PHY_REALTEK_INIT1 0x0000 | 531 | #define PHY_REALTEK_INIT1 0x0000 |
513 | #define PHY_REALTEK_INIT2 0x8e00 | 532 | #define PHY_REALTEK_INIT2 0x8e00 |
514 | #define PHY_REALTEK_INIT3 0x0001 | 533 | #define PHY_REALTEK_INIT3 0x0001 |
515 | #define PHY_REALTEK_INIT4 0xad17 | 534 | #define PHY_REALTEK_INIT4 0xad17 |
535 | #define PHY_REALTEK_INIT5 0xfb54 | ||
536 | #define PHY_REALTEK_INIT6 0xf5c7 | ||
537 | #define PHY_REALTEK_INIT7 0x1000 | ||
538 | #define PHY_REALTEK_INIT8 0x0003 | ||
539 | #define PHY_REALTEK_INIT_MSK1 0x0003 | ||
516 | 540 | ||
517 | #define PHY_GIGABIT 0x0100 | 541 | #define PHY_GIGABIT 0x0100 |
518 | 542 | ||
@@ -691,6 +715,7 @@ struct fe_priv { | |||
691 | int wolenabled; | 715 | int wolenabled; |
692 | unsigned int phy_oui; | 716 | unsigned int phy_oui; |
693 | unsigned int phy_model; | 717 | unsigned int phy_model; |
718 | unsigned int phy_rev; | ||
694 | u16 gigabit; | 719 | u16 gigabit; |
695 | int intr_test; | 720 | int intr_test; |
696 | int recover_error; | 721 | int recover_error; |
@@ -704,6 +729,7 @@ struct fe_priv { | |||
704 | u32 txrxctl_bits; | 729 | u32 txrxctl_bits; |
705 | u32 vlanctl_bits; | 730 | u32 vlanctl_bits; |
706 | u32 driver_data; | 731 | u32 driver_data; |
732 | u32 device_id; | ||
707 | u32 register_size; | 733 | u32 register_size; |
708 | int rx_csum; | 734 | int rx_csum; |
709 | u32 mac_in_use; | 735 | u32 mac_in_use; |
@@ -814,6 +840,16 @@ enum { | |||
814 | }; | 840 | }; |
815 | static int dma_64bit = NV_DMA_64BIT_ENABLED; | 841 | static int dma_64bit = NV_DMA_64BIT_ENABLED; |
816 | 842 | ||
843 | /* | ||
844 | * Crossover Detection | ||
845 | * Realtek 8201 phy + some OEM boards do not work properly. | ||
846 | */ | ||
847 | enum { | ||
848 | NV_CROSSOVER_DETECTION_DISABLED, | ||
849 | NV_CROSSOVER_DETECTION_ENABLED | ||
850 | }; | ||
851 | static int phy_cross = NV_CROSSOVER_DETECTION_DISABLED; | ||
852 | |||
817 | static inline struct fe_priv *get_nvpriv(struct net_device *dev) | 853 | static inline struct fe_priv *get_nvpriv(struct net_device *dev) |
818 | { | 854 | { |
819 | return netdev_priv(dev); | 855 | return netdev_priv(dev); |
@@ -1078,25 +1114,53 @@ static int phy_init(struct net_device *dev) | |||
1078 | } | 1114 | } |
1079 | } | 1115 | } |
1080 | if (np->phy_oui == PHY_OUI_REALTEK) { | 1116 | if (np->phy_oui == PHY_OUI_REALTEK) { |
1081 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) { | 1117 | if (np->phy_model == PHY_MODEL_REALTEK_8211 && |
1082 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | 1118 | np->phy_rev == PHY_REV_REALTEK_8211B) { |
1083 | return PHY_ERROR; | 1119 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) { |
1084 | } | 1120 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); |
1085 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) { | 1121 | return PHY_ERROR; |
1086 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | 1122 | } |
1087 | return PHY_ERROR; | 1123 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) { |
1088 | } | 1124 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); |
1089 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) { | 1125 | return PHY_ERROR; |
1090 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | 1126 | } |
1091 | return PHY_ERROR; | 1127 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) { |
1092 | } | 1128 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); |
1093 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) { | 1129 | return PHY_ERROR; |
1094 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | 1130 | } |
1095 | return PHY_ERROR; | 1131 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) { |
1132 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | ||
1133 | return PHY_ERROR; | ||
1134 | } | ||
1135 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG4, PHY_REALTEK_INIT5)) { | ||
1136 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | ||
1137 | return PHY_ERROR; | ||
1138 | } | ||
1139 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG5, PHY_REALTEK_INIT6)) { | ||
1140 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | ||
1141 | return PHY_ERROR; | ||
1142 | } | ||
1143 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) { | ||
1144 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | ||
1145 | return PHY_ERROR; | ||
1146 | } | ||
1096 | } | 1147 | } |
1097 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) { | 1148 | if (np->phy_model == PHY_MODEL_REALTEK_8201) { |
1098 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | 1149 | if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 || |
1099 | return PHY_ERROR; | 1150 | np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 || |
1151 | np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_34 || | ||
1152 | np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_35 || | ||
1153 | np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_36 || | ||
1154 | np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_37 || | ||
1155 | np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_38 || | ||
1156 | np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_39) { | ||
1157 | phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ); | ||
1158 | phy_reserved |= PHY_REALTEK_INIT7; | ||
1159 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, phy_reserved)) { | ||
1160 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | ||
1161 | return PHY_ERROR; | ||
1162 | } | ||
1163 | } | ||
1100 | } | 1164 | } |
1101 | } | 1165 | } |
1102 | 1166 | ||
@@ -1236,26 +1300,71 @@ static int phy_init(struct net_device *dev) | |||
1236 | } | 1300 | } |
1237 | } | 1301 | } |
1238 | if (np->phy_oui == PHY_OUI_REALTEK) { | 1302 | if (np->phy_oui == PHY_OUI_REALTEK) { |
1239 | /* reset could have cleared these out, set them back */ | 1303 | if (np->phy_model == PHY_MODEL_REALTEK_8211 && |
1240 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) { | 1304 | np->phy_rev == PHY_REV_REALTEK_8211B) { |
1241 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | 1305 | /* reset could have cleared these out, set them back */ |
1242 | return PHY_ERROR; | 1306 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) { |
1243 | } | 1307 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); |
1244 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) { | 1308 | return PHY_ERROR; |
1245 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | 1309 | } |
1246 | return PHY_ERROR; | 1310 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, PHY_REALTEK_INIT2)) { |
1247 | } | 1311 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); |
1248 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) { | 1312 | return PHY_ERROR; |
1249 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | 1313 | } |
1250 | return PHY_ERROR; | 1314 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) { |
1251 | } | 1315 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); |
1252 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) { | 1316 | return PHY_ERROR; |
1253 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | 1317 | } |
1254 | return PHY_ERROR; | 1318 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG3, PHY_REALTEK_INIT4)) { |
1319 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | ||
1320 | return PHY_ERROR; | ||
1321 | } | ||
1322 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG4, PHY_REALTEK_INIT5)) { | ||
1323 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | ||
1324 | return PHY_ERROR; | ||
1325 | } | ||
1326 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG5, PHY_REALTEK_INIT6)) { | ||
1327 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | ||
1328 | return PHY_ERROR; | ||
1329 | } | ||
1330 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) { | ||
1331 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | ||
1332 | return PHY_ERROR; | ||
1333 | } | ||
1255 | } | 1334 | } |
1256 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) { | 1335 | if (np->phy_model == PHY_MODEL_REALTEK_8201) { |
1257 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | 1336 | if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 || |
1258 | return PHY_ERROR; | 1337 | np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 || |
1338 | np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_34 || | ||
1339 | np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_35 || | ||
1340 | np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_36 || | ||
1341 | np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_37 || | ||
1342 | np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_38 || | ||
1343 | np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_39) { | ||
1344 | phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ); | ||
1345 | phy_reserved |= PHY_REALTEK_INIT7; | ||
1346 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, phy_reserved)) { | ||
1347 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | ||
1348 | return PHY_ERROR; | ||
1349 | } | ||
1350 | } | ||
1351 | if (phy_cross == NV_CROSSOVER_DETECTION_DISABLED) { | ||
1352 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3)) { | ||
1353 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | ||
1354 | return PHY_ERROR; | ||
1355 | } | ||
1356 | phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, MII_READ); | ||
1357 | phy_reserved &= ~PHY_REALTEK_INIT_MSK1; | ||
1358 | phy_reserved |= PHY_REALTEK_INIT3; | ||
1359 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, phy_reserved)) { | ||
1360 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | ||
1361 | return PHY_ERROR; | ||
1362 | } | ||
1363 | if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1)) { | ||
1364 | printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); | ||
1365 | return PHY_ERROR; | ||
1366 | } | ||
1367 | } | ||
1259 | } | 1368 | } |
1260 | } | 1369 | } |
1261 | 1370 | ||
@@ -1769,6 +1878,115 @@ static inline u32 nv_get_empty_tx_slots(struct fe_priv *np) | |||
1769 | return (u32)(np->tx_ring_size - ((np->tx_ring_size + (np->put_tx_ctx - np->get_tx_ctx)) % np->tx_ring_size)); | 1878 | return (u32)(np->tx_ring_size - ((np->tx_ring_size + (np->put_tx_ctx - np->get_tx_ctx)) % np->tx_ring_size)); |
1770 | } | 1879 | } |
1771 | 1880 | ||
1881 | static void nv_legacybackoff_reseed(struct net_device *dev) | ||
1882 | { | ||
1883 | u8 __iomem *base = get_hwbase(dev); | ||
1884 | u32 reg; | ||
1885 | u32 low; | ||
1886 | int tx_status = 0; | ||
1887 | |||
1888 | reg = readl(base + NvRegSlotTime) & ~NVREG_SLOTTIME_MASK; | ||
1889 | get_random_bytes(&low, sizeof(low)); | ||
1890 | reg |= low & NVREG_SLOTTIME_MASK; | ||
1891 | |||
1892 | /* Need to stop tx before change takes effect. | ||
1893 | * Caller has already gained np->lock. | ||
1894 | */ | ||
1895 | tx_status = readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_START; | ||
1896 | if (tx_status) | ||
1897 | nv_stop_tx(dev); | ||
1898 | nv_stop_rx(dev); | ||
1899 | writel(reg, base + NvRegSlotTime); | ||
1900 | if (tx_status) | ||
1901 | nv_start_tx(dev); | ||
1902 | nv_start_rx(dev); | ||
1903 | } | ||
1904 | |||
1905 | /* Gear Backoff Seeds */ | ||
1906 | #define BACKOFF_SEEDSET_ROWS 8 | ||
1907 | #define BACKOFF_SEEDSET_LFSRS 15 | ||
1908 | |||
1909 | /* Known Good seed sets */ | ||
1910 | static const u32 main_seedset[BACKOFF_SEEDSET_ROWS][BACKOFF_SEEDSET_LFSRS] = { | ||
1911 | {145, 155, 165, 175, 185, 196, 235, 245, 255, 265, 275, 285, 660, 690, 874}, | ||
1912 | {245, 255, 265, 575, 385, 298, 335, 345, 355, 366, 375, 385, 761, 790, 974}, | ||
1913 | {145, 155, 165, 175, 185, 196, 235, 245, 255, 265, 275, 285, 660, 690, 874}, | ||
1914 | {245, 255, 265, 575, 385, 298, 335, 345, 355, 366, 375, 386, 761, 790, 974}, | ||
1915 | {266, 265, 276, 585, 397, 208, 345, 355, 365, 376, 385, 396, 771, 700, 984}, | ||
1916 | {266, 265, 276, 586, 397, 208, 346, 355, 365, 376, 285, 396, 771, 700, 984}, | ||
1917 | {366, 365, 376, 686, 497, 308, 447, 455, 466, 476, 485, 496, 871, 800, 84}, | ||
1918 | {466, 465, 476, 786, 597, 408, 547, 555, 566, 576, 585, 597, 971, 900, 184}}; | ||
1919 | |||
1920 | static const u32 gear_seedset[BACKOFF_SEEDSET_ROWS][BACKOFF_SEEDSET_LFSRS] = { | ||
1921 | {251, 262, 273, 324, 319, 508, 375, 364, 341, 371, 398, 193, 375, 30, 295}, | ||
1922 | {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395}, | ||
1923 | {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 397}, | ||
1924 | {251, 262, 273, 324, 319, 508, 375, 364, 341, 371, 398, 193, 375, 30, 295}, | ||
1925 | {251, 262, 273, 324, 319, 508, 375, 364, 341, 371, 398, 193, 375, 30, 295}, | ||
1926 | {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395}, | ||
1927 | {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395}, | ||
1928 | {351, 375, 373, 469, 551, 639, 477, 464, 441, 472, 498, 293, 476, 130, 395}}; | ||
1929 | |||
1930 | static void nv_gear_backoff_reseed(struct net_device *dev) | ||
1931 | { | ||
1932 | u8 __iomem *base = get_hwbase(dev); | ||
1933 | u32 miniseed1, miniseed2, miniseed2_reversed, miniseed3, miniseed3_reversed; | ||
1934 | u32 temp, seedset, combinedSeed; | ||
1935 | int i; | ||
1936 | |||
1937 | /* Setup seed for free running LFSR */ | ||
1938 | /* We are going to read the time stamp counter 3 times | ||
1939 | and swizzle bits around to increase randomness */ | ||
1940 | get_random_bytes(&miniseed1, sizeof(miniseed1)); | ||
1941 | miniseed1 &= 0x0fff; | ||
1942 | if (miniseed1 == 0) | ||
1943 | miniseed1 = 0xabc; | ||
1944 | |||
1945 | get_random_bytes(&miniseed2, sizeof(miniseed2)); | ||
1946 | miniseed2 &= 0x0fff; | ||
1947 | if (miniseed2 == 0) | ||
1948 | miniseed2 = 0xabc; | ||
1949 | miniseed2_reversed = | ||
1950 | ((miniseed2 & 0xF00) >> 8) | | ||
1951 | (miniseed2 & 0x0F0) | | ||
1952 | ((miniseed2 & 0x00F) << 8); | ||
1953 | |||
1954 | get_random_bytes(&miniseed3, sizeof(miniseed3)); | ||
1955 | miniseed3 &= 0x0fff; | ||
1956 | if (miniseed3 == 0) | ||
1957 | miniseed3 = 0xabc; | ||
1958 | miniseed3_reversed = | ||
1959 | ((miniseed3 & 0xF00) >> 8) | | ||
1960 | (miniseed3 & 0x0F0) | | ||
1961 | ((miniseed3 & 0x00F) << 8); | ||
1962 | |||
1963 | combinedSeed = ((miniseed1 ^ miniseed2_reversed) << 12) | | ||
1964 | (miniseed2 ^ miniseed3_reversed); | ||
1965 | |||
1966 | /* Seeds can not be zero */ | ||
1967 | if ((combinedSeed & NVREG_BKOFFCTRL_SEED_MASK) == 0) | ||
1968 | combinedSeed |= 0x08; | ||
1969 | if ((combinedSeed & (NVREG_BKOFFCTRL_SEED_MASK << NVREG_BKOFFCTRL_GEAR)) == 0) | ||
1970 | combinedSeed |= 0x8000; | ||
1971 | |||
1972 | /* No need to disable tx here */ | ||
1973 | temp = NVREG_BKOFFCTRL_DEFAULT | (0 << NVREG_BKOFFCTRL_SELECT); | ||
1974 | temp |= combinedSeed & NVREG_BKOFFCTRL_SEED_MASK; | ||
1975 | temp |= combinedSeed >> NVREG_BKOFFCTRL_GEAR; | ||
1976 | writel(temp,base + NvRegBackOffControl); | ||
1977 | |||
1978 | /* Setup seeds for all gear LFSRs. */ | ||
1979 | get_random_bytes(&seedset, sizeof(seedset)); | ||
1980 | seedset = seedset % BACKOFF_SEEDSET_ROWS; | ||
1981 | for (i = 1; i <= BACKOFF_SEEDSET_LFSRS; i++) | ||
1982 | { | ||
1983 | temp = NVREG_BKOFFCTRL_DEFAULT | (i << NVREG_BKOFFCTRL_SELECT); | ||
1984 | temp |= main_seedset[seedset][i-1] & 0x3ff; | ||
1985 | temp |= ((gear_seedset[seedset][i-1] & 0x3ff) << NVREG_BKOFFCTRL_GEAR); | ||
1986 | writel(temp, base + NvRegBackOffControl); | ||
1987 | } | ||
1988 | } | ||
1989 | |||
1772 | /* | 1990 | /* |
1773 | * nv_start_xmit: dev->hard_start_xmit function | 1991 | * nv_start_xmit: dev->hard_start_xmit function |
1774 | * Called with netif_tx_lock held. | 1992 | * Called with netif_tx_lock held. |
@@ -2088,6 +2306,8 @@ static void nv_tx_done(struct net_device *dev) | |||
2088 | dev->stats.tx_fifo_errors++; | 2306 | dev->stats.tx_fifo_errors++; |
2089 | if (flags & NV_TX_CARRIERLOST) | 2307 | if (flags & NV_TX_CARRIERLOST) |
2090 | dev->stats.tx_carrier_errors++; | 2308 | dev->stats.tx_carrier_errors++; |
2309 | if ((flags & NV_TX_RETRYERROR) && !(flags & NV_TX_RETRYCOUNT_MASK)) | ||
2310 | nv_legacybackoff_reseed(dev); | ||
2091 | dev->stats.tx_errors++; | 2311 | dev->stats.tx_errors++; |
2092 | } else { | 2312 | } else { |
2093 | dev->stats.tx_packets++; | 2313 | dev->stats.tx_packets++; |
@@ -2103,6 +2323,8 @@ static void nv_tx_done(struct net_device *dev) | |||
2103 | dev->stats.tx_fifo_errors++; | 2323 | dev->stats.tx_fifo_errors++; |
2104 | if (flags & NV_TX2_CARRIERLOST) | 2324 | if (flags & NV_TX2_CARRIERLOST) |
2105 | dev->stats.tx_carrier_errors++; | 2325 | dev->stats.tx_carrier_errors++; |
2326 | if ((flags & NV_TX2_RETRYERROR) && !(flags & NV_TX2_RETRYCOUNT_MASK)) | ||
2327 | nv_legacybackoff_reseed(dev); | ||
2106 | dev->stats.tx_errors++; | 2328 | dev->stats.tx_errors++; |
2107 | } else { | 2329 | } else { |
2108 | dev->stats.tx_packets++; | 2330 | dev->stats.tx_packets++; |
@@ -2144,6 +2366,15 @@ static void nv_tx_done_optimized(struct net_device *dev, int limit) | |||
2144 | if (flags & NV_TX2_LASTPACKET) { | 2366 | if (flags & NV_TX2_LASTPACKET) { |
2145 | if (!(flags & NV_TX2_ERROR)) | 2367 | if (!(flags & NV_TX2_ERROR)) |
2146 | dev->stats.tx_packets++; | 2368 | dev->stats.tx_packets++; |
2369 | else { | ||
2370 | if ((flags & NV_TX2_RETRYERROR) && !(flags & NV_TX2_RETRYCOUNT_MASK)) { | ||
2371 | if (np->driver_data & DEV_HAS_GEAR_MODE) | ||
2372 | nv_gear_backoff_reseed(dev); | ||
2373 | else | ||
2374 | nv_legacybackoff_reseed(dev); | ||
2375 | } | ||
2376 | } | ||
2377 | |||
2147 | dev_kfree_skb_any(np->get_tx_ctx->skb); | 2378 | dev_kfree_skb_any(np->get_tx_ctx->skb); |
2148 | np->get_tx_ctx->skb = NULL; | 2379 | np->get_tx_ctx->skb = NULL; |
2149 | 2380 | ||
@@ -2905,15 +3136,14 @@ set_speed: | |||
2905 | } | 3136 | } |
2906 | 3137 | ||
2907 | if (np->gigabit == PHY_GIGABIT) { | 3138 | if (np->gigabit == PHY_GIGABIT) { |
2908 | phyreg = readl(base + NvRegRandomSeed); | 3139 | phyreg = readl(base + NvRegSlotTime); |
2909 | phyreg &= ~(0x3FF00); | 3140 | phyreg &= ~(0x3FF00); |
2910 | if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_10) | 3141 | if (((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_10) || |
2911 | phyreg |= NVREG_RNDSEED_FORCE3; | 3142 | ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100)) |
2912 | else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100) | 3143 | phyreg |= NVREG_SLOTTIME_10_100_FULL; |
2913 | phyreg |= NVREG_RNDSEED_FORCE2; | ||
2914 | else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000) | 3144 | else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000) |
2915 | phyreg |= NVREG_RNDSEED_FORCE; | 3145 | phyreg |= NVREG_SLOTTIME_1000_FULL; |
2916 | writel(phyreg, base + NvRegRandomSeed); | 3146 | writel(phyreg, base + NvRegSlotTime); |
2917 | } | 3147 | } |
2918 | 3148 | ||
2919 | phyreg = readl(base + NvRegPhyInterface); | 3149 | phyreg = readl(base + NvRegPhyInterface); |
@@ -4843,6 +5073,7 @@ static int nv_open(struct net_device *dev) | |||
4843 | u8 __iomem *base = get_hwbase(dev); | 5073 | u8 __iomem *base = get_hwbase(dev); |
4844 | int ret = 1; | 5074 | int ret = 1; |
4845 | int oom, i; | 5075 | int oom, i; |
5076 | u32 low; | ||
4846 | 5077 | ||
4847 | dprintk(KERN_DEBUG "nv_open: begin\n"); | 5078 | dprintk(KERN_DEBUG "nv_open: begin\n"); |
4848 | 5079 | ||
@@ -4902,8 +5133,20 @@ static int nv_open(struct net_device *dev) | |||
4902 | writel(np->rx_buf_sz, base + NvRegOffloadConfig); | 5133 | writel(np->rx_buf_sz, base + NvRegOffloadConfig); |
4903 | 5134 | ||
4904 | writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus); | 5135 | writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus); |
4905 | get_random_bytes(&i, sizeof(i)); | 5136 | |
4906 | writel(NVREG_RNDSEED_FORCE | (i&NVREG_RNDSEED_MASK), base + NvRegRandomSeed); | 5137 | get_random_bytes(&low, sizeof(low)); |
5138 | low &= NVREG_SLOTTIME_MASK; | ||
5139 | if (np->desc_ver == DESC_VER_1) { | ||
5140 | writel(low|NVREG_SLOTTIME_DEFAULT, base + NvRegSlotTime); | ||
5141 | } else { | ||
5142 | if (!(np->driver_data & DEV_HAS_GEAR_MODE)) { | ||
5143 | /* setup legacy backoff */ | ||
5144 | writel(NVREG_SLOTTIME_LEGBF_ENABLED|NVREG_SLOTTIME_10_100_FULL|low, base + NvRegSlotTime); | ||
5145 | } else { | ||
5146 | writel(NVREG_SLOTTIME_10_100_FULL, base + NvRegSlotTime); | ||
5147 | nv_gear_backoff_reseed(dev); | ||
5148 | } | ||
5149 | } | ||
4907 | writel(NVREG_TX_DEFERRAL_DEFAULT, base + NvRegTxDeferral); | 5150 | writel(NVREG_TX_DEFERRAL_DEFAULT, base + NvRegTxDeferral); |
4908 | writel(NVREG_RX_DEFERRAL_DEFAULT, base + NvRegRxDeferral); | 5151 | writel(NVREG_RX_DEFERRAL_DEFAULT, base + NvRegRxDeferral); |
4909 | if (poll_interval == -1) { | 5152 | if (poll_interval == -1) { |
@@ -5110,6 +5353,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
5110 | 5353 | ||
5111 | /* copy of driver data */ | 5354 | /* copy of driver data */ |
5112 | np->driver_data = id->driver_data; | 5355 | np->driver_data = id->driver_data; |
5356 | /* copy of device id */ | ||
5357 | np->device_id = id->device; | ||
5113 | 5358 | ||
5114 | /* handle different descriptor versions */ | 5359 | /* handle different descriptor versions */ |
5115 | if (id->driver_data & DEV_HAS_HIGH_DMA) { | 5360 | if (id->driver_data & DEV_HAS_HIGH_DMA) { |
@@ -5399,6 +5644,14 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i | |||
5399 | pci_name(pci_dev), id1, id2, phyaddr); | 5644 | pci_name(pci_dev), id1, id2, phyaddr); |
5400 | np->phyaddr = phyaddr; | 5645 | np->phyaddr = phyaddr; |
5401 | np->phy_oui = id1 | id2; | 5646 | np->phy_oui = id1 | id2; |
5647 | |||
5648 | /* Realtek hardcoded phy id1 to all zero's on certain phys */ | ||
5649 | if (np->phy_oui == PHY_OUI_REALTEK2) | ||
5650 | np->phy_oui = PHY_OUI_REALTEK; | ||
5651 | /* Setup phy revision for Realtek */ | ||
5652 | if (np->phy_oui == PHY_OUI_REALTEK && np->phy_model == PHY_MODEL_REALTEK_8211) | ||
5653 | np->phy_rev = mii_rw(dev, phyaddr, MII_RESV1, MII_READ) & PHY_REV_MASK; | ||
5654 | |||
5402 | break; | 5655 | break; |
5403 | } | 5656 | } |
5404 | if (i == 33) { | 5657 | if (i == 33) { |
@@ -5477,6 +5730,28 @@ out: | |||
5477 | return err; | 5730 | return err; |
5478 | } | 5731 | } |
5479 | 5732 | ||
5733 | static void nv_restore_phy(struct net_device *dev) | ||
5734 | { | ||
5735 | struct fe_priv *np = netdev_priv(dev); | ||
5736 | u16 phy_reserved, mii_control; | ||
5737 | |||
5738 | if (np->phy_oui == PHY_OUI_REALTEK && | ||
5739 | np->phy_model == PHY_MODEL_REALTEK_8201 && | ||
5740 | phy_cross == NV_CROSSOVER_DETECTION_DISABLED) { | ||
5741 | mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT3); | ||
5742 | phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, MII_READ); | ||
5743 | phy_reserved &= ~PHY_REALTEK_INIT_MSK1; | ||
5744 | phy_reserved |= PHY_REALTEK_INIT8; | ||
5745 | mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG2, phy_reserved); | ||
5746 | mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG1, PHY_REALTEK_INIT1); | ||
5747 | |||
5748 | /* restart auto negotiation */ | ||
5749 | mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); | ||
5750 | mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE); | ||
5751 | mii_rw(dev, np->phyaddr, MII_BMCR, mii_control); | ||
5752 | } | ||
5753 | } | ||
5754 | |||
5480 | static void __devexit nv_remove(struct pci_dev *pci_dev) | 5755 | static void __devexit nv_remove(struct pci_dev *pci_dev) |
5481 | { | 5756 | { |
5482 | struct net_device *dev = pci_get_drvdata(pci_dev); | 5757 | struct net_device *dev = pci_get_drvdata(pci_dev); |
@@ -5493,6 +5768,9 @@ static void __devexit nv_remove(struct pci_dev *pci_dev) | |||
5493 | writel(readl(base + NvRegTransmitPoll) & ~NVREG_TRANSMITPOLL_MAC_ADDR_REV, | 5768 | writel(readl(base + NvRegTransmitPoll) & ~NVREG_TRANSMITPOLL_MAC_ADDR_REV, |
5494 | base + NvRegTransmitPoll); | 5769 | base + NvRegTransmitPoll); |
5495 | 5770 | ||
5771 | /* restore any phy related changes */ | ||
5772 | nv_restore_phy(dev); | ||
5773 | |||
5496 | /* free all structures */ | 5774 | /* free all structures */ |
5497 | free_rings(dev); | 5775 | free_rings(dev); |
5498 | iounmap(get_hwbase(dev)); | 5776 | iounmap(get_hwbase(dev)); |
@@ -5632,83 +5910,83 @@ static struct pci_device_id pci_tbl[] = { | |||
5632 | }, | 5910 | }, |
5633 | { /* MCP65 Ethernet Controller */ | 5911 | { /* MCP65 Ethernet Controller */ |
5634 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20), | 5912 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20), |
5635 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_NEED_TX_LIMIT, | 5913 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, |
5636 | }, | 5914 | }, |
5637 | { /* MCP65 Ethernet Controller */ | 5915 | { /* MCP65 Ethernet Controller */ |
5638 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21), | 5916 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21), |
5639 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT, | 5917 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, |
5640 | }, | 5918 | }, |
5641 | { /* MCP65 Ethernet Controller */ | 5919 | { /* MCP65 Ethernet Controller */ |
5642 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22), | 5920 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22), |
5643 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT, | 5921 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, |
5644 | }, | 5922 | }, |
5645 | { /* MCP65 Ethernet Controller */ | 5923 | { /* MCP65 Ethernet Controller */ |
5646 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23), | 5924 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23), |
5647 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT, | 5925 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, |
5648 | }, | 5926 | }, |
5649 | { /* MCP67 Ethernet Controller */ | 5927 | { /* MCP67 Ethernet Controller */ |
5650 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24), | 5928 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24), |
5651 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, | 5929 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, |
5652 | }, | 5930 | }, |
5653 | { /* MCP67 Ethernet Controller */ | 5931 | { /* MCP67 Ethernet Controller */ |
5654 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25), | 5932 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25), |
5655 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, | 5933 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, |
5656 | }, | 5934 | }, |
5657 | { /* MCP67 Ethernet Controller */ | 5935 | { /* MCP67 Ethernet Controller */ |
5658 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26), | 5936 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26), |
5659 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, | 5937 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, |
5660 | }, | 5938 | }, |
5661 | { /* MCP67 Ethernet Controller */ | 5939 | { /* MCP67 Ethernet Controller */ |
5662 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27), | 5940 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27), |
5663 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, | 5941 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE, |
5664 | }, | 5942 | }, |
5665 | { /* MCP73 Ethernet Controller */ | 5943 | { /* MCP73 Ethernet Controller */ |
5666 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_28), | 5944 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_28), |
5667 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, | 5945 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, |
5668 | }, | 5946 | }, |
5669 | { /* MCP73 Ethernet Controller */ | 5947 | { /* MCP73 Ethernet Controller */ |
5670 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_29), | 5948 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_29), |
5671 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, | 5949 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, |
5672 | }, | 5950 | }, |
5673 | { /* MCP73 Ethernet Controller */ | 5951 | { /* MCP73 Ethernet Controller */ |
5674 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_30), | 5952 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_30), |
5675 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, | 5953 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, |
5676 | }, | 5954 | }, |
5677 | { /* MCP73 Ethernet Controller */ | 5955 | { /* MCP73 Ethernet Controller */ |
5678 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_31), | 5956 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_31), |
5679 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, | 5957 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE, |
5680 | }, | 5958 | }, |
5681 | { /* MCP77 Ethernet Controller */ | 5959 | { /* MCP77 Ethernet Controller */ |
5682 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_32), | 5960 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_32), |
5683 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT, | 5961 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, |
5684 | }, | 5962 | }, |
5685 | { /* MCP77 Ethernet Controller */ | 5963 | { /* MCP77 Ethernet Controller */ |
5686 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_33), | 5964 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_33), |
5687 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT, | 5965 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, |
5688 | }, | 5966 | }, |
5689 | { /* MCP77 Ethernet Controller */ | 5967 | { /* MCP77 Ethernet Controller */ |
5690 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_34), | 5968 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_34), |
5691 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT, | 5969 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, |
5692 | }, | 5970 | }, |
5693 | { /* MCP77 Ethernet Controller */ | 5971 | { /* MCP77 Ethernet Controller */ |
5694 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_35), | 5972 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_35), |
5695 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT, | 5973 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, |
5696 | }, | 5974 | }, |
5697 | { /* MCP79 Ethernet Controller */ | 5975 | { /* MCP79 Ethernet Controller */ |
5698 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36), | 5976 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36), |
5699 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT, | 5977 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, |
5700 | }, | 5978 | }, |
5701 | { /* MCP79 Ethernet Controller */ | 5979 | { /* MCP79 Ethernet Controller */ |
5702 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37), | 5980 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37), |
5703 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT, | 5981 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, |
5704 | }, | 5982 | }, |
5705 | { /* MCP79 Ethernet Controller */ | 5983 | { /* MCP79 Ethernet Controller */ |
5706 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_38), | 5984 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_38), |
5707 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT, | 5985 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, |
5708 | }, | 5986 | }, |
5709 | { /* MCP79 Ethernet Controller */ | 5987 | { /* MCP79 Ethernet Controller */ |
5710 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_39), | 5988 | PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_39), |
5711 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT, | 5989 | .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, |
5712 | }, | 5990 | }, |
5713 | {0,}, | 5991 | {0,}, |
5714 | }; | 5992 | }; |
@@ -5744,6 +6022,8 @@ module_param(msix, int, 0); | |||
5744 | MODULE_PARM_DESC(msix, "MSIX interrupts are enabled by setting to 1 and disabled by setting to 0."); | 6022 | MODULE_PARM_DESC(msix, "MSIX interrupts are enabled by setting to 1 and disabled by setting to 0."); |
5745 | module_param(dma_64bit, int, 0); | 6023 | module_param(dma_64bit, int, 0); |
5746 | MODULE_PARM_DESC(dma_64bit, "High DMA is enabled by setting to 1 and disabled by setting to 0."); | 6024 | MODULE_PARM_DESC(dma_64bit, "High DMA is enabled by setting to 1 and disabled by setting to 0."); |
6025 | module_param(phy_cross, int, 0); | ||
6026 | MODULE_PARM_DESC(phy_cross, "Phy crossover detection for Realtek 8201 phy is enabled by setting to 1 and disabled by setting to 0."); | ||
5747 | 6027 | ||
5748 | MODULE_AUTHOR("Manfred Spraul <manfred@colorfullife.com>"); | 6028 | MODULE_AUTHOR("Manfred Spraul <manfred@colorfullife.com>"); |
5749 | MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver"); | 6029 | MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver"); |
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index c8c3df737d73..99a4b990939f 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c | |||
@@ -98,7 +98,6 @@ | |||
98 | #include "gianfar_mii.h" | 98 | #include "gianfar_mii.h" |
99 | 99 | ||
100 | #define TX_TIMEOUT (1*HZ) | 100 | #define TX_TIMEOUT (1*HZ) |
101 | #define SKB_ALLOC_TIMEOUT 1000000 | ||
102 | #undef BRIEF_GFAR_ERRORS | 101 | #undef BRIEF_GFAR_ERRORS |
103 | #undef VERBOSE_GFAR_ERRORS | 102 | #undef VERBOSE_GFAR_ERRORS |
104 | 103 | ||
@@ -115,7 +114,9 @@ static int gfar_enet_open(struct net_device *dev); | |||
115 | static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev); | 114 | static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev); |
116 | static void gfar_timeout(struct net_device *dev); | 115 | static void gfar_timeout(struct net_device *dev); |
117 | static int gfar_close(struct net_device *dev); | 116 | static int gfar_close(struct net_device *dev); |
118 | struct sk_buff *gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp); | 117 | struct sk_buff *gfar_new_skb(struct net_device *dev); |
118 | static void gfar_new_rxbdp(struct net_device *dev, struct rxbd8 *bdp, | ||
119 | struct sk_buff *skb); | ||
119 | static int gfar_set_mac_address(struct net_device *dev); | 120 | static int gfar_set_mac_address(struct net_device *dev); |
120 | static int gfar_change_mtu(struct net_device *dev, int new_mtu); | 121 | static int gfar_change_mtu(struct net_device *dev, int new_mtu); |
121 | static irqreturn_t gfar_error(int irq, void *dev_id); | 122 | static irqreturn_t gfar_error(int irq, void *dev_id); |
@@ -783,14 +784,21 @@ int startup_gfar(struct net_device *dev) | |||
783 | 784 | ||
784 | rxbdp = priv->rx_bd_base; | 785 | rxbdp = priv->rx_bd_base; |
785 | for (i = 0; i < priv->rx_ring_size; i++) { | 786 | for (i = 0; i < priv->rx_ring_size; i++) { |
786 | struct sk_buff *skb = NULL; | 787 | struct sk_buff *skb; |
787 | 788 | ||
788 | rxbdp->status = 0; | 789 | skb = gfar_new_skb(dev); |
789 | 790 | ||
790 | skb = gfar_new_skb(dev, rxbdp); | 791 | if (!skb) { |
792 | printk(KERN_ERR "%s: Can't allocate RX buffers\n", | ||
793 | dev->name); | ||
794 | |||
795 | goto err_rxalloc_fail; | ||
796 | } | ||
791 | 797 | ||
792 | priv->rx_skbuff[i] = skb; | 798 | priv->rx_skbuff[i] = skb; |
793 | 799 | ||
800 | gfar_new_rxbdp(dev, rxbdp, skb); | ||
801 | |||
794 | rxbdp++; | 802 | rxbdp++; |
795 | } | 803 | } |
796 | 804 | ||
@@ -916,6 +924,7 @@ rx_irq_fail: | |||
916 | tx_irq_fail: | 924 | tx_irq_fail: |
917 | free_irq(priv->interruptError, dev); | 925 | free_irq(priv->interruptError, dev); |
918 | err_irq_fail: | 926 | err_irq_fail: |
927 | err_rxalloc_fail: | ||
919 | rx_skb_fail: | 928 | rx_skb_fail: |
920 | free_skb_resources(priv); | 929 | free_skb_resources(priv); |
921 | tx_skb_fail: | 930 | tx_skb_fail: |
@@ -1328,18 +1337,37 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id) | |||
1328 | return IRQ_HANDLED; | 1337 | return IRQ_HANDLED; |
1329 | } | 1338 | } |
1330 | 1339 | ||
1331 | struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp) | 1340 | static void gfar_new_rxbdp(struct net_device *dev, struct rxbd8 *bdp, |
1341 | struct sk_buff *skb) | ||
1342 | { | ||
1343 | struct gfar_private *priv = netdev_priv(dev); | ||
1344 | u32 * status_len = (u32 *)bdp; | ||
1345 | u16 flags; | ||
1346 | |||
1347 | bdp->bufPtr = dma_map_single(&dev->dev, skb->data, | ||
1348 | priv->rx_buffer_size, DMA_FROM_DEVICE); | ||
1349 | |||
1350 | flags = RXBD_EMPTY | RXBD_INTERRUPT; | ||
1351 | |||
1352 | if (bdp == priv->rx_bd_base + priv->rx_ring_size - 1) | ||
1353 | flags |= RXBD_WRAP; | ||
1354 | |||
1355 | eieio(); | ||
1356 | |||
1357 | *status_len = (u32)flags << 16; | ||
1358 | } | ||
1359 | |||
1360 | |||
1361 | struct sk_buff * gfar_new_skb(struct net_device *dev) | ||
1332 | { | 1362 | { |
1333 | unsigned int alignamount; | 1363 | unsigned int alignamount; |
1334 | struct gfar_private *priv = netdev_priv(dev); | 1364 | struct gfar_private *priv = netdev_priv(dev); |
1335 | struct sk_buff *skb = NULL; | 1365 | struct sk_buff *skb = NULL; |
1336 | unsigned int timeout = SKB_ALLOC_TIMEOUT; | ||
1337 | 1366 | ||
1338 | /* We have to allocate the skb, so keep trying till we succeed */ | 1367 | /* We have to allocate the skb, so keep trying till we succeed */ |
1339 | while ((!skb) && timeout--) | 1368 | skb = netdev_alloc_skb(dev, priv->rx_buffer_size + RXBUF_ALIGNMENT); |
1340 | skb = dev_alloc_skb(priv->rx_buffer_size + RXBUF_ALIGNMENT); | ||
1341 | 1369 | ||
1342 | if (NULL == skb) | 1370 | if (!skb) |
1343 | return NULL; | 1371 | return NULL; |
1344 | 1372 | ||
1345 | alignamount = RXBUF_ALIGNMENT - | 1373 | alignamount = RXBUF_ALIGNMENT - |
@@ -1350,15 +1378,6 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp) | |||
1350 | */ | 1378 | */ |
1351 | skb_reserve(skb, alignamount); | 1379 | skb_reserve(skb, alignamount); |
1352 | 1380 | ||
1353 | bdp->bufPtr = dma_map_single(&dev->dev, skb->data, | ||
1354 | priv->rx_buffer_size, DMA_FROM_DEVICE); | ||
1355 | |||
1356 | bdp->length = 0; | ||
1357 | |||
1358 | /* Mark the buffer empty */ | ||
1359 | eieio(); | ||
1360 | bdp->status |= (RXBD_EMPTY | RXBD_INTERRUPT); | ||
1361 | |||
1362 | return skb; | 1381 | return skb; |
1363 | } | 1382 | } |
1364 | 1383 | ||
@@ -1544,10 +1563,31 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) | |||
1544 | bdp = priv->cur_rx; | 1563 | bdp = priv->cur_rx; |
1545 | 1564 | ||
1546 | while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) { | 1565 | while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) { |
1566 | struct sk_buff *newskb; | ||
1547 | rmb(); | 1567 | rmb(); |
1568 | |||
1569 | /* Add another skb for the future */ | ||
1570 | newskb = gfar_new_skb(dev); | ||
1571 | |||
1548 | skb = priv->rx_skbuff[priv->skb_currx]; | 1572 | skb = priv->rx_skbuff[priv->skb_currx]; |
1549 | 1573 | ||
1550 | if ((bdp->status & RXBD_LAST) && !(bdp->status & RXBD_ERR)) { | 1574 | /* We drop the frame if we failed to allocate a new buffer */ |
1575 | if (unlikely(!newskb || !(bdp->status & RXBD_LAST) || | ||
1576 | bdp->status & RXBD_ERR)) { | ||
1577 | count_errors(bdp->status, dev); | ||
1578 | |||
1579 | if (unlikely(!newskb)) | ||
1580 | newskb = skb; | ||
1581 | |||
1582 | if (skb) { | ||
1583 | dma_unmap_single(&priv->dev->dev, | ||
1584 | bdp->bufPtr, | ||
1585 | priv->rx_buffer_size, | ||
1586 | DMA_FROM_DEVICE); | ||
1587 | |||
1588 | dev_kfree_skb_any(skb); | ||
1589 | } | ||
1590 | } else { | ||
1551 | /* Increment the number of packets */ | 1591 | /* Increment the number of packets */ |
1552 | dev->stats.rx_packets++; | 1592 | dev->stats.rx_packets++; |
1553 | howmany++; | 1593 | howmany++; |
@@ -1558,23 +1598,14 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) | |||
1558 | gfar_process_frame(dev, skb, pkt_len); | 1598 | gfar_process_frame(dev, skb, pkt_len); |
1559 | 1599 | ||
1560 | dev->stats.rx_bytes += pkt_len; | 1600 | dev->stats.rx_bytes += pkt_len; |
1561 | } else { | ||
1562 | count_errors(bdp->status, dev); | ||
1563 | |||
1564 | if (skb) | ||
1565 | dev_kfree_skb_any(skb); | ||
1566 | |||
1567 | priv->rx_skbuff[priv->skb_currx] = NULL; | ||
1568 | } | 1601 | } |
1569 | 1602 | ||
1570 | dev->last_rx = jiffies; | 1603 | dev->last_rx = jiffies; |
1571 | 1604 | ||
1572 | /* Clear the status flags for this buffer */ | 1605 | priv->rx_skbuff[priv->skb_currx] = newskb; |
1573 | bdp->status &= ~RXBD_STATS; | ||
1574 | 1606 | ||
1575 | /* Add another skb for the future */ | 1607 | /* Setup the new bdp */ |
1576 | skb = gfar_new_skb(dev, bdp); | 1608 | gfar_new_rxbdp(dev, bdp, newskb); |
1577 | priv->rx_skbuff[priv->skb_currx] = skb; | ||
1578 | 1609 | ||
1579 | /* Update to the next pointer */ | 1610 | /* Update to the next pointer */ |
1580 | if (bdp->status & RXBD_WRAP) | 1611 | if (bdp->status & RXBD_WRAP) |
@@ -1584,9 +1615,8 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) | |||
1584 | 1615 | ||
1585 | /* update to point at the next skb */ | 1616 | /* update to point at the next skb */ |
1586 | priv->skb_currx = | 1617 | priv->skb_currx = |
1587 | (priv->skb_currx + | 1618 | (priv->skb_currx + 1) & |
1588 | 1) & RX_RING_MOD_MASK(priv->rx_ring_size); | 1619 | RX_RING_MOD_MASK(priv->rx_ring_size); |
1589 | |||
1590 | } | 1620 | } |
1591 | 1621 | ||
1592 | /* Update the current rxbd pointer to be the next one */ | 1622 | /* Update the current rxbd pointer to be the next one */ |
@@ -2001,12 +2031,16 @@ static irqreturn_t gfar_error(int irq, void *dev_id) | |||
2001 | return IRQ_HANDLED; | 2031 | return IRQ_HANDLED; |
2002 | } | 2032 | } |
2003 | 2033 | ||
2034 | /* work with hotplug and coldplug */ | ||
2035 | MODULE_ALIAS("platform:fsl-gianfar"); | ||
2036 | |||
2004 | /* Structure for a device driver */ | 2037 | /* Structure for a device driver */ |
2005 | static struct platform_driver gfar_driver = { | 2038 | static struct platform_driver gfar_driver = { |
2006 | .probe = gfar_probe, | 2039 | .probe = gfar_probe, |
2007 | .remove = gfar_remove, | 2040 | .remove = gfar_remove, |
2008 | .driver = { | 2041 | .driver = { |
2009 | .name = "fsl-gianfar", | 2042 | .name = "fsl-gianfar", |
2043 | .owner = THIS_MODULE, | ||
2010 | }, | 2044 | }, |
2011 | }; | 2045 | }; |
2012 | 2046 | ||
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 378a23963495..5d2108c5ac7c 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c | |||
@@ -43,6 +43,8 @@ | |||
43 | #include <asm/io.h> | 43 | #include <asm/io.h> |
44 | #include <asm/dma.h> | 44 | #include <asm/dma.h> |
45 | #include <asm/uaccess.h> | 45 | #include <asm/uaccess.h> |
46 | #include <asm/dcr.h> | ||
47 | #include <asm/dcr-regs.h> | ||
46 | 48 | ||
47 | #include "core.h" | 49 | #include "core.h" |
48 | 50 | ||
@@ -127,10 +129,35 @@ static struct device_node *emac_boot_list[EMAC_BOOT_LIST_SIZE]; | |||
127 | static inline void emac_report_timeout_error(struct emac_instance *dev, | 129 | static inline void emac_report_timeout_error(struct emac_instance *dev, |
128 | const char *error) | 130 | const char *error) |
129 | { | 131 | { |
130 | if (net_ratelimit()) | 132 | if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX | |
133 | EMAC_FTR_440EP_PHY_CLK_FIX)) | ||
134 | DBG(dev, "%s" NL, error); | ||
135 | else if (net_ratelimit()) | ||
131 | printk(KERN_ERR "%s: %s\n", dev->ndev->name, error); | 136 | printk(KERN_ERR "%s: %s\n", dev->ndev->name, error); |
132 | } | 137 | } |
133 | 138 | ||
139 | /* EMAC PHY clock workaround: | ||
140 | * 440EP/440GR has more sane SDR0_MFR register implementation than 440GX, | ||
141 | * which allows controlling each EMAC clock | ||
142 | */ | ||
143 | static inline void emac_rx_clk_tx(struct emac_instance *dev) | ||
144 | { | ||
145 | #ifdef CONFIG_PPC_DCR_NATIVE | ||
146 | if (emac_has_feature(dev, EMAC_FTR_440EP_PHY_CLK_FIX)) | ||
147 | dcri_clrset(SDR0, SDR0_MFR, | ||
148 | 0, SDR0_MFR_ECS >> dev->cell_index); | ||
149 | #endif | ||
150 | } | ||
151 | |||
152 | static inline void emac_rx_clk_default(struct emac_instance *dev) | ||
153 | { | ||
154 | #ifdef CONFIG_PPC_DCR_NATIVE | ||
155 | if (emac_has_feature(dev, EMAC_FTR_440EP_PHY_CLK_FIX)) | ||
156 | dcri_clrset(SDR0, SDR0_MFR, | ||
157 | SDR0_MFR_ECS >> dev->cell_index, 0); | ||
158 | #endif | ||
159 | } | ||
160 | |||
134 | /* PHY polling intervals */ | 161 | /* PHY polling intervals */ |
135 | #define PHY_POLL_LINK_ON HZ | 162 | #define PHY_POLL_LINK_ON HZ |
136 | #define PHY_POLL_LINK_OFF (HZ / 5) | 163 | #define PHY_POLL_LINK_OFF (HZ / 5) |
@@ -524,7 +551,10 @@ static int emac_configure(struct emac_instance *dev) | |||
524 | rx_size = dev->rx_fifo_size_gige; | 551 | rx_size = dev->rx_fifo_size_gige; |
525 | 552 | ||
526 | if (dev->ndev->mtu > ETH_DATA_LEN) { | 553 | if (dev->ndev->mtu > ETH_DATA_LEN) { |
527 | mr1 |= EMAC_MR1_JPSM; | 554 | if (emac_has_feature(dev, EMAC_FTR_EMAC4)) |
555 | mr1 |= EMAC4_MR1_JPSM; | ||
556 | else | ||
557 | mr1 |= EMAC_MR1_JPSM; | ||
528 | dev->stop_timeout = STOP_TIMEOUT_1000_JUMBO; | 558 | dev->stop_timeout = STOP_TIMEOUT_1000_JUMBO; |
529 | } else | 559 | } else |
530 | dev->stop_timeout = STOP_TIMEOUT_1000; | 560 | dev->stop_timeout = STOP_TIMEOUT_1000; |
@@ -708,7 +738,7 @@ static int __emac_mdio_read(struct emac_instance *dev, u8 id, u8 reg) | |||
708 | rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port); | 738 | rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port); |
709 | 739 | ||
710 | /* Wait for management interface to become idle */ | 740 | /* Wait for management interface to become idle */ |
711 | n = 10; | 741 | n = 20; |
712 | while (!emac_phy_done(dev, in_be32(&p->stacr))) { | 742 | while (!emac_phy_done(dev, in_be32(&p->stacr))) { |
713 | udelay(1); | 743 | udelay(1); |
714 | if (!--n) { | 744 | if (!--n) { |
@@ -733,7 +763,7 @@ static int __emac_mdio_read(struct emac_instance *dev, u8 id, u8 reg) | |||
733 | out_be32(&p->stacr, r); | 763 | out_be32(&p->stacr, r); |
734 | 764 | ||
735 | /* Wait for read to complete */ | 765 | /* Wait for read to complete */ |
736 | n = 100; | 766 | n = 200; |
737 | while (!emac_phy_done(dev, (r = in_be32(&p->stacr)))) { | 767 | while (!emac_phy_done(dev, (r = in_be32(&p->stacr)))) { |
738 | udelay(1); | 768 | udelay(1); |
739 | if (!--n) { | 769 | if (!--n) { |
@@ -780,7 +810,7 @@ static void __emac_mdio_write(struct emac_instance *dev, u8 id, u8 reg, | |||
780 | rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port); | 810 | rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port); |
781 | 811 | ||
782 | /* Wait for management interface to be idle */ | 812 | /* Wait for management interface to be idle */ |
783 | n = 10; | 813 | n = 20; |
784 | while (!emac_phy_done(dev, in_be32(&p->stacr))) { | 814 | while (!emac_phy_done(dev, in_be32(&p->stacr))) { |
785 | udelay(1); | 815 | udelay(1); |
786 | if (!--n) { | 816 | if (!--n) { |
@@ -806,7 +836,7 @@ static void __emac_mdio_write(struct emac_instance *dev, u8 id, u8 reg, | |||
806 | out_be32(&p->stacr, r); | 836 | out_be32(&p->stacr, r); |
807 | 837 | ||
808 | /* Wait for write to complete */ | 838 | /* Wait for write to complete */ |
809 | n = 100; | 839 | n = 200; |
810 | while (!emac_phy_done(dev, in_be32(&p->stacr))) { | 840 | while (!emac_phy_done(dev, in_be32(&p->stacr))) { |
811 | udelay(1); | 841 | udelay(1); |
812 | if (!--n) { | 842 | if (!--n) { |
@@ -1094,9 +1124,11 @@ static int emac_open(struct net_device *ndev) | |||
1094 | int link_poll_interval; | 1124 | int link_poll_interval; |
1095 | if (dev->phy.def->ops->poll_link(&dev->phy)) { | 1125 | if (dev->phy.def->ops->poll_link(&dev->phy)) { |
1096 | dev->phy.def->ops->read_link(&dev->phy); | 1126 | dev->phy.def->ops->read_link(&dev->phy); |
1127 | emac_rx_clk_default(dev); | ||
1097 | netif_carrier_on(dev->ndev); | 1128 | netif_carrier_on(dev->ndev); |
1098 | link_poll_interval = PHY_POLL_LINK_ON; | 1129 | link_poll_interval = PHY_POLL_LINK_ON; |
1099 | } else { | 1130 | } else { |
1131 | emac_rx_clk_tx(dev); | ||
1100 | netif_carrier_off(dev->ndev); | 1132 | netif_carrier_off(dev->ndev); |
1101 | link_poll_interval = PHY_POLL_LINK_OFF; | 1133 | link_poll_interval = PHY_POLL_LINK_OFF; |
1102 | } | 1134 | } |
@@ -1174,6 +1206,7 @@ static void emac_link_timer(struct work_struct *work) | |||
1174 | 1206 | ||
1175 | if (dev->phy.def->ops->poll_link(&dev->phy)) { | 1207 | if (dev->phy.def->ops->poll_link(&dev->phy)) { |
1176 | if (!netif_carrier_ok(dev->ndev)) { | 1208 | if (!netif_carrier_ok(dev->ndev)) { |
1209 | emac_rx_clk_default(dev); | ||
1177 | /* Get new link parameters */ | 1210 | /* Get new link parameters */ |
1178 | dev->phy.def->ops->read_link(&dev->phy); | 1211 | dev->phy.def->ops->read_link(&dev->phy); |
1179 | 1212 | ||
@@ -1186,6 +1219,7 @@ static void emac_link_timer(struct work_struct *work) | |||
1186 | link_poll_interval = PHY_POLL_LINK_ON; | 1219 | link_poll_interval = PHY_POLL_LINK_ON; |
1187 | } else { | 1220 | } else { |
1188 | if (netif_carrier_ok(dev->ndev)) { | 1221 | if (netif_carrier_ok(dev->ndev)) { |
1222 | emac_rx_clk_tx(dev); | ||
1189 | netif_carrier_off(dev->ndev); | 1223 | netif_carrier_off(dev->ndev); |
1190 | netif_tx_disable(dev->ndev); | 1224 | netif_tx_disable(dev->ndev); |
1191 | emac_reinitialize(dev); | 1225 | emac_reinitialize(dev); |
@@ -2237,7 +2271,7 @@ static int __devinit emac_of_bus_notify(struct notifier_block *nb, | |||
2237 | return 0; | 2271 | return 0; |
2238 | } | 2272 | } |
2239 | 2273 | ||
2240 | static struct notifier_block emac_of_bus_notifier = { | 2274 | static struct notifier_block emac_of_bus_notifier __devinitdata = { |
2241 | .notifier_call = emac_of_bus_notify | 2275 | .notifier_call = emac_of_bus_notify |
2242 | }; | 2276 | }; |
2243 | 2277 | ||
@@ -2330,6 +2364,19 @@ static int __devinit emac_init_phy(struct emac_instance *dev) | |||
2330 | dev->phy.mdio_read = emac_mdio_read; | 2364 | dev->phy.mdio_read = emac_mdio_read; |
2331 | dev->phy.mdio_write = emac_mdio_write; | 2365 | dev->phy.mdio_write = emac_mdio_write; |
2332 | 2366 | ||
2367 | /* Enable internal clock source */ | ||
2368 | #ifdef CONFIG_PPC_DCR_NATIVE | ||
2369 | if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX)) | ||
2370 | dcri_clrset(SDR0, SDR0_MFR, 0, SDR0_MFR_ECS); | ||
2371 | #endif | ||
2372 | /* PHY clock workaround */ | ||
2373 | emac_rx_clk_tx(dev); | ||
2374 | |||
2375 | /* Enable internal clock source on 440GX*/ | ||
2376 | #ifdef CONFIG_PPC_DCR_NATIVE | ||
2377 | if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX)) | ||
2378 | dcri_clrset(SDR0, SDR0_MFR, 0, SDR0_MFR_ECS); | ||
2379 | #endif | ||
2333 | /* Configure EMAC with defaults so we can at least use MDIO | 2380 | /* Configure EMAC with defaults so we can at least use MDIO |
2334 | * This is needed mostly for 440GX | 2381 | * This is needed mostly for 440GX |
2335 | */ | 2382 | */ |
@@ -2362,6 +2409,12 @@ static int __devinit emac_init_phy(struct emac_instance *dev) | |||
2362 | if (!emac_mii_phy_probe(&dev->phy, i)) | 2409 | if (!emac_mii_phy_probe(&dev->phy, i)) |
2363 | break; | 2410 | break; |
2364 | } | 2411 | } |
2412 | |||
2413 | /* Enable external clock source */ | ||
2414 | #ifdef CONFIG_PPC_DCR_NATIVE | ||
2415 | if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX)) | ||
2416 | dcri_clrset(SDR0, SDR0_MFR, SDR0_MFR_ECS, 0); | ||
2417 | #endif | ||
2365 | mutex_unlock(&emac_phy_map_lock); | 2418 | mutex_unlock(&emac_phy_map_lock); |
2366 | if (i == 0x20) { | 2419 | if (i == 0x20) { |
2367 | printk(KERN_WARNING "%s: can't find PHY!\n", np->full_name); | 2420 | printk(KERN_WARNING "%s: can't find PHY!\n", np->full_name); |
@@ -2487,8 +2540,15 @@ static int __devinit emac_init_config(struct emac_instance *dev) | |||
2487 | } | 2540 | } |
2488 | 2541 | ||
2489 | /* Check EMAC version */ | 2542 | /* Check EMAC version */ |
2490 | if (of_device_is_compatible(np, "ibm,emac4")) | 2543 | if (of_device_is_compatible(np, "ibm,emac4")) { |
2491 | dev->features |= EMAC_FTR_EMAC4; | 2544 | dev->features |= EMAC_FTR_EMAC4; |
2545 | if (of_device_is_compatible(np, "ibm,emac-440gx")) | ||
2546 | dev->features |= EMAC_FTR_440GX_PHY_CLK_FIX; | ||
2547 | } else { | ||
2548 | if (of_device_is_compatible(np, "ibm,emac-440ep") || | ||
2549 | of_device_is_compatible(np, "ibm,emac-440gr")) | ||
2550 | dev->features |= EMAC_FTR_440EP_PHY_CLK_FIX; | ||
2551 | } | ||
2492 | 2552 | ||
2493 | /* Fixup some feature bits based on the device tree */ | 2553 | /* Fixup some feature bits based on the device tree */ |
2494 | if (of_get_property(np, "has-inverted-stacr-oc", NULL)) | 2554 | if (of_get_property(np, "has-inverted-stacr-oc", NULL)) |
@@ -2559,8 +2619,11 @@ static int __devinit emac_probe(struct of_device *ofdev, | |||
2559 | struct device_node **blist = NULL; | 2619 | struct device_node **blist = NULL; |
2560 | int err, i; | 2620 | int err, i; |
2561 | 2621 | ||
2562 | /* Skip unused/unwired EMACS */ | 2622 | /* Skip unused/unwired EMACS. We leave the check for an unused |
2563 | if (of_get_property(np, "unused", NULL)) | 2623 | * property here for now, but new flat device trees should set a |
2624 | * status property to "disabled" instead. | ||
2625 | */ | ||
2626 | if (of_get_property(np, "unused", NULL) || !of_device_is_available(np)) | ||
2564 | return -ENODEV; | 2627 | return -ENODEV; |
2565 | 2628 | ||
2566 | /* Find ourselves in the bootlist if we are there */ | 2629 | /* Find ourselves in the bootlist if we are there */ |
diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h index 4e74d8287c65..1683db9870a4 100644 --- a/drivers/net/ibm_newemac/core.h +++ b/drivers/net/ibm_newemac/core.h | |||
@@ -301,6 +301,14 @@ struct emac_instance { | |||
301 | * Set if we have new type STACR with STAOPC | 301 | * Set if we have new type STACR with STAOPC |
302 | */ | 302 | */ |
303 | #define EMAC_FTR_HAS_NEW_STACR 0x00000040 | 303 | #define EMAC_FTR_HAS_NEW_STACR 0x00000040 |
304 | /* | ||
305 | * Set if we need phy clock workaround for 440gx | ||
306 | */ | ||
307 | #define EMAC_FTR_440GX_PHY_CLK_FIX 0x00000080 | ||
308 | /* | ||
309 | * Set if we need phy clock workaround for 440ep or 440gr | ||
310 | */ | ||
311 | #define EMAC_FTR_440EP_PHY_CLK_FIX 0x00000100 | ||
304 | 312 | ||
305 | 313 | ||
306 | /* Right now, we don't quite handle the always/possible masks on the | 314 | /* Right now, we don't quite handle the always/possible masks on the |
@@ -312,8 +320,8 @@ enum { | |||
312 | 320 | ||
313 | EMAC_FTRS_POSSIBLE = | 321 | EMAC_FTRS_POSSIBLE = |
314 | #ifdef CONFIG_IBM_NEW_EMAC_EMAC4 | 322 | #ifdef CONFIG_IBM_NEW_EMAC_EMAC4 |
315 | EMAC_FTR_EMAC4 | EMAC_FTR_HAS_NEW_STACR | | 323 | EMAC_FTR_EMAC4 | EMAC_FTR_HAS_NEW_STACR | |
316 | EMAC_FTR_STACR_OC_INVERT | | 324 | EMAC_FTR_STACR_OC_INVERT | EMAC_FTR_440GX_PHY_CLK_FIX | |
317 | #endif | 325 | #endif |
318 | #ifdef CONFIG_IBM_NEW_EMAC_TAH | 326 | #ifdef CONFIG_IBM_NEW_EMAC_TAH |
319 | EMAC_FTR_HAS_TAH | | 327 | EMAC_FTR_HAS_TAH | |
@@ -324,7 +332,7 @@ enum { | |||
324 | #ifdef CONFIG_IBM_NEW_EMAC_RGMII | 332 | #ifdef CONFIG_IBM_NEW_EMAC_RGMII |
325 | EMAC_FTR_HAS_RGMII | | 333 | EMAC_FTR_HAS_RGMII | |
326 | #endif | 334 | #endif |
327 | 0, | 335 | EMAC_FTR_440EP_PHY_CLK_FIX, |
328 | }; | 336 | }; |
329 | 337 | ||
330 | static inline int emac_has_feature(struct emac_instance *dev, | 338 | static inline int emac_has_feature(struct emac_instance *dev, |
diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c index 6869f08c9dcb..10c267b2b961 100644 --- a/drivers/net/ibm_newemac/mal.c +++ b/drivers/net/ibm_newemac/mal.c | |||
@@ -61,8 +61,8 @@ int __devinit mal_register_commac(struct mal_instance *mal, | |||
61 | return 0; | 61 | return 0; |
62 | } | 62 | } |
63 | 63 | ||
64 | void __devexit mal_unregister_commac(struct mal_instance *mal, | 64 | void mal_unregister_commac(struct mal_instance *mal, |
65 | struct mal_commac *commac) | 65 | struct mal_commac *commac) |
66 | { | 66 | { |
67 | unsigned long flags; | 67 | unsigned long flags; |
68 | 68 | ||
@@ -136,6 +136,14 @@ void mal_enable_rx_channel(struct mal_instance *mal, int channel) | |||
136 | { | 136 | { |
137 | unsigned long flags; | 137 | unsigned long flags; |
138 | 138 | ||
139 | /* | ||
140 | * On some 4xx PPC's (e.g. 460EX/GT), the rx channel is a multiple | ||
141 | * of 8, but enabling in MAL_RXCASR needs the divided by 8 value | ||
142 | * for the bitmask | ||
143 | */ | ||
144 | if (!(channel % 8)) | ||
145 | channel >>= 3; | ||
146 | |||
139 | spin_lock_irqsave(&mal->lock, flags); | 147 | spin_lock_irqsave(&mal->lock, flags); |
140 | 148 | ||
141 | MAL_DBG(mal, "enable_rx(%d)" NL, channel); | 149 | MAL_DBG(mal, "enable_rx(%d)" NL, channel); |
@@ -148,6 +156,14 @@ void mal_enable_rx_channel(struct mal_instance *mal, int channel) | |||
148 | 156 | ||
149 | void mal_disable_rx_channel(struct mal_instance *mal, int channel) | 157 | void mal_disable_rx_channel(struct mal_instance *mal, int channel) |
150 | { | 158 | { |
159 | /* | ||
160 | * On some 4xx PPC's (e.g. 460EX/GT), the rx channel is a multiple | ||
161 | * of 8, but enabling in MAL_RXCASR needs the divided by 8 value | ||
162 | * for the bitmask | ||
163 | */ | ||
164 | if (!(channel % 8)) | ||
165 | channel >>= 3; | ||
166 | |||
151 | set_mal_dcrn(mal, MAL_RXCARR, MAL_CHAN_MASK(channel)); | 167 | set_mal_dcrn(mal, MAL_RXCARR, MAL_CHAN_MASK(channel)); |
152 | 168 | ||
153 | MAL_DBG(mal, "disable_rx(%d)" NL, channel); | 169 | MAL_DBG(mal, "disable_rx(%d)" NL, channel); |
diff --git a/drivers/net/ibm_newemac/rgmii.c b/drivers/net/ibm_newemac/rgmii.c index 5757788227be..e32da3de2695 100644 --- a/drivers/net/ibm_newemac/rgmii.c +++ b/drivers/net/ibm_newemac/rgmii.c | |||
@@ -179,7 +179,7 @@ void rgmii_put_mdio(struct of_device *ofdev, int input) | |||
179 | mutex_unlock(&dev->lock); | 179 | mutex_unlock(&dev->lock); |
180 | } | 180 | } |
181 | 181 | ||
182 | void __devexit rgmii_detach(struct of_device *ofdev, int input) | 182 | void rgmii_detach(struct of_device *ofdev, int input) |
183 | { | 183 | { |
184 | struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); | 184 | struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev); |
185 | struct rgmii_regs __iomem *p = dev->base; | 185 | struct rgmii_regs __iomem *p = dev->base; |
diff --git a/drivers/net/ibm_newemac/tah.c b/drivers/net/ibm_newemac/tah.c index b023d10d7e1c..30173a9fb557 100644 --- a/drivers/net/ibm_newemac/tah.c +++ b/drivers/net/ibm_newemac/tah.c | |||
@@ -35,7 +35,7 @@ int __devinit tah_attach(struct of_device *ofdev, int channel) | |||
35 | return 0; | 35 | return 0; |
36 | } | 36 | } |
37 | 37 | ||
38 | void __devexit tah_detach(struct of_device *ofdev, int channel) | 38 | void tah_detach(struct of_device *ofdev, int channel) |
39 | { | 39 | { |
40 | struct tah_instance *dev = dev_get_drvdata(&ofdev->dev); | 40 | struct tah_instance *dev = dev_get_drvdata(&ofdev->dev); |
41 | 41 | ||
diff --git a/drivers/net/ibm_newemac/zmii.c b/drivers/net/ibm_newemac/zmii.c index 2ea472aeab06..17b154124943 100644 --- a/drivers/net/ibm_newemac/zmii.c +++ b/drivers/net/ibm_newemac/zmii.c | |||
@@ -189,7 +189,7 @@ void zmii_set_speed(struct of_device *ofdev, int input, int speed) | |||
189 | mutex_unlock(&dev->lock); | 189 | mutex_unlock(&dev->lock); |
190 | } | 190 | } |
191 | 191 | ||
192 | void __devexit zmii_detach(struct of_device *ofdev, int input) | 192 | void zmii_detach(struct of_device *ofdev, int input) |
193 | { | 193 | { |
194 | struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev); | 194 | struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev); |
195 | 195 | ||
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index aaee02e9e3f0..ae398f04c7b4 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c | |||
@@ -871,6 +871,7 @@ static int __devinit igb_probe(struct pci_dev *pdev, | |||
871 | goto err_pci_reg; | 871 | goto err_pci_reg; |
872 | 872 | ||
873 | pci_set_master(pdev); | 873 | pci_set_master(pdev); |
874 | pci_save_state(pdev); | ||
874 | 875 | ||
875 | err = -ENOMEM; | 876 | err = -ENOMEM; |
876 | netdev = alloc_etherdev(sizeof(struct igb_adapter)); | 877 | netdev = alloc_etherdev(sizeof(struct igb_adapter)); |
@@ -4079,6 +4080,7 @@ static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev) | |||
4079 | return PCI_ERS_RESULT_DISCONNECT; | 4080 | return PCI_ERS_RESULT_DISCONNECT; |
4080 | } | 4081 | } |
4081 | pci_set_master(pdev); | 4082 | pci_set_master(pdev); |
4083 | pci_restore_state(pdev); | ||
4082 | 4084 | ||
4083 | pci_enable_wake(pdev, PCI_D3hot, 0); | 4085 | pci_enable_wake(pdev, PCI_D3hot, 0); |
4084 | pci_enable_wake(pdev, PCI_D3cold, 0); | 4086 | pci_enable_wake(pdev, PCI_D3cold, 0); |
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index 9f584521304a..083b0dd70fef 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c | |||
@@ -60,6 +60,7 @@ static struct platform_driver ali_ircc_driver = { | |||
60 | .resume = ali_ircc_resume, | 60 | .resume = ali_ircc_resume, |
61 | .driver = { | 61 | .driver = { |
62 | .name = ALI_IRCC_DRIVER_NAME, | 62 | .name = ALI_IRCC_DRIVER_NAME, |
63 | .owner = THIS_MODULE, | ||
63 | }, | 64 | }, |
64 | }; | 65 | }; |
65 | 66 | ||
@@ -2256,6 +2257,7 @@ static void FIR2SIR(int iobase) | |||
2256 | MODULE_AUTHOR("Benjamin Kong <benjamin_kong@ali.com.tw>"); | 2257 | MODULE_AUTHOR("Benjamin Kong <benjamin_kong@ali.com.tw>"); |
2257 | MODULE_DESCRIPTION("ALi FIR Controller Driver"); | 2258 | MODULE_DESCRIPTION("ALi FIR Controller Driver"); |
2258 | MODULE_LICENSE("GPL"); | 2259 | MODULE_LICENSE("GPL"); |
2260 | MODULE_ALIAS("platform:" ALI_IRCC_DRIVER_NAME); | ||
2259 | 2261 | ||
2260 | 2262 | ||
2261 | module_param_array(io, int, NULL, 0); | 2263 | module_param_array(io, int, NULL, 0); |
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index 8db71ab20456..d5c2d27f3ea4 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c | |||
@@ -908,6 +908,7 @@ static int pxa_irda_remove(struct platform_device *_dev) | |||
908 | static struct platform_driver pxa_ir_driver = { | 908 | static struct platform_driver pxa_ir_driver = { |
909 | .driver = { | 909 | .driver = { |
910 | .name = "pxa2xx-ir", | 910 | .name = "pxa2xx-ir", |
911 | .owner = THIS_MODULE, | ||
911 | }, | 912 | }, |
912 | .probe = pxa_irda_probe, | 913 | .probe = pxa_irda_probe, |
913 | .remove = pxa_irda_remove, | 914 | .remove = pxa_irda_remove, |
@@ -929,3 +930,4 @@ module_init(pxa_irda_init); | |||
929 | module_exit(pxa_irda_exit); | 930 | module_exit(pxa_irda_exit); |
930 | 931 | ||
931 | MODULE_LICENSE("GPL"); | 932 | MODULE_LICENSE("GPL"); |
933 | MODULE_ALIAS("platform:pxa2xx-ir"); | ||
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 056639f72bec..1bc8518f9197 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c | |||
@@ -1008,6 +1008,7 @@ static struct platform_driver sa1100ir_driver = { | |||
1008 | .resume = sa1100_irda_resume, | 1008 | .resume = sa1100_irda_resume, |
1009 | .driver = { | 1009 | .driver = { |
1010 | .name = "sa11x0-ir", | 1010 | .name = "sa11x0-ir", |
1011 | .owner = THIS_MODULE, | ||
1011 | }, | 1012 | }, |
1012 | }; | 1013 | }; |
1013 | 1014 | ||
@@ -1041,3 +1042,4 @@ MODULE_LICENSE("GPL"); | |||
1041 | MODULE_PARM_DESC(power_level, "IrDA power level, 1 (low) to 3 (high)"); | 1042 | MODULE_PARM_DESC(power_level, "IrDA power level, 1 (low) to 3 (high)"); |
1042 | MODULE_PARM_DESC(tx_lpm, "Enable transmitter low power (1.6us) mode"); | 1043 | MODULE_PARM_DESC(tx_lpm, "Enable transmitter low power (1.6us) mode"); |
1043 | MODULE_PARM_DESC(max_rate, "Maximum baud rate (4000000, 115200, 57600, 38400, 19200, 9600)"); | 1044 | MODULE_PARM_DESC(max_rate, "Maximum baud rate (4000000, 115200, 57600, 38400, 19200, 9600)"); |
1045 | MODULE_ALIAS("platform:sa11x0-ir"); | ||
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index cb371a8c24a7..7b859220c255 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c | |||
@@ -3431,6 +3431,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, | |||
3431 | } | 3431 | } |
3432 | 3432 | ||
3433 | pci_set_master(pdev); | 3433 | pci_set_master(pdev); |
3434 | pci_save_state(pdev); | ||
3434 | 3435 | ||
3435 | #ifdef CONFIG_NETDEVICES_MULTIQUEUE | 3436 | #ifdef CONFIG_NETDEVICES_MULTIQUEUE |
3436 | netdev = alloc_etherdev_mq(sizeof(struct ixgbe_adapter), MAX_TX_QUEUES); | 3437 | netdev = alloc_etherdev_mq(sizeof(struct ixgbe_adapter), MAX_TX_QUEUES); |
@@ -3721,6 +3722,7 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev) | |||
3721 | return PCI_ERS_RESULT_DISCONNECT; | 3722 | return PCI_ERS_RESULT_DISCONNECT; |
3722 | } | 3723 | } |
3723 | pci_set_master(pdev); | 3724 | pci_set_master(pdev); |
3725 | pci_restore_state(pdev); | ||
3724 | 3726 | ||
3725 | pci_enable_wake(pdev, PCI_D3hot, 0); | 3727 | pci_enable_wake(pdev, PCI_D3hot, 0); |
3726 | pci_enable_wake(pdev, PCI_D3cold, 0); | 3728 | pci_enable_wake(pdev, PCI_D3cold, 0); |
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index 5c154fe13859..07944820f745 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c | |||
@@ -249,6 +249,7 @@ out: | |||
249 | MODULE_DESCRIPTION("Jazz SONIC ethernet driver"); | 249 | MODULE_DESCRIPTION("Jazz SONIC ethernet driver"); |
250 | module_param(sonic_debug, int, 0); | 250 | module_param(sonic_debug, int, 0); |
251 | MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)"); | 251 | MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)"); |
252 | MODULE_ALIAS("platform:jazzsonic"); | ||
252 | 253 | ||
253 | #include "sonic.c" | 254 | #include "sonic.c" |
254 | 255 | ||
@@ -271,6 +272,7 @@ static struct platform_driver jazz_sonic_driver = { | |||
271 | .remove = __devexit_p(jazz_sonic_device_remove), | 272 | .remove = __devexit_p(jazz_sonic_device_remove), |
272 | .driver = { | 273 | .driver = { |
273 | .name = jazz_sonic_string, | 274 | .name = jazz_sonic_string, |
275 | .owner = THIS_MODULE, | ||
274 | }, | 276 | }, |
275 | }; | 277 | }; |
276 | 278 | ||
diff --git a/drivers/net/korina.c b/drivers/net/korina.c index 1d24a73a0e1a..e18576316bda 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c | |||
@@ -883,7 +883,7 @@ static int korina_init(struct net_device *dev) | |||
883 | static int korina_restart(struct net_device *dev) | 883 | static int korina_restart(struct net_device *dev) |
884 | { | 884 | { |
885 | struct korina_private *lp = netdev_priv(dev); | 885 | struct korina_private *lp = netdev_priv(dev); |
886 | int ret = 0; | 886 | int ret; |
887 | 887 | ||
888 | /* | 888 | /* |
889 | * Disable interrupts | 889 | * Disable interrupts |
@@ -987,7 +987,7 @@ static void korina_poll_controller(struct net_device *dev) | |||
987 | static int korina_open(struct net_device *dev) | 987 | static int korina_open(struct net_device *dev) |
988 | { | 988 | { |
989 | struct korina_private *lp = netdev_priv(dev); | 989 | struct korina_private *lp = netdev_priv(dev); |
990 | int ret = 0; | 990 | int ret; |
991 | 991 | ||
992 | /* Initialize */ | 992 | /* Initialize */ |
993 | ret = korina_init(dev); | 993 | ret = korina_init(dev); |
@@ -1031,6 +1031,8 @@ static int korina_open(struct net_device *dev) | |||
1031 | dev->name, lp->und_irq); | 1031 | dev->name, lp->und_irq); |
1032 | goto err_free_ovr_irq; | 1032 | goto err_free_ovr_irq; |
1033 | } | 1033 | } |
1034 | out: | ||
1035 | return ret; | ||
1034 | 1036 | ||
1035 | err_free_ovr_irq: | 1037 | err_free_ovr_irq: |
1036 | free_irq(lp->ovr_irq, dev); | 1038 | free_irq(lp->ovr_irq, dev); |
@@ -1041,8 +1043,6 @@ err_free_rx_irq: | |||
1041 | err_release: | 1043 | err_release: |
1042 | korina_free_ring(dev); | 1044 | korina_free_ring(dev); |
1043 | goto out; | 1045 | goto out; |
1044 | out: | ||
1045 | return ret; | ||
1046 | } | 1046 | } |
1047 | 1047 | ||
1048 | static int korina_close(struct net_device *dev) | 1048 | static int korina_close(struct net_device *dev) |
@@ -1082,7 +1082,7 @@ static int korina_probe(struct platform_device *pdev) | |||
1082 | struct korina_private *lp; | 1082 | struct korina_private *lp; |
1083 | struct net_device *dev; | 1083 | struct net_device *dev; |
1084 | struct resource *r; | 1084 | struct resource *r; |
1085 | int retval, err; | 1085 | int rc; |
1086 | 1086 | ||
1087 | dev = alloc_etherdev(sizeof(struct korina_private)); | 1087 | dev = alloc_etherdev(sizeof(struct korina_private)); |
1088 | if (!dev) { | 1088 | if (!dev) { |
@@ -1106,7 +1106,7 @@ static int korina_probe(struct platform_device *pdev) | |||
1106 | lp->eth_regs = ioremap_nocache(r->start, r->end - r->start); | 1106 | lp->eth_regs = ioremap_nocache(r->start, r->end - r->start); |
1107 | if (!lp->eth_regs) { | 1107 | if (!lp->eth_regs) { |
1108 | printk(KERN_ERR DRV_NAME "cannot remap registers\n"); | 1108 | printk(KERN_ERR DRV_NAME "cannot remap registers\n"); |
1109 | retval = -ENXIO; | 1109 | rc = -ENXIO; |
1110 | goto probe_err_out; | 1110 | goto probe_err_out; |
1111 | } | 1111 | } |
1112 | 1112 | ||
@@ -1114,7 +1114,7 @@ static int korina_probe(struct platform_device *pdev) | |||
1114 | lp->rx_dma_regs = ioremap_nocache(r->start, r->end - r->start); | 1114 | lp->rx_dma_regs = ioremap_nocache(r->start, r->end - r->start); |
1115 | if (!lp->rx_dma_regs) { | 1115 | if (!lp->rx_dma_regs) { |
1116 | printk(KERN_ERR DRV_NAME "cannot remap Rx DMA registers\n"); | 1116 | printk(KERN_ERR DRV_NAME "cannot remap Rx DMA registers\n"); |
1117 | retval = -ENXIO; | 1117 | rc = -ENXIO; |
1118 | goto probe_err_dma_rx; | 1118 | goto probe_err_dma_rx; |
1119 | } | 1119 | } |
1120 | 1120 | ||
@@ -1122,14 +1122,14 @@ static int korina_probe(struct platform_device *pdev) | |||
1122 | lp->tx_dma_regs = ioremap_nocache(r->start, r->end - r->start); | 1122 | lp->tx_dma_regs = ioremap_nocache(r->start, r->end - r->start); |
1123 | if (!lp->tx_dma_regs) { | 1123 | if (!lp->tx_dma_regs) { |
1124 | printk(KERN_ERR DRV_NAME "cannot remap Tx DMA registers\n"); | 1124 | printk(KERN_ERR DRV_NAME "cannot remap Tx DMA registers\n"); |
1125 | retval = -ENXIO; | 1125 | rc = -ENXIO; |
1126 | goto probe_err_dma_tx; | 1126 | goto probe_err_dma_tx; |
1127 | } | 1127 | } |
1128 | 1128 | ||
1129 | lp->td_ring = kmalloc(TD_RING_SIZE + RD_RING_SIZE, GFP_KERNEL); | 1129 | lp->td_ring = kmalloc(TD_RING_SIZE + RD_RING_SIZE, GFP_KERNEL); |
1130 | if (!lp->td_ring) { | 1130 | if (!lp->td_ring) { |
1131 | printk(KERN_ERR DRV_NAME "cannot allocate descriptors\n"); | 1131 | printk(KERN_ERR DRV_NAME "cannot allocate descriptors\n"); |
1132 | retval = -ENOMEM; | 1132 | rc = -ENXIO; |
1133 | goto probe_err_td_ring; | 1133 | goto probe_err_td_ring; |
1134 | } | 1134 | } |
1135 | 1135 | ||
@@ -1166,14 +1166,14 @@ static int korina_probe(struct platform_device *pdev) | |||
1166 | lp->mii_if.phy_id_mask = 0x1f; | 1166 | lp->mii_if.phy_id_mask = 0x1f; |
1167 | lp->mii_if.reg_num_mask = 0x1f; | 1167 | lp->mii_if.reg_num_mask = 0x1f; |
1168 | 1168 | ||
1169 | err = register_netdev(dev); | 1169 | rc = register_netdev(dev); |
1170 | if (err) { | 1170 | if (rc < 0) { |
1171 | printk(KERN_ERR DRV_NAME | 1171 | printk(KERN_ERR DRV_NAME |
1172 | ": cannot register net device %d\n", err); | 1172 | ": cannot register net device %d\n", rc); |
1173 | retval = -EINVAL; | ||
1174 | goto probe_err_register; | 1173 | goto probe_err_register; |
1175 | } | 1174 | } |
1176 | return 0; | 1175 | out: |
1176 | return rc; | ||
1177 | 1177 | ||
1178 | probe_err_register: | 1178 | probe_err_register: |
1179 | kfree(lp->td_ring); | 1179 | kfree(lp->td_ring); |
@@ -1185,7 +1185,7 @@ probe_err_dma_rx: | |||
1185 | iounmap(lp->eth_regs); | 1185 | iounmap(lp->eth_regs); |
1186 | probe_err_out: | 1186 | probe_err_out: |
1187 | free_netdev(dev); | 1187 | free_netdev(dev); |
1188 | return retval; | 1188 | goto out; |
1189 | } | 1189 | } |
1190 | 1190 | ||
1191 | static int korina_remove(struct platform_device *pdev) | 1191 | static int korina_remove(struct platform_device *pdev) |
@@ -1193,12 +1193,9 @@ static int korina_remove(struct platform_device *pdev) | |||
1193 | struct korina_device *bif = platform_get_drvdata(pdev); | 1193 | struct korina_device *bif = platform_get_drvdata(pdev); |
1194 | struct korina_private *lp = netdev_priv(bif->dev); | 1194 | struct korina_private *lp = netdev_priv(bif->dev); |
1195 | 1195 | ||
1196 | if (lp->eth_regs) | 1196 | iounmap(lp->eth_regs); |
1197 | iounmap(lp->eth_regs); | 1197 | iounmap(lp->rx_dma_regs); |
1198 | if (lp->rx_dma_regs) | 1198 | iounmap(lp->tx_dma_regs); |
1199 | iounmap(lp->rx_dma_regs); | ||
1200 | if (lp->tx_dma_regs) | ||
1201 | iounmap(lp->tx_dma_regs); | ||
1202 | 1199 | ||
1203 | platform_set_drvdata(pdev, NULL); | 1200 | platform_set_drvdata(pdev, NULL); |
1204 | unregister_netdev(bif->dev); | 1201 | unregister_netdev(bif->dev); |
diff --git a/drivers/net/macb.c b/drivers/net/macb.c index d513bb8a4902..92dccd43bdca 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c | |||
@@ -1281,6 +1281,7 @@ static struct platform_driver macb_driver = { | |||
1281 | .remove = __exit_p(macb_remove), | 1281 | .remove = __exit_p(macb_remove), |
1282 | .driver = { | 1282 | .driver = { |
1283 | .name = "macb", | 1283 | .name = "macb", |
1284 | .owner = THIS_MODULE, | ||
1284 | }, | 1285 | }, |
1285 | }; | 1286 | }; |
1286 | 1287 | ||
@@ -1300,3 +1301,4 @@ module_exit(macb_exit); | |||
1300 | MODULE_LICENSE("GPL"); | 1301 | MODULE_LICENSE("GPL"); |
1301 | MODULE_DESCRIPTION("Atmel MACB Ethernet driver"); | 1302 | MODULE_DESCRIPTION("Atmel MACB Ethernet driver"); |
1302 | MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>"); | 1303 | MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>"); |
1304 | MODULE_ALIAS("platform:macb"); | ||
diff --git a/drivers/net/meth.c b/drivers/net/meth.c index cdaa8fc21809..0b32648a2136 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c | |||
@@ -830,6 +830,7 @@ static struct platform_driver meth_driver = { | |||
830 | .remove = __devexit_p(meth_remove), | 830 | .remove = __devexit_p(meth_remove), |
831 | .driver = { | 831 | .driver = { |
832 | .name = "meth", | 832 | .name = "meth", |
833 | .owner = THIS_MODULE, | ||
833 | } | 834 | } |
834 | }; | 835 | }; |
835 | 836 | ||
@@ -855,3 +856,4 @@ module_exit(meth_exit_module); | |||
855 | MODULE_AUTHOR("Ilya Volynets <ilya@theIlya.com>"); | 856 | MODULE_AUTHOR("Ilya Volynets <ilya@theIlya.com>"); |
856 | MODULE_DESCRIPTION("SGI O2 Builtin Fast Ethernet driver"); | 857 | MODULE_DESCRIPTION("SGI O2 Builtin Fast Ethernet driver"); |
857 | MODULE_LICENSE("GPL"); | 858 | MODULE_LICENSE("GPL"); |
859 | MODULE_ALIAS("platform:meth"); | ||
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 601ffd69ebc8..381b36e5f64c 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c | |||
@@ -2030,6 +2030,7 @@ static struct platform_driver mv643xx_eth_driver = { | |||
2030 | .shutdown = mv643xx_eth_shutdown, | 2030 | .shutdown = mv643xx_eth_shutdown, |
2031 | .driver = { | 2031 | .driver = { |
2032 | .name = MV643XX_ETH_NAME, | 2032 | .name = MV643XX_ETH_NAME, |
2033 | .owner = THIS_MODULE, | ||
2033 | }, | 2034 | }, |
2034 | }; | 2035 | }; |
2035 | 2036 | ||
@@ -2038,6 +2039,7 @@ static struct platform_driver mv643xx_eth_shared_driver = { | |||
2038 | .remove = mv643xx_eth_shared_remove, | 2039 | .remove = mv643xx_eth_shared_remove, |
2039 | .driver = { | 2040 | .driver = { |
2040 | .name = MV643XX_ETH_SHARED_NAME, | 2041 | .name = MV643XX_ETH_SHARED_NAME, |
2042 | .owner = THIS_MODULE, | ||
2041 | }, | 2043 | }, |
2042 | }; | 2044 | }; |
2043 | 2045 | ||
@@ -2085,7 +2087,8 @@ MODULE_LICENSE("GPL"); | |||
2085 | MODULE_AUTHOR( "Rabeeh Khoury, Assaf Hoffman, Matthew Dharm, Manish Lachwani" | 2087 | MODULE_AUTHOR( "Rabeeh Khoury, Assaf Hoffman, Matthew Dharm, Manish Lachwani" |
2086 | " and Dale Farnsworth"); | 2088 | " and Dale Farnsworth"); |
2087 | MODULE_DESCRIPTION("Ethernet driver for Marvell MV643XX"); | 2089 | MODULE_DESCRIPTION("Ethernet driver for Marvell MV643XX"); |
2088 | MODULE_ALIAS("platform:mv643xx_eth"); | 2090 | MODULE_ALIAS("platform:" MV643XX_ETH_NAME); |
2091 | MODULE_ALIAS("platform:" MV643XX_ETH_SHARED_NAME); | ||
2089 | 2092 | ||
2090 | /* | 2093 | /* |
2091 | * The second part is the low level driver of the gigE ethernet ports. | 2094 | * The second part is the low level driver of the gigE ethernet ports. |
diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c index 78d34af13a1c..dc442e370850 100644 --- a/drivers/net/netx-eth.c +++ b/drivers/net/netx-eth.c | |||
@@ -502,4 +502,4 @@ module_exit(netx_eth_cleanup); | |||
502 | 502 | ||
503 | MODULE_AUTHOR("Sascha Hauer, Pengutronix"); | 503 | MODULE_AUTHOR("Sascha Hauer, Pengutronix"); |
504 | MODULE_LICENSE("GPL"); | 504 | MODULE_LICENSE("GPL"); |
505 | 505 | MODULE_ALIAS("platform:" CARDNAME); | |
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 05748ca6f216..af7356468251 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c | |||
@@ -1132,8 +1132,8 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter) | |||
1132 | u32 fw_minor = 0; | 1132 | u32 fw_minor = 0; |
1133 | u32 fw_build = 0; | 1133 | u32 fw_build = 0; |
1134 | char brd_name[NETXEN_MAX_SHORT_NAME]; | 1134 | char brd_name[NETXEN_MAX_SHORT_NAME]; |
1135 | struct netxen_new_user_info user_info; | 1135 | char serial_num[32]; |
1136 | int i, addr = NETXEN_USER_START; | 1136 | int i, addr; |
1137 | __le32 *ptr32; | 1137 | __le32 *ptr32; |
1138 | 1138 | ||
1139 | struct netxen_board_info *board_info = &(adapter->ahw.boardcfg); | 1139 | struct netxen_board_info *board_info = &(adapter->ahw.boardcfg); |
@@ -1150,10 +1150,10 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter) | |||
1150 | valid = 0; | 1150 | valid = 0; |
1151 | } | 1151 | } |
1152 | if (valid) { | 1152 | if (valid) { |
1153 | ptr32 = (u32 *) & user_info; | 1153 | ptr32 = (u32 *)&serial_num; |
1154 | for (i = 0; | 1154 | addr = NETXEN_USER_START + |
1155 | i < sizeof(struct netxen_new_user_info) / sizeof(u32); | 1155 | offsetof(struct netxen_new_user_info, serial_num); |
1156 | i++) { | 1156 | for (i = 0; i < 8; i++) { |
1157 | if (netxen_rom_fast_read(adapter, addr, ptr32) == -1) { | 1157 | if (netxen_rom_fast_read(adapter, addr, ptr32) == -1) { |
1158 | printk("%s: ERROR reading %s board userarea.\n", | 1158 | printk("%s: ERROR reading %s board userarea.\n", |
1159 | netxen_nic_driver_name, | 1159 | netxen_nic_driver_name, |
@@ -1163,10 +1163,11 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter) | |||
1163 | ptr32++; | 1163 | ptr32++; |
1164 | addr += sizeof(u32); | 1164 | addr += sizeof(u32); |
1165 | } | 1165 | } |
1166 | |||
1166 | get_brd_name_by_type(board_info->board_type, brd_name); | 1167 | get_brd_name_by_type(board_info->board_type, brd_name); |
1167 | 1168 | ||
1168 | printk("NetXen %s Board S/N %s Chip id 0x%x\n", | 1169 | printk("NetXen %s Board S/N %s Chip id 0x%x\n", |
1169 | brd_name, user_info.serial_num, board_info->chip_id); | 1170 | brd_name, serial_num, board_info->chip_id); |
1170 | 1171 | ||
1171 | printk("NetXen %s Board #%d, Chip id 0x%x\n", | 1172 | printk("NetXen %s Board #%d, Chip id 0x%x\n", |
1172 | board_info->board_type == 0x0b ? "XGB" : "GBE", | 1173 | board_info->board_type == 0x0b ? "XGB" : "GBE", |
diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 7565c2d7f30e..4009c4ce96b4 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c | |||
@@ -33,8 +33,8 @@ | |||
33 | 33 | ||
34 | #define DRV_MODULE_NAME "niu" | 34 | #define DRV_MODULE_NAME "niu" |
35 | #define PFX DRV_MODULE_NAME ": " | 35 | #define PFX DRV_MODULE_NAME ": " |
36 | #define DRV_MODULE_VERSION "0.7" | 36 | #define DRV_MODULE_VERSION "0.8" |
37 | #define DRV_MODULE_RELDATE "February 18, 2008" | 37 | #define DRV_MODULE_RELDATE "April 24, 2008" |
38 | 38 | ||
39 | static char version[] __devinitdata = | 39 | static char version[] __devinitdata = |
40 | DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; | 40 | DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; |
@@ -673,11 +673,16 @@ static int serdes_init_10g(struct niu *np) | |||
673 | } | 673 | } |
674 | 674 | ||
675 | if ((sig & mask) != val) { | 675 | if ((sig & mask) != val) { |
676 | if (np->flags & NIU_FLAGS_HOTPLUG_PHY) { | ||
677 | np->flags &= ~NIU_FLAGS_HOTPLUG_PHY_PRESENT; | ||
678 | return 0; | ||
679 | } | ||
676 | dev_err(np->device, PFX "Port %u signal bits [%08x] are not " | 680 | dev_err(np->device, PFX "Port %u signal bits [%08x] are not " |
677 | "[%08x]\n", np->port, (int) (sig & mask), (int) val); | 681 | "[%08x]\n", np->port, (int) (sig & mask), (int) val); |
678 | return -ENODEV; | 682 | return -ENODEV; |
679 | } | 683 | } |
680 | 684 | if (np->flags & NIU_FLAGS_HOTPLUG_PHY) | |
685 | np->flags |= NIU_FLAGS_HOTPLUG_PHY_PRESENT; | ||
681 | return 0; | 686 | return 0; |
682 | } | 687 | } |
683 | 688 | ||
@@ -998,6 +1003,28 @@ static int bcm8704_user_dev3_readback(struct niu *np, int reg) | |||
998 | return 0; | 1003 | return 0; |
999 | } | 1004 | } |
1000 | 1005 | ||
1006 | static int bcm8706_init_user_dev3(struct niu *np) | ||
1007 | { | ||
1008 | int err; | ||
1009 | |||
1010 | |||
1011 | err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, | ||
1012 | BCM8704_USER_OPT_DIGITAL_CTRL); | ||
1013 | if (err < 0) | ||
1014 | return err; | ||
1015 | err &= ~USER_ODIG_CTRL_GPIOS; | ||
1016 | err |= (0x3 << USER_ODIG_CTRL_GPIOS_SHIFT); | ||
1017 | err |= USER_ODIG_CTRL_RESV2; | ||
1018 | err = mdio_write(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, | ||
1019 | BCM8704_USER_OPT_DIGITAL_CTRL, err); | ||
1020 | if (err) | ||
1021 | return err; | ||
1022 | |||
1023 | mdelay(1000); | ||
1024 | |||
1025 | return 0; | ||
1026 | } | ||
1027 | |||
1001 | static int bcm8704_init_user_dev3(struct niu *np) | 1028 | static int bcm8704_init_user_dev3(struct niu *np) |
1002 | { | 1029 | { |
1003 | int err; | 1030 | int err; |
@@ -1127,33 +1154,11 @@ static int xcvr_init_10g_mrvl88x2011(struct niu *np) | |||
1127 | MRVL88X2011_10G_PMD_TX_DIS, MRVL88X2011_ENA_PMDTX); | 1154 | MRVL88X2011_10G_PMD_TX_DIS, MRVL88X2011_ENA_PMDTX); |
1128 | } | 1155 | } |
1129 | 1156 | ||
1130 | static int xcvr_init_10g_bcm8704(struct niu *np) | 1157 | |
1158 | static int xcvr_diag_bcm870x(struct niu *np) | ||
1131 | { | 1159 | { |
1132 | struct niu_link_config *lp = &np->link_config; | ||
1133 | u16 analog_stat0, tx_alarm_status; | 1160 | u16 analog_stat0, tx_alarm_status; |
1134 | int err; | 1161 | int err = 0; |
1135 | |||
1136 | err = bcm8704_reset(np); | ||
1137 | if (err) | ||
1138 | return err; | ||
1139 | |||
1140 | err = bcm8704_init_user_dev3(np); | ||
1141 | if (err) | ||
1142 | return err; | ||
1143 | |||
1144 | err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR, | ||
1145 | MII_BMCR); | ||
1146 | if (err < 0) | ||
1147 | return err; | ||
1148 | err &= ~BMCR_LOOPBACK; | ||
1149 | |||
1150 | if (lp->loopback_mode == LOOPBACK_MAC) | ||
1151 | err |= BMCR_LOOPBACK; | ||
1152 | |||
1153 | err = mdio_write(np, np->phy_addr, BCM8704_PCS_DEV_ADDR, | ||
1154 | MII_BMCR, err); | ||
1155 | if (err) | ||
1156 | return err; | ||
1157 | 1162 | ||
1158 | #if 1 | 1163 | #if 1 |
1159 | err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR, | 1164 | err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR, |
@@ -1211,6 +1216,89 @@ static int xcvr_init_10g_bcm8704(struct niu *np) | |||
1211 | return 0; | 1216 | return 0; |
1212 | } | 1217 | } |
1213 | 1218 | ||
1219 | static int xcvr_10g_set_lb_bcm870x(struct niu *np) | ||
1220 | { | ||
1221 | struct niu_link_config *lp = &np->link_config; | ||
1222 | int err; | ||
1223 | |||
1224 | err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR, | ||
1225 | MII_BMCR); | ||
1226 | if (err < 0) | ||
1227 | return err; | ||
1228 | |||
1229 | err &= ~BMCR_LOOPBACK; | ||
1230 | |||
1231 | if (lp->loopback_mode == LOOPBACK_MAC) | ||
1232 | err |= BMCR_LOOPBACK; | ||
1233 | |||
1234 | err = mdio_write(np, np->phy_addr, BCM8704_PCS_DEV_ADDR, | ||
1235 | MII_BMCR, err); | ||
1236 | if (err) | ||
1237 | return err; | ||
1238 | |||
1239 | return 0; | ||
1240 | } | ||
1241 | |||
1242 | static int xcvr_init_10g_bcm8706(struct niu *np) | ||
1243 | { | ||
1244 | int err = 0; | ||
1245 | u64 val; | ||
1246 | |||
1247 | if ((np->flags & NIU_FLAGS_HOTPLUG_PHY) && | ||
1248 | (np->flags & NIU_FLAGS_HOTPLUG_PHY_PRESENT) == 0) | ||
1249 | return err; | ||
1250 | |||
1251 | val = nr64_mac(XMAC_CONFIG); | ||
1252 | val &= ~XMAC_CONFIG_LED_POLARITY; | ||
1253 | val |= XMAC_CONFIG_FORCE_LED_ON; | ||
1254 | nw64_mac(XMAC_CONFIG, val); | ||
1255 | |||
1256 | val = nr64(MIF_CONFIG); | ||
1257 | val |= MIF_CONFIG_INDIRECT_MODE; | ||
1258 | nw64(MIF_CONFIG, val); | ||
1259 | |||
1260 | err = bcm8704_reset(np); | ||
1261 | if (err) | ||
1262 | return err; | ||
1263 | |||
1264 | err = xcvr_10g_set_lb_bcm870x(np); | ||
1265 | if (err) | ||
1266 | return err; | ||
1267 | |||
1268 | err = bcm8706_init_user_dev3(np); | ||
1269 | if (err) | ||
1270 | return err; | ||
1271 | |||
1272 | err = xcvr_diag_bcm870x(np); | ||
1273 | if (err) | ||
1274 | return err; | ||
1275 | |||
1276 | return 0; | ||
1277 | } | ||
1278 | |||
1279 | static int xcvr_init_10g_bcm8704(struct niu *np) | ||
1280 | { | ||
1281 | int err; | ||
1282 | |||
1283 | err = bcm8704_reset(np); | ||
1284 | if (err) | ||
1285 | return err; | ||
1286 | |||
1287 | err = bcm8704_init_user_dev3(np); | ||
1288 | if (err) | ||
1289 | return err; | ||
1290 | |||
1291 | err = xcvr_10g_set_lb_bcm870x(np); | ||
1292 | if (err) | ||
1293 | return err; | ||
1294 | |||
1295 | err = xcvr_diag_bcm870x(np); | ||
1296 | if (err) | ||
1297 | return err; | ||
1298 | |||
1299 | return 0; | ||
1300 | } | ||
1301 | |||
1214 | static int xcvr_init_10g(struct niu *np) | 1302 | static int xcvr_init_10g(struct niu *np) |
1215 | { | 1303 | { |
1216 | int phy_id, err; | 1304 | int phy_id, err; |
@@ -1548,6 +1636,59 @@ out: | |||
1548 | return err; | 1636 | return err; |
1549 | } | 1637 | } |
1550 | 1638 | ||
1639 | static int link_status_10g_bcm8706(struct niu *np, int *link_up_p) | ||
1640 | { | ||
1641 | int err, link_up; | ||
1642 | link_up = 0; | ||
1643 | |||
1644 | err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR, | ||
1645 | BCM8704_PMD_RCV_SIGDET); | ||
1646 | if (err < 0) | ||
1647 | goto out; | ||
1648 | if (!(err & PMD_RCV_SIGDET_GLOBAL)) { | ||
1649 | err = 0; | ||
1650 | goto out; | ||
1651 | } | ||
1652 | |||
1653 | err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR, | ||
1654 | BCM8704_PCS_10G_R_STATUS); | ||
1655 | if (err < 0) | ||
1656 | goto out; | ||
1657 | |||
1658 | if (!(err & PCS_10G_R_STATUS_BLK_LOCK)) { | ||
1659 | err = 0; | ||
1660 | goto out; | ||
1661 | } | ||
1662 | |||
1663 | err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR, | ||
1664 | BCM8704_PHYXS_XGXS_LANE_STAT); | ||
1665 | if (err < 0) | ||
1666 | goto out; | ||
1667 | if (err != (PHYXS_XGXS_LANE_STAT_ALINGED | | ||
1668 | PHYXS_XGXS_LANE_STAT_MAGIC | | ||
1669 | PHYXS_XGXS_LANE_STAT_PATTEST | | ||
1670 | PHYXS_XGXS_LANE_STAT_LANE3 | | ||
1671 | PHYXS_XGXS_LANE_STAT_LANE2 | | ||
1672 | PHYXS_XGXS_LANE_STAT_LANE1 | | ||
1673 | PHYXS_XGXS_LANE_STAT_LANE0)) { | ||
1674 | err = 0; | ||
1675 | np->link_config.active_speed = SPEED_INVALID; | ||
1676 | np->link_config.active_duplex = DUPLEX_INVALID; | ||
1677 | goto out; | ||
1678 | } | ||
1679 | |||
1680 | link_up = 1; | ||
1681 | np->link_config.active_speed = SPEED_10000; | ||
1682 | np->link_config.active_duplex = DUPLEX_FULL; | ||
1683 | err = 0; | ||
1684 | |||
1685 | out: | ||
1686 | *link_up_p = link_up; | ||
1687 | if (np->flags & NIU_FLAGS_HOTPLUG_PHY) | ||
1688 | err = 0; | ||
1689 | return err; | ||
1690 | } | ||
1691 | |||
1551 | static int link_status_10g_bcom(struct niu *np, int *link_up_p) | 1692 | static int link_status_10g_bcom(struct niu *np, int *link_up_p) |
1552 | { | 1693 | { |
1553 | int err, link_up; | 1694 | int err, link_up; |
@@ -1627,6 +1768,82 @@ static int link_status_10g(struct niu *np, int *link_up_p) | |||
1627 | return err; | 1768 | return err; |
1628 | } | 1769 | } |
1629 | 1770 | ||
1771 | static int niu_10g_phy_present(struct niu *np) | ||
1772 | { | ||
1773 | u64 sig, mask, val; | ||
1774 | |||
1775 | sig = nr64(ESR_INT_SIGNALS); | ||
1776 | switch (np->port) { | ||
1777 | case 0: | ||
1778 | mask = ESR_INT_SIGNALS_P0_BITS; | ||
1779 | val = (ESR_INT_SRDY0_P0 | | ||
1780 | ESR_INT_DET0_P0 | | ||
1781 | ESR_INT_XSRDY_P0 | | ||
1782 | ESR_INT_XDP_P0_CH3 | | ||
1783 | ESR_INT_XDP_P0_CH2 | | ||
1784 | ESR_INT_XDP_P0_CH1 | | ||
1785 | ESR_INT_XDP_P0_CH0); | ||
1786 | break; | ||
1787 | |||
1788 | case 1: | ||
1789 | mask = ESR_INT_SIGNALS_P1_BITS; | ||
1790 | val = (ESR_INT_SRDY0_P1 | | ||
1791 | ESR_INT_DET0_P1 | | ||
1792 | ESR_INT_XSRDY_P1 | | ||
1793 | ESR_INT_XDP_P1_CH3 | | ||
1794 | ESR_INT_XDP_P1_CH2 | | ||
1795 | ESR_INT_XDP_P1_CH1 | | ||
1796 | ESR_INT_XDP_P1_CH0); | ||
1797 | break; | ||
1798 | |||
1799 | default: | ||
1800 | return 0; | ||
1801 | } | ||
1802 | |||
1803 | if ((sig & mask) != val) | ||
1804 | return 0; | ||
1805 | return 1; | ||
1806 | } | ||
1807 | |||
1808 | static int link_status_10g_hotplug(struct niu *np, int *link_up_p) | ||
1809 | { | ||
1810 | unsigned long flags; | ||
1811 | int err = 0; | ||
1812 | int phy_present; | ||
1813 | int phy_present_prev; | ||
1814 | |||
1815 | spin_lock_irqsave(&np->lock, flags); | ||
1816 | |||
1817 | if (np->link_config.loopback_mode == LOOPBACK_DISABLED) { | ||
1818 | phy_present_prev = (np->flags & NIU_FLAGS_HOTPLUG_PHY_PRESENT) ? | ||
1819 | 1 : 0; | ||
1820 | phy_present = niu_10g_phy_present(np); | ||
1821 | if (phy_present != phy_present_prev) { | ||
1822 | /* state change */ | ||
1823 | if (phy_present) { | ||
1824 | np->flags |= NIU_FLAGS_HOTPLUG_PHY_PRESENT; | ||
1825 | if (np->phy_ops->xcvr_init) | ||
1826 | err = np->phy_ops->xcvr_init(np); | ||
1827 | if (err) { | ||
1828 | /* debounce */ | ||
1829 | np->flags &= ~NIU_FLAGS_HOTPLUG_PHY_PRESENT; | ||
1830 | } | ||
1831 | } else { | ||
1832 | np->flags &= ~NIU_FLAGS_HOTPLUG_PHY_PRESENT; | ||
1833 | *link_up_p = 0; | ||
1834 | niuwarn(LINK, "%s: Hotplug PHY Removed\n", | ||
1835 | np->dev->name); | ||
1836 | } | ||
1837 | } | ||
1838 | if (np->flags & NIU_FLAGS_HOTPLUG_PHY_PRESENT) | ||
1839 | err = link_status_10g_bcm8706(np, link_up_p); | ||
1840 | } | ||
1841 | |||
1842 | spin_unlock_irqrestore(&np->lock, flags); | ||
1843 | |||
1844 | return err; | ||
1845 | } | ||
1846 | |||
1630 | static int link_status_1g(struct niu *np, int *link_up_p) | 1847 | static int link_status_1g(struct niu *np, int *link_up_p) |
1631 | { | 1848 | { |
1632 | struct niu_link_config *lp = &np->link_config; | 1849 | struct niu_link_config *lp = &np->link_config; |
@@ -1761,6 +1978,12 @@ static const struct niu_phy_ops phy_ops_10g_fiber = { | |||
1761 | .link_status = link_status_10g, | 1978 | .link_status = link_status_10g, |
1762 | }; | 1979 | }; |
1763 | 1980 | ||
1981 | static const struct niu_phy_ops phy_ops_10g_fiber_hotplug = { | ||
1982 | .serdes_init = serdes_init_10g, | ||
1983 | .xcvr_init = xcvr_init_10g_bcm8706, | ||
1984 | .link_status = link_status_10g_hotplug, | ||
1985 | }; | ||
1986 | |||
1764 | static const struct niu_phy_ops phy_ops_10g_copper = { | 1987 | static const struct niu_phy_ops phy_ops_10g_copper = { |
1765 | .serdes_init = serdes_init_10g, | 1988 | .serdes_init = serdes_init_10g, |
1766 | .link_status = link_status_10g, /* XXX */ | 1989 | .link_status = link_status_10g, /* XXX */ |
@@ -1792,6 +2015,11 @@ static const struct niu_phy_template phy_template_10g_fiber = { | |||
1792 | .phy_addr_base = 8, | 2015 | .phy_addr_base = 8, |
1793 | }; | 2016 | }; |
1794 | 2017 | ||
2018 | static const struct niu_phy_template phy_template_10g_fiber_hotplug = { | ||
2019 | .ops = &phy_ops_10g_fiber_hotplug, | ||
2020 | .phy_addr_base = 8, | ||
2021 | }; | ||
2022 | |||
1795 | static const struct niu_phy_template phy_template_10g_copper = { | 2023 | static const struct niu_phy_template phy_template_10g_copper = { |
1796 | .ops = &phy_ops_10g_copper, | 2024 | .ops = &phy_ops_10g_copper, |
1797 | .phy_addr_base = 10, | 2025 | .phy_addr_base = 10, |
@@ -1996,6 +2224,13 @@ static int niu_determine_phy_disposition(struct niu *np) | |||
1996 | plat_type == PLAT_TYPE_VF_P1) | 2224 | plat_type == PLAT_TYPE_VF_P1) |
1997 | phy_addr_off = 8; | 2225 | phy_addr_off = 8; |
1998 | phy_addr_off += np->port; | 2226 | phy_addr_off += np->port; |
2227 | if (np->flags & NIU_FLAGS_HOTPLUG_PHY) { | ||
2228 | tp = &phy_template_10g_fiber_hotplug; | ||
2229 | if (np->port == 0) | ||
2230 | phy_addr_off = 8; | ||
2231 | if (np->port == 1) | ||
2232 | phy_addr_off = 12; | ||
2233 | } | ||
1999 | break; | 2234 | break; |
2000 | 2235 | ||
2001 | case NIU_FLAGS_10G | NIU_FLAGS_XCVR_SERDES: | 2236 | case NIU_FLAGS_10G | NIU_FLAGS_XCVR_SERDES: |
@@ -6773,6 +7008,37 @@ static int __devinit niu_phy_type_prop_decode(struct niu *np, | |||
6773 | return 0; | 7008 | return 0; |
6774 | } | 7009 | } |
6775 | 7010 | ||
7011 | /* niu board models have a trailing dash version incremented | ||
7012 | * with HW rev change. Need to ingnore the dash version while | ||
7013 | * checking for match | ||
7014 | * | ||
7015 | * for example, for the 10G card the current vpd.board_model | ||
7016 | * is 501-5283-04, of which -04 is the dash version and have | ||
7017 | * to be ignored | ||
7018 | */ | ||
7019 | static int niu_board_model_match(struct niu *np, const char *model) | ||
7020 | { | ||
7021 | return !strncmp(np->vpd.board_model, model, strlen(model)); | ||
7022 | } | ||
7023 | |||
7024 | static int niu_pci_vpd_get_nports(struct niu *np) | ||
7025 | { | ||
7026 | int ports = 0; | ||
7027 | |||
7028 | if ((niu_board_model_match(np, NIU_QGC_LP_BM_STR)) || | ||
7029 | (niu_board_model_match(np, NIU_QGC_PEM_BM_STR)) || | ||
7030 | (niu_board_model_match(np, NIU_ALONSO_BM_STR))) { | ||
7031 | ports = 4; | ||
7032 | } else if ((niu_board_model_match(np, NIU_2XGF_LP_BM_STR)) || | ||
7033 | (niu_board_model_match(np, NIU_2XGF_PEM_BM_STR)) || | ||
7034 | (niu_board_model_match(np, NIU_FOXXY_BM_STR)) || | ||
7035 | (niu_board_model_match(np, NIU_2XGF_MRVL_BM_STR))) { | ||
7036 | ports = 2; | ||
7037 | } | ||
7038 | |||
7039 | return ports; | ||
7040 | } | ||
7041 | |||
6776 | static void __devinit niu_pci_vpd_validate(struct niu *np) | 7042 | static void __devinit niu_pci_vpd_validate(struct niu *np) |
6777 | { | 7043 | { |
6778 | struct net_device *dev = np->dev; | 7044 | struct net_device *dev = np->dev; |
@@ -6799,6 +7065,9 @@ static void __devinit niu_pci_vpd_validate(struct niu *np) | |||
6799 | } | 7065 | } |
6800 | if (np->flags & NIU_FLAGS_10G) | 7066 | if (np->flags & NIU_FLAGS_10G) |
6801 | np->mac_xcvr = MAC_XCVR_XPCS; | 7067 | np->mac_xcvr = MAC_XCVR_XPCS; |
7068 | } else if (niu_board_model_match(np, NIU_FOXXY_BM_STR)) { | ||
7069 | np->flags |= (NIU_FLAGS_10G | NIU_FLAGS_FIBER | | ||
7070 | NIU_FLAGS_HOTPLUG_PHY); | ||
6802 | } else if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) { | 7071 | } else if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) { |
6803 | dev_err(np->device, PFX "Illegal phy string [%s].\n", | 7072 | dev_err(np->device, PFX "Illegal phy string [%s].\n", |
6804 | np->vpd.phy_type); | 7073 | np->vpd.phy_type); |
@@ -6987,11 +7256,17 @@ static int __devinit niu_get_and_validate_port(struct niu *np) | |||
6987 | if (parent->plat_type == PLAT_TYPE_NIU) { | 7256 | if (parent->plat_type == PLAT_TYPE_NIU) { |
6988 | parent->num_ports = 2; | 7257 | parent->num_ports = 2; |
6989 | } else { | 7258 | } else { |
6990 | parent->num_ports = nr64(ESPC_NUM_PORTS_MACS) & | 7259 | parent->num_ports = niu_pci_vpd_get_nports(np); |
6991 | ESPC_NUM_PORTS_MACS_VAL; | 7260 | if (!parent->num_ports) { |
6992 | 7261 | /* Fall back to SPROM as last resort. | |
6993 | if (!parent->num_ports) | 7262 | * This will fail on most cards. |
6994 | parent->num_ports = 4; | 7263 | */ |
7264 | parent->num_ports = nr64(ESPC_NUM_PORTS_MACS) & | ||
7265 | ESPC_NUM_PORTS_MACS_VAL; | ||
7266 | |||
7267 | if (!parent->num_ports) | ||
7268 | return -ENODEV; | ||
7269 | } | ||
6995 | } | 7270 | } |
6996 | } | 7271 | } |
6997 | 7272 | ||
@@ -7015,7 +7290,8 @@ static int __devinit phy_record(struct niu_parent *parent, | |||
7015 | return 0; | 7290 | return 0; |
7016 | if (type == PHY_TYPE_PMA_PMD || type == PHY_TYPE_PCS) { | 7291 | if (type == PHY_TYPE_PMA_PMD || type == PHY_TYPE_PCS) { |
7017 | if (((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8704) && | 7292 | if (((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8704) && |
7018 | ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_MRVL88X2011)) | 7293 | ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_MRVL88X2011) && |
7294 | ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8706)) | ||
7019 | return 0; | 7295 | return 0; |
7020 | } else { | 7296 | } else { |
7021 | if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM5464R) | 7297 | if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM5464R) |
@@ -7262,7 +7538,6 @@ static int __devinit walk_phys(struct niu *np, struct niu_parent *parent) | |||
7262 | u32 val; | 7538 | u32 val; |
7263 | int err; | 7539 | int err; |
7264 | 7540 | ||
7265 | |||
7266 | if (!strcmp(np->vpd.model, "SUNW,CP3220") || | 7541 | if (!strcmp(np->vpd.model, "SUNW,CP3220") || |
7267 | !strcmp(np->vpd.model, "SUNW,CP3260")) { | 7542 | !strcmp(np->vpd.model, "SUNW,CP3260")) { |
7268 | num_10g = 0; | 7543 | num_10g = 0; |
@@ -7273,6 +7548,12 @@ static int __devinit walk_phys(struct niu *np, struct niu_parent *parent) | |||
7273 | phy_encode(PORT_TYPE_1G, 1) | | 7548 | phy_encode(PORT_TYPE_1G, 1) | |
7274 | phy_encode(PORT_TYPE_1G, 2) | | 7549 | phy_encode(PORT_TYPE_1G, 2) | |
7275 | phy_encode(PORT_TYPE_1G, 3)); | 7550 | phy_encode(PORT_TYPE_1G, 3)); |
7551 | } else if (niu_board_model_match(np, NIU_FOXXY_BM_STR)) { | ||
7552 | num_10g = 2; | ||
7553 | num_1g = 0; | ||
7554 | parent->num_ports = 2; | ||
7555 | val = (phy_encode(PORT_TYPE_10G, 0) | | ||
7556 | phy_encode(PORT_TYPE_10G, 1)); | ||
7276 | } else { | 7557 | } else { |
7277 | err = fill_phy_probe_info(np, parent, info); | 7558 | err = fill_phy_probe_info(np, parent, info); |
7278 | if (err) | 7559 | if (err) |
@@ -7733,15 +8014,16 @@ static int __devinit niu_get_invariants(struct niu *np) | |||
7733 | 8014 | ||
7734 | have_props = !err; | 8015 | have_props = !err; |
7735 | 8016 | ||
7736 | err = niu_get_and_validate_port(np); | ||
7737 | if (err) | ||
7738 | return err; | ||
7739 | |||
7740 | err = niu_init_mac_ipp_pcs_base(np); | 8017 | err = niu_init_mac_ipp_pcs_base(np); |
7741 | if (err) | 8018 | if (err) |
7742 | return err; | 8019 | return err; |
7743 | 8020 | ||
7744 | if (!have_props) { | 8021 | if (have_props) { |
8022 | err = niu_get_and_validate_port(np); | ||
8023 | if (err) | ||
8024 | return err; | ||
8025 | |||
8026 | } else { | ||
7745 | if (np->parent->plat_type == PLAT_TYPE_NIU) | 8027 | if (np->parent->plat_type == PLAT_TYPE_NIU) |
7746 | return -EINVAL; | 8028 | return -EINVAL; |
7747 | 8029 | ||
@@ -7753,10 +8035,17 @@ static int __devinit niu_get_invariants(struct niu *np) | |||
7753 | niu_pci_vpd_fetch(np, offset); | 8035 | niu_pci_vpd_fetch(np, offset); |
7754 | nw64(ESPC_PIO_EN, 0); | 8036 | nw64(ESPC_PIO_EN, 0); |
7755 | 8037 | ||
7756 | if (np->flags & NIU_FLAGS_VPD_VALID) | 8038 | if (np->flags & NIU_FLAGS_VPD_VALID) { |
7757 | niu_pci_vpd_validate(np); | 8039 | niu_pci_vpd_validate(np); |
8040 | err = niu_get_and_validate_port(np); | ||
8041 | if (err) | ||
8042 | return err; | ||
8043 | } | ||
7758 | 8044 | ||
7759 | if (!(np->flags & NIU_FLAGS_VPD_VALID)) { | 8045 | if (!(np->flags & NIU_FLAGS_VPD_VALID)) { |
8046 | err = niu_get_and_validate_port(np); | ||
8047 | if (err) | ||
8048 | return err; | ||
7760 | err = niu_pci_probe_sprom(np); | 8049 | err = niu_pci_probe_sprom(np); |
7761 | if (err) | 8050 | if (err) |
7762 | return err; | 8051 | return err; |
diff --git a/drivers/net/niu.h b/drivers/net/niu.h index 336aed08b275..97ffbe137bcb 100644 --- a/drivers/net/niu.h +++ b/drivers/net/niu.h | |||
@@ -2537,6 +2537,7 @@ struct fcram_hash_ipv6 { | |||
2537 | 2537 | ||
2538 | #define NIU_PHY_ID_MASK 0xfffff0f0 | 2538 | #define NIU_PHY_ID_MASK 0xfffff0f0 |
2539 | #define NIU_PHY_ID_BCM8704 0x00206030 | 2539 | #define NIU_PHY_ID_BCM8704 0x00206030 |
2540 | #define NIU_PHY_ID_BCM8706 0x00206035 | ||
2540 | #define NIU_PHY_ID_BCM5464R 0x002060b0 | 2541 | #define NIU_PHY_ID_BCM5464R 0x002060b0 |
2541 | #define NIU_PHY_ID_MRVL88X2011 0x01410020 | 2542 | #define NIU_PHY_ID_MRVL88X2011 0x01410020 |
2542 | 2543 | ||
@@ -2937,6 +2938,15 @@ struct rx_ring_info { | |||
2937 | 2938 | ||
2938 | #define NIU_MAX_MTU 9216 | 2939 | #define NIU_MAX_MTU 9216 |
2939 | 2940 | ||
2941 | /* VPD strings */ | ||
2942 | #define NIU_QGC_LP_BM_STR "501-7606" | ||
2943 | #define NIU_2XGF_LP_BM_STR "501-7283" | ||
2944 | #define NIU_QGC_PEM_BM_STR "501-7765" | ||
2945 | #define NIU_2XGF_PEM_BM_STR "501-7626" | ||
2946 | #define NIU_ALONSO_BM_STR "373-0202" | ||
2947 | #define NIU_FOXXY_BM_STR "501-7961" | ||
2948 | #define NIU_2XGF_MRVL_BM_STR "SK-6E82" | ||
2949 | |||
2940 | #define NIU_VPD_MIN_MAJOR 3 | 2950 | #define NIU_VPD_MIN_MAJOR 3 |
2941 | #define NIU_VPD_MIN_MINOR 4 | 2951 | #define NIU_VPD_MIN_MINOR 4 |
2942 | 2952 | ||
@@ -3199,6 +3209,8 @@ struct niu { | |||
3199 | struct niu_parent *parent; | 3209 | struct niu_parent *parent; |
3200 | 3210 | ||
3201 | u32 flags; | 3211 | u32 flags; |
3212 | #define NIU_FLAGS_HOTPLUG_PHY_PRESENT 0x02000000 /* Removebale PHY detected*/ | ||
3213 | #define NIU_FLAGS_HOTPLUG_PHY 0x01000000 /* Removebale PHY */ | ||
3202 | #define NIU_FLAGS_VPD_VALID 0x00800000 /* VPD has valid version */ | 3214 | #define NIU_FLAGS_VPD_VALID 0x00800000 /* VPD has valid version */ |
3203 | #define NIU_FLAGS_MSIX 0x00400000 /* MSI-X in use */ | 3215 | #define NIU_FLAGS_MSIX 0x00400000 /* MSI-X in use */ |
3204 | #define NIU_FLAGS_MCAST 0x00200000 /* multicast filter enabled */ | 3216 | #define NIU_FLAGS_MCAST 0x00200000 /* multicast filter enabled */ |
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 963630c65ca9..94e0b7ed76f1 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c | |||
@@ -89,6 +89,9 @@ int mdiobus_register(struct mii_bus *bus) | |||
89 | 89 | ||
90 | phydev->bus = bus; | 90 | phydev->bus = bus; |
91 | 91 | ||
92 | /* Run all of the fixups for this PHY */ | ||
93 | phy_scan_fixups(phydev); | ||
94 | |||
92 | err = device_register(&phydev->dev); | 95 | err = device_register(&phydev->dev); |
93 | 96 | ||
94 | if (err) { | 97 | if (err) { |
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 12fccb1c76dc..3c18bb594957 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c | |||
@@ -406,8 +406,10 @@ int phy_mii_ioctl(struct phy_device *phydev, | |||
406 | 406 | ||
407 | if (mii_data->reg_num == MII_BMCR | 407 | if (mii_data->reg_num == MII_BMCR |
408 | && val & BMCR_RESET | 408 | && val & BMCR_RESET |
409 | && phydev->drv->config_init) | 409 | && phydev->drv->config_init) { |
410 | phy_scan_fixups(phydev); | ||
410 | phydev->drv->config_init(phydev); | 411 | phydev->drv->config_init(phydev); |
412 | } | ||
411 | break; | 413 | break; |
412 | 414 | ||
413 | default: | 415 | default: |
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 8b1121b02f98..ddf8d51832a6 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c | |||
@@ -53,6 +53,96 @@ static void phy_device_release(struct device *dev) | |||
53 | phy_device_free(to_phy_device(dev)); | 53 | phy_device_free(to_phy_device(dev)); |
54 | } | 54 | } |
55 | 55 | ||
56 | static LIST_HEAD(phy_fixup_list); | ||
57 | static DEFINE_MUTEX(phy_fixup_lock); | ||
58 | |||
59 | /* | ||
60 | * Creates a new phy_fixup and adds it to the list | ||
61 | * @bus_id: A string which matches phydev->dev.bus_id (or PHY_ANY_ID) | ||
62 | * @phy_uid: Used to match against phydev->phy_id (the UID of the PHY) | ||
63 | * It can also be PHY_ANY_UID | ||
64 | * @phy_uid_mask: Applied to phydev->phy_id and fixup->phy_uid before | ||
65 | * comparison | ||
66 | * @run: The actual code to be run when a matching PHY is found | ||
67 | */ | ||
68 | int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask, | ||
69 | int (*run)(struct phy_device *)) | ||
70 | { | ||
71 | struct phy_fixup *fixup; | ||
72 | |||
73 | fixup = kzalloc(sizeof(struct phy_fixup), GFP_KERNEL); | ||
74 | if (!fixup) | ||
75 | return -ENOMEM; | ||
76 | |||
77 | strncpy(fixup->bus_id, bus_id, BUS_ID_SIZE); | ||
78 | fixup->phy_uid = phy_uid; | ||
79 | fixup->phy_uid_mask = phy_uid_mask; | ||
80 | fixup->run = run; | ||
81 | |||
82 | mutex_lock(&phy_fixup_lock); | ||
83 | list_add_tail(&fixup->list, &phy_fixup_list); | ||
84 | mutex_unlock(&phy_fixup_lock); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | EXPORT_SYMBOL(phy_register_fixup); | ||
89 | |||
90 | /* Registers a fixup to be run on any PHY with the UID in phy_uid */ | ||
91 | int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask, | ||
92 | int (*run)(struct phy_device *)) | ||
93 | { | ||
94 | return phy_register_fixup(PHY_ANY_ID, phy_uid, phy_uid_mask, run); | ||
95 | } | ||
96 | EXPORT_SYMBOL(phy_register_fixup_for_uid); | ||
97 | |||
98 | /* Registers a fixup to be run on the PHY with id string bus_id */ | ||
99 | int phy_register_fixup_for_id(const char *bus_id, | ||
100 | int (*run)(struct phy_device *)) | ||
101 | { | ||
102 | return phy_register_fixup(bus_id, PHY_ANY_UID, 0xffffffff, run); | ||
103 | } | ||
104 | EXPORT_SYMBOL(phy_register_fixup_for_id); | ||
105 | |||
106 | /* | ||
107 | * Returns 1 if fixup matches phydev in bus_id and phy_uid. | ||
108 | * Fixups can be set to match any in one or more fields. | ||
109 | */ | ||
110 | static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup) | ||
111 | { | ||
112 | if (strcmp(fixup->bus_id, phydev->dev.bus_id) != 0) | ||
113 | if (strcmp(fixup->bus_id, PHY_ANY_ID) != 0) | ||
114 | return 0; | ||
115 | |||
116 | if ((fixup->phy_uid & fixup->phy_uid_mask) != | ||
117 | (phydev->phy_id & fixup->phy_uid_mask)) | ||
118 | if (fixup->phy_uid != PHY_ANY_UID) | ||
119 | return 0; | ||
120 | |||
121 | return 1; | ||
122 | } | ||
123 | |||
124 | /* Runs any matching fixups for this phydev */ | ||
125 | int phy_scan_fixups(struct phy_device *phydev) | ||
126 | { | ||
127 | struct phy_fixup *fixup; | ||
128 | |||
129 | mutex_lock(&phy_fixup_lock); | ||
130 | list_for_each_entry(fixup, &phy_fixup_list, list) { | ||
131 | if (phy_needs_fixup(phydev, fixup)) { | ||
132 | int err; | ||
133 | |||
134 | err = fixup->run(phydev); | ||
135 | |||
136 | if (err < 0) | ||
137 | return err; | ||
138 | } | ||
139 | } | ||
140 | mutex_unlock(&phy_fixup_lock); | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | EXPORT_SYMBOL(phy_scan_fixups); | ||
145 | |||
56 | struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) | 146 | struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) |
57 | { | 147 | { |
58 | struct phy_device *dev; | 148 | struct phy_device *dev; |
@@ -179,13 +269,13 @@ void phy_prepare_link(struct phy_device *phydev, | |||
179 | * choose to call only the subset of functions which provide | 269 | * choose to call only the subset of functions which provide |
180 | * the desired functionality. | 270 | * the desired functionality. |
181 | */ | 271 | */ |
182 | struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, | 272 | struct phy_device * phy_connect(struct net_device *dev, const char *bus_id, |
183 | void (*handler)(struct net_device *), u32 flags, | 273 | void (*handler)(struct net_device *), u32 flags, |
184 | phy_interface_t interface) | 274 | phy_interface_t interface) |
185 | { | 275 | { |
186 | struct phy_device *phydev; | 276 | struct phy_device *phydev; |
187 | 277 | ||
188 | phydev = phy_attach(dev, phy_id, flags, interface); | 278 | phydev = phy_attach(dev, bus_id, flags, interface); |
189 | 279 | ||
190 | if (IS_ERR(phydev)) | 280 | if (IS_ERR(phydev)) |
191 | return phydev; | 281 | return phydev; |
@@ -226,7 +316,7 @@ static int phy_compare_id(struct device *dev, void *data) | |||
226 | /** | 316 | /** |
227 | * phy_attach - attach a network device to a particular PHY device | 317 | * phy_attach - attach a network device to a particular PHY device |
228 | * @dev: network device to attach | 318 | * @dev: network device to attach |
229 | * @phy_id: PHY device to attach | 319 | * @bus_id: PHY device to attach |
230 | * @flags: PHY device's dev_flags | 320 | * @flags: PHY device's dev_flags |
231 | * @interface: PHY device's interface | 321 | * @interface: PHY device's interface |
232 | * | 322 | * |
@@ -238,7 +328,7 @@ static int phy_compare_id(struct device *dev, void *data) | |||
238 | * change. The phy_device is returned to the attaching driver. | 328 | * change. The phy_device is returned to the attaching driver. |
239 | */ | 329 | */ |
240 | struct phy_device *phy_attach(struct net_device *dev, | 330 | struct phy_device *phy_attach(struct net_device *dev, |
241 | const char *phy_id, u32 flags, phy_interface_t interface) | 331 | const char *bus_id, u32 flags, phy_interface_t interface) |
242 | { | 332 | { |
243 | struct bus_type *bus = &mdio_bus_type; | 333 | struct bus_type *bus = &mdio_bus_type; |
244 | struct phy_device *phydev; | 334 | struct phy_device *phydev; |
@@ -246,12 +336,12 @@ struct phy_device *phy_attach(struct net_device *dev, | |||
246 | 336 | ||
247 | /* Search the list of PHY devices on the mdio bus for the | 337 | /* Search the list of PHY devices on the mdio bus for the |
248 | * PHY with the requested name */ | 338 | * PHY with the requested name */ |
249 | d = bus_find_device(bus, NULL, (void *)phy_id, phy_compare_id); | 339 | d = bus_find_device(bus, NULL, (void *)bus_id, phy_compare_id); |
250 | 340 | ||
251 | if (d) { | 341 | if (d) { |
252 | phydev = to_phy_device(d); | 342 | phydev = to_phy_device(d); |
253 | } else { | 343 | } else { |
254 | printk(KERN_ERR "%s not found\n", phy_id); | 344 | printk(KERN_ERR "%s not found\n", bus_id); |
255 | return ERR_PTR(-ENODEV); | 345 | return ERR_PTR(-ENODEV); |
256 | } | 346 | } |
257 | 347 | ||
@@ -271,7 +361,7 @@ struct phy_device *phy_attach(struct net_device *dev, | |||
271 | 361 | ||
272 | if (phydev->attached_dev) { | 362 | if (phydev->attached_dev) { |
273 | printk(KERN_ERR "%s: %s already attached\n", | 363 | printk(KERN_ERR "%s: %s already attached\n", |
274 | dev->name, phy_id); | 364 | dev->name, bus_id); |
275 | return ERR_PTR(-EBUSY); | 365 | return ERR_PTR(-EBUSY); |
276 | } | 366 | } |
277 | 367 | ||
@@ -287,6 +377,11 @@ struct phy_device *phy_attach(struct net_device *dev, | |||
287 | if (phydev->drv->config_init) { | 377 | if (phydev->drv->config_init) { |
288 | int err; | 378 | int err; |
289 | 379 | ||
380 | err = phy_scan_fixups(phydev); | ||
381 | |||
382 | if (err < 0) | ||
383 | return ERR_PTR(err); | ||
384 | |||
290 | err = phydev->drv->config_init(phydev); | 385 | err = phydev->drv->config_init(phydev); |
291 | 386 | ||
292 | if (err < 0) | 387 | if (err < 0) |
@@ -395,6 +490,7 @@ EXPORT_SYMBOL(genphy_config_advert); | |||
395 | */ | 490 | */ |
396 | int genphy_setup_forced(struct phy_device *phydev) | 491 | int genphy_setup_forced(struct phy_device *phydev) |
397 | { | 492 | { |
493 | int err; | ||
398 | int ctl = 0; | 494 | int ctl = 0; |
399 | 495 | ||
400 | phydev->pause = phydev->asym_pause = 0; | 496 | phydev->pause = phydev->asym_pause = 0; |
@@ -407,17 +503,26 @@ int genphy_setup_forced(struct phy_device *phydev) | |||
407 | if (DUPLEX_FULL == phydev->duplex) | 503 | if (DUPLEX_FULL == phydev->duplex) |
408 | ctl |= BMCR_FULLDPLX; | 504 | ctl |= BMCR_FULLDPLX; |
409 | 505 | ||
410 | ctl = phy_write(phydev, MII_BMCR, ctl); | 506 | err = phy_write(phydev, MII_BMCR, ctl); |
411 | 507 | ||
412 | if (ctl < 0) | 508 | if (err < 0) |
413 | return ctl; | 509 | return err; |
510 | |||
511 | /* | ||
512 | * Run the fixups on this PHY, just in case the | ||
513 | * board code needs to change something after a reset | ||
514 | */ | ||
515 | err = phy_scan_fixups(phydev); | ||
516 | |||
517 | if (err < 0) | ||
518 | return err; | ||
414 | 519 | ||
415 | /* We just reset the device, so we'd better configure any | 520 | /* We just reset the device, so we'd better configure any |
416 | * settings the PHY requires to operate */ | 521 | * settings the PHY requires to operate */ |
417 | if (phydev->drv->config_init) | 522 | if (phydev->drv->config_init) |
418 | ctl = phydev->drv->config_init(phydev); | 523 | err = phydev->drv->config_init(phydev); |
419 | 524 | ||
420 | return ctl; | 525 | return err; |
421 | } | 526 | } |
422 | 527 | ||
423 | 528 | ||
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index dcbe01b0ca0d..157fd932e951 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c | |||
@@ -86,7 +86,7 @@ | |||
86 | #include "s2io.h" | 86 | #include "s2io.h" |
87 | #include "s2io-regs.h" | 87 | #include "s2io-regs.h" |
88 | 88 | ||
89 | #define DRV_VERSION "2.0.26.20" | 89 | #define DRV_VERSION "2.0.26.22" |
90 | 90 | ||
91 | /* S2io Driver name & version. */ | 91 | /* S2io Driver name & version. */ |
92 | static char s2io_driver_name[] = "Neterion"; | 92 | static char s2io_driver_name[] = "Neterion"; |
@@ -117,20 +117,6 @@ static inline int RXD_IS_UP2DT(struct RxD_t *rxdp) | |||
117 | 117 | ||
118 | #define LINK_IS_UP(val64) (!(val64 & (ADAPTER_STATUS_RMAC_REMOTE_FAULT | \ | 118 | #define LINK_IS_UP(val64) (!(val64 & (ADAPTER_STATUS_RMAC_REMOTE_FAULT | \ |
119 | ADAPTER_STATUS_RMAC_LOCAL_FAULT))) | 119 | ADAPTER_STATUS_RMAC_LOCAL_FAULT))) |
120 | #define TASKLET_IN_USE test_and_set_bit(0, (&sp->tasklet_status)) | ||
121 | #define PANIC 1 | ||
122 | #define LOW 2 | ||
123 | static inline int rx_buffer_level(struct s2io_nic * sp, int rxb_size, int ring) | ||
124 | { | ||
125 | struct mac_info *mac_control; | ||
126 | |||
127 | mac_control = &sp->mac_control; | ||
128 | if (rxb_size <= rxd_count[sp->rxd_mode]) | ||
129 | return PANIC; | ||
130 | else if ((mac_control->rings[ring].pkt_cnt - rxb_size) > 16) | ||
131 | return LOW; | ||
132 | return 0; | ||
133 | } | ||
134 | 120 | ||
135 | static inline int is_s2io_card_up(const struct s2io_nic * sp) | 121 | static inline int is_s2io_card_up(const struct s2io_nic * sp) |
136 | { | 122 | { |
@@ -2458,7 +2444,7 @@ static void free_tx_buffers(struct s2io_nic *nic) | |||
2458 | for (i = 0; i < config->tx_fifo_num; i++) { | 2444 | for (i = 0; i < config->tx_fifo_num; i++) { |
2459 | unsigned long flags; | 2445 | unsigned long flags; |
2460 | spin_lock_irqsave(&mac_control->fifos[i].tx_lock, flags); | 2446 | spin_lock_irqsave(&mac_control->fifos[i].tx_lock, flags); |
2461 | for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) { | 2447 | for (j = 0; j < config->tx_cfg[i].fifo_len; j++) { |
2462 | txdp = (struct TxD *) \ | 2448 | txdp = (struct TxD *) \ |
2463 | mac_control->fifos[i].list_info[j].list_virt_addr; | 2449 | mac_control->fifos[i].list_info[j].list_virt_addr; |
2464 | skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j); | 2450 | skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j); |
@@ -2544,7 +2530,6 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) | |||
2544 | struct config_param *config; | 2530 | struct config_param *config; |
2545 | u64 tmp; | 2531 | u64 tmp; |
2546 | struct buffAdd *ba; | 2532 | struct buffAdd *ba; |
2547 | unsigned long flags; | ||
2548 | struct RxD_t *first_rxdp = NULL; | 2533 | struct RxD_t *first_rxdp = NULL; |
2549 | u64 Buffer0_ptr = 0, Buffer1_ptr = 0; | 2534 | u64 Buffer0_ptr = 0, Buffer1_ptr = 0; |
2550 | struct RxD1 *rxdp1; | 2535 | struct RxD1 *rxdp1; |
@@ -2592,15 +2577,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) | |||
2592 | DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n", | 2577 | DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n", |
2593 | dev->name, rxdp); | 2578 | dev->name, rxdp); |
2594 | } | 2579 | } |
2595 | if(!napi) { | 2580 | |
2596 | spin_lock_irqsave(&nic->put_lock, flags); | ||
2597 | mac_control->rings[ring_no].put_pos = | ||
2598 | (block_no * (rxd_count[nic->rxd_mode] + 1)) + off; | ||
2599 | spin_unlock_irqrestore(&nic->put_lock, flags); | ||
2600 | } else { | ||
2601 | mac_control->rings[ring_no].put_pos = | ||
2602 | (block_no * (rxd_count[nic->rxd_mode] + 1)) + off; | ||
2603 | } | ||
2604 | if ((rxdp->Control_1 & RXD_OWN_XENA) && | 2581 | if ((rxdp->Control_1 & RXD_OWN_XENA) && |
2605 | ((nic->rxd_mode == RXD_MODE_3B) && | 2582 | ((nic->rxd_mode == RXD_MODE_3B) && |
2606 | (rxdp->Control_2 & s2BIT(0)))) { | 2583 | (rxdp->Control_2 & s2BIT(0)))) { |
@@ -2978,7 +2955,7 @@ static void rx_intr_handler(struct ring_info *ring_data) | |||
2978 | { | 2955 | { |
2979 | struct s2io_nic *nic = ring_data->nic; | 2956 | struct s2io_nic *nic = ring_data->nic; |
2980 | struct net_device *dev = (struct net_device *) nic->dev; | 2957 | struct net_device *dev = (struct net_device *) nic->dev; |
2981 | int get_block, put_block, put_offset; | 2958 | int get_block, put_block; |
2982 | struct rx_curr_get_info get_info, put_info; | 2959 | struct rx_curr_get_info get_info, put_info; |
2983 | struct RxD_t *rxdp; | 2960 | struct RxD_t *rxdp; |
2984 | struct sk_buff *skb; | 2961 | struct sk_buff *skb; |
@@ -2987,19 +2964,11 @@ static void rx_intr_handler(struct ring_info *ring_data) | |||
2987 | struct RxD1* rxdp1; | 2964 | struct RxD1* rxdp1; |
2988 | struct RxD3* rxdp3; | 2965 | struct RxD3* rxdp3; |
2989 | 2966 | ||
2990 | spin_lock(&nic->rx_lock); | ||
2991 | |||
2992 | get_info = ring_data->rx_curr_get_info; | 2967 | get_info = ring_data->rx_curr_get_info; |
2993 | get_block = get_info.block_index; | 2968 | get_block = get_info.block_index; |
2994 | memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info)); | 2969 | memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info)); |
2995 | put_block = put_info.block_index; | 2970 | put_block = put_info.block_index; |
2996 | rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr; | 2971 | rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr; |
2997 | if (!napi) { | ||
2998 | spin_lock(&nic->put_lock); | ||
2999 | put_offset = ring_data->put_pos; | ||
3000 | spin_unlock(&nic->put_lock); | ||
3001 | } else | ||
3002 | put_offset = ring_data->put_pos; | ||
3003 | 2972 | ||
3004 | while (RXD_IS_UP2DT(rxdp)) { | 2973 | while (RXD_IS_UP2DT(rxdp)) { |
3005 | /* | 2974 | /* |
@@ -3016,7 +2985,6 @@ static void rx_intr_handler(struct ring_info *ring_data) | |||
3016 | DBG_PRINT(ERR_DBG, "%s: The skb is ", | 2985 | DBG_PRINT(ERR_DBG, "%s: The skb is ", |
3017 | dev->name); | 2986 | dev->name); |
3018 | DBG_PRINT(ERR_DBG, "Null in Rx Intr\n"); | 2987 | DBG_PRINT(ERR_DBG, "Null in Rx Intr\n"); |
3019 | spin_unlock(&nic->rx_lock); | ||
3020 | return; | 2988 | return; |
3021 | } | 2989 | } |
3022 | if (nic->rxd_mode == RXD_MODE_1) { | 2990 | if (nic->rxd_mode == RXD_MODE_1) { |
@@ -3072,8 +3040,6 @@ static void rx_intr_handler(struct ring_info *ring_data) | |||
3072 | } | 3040 | } |
3073 | } | 3041 | } |
3074 | } | 3042 | } |
3075 | |||
3076 | spin_unlock(&nic->rx_lock); | ||
3077 | } | 3043 | } |
3078 | 3044 | ||
3079 | /** | 3045 | /** |
@@ -4105,7 +4071,6 @@ static int s2io_close(struct net_device *dev) | |||
4105 | do_s2io_delete_unicast_mc(sp, tmp64); | 4071 | do_s2io_delete_unicast_mc(sp, tmp64); |
4106 | } | 4072 | } |
4107 | 4073 | ||
4108 | /* Reset card, kill tasklet and free Tx and Rx buffers. */ | ||
4109 | s2io_card_down(sp); | 4074 | s2io_card_down(sp); |
4110 | 4075 | ||
4111 | return 0; | 4076 | return 0; |
@@ -4370,29 +4335,9 @@ s2io_alarm_handle(unsigned long data) | |||
4370 | 4335 | ||
4371 | static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n) | 4336 | static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n) |
4372 | { | 4337 | { |
4373 | int rxb_size, level; | 4338 | if (fill_rx_buffers(sp, rng_n) == -ENOMEM) { |
4374 | 4339 | DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name); | |
4375 | if (!sp->lro) { | 4340 | DBG_PRINT(INFO_DBG, " in Rx Intr!!\n"); |
4376 | rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]); | ||
4377 | level = rx_buffer_level(sp, rxb_size, rng_n); | ||
4378 | |||
4379 | if ((level == PANIC) && (!TASKLET_IN_USE)) { | ||
4380 | int ret; | ||
4381 | DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__); | ||
4382 | DBG_PRINT(INTR_DBG, "PANIC levels\n"); | ||
4383 | if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) { | ||
4384 | DBG_PRINT(INFO_DBG, "Out of memory in %s", | ||
4385 | __FUNCTION__); | ||
4386 | clear_bit(0, (&sp->tasklet_status)); | ||
4387 | return -1; | ||
4388 | } | ||
4389 | clear_bit(0, (&sp->tasklet_status)); | ||
4390 | } else if (level == LOW) | ||
4391 | tasklet_schedule(&sp->task); | ||
4392 | |||
4393 | } else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) { | ||
4394 | DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name); | ||
4395 | DBG_PRINT(INFO_DBG, " in Rx Intr!!\n"); | ||
4396 | } | 4341 | } |
4397 | return 0; | 4342 | return 0; |
4398 | } | 4343 | } |
@@ -6770,49 +6715,6 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu) | |||
6770 | } | 6715 | } |
6771 | 6716 | ||
6772 | /** | 6717 | /** |
6773 | * s2io_tasklet - Bottom half of the ISR. | ||
6774 | * @dev_adr : address of the device structure in dma_addr_t format. | ||
6775 | * Description: | ||
6776 | * This is the tasklet or the bottom half of the ISR. This is | ||
6777 | * an extension of the ISR which is scheduled by the scheduler to be run | ||
6778 | * when the load on the CPU is low. All low priority tasks of the ISR can | ||
6779 | * be pushed into the tasklet. For now the tasklet is used only to | ||
6780 | * replenish the Rx buffers in the Rx buffer descriptors. | ||
6781 | * Return value: | ||
6782 | * void. | ||
6783 | */ | ||
6784 | |||
6785 | static void s2io_tasklet(unsigned long dev_addr) | ||
6786 | { | ||
6787 | struct net_device *dev = (struct net_device *) dev_addr; | ||
6788 | struct s2io_nic *sp = dev->priv; | ||
6789 | int i, ret; | ||
6790 | struct mac_info *mac_control; | ||
6791 | struct config_param *config; | ||
6792 | |||
6793 | mac_control = &sp->mac_control; | ||
6794 | config = &sp->config; | ||
6795 | |||
6796 | if (!TASKLET_IN_USE) { | ||
6797 | for (i = 0; i < config->rx_ring_num; i++) { | ||
6798 | ret = fill_rx_buffers(sp, i); | ||
6799 | if (ret == -ENOMEM) { | ||
6800 | DBG_PRINT(INFO_DBG, "%s: Out of ", | ||
6801 | dev->name); | ||
6802 | DBG_PRINT(INFO_DBG, "memory in tasklet\n"); | ||
6803 | break; | ||
6804 | } else if (ret == -EFILL) { | ||
6805 | DBG_PRINT(INFO_DBG, | ||
6806 | "%s: Rx Ring %d is full\n", | ||
6807 | dev->name, i); | ||
6808 | break; | ||
6809 | } | ||
6810 | } | ||
6811 | clear_bit(0, (&sp->tasklet_status)); | ||
6812 | } | ||
6813 | } | ||
6814 | |||
6815 | /** | ||
6816 | * s2io_set_link - Set the LInk status | 6718 | * s2io_set_link - Set the LInk status |
6817 | * @data: long pointer to device private structue | 6719 | * @data: long pointer to device private structue |
6818 | * Description: Sets the link status for the adapter | 6720 | * Description: Sets the link status for the adapter |
@@ -7161,7 +7063,6 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) | |||
7161 | { | 7063 | { |
7162 | int cnt = 0; | 7064 | int cnt = 0; |
7163 | struct XENA_dev_config __iomem *bar0 = sp->bar0; | 7065 | struct XENA_dev_config __iomem *bar0 = sp->bar0; |
7164 | unsigned long flags; | ||
7165 | register u64 val64 = 0; | 7066 | register u64 val64 = 0; |
7166 | struct config_param *config; | 7067 | struct config_param *config; |
7167 | config = &sp->config; | 7068 | config = &sp->config; |
@@ -7186,9 +7087,6 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) | |||
7186 | 7087 | ||
7187 | s2io_rem_isr(sp); | 7088 | s2io_rem_isr(sp); |
7188 | 7089 | ||
7189 | /* Kill tasklet. */ | ||
7190 | tasklet_kill(&sp->task); | ||
7191 | |||
7192 | /* Check if the device is Quiescent and then Reset the NIC */ | 7090 | /* Check if the device is Quiescent and then Reset the NIC */ |
7193 | while(do_io) { | 7091 | while(do_io) { |
7194 | /* As per the HW requirement we need to replenish the | 7092 | /* As per the HW requirement we need to replenish the |
@@ -7223,9 +7121,7 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) | |||
7223 | free_tx_buffers(sp); | 7121 | free_tx_buffers(sp); |
7224 | 7122 | ||
7225 | /* Free all Rx buffers */ | 7123 | /* Free all Rx buffers */ |
7226 | spin_lock_irqsave(&sp->rx_lock, flags); | ||
7227 | free_rx_buffers(sp); | 7124 | free_rx_buffers(sp); |
7228 | spin_unlock_irqrestore(&sp->rx_lock, flags); | ||
7229 | 7125 | ||
7230 | clear_bit(__S2IO_STATE_LINK_TASK, &(sp->state)); | 7126 | clear_bit(__S2IO_STATE_LINK_TASK, &(sp->state)); |
7231 | } | 7127 | } |
@@ -7314,9 +7210,6 @@ static int s2io_card_up(struct s2io_nic * sp) | |||
7314 | 7210 | ||
7315 | S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2)); | 7211 | S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2)); |
7316 | 7212 | ||
7317 | /* Enable tasklet for the device */ | ||
7318 | tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev); | ||
7319 | |||
7320 | /* Enable select interrupts */ | 7213 | /* Enable select interrupts */ |
7321 | en_dis_err_alarms(sp, ENA_ALL_INTRS, ENABLE_INTRS); | 7214 | en_dis_err_alarms(sp, ENA_ALL_INTRS, ENABLE_INTRS); |
7322 | if (sp->config.intr_type != INTA) | 7215 | if (sp->config.intr_type != INTA) |
@@ -8119,20 +8012,15 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
8119 | s2io_reset(sp); | 8012 | s2io_reset(sp); |
8120 | 8013 | ||
8121 | /* | 8014 | /* |
8122 | * Initialize the tasklet status and link state flags | 8015 | * Initialize link state flags |
8123 | * and the card state parameter | 8016 | * and the card state parameter |
8124 | */ | 8017 | */ |
8125 | sp->tasklet_status = 0; | ||
8126 | sp->state = 0; | 8018 | sp->state = 0; |
8127 | 8019 | ||
8128 | /* Initialize spinlocks */ | 8020 | /* Initialize spinlocks */ |
8129 | for (i = 0; i < sp->config.tx_fifo_num; i++) | 8021 | for (i = 0; i < sp->config.tx_fifo_num; i++) |
8130 | spin_lock_init(&mac_control->fifos[i].tx_lock); | 8022 | spin_lock_init(&mac_control->fifos[i].tx_lock); |
8131 | 8023 | ||
8132 | if (!napi) | ||
8133 | spin_lock_init(&sp->put_lock); | ||
8134 | spin_lock_init(&sp->rx_lock); | ||
8135 | |||
8136 | /* | 8024 | /* |
8137 | * SXE-002: Configure link and activity LED to init state | 8025 | * SXE-002: Configure link and activity LED to init state |
8138 | * on driver load. | 8026 | * on driver load. |
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index e68fdf7e4260..ce53a02105f2 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h | |||
@@ -703,9 +703,6 @@ struct ring_info { | |||
703 | */ | 703 | */ |
704 | struct rx_curr_get_info rx_curr_get_info; | 704 | struct rx_curr_get_info rx_curr_get_info; |
705 | 705 | ||
706 | /* Index to the absolute position of the put pointer of Rx ring */ | ||
707 | int put_pos; | ||
708 | |||
709 | /* Buffer Address store. */ | 706 | /* Buffer Address store. */ |
710 | struct buffAdd **ba; | 707 | struct buffAdd **ba; |
711 | struct s2io_nic *nic; | 708 | struct s2io_nic *nic; |
@@ -868,8 +865,6 @@ struct s2io_nic { | |||
868 | int device_enabled_once; | 865 | int device_enabled_once; |
869 | 866 | ||
870 | char name[60]; | 867 | char name[60]; |
871 | struct tasklet_struct task; | ||
872 | volatile unsigned long tasklet_status; | ||
873 | 868 | ||
874 | /* Timer that handles I/O errors/exceptions */ | 869 | /* Timer that handles I/O errors/exceptions */ |
875 | struct timer_list alarm_timer; | 870 | struct timer_list alarm_timer; |
@@ -879,8 +874,6 @@ struct s2io_nic { | |||
879 | 874 | ||
880 | atomic_t rx_bufs_left[MAX_RX_RINGS]; | 875 | atomic_t rx_bufs_left[MAX_RX_RINGS]; |
881 | 876 | ||
882 | spinlock_t put_lock; | ||
883 | |||
884 | #define PROMISC 1 | 877 | #define PROMISC 1 |
885 | #define ALL_MULTI 2 | 878 | #define ALL_MULTI 2 |
886 | 879 | ||
@@ -964,7 +957,6 @@ struct s2io_nic { | |||
964 | u8 lro; | 957 | u8 lro; |
965 | u16 lro_max_aggr_per_sess; | 958 | u16 lro_max_aggr_per_sess; |
966 | volatile unsigned long state; | 959 | volatile unsigned long state; |
967 | spinlock_t rx_lock; | ||
968 | u64 general_int_mask; | 960 | u64 general_int_mask; |
969 | #define VPD_STRING_LEN 80 | 961 | #define VPD_STRING_LEN 80 |
970 | u8 product_name[VPD_STRING_LEN]; | 962 | u8 product_name[VPD_STRING_LEN]; |
@@ -1094,7 +1086,6 @@ static void s2io_handle_errors(void * dev_id); | |||
1094 | static int s2io_starter(void); | 1086 | static int s2io_starter(void); |
1095 | static void s2io_closer(void); | 1087 | static void s2io_closer(void); |
1096 | static void s2io_tx_watchdog(struct net_device *dev); | 1088 | static void s2io_tx_watchdog(struct net_device *dev); |
1097 | static void s2io_tasklet(unsigned long dev_addr); | ||
1098 | static void s2io_set_multicast(struct net_device *dev); | 1089 | static void s2io_set_multicast(struct net_device *dev); |
1099 | static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp); | 1090 | static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp); |
1100 | static void s2io_link(struct s2io_nic * sp, int link); | 1091 | static void s2io_link(struct s2io_nic * sp, int link); |
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 78994ede0cb0..6261201403cd 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c | |||
@@ -825,7 +825,8 @@ static struct platform_driver sgiseeq_driver = { | |||
825 | .probe = sgiseeq_probe, | 825 | .probe = sgiseeq_probe, |
826 | .remove = __devexit_p(sgiseeq_remove), | 826 | .remove = __devexit_p(sgiseeq_remove), |
827 | .driver = { | 827 | .driver = { |
828 | .name = "sgiseeq" | 828 | .name = "sgiseeq", |
829 | .owner = THIS_MODULE, | ||
829 | } | 830 | } |
830 | }; | 831 | }; |
831 | 832 | ||
@@ -850,3 +851,4 @@ module_exit(sgiseeq_module_exit); | |||
850 | MODULE_DESCRIPTION("SGI Seeq 8003 driver"); | 851 | MODULE_DESCRIPTION("SGI Seeq 8003 driver"); |
851 | MODULE_AUTHOR("Linux/MIPS Mailing List <linux-mips@linux-mips.org>"); | 852 | MODULE_AUTHOR("Linux/MIPS Mailing List <linux-mips@linux-mips.org>"); |
852 | MODULE_LICENSE("GPL"); | 853 | MODULE_LICENSE("GPL"); |
854 | MODULE_ALIAS("platform:sgiseeq"); | ||
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 76cc1d3adf71..4e2800205189 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c | |||
@@ -92,6 +92,7 @@ module_param(tx_fifo_kb, int, 0400); | |||
92 | MODULE_PARM_DESC(tx_fifo_kb,"transmit FIFO size in KB (1<x<15)(default=8)"); | 92 | MODULE_PARM_DESC(tx_fifo_kb,"transmit FIFO size in KB (1<x<15)(default=8)"); |
93 | 93 | ||
94 | MODULE_LICENSE("GPL"); | 94 | MODULE_LICENSE("GPL"); |
95 | MODULE_ALIAS("platform:smc911x"); | ||
95 | 96 | ||
96 | /* | 97 | /* |
97 | * The internal workings of the driver. If you are changing anything | 98 | * The internal workings of the driver. If you are changing anything |
@@ -243,7 +244,7 @@ static void smc911x_reset(struct net_device *dev) | |||
243 | do { | 244 | do { |
244 | udelay(10); | 245 | udelay(10); |
245 | reg = SMC_GET_PMT_CTRL() & PMT_CTRL_READY_; | 246 | reg = SMC_GET_PMT_CTRL() & PMT_CTRL_READY_; |
246 | } while ( timeout-- && !reg); | 247 | } while (--timeout && !reg); |
247 | if (timeout == 0) { | 248 | if (timeout == 0) { |
248 | PRINTK("%s: smc911x_reset timeout waiting for PM restore\n", dev->name); | 249 | PRINTK("%s: smc911x_reset timeout waiting for PM restore\n", dev->name); |
249 | return; | 250 | return; |
@@ -267,7 +268,7 @@ static void smc911x_reset(struct net_device *dev) | |||
267 | resets++; | 268 | resets++; |
268 | break; | 269 | break; |
269 | } | 270 | } |
270 | } while ( timeout-- && (reg & HW_CFG_SRST_)); | 271 | } while (--timeout && (reg & HW_CFG_SRST_)); |
271 | } | 272 | } |
272 | if (timeout == 0) { | 273 | if (timeout == 0) { |
273 | PRINTK("%s: smc911x_reset timeout waiting for reset\n", dev->name); | 274 | PRINTK("%s: smc911x_reset timeout waiting for reset\n", dev->name); |
@@ -413,7 +414,7 @@ static inline void smc911x_drop_pkt(struct net_device *dev) | |||
413 | do { | 414 | do { |
414 | udelay(10); | 415 | udelay(10); |
415 | reg = SMC_GET_RX_DP_CTRL() & RX_DP_CTRL_FFWD_BUSY_; | 416 | reg = SMC_GET_RX_DP_CTRL() & RX_DP_CTRL_FFWD_BUSY_; |
416 | } while ( timeout-- && reg); | 417 | } while (--timeout && reg); |
417 | if (timeout == 0) { | 418 | if (timeout == 0) { |
418 | PRINTK("%s: timeout waiting for RX fast forward\n", dev->name); | 419 | PRINTK("%s: timeout waiting for RX fast forward\n", dev->name); |
419 | } | 420 | } |
@@ -2262,6 +2263,7 @@ static struct platform_driver smc911x_driver = { | |||
2262 | .resume = smc911x_drv_resume, | 2263 | .resume = smc911x_drv_resume, |
2263 | .driver = { | 2264 | .driver = { |
2264 | .name = CARDNAME, | 2265 | .name = CARDNAME, |
2266 | .owner = THIS_MODULE, | ||
2265 | }, | 2267 | }, |
2266 | }; | 2268 | }; |
2267 | 2269 | ||
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 600b92af3334..a188e33484e6 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c | |||
@@ -132,6 +132,7 @@ module_param(watchdog, int, 0400); | |||
132 | MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); | 132 | MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); |
133 | 133 | ||
134 | MODULE_LICENSE("GPL"); | 134 | MODULE_LICENSE("GPL"); |
135 | MODULE_ALIAS("platform:smc91x"); | ||
135 | 136 | ||
136 | /* | 137 | /* |
137 | * The internal workings of the driver. If you are changing anything | 138 | * The internal workings of the driver. If you are changing anything |
@@ -2308,6 +2309,7 @@ static struct platform_driver smc_driver = { | |||
2308 | .resume = smc_drv_resume, | 2309 | .resume = smc_drv_resume, |
2309 | .driver = { | 2310 | .driver = { |
2310 | .name = CARDNAME, | 2311 | .name = CARDNAME, |
2312 | .owner = THIS_MODULE, | ||
2311 | }, | 2313 | }, |
2312 | }; | 2314 | }; |
2313 | 2315 | ||
diff --git a/drivers/net/sni_82596.c b/drivers/net/sni_82596.c index 2cf6794acb4f..854ccf2b4105 100644 --- a/drivers/net/sni_82596.c +++ b/drivers/net/sni_82596.c | |||
@@ -44,6 +44,7 @@ static const char sni_82596_string[] = "snirm_82596"; | |||
44 | MODULE_AUTHOR("Thomas Bogendoerfer"); | 44 | MODULE_AUTHOR("Thomas Bogendoerfer"); |
45 | MODULE_DESCRIPTION("i82596 driver"); | 45 | MODULE_DESCRIPTION("i82596 driver"); |
46 | MODULE_LICENSE("GPL"); | 46 | MODULE_LICENSE("GPL"); |
47 | MODULE_ALIAS("platform:snirm_82596"); | ||
47 | module_param(i596_debug, int, 0); | 48 | module_param(i596_debug, int, 0); |
48 | MODULE_PARM_DESC(i596_debug, "82596 debug mask"); | 49 | MODULE_PARM_DESC(i596_debug, "82596 debug mask"); |
49 | 50 | ||
@@ -166,6 +167,7 @@ static struct platform_driver sni_82596_driver = { | |||
166 | .remove = __devexit_p(sni_82596_driver_remove), | 167 | .remove = __devexit_p(sni_82596_driver_remove), |
167 | .driver = { | 168 | .driver = { |
168 | .name = sni_82596_string, | 169 | .name = sni_82596_string, |
170 | .owner = THIS_MODULE, | ||
169 | }, | 171 | }, |
170 | }; | 172 | }; |
171 | 173 | ||
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 17585e5eed53..e83b166aa6b9 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c | |||
@@ -625,6 +625,12 @@ static void __init bdx_firmware_endianess(void) | |||
625 | s_firmLoad[i] = CPU_CHIP_SWAP32(s_firmLoad[i]); | 625 | s_firmLoad[i] = CPU_CHIP_SWAP32(s_firmLoad[i]); |
626 | } | 626 | } |
627 | 627 | ||
628 | static int bdx_range_check(struct bdx_priv *priv, u32 offset) | ||
629 | { | ||
630 | return (offset > (u32) (BDX_REGS_SIZE / priv->nic->port_num)) ? | ||
631 | -EINVAL : 0; | ||
632 | } | ||
633 | |||
628 | static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd) | 634 | static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd) |
629 | { | 635 | { |
630 | struct bdx_priv *priv = ndev->priv; | 636 | struct bdx_priv *priv = ndev->priv; |
@@ -643,9 +649,15 @@ static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd) | |||
643 | DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]); | 649 | DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]); |
644 | } | 650 | } |
645 | 651 | ||
652 | if (!capable(CAP_NET_ADMIN)) | ||
653 | return -EPERM; | ||
654 | |||
646 | switch (data[0]) { | 655 | switch (data[0]) { |
647 | 656 | ||
648 | case BDX_OP_READ: | 657 | case BDX_OP_READ: |
658 | error = bdx_range_check(priv, data[1]); | ||
659 | if (error < 0) | ||
660 | return error; | ||
649 | data[2] = READ_REG(priv, data[1]); | 661 | data[2] = READ_REG(priv, data[1]); |
650 | DBG("read_reg(0x%x)=0x%x (dec %d)\n", data[1], data[2], | 662 | DBG("read_reg(0x%x)=0x%x (dec %d)\n", data[1], data[2], |
651 | data[2]); | 663 | data[2]); |
@@ -655,6 +667,9 @@ static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd) | |||
655 | break; | 667 | break; |
656 | 668 | ||
657 | case BDX_OP_WRITE: | 669 | case BDX_OP_WRITE: |
670 | error = bdx_range_check(priv, data[1]); | ||
671 | if (error < 0) | ||
672 | return error; | ||
658 | WRITE_REG(priv, data[1], data[2]); | 673 | WRITE_REG(priv, data[1], data[2]); |
659 | DBG("write_reg(0x%x, 0x%x)\n", data[1], data[2]); | 674 | DBG("write_reg(0x%x, 0x%x)\n", data[1], data[2]); |
660 | break; | 675 | break; |
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index bc4c62b8e81a..e3f74c9f78bd 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c | |||
@@ -4017,6 +4017,8 @@ static int tg3_halt(struct tg3 *, int, int); | |||
4017 | * Invoked with tp->lock held. | 4017 | * Invoked with tp->lock held. |
4018 | */ | 4018 | */ |
4019 | static int tg3_restart_hw(struct tg3 *tp, int reset_phy) | 4019 | static int tg3_restart_hw(struct tg3 *tp, int reset_phy) |
4020 | __releases(tp->lock) | ||
4021 | __acquires(tp->lock) | ||
4020 | { | 4022 | { |
4021 | int err; | 4023 | int err; |
4022 | 4024 | ||
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index 6f33f84d37b0..6017d5267d08 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c | |||
@@ -162,6 +162,7 @@ static struct platform_driver tsi_eth_driver = { | |||
162 | .remove = tsi108_ether_remove, | 162 | .remove = tsi108_ether_remove, |
163 | .driver = { | 163 | .driver = { |
164 | .name = "tsi-ethernet", | 164 | .name = "tsi-ethernet", |
165 | .owner = THIS_MODULE, | ||
165 | }, | 166 | }, |
166 | }; | 167 | }; |
167 | 168 | ||
@@ -1729,3 +1730,4 @@ module_exit(tsi108_ether_exit); | |||
1729 | MODULE_AUTHOR("Tundra Semiconductor Corporation"); | 1730 | MODULE_AUTHOR("Tundra Semiconductor Corporation"); |
1730 | MODULE_DESCRIPTION("Tsi108 Gigabit Ethernet driver"); | 1731 | MODULE_DESCRIPTION("Tsi108 Gigabit Ethernet driver"); |
1731 | MODULE_LICENSE("GPL"); | 1732 | MODULE_LICENSE("GPL"); |
1733 | MODULE_ALIAS("platform:tsi-ethernet"); | ||
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 333961bb7873..c0dd25ba7a18 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c | |||
@@ -2183,7 +2183,6 @@ typhoon_resume(struct pci_dev *pdev) | |||
2183 | } | 2183 | } |
2184 | 2184 | ||
2185 | netif_device_attach(dev); | 2185 | netif_device_attach(dev); |
2186 | netif_start_queue(dev); | ||
2187 | return 0; | 2186 | return 0; |
2188 | 2187 | ||
2189 | reset: | 2188 | reset: |
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 2f11254bcc07..281ce3d39532 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c | |||
@@ -3932,7 +3932,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
3932 | ug_info->uf_info.irq = irq_of_parse_and_map(np, 0); | 3932 | ug_info->uf_info.irq = irq_of_parse_and_map(np, 0); |
3933 | fixed_link = of_get_property(np, "fixed-link", NULL); | 3933 | fixed_link = of_get_property(np, "fixed-link", NULL); |
3934 | if (fixed_link) { | 3934 | if (fixed_link) { |
3935 | ug_info->mdio_bus = 0; | 3935 | snprintf(ug_info->mdio_bus, MII_BUS_ID_SIZE, "0"); |
3936 | ug_info->phy_address = fixed_link[0]; | 3936 | ug_info->phy_address = fixed_link[0]; |
3937 | phy = NULL; | 3937 | phy = NULL; |
3938 | } else { | 3938 | } else { |
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index ed1afaf683a4..6b8d882d197b 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c | |||
@@ -605,7 +605,6 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index, | |||
605 | static void velocity_init_cam_filter(struct velocity_info *vptr) | 605 | static void velocity_init_cam_filter(struct velocity_info *vptr) |
606 | { | 606 | { |
607 | struct mac_regs __iomem * regs = vptr->mac_regs; | 607 | struct mac_regs __iomem * regs = vptr->mac_regs; |
608 | unsigned short vid; | ||
609 | 608 | ||
610 | /* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */ | 609 | /* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */ |
611 | WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, ®s->MCFG); | 610 | WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, ®s->MCFG); |
@@ -617,29 +616,33 @@ static void velocity_init_cam_filter(struct velocity_info *vptr) | |||
617 | mac_set_vlan_cam_mask(regs, vptr->vCAMmask); | 616 | mac_set_vlan_cam_mask(regs, vptr->vCAMmask); |
618 | mac_set_cam_mask(regs, vptr->mCAMmask); | 617 | mac_set_cam_mask(regs, vptr->mCAMmask); |
619 | 618 | ||
620 | /* Enable first VCAM */ | 619 | /* Enable VCAMs */ |
621 | if (vptr->vlgrp) { | 620 | if (vptr->vlgrp) { |
622 | for (vid = 0; vid < VLAN_VID_MASK; vid++) { | 621 | unsigned int vid, i = 0; |
623 | if (vlan_group_get_device(vptr->vlgrp, vid)) { | 622 | |
624 | /* If Tagging option is enabled and | 623 | if (!vlan_group_get_device(vptr->vlgrp, 0)) |
625 | VLAN ID is not zero, then | 624 | WORD_REG_BITS_ON(MCFG_RTGOPT, ®s->MCFG); |
626 | turn on MCFG_RTGOPT also */ | ||
627 | if (vid != 0) | ||
628 | WORD_REG_BITS_ON(MCFG_RTGOPT, ®s->MCFG); | ||
629 | 625 | ||
630 | mac_set_vlan_cam(regs, 0, (u8 *) &vid); | 626 | for (vid = 1; (vid < VLAN_VID_MASK); vid++) { |
627 | if (vlan_group_get_device(vptr->vlgrp, vid)) { | ||
628 | mac_set_vlan_cam(regs, i, (u8 *) &vid); | ||
629 | vptr->vCAMmask[i / 8] |= 0x1 << (i % 8); | ||
630 | if (++i >= VCAM_SIZE) | ||
631 | break; | ||
631 | } | 632 | } |
632 | } | 633 | } |
633 | vptr->vCAMmask[0] |= 1; | ||
634 | mac_set_vlan_cam_mask(regs, vptr->vCAMmask); | 634 | mac_set_vlan_cam_mask(regs, vptr->vCAMmask); |
635 | } else { | ||
636 | u16 temp = 0; | ||
637 | mac_set_vlan_cam(regs, 0, (u8 *) &temp); | ||
638 | temp = 1; | ||
639 | mac_set_vlan_cam_mask(regs, (u8 *) &temp); | ||
640 | } | 635 | } |
641 | } | 636 | } |
642 | 637 | ||
638 | static void velocity_vlan_rx_register(struct net_device *dev, | ||
639 | struct vlan_group *grp) | ||
640 | { | ||
641 | struct velocity_info *vptr = netdev_priv(dev); | ||
642 | |||
643 | vptr->vlgrp = grp; | ||
644 | } | ||
645 | |||
643 | static void velocity_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) | 646 | static void velocity_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) |
644 | { | 647 | { |
645 | struct velocity_info *vptr = netdev_priv(dev); | 648 | struct velocity_info *vptr = netdev_priv(dev); |
@@ -959,11 +962,13 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi | |||
959 | 962 | ||
960 | dev->vlan_rx_add_vid = velocity_vlan_rx_add_vid; | 963 | dev->vlan_rx_add_vid = velocity_vlan_rx_add_vid; |
961 | dev->vlan_rx_kill_vid = velocity_vlan_rx_kill_vid; | 964 | dev->vlan_rx_kill_vid = velocity_vlan_rx_kill_vid; |
965 | dev->vlan_rx_register = velocity_vlan_rx_register; | ||
962 | 966 | ||
963 | #ifdef VELOCITY_ZERO_COPY_SUPPORT | 967 | #ifdef VELOCITY_ZERO_COPY_SUPPORT |
964 | dev->features |= NETIF_F_SG; | 968 | dev->features |= NETIF_F_SG; |
965 | #endif | 969 | #endif |
966 | dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER; | 970 | dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | |
971 | NETIF_F_HW_VLAN_RX; | ||
967 | 972 | ||
968 | if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) | 973 | if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) |
969 | dev->features |= NETIF_F_IP_CSUM; | 974 | dev->features |= NETIF_F_IP_CSUM; |
@@ -1597,8 +1602,13 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) | |||
1597 | skb_put(skb, pkt_len - 4); | 1602 | skb_put(skb, pkt_len - 4); |
1598 | skb->protocol = eth_type_trans(skb, vptr->dev); | 1603 | skb->protocol = eth_type_trans(skb, vptr->dev); |
1599 | 1604 | ||
1605 | if (vptr->vlgrp && (rd->rdesc0.RSR & RSR_DETAG)) { | ||
1606 | vlan_hwaccel_rx(skb, vptr->vlgrp, | ||
1607 | swab16(le16_to_cpu(rd->rdesc1.PQTAG))); | ||
1608 | } else | ||
1609 | netif_rx(skb); | ||
1610 | |||
1600 | stats->rx_bytes += pkt_len; | 1611 | stats->rx_bytes += pkt_len; |
1601 | netif_rx(skb); | ||
1602 | 1612 | ||
1603 | return 0; | 1613 | return 0; |
1604 | } | 1614 | } |
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c index c4c8eab8574f..c2cc42f723d5 100644 --- a/drivers/net/wan/c101.c +++ b/drivers/net/wan/c101.c | |||
@@ -402,7 +402,7 @@ static int __init c101_init(void) | |||
402 | #ifdef MODULE | 402 | #ifdef MODULE |
403 | printk(KERN_INFO "c101: no card initialized\n"); | 403 | printk(KERN_INFO "c101: no card initialized\n"); |
404 | #endif | 404 | #endif |
405 | return -ENOSYS; /* no parameters specified, abort */ | 405 | return -EINVAL; /* no parameters specified, abort */ |
406 | } | 406 | } |
407 | 407 | ||
408 | printk(KERN_INFO "%s\n", version); | 408 | printk(KERN_INFO "%s\n", version); |
@@ -420,11 +420,11 @@ static int __init c101_init(void) | |||
420 | c101_run(irq, ram); | 420 | c101_run(irq, ram); |
421 | 421 | ||
422 | if (*hw == '\x0') | 422 | if (*hw == '\x0') |
423 | return first_card ? 0 : -ENOSYS; | 423 | return first_card ? 0 : -EINVAL; |
424 | }while(*hw++ == ':'); | 424 | }while(*hw++ == ':'); |
425 | 425 | ||
426 | printk(KERN_ERR "c101: invalid hardware parameters\n"); | 426 | printk(KERN_ERR "c101: invalid hardware parameters\n"); |
427 | return first_card ? 0 : -ENOSYS; | 427 | return first_card ? 0 : -EINVAL; |
428 | } | 428 | } |
429 | 429 | ||
430 | 430 | ||
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index c4ab0326f911..520bb0b1a9a2 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c | |||
@@ -1090,10 +1090,6 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) | |||
1090 | pvc_device *pvc = NULL; | 1090 | pvc_device *pvc = NULL; |
1091 | struct net_device *dev; | 1091 | struct net_device *dev; |
1092 | int result, used; | 1092 | int result, used; |
1093 | char * prefix = "pvc%d"; | ||
1094 | |||
1095 | if (type == ARPHRD_ETHER) | ||
1096 | prefix = "pvceth%d"; | ||
1097 | 1093 | ||
1098 | if ((pvc = add_pvc(frad, dlci)) == NULL) { | 1094 | if ((pvc = add_pvc(frad, dlci)) == NULL) { |
1099 | printk(KERN_WARNING "%s: Memory squeeze on fr_add_pvc()\n", | 1095 | printk(KERN_WARNING "%s: Memory squeeze on fr_add_pvc()\n", |
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 7483d45bc5bc..e62018a36133 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c | |||
@@ -1809,3 +1809,5 @@ module_exit(netif_exit); | |||
1809 | 1809 | ||
1810 | MODULE_DESCRIPTION("Xen virtual network device frontend"); | 1810 | MODULE_DESCRIPTION("Xen virtual network device frontend"); |
1811 | MODULE_LICENSE("GPL"); | 1811 | MODULE_LICENSE("GPL"); |
1812 | MODULE_ALIAS("xen:vif"); | ||
1813 | MODULE_ALIAS("xennet"); | ||
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 1bd5fb30237d..e3dc8f8d0c3e 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -1930,6 +1930,20 @@ config FB_VIRTUAL | |||
1930 | 1930 | ||
1931 | If unsure, say N. | 1931 | If unsure, say N. |
1932 | 1932 | ||
1933 | config XEN_FBDEV_FRONTEND | ||
1934 | tristate "Xen virtual frame buffer support" | ||
1935 | depends on FB && XEN | ||
1936 | select FB_SYS_FILLRECT | ||
1937 | select FB_SYS_COPYAREA | ||
1938 | select FB_SYS_IMAGEBLIT | ||
1939 | select FB_SYS_FOPS | ||
1940 | select FB_DEFERRED_IO | ||
1941 | default y | ||
1942 | help | ||
1943 | This driver implements the front-end of the Xen virtual | ||
1944 | frame buffer driver. It communicates with a back-end | ||
1945 | in another domain. | ||
1946 | |||
1933 | source "drivers/video/omap/Kconfig" | 1947 | source "drivers/video/omap/Kconfig" |
1934 | 1948 | ||
1935 | source "drivers/video/backlight/Kconfig" | 1949 | source "drivers/video/backlight/Kconfig" |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 11c0e5e05f21..f172b9b73314 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -114,6 +114,7 @@ obj-$(CONFIG_FB_PS3) += ps3fb.o | |||
114 | obj-$(CONFIG_FB_SM501) += sm501fb.o | 114 | obj-$(CONFIG_FB_SM501) += sm501fb.o |
115 | obj-$(CONFIG_FB_XILINX) += xilinxfb.o | 115 | obj-$(CONFIG_FB_XILINX) += xilinxfb.o |
116 | obj-$(CONFIG_FB_OMAP) += omap/ | 116 | obj-$(CONFIG_FB_OMAP) += omap/ |
117 | obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o | ||
117 | 118 | ||
118 | # Platform or fallback drivers go here | 119 | # Platform or fallback drivers go here |
119 | obj-$(CONFIG_FB_UVESA) += uvesafb.o | 120 | obj-$(CONFIG_FB_UVESA) += uvesafb.o |
diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c new file mode 100644 index 000000000000..619a6f8d65a2 --- /dev/null +++ b/drivers/video/xen-fbfront.c | |||
@@ -0,0 +1,550 @@ | |||
1 | /* | ||
2 | * Xen para-virtual frame buffer device | ||
3 | * | ||
4 | * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com> | ||
5 | * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> | ||
6 | * | ||
7 | * Based on linux/drivers/video/q40fb.c | ||
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 for | ||
11 | * more details. | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * TODO: | ||
16 | * | ||
17 | * Switch to grant tables when they become capable of dealing with the | ||
18 | * frame buffer. | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/fb.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/vmalloc.h> | ||
26 | #include <linux/mm.h> | ||
27 | #include <asm/xen/hypervisor.h> | ||
28 | #include <xen/events.h> | ||
29 | #include <xen/page.h> | ||
30 | #include <xen/interface/io/fbif.h> | ||
31 | #include <xen/interface/io/protocols.h> | ||
32 | #include <xen/xenbus.h> | ||
33 | |||
34 | struct xenfb_info { | ||
35 | unsigned char *fb; | ||
36 | struct fb_info *fb_info; | ||
37 | int x1, y1, x2, y2; /* dirty rectangle, | ||
38 | protected by dirty_lock */ | ||
39 | spinlock_t dirty_lock; | ||
40 | int nr_pages; | ||
41 | int irq; | ||
42 | struct xenfb_page *page; | ||
43 | unsigned long *mfns; | ||
44 | int update_wanted; /* XENFB_TYPE_UPDATE wanted */ | ||
45 | |||
46 | struct xenbus_device *xbdev; | ||
47 | }; | ||
48 | |||
49 | static u32 xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8; | ||
50 | |||
51 | static int xenfb_remove(struct xenbus_device *); | ||
52 | static void xenfb_init_shared_page(struct xenfb_info *); | ||
53 | static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *); | ||
54 | static void xenfb_disconnect_backend(struct xenfb_info *); | ||
55 | |||
56 | static void xenfb_do_update(struct xenfb_info *info, | ||
57 | int x, int y, int w, int h) | ||
58 | { | ||
59 | union xenfb_out_event event; | ||
60 | u32 prod; | ||
61 | |||
62 | event.type = XENFB_TYPE_UPDATE; | ||
63 | event.update.x = x; | ||
64 | event.update.y = y; | ||
65 | event.update.width = w; | ||
66 | event.update.height = h; | ||
67 | |||
68 | prod = info->page->out_prod; | ||
69 | /* caller ensures !xenfb_queue_full() */ | ||
70 | mb(); /* ensure ring space available */ | ||
71 | XENFB_OUT_RING_REF(info->page, prod) = event; | ||
72 | wmb(); /* ensure ring contents visible */ | ||
73 | info->page->out_prod = prod + 1; | ||
74 | |||
75 | notify_remote_via_irq(info->irq); | ||
76 | } | ||
77 | |||
78 | static int xenfb_queue_full(struct xenfb_info *info) | ||
79 | { | ||
80 | u32 cons, prod; | ||
81 | |||
82 | prod = info->page->out_prod; | ||
83 | cons = info->page->out_cons; | ||
84 | return prod - cons == XENFB_OUT_RING_LEN; | ||
85 | } | ||
86 | |||
87 | static void xenfb_refresh(struct xenfb_info *info, | ||
88 | int x1, int y1, int w, int h) | ||
89 | { | ||
90 | unsigned long flags; | ||
91 | int y2 = y1 + h - 1; | ||
92 | int x2 = x1 + w - 1; | ||
93 | |||
94 | if (!info->update_wanted) | ||
95 | return; | ||
96 | |||
97 | spin_lock_irqsave(&info->dirty_lock, flags); | ||
98 | |||
99 | /* Combine with dirty rectangle: */ | ||
100 | if (info->y1 < y1) | ||
101 | y1 = info->y1; | ||
102 | if (info->y2 > y2) | ||
103 | y2 = info->y2; | ||
104 | if (info->x1 < x1) | ||
105 | x1 = info->x1; | ||
106 | if (info->x2 > x2) | ||
107 | x2 = info->x2; | ||
108 | |||
109 | if (xenfb_queue_full(info)) { | ||
110 | /* Can't send right now, stash it in the dirty rectangle */ | ||
111 | info->x1 = x1; | ||
112 | info->x2 = x2; | ||
113 | info->y1 = y1; | ||
114 | info->y2 = y2; | ||
115 | spin_unlock_irqrestore(&info->dirty_lock, flags); | ||
116 | return; | ||
117 | } | ||
118 | |||
119 | /* Clear dirty rectangle: */ | ||
120 | info->x1 = info->y1 = INT_MAX; | ||
121 | info->x2 = info->y2 = 0; | ||
122 | |||
123 | spin_unlock_irqrestore(&info->dirty_lock, flags); | ||
124 | |||
125 | if (x1 <= x2 && y1 <= y2) | ||
126 | xenfb_do_update(info, x1, y1, x2 - x1 + 1, y2 - y1 + 1); | ||
127 | } | ||
128 | |||
129 | static void xenfb_deferred_io(struct fb_info *fb_info, | ||
130 | struct list_head *pagelist) | ||
131 | { | ||
132 | struct xenfb_info *info = fb_info->par; | ||
133 | struct page *page; | ||
134 | unsigned long beg, end; | ||
135 | int y1, y2, miny, maxy; | ||
136 | |||
137 | miny = INT_MAX; | ||
138 | maxy = 0; | ||
139 | list_for_each_entry(page, pagelist, lru) { | ||
140 | beg = page->index << PAGE_SHIFT; | ||
141 | end = beg + PAGE_SIZE - 1; | ||
142 | y1 = beg / fb_info->fix.line_length; | ||
143 | y2 = end / fb_info->fix.line_length; | ||
144 | if (y2 >= fb_info->var.yres) | ||
145 | y2 = fb_info->var.yres - 1; | ||
146 | if (miny > y1) | ||
147 | miny = y1; | ||
148 | if (maxy < y2) | ||
149 | maxy = y2; | ||
150 | } | ||
151 | xenfb_refresh(info, 0, miny, fb_info->var.xres, maxy - miny + 1); | ||
152 | } | ||
153 | |||
154 | static struct fb_deferred_io xenfb_defio = { | ||
155 | .delay = HZ / 20, | ||
156 | .deferred_io = xenfb_deferred_io, | ||
157 | }; | ||
158 | |||
159 | static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green, | ||
160 | unsigned blue, unsigned transp, | ||
161 | struct fb_info *info) | ||
162 | { | ||
163 | u32 v; | ||
164 | |||
165 | if (regno > info->cmap.len) | ||
166 | return 1; | ||
167 | |||
168 | #define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16) | ||
169 | red = CNVT_TOHW(red, info->var.red.length); | ||
170 | green = CNVT_TOHW(green, info->var.green.length); | ||
171 | blue = CNVT_TOHW(blue, info->var.blue.length); | ||
172 | transp = CNVT_TOHW(transp, info->var.transp.length); | ||
173 | #undef CNVT_TOHW | ||
174 | |||
175 | v = (red << info->var.red.offset) | | ||
176 | (green << info->var.green.offset) | | ||
177 | (blue << info->var.blue.offset); | ||
178 | |||
179 | switch (info->var.bits_per_pixel) { | ||
180 | case 16: | ||
181 | case 24: | ||
182 | case 32: | ||
183 | ((u32 *)info->pseudo_palette)[regno] = v; | ||
184 | break; | ||
185 | } | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) | ||
191 | { | ||
192 | struct xenfb_info *info = p->par; | ||
193 | |||
194 | sys_fillrect(p, rect); | ||
195 | xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height); | ||
196 | } | ||
197 | |||
198 | static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image) | ||
199 | { | ||
200 | struct xenfb_info *info = p->par; | ||
201 | |||
202 | sys_imageblit(p, image); | ||
203 | xenfb_refresh(info, image->dx, image->dy, image->width, image->height); | ||
204 | } | ||
205 | |||
206 | static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) | ||
207 | { | ||
208 | struct xenfb_info *info = p->par; | ||
209 | |||
210 | sys_copyarea(p, area); | ||
211 | xenfb_refresh(info, area->dx, area->dy, area->width, area->height); | ||
212 | } | ||
213 | |||
214 | static ssize_t xenfb_write(struct fb_info *p, const char __user *buf, | ||
215 | size_t count, loff_t *ppos) | ||
216 | { | ||
217 | struct xenfb_info *info = p->par; | ||
218 | ssize_t res; | ||
219 | |||
220 | res = fb_sys_write(p, buf, count, ppos); | ||
221 | xenfb_refresh(info, 0, 0, info->page->width, info->page->height); | ||
222 | return res; | ||
223 | } | ||
224 | |||
225 | static struct fb_ops xenfb_fb_ops = { | ||
226 | .owner = THIS_MODULE, | ||
227 | .fb_read = fb_sys_read, | ||
228 | .fb_write = xenfb_write, | ||
229 | .fb_setcolreg = xenfb_setcolreg, | ||
230 | .fb_fillrect = xenfb_fillrect, | ||
231 | .fb_copyarea = xenfb_copyarea, | ||
232 | .fb_imageblit = xenfb_imageblit, | ||
233 | }; | ||
234 | |||
235 | static irqreturn_t xenfb_event_handler(int rq, void *dev_id) | ||
236 | { | ||
237 | /* | ||
238 | * No in events recognized, simply ignore them all. | ||
239 | * If you need to recognize some, see xen-kbdfront's | ||
240 | * input_handler() for how to do that. | ||
241 | */ | ||
242 | struct xenfb_info *info = dev_id; | ||
243 | struct xenfb_page *page = info->page; | ||
244 | |||
245 | if (page->in_cons != page->in_prod) { | ||
246 | info->page->in_cons = info->page->in_prod; | ||
247 | notify_remote_via_irq(info->irq); | ||
248 | } | ||
249 | |||
250 | /* Flush dirty rectangle: */ | ||
251 | xenfb_refresh(info, INT_MAX, INT_MAX, -INT_MAX, -INT_MAX); | ||
252 | |||
253 | return IRQ_HANDLED; | ||
254 | } | ||
255 | |||
256 | static int __devinit xenfb_probe(struct xenbus_device *dev, | ||
257 | const struct xenbus_device_id *id) | ||
258 | { | ||
259 | struct xenfb_info *info; | ||
260 | struct fb_info *fb_info; | ||
261 | int ret; | ||
262 | |||
263 | info = kzalloc(sizeof(*info), GFP_KERNEL); | ||
264 | if (info == NULL) { | ||
265 | xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); | ||
266 | return -ENOMEM; | ||
267 | } | ||
268 | dev->dev.driver_data = info; | ||
269 | info->xbdev = dev; | ||
270 | info->irq = -1; | ||
271 | info->x1 = info->y1 = INT_MAX; | ||
272 | spin_lock_init(&info->dirty_lock); | ||
273 | |||
274 | info->fb = vmalloc(xenfb_mem_len); | ||
275 | if (info->fb == NULL) | ||
276 | goto error_nomem; | ||
277 | memset(info->fb, 0, xenfb_mem_len); | ||
278 | |||
279 | info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
280 | |||
281 | info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages); | ||
282 | if (!info->mfns) | ||
283 | goto error_nomem; | ||
284 | |||
285 | /* set up shared page */ | ||
286 | info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); | ||
287 | if (!info->page) | ||
288 | goto error_nomem; | ||
289 | |||
290 | xenfb_init_shared_page(info); | ||
291 | |||
292 | /* abusing framebuffer_alloc() to allocate pseudo_palette */ | ||
293 | fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL); | ||
294 | if (fb_info == NULL) | ||
295 | goto error_nomem; | ||
296 | |||
297 | /* complete the abuse: */ | ||
298 | fb_info->pseudo_palette = fb_info->par; | ||
299 | fb_info->par = info; | ||
300 | |||
301 | fb_info->screen_base = info->fb; | ||
302 | |||
303 | fb_info->fbops = &xenfb_fb_ops; | ||
304 | fb_info->var.xres_virtual = fb_info->var.xres = info->page->width; | ||
305 | fb_info->var.yres_virtual = fb_info->var.yres = info->page->height; | ||
306 | fb_info->var.bits_per_pixel = info->page->depth; | ||
307 | |||
308 | fb_info->var.red = (struct fb_bitfield){16, 8, 0}; | ||
309 | fb_info->var.green = (struct fb_bitfield){8, 8, 0}; | ||
310 | fb_info->var.blue = (struct fb_bitfield){0, 8, 0}; | ||
311 | |||
312 | fb_info->var.activate = FB_ACTIVATE_NOW; | ||
313 | fb_info->var.height = -1; | ||
314 | fb_info->var.width = -1; | ||
315 | fb_info->var.vmode = FB_VMODE_NONINTERLACED; | ||
316 | |||
317 | fb_info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
318 | fb_info->fix.line_length = info->page->line_length; | ||
319 | fb_info->fix.smem_start = 0; | ||
320 | fb_info->fix.smem_len = xenfb_mem_len; | ||
321 | strcpy(fb_info->fix.id, "xen"); | ||
322 | fb_info->fix.type = FB_TYPE_PACKED_PIXELS; | ||
323 | fb_info->fix.accel = FB_ACCEL_NONE; | ||
324 | |||
325 | fb_info->flags = FBINFO_FLAG_DEFAULT; | ||
326 | |||
327 | ret = fb_alloc_cmap(&fb_info->cmap, 256, 0); | ||
328 | if (ret < 0) { | ||
329 | framebuffer_release(fb_info); | ||
330 | xenbus_dev_fatal(dev, ret, "fb_alloc_cmap"); | ||
331 | goto error; | ||
332 | } | ||
333 | |||
334 | fb_info->fbdefio = &xenfb_defio; | ||
335 | fb_deferred_io_init(fb_info); | ||
336 | |||
337 | ret = register_framebuffer(fb_info); | ||
338 | if (ret) { | ||
339 | fb_deferred_io_cleanup(fb_info); | ||
340 | fb_dealloc_cmap(&fb_info->cmap); | ||
341 | framebuffer_release(fb_info); | ||
342 | xenbus_dev_fatal(dev, ret, "register_framebuffer"); | ||
343 | goto error; | ||
344 | } | ||
345 | info->fb_info = fb_info; | ||
346 | |||
347 | ret = xenfb_connect_backend(dev, info); | ||
348 | if (ret < 0) | ||
349 | goto error; | ||
350 | |||
351 | return 0; | ||
352 | |||
353 | error_nomem: | ||
354 | ret = -ENOMEM; | ||
355 | xenbus_dev_fatal(dev, ret, "allocating device memory"); | ||
356 | error: | ||
357 | xenfb_remove(dev); | ||
358 | return ret; | ||
359 | } | ||
360 | |||
361 | static int xenfb_resume(struct xenbus_device *dev) | ||
362 | { | ||
363 | struct xenfb_info *info = dev->dev.driver_data; | ||
364 | |||
365 | xenfb_disconnect_backend(info); | ||
366 | xenfb_init_shared_page(info); | ||
367 | return xenfb_connect_backend(dev, info); | ||
368 | } | ||
369 | |||
370 | static int xenfb_remove(struct xenbus_device *dev) | ||
371 | { | ||
372 | struct xenfb_info *info = dev->dev.driver_data; | ||
373 | |||
374 | xenfb_disconnect_backend(info); | ||
375 | if (info->fb_info) { | ||
376 | fb_deferred_io_cleanup(info->fb_info); | ||
377 | unregister_framebuffer(info->fb_info); | ||
378 | fb_dealloc_cmap(&info->fb_info->cmap); | ||
379 | framebuffer_release(info->fb_info); | ||
380 | } | ||
381 | free_page((unsigned long)info->page); | ||
382 | vfree(info->mfns); | ||
383 | vfree(info->fb); | ||
384 | kfree(info); | ||
385 | |||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static unsigned long vmalloc_to_mfn(void *address) | ||
390 | { | ||
391 | return pfn_to_mfn(vmalloc_to_pfn(address)); | ||
392 | } | ||
393 | |||
394 | static void xenfb_init_shared_page(struct xenfb_info *info) | ||
395 | { | ||
396 | int i; | ||
397 | |||
398 | for (i = 0; i < info->nr_pages; i++) | ||
399 | info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); | ||
400 | |||
401 | info->page->pd[0] = vmalloc_to_mfn(info->mfns); | ||
402 | info->page->pd[1] = 0; | ||
403 | info->page->width = XENFB_WIDTH; | ||
404 | info->page->height = XENFB_HEIGHT; | ||
405 | info->page->depth = XENFB_DEPTH; | ||
406 | info->page->line_length = (info->page->depth / 8) * info->page->width; | ||
407 | info->page->mem_length = xenfb_mem_len; | ||
408 | info->page->in_cons = info->page->in_prod = 0; | ||
409 | info->page->out_cons = info->page->out_prod = 0; | ||
410 | } | ||
411 | |||
412 | static int xenfb_connect_backend(struct xenbus_device *dev, | ||
413 | struct xenfb_info *info) | ||
414 | { | ||
415 | int ret, evtchn; | ||
416 | struct xenbus_transaction xbt; | ||
417 | |||
418 | ret = xenbus_alloc_evtchn(dev, &evtchn); | ||
419 | if (ret) | ||
420 | return ret; | ||
421 | ret = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler, | ||
422 | 0, dev->devicetype, info); | ||
423 | if (ret < 0) { | ||
424 | xenbus_free_evtchn(dev, evtchn); | ||
425 | xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); | ||
426 | return ret; | ||
427 | } | ||
428 | info->irq = ret; | ||
429 | |||
430 | again: | ||
431 | ret = xenbus_transaction_start(&xbt); | ||
432 | if (ret) { | ||
433 | xenbus_dev_fatal(dev, ret, "starting transaction"); | ||
434 | return ret; | ||
435 | } | ||
436 | ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", | ||
437 | virt_to_mfn(info->page)); | ||
438 | if (ret) | ||
439 | goto error_xenbus; | ||
440 | ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", | ||
441 | evtchn); | ||
442 | if (ret) | ||
443 | goto error_xenbus; | ||
444 | ret = xenbus_printf(xbt, dev->nodename, "protocol", "%s", | ||
445 | XEN_IO_PROTO_ABI_NATIVE); | ||
446 | if (ret) | ||
447 | goto error_xenbus; | ||
448 | ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1"); | ||
449 | if (ret) | ||
450 | goto error_xenbus; | ||
451 | ret = xenbus_transaction_end(xbt, 0); | ||
452 | if (ret) { | ||
453 | if (ret == -EAGAIN) | ||
454 | goto again; | ||
455 | xenbus_dev_fatal(dev, ret, "completing transaction"); | ||
456 | return ret; | ||
457 | } | ||
458 | |||
459 | xenbus_switch_state(dev, XenbusStateInitialised); | ||
460 | return 0; | ||
461 | |||
462 | error_xenbus: | ||
463 | xenbus_transaction_end(xbt, 1); | ||
464 | xenbus_dev_fatal(dev, ret, "writing xenstore"); | ||
465 | return ret; | ||
466 | } | ||
467 | |||
468 | static void xenfb_disconnect_backend(struct xenfb_info *info) | ||
469 | { | ||
470 | if (info->irq >= 0) | ||
471 | unbind_from_irqhandler(info->irq, info); | ||
472 | info->irq = -1; | ||
473 | } | ||
474 | |||
475 | static void xenfb_backend_changed(struct xenbus_device *dev, | ||
476 | enum xenbus_state backend_state) | ||
477 | { | ||
478 | struct xenfb_info *info = dev->dev.driver_data; | ||
479 | int val; | ||
480 | |||
481 | switch (backend_state) { | ||
482 | case XenbusStateInitialising: | ||
483 | case XenbusStateInitialised: | ||
484 | case XenbusStateUnknown: | ||
485 | case XenbusStateClosed: | ||
486 | break; | ||
487 | |||
488 | case XenbusStateInitWait: | ||
489 | InitWait: | ||
490 | xenbus_switch_state(dev, XenbusStateConnected); | ||
491 | break; | ||
492 | |||
493 | case XenbusStateConnected: | ||
494 | /* | ||
495 | * Work around xenbus race condition: If backend goes | ||
496 | * through InitWait to Connected fast enough, we can | ||
497 | * get Connected twice here. | ||
498 | */ | ||
499 | if (dev->state != XenbusStateConnected) | ||
500 | goto InitWait; /* no InitWait seen yet, fudge it */ | ||
501 | |||
502 | if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, | ||
503 | "request-update", "%d", &val) < 0) | ||
504 | val = 0; | ||
505 | if (val) | ||
506 | info->update_wanted = 1; | ||
507 | break; | ||
508 | |||
509 | case XenbusStateClosing: | ||
510 | xenbus_frontend_closed(dev); | ||
511 | break; | ||
512 | } | ||
513 | } | ||
514 | |||
515 | static struct xenbus_device_id xenfb_ids[] = { | ||
516 | { "vfb" }, | ||
517 | { "" } | ||
518 | }; | ||
519 | |||
520 | static struct xenbus_driver xenfb = { | ||
521 | .name = "vfb", | ||
522 | .owner = THIS_MODULE, | ||
523 | .ids = xenfb_ids, | ||
524 | .probe = xenfb_probe, | ||
525 | .remove = xenfb_remove, | ||
526 | .resume = xenfb_resume, | ||
527 | .otherend_changed = xenfb_backend_changed, | ||
528 | }; | ||
529 | |||
530 | static int __init xenfb_init(void) | ||
531 | { | ||
532 | if (!is_running_on_xen()) | ||
533 | return -ENODEV; | ||
534 | |||
535 | /* Nothing to do if running in dom0. */ | ||
536 | if (is_initial_xendomain()) | ||
537 | return -ENODEV; | ||
538 | |||
539 | return xenbus_register_frontend(&xenfb); | ||
540 | } | ||
541 | |||
542 | static void __exit xenfb_cleanup(void) | ||
543 | { | ||
544 | xenbus_unregister_driver(&xenfb); | ||
545 | } | ||
546 | |||
547 | module_init(xenfb_init); | ||
548 | module_exit(xenfb_cleanup); | ||
549 | |||
550 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig new file mode 100644 index 000000000000..4b75a16de009 --- /dev/null +++ b/drivers/xen/Kconfig | |||
@@ -0,0 +1,19 @@ | |||
1 | config XEN_BALLOON | ||
2 | bool "Xen memory balloon driver" | ||
3 | depends on XEN | ||
4 | default y | ||
5 | help | ||
6 | The balloon driver allows the Xen domain to request more memory from | ||
7 | the system to expand the domain's memory allocation, or alternatively | ||
8 | return unneeded memory to the system. | ||
9 | |||
10 | config XEN_SCRUB_PAGES | ||
11 | bool "Scrub pages before returning them to system" | ||
12 | depends on XEN_BALLOON | ||
13 | default y | ||
14 | help | ||
15 | Scrub pages before returning them to the system for reuse by | ||
16 | other domains. This makes sure that any confidential data | ||
17 | is not accidentally visible to other domains. Is it more | ||
18 | secure, but slightly less efficient. | ||
19 | If in doubt, say yes. | ||
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 56592f0d6cef..37af04f1ffd9 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile | |||
@@ -1,2 +1,4 @@ | |||
1 | obj-y += grant-table.o | 1 | obj-y += grant-table.o features.o events.o |
2 | obj-y += xenbus/ | 2 | obj-y += xenbus/ |
3 | obj-$(CONFIG_XEN_XENCOMM) += xencomm.o | ||
4 | obj-$(CONFIG_XEN_BALLOON) += balloon.o | ||
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c new file mode 100644 index 000000000000..ab25ba6cbbb9 --- /dev/null +++ b/drivers/xen/balloon.c | |||
@@ -0,0 +1,712 @@ | |||
1 | /****************************************************************************** | ||
2 | * balloon.c | ||
3 | * | ||
4 | * Xen balloon driver - enables returning/claiming memory to/from Xen. | ||
5 | * | ||
6 | * Copyright (c) 2003, B Dragovic | ||
7 | * Copyright (c) 2003-2004, M Williamson, K Fraser | ||
8 | * Copyright (c) 2005 Dan M. Smith, IBM Corporation | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License version 2 | ||
12 | * as published by the Free Software Foundation; or, when distributed | ||
13 | * separately from the Linux kernel or incorporated into other | ||
14 | * software packages, subject to the following license: | ||
15 | * | ||
16 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
17 | * of this source file (the "Software"), to deal in the Software without | ||
18 | * restriction, including without limitation the rights to use, copy, modify, | ||
19 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, | ||
20 | * and to permit persons to whom the Software is furnished to do so, subject to | ||
21 | * the following conditions: | ||
22 | * | ||
23 | * The above copyright notice and this permission notice shall be included in | ||
24 | * all copies or substantial portions of the Software. | ||
25 | * | ||
26 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
27 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
28 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
29 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
30 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
31 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
32 | * IN THE SOFTWARE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/sched.h> | ||
38 | #include <linux/errno.h> | ||
39 | #include <linux/mm.h> | ||
40 | #include <linux/bootmem.h> | ||
41 | #include <linux/pagemap.h> | ||
42 | #include <linux/highmem.h> | ||
43 | #include <linux/mutex.h> | ||
44 | #include <linux/highmem.h> | ||
45 | #include <linux/list.h> | ||
46 | #include <linux/sysdev.h> | ||
47 | |||
48 | #include <asm/xen/hypervisor.h> | ||
49 | #include <asm/page.h> | ||
50 | #include <asm/pgalloc.h> | ||
51 | #include <asm/pgtable.h> | ||
52 | #include <asm/uaccess.h> | ||
53 | #include <asm/tlb.h> | ||
54 | |||
55 | #include <xen/interface/memory.h> | ||
56 | #include <xen/balloon.h> | ||
57 | #include <xen/xenbus.h> | ||
58 | #include <xen/features.h> | ||
59 | #include <xen/page.h> | ||
60 | |||
61 | #define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10)) | ||
62 | |||
63 | #define BALLOON_CLASS_NAME "memory" | ||
64 | |||
65 | struct balloon_stats { | ||
66 | /* We aim for 'current allocation' == 'target allocation'. */ | ||
67 | unsigned long current_pages; | ||
68 | unsigned long target_pages; | ||
69 | /* We may hit the hard limit in Xen. If we do then we remember it. */ | ||
70 | unsigned long hard_limit; | ||
71 | /* | ||
72 | * Drivers may alter the memory reservation independently, but they | ||
73 | * must inform the balloon driver so we avoid hitting the hard limit. | ||
74 | */ | ||
75 | unsigned long driver_pages; | ||
76 | /* Number of pages in high- and low-memory balloons. */ | ||
77 | unsigned long balloon_low; | ||
78 | unsigned long balloon_high; | ||
79 | }; | ||
80 | |||
81 | static DEFINE_MUTEX(balloon_mutex); | ||
82 | |||
83 | static struct sys_device balloon_sysdev; | ||
84 | |||
85 | static int register_balloon(struct sys_device *sysdev); | ||
86 | |||
87 | /* | ||
88 | * Protects atomic reservation decrease/increase against concurrent increases. | ||
89 | * Also protects non-atomic updates of current_pages and driver_pages, and | ||
90 | * balloon lists. | ||
91 | */ | ||
92 | static DEFINE_SPINLOCK(balloon_lock); | ||
93 | |||
94 | static struct balloon_stats balloon_stats; | ||
95 | |||
96 | /* We increase/decrease in batches which fit in a page */ | ||
97 | static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)]; | ||
98 | |||
99 | /* VM /proc information for memory */ | ||
100 | extern unsigned long totalram_pages; | ||
101 | |||
102 | #ifdef CONFIG_HIGHMEM | ||
103 | extern unsigned long totalhigh_pages; | ||
104 | #define inc_totalhigh_pages() (totalhigh_pages++) | ||
105 | #define dec_totalhigh_pages() (totalhigh_pages--) | ||
106 | #else | ||
107 | #define inc_totalhigh_pages() do {} while(0) | ||
108 | #define dec_totalhigh_pages() do {} while(0) | ||
109 | #endif | ||
110 | |||
111 | /* List of ballooned pages, threaded through the mem_map array. */ | ||
112 | static LIST_HEAD(ballooned_pages); | ||
113 | |||
114 | /* Main work function, always executed in process context. */ | ||
115 | static void balloon_process(struct work_struct *work); | ||
116 | static DECLARE_WORK(balloon_worker, balloon_process); | ||
117 | static struct timer_list balloon_timer; | ||
118 | |||
119 | /* When ballooning out (allocating memory to return to Xen) we don't really | ||
120 | want the kernel to try too hard since that can trigger the oom killer. */ | ||
121 | #define GFP_BALLOON \ | ||
122 | (GFP_HIGHUSER | __GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC) | ||
123 | |||
124 | static void scrub_page(struct page *page) | ||
125 | { | ||
126 | #ifdef CONFIG_XEN_SCRUB_PAGES | ||
127 | if (PageHighMem(page)) { | ||
128 | void *v = kmap(page); | ||
129 | clear_page(v); | ||
130 | kunmap(v); | ||
131 | } else { | ||
132 | void *v = page_address(page); | ||
133 | clear_page(v); | ||
134 | } | ||
135 | #endif | ||
136 | } | ||
137 | |||
138 | /* balloon_append: add the given page to the balloon. */ | ||
139 | static void balloon_append(struct page *page) | ||
140 | { | ||
141 | /* Lowmem is re-populated first, so highmem pages go at list tail. */ | ||
142 | if (PageHighMem(page)) { | ||
143 | list_add_tail(&page->lru, &ballooned_pages); | ||
144 | balloon_stats.balloon_high++; | ||
145 | dec_totalhigh_pages(); | ||
146 | } else { | ||
147 | list_add(&page->lru, &ballooned_pages); | ||
148 | balloon_stats.balloon_low++; | ||
149 | } | ||
150 | } | ||
151 | |||
152 | /* balloon_retrieve: rescue a page from the balloon, if it is not empty. */ | ||
153 | static struct page *balloon_retrieve(void) | ||
154 | { | ||
155 | struct page *page; | ||
156 | |||
157 | if (list_empty(&ballooned_pages)) | ||
158 | return NULL; | ||
159 | |||
160 | page = list_entry(ballooned_pages.next, struct page, lru); | ||
161 | list_del(&page->lru); | ||
162 | |||
163 | if (PageHighMem(page)) { | ||
164 | balloon_stats.balloon_high--; | ||
165 | inc_totalhigh_pages(); | ||
166 | } | ||
167 | else | ||
168 | balloon_stats.balloon_low--; | ||
169 | |||
170 | return page; | ||
171 | } | ||
172 | |||
173 | static struct page *balloon_first_page(void) | ||
174 | { | ||
175 | if (list_empty(&ballooned_pages)) | ||
176 | return NULL; | ||
177 | return list_entry(ballooned_pages.next, struct page, lru); | ||
178 | } | ||
179 | |||
180 | static struct page *balloon_next_page(struct page *page) | ||
181 | { | ||
182 | struct list_head *next = page->lru.next; | ||
183 | if (next == &ballooned_pages) | ||
184 | return NULL; | ||
185 | return list_entry(next, struct page, lru); | ||
186 | } | ||
187 | |||
188 | static void balloon_alarm(unsigned long unused) | ||
189 | { | ||
190 | schedule_work(&balloon_worker); | ||
191 | } | ||
192 | |||
193 | static unsigned long current_target(void) | ||
194 | { | ||
195 | unsigned long target = min(balloon_stats.target_pages, balloon_stats.hard_limit); | ||
196 | |||
197 | target = min(target, | ||
198 | balloon_stats.current_pages + | ||
199 | balloon_stats.balloon_low + | ||
200 | balloon_stats.balloon_high); | ||
201 | |||
202 | return target; | ||
203 | } | ||
204 | |||
205 | static int increase_reservation(unsigned long nr_pages) | ||
206 | { | ||
207 | unsigned long pfn, i, flags; | ||
208 | struct page *page; | ||
209 | long rc; | ||
210 | struct xen_memory_reservation reservation = { | ||
211 | .address_bits = 0, | ||
212 | .extent_order = 0, | ||
213 | .domid = DOMID_SELF | ||
214 | }; | ||
215 | |||
216 | if (nr_pages > ARRAY_SIZE(frame_list)) | ||
217 | nr_pages = ARRAY_SIZE(frame_list); | ||
218 | |||
219 | spin_lock_irqsave(&balloon_lock, flags); | ||
220 | |||
221 | page = balloon_first_page(); | ||
222 | for (i = 0; i < nr_pages; i++) { | ||
223 | BUG_ON(page == NULL); | ||
224 | frame_list[i] = page_to_pfn(page);; | ||
225 | page = balloon_next_page(page); | ||
226 | } | ||
227 | |||
228 | reservation.extent_start = (unsigned long)frame_list; | ||
229 | reservation.nr_extents = nr_pages; | ||
230 | rc = HYPERVISOR_memory_op( | ||
231 | XENMEM_populate_physmap, &reservation); | ||
232 | if (rc < nr_pages) { | ||
233 | if (rc > 0) { | ||
234 | int ret; | ||
235 | |||
236 | /* We hit the Xen hard limit: reprobe. */ | ||
237 | reservation.nr_extents = rc; | ||
238 | ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, | ||
239 | &reservation); | ||
240 | BUG_ON(ret != rc); | ||
241 | } | ||
242 | if (rc >= 0) | ||
243 | balloon_stats.hard_limit = (balloon_stats.current_pages + rc - | ||
244 | balloon_stats.driver_pages); | ||
245 | goto out; | ||
246 | } | ||
247 | |||
248 | for (i = 0; i < nr_pages; i++) { | ||
249 | page = balloon_retrieve(); | ||
250 | BUG_ON(page == NULL); | ||
251 | |||
252 | pfn = page_to_pfn(page); | ||
253 | BUG_ON(!xen_feature(XENFEAT_auto_translated_physmap) && | ||
254 | phys_to_machine_mapping_valid(pfn)); | ||
255 | |||
256 | set_phys_to_machine(pfn, frame_list[i]); | ||
257 | |||
258 | /* Link back into the page tables if not highmem. */ | ||
259 | if (pfn < max_low_pfn) { | ||
260 | int ret; | ||
261 | ret = HYPERVISOR_update_va_mapping( | ||
262 | (unsigned long)__va(pfn << PAGE_SHIFT), | ||
263 | mfn_pte(frame_list[i], PAGE_KERNEL), | ||
264 | 0); | ||
265 | BUG_ON(ret); | ||
266 | } | ||
267 | |||
268 | /* Relinquish the page back to the allocator. */ | ||
269 | ClearPageReserved(page); | ||
270 | init_page_count(page); | ||
271 | __free_page(page); | ||
272 | } | ||
273 | |||
274 | balloon_stats.current_pages += nr_pages; | ||
275 | totalram_pages = balloon_stats.current_pages; | ||
276 | |||
277 | out: | ||
278 | spin_unlock_irqrestore(&balloon_lock, flags); | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static int decrease_reservation(unsigned long nr_pages) | ||
284 | { | ||
285 | unsigned long pfn, i, flags; | ||
286 | struct page *page; | ||
287 | int need_sleep = 0; | ||
288 | int ret; | ||
289 | struct xen_memory_reservation reservation = { | ||
290 | .address_bits = 0, | ||
291 | .extent_order = 0, | ||
292 | .domid = DOMID_SELF | ||
293 | }; | ||
294 | |||
295 | if (nr_pages > ARRAY_SIZE(frame_list)) | ||
296 | nr_pages = ARRAY_SIZE(frame_list); | ||
297 | |||
298 | for (i = 0; i < nr_pages; i++) { | ||
299 | if ((page = alloc_page(GFP_BALLOON)) == NULL) { | ||
300 | nr_pages = i; | ||
301 | need_sleep = 1; | ||
302 | break; | ||
303 | } | ||
304 | |||
305 | pfn = page_to_pfn(page); | ||
306 | frame_list[i] = pfn_to_mfn(pfn); | ||
307 | |||
308 | scrub_page(page); | ||
309 | } | ||
310 | |||
311 | /* Ensure that ballooned highmem pages don't have kmaps. */ | ||
312 | kmap_flush_unused(); | ||
313 | flush_tlb_all(); | ||
314 | |||
315 | spin_lock_irqsave(&balloon_lock, flags); | ||
316 | |||
317 | /* No more mappings: invalidate P2M and add to balloon. */ | ||
318 | for (i = 0; i < nr_pages; i++) { | ||
319 | pfn = mfn_to_pfn(frame_list[i]); | ||
320 | set_phys_to_machine(pfn, INVALID_P2M_ENTRY); | ||
321 | balloon_append(pfn_to_page(pfn)); | ||
322 | } | ||
323 | |||
324 | reservation.extent_start = (unsigned long)frame_list; | ||
325 | reservation.nr_extents = nr_pages; | ||
326 | ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation); | ||
327 | BUG_ON(ret != nr_pages); | ||
328 | |||
329 | balloon_stats.current_pages -= nr_pages; | ||
330 | totalram_pages = balloon_stats.current_pages; | ||
331 | |||
332 | spin_unlock_irqrestore(&balloon_lock, flags); | ||
333 | |||
334 | return need_sleep; | ||
335 | } | ||
336 | |||
337 | /* | ||
338 | * We avoid multiple worker processes conflicting via the balloon mutex. | ||
339 | * We may of course race updates of the target counts (which are protected | ||
340 | * by the balloon lock), or with changes to the Xen hard limit, but we will | ||
341 | * recover from these in time. | ||
342 | */ | ||
343 | static void balloon_process(struct work_struct *work) | ||
344 | { | ||
345 | int need_sleep = 0; | ||
346 | long credit; | ||
347 | |||
348 | mutex_lock(&balloon_mutex); | ||
349 | |||
350 | do { | ||
351 | credit = current_target() - balloon_stats.current_pages; | ||
352 | if (credit > 0) | ||
353 | need_sleep = (increase_reservation(credit) != 0); | ||
354 | if (credit < 0) | ||
355 | need_sleep = (decrease_reservation(-credit) != 0); | ||
356 | |||
357 | #ifndef CONFIG_PREEMPT | ||
358 | if (need_resched()) | ||
359 | schedule(); | ||
360 | #endif | ||
361 | } while ((credit != 0) && !need_sleep); | ||
362 | |||
363 | /* Schedule more work if there is some still to be done. */ | ||
364 | if (current_target() != balloon_stats.current_pages) | ||
365 | mod_timer(&balloon_timer, jiffies + HZ); | ||
366 | |||
367 | mutex_unlock(&balloon_mutex); | ||
368 | } | ||
369 | |||
370 | /* Resets the Xen limit, sets new target, and kicks off processing. */ | ||
371 | void balloon_set_new_target(unsigned long target) | ||
372 | { | ||
373 | /* No need for lock. Not read-modify-write updates. */ | ||
374 | balloon_stats.hard_limit = ~0UL; | ||
375 | balloon_stats.target_pages = target; | ||
376 | schedule_work(&balloon_worker); | ||
377 | } | ||
378 | |||
379 | static struct xenbus_watch target_watch = | ||
380 | { | ||
381 | .node = "memory/target" | ||
382 | }; | ||
383 | |||
384 | /* React to a change in the target key */ | ||
385 | static void watch_target(struct xenbus_watch *watch, | ||
386 | const char **vec, unsigned int len) | ||
387 | { | ||
388 | unsigned long long new_target; | ||
389 | int err; | ||
390 | |||
391 | err = xenbus_scanf(XBT_NIL, "memory", "target", "%llu", &new_target); | ||
392 | if (err != 1) { | ||
393 | /* This is ok (for domain0 at least) - so just return */ | ||
394 | return; | ||
395 | } | ||
396 | |||
397 | /* The given memory/target value is in KiB, so it needs converting to | ||
398 | * pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10. | ||
399 | */ | ||
400 | balloon_set_new_target(new_target >> (PAGE_SHIFT - 10)); | ||
401 | } | ||
402 | |||
403 | static int balloon_init_watcher(struct notifier_block *notifier, | ||
404 | unsigned long event, | ||
405 | void *data) | ||
406 | { | ||
407 | int err; | ||
408 | |||
409 | err = register_xenbus_watch(&target_watch); | ||
410 | if (err) | ||
411 | printk(KERN_ERR "Failed to set balloon watcher\n"); | ||
412 | |||
413 | return NOTIFY_DONE; | ||
414 | } | ||
415 | |||
416 | static struct notifier_block xenstore_notifier; | ||
417 | |||
418 | static int __init balloon_init(void) | ||
419 | { | ||
420 | unsigned long pfn; | ||
421 | struct page *page; | ||
422 | |||
423 | if (!is_running_on_xen()) | ||
424 | return -ENODEV; | ||
425 | |||
426 | pr_info("xen_balloon: Initialising balloon driver.\n"); | ||
427 | |||
428 | balloon_stats.current_pages = min(xen_start_info->nr_pages, max_pfn); | ||
429 | totalram_pages = balloon_stats.current_pages; | ||
430 | balloon_stats.target_pages = balloon_stats.current_pages; | ||
431 | balloon_stats.balloon_low = 0; | ||
432 | balloon_stats.balloon_high = 0; | ||
433 | balloon_stats.driver_pages = 0UL; | ||
434 | balloon_stats.hard_limit = ~0UL; | ||
435 | |||
436 | init_timer(&balloon_timer); | ||
437 | balloon_timer.data = 0; | ||
438 | balloon_timer.function = balloon_alarm; | ||
439 | |||
440 | register_balloon(&balloon_sysdev); | ||
441 | |||
442 | /* Initialise the balloon with excess memory space. */ | ||
443 | for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) { | ||
444 | page = pfn_to_page(pfn); | ||
445 | if (!PageReserved(page)) | ||
446 | balloon_append(page); | ||
447 | } | ||
448 | |||
449 | target_watch.callback = watch_target; | ||
450 | xenstore_notifier.notifier_call = balloon_init_watcher; | ||
451 | |||
452 | register_xenstore_notifier(&xenstore_notifier); | ||
453 | |||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | subsys_initcall(balloon_init); | ||
458 | |||
459 | static void balloon_exit(void) | ||
460 | { | ||
461 | /* XXX - release balloon here */ | ||
462 | return; | ||
463 | } | ||
464 | |||
465 | module_exit(balloon_exit); | ||
466 | |||
467 | static void balloon_update_driver_allowance(long delta) | ||
468 | { | ||
469 | unsigned long flags; | ||
470 | |||
471 | spin_lock_irqsave(&balloon_lock, flags); | ||
472 | balloon_stats.driver_pages += delta; | ||
473 | spin_unlock_irqrestore(&balloon_lock, flags); | ||
474 | } | ||
475 | |||
476 | static int dealloc_pte_fn( | ||
477 | pte_t *pte, struct page *pmd_page, unsigned long addr, void *data) | ||
478 | { | ||
479 | unsigned long mfn = pte_mfn(*pte); | ||
480 | int ret; | ||
481 | struct xen_memory_reservation reservation = { | ||
482 | .nr_extents = 1, | ||
483 | .extent_order = 0, | ||
484 | .domid = DOMID_SELF | ||
485 | }; | ||
486 | reservation.extent_start = (unsigned long)&mfn; | ||
487 | set_pte_at(&init_mm, addr, pte, __pte_ma(0ull)); | ||
488 | set_phys_to_machine(__pa(addr) >> PAGE_SHIFT, INVALID_P2M_ENTRY); | ||
489 | ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation); | ||
490 | BUG_ON(ret != 1); | ||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | static struct page **alloc_empty_pages_and_pagevec(int nr_pages) | ||
495 | { | ||
496 | unsigned long vaddr, flags; | ||
497 | struct page *page, **pagevec; | ||
498 | int i, ret; | ||
499 | |||
500 | pagevec = kmalloc(sizeof(page) * nr_pages, GFP_KERNEL); | ||
501 | if (pagevec == NULL) | ||
502 | return NULL; | ||
503 | |||
504 | for (i = 0; i < nr_pages; i++) { | ||
505 | page = pagevec[i] = alloc_page(GFP_KERNEL); | ||
506 | if (page == NULL) | ||
507 | goto err; | ||
508 | |||
509 | vaddr = (unsigned long)page_address(page); | ||
510 | |||
511 | scrub_page(page); | ||
512 | |||
513 | spin_lock_irqsave(&balloon_lock, flags); | ||
514 | |||
515 | if (xen_feature(XENFEAT_auto_translated_physmap)) { | ||
516 | unsigned long gmfn = page_to_pfn(page); | ||
517 | struct xen_memory_reservation reservation = { | ||
518 | .nr_extents = 1, | ||
519 | .extent_order = 0, | ||
520 | .domid = DOMID_SELF | ||
521 | }; | ||
522 | reservation.extent_start = (unsigned long)&gmfn; | ||
523 | ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, | ||
524 | &reservation); | ||
525 | if (ret == 1) | ||
526 | ret = 0; /* success */ | ||
527 | } else { | ||
528 | ret = apply_to_page_range(&init_mm, vaddr, PAGE_SIZE, | ||
529 | dealloc_pte_fn, NULL); | ||
530 | } | ||
531 | |||
532 | if (ret != 0) { | ||
533 | spin_unlock_irqrestore(&balloon_lock, flags); | ||
534 | __free_page(page); | ||
535 | goto err; | ||
536 | } | ||
537 | |||
538 | totalram_pages = --balloon_stats.current_pages; | ||
539 | |||
540 | spin_unlock_irqrestore(&balloon_lock, flags); | ||
541 | } | ||
542 | |||
543 | out: | ||
544 | schedule_work(&balloon_worker); | ||
545 | flush_tlb_all(); | ||
546 | return pagevec; | ||
547 | |||
548 | err: | ||
549 | spin_lock_irqsave(&balloon_lock, flags); | ||
550 | while (--i >= 0) | ||
551 | balloon_append(pagevec[i]); | ||
552 | spin_unlock_irqrestore(&balloon_lock, flags); | ||
553 | kfree(pagevec); | ||
554 | pagevec = NULL; | ||
555 | goto out; | ||
556 | } | ||
557 | |||
558 | static void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages) | ||
559 | { | ||
560 | unsigned long flags; | ||
561 | int i; | ||
562 | |||
563 | if (pagevec == NULL) | ||
564 | return; | ||
565 | |||
566 | spin_lock_irqsave(&balloon_lock, flags); | ||
567 | for (i = 0; i < nr_pages; i++) { | ||
568 | BUG_ON(page_count(pagevec[i]) != 1); | ||
569 | balloon_append(pagevec[i]); | ||
570 | } | ||
571 | spin_unlock_irqrestore(&balloon_lock, flags); | ||
572 | |||
573 | kfree(pagevec); | ||
574 | |||
575 | schedule_work(&balloon_worker); | ||
576 | } | ||
577 | |||
578 | static void balloon_release_driver_page(struct page *page) | ||
579 | { | ||
580 | unsigned long flags; | ||
581 | |||
582 | spin_lock_irqsave(&balloon_lock, flags); | ||
583 | balloon_append(page); | ||
584 | balloon_stats.driver_pages--; | ||
585 | spin_unlock_irqrestore(&balloon_lock, flags); | ||
586 | |||
587 | schedule_work(&balloon_worker); | ||
588 | } | ||
589 | |||
590 | |||
591 | #define BALLOON_SHOW(name, format, args...) \ | ||
592 | static ssize_t show_##name(struct sys_device *dev, \ | ||
593 | char *buf) \ | ||
594 | { \ | ||
595 | return sprintf(buf, format, ##args); \ | ||
596 | } \ | ||
597 | static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL) | ||
598 | |||
599 | BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages)); | ||
600 | BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low)); | ||
601 | BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_high)); | ||
602 | BALLOON_SHOW(hard_limit_kb, | ||
603 | (balloon_stats.hard_limit!=~0UL) ? "%lu\n" : "???\n", | ||
604 | (balloon_stats.hard_limit!=~0UL) ? PAGES2KB(balloon_stats.hard_limit) : 0); | ||
605 | BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(balloon_stats.driver_pages)); | ||
606 | |||
607 | static ssize_t show_target_kb(struct sys_device *dev, char *buf) | ||
608 | { | ||
609 | return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages)); | ||
610 | } | ||
611 | |||
612 | static ssize_t store_target_kb(struct sys_device *dev, | ||
613 | const char *buf, | ||
614 | size_t count) | ||
615 | { | ||
616 | char memstring[64], *endchar; | ||
617 | unsigned long long target_bytes; | ||
618 | |||
619 | if (!capable(CAP_SYS_ADMIN)) | ||
620 | return -EPERM; | ||
621 | |||
622 | if (count <= 1) | ||
623 | return -EBADMSG; /* runt */ | ||
624 | if (count > sizeof(memstring)) | ||
625 | return -EFBIG; /* too long */ | ||
626 | strcpy(memstring, buf); | ||
627 | |||
628 | target_bytes = memparse(memstring, &endchar); | ||
629 | balloon_set_new_target(target_bytes >> PAGE_SHIFT); | ||
630 | |||
631 | return count; | ||
632 | } | ||
633 | |||
634 | static SYSDEV_ATTR(target_kb, S_IRUGO | S_IWUSR, | ||
635 | show_target_kb, store_target_kb); | ||
636 | |||
637 | static struct sysdev_attribute *balloon_attrs[] = { | ||
638 | &attr_target_kb, | ||
639 | }; | ||
640 | |||
641 | static struct attribute *balloon_info_attrs[] = { | ||
642 | &attr_current_kb.attr, | ||
643 | &attr_low_kb.attr, | ||
644 | &attr_high_kb.attr, | ||
645 | &attr_hard_limit_kb.attr, | ||
646 | &attr_driver_kb.attr, | ||
647 | NULL | ||
648 | }; | ||
649 | |||
650 | static struct attribute_group balloon_info_group = { | ||
651 | .name = "info", | ||
652 | .attrs = balloon_info_attrs, | ||
653 | }; | ||
654 | |||
655 | static struct sysdev_class balloon_sysdev_class = { | ||
656 | .name = BALLOON_CLASS_NAME, | ||
657 | }; | ||
658 | |||
659 | static int register_balloon(struct sys_device *sysdev) | ||
660 | { | ||
661 | int i, error; | ||
662 | |||
663 | error = sysdev_class_register(&balloon_sysdev_class); | ||
664 | if (error) | ||
665 | return error; | ||
666 | |||
667 | sysdev->id = 0; | ||
668 | sysdev->cls = &balloon_sysdev_class; | ||
669 | |||
670 | error = sysdev_register(sysdev); | ||
671 | if (error) { | ||
672 | sysdev_class_unregister(&balloon_sysdev_class); | ||
673 | return error; | ||
674 | } | ||
675 | |||
676 | for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) { | ||
677 | error = sysdev_create_file(sysdev, balloon_attrs[i]); | ||
678 | if (error) | ||
679 | goto fail; | ||
680 | } | ||
681 | |||
682 | error = sysfs_create_group(&sysdev->kobj, &balloon_info_group); | ||
683 | if (error) | ||
684 | goto fail; | ||
685 | |||
686 | return 0; | ||
687 | |||
688 | fail: | ||
689 | while (--i >= 0) | ||
690 | sysdev_remove_file(sysdev, balloon_attrs[i]); | ||
691 | sysdev_unregister(sysdev); | ||
692 | sysdev_class_unregister(&balloon_sysdev_class); | ||
693 | return error; | ||
694 | } | ||
695 | |||
696 | static void unregister_balloon(struct sys_device *sysdev) | ||
697 | { | ||
698 | int i; | ||
699 | |||
700 | sysfs_remove_group(&sysdev->kobj, &balloon_info_group); | ||
701 | for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) | ||
702 | sysdev_remove_file(sysdev, balloon_attrs[i]); | ||
703 | sysdev_unregister(sysdev); | ||
704 | sysdev_class_unregister(&balloon_sysdev_class); | ||
705 | } | ||
706 | |||
707 | static void balloon_sysfs_exit(void) | ||
708 | { | ||
709 | unregister_balloon(&balloon_sysdev); | ||
710 | } | ||
711 | |||
712 | MODULE_LICENSE("GPL"); | ||
diff --git a/arch/x86/xen/events.c b/drivers/xen/events.c index dcf613e17581..4f0f22b020ea 100644 --- a/arch/x86/xen/events.c +++ b/drivers/xen/events.c | |||
@@ -33,12 +33,11 @@ | |||
33 | #include <asm/xen/hypercall.h> | 33 | #include <asm/xen/hypercall.h> |
34 | #include <asm/xen/hypervisor.h> | 34 | #include <asm/xen/hypervisor.h> |
35 | 35 | ||
36 | #include <xen/xen-ops.h> | ||
36 | #include <xen/events.h> | 37 | #include <xen/events.h> |
37 | #include <xen/interface/xen.h> | 38 | #include <xen/interface/xen.h> |
38 | #include <xen/interface/event_channel.h> | 39 | #include <xen/interface/event_channel.h> |
39 | 40 | ||
40 | #include "xen-ops.h" | ||
41 | |||
42 | /* | 41 | /* |
43 | * This lock protects updates to the following mapping and reference-count | 42 | * This lock protects updates to the following mapping and reference-count |
44 | * arrays. The lock does not need to be acquired to read the mapping tables. | 43 | * arrays. The lock does not need to be acquired to read the mapping tables. |
@@ -455,6 +454,53 @@ void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector) | |||
455 | notify_remote_via_irq(irq); | 454 | notify_remote_via_irq(irq); |
456 | } | 455 | } |
457 | 456 | ||
457 | irqreturn_t xen_debug_interrupt(int irq, void *dev_id) | ||
458 | { | ||
459 | struct shared_info *sh = HYPERVISOR_shared_info; | ||
460 | int cpu = smp_processor_id(); | ||
461 | int i; | ||
462 | unsigned long flags; | ||
463 | static DEFINE_SPINLOCK(debug_lock); | ||
464 | |||
465 | spin_lock_irqsave(&debug_lock, flags); | ||
466 | |||
467 | printk("vcpu %d\n ", cpu); | ||
468 | |||
469 | for_each_online_cpu(i) { | ||
470 | struct vcpu_info *v = per_cpu(xen_vcpu, i); | ||
471 | printk("%d: masked=%d pending=%d event_sel %08lx\n ", i, | ||
472 | (get_irq_regs() && i == cpu) ? xen_irqs_disabled(get_irq_regs()) : v->evtchn_upcall_mask, | ||
473 | v->evtchn_upcall_pending, | ||
474 | v->evtchn_pending_sel); | ||
475 | } | ||
476 | printk("pending:\n "); | ||
477 | for(i = ARRAY_SIZE(sh->evtchn_pending)-1; i >= 0; i--) | ||
478 | printk("%08lx%s", sh->evtchn_pending[i], | ||
479 | i % 8 == 0 ? "\n " : " "); | ||
480 | printk("\nmasks:\n "); | ||
481 | for(i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--) | ||
482 | printk("%08lx%s", sh->evtchn_mask[i], | ||
483 | i % 8 == 0 ? "\n " : " "); | ||
484 | |||
485 | printk("\nunmasked:\n "); | ||
486 | for(i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--) | ||
487 | printk("%08lx%s", sh->evtchn_pending[i] & ~sh->evtchn_mask[i], | ||
488 | i % 8 == 0 ? "\n " : " "); | ||
489 | |||
490 | printk("\npending list:\n"); | ||
491 | for(i = 0; i < NR_EVENT_CHANNELS; i++) { | ||
492 | if (sync_test_bit(i, sh->evtchn_pending)) { | ||
493 | printk(" %d: event %d -> irq %d\n", | ||
494 | cpu_evtchn[i], i, | ||
495 | evtchn_to_irq[i]); | ||
496 | } | ||
497 | } | ||
498 | |||
499 | spin_unlock_irqrestore(&debug_lock, flags); | ||
500 | |||
501 | return IRQ_HANDLED; | ||
502 | } | ||
503 | |||
458 | 504 | ||
459 | /* | 505 | /* |
460 | * Search the CPUs pending events bitmasks. For each one found, map | 506 | * Search the CPUs pending events bitmasks. For each one found, map |
@@ -470,29 +516,44 @@ void xen_evtchn_do_upcall(struct pt_regs *regs) | |||
470 | int cpu = get_cpu(); | 516 | int cpu = get_cpu(); |
471 | struct shared_info *s = HYPERVISOR_shared_info; | 517 | struct shared_info *s = HYPERVISOR_shared_info; |
472 | struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu); | 518 | struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu); |
473 | unsigned long pending_words; | 519 | static DEFINE_PER_CPU(unsigned, nesting_count); |
520 | unsigned count; | ||
474 | 521 | ||
475 | vcpu_info->evtchn_upcall_pending = 0; | 522 | do { |
523 | unsigned long pending_words; | ||
476 | 524 | ||
477 | /* NB. No need for a barrier here -- XCHG is a barrier on x86. */ | 525 | vcpu_info->evtchn_upcall_pending = 0; |
478 | pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0); | ||
479 | while (pending_words != 0) { | ||
480 | unsigned long pending_bits; | ||
481 | int word_idx = __ffs(pending_words); | ||
482 | pending_words &= ~(1UL << word_idx); | ||
483 | 526 | ||
484 | while ((pending_bits = active_evtchns(cpu, s, word_idx)) != 0) { | 527 | if (__get_cpu_var(nesting_count)++) |
485 | int bit_idx = __ffs(pending_bits); | 528 | goto out; |
486 | int port = (word_idx * BITS_PER_LONG) + bit_idx; | ||
487 | int irq = evtchn_to_irq[port]; | ||
488 | 529 | ||
489 | if (irq != -1) { | 530 | #ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */ |
490 | regs->orig_ax = ~irq; | 531 | /* Clear master flag /before/ clearing selector flag. */ |
491 | do_IRQ(regs); | 532 | rmb(); |
533 | #endif | ||
534 | pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0); | ||
535 | while (pending_words != 0) { | ||
536 | unsigned long pending_bits; | ||
537 | int word_idx = __ffs(pending_words); | ||
538 | pending_words &= ~(1UL << word_idx); | ||
539 | |||
540 | while ((pending_bits = active_evtchns(cpu, s, word_idx)) != 0) { | ||
541 | int bit_idx = __ffs(pending_bits); | ||
542 | int port = (word_idx * BITS_PER_LONG) + bit_idx; | ||
543 | int irq = evtchn_to_irq[port]; | ||
544 | |||
545 | if (irq != -1) | ||
546 | xen_do_IRQ(irq, regs); | ||
492 | } | 547 | } |
493 | } | 548 | } |
494 | } | ||
495 | 549 | ||
550 | BUG_ON(!irqs_disabled()); | ||
551 | |||
552 | count = __get_cpu_var(nesting_count); | ||
553 | __get_cpu_var(nesting_count) = 0; | ||
554 | } while(count != 1); | ||
555 | |||
556 | out: | ||
496 | put_cpu(); | 557 | put_cpu(); |
497 | } | 558 | } |
498 | 559 | ||
@@ -525,6 +586,22 @@ static void set_affinity_irq(unsigned irq, cpumask_t dest) | |||
525 | rebind_irq_to_cpu(irq, tcpu); | 586 | rebind_irq_to_cpu(irq, tcpu); |
526 | } | 587 | } |
527 | 588 | ||
589 | int resend_irq_on_evtchn(unsigned int irq) | ||
590 | { | ||
591 | int masked, evtchn = evtchn_from_irq(irq); | ||
592 | struct shared_info *s = HYPERVISOR_shared_info; | ||
593 | |||
594 | if (!VALID_EVTCHN(evtchn)) | ||
595 | return 1; | ||
596 | |||
597 | masked = sync_test_and_set_bit(evtchn, s->evtchn_mask); | ||
598 | sync_set_bit(evtchn, s->evtchn_pending); | ||
599 | if (!masked) | ||
600 | unmask_evtchn(evtchn); | ||
601 | |||
602 | return 1; | ||
603 | } | ||
604 | |||
528 | static void enable_dynirq(unsigned int irq) | 605 | static void enable_dynirq(unsigned int irq) |
529 | { | 606 | { |
530 | int evtchn = evtchn_from_irq(irq); | 607 | int evtchn = evtchn_from_irq(irq); |
@@ -554,10 +631,16 @@ static void ack_dynirq(unsigned int irq) | |||
554 | static int retrigger_dynirq(unsigned int irq) | 631 | static int retrigger_dynirq(unsigned int irq) |
555 | { | 632 | { |
556 | int evtchn = evtchn_from_irq(irq); | 633 | int evtchn = evtchn_from_irq(irq); |
634 | struct shared_info *sh = HYPERVISOR_shared_info; | ||
557 | int ret = 0; | 635 | int ret = 0; |
558 | 636 | ||
559 | if (VALID_EVTCHN(evtchn)) { | 637 | if (VALID_EVTCHN(evtchn)) { |
560 | set_evtchn(evtchn); | 638 | int masked; |
639 | |||
640 | masked = sync_test_and_set_bit(evtchn, sh->evtchn_mask); | ||
641 | sync_set_bit(evtchn, sh->evtchn_pending); | ||
642 | if (!masked) | ||
643 | unmask_evtchn(evtchn); | ||
561 | ret = 1; | 644 | ret = 1; |
562 | } | 645 | } |
563 | 646 | ||
diff --git a/arch/x86/xen/features.c b/drivers/xen/features.c index 0707714e40d6..0707714e40d6 100644 --- a/arch/x86/xen/features.c +++ b/drivers/xen/features.c | |||
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index d85dc6d41c2a..52b6b41b909d 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c | |||
@@ -439,24 +439,6 @@ static inline unsigned int max_nr_grant_frames(void) | |||
439 | return xen_max; | 439 | return xen_max; |
440 | } | 440 | } |
441 | 441 | ||
442 | static int map_pte_fn(pte_t *pte, struct page *pmd_page, | ||
443 | unsigned long addr, void *data) | ||
444 | { | ||
445 | unsigned long **frames = (unsigned long **)data; | ||
446 | |||
447 | set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL)); | ||
448 | (*frames)++; | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int unmap_pte_fn(pte_t *pte, struct page *pmd_page, | ||
453 | unsigned long addr, void *data) | ||
454 | { | ||
455 | |||
456 | set_pte_at(&init_mm, addr, pte, __pte(0)); | ||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | static int gnttab_map(unsigned int start_idx, unsigned int end_idx) | 442 | static int gnttab_map(unsigned int start_idx, unsigned int end_idx) |
461 | { | 443 | { |
462 | struct gnttab_setup_table setup; | 444 | struct gnttab_setup_table setup; |
@@ -470,7 +452,7 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx) | |||
470 | 452 | ||
471 | setup.dom = DOMID_SELF; | 453 | setup.dom = DOMID_SELF; |
472 | setup.nr_frames = nr_gframes; | 454 | setup.nr_frames = nr_gframes; |
473 | setup.frame_list = frames; | 455 | set_xen_guest_handle(setup.frame_list, frames); |
474 | 456 | ||
475 | rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1); | 457 | rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1); |
476 | if (rc == -ENOSYS) { | 458 | if (rc == -ENOSYS) { |
@@ -480,17 +462,9 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx) | |||
480 | 462 | ||
481 | BUG_ON(rc || setup.status); | 463 | BUG_ON(rc || setup.status); |
482 | 464 | ||
483 | if (shared == NULL) { | 465 | rc = arch_gnttab_map_shared(frames, nr_gframes, max_nr_grant_frames(), |
484 | struct vm_struct *area; | 466 | &shared); |
485 | area = alloc_vm_area(PAGE_SIZE * max_nr_grant_frames()); | ||
486 | BUG_ON(area == NULL); | ||
487 | shared = area->addr; | ||
488 | } | ||
489 | rc = apply_to_page_range(&init_mm, (unsigned long)shared, | ||
490 | PAGE_SIZE * nr_gframes, | ||
491 | map_pte_fn, &frames); | ||
492 | BUG_ON(rc); | 467 | BUG_ON(rc); |
493 | frames -= nr_gframes; /* adjust after map_pte_fn() */ | ||
494 | 468 | ||
495 | kfree(frames); | 469 | kfree(frames); |
496 | 470 | ||
@@ -506,10 +480,7 @@ static int gnttab_resume(void) | |||
506 | 480 | ||
507 | static int gnttab_suspend(void) | 481 | static int gnttab_suspend(void) |
508 | { | 482 | { |
509 | apply_to_page_range(&init_mm, (unsigned long)shared, | 483 | arch_gnttab_unmap_shared(shared, nr_grant_frames); |
510 | PAGE_SIZE * nr_grant_frames, | ||
511 | unmap_pte_fn, NULL); | ||
512 | |||
513 | return 0; | 484 | return 0; |
514 | } | 485 | } |
515 | 486 | ||
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c index 9fd2f70ab46d..0f86b0ff7879 100644 --- a/drivers/xen/xenbus/xenbus_client.c +++ b/drivers/xen/xenbus/xenbus_client.c | |||
@@ -399,7 +399,7 @@ int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr) | |||
399 | 399 | ||
400 | *vaddr = NULL; | 400 | *vaddr = NULL; |
401 | 401 | ||
402 | area = alloc_vm_area(PAGE_SIZE); | 402 | area = xen_alloc_vm_area(PAGE_SIZE); |
403 | if (!area) | 403 | if (!area) |
404 | return -ENOMEM; | 404 | return -ENOMEM; |
405 | 405 | ||
@@ -409,7 +409,7 @@ int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr) | |||
409 | BUG(); | 409 | BUG(); |
410 | 410 | ||
411 | if (op.status != GNTST_okay) { | 411 | if (op.status != GNTST_okay) { |
412 | free_vm_area(area); | 412 | xen_free_vm_area(area); |
413 | xenbus_dev_fatal(dev, op.status, | 413 | xenbus_dev_fatal(dev, op.status, |
414 | "mapping in shared page %d from domain %d", | 414 | "mapping in shared page %d from domain %d", |
415 | gnt_ref, dev->otherend_id); | 415 | gnt_ref, dev->otherend_id); |
@@ -508,7 +508,7 @@ int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr) | |||
508 | BUG(); | 508 | BUG(); |
509 | 509 | ||
510 | if (op.status == GNTST_okay) | 510 | if (op.status == GNTST_okay) |
511 | free_vm_area(area); | 511 | xen_free_vm_area(area); |
512 | else | 512 | else |
513 | xenbus_dev_error(dev, op.status, | 513 | xenbus_dev_error(dev, op.status, |
514 | "unmapping page at handle %d error %d", | 514 | "unmapping page at handle %d error %d", |
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index 4750de316ad3..57ceb5346b74 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c | |||
@@ -88,6 +88,16 @@ int xenbus_match(struct device *_dev, struct device_driver *_drv) | |||
88 | return match_device(drv->ids, to_xenbus_device(_dev)) != NULL; | 88 | return match_device(drv->ids, to_xenbus_device(_dev)) != NULL; |
89 | } | 89 | } |
90 | 90 | ||
91 | static int xenbus_uevent(struct device *_dev, struct kobj_uevent_env *env) | ||
92 | { | ||
93 | struct xenbus_device *dev = to_xenbus_device(_dev); | ||
94 | |||
95 | if (add_uevent_var(env, "MODALIAS=xen:%s", dev->devicetype)) | ||
96 | return -ENOMEM; | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
91 | /* device/<type>/<id> => <type>-<id> */ | 101 | /* device/<type>/<id> => <type>-<id> */ |
92 | static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename) | 102 | static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename) |
93 | { | 103 | { |
@@ -166,6 +176,7 @@ static struct xen_bus_type xenbus_frontend = { | |||
166 | .bus = { | 176 | .bus = { |
167 | .name = "xen", | 177 | .name = "xen", |
168 | .match = xenbus_match, | 178 | .match = xenbus_match, |
179 | .uevent = xenbus_uevent, | ||
169 | .probe = xenbus_dev_probe, | 180 | .probe = xenbus_dev_probe, |
170 | .remove = xenbus_dev_remove, | 181 | .remove = xenbus_dev_remove, |
171 | .shutdown = xenbus_dev_shutdown, | 182 | .shutdown = xenbus_dev_shutdown, |
@@ -438,6 +449,12 @@ static ssize_t xendev_show_devtype(struct device *dev, | |||
438 | } | 449 | } |
439 | DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL); | 450 | DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL); |
440 | 451 | ||
452 | static ssize_t xendev_show_modalias(struct device *dev, | ||
453 | struct device_attribute *attr, char *buf) | ||
454 | { | ||
455 | return sprintf(buf, "xen:%s\n", to_xenbus_device(dev)->devicetype); | ||
456 | } | ||
457 | DEVICE_ATTR(modalias, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_modalias, NULL); | ||
441 | 458 | ||
442 | int xenbus_probe_node(struct xen_bus_type *bus, | 459 | int xenbus_probe_node(struct xen_bus_type *bus, |
443 | const char *type, | 460 | const char *type, |
@@ -492,10 +509,16 @@ int xenbus_probe_node(struct xen_bus_type *bus, | |||
492 | 509 | ||
493 | err = device_create_file(&xendev->dev, &dev_attr_devtype); | 510 | err = device_create_file(&xendev->dev, &dev_attr_devtype); |
494 | if (err) | 511 | if (err) |
495 | goto fail_remove_file; | 512 | goto fail_remove_nodename; |
513 | |||
514 | err = device_create_file(&xendev->dev, &dev_attr_modalias); | ||
515 | if (err) | ||
516 | goto fail_remove_devtype; | ||
496 | 517 | ||
497 | return 0; | 518 | return 0; |
498 | fail_remove_file: | 519 | fail_remove_devtype: |
520 | device_remove_file(&xendev->dev, &dev_attr_devtype); | ||
521 | fail_remove_nodename: | ||
499 | device_remove_file(&xendev->dev, &dev_attr_nodename); | 522 | device_remove_file(&xendev->dev, &dev_attr_nodename); |
500 | fail_unregister: | 523 | fail_unregister: |
501 | device_unregister(&xendev->dev); | 524 | device_unregister(&xendev->dev); |
@@ -846,6 +869,7 @@ static int is_disconnected_device(struct device *dev, void *data) | |||
846 | { | 869 | { |
847 | struct xenbus_device *xendev = to_xenbus_device(dev); | 870 | struct xenbus_device *xendev = to_xenbus_device(dev); |
848 | struct device_driver *drv = data; | 871 | struct device_driver *drv = data; |
872 | struct xenbus_driver *xendrv; | ||
849 | 873 | ||
850 | /* | 874 | /* |
851 | * A device with no driver will never connect. We care only about | 875 | * A device with no driver will never connect. We care only about |
@@ -858,7 +882,9 @@ static int is_disconnected_device(struct device *dev, void *data) | |||
858 | if (drv && (dev->driver != drv)) | 882 | if (drv && (dev->driver != drv)) |
859 | return 0; | 883 | return 0; |
860 | 884 | ||
861 | return (xendev->state != XenbusStateConnected); | 885 | xendrv = to_xenbus_driver(dev->driver); |
886 | return (xendev->state != XenbusStateConnected || | ||
887 | (xendrv->is_ready && !xendrv->is_ready(xendev))); | ||
862 | } | 888 | } |
863 | 889 | ||
864 | static int exists_disconnected_device(struct device_driver *drv) | 890 | static int exists_disconnected_device(struct device_driver *drv) |
diff --git a/drivers/xen/xencomm.c b/drivers/xen/xencomm.c new file mode 100644 index 000000000000..797cb4e31f07 --- /dev/null +++ b/drivers/xen/xencomm.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
15 | * | ||
16 | * Copyright (C) IBM Corp. 2006 | ||
17 | * | ||
18 | * Authors: Hollis Blanchard <hollisb@us.ibm.com> | ||
19 | */ | ||
20 | |||
21 | #include <linux/gfp.h> | ||
22 | #include <linux/mm.h> | ||
23 | #include <asm/page.h> | ||
24 | #include <xen/xencomm.h> | ||
25 | #include <xen/interface/xen.h> | ||
26 | #ifdef __ia64__ | ||
27 | #include <asm/xen/xencomm.h> /* for is_kern_addr() */ | ||
28 | #endif | ||
29 | |||
30 | #ifdef HAVE_XEN_PLATFORM_COMPAT_H | ||
31 | #include <xen/platform-compat.h> | ||
32 | #endif | ||
33 | |||
34 | static int xencomm_init(struct xencomm_desc *desc, | ||
35 | void *buffer, unsigned long bytes) | ||
36 | { | ||
37 | unsigned long recorded = 0; | ||
38 | int i = 0; | ||
39 | |||
40 | while ((recorded < bytes) && (i < desc->nr_addrs)) { | ||
41 | unsigned long vaddr = (unsigned long)buffer + recorded; | ||
42 | unsigned long paddr; | ||
43 | int offset; | ||
44 | int chunksz; | ||
45 | |||
46 | offset = vaddr % PAGE_SIZE; /* handle partial pages */ | ||
47 | chunksz = min(PAGE_SIZE - offset, bytes - recorded); | ||
48 | |||
49 | paddr = xencomm_vtop(vaddr); | ||
50 | if (paddr == ~0UL) { | ||
51 | printk(KERN_DEBUG "%s: couldn't translate vaddr %lx\n", | ||
52 | __func__, vaddr); | ||
53 | return -EINVAL; | ||
54 | } | ||
55 | |||
56 | desc->address[i++] = paddr; | ||
57 | recorded += chunksz; | ||
58 | } | ||
59 | |||
60 | if (recorded < bytes) { | ||
61 | printk(KERN_DEBUG | ||
62 | "%s: could only translate %ld of %ld bytes\n", | ||
63 | __func__, recorded, bytes); | ||
64 | return -ENOSPC; | ||
65 | } | ||
66 | |||
67 | /* mark remaining addresses invalid (just for safety) */ | ||
68 | while (i < desc->nr_addrs) | ||
69 | desc->address[i++] = XENCOMM_INVALID; | ||
70 | |||
71 | desc->magic = XENCOMM_MAGIC; | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static struct xencomm_desc *xencomm_alloc(gfp_t gfp_mask, | ||
77 | void *buffer, unsigned long bytes) | ||
78 | { | ||
79 | struct xencomm_desc *desc; | ||
80 | unsigned long buffer_ulong = (unsigned long)buffer; | ||
81 | unsigned long start = buffer_ulong & PAGE_MASK; | ||
82 | unsigned long end = (buffer_ulong + bytes) | ~PAGE_MASK; | ||
83 | unsigned long nr_addrs = (end - start + 1) >> PAGE_SHIFT; | ||
84 | unsigned long size = sizeof(*desc) + | ||
85 | sizeof(desc->address[0]) * nr_addrs; | ||
86 | |||
87 | /* | ||
88 | * slab allocator returns at least sizeof(void*) aligned pointer. | ||
89 | * When sizeof(*desc) > sizeof(void*), struct xencomm_desc might | ||
90 | * cross page boundary. | ||
91 | */ | ||
92 | if (sizeof(*desc) > sizeof(void *)) { | ||
93 | unsigned long order = get_order(size); | ||
94 | desc = (struct xencomm_desc *)__get_free_pages(gfp_mask, | ||
95 | order); | ||
96 | if (desc == NULL) | ||
97 | return NULL; | ||
98 | |||
99 | desc->nr_addrs = | ||
100 | ((PAGE_SIZE << order) - sizeof(struct xencomm_desc)) / | ||
101 | sizeof(*desc->address); | ||
102 | } else { | ||
103 | desc = kmalloc(size, gfp_mask); | ||
104 | if (desc == NULL) | ||
105 | return NULL; | ||
106 | |||
107 | desc->nr_addrs = nr_addrs; | ||
108 | } | ||
109 | return desc; | ||
110 | } | ||
111 | |||
112 | void xencomm_free(struct xencomm_handle *desc) | ||
113 | { | ||
114 | if (desc && !((ulong)desc & XENCOMM_INLINE_FLAG)) { | ||
115 | struct xencomm_desc *desc__ = (struct xencomm_desc *)desc; | ||
116 | if (sizeof(*desc__) > sizeof(void *)) { | ||
117 | unsigned long size = sizeof(*desc__) + | ||
118 | sizeof(desc__->address[0]) * desc__->nr_addrs; | ||
119 | unsigned long order = get_order(size); | ||
120 | free_pages((unsigned long)__va(desc), order); | ||
121 | } else | ||
122 | kfree(__va(desc)); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | static int xencomm_create(void *buffer, unsigned long bytes, | ||
127 | struct xencomm_desc **ret, gfp_t gfp_mask) | ||
128 | { | ||
129 | struct xencomm_desc *desc; | ||
130 | int rc; | ||
131 | |||
132 | pr_debug("%s: %p[%ld]\n", __func__, buffer, bytes); | ||
133 | |||
134 | if (bytes == 0) { | ||
135 | /* don't create a descriptor; Xen recognizes NULL. */ | ||
136 | BUG_ON(buffer != NULL); | ||
137 | *ret = NULL; | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | BUG_ON(buffer == NULL); /* 'bytes' is non-zero */ | ||
142 | |||
143 | desc = xencomm_alloc(gfp_mask, buffer, bytes); | ||
144 | if (!desc) { | ||
145 | printk(KERN_DEBUG "%s failure\n", "xencomm_alloc"); | ||
146 | return -ENOMEM; | ||
147 | } | ||
148 | |||
149 | rc = xencomm_init(desc, buffer, bytes); | ||
150 | if (rc) { | ||
151 | printk(KERN_DEBUG "%s failure: %d\n", "xencomm_init", rc); | ||
152 | xencomm_free((struct xencomm_handle *)__pa(desc)); | ||
153 | return rc; | ||
154 | } | ||
155 | |||
156 | *ret = desc; | ||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | /* check if memory address is within VMALLOC region */ | ||
161 | static int is_phys_contiguous(unsigned long addr) | ||
162 | { | ||
163 | if (!is_kernel_addr(addr)) | ||
164 | return 0; | ||
165 | |||
166 | return (addr < VMALLOC_START) || (addr >= VMALLOC_END); | ||
167 | } | ||
168 | |||
169 | static struct xencomm_handle *xencomm_create_inline(void *ptr) | ||
170 | { | ||
171 | unsigned long paddr; | ||
172 | |||
173 | BUG_ON(!is_phys_contiguous((unsigned long)ptr)); | ||
174 | |||
175 | paddr = (unsigned long)xencomm_pa(ptr); | ||
176 | BUG_ON(paddr & XENCOMM_INLINE_FLAG); | ||
177 | return (struct xencomm_handle *)(paddr | XENCOMM_INLINE_FLAG); | ||
178 | } | ||
179 | |||
180 | /* "mini" routine, for stack-based communications: */ | ||
181 | static int xencomm_create_mini(void *buffer, | ||
182 | unsigned long bytes, struct xencomm_mini *xc_desc, | ||
183 | struct xencomm_desc **ret) | ||
184 | { | ||
185 | int rc = 0; | ||
186 | struct xencomm_desc *desc; | ||
187 | BUG_ON(((unsigned long)xc_desc) % sizeof(*xc_desc) != 0); | ||
188 | |||
189 | desc = (void *)xc_desc; | ||
190 | |||
191 | desc->nr_addrs = XENCOMM_MINI_ADDRS; | ||
192 | |||
193 | rc = xencomm_init(desc, buffer, bytes); | ||
194 | if (!rc) | ||
195 | *ret = desc; | ||
196 | |||
197 | return rc; | ||
198 | } | ||
199 | |||
200 | struct xencomm_handle *xencomm_map(void *ptr, unsigned long bytes) | ||
201 | { | ||
202 | int rc; | ||
203 | struct xencomm_desc *desc; | ||
204 | |||
205 | if (is_phys_contiguous((unsigned long)ptr)) | ||
206 | return xencomm_create_inline(ptr); | ||
207 | |||
208 | rc = xencomm_create(ptr, bytes, &desc, GFP_KERNEL); | ||
209 | |||
210 | if (rc || desc == NULL) | ||
211 | return NULL; | ||
212 | |||
213 | return xencomm_pa(desc); | ||
214 | } | ||
215 | |||
216 | struct xencomm_handle *__xencomm_map_no_alloc(void *ptr, unsigned long bytes, | ||
217 | struct xencomm_mini *xc_desc) | ||
218 | { | ||
219 | int rc; | ||
220 | struct xencomm_desc *desc = NULL; | ||
221 | |||
222 | if (is_phys_contiguous((unsigned long)ptr)) | ||
223 | return xencomm_create_inline(ptr); | ||
224 | |||
225 | rc = xencomm_create_mini(ptr, bytes, xc_desc, | ||
226 | &desc); | ||
227 | |||
228 | if (rc) | ||
229 | return NULL; | ||
230 | |||
231 | return xencomm_pa(desc); | ||
232 | } | ||
diff --git a/fs/jffs2/README.Locking b/fs/jffs2/README.Locking index d14d5a4dc5ac..3ea36554107f 100644 --- a/fs/jffs2/README.Locking +++ b/fs/jffs2/README.Locking | |||
@@ -14,7 +14,7 @@ be fairly close. | |||
14 | alloc_sem | 14 | alloc_sem |
15 | --------- | 15 | --------- |
16 | 16 | ||
17 | The alloc_sem is a per-filesystem semaphore, used primarily to ensure | 17 | The alloc_sem is a per-filesystem mutex, used primarily to ensure |
18 | contiguous allocation of space on the medium. It is automatically | 18 | contiguous allocation of space on the medium. It is automatically |
19 | obtained during space allocations (jffs2_reserve_space()) and freed | 19 | obtained during space allocations (jffs2_reserve_space()) and freed |
20 | upon write completion (jffs2_complete_reservation()). Note that | 20 | upon write completion (jffs2_complete_reservation()). Note that |
@@ -41,10 +41,10 @@ if the wbuf is currently holding any data is permitted, though. | |||
41 | Ordering constraints: See f->sem. | 41 | Ordering constraints: See f->sem. |
42 | 42 | ||
43 | 43 | ||
44 | File Semaphore f->sem | 44 | File Mutex f->sem |
45 | --------------------- | 45 | --------------------- |
46 | 46 | ||
47 | This is the JFFS2-internal equivalent of the inode semaphore i->i_sem. | 47 | This is the JFFS2-internal equivalent of the inode mutex i->i_sem. |
48 | It protects the contents of the jffs2_inode_info private inode data, | 48 | It protects the contents of the jffs2_inode_info private inode data, |
49 | including the linked list of node fragments (but see the notes below on | 49 | including the linked list of node fragments (but see the notes below on |
50 | erase_completion_lock), etc. | 50 | erase_completion_lock), etc. |
@@ -60,14 +60,14 @@ lead to deadlock, unless we played games with unlocking the i_sem | |||
60 | before calling the space allocation functions. | 60 | before calling the space allocation functions. |
61 | 61 | ||
62 | Instead of playing such games, we just have an extra internal | 62 | Instead of playing such games, we just have an extra internal |
63 | semaphore, which is obtained by the garbage collection code and also | 63 | mutex, which is obtained by the garbage collection code and also |
64 | by the normal file system code _after_ allocation of space. | 64 | by the normal file system code _after_ allocation of space. |
65 | 65 | ||
66 | Ordering constraints: | 66 | Ordering constraints: |
67 | 67 | ||
68 | 1. Never attempt to allocate space or lock alloc_sem with | 68 | 1. Never attempt to allocate space or lock alloc_sem with |
69 | any f->sem held. | 69 | any f->sem held. |
70 | 2. Never attempt to lock two file semaphores in one thread. | 70 | 2. Never attempt to lock two file mutexes in one thread. |
71 | No ordering rules have been made for doing so. | 71 | No ordering rules have been made for doing so. |
72 | 72 | ||
73 | 73 | ||
@@ -86,8 +86,8 @@ a simple spin_lock() rather than spin_lock_bh(). | |||
86 | 86 | ||
87 | Note that the per-inode list of physical nodes (f->nodes) is a special | 87 | Note that the per-inode list of physical nodes (f->nodes) is a special |
88 | case. Any changes to _valid_ nodes (i.e. ->flash_offset & 1 == 0) in | 88 | case. Any changes to _valid_ nodes (i.e. ->flash_offset & 1 == 0) in |
89 | the list are protected by the file semaphore f->sem. But the erase | 89 | the list are protected by the file mutex f->sem. But the erase code |
90 | code may remove _obsolete_ nodes from the list while holding only the | 90 | may remove _obsolete_ nodes from the list while holding only the |
91 | erase_completion_lock. So you can walk the list only while holding the | 91 | erase_completion_lock. So you can walk the list only while holding the |
92 | erase_completion_lock, and can drop the lock temporarily mid-walk as | 92 | erase_completion_lock, and can drop the lock temporarily mid-walk as |
93 | long as the pointer you're holding is to a _valid_ node, not an | 93 | long as the pointer you're holding is to a _valid_ node, not an |
@@ -124,10 +124,10 @@ Ordering constraints: | |||
124 | erase_free_sem | 124 | erase_free_sem |
125 | -------------- | 125 | -------------- |
126 | 126 | ||
127 | This semaphore is only used by the erase code which frees obsolete | 127 | This mutex is only used by the erase code which frees obsolete node |
128 | node references and the jffs2_garbage_collect_deletion_dirent() | 128 | references and the jffs2_garbage_collect_deletion_dirent() function. |
129 | function. The latter function on NAND flash must read _obsolete_ nodes | 129 | The latter function on NAND flash must read _obsolete_ nodes to |
130 | to determine whether the 'deletion dirent' under consideration can be | 130 | determine whether the 'deletion dirent' under consideration can be |
131 | discarded or whether it is still required to show that an inode has | 131 | discarded or whether it is still required to show that an inode has |
132 | been unlinked. Because reading from the flash may sleep, the | 132 | been unlinked. Because reading from the flash may sleep, the |
133 | erase_completion_lock cannot be held, so an alternative, more | 133 | erase_completion_lock cannot be held, so an alternative, more |
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index 722a6b682951..d58f845ccb85 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c | |||
@@ -345,6 +345,7 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c) | |||
345 | INIT_LIST_HEAD(&c->dirty_list); | 345 | INIT_LIST_HEAD(&c->dirty_list); |
346 | INIT_LIST_HEAD(&c->erasable_list); | 346 | INIT_LIST_HEAD(&c->erasable_list); |
347 | INIT_LIST_HEAD(&c->erasing_list); | 347 | INIT_LIST_HEAD(&c->erasing_list); |
348 | INIT_LIST_HEAD(&c->erase_checking_list); | ||
348 | INIT_LIST_HEAD(&c->erase_pending_list); | 349 | INIT_LIST_HEAD(&c->erase_pending_list); |
349 | INIT_LIST_HEAD(&c->erasable_pending_wbuf_list); | 350 | INIT_LIST_HEAD(&c->erasable_pending_wbuf_list); |
350 | INIT_LIST_HEAD(&c->erase_complete_list); | 351 | INIT_LIST_HEAD(&c->erase_complete_list); |
diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c index 3a32c64ed497..5544d31c066b 100644 --- a/fs/jffs2/debug.c +++ b/fs/jffs2/debug.c | |||
@@ -62,9 +62,9 @@ __jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c, | |||
62 | void | 62 | void |
63 | __jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f) | 63 | __jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f) |
64 | { | 64 | { |
65 | down(&f->sem); | 65 | mutex_lock(&f->sem); |
66 | __jffs2_dbg_fragtree_paranoia_check_nolock(f); | 66 | __jffs2_dbg_fragtree_paranoia_check_nolock(f); |
67 | up(&f->sem); | 67 | mutex_unlock(&f->sem); |
68 | } | 68 | } |
69 | 69 | ||
70 | void | 70 | void |
@@ -153,6 +153,139 @@ __jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c, | |||
153 | kfree(buf); | 153 | kfree(buf); |
154 | } | 154 | } |
155 | 155 | ||
156 | void __jffs2_dbg_superblock_counts(struct jffs2_sb_info *c) | ||
157 | { | ||
158 | struct jffs2_eraseblock *jeb; | ||
159 | uint32_t free = 0, dirty = 0, used = 0, wasted = 0, | ||
160 | erasing = 0, bad = 0, unchecked = 0; | ||
161 | int nr_counted = 0; | ||
162 | int dump = 0; | ||
163 | |||
164 | if (c->gcblock) { | ||
165 | nr_counted++; | ||
166 | free += c->gcblock->free_size; | ||
167 | dirty += c->gcblock->dirty_size; | ||
168 | used += c->gcblock->used_size; | ||
169 | wasted += c->gcblock->wasted_size; | ||
170 | unchecked += c->gcblock->unchecked_size; | ||
171 | } | ||
172 | if (c->nextblock) { | ||
173 | nr_counted++; | ||
174 | free += c->nextblock->free_size; | ||
175 | dirty += c->nextblock->dirty_size; | ||
176 | used += c->nextblock->used_size; | ||
177 | wasted += c->nextblock->wasted_size; | ||
178 | unchecked += c->nextblock->unchecked_size; | ||
179 | } | ||
180 | list_for_each_entry(jeb, &c->clean_list, list) { | ||
181 | nr_counted++; | ||
182 | free += jeb->free_size; | ||
183 | dirty += jeb->dirty_size; | ||
184 | used += jeb->used_size; | ||
185 | wasted += jeb->wasted_size; | ||
186 | unchecked += jeb->unchecked_size; | ||
187 | } | ||
188 | list_for_each_entry(jeb, &c->very_dirty_list, list) { | ||
189 | nr_counted++; | ||
190 | free += jeb->free_size; | ||
191 | dirty += jeb->dirty_size; | ||
192 | used += jeb->used_size; | ||
193 | wasted += jeb->wasted_size; | ||
194 | unchecked += jeb->unchecked_size; | ||
195 | } | ||
196 | list_for_each_entry(jeb, &c->dirty_list, list) { | ||
197 | nr_counted++; | ||
198 | free += jeb->free_size; | ||
199 | dirty += jeb->dirty_size; | ||
200 | used += jeb->used_size; | ||
201 | wasted += jeb->wasted_size; | ||
202 | unchecked += jeb->unchecked_size; | ||
203 | } | ||
204 | list_for_each_entry(jeb, &c->erasable_list, list) { | ||
205 | nr_counted++; | ||
206 | free += jeb->free_size; | ||
207 | dirty += jeb->dirty_size; | ||
208 | used += jeb->used_size; | ||
209 | wasted += jeb->wasted_size; | ||
210 | unchecked += jeb->unchecked_size; | ||
211 | } | ||
212 | list_for_each_entry(jeb, &c->erasable_pending_wbuf_list, list) { | ||
213 | nr_counted++; | ||
214 | free += jeb->free_size; | ||
215 | dirty += jeb->dirty_size; | ||
216 | used += jeb->used_size; | ||
217 | wasted += jeb->wasted_size; | ||
218 | unchecked += jeb->unchecked_size; | ||
219 | } | ||
220 | list_for_each_entry(jeb, &c->erase_pending_list, list) { | ||
221 | nr_counted++; | ||
222 | free += jeb->free_size; | ||
223 | dirty += jeb->dirty_size; | ||
224 | used += jeb->used_size; | ||
225 | wasted += jeb->wasted_size; | ||
226 | unchecked += jeb->unchecked_size; | ||
227 | } | ||
228 | list_for_each_entry(jeb, &c->free_list, list) { | ||
229 | nr_counted++; | ||
230 | free += jeb->free_size; | ||
231 | dirty += jeb->dirty_size; | ||
232 | used += jeb->used_size; | ||
233 | wasted += jeb->wasted_size; | ||
234 | unchecked += jeb->unchecked_size; | ||
235 | } | ||
236 | list_for_each_entry(jeb, &c->bad_used_list, list) { | ||
237 | nr_counted++; | ||
238 | free += jeb->free_size; | ||
239 | dirty += jeb->dirty_size; | ||
240 | used += jeb->used_size; | ||
241 | wasted += jeb->wasted_size; | ||
242 | unchecked += jeb->unchecked_size; | ||
243 | } | ||
244 | |||
245 | list_for_each_entry(jeb, &c->erasing_list, list) { | ||
246 | nr_counted++; | ||
247 | erasing += c->sector_size; | ||
248 | } | ||
249 | list_for_each_entry(jeb, &c->erase_checking_list, list) { | ||
250 | nr_counted++; | ||
251 | erasing += c->sector_size; | ||
252 | } | ||
253 | list_for_each_entry(jeb, &c->erase_complete_list, list) { | ||
254 | nr_counted++; | ||
255 | erasing += c->sector_size; | ||
256 | } | ||
257 | list_for_each_entry(jeb, &c->bad_list, list) { | ||
258 | nr_counted++; | ||
259 | bad += c->sector_size; | ||
260 | } | ||
261 | |||
262 | #define check(sz) \ | ||
263 | if (sz != c->sz##_size) { \ | ||
264 | printk(KERN_WARNING #sz "_size mismatch counted 0x%x, c->" #sz "_size 0x%x\n", \ | ||
265 | sz, c->sz##_size); \ | ||
266 | dump = 1; \ | ||
267 | } | ||
268 | check(free); | ||
269 | check(dirty); | ||
270 | check(used); | ||
271 | check(wasted); | ||
272 | check(unchecked); | ||
273 | check(bad); | ||
274 | check(erasing); | ||
275 | #undef check | ||
276 | |||
277 | if (nr_counted != c->nr_blocks) { | ||
278 | printk(KERN_WARNING "%s counted only 0x%x blocks of 0x%x. Where are the others?\n", | ||
279 | __func__, nr_counted, c->nr_blocks); | ||
280 | dump = 1; | ||
281 | } | ||
282 | |||
283 | if (dump) { | ||
284 | __jffs2_dbg_dump_block_lists_nolock(c); | ||
285 | BUG(); | ||
286 | } | ||
287 | } | ||
288 | |||
156 | /* | 289 | /* |
157 | * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'. | 290 | * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'. |
158 | */ | 291 | */ |
@@ -229,6 +362,9 @@ __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c, | |||
229 | } | 362 | } |
230 | #endif | 363 | #endif |
231 | 364 | ||
365 | if (!(c->flags & (JFFS2_SB_FLAG_BUILDING|JFFS2_SB_FLAG_SCANNING))) | ||
366 | __jffs2_dbg_superblock_counts(c); | ||
367 | |||
232 | return; | 368 | return; |
233 | 369 | ||
234 | error: | 370 | error: |
@@ -268,7 +404,10 @@ __jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c, | |||
268 | 404 | ||
269 | printk(JFFS2_DBG); | 405 | printk(JFFS2_DBG); |
270 | for (ref = jeb->first_node; ; ref = ref_next(ref)) { | 406 | for (ref = jeb->first_node; ; ref = ref_next(ref)) { |
271 | printk("%#08x(%#x)", ref_offset(ref), ref->__totlen); | 407 | printk("%#08x", ref_offset(ref)); |
408 | #ifdef TEST_TOTLEN | ||
409 | printk("(%x)", ref->__totlen); | ||
410 | #endif | ||
272 | if (ref_next(ref)) | 411 | if (ref_next(ref)) |
273 | printk("->"); | 412 | printk("->"); |
274 | else | 413 | else |
@@ -447,6 +586,21 @@ __jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c) | |||
447 | } | 586 | } |
448 | } | 587 | } |
449 | } | 588 | } |
589 | if (list_empty(&c->erase_checking_list)) { | ||
590 | printk(JFFS2_DBG "erase_checking_list: empty\n"); | ||
591 | } else { | ||
592 | struct list_head *this; | ||
593 | |||
594 | list_for_each(this, &c->erase_checking_list) { | ||
595 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
596 | |||
597 | if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { | ||
598 | printk(JFFS2_DBG "erase_checking_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", | ||
599 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, | ||
600 | jeb->unchecked_size, jeb->free_size); | ||
601 | } | ||
602 | } | ||
603 | } | ||
450 | 604 | ||
451 | if (list_empty(&c->erase_pending_list)) { | 605 | if (list_empty(&c->erase_pending_list)) { |
452 | printk(JFFS2_DBG "erase_pending_list: empty\n"); | 606 | printk(JFFS2_DBG "erase_pending_list: empty\n"); |
@@ -532,9 +686,9 @@ __jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c) | |||
532 | void | 686 | void |
533 | __jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f) | 687 | __jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f) |
534 | { | 688 | { |
535 | down(&f->sem); | 689 | mutex_lock(&f->sem); |
536 | jffs2_dbg_dump_fragtree_nolock(f); | 690 | jffs2_dbg_dump_fragtree_nolock(f); |
537 | up(&f->sem); | 691 | mutex_unlock(&f->sem); |
538 | } | 692 | } |
539 | 693 | ||
540 | void | 694 | void |
diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h index 4130adabd76e..9645275023e6 100644 --- a/fs/jffs2/debug.h +++ b/fs/jffs2/debug.h | |||
@@ -38,6 +38,7 @@ | |||
38 | 38 | ||
39 | #if CONFIG_JFFS2_FS_DEBUG > 1 | 39 | #if CONFIG_JFFS2_FS_DEBUG > 1 |
40 | #define JFFS2_DBG_FRAGTREE2_MESSAGES | 40 | #define JFFS2_DBG_FRAGTREE2_MESSAGES |
41 | #define JFFS2_DBG_READINODE2_MESSAGES | ||
41 | #define JFFS2_DBG_MEMALLOC_MESSAGES | 42 | #define JFFS2_DBG_MEMALLOC_MESSAGES |
42 | #endif | 43 | #endif |
43 | 44 | ||
@@ -115,6 +116,11 @@ | |||
115 | #else | 116 | #else |
116 | #define dbg_readinode(fmt, ...) | 117 | #define dbg_readinode(fmt, ...) |
117 | #endif | 118 | #endif |
119 | #ifdef JFFS2_DBG_READINODE2_MESSAGES | ||
120 | #define dbg_readinode2(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) | ||
121 | #else | ||
122 | #define dbg_readinode2(fmt, ...) | ||
123 | #endif | ||
118 | 124 | ||
119 | /* Fragtree build debugging messages */ | 125 | /* Fragtree build debugging messages */ |
120 | #ifdef JFFS2_DBG_FRAGTREE_MESSAGES | 126 | #ifdef JFFS2_DBG_FRAGTREE_MESSAGES |
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index f948f7e6ec82..c63e7a96af0d 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c | |||
@@ -86,7 +86,7 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, | |||
86 | dir_f = JFFS2_INODE_INFO(dir_i); | 86 | dir_f = JFFS2_INODE_INFO(dir_i); |
87 | c = JFFS2_SB_INFO(dir_i->i_sb); | 87 | c = JFFS2_SB_INFO(dir_i->i_sb); |
88 | 88 | ||
89 | down(&dir_f->sem); | 89 | mutex_lock(&dir_f->sem); |
90 | 90 | ||
91 | /* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */ | 91 | /* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */ |
92 | for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= target->d_name.hash; fd_list = fd_list->next) { | 92 | for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= target->d_name.hash; fd_list = fd_list->next) { |
@@ -99,7 +99,7 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, | |||
99 | } | 99 | } |
100 | if (fd) | 100 | if (fd) |
101 | ino = fd->ino; | 101 | ino = fd->ino; |
102 | up(&dir_f->sem); | 102 | mutex_unlock(&dir_f->sem); |
103 | if (ino) { | 103 | if (ino) { |
104 | inode = jffs2_iget(dir_i->i_sb, ino); | 104 | inode = jffs2_iget(dir_i->i_sb, ino); |
105 | if (IS_ERR(inode)) { | 105 | if (IS_ERR(inode)) { |
@@ -146,7 +146,7 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
146 | } | 146 | } |
147 | 147 | ||
148 | curofs=1; | 148 | curofs=1; |
149 | down(&f->sem); | 149 | mutex_lock(&f->sem); |
150 | for (fd = f->dents; fd; fd = fd->next) { | 150 | for (fd = f->dents; fd; fd = fd->next) { |
151 | 151 | ||
152 | curofs++; | 152 | curofs++; |
@@ -166,7 +166,7 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
166 | break; | 166 | break; |
167 | offset++; | 167 | offset++; |
168 | } | 168 | } |
169 | up(&f->sem); | 169 | mutex_unlock(&f->sem); |
170 | out: | 170 | out: |
171 | filp->f_pos = offset; | 171 | filp->f_pos = offset; |
172 | return 0; | 172 | return 0; |
@@ -275,9 +275,9 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de | |||
275 | ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now); | 275 | ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now); |
276 | 276 | ||
277 | if (!ret) { | 277 | if (!ret) { |
278 | down(&f->sem); | 278 | mutex_lock(&f->sem); |
279 | old_dentry->d_inode->i_nlink = ++f->inocache->nlink; | 279 | old_dentry->d_inode->i_nlink = ++f->inocache->nlink; |
280 | up(&f->sem); | 280 | mutex_unlock(&f->sem); |
281 | d_instantiate(dentry, old_dentry->d_inode); | 281 | d_instantiate(dentry, old_dentry->d_inode); |
282 | dir_i->i_mtime = dir_i->i_ctime = ITIME(now); | 282 | dir_i->i_mtime = dir_i->i_ctime = ITIME(now); |
283 | atomic_inc(&old_dentry->d_inode->i_count); | 283 | atomic_inc(&old_dentry->d_inode->i_count); |
@@ -351,7 +351,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
351 | 351 | ||
352 | if (IS_ERR(fn)) { | 352 | if (IS_ERR(fn)) { |
353 | /* Eeek. Wave bye bye */ | 353 | /* Eeek. Wave bye bye */ |
354 | up(&f->sem); | 354 | mutex_unlock(&f->sem); |
355 | jffs2_complete_reservation(c); | 355 | jffs2_complete_reservation(c); |
356 | jffs2_clear_inode(inode); | 356 | jffs2_clear_inode(inode); |
357 | return PTR_ERR(fn); | 357 | return PTR_ERR(fn); |
@@ -361,7 +361,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
361 | f->target = kmalloc(targetlen + 1, GFP_KERNEL); | 361 | f->target = kmalloc(targetlen + 1, GFP_KERNEL); |
362 | if (!f->target) { | 362 | if (!f->target) { |
363 | printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); | 363 | printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); |
364 | up(&f->sem); | 364 | mutex_unlock(&f->sem); |
365 | jffs2_complete_reservation(c); | 365 | jffs2_complete_reservation(c); |
366 | jffs2_clear_inode(inode); | 366 | jffs2_clear_inode(inode); |
367 | return -ENOMEM; | 367 | return -ENOMEM; |
@@ -374,7 +374,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
374 | obsoleted by the first data write | 374 | obsoleted by the first data write |
375 | */ | 375 | */ |
376 | f->metadata = fn; | 376 | f->metadata = fn; |
377 | up(&f->sem); | 377 | mutex_unlock(&f->sem); |
378 | 378 | ||
379 | jffs2_complete_reservation(c); | 379 | jffs2_complete_reservation(c); |
380 | 380 | ||
@@ -406,7 +406,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
406 | } | 406 | } |
407 | 407 | ||
408 | dir_f = JFFS2_INODE_INFO(dir_i); | 408 | dir_f = JFFS2_INODE_INFO(dir_i); |
409 | down(&dir_f->sem); | 409 | mutex_lock(&dir_f->sem); |
410 | 410 | ||
411 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 411 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
412 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); | 412 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); |
@@ -429,7 +429,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
429 | as if it were the final unlink() */ | 429 | as if it were the final unlink() */ |
430 | jffs2_complete_reservation(c); | 430 | jffs2_complete_reservation(c); |
431 | jffs2_free_raw_dirent(rd); | 431 | jffs2_free_raw_dirent(rd); |
432 | up(&dir_f->sem); | 432 | mutex_unlock(&dir_f->sem); |
433 | jffs2_clear_inode(inode); | 433 | jffs2_clear_inode(inode); |
434 | return PTR_ERR(fd); | 434 | return PTR_ERR(fd); |
435 | } | 435 | } |
@@ -442,7 +442,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
442 | one if necessary. */ | 442 | one if necessary. */ |
443 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); | 443 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); |
444 | 444 | ||
445 | up(&dir_f->sem); | 445 | mutex_unlock(&dir_f->sem); |
446 | jffs2_complete_reservation(c); | 446 | jffs2_complete_reservation(c); |
447 | 447 | ||
448 | d_instantiate(dentry, inode); | 448 | d_instantiate(dentry, inode); |
@@ -507,7 +507,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
507 | 507 | ||
508 | if (IS_ERR(fn)) { | 508 | if (IS_ERR(fn)) { |
509 | /* Eeek. Wave bye bye */ | 509 | /* Eeek. Wave bye bye */ |
510 | up(&f->sem); | 510 | mutex_unlock(&f->sem); |
511 | jffs2_complete_reservation(c); | 511 | jffs2_complete_reservation(c); |
512 | jffs2_clear_inode(inode); | 512 | jffs2_clear_inode(inode); |
513 | return PTR_ERR(fn); | 513 | return PTR_ERR(fn); |
@@ -516,7 +516,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
516 | obsoleted by the first data write | 516 | obsoleted by the first data write |
517 | */ | 517 | */ |
518 | f->metadata = fn; | 518 | f->metadata = fn; |
519 | up(&f->sem); | 519 | mutex_unlock(&f->sem); |
520 | 520 | ||
521 | jffs2_complete_reservation(c); | 521 | jffs2_complete_reservation(c); |
522 | 522 | ||
@@ -548,7 +548,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
548 | } | 548 | } |
549 | 549 | ||
550 | dir_f = JFFS2_INODE_INFO(dir_i); | 550 | dir_f = JFFS2_INODE_INFO(dir_i); |
551 | down(&dir_f->sem); | 551 | mutex_lock(&dir_f->sem); |
552 | 552 | ||
553 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 553 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
554 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); | 554 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); |
@@ -571,7 +571,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
571 | as if it were the final unlink() */ | 571 | as if it were the final unlink() */ |
572 | jffs2_complete_reservation(c); | 572 | jffs2_complete_reservation(c); |
573 | jffs2_free_raw_dirent(rd); | 573 | jffs2_free_raw_dirent(rd); |
574 | up(&dir_f->sem); | 574 | mutex_unlock(&dir_f->sem); |
575 | jffs2_clear_inode(inode); | 575 | jffs2_clear_inode(inode); |
576 | return PTR_ERR(fd); | 576 | return PTR_ERR(fd); |
577 | } | 577 | } |
@@ -585,7 +585,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
585 | one if necessary. */ | 585 | one if necessary. */ |
586 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); | 586 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); |
587 | 587 | ||
588 | up(&dir_f->sem); | 588 | mutex_unlock(&dir_f->sem); |
589 | jffs2_complete_reservation(c); | 589 | jffs2_complete_reservation(c); |
590 | 590 | ||
591 | d_instantiate(dentry, inode); | 591 | d_instantiate(dentry, inode); |
@@ -673,7 +673,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
673 | 673 | ||
674 | if (IS_ERR(fn)) { | 674 | if (IS_ERR(fn)) { |
675 | /* Eeek. Wave bye bye */ | 675 | /* Eeek. Wave bye bye */ |
676 | up(&f->sem); | 676 | mutex_unlock(&f->sem); |
677 | jffs2_complete_reservation(c); | 677 | jffs2_complete_reservation(c); |
678 | jffs2_clear_inode(inode); | 678 | jffs2_clear_inode(inode); |
679 | return PTR_ERR(fn); | 679 | return PTR_ERR(fn); |
@@ -682,7 +682,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
682 | obsoleted by the first data write | 682 | obsoleted by the first data write |
683 | */ | 683 | */ |
684 | f->metadata = fn; | 684 | f->metadata = fn; |
685 | up(&f->sem); | 685 | mutex_unlock(&f->sem); |
686 | 686 | ||
687 | jffs2_complete_reservation(c); | 687 | jffs2_complete_reservation(c); |
688 | 688 | ||
@@ -714,7 +714,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
714 | } | 714 | } |
715 | 715 | ||
716 | dir_f = JFFS2_INODE_INFO(dir_i); | 716 | dir_f = JFFS2_INODE_INFO(dir_i); |
717 | down(&dir_f->sem); | 717 | mutex_lock(&dir_f->sem); |
718 | 718 | ||
719 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 719 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
720 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); | 720 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); |
@@ -740,7 +740,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
740 | as if it were the final unlink() */ | 740 | as if it were the final unlink() */ |
741 | jffs2_complete_reservation(c); | 741 | jffs2_complete_reservation(c); |
742 | jffs2_free_raw_dirent(rd); | 742 | jffs2_free_raw_dirent(rd); |
743 | up(&dir_f->sem); | 743 | mutex_unlock(&dir_f->sem); |
744 | jffs2_clear_inode(inode); | 744 | jffs2_clear_inode(inode); |
745 | return PTR_ERR(fd); | 745 | return PTR_ERR(fd); |
746 | } | 746 | } |
@@ -753,7 +753,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
753 | one if necessary. */ | 753 | one if necessary. */ |
754 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); | 754 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); |
755 | 755 | ||
756 | up(&dir_f->sem); | 756 | mutex_unlock(&dir_f->sem); |
757 | jffs2_complete_reservation(c); | 757 | jffs2_complete_reservation(c); |
758 | 758 | ||
759 | d_instantiate(dentry, inode); | 759 | d_instantiate(dentry, inode); |
@@ -780,14 +780,14 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, | |||
780 | if (S_ISDIR(new_dentry->d_inode->i_mode)) { | 780 | if (S_ISDIR(new_dentry->d_inode->i_mode)) { |
781 | struct jffs2_full_dirent *fd; | 781 | struct jffs2_full_dirent *fd; |
782 | 782 | ||
783 | down(&victim_f->sem); | 783 | mutex_lock(&victim_f->sem); |
784 | for (fd = victim_f->dents; fd; fd = fd->next) { | 784 | for (fd = victim_f->dents; fd; fd = fd->next) { |
785 | if (fd->ino) { | 785 | if (fd->ino) { |
786 | up(&victim_f->sem); | 786 | mutex_unlock(&victim_f->sem); |
787 | return -ENOTEMPTY; | 787 | return -ENOTEMPTY; |
788 | } | 788 | } |
789 | } | 789 | } |
790 | up(&victim_f->sem); | 790 | mutex_unlock(&victim_f->sem); |
791 | } | 791 | } |
792 | } | 792 | } |
793 | 793 | ||
@@ -816,9 +816,9 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, | |||
816 | /* Don't oops if the victim was a dirent pointing to an | 816 | /* Don't oops if the victim was a dirent pointing to an |
817 | inode which didn't exist. */ | 817 | inode which didn't exist. */ |
818 | if (victim_f->inocache) { | 818 | if (victim_f->inocache) { |
819 | down(&victim_f->sem); | 819 | mutex_lock(&victim_f->sem); |
820 | victim_f->inocache->nlink--; | 820 | victim_f->inocache->nlink--; |
821 | up(&victim_f->sem); | 821 | mutex_unlock(&victim_f->sem); |
822 | } | 822 | } |
823 | } | 823 | } |
824 | 824 | ||
@@ -836,11 +836,11 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, | |||
836 | if (ret) { | 836 | if (ret) { |
837 | /* Oh shit. We really ought to make a single node which can do both atomically */ | 837 | /* Oh shit. We really ought to make a single node which can do both atomically */ |
838 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); | 838 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); |
839 | down(&f->sem); | 839 | mutex_lock(&f->sem); |
840 | inc_nlink(old_dentry->d_inode); | 840 | inc_nlink(old_dentry->d_inode); |
841 | if (f->inocache) | 841 | if (f->inocache) |
842 | f->inocache->nlink++; | 842 | f->inocache->nlink++; |
843 | up(&f->sem); | 843 | mutex_unlock(&f->sem); |
844 | 844 | ||
845 | printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret); | 845 | printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret); |
846 | /* Might as well let the VFS know */ | 846 | /* Might as well let the VFS know */ |
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index a1db9180633f..25a640e566d3 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c | |||
@@ -50,14 +50,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, | |||
50 | instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); | 50 | instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); |
51 | if (!instr) { | 51 | if (!instr) { |
52 | printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); | 52 | printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); |
53 | down(&c->erase_free_sem); | 53 | mutex_lock(&c->erase_free_sem); |
54 | spin_lock(&c->erase_completion_lock); | 54 | spin_lock(&c->erase_completion_lock); |
55 | list_move(&jeb->list, &c->erase_pending_list); | 55 | list_move(&jeb->list, &c->erase_pending_list); |
56 | c->erasing_size -= c->sector_size; | 56 | c->erasing_size -= c->sector_size; |
57 | c->dirty_size += c->sector_size; | 57 | c->dirty_size += c->sector_size; |
58 | jeb->dirty_size = c->sector_size; | 58 | jeb->dirty_size = c->sector_size; |
59 | spin_unlock(&c->erase_completion_lock); | 59 | spin_unlock(&c->erase_completion_lock); |
60 | up(&c->erase_free_sem); | 60 | mutex_unlock(&c->erase_free_sem); |
61 | return; | 61 | return; |
62 | } | 62 | } |
63 | 63 | ||
@@ -84,14 +84,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, | |||
84 | if (ret == -ENOMEM || ret == -EAGAIN) { | 84 | if (ret == -ENOMEM || ret == -EAGAIN) { |
85 | /* Erase failed immediately. Refile it on the list */ | 85 | /* Erase failed immediately. Refile it on the list */ |
86 | D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret)); | 86 | D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret)); |
87 | down(&c->erase_free_sem); | 87 | mutex_lock(&c->erase_free_sem); |
88 | spin_lock(&c->erase_completion_lock); | 88 | spin_lock(&c->erase_completion_lock); |
89 | list_move(&jeb->list, &c->erase_pending_list); | 89 | list_move(&jeb->list, &c->erase_pending_list); |
90 | c->erasing_size -= c->sector_size; | 90 | c->erasing_size -= c->sector_size; |
91 | c->dirty_size += c->sector_size; | 91 | c->dirty_size += c->sector_size; |
92 | jeb->dirty_size = c->sector_size; | 92 | jeb->dirty_size = c->sector_size; |
93 | spin_unlock(&c->erase_completion_lock); | 93 | spin_unlock(&c->erase_completion_lock); |
94 | up(&c->erase_free_sem); | 94 | mutex_unlock(&c->erase_free_sem); |
95 | return; | 95 | return; |
96 | } | 96 | } |
97 | 97 | ||
@@ -107,7 +107,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
107 | { | 107 | { |
108 | struct jffs2_eraseblock *jeb; | 108 | struct jffs2_eraseblock *jeb; |
109 | 109 | ||
110 | down(&c->erase_free_sem); | 110 | mutex_lock(&c->erase_free_sem); |
111 | 111 | ||
112 | spin_lock(&c->erase_completion_lock); | 112 | spin_lock(&c->erase_completion_lock); |
113 | 113 | ||
@@ -116,9 +116,9 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
116 | 116 | ||
117 | if (!list_empty(&c->erase_complete_list)) { | 117 | if (!list_empty(&c->erase_complete_list)) { |
118 | jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list); | 118 | jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list); |
119 | list_del(&jeb->list); | 119 | list_move(&jeb->list, &c->erase_checking_list); |
120 | spin_unlock(&c->erase_completion_lock); | 120 | spin_unlock(&c->erase_completion_lock); |
121 | up(&c->erase_free_sem); | 121 | mutex_unlock(&c->erase_free_sem); |
122 | jffs2_mark_erased_block(c, jeb); | 122 | jffs2_mark_erased_block(c, jeb); |
123 | 123 | ||
124 | if (!--count) { | 124 | if (!--count) { |
@@ -139,7 +139,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
139 | jffs2_free_jeb_node_refs(c, jeb); | 139 | jffs2_free_jeb_node_refs(c, jeb); |
140 | list_add(&jeb->list, &c->erasing_list); | 140 | list_add(&jeb->list, &c->erasing_list); |
141 | spin_unlock(&c->erase_completion_lock); | 141 | spin_unlock(&c->erase_completion_lock); |
142 | up(&c->erase_free_sem); | 142 | mutex_unlock(&c->erase_free_sem); |
143 | 143 | ||
144 | jffs2_erase_block(c, jeb); | 144 | jffs2_erase_block(c, jeb); |
145 | 145 | ||
@@ -149,12 +149,12 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
149 | 149 | ||
150 | /* Be nice */ | 150 | /* Be nice */ |
151 | yield(); | 151 | yield(); |
152 | down(&c->erase_free_sem); | 152 | mutex_lock(&c->erase_free_sem); |
153 | spin_lock(&c->erase_completion_lock); | 153 | spin_lock(&c->erase_completion_lock); |
154 | } | 154 | } |
155 | 155 | ||
156 | spin_unlock(&c->erase_completion_lock); | 156 | spin_unlock(&c->erase_completion_lock); |
157 | up(&c->erase_free_sem); | 157 | mutex_unlock(&c->erase_free_sem); |
158 | done: | 158 | done: |
159 | D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n")); | 159 | D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n")); |
160 | } | 160 | } |
@@ -162,11 +162,11 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
162 | static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) | 162 | static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) |
163 | { | 163 | { |
164 | D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset)); | 164 | D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset)); |
165 | down(&c->erase_free_sem); | 165 | mutex_lock(&c->erase_free_sem); |
166 | spin_lock(&c->erase_completion_lock); | 166 | spin_lock(&c->erase_completion_lock); |
167 | list_move_tail(&jeb->list, &c->erase_complete_list); | 167 | list_move_tail(&jeb->list, &c->erase_complete_list); |
168 | spin_unlock(&c->erase_completion_lock); | 168 | spin_unlock(&c->erase_completion_lock); |
169 | up(&c->erase_free_sem); | 169 | mutex_unlock(&c->erase_free_sem); |
170 | /* Ensure that kupdated calls us again to mark them clean */ | 170 | /* Ensure that kupdated calls us again to mark them clean */ |
171 | jffs2_erase_pending_trigger(c); | 171 | jffs2_erase_pending_trigger(c); |
172 | } | 172 | } |
@@ -180,26 +180,26 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
180 | failed too many times. */ | 180 | failed too many times. */ |
181 | if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { | 181 | if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { |
182 | /* We'd like to give this block another try. */ | 182 | /* We'd like to give this block another try. */ |
183 | down(&c->erase_free_sem); | 183 | mutex_lock(&c->erase_free_sem); |
184 | spin_lock(&c->erase_completion_lock); | 184 | spin_lock(&c->erase_completion_lock); |
185 | list_move(&jeb->list, &c->erase_pending_list); | 185 | list_move(&jeb->list, &c->erase_pending_list); |
186 | c->erasing_size -= c->sector_size; | 186 | c->erasing_size -= c->sector_size; |
187 | c->dirty_size += c->sector_size; | 187 | c->dirty_size += c->sector_size; |
188 | jeb->dirty_size = c->sector_size; | 188 | jeb->dirty_size = c->sector_size; |
189 | spin_unlock(&c->erase_completion_lock); | 189 | spin_unlock(&c->erase_completion_lock); |
190 | up(&c->erase_free_sem); | 190 | mutex_unlock(&c->erase_free_sem); |
191 | return; | 191 | return; |
192 | } | 192 | } |
193 | } | 193 | } |
194 | 194 | ||
195 | down(&c->erase_free_sem); | 195 | mutex_lock(&c->erase_free_sem); |
196 | spin_lock(&c->erase_completion_lock); | 196 | spin_lock(&c->erase_completion_lock); |
197 | c->erasing_size -= c->sector_size; | 197 | c->erasing_size -= c->sector_size; |
198 | c->bad_size += c->sector_size; | 198 | c->bad_size += c->sector_size; |
199 | list_move(&jeb->list, &c->bad_list); | 199 | list_move(&jeb->list, &c->bad_list); |
200 | c->nr_erasing_blocks--; | 200 | c->nr_erasing_blocks--; |
201 | spin_unlock(&c->erase_completion_lock); | 201 | spin_unlock(&c->erase_completion_lock); |
202 | up(&c->erase_free_sem); | 202 | mutex_unlock(&c->erase_free_sem); |
203 | wake_up(&c->erase_wait); | 203 | wake_up(&c->erase_wait); |
204 | } | 204 | } |
205 | 205 | ||
@@ -350,9 +350,11 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl | |||
350 | break; | 350 | break; |
351 | } while(--retlen); | 351 | } while(--retlen); |
352 | c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size); | 352 | c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size); |
353 | if (retlen) | 353 | if (retlen) { |
354 | printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n", | 354 | printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n", |
355 | *wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf)); | 355 | *wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf)); |
356 | return -EIO; | ||
357 | } | ||
356 | return 0; | 358 | return 0; |
357 | } | 359 | } |
358 | do_flash_read: | 360 | do_flash_read: |
@@ -373,10 +375,12 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl | |||
373 | ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf); | 375 | ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf); |
374 | if (ret) { | 376 | if (ret) { |
375 | printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); | 377 | printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); |
378 | ret = -EIO; | ||
376 | goto fail; | 379 | goto fail; |
377 | } | 380 | } |
378 | if (retlen != readlen) { | 381 | if (retlen != readlen) { |
379 | printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen); | 382 | printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen); |
383 | ret = -EIO; | ||
380 | goto fail; | 384 | goto fail; |
381 | } | 385 | } |
382 | for (i=0; i<readlen; i += sizeof(unsigned long)) { | 386 | for (i=0; i<readlen; i += sizeof(unsigned long)) { |
@@ -385,6 +389,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl | |||
385 | if (*datum + 1) { | 389 | if (*datum + 1) { |
386 | *bad_offset += i; | 390 | *bad_offset += i; |
387 | printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", *datum, *bad_offset); | 391 | printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", *datum, *bad_offset); |
392 | ret = -EIO; | ||
388 | goto fail; | 393 | goto fail; |
389 | } | 394 | } |
390 | } | 395 | } |
@@ -419,9 +424,6 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb | |||
419 | if (jffs2_write_nand_cleanmarker(c, jeb)) | 424 | if (jffs2_write_nand_cleanmarker(c, jeb)) |
420 | goto filebad; | 425 | goto filebad; |
421 | } | 426 | } |
422 | |||
423 | /* Everything else got zeroed before the erase */ | ||
424 | jeb->free_size = c->sector_size; | ||
425 | } else { | 427 | } else { |
426 | 428 | ||
427 | struct kvec vecs[1]; | 429 | struct kvec vecs[1]; |
@@ -449,48 +451,50 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb | |||
449 | 451 | ||
450 | goto filebad; | 452 | goto filebad; |
451 | } | 453 | } |
452 | |||
453 | /* Everything else got zeroed before the erase */ | ||
454 | jeb->free_size = c->sector_size; | ||
455 | /* FIXME Special case for cleanmarker in empty block */ | ||
456 | jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL); | ||
457 | } | 454 | } |
455 | /* Everything else got zeroed before the erase */ | ||
456 | jeb->free_size = c->sector_size; | ||
458 | 457 | ||
459 | down(&c->erase_free_sem); | 458 | mutex_lock(&c->erase_free_sem); |
460 | spin_lock(&c->erase_completion_lock); | 459 | spin_lock(&c->erase_completion_lock); |
460 | |||
461 | c->erasing_size -= c->sector_size; | 461 | c->erasing_size -= c->sector_size; |
462 | c->free_size += jeb->free_size; | 462 | c->free_size += c->sector_size; |
463 | c->used_size += jeb->used_size; | ||
464 | 463 | ||
465 | jffs2_dbg_acct_sanity_check_nolock(c,jeb); | 464 | /* Account for cleanmarker now, if it's in-band */ |
466 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); | 465 | if (c->cleanmarker_size && !jffs2_cleanmarker_oob(c)) |
466 | jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL); | ||
467 | 467 | ||
468 | list_add_tail(&jeb->list, &c->free_list); | 468 | list_move_tail(&jeb->list, &c->free_list); |
469 | c->nr_erasing_blocks--; | 469 | c->nr_erasing_blocks--; |
470 | c->nr_free_blocks++; | 470 | c->nr_free_blocks++; |
471 | |||
472 | jffs2_dbg_acct_sanity_check_nolock(c, jeb); | ||
473 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); | ||
474 | |||
471 | spin_unlock(&c->erase_completion_lock); | 475 | spin_unlock(&c->erase_completion_lock); |
472 | up(&c->erase_free_sem); | 476 | mutex_unlock(&c->erase_free_sem); |
473 | wake_up(&c->erase_wait); | 477 | wake_up(&c->erase_wait); |
474 | return; | 478 | return; |
475 | 479 | ||
476 | filebad: | 480 | filebad: |
477 | down(&c->erase_free_sem); | 481 | mutex_lock(&c->erase_free_sem); |
478 | spin_lock(&c->erase_completion_lock); | 482 | spin_lock(&c->erase_completion_lock); |
479 | /* Stick it on a list (any list) so erase_failed can take it | 483 | /* Stick it on a list (any list) so erase_failed can take it |
480 | right off again. Silly, but shouldn't happen often. */ | 484 | right off again. Silly, but shouldn't happen often. */ |
481 | list_add(&jeb->list, &c->erasing_list); | 485 | list_move(&jeb->list, &c->erasing_list); |
482 | spin_unlock(&c->erase_completion_lock); | 486 | spin_unlock(&c->erase_completion_lock); |
483 | up(&c->erase_free_sem); | 487 | mutex_unlock(&c->erase_free_sem); |
484 | jffs2_erase_failed(c, jeb, bad_offset); | 488 | jffs2_erase_failed(c, jeb, bad_offset); |
485 | return; | 489 | return; |
486 | 490 | ||
487 | refile: | 491 | refile: |
488 | /* Stick it back on the list from whence it came and come back later */ | 492 | /* Stick it back on the list from whence it came and come back later */ |
489 | jffs2_erase_pending_trigger(c); | 493 | jffs2_erase_pending_trigger(c); |
490 | down(&c->erase_free_sem); | 494 | mutex_lock(&c->erase_free_sem); |
491 | spin_lock(&c->erase_completion_lock); | 495 | spin_lock(&c->erase_completion_lock); |
492 | list_add(&jeb->list, &c->erase_complete_list); | 496 | list_move(&jeb->list, &c->erase_complete_list); |
493 | spin_unlock(&c->erase_completion_lock); | 497 | spin_unlock(&c->erase_completion_lock); |
494 | up(&c->erase_free_sem); | 498 | mutex_unlock(&c->erase_free_sem); |
495 | return; | 499 | return; |
496 | } | 500 | } |
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index dcc2734e0b5d..5e920343b2c5 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c | |||
@@ -115,9 +115,9 @@ static int jffs2_readpage (struct file *filp, struct page *pg) | |||
115 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->mapping->host); | 115 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->mapping->host); |
116 | int ret; | 116 | int ret; |
117 | 117 | ||
118 | down(&f->sem); | 118 | mutex_lock(&f->sem); |
119 | ret = jffs2_do_readpage_unlock(pg->mapping->host, pg); | 119 | ret = jffs2_do_readpage_unlock(pg->mapping->host, pg); |
120 | up(&f->sem); | 120 | mutex_unlock(&f->sem); |
121 | return ret; | 121 | return ret; |
122 | } | 122 | } |
123 | 123 | ||
@@ -154,7 +154,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, | |||
154 | if (ret) | 154 | if (ret) |
155 | goto out_page; | 155 | goto out_page; |
156 | 156 | ||
157 | down(&f->sem); | 157 | mutex_lock(&f->sem); |
158 | memset(&ri, 0, sizeof(ri)); | 158 | memset(&ri, 0, sizeof(ri)); |
159 | 159 | ||
160 | ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 160 | ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
@@ -181,7 +181,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, | |||
181 | if (IS_ERR(fn)) { | 181 | if (IS_ERR(fn)) { |
182 | ret = PTR_ERR(fn); | 182 | ret = PTR_ERR(fn); |
183 | jffs2_complete_reservation(c); | 183 | jffs2_complete_reservation(c); |
184 | up(&f->sem); | 184 | mutex_unlock(&f->sem); |
185 | goto out_page; | 185 | goto out_page; |
186 | } | 186 | } |
187 | ret = jffs2_add_full_dnode_to_inode(c, f, fn); | 187 | ret = jffs2_add_full_dnode_to_inode(c, f, fn); |
@@ -195,12 +195,12 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, | |||
195 | jffs2_mark_node_obsolete(c, fn->raw); | 195 | jffs2_mark_node_obsolete(c, fn->raw); |
196 | jffs2_free_full_dnode(fn); | 196 | jffs2_free_full_dnode(fn); |
197 | jffs2_complete_reservation(c); | 197 | jffs2_complete_reservation(c); |
198 | up(&f->sem); | 198 | mutex_unlock(&f->sem); |
199 | goto out_page; | 199 | goto out_page; |
200 | } | 200 | } |
201 | jffs2_complete_reservation(c); | 201 | jffs2_complete_reservation(c); |
202 | inode->i_size = pageofs; | 202 | inode->i_size = pageofs; |
203 | up(&f->sem); | 203 | mutex_unlock(&f->sem); |
204 | } | 204 | } |
205 | 205 | ||
206 | /* | 206 | /* |
@@ -209,9 +209,9 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, | |||
209 | * case of a short-copy. | 209 | * case of a short-copy. |
210 | */ | 210 | */ |
211 | if (!PageUptodate(pg)) { | 211 | if (!PageUptodate(pg)) { |
212 | down(&f->sem); | 212 | mutex_lock(&f->sem); |
213 | ret = jffs2_do_readpage_nolock(inode, pg); | 213 | ret = jffs2_do_readpage_nolock(inode, pg); |
214 | up(&f->sem); | 214 | mutex_unlock(&f->sem); |
215 | if (ret) | 215 | if (ret) |
216 | goto out_page; | 216 | goto out_page; |
217 | } | 217 | } |
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index e26ea78c7892..3eb1c84b0a33 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c | |||
@@ -36,6 +36,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
36 | unsigned int ivalid; | 36 | unsigned int ivalid; |
37 | uint32_t alloclen; | 37 | uint32_t alloclen; |
38 | int ret; | 38 | int ret; |
39 | int alloc_type = ALLOC_NORMAL; | ||
39 | 40 | ||
40 | D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino)); | 41 | D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino)); |
41 | 42 | ||
@@ -50,20 +51,20 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
50 | mdata = (char *)&dev; | 51 | mdata = (char *)&dev; |
51 | D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen)); | 52 | D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen)); |
52 | } else if (S_ISLNK(inode->i_mode)) { | 53 | } else if (S_ISLNK(inode->i_mode)) { |
53 | down(&f->sem); | 54 | mutex_lock(&f->sem); |
54 | mdatalen = f->metadata->size; | 55 | mdatalen = f->metadata->size; |
55 | mdata = kmalloc(f->metadata->size, GFP_USER); | 56 | mdata = kmalloc(f->metadata->size, GFP_USER); |
56 | if (!mdata) { | 57 | if (!mdata) { |
57 | up(&f->sem); | 58 | mutex_unlock(&f->sem); |
58 | return -ENOMEM; | 59 | return -ENOMEM; |
59 | } | 60 | } |
60 | ret = jffs2_read_dnode(c, f, f->metadata, mdata, 0, mdatalen); | 61 | ret = jffs2_read_dnode(c, f, f->metadata, mdata, 0, mdatalen); |
61 | if (ret) { | 62 | if (ret) { |
62 | up(&f->sem); | 63 | mutex_unlock(&f->sem); |
63 | kfree(mdata); | 64 | kfree(mdata); |
64 | return ret; | 65 | return ret; |
65 | } | 66 | } |
66 | up(&f->sem); | 67 | mutex_unlock(&f->sem); |
67 | D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen)); | 68 | D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen)); |
68 | } | 69 | } |
69 | 70 | ||
@@ -82,7 +83,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
82 | kfree(mdata); | 83 | kfree(mdata); |
83 | return ret; | 84 | return ret; |
84 | } | 85 | } |
85 | down(&f->sem); | 86 | mutex_lock(&f->sem); |
86 | ivalid = iattr->ia_valid; | 87 | ivalid = iattr->ia_valid; |
87 | 88 | ||
88 | ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 89 | ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
@@ -115,6 +116,10 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
115 | ri->compr = JFFS2_COMPR_ZERO; | 116 | ri->compr = JFFS2_COMPR_ZERO; |
116 | ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size); | 117 | ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size); |
117 | ri->offset = cpu_to_je32(inode->i_size); | 118 | ri->offset = cpu_to_je32(inode->i_size); |
119 | } else if (ivalid & ATTR_SIZE && !iattr->ia_size) { | ||
120 | /* For truncate-to-zero, treat it as deletion because | ||
121 | it'll always be obsoleting all previous nodes */ | ||
122 | alloc_type = ALLOC_DELETION; | ||
118 | } | 123 | } |
119 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); | 124 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); |
120 | if (mdatalen) | 125 | if (mdatalen) |
@@ -122,14 +127,14 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
122 | else | 127 | else |
123 | ri->data_crc = cpu_to_je32(0); | 128 | ri->data_crc = cpu_to_je32(0); |
124 | 129 | ||
125 | new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, ALLOC_NORMAL); | 130 | new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, alloc_type); |
126 | if (S_ISLNK(inode->i_mode)) | 131 | if (S_ISLNK(inode->i_mode)) |
127 | kfree(mdata); | 132 | kfree(mdata); |
128 | 133 | ||
129 | if (IS_ERR(new_metadata)) { | 134 | if (IS_ERR(new_metadata)) { |
130 | jffs2_complete_reservation(c); | 135 | jffs2_complete_reservation(c); |
131 | jffs2_free_raw_inode(ri); | 136 | jffs2_free_raw_inode(ri); |
132 | up(&f->sem); | 137 | mutex_unlock(&f->sem); |
133 | return PTR_ERR(new_metadata); | 138 | return PTR_ERR(new_metadata); |
134 | } | 139 | } |
135 | /* It worked. Update the inode */ | 140 | /* It worked. Update the inode */ |
@@ -149,6 +154,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
149 | if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { | 154 | if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { |
150 | jffs2_add_full_dnode_to_inode(c, f, new_metadata); | 155 | jffs2_add_full_dnode_to_inode(c, f, new_metadata); |
151 | inode->i_size = iattr->ia_size; | 156 | inode->i_size = iattr->ia_size; |
157 | inode->i_blocks = (inode->i_size + 511) >> 9; | ||
152 | f->metadata = NULL; | 158 | f->metadata = NULL; |
153 | } else { | 159 | } else { |
154 | f->metadata = new_metadata; | 160 | f->metadata = new_metadata; |
@@ -159,7 +165,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
159 | } | 165 | } |
160 | jffs2_free_raw_inode(ri); | 166 | jffs2_free_raw_inode(ri); |
161 | 167 | ||
162 | up(&f->sem); | 168 | mutex_unlock(&f->sem); |
163 | jffs2_complete_reservation(c); | 169 | jffs2_complete_reservation(c); |
164 | 170 | ||
165 | /* We have to do the vmtruncate() without f->sem held, since | 171 | /* We have to do the vmtruncate() without f->sem held, since |
@@ -167,8 +173,10 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
167 | We are protected from a simultaneous write() extending i_size | 173 | We are protected from a simultaneous write() extending i_size |
168 | back past iattr->ia_size, because do_truncate() holds the | 174 | back past iattr->ia_size, because do_truncate() holds the |
169 | generic inode semaphore. */ | 175 | generic inode semaphore. */ |
170 | if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) | 176 | if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) { |
171 | vmtruncate(inode, iattr->ia_size); | 177 | vmtruncate(inode, iattr->ia_size); |
178 | inode->i_blocks = (inode->i_size + 511) >> 9; | ||
179 | } | ||
172 | 180 | ||
173 | return 0; | 181 | return 0; |
174 | } | 182 | } |
@@ -248,12 +256,12 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino) | |||
248 | c = JFFS2_SB_INFO(inode->i_sb); | 256 | c = JFFS2_SB_INFO(inode->i_sb); |
249 | 257 | ||
250 | jffs2_init_inode_info(f); | 258 | jffs2_init_inode_info(f); |
251 | down(&f->sem); | 259 | mutex_lock(&f->sem); |
252 | 260 | ||
253 | ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node); | 261 | ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node); |
254 | 262 | ||
255 | if (ret) { | 263 | if (ret) { |
256 | up(&f->sem); | 264 | mutex_unlock(&f->sem); |
257 | iget_failed(inode); | 265 | iget_failed(inode); |
258 | return ERR_PTR(ret); | 266 | return ERR_PTR(ret); |
259 | } | 267 | } |
@@ -330,7 +338,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino) | |||
330 | printk(KERN_WARNING "jffs2_read_inode(): Bogus imode %o for ino %lu\n", inode->i_mode, (unsigned long)inode->i_ino); | 338 | printk(KERN_WARNING "jffs2_read_inode(): Bogus imode %o for ino %lu\n", inode->i_mode, (unsigned long)inode->i_ino); |
331 | } | 339 | } |
332 | 340 | ||
333 | up(&f->sem); | 341 | mutex_unlock(&f->sem); |
334 | 342 | ||
335 | D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n")); | 343 | D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n")); |
336 | unlock_new_inode(inode); | 344 | unlock_new_inode(inode); |
@@ -339,7 +347,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino) | |||
339 | error_io: | 347 | error_io: |
340 | ret = -EIO; | 348 | ret = -EIO; |
341 | error: | 349 | error: |
342 | up(&f->sem); | 350 | mutex_unlock(&f->sem); |
343 | jffs2_do_clear_inode(c, f); | 351 | jffs2_do_clear_inode(c, f); |
344 | iget_failed(inode); | 352 | iget_failed(inode); |
345 | return ERR_PTR(ret); | 353 | return ERR_PTR(ret); |
@@ -380,9 +388,9 @@ int jffs2_remount_fs (struct super_block *sb, int *flags, char *data) | |||
380 | Flush the writebuffer, if neccecary, else we loose it */ | 388 | Flush the writebuffer, if neccecary, else we loose it */ |
381 | if (!(sb->s_flags & MS_RDONLY)) { | 389 | if (!(sb->s_flags & MS_RDONLY)) { |
382 | jffs2_stop_garbage_collect_thread(c); | 390 | jffs2_stop_garbage_collect_thread(c); |
383 | down(&c->alloc_sem); | 391 | mutex_lock(&c->alloc_sem); |
384 | jffs2_flush_wbuf_pad(c); | 392 | jffs2_flush_wbuf_pad(c); |
385 | up(&c->alloc_sem); | 393 | mutex_unlock(&c->alloc_sem); |
386 | } | 394 | } |
387 | 395 | ||
388 | if (!(*flags & MS_RDONLY)) | 396 | if (!(*flags & MS_RDONLY)) |
@@ -429,7 +437,7 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i | |||
429 | 437 | ||
430 | f = JFFS2_INODE_INFO(inode); | 438 | f = JFFS2_INODE_INFO(inode); |
431 | jffs2_init_inode_info(f); | 439 | jffs2_init_inode_info(f); |
432 | down(&f->sem); | 440 | mutex_lock(&f->sem); |
433 | 441 | ||
434 | memset(ri, 0, sizeof(*ri)); | 442 | memset(ri, 0, sizeof(*ri)); |
435 | /* Set OS-specific defaults for new inodes */ | 443 | /* Set OS-specific defaults for new inodes */ |
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 32ff0373aa04..bad005664e30 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c | |||
@@ -126,7 +126,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
126 | int ret = 0, inum, nlink; | 126 | int ret = 0, inum, nlink; |
127 | int xattr = 0; | 127 | int xattr = 0; |
128 | 128 | ||
129 | if (down_interruptible(&c->alloc_sem)) | 129 | if (mutex_lock_interruptible(&c->alloc_sem)) |
130 | return -EINTR; | 130 | return -EINTR; |
131 | 131 | ||
132 | for (;;) { | 132 | for (;;) { |
@@ -143,7 +143,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
143 | c->unchecked_size); | 143 | c->unchecked_size); |
144 | jffs2_dbg_dump_block_lists_nolock(c); | 144 | jffs2_dbg_dump_block_lists_nolock(c); |
145 | spin_unlock(&c->erase_completion_lock); | 145 | spin_unlock(&c->erase_completion_lock); |
146 | up(&c->alloc_sem); | 146 | mutex_unlock(&c->alloc_sem); |
147 | return -ENOSPC; | 147 | return -ENOSPC; |
148 | } | 148 | } |
149 | 149 | ||
@@ -190,7 +190,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
190 | made no progress in this case, but that should be OK */ | 190 | made no progress in this case, but that should be OK */ |
191 | c->checked_ino--; | 191 | c->checked_ino--; |
192 | 192 | ||
193 | up(&c->alloc_sem); | 193 | mutex_unlock(&c->alloc_sem); |
194 | sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); | 194 | sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); |
195 | return 0; | 195 | return 0; |
196 | 196 | ||
@@ -210,7 +210,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
210 | printk(KERN_WARNING "Returned error for crccheck of ino #%u. Expect badness...\n", ic->ino); | 210 | printk(KERN_WARNING "Returned error for crccheck of ino #%u. Expect badness...\n", ic->ino); |
211 | 211 | ||
212 | jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT); | 212 | jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT); |
213 | up(&c->alloc_sem); | 213 | mutex_unlock(&c->alloc_sem); |
214 | return ret; | 214 | return ret; |
215 | } | 215 | } |
216 | 216 | ||
@@ -221,9 +221,15 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
221 | jeb = jffs2_find_gc_block(c); | 221 | jeb = jffs2_find_gc_block(c); |
222 | 222 | ||
223 | if (!jeb) { | 223 | if (!jeb) { |
224 | D1 (printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n")); | 224 | /* Couldn't find a free block. But maybe we can just erase one and make 'progress'? */ |
225 | if (!list_empty(&c->erase_pending_list)) { | ||
226 | spin_unlock(&c->erase_completion_lock); | ||
227 | mutex_unlock(&c->alloc_sem); | ||
228 | return -EAGAIN; | ||
229 | } | ||
230 | D1(printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n")); | ||
225 | spin_unlock(&c->erase_completion_lock); | 231 | spin_unlock(&c->erase_completion_lock); |
226 | up(&c->alloc_sem); | 232 | mutex_unlock(&c->alloc_sem); |
227 | return -EIO; | 233 | return -EIO; |
228 | } | 234 | } |
229 | 235 | ||
@@ -232,7 +238,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
232 | printk(KERN_DEBUG "Nextblock at %08x, used_size %08x, dirty_size %08x, wasted_size %08x, free_size %08x\n", c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->free_size)); | 238 | printk(KERN_DEBUG "Nextblock at %08x, used_size %08x, dirty_size %08x, wasted_size %08x, free_size %08x\n", c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->free_size)); |
233 | 239 | ||
234 | if (!jeb->used_size) { | 240 | if (!jeb->used_size) { |
235 | up(&c->alloc_sem); | 241 | mutex_unlock(&c->alloc_sem); |
236 | goto eraseit; | 242 | goto eraseit; |
237 | } | 243 | } |
238 | 244 | ||
@@ -248,7 +254,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
248 | jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size); | 254 | jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size); |
249 | jeb->gc_node = raw; | 255 | jeb->gc_node = raw; |
250 | spin_unlock(&c->erase_completion_lock); | 256 | spin_unlock(&c->erase_completion_lock); |
251 | up(&c->alloc_sem); | 257 | mutex_unlock(&c->alloc_sem); |
252 | BUG(); | 258 | BUG(); |
253 | } | 259 | } |
254 | } | 260 | } |
@@ -266,7 +272,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
266 | /* Just mark it obsolete */ | 272 | /* Just mark it obsolete */ |
267 | jffs2_mark_node_obsolete(c, raw); | 273 | jffs2_mark_node_obsolete(c, raw); |
268 | } | 274 | } |
269 | up(&c->alloc_sem); | 275 | mutex_unlock(&c->alloc_sem); |
270 | goto eraseit_lock; | 276 | goto eraseit_lock; |
271 | } | 277 | } |
272 | 278 | ||
@@ -334,7 +340,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
334 | */ | 340 | */ |
335 | printk(KERN_CRIT "Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n", | 341 | printk(KERN_CRIT "Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n", |
336 | ic->ino, ic->state); | 342 | ic->ino, ic->state); |
337 | up(&c->alloc_sem); | 343 | mutex_unlock(&c->alloc_sem); |
338 | spin_unlock(&c->inocache_lock); | 344 | spin_unlock(&c->inocache_lock); |
339 | BUG(); | 345 | BUG(); |
340 | 346 | ||
@@ -345,7 +351,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
345 | the alloc_sem() (for marking nodes invalid) so we must | 351 | the alloc_sem() (for marking nodes invalid) so we must |
346 | drop the alloc_sem before sleeping. */ | 352 | drop the alloc_sem before sleeping. */ |
347 | 353 | ||
348 | up(&c->alloc_sem); | 354 | mutex_unlock(&c->alloc_sem); |
349 | D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n", | 355 | D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n", |
350 | ic->ino, ic->state)); | 356 | ic->ino, ic->state)); |
351 | sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); | 357 | sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); |
@@ -416,7 +422,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
416 | ret = -ENOSPC; | 422 | ret = -ENOSPC; |
417 | } | 423 | } |
418 | release_sem: | 424 | release_sem: |
419 | up(&c->alloc_sem); | 425 | mutex_unlock(&c->alloc_sem); |
420 | 426 | ||
421 | eraseit_lock: | 427 | eraseit_lock: |
422 | /* If we've finished this block, start it erasing */ | 428 | /* If we've finished this block, start it erasing */ |
@@ -445,7 +451,7 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_era | |||
445 | uint32_t start = 0, end = 0, nrfrags = 0; | 451 | uint32_t start = 0, end = 0, nrfrags = 0; |
446 | int ret = 0; | 452 | int ret = 0; |
447 | 453 | ||
448 | down(&f->sem); | 454 | mutex_lock(&f->sem); |
449 | 455 | ||
450 | /* Now we have the lock for this inode. Check that it's still the one at the head | 456 | /* Now we have the lock for this inode. Check that it's still the one at the head |
451 | of the list. */ | 457 | of the list. */ |
@@ -525,7 +531,7 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_era | |||
525 | } | 531 | } |
526 | } | 532 | } |
527 | upnout: | 533 | upnout: |
528 | up(&f->sem); | 534 | mutex_unlock(&f->sem); |
529 | 535 | ||
530 | return ret; | 536 | return ret; |
531 | } | 537 | } |
@@ -846,7 +852,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct | |||
846 | /* Prevent the erase code from nicking the obsolete node refs while | 852 | /* Prevent the erase code from nicking the obsolete node refs while |
847 | we're looking at them. I really don't like this extra lock but | 853 | we're looking at them. I really don't like this extra lock but |
848 | can't see any alternative. Suggestions on a postcard to... */ | 854 | can't see any alternative. Suggestions on a postcard to... */ |
849 | down(&c->erase_free_sem); | 855 | mutex_lock(&c->erase_free_sem); |
850 | 856 | ||
851 | for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) { | 857 | for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) { |
852 | 858 | ||
@@ -899,7 +905,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct | |||
899 | /* OK. The name really does match. There really is still an older node on | 905 | /* OK. The name really does match. There really is still an older node on |
900 | the flash which our deletion dirent obsoletes. So we have to write out | 906 | the flash which our deletion dirent obsoletes. So we have to write out |
901 | a new deletion dirent to replace it */ | 907 | a new deletion dirent to replace it */ |
902 | up(&c->erase_free_sem); | 908 | mutex_unlock(&c->erase_free_sem); |
903 | 909 | ||
904 | D1(printk(KERN_DEBUG "Deletion dirent at %08x still obsoletes real dirent \"%s\" at %08x for ino #%u\n", | 910 | D1(printk(KERN_DEBUG "Deletion dirent at %08x still obsoletes real dirent \"%s\" at %08x for ino #%u\n", |
905 | ref_offset(fd->raw), fd->name, ref_offset(raw), je32_to_cpu(rd->ino))); | 911 | ref_offset(fd->raw), fd->name, ref_offset(raw), je32_to_cpu(rd->ino))); |
@@ -908,7 +914,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct | |||
908 | return jffs2_garbage_collect_dirent(c, jeb, f, fd); | 914 | return jffs2_garbage_collect_dirent(c, jeb, f, fd); |
909 | } | 915 | } |
910 | 916 | ||
911 | up(&c->erase_free_sem); | 917 | mutex_unlock(&c->erase_free_sem); |
912 | kfree(rd); | 918 | kfree(rd); |
913 | } | 919 | } |
914 | 920 | ||
@@ -1081,7 +1087,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras | |||
1081 | return 0; | 1087 | return 0; |
1082 | } | 1088 | } |
1083 | 1089 | ||
1084 | static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 1090 | static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *orig_jeb, |
1085 | struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, | 1091 | struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, |
1086 | uint32_t start, uint32_t end) | 1092 | uint32_t start, uint32_t end) |
1087 | { | 1093 | { |
diff --git a/fs/jffs2/ioctl.c b/fs/jffs2/ioctl.c index f4d525b0ea53..e2177210f621 100644 --- a/fs/jffs2/ioctl.c +++ b/fs/jffs2/ioctl.c | |||
@@ -10,6 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/fs.h> | 12 | #include <linux/fs.h> |
13 | #include "nodelist.h" | ||
13 | 14 | ||
14 | int jffs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | 15 | int jffs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, |
15 | unsigned long arg) | 16 | unsigned long arg) |
diff --git a/fs/jffs2/jffs2_fs_i.h b/fs/jffs2/jffs2_fs_i.h index a841f4973a74..31559f45fdde 100644 --- a/fs/jffs2/jffs2_fs_i.h +++ b/fs/jffs2/jffs2_fs_i.h | |||
@@ -15,7 +15,7 @@ | |||
15 | #include <linux/version.h> | 15 | #include <linux/version.h> |
16 | #include <linux/rbtree.h> | 16 | #include <linux/rbtree.h> |
17 | #include <linux/posix_acl.h> | 17 | #include <linux/posix_acl.h> |
18 | #include <linux/semaphore.h> | 18 | #include <linux/mutex.h> |
19 | 19 | ||
20 | struct jffs2_inode_info { | 20 | struct jffs2_inode_info { |
21 | /* We need an internal mutex similar to inode->i_mutex. | 21 | /* We need an internal mutex similar to inode->i_mutex. |
@@ -24,7 +24,7 @@ struct jffs2_inode_info { | |||
24 | before letting GC proceed. Or we'd have to put ugliness | 24 | before letting GC proceed. Or we'd have to put ugliness |
25 | into the GC code so it didn't attempt to obtain the i_mutex | 25 | into the GC code so it didn't attempt to obtain the i_mutex |
26 | for the inode(s) which are already locked */ | 26 | for the inode(s) which are already locked */ |
27 | struct semaphore sem; | 27 | struct mutex sem; |
28 | 28 | ||
29 | /* The highest (datanode) version number used for this ino */ | 29 | /* The highest (datanode) version number used for this ino */ |
30 | uint32_t highest_version; | 30 | uint32_t highest_version; |
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 18fca2b9e531..85ef6dbb1be7 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h | |||
@@ -16,7 +16,7 @@ | |||
16 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
17 | #include <linux/workqueue.h> | 17 | #include <linux/workqueue.h> |
18 | #include <linux/completion.h> | 18 | #include <linux/completion.h> |
19 | #include <linux/semaphore.h> | 19 | #include <linux/mutex.h> |
20 | #include <linux/timer.h> | 20 | #include <linux/timer.h> |
21 | #include <linux/wait.h> | 21 | #include <linux/wait.h> |
22 | #include <linux/list.h> | 22 | #include <linux/list.h> |
@@ -44,7 +44,7 @@ struct jffs2_sb_info { | |||
44 | struct completion gc_thread_start; /* GC thread start completion */ | 44 | struct completion gc_thread_start; /* GC thread start completion */ |
45 | struct completion gc_thread_exit; /* GC thread exit completion port */ | 45 | struct completion gc_thread_exit; /* GC thread exit completion port */ |
46 | 46 | ||
47 | struct semaphore alloc_sem; /* Used to protect all the following | 47 | struct mutex alloc_sem; /* Used to protect all the following |
48 | fields, and also to protect against | 48 | fields, and also to protect against |
49 | out-of-order writing of nodes. And GC. */ | 49 | out-of-order writing of nodes. And GC. */ |
50 | uint32_t cleanmarker_size; /* Size of an _inline_ CLEANMARKER | 50 | uint32_t cleanmarker_size; /* Size of an _inline_ CLEANMARKER |
@@ -87,6 +87,7 @@ struct jffs2_sb_info { | |||
87 | struct list_head erasable_list; /* Blocks which are completely dirty, and need erasing */ | 87 | struct list_head erasable_list; /* Blocks which are completely dirty, and need erasing */ |
88 | struct list_head erasable_pending_wbuf_list; /* Blocks which need erasing but only after the current wbuf is flushed */ | 88 | struct list_head erasable_pending_wbuf_list; /* Blocks which need erasing but only after the current wbuf is flushed */ |
89 | struct list_head erasing_list; /* Blocks which are currently erasing */ | 89 | struct list_head erasing_list; /* Blocks which are currently erasing */ |
90 | struct list_head erase_checking_list; /* Blocks which are being checked and marked */ | ||
90 | struct list_head erase_pending_list; /* Blocks which need erasing now */ | 91 | struct list_head erase_pending_list; /* Blocks which need erasing now */ |
91 | struct list_head erase_complete_list; /* Blocks which are erased and need the clean marker written to them */ | 92 | struct list_head erase_complete_list; /* Blocks which are erased and need the clean marker written to them */ |
92 | struct list_head free_list; /* Blocks which are free and ready to be used */ | 93 | struct list_head free_list; /* Blocks which are free and ready to be used */ |
@@ -104,7 +105,7 @@ struct jffs2_sb_info { | |||
104 | /* Sem to allow jffs2_garbage_collect_deletion_dirent to | 105 | /* Sem to allow jffs2_garbage_collect_deletion_dirent to |
105 | drop the erase_completion_lock while it's holding a pointer | 106 | drop the erase_completion_lock while it's holding a pointer |
106 | to an obsoleted node. I don't like this. Alternatives welcomed. */ | 107 | to an obsoleted node. I don't like this. Alternatives welcomed. */ |
107 | struct semaphore erase_free_sem; | 108 | struct mutex erase_free_sem; |
108 | 109 | ||
109 | uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */ | 110 | uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */ |
110 | 111 | ||
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index ec1aae9e695e..8219df6eb6d8 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h | |||
@@ -87,7 +87,7 @@ struct jffs2_raw_node_ref | |||
87 | xattr_ref or xattr_datum instead. The common part of those structures | 87 | xattr_ref or xattr_datum instead. The common part of those structures |
88 | has NULL in the first word. See jffs2_raw_ref_to_ic() below */ | 88 | has NULL in the first word. See jffs2_raw_ref_to_ic() below */ |
89 | uint32_t flash_offset; | 89 | uint32_t flash_offset; |
90 | #define TEST_TOTLEN | 90 | #undef TEST_TOTLEN |
91 | #ifdef TEST_TOTLEN | 91 | #ifdef TEST_TOTLEN |
92 | uint32_t __totlen; /* This may die; use ref_totlen(c, jeb, ) below */ | 92 | uint32_t __totlen; /* This may die; use ref_totlen(c, jeb, ) below */ |
93 | #endif | 93 | #endif |
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index a0313fa8748e..9df8f3ef20df 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c | |||
@@ -48,7 +48,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, | |||
48 | minsize = PAD(minsize); | 48 | minsize = PAD(minsize); |
49 | 49 | ||
50 | D1(printk(KERN_DEBUG "jffs2_reserve_space(): Requested 0x%x bytes\n", minsize)); | 50 | D1(printk(KERN_DEBUG "jffs2_reserve_space(): Requested 0x%x bytes\n", minsize)); |
51 | down(&c->alloc_sem); | 51 | mutex_lock(&c->alloc_sem); |
52 | 52 | ||
53 | D1(printk(KERN_DEBUG "jffs2_reserve_space(): alloc sem got\n")); | 53 | D1(printk(KERN_DEBUG "jffs2_reserve_space(): alloc sem got\n")); |
54 | 54 | ||
@@ -57,7 +57,6 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, | |||
57 | /* this needs a little more thought (true <tglx> :)) */ | 57 | /* this needs a little more thought (true <tglx> :)) */ |
58 | while(ret == -EAGAIN) { | 58 | while(ret == -EAGAIN) { |
59 | while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) { | 59 | while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) { |
60 | int ret; | ||
61 | uint32_t dirty, avail; | 60 | uint32_t dirty, avail; |
62 | 61 | ||
63 | /* calculate real dirty size | 62 | /* calculate real dirty size |
@@ -82,7 +81,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, | |||
82 | dirty, c->unchecked_size, c->sector_size)); | 81 | dirty, c->unchecked_size, c->sector_size)); |
83 | 82 | ||
84 | spin_unlock(&c->erase_completion_lock); | 83 | spin_unlock(&c->erase_completion_lock); |
85 | up(&c->alloc_sem); | 84 | mutex_unlock(&c->alloc_sem); |
86 | return -ENOSPC; | 85 | return -ENOSPC; |
87 | } | 86 | } |
88 | 87 | ||
@@ -105,11 +104,11 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, | |||
105 | D1(printk(KERN_DEBUG "max. available size 0x%08x < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n", | 104 | D1(printk(KERN_DEBUG "max. available size 0x%08x < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n", |
106 | avail, blocksneeded * c->sector_size)); | 105 | avail, blocksneeded * c->sector_size)); |
107 | spin_unlock(&c->erase_completion_lock); | 106 | spin_unlock(&c->erase_completion_lock); |
108 | up(&c->alloc_sem); | 107 | mutex_unlock(&c->alloc_sem); |
109 | return -ENOSPC; | 108 | return -ENOSPC; |
110 | } | 109 | } |
111 | 110 | ||
112 | up(&c->alloc_sem); | 111 | mutex_unlock(&c->alloc_sem); |
113 | 112 | ||
114 | D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n", | 113 | D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n", |
115 | c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size, | 114 | c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size, |
@@ -117,7 +116,10 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, | |||
117 | spin_unlock(&c->erase_completion_lock); | 116 | spin_unlock(&c->erase_completion_lock); |
118 | 117 | ||
119 | ret = jffs2_garbage_collect_pass(c); | 118 | ret = jffs2_garbage_collect_pass(c); |
120 | if (ret) | 119 | |
120 | if (ret == -EAGAIN) | ||
121 | jffs2_erase_pending_blocks(c, 1); | ||
122 | else if (ret) | ||
121 | return ret; | 123 | return ret; |
122 | 124 | ||
123 | cond_resched(); | 125 | cond_resched(); |
@@ -125,7 +127,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, | |||
125 | if (signal_pending(current)) | 127 | if (signal_pending(current)) |
126 | return -EINTR; | 128 | return -EINTR; |
127 | 129 | ||
128 | down(&c->alloc_sem); | 130 | mutex_lock(&c->alloc_sem); |
129 | spin_lock(&c->erase_completion_lock); | 131 | spin_lock(&c->erase_completion_lock); |
130 | } | 132 | } |
131 | 133 | ||
@@ -138,7 +140,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, | |||
138 | if (!ret) | 140 | if (!ret) |
139 | ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); | 141 | ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); |
140 | if (ret) | 142 | if (ret) |
141 | up(&c->alloc_sem); | 143 | mutex_unlock(&c->alloc_sem); |
142 | return ret; | 144 | return ret; |
143 | } | 145 | } |
144 | 146 | ||
@@ -463,7 +465,7 @@ void jffs2_complete_reservation(struct jffs2_sb_info *c) | |||
463 | { | 465 | { |
464 | D1(printk(KERN_DEBUG "jffs2_complete_reservation()\n")); | 466 | D1(printk(KERN_DEBUG "jffs2_complete_reservation()\n")); |
465 | jffs2_garbage_collect_trigger(c); | 467 | jffs2_garbage_collect_trigger(c); |
466 | up(&c->alloc_sem); | 468 | mutex_unlock(&c->alloc_sem); |
467 | } | 469 | } |
468 | 470 | ||
469 | static inline int on_list(struct list_head *obj, struct list_head *head) | 471 | static inline int on_list(struct list_head *obj, struct list_head *head) |
@@ -512,7 +514,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
512 | any jffs2_raw_node_refs. So we don't need to stop erases from | 514 | any jffs2_raw_node_refs. So we don't need to stop erases from |
513 | happening, or protect against people holding an obsolete | 515 | happening, or protect against people holding an obsolete |
514 | jffs2_raw_node_ref without the erase_completion_lock. */ | 516 | jffs2_raw_node_ref without the erase_completion_lock. */ |
515 | down(&c->erase_free_sem); | 517 | mutex_lock(&c->erase_free_sem); |
516 | } | 518 | } |
517 | 519 | ||
518 | spin_lock(&c->erase_completion_lock); | 520 | spin_lock(&c->erase_completion_lock); |
@@ -715,7 +717,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
715 | } | 717 | } |
716 | 718 | ||
717 | out_erase_sem: | 719 | out_erase_sem: |
718 | up(&c->erase_free_sem); | 720 | mutex_unlock(&c->erase_free_sem); |
719 | } | 721 | } |
720 | 722 | ||
721 | int jffs2_thread_should_wake(struct jffs2_sb_info *c) | 723 | int jffs2_thread_should_wake(struct jffs2_sb_info *c) |
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index e512a93d6249..4cb4d76de07f 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c | |||
@@ -825,8 +825,9 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
825 | else // normal case... | 825 | else // normal case... |
826 | tn->fn->size = je32_to_cpu(rd->dsize); | 826 | tn->fn->size = je32_to_cpu(rd->dsize); |
827 | 827 | ||
828 | dbg_readinode("dnode @%08x: ver %u, offset %#04x, dsize %#04x, csize %#04x\n", | 828 | dbg_readinode2("dnode @%08x: ver %u, offset %#04x, dsize %#04x, csize %#04x\n", |
829 | ref_offset(ref), je32_to_cpu(rd->version), je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize), csize); | 829 | ref_offset(ref), je32_to_cpu(rd->version), |
830 | je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize), csize); | ||
830 | 831 | ||
831 | ret = jffs2_add_tn_to_tree(c, rii, tn); | 832 | ret = jffs2_add_tn_to_tree(c, rii, tn); |
832 | 833 | ||
@@ -836,13 +837,13 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
836 | jffs2_free_tmp_dnode_info(tn); | 837 | jffs2_free_tmp_dnode_info(tn); |
837 | return ret; | 838 | return ret; |
838 | } | 839 | } |
839 | #ifdef JFFS2_DBG_READINODE_MESSAGES | 840 | #ifdef JFFS2_DBG_READINODE2_MESSAGES |
840 | dbg_readinode("After adding ver %d:\n", je32_to_cpu(rd->version)); | 841 | dbg_readinode2("After adding ver %d:\n", je32_to_cpu(rd->version)); |
841 | tn = tn_first(&rii->tn_root); | 842 | tn = tn_first(&rii->tn_root); |
842 | while (tn) { | 843 | while (tn) { |
843 | dbg_readinode("%p: v %d r 0x%x-0x%x ov %d\n", | 844 | dbg_readinode2("%p: v %d r 0x%x-0x%x ov %d\n", |
844 | tn, tn->version, tn->fn->ofs, | 845 | tn, tn->version, tn->fn->ofs, |
845 | tn->fn->ofs+tn->fn->size, tn->overlapped); | 846 | tn->fn->ofs+tn->fn->size, tn->overlapped); |
846 | tn = tn_next(tn); | 847 | tn = tn_next(tn); |
847 | } | 848 | } |
848 | #endif | 849 | #endif |
@@ -1193,7 +1194,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
1193 | JFFS2_ERROR("failed to read from flash: error %d, %zd of %zd bytes read\n", | 1194 | JFFS2_ERROR("failed to read from flash: error %d, %zd of %zd bytes read\n", |
1194 | ret, retlen, sizeof(*latest_node)); | 1195 | ret, retlen, sizeof(*latest_node)); |
1195 | /* FIXME: If this fails, there seems to be a memory leak. Find it. */ | 1196 | /* FIXME: If this fails, there seems to be a memory leak. Find it. */ |
1196 | up(&f->sem); | 1197 | mutex_unlock(&f->sem); |
1197 | jffs2_do_clear_inode(c, f); | 1198 | jffs2_do_clear_inode(c, f); |
1198 | return ret?ret:-EIO; | 1199 | return ret?ret:-EIO; |
1199 | } | 1200 | } |
@@ -1202,7 +1203,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
1202 | if (crc != je32_to_cpu(latest_node->node_crc)) { | 1203 | if (crc != je32_to_cpu(latest_node->node_crc)) { |
1203 | JFFS2_ERROR("CRC failed for read_inode of inode %u at physical location 0x%x\n", | 1204 | JFFS2_ERROR("CRC failed for read_inode of inode %u at physical location 0x%x\n", |
1204 | f->inocache->ino, ref_offset(rii.latest_ref)); | 1205 | f->inocache->ino, ref_offset(rii.latest_ref)); |
1205 | up(&f->sem); | 1206 | mutex_unlock(&f->sem); |
1206 | jffs2_do_clear_inode(c, f); | 1207 | jffs2_do_clear_inode(c, f); |
1207 | return -EIO; | 1208 | return -EIO; |
1208 | } | 1209 | } |
@@ -1242,7 +1243,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
1242 | f->target = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); | 1243 | f->target = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); |
1243 | if (!f->target) { | 1244 | if (!f->target) { |
1244 | JFFS2_ERROR("can't allocate %d bytes of memory for the symlink target path cache\n", je32_to_cpu(latest_node->csize)); | 1245 | JFFS2_ERROR("can't allocate %d bytes of memory for the symlink target path cache\n", je32_to_cpu(latest_node->csize)); |
1245 | up(&f->sem); | 1246 | mutex_unlock(&f->sem); |
1246 | jffs2_do_clear_inode(c, f); | 1247 | jffs2_do_clear_inode(c, f); |
1247 | return -ENOMEM; | 1248 | return -ENOMEM; |
1248 | } | 1249 | } |
@@ -1255,7 +1256,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
1255 | ret = -EIO; | 1256 | ret = -EIO; |
1256 | kfree(f->target); | 1257 | kfree(f->target); |
1257 | f->target = NULL; | 1258 | f->target = NULL; |
1258 | up(&f->sem); | 1259 | mutex_unlock(&f->sem); |
1259 | jffs2_do_clear_inode(c, f); | 1260 | jffs2_do_clear_inode(c, f); |
1260 | return -ret; | 1261 | return -ret; |
1261 | } | 1262 | } |
@@ -1273,14 +1274,14 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
1273 | if (f->metadata) { | 1274 | if (f->metadata) { |
1274 | JFFS2_ERROR("Argh. Special inode #%u with mode 0%o had metadata node\n", | 1275 | JFFS2_ERROR("Argh. Special inode #%u with mode 0%o had metadata node\n", |
1275 | f->inocache->ino, jemode_to_cpu(latest_node->mode)); | 1276 | f->inocache->ino, jemode_to_cpu(latest_node->mode)); |
1276 | up(&f->sem); | 1277 | mutex_unlock(&f->sem); |
1277 | jffs2_do_clear_inode(c, f); | 1278 | jffs2_do_clear_inode(c, f); |
1278 | return -EIO; | 1279 | return -EIO; |
1279 | } | 1280 | } |
1280 | if (!frag_first(&f->fragtree)) { | 1281 | if (!frag_first(&f->fragtree)) { |
1281 | JFFS2_ERROR("Argh. Special inode #%u with mode 0%o has no fragments\n", | 1282 | JFFS2_ERROR("Argh. Special inode #%u with mode 0%o has no fragments\n", |
1282 | f->inocache->ino, jemode_to_cpu(latest_node->mode)); | 1283 | f->inocache->ino, jemode_to_cpu(latest_node->mode)); |
1283 | up(&f->sem); | 1284 | mutex_unlock(&f->sem); |
1284 | jffs2_do_clear_inode(c, f); | 1285 | jffs2_do_clear_inode(c, f); |
1285 | return -EIO; | 1286 | return -EIO; |
1286 | } | 1287 | } |
@@ -1289,7 +1290,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
1289 | JFFS2_ERROR("Argh. Special inode #%u with mode 0x%x had more than one node\n", | 1290 | JFFS2_ERROR("Argh. Special inode #%u with mode 0x%x had more than one node\n", |
1290 | f->inocache->ino, jemode_to_cpu(latest_node->mode)); | 1291 | f->inocache->ino, jemode_to_cpu(latest_node->mode)); |
1291 | /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */ | 1292 | /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */ |
1292 | up(&f->sem); | 1293 | mutex_unlock(&f->sem); |
1293 | jffs2_do_clear_inode(c, f); | 1294 | jffs2_do_clear_inode(c, f); |
1294 | return -EIO; | 1295 | return -EIO; |
1295 | } | 1296 | } |
@@ -1379,12 +1380,13 @@ int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *i | |||
1379 | if (!f) | 1380 | if (!f) |
1380 | return -ENOMEM; | 1381 | return -ENOMEM; |
1381 | 1382 | ||
1382 | init_MUTEX_LOCKED(&f->sem); | 1383 | mutex_init(&f->sem); |
1384 | mutex_lock(&f->sem); | ||
1383 | f->inocache = ic; | 1385 | f->inocache = ic; |
1384 | 1386 | ||
1385 | ret = jffs2_do_read_inode_internal(c, f, &n); | 1387 | ret = jffs2_do_read_inode_internal(c, f, &n); |
1386 | if (!ret) { | 1388 | if (!ret) { |
1387 | up(&f->sem); | 1389 | mutex_unlock(&f->sem); |
1388 | jffs2_do_clear_inode(c, f); | 1390 | jffs2_do_clear_inode(c, f); |
1389 | } | 1391 | } |
1390 | kfree (f); | 1392 | kfree (f); |
@@ -1398,7 +1400,7 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | |||
1398 | 1400 | ||
1399 | jffs2_clear_acl(f); | 1401 | jffs2_clear_acl(f); |
1400 | jffs2_xattr_delete_inode(c, f->inocache); | 1402 | jffs2_xattr_delete_inode(c, f->inocache); |
1401 | down(&f->sem); | 1403 | mutex_lock(&f->sem); |
1402 | deleted = f->inocache && !f->inocache->nlink; | 1404 | deleted = f->inocache && !f->inocache->nlink; |
1403 | 1405 | ||
1404 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) | 1406 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) |
@@ -1430,5 +1432,5 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | |||
1430 | jffs2_del_ino_cache(c, f->inocache); | 1432 | jffs2_del_ino_cache(c, f->inocache); |
1431 | } | 1433 | } |
1432 | 1434 | ||
1433 | up(&f->sem); | 1435 | mutex_unlock(&f->sem); |
1434 | } | 1436 | } |
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 4677355996cc..f3353df178e7 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c | |||
@@ -47,7 +47,7 @@ static void jffs2_i_init_once(struct kmem_cache *cachep, void *foo) | |||
47 | { | 47 | { |
48 | struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo; | 48 | struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo; |
49 | 49 | ||
50 | init_MUTEX(&ei->sem); | 50 | mutex_init(&ei->sem); |
51 | inode_init_once(&ei->vfs_inode); | 51 | inode_init_once(&ei->vfs_inode); |
52 | } | 52 | } |
53 | 53 | ||
@@ -55,9 +55,9 @@ static int jffs2_sync_fs(struct super_block *sb, int wait) | |||
55 | { | 55 | { |
56 | struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); | 56 | struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); |
57 | 57 | ||
58 | down(&c->alloc_sem); | 58 | mutex_lock(&c->alloc_sem); |
59 | jffs2_flush_wbuf_pad(c); | 59 | jffs2_flush_wbuf_pad(c); |
60 | up(&c->alloc_sem); | 60 | mutex_unlock(&c->alloc_sem); |
61 | return 0; | 61 | return 0; |
62 | } | 62 | } |
63 | 63 | ||
@@ -95,8 +95,8 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent) | |||
95 | 95 | ||
96 | /* Initialize JFFS2 superblock locks, the further initialization will | 96 | /* Initialize JFFS2 superblock locks, the further initialization will |
97 | * be done later */ | 97 | * be done later */ |
98 | init_MUTEX(&c->alloc_sem); | 98 | mutex_init(&c->alloc_sem); |
99 | init_MUTEX(&c->erase_free_sem); | 99 | mutex_init(&c->erase_free_sem); |
100 | init_waitqueue_head(&c->erase_wait); | 100 | init_waitqueue_head(&c->erase_wait); |
101 | init_waitqueue_head(&c->inocache_wq); | 101 | init_waitqueue_head(&c->inocache_wq); |
102 | spin_lock_init(&c->erase_completion_lock); | 102 | spin_lock_init(&c->erase_completion_lock); |
@@ -125,9 +125,9 @@ static void jffs2_put_super (struct super_block *sb) | |||
125 | 125 | ||
126 | D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n")); | 126 | D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n")); |
127 | 127 | ||
128 | down(&c->alloc_sem); | 128 | mutex_lock(&c->alloc_sem); |
129 | jffs2_flush_wbuf_pad(c); | 129 | jffs2_flush_wbuf_pad(c); |
130 | up(&c->alloc_sem); | 130 | mutex_unlock(&c->alloc_sem); |
131 | 131 | ||
132 | jffs2_sum_exit(c); | 132 | jffs2_sum_exit(c); |
133 | 133 | ||
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index d1d4f27464ba..8de52b607678 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c | |||
@@ -578,8 +578,8 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
578 | if (!jffs2_is_writebuffered(c)) | 578 | if (!jffs2_is_writebuffered(c)) |
579 | return 0; | 579 | return 0; |
580 | 580 | ||
581 | if (!down_trylock(&c->alloc_sem)) { | 581 | if (mutex_trylock(&c->alloc_sem)) { |
582 | up(&c->alloc_sem); | 582 | mutex_unlock(&c->alloc_sem); |
583 | printk(KERN_CRIT "jffs2_flush_wbuf() called with alloc_sem not locked!\n"); | 583 | printk(KERN_CRIT "jffs2_flush_wbuf() called with alloc_sem not locked!\n"); |
584 | BUG(); | 584 | BUG(); |
585 | } | 585 | } |
@@ -702,10 +702,10 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) | |||
702 | if (!c->wbuf) | 702 | if (!c->wbuf) |
703 | return 0; | 703 | return 0; |
704 | 704 | ||
705 | down(&c->alloc_sem); | 705 | mutex_lock(&c->alloc_sem); |
706 | if (!jffs2_wbuf_pending_for_ino(c, ino)) { | 706 | if (!jffs2_wbuf_pending_for_ino(c, ino)) { |
707 | D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino)); | 707 | D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino)); |
708 | up(&c->alloc_sem); | 708 | mutex_unlock(&c->alloc_sem); |
709 | return 0; | 709 | return 0; |
710 | } | 710 | } |
711 | 711 | ||
@@ -725,14 +725,14 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) | |||
725 | } else while (old_wbuf_len && | 725 | } else while (old_wbuf_len && |
726 | old_wbuf_ofs == c->wbuf_ofs) { | 726 | old_wbuf_ofs == c->wbuf_ofs) { |
727 | 727 | ||
728 | up(&c->alloc_sem); | 728 | mutex_unlock(&c->alloc_sem); |
729 | 729 | ||
730 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() calls gc pass\n")); | 730 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() calls gc pass\n")); |
731 | 731 | ||
732 | ret = jffs2_garbage_collect_pass(c); | 732 | ret = jffs2_garbage_collect_pass(c); |
733 | if (ret) { | 733 | if (ret) { |
734 | /* GC failed. Flush it with padding instead */ | 734 | /* GC failed. Flush it with padding instead */ |
735 | down(&c->alloc_sem); | 735 | mutex_lock(&c->alloc_sem); |
736 | down_write(&c->wbuf_sem); | 736 | down_write(&c->wbuf_sem); |
737 | ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); | 737 | ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); |
738 | /* retry flushing wbuf in case jffs2_wbuf_recover | 738 | /* retry flushing wbuf in case jffs2_wbuf_recover |
@@ -742,12 +742,12 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) | |||
742 | up_write(&c->wbuf_sem); | 742 | up_write(&c->wbuf_sem); |
743 | break; | 743 | break; |
744 | } | 744 | } |
745 | down(&c->alloc_sem); | 745 | mutex_lock(&c->alloc_sem); |
746 | } | 746 | } |
747 | 747 | ||
748 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() ends...\n")); | 748 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() ends...\n")); |
749 | 749 | ||
750 | up(&c->alloc_sem); | 750 | mutex_unlock(&c->alloc_sem); |
751 | return ret; | 751 | return ret; |
752 | } | 752 | } |
753 | 753 | ||
@@ -1236,12 +1236,24 @@ int jffs2_dataflash_setup(struct jffs2_sb_info *c) { | |||
1236 | if (!c->wbuf) | 1236 | if (!c->wbuf) |
1237 | return -ENOMEM; | 1237 | return -ENOMEM; |
1238 | 1238 | ||
1239 | #ifdef CONFIG_JFFS2_FS_WBUF_VERIFY | ||
1240 | c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL); | ||
1241 | if (!c->wbuf_verify) { | ||
1242 | kfree(c->oobbuf); | ||
1243 | kfree(c->wbuf); | ||
1244 | return -ENOMEM; | ||
1245 | } | ||
1246 | #endif | ||
1247 | |||
1239 | printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size); | 1248 | printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size); |
1240 | 1249 | ||
1241 | return 0; | 1250 | return 0; |
1242 | } | 1251 | } |
1243 | 1252 | ||
1244 | void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) { | 1253 | void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) { |
1254 | #ifdef CONFIG_JFFS2_FS_WBUF_VERIFY | ||
1255 | kfree(c->wbuf_verify); | ||
1256 | #endif | ||
1245 | kfree(c->wbuf); | 1257 | kfree(c->wbuf); |
1246 | } | 1258 | } |
1247 | 1259 | ||
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 776f13cbf2b5..665fce9797d3 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c | |||
@@ -137,12 +137,12 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 | |||
137 | JFFS2_SUMMARY_INODE_SIZE); | 137 | JFFS2_SUMMARY_INODE_SIZE); |
138 | } else { | 138 | } else { |
139 | /* Locking pain */ | 139 | /* Locking pain */ |
140 | up(&f->sem); | 140 | mutex_unlock(&f->sem); |
141 | jffs2_complete_reservation(c); | 141 | jffs2_complete_reservation(c); |
142 | 142 | ||
143 | ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &dummy, | 143 | ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &dummy, |
144 | alloc_mode, JFFS2_SUMMARY_INODE_SIZE); | 144 | alloc_mode, JFFS2_SUMMARY_INODE_SIZE); |
145 | down(&f->sem); | 145 | mutex_lock(&f->sem); |
146 | } | 146 | } |
147 | 147 | ||
148 | if (!ret) { | 148 | if (!ret) { |
@@ -285,12 +285,12 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff | |||
285 | JFFS2_SUMMARY_DIRENT_SIZE(namelen)); | 285 | JFFS2_SUMMARY_DIRENT_SIZE(namelen)); |
286 | } else { | 286 | } else { |
287 | /* Locking pain */ | 287 | /* Locking pain */ |
288 | up(&f->sem); | 288 | mutex_unlock(&f->sem); |
289 | jffs2_complete_reservation(c); | 289 | jffs2_complete_reservation(c); |
290 | 290 | ||
291 | ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &dummy, | 291 | ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &dummy, |
292 | alloc_mode, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); | 292 | alloc_mode, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); |
293 | down(&f->sem); | 293 | mutex_lock(&f->sem); |
294 | } | 294 | } |
295 | 295 | ||
296 | if (!ret) { | 296 | if (!ret) { |
@@ -353,7 +353,7 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
353 | D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret)); | 353 | D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret)); |
354 | break; | 354 | break; |
355 | } | 355 | } |
356 | down(&f->sem); | 356 | mutex_lock(&f->sem); |
357 | datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1))); | 357 | datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1))); |
358 | cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen); | 358 | cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen); |
359 | 359 | ||
@@ -381,7 +381,7 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
381 | 381 | ||
382 | if (IS_ERR(fn)) { | 382 | if (IS_ERR(fn)) { |
383 | ret = PTR_ERR(fn); | 383 | ret = PTR_ERR(fn); |
384 | up(&f->sem); | 384 | mutex_unlock(&f->sem); |
385 | jffs2_complete_reservation(c); | 385 | jffs2_complete_reservation(c); |
386 | if (!retried) { | 386 | if (!retried) { |
387 | /* Write error to be retried */ | 387 | /* Write error to be retried */ |
@@ -403,11 +403,11 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
403 | jffs2_mark_node_obsolete(c, fn->raw); | 403 | jffs2_mark_node_obsolete(c, fn->raw); |
404 | jffs2_free_full_dnode(fn); | 404 | jffs2_free_full_dnode(fn); |
405 | 405 | ||
406 | up(&f->sem); | 406 | mutex_unlock(&f->sem); |
407 | jffs2_complete_reservation(c); | 407 | jffs2_complete_reservation(c); |
408 | break; | 408 | break; |
409 | } | 409 | } |
410 | up(&f->sem); | 410 | mutex_unlock(&f->sem); |
411 | jffs2_complete_reservation(c); | 411 | jffs2_complete_reservation(c); |
412 | if (!datalen) { | 412 | if (!datalen) { |
413 | printk(KERN_WARNING "Eep. We didn't actually write any data in jffs2_write_inode_range()\n"); | 413 | printk(KERN_WARNING "Eep. We didn't actually write any data in jffs2_write_inode_range()\n"); |
@@ -439,7 +439,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str | |||
439 | JFFS2_SUMMARY_INODE_SIZE); | 439 | JFFS2_SUMMARY_INODE_SIZE); |
440 | D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen)); | 440 | D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen)); |
441 | if (ret) { | 441 | if (ret) { |
442 | up(&f->sem); | 442 | mutex_unlock(&f->sem); |
443 | return ret; | 443 | return ret; |
444 | } | 444 | } |
445 | 445 | ||
@@ -454,7 +454,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str | |||
454 | if (IS_ERR(fn)) { | 454 | if (IS_ERR(fn)) { |
455 | D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n")); | 455 | D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n")); |
456 | /* Eeek. Wave bye bye */ | 456 | /* Eeek. Wave bye bye */ |
457 | up(&f->sem); | 457 | mutex_unlock(&f->sem); |
458 | jffs2_complete_reservation(c); | 458 | jffs2_complete_reservation(c); |
459 | return PTR_ERR(fn); | 459 | return PTR_ERR(fn); |
460 | } | 460 | } |
@@ -463,7 +463,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str | |||
463 | */ | 463 | */ |
464 | f->metadata = fn; | 464 | f->metadata = fn; |
465 | 465 | ||
466 | up(&f->sem); | 466 | mutex_unlock(&f->sem); |
467 | jffs2_complete_reservation(c); | 467 | jffs2_complete_reservation(c); |
468 | 468 | ||
469 | ret = jffs2_init_security(&f->vfs_inode, &dir_f->vfs_inode); | 469 | ret = jffs2_init_security(&f->vfs_inode, &dir_f->vfs_inode); |
@@ -489,7 +489,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str | |||
489 | return -ENOMEM; | 489 | return -ENOMEM; |
490 | } | 490 | } |
491 | 491 | ||
492 | down(&dir_f->sem); | 492 | mutex_lock(&dir_f->sem); |
493 | 493 | ||
494 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 494 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
495 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); | 495 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); |
@@ -513,7 +513,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str | |||
513 | /* dirent failed to write. Delete the inode normally | 513 | /* dirent failed to write. Delete the inode normally |
514 | as if it were the final unlink() */ | 514 | as if it were the final unlink() */ |
515 | jffs2_complete_reservation(c); | 515 | jffs2_complete_reservation(c); |
516 | up(&dir_f->sem); | 516 | mutex_unlock(&dir_f->sem); |
517 | return PTR_ERR(fd); | 517 | return PTR_ERR(fd); |
518 | } | 518 | } |
519 | 519 | ||
@@ -522,7 +522,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str | |||
522 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); | 522 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); |
523 | 523 | ||
524 | jffs2_complete_reservation(c); | 524 | jffs2_complete_reservation(c); |
525 | up(&dir_f->sem); | 525 | mutex_unlock(&dir_f->sem); |
526 | 526 | ||
527 | return 0; | 527 | return 0; |
528 | } | 528 | } |
@@ -551,7 +551,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
551 | return ret; | 551 | return ret; |
552 | } | 552 | } |
553 | 553 | ||
554 | down(&dir_f->sem); | 554 | mutex_lock(&dir_f->sem); |
555 | 555 | ||
556 | /* Build a deletion node */ | 556 | /* Build a deletion node */ |
557 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 557 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
@@ -574,21 +574,21 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
574 | 574 | ||
575 | if (IS_ERR(fd)) { | 575 | if (IS_ERR(fd)) { |
576 | jffs2_complete_reservation(c); | 576 | jffs2_complete_reservation(c); |
577 | up(&dir_f->sem); | 577 | mutex_unlock(&dir_f->sem); |
578 | return PTR_ERR(fd); | 578 | return PTR_ERR(fd); |
579 | } | 579 | } |
580 | 580 | ||
581 | /* File it. This will mark the old one obsolete. */ | 581 | /* File it. This will mark the old one obsolete. */ |
582 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); | 582 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); |
583 | up(&dir_f->sem); | 583 | mutex_unlock(&dir_f->sem); |
584 | } else { | 584 | } else { |
585 | struct jffs2_full_dirent *fd = dir_f->dents; | ||
586 | uint32_t nhash = full_name_hash(name, namelen); | 585 | uint32_t nhash = full_name_hash(name, namelen); |
587 | 586 | ||
587 | fd = dir_f->dents; | ||
588 | /* We don't actually want to reserve any space, but we do | 588 | /* We don't actually want to reserve any space, but we do |
589 | want to be holding the alloc_sem when we write to flash */ | 589 | want to be holding the alloc_sem when we write to flash */ |
590 | down(&c->alloc_sem); | 590 | mutex_lock(&c->alloc_sem); |
591 | down(&dir_f->sem); | 591 | mutex_lock(&dir_f->sem); |
592 | 592 | ||
593 | for (fd = dir_f->dents; fd; fd = fd->next) { | 593 | for (fd = dir_f->dents; fd; fd = fd->next) { |
594 | if (fd->nhash == nhash && | 594 | if (fd->nhash == nhash && |
@@ -607,7 +607,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
607 | break; | 607 | break; |
608 | } | 608 | } |
609 | } | 609 | } |
610 | up(&dir_f->sem); | 610 | mutex_unlock(&dir_f->sem); |
611 | } | 611 | } |
612 | 612 | ||
613 | /* dead_f is NULL if this was a rename not a real unlink */ | 613 | /* dead_f is NULL if this was a rename not a real unlink */ |
@@ -615,7 +615,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
615 | pointing to an inode which didn't exist. */ | 615 | pointing to an inode which didn't exist. */ |
616 | if (dead_f && dead_f->inocache) { | 616 | if (dead_f && dead_f->inocache) { |
617 | 617 | ||
618 | down(&dead_f->sem); | 618 | mutex_lock(&dead_f->sem); |
619 | 619 | ||
620 | if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) { | 620 | if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) { |
621 | while (dead_f->dents) { | 621 | while (dead_f->dents) { |
@@ -639,7 +639,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
639 | 639 | ||
640 | dead_f->inocache->nlink--; | 640 | dead_f->inocache->nlink--; |
641 | /* NB: Caller must set inode nlink if appropriate */ | 641 | /* NB: Caller must set inode nlink if appropriate */ |
642 | up(&dead_f->sem); | 642 | mutex_unlock(&dead_f->sem); |
643 | } | 643 | } |
644 | 644 | ||
645 | jffs2_complete_reservation(c); | 645 | jffs2_complete_reservation(c); |
@@ -666,7 +666,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint | |||
666 | return ret; | 666 | return ret; |
667 | } | 667 | } |
668 | 668 | ||
669 | down(&dir_f->sem); | 669 | mutex_lock(&dir_f->sem); |
670 | 670 | ||
671 | /* Build a deletion node */ | 671 | /* Build a deletion node */ |
672 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 672 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
@@ -691,7 +691,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint | |||
691 | 691 | ||
692 | if (IS_ERR(fd)) { | 692 | if (IS_ERR(fd)) { |
693 | jffs2_complete_reservation(c); | 693 | jffs2_complete_reservation(c); |
694 | up(&dir_f->sem); | 694 | mutex_unlock(&dir_f->sem); |
695 | return PTR_ERR(fd); | 695 | return PTR_ERR(fd); |
696 | } | 696 | } |
697 | 697 | ||
@@ -699,7 +699,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint | |||
699 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); | 699 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); |
700 | 700 | ||
701 | jffs2_complete_reservation(c); | 701 | jffs2_complete_reservation(c); |
702 | up(&dir_f->sem); | 702 | mutex_unlock(&dir_f->sem); |
703 | 703 | ||
704 | return 0; | 704 | return 0; |
705 | } | 705 | } |
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 1f122c1940af..4d81553d2948 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
@@ -632,7 +632,7 @@ nlmsvc_update_deferred_block(struct nlm_block *block, struct file_lock *conf, | |||
632 | block->b_flags |= B_TIMED_OUT; | 632 | block->b_flags |= B_TIMED_OUT; |
633 | if (conf) { | 633 | if (conf) { |
634 | if (block->b_fl) | 634 | if (block->b_fl) |
635 | locks_copy_lock(block->b_fl, conf); | 635 | __locks_copy_lock(block->b_fl, conf); |
636 | } | 636 | } |
637 | } | 637 | } |
638 | 638 | ||
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index dbbefbcd6712..d1c48b539df8 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/lockd/lockd.h> | 18 | #include <linux/lockd/lockd.h> |
19 | #include <linux/lockd/share.h> | 19 | #include <linux/lockd/share.h> |
20 | #include <linux/lockd/sm_inter.h> | 20 | #include <linux/lockd/sm_inter.h> |
21 | #include <linux/module.h> | ||
22 | #include <linux/mount.h> | ||
21 | 23 | ||
22 | #define NLMDBG_FACILITY NLMDBG_SVCSUBS | 24 | #define NLMDBG_FACILITY NLMDBG_SVCSUBS |
23 | 25 | ||
@@ -194,6 +196,12 @@ again: | |||
194 | return 0; | 196 | return 0; |
195 | } | 197 | } |
196 | 198 | ||
199 | static int | ||
200 | nlmsvc_always_match(void *dummy1, struct nlm_host *dummy2) | ||
201 | { | ||
202 | return 1; | ||
203 | } | ||
204 | |||
197 | /* | 205 | /* |
198 | * Inspect a single file | 206 | * Inspect a single file |
199 | */ | 207 | */ |
@@ -230,7 +238,8 @@ nlm_file_inuse(struct nlm_file *file) | |||
230 | * Loop over all files in the file table. | 238 | * Loop over all files in the file table. |
231 | */ | 239 | */ |
232 | static int | 240 | static int |
233 | nlm_traverse_files(struct nlm_host *host, nlm_host_match_fn_t match) | 241 | nlm_traverse_files(void *data, nlm_host_match_fn_t match, |
242 | int (*is_failover_file)(void *data, struct nlm_file *file)) | ||
234 | { | 243 | { |
235 | struct hlist_node *pos, *next; | 244 | struct hlist_node *pos, *next; |
236 | struct nlm_file *file; | 245 | struct nlm_file *file; |
@@ -239,12 +248,14 @@ nlm_traverse_files(struct nlm_host *host, nlm_host_match_fn_t match) | |||
239 | mutex_lock(&nlm_file_mutex); | 248 | mutex_lock(&nlm_file_mutex); |
240 | for (i = 0; i < FILE_NRHASH; i++) { | 249 | for (i = 0; i < FILE_NRHASH; i++) { |
241 | hlist_for_each_entry_safe(file, pos, next, &nlm_files[i], f_list) { | 250 | hlist_for_each_entry_safe(file, pos, next, &nlm_files[i], f_list) { |
251 | if (is_failover_file && !is_failover_file(data, file)) | ||
252 | continue; | ||
242 | file->f_count++; | 253 | file->f_count++; |
243 | mutex_unlock(&nlm_file_mutex); | 254 | mutex_unlock(&nlm_file_mutex); |
244 | 255 | ||
245 | /* Traverse locks, blocks and shares of this file | 256 | /* Traverse locks, blocks and shares of this file |
246 | * and update file->f_locks count */ | 257 | * and update file->f_locks count */ |
247 | if (nlm_inspect_file(host, file, match)) | 258 | if (nlm_inspect_file(data, file, match)) |
248 | ret = 1; | 259 | ret = 1; |
249 | 260 | ||
250 | mutex_lock(&nlm_file_mutex); | 261 | mutex_lock(&nlm_file_mutex); |
@@ -303,21 +314,27 @@ nlm_release_file(struct nlm_file *file) | |||
303 | * Used by nlmsvc_invalidate_all | 314 | * Used by nlmsvc_invalidate_all |
304 | */ | 315 | */ |
305 | static int | 316 | static int |
306 | nlmsvc_mark_host(struct nlm_host *host, struct nlm_host *dummy) | 317 | nlmsvc_mark_host(void *data, struct nlm_host *dummy) |
307 | { | 318 | { |
319 | struct nlm_host *host = data; | ||
320 | |||
308 | host->h_inuse = 1; | 321 | host->h_inuse = 1; |
309 | return 0; | 322 | return 0; |
310 | } | 323 | } |
311 | 324 | ||
312 | static int | 325 | static int |
313 | nlmsvc_same_host(struct nlm_host *host, struct nlm_host *other) | 326 | nlmsvc_same_host(void *data, struct nlm_host *other) |
314 | { | 327 | { |
328 | struct nlm_host *host = data; | ||
329 | |||
315 | return host == other; | 330 | return host == other; |
316 | } | 331 | } |
317 | 332 | ||
318 | static int | 333 | static int |
319 | nlmsvc_is_client(struct nlm_host *host, struct nlm_host *dummy) | 334 | nlmsvc_is_client(void *data, struct nlm_host *dummy) |
320 | { | 335 | { |
336 | struct nlm_host *host = data; | ||
337 | |||
321 | if (host->h_server) { | 338 | if (host->h_server) { |
322 | /* we are destroying locks even though the client | 339 | /* we are destroying locks even though the client |
323 | * hasn't asked us too, so don't unmonitor the | 340 | * hasn't asked us too, so don't unmonitor the |
@@ -337,7 +354,7 @@ void | |||
337 | nlmsvc_mark_resources(void) | 354 | nlmsvc_mark_resources(void) |
338 | { | 355 | { |
339 | dprintk("lockd: nlmsvc_mark_resources\n"); | 356 | dprintk("lockd: nlmsvc_mark_resources\n"); |
340 | nlm_traverse_files(NULL, nlmsvc_mark_host); | 357 | nlm_traverse_files(NULL, nlmsvc_mark_host, NULL); |
341 | } | 358 | } |
342 | 359 | ||
343 | /* | 360 | /* |
@@ -348,7 +365,7 @@ nlmsvc_free_host_resources(struct nlm_host *host) | |||
348 | { | 365 | { |
349 | dprintk("lockd: nlmsvc_free_host_resources\n"); | 366 | dprintk("lockd: nlmsvc_free_host_resources\n"); |
350 | 367 | ||
351 | if (nlm_traverse_files(host, nlmsvc_same_host)) { | 368 | if (nlm_traverse_files(host, nlmsvc_same_host, NULL)) { |
352 | printk(KERN_WARNING | 369 | printk(KERN_WARNING |
353 | "lockd: couldn't remove all locks held by %s\n", | 370 | "lockd: couldn't remove all locks held by %s\n", |
354 | host->h_name); | 371 | host->h_name); |
@@ -368,5 +385,41 @@ nlmsvc_invalidate_all(void) | |||
368 | * turn, which is about as inefficient as it gets. | 385 | * turn, which is about as inefficient as it gets. |
369 | * Now we just do it once in nlm_traverse_files. | 386 | * Now we just do it once in nlm_traverse_files. |
370 | */ | 387 | */ |
371 | nlm_traverse_files(NULL, nlmsvc_is_client); | 388 | nlm_traverse_files(NULL, nlmsvc_is_client, NULL); |
389 | } | ||
390 | |||
391 | static int | ||
392 | nlmsvc_match_sb(void *datap, struct nlm_file *file) | ||
393 | { | ||
394 | struct super_block *sb = datap; | ||
395 | |||
396 | return sb == file->f_file->f_path.mnt->mnt_sb; | ||
397 | } | ||
398 | |||
399 | int | ||
400 | nlmsvc_unlock_all_by_sb(struct super_block *sb) | ||
401 | { | ||
402 | int ret; | ||
403 | |||
404 | ret = nlm_traverse_files(sb, nlmsvc_always_match, nlmsvc_match_sb); | ||
405 | return ret ? -EIO : 0; | ||
406 | } | ||
407 | EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_sb); | ||
408 | |||
409 | static int | ||
410 | nlmsvc_match_ip(void *datap, struct nlm_host *host) | ||
411 | { | ||
412 | __be32 *server_addr = datap; | ||
413 | |||
414 | return host->h_saddr.sin_addr.s_addr == *server_addr; | ||
415 | } | ||
416 | |||
417 | int | ||
418 | nlmsvc_unlock_all_by_ip(__be32 server_addr) | ||
419 | { | ||
420 | int ret; | ||
421 | ret = nlm_traverse_files(&server_addr, nlmsvc_match_ip, NULL); | ||
422 | return ret ? -EIO : 0; | ||
423 | |||
372 | } | 424 | } |
425 | EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_ip); | ||
diff --git a/fs/locks.c b/fs/locks.c index 592faadbcec1..e1ea2fe03681 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -224,7 +224,7 @@ static void locks_copy_private(struct file_lock *new, struct file_lock *fl) | |||
224 | /* | 224 | /* |
225 | * Initialize a new lock from an existing file_lock structure. | 225 | * Initialize a new lock from an existing file_lock structure. |
226 | */ | 226 | */ |
227 | static void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl) | 227 | void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl) |
228 | { | 228 | { |
229 | new->fl_owner = fl->fl_owner; | 229 | new->fl_owner = fl->fl_owner; |
230 | new->fl_pid = fl->fl_pid; | 230 | new->fl_pid = fl->fl_pid; |
@@ -833,7 +833,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
833 | if (!posix_locks_conflict(request, fl)) | 833 | if (!posix_locks_conflict(request, fl)) |
834 | continue; | 834 | continue; |
835 | if (conflock) | 835 | if (conflock) |
836 | locks_copy_lock(conflock, fl); | 836 | __locks_copy_lock(conflock, fl); |
837 | error = -EAGAIN; | 837 | error = -EAGAIN; |
838 | if (!(request->fl_flags & FL_SLEEP)) | 838 | if (!(request->fl_flags & FL_SLEEP)) |
839 | goto out; | 839 | goto out; |
@@ -1367,18 +1367,20 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1367 | 1367 | ||
1368 | lease = *flp; | 1368 | lease = *flp; |
1369 | 1369 | ||
1370 | error = -EAGAIN; | 1370 | if (arg != F_UNLCK) { |
1371 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) | 1371 | error = -ENOMEM; |
1372 | goto out; | 1372 | new_fl = locks_alloc_lock(); |
1373 | if ((arg == F_WRLCK) | 1373 | if (new_fl == NULL) |
1374 | && ((atomic_read(&dentry->d_count) > 1) | 1374 | goto out; |
1375 | || (atomic_read(&inode->i_count) > 1))) | ||
1376 | goto out; | ||
1377 | 1375 | ||
1378 | error = -ENOMEM; | 1376 | error = -EAGAIN; |
1379 | new_fl = locks_alloc_lock(); | 1377 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) |
1380 | if (new_fl == NULL) | 1378 | goto out; |
1381 | goto out; | 1379 | if ((arg == F_WRLCK) |
1380 | && ((atomic_read(&dentry->d_count) > 1) | ||
1381 | || (atomic_read(&inode->i_count) > 1))) | ||
1382 | goto out; | ||
1383 | } | ||
1382 | 1384 | ||
1383 | /* | 1385 | /* |
1384 | * At this point, we know that if there is an exclusive | 1386 | * At this point, we know that if there is an exclusive |
@@ -1404,6 +1406,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1404 | rdlease_count++; | 1406 | rdlease_count++; |
1405 | } | 1407 | } |
1406 | 1408 | ||
1409 | error = -EAGAIN; | ||
1407 | if ((arg == F_RDLCK && (wrlease_count > 0)) || | 1410 | if ((arg == F_RDLCK && (wrlease_count > 0)) || |
1408 | (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0))) | 1411 | (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0))) |
1409 | goto out; | 1412 | goto out; |
@@ -1490,8 +1493,7 @@ EXPORT_SYMBOL_GPL(vfs_setlease); | |||
1490 | int fcntl_setlease(unsigned int fd, struct file *filp, long arg) | 1493 | int fcntl_setlease(unsigned int fd, struct file *filp, long arg) |
1491 | { | 1494 | { |
1492 | struct file_lock fl, *flp = &fl; | 1495 | struct file_lock fl, *flp = &fl; |
1493 | struct dentry *dentry = filp->f_path.dentry; | 1496 | struct inode *inode = filp->f_path.dentry->d_inode; |
1494 | struct inode *inode = dentry->d_inode; | ||
1495 | int error; | 1497 | int error; |
1496 | 1498 | ||
1497 | locks_init_lock(&fl); | 1499 | locks_init_lock(&fl); |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 55dfdd71f1b0..8799b8708188 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -2712,9 +2712,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2712 | * Note: locks.c uses the BKL to protect the inode's lock list. | 2712 | * Note: locks.c uses the BKL to protect the inode's lock list. |
2713 | */ | 2713 | */ |
2714 | 2714 | ||
2715 | /* XXX?: Just to divert the locks_release_private at the start of | ||
2716 | * locks_copy_lock: */ | ||
2717 | locks_init_lock(&conflock); | ||
2718 | err = vfs_lock_file(filp, cmd, &file_lock, &conflock); | 2715 | err = vfs_lock_file(filp, cmd, &file_lock, &conflock); |
2719 | switch (-err) { | 2716 | switch (-err) { |
2720 | case 0: /* success! */ | 2717 | case 0: /* success! */ |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 1ba7ad981935..c513bbdf2d36 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -376,20 +376,6 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia | |||
376 | goto xdr_error; | 376 | goto xdr_error; |
377 | } | 377 | } |
378 | } | 378 | } |
379 | if (bmval[1] & FATTR4_WORD1_TIME_METADATA) { | ||
380 | /* We require the high 32 bits of 'seconds' to be 0, and we ignore | ||
381 | all 32 bits of 'nseconds'. */ | ||
382 | READ_BUF(12); | ||
383 | len += 12; | ||
384 | READ32(dummy32); | ||
385 | if (dummy32) | ||
386 | return nfserr_inval; | ||
387 | READ32(iattr->ia_ctime.tv_sec); | ||
388 | READ32(iattr->ia_ctime.tv_nsec); | ||
389 | if (iattr->ia_ctime.tv_nsec >= (u32)1000000000) | ||
390 | return nfserr_inval; | ||
391 | iattr->ia_valid |= ATTR_CTIME; | ||
392 | } | ||
393 | if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) { | 379 | if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) { |
394 | READ_BUF(4); | 380 | READ_BUF(4); |
395 | len += 4; | 381 | len += 4; |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 613bcb8171a5..42f3820ee8f5 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
23 | #include <linux/pagemap.h> | 23 | #include <linux/pagemap.h> |
24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <linux/inet.h> | ||
25 | #include <linux/string.h> | 26 | #include <linux/string.h> |
26 | #include <linux/smp_lock.h> | 27 | #include <linux/smp_lock.h> |
27 | #include <linux/ctype.h> | 28 | #include <linux/ctype.h> |
@@ -35,6 +36,7 @@ | |||
35 | #include <linux/nfsd/cache.h> | 36 | #include <linux/nfsd/cache.h> |
36 | #include <linux/nfsd/xdr.h> | 37 | #include <linux/nfsd/xdr.h> |
37 | #include <linux/nfsd/syscall.h> | 38 | #include <linux/nfsd/syscall.h> |
39 | #include <linux/lockd/lockd.h> | ||
38 | 40 | ||
39 | #include <asm/uaccess.h> | 41 | #include <asm/uaccess.h> |
40 | #include <net/ipv6.h> | 42 | #include <net/ipv6.h> |
@@ -53,6 +55,8 @@ enum { | |||
53 | NFSD_Getfs, | 55 | NFSD_Getfs, |
54 | NFSD_List, | 56 | NFSD_List, |
55 | NFSD_Fh, | 57 | NFSD_Fh, |
58 | NFSD_FO_UnlockIP, | ||
59 | NFSD_FO_UnlockFS, | ||
56 | NFSD_Threads, | 60 | NFSD_Threads, |
57 | NFSD_Pool_Threads, | 61 | NFSD_Pool_Threads, |
58 | NFSD_Versions, | 62 | NFSD_Versions, |
@@ -89,6 +93,9 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size); | |||
89 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); | 93 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); |
90 | #endif | 94 | #endif |
91 | 95 | ||
96 | static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size); | ||
97 | static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size); | ||
98 | |||
92 | static ssize_t (*write_op[])(struct file *, char *, size_t) = { | 99 | static ssize_t (*write_op[])(struct file *, char *, size_t) = { |
93 | [NFSD_Svc] = write_svc, | 100 | [NFSD_Svc] = write_svc, |
94 | [NFSD_Add] = write_add, | 101 | [NFSD_Add] = write_add, |
@@ -98,6 +105,8 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = { | |||
98 | [NFSD_Getfd] = write_getfd, | 105 | [NFSD_Getfd] = write_getfd, |
99 | [NFSD_Getfs] = write_getfs, | 106 | [NFSD_Getfs] = write_getfs, |
100 | [NFSD_Fh] = write_filehandle, | 107 | [NFSD_Fh] = write_filehandle, |
108 | [NFSD_FO_UnlockIP] = failover_unlock_ip, | ||
109 | [NFSD_FO_UnlockFS] = failover_unlock_fs, | ||
101 | [NFSD_Threads] = write_threads, | 110 | [NFSD_Threads] = write_threads, |
102 | [NFSD_Pool_Threads] = write_pool_threads, | 111 | [NFSD_Pool_Threads] = write_pool_threads, |
103 | [NFSD_Versions] = write_versions, | 112 | [NFSD_Versions] = write_versions, |
@@ -298,6 +307,58 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size) | |||
298 | return err; | 307 | return err; |
299 | } | 308 | } |
300 | 309 | ||
310 | static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size) | ||
311 | { | ||
312 | __be32 server_ip; | ||
313 | char *fo_path, c; | ||
314 | int b1, b2, b3, b4; | ||
315 | |||
316 | /* sanity check */ | ||
317 | if (size == 0) | ||
318 | return -EINVAL; | ||
319 | |||
320 | if (buf[size-1] != '\n') | ||
321 | return -EINVAL; | ||
322 | |||
323 | fo_path = buf; | ||
324 | if (qword_get(&buf, fo_path, size) < 0) | ||
325 | return -EINVAL; | ||
326 | |||
327 | /* get ipv4 address */ | ||
328 | if (sscanf(fo_path, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4) | ||
329 | return -EINVAL; | ||
330 | server_ip = htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4); | ||
331 | |||
332 | return nlmsvc_unlock_all_by_ip(server_ip); | ||
333 | } | ||
334 | |||
335 | static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size) | ||
336 | { | ||
337 | struct nameidata nd; | ||
338 | char *fo_path; | ||
339 | int error; | ||
340 | |||
341 | /* sanity check */ | ||
342 | if (size == 0) | ||
343 | return -EINVAL; | ||
344 | |||
345 | if (buf[size-1] != '\n') | ||
346 | return -EINVAL; | ||
347 | |||
348 | fo_path = buf; | ||
349 | if (qword_get(&buf, fo_path, size) < 0) | ||
350 | return -EINVAL; | ||
351 | |||
352 | error = path_lookup(fo_path, 0, &nd); | ||
353 | if (error) | ||
354 | return error; | ||
355 | |||
356 | error = nlmsvc_unlock_all_by_sb(nd.path.mnt->mnt_sb); | ||
357 | |||
358 | path_put(&nd.path); | ||
359 | return error; | ||
360 | } | ||
361 | |||
301 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size) | 362 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size) |
302 | { | 363 | { |
303 | /* request is: | 364 | /* request is: |
@@ -700,6 +761,10 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) | |||
700 | [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR}, | 761 | [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR}, |
701 | [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR}, | 762 | [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR}, |
702 | [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, | 763 | [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, |
764 | [NFSD_FO_UnlockIP] = {"unlock_ip", | ||
765 | &transaction_ops, S_IWUSR|S_IRUSR}, | ||
766 | [NFSD_FO_UnlockFS] = {"unlock_filesystem", | ||
767 | &transaction_ops, S_IWUSR|S_IRUSR}, | ||
703 | [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, | 768 | [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, |
704 | [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, | 769 | [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, |
705 | [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR}, | 770 | [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR}, |
diff --git a/include/asm-arm/arch-pxa/pxa3xx_nand.h b/include/asm-arm/arch-pxa/pxa3xx_nand.h new file mode 100644 index 000000000000..81a8937486cb --- /dev/null +++ b/include/asm-arm/arch-pxa/pxa3xx_nand.h | |||
@@ -0,0 +1,18 @@ | |||
1 | #ifndef __ASM_ARCH_PXA3XX_NAND_H | ||
2 | #define __ASM_ARCH_PXA3XX_NAND_H | ||
3 | |||
4 | #include <linux/mtd/mtd.h> | ||
5 | #include <linux/mtd/partitions.h> | ||
6 | |||
7 | struct pxa3xx_nand_platform_data { | ||
8 | |||
9 | /* the data flash bus is shared between the Static Memory | ||
10 | * Controller and the Data Flash Controller, the arbiter | ||
11 | * controls the ownership of the bus | ||
12 | */ | ||
13 | int enable_arbiter; | ||
14 | |||
15 | struct mtd_partition *parts; | ||
16 | unsigned int nr_parts; | ||
17 | }; | ||
18 | #endif /* __ASM_ARCH_PXA3XX_NAND_H */ | ||
diff --git a/include/asm-arm/plat-s3c/nand.h b/include/asm-arm/plat-s3c/nand.h index 8816f7f9cee1..ad6bbe90616e 100644 --- a/include/asm-arm/plat-s3c/nand.h +++ b/include/asm-arm/plat-s3c/nand.h | |||
@@ -22,11 +22,14 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | struct s3c2410_nand_set { | 24 | struct s3c2410_nand_set { |
25 | unsigned int disable_ecc : 1; | ||
26 | |||
25 | int nr_chips; | 27 | int nr_chips; |
26 | int nr_partitions; | 28 | int nr_partitions; |
27 | char *name; | 29 | char *name; |
28 | int *nr_map; | 30 | int *nr_map; |
29 | struct mtd_partition *partitions; | 31 | struct mtd_partition *partitions; |
32 | struct nand_ecclayout *ecc_layout; | ||
30 | }; | 33 | }; |
31 | 34 | ||
32 | struct s3c2410_platform_nand { | 35 | struct s3c2410_platform_nand { |
@@ -36,6 +39,8 @@ struct s3c2410_platform_nand { | |||
36 | int twrph0; /* active time for nWE/nOE */ | 39 | int twrph0; /* active time for nWE/nOE */ |
37 | int twrph1; /* time for release CLE/ALE from nWE/nOE inactive */ | 40 | int twrph1; /* time for release CLE/ALE from nWE/nOE inactive */ |
38 | 41 | ||
42 | unsigned int ignore_unset_ecc : 1; | ||
43 | |||
39 | int nr_sets; | 44 | int nr_sets; |
40 | struct s3c2410_nand_set *sets; | 45 | struct s3c2410_nand_set *sets; |
41 | 46 | ||
diff --git a/include/asm-x86/fixmap.h b/include/asm-x86/fixmap.h index 382eb271a892..5bd206973dca 100644 --- a/include/asm-x86/fixmap.h +++ b/include/asm-x86/fixmap.h | |||
@@ -1,5 +1,13 @@ | |||
1 | #ifndef _ASM_FIXMAP_H | ||
2 | #define _ASM_FIXMAP_H | ||
3 | |||
1 | #ifdef CONFIG_X86_32 | 4 | #ifdef CONFIG_X86_32 |
2 | # include "fixmap_32.h" | 5 | # include "fixmap_32.h" |
3 | #else | 6 | #else |
4 | # include "fixmap_64.h" | 7 | # include "fixmap_64.h" |
5 | #endif | 8 | #endif |
9 | |||
10 | #define clear_fixmap(idx) \ | ||
11 | __set_fixmap(idx, 0, __pgprot(0)) | ||
12 | |||
13 | #endif | ||
diff --git a/include/asm-x86/fixmap_32.h b/include/asm-x86/fixmap_32.h index eb1665125c44..4b96148e90c1 100644 --- a/include/asm-x86/fixmap_32.h +++ b/include/asm-x86/fixmap_32.h | |||
@@ -10,8 +10,8 @@ | |||
10 | * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 | 10 | * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #ifndef _ASM_FIXMAP_H | 13 | #ifndef _ASM_FIXMAP_32_H |
14 | #define _ASM_FIXMAP_H | 14 | #define _ASM_FIXMAP_32_H |
15 | 15 | ||
16 | 16 | ||
17 | /* used by vmalloc.c, vsyscall.lds.S. | 17 | /* used by vmalloc.c, vsyscall.lds.S. |
@@ -121,9 +121,6 @@ extern void reserve_top_address(unsigned long reserve); | |||
121 | #define set_fixmap_nocache(idx, phys) \ | 121 | #define set_fixmap_nocache(idx, phys) \ |
122 | __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE) | 122 | __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE) |
123 | 123 | ||
124 | #define clear_fixmap(idx) \ | ||
125 | __set_fixmap(idx, 0, __pgprot(0)) | ||
126 | |||
127 | #define FIXADDR_TOP ((unsigned long)__FIXADDR_TOP) | 124 | #define FIXADDR_TOP ((unsigned long)__FIXADDR_TOP) |
128 | 125 | ||
129 | #define __FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT) | 126 | #define __FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT) |
diff --git a/include/asm-x86/fixmap_64.h b/include/asm-x86/fixmap_64.h index f3d76858c0e6..355d26a75a82 100644 --- a/include/asm-x86/fixmap_64.h +++ b/include/asm-x86/fixmap_64.h | |||
@@ -8,8 +8,8 @@ | |||
8 | * Copyright (C) 1998 Ingo Molnar | 8 | * Copyright (C) 1998 Ingo Molnar |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #ifndef _ASM_FIXMAP_H | 11 | #ifndef _ASM_FIXMAP_64_H |
12 | #define _ASM_FIXMAP_H | 12 | #define _ASM_FIXMAP_64_H |
13 | 13 | ||
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <asm/apicdef.h> | 15 | #include <asm/apicdef.h> |
diff --git a/include/asm-x86/paravirt.h b/include/asm-x86/paravirt.h index 3d419398499b..0f13b945e240 100644 --- a/include/asm-x86/paravirt.h +++ b/include/asm-x86/paravirt.h | |||
@@ -220,11 +220,13 @@ struct pv_mmu_ops { | |||
220 | unsigned long va); | 220 | unsigned long va); |
221 | 221 | ||
222 | /* Hooks for allocating/releasing pagetable pages */ | 222 | /* Hooks for allocating/releasing pagetable pages */ |
223 | void (*alloc_pt)(struct mm_struct *mm, u32 pfn); | 223 | void (*alloc_pte)(struct mm_struct *mm, u32 pfn); |
224 | void (*alloc_pd)(struct mm_struct *mm, u32 pfn); | 224 | void (*alloc_pmd)(struct mm_struct *mm, u32 pfn); |
225 | void (*alloc_pd_clone)(u32 pfn, u32 clonepfn, u32 start, u32 count); | 225 | void (*alloc_pmd_clone)(u32 pfn, u32 clonepfn, u32 start, u32 count); |
226 | void (*release_pt)(u32 pfn); | 226 | void (*alloc_pud)(struct mm_struct *mm, u32 pfn); |
227 | void (*release_pd)(u32 pfn); | 227 | void (*release_pte)(u32 pfn); |
228 | void (*release_pmd)(u32 pfn); | ||
229 | void (*release_pud)(u32 pfn); | ||
228 | 230 | ||
229 | /* Pagetable manipulation functions */ | 231 | /* Pagetable manipulation functions */ |
230 | void (*set_pte)(pte_t *ptep, pte_t pteval); | 232 | void (*set_pte)(pte_t *ptep, pte_t pteval); |
@@ -910,28 +912,37 @@ static inline void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, | |||
910 | PVOP_VCALL3(pv_mmu_ops.flush_tlb_others, &cpumask, mm, va); | 912 | PVOP_VCALL3(pv_mmu_ops.flush_tlb_others, &cpumask, mm, va); |
911 | } | 913 | } |
912 | 914 | ||
913 | static inline void paravirt_alloc_pt(struct mm_struct *mm, unsigned pfn) | 915 | static inline void paravirt_alloc_pte(struct mm_struct *mm, unsigned pfn) |
914 | { | 916 | { |
915 | PVOP_VCALL2(pv_mmu_ops.alloc_pt, mm, pfn); | 917 | PVOP_VCALL2(pv_mmu_ops.alloc_pte, mm, pfn); |
916 | } | 918 | } |
917 | static inline void paravirt_release_pt(unsigned pfn) | 919 | static inline void paravirt_release_pte(unsigned pfn) |
918 | { | 920 | { |
919 | PVOP_VCALL1(pv_mmu_ops.release_pt, pfn); | 921 | PVOP_VCALL1(pv_mmu_ops.release_pte, pfn); |
920 | } | 922 | } |
921 | 923 | ||
922 | static inline void paravirt_alloc_pd(struct mm_struct *mm, unsigned pfn) | 924 | static inline void paravirt_alloc_pmd(struct mm_struct *mm, unsigned pfn) |
923 | { | 925 | { |
924 | PVOP_VCALL2(pv_mmu_ops.alloc_pd, mm, pfn); | 926 | PVOP_VCALL2(pv_mmu_ops.alloc_pmd, mm, pfn); |
925 | } | 927 | } |
926 | 928 | ||
927 | static inline void paravirt_alloc_pd_clone(unsigned pfn, unsigned clonepfn, | 929 | static inline void paravirt_alloc_pmd_clone(unsigned pfn, unsigned clonepfn, |
928 | unsigned start, unsigned count) | 930 | unsigned start, unsigned count) |
929 | { | 931 | { |
930 | PVOP_VCALL4(pv_mmu_ops.alloc_pd_clone, pfn, clonepfn, start, count); | 932 | PVOP_VCALL4(pv_mmu_ops.alloc_pmd_clone, pfn, clonepfn, start, count); |
931 | } | 933 | } |
932 | static inline void paravirt_release_pd(unsigned pfn) | 934 | static inline void paravirt_release_pmd(unsigned pfn) |
933 | { | 935 | { |
934 | PVOP_VCALL1(pv_mmu_ops.release_pd, pfn); | 936 | PVOP_VCALL1(pv_mmu_ops.release_pmd, pfn); |
937 | } | ||
938 | |||
939 | static inline void paravirt_alloc_pud(struct mm_struct *mm, unsigned pfn) | ||
940 | { | ||
941 | PVOP_VCALL2(pv_mmu_ops.alloc_pud, mm, pfn); | ||
942 | } | ||
943 | static inline void paravirt_release_pud(unsigned pfn) | ||
944 | { | ||
945 | PVOP_VCALL1(pv_mmu_ops.release_pud, pfn); | ||
935 | } | 946 | } |
936 | 947 | ||
937 | #ifdef CONFIG_HIGHPTE | 948 | #ifdef CONFIG_HIGHPTE |
diff --git a/include/asm-x86/pgalloc.h b/include/asm-x86/pgalloc.h index 5886eed05886..91e4641f3f31 100644 --- a/include/asm-x86/pgalloc.h +++ b/include/asm-x86/pgalloc.h | |||
@@ -1,5 +1,110 @@ | |||
1 | #ifdef CONFIG_X86_32 | 1 | #ifndef _ASM_X86_PGALLOC_H |
2 | # include "pgalloc_32.h" | 2 | #define _ASM_X86_PGALLOC_H |
3 | |||
4 | #include <linux/threads.h> | ||
5 | #include <linux/mm.h> /* for struct page */ | ||
6 | #include <linux/pagemap.h> | ||
7 | |||
8 | #ifdef CONFIG_PARAVIRT | ||
9 | #include <asm/paravirt.h> | ||
3 | #else | 10 | #else |
4 | # include "pgalloc_64.h" | 11 | static inline void paravirt_alloc_pte(struct mm_struct *mm, unsigned long pfn) {} |
12 | static inline void paravirt_alloc_pmd(struct mm_struct *mm, unsigned long pfn) {} | ||
13 | static inline void paravirt_alloc_pmd_clone(unsigned long pfn, unsigned long clonepfn, | ||
14 | unsigned long start, unsigned long count) {} | ||
15 | static inline void paravirt_alloc_pud(struct mm_struct *mm, unsigned long pfn) {} | ||
16 | static inline void paravirt_release_pte(unsigned long pfn) {} | ||
17 | static inline void paravirt_release_pmd(unsigned long pfn) {} | ||
18 | static inline void paravirt_release_pud(unsigned long pfn) {} | ||
5 | #endif | 19 | #endif |
20 | |||
21 | /* | ||
22 | * Allocate and free page tables. | ||
23 | */ | ||
24 | extern pgd_t *pgd_alloc(struct mm_struct *); | ||
25 | extern void pgd_free(struct mm_struct *mm, pgd_t *pgd); | ||
26 | |||
27 | extern pte_t *pte_alloc_one_kernel(struct mm_struct *, unsigned long); | ||
28 | extern pgtable_t pte_alloc_one(struct mm_struct *, unsigned long); | ||
29 | |||
30 | /* Should really implement gc for free page table pages. This could be | ||
31 | done with a reference count in struct page. */ | ||
32 | |||
33 | static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) | ||
34 | { | ||
35 | BUG_ON((unsigned long)pte & (PAGE_SIZE-1)); | ||
36 | free_page((unsigned long)pte); | ||
37 | } | ||
38 | |||
39 | static inline void pte_free(struct mm_struct *mm, struct page *pte) | ||
40 | { | ||
41 | __free_page(pte); | ||
42 | } | ||
43 | |||
44 | extern void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte); | ||
45 | |||
46 | static inline void pmd_populate_kernel(struct mm_struct *mm, | ||
47 | pmd_t *pmd, pte_t *pte) | ||
48 | { | ||
49 | paravirt_alloc_pte(mm, __pa(pte) >> PAGE_SHIFT); | ||
50 | set_pmd(pmd, __pmd(__pa(pte) | _PAGE_TABLE)); | ||
51 | } | ||
52 | |||
53 | static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, | ||
54 | struct page *pte) | ||
55 | { | ||
56 | unsigned long pfn = page_to_pfn(pte); | ||
57 | |||
58 | paravirt_alloc_pte(mm, pfn); | ||
59 | set_pmd(pmd, __pmd(((pteval_t)pfn << PAGE_SHIFT) | _PAGE_TABLE)); | ||
60 | } | ||
61 | |||
62 | #define pmd_pgtable(pmd) pmd_page(pmd) | ||
63 | |||
64 | #if PAGETABLE_LEVELS > 2 | ||
65 | static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) | ||
66 | { | ||
67 | return (pmd_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT); | ||
68 | } | ||
69 | |||
70 | static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) | ||
71 | { | ||
72 | BUG_ON((unsigned long)pmd & (PAGE_SIZE-1)); | ||
73 | free_page((unsigned long)pmd); | ||
74 | } | ||
75 | |||
76 | extern void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd); | ||
77 | |||
78 | #ifdef CONFIG_X86_PAE | ||
79 | extern void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd); | ||
80 | #else /* !CONFIG_X86_PAE */ | ||
81 | static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) | ||
82 | { | ||
83 | paravirt_alloc_pmd(mm, __pa(pmd) >> PAGE_SHIFT); | ||
84 | set_pud(pud, __pud(_PAGE_TABLE | __pa(pmd))); | ||
85 | } | ||
86 | #endif /* CONFIG_X86_PAE */ | ||
87 | |||
88 | #if PAGETABLE_LEVELS > 3 | ||
89 | static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) | ||
90 | { | ||
91 | paravirt_alloc_pud(mm, __pa(pud) >> PAGE_SHIFT); | ||
92 | set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pud))); | ||
93 | } | ||
94 | |||
95 | static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) | ||
96 | { | ||
97 | return (pud_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT); | ||
98 | } | ||
99 | |||
100 | static inline void pud_free(struct mm_struct *mm, pud_t *pud) | ||
101 | { | ||
102 | BUG_ON((unsigned long)pud & (PAGE_SIZE-1)); | ||
103 | free_page((unsigned long)pud); | ||
104 | } | ||
105 | |||
106 | extern void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pud); | ||
107 | #endif /* PAGETABLE_LEVELS > 3 */ | ||
108 | #endif /* PAGETABLE_LEVELS > 2 */ | ||
109 | |||
110 | #endif /* _ASM_X86_PGALLOC_H */ | ||
diff --git a/include/asm-x86/pgalloc_32.h b/include/asm-x86/pgalloc_32.h deleted file mode 100644 index 6bea6e5b5ee5..000000000000 --- a/include/asm-x86/pgalloc_32.h +++ /dev/null | |||
@@ -1,95 +0,0 @@ | |||
1 | #ifndef _I386_PGALLOC_H | ||
2 | #define _I386_PGALLOC_H | ||
3 | |||
4 | #include <linux/threads.h> | ||
5 | #include <linux/mm.h> /* for struct page */ | ||
6 | #include <linux/pagemap.h> | ||
7 | #include <asm/tlb.h> | ||
8 | #include <asm-generic/tlb.h> | ||
9 | |||
10 | #ifdef CONFIG_PARAVIRT | ||
11 | #include <asm/paravirt.h> | ||
12 | #else | ||
13 | #define paravirt_alloc_pt(mm, pfn) do { } while (0) | ||
14 | #define paravirt_alloc_pd(mm, pfn) do { } while (0) | ||
15 | #define paravirt_alloc_pd_clone(pfn, clonepfn, start, count) do { } while (0) | ||
16 | #define paravirt_release_pt(pfn) do { } while (0) | ||
17 | #define paravirt_release_pd(pfn) do { } while (0) | ||
18 | #endif | ||
19 | |||
20 | static inline void pmd_populate_kernel(struct mm_struct *mm, | ||
21 | pmd_t *pmd, pte_t *pte) | ||
22 | { | ||
23 | paravirt_alloc_pt(mm, __pa(pte) >> PAGE_SHIFT); | ||
24 | set_pmd(pmd, __pmd(__pa(pte) | _PAGE_TABLE)); | ||
25 | } | ||
26 | |||
27 | static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *pte) | ||
28 | { | ||
29 | unsigned long pfn = page_to_pfn(pte); | ||
30 | |||
31 | paravirt_alloc_pt(mm, pfn); | ||
32 | set_pmd(pmd, __pmd(((pteval_t)pfn << PAGE_SHIFT) | _PAGE_TABLE)); | ||
33 | } | ||
34 | #define pmd_pgtable(pmd) pmd_page(pmd) | ||
35 | |||
36 | /* | ||
37 | * Allocate and free page tables. | ||
38 | */ | ||
39 | extern pgd_t *pgd_alloc(struct mm_struct *); | ||
40 | extern void pgd_free(struct mm_struct *mm, pgd_t *pgd); | ||
41 | |||
42 | extern pte_t *pte_alloc_one_kernel(struct mm_struct *, unsigned long); | ||
43 | extern pgtable_t pte_alloc_one(struct mm_struct *, unsigned long); | ||
44 | |||
45 | static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) | ||
46 | { | ||
47 | free_page((unsigned long)pte); | ||
48 | } | ||
49 | |||
50 | static inline void pte_free(struct mm_struct *mm, pgtable_t pte) | ||
51 | { | ||
52 | pgtable_page_dtor(pte); | ||
53 | __free_page(pte); | ||
54 | } | ||
55 | |||
56 | |||
57 | extern void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte); | ||
58 | |||
59 | #ifdef CONFIG_X86_PAE | ||
60 | /* | ||
61 | * In the PAE case we free the pmds as part of the pgd. | ||
62 | */ | ||
63 | static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) | ||
64 | { | ||
65 | return (pmd_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT); | ||
66 | } | ||
67 | |||
68 | static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) | ||
69 | { | ||
70 | BUG_ON((unsigned long)pmd & (PAGE_SIZE-1)); | ||
71 | free_page((unsigned long)pmd); | ||
72 | } | ||
73 | |||
74 | extern void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd); | ||
75 | |||
76 | static inline void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd) | ||
77 | { | ||
78 | paravirt_alloc_pd(mm, __pa(pmd) >> PAGE_SHIFT); | ||
79 | |||
80 | /* Note: almost everything apart from _PAGE_PRESENT is | ||
81 | reserved at the pmd (PDPT) level. */ | ||
82 | set_pud(pudp, __pud(__pa(pmd) | _PAGE_PRESENT)); | ||
83 | |||
84 | /* | ||
85 | * According to Intel App note "TLBs, Paging-Structure Caches, | ||
86 | * and Their Invalidation", April 2007, document 317080-001, | ||
87 | * section 8.1: in PAE mode we explicitly have to flush the | ||
88 | * TLB via cr3 if the top-level pgd is changed... | ||
89 | */ | ||
90 | if (mm == current->active_mm) | ||
91 | write_cr3(read_cr3()); | ||
92 | } | ||
93 | #endif /* CONFIG_X86_PAE */ | ||
94 | |||
95 | #endif /* _I386_PGALLOC_H */ | ||
diff --git a/include/asm-x86/pgalloc_64.h b/include/asm-x86/pgalloc_64.h deleted file mode 100644 index 8d6722320dcc..000000000000 --- a/include/asm-x86/pgalloc_64.h +++ /dev/null | |||
@@ -1,133 +0,0 @@ | |||
1 | #ifndef _X86_64_PGALLOC_H | ||
2 | #define _X86_64_PGALLOC_H | ||
3 | |||
4 | #include <asm/pda.h> | ||
5 | #include <linux/threads.h> | ||
6 | #include <linux/mm.h> | ||
7 | |||
8 | #define pmd_populate_kernel(mm, pmd, pte) \ | ||
9 | set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte))) | ||
10 | #define pud_populate(mm, pud, pmd) \ | ||
11 | set_pud(pud, __pud(_PAGE_TABLE | __pa(pmd))) | ||
12 | #define pgd_populate(mm, pgd, pud) \ | ||
13 | set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pud))) | ||
14 | |||
15 | #define pmd_pgtable(pmd) pmd_page(pmd) | ||
16 | |||
17 | static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *pte) | ||
18 | { | ||
19 | set_pmd(pmd, __pmd(_PAGE_TABLE | (page_to_pfn(pte) << PAGE_SHIFT))); | ||
20 | } | ||
21 | |||
22 | static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) | ||
23 | { | ||
24 | BUG_ON((unsigned long)pmd & (PAGE_SIZE-1)); | ||
25 | free_page((unsigned long)pmd); | ||
26 | } | ||
27 | |||
28 | static inline pmd_t *pmd_alloc_one (struct mm_struct *mm, unsigned long addr) | ||
29 | { | ||
30 | return (pmd_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT); | ||
31 | } | ||
32 | |||
33 | static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) | ||
34 | { | ||
35 | return (pud_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT); | ||
36 | } | ||
37 | |||
38 | static inline void pud_free(struct mm_struct *mm, pud_t *pud) | ||
39 | { | ||
40 | BUG_ON((unsigned long)pud & (PAGE_SIZE-1)); | ||
41 | free_page((unsigned long)pud); | ||
42 | } | ||
43 | |||
44 | static inline void pgd_list_add(pgd_t *pgd) | ||
45 | { | ||
46 | struct page *page = virt_to_page(pgd); | ||
47 | unsigned long flags; | ||
48 | |||
49 | spin_lock_irqsave(&pgd_lock, flags); | ||
50 | list_add(&page->lru, &pgd_list); | ||
51 | spin_unlock_irqrestore(&pgd_lock, flags); | ||
52 | } | ||
53 | |||
54 | static inline void pgd_list_del(pgd_t *pgd) | ||
55 | { | ||
56 | struct page *page = virt_to_page(pgd); | ||
57 | unsigned long flags; | ||
58 | |||
59 | spin_lock_irqsave(&pgd_lock, flags); | ||
60 | list_del(&page->lru); | ||
61 | spin_unlock_irqrestore(&pgd_lock, flags); | ||
62 | } | ||
63 | |||
64 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) | ||
65 | { | ||
66 | unsigned boundary; | ||
67 | pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT); | ||
68 | if (!pgd) | ||
69 | return NULL; | ||
70 | pgd_list_add(pgd); | ||
71 | /* | ||
72 | * Copy kernel pointers in from init. | ||
73 | * Could keep a freelist or slab cache of those because the kernel | ||
74 | * part never changes. | ||
75 | */ | ||
76 | boundary = pgd_index(__PAGE_OFFSET); | ||
77 | memset(pgd, 0, boundary * sizeof(pgd_t)); | ||
78 | memcpy(pgd + boundary, | ||
79 | init_level4_pgt + boundary, | ||
80 | (PTRS_PER_PGD - boundary) * sizeof(pgd_t)); | ||
81 | return pgd; | ||
82 | } | ||
83 | |||
84 | static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) | ||
85 | { | ||
86 | BUG_ON((unsigned long)pgd & (PAGE_SIZE-1)); | ||
87 | pgd_list_del(pgd); | ||
88 | free_page((unsigned long)pgd); | ||
89 | } | ||
90 | |||
91 | static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) | ||
92 | { | ||
93 | return (pte_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT); | ||
94 | } | ||
95 | |||
96 | static inline pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address) | ||
97 | { | ||
98 | struct page *page; | ||
99 | void *p; | ||
100 | |||
101 | p = (void *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT); | ||
102 | if (!p) | ||
103 | return NULL; | ||
104 | page = virt_to_page(p); | ||
105 | pgtable_page_ctor(page); | ||
106 | return page; | ||
107 | } | ||
108 | |||
109 | /* Should really implement gc for free page table pages. This could be | ||
110 | done with a reference count in struct page. */ | ||
111 | |||
112 | static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) | ||
113 | { | ||
114 | BUG_ON((unsigned long)pte & (PAGE_SIZE-1)); | ||
115 | free_page((unsigned long)pte); | ||
116 | } | ||
117 | |||
118 | static inline void pte_free(struct mm_struct *mm, pgtable_t pte) | ||
119 | { | ||
120 | pgtable_page_dtor(pte); | ||
121 | __free_page(pte); | ||
122 | } | ||
123 | |||
124 | #define __pte_free_tlb(tlb,pte) \ | ||
125 | do { \ | ||
126 | pgtable_page_dtor((pte)); \ | ||
127 | tlb_remove_page((tlb), (pte)); \ | ||
128 | } while (0) | ||
129 | |||
130 | #define __pmd_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x)) | ||
131 | #define __pud_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x)) | ||
132 | |||
133 | #endif /* _X86_64_PGALLOC_H */ | ||
diff --git a/include/asm-x86/pgtable.h b/include/asm-x86/pgtable.h index f1d9f4a03f6f..b8a08bd7bd48 100644 --- a/include/asm-x86/pgtable.h +++ b/include/asm-x86/pgtable.h | |||
@@ -1,7 +1,6 @@ | |||
1 | #ifndef _ASM_X86_PGTABLE_H | 1 | #ifndef _ASM_X86_PGTABLE_H |
2 | #define _ASM_X86_PGTABLE_H | 2 | #define _ASM_X86_PGTABLE_H |
3 | 3 | ||
4 | #define USER_PTRS_PER_PGD ((TASK_SIZE-1)/PGDIR_SIZE+1) | ||
5 | #define FIRST_USER_ADDRESS 0 | 4 | #define FIRST_USER_ADDRESS 0 |
6 | 5 | ||
7 | #define _PAGE_BIT_PRESENT 0 /* is present */ | 6 | #define _PAGE_BIT_PRESENT 0 /* is present */ |
@@ -330,6 +329,9 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) | |||
330 | # include "pgtable_64.h" | 329 | # include "pgtable_64.h" |
331 | #endif | 330 | #endif |
332 | 331 | ||
332 | #define KERNEL_PGD_BOUNDARY pgd_index(PAGE_OFFSET) | ||
333 | #define KERNEL_PGD_PTRS (PTRS_PER_PGD - KERNEL_PGD_BOUNDARY) | ||
334 | |||
333 | #ifndef __ASSEMBLY__ | 335 | #ifndef __ASSEMBLY__ |
334 | 336 | ||
335 | enum { | 337 | enum { |
@@ -389,37 +391,17 @@ static inline void native_set_pte_at(struct mm_struct *mm, unsigned long addr, | |||
389 | * bit at the same time. | 391 | * bit at the same time. |
390 | */ | 392 | */ |
391 | #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS | 393 | #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS |
392 | #define ptep_set_access_flags(vma, address, ptep, entry, dirty) \ | 394 | extern int ptep_set_access_flags(struct vm_area_struct *vma, |
393 | ({ \ | 395 | unsigned long address, pte_t *ptep, |
394 | int __changed = !pte_same(*(ptep), entry); \ | 396 | pte_t entry, int dirty); |
395 | if (__changed && dirty) { \ | ||
396 | *ptep = entry; \ | ||
397 | pte_update_defer((vma)->vm_mm, (address), (ptep)); \ | ||
398 | flush_tlb_page(vma, address); \ | ||
399 | } \ | ||
400 | __changed; \ | ||
401 | }) | ||
402 | 397 | ||
403 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG | 398 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG |
404 | #define ptep_test_and_clear_young(vma, addr, ptep) ({ \ | 399 | extern int ptep_test_and_clear_young(struct vm_area_struct *vma, |
405 | int __ret = 0; \ | 400 | unsigned long addr, pte_t *ptep); |
406 | if (pte_young(*(ptep))) \ | ||
407 | __ret = test_and_clear_bit(_PAGE_BIT_ACCESSED, \ | ||
408 | &(ptep)->pte); \ | ||
409 | if (__ret) \ | ||
410 | pte_update((vma)->vm_mm, addr, ptep); \ | ||
411 | __ret; \ | ||
412 | }) | ||
413 | 401 | ||
414 | #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH | 402 | #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH |
415 | #define ptep_clear_flush_young(vma, address, ptep) \ | 403 | extern int ptep_clear_flush_young(struct vm_area_struct *vma, |
416 | ({ \ | 404 | unsigned long address, pte_t *ptep); |
417 | int __young; \ | ||
418 | __young = ptep_test_and_clear_young((vma), (address), (ptep)); \ | ||
419 | if (__young) \ | ||
420 | flush_tlb_page(vma, address); \ | ||
421 | __young; \ | ||
422 | }) | ||
423 | 405 | ||
424 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR | 406 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR |
425 | static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, | 407 | static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, |
@@ -456,6 +438,22 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, | |||
456 | pte_update(mm, addr, ptep); | 438 | pte_update(mm, addr, ptep); |
457 | } | 439 | } |
458 | 440 | ||
441 | /* | ||
442 | * clone_pgd_range(pgd_t *dst, pgd_t *src, int count); | ||
443 | * | ||
444 | * dst - pointer to pgd range anwhere on a pgd page | ||
445 | * src - "" | ||
446 | * count - the number of pgds to copy. | ||
447 | * | ||
448 | * dst and src can be on the same page, but the range must not overlap, | ||
449 | * and must not cross a page boundary. | ||
450 | */ | ||
451 | static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count) | ||
452 | { | ||
453 | memcpy(dst, src, count * sizeof(pgd_t)); | ||
454 | } | ||
455 | |||
456 | |||
459 | #include <asm-generic/pgtable.h> | 457 | #include <asm-generic/pgtable.h> |
460 | #endif /* __ASSEMBLY__ */ | 458 | #endif /* __ASSEMBLY__ */ |
461 | 459 | ||
diff --git a/include/asm-x86/pgtable_32.h b/include/asm-x86/pgtable_32.h index c4a643674458..168b6447cf18 100644 --- a/include/asm-x86/pgtable_32.h +++ b/include/asm-x86/pgtable_32.h | |||
@@ -48,9 +48,6 @@ void paging_init(void); | |||
48 | #define PGDIR_SIZE (1UL << PGDIR_SHIFT) | 48 | #define PGDIR_SIZE (1UL << PGDIR_SHIFT) |
49 | #define PGDIR_MASK (~(PGDIR_SIZE - 1)) | 49 | #define PGDIR_MASK (~(PGDIR_SIZE - 1)) |
50 | 50 | ||
51 | #define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT) | ||
52 | #define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS) | ||
53 | |||
54 | /* Just any arbitrary offset to the start of the vmalloc VM area: the | 51 | /* Just any arbitrary offset to the start of the vmalloc VM area: the |
55 | * current 8MB value just means that there will be a 8MB "hole" after the | 52 | * current 8MB value just means that there will be a 8MB "hole" after the |
56 | * physical memory until the kernel virtual memory starts. That means that | 53 | * physical memory until the kernel virtual memory starts. That means that |
@@ -109,21 +106,6 @@ extern int pmd_bad(pmd_t pmd); | |||
109 | #endif | 106 | #endif |
110 | 107 | ||
111 | /* | 108 | /* |
112 | * clone_pgd_range(pgd_t *dst, pgd_t *src, int count); | ||
113 | * | ||
114 | * dst - pointer to pgd range anwhere on a pgd page | ||
115 | * src - "" | ||
116 | * count - the number of pgds to copy. | ||
117 | * | ||
118 | * dst and src can be on the same page, but the range must not overlap, | ||
119 | * and must not cross a page boundary. | ||
120 | */ | ||
121 | static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count) | ||
122 | { | ||
123 | memcpy(dst, src, count * sizeof(pgd_t)); | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * Macro to mark a page protection value as "uncacheable". | 109 | * Macro to mark a page protection value as "uncacheable". |
128 | * On processors which do not support it, this is a no-op. | 110 | * On processors which do not support it, this is a no-op. |
129 | */ | 111 | */ |
diff --git a/include/asm-x86/pgtable_64.h b/include/asm-x86/pgtable_64.h index 9fd87d0b6477..a3bbf8766c1d 100644 --- a/include/asm-x86/pgtable_64.h +++ b/include/asm-x86/pgtable_64.h | |||
@@ -24,7 +24,7 @@ extern void paging_init(void); | |||
24 | 24 | ||
25 | #endif /* !__ASSEMBLY__ */ | 25 | #endif /* !__ASSEMBLY__ */ |
26 | 26 | ||
27 | #define SHARED_KERNEL_PMD 1 | 27 | #define SHARED_KERNEL_PMD 0 |
28 | 28 | ||
29 | /* | 29 | /* |
30 | * PGDIR_SHIFT determines what a top-level page table entry can map | 30 | * PGDIR_SHIFT determines what a top-level page table entry can map |
diff --git a/include/asm-x86/xen/events.h b/include/asm-x86/xen/events.h new file mode 100644 index 000000000000..596312a7bfc9 --- /dev/null +++ b/include/asm-x86/xen/events.h | |||
@@ -0,0 +1,22 @@ | |||
1 | #ifndef __XEN_EVENTS_H | ||
2 | #define __XEN_EVENTS_H | ||
3 | |||
4 | enum ipi_vector { | ||
5 | XEN_RESCHEDULE_VECTOR, | ||
6 | XEN_CALL_FUNCTION_VECTOR, | ||
7 | |||
8 | XEN_NR_IPIS, | ||
9 | }; | ||
10 | |||
11 | static inline int xen_irqs_disabled(struct pt_regs *regs) | ||
12 | { | ||
13 | return raw_irqs_disabled_flags(regs->flags); | ||
14 | } | ||
15 | |||
16 | static inline void xen_do_IRQ(int irq, struct pt_regs *regs) | ||
17 | { | ||
18 | regs->orig_ax = ~irq; | ||
19 | do_IRQ(regs); | ||
20 | } | ||
21 | |||
22 | #endif /* __XEN_EVENTS_H */ | ||
diff --git a/include/asm-x86/xen/grant_table.h b/include/asm-x86/xen/grant_table.h new file mode 100644 index 000000000000..2444d4593a3b --- /dev/null +++ b/include/asm-x86/xen/grant_table.h | |||
@@ -0,0 +1,7 @@ | |||
1 | #ifndef __XEN_GRANT_TABLE_H | ||
2 | #define __XEN_GRANT_TABLE_H | ||
3 | |||
4 | #define xen_alloc_vm_area(size) alloc_vm_area(size) | ||
5 | #define xen_free_vm_area(area) free_vm_area(area) | ||
6 | |||
7 | #endif /* __XEN_GRANT_TABLE_H */ | ||
diff --git a/include/asm-x86/xen/hypercall.h b/include/asm-x86/xen/hypercall.h index bc0ee7d961ca..c2ccd997ed35 100644 --- a/include/asm-x86/xen/hypercall.h +++ b/include/asm-x86/xen/hypercall.h | |||
@@ -164,6 +164,12 @@ HYPERVISOR_set_callbacks(unsigned long event_selector, | |||
164 | } | 164 | } |
165 | 165 | ||
166 | static inline int | 166 | static inline int |
167 | HYPERVISOR_callback_op(int cmd, void *arg) | ||
168 | { | ||
169 | return _hypercall2(int, callback_op, cmd, arg); | ||
170 | } | ||
171 | |||
172 | static inline int | ||
167 | HYPERVISOR_fpu_taskswitch(int set) | 173 | HYPERVISOR_fpu_taskswitch(int set) |
168 | { | 174 | { |
169 | return _hypercall1(int, fpu_taskswitch, set); | 175 | return _hypercall1(int, fpu_taskswitch, set); |
diff --git a/include/asm-x86/xen/interface.h b/include/asm-x86/xen/interface.h index 165c3968e138..6227000a1e84 100644 --- a/include/asm-x86/xen/interface.h +++ b/include/asm-x86/xen/interface.h | |||
@@ -22,6 +22,30 @@ | |||
22 | #define DEFINE_GUEST_HANDLE(name) __DEFINE_GUEST_HANDLE(name, name) | 22 | #define DEFINE_GUEST_HANDLE(name) __DEFINE_GUEST_HANDLE(name, name) |
23 | #define GUEST_HANDLE(name) __guest_handle_ ## name | 23 | #define GUEST_HANDLE(name) __guest_handle_ ## name |
24 | 24 | ||
25 | #ifdef __XEN__ | ||
26 | #if defined(__i386__) | ||
27 | #define set_xen_guest_handle(hnd, val) \ | ||
28 | do { \ | ||
29 | if (sizeof(hnd) == 8) \ | ||
30 | *(uint64_t *)&(hnd) = 0; \ | ||
31 | (hnd).p = val; \ | ||
32 | } while (0) | ||
33 | #elif defined(__x86_64__) | ||
34 | #define set_xen_guest_handle(hnd, val) do { (hnd).p = val; } while (0) | ||
35 | #endif | ||
36 | #else | ||
37 | #if defined(__i386__) | ||
38 | #define set_xen_guest_handle(hnd, val) \ | ||
39 | do { \ | ||
40 | if (sizeof(hnd) == 8) \ | ||
41 | *(uint64_t *)&(hnd) = 0; \ | ||
42 | (hnd) = val; \ | ||
43 | } while (0) | ||
44 | #elif defined(__x86_64__) | ||
45 | #define set_xen_guest_handle(hnd, val) do { (hnd) = val; } while (0) | ||
46 | #endif | ||
47 | #endif | ||
48 | |||
25 | #ifndef __ASSEMBLY__ | 49 | #ifndef __ASSEMBLY__ |
26 | /* Guest handles for primitive C types. */ | 50 | /* Guest handles for primitive C types. */ |
27 | __DEFINE_GUEST_HANDLE(uchar, unsigned char); | 51 | __DEFINE_GUEST_HANDLE(uchar, unsigned char); |
@@ -171,6 +195,10 @@ struct arch_vcpu_info { | |||
171 | unsigned long pad[5]; /* sizeof(struct vcpu_info) == 64 */ | 195 | unsigned long pad[5]; /* sizeof(struct vcpu_info) == 64 */ |
172 | }; | 196 | }; |
173 | 197 | ||
198 | struct xen_callback { | ||
199 | unsigned long cs; | ||
200 | unsigned long eip; | ||
201 | }; | ||
174 | #endif /* !__ASSEMBLY__ */ | 202 | #endif /* !__ASSEMBLY__ */ |
175 | 203 | ||
176 | /* | 204 | /* |
diff --git a/include/asm-x86/xen/page.h b/include/asm-x86/xen/page.h new file mode 100644 index 000000000000..01799305f02a --- /dev/null +++ b/include/asm-x86/xen/page.h | |||
@@ -0,0 +1,168 @@ | |||
1 | #ifndef __XEN_PAGE_H | ||
2 | #define __XEN_PAGE_H | ||
3 | |||
4 | #include <linux/pfn.h> | ||
5 | |||
6 | #include <asm/uaccess.h> | ||
7 | #include <asm/pgtable.h> | ||
8 | |||
9 | #include <xen/features.h> | ||
10 | |||
11 | /* Xen machine address */ | ||
12 | typedef struct xmaddr { | ||
13 | phys_addr_t maddr; | ||
14 | } xmaddr_t; | ||
15 | |||
16 | /* Xen pseudo-physical address */ | ||
17 | typedef struct xpaddr { | ||
18 | phys_addr_t paddr; | ||
19 | } xpaddr_t; | ||
20 | |||
21 | #define XMADDR(x) ((xmaddr_t) { .maddr = (x) }) | ||
22 | #define XPADDR(x) ((xpaddr_t) { .paddr = (x) }) | ||
23 | |||
24 | /**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/ | ||
25 | #define INVALID_P2M_ENTRY (~0UL) | ||
26 | #define FOREIGN_FRAME_BIT (1UL<<31) | ||
27 | #define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT) | ||
28 | |||
29 | extern unsigned long *phys_to_machine_mapping; | ||
30 | |||
31 | static inline unsigned long pfn_to_mfn(unsigned long pfn) | ||
32 | { | ||
33 | if (xen_feature(XENFEAT_auto_translated_physmap)) | ||
34 | return pfn; | ||
35 | |||
36 | return phys_to_machine_mapping[(unsigned int)(pfn)] & | ||
37 | ~FOREIGN_FRAME_BIT; | ||
38 | } | ||
39 | |||
40 | static inline int phys_to_machine_mapping_valid(unsigned long pfn) | ||
41 | { | ||
42 | if (xen_feature(XENFEAT_auto_translated_physmap)) | ||
43 | return 1; | ||
44 | |||
45 | return (phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY); | ||
46 | } | ||
47 | |||
48 | static inline unsigned long mfn_to_pfn(unsigned long mfn) | ||
49 | { | ||
50 | unsigned long pfn; | ||
51 | |||
52 | if (xen_feature(XENFEAT_auto_translated_physmap)) | ||
53 | return mfn; | ||
54 | |||
55 | #if 0 | ||
56 | if (unlikely((mfn >> machine_to_phys_order) != 0)) | ||
57 | return max_mapnr; | ||
58 | #endif | ||
59 | |||
60 | pfn = 0; | ||
61 | /* | ||
62 | * The array access can fail (e.g., device space beyond end of RAM). | ||
63 | * In such cases it doesn't matter what we return (we return garbage), | ||
64 | * but we must handle the fault without crashing! | ||
65 | */ | ||
66 | __get_user(pfn, &machine_to_phys_mapping[mfn]); | ||
67 | |||
68 | return pfn; | ||
69 | } | ||
70 | |||
71 | static inline xmaddr_t phys_to_machine(xpaddr_t phys) | ||
72 | { | ||
73 | unsigned offset = phys.paddr & ~PAGE_MASK; | ||
74 | return XMADDR(PFN_PHYS((u64)pfn_to_mfn(PFN_DOWN(phys.paddr))) | offset); | ||
75 | } | ||
76 | |||
77 | static inline xpaddr_t machine_to_phys(xmaddr_t machine) | ||
78 | { | ||
79 | unsigned offset = machine.maddr & ~PAGE_MASK; | ||
80 | return XPADDR(PFN_PHYS((u64)mfn_to_pfn(PFN_DOWN(machine.maddr))) | offset); | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * We detect special mappings in one of two ways: | ||
85 | * 1. If the MFN is an I/O page then Xen will set the m2p entry | ||
86 | * to be outside our maximum possible pseudophys range. | ||
87 | * 2. If the MFN belongs to a different domain then we will certainly | ||
88 | * not have MFN in our p2m table. Conversely, if the page is ours, | ||
89 | * then we'll have p2m(m2p(MFN))==MFN. | ||
90 | * If we detect a special mapping then it doesn't have a 'struct page'. | ||
91 | * We force !pfn_valid() by returning an out-of-range pointer. | ||
92 | * | ||
93 | * NB. These checks require that, for any MFN that is not in our reservation, | ||
94 | * there is no PFN such that p2m(PFN) == MFN. Otherwise we can get confused if | ||
95 | * we are foreign-mapping the MFN, and the other domain as m2p(MFN) == PFN. | ||
96 | * Yikes! Various places must poke in INVALID_P2M_ENTRY for safety. | ||
97 | * | ||
98 | * NB2. When deliberately mapping foreign pages into the p2m table, you *must* | ||
99 | * use FOREIGN_FRAME(). This will cause pte_pfn() to choke on it, as we | ||
100 | * require. In all the cases we care about, the FOREIGN_FRAME bit is | ||
101 | * masked (e.g., pfn_to_mfn()) so behaviour there is correct. | ||
102 | */ | ||
103 | static inline unsigned long mfn_to_local_pfn(unsigned long mfn) | ||
104 | { | ||
105 | extern unsigned long max_mapnr; | ||
106 | unsigned long pfn = mfn_to_pfn(mfn); | ||
107 | if ((pfn < max_mapnr) | ||
108 | && !xen_feature(XENFEAT_auto_translated_physmap) | ||
109 | && (phys_to_machine_mapping[pfn] != mfn)) | ||
110 | return max_mapnr; /* force !pfn_valid() */ | ||
111 | return pfn; | ||
112 | } | ||
113 | |||
114 | static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn) | ||
115 | { | ||
116 | if (xen_feature(XENFEAT_auto_translated_physmap)) { | ||
117 | BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY); | ||
118 | return; | ||
119 | } | ||
120 | phys_to_machine_mapping[pfn] = mfn; | ||
121 | } | ||
122 | |||
123 | /* VIRT <-> MACHINE conversion */ | ||
124 | #define virt_to_machine(v) (phys_to_machine(XPADDR(__pa(v)))) | ||
125 | #define virt_to_mfn(v) (pfn_to_mfn(PFN_DOWN(__pa(v)))) | ||
126 | #define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT)) | ||
127 | |||
128 | static inline unsigned long pte_mfn(pte_t pte) | ||
129 | { | ||
130 | return (pte.pte & ~_PAGE_NX) >> PAGE_SHIFT; | ||
131 | } | ||
132 | |||
133 | static inline pte_t mfn_pte(unsigned long page_nr, pgprot_t pgprot) | ||
134 | { | ||
135 | pte_t pte; | ||
136 | |||
137 | pte.pte = ((phys_addr_t)page_nr << PAGE_SHIFT) | | ||
138 | (pgprot_val(pgprot) & __supported_pte_mask); | ||
139 | |||
140 | return pte; | ||
141 | } | ||
142 | |||
143 | static inline pteval_t pte_val_ma(pte_t pte) | ||
144 | { | ||
145 | return pte.pte; | ||
146 | } | ||
147 | |||
148 | static inline pte_t __pte_ma(pteval_t x) | ||
149 | { | ||
150 | return (pte_t) { .pte = x }; | ||
151 | } | ||
152 | |||
153 | #ifdef CONFIG_X86_PAE | ||
154 | #define pmd_val_ma(v) ((v).pmd) | ||
155 | #define pud_val_ma(v) ((v).pgd.pgd) | ||
156 | #define __pmd_ma(x) ((pmd_t) { (x) } ) | ||
157 | #else /* !X86_PAE */ | ||
158 | #define pmd_val_ma(v) ((v).pud.pgd.pgd) | ||
159 | #endif /* CONFIG_X86_PAE */ | ||
160 | |||
161 | #define pgd_val_ma(x) ((x).pgd) | ||
162 | |||
163 | |||
164 | xmaddr_t arbitrary_virt_to_machine(unsigned long address); | ||
165 | void make_lowmem_page_readonly(void *vaddr); | ||
166 | void make_lowmem_page_readwrite(void *vaddr); | ||
167 | |||
168 | #endif /* __XEN_PAGE_H */ | ||
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index cb784579956b..ad3b787479a4 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2001 Sistina Software (UK) Limited. | 2 | * Copyright (C) 2001 Sistina Software (UK) Limited. |
3 | * Copyright (C) 2004 Red Hat, Inc. All rights reserved. | 3 | * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. |
4 | * | 4 | * |
5 | * This file is released under the LGPL. | 5 | * This file is released under the LGPL. |
6 | */ | 6 | */ |
@@ -10,6 +10,8 @@ | |||
10 | 10 | ||
11 | #ifdef __KERNEL__ | 11 | #ifdef __KERNEL__ |
12 | 12 | ||
13 | #include <linux/bio.h> | ||
14 | |||
13 | struct dm_target; | 15 | struct dm_target; |
14 | struct dm_table; | 16 | struct dm_table; |
15 | struct dm_dev; | 17 | struct dm_dev; |
@@ -250,11 +252,97 @@ void dm_table_event(struct dm_table *t); | |||
250 | */ | 252 | */ |
251 | int dm_swap_table(struct mapped_device *md, struct dm_table *t); | 253 | int dm_swap_table(struct mapped_device *md, struct dm_table *t); |
252 | 254 | ||
255 | /*----------------------------------------------------------------- | ||
256 | * Macros. | ||
257 | *---------------------------------------------------------------*/ | ||
258 | #define DM_NAME "device-mapper" | ||
259 | |||
260 | #define DMERR(f, arg...) \ | ||
261 | printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg) | ||
262 | #define DMERR_LIMIT(f, arg...) \ | ||
263 | do { \ | ||
264 | if (printk_ratelimit()) \ | ||
265 | printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " \ | ||
266 | f "\n", ## arg); \ | ||
267 | } while (0) | ||
268 | |||
269 | #define DMWARN(f, arg...) \ | ||
270 | printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg) | ||
271 | #define DMWARN_LIMIT(f, arg...) \ | ||
272 | do { \ | ||
273 | if (printk_ratelimit()) \ | ||
274 | printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " \ | ||
275 | f "\n", ## arg); \ | ||
276 | } while (0) | ||
277 | |||
278 | #define DMINFO(f, arg...) \ | ||
279 | printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg) | ||
280 | #define DMINFO_LIMIT(f, arg...) \ | ||
281 | do { \ | ||
282 | if (printk_ratelimit()) \ | ||
283 | printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f \ | ||
284 | "\n", ## arg); \ | ||
285 | } while (0) | ||
286 | |||
287 | #ifdef CONFIG_DM_DEBUG | ||
288 | # define DMDEBUG(f, arg...) \ | ||
289 | printk(KERN_DEBUG DM_NAME ": " DM_MSG_PREFIX " DEBUG: " f "\n", ## arg) | ||
290 | # define DMDEBUG_LIMIT(f, arg...) \ | ||
291 | do { \ | ||
292 | if (printk_ratelimit()) \ | ||
293 | printk(KERN_DEBUG DM_NAME ": " DM_MSG_PREFIX ": " f \ | ||
294 | "\n", ## arg); \ | ||
295 | } while (0) | ||
296 | #else | ||
297 | # define DMDEBUG(f, arg...) do {} while (0) | ||
298 | # define DMDEBUG_LIMIT(f, arg...) do {} while (0) | ||
299 | #endif | ||
300 | |||
301 | #define DMEMIT(x...) sz += ((sz >= maxlen) ? \ | ||
302 | 0 : scnprintf(result + sz, maxlen - sz, x)) | ||
303 | |||
304 | #define SECTOR_SHIFT 9 | ||
305 | |||
306 | /* | ||
307 | * Definitions of return values from target end_io function. | ||
308 | */ | ||
309 | #define DM_ENDIO_INCOMPLETE 1 | ||
310 | #define DM_ENDIO_REQUEUE 2 | ||
311 | |||
312 | /* | ||
313 | * Definitions of return values from target map function. | ||
314 | */ | ||
315 | #define DM_MAPIO_SUBMITTED 0 | ||
316 | #define DM_MAPIO_REMAPPED 1 | ||
317 | #define DM_MAPIO_REQUEUE DM_ENDIO_REQUEUE | ||
318 | |||
319 | /* | ||
320 | * Ceiling(n / sz) | ||
321 | */ | ||
322 | #define dm_div_up(n, sz) (((n) + (sz) - 1) / (sz)) | ||
323 | |||
324 | #define dm_sector_div_up(n, sz) ( \ | ||
325 | { \ | ||
326 | sector_t _r = ((n) + (sz) - 1); \ | ||
327 | sector_div(_r, (sz)); \ | ||
328 | _r; \ | ||
329 | } \ | ||
330 | ) | ||
331 | |||
253 | /* | 332 | /* |
254 | * Prepare a table for a device that will error all I/O. | 333 | * ceiling(n / size) * size |
255 | * To make it active, call dm_suspend(), dm_swap_table() then dm_resume(). | ||
256 | */ | 334 | */ |
257 | int dm_create_error_table(struct dm_table **result, struct mapped_device *md); | 335 | #define dm_round_up(n, sz) (dm_div_up((n), (sz)) * (sz)) |
336 | |||
337 | static inline sector_t to_sector(unsigned long n) | ||
338 | { | ||
339 | return (n >> SECTOR_SHIFT); | ||
340 | } | ||
341 | |||
342 | static inline unsigned long to_bytes(sector_t n) | ||
343 | { | ||
344 | return (n << SECTOR_SHIFT); | ||
345 | } | ||
258 | 346 | ||
259 | #endif /* __KERNEL__ */ | 347 | #endif /* __KERNEL__ */ |
260 | #endif /* _LINUX_DEVICE_MAPPER_H */ | 348 | #endif /* _LINUX_DEVICE_MAPPER_H */ |
diff --git a/drivers/md/dm-log.h b/include/linux/dm-dirty-log.h index 3fae87eb5963..600c5fb2daad 100644 --- a/drivers/md/dm-log.h +++ b/include/linux/dm-dirty-log.h | |||
@@ -1,52 +1,56 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2003 Sistina Software | 2 | * Copyright (C) 2003 Sistina Software |
3 | * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. | ||
4 | * | ||
5 | * Device-Mapper dirty region log. | ||
3 | * | 6 | * |
4 | * This file is released under the LGPL. | 7 | * This file is released under the LGPL. |
5 | */ | 8 | */ |
6 | 9 | ||
7 | #ifndef DM_DIRTY_LOG | 10 | #ifndef _LINUX_DM_DIRTY_LOG |
8 | #define DM_DIRTY_LOG | 11 | #define _LINUX_DM_DIRTY_LOG |
12 | |||
13 | #ifdef __KERNEL__ | ||
9 | 14 | ||
10 | #include "dm.h" | 15 | #include <linux/types.h> |
16 | #include <linux/device-mapper.h> | ||
11 | 17 | ||
12 | typedef sector_t region_t; | 18 | typedef sector_t region_t; |
13 | 19 | ||
14 | struct dirty_log_type; | 20 | struct dm_dirty_log_type; |
15 | 21 | ||
16 | struct dirty_log { | 22 | struct dm_dirty_log { |
17 | struct dirty_log_type *type; | 23 | struct dm_dirty_log_type *type; |
18 | void *context; | 24 | void *context; |
19 | }; | 25 | }; |
20 | 26 | ||
21 | struct dirty_log_type { | 27 | struct dm_dirty_log_type { |
22 | struct list_head list; | ||
23 | const char *name; | 28 | const char *name; |
24 | struct module *module; | 29 | struct module *module; |
25 | unsigned int use_count; | ||
26 | 30 | ||
27 | int (*ctr)(struct dirty_log *log, struct dm_target *ti, | 31 | int (*ctr)(struct dm_dirty_log *log, struct dm_target *ti, |
28 | unsigned int argc, char **argv); | 32 | unsigned argc, char **argv); |
29 | void (*dtr)(struct dirty_log *log); | 33 | void (*dtr)(struct dm_dirty_log *log); |
30 | 34 | ||
31 | /* | 35 | /* |
32 | * There are times when we don't want the log to touch | 36 | * There are times when we don't want the log to touch |
33 | * the disk. | 37 | * the disk. |
34 | */ | 38 | */ |
35 | int (*presuspend)(struct dirty_log *log); | 39 | int (*presuspend)(struct dm_dirty_log *log); |
36 | int (*postsuspend)(struct dirty_log *log); | 40 | int (*postsuspend)(struct dm_dirty_log *log); |
37 | int (*resume)(struct dirty_log *log); | 41 | int (*resume)(struct dm_dirty_log *log); |
38 | 42 | ||
39 | /* | 43 | /* |
40 | * Retrieves the smallest size of region that the log can | 44 | * Retrieves the smallest size of region that the log can |
41 | * deal with. | 45 | * deal with. |
42 | */ | 46 | */ |
43 | uint32_t (*get_region_size)(struct dirty_log *log); | 47 | uint32_t (*get_region_size)(struct dm_dirty_log *log); |
44 | 48 | ||
45 | /* | 49 | /* |
46 | * A predicate to say whether a region is clean or not. | 50 | * A predicate to say whether a region is clean or not. |
47 | * May block. | 51 | * May block. |
48 | */ | 52 | */ |
49 | int (*is_clean)(struct dirty_log *log, region_t region); | 53 | int (*is_clean)(struct dm_dirty_log *log, region_t region); |
50 | 54 | ||
51 | /* | 55 | /* |
52 | * Returns: 0, 1, -EWOULDBLOCK, < 0 | 56 | * Returns: 0, 1, -EWOULDBLOCK, < 0 |
@@ -59,13 +63,14 @@ struct dirty_log_type { | |||
59 | * passed to a daemon to deal with, since a daemon is | 63 | * passed to a daemon to deal with, since a daemon is |
60 | * allowed to block. | 64 | * allowed to block. |
61 | */ | 65 | */ |
62 | int (*in_sync)(struct dirty_log *log, region_t region, int can_block); | 66 | int (*in_sync)(struct dm_dirty_log *log, region_t region, |
67 | int can_block); | ||
63 | 68 | ||
64 | /* | 69 | /* |
65 | * Flush the current log state (eg, to disk). This | 70 | * Flush the current log state (eg, to disk). This |
66 | * function may block. | 71 | * function may block. |
67 | */ | 72 | */ |
68 | int (*flush)(struct dirty_log *log); | 73 | int (*flush)(struct dm_dirty_log *log); |
69 | 74 | ||
70 | /* | 75 | /* |
71 | * Mark an area as clean or dirty. These functions may | 76 | * Mark an area as clean or dirty. These functions may |
@@ -73,8 +78,8 @@ struct dirty_log_type { | |||
73 | * be extremely rare (eg, allocating another chunk of | 78 | * be extremely rare (eg, allocating another chunk of |
74 | * memory for some reason). | 79 | * memory for some reason). |
75 | */ | 80 | */ |
76 | void (*mark_region)(struct dirty_log *log, region_t region); | 81 | void (*mark_region)(struct dm_dirty_log *log, region_t region); |
77 | void (*clear_region)(struct dirty_log *log, region_t region); | 82 | void (*clear_region)(struct dm_dirty_log *log, region_t region); |
78 | 83 | ||
79 | /* | 84 | /* |
80 | * Returns: <0 (error), 0 (no region), 1 (region) | 85 | * Returns: <0 (error), 0 (no region), 1 (region) |
@@ -88,44 +93,39 @@ struct dirty_log_type { | |||
88 | * tells you if an area is synchronised, the other | 93 | * tells you if an area is synchronised, the other |
89 | * assigns recovery work. | 94 | * assigns recovery work. |
90 | */ | 95 | */ |
91 | int (*get_resync_work)(struct dirty_log *log, region_t *region); | 96 | int (*get_resync_work)(struct dm_dirty_log *log, region_t *region); |
92 | 97 | ||
93 | /* | 98 | /* |
94 | * This notifies the log that the resync status of a region | 99 | * This notifies the log that the resync status of a region |
95 | * has changed. It also clears the region from the recovering | 100 | * has changed. It also clears the region from the recovering |
96 | * list (if present). | 101 | * list (if present). |
97 | */ | 102 | */ |
98 | void (*set_region_sync)(struct dirty_log *log, | 103 | void (*set_region_sync)(struct dm_dirty_log *log, |
99 | region_t region, int in_sync); | 104 | region_t region, int in_sync); |
100 | 105 | ||
101 | /* | 106 | /* |
102 | * Returns the number of regions that are in sync. | 107 | * Returns the number of regions that are in sync. |
103 | */ | 108 | */ |
104 | region_t (*get_sync_count)(struct dirty_log *log); | 109 | region_t (*get_sync_count)(struct dm_dirty_log *log); |
105 | 110 | ||
106 | /* | 111 | /* |
107 | * Support function for mirror status requests. | 112 | * Support function for mirror status requests. |
108 | */ | 113 | */ |
109 | int (*status)(struct dirty_log *log, status_type_t status_type, | 114 | int (*status)(struct dm_dirty_log *log, status_type_t status_type, |
110 | char *result, unsigned int maxlen); | 115 | char *result, unsigned maxlen); |
111 | }; | 116 | }; |
112 | 117 | ||
113 | int dm_register_dirty_log_type(struct dirty_log_type *type); | 118 | int dm_dirty_log_type_register(struct dm_dirty_log_type *type); |
114 | int dm_unregister_dirty_log_type(struct dirty_log_type *type); | 119 | int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type); |
115 | |||
116 | 120 | ||
117 | /* | 121 | /* |
118 | * Make sure you use these two functions, rather than calling | 122 | * Make sure you use these two functions, rather than calling |
119 | * type->constructor/destructor() directly. | 123 | * type->constructor/destructor() directly. |
120 | */ | 124 | */ |
121 | struct dirty_log *dm_create_dirty_log(const char *type_name, struct dm_target *ti, | 125 | struct dm_dirty_log *dm_dirty_log_create(const char *type_name, |
122 | unsigned int argc, char **argv); | 126 | struct dm_target *ti, |
123 | void dm_destroy_dirty_log(struct dirty_log *log); | 127 | unsigned argc, char **argv); |
124 | 128 | void dm_dirty_log_destroy(struct dm_dirty_log *log); | |
125 | /* | ||
126 | * init/exit functions. | ||
127 | */ | ||
128 | int dm_dirty_log_init(void); | ||
129 | void dm_dirty_log_exit(void); | ||
130 | 129 | ||
131 | #endif | 130 | #endif /* __KERNEL__ */ |
131 | #endif /* _LINUX_DM_DIRTY_LOG_H */ | ||
diff --git a/drivers/md/dm-io.h b/include/linux/dm-io.h index f647e2cceaa6..b6bf17ee2f61 100644 --- a/drivers/md/dm-io.h +++ b/include/linux/dm-io.h | |||
@@ -1,15 +1,20 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2003 Sistina Software | 2 | * Copyright (C) 2003 Sistina Software |
3 | * Copyright (C) 2004 - 2008 Red Hat, Inc. All rights reserved. | ||
4 | * | ||
5 | * Device-Mapper low-level I/O. | ||
3 | * | 6 | * |
4 | * This file is released under the GPL. | 7 | * This file is released under the GPL. |
5 | */ | 8 | */ |
6 | 9 | ||
7 | #ifndef _DM_IO_H | 10 | #ifndef _LINUX_DM_IO_H |
8 | #define _DM_IO_H | 11 | #define _LINUX_DM_IO_H |
12 | |||
13 | #ifdef __KERNEL__ | ||
9 | 14 | ||
10 | #include "dm.h" | 15 | #include <linux/types.h> |
11 | 16 | ||
12 | struct io_region { | 17 | struct dm_io_region { |
13 | struct block_device *bdev; | 18 | struct block_device *bdev; |
14 | sector_t sector; | 19 | sector_t sector; |
15 | sector_t count; /* If this is zero the region is ignored. */ | 20 | sector_t count; /* If this is zero the region is ignored. */ |
@@ -74,6 +79,7 @@ void dm_io_client_destroy(struct dm_io_client *client); | |||
74 | * error occurred doing io to the corresponding region. | 79 | * error occurred doing io to the corresponding region. |
75 | */ | 80 | */ |
76 | int dm_io(struct dm_io_request *io_req, unsigned num_regions, | 81 | int dm_io(struct dm_io_request *io_req, unsigned num_regions, |
77 | struct io_region *region, unsigned long *sync_error_bits); | 82 | struct dm_io_region *region, unsigned long *sync_error_bits); |
78 | 83 | ||
79 | #endif | 84 | #endif /* __KERNEL__ */ |
85 | #endif /* _LINUX_DM_IO_H */ | ||
diff --git a/include/linux/dm-kcopyd.h b/include/linux/dm-kcopyd.h new file mode 100644 index 000000000000..5db216311695 --- /dev/null +++ b/include/linux/dm-kcopyd.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 - 2003 Sistina Software | ||
3 | * Copyright (C) 2004 - 2008 Red Hat, Inc. All rights reserved. | ||
4 | * | ||
5 | * kcopyd provides a simple interface for copying an area of one | ||
6 | * block-device to one or more other block-devices, either synchronous | ||
7 | * or with an asynchronous completion notification. | ||
8 | * | ||
9 | * This file is released under the GPL. | ||
10 | */ | ||
11 | |||
12 | #ifndef _LINUX_DM_KCOPYD_H | ||
13 | #define _LINUX_DM_KCOPYD_H | ||
14 | |||
15 | #ifdef __KERNEL__ | ||
16 | |||
17 | #include <linux/dm-io.h> | ||
18 | |||
19 | /* FIXME: make this configurable */ | ||
20 | #define DM_KCOPYD_MAX_REGIONS 8 | ||
21 | |||
22 | #define DM_KCOPYD_IGNORE_ERROR 1 | ||
23 | |||
24 | /* | ||
25 | * To use kcopyd you must first create a dm_kcopyd_client object. | ||
26 | */ | ||
27 | struct dm_kcopyd_client; | ||
28 | int dm_kcopyd_client_create(unsigned num_pages, | ||
29 | struct dm_kcopyd_client **result); | ||
30 | void dm_kcopyd_client_destroy(struct dm_kcopyd_client *kc); | ||
31 | |||
32 | /* | ||
33 | * Submit a copy job to kcopyd. This is built on top of the | ||
34 | * previous three fns. | ||
35 | * | ||
36 | * read_err is a boolean, | ||
37 | * write_err is a bitset, with 1 bit for each destination region | ||
38 | */ | ||
39 | typedef void (*dm_kcopyd_notify_fn)(int read_err, unsigned long write_err, | ||
40 | void *context); | ||
41 | |||
42 | int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from, | ||
43 | unsigned num_dests, struct dm_io_region *dests, | ||
44 | unsigned flags, dm_kcopyd_notify_fn fn, void *context); | ||
45 | |||
46 | #endif /* __KERNEL__ */ | ||
47 | #endif /* _LINUX_DM_KCOPYD_H */ | ||
diff --git a/include/linux/fs.h b/include/linux/fs.h index cc2be2cf7d41..6556f2f967e5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -973,6 +973,7 @@ extern int do_sync_mapping_range(struct address_space *mapping, loff_t offset, | |||
973 | /* fs/locks.c */ | 973 | /* fs/locks.c */ |
974 | extern void locks_init_lock(struct file_lock *); | 974 | extern void locks_init_lock(struct file_lock *); |
975 | extern void locks_copy_lock(struct file_lock *, struct file_lock *); | 975 | extern void locks_copy_lock(struct file_lock *, struct file_lock *); |
976 | extern void __locks_copy_lock(struct file_lock *, const struct file_lock *); | ||
976 | extern void locks_remove_posix(struct file *, fl_owner_t); | 977 | extern void locks_remove_posix(struct file *, fl_owner_t); |
977 | extern void locks_remove_flock(struct file *); | 978 | extern void locks_remove_flock(struct file *); |
978 | extern void posix_test_lock(struct file *, struct file_lock *); | 979 | extern void posix_test_lock(struct file *, struct file_lock *); |
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 94649a8da014..102d928f7206 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h | |||
@@ -194,7 +194,7 @@ void nsm_release(struct nsm_handle *); | |||
194 | * This is used in garbage collection and resource reclaim | 194 | * This is used in garbage collection and resource reclaim |
195 | * A return value != 0 means destroy the lock/block/share | 195 | * A return value != 0 means destroy the lock/block/share |
196 | */ | 196 | */ |
197 | typedef int (*nlm_host_match_fn_t)(struct nlm_host *cur, struct nlm_host *ref); | 197 | typedef int (*nlm_host_match_fn_t)(void *cur, struct nlm_host *ref); |
198 | 198 | ||
199 | /* | 199 | /* |
200 | * Server-side lock handling | 200 | * Server-side lock handling |
@@ -220,6 +220,12 @@ void nlmsvc_mark_resources(void); | |||
220 | void nlmsvc_free_host_resources(struct nlm_host *); | 220 | void nlmsvc_free_host_resources(struct nlm_host *); |
221 | void nlmsvc_invalidate_all(void); | 221 | void nlmsvc_invalidate_all(void); |
222 | 222 | ||
223 | /* | ||
224 | * Cluster failover support | ||
225 | */ | ||
226 | int nlmsvc_unlock_all_by_sb(struct super_block *sb); | ||
227 | int nlmsvc_unlock_all_by_ip(__be32 server_addr); | ||
228 | |||
223 | static inline struct inode *nlmsvc_file_inode(struct nlm_file *file) | 229 | static inline struct inode *nlmsvc_file_inode(struct nlm_file *file) |
224 | { | 230 | { |
225 | return file->f_file->f_path.dentry->d_inode; | 231 | return file->f_file->f_path.dentry->d_inode; |
diff --git a/include/linux/mtd/inftl.h b/include/linux/mtd/inftl.h index 6977780e548f..85fd041d44ad 100644 --- a/include/linux/mtd/inftl.h +++ b/include/linux/mtd/inftl.h | |||
@@ -57,6 +57,11 @@ extern char inftlmountrev[]; | |||
57 | void INFTL_dumptables(struct INFTLrecord *s); | 57 | void INFTL_dumptables(struct INFTLrecord *s); |
58 | void INFTL_dumpVUchains(struct INFTLrecord *s); | 58 | void INFTL_dumpVUchains(struct INFTLrecord *s); |
59 | 59 | ||
60 | int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, | ||
61 | size_t *retlen, uint8_t *buf); | ||
62 | int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, | ||
63 | size_t *retlen, uint8_t *buf); | ||
64 | |||
60 | #endif /* __KERNEL__ */ | 65 | #endif /* __KERNEL__ */ |
61 | 66 | ||
62 | #endif /* __MTD_INFTL_H__ */ | 67 | #endif /* __MTD_INFTL_H__ */ |
diff --git a/include/linux/mtd/nftl.h b/include/linux/mtd/nftl.h index bcf2fb3fa4a7..001eec50cac6 100644 --- a/include/linux/mtd/nftl.h +++ b/include/linux/mtd/nftl.h | |||
@@ -43,6 +43,11 @@ struct NFTLrecord { | |||
43 | int NFTL_mount(struct NFTLrecord *s); | 43 | int NFTL_mount(struct NFTLrecord *s); |
44 | int NFTL_formatblock(struct NFTLrecord *s, int block); | 44 | int NFTL_formatblock(struct NFTLrecord *s, int block); |
45 | 45 | ||
46 | int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, | ||
47 | size_t *retlen, uint8_t *buf); | ||
48 | int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, | ||
49 | size_t *retlen, uint8_t *buf); | ||
50 | |||
46 | #ifndef NFTL_MAJOR | 51 | #ifndef NFTL_MAJOR |
47 | #define NFTL_MAJOR 93 | 52 | #define NFTL_MAJOR 93 |
48 | #endif | 53 | #endif |
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h index fd0a260e070b..9aa2a9149b58 100644 --- a/include/linux/mtd/onenand.h +++ b/include/linux/mtd/onenand.h | |||
@@ -187,4 +187,7 @@ struct onenand_manufacturers { | |||
187 | char *name; | 187 | char *name; |
188 | }; | 188 | }; |
189 | 189 | ||
190 | int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, | ||
191 | struct mtd_oob_ops *ops); | ||
192 | |||
190 | #endif /* __LINUX_MTD_ONENAND_H */ | 193 | #endif /* __LINUX_MTD_ONENAND_H */ |
diff --git a/include/linux/mtd/plat-ram.h b/include/linux/mtd/plat-ram.h index 9667863bd7e3..0e37ad07bce2 100644 --- a/include/linux/mtd/plat-ram.h +++ b/include/linux/mtd/plat-ram.h | |||
@@ -21,8 +21,9 @@ | |||
21 | #define PLATRAM_RW (1) | 21 | #define PLATRAM_RW (1) |
22 | 22 | ||
23 | struct platdata_mtd_ram { | 23 | struct platdata_mtd_ram { |
24 | char *mapname; | 24 | const char *mapname; |
25 | char **probes; | 25 | const char **map_probes; |
26 | const char **probes; | ||
26 | struct mtd_partition *partitions; | 27 | struct mtd_partition *partitions; |
27 | int nr_partitions; | 28 | int nr_partitions; |
28 | int bankwidth; | 29 | int bankwidth; |
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 21ee440dd3e7..41d30c9c9de6 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h | |||
@@ -329,7 +329,7 @@ extern struct timeval nfssvc_boot; | |||
329 | (FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL ) | 329 | (FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL ) |
330 | #define NFSD_WRITEABLE_ATTRS_WORD1 \ | 330 | #define NFSD_WRITEABLE_ATTRS_WORD1 \ |
331 | (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ | 331 | (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ |
332 | | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_MODIFY_SET) | 332 | | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) |
333 | 333 | ||
334 | #endif /* CONFIG_NFSD_V4 */ | 334 | #endif /* CONFIG_NFSD_V4 */ |
335 | 335 | ||
diff --git a/include/linux/phy.h b/include/linux/phy.h index 779cbcd65f62..02df20f085fe 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h | |||
@@ -379,6 +379,18 @@ struct phy_driver { | |||
379 | }; | 379 | }; |
380 | #define to_phy_driver(d) container_of(d, struct phy_driver, driver) | 380 | #define to_phy_driver(d) container_of(d, struct phy_driver, driver) |
381 | 381 | ||
382 | #define PHY_ANY_ID "MATCH ANY PHY" | ||
383 | #define PHY_ANY_UID 0xffffffff | ||
384 | |||
385 | /* A Structure for boards to register fixups with the PHY Lib */ | ||
386 | struct phy_fixup { | ||
387 | struct list_head list; | ||
388 | char bus_id[BUS_ID_SIZE]; | ||
389 | u32 phy_uid; | ||
390 | u32 phy_uid_mask; | ||
391 | int (*run)(struct phy_device *phydev); | ||
392 | }; | ||
393 | |||
382 | int phy_read(struct phy_device *phydev, u16 regnum); | 394 | int phy_read(struct phy_device *phydev, u16 regnum); |
383 | int phy_write(struct phy_device *phydev, u16 regnum, u16 val); | 395 | int phy_write(struct phy_device *phydev, u16 regnum, u16 val); |
384 | int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id); | 396 | int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id); |
@@ -386,8 +398,8 @@ struct phy_device* get_phy_device(struct mii_bus *bus, int addr); | |||
386 | int phy_clear_interrupt(struct phy_device *phydev); | 398 | int phy_clear_interrupt(struct phy_device *phydev); |
387 | int phy_config_interrupt(struct phy_device *phydev, u32 interrupts); | 399 | int phy_config_interrupt(struct phy_device *phydev, u32 interrupts); |
388 | struct phy_device * phy_attach(struct net_device *dev, | 400 | struct phy_device * phy_attach(struct net_device *dev, |
389 | const char *phy_id, u32 flags, phy_interface_t interface); | 401 | const char *bus_id, u32 flags, phy_interface_t interface); |
390 | struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, | 402 | struct phy_device * phy_connect(struct net_device *dev, const char *bus_id, |
391 | void (*handler)(struct net_device *), u32 flags, | 403 | void (*handler)(struct net_device *), u32 flags, |
392 | phy_interface_t interface); | 404 | phy_interface_t interface); |
393 | void phy_disconnect(struct phy_device *phydev); | 405 | void phy_disconnect(struct phy_device *phydev); |
@@ -427,5 +439,13 @@ void phy_print_status(struct phy_device *phydev); | |||
427 | struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id); | 439 | struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id); |
428 | void phy_device_free(struct phy_device *phydev); | 440 | void phy_device_free(struct phy_device *phydev); |
429 | 441 | ||
442 | int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask, | ||
443 | int (*run)(struct phy_device *)); | ||
444 | int phy_register_fixup_for_id(const char *bus_id, | ||
445 | int (*run)(struct phy_device *)); | ||
446 | int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask, | ||
447 | int (*run)(struct phy_device *)); | ||
448 | int phy_scan_fixups(struct phy_device *phydev); | ||
449 | |||
430 | extern struct bus_type mdio_bus_type; | 450 | extern struct bus_type mdio_bus_type; |
431 | #endif /* __PHY_H */ | 451 | #endif /* __PHY_H */ |
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 0c82c80b277f..2ca6bae88721 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h | |||
@@ -97,10 +97,10 @@ struct xfrm_algo { | |||
97 | }; | 97 | }; |
98 | 98 | ||
99 | struct xfrm_algo_aead { | 99 | struct xfrm_algo_aead { |
100 | char alg_name[64]; | 100 | char alg_name[64]; |
101 | int alg_key_len; /* in bits */ | 101 | unsigned int alg_key_len; /* in bits */ |
102 | int alg_icv_len; /* in bits */ | 102 | unsigned int alg_icv_len; /* in bits */ |
103 | char alg_key[0]; | 103 | char alg_key[0]; |
104 | }; | 104 | }; |
105 | 105 | ||
106 | struct xfrm_stats { | 106 | struct xfrm_stats { |
diff --git a/include/mtd/Kbuild b/include/mtd/Kbuild index 4d46b3bdebd8..8eb018f96002 100644 --- a/include/mtd/Kbuild +++ b/include/mtd/Kbuild | |||
@@ -3,5 +3,4 @@ header-y += jffs2-user.h | |||
3 | header-y += mtd-abi.h | 3 | header-y += mtd-abi.h |
4 | header-y += mtd-user.h | 4 | header-y += mtd-user.h |
5 | header-y += nftl-user.h | 5 | header-y += nftl-user.h |
6 | header-y += ubi-header.h | ||
7 | header-y += ubi-user.h | 6 | header-y += ubi-user.h |
diff --git a/include/xen/balloon.h b/include/xen/balloon.h new file mode 100644 index 000000000000..fe43b0f3c86a --- /dev/null +++ b/include/xen/balloon.h | |||
@@ -0,0 +1,61 @@ | |||
1 | /****************************************************************************** | ||
2 | * balloon.h | ||
3 | * | ||
4 | * Xen balloon driver - enables returning/claiming memory to/from Xen. | ||
5 | * | ||
6 | * Copyright (c) 2003, B Dragovic | ||
7 | * Copyright (c) 2003-2004, M Williamson, K Fraser | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version 2 | ||
11 | * as published by the Free Software Foundation; or, when distributed | ||
12 | * separately from the Linux kernel or incorporated into other | ||
13 | * software packages, subject to the following license: | ||
14 | * | ||
15 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
16 | * of this source file (the "Software"), to deal in the Software without | ||
17 | * restriction, including without limitation the rights to use, copy, modify, | ||
18 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, | ||
19 | * and to permit persons to whom the Software is furnished to do so, subject to | ||
20 | * the following conditions: | ||
21 | * | ||
22 | * The above copyright notice and this permission notice shall be included in | ||
23 | * all copies or substantial portions of the Software. | ||
24 | * | ||
25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
26 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
27 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
28 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
29 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
30 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
31 | * IN THE SOFTWARE. | ||
32 | */ | ||
33 | |||
34 | #ifndef __XEN_BALLOON_H__ | ||
35 | #define __XEN_BALLOON_H__ | ||
36 | |||
37 | #include <linux/spinlock.h> | ||
38 | |||
39 | #if 0 | ||
40 | /* | ||
41 | * Inform the balloon driver that it should allow some slop for device-driver | ||
42 | * memory activities. | ||
43 | */ | ||
44 | void balloon_update_driver_allowance(long delta); | ||
45 | |||
46 | /* Allocate/free a set of empty pages in low memory (i.e., no RAM mapped). */ | ||
47 | struct page **alloc_empty_pages_and_pagevec(int nr_pages); | ||
48 | void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages); | ||
49 | |||
50 | void balloon_release_driver_page(struct page *page); | ||
51 | |||
52 | /* | ||
53 | * Prevent the balloon driver from changing the memory reservation during | ||
54 | * a driver critical region. | ||
55 | */ | ||
56 | extern spinlock_t balloon_lock; | ||
57 | #define balloon_lock(__flags) spin_lock_irqsave(&balloon_lock, __flags) | ||
58 | #define balloon_unlock(__flags) spin_unlock_irqrestore(&balloon_lock, __flags) | ||
59 | #endif | ||
60 | |||
61 | #endif /* __XEN_BALLOON_H__ */ | ||
diff --git a/include/xen/events.h b/include/xen/events.h index 2bde54d29be5..acd8e062c85f 100644 --- a/include/xen/events.h +++ b/include/xen/events.h | |||
@@ -5,13 +5,7 @@ | |||
5 | 5 | ||
6 | #include <xen/interface/event_channel.h> | 6 | #include <xen/interface/event_channel.h> |
7 | #include <asm/xen/hypercall.h> | 7 | #include <asm/xen/hypercall.h> |
8 | 8 | #include <asm/xen/events.h> | |
9 | enum ipi_vector { | ||
10 | XEN_RESCHEDULE_VECTOR, | ||
11 | XEN_CALL_FUNCTION_VECTOR, | ||
12 | |||
13 | XEN_NR_IPIS, | ||
14 | }; | ||
15 | 9 | ||
16 | int bind_evtchn_to_irq(unsigned int evtchn); | 10 | int bind_evtchn_to_irq(unsigned int evtchn); |
17 | int bind_evtchn_to_irqhandler(unsigned int evtchn, | 11 | int bind_evtchn_to_irqhandler(unsigned int evtchn, |
@@ -37,6 +31,7 @@ int bind_ipi_to_irqhandler(enum ipi_vector ipi, | |||
37 | void unbind_from_irqhandler(unsigned int irq, void *dev_id); | 31 | void unbind_from_irqhandler(unsigned int irq, void *dev_id); |
38 | 32 | ||
39 | void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector); | 33 | void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector); |
34 | int resend_irq_on_evtchn(unsigned int irq); | ||
40 | 35 | ||
41 | static inline void notify_remote_via_evtchn(int port) | 36 | static inline void notify_remote_via_evtchn(int port) |
42 | { | 37 | { |
diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h index 761c83498e03..466204846121 100644 --- a/include/xen/grant_table.h +++ b/include/xen/grant_table.h | |||
@@ -39,6 +39,7 @@ | |||
39 | 39 | ||
40 | #include <asm/xen/hypervisor.h> | 40 | #include <asm/xen/hypervisor.h> |
41 | #include <xen/interface/grant_table.h> | 41 | #include <xen/interface/grant_table.h> |
42 | #include <asm/xen/grant_table.h> | ||
42 | 43 | ||
43 | /* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */ | 44 | /* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */ |
44 | #define NR_GRANT_FRAMES 4 | 45 | #define NR_GRANT_FRAMES 4 |
@@ -102,6 +103,12 @@ void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, | |||
102 | void gnttab_grant_foreign_transfer_ref(grant_ref_t, domid_t domid, | 103 | void gnttab_grant_foreign_transfer_ref(grant_ref_t, domid_t domid, |
103 | unsigned long pfn); | 104 | unsigned long pfn); |
104 | 105 | ||
106 | int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes, | ||
107 | unsigned long max_nr_gframes, | ||
108 | struct grant_entry **__shared); | ||
109 | void arch_gnttab_unmap_shared(struct grant_entry *shared, | ||
110 | unsigned long nr_gframes); | ||
111 | |||
105 | #define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr)) | 112 | #define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr)) |
106 | 113 | ||
107 | #endif /* __ASM_GNTTAB_H__ */ | 114 | #endif /* __ASM_GNTTAB_H__ */ |
diff --git a/include/xen/interface/callback.h b/include/xen/interface/callback.h new file mode 100644 index 000000000000..4aadcba31af9 --- /dev/null +++ b/include/xen/interface/callback.h | |||
@@ -0,0 +1,102 @@ | |||
1 | /****************************************************************************** | ||
2 | * callback.h | ||
3 | * | ||
4 | * Register guest OS callbacks with Xen. | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to | ||
8 | * deal in the Software without restriction, including without limitation the | ||
9 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||
10 | * sell copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
22 | * DEALINGS IN THE SOFTWARE. | ||
23 | * | ||
24 | * Copyright (c) 2006, Ian Campbell | ||
25 | */ | ||
26 | |||
27 | #ifndef __XEN_PUBLIC_CALLBACK_H__ | ||
28 | #define __XEN_PUBLIC_CALLBACK_H__ | ||
29 | |||
30 | #include "xen.h" | ||
31 | |||
32 | /* | ||
33 | * Prototype for this hypercall is: | ||
34 | * long callback_op(int cmd, void *extra_args) | ||
35 | * @cmd == CALLBACKOP_??? (callback operation). | ||
36 | * @extra_args == Operation-specific extra arguments (NULL if none). | ||
37 | */ | ||
38 | |||
39 | /* ia64, x86: Callback for event delivery. */ | ||
40 | #define CALLBACKTYPE_event 0 | ||
41 | |||
42 | /* x86: Failsafe callback when guest state cannot be restored by Xen. */ | ||
43 | #define CALLBACKTYPE_failsafe 1 | ||
44 | |||
45 | /* x86/64 hypervisor: Syscall by 64-bit guest app ('64-on-64-on-64'). */ | ||
46 | #define CALLBACKTYPE_syscall 2 | ||
47 | |||
48 | /* | ||
49 | * x86/32 hypervisor: Only available on x86/32 when supervisor_mode_kernel | ||
50 | * feature is enabled. Do not use this callback type in new code. | ||
51 | */ | ||
52 | #define CALLBACKTYPE_sysenter_deprecated 3 | ||
53 | |||
54 | /* x86: Callback for NMI delivery. */ | ||
55 | #define CALLBACKTYPE_nmi 4 | ||
56 | |||
57 | /* | ||
58 | * x86: sysenter is only available as follows: | ||
59 | * - 32-bit hypervisor: with the supervisor_mode_kernel feature enabled | ||
60 | * - 64-bit hypervisor: 32-bit guest applications on Intel CPUs | ||
61 | * ('32-on-32-on-64', '32-on-64-on-64') | ||
62 | * [nb. also 64-bit guest applications on Intel CPUs | ||
63 | * ('64-on-64-on-64'), but syscall is preferred] | ||
64 | */ | ||
65 | #define CALLBACKTYPE_sysenter 5 | ||
66 | |||
67 | /* | ||
68 | * x86/64 hypervisor: Syscall by 32-bit guest app on AMD CPUs | ||
69 | * ('32-on-32-on-64', '32-on-64-on-64') | ||
70 | */ | ||
71 | #define CALLBACKTYPE_syscall32 7 | ||
72 | |||
73 | /* | ||
74 | * Disable event deliver during callback? This flag is ignored for event and | ||
75 | * NMI callbacks: event delivery is unconditionally disabled. | ||
76 | */ | ||
77 | #define _CALLBACKF_mask_events 0 | ||
78 | #define CALLBACKF_mask_events (1U << _CALLBACKF_mask_events) | ||
79 | |||
80 | /* | ||
81 | * Register a callback. | ||
82 | */ | ||
83 | #define CALLBACKOP_register 0 | ||
84 | struct callback_register { | ||
85 | uint16_t type; | ||
86 | uint16_t flags; | ||
87 | struct xen_callback address; | ||
88 | }; | ||
89 | |||
90 | /* | ||
91 | * Unregister a callback. | ||
92 | * | ||
93 | * Not all callbacks can be unregistered. -EINVAL will be returned if | ||
94 | * you attempt to unregister such a callback. | ||
95 | */ | ||
96 | #define CALLBACKOP_unregister 1 | ||
97 | struct callback_unregister { | ||
98 | uint16_t type; | ||
99 | uint16_t _unused; | ||
100 | }; | ||
101 | |||
102 | #endif /* __XEN_PUBLIC_CALLBACK_H__ */ | ||
diff --git a/include/xen/interface/grant_table.h b/include/xen/interface/grant_table.h index 219049802cf2..39da93c21de0 100644 --- a/include/xen/interface/grant_table.h +++ b/include/xen/interface/grant_table.h | |||
@@ -185,6 +185,7 @@ struct gnttab_map_grant_ref { | |||
185 | grant_handle_t handle; | 185 | grant_handle_t handle; |
186 | uint64_t dev_bus_addr; | 186 | uint64_t dev_bus_addr; |
187 | }; | 187 | }; |
188 | DEFINE_GUEST_HANDLE_STRUCT(gnttab_map_grant_ref); | ||
188 | 189 | ||
189 | /* | 190 | /* |
190 | * GNTTABOP_unmap_grant_ref: Destroy one or more grant-reference mappings | 191 | * GNTTABOP_unmap_grant_ref: Destroy one or more grant-reference mappings |
@@ -206,6 +207,7 @@ struct gnttab_unmap_grant_ref { | |||
206 | /* OUT parameters. */ | 207 | /* OUT parameters. */ |
207 | int16_t status; /* GNTST_* */ | 208 | int16_t status; /* GNTST_* */ |
208 | }; | 209 | }; |
210 | DEFINE_GUEST_HANDLE_STRUCT(gnttab_unmap_grant_ref); | ||
209 | 211 | ||
210 | /* | 212 | /* |
211 | * GNTTABOP_setup_table: Set up a grant table for <dom> comprising at least | 213 | * GNTTABOP_setup_table: Set up a grant table for <dom> comprising at least |
@@ -223,8 +225,9 @@ struct gnttab_setup_table { | |||
223 | uint32_t nr_frames; | 225 | uint32_t nr_frames; |
224 | /* OUT parameters. */ | 226 | /* OUT parameters. */ |
225 | int16_t status; /* GNTST_* */ | 227 | int16_t status; /* GNTST_* */ |
226 | ulong *frame_list; | 228 | GUEST_HANDLE(ulong) frame_list; |
227 | }; | 229 | }; |
230 | DEFINE_GUEST_HANDLE_STRUCT(gnttab_setup_table); | ||
228 | 231 | ||
229 | /* | 232 | /* |
230 | * GNTTABOP_dump_table: Dump the contents of the grant table to the | 233 | * GNTTABOP_dump_table: Dump the contents of the grant table to the |
@@ -237,6 +240,7 @@ struct gnttab_dump_table { | |||
237 | /* OUT parameters. */ | 240 | /* OUT parameters. */ |
238 | int16_t status; /* GNTST_* */ | 241 | int16_t status; /* GNTST_* */ |
239 | }; | 242 | }; |
243 | DEFINE_GUEST_HANDLE_STRUCT(gnttab_dump_table); | ||
240 | 244 | ||
241 | /* | 245 | /* |
242 | * GNTTABOP_transfer_grant_ref: Transfer <frame> to a foreign domain. The | 246 | * GNTTABOP_transfer_grant_ref: Transfer <frame> to a foreign domain. The |
@@ -255,7 +259,7 @@ struct gnttab_transfer { | |||
255 | /* OUT parameters. */ | 259 | /* OUT parameters. */ |
256 | int16_t status; | 260 | int16_t status; |
257 | }; | 261 | }; |
258 | 262 | DEFINE_GUEST_HANDLE_STRUCT(gnttab_transfer); | |
259 | 263 | ||
260 | /* | 264 | /* |
261 | * GNTTABOP_copy: Hypervisor based copy | 265 | * GNTTABOP_copy: Hypervisor based copy |
@@ -296,6 +300,7 @@ struct gnttab_copy { | |||
296 | /* OUT parameters. */ | 300 | /* OUT parameters. */ |
297 | int16_t status; | 301 | int16_t status; |
298 | }; | 302 | }; |
303 | DEFINE_GUEST_HANDLE_STRUCT(gnttab_copy); | ||
299 | 304 | ||
300 | /* | 305 | /* |
301 | * GNTTABOP_query_size: Query the current and maximum sizes of the shared | 306 | * GNTTABOP_query_size: Query the current and maximum sizes of the shared |
@@ -313,7 +318,7 @@ struct gnttab_query_size { | |||
313 | uint32_t max_nr_frames; | 318 | uint32_t max_nr_frames; |
314 | int16_t status; /* GNTST_* */ | 319 | int16_t status; /* GNTST_* */ |
315 | }; | 320 | }; |
316 | 321 | DEFINE_GUEST_HANDLE_STRUCT(gnttab_query_size); | |
317 | 322 | ||
318 | /* | 323 | /* |
319 | * Bitfield values for update_pin_status.flags. | 324 | * Bitfield values for update_pin_status.flags. |
diff --git a/include/xen/interface/io/fbif.h b/include/xen/interface/io/fbif.h new file mode 100644 index 000000000000..5a934dd7796d --- /dev/null +++ b/include/xen/interface/io/fbif.h | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | * fbif.h -- Xen virtual frame buffer device | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
5 | * of this software and associated documentation files (the "Software"), to | ||
6 | * deal in the Software without restriction, including without limitation the | ||
7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||
8 | * sell copies of the Software, and to permit persons to whom the Software is | ||
9 | * furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> | ||
23 | * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> | ||
24 | */ | ||
25 | |||
26 | #ifndef __XEN_PUBLIC_IO_FBIF_H__ | ||
27 | #define __XEN_PUBLIC_IO_FBIF_H__ | ||
28 | |||
29 | /* Out events (frontend -> backend) */ | ||
30 | |||
31 | /* | ||
32 | * Out events may be sent only when requested by backend, and receipt | ||
33 | * of an unknown out event is an error. | ||
34 | */ | ||
35 | |||
36 | /* Event type 1 currently not used */ | ||
37 | /* | ||
38 | * Framebuffer update notification event | ||
39 | * Capable frontend sets feature-update in xenstore. | ||
40 | * Backend requests it by setting request-update in xenstore. | ||
41 | */ | ||
42 | #define XENFB_TYPE_UPDATE 2 | ||
43 | |||
44 | struct xenfb_update { | ||
45 | uint8_t type; /* XENFB_TYPE_UPDATE */ | ||
46 | int32_t x; /* source x */ | ||
47 | int32_t y; /* source y */ | ||
48 | int32_t width; /* rect width */ | ||
49 | int32_t height; /* rect height */ | ||
50 | }; | ||
51 | |||
52 | #define XENFB_OUT_EVENT_SIZE 40 | ||
53 | |||
54 | union xenfb_out_event { | ||
55 | uint8_t type; | ||
56 | struct xenfb_update update; | ||
57 | char pad[XENFB_OUT_EVENT_SIZE]; | ||
58 | }; | ||
59 | |||
60 | /* In events (backend -> frontend) */ | ||
61 | |||
62 | /* | ||
63 | * Frontends should ignore unknown in events. | ||
64 | * No in events currently defined. | ||
65 | */ | ||
66 | |||
67 | #define XENFB_IN_EVENT_SIZE 40 | ||
68 | |||
69 | union xenfb_in_event { | ||
70 | uint8_t type; | ||
71 | char pad[XENFB_IN_EVENT_SIZE]; | ||
72 | }; | ||
73 | |||
74 | /* shared page */ | ||
75 | |||
76 | #define XENFB_IN_RING_SIZE 1024 | ||
77 | #define XENFB_IN_RING_LEN (XENFB_IN_RING_SIZE / XENFB_IN_EVENT_SIZE) | ||
78 | #define XENFB_IN_RING_OFFS 1024 | ||
79 | #define XENFB_IN_RING(page) \ | ||
80 | ((union xenfb_in_event *)((char *)(page) + XENFB_IN_RING_OFFS)) | ||
81 | #define XENFB_IN_RING_REF(page, idx) \ | ||
82 | (XENFB_IN_RING((page))[(idx) % XENFB_IN_RING_LEN]) | ||
83 | |||
84 | #define XENFB_OUT_RING_SIZE 2048 | ||
85 | #define XENFB_OUT_RING_LEN (XENFB_OUT_RING_SIZE / XENFB_OUT_EVENT_SIZE) | ||
86 | #define XENFB_OUT_RING_OFFS (XENFB_IN_RING_OFFS + XENFB_IN_RING_SIZE) | ||
87 | #define XENFB_OUT_RING(page) \ | ||
88 | ((union xenfb_out_event *)((char *)(page) + XENFB_OUT_RING_OFFS)) | ||
89 | #define XENFB_OUT_RING_REF(page, idx) \ | ||
90 | (XENFB_OUT_RING((page))[(idx) % XENFB_OUT_RING_LEN]) | ||
91 | |||
92 | struct xenfb_page { | ||
93 | uint32_t in_cons, in_prod; | ||
94 | uint32_t out_cons, out_prod; | ||
95 | |||
96 | int32_t width; /* width of the framebuffer (in pixels) */ | ||
97 | int32_t height; /* height of the framebuffer (in pixels) */ | ||
98 | uint32_t line_length; /* length of a row of pixels (in bytes) */ | ||
99 | uint32_t mem_length; /* length of the framebuffer (in bytes) */ | ||
100 | uint8_t depth; /* depth of a pixel (in bits) */ | ||
101 | |||
102 | /* | ||
103 | * Framebuffer page directory | ||
104 | * | ||
105 | * Each directory page holds PAGE_SIZE / sizeof(*pd) | ||
106 | * framebuffer pages, and can thus map up to PAGE_SIZE * | ||
107 | * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and | ||
108 | * sizeof(unsigned long) == 4, that's 4 Megs. Two directory | ||
109 | * pages should be enough for a while. | ||
110 | */ | ||
111 | unsigned long pd[2]; | ||
112 | }; | ||
113 | |||
114 | /* | ||
115 | * Wart: xenkbd needs to know resolution. Put it here until a better | ||
116 | * solution is found, but don't leak it to the backend. | ||
117 | */ | ||
118 | #ifdef __KERNEL__ | ||
119 | #define XENFB_WIDTH 800 | ||
120 | #define XENFB_HEIGHT 600 | ||
121 | #define XENFB_DEPTH 32 | ||
122 | #endif | ||
123 | |||
124 | #endif | ||
diff --git a/include/xen/interface/io/kbdif.h b/include/xen/interface/io/kbdif.h new file mode 100644 index 000000000000..fb97f4284ffd --- /dev/null +++ b/include/xen/interface/io/kbdif.h | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * kbdif.h -- Xen virtual keyboard/mouse | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
5 | * of this software and associated documentation files (the "Software"), to | ||
6 | * deal in the Software without restriction, including without limitation the | ||
7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||
8 | * sell copies of the Software, and to permit persons to whom the Software is | ||
9 | * furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> | ||
23 | * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> | ||
24 | */ | ||
25 | |||
26 | #ifndef __XEN_PUBLIC_IO_KBDIF_H__ | ||
27 | #define __XEN_PUBLIC_IO_KBDIF_H__ | ||
28 | |||
29 | /* In events (backend -> frontend) */ | ||
30 | |||
31 | /* | ||
32 | * Frontends should ignore unknown in events. | ||
33 | */ | ||
34 | |||
35 | /* Pointer movement event */ | ||
36 | #define XENKBD_TYPE_MOTION 1 | ||
37 | /* Event type 2 currently not used */ | ||
38 | /* Key event (includes pointer buttons) */ | ||
39 | #define XENKBD_TYPE_KEY 3 | ||
40 | /* | ||
41 | * Pointer position event | ||
42 | * Capable backend sets feature-abs-pointer in xenstore. | ||
43 | * Frontend requests ot instead of XENKBD_TYPE_MOTION by setting | ||
44 | * request-abs-update in xenstore. | ||
45 | */ | ||
46 | #define XENKBD_TYPE_POS 4 | ||
47 | |||
48 | struct xenkbd_motion { | ||
49 | uint8_t type; /* XENKBD_TYPE_MOTION */ | ||
50 | int32_t rel_x; /* relative X motion */ | ||
51 | int32_t rel_y; /* relative Y motion */ | ||
52 | }; | ||
53 | |||
54 | struct xenkbd_key { | ||
55 | uint8_t type; /* XENKBD_TYPE_KEY */ | ||
56 | uint8_t pressed; /* 1 if pressed; 0 otherwise */ | ||
57 | uint32_t keycode; /* KEY_* from linux/input.h */ | ||
58 | }; | ||
59 | |||
60 | struct xenkbd_position { | ||
61 | uint8_t type; /* XENKBD_TYPE_POS */ | ||
62 | int32_t abs_x; /* absolute X position (in FB pixels) */ | ||
63 | int32_t abs_y; /* absolute Y position (in FB pixels) */ | ||
64 | }; | ||
65 | |||
66 | #define XENKBD_IN_EVENT_SIZE 40 | ||
67 | |||
68 | union xenkbd_in_event { | ||
69 | uint8_t type; | ||
70 | struct xenkbd_motion motion; | ||
71 | struct xenkbd_key key; | ||
72 | struct xenkbd_position pos; | ||
73 | char pad[XENKBD_IN_EVENT_SIZE]; | ||
74 | }; | ||
75 | |||
76 | /* Out events (frontend -> backend) */ | ||
77 | |||
78 | /* | ||
79 | * Out events may be sent only when requested by backend, and receipt | ||
80 | * of an unknown out event is an error. | ||
81 | * No out events currently defined. | ||
82 | */ | ||
83 | |||
84 | #define XENKBD_OUT_EVENT_SIZE 40 | ||
85 | |||
86 | union xenkbd_out_event { | ||
87 | uint8_t type; | ||
88 | char pad[XENKBD_OUT_EVENT_SIZE]; | ||
89 | }; | ||
90 | |||
91 | /* shared page */ | ||
92 | |||
93 | #define XENKBD_IN_RING_SIZE 2048 | ||
94 | #define XENKBD_IN_RING_LEN (XENKBD_IN_RING_SIZE / XENKBD_IN_EVENT_SIZE) | ||
95 | #define XENKBD_IN_RING_OFFS 1024 | ||
96 | #define XENKBD_IN_RING(page) \ | ||
97 | ((union xenkbd_in_event *)((char *)(page) + XENKBD_IN_RING_OFFS)) | ||
98 | #define XENKBD_IN_RING_REF(page, idx) \ | ||
99 | (XENKBD_IN_RING((page))[(idx) % XENKBD_IN_RING_LEN]) | ||
100 | |||
101 | #define XENKBD_OUT_RING_SIZE 1024 | ||
102 | #define XENKBD_OUT_RING_LEN (XENKBD_OUT_RING_SIZE / XENKBD_OUT_EVENT_SIZE) | ||
103 | #define XENKBD_OUT_RING_OFFS (XENKBD_IN_RING_OFFS + XENKBD_IN_RING_SIZE) | ||
104 | #define XENKBD_OUT_RING(page) \ | ||
105 | ((union xenkbd_out_event *)((char *)(page) + XENKBD_OUT_RING_OFFS)) | ||
106 | #define XENKBD_OUT_RING_REF(page, idx) \ | ||
107 | (XENKBD_OUT_RING((page))[(idx) % XENKBD_OUT_RING_LEN]) | ||
108 | |||
109 | struct xenkbd_page { | ||
110 | uint32_t in_cons, in_prod; | ||
111 | uint32_t out_cons, out_prod; | ||
112 | }; | ||
113 | |||
114 | #endif | ||
diff --git a/include/xen/interface/io/protocols.h b/include/xen/interface/io/protocols.h new file mode 100644 index 000000000000..01fc8ae5f0b0 --- /dev/null +++ b/include/xen/interface/io/protocols.h | |||
@@ -0,0 +1,21 @@ | |||
1 | #ifndef __XEN_PROTOCOLS_H__ | ||
2 | #define __XEN_PROTOCOLS_H__ | ||
3 | |||
4 | #define XEN_IO_PROTO_ABI_X86_32 "x86_32-abi" | ||
5 | #define XEN_IO_PROTO_ABI_X86_64 "x86_64-abi" | ||
6 | #define XEN_IO_PROTO_ABI_IA64 "ia64-abi" | ||
7 | #define XEN_IO_PROTO_ABI_POWERPC64 "powerpc64-abi" | ||
8 | |||
9 | #if defined(__i386__) | ||
10 | # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_X86_32 | ||
11 | #elif defined(__x86_64__) | ||
12 | # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_X86_64 | ||
13 | #elif defined(__ia64__) | ||
14 | # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_IA64 | ||
15 | #elif defined(__powerpc64__) | ||
16 | # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_POWERPC64 | ||
17 | #else | ||
18 | # error arch fixup needed here | ||
19 | #endif | ||
20 | |||
21 | #endif | ||
diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h index af36ead16817..da768469aa92 100644 --- a/include/xen/interface/memory.h +++ b/include/xen/interface/memory.h | |||
@@ -29,7 +29,7 @@ struct xen_memory_reservation { | |||
29 | * OUT: GMFN bases of extents that were allocated | 29 | * OUT: GMFN bases of extents that were allocated |
30 | * (NB. This command also updates the mach_to_phys translation table) | 30 | * (NB. This command also updates the mach_to_phys translation table) |
31 | */ | 31 | */ |
32 | GUEST_HANDLE(ulong) extent_start; | 32 | ulong extent_start; |
33 | 33 | ||
34 | /* Number of extents, and size/alignment of each (2^extent_order pages). */ | 34 | /* Number of extents, and size/alignment of each (2^extent_order pages). */ |
35 | unsigned long nr_extents; | 35 | unsigned long nr_extents; |
@@ -50,7 +50,6 @@ struct xen_memory_reservation { | |||
50 | domid_t domid; | 50 | domid_t domid; |
51 | 51 | ||
52 | }; | 52 | }; |
53 | DEFINE_GUEST_HANDLE_STRUCT(xen_memory_reservation); | ||
54 | 53 | ||
55 | /* | 54 | /* |
56 | * Returns the maximum machine frame number of mapped RAM in this system. | 55 | * Returns the maximum machine frame number of mapped RAM in this system. |
@@ -86,7 +85,7 @@ struct xen_machphys_mfn_list { | |||
86 | * any large discontiguities in the machine address space, 2MB gaps in | 85 | * any large discontiguities in the machine address space, 2MB gaps in |
87 | * the machphys table will be represented by an MFN base of zero. | 86 | * the machphys table will be represented by an MFN base of zero. |
88 | */ | 87 | */ |
89 | GUEST_HANDLE(ulong) extent_start; | 88 | ulong extent_start; |
90 | 89 | ||
91 | /* | 90 | /* |
92 | * Number of extents written to the above array. This will be smaller | 91 | * Number of extents written to the above array. This will be smaller |
@@ -94,7 +93,6 @@ struct xen_machphys_mfn_list { | |||
94 | */ | 93 | */ |
95 | unsigned int nr_extents; | 94 | unsigned int nr_extents; |
96 | }; | 95 | }; |
97 | DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mfn_list); | ||
98 | 96 | ||
99 | /* | 97 | /* |
100 | * Sets the GPFN at which a particular page appears in the specified guest's | 98 | * Sets the GPFN at which a particular page appears in the specified guest's |
@@ -117,7 +115,6 @@ struct xen_add_to_physmap { | |||
117 | /* GPFN where the source mapping page should appear. */ | 115 | /* GPFN where the source mapping page should appear. */ |
118 | unsigned long gpfn; | 116 | unsigned long gpfn; |
119 | }; | 117 | }; |
120 | DEFINE_GUEST_HANDLE_STRUCT(xen_add_to_physmap); | ||
121 | 118 | ||
122 | /* | 119 | /* |
123 | * Translates a list of domain-specific GPFNs into MFNs. Returns a -ve error | 120 | * Translates a list of domain-specific GPFNs into MFNs. Returns a -ve error |
@@ -132,14 +129,13 @@ struct xen_translate_gpfn_list { | |||
132 | unsigned long nr_gpfns; | 129 | unsigned long nr_gpfns; |
133 | 130 | ||
134 | /* List of GPFNs to translate. */ | 131 | /* List of GPFNs to translate. */ |
135 | GUEST_HANDLE(ulong) gpfn_list; | 132 | ulong gpfn_list; |
136 | 133 | ||
137 | /* | 134 | /* |
138 | * Output list to contain MFN translations. May be the same as the input | 135 | * Output list to contain MFN translations. May be the same as the input |
139 | * list (in which case each input GPFN is overwritten with the output MFN). | 136 | * list (in which case each input GPFN is overwritten with the output MFN). |
140 | */ | 137 | */ |
141 | GUEST_HANDLE(ulong) mfn_list; | 138 | ulong mfn_list; |
142 | }; | 139 | }; |
143 | DEFINE_GUEST_HANDLE_STRUCT(xen_translate_gpfn_list); | ||
144 | 140 | ||
145 | #endif /* __XEN_PUBLIC_MEMORY_H__ */ | 141 | #endif /* __XEN_PUBLIC_MEMORY_H__ */ |
diff --git a/include/xen/interface/vcpu.h b/include/xen/interface/vcpu.h index b05d8a6d9143..87e6f8a48661 100644 --- a/include/xen/interface/vcpu.h +++ b/include/xen/interface/vcpu.h | |||
@@ -85,6 +85,7 @@ struct vcpu_runstate_info { | |||
85 | */ | 85 | */ |
86 | uint64_t time[4]; | 86 | uint64_t time[4]; |
87 | }; | 87 | }; |
88 | DEFINE_GUEST_HANDLE_STRUCT(vcpu_runstate_info); | ||
88 | 89 | ||
89 | /* VCPU is currently running on a physical CPU. */ | 90 | /* VCPU is currently running on a physical CPU. */ |
90 | #define RUNSTATE_running 0 | 91 | #define RUNSTATE_running 0 |
@@ -119,6 +120,7 @@ struct vcpu_runstate_info { | |||
119 | #define VCPUOP_register_runstate_memory_area 5 | 120 | #define VCPUOP_register_runstate_memory_area 5 |
120 | struct vcpu_register_runstate_memory_area { | 121 | struct vcpu_register_runstate_memory_area { |
121 | union { | 122 | union { |
123 | GUEST_HANDLE(vcpu_runstate_info) h; | ||
122 | struct vcpu_runstate_info *v; | 124 | struct vcpu_runstate_info *v; |
123 | uint64_t p; | 125 | uint64_t p; |
124 | } addr; | 126 | } addr; |
@@ -134,6 +136,7 @@ struct vcpu_register_runstate_memory_area { | |||
134 | struct vcpu_set_periodic_timer { | 136 | struct vcpu_set_periodic_timer { |
135 | uint64_t period_ns; | 137 | uint64_t period_ns; |
136 | }; | 138 | }; |
139 | DEFINE_GUEST_HANDLE_STRUCT(vcpu_set_periodic_timer); | ||
137 | 140 | ||
138 | /* | 141 | /* |
139 | * Set or stop a VCPU's single-shot timer. Every VCPU has one single-shot | 142 | * Set or stop a VCPU's single-shot timer. Every VCPU has one single-shot |
@@ -145,6 +148,7 @@ struct vcpu_set_singleshot_timer { | |||
145 | uint64_t timeout_abs_ns; | 148 | uint64_t timeout_abs_ns; |
146 | uint32_t flags; /* VCPU_SSHOTTMR_??? */ | 149 | uint32_t flags; /* VCPU_SSHOTTMR_??? */ |
147 | }; | 150 | }; |
151 | DEFINE_GUEST_HANDLE_STRUCT(vcpu_set_singleshot_timer); | ||
148 | 152 | ||
149 | /* Flags to VCPUOP_set_singleshot_timer. */ | 153 | /* Flags to VCPUOP_set_singleshot_timer. */ |
150 | /* Require the timeout to be in the future (return -ETIME if it's passed). */ | 154 | /* Require the timeout to be in the future (return -ETIME if it's passed). */ |
@@ -164,5 +168,6 @@ struct vcpu_register_vcpu_info { | |||
164 | uint32_t offset; /* offset within page */ | 168 | uint32_t offset; /* offset within page */ |
165 | uint32_t rsvd; /* unused */ | 169 | uint32_t rsvd; /* unused */ |
166 | }; | 170 | }; |
171 | DEFINE_GUEST_HANDLE_STRUCT(vcpu_register_vcpu_info); | ||
167 | 172 | ||
168 | #endif /* __XEN_PUBLIC_VCPU_H__ */ | 173 | #endif /* __XEN_PUBLIC_VCPU_H__ */ |
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h index 518a5bf79ed3..9b018da48cf3 100644 --- a/include/xen/interface/xen.h +++ b/include/xen/interface/xen.h | |||
@@ -58,6 +58,16 @@ | |||
58 | #define __HYPERVISOR_physdev_op 33 | 58 | #define __HYPERVISOR_physdev_op 33 |
59 | #define __HYPERVISOR_hvm_op 34 | 59 | #define __HYPERVISOR_hvm_op 34 |
60 | 60 | ||
61 | /* Architecture-specific hypercall definitions. */ | ||
62 | #define __HYPERVISOR_arch_0 48 | ||
63 | #define __HYPERVISOR_arch_1 49 | ||
64 | #define __HYPERVISOR_arch_2 50 | ||
65 | #define __HYPERVISOR_arch_3 51 | ||
66 | #define __HYPERVISOR_arch_4 52 | ||
67 | #define __HYPERVISOR_arch_5 53 | ||
68 | #define __HYPERVISOR_arch_6 54 | ||
69 | #define __HYPERVISOR_arch_7 55 | ||
70 | |||
61 | /* | 71 | /* |
62 | * VIRTUAL INTERRUPTS | 72 | * VIRTUAL INTERRUPTS |
63 | * | 73 | * |
@@ -68,8 +78,18 @@ | |||
68 | #define VIRQ_CONSOLE 2 /* (DOM0) Bytes received on emergency console. */ | 78 | #define VIRQ_CONSOLE 2 /* (DOM0) Bytes received on emergency console. */ |
69 | #define VIRQ_DOM_EXC 3 /* (DOM0) Exceptional event for some domain. */ | 79 | #define VIRQ_DOM_EXC 3 /* (DOM0) Exceptional event for some domain. */ |
70 | #define VIRQ_DEBUGGER 6 /* (DOM0) A domain has paused for debugging. */ | 80 | #define VIRQ_DEBUGGER 6 /* (DOM0) A domain has paused for debugging. */ |
71 | #define NR_VIRQS 8 | ||
72 | 81 | ||
82 | /* Architecture-specific VIRQ definitions. */ | ||
83 | #define VIRQ_ARCH_0 16 | ||
84 | #define VIRQ_ARCH_1 17 | ||
85 | #define VIRQ_ARCH_2 18 | ||
86 | #define VIRQ_ARCH_3 19 | ||
87 | #define VIRQ_ARCH_4 20 | ||
88 | #define VIRQ_ARCH_5 21 | ||
89 | #define VIRQ_ARCH_6 22 | ||
90 | #define VIRQ_ARCH_7 23 | ||
91 | |||
92 | #define NR_VIRQS 24 | ||
73 | /* | 93 | /* |
74 | * MMU-UPDATE REQUESTS | 94 | * MMU-UPDATE REQUESTS |
75 | * | 95 | * |
diff --git a/include/xen/interface/xencomm.h b/include/xen/interface/xencomm.h new file mode 100644 index 000000000000..ac45e0712afa --- /dev/null +++ b/include/xen/interface/xencomm.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
3 | * of this software and associated documentation files (the "Software"), to | ||
4 | * deal in the Software without restriction, including without limitation the | ||
5 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||
6 | * sell copies of the Software, and to permit persons to whom the Software is | ||
7 | * furnished to do so, subject to the following conditions: | ||
8 | * | ||
9 | * The above copyright notice and this permission notice shall be included in | ||
10 | * all copies or substantial portions of the Software. | ||
11 | * | ||
12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
13 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
15 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
16 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
17 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
18 | * DEALINGS IN THE SOFTWARE. | ||
19 | * | ||
20 | * Copyright (C) IBM Corp. 2006 | ||
21 | */ | ||
22 | |||
23 | #ifndef _XEN_XENCOMM_H_ | ||
24 | #define _XEN_XENCOMM_H_ | ||
25 | |||
26 | /* A xencomm descriptor is a scatter/gather list containing physical | ||
27 | * addresses corresponding to a virtually contiguous memory area. The | ||
28 | * hypervisor translates these physical addresses to machine addresses to copy | ||
29 | * to and from the virtually contiguous area. | ||
30 | */ | ||
31 | |||
32 | #define XENCOMM_MAGIC 0x58434F4D /* 'XCOM' */ | ||
33 | #define XENCOMM_INVALID (~0UL) | ||
34 | |||
35 | struct xencomm_desc { | ||
36 | uint32_t magic; | ||
37 | uint32_t nr_addrs; /* the number of entries in address[] */ | ||
38 | uint64_t address[0]; | ||
39 | }; | ||
40 | |||
41 | #endif /* _XEN_XENCOMM_H_ */ | ||
diff --git a/include/xen/page.h b/include/xen/page.h index 031ef22a971e..eaf85fab1263 100644 --- a/include/xen/page.h +++ b/include/xen/page.h | |||
@@ -1,180 +1 @@ | |||
1 | #ifndef __XEN_PAGE_H | #include <asm/xen/page.h> | |
2 | #define __XEN_PAGE_H | ||
3 | |||
4 | #include <linux/pfn.h> | ||
5 | |||
6 | #include <asm/uaccess.h> | ||
7 | #include <asm/pgtable.h> | ||
8 | |||
9 | #include <xen/features.h> | ||
10 | |||
11 | #ifdef CONFIG_X86_PAE | ||
12 | /* Xen machine address */ | ||
13 | typedef struct xmaddr { | ||
14 | unsigned long long maddr; | ||
15 | } xmaddr_t; | ||
16 | |||
17 | /* Xen pseudo-physical address */ | ||
18 | typedef struct xpaddr { | ||
19 | unsigned long long paddr; | ||
20 | } xpaddr_t; | ||
21 | #else | ||
22 | /* Xen machine address */ | ||
23 | typedef struct xmaddr { | ||
24 | unsigned long maddr; | ||
25 | } xmaddr_t; | ||
26 | |||
27 | /* Xen pseudo-physical address */ | ||
28 | typedef struct xpaddr { | ||
29 | unsigned long paddr; | ||
30 | } xpaddr_t; | ||
31 | #endif | ||
32 | |||
33 | #define XMADDR(x) ((xmaddr_t) { .maddr = (x) }) | ||
34 | #define XPADDR(x) ((xpaddr_t) { .paddr = (x) }) | ||
35 | |||
36 | /**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/ | ||
37 | #define INVALID_P2M_ENTRY (~0UL) | ||
38 | #define FOREIGN_FRAME_BIT (1UL<<31) | ||
39 | #define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT) | ||
40 | |||
41 | extern unsigned long *phys_to_machine_mapping; | ||
42 | |||
43 | static inline unsigned long pfn_to_mfn(unsigned long pfn) | ||
44 | { | ||
45 | if (xen_feature(XENFEAT_auto_translated_physmap)) | ||
46 | return pfn; | ||
47 | |||
48 | return phys_to_machine_mapping[(unsigned int)(pfn)] & | ||
49 | ~FOREIGN_FRAME_BIT; | ||
50 | } | ||
51 | |||
52 | static inline int phys_to_machine_mapping_valid(unsigned long pfn) | ||
53 | { | ||
54 | if (xen_feature(XENFEAT_auto_translated_physmap)) | ||
55 | return 1; | ||
56 | |||
57 | return (phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY); | ||
58 | } | ||
59 | |||
60 | static inline unsigned long mfn_to_pfn(unsigned long mfn) | ||
61 | { | ||
62 | unsigned long pfn; | ||
63 | |||
64 | if (xen_feature(XENFEAT_auto_translated_physmap)) | ||
65 | return mfn; | ||
66 | |||
67 | #if 0 | ||
68 | if (unlikely((mfn >> machine_to_phys_order) != 0)) | ||
69 | return max_mapnr; | ||
70 | #endif | ||
71 | |||
72 | pfn = 0; | ||
73 | /* | ||
74 | * The array access can fail (e.g., device space beyond end of RAM). | ||
75 | * In such cases it doesn't matter what we return (we return garbage), | ||
76 | * but we must handle the fault without crashing! | ||
77 | */ | ||
78 | __get_user(pfn, &machine_to_phys_mapping[mfn]); | ||
79 | |||
80 | return pfn; | ||
81 | } | ||
82 | |||
83 | static inline xmaddr_t phys_to_machine(xpaddr_t phys) | ||
84 | { | ||
85 | unsigned offset = phys.paddr & ~PAGE_MASK; | ||
86 | return XMADDR(PFN_PHYS((u64)pfn_to_mfn(PFN_DOWN(phys.paddr))) | offset); | ||
87 | } | ||
88 | |||
89 | static inline xpaddr_t machine_to_phys(xmaddr_t machine) | ||
90 | { | ||
91 | unsigned offset = machine.maddr & ~PAGE_MASK; | ||
92 | return XPADDR(PFN_PHYS((u64)mfn_to_pfn(PFN_DOWN(machine.maddr))) | offset); | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * We detect special mappings in one of two ways: | ||
97 | * 1. If the MFN is an I/O page then Xen will set the m2p entry | ||
98 | * to be outside our maximum possible pseudophys range. | ||
99 | * 2. If the MFN belongs to a different domain then we will certainly | ||
100 | * not have MFN in our p2m table. Conversely, if the page is ours, | ||
101 | * then we'll have p2m(m2p(MFN))==MFN. | ||
102 | * If we detect a special mapping then it doesn't have a 'struct page'. | ||
103 | * We force !pfn_valid() by returning an out-of-range pointer. | ||
104 | * | ||
105 | * NB. These checks require that, for any MFN that is not in our reservation, | ||
106 | * there is no PFN such that p2m(PFN) == MFN. Otherwise we can get confused if | ||
107 | * we are foreign-mapping the MFN, and the other domain as m2p(MFN) == PFN. | ||
108 | * Yikes! Various places must poke in INVALID_P2M_ENTRY for safety. | ||
109 | * | ||
110 | * NB2. When deliberately mapping foreign pages into the p2m table, you *must* | ||
111 | * use FOREIGN_FRAME(). This will cause pte_pfn() to choke on it, as we | ||
112 | * require. In all the cases we care about, the FOREIGN_FRAME bit is | ||
113 | * masked (e.g., pfn_to_mfn()) so behaviour there is correct. | ||
114 | */ | ||
115 | static inline unsigned long mfn_to_local_pfn(unsigned long mfn) | ||
116 | { | ||
117 | extern unsigned long max_mapnr; | ||
118 | unsigned long pfn = mfn_to_pfn(mfn); | ||
119 | if ((pfn < max_mapnr) | ||
120 | && !xen_feature(XENFEAT_auto_translated_physmap) | ||
121 | && (phys_to_machine_mapping[pfn] != mfn)) | ||
122 | return max_mapnr; /* force !pfn_valid() */ | ||
123 | return pfn; | ||
124 | } | ||
125 | |||
126 | static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn) | ||
127 | { | ||
128 | if (xen_feature(XENFEAT_auto_translated_physmap)) { | ||
129 | BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY); | ||
130 | return; | ||
131 | } | ||
132 | phys_to_machine_mapping[pfn] = mfn; | ||
133 | } | ||
134 | |||
135 | /* VIRT <-> MACHINE conversion */ | ||
136 | #define virt_to_machine(v) (phys_to_machine(XPADDR(__pa(v)))) | ||
137 | #define virt_to_mfn(v) (pfn_to_mfn(PFN_DOWN(__pa(v)))) | ||
138 | #define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT)) | ||
139 | |||
140 | #ifdef CONFIG_X86_PAE | ||
141 | #define pte_mfn(_pte) (((_pte).pte_low >> PAGE_SHIFT) | \ | ||
142 | (((_pte).pte_high & 0xfff) << (32-PAGE_SHIFT))) | ||
143 | |||
144 | static inline pte_t mfn_pte(unsigned long page_nr, pgprot_t pgprot) | ||
145 | { | ||
146 | pte_t pte; | ||
147 | |||
148 | pte.pte_high = (page_nr >> (32 - PAGE_SHIFT)) | | ||
149 | (pgprot_val(pgprot) >> 32); | ||
150 | pte.pte_high &= (__supported_pte_mask >> 32); | ||
151 | pte.pte_low = ((page_nr << PAGE_SHIFT) | pgprot_val(pgprot)); | ||
152 | pte.pte_low &= __supported_pte_mask; | ||
153 | |||
154 | return pte; | ||
155 | } | ||
156 | |||
157 | static inline unsigned long long pte_val_ma(pte_t x) | ||
158 | { | ||
159 | return x.pte; | ||
160 | } | ||
161 | #define pmd_val_ma(v) ((v).pmd) | ||
162 | #define pud_val_ma(v) ((v).pgd.pgd) | ||
163 | #define __pte_ma(x) ((pte_t) { .pte = (x) }) | ||
164 | #define __pmd_ma(x) ((pmd_t) { (x) } ) | ||
165 | #else /* !X86_PAE */ | ||
166 | #define pte_mfn(_pte) ((_pte).pte_low >> PAGE_SHIFT) | ||
167 | #define mfn_pte(pfn, prot) __pte_ma(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) | ||
168 | #define pte_val_ma(x) ((x).pte) | ||
169 | #define pmd_val_ma(v) ((v).pud.pgd.pgd) | ||
170 | #define __pte_ma(x) ((pte_t) { (x) } ) | ||
171 | #endif /* CONFIG_X86_PAE */ | ||
172 | |||
173 | #define pgd_val_ma(x) ((x).pgd) | ||
174 | |||
175 | |||
176 | xmaddr_t arbitrary_virt_to_machine(unsigned long address); | ||
177 | void make_lowmem_page_readonly(void *vaddr); | ||
178 | void make_lowmem_page_readwrite(void *vaddr); | ||
179 | |||
180 | #endif /* __XEN_PAGE_H */ | ||
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h new file mode 100644 index 000000000000..10ddfe0142d0 --- /dev/null +++ b/include/xen/xen-ops.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifndef INCLUDE_XEN_OPS_H | ||
2 | #define INCLUDE_XEN_OPS_H | ||
3 | |||
4 | #include <linux/percpu.h> | ||
5 | |||
6 | DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu); | ||
7 | |||
8 | #endif /* INCLUDE_XEN_OPS_H */ | ||
diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h index 6f7c290651ae..6369d89c25d5 100644 --- a/include/xen/xenbus.h +++ b/include/xen/xenbus.h | |||
@@ -97,6 +97,7 @@ struct xenbus_driver { | |||
97 | int (*uevent)(struct xenbus_device *, char **, int, char *, int); | 97 | int (*uevent)(struct xenbus_device *, char **, int, char *, int); |
98 | struct device_driver driver; | 98 | struct device_driver driver; |
99 | int (*read_otherend_details)(struct xenbus_device *dev); | 99 | int (*read_otherend_details)(struct xenbus_device *dev); |
100 | int (*is_ready)(struct xenbus_device *dev); | ||
100 | }; | 101 | }; |
101 | 102 | ||
102 | static inline struct xenbus_driver *to_xenbus_driver(struct device_driver *drv) | 103 | static inline struct xenbus_driver *to_xenbus_driver(struct device_driver *drv) |
diff --git a/include/xen/xencomm.h b/include/xen/xencomm.h new file mode 100644 index 000000000000..e43b039be112 --- /dev/null +++ b/include/xen/xencomm.h | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
15 | * | ||
16 | * Copyright (C) IBM Corp. 2006 | ||
17 | * | ||
18 | * Authors: Hollis Blanchard <hollisb@us.ibm.com> | ||
19 | * Jerone Young <jyoung5@us.ibm.com> | ||
20 | */ | ||
21 | |||
22 | #ifndef _LINUX_XENCOMM_H_ | ||
23 | #define _LINUX_XENCOMM_H_ | ||
24 | |||
25 | #include <xen/interface/xencomm.h> | ||
26 | |||
27 | #define XENCOMM_MINI_ADDRS 3 | ||
28 | struct xencomm_mini { | ||
29 | struct xencomm_desc _desc; | ||
30 | uint64_t address[XENCOMM_MINI_ADDRS]; | ||
31 | }; | ||
32 | |||
33 | /* To avoid additionnal virt to phys conversion, an opaque structure is | ||
34 | presented. */ | ||
35 | struct xencomm_handle; | ||
36 | |||
37 | extern void xencomm_free(struct xencomm_handle *desc); | ||
38 | extern struct xencomm_handle *xencomm_map(void *ptr, unsigned long bytes); | ||
39 | extern struct xencomm_handle *__xencomm_map_no_alloc(void *ptr, | ||
40 | unsigned long bytes, struct xencomm_mini *xc_area); | ||
41 | |||
42 | #if 0 | ||
43 | #define XENCOMM_MINI_ALIGNED(xc_desc, n) \ | ||
44 | struct xencomm_mini xc_desc ## _base[(n)] \ | ||
45 | __attribute__((__aligned__(sizeof(struct xencomm_mini)))); \ | ||
46 | struct xencomm_mini *xc_desc = &xc_desc ## _base[0]; | ||
47 | #else | ||
48 | /* | ||
49 | * gcc bug workaround: | ||
50 | * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=16660 | ||
51 | * gcc doesn't handle properly stack variable with | ||
52 | * __attribute__((__align__(sizeof(struct xencomm_mini)))) | ||
53 | */ | ||
54 | #define XENCOMM_MINI_ALIGNED(xc_desc, n) \ | ||
55 | unsigned char xc_desc ## _base[((n) + 1 ) * \ | ||
56 | sizeof(struct xencomm_mini)]; \ | ||
57 | struct xencomm_mini *xc_desc = (struct xencomm_mini *) \ | ||
58 | ((unsigned long)xc_desc ## _base + \ | ||
59 | (sizeof(struct xencomm_mini) - \ | ||
60 | ((unsigned long)xc_desc ## _base) % \ | ||
61 | sizeof(struct xencomm_mini))); | ||
62 | #endif | ||
63 | #define xencomm_map_no_alloc(ptr, bytes) \ | ||
64 | ({ XENCOMM_MINI_ALIGNED(xc_desc, 1); \ | ||
65 | __xencomm_map_no_alloc(ptr, bytes, xc_desc); }) | ||
66 | |||
67 | /* provided by architecture code: */ | ||
68 | extern unsigned long xencomm_vtop(unsigned long vaddr); | ||
69 | |||
70 | static inline void *xencomm_pa(void *ptr) | ||
71 | { | ||
72 | return (void *)xencomm_vtop((unsigned long)ptr); | ||
73 | } | ||
74 | |||
75 | #define xen_guest_handle(hnd) ((hnd).p) | ||
76 | |||
77 | #endif /* _LINUX_XENCOMM_H_ */ | ||
diff --git a/kernel/sched.c b/kernel/sched.c index 0014b03adaca..09ca69b2c17d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -8128,7 +8128,7 @@ void __init sched_init(void) | |||
8128 | * we use alloc_bootmem(). | 8128 | * we use alloc_bootmem(). |
8129 | */ | 8129 | */ |
8130 | if (alloc_size) { | 8130 | if (alloc_size) { |
8131 | ptr = (unsigned long)alloc_bootmem_low(alloc_size); | 8131 | ptr = (unsigned long)alloc_bootmem(alloc_size); |
8132 | 8132 | ||
8133 | #ifdef CONFIG_FAIR_GROUP_SCHED | 8133 | #ifdef CONFIG_FAIR_GROUP_SCHED |
8134 | init_task_group.se = (struct sched_entity **)ptr; | 8134 | init_task_group.se = (struct sched_entity **)ptr; |
diff --git a/net/can/raw.c b/net/can/raw.c index ead50c7c0d40..201cbfc6b9ec 100644 --- a/net/can/raw.c +++ b/net/can/raw.c | |||
@@ -573,7 +573,8 @@ static int raw_getsockopt(struct socket *sock, int level, int optname, | |||
573 | int fsize = ro->count * sizeof(struct can_filter); | 573 | int fsize = ro->count * sizeof(struct can_filter); |
574 | if (len > fsize) | 574 | if (len > fsize) |
575 | len = fsize; | 575 | len = fsize; |
576 | err = copy_to_user(optval, ro->filter, len); | 576 | if (copy_to_user(optval, ro->filter, len)) |
577 | err = -EFAULT; | ||
577 | } else | 578 | } else |
578 | len = 0; | 579 | len = 0; |
579 | release_sock(sk); | 580 | release_sock(sk); |
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index a29b43d0b450..0133b5ebd545 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -323,6 +323,11 @@ static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr) | |||
323 | bytes_remaining -= eeprom.len; | 323 | bytes_remaining -= eeprom.len; |
324 | } | 324 | } |
325 | 325 | ||
326 | eeprom.len = userbuf - (useraddr + sizeof(eeprom)); | ||
327 | eeprom.offset -= eeprom.len; | ||
328 | if (copy_to_user(useraddr, &eeprom, sizeof(eeprom))) | ||
329 | ret = -EFAULT; | ||
330 | |||
326 | kfree(data); | 331 | kfree(data); |
327 | return ret; | 332 | return ret; |
328 | } | 333 | } |
diff --git a/net/dccp/probe.c b/net/dccp/probe.c index 6e1df62bd7c9..0bcdc9250279 100644 --- a/net/dccp/probe.c +++ b/net/dccp/probe.c | |||
@@ -140,7 +140,7 @@ static ssize_t dccpprobe_read(struct file *file, char __user *buf, | |||
140 | goto out_free; | 140 | goto out_free; |
141 | 141 | ||
142 | cnt = kfifo_get(dccpw.fifo, tbuf, len); | 142 | cnt = kfifo_get(dccpw.fifo, tbuf, len); |
143 | error = copy_to_user(buf, tbuf, cnt); | 143 | error = copy_to_user(buf, tbuf, cnt) ? -EFAULT : 0; |
144 | 144 | ||
145 | out_free: | 145 | out_free: |
146 | vfree(tbuf); | 146 | vfree(tbuf); |
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c index 1c509592574a..5ff0ce6e9d39 100644 --- a/net/ipv4/tcp_probe.c +++ b/net/ipv4/tcp_probe.c | |||
@@ -190,19 +190,18 @@ static ssize_t tcpprobe_read(struct file *file, char __user *buf, | |||
190 | 190 | ||
191 | width = tcpprobe_sprint(tbuf, sizeof(tbuf)); | 191 | width = tcpprobe_sprint(tbuf, sizeof(tbuf)); |
192 | 192 | ||
193 | if (width < len) | 193 | if (cnt + width < len) |
194 | tcp_probe.tail = (tcp_probe.tail + 1) % bufsize; | 194 | tcp_probe.tail = (tcp_probe.tail + 1) % bufsize; |
195 | 195 | ||
196 | spin_unlock_bh(&tcp_probe.lock); | 196 | spin_unlock_bh(&tcp_probe.lock); |
197 | 197 | ||
198 | /* if record greater than space available | 198 | /* if record greater than space available |
199 | return partial buffer (so far) */ | 199 | return partial buffer (so far) */ |
200 | if (width >= len) | 200 | if (cnt + width >= len) |
201 | break; | 201 | break; |
202 | 202 | ||
203 | error = copy_to_user(buf + cnt, tbuf, width); | 203 | if (copy_to_user(buf + cnt, tbuf, width)) |
204 | if (error) | 204 | return -EFAULT; |
205 | break; | ||
206 | cnt += width; | 205 | cnt += width; |
207 | } | 206 | } |
208 | 207 | ||
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index 42814a2ec9d7..b2c9becc02e8 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig | |||
@@ -167,7 +167,7 @@ config IPV6_SIT | |||
167 | Tunneling means encapsulating data of one protocol type within | 167 | Tunneling means encapsulating data of one protocol type within |
168 | another protocol and sending it over a channel that understands the | 168 | another protocol and sending it over a channel that understands the |
169 | encapsulating protocol. This driver implements encapsulation of IPv6 | 169 | encapsulating protocol. This driver implements encapsulation of IPv6 |
170 | into IPv4 packets. This is useful if you want to connect two IPv6 | 170 | into IPv4 packets. This is useful if you want to connect to IPv6 |
171 | networks over an IPv4-only path. | 171 | networks over an IPv4-only path. |
172 | 172 | ||
173 | Saying M here will produce a module called sit.ko. If unsure, say Y. | 173 | Saying M here will produce a module called sit.ko. If unsure, say Y. |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 6193b124cbc7..396f0ea11090 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -971,6 +971,19 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, | |||
971 | 971 | ||
972 | switch (optname) { | 972 | switch (optname) { |
973 | case IPV6_CHECKSUM: | 973 | case IPV6_CHECKSUM: |
974 | if (inet_sk(sk)->num == IPPROTO_ICMPV6 && | ||
975 | level == IPPROTO_IPV6) { | ||
976 | /* | ||
977 | * RFC3542 tells that IPV6_CHECKSUM socket | ||
978 | * option in the IPPROTO_IPV6 level is not | ||
979 | * allowed on ICMPv6 sockets. | ||
980 | * If you want to set it, use IPPROTO_RAW | ||
981 | * level IPV6_CHECKSUM socket option | ||
982 | * (Linux extension). | ||
983 | */ | ||
984 | return -EINVAL; | ||
985 | } | ||
986 | |||
974 | /* You may get strange result with a positive odd offset; | 987 | /* You may get strange result with a positive odd offset; |
975 | RFC2292bis agrees with me. */ | 988 | RFC2292bis agrees with me. */ |
976 | if (val > 0 && (val&1)) | 989 | if (val > 0 && (val&1)) |
@@ -1046,6 +1059,11 @@ static int do_rawv6_getsockopt(struct sock *sk, int level, int optname, | |||
1046 | 1059 | ||
1047 | switch (optname) { | 1060 | switch (optname) { |
1048 | case IPV6_CHECKSUM: | 1061 | case IPV6_CHECKSUM: |
1062 | /* | ||
1063 | * We allow getsockopt() for IPPROTO_IPV6-level | ||
1064 | * IPV6_CHECKSUM socket option on ICMPv6 sockets | ||
1065 | * since RFC3542 is silent about it. | ||
1066 | */ | ||
1049 | if (rp->checksum == 0) | 1067 | if (rp->checksum == 0) |
1050 | val = -1; | 1068 | val = -1; |
1051 | else | 1069 | else |
diff --git a/net/key/af_key.c b/net/key/af_key.c index 81a8e5297ad1..2403a31fe0f6 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -2356,7 +2356,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg | |||
2356 | struct xfrm_selector sel; | 2356 | struct xfrm_selector sel; |
2357 | struct km_event c; | 2357 | struct km_event c; |
2358 | struct sadb_x_sec_ctx *sec_ctx; | 2358 | struct sadb_x_sec_ctx *sec_ctx; |
2359 | struct xfrm_sec_ctx *pol_ctx; | 2359 | struct xfrm_sec_ctx *pol_ctx = NULL; |
2360 | 2360 | ||
2361 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], | 2361 | if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], |
2362 | ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || | 2362 | ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || |
@@ -2396,8 +2396,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg | |||
2396 | kfree(uctx); | 2396 | kfree(uctx); |
2397 | if (err) | 2397 | if (err) |
2398 | return err; | 2398 | return err; |
2399 | } else | 2399 | } |
2400 | pol_ctx = NULL; | ||
2401 | 2400 | ||
2402 | xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, | 2401 | xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, |
2403 | pol->sadb_x_policy_dir - 1, &sel, pol_ctx, | 2402 | pol->sadb_x_policy_dir - 1, &sel, pol_ctx, |
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 05853159536a..230f9ca2ad6b 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -1756,8 +1756,8 @@ static int getsockopt(struct socket *sock, | |||
1756 | else if (len < sizeof(value)) { | 1756 | else if (len < sizeof(value)) { |
1757 | res = -EINVAL; | 1757 | res = -EINVAL; |
1758 | } | 1758 | } |
1759 | else if ((res = copy_to_user(ov, &value, sizeof(value)))) { | 1759 | else if (copy_to_user(ov, &value, sizeof(value))) { |
1760 | /* couldn't return value */ | 1760 | res = -EFAULT; |
1761 | } | 1761 | } |
1762 | else { | 1762 | else { |
1763 | res = put_user(sizeof(value), ol); | 1763 | res = put_user(sizeof(value), ol); |