diff options
105 files changed, 3264 insertions, 554 deletions
diff --git a/Documentation/ABI/obsolete/proc-pid-oom_adj b/Documentation/ABI/obsolete/proc-pid-oom_adj new file mode 100644 index 000000000000..cf63f264ce0f --- /dev/null +++ b/Documentation/ABI/obsolete/proc-pid-oom_adj | |||
@@ -0,0 +1,22 @@ | |||
1 | What: /proc/<pid>/oom_adj | ||
2 | When: August 2012 | ||
3 | Why: /proc/<pid>/oom_adj allows userspace to influence the oom killer's | ||
4 | badness heuristic used to determine which task to kill when the kernel | ||
5 | is out of memory. | ||
6 | |||
7 | The badness heuristic has since been rewritten since the introduction of | ||
8 | this tunable such that its meaning is deprecated. The value was | ||
9 | implemented as a bitshift on a score generated by the badness() | ||
10 | function that did not have any precise units of measure. With the | ||
11 | rewrite, the score is given as a proportion of available memory to the | ||
12 | task allocating pages, so using a bitshift which grows the score | ||
13 | exponentially is, thus, impossible to tune with fine granularity. | ||
14 | |||
15 | A much more powerful interface, /proc/<pid>/oom_score_adj, was | ||
16 | introduced with the oom killer rewrite that allows users to increase or | ||
17 | decrease the badness() score linearly. This interface will replace | ||
18 | /proc/<pid>/oom_adj. | ||
19 | |||
20 | A warning will be emitted to the kernel log if an application uses this | ||
21 | deprecated interface. After it is printed once, future warnings will be | ||
22 | suppressed until the kernel is rebooted. | ||
diff --git a/Documentation/filesystems/xfs-delayed-logging-design.txt b/Documentation/filesystems/xfs-delayed-logging-design.txt index 96d0df28bed3..7445bf335dae 100644 --- a/Documentation/filesystems/xfs-delayed-logging-design.txt +++ b/Documentation/filesystems/xfs-delayed-logging-design.txt | |||
@@ -794,17 +794,6 @@ designed. | |||
794 | 794 | ||
795 | Roadmap: | 795 | Roadmap: |
796 | 796 | ||
797 | 2.6.37 Remove experimental tag from mount option | ||
798 | => should be roughly 6 months after initial merge | ||
799 | => enough time to: | ||
800 | => gain confidence and fix problems reported by early | ||
801 | adopters (a.k.a. guinea pigs) | ||
802 | => address worst performance regressions and undesired | ||
803 | behaviours | ||
804 | => start tuning/optimising code for parallelism | ||
805 | => start tuning/optimising algorithms consuming | ||
806 | excessive CPU time | ||
807 | |||
808 | 2.6.39 Switch default mount option to use delayed logging | 797 | 2.6.39 Switch default mount option to use delayed logging |
809 | => should be roughly 12 months after initial merge | 798 | => should be roughly 12 months after initial merge |
810 | => enough time to shake out remaining problems before next round of | 799 | => enough time to shake out remaining problems before next round of |
diff --git a/Documentation/leds-class.txt b/Documentation/leds-class.txt index 8fd5ca2ae32d..58b266bd1846 100644 --- a/Documentation/leds-class.txt +++ b/Documentation/leds-class.txt | |||
@@ -60,15 +60,18 @@ Hardware accelerated blink of LEDs | |||
60 | 60 | ||
61 | Some LEDs can be programmed to blink without any CPU interaction. To | 61 | Some LEDs can be programmed to blink without any CPU interaction. To |
62 | support this feature, a LED driver can optionally implement the | 62 | support this feature, a LED driver can optionally implement the |
63 | blink_set() function (see <linux/leds.h>). If implemented, triggers can | 63 | blink_set() function (see <linux/leds.h>). To set an LED to blinking, |
64 | attempt to use it before falling back to software timers. The blink_set() | 64 | however, it is better to use use the API function led_blink_set(), |
65 | function should return 0 if the blink setting is supported, or -EINVAL | 65 | as it will check and implement software fallback if necessary. |
66 | otherwise, which means that LED blinking will be handled by software. | 66 | |
67 | 67 | To turn off blinking again, use the API function led_brightness_set() | |
68 | The blink_set() function should choose a user friendly blinking | 68 | as that will not just set the LED brightness but also stop any software |
69 | value if it is called with *delay_on==0 && *delay_off==0 parameters. In | 69 | timers that may have been required for blinking. |
70 | this case the driver should give back the chosen value through delay_on | 70 | |
71 | and delay_off parameters to the leds subsystem. | 71 | The blink_set() function should choose a user friendly blinking value |
72 | if it is called with *delay_on==0 && *delay_off==0 parameters. In this | ||
73 | case the driver should give back the chosen value through delay_on and | ||
74 | delay_off parameters to the leds subsystem. | ||
72 | 75 | ||
73 | Setting the brightness to zero with brightness_set() callback function | 76 | Setting the brightness to zero with brightness_set() callback function |
74 | should completely turn off the LED and cancel the previously programmed | 77 | should completely turn off the LED and cancel the previously programmed |
diff --git a/Documentation/leds/leds-lp5521.txt b/Documentation/leds/leds-lp5521.txt new file mode 100644 index 000000000000..c4d8d151e0fe --- /dev/null +++ b/Documentation/leds/leds-lp5521.txt | |||
@@ -0,0 +1,88 @@ | |||
1 | Kernel driver for lp5521 | ||
2 | ======================== | ||
3 | |||
4 | * National Semiconductor LP5521 led driver chip | ||
5 | * Datasheet: http://www.national.com/pf/LP/LP5521.html | ||
6 | |||
7 | Authors: Mathias Nyman, Yuri Zaporozhets, Samu Onkalo | ||
8 | Contact: Samu Onkalo (samu.p.onkalo-at-nokia.com) | ||
9 | |||
10 | Description | ||
11 | ----------- | ||
12 | |||
13 | LP5521 can drive up to 3 channels. Leds can be controlled directly via | ||
14 | the led class control interface. Channels have generic names: | ||
15 | lp5521:channelx, where x is 0 .. 2 | ||
16 | |||
17 | All three channels can be also controlled using the engine micro programs. | ||
18 | More details of the instructions can be found from the public data sheet. | ||
19 | |||
20 | Control interface for the engines: | ||
21 | x is 1 .. 3 | ||
22 | enginex_mode : disabled, load, run | ||
23 | enginex_load : store program (visible only in engine load mode) | ||
24 | |||
25 | Example (start to blink the channel 2 led): | ||
26 | cd /sys/class/leds/lp5521:channel2/device | ||
27 | echo "load" > engine3_mode | ||
28 | echo "037f4d0003ff6000" > engine3_load | ||
29 | echo "run" > engine3_mode | ||
30 | |||
31 | stop the engine: | ||
32 | echo "disabled" > engine3_mode | ||
33 | |||
34 | sysfs contains a selftest entry. | ||
35 | The test communicates with the chip and checks that | ||
36 | the clock mode is automatically set to the requested one. | ||
37 | |||
38 | Each channel has its own led current settings. | ||
39 | /sys/class/leds/lp5521:channel0/led_current - RW | ||
40 | /sys/class/leds/lp5521:channel0/max_current - RO | ||
41 | Format: 10x mA i.e 10 means 1.0 mA | ||
42 | |||
43 | example platform data: | ||
44 | |||
45 | Note: chan_nr can have values between 0 and 2. | ||
46 | |||
47 | static struct lp5521_led_config lp5521_led_config[] = { | ||
48 | { | ||
49 | .chan_nr = 0, | ||
50 | .led_current = 50, | ||
51 | .max_current = 130, | ||
52 | }, { | ||
53 | .chan_nr = 1, | ||
54 | .led_current = 0, | ||
55 | .max_current = 130, | ||
56 | }, { | ||
57 | .chan_nr = 2, | ||
58 | .led_current = 0, | ||
59 | .max_current = 130, | ||
60 | } | ||
61 | }; | ||
62 | |||
63 | static int lp5521_setup(void) | ||
64 | { | ||
65 | /* setup HW resources */ | ||
66 | } | ||
67 | |||
68 | static void lp5521_release(void) | ||
69 | { | ||
70 | /* Release HW resources */ | ||
71 | } | ||
72 | |||
73 | static void lp5521_enable(bool state) | ||
74 | { | ||
75 | /* Control of chip enable signal */ | ||
76 | } | ||
77 | |||
78 | static struct lp5521_platform_data lp5521_platform_data = { | ||
79 | .led_config = lp5521_led_config, | ||
80 | .num_channels = ARRAY_SIZE(lp5521_led_config), | ||
81 | .clock_mode = LP5521_CLOCK_EXT, | ||
82 | .setup_resources = lp5521_setup, | ||
83 | .release_resources = lp5521_release, | ||
84 | .enable = lp5521_enable, | ||
85 | }; | ||
86 | |||
87 | If the current is set to 0 in the platform data, that channel is | ||
88 | disabled and it is not visible in the sysfs. | ||
diff --git a/Documentation/leds/leds-lp5523.txt b/Documentation/leds/leds-lp5523.txt new file mode 100644 index 000000000000..fad2feb8b7ce --- /dev/null +++ b/Documentation/leds/leds-lp5523.txt | |||
@@ -0,0 +1,83 @@ | |||
1 | Kernel driver for lp5523 | ||
2 | ======================== | ||
3 | |||
4 | * National Semiconductor LP5523 led driver chip | ||
5 | * Datasheet: http://www.national.com/pf/LP/LP5523.html | ||
6 | |||
7 | Authors: Mathias Nyman, Yuri Zaporozhets, Samu Onkalo | ||
8 | Contact: Samu Onkalo (samu.p.onkalo-at-nokia.com) | ||
9 | |||
10 | Description | ||
11 | ----------- | ||
12 | LP5523 can drive up to 9 channels. Leds can be controlled directly via | ||
13 | the led class control interface. Channels have generic names: | ||
14 | lp5523:channelx where x is 0...8 | ||
15 | |||
16 | The chip provides 3 engines. Each engine can control channels without | ||
17 | interaction from the main CPU. Details of the micro engine code can be found | ||
18 | from the public data sheet. Leds can be muxed to different channels. | ||
19 | |||
20 | Control interface for the engines: | ||
21 | x is 1 .. 3 | ||
22 | enginex_mode : disabled, load, run | ||
23 | enginex_load : microcode load (visible only in load mode) | ||
24 | enginex_leds : led mux control (visible only in load mode) | ||
25 | |||
26 | cd /sys/class/leds/lp5523:channel2/device | ||
27 | echo "load" > engine3_mode | ||
28 | echo "9d80400004ff05ff437f0000" > engine3_load | ||
29 | echo "111111111" > engine3_leds | ||
30 | echo "run" > engine3_mode | ||
31 | |||
32 | sysfs contains a selftest entry. It measures each channel | ||
33 | voltage level and checks if it looks reasonable. If the level is too high, | ||
34 | the led is missing; if the level is too low, there is a short circuit. | ||
35 | |||
36 | Selftest uses always the current from the platform data. | ||
37 | |||
38 | Each channel contains led current settings. | ||
39 | /sys/class/leds/lp5523:channel2/led_current - RW | ||
40 | /sys/class/leds/lp5523:channel2/max_current - RO | ||
41 | Format: 10x mA i.e 10 means 1.0 mA | ||
42 | |||
43 | Example platform data: | ||
44 | |||
45 | Note - chan_nr can have values between 0 and 8. | ||
46 | |||
47 | static struct lp5523_led_config lp5523_led_config[] = { | ||
48 | { | ||
49 | .chan_nr = 0, | ||
50 | .led_current = 50, | ||
51 | .max_current = 130, | ||
52 | }, | ||
53 | ... | ||
54 | }, { | ||
55 | .chan_nr = 8, | ||
56 | .led_current = 50, | ||
57 | .max_current = 130, | ||
58 | } | ||
59 | }; | ||
60 | |||
61 | static int lp5523_setup(void) | ||
62 | { | ||
63 | /* Setup HW resources */ | ||
64 | } | ||
65 | |||
66 | static void lp5523_release(void) | ||
67 | { | ||
68 | /* Release HW resources */ | ||
69 | } | ||
70 | |||
71 | static void lp5523_enable(bool state) | ||
72 | { | ||
73 | /* Control chip enable signal */ | ||
74 | } | ||
75 | |||
76 | static struct lp5523_platform_data lp5523_platform_data = { | ||
77 | .led_config = lp5523_led_config, | ||
78 | .num_channels = ARRAY_SIZE(lp5523_led_config), | ||
79 | .clock_mode = LP5523_CLOCK_EXT, | ||
80 | .setup_resources = lp5523_setup, | ||
81 | .release_resources = lp5523_release, | ||
82 | .enable = lp5523_enable, | ||
83 | }; | ||
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 3894eaa23486..209e1584c3dc 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt | |||
@@ -28,6 +28,7 @@ show up in /proc/sys/kernel: | |||
28 | - core_uses_pid | 28 | - core_uses_pid |
29 | - ctrl-alt-del | 29 | - ctrl-alt-del |
30 | - dentry-state | 30 | - dentry-state |
31 | - dmesg_restrict | ||
31 | - domainname | 32 | - domainname |
32 | - hostname | 33 | - hostname |
33 | - hotplug | 34 | - hotplug |
@@ -213,6 +214,19 @@ to decide what to do with it. | |||
213 | 214 | ||
214 | ============================================================== | 215 | ============================================================== |
215 | 216 | ||
217 | dmesg_restrict: | ||
218 | |||
219 | This toggle indicates whether unprivileged users are prevented from using | ||
220 | dmesg(8) to view messages from the kernel's log buffer. When | ||
221 | dmesg_restrict is set to (0) there are no restrictions. When | ||
222 | dmesg_restrict is set set to (1), users must have CAP_SYS_ADMIN to use | ||
223 | dmesg(8). | ||
224 | |||
225 | The kernel config option CONFIG_SECURITY_DMESG_RESTRICT sets the default | ||
226 | value of dmesg_restrict. | ||
227 | |||
228 | ============================================================== | ||
229 | |||
216 | domainname & hostname: | 230 | domainname & hostname: |
217 | 231 | ||
218 | These files can be used to set the NIS/YP domainname and the | 232 | These files can be used to set the NIS/YP domainname and the |
diff --git a/arch/um/include/asm/ptrace-generic.h b/arch/um/include/asm/ptrace-generic.h index 2cd899f75a3c..b7c5bab9bd77 100644 --- a/arch/um/include/asm/ptrace-generic.h +++ b/arch/um/include/asm/ptrace-generic.h | |||
@@ -38,8 +38,8 @@ struct pt_regs { | |||
38 | 38 | ||
39 | struct task_struct; | 39 | struct task_struct; |
40 | 40 | ||
41 | extern long subarch_ptrace(struct task_struct *child, long request, long addr, | 41 | extern long subarch_ptrace(struct task_struct *child, long request, |
42 | long data); | 42 | unsigned long addr, unsigned long data); |
43 | extern unsigned long getreg(struct task_struct *child, int regno); | 43 | extern unsigned long getreg(struct task_struct *child, int regno); |
44 | extern int putreg(struct task_struct *child, int regno, unsigned long value); | 44 | extern int putreg(struct task_struct *child, int regno, unsigned long value); |
45 | extern int get_fpregs(struct user_i387_struct __user *buf, | 45 | extern int get_fpregs(struct user_i387_struct __user *buf, |
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index a5e33f29bbeb..701b672c1122 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c | |||
@@ -122,7 +122,7 @@ long arch_ptrace(struct task_struct *child, long request, | |||
122 | break; | 122 | break; |
123 | 123 | ||
124 | case PTRACE_SET_THREAD_AREA: | 124 | case PTRACE_SET_THREAD_AREA: |
125 | ret = ptrace_set_thread_area(child, addr, datavp); | 125 | ret = ptrace_set_thread_area(child, addr, vp); |
126 | break; | 126 | break; |
127 | 127 | ||
128 | case PTRACE_FAULTINFO: { | 128 | case PTRACE_FAULTINFO: { |
diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c index de3078215fe6..75586f1f86e7 100644 --- a/crypto/pcrypt.c +++ b/crypto/pcrypt.c | |||
@@ -504,7 +504,6 @@ err: | |||
504 | 504 | ||
505 | static void pcrypt_fini_padata(struct padata_pcrypt *pcrypt) | 505 | static void pcrypt_fini_padata(struct padata_pcrypt *pcrypt) |
506 | { | 506 | { |
507 | kobject_put(&pcrypt->pinst->kobj); | ||
508 | free_cpumask_var(pcrypt->cb_cpumask->mask); | 507 | free_cpumask_var(pcrypt->cb_cpumask->mask); |
509 | kfree(pcrypt->cb_cpumask); | 508 | kfree(pcrypt->cb_cpumask); |
510 | 509 | ||
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 6b6760ea2435..9272c38dd3c6 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c | |||
@@ -1210,14 +1210,14 @@ static void gen6_write_entry(dma_addr_t addr, unsigned int entry, | |||
1210 | unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT; | 1210 | unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT; |
1211 | u32 pte_flags; | 1211 | u32 pte_flags; |
1212 | 1212 | ||
1213 | if (type_mask == AGP_USER_UNCACHED_MEMORY) | 1213 | if (type_mask == AGP_USER_MEMORY) |
1214 | pte_flags = GEN6_PTE_UNCACHED | I810_PTE_VALID; | 1214 | pte_flags = GEN6_PTE_UNCACHED | I810_PTE_VALID; |
1215 | else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) { | 1215 | else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) { |
1216 | pte_flags = GEN6_PTE_LLC | I810_PTE_VALID; | 1216 | pte_flags = GEN6_PTE_LLC_MLC | I810_PTE_VALID; |
1217 | if (gfdt) | 1217 | if (gfdt) |
1218 | pte_flags |= GEN6_PTE_GFDT; | 1218 | pte_flags |= GEN6_PTE_GFDT; |
1219 | } else { /* set 'normal'/'cached' to LLC by default */ | 1219 | } else { /* set 'normal'/'cached' to LLC by default */ |
1220 | pte_flags = GEN6_PTE_LLC_MLC | I810_PTE_VALID; | 1220 | pte_flags = GEN6_PTE_LLC | I810_PTE_VALID; |
1221 | if (gfdt) | 1221 | if (gfdt) |
1222 | pte_flags |= GEN6_PTE_GFDT; | 1222 | pte_flags |= GEN6_PTE_GFDT; |
1223 | } | 1223 | } |
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index dcbeb98f195a..f7af91cb273d 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
@@ -276,7 +276,7 @@ static bool drm_encoder_crtc_ok(struct drm_encoder *encoder, | |||
276 | struct drm_crtc *tmp; | 276 | struct drm_crtc *tmp; |
277 | int crtc_mask = 1; | 277 | int crtc_mask = 1; |
278 | 278 | ||
279 | WARN(!crtc, "checking null crtc?"); | 279 | WARN(!crtc, "checking null crtc?\n"); |
280 | 280 | ||
281 | dev = crtc->dev; | 281 | dev = crtc->dev; |
282 | 282 | ||
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index c1a26217a530..a245d17165ae 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -240,7 +240,7 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf, | |||
240 | .addr = DDC_ADDR, | 240 | .addr = DDC_ADDR, |
241 | .flags = I2C_M_RD, | 241 | .flags = I2C_M_RD, |
242 | .len = len, | 242 | .len = len, |
243 | .buf = buf + start, | 243 | .buf = buf, |
244 | } | 244 | } |
245 | }; | 245 | }; |
246 | 246 | ||
@@ -253,7 +253,7 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf, | |||
253 | static u8 * | 253 | static u8 * |
254 | drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) | 254 | drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) |
255 | { | 255 | { |
256 | int i, j = 0; | 256 | int i, j = 0, valid_extensions = 0; |
257 | u8 *block, *new; | 257 | u8 *block, *new; |
258 | 258 | ||
259 | if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL) | 259 | if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL) |
@@ -280,14 +280,28 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) | |||
280 | 280 | ||
281 | for (j = 1; j <= block[0x7e]; j++) { | 281 | for (j = 1; j <= block[0x7e]; j++) { |
282 | for (i = 0; i < 4; i++) { | 282 | for (i = 0; i < 4; i++) { |
283 | if (drm_do_probe_ddc_edid(adapter, block, j, | 283 | if (drm_do_probe_ddc_edid(adapter, |
284 | EDID_LENGTH)) | 284 | block + (valid_extensions + 1) * EDID_LENGTH, |
285 | j, EDID_LENGTH)) | ||
285 | goto out; | 286 | goto out; |
286 | if (drm_edid_block_valid(block + j * EDID_LENGTH)) | 287 | if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH)) { |
288 | valid_extensions++; | ||
287 | break; | 289 | break; |
290 | } | ||
288 | } | 291 | } |
289 | if (i == 4) | 292 | if (i == 4) |
290 | goto carp; | 293 | dev_warn(connector->dev->dev, |
294 | "%s: Ignoring invalid EDID block %d.\n", | ||
295 | drm_get_connector_name(connector), j); | ||
296 | } | ||
297 | |||
298 | if (valid_extensions != block[0x7e]) { | ||
299 | block[EDID_LENGTH-1] += block[0x7e] - valid_extensions; | ||
300 | block[0x7e] = valid_extensions; | ||
301 | new = krealloc(block, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL); | ||
302 | if (!new) | ||
303 | goto out; | ||
304 | block = new; | ||
291 | } | 305 | } |
292 | 306 | ||
293 | return block; | 307 | return block; |
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 3467dd420760..80745f85902c 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
@@ -44,7 +44,7 @@ unsigned int i915_fbpercrtc = 0; | |||
44 | module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); | 44 | module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); |
45 | 45 | ||
46 | unsigned int i915_powersave = 1; | 46 | unsigned int i915_powersave = 1; |
47 | module_param_named(powersave, i915_powersave, int, 0400); | 47 | module_param_named(powersave, i915_powersave, int, 0600); |
48 | 48 | ||
49 | unsigned int i915_lvds_downclock = 0; | 49 | unsigned int i915_lvds_downclock = 0; |
50 | module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400); | 50 | module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400); |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2c2c19b6285e..90414ae86afc 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -1321,6 +1321,7 @@ static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg, | |||
1321 | 1321 | ||
1322 | #define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type) | 1322 | #define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type) |
1323 | #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT) | 1323 | #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT) |
1324 | #define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX) | ||
1324 | 1325 | ||
1325 | #define PRIMARY_RINGBUFFER_SIZE (128*1024) | 1326 | #define PRIMARY_RINGBUFFER_SIZE (128*1024) |
1326 | 1327 | ||
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8eb8453208b5..ef188e391406 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -2172,7 +2172,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj) | |||
2172 | static int i915_ring_idle(struct drm_device *dev, | 2172 | static int i915_ring_idle(struct drm_device *dev, |
2173 | struct intel_ring_buffer *ring) | 2173 | struct intel_ring_buffer *ring) |
2174 | { | 2174 | { |
2175 | if (list_empty(&ring->gpu_write_list)) | 2175 | if (list_empty(&ring->gpu_write_list) && list_empty(&ring->active_list)) |
2176 | return 0; | 2176 | return 0; |
2177 | 2177 | ||
2178 | i915_gem_flush_ring(dev, NULL, ring, | 2178 | i915_gem_flush_ring(dev, NULL, ring, |
@@ -2190,9 +2190,7 @@ i915_gpu_idle(struct drm_device *dev) | |||
2190 | int ret; | 2190 | int ret; |
2191 | 2191 | ||
2192 | lists_empty = (list_empty(&dev_priv->mm.flushing_list) && | 2192 | lists_empty = (list_empty(&dev_priv->mm.flushing_list) && |
2193 | list_empty(&dev_priv->render_ring.active_list) && | 2193 | list_empty(&dev_priv->mm.active_list)); |
2194 | list_empty(&dev_priv->bsd_ring.active_list) && | ||
2195 | list_empty(&dev_priv->blt_ring.active_list)); | ||
2196 | if (lists_empty) | 2194 | if (lists_empty) |
2197 | return 0; | 2195 | return 0; |
2198 | 2196 | ||
@@ -3108,7 +3106,8 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj, | |||
3108 | * write domain | 3106 | * write domain |
3109 | */ | 3107 | */ |
3110 | if (obj->write_domain && | 3108 | if (obj->write_domain && |
3111 | obj->write_domain != obj->pending_read_domains) { | 3109 | (obj->write_domain != obj->pending_read_domains || |
3110 | obj_priv->ring != ring)) { | ||
3112 | flush_domains |= obj->write_domain; | 3111 | flush_domains |= obj->write_domain; |
3113 | invalidate_domains |= | 3112 | invalidate_domains |= |
3114 | obj->pending_read_domains & ~obj->write_domain; | 3113 | obj->pending_read_domains & ~obj->write_domain; |
@@ -3497,6 +3496,52 @@ i915_gem_execbuffer_pin(struct drm_device *dev, | |||
3497 | return 0; | 3496 | return 0; |
3498 | } | 3497 | } |
3499 | 3498 | ||
3499 | static int | ||
3500 | i915_gem_execbuffer_move_to_gpu(struct drm_device *dev, | ||
3501 | struct drm_file *file, | ||
3502 | struct intel_ring_buffer *ring, | ||
3503 | struct drm_gem_object **objects, | ||
3504 | int count) | ||
3505 | { | ||
3506 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
3507 | int ret, i; | ||
3508 | |||
3509 | /* Zero the global flush/invalidate flags. These | ||
3510 | * will be modified as new domains are computed | ||
3511 | * for each object | ||
3512 | */ | ||
3513 | dev->invalidate_domains = 0; | ||
3514 | dev->flush_domains = 0; | ||
3515 | dev_priv->mm.flush_rings = 0; | ||
3516 | for (i = 0; i < count; i++) | ||
3517 | i915_gem_object_set_to_gpu_domain(objects[i], ring); | ||
3518 | |||
3519 | if (dev->invalidate_domains | dev->flush_domains) { | ||
3520 | #if WATCH_EXEC | ||
3521 | DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n", | ||
3522 | __func__, | ||
3523 | dev->invalidate_domains, | ||
3524 | dev->flush_domains); | ||
3525 | #endif | ||
3526 | i915_gem_flush(dev, file, | ||
3527 | dev->invalidate_domains, | ||
3528 | dev->flush_domains, | ||
3529 | dev_priv->mm.flush_rings); | ||
3530 | } | ||
3531 | |||
3532 | for (i = 0; i < count; i++) { | ||
3533 | struct drm_i915_gem_object *obj = to_intel_bo(objects[i]); | ||
3534 | /* XXX replace with semaphores */ | ||
3535 | if (obj->ring && ring != obj->ring) { | ||
3536 | ret = i915_gem_object_wait_rendering(&obj->base, true); | ||
3537 | if (ret) | ||
3538 | return ret; | ||
3539 | } | ||
3540 | } | ||
3541 | |||
3542 | return 0; | ||
3543 | } | ||
3544 | |||
3500 | /* Throttle our rendering by waiting until the ring has completed our requests | 3545 | /* Throttle our rendering by waiting until the ring has completed our requests |
3501 | * emitted over 20 msec ago. | 3546 | * emitted over 20 msec ago. |
3502 | * | 3547 | * |
@@ -3757,33 +3802,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, | |||
3757 | goto err; | 3802 | goto err; |
3758 | } | 3803 | } |
3759 | 3804 | ||
3760 | /* Zero the global flush/invalidate flags. These | 3805 | ret = i915_gem_execbuffer_move_to_gpu(dev, file, ring, |
3761 | * will be modified as new domains are computed | 3806 | object_list, args->buffer_count); |
3762 | * for each object | 3807 | if (ret) |
3763 | */ | 3808 | goto err; |
3764 | dev->invalidate_domains = 0; | ||
3765 | dev->flush_domains = 0; | ||
3766 | dev_priv->mm.flush_rings = 0; | ||
3767 | |||
3768 | for (i = 0; i < args->buffer_count; i++) { | ||
3769 | struct drm_gem_object *obj = object_list[i]; | ||
3770 | |||
3771 | /* Compute new gpu domains and update invalidate/flush */ | ||
3772 | i915_gem_object_set_to_gpu_domain(obj, ring); | ||
3773 | } | ||
3774 | |||
3775 | if (dev->invalidate_domains | dev->flush_domains) { | ||
3776 | #if WATCH_EXEC | ||
3777 | DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n", | ||
3778 | __func__, | ||
3779 | dev->invalidate_domains, | ||
3780 | dev->flush_domains); | ||
3781 | #endif | ||
3782 | i915_gem_flush(dev, file, | ||
3783 | dev->invalidate_domains, | ||
3784 | dev->flush_domains, | ||
3785 | dev_priv->mm.flush_rings); | ||
3786 | } | ||
3787 | 3809 | ||
3788 | for (i = 0; i < args->buffer_count; i++) { | 3810 | for (i = 0; i < args->buffer_count; i++) { |
3789 | struct drm_gem_object *obj = object_list[i]; | 3811 | struct drm_gem_object *obj = object_list[i]; |
@@ -4043,8 +4065,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) | |||
4043 | alignment = i915_gem_get_gtt_alignment(obj); | 4065 | alignment = i915_gem_get_gtt_alignment(obj); |
4044 | if (obj_priv->gtt_offset & (alignment - 1)) { | 4066 | if (obj_priv->gtt_offset & (alignment - 1)) { |
4045 | WARN(obj_priv->pin_count, | 4067 | WARN(obj_priv->pin_count, |
4046 | "bo is already pinned with incorrect alignment:" | 4068 | "bo is already pinned with incorrect alignment: offset=%x, req.alignment=%x\n", |
4047 | " offset=%x, req.alignment=%x\n", | ||
4048 | obj_priv->gtt_offset, alignment); | 4069 | obj_priv->gtt_offset, alignment); |
4049 | ret = i915_gem_object_unbind(obj); | 4070 | ret = i915_gem_object_unbind(obj); |
4050 | if (ret) | 4071 | if (ret) |
@@ -4856,17 +4877,24 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, | |||
4856 | struct drm_file *file_priv) | 4877 | struct drm_file *file_priv) |
4857 | { | 4878 | { |
4858 | struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); | 4879 | struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); |
4859 | void *obj_addr; | 4880 | void *vaddr = obj_priv->phys_obj->handle->vaddr + args->offset; |
4860 | int ret; | 4881 | char __user *user_data = (char __user *) (uintptr_t) args->data_ptr; |
4861 | char __user *user_data; | ||
4862 | 4882 | ||
4863 | user_data = (char __user *) (uintptr_t) args->data_ptr; | 4883 | DRM_DEBUG_DRIVER("vaddr %p, %lld\n", vaddr, args->size); |
4864 | obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset; | ||
4865 | 4884 | ||
4866 | DRM_DEBUG_DRIVER("obj_addr %p, %lld\n", obj_addr, args->size); | 4885 | if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) { |
4867 | ret = copy_from_user(obj_addr, user_data, args->size); | 4886 | unsigned long unwritten; |
4868 | if (ret) | 4887 | |
4869 | return -EFAULT; | 4888 | /* The physical object once assigned is fixed for the lifetime |
4889 | * of the obj, so we can safely drop the lock and continue | ||
4890 | * to access vaddr. | ||
4891 | */ | ||
4892 | mutex_unlock(&dev->struct_mutex); | ||
4893 | unwritten = copy_from_user(vaddr, user_data, args->size); | ||
4894 | mutex_lock(&dev->struct_mutex); | ||
4895 | if (unwritten) | ||
4896 | return -EFAULT; | ||
4897 | } | ||
4870 | 4898 | ||
4871 | drm_agp_chipset_flush(dev); | 4899 | drm_agp_chipset_flush(dev); |
4872 | return 0; | 4900 | return 0; |
@@ -4900,9 +4928,7 @@ i915_gpu_is_active(struct drm_device *dev) | |||
4900 | int lists_empty; | 4928 | int lists_empty; |
4901 | 4929 | ||
4902 | lists_empty = list_empty(&dev_priv->mm.flushing_list) && | 4930 | lists_empty = list_empty(&dev_priv->mm.flushing_list) && |
4903 | list_empty(&dev_priv->render_ring.active_list) && | 4931 | list_empty(&dev_priv->mm.active_list); |
4904 | list_empty(&dev_priv->bsd_ring.active_list) && | ||
4905 | list_empty(&dev_priv->blt_ring.active_list); | ||
4906 | 4932 | ||
4907 | return !lists_empty; | 4933 | return !lists_empty; |
4908 | } | 4934 | } |
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 43a4013f53fa..d8ae7d1d0cc6 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c | |||
@@ -165,9 +165,7 @@ i915_gem_evict_everything(struct drm_device *dev) | |||
165 | 165 | ||
166 | lists_empty = (list_empty(&dev_priv->mm.inactive_list) && | 166 | lists_empty = (list_empty(&dev_priv->mm.inactive_list) && |
167 | list_empty(&dev_priv->mm.flushing_list) && | 167 | list_empty(&dev_priv->mm.flushing_list) && |
168 | list_empty(&dev_priv->render_ring.active_list) && | 168 | list_empty(&dev_priv->mm.active_list)); |
169 | list_empty(&dev_priv->bsd_ring.active_list) && | ||
170 | list_empty(&dev_priv->blt_ring.active_list)); | ||
171 | if (lists_empty) | 169 | if (lists_empty) |
172 | return -ENOSPC; | 170 | return -ENOSPC; |
173 | 171 | ||
@@ -184,9 +182,7 @@ i915_gem_evict_everything(struct drm_device *dev) | |||
184 | 182 | ||
185 | lists_empty = (list_empty(&dev_priv->mm.inactive_list) && | 183 | lists_empty = (list_empty(&dev_priv->mm.inactive_list) && |
186 | list_empty(&dev_priv->mm.flushing_list) && | 184 | list_empty(&dev_priv->mm.flushing_list) && |
187 | list_empty(&dev_priv->render_ring.active_list) && | 185 | list_empty(&dev_priv->mm.active_list)); |
188 | list_empty(&dev_priv->bsd_ring.active_list) && | ||
189 | list_empty(&dev_priv->blt_ring.active_list)); | ||
190 | BUG_ON(!lists_empty); | 186 | BUG_ON(!lists_empty); |
191 | 187 | ||
192 | return 0; | 188 | return 0; |
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 989c19d2d959..454c064f8ef7 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c | |||
@@ -862,8 +862,10 @@ int i915_restore_state(struct drm_device *dev) | |||
862 | /* Clock gating state */ | 862 | /* Clock gating state */ |
863 | intel_init_clock_gating(dev); | 863 | intel_init_clock_gating(dev); |
864 | 864 | ||
865 | if (HAS_PCH_SPLIT(dev)) | 865 | if (HAS_PCH_SPLIT(dev)) { |
866 | ironlake_enable_drps(dev); | 866 | ironlake_enable_drps(dev); |
867 | intel_init_emon(dev); | ||
868 | } | ||
867 | 869 | ||
868 | /* Cache mode state */ | 870 | /* Cache mode state */ |
869 | I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000); | 871 | I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000); |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 990f065374b2..48d8fd686ea9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -1681,6 +1681,37 @@ static void ironlake_set_pll_edp(struct drm_crtc *crtc, int clock) | |||
1681 | udelay(500); | 1681 | udelay(500); |
1682 | } | 1682 | } |
1683 | 1683 | ||
1684 | static void intel_fdi_normal_train(struct drm_crtc *crtc) | ||
1685 | { | ||
1686 | struct drm_device *dev = crtc->dev; | ||
1687 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
1688 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
1689 | int pipe = intel_crtc->pipe; | ||
1690 | u32 reg, temp; | ||
1691 | |||
1692 | /* enable normal train */ | ||
1693 | reg = FDI_TX_CTL(pipe); | ||
1694 | temp = I915_READ(reg); | ||
1695 | temp &= ~FDI_LINK_TRAIN_NONE; | ||
1696 | temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE; | ||
1697 | I915_WRITE(reg, temp); | ||
1698 | |||
1699 | reg = FDI_RX_CTL(pipe); | ||
1700 | temp = I915_READ(reg); | ||
1701 | if (HAS_PCH_CPT(dev)) { | ||
1702 | temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; | ||
1703 | temp |= FDI_LINK_TRAIN_NORMAL_CPT; | ||
1704 | } else { | ||
1705 | temp &= ~FDI_LINK_TRAIN_NONE; | ||
1706 | temp |= FDI_LINK_TRAIN_NONE; | ||
1707 | } | ||
1708 | I915_WRITE(reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE); | ||
1709 | |||
1710 | /* wait one idle pattern time */ | ||
1711 | POSTING_READ(reg); | ||
1712 | udelay(1000); | ||
1713 | } | ||
1714 | |||
1684 | /* The FDI link training functions for ILK/Ibexpeak. */ | 1715 | /* The FDI link training functions for ILK/Ibexpeak. */ |
1685 | static void ironlake_fdi_link_train(struct drm_crtc *crtc) | 1716 | static void ironlake_fdi_link_train(struct drm_crtc *crtc) |
1686 | { | 1717 | { |
@@ -1767,27 +1798,6 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc) | |||
1767 | 1798 | ||
1768 | DRM_DEBUG_KMS("FDI train done\n"); | 1799 | DRM_DEBUG_KMS("FDI train done\n"); |
1769 | 1800 | ||
1770 | /* enable normal train */ | ||
1771 | reg = FDI_TX_CTL(pipe); | ||
1772 | temp = I915_READ(reg); | ||
1773 | temp &= ~FDI_LINK_TRAIN_NONE; | ||
1774 | temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE; | ||
1775 | I915_WRITE(reg, temp); | ||
1776 | |||
1777 | reg = FDI_RX_CTL(pipe); | ||
1778 | temp = I915_READ(reg); | ||
1779 | if (HAS_PCH_CPT(dev)) { | ||
1780 | temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; | ||
1781 | temp |= FDI_LINK_TRAIN_NORMAL_CPT; | ||
1782 | } else { | ||
1783 | temp &= ~FDI_LINK_TRAIN_NONE; | ||
1784 | temp |= FDI_LINK_TRAIN_NONE; | ||
1785 | } | ||
1786 | I915_WRITE(reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE); | ||
1787 | |||
1788 | /* wait one idle pattern time */ | ||
1789 | POSTING_READ(reg); | ||
1790 | udelay(1000); | ||
1791 | } | 1801 | } |
1792 | 1802 | ||
1793 | static const int const snb_b_fdi_train_param [] = { | 1803 | static const int const snb_b_fdi_train_param [] = { |
@@ -2090,6 +2100,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) | |||
2090 | I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe))); | 2100 | I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe))); |
2091 | I915_WRITE(TRANS_VSYNC(pipe), I915_READ(VSYNC(pipe))); | 2101 | I915_WRITE(TRANS_VSYNC(pipe), I915_READ(VSYNC(pipe))); |
2092 | 2102 | ||
2103 | intel_fdi_normal_train(crtc); | ||
2104 | |||
2093 | /* For PCH DP, enable TRANS_DP_CTL */ | 2105 | /* For PCH DP, enable TRANS_DP_CTL */ |
2094 | if (HAS_PCH_CPT(dev) && | 2106 | if (HAS_PCH_CPT(dev) && |
2095 | intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) { | 2107 | intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) { |
@@ -2200,9 +2212,10 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) | |||
2200 | udelay(100); | 2212 | udelay(100); |
2201 | 2213 | ||
2202 | /* Ironlake workaround, disable clock pointer after downing FDI */ | 2214 | /* Ironlake workaround, disable clock pointer after downing FDI */ |
2203 | I915_WRITE(FDI_RX_CHICKEN(pipe), | 2215 | if (HAS_PCH_IBX(dev)) |
2204 | I915_READ(FDI_RX_CHICKEN(pipe) & | 2216 | I915_WRITE(FDI_RX_CHICKEN(pipe), |
2205 | ~FDI_RX_PHASE_SYNC_POINTER_ENABLE)); | 2217 | I915_READ(FDI_RX_CHICKEN(pipe) & |
2218 | ~FDI_RX_PHASE_SYNC_POINTER_ENABLE)); | ||
2206 | 2219 | ||
2207 | /* still set train pattern 1 */ | 2220 | /* still set train pattern 1 */ |
2208 | reg = FDI_TX_CTL(pipe); | 2221 | reg = FDI_TX_CTL(pipe); |
@@ -5581,20 +5594,19 @@ void ironlake_enable_drps(struct drm_device *dev) | |||
5581 | fmin = (rgvmodectl & MEMMODE_FMIN_MASK); | 5594 | fmin = (rgvmodectl & MEMMODE_FMIN_MASK); |
5582 | fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >> | 5595 | fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >> |
5583 | MEMMODE_FSTART_SHIFT; | 5596 | MEMMODE_FSTART_SHIFT; |
5584 | fstart = fmax; | ||
5585 | 5597 | ||
5586 | vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >> | 5598 | vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >> |
5587 | PXVFREQ_PX_SHIFT; | 5599 | PXVFREQ_PX_SHIFT; |
5588 | 5600 | ||
5589 | dev_priv->fmax = fstart; /* IPS callback will increase this */ | 5601 | dev_priv->fmax = fmax; /* IPS callback will increase this */ |
5590 | dev_priv->fstart = fstart; | 5602 | dev_priv->fstart = fstart; |
5591 | 5603 | ||
5592 | dev_priv->max_delay = fmax; | 5604 | dev_priv->max_delay = fstart; |
5593 | dev_priv->min_delay = fmin; | 5605 | dev_priv->min_delay = fmin; |
5594 | dev_priv->cur_delay = fstart; | 5606 | dev_priv->cur_delay = fstart; |
5595 | 5607 | ||
5596 | DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n", fmax, fmin, | 5608 | DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n", |
5597 | fstart); | 5609 | fmax, fmin, fstart); |
5598 | 5610 | ||
5599 | I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN); | 5611 | I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN); |
5600 | 5612 | ||
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 891f4f1d63b1..c8e005553310 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
@@ -1517,7 +1517,7 @@ g4x_dp_detect(struct intel_dp *intel_dp) | |||
1517 | status = connector_status_connected; | 1517 | status = connector_status_connected; |
1518 | } | 1518 | } |
1519 | 1519 | ||
1520 | return bit; | 1520 | return status; |
1521 | } | 1521 | } |
1522 | 1522 | ||
1523 | /** | 1523 | /** |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9af9f86a8765..21551fe74541 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
@@ -296,6 +296,7 @@ extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, | |||
296 | extern void intel_init_clock_gating(struct drm_device *dev); | 296 | extern void intel_init_clock_gating(struct drm_device *dev); |
297 | extern void ironlake_enable_drps(struct drm_device *dev); | 297 | extern void ironlake_enable_drps(struct drm_device *dev); |
298 | extern void ironlake_disable_drps(struct drm_device *dev); | 298 | extern void ironlake_disable_drps(struct drm_device *dev); |
299 | extern void intel_init_emon(struct drm_device *dev); | ||
299 | 300 | ||
300 | extern int intel_pin_and_fence_fb_obj(struct drm_device *dev, | 301 | extern int intel_pin_and_fence_fb_obj(struct drm_device *dev, |
301 | struct drm_gem_object *obj, | 302 | struct drm_gem_object *obj, |
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index f1a649990ea9..4324a326f98e 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
@@ -481,11 +481,8 @@ static int intel_lvds_get_modes(struct drm_connector *connector) | |||
481 | struct drm_device *dev = connector->dev; | 481 | struct drm_device *dev = connector->dev; |
482 | struct drm_display_mode *mode; | 482 | struct drm_display_mode *mode; |
483 | 483 | ||
484 | if (intel_lvds->edid) { | 484 | if (intel_lvds->edid) |
485 | drm_mode_connector_update_edid_property(connector, | ||
486 | intel_lvds->edid); | ||
487 | return drm_add_edid_modes(connector, intel_lvds->edid); | 485 | return drm_add_edid_modes(connector, intel_lvds->edid); |
488 | } | ||
489 | 486 | ||
490 | mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode); | 487 | mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode); |
491 | if (mode == 0) | 488 | if (mode == 0) |
@@ -939,7 +936,16 @@ void intel_lvds_init(struct drm_device *dev) | |||
939 | */ | 936 | */ |
940 | intel_lvds->edid = drm_get_edid(connector, | 937 | intel_lvds->edid = drm_get_edid(connector, |
941 | &dev_priv->gmbus[pin].adapter); | 938 | &dev_priv->gmbus[pin].adapter); |
942 | 939 | if (intel_lvds->edid) { | |
940 | if (drm_add_edid_modes(connector, | ||
941 | intel_lvds->edid)) { | ||
942 | drm_mode_connector_update_edid_property(connector, | ||
943 | intel_lvds->edid); | ||
944 | } else { | ||
945 | kfree(intel_lvds->edid); | ||
946 | intel_lvds->edid = NULL; | ||
947 | } | ||
948 | } | ||
943 | if (!intel_lvds->edid) { | 949 | if (!intel_lvds->edid) { |
944 | /* Didn't get an EDID, so | 950 | /* Didn't get an EDID, so |
945 | * Set wide sync ranges so we get all modes | 951 | * Set wide sync ranges so we get all modes |
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 917c7dc3cd6b..9b0d9a867aea 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c | |||
@@ -512,6 +512,6 @@ int intel_opregion_setup(struct drm_device *dev) | |||
512 | return 0; | 512 | return 0; |
513 | 513 | ||
514 | err_out: | 514 | err_out: |
515 | iounmap(opregion->header); | 515 | iounmap(base); |
516 | return err; | 516 | return err; |
517 | } | 517 | } |
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index afb96d25219a..02ff0a481f47 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c | |||
@@ -946,7 +946,9 @@ static int check_overlay_src(struct drm_device *dev, | |||
946 | { | 946 | { |
947 | int uv_hscale = uv_hsubsampling(rec->flags); | 947 | int uv_hscale = uv_hsubsampling(rec->flags); |
948 | int uv_vscale = uv_vsubsampling(rec->flags); | 948 | int uv_vscale = uv_vsubsampling(rec->flags); |
949 | u32 stride_mask, depth, tmp; | 949 | u32 stride_mask; |
950 | int depth; | ||
951 | u32 tmp; | ||
950 | 952 | ||
951 | /* check src dimensions */ | 953 | /* check src dimensions */ |
952 | if (IS_845G(dev) || IS_I830(dev)) { | 954 | if (IS_845G(dev) || IS_I830(dev)) { |
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 09f2dc353ae2..b83306f9244b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c | |||
@@ -177,7 +177,7 @@ static int init_ring_common(struct drm_device *dev, | |||
177 | 177 | ||
178 | I915_WRITE_CTL(ring, | 178 | I915_WRITE_CTL(ring, |
179 | ((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES) | 179 | ((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES) |
180 | | RING_NO_REPORT | RING_VALID); | 180 | | RING_REPORT_64K | RING_VALID); |
181 | 181 | ||
182 | head = I915_READ_HEAD(ring) & HEAD_ADDR; | 182 | head = I915_READ_HEAD(ring) & HEAD_ADDR; |
183 | /* If the head is still not zero, the ring is dead */ | 183 | /* If the head is still not zero, the ring is dead */ |
@@ -654,6 +654,10 @@ void intel_cleanup_ring_buffer(struct drm_device *dev, | |||
654 | i915_gem_object_unpin(ring->gem_object); | 654 | i915_gem_object_unpin(ring->gem_object); |
655 | drm_gem_object_unreference(ring->gem_object); | 655 | drm_gem_object_unreference(ring->gem_object); |
656 | ring->gem_object = NULL; | 656 | ring->gem_object = NULL; |
657 | |||
658 | if (ring->cleanup) | ||
659 | ring->cleanup(ring); | ||
660 | |||
657 | cleanup_status_page(dev, ring); | 661 | cleanup_status_page(dev, ring); |
658 | } | 662 | } |
659 | 663 | ||
@@ -688,6 +692,17 @@ int intel_wait_ring_buffer(struct drm_device *dev, | |||
688 | { | 692 | { |
689 | unsigned long end; | 693 | unsigned long end; |
690 | drm_i915_private_t *dev_priv = dev->dev_private; | 694 | drm_i915_private_t *dev_priv = dev->dev_private; |
695 | u32 head; | ||
696 | |||
697 | head = intel_read_status_page(ring, 4); | ||
698 | if (head) { | ||
699 | ring->head = head & HEAD_ADDR; | ||
700 | ring->space = ring->head - (ring->tail + 8); | ||
701 | if (ring->space < 0) | ||
702 | ring->space += ring->size; | ||
703 | if (ring->space >= n) | ||
704 | return 0; | ||
705 | } | ||
691 | 706 | ||
692 | trace_i915_ring_wait_begin (dev); | 707 | trace_i915_ring_wait_begin (dev); |
693 | end = jiffies + 3 * HZ; | 708 | end = jiffies + 3 * HZ; |
@@ -854,19 +869,125 @@ blt_ring_put_user_irq(struct drm_device *dev, | |||
854 | /* do nothing */ | 869 | /* do nothing */ |
855 | } | 870 | } |
856 | 871 | ||
872 | |||
873 | /* Workaround for some stepping of SNB, | ||
874 | * each time when BLT engine ring tail moved, | ||
875 | * the first command in the ring to be parsed | ||
876 | * should be MI_BATCH_BUFFER_START | ||
877 | */ | ||
878 | #define NEED_BLT_WORKAROUND(dev) \ | ||
879 | (IS_GEN6(dev) && (dev->pdev->revision < 8)) | ||
880 | |||
881 | static inline struct drm_i915_gem_object * | ||
882 | to_blt_workaround(struct intel_ring_buffer *ring) | ||
883 | { | ||
884 | return ring->private; | ||
885 | } | ||
886 | |||
887 | static int blt_ring_init(struct drm_device *dev, | ||
888 | struct intel_ring_buffer *ring) | ||
889 | { | ||
890 | if (NEED_BLT_WORKAROUND(dev)) { | ||
891 | struct drm_i915_gem_object *obj; | ||
892 | u32 __iomem *ptr; | ||
893 | int ret; | ||
894 | |||
895 | obj = to_intel_bo(i915_gem_alloc_object(dev, 4096)); | ||
896 | if (obj == NULL) | ||
897 | return -ENOMEM; | ||
898 | |||
899 | ret = i915_gem_object_pin(&obj->base, 4096); | ||
900 | if (ret) { | ||
901 | drm_gem_object_unreference(&obj->base); | ||
902 | return ret; | ||
903 | } | ||
904 | |||
905 | ptr = kmap(obj->pages[0]); | ||
906 | iowrite32(MI_BATCH_BUFFER_END, ptr); | ||
907 | iowrite32(MI_NOOP, ptr+1); | ||
908 | kunmap(obj->pages[0]); | ||
909 | |||
910 | ret = i915_gem_object_set_to_gtt_domain(&obj->base, false); | ||
911 | if (ret) { | ||
912 | i915_gem_object_unpin(&obj->base); | ||
913 | drm_gem_object_unreference(&obj->base); | ||
914 | return ret; | ||
915 | } | ||
916 | |||
917 | ring->private = obj; | ||
918 | } | ||
919 | |||
920 | return init_ring_common(dev, ring); | ||
921 | } | ||
922 | |||
923 | static void blt_ring_begin(struct drm_device *dev, | ||
924 | struct intel_ring_buffer *ring, | ||
925 | int num_dwords) | ||
926 | { | ||
927 | if (ring->private) { | ||
928 | intel_ring_begin(dev, ring, num_dwords+2); | ||
929 | intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START); | ||
930 | intel_ring_emit(dev, ring, to_blt_workaround(ring)->gtt_offset); | ||
931 | } else | ||
932 | intel_ring_begin(dev, ring, 4); | ||
933 | } | ||
934 | |||
935 | static void blt_ring_flush(struct drm_device *dev, | ||
936 | struct intel_ring_buffer *ring, | ||
937 | u32 invalidate_domains, | ||
938 | u32 flush_domains) | ||
939 | { | ||
940 | blt_ring_begin(dev, ring, 4); | ||
941 | intel_ring_emit(dev, ring, MI_FLUSH_DW); | ||
942 | intel_ring_emit(dev, ring, 0); | ||
943 | intel_ring_emit(dev, ring, 0); | ||
944 | intel_ring_emit(dev, ring, 0); | ||
945 | intel_ring_advance(dev, ring); | ||
946 | } | ||
947 | |||
948 | static u32 | ||
949 | blt_ring_add_request(struct drm_device *dev, | ||
950 | struct intel_ring_buffer *ring, | ||
951 | u32 flush_domains) | ||
952 | { | ||
953 | u32 seqno = i915_gem_get_seqno(dev); | ||
954 | |||
955 | blt_ring_begin(dev, ring, 4); | ||
956 | intel_ring_emit(dev, ring, MI_STORE_DWORD_INDEX); | ||
957 | intel_ring_emit(dev, ring, | ||
958 | I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); | ||
959 | intel_ring_emit(dev, ring, seqno); | ||
960 | intel_ring_emit(dev, ring, MI_USER_INTERRUPT); | ||
961 | intel_ring_advance(dev, ring); | ||
962 | |||
963 | DRM_DEBUG_DRIVER("%s %d\n", ring->name, seqno); | ||
964 | return seqno; | ||
965 | } | ||
966 | |||
967 | static void blt_ring_cleanup(struct intel_ring_buffer *ring) | ||
968 | { | ||
969 | if (!ring->private) | ||
970 | return; | ||
971 | |||
972 | i915_gem_object_unpin(ring->private); | ||
973 | drm_gem_object_unreference(ring->private); | ||
974 | ring->private = NULL; | ||
975 | } | ||
976 | |||
857 | static const struct intel_ring_buffer gen6_blt_ring = { | 977 | static const struct intel_ring_buffer gen6_blt_ring = { |
858 | .name = "blt ring", | 978 | .name = "blt ring", |
859 | .id = RING_BLT, | 979 | .id = RING_BLT, |
860 | .mmio_base = BLT_RING_BASE, | 980 | .mmio_base = BLT_RING_BASE, |
861 | .size = 32 * PAGE_SIZE, | 981 | .size = 32 * PAGE_SIZE, |
862 | .init = init_ring_common, | 982 | .init = blt_ring_init, |
863 | .write_tail = ring_write_tail, | 983 | .write_tail = ring_write_tail, |
864 | .flush = gen6_ring_flush, | 984 | .flush = blt_ring_flush, |
865 | .add_request = ring_add_request, | 985 | .add_request = blt_ring_add_request, |
866 | .get_seqno = ring_status_page_get_seqno, | 986 | .get_seqno = ring_status_page_get_seqno, |
867 | .user_irq_get = blt_ring_get_user_irq, | 987 | .user_irq_get = blt_ring_get_user_irq, |
868 | .user_irq_put = blt_ring_put_user_irq, | 988 | .user_irq_put = blt_ring_put_user_irq, |
869 | .dispatch_gem_execbuffer = gen6_ring_dispatch_gem_execbuffer, | 989 | .dispatch_gem_execbuffer = gen6_ring_dispatch_gem_execbuffer, |
990 | .cleanup = blt_ring_cleanup, | ||
870 | }; | 991 | }; |
871 | 992 | ||
872 | int intel_init_render_ring_buffer(struct drm_device *dev) | 993 | int intel_init_render_ring_buffer(struct drm_device *dev) |
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index a05aff0e5764..3126c2681983 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h | |||
@@ -63,6 +63,7 @@ struct intel_ring_buffer { | |||
63 | struct drm_i915_gem_execbuffer2 *exec, | 63 | struct drm_i915_gem_execbuffer2 *exec, |
64 | struct drm_clip_rect *cliprects, | 64 | struct drm_clip_rect *cliprects, |
65 | uint64_t exec_offset); | 65 | uint64_t exec_offset); |
66 | void (*cleanup)(struct intel_ring_buffer *ring); | ||
66 | 67 | ||
67 | /** | 68 | /** |
68 | * List of objects currently involved in rendering from the | 69 | * List of objects currently involved in rendering from the |
@@ -98,6 +99,8 @@ struct intel_ring_buffer { | |||
98 | 99 | ||
99 | wait_queue_head_t irq_queue; | 100 | wait_queue_head_t irq_queue; |
100 | drm_local_map_t map; | 101 | drm_local_map_t map; |
102 | |||
103 | void *private; | ||
101 | }; | 104 | }; |
102 | 105 | ||
103 | static inline u32 | 106 | static inline u32 |
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index f12a5b3ec050..488c36c8f5e6 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c | |||
@@ -2033,7 +2033,7 @@ int evergreen_irq_set(struct radeon_device *rdev) | |||
2033 | u32 grbm_int_cntl = 0; | 2033 | u32 grbm_int_cntl = 0; |
2034 | 2034 | ||
2035 | if (!rdev->irq.installed) { | 2035 | if (!rdev->irq.installed) { |
2036 | WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n"); | 2036 | WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); |
2037 | return -EINVAL; | 2037 | return -EINVAL; |
2038 | } | 2038 | } |
2039 | /* don't enable anything if the ih is disabled */ | 2039 | /* don't enable anything if the ih is disabled */ |
@@ -2295,6 +2295,7 @@ restart_ih: | |||
2295 | case 0: /* D1 vblank */ | 2295 | case 0: /* D1 vblank */ |
2296 | if (disp_int & LB_D1_VBLANK_INTERRUPT) { | 2296 | if (disp_int & LB_D1_VBLANK_INTERRUPT) { |
2297 | drm_handle_vblank(rdev->ddev, 0); | 2297 | drm_handle_vblank(rdev->ddev, 0); |
2298 | rdev->pm.vblank_sync = true; | ||
2298 | wake_up(&rdev->irq.vblank_queue); | 2299 | wake_up(&rdev->irq.vblank_queue); |
2299 | disp_int &= ~LB_D1_VBLANK_INTERRUPT; | 2300 | disp_int &= ~LB_D1_VBLANK_INTERRUPT; |
2300 | DRM_DEBUG("IH: D1 vblank\n"); | 2301 | DRM_DEBUG("IH: D1 vblank\n"); |
@@ -2316,6 +2317,7 @@ restart_ih: | |||
2316 | case 0: /* D2 vblank */ | 2317 | case 0: /* D2 vblank */ |
2317 | if (disp_int_cont & LB_D2_VBLANK_INTERRUPT) { | 2318 | if (disp_int_cont & LB_D2_VBLANK_INTERRUPT) { |
2318 | drm_handle_vblank(rdev->ddev, 1); | 2319 | drm_handle_vblank(rdev->ddev, 1); |
2320 | rdev->pm.vblank_sync = true; | ||
2319 | wake_up(&rdev->irq.vblank_queue); | 2321 | wake_up(&rdev->irq.vblank_queue); |
2320 | disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; | 2322 | disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; |
2321 | DRM_DEBUG("IH: D2 vblank\n"); | 2323 | DRM_DEBUG("IH: D2 vblank\n"); |
@@ -2337,6 +2339,7 @@ restart_ih: | |||
2337 | case 0: /* D3 vblank */ | 2339 | case 0: /* D3 vblank */ |
2338 | if (disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) { | 2340 | if (disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) { |
2339 | drm_handle_vblank(rdev->ddev, 2); | 2341 | drm_handle_vblank(rdev->ddev, 2); |
2342 | rdev->pm.vblank_sync = true; | ||
2340 | wake_up(&rdev->irq.vblank_queue); | 2343 | wake_up(&rdev->irq.vblank_queue); |
2341 | disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; | 2344 | disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; |
2342 | DRM_DEBUG("IH: D3 vblank\n"); | 2345 | DRM_DEBUG("IH: D3 vblank\n"); |
@@ -2358,6 +2361,7 @@ restart_ih: | |||
2358 | case 0: /* D4 vblank */ | 2361 | case 0: /* D4 vblank */ |
2359 | if (disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) { | 2362 | if (disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) { |
2360 | drm_handle_vblank(rdev->ddev, 3); | 2363 | drm_handle_vblank(rdev->ddev, 3); |
2364 | rdev->pm.vblank_sync = true; | ||
2361 | wake_up(&rdev->irq.vblank_queue); | 2365 | wake_up(&rdev->irq.vblank_queue); |
2362 | disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; | 2366 | disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; |
2363 | DRM_DEBUG("IH: D4 vblank\n"); | 2367 | DRM_DEBUG("IH: D4 vblank\n"); |
@@ -2379,6 +2383,7 @@ restart_ih: | |||
2379 | case 0: /* D5 vblank */ | 2383 | case 0: /* D5 vblank */ |
2380 | if (disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) { | 2384 | if (disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) { |
2381 | drm_handle_vblank(rdev->ddev, 4); | 2385 | drm_handle_vblank(rdev->ddev, 4); |
2386 | rdev->pm.vblank_sync = true; | ||
2382 | wake_up(&rdev->irq.vblank_queue); | 2387 | wake_up(&rdev->irq.vblank_queue); |
2383 | disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; | 2388 | disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; |
2384 | DRM_DEBUG("IH: D5 vblank\n"); | 2389 | DRM_DEBUG("IH: D5 vblank\n"); |
@@ -2400,6 +2405,7 @@ restart_ih: | |||
2400 | case 0: /* D6 vblank */ | 2405 | case 0: /* D6 vblank */ |
2401 | if (disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) { | 2406 | if (disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) { |
2402 | drm_handle_vblank(rdev->ddev, 5); | 2407 | drm_handle_vblank(rdev->ddev, 5); |
2408 | rdev->pm.vblank_sync = true; | ||
2403 | wake_up(&rdev->irq.vblank_queue); | 2409 | wake_up(&rdev->irq.vblank_queue); |
2404 | disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; | 2410 | disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; |
2405 | DRM_DEBUG("IH: D6 vblank\n"); | 2411 | DRM_DEBUG("IH: D6 vblank\n"); |
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 0e8f28a68927..8e10aa9f74b0 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c | |||
@@ -442,7 +442,7 @@ int r100_pci_gart_init(struct radeon_device *rdev) | |||
442 | int r; | 442 | int r; |
443 | 443 | ||
444 | if (rdev->gart.table.ram.ptr) { | 444 | if (rdev->gart.table.ram.ptr) { |
445 | WARN(1, "R100 PCI GART already initialized.\n"); | 445 | WARN(1, "R100 PCI GART already initialized\n"); |
446 | return 0; | 446 | return 0; |
447 | } | 447 | } |
448 | /* Initialize common gart structure */ | 448 | /* Initialize common gart structure */ |
@@ -516,7 +516,7 @@ int r100_irq_set(struct radeon_device *rdev) | |||
516 | uint32_t tmp = 0; | 516 | uint32_t tmp = 0; |
517 | 517 | ||
518 | if (!rdev->irq.installed) { | 518 | if (!rdev->irq.installed) { |
519 | WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n"); | 519 | WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); |
520 | WREG32(R_000040_GEN_INT_CNTL, 0); | 520 | WREG32(R_000040_GEN_INT_CNTL, 0); |
521 | return -EINVAL; | 521 | return -EINVAL; |
522 | } | 522 | } |
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 34527e600fe9..cde1d3480d93 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c | |||
@@ -91,7 +91,7 @@ int rv370_pcie_gart_init(struct radeon_device *rdev) | |||
91 | int r; | 91 | int r; |
92 | 92 | ||
93 | if (rdev->gart.table.vram.robj) { | 93 | if (rdev->gart.table.vram.robj) { |
94 | WARN(1, "RV370 PCIE GART already initialized.\n"); | 94 | WARN(1, "RV370 PCIE GART already initialized\n"); |
95 | return 0; | 95 | return 0; |
96 | } | 96 | } |
97 | /* Initialize common gart structure */ | 97 | /* Initialize common gart structure */ |
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 33952a12f0a3..0f806cc7dc75 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c | |||
@@ -97,14 +97,8 @@ u32 rv6xx_get_temp(struct radeon_device *rdev) | |||
97 | { | 97 | { |
98 | u32 temp = (RREG32(CG_THERMAL_STATUS) & ASIC_T_MASK) >> | 98 | u32 temp = (RREG32(CG_THERMAL_STATUS) & ASIC_T_MASK) >> |
99 | ASIC_T_SHIFT; | 99 | ASIC_T_SHIFT; |
100 | u32 actual_temp = 0; | ||
101 | 100 | ||
102 | if ((temp >> 7) & 1) | 101 | return temp * 1000; |
103 | actual_temp = 0; | ||
104 | else | ||
105 | actual_temp = (temp >> 1) & 0xff; | ||
106 | |||
107 | return actual_temp * 1000; | ||
108 | } | 102 | } |
109 | 103 | ||
110 | void r600_pm_get_dynpm_state(struct radeon_device *rdev) | 104 | void r600_pm_get_dynpm_state(struct radeon_device *rdev) |
@@ -919,7 +913,7 @@ int r600_pcie_gart_init(struct radeon_device *rdev) | |||
919 | int r; | 913 | int r; |
920 | 914 | ||
921 | if (rdev->gart.table.vram.robj) { | 915 | if (rdev->gart.table.vram.robj) { |
922 | WARN(1, "R600 PCIE GART already initialized.\n"); | 916 | WARN(1, "R600 PCIE GART already initialized\n"); |
923 | return 0; | 917 | return 0; |
924 | } | 918 | } |
925 | /* Initialize common gart structure */ | 919 | /* Initialize common gart structure */ |
@@ -2995,7 +2989,7 @@ int r600_irq_set(struct radeon_device *rdev) | |||
2995 | u32 hdmi1, hdmi2; | 2989 | u32 hdmi1, hdmi2; |
2996 | 2990 | ||
2997 | if (!rdev->irq.installed) { | 2991 | if (!rdev->irq.installed) { |
2998 | WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n"); | 2992 | WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); |
2999 | return -EINVAL; | 2993 | return -EINVAL; |
3000 | } | 2994 | } |
3001 | /* don't enable anything if the ih is disabled */ | 2995 | /* don't enable anything if the ih is disabled */ |
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 04cac7ec9039..87ead090c7d5 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c | |||
@@ -526,8 +526,6 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) | |||
526 | if (crev < 2) | 526 | if (crev < 2) |
527 | return false; | 527 | return false; |
528 | 528 | ||
529 | router.valid = false; | ||
530 | |||
531 | obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset); | 529 | obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset); |
532 | path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *) | 530 | path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *) |
533 | (ctx->bios + data_offset + | 531 | (ctx->bios + data_offset + |
@@ -624,6 +622,8 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) | |||
624 | if (connector_type == DRM_MODE_CONNECTOR_Unknown) | 622 | if (connector_type == DRM_MODE_CONNECTOR_Unknown) |
625 | continue; | 623 | continue; |
626 | 624 | ||
625 | router.ddc_valid = false; | ||
626 | router.cd_valid = false; | ||
627 | for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) { | 627 | for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) { |
628 | uint8_t grph_obj_id, grph_obj_num, grph_obj_type; | 628 | uint8_t grph_obj_id, grph_obj_num, grph_obj_type; |
629 | 629 | ||
@@ -647,9 +647,8 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) | |||
647 | usDeviceTag)); | 647 | usDeviceTag)); |
648 | 648 | ||
649 | } else if (grph_obj_type == GRAPH_OBJECT_TYPE_ROUTER) { | 649 | } else if (grph_obj_type == GRAPH_OBJECT_TYPE_ROUTER) { |
650 | router.valid = false; | ||
651 | for (k = 0; k < router_obj->ucNumberOfObjects; k++) { | 650 | for (k = 0; k < router_obj->ucNumberOfObjects; k++) { |
652 | u16 router_obj_id = le16_to_cpu(router_obj->asObjects[j].usObjectID); | 651 | u16 router_obj_id = le16_to_cpu(router_obj->asObjects[k].usObjectID); |
653 | if (le16_to_cpu(path->usGraphicObjIds[j]) == router_obj_id) { | 652 | if (le16_to_cpu(path->usGraphicObjIds[j]) == router_obj_id) { |
654 | ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *) | 653 | ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *) |
655 | (ctx->bios + data_offset + | 654 | (ctx->bios + data_offset + |
@@ -657,6 +656,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) | |||
657 | ATOM_I2C_RECORD *i2c_record; | 656 | ATOM_I2C_RECORD *i2c_record; |
658 | ATOM_I2C_ID_CONFIG_ACCESS *i2c_config; | 657 | ATOM_I2C_ID_CONFIG_ACCESS *i2c_config; |
659 | ATOM_ROUTER_DDC_PATH_SELECT_RECORD *ddc_path; | 658 | ATOM_ROUTER_DDC_PATH_SELECT_RECORD *ddc_path; |
659 | ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *cd_path; | ||
660 | ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *router_src_dst_table = | 660 | ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *router_src_dst_table = |
661 | (ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *) | 661 | (ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *) |
662 | (ctx->bios + data_offset + | 662 | (ctx->bios + data_offset + |
@@ -690,10 +690,18 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) | |||
690 | case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE: | 690 | case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE: |
691 | ddc_path = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD *) | 691 | ddc_path = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD *) |
692 | record; | 692 | record; |
693 | router.valid = true; | 693 | router.ddc_valid = true; |
694 | router.mux_type = ddc_path->ucMuxType; | 694 | router.ddc_mux_type = ddc_path->ucMuxType; |
695 | router.mux_control_pin = ddc_path->ucMuxControlPin; | 695 | router.ddc_mux_control_pin = ddc_path->ucMuxControlPin; |
696 | router.mux_state = ddc_path->ucMuxState[enum_id]; | 696 | router.ddc_mux_state = ddc_path->ucMuxState[enum_id]; |
697 | break; | ||
698 | case ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE: | ||
699 | cd_path = (ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *) | ||
700 | record; | ||
701 | router.cd_valid = true; | ||
702 | router.cd_mux_type = cd_path->ucMuxType; | ||
703 | router.cd_mux_control_pin = cd_path->ucMuxControlPin; | ||
704 | router.cd_mux_state = cd_path->ucMuxState[enum_id]; | ||
697 | break; | 705 | break; |
698 | } | 706 | } |
699 | record = (ATOM_COMMON_RECORD_HEADER *) | 707 | record = (ATOM_COMMON_RECORD_HEADER *) |
@@ -860,7 +868,8 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct | |||
860 | size_t bc_size = sizeof(*bios_connectors) * ATOM_MAX_SUPPORTED_DEVICE; | 868 | size_t bc_size = sizeof(*bios_connectors) * ATOM_MAX_SUPPORTED_DEVICE; |
861 | struct radeon_router router; | 869 | struct radeon_router router; |
862 | 870 | ||
863 | router.valid = false; | 871 | router.ddc_valid = false; |
872 | router.cd_valid = false; | ||
864 | 873 | ||
865 | bios_connectors = kzalloc(bc_size, GFP_KERNEL); | 874 | bios_connectors = kzalloc(bc_size, GFP_KERNEL); |
866 | if (!bios_connectors) | 875 | if (!bios_connectors) |
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 4dac4b0a02ee..fe6c74780f18 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c | |||
@@ -183,13 +183,13 @@ radeon_connector_analog_encoder_conflict_solve(struct drm_connector *connector, | |||
183 | continue; | 183 | continue; |
184 | 184 | ||
185 | if (priority == true) { | 185 | if (priority == true) { |
186 | DRM_INFO("1: conflicting encoders switching off %s\n", drm_get_connector_name(conflict)); | 186 | DRM_DEBUG_KMS("1: conflicting encoders switching off %s\n", drm_get_connector_name(conflict)); |
187 | DRM_INFO("in favor of %s\n", drm_get_connector_name(connector)); | 187 | DRM_DEBUG_KMS("in favor of %s\n", drm_get_connector_name(connector)); |
188 | conflict->status = connector_status_disconnected; | 188 | conflict->status = connector_status_disconnected; |
189 | radeon_connector_update_scratch_regs(conflict, connector_status_disconnected); | 189 | radeon_connector_update_scratch_regs(conflict, connector_status_disconnected); |
190 | } else { | 190 | } else { |
191 | DRM_INFO("2: conflicting encoders switching off %s\n", drm_get_connector_name(connector)); | 191 | DRM_DEBUG_KMS("2: conflicting encoders switching off %s\n", drm_get_connector_name(connector)); |
192 | DRM_INFO("in favor of %s\n", drm_get_connector_name(conflict)); | 192 | DRM_DEBUG_KMS("in favor of %s\n", drm_get_connector_name(conflict)); |
193 | current_status = connector_status_disconnected; | 193 | current_status = connector_status_disconnected; |
194 | } | 194 | } |
195 | break; | 195 | break; |
@@ -432,13 +432,13 @@ static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder, | |||
432 | mode->vdisplay == native_mode->vdisplay) { | 432 | mode->vdisplay == native_mode->vdisplay) { |
433 | *native_mode = *mode; | 433 | *native_mode = *mode; |
434 | drm_mode_set_crtcinfo(native_mode, CRTC_INTERLACE_HALVE_V); | 434 | drm_mode_set_crtcinfo(native_mode, CRTC_INTERLACE_HALVE_V); |
435 | DRM_INFO("Determined LVDS native mode details from EDID\n"); | 435 | DRM_DEBUG_KMS("Determined LVDS native mode details from EDID\n"); |
436 | break; | 436 | break; |
437 | } | 437 | } |
438 | } | 438 | } |
439 | } | 439 | } |
440 | if (!native_mode->clock) { | 440 | if (!native_mode->clock) { |
441 | DRM_INFO("No LVDS native mode details, disabling RMX\n"); | 441 | DRM_DEBUG_KMS("No LVDS native mode details, disabling RMX\n"); |
442 | radeon_encoder->rmx_type = RMX_OFF; | 442 | radeon_encoder->rmx_type = RMX_OFF; |
443 | } | 443 | } |
444 | } | 444 | } |
@@ -1116,7 +1116,7 @@ radeon_add_atom_connector(struct drm_device *dev, | |||
1116 | radeon_connector->shared_ddc = true; | 1116 | radeon_connector->shared_ddc = true; |
1117 | shared_ddc = true; | 1117 | shared_ddc = true; |
1118 | } | 1118 | } |
1119 | if (radeon_connector->router_bus && router->valid && | 1119 | if (radeon_connector->router_bus && router->ddc_valid && |
1120 | (radeon_connector->router.router_id == router->router_id)) { | 1120 | (radeon_connector->router.router_id == router->router_id)) { |
1121 | radeon_connector->shared_ddc = false; | 1121 | radeon_connector->shared_ddc = false; |
1122 | shared_ddc = false; | 1122 | shared_ddc = false; |
@@ -1136,7 +1136,7 @@ radeon_add_atom_connector(struct drm_device *dev, | |||
1136 | radeon_connector->connector_object_id = connector_object_id; | 1136 | radeon_connector->connector_object_id = connector_object_id; |
1137 | radeon_connector->hpd = *hpd; | 1137 | radeon_connector->hpd = *hpd; |
1138 | radeon_connector->router = *router; | 1138 | radeon_connector->router = *router; |
1139 | if (router->valid) { | 1139 | if (router->ddc_valid || router->cd_valid) { |
1140 | radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info); | 1140 | radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info); |
1141 | if (!radeon_connector->router_bus) | 1141 | if (!radeon_connector->router_bus) |
1142 | goto failed; | 1142 | goto failed; |
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 0383631da69c..1df4dc6c063c 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c | |||
@@ -315,10 +315,14 @@ static void radeon_print_display_setup(struct drm_device *dev) | |||
315 | radeon_connector->ddc_bus->rec.en_data_reg, | 315 | radeon_connector->ddc_bus->rec.en_data_reg, |
316 | radeon_connector->ddc_bus->rec.y_clk_reg, | 316 | radeon_connector->ddc_bus->rec.y_clk_reg, |
317 | radeon_connector->ddc_bus->rec.y_data_reg); | 317 | radeon_connector->ddc_bus->rec.y_data_reg); |
318 | if (radeon_connector->router_bus) | 318 | if (radeon_connector->router.ddc_valid) |
319 | DRM_INFO(" DDC Router 0x%x/0x%x\n", | 319 | DRM_INFO(" DDC Router 0x%x/0x%x\n", |
320 | radeon_connector->router.mux_control_pin, | 320 | radeon_connector->router.ddc_mux_control_pin, |
321 | radeon_connector->router.mux_state); | 321 | radeon_connector->router.ddc_mux_state); |
322 | if (radeon_connector->router.cd_valid) | ||
323 | DRM_INFO(" Clock/Data Router 0x%x/0x%x\n", | ||
324 | radeon_connector->router.cd_mux_control_pin, | ||
325 | radeon_connector->router.cd_mux_state); | ||
322 | } else { | 326 | } else { |
323 | if (connector->connector_type == DRM_MODE_CONNECTOR_VGA || | 327 | if (connector->connector_type == DRM_MODE_CONNECTOR_VGA || |
324 | connector->connector_type == DRM_MODE_CONNECTOR_DVII || | 328 | connector->connector_type == DRM_MODE_CONNECTOR_DVII || |
@@ -398,8 +402,8 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) | |||
398 | int ret = 0; | 402 | int ret = 0; |
399 | 403 | ||
400 | /* on hw with routers, select right port */ | 404 | /* on hw with routers, select right port */ |
401 | if (radeon_connector->router.valid) | 405 | if (radeon_connector->router.ddc_valid) |
402 | radeon_router_select_port(radeon_connector); | 406 | radeon_router_select_ddc_port(radeon_connector); |
403 | 407 | ||
404 | if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || | 408 | if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || |
405 | (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) { | 409 | (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) { |
@@ -432,8 +436,8 @@ static int radeon_ddc_dump(struct drm_connector *connector) | |||
432 | int ret = 0; | 436 | int ret = 0; |
433 | 437 | ||
434 | /* on hw with routers, select right port */ | 438 | /* on hw with routers, select right port */ |
435 | if (radeon_connector->router.valid) | 439 | if (radeon_connector->router.ddc_valid) |
436 | radeon_router_select_port(radeon_connector); | 440 | radeon_router_select_ddc_port(radeon_connector); |
437 | 441 | ||
438 | if (!radeon_connector->ddc_bus) | 442 | if (!radeon_connector->ddc_bus) |
439 | return -1; | 443 | return -1; |
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index ae58b6849a2e..f678257c42e6 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c | |||
@@ -1520,6 +1520,7 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec | |||
1520 | static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) | 1520 | static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) |
1521 | { | 1521 | { |
1522 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | 1522 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
1523 | struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); | ||
1523 | 1524 | ||
1524 | if (radeon_encoder->active_device & | 1525 | if (radeon_encoder->active_device & |
1525 | (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) { | 1526 | (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) { |
@@ -1531,6 +1532,13 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) | |||
1531 | radeon_atom_output_lock(encoder, true); | 1532 | radeon_atom_output_lock(encoder, true); |
1532 | radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); | 1533 | radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); |
1533 | 1534 | ||
1535 | /* select the clock/data port if it uses a router */ | ||
1536 | if (connector) { | ||
1537 | struct radeon_connector *radeon_connector = to_radeon_connector(connector); | ||
1538 | if (radeon_connector->router.cd_valid) | ||
1539 | radeon_router_select_cd_port(radeon_connector); | ||
1540 | } | ||
1541 | |||
1534 | /* this is needed for the pll/ss setup to work correctly in some cases */ | 1542 | /* this is needed for the pll/ss setup to work correctly in some cases */ |
1535 | atombios_set_encoder_crtc_source(encoder); | 1543 | atombios_set_encoder_crtc_source(encoder); |
1536 | } | 1544 | } |
@@ -1547,6 +1555,23 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder) | |||
1547 | struct radeon_device *rdev = dev->dev_private; | 1555 | struct radeon_device *rdev = dev->dev_private; |
1548 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | 1556 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); |
1549 | struct radeon_encoder_atom_dig *dig; | 1557 | struct radeon_encoder_atom_dig *dig; |
1558 | |||
1559 | /* check for pre-DCE3 cards with shared encoders; | ||
1560 | * can't really use the links individually, so don't disable | ||
1561 | * the encoder if it's in use by another connector | ||
1562 | */ | ||
1563 | if (!ASIC_IS_DCE3(rdev)) { | ||
1564 | struct drm_encoder *other_encoder; | ||
1565 | struct radeon_encoder *other_radeon_encoder; | ||
1566 | |||
1567 | list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) { | ||
1568 | other_radeon_encoder = to_radeon_encoder(other_encoder); | ||
1569 | if ((radeon_encoder->encoder_id == other_radeon_encoder->encoder_id) && | ||
1570 | drm_helper_encoder_in_use(other_encoder)) | ||
1571 | goto disable_done; | ||
1572 | } | ||
1573 | } | ||
1574 | |||
1550 | radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); | 1575 | radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); |
1551 | 1576 | ||
1552 | switch (radeon_encoder->encoder_id) { | 1577 | switch (radeon_encoder->encoder_id) { |
@@ -1586,6 +1611,7 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder) | |||
1586 | break; | 1611 | break; |
1587 | } | 1612 | } |
1588 | 1613 | ||
1614 | disable_done: | ||
1589 | if (radeon_encoder_is_digital(encoder)) { | 1615 | if (radeon_encoder_is_digital(encoder)) { |
1590 | if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) | 1616 | if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) |
1591 | r600_hdmi_disable(encoder); | 1617 | r600_hdmi_disable(encoder); |
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 216392d0353b..daacb281dfaf 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c | |||
@@ -240,7 +240,8 @@ retry: | |||
240 | */ | 240 | */ |
241 | if (seq == rdev->fence_drv.last_seq && radeon_gpu_is_lockup(rdev)) { | 241 | if (seq == rdev->fence_drv.last_seq && radeon_gpu_is_lockup(rdev)) { |
242 | /* good news we believe it's a lockup */ | 242 | /* good news we believe it's a lockup */ |
243 | WARN(1, "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n", fence->seq, seq); | 243 | WARN(1, "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n", |
244 | fence->seq, seq); | ||
244 | /* FIXME: what should we do ? marking everyone | 245 | /* FIXME: what should we do ? marking everyone |
245 | * as signaled for now | 246 | * as signaled for now |
246 | */ | 247 | */ |
diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 6a13ee38a5b9..0cfbba02c4d0 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c | |||
@@ -53,8 +53,8 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector) | |||
53 | }; | 53 | }; |
54 | 54 | ||
55 | /* on hw with routers, select right port */ | 55 | /* on hw with routers, select right port */ |
56 | if (radeon_connector->router.valid) | 56 | if (radeon_connector->router.ddc_valid) |
57 | radeon_router_select_port(radeon_connector); | 57 | radeon_router_select_ddc_port(radeon_connector); |
58 | 58 | ||
59 | ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2); | 59 | ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2); |
60 | if (ret == 2) | 60 | if (ret == 2) |
@@ -1084,26 +1084,51 @@ void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c_bus, | |||
1084 | addr, val); | 1084 | addr, val); |
1085 | } | 1085 | } |
1086 | 1086 | ||
1087 | /* router switching */ | 1087 | /* ddc router switching */ |
1088 | void radeon_router_select_port(struct radeon_connector *radeon_connector) | 1088 | void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector) |
1089 | { | 1089 | { |
1090 | u8 val; | 1090 | u8 val; |
1091 | 1091 | ||
1092 | if (!radeon_connector->router.valid) | 1092 | if (!radeon_connector->router.ddc_valid) |
1093 | return; | 1093 | return; |
1094 | 1094 | ||
1095 | radeon_i2c_get_byte(radeon_connector->router_bus, | 1095 | radeon_i2c_get_byte(radeon_connector->router_bus, |
1096 | radeon_connector->router.i2c_addr, | 1096 | radeon_connector->router.i2c_addr, |
1097 | 0x3, &val); | 1097 | 0x3, &val); |
1098 | val &= radeon_connector->router.mux_control_pin; | 1098 | val &= ~radeon_connector->router.ddc_mux_control_pin; |
1099 | radeon_i2c_put_byte(radeon_connector->router_bus, | 1099 | radeon_i2c_put_byte(radeon_connector->router_bus, |
1100 | radeon_connector->router.i2c_addr, | 1100 | radeon_connector->router.i2c_addr, |
1101 | 0x3, val); | 1101 | 0x3, val); |
1102 | radeon_i2c_get_byte(radeon_connector->router_bus, | 1102 | radeon_i2c_get_byte(radeon_connector->router_bus, |
1103 | radeon_connector->router.i2c_addr, | 1103 | radeon_connector->router.i2c_addr, |
1104 | 0x1, &val); | 1104 | 0x1, &val); |
1105 | val &= radeon_connector->router.mux_control_pin; | 1105 | val &= ~radeon_connector->router.ddc_mux_control_pin; |
1106 | val |= radeon_connector->router.mux_state; | 1106 | val |= radeon_connector->router.ddc_mux_state; |
1107 | radeon_i2c_put_byte(radeon_connector->router_bus, | ||
1108 | radeon_connector->router.i2c_addr, | ||
1109 | 0x1, val); | ||
1110 | } | ||
1111 | |||
1112 | /* clock/data router switching */ | ||
1113 | void radeon_router_select_cd_port(struct radeon_connector *radeon_connector) | ||
1114 | { | ||
1115 | u8 val; | ||
1116 | |||
1117 | if (!radeon_connector->router.cd_valid) | ||
1118 | return; | ||
1119 | |||
1120 | radeon_i2c_get_byte(radeon_connector->router_bus, | ||
1121 | radeon_connector->router.i2c_addr, | ||
1122 | 0x3, &val); | ||
1123 | val &= ~radeon_connector->router.cd_mux_control_pin; | ||
1124 | radeon_i2c_put_byte(radeon_connector->router_bus, | ||
1125 | radeon_connector->router.i2c_addr, | ||
1126 | 0x3, val); | ||
1127 | radeon_i2c_get_byte(radeon_connector->router_bus, | ||
1128 | radeon_connector->router.i2c_addr, | ||
1129 | 0x1, &val); | ||
1130 | val &= ~radeon_connector->router.cd_mux_control_pin; | ||
1131 | val |= radeon_connector->router.cd_mux_state; | ||
1107 | radeon_i2c_put_byte(radeon_connector->router_bus, | 1132 | radeon_i2c_put_byte(radeon_connector->router_bus, |
1108 | radeon_connector->router.i2c_addr, | 1133 | radeon_connector->router.i2c_addr, |
1109 | 0x1, val); | 1134 | 0x1, val); |
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 92457163d070..680f57644e86 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
@@ -401,13 +401,19 @@ struct radeon_hpd { | |||
401 | }; | 401 | }; |
402 | 402 | ||
403 | struct radeon_router { | 403 | struct radeon_router { |
404 | bool valid; | ||
405 | u32 router_id; | 404 | u32 router_id; |
406 | struct radeon_i2c_bus_rec i2c_info; | 405 | struct radeon_i2c_bus_rec i2c_info; |
407 | u8 i2c_addr; | 406 | u8 i2c_addr; |
408 | u8 mux_type; | 407 | /* i2c mux */ |
409 | u8 mux_control_pin; | 408 | bool ddc_valid; |
410 | u8 mux_state; | 409 | u8 ddc_mux_type; |
410 | u8 ddc_mux_control_pin; | ||
411 | u8 ddc_mux_state; | ||
412 | /* clock/data mux */ | ||
413 | bool cd_valid; | ||
414 | u8 cd_mux_type; | ||
415 | u8 cd_mux_control_pin; | ||
416 | u8 cd_mux_state; | ||
411 | }; | 417 | }; |
412 | 418 | ||
413 | struct radeon_connector { | 419 | struct radeon_connector { |
@@ -488,7 +494,8 @@ extern void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c, | |||
488 | u8 slave_addr, | 494 | u8 slave_addr, |
489 | u8 addr, | 495 | u8 addr, |
490 | u8 val); | 496 | u8 val); |
491 | extern void radeon_router_select_port(struct radeon_connector *radeon_connector); | 497 | extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector); |
498 | extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector); | ||
492 | extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector); | 499 | extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector); |
493 | extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector); | 500 | extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector); |
494 | 501 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index d7ab91416410..8eb183466015 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c | |||
@@ -102,6 +102,8 @@ int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj, | |||
102 | type = ttm_bo_type_device; | 102 | type = ttm_bo_type_device; |
103 | } | 103 | } |
104 | *bo_ptr = NULL; | 104 | *bo_ptr = NULL; |
105 | |||
106 | retry: | ||
105 | bo = kzalloc(sizeof(struct radeon_bo), GFP_KERNEL); | 107 | bo = kzalloc(sizeof(struct radeon_bo), GFP_KERNEL); |
106 | if (bo == NULL) | 108 | if (bo == NULL) |
107 | return -ENOMEM; | 109 | return -ENOMEM; |
@@ -109,8 +111,6 @@ int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj, | |||
109 | bo->gobj = gobj; | 111 | bo->gobj = gobj; |
110 | bo->surface_reg = -1; | 112 | bo->surface_reg = -1; |
111 | INIT_LIST_HEAD(&bo->list); | 113 | INIT_LIST_HEAD(&bo->list); |
112 | |||
113 | retry: | ||
114 | radeon_ttm_placement_from_domain(bo, domain); | 114 | radeon_ttm_placement_from_domain(bo, domain); |
115 | /* Kernel allocation are uninterruptible */ | 115 | /* Kernel allocation are uninterruptible */ |
116 | mutex_lock(&rdev->vram_mutex); | 116 | mutex_lock(&rdev->vram_mutex); |
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index fe95bb35317e..01c2c736a1da 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c | |||
@@ -689,7 +689,8 @@ static int radeon_ttm_backend_bind(struct ttm_backend *backend, | |||
689 | gtt = container_of(backend, struct radeon_ttm_backend, backend); | 689 | gtt = container_of(backend, struct radeon_ttm_backend, backend); |
690 | gtt->offset = bo_mem->start << PAGE_SHIFT; | 690 | gtt->offset = bo_mem->start << PAGE_SHIFT; |
691 | if (!gtt->num_pages) { | 691 | if (!gtt->num_pages) { |
692 | WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n", gtt->num_pages, bo_mem, backend); | 692 | WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n", |
693 | gtt->num_pages, bo_mem, backend); | ||
693 | } | 694 | } |
694 | r = radeon_gart_bind(gtt->rdev, gtt->offset, | 695 | r = radeon_gart_bind(gtt->rdev, gtt->offset, |
695 | gtt->num_pages, gtt->pages); | 696 | gtt->num_pages, gtt->pages); |
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index f683e51a2a06..5512e4e5e636 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c | |||
@@ -78,7 +78,7 @@ int rs400_gart_init(struct radeon_device *rdev) | |||
78 | int r; | 78 | int r; |
79 | 79 | ||
80 | if (rdev->gart.table.ram.ptr) { | 80 | if (rdev->gart.table.ram.ptr) { |
81 | WARN(1, "RS400 GART already initialized.\n"); | 81 | WARN(1, "RS400 GART already initialized\n"); |
82 | return 0; | 82 | return 0; |
83 | } | 83 | } |
84 | /* Check gart size */ | 84 | /* Check gart size */ |
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index b091a1f6fa4e..f1c6e02c2e6b 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c | |||
@@ -375,7 +375,7 @@ int rs600_gart_init(struct radeon_device *rdev) | |||
375 | int r; | 375 | int r; |
376 | 376 | ||
377 | if (rdev->gart.table.vram.robj) { | 377 | if (rdev->gart.table.vram.robj) { |
378 | WARN(1, "RS600 GART already initialized.\n"); | 378 | WARN(1, "RS600 GART already initialized\n"); |
379 | return 0; | 379 | return 0; |
380 | } | 380 | } |
381 | /* Initialize common gart structure */ | 381 | /* Initialize common gart structure */ |
@@ -505,7 +505,7 @@ int rs600_irq_set(struct radeon_device *rdev) | |||
505 | ~S_007D18_DC_HOT_PLUG_DETECT2_INT_EN(1); | 505 | ~S_007D18_DC_HOT_PLUG_DETECT2_INT_EN(1); |
506 | 506 | ||
507 | if (!rdev->irq.installed) { | 507 | if (!rdev->irq.installed) { |
508 | WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n"); | 508 | WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); |
509 | WREG32(R_000040_GEN_INT_CNTL, 0); | 509 | WREG32(R_000040_GEN_INT_CNTL, 0); |
510 | return -EINVAL; | 510 | return -EINVAL; |
511 | } | 511 | } |
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index a1cb783c7131..3ca77dc03915 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c | |||
@@ -27,14 +27,6 @@ | |||
27 | /* | 27 | /* |
28 | * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> | 28 | * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> |
29 | */ | 29 | */ |
30 | /* Notes: | ||
31 | * | ||
32 | * We store bo pointer in drm_mm_node struct so we know which bo own a | ||
33 | * specific node. There is no protection on the pointer, thus to make | ||
34 | * sure things don't go berserk you have to access this pointer while | ||
35 | * holding the global lru lock and make sure anytime you free a node you | ||
36 | * reset the pointer to NULL. | ||
37 | */ | ||
38 | 30 | ||
39 | #include "ttm/ttm_module.h" | 31 | #include "ttm/ttm_module.h" |
40 | #include "ttm/ttm_bo_driver.h" | 32 | #include "ttm/ttm_bo_driver.h" |
@@ -45,6 +37,7 @@ | |||
45 | #include <linux/mm.h> | 37 | #include <linux/mm.h> |
46 | #include <linux/file.h> | 38 | #include <linux/file.h> |
47 | #include <linux/module.h> | 39 | #include <linux/module.h> |
40 | #include <asm/atomic.h> | ||
48 | 41 | ||
49 | #define TTM_ASSERT_LOCKED(param) | 42 | #define TTM_ASSERT_LOCKED(param) |
50 | #define TTM_DEBUG(fmt, arg...) | 43 | #define TTM_DEBUG(fmt, arg...) |
@@ -452,6 +445,11 @@ static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo) | |||
452 | ttm_bo_mem_put(bo, &bo->mem); | 445 | ttm_bo_mem_put(bo, &bo->mem); |
453 | 446 | ||
454 | atomic_set(&bo->reserved, 0); | 447 | atomic_set(&bo->reserved, 0); |
448 | |||
449 | /* | ||
450 | * Make processes trying to reserve really pick it up. | ||
451 | */ | ||
452 | smp_mb__after_atomic_dec(); | ||
455 | wake_up_all(&bo->event_queue); | 453 | wake_up_all(&bo->event_queue); |
456 | } | 454 | } |
457 | 455 | ||
@@ -460,7 +458,7 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) | |||
460 | struct ttm_bo_device *bdev = bo->bdev; | 458 | struct ttm_bo_device *bdev = bo->bdev; |
461 | struct ttm_bo_global *glob = bo->glob; | 459 | struct ttm_bo_global *glob = bo->glob; |
462 | struct ttm_bo_driver *driver; | 460 | struct ttm_bo_driver *driver; |
463 | void *sync_obj; | 461 | void *sync_obj = NULL; |
464 | void *sync_obj_arg; | 462 | void *sync_obj_arg; |
465 | int put_count; | 463 | int put_count; |
466 | int ret; | 464 | int ret; |
@@ -495,17 +493,20 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) | |||
495 | spin_lock(&glob->lru_lock); | 493 | spin_lock(&glob->lru_lock); |
496 | } | 494 | } |
497 | queue: | 495 | queue: |
498 | sync_obj = bo->sync_obj; | ||
499 | sync_obj_arg = bo->sync_obj_arg; | ||
500 | driver = bdev->driver; | 496 | driver = bdev->driver; |
497 | if (bo->sync_obj) | ||
498 | sync_obj = driver->sync_obj_ref(bo->sync_obj); | ||
499 | sync_obj_arg = bo->sync_obj_arg; | ||
501 | 500 | ||
502 | kref_get(&bo->list_kref); | 501 | kref_get(&bo->list_kref); |
503 | list_add_tail(&bo->ddestroy, &bdev->ddestroy); | 502 | list_add_tail(&bo->ddestroy, &bdev->ddestroy); |
504 | spin_unlock(&glob->lru_lock); | 503 | spin_unlock(&glob->lru_lock); |
505 | spin_unlock(&bo->lock); | 504 | spin_unlock(&bo->lock); |
506 | 505 | ||
507 | if (sync_obj) | 506 | if (sync_obj) { |
508 | driver->sync_obj_flush(sync_obj, sync_obj_arg); | 507 | driver->sync_obj_flush(sync_obj, sync_obj_arg); |
508 | driver->sync_obj_unref(&sync_obj); | ||
509 | } | ||
509 | schedule_delayed_work(&bdev->wq, | 510 | schedule_delayed_work(&bdev->wq, |
510 | ((HZ / 100) < 1) ? 1 : HZ / 100); | 511 | ((HZ / 100) < 1) ? 1 : HZ / 100); |
511 | } | 512 | } |
@@ -822,7 +823,6 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo, | |||
822 | bool no_wait_gpu) | 823 | bool no_wait_gpu) |
823 | { | 824 | { |
824 | struct ttm_bo_device *bdev = bo->bdev; | 825 | struct ttm_bo_device *bdev = bo->bdev; |
825 | struct ttm_bo_global *glob = bdev->glob; | ||
826 | struct ttm_mem_type_manager *man = &bdev->man[mem_type]; | 826 | struct ttm_mem_type_manager *man = &bdev->man[mem_type]; |
827 | int ret; | 827 | int ret; |
828 | 828 | ||
@@ -832,12 +832,6 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo, | |||
832 | return ret; | 832 | return ret; |
833 | if (mem->mm_node) | 833 | if (mem->mm_node) |
834 | break; | 834 | break; |
835 | spin_lock(&glob->lru_lock); | ||
836 | if (list_empty(&man->lru)) { | ||
837 | spin_unlock(&glob->lru_lock); | ||
838 | break; | ||
839 | } | ||
840 | spin_unlock(&glob->lru_lock); | ||
841 | ret = ttm_mem_evict_first(bdev, mem_type, interruptible, | 835 | ret = ttm_mem_evict_first(bdev, mem_type, interruptible, |
842 | no_wait_reserve, no_wait_gpu); | 836 | no_wait_reserve, no_wait_gpu); |
843 | if (unlikely(ret != 0)) | 837 | if (unlikely(ret != 0)) |
@@ -1125,35 +1119,9 @@ EXPORT_SYMBOL(ttm_bo_validate); | |||
1125 | int ttm_bo_check_placement(struct ttm_buffer_object *bo, | 1119 | int ttm_bo_check_placement(struct ttm_buffer_object *bo, |
1126 | struct ttm_placement *placement) | 1120 | struct ttm_placement *placement) |
1127 | { | 1121 | { |
1128 | int i; | 1122 | BUG_ON((placement->fpfn || placement->lpfn) && |
1123 | (bo->mem.num_pages > (placement->lpfn - placement->fpfn))); | ||
1129 | 1124 | ||
1130 | if (placement->fpfn || placement->lpfn) { | ||
1131 | if (bo->mem.num_pages > (placement->lpfn - placement->fpfn)) { | ||
1132 | printk(KERN_ERR TTM_PFX "Page number range to small " | ||
1133 | "Need %lu pages, range is [%u, %u]\n", | ||
1134 | bo->mem.num_pages, placement->fpfn, | ||
1135 | placement->lpfn); | ||
1136 | return -EINVAL; | ||
1137 | } | ||
1138 | } | ||
1139 | for (i = 0; i < placement->num_placement; i++) { | ||
1140 | if (!capable(CAP_SYS_ADMIN)) { | ||
1141 | if (placement->placement[i] & TTM_PL_FLAG_NO_EVICT) { | ||
1142 | printk(KERN_ERR TTM_PFX "Need to be root to " | ||
1143 | "modify NO_EVICT status.\n"); | ||
1144 | return -EINVAL; | ||
1145 | } | ||
1146 | } | ||
1147 | } | ||
1148 | for (i = 0; i < placement->num_busy_placement; i++) { | ||
1149 | if (!capable(CAP_SYS_ADMIN)) { | ||
1150 | if (placement->busy_placement[i] & TTM_PL_FLAG_NO_EVICT) { | ||
1151 | printk(KERN_ERR TTM_PFX "Need to be root to " | ||
1152 | "modify NO_EVICT status.\n"); | ||
1153 | return -EINVAL; | ||
1154 | } | ||
1155 | } | ||
1156 | } | ||
1157 | return 0; | 1125 | return 0; |
1158 | } | 1126 | } |
1159 | 1127 | ||
@@ -1176,6 +1144,10 @@ int ttm_bo_init(struct ttm_bo_device *bdev, | |||
1176 | num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; | 1144 | num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; |
1177 | if (num_pages == 0) { | 1145 | if (num_pages == 0) { |
1178 | printk(KERN_ERR TTM_PFX "Illegal buffer object size.\n"); | 1146 | printk(KERN_ERR TTM_PFX "Illegal buffer object size.\n"); |
1147 | if (destroy) | ||
1148 | (*destroy)(bo); | ||
1149 | else | ||
1150 | kfree(bo); | ||
1179 | return -EINVAL; | 1151 | return -EINVAL; |
1180 | } | 1152 | } |
1181 | bo->destroy = destroy; | 1153 | bo->destroy = destroy; |
@@ -1369,18 +1341,9 @@ int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type, | |||
1369 | int ret = -EINVAL; | 1341 | int ret = -EINVAL; |
1370 | struct ttm_mem_type_manager *man; | 1342 | struct ttm_mem_type_manager *man; |
1371 | 1343 | ||
1372 | if (type >= TTM_NUM_MEM_TYPES) { | 1344 | BUG_ON(type >= TTM_NUM_MEM_TYPES); |
1373 | printk(KERN_ERR TTM_PFX "Illegal memory type %d\n", type); | ||
1374 | return ret; | ||
1375 | } | ||
1376 | |||
1377 | man = &bdev->man[type]; | 1345 | man = &bdev->man[type]; |
1378 | if (man->has_type) { | 1346 | BUG_ON(man->has_type); |
1379 | printk(KERN_ERR TTM_PFX | ||
1380 | "Memory manager already initialized for type %d\n", | ||
1381 | type); | ||
1382 | return ret; | ||
1383 | } | ||
1384 | 1347 | ||
1385 | ret = bdev->driver->init_mem_type(bdev, type, man); | 1348 | ret = bdev->driver->init_mem_type(bdev, type, man); |
1386 | if (ret) | 1349 | if (ret) |
@@ -1389,13 +1352,6 @@ int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type, | |||
1389 | 1352 | ||
1390 | ret = 0; | 1353 | ret = 0; |
1391 | if (type != TTM_PL_SYSTEM) { | 1354 | if (type != TTM_PL_SYSTEM) { |
1392 | if (!p_size) { | ||
1393 | printk(KERN_ERR TTM_PFX | ||
1394 | "Zero size memory manager type %d\n", | ||
1395 | type); | ||
1396 | return ret; | ||
1397 | } | ||
1398 | |||
1399 | ret = (*man->func->init)(man, p_size); | 1355 | ret = (*man->func->init)(man, p_size); |
1400 | if (ret) | 1356 | if (ret) |
1401 | return ret; | 1357 | return ret; |
diff --git a/drivers/gpu/drm/ttm/ttm_bo_manager.c b/drivers/gpu/drm/ttm/ttm_bo_manager.c index 7410c190c891..038e947d00f9 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_manager.c +++ b/drivers/gpu/drm/ttm/ttm_bo_manager.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /************************************************************************** | 1 | /************************************************************************** |
2 | * | 2 | * |
3 | * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA | 3 | * Copyright (c) 2007-2010 VMware, Inc., Palo Alto, CA., USA |
4 | * All Rights Reserved. | 4 | * All Rights Reserved. |
5 | * | 5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a | 6 | * Permission is hereby granted, free of charge, to any person obtaining a |
@@ -31,20 +31,29 @@ | |||
31 | #include "ttm/ttm_module.h" | 31 | #include "ttm/ttm_module.h" |
32 | #include "ttm/ttm_bo_driver.h" | 32 | #include "ttm/ttm_bo_driver.h" |
33 | #include "ttm/ttm_placement.h" | 33 | #include "ttm/ttm_placement.h" |
34 | #include <linux/jiffies.h> | 34 | #include "drm_mm.h" |
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/sched.h> | 36 | #include <linux/spinlock.h> |
37 | #include <linux/mm.h> | ||
38 | #include <linux/file.h> | ||
39 | #include <linux/module.h> | 37 | #include <linux/module.h> |
40 | 38 | ||
39 | /** | ||
40 | * Currently we use a spinlock for the lock, but a mutex *may* be | ||
41 | * more appropriate to reduce scheduling latency if the range manager | ||
42 | * ends up with very fragmented allocation patterns. | ||
43 | */ | ||
44 | |||
45 | struct ttm_range_manager { | ||
46 | struct drm_mm mm; | ||
47 | spinlock_t lock; | ||
48 | }; | ||
49 | |||
41 | static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man, | 50 | static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man, |
42 | struct ttm_buffer_object *bo, | 51 | struct ttm_buffer_object *bo, |
43 | struct ttm_placement *placement, | 52 | struct ttm_placement *placement, |
44 | struct ttm_mem_reg *mem) | 53 | struct ttm_mem_reg *mem) |
45 | { | 54 | { |
46 | struct ttm_bo_global *glob = man->bdev->glob; | 55 | struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv; |
47 | struct drm_mm *mm = man->priv; | 56 | struct drm_mm *mm = &rman->mm; |
48 | struct drm_mm_node *node = NULL; | 57 | struct drm_mm_node *node = NULL; |
49 | unsigned long lpfn; | 58 | unsigned long lpfn; |
50 | int ret; | 59 | int ret; |
@@ -57,19 +66,19 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man, | |||
57 | if (unlikely(ret)) | 66 | if (unlikely(ret)) |
58 | return ret; | 67 | return ret; |
59 | 68 | ||
60 | spin_lock(&glob->lru_lock); | 69 | spin_lock(&rman->lock); |
61 | node = drm_mm_search_free_in_range(mm, | 70 | node = drm_mm_search_free_in_range(mm, |
62 | mem->num_pages, mem->page_alignment, | 71 | mem->num_pages, mem->page_alignment, |
63 | placement->fpfn, lpfn, 1); | 72 | placement->fpfn, lpfn, 1); |
64 | if (unlikely(node == NULL)) { | 73 | if (unlikely(node == NULL)) { |
65 | spin_unlock(&glob->lru_lock); | 74 | spin_unlock(&rman->lock); |
66 | return 0; | 75 | return 0; |
67 | } | 76 | } |
68 | node = drm_mm_get_block_atomic_range(node, mem->num_pages, | 77 | node = drm_mm_get_block_atomic_range(node, mem->num_pages, |
69 | mem->page_alignment, | 78 | mem->page_alignment, |
70 | placement->fpfn, | 79 | placement->fpfn, |
71 | lpfn); | 80 | lpfn); |
72 | spin_unlock(&glob->lru_lock); | 81 | spin_unlock(&rman->lock); |
73 | } while (node == NULL); | 82 | } while (node == NULL); |
74 | 83 | ||
75 | mem->mm_node = node; | 84 | mem->mm_node = node; |
@@ -80,12 +89,12 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man, | |||
80 | static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man, | 89 | static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man, |
81 | struct ttm_mem_reg *mem) | 90 | struct ttm_mem_reg *mem) |
82 | { | 91 | { |
83 | struct ttm_bo_global *glob = man->bdev->glob; | 92 | struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv; |
84 | 93 | ||
85 | if (mem->mm_node) { | 94 | if (mem->mm_node) { |
86 | spin_lock(&glob->lru_lock); | 95 | spin_lock(&rman->lock); |
87 | drm_mm_put_block(mem->mm_node); | 96 | drm_mm_put_block(mem->mm_node); |
88 | spin_unlock(&glob->lru_lock); | 97 | spin_unlock(&rman->lock); |
89 | mem->mm_node = NULL; | 98 | mem->mm_node = NULL; |
90 | } | 99 | } |
91 | } | 100 | } |
@@ -93,49 +102,49 @@ static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man, | |||
93 | static int ttm_bo_man_init(struct ttm_mem_type_manager *man, | 102 | static int ttm_bo_man_init(struct ttm_mem_type_manager *man, |
94 | unsigned long p_size) | 103 | unsigned long p_size) |
95 | { | 104 | { |
96 | struct drm_mm *mm; | 105 | struct ttm_range_manager *rman; |
97 | int ret; | 106 | int ret; |
98 | 107 | ||
99 | mm = kzalloc(sizeof(*mm), GFP_KERNEL); | 108 | rman = kzalloc(sizeof(*rman), GFP_KERNEL); |
100 | if (!mm) | 109 | if (!rman) |
101 | return -ENOMEM; | 110 | return -ENOMEM; |
102 | 111 | ||
103 | ret = drm_mm_init(mm, 0, p_size); | 112 | ret = drm_mm_init(&rman->mm, 0, p_size); |
104 | if (ret) { | 113 | if (ret) { |
105 | kfree(mm); | 114 | kfree(rman); |
106 | return ret; | 115 | return ret; |
107 | } | 116 | } |
108 | 117 | ||
109 | man->priv = mm; | 118 | spin_lock_init(&rman->lock); |
119 | man->priv = rman; | ||
110 | return 0; | 120 | return 0; |
111 | } | 121 | } |
112 | 122 | ||
113 | static int ttm_bo_man_takedown(struct ttm_mem_type_manager *man) | 123 | static int ttm_bo_man_takedown(struct ttm_mem_type_manager *man) |
114 | { | 124 | { |
115 | struct ttm_bo_global *glob = man->bdev->glob; | 125 | struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv; |
116 | struct drm_mm *mm = man->priv; | 126 | struct drm_mm *mm = &rman->mm; |
117 | int ret = 0; | ||
118 | 127 | ||
119 | spin_lock(&glob->lru_lock); | 128 | spin_lock(&rman->lock); |
120 | if (drm_mm_clean(mm)) { | 129 | if (drm_mm_clean(mm)) { |
121 | drm_mm_takedown(mm); | 130 | drm_mm_takedown(mm); |
122 | kfree(mm); | 131 | spin_unlock(&rman->lock); |
132 | kfree(rman); | ||
123 | man->priv = NULL; | 133 | man->priv = NULL; |
124 | } else | 134 | return 0; |
125 | ret = -EBUSY; | 135 | } |
126 | spin_unlock(&glob->lru_lock); | 136 | spin_unlock(&rman->lock); |
127 | return ret; | 137 | return -EBUSY; |
128 | } | 138 | } |
129 | 139 | ||
130 | static void ttm_bo_man_debug(struct ttm_mem_type_manager *man, | 140 | static void ttm_bo_man_debug(struct ttm_mem_type_manager *man, |
131 | const char *prefix) | 141 | const char *prefix) |
132 | { | 142 | { |
133 | struct ttm_bo_global *glob = man->bdev->glob; | 143 | struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv; |
134 | struct drm_mm *mm = man->priv; | ||
135 | 144 | ||
136 | spin_lock(&glob->lru_lock); | 145 | spin_lock(&rman->lock); |
137 | drm_mm_debug_table(mm, prefix); | 146 | drm_mm_debug_table(&rman->mm, prefix); |
138 | spin_unlock(&glob->lru_lock); | 147 | spin_unlock(&rman->lock); |
139 | } | 148 | } |
140 | 149 | ||
141 | const struct ttm_mem_type_manager_func ttm_bo_manager_func = { | 150 | const struct ttm_mem_type_manager_func ttm_bo_manager_func = { |
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index a7bab87a548b..af789dc869b9 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c | |||
@@ -440,10 +440,8 @@ int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem) | |||
440 | return ret; | 440 | return ret; |
441 | 441 | ||
442 | ret = be->func->bind(be, bo_mem); | 442 | ret = be->func->bind(be, bo_mem); |
443 | if (ret) { | 443 | if (unlikely(ret != 0)) |
444 | printk(KERN_ERR TTM_PFX "Couldn't bind backend.\n"); | ||
445 | return ret; | 444 | return ret; |
446 | } | ||
447 | 445 | ||
448 | ttm->state = tt_bound; | 446 | ttm->state = tt_bound; |
449 | 447 | ||
diff --git a/drivers/gpu/drm/via/via_dmablit.c b/drivers/gpu/drm/via/via_dmablit.c index 9b5b4d9dd62c..3e038a394c51 100644 --- a/drivers/gpu/drm/via/via_dmablit.c +++ b/drivers/gpu/drm/via/via_dmablit.c | |||
@@ -235,9 +235,9 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer) | |||
235 | vsg->num_pages = VIA_PFN(xfer->mem_addr + (xfer->num_lines * xfer->mem_stride - 1)) - | 235 | vsg->num_pages = VIA_PFN(xfer->mem_addr + (xfer->num_lines * xfer->mem_stride - 1)) - |
236 | first_pfn + 1; | 236 | first_pfn + 1; |
237 | 237 | ||
238 | if (NULL == (vsg->pages = vmalloc(sizeof(struct page *) * vsg->num_pages))) | 238 | vsg->pages = vzalloc(sizeof(struct page *) * vsg->num_pages); |
239 | if (NULL == vsg->pages) | ||
239 | return -ENOMEM; | 240 | return -ENOMEM; |
240 | memset(vsg->pages, 0, sizeof(struct page *) * vsg->num_pages); | ||
241 | down_read(¤t->mm->mmap_sem); | 241 | down_read(¤t->mm->mmap_sem); |
242 | ret = get_user_pages(current, current->mm, | 242 | ret = get_user_pages(current, current->mm, |
243 | (unsigned long)xfer->mem_addr, | 243 | (unsigned long)xfer->mem_addr, |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 51d9f9f1d7f2..76954e3528c1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | |||
@@ -691,6 +691,7 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, | |||
691 | 691 | ||
692 | fence_rep.error = ret; | 692 | fence_rep.error = ret; |
693 | fence_rep.fence_seq = (uint64_t) sequence; | 693 | fence_rep.fence_seq = (uint64_t) sequence; |
694 | fence_rep.pad64 = 0; | ||
694 | 695 | ||
695 | user_fence_rep = (struct drm_vmw_fence_rep __user *) | 696 | user_fence_rep = (struct drm_vmw_fence_rep __user *) |
696 | (unsigned long)arg->fence_rep; | 697 | (unsigned long)arg->fence_rep; |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 87c6e6156d7d..cceeb42789b6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | |||
@@ -720,6 +720,8 @@ static int vmw_surface_dmabuf_pin(struct vmw_framebuffer *vfb) | |||
720 | &vmw_vram_ne_placement, | 720 | &vmw_vram_ne_placement, |
721 | false, &vmw_dmabuf_bo_free); | 721 | false, &vmw_dmabuf_bo_free); |
722 | vmw_overlay_resume_all(dev_priv); | 722 | vmw_overlay_resume_all(dev_priv); |
723 | if (unlikely(ret != 0)) | ||
724 | vfbs->buffer = NULL; | ||
723 | 725 | ||
724 | return ret; | 726 | return ret; |
725 | } | 727 | } |
@@ -730,6 +732,9 @@ static int vmw_surface_dmabuf_unpin(struct vmw_framebuffer *vfb) | |||
730 | struct vmw_framebuffer_surface *vfbs = | 732 | struct vmw_framebuffer_surface *vfbs = |
731 | vmw_framebuffer_to_vfbs(&vfb->base); | 733 | vmw_framebuffer_to_vfbs(&vfb->base); |
732 | 734 | ||
735 | if (unlikely(vfbs->buffer == NULL)) | ||
736 | return 0; | ||
737 | |||
733 | bo = &vfbs->buffer->base; | 738 | bo = &vfbs->buffer->base; |
734 | ttm_bo_unref(&bo); | 739 | ttm_bo_unref(&bo); |
735 | vfbs->buffer = NULL; | 740 | vfbs->buffer = NULL; |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index a01c47ddb5bc..29113c9b26a8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | |||
@@ -557,7 +557,7 @@ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv) | |||
557 | return -EINVAL; | 557 | return -EINVAL; |
558 | } | 558 | } |
559 | 559 | ||
560 | dev_priv->ldu_priv = kmalloc(GFP_KERNEL, sizeof(*dev_priv->ldu_priv)); | 560 | dev_priv->ldu_priv = kmalloc(sizeof(*dev_priv->ldu_priv), GFP_KERNEL); |
561 | 561 | ||
562 | if (!dev_priv->ldu_priv) | 562 | if (!dev_priv->ldu_priv) |
563 | return -ENOMEM; | 563 | return -ENOMEM; |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index df2036ed18d5..f1a52f9e7298 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | |||
@@ -585,7 +585,7 @@ int vmw_overlay_init(struct vmw_private *dev_priv) | |||
585 | return -ENOSYS; | 585 | return -ENOSYS; |
586 | } | 586 | } |
587 | 587 | ||
588 | overlay = kmalloc(GFP_KERNEL, sizeof(*overlay)); | 588 | overlay = kmalloc(sizeof(*overlay), GFP_KERNEL); |
589 | if (!overlay) | 589 | if (!overlay) |
590 | return -ENOMEM; | 590 | return -ENOMEM; |
591 | 591 | ||
diff --git a/drivers/gpu/stub/Kconfig b/drivers/gpu/stub/Kconfig index 742c423567cf..0e1edd7311ff 100644 --- a/drivers/gpu/stub/Kconfig +++ b/drivers/gpu/stub/Kconfig | |||
@@ -3,6 +3,9 @@ config STUB_POULSBO | |||
3 | depends on PCI | 3 | depends on PCI |
4 | # Poulsbo stub depends on ACPI_VIDEO when ACPI is enabled | 4 | # Poulsbo stub depends on ACPI_VIDEO when ACPI is enabled |
5 | # but for select to work, need to select ACPI_VIDEO's dependencies, ick | 5 | # but for select to work, need to select ACPI_VIDEO's dependencies, ick |
6 | select VIDEO_OUTPUT_CONTROL if ACPI | ||
7 | select BACKLIGHT_CLASS_DEVICE if ACPI | ||
8 | select INPUT if ACPI | ||
6 | select ACPI_VIDEO if ACPI | 9 | select ACPI_VIDEO if ACPI |
7 | help | 10 | help |
8 | Choose this option if you have a system that has Intel GMA500 | 11 | Choose this option if you have a system that has Intel GMA500 |
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index cc2a88d5192f..77b8fd20cd90 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig | |||
@@ -10,7 +10,7 @@ menuconfig NEW_LEDS | |||
10 | if NEW_LEDS | 10 | if NEW_LEDS |
11 | 11 | ||
12 | config LEDS_CLASS | 12 | config LEDS_CLASS |
13 | tristate "LED Class Support" | 13 | bool "LED Class Support" |
14 | help | 14 | help |
15 | This option enables the led sysfs class in /sys/class/leds. You'll | 15 | This option enables the led sysfs class in /sys/class/leds. You'll |
16 | need this to do anything useful with LEDs. If unsure, say N. | 16 | need this to do anything useful with LEDs. If unsure, say N. |
@@ -176,6 +176,24 @@ config LEDS_LP3944 | |||
176 | To compile this driver as a module, choose M here: the | 176 | To compile this driver as a module, choose M here: the |
177 | module will be called leds-lp3944. | 177 | module will be called leds-lp3944. |
178 | 178 | ||
179 | config LEDS_LP5521 | ||
180 | tristate "LED Support for N.S. LP5521 LED driver chip" | ||
181 | depends on LEDS_CLASS && I2C | ||
182 | help | ||
183 | If you say yes here you get support for the National Semiconductor | ||
184 | LP5521 LED driver. It is 3 channel chip with programmable engines. | ||
185 | Driver provides direct control via LED class and interface for | ||
186 | programming the engines. | ||
187 | |||
188 | config LEDS_LP5523 | ||
189 | tristate "LED Support for N.S. LP5523 LED driver chip" | ||
190 | depends on LEDS_CLASS && I2C | ||
191 | help | ||
192 | If you say yes here you get support for the National Semiconductor | ||
193 | LP5523 LED driver. It is 9 channel chip with programmable engines. | ||
194 | Driver provides direct control via LED class and interface for | ||
195 | programming the engines. | ||
196 | |||
179 | config LEDS_CLEVO_MAIL | 197 | config LEDS_CLEVO_MAIL |
180 | tristate "Mail LED on Clevo notebook" | 198 | tristate "Mail LED on Clevo notebook" |
181 | depends on X86 && SERIO_I8042 && DMI | 199 | depends on X86 && SERIO_I8042 && DMI |
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 9c96db40ef6d..aae6989ff6b6 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile | |||
@@ -23,6 +23,8 @@ obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o | |||
23 | obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o | 23 | obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o |
24 | obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o | 24 | obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o |
25 | obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o | 25 | obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o |
26 | obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o | ||
27 | obj-$(CONFIG_LEDS_LP5523) += leds-lp5523.o | ||
26 | obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o | 28 | obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o |
27 | obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o | 29 | obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o |
28 | obj-$(CONFIG_LEDS_FSG) += leds-fsg.o | 30 | obj-$(CONFIG_LEDS_FSG) += leds-fsg.o |
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 260660076507..211e21f34bd5 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c | |||
@@ -81,6 +81,79 @@ static struct device_attribute led_class_attrs[] = { | |||
81 | __ATTR_NULL, | 81 | __ATTR_NULL, |
82 | }; | 82 | }; |
83 | 83 | ||
84 | static void led_timer_function(unsigned long data) | ||
85 | { | ||
86 | struct led_classdev *led_cdev = (void *)data; | ||
87 | unsigned long brightness; | ||
88 | unsigned long delay; | ||
89 | |||
90 | if (!led_cdev->blink_delay_on || !led_cdev->blink_delay_off) { | ||
91 | led_set_brightness(led_cdev, LED_OFF); | ||
92 | return; | ||
93 | } | ||
94 | |||
95 | brightness = led_get_brightness(led_cdev); | ||
96 | if (!brightness) { | ||
97 | /* Time to switch the LED on. */ | ||
98 | brightness = led_cdev->blink_brightness; | ||
99 | delay = led_cdev->blink_delay_on; | ||
100 | } else { | ||
101 | /* Store the current brightness value to be able | ||
102 | * to restore it when the delay_off period is over. | ||
103 | */ | ||
104 | led_cdev->blink_brightness = brightness; | ||
105 | brightness = LED_OFF; | ||
106 | delay = led_cdev->blink_delay_off; | ||
107 | } | ||
108 | |||
109 | led_set_brightness(led_cdev, brightness); | ||
110 | |||
111 | mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay)); | ||
112 | } | ||
113 | |||
114 | static void led_stop_software_blink(struct led_classdev *led_cdev) | ||
115 | { | ||
116 | /* deactivate previous settings */ | ||
117 | del_timer_sync(&led_cdev->blink_timer); | ||
118 | led_cdev->blink_delay_on = 0; | ||
119 | led_cdev->blink_delay_off = 0; | ||
120 | } | ||
121 | |||
122 | static void led_set_software_blink(struct led_classdev *led_cdev, | ||
123 | unsigned long delay_on, | ||
124 | unsigned long delay_off) | ||
125 | { | ||
126 | int current_brightness; | ||
127 | |||
128 | current_brightness = led_get_brightness(led_cdev); | ||
129 | if (current_brightness) | ||
130 | led_cdev->blink_brightness = current_brightness; | ||
131 | if (!led_cdev->blink_brightness) | ||
132 | led_cdev->blink_brightness = led_cdev->max_brightness; | ||
133 | |||
134 | if (delay_on == led_cdev->blink_delay_on && | ||
135 | delay_off == led_cdev->blink_delay_off) | ||
136 | return; | ||
137 | |||
138 | led_stop_software_blink(led_cdev); | ||
139 | |||
140 | led_cdev->blink_delay_on = delay_on; | ||
141 | led_cdev->blink_delay_off = delay_off; | ||
142 | |||
143 | /* never on - don't blink */ | ||
144 | if (!delay_on) | ||
145 | return; | ||
146 | |||
147 | /* never off - just set to brightness */ | ||
148 | if (!delay_off) { | ||
149 | led_set_brightness(led_cdev, led_cdev->blink_brightness); | ||
150 | return; | ||
151 | } | ||
152 | |||
153 | mod_timer(&led_cdev->blink_timer, jiffies + 1); | ||
154 | } | ||
155 | |||
156 | |||
84 | /** | 157 | /** |
85 | * led_classdev_suspend - suspend an led_classdev. | 158 | * led_classdev_suspend - suspend an led_classdev. |
86 | * @led_cdev: the led_classdev to suspend. | 159 | * @led_cdev: the led_classdev to suspend. |
@@ -148,6 +221,10 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) | |||
148 | 221 | ||
149 | led_update_brightness(led_cdev); | 222 | led_update_brightness(led_cdev); |
150 | 223 | ||
224 | init_timer(&led_cdev->blink_timer); | ||
225 | led_cdev->blink_timer.function = led_timer_function; | ||
226 | led_cdev->blink_timer.data = (unsigned long)led_cdev; | ||
227 | |||
151 | #ifdef CONFIG_LEDS_TRIGGERS | 228 | #ifdef CONFIG_LEDS_TRIGGERS |
152 | led_trigger_set_default(led_cdev); | 229 | led_trigger_set_default(led_cdev); |
153 | #endif | 230 | #endif |
@@ -157,7 +234,6 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) | |||
157 | 234 | ||
158 | return 0; | 235 | return 0; |
159 | } | 236 | } |
160 | |||
161 | EXPORT_SYMBOL_GPL(led_classdev_register); | 237 | EXPORT_SYMBOL_GPL(led_classdev_register); |
162 | 238 | ||
163 | /** | 239 | /** |
@@ -175,6 +251,9 @@ void led_classdev_unregister(struct led_classdev *led_cdev) | |||
175 | up_write(&led_cdev->trigger_lock); | 251 | up_write(&led_cdev->trigger_lock); |
176 | #endif | 252 | #endif |
177 | 253 | ||
254 | /* Stop blinking */ | ||
255 | led_brightness_set(led_cdev, LED_OFF); | ||
256 | |||
178 | device_unregister(led_cdev->dev); | 257 | device_unregister(led_cdev->dev); |
179 | 258 | ||
180 | down_write(&leds_list_lock); | 259 | down_write(&leds_list_lock); |
@@ -183,6 +262,30 @@ void led_classdev_unregister(struct led_classdev *led_cdev) | |||
183 | } | 262 | } |
184 | EXPORT_SYMBOL_GPL(led_classdev_unregister); | 263 | EXPORT_SYMBOL_GPL(led_classdev_unregister); |
185 | 264 | ||
265 | void led_blink_set(struct led_classdev *led_cdev, | ||
266 | unsigned long *delay_on, | ||
267 | unsigned long *delay_off) | ||
268 | { | ||
269 | if (led_cdev->blink_set && | ||
270 | led_cdev->blink_set(led_cdev, delay_on, delay_off)) | ||
271 | return; | ||
272 | |||
273 | /* blink with 1 Hz as default if nothing specified */ | ||
274 | if (!*delay_on && !*delay_off) | ||
275 | *delay_on = *delay_off = 500; | ||
276 | |||
277 | led_set_software_blink(led_cdev, *delay_on, *delay_off); | ||
278 | } | ||
279 | EXPORT_SYMBOL(led_blink_set); | ||
280 | |||
281 | void led_brightness_set(struct led_classdev *led_cdev, | ||
282 | enum led_brightness brightness) | ||
283 | { | ||
284 | led_stop_software_blink(led_cdev); | ||
285 | led_cdev->brightness_set(led_cdev, brightness); | ||
286 | } | ||
287 | EXPORT_SYMBOL(led_brightness_set); | ||
288 | |||
186 | static int __init leds_init(void) | 289 | static int __init leds_init(void) |
187 | { | 290 | { |
188 | leds_class = class_create(THIS_MODULE, "leds"); | 291 | leds_class = class_create(THIS_MODULE, "leds"); |
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index f1c00db88b5e..c41eb6180c9c 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c | |||
@@ -113,7 +113,7 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger) | |||
113 | if (led_cdev->trigger->deactivate) | 113 | if (led_cdev->trigger->deactivate) |
114 | led_cdev->trigger->deactivate(led_cdev); | 114 | led_cdev->trigger->deactivate(led_cdev); |
115 | led_cdev->trigger = NULL; | 115 | led_cdev->trigger = NULL; |
116 | led_set_brightness(led_cdev, LED_OFF); | 116 | led_brightness_set(led_cdev, LED_OFF); |
117 | } | 117 | } |
118 | if (trigger) { | 118 | if (trigger) { |
119 | write_lock_irqsave(&trigger->leddev_list_lock, flags); | 119 | write_lock_irqsave(&trigger->leddev_list_lock, flags); |
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index ea57e05d08f3..4d9fa38d9ff6 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c | |||
@@ -316,7 +316,7 @@ static struct of_platform_driver of_gpio_leds_driver = { | |||
316 | 316 | ||
317 | static int __init gpio_led_init(void) | 317 | static int __init gpio_led_init(void) |
318 | { | 318 | { |
319 | int ret; | 319 | int ret = 0; |
320 | 320 | ||
321 | #ifdef CONFIG_LEDS_GPIO_PLATFORM | 321 | #ifdef CONFIG_LEDS_GPIO_PLATFORM |
322 | ret = platform_driver_register(&gpio_led_driver); | 322 | ret = platform_driver_register(&gpio_led_driver); |
diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c new file mode 100644 index 000000000000..3782f31f06d2 --- /dev/null +++ b/drivers/leds/leds-lp5521.c | |||
@@ -0,0 +1,821 @@ | |||
1 | /* | ||
2 | * LP5521 LED chip driver. | ||
3 | * | ||
4 | * Copyright (C) 2010 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Samu Onkalo <samu.p.onkalo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/mutex.h> | ||
27 | #include <linux/gpio.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/ctype.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | #include <linux/wait.h> | ||
33 | #include <linux/leds.h> | ||
34 | #include <linux/leds-lp5521.h> | ||
35 | #include <linux/workqueue.h> | ||
36 | #include <linux/slab.h> | ||
37 | |||
38 | #define LP5521_PROGRAM_LENGTH 32 /* in bytes */ | ||
39 | |||
40 | #define LP5521_MAX_LEDS 3 /* Maximum number of LEDs */ | ||
41 | #define LP5521_MAX_ENGINES 3 /* Maximum number of engines */ | ||
42 | |||
43 | #define LP5521_ENG_MASK_BASE 0x30 /* 00110000 */ | ||
44 | #define LP5521_ENG_STATUS_MASK 0x07 /* 00000111 */ | ||
45 | |||
46 | #define LP5521_CMD_LOAD 0x15 /* 00010101 */ | ||
47 | #define LP5521_CMD_RUN 0x2a /* 00101010 */ | ||
48 | #define LP5521_CMD_DIRECT 0x3f /* 00111111 */ | ||
49 | #define LP5521_CMD_DISABLED 0x00 /* 00000000 */ | ||
50 | |||
51 | /* Registers */ | ||
52 | #define LP5521_REG_ENABLE 0x00 | ||
53 | #define LP5521_REG_OP_MODE 0x01 | ||
54 | #define LP5521_REG_R_PWM 0x02 | ||
55 | #define LP5521_REG_G_PWM 0x03 | ||
56 | #define LP5521_REG_B_PWM 0x04 | ||
57 | #define LP5521_REG_R_CURRENT 0x05 | ||
58 | #define LP5521_REG_G_CURRENT 0x06 | ||
59 | #define LP5521_REG_B_CURRENT 0x07 | ||
60 | #define LP5521_REG_CONFIG 0x08 | ||
61 | #define LP5521_REG_R_CHANNEL_PC 0x09 | ||
62 | #define LP5521_REG_G_CHANNEL_PC 0x0A | ||
63 | #define LP5521_REG_B_CHANNEL_PC 0x0B | ||
64 | #define LP5521_REG_STATUS 0x0C | ||
65 | #define LP5521_REG_RESET 0x0D | ||
66 | #define LP5521_REG_GPO 0x0E | ||
67 | #define LP5521_REG_R_PROG_MEM 0x10 | ||
68 | #define LP5521_REG_G_PROG_MEM 0x30 | ||
69 | #define LP5521_REG_B_PROG_MEM 0x50 | ||
70 | |||
71 | #define LP5521_PROG_MEM_BASE LP5521_REG_R_PROG_MEM | ||
72 | #define LP5521_PROG_MEM_SIZE 0x20 | ||
73 | |||
74 | /* Base register to set LED current */ | ||
75 | #define LP5521_REG_LED_CURRENT_BASE LP5521_REG_R_CURRENT | ||
76 | |||
77 | /* Base register to set the brightness */ | ||
78 | #define LP5521_REG_LED_PWM_BASE LP5521_REG_R_PWM | ||
79 | |||
80 | /* Bits in ENABLE register */ | ||
81 | #define LP5521_MASTER_ENABLE 0x40 /* Chip master enable */ | ||
82 | #define LP5521_LOGARITHMIC_PWM 0x80 /* Logarithmic PWM adjustment */ | ||
83 | #define LP5521_EXEC_RUN 0x2A | ||
84 | |||
85 | /* Bits in CONFIG register */ | ||
86 | #define LP5521_PWM_HF 0x40 /* PWM: 0 = 256Hz, 1 = 558Hz */ | ||
87 | #define LP5521_PWRSAVE_EN 0x20 /* 1 = Power save mode */ | ||
88 | #define LP5521_CP_MODE_OFF 0 /* Charge pump (CP) off */ | ||
89 | #define LP5521_CP_MODE_BYPASS 8 /* CP forced to bypass mode */ | ||
90 | #define LP5521_CP_MODE_1X5 0x10 /* CP forced to 1.5x mode */ | ||
91 | #define LP5521_CP_MODE_AUTO 0x18 /* Automatic mode selection */ | ||
92 | #define LP5521_R_TO_BATT 4 /* R out: 0 = CP, 1 = Vbat */ | ||
93 | #define LP5521_CLK_SRC_EXT 0 /* Ext-clk source (CLK_32K) */ | ||
94 | #define LP5521_CLK_INT 1 /* Internal clock */ | ||
95 | #define LP5521_CLK_AUTO 2 /* Automatic clock selection */ | ||
96 | |||
97 | /* Status */ | ||
98 | #define LP5521_EXT_CLK_USED 0x08 | ||
99 | |||
100 | struct lp5521_engine { | ||
101 | const struct attribute_group *attributes; | ||
102 | int id; | ||
103 | u8 mode; | ||
104 | u8 prog_page; | ||
105 | u8 engine_mask; | ||
106 | }; | ||
107 | |||
108 | struct lp5521_led { | ||
109 | int id; | ||
110 | u8 chan_nr; | ||
111 | u8 led_current; | ||
112 | u8 max_current; | ||
113 | struct led_classdev cdev; | ||
114 | struct work_struct brightness_work; | ||
115 | u8 brightness; | ||
116 | }; | ||
117 | |||
118 | struct lp5521_chip { | ||
119 | struct lp5521_platform_data *pdata; | ||
120 | struct mutex lock; /* Serialize control */ | ||
121 | struct i2c_client *client; | ||
122 | struct lp5521_engine engines[LP5521_MAX_ENGINES]; | ||
123 | struct lp5521_led leds[LP5521_MAX_LEDS]; | ||
124 | u8 num_channels; | ||
125 | u8 num_leds; | ||
126 | }; | ||
127 | |||
128 | #define cdev_to_led(c) container_of(c, struct lp5521_led, cdev) | ||
129 | #define engine_to_lp5521(eng) container_of((eng), struct lp5521_chip, \ | ||
130 | engines[(eng)->id - 1]) | ||
131 | #define led_to_lp5521(led) container_of((led), struct lp5521_chip, \ | ||
132 | leds[(led)->id]) | ||
133 | |||
134 | static void lp5521_led_brightness_work(struct work_struct *work); | ||
135 | |||
136 | static inline int lp5521_write(struct i2c_client *client, u8 reg, u8 value) | ||
137 | { | ||
138 | return i2c_smbus_write_byte_data(client, reg, value); | ||
139 | } | ||
140 | |||
141 | static int lp5521_read(struct i2c_client *client, u8 reg, u8 *buf) | ||
142 | { | ||
143 | s32 ret; | ||
144 | |||
145 | ret = i2c_smbus_read_byte_data(client, reg); | ||
146 | if (ret < 0) | ||
147 | return -EIO; | ||
148 | |||
149 | *buf = ret; | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int lp5521_set_engine_mode(struct lp5521_engine *engine, u8 mode) | ||
154 | { | ||
155 | struct lp5521_chip *chip = engine_to_lp5521(engine); | ||
156 | struct i2c_client *client = chip->client; | ||
157 | int ret; | ||
158 | u8 engine_state; | ||
159 | |||
160 | /* Only transition between RUN and DIRECT mode are handled here */ | ||
161 | if (mode == LP5521_CMD_LOAD) | ||
162 | return 0; | ||
163 | |||
164 | if (mode == LP5521_CMD_DISABLED) | ||
165 | mode = LP5521_CMD_DIRECT; | ||
166 | |||
167 | ret = lp5521_read(client, LP5521_REG_OP_MODE, &engine_state); | ||
168 | |||
169 | /* set mode only for this engine */ | ||
170 | engine_state &= ~(engine->engine_mask); | ||
171 | mode &= engine->engine_mask; | ||
172 | engine_state |= mode; | ||
173 | ret |= lp5521_write(client, LP5521_REG_OP_MODE, engine_state); | ||
174 | |||
175 | return ret; | ||
176 | } | ||
177 | |||
178 | static int lp5521_load_program(struct lp5521_engine *eng, const u8 *pattern) | ||
179 | { | ||
180 | struct lp5521_chip *chip = engine_to_lp5521(eng); | ||
181 | struct i2c_client *client = chip->client; | ||
182 | int ret; | ||
183 | int addr; | ||
184 | u8 mode; | ||
185 | |||
186 | /* move current engine to direct mode and remember the state */ | ||
187 | ret = lp5521_set_engine_mode(eng, LP5521_CMD_DIRECT); | ||
188 | usleep_range(1000, 10000); | ||
189 | ret |= lp5521_read(client, LP5521_REG_OP_MODE, &mode); | ||
190 | |||
191 | /* For loading, all the engines to load mode */ | ||
192 | lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT); | ||
193 | usleep_range(1000, 10000); | ||
194 | lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_LOAD); | ||
195 | usleep_range(1000, 10000); | ||
196 | |||
197 | addr = LP5521_PROG_MEM_BASE + eng->prog_page * LP5521_PROG_MEM_SIZE; | ||
198 | i2c_smbus_write_i2c_block_data(client, | ||
199 | addr, | ||
200 | LP5521_PROG_MEM_SIZE, | ||
201 | pattern); | ||
202 | |||
203 | ret |= lp5521_write(client, LP5521_REG_OP_MODE, mode); | ||
204 | return ret; | ||
205 | } | ||
206 | |||
207 | static int lp5521_set_led_current(struct lp5521_chip *chip, int led, u8 curr) | ||
208 | { | ||
209 | return lp5521_write(chip->client, | ||
210 | LP5521_REG_LED_CURRENT_BASE + chip->leds[led].chan_nr, | ||
211 | curr); | ||
212 | } | ||
213 | |||
214 | static void lp5521_init_engine(struct lp5521_chip *chip, | ||
215 | const struct attribute_group *attr_group) | ||
216 | { | ||
217 | int i; | ||
218 | for (i = 0; i < ARRAY_SIZE(chip->engines); i++) { | ||
219 | chip->engines[i].id = i + 1; | ||
220 | chip->engines[i].engine_mask = LP5521_ENG_MASK_BASE >> (i * 2); | ||
221 | chip->engines[i].prog_page = i; | ||
222 | chip->engines[i].attributes = &attr_group[i]; | ||
223 | } | ||
224 | } | ||
225 | |||
226 | static int lp5521_configure(struct i2c_client *client, | ||
227 | const struct attribute_group *attr_group) | ||
228 | { | ||
229 | struct lp5521_chip *chip = i2c_get_clientdata(client); | ||
230 | int ret; | ||
231 | |||
232 | lp5521_init_engine(chip, attr_group); | ||
233 | |||
234 | lp5521_write(client, LP5521_REG_RESET, 0xff); | ||
235 | |||
236 | usleep_range(10000, 20000); | ||
237 | |||
238 | /* Set all PWMs to direct control mode */ | ||
239 | ret = lp5521_write(client, LP5521_REG_OP_MODE, 0x3F); | ||
240 | |||
241 | /* Enable auto-powersave, set charge pump to auto, red to battery */ | ||
242 | ret |= lp5521_write(client, LP5521_REG_CONFIG, | ||
243 | LP5521_PWRSAVE_EN | LP5521_CP_MODE_AUTO | LP5521_R_TO_BATT); | ||
244 | |||
245 | /* Initialize all channels PWM to zero -> leds off */ | ||
246 | ret |= lp5521_write(client, LP5521_REG_R_PWM, 0); | ||
247 | ret |= lp5521_write(client, LP5521_REG_G_PWM, 0); | ||
248 | ret |= lp5521_write(client, LP5521_REG_B_PWM, 0); | ||
249 | |||
250 | /* Set engines are set to run state when OP_MODE enables engines */ | ||
251 | ret |= lp5521_write(client, LP5521_REG_ENABLE, | ||
252 | LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM | | ||
253 | LP5521_EXEC_RUN); | ||
254 | /* enable takes 500us */ | ||
255 | usleep_range(500, 20000); | ||
256 | |||
257 | return ret; | ||
258 | } | ||
259 | |||
260 | static int lp5521_run_selftest(struct lp5521_chip *chip, char *buf) | ||
261 | { | ||
262 | int ret; | ||
263 | u8 status; | ||
264 | |||
265 | ret = lp5521_read(chip->client, LP5521_REG_STATUS, &status); | ||
266 | if (ret < 0) | ||
267 | return ret; | ||
268 | |||
269 | /* Check that ext clock is really in use if requested */ | ||
270 | if (chip->pdata && chip->pdata->clock_mode == LP5521_CLOCK_EXT) | ||
271 | if ((status & LP5521_EXT_CLK_USED) == 0) | ||
272 | return -EIO; | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static void lp5521_set_brightness(struct led_classdev *cdev, | ||
277 | enum led_brightness brightness) | ||
278 | { | ||
279 | struct lp5521_led *led = cdev_to_led(cdev); | ||
280 | led->brightness = (u8)brightness; | ||
281 | schedule_work(&led->brightness_work); | ||
282 | } | ||
283 | |||
284 | static void lp5521_led_brightness_work(struct work_struct *work) | ||
285 | { | ||
286 | struct lp5521_led *led = container_of(work, | ||
287 | struct lp5521_led, | ||
288 | brightness_work); | ||
289 | struct lp5521_chip *chip = led_to_lp5521(led); | ||
290 | struct i2c_client *client = chip->client; | ||
291 | |||
292 | mutex_lock(&chip->lock); | ||
293 | lp5521_write(client, LP5521_REG_LED_PWM_BASE + led->chan_nr, | ||
294 | led->brightness); | ||
295 | mutex_unlock(&chip->lock); | ||
296 | } | ||
297 | |||
298 | /* Detect the chip by setting its ENABLE register and reading it back. */ | ||
299 | static int lp5521_detect(struct i2c_client *client) | ||
300 | { | ||
301 | int ret; | ||
302 | u8 buf; | ||
303 | |||
304 | ret = lp5521_write(client, LP5521_REG_ENABLE, | ||
305 | LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM); | ||
306 | if (ret) | ||
307 | return ret; | ||
308 | usleep_range(1000, 10000); | ||
309 | ret = lp5521_read(client, LP5521_REG_ENABLE, &buf); | ||
310 | if (ret) | ||
311 | return ret; | ||
312 | if (buf != (LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM)) | ||
313 | return -ENODEV; | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | /* Set engine mode and create appropriate sysfs attributes, if required. */ | ||
319 | static int lp5521_set_mode(struct lp5521_engine *engine, u8 mode) | ||
320 | { | ||
321 | struct lp5521_chip *chip = engine_to_lp5521(engine); | ||
322 | struct i2c_client *client = chip->client; | ||
323 | struct device *dev = &client->dev; | ||
324 | int ret = 0; | ||
325 | |||
326 | /* if in that mode already do nothing, except for run */ | ||
327 | if (mode == engine->mode && mode != LP5521_CMD_RUN) | ||
328 | return 0; | ||
329 | |||
330 | if (mode == LP5521_CMD_RUN) { | ||
331 | ret = lp5521_set_engine_mode(engine, LP5521_CMD_RUN); | ||
332 | } else if (mode == LP5521_CMD_LOAD) { | ||
333 | lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED); | ||
334 | lp5521_set_engine_mode(engine, LP5521_CMD_LOAD); | ||
335 | |||
336 | ret = sysfs_create_group(&dev->kobj, engine->attributes); | ||
337 | if (ret) | ||
338 | return ret; | ||
339 | } else if (mode == LP5521_CMD_DISABLED) { | ||
340 | lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED); | ||
341 | } | ||
342 | |||
343 | /* remove load attribute from sysfs if not in load mode */ | ||
344 | if (engine->mode == LP5521_CMD_LOAD && mode != LP5521_CMD_LOAD) | ||
345 | sysfs_remove_group(&dev->kobj, engine->attributes); | ||
346 | |||
347 | engine->mode = mode; | ||
348 | |||
349 | return ret; | ||
350 | } | ||
351 | |||
352 | static int lp5521_do_store_load(struct lp5521_engine *engine, | ||
353 | const char *buf, size_t len) | ||
354 | { | ||
355 | struct lp5521_chip *chip = engine_to_lp5521(engine); | ||
356 | struct i2c_client *client = chip->client; | ||
357 | int ret, nrchars, offset = 0, i = 0; | ||
358 | char c[3]; | ||
359 | unsigned cmd; | ||
360 | u8 pattern[LP5521_PROGRAM_LENGTH] = {0}; | ||
361 | |||
362 | while ((offset < len - 1) && (i < LP5521_PROGRAM_LENGTH)) { | ||
363 | /* separate sscanfs because length is working only for %s */ | ||
364 | ret = sscanf(buf + offset, "%2s%n ", c, &nrchars); | ||
365 | ret = sscanf(c, "%2x", &cmd); | ||
366 | if (ret != 1) | ||
367 | goto fail; | ||
368 | pattern[i] = (u8)cmd; | ||
369 | |||
370 | offset += nrchars; | ||
371 | i++; | ||
372 | } | ||
373 | |||
374 | /* Each instruction is 16bit long. Check that length is even */ | ||
375 | if (i % 2) | ||
376 | goto fail; | ||
377 | |||
378 | mutex_lock(&chip->lock); | ||
379 | ret = lp5521_load_program(engine, pattern); | ||
380 | mutex_unlock(&chip->lock); | ||
381 | |||
382 | if (ret) { | ||
383 | dev_err(&client->dev, "failed loading pattern\n"); | ||
384 | return ret; | ||
385 | } | ||
386 | |||
387 | return len; | ||
388 | fail: | ||
389 | dev_err(&client->dev, "wrong pattern format\n"); | ||
390 | return -EINVAL; | ||
391 | } | ||
392 | |||
393 | static ssize_t store_engine_load(struct device *dev, | ||
394 | struct device_attribute *attr, | ||
395 | const char *buf, size_t len, int nr) | ||
396 | { | ||
397 | struct i2c_client *client = to_i2c_client(dev); | ||
398 | struct lp5521_chip *chip = i2c_get_clientdata(client); | ||
399 | return lp5521_do_store_load(&chip->engines[nr - 1], buf, len); | ||
400 | } | ||
401 | |||
402 | #define store_load(nr) \ | ||
403 | static ssize_t store_engine##nr##_load(struct device *dev, \ | ||
404 | struct device_attribute *attr, \ | ||
405 | const char *buf, size_t len) \ | ||
406 | { \ | ||
407 | return store_engine_load(dev, attr, buf, len, nr); \ | ||
408 | } | ||
409 | store_load(1) | ||
410 | store_load(2) | ||
411 | store_load(3) | ||
412 | |||
413 | static ssize_t show_engine_mode(struct device *dev, | ||
414 | struct device_attribute *attr, | ||
415 | char *buf, int nr) | ||
416 | { | ||
417 | struct i2c_client *client = to_i2c_client(dev); | ||
418 | struct lp5521_chip *chip = i2c_get_clientdata(client); | ||
419 | switch (chip->engines[nr - 1].mode) { | ||
420 | case LP5521_CMD_RUN: | ||
421 | return sprintf(buf, "run\n"); | ||
422 | case LP5521_CMD_LOAD: | ||
423 | return sprintf(buf, "load\n"); | ||
424 | case LP5521_CMD_DISABLED: | ||
425 | return sprintf(buf, "disabled\n"); | ||
426 | default: | ||
427 | return sprintf(buf, "disabled\n"); | ||
428 | } | ||
429 | } | ||
430 | |||
431 | #define show_mode(nr) \ | ||
432 | static ssize_t show_engine##nr##_mode(struct device *dev, \ | ||
433 | struct device_attribute *attr, \ | ||
434 | char *buf) \ | ||
435 | { \ | ||
436 | return show_engine_mode(dev, attr, buf, nr); \ | ||
437 | } | ||
438 | show_mode(1) | ||
439 | show_mode(2) | ||
440 | show_mode(3) | ||
441 | |||
442 | static ssize_t store_engine_mode(struct device *dev, | ||
443 | struct device_attribute *attr, | ||
444 | const char *buf, size_t len, int nr) | ||
445 | { | ||
446 | struct i2c_client *client = to_i2c_client(dev); | ||
447 | struct lp5521_chip *chip = i2c_get_clientdata(client); | ||
448 | struct lp5521_engine *engine = &chip->engines[nr - 1]; | ||
449 | mutex_lock(&chip->lock); | ||
450 | |||
451 | if (!strncmp(buf, "run", 3)) | ||
452 | lp5521_set_mode(engine, LP5521_CMD_RUN); | ||
453 | else if (!strncmp(buf, "load", 4)) | ||
454 | lp5521_set_mode(engine, LP5521_CMD_LOAD); | ||
455 | else if (!strncmp(buf, "disabled", 8)) | ||
456 | lp5521_set_mode(engine, LP5521_CMD_DISABLED); | ||
457 | |||
458 | mutex_unlock(&chip->lock); | ||
459 | return len; | ||
460 | } | ||
461 | |||
462 | #define store_mode(nr) \ | ||
463 | static ssize_t store_engine##nr##_mode(struct device *dev, \ | ||
464 | struct device_attribute *attr, \ | ||
465 | const char *buf, size_t len) \ | ||
466 | { \ | ||
467 | return store_engine_mode(dev, attr, buf, len, nr); \ | ||
468 | } | ||
469 | store_mode(1) | ||
470 | store_mode(2) | ||
471 | store_mode(3) | ||
472 | |||
473 | static ssize_t show_max_current(struct device *dev, | ||
474 | struct device_attribute *attr, | ||
475 | char *buf) | ||
476 | { | ||
477 | struct led_classdev *led_cdev = dev_get_drvdata(dev); | ||
478 | struct lp5521_led *led = cdev_to_led(led_cdev); | ||
479 | |||
480 | return sprintf(buf, "%d\n", led->max_current); | ||
481 | } | ||
482 | |||
483 | static ssize_t show_current(struct device *dev, | ||
484 | struct device_attribute *attr, | ||
485 | char *buf) | ||
486 | { | ||
487 | struct led_classdev *led_cdev = dev_get_drvdata(dev); | ||
488 | struct lp5521_led *led = cdev_to_led(led_cdev); | ||
489 | |||
490 | return sprintf(buf, "%d\n", led->led_current); | ||
491 | } | ||
492 | |||
493 | static ssize_t store_current(struct device *dev, | ||
494 | struct device_attribute *attr, | ||
495 | const char *buf, size_t len) | ||
496 | { | ||
497 | struct led_classdev *led_cdev = dev_get_drvdata(dev); | ||
498 | struct lp5521_led *led = cdev_to_led(led_cdev); | ||
499 | struct lp5521_chip *chip = led_to_lp5521(led); | ||
500 | ssize_t ret; | ||
501 | unsigned long curr; | ||
502 | |||
503 | if (strict_strtoul(buf, 0, &curr)) | ||
504 | return -EINVAL; | ||
505 | |||
506 | if (curr > led->max_current) | ||
507 | return -EINVAL; | ||
508 | |||
509 | mutex_lock(&chip->lock); | ||
510 | ret = lp5521_set_led_current(chip, led->id, curr); | ||
511 | mutex_unlock(&chip->lock); | ||
512 | |||
513 | if (ret < 0) | ||
514 | return ret; | ||
515 | |||
516 | led->led_current = (u8)curr; | ||
517 | |||
518 | return len; | ||
519 | } | ||
520 | |||
521 | static ssize_t lp5521_selftest(struct device *dev, | ||
522 | struct device_attribute *attr, | ||
523 | char *buf) | ||
524 | { | ||
525 | struct i2c_client *client = to_i2c_client(dev); | ||
526 | struct lp5521_chip *chip = i2c_get_clientdata(client); | ||
527 | int ret; | ||
528 | |||
529 | mutex_lock(&chip->lock); | ||
530 | ret = lp5521_run_selftest(chip, buf); | ||
531 | mutex_unlock(&chip->lock); | ||
532 | return sprintf(buf, "%s\n", ret ? "FAIL" : "OK"); | ||
533 | } | ||
534 | |||
535 | /* led class device attributes */ | ||
536 | static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current); | ||
537 | static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL); | ||
538 | |||
539 | static struct attribute *lp5521_led_attributes[] = { | ||
540 | &dev_attr_led_current.attr, | ||
541 | &dev_attr_max_current.attr, | ||
542 | NULL, | ||
543 | }; | ||
544 | |||
545 | static struct attribute_group lp5521_led_attribute_group = { | ||
546 | .attrs = lp5521_led_attributes | ||
547 | }; | ||
548 | |||
549 | /* device attributes */ | ||
550 | static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUGO, | ||
551 | show_engine1_mode, store_engine1_mode); | ||
552 | static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUGO, | ||
553 | show_engine2_mode, store_engine2_mode); | ||
554 | static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUGO, | ||
555 | show_engine3_mode, store_engine3_mode); | ||
556 | static DEVICE_ATTR(engine1_load, S_IWUGO, NULL, store_engine1_load); | ||
557 | static DEVICE_ATTR(engine2_load, S_IWUGO, NULL, store_engine2_load); | ||
558 | static DEVICE_ATTR(engine3_load, S_IWUGO, NULL, store_engine3_load); | ||
559 | static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL); | ||
560 | |||
561 | static struct attribute *lp5521_attributes[] = { | ||
562 | &dev_attr_engine1_mode.attr, | ||
563 | &dev_attr_engine2_mode.attr, | ||
564 | &dev_attr_engine3_mode.attr, | ||
565 | &dev_attr_selftest.attr, | ||
566 | NULL | ||
567 | }; | ||
568 | |||
569 | static struct attribute *lp5521_engine1_attributes[] = { | ||
570 | &dev_attr_engine1_load.attr, | ||
571 | NULL | ||
572 | }; | ||
573 | |||
574 | static struct attribute *lp5521_engine2_attributes[] = { | ||
575 | &dev_attr_engine2_load.attr, | ||
576 | NULL | ||
577 | }; | ||
578 | |||
579 | static struct attribute *lp5521_engine3_attributes[] = { | ||
580 | &dev_attr_engine3_load.attr, | ||
581 | NULL | ||
582 | }; | ||
583 | |||
584 | static const struct attribute_group lp5521_group = { | ||
585 | .attrs = lp5521_attributes, | ||
586 | }; | ||
587 | |||
588 | static const struct attribute_group lp5521_engine_group[] = { | ||
589 | {.attrs = lp5521_engine1_attributes }, | ||
590 | {.attrs = lp5521_engine2_attributes }, | ||
591 | {.attrs = lp5521_engine3_attributes }, | ||
592 | }; | ||
593 | |||
594 | static int lp5521_register_sysfs(struct i2c_client *client) | ||
595 | { | ||
596 | struct device *dev = &client->dev; | ||
597 | return sysfs_create_group(&dev->kobj, &lp5521_group); | ||
598 | } | ||
599 | |||
600 | static void lp5521_unregister_sysfs(struct i2c_client *client) | ||
601 | { | ||
602 | struct lp5521_chip *chip = i2c_get_clientdata(client); | ||
603 | struct device *dev = &client->dev; | ||
604 | int i; | ||
605 | |||
606 | sysfs_remove_group(&dev->kobj, &lp5521_group); | ||
607 | |||
608 | for (i = 0; i < ARRAY_SIZE(chip->engines); i++) { | ||
609 | if (chip->engines[i].mode == LP5521_CMD_LOAD) | ||
610 | sysfs_remove_group(&dev->kobj, | ||
611 | chip->engines[i].attributes); | ||
612 | } | ||
613 | |||
614 | for (i = 0; i < chip->num_leds; i++) | ||
615 | sysfs_remove_group(&chip->leds[i].cdev.dev->kobj, | ||
616 | &lp5521_led_attribute_group); | ||
617 | } | ||
618 | |||
619 | static int __init lp5521_init_led(struct lp5521_led *led, | ||
620 | struct i2c_client *client, | ||
621 | int chan, struct lp5521_platform_data *pdata) | ||
622 | { | ||
623 | struct device *dev = &client->dev; | ||
624 | char name[32]; | ||
625 | int res; | ||
626 | |||
627 | if (chan >= LP5521_MAX_LEDS) | ||
628 | return -EINVAL; | ||
629 | |||
630 | if (pdata->led_config[chan].led_current == 0) | ||
631 | return 0; | ||
632 | |||
633 | led->led_current = pdata->led_config[chan].led_current; | ||
634 | led->max_current = pdata->led_config[chan].max_current; | ||
635 | led->chan_nr = pdata->led_config[chan].chan_nr; | ||
636 | |||
637 | if (led->chan_nr >= LP5521_MAX_LEDS) { | ||
638 | dev_err(dev, "Use channel numbers between 0 and %d\n", | ||
639 | LP5521_MAX_LEDS - 1); | ||
640 | return -EINVAL; | ||
641 | } | ||
642 | |||
643 | snprintf(name, sizeof(name), "%s:channel%d", client->name, chan); | ||
644 | led->cdev.brightness_set = lp5521_set_brightness; | ||
645 | led->cdev.name = name; | ||
646 | res = led_classdev_register(dev, &led->cdev); | ||
647 | if (res < 0) { | ||
648 | dev_err(dev, "couldn't register led on channel %d\n", chan); | ||
649 | return res; | ||
650 | } | ||
651 | |||
652 | res = sysfs_create_group(&led->cdev.dev->kobj, | ||
653 | &lp5521_led_attribute_group); | ||
654 | if (res < 0) { | ||
655 | dev_err(dev, "couldn't register current attribute\n"); | ||
656 | led_classdev_unregister(&led->cdev); | ||
657 | return res; | ||
658 | } | ||
659 | return 0; | ||
660 | } | ||
661 | |||
662 | static int lp5521_probe(struct i2c_client *client, | ||
663 | const struct i2c_device_id *id) | ||
664 | { | ||
665 | struct lp5521_chip *chip; | ||
666 | struct lp5521_platform_data *pdata; | ||
667 | int ret, i, led; | ||
668 | |||
669 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | ||
670 | if (!chip) | ||
671 | return -ENOMEM; | ||
672 | |||
673 | i2c_set_clientdata(client, chip); | ||
674 | chip->client = client; | ||
675 | |||
676 | pdata = client->dev.platform_data; | ||
677 | |||
678 | if (!pdata) { | ||
679 | dev_err(&client->dev, "no platform data\n"); | ||
680 | ret = -EINVAL; | ||
681 | goto fail1; | ||
682 | } | ||
683 | |||
684 | mutex_init(&chip->lock); | ||
685 | |||
686 | chip->pdata = pdata; | ||
687 | |||
688 | if (pdata->setup_resources) { | ||
689 | ret = pdata->setup_resources(); | ||
690 | if (ret < 0) | ||
691 | goto fail1; | ||
692 | } | ||
693 | |||
694 | if (pdata->enable) { | ||
695 | pdata->enable(0); | ||
696 | usleep_range(1000, 10000); | ||
697 | pdata->enable(1); | ||
698 | usleep_range(1000, 10000); /* Spec says min 500us */ | ||
699 | } | ||
700 | |||
701 | ret = lp5521_detect(client); | ||
702 | |||
703 | if (ret) { | ||
704 | dev_err(&client->dev, "Chip not found\n"); | ||
705 | goto fail2; | ||
706 | } | ||
707 | |||
708 | dev_info(&client->dev, "%s programmable led chip found\n", id->name); | ||
709 | |||
710 | ret = lp5521_configure(client, lp5521_engine_group); | ||
711 | if (ret < 0) { | ||
712 | dev_err(&client->dev, "error configuring chip\n"); | ||
713 | goto fail2; | ||
714 | } | ||
715 | |||
716 | /* Initialize leds */ | ||
717 | chip->num_channels = pdata->num_channels; | ||
718 | chip->num_leds = 0; | ||
719 | led = 0; | ||
720 | for (i = 0; i < pdata->num_channels; i++) { | ||
721 | /* Do not initialize channels that are not connected */ | ||
722 | if (pdata->led_config[i].led_current == 0) | ||
723 | continue; | ||
724 | |||
725 | ret = lp5521_init_led(&chip->leds[led], client, i, pdata); | ||
726 | if (ret) { | ||
727 | dev_err(&client->dev, "error initializing leds\n"); | ||
728 | goto fail3; | ||
729 | } | ||
730 | chip->num_leds++; | ||
731 | |||
732 | chip->leds[led].id = led; | ||
733 | /* Set initial LED current */ | ||
734 | lp5521_set_led_current(chip, led, | ||
735 | chip->leds[led].led_current); | ||
736 | |||
737 | INIT_WORK(&(chip->leds[led].brightness_work), | ||
738 | lp5521_led_brightness_work); | ||
739 | |||
740 | led++; | ||
741 | } | ||
742 | |||
743 | ret = lp5521_register_sysfs(client); | ||
744 | if (ret) { | ||
745 | dev_err(&client->dev, "registering sysfs failed\n"); | ||
746 | goto fail3; | ||
747 | } | ||
748 | return ret; | ||
749 | fail3: | ||
750 | for (i = 0; i < chip->num_leds; i++) { | ||
751 | led_classdev_unregister(&chip->leds[i].cdev); | ||
752 | cancel_work_sync(&chip->leds[i].brightness_work); | ||
753 | } | ||
754 | fail2: | ||
755 | if (pdata->enable) | ||
756 | pdata->enable(0); | ||
757 | if (pdata->release_resources) | ||
758 | pdata->release_resources(); | ||
759 | fail1: | ||
760 | kfree(chip); | ||
761 | return ret; | ||
762 | } | ||
763 | |||
764 | static int lp5521_remove(struct i2c_client *client) | ||
765 | { | ||
766 | struct lp5521_chip *chip = i2c_get_clientdata(client); | ||
767 | int i; | ||
768 | |||
769 | lp5521_unregister_sysfs(client); | ||
770 | |||
771 | for (i = 0; i < chip->num_leds; i++) { | ||
772 | led_classdev_unregister(&chip->leds[i].cdev); | ||
773 | cancel_work_sync(&chip->leds[i].brightness_work); | ||
774 | } | ||
775 | |||
776 | if (chip->pdata->enable) | ||
777 | chip->pdata->enable(0); | ||
778 | if (chip->pdata->release_resources) | ||
779 | chip->pdata->release_resources(); | ||
780 | kfree(chip); | ||
781 | return 0; | ||
782 | } | ||
783 | |||
784 | static const struct i2c_device_id lp5521_id[] = { | ||
785 | { "lp5521", 0 }, /* Three channel chip */ | ||
786 | { } | ||
787 | }; | ||
788 | MODULE_DEVICE_TABLE(i2c, lp5521_id); | ||
789 | |||
790 | static struct i2c_driver lp5521_driver = { | ||
791 | .driver = { | ||
792 | .name = "lp5521", | ||
793 | }, | ||
794 | .probe = lp5521_probe, | ||
795 | .remove = lp5521_remove, | ||
796 | .id_table = lp5521_id, | ||
797 | }; | ||
798 | |||
799 | static int __init lp5521_init(void) | ||
800 | { | ||
801 | int ret; | ||
802 | |||
803 | ret = i2c_add_driver(&lp5521_driver); | ||
804 | |||
805 | if (ret < 0) | ||
806 | printk(KERN_ALERT "Adding lp5521 driver failed\n"); | ||
807 | |||
808 | return ret; | ||
809 | } | ||
810 | |||
811 | static void __exit lp5521_exit(void) | ||
812 | { | ||
813 | i2c_del_driver(&lp5521_driver); | ||
814 | } | ||
815 | |||
816 | module_init(lp5521_init); | ||
817 | module_exit(lp5521_exit); | ||
818 | |||
819 | MODULE_AUTHOR("Mathias Nyman, Yuri Zaporozhets, Samu Onkalo"); | ||
820 | MODULE_DESCRIPTION("LP5521 LED engine"); | ||
821 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c new file mode 100644 index 000000000000..1e11fcc08b28 --- /dev/null +++ b/drivers/leds/leds-lp5523.c | |||
@@ -0,0 +1,1065 @@ | |||
1 | /* | ||
2 | * lp5523.c - LP5523 LED Driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Samu Onkalo <samu.p.onkalo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/mutex.h> | ||
27 | #include <linux/gpio.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/ctype.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | #include <linux/wait.h> | ||
33 | #include <linux/leds.h> | ||
34 | #include <linux/leds-lp5523.h> | ||
35 | #include <linux/workqueue.h> | ||
36 | #include <linux/slab.h> | ||
37 | |||
38 | #define LP5523_REG_ENABLE 0x00 | ||
39 | #define LP5523_REG_OP_MODE 0x01 | ||
40 | #define LP5523_REG_RATIOMETRIC_MSB 0x02 | ||
41 | #define LP5523_REG_RATIOMETRIC_LSB 0x03 | ||
42 | #define LP5523_REG_ENABLE_LEDS_MSB 0x04 | ||
43 | #define LP5523_REG_ENABLE_LEDS_LSB 0x05 | ||
44 | #define LP5523_REG_LED_CNTRL_BASE 0x06 | ||
45 | #define LP5523_REG_LED_PWM_BASE 0x16 | ||
46 | #define LP5523_REG_LED_CURRENT_BASE 0x26 | ||
47 | #define LP5523_REG_CONFIG 0x36 | ||
48 | #define LP5523_REG_CHANNEL1_PC 0x37 | ||
49 | #define LP5523_REG_CHANNEL2_PC 0x38 | ||
50 | #define LP5523_REG_CHANNEL3_PC 0x39 | ||
51 | #define LP5523_REG_STATUS 0x3a | ||
52 | #define LP5523_REG_GPO 0x3b | ||
53 | #define LP5523_REG_VARIABLE 0x3c | ||
54 | #define LP5523_REG_RESET 0x3d | ||
55 | #define LP5523_REG_TEMP_CTRL 0x3e | ||
56 | #define LP5523_REG_TEMP_READ 0x3f | ||
57 | #define LP5523_REG_TEMP_WRITE 0x40 | ||
58 | #define LP5523_REG_LED_TEST_CTRL 0x41 | ||
59 | #define LP5523_REG_LED_TEST_ADC 0x42 | ||
60 | #define LP5523_REG_ENG1_VARIABLE 0x45 | ||
61 | #define LP5523_REG_ENG2_VARIABLE 0x46 | ||
62 | #define LP5523_REG_ENG3_VARIABLE 0x47 | ||
63 | #define LP5523_REG_MASTER_FADER1 0x48 | ||
64 | #define LP5523_REG_MASTER_FADER2 0x49 | ||
65 | #define LP5523_REG_MASTER_FADER3 0x4a | ||
66 | #define LP5523_REG_CH1_PROG_START 0x4c | ||
67 | #define LP5523_REG_CH2_PROG_START 0x4d | ||
68 | #define LP5523_REG_CH3_PROG_START 0x4e | ||
69 | #define LP5523_REG_PROG_PAGE_SEL 0x4f | ||
70 | #define LP5523_REG_PROG_MEM 0x50 | ||
71 | |||
72 | #define LP5523_CMD_LOAD 0x15 /* 00010101 */ | ||
73 | #define LP5523_CMD_RUN 0x2a /* 00101010 */ | ||
74 | #define LP5523_CMD_DISABLED 0x00 /* 00000000 */ | ||
75 | |||
76 | #define LP5523_ENABLE 0x40 | ||
77 | #define LP5523_AUTO_INC 0x40 | ||
78 | #define LP5523_PWR_SAVE 0x20 | ||
79 | #define LP5523_PWM_PWR_SAVE 0x04 | ||
80 | #define LP5523_CP_1 0x08 | ||
81 | #define LP5523_CP_1_5 0x10 | ||
82 | #define LP5523_CP_AUTO 0x18 | ||
83 | #define LP5523_INT_CLK 0x01 | ||
84 | #define LP5523_AUTO_CLK 0x02 | ||
85 | #define LP5523_EN_LEDTEST 0x80 | ||
86 | #define LP5523_LEDTEST_DONE 0x80 | ||
87 | |||
88 | #define LP5523_DEFAULT_CURRENT 50 /* microAmps */ | ||
89 | #define LP5523_PROGRAM_LENGTH 32 /* in bytes */ | ||
90 | #define LP5523_PROGRAM_PAGES 6 | ||
91 | #define LP5523_ADC_SHORTCIRC_LIM 80 | ||
92 | |||
93 | #define LP5523_LEDS 9 | ||
94 | #define LP5523_ENGINES 3 | ||
95 | |||
96 | #define LP5523_ENG_MASK_BASE 0x30 /* 00110000 */ | ||
97 | |||
98 | #define LP5523_ENG_STATUS_MASK 0x07 /* 00000111 */ | ||
99 | |||
100 | #define LP5523_IRQ_FLAGS IRQF_TRIGGER_FALLING | ||
101 | |||
102 | #define LP5523_EXT_CLK_USED 0x08 | ||
103 | |||
104 | #define LED_ACTIVE(mux, led) (!!(mux & (0x0001 << led))) | ||
105 | #define SHIFT_MASK(id) (((id) - 1) * 2) | ||
106 | |||
107 | struct lp5523_engine { | ||
108 | const struct attribute_group *attributes; | ||
109 | int id; | ||
110 | u8 mode; | ||
111 | u8 prog_page; | ||
112 | u8 mux_page; | ||
113 | u16 led_mux; | ||
114 | u8 engine_mask; | ||
115 | }; | ||
116 | |||
117 | struct lp5523_led { | ||
118 | int id; | ||
119 | u8 chan_nr; | ||
120 | u8 led_current; | ||
121 | u8 max_current; | ||
122 | struct led_classdev cdev; | ||
123 | struct work_struct brightness_work; | ||
124 | u8 brightness; | ||
125 | }; | ||
126 | |||
127 | struct lp5523_chip { | ||
128 | struct mutex lock; /* Serialize control */ | ||
129 | struct i2c_client *client; | ||
130 | struct lp5523_engine engines[LP5523_ENGINES]; | ||
131 | struct lp5523_led leds[LP5523_LEDS]; | ||
132 | struct lp5523_platform_data *pdata; | ||
133 | u8 num_channels; | ||
134 | u8 num_leds; | ||
135 | }; | ||
136 | |||
137 | #define cdev_to_led(c) container_of(c, struct lp5523_led, cdev) | ||
138 | |||
139 | static struct lp5523_chip *engine_to_lp5523(struct lp5523_engine *engine) | ||
140 | { | ||
141 | return container_of(engine, struct lp5523_chip, | ||
142 | engines[engine->id - 1]); | ||
143 | } | ||
144 | |||
145 | static struct lp5523_chip *led_to_lp5523(struct lp5523_led *led) | ||
146 | { | ||
147 | return container_of(led, struct lp5523_chip, | ||
148 | leds[led->id]); | ||
149 | } | ||
150 | |||
151 | static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode); | ||
152 | static int lp5523_set_engine_mode(struct lp5523_engine *engine, u8 mode); | ||
153 | static int lp5523_load_program(struct lp5523_engine *engine, u8 *pattern); | ||
154 | |||
155 | static void lp5523_led_brightness_work(struct work_struct *work); | ||
156 | |||
157 | static int lp5523_write(struct i2c_client *client, u8 reg, u8 value) | ||
158 | { | ||
159 | return i2c_smbus_write_byte_data(client, reg, value); | ||
160 | } | ||
161 | |||
162 | static int lp5523_read(struct i2c_client *client, u8 reg, u8 *buf) | ||
163 | { | ||
164 | s32 ret = i2c_smbus_read_byte_data(client, reg); | ||
165 | |||
166 | if (ret < 0) | ||
167 | return -EIO; | ||
168 | |||
169 | *buf = ret; | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static int lp5523_detect(struct i2c_client *client) | ||
174 | { | ||
175 | int ret; | ||
176 | u8 buf; | ||
177 | |||
178 | ret = lp5523_write(client, LP5523_REG_ENABLE, 0x40); | ||
179 | if (ret) | ||
180 | return ret; | ||
181 | ret = lp5523_read(client, LP5523_REG_ENABLE, &buf); | ||
182 | if (ret) | ||
183 | return ret; | ||
184 | if (buf == 0x40) | ||
185 | return 0; | ||
186 | else | ||
187 | return -ENODEV; | ||
188 | } | ||
189 | |||
190 | static int lp5523_configure(struct i2c_client *client) | ||
191 | { | ||
192 | struct lp5523_chip *chip = i2c_get_clientdata(client); | ||
193 | int ret = 0; | ||
194 | u8 status; | ||
195 | |||
196 | /* one pattern per engine setting led mux start and stop addresses */ | ||
197 | u8 pattern[][LP5523_PROGRAM_LENGTH] = { | ||
198 | { 0x9c, 0x30, 0x9c, 0xb0, 0x9d, 0x80, 0xd8, 0x00, 0}, | ||
199 | { 0x9c, 0x40, 0x9c, 0xc0, 0x9d, 0x80, 0xd8, 0x00, 0}, | ||
200 | { 0x9c, 0x50, 0x9c, 0xd0, 0x9d, 0x80, 0xd8, 0x00, 0}, | ||
201 | }; | ||
202 | |||
203 | lp5523_write(client, LP5523_REG_RESET, 0xff); | ||
204 | |||
205 | usleep_range(10000, 100000); | ||
206 | |||
207 | ret |= lp5523_write(client, LP5523_REG_ENABLE, LP5523_ENABLE); | ||
208 | /* Chip startup time after reset is 500 us */ | ||
209 | usleep_range(1000, 10000); | ||
210 | |||
211 | ret |= lp5523_write(client, LP5523_REG_CONFIG, | ||
212 | LP5523_AUTO_INC | LP5523_PWR_SAVE | | ||
213 | LP5523_CP_AUTO | LP5523_AUTO_CLK | | ||
214 | LP5523_PWM_PWR_SAVE); | ||
215 | |||
216 | /* turn on all leds */ | ||
217 | ret |= lp5523_write(client, LP5523_REG_ENABLE_LEDS_MSB, 0x01); | ||
218 | ret |= lp5523_write(client, LP5523_REG_ENABLE_LEDS_LSB, 0xff); | ||
219 | |||
220 | /* hardcode 32 bytes of memory for each engine from program memory */ | ||
221 | ret |= lp5523_write(client, LP5523_REG_CH1_PROG_START, 0x00); | ||
222 | ret |= lp5523_write(client, LP5523_REG_CH2_PROG_START, 0x10); | ||
223 | ret |= lp5523_write(client, LP5523_REG_CH3_PROG_START, 0x20); | ||
224 | |||
225 | /* write led mux address space for each channel */ | ||
226 | ret |= lp5523_load_program(&chip->engines[0], pattern[0]); | ||
227 | ret |= lp5523_load_program(&chip->engines[1], pattern[1]); | ||
228 | ret |= lp5523_load_program(&chip->engines[2], pattern[2]); | ||
229 | |||
230 | if (ret) { | ||
231 | dev_err(&client->dev, "could not load mux programs\n"); | ||
232 | return -1; | ||
233 | } | ||
234 | |||
235 | /* set all engines exec state and mode to run 00101010 */ | ||
236 | ret |= lp5523_write(client, LP5523_REG_ENABLE, | ||
237 | (LP5523_CMD_RUN | LP5523_ENABLE)); | ||
238 | |||
239 | ret |= lp5523_write(client, LP5523_REG_OP_MODE, LP5523_CMD_RUN); | ||
240 | |||
241 | if (ret) { | ||
242 | dev_err(&client->dev, "could not start mux programs\n"); | ||
243 | return -1; | ||
244 | } | ||
245 | |||
246 | /* Wait 3ms and check the engine status */ | ||
247 | usleep_range(3000, 20000); | ||
248 | lp5523_read(client, LP5523_REG_STATUS, &status); | ||
249 | status &= LP5523_ENG_STATUS_MASK; | ||
250 | |||
251 | if (status == LP5523_ENG_STATUS_MASK) { | ||
252 | dev_dbg(&client->dev, "all engines configured\n"); | ||
253 | } else { | ||
254 | dev_info(&client->dev, "status == %x\n", status); | ||
255 | dev_err(&client->dev, "cound not configure LED engine\n"); | ||
256 | return -1; | ||
257 | } | ||
258 | |||
259 | dev_info(&client->dev, "disabling engines\n"); | ||
260 | |||
261 | ret |= lp5523_write(client, LP5523_REG_OP_MODE, LP5523_CMD_DISABLED); | ||
262 | |||
263 | return ret; | ||
264 | } | ||
265 | |||
266 | static int lp5523_set_engine_mode(struct lp5523_engine *engine, u8 mode) | ||
267 | { | ||
268 | struct lp5523_chip *chip = engine_to_lp5523(engine); | ||
269 | struct i2c_client *client = chip->client; | ||
270 | int ret; | ||
271 | u8 engine_state; | ||
272 | |||
273 | ret = lp5523_read(client, LP5523_REG_OP_MODE, &engine_state); | ||
274 | if (ret) | ||
275 | goto fail; | ||
276 | |||
277 | engine_state &= ~(engine->engine_mask); | ||
278 | |||
279 | /* set mode only for this engine */ | ||
280 | mode &= engine->engine_mask; | ||
281 | |||
282 | engine_state |= mode; | ||
283 | |||
284 | ret |= lp5523_write(client, LP5523_REG_OP_MODE, engine_state); | ||
285 | fail: | ||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | static int lp5523_load_mux(struct lp5523_engine *engine, u16 mux) | ||
290 | { | ||
291 | struct lp5523_chip *chip = engine_to_lp5523(engine); | ||
292 | struct i2c_client *client = chip->client; | ||
293 | int ret = 0; | ||
294 | |||
295 | ret |= lp5523_set_engine_mode(engine, LP5523_CMD_LOAD); | ||
296 | |||
297 | ret |= lp5523_write(client, LP5523_REG_PROG_PAGE_SEL, engine->mux_page); | ||
298 | ret |= lp5523_write(client, LP5523_REG_PROG_MEM, | ||
299 | (u8)(mux >> 8)); | ||
300 | ret |= lp5523_write(client, LP5523_REG_PROG_MEM + 1, (u8)(mux)); | ||
301 | engine->led_mux = mux; | ||
302 | |||
303 | return ret; | ||
304 | } | ||
305 | |||
306 | static int lp5523_load_program(struct lp5523_engine *engine, u8 *pattern) | ||
307 | { | ||
308 | struct lp5523_chip *chip = engine_to_lp5523(engine); | ||
309 | struct i2c_client *client = chip->client; | ||
310 | |||
311 | int ret = 0; | ||
312 | |||
313 | ret |= lp5523_set_engine_mode(engine, LP5523_CMD_LOAD); | ||
314 | |||
315 | ret |= lp5523_write(client, LP5523_REG_PROG_PAGE_SEL, | ||
316 | engine->prog_page); | ||
317 | ret |= i2c_smbus_write_i2c_block_data(client, LP5523_REG_PROG_MEM, | ||
318 | LP5523_PROGRAM_LENGTH, pattern); | ||
319 | |||
320 | return ret; | ||
321 | } | ||
322 | |||
323 | static int lp5523_run_program(struct lp5523_engine *engine) | ||
324 | { | ||
325 | struct lp5523_chip *chip = engine_to_lp5523(engine); | ||
326 | struct i2c_client *client = chip->client; | ||
327 | int ret; | ||
328 | |||
329 | ret = lp5523_write(client, LP5523_REG_ENABLE, | ||
330 | LP5523_CMD_RUN | LP5523_ENABLE); | ||
331 | if (ret) | ||
332 | goto fail; | ||
333 | |||
334 | ret = lp5523_set_engine_mode(engine, LP5523_CMD_RUN); | ||
335 | fail: | ||
336 | return ret; | ||
337 | } | ||
338 | |||
339 | static int lp5523_mux_parse(const char *buf, u16 *mux, size_t len) | ||
340 | { | ||
341 | int i; | ||
342 | u16 tmp_mux = 0; | ||
343 | len = len < LP5523_LEDS ? len : LP5523_LEDS; | ||
344 | for (i = 0; i < len; i++) { | ||
345 | switch (buf[i]) { | ||
346 | case '1': | ||
347 | tmp_mux |= (1 << i); | ||
348 | break; | ||
349 | case '0': | ||
350 | break; | ||
351 | case '\n': | ||
352 | i = len; | ||
353 | break; | ||
354 | default: | ||
355 | return -1; | ||
356 | } | ||
357 | } | ||
358 | *mux = tmp_mux; | ||
359 | |||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | static void lp5523_mux_to_array(u16 led_mux, char *array) | ||
364 | { | ||
365 | int i, pos = 0; | ||
366 | for (i = 0; i < LP5523_LEDS; i++) | ||
367 | pos += sprintf(array + pos, "%x", LED_ACTIVE(led_mux, i)); | ||
368 | |||
369 | array[pos] = '\0'; | ||
370 | } | ||
371 | |||
372 | /*--------------------------------------------------------------*/ | ||
373 | /* Sysfs interface */ | ||
374 | /*--------------------------------------------------------------*/ | ||
375 | |||
376 | static ssize_t show_engine_leds(struct device *dev, | ||
377 | struct device_attribute *attr, | ||
378 | char *buf, int nr) | ||
379 | { | ||
380 | struct i2c_client *client = to_i2c_client(dev); | ||
381 | struct lp5523_chip *chip = i2c_get_clientdata(client); | ||
382 | char mux[LP5523_LEDS + 1]; | ||
383 | |||
384 | lp5523_mux_to_array(chip->engines[nr - 1].led_mux, mux); | ||
385 | |||
386 | return sprintf(buf, "%s\n", mux); | ||
387 | } | ||
388 | |||
389 | #define show_leds(nr) \ | ||
390 | static ssize_t show_engine##nr##_leds(struct device *dev, \ | ||
391 | struct device_attribute *attr, \ | ||
392 | char *buf) \ | ||
393 | { \ | ||
394 | return show_engine_leds(dev, attr, buf, nr); \ | ||
395 | } | ||
396 | show_leds(1) | ||
397 | show_leds(2) | ||
398 | show_leds(3) | ||
399 | |||
400 | static ssize_t store_engine_leds(struct device *dev, | ||
401 | struct device_attribute *attr, | ||
402 | const char *buf, size_t len, int nr) | ||
403 | { | ||
404 | struct i2c_client *client = to_i2c_client(dev); | ||
405 | struct lp5523_chip *chip = i2c_get_clientdata(client); | ||
406 | u16 mux = 0; | ||
407 | |||
408 | if (lp5523_mux_parse(buf, &mux, len)) | ||
409 | return -EINVAL; | ||
410 | |||
411 | if (lp5523_load_mux(&chip->engines[nr - 1], mux)) | ||
412 | return -EINVAL; | ||
413 | |||
414 | return len; | ||
415 | } | ||
416 | |||
417 | #define store_leds(nr) \ | ||
418 | static ssize_t store_engine##nr##_leds(struct device *dev, \ | ||
419 | struct device_attribute *attr, \ | ||
420 | const char *buf, size_t len) \ | ||
421 | { \ | ||
422 | return store_engine_leds(dev, attr, buf, len, nr); \ | ||
423 | } | ||
424 | store_leds(1) | ||
425 | store_leds(2) | ||
426 | store_leds(3) | ||
427 | |||
428 | static ssize_t lp5523_selftest(struct device *dev, | ||
429 | struct device_attribute *attr, | ||
430 | char *buf) | ||
431 | { | ||
432 | struct i2c_client *client = to_i2c_client(dev); | ||
433 | struct lp5523_chip *chip = i2c_get_clientdata(client); | ||
434 | int i, ret, pos = 0; | ||
435 | int led = 0; | ||
436 | u8 status, adc, vdd; | ||
437 | |||
438 | mutex_lock(&chip->lock); | ||
439 | |||
440 | ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status); | ||
441 | if (ret < 0) | ||
442 | goto fail; | ||
443 | |||
444 | /* Check that ext clock is really in use if requested */ | ||
445 | if ((chip->pdata) && (chip->pdata->clock_mode == LP5523_CLOCK_EXT)) | ||
446 | if ((status & LP5523_EXT_CLK_USED) == 0) | ||
447 | goto fail; | ||
448 | |||
449 | /* Measure VDD (i.e. VBAT) first (channel 16 corresponds to VDD) */ | ||
450 | lp5523_write(chip->client, LP5523_REG_LED_TEST_CTRL, | ||
451 | LP5523_EN_LEDTEST | 16); | ||
452 | usleep_range(3000, 10000); | ||
453 | ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status); | ||
454 | if (!(status & LP5523_LEDTEST_DONE)) | ||
455 | usleep_range(3000, 10000); | ||
456 | |||
457 | ret |= lp5523_read(chip->client, LP5523_REG_LED_TEST_ADC, &vdd); | ||
458 | vdd--; /* There may be some fluctuation in measurement */ | ||
459 | |||
460 | for (i = 0; i < LP5523_LEDS; i++) { | ||
461 | /* Skip non-existing channels */ | ||
462 | if (chip->pdata->led_config[i].led_current == 0) | ||
463 | continue; | ||
464 | |||
465 | /* Set default current */ | ||
466 | lp5523_write(chip->client, | ||
467 | LP5523_REG_LED_CURRENT_BASE + i, | ||
468 | chip->pdata->led_config[i].led_current); | ||
469 | |||
470 | lp5523_write(chip->client, LP5523_REG_LED_PWM_BASE + i, 0xff); | ||
471 | /* let current stabilize 2ms before measurements start */ | ||
472 | usleep_range(2000, 10000); | ||
473 | lp5523_write(chip->client, | ||
474 | LP5523_REG_LED_TEST_CTRL, | ||
475 | LP5523_EN_LEDTEST | i); | ||
476 | /* ledtest takes 2.7ms */ | ||
477 | usleep_range(3000, 10000); | ||
478 | ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status); | ||
479 | if (!(status & LP5523_LEDTEST_DONE)) | ||
480 | usleep_range(3000, 10000); | ||
481 | ret |= lp5523_read(chip->client, LP5523_REG_LED_TEST_ADC, &adc); | ||
482 | |||
483 | if (adc >= vdd || adc < LP5523_ADC_SHORTCIRC_LIM) | ||
484 | pos += sprintf(buf + pos, "LED %d FAIL\n", i); | ||
485 | |||
486 | lp5523_write(chip->client, LP5523_REG_LED_PWM_BASE + i, 0x00); | ||
487 | |||
488 | /* Restore current */ | ||
489 | lp5523_write(chip->client, | ||
490 | LP5523_REG_LED_CURRENT_BASE + i, | ||
491 | chip->leds[led].led_current); | ||
492 | led++; | ||
493 | } | ||
494 | if (pos == 0) | ||
495 | pos = sprintf(buf, "OK\n"); | ||
496 | goto release_lock; | ||
497 | fail: | ||
498 | pos = sprintf(buf, "FAIL\n"); | ||
499 | |||
500 | release_lock: | ||
501 | mutex_unlock(&chip->lock); | ||
502 | |||
503 | return pos; | ||
504 | } | ||
505 | |||
506 | static void lp5523_set_brightness(struct led_classdev *cdev, | ||
507 | enum led_brightness brightness) | ||
508 | { | ||
509 | struct lp5523_led *led = cdev_to_led(cdev); | ||
510 | |||
511 | led->brightness = (u8)brightness; | ||
512 | |||
513 | schedule_work(&led->brightness_work); | ||
514 | } | ||
515 | |||
516 | static void lp5523_led_brightness_work(struct work_struct *work) | ||
517 | { | ||
518 | struct lp5523_led *led = container_of(work, | ||
519 | struct lp5523_led, | ||
520 | brightness_work); | ||
521 | struct lp5523_chip *chip = led_to_lp5523(led); | ||
522 | struct i2c_client *client = chip->client; | ||
523 | |||
524 | mutex_lock(&chip->lock); | ||
525 | |||
526 | lp5523_write(client, LP5523_REG_LED_PWM_BASE + led->chan_nr, | ||
527 | led->brightness); | ||
528 | |||
529 | mutex_unlock(&chip->lock); | ||
530 | } | ||
531 | |||
532 | static int lp5523_do_store_load(struct lp5523_engine *engine, | ||
533 | const char *buf, size_t len) | ||
534 | { | ||
535 | struct lp5523_chip *chip = engine_to_lp5523(engine); | ||
536 | struct i2c_client *client = chip->client; | ||
537 | int ret, nrchars, offset = 0, i = 0; | ||
538 | char c[3]; | ||
539 | unsigned cmd; | ||
540 | u8 pattern[LP5523_PROGRAM_LENGTH] = {0}; | ||
541 | |||
542 | while ((offset < len - 1) && (i < LP5523_PROGRAM_LENGTH)) { | ||
543 | /* separate sscanfs because length is working only for %s */ | ||
544 | ret = sscanf(buf + offset, "%2s%n ", c, &nrchars); | ||
545 | ret = sscanf(c, "%2x", &cmd); | ||
546 | if (ret != 1) | ||
547 | goto fail; | ||
548 | pattern[i] = (u8)cmd; | ||
549 | |||
550 | offset += nrchars; | ||
551 | i++; | ||
552 | } | ||
553 | |||
554 | /* Each instruction is 16bit long. Check that length is even */ | ||
555 | if (i % 2) | ||
556 | goto fail; | ||
557 | |||
558 | mutex_lock(&chip->lock); | ||
559 | |||
560 | ret = lp5523_load_program(engine, pattern); | ||
561 | mutex_unlock(&chip->lock); | ||
562 | |||
563 | if (ret) { | ||
564 | dev_err(&client->dev, "failed loading pattern\n"); | ||
565 | return ret; | ||
566 | } | ||
567 | |||
568 | return len; | ||
569 | fail: | ||
570 | dev_err(&client->dev, "wrong pattern format\n"); | ||
571 | return -EINVAL; | ||
572 | } | ||
573 | |||
574 | static ssize_t store_engine_load(struct device *dev, | ||
575 | struct device_attribute *attr, | ||
576 | const char *buf, size_t len, int nr) | ||
577 | { | ||
578 | struct i2c_client *client = to_i2c_client(dev); | ||
579 | struct lp5523_chip *chip = i2c_get_clientdata(client); | ||
580 | return lp5523_do_store_load(&chip->engines[nr - 1], buf, len); | ||
581 | } | ||
582 | |||
583 | #define store_load(nr) \ | ||
584 | static ssize_t store_engine##nr##_load(struct device *dev, \ | ||
585 | struct device_attribute *attr, \ | ||
586 | const char *buf, size_t len) \ | ||
587 | { \ | ||
588 | return store_engine_load(dev, attr, buf, len, nr); \ | ||
589 | } | ||
590 | store_load(1) | ||
591 | store_load(2) | ||
592 | store_load(3) | ||
593 | |||
594 | static ssize_t show_engine_mode(struct device *dev, | ||
595 | struct device_attribute *attr, | ||
596 | char *buf, int nr) | ||
597 | { | ||
598 | struct i2c_client *client = to_i2c_client(dev); | ||
599 | struct lp5523_chip *chip = i2c_get_clientdata(client); | ||
600 | switch (chip->engines[nr - 1].mode) { | ||
601 | case LP5523_CMD_RUN: | ||
602 | return sprintf(buf, "run\n"); | ||
603 | case LP5523_CMD_LOAD: | ||
604 | return sprintf(buf, "load\n"); | ||
605 | case LP5523_CMD_DISABLED: | ||
606 | return sprintf(buf, "disabled\n"); | ||
607 | default: | ||
608 | return sprintf(buf, "disabled\n"); | ||
609 | } | ||
610 | } | ||
611 | |||
612 | #define show_mode(nr) \ | ||
613 | static ssize_t show_engine##nr##_mode(struct device *dev, \ | ||
614 | struct device_attribute *attr, \ | ||
615 | char *buf) \ | ||
616 | { \ | ||
617 | return show_engine_mode(dev, attr, buf, nr); \ | ||
618 | } | ||
619 | show_mode(1) | ||
620 | show_mode(2) | ||
621 | show_mode(3) | ||
622 | |||
623 | static ssize_t store_engine_mode(struct device *dev, | ||
624 | struct device_attribute *attr, | ||
625 | const char *buf, size_t len, int nr) | ||
626 | { | ||
627 | struct i2c_client *client = to_i2c_client(dev); | ||
628 | struct lp5523_chip *chip = i2c_get_clientdata(client); | ||
629 | struct lp5523_engine *engine = &chip->engines[nr - 1]; | ||
630 | mutex_lock(&chip->lock); | ||
631 | |||
632 | if (!strncmp(buf, "run", 3)) | ||
633 | lp5523_set_mode(engine, LP5523_CMD_RUN); | ||
634 | else if (!strncmp(buf, "load", 4)) | ||
635 | lp5523_set_mode(engine, LP5523_CMD_LOAD); | ||
636 | else if (!strncmp(buf, "disabled", 8)) | ||
637 | lp5523_set_mode(engine, LP5523_CMD_DISABLED); | ||
638 | |||
639 | mutex_unlock(&chip->lock); | ||
640 | return len; | ||
641 | } | ||
642 | |||
643 | #define store_mode(nr) \ | ||
644 | static ssize_t store_engine##nr##_mode(struct device *dev, \ | ||
645 | struct device_attribute *attr, \ | ||
646 | const char *buf, size_t len) \ | ||
647 | { \ | ||
648 | return store_engine_mode(dev, attr, buf, len, nr); \ | ||
649 | } | ||
650 | store_mode(1) | ||
651 | store_mode(2) | ||
652 | store_mode(3) | ||
653 | |||
654 | static ssize_t show_max_current(struct device *dev, | ||
655 | struct device_attribute *attr, | ||
656 | char *buf) | ||
657 | { | ||
658 | struct led_classdev *led_cdev = dev_get_drvdata(dev); | ||
659 | struct lp5523_led *led = cdev_to_led(led_cdev); | ||
660 | |||
661 | return sprintf(buf, "%d\n", led->max_current); | ||
662 | } | ||
663 | |||
664 | static ssize_t show_current(struct device *dev, | ||
665 | struct device_attribute *attr, | ||
666 | char *buf) | ||
667 | { | ||
668 | struct led_classdev *led_cdev = dev_get_drvdata(dev); | ||
669 | struct lp5523_led *led = cdev_to_led(led_cdev); | ||
670 | |||
671 | return sprintf(buf, "%d\n", led->led_current); | ||
672 | } | ||
673 | |||
674 | static ssize_t store_current(struct device *dev, | ||
675 | struct device_attribute *attr, | ||
676 | const char *buf, size_t len) | ||
677 | { | ||
678 | struct led_classdev *led_cdev = dev_get_drvdata(dev); | ||
679 | struct lp5523_led *led = cdev_to_led(led_cdev); | ||
680 | struct lp5523_chip *chip = led_to_lp5523(led); | ||
681 | ssize_t ret; | ||
682 | unsigned long curr; | ||
683 | |||
684 | if (strict_strtoul(buf, 0, &curr)) | ||
685 | return -EINVAL; | ||
686 | |||
687 | if (curr > led->max_current) | ||
688 | return -EINVAL; | ||
689 | |||
690 | mutex_lock(&chip->lock); | ||
691 | ret = lp5523_write(chip->client, | ||
692 | LP5523_REG_LED_CURRENT_BASE + led->chan_nr, | ||
693 | (u8)curr); | ||
694 | mutex_unlock(&chip->lock); | ||
695 | |||
696 | if (ret < 0) | ||
697 | return ret; | ||
698 | |||
699 | led->led_current = (u8)curr; | ||
700 | |||
701 | return len; | ||
702 | } | ||
703 | |||
704 | /* led class device attributes */ | ||
705 | static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current); | ||
706 | static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL); | ||
707 | |||
708 | static struct attribute *lp5523_led_attributes[] = { | ||
709 | &dev_attr_led_current.attr, | ||
710 | &dev_attr_max_current.attr, | ||
711 | NULL, | ||
712 | }; | ||
713 | |||
714 | static struct attribute_group lp5523_led_attribute_group = { | ||
715 | .attrs = lp5523_led_attributes | ||
716 | }; | ||
717 | |||
718 | /* device attributes */ | ||
719 | static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUGO, | ||
720 | show_engine1_mode, store_engine1_mode); | ||
721 | static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUGO, | ||
722 | show_engine2_mode, store_engine2_mode); | ||
723 | static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUGO, | ||
724 | show_engine3_mode, store_engine3_mode); | ||
725 | static DEVICE_ATTR(engine1_leds, S_IRUGO | S_IWUGO, | ||
726 | show_engine1_leds, store_engine1_leds); | ||
727 | static DEVICE_ATTR(engine2_leds, S_IRUGO | S_IWUGO, | ||
728 | show_engine2_leds, store_engine2_leds); | ||
729 | static DEVICE_ATTR(engine3_leds, S_IRUGO | S_IWUGO, | ||
730 | show_engine3_leds, store_engine3_leds); | ||
731 | static DEVICE_ATTR(engine1_load, S_IWUGO, NULL, store_engine1_load); | ||
732 | static DEVICE_ATTR(engine2_load, S_IWUGO, NULL, store_engine2_load); | ||
733 | static DEVICE_ATTR(engine3_load, S_IWUGO, NULL, store_engine3_load); | ||
734 | static DEVICE_ATTR(selftest, S_IRUGO, lp5523_selftest, NULL); | ||
735 | |||
736 | static struct attribute *lp5523_attributes[] = { | ||
737 | &dev_attr_engine1_mode.attr, | ||
738 | &dev_attr_engine2_mode.attr, | ||
739 | &dev_attr_engine3_mode.attr, | ||
740 | &dev_attr_selftest.attr, | ||
741 | NULL | ||
742 | }; | ||
743 | |||
744 | static struct attribute *lp5523_engine1_attributes[] = { | ||
745 | &dev_attr_engine1_load.attr, | ||
746 | &dev_attr_engine1_leds.attr, | ||
747 | NULL | ||
748 | }; | ||
749 | |||
750 | static struct attribute *lp5523_engine2_attributes[] = { | ||
751 | &dev_attr_engine2_load.attr, | ||
752 | &dev_attr_engine2_leds.attr, | ||
753 | NULL | ||
754 | }; | ||
755 | |||
756 | static struct attribute *lp5523_engine3_attributes[] = { | ||
757 | &dev_attr_engine3_load.attr, | ||
758 | &dev_attr_engine3_leds.attr, | ||
759 | NULL | ||
760 | }; | ||
761 | |||
762 | static const struct attribute_group lp5523_group = { | ||
763 | .attrs = lp5523_attributes, | ||
764 | }; | ||
765 | |||
766 | static const struct attribute_group lp5523_engine_group[] = { | ||
767 | {.attrs = lp5523_engine1_attributes }, | ||
768 | {.attrs = lp5523_engine2_attributes }, | ||
769 | {.attrs = lp5523_engine3_attributes }, | ||
770 | }; | ||
771 | |||
772 | static int lp5523_register_sysfs(struct i2c_client *client) | ||
773 | { | ||
774 | struct device *dev = &client->dev; | ||
775 | int ret; | ||
776 | |||
777 | ret = sysfs_create_group(&dev->kobj, &lp5523_group); | ||
778 | if (ret < 0) | ||
779 | return ret; | ||
780 | |||
781 | return 0; | ||
782 | } | ||
783 | |||
784 | static void lp5523_unregister_sysfs(struct i2c_client *client) | ||
785 | { | ||
786 | struct lp5523_chip *chip = i2c_get_clientdata(client); | ||
787 | struct device *dev = &client->dev; | ||
788 | int i; | ||
789 | |||
790 | sysfs_remove_group(&dev->kobj, &lp5523_group); | ||
791 | |||
792 | for (i = 0; i < ARRAY_SIZE(chip->engines); i++) | ||
793 | if (chip->engines[i].mode == LP5523_CMD_LOAD) | ||
794 | sysfs_remove_group(&dev->kobj, &lp5523_engine_group[i]); | ||
795 | |||
796 | for (i = 0; i < chip->num_leds; i++) | ||
797 | sysfs_remove_group(&chip->leds[i].cdev.dev->kobj, | ||
798 | &lp5523_led_attribute_group); | ||
799 | } | ||
800 | |||
801 | /*--------------------------------------------------------------*/ | ||
802 | /* Set chip operating mode */ | ||
803 | /*--------------------------------------------------------------*/ | ||
804 | static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode) | ||
805 | { | ||
806 | /* engine to chip */ | ||
807 | struct lp5523_chip *chip = engine_to_lp5523(engine); | ||
808 | struct i2c_client *client = chip->client; | ||
809 | struct device *dev = &client->dev; | ||
810 | int ret = 0; | ||
811 | |||
812 | /* if in that mode already do nothing, except for run */ | ||
813 | if (mode == engine->mode && mode != LP5523_CMD_RUN) | ||
814 | return 0; | ||
815 | |||
816 | if (mode == LP5523_CMD_RUN) { | ||
817 | ret = lp5523_run_program(engine); | ||
818 | } else if (mode == LP5523_CMD_LOAD) { | ||
819 | lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED); | ||
820 | lp5523_set_engine_mode(engine, LP5523_CMD_LOAD); | ||
821 | |||
822 | ret = sysfs_create_group(&dev->kobj, engine->attributes); | ||
823 | if (ret) | ||
824 | return ret; | ||
825 | } else if (mode == LP5523_CMD_DISABLED) { | ||
826 | lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED); | ||
827 | } | ||
828 | |||
829 | /* remove load attribute from sysfs if not in load mode */ | ||
830 | if (engine->mode == LP5523_CMD_LOAD && mode != LP5523_CMD_LOAD) | ||
831 | sysfs_remove_group(&dev->kobj, engine->attributes); | ||
832 | |||
833 | engine->mode = mode; | ||
834 | |||
835 | return ret; | ||
836 | } | ||
837 | |||
838 | /*--------------------------------------------------------------*/ | ||
839 | /* Probe, Attach, Remove */ | ||
840 | /*--------------------------------------------------------------*/ | ||
841 | static int __init lp5523_init_engine(struct lp5523_engine *engine, int id) | ||
842 | { | ||
843 | if (id < 1 || id > LP5523_ENGINES) | ||
844 | return -1; | ||
845 | engine->id = id; | ||
846 | engine->engine_mask = LP5523_ENG_MASK_BASE >> SHIFT_MASK(id); | ||
847 | engine->prog_page = id - 1; | ||
848 | engine->mux_page = id + 2; | ||
849 | engine->attributes = &lp5523_engine_group[id - 1]; | ||
850 | |||
851 | return 0; | ||
852 | } | ||
853 | |||
854 | static int __init lp5523_init_led(struct lp5523_led *led, struct device *dev, | ||
855 | int chan, struct lp5523_platform_data *pdata) | ||
856 | { | ||
857 | char name[32]; | ||
858 | int res; | ||
859 | |||
860 | if (chan >= LP5523_LEDS) | ||
861 | return -EINVAL; | ||
862 | |||
863 | if (pdata->led_config[chan].led_current) { | ||
864 | led->led_current = pdata->led_config[chan].led_current; | ||
865 | led->max_current = pdata->led_config[chan].max_current; | ||
866 | led->chan_nr = pdata->led_config[chan].chan_nr; | ||
867 | |||
868 | if (led->chan_nr >= LP5523_LEDS) { | ||
869 | dev_err(dev, "Use channel numbers between 0 and %d\n", | ||
870 | LP5523_LEDS - 1); | ||
871 | return -EINVAL; | ||
872 | } | ||
873 | |||
874 | snprintf(name, 32, "lp5523:channel%d", chan); | ||
875 | |||
876 | led->cdev.name = name; | ||
877 | led->cdev.brightness_set = lp5523_set_brightness; | ||
878 | res = led_classdev_register(dev, &led->cdev); | ||
879 | if (res < 0) { | ||
880 | dev_err(dev, "couldn't register led on channel %d\n", | ||
881 | chan); | ||
882 | return res; | ||
883 | } | ||
884 | res = sysfs_create_group(&led->cdev.dev->kobj, | ||
885 | &lp5523_led_attribute_group); | ||
886 | if (res < 0) { | ||
887 | dev_err(dev, "couldn't register current attribute\n"); | ||
888 | led_classdev_unregister(&led->cdev); | ||
889 | return res; | ||
890 | } | ||
891 | } else { | ||
892 | led->led_current = 0; | ||
893 | } | ||
894 | return 0; | ||
895 | } | ||
896 | |||
897 | static struct i2c_driver lp5523_driver; | ||
898 | |||
899 | static int lp5523_probe(struct i2c_client *client, | ||
900 | const struct i2c_device_id *id) | ||
901 | { | ||
902 | struct lp5523_chip *chip; | ||
903 | struct lp5523_platform_data *pdata; | ||
904 | int ret, i, led; | ||
905 | |||
906 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | ||
907 | if (!chip) | ||
908 | return -ENOMEM; | ||
909 | |||
910 | i2c_set_clientdata(client, chip); | ||
911 | chip->client = client; | ||
912 | |||
913 | pdata = client->dev.platform_data; | ||
914 | |||
915 | if (!pdata) { | ||
916 | dev_err(&client->dev, "no platform data\n"); | ||
917 | ret = -EINVAL; | ||
918 | goto fail1; | ||
919 | } | ||
920 | |||
921 | mutex_init(&chip->lock); | ||
922 | |||
923 | chip->pdata = pdata; | ||
924 | |||
925 | if (pdata->setup_resources) { | ||
926 | ret = pdata->setup_resources(); | ||
927 | if (ret < 0) | ||
928 | goto fail1; | ||
929 | } | ||
930 | |||
931 | if (pdata->enable) { | ||
932 | pdata->enable(0); | ||
933 | usleep_range(1000, 10000); | ||
934 | pdata->enable(1); | ||
935 | usleep_range(1000, 10000); /* Spec says min 500us */ | ||
936 | } | ||
937 | |||
938 | ret = lp5523_detect(client); | ||
939 | if (ret) | ||
940 | goto fail2; | ||
941 | |||
942 | dev_info(&client->dev, "LP5523 Programmable led chip found\n"); | ||
943 | |||
944 | /* Initialize engines */ | ||
945 | for (i = 0; i < ARRAY_SIZE(chip->engines); i++) { | ||
946 | ret = lp5523_init_engine(&chip->engines[i], i + 1); | ||
947 | if (ret) { | ||
948 | dev_err(&client->dev, "error initializing engine\n"); | ||
949 | goto fail2; | ||
950 | } | ||
951 | } | ||
952 | ret = lp5523_configure(client); | ||
953 | if (ret < 0) { | ||
954 | dev_err(&client->dev, "error configuring chip\n"); | ||
955 | goto fail2; | ||
956 | } | ||
957 | |||
958 | /* Initialize leds */ | ||
959 | chip->num_channels = pdata->num_channels; | ||
960 | chip->num_leds = 0; | ||
961 | led = 0; | ||
962 | for (i = 0; i < pdata->num_channels; i++) { | ||
963 | /* Do not initialize channels that are not connected */ | ||
964 | if (pdata->led_config[i].led_current == 0) | ||
965 | continue; | ||
966 | |||
967 | ret = lp5523_init_led(&chip->leds[led], &client->dev, i, pdata); | ||
968 | if (ret) { | ||
969 | dev_err(&client->dev, "error initializing leds\n"); | ||
970 | goto fail3; | ||
971 | } | ||
972 | chip->num_leds++; | ||
973 | |||
974 | chip->leds[led].id = led; | ||
975 | /* Set LED current */ | ||
976 | lp5523_write(client, | ||
977 | LP5523_REG_LED_CURRENT_BASE + chip->leds[led].chan_nr, | ||
978 | chip->leds[led].led_current); | ||
979 | |||
980 | INIT_WORK(&(chip->leds[led].brightness_work), | ||
981 | lp5523_led_brightness_work); | ||
982 | |||
983 | led++; | ||
984 | } | ||
985 | |||
986 | ret = lp5523_register_sysfs(client); | ||
987 | if (ret) { | ||
988 | dev_err(&client->dev, "registering sysfs failed\n"); | ||
989 | goto fail3; | ||
990 | } | ||
991 | return ret; | ||
992 | fail3: | ||
993 | for (i = 0; i < chip->num_leds; i++) { | ||
994 | led_classdev_unregister(&chip->leds[i].cdev); | ||
995 | cancel_work_sync(&chip->leds[i].brightness_work); | ||
996 | } | ||
997 | fail2: | ||
998 | if (pdata->enable) | ||
999 | pdata->enable(0); | ||
1000 | if (pdata->release_resources) | ||
1001 | pdata->release_resources(); | ||
1002 | fail1: | ||
1003 | kfree(chip); | ||
1004 | return ret; | ||
1005 | } | ||
1006 | |||
1007 | static int lp5523_remove(struct i2c_client *client) | ||
1008 | { | ||
1009 | struct lp5523_chip *chip = i2c_get_clientdata(client); | ||
1010 | int i; | ||
1011 | |||
1012 | lp5523_unregister_sysfs(client); | ||
1013 | |||
1014 | for (i = 0; i < chip->num_leds; i++) { | ||
1015 | led_classdev_unregister(&chip->leds[i].cdev); | ||
1016 | cancel_work_sync(&chip->leds[i].brightness_work); | ||
1017 | } | ||
1018 | |||
1019 | if (chip->pdata->enable) | ||
1020 | chip->pdata->enable(0); | ||
1021 | if (chip->pdata->release_resources) | ||
1022 | chip->pdata->release_resources(); | ||
1023 | kfree(chip); | ||
1024 | return 0; | ||
1025 | } | ||
1026 | |||
1027 | static const struct i2c_device_id lp5523_id[] = { | ||
1028 | { "lp5523", 0 }, | ||
1029 | { } | ||
1030 | }; | ||
1031 | |||
1032 | MODULE_DEVICE_TABLE(i2c, lp5523_id); | ||
1033 | |||
1034 | static struct i2c_driver lp5523_driver = { | ||
1035 | .driver = { | ||
1036 | .name = "lp5523", | ||
1037 | }, | ||
1038 | .probe = lp5523_probe, | ||
1039 | .remove = lp5523_remove, | ||
1040 | .id_table = lp5523_id, | ||
1041 | }; | ||
1042 | |||
1043 | static int __init lp5523_init(void) | ||
1044 | { | ||
1045 | int ret; | ||
1046 | |||
1047 | ret = i2c_add_driver(&lp5523_driver); | ||
1048 | |||
1049 | if (ret < 0) | ||
1050 | printk(KERN_ALERT "Adding lp5523 driver failed\n"); | ||
1051 | |||
1052 | return ret; | ||
1053 | } | ||
1054 | |||
1055 | static void __exit lp5523_exit(void) | ||
1056 | { | ||
1057 | i2c_del_driver(&lp5523_driver); | ||
1058 | } | ||
1059 | |||
1060 | module_init(lp5523_init); | ||
1061 | module_exit(lp5523_exit); | ||
1062 | |||
1063 | MODULE_AUTHOR("Mathias Nyman <mathias.nyman@nokia.com>"); | ||
1064 | MODULE_DESCRIPTION("LP5523 LED engine"); | ||
1065 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c index 82b77bd482ff..b09bcbeade9c 100644 --- a/drivers/leds/ledtrig-timer.c +++ b/drivers/leds/ledtrig-timer.c | |||
@@ -12,73 +12,25 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/jiffies.h> | ||
16 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
17 | #include <linux/init.h> | 16 | #include <linux/init.h> |
18 | #include <linux/list.h> | ||
19 | #include <linux/spinlock.h> | ||
20 | #include <linux/device.h> | 17 | #include <linux/device.h> |
21 | #include <linux/sysdev.h> | ||
22 | #include <linux/timer.h> | ||
23 | #include <linux/ctype.h> | 18 | #include <linux/ctype.h> |
24 | #include <linux/leds.h> | 19 | #include <linux/leds.h> |
25 | #include <linux/slab.h> | ||
26 | #include "leds.h" | 20 | #include "leds.h" |
27 | 21 | ||
28 | struct timer_trig_data { | ||
29 | int brightness_on; /* LED brightness during "on" period. | ||
30 | * (LED_OFF < brightness_on <= LED_FULL) | ||
31 | */ | ||
32 | unsigned long delay_on; /* milliseconds on */ | ||
33 | unsigned long delay_off; /* milliseconds off */ | ||
34 | struct timer_list timer; | ||
35 | }; | ||
36 | |||
37 | static void led_timer_function(unsigned long data) | ||
38 | { | ||
39 | struct led_classdev *led_cdev = (struct led_classdev *) data; | ||
40 | struct timer_trig_data *timer_data = led_cdev->trigger_data; | ||
41 | unsigned long brightness; | ||
42 | unsigned long delay; | ||
43 | |||
44 | if (!timer_data->delay_on || !timer_data->delay_off) { | ||
45 | led_set_brightness(led_cdev, LED_OFF); | ||
46 | return; | ||
47 | } | ||
48 | |||
49 | brightness = led_get_brightness(led_cdev); | ||
50 | if (!brightness) { | ||
51 | /* Time to switch the LED on. */ | ||
52 | brightness = timer_data->brightness_on; | ||
53 | delay = timer_data->delay_on; | ||
54 | } else { | ||
55 | /* Store the current brightness value to be able | ||
56 | * to restore it when the delay_off period is over. | ||
57 | */ | ||
58 | timer_data->brightness_on = brightness; | ||
59 | brightness = LED_OFF; | ||
60 | delay = timer_data->delay_off; | ||
61 | } | ||
62 | |||
63 | led_set_brightness(led_cdev, brightness); | ||
64 | |||
65 | mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay)); | ||
66 | } | ||
67 | |||
68 | static ssize_t led_delay_on_show(struct device *dev, | 22 | static ssize_t led_delay_on_show(struct device *dev, |
69 | struct device_attribute *attr, char *buf) | 23 | struct device_attribute *attr, char *buf) |
70 | { | 24 | { |
71 | struct led_classdev *led_cdev = dev_get_drvdata(dev); | 25 | struct led_classdev *led_cdev = dev_get_drvdata(dev); |
72 | struct timer_trig_data *timer_data = led_cdev->trigger_data; | ||
73 | 26 | ||
74 | return sprintf(buf, "%lu\n", timer_data->delay_on); | 27 | return sprintf(buf, "%lu\n", led_cdev->blink_delay_on); |
75 | } | 28 | } |
76 | 29 | ||
77 | static ssize_t led_delay_on_store(struct device *dev, | 30 | static ssize_t led_delay_on_store(struct device *dev, |
78 | struct device_attribute *attr, const char *buf, size_t size) | 31 | struct device_attribute *attr, const char *buf, size_t size) |
79 | { | 32 | { |
80 | struct led_classdev *led_cdev = dev_get_drvdata(dev); | 33 | struct led_classdev *led_cdev = dev_get_drvdata(dev); |
81 | struct timer_trig_data *timer_data = led_cdev->trigger_data; | ||
82 | int ret = -EINVAL; | 34 | int ret = -EINVAL; |
83 | char *after; | 35 | char *after; |
84 | unsigned long state = simple_strtoul(buf, &after, 10); | 36 | unsigned long state = simple_strtoul(buf, &after, 10); |
@@ -88,21 +40,7 @@ static ssize_t led_delay_on_store(struct device *dev, | |||
88 | count++; | 40 | count++; |
89 | 41 | ||
90 | if (count == size) { | 42 | if (count == size) { |
91 | if (timer_data->delay_on != state) { | 43 | led_blink_set(led_cdev, &state, &led_cdev->blink_delay_off); |
92 | /* the new value differs from the previous */ | ||
93 | timer_data->delay_on = state; | ||
94 | |||
95 | /* deactivate previous settings */ | ||
96 | del_timer_sync(&timer_data->timer); | ||
97 | |||
98 | /* try to activate hardware acceleration, if any */ | ||
99 | if (!led_cdev->blink_set || | ||
100 | led_cdev->blink_set(led_cdev, | ||
101 | &timer_data->delay_on, &timer_data->delay_off)) { | ||
102 | /* no hardware acceleration, blink via timer */ | ||
103 | mod_timer(&timer_data->timer, jiffies + 1); | ||
104 | } | ||
105 | } | ||
106 | ret = count; | 44 | ret = count; |
107 | } | 45 | } |
108 | 46 | ||
@@ -113,16 +51,14 @@ static ssize_t led_delay_off_show(struct device *dev, | |||
113 | struct device_attribute *attr, char *buf) | 51 | struct device_attribute *attr, char *buf) |
114 | { | 52 | { |
115 | struct led_classdev *led_cdev = dev_get_drvdata(dev); | 53 | struct led_classdev *led_cdev = dev_get_drvdata(dev); |
116 | struct timer_trig_data *timer_data = led_cdev->trigger_data; | ||
117 | 54 | ||
118 | return sprintf(buf, "%lu\n", timer_data->delay_off); | 55 | return sprintf(buf, "%lu\n", led_cdev->blink_delay_off); |
119 | } | 56 | } |
120 | 57 | ||
121 | static ssize_t led_delay_off_store(struct device *dev, | 58 | static ssize_t led_delay_off_store(struct device *dev, |
122 | struct device_attribute *attr, const char *buf, size_t size) | 59 | struct device_attribute *attr, const char *buf, size_t size) |
123 | { | 60 | { |
124 | struct led_classdev *led_cdev = dev_get_drvdata(dev); | 61 | struct led_classdev *led_cdev = dev_get_drvdata(dev); |
125 | struct timer_trig_data *timer_data = led_cdev->trigger_data; | ||
126 | int ret = -EINVAL; | 62 | int ret = -EINVAL; |
127 | char *after; | 63 | char *after; |
128 | unsigned long state = simple_strtoul(buf, &after, 10); | 64 | unsigned long state = simple_strtoul(buf, &after, 10); |
@@ -132,21 +68,7 @@ static ssize_t led_delay_off_store(struct device *dev, | |||
132 | count++; | 68 | count++; |
133 | 69 | ||
134 | if (count == size) { | 70 | if (count == size) { |
135 | if (timer_data->delay_off != state) { | 71 | led_blink_set(led_cdev, &led_cdev->blink_delay_on, &state); |
136 | /* the new value differs from the previous */ | ||
137 | timer_data->delay_off = state; | ||
138 | |||
139 | /* deactivate previous settings */ | ||
140 | del_timer_sync(&timer_data->timer); | ||
141 | |||
142 | /* try to activate hardware acceleration, if any */ | ||
143 | if (!led_cdev->blink_set || | ||
144 | led_cdev->blink_set(led_cdev, | ||
145 | &timer_data->delay_on, &timer_data->delay_off)) { | ||
146 | /* no hardware acceleration, blink via timer */ | ||
147 | mod_timer(&timer_data->timer, jiffies + 1); | ||
148 | } | ||
149 | } | ||
150 | ret = count; | 72 | ret = count; |
151 | } | 73 | } |
152 | 74 | ||
@@ -158,60 +80,34 @@ static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store); | |||
158 | 80 | ||
159 | static void timer_trig_activate(struct led_classdev *led_cdev) | 81 | static void timer_trig_activate(struct led_classdev *led_cdev) |
160 | { | 82 | { |
161 | struct timer_trig_data *timer_data; | ||
162 | int rc; | 83 | int rc; |
163 | 84 | ||
164 | timer_data = kzalloc(sizeof(struct timer_trig_data), GFP_KERNEL); | 85 | led_cdev->trigger_data = NULL; |
165 | if (!timer_data) | ||
166 | return; | ||
167 | |||
168 | timer_data->brightness_on = led_get_brightness(led_cdev); | ||
169 | if (timer_data->brightness_on == LED_OFF) | ||
170 | timer_data->brightness_on = led_cdev->max_brightness; | ||
171 | led_cdev->trigger_data = timer_data; | ||
172 | |||
173 | init_timer(&timer_data->timer); | ||
174 | timer_data->timer.function = led_timer_function; | ||
175 | timer_data->timer.data = (unsigned long) led_cdev; | ||
176 | 86 | ||
177 | rc = device_create_file(led_cdev->dev, &dev_attr_delay_on); | 87 | rc = device_create_file(led_cdev->dev, &dev_attr_delay_on); |
178 | if (rc) | 88 | if (rc) |
179 | goto err_out; | 89 | return; |
180 | rc = device_create_file(led_cdev->dev, &dev_attr_delay_off); | 90 | rc = device_create_file(led_cdev->dev, &dev_attr_delay_off); |
181 | if (rc) | 91 | if (rc) |
182 | goto err_out_delayon; | 92 | goto err_out_delayon; |
183 | 93 | ||
184 | /* If there is hardware support for blinking, start one | 94 | led_cdev->trigger_data = (void *)1; |
185 | * user friendly blink rate chosen by the driver. | ||
186 | */ | ||
187 | if (led_cdev->blink_set) | ||
188 | led_cdev->blink_set(led_cdev, | ||
189 | &timer_data->delay_on, &timer_data->delay_off); | ||
190 | 95 | ||
191 | return; | 96 | return; |
192 | 97 | ||
193 | err_out_delayon: | 98 | err_out_delayon: |
194 | device_remove_file(led_cdev->dev, &dev_attr_delay_on); | 99 | device_remove_file(led_cdev->dev, &dev_attr_delay_on); |
195 | err_out: | ||
196 | led_cdev->trigger_data = NULL; | ||
197 | kfree(timer_data); | ||
198 | } | 100 | } |
199 | 101 | ||
200 | static void timer_trig_deactivate(struct led_classdev *led_cdev) | 102 | static void timer_trig_deactivate(struct led_classdev *led_cdev) |
201 | { | 103 | { |
202 | struct timer_trig_data *timer_data = led_cdev->trigger_data; | 104 | if (led_cdev->trigger_data) { |
203 | unsigned long on = 0, off = 0; | ||
204 | |||
205 | if (timer_data) { | ||
206 | device_remove_file(led_cdev->dev, &dev_attr_delay_on); | 105 | device_remove_file(led_cdev->dev, &dev_attr_delay_on); |
207 | device_remove_file(led_cdev->dev, &dev_attr_delay_off); | 106 | device_remove_file(led_cdev->dev, &dev_attr_delay_off); |
208 | del_timer_sync(&timer_data->timer); | ||
209 | kfree(timer_data); | ||
210 | } | 107 | } |
211 | 108 | ||
212 | /* If there is hardware support for blinking, stop it */ | 109 | /* Stop blinking */ |
213 | if (led_cdev->blink_set) | 110 | led_brightness_set(led_cdev, LED_OFF); |
214 | led_cdev->blink_set(led_cdev, &on, &off); | ||
215 | } | 111 | } |
216 | 112 | ||
217 | static struct led_trigger timer_led_trigger = { | 113 | static struct led_trigger timer_led_trigger = { |
diff --git a/drivers/macintosh/adb-iop.c b/drivers/macintosh/adb-iop.c index 444696625171..f5f4da3d0b67 100644 --- a/drivers/macintosh/adb-iop.c +++ b/drivers/macintosh/adb-iop.c | |||
@@ -80,7 +80,7 @@ static void adb_iop_end_req(struct adb_request *req, int state) | |||
80 | static void adb_iop_complete(struct iop_msg *msg) | 80 | static void adb_iop_complete(struct iop_msg *msg) |
81 | { | 81 | { |
82 | struct adb_request *req; | 82 | struct adb_request *req; |
83 | uint flags; | 83 | unsigned long flags; |
84 | 84 | ||
85 | local_irq_save(flags); | 85 | local_irq_save(flags); |
86 | 86 | ||
@@ -103,7 +103,7 @@ static void adb_iop_listen(struct iop_msg *msg) | |||
103 | { | 103 | { |
104 | struct adb_iopmsg *amsg = (struct adb_iopmsg *) msg->message; | 104 | struct adb_iopmsg *amsg = (struct adb_iopmsg *) msg->message; |
105 | struct adb_request *req; | 105 | struct adb_request *req; |
106 | uint flags; | 106 | unsigned long flags; |
107 | #ifdef DEBUG_ADB_IOP | 107 | #ifdef DEBUG_ADB_IOP |
108 | int i; | 108 | int i; |
109 | #endif | 109 | #endif |
diff --git a/drivers/misc/apds9802als.c b/drivers/misc/apds9802als.c index f9b91ba8900c..0ed09358027e 100644 --- a/drivers/misc/apds9802als.c +++ b/drivers/misc/apds9802als.c | |||
@@ -123,7 +123,7 @@ static ssize_t als_sensing_range_store(struct device *dev, | |||
123 | { | 123 | { |
124 | struct i2c_client *client = to_i2c_client(dev); | 124 | struct i2c_client *client = to_i2c_client(dev); |
125 | struct als_data *data = i2c_get_clientdata(client); | 125 | struct als_data *data = i2c_get_clientdata(client); |
126 | unsigned int ret_val; | 126 | int ret_val; |
127 | unsigned long val; | 127 | unsigned long val; |
128 | 128 | ||
129 | if (strict_strtoul(buf, 10, &val)) | 129 | if (strict_strtoul(buf, 10, &val)) |
diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c index cee632e645e1..d79a972f2c79 100644 --- a/drivers/misc/bh1770glc.c +++ b/drivers/misc/bh1770glc.c | |||
@@ -649,7 +649,7 @@ static ssize_t bh1770_power_state_store(struct device *dev, | |||
649 | { | 649 | { |
650 | struct bh1770_chip *chip = dev_get_drvdata(dev); | 650 | struct bh1770_chip *chip = dev_get_drvdata(dev); |
651 | unsigned long value; | 651 | unsigned long value; |
652 | size_t ret; | 652 | ssize_t ret; |
653 | 653 | ||
654 | if (strict_strtoul(buf, 0, &value)) | 654 | if (strict_strtoul(buf, 0, &value)) |
655 | return -EINVAL; | 655 | return -EINVAL; |
@@ -659,8 +659,12 @@ static ssize_t bh1770_power_state_store(struct device *dev, | |||
659 | pm_runtime_get_sync(dev); | 659 | pm_runtime_get_sync(dev); |
660 | 660 | ||
661 | ret = bh1770_lux_rate(chip, chip->lux_rate_index); | 661 | ret = bh1770_lux_rate(chip, chip->lux_rate_index); |
662 | ret |= bh1770_lux_interrupt_control(chip, BH1770_ENABLE); | 662 | if (ret < 0) { |
663 | pm_runtime_put(dev); | ||
664 | goto leave; | ||
665 | } | ||
663 | 666 | ||
667 | ret = bh1770_lux_interrupt_control(chip, BH1770_ENABLE); | ||
664 | if (ret < 0) { | 668 | if (ret < 0) { |
665 | pm_runtime_put(dev); | 669 | pm_runtime_put(dev); |
666 | goto leave; | 670 | goto leave; |
diff --git a/drivers/misc/isl29020.c b/drivers/misc/isl29020.c index 34fe835921c4..ca47e6285075 100644 --- a/drivers/misc/isl29020.c +++ b/drivers/misc/isl29020.c | |||
@@ -87,7 +87,7 @@ static ssize_t als_sensing_range_store(struct device *dev, | |||
87 | struct device_attribute *attr, const char *buf, size_t count) | 87 | struct device_attribute *attr, const char *buf, size_t count) |
88 | { | 88 | { |
89 | struct i2c_client *client = to_i2c_client(dev); | 89 | struct i2c_client *client = to_i2c_client(dev); |
90 | unsigned int ret_val; | 90 | int ret_val; |
91 | unsigned long val; | 91 | unsigned long val; |
92 | 92 | ||
93 | if (strict_strtoul(buf, 10, &val)) | 93 | if (strict_strtoul(buf, 10, &val)) |
@@ -106,6 +106,8 @@ static ssize_t als_sensing_range_store(struct device *dev, | |||
106 | val = 4; | 106 | val = 4; |
107 | 107 | ||
108 | ret_val = i2c_smbus_read_byte_data(client, 0x00); | 108 | ret_val = i2c_smbus_read_byte_data(client, 0x00); |
109 | if (ret_val < 0) | ||
110 | return ret_val; | ||
109 | 111 | ||
110 | ret_val &= 0xFC; /*reset the bit before setting them */ | 112 | ret_val &= 0xFC; /*reset the bit before setting them */ |
111 | ret_val |= val - 1; | 113 | ret_val |= val - 1; |
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index eea1ef2f502b..4396d4b9bfb9 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig | |||
@@ -221,9 +221,6 @@ config RT2X00_LIB_LEDS | |||
221 | boolean | 221 | boolean |
222 | default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n) | 222 | default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n) |
223 | 223 | ||
224 | comment "rt2x00 leds support disabled due to modularized LEDS_CLASS and built-in rt2x00" | ||
225 | depends on RT2X00_LIB=y && LEDS_CLASS=m | ||
226 | |||
227 | config RT2X00_LIB_DEBUGFS | 224 | config RT2X00_LIB_DEBUGFS |
228 | bool "Ralink debugfs support" | 225 | bool "Ralink debugfs support" |
229 | depends on RT2X00_LIB && MAC80211_DEBUGFS | 226 | depends on RT2X00_LIB && MAC80211_DEBUGFS |
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index 68cf0c99138a..7b5080c45569 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c | |||
@@ -1159,11 +1159,11 @@ int __devinit rio_init_mports(void) | |||
1159 | 1159 | ||
1160 | list_for_each_entry(port, &rio_mports, node) { | 1160 | list_for_each_entry(port, &rio_mports, node) { |
1161 | if (!request_mem_region(port->iores.start, | 1161 | if (!request_mem_region(port->iores.start, |
1162 | port->iores.end - port->iores.start, | 1162 | resource_size(&port->iores), |
1163 | port->name)) { | 1163 | port->name)) { |
1164 | printk(KERN_ERR | 1164 | printk(KERN_ERR |
1165 | "RIO: Error requesting master port region 0x%016llx-0x%016llx\n", | 1165 | "RIO: Error requesting master port region 0x%016llx-0x%016llx\n", |
1166 | (u64)port->iores.start, (u64)port->iores.end - 1); | 1166 | (u64)port->iores.start, (u64)port->iores.end); |
1167 | rc = -ENOMEM; | 1167 | rc = -ENOMEM; |
1168 | goto out; | 1168 | goto out; |
1169 | } | 1169 | } |
diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 3ec24609151e..734c650a47c4 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c | |||
@@ -502,8 +502,10 @@ static ssize_t adp8860_bl_l1_daylight_max_store(struct device *dev, | |||
502 | struct device_attribute *attr, const char *buf, size_t count) | 502 | struct device_attribute *attr, const char *buf, size_t count) |
503 | { | 503 | { |
504 | struct adp8860_bl *data = dev_get_drvdata(dev); | 504 | struct adp8860_bl *data = dev_get_drvdata(dev); |
505 | int ret = strict_strtoul(buf, 10, &data->cached_daylight_max); | ||
506 | if (ret) | ||
507 | return ret; | ||
505 | 508 | ||
506 | strict_strtoul(buf, 10, &data->cached_daylight_max); | ||
507 | return adp8860_store(dev, buf, count, ADP8860_BLMX1); | 509 | return adp8860_store(dev, buf, count, ADP8860_BLMX1); |
508 | } | 510 | } |
509 | static DEVICE_ATTR(l1_daylight_max, 0664, adp8860_bl_l1_daylight_max_show, | 511 | static DEVICE_ATTR(l1_daylight_max, 0664, adp8860_bl_l1_daylight_max_show, |
@@ -614,7 +616,7 @@ static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev, | |||
614 | if (val == 0) { | 616 | if (val == 0) { |
615 | /* Enable automatic ambient light sensing */ | 617 | /* Enable automatic ambient light sensing */ |
616 | adp8860_set_bits(data->client, ADP8860_MDCR, CMP_AUTOEN); | 618 | adp8860_set_bits(data->client, ADP8860_MDCR, CMP_AUTOEN); |
617 | } else if ((val > 0) && (val < 6)) { | 619 | } else if ((val > 0) && (val <= 3)) { |
618 | /* Disable automatic ambient light sensing */ | 620 | /* Disable automatic ambient light sensing */ |
619 | adp8860_clr_bits(data->client, ADP8860_MDCR, CMP_AUTOEN); | 621 | adp8860_clr_bits(data->client, ADP8860_MDCR, CMP_AUTOEN); |
620 | 622 | ||
@@ -622,7 +624,7 @@ static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev, | |||
622 | mutex_lock(&data->lock); | 624 | mutex_lock(&data->lock); |
623 | adp8860_read(data->client, ADP8860_CFGR, ®_val); | 625 | adp8860_read(data->client, ADP8860_CFGR, ®_val); |
624 | reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT); | 626 | reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT); |
625 | reg_val |= val << CFGR_BLV_SHIFT; | 627 | reg_val |= (val - 1) << CFGR_BLV_SHIFT; |
626 | adp8860_write(data->client, ADP8860_CFGR, reg_val); | 628 | adp8860_write(data->client, ADP8860_CFGR, reg_val); |
627 | mutex_unlock(&data->lock); | 629 | mutex_unlock(&data->lock); |
628 | } | 630 | } |
diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index 9093ef0fa869..c67801e57aaf 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c | |||
@@ -78,7 +78,7 @@ static int l4f00242t03_lcd_power_set(struct lcd_device *ld, int power) | |||
78 | const u16 slpin = 0x10; | 78 | const u16 slpin = 0x10; |
79 | const u16 disoff = 0x28; | 79 | const u16 disoff = 0x28; |
80 | 80 | ||
81 | if (power) { | 81 | if (power <= FB_BLANK_NORMAL) { |
82 | if (priv->lcd_on) | 82 | if (priv->lcd_on) |
83 | return 0; | 83 | return 0; |
84 | 84 | ||
diff --git a/drivers/video/backlight/lms283gf05.c b/drivers/video/backlight/lms283gf05.c index abc43a0eb97d..5d3cf33953ac 100644 --- a/drivers/video/backlight/lms283gf05.c +++ b/drivers/video/backlight/lms283gf05.c | |||
@@ -129,7 +129,7 @@ static int lms283gf05_power_set(struct lcd_device *ld, int power) | |||
129 | struct spi_device *spi = st->spi; | 129 | struct spi_device *spi = st->spi; |
130 | struct lms283gf05_pdata *pdata = spi->dev.platform_data; | 130 | struct lms283gf05_pdata *pdata = spi->dev.platform_data; |
131 | 131 | ||
132 | if (power) { | 132 | if (power <= FB_BLANK_NORMAL) { |
133 | if (pdata) | 133 | if (pdata) |
134 | lms283gf05_reset(pdata->reset_gpio, | 134 | lms283gf05_reset(pdata->reset_gpio, |
135 | pdata->reset_inverted); | 135 | pdata->reset_inverted); |
diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c index 9fb533f6373e..1485f7345f49 100644 --- a/drivers/video/backlight/mbp_nvidia_bl.c +++ b/drivers/video/backlight/mbp_nvidia_bl.c | |||
@@ -335,6 +335,24 @@ static const struct dmi_system_id __initdata mbp_device_table[] = { | |||
335 | }, | 335 | }, |
336 | .driver_data = (void *)&nvidia_chipset_data, | 336 | .driver_data = (void *)&nvidia_chipset_data, |
337 | }, | 337 | }, |
338 | { | ||
339 | .callback = mbp_dmi_match, | ||
340 | .ident = "MacBookAir 3,1", | ||
341 | .matches = { | ||
342 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | ||
343 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,1"), | ||
344 | }, | ||
345 | .driver_data = (void *)&nvidia_chipset_data, | ||
346 | }, | ||
347 | { | ||
348 | .callback = mbp_dmi_match, | ||
349 | .ident = "MacBookAir 3,2", | ||
350 | .matches = { | ||
351 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | ||
352 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,2"), | ||
353 | }, | ||
354 | .driver_data = (void *)&nvidia_chipset_data, | ||
355 | }, | ||
338 | { } | 356 | { } |
339 | }; | 357 | }; |
340 | 358 | ||
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 550443518891..21866ec69656 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c | |||
@@ -25,6 +25,7 @@ struct pwm_bl_data { | |||
25 | struct pwm_device *pwm; | 25 | struct pwm_device *pwm; |
26 | struct device *dev; | 26 | struct device *dev; |
27 | unsigned int period; | 27 | unsigned int period; |
28 | unsigned int lth_brightness; | ||
28 | int (*notify)(struct device *, | 29 | int (*notify)(struct device *, |
29 | int brightness); | 30 | int brightness); |
30 | }; | 31 | }; |
@@ -48,7 +49,9 @@ static int pwm_backlight_update_status(struct backlight_device *bl) | |||
48 | pwm_config(pb->pwm, 0, pb->period); | 49 | pwm_config(pb->pwm, 0, pb->period); |
49 | pwm_disable(pb->pwm); | 50 | pwm_disable(pb->pwm); |
50 | } else { | 51 | } else { |
51 | pwm_config(pb->pwm, brightness * pb->period / max, pb->period); | 52 | brightness = pb->lth_brightness + |
53 | (brightness * (pb->period - pb->lth_brightness) / max); | ||
54 | pwm_config(pb->pwm, brightness, pb->period); | ||
52 | pwm_enable(pb->pwm); | 55 | pwm_enable(pb->pwm); |
53 | } | 56 | } |
54 | return 0; | 57 | return 0; |
@@ -92,6 +95,8 @@ static int pwm_backlight_probe(struct platform_device *pdev) | |||
92 | 95 | ||
93 | pb->period = data->pwm_period_ns; | 96 | pb->period = data->pwm_period_ns; |
94 | pb->notify = data->notify; | 97 | pb->notify = data->notify; |
98 | pb->lth_brightness = data->lth_brightness * | ||
99 | (data->pwm_period_ns / data->max_brightness); | ||
95 | pb->dev = &pdev->dev; | 100 | pb->dev = &pdev->dev; |
96 | 101 | ||
97 | pb->pwm = pwm_request(data->pwm_id, "backlight"); | 102 | pb->pwm = pwm_request(data->pwm_id, "backlight"); |
diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c index a3128c9cb7ad..5927db0da999 100644 --- a/drivers/video/backlight/s6e63m0.c +++ b/drivers/video/backlight/s6e63m0.c | |||
@@ -729,10 +729,10 @@ static ssize_t s6e63m0_sysfs_show_gamma_table(struct device *dev, | |||
729 | 729 | ||
730 | return strlen(buf); | 730 | return strlen(buf); |
731 | } | 731 | } |
732 | static DEVICE_ATTR(gamma_table, 0644, | 732 | static DEVICE_ATTR(gamma_table, 0444, |
733 | s6e63m0_sysfs_show_gamma_table, NULL); | 733 | s6e63m0_sysfs_show_gamma_table, NULL); |
734 | 734 | ||
735 | static int __init s6e63m0_probe(struct spi_device *spi) | 735 | static int __devinit s6e63m0_probe(struct spi_device *spi) |
736 | { | 736 | { |
737 | int ret = 0; | 737 | int ret = 0; |
738 | struct s6e63m0 *lcd = NULL; | 738 | struct s6e63m0 *lcd = NULL; |
@@ -829,6 +829,9 @@ static int __devexit s6e63m0_remove(struct spi_device *spi) | |||
829 | struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); | 829 | struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); |
830 | 830 | ||
831 | s6e63m0_power(lcd, FB_BLANK_POWERDOWN); | 831 | s6e63m0_power(lcd, FB_BLANK_POWERDOWN); |
832 | device_remove_file(&spi->dev, &dev_attr_gamma_table); | ||
833 | device_remove_file(&spi->dev, &dev_attr_gamma_mode); | ||
834 | backlight_device_unregister(lcd->bd); | ||
832 | lcd_device_unregister(lcd->ld); | 835 | lcd_device_unregister(lcd->ld); |
833 | kfree(lcd); | 836 | kfree(lcd); |
834 | 837 | ||
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index d6cfac1f0a40..a5fe68189eed 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
@@ -932,8 +932,7 @@ struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag, | |||
932 | if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) { | 932 | if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) { |
933 | *user = current_user(); | 933 | *user = current_user(); |
934 | if (user_shm_lock(size, *user)) { | 934 | if (user_shm_lock(size, *user)) { |
935 | WARN_ONCE(1, | 935 | printk_once(KERN_WARNING "Using mlock ulimits for SHM_HUGETLB is deprecated\n"); |
936 | "Using mlock ulimits for SHM_HUGETLB deprecated\n"); | ||
937 | } else { | 936 | } else { |
938 | *user = NULL; | 937 | *user = NULL; |
939 | return ERR_PTR(-EPERM); | 938 | return ERR_PTR(-EPERM); |
diff --git a/fs/locks.c b/fs/locks.c index 65765cb6afed..0e62dd35d088 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -1504,9 +1504,8 @@ static int do_fcntl_delete_lease(struct file *filp) | |||
1504 | 1504 | ||
1505 | static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) | 1505 | static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) |
1506 | { | 1506 | { |
1507 | struct file_lock *fl; | 1507 | struct file_lock *fl, *ret; |
1508 | struct fasync_struct *new; | 1508 | struct fasync_struct *new; |
1509 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
1510 | int error; | 1509 | int error; |
1511 | 1510 | ||
1512 | fl = lease_alloc(filp, arg); | 1511 | fl = lease_alloc(filp, arg); |
@@ -1518,13 +1517,16 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) | |||
1518 | locks_free_lock(fl); | 1517 | locks_free_lock(fl); |
1519 | return -ENOMEM; | 1518 | return -ENOMEM; |
1520 | } | 1519 | } |
1520 | ret = fl; | ||
1521 | lock_flocks(); | 1521 | lock_flocks(); |
1522 | error = __vfs_setlease(filp, arg, &fl); | 1522 | error = __vfs_setlease(filp, arg, &ret); |
1523 | if (error) { | 1523 | if (error) { |
1524 | unlock_flocks(); | 1524 | unlock_flocks(); |
1525 | locks_free_lock(fl); | 1525 | locks_free_lock(fl); |
1526 | goto out_free_fasync; | 1526 | goto out_free_fasync; |
1527 | } | 1527 | } |
1528 | if (ret != fl) | ||
1529 | locks_free_lock(fl); | ||
1528 | 1530 | ||
1529 | /* | 1531 | /* |
1530 | * fasync_insert_entry() returns the old entry if any. | 1532 | * fasync_insert_entry() returns the old entry if any. |
@@ -1532,17 +1534,10 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) | |||
1532 | * inserted it into the fasync list. Clear new so that | 1534 | * inserted it into the fasync list. Clear new so that |
1533 | * we don't release it here. | 1535 | * we don't release it here. |
1534 | */ | 1536 | */ |
1535 | if (!fasync_insert_entry(fd, filp, &fl->fl_fasync, new)) | 1537 | if (!fasync_insert_entry(fd, filp, &ret->fl_fasync, new)) |
1536 | new = NULL; | 1538 | new = NULL; |
1537 | 1539 | ||
1538 | if (error < 0) { | 1540 | error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); |
1539 | /* remove lease just inserted by setlease */ | ||
1540 | fl->fl_type = F_UNLCK | F_INPROGRESS; | ||
1541 | fl->fl_break_time = jiffies - 10; | ||
1542 | time_out_leases(inode); | ||
1543 | } else { | ||
1544 | error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); | ||
1545 | } | ||
1546 | unlock_flocks(); | 1541 | unlock_flocks(); |
1547 | 1542 | ||
1548 | out_free_fasync: | 1543 | out_free_fasync: |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f1e5ec6b5105..ad2bfa68d534 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -673,16 +673,17 @@ static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) | |||
673 | spin_unlock(&clp->cl_lock); | 673 | spin_unlock(&clp->cl_lock); |
674 | } | 674 | } |
675 | 675 | ||
676 | static void nfsd4_register_conn(struct nfsd4_conn *conn) | 676 | static int nfsd4_register_conn(struct nfsd4_conn *conn) |
677 | { | 677 | { |
678 | conn->cn_xpt_user.callback = nfsd4_conn_lost; | 678 | conn->cn_xpt_user.callback = nfsd4_conn_lost; |
679 | register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); | 679 | return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); |
680 | } | 680 | } |
681 | 681 | ||
682 | static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses) | 682 | static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses) |
683 | { | 683 | { |
684 | struct nfsd4_conn *conn; | 684 | struct nfsd4_conn *conn; |
685 | u32 flags = NFS4_CDFC4_FORE; | 685 | u32 flags = NFS4_CDFC4_FORE; |
686 | int ret; | ||
686 | 687 | ||
687 | if (ses->se_flags & SESSION4_BACK_CHAN) | 688 | if (ses->se_flags & SESSION4_BACK_CHAN) |
688 | flags |= NFS4_CDFC4_BACK; | 689 | flags |= NFS4_CDFC4_BACK; |
@@ -690,7 +691,10 @@ static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses) | |||
690 | if (!conn) | 691 | if (!conn) |
691 | return nfserr_jukebox; | 692 | return nfserr_jukebox; |
692 | nfsd4_hash_conn(conn, ses); | 693 | nfsd4_hash_conn(conn, ses); |
693 | nfsd4_register_conn(conn); | 694 | ret = nfsd4_register_conn(conn); |
695 | if (ret) | ||
696 | /* oops; xprt is already down: */ | ||
697 | nfsd4_conn_lost(&conn->cn_xpt_user); | ||
694 | return nfs_ok; | 698 | return nfs_ok; |
695 | } | 699 | } |
696 | 700 | ||
@@ -1644,6 +1648,7 @@ static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_sessi | |||
1644 | { | 1648 | { |
1645 | struct nfs4_client *clp = ses->se_client; | 1649 | struct nfs4_client *clp = ses->se_client; |
1646 | struct nfsd4_conn *c; | 1650 | struct nfsd4_conn *c; |
1651 | int ret; | ||
1647 | 1652 | ||
1648 | spin_lock(&clp->cl_lock); | 1653 | spin_lock(&clp->cl_lock); |
1649 | c = __nfsd4_find_conn(new->cn_xprt, ses); | 1654 | c = __nfsd4_find_conn(new->cn_xprt, ses); |
@@ -1654,7 +1659,10 @@ static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_sessi | |||
1654 | } | 1659 | } |
1655 | __nfsd4_hash_conn(new, ses); | 1660 | __nfsd4_hash_conn(new, ses); |
1656 | spin_unlock(&clp->cl_lock); | 1661 | spin_unlock(&clp->cl_lock); |
1657 | nfsd4_register_conn(new); | 1662 | ret = nfsd4_register_conn(new); |
1663 | if (ret) | ||
1664 | /* oops; xprt is already down: */ | ||
1665 | nfsd4_conn_lost(&new->cn_xpt_user); | ||
1658 | return; | 1666 | return; |
1659 | } | 1667 | } |
1660 | 1668 | ||
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index c9af48fffcd7..7d287afccde5 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
@@ -1111,11 +1111,12 @@ xfs_vm_writepage( | |||
1111 | uptodate = 0; | 1111 | uptodate = 0; |
1112 | 1112 | ||
1113 | /* | 1113 | /* |
1114 | * A hole may still be marked uptodate because discard_buffer | 1114 | * set_page_dirty dirties all buffers in a page, independent |
1115 | * leaves the flag set. | 1115 | * of their state. The dirty state however is entirely |
1116 | * meaningless for holes (!mapped && uptodate), so skip | ||
1117 | * buffers covering holes here. | ||
1116 | */ | 1118 | */ |
1117 | if (!buffer_mapped(bh) && buffer_uptodate(bh)) { | 1119 | if (!buffer_mapped(bh) && buffer_uptodate(bh)) { |
1118 | ASSERT(!buffer_dirty(bh)); | ||
1119 | imap_valid = 0; | 1120 | imap_valid = 0; |
1120 | continue; | 1121 | continue; |
1121 | } | 1122 | } |
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 63fd2c07cb57..aa1d353def29 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c | |||
@@ -1781,7 +1781,6 @@ xfs_buf_delwri_split( | |||
1781 | INIT_LIST_HEAD(list); | 1781 | INIT_LIST_HEAD(list); |
1782 | spin_lock(dwlk); | 1782 | spin_lock(dwlk); |
1783 | list_for_each_entry_safe(bp, n, dwq, b_list) { | 1783 | list_for_each_entry_safe(bp, n, dwq, b_list) { |
1784 | trace_xfs_buf_delwri_split(bp, _RET_IP_); | ||
1785 | ASSERT(bp->b_flags & XBF_DELWRI); | 1784 | ASSERT(bp->b_flags & XBF_DELWRI); |
1786 | 1785 | ||
1787 | if (!XFS_BUF_ISPINNED(bp) && !xfs_buf_cond_lock(bp)) { | 1786 | if (!XFS_BUF_ISPINNED(bp) && !xfs_buf_cond_lock(bp)) { |
@@ -1795,6 +1794,7 @@ xfs_buf_delwri_split( | |||
1795 | _XBF_RUN_QUEUES); | 1794 | _XBF_RUN_QUEUES); |
1796 | bp->b_flags |= XBF_WRITE; | 1795 | bp->b_flags |= XBF_WRITE; |
1797 | list_move_tail(&bp->b_list, list); | 1796 | list_move_tail(&bp->b_list, list); |
1797 | trace_xfs_buf_delwri_split(bp, _RET_IP_); | ||
1798 | } else | 1798 | } else |
1799 | skipped++; | 1799 | skipped++; |
1800 | } | 1800 | } |
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index 2ea238f6d38e..ad442d9e392e 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c | |||
@@ -416,7 +416,7 @@ xfs_attrlist_by_handle( | |||
416 | if (IS_ERR(dentry)) | 416 | if (IS_ERR(dentry)) |
417 | return PTR_ERR(dentry); | 417 | return PTR_ERR(dentry); |
418 | 418 | ||
419 | kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL); | 419 | kbuf = kzalloc(al_hreq.buflen, GFP_KERNEL); |
420 | if (!kbuf) | 420 | if (!kbuf) |
421 | goto out_dput; | 421 | goto out_dput; |
422 | 422 | ||
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 96107efc0c61..94d5fd6a2973 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c | |||
@@ -762,7 +762,8 @@ xfs_setup_inode( | |||
762 | inode->i_state = I_NEW; | 762 | inode->i_state = I_NEW; |
763 | 763 | ||
764 | inode_sb_list_add(inode); | 764 | inode_sb_list_add(inode); |
765 | insert_inode_hash(inode); | 765 | /* make the inode look hashed for the writeback code */ |
766 | hlist_add_fake(&inode->i_hash); | ||
766 | 767 | ||
767 | inode->i_mode = ip->i_d.di_mode; | 768 | inode->i_mode = ip->i_d.di_mode; |
768 | inode->i_nlink = ip->i_d.di_nlink; | 769 | inode->i_nlink = ip->i_d.di_nlink; |
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 9f3a78fe6ae4..064f964d4f3c 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c | |||
@@ -353,9 +353,6 @@ xfs_parseargs( | |||
353 | mp->m_qflags &= ~XFS_OQUOTA_ENFD; | 353 | mp->m_qflags &= ~XFS_OQUOTA_ENFD; |
354 | } else if (!strcmp(this_char, MNTOPT_DELAYLOG)) { | 354 | } else if (!strcmp(this_char, MNTOPT_DELAYLOG)) { |
355 | mp->m_flags |= XFS_MOUNT_DELAYLOG; | 355 | mp->m_flags |= XFS_MOUNT_DELAYLOG; |
356 | cmn_err(CE_WARN, | ||
357 | "Enabling EXPERIMENTAL delayed logging feature " | ||
358 | "- use at your own risk.\n"); | ||
359 | } else if (!strcmp(this_char, MNTOPT_NODELAYLOG)) { | 356 | } else if (!strcmp(this_char, MNTOPT_NODELAYLOG)) { |
360 | mp->m_flags &= ~XFS_MOUNT_DELAYLOG; | 357 | mp->m_flags &= ~XFS_MOUNT_DELAYLOG; |
361 | } else if (!strcmp(this_char, "ihashsize")) { | 358 | } else if (!strcmp(this_char, "ihashsize")) { |
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index 37d33254981d..afb0d7cfad1c 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c | |||
@@ -853,6 +853,7 @@ restart: | |||
853 | if (trylock) { | 853 | if (trylock) { |
854 | if (!mutex_trylock(&pag->pag_ici_reclaim_lock)) { | 854 | if (!mutex_trylock(&pag->pag_ici_reclaim_lock)) { |
855 | skipped++; | 855 | skipped++; |
856 | xfs_perag_put(pag); | ||
856 | continue; | 857 | continue; |
857 | } | 858 | } |
858 | first_index = pag->pag_ici_reclaim_cursor; | 859 | first_index = pag->pag_ici_reclaim_cursor; |
diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c index 9b715dce5699..9124425b7f2f 100644 --- a/fs/xfs/xfs_filestream.c +++ b/fs/xfs/xfs_filestream.c | |||
@@ -744,9 +744,15 @@ xfs_filestream_new_ag( | |||
744 | * If the file's parent directory is known, take its iolock in exclusive | 744 | * If the file's parent directory is known, take its iolock in exclusive |
745 | * mode to prevent two sibling files from racing each other to migrate | 745 | * mode to prevent two sibling files from racing each other to migrate |
746 | * themselves and their parent to different AGs. | 746 | * themselves and their parent to different AGs. |
747 | * | ||
748 | * Note that we lock the parent directory iolock inside the child | ||
749 | * iolock here. That's fine as we never hold both parent and child | ||
750 | * iolock in any other place. This is different from the ilock, | ||
751 | * which requires locking of the child after the parent for namespace | ||
752 | * operations. | ||
747 | */ | 753 | */ |
748 | if (pip) | 754 | if (pip) |
749 | xfs_ilock(pip, XFS_IOLOCK_EXCL); | 755 | xfs_ilock(pip, XFS_IOLOCK_EXCL | XFS_IOLOCK_PARENT); |
750 | 756 | ||
751 | /* | 757 | /* |
752 | * A new AG needs to be found for the file. If the file's parent | 758 | * A new AG needs to be found for the file. If the file's parent |
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index b1498ab5a399..19e9dfa1c254 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
@@ -275,6 +275,7 @@ xfs_free_perag( | |||
275 | pag = radix_tree_delete(&mp->m_perag_tree, agno); | 275 | pag = radix_tree_delete(&mp->m_perag_tree, agno); |
276 | spin_unlock(&mp->m_perag_lock); | 276 | spin_unlock(&mp->m_perag_lock); |
277 | ASSERT(pag); | 277 | ASSERT(pag); |
278 | ASSERT(atomic_read(&pag->pag_ref) == 0); | ||
278 | call_rcu(&pag->rcu_head, __xfs_free_perag); | 279 | call_rcu(&pag->rcu_head, __xfs_free_perag); |
279 | } | 280 | } |
280 | } | 281 | } |
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h index e0e64b113bd6..9bb6eda4cd21 100644 --- a/fs/xfs/xfs_quota.h +++ b/fs/xfs/xfs_quota.h | |||
@@ -346,8 +346,17 @@ xfs_qm_vop_dqalloc(struct xfs_inode *ip, uid_t uid, gid_t gid, prid_t prid, | |||
346 | #define xfs_trans_mod_dquot_byino(tp, ip, fields, delta) | 346 | #define xfs_trans_mod_dquot_byino(tp, ip, fields, delta) |
347 | #define xfs_trans_apply_dquot_deltas(tp) | 347 | #define xfs_trans_apply_dquot_deltas(tp) |
348 | #define xfs_trans_unreserve_and_mod_dquots(tp) | 348 | #define xfs_trans_unreserve_and_mod_dquots(tp) |
349 | #define xfs_trans_reserve_quota_nblks(tp, ip, nblks, ninos, flags) (0) | 349 | static inline int xfs_trans_reserve_quota_nblks(struct xfs_trans *tp, |
350 | #define xfs_trans_reserve_quota_bydquots(tp, mp, u, g, nb, ni, fl) (0) | 350 | struct xfs_inode *ip, long nblks, long ninos, uint flags) |
351 | { | ||
352 | return 0; | ||
353 | } | ||
354 | static inline int xfs_trans_reserve_quota_bydquots(struct xfs_trans *tp, | ||
355 | struct xfs_mount *mp, struct xfs_dquot *udqp, | ||
356 | struct xfs_dquot *gdqp, long nblks, long nions, uint flags) | ||
357 | { | ||
358 | return 0; | ||
359 | } | ||
351 | #define xfs_qm_vop_create_dqattach(tp, ip, u, g) | 360 | #define xfs_qm_vop_create_dqattach(tp, ip, u, g) |
352 | #define xfs_qm_vop_rename_dqattach(it) (0) | 361 | #define xfs_qm_vop_rename_dqattach(it) (0) |
353 | #define xfs_qm_vop_chown(tp, ip, old, new) (NULL) | 362 | #define xfs_qm_vop_chown(tp, ip, old, new) (NULL) |
@@ -357,11 +366,14 @@ xfs_qm_vop_dqalloc(struct xfs_inode *ip, uid_t uid, gid_t gid, prid_t prid, | |||
357 | #define xfs_qm_dqdetach(ip) | 366 | #define xfs_qm_dqdetach(ip) |
358 | #define xfs_qm_dqrele(d) | 367 | #define xfs_qm_dqrele(d) |
359 | #define xfs_qm_statvfs(ip, s) | 368 | #define xfs_qm_statvfs(ip, s) |
360 | #define xfs_qm_sync(mp, fl) (0) | 369 | static inline int xfs_qm_sync(struct xfs_mount *mp, int flags) |
370 | { | ||
371 | return 0; | ||
372 | } | ||
361 | #define xfs_qm_newmount(mp, a, b) (0) | 373 | #define xfs_qm_newmount(mp, a, b) (0) |
362 | #define xfs_qm_mount_quotas(mp) | 374 | #define xfs_qm_mount_quotas(mp) |
363 | #define xfs_qm_unmount(mp) | 375 | #define xfs_qm_unmount(mp) |
364 | #define xfs_qm_unmount_quotas(mp) (0) | 376 | #define xfs_qm_unmount_quotas(mp) |
365 | #endif /* CONFIG_XFS_QUOTA */ | 377 | #endif /* CONFIG_XFS_QUOTA */ |
366 | 378 | ||
367 | #define xfs_trans_unreserve_quota_nblks(tp, ip, nblks, ninos, flags) \ | 379 | #define xfs_trans_unreserve_quota_nblks(tp, ip, nblks, ninos, flags) \ |
diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index 5afa5b52063e..beafc156a535 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h | |||
@@ -432,6 +432,10 @@ extern void ttm_bo_synccpu_write_release(struct ttm_buffer_object *bo); | |||
432 | * together with the @destroy function, | 432 | * together with the @destroy function, |
433 | * enables driver-specific objects derived from a ttm_buffer_object. | 433 | * enables driver-specific objects derived from a ttm_buffer_object. |
434 | * On successful return, the object kref and list_kref are set to 1. | 434 | * On successful return, the object kref and list_kref are set to 1. |
435 | * If a failure occurs, the function will call the @destroy function, or | ||
436 | * kfree() if @destroy is NULL. Thus, after a failure, dereferencing @bo is | ||
437 | * illegal and will likely cause memory corruption. | ||
438 | * | ||
435 | * Returns | 439 | * Returns |
436 | * -ENOMEM: Out of memory. | 440 | * -ENOMEM: Out of memory. |
437 | * -EINVAL: Invalid placement flags. | 441 | * -EINVAL: Invalid placement flags. |
diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index d01b4ddbdc56..8e0c848326b6 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h | |||
@@ -206,14 +206,84 @@ struct ttm_tt { | |||
206 | struct ttm_mem_type_manager; | 206 | struct ttm_mem_type_manager; |
207 | 207 | ||
208 | struct ttm_mem_type_manager_func { | 208 | struct ttm_mem_type_manager_func { |
209 | /** | ||
210 | * struct ttm_mem_type_manager member init | ||
211 | * | ||
212 | * @man: Pointer to a memory type manager. | ||
213 | * @p_size: Implementation dependent, but typically the size of the | ||
214 | * range to be managed in pages. | ||
215 | * | ||
216 | * Called to initialize a private range manager. The function is | ||
217 | * expected to initialize the man::priv member. | ||
218 | * Returns 0 on success, negative error code on failure. | ||
219 | */ | ||
209 | int (*init)(struct ttm_mem_type_manager *man, unsigned long p_size); | 220 | int (*init)(struct ttm_mem_type_manager *man, unsigned long p_size); |
221 | |||
222 | /** | ||
223 | * struct ttm_mem_type_manager member takedown | ||
224 | * | ||
225 | * @man: Pointer to a memory type manager. | ||
226 | * | ||
227 | * Called to undo the setup done in init. All allocated resources | ||
228 | * should be freed. | ||
229 | */ | ||
210 | int (*takedown)(struct ttm_mem_type_manager *man); | 230 | int (*takedown)(struct ttm_mem_type_manager *man); |
231 | |||
232 | /** | ||
233 | * struct ttm_mem_type_manager member get_node | ||
234 | * | ||
235 | * @man: Pointer to a memory type manager. | ||
236 | * @bo: Pointer to the buffer object we're allocating space for. | ||
237 | * @placement: Placement details. | ||
238 | * @mem: Pointer to a struct ttm_mem_reg to be filled in. | ||
239 | * | ||
240 | * This function should allocate space in the memory type managed | ||
241 | * by @man. Placement details if | ||
242 | * applicable are given by @placement. If successful, | ||
243 | * @mem::mm_node should be set to a non-null value, and | ||
244 | * @mem::start should be set to a value identifying the beginning | ||
245 | * of the range allocated, and the function should return zero. | ||
246 | * If the memory region accomodate the buffer object, @mem::mm_node | ||
247 | * should be set to NULL, and the function should return 0. | ||
248 | * If a system error occured, preventing the request to be fulfilled, | ||
249 | * the function should return a negative error code. | ||
250 | * | ||
251 | * Note that @mem::mm_node will only be dereferenced by | ||
252 | * struct ttm_mem_type_manager functions and optionally by the driver, | ||
253 | * which has knowledge of the underlying type. | ||
254 | * | ||
255 | * This function may not be called from within atomic context, so | ||
256 | * an implementation can and must use either a mutex or a spinlock to | ||
257 | * protect any data structures managing the space. | ||
258 | */ | ||
211 | int (*get_node)(struct ttm_mem_type_manager *man, | 259 | int (*get_node)(struct ttm_mem_type_manager *man, |
212 | struct ttm_buffer_object *bo, | 260 | struct ttm_buffer_object *bo, |
213 | struct ttm_placement *placement, | 261 | struct ttm_placement *placement, |
214 | struct ttm_mem_reg *mem); | 262 | struct ttm_mem_reg *mem); |
263 | |||
264 | /** | ||
265 | * struct ttm_mem_type_manager member put_node | ||
266 | * | ||
267 | * @man: Pointer to a memory type manager. | ||
268 | * @mem: Pointer to a struct ttm_mem_reg to be filled in. | ||
269 | * | ||
270 | * This function frees memory type resources previously allocated | ||
271 | * and that are identified by @mem::mm_node and @mem::start. May not | ||
272 | * be called from within atomic context. | ||
273 | */ | ||
215 | void (*put_node)(struct ttm_mem_type_manager *man, | 274 | void (*put_node)(struct ttm_mem_type_manager *man, |
216 | struct ttm_mem_reg *mem); | 275 | struct ttm_mem_reg *mem); |
276 | |||
277 | /** | ||
278 | * struct ttm_mem_type_manager member debug | ||
279 | * | ||
280 | * @man: Pointer to a memory type manager. | ||
281 | * @prefix: Prefix to be used in printout to identify the caller. | ||
282 | * | ||
283 | * This function is called to print out the state of the memory | ||
284 | * type manager to aid debugging of out-of-memory conditions. | ||
285 | * It may not be called from within atomic context. | ||
286 | */ | ||
217 | void (*debug)(struct ttm_mem_type_manager *man, const char *prefix); | 287 | void (*debug)(struct ttm_mem_type_manager *man, const char *prefix); |
218 | }; | 288 | }; |
219 | 289 | ||
@@ -231,14 +301,13 @@ struct ttm_mem_type_manager { | |||
231 | uint64_t size; | 301 | uint64_t size; |
232 | uint32_t available_caching; | 302 | uint32_t available_caching; |
233 | uint32_t default_caching; | 303 | uint32_t default_caching; |
304 | const struct ttm_mem_type_manager_func *func; | ||
305 | void *priv; | ||
234 | 306 | ||
235 | /* | 307 | /* |
236 | * Protected by the bdev->lru_lock. | 308 | * Protected by the global->lru_lock. |
237 | * TODO: Consider one lru_lock per ttm_mem_type_manager. | ||
238 | * Plays ill with list removal, though. | ||
239 | */ | 309 | */ |
240 | const struct ttm_mem_type_manager_func *func; | 310 | |
241 | void *priv; | ||
242 | struct list_head lru; | 311 | struct list_head lru; |
243 | }; | 312 | }; |
244 | 313 | ||
diff --git a/include/linux/atomic.h b/include/linux/atomic.h new file mode 100644 index 000000000000..96c038e43d66 --- /dev/null +++ b/include/linux/atomic.h | |||
@@ -0,0 +1,37 @@ | |||
1 | #ifndef _LINUX_ATOMIC_H | ||
2 | #define _LINUX_ATOMIC_H | ||
3 | #include <asm/atomic.h> | ||
4 | |||
5 | /** | ||
6 | * atomic_inc_not_zero_hint - increment if not null | ||
7 | * @v: pointer of type atomic_t | ||
8 | * @hint: probable value of the atomic before the increment | ||
9 | * | ||
10 | * This version of atomic_inc_not_zero() gives a hint of probable | ||
11 | * value of the atomic. This helps processor to not read the memory | ||
12 | * before doing the atomic read/modify/write cycle, lowering | ||
13 | * number of bus transactions on some arches. | ||
14 | * | ||
15 | * Returns: 0 if increment was not done, 1 otherwise. | ||
16 | */ | ||
17 | #ifndef atomic_inc_not_zero_hint | ||
18 | static inline int atomic_inc_not_zero_hint(atomic_t *v, int hint) | ||
19 | { | ||
20 | int val, c = hint; | ||
21 | |||
22 | /* sanity test, should be removed by compiler if hint is a constant */ | ||
23 | if (!hint) | ||
24 | return atomic_inc_not_zero(v); | ||
25 | |||
26 | do { | ||
27 | val = atomic_cmpxchg(v, c, c + 1); | ||
28 | if (val == c) | ||
29 | return 1; | ||
30 | c = val; | ||
31 | } while (c); | ||
32 | |||
33 | return 0; | ||
34 | } | ||
35 | #endif | ||
36 | |||
37 | #endif /* _LINUX_ATOMIC_H */ | ||
diff --git a/include/linux/highmem.h b/include/linux/highmem.h index e9138198e823..b676c585574e 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/kernel.h> | 5 | #include <linux/kernel.h> |
6 | #include <linux/mm.h> | 6 | #include <linux/mm.h> |
7 | #include <linux/uaccess.h> | 7 | #include <linux/uaccess.h> |
8 | #include <linux/hardirq.h> | ||
8 | 9 | ||
9 | #include <asm/cacheflush.h> | 10 | #include <asm/cacheflush.h> |
10 | 11 | ||
diff --git a/include/linux/kernel.h b/include/linux/kernel.h index b526947bdf48..fc3da9e4da19 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h | |||
@@ -293,6 +293,7 @@ extern bool printk_timed_ratelimit(unsigned long *caller_jiffies, | |||
293 | unsigned int interval_msec); | 293 | unsigned int interval_msec); |
294 | 294 | ||
295 | extern int printk_delay_msec; | 295 | extern int printk_delay_msec; |
296 | extern int dmesg_restrict; | ||
296 | 297 | ||
297 | /* | 298 | /* |
298 | * Print a one-time message (analogous to WARN_ONCE() et al): | 299 | * Print a one-time message (analogous to WARN_ONCE() et al): |
diff --git a/include/linux/leds-lp5521.h b/include/linux/leds-lp5521.h new file mode 100644 index 000000000000..38368d785f08 --- /dev/null +++ b/include/linux/leds-lp5521.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * LP5521 LED chip driver. | ||
3 | * | ||
4 | * Copyright (C) 2010 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Samu Onkalo <samu.p.onkalo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | */ | ||
22 | |||
23 | #ifndef __LINUX_LP5521_H | ||
24 | #define __LINUX_LP5521_H | ||
25 | |||
26 | /* See Documentation/leds/leds-lp5521.txt */ | ||
27 | |||
28 | struct lp5521_led_config { | ||
29 | u8 chan_nr; | ||
30 | u8 led_current; /* mA x10, 0 if led is not connected */ | ||
31 | u8 max_current; | ||
32 | }; | ||
33 | |||
34 | #define LP5521_CLOCK_AUTO 0 | ||
35 | #define LP5521_CLOCK_INT 1 | ||
36 | #define LP5521_CLOCK_EXT 2 | ||
37 | |||
38 | struct lp5521_platform_data { | ||
39 | struct lp5521_led_config *led_config; | ||
40 | u8 num_channels; | ||
41 | u8 clock_mode; | ||
42 | int (*setup_resources)(void); | ||
43 | void (*release_resources)(void); | ||
44 | void (*enable)(bool state); | ||
45 | }; | ||
46 | |||
47 | #endif /* __LINUX_LP5521_H */ | ||
diff --git a/include/linux/leds-lp5523.h b/include/linux/leds-lp5523.h new file mode 100644 index 000000000000..796747637b80 --- /dev/null +++ b/include/linux/leds-lp5523.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * LP5523 LED Driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Nokia Corporation | ||
5 | * | ||
6 | * Contact: Samu Onkalo <samu.p.onkalo@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | */ | ||
22 | |||
23 | #ifndef __LINUX_LP5523_H | ||
24 | #define __LINUX_LP5523_H | ||
25 | |||
26 | /* See Documentation/leds/leds-lp5523.txt */ | ||
27 | |||
28 | struct lp5523_led_config { | ||
29 | u8 chan_nr; | ||
30 | u8 led_current; /* mA x10, 0 if led is not connected */ | ||
31 | u8 max_current; | ||
32 | }; | ||
33 | |||
34 | #define LP5523_CLOCK_AUTO 0 | ||
35 | #define LP5523_CLOCK_INT 1 | ||
36 | #define LP5523_CLOCK_EXT 2 | ||
37 | |||
38 | struct lp5523_platform_data { | ||
39 | struct lp5523_led_config *led_config; | ||
40 | u8 num_channels; | ||
41 | u8 clock_mode; | ||
42 | int (*setup_resources)(void); | ||
43 | void (*release_resources)(void); | ||
44 | void (*enable)(bool state); | ||
45 | }; | ||
46 | |||
47 | #endif /* __LINUX_LP5523_H */ | ||
diff --git a/include/linux/leds.h b/include/linux/leds.h index ba6986a11663..0f19df9e37b0 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/list.h> | 15 | #include <linux/list.h> |
16 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
17 | #include <linux/rwsem.h> | 17 | #include <linux/rwsem.h> |
18 | #include <linux/timer.h> | ||
18 | 19 | ||
19 | struct device; | 20 | struct device; |
20 | /* | 21 | /* |
@@ -45,10 +46,14 @@ struct led_classdev { | |||
45 | /* Get LED brightness level */ | 46 | /* Get LED brightness level */ |
46 | enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); | 47 | enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); |
47 | 48 | ||
48 | /* Activate hardware accelerated blink, delays are in | 49 | /* |
49 | * miliseconds and if none is provided then a sensible default | 50 | * Activate hardware accelerated blink, delays are in milliseconds |
50 | * should be chosen. The call can adjust the timings if it can't | 51 | * and if both are zero then a sensible default should be chosen. |
51 | * match the values specified exactly. */ | 52 | * The call should adjust the timings in that case and if it can't |
53 | * match the values specified exactly. | ||
54 | * Deactivate blinking again when the brightness is set to a fixed | ||
55 | * value via the brightness_set() callback. | ||
56 | */ | ||
52 | int (*blink_set)(struct led_classdev *led_cdev, | 57 | int (*blink_set)(struct led_classdev *led_cdev, |
53 | unsigned long *delay_on, | 58 | unsigned long *delay_on, |
54 | unsigned long *delay_off); | 59 | unsigned long *delay_off); |
@@ -57,6 +62,10 @@ struct led_classdev { | |||
57 | struct list_head node; /* LED Device list */ | 62 | struct list_head node; /* LED Device list */ |
58 | const char *default_trigger; /* Trigger to use */ | 63 | const char *default_trigger; /* Trigger to use */ |
59 | 64 | ||
65 | unsigned long blink_delay_on, blink_delay_off; | ||
66 | struct timer_list blink_timer; | ||
67 | int blink_brightness; | ||
68 | |||
60 | #ifdef CONFIG_LEDS_TRIGGERS | 69 | #ifdef CONFIG_LEDS_TRIGGERS |
61 | /* Protects the trigger data below */ | 70 | /* Protects the trigger data below */ |
62 | struct rw_semaphore trigger_lock; | 71 | struct rw_semaphore trigger_lock; |
@@ -73,6 +82,36 @@ extern void led_classdev_unregister(struct led_classdev *led_cdev); | |||
73 | extern void led_classdev_suspend(struct led_classdev *led_cdev); | 82 | extern void led_classdev_suspend(struct led_classdev *led_cdev); |
74 | extern void led_classdev_resume(struct led_classdev *led_cdev); | 83 | extern void led_classdev_resume(struct led_classdev *led_cdev); |
75 | 84 | ||
85 | /** | ||
86 | * led_blink_set - set blinking with software fallback | ||
87 | * @led_cdev: the LED to start blinking | ||
88 | * @delay_on: the time it should be on (in ms) | ||
89 | * @delay_off: the time it should ble off (in ms) | ||
90 | * | ||
91 | * This function makes the LED blink, attempting to use the | ||
92 | * hardware acceleration if possible, but falling back to | ||
93 | * software blinking if there is no hardware blinking or if | ||
94 | * the LED refuses the passed values. | ||
95 | * | ||
96 | * Note that if software blinking is active, simply calling | ||
97 | * led_cdev->brightness_set() will not stop the blinking, | ||
98 | * use led_classdev_brightness_set() instead. | ||
99 | */ | ||
100 | extern void led_blink_set(struct led_classdev *led_cdev, | ||
101 | unsigned long *delay_on, | ||
102 | unsigned long *delay_off); | ||
103 | /** | ||
104 | * led_brightness_set - set LED brightness | ||
105 | * @led_cdev: the LED to set | ||
106 | * @brightness: the brightness to set it to | ||
107 | * | ||
108 | * Set an LED's brightness, and, if necessary, cancel the | ||
109 | * software blink timer that implements blinking when the | ||
110 | * hardware doesn't. | ||
111 | */ | ||
112 | extern void led_brightness_set(struct led_classdev *led_cdev, | ||
113 | enum led_brightness brightness); | ||
114 | |||
76 | /* | 115 | /* |
77 | * LED Triggers | 116 | * LED Triggers |
78 | */ | 117 | */ |
diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h index 01b3d759f1fc..e031e1a486d9 100644 --- a/include/linux/pwm_backlight.h +++ b/include/linux/pwm_backlight.h | |||
@@ -8,6 +8,7 @@ struct platform_pwm_backlight_data { | |||
8 | int pwm_id; | 8 | int pwm_id; |
9 | unsigned int max_brightness; | 9 | unsigned int max_brightness; |
10 | unsigned int dft_brightness; | 10 | unsigned int dft_brightness; |
11 | unsigned int lth_brightness; | ||
11 | unsigned int pwm_period_ns; | 12 | unsigned int pwm_period_ns; |
12 | int (*init)(struct device *dev); | 13 | int (*init)(struct device *dev); |
13 | int (*notify)(struct device *dev, int brightness); | 14 | int (*notify)(struct device *dev, int brightness); |
diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index a39cbed9ee17..ab2baa5c4884 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h | |||
@@ -34,19 +34,13 @@ | |||
34 | * needed for RCU lookups (because root->height is unreliable). The only | 34 | * needed for RCU lookups (because root->height is unreliable). The only |
35 | * time callers need worry about this is when doing a lookup_slot under | 35 | * time callers need worry about this is when doing a lookup_slot under |
36 | * RCU. | 36 | * RCU. |
37 | * | ||
38 | * Indirect pointer in fact is also used to tag the last pointer of a node | ||
39 | * when it is shrunk, before we rcu free the node. See shrink code for | ||
40 | * details. | ||
37 | */ | 41 | */ |
38 | #define RADIX_TREE_INDIRECT_PTR 1 | 42 | #define RADIX_TREE_INDIRECT_PTR 1 |
39 | #define RADIX_TREE_RETRY ((void *)-1UL) | ||
40 | |||
41 | static inline void *radix_tree_ptr_to_indirect(void *ptr) | ||
42 | { | ||
43 | return (void *)((unsigned long)ptr | RADIX_TREE_INDIRECT_PTR); | ||
44 | } | ||
45 | 43 | ||
46 | static inline void *radix_tree_indirect_to_ptr(void *ptr) | ||
47 | { | ||
48 | return (void *)((unsigned long)ptr & ~RADIX_TREE_INDIRECT_PTR); | ||
49 | } | ||
50 | #define radix_tree_indirect_to_ptr(ptr) \ | 44 | #define radix_tree_indirect_to_ptr(ptr) \ |
51 | radix_tree_indirect_to_ptr((void __force *)(ptr)) | 45 | radix_tree_indirect_to_ptr((void __force *)(ptr)) |
52 | 46 | ||
@@ -140,16 +134,29 @@ do { \ | |||
140 | * removed. | 134 | * removed. |
141 | * | 135 | * |
142 | * For use with radix_tree_lookup_slot(). Caller must hold tree at least read | 136 | * For use with radix_tree_lookup_slot(). Caller must hold tree at least read |
143 | * locked across slot lookup and dereference. More likely, will be used with | 137 | * locked across slot lookup and dereference. Not required if write lock is |
144 | * radix_tree_replace_slot(), as well, so caller will hold tree write locked. | 138 | * held (ie. items cannot be concurrently inserted). |
139 | * | ||
140 | * radix_tree_deref_retry must be used to confirm validity of the pointer if | ||
141 | * only the read lock is held. | ||
145 | */ | 142 | */ |
146 | static inline void *radix_tree_deref_slot(void **pslot) | 143 | static inline void *radix_tree_deref_slot(void **pslot) |
147 | { | 144 | { |
148 | void *ret = rcu_dereference(*pslot); | 145 | return rcu_dereference(*pslot); |
149 | if (unlikely(radix_tree_is_indirect_ptr(ret))) | ||
150 | ret = RADIX_TREE_RETRY; | ||
151 | return ret; | ||
152 | } | 146 | } |
147 | |||
148 | /** | ||
149 | * radix_tree_deref_retry - check radix_tree_deref_slot | ||
150 | * @arg: pointer returned by radix_tree_deref_slot | ||
151 | * Returns: 0 if retry is not required, otherwise retry is required | ||
152 | * | ||
153 | * radix_tree_deref_retry must be used with radix_tree_deref_slot. | ||
154 | */ | ||
155 | static inline int radix_tree_deref_retry(void *arg) | ||
156 | { | ||
157 | return unlikely((unsigned long)arg & RADIX_TREE_INDIRECT_PTR); | ||
158 | } | ||
159 | |||
153 | /** | 160 | /** |
154 | * radix_tree_replace_slot - replace item in a slot | 161 | * radix_tree_replace_slot - replace item in a slot |
155 | * @pslot: pointer to slot, returned by radix_tree_lookup_slot | 162 | * @pslot: pointer to slot, returned by radix_tree_lookup_slot |
diff --git a/include/linux/resource.h b/include/linux/resource.h index 88d36f9145ba..d01c96c1966e 100644 --- a/include/linux/resource.h +++ b/include/linux/resource.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define _LINUX_RESOURCE_H | 2 | #define _LINUX_RESOURCE_H |
3 | 3 | ||
4 | #include <linux/time.h> | 4 | #include <linux/time.h> |
5 | #include <linux/types.h> | ||
5 | 6 | ||
6 | /* | 7 | /* |
7 | * Resource control/accounting header file for linux | 8 | * Resource control/accounting header file for linux |
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index bbdb680ffbe9..aea0d438e3c7 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h | |||
@@ -82,18 +82,28 @@ struct svc_xprt { | |||
82 | struct net *xpt_net; | 82 | struct net *xpt_net; |
83 | }; | 83 | }; |
84 | 84 | ||
85 | static inline void register_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u) | 85 | static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u) |
86 | { | 86 | { |
87 | spin_lock(&xpt->xpt_lock); | 87 | spin_lock(&xpt->xpt_lock); |
88 | list_add(&u->list, &xpt->xpt_users); | 88 | list_del_init(&u->list); |
89 | spin_unlock(&xpt->xpt_lock); | 89 | spin_unlock(&xpt->xpt_lock); |
90 | } | 90 | } |
91 | 91 | ||
92 | static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u) | 92 | static inline int register_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u) |
93 | { | 93 | { |
94 | spin_lock(&xpt->xpt_lock); | 94 | spin_lock(&xpt->xpt_lock); |
95 | list_del_init(&u->list); | 95 | if (test_bit(XPT_CLOSE, &xpt->xpt_flags)) { |
96 | /* | ||
97 | * The connection is about to be deleted soon (or, | ||
98 | * worse, may already be deleted--in which case we've | ||
99 | * already notified the xpt_users). | ||
100 | */ | ||
101 | spin_unlock(&xpt->xpt_lock); | ||
102 | return -ENOTCONN; | ||
103 | } | ||
104 | list_add(&u->list, &xpt->xpt_users); | ||
96 | spin_unlock(&xpt->xpt_lock); | 105 | spin_unlock(&xpt->xpt_lock); |
106 | return 0; | ||
97 | } | 107 | } |
98 | 108 | ||
99 | int svc_reg_xprt_class(struct svc_xprt_class *); | 109 | int svc_reg_xprt_class(struct svc_xprt_class *); |
diff --git a/kernel/latencytop.c b/kernel/latencytop.c index 877fb306d415..17110a4a4fc2 100644 --- a/kernel/latencytop.c +++ b/kernel/latencytop.c | |||
@@ -194,14 +194,7 @@ __account_scheduler_latency(struct task_struct *tsk, int usecs, int inter) | |||
194 | 194 | ||
195 | account_global_scheduler_latency(tsk, &lat); | 195 | account_global_scheduler_latency(tsk, &lat); |
196 | 196 | ||
197 | /* | 197 | for (i = 0; i < tsk->latency_record_count; i++) { |
198 | * short term hack; if we're > 32 we stop; future we recycle: | ||
199 | */ | ||
200 | tsk->latency_record_count++; | ||
201 | if (tsk->latency_record_count >= LT_SAVECOUNT) | ||
202 | goto out_unlock; | ||
203 | |||
204 | for (i = 0; i < LT_SAVECOUNT; i++) { | ||
205 | struct latency_record *mylat; | 198 | struct latency_record *mylat; |
206 | int same = 1; | 199 | int same = 1; |
207 | 200 | ||
@@ -227,8 +220,14 @@ __account_scheduler_latency(struct task_struct *tsk, int usecs, int inter) | |||
227 | } | 220 | } |
228 | } | 221 | } |
229 | 222 | ||
223 | /* | ||
224 | * short term hack; if we're > 32 we stop; future we recycle: | ||
225 | */ | ||
226 | if (tsk->latency_record_count >= LT_SAVECOUNT) | ||
227 | goto out_unlock; | ||
228 | |||
230 | /* Allocated a new one: */ | 229 | /* Allocated a new one: */ |
231 | i = tsk->latency_record_count; | 230 | i = tsk->latency_record_count++; |
232 | memcpy(&tsk->latency_record[i], &lat, sizeof(struct latency_record)); | 231 | memcpy(&tsk->latency_record[i], &lat, sizeof(struct latency_record)); |
233 | 232 | ||
234 | out_unlock: | 233 | out_unlock: |
diff --git a/kernel/printk.c b/kernel/printk.c index b2ebaee8c377..38e7d5868d60 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -261,6 +261,12 @@ static inline void boot_delay_msec(void) | |||
261 | } | 261 | } |
262 | #endif | 262 | #endif |
263 | 263 | ||
264 | #ifdef CONFIG_SECURITY_DMESG_RESTRICT | ||
265 | int dmesg_restrict = 1; | ||
266 | #else | ||
267 | int dmesg_restrict; | ||
268 | #endif | ||
269 | |||
264 | int do_syslog(int type, char __user *buf, int len, bool from_file) | 270 | int do_syslog(int type, char __user *buf, int len, bool from_file) |
265 | { | 271 | { |
266 | unsigned i, j, limit, count; | 272 | unsigned i, j, limit, count; |
diff --git a/kernel/range.c b/kernel/range.c index 471b66acabb5..37fa9b99ad58 100644 --- a/kernel/range.c +++ b/kernel/range.c | |||
@@ -119,7 +119,7 @@ static int cmp_range(const void *x1, const void *x2) | |||
119 | 119 | ||
120 | int clean_sort_range(struct range *range, int az) | 120 | int clean_sort_range(struct range *range, int az) |
121 | { | 121 | { |
122 | int i, j, k = az - 1, nr_range = 0; | 122 | int i, j, k = az - 1, nr_range = az; |
123 | 123 | ||
124 | for (i = 0; i < k; i++) { | 124 | for (i = 0; i < k; i++) { |
125 | if (range[i].end) | 125 | if (range[i].end) |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index c33a1edb799f..b65bf634035e 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -704,6 +704,15 @@ static struct ctl_table kern_table[] = { | |||
704 | }, | 704 | }, |
705 | #endif | 705 | #endif |
706 | { | 706 | { |
707 | .procname = "dmesg_restrict", | ||
708 | .data = &dmesg_restrict, | ||
709 | .maxlen = sizeof(int), | ||
710 | .mode = 0644, | ||
711 | .proc_handler = proc_dointvec_minmax, | ||
712 | .extra1 = &zero, | ||
713 | .extra2 = &one, | ||
714 | }, | ||
715 | { | ||
707 | .procname = "ngroups_max", | 716 | .procname = "ngroups_max", |
708 | .data = &ngroups_max, | 717 | .data = &ngroups_max, |
709 | .maxlen = sizeof (int), | 718 | .maxlen = sizeof (int), |
diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 6f412ab4c24f..5086bb962b4d 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c | |||
@@ -82,6 +82,16 @@ struct radix_tree_preload { | |||
82 | }; | 82 | }; |
83 | static DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, }; | 83 | static DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, }; |
84 | 84 | ||
85 | static inline void *ptr_to_indirect(void *ptr) | ||
86 | { | ||
87 | return (void *)((unsigned long)ptr | RADIX_TREE_INDIRECT_PTR); | ||
88 | } | ||
89 | |||
90 | static inline void *indirect_to_ptr(void *ptr) | ||
91 | { | ||
92 | return (void *)((unsigned long)ptr & ~RADIX_TREE_INDIRECT_PTR); | ||
93 | } | ||
94 | |||
85 | static inline gfp_t root_gfp_mask(struct radix_tree_root *root) | 95 | static inline gfp_t root_gfp_mask(struct radix_tree_root *root) |
86 | { | 96 | { |
87 | return root->gfp_mask & __GFP_BITS_MASK; | 97 | return root->gfp_mask & __GFP_BITS_MASK; |
@@ -265,7 +275,7 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) | |||
265 | return -ENOMEM; | 275 | return -ENOMEM; |
266 | 276 | ||
267 | /* Increase the height. */ | 277 | /* Increase the height. */ |
268 | node->slots[0] = radix_tree_indirect_to_ptr(root->rnode); | 278 | node->slots[0] = indirect_to_ptr(root->rnode); |
269 | 279 | ||
270 | /* Propagate the aggregated tag info into the new root */ | 280 | /* Propagate the aggregated tag info into the new root */ |
271 | for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { | 281 | for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { |
@@ -276,7 +286,7 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) | |||
276 | newheight = root->height+1; | 286 | newheight = root->height+1; |
277 | node->height = newheight; | 287 | node->height = newheight; |
278 | node->count = 1; | 288 | node->count = 1; |
279 | node = radix_tree_ptr_to_indirect(node); | 289 | node = ptr_to_indirect(node); |
280 | rcu_assign_pointer(root->rnode, node); | 290 | rcu_assign_pointer(root->rnode, node); |
281 | root->height = newheight; | 291 | root->height = newheight; |
282 | } while (height > root->height); | 292 | } while (height > root->height); |
@@ -309,7 +319,7 @@ int radix_tree_insert(struct radix_tree_root *root, | |||
309 | return error; | 319 | return error; |
310 | } | 320 | } |
311 | 321 | ||
312 | slot = radix_tree_indirect_to_ptr(root->rnode); | 322 | slot = indirect_to_ptr(root->rnode); |
313 | 323 | ||
314 | height = root->height; | 324 | height = root->height; |
315 | shift = (height-1) * RADIX_TREE_MAP_SHIFT; | 325 | shift = (height-1) * RADIX_TREE_MAP_SHIFT; |
@@ -325,8 +335,7 @@ int radix_tree_insert(struct radix_tree_root *root, | |||
325 | rcu_assign_pointer(node->slots[offset], slot); | 335 | rcu_assign_pointer(node->slots[offset], slot); |
326 | node->count++; | 336 | node->count++; |
327 | } else | 337 | } else |
328 | rcu_assign_pointer(root->rnode, | 338 | rcu_assign_pointer(root->rnode, ptr_to_indirect(slot)); |
329 | radix_tree_ptr_to_indirect(slot)); | ||
330 | } | 339 | } |
331 | 340 | ||
332 | /* Go a level down */ | 341 | /* Go a level down */ |
@@ -374,7 +383,7 @@ static void *radix_tree_lookup_element(struct radix_tree_root *root, | |||
374 | return NULL; | 383 | return NULL; |
375 | return is_slot ? (void *)&root->rnode : node; | 384 | return is_slot ? (void *)&root->rnode : node; |
376 | } | 385 | } |
377 | node = radix_tree_indirect_to_ptr(node); | 386 | node = indirect_to_ptr(node); |
378 | 387 | ||
379 | height = node->height; | 388 | height = node->height; |
380 | if (index > radix_tree_maxindex(height)) | 389 | if (index > radix_tree_maxindex(height)) |
@@ -393,7 +402,7 @@ static void *radix_tree_lookup_element(struct radix_tree_root *root, | |||
393 | height--; | 402 | height--; |
394 | } while (height > 0); | 403 | } while (height > 0); |
395 | 404 | ||
396 | return is_slot ? (void *)slot:node; | 405 | return is_slot ? (void *)slot : indirect_to_ptr(node); |
397 | } | 406 | } |
398 | 407 | ||
399 | /** | 408 | /** |
@@ -455,7 +464,7 @@ void *radix_tree_tag_set(struct radix_tree_root *root, | |||
455 | height = root->height; | 464 | height = root->height; |
456 | BUG_ON(index > radix_tree_maxindex(height)); | 465 | BUG_ON(index > radix_tree_maxindex(height)); |
457 | 466 | ||
458 | slot = radix_tree_indirect_to_ptr(root->rnode); | 467 | slot = indirect_to_ptr(root->rnode); |
459 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; | 468 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; |
460 | 469 | ||
461 | while (height > 0) { | 470 | while (height > 0) { |
@@ -509,7 +518,7 @@ void *radix_tree_tag_clear(struct radix_tree_root *root, | |||
509 | 518 | ||
510 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; | 519 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; |
511 | pathp->node = NULL; | 520 | pathp->node = NULL; |
512 | slot = radix_tree_indirect_to_ptr(root->rnode); | 521 | slot = indirect_to_ptr(root->rnode); |
513 | 522 | ||
514 | while (height > 0) { | 523 | while (height > 0) { |
515 | int offset; | 524 | int offset; |
@@ -579,7 +588,7 @@ int radix_tree_tag_get(struct radix_tree_root *root, | |||
579 | 588 | ||
580 | if (!radix_tree_is_indirect_ptr(node)) | 589 | if (!radix_tree_is_indirect_ptr(node)) |
581 | return (index == 0); | 590 | return (index == 0); |
582 | node = radix_tree_indirect_to_ptr(node); | 591 | node = indirect_to_ptr(node); |
583 | 592 | ||
584 | height = node->height; | 593 | height = node->height; |
585 | if (index > radix_tree_maxindex(height)) | 594 | if (index > radix_tree_maxindex(height)) |
@@ -666,7 +675,7 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root, | |||
666 | } | 675 | } |
667 | 676 | ||
668 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; | 677 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; |
669 | slot = radix_tree_indirect_to_ptr(root->rnode); | 678 | slot = indirect_to_ptr(root->rnode); |
670 | 679 | ||
671 | /* | 680 | /* |
672 | * we fill the path from (root->height - 2) to 0, leaving the index at | 681 | * we fill the path from (root->height - 2) to 0, leaving the index at |
@@ -897,7 +906,7 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results, | |||
897 | results[0] = node; | 906 | results[0] = node; |
898 | return 1; | 907 | return 1; |
899 | } | 908 | } |
900 | node = radix_tree_indirect_to_ptr(node); | 909 | node = indirect_to_ptr(node); |
901 | 910 | ||
902 | max_index = radix_tree_maxindex(node->height); | 911 | max_index = radix_tree_maxindex(node->height); |
903 | 912 | ||
@@ -916,7 +925,8 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results, | |||
916 | slot = *(((void ***)results)[ret + i]); | 925 | slot = *(((void ***)results)[ret + i]); |
917 | if (!slot) | 926 | if (!slot) |
918 | continue; | 927 | continue; |
919 | results[ret + nr_found] = rcu_dereference_raw(slot); | 928 | results[ret + nr_found] = |
929 | indirect_to_ptr(rcu_dereference_raw(slot)); | ||
920 | nr_found++; | 930 | nr_found++; |
921 | } | 931 | } |
922 | ret += nr_found; | 932 | ret += nr_found; |
@@ -965,7 +975,7 @@ radix_tree_gang_lookup_slot(struct radix_tree_root *root, void ***results, | |||
965 | results[0] = (void **)&root->rnode; | 975 | results[0] = (void **)&root->rnode; |
966 | return 1; | 976 | return 1; |
967 | } | 977 | } |
968 | node = radix_tree_indirect_to_ptr(node); | 978 | node = indirect_to_ptr(node); |
969 | 979 | ||
970 | max_index = radix_tree_maxindex(node->height); | 980 | max_index = radix_tree_maxindex(node->height); |
971 | 981 | ||
@@ -1090,7 +1100,7 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, | |||
1090 | results[0] = node; | 1100 | results[0] = node; |
1091 | return 1; | 1101 | return 1; |
1092 | } | 1102 | } |
1093 | node = radix_tree_indirect_to_ptr(node); | 1103 | node = indirect_to_ptr(node); |
1094 | 1104 | ||
1095 | max_index = radix_tree_maxindex(node->height); | 1105 | max_index = radix_tree_maxindex(node->height); |
1096 | 1106 | ||
@@ -1109,7 +1119,8 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, | |||
1109 | slot = *(((void ***)results)[ret + i]); | 1119 | slot = *(((void ***)results)[ret + i]); |
1110 | if (!slot) | 1120 | if (!slot) |
1111 | continue; | 1121 | continue; |
1112 | results[ret + nr_found] = rcu_dereference_raw(slot); | 1122 | results[ret + nr_found] = |
1123 | indirect_to_ptr(rcu_dereference_raw(slot)); | ||
1113 | nr_found++; | 1124 | nr_found++; |
1114 | } | 1125 | } |
1115 | ret += nr_found; | 1126 | ret += nr_found; |
@@ -1159,7 +1170,7 @@ radix_tree_gang_lookup_tag_slot(struct radix_tree_root *root, void ***results, | |||
1159 | results[0] = (void **)&root->rnode; | 1170 | results[0] = (void **)&root->rnode; |
1160 | return 1; | 1171 | return 1; |
1161 | } | 1172 | } |
1162 | node = radix_tree_indirect_to_ptr(node); | 1173 | node = indirect_to_ptr(node); |
1163 | 1174 | ||
1164 | max_index = radix_tree_maxindex(node->height); | 1175 | max_index = radix_tree_maxindex(node->height); |
1165 | 1176 | ||
@@ -1195,7 +1206,7 @@ static inline void radix_tree_shrink(struct radix_tree_root *root) | |||
1195 | void *newptr; | 1206 | void *newptr; |
1196 | 1207 | ||
1197 | BUG_ON(!radix_tree_is_indirect_ptr(to_free)); | 1208 | BUG_ON(!radix_tree_is_indirect_ptr(to_free)); |
1198 | to_free = radix_tree_indirect_to_ptr(to_free); | 1209 | to_free = indirect_to_ptr(to_free); |
1199 | 1210 | ||
1200 | /* | 1211 | /* |
1201 | * The candidate node has more than one child, or its child | 1212 | * The candidate node has more than one child, or its child |
@@ -1208,16 +1219,39 @@ static inline void radix_tree_shrink(struct radix_tree_root *root) | |||
1208 | 1219 | ||
1209 | /* | 1220 | /* |
1210 | * We don't need rcu_assign_pointer(), since we are simply | 1221 | * We don't need rcu_assign_pointer(), since we are simply |
1211 | * moving the node from one part of the tree to another. If | 1222 | * moving the node from one part of the tree to another: if it |
1212 | * it was safe to dereference the old pointer to it | 1223 | * was safe to dereference the old pointer to it |
1213 | * (to_free->slots[0]), it will be safe to dereference the new | 1224 | * (to_free->slots[0]), it will be safe to dereference the new |
1214 | * one (root->rnode). | 1225 | * one (root->rnode) as far as dependent read barriers go. |
1215 | */ | 1226 | */ |
1216 | newptr = to_free->slots[0]; | 1227 | newptr = to_free->slots[0]; |
1217 | if (root->height > 1) | 1228 | if (root->height > 1) |
1218 | newptr = radix_tree_ptr_to_indirect(newptr); | 1229 | newptr = ptr_to_indirect(newptr); |
1219 | root->rnode = newptr; | 1230 | root->rnode = newptr; |
1220 | root->height--; | 1231 | root->height--; |
1232 | |||
1233 | /* | ||
1234 | * We have a dilemma here. The node's slot[0] must not be | ||
1235 | * NULLed in case there are concurrent lookups expecting to | ||
1236 | * find the item. However if this was a bottom-level node, | ||
1237 | * then it may be subject to the slot pointer being visible | ||
1238 | * to callers dereferencing it. If item corresponding to | ||
1239 | * slot[0] is subsequently deleted, these callers would expect | ||
1240 | * their slot to become empty sooner or later. | ||
1241 | * | ||
1242 | * For example, lockless pagecache will look up a slot, deref | ||
1243 | * the page pointer, and if the page is 0 refcount it means it | ||
1244 | * was concurrently deleted from pagecache so try the deref | ||
1245 | * again. Fortunately there is already a requirement for logic | ||
1246 | * to retry the entire slot lookup -- the indirect pointer | ||
1247 | * problem (replacing direct root node with an indirect pointer | ||
1248 | * also results in a stale slot). So tag the slot as indirect | ||
1249 | * to force callers to retry. | ||
1250 | */ | ||
1251 | if (root->height == 0) | ||
1252 | *((unsigned long *)&to_free->slots[0]) |= | ||
1253 | RADIX_TREE_INDIRECT_PTR; | ||
1254 | |||
1221 | radix_tree_node_free(to_free); | 1255 | radix_tree_node_free(to_free); |
1222 | } | 1256 | } |
1223 | } | 1257 | } |
@@ -1254,7 +1288,7 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) | |||
1254 | root->rnode = NULL; | 1288 | root->rnode = NULL; |
1255 | goto out; | 1289 | goto out; |
1256 | } | 1290 | } |
1257 | slot = radix_tree_indirect_to_ptr(slot); | 1291 | slot = indirect_to_ptr(slot); |
1258 | 1292 | ||
1259 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; | 1293 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; |
1260 | pathp->node = NULL; | 1294 | pathp->node = NULL; |
@@ -1296,8 +1330,7 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) | |||
1296 | radix_tree_node_free(to_free); | 1330 | radix_tree_node_free(to_free); |
1297 | 1331 | ||
1298 | if (pathp->node->count) { | 1332 | if (pathp->node->count) { |
1299 | if (pathp->node == | 1333 | if (pathp->node == indirect_to_ptr(root->rnode)) |
1300 | radix_tree_indirect_to_ptr(root->rnode)) | ||
1301 | radix_tree_shrink(root); | 1334 | radix_tree_shrink(root); |
1302 | goto out; | 1335 | goto out; |
1303 | } | 1336 | } |
diff --git a/mm/filemap.c b/mm/filemap.c index 61ba5e405791..ea89840fc65f 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -644,7 +644,9 @@ repeat: | |||
644 | pagep = radix_tree_lookup_slot(&mapping->page_tree, offset); | 644 | pagep = radix_tree_lookup_slot(&mapping->page_tree, offset); |
645 | if (pagep) { | 645 | if (pagep) { |
646 | page = radix_tree_deref_slot(pagep); | 646 | page = radix_tree_deref_slot(pagep); |
647 | if (unlikely(!page || page == RADIX_TREE_RETRY)) | 647 | if (unlikely(!page)) |
648 | goto out; | ||
649 | if (radix_tree_deref_retry(page)) | ||
648 | goto repeat; | 650 | goto repeat; |
649 | 651 | ||
650 | if (!page_cache_get_speculative(page)) | 652 | if (!page_cache_get_speculative(page)) |
@@ -660,6 +662,7 @@ repeat: | |||
660 | goto repeat; | 662 | goto repeat; |
661 | } | 663 | } |
662 | } | 664 | } |
665 | out: | ||
663 | rcu_read_unlock(); | 666 | rcu_read_unlock(); |
664 | 667 | ||
665 | return page; | 668 | return page; |
@@ -777,12 +780,11 @@ repeat: | |||
777 | page = radix_tree_deref_slot((void **)pages[i]); | 780 | page = radix_tree_deref_slot((void **)pages[i]); |
778 | if (unlikely(!page)) | 781 | if (unlikely(!page)) |
779 | continue; | 782 | continue; |
780 | /* | 783 | if (radix_tree_deref_retry(page)) { |
781 | * this can only trigger if nr_found == 1, making livelock | 784 | if (ret) |
782 | * a non issue. | 785 | start = pages[ret-1]->index; |
783 | */ | ||
784 | if (unlikely(page == RADIX_TREE_RETRY)) | ||
785 | goto restart; | 786 | goto restart; |
787 | } | ||
786 | 788 | ||
787 | if (!page_cache_get_speculative(page)) | 789 | if (!page_cache_get_speculative(page)) |
788 | goto repeat; | 790 | goto repeat; |
@@ -830,11 +832,7 @@ repeat: | |||
830 | page = radix_tree_deref_slot((void **)pages[i]); | 832 | page = radix_tree_deref_slot((void **)pages[i]); |
831 | if (unlikely(!page)) | 833 | if (unlikely(!page)) |
832 | continue; | 834 | continue; |
833 | /* | 835 | if (radix_tree_deref_retry(page)) |
834 | * this can only trigger if nr_found == 1, making livelock | ||
835 | * a non issue. | ||
836 | */ | ||
837 | if (unlikely(page == RADIX_TREE_RETRY)) | ||
838 | goto restart; | 836 | goto restart; |
839 | 837 | ||
840 | if (page->mapping == NULL || page->index != index) | 838 | if (page->mapping == NULL || page->index != index) |
@@ -887,11 +885,7 @@ repeat: | |||
887 | page = radix_tree_deref_slot((void **)pages[i]); | 885 | page = radix_tree_deref_slot((void **)pages[i]); |
888 | if (unlikely(!page)) | 886 | if (unlikely(!page)) |
889 | continue; | 887 | continue; |
890 | /* | 888 | if (radix_tree_deref_retry(page)) |
891 | * this can only trigger if nr_found == 1, making livelock | ||
892 | * a non issue. | ||
893 | */ | ||
894 | if (unlikely(page == RADIX_TREE_RETRY)) | ||
895 | goto restart; | 889 | goto restart; |
896 | 890 | ||
897 | if (!page_cache_get_speculative(page)) | 891 | if (!page_cache_get_speculative(page)) |
@@ -1029,6 +1023,9 @@ find_page: | |||
1029 | goto page_not_up_to_date; | 1023 | goto page_not_up_to_date; |
1030 | if (!trylock_page(page)) | 1024 | if (!trylock_page(page)) |
1031 | goto page_not_up_to_date; | 1025 | goto page_not_up_to_date; |
1026 | /* Did it get truncated before we got the lock? */ | ||
1027 | if (!page->mapping) | ||
1028 | goto page_not_up_to_date_locked; | ||
1032 | if (!mapping->a_ops->is_partially_uptodate(page, | 1029 | if (!mapping->a_ops->is_partially_uptodate(page, |
1033 | desc, offset)) | 1030 | desc, offset)) |
1034 | goto page_not_up_to_date_locked; | 1031 | goto page_not_up_to_date_locked; |
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 9a99cfaf0a19..2efa8ea07ff7 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -4208,15 +4208,17 @@ static struct mem_cgroup *mem_cgroup_alloc(void) | |||
4208 | 4208 | ||
4209 | memset(mem, 0, size); | 4209 | memset(mem, 0, size); |
4210 | mem->stat = alloc_percpu(struct mem_cgroup_stat_cpu); | 4210 | mem->stat = alloc_percpu(struct mem_cgroup_stat_cpu); |
4211 | if (!mem->stat) { | 4211 | if (!mem->stat) |
4212 | if (size < PAGE_SIZE) | 4212 | goto out_free; |
4213 | kfree(mem); | ||
4214 | else | ||
4215 | vfree(mem); | ||
4216 | mem = NULL; | ||
4217 | } | ||
4218 | spin_lock_init(&mem->pcp_counter_lock); | 4213 | spin_lock_init(&mem->pcp_counter_lock); |
4219 | return mem; | 4214 | return mem; |
4215 | |||
4216 | out_free: | ||
4217 | if (size < PAGE_SIZE) | ||
4218 | kfree(mem); | ||
4219 | else | ||
4220 | vfree(mem); | ||
4221 | return NULL; | ||
4220 | } | 4222 | } |
4221 | 4223 | ||
4222 | /* | 4224 | /* |
diff --git a/mm/vmscan.c b/mm/vmscan.c index b8a6fdc21312..d31d7ce52c0e 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c | |||
@@ -913,7 +913,7 @@ keep_lumpy: | |||
913 | * back off and wait for congestion to clear because further reclaim | 913 | * back off and wait for congestion to clear because further reclaim |
914 | * will encounter the same problem | 914 | * will encounter the same problem |
915 | */ | 915 | */ |
916 | if (nr_dirty == nr_congested) | 916 | if (nr_dirty == nr_congested && nr_dirty != 0) |
917 | zone_set_flag(zone, ZONE_CONGESTED); | 917 | zone_set_flag(zone, ZONE_CONGESTED); |
918 | 918 | ||
919 | free_page_list(&free_pages); | 919 | free_page_list(&free_pages); |
diff --git a/security/Kconfig b/security/Kconfig index bd72ae623494..e80da955e687 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
@@ -39,6 +39,18 @@ config KEYS_DEBUG_PROC_KEYS | |||
39 | 39 | ||
40 | If you are unsure as to whether this is required, answer N. | 40 | If you are unsure as to whether this is required, answer N. |
41 | 41 | ||
42 | config SECURITY_DMESG_RESTRICT | ||
43 | bool "Restrict unprivileged access to the kernel syslog" | ||
44 | default n | ||
45 | help | ||
46 | This enforces restrictions on unprivileged users reading the kernel | ||
47 | syslog via dmesg(8). | ||
48 | |||
49 | If this option is not selected, no restrictions will be enforced | ||
50 | unless the dmesg_restrict sysctl is explicitly set to (1). | ||
51 | |||
52 | If you are unsure how to answer this question, answer N. | ||
53 | |||
42 | config SECURITY | 54 | config SECURITY |
43 | bool "Enable different security models" | 55 | bool "Enable different security models" |
44 | depends on SYSFS | 56 | depends on SYSFS |
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index cf1de4462ccd..b7106f192b75 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c | |||
@@ -922,7 +922,7 @@ static int __init apparmor_init(void) | |||
922 | error = register_security(&apparmor_ops); | 922 | error = register_security(&apparmor_ops); |
923 | if (error) { | 923 | if (error) { |
924 | AA_ERROR("Unable to register AppArmor\n"); | 924 | AA_ERROR("Unable to register AppArmor\n"); |
925 | goto register_security_out; | 925 | goto set_init_cxt_out; |
926 | } | 926 | } |
927 | 927 | ||
928 | /* Report that AppArmor successfully initialized */ | 928 | /* Report that AppArmor successfully initialized */ |
@@ -936,6 +936,9 @@ static int __init apparmor_init(void) | |||
936 | 936 | ||
937 | return error; | 937 | return error; |
938 | 938 | ||
939 | set_init_cxt_out: | ||
940 | aa_free_task_context(current->real_cred->security); | ||
941 | |||
939 | register_security_out: | 942 | register_security_out: |
940 | aa_free_root_ns(); | 943 | aa_free_root_ns(); |
941 | 944 | ||
@@ -944,7 +947,6 @@ alloc_out: | |||
944 | 947 | ||
945 | apparmor_enabled = 0; | 948 | apparmor_enabled = 0; |
946 | return error; | 949 | return error; |
947 | |||
948 | } | 950 | } |
949 | 951 | ||
950 | security_initcall(apparmor_init); | 952 | security_initcall(apparmor_init); |
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 52cc865f1464..4f0eadee78b8 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c | |||
@@ -306,7 +306,7 @@ static struct aa_namespace *alloc_namespace(const char *prefix, | |||
306 | return ns; | 306 | return ns; |
307 | 307 | ||
308 | fail_unconfined: | 308 | fail_unconfined: |
309 | kzfree(ns->base.name); | 309 | kzfree(ns->base.hname); |
310 | fail_ns: | 310 | fail_ns: |
311 | kzfree(ns); | 311 | kzfree(ns); |
312 | return NULL; | 312 | return NULL; |
diff --git a/security/commoncap.c b/security/commoncap.c index 5e632b4857e4..04b80f9912bf 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -895,6 +895,8 @@ int cap_syslog(int type, bool from_file) | |||
895 | { | 895 | { |
896 | if (type != SYSLOG_ACTION_OPEN && from_file) | 896 | if (type != SYSLOG_ACTION_OPEN && from_file) |
897 | return 0; | 897 | return 0; |
898 | if (dmesg_restrict && !capable(CAP_SYS_ADMIN)) | ||
899 | return -EPERM; | ||
898 | if ((type != SYSLOG_ACTION_READ_ALL && | 900 | if ((type != SYSLOG_ACTION_READ_ALL && |
899 | type != SYSLOG_ACTION_SIZE_BUFFER) && !capable(CAP_SYS_ADMIN)) | 901 | type != SYSLOG_ACTION_SIZE_BUFFER) && !capable(CAP_SYS_ADMIN)) |
900 | return -EPERM; | 902 | return -EPERM; |