diff options
396 files changed, 10827 insertions, 2804 deletions
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 4ee2304f82f9..6c11d77c8d02 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl | |||
@@ -978,10 +978,25 @@ int max_width, max_height;</synopsis> | |||
978 | If the parameters are deemed valid, drivers then create, initialize and | 978 | If the parameters are deemed valid, drivers then create, initialize and |
979 | return an instance of struct <structname>drm_framebuffer</structname>. | 979 | return an instance of struct <structname>drm_framebuffer</structname>. |
980 | If desired the instance can be embedded in a larger driver-specific | 980 | If desired the instance can be embedded in a larger driver-specific |
981 | structure. The new instance is initialized with a call to | 981 | structure. Drivers must fill its <structfield>width</structfield>, |
982 | <function>drm_framebuffer_init</function> which takes a pointer to DRM | 982 | <structfield>height</structfield>, <structfield>pitches</structfield>, |
983 | frame buffer operations (struct | 983 | <structfield>offsets</structfield>, <structfield>depth</structfield>, |
984 | <structname>drm_framebuffer_funcs</structname>). Frame buffer operations are | 984 | <structfield>bits_per_pixel</structfield> and |
985 | <structfield>pixel_format</structfield> fields from the values passed | ||
986 | through the <parameter>drm_mode_fb_cmd2</parameter> argument. They | ||
987 | should call the <function>drm_helper_mode_fill_fb_struct</function> | ||
988 | helper function to do so. | ||
989 | </para> | ||
990 | |||
991 | <para> | ||
992 | The initailization of the new framebuffer instance is finalized with a | ||
993 | call to <function>drm_framebuffer_init</function> which takes a pointer | ||
994 | to DRM frame buffer operations (struct | ||
995 | <structname>drm_framebuffer_funcs</structname>). Note that this function | ||
996 | publishes the framebuffer and so from this point on it can be accessed | ||
997 | concurrently from other threads. Hence it must be the last step in the | ||
998 | driver's framebuffer initialization sequence. Frame buffer operations | ||
999 | are | ||
985 | <itemizedlist> | 1000 | <itemizedlist> |
986 | <listitem> | 1001 | <listitem> |
987 | <synopsis>int (*create_handle)(struct drm_framebuffer *fb, | 1002 | <synopsis>int (*create_handle)(struct drm_framebuffer *fb, |
@@ -1022,16 +1037,16 @@ int max_width, max_height;</synopsis> | |||
1022 | </itemizedlist> | 1037 | </itemizedlist> |
1023 | </para> | 1038 | </para> |
1024 | <para> | 1039 | <para> |
1025 | After initializing the <structname>drm_framebuffer</structname> | 1040 | The lifetime of a drm framebuffer is controlled with a reference count, |
1026 | instance drivers must fill its <structfield>width</structfield>, | 1041 | drivers can grab additional references with |
1027 | <structfield>height</structfield>, <structfield>pitches</structfield>, | 1042 | <function>drm_framebuffer_reference</function> </para> and drop them |
1028 | <structfield>offsets</structfield>, <structfield>depth</structfield>, | 1043 | again with <function>drm_framebuffer_unreference</function>. For |
1029 | <structfield>bits_per_pixel</structfield> and | 1044 | driver-private framebuffers for which the last reference is never |
1030 | <structfield>pixel_format</structfield> fields from the values passed | 1045 | dropped (e.g. for the fbdev framebuffer when the struct |
1031 | through the <parameter>drm_mode_fb_cmd2</parameter> argument. They | 1046 | <structname>drm_framebuffer</structname> is embedded into the fbdev |
1032 | should call the <function>drm_helper_mode_fill_fb_struct</function> | 1047 | helper struct) drivers can manually clean up a framebuffer at module |
1033 | helper function to do so. | 1048 | unload time with |
1034 | </para> | 1049 | <function>drm_framebuffer_unregister_private</function>. |
1035 | </sect2> | 1050 | </sect2> |
1036 | <sect2> | 1051 | <sect2> |
1037 | <title>Output Polling</title> | 1052 | <title>Output Polling</title> |
@@ -1043,6 +1058,22 @@ int max_width, max_height;</synopsis> | |||
1043 | operation. | 1058 | operation. |
1044 | </para> | 1059 | </para> |
1045 | </sect2> | 1060 | </sect2> |
1061 | <sect2> | ||
1062 | <title>Locking</title> | ||
1063 | <para> | ||
1064 | Beside some lookup structures with their own locking (which is hidden | ||
1065 | behind the interface functions) most of the modeset state is protected | ||
1066 | by the <code>dev-<mode_config.lock</code> mutex and additionally | ||
1067 | per-crtc locks to allow cursor updates, pageflips and similar operations | ||
1068 | to occur concurrently with background tasks like output detection. | ||
1069 | Operations which cross domains like a full modeset always grab all | ||
1070 | locks. Drivers there need to protect resources shared between crtcs with | ||
1071 | additional locking. They also need to be careful to always grab the | ||
1072 | relevant crtc locks if a modset functions touches crtc state, e.g. for | ||
1073 | load detection (which does only grab the <code>mode_config.lock</code> | ||
1074 | to allow concurrent screen updates on live crtcs). | ||
1075 | </para> | ||
1076 | </sect2> | ||
1046 | </sect1> | 1077 | </sect1> |
1047 | 1078 | ||
1048 | <!-- Internals: kms initialization and cleanup --> | 1079 | <!-- Internals: kms initialization and cleanup --> |
@@ -1609,6 +1640,10 @@ void intel_crt_init(struct drm_device *dev) | |||
1609 | make its properties available to applications. | 1640 | make its properties available to applications. |
1610 | </para> | 1641 | </para> |
1611 | </sect2> | 1642 | </sect2> |
1643 | <sect2> | ||
1644 | <title>KMS API Functions</title> | ||
1645 | !Edrivers/gpu/drm/drm_crtc.c | ||
1646 | </sect2> | ||
1612 | </sect1> | 1647 | </sect1> |
1613 | 1648 | ||
1614 | <!-- Internals: kms helper functions --> | 1649 | <!-- Internals: kms helper functions --> |
diff --git a/MAINTAINERS b/MAINTAINERS index 915564eda145..3105c4868c4e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -228,7 +228,7 @@ S: Maintained | |||
228 | F: drivers/platform/x86/acerhdf.c | 228 | F: drivers/platform/x86/acerhdf.c |
229 | 229 | ||
230 | ACER WMI LAPTOP EXTRAS | 230 | ACER WMI LAPTOP EXTRAS |
231 | M: Joey Lee <jlee@novell.com> | 231 | M: "Lee, Chun-Yi" <jlee@suse.com> |
232 | L: platform-driver-x86@vger.kernel.org | 232 | L: platform-driver-x86@vger.kernel.org |
233 | S: Maintained | 233 | S: Maintained |
234 | F: drivers/platform/x86/acer-wmi.c | 234 | F: drivers/platform/x86/acer-wmi.c |
@@ -648,7 +648,7 @@ F: arch/arm/ | |||
648 | 648 | ||
649 | ARM SUB-ARCHITECTURES | 649 | ARM SUB-ARCHITECTURES |
650 | L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) | 650 | L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) |
651 | S: MAINTAINED | 651 | S: Maintained |
652 | F: arch/arm/mach-*/ | 652 | F: arch/arm/mach-*/ |
653 | F: arch/arm/plat-*/ | 653 | F: arch/arm/plat-*/ |
654 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git | 654 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git |
@@ -1351,6 +1351,14 @@ W: http://wireless.kernel.org/en/users/Drivers/ath9k | |||
1351 | S: Supported | 1351 | S: Supported |
1352 | F: drivers/net/wireless/ath/ath9k/ | 1352 | F: drivers/net/wireless/ath/ath9k/ |
1353 | 1353 | ||
1354 | WILOCITY WIL6210 WIRELESS DRIVER | ||
1355 | M: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com> | ||
1356 | L: linux-wireless@vger.kernel.org | ||
1357 | L: wil6210@qca.qualcomm.com | ||
1358 | S: Supported | ||
1359 | W: http://wireless.kernel.org/en/users/Drivers/wil6210 | ||
1360 | F: drivers/net/wireless/ath/wil6210/ | ||
1361 | |||
1354 | CARL9170 LINUX COMMUNITY WIRELESS DRIVER | 1362 | CARL9170 LINUX COMMUNITY WIRELESS DRIVER |
1355 | M: Christian Lamparter <chunkeey@googlemail.com> | 1363 | M: Christian Lamparter <chunkeey@googlemail.com> |
1356 | L: linux-wireless@vger.kernel.org | 1364 | L: linux-wireless@vger.kernel.org |
@@ -1964,9 +1972,9 @@ S: Maintained | |||
1964 | F: drivers/usb/host/ohci-ep93xx.c | 1972 | F: drivers/usb/host/ohci-ep93xx.c |
1965 | 1973 | ||
1966 | CIRRUS LOGIC CS4270 SOUND DRIVER | 1974 | CIRRUS LOGIC CS4270 SOUND DRIVER |
1967 | M: Timur Tabi <timur@freescale.com> | 1975 | M: Timur Tabi <timur@tabi.org> |
1968 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) | 1976 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) |
1969 | S: Supported | 1977 | S: Odd Fixes |
1970 | F: sound/soc/codecs/cs4270* | 1978 | F: sound/soc/codecs/cs4270* |
1971 | 1979 | ||
1972 | CLEANCACHE API | 1980 | CLEANCACHE API |
@@ -3183,9 +3191,9 @@ F: include/uapi/video/ | |||
3183 | F: include/uapi/linux/fb.h | 3191 | F: include/uapi/linux/fb.h |
3184 | 3192 | ||
3185 | FREESCALE DIU FRAMEBUFFER DRIVER | 3193 | FREESCALE DIU FRAMEBUFFER DRIVER |
3186 | M: Timur Tabi <timur@freescale.com> | 3194 | M: Timur Tabi <timur@tabi.org> |
3187 | L: linux-fbdev@vger.kernel.org | 3195 | L: linux-fbdev@vger.kernel.org |
3188 | S: Supported | 3196 | S: Maintained |
3189 | F: drivers/video/fsl-diu-fb.* | 3197 | F: drivers/video/fsl-diu-fb.* |
3190 | 3198 | ||
3191 | FREESCALE DMA DRIVER | 3199 | FREESCALE DMA DRIVER |
@@ -3220,9 +3228,8 @@ F: drivers/net/ethernet/freescale/fs_enet/ | |||
3220 | F: include/linux/fs_enet_pd.h | 3228 | F: include/linux/fs_enet_pd.h |
3221 | 3229 | ||
3222 | FREESCALE QUICC ENGINE LIBRARY | 3230 | FREESCALE QUICC ENGINE LIBRARY |
3223 | M: Timur Tabi <timur@freescale.com> | ||
3224 | L: linuxppc-dev@lists.ozlabs.org | 3231 | L: linuxppc-dev@lists.ozlabs.org |
3225 | S: Supported | 3232 | S: Orphan |
3226 | F: arch/powerpc/sysdev/qe_lib/ | 3233 | F: arch/powerpc/sysdev/qe_lib/ |
3227 | F: arch/powerpc/include/asm/*qe.h | 3234 | F: arch/powerpc/include/asm/*qe.h |
3228 | 3235 | ||
@@ -3241,16 +3248,16 @@ S: Maintained | |||
3241 | F: drivers/net/ethernet/freescale/ucc_geth* | 3248 | F: drivers/net/ethernet/freescale/ucc_geth* |
3242 | 3249 | ||
3243 | FREESCALE QUICC ENGINE UCC UART DRIVER | 3250 | FREESCALE QUICC ENGINE UCC UART DRIVER |
3244 | M: Timur Tabi <timur@freescale.com> | 3251 | M: Timur Tabi <timur@tabi.org> |
3245 | L: linuxppc-dev@lists.ozlabs.org | 3252 | L: linuxppc-dev@lists.ozlabs.org |
3246 | S: Supported | 3253 | S: Maintained |
3247 | F: drivers/tty/serial/ucc_uart.c | 3254 | F: drivers/tty/serial/ucc_uart.c |
3248 | 3255 | ||
3249 | FREESCALE SOC SOUND DRIVERS | 3256 | FREESCALE SOC SOUND DRIVERS |
3250 | M: Timur Tabi <timur@freescale.com> | 3257 | M: Timur Tabi <timur@tabi.org> |
3251 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) | 3258 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) |
3252 | L: linuxppc-dev@lists.ozlabs.org | 3259 | L: linuxppc-dev@lists.ozlabs.org |
3253 | S: Supported | 3260 | S: Maintained |
3254 | F: sound/soc/fsl/fsl* | 3261 | F: sound/soc/fsl/fsl* |
3255 | F: sound/soc/fsl/mpc8610_hpcd.c | 3262 | F: sound/soc/fsl/mpc8610_hpcd.c |
3256 | 3263 | ||
@@ -5077,7 +5084,7 @@ S: Maintained | |||
5077 | F: drivers/media/radio/radio-mr800.c | 5084 | F: drivers/media/radio/radio-mr800.c |
5078 | 5085 | ||
5079 | MSI LAPTOP SUPPORT | 5086 | MSI LAPTOP SUPPORT |
5080 | M: "Lee, Chun-Yi" <jlee@novell.com> | 5087 | M: "Lee, Chun-Yi" <jlee@suse.com> |
5081 | L: platform-driver-x86@vger.kernel.org | 5088 | L: platform-driver-x86@vger.kernel.org |
5082 | S: Maintained | 5089 | S: Maintained |
5083 | F: drivers/platform/x86/msi-laptop.c | 5090 | F: drivers/platform/x86/msi-laptop.c |
@@ -5507,8 +5514,7 @@ M: Benoît Cousson <b-cousson@ti.com> | |||
5507 | M: Paul Walmsley <paul@pwsan.com> | 5514 | M: Paul Walmsley <paul@pwsan.com> |
5508 | L: linux-omap@vger.kernel.org | 5515 | L: linux-omap@vger.kernel.org |
5509 | S: Maintained | 5516 | S: Maintained |
5510 | F: arch/arm/mach-omap2/omap_hwmod.c | 5517 | F: arch/arm/mach-omap2/omap_hwmod.* |
5511 | F: arch/arm/plat-omap/include/plat/omap_hwmod.h | ||
5512 | 5518 | ||
5513 | OMAP HWMOD DATA FOR OMAP4-BASED DEVICES | 5519 | OMAP HWMOD DATA FOR OMAP4-BASED DEVICES |
5514 | M: Benoît Cousson <b-cousson@ti.com> | 5520 | M: Benoît Cousson <b-cousson@ti.com> |
@@ -7334,7 +7340,7 @@ S: Odd Fixes | |||
7334 | F: drivers/staging/speakup/ | 7340 | F: drivers/staging/speakup/ |
7335 | 7341 | ||
7336 | STAGING - TI DSP BRIDGE DRIVERS | 7342 | STAGING - TI DSP BRIDGE DRIVERS |
7337 | M: Omar Ramirez Luna <omar.ramirez@ti.com> | 7343 | M: Omar Ramirez Luna <omar.ramirez@copitl.com> |
7338 | S: Odd Fixes | 7344 | S: Odd Fixes |
7339 | F: drivers/staging/tidspbridge/ | 7345 | F: drivers/staging/tidspbridge/ |
7340 | 7346 | ||
@@ -8526,7 +8532,7 @@ F: Documentation/x86/ | |||
8526 | F: arch/x86/ | 8532 | F: arch/x86/ |
8527 | 8533 | ||
8528 | X86 PLATFORM DRIVERS | 8534 | X86 PLATFORM DRIVERS |
8529 | M: Matthew Garrett <mjg@redhat.com> | 8535 | M: Matthew Garrett <matthew.garrett@nebula.com> |
8530 | L: platform-driver-x86@vger.kernel.org | 8536 | L: platform-driver-x86@vger.kernel.org |
8531 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86.git | 8537 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86.git |
8532 | S: Maintained | 8538 | S: Maintained |
@@ -1,7 +1,7 @@ | |||
1 | VERSION = 3 | 1 | VERSION = 3 |
2 | PATCHLEVEL = 8 | 2 | PATCHLEVEL = 8 |
3 | SUBLEVEL = 0 | 3 | SUBLEVEL = 0 |
4 | EXTRAVERSION = -rc3 | 4 | EXTRAVERSION = -rc4 |
5 | NAME = Terrified Chipmunk | 5 | NAME = Terrified Chipmunk |
6 | 6 | ||
7 | # *DOCUMENTATION* | 7 | # *DOCUMENTATION* |
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index e44da40d984f..5ebb44fe826a 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile | |||
@@ -155,6 +155,7 @@ dtb-$(CONFIG_ARCH_VT8500) += vt8500-bv07.dtb \ | |||
155 | dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb | 155 | dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb |
156 | 156 | ||
157 | targets += dtbs | 157 | targets += dtbs |
158 | targets += $(dtb-y) | ||
158 | endif | 159 | endif |
159 | 160 | ||
160 | # *.dtb used to be generated in the directory above. Clean out the | 161 | # *.dtb used to be generated in the directory above. Clean out the |
diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi index 68bccf41a2c6..cb7bcc51608d 100644 --- a/arch/arm/boot/dts/at91sam9260.dtsi +++ b/arch/arm/boot/dts/at91sam9260.dtsi | |||
@@ -306,6 +306,22 @@ | |||
306 | }; | 306 | }; |
307 | }; | 307 | }; |
308 | 308 | ||
309 | ssc0 { | ||
310 | pinctrl_ssc0_tx: ssc0_tx-0 { | ||
311 | atmel,pins = | ||
312 | <1 16 0x1 0x0 /* PB16 periph A */ | ||
313 | 1 17 0x1 0x0 /* PB17 periph A */ | ||
314 | 1 18 0x1 0x0>; /* PB18 periph A */ | ||
315 | }; | ||
316 | |||
317 | pinctrl_ssc0_rx: ssc0_rx-0 { | ||
318 | atmel,pins = | ||
319 | <1 19 0x1 0x0 /* PB19 periph A */ | ||
320 | 1 20 0x1 0x0 /* PB20 periph A */ | ||
321 | 1 21 0x1 0x0>; /* PB21 periph A */ | ||
322 | }; | ||
323 | }; | ||
324 | |||
309 | pioA: gpio@fffff400 { | 325 | pioA: gpio@fffff400 { |
310 | compatible = "atmel,at91rm9200-gpio"; | 326 | compatible = "atmel,at91rm9200-gpio"; |
311 | reg = <0xfffff400 0x200>; | 327 | reg = <0xfffff400 0x200>; |
@@ -450,6 +466,8 @@ | |||
450 | compatible = "atmel,at91rm9200-ssc"; | 466 | compatible = "atmel,at91rm9200-ssc"; |
451 | reg = <0xfffbc000 0x4000>; | 467 | reg = <0xfffbc000 0x4000>; |
452 | interrupts = <14 4 5>; | 468 | interrupts = <14 4 5>; |
469 | pinctrl-names = "default"; | ||
470 | pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>; | ||
453 | status = "disabled"; | 471 | status = "disabled"; |
454 | }; | 472 | }; |
455 | 473 | ||
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi index 32ec62cf5385..271d4de026e9 100644 --- a/arch/arm/boot/dts/at91sam9263.dtsi +++ b/arch/arm/boot/dts/at91sam9263.dtsi | |||
@@ -271,6 +271,38 @@ | |||
271 | }; | 271 | }; |
272 | }; | 272 | }; |
273 | 273 | ||
274 | ssc0 { | ||
275 | pinctrl_ssc0_tx: ssc0_tx-0 { | ||
276 | atmel,pins = | ||
277 | <1 0 0x2 0x0 /* PB0 periph B */ | ||
278 | 1 1 0x2 0x0 /* PB1 periph B */ | ||
279 | 1 2 0x2 0x0>; /* PB2 periph B */ | ||
280 | }; | ||
281 | |||
282 | pinctrl_ssc0_rx: ssc0_rx-0 { | ||
283 | atmel,pins = | ||
284 | <1 3 0x2 0x0 /* PB3 periph B */ | ||
285 | 1 4 0x2 0x0 /* PB4 periph B */ | ||
286 | 1 5 0x2 0x0>; /* PB5 periph B */ | ||
287 | }; | ||
288 | }; | ||
289 | |||
290 | ssc1 { | ||
291 | pinctrl_ssc1_tx: ssc1_tx-0 { | ||
292 | atmel,pins = | ||
293 | <1 6 0x1 0x0 /* PB6 periph A */ | ||
294 | 1 7 0x1 0x0 /* PB7 periph A */ | ||
295 | 1 8 0x1 0x0>; /* PB8 periph A */ | ||
296 | }; | ||
297 | |||
298 | pinctrl_ssc1_rx: ssc1_rx-0 { | ||
299 | atmel,pins = | ||
300 | <1 9 0x1 0x0 /* PB9 periph A */ | ||
301 | 1 10 0x1 0x0 /* PB10 periph A */ | ||
302 | 1 11 0x1 0x0>; /* PB11 periph A */ | ||
303 | }; | ||
304 | }; | ||
305 | |||
274 | pioA: gpio@fffff200 { | 306 | pioA: gpio@fffff200 { |
275 | compatible = "atmel,at91rm9200-gpio"; | 307 | compatible = "atmel,at91rm9200-gpio"; |
276 | reg = <0xfffff200 0x200>; | 308 | reg = <0xfffff200 0x200>; |
@@ -368,6 +400,8 @@ | |||
368 | compatible = "atmel,at91rm9200-ssc"; | 400 | compatible = "atmel,at91rm9200-ssc"; |
369 | reg = <0xfff98000 0x4000>; | 401 | reg = <0xfff98000 0x4000>; |
370 | interrupts = <16 4 5>; | 402 | interrupts = <16 4 5>; |
403 | pinctrl-names = "default"; | ||
404 | pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>; | ||
371 | status = "disabled"; | 405 | status = "disabled"; |
372 | }; | 406 | }; |
373 | 407 | ||
@@ -375,6 +409,8 @@ | |||
375 | compatible = "atmel,at91rm9200-ssc"; | 409 | compatible = "atmel,at91rm9200-ssc"; |
376 | reg = <0xfff9c000 0x4000>; | 410 | reg = <0xfff9c000 0x4000>; |
377 | interrupts = <17 4 5>; | 411 | interrupts = <17 4 5>; |
412 | pinctrl-names = "default"; | ||
413 | pinctrl-0 = <&pinctrl_ssc1_tx &pinctrl_ssc1_rx>; | ||
378 | status = "disabled"; | 414 | status = "disabled"; |
379 | }; | 415 | }; |
380 | 416 | ||
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi index 231858ffd850..6b1d4cab24c2 100644 --- a/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/at91sam9g45.dtsi | |||
@@ -290,6 +290,38 @@ | |||
290 | }; | 290 | }; |
291 | }; | 291 | }; |
292 | 292 | ||
293 | ssc0 { | ||
294 | pinctrl_ssc0_tx: ssc0_tx-0 { | ||
295 | atmel,pins = | ||
296 | <3 0 0x1 0x0 /* PD0 periph A */ | ||
297 | 3 1 0x1 0x0 /* PD1 periph A */ | ||
298 | 3 2 0x1 0x0>; /* PD2 periph A */ | ||
299 | }; | ||
300 | |||
301 | pinctrl_ssc0_rx: ssc0_rx-0 { | ||
302 | atmel,pins = | ||
303 | <3 3 0x1 0x0 /* PD3 periph A */ | ||
304 | 3 4 0x1 0x0 /* PD4 periph A */ | ||
305 | 3 5 0x1 0x0>; /* PD5 periph A */ | ||
306 | }; | ||
307 | }; | ||
308 | |||
309 | ssc1 { | ||
310 | pinctrl_ssc1_tx: ssc1_tx-0 { | ||
311 | atmel,pins = | ||
312 | <3 10 0x1 0x0 /* PD10 periph A */ | ||
313 | 3 11 0x1 0x0 /* PD11 periph A */ | ||
314 | 3 12 0x1 0x0>; /* PD12 periph A */ | ||
315 | }; | ||
316 | |||
317 | pinctrl_ssc1_rx: ssc1_rx-0 { | ||
318 | atmel,pins = | ||
319 | <3 13 0x1 0x0 /* PD13 periph A */ | ||
320 | 3 14 0x1 0x0 /* PD14 periph A */ | ||
321 | 3 15 0x1 0x0>; /* PD15 periph A */ | ||
322 | }; | ||
323 | }; | ||
324 | |||
293 | pioA: gpio@fffff200 { | 325 | pioA: gpio@fffff200 { |
294 | compatible = "atmel,at91rm9200-gpio"; | 326 | compatible = "atmel,at91rm9200-gpio"; |
295 | reg = <0xfffff200 0x200>; | 327 | reg = <0xfffff200 0x200>; |
@@ -425,6 +457,8 @@ | |||
425 | compatible = "atmel,at91sam9g45-ssc"; | 457 | compatible = "atmel,at91sam9g45-ssc"; |
426 | reg = <0xfff9c000 0x4000>; | 458 | reg = <0xfff9c000 0x4000>; |
427 | interrupts = <16 4 5>; | 459 | interrupts = <16 4 5>; |
460 | pinctrl-names = "default"; | ||
461 | pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>; | ||
428 | status = "disabled"; | 462 | status = "disabled"; |
429 | }; | 463 | }; |
430 | 464 | ||
@@ -432,6 +466,8 @@ | |||
432 | compatible = "atmel,at91sam9g45-ssc"; | 466 | compatible = "atmel,at91sam9g45-ssc"; |
433 | reg = <0xfffa0000 0x4000>; | 467 | reg = <0xfffa0000 0x4000>; |
434 | interrupts = <17 4 5>; | 468 | interrupts = <17 4 5>; |
469 | pinctrl-names = "default"; | ||
470 | pinctrl-0 = <&pinctrl_ssc1_tx &pinctrl_ssc1_rx>; | ||
435 | status = "disabled"; | 471 | status = "disabled"; |
436 | }; | 472 | }; |
437 | 473 | ||
diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi index e9efb34f4379..80e29c605d4e 100644 --- a/arch/arm/boot/dts/at91sam9n12.dtsi +++ b/arch/arm/boot/dts/at91sam9n12.dtsi | |||
@@ -28,6 +28,7 @@ | |||
28 | tcb1 = &tcb1; | 28 | tcb1 = &tcb1; |
29 | i2c0 = &i2c0; | 29 | i2c0 = &i2c0; |
30 | i2c1 = &i2c1; | 30 | i2c1 = &i2c1; |
31 | ssc0 = &ssc0; | ||
31 | }; | 32 | }; |
32 | cpus { | 33 | cpus { |
33 | cpu@0 { | 34 | cpu@0 { |
@@ -244,6 +245,22 @@ | |||
244 | }; | 245 | }; |
245 | }; | 246 | }; |
246 | 247 | ||
248 | ssc0 { | ||
249 | pinctrl_ssc0_tx: ssc0_tx-0 { | ||
250 | atmel,pins = | ||
251 | <0 24 0x2 0x0 /* PA24 periph B */ | ||
252 | 0 25 0x2 0x0 /* PA25 periph B */ | ||
253 | 0 26 0x2 0x0>; /* PA26 periph B */ | ||
254 | }; | ||
255 | |||
256 | pinctrl_ssc0_rx: ssc0_rx-0 { | ||
257 | atmel,pins = | ||
258 | <0 27 0x2 0x0 /* PA27 periph B */ | ||
259 | 0 28 0x2 0x0 /* PA28 periph B */ | ||
260 | 0 29 0x2 0x0>; /* PA29 periph B */ | ||
261 | }; | ||
262 | }; | ||
263 | |||
247 | pioA: gpio@fffff400 { | 264 | pioA: gpio@fffff400 { |
248 | compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; | 265 | compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; |
249 | reg = <0xfffff400 0x200>; | 266 | reg = <0xfffff400 0x200>; |
@@ -294,6 +311,15 @@ | |||
294 | status = "disabled"; | 311 | status = "disabled"; |
295 | }; | 312 | }; |
296 | 313 | ||
314 | ssc0: ssc@f0010000 { | ||
315 | compatible = "atmel,at91sam9g45-ssc"; | ||
316 | reg = <0xf0010000 0x4000>; | ||
317 | interrupts = <28 4 5>; | ||
318 | pinctrl-names = "default"; | ||
319 | pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>; | ||
320 | status = "disabled"; | ||
321 | }; | ||
322 | |||
297 | usart0: serial@f801c000 { | 323 | usart0: serial@f801c000 { |
298 | compatible = "atmel,at91sam9260-usart"; | 324 | compatible = "atmel,at91sam9260-usart"; |
299 | reg = <0xf801c000 0x4000>; | 325 | reg = <0xf801c000 0x4000>; |
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index 40ac3a4eb1ab..3a47cf952146 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi | |||
@@ -88,13 +88,6 @@ | |||
88 | interrupts = <1 4 7>; | 88 | interrupts = <1 4 7>; |
89 | }; | 89 | }; |
90 | 90 | ||
91 | ssc0: ssc@f0010000 { | ||
92 | compatible = "atmel,at91sam9g45-ssc"; | ||
93 | reg = <0xf0010000 0x4000>; | ||
94 | interrupts = <28 4 5>; | ||
95 | status = "disabled"; | ||
96 | }; | ||
97 | |||
98 | tcb0: timer@f8008000 { | 91 | tcb0: timer@f8008000 { |
99 | compatible = "atmel,at91sam9x5-tcb"; | 92 | compatible = "atmel,at91sam9x5-tcb"; |
100 | reg = <0xf8008000 0x100>; | 93 | reg = <0xf8008000 0x100>; |
@@ -290,6 +283,22 @@ | |||
290 | }; | 283 | }; |
291 | }; | 284 | }; |
292 | 285 | ||
286 | ssc0 { | ||
287 | pinctrl_ssc0_tx: ssc0_tx-0 { | ||
288 | atmel,pins = | ||
289 | <0 24 0x2 0x0 /* PA24 periph B */ | ||
290 | 0 25 0x2 0x0 /* PA25 periph B */ | ||
291 | 0 26 0x2 0x0>; /* PA26 periph B */ | ||
292 | }; | ||
293 | |||
294 | pinctrl_ssc0_rx: ssc0_rx-0 { | ||
295 | atmel,pins = | ||
296 | <0 27 0x2 0x0 /* PA27 periph B */ | ||
297 | 0 28 0x2 0x0 /* PA28 periph B */ | ||
298 | 0 29 0x2 0x0>; /* PA29 periph B */ | ||
299 | }; | ||
300 | }; | ||
301 | |||
293 | pioA: gpio@fffff400 { | 302 | pioA: gpio@fffff400 { |
294 | compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; | 303 | compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; |
295 | reg = <0xfffff400 0x200>; | 304 | reg = <0xfffff400 0x200>; |
@@ -333,6 +342,15 @@ | |||
333 | }; | 342 | }; |
334 | }; | 343 | }; |
335 | 344 | ||
345 | ssc0: ssc@f0010000 { | ||
346 | compatible = "atmel,at91sam9g45-ssc"; | ||
347 | reg = <0xf0010000 0x4000>; | ||
348 | interrupts = <28 4 5>; | ||
349 | pinctrl-names = "default"; | ||
350 | pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>; | ||
351 | status = "disabled"; | ||
352 | }; | ||
353 | |||
336 | mmc0: mmc@f0008000 { | 354 | mmc0: mmc@f0008000 { |
337 | compatible = "atmel,hsmci"; | 355 | compatible = "atmel,hsmci"; |
338 | reg = <0xf0008000 0x600>; | 356 | reg = <0xf0008000 0x600>; |
diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h b/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h index a611ad3153c7..b6132aa95dc0 100644 --- a/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h +++ b/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h | |||
@@ -463,6 +463,9 @@ | |||
463 | GPIO76_LCD_PCLK, \ | 463 | GPIO76_LCD_PCLK, \ |
464 | GPIO77_LCD_BIAS | 464 | GPIO77_LCD_BIAS |
465 | 465 | ||
466 | /* these enable a work-around for a hw bug in pxa27x during ac97 warm reset */ | ||
467 | #define GPIO113_AC97_nRESET_GPIO_HIGH MFP_CFG_OUT(GPIO113, AF0, DEFAULT) | ||
468 | #define GPIO95_AC97_nRESET_GPIO_HIGH MFP_CFG_OUT(GPIO95, AF0, DEFAULT) | ||
466 | 469 | ||
467 | extern int keypad_set_wake(unsigned int on); | 470 | extern int keypad_set_wake(unsigned int on); |
468 | #endif /* __ASM_ARCH_MFP_PXA27X_H */ | 471 | #endif /* __ASM_ARCH_MFP_PXA27X_H */ |
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 8047ee0effc5..616cb87b6179 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c | |||
@@ -47,9 +47,9 @@ void pxa27x_clear_otgph(void) | |||
47 | EXPORT_SYMBOL(pxa27x_clear_otgph); | 47 | EXPORT_SYMBOL(pxa27x_clear_otgph); |
48 | 48 | ||
49 | static unsigned long ac97_reset_config[] = { | 49 | static unsigned long ac97_reset_config[] = { |
50 | GPIO113_GPIO, | 50 | GPIO113_AC97_nRESET_GPIO_HIGH, |
51 | GPIO113_AC97_nRESET, | 51 | GPIO113_AC97_nRESET, |
52 | GPIO95_GPIO, | 52 | GPIO95_AC97_nRESET_GPIO_HIGH, |
53 | GPIO95_AC97_nRESET, | 53 | GPIO95_AC97_nRESET, |
54 | }; | 54 | }; |
55 | 55 | ||
diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile index 801e2d7fcbc6..32ac0aef0068 100644 --- a/arch/arm64/boot/dts/Makefile +++ b/arch/arm64/boot/dts/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | targets += dtbs | 1 | targets += dtbs |
2 | targets += $(dtb-y) | ||
2 | 3 | ||
3 | dtbs: $(addprefix $(obj)/, $(dtb-y)) | 4 | dtbs: $(addprefix $(obj)/, $(dtb-y)) |
4 | 5 | ||
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 64b133949502..e333a243bfcc 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h | |||
@@ -24,7 +24,8 @@ | |||
24 | /* | 24 | /* |
25 | * Software defined PTE bits definition. | 25 | * Software defined PTE bits definition. |
26 | */ | 26 | */ |
27 | #define PTE_VALID (_AT(pteval_t, 1) << 0) /* pte_present() check */ | 27 | #define PTE_VALID (_AT(pteval_t, 1) << 0) |
28 | #define PTE_PROT_NONE (_AT(pteval_t, 1) << 1) /* only when !PTE_VALID */ | ||
28 | #define PTE_FILE (_AT(pteval_t, 1) << 2) /* only when !pte_present() */ | 29 | #define PTE_FILE (_AT(pteval_t, 1) << 2) /* only when !pte_present() */ |
29 | #define PTE_DIRTY (_AT(pteval_t, 1) << 55) | 30 | #define PTE_DIRTY (_AT(pteval_t, 1) << 55) |
30 | #define PTE_SPECIAL (_AT(pteval_t, 1) << 56) | 31 | #define PTE_SPECIAL (_AT(pteval_t, 1) << 56) |
@@ -60,9 +61,12 @@ extern void __pgd_error(const char *file, int line, unsigned long val); | |||
60 | 61 | ||
61 | extern pgprot_t pgprot_default; | 62 | extern pgprot_t pgprot_default; |
62 | 63 | ||
63 | #define _MOD_PROT(p, b) __pgprot(pgprot_val(p) | (b)) | 64 | #define __pgprot_modify(prot,mask,bits) \ |
65 | __pgprot((pgprot_val(prot) & ~(mask)) | (bits)) | ||
66 | |||
67 | #define _MOD_PROT(p, b) __pgprot_modify(p, 0, b) | ||
64 | 68 | ||
65 | #define PAGE_NONE _MOD_PROT(pgprot_default, PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) | 69 | #define PAGE_NONE __pgprot_modify(pgprot_default, PTE_TYPE_MASK, PTE_PROT_NONE) |
66 | #define PAGE_SHARED _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) | 70 | #define PAGE_SHARED _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) |
67 | #define PAGE_SHARED_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN) | 71 | #define PAGE_SHARED_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN) |
68 | #define PAGE_COPY _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) | 72 | #define PAGE_COPY _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) |
@@ -72,7 +76,7 @@ extern pgprot_t pgprot_default; | |||
72 | #define PAGE_KERNEL _MOD_PROT(pgprot_default, PTE_PXN | PTE_UXN | PTE_DIRTY) | 76 | #define PAGE_KERNEL _MOD_PROT(pgprot_default, PTE_PXN | PTE_UXN | PTE_DIRTY) |
73 | #define PAGE_KERNEL_EXEC _MOD_PROT(pgprot_default, PTE_UXN | PTE_DIRTY) | 77 | #define PAGE_KERNEL_EXEC _MOD_PROT(pgprot_default, PTE_UXN | PTE_DIRTY) |
74 | 78 | ||
75 | #define __PAGE_NONE __pgprot(_PAGE_DEFAULT | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) | 79 | #define __PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_TYPE_MASK) | PTE_PROT_NONE) |
76 | #define __PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) | 80 | #define __PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) |
77 | #define __PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN) | 81 | #define __PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN) |
78 | #define __PAGE_COPY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) | 82 | #define __PAGE_COPY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY) |
@@ -125,16 +129,15 @@ extern struct page *empty_zero_page; | |||
125 | /* | 129 | /* |
126 | * The following only work if pte_present(). Undefined behaviour otherwise. | 130 | * The following only work if pte_present(). Undefined behaviour otherwise. |
127 | */ | 131 | */ |
128 | #define pte_present(pte) (pte_val(pte) & PTE_VALID) | 132 | #define pte_present(pte) (pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)) |
129 | #define pte_dirty(pte) (pte_val(pte) & PTE_DIRTY) | 133 | #define pte_dirty(pte) (pte_val(pte) & PTE_DIRTY) |
130 | #define pte_young(pte) (pte_val(pte) & PTE_AF) | 134 | #define pte_young(pte) (pte_val(pte) & PTE_AF) |
131 | #define pte_special(pte) (pte_val(pte) & PTE_SPECIAL) | 135 | #define pte_special(pte) (pte_val(pte) & PTE_SPECIAL) |
132 | #define pte_write(pte) (!(pte_val(pte) & PTE_RDONLY)) | 136 | #define pte_write(pte) (!(pte_val(pte) & PTE_RDONLY)) |
133 | #define pte_exec(pte) (!(pte_val(pte) & PTE_UXN)) | 137 | #define pte_exec(pte) (!(pte_val(pte) & PTE_UXN)) |
134 | 138 | ||
135 | #define pte_present_exec_user(pte) \ | 139 | #define pte_valid_user(pte) \ |
136 | ((pte_val(pte) & (PTE_VALID | PTE_USER | PTE_UXN)) == \ | 140 | ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER)) |
137 | (PTE_VALID | PTE_USER)) | ||
138 | 141 | ||
139 | #define PTE_BIT_FUNC(fn,op) \ | 142 | #define PTE_BIT_FUNC(fn,op) \ |
140 | static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; } | 143 | static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; } |
@@ -157,10 +160,13 @@ extern void __sync_icache_dcache(pte_t pteval, unsigned long addr); | |||
157 | static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, | 160 | static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, |
158 | pte_t *ptep, pte_t pte) | 161 | pte_t *ptep, pte_t pte) |
159 | { | 162 | { |
160 | if (pte_present_exec_user(pte)) | 163 | if (pte_valid_user(pte)) { |
161 | __sync_icache_dcache(pte, addr); | 164 | if (pte_exec(pte)) |
162 | if (!pte_dirty(pte)) | 165 | __sync_icache_dcache(pte, addr); |
163 | pte = pte_wrprotect(pte); | 166 | if (!pte_dirty(pte)) |
167 | pte = pte_wrprotect(pte); | ||
168 | } | ||
169 | |||
164 | set_pte(ptep, pte); | 170 | set_pte(ptep, pte); |
165 | } | 171 | } |
166 | 172 | ||
@@ -170,9 +176,6 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, | |||
170 | #define pte_huge(pte) ((pte_val(pte) & PTE_TYPE_MASK) == PTE_TYPE_HUGEPAGE) | 176 | #define pte_huge(pte) ((pte_val(pte) & PTE_TYPE_MASK) == PTE_TYPE_HUGEPAGE) |
171 | #define pte_mkhuge(pte) (__pte((pte_val(pte) & ~PTE_TYPE_MASK) | PTE_TYPE_HUGEPAGE)) | 177 | #define pte_mkhuge(pte) (__pte((pte_val(pte) & ~PTE_TYPE_MASK) | PTE_TYPE_HUGEPAGE)) |
172 | 178 | ||
173 | #define __pgprot_modify(prot,mask,bits) \ | ||
174 | __pgprot((pgprot_val(prot) & ~(mask)) | (bits)) | ||
175 | |||
176 | #define __HAVE_ARCH_PTE_SPECIAL | 179 | #define __HAVE_ARCH_PTE_SPECIAL |
177 | 180 | ||
178 | /* | 181 | /* |
@@ -264,7 +267,8 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr) | |||
264 | 267 | ||
265 | static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) | 268 | static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) |
266 | { | 269 | { |
267 | const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY; | 270 | const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY | |
271 | PTE_PROT_NONE | PTE_VALID; | ||
268 | pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask); | 272 | pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask); |
269 | return pte; | 273 | return pte; |
270 | } | 274 | } |
diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h index 58432625fdb3..5ef47ba3ed45 100644 --- a/arch/arm64/include/asm/unistd32.h +++ b/arch/arm64/include/asm/unistd32.h | |||
@@ -395,8 +395,13 @@ __SYSCALL(370, sys_name_to_handle_at) | |||
395 | __SYSCALL(371, compat_sys_open_by_handle_at) | 395 | __SYSCALL(371, compat_sys_open_by_handle_at) |
396 | __SYSCALL(372, compat_sys_clock_adjtime) | 396 | __SYSCALL(372, compat_sys_clock_adjtime) |
397 | __SYSCALL(373, sys_syncfs) | 397 | __SYSCALL(373, sys_syncfs) |
398 | __SYSCALL(374, compat_sys_sendmmsg) | ||
399 | __SYSCALL(375, sys_setns) | ||
400 | __SYSCALL(376, compat_sys_process_vm_readv) | ||
401 | __SYSCALL(377, compat_sys_process_vm_writev) | ||
402 | __SYSCALL(378, sys_ni_syscall) /* 378 for kcmp */ | ||
398 | 403 | ||
399 | #define __NR_compat_syscalls 374 | 404 | #define __NR_compat_syscalls 379 |
400 | 405 | ||
401 | /* | 406 | /* |
402 | * Compat syscall numbers used by the AArch64 kernel. | 407 | * Compat syscall numbers used by the AArch64 kernel. |
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c index c958cb84d75f..6a389dc1bd49 100644 --- a/arch/arm64/kernel/vdso.c +++ b/arch/arm64/kernel/vdso.c | |||
@@ -252,10 +252,6 @@ void update_vsyscall(struct timekeeper *tk) | |||
252 | 252 | ||
253 | void update_vsyscall_tz(void) | 253 | void update_vsyscall_tz(void) |
254 | { | 254 | { |
255 | ++vdso_data->tb_seq_count; | ||
256 | smp_wmb(); | ||
257 | vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; | 255 | vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; |
258 | vdso_data->tz_dsttime = sys_tz.tz_dsttime; | 256 | vdso_data->tz_dsttime = sys_tz.tz_dsttime; |
259 | smp_wmb(); | ||
260 | ++vdso_data->tb_seq_count; | ||
261 | } | 257 | } |
diff --git a/arch/arm64/kernel/vdso/gettimeofday.S b/arch/arm64/kernel/vdso/gettimeofday.S index 8bf658d974f9..f0a6d10b5211 100644 --- a/arch/arm64/kernel/vdso/gettimeofday.S +++ b/arch/arm64/kernel/vdso/gettimeofday.S | |||
@@ -73,8 +73,6 @@ ENTRY(__kernel_gettimeofday) | |||
73 | /* If tz is NULL, return 0. */ | 73 | /* If tz is NULL, return 0. */ |
74 | cbz x1, 3f | 74 | cbz x1, 3f |
75 | ldp w4, w5, [vdso_data, #VDSO_TZ_MINWEST] | 75 | ldp w4, w5, [vdso_data, #VDSO_TZ_MINWEST] |
76 | seqcnt_read w9 | ||
77 | seqcnt_check w9, 1b | ||
78 | stp w4, w5, [x1, #TZ_MINWEST] | 76 | stp w4, w5, [x1, #TZ_MINWEST] |
79 | 3: | 77 | 3: |
80 | mov x0, xzr | 78 | mov x0, xzr |
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig index aa03f2e13385..e70001cfa05b 100644 --- a/arch/mn10300/Kconfig +++ b/arch/mn10300/Kconfig | |||
@@ -6,6 +6,7 @@ config MN10300 | |||
6 | select ARCH_WANT_IPC_PARSE_VERSION | 6 | select ARCH_WANT_IPC_PARSE_VERSION |
7 | select HAVE_ARCH_TRACEHOOK | 7 | select HAVE_ARCH_TRACEHOOK |
8 | select HAVE_ARCH_KGDB | 8 | select HAVE_ARCH_KGDB |
9 | select GENERIC_ATOMIC64 | ||
9 | select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER | 10 | select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER |
10 | select GENERIC_CLOCKEVENTS | 11 | select GENERIC_CLOCKEVENTS |
11 | select MODULES_USE_ELF_RELA | 12 | select MODULES_USE_ELF_RELA |
diff --git a/arch/powerpc/include/uapi/asm/kvm_para.h b/arch/powerpc/include/uapi/asm/kvm_para.h index ed0e0254b47f..e3af3286a068 100644 --- a/arch/powerpc/include/uapi/asm/kvm_para.h +++ b/arch/powerpc/include/uapi/asm/kvm_para.h | |||
@@ -78,7 +78,7 @@ struct kvm_vcpu_arch_shared { | |||
78 | 78 | ||
79 | #define KVM_HCALL_TOKEN(num) _EV_HCALL_TOKEN(EV_KVM_VENDOR_ID, num) | 79 | #define KVM_HCALL_TOKEN(num) _EV_HCALL_TOKEN(EV_KVM_VENDOR_ID, num) |
80 | 80 | ||
81 | #include <uapi/asm/epapr_hcalls.h> | 81 | #include <asm/epapr_hcalls.h> |
82 | 82 | ||
83 | #define KVM_FEATURE_MAGIC_PAGE 1 | 83 | #define KVM_FEATURE_MAGIC_PAGE 1 |
84 | 84 | ||
diff --git a/arch/powerpc/kvm/book3s_hv_ras.c b/arch/powerpc/kvm/book3s_hv_ras.c index 35f3cf0269b3..a353c485808c 100644 --- a/arch/powerpc/kvm/book3s_hv_ras.c +++ b/arch/powerpc/kvm/book3s_hv_ras.c | |||
@@ -79,7 +79,9 @@ static void flush_tlb_power7(struct kvm_vcpu *vcpu) | |||
79 | static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) | 79 | static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) |
80 | { | 80 | { |
81 | unsigned long srr1 = vcpu->arch.shregs.msr; | 81 | unsigned long srr1 = vcpu->arch.shregs.msr; |
82 | #ifdef CONFIG_PPC_POWERNV | ||
82 | struct opal_machine_check_event *opal_evt; | 83 | struct opal_machine_check_event *opal_evt; |
84 | #endif | ||
83 | long handled = 1; | 85 | long handled = 1; |
84 | 86 | ||
85 | if (srr1 & SRR1_MC_LDSTERR) { | 87 | if (srr1 & SRR1_MC_LDSTERR) { |
@@ -117,6 +119,7 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) | |||
117 | handled = 0; | 119 | handled = 0; |
118 | } | 120 | } |
119 | 121 | ||
122 | #ifdef CONFIG_PPC_POWERNV | ||
120 | /* | 123 | /* |
121 | * See if OPAL has already handled the condition. | 124 | * See if OPAL has already handled the condition. |
122 | * We assume that if the condition is recovered then OPAL | 125 | * We assume that if the condition is recovered then OPAL |
@@ -131,6 +134,7 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) | |||
131 | 134 | ||
132 | if (handled) | 135 | if (handled) |
133 | opal_evt->in_use = 0; | 136 | opal_evt->in_use = 0; |
137 | #endif | ||
134 | 138 | ||
135 | return handled; | 139 | return handled; |
136 | } | 140 | } |
diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 4b8e08b56f49..7e3ce78d4290 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile | |||
@@ -24,8 +24,8 @@ CHECKFLAGS += -D__s390__ -msize-long | |||
24 | else | 24 | else |
25 | LD_BFD := elf64-s390 | 25 | LD_BFD := elf64-s390 |
26 | LDFLAGS := -m elf64_s390 | 26 | LDFLAGS := -m elf64_s390 |
27 | KBUILD_AFLAGS_MODULE += -fpic -D__PIC__ | 27 | KBUILD_AFLAGS_MODULE += -fPIC |
28 | KBUILD_CFLAGS_MODULE += -fpic -D__PIC__ | 28 | KBUILD_CFLAGS_MODULE += -fPIC |
29 | KBUILD_CFLAGS += -m64 | 29 | KBUILD_CFLAGS += -m64 |
30 | KBUILD_AFLAGS += -m64 | 30 | KBUILD_AFLAGS += -m64 |
31 | UTS_MACHINE := s390x | 31 | UTS_MACHINE := s390x |
diff --git a/arch/s390/include/asm/dma.h b/arch/s390/include/asm/dma.h index de015d85e3e5..bb9bdcd20864 100644 --- a/arch/s390/include/asm/dma.h +++ b/arch/s390/include/asm/dma.h | |||
@@ -10,4 +10,10 @@ | |||
10 | */ | 10 | */ |
11 | #define MAX_DMA_ADDRESS 0x80000000 | 11 | #define MAX_DMA_ADDRESS 0x80000000 |
12 | 12 | ||
13 | #ifdef CONFIG_PCI | ||
14 | extern int isa_dma_bridge_buggy; | ||
15 | #else | ||
16 | #define isa_dma_bridge_buggy (0) | ||
17 | #endif | ||
18 | |||
13 | #endif /* _ASM_S390_DMA_H */ | 19 | #endif /* _ASM_S390_DMA_H */ |
diff --git a/arch/s390/include/asm/io.h b/arch/s390/include/asm/io.h index 16c3eb164f4f..27cb32185ce1 100644 --- a/arch/s390/include/asm/io.h +++ b/arch/s390/include/asm/io.h | |||
@@ -85,6 +85,11 @@ static inline void iounmap(volatile void __iomem *addr) | |||
85 | #define __raw_writel zpci_write_u32 | 85 | #define __raw_writel zpci_write_u32 |
86 | #define __raw_writeq zpci_write_u64 | 86 | #define __raw_writeq zpci_write_u64 |
87 | 87 | ||
88 | #define readb_relaxed readb | ||
89 | #define readw_relaxed readw | ||
90 | #define readl_relaxed readl | ||
91 | #define readq_relaxed readq | ||
92 | |||
88 | #endif /* CONFIG_PCI */ | 93 | #endif /* CONFIG_PCI */ |
89 | 94 | ||
90 | #include <asm-generic/io.h> | 95 | #include <asm-generic/io.h> |
diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index e6972f85d2b0..7def77302d63 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h | |||
@@ -2,43 +2,61 @@ | |||
2 | #define _ASM_IRQ_H | 2 | #define _ASM_IRQ_H |
3 | 3 | ||
4 | #include <linux/hardirq.h> | 4 | #include <linux/hardirq.h> |
5 | #include <linux/percpu.h> | ||
6 | #include <linux/cache.h> | ||
5 | #include <linux/types.h> | 7 | #include <linux/types.h> |
6 | 8 | ||
7 | enum interruption_class { | 9 | enum interruption_main_class { |
8 | EXTERNAL_INTERRUPT, | 10 | EXTERNAL_INTERRUPT, |
9 | IO_INTERRUPT, | 11 | IO_INTERRUPT, |
10 | EXTINT_CLK, | 12 | NR_IRQS |
11 | EXTINT_EXC, | 13 | }; |
12 | EXTINT_EMS, | 14 | |
13 | EXTINT_TMR, | 15 | enum interruption_class { |
14 | EXTINT_TLA, | 16 | IRQEXT_CLK, |
15 | EXTINT_PFL, | 17 | IRQEXT_EXC, |
16 | EXTINT_DSD, | 18 | IRQEXT_EMS, |
17 | EXTINT_VRT, | 19 | IRQEXT_TMR, |
18 | EXTINT_SCP, | 20 | IRQEXT_TLA, |
19 | EXTINT_IUC, | 21 | IRQEXT_PFL, |
20 | EXTINT_CMS, | 22 | IRQEXT_DSD, |
21 | EXTINT_CMC, | 23 | IRQEXT_VRT, |
22 | EXTINT_CMR, | 24 | IRQEXT_SCP, |
23 | IOINT_CIO, | 25 | IRQEXT_IUC, |
24 | IOINT_QAI, | 26 | IRQEXT_CMS, |
25 | IOINT_DAS, | 27 | IRQEXT_CMC, |
26 | IOINT_C15, | 28 | IRQEXT_CMR, |
27 | IOINT_C70, | 29 | IRQIO_CIO, |
28 | IOINT_TAP, | 30 | IRQIO_QAI, |
29 | IOINT_VMR, | 31 | IRQIO_DAS, |
30 | IOINT_LCS, | 32 | IRQIO_C15, |
31 | IOINT_CLW, | 33 | IRQIO_C70, |
32 | IOINT_CTC, | 34 | IRQIO_TAP, |
33 | IOINT_APB, | 35 | IRQIO_VMR, |
34 | IOINT_ADM, | 36 | IRQIO_LCS, |
35 | IOINT_CSC, | 37 | IRQIO_CLW, |
36 | IOINT_PCI, | 38 | IRQIO_CTC, |
37 | IOINT_MSI, | 39 | IRQIO_APB, |
40 | IRQIO_ADM, | ||
41 | IRQIO_CSC, | ||
42 | IRQIO_PCI, | ||
43 | IRQIO_MSI, | ||
38 | NMI_NMI, | 44 | NMI_NMI, |
39 | NR_IRQS, | 45 | CPU_RST, |
46 | NR_ARCH_IRQS | ||
40 | }; | 47 | }; |
41 | 48 | ||
49 | struct irq_stat { | ||
50 | unsigned int irqs[NR_ARCH_IRQS]; | ||
51 | }; | ||
52 | |||
53 | DECLARE_PER_CPU_SHARED_ALIGNED(struct irq_stat, irq_stat); | ||
54 | |||
55 | static __always_inline void inc_irq_stat(enum interruption_class irq) | ||
56 | { | ||
57 | __get_cpu_var(irq_stat).irqs[irq]++; | ||
58 | } | ||
59 | |||
42 | struct ext_code { | 60 | struct ext_code { |
43 | unsigned short subcode; | 61 | unsigned short subcode; |
44 | unsigned short code; | 62 | unsigned short code; |
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index c928dc1938f2..c1d7930a82f4 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
@@ -1387,10 +1387,7 @@ static inline int has_transparent_hugepage(void) | |||
1387 | 1387 | ||
1388 | static inline unsigned long pmd_pfn(pmd_t pmd) | 1388 | static inline unsigned long pmd_pfn(pmd_t pmd) |
1389 | { | 1389 | { |
1390 | if (pmd_trans_huge(pmd)) | 1390 | return pmd_val(pmd) >> PAGE_SHIFT; |
1391 | return pmd_val(pmd) >> HPAGE_SHIFT; | ||
1392 | else | ||
1393 | return pmd_val(pmd) >> PAGE_SHIFT; | ||
1394 | } | 1391 | } |
1395 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ | 1392 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ |
1396 | 1393 | ||
diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h index fba4d66788a2..4c060bb5b8ea 100644 --- a/arch/s390/include/asm/timex.h +++ b/arch/s390/include/asm/timex.h | |||
@@ -128,4 +128,32 @@ static inline unsigned long long get_clock_monotonic(void) | |||
128 | return get_clock_xt() - sched_clock_base_cc; | 128 | return get_clock_xt() - sched_clock_base_cc; |
129 | } | 129 | } |
130 | 130 | ||
131 | /** | ||
132 | * tod_to_ns - convert a TOD format value to nanoseconds | ||
133 | * @todval: to be converted TOD format value | ||
134 | * Returns: number of nanoseconds that correspond to the TOD format value | ||
135 | * | ||
136 | * Converting a 64 Bit TOD format value to nanoseconds means that the value | ||
137 | * must be divided by 4.096. In order to achieve that we multiply with 125 | ||
138 | * and divide by 512: | ||
139 | * | ||
140 | * ns = (todval * 125) >> 9; | ||
141 | * | ||
142 | * In order to avoid an overflow with the multiplication we can rewrite this. | ||
143 | * With a split todval == 2^32 * th + tl (th upper 32 bits, tl lower 32 bits) | ||
144 | * we end up with | ||
145 | * | ||
146 | * ns = ((2^32 * th + tl) * 125 ) >> 9; | ||
147 | * -> ns = (2^23 * th * 125) + ((tl * 125) >> 9); | ||
148 | * | ||
149 | */ | ||
150 | static inline unsigned long long tod_to_ns(unsigned long long todval) | ||
151 | { | ||
152 | unsigned long long ns; | ||
153 | |||
154 | ns = ((todval >> 32) << 23) * 125; | ||
155 | ns += ((todval & 0xffffffff) * 125) >> 9; | ||
156 | return ns; | ||
157 | } | ||
158 | |||
131 | #endif | 159 | #endif |
diff --git a/arch/s390/include/uapi/asm/unistd.h b/arch/s390/include/uapi/asm/unistd.h index 63e6078699f1..864f693c237f 100644 --- a/arch/s390/include/uapi/asm/unistd.h +++ b/arch/s390/include/uapi/asm/unistd.h | |||
@@ -279,7 +279,8 @@ | |||
279 | #define __NR_process_vm_writev 341 | 279 | #define __NR_process_vm_writev 341 |
280 | #define __NR_s390_runtime_instr 342 | 280 | #define __NR_s390_runtime_instr 342 |
281 | #define __NR_kcmp 343 | 281 | #define __NR_kcmp 343 |
282 | #define NR_syscalls 344 | 282 | #define __NR_finit_module 344 |
283 | #define NR_syscalls 345 | ||
283 | 284 | ||
284 | /* | 285 | /* |
285 | * There are some system calls that are not present on 64 bit, some | 286 | * There are some system calls that are not present on 64 bit, some |
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 827e094a2f49..9b9a805656b5 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S | |||
@@ -1659,3 +1659,9 @@ ENTRY(sys_kcmp_wrapper) | |||
1659 | llgfr %r5,%r5 # unsigned long | 1659 | llgfr %r5,%r5 # unsigned long |
1660 | llgfr %r6,%r6 # unsigned long | 1660 | llgfr %r6,%r6 # unsigned long |
1661 | jg sys_kcmp | 1661 | jg sys_kcmp |
1662 | |||
1663 | ENTRY(sys_finit_module_wrapper) | ||
1664 | lgfr %r2,%r2 # int | ||
1665 | llgtr %r3,%r3 # const char __user * | ||
1666 | lgfr %r4,%r4 # int | ||
1667 | jg sys_finit_module | ||
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index ba500d8dc392..4e8215e0d4b6 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c | |||
@@ -1127,13 +1127,14 @@ debug_register_view(debug_info_t * id, struct debug_view *view) | |||
1127 | if (i == DEBUG_MAX_VIEWS) { | 1127 | if (i == DEBUG_MAX_VIEWS) { |
1128 | pr_err("Registering view %s/%s would exceed the maximum " | 1128 | pr_err("Registering view %s/%s would exceed the maximum " |
1129 | "number of views %i\n", id->name, view->name, i); | 1129 | "number of views %i\n", id->name, view->name, i); |
1130 | debugfs_remove(pde); | ||
1131 | rc = -1; | 1130 | rc = -1; |
1132 | } else { | 1131 | } else { |
1133 | id->views[i] = view; | 1132 | id->views[i] = view; |
1134 | id->debugfs_entries[i] = pde; | 1133 | id->debugfs_entries[i] = pde; |
1135 | } | 1134 | } |
1136 | spin_unlock_irqrestore(&id->lock, flags); | 1135 | spin_unlock_irqrestore(&id->lock, flags); |
1136 | if (rc) | ||
1137 | debugfs_remove(pde); | ||
1137 | out: | 1138 | out: |
1138 | return rc; | 1139 | return rc; |
1139 | } | 1140 | } |
@@ -1146,9 +1147,9 @@ EXPORT_SYMBOL(debug_register_view); | |||
1146 | int | 1147 | int |
1147 | debug_unregister_view(debug_info_t * id, struct debug_view *view) | 1148 | debug_unregister_view(debug_info_t * id, struct debug_view *view) |
1148 | { | 1149 | { |
1149 | int rc = 0; | 1150 | struct dentry *dentry = NULL; |
1150 | int i; | ||
1151 | unsigned long flags; | 1151 | unsigned long flags; |
1152 | int i, rc = 0; | ||
1152 | 1153 | ||
1153 | if (!id) | 1154 | if (!id) |
1154 | goto out; | 1155 | goto out; |
@@ -1160,10 +1161,12 @@ debug_unregister_view(debug_info_t * id, struct debug_view *view) | |||
1160 | if (i == DEBUG_MAX_VIEWS) | 1161 | if (i == DEBUG_MAX_VIEWS) |
1161 | rc = -1; | 1162 | rc = -1; |
1162 | else { | 1163 | else { |
1163 | debugfs_remove(id->debugfs_entries[i]); | 1164 | dentry = id->debugfs_entries[i]; |
1164 | id->views[i] = NULL; | 1165 | id->views[i] = NULL; |
1166 | id->debugfs_entries[i] = NULL; | ||
1165 | } | 1167 | } |
1166 | spin_unlock_irqrestore(&id->lock, flags); | 1168 | spin_unlock_irqrestore(&id->lock, flags); |
1169 | debugfs_remove(dentry); | ||
1167 | out: | 1170 | out: |
1168 | return rc; | 1171 | return rc; |
1169 | } | 1172 | } |
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index bf24293970ce..9df824ea1667 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c | |||
@@ -24,43 +24,65 @@ | |||
24 | #include <asm/irq.h> | 24 | #include <asm/irq.h> |
25 | #include "entry.h" | 25 | #include "entry.h" |
26 | 26 | ||
27 | DEFINE_PER_CPU_SHARED_ALIGNED(struct irq_stat, irq_stat); | ||
28 | EXPORT_PER_CPU_SYMBOL_GPL(irq_stat); | ||
29 | |||
27 | struct irq_class { | 30 | struct irq_class { |
28 | char *name; | 31 | char *name; |
29 | char *desc; | 32 | char *desc; |
30 | }; | 33 | }; |
31 | 34 | ||
32 | static const struct irq_class intrclass_names[] = { | 35 | /* |
36 | * The list of "main" irq classes on s390. This is the list of interrrupts | ||
37 | * that appear both in /proc/stat ("intr" line) and /proc/interrupts. | ||
38 | * Historically only external and I/O interrupts have been part of /proc/stat. | ||
39 | * We can't add the split external and I/O sub classes since the first field | ||
40 | * in the "intr" line in /proc/stat is supposed to be the sum of all other | ||
41 | * fields. | ||
42 | * Since the external and I/O interrupt fields are already sums we would end | ||
43 | * up with having a sum which accounts each interrupt twice. | ||
44 | */ | ||
45 | static const struct irq_class irqclass_main_desc[NR_IRQS] = { | ||
33 | [EXTERNAL_INTERRUPT] = {.name = "EXT"}, | 46 | [EXTERNAL_INTERRUPT] = {.name = "EXT"}, |
34 | [IO_INTERRUPT] = {.name = "I/O"}, | 47 | [IO_INTERRUPT] = {.name = "I/O"} |
35 | [EXTINT_CLK] = {.name = "CLK", .desc = "[EXT] Clock Comparator"}, | 48 | }; |
36 | [EXTINT_EXC] = {.name = "EXC", .desc = "[EXT] External Call"}, | 49 | |
37 | [EXTINT_EMS] = {.name = "EMS", .desc = "[EXT] Emergency Signal"}, | 50 | /* |
38 | [EXTINT_TMR] = {.name = "TMR", .desc = "[EXT] CPU Timer"}, | 51 | * The list of split external and I/O interrupts that appear only in |
39 | [EXTINT_TLA] = {.name = "TAL", .desc = "[EXT] Timing Alert"}, | 52 | * /proc/interrupts. |
40 | [EXTINT_PFL] = {.name = "PFL", .desc = "[EXT] Pseudo Page Fault"}, | 53 | * In addition this list contains non external / I/O events like NMIs. |
41 | [EXTINT_DSD] = {.name = "DSD", .desc = "[EXT] DASD Diag"}, | 54 | */ |
42 | [EXTINT_VRT] = {.name = "VRT", .desc = "[EXT] Virtio"}, | 55 | static const struct irq_class irqclass_sub_desc[NR_ARCH_IRQS] = { |
43 | [EXTINT_SCP] = {.name = "SCP", .desc = "[EXT] Service Call"}, | 56 | [IRQEXT_CLK] = {.name = "CLK", .desc = "[EXT] Clock Comparator"}, |
44 | [EXTINT_IUC] = {.name = "IUC", .desc = "[EXT] IUCV"}, | 57 | [IRQEXT_EXC] = {.name = "EXC", .desc = "[EXT] External Call"}, |
45 | [EXTINT_CMS] = {.name = "CMS", .desc = "[EXT] CPU-Measurement: Sampling"}, | 58 | [IRQEXT_EMS] = {.name = "EMS", .desc = "[EXT] Emergency Signal"}, |
46 | [EXTINT_CMC] = {.name = "CMC", .desc = "[EXT] CPU-Measurement: Counter"}, | 59 | [IRQEXT_TMR] = {.name = "TMR", .desc = "[EXT] CPU Timer"}, |
47 | [EXTINT_CMR] = {.name = "CMR", .desc = "[EXT] CPU-Measurement: RI"}, | 60 | [IRQEXT_TLA] = {.name = "TAL", .desc = "[EXT] Timing Alert"}, |
48 | [IOINT_CIO] = {.name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt"}, | 61 | [IRQEXT_PFL] = {.name = "PFL", .desc = "[EXT] Pseudo Page Fault"}, |
49 | [IOINT_QAI] = {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt"}, | 62 | [IRQEXT_DSD] = {.name = "DSD", .desc = "[EXT] DASD Diag"}, |
50 | [IOINT_DAS] = {.name = "DAS", .desc = "[I/O] DASD"}, | 63 | [IRQEXT_VRT] = {.name = "VRT", .desc = "[EXT] Virtio"}, |
51 | [IOINT_C15] = {.name = "C15", .desc = "[I/O] 3215"}, | 64 | [IRQEXT_SCP] = {.name = "SCP", .desc = "[EXT] Service Call"}, |
52 | [IOINT_C70] = {.name = "C70", .desc = "[I/O] 3270"}, | 65 | [IRQEXT_IUC] = {.name = "IUC", .desc = "[EXT] IUCV"}, |
53 | [IOINT_TAP] = {.name = "TAP", .desc = "[I/O] Tape"}, | 66 | [IRQEXT_CMS] = {.name = "CMS", .desc = "[EXT] CPU-Measurement: Sampling"}, |
54 | [IOINT_VMR] = {.name = "VMR", .desc = "[I/O] Unit Record Devices"}, | 67 | [IRQEXT_CMC] = {.name = "CMC", .desc = "[EXT] CPU-Measurement: Counter"}, |
55 | [IOINT_LCS] = {.name = "LCS", .desc = "[I/O] LCS"}, | 68 | [IRQEXT_CMR] = {.name = "CMR", .desc = "[EXT] CPU-Measurement: RI"}, |
56 | [IOINT_CLW] = {.name = "CLW", .desc = "[I/O] CLAW"}, | 69 | [IRQIO_CIO] = {.name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt"}, |
57 | [IOINT_CTC] = {.name = "CTC", .desc = "[I/O] CTC"}, | 70 | [IRQIO_QAI] = {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt"}, |
58 | [IOINT_APB] = {.name = "APB", .desc = "[I/O] AP Bus"}, | 71 | [IRQIO_DAS] = {.name = "DAS", .desc = "[I/O] DASD"}, |
59 | [IOINT_ADM] = {.name = "ADM", .desc = "[I/O] EADM Subchannel"}, | 72 | [IRQIO_C15] = {.name = "C15", .desc = "[I/O] 3215"}, |
60 | [IOINT_CSC] = {.name = "CSC", .desc = "[I/O] CHSC Subchannel"}, | 73 | [IRQIO_C70] = {.name = "C70", .desc = "[I/O] 3270"}, |
61 | [IOINT_PCI] = {.name = "PCI", .desc = "[I/O] PCI Interrupt" }, | 74 | [IRQIO_TAP] = {.name = "TAP", .desc = "[I/O] Tape"}, |
62 | [IOINT_MSI] = {.name = "MSI", .desc = "[I/O] MSI Interrupt" }, | 75 | [IRQIO_VMR] = {.name = "VMR", .desc = "[I/O] Unit Record Devices"}, |
76 | [IRQIO_LCS] = {.name = "LCS", .desc = "[I/O] LCS"}, | ||
77 | [IRQIO_CLW] = {.name = "CLW", .desc = "[I/O] CLAW"}, | ||
78 | [IRQIO_CTC] = {.name = "CTC", .desc = "[I/O] CTC"}, | ||
79 | [IRQIO_APB] = {.name = "APB", .desc = "[I/O] AP Bus"}, | ||
80 | [IRQIO_ADM] = {.name = "ADM", .desc = "[I/O] EADM Subchannel"}, | ||
81 | [IRQIO_CSC] = {.name = "CSC", .desc = "[I/O] CHSC Subchannel"}, | ||
82 | [IRQIO_PCI] = {.name = "PCI", .desc = "[I/O] PCI Interrupt" }, | ||
83 | [IRQIO_MSI] = {.name = "MSI", .desc = "[I/O] MSI Interrupt" }, | ||
63 | [NMI_NMI] = {.name = "NMI", .desc = "[NMI] Machine Check"}, | 84 | [NMI_NMI] = {.name = "NMI", .desc = "[NMI] Machine Check"}, |
85 | [CPU_RST] = {.name = "RST", .desc = "[CPU] CPU Restart"}, | ||
64 | }; | 86 | }; |
65 | 87 | ||
66 | /* | 88 | /* |
@@ -68,30 +90,34 @@ static const struct irq_class intrclass_names[] = { | |||
68 | */ | 90 | */ |
69 | int show_interrupts(struct seq_file *p, void *v) | 91 | int show_interrupts(struct seq_file *p, void *v) |
70 | { | 92 | { |
71 | int i = *(loff_t *) v, j; | 93 | int irq = *(loff_t *) v; |
94 | int cpu; | ||
72 | 95 | ||
73 | get_online_cpus(); | 96 | get_online_cpus(); |
74 | if (i == 0) { | 97 | if (irq == 0) { |
75 | seq_puts(p, " "); | 98 | seq_puts(p, " "); |
76 | for_each_online_cpu(j) | 99 | for_each_online_cpu(cpu) |
77 | seq_printf(p, "CPU%d ",j); | 100 | seq_printf(p, "CPU%d ", cpu); |
78 | seq_putc(p, '\n'); | 101 | seq_putc(p, '\n'); |
79 | } | 102 | } |
80 | 103 | if (irq < NR_IRQS) { | |
81 | if (i < NR_IRQS) { | 104 | seq_printf(p, "%s: ", irqclass_main_desc[irq].name); |
82 | seq_printf(p, "%s: ", intrclass_names[i].name); | 105 | for_each_online_cpu(cpu) |
83 | #ifndef CONFIG_SMP | 106 | seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[irq]); |
84 | seq_printf(p, "%10u ", kstat_irqs(i)); | 107 | seq_putc(p, '\n'); |
85 | #else | 108 | goto skip_arch_irqs; |
86 | for_each_online_cpu(j) | 109 | } |
87 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); | 110 | for (irq = 0; irq < NR_ARCH_IRQS; irq++) { |
88 | #endif | 111 | seq_printf(p, "%s: ", irqclass_sub_desc[irq].name); |
89 | if (intrclass_names[i].desc) | 112 | for_each_online_cpu(cpu) |
90 | seq_printf(p, " %s", intrclass_names[i].desc); | 113 | seq_printf(p, "%10u ", per_cpu(irq_stat, cpu).irqs[irq]); |
91 | seq_putc(p, '\n'); | 114 | if (irqclass_sub_desc[irq].desc) |
92 | } | 115 | seq_printf(p, " %s", irqclass_sub_desc[irq].desc); |
116 | seq_putc(p, '\n'); | ||
117 | } | ||
118 | skip_arch_irqs: | ||
93 | put_online_cpus(); | 119 | put_online_cpus(); |
94 | return 0; | 120 | return 0; |
95 | } | 121 | } |
96 | 122 | ||
97 | /* | 123 | /* |
@@ -222,7 +248,7 @@ void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code, | |||
222 | /* Serve timer interrupts first. */ | 248 | /* Serve timer interrupts first. */ |
223 | clock_comparator_work(); | 249 | clock_comparator_work(); |
224 | } | 250 | } |
225 | kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++; | 251 | kstat_incr_irqs_this_cpu(EXTERNAL_INTERRUPT, NULL); |
226 | if (ext_code.code != 0x1004) | 252 | if (ext_code.code != 0x1004) |
227 | __get_cpu_var(s390_idle).nohz_delay = 1; | 253 | __get_cpu_var(s390_idle).nohz_delay = 1; |
228 | 254 | ||
diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index a6daa5c5cdb0..7918fbea36bb 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c | |||
@@ -254,7 +254,7 @@ void notrace s390_do_machine_check(struct pt_regs *regs) | |||
254 | int umode; | 254 | int umode; |
255 | 255 | ||
256 | nmi_enter(); | 256 | nmi_enter(); |
257 | kstat_cpu(smp_processor_id()).irqs[NMI_NMI]++; | 257 | inc_irq_stat(NMI_NMI); |
258 | mci = (struct mci *) &S390_lowcore.mcck_interruption_code; | 258 | mci = (struct mci *) &S390_lowcore.mcck_interruption_code; |
259 | mcck = &__get_cpu_var(cpu_mcck); | 259 | mcck = &__get_cpu_var(cpu_mcck); |
260 | umode = user_mode(regs); | 260 | umode = user_mode(regs); |
diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c index c4e7269d4a09..86ec7447e1f5 100644 --- a/arch/s390/kernel/perf_cpum_cf.c +++ b/arch/s390/kernel/perf_cpum_cf.c | |||
@@ -229,7 +229,7 @@ static void cpumf_measurement_alert(struct ext_code ext_code, | |||
229 | if (!(alert & CPU_MF_INT_CF_MASK)) | 229 | if (!(alert & CPU_MF_INT_CF_MASK)) |
230 | return; | 230 | return; |
231 | 231 | ||
232 | kstat_cpu(smp_processor_id()).irqs[EXTINT_CMC]++; | 232 | inc_irq_stat(IRQEXT_CMC); |
233 | cpuhw = &__get_cpu_var(cpu_hw_events); | 233 | cpuhw = &__get_cpu_var(cpu_hw_events); |
234 | 234 | ||
235 | /* Measurement alerts are shared and might happen when the PMU | 235 | /* Measurement alerts are shared and might happen when the PMU |
diff --git a/arch/s390/kernel/runtime_instr.c b/arch/s390/kernel/runtime_instr.c index 61066f6f71a5..077a99389b07 100644 --- a/arch/s390/kernel/runtime_instr.c +++ b/arch/s390/kernel/runtime_instr.c | |||
@@ -71,7 +71,7 @@ static void runtime_instr_int_handler(struct ext_code ext_code, | |||
71 | if (!(param32 & CPU_MF_INT_RI_MASK)) | 71 | if (!(param32 & CPU_MF_INT_RI_MASK)) |
72 | return; | 72 | return; |
73 | 73 | ||
74 | kstat_cpu(smp_processor_id()).irqs[EXTINT_CMR]++; | 74 | inc_irq_stat(IRQEXT_CMR); |
75 | 75 | ||
76 | if (!current->thread.ri_cb) | 76 | if (!current->thread.ri_cb) |
77 | return; | 77 | return; |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 2568590973ad..a5360de85ec7 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -16,7 +16,7 @@ | |||
16 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | 16 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
17 | 17 | ||
18 | #include <linux/errno.h> | 18 | #include <linux/errno.h> |
19 | #include <linux/module.h> | 19 | #include <linux/export.h> |
20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
22 | #include <linux/memblock.h> | 22 | #include <linux/memblock.h> |
@@ -289,6 +289,7 @@ void machine_power_off(void) | |||
289 | * Dummy power off function. | 289 | * Dummy power off function. |
290 | */ | 290 | */ |
291 | void (*pm_power_off)(void) = machine_power_off; | 291 | void (*pm_power_off)(void) = machine_power_off; |
292 | EXPORT_SYMBOL_GPL(pm_power_off); | ||
292 | 293 | ||
293 | static int __init early_parse_mem(char *p) | 294 | static int __init early_parse_mem(char *p) |
294 | { | 295 | { |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 0b45baa55438..7433a2f9e5cc 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -433,9 +433,9 @@ static void do_ext_call_interrupt(struct ext_code ext_code, | |||
433 | 433 | ||
434 | cpu = smp_processor_id(); | 434 | cpu = smp_processor_id(); |
435 | if (ext_code.code == 0x1202) | 435 | if (ext_code.code == 0x1202) |
436 | kstat_cpu(cpu).irqs[EXTINT_EXC]++; | 436 | inc_irq_stat(IRQEXT_EXC); |
437 | else | 437 | else |
438 | kstat_cpu(cpu).irqs[EXTINT_EMS]++; | 438 | inc_irq_stat(IRQEXT_EMS); |
439 | /* | 439 | /* |
440 | * handle bit signal external calls | 440 | * handle bit signal external calls |
441 | */ | 441 | */ |
@@ -623,9 +623,10 @@ static struct sclp_cpu_info *smp_get_cpu_info(void) | |||
623 | return info; | 623 | return info; |
624 | } | 624 | } |
625 | 625 | ||
626 | static int smp_add_present_cpu(int cpu); | 626 | static int __cpuinit smp_add_present_cpu(int cpu); |
627 | 627 | ||
628 | static int __smp_rescan_cpus(struct sclp_cpu_info *info, int sysfs_add) | 628 | static int __cpuinit __smp_rescan_cpus(struct sclp_cpu_info *info, |
629 | int sysfs_add) | ||
629 | { | 630 | { |
630 | struct pcpu *pcpu; | 631 | struct pcpu *pcpu; |
631 | cpumask_t avail; | 632 | cpumask_t avail; |
@@ -708,6 +709,7 @@ static void __cpuinit smp_start_secondary(void *cpuvoid) | |||
708 | pfault_init(); | 709 | pfault_init(); |
709 | notify_cpu_starting(smp_processor_id()); | 710 | notify_cpu_starting(smp_processor_id()); |
710 | set_cpu_online(smp_processor_id(), true); | 711 | set_cpu_online(smp_processor_id(), true); |
712 | inc_irq_stat(CPU_RST); | ||
711 | local_irq_enable(); | 713 | local_irq_enable(); |
712 | /* cpu_idle will call schedule for us */ | 714 | /* cpu_idle will call schedule for us */ |
713 | cpu_idle(); | 715 | cpu_idle(); |
@@ -985,7 +987,7 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self, | |||
985 | return notifier_from_errno(err); | 987 | return notifier_from_errno(err); |
986 | } | 988 | } |
987 | 989 | ||
988 | static int smp_add_present_cpu(int cpu) | 990 | static int __cpuinit smp_add_present_cpu(int cpu) |
989 | { | 991 | { |
990 | struct cpu *c = &pcpu_devices[cpu].cpu; | 992 | struct cpu *c = &pcpu_devices[cpu].cpu; |
991 | struct device *s = &c->dev; | 993 | struct device *s = &c->dev; |
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index 48174850f3b0..6a6c61f94dd3 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S | |||
@@ -352,3 +352,4 @@ SYSCALL(sys_process_vm_readv,sys_process_vm_readv,compat_sys_process_vm_readv_wr | |||
352 | SYSCALL(sys_process_vm_writev,sys_process_vm_writev,compat_sys_process_vm_writev_wrapper) | 352 | SYSCALL(sys_process_vm_writev,sys_process_vm_writev,compat_sys_process_vm_writev_wrapper) |
353 | SYSCALL(sys_ni_syscall,sys_s390_runtime_instr,sys_s390_runtime_instr_wrapper) | 353 | SYSCALL(sys_ni_syscall,sys_s390_runtime_instr,sys_s390_runtime_instr_wrapper) |
354 | SYSCALL(sys_kcmp,sys_kcmp,sys_kcmp_wrapper) | 354 | SYSCALL(sys_kcmp,sys_kcmp,sys_kcmp_wrapper) |
355 | SYSCALL(sys_finit_module,sys_finit_module,sys_finit_module_wrapper) | ||
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 7fcd690d42c7..a5f4f5a1d24b 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
@@ -63,7 +63,7 @@ static DEFINE_PER_CPU(struct clock_event_device, comparators); | |||
63 | */ | 63 | */ |
64 | unsigned long long notrace __kprobes sched_clock(void) | 64 | unsigned long long notrace __kprobes sched_clock(void) |
65 | { | 65 | { |
66 | return (get_clock_monotonic() * 125) >> 9; | 66 | return tod_to_ns(get_clock_monotonic()); |
67 | } | 67 | } |
68 | 68 | ||
69 | /* | 69 | /* |
@@ -168,7 +168,7 @@ static void clock_comparator_interrupt(struct ext_code ext_code, | |||
168 | unsigned int param32, | 168 | unsigned int param32, |
169 | unsigned long param64) | 169 | unsigned long param64) |
170 | { | 170 | { |
171 | kstat_cpu(smp_processor_id()).irqs[EXTINT_CLK]++; | 171 | inc_irq_stat(IRQEXT_CLK); |
172 | if (S390_lowcore.clock_comparator == -1ULL) | 172 | if (S390_lowcore.clock_comparator == -1ULL) |
173 | set_clock_comparator(S390_lowcore.clock_comparator); | 173 | set_clock_comparator(S390_lowcore.clock_comparator); |
174 | } | 174 | } |
@@ -179,7 +179,7 @@ static void stp_timing_alert(struct stp_irq_parm *); | |||
179 | static void timing_alert_interrupt(struct ext_code ext_code, | 179 | static void timing_alert_interrupt(struct ext_code ext_code, |
180 | unsigned int param32, unsigned long param64) | 180 | unsigned int param32, unsigned long param64) |
181 | { | 181 | { |
182 | kstat_cpu(smp_processor_id()).irqs[EXTINT_TLA]++; | 182 | inc_irq_stat(IRQEXT_TLA); |
183 | if (param32 & 0x00c40000) | 183 | if (param32 & 0x00c40000) |
184 | etr_timing_alert((struct etr_irq_parm *) ¶m32); | 184 | etr_timing_alert((struct etr_irq_parm *) ¶m32); |
185 | if (param32 & 0x00038000) | 185 | if (param32 & 0x00038000) |
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index f1aba87cceb8..4b2e3e317004 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/bootmem.h> | 10 | #include <linux/bootmem.h> |
11 | #include <linux/cpuset.h> | 11 | #include <linux/cpuset.h> |
12 | #include <linux/device.h> | 12 | #include <linux/device.h> |
13 | #include <linux/export.h> | ||
13 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
14 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
15 | #include <linux/init.h> | 16 | #include <linux/init.h> |
@@ -42,6 +43,7 @@ static struct mask_info socket_info; | |||
42 | static struct mask_info book_info; | 43 | static struct mask_info book_info; |
43 | 44 | ||
44 | struct cpu_topology_s390 cpu_topology[NR_CPUS]; | 45 | struct cpu_topology_s390 cpu_topology[NR_CPUS]; |
46 | EXPORT_SYMBOL_GPL(cpu_topology); | ||
45 | 47 | ||
46 | static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) | 48 | static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) |
47 | { | 49 | { |
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index c30615e605ac..82c481ddef76 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c | |||
@@ -408,7 +408,7 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu) | |||
408 | return 0; | 408 | return 0; |
409 | } | 409 | } |
410 | 410 | ||
411 | sltime = ((vcpu->arch.sie_block->ckc - now)*125)>>9; | 411 | sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now); |
412 | 412 | ||
413 | hrtimer_start(&vcpu->arch.ckc_timer, ktime_set (0, sltime) , HRTIMER_MODE_REL); | 413 | hrtimer_start(&vcpu->arch.ckc_timer, ktime_set (0, sltime) , HRTIMER_MODE_REL); |
414 | VCPU_EVENT(vcpu, 5, "enabled wait via clock comparator: %llx ns", sltime); | 414 | VCPU_EVENT(vcpu, 5, "enabled wait via clock comparator: %llx ns", sltime); |
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index c9011bfaabbe..f090e819bf71 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
@@ -613,7 +613,9 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) | |||
613 | kvm_s390_deliver_pending_interrupts(vcpu); | 613 | kvm_s390_deliver_pending_interrupts(vcpu); |
614 | 614 | ||
615 | vcpu->arch.sie_block->icptcode = 0; | 615 | vcpu->arch.sie_block->icptcode = 0; |
616 | preempt_disable(); | ||
616 | kvm_guest_enter(); | 617 | kvm_guest_enter(); |
618 | preempt_enable(); | ||
617 | VCPU_EVENT(vcpu, 6, "entering sie flags %x", | 619 | VCPU_EVENT(vcpu, 6, "entering sie flags %x", |
618 | atomic_read(&vcpu->arch.sie_block->cpuflags)); | 620 | atomic_read(&vcpu->arch.sie_block->cpuflags)); |
619 | trace_kvm_s390_sie_enter(vcpu, | 621 | trace_kvm_s390_sie_enter(vcpu, |
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 42601d6e166f..2fb9e63b8fc4 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
@@ -569,7 +569,7 @@ static void pfault_interrupt(struct ext_code ext_code, | |||
569 | subcode = ext_code.subcode; | 569 | subcode = ext_code.subcode; |
570 | if ((subcode & 0xff00) != __SUBCODE_MASK) | 570 | if ((subcode & 0xff00) != __SUBCODE_MASK) |
571 | return; | 571 | return; |
572 | kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++; | 572 | inc_irq_stat(IRQEXT_PFL); |
573 | /* Get the token (= pid of the affected task). */ | 573 | /* Get the token (= pid of the affected task). */ |
574 | pid = sizeof(void *) == 4 ? param32 : param64; | 574 | pid = sizeof(void *) == 4 ? param32 : param64; |
575 | rcu_read_lock(); | 575 | rcu_read_lock(); |
diff --git a/arch/s390/oprofile/hwsampler.c b/arch/s390/oprofile/hwsampler.c index 0cb385da202c..b5b2916895e0 100644 --- a/arch/s390/oprofile/hwsampler.c +++ b/arch/s390/oprofile/hwsampler.c | |||
@@ -233,7 +233,7 @@ static void hws_ext_handler(struct ext_code ext_code, | |||
233 | if (!(param32 & CPU_MF_INT_SF_MASK)) | 233 | if (!(param32 & CPU_MF_INT_SF_MASK)) |
234 | return; | 234 | return; |
235 | 235 | ||
236 | kstat_cpu(smp_processor_id()).irqs[EXTINT_CMS]++; | 236 | inc_irq_stat(IRQEXT_CMS); |
237 | atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32); | 237 | atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32); |
238 | 238 | ||
239 | if (hws_wq) | 239 | if (hws_wq) |
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index ff49427e9941..60e0372545d2 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c | |||
@@ -160,35 +160,6 @@ int pci_proc_domain(struct pci_bus *bus) | |||
160 | } | 160 | } |
161 | EXPORT_SYMBOL_GPL(pci_proc_domain); | 161 | EXPORT_SYMBOL_GPL(pci_proc_domain); |
162 | 162 | ||
163 | /* Store PCI function information block */ | ||
164 | static int zpci_store_fib(struct zpci_dev *zdev, u8 *fc) | ||
165 | { | ||
166 | struct zpci_fib *fib; | ||
167 | u8 status, cc; | ||
168 | |||
169 | fib = (void *) get_zeroed_page(GFP_KERNEL); | ||
170 | if (!fib) | ||
171 | return -ENOMEM; | ||
172 | |||
173 | do { | ||
174 | cc = __stpcifc(zdev->fh, 0, fib, &status); | ||
175 | if (cc == 2) { | ||
176 | msleep(ZPCI_INSN_BUSY_DELAY); | ||
177 | memset(fib, 0, PAGE_SIZE); | ||
178 | } | ||
179 | } while (cc == 2); | ||
180 | |||
181 | if (cc) | ||
182 | pr_err_once("%s: cc: %u status: %u\n", | ||
183 | __func__, cc, status); | ||
184 | |||
185 | /* Return PCI function controls */ | ||
186 | *fc = fib->fc; | ||
187 | |||
188 | free_page((unsigned long) fib); | ||
189 | return (cc) ? -EIO : 0; | ||
190 | } | ||
191 | |||
192 | /* Modify PCI: Register adapter interruptions */ | 163 | /* Modify PCI: Register adapter interruptions */ |
193 | static int zpci_register_airq(struct zpci_dev *zdev, unsigned int aisb, | 164 | static int zpci_register_airq(struct zpci_dev *zdev, unsigned int aisb, |
194 | u64 aibv) | 165 | u64 aibv) |
@@ -469,7 +440,7 @@ static void zpci_irq_handler(void *dont, void *need) | |||
469 | int rescan = 0, max = aisb_max; | 440 | int rescan = 0, max = aisb_max; |
470 | struct zdev_irq_map *imap; | 441 | struct zdev_irq_map *imap; |
471 | 442 | ||
472 | kstat_cpu(smp_processor_id()).irqs[IOINT_PCI]++; | 443 | inc_irq_stat(IRQIO_PCI); |
473 | sbit = start; | 444 | sbit = start; |
474 | 445 | ||
475 | scan: | 446 | scan: |
@@ -481,7 +452,7 @@ scan: | |||
481 | /* find vector bit */ | 452 | /* find vector bit */ |
482 | imap = bucket->imap[sbit]; | 453 | imap = bucket->imap[sbit]; |
483 | for_each_set_bit_left(mbit, &imap->aibv, imap->msi_vecs) { | 454 | for_each_set_bit_left(mbit, &imap->aibv, imap->msi_vecs) { |
484 | kstat_cpu(smp_processor_id()).irqs[IOINT_MSI]++; | 455 | inc_irq_stat(IRQIO_MSI); |
485 | clear_bit(63 - mbit, &imap->aibv); | 456 | clear_bit(63 - mbit, &imap->aibv); |
486 | 457 | ||
487 | spin_lock(&imap->lock); | 458 | spin_lock(&imap->lock); |
diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c index 6138468b420f..a547419907c3 100644 --- a/arch/s390/pci/pci_dma.c +++ b/arch/s390/pci/pci_dma.c | |||
@@ -13,8 +13,6 @@ | |||
13 | #include <linux/pci.h> | 13 | #include <linux/pci.h> |
14 | #include <asm/pci_dma.h> | 14 | #include <asm/pci_dma.h> |
15 | 15 | ||
16 | static enum zpci_ioat_dtype zpci_ioat_dt = ZPCI_IOTA_RTTO; | ||
17 | |||
18 | static struct kmem_cache *dma_region_table_cache; | 16 | static struct kmem_cache *dma_region_table_cache; |
19 | static struct kmem_cache *dma_page_table_cache; | 17 | static struct kmem_cache *dma_page_table_cache; |
20 | 18 | ||
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 3fede4556c91..a0fa5791cd44 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c | |||
@@ -70,6 +70,16 @@ | |||
70 | * OFF-ON : MMC | 70 | * OFF-ON : MMC |
71 | */ | 71 | */ |
72 | 72 | ||
73 | /* | ||
74 | * FSI - DA7210 | ||
75 | * | ||
76 | * it needs amixer settings for playing | ||
77 | * | ||
78 | * amixer set 'HeadPhone' 80 | ||
79 | * amixer set 'Out Mixer Left DAC Left' on | ||
80 | * amixer set 'Out Mixer Right DAC Right' on | ||
81 | */ | ||
82 | |||
73 | /* Heartbeat */ | 83 | /* Heartbeat */ |
74 | static unsigned char led_pos[] = { 0, 1, 2, 3 }; | 84 | static unsigned char led_pos[] = { 0, 1, 2, 3 }; |
75 | 85 | ||
diff --git a/arch/sh/include/asm/elf.h b/arch/sh/include/asm/elf.h index 37924afa8d8a..bf9f44f17c29 100644 --- a/arch/sh/include/asm/elf.h +++ b/arch/sh/include/asm/elf.h | |||
@@ -203,9 +203,9 @@ extern void __kernel_vsyscall; | |||
203 | if (vdso_enabled) \ | 203 | if (vdso_enabled) \ |
204 | NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_BASE); \ | 204 | NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_BASE); \ |
205 | else \ | 205 | else \ |
206 | NEW_AUX_ENT(AT_IGNORE, 0); | 206 | NEW_AUX_ENT(AT_IGNORE, 0) |
207 | #else | 207 | #else |
208 | #define VSYSCALL_AUX_ENT | 208 | #define VSYSCALL_AUX_ENT NEW_AUX_ENT(AT_IGNORE, 0) |
209 | #endif /* CONFIG_VSYSCALL */ | 209 | #endif /* CONFIG_VSYSCALL */ |
210 | 210 | ||
211 | #ifdef CONFIG_SH_FPU | 211 | #ifdef CONFIG_SH_FPU |
diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h index b1320d55ca30..e699a12cdcca 100644 --- a/arch/sh/include/asm/processor_32.h +++ b/arch/sh/include/asm/processor_32.h | |||
@@ -39,7 +39,7 @@ | |||
39 | /* This decides where the kernel will search for a free chunk of vm | 39 | /* This decides where the kernel will search for a free chunk of vm |
40 | * space during mmap's. | 40 | * space during mmap's. |
41 | */ | 41 | */ |
42 | #define TASK_UNMAPPED_BASE (TASK_SIZE / 3) | 42 | #define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE / 3) |
43 | 43 | ||
44 | /* | 44 | /* |
45 | * Bit of SR register | 45 | * Bit of SR register |
diff --git a/arch/sh/include/asm/processor_64.h b/arch/sh/include/asm/processor_64.h index 1ee8946f0952..1cc7d3197143 100644 --- a/arch/sh/include/asm/processor_64.h +++ b/arch/sh/include/asm/processor_64.h | |||
@@ -47,7 +47,7 @@ pc; }) | |||
47 | /* This decides where the kernel will search for a free chunk of vm | 47 | /* This decides where the kernel will search for a free chunk of vm |
48 | * space during mmap's. | 48 | * space during mmap's. |
49 | */ | 49 | */ |
50 | #define TASK_UNMAPPED_BASE (TASK_SIZE / 3) | 50 | #define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE / 3) |
51 | 51 | ||
52 | /* | 52 | /* |
53 | * Bit of SR register | 53 | * Bit of SR register |
diff --git a/arch/sh/include/uapi/asm/unistd_32.h b/arch/sh/include/uapi/asm/unistd_32.h index 9e465f246dc1..d13a1d623736 100644 --- a/arch/sh/include/uapi/asm/unistd_32.h +++ b/arch/sh/include/uapi/asm/unistd_32.h | |||
@@ -379,7 +379,8 @@ | |||
379 | #define __NR_process_vm_readv 365 | 379 | #define __NR_process_vm_readv 365 |
380 | #define __NR_process_vm_writev 366 | 380 | #define __NR_process_vm_writev 366 |
381 | #define __NR_kcmp 367 | 381 | #define __NR_kcmp 367 |
382 | #define __NR_finit_module 368 | ||
382 | 383 | ||
383 | #define NR_syscalls 368 | 384 | #define NR_syscalls 369 |
384 | 385 | ||
385 | #endif /* __ASM_SH_UNISTD_32_H */ | 386 | #endif /* __ASM_SH_UNISTD_32_H */ |
diff --git a/arch/sh/include/uapi/asm/unistd_64.h b/arch/sh/include/uapi/asm/unistd_64.h index 8e3a2edd284e..e6820c86e8c7 100644 --- a/arch/sh/include/uapi/asm/unistd_64.h +++ b/arch/sh/include/uapi/asm/unistd_64.h | |||
@@ -399,7 +399,8 @@ | |||
399 | #define __NR_process_vm_readv 376 | 399 | #define __NR_process_vm_readv 376 |
400 | #define __NR_process_vm_writev 377 | 400 | #define __NR_process_vm_writev 377 |
401 | #define __NR_kcmp 378 | 401 | #define __NR_kcmp 378 |
402 | #define __NR_finit_module 379 | ||
402 | 403 | ||
403 | #define NR_syscalls 379 | 404 | #define NR_syscalls 380 |
404 | 405 | ||
405 | #endif /* __ASM_SH_UNISTD_64_H */ | 406 | #endif /* __ASM_SH_UNISTD_64_H */ |
diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S index fe97ae5e56f1..734234be2f01 100644 --- a/arch/sh/kernel/syscalls_32.S +++ b/arch/sh/kernel/syscalls_32.S | |||
@@ -385,3 +385,4 @@ ENTRY(sys_call_table) | |||
385 | .long sys_process_vm_readv /* 365 */ | 385 | .long sys_process_vm_readv /* 365 */ |
386 | .long sys_process_vm_writev | 386 | .long sys_process_vm_writev |
387 | .long sys_kcmp | 387 | .long sys_kcmp |
388 | .long sys_finit_module | ||
diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S index 5c7b1c67bdc1..579fcb9a896b 100644 --- a/arch/sh/kernel/syscalls_64.S +++ b/arch/sh/kernel/syscalls_64.S | |||
@@ -405,3 +405,4 @@ sys_call_table: | |||
405 | .long sys_process_vm_readv | 405 | .long sys_process_vm_readv |
406 | .long sys_process_vm_writev | 406 | .long sys_process_vm_writev |
407 | .long sys_kcmp | 407 | .long sys_kcmp |
408 | .long sys_finit_module | ||
diff --git a/arch/sh/lib/mcount.S b/arch/sh/lib/mcount.S index 60164e65d665..52aa2011d753 100644 --- a/arch/sh/lib/mcount.S +++ b/arch/sh/lib/mcount.S | |||
@@ -294,6 +294,8 @@ stack_panic: | |||
294 | .align 2 | 294 | .align 2 |
295 | .L_init_thread_union: | 295 | .L_init_thread_union: |
296 | .long init_thread_union | 296 | .long init_thread_union |
297 | .L_ebss: | ||
298 | .long __bss_stop | ||
297 | .Lpanic: | 299 | .Lpanic: |
298 | .long panic | 300 | .long panic |
299 | .Lpanic_s: | 301 | .Lpanic_s: |
diff --git a/arch/sparc/include/uapi/asm/unistd.h b/arch/sparc/include/uapi/asm/unistd.h index cac719d1bc5c..62ced589bcf7 100644 --- a/arch/sparc/include/uapi/asm/unistd.h +++ b/arch/sparc/include/uapi/asm/unistd.h | |||
@@ -407,8 +407,9 @@ | |||
407 | #define __NR_process_vm_writev 339 | 407 | #define __NR_process_vm_writev 339 |
408 | #define __NR_kern_features 340 | 408 | #define __NR_kern_features 340 |
409 | #define __NR_kcmp 341 | 409 | #define __NR_kcmp 341 |
410 | #define __NR_finit_module 342 | ||
410 | 411 | ||
411 | #define NR_syscalls 342 | 412 | #define NR_syscalls 343 |
412 | 413 | ||
413 | /* Bitmask values returned from kern_features system call. */ | 414 | /* Bitmask values returned from kern_features system call. */ |
414 | #define KERN_FEATURE_MIXED_MODE_STACK 0x00000001 | 415 | #define KERN_FEATURE_MIXED_MODE_STACK 0x00000001 |
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index 04bacce76fe6..baf4366e2d6a 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c | |||
@@ -378,7 +378,8 @@ static void apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p) | |||
378 | /* Cook up fake bus resources for SUNW,simba PCI bridges which lack | 378 | /* Cook up fake bus resources for SUNW,simba PCI bridges which lack |
379 | * a proper 'ranges' property. | 379 | * a proper 'ranges' property. |
380 | */ | 380 | */ |
381 | static void apb_fake_ranges(struct pci_dev *dev, struct pci_bus *bus, | 381 | static void apb_fake_ranges(struct pci_dev *dev, |
382 | struct pci_bus *bus, | ||
382 | struct pci_pbm_info *pbm) | 383 | struct pci_pbm_info *pbm) |
383 | { | 384 | { |
384 | struct pci_bus_region region; | 385 | struct pci_bus_region region; |
@@ -403,13 +404,15 @@ static void apb_fake_ranges(struct pci_dev *dev, struct pci_bus *bus, | |||
403 | pcibios_bus_to_resource(dev, res, ®ion); | 404 | pcibios_bus_to_resource(dev, res, ®ion); |
404 | } | 405 | } |
405 | 406 | ||
406 | static void pci_of_scan_bus(struct pci_pbm_info *pbm, struct device_node *node, | 407 | static void pci_of_scan_bus(struct pci_pbm_info *pbm, |
408 | struct device_node *node, | ||
407 | struct pci_bus *bus); | 409 | struct pci_bus *bus); |
408 | 410 | ||
409 | #define GET_64BIT(prop, i) ((((u64) (prop)[(i)]) << 32) | (prop)[(i)+1]) | 411 | #define GET_64BIT(prop, i) ((((u64) (prop)[(i)]) << 32) | (prop)[(i)+1]) |
410 | 412 | ||
411 | static void of_scan_pci_bridge(struct pci_pbm_info *pbm, | 413 | static void of_scan_pci_bridge(struct pci_pbm_info *pbm, |
412 | struct device_node *node, struct pci_dev *dev) | 414 | struct device_node *node, |
415 | struct pci_dev *dev) | ||
413 | { | 416 | { |
414 | struct pci_bus *bus; | 417 | struct pci_bus *bus; |
415 | const u32 *busrange, *ranges; | 418 | const u32 *busrange, *ranges; |
@@ -500,7 +503,8 @@ after_ranges: | |||
500 | pci_of_scan_bus(pbm, node, bus); | 503 | pci_of_scan_bus(pbm, node, bus); |
501 | } | 504 | } |
502 | 505 | ||
503 | static void pci_of_scan_bus(struct pci_pbm_info *pbm, struct device_node *node, | 506 | static void pci_of_scan_bus(struct pci_pbm_info *pbm, |
507 | struct device_node *node, | ||
504 | struct pci_bus *bus) | 508 | struct pci_bus *bus) |
505 | { | 509 | { |
506 | struct device_node *child; | 510 | struct device_node *child; |
diff --git a/arch/sparc/kernel/pci_psycho.c b/arch/sparc/kernel/pci_psycho.c index b85238289717..c647634ead2b 100644 --- a/arch/sparc/kernel/pci_psycho.c +++ b/arch/sparc/kernel/pci_psycho.c | |||
@@ -366,7 +366,8 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm) | |||
366 | pci_config_write8(addr, 64); | 366 | pci_config_write8(addr, 64); |
367 | } | 367 | } |
368 | 368 | ||
369 | static void psycho_scan_bus(struct pci_pbm_info *pbm, struct device *parent) | 369 | static void psycho_scan_bus(struct pci_pbm_info *pbm, |
370 | struct device *parent) | ||
370 | { | 371 | { |
371 | pbm_config_busmastering(pbm); | 372 | pbm_config_busmastering(pbm); |
372 | pbm->is_66mhz_capable = 0; | 373 | pbm->is_66mhz_capable = 0; |
diff --git a/arch/sparc/kernel/pci_sabre.c b/arch/sparc/kernel/pci_sabre.c index 531186d7c9ab..6f00d27e8dac 100644 --- a/arch/sparc/kernel/pci_sabre.c +++ b/arch/sparc/kernel/pci_sabre.c | |||
@@ -442,7 +442,8 @@ static void sabre_scan_bus(struct pci_pbm_info *pbm, struct device *parent) | |||
442 | sabre_register_error_handlers(pbm); | 442 | sabre_register_error_handlers(pbm); |
443 | } | 443 | } |
444 | 444 | ||
445 | static void sabre_pbm_init(struct pci_pbm_info *pbm, struct platform_device *op) | 445 | static void sabre_pbm_init(struct pci_pbm_info *pbm, |
446 | struct platform_device *op) | ||
446 | { | 447 | { |
447 | psycho_pbm_init_common(pbm, op, "SABRE", PBM_CHIP_TYPE_SABRE); | 448 | psycho_pbm_init_common(pbm, op, "SABRE", PBM_CHIP_TYPE_SABRE); |
448 | pbm->pci_afsr = pbm->controller_regs + SABRE_PIOAFSR; | 449 | pbm->pci_afsr = pbm->controller_regs + SABRE_PIOAFSR; |
diff --git a/arch/sparc/kernel/pci_schizo.c b/arch/sparc/kernel/pci_schizo.c index 29e888158ae6..8f76f23dac38 100644 --- a/arch/sparc/kernel/pci_schizo.c +++ b/arch/sparc/kernel/pci_schizo.c | |||
@@ -1306,8 +1306,9 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm) | |||
1306 | } | 1306 | } |
1307 | } | 1307 | } |
1308 | 1308 | ||
1309 | static int schizo_pbm_init(struct pci_pbm_info *pbm, struct platform_device *op, | 1309 | static int schizo_pbm_init(struct pci_pbm_info *pbm, |
1310 | u32 portid, int chip_type) | 1310 | struct platform_device *op, u32 portid, |
1311 | int chip_type) | ||
1311 | { | 1312 | { |
1312 | const struct linux_prom64_registers *regs; | 1313 | const struct linux_prom64_registers *regs; |
1313 | struct device_node *dp = op->dev.of_node; | 1314 | struct device_node *dp = op->dev.of_node; |
diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S index 5147f574f125..6ac43c36bbbf 100644 --- a/arch/sparc/kernel/systbls_32.S +++ b/arch/sparc/kernel/systbls_32.S | |||
@@ -85,4 +85,4 @@ sys_call_table: | |||
85 | /*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init | 85 | /*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init |
86 | /*330*/ .long sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime | 86 | /*330*/ .long sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime |
87 | /*335*/ .long sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev | 87 | /*335*/ .long sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev |
88 | /*340*/ .long sys_ni_syscall, sys_kcmp | 88 | /*340*/ .long sys_ni_syscall, sys_kcmp, sys_finit_module |
diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index cdbd9b817751..1009ecb92678 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S | |||
@@ -86,7 +86,7 @@ sys_call_table32: | |||
86 | .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init | 86 | .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init |
87 | /*330*/ .word sys32_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime | 87 | /*330*/ .word sys32_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime |
88 | .word sys_syncfs, compat_sys_sendmmsg, sys_setns, compat_sys_process_vm_readv, compat_sys_process_vm_writev | 88 | .word sys_syncfs, compat_sys_sendmmsg, sys_setns, compat_sys_process_vm_readv, compat_sys_process_vm_writev |
89 | /*340*/ .word sys_kern_features, sys_kcmp | 89 | /*340*/ .word sys_kern_features, sys_kcmp, sys_finit_module |
90 | 90 | ||
91 | #endif /* CONFIG_COMPAT */ | 91 | #endif /* CONFIG_COMPAT */ |
92 | 92 | ||
@@ -164,4 +164,4 @@ sys_call_table: | |||
164 | .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init | 164 | .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init |
165 | /*330*/ .word sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime | 165 | /*330*/ .word sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime |
166 | .word sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev | 166 | .word sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev |
167 | /*340*/ .word sys_kern_features, sys_kcmp | 167 | /*340*/ .word sys_kern_features, sys_kcmp, sys_finit_module |
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index b1942e222768..18e329ca108e 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c | |||
@@ -302,7 +302,7 @@ static efi_status_t setup_efi_pci(struct boot_params *params) | |||
302 | if (status != EFI_SUCCESS) | 302 | if (status != EFI_SUCCESS) |
303 | continue; | 303 | continue; |
304 | 304 | ||
305 | if (!attributes & EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM) | 305 | if (!(attributes & EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM)) |
306 | continue; | 306 | continue; |
307 | 307 | ||
308 | if (!pci->romimage || !pci->romsize) | 308 | if (!pci->romimage || !pci->romsize) |
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 08b973f64032..9c2bd8bd4b4c 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <asm/apicdef.h> | 43 | #include <asm/apicdef.h> |
44 | #include <asm/hypervisor.h> | 44 | #include <asm/hypervisor.h> |
45 | #include <asm/kvm_guest.h> | 45 | #include <asm/kvm_guest.h> |
46 | #include <asm/context_tracking.h> | ||
46 | 47 | ||
47 | static int kvmapf = 1; | 48 | static int kvmapf = 1; |
48 | 49 | ||
@@ -121,6 +122,8 @@ void kvm_async_pf_task_wait(u32 token) | |||
121 | struct kvm_task_sleep_node n, *e; | 122 | struct kvm_task_sleep_node n, *e; |
122 | DEFINE_WAIT(wait); | 123 | DEFINE_WAIT(wait); |
123 | 124 | ||
125 | rcu_irq_enter(); | ||
126 | |||
124 | spin_lock(&b->lock); | 127 | spin_lock(&b->lock); |
125 | e = _find_apf_task(b, token); | 128 | e = _find_apf_task(b, token); |
126 | if (e) { | 129 | if (e) { |
@@ -128,6 +131,8 @@ void kvm_async_pf_task_wait(u32 token) | |||
128 | hlist_del(&e->link); | 131 | hlist_del(&e->link); |
129 | kfree(e); | 132 | kfree(e); |
130 | spin_unlock(&b->lock); | 133 | spin_unlock(&b->lock); |
134 | |||
135 | rcu_irq_exit(); | ||
131 | return; | 136 | return; |
132 | } | 137 | } |
133 | 138 | ||
@@ -152,13 +157,16 @@ void kvm_async_pf_task_wait(u32 token) | |||
152 | /* | 157 | /* |
153 | * We cannot reschedule. So halt. | 158 | * We cannot reschedule. So halt. |
154 | */ | 159 | */ |
160 | rcu_irq_exit(); | ||
155 | native_safe_halt(); | 161 | native_safe_halt(); |
162 | rcu_irq_enter(); | ||
156 | local_irq_disable(); | 163 | local_irq_disable(); |
157 | } | 164 | } |
158 | } | 165 | } |
159 | if (!n.halted) | 166 | if (!n.halted) |
160 | finish_wait(&n.wq, &wait); | 167 | finish_wait(&n.wq, &wait); |
161 | 168 | ||
169 | rcu_irq_exit(); | ||
162 | return; | 170 | return; |
163 | } | 171 | } |
164 | EXPORT_SYMBOL_GPL(kvm_async_pf_task_wait); | 172 | EXPORT_SYMBOL_GPL(kvm_async_pf_task_wait); |
@@ -252,10 +260,10 @@ do_async_page_fault(struct pt_regs *regs, unsigned long error_code) | |||
252 | break; | 260 | break; |
253 | case KVM_PV_REASON_PAGE_NOT_PRESENT: | 261 | case KVM_PV_REASON_PAGE_NOT_PRESENT: |
254 | /* page is swapped out by the host. */ | 262 | /* page is swapped out by the host. */ |
255 | rcu_irq_enter(); | 263 | exception_enter(regs); |
256 | exit_idle(); | 264 | exit_idle(); |
257 | kvm_async_pf_task_wait((u32)read_cr2()); | 265 | kvm_async_pf_task_wait((u32)read_cr2()); |
258 | rcu_irq_exit(); | 266 | exception_exit(regs); |
259 | break; | 267 | break; |
260 | case KVM_PV_REASON_PAGE_READY: | 268 | case KVM_PV_REASON_PAGE_READY: |
261 | rcu_irq_enter(); | 269 | rcu_irq_enter(); |
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 23ddd558fbd5..00f6c1472b85 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
@@ -610,6 +610,83 @@ static __init void reserve_ibft_region(void) | |||
610 | 610 | ||
611 | static unsigned reserve_low = CONFIG_X86_RESERVE_LOW << 10; | 611 | static unsigned reserve_low = CONFIG_X86_RESERVE_LOW << 10; |
612 | 612 | ||
613 | static bool __init snb_gfx_workaround_needed(void) | ||
614 | { | ||
615 | #ifdef CONFIG_PCI | ||
616 | int i; | ||
617 | u16 vendor, devid; | ||
618 | static const __initconst u16 snb_ids[] = { | ||
619 | 0x0102, | ||
620 | 0x0112, | ||
621 | 0x0122, | ||
622 | 0x0106, | ||
623 | 0x0116, | ||
624 | 0x0126, | ||
625 | 0x010a, | ||
626 | }; | ||
627 | |||
628 | /* Assume no if something weird is going on with PCI */ | ||
629 | if (!early_pci_allowed()) | ||
630 | return false; | ||
631 | |||
632 | vendor = read_pci_config_16(0, 2, 0, PCI_VENDOR_ID); | ||
633 | if (vendor != 0x8086) | ||
634 | return false; | ||
635 | |||
636 | devid = read_pci_config_16(0, 2, 0, PCI_DEVICE_ID); | ||
637 | for (i = 0; i < ARRAY_SIZE(snb_ids); i++) | ||
638 | if (devid == snb_ids[i]) | ||
639 | return true; | ||
640 | #endif | ||
641 | |||
642 | return false; | ||
643 | } | ||
644 | |||
645 | /* | ||
646 | * Sandy Bridge graphics has trouble with certain ranges, exclude | ||
647 | * them from allocation. | ||
648 | */ | ||
649 | static void __init trim_snb_memory(void) | ||
650 | { | ||
651 | static const __initconst unsigned long bad_pages[] = { | ||
652 | 0x20050000, | ||
653 | 0x20110000, | ||
654 | 0x20130000, | ||
655 | 0x20138000, | ||
656 | 0x40004000, | ||
657 | }; | ||
658 | int i; | ||
659 | |||
660 | if (!snb_gfx_workaround_needed()) | ||
661 | return; | ||
662 | |||
663 | printk(KERN_DEBUG "reserving inaccessible SNB gfx pages\n"); | ||
664 | |||
665 | /* | ||
666 | * Reserve all memory below the 1 MB mark that has not | ||
667 | * already been reserved. | ||
668 | */ | ||
669 | memblock_reserve(0, 1<<20); | ||
670 | |||
671 | for (i = 0; i < ARRAY_SIZE(bad_pages); i++) { | ||
672 | if (memblock_reserve(bad_pages[i], PAGE_SIZE)) | ||
673 | printk(KERN_WARNING "failed to reserve 0x%08lx\n", | ||
674 | bad_pages[i]); | ||
675 | } | ||
676 | } | ||
677 | |||
678 | /* | ||
679 | * Here we put platform-specific memory range workarounds, i.e. | ||
680 | * memory known to be corrupt or otherwise in need to be reserved on | ||
681 | * specific platforms. | ||
682 | * | ||
683 | * If this gets used more widely it could use a real dispatch mechanism. | ||
684 | */ | ||
685 | static void __init trim_platform_memory_ranges(void) | ||
686 | { | ||
687 | trim_snb_memory(); | ||
688 | } | ||
689 | |||
613 | static void __init trim_bios_range(void) | 690 | static void __init trim_bios_range(void) |
614 | { | 691 | { |
615 | /* | 692 | /* |
@@ -630,6 +707,7 @@ static void __init trim_bios_range(void) | |||
630 | * take them out. | 707 | * take them out. |
631 | */ | 708 | */ |
632 | e820_remove_range(BIOS_BEGIN, BIOS_END - BIOS_BEGIN, E820_RAM, 1); | 709 | e820_remove_range(BIOS_BEGIN, BIOS_END - BIOS_BEGIN, E820_RAM, 1); |
710 | |||
633 | sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); | 711 | sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); |
634 | } | 712 | } |
635 | 713 | ||
@@ -908,6 +986,8 @@ void __init setup_arch(char **cmdline_p) | |||
908 | 986 | ||
909 | setup_real_mode(); | 987 | setup_real_mode(); |
910 | 988 | ||
989 | trim_platform_memory_ranges(); | ||
990 | |||
911 | init_gbpages(); | 991 | init_gbpages(); |
912 | 992 | ||
913 | /* max_pfn_mapped is updated here */ | 993 | /* max_pfn_mapped is updated here */ |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 76f54461f7cb..c243b81e3c74 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -120,7 +120,7 @@ struct kvm_shared_msrs { | |||
120 | }; | 120 | }; |
121 | 121 | ||
122 | static struct kvm_shared_msrs_global __read_mostly shared_msrs_global; | 122 | static struct kvm_shared_msrs_global __read_mostly shared_msrs_global; |
123 | static DEFINE_PER_CPU(struct kvm_shared_msrs, shared_msrs); | 123 | static struct kvm_shared_msrs __percpu *shared_msrs; |
124 | 124 | ||
125 | struct kvm_stats_debugfs_item debugfs_entries[] = { | 125 | struct kvm_stats_debugfs_item debugfs_entries[] = { |
126 | { "pf_fixed", VCPU_STAT(pf_fixed) }, | 126 | { "pf_fixed", VCPU_STAT(pf_fixed) }, |
@@ -191,10 +191,10 @@ static void kvm_on_user_return(struct user_return_notifier *urn) | |||
191 | 191 | ||
192 | static void shared_msr_update(unsigned slot, u32 msr) | 192 | static void shared_msr_update(unsigned slot, u32 msr) |
193 | { | 193 | { |
194 | struct kvm_shared_msrs *smsr; | ||
195 | u64 value; | 194 | u64 value; |
195 | unsigned int cpu = smp_processor_id(); | ||
196 | struct kvm_shared_msrs *smsr = per_cpu_ptr(shared_msrs, cpu); | ||
196 | 197 | ||
197 | smsr = &__get_cpu_var(shared_msrs); | ||
198 | /* only read, and nobody should modify it at this time, | 198 | /* only read, and nobody should modify it at this time, |
199 | * so don't need lock */ | 199 | * so don't need lock */ |
200 | if (slot >= shared_msrs_global.nr) { | 200 | if (slot >= shared_msrs_global.nr) { |
@@ -226,7 +226,8 @@ static void kvm_shared_msr_cpu_online(void) | |||
226 | 226 | ||
227 | void kvm_set_shared_msr(unsigned slot, u64 value, u64 mask) | 227 | void kvm_set_shared_msr(unsigned slot, u64 value, u64 mask) |
228 | { | 228 | { |
229 | struct kvm_shared_msrs *smsr = &__get_cpu_var(shared_msrs); | 229 | unsigned int cpu = smp_processor_id(); |
230 | struct kvm_shared_msrs *smsr = per_cpu_ptr(shared_msrs, cpu); | ||
230 | 231 | ||
231 | if (((value ^ smsr->values[slot].curr) & mask) == 0) | 232 | if (((value ^ smsr->values[slot].curr) & mask) == 0) |
232 | return; | 233 | return; |
@@ -242,7 +243,8 @@ EXPORT_SYMBOL_GPL(kvm_set_shared_msr); | |||
242 | 243 | ||
243 | static void drop_user_return_notifiers(void *ignore) | 244 | static void drop_user_return_notifiers(void *ignore) |
244 | { | 245 | { |
245 | struct kvm_shared_msrs *smsr = &__get_cpu_var(shared_msrs); | 246 | unsigned int cpu = smp_processor_id(); |
247 | struct kvm_shared_msrs *smsr = per_cpu_ptr(shared_msrs, cpu); | ||
246 | 248 | ||
247 | if (smsr->registered) | 249 | if (smsr->registered) |
248 | kvm_on_user_return(&smsr->urn); | 250 | kvm_on_user_return(&smsr->urn); |
@@ -5233,9 +5235,16 @@ int kvm_arch_init(void *opaque) | |||
5233 | goto out; | 5235 | goto out; |
5234 | } | 5236 | } |
5235 | 5237 | ||
5238 | r = -ENOMEM; | ||
5239 | shared_msrs = alloc_percpu(struct kvm_shared_msrs); | ||
5240 | if (!shared_msrs) { | ||
5241 | printk(KERN_ERR "kvm: failed to allocate percpu kvm_shared_msrs\n"); | ||
5242 | goto out; | ||
5243 | } | ||
5244 | |||
5236 | r = kvm_mmu_module_init(); | 5245 | r = kvm_mmu_module_init(); |
5237 | if (r) | 5246 | if (r) |
5238 | goto out; | 5247 | goto out_free_percpu; |
5239 | 5248 | ||
5240 | kvm_set_mmio_spte_mask(); | 5249 | kvm_set_mmio_spte_mask(); |
5241 | kvm_init_msr_list(); | 5250 | kvm_init_msr_list(); |
@@ -5258,6 +5267,8 @@ int kvm_arch_init(void *opaque) | |||
5258 | 5267 | ||
5259 | return 0; | 5268 | return 0; |
5260 | 5269 | ||
5270 | out_free_percpu: | ||
5271 | free_percpu(shared_msrs); | ||
5261 | out: | 5272 | out: |
5262 | return r; | 5273 | return r; |
5263 | } | 5274 | } |
@@ -5275,6 +5286,7 @@ void kvm_arch_exit(void) | |||
5275 | #endif | 5286 | #endif |
5276 | kvm_x86_ops = NULL; | 5287 | kvm_x86_ops = NULL; |
5277 | kvm_mmu_module_exit(); | 5288 | kvm_mmu_module_exit(); |
5289 | free_percpu(shared_msrs); | ||
5278 | } | 5290 | } |
5279 | 5291 | ||
5280 | int kvm_emulate_halt(struct kvm_vcpu *vcpu) | 5292 | int kvm_emulate_halt(struct kvm_vcpu *vcpu) |
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 95af6f674a6c..35da18113216 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c | |||
@@ -297,7 +297,7 @@ static int acpi_platform_notify(struct device *dev) | |||
297 | if (!ret) { | 297 | if (!ret) { |
298 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 298 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
299 | 299 | ||
300 | acpi_get_name(dev->acpi_handle, ACPI_FULL_PATHNAME, &buffer); | 300 | acpi_get_name(ACPI_HANDLE(dev), ACPI_FULL_PATHNAME, &buffer); |
301 | DBG("Device %s -> %s\n", dev_name(dev), (char *)buffer.pointer); | 301 | DBG("Device %s -> %s\n", dev_name(dev), (char *)buffer.pointer); |
302 | kfree(buffer.pointer); | 302 | kfree(buffer.pointer); |
303 | } else | 303 | } else |
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 63452943abd1..fb10728f6372 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c | |||
@@ -224,7 +224,7 @@ static void cpu_device_release(struct device *dev) | |||
224 | * by the cpu device. | 224 | * by the cpu device. |
225 | * | 225 | * |
226 | * Never copy this way of doing things, or you too will be made fun of | 226 | * Never copy this way of doing things, or you too will be made fun of |
227 | * on the linux-kerenl list, you have been warned. | 227 | * on the linux-kernel list, you have been warned. |
228 | */ | 228 | */ |
229 | } | 229 | } |
230 | 230 | ||
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index d81460309182..b392b353be39 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
@@ -305,7 +305,7 @@ static bool fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf | |||
305 | char *buf; | 305 | char *buf; |
306 | 306 | ||
307 | size = fw_file_size(file); | 307 | size = fw_file_size(file); |
308 | if (size < 0) | 308 | if (size <= 0) |
309 | return false; | 309 | return false; |
310 | buf = vmalloc(size); | 310 | buf = vmalloc(size); |
311 | if (!buf) | 311 | if (!buf) |
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 07aad786f817..46a213a596e2 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c | |||
@@ -56,6 +56,19 @@ static const struct file_operations regmap_name_fops = { | |||
56 | .llseek = default_llseek, | 56 | .llseek = default_llseek, |
57 | }; | 57 | }; |
58 | 58 | ||
59 | static void regmap_debugfs_free_dump_cache(struct regmap *map) | ||
60 | { | ||
61 | struct regmap_debugfs_off_cache *c; | ||
62 | |||
63 | while (!list_empty(&map->debugfs_off_cache)) { | ||
64 | c = list_first_entry(&map->debugfs_off_cache, | ||
65 | struct regmap_debugfs_off_cache, | ||
66 | list); | ||
67 | list_del(&c->list); | ||
68 | kfree(c); | ||
69 | } | ||
70 | } | ||
71 | |||
59 | /* | 72 | /* |
60 | * Work out where the start offset maps into register numbers, bearing | 73 | * Work out where the start offset maps into register numbers, bearing |
61 | * in mind that we suppress hidden registers. | 74 | * in mind that we suppress hidden registers. |
@@ -91,8 +104,10 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map, | |||
91 | /* No cache entry? Start a new one */ | 104 | /* No cache entry? Start a new one */ |
92 | if (!c) { | 105 | if (!c) { |
93 | c = kzalloc(sizeof(*c), GFP_KERNEL); | 106 | c = kzalloc(sizeof(*c), GFP_KERNEL); |
94 | if (!c) | 107 | if (!c) { |
95 | break; | 108 | regmap_debugfs_free_dump_cache(map); |
109 | return base; | ||
110 | } | ||
96 | c->min = p; | 111 | c->min = p; |
97 | c->base_reg = i; | 112 | c->base_reg = i; |
98 | } | 113 | } |
@@ -101,14 +116,34 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map, | |||
101 | } | 116 | } |
102 | } | 117 | } |
103 | 118 | ||
119 | /* Close the last entry off if we didn't scan beyond it */ | ||
120 | if (c) { | ||
121 | c->max = p - 1; | ||
122 | list_add_tail(&c->list, | ||
123 | &map->debugfs_off_cache); | ||
124 | } else { | ||
125 | return base; | ||
126 | } | ||
127 | |||
128 | /* | ||
129 | * This should never happen; we return above if we fail to | ||
130 | * allocate and we should never be in this code if there are | ||
131 | * no registers at all. | ||
132 | */ | ||
133 | if (list_empty(&map->debugfs_off_cache)) { | ||
134 | WARN_ON(list_empty(&map->debugfs_off_cache)); | ||
135 | return base; | ||
136 | } | ||
137 | |||
104 | /* Find the relevant block */ | 138 | /* Find the relevant block */ |
105 | list_for_each_entry(c, &map->debugfs_off_cache, list) { | 139 | list_for_each_entry(c, &map->debugfs_off_cache, list) { |
106 | if (*pos >= c->min && *pos <= c->max) { | 140 | if (from >= c->min && from <= c->max) { |
107 | *pos = c->min; | 141 | *pos = c->min; |
108 | return c->base_reg; | 142 | return c->base_reg; |
109 | } | 143 | } |
110 | 144 | ||
111 | ret = c->max; | 145 | *pos = c->min; |
146 | ret = c->base_reg; | ||
112 | } | 147 | } |
113 | 148 | ||
114 | return ret; | 149 | return ret; |
@@ -387,16 +422,8 @@ void regmap_debugfs_init(struct regmap *map, const char *name) | |||
387 | 422 | ||
388 | void regmap_debugfs_exit(struct regmap *map) | 423 | void regmap_debugfs_exit(struct regmap *map) |
389 | { | 424 | { |
390 | struct regmap_debugfs_off_cache *c; | ||
391 | |||
392 | debugfs_remove_recursive(map->debugfs); | 425 | debugfs_remove_recursive(map->debugfs); |
393 | while (!list_empty(&map->debugfs_off_cache)) { | 426 | regmap_debugfs_free_dump_cache(map); |
394 | c = list_first_entry(&map->debugfs_off_cache, | ||
395 | struct regmap_debugfs_off_cache, | ||
396 | list); | ||
397 | list_del(&c->list); | ||
398 | kfree(c); | ||
399 | } | ||
400 | kfree(map->debugfs_name); | 427 | kfree(map->debugfs_name); |
401 | } | 428 | } |
402 | 429 | ||
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index fb4a7dd57f94..e1f6860e069c 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c | |||
@@ -69,24 +69,15 @@ int cpuidle_play_dead(void) | |||
69 | { | 69 | { |
70 | struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); | 70 | struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); |
71 | struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); | 71 | struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); |
72 | int i, dead_state = -1; | 72 | int i; |
73 | int power_usage = INT_MAX; | ||
74 | 73 | ||
75 | if (!drv) | 74 | if (!drv) |
76 | return -ENODEV; | 75 | return -ENODEV; |
77 | 76 | ||
78 | /* Find lowest-power state that supports long-term idle */ | 77 | /* Find lowest-power state that supports long-term idle */ |
79 | for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) { | 78 | for (i = drv->state_count - 1; i >= CPUIDLE_DRIVER_STATE_START; i--) |
80 | struct cpuidle_state *s = &drv->states[i]; | 79 | if (drv->states[i].enter_dead) |
81 | 80 | return drv->states[i].enter_dead(dev, i); | |
82 | if (s->power_usage < power_usage && s->enter_dead) { | ||
83 | power_usage = s->power_usage; | ||
84 | dead_state = i; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | if (dead_state != -1) | ||
89 | return drv->states[dead_state].enter_dead(dev, dead_state); | ||
90 | 81 | ||
91 | return -ENODEV; | 82 | return -ENODEV; |
92 | } | 83 | } |
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index c2b281afe0ed..422c7b69ba7c 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c | |||
@@ -19,34 +19,9 @@ DEFINE_SPINLOCK(cpuidle_driver_lock); | |||
19 | static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu); | 19 | static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu); |
20 | static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu); | 20 | static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu); |
21 | 21 | ||
22 | static void set_power_states(struct cpuidle_driver *drv) | ||
23 | { | ||
24 | int i; | ||
25 | |||
26 | /* | ||
27 | * cpuidle driver should set the drv->power_specified bit | ||
28 | * before registering if the driver provides | ||
29 | * power_usage numbers. | ||
30 | * | ||
31 | * If power_specified is not set, | ||
32 | * we fill in power_usage with decreasing values as the | ||
33 | * cpuidle code has an implicit assumption that state Cn | ||
34 | * uses less power than C(n-1). | ||
35 | * | ||
36 | * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned | ||
37 | * an power value of -1. So we use -2, -3, etc, for other | ||
38 | * c-states. | ||
39 | */ | ||
40 | for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) | ||
41 | drv->states[i].power_usage = -1 - i; | ||
42 | } | ||
43 | |||
44 | static void __cpuidle_driver_init(struct cpuidle_driver *drv) | 22 | static void __cpuidle_driver_init(struct cpuidle_driver *drv) |
45 | { | 23 | { |
46 | drv->refcnt = 0; | 24 | drv->refcnt = 0; |
47 | |||
48 | if (!drv->power_specified) | ||
49 | set_power_states(drv); | ||
50 | } | 25 | } |
51 | 26 | ||
52 | static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu) | 27 | static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu) |
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 20ea33afdda1..fe343a06b7da 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c | |||
@@ -312,7 +312,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) | |||
312 | { | 312 | { |
313 | struct menu_device *data = &__get_cpu_var(menu_devices); | 313 | struct menu_device *data = &__get_cpu_var(menu_devices); |
314 | int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); | 314 | int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); |
315 | int power_usage = INT_MAX; | ||
316 | int i; | 315 | int i; |
317 | int multiplier; | 316 | int multiplier; |
318 | struct timespec t; | 317 | struct timespec t; |
@@ -383,11 +382,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) | |||
383 | if (s->exit_latency * multiplier > data->predicted_us) | 382 | if (s->exit_latency * multiplier > data->predicted_us) |
384 | continue; | 383 | continue; |
385 | 384 | ||
386 | if (s->power_usage < power_usage) { | 385 | data->last_state_idx = i; |
387 | power_usage = s->power_usage; | 386 | data->exit_us = s->exit_latency; |
388 | data->last_state_idx = i; | ||
389 | data->exit_us = s->exit_latency; | ||
390 | } | ||
391 | } | 387 | } |
392 | 388 | ||
393 | /* not deepest C-state chosen for low predicted residency */ | 389 | /* not deepest C-state chosen for low predicted residency */ |
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 340942946106..428754af6236 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c | |||
@@ -374,7 +374,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device) | |||
374 | struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device); | 374 | struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device); |
375 | 375 | ||
376 | /* state statistics */ | 376 | /* state statistics */ |
377 | for (i = 0; i < drv->state_count; i++) { | 377 | for (i = 0; i < device->state_count; i++) { |
378 | kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL); | 378 | kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL); |
379 | if (!kobj) | 379 | if (!kobj) |
380 | goto error_state; | 380 | goto error_state; |
diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index 2d2c2f8d6dc6..df0d0a08097a 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c | |||
@@ -94,9 +94,9 @@ static int ast_drm_thaw(struct drm_device *dev) | |||
94 | ast_post_gpu(dev); | 94 | ast_post_gpu(dev); |
95 | 95 | ||
96 | drm_mode_config_reset(dev); | 96 | drm_mode_config_reset(dev); |
97 | mutex_lock(&dev->mode_config.mutex); | 97 | drm_modeset_lock_all(dev); |
98 | drm_helper_resume_force_mode(dev); | 98 | drm_helper_resume_force_mode(dev); |
99 | mutex_unlock(&dev->mode_config.mutex); | 99 | drm_modeset_unlock_all(dev); |
100 | 100 | ||
101 | console_lock(); | 101 | console_lock(); |
102 | ast_fbdev_set_suspend(dev, 0); | 102 | ast_fbdev_set_suspend(dev, 0); |
diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 5ccf984f063a..528429252f0f 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h | |||
@@ -98,6 +98,8 @@ struct ast_private { | |||
98 | 98 | ||
99 | struct drm_gem_object *cursor_cache; | 99 | struct drm_gem_object *cursor_cache; |
100 | uint64_t cursor_cache_gpu_addr; | 100 | uint64_t cursor_cache_gpu_addr; |
101 | /* Acces to this cache is protected by the crtc->mutex of the only crtc | ||
102 | * we have. */ | ||
101 | struct ttm_bo_kmap_obj cache_kmap; | 103 | struct ttm_bo_kmap_obj cache_kmap; |
102 | int next_cursor; | 104 | int next_cursor; |
103 | }; | 105 | }; |
diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c index d9ec77959dff..3e6584b940dc 100644 --- a/drivers/gpu/drm/ast/ast_fb.c +++ b/drivers/gpu/drm/ast/ast_fb.c | |||
@@ -290,6 +290,7 @@ static void ast_fbdev_destroy(struct drm_device *dev, | |||
290 | drm_fb_helper_fini(&afbdev->helper); | 290 | drm_fb_helper_fini(&afbdev->helper); |
291 | 291 | ||
292 | vfree(afbdev->sysram); | 292 | vfree(afbdev->sysram); |
293 | drm_framebuffer_unregister_private(&afb->base); | ||
293 | drm_framebuffer_cleanup(&afb->base); | 294 | drm_framebuffer_cleanup(&afb->base); |
294 | } | 295 | } |
295 | 296 | ||
diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index f668e6cc0f7a..f60fd7bd1183 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c | |||
@@ -246,16 +246,8 @@ static void ast_user_framebuffer_destroy(struct drm_framebuffer *fb) | |||
246 | kfree(fb); | 246 | kfree(fb); |
247 | } | 247 | } |
248 | 248 | ||
249 | static int ast_user_framebuffer_create_handle(struct drm_framebuffer *fb, | ||
250 | struct drm_file *file, | ||
251 | unsigned int *handle) | ||
252 | { | ||
253 | return -EINVAL; | ||
254 | } | ||
255 | |||
256 | static const struct drm_framebuffer_funcs ast_fb_funcs = { | 249 | static const struct drm_framebuffer_funcs ast_fb_funcs = { |
257 | .destroy = ast_user_framebuffer_destroy, | 250 | .destroy = ast_user_framebuffer_destroy, |
258 | .create_handle = ast_user_framebuffer_create_handle, | ||
259 | }; | 251 | }; |
260 | 252 | ||
261 | 253 | ||
@@ -266,13 +258,13 @@ int ast_framebuffer_init(struct drm_device *dev, | |||
266 | { | 258 | { |
267 | int ret; | 259 | int ret; |
268 | 260 | ||
261 | drm_helper_mode_fill_fb_struct(&ast_fb->base, mode_cmd); | ||
262 | ast_fb->obj = obj; | ||
269 | ret = drm_framebuffer_init(dev, &ast_fb->base, &ast_fb_funcs); | 263 | ret = drm_framebuffer_init(dev, &ast_fb->base, &ast_fb_funcs); |
270 | if (ret) { | 264 | if (ret) { |
271 | DRM_ERROR("framebuffer init failed %d\n", ret); | 265 | DRM_ERROR("framebuffer init failed %d\n", ret); |
272 | return ret; | 266 | return ret; |
273 | } | 267 | } |
274 | drm_helper_mode_fill_fb_struct(&ast_fb->base, mode_cmd); | ||
275 | ast_fb->obj = obj; | ||
276 | return 0; | 268 | return 0; |
277 | } | 269 | } |
278 | 270 | ||
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c index 6c6b4c87d309..3daea0f638c3 100644 --- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c +++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c | |||
@@ -258,6 +258,7 @@ static int cirrus_fbdev_destroy(struct drm_device *dev, | |||
258 | 258 | ||
259 | vfree(gfbdev->sysram); | 259 | vfree(gfbdev->sysram); |
260 | drm_fb_helper_fini(&gfbdev->helper); | 260 | drm_fb_helper_fini(&gfbdev->helper); |
261 | drm_framebuffer_unregister_private(&gfb->base); | ||
261 | drm_framebuffer_cleanup(&gfb->base); | 262 | drm_framebuffer_cleanup(&gfb->base); |
262 | 263 | ||
263 | return 0; | 264 | return 0; |
diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c index 6a9b12e88d46..35cbae827771 100644 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ b/drivers/gpu/drm/cirrus/cirrus_main.c | |||
@@ -23,16 +23,8 @@ static void cirrus_user_framebuffer_destroy(struct drm_framebuffer *fb) | |||
23 | kfree(fb); | 23 | kfree(fb); |
24 | } | 24 | } |
25 | 25 | ||
26 | static int cirrus_user_framebuffer_create_handle(struct drm_framebuffer *fb, | ||
27 | struct drm_file *file_priv, | ||
28 | unsigned int *handle) | ||
29 | { | ||
30 | return 0; | ||
31 | } | ||
32 | |||
33 | static const struct drm_framebuffer_funcs cirrus_fb_funcs = { | 26 | static const struct drm_framebuffer_funcs cirrus_fb_funcs = { |
34 | .destroy = cirrus_user_framebuffer_destroy, | 27 | .destroy = cirrus_user_framebuffer_destroy, |
35 | .create_handle = cirrus_user_framebuffer_create_handle, | ||
36 | }; | 28 | }; |
37 | 29 | ||
38 | int cirrus_framebuffer_init(struct drm_device *dev, | 30 | int cirrus_framebuffer_init(struct drm_device *dev, |
@@ -42,13 +34,13 @@ int cirrus_framebuffer_init(struct drm_device *dev, | |||
42 | { | 34 | { |
43 | int ret; | 35 | int ret; |
44 | 36 | ||
37 | drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd); | ||
38 | gfb->obj = obj; | ||
45 | ret = drm_framebuffer_init(dev, &gfb->base, &cirrus_fb_funcs); | 39 | ret = drm_framebuffer_init(dev, &gfb->base, &cirrus_fb_funcs); |
46 | if (ret) { | 40 | if (ret) { |
47 | DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); | 41 | DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); |
48 | return ret; | 42 | return ret; |
49 | } | 43 | } |
50 | drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd); | ||
51 | gfb->obj = obj; | ||
52 | return 0; | 44 | return 0; |
53 | } | 45 | } |
54 | 46 | ||
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f2d667b8bee2..9c797f6fea75 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -37,6 +37,40 @@ | |||
37 | #include <drm/drm_edid.h> | 37 | #include <drm/drm_edid.h> |
38 | #include <drm/drm_fourcc.h> | 38 | #include <drm/drm_fourcc.h> |
39 | 39 | ||
40 | /** | ||
41 | * drm_modeset_lock_all - take all modeset locks | ||
42 | * @dev: drm device | ||
43 | * | ||
44 | * This function takes all modeset locks, suitable where a more fine-grained | ||
45 | * scheme isn't (yet) implemented. | ||
46 | */ | ||
47 | void drm_modeset_lock_all(struct drm_device *dev) | ||
48 | { | ||
49 | struct drm_crtc *crtc; | ||
50 | |||
51 | mutex_lock(&dev->mode_config.mutex); | ||
52 | |||
53 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) | ||
54 | mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex); | ||
55 | } | ||
56 | EXPORT_SYMBOL(drm_modeset_lock_all); | ||
57 | |||
58 | /** | ||
59 | * drm_modeset_unlock_all - drop all modeset locks | ||
60 | * @dev: device | ||
61 | */ | ||
62 | void drm_modeset_unlock_all(struct drm_device *dev) | ||
63 | { | ||
64 | struct drm_crtc *crtc; | ||
65 | |||
66 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) | ||
67 | mutex_unlock(&crtc->mutex); | ||
68 | |||
69 | mutex_unlock(&dev->mode_config.mutex); | ||
70 | } | ||
71 | |||
72 | EXPORT_SYMBOL(drm_modeset_unlock_all); | ||
73 | |||
40 | /* Avoid boilerplate. I'm tired of typing. */ | 74 | /* Avoid boilerplate. I'm tired of typing. */ |
41 | #define DRM_ENUM_NAME_FN(fnname, list) \ | 75 | #define DRM_ENUM_NAME_FN(fnname, list) \ |
42 | char *fnname(int val) \ | 76 | char *fnname(int val) \ |
@@ -203,12 +237,10 @@ char *drm_get_connector_status_name(enum drm_connector_status status) | |||
203 | } | 237 | } |
204 | 238 | ||
205 | /** | 239 | /** |
206 | * drm_mode_object_get - allocate a new identifier | 240 | * drm_mode_object_get - allocate a new modeset identifier |
207 | * @dev: DRM device | 241 | * @dev: DRM device |
208 | * @ptr: object pointer, used to generate unique ID | 242 | * @obj: object pointer, used to generate unique ID |
209 | * @type: object type | 243 | * @obj_type: object type |
210 | * | ||
211 | * LOCKING: | ||
212 | * | 244 | * |
213 | * Create a unique identifier based on @ptr in @dev's identifier space. Used | 245 | * Create a unique identifier based on @ptr in @dev's identifier space. Used |
214 | * for tracking modes, CRTCs and connectors. | 246 | * for tracking modes, CRTCs and connectors. |
@@ -231,24 +263,27 @@ again: | |||
231 | 263 | ||
232 | mutex_lock(&dev->mode_config.idr_mutex); | 264 | mutex_lock(&dev->mode_config.idr_mutex); |
233 | ret = idr_get_new_above(&dev->mode_config.crtc_idr, obj, 1, &new_id); | 265 | ret = idr_get_new_above(&dev->mode_config.crtc_idr, obj, 1, &new_id); |
266 | |||
267 | if (!ret) { | ||
268 | /* | ||
269 | * Set up the object linking under the protection of the idr | ||
270 | * lock so that other users can't see inconsistent state. | ||
271 | */ | ||
272 | obj->id = new_id; | ||
273 | obj->type = obj_type; | ||
274 | } | ||
234 | mutex_unlock(&dev->mode_config.idr_mutex); | 275 | mutex_unlock(&dev->mode_config.idr_mutex); |
276 | |||
235 | if (ret == -EAGAIN) | 277 | if (ret == -EAGAIN) |
236 | goto again; | 278 | goto again; |
237 | else if (ret) | ||
238 | return ret; | ||
239 | 279 | ||
240 | obj->id = new_id; | 280 | return ret; |
241 | obj->type = obj_type; | ||
242 | return 0; | ||
243 | } | 281 | } |
244 | 282 | ||
245 | /** | 283 | /** |
246 | * drm_mode_object_put - free an identifer | 284 | * drm_mode_object_put - free a modeset identifer |
247 | * @dev: DRM device | 285 | * @dev: DRM device |
248 | * @id: ID to free | 286 | * @object: object to free |
249 | * | ||
250 | * LOCKING: | ||
251 | * Caller must hold DRM mode_config lock. | ||
252 | * | 287 | * |
253 | * Free @id from @dev's unique identifier pool. | 288 | * Free @id from @dev's unique identifier pool. |
254 | */ | 289 | */ |
@@ -260,11 +295,24 @@ static void drm_mode_object_put(struct drm_device *dev, | |||
260 | mutex_unlock(&dev->mode_config.idr_mutex); | 295 | mutex_unlock(&dev->mode_config.idr_mutex); |
261 | } | 296 | } |
262 | 297 | ||
298 | /** | ||
299 | * drm_mode_object_find - look up a drm object with static lifetime | ||
300 | * @dev: drm device | ||
301 | * @id: id of the mode object | ||
302 | * @type: type of the mode object | ||
303 | * | ||
304 | * Note that framebuffers cannot be looked up with this functions - since those | ||
305 | * are reference counted, they need special treatment. | ||
306 | */ | ||
263 | struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, | 307 | struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, |
264 | uint32_t id, uint32_t type) | 308 | uint32_t id, uint32_t type) |
265 | { | 309 | { |
266 | struct drm_mode_object *obj = NULL; | 310 | struct drm_mode_object *obj = NULL; |
267 | 311 | ||
312 | /* Framebuffers are reference counted and need their own lookup | ||
313 | * function.*/ | ||
314 | WARN_ON(type == DRM_MODE_OBJECT_FB); | ||
315 | |||
268 | mutex_lock(&dev->mode_config.idr_mutex); | 316 | mutex_lock(&dev->mode_config.idr_mutex); |
269 | obj = idr_find(&dev->mode_config.crtc_idr, id); | 317 | obj = idr_find(&dev->mode_config.crtc_idr, id); |
270 | if (!obj || (obj->type != type) || (obj->id != id)) | 318 | if (!obj || (obj->type != type) || (obj->id != id)) |
@@ -278,13 +326,18 @@ EXPORT_SYMBOL(drm_mode_object_find); | |||
278 | /** | 326 | /** |
279 | * drm_framebuffer_init - initialize a framebuffer | 327 | * drm_framebuffer_init - initialize a framebuffer |
280 | * @dev: DRM device | 328 | * @dev: DRM device |
281 | * | 329 | * @fb: framebuffer to be initialized |
282 | * LOCKING: | 330 | * @funcs: ... with these functions |
283 | * Caller must hold mode config lock. | ||
284 | * | 331 | * |
285 | * Allocates an ID for the framebuffer's parent mode object, sets its mode | 332 | * Allocates an ID for the framebuffer's parent mode object, sets its mode |
286 | * functions & device file and adds it to the master fd list. | 333 | * functions & device file and adds it to the master fd list. |
287 | * | 334 | * |
335 | * IMPORTANT: | ||
336 | * This functions publishes the fb and makes it available for concurrent access | ||
337 | * by other users. Which means by this point the fb _must_ be fully set up - | ||
338 | * since all the fb attributes are invariant over its lifetime, no further | ||
339 | * locking but only correct reference counting is required. | ||
340 | * | ||
288 | * RETURNS: | 341 | * RETURNS: |
289 | * Zero on success, error code on failure. | 342 | * Zero on success, error code on failure. |
290 | */ | 343 | */ |
@@ -293,16 +346,23 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, | |||
293 | { | 346 | { |
294 | int ret; | 347 | int ret; |
295 | 348 | ||
349 | mutex_lock(&dev->mode_config.fb_lock); | ||
296 | kref_init(&fb->refcount); | 350 | kref_init(&fb->refcount); |
351 | INIT_LIST_HEAD(&fb->filp_head); | ||
352 | fb->dev = dev; | ||
353 | fb->funcs = funcs; | ||
297 | 354 | ||
298 | ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); | 355 | ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); |
299 | if (ret) | 356 | if (ret) |
300 | return ret; | 357 | goto out; |
358 | |||
359 | /* Grab the idr reference. */ | ||
360 | drm_framebuffer_reference(fb); | ||
301 | 361 | ||
302 | fb->dev = dev; | ||
303 | fb->funcs = funcs; | ||
304 | dev->mode_config.num_fb++; | 362 | dev->mode_config.num_fb++; |
305 | list_add(&fb->head, &dev->mode_config.fb_list); | 363 | list_add(&fb->head, &dev->mode_config.fb_list); |
364 | out: | ||
365 | mutex_unlock(&dev->mode_config.fb_lock); | ||
306 | 366 | ||
307 | return 0; | 367 | return 0; |
308 | } | 368 | } |
@@ -315,23 +375,63 @@ static void drm_framebuffer_free(struct kref *kref) | |||
315 | fb->funcs->destroy(fb); | 375 | fb->funcs->destroy(fb); |
316 | } | 376 | } |
317 | 377 | ||
378 | static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev, | ||
379 | uint32_t id) | ||
380 | { | ||
381 | struct drm_mode_object *obj = NULL; | ||
382 | struct drm_framebuffer *fb; | ||
383 | |||
384 | mutex_lock(&dev->mode_config.idr_mutex); | ||
385 | obj = idr_find(&dev->mode_config.crtc_idr, id); | ||
386 | if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id)) | ||
387 | fb = NULL; | ||
388 | else | ||
389 | fb = obj_to_fb(obj); | ||
390 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
391 | |||
392 | return fb; | ||
393 | } | ||
394 | |||
395 | /** | ||
396 | * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference | ||
397 | * @dev: drm device | ||
398 | * @id: id of the fb object | ||
399 | * | ||
400 | * If successful, this grabs an additional reference to the framebuffer - | ||
401 | * callers need to make sure to eventually unreference the returned framebuffer | ||
402 | * again. | ||
403 | */ | ||
404 | struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, | ||
405 | uint32_t id) | ||
406 | { | ||
407 | struct drm_framebuffer *fb; | ||
408 | |||
409 | mutex_lock(&dev->mode_config.fb_lock); | ||
410 | fb = __drm_framebuffer_lookup(dev, id); | ||
411 | if (fb) | ||
412 | kref_get(&fb->refcount); | ||
413 | mutex_unlock(&dev->mode_config.fb_lock); | ||
414 | |||
415 | return fb; | ||
416 | } | ||
417 | EXPORT_SYMBOL(drm_framebuffer_lookup); | ||
418 | |||
318 | /** | 419 | /** |
319 | * drm_framebuffer_unreference - unref a framebuffer | 420 | * drm_framebuffer_unreference - unref a framebuffer |
421 | * @fb: framebuffer to unref | ||
320 | * | 422 | * |
321 | * LOCKING: | 423 | * This functions decrements the fb's refcount and frees it if it drops to zero. |
322 | * Caller must hold mode config lock. | ||
323 | */ | 424 | */ |
324 | void drm_framebuffer_unreference(struct drm_framebuffer *fb) | 425 | void drm_framebuffer_unreference(struct drm_framebuffer *fb) |
325 | { | 426 | { |
326 | struct drm_device *dev = fb->dev; | ||
327 | DRM_DEBUG("FB ID: %d\n", fb->base.id); | 427 | DRM_DEBUG("FB ID: %d\n", fb->base.id); |
328 | WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); | ||
329 | kref_put(&fb->refcount, drm_framebuffer_free); | 428 | kref_put(&fb->refcount, drm_framebuffer_free); |
330 | } | 429 | } |
331 | EXPORT_SYMBOL(drm_framebuffer_unreference); | 430 | EXPORT_SYMBOL(drm_framebuffer_unreference); |
332 | 431 | ||
333 | /** | 432 | /** |
334 | * drm_framebuffer_reference - incr the fb refcnt | 433 | * drm_framebuffer_reference - incr the fb refcnt |
434 | * @fb: framebuffer | ||
335 | */ | 435 | */ |
336 | void drm_framebuffer_reference(struct drm_framebuffer *fb) | 436 | void drm_framebuffer_reference(struct drm_framebuffer *fb) |
337 | { | 437 | { |
@@ -340,29 +440,74 @@ void drm_framebuffer_reference(struct drm_framebuffer *fb) | |||
340 | } | 440 | } |
341 | EXPORT_SYMBOL(drm_framebuffer_reference); | 441 | EXPORT_SYMBOL(drm_framebuffer_reference); |
342 | 442 | ||
443 | static void drm_framebuffer_free_bug(struct kref *kref) | ||
444 | { | ||
445 | BUG(); | ||
446 | } | ||
447 | |||
448 | static void __drm_framebuffer_unreference(struct drm_framebuffer *fb) | ||
449 | { | ||
450 | DRM_DEBUG("FB ID: %d\n", fb->base.id); | ||
451 | kref_put(&fb->refcount, drm_framebuffer_free_bug); | ||
452 | } | ||
453 | |||
454 | /* dev->mode_config.fb_lock must be held! */ | ||
455 | static void __drm_framebuffer_unregister(struct drm_device *dev, | ||
456 | struct drm_framebuffer *fb) | ||
457 | { | ||
458 | mutex_lock(&dev->mode_config.idr_mutex); | ||
459 | idr_remove(&dev->mode_config.crtc_idr, fb->base.id); | ||
460 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
461 | |||
462 | fb->base.id = 0; | ||
463 | |||
464 | __drm_framebuffer_unreference(fb); | ||
465 | } | ||
466 | |||
467 | /** | ||
468 | * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr | ||
469 | * @fb: fb to unregister | ||
470 | * | ||
471 | * Drivers need to call this when cleaning up driver-private framebuffers, e.g. | ||
472 | * those used for fbdev. Note that the caller must hold a reference of it's own, | ||
473 | * i.e. the object may not be destroyed through this call (since it'll lead to a | ||
474 | * locking inversion). | ||
475 | */ | ||
476 | void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) | ||
477 | { | ||
478 | struct drm_device *dev = fb->dev; | ||
479 | |||
480 | mutex_lock(&dev->mode_config.fb_lock); | ||
481 | /* Mark fb as reaped and drop idr ref. */ | ||
482 | __drm_framebuffer_unregister(dev, fb); | ||
483 | mutex_unlock(&dev->mode_config.fb_lock); | ||
484 | } | ||
485 | EXPORT_SYMBOL(drm_framebuffer_unregister_private); | ||
486 | |||
343 | /** | 487 | /** |
344 | * drm_framebuffer_cleanup - remove a framebuffer object | 488 | * drm_framebuffer_cleanup - remove a framebuffer object |
345 | * @fb: framebuffer to remove | 489 | * @fb: framebuffer to remove |
346 | * | 490 | * |
347 | * LOCKING: | 491 | * Cleanup references to a user-created framebuffer. This function is intended |
348 | * Caller must hold mode config lock. | 492 | * to be used from the drivers ->destroy callback. |
493 | * | ||
494 | * Note that this function does not remove the fb from active usuage - if it is | ||
495 | * still used anywhere, hilarity can ensue since userspace could call getfb on | ||
496 | * the id and get back -EINVAL. Obviously no concern at driver unload time. | ||
349 | * | 497 | * |
350 | * Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes | 498 | * Also, the framebuffer will not be removed from the lookup idr - for |
351 | * it, setting it to NULL. | 499 | * user-created framebuffers this will happen in in the rmfb ioctl. For |
500 | * driver-private objects (e.g. for fbdev) drivers need to explicitly call | ||
501 | * drm_framebuffer_unregister_private. | ||
352 | */ | 502 | */ |
353 | void drm_framebuffer_cleanup(struct drm_framebuffer *fb) | 503 | void drm_framebuffer_cleanup(struct drm_framebuffer *fb) |
354 | { | 504 | { |
355 | struct drm_device *dev = fb->dev; | 505 | struct drm_device *dev = fb->dev; |
356 | /* | 506 | |
357 | * This could be moved to drm_framebuffer_remove(), but for | 507 | mutex_lock(&dev->mode_config.fb_lock); |
358 | * debugging is nice to keep around the list of fb's that are | ||
359 | * no longer associated w/ a drm_file but are not unreferenced | ||
360 | * yet. (i915 and omapdrm have debugfs files which will show | ||
361 | * this.) | ||
362 | */ | ||
363 | drm_mode_object_put(dev, &fb->base); | ||
364 | list_del(&fb->head); | 508 | list_del(&fb->head); |
365 | dev->mode_config.num_fb--; | 509 | dev->mode_config.num_fb--; |
510 | mutex_unlock(&dev->mode_config.fb_lock); | ||
366 | } | 511 | } |
367 | EXPORT_SYMBOL(drm_framebuffer_cleanup); | 512 | EXPORT_SYMBOL(drm_framebuffer_cleanup); |
368 | 513 | ||
@@ -370,11 +515,13 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup); | |||
370 | * drm_framebuffer_remove - remove and unreference a framebuffer object | 515 | * drm_framebuffer_remove - remove and unreference a framebuffer object |
371 | * @fb: framebuffer to remove | 516 | * @fb: framebuffer to remove |
372 | * | 517 | * |
373 | * LOCKING: | ||
374 | * Caller must hold mode config lock. | ||
375 | * | ||
376 | * Scans all the CRTCs and planes in @dev's mode_config. If they're | 518 | * Scans all the CRTCs and planes in @dev's mode_config. If they're |
377 | * using @fb, removes it, setting it to NULL. | 519 | * using @fb, removes it, setting it to NULL. Then drops the reference to the |
520 | * passed-in framebuffer. Might take the modeset locks. | ||
521 | * | ||
522 | * Note that this function optimizes the cleanup away if the caller holds the | ||
523 | * last reference to the framebuffer. It is also guaranteed to not take the | ||
524 | * modeset locks in this case. | ||
378 | */ | 525 | */ |
379 | void drm_framebuffer_remove(struct drm_framebuffer *fb) | 526 | void drm_framebuffer_remove(struct drm_framebuffer *fb) |
380 | { | 527 | { |
@@ -384,33 +531,53 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) | |||
384 | struct drm_mode_set set; | 531 | struct drm_mode_set set; |
385 | int ret; | 532 | int ret; |
386 | 533 | ||
387 | /* remove from any CRTC */ | 534 | WARN_ON(!list_empty(&fb->filp_head)); |
388 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 535 | |
389 | if (crtc->fb == fb) { | 536 | /* |
390 | /* should turn off the crtc */ | 537 | * drm ABI mandates that we remove any deleted framebuffers from active |
391 | memset(&set, 0, sizeof(struct drm_mode_set)); | 538 | * useage. But since most sane clients only remove framebuffers they no |
392 | set.crtc = crtc; | 539 | * longer need, try to optimize this away. |
393 | set.fb = NULL; | 540 | * |
394 | ret = crtc->funcs->set_config(&set); | 541 | * Since we're holding a reference ourselves, observing a refcount of 1 |
395 | if (ret) | 542 | * means that we're the last holder and can skip it. Also, the refcount |
396 | DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); | 543 | * can never increase from 1 again, so we don't need any barriers or |
544 | * locks. | ||
545 | * | ||
546 | * Note that userspace could try to race with use and instate a new | ||
547 | * usage _after_ we've cleared all current ones. End result will be an | ||
548 | * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot | ||
549 | * in this manner. | ||
550 | */ | ||
551 | if (atomic_read(&fb->refcount.refcount) > 1) { | ||
552 | drm_modeset_lock_all(dev); | ||
553 | /* remove from any CRTC */ | ||
554 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
555 | if (crtc->fb == fb) { | ||
556 | /* should turn off the crtc */ | ||
557 | memset(&set, 0, sizeof(struct drm_mode_set)); | ||
558 | set.crtc = crtc; | ||
559 | set.fb = NULL; | ||
560 | ret = drm_mode_set_config_internal(&set); | ||
561 | if (ret) | ||
562 | DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); | ||
563 | } | ||
397 | } | 564 | } |
398 | } | ||
399 | 565 | ||
400 | list_for_each_entry(plane, &dev->mode_config.plane_list, head) { | 566 | list_for_each_entry(plane, &dev->mode_config.plane_list, head) { |
401 | if (plane->fb == fb) { | 567 | if (plane->fb == fb) { |
402 | /* should turn off the crtc */ | 568 | /* should turn off the crtc */ |
403 | ret = plane->funcs->disable_plane(plane); | 569 | ret = plane->funcs->disable_plane(plane); |
404 | if (ret) | 570 | if (ret) |
405 | DRM_ERROR("failed to disable plane with busy fb\n"); | 571 | DRM_ERROR("failed to disable plane with busy fb\n"); |
406 | /* disconnect the plane from the fb and crtc: */ | 572 | /* disconnect the plane from the fb and crtc: */ |
407 | plane->fb = NULL; | 573 | __drm_framebuffer_unreference(plane->fb); |
408 | plane->crtc = NULL; | 574 | plane->fb = NULL; |
575 | plane->crtc = NULL; | ||
576 | } | ||
409 | } | 577 | } |
578 | drm_modeset_unlock_all(dev); | ||
410 | } | 579 | } |
411 | 580 | ||
412 | list_del(&fb->filp_head); | ||
413 | |||
414 | drm_framebuffer_unreference(fb); | 581 | drm_framebuffer_unreference(fb); |
415 | } | 582 | } |
416 | EXPORT_SYMBOL(drm_framebuffer_remove); | 583 | EXPORT_SYMBOL(drm_framebuffer_remove); |
@@ -421,9 +588,6 @@ EXPORT_SYMBOL(drm_framebuffer_remove); | |||
421 | * @crtc: CRTC object to init | 588 | * @crtc: CRTC object to init |
422 | * @funcs: callbacks for the new CRTC | 589 | * @funcs: callbacks for the new CRTC |
423 | * | 590 | * |
424 | * LOCKING: | ||
425 | * Takes mode_config lock. | ||
426 | * | ||
427 | * Inits a new object created as base part of an driver crtc object. | 591 | * Inits a new object created as base part of an driver crtc object. |
428 | * | 592 | * |
429 | * RETURNS: | 593 | * RETURNS: |
@@ -438,7 +602,9 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, | |||
438 | crtc->funcs = funcs; | 602 | crtc->funcs = funcs; |
439 | crtc->invert_dimensions = false; | 603 | crtc->invert_dimensions = false; |
440 | 604 | ||
441 | mutex_lock(&dev->mode_config.mutex); | 605 | drm_modeset_lock_all(dev); |
606 | mutex_init(&crtc->mutex); | ||
607 | mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex); | ||
442 | 608 | ||
443 | ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); | 609 | ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); |
444 | if (ret) | 610 | if (ret) |
@@ -450,7 +616,7 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, | |||
450 | dev->mode_config.num_crtc++; | 616 | dev->mode_config.num_crtc++; |
451 | 617 | ||
452 | out: | 618 | out: |
453 | mutex_unlock(&dev->mode_config.mutex); | 619 | drm_modeset_unlock_all(dev); |
454 | 620 | ||
455 | return ret; | 621 | return ret; |
456 | } | 622 | } |
@@ -460,9 +626,6 @@ EXPORT_SYMBOL(drm_crtc_init); | |||
460 | * drm_crtc_cleanup - Cleans up the core crtc usage. | 626 | * drm_crtc_cleanup - Cleans up the core crtc usage. |
461 | * @crtc: CRTC to cleanup | 627 | * @crtc: CRTC to cleanup |
462 | * | 628 | * |
463 | * LOCKING: | ||
464 | * Caller must hold mode config lock. | ||
465 | * | ||
466 | * Cleanup @crtc. Removes from drm modesetting space | 629 | * Cleanup @crtc. Removes from drm modesetting space |
467 | * does NOT free object, caller does that. | 630 | * does NOT free object, caller does that. |
468 | */ | 631 | */ |
@@ -484,9 +647,6 @@ EXPORT_SYMBOL(drm_crtc_cleanup); | |||
484 | * @connector: connector the new mode | 647 | * @connector: connector the new mode |
485 | * @mode: mode data | 648 | * @mode: mode data |
486 | * | 649 | * |
487 | * LOCKING: | ||
488 | * Caller must hold mode config lock. | ||
489 | * | ||
490 | * Add @mode to @connector's mode list for later use. | 650 | * Add @mode to @connector's mode list for later use. |
491 | */ | 651 | */ |
492 | void drm_mode_probed_add(struct drm_connector *connector, | 652 | void drm_mode_probed_add(struct drm_connector *connector, |
@@ -501,9 +661,6 @@ EXPORT_SYMBOL(drm_mode_probed_add); | |||
501 | * @connector: connector list to modify | 661 | * @connector: connector list to modify |
502 | * @mode: mode to remove | 662 | * @mode: mode to remove |
503 | * | 663 | * |
504 | * LOCKING: | ||
505 | * Caller must hold mode config lock. | ||
506 | * | ||
507 | * Remove @mode from @connector's mode list, then free it. | 664 | * Remove @mode from @connector's mode list, then free it. |
508 | */ | 665 | */ |
509 | void drm_mode_remove(struct drm_connector *connector, | 666 | void drm_mode_remove(struct drm_connector *connector, |
@@ -519,10 +676,7 @@ EXPORT_SYMBOL(drm_mode_remove); | |||
519 | * @dev: DRM device | 676 | * @dev: DRM device |
520 | * @connector: the connector to init | 677 | * @connector: the connector to init |
521 | * @funcs: callbacks for this connector | 678 | * @funcs: callbacks for this connector |
522 | * @name: user visible name of the connector | 679 | * @connector_type: user visible type of the connector |
523 | * | ||
524 | * LOCKING: | ||
525 | * Takes mode config lock. | ||
526 | * | 680 | * |
527 | * Initialises a preallocated connector. Connectors should be | 681 | * Initialises a preallocated connector. Connectors should be |
528 | * subclassed as part of driver connector objects. | 682 | * subclassed as part of driver connector objects. |
@@ -537,7 +691,7 @@ int drm_connector_init(struct drm_device *dev, | |||
537 | { | 691 | { |
538 | int ret; | 692 | int ret; |
539 | 693 | ||
540 | mutex_lock(&dev->mode_config.mutex); | 694 | drm_modeset_lock_all(dev); |
541 | 695 | ||
542 | ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR); | 696 | ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR); |
543 | if (ret) | 697 | if (ret) |
@@ -567,7 +721,7 @@ int drm_connector_init(struct drm_device *dev, | |||
567 | dev->mode_config.dpms_property, 0); | 721 | dev->mode_config.dpms_property, 0); |
568 | 722 | ||
569 | out: | 723 | out: |
570 | mutex_unlock(&dev->mode_config.mutex); | 724 | drm_modeset_unlock_all(dev); |
571 | 725 | ||
572 | return ret; | 726 | return ret; |
573 | } | 727 | } |
@@ -577,9 +731,6 @@ EXPORT_SYMBOL(drm_connector_init); | |||
577 | * drm_connector_cleanup - cleans up an initialised connector | 731 | * drm_connector_cleanup - cleans up an initialised connector |
578 | * @connector: connector to cleanup | 732 | * @connector: connector to cleanup |
579 | * | 733 | * |
580 | * LOCKING: | ||
581 | * Takes mode config lock. | ||
582 | * | ||
583 | * Cleans up the connector but doesn't free the object. | 734 | * Cleans up the connector but doesn't free the object. |
584 | */ | 735 | */ |
585 | void drm_connector_cleanup(struct drm_connector *connector) | 736 | void drm_connector_cleanup(struct drm_connector *connector) |
@@ -596,11 +747,9 @@ void drm_connector_cleanup(struct drm_connector *connector) | |||
596 | list_for_each_entry_safe(mode, t, &connector->user_modes, head) | 747 | list_for_each_entry_safe(mode, t, &connector->user_modes, head) |
597 | drm_mode_remove(connector, mode); | 748 | drm_mode_remove(connector, mode); |
598 | 749 | ||
599 | mutex_lock(&dev->mode_config.mutex); | ||
600 | drm_mode_object_put(dev, &connector->base); | 750 | drm_mode_object_put(dev, &connector->base); |
601 | list_del(&connector->head); | 751 | list_del(&connector->head); |
602 | dev->mode_config.num_connector--; | 752 | dev->mode_config.num_connector--; |
603 | mutex_unlock(&dev->mode_config.mutex); | ||
604 | } | 753 | } |
605 | EXPORT_SYMBOL(drm_connector_cleanup); | 754 | EXPORT_SYMBOL(drm_connector_cleanup); |
606 | 755 | ||
@@ -622,7 +771,7 @@ int drm_encoder_init(struct drm_device *dev, | |||
622 | { | 771 | { |
623 | int ret; | 772 | int ret; |
624 | 773 | ||
625 | mutex_lock(&dev->mode_config.mutex); | 774 | drm_modeset_lock_all(dev); |
626 | 775 | ||
627 | ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); | 776 | ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); |
628 | if (ret) | 777 | if (ret) |
@@ -636,7 +785,7 @@ int drm_encoder_init(struct drm_device *dev, | |||
636 | dev->mode_config.num_encoder++; | 785 | dev->mode_config.num_encoder++; |
637 | 786 | ||
638 | out: | 787 | out: |
639 | mutex_unlock(&dev->mode_config.mutex); | 788 | drm_modeset_unlock_all(dev); |
640 | 789 | ||
641 | return ret; | 790 | return ret; |
642 | } | 791 | } |
@@ -645,11 +794,11 @@ EXPORT_SYMBOL(drm_encoder_init); | |||
645 | void drm_encoder_cleanup(struct drm_encoder *encoder) | 794 | void drm_encoder_cleanup(struct drm_encoder *encoder) |
646 | { | 795 | { |
647 | struct drm_device *dev = encoder->dev; | 796 | struct drm_device *dev = encoder->dev; |
648 | mutex_lock(&dev->mode_config.mutex); | 797 | drm_modeset_lock_all(dev); |
649 | drm_mode_object_put(dev, &encoder->base); | 798 | drm_mode_object_put(dev, &encoder->base); |
650 | list_del(&encoder->head); | 799 | list_del(&encoder->head); |
651 | dev->mode_config.num_encoder--; | 800 | dev->mode_config.num_encoder--; |
652 | mutex_unlock(&dev->mode_config.mutex); | 801 | drm_modeset_unlock_all(dev); |
653 | } | 802 | } |
654 | EXPORT_SYMBOL(drm_encoder_cleanup); | 803 | EXPORT_SYMBOL(drm_encoder_cleanup); |
655 | 804 | ||
@@ -661,7 +810,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, | |||
661 | { | 810 | { |
662 | int ret; | 811 | int ret; |
663 | 812 | ||
664 | mutex_lock(&dev->mode_config.mutex); | 813 | drm_modeset_lock_all(dev); |
665 | 814 | ||
666 | ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); | 815 | ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE); |
667 | if (ret) | 816 | if (ret) |
@@ -695,7 +844,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, | |||
695 | } | 844 | } |
696 | 845 | ||
697 | out: | 846 | out: |
698 | mutex_unlock(&dev->mode_config.mutex); | 847 | drm_modeset_unlock_all(dev); |
699 | 848 | ||
700 | return ret; | 849 | return ret; |
701 | } | 850 | } |
@@ -705,7 +854,7 @@ void drm_plane_cleanup(struct drm_plane *plane) | |||
705 | { | 854 | { |
706 | struct drm_device *dev = plane->dev; | 855 | struct drm_device *dev = plane->dev; |
707 | 856 | ||
708 | mutex_lock(&dev->mode_config.mutex); | 857 | drm_modeset_lock_all(dev); |
709 | kfree(plane->format_types); | 858 | kfree(plane->format_types); |
710 | drm_mode_object_put(dev, &plane->base); | 859 | drm_mode_object_put(dev, &plane->base); |
711 | /* if not added to a list, it must be a private plane */ | 860 | /* if not added to a list, it must be a private plane */ |
@@ -713,7 +862,7 @@ void drm_plane_cleanup(struct drm_plane *plane) | |||
713 | list_del(&plane->head); | 862 | list_del(&plane->head); |
714 | dev->mode_config.num_plane--; | 863 | dev->mode_config.num_plane--; |
715 | } | 864 | } |
716 | mutex_unlock(&dev->mode_config.mutex); | 865 | drm_modeset_unlock_all(dev); |
717 | } | 866 | } |
718 | EXPORT_SYMBOL(drm_plane_cleanup); | 867 | EXPORT_SYMBOL(drm_plane_cleanup); |
719 | 868 | ||
@@ -721,9 +870,6 @@ EXPORT_SYMBOL(drm_plane_cleanup); | |||
721 | * drm_mode_create - create a new display mode | 870 | * drm_mode_create - create a new display mode |
722 | * @dev: DRM device | 871 | * @dev: DRM device |
723 | * | 872 | * |
724 | * LOCKING: | ||
725 | * Caller must hold DRM mode_config lock. | ||
726 | * | ||
727 | * Create a new drm_display_mode, give it an ID, and return it. | 873 | * Create a new drm_display_mode, give it an ID, and return it. |
728 | * | 874 | * |
729 | * RETURNS: | 875 | * RETURNS: |
@@ -751,9 +897,6 @@ EXPORT_SYMBOL(drm_mode_create); | |||
751 | * @dev: DRM device | 897 | * @dev: DRM device |
752 | * @mode: mode to remove | 898 | * @mode: mode to remove |
753 | * | 899 | * |
754 | * LOCKING: | ||
755 | * Caller must hold mode config lock. | ||
756 | * | ||
757 | * Free @mode's unique identifier, then free it. | 900 | * Free @mode's unique identifier, then free it. |
758 | */ | 901 | */ |
759 | void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) | 902 | void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) |
@@ -978,16 +1121,19 @@ EXPORT_SYMBOL(drm_mode_create_dirty_info_property); | |||
978 | * drm_mode_config_init - initialize DRM mode_configuration structure | 1121 | * drm_mode_config_init - initialize DRM mode_configuration structure |
979 | * @dev: DRM device | 1122 | * @dev: DRM device |
980 | * | 1123 | * |
981 | * LOCKING: | ||
982 | * None, should happen single threaded at init time. | ||
983 | * | ||
984 | * Initialize @dev's mode_config structure, used for tracking the graphics | 1124 | * Initialize @dev's mode_config structure, used for tracking the graphics |
985 | * configuration of @dev. | 1125 | * configuration of @dev. |
1126 | * | ||
1127 | * Since this initializes the modeset locks, no locking is possible. Which is no | ||
1128 | * problem, since this should happen single threaded at init time. It is the | ||
1129 | * driver's problem to ensure this guarantee. | ||
1130 | * | ||
986 | */ | 1131 | */ |
987 | void drm_mode_config_init(struct drm_device *dev) | 1132 | void drm_mode_config_init(struct drm_device *dev) |
988 | { | 1133 | { |
989 | mutex_init(&dev->mode_config.mutex); | 1134 | mutex_init(&dev->mode_config.mutex); |
990 | mutex_init(&dev->mode_config.idr_mutex); | 1135 | mutex_init(&dev->mode_config.idr_mutex); |
1136 | mutex_init(&dev->mode_config.fb_lock); | ||
991 | INIT_LIST_HEAD(&dev->mode_config.fb_list); | 1137 | INIT_LIST_HEAD(&dev->mode_config.fb_list); |
992 | INIT_LIST_HEAD(&dev->mode_config.crtc_list); | 1138 | INIT_LIST_HEAD(&dev->mode_config.crtc_list); |
993 | INIT_LIST_HEAD(&dev->mode_config.connector_list); | 1139 | INIT_LIST_HEAD(&dev->mode_config.connector_list); |
@@ -997,9 +1143,9 @@ void drm_mode_config_init(struct drm_device *dev) | |||
997 | INIT_LIST_HEAD(&dev->mode_config.plane_list); | 1143 | INIT_LIST_HEAD(&dev->mode_config.plane_list); |
998 | idr_init(&dev->mode_config.crtc_idr); | 1144 | idr_init(&dev->mode_config.crtc_idr); |
999 | 1145 | ||
1000 | mutex_lock(&dev->mode_config.mutex); | 1146 | drm_modeset_lock_all(dev); |
1001 | drm_mode_create_standard_connector_properties(dev); | 1147 | drm_mode_create_standard_connector_properties(dev); |
1002 | mutex_unlock(&dev->mode_config.mutex); | 1148 | drm_modeset_unlock_all(dev); |
1003 | 1149 | ||
1004 | /* Just to be sure */ | 1150 | /* Just to be sure */ |
1005 | dev->mode_config.num_fb = 0; | 1151 | dev->mode_config.num_fb = 0; |
@@ -1057,12 +1203,13 @@ EXPORT_SYMBOL(drm_mode_group_init_legacy_group); | |||
1057 | * drm_mode_config_cleanup - free up DRM mode_config info | 1203 | * drm_mode_config_cleanup - free up DRM mode_config info |
1058 | * @dev: DRM device | 1204 | * @dev: DRM device |
1059 | * | 1205 | * |
1060 | * LOCKING: | ||
1061 | * Caller must hold mode config lock. | ||
1062 | * | ||
1063 | * Free up all the connectors and CRTCs associated with this DRM device, then | 1206 | * Free up all the connectors and CRTCs associated with this DRM device, then |
1064 | * free up the framebuffers and associated buffer objects. | 1207 | * free up the framebuffers and associated buffer objects. |
1065 | * | 1208 | * |
1209 | * Note that since this /should/ happen single-threaded at driver/device | ||
1210 | * teardown time, no locking is required. It's the driver's job to ensure that | ||
1211 | * this guarantee actually holds true. | ||
1212 | * | ||
1066 | * FIXME: cleanup any dangling user buffer objects too | 1213 | * FIXME: cleanup any dangling user buffer objects too |
1067 | */ | 1214 | */ |
1068 | void drm_mode_config_cleanup(struct drm_device *dev) | 1215 | void drm_mode_config_cleanup(struct drm_device *dev) |
@@ -1089,6 +1236,15 @@ void drm_mode_config_cleanup(struct drm_device *dev) | |||
1089 | drm_property_destroy(dev, property); | 1236 | drm_property_destroy(dev, property); |
1090 | } | 1237 | } |
1091 | 1238 | ||
1239 | /* | ||
1240 | * Single-threaded teardown context, so it's not required to grab the | ||
1241 | * fb_lock to protect against concurrent fb_list access. Contrary, it | ||
1242 | * would actually deadlock with the drm_framebuffer_cleanup function. | ||
1243 | * | ||
1244 | * Also, if there are any framebuffers left, that's a driver leak now, | ||
1245 | * so politely WARN about this. | ||
1246 | */ | ||
1247 | WARN_ON(!list_empty(&dev->mode_config.fb_list)); | ||
1092 | list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { | 1248 | list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { |
1093 | drm_framebuffer_remove(fb); | 1249 | drm_framebuffer_remove(fb); |
1094 | } | 1250 | } |
@@ -1112,9 +1268,6 @@ EXPORT_SYMBOL(drm_mode_config_cleanup); | |||
1112 | * @out: drm_mode_modeinfo struct to return to the user | 1268 | * @out: drm_mode_modeinfo struct to return to the user |
1113 | * @in: drm_display_mode to use | 1269 | * @in: drm_display_mode to use |
1114 | * | 1270 | * |
1115 | * LOCKING: | ||
1116 | * None. | ||
1117 | * | ||
1118 | * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to | 1271 | * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to |
1119 | * the user. | 1272 | * the user. |
1120 | */ | 1273 | */ |
@@ -1151,9 +1304,6 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, | |||
1151 | * @out: drm_display_mode to return to the user | 1304 | * @out: drm_display_mode to return to the user |
1152 | * @in: drm_mode_modeinfo to use | 1305 | * @in: drm_mode_modeinfo to use |
1153 | * | 1306 | * |
1154 | * LOCKING: | ||
1155 | * None. | ||
1156 | * | ||
1157 | * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to | 1307 | * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to |
1158 | * the caller. | 1308 | * the caller. |
1159 | * | 1309 | * |
@@ -1188,13 +1338,9 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out, | |||
1188 | 1338 | ||
1189 | /** | 1339 | /** |
1190 | * drm_mode_getresources - get graphics configuration | 1340 | * drm_mode_getresources - get graphics configuration |
1191 | * @inode: inode from the ioctl | 1341 | * @dev: drm device for the ioctl |
1192 | * @filp: file * from the ioctl | 1342 | * @data: data pointer for the ioctl |
1193 | * @cmd: cmd from ioctl | 1343 | * @file_priv: drm file for the ioctl call |
1194 | * @arg: arg from ioctl | ||
1195 | * | ||
1196 | * LOCKING: | ||
1197 | * Takes mode config lock. | ||
1198 | * | 1344 | * |
1199 | * Construct a set of configuration description structures and return | 1345 | * Construct a set of configuration description structures and return |
1200 | * them to the user, including CRTC, connector and framebuffer configuration. | 1346 | * them to the user, including CRTC, connector and framebuffer configuration. |
@@ -1228,8 +1374,8 @@ int drm_mode_getresources(struct drm_device *dev, void *data, | |||
1228 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 1374 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
1229 | return -EINVAL; | 1375 | return -EINVAL; |
1230 | 1376 | ||
1231 | mutex_lock(&dev->mode_config.mutex); | ||
1232 | 1377 | ||
1378 | mutex_lock(&file_priv->fbs_lock); | ||
1233 | /* | 1379 | /* |
1234 | * For the non-control nodes we need to limit the list of resources | 1380 | * For the non-control nodes we need to limit the list of resources |
1235 | * by IDs in the group list for this node | 1381 | * by IDs in the group list for this node |
@@ -1237,6 +1383,23 @@ int drm_mode_getresources(struct drm_device *dev, void *data, | |||
1237 | list_for_each(lh, &file_priv->fbs) | 1383 | list_for_each(lh, &file_priv->fbs) |
1238 | fb_count++; | 1384 | fb_count++; |
1239 | 1385 | ||
1386 | /* handle this in 4 parts */ | ||
1387 | /* FBs */ | ||
1388 | if (card_res->count_fbs >= fb_count) { | ||
1389 | copied = 0; | ||
1390 | fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr; | ||
1391 | list_for_each_entry(fb, &file_priv->fbs, filp_head) { | ||
1392 | if (put_user(fb->base.id, fb_id + copied)) { | ||
1393 | mutex_unlock(&file_priv->fbs_lock); | ||
1394 | return -EFAULT; | ||
1395 | } | ||
1396 | copied++; | ||
1397 | } | ||
1398 | } | ||
1399 | card_res->count_fbs = fb_count; | ||
1400 | mutex_unlock(&file_priv->fbs_lock); | ||
1401 | |||
1402 | drm_modeset_lock_all(dev); | ||
1240 | mode_group = &file_priv->master->minor->mode_group; | 1403 | mode_group = &file_priv->master->minor->mode_group; |
1241 | if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { | 1404 | if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { |
1242 | 1405 | ||
@@ -1260,21 +1423,6 @@ int drm_mode_getresources(struct drm_device *dev, void *data, | |||
1260 | card_res->max_width = dev->mode_config.max_width; | 1423 | card_res->max_width = dev->mode_config.max_width; |
1261 | card_res->min_width = dev->mode_config.min_width; | 1424 | card_res->min_width = dev->mode_config.min_width; |
1262 | 1425 | ||
1263 | /* handle this in 4 parts */ | ||
1264 | /* FBs */ | ||
1265 | if (card_res->count_fbs >= fb_count) { | ||
1266 | copied = 0; | ||
1267 | fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr; | ||
1268 | list_for_each_entry(fb, &file_priv->fbs, filp_head) { | ||
1269 | if (put_user(fb->base.id, fb_id + copied)) { | ||
1270 | ret = -EFAULT; | ||
1271 | goto out; | ||
1272 | } | ||
1273 | copied++; | ||
1274 | } | ||
1275 | } | ||
1276 | card_res->count_fbs = fb_count; | ||
1277 | |||
1278 | /* CRTCs */ | 1426 | /* CRTCs */ |
1279 | if (card_res->count_crtcs >= crtc_count) { | 1427 | if (card_res->count_crtcs >= crtc_count) { |
1280 | copied = 0; | 1428 | copied = 0; |
@@ -1370,19 +1518,15 @@ int drm_mode_getresources(struct drm_device *dev, void *data, | |||
1370 | card_res->count_connectors, card_res->count_encoders); | 1518 | card_res->count_connectors, card_res->count_encoders); |
1371 | 1519 | ||
1372 | out: | 1520 | out: |
1373 | mutex_unlock(&dev->mode_config.mutex); | 1521 | drm_modeset_unlock_all(dev); |
1374 | return ret; | 1522 | return ret; |
1375 | } | 1523 | } |
1376 | 1524 | ||
1377 | /** | 1525 | /** |
1378 | * drm_mode_getcrtc - get CRTC configuration | 1526 | * drm_mode_getcrtc - get CRTC configuration |
1379 | * @inode: inode from the ioctl | 1527 | * @dev: drm device for the ioctl |
1380 | * @filp: file * from the ioctl | 1528 | * @data: data pointer for the ioctl |
1381 | * @cmd: cmd from ioctl | 1529 | * @file_priv: drm file for the ioctl call |
1382 | * @arg: arg from ioctl | ||
1383 | * | ||
1384 | * LOCKING: | ||
1385 | * Takes mode config lock. | ||
1386 | * | 1530 | * |
1387 | * Construct a CRTC configuration structure to return to the user. | 1531 | * Construct a CRTC configuration structure to return to the user. |
1388 | * | 1532 | * |
@@ -1402,7 +1546,7 @@ int drm_mode_getcrtc(struct drm_device *dev, | |||
1402 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 1546 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
1403 | return -EINVAL; | 1547 | return -EINVAL; |
1404 | 1548 | ||
1405 | mutex_lock(&dev->mode_config.mutex); | 1549 | drm_modeset_lock_all(dev); |
1406 | 1550 | ||
1407 | obj = drm_mode_object_find(dev, crtc_resp->crtc_id, | 1551 | obj = drm_mode_object_find(dev, crtc_resp->crtc_id, |
1408 | DRM_MODE_OBJECT_CRTC); | 1552 | DRM_MODE_OBJECT_CRTC); |
@@ -1430,19 +1574,15 @@ int drm_mode_getcrtc(struct drm_device *dev, | |||
1430 | } | 1574 | } |
1431 | 1575 | ||
1432 | out: | 1576 | out: |
1433 | mutex_unlock(&dev->mode_config.mutex); | 1577 | drm_modeset_unlock_all(dev); |
1434 | return ret; | 1578 | return ret; |
1435 | } | 1579 | } |
1436 | 1580 | ||
1437 | /** | 1581 | /** |
1438 | * drm_mode_getconnector - get connector configuration | 1582 | * drm_mode_getconnector - get connector configuration |
1439 | * @inode: inode from the ioctl | 1583 | * @dev: drm device for the ioctl |
1440 | * @filp: file * from the ioctl | 1584 | * @data: data pointer for the ioctl |
1441 | * @cmd: cmd from ioctl | 1585 | * @file_priv: drm file for the ioctl call |
1442 | * @arg: arg from ioctl | ||
1443 | * | ||
1444 | * LOCKING: | ||
1445 | * Takes mode config lock. | ||
1446 | * | 1586 | * |
1447 | * Construct a connector configuration structure to return to the user. | 1587 | * Construct a connector configuration structure to return to the user. |
1448 | * | 1588 | * |
@@ -1575,6 +1715,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, | |||
1575 | 1715 | ||
1576 | out: | 1716 | out: |
1577 | mutex_unlock(&dev->mode_config.mutex); | 1717 | mutex_unlock(&dev->mode_config.mutex); |
1718 | |||
1578 | return ret; | 1719 | return ret; |
1579 | } | 1720 | } |
1580 | 1721 | ||
@@ -1589,7 +1730,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, | |||
1589 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 1730 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
1590 | return -EINVAL; | 1731 | return -EINVAL; |
1591 | 1732 | ||
1592 | mutex_lock(&dev->mode_config.mutex); | 1733 | drm_modeset_lock_all(dev); |
1593 | obj = drm_mode_object_find(dev, enc_resp->encoder_id, | 1734 | obj = drm_mode_object_find(dev, enc_resp->encoder_id, |
1594 | DRM_MODE_OBJECT_ENCODER); | 1735 | DRM_MODE_OBJECT_ENCODER); |
1595 | if (!obj) { | 1736 | if (!obj) { |
@@ -1608,7 +1749,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, | |||
1608 | enc_resp->possible_clones = encoder->possible_clones; | 1749 | enc_resp->possible_clones = encoder->possible_clones; |
1609 | 1750 | ||
1610 | out: | 1751 | out: |
1611 | mutex_unlock(&dev->mode_config.mutex); | 1752 | drm_modeset_unlock_all(dev); |
1612 | return ret; | 1753 | return ret; |
1613 | } | 1754 | } |
1614 | 1755 | ||
@@ -1618,9 +1759,6 @@ out: | |||
1618 | * @data: ioctl data | 1759 | * @data: ioctl data |
1619 | * @file_priv: DRM file info | 1760 | * @file_priv: DRM file info |
1620 | * | 1761 | * |
1621 | * LOCKING: | ||
1622 | * Takes mode config lock. | ||
1623 | * | ||
1624 | * Return an plane count and set of IDs. | 1762 | * Return an plane count and set of IDs. |
1625 | */ | 1763 | */ |
1626 | int drm_mode_getplane_res(struct drm_device *dev, void *data, | 1764 | int drm_mode_getplane_res(struct drm_device *dev, void *data, |
@@ -1635,7 +1773,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, | |||
1635 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 1773 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
1636 | return -EINVAL; | 1774 | return -EINVAL; |
1637 | 1775 | ||
1638 | mutex_lock(&dev->mode_config.mutex); | 1776 | drm_modeset_lock_all(dev); |
1639 | config = &dev->mode_config; | 1777 | config = &dev->mode_config; |
1640 | 1778 | ||
1641 | /* | 1779 | /* |
@@ -1657,7 +1795,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, | |||
1657 | plane_resp->count_planes = config->num_plane; | 1795 | plane_resp->count_planes = config->num_plane; |
1658 | 1796 | ||
1659 | out: | 1797 | out: |
1660 | mutex_unlock(&dev->mode_config.mutex); | 1798 | drm_modeset_unlock_all(dev); |
1661 | return ret; | 1799 | return ret; |
1662 | } | 1800 | } |
1663 | 1801 | ||
@@ -1667,9 +1805,6 @@ out: | |||
1667 | * @data: ioctl data | 1805 | * @data: ioctl data |
1668 | * @file_priv: DRM file info | 1806 | * @file_priv: DRM file info |
1669 | * | 1807 | * |
1670 | * LOCKING: | ||
1671 | * Takes mode config lock. | ||
1672 | * | ||
1673 | * Return plane info, including formats supported, gamma size, any | 1808 | * Return plane info, including formats supported, gamma size, any |
1674 | * current fb, etc. | 1809 | * current fb, etc. |
1675 | */ | 1810 | */ |
@@ -1685,7 +1820,7 @@ int drm_mode_getplane(struct drm_device *dev, void *data, | |||
1685 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 1820 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
1686 | return -EINVAL; | 1821 | return -EINVAL; |
1687 | 1822 | ||
1688 | mutex_lock(&dev->mode_config.mutex); | 1823 | drm_modeset_lock_all(dev); |
1689 | obj = drm_mode_object_find(dev, plane_resp->plane_id, | 1824 | obj = drm_mode_object_find(dev, plane_resp->plane_id, |
1690 | DRM_MODE_OBJECT_PLANE); | 1825 | DRM_MODE_OBJECT_PLANE); |
1691 | if (!obj) { | 1826 | if (!obj) { |
@@ -1725,7 +1860,7 @@ int drm_mode_getplane(struct drm_device *dev, void *data, | |||
1725 | plane_resp->count_format_types = plane->format_count; | 1860 | plane_resp->count_format_types = plane->format_count; |
1726 | 1861 | ||
1727 | out: | 1862 | out: |
1728 | mutex_unlock(&dev->mode_config.mutex); | 1863 | drm_modeset_unlock_all(dev); |
1729 | return ret; | 1864 | return ret; |
1730 | } | 1865 | } |
1731 | 1866 | ||
@@ -1733,10 +1868,7 @@ out: | |||
1733 | * drm_mode_setplane - set up or tear down an plane | 1868 | * drm_mode_setplane - set up or tear down an plane |
1734 | * @dev: DRM device | 1869 | * @dev: DRM device |
1735 | * @data: ioctl data* | 1870 | * @data: ioctl data* |
1736 | * @file_prive: DRM file info | 1871 | * @file_priv: DRM file info |
1737 | * | ||
1738 | * LOCKING: | ||
1739 | * Takes mode config lock. | ||
1740 | * | 1872 | * |
1741 | * Set plane info, including placement, fb, scaling, and other factors. | 1873 | * Set plane info, including placement, fb, scaling, and other factors. |
1742 | * Or pass a NULL fb to disable. | 1874 | * Or pass a NULL fb to disable. |
@@ -1748,7 +1880,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data, | |||
1748 | struct drm_mode_object *obj; | 1880 | struct drm_mode_object *obj; |
1749 | struct drm_plane *plane; | 1881 | struct drm_plane *plane; |
1750 | struct drm_crtc *crtc; | 1882 | struct drm_crtc *crtc; |
1751 | struct drm_framebuffer *fb; | 1883 | struct drm_framebuffer *fb = NULL, *old_fb = NULL; |
1752 | int ret = 0; | 1884 | int ret = 0; |
1753 | unsigned int fb_width, fb_height; | 1885 | unsigned int fb_width, fb_height; |
1754 | int i; | 1886 | int i; |
@@ -1756,8 +1888,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data, | |||
1756 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 1888 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
1757 | return -EINVAL; | 1889 | return -EINVAL; |
1758 | 1890 | ||
1759 | mutex_lock(&dev->mode_config.mutex); | ||
1760 | |||
1761 | /* | 1891 | /* |
1762 | * First, find the plane, crtc, and fb objects. If not available, | 1892 | * First, find the plane, crtc, and fb objects. If not available, |
1763 | * we don't bother to call the driver. | 1893 | * we don't bother to call the driver. |
@@ -1767,16 +1897,18 @@ int drm_mode_setplane(struct drm_device *dev, void *data, | |||
1767 | if (!obj) { | 1897 | if (!obj) { |
1768 | DRM_DEBUG_KMS("Unknown plane ID %d\n", | 1898 | DRM_DEBUG_KMS("Unknown plane ID %d\n", |
1769 | plane_req->plane_id); | 1899 | plane_req->plane_id); |
1770 | ret = -ENOENT; | 1900 | return -ENOENT; |
1771 | goto out; | ||
1772 | } | 1901 | } |
1773 | plane = obj_to_plane(obj); | 1902 | plane = obj_to_plane(obj); |
1774 | 1903 | ||
1775 | /* No fb means shut it down */ | 1904 | /* No fb means shut it down */ |
1776 | if (!plane_req->fb_id) { | 1905 | if (!plane_req->fb_id) { |
1906 | drm_modeset_lock_all(dev); | ||
1907 | old_fb = plane->fb; | ||
1777 | plane->funcs->disable_plane(plane); | 1908 | plane->funcs->disable_plane(plane); |
1778 | plane->crtc = NULL; | 1909 | plane->crtc = NULL; |
1779 | plane->fb = NULL; | 1910 | plane->fb = NULL; |
1911 | drm_modeset_unlock_all(dev); | ||
1780 | goto out; | 1912 | goto out; |
1781 | } | 1913 | } |
1782 | 1914 | ||
@@ -1790,15 +1922,13 @@ int drm_mode_setplane(struct drm_device *dev, void *data, | |||
1790 | } | 1922 | } |
1791 | crtc = obj_to_crtc(obj); | 1923 | crtc = obj_to_crtc(obj); |
1792 | 1924 | ||
1793 | obj = drm_mode_object_find(dev, plane_req->fb_id, | 1925 | fb = drm_framebuffer_lookup(dev, plane_req->fb_id); |
1794 | DRM_MODE_OBJECT_FB); | 1926 | if (!fb) { |
1795 | if (!obj) { | ||
1796 | DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", | 1927 | DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", |
1797 | plane_req->fb_id); | 1928 | plane_req->fb_id); |
1798 | ret = -ENOENT; | 1929 | ret = -ENOENT; |
1799 | goto out; | 1930 | goto out; |
1800 | } | 1931 | } |
1801 | fb = obj_to_fb(obj); | ||
1802 | 1932 | ||
1803 | /* Check whether this plane supports the fb pixel format. */ | 1933 | /* Check whether this plane supports the fb pixel format. */ |
1804 | for (i = 0; i < plane->format_count; i++) | 1934 | for (i = 0; i < plane->format_count; i++) |
@@ -1844,31 +1974,62 @@ int drm_mode_setplane(struct drm_device *dev, void *data, | |||
1844 | goto out; | 1974 | goto out; |
1845 | } | 1975 | } |
1846 | 1976 | ||
1977 | drm_modeset_lock_all(dev); | ||
1847 | ret = plane->funcs->update_plane(plane, crtc, fb, | 1978 | ret = plane->funcs->update_plane(plane, crtc, fb, |
1848 | plane_req->crtc_x, plane_req->crtc_y, | 1979 | plane_req->crtc_x, plane_req->crtc_y, |
1849 | plane_req->crtc_w, plane_req->crtc_h, | 1980 | plane_req->crtc_w, plane_req->crtc_h, |
1850 | plane_req->src_x, plane_req->src_y, | 1981 | plane_req->src_x, plane_req->src_y, |
1851 | plane_req->src_w, plane_req->src_h); | 1982 | plane_req->src_w, plane_req->src_h); |
1852 | if (!ret) { | 1983 | if (!ret) { |
1984 | old_fb = plane->fb; | ||
1985 | fb = NULL; | ||
1853 | plane->crtc = crtc; | 1986 | plane->crtc = crtc; |
1854 | plane->fb = fb; | 1987 | plane->fb = fb; |
1855 | } | 1988 | } |
1989 | drm_modeset_unlock_all(dev); | ||
1856 | 1990 | ||
1857 | out: | 1991 | out: |
1858 | mutex_unlock(&dev->mode_config.mutex); | 1992 | if (fb) |
1993 | drm_framebuffer_unreference(fb); | ||
1994 | if (old_fb) | ||
1995 | drm_framebuffer_unreference(old_fb); | ||
1859 | 1996 | ||
1860 | return ret; | 1997 | return ret; |
1861 | } | 1998 | } |
1862 | 1999 | ||
1863 | /** | 2000 | /** |
1864 | * drm_mode_setcrtc - set CRTC configuration | 2001 | * drm_mode_set_config_internal - helper to call ->set_config |
1865 | * @inode: inode from the ioctl | 2002 | * @set: modeset config to set |
1866 | * @filp: file * from the ioctl | ||
1867 | * @cmd: cmd from ioctl | ||
1868 | * @arg: arg from ioctl | ||
1869 | * | 2003 | * |
1870 | * LOCKING: | 2004 | * This is a little helper to wrap internal calls to the ->set_config driver |
1871 | * Takes mode config lock. | 2005 | * interface. The only thing it adds is correct refcounting dance. |
2006 | */ | ||
2007 | int drm_mode_set_config_internal(struct drm_mode_set *set) | ||
2008 | { | ||
2009 | struct drm_crtc *crtc = set->crtc; | ||
2010 | struct drm_framebuffer *fb, *old_fb; | ||
2011 | int ret; | ||
2012 | |||
2013 | old_fb = crtc->fb; | ||
2014 | fb = set->fb; | ||
2015 | |||
2016 | ret = crtc->funcs->set_config(set); | ||
2017 | if (ret == 0) { | ||
2018 | if (old_fb) | ||
2019 | drm_framebuffer_unreference(old_fb); | ||
2020 | if (fb) | ||
2021 | drm_framebuffer_reference(fb); | ||
2022 | } | ||
2023 | |||
2024 | return ret; | ||
2025 | } | ||
2026 | EXPORT_SYMBOL(drm_mode_set_config_internal); | ||
2027 | |||
2028 | /** | ||
2029 | * drm_mode_setcrtc - set CRTC configuration | ||
2030 | * @dev: drm device for the ioctl | ||
2031 | * @data: data pointer for the ioctl | ||
2032 | * @file_priv: drm file for the ioctl call | ||
1872 | * | 2033 | * |
1873 | * Build a new CRTC configuration based on user request. | 2034 | * Build a new CRTC configuration based on user request. |
1874 | * | 2035 | * |
@@ -1899,7 +2060,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, | |||
1899 | if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX) | 2060 | if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX) |
1900 | return -ERANGE; | 2061 | return -ERANGE; |
1901 | 2062 | ||
1902 | mutex_lock(&dev->mode_config.mutex); | 2063 | drm_modeset_lock_all(dev); |
1903 | obj = drm_mode_object_find(dev, crtc_req->crtc_id, | 2064 | obj = drm_mode_object_find(dev, crtc_req->crtc_id, |
1904 | DRM_MODE_OBJECT_CRTC); | 2065 | DRM_MODE_OBJECT_CRTC); |
1905 | if (!obj) { | 2066 | if (!obj) { |
@@ -1921,16 +2082,16 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, | |||
1921 | goto out; | 2082 | goto out; |
1922 | } | 2083 | } |
1923 | fb = crtc->fb; | 2084 | fb = crtc->fb; |
2085 | /* Make refcounting symmetric with the lookup path. */ | ||
2086 | drm_framebuffer_reference(fb); | ||
1924 | } else { | 2087 | } else { |
1925 | obj = drm_mode_object_find(dev, crtc_req->fb_id, | 2088 | fb = drm_framebuffer_lookup(dev, crtc_req->fb_id); |
1926 | DRM_MODE_OBJECT_FB); | 2089 | if (!fb) { |
1927 | if (!obj) { | ||
1928 | DRM_DEBUG_KMS("Unknown FB ID%d\n", | 2090 | DRM_DEBUG_KMS("Unknown FB ID%d\n", |
1929 | crtc_req->fb_id); | 2091 | crtc_req->fb_id); |
1930 | ret = -EINVAL; | 2092 | ret = -EINVAL; |
1931 | goto out; | 2093 | goto out; |
1932 | } | 2094 | } |
1933 | fb = obj_to_fb(obj); | ||
1934 | } | 2095 | } |
1935 | 2096 | ||
1936 | mode = drm_mode_create(dev); | 2097 | mode = drm_mode_create(dev); |
@@ -2027,12 +2188,15 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, | |||
2027 | set.connectors = connector_set; | 2188 | set.connectors = connector_set; |
2028 | set.num_connectors = crtc_req->count_connectors; | 2189 | set.num_connectors = crtc_req->count_connectors; |
2029 | set.fb = fb; | 2190 | set.fb = fb; |
2030 | ret = crtc->funcs->set_config(&set); | 2191 | ret = drm_mode_set_config_internal(&set); |
2031 | 2192 | ||
2032 | out: | 2193 | out: |
2194 | if (fb) | ||
2195 | drm_framebuffer_unreference(fb); | ||
2196 | |||
2033 | kfree(connector_set); | 2197 | kfree(connector_set); |
2034 | drm_mode_destroy(dev, mode); | 2198 | drm_mode_destroy(dev, mode); |
2035 | mutex_unlock(&dev->mode_config.mutex); | 2199 | drm_modeset_unlock_all(dev); |
2036 | return ret; | 2200 | return ret; |
2037 | } | 2201 | } |
2038 | 2202 | ||
@@ -2050,15 +2214,14 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, | |||
2050 | if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) | 2214 | if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) |
2051 | return -EINVAL; | 2215 | return -EINVAL; |
2052 | 2216 | ||
2053 | mutex_lock(&dev->mode_config.mutex); | ||
2054 | obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC); | 2217 | obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC); |
2055 | if (!obj) { | 2218 | if (!obj) { |
2056 | DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); | 2219 | DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); |
2057 | ret = -EINVAL; | 2220 | return -EINVAL; |
2058 | goto out; | ||
2059 | } | 2221 | } |
2060 | crtc = obj_to_crtc(obj); | 2222 | crtc = obj_to_crtc(obj); |
2061 | 2223 | ||
2224 | mutex_lock(&crtc->mutex); | ||
2062 | if (req->flags & DRM_MODE_CURSOR_BO) { | 2225 | if (req->flags & DRM_MODE_CURSOR_BO) { |
2063 | if (!crtc->funcs->cursor_set) { | 2226 | if (!crtc->funcs->cursor_set) { |
2064 | ret = -ENXIO; | 2227 | ret = -ENXIO; |
@@ -2078,7 +2241,8 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, | |||
2078 | } | 2241 | } |
2079 | } | 2242 | } |
2080 | out: | 2243 | out: |
2081 | mutex_unlock(&dev->mode_config.mutex); | 2244 | mutex_unlock(&crtc->mutex); |
2245 | |||
2082 | return ret; | 2246 | return ret; |
2083 | } | 2247 | } |
2084 | 2248 | ||
@@ -2120,13 +2284,9 @@ EXPORT_SYMBOL(drm_mode_legacy_fb_format); | |||
2120 | 2284 | ||
2121 | /** | 2285 | /** |
2122 | * drm_mode_addfb - add an FB to the graphics configuration | 2286 | * drm_mode_addfb - add an FB to the graphics configuration |
2123 | * @inode: inode from the ioctl | 2287 | * @dev: drm device for the ioctl |
2124 | * @filp: file * from the ioctl | 2288 | * @data: data pointer for the ioctl |
2125 | * @cmd: cmd from ioctl | 2289 | * @file_priv: drm file for the ioctl call |
2126 | * @arg: arg from ioctl | ||
2127 | * | ||
2128 | * LOCKING: | ||
2129 | * Takes mode config lock. | ||
2130 | * | 2290 | * |
2131 | * Add a new FB to the specified CRTC, given a user request. | 2291 | * Add a new FB to the specified CRTC, given a user request. |
2132 | * | 2292 | * |
@@ -2161,24 +2321,19 @@ int drm_mode_addfb(struct drm_device *dev, | |||
2161 | if ((config->min_height > r.height) || (r.height > config->max_height)) | 2321 | if ((config->min_height > r.height) || (r.height > config->max_height)) |
2162 | return -EINVAL; | 2322 | return -EINVAL; |
2163 | 2323 | ||
2164 | mutex_lock(&dev->mode_config.mutex); | ||
2165 | |||
2166 | /* TODO check buffer is sufficiently large */ | ||
2167 | /* TODO setup destructor callback */ | ||
2168 | |||
2169 | fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r); | 2324 | fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r); |
2170 | if (IS_ERR(fb)) { | 2325 | if (IS_ERR(fb)) { |
2171 | DRM_DEBUG_KMS("could not create framebuffer\n"); | 2326 | DRM_DEBUG_KMS("could not create framebuffer\n"); |
2172 | ret = PTR_ERR(fb); | 2327 | drm_modeset_unlock_all(dev); |
2173 | goto out; | 2328 | return PTR_ERR(fb); |
2174 | } | 2329 | } |
2175 | 2330 | ||
2331 | mutex_lock(&file_priv->fbs_lock); | ||
2176 | or->fb_id = fb->base.id; | 2332 | or->fb_id = fb->base.id; |
2177 | list_add(&fb->filp_head, &file_priv->fbs); | 2333 | list_add(&fb->filp_head, &file_priv->fbs); |
2178 | DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); | 2334 | DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); |
2335 | mutex_unlock(&file_priv->fbs_lock); | ||
2179 | 2336 | ||
2180 | out: | ||
2181 | mutex_unlock(&dev->mode_config.mutex); | ||
2182 | return ret; | 2337 | return ret; |
2183 | } | 2338 | } |
2184 | 2339 | ||
@@ -2304,13 +2459,9 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) | |||
2304 | 2459 | ||
2305 | /** | 2460 | /** |
2306 | * drm_mode_addfb2 - add an FB to the graphics configuration | 2461 | * drm_mode_addfb2 - add an FB to the graphics configuration |
2307 | * @inode: inode from the ioctl | 2462 | * @dev: drm device for the ioctl |
2308 | * @filp: file * from the ioctl | 2463 | * @data: data pointer for the ioctl |
2309 | * @cmd: cmd from ioctl | 2464 | * @file_priv: drm file for the ioctl call |
2310 | * @arg: arg from ioctl | ||
2311 | * | ||
2312 | * LOCKING: | ||
2313 | * Takes mode config lock. | ||
2314 | * | 2465 | * |
2315 | * Add a new FB to the specified CRTC, given a user request with format. | 2466 | * Add a new FB to the specified CRTC, given a user request with format. |
2316 | * | 2467 | * |
@@ -2350,33 +2501,28 @@ int drm_mode_addfb2(struct drm_device *dev, | |||
2350 | if (ret) | 2501 | if (ret) |
2351 | return ret; | 2502 | return ret; |
2352 | 2503 | ||
2353 | mutex_lock(&dev->mode_config.mutex); | ||
2354 | |||
2355 | fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); | 2504 | fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); |
2356 | if (IS_ERR(fb)) { | 2505 | if (IS_ERR(fb)) { |
2357 | DRM_DEBUG_KMS("could not create framebuffer\n"); | 2506 | DRM_DEBUG_KMS("could not create framebuffer\n"); |
2358 | ret = PTR_ERR(fb); | 2507 | drm_modeset_unlock_all(dev); |
2359 | goto out; | 2508 | return PTR_ERR(fb); |
2360 | } | 2509 | } |
2361 | 2510 | ||
2511 | mutex_lock(&file_priv->fbs_lock); | ||
2362 | r->fb_id = fb->base.id; | 2512 | r->fb_id = fb->base.id; |
2363 | list_add(&fb->filp_head, &file_priv->fbs); | 2513 | list_add(&fb->filp_head, &file_priv->fbs); |
2364 | DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); | 2514 | DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); |
2515 | mutex_unlock(&file_priv->fbs_lock); | ||
2516 | |||
2365 | 2517 | ||
2366 | out: | ||
2367 | mutex_unlock(&dev->mode_config.mutex); | ||
2368 | return ret; | 2518 | return ret; |
2369 | } | 2519 | } |
2370 | 2520 | ||
2371 | /** | 2521 | /** |
2372 | * drm_mode_rmfb - remove an FB from the configuration | 2522 | * drm_mode_rmfb - remove an FB from the configuration |
2373 | * @inode: inode from the ioctl | 2523 | * @dev: drm device for the ioctl |
2374 | * @filp: file * from the ioctl | 2524 | * @data: data pointer for the ioctl |
2375 | * @cmd: cmd from ioctl | 2525 | * @file_priv: drm file for the ioctl call |
2376 | * @arg: arg from ioctl | ||
2377 | * | ||
2378 | * LOCKING: | ||
2379 | * Takes mode config lock. | ||
2380 | * | 2526 | * |
2381 | * Remove the FB specified by the user. | 2527 | * Remove the FB specified by the user. |
2382 | * | 2528 | * |
@@ -2388,50 +2534,49 @@ out: | |||
2388 | int drm_mode_rmfb(struct drm_device *dev, | 2534 | int drm_mode_rmfb(struct drm_device *dev, |
2389 | void *data, struct drm_file *file_priv) | 2535 | void *data, struct drm_file *file_priv) |
2390 | { | 2536 | { |
2391 | struct drm_mode_object *obj; | ||
2392 | struct drm_framebuffer *fb = NULL; | 2537 | struct drm_framebuffer *fb = NULL; |
2393 | struct drm_framebuffer *fbl = NULL; | 2538 | struct drm_framebuffer *fbl = NULL; |
2394 | uint32_t *id = data; | 2539 | uint32_t *id = data; |
2395 | int ret = 0; | ||
2396 | int found = 0; | 2540 | int found = 0; |
2397 | 2541 | ||
2398 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 2542 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
2399 | return -EINVAL; | 2543 | return -EINVAL; |
2400 | 2544 | ||
2401 | mutex_lock(&dev->mode_config.mutex); | 2545 | mutex_lock(&file_priv->fbs_lock); |
2402 | obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB); | 2546 | mutex_lock(&dev->mode_config.fb_lock); |
2403 | /* TODO check that we really get a framebuffer back. */ | 2547 | fb = __drm_framebuffer_lookup(dev, *id); |
2404 | if (!obj) { | 2548 | if (!fb) |
2405 | ret = -EINVAL; | 2549 | goto fail_lookup; |
2406 | goto out; | ||
2407 | } | ||
2408 | fb = obj_to_fb(obj); | ||
2409 | 2550 | ||
2410 | list_for_each_entry(fbl, &file_priv->fbs, filp_head) | 2551 | list_for_each_entry(fbl, &file_priv->fbs, filp_head) |
2411 | if (fb == fbl) | 2552 | if (fb == fbl) |
2412 | found = 1; | 2553 | found = 1; |
2554 | if (!found) | ||
2555 | goto fail_lookup; | ||
2413 | 2556 | ||
2414 | if (!found) { | 2557 | /* Mark fb as reaped, we still have a ref from fpriv->fbs. */ |
2415 | ret = -EINVAL; | 2558 | __drm_framebuffer_unregister(dev, fb); |
2416 | goto out; | 2559 | |
2417 | } | 2560 | list_del_init(&fb->filp_head); |
2561 | mutex_unlock(&dev->mode_config.fb_lock); | ||
2562 | mutex_unlock(&file_priv->fbs_lock); | ||
2418 | 2563 | ||
2419 | drm_framebuffer_remove(fb); | 2564 | drm_framebuffer_remove(fb); |
2420 | 2565 | ||
2421 | out: | 2566 | return 0; |
2422 | mutex_unlock(&dev->mode_config.mutex); | 2567 | |
2423 | return ret; | 2568 | fail_lookup: |
2569 | mutex_unlock(&dev->mode_config.fb_lock); | ||
2570 | mutex_unlock(&file_priv->fbs_lock); | ||
2571 | |||
2572 | return -EINVAL; | ||
2424 | } | 2573 | } |
2425 | 2574 | ||
2426 | /** | 2575 | /** |
2427 | * drm_mode_getfb - get FB info | 2576 | * drm_mode_getfb - get FB info |
2428 | * @inode: inode from the ioctl | 2577 | * @dev: drm device for the ioctl |
2429 | * @filp: file * from the ioctl | 2578 | * @data: data pointer for the ioctl |
2430 | * @cmd: cmd from ioctl | 2579 | * @file_priv: drm file for the ioctl call |
2431 | * @arg: arg from ioctl | ||
2432 | * | ||
2433 | * LOCKING: | ||
2434 | * Takes mode config lock. | ||
2435 | * | 2580 | * |
2436 | * Lookup the FB given its ID and return info about it. | 2581 | * Lookup the FB given its ID and return info about it. |
2437 | * | 2582 | * |
@@ -2444,30 +2589,28 @@ int drm_mode_getfb(struct drm_device *dev, | |||
2444 | void *data, struct drm_file *file_priv) | 2589 | void *data, struct drm_file *file_priv) |
2445 | { | 2590 | { |
2446 | struct drm_mode_fb_cmd *r = data; | 2591 | struct drm_mode_fb_cmd *r = data; |
2447 | struct drm_mode_object *obj; | ||
2448 | struct drm_framebuffer *fb; | 2592 | struct drm_framebuffer *fb; |
2449 | int ret = 0; | 2593 | int ret; |
2450 | 2594 | ||
2451 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 2595 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
2452 | return -EINVAL; | 2596 | return -EINVAL; |
2453 | 2597 | ||
2454 | mutex_lock(&dev->mode_config.mutex); | 2598 | fb = drm_framebuffer_lookup(dev, r->fb_id); |
2455 | obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); | 2599 | if (!fb) |
2456 | if (!obj) { | 2600 | return -EINVAL; |
2457 | ret = -EINVAL; | ||
2458 | goto out; | ||
2459 | } | ||
2460 | fb = obj_to_fb(obj); | ||
2461 | 2601 | ||
2462 | r->height = fb->height; | 2602 | r->height = fb->height; |
2463 | r->width = fb->width; | 2603 | r->width = fb->width; |
2464 | r->depth = fb->depth; | 2604 | r->depth = fb->depth; |
2465 | r->bpp = fb->bits_per_pixel; | 2605 | r->bpp = fb->bits_per_pixel; |
2466 | r->pitch = fb->pitches[0]; | 2606 | r->pitch = fb->pitches[0]; |
2467 | fb->funcs->create_handle(fb, file_priv, &r->handle); | 2607 | if (fb->funcs->create_handle) |
2608 | ret = fb->funcs->create_handle(fb, file_priv, &r->handle); | ||
2609 | else | ||
2610 | ret = -ENODEV; | ||
2611 | |||
2612 | drm_framebuffer_unreference(fb); | ||
2468 | 2613 | ||
2469 | out: | ||
2470 | mutex_unlock(&dev->mode_config.mutex); | ||
2471 | return ret; | 2614 | return ret; |
2472 | } | 2615 | } |
2473 | 2616 | ||
@@ -2477,7 +2620,6 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, | |||
2477 | struct drm_clip_rect __user *clips_ptr; | 2620 | struct drm_clip_rect __user *clips_ptr; |
2478 | struct drm_clip_rect *clips = NULL; | 2621 | struct drm_clip_rect *clips = NULL; |
2479 | struct drm_mode_fb_dirty_cmd *r = data; | 2622 | struct drm_mode_fb_dirty_cmd *r = data; |
2480 | struct drm_mode_object *obj; | ||
2481 | struct drm_framebuffer *fb; | 2623 | struct drm_framebuffer *fb; |
2482 | unsigned flags; | 2624 | unsigned flags; |
2483 | int num_clips; | 2625 | int num_clips; |
@@ -2486,13 +2628,9 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, | |||
2486 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 2628 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
2487 | return -EINVAL; | 2629 | return -EINVAL; |
2488 | 2630 | ||
2489 | mutex_lock(&dev->mode_config.mutex); | 2631 | fb = drm_framebuffer_lookup(dev, r->fb_id); |
2490 | obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); | 2632 | if (!fb) |
2491 | if (!obj) { | 2633 | return -EINVAL; |
2492 | ret = -EINVAL; | ||
2493 | goto out_err1; | ||
2494 | } | ||
2495 | fb = obj_to_fb(obj); | ||
2496 | 2634 | ||
2497 | num_clips = r->num_clips; | 2635 | num_clips = r->num_clips; |
2498 | clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; | 2636 | clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; |
@@ -2530,27 +2668,26 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, | |||
2530 | } | 2668 | } |
2531 | 2669 | ||
2532 | if (fb->funcs->dirty) { | 2670 | if (fb->funcs->dirty) { |
2671 | drm_modeset_lock_all(dev); | ||
2533 | ret = fb->funcs->dirty(fb, file_priv, flags, r->color, | 2672 | ret = fb->funcs->dirty(fb, file_priv, flags, r->color, |
2534 | clips, num_clips); | 2673 | clips, num_clips); |
2674 | drm_modeset_unlock_all(dev); | ||
2535 | } else { | 2675 | } else { |
2536 | ret = -ENOSYS; | 2676 | ret = -ENOSYS; |
2537 | goto out_err2; | ||
2538 | } | 2677 | } |
2539 | 2678 | ||
2540 | out_err2: | 2679 | out_err2: |
2541 | kfree(clips); | 2680 | kfree(clips); |
2542 | out_err1: | 2681 | out_err1: |
2543 | mutex_unlock(&dev->mode_config.mutex); | 2682 | drm_framebuffer_unreference(fb); |
2683 | |||
2544 | return ret; | 2684 | return ret; |
2545 | } | 2685 | } |
2546 | 2686 | ||
2547 | 2687 | ||
2548 | /** | 2688 | /** |
2549 | * drm_fb_release - remove and free the FBs on this file | 2689 | * drm_fb_release - remove and free the FBs on this file |
2550 | * @filp: file * from the ioctl | 2690 | * @priv: drm file for the ioctl |
2551 | * | ||
2552 | * LOCKING: | ||
2553 | * Takes mode config lock. | ||
2554 | * | 2691 | * |
2555 | * Destroy all the FBs associated with @filp. | 2692 | * Destroy all the FBs associated with @filp. |
2556 | * | 2693 | * |
@@ -2564,11 +2701,20 @@ void drm_fb_release(struct drm_file *priv) | |||
2564 | struct drm_device *dev = priv->minor->dev; | 2701 | struct drm_device *dev = priv->minor->dev; |
2565 | struct drm_framebuffer *fb, *tfb; | 2702 | struct drm_framebuffer *fb, *tfb; |
2566 | 2703 | ||
2567 | mutex_lock(&dev->mode_config.mutex); | 2704 | mutex_lock(&priv->fbs_lock); |
2568 | list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { | 2705 | list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { |
2706 | |||
2707 | mutex_lock(&dev->mode_config.fb_lock); | ||
2708 | /* Mark fb as reaped, we still have a ref from fpriv->fbs. */ | ||
2709 | __drm_framebuffer_unregister(dev, fb); | ||
2710 | mutex_unlock(&dev->mode_config.fb_lock); | ||
2711 | |||
2712 | list_del_init(&fb->filp_head); | ||
2713 | |||
2714 | /* This will also drop the fpriv->fbs reference. */ | ||
2569 | drm_framebuffer_remove(fb); | 2715 | drm_framebuffer_remove(fb); |
2570 | } | 2716 | } |
2571 | mutex_unlock(&dev->mode_config.mutex); | 2717 | mutex_unlock(&priv->fbs_lock); |
2572 | } | 2718 | } |
2573 | 2719 | ||
2574 | /** | 2720 | /** |
@@ -2660,10 +2806,9 @@ EXPORT_SYMBOL(drm_mode_detachmode_crtc); | |||
2660 | 2806 | ||
2661 | /** | 2807 | /** |
2662 | * drm_fb_attachmode - Attach a user mode to an connector | 2808 | * drm_fb_attachmode - Attach a user mode to an connector |
2663 | * @inode: inode from the ioctl | 2809 | * @dev: drm device for the ioctl |
2664 | * @filp: file * from the ioctl | 2810 | * @data: data pointer for the ioctl |
2665 | * @cmd: cmd from ioctl | 2811 | * @file_priv: drm file for the ioctl call |
2666 | * @arg: arg from ioctl | ||
2667 | * | 2812 | * |
2668 | * This attaches a user specified mode to an connector. | 2813 | * This attaches a user specified mode to an connector. |
2669 | * Called by the user via ioctl. | 2814 | * Called by the user via ioctl. |
@@ -2684,7 +2829,7 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev, | |||
2684 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 2829 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
2685 | return -EINVAL; | 2830 | return -EINVAL; |
2686 | 2831 | ||
2687 | mutex_lock(&dev->mode_config.mutex); | 2832 | drm_modeset_lock_all(dev); |
2688 | 2833 | ||
2689 | obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); | 2834 | obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); |
2690 | if (!obj) { | 2835 | if (!obj) { |
@@ -2708,17 +2853,16 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev, | |||
2708 | 2853 | ||
2709 | drm_mode_attachmode(dev, connector, mode); | 2854 | drm_mode_attachmode(dev, connector, mode); |
2710 | out: | 2855 | out: |
2711 | mutex_unlock(&dev->mode_config.mutex); | 2856 | drm_modeset_unlock_all(dev); |
2712 | return ret; | 2857 | return ret; |
2713 | } | 2858 | } |
2714 | 2859 | ||
2715 | 2860 | ||
2716 | /** | 2861 | /** |
2717 | * drm_fb_detachmode - Detach a user specified mode from an connector | 2862 | * drm_fb_detachmode - Detach a user specified mode from an connector |
2718 | * @inode: inode from the ioctl | 2863 | * @dev: drm device for the ioctl |
2719 | * @filp: file * from the ioctl | 2864 | * @data: data pointer for the ioctl |
2720 | * @cmd: cmd from ioctl | 2865 | * @file_priv: drm file for the ioctl call |
2721 | * @arg: arg from ioctl | ||
2722 | * | 2866 | * |
2723 | * Called by the user via ioctl. | 2867 | * Called by the user via ioctl. |
2724 | * | 2868 | * |
@@ -2738,7 +2882,7 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev, | |||
2738 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 2882 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
2739 | return -EINVAL; | 2883 | return -EINVAL; |
2740 | 2884 | ||
2741 | mutex_lock(&dev->mode_config.mutex); | 2885 | drm_modeset_lock_all(dev); |
2742 | 2886 | ||
2743 | obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); | 2887 | obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); |
2744 | if (!obj) { | 2888 | if (!obj) { |
@@ -2755,7 +2899,7 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev, | |||
2755 | 2899 | ||
2756 | ret = drm_mode_detachmode(dev, connector, &mode); | 2900 | ret = drm_mode_detachmode(dev, connector, &mode); |
2757 | out: | 2901 | out: |
2758 | mutex_unlock(&dev->mode_config.mutex); | 2902 | drm_modeset_unlock_all(dev); |
2759 | return ret; | 2903 | return ret; |
2760 | } | 2904 | } |
2761 | 2905 | ||
@@ -3001,7 +3145,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, | |||
3001 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 3145 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
3002 | return -EINVAL; | 3146 | return -EINVAL; |
3003 | 3147 | ||
3004 | mutex_lock(&dev->mode_config.mutex); | 3148 | drm_modeset_lock_all(dev); |
3005 | obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); | 3149 | obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); |
3006 | if (!obj) { | 3150 | if (!obj) { |
3007 | ret = -EINVAL; | 3151 | ret = -EINVAL; |
@@ -3079,7 +3223,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, | |||
3079 | out_resp->count_enum_blobs = blob_count; | 3223 | out_resp->count_enum_blobs = blob_count; |
3080 | } | 3224 | } |
3081 | done: | 3225 | done: |
3082 | mutex_unlock(&dev->mode_config.mutex); | 3226 | drm_modeset_unlock_all(dev); |
3083 | return ret; | 3227 | return ret; |
3084 | } | 3228 | } |
3085 | 3229 | ||
@@ -3130,7 +3274,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev, | |||
3130 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 3274 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
3131 | return -EINVAL; | 3275 | return -EINVAL; |
3132 | 3276 | ||
3133 | mutex_lock(&dev->mode_config.mutex); | 3277 | drm_modeset_lock_all(dev); |
3134 | obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB); | 3278 | obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB); |
3135 | if (!obj) { | 3279 | if (!obj) { |
3136 | ret = -EINVAL; | 3280 | ret = -EINVAL; |
@@ -3148,7 +3292,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev, | |||
3148 | out_resp->length = blob->length; | 3292 | out_resp->length = blob->length; |
3149 | 3293 | ||
3150 | done: | 3294 | done: |
3151 | mutex_unlock(&dev->mode_config.mutex); | 3295 | drm_modeset_unlock_all(dev); |
3152 | return ret; | 3296 | return ret; |
3153 | } | 3297 | } |
3154 | 3298 | ||
@@ -3290,7 +3434,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, | |||
3290 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 3434 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
3291 | return -EINVAL; | 3435 | return -EINVAL; |
3292 | 3436 | ||
3293 | mutex_lock(&dev->mode_config.mutex); | 3437 | drm_modeset_lock_all(dev); |
3294 | 3438 | ||
3295 | obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); | 3439 | obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); |
3296 | if (!obj) { | 3440 | if (!obj) { |
@@ -3327,7 +3471,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, | |||
3327 | } | 3471 | } |
3328 | arg->count_props = props_count; | 3472 | arg->count_props = props_count; |
3329 | out: | 3473 | out: |
3330 | mutex_unlock(&dev->mode_config.mutex); | 3474 | drm_modeset_unlock_all(dev); |
3331 | return ret; | 3475 | return ret; |
3332 | } | 3476 | } |
3333 | 3477 | ||
@@ -3344,7 +3488,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | |||
3344 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 3488 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
3345 | return -EINVAL; | 3489 | return -EINVAL; |
3346 | 3490 | ||
3347 | mutex_lock(&dev->mode_config.mutex); | 3491 | drm_modeset_lock_all(dev); |
3348 | 3492 | ||
3349 | arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); | 3493 | arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type); |
3350 | if (!arg_obj) | 3494 | if (!arg_obj) |
@@ -3382,7 +3526,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, | |||
3382 | } | 3526 | } |
3383 | 3527 | ||
3384 | out: | 3528 | out: |
3385 | mutex_unlock(&dev->mode_config.mutex); | 3529 | drm_modeset_unlock_all(dev); |
3386 | return ret; | 3530 | return ret; |
3387 | } | 3531 | } |
3388 | 3532 | ||
@@ -3444,7 +3588,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, | |||
3444 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 3588 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
3445 | return -EINVAL; | 3589 | return -EINVAL; |
3446 | 3590 | ||
3447 | mutex_lock(&dev->mode_config.mutex); | 3591 | drm_modeset_lock_all(dev); |
3448 | obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); | 3592 | obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); |
3449 | if (!obj) { | 3593 | if (!obj) { |
3450 | ret = -EINVAL; | 3594 | ret = -EINVAL; |
@@ -3485,7 +3629,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, | |||
3485 | crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); | 3629 | crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); |
3486 | 3630 | ||
3487 | out: | 3631 | out: |
3488 | mutex_unlock(&dev->mode_config.mutex); | 3632 | drm_modeset_unlock_all(dev); |
3489 | return ret; | 3633 | return ret; |
3490 | 3634 | ||
3491 | } | 3635 | } |
@@ -3503,7 +3647,7 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, | |||
3503 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 3647 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
3504 | return -EINVAL; | 3648 | return -EINVAL; |
3505 | 3649 | ||
3506 | mutex_lock(&dev->mode_config.mutex); | 3650 | drm_modeset_lock_all(dev); |
3507 | obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); | 3651 | obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); |
3508 | if (!obj) { | 3652 | if (!obj) { |
3509 | ret = -EINVAL; | 3653 | ret = -EINVAL; |
@@ -3536,7 +3680,7 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, | |||
3536 | goto out; | 3680 | goto out; |
3537 | } | 3681 | } |
3538 | out: | 3682 | out: |
3539 | mutex_unlock(&dev->mode_config.mutex); | 3683 | drm_modeset_unlock_all(dev); |
3540 | return ret; | 3684 | return ret; |
3541 | } | 3685 | } |
3542 | 3686 | ||
@@ -3546,7 +3690,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
3546 | struct drm_mode_crtc_page_flip *page_flip = data; | 3690 | struct drm_mode_crtc_page_flip *page_flip = data; |
3547 | struct drm_mode_object *obj; | 3691 | struct drm_mode_object *obj; |
3548 | struct drm_crtc *crtc; | 3692 | struct drm_crtc *crtc; |
3549 | struct drm_framebuffer *fb; | 3693 | struct drm_framebuffer *fb = NULL, *old_fb = NULL; |
3550 | struct drm_pending_vblank_event *e = NULL; | 3694 | struct drm_pending_vblank_event *e = NULL; |
3551 | unsigned long flags; | 3695 | unsigned long flags; |
3552 | int hdisplay, vdisplay; | 3696 | int hdisplay, vdisplay; |
@@ -3556,12 +3700,12 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
3556 | page_flip->reserved != 0) | 3700 | page_flip->reserved != 0) |
3557 | return -EINVAL; | 3701 | return -EINVAL; |
3558 | 3702 | ||
3559 | mutex_lock(&dev->mode_config.mutex); | ||
3560 | obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC); | 3703 | obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC); |
3561 | if (!obj) | 3704 | if (!obj) |
3562 | goto out; | 3705 | return -EINVAL; |
3563 | crtc = obj_to_crtc(obj); | 3706 | crtc = obj_to_crtc(obj); |
3564 | 3707 | ||
3708 | mutex_lock(&crtc->mutex); | ||
3565 | if (crtc->fb == NULL) { | 3709 | if (crtc->fb == NULL) { |
3566 | /* The framebuffer is currently unbound, presumably | 3710 | /* The framebuffer is currently unbound, presumably |
3567 | * due to a hotplug event, that userspace has not | 3711 | * due to a hotplug event, that userspace has not |
@@ -3574,10 +3718,9 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
3574 | if (crtc->funcs->page_flip == NULL) | 3718 | if (crtc->funcs->page_flip == NULL) |
3575 | goto out; | 3719 | goto out; |
3576 | 3720 | ||
3577 | obj = drm_mode_object_find(dev, page_flip->fb_id, DRM_MODE_OBJECT_FB); | 3721 | fb = drm_framebuffer_lookup(dev, page_flip->fb_id); |
3578 | if (!obj) | 3722 | if (!fb) |
3579 | goto out; | 3723 | goto out; |
3580 | fb = obj_to_fb(obj); | ||
3581 | 3724 | ||
3582 | hdisplay = crtc->mode.hdisplay; | 3725 | hdisplay = crtc->mode.hdisplay; |
3583 | vdisplay = crtc->mode.vdisplay; | 3726 | vdisplay = crtc->mode.vdisplay; |
@@ -3623,6 +3766,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
3623 | (void (*) (struct drm_pending_event *)) kfree; | 3766 | (void (*) (struct drm_pending_event *)) kfree; |
3624 | } | 3767 | } |
3625 | 3768 | ||
3769 | old_fb = crtc->fb; | ||
3626 | ret = crtc->funcs->page_flip(crtc, fb, e); | 3770 | ret = crtc->funcs->page_flip(crtc, fb, e); |
3627 | if (ret) { | 3771 | if (ret) { |
3628 | if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { | 3772 | if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { |
@@ -3631,10 +3775,20 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
3631 | spin_unlock_irqrestore(&dev->event_lock, flags); | 3775 | spin_unlock_irqrestore(&dev->event_lock, flags); |
3632 | kfree(e); | 3776 | kfree(e); |
3633 | } | 3777 | } |
3778 | /* Keep the old fb, don't unref it. */ | ||
3779 | old_fb = NULL; | ||
3780 | } else { | ||
3781 | /* Unref only the old framebuffer. */ | ||
3782 | fb = NULL; | ||
3634 | } | 3783 | } |
3635 | 3784 | ||
3636 | out: | 3785 | out: |
3637 | mutex_unlock(&dev->mode_config.mutex); | 3786 | if (fb) |
3787 | drm_framebuffer_unreference(fb); | ||
3788 | if (old_fb) | ||
3789 | drm_framebuffer_unreference(old_fb); | ||
3790 | mutex_unlock(&crtc->mutex); | ||
3791 | |||
3638 | return ret; | 3792 | return ret; |
3639 | } | 3793 | } |
3640 | 3794 | ||
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index fd9d0af4d536..3742bc96421e 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c | |||
@@ -85,6 +85,11 @@ static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev, | |||
85 | if (!fb_cma) | 85 | if (!fb_cma) |
86 | return ERR_PTR(-ENOMEM); | 86 | return ERR_PTR(-ENOMEM); |
87 | 87 | ||
88 | drm_helper_mode_fill_fb_struct(&fb_cma->fb, mode_cmd); | ||
89 | |||
90 | for (i = 0; i < num_planes; i++) | ||
91 | fb_cma->obj[i] = obj[i]; | ||
92 | |||
88 | ret = drm_framebuffer_init(dev, &fb_cma->fb, &drm_fb_cma_funcs); | 93 | ret = drm_framebuffer_init(dev, &fb_cma->fb, &drm_fb_cma_funcs); |
89 | if (ret) { | 94 | if (ret) { |
90 | dev_err(dev->dev, "Failed to initalize framebuffer: %d\n", ret); | 95 | dev_err(dev->dev, "Failed to initalize framebuffer: %d\n", ret); |
@@ -92,11 +97,6 @@ static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev, | |||
92 | return ERR_PTR(ret); | 97 | return ERR_PTR(ret); |
93 | } | 98 | } |
94 | 99 | ||
95 | drm_helper_mode_fill_fb_struct(&fb_cma->fb, mode_cmd); | ||
96 | |||
97 | for (i = 0; i < num_planes; i++) | ||
98 | fb_cma->obj[i] = obj[i]; | ||
99 | |||
100 | return fb_cma; | 100 | return fb_cma; |
101 | } | 101 | } |
102 | 102 | ||
@@ -266,6 +266,7 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper, | |||
266 | return 0; | 266 | return 0; |
267 | 267 | ||
268 | err_drm_fb_cma_destroy: | 268 | err_drm_fb_cma_destroy: |
269 | drm_framebuffer_unregister_private(fb); | ||
269 | drm_fb_cma_destroy(fb); | 270 | drm_fb_cma_destroy(fb); |
270 | err_framebuffer_release: | 271 | err_framebuffer_release: |
271 | framebuffer_release(fbi); | 272 | framebuffer_release(fbi); |
@@ -370,8 +371,10 @@ void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma) | |||
370 | framebuffer_release(info); | 371 | framebuffer_release(info); |
371 | } | 372 | } |
372 | 373 | ||
373 | if (fbdev_cma->fb) | 374 | if (fbdev_cma->fb) { |
375 | drm_framebuffer_unregister_private(&fbdev_cma->fb->fb); | ||
374 | drm_fb_cma_destroy(&fbdev_cma->fb->fb); | 376 | drm_fb_cma_destroy(&fbdev_cma->fb->fb); |
377 | } | ||
375 | 378 | ||
376 | drm_fb_helper_fini(&fbdev_cma->fb_helper); | 379 | drm_fb_helper_fini(&fbdev_cma->fb_helper); |
377 | kfree(fbdev_cma); | 380 | kfree(fbdev_cma); |
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 954d175bd7fa..0c6e25e979dd 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c | |||
@@ -245,7 +245,7 @@ bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper) | |||
245 | int i, ret; | 245 | int i, ret; |
246 | for (i = 0; i < fb_helper->crtc_count; i++) { | 246 | for (i = 0; i < fb_helper->crtc_count; i++) { |
247 | struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; | 247 | struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; |
248 | ret = mode_set->crtc->funcs->set_config(mode_set); | 248 | ret = drm_mode_set_config_internal(mode_set); |
249 | if (ret) | 249 | if (ret) |
250 | error = true; | 250 | error = true; |
251 | } | 251 | } |
@@ -305,6 +305,24 @@ void drm_fb_helper_restore(void) | |||
305 | } | 305 | } |
306 | EXPORT_SYMBOL(drm_fb_helper_restore); | 306 | EXPORT_SYMBOL(drm_fb_helper_restore); |
307 | 307 | ||
308 | static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) | ||
309 | { | ||
310 | struct drm_device *dev = fb_helper->dev; | ||
311 | struct drm_crtc *crtc; | ||
312 | int bound = 0, crtcs_bound = 0; | ||
313 | |||
314 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
315 | if (crtc->fb) | ||
316 | crtcs_bound++; | ||
317 | if (crtc->fb == fb_helper->fb) | ||
318 | bound++; | ||
319 | } | ||
320 | |||
321 | if (bound < crtcs_bound) | ||
322 | return false; | ||
323 | return true; | ||
324 | } | ||
325 | |||
308 | #ifdef CONFIG_MAGIC_SYSRQ | 326 | #ifdef CONFIG_MAGIC_SYSRQ |
309 | static void drm_fb_helper_restore_work_fn(struct work_struct *ignored) | 327 | static void drm_fb_helper_restore_work_fn(struct work_struct *ignored) |
310 | { | 328 | { |
@@ -337,7 +355,12 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode) | |||
337 | /* | 355 | /* |
338 | * For each CRTC in this fb, turn the connectors on/off. | 356 | * For each CRTC in this fb, turn the connectors on/off. |
339 | */ | 357 | */ |
340 | mutex_lock(&dev->mode_config.mutex); | 358 | drm_modeset_lock_all(dev); |
359 | if (!drm_fb_helper_is_bound(fb_helper)) { | ||
360 | drm_modeset_unlock_all(dev); | ||
361 | return; | ||
362 | } | ||
363 | |||
341 | for (i = 0; i < fb_helper->crtc_count; i++) { | 364 | for (i = 0; i < fb_helper->crtc_count; i++) { |
342 | crtc = fb_helper->crtc_info[i].mode_set.crtc; | 365 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
343 | 366 | ||
@@ -352,7 +375,7 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode) | |||
352 | dev->mode_config.dpms_property, dpms_mode); | 375 | dev->mode_config.dpms_property, dpms_mode); |
353 | } | 376 | } |
354 | } | 377 | } |
355 | mutex_unlock(&dev->mode_config.mutex); | 378 | drm_modeset_unlock_all(dev); |
356 | } | 379 | } |
357 | 380 | ||
358 | int drm_fb_helper_blank(int blank, struct fb_info *info) | 381 | int drm_fb_helper_blank(int blank, struct fb_info *info) |
@@ -672,16 +695,16 @@ int drm_fb_helper_set_par(struct fb_info *info) | |||
672 | return -EINVAL; | 695 | return -EINVAL; |
673 | } | 696 | } |
674 | 697 | ||
675 | mutex_lock(&dev->mode_config.mutex); | 698 | drm_modeset_lock_all(dev); |
676 | for (i = 0; i < fb_helper->crtc_count; i++) { | 699 | for (i = 0; i < fb_helper->crtc_count; i++) { |
677 | crtc = fb_helper->crtc_info[i].mode_set.crtc; | 700 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
678 | ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set); | 701 | ret = drm_mode_set_config_internal(&fb_helper->crtc_info[i].mode_set); |
679 | if (ret) { | 702 | if (ret) { |
680 | mutex_unlock(&dev->mode_config.mutex); | 703 | drm_modeset_unlock_all(dev); |
681 | return ret; | 704 | return ret; |
682 | } | 705 | } |
683 | } | 706 | } |
684 | mutex_unlock(&dev->mode_config.mutex); | 707 | drm_modeset_unlock_all(dev); |
685 | 708 | ||
686 | if (fb_helper->delayed_hotplug) { | 709 | if (fb_helper->delayed_hotplug) { |
687 | fb_helper->delayed_hotplug = false; | 710 | fb_helper->delayed_hotplug = false; |
@@ -701,7 +724,12 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, | |||
701 | int ret = 0; | 724 | int ret = 0; |
702 | int i; | 725 | int i; |
703 | 726 | ||
704 | mutex_lock(&dev->mode_config.mutex); | 727 | drm_modeset_lock_all(dev); |
728 | if (!drm_fb_helper_is_bound(fb_helper)) { | ||
729 | drm_modeset_unlock_all(dev); | ||
730 | return -EBUSY; | ||
731 | } | ||
732 | |||
705 | for (i = 0; i < fb_helper->crtc_count; i++) { | 733 | for (i = 0; i < fb_helper->crtc_count; i++) { |
706 | crtc = fb_helper->crtc_info[i].mode_set.crtc; | 734 | crtc = fb_helper->crtc_info[i].mode_set.crtc; |
707 | 735 | ||
@@ -711,14 +739,14 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, | |||
711 | modeset->y = var->yoffset; | 739 | modeset->y = var->yoffset; |
712 | 740 | ||
713 | if (modeset->num_connectors) { | 741 | if (modeset->num_connectors) { |
714 | ret = crtc->funcs->set_config(modeset); | 742 | ret = drm_mode_set_config_internal(modeset); |
715 | if (!ret) { | 743 | if (!ret) { |
716 | info->var.xoffset = var->xoffset; | 744 | info->var.xoffset = var->xoffset; |
717 | info->var.yoffset = var->yoffset; | 745 | info->var.yoffset = var->yoffset; |
718 | } | 746 | } |
719 | } | 747 | } |
720 | } | 748 | } |
721 | mutex_unlock(&dev->mode_config.mutex); | 749 | drm_modeset_unlock_all(dev); |
722 | return ret; | 750 | return ret; |
723 | } | 751 | } |
724 | EXPORT_SYMBOL(drm_fb_helper_pan_display); | 752 | EXPORT_SYMBOL(drm_fb_helper_pan_display); |
@@ -1369,23 +1397,14 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) | |||
1369 | struct drm_device *dev = fb_helper->dev; | 1397 | struct drm_device *dev = fb_helper->dev; |
1370 | int count = 0; | 1398 | int count = 0; |
1371 | u32 max_width, max_height, bpp_sel; | 1399 | u32 max_width, max_height, bpp_sel; |
1372 | int bound = 0, crtcs_bound = 0; | ||
1373 | struct drm_crtc *crtc; | ||
1374 | 1400 | ||
1375 | if (!fb_helper->fb) | 1401 | if (!fb_helper->fb) |
1376 | return 0; | 1402 | return 0; |
1377 | 1403 | ||
1378 | mutex_lock(&dev->mode_config.mutex); | 1404 | drm_modeset_lock_all(dev); |
1379 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 1405 | if (!drm_fb_helper_is_bound(fb_helper)) { |
1380 | if (crtc->fb) | ||
1381 | crtcs_bound++; | ||
1382 | if (crtc->fb == fb_helper->fb) | ||
1383 | bound++; | ||
1384 | } | ||
1385 | |||
1386 | if (bound < crtcs_bound) { | ||
1387 | fb_helper->delayed_hotplug = true; | 1406 | fb_helper->delayed_hotplug = true; |
1388 | mutex_unlock(&dev->mode_config.mutex); | 1407 | drm_modeset_unlock_all(dev); |
1389 | return 0; | 1408 | return 0; |
1390 | } | 1409 | } |
1391 | DRM_DEBUG_KMS("\n"); | 1410 | DRM_DEBUG_KMS("\n"); |
@@ -1397,7 +1416,7 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) | |||
1397 | count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, | 1416 | count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, |
1398 | max_height); | 1417 | max_height); |
1399 | drm_setup_crtcs(fb_helper); | 1418 | drm_setup_crtcs(fb_helper); |
1400 | mutex_unlock(&dev->mode_config.mutex); | 1419 | drm_modeset_unlock_all(dev); |
1401 | 1420 | ||
1402 | return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); | 1421 | return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); |
1403 | } | 1422 | } |
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 133b4132983e..13fdcd10a605 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c | |||
@@ -276,6 +276,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, | |||
276 | 276 | ||
277 | INIT_LIST_HEAD(&priv->lhead); | 277 | INIT_LIST_HEAD(&priv->lhead); |
278 | INIT_LIST_HEAD(&priv->fbs); | 278 | INIT_LIST_HEAD(&priv->fbs); |
279 | mutex_init(&priv->fbs_lock); | ||
279 | INIT_LIST_HEAD(&priv->event_list); | 280 | INIT_LIST_HEAD(&priv->event_list); |
280 | init_waitqueue_head(&priv->event_wait); | 281 | init_waitqueue_head(&priv->event_wait); |
281 | priv->event_space = 4096; /* set aside 4k for event buffer */ | 282 | priv->event_space = 4096; /* set aside 4k for event buffer */ |
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 86272f04b82f..db1e2d6f90d7 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c | |||
@@ -252,11 +252,13 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, | |||
252 | 252 | ||
253 | BUG_ON(!hole_node->hole_follows || node->allocated); | 253 | BUG_ON(!hole_node->hole_follows || node->allocated); |
254 | 254 | ||
255 | if (mm->color_adjust) | ||
256 | mm->color_adjust(hole_node, color, &adj_start, &adj_end); | ||
257 | |||
258 | if (adj_start < start) | 255 | if (adj_start < start) |
259 | adj_start = start; | 256 | adj_start = start; |
257 | if (adj_end > end) | ||
258 | adj_end = end; | ||
259 | |||
260 | if (mm->color_adjust) | ||
261 | mm->color_adjust(hole_node, color, &adj_start, &adj_end); | ||
260 | 262 | ||
261 | if (alignment) { | 263 | if (alignment) { |
262 | unsigned tmp = adj_start % alignment; | 264 | unsigned tmp = adj_start % alignment; |
@@ -536,7 +538,7 @@ void drm_mm_init_scan(struct drm_mm *mm, | |||
536 | mm->scan_size = size; | 538 | mm->scan_size = size; |
537 | mm->scanned_blocks = 0; | 539 | mm->scanned_blocks = 0; |
538 | mm->scan_hit_start = 0; | 540 | mm->scan_hit_start = 0; |
539 | mm->scan_hit_size = 0; | 541 | mm->scan_hit_end = 0; |
540 | mm->scan_check_range = 0; | 542 | mm->scan_check_range = 0; |
541 | mm->prev_scanned_node = NULL; | 543 | mm->prev_scanned_node = NULL; |
542 | } | 544 | } |
@@ -563,7 +565,7 @@ void drm_mm_init_scan_with_range(struct drm_mm *mm, | |||
563 | mm->scan_size = size; | 565 | mm->scan_size = size; |
564 | mm->scanned_blocks = 0; | 566 | mm->scanned_blocks = 0; |
565 | mm->scan_hit_start = 0; | 567 | mm->scan_hit_start = 0; |
566 | mm->scan_hit_size = 0; | 568 | mm->scan_hit_end = 0; |
567 | mm->scan_start = start; | 569 | mm->scan_start = start; |
568 | mm->scan_end = end; | 570 | mm->scan_end = end; |
569 | mm->scan_check_range = 1; | 571 | mm->scan_check_range = 1; |
@@ -582,8 +584,7 @@ int drm_mm_scan_add_block(struct drm_mm_node *node) | |||
582 | struct drm_mm *mm = node->mm; | 584 | struct drm_mm *mm = node->mm; |
583 | struct drm_mm_node *prev_node; | 585 | struct drm_mm_node *prev_node; |
584 | unsigned long hole_start, hole_end; | 586 | unsigned long hole_start, hole_end; |
585 | unsigned long adj_start; | 587 | unsigned long adj_start, adj_end; |
586 | unsigned long adj_end; | ||
587 | 588 | ||
588 | mm->scanned_blocks++; | 589 | mm->scanned_blocks++; |
589 | 590 | ||
@@ -600,14 +601,8 @@ int drm_mm_scan_add_block(struct drm_mm_node *node) | |||
600 | node->node_list.next = &mm->prev_scanned_node->node_list; | 601 | node->node_list.next = &mm->prev_scanned_node->node_list; |
601 | mm->prev_scanned_node = node; | 602 | mm->prev_scanned_node = node; |
602 | 603 | ||
603 | hole_start = drm_mm_hole_node_start(prev_node); | 604 | adj_start = hole_start = drm_mm_hole_node_start(prev_node); |
604 | hole_end = drm_mm_hole_node_end(prev_node); | 605 | adj_end = hole_end = drm_mm_hole_node_end(prev_node); |
605 | |||
606 | adj_start = hole_start; | ||
607 | adj_end = hole_end; | ||
608 | |||
609 | if (mm->color_adjust) | ||
610 | mm->color_adjust(prev_node, mm->scan_color, &adj_start, &adj_end); | ||
611 | 606 | ||
612 | if (mm->scan_check_range) { | 607 | if (mm->scan_check_range) { |
613 | if (adj_start < mm->scan_start) | 608 | if (adj_start < mm->scan_start) |
@@ -616,11 +611,14 @@ int drm_mm_scan_add_block(struct drm_mm_node *node) | |||
616 | adj_end = mm->scan_end; | 611 | adj_end = mm->scan_end; |
617 | } | 612 | } |
618 | 613 | ||
614 | if (mm->color_adjust) | ||
615 | mm->color_adjust(prev_node, mm->scan_color, | ||
616 | &adj_start, &adj_end); | ||
617 | |||
619 | if (check_free_hole(adj_start, adj_end, | 618 | if (check_free_hole(adj_start, adj_end, |
620 | mm->scan_size, mm->scan_alignment)) { | 619 | mm->scan_size, mm->scan_alignment)) { |
621 | mm->scan_hit_start = hole_start; | 620 | mm->scan_hit_start = hole_start; |
622 | mm->scan_hit_size = hole_end; | 621 | mm->scan_hit_end = hole_end; |
623 | |||
624 | return 1; | 622 | return 1; |
625 | } | 623 | } |
626 | 624 | ||
@@ -656,19 +654,10 @@ int drm_mm_scan_remove_block(struct drm_mm_node *node) | |||
656 | node_list); | 654 | node_list); |
657 | 655 | ||
658 | prev_node->hole_follows = node->scanned_preceeds_hole; | 656 | prev_node->hole_follows = node->scanned_preceeds_hole; |
659 | INIT_LIST_HEAD(&node->node_list); | ||
660 | list_add(&node->node_list, &prev_node->node_list); | 657 | list_add(&node->node_list, &prev_node->node_list); |
661 | 658 | ||
662 | /* Only need to check for containement because start&size for the | 659 | return (drm_mm_hole_node_end(node) > mm->scan_hit_start && |
663 | * complete resulting free block (not just the desired part) is | 660 | node->start < mm->scan_hit_end); |
664 | * stored. */ | ||
665 | if (node->start >= mm->scan_hit_start && | ||
666 | node->start + node->size | ||
667 | <= mm->scan_hit_start + mm->scan_hit_size) { | ||
668 | return 1; | ||
669 | } | ||
670 | |||
671 | return 0; | ||
672 | } | 661 | } |
673 | EXPORT_SYMBOL(drm_mm_scan_remove_block); | 662 | EXPORT_SYMBOL(drm_mm_scan_remove_block); |
674 | 663 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 71f867340a88..90d335cfb8c0 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c | |||
@@ -326,8 +326,10 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev, | |||
326 | /* release drm framebuffer and real buffer */ | 326 | /* release drm framebuffer and real buffer */ |
327 | if (fb_helper->fb && fb_helper->fb->funcs) { | 327 | if (fb_helper->fb && fb_helper->fb->funcs) { |
328 | fb = fb_helper->fb; | 328 | fb = fb_helper->fb; |
329 | if (fb) | 329 | if (fb) { |
330 | drm_framebuffer_unregister_private(fb); | ||
330 | drm_framebuffer_remove(fb); | 331 | drm_framebuffer_remove(fb); |
332 | } | ||
331 | } | 333 | } |
332 | 334 | ||
333 | /* release linux framebuffer */ | 335 | /* release linux framebuffer */ |
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index afded54dbb10..c1ef37e2efdf 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c | |||
@@ -260,13 +260,13 @@ static int psb_framebuffer_init(struct drm_device *dev, | |||
260 | default: | 260 | default: |
261 | return -EINVAL; | 261 | return -EINVAL; |
262 | } | 262 | } |
263 | drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd); | ||
264 | fb->gtt = gt; | ||
263 | ret = drm_framebuffer_init(dev, &fb->base, &psb_fb_funcs); | 265 | ret = drm_framebuffer_init(dev, &fb->base, &psb_fb_funcs); |
264 | if (ret) { | 266 | if (ret) { |
265 | dev_err(dev->dev, "framebuffer init failed: %d\n", ret); | 267 | dev_err(dev->dev, "framebuffer init failed: %d\n", ret); |
266 | return ret; | 268 | return ret; |
267 | } | 269 | } |
268 | drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd); | ||
269 | fb->gtt = gt; | ||
270 | return 0; | 270 | return 0; |
271 | } | 271 | } |
272 | 272 | ||
@@ -590,6 +590,7 @@ static int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev) | |||
590 | framebuffer_release(info); | 590 | framebuffer_release(info); |
591 | } | 591 | } |
592 | drm_fb_helper_fini(&fbdev->psb_fb_helper); | 592 | drm_fb_helper_fini(&fbdev->psb_fb_helper); |
593 | drm_framebuffer_unregister_private(&psbfb->base); | ||
593 | drm_framebuffer_cleanup(&psbfb->base); | 594 | drm_framebuffer_cleanup(&psbfb->base); |
594 | 595 | ||
595 | if (psbfb->gtt) | 596 | if (psbfb->gtt) |
@@ -668,30 +669,6 @@ static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb) | |||
668 | { | 669 | { |
669 | struct psb_framebuffer *psbfb = to_psb_fb(fb); | 670 | struct psb_framebuffer *psbfb = to_psb_fb(fb); |
670 | struct gtt_range *r = psbfb->gtt; | 671 | struct gtt_range *r = psbfb->gtt; |
671 | struct drm_device *dev = fb->dev; | ||
672 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
673 | struct psb_fbdev *fbdev = dev_priv->fbdev; | ||
674 | struct drm_crtc *crtc; | ||
675 | int reset = 0; | ||
676 | |||
677 | /* Should never get stolen memory for a user fb */ | ||
678 | WARN_ON(r->stolen); | ||
679 | |||
680 | /* Check if we are erroneously live */ | ||
681 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) | ||
682 | if (crtc->fb == fb) | ||
683 | reset = 1; | ||
684 | |||
685 | if (reset) | ||
686 | /* | ||
687 | * Now force a sane response before we permit the DRM CRTC | ||
688 | * layer to do stupid things like blank the display. Instead | ||
689 | * we reset this framebuffer as if the user had forced a reset. | ||
690 | * We must do this before the cleanup so that the DRM layer | ||
691 | * doesn't get a chance to stick its oar in where it isn't | ||
692 | * wanted. | ||
693 | */ | ||
694 | drm_fb_helper_restore_fbdev_mode(&fbdev->psb_fb_helper); | ||
695 | 672 | ||
696 | /* Let DRM do its clean up */ | 673 | /* Let DRM do its clean up */ |
697 | drm_framebuffer_cleanup(fb); | 674 | drm_framebuffer_cleanup(fb); |
diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c index b58c4701c4e8..f6f534b4197e 100644 --- a/drivers/gpu/drm/gma500/psb_device.c +++ b/drivers/gpu/drm/gma500/psb_device.c | |||
@@ -194,7 +194,7 @@ static int psb_save_display_registers(struct drm_device *dev) | |||
194 | regs->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT); | 194 | regs->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT); |
195 | 195 | ||
196 | /* Save crtc and output state */ | 196 | /* Save crtc and output state */ |
197 | mutex_lock(&dev->mode_config.mutex); | 197 | drm_modeset_lock_all(dev); |
198 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 198 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
199 | if (drm_helper_crtc_in_use(crtc)) | 199 | if (drm_helper_crtc_in_use(crtc)) |
200 | crtc->funcs->save(crtc); | 200 | crtc->funcs->save(crtc); |
@@ -204,7 +204,7 @@ static int psb_save_display_registers(struct drm_device *dev) | |||
204 | if (connector->funcs->save) | 204 | if (connector->funcs->save) |
205 | connector->funcs->save(connector); | 205 | connector->funcs->save(connector); |
206 | 206 | ||
207 | mutex_unlock(&dev->mode_config.mutex); | 207 | drm_modeset_unlock_all(dev); |
208 | return 0; | 208 | return 0; |
209 | } | 209 | } |
210 | 210 | ||
@@ -234,7 +234,7 @@ static int psb_restore_display_registers(struct drm_device *dev) | |||
234 | /*make sure VGA plane is off. it initializes to on after reset!*/ | 234 | /*make sure VGA plane is off. it initializes to on after reset!*/ |
235 | PSB_WVDC32(0x80000000, VGACNTRL); | 235 | PSB_WVDC32(0x80000000, VGACNTRL); |
236 | 236 | ||
237 | mutex_lock(&dev->mode_config.mutex); | 237 | drm_modeset_lock_all(dev); |
238 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) | 238 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) |
239 | if (drm_helper_crtc_in_use(crtc)) | 239 | if (drm_helper_crtc_in_use(crtc)) |
240 | crtc->funcs->restore(crtc); | 240 | crtc->funcs->restore(crtc); |
@@ -243,7 +243,7 @@ static int psb_restore_display_registers(struct drm_device *dev) | |||
243 | if (connector->funcs->restore) | 243 | if (connector->funcs->restore) |
244 | connector->funcs->restore(connector); | 244 | connector->funcs->restore(connector); |
245 | 245 | ||
246 | mutex_unlock(&dev->mode_config.mutex); | 246 | drm_modeset_unlock_all(dev); |
247 | return 0; | 247 | return 0; |
248 | } | 248 | } |
249 | 249 | ||
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index dd1fbfa7e467..111e3df9c5de 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c | |||
@@ -149,6 +149,16 @@ static struct drm_ioctl_desc psb_ioctls[] = { | |||
149 | 149 | ||
150 | static void psb_lastclose(struct drm_device *dev) | 150 | static void psb_lastclose(struct drm_device *dev) |
151 | { | 151 | { |
152 | int ret; | ||
153 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
154 | struct psb_fbdev *fbdev = dev_priv->fbdev; | ||
155 | |||
156 | drm_modeset_lock_all(dev); | ||
157 | ret = drm_fb_helper_restore_fbdev_mode(&fbdev->psb_fb_helper); | ||
158 | if (ret) | ||
159 | DRM_DEBUG("failed to restore crtc mode\n"); | ||
160 | drm_modeset_unlock_all(dev); | ||
161 | |||
152 | return; | 162 | return; |
153 | } | 163 | } |
154 | 164 | ||
@@ -476,7 +486,7 @@ static int psb_mode_operation_ioctl(struct drm_device *dev, void *data, | |||
476 | case PSB_MODE_OPERATION_MODE_VALID: | 486 | case PSB_MODE_OPERATION_MODE_VALID: |
477 | umode = &arg->mode; | 487 | umode = &arg->mode; |
478 | 488 | ||
479 | mutex_lock(&dev->mode_config.mutex); | 489 | drm_modeset_lock_all(dev); |
480 | 490 | ||
481 | obj = drm_mode_object_find(dev, obj_id, | 491 | obj = drm_mode_object_find(dev, obj_id, |
482 | DRM_MODE_OBJECT_CONNECTOR); | 492 | DRM_MODE_OBJECT_CONNECTOR); |
@@ -525,7 +535,7 @@ static int psb_mode_operation_ioctl(struct drm_device *dev, void *data, | |||
525 | if (mode) | 535 | if (mode) |
526 | drm_mode_destroy(dev, mode); | 536 | drm_mode_destroy(dev, mode); |
527 | mode_op_out: | 537 | mode_op_out: |
528 | mutex_unlock(&dev->mode_config.mutex); | 538 | drm_modeset_unlock_all(dev); |
529 | return ret; | 539 | return ret; |
530 | 540 | ||
531 | default: | 541 | default: |
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c index b865d0728e28..51fa32392029 100644 --- a/drivers/gpu/drm/i2c/ch7006_drv.c +++ b/drivers/gpu/drm/i2c/ch7006_drv.c | |||
@@ -364,7 +364,7 @@ static int ch7006_encoder_set_property(struct drm_encoder *encoder, | |||
364 | .crtc = crtc, | 364 | .crtc = crtc, |
365 | }; | 365 | }; |
366 | 366 | ||
367 | crtc->funcs->set_config(&modeset); | 367 | drm_mode_set_config_internal(&modeset); |
368 | } | 368 | } |
369 | } | 369 | } |
370 | 370 | ||
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index f7d88e99ebf0..7576e7874698 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c | |||
@@ -1440,28 +1440,31 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) | |||
1440 | ifbdev = dev_priv->fbdev; | 1440 | ifbdev = dev_priv->fbdev; |
1441 | fb = to_intel_framebuffer(ifbdev->helper.fb); | 1441 | fb = to_intel_framebuffer(ifbdev->helper.fb); |
1442 | 1442 | ||
1443 | seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, obj ", | 1443 | seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, refcount %d, obj ", |
1444 | fb->base.width, | 1444 | fb->base.width, |
1445 | fb->base.height, | 1445 | fb->base.height, |
1446 | fb->base.depth, | 1446 | fb->base.depth, |
1447 | fb->base.bits_per_pixel); | 1447 | fb->base.bits_per_pixel, |
1448 | atomic_read(&fb->base.refcount.refcount)); | ||
1448 | describe_obj(m, fb->obj); | 1449 | describe_obj(m, fb->obj); |
1449 | seq_printf(m, "\n"); | 1450 | seq_printf(m, "\n"); |
1451 | mutex_unlock(&dev->mode_config.mutex); | ||
1450 | 1452 | ||
1453 | mutex_lock(&dev->mode_config.fb_lock); | ||
1451 | list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) { | 1454 | list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) { |
1452 | if (&fb->base == ifbdev->helper.fb) | 1455 | if (&fb->base == ifbdev->helper.fb) |
1453 | continue; | 1456 | continue; |
1454 | 1457 | ||
1455 | seq_printf(m, "user size: %d x %d, depth %d, %d bpp, obj ", | 1458 | seq_printf(m, "user size: %d x %d, depth %d, %d bpp, refcount %d, obj ", |
1456 | fb->base.width, | 1459 | fb->base.width, |
1457 | fb->base.height, | 1460 | fb->base.height, |
1458 | fb->base.depth, | 1461 | fb->base.depth, |
1459 | fb->base.bits_per_pixel); | 1462 | fb->base.bits_per_pixel, |
1463 | atomic_read(&fb->base.refcount.refcount)); | ||
1460 | describe_obj(m, fb->obj); | 1464 | describe_obj(m, fb->obj); |
1461 | seq_printf(m, "\n"); | 1465 | seq_printf(m, "\n"); |
1462 | } | 1466 | } |
1463 | 1467 | mutex_unlock(&dev->mode_config.fb_lock); | |
1464 | mutex_unlock(&dev->mode_config.mutex); | ||
1465 | 1468 | ||
1466 | return 0; | 1469 | return 0; |
1467 | } | 1470 | } |
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e6cc020ea32c..4418e14e3d69 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -1720,7 +1720,8 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj) | |||
1720 | } | 1720 | } |
1721 | 1721 | ||
1722 | static long | 1722 | static long |
1723 | i915_gem_purge(struct drm_i915_private *dev_priv, long target) | 1723 | __i915_gem_shrink(struct drm_i915_private *dev_priv, long target, |
1724 | bool purgeable_only) | ||
1724 | { | 1725 | { |
1725 | struct drm_i915_gem_object *obj, *next; | 1726 | struct drm_i915_gem_object *obj, *next; |
1726 | long count = 0; | 1727 | long count = 0; |
@@ -1728,7 +1729,7 @@ i915_gem_purge(struct drm_i915_private *dev_priv, long target) | |||
1728 | list_for_each_entry_safe(obj, next, | 1729 | list_for_each_entry_safe(obj, next, |
1729 | &dev_priv->mm.unbound_list, | 1730 | &dev_priv->mm.unbound_list, |
1730 | gtt_list) { | 1731 | gtt_list) { |
1731 | if (i915_gem_object_is_purgeable(obj) && | 1732 | if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) && |
1732 | i915_gem_object_put_pages(obj) == 0) { | 1733 | i915_gem_object_put_pages(obj) == 0) { |
1733 | count += obj->base.size >> PAGE_SHIFT; | 1734 | count += obj->base.size >> PAGE_SHIFT; |
1734 | if (count >= target) | 1735 | if (count >= target) |
@@ -1739,7 +1740,7 @@ i915_gem_purge(struct drm_i915_private *dev_priv, long target) | |||
1739 | list_for_each_entry_safe(obj, next, | 1740 | list_for_each_entry_safe(obj, next, |
1740 | &dev_priv->mm.inactive_list, | 1741 | &dev_priv->mm.inactive_list, |
1741 | mm_list) { | 1742 | mm_list) { |
1742 | if (i915_gem_object_is_purgeable(obj) && | 1743 | if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) && |
1743 | i915_gem_object_unbind(obj) == 0 && | 1744 | i915_gem_object_unbind(obj) == 0 && |
1744 | i915_gem_object_put_pages(obj) == 0) { | 1745 | i915_gem_object_put_pages(obj) == 0) { |
1745 | count += obj->base.size >> PAGE_SHIFT; | 1746 | count += obj->base.size >> PAGE_SHIFT; |
@@ -1751,6 +1752,12 @@ i915_gem_purge(struct drm_i915_private *dev_priv, long target) | |||
1751 | return count; | 1752 | return count; |
1752 | } | 1753 | } |
1753 | 1754 | ||
1755 | static long | ||
1756 | i915_gem_purge(struct drm_i915_private *dev_priv, long target) | ||
1757 | { | ||
1758 | return __i915_gem_shrink(dev_priv, target, true); | ||
1759 | } | ||
1760 | |||
1754 | static void | 1761 | static void |
1755 | i915_gem_shrink_all(struct drm_i915_private *dev_priv) | 1762 | i915_gem_shrink_all(struct drm_i915_private *dev_priv) |
1756 | { | 1763 | { |
@@ -3545,14 +3552,15 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data, | |||
3545 | goto out; | 3552 | goto out; |
3546 | } | 3553 | } |
3547 | 3554 | ||
3548 | obj->user_pin_count++; | 3555 | if (obj->user_pin_count == 0) { |
3549 | obj->pin_filp = file; | ||
3550 | if (obj->user_pin_count == 1) { | ||
3551 | ret = i915_gem_object_pin(obj, args->alignment, true, false); | 3556 | ret = i915_gem_object_pin(obj, args->alignment, true, false); |
3552 | if (ret) | 3557 | if (ret) |
3553 | goto out; | 3558 | goto out; |
3554 | } | 3559 | } |
3555 | 3560 | ||
3561 | obj->user_pin_count++; | ||
3562 | obj->pin_filp = file; | ||
3563 | |||
3556 | /* XXX - flush the CPU caches for pinned objects | 3564 | /* XXX - flush the CPU caches for pinned objects |
3557 | * as the X server doesn't manage domains yet | 3565 | * as the X server doesn't manage domains yet |
3558 | */ | 3566 | */ |
@@ -4382,6 +4390,9 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc) | |||
4382 | if (nr_to_scan) { | 4390 | if (nr_to_scan) { |
4383 | nr_to_scan -= i915_gem_purge(dev_priv, nr_to_scan); | 4391 | nr_to_scan -= i915_gem_purge(dev_priv, nr_to_scan); |
4384 | if (nr_to_scan > 0) | 4392 | if (nr_to_scan > 0) |
4393 | nr_to_scan -= __i915_gem_shrink(dev_priv, nr_to_scan, | ||
4394 | false); | ||
4395 | if (nr_to_scan > 0) | ||
4385 | i915_gem_shrink_all(dev_priv); | 4396 | i915_gem_shrink_all(dev_priv); |
4386 | } | 4397 | } |
4387 | 4398 | ||
@@ -4389,7 +4400,7 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc) | |||
4389 | list_for_each_entry(obj, &dev_priv->mm.unbound_list, gtt_list) | 4400 | list_for_each_entry(obj, &dev_priv->mm.unbound_list, gtt_list) |
4390 | if (obj->pages_pin_count == 0) | 4401 | if (obj->pages_pin_count == 0) |
4391 | cnt += obj->base.size >> PAGE_SHIFT; | 4402 | cnt += obj->base.size >> PAGE_SHIFT; |
4392 | list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) | 4403 | list_for_each_entry(obj, &dev_priv->mm.inactive_list, gtt_list) |
4393 | if (obj->pin_count == 0 && obj->pages_pin_count == 0) | 4404 | if (obj->pin_count == 0 && obj->pages_pin_count == 0) |
4394 | cnt += obj->base.size >> PAGE_SHIFT; | 4405 | cnt += obj->base.size >> PAGE_SHIFT; |
4395 | 4406 | ||
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8c36a11a9a57..8cda2ad19e26 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -6415,6 +6415,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, | |||
6415 | if (encoder->crtc) { | 6415 | if (encoder->crtc) { |
6416 | crtc = encoder->crtc; | 6416 | crtc = encoder->crtc; |
6417 | 6417 | ||
6418 | mutex_lock(&crtc->mutex); | ||
6419 | |||
6418 | old->dpms_mode = connector->dpms; | 6420 | old->dpms_mode = connector->dpms; |
6419 | old->load_detect_temp = false; | 6421 | old->load_detect_temp = false; |
6420 | 6422 | ||
@@ -6444,6 +6446,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, | |||
6444 | return false; | 6446 | return false; |
6445 | } | 6447 | } |
6446 | 6448 | ||
6449 | mutex_lock(&crtc->mutex); | ||
6447 | intel_encoder->new_crtc = to_intel_crtc(crtc); | 6450 | intel_encoder->new_crtc = to_intel_crtc(crtc); |
6448 | to_intel_connector(connector)->new_encoder = intel_encoder; | 6451 | to_intel_connector(connector)->new_encoder = intel_encoder; |
6449 | 6452 | ||
@@ -6471,6 +6474,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, | |||
6471 | DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n"); | 6474 | DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n"); |
6472 | if (IS_ERR(fb)) { | 6475 | if (IS_ERR(fb)) { |
6473 | DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n"); | 6476 | DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n"); |
6477 | mutex_unlock(&crtc->mutex); | ||
6474 | return false; | 6478 | return false; |
6475 | } | 6479 | } |
6476 | 6480 | ||
@@ -6478,6 +6482,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, | |||
6478 | DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); | 6482 | DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); |
6479 | if (old->release_fb) | 6483 | if (old->release_fb) |
6480 | old->release_fb->funcs->destroy(old->release_fb); | 6484 | old->release_fb->funcs->destroy(old->release_fb); |
6485 | mutex_unlock(&crtc->mutex); | ||
6481 | return false; | 6486 | return false; |
6482 | } | 6487 | } |
6483 | 6488 | ||
@@ -6492,20 +6497,21 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, | |||
6492 | struct intel_encoder *intel_encoder = | 6497 | struct intel_encoder *intel_encoder = |
6493 | intel_attached_encoder(connector); | 6498 | intel_attached_encoder(connector); |
6494 | struct drm_encoder *encoder = &intel_encoder->base; | 6499 | struct drm_encoder *encoder = &intel_encoder->base; |
6500 | struct drm_crtc *crtc = encoder->crtc; | ||
6495 | 6501 | ||
6496 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", | 6502 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", |
6497 | connector->base.id, drm_get_connector_name(connector), | 6503 | connector->base.id, drm_get_connector_name(connector), |
6498 | encoder->base.id, drm_get_encoder_name(encoder)); | 6504 | encoder->base.id, drm_get_encoder_name(encoder)); |
6499 | 6505 | ||
6500 | if (old->load_detect_temp) { | 6506 | if (old->load_detect_temp) { |
6501 | struct drm_crtc *crtc = encoder->crtc; | ||
6502 | |||
6503 | to_intel_connector(connector)->new_encoder = NULL; | 6507 | to_intel_connector(connector)->new_encoder = NULL; |
6504 | intel_encoder->new_crtc = NULL; | 6508 | intel_encoder->new_crtc = NULL; |
6505 | intel_set_mode(crtc, NULL, 0, 0, NULL); | 6509 | intel_set_mode(crtc, NULL, 0, 0, NULL); |
6506 | 6510 | ||
6507 | if (old->release_fb) | 6511 | if (old->release_fb) { |
6508 | old->release_fb->funcs->destroy(old->release_fb); | 6512 | drm_framebuffer_unregister_private(old->release_fb); |
6513 | drm_framebuffer_unreference(old->release_fb); | ||
6514 | } | ||
6509 | 6515 | ||
6510 | return; | 6516 | return; |
6511 | } | 6517 | } |
@@ -6513,6 +6519,8 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, | |||
6513 | /* Switch crtc and encoder back off if necessary */ | 6519 | /* Switch crtc and encoder back off if necessary */ |
6514 | if (old->dpms_mode != DRM_MODE_DPMS_ON) | 6520 | if (old->dpms_mode != DRM_MODE_DPMS_ON) |
6515 | connector->funcs->dpms(connector, old->dpms_mode); | 6521 | connector->funcs->dpms(connector, old->dpms_mode); |
6522 | |||
6523 | mutex_unlock(&crtc->mutex); | ||
6516 | } | 6524 | } |
6517 | 6525 | ||
6518 | /* Returns the clock of the currently programmed mode of the given pipe. */ | 6526 | /* Returns the clock of the currently programmed mode of the given pipe. */ |
@@ -8318,19 +8326,30 @@ int intel_framebuffer_init(struct drm_device *dev, | |||
8318 | { | 8326 | { |
8319 | int ret; | 8327 | int ret; |
8320 | 8328 | ||
8321 | if (obj->tiling_mode == I915_TILING_Y) | 8329 | if (obj->tiling_mode == I915_TILING_Y) { |
8330 | DRM_DEBUG("hardware does not support tiling Y\n"); | ||
8322 | return -EINVAL; | 8331 | return -EINVAL; |
8332 | } | ||
8323 | 8333 | ||
8324 | if (mode_cmd->pitches[0] & 63) | 8334 | if (mode_cmd->pitches[0] & 63) { |
8335 | DRM_DEBUG("pitch (%d) must be at least 64 byte aligned\n", | ||
8336 | mode_cmd->pitches[0]); | ||
8325 | return -EINVAL; | 8337 | return -EINVAL; |
8338 | } | ||
8326 | 8339 | ||
8327 | /* FIXME <= Gen4 stride limits are bit unclear */ | 8340 | /* FIXME <= Gen4 stride limits are bit unclear */ |
8328 | if (mode_cmd->pitches[0] > 32768) | 8341 | if (mode_cmd->pitches[0] > 32768) { |
8342 | DRM_DEBUG("pitch (%d) must be at less than 32768\n", | ||
8343 | mode_cmd->pitches[0]); | ||
8329 | return -EINVAL; | 8344 | return -EINVAL; |
8345 | } | ||
8330 | 8346 | ||
8331 | if (obj->tiling_mode != I915_TILING_NONE && | 8347 | if (obj->tiling_mode != I915_TILING_NONE && |
8332 | mode_cmd->pitches[0] != obj->stride) | 8348 | mode_cmd->pitches[0] != obj->stride) { |
8349 | DRM_DEBUG("pitch (%d) must match tiling stride (%d)\n", | ||
8350 | mode_cmd->pitches[0], obj->stride); | ||
8333 | return -EINVAL; | 8351 | return -EINVAL; |
8352 | } | ||
8334 | 8353 | ||
8335 | /* Reject formats not supported by any plane early. */ | 8354 | /* Reject formats not supported by any plane early. */ |
8336 | switch (mode_cmd->pixel_format) { | 8355 | switch (mode_cmd->pixel_format) { |
@@ -8341,8 +8360,10 @@ int intel_framebuffer_init(struct drm_device *dev, | |||
8341 | break; | 8360 | break; |
8342 | case DRM_FORMAT_XRGB1555: | 8361 | case DRM_FORMAT_XRGB1555: |
8343 | case DRM_FORMAT_ARGB1555: | 8362 | case DRM_FORMAT_ARGB1555: |
8344 | if (INTEL_INFO(dev)->gen > 3) | 8363 | if (INTEL_INFO(dev)->gen > 3) { |
8364 | DRM_DEBUG("invalid format: 0x%08x\n", mode_cmd->pixel_format); | ||
8345 | return -EINVAL; | 8365 | return -EINVAL; |
8366 | } | ||
8346 | break; | 8367 | break; |
8347 | case DRM_FORMAT_XBGR8888: | 8368 | case DRM_FORMAT_XBGR8888: |
8348 | case DRM_FORMAT_ABGR8888: | 8369 | case DRM_FORMAT_ABGR8888: |
@@ -8350,18 +8371,22 @@ int intel_framebuffer_init(struct drm_device *dev, | |||
8350 | case DRM_FORMAT_ARGB2101010: | 8371 | case DRM_FORMAT_ARGB2101010: |
8351 | case DRM_FORMAT_XBGR2101010: | 8372 | case DRM_FORMAT_XBGR2101010: |
8352 | case DRM_FORMAT_ABGR2101010: | 8373 | case DRM_FORMAT_ABGR2101010: |
8353 | if (INTEL_INFO(dev)->gen < 4) | 8374 | if (INTEL_INFO(dev)->gen < 4) { |
8375 | DRM_DEBUG("invalid format: 0x%08x\n", mode_cmd->pixel_format); | ||
8354 | return -EINVAL; | 8376 | return -EINVAL; |
8377 | } | ||
8355 | break; | 8378 | break; |
8356 | case DRM_FORMAT_YUYV: | 8379 | case DRM_FORMAT_YUYV: |
8357 | case DRM_FORMAT_UYVY: | 8380 | case DRM_FORMAT_UYVY: |
8358 | case DRM_FORMAT_YVYU: | 8381 | case DRM_FORMAT_YVYU: |
8359 | case DRM_FORMAT_VYUY: | 8382 | case DRM_FORMAT_VYUY: |
8360 | if (INTEL_INFO(dev)->gen < 6) | 8383 | if (INTEL_INFO(dev)->gen < 5) { |
8384 | DRM_DEBUG("invalid format: 0x%08x\n", mode_cmd->pixel_format); | ||
8361 | return -EINVAL; | 8385 | return -EINVAL; |
8386 | } | ||
8362 | break; | 8387 | break; |
8363 | default: | 8388 | default: |
8364 | DRM_DEBUG_KMS("unsupported pixel format 0x%08x\n", mode_cmd->pixel_format); | 8389 | DRM_DEBUG("unsupported pixel format 0x%08x\n", mode_cmd->pixel_format); |
8365 | return -EINVAL; | 8390 | return -EINVAL; |
8366 | } | 8391 | } |
8367 | 8392 | ||
@@ -8369,14 +8394,15 @@ int intel_framebuffer_init(struct drm_device *dev, | |||
8369 | if (mode_cmd->offsets[0] != 0) | 8394 | if (mode_cmd->offsets[0] != 0) |
8370 | return -EINVAL; | 8395 | return -EINVAL; |
8371 | 8396 | ||
8397 | drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); | ||
8398 | intel_fb->obj = obj; | ||
8399 | |||
8372 | ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); | 8400 | ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); |
8373 | if (ret) { | 8401 | if (ret) { |
8374 | DRM_ERROR("framebuffer init failed %d\n", ret); | 8402 | DRM_ERROR("framebuffer init failed %d\n", ret); |
8375 | return ret; | 8403 | return ret; |
8376 | } | 8404 | } |
8377 | 8405 | ||
8378 | drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); | ||
8379 | intel_fb->obj = obj; | ||
8380 | return 0; | 8406 | return 0; |
8381 | } | 8407 | } |
8382 | 8408 | ||
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5f12eb2d0fb5..e64c75727702 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
@@ -1101,6 +1101,8 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp) | |||
1101 | struct drm_i915_private *dev_priv = dev->dev_private; | 1101 | struct drm_i915_private *dev_priv = dev->dev_private; |
1102 | u32 pp; | 1102 | u32 pp; |
1103 | 1103 | ||
1104 | WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); | ||
1105 | |||
1104 | if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) { | 1106 | if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) { |
1105 | pp = ironlake_get_pp_control(dev_priv); | 1107 | pp = ironlake_get_pp_control(dev_priv); |
1106 | pp &= ~EDP_FORCE_VDD; | 1108 | pp &= ~EDP_FORCE_VDD; |
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 71d55801c0d9..755c27450a2c 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c | |||
@@ -221,6 +221,7 @@ static void intel_fbdev_destroy(struct drm_device *dev, | |||
221 | 221 | ||
222 | drm_fb_helper_fini(&ifbdev->helper); | 222 | drm_fb_helper_fini(&ifbdev->helper); |
223 | 223 | ||
224 | drm_framebuffer_unregister_private(&ifb->base); | ||
224 | drm_framebuffer_cleanup(&ifb->base); | 225 | drm_framebuffer_cleanup(&ifb->base); |
225 | if (ifb->obj) { | 226 | if (ifb->obj) { |
226 | drm_gem_object_unreference_unlocked(&ifb->obj->base); | 227 | drm_gem_object_unreference_unlocked(&ifb->obj->base); |
@@ -297,7 +298,7 @@ void intel_fb_restore_mode(struct drm_device *dev) | |||
297 | struct drm_mode_config *config = &dev->mode_config; | 298 | struct drm_mode_config *config = &dev->mode_config; |
298 | struct drm_plane *plane; | 299 | struct drm_plane *plane; |
299 | 300 | ||
300 | mutex_lock(&dev->mode_config.mutex); | 301 | drm_modeset_lock_all(dev); |
301 | 302 | ||
302 | ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); | 303 | ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); |
303 | if (ret) | 304 | if (ret) |
@@ -307,5 +308,5 @@ void intel_fb_restore_mode(struct drm_device *dev) | |||
307 | list_for_each_entry(plane, &config->plane_list, head) | 308 | list_for_each_entry(plane, &config->plane_list, head) |
308 | plane->funcs->disable_plane(plane); | 309 | plane->funcs->disable_plane(plane); |
309 | 310 | ||
310 | mutex_unlock(&dev->mode_config.mutex); | 311 | drm_modeset_unlock_all(dev); |
311 | } | 312 | } |
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 8c61876dbe95..5e3f08e3fd8b 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
@@ -586,9 +586,9 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, | |||
586 | 586 | ||
587 | dev_priv->modeset_on_lid = 0; | 587 | dev_priv->modeset_on_lid = 0; |
588 | 588 | ||
589 | mutex_lock(&dev->mode_config.mutex); | 589 | drm_modeset_lock_all(dev); |
590 | intel_modeset_setup_hw_state(dev, true); | 590 | intel_modeset_setup_hw_state(dev, true); |
591 | mutex_unlock(&dev->mode_config.mutex); | 591 | drm_modeset_unlock_all(dev); |
592 | 592 | ||
593 | return NOTIFY_OK; | 593 | return NOTIFY_OK; |
594 | } | 594 | } |
@@ -830,14 +830,6 @@ static const struct dmi_system_id intel_no_lvds[] = { | |||
830 | }, | 830 | }, |
831 | { | 831 | { |
832 | .callback = intel_no_lvds_dmi_callback, | 832 | .callback = intel_no_lvds_dmi_callback, |
833 | .ident = "ZOTAC ZBOXSD-ID12/ID13", | ||
834 | .matches = { | ||
835 | DMI_MATCH(DMI_BOARD_VENDOR, "ZOTAC"), | ||
836 | DMI_MATCH(DMI_BOARD_NAME, "ZBOXSD-ID12/ID13"), | ||
837 | }, | ||
838 | }, | ||
839 | { | ||
840 | .callback = intel_no_lvds_dmi_callback, | ||
841 | .ident = "Gigabyte GA-D525TUD", | 833 | .ident = "Gigabyte GA-D525TUD", |
842 | .matches = { | 834 | .matches = { |
843 | DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."), | 835 | DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."), |
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index fabe0acf808d..1e901c3c18af 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c | |||
@@ -1045,13 +1045,13 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, | |||
1045 | } | 1045 | } |
1046 | 1046 | ||
1047 | if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) { | 1047 | if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) { |
1048 | mutex_lock(&dev->mode_config.mutex); | 1048 | drm_modeset_lock_all(dev); |
1049 | mutex_lock(&dev->struct_mutex); | 1049 | mutex_lock(&dev->struct_mutex); |
1050 | 1050 | ||
1051 | ret = intel_overlay_switch_off(overlay); | 1051 | ret = intel_overlay_switch_off(overlay); |
1052 | 1052 | ||
1053 | mutex_unlock(&dev->struct_mutex); | 1053 | mutex_unlock(&dev->struct_mutex); |
1054 | mutex_unlock(&dev->mode_config.mutex); | 1054 | drm_modeset_unlock_all(dev); |
1055 | 1055 | ||
1056 | return ret; | 1056 | return ret; |
1057 | } | 1057 | } |
@@ -1075,7 +1075,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, | |||
1075 | goto out_free; | 1075 | goto out_free; |
1076 | } | 1076 | } |
1077 | 1077 | ||
1078 | mutex_lock(&dev->mode_config.mutex); | 1078 | drm_modeset_lock_all(dev); |
1079 | mutex_lock(&dev->struct_mutex); | 1079 | mutex_lock(&dev->struct_mutex); |
1080 | 1080 | ||
1081 | if (new_bo->tiling_mode) { | 1081 | if (new_bo->tiling_mode) { |
@@ -1157,7 +1157,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, | |||
1157 | goto out_unlock; | 1157 | goto out_unlock; |
1158 | 1158 | ||
1159 | mutex_unlock(&dev->struct_mutex); | 1159 | mutex_unlock(&dev->struct_mutex); |
1160 | mutex_unlock(&dev->mode_config.mutex); | 1160 | drm_modeset_unlock_all(dev); |
1161 | 1161 | ||
1162 | kfree(params); | 1162 | kfree(params); |
1163 | 1163 | ||
@@ -1165,7 +1165,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, | |||
1165 | 1165 | ||
1166 | out_unlock: | 1166 | out_unlock: |
1167 | mutex_unlock(&dev->struct_mutex); | 1167 | mutex_unlock(&dev->struct_mutex); |
1168 | mutex_unlock(&dev->mode_config.mutex); | 1168 | drm_modeset_unlock_all(dev); |
1169 | drm_gem_object_unreference_unlocked(&new_bo->base); | 1169 | drm_gem_object_unreference_unlocked(&new_bo->base); |
1170 | out_free: | 1170 | out_free: |
1171 | kfree(params); | 1171 | kfree(params); |
@@ -1241,7 +1241,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, | |||
1241 | return -ENODEV; | 1241 | return -ENODEV; |
1242 | } | 1242 | } |
1243 | 1243 | ||
1244 | mutex_lock(&dev->mode_config.mutex); | 1244 | drm_modeset_lock_all(dev); |
1245 | mutex_lock(&dev->struct_mutex); | 1245 | mutex_lock(&dev->struct_mutex); |
1246 | 1246 | ||
1247 | ret = -EINVAL; | 1247 | ret = -EINVAL; |
@@ -1307,7 +1307,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, | |||
1307 | ret = 0; | 1307 | ret = 0; |
1308 | out_unlock: | 1308 | out_unlock: |
1309 | mutex_unlock(&dev->struct_mutex); | 1309 | mutex_unlock(&dev->struct_mutex); |
1310 | mutex_unlock(&dev->mode_config.mutex); | 1310 | drm_modeset_unlock_all(dev); |
1311 | 1311 | ||
1312 | return ret; | 1312 | return ret; |
1313 | } | 1313 | } |
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5a8a72c5a89d..ca9734529229 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c | |||
@@ -44,6 +44,14 @@ | |||
44 | * i915.i915_enable_fbc parameter | 44 | * i915.i915_enable_fbc parameter |
45 | */ | 45 | */ |
46 | 46 | ||
47 | static bool intel_crtc_active(struct drm_crtc *crtc) | ||
48 | { | ||
49 | /* Be paranoid as we can arrive here with only partial | ||
50 | * state retrieved from the hardware during setup. | ||
51 | */ | ||
52 | return to_intel_crtc(crtc)->active && crtc->fb && crtc->mode.clock; | ||
53 | } | ||
54 | |||
47 | static void i8xx_disable_fbc(struct drm_device *dev) | 55 | static void i8xx_disable_fbc(struct drm_device *dev) |
48 | { | 56 | { |
49 | struct drm_i915_private *dev_priv = dev->dev_private; | 57 | struct drm_i915_private *dev_priv = dev->dev_private; |
@@ -405,9 +413,8 @@ void intel_update_fbc(struct drm_device *dev) | |||
405 | * - going to an unsupported config (interlace, pixel multiply, etc.) | 413 | * - going to an unsupported config (interlace, pixel multiply, etc.) |
406 | */ | 414 | */ |
407 | list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) { | 415 | list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) { |
408 | if (to_intel_crtc(tmp_crtc)->active && | 416 | if (intel_crtc_active(tmp_crtc) && |
409 | !to_intel_crtc(tmp_crtc)->primary_disabled && | 417 | !to_intel_crtc(tmp_crtc)->primary_disabled) { |
410 | tmp_crtc->fb) { | ||
411 | if (crtc) { | 418 | if (crtc) { |
412 | DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); | 419 | DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); |
413 | dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES; | 420 | dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES; |
@@ -995,7 +1002,7 @@ static struct drm_crtc *single_enabled_crtc(struct drm_device *dev) | |||
995 | struct drm_crtc *crtc, *enabled = NULL; | 1002 | struct drm_crtc *crtc, *enabled = NULL; |
996 | 1003 | ||
997 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 1004 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
998 | if (to_intel_crtc(crtc)->active && crtc->fb) { | 1005 | if (intel_crtc_active(crtc)) { |
999 | if (enabled) | 1006 | if (enabled) |
1000 | return NULL; | 1007 | return NULL; |
1001 | enabled = crtc; | 1008 | enabled = crtc; |
@@ -1089,7 +1096,7 @@ static bool g4x_compute_wm0(struct drm_device *dev, | |||
1089 | int entries, tlb_miss; | 1096 | int entries, tlb_miss; |
1090 | 1097 | ||
1091 | crtc = intel_get_crtc_for_plane(dev, plane); | 1098 | crtc = intel_get_crtc_for_plane(dev, plane); |
1092 | if (crtc->fb == NULL || !to_intel_crtc(crtc)->active) { | 1099 | if (!intel_crtc_active(crtc)) { |
1093 | *cursor_wm = cursor->guard_size; | 1100 | *cursor_wm = cursor->guard_size; |
1094 | *plane_wm = display->guard_size; | 1101 | *plane_wm = display->guard_size; |
1095 | return false; | 1102 | return false; |
@@ -1218,7 +1225,7 @@ static bool vlv_compute_drain_latency(struct drm_device *dev, | |||
1218 | int entries; | 1225 | int entries; |
1219 | 1226 | ||
1220 | crtc = intel_get_crtc_for_plane(dev, plane); | 1227 | crtc = intel_get_crtc_for_plane(dev, plane); |
1221 | if (crtc->fb == NULL || !to_intel_crtc(crtc)->active) | 1228 | if (!intel_crtc_active(crtc)) |
1222 | return false; | 1229 | return false; |
1223 | 1230 | ||
1224 | clock = crtc->mode.clock; /* VESA DOT Clock */ | 1231 | clock = crtc->mode.clock; /* VESA DOT Clock */ |
@@ -1479,7 +1486,7 @@ static void i9xx_update_wm(struct drm_device *dev) | |||
1479 | 1486 | ||
1480 | fifo_size = dev_priv->display.get_fifo_size(dev, 0); | 1487 | fifo_size = dev_priv->display.get_fifo_size(dev, 0); |
1481 | crtc = intel_get_crtc_for_plane(dev, 0); | 1488 | crtc = intel_get_crtc_for_plane(dev, 0); |
1482 | if (to_intel_crtc(crtc)->active && crtc->fb) { | 1489 | if (intel_crtc_active(crtc)) { |
1483 | int cpp = crtc->fb->bits_per_pixel / 8; | 1490 | int cpp = crtc->fb->bits_per_pixel / 8; |
1484 | if (IS_GEN2(dev)) | 1491 | if (IS_GEN2(dev)) |
1485 | cpp = 4; | 1492 | cpp = 4; |
@@ -1493,7 +1500,7 @@ static void i9xx_update_wm(struct drm_device *dev) | |||
1493 | 1500 | ||
1494 | fifo_size = dev_priv->display.get_fifo_size(dev, 1); | 1501 | fifo_size = dev_priv->display.get_fifo_size(dev, 1); |
1495 | crtc = intel_get_crtc_for_plane(dev, 1); | 1502 | crtc = intel_get_crtc_for_plane(dev, 1); |
1496 | if (to_intel_crtc(crtc)->active && crtc->fb) { | 1503 | if (intel_crtc_active(crtc)) { |
1497 | int cpp = crtc->fb->bits_per_pixel / 8; | 1504 | int cpp = crtc->fb->bits_per_pixel / 8; |
1498 | if (IS_GEN2(dev)) | 1505 | if (IS_GEN2(dev)) |
1499 | cpp = 4; | 1506 | cpp = 4; |
@@ -2047,7 +2054,7 @@ sandybridge_compute_sprite_wm(struct drm_device *dev, int plane, | |||
2047 | int entries, tlb_miss; | 2054 | int entries, tlb_miss; |
2048 | 2055 | ||
2049 | crtc = intel_get_crtc_for_plane(dev, plane); | 2056 | crtc = intel_get_crtc_for_plane(dev, plane); |
2050 | if (crtc->fb == NULL || !to_intel_crtc(crtc)->active) { | 2057 | if (!intel_crtc_active(crtc)) { |
2051 | *sprite_wm = display->guard_size; | 2058 | *sprite_wm = display->guard_size; |
2052 | return false; | 2059 | return false; |
2053 | } | 2060 | } |
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 827dcd4edf1c..f8293061d6bd 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c | |||
@@ -120,11 +120,10 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, | |||
120 | I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); | 120 | I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); |
121 | I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); | 121 | I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); |
122 | 122 | ||
123 | linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); | 123 | linear_offset = y * fb->pitches[0] + x * pixel_size; |
124 | sprsurf_offset = | 124 | sprsurf_offset = |
125 | intel_gen4_compute_offset_xtiled(&x, &y, | 125 | intel_gen4_compute_offset_xtiled(&x, &y, |
126 | fb->bits_per_pixel / 8, | 126 | pixel_size, fb->pitches[0]); |
127 | fb->pitches[0]); | ||
128 | linear_offset -= sprsurf_offset; | 127 | linear_offset -= sprsurf_offset; |
129 | 128 | ||
130 | /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET | 129 | /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET |
@@ -286,11 +285,10 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, | |||
286 | I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); | 285 | I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); |
287 | I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); | 286 | I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); |
288 | 287 | ||
289 | linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); | 288 | linear_offset = y * fb->pitches[0] + x * pixel_size; |
290 | dvssurf_offset = | 289 | dvssurf_offset = |
291 | intel_gen4_compute_offset_xtiled(&x, &y, | 290 | intel_gen4_compute_offset_xtiled(&x, &y, |
292 | fb->bits_per_pixel / 8, | 291 | pixel_size, fb->pitches[0]); |
293 | fb->pitches[0]); | ||
294 | linear_offset -= dvssurf_offset; | 292 | linear_offset -= dvssurf_offset; |
295 | 293 | ||
296 | if (obj->tiling_mode != I915_TILING_NONE) | 294 | if (obj->tiling_mode != I915_TILING_NONE) |
@@ -595,7 +593,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, | |||
595 | if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) | 593 | if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) |
596 | return -EINVAL; | 594 | return -EINVAL; |
597 | 595 | ||
598 | mutex_lock(&dev->mode_config.mutex); | 596 | drm_modeset_lock_all(dev); |
599 | 597 | ||
600 | obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE); | 598 | obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE); |
601 | if (!obj) { | 599 | if (!obj) { |
@@ -608,7 +606,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, | |||
608 | ret = intel_plane->update_colorkey(plane, set); | 606 | ret = intel_plane->update_colorkey(plane, set); |
609 | 607 | ||
610 | out_unlock: | 608 | out_unlock: |
611 | mutex_unlock(&dev->mode_config.mutex); | 609 | drm_modeset_unlock_all(dev); |
612 | return ret; | 610 | return ret; |
613 | } | 611 | } |
614 | 612 | ||
@@ -624,7 +622,7 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data, | |||
624 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 622 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
625 | return -ENODEV; | 623 | return -ENODEV; |
626 | 624 | ||
627 | mutex_lock(&dev->mode_config.mutex); | 625 | drm_modeset_lock_all(dev); |
628 | 626 | ||
629 | obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE); | 627 | obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE); |
630 | if (!obj) { | 628 | if (!obj) { |
@@ -637,7 +635,7 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data, | |||
637 | intel_plane->get_colorkey(plane, get); | 635 | intel_plane->get_colorkey(plane, get); |
638 | 636 | ||
639 | out_unlock: | 637 | out_unlock: |
640 | mutex_unlock(&dev->mode_config.mutex); | 638 | drm_modeset_unlock_all(dev); |
641 | return ret; | 639 | return ret; |
642 | } | 640 | } |
643 | 641 | ||
diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c index 2f486481d79a..5c69b432f99a 100644 --- a/drivers/gpu/drm/mgag200/mgag200_fb.c +++ b/drivers/gpu/drm/mgag200/mgag200_fb.c | |||
@@ -247,6 +247,7 @@ static int mga_fbdev_destroy(struct drm_device *dev, | |||
247 | } | 247 | } |
248 | drm_fb_helper_fini(&mfbdev->helper); | 248 | drm_fb_helper_fini(&mfbdev->helper); |
249 | vfree(mfbdev->sysram); | 249 | vfree(mfbdev->sysram); |
250 | drm_framebuffer_unregister_private(&mfb->base); | ||
250 | drm_framebuffer_cleanup(&mfb->base); | 251 | drm_framebuffer_cleanup(&mfb->base); |
251 | 252 | ||
252 | return 0; | 253 | return 0; |
diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c index 70dd3c5529d4..64297c72464f 100644 --- a/drivers/gpu/drm/mgag200/mgag200_main.c +++ b/drivers/gpu/drm/mgag200/mgag200_main.c | |||
@@ -23,16 +23,8 @@ static void mga_user_framebuffer_destroy(struct drm_framebuffer *fb) | |||
23 | kfree(fb); | 23 | kfree(fb); |
24 | } | 24 | } |
25 | 25 | ||
26 | static int mga_user_framebuffer_create_handle(struct drm_framebuffer *fb, | ||
27 | struct drm_file *file_priv, | ||
28 | unsigned int *handle) | ||
29 | { | ||
30 | return 0; | ||
31 | } | ||
32 | |||
33 | static const struct drm_framebuffer_funcs mga_fb_funcs = { | 26 | static const struct drm_framebuffer_funcs mga_fb_funcs = { |
34 | .destroy = mga_user_framebuffer_destroy, | 27 | .destroy = mga_user_framebuffer_destroy, |
35 | .create_handle = mga_user_framebuffer_create_handle, | ||
36 | }; | 28 | }; |
37 | 29 | ||
38 | int mgag200_framebuffer_init(struct drm_device *dev, | 30 | int mgag200_framebuffer_init(struct drm_device *dev, |
@@ -40,13 +32,15 @@ int mgag200_framebuffer_init(struct drm_device *dev, | |||
40 | struct drm_mode_fb_cmd2 *mode_cmd, | 32 | struct drm_mode_fb_cmd2 *mode_cmd, |
41 | struct drm_gem_object *obj) | 33 | struct drm_gem_object *obj) |
42 | { | 34 | { |
43 | int ret = drm_framebuffer_init(dev, &gfb->base, &mga_fb_funcs); | 35 | int ret; |
36 | |||
37 | drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd); | ||
38 | gfb->obj = obj; | ||
39 | ret = drm_framebuffer_init(dev, &gfb->base, &mga_fb_funcs); | ||
44 | if (ret) { | 40 | if (ret) { |
45 | DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); | 41 | DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); |
46 | return ret; | 42 | return ret; |
47 | } | 43 | } |
48 | drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd); | ||
49 | gfb->obj = obj; | ||
50 | return 0; | 44 | return 0; |
51 | } | 45 | } |
52 | 46 | ||
diff --git a/drivers/gpu/drm/nouveau/core/core/client.c b/drivers/gpu/drm/nouveau/core/core/client.c index c617f0480071..8bbb58f94a19 100644 --- a/drivers/gpu/drm/nouveau/core/core/client.c +++ b/drivers/gpu/drm/nouveau/core/core/client.c | |||
@@ -66,10 +66,8 @@ nouveau_client_create_(const char *name, u64 devname, const char *cfg, | |||
66 | 66 | ||
67 | ret = nouveau_handle_create(nv_object(client), ~0, ~0, | 67 | ret = nouveau_handle_create(nv_object(client), ~0, ~0, |
68 | nv_object(client), &client->root); | 68 | nv_object(client), &client->root); |
69 | if (ret) { | 69 | if (ret) |
70 | nouveau_namedb_destroy(&client->base); | ||
71 | return ret; | 70 | return ret; |
72 | } | ||
73 | 71 | ||
74 | /* prevent init/fini being called, os in in charge of this */ | 72 | /* prevent init/fini being called, os in in charge of this */ |
75 | atomic_set(&nv_object(client)->usecount, 2); | 73 | atomic_set(&nv_object(client)->usecount, 2); |
diff --git a/drivers/gpu/drm/nouveau/core/core/handle.c b/drivers/gpu/drm/nouveau/core/core/handle.c index b8d2cbf8a7a7..264c2b338ac3 100644 --- a/drivers/gpu/drm/nouveau/core/core/handle.c +++ b/drivers/gpu/drm/nouveau/core/core/handle.c | |||
@@ -109,7 +109,7 @@ nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle, | |||
109 | while (!nv_iclass(namedb, NV_NAMEDB_CLASS)) | 109 | while (!nv_iclass(namedb, NV_NAMEDB_CLASS)) |
110 | namedb = namedb->parent; | 110 | namedb = namedb->parent; |
111 | 111 | ||
112 | handle = *phandle = kzalloc(sizeof(*handle), GFP_KERNEL); | 112 | handle = kzalloc(sizeof(*handle), GFP_KERNEL); |
113 | if (!handle) | 113 | if (!handle) |
114 | return -ENOMEM; | 114 | return -ENOMEM; |
115 | 115 | ||
@@ -146,6 +146,9 @@ nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle, | |||
146 | } | 146 | } |
147 | 147 | ||
148 | hprintk(handle, TRACE, "created\n"); | 148 | hprintk(handle, TRACE, "created\n"); |
149 | |||
150 | *phandle = handle; | ||
151 | |||
149 | return 0; | 152 | return 0; |
150 | } | 153 | } |
151 | 154 | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index 0f09af135415..ca1a7d76a95b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c | |||
@@ -851,20 +851,23 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) | |||
851 | for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) | 851 | for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) |
852 | ctrl = nv_rd32(priv, 0x610b5c + (i * 8)); | 852 | ctrl = nv_rd32(priv, 0x610b5c + (i * 8)); |
853 | 853 | ||
854 | if (nv_device(priv)->chipset < 0x90 || | 854 | if (!(ctrl & (1 << head))) { |
855 | nv_device(priv)->chipset == 0x92 || | 855 | if (nv_device(priv)->chipset < 0x90 || |
856 | nv_device(priv)->chipset == 0xa0) { | 856 | nv_device(priv)->chipset == 0x92 || |
857 | for (i = 0; !(ctrl & (1 << head)) && i < 2; i++) | 857 | nv_device(priv)->chipset == 0xa0) { |
858 | ctrl = nv_rd32(priv, 0x610b74 + (i * 8)); | 858 | for (i = 0; !(ctrl & (1 << head)) && i < 2; i++) |
859 | i += 3; | 859 | ctrl = nv_rd32(priv, 0x610b74 + (i * 8)); |
860 | } else { | 860 | i += 4; |
861 | for (i = 0; !(ctrl & (1 << head)) && i < 4; i++) | 861 | } else { |
862 | ctrl = nv_rd32(priv, 0x610798 + (i * 8)); | 862 | for (i = 0; !(ctrl & (1 << head)) && i < 4; i++) |
863 | i += 3; | 863 | ctrl = nv_rd32(priv, 0x610798 + (i * 8)); |
864 | i += 4; | ||
865 | } | ||
864 | } | 866 | } |
865 | 867 | ||
866 | if (!(ctrl & (1 << head))) | 868 | if (!(ctrl & (1 << head))) |
867 | return false; | 869 | return false; |
870 | i--; | ||
868 | 871 | ||
869 | data = exec_lookup(priv, head, i, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info); | 872 | data = exec_lookup(priv, head, i, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info); |
870 | if (data) { | 873 | if (data) { |
@@ -898,20 +901,23 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, | |||
898 | for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) | 901 | for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) |
899 | ctrl = nv_rd32(priv, 0x610b58 + (i * 8)); | 902 | ctrl = nv_rd32(priv, 0x610b58 + (i * 8)); |
900 | 903 | ||
901 | if (nv_device(priv)->chipset < 0x90 || | 904 | if (!(ctrl & (1 << head))) { |
902 | nv_device(priv)->chipset == 0x92 || | 905 | if (nv_device(priv)->chipset < 0x90 || |
903 | nv_device(priv)->chipset == 0xa0) { | 906 | nv_device(priv)->chipset == 0x92 || |
904 | for (i = 0; !(ctrl & (1 << head)) && i < 2; i++) | 907 | nv_device(priv)->chipset == 0xa0) { |
905 | ctrl = nv_rd32(priv, 0x610b70 + (i * 8)); | 908 | for (i = 0; !(ctrl & (1 << head)) && i < 2; i++) |
906 | i += 3; | 909 | ctrl = nv_rd32(priv, 0x610b70 + (i * 8)); |
907 | } else { | 910 | i += 4; |
908 | for (i = 0; !(ctrl & (1 << head)) && i < 4; i++) | 911 | } else { |
909 | ctrl = nv_rd32(priv, 0x610794 + (i * 8)); | 912 | for (i = 0; !(ctrl & (1 << head)) && i < 4; i++) |
910 | i += 3; | 913 | ctrl = nv_rd32(priv, 0x610794 + (i * 8)); |
914 | i += 4; | ||
915 | } | ||
911 | } | 916 | } |
912 | 917 | ||
913 | if (!(ctrl & (1 << head))) | 918 | if (!(ctrl & (1 << head))) |
914 | return 0x0000; | 919 | return 0x0000; |
920 | i--; | ||
915 | 921 | ||
916 | data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1); | 922 | data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1); |
917 | if (!data) | 923 | if (!data) |
diff --git a/drivers/gpu/drm/nouveau/core/include/core/client.h b/drivers/gpu/drm/nouveau/core/include/core/client.h index 0193532ceac9..63acc0346ff2 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/client.h +++ b/drivers/gpu/drm/nouveau/core/include/core/client.h | |||
@@ -36,6 +36,9 @@ nouveau_client(void *obj) | |||
36 | 36 | ||
37 | int nouveau_client_create_(const char *name, u64 device, const char *cfg, | 37 | int nouveau_client_create_(const char *name, u64 device, const char *cfg, |
38 | const char *dbg, int, void **); | 38 | const char *dbg, int, void **); |
39 | #define nouveau_client_destroy(p) \ | ||
40 | nouveau_namedb_destroy(&(p)->base) | ||
41 | |||
39 | int nouveau_client_init(struct nouveau_client *); | 42 | int nouveau_client_init(struct nouveau_client *); |
40 | int nouveau_client_fini(struct nouveau_client *, bool suspend); | 43 | int nouveau_client_fini(struct nouveau_client *, bool suspend); |
41 | 44 | ||
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h index c345097592f2..b2f3d4d0aa49 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h | |||
@@ -38,6 +38,8 @@ enum nvbios_pll_type { | |||
38 | PLL_UNK42 = 0x42, | 38 | PLL_UNK42 = 0x42, |
39 | PLL_VPLL0 = 0x80, | 39 | PLL_VPLL0 = 0x80, |
40 | PLL_VPLL1 = 0x81, | 40 | PLL_VPLL1 = 0x81, |
41 | PLL_VPLL2 = 0x82, | ||
42 | PLL_VPLL3 = 0x83, | ||
41 | PLL_MAX = 0xff | 43 | PLL_MAX = 0xff |
42 | }; | 44 | }; |
43 | 45 | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c index 2917d552689b..690ed438b2ad 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c | |||
@@ -1534,7 +1534,6 @@ init_io(struct nvbios_init *init) | |||
1534 | mdelay(10); | 1534 | mdelay(10); |
1535 | init_wr32(init, 0x614100, 0x10000018); | 1535 | init_wr32(init, 0x614100, 0x10000018); |
1536 | init_wr32(init, 0x614900, 0x10000018); | 1536 | init_wr32(init, 0x614900, 0x10000018); |
1537 | return; | ||
1538 | } | 1537 | } |
1539 | 1538 | ||
1540 | value = init_rdport(init, port) & mask; | 1539 | value = init_rdport(init, port) & mask; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c index f6962c9b6c36..7c9626258a46 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c | |||
@@ -52,6 +52,8 @@ nvc0_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq) | |||
52 | switch (info.type) { | 52 | switch (info.type) { |
53 | case PLL_VPLL0: | 53 | case PLL_VPLL0: |
54 | case PLL_VPLL1: | 54 | case PLL_VPLL1: |
55 | case PLL_VPLL2: | ||
56 | case PLL_VPLL3: | ||
55 | nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100); | 57 | nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100); |
56 | nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M); | 58 | nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M); |
57 | nv_wr32(priv, info.reg + 0x10, fN << 16); | 59 | nv_wr32(priv, info.reg + 0x10, fN << 16); |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c index 306bdf121452..7606ed15b6fa 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c | |||
@@ -145,14 +145,14 @@ nvc0_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, | |||
145 | mem->memtype = type; | 145 | mem->memtype = type; |
146 | mem->size = size; | 146 | mem->size = size; |
147 | 147 | ||
148 | mutex_lock(&mm->mutex); | 148 | mutex_lock(&pfb->base.mutex); |
149 | do { | 149 | do { |
150 | if (back) | 150 | if (back) |
151 | ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r); | 151 | ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r); |
152 | else | 152 | else |
153 | ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r); | 153 | ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r); |
154 | if (ret) { | 154 | if (ret) { |
155 | mutex_unlock(&mm->mutex); | 155 | mutex_unlock(&pfb->base.mutex); |
156 | pfb->ram.put(pfb, &mem); | 156 | pfb->ram.put(pfb, &mem); |
157 | return ret; | 157 | return ret; |
158 | } | 158 | } |
@@ -160,7 +160,7 @@ nvc0_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, | |||
160 | list_add_tail(&r->rl_entry, &mem->regions); | 160 | list_add_tail(&r->rl_entry, &mem->regions); |
161 | size -= r->length; | 161 | size -= r->length; |
162 | } while (size); | 162 | } while (size); |
163 | mutex_unlock(&mm->mutex); | 163 | mutex_unlock(&pfb->base.mutex); |
164 | 164 | ||
165 | r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry); | 165 | r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry); |
166 | mem->offset = (u64)r->offset << 12; | 166 | mem->offset = (u64)r->offset << 12; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c index 1188227ca6aa..6565f3dbbe04 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c | |||
@@ -40,15 +40,21 @@ nouveau_instobj_create_(struct nouveau_object *parent, | |||
40 | if (ret) | 40 | if (ret) |
41 | return ret; | 41 | return ret; |
42 | 42 | ||
43 | mutex_lock(&imem->base.mutex); | ||
43 | list_add(&iobj->head, &imem->list); | 44 | list_add(&iobj->head, &imem->list); |
45 | mutex_unlock(&imem->base.mutex); | ||
44 | return 0; | 46 | return 0; |
45 | } | 47 | } |
46 | 48 | ||
47 | void | 49 | void |
48 | nouveau_instobj_destroy(struct nouveau_instobj *iobj) | 50 | nouveau_instobj_destroy(struct nouveau_instobj *iobj) |
49 | { | 51 | { |
50 | if (iobj->head.prev) | 52 | struct nouveau_subdev *subdev = nv_subdev(iobj->base.engine); |
51 | list_del(&iobj->head); | 53 | |
54 | mutex_lock(&subdev->mutex); | ||
55 | list_del(&iobj->head); | ||
56 | mutex_unlock(&subdev->mutex); | ||
57 | |||
52 | return nouveau_object_destroy(&iobj->base); | 58 | return nouveau_object_destroy(&iobj->base); |
53 | } | 59 | } |
54 | 60 | ||
@@ -88,6 +94,8 @@ nouveau_instmem_init(struct nouveau_instmem *imem) | |||
88 | if (ret) | 94 | if (ret) |
89 | return ret; | 95 | return ret; |
90 | 96 | ||
97 | mutex_lock(&imem->base.mutex); | ||
98 | |||
91 | list_for_each_entry(iobj, &imem->list, head) { | 99 | list_for_each_entry(iobj, &imem->list, head) { |
92 | if (iobj->suspend) { | 100 | if (iobj->suspend) { |
93 | for (i = 0; i < iobj->size; i += 4) | 101 | for (i = 0; i < iobj->size; i += 4) |
@@ -97,6 +105,8 @@ nouveau_instmem_init(struct nouveau_instmem *imem) | |||
97 | } | 105 | } |
98 | } | 106 | } |
99 | 107 | ||
108 | mutex_unlock(&imem->base.mutex); | ||
109 | |||
100 | return 0; | 110 | return 0; |
101 | } | 111 | } |
102 | 112 | ||
@@ -104,17 +114,26 @@ int | |||
104 | nouveau_instmem_fini(struct nouveau_instmem *imem, bool suspend) | 114 | nouveau_instmem_fini(struct nouveau_instmem *imem, bool suspend) |
105 | { | 115 | { |
106 | struct nouveau_instobj *iobj; | 116 | struct nouveau_instobj *iobj; |
107 | int i; | 117 | int i, ret = 0; |
108 | 118 | ||
109 | if (suspend) { | 119 | if (suspend) { |
120 | mutex_lock(&imem->base.mutex); | ||
121 | |||
110 | list_for_each_entry(iobj, &imem->list, head) { | 122 | list_for_each_entry(iobj, &imem->list, head) { |
111 | iobj->suspend = vmalloc(iobj->size); | 123 | iobj->suspend = vmalloc(iobj->size); |
112 | if (iobj->suspend) { | 124 | if (!iobj->suspend) { |
113 | for (i = 0; i < iobj->size; i += 4) | 125 | ret = -ENOMEM; |
114 | iobj->suspend[i / 4] = nv_ro32(iobj, i); | 126 | break; |
115 | } else | 127 | } |
116 | return -ENOMEM; | 128 | |
129 | for (i = 0; i < iobj->size; i += 4) | ||
130 | iobj->suspend[i / 4] = nv_ro32(iobj, i); | ||
117 | } | 131 | } |
132 | |||
133 | mutex_unlock(&imem->base.mutex); | ||
134 | |||
135 | if (ret) | ||
136 | return ret; | ||
118 | } | 137 | } |
119 | 138 | ||
120 | return nouveau_subdev_fini(&imem->base, suspend); | 139 | return nouveau_subdev_fini(&imem->base, suspend); |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c index 082c11b75acb..77c67fc970e6 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c | |||
@@ -352,7 +352,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length, | |||
352 | u64 mm_length = (offset + length) - mm_offset; | 352 | u64 mm_length = (offset + length) - mm_offset; |
353 | int ret; | 353 | int ret; |
354 | 354 | ||
355 | vm = *pvm = kzalloc(sizeof(*vm), GFP_KERNEL); | 355 | vm = kzalloc(sizeof(*vm), GFP_KERNEL); |
356 | if (!vm) | 356 | if (!vm) |
357 | return -ENOMEM; | 357 | return -ENOMEM; |
358 | 358 | ||
@@ -376,6 +376,8 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length, | |||
376 | return ret; | 376 | return ret; |
377 | } | 377 | } |
378 | 378 | ||
379 | *pvm = vm; | ||
380 | |||
379 | return 0; | 381 | return 0; |
380 | } | 382 | } |
381 | 383 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 69d7b1d0b9d6..64d6e3047dee 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c | |||
@@ -300,17 +300,18 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype) | |||
300 | struct ttm_buffer_object *bo = &nvbo->bo; | 300 | struct ttm_buffer_object *bo = &nvbo->bo; |
301 | int ret; | 301 | int ret; |
302 | 302 | ||
303 | ret = ttm_bo_reserve(bo, false, false, false, 0); | ||
304 | if (ret) | ||
305 | goto out; | ||
306 | |||
303 | if (nvbo->pin_refcnt && !(memtype & (1 << bo->mem.mem_type))) { | 307 | if (nvbo->pin_refcnt && !(memtype & (1 << bo->mem.mem_type))) { |
304 | NV_ERROR(drm, "bo %p pinned elsewhere: 0x%08x vs 0x%08x\n", bo, | 308 | NV_ERROR(drm, "bo %p pinned elsewhere: 0x%08x vs 0x%08x\n", bo, |
305 | 1 << bo->mem.mem_type, memtype); | 309 | 1 << bo->mem.mem_type, memtype); |
306 | return -EINVAL; | 310 | ret = -EINVAL; |
311 | goto out; | ||
307 | } | 312 | } |
308 | 313 | ||
309 | if (nvbo->pin_refcnt++) | 314 | if (nvbo->pin_refcnt++) |
310 | return 0; | ||
311 | |||
312 | ret = ttm_bo_reserve(bo, false, false, false, 0); | ||
313 | if (ret) | ||
314 | goto out; | 315 | goto out; |
315 | 316 | ||
316 | nouveau_bo_placement_set(nvbo, memtype, 0); | 317 | nouveau_bo_placement_set(nvbo, memtype, 0); |
@@ -328,10 +329,8 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype) | |||
328 | break; | 329 | break; |
329 | } | 330 | } |
330 | } | 331 | } |
331 | ttm_bo_unreserve(bo); | ||
332 | out: | 332 | out: |
333 | if (unlikely(ret)) | 333 | ttm_bo_unreserve(bo); |
334 | nvbo->pin_refcnt--; | ||
335 | return ret; | 334 | return ret; |
336 | } | 335 | } |
337 | 336 | ||
@@ -342,13 +341,13 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo) | |||
342 | struct ttm_buffer_object *bo = &nvbo->bo; | 341 | struct ttm_buffer_object *bo = &nvbo->bo; |
343 | int ret; | 342 | int ret; |
344 | 343 | ||
345 | if (--nvbo->pin_refcnt) | ||
346 | return 0; | ||
347 | |||
348 | ret = ttm_bo_reserve(bo, false, false, false, 0); | 344 | ret = ttm_bo_reserve(bo, false, false, false, 0); |
349 | if (ret) | 345 | if (ret) |
350 | return ret; | 346 | return ret; |
351 | 347 | ||
348 | if (--nvbo->pin_refcnt) | ||
349 | goto out; | ||
350 | |||
352 | nouveau_bo_placement_set(nvbo, bo->mem.placement, 0); | 351 | nouveau_bo_placement_set(nvbo, bo->mem.placement, 0); |
353 | 352 | ||
354 | ret = nouveau_bo_validate(nvbo, false, false); | 353 | ret = nouveau_bo_validate(nvbo, false, false); |
@@ -365,6 +364,7 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo) | |||
365 | } | 364 | } |
366 | } | 365 | } |
367 | 366 | ||
367 | out: | ||
368 | ttm_bo_unreserve(bo); | 368 | ttm_bo_unreserve(bo); |
369 | return ret; | 369 | return ret; |
370 | } | 370 | } |
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h index 25ca37989d2c..81d00fe03b56 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.h +++ b/drivers/gpu/drm/nouveau/nouveau_bo.h | |||
@@ -28,6 +28,8 @@ struct nouveau_bo { | |||
28 | struct nouveau_drm_tile *tile; | 28 | struct nouveau_drm_tile *tile; |
29 | 29 | ||
30 | struct drm_gem_object *gem; | 30 | struct drm_gem_object *gem; |
31 | |||
32 | /* protect by the ttm reservation lock */ | ||
31 | int pin_refcnt; | 33 | int pin_refcnt; |
32 | 34 | ||
33 | struct ttm_bo_kmap_obj dma_buf_vmap; | 35 | struct ttm_bo_kmap_obj dma_buf_vmap; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index ac340ba32017..e620ba8271b4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c | |||
@@ -127,12 +127,26 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, | |||
127 | struct nouveau_encoder **pnv_encoder) | 127 | struct nouveau_encoder **pnv_encoder) |
128 | { | 128 | { |
129 | struct drm_device *dev = connector->dev; | 129 | struct drm_device *dev = connector->dev; |
130 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | ||
130 | struct nouveau_drm *drm = nouveau_drm(dev); | 131 | struct nouveau_drm *drm = nouveau_drm(dev); |
132 | struct nouveau_gpio *gpio = nouveau_gpio(drm->device); | ||
131 | struct nouveau_i2c *i2c = nouveau_i2c(drm->device); | 133 | struct nouveau_i2c *i2c = nouveau_i2c(drm->device); |
132 | int i; | 134 | struct nouveau_i2c_port *port = NULL; |
135 | int i, panel = -ENODEV; | ||
136 | |||
137 | /* eDP panels need powering on by us (if the VBIOS doesn't default it | ||
138 | * to on) before doing any AUX channel transactions. LVDS panel power | ||
139 | * is handled by the SOR itself, and not required for LVDS DDC. | ||
140 | */ | ||
141 | if (nv_connector->type == DCB_CONNECTOR_eDP) { | ||
142 | panel = gpio->get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff); | ||
143 | if (panel == 0) { | ||
144 | gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1); | ||
145 | msleep(300); | ||
146 | } | ||
147 | } | ||
133 | 148 | ||
134 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { | 149 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { |
135 | struct nouveau_i2c_port *port = NULL; | ||
136 | struct nouveau_encoder *nv_encoder; | 150 | struct nouveau_encoder *nv_encoder; |
137 | struct drm_mode_object *obj; | 151 | struct drm_mode_object *obj; |
138 | int id; | 152 | int id; |
@@ -150,11 +164,19 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, | |||
150 | port = i2c->find(i2c, nv_encoder->dcb->i2c_index); | 164 | port = i2c->find(i2c, nv_encoder->dcb->i2c_index); |
151 | if (port && nv_probe_i2c(port, 0x50)) { | 165 | if (port && nv_probe_i2c(port, 0x50)) { |
152 | *pnv_encoder = nv_encoder; | 166 | *pnv_encoder = nv_encoder; |
153 | return port; | 167 | break; |
154 | } | 168 | } |
169 | |||
170 | port = NULL; | ||
155 | } | 171 | } |
156 | 172 | ||
157 | return NULL; | 173 | /* eDP panel not detected, restore panel power GPIO to previous |
174 | * state to avoid confusing the SOR for other output types. | ||
175 | */ | ||
176 | if (!port && panel == 0) | ||
177 | gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, panel); | ||
178 | |||
179 | return port; | ||
158 | } | 180 | } |
159 | 181 | ||
160 | static struct nouveau_encoder * | 182 | static struct nouveau_encoder * |
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index e4188f24fc75..d42c9e860c16 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c | |||
@@ -78,11 +78,6 @@ nouveau_framebuffer_init(struct drm_device *dev, | |||
78 | struct drm_framebuffer *fb = &nv_fb->base; | 78 | struct drm_framebuffer *fb = &nv_fb->base; |
79 | int ret; | 79 | int ret; |
80 | 80 | ||
81 | ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs); | ||
82 | if (ret) { | ||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | drm_helper_mode_fill_fb_struct(fb, mode_cmd); | 81 | drm_helper_mode_fill_fb_struct(fb, mode_cmd); |
87 | nv_fb->nvbo = nvbo; | 82 | nv_fb->nvbo = nvbo; |
88 | 83 | ||
@@ -125,6 +120,11 @@ nouveau_framebuffer_init(struct drm_device *dev, | |||
125 | } | 120 | } |
126 | } | 121 | } |
127 | 122 | ||
123 | ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs); | ||
124 | if (ret) { | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | return 0; | 128 | return 0; |
129 | } | 129 | } |
130 | 130 | ||
@@ -225,15 +225,6 @@ nouveau_display_init(struct drm_device *dev) | |||
225 | if (ret) | 225 | if (ret) |
226 | return ret; | 226 | return ret; |
227 | 227 | ||
228 | /* power on internal panel if it's not already. the init tables of | ||
229 | * some vbios default this to off for some reason, causing the | ||
230 | * panel to not work after resume | ||
231 | */ | ||
232 | if (gpio && gpio->get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff) == 0) { | ||
233 | gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1); | ||
234 | msleep(300); | ||
235 | } | ||
236 | |||
237 | /* enable polling for external displays */ | 228 | /* enable polling for external displays */ |
238 | drm_kms_helper_poll_enable(dev); | 229 | drm_kms_helper_poll_enable(dev); |
239 | 230 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 180a45e3b525..8b090f1eb51d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
@@ -84,11 +84,16 @@ nouveau_cli_create(struct pci_dev *pdev, const char *name, | |||
84 | struct nouveau_cli *cli; | 84 | struct nouveau_cli *cli; |
85 | int ret; | 85 | int ret; |
86 | 86 | ||
87 | *pcli = NULL; | ||
87 | ret = nouveau_client_create_(name, nouveau_name(pdev), nouveau_config, | 88 | ret = nouveau_client_create_(name, nouveau_name(pdev), nouveau_config, |
88 | nouveau_debug, size, pcli); | 89 | nouveau_debug, size, pcli); |
89 | cli = *pcli; | 90 | cli = *pcli; |
90 | if (ret) | 91 | if (ret) { |
92 | if (cli) | ||
93 | nouveau_client_destroy(&cli->base); | ||
94 | *pcli = NULL; | ||
91 | return ret; | 95 | return ret; |
96 | } | ||
92 | 97 | ||
93 | mutex_init(&cli->mutex); | 98 | mutex_init(&cli->mutex); |
94 | return 0; | 99 | return 0; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 67a1a069de28..d4ecb4deb484 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c | |||
@@ -433,6 +433,7 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon) | |||
433 | nouveau_fb->nvbo = NULL; | 433 | nouveau_fb->nvbo = NULL; |
434 | } | 434 | } |
435 | drm_fb_helper_fini(&fbcon->helper); | 435 | drm_fb_helper_fini(&fbcon->helper); |
436 | drm_framebuffer_unregister_private(&nouveau_fb->base); | ||
436 | drm_framebuffer_cleanup(&nouveau_fb->base); | 437 | drm_framebuffer_cleanup(&nouveau_fb->base); |
437 | return 0; | 438 | return 0; |
438 | } | 439 | } |
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h index bedafd1c9539..cdb83acdffe2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.h +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h | |||
@@ -60,6 +60,7 @@ u32 nv10_fence_read(struct nouveau_channel *); | |||
60 | void nv10_fence_context_del(struct nouveau_channel *); | 60 | void nv10_fence_context_del(struct nouveau_channel *); |
61 | void nv10_fence_destroy(struct nouveau_drm *); | 61 | void nv10_fence_destroy(struct nouveau_drm *); |
62 | int nv10_fence_create(struct nouveau_drm *); | 62 | int nv10_fence_create(struct nouveau_drm *); |
63 | void nv17_fence_resume(struct nouveau_drm *drm); | ||
63 | 64 | ||
64 | int nv50_fence_create(struct nouveau_drm *); | 65 | int nv50_fence_create(struct nouveau_drm *); |
65 | int nv84_fence_create(struct nouveau_drm *); | 66 | int nv84_fence_create(struct nouveau_drm *); |
diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index 184cdf806761..39ffc07f906b 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c | |||
@@ -505,7 +505,7 @@ static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode) | |||
505 | 505 | ||
506 | static inline bool is_powersaving_dpms(int mode) | 506 | static inline bool is_powersaving_dpms(int mode) |
507 | { | 507 | { |
508 | return (mode != DRM_MODE_DPMS_ON); | 508 | return mode != DRM_MODE_DPMS_ON && mode != NV_DPMS_CLEARED; |
509 | } | 509 | } |
510 | 510 | ||
511 | static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode) | 511 | static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode) |
diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c index 2cd6fb8c548e..4c6e9f83fe82 100644 --- a/drivers/gpu/drm/nouveau/nv04_display.c +++ b/drivers/gpu/drm/nouveau/nv04_display.c | |||
@@ -140,7 +140,7 @@ nv04_display_destroy(struct drm_device *dev) | |||
140 | .crtc = crtc, | 140 | .crtc = crtc, |
141 | }; | 141 | }; |
142 | 142 | ||
143 | crtc->funcs->set_config(&modeset); | 143 | drm_mode_set_config_internal(&modeset); |
144 | } | 144 | } |
145 | 145 | ||
146 | /* Restore state */ | 146 | /* Restore state */ |
diff --git a/drivers/gpu/drm/nouveau/nv10_fence.c b/drivers/gpu/drm/nouveau/nv10_fence.c index 7ae7f97a6d4d..03017f24d593 100644 --- a/drivers/gpu/drm/nouveau/nv10_fence.c +++ b/drivers/gpu/drm/nouveau/nv10_fence.c | |||
@@ -162,6 +162,13 @@ nv10_fence_destroy(struct nouveau_drm *drm) | |||
162 | kfree(priv); | 162 | kfree(priv); |
163 | } | 163 | } |
164 | 164 | ||
165 | void nv17_fence_resume(struct nouveau_drm *drm) | ||
166 | { | ||
167 | struct nv10_fence_priv *priv = drm->fence; | ||
168 | |||
169 | nouveau_bo_wr32(priv->bo, 0, priv->sequence); | ||
170 | } | ||
171 | |||
165 | int | 172 | int |
166 | nv10_fence_create(struct nouveau_drm *drm) | 173 | nv10_fence_create(struct nouveau_drm *drm) |
167 | { | 174 | { |
@@ -197,6 +204,7 @@ nv10_fence_create(struct nouveau_drm *drm) | |||
197 | if (ret == 0) { | 204 | if (ret == 0) { |
198 | nouveau_bo_wr32(priv->bo, 0x000, 0x00000000); | 205 | nouveau_bo_wr32(priv->bo, 0x000, 0x00000000); |
199 | priv->base.sync = nv17_fence_sync; | 206 | priv->base.sync = nv17_fence_sync; |
207 | priv->base.resume = nv17_fence_resume; | ||
200 | } | 208 | } |
201 | } | 209 | } |
202 | 210 | ||
diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c index 2ca276ada507..977e42be2050 100644 --- a/drivers/gpu/drm/nouveau/nv17_tv.c +++ b/drivers/gpu/drm/nouveau/nv17_tv.c | |||
@@ -768,7 +768,7 @@ static int nv17_tv_set_property(struct drm_encoder *encoder, | |||
768 | .crtc = crtc, | 768 | .crtc = crtc, |
769 | }; | 769 | }; |
770 | 770 | ||
771 | crtc->funcs->set_config(&modeset); | 771 | drm_mode_set_config_internal(&modeset); |
772 | } | 772 | } |
773 | } | 773 | } |
774 | 774 | ||
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 35874085a61e..d4cbea19b890 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c | |||
@@ -128,6 +128,11 @@ struct nv50_dmac { | |||
128 | struct nv50_chan base; | 128 | struct nv50_chan base; |
129 | dma_addr_t handle; | 129 | dma_addr_t handle; |
130 | u32 *ptr; | 130 | u32 *ptr; |
131 | |||
132 | /* Protects against concurrent pushbuf access to this channel, lock is | ||
133 | * grabbed by evo_wait (if the pushbuf reservation is successful) and | ||
134 | * dropped again by evo_kick. */ | ||
135 | struct mutex lock; | ||
131 | }; | 136 | }; |
132 | 137 | ||
133 | static void | 138 | static void |
@@ -271,6 +276,8 @@ nv50_dmac_create(struct nouveau_object *core, u32 bclass, u8 head, | |||
271 | u32 pushbuf = *(u32 *)data; | 276 | u32 pushbuf = *(u32 *)data; |
272 | int ret; | 277 | int ret; |
273 | 278 | ||
279 | mutex_init(&dmac->lock); | ||
280 | |||
274 | dmac->ptr = pci_alloc_consistent(nv_device(core)->pdev, PAGE_SIZE, | 281 | dmac->ptr = pci_alloc_consistent(nv_device(core)->pdev, PAGE_SIZE, |
275 | &dmac->handle); | 282 | &dmac->handle); |
276 | if (!dmac->ptr) | 283 | if (!dmac->ptr) |
@@ -395,11 +402,13 @@ evo_wait(void *evoc, int nr) | |||
395 | struct nv50_dmac *dmac = evoc; | 402 | struct nv50_dmac *dmac = evoc; |
396 | u32 put = nv_ro32(dmac->base.user, 0x0000) / 4; | 403 | u32 put = nv_ro32(dmac->base.user, 0x0000) / 4; |
397 | 404 | ||
405 | mutex_lock(&dmac->lock); | ||
398 | if (put + nr >= (PAGE_SIZE / 4) - 8) { | 406 | if (put + nr >= (PAGE_SIZE / 4) - 8) { |
399 | dmac->ptr[put] = 0x20000000; | 407 | dmac->ptr[put] = 0x20000000; |
400 | 408 | ||
401 | nv_wo32(dmac->base.user, 0x0000, 0x00000000); | 409 | nv_wo32(dmac->base.user, 0x0000, 0x00000000); |
402 | if (!nv_wait(dmac->base.user, 0x0004, ~0, 0x00000000)) { | 410 | if (!nv_wait(dmac->base.user, 0x0004, ~0, 0x00000000)) { |
411 | mutex_unlock(&dmac->lock); | ||
403 | NV_ERROR(dmac->base.user, "channel stalled\n"); | 412 | NV_ERROR(dmac->base.user, "channel stalled\n"); |
404 | return NULL; | 413 | return NULL; |
405 | } | 414 | } |
@@ -415,6 +424,7 @@ evo_kick(u32 *push, void *evoc) | |||
415 | { | 424 | { |
416 | struct nv50_dmac *dmac = evoc; | 425 | struct nv50_dmac *dmac = evoc; |
417 | nv_wo32(dmac->base.user, 0x0000, (push - dmac->ptr) << 2); | 426 | nv_wo32(dmac->base.user, 0x0000, (push - dmac->ptr) << 2); |
427 | mutex_unlock(&dmac->lock); | ||
418 | } | 428 | } |
419 | 429 | ||
420 | #define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m)) | 430 | #define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m)) |
diff --git a/drivers/gpu/drm/nouveau/nv50_fence.c b/drivers/gpu/drm/nouveau/nv50_fence.c index c20f2727ea0b..d889f3ac0d41 100644 --- a/drivers/gpu/drm/nouveau/nv50_fence.c +++ b/drivers/gpu/drm/nouveau/nv50_fence.c | |||
@@ -122,6 +122,7 @@ nv50_fence_create(struct nouveau_drm *drm) | |||
122 | if (ret == 0) { | 122 | if (ret == 0) { |
123 | nouveau_bo_wr32(priv->bo, 0x000, 0x00000000); | 123 | nouveau_bo_wr32(priv->bo, 0x000, 0x00000000); |
124 | priv->base.sync = nv17_fence_sync; | 124 | priv->base.sync = nv17_fence_sync; |
125 | priv->base.resume = nv17_fence_resume; | ||
125 | } | 126 | } |
126 | 127 | ||
127 | if (ret) | 128 | if (ret) |
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 03191a56eb44..69ec24ab8d63 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c | |||
@@ -2476,8 +2476,10 @@ static void r600_cs_parser_fini(struct radeon_cs_parser *parser, int error) | |||
2476 | kfree(parser->relocs); | 2476 | kfree(parser->relocs); |
2477 | for (i = 0; i < parser->nchunks; i++) { | 2477 | for (i = 0; i < parser->nchunks; i++) { |
2478 | kfree(parser->chunks[i].kdata); | 2478 | kfree(parser->chunks[i].kdata); |
2479 | kfree(parser->chunks[i].kpage[0]); | 2479 | if (parser->rdev && (parser->rdev->flags & RADEON_IS_AGP)) { |
2480 | kfree(parser->chunks[i].kpage[1]); | 2480 | kfree(parser->chunks[i].kpage[0]); |
2481 | kfree(parser->chunks[i].kpage[1]); | ||
2482 | } | ||
2481 | } | 2483 | } |
2482 | kfree(parser->chunks); | 2484 | kfree(parser->chunks); |
2483 | kfree(parser->chunks_array); | 2485 | kfree(parser->chunks_array); |
@@ -2561,16 +2563,16 @@ int r600_dma_cs_next_reloc(struct radeon_cs_parser *p, | |||
2561 | struct radeon_cs_chunk *relocs_chunk; | 2563 | struct radeon_cs_chunk *relocs_chunk; |
2562 | unsigned idx; | 2564 | unsigned idx; |
2563 | 2565 | ||
2566 | *cs_reloc = NULL; | ||
2564 | if (p->chunk_relocs_idx == -1) { | 2567 | if (p->chunk_relocs_idx == -1) { |
2565 | DRM_ERROR("No relocation chunk !\n"); | 2568 | DRM_ERROR("No relocation chunk !\n"); |
2566 | return -EINVAL; | 2569 | return -EINVAL; |
2567 | } | 2570 | } |
2568 | *cs_reloc = NULL; | ||
2569 | relocs_chunk = &p->chunks[p->chunk_relocs_idx]; | 2571 | relocs_chunk = &p->chunks[p->chunk_relocs_idx]; |
2570 | idx = p->dma_reloc_idx; | 2572 | idx = p->dma_reloc_idx; |
2571 | if (idx >= relocs_chunk->length_dw) { | 2573 | if (idx >= p->nrelocs) { |
2572 | DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", | 2574 | DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", |
2573 | idx, relocs_chunk->length_dw); | 2575 | idx, p->nrelocs); |
2574 | return -EINVAL; | 2576 | return -EINVAL; |
2575 | } | 2577 | } |
2576 | *cs_reloc = p->relocs_ptr[idx]; | 2578 | *cs_reloc = p->relocs_ptr[idx]; |
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 396baba0141a..469661fd1903 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c | |||
@@ -279,13 +279,13 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) | |||
279 | p->chunks[p->chunk_ib_idx].length_dw); | 279 | p->chunks[p->chunk_ib_idx].length_dw); |
280 | return -EINVAL; | 280 | return -EINVAL; |
281 | } | 281 | } |
282 | if ((p->rdev->flags & RADEON_IS_AGP)) { | 282 | if (p->rdev && (p->rdev->flags & RADEON_IS_AGP)) { |
283 | p->chunks[p->chunk_ib_idx].kpage[0] = kmalloc(PAGE_SIZE, GFP_KERNEL); | 283 | p->chunks[p->chunk_ib_idx].kpage[0] = kmalloc(PAGE_SIZE, GFP_KERNEL); |
284 | p->chunks[p->chunk_ib_idx].kpage[1] = kmalloc(PAGE_SIZE, GFP_KERNEL); | 284 | p->chunks[p->chunk_ib_idx].kpage[1] = kmalloc(PAGE_SIZE, GFP_KERNEL); |
285 | if (p->chunks[p->chunk_ib_idx].kpage[0] == NULL || | 285 | if (p->chunks[p->chunk_ib_idx].kpage[0] == NULL || |
286 | p->chunks[p->chunk_ib_idx].kpage[1] == NULL) { | 286 | p->chunks[p->chunk_ib_idx].kpage[1] == NULL) { |
287 | kfree(p->chunks[i].kpage[0]); | 287 | kfree(p->chunks[p->chunk_ib_idx].kpage[0]); |
288 | kfree(p->chunks[i].kpage[1]); | 288 | kfree(p->chunks[p->chunk_ib_idx].kpage[1]); |
289 | return -ENOMEM; | 289 | return -ENOMEM; |
290 | } | 290 | } |
291 | } | 291 | } |
@@ -583,7 +583,8 @@ static int radeon_cs_update_pages(struct radeon_cs_parser *p, int pg_idx) | |||
583 | struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx]; | 583 | struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx]; |
584 | int i; | 584 | int i; |
585 | int size = PAGE_SIZE; | 585 | int size = PAGE_SIZE; |
586 | bool copy1 = (p->rdev->flags & RADEON_IS_AGP) ? false : true; | 586 | bool copy1 = (p->rdev && (p->rdev->flags & RADEON_IS_AGP)) ? |
587 | false : true; | ||
587 | 588 | ||
588 | for (i = ibc->last_copied_page + 1; i < pg_idx; i++) { | 589 | for (i = ibc->last_copied_page + 1; i < pg_idx; i++) { |
589 | if (DRM_COPY_FROM_USER(p->ib.ptr + (i * (PAGE_SIZE/4)), | 590 | if (DRM_COPY_FROM_USER(p->ib.ptr + (i * (PAGE_SIZE/4)), |
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index ad6df625e8b8..c1680e6d76ad 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c | |||
@@ -245,8 +245,14 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, | |||
245 | int i = 0; | 245 | int i = 0; |
246 | struct drm_crtc *crtc_p; | 246 | struct drm_crtc *crtc_p; |
247 | 247 | ||
248 | /* avivo cursor image can't end on 128 pixel boundary or | 248 | /* |
249 | * avivo cursor image can't end on 128 pixel boundary or | ||
249 | * go past the end of the frame if both crtcs are enabled | 250 | * go past the end of the frame if both crtcs are enabled |
251 | * | ||
252 | * NOTE: It is safe to access crtc->enabled of other crtcs | ||
253 | * without holding either the mode_config lock or the other | ||
254 | * crtc's lock as long as write access to this flag _always_ | ||
255 | * grabs all locks. | ||
250 | */ | 256 | */ |
251 | list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) { | 257 | list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) { |
252 | if (crtc_p->enabled) | 258 | if (crtc_p->enabled) |
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 1da2386d7cf7..12ec3effb409 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c | |||
@@ -1089,12 +1089,12 @@ radeon_framebuffer_init(struct drm_device *dev, | |||
1089 | { | 1089 | { |
1090 | int ret; | 1090 | int ret; |
1091 | rfb->obj = obj; | 1091 | rfb->obj = obj; |
1092 | drm_helper_mode_fill_fb_struct(&rfb->base, mode_cmd); | ||
1092 | ret = drm_framebuffer_init(dev, &rfb->base, &radeon_fb_funcs); | 1093 | ret = drm_framebuffer_init(dev, &rfb->base, &radeon_fb_funcs); |
1093 | if (ret) { | 1094 | if (ret) { |
1094 | rfb->obj = NULL; | 1095 | rfb->obj = NULL; |
1095 | return ret; | 1096 | return ret; |
1096 | } | 1097 | } |
1097 | drm_helper_mode_fill_fb_struct(&rfb->base, mode_cmd); | ||
1098 | return 0; | 1098 | return 0; |
1099 | } | 1099 | } |
1100 | 1100 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index cc8489d8c6d1..515e5ee1f9ee 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c | |||
@@ -293,6 +293,7 @@ out_unref: | |||
293 | } | 293 | } |
294 | if (fb && ret) { | 294 | if (fb && ret) { |
295 | drm_gem_object_unreference(gobj); | 295 | drm_gem_object_unreference(gobj); |
296 | drm_framebuffer_unregister_private(fb); | ||
296 | drm_framebuffer_cleanup(fb); | 297 | drm_framebuffer_cleanup(fb); |
297 | kfree(fb); | 298 | kfree(fb); |
298 | } | 299 | } |
@@ -339,6 +340,7 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb | |||
339 | rfb->obj = NULL; | 340 | rfb->obj = NULL; |
340 | } | 341 | } |
341 | drm_fb_helper_fini(&rfbdev->helper); | 342 | drm_fb_helper_fini(&rfbdev->helper); |
343 | drm_framebuffer_unregister_private(&rfb->base); | ||
342 | drm_framebuffer_cleanup(&rfb->base); | 344 | drm_framebuffer_cleanup(&rfb->base); |
343 | 345 | ||
344 | return 0; | 346 | return 0; |
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index f5ba2241dacc..62cd512f5c8d 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c | |||
@@ -640,6 +640,14 @@ static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_enc | |||
640 | enum drm_connector_status found = connector_status_disconnected; | 640 | enum drm_connector_status found = connector_status_disconnected; |
641 | bool color = true; | 641 | bool color = true; |
642 | 642 | ||
643 | /* just don't bother on RN50 those chip are often connected to remoting | ||
644 | * console hw and often we get failure to load detect those. So to make | ||
645 | * everyone happy report the encoder as always connected. | ||
646 | */ | ||
647 | if (ASIC_IS_RN50(rdev)) { | ||
648 | return connector_status_connected; | ||
649 | } | ||
650 | |||
643 | /* save the regs we need */ | 651 | /* save the regs we need */ |
644 | vclk_ecp_cntl = RREG32_PLL(RADEON_VCLK_ECP_CNTL); | 652 | vclk_ecp_cntl = RREG32_PLL(RADEON_VCLK_ECP_CNTL); |
645 | crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); | 653 | crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); |
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index d1d5306ebf24..f6e0b5395051 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c | |||
@@ -313,9 +313,9 @@ static int shmob_drm_pm_resume(struct device *dev) | |||
313 | { | 313 | { |
314 | struct shmob_drm_device *sdev = dev_get_drvdata(dev); | 314 | struct shmob_drm_device *sdev = dev_get_drvdata(dev); |
315 | 315 | ||
316 | mutex_lock(&sdev->ddev->mode_config.mutex); | 316 | drm_modeset_lock_all(sdev->ddev); |
317 | shmob_drm_crtc_resume(&sdev->crtc); | 317 | shmob_drm_crtc_resume(&sdev->crtc); |
318 | mutex_unlock(&sdev->ddev->mode_config.mutex); | 318 | drm_modeset_unlock_all(sdev->ddev); |
319 | 319 | ||
320 | drm_kms_helper_poll_enable(sdev->ddev); | 320 | drm_kms_helper_poll_enable(sdev->ddev); |
321 | return 0; | 321 | return 0; |
diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index 512f44add89f..fe5cdbcf2636 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c | |||
@@ -22,13 +22,17 @@ | |||
22 | static u8 *udl_get_edid(struct udl_device *udl) | 22 | static u8 *udl_get_edid(struct udl_device *udl) |
23 | { | 23 | { |
24 | u8 *block; | 24 | u8 *block; |
25 | char rbuf[3]; | 25 | char *rbuf; |
26 | int ret, i; | 26 | int ret, i; |
27 | 27 | ||
28 | block = kmalloc(EDID_LENGTH, GFP_KERNEL); | 28 | block = kmalloc(EDID_LENGTH, GFP_KERNEL); |
29 | if (block == NULL) | 29 | if (block == NULL) |
30 | return NULL; | 30 | return NULL; |
31 | 31 | ||
32 | rbuf = kmalloc(2, GFP_KERNEL); | ||
33 | if (rbuf == NULL) | ||
34 | goto error; | ||
35 | |||
32 | for (i = 0; i < EDID_LENGTH; i++) { | 36 | for (i = 0; i < EDID_LENGTH; i++) { |
33 | ret = usb_control_msg(udl->ddev->usbdev, | 37 | ret = usb_control_msg(udl->ddev->usbdev, |
34 | usb_rcvctrlpipe(udl->ddev->usbdev, 0), (0x02), | 38 | usb_rcvctrlpipe(udl->ddev->usbdev, 0), (0x02), |
@@ -36,16 +40,17 @@ static u8 *udl_get_edid(struct udl_device *udl) | |||
36 | HZ); | 40 | HZ); |
37 | if (ret < 1) { | 41 | if (ret < 1) { |
38 | DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret); | 42 | DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret); |
39 | i--; | ||
40 | goto error; | 43 | goto error; |
41 | } | 44 | } |
42 | block[i] = rbuf[1]; | 45 | block[i] = rbuf[1]; |
43 | } | 46 | } |
44 | 47 | ||
48 | kfree(rbuf); | ||
45 | return block; | 49 | return block; |
46 | 50 | ||
47 | error: | 51 | error: |
48 | kfree(block); | 52 | kfree(block); |
53 | kfree(rbuf); | ||
49 | return NULL; | 54 | return NULL; |
50 | } | 55 | } |
51 | 56 | ||
@@ -57,6 +62,14 @@ static int udl_get_modes(struct drm_connector *connector) | |||
57 | 62 | ||
58 | edid = (struct edid *)udl_get_edid(udl); | 63 | edid = (struct edid *)udl_get_edid(udl); |
59 | 64 | ||
65 | /* | ||
66 | * We only read the main block, but if the monitor reports extension | ||
67 | * blocks then the drm edid code expects them to be present, so patch | ||
68 | * the extension count to 0. | ||
69 | */ | ||
70 | edid->checksum += edid->extensions; | ||
71 | edid->extensions = 0; | ||
72 | |||
60 | drm_mode_connector_update_edid_property(connector, edid); | 73 | drm_mode_connector_update_edid_property(connector, edid); |
61 | ret = drm_add_edid_modes(connector, edid); | 74 | ret = drm_add_edid_modes(connector, edid); |
62 | kfree(edid); | 75 | kfree(edid); |
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index d4ab3beaada0..caa84f1de9c1 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c | |||
@@ -422,7 +422,6 @@ static void udl_user_framebuffer_destroy(struct drm_framebuffer *fb) | |||
422 | static const struct drm_framebuffer_funcs udlfb_funcs = { | 422 | static const struct drm_framebuffer_funcs udlfb_funcs = { |
423 | .destroy = udl_user_framebuffer_destroy, | 423 | .destroy = udl_user_framebuffer_destroy, |
424 | .dirty = udl_user_framebuffer_dirty, | 424 | .dirty = udl_user_framebuffer_dirty, |
425 | .create_handle = NULL, | ||
426 | }; | 425 | }; |
427 | 426 | ||
428 | 427 | ||
@@ -435,8 +434,8 @@ udl_framebuffer_init(struct drm_device *dev, | |||
435 | int ret; | 434 | int ret; |
436 | 435 | ||
437 | ufb->obj = obj; | 436 | ufb->obj = obj; |
438 | ret = drm_framebuffer_init(dev, &ufb->base, &udlfb_funcs); | ||
439 | drm_helper_mode_fill_fb_struct(&ufb->base, mode_cmd); | 437 | drm_helper_mode_fill_fb_struct(&ufb->base, mode_cmd); |
438 | ret = drm_framebuffer_init(dev, &ufb->base, &udlfb_funcs); | ||
440 | return ret; | 439 | return ret; |
441 | } | 440 | } |
442 | 441 | ||
@@ -556,6 +555,7 @@ static void udl_fbdev_destroy(struct drm_device *dev, | |||
556 | framebuffer_release(info); | 555 | framebuffer_release(info); |
557 | } | 556 | } |
558 | drm_fb_helper_fini(&ufbdev->helper); | 557 | drm_fb_helper_fini(&ufbdev->helper); |
558 | drm_framebuffer_unregister_private(&ufbdev->ufb.base); | ||
559 | drm_framebuffer_cleanup(&ufbdev->ufb.base); | 559 | drm_framebuffer_cleanup(&ufbdev->ufb.base); |
560 | drm_gem_object_unreference_unlocked(&ufbdev->ufb.obj->base); | 560 | drm_gem_object_unreference_unlocked(&ufbdev->ufb.obj->base); |
561 | } | 561 | } |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 161f8b2549aa..07dfd823cc30 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | |||
@@ -829,7 +829,7 @@ static void vmw_lastclose(struct drm_device *dev) | |||
829 | 829 | ||
830 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 830 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
831 | set.crtc = crtc; | 831 | set.crtc = crtc; |
832 | ret = crtc->funcs->set_config(&set); | 832 | ret = drm_mode_set_config_internal(&set); |
833 | WARN_ON(ret != 0); | 833 | WARN_ON(ret != 0); |
834 | } | 834 | } |
835 | 835 | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index d9fbbe191071..c509d40c4897 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | |||
@@ -131,7 +131,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, | |||
131 | struct vmw_master *vmaster = vmw_master(file_priv->master); | 131 | struct vmw_master *vmaster = vmw_master(file_priv->master); |
132 | struct drm_vmw_rect __user *clips_ptr; | 132 | struct drm_vmw_rect __user *clips_ptr; |
133 | struct drm_vmw_rect *clips = NULL; | 133 | struct drm_vmw_rect *clips = NULL; |
134 | struct drm_mode_object *obj; | 134 | struct drm_framebuffer *fb; |
135 | struct vmw_framebuffer *vfb; | 135 | struct vmw_framebuffer *vfb; |
136 | struct vmw_resource *res; | 136 | struct vmw_resource *res; |
137 | uint32_t num_clips; | 137 | uint32_t num_clips; |
@@ -163,19 +163,15 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, | |||
163 | goto out_no_copy; | 163 | goto out_no_copy; |
164 | } | 164 | } |
165 | 165 | ||
166 | ret = mutex_lock_interruptible(&dev->mode_config.mutex); | 166 | drm_modeset_lock_all(dev); |
167 | if (unlikely(ret != 0)) { | ||
168 | ret = -ERESTARTSYS; | ||
169 | goto out_no_mode_mutex; | ||
170 | } | ||
171 | 167 | ||
172 | obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB); | 168 | fb = drm_framebuffer_lookup(dev, arg->fb_id); |
173 | if (!obj) { | 169 | if (!fb) { |
174 | DRM_ERROR("Invalid framebuffer id.\n"); | 170 | DRM_ERROR("Invalid framebuffer id.\n"); |
175 | ret = -EINVAL; | 171 | ret = -EINVAL; |
176 | goto out_no_fb; | 172 | goto out_no_fb; |
177 | } | 173 | } |
178 | vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj)); | 174 | vfb = vmw_framebuffer_to_vfb(fb); |
179 | 175 | ||
180 | ret = ttm_read_lock(&vmaster->lock, true); | 176 | ret = ttm_read_lock(&vmaster->lock, true); |
181 | if (unlikely(ret != 0)) | 177 | if (unlikely(ret != 0)) |
@@ -199,9 +195,9 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, | |||
199 | out_no_surface: | 195 | out_no_surface: |
200 | ttm_read_unlock(&vmaster->lock); | 196 | ttm_read_unlock(&vmaster->lock); |
201 | out_no_ttm_lock: | 197 | out_no_ttm_lock: |
198 | drm_framebuffer_unreference(fb); | ||
202 | out_no_fb: | 199 | out_no_fb: |
203 | mutex_unlock(&dev->mode_config.mutex); | 200 | drm_modeset_unlock_all(dev); |
204 | out_no_mode_mutex: | ||
205 | out_no_copy: | 201 | out_no_copy: |
206 | kfree(clips); | 202 | kfree(clips); |
207 | out_clips: | 203 | out_clips: |
@@ -220,7 +216,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, | |||
220 | struct vmw_master *vmaster = vmw_master(file_priv->master); | 216 | struct vmw_master *vmaster = vmw_master(file_priv->master); |
221 | struct drm_vmw_rect __user *clips_ptr; | 217 | struct drm_vmw_rect __user *clips_ptr; |
222 | struct drm_vmw_rect *clips = NULL; | 218 | struct drm_vmw_rect *clips = NULL; |
223 | struct drm_mode_object *obj; | 219 | struct drm_framebuffer *fb; |
224 | struct vmw_framebuffer *vfb; | 220 | struct vmw_framebuffer *vfb; |
225 | uint32_t num_clips; | 221 | uint32_t num_clips; |
226 | int ret; | 222 | int ret; |
@@ -251,24 +247,20 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, | |||
251 | goto out_no_copy; | 247 | goto out_no_copy; |
252 | } | 248 | } |
253 | 249 | ||
254 | ret = mutex_lock_interruptible(&dev->mode_config.mutex); | 250 | drm_modeset_lock_all(dev); |
255 | if (unlikely(ret != 0)) { | ||
256 | ret = -ERESTARTSYS; | ||
257 | goto out_no_mode_mutex; | ||
258 | } | ||
259 | 251 | ||
260 | obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB); | 252 | fb = drm_framebuffer_lookup(dev, arg->fb_id); |
261 | if (!obj) { | 253 | if (!fb) { |
262 | DRM_ERROR("Invalid framebuffer id.\n"); | 254 | DRM_ERROR("Invalid framebuffer id.\n"); |
263 | ret = -EINVAL; | 255 | ret = -EINVAL; |
264 | goto out_no_fb; | 256 | goto out_no_fb; |
265 | } | 257 | } |
266 | 258 | ||
267 | vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj)); | 259 | vfb = vmw_framebuffer_to_vfb(fb); |
268 | if (!vfb->dmabuf) { | 260 | if (!vfb->dmabuf) { |
269 | DRM_ERROR("Framebuffer not dmabuf backed.\n"); | 261 | DRM_ERROR("Framebuffer not dmabuf backed.\n"); |
270 | ret = -EINVAL; | 262 | ret = -EINVAL; |
271 | goto out_no_fb; | 263 | goto out_no_ttm_lock; |
272 | } | 264 | } |
273 | 265 | ||
274 | ret = ttm_read_lock(&vmaster->lock, true); | 266 | ret = ttm_read_lock(&vmaster->lock, true); |
@@ -281,9 +273,9 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, | |||
281 | 273 | ||
282 | ttm_read_unlock(&vmaster->lock); | 274 | ttm_read_unlock(&vmaster->lock); |
283 | out_no_ttm_lock: | 275 | out_no_ttm_lock: |
276 | drm_framebuffer_unreference(fb); | ||
284 | out_no_fb: | 277 | out_no_fb: |
285 | mutex_unlock(&dev->mode_config.mutex); | 278 | drm_modeset_unlock_all(dev); |
286 | out_no_mode_mutex: | ||
287 | out_no_copy: | 279 | out_no_copy: |
288 | kfree(clips); | 280 | kfree(clips); |
289 | out_clips: | 281 | out_clips: |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 54743943d8b3..3e3c7ab33ca2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | |||
@@ -180,16 +180,29 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, | |||
180 | struct vmw_dma_buffer *dmabuf = NULL; | 180 | struct vmw_dma_buffer *dmabuf = NULL; |
181 | int ret; | 181 | int ret; |
182 | 182 | ||
183 | /* | ||
184 | * FIXME: Unclear whether there's any global state touched by the | ||
185 | * cursor_set function, especially vmw_cursor_update_position looks | ||
186 | * suspicious. For now take the easy route and reacquire all locks. We | ||
187 | * can do this since the caller in the drm core doesn't check anything | ||
188 | * which is protected by any looks. | ||
189 | */ | ||
190 | mutex_unlock(&crtc->mutex); | ||
191 | drm_modeset_lock_all(dev_priv->dev); | ||
192 | |||
183 | /* A lot of the code assumes this */ | 193 | /* A lot of the code assumes this */ |
184 | if (handle && (width != 64 || height != 64)) | 194 | if (handle && (width != 64 || height != 64)) { |
185 | return -EINVAL; | 195 | ret = -EINVAL; |
196 | goto out; | ||
197 | } | ||
186 | 198 | ||
187 | if (handle) { | 199 | if (handle) { |
188 | ret = vmw_user_lookup_handle(dev_priv, tfile, | 200 | ret = vmw_user_lookup_handle(dev_priv, tfile, |
189 | handle, &surface, &dmabuf); | 201 | handle, &surface, &dmabuf); |
190 | if (ret) { | 202 | if (ret) { |
191 | DRM_ERROR("failed to find surface or dmabuf: %i\n", ret); | 203 | DRM_ERROR("failed to find surface or dmabuf: %i\n", ret); |
192 | return -EINVAL; | 204 | ret = -EINVAL; |
205 | goto out; | ||
193 | } | 206 | } |
194 | } | 207 | } |
195 | 208 | ||
@@ -197,7 +210,8 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, | |||
197 | if (surface && !surface->snooper.image) { | 210 | if (surface && !surface->snooper.image) { |
198 | DRM_ERROR("surface not suitable for cursor\n"); | 211 | DRM_ERROR("surface not suitable for cursor\n"); |
199 | vmw_surface_unreference(&surface); | 212 | vmw_surface_unreference(&surface); |
200 | return -EINVAL; | 213 | ret = -EINVAL; |
214 | goto out; | ||
201 | } | 215 | } |
202 | 216 | ||
203 | /* takedown old cursor */ | 217 | /* takedown old cursor */ |
@@ -225,14 +239,20 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, | |||
225 | du->hotspot_x, du->hotspot_y); | 239 | du->hotspot_x, du->hotspot_y); |
226 | } else { | 240 | } else { |
227 | vmw_cursor_update_position(dev_priv, false, 0, 0); | 241 | vmw_cursor_update_position(dev_priv, false, 0, 0); |
228 | return 0; | 242 | ret = 0; |
243 | goto out; | ||
229 | } | 244 | } |
230 | 245 | ||
231 | vmw_cursor_update_position(dev_priv, true, | 246 | vmw_cursor_update_position(dev_priv, true, |
232 | du->cursor_x + du->hotspot_x, | 247 | du->cursor_x + du->hotspot_x, |
233 | du->cursor_y + du->hotspot_y); | 248 | du->cursor_y + du->hotspot_y); |
234 | 249 | ||
235 | return 0; | 250 | ret = 0; |
251 | out: | ||
252 | drm_modeset_unlock_all(dev_priv->dev); | ||
253 | mutex_lock(&crtc->mutex); | ||
254 | |||
255 | return ret; | ||
236 | } | 256 | } |
237 | 257 | ||
238 | int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) | 258 | int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) |
@@ -244,10 +264,23 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) | |||
244 | du->cursor_x = x + crtc->x; | 264 | du->cursor_x = x + crtc->x; |
245 | du->cursor_y = y + crtc->y; | 265 | du->cursor_y = y + crtc->y; |
246 | 266 | ||
267 | /* | ||
268 | * FIXME: Unclear whether there's any global state touched by the | ||
269 | * cursor_set function, especially vmw_cursor_update_position looks | ||
270 | * suspicious. For now take the easy route and reacquire all locks. We | ||
271 | * can do this since the caller in the drm core doesn't check anything | ||
272 | * which is protected by any looks. | ||
273 | */ | ||
274 | mutex_unlock(&crtc->mutex); | ||
275 | drm_modeset_lock_all(dev_priv->dev); | ||
276 | |||
247 | vmw_cursor_update_position(dev_priv, shown, | 277 | vmw_cursor_update_position(dev_priv, shown, |
248 | du->cursor_x + du->hotspot_x, | 278 | du->cursor_x + du->hotspot_x, |
249 | du->cursor_y + du->hotspot_y); | 279 | du->cursor_y + du->hotspot_y); |
250 | 280 | ||
281 | drm_modeset_unlock_all(dev_priv->dev); | ||
282 | mutex_lock(&crtc->mutex); | ||
283 | |||
251 | return 0; | 284 | return 0; |
252 | } | 285 | } |
253 | 286 | ||
@@ -373,16 +406,6 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv) | |||
373 | * Generic framebuffer code | 406 | * Generic framebuffer code |
374 | */ | 407 | */ |
375 | 408 | ||
376 | int vmw_framebuffer_create_handle(struct drm_framebuffer *fb, | ||
377 | struct drm_file *file_priv, | ||
378 | unsigned int *handle) | ||
379 | { | ||
380 | if (handle) | ||
381 | *handle = 0; | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | /* | 409 | /* |
387 | * Surface framebuffer code | 410 | * Surface framebuffer code |
388 | */ | 411 | */ |
@@ -610,7 +633,6 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, | |||
610 | static struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = { | 633 | static struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = { |
611 | .destroy = vmw_framebuffer_surface_destroy, | 634 | .destroy = vmw_framebuffer_surface_destroy, |
612 | .dirty = vmw_framebuffer_surface_dirty, | 635 | .dirty = vmw_framebuffer_surface_dirty, |
613 | .create_handle = vmw_framebuffer_create_handle, | ||
614 | }; | 636 | }; |
615 | 637 | ||
616 | static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, | 638 | static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, |
@@ -681,14 +703,10 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, | |||
681 | goto out_err1; | 703 | goto out_err1; |
682 | } | 704 | } |
683 | 705 | ||
684 | ret = drm_framebuffer_init(dev, &vfbs->base.base, | ||
685 | &vmw_framebuffer_surface_funcs); | ||
686 | if (ret) | ||
687 | goto out_err2; | ||
688 | |||
689 | if (!vmw_surface_reference(surface)) { | 706 | if (!vmw_surface_reference(surface)) { |
690 | DRM_ERROR("failed to reference surface %p\n", surface); | 707 | DRM_ERROR("failed to reference surface %p\n", surface); |
691 | goto out_err3; | 708 | ret = -EINVAL; |
709 | goto out_err2; | ||
692 | } | 710 | } |
693 | 711 | ||
694 | /* XXX get the first 3 from the surface info */ | 712 | /* XXX get the first 3 from the surface info */ |
@@ -707,10 +725,15 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, | |||
707 | 725 | ||
708 | *out = &vfbs->base; | 726 | *out = &vfbs->base; |
709 | 727 | ||
728 | ret = drm_framebuffer_init(dev, &vfbs->base.base, | ||
729 | &vmw_framebuffer_surface_funcs); | ||
730 | if (ret) | ||
731 | goto out_err3; | ||
732 | |||
710 | return 0; | 733 | return 0; |
711 | 734 | ||
712 | out_err3: | 735 | out_err3: |
713 | drm_framebuffer_cleanup(&vfbs->base.base); | 736 | vmw_surface_unreference(&surface); |
714 | out_err2: | 737 | out_err2: |
715 | kfree(vfbs); | 738 | kfree(vfbs); |
716 | out_err1: | 739 | out_err1: |
@@ -960,7 +983,6 @@ int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, | |||
960 | static struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = { | 983 | static struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = { |
961 | .destroy = vmw_framebuffer_dmabuf_destroy, | 984 | .destroy = vmw_framebuffer_dmabuf_destroy, |
962 | .dirty = vmw_framebuffer_dmabuf_dirty, | 985 | .dirty = vmw_framebuffer_dmabuf_dirty, |
963 | .create_handle = vmw_framebuffer_create_handle, | ||
964 | }; | 986 | }; |
965 | 987 | ||
966 | /** | 988 | /** |
@@ -1053,14 +1075,10 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, | |||
1053 | goto out_err1; | 1075 | goto out_err1; |
1054 | } | 1076 | } |
1055 | 1077 | ||
1056 | ret = drm_framebuffer_init(dev, &vfbd->base.base, | ||
1057 | &vmw_framebuffer_dmabuf_funcs); | ||
1058 | if (ret) | ||
1059 | goto out_err2; | ||
1060 | |||
1061 | if (!vmw_dmabuf_reference(dmabuf)) { | 1078 | if (!vmw_dmabuf_reference(dmabuf)) { |
1062 | DRM_ERROR("failed to reference dmabuf %p\n", dmabuf); | 1079 | DRM_ERROR("failed to reference dmabuf %p\n", dmabuf); |
1063 | goto out_err3; | 1080 | ret = -EINVAL; |
1081 | goto out_err2; | ||
1064 | } | 1082 | } |
1065 | 1083 | ||
1066 | vfbd->base.base.bits_per_pixel = mode_cmd->bpp; | 1084 | vfbd->base.base.bits_per_pixel = mode_cmd->bpp; |
@@ -1077,10 +1095,15 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, | |||
1077 | vfbd->base.user_handle = mode_cmd->handle; | 1095 | vfbd->base.user_handle = mode_cmd->handle; |
1078 | *out = &vfbd->base; | 1096 | *out = &vfbd->base; |
1079 | 1097 | ||
1098 | ret = drm_framebuffer_init(dev, &vfbd->base.base, | ||
1099 | &vmw_framebuffer_dmabuf_funcs); | ||
1100 | if (ret) | ||
1101 | goto out_err3; | ||
1102 | |||
1080 | return 0; | 1103 | return 0; |
1081 | 1104 | ||
1082 | out_err3: | 1105 | out_err3: |
1083 | drm_framebuffer_cleanup(&vfbd->base.base); | 1106 | vmw_dmabuf_unreference(&dmabuf); |
1084 | out_err2: | 1107 | out_err2: |
1085 | kfree(vfbd); | 1108 | kfree(vfbd); |
1086 | out_err1: | 1109 | out_err1: |
diff --git a/drivers/hwmon/vexpress.c b/drivers/hwmon/vexpress.c index 86d7f6d858b1..d867e6bb2be1 100644 --- a/drivers/hwmon/vexpress.c +++ b/drivers/hwmon/vexpress.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/hwmon.h> | 19 | #include <linux/hwmon.h> |
20 | #include <linux/hwmon-sysfs.h> | 20 | #include <linux/hwmon-sysfs.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/of.h> | ||
22 | #include <linux/of_device.h> | 23 | #include <linux/of_device.h> |
23 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
24 | #include <linux/vexpress.h> | 25 | #include <linux/vexpress.h> |
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index fe4bcd7c5b12..05e996fafc9d 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig | |||
@@ -8,6 +8,7 @@ config HID_SENSOR_ACCEL_3D | |||
8 | select IIO_BUFFER | 8 | select IIO_BUFFER |
9 | select IIO_TRIGGERED_BUFFER | 9 | select IIO_TRIGGERED_BUFFER |
10 | select HID_SENSOR_IIO_COMMON | 10 | select HID_SENSOR_IIO_COMMON |
11 | select HID_SENSOR_IIO_TRIGGER | ||
11 | tristate "HID Accelerometers 3D" | 12 | tristate "HID Accelerometers 3D" |
12 | help | 13 | help |
13 | Say yes here to build support for the HID SENSOR | 14 | Say yes here to build support for the HID SENSOR |
diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index 4a5f639bc684..bbad9b94cd75 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c | |||
@@ -411,7 +411,11 @@ static int ad7266_probe(struct spi_device *spi) | |||
411 | if (ret) | 411 | if (ret) |
412 | goto error_put_reg; | 412 | goto error_put_reg; |
413 | 413 | ||
414 | st->vref_uv = regulator_get_voltage(st->reg); | 414 | ret = regulator_get_voltage(st->reg); |
415 | if (ret < 0) | ||
416 | goto error_disable_reg; | ||
417 | |||
418 | st->vref_uv = ret; | ||
415 | } else { | 419 | } else { |
416 | /* Use internal reference */ | 420 | /* Use internal reference */ |
417 | st->vref_uv = 2500000; | 421 | st->vref_uv = 2500000; |
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 04b013561f0f..a526c0e3aaa8 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c | |||
@@ -80,7 +80,7 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p) | |||
80 | *timestamp = pf->timestamp; | 80 | *timestamp = pf->timestamp; |
81 | } | 81 | } |
82 | 82 | ||
83 | iio_push_to_buffers(indio_dev, (u8 *)st->buffer); | 83 | iio_push_to_buffers(idev, (u8 *)st->buffer); |
84 | 84 | ||
85 | iio_trigger_notify_done(idev->trig); | 85 | iio_trigger_notify_done(idev->trig); |
86 | 86 | ||
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index b5669be6f396..03b25b3dc71e 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c | |||
@@ -1605,19 +1605,20 @@ static int max1363_probe(struct i2c_client *client, | |||
1605 | 1605 | ||
1606 | return 0; | 1606 | return 0; |
1607 | error_free_irq: | 1607 | error_free_irq: |
1608 | free_irq(st->client->irq, indio_dev); | 1608 | if (client->irq) |
1609 | free_irq(st->client->irq, indio_dev); | ||
1609 | error_uninit_buffer: | 1610 | error_uninit_buffer: |
1610 | iio_buffer_unregister(indio_dev); | 1611 | iio_buffer_unregister(indio_dev); |
1611 | error_cleanup_buffer: | 1612 | error_cleanup_buffer: |
1612 | max1363_buffer_cleanup(indio_dev); | 1613 | max1363_buffer_cleanup(indio_dev); |
1613 | error_free_available_scan_masks: | 1614 | error_free_available_scan_masks: |
1614 | kfree(indio_dev->available_scan_masks); | 1615 | kfree(indio_dev->available_scan_masks); |
1615 | error_unregister_map: | ||
1616 | iio_map_array_unregister(indio_dev, client->dev.platform_data); | ||
1617 | error_disable_reg: | 1616 | error_disable_reg: |
1618 | regulator_disable(st->reg); | 1617 | regulator_disable(st->reg); |
1619 | error_put_reg: | 1618 | error_put_reg: |
1620 | regulator_put(st->reg); | 1619 | regulator_put(st->reg); |
1620 | error_unregister_map: | ||
1621 | iio_map_array_unregister(indio_dev, client->dev.platform_data); | ||
1621 | error_free_device: | 1622 | error_free_device: |
1622 | iio_device_free(indio_dev); | 1623 | iio_device_free(indio_dev); |
1623 | error_out: | 1624 | error_out: |
@@ -1635,10 +1636,8 @@ static int max1363_remove(struct i2c_client *client) | |||
1635 | iio_buffer_unregister(indio_dev); | 1636 | iio_buffer_unregister(indio_dev); |
1636 | max1363_buffer_cleanup(indio_dev); | 1637 | max1363_buffer_cleanup(indio_dev); |
1637 | kfree(indio_dev->available_scan_masks); | 1638 | kfree(indio_dev->available_scan_masks); |
1638 | if (!IS_ERR(st->reg)) { | 1639 | regulator_disable(st->reg); |
1639 | regulator_disable(st->reg); | 1640 | regulator_put(st->reg); |
1640 | regulator_put(st->reg); | ||
1641 | } | ||
1642 | iio_map_array_unregister(indio_dev, client->dev.platform_data); | 1641 | iio_map_array_unregister(indio_dev, client->dev.platform_data); |
1643 | iio_device_free(indio_dev); | 1642 | iio_device_free(indio_dev); |
1644 | 1643 | ||
diff --git a/drivers/iio/common/hid-sensors/Kconfig b/drivers/iio/common/hid-sensors/Kconfig index ae10778da7aa..1178121b55b0 100644 --- a/drivers/iio/common/hid-sensors/Kconfig +++ b/drivers/iio/common/hid-sensors/Kconfig | |||
@@ -6,7 +6,7 @@ menu "Hid Sensor IIO Common" | |||
6 | config HID_SENSOR_IIO_COMMON | 6 | config HID_SENSOR_IIO_COMMON |
7 | tristate "Common modules for all HID Sensor IIO drivers" | 7 | tristate "Common modules for all HID Sensor IIO drivers" |
8 | depends on HID_SENSOR_HUB | 8 | depends on HID_SENSOR_HUB |
9 | select IIO_TRIGGER if IIO_BUFFER | 9 | select HID_SENSOR_IIO_TRIGGER if IIO_BUFFER |
10 | help | 10 | help |
11 | Say yes here to build support for HID sensor to use | 11 | Say yes here to build support for HID sensor to use |
12 | HID sensor common processing for attributes and IIO triggers. | 12 | HID sensor common processing for attributes and IIO triggers. |
@@ -14,6 +14,17 @@ config HID_SENSOR_IIO_COMMON | |||
14 | HID sensor drivers, this module contains processing for those | 14 | HID sensor drivers, this module contains processing for those |
15 | attributes. | 15 | attributes. |
16 | 16 | ||
17 | config HID_SENSOR_IIO_TRIGGER | ||
18 | tristate "Common module (trigger) for all HID Sensor IIO drivers" | ||
19 | depends on HID_SENSOR_HUB && HID_SENSOR_IIO_COMMON | ||
20 | select IIO_TRIGGER | ||
21 | help | ||
22 | Say yes here to build trigger support for HID sensors. | ||
23 | Triggers will be send if all requested attributes were read. | ||
24 | |||
25 | If this driver is compiled as a module, it will be named | ||
26 | hid-sensor-trigger. | ||
27 | |||
17 | config HID_SENSOR_ENUM_BASE_QUIRKS | 28 | config HID_SENSOR_ENUM_BASE_QUIRKS |
18 | bool "ENUM base quirks for HID Sensor IIO drivers" | 29 | bool "ENUM base quirks for HID Sensor IIO drivers" |
19 | depends on HID_SENSOR_IIO_COMMON | 30 | depends on HID_SENSOR_IIO_COMMON |
diff --git a/drivers/iio/common/hid-sensors/Makefile b/drivers/iio/common/hid-sensors/Makefile index 1f463e00c242..22e7c5a82325 100644 --- a/drivers/iio/common/hid-sensors/Makefile +++ b/drivers/iio/common/hid-sensors/Makefile | |||
@@ -3,4 +3,5 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_HID_SENSOR_IIO_COMMON) += hid-sensor-iio-common.o | 5 | obj-$(CONFIG_HID_SENSOR_IIO_COMMON) += hid-sensor-iio-common.o |
6 | hid-sensor-iio-common-y := hid-sensor-attributes.o hid-sensor-trigger.o | 6 | obj-$(CONFIG_HID_SENSOR_IIO_TRIGGER) += hid-sensor-trigger.o |
7 | hid-sensor-iio-common-y := hid-sensor-attributes.o | ||
diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 6c7898c765d9..483fc379a2da 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c | |||
@@ -406,7 +406,11 @@ static int ad5380_probe(struct device *dev, struct regmap *regmap, | |||
406 | goto error_free_reg; | 406 | goto error_free_reg; |
407 | } | 407 | } |
408 | 408 | ||
409 | st->vref = regulator_get_voltage(st->vref_reg); | 409 | ret = regulator_get_voltage(st->vref_reg); |
410 | if (ret < 0) | ||
411 | goto error_disable_reg; | ||
412 | |||
413 | st->vref = ret; | ||
410 | } else { | 414 | } else { |
411 | st->vref = st->chip_info->int_vref; | 415 | st->vref = st->chip_info->int_vref; |
412 | ctrl |= AD5380_CTRL_INT_VREF_EN; | 416 | ctrl |= AD5380_CTRL_INT_VREF_EN; |
diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c index 29f653dab2f7..f5583aedfb59 100644 --- a/drivers/iio/dac/ad5446.c +++ b/drivers/iio/dac/ad5446.c | |||
@@ -226,7 +226,11 @@ static int ad5446_probe(struct device *dev, const char *name, | |||
226 | if (ret) | 226 | if (ret) |
227 | goto error_put_reg; | 227 | goto error_put_reg; |
228 | 228 | ||
229 | voltage_uv = regulator_get_voltage(reg); | 229 | ret = regulator_get_voltage(reg); |
230 | if (ret < 0) | ||
231 | goto error_disable_reg; | ||
232 | |||
233 | voltage_uv = ret; | ||
230 | } | 234 | } |
231 | 235 | ||
232 | indio_dev = iio_device_alloc(sizeof(*st)); | 236 | indio_dev = iio_device_alloc(sizeof(*st)); |
diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index b2a31a0468ed..0661829f2773 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c | |||
@@ -296,7 +296,11 @@ static int ad5504_probe(struct spi_device *spi) | |||
296 | if (ret) | 296 | if (ret) |
297 | goto error_put_reg; | 297 | goto error_put_reg; |
298 | 298 | ||
299 | voltage_uv = regulator_get_voltage(reg); | 299 | ret = regulator_get_voltage(reg); |
300 | if (ret < 0) | ||
301 | goto error_disable_reg; | ||
302 | |||
303 | voltage_uv = ret; | ||
300 | } | 304 | } |
301 | 305 | ||
302 | spi_set_drvdata(spi, indio_dev); | 306 | spi_set_drvdata(spi, indio_dev); |
diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c index e9947969f9fe..f6e116627b71 100644 --- a/drivers/iio/dac/ad5624r_spi.c +++ b/drivers/iio/dac/ad5624r_spi.c | |||
@@ -238,7 +238,11 @@ static int ad5624r_probe(struct spi_device *spi) | |||
238 | if (ret) | 238 | if (ret) |
239 | goto error_put_reg; | 239 | goto error_put_reg; |
240 | 240 | ||
241 | voltage_uv = regulator_get_voltage(st->reg); | 241 | ret = regulator_get_voltage(st->reg); |
242 | if (ret < 0) | ||
243 | goto error_disable_reg; | ||
244 | |||
245 | voltage_uv = ret; | ||
242 | } | 246 | } |
243 | 247 | ||
244 | spi_set_drvdata(spi, indio_dev); | 248 | spi_set_drvdata(spi, indio_dev); |
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 36e51382ae52..ca9609d7a15c 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c | |||
@@ -332,7 +332,11 @@ static int ad5686_probe(struct spi_device *spi) | |||
332 | if (ret) | 332 | if (ret) |
333 | goto error_put_reg; | 333 | goto error_put_reg; |
334 | 334 | ||
335 | voltage_uv = regulator_get_voltage(st->reg); | 335 | ret = regulator_get_voltage(st->reg); |
336 | if (ret < 0) | ||
337 | goto error_disable_reg; | ||
338 | |||
339 | voltage_uv = ret; | ||
336 | } | 340 | } |
337 | 341 | ||
338 | st->chip_info = | 342 | st->chip_info = |
diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index c84180f23139..6407b5407ddd 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c | |||
@@ -365,7 +365,11 @@ static int ad5791_probe(struct spi_device *spi) | |||
365 | if (ret) | 365 | if (ret) |
366 | goto error_put_reg_pos; | 366 | goto error_put_reg_pos; |
367 | 367 | ||
368 | pos_voltage_uv = regulator_get_voltage(st->reg_vdd); | 368 | ret = regulator_get_voltage(st->reg_vdd); |
369 | if (ret < 0) | ||
370 | goto error_disable_reg_pos; | ||
371 | |||
372 | pos_voltage_uv = ret; | ||
369 | } | 373 | } |
370 | 374 | ||
371 | st->reg_vss = regulator_get(&spi->dev, "vss"); | 375 | st->reg_vss = regulator_get(&spi->dev, "vss"); |
@@ -374,7 +378,11 @@ static int ad5791_probe(struct spi_device *spi) | |||
374 | if (ret) | 378 | if (ret) |
375 | goto error_put_reg_neg; | 379 | goto error_put_reg_neg; |
376 | 380 | ||
377 | neg_voltage_uv = regulator_get_voltage(st->reg_vss); | 381 | ret = regulator_get_voltage(st->reg_vss); |
382 | if (ret < 0) | ||
383 | goto error_disable_reg_neg; | ||
384 | |||
385 | neg_voltage_uv = ret; | ||
378 | } | 386 | } |
379 | 387 | ||
380 | st->pwr_down = true; | 388 | st->pwr_down = true; |
@@ -428,6 +436,7 @@ error_put_reg_neg: | |||
428 | if (!IS_ERR(st->reg_vss)) | 436 | if (!IS_ERR(st->reg_vss)) |
429 | regulator_put(st->reg_vss); | 437 | regulator_put(st->reg_vss); |
430 | 438 | ||
439 | error_disable_reg_pos: | ||
431 | if (!IS_ERR(st->reg_vdd)) | 440 | if (!IS_ERR(st->reg_vdd)) |
432 | regulator_disable(st->reg_vdd); | 441 | regulator_disable(st->reg_vdd); |
433 | error_put_reg_pos: | 442 | error_put_reg_pos: |
diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index e5033b4cfba0..a884252ac66b 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c | |||
@@ -173,7 +173,7 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq) | |||
173 | } while ((st->r1_mod > ADF4350_MAX_MODULUS) && r_cnt); | 173 | } while ((st->r1_mod > ADF4350_MAX_MODULUS) && r_cnt); |
174 | } while (r_cnt == 0); | 174 | } while (r_cnt == 0); |
175 | 175 | ||
176 | tmp = freq * (u64)st->r1_mod + (st->fpfd > 1); | 176 | tmp = freq * (u64)st->r1_mod + (st->fpfd >> 1); |
177 | do_div(tmp, st->fpfd); /* Div round closest (n + d/2)/d */ | 177 | do_div(tmp, st->fpfd); /* Div round closest (n + d/2)/d */ |
178 | st->r0_fract = do_div(tmp, st->r1_mod); | 178 | st->r0_fract = do_div(tmp, st->r1_mod); |
179 | st->r0_int = tmp; | 179 | st->r0_int = tmp; |
diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig index 48ed1483ff27..96b68f63a902 100644 --- a/drivers/iio/gyro/Kconfig +++ b/drivers/iio/gyro/Kconfig | |||
@@ -17,6 +17,7 @@ config HID_SENSOR_GYRO_3D | |||
17 | select IIO_BUFFER | 17 | select IIO_BUFFER |
18 | select IIO_TRIGGERED_BUFFER | 18 | select IIO_TRIGGERED_BUFFER |
19 | select HID_SENSOR_IIO_COMMON | 19 | select HID_SENSOR_IIO_COMMON |
20 | select HID_SENSOR_IIO_TRIGGER | ||
20 | tristate "HID Gyroscope 3D" | 21 | tristate "HID Gyroscope 3D" |
21 | help | 22 | help |
22 | Say yes here to build support for the HID SENSOR | 23 | Say yes here to build support for the HID SENSOR |
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 1763c9bcb98a..dbf80abc834f 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig | |||
@@ -47,6 +47,7 @@ config HID_SENSOR_ALS | |||
47 | select IIO_BUFFER | 47 | select IIO_BUFFER |
48 | select IIO_TRIGGERED_BUFFER | 48 | select IIO_TRIGGERED_BUFFER |
49 | select HID_SENSOR_IIO_COMMON | 49 | select HID_SENSOR_IIO_COMMON |
50 | select HID_SENSOR_IIO_TRIGGER | ||
50 | tristate "HID ALS" | 51 | tristate "HID ALS" |
51 | help | 52 | help |
52 | Say yes here to build support for the HID SENSOR | 53 | Say yes here to build support for the HID SENSOR |
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index c1f0cdd57037..ff11d68225cf 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig | |||
@@ -8,6 +8,7 @@ config HID_SENSOR_MAGNETOMETER_3D | |||
8 | select IIO_BUFFER | 8 | select IIO_BUFFER |
9 | select IIO_TRIGGERED_BUFFER | 9 | select IIO_TRIGGERED_BUFFER |
10 | select HID_SENSOR_IIO_COMMON | 10 | select HID_SENSOR_IIO_COMMON |
11 | select HID_SENSOR_IIO_TRIGGER | ||
11 | tristate "HID Magenetometer 3D" | 12 | tristate "HID Magenetometer 3D" |
12 | help | 13 | help |
13 | Say yes here to build support for the HID SENSOR | 14 | Say yes here to build support for the HID SENSOR |
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 1c0abd4dfc43..47ad4e270877 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -292,6 +292,7 @@ config TWL4030_CORE | |||
292 | bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support" | 292 | bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support" |
293 | depends on I2C=y && GENERIC_HARDIRQS | 293 | depends on I2C=y && GENERIC_HARDIRQS |
294 | select IRQ_DOMAIN | 294 | select IRQ_DOMAIN |
295 | select REGMAP_I2C | ||
295 | help | 296 | help |
296 | Say yes here if you have TWL4030 / TWL6030 family chip on your board. | 297 | Say yes here if you have TWL4030 / TWL6030 family chip on your board. |
297 | This core driver provides register access and IRQ handling | 298 | This core driver provides register access and IRQ handling |
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index 158da5a81a66..3c09cbb70b1d 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | 20 | ||
21 | #include <linux/of.h> | 21 | #include <linux/of.h> |
22 | #include <linux/pinctrl/consumer.h> | ||
22 | 23 | ||
23 | /* Serialize access to ssc_list and user count */ | 24 | /* Serialize access to ssc_list and user count */ |
24 | static DEFINE_SPINLOCK(user_lock); | 25 | static DEFINE_SPINLOCK(user_lock); |
@@ -131,6 +132,13 @@ static int ssc_probe(struct platform_device *pdev) | |||
131 | struct resource *regs; | 132 | struct resource *regs; |
132 | struct ssc_device *ssc; | 133 | struct ssc_device *ssc; |
133 | const struct atmel_ssc_platform_data *plat_dat; | 134 | const struct atmel_ssc_platform_data *plat_dat; |
135 | struct pinctrl *pinctrl; | ||
136 | |||
137 | pinctrl = devm_pinctrl_get_select_default(&pdev->dev); | ||
138 | if (IS_ERR(pinctrl)) { | ||
139 | dev_err(&pdev->dev, "Failed to request pinctrl\n"); | ||
140 | return PTR_ERR(pinctrl); | ||
141 | } | ||
134 | 142 | ||
135 | ssc = devm_kzalloc(&pdev->dev, sizeof(struct ssc_device), GFP_KERNEL); | 143 | ssc = devm_kzalloc(&pdev->dev, sizeof(struct ssc_device), GFP_KERNEL); |
136 | if (!ssc) { | 144 | if (!ssc) { |
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 18794aea6062..e40ffd9502d1 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c | |||
@@ -187,13 +187,13 @@ int mei_amthif_read(struct mei_device *dev, struct file *file, | |||
187 | wait_ret = wait_event_interruptible(dev->iamthif_cl.wait, | 187 | wait_ret = wait_event_interruptible(dev->iamthif_cl.wait, |
188 | (cb = mei_amthif_find_read_list_entry(dev, file))); | 188 | (cb = mei_amthif_find_read_list_entry(dev, file))); |
189 | 189 | ||
190 | /* Locking again the Mutex */ | ||
191 | mutex_lock(&dev->device_lock); | ||
192 | |||
190 | if (wait_ret) | 193 | if (wait_ret) |
191 | return -ERESTARTSYS; | 194 | return -ERESTARTSYS; |
192 | 195 | ||
193 | dev_dbg(&dev->pdev->dev, "woke up from sleep\n"); | 196 | dev_dbg(&dev->pdev->dev, "woke up from sleep\n"); |
194 | |||
195 | /* Locking again the Mutex */ | ||
196 | mutex_lock(&dev->device_lock); | ||
197 | } | 197 | } |
198 | 198 | ||
199 | 199 | ||
diff --git a/drivers/net/ethernet/adi/Kconfig b/drivers/net/ethernet/adi/Kconfig index e49c0eff040b..a9481606bbcd 100644 --- a/drivers/net/ethernet/adi/Kconfig +++ b/drivers/net/ethernet/adi/Kconfig | |||
@@ -61,6 +61,7 @@ config BFIN_RX_DESC_NUM | |||
61 | 61 | ||
62 | config BFIN_MAC_USE_HWSTAMP | 62 | config BFIN_MAC_USE_HWSTAMP |
63 | bool "Use IEEE 1588 hwstamp" | 63 | bool "Use IEEE 1588 hwstamp" |
64 | depends on BFIN_MAC && BF518 | ||
64 | select PTP_1588_CLOCK | 65 | select PTP_1588_CLOCK |
65 | default y | 66 | default y |
66 | ---help--- | 67 | ---help--- |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 01588b66a38c..f771ddfba646 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | |||
@@ -80,12 +80,37 @@ static inline void bnx2x_move_fp(struct bnx2x *bp, int from, int to) | |||
80 | new_txdata_index = new_max_eth_txqs + FCOE_TXQ_IDX_OFFSET; | 80 | new_txdata_index = new_max_eth_txqs + FCOE_TXQ_IDX_OFFSET; |
81 | } | 81 | } |
82 | 82 | ||
83 | memcpy(&bp->bnx2x_txq[old_txdata_index], | 83 | memcpy(&bp->bnx2x_txq[new_txdata_index], |
84 | &bp->bnx2x_txq[new_txdata_index], | 84 | &bp->bnx2x_txq[old_txdata_index], |
85 | sizeof(struct bnx2x_fp_txdata)); | 85 | sizeof(struct bnx2x_fp_txdata)); |
86 | to_fp->txdata_ptr[0] = &bp->bnx2x_txq[new_txdata_index]; | 86 | to_fp->txdata_ptr[0] = &bp->bnx2x_txq[new_txdata_index]; |
87 | } | 87 | } |
88 | 88 | ||
89 | /** | ||
90 | * bnx2x_shrink_eth_fp - guarantees fastpath structures stay intact | ||
91 | * | ||
92 | * @bp: driver handle | ||
93 | * @delta: number of eth queues which were not allocated | ||
94 | */ | ||
95 | static void bnx2x_shrink_eth_fp(struct bnx2x *bp, int delta) | ||
96 | { | ||
97 | int i, cos, old_eth_num = BNX2X_NUM_ETH_QUEUES(bp); | ||
98 | |||
99 | /* Queue pointer cannot be re-set on an fp-basis, as moving pointer | ||
100 | * backward along the array could cause memory to be overriden | ||
101 | */ | ||
102 | for (cos = 1; cos < bp->max_cos; cos++) { | ||
103 | for (i = 0; i < old_eth_num - delta; i++) { | ||
104 | struct bnx2x_fastpath *fp = &bp->fp[i]; | ||
105 | int new_idx = cos * (old_eth_num - delta) + i; | ||
106 | |||
107 | memcpy(&bp->bnx2x_txq[new_idx], fp->txdata_ptr[cos], | ||
108 | sizeof(struct bnx2x_fp_txdata)); | ||
109 | fp->txdata_ptr[cos] = &bp->bnx2x_txq[new_idx]; | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | |||
89 | int load_count[2][3] = { {0} }; /* per-path: 0-common, 1-port0, 2-port1 */ | 114 | int load_count[2][3] = { {0} }; /* per-path: 0-common, 1-port0, 2-port1 */ |
90 | 115 | ||
91 | /* free skb in the packet ring at pos idx | 116 | /* free skb in the packet ring at pos idx |
@@ -3863,6 +3888,7 @@ int bnx2x_alloc_fp_mem(struct bnx2x *bp) | |||
3863 | int delta = BNX2X_NUM_ETH_QUEUES(bp) - i; | 3888 | int delta = BNX2X_NUM_ETH_QUEUES(bp) - i; |
3864 | 3889 | ||
3865 | WARN_ON(delta < 0); | 3890 | WARN_ON(delta < 0); |
3891 | bnx2x_shrink_eth_fp(bp, delta); | ||
3866 | if (CNIC_SUPPORT(bp)) | 3892 | if (CNIC_SUPPORT(bp)) |
3867 | /* move non eth FPs next to last eth FP | 3893 | /* move non eth FPs next to last eth FP |
3868 | * must be done in that order | 3894 | * must be done in that order |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 277f17e3c8f8..a427b49a886c 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | |||
@@ -2777,10 +2777,10 @@ static int bnx2x_set_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info) | |||
2777 | } else if ((info->flow_type == UDP_V6_FLOW) && | 2777 | } else if ((info->flow_type == UDP_V6_FLOW) && |
2778 | (bp->rss_conf_obj.udp_rss_v6 != udp_rss_requested)) { | 2778 | (bp->rss_conf_obj.udp_rss_v6 != udp_rss_requested)) { |
2779 | bp->rss_conf_obj.udp_rss_v6 = udp_rss_requested; | 2779 | bp->rss_conf_obj.udp_rss_v6 = udp_rss_requested; |
2780 | return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, 0); | ||
2781 | DP(BNX2X_MSG_ETHTOOL, | 2780 | DP(BNX2X_MSG_ETHTOOL, |
2782 | "rss re-configured, UDP 4-tupple %s\n", | 2781 | "rss re-configured, UDP 4-tupple %s\n", |
2783 | udp_rss_requested ? "enabled" : "disabled"); | 2782 | udp_rss_requested ? "enabled" : "disabled"); |
2783 | return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, 0); | ||
2784 | } else { | 2784 | } else { |
2785 | return 0; | 2785 | return 0; |
2786 | } | 2786 | } |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 940ef859dc60..5523da3afcdc 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | |||
@@ -127,6 +127,17 @@ MODULE_PARM_DESC(debug, " Default debug msglevel"); | |||
127 | 127 | ||
128 | struct workqueue_struct *bnx2x_wq; | 128 | struct workqueue_struct *bnx2x_wq; |
129 | 129 | ||
130 | struct bnx2x_mac_vals { | ||
131 | u32 xmac_addr; | ||
132 | u32 xmac_val; | ||
133 | u32 emac_addr; | ||
134 | u32 emac_val; | ||
135 | u32 umac_addr; | ||
136 | u32 umac_val; | ||
137 | u32 bmac_addr; | ||
138 | u32 bmac_val[2]; | ||
139 | }; | ||
140 | |||
130 | enum bnx2x_board_type { | 141 | enum bnx2x_board_type { |
131 | BCM57710 = 0, | 142 | BCM57710 = 0, |
132 | BCM57711, | 143 | BCM57711, |
@@ -9420,12 +9431,19 @@ static inline void bnx2x_undi_int_disable(struct bnx2x *bp) | |||
9420 | bnx2x_undi_int_disable_e1h(bp); | 9431 | bnx2x_undi_int_disable_e1h(bp); |
9421 | } | 9432 | } |
9422 | 9433 | ||
9423 | static void bnx2x_prev_unload_close_mac(struct bnx2x *bp) | 9434 | static void bnx2x_prev_unload_close_mac(struct bnx2x *bp, |
9435 | struct bnx2x_mac_vals *vals) | ||
9424 | { | 9436 | { |
9425 | u32 val, base_addr, offset, mask, reset_reg; | 9437 | u32 val, base_addr, offset, mask, reset_reg; |
9426 | bool mac_stopped = false; | 9438 | bool mac_stopped = false; |
9427 | u8 port = BP_PORT(bp); | 9439 | u8 port = BP_PORT(bp); |
9428 | 9440 | ||
9441 | /* reset addresses as they also mark which values were changed */ | ||
9442 | vals->bmac_addr = 0; | ||
9443 | vals->umac_addr = 0; | ||
9444 | vals->xmac_addr = 0; | ||
9445 | vals->emac_addr = 0; | ||
9446 | |||
9429 | reset_reg = REG_RD(bp, MISC_REG_RESET_REG_2); | 9447 | reset_reg = REG_RD(bp, MISC_REG_RESET_REG_2); |
9430 | 9448 | ||
9431 | if (!CHIP_IS_E3(bp)) { | 9449 | if (!CHIP_IS_E3(bp)) { |
@@ -9447,14 +9465,18 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp) | |||
9447 | */ | 9465 | */ |
9448 | wb_data[0] = REG_RD(bp, base_addr + offset); | 9466 | wb_data[0] = REG_RD(bp, base_addr + offset); |
9449 | wb_data[1] = REG_RD(bp, base_addr + offset + 0x4); | 9467 | wb_data[1] = REG_RD(bp, base_addr + offset + 0x4); |
9468 | vals->bmac_addr = base_addr + offset; | ||
9469 | vals->bmac_val[0] = wb_data[0]; | ||
9470 | vals->bmac_val[1] = wb_data[1]; | ||
9450 | wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE; | 9471 | wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE; |
9451 | REG_WR(bp, base_addr + offset, wb_data[0]); | 9472 | REG_WR(bp, vals->bmac_addr, wb_data[0]); |
9452 | REG_WR(bp, base_addr + offset + 0x4, wb_data[1]); | 9473 | REG_WR(bp, vals->bmac_addr + 0x4, wb_data[1]); |
9453 | 9474 | ||
9454 | } | 9475 | } |
9455 | BNX2X_DEV_INFO("Disable emac Rx\n"); | 9476 | BNX2X_DEV_INFO("Disable emac Rx\n"); |
9456 | REG_WR(bp, NIG_REG_NIG_EMAC0_EN + BP_PORT(bp)*4, 0); | 9477 | vals->emac_addr = NIG_REG_NIG_EMAC0_EN + BP_PORT(bp)*4; |
9457 | 9478 | vals->emac_val = REG_RD(bp, vals->emac_addr); | |
9479 | REG_WR(bp, vals->emac_addr, 0); | ||
9458 | mac_stopped = true; | 9480 | mac_stopped = true; |
9459 | } else { | 9481 | } else { |
9460 | if (reset_reg & MISC_REGISTERS_RESET_REG_2_XMAC) { | 9482 | if (reset_reg & MISC_REGISTERS_RESET_REG_2_XMAC) { |
@@ -9465,14 +9487,18 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp) | |||
9465 | val & ~(1 << 1)); | 9487 | val & ~(1 << 1)); |
9466 | REG_WR(bp, base_addr + XMAC_REG_PFC_CTRL_HI, | 9488 | REG_WR(bp, base_addr + XMAC_REG_PFC_CTRL_HI, |
9467 | val | (1 << 1)); | 9489 | val | (1 << 1)); |
9468 | REG_WR(bp, base_addr + XMAC_REG_CTRL, 0); | 9490 | vals->xmac_addr = base_addr + XMAC_REG_CTRL; |
9491 | vals->xmac_val = REG_RD(bp, vals->xmac_addr); | ||
9492 | REG_WR(bp, vals->xmac_addr, 0); | ||
9469 | mac_stopped = true; | 9493 | mac_stopped = true; |
9470 | } | 9494 | } |
9471 | mask = MISC_REGISTERS_RESET_REG_2_UMAC0 << port; | 9495 | mask = MISC_REGISTERS_RESET_REG_2_UMAC0 << port; |
9472 | if (mask & reset_reg) { | 9496 | if (mask & reset_reg) { |
9473 | BNX2X_DEV_INFO("Disable umac Rx\n"); | 9497 | BNX2X_DEV_INFO("Disable umac Rx\n"); |
9474 | base_addr = BP_PORT(bp) ? GRCBASE_UMAC1 : GRCBASE_UMAC0; | 9498 | base_addr = BP_PORT(bp) ? GRCBASE_UMAC1 : GRCBASE_UMAC0; |
9475 | REG_WR(bp, base_addr + UMAC_REG_COMMAND_CONFIG, 0); | 9499 | vals->umac_addr = base_addr + UMAC_REG_COMMAND_CONFIG; |
9500 | vals->umac_val = REG_RD(bp, vals->umac_addr); | ||
9501 | REG_WR(bp, vals->umac_addr, 0); | ||
9476 | mac_stopped = true; | 9502 | mac_stopped = true; |
9477 | } | 9503 | } |
9478 | } | 9504 | } |
@@ -9664,12 +9690,16 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp) | |||
9664 | { | 9690 | { |
9665 | u32 reset_reg, tmp_reg = 0, rc; | 9691 | u32 reset_reg, tmp_reg = 0, rc; |
9666 | bool prev_undi = false; | 9692 | bool prev_undi = false; |
9693 | struct bnx2x_mac_vals mac_vals; | ||
9694 | |||
9667 | /* It is possible a previous function received 'common' answer, | 9695 | /* It is possible a previous function received 'common' answer, |
9668 | * but hasn't loaded yet, therefore creating a scenario of | 9696 | * but hasn't loaded yet, therefore creating a scenario of |
9669 | * multiple functions receiving 'common' on the same path. | 9697 | * multiple functions receiving 'common' on the same path. |
9670 | */ | 9698 | */ |
9671 | BNX2X_DEV_INFO("Common unload Flow\n"); | 9699 | BNX2X_DEV_INFO("Common unload Flow\n"); |
9672 | 9700 | ||
9701 | memset(&mac_vals, 0, sizeof(mac_vals)); | ||
9702 | |||
9673 | if (bnx2x_prev_is_path_marked(bp)) | 9703 | if (bnx2x_prev_is_path_marked(bp)) |
9674 | return bnx2x_prev_mcp_done(bp); | 9704 | return bnx2x_prev_mcp_done(bp); |
9675 | 9705 | ||
@@ -9680,7 +9710,10 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp) | |||
9680 | u32 timer_count = 1000; | 9710 | u32 timer_count = 1000; |
9681 | 9711 | ||
9682 | /* Close the MAC Rx to prevent BRB from filling up */ | 9712 | /* Close the MAC Rx to prevent BRB from filling up */ |
9683 | bnx2x_prev_unload_close_mac(bp); | 9713 | bnx2x_prev_unload_close_mac(bp, &mac_vals); |
9714 | |||
9715 | /* close LLH filters towards the BRB */ | ||
9716 | bnx2x_set_rx_filter(&bp->link_params, 0); | ||
9684 | 9717 | ||
9685 | /* Check if the UNDI driver was previously loaded | 9718 | /* Check if the UNDI driver was previously loaded |
9686 | * UNDI driver initializes CID offset for normal bell to 0x7 | 9719 | * UNDI driver initializes CID offset for normal bell to 0x7 |
@@ -9727,6 +9760,17 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp) | |||
9727 | /* No packets are in the pipeline, path is ready for reset */ | 9760 | /* No packets are in the pipeline, path is ready for reset */ |
9728 | bnx2x_reset_common(bp); | 9761 | bnx2x_reset_common(bp); |
9729 | 9762 | ||
9763 | if (mac_vals.xmac_addr) | ||
9764 | REG_WR(bp, mac_vals.xmac_addr, mac_vals.xmac_val); | ||
9765 | if (mac_vals.umac_addr) | ||
9766 | REG_WR(bp, mac_vals.umac_addr, mac_vals.umac_val); | ||
9767 | if (mac_vals.emac_addr) | ||
9768 | REG_WR(bp, mac_vals.emac_addr, mac_vals.emac_val); | ||
9769 | if (mac_vals.bmac_addr) { | ||
9770 | REG_WR(bp, mac_vals.bmac_addr, mac_vals.bmac_val[0]); | ||
9771 | REG_WR(bp, mac_vals.bmac_addr + 4, mac_vals.bmac_val[1]); | ||
9772 | } | ||
9773 | |||
9730 | rc = bnx2x_prev_mark_path(bp, prev_undi); | 9774 | rc = bnx2x_prev_mark_path(bp, prev_undi); |
9731 | if (rc) { | 9775 | if (rc) { |
9732 | bnx2x_prev_mcp_done(bp); | 9776 | bnx2x_prev_mcp_done(bp); |
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 3bc1912afba9..4eba17b83ba8 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h | |||
@@ -190,6 +190,7 @@ struct be_eq_obj { | |||
190 | 190 | ||
191 | u8 idx; /* array index */ | 191 | u8 idx; /* array index */ |
192 | u16 tx_budget; | 192 | u16 tx_budget; |
193 | u16 spurious_intr; | ||
193 | struct napi_struct napi; | 194 | struct napi_struct napi; |
194 | struct be_adapter *adapter; | 195 | struct be_adapter *adapter; |
195 | } ____cacheline_aligned_in_smp; | 196 | } ____cacheline_aligned_in_smp; |
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 9dca22be8125..5c995700e534 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c | |||
@@ -2026,19 +2026,30 @@ static irqreturn_t be_intx(int irq, void *dev) | |||
2026 | struct be_adapter *adapter = eqo->adapter; | 2026 | struct be_adapter *adapter = eqo->adapter; |
2027 | int num_evts = 0; | 2027 | int num_evts = 0; |
2028 | 2028 | ||
2029 | /* On Lancer, clear-intr bit of the EQ DB does not work. | 2029 | /* IRQ is not expected when NAPI is scheduled as the EQ |
2030 | * INTx is de-asserted only on notifying num evts. | 2030 | * will not be armed. |
2031 | * But, this can happen on Lancer INTx where it takes | ||
2032 | * a while to de-assert INTx or in BE2 where occasionaly | ||
2033 | * an interrupt may be raised even when EQ is unarmed. | ||
2034 | * If NAPI is already scheduled, then counting & notifying | ||
2035 | * events will orphan them. | ||
2031 | */ | 2036 | */ |
2032 | if (lancer_chip(adapter)) | 2037 | if (napi_schedule_prep(&eqo->napi)) { |
2033 | num_evts = events_get(eqo); | 2038 | num_evts = events_get(eqo); |
2039 | __napi_schedule(&eqo->napi); | ||
2040 | if (num_evts) | ||
2041 | eqo->spurious_intr = 0; | ||
2042 | } | ||
2043 | be_eq_notify(adapter, eqo->q.id, false, true, num_evts); | ||
2034 | 2044 | ||
2035 | /* The EQ-notify may not de-assert INTx rightaway, causing | 2045 | /* Return IRQ_HANDLED only for the the first spurious intr |
2036 | * the ISR to be invoked again. So, return HANDLED even when | 2046 | * after a valid intr to stop the kernel from branding |
2037 | * num_evts is zero. | 2047 | * this irq as a bad one! |
2038 | */ | 2048 | */ |
2039 | be_eq_notify(adapter, eqo->q.id, false, true, num_evts); | 2049 | if (num_evts || eqo->spurious_intr++ == 0) |
2040 | napi_schedule(&eqo->napi); | 2050 | return IRQ_HANDLED; |
2041 | return IRQ_HANDLED; | 2051 | else |
2052 | return IRQ_NONE; | ||
2042 | } | 2053 | } |
2043 | 2054 | ||
2044 | static irqreturn_t be_msix(int irq, void *dev) | 2055 | static irqreturn_t be_msix(int irq, void *dev) |
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index f80cd975daed..3e73742024b0 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c | |||
@@ -4678,7 +4678,7 @@ static int qlge_probe(struct pci_dev *pdev, | |||
4678 | qdev = netdev_priv(ndev); | 4678 | qdev = netdev_priv(ndev); |
4679 | SET_NETDEV_DEV(ndev, &pdev->dev); | 4679 | SET_NETDEV_DEV(ndev, &pdev->dev); |
4680 | ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | | 4680 | ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | |
4681 | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN | | 4681 | NETIF_F_TSO | NETIF_F_TSO_ECN | |
4682 | NETIF_F_HW_VLAN_TX | NETIF_F_RXCSUM; | 4682 | NETIF_F_HW_VLAN_TX | NETIF_F_RXCSUM; |
4683 | ndev->features = ndev->hw_features | | 4683 | ndev->features = ndev->hw_features | |
4684 | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; | 4684 | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; |
diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig index 5778a4ae1164..122d60c0481b 100644 --- a/drivers/net/ethernet/xilinx/Kconfig +++ b/drivers/net/ethernet/xilinx/Kconfig | |||
@@ -27,7 +27,7 @@ config XILINX_EMACLITE | |||
27 | 27 | ||
28 | config XILINX_AXI_EMAC | 28 | config XILINX_AXI_EMAC |
29 | tristate "Xilinx 10/100/1000 AXI Ethernet support" | 29 | tristate "Xilinx 10/100/1000 AXI Ethernet support" |
30 | depends on (PPC32 || MICROBLAZE) | 30 | depends on MICROBLAZE |
31 | select PHYLIB | 31 | select PHYLIB |
32 | ---help--- | 32 | ---help--- |
33 | This driver supports the 10/100/1000 Ethernet from Xilinx for the | 33 | This driver supports the 10/100/1000 Ethernet from Xilinx for the |
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index d9f69b82cc4f..6f47100e58d7 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c | |||
@@ -1590,7 +1590,7 @@ static int axienet_of_probe(struct platform_device *op) | |||
1590 | lp->rx_irq = irq_of_parse_and_map(np, 1); | 1590 | lp->rx_irq = irq_of_parse_and_map(np, 1); |
1591 | lp->tx_irq = irq_of_parse_and_map(np, 0); | 1591 | lp->tx_irq = irq_of_parse_and_map(np, 0); |
1592 | of_node_put(np); | 1592 | of_node_put(np); |
1593 | if ((lp->rx_irq == NO_IRQ) || (lp->tx_irq == NO_IRQ)) { | 1593 | if ((lp->rx_irq <= 0) || (lp->tx_irq <= 0)) { |
1594 | dev_err(&op->dev, "could not determine irqs\n"); | 1594 | dev_err(&op->dev, "could not determine irqs\n"); |
1595 | ret = -ENOMEM; | 1595 | ret = -ENOMEM; |
1596 | goto err_iounmap_2; | 1596 | goto err_iounmap_2; |
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index fbd106edbe59..af372d0957fe 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -404,8 +404,8 @@ static void __tun_detach(struct tun_file *tfile, bool clean) | |||
404 | struct tun_struct *tun; | 404 | struct tun_struct *tun; |
405 | struct net_device *dev; | 405 | struct net_device *dev; |
406 | 406 | ||
407 | tun = rcu_dereference_protected(tfile->tun, | 407 | tun = rtnl_dereference(tfile->tun); |
408 | lockdep_rtnl_is_held()); | 408 | |
409 | if (tun) { | 409 | if (tun) { |
410 | u16 index = tfile->queue_index; | 410 | u16 index = tfile->queue_index; |
411 | BUG_ON(index >= tun->numqueues); | 411 | BUG_ON(index >= tun->numqueues); |
@@ -414,8 +414,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean) | |||
414 | rcu_assign_pointer(tun->tfiles[index], | 414 | rcu_assign_pointer(tun->tfiles[index], |
415 | tun->tfiles[tun->numqueues - 1]); | 415 | tun->tfiles[tun->numqueues - 1]); |
416 | rcu_assign_pointer(tfile->tun, NULL); | 416 | rcu_assign_pointer(tfile->tun, NULL); |
417 | ntfile = rcu_dereference_protected(tun->tfiles[index], | 417 | ntfile = rtnl_dereference(tun->tfiles[index]); |
418 | lockdep_rtnl_is_held()); | ||
419 | ntfile->queue_index = index; | 418 | ntfile->queue_index = index; |
420 | 419 | ||
421 | --tun->numqueues; | 420 | --tun->numqueues; |
@@ -429,8 +428,10 @@ static void __tun_detach(struct tun_file *tfile, bool clean) | |||
429 | /* Drop read queue */ | 428 | /* Drop read queue */ |
430 | skb_queue_purge(&tfile->sk.sk_receive_queue); | 429 | skb_queue_purge(&tfile->sk.sk_receive_queue); |
431 | tun_set_real_num_queues(tun); | 430 | tun_set_real_num_queues(tun); |
432 | } else if (tfile->detached && clean) | 431 | } else if (tfile->detached && clean) { |
433 | tun = tun_enable_queue(tfile); | 432 | tun = tun_enable_queue(tfile); |
433 | sock_put(&tfile->sk); | ||
434 | } | ||
434 | 435 | ||
435 | if (clean) { | 436 | if (clean) { |
436 | if (tun && tun->numqueues == 0 && tun->numdisabled == 0 && | 437 | if (tun && tun->numqueues == 0 && tun->numdisabled == 0 && |
@@ -458,8 +459,7 @@ static void tun_detach_all(struct net_device *dev) | |||
458 | int i, n = tun->numqueues; | 459 | int i, n = tun->numqueues; |
459 | 460 | ||
460 | for (i = 0; i < n; i++) { | 461 | for (i = 0; i < n; i++) { |
461 | tfile = rcu_dereference_protected(tun->tfiles[i], | 462 | tfile = rtnl_dereference(tun->tfiles[i]); |
462 | lockdep_rtnl_is_held()); | ||
463 | BUG_ON(!tfile); | 463 | BUG_ON(!tfile); |
464 | wake_up_all(&tfile->wq.wait); | 464 | wake_up_all(&tfile->wq.wait); |
465 | rcu_assign_pointer(tfile->tun, NULL); | 465 | rcu_assign_pointer(tfile->tun, NULL); |
@@ -469,8 +469,7 @@ static void tun_detach_all(struct net_device *dev) | |||
469 | 469 | ||
470 | synchronize_net(); | 470 | synchronize_net(); |
471 | for (i = 0; i < n; i++) { | 471 | for (i = 0; i < n; i++) { |
472 | tfile = rcu_dereference_protected(tun->tfiles[i], | 472 | tfile = rtnl_dereference(tun->tfiles[i]); |
473 | lockdep_rtnl_is_held()); | ||
474 | /* Drop read queue */ | 473 | /* Drop read queue */ |
475 | skb_queue_purge(&tfile->sk.sk_receive_queue); | 474 | skb_queue_purge(&tfile->sk.sk_receive_queue); |
476 | sock_put(&tfile->sk); | 475 | sock_put(&tfile->sk); |
@@ -481,6 +480,9 @@ static void tun_detach_all(struct net_device *dev) | |||
481 | sock_put(&tfile->sk); | 480 | sock_put(&tfile->sk); |
482 | } | 481 | } |
483 | BUG_ON(tun->numdisabled != 0); | 482 | BUG_ON(tun->numdisabled != 0); |
483 | |||
484 | if (tun->flags & TUN_PERSIST) | ||
485 | module_put(THIS_MODULE); | ||
484 | } | 486 | } |
485 | 487 | ||
486 | static int tun_attach(struct tun_struct *tun, struct file *file) | 488 | static int tun_attach(struct tun_struct *tun, struct file *file) |
@@ -489,7 +491,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file) | |||
489 | int err; | 491 | int err; |
490 | 492 | ||
491 | err = -EINVAL; | 493 | err = -EINVAL; |
492 | if (rcu_dereference_protected(tfile->tun, lockdep_rtnl_is_held())) | 494 | if (rtnl_dereference(tfile->tun)) |
493 | goto out; | 495 | goto out; |
494 | 496 | ||
495 | err = -EBUSY; | 497 | err = -EBUSY; |
@@ -1544,6 +1546,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
1544 | struct net_device *dev; | 1546 | struct net_device *dev; |
1545 | int err; | 1547 | int err; |
1546 | 1548 | ||
1549 | if (tfile->detached) | ||
1550 | return -EINVAL; | ||
1551 | |||
1547 | dev = __dev_get_by_name(net, ifr->ifr_name); | 1552 | dev = __dev_get_by_name(net, ifr->ifr_name); |
1548 | if (dev) { | 1553 | if (dev) { |
1549 | if (ifr->ifr_flags & IFF_TUN_EXCL) | 1554 | if (ifr->ifr_flags & IFF_TUN_EXCL) |
@@ -1738,8 +1743,7 @@ static void tun_detach_filter(struct tun_struct *tun, int n) | |||
1738 | struct tun_file *tfile; | 1743 | struct tun_file *tfile; |
1739 | 1744 | ||
1740 | for (i = 0; i < n; i++) { | 1745 | for (i = 0; i < n; i++) { |
1741 | tfile = rcu_dereference_protected(tun->tfiles[i], | 1746 | tfile = rtnl_dereference(tun->tfiles[i]); |
1742 | lockdep_rtnl_is_held()); | ||
1743 | sk_detach_filter(tfile->socket.sk); | 1747 | sk_detach_filter(tfile->socket.sk); |
1744 | } | 1748 | } |
1745 | 1749 | ||
@@ -1752,8 +1756,7 @@ static int tun_attach_filter(struct tun_struct *tun) | |||
1752 | struct tun_file *tfile; | 1756 | struct tun_file *tfile; |
1753 | 1757 | ||
1754 | for (i = 0; i < tun->numqueues; i++) { | 1758 | for (i = 0; i < tun->numqueues; i++) { |
1755 | tfile = rcu_dereference_protected(tun->tfiles[i], | 1759 | tfile = rtnl_dereference(tun->tfiles[i]); |
1756 | lockdep_rtnl_is_held()); | ||
1757 | ret = sk_attach_filter(&tun->fprog, tfile->socket.sk); | 1760 | ret = sk_attach_filter(&tun->fprog, tfile->socket.sk); |
1758 | if (ret) { | 1761 | if (ret) { |
1759 | tun_detach_filter(tun, i); | 1762 | tun_detach_filter(tun, i); |
@@ -1771,8 +1774,7 @@ static void tun_set_sndbuf(struct tun_struct *tun) | |||
1771 | int i; | 1774 | int i; |
1772 | 1775 | ||
1773 | for (i = 0; i < tun->numqueues; i++) { | 1776 | for (i = 0; i < tun->numqueues; i++) { |
1774 | tfile = rcu_dereference_protected(tun->tfiles[i], | 1777 | tfile = rtnl_dereference(tun->tfiles[i]); |
1775 | lockdep_rtnl_is_held()); | ||
1776 | tfile->socket.sk->sk_sndbuf = tun->sndbuf; | 1778 | tfile->socket.sk->sk_sndbuf = tun->sndbuf; |
1777 | } | 1779 | } |
1778 | } | 1780 | } |
@@ -1789,13 +1791,10 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr) | |||
1789 | tun = tfile->detached; | 1791 | tun = tfile->detached; |
1790 | if (!tun) | 1792 | if (!tun) |
1791 | ret = -EINVAL; | 1793 | ret = -EINVAL; |
1792 | else if (tun_not_capable(tun)) | ||
1793 | ret = -EPERM; | ||
1794 | else | 1794 | else |
1795 | ret = tun_attach(tun, file); | 1795 | ret = tun_attach(tun, file); |
1796 | } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) { | 1796 | } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) { |
1797 | tun = rcu_dereference_protected(tfile->tun, | 1797 | tun = rtnl_dereference(tfile->tun); |
1798 | lockdep_rtnl_is_held()); | ||
1799 | if (!tun || !(tun->flags & TUN_TAP_MQ)) | 1798 | if (!tun || !(tun->flags & TUN_TAP_MQ)) |
1800 | ret = -EINVAL; | 1799 | ret = -EINVAL; |
1801 | else | 1800 | else |
@@ -1880,10 +1879,11 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
1880 | /* Disable/Enable persist mode. Keep an extra reference to the | 1879 | /* Disable/Enable persist mode. Keep an extra reference to the |
1881 | * module to prevent the module being unprobed. | 1880 | * module to prevent the module being unprobed. |
1882 | */ | 1881 | */ |
1883 | if (arg) { | 1882 | if (arg && !(tun->flags & TUN_PERSIST)) { |
1884 | tun->flags |= TUN_PERSIST; | 1883 | tun->flags |= TUN_PERSIST; |
1885 | __module_get(THIS_MODULE); | 1884 | __module_get(THIS_MODULE); |
1886 | } else { | 1885 | } |
1886 | if (!arg && (tun->flags & TUN_PERSIST)) { | ||
1887 | tun->flags &= ~TUN_PERSIST; | 1887 | tun->flags &= ~TUN_PERSIST; |
1888 | module_put(THIS_MODULE); | 1888 | module_put(THIS_MODULE); |
1889 | } | 1889 | } |
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 1a67a4f829fe..2c02b4e84094 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig | |||
@@ -30,5 +30,6 @@ source "drivers/net/wireless/ath/ath9k/Kconfig" | |||
30 | source "drivers/net/wireless/ath/carl9170/Kconfig" | 30 | source "drivers/net/wireless/ath/carl9170/Kconfig" |
31 | source "drivers/net/wireless/ath/ath6kl/Kconfig" | 31 | source "drivers/net/wireless/ath/ath6kl/Kconfig" |
32 | source "drivers/net/wireless/ath/ar5523/Kconfig" | 32 | source "drivers/net/wireless/ath/ar5523/Kconfig" |
33 | source "drivers/net/wireless/ath/wil6210/Kconfig" | ||
33 | 34 | ||
34 | endif | 35 | endif |
diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index 1e18621326dc..97b964ded2be 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile | |||
@@ -3,6 +3,7 @@ obj-$(CONFIG_ATH9K_HW) += ath9k/ | |||
3 | obj-$(CONFIG_CARL9170) += carl9170/ | 3 | obj-$(CONFIG_CARL9170) += carl9170/ |
4 | obj-$(CONFIG_ATH6KL) += ath6kl/ | 4 | obj-$(CONFIG_ATH6KL) += ath6kl/ |
5 | obj-$(CONFIG_AR5523) += ar5523/ | 5 | obj-$(CONFIG_AR5523) += ar5523/ |
6 | obj-$(CONFIG_WIL6210) += wil6210/ | ||
6 | 7 | ||
7 | obj-$(CONFIG_ATH_COMMON) += ath.o | 8 | obj-$(CONFIG_ATH_COMMON) += ath.o |
8 | 9 | ||
diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig new file mode 100644 index 000000000000..bac3d98a0cfb --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/Kconfig | |||
@@ -0,0 +1,29 @@ | |||
1 | config WIL6210 | ||
2 | tristate "Wilocity 60g WiFi card wil6210 support" | ||
3 | depends on CFG80211 | ||
4 | depends on PCI | ||
5 | default n | ||
6 | ---help--- | ||
7 | This module adds support for wireless adapter based on | ||
8 | wil6210 chip by Wilocity. It supports operation on the | ||
9 | 60 GHz band, covered by the IEEE802.11ad standard. | ||
10 | |||
11 | http://wireless.kernel.org/en/users/Drivers/wil6210 | ||
12 | |||
13 | If you choose to build it as a module, it will be called | ||
14 | wil6210 | ||
15 | |||
16 | config WIL6210_ISR_COR | ||
17 | bool "Use Clear-On-Read mode for ISR registers for wil6210" | ||
18 | depends on WIL6210 | ||
19 | default y | ||
20 | ---help--- | ||
21 | ISR registers on wil6210 chip may operate in either | ||
22 | COR (Clear-On-Read) or W1C (Write-1-to-Clear) mode. | ||
23 | For production code, use COR (say y); is default since | ||
24 | it saves extra target transaction; | ||
25 | For ISR debug, use W1C (say n); is allows to monitor ISR | ||
26 | registers with debugfs. If COR were used, ISR would | ||
27 | self-clear when accessed for debug purposes, it makes | ||
28 | such monitoring impossible. | ||
29 | Say y unless you debug interrupts | ||
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile new file mode 100644 index 000000000000..9396dc9fe3c5 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | obj-$(CONFIG_WIL6210) += wil6210.o | ||
2 | |||
3 | wil6210-objs := main.o | ||
4 | wil6210-objs += netdev.o | ||
5 | wil6210-objs += cfg80211.o | ||
6 | wil6210-objs += pcie_bus.o | ||
7 | wil6210-objs += debugfs.o | ||
8 | wil6210-objs += wmi.o | ||
9 | wil6210-objs += interrupt.o | ||
10 | wil6210-objs += txrx.o | ||
11 | |||
12 | subdir-ccflags-y += -Werror | ||
13 | subdir-ccflags-y += -D__CHECK_ENDIAN__ | ||
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c new file mode 100644 index 000000000000..116f4e807ae1 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c | |||
@@ -0,0 +1,573 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/netdevice.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/etherdevice.h> | ||
21 | #include <linux/wireless.h> | ||
22 | #include <linux/ieee80211.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/version.h> | ||
25 | #include <net/cfg80211.h> | ||
26 | |||
27 | #include "wil6210.h" | ||
28 | #include "wmi.h" | ||
29 | |||
30 | #define CHAN60G(_channel, _flags) { \ | ||
31 | .band = IEEE80211_BAND_60GHZ, \ | ||
32 | .center_freq = 56160 + (2160 * (_channel)), \ | ||
33 | .hw_value = (_channel), \ | ||
34 | .flags = (_flags), \ | ||
35 | .max_antenna_gain = 0, \ | ||
36 | .max_power = 40, \ | ||
37 | } | ||
38 | |||
39 | static struct ieee80211_channel wil_60ghz_channels[] = { | ||
40 | CHAN60G(1, 0), | ||
41 | CHAN60G(2, 0), | ||
42 | CHAN60G(3, 0), | ||
43 | /* channel 4 not supported yet */ | ||
44 | }; | ||
45 | |||
46 | static struct ieee80211_supported_band wil_band_60ghz = { | ||
47 | .channels = wil_60ghz_channels, | ||
48 | .n_channels = ARRAY_SIZE(wil_60ghz_channels), | ||
49 | .ht_cap = { | ||
50 | .ht_supported = true, | ||
51 | .cap = 0, /* TODO */ | ||
52 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, /* TODO */ | ||
53 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, /* TODO */ | ||
54 | .mcs = { | ||
55 | /* MCS 1..12 - SC PHY */ | ||
56 | .rx_mask = {0xfe, 0x1f}, /* 1..12 */ | ||
57 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED, /* TODO */ | ||
58 | }, | ||
59 | }, | ||
60 | }; | ||
61 | |||
62 | static const struct ieee80211_txrx_stypes | ||
63 | wil_mgmt_stypes[NUM_NL80211_IFTYPES] = { | ||
64 | [NL80211_IFTYPE_STATION] = { | ||
65 | .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
66 | BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | ||
67 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
68 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
69 | }, | ||
70 | [NL80211_IFTYPE_AP] = { | ||
71 | .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
72 | BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | ||
73 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
74 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
75 | }, | ||
76 | [NL80211_IFTYPE_P2P_CLIENT] = { | ||
77 | .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
78 | BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | ||
79 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
80 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
81 | }, | ||
82 | [NL80211_IFTYPE_P2P_GO] = { | ||
83 | .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
84 | BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | ||
85 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
86 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
87 | }, | ||
88 | }; | ||
89 | |||
90 | static const u32 wil_cipher_suites[] = { | ||
91 | WLAN_CIPHER_SUITE_GCMP, | ||
92 | }; | ||
93 | |||
94 | int wil_iftype_nl2wmi(enum nl80211_iftype type) | ||
95 | { | ||
96 | static const struct { | ||
97 | enum nl80211_iftype nl; | ||
98 | enum wmi_network_type wmi; | ||
99 | } __nl2wmi[] = { | ||
100 | {NL80211_IFTYPE_ADHOC, WMI_NETTYPE_ADHOC}, | ||
101 | {NL80211_IFTYPE_STATION, WMI_NETTYPE_INFRA}, | ||
102 | {NL80211_IFTYPE_AP, WMI_NETTYPE_AP}, | ||
103 | {NL80211_IFTYPE_P2P_CLIENT, WMI_NETTYPE_P2P}, | ||
104 | {NL80211_IFTYPE_P2P_GO, WMI_NETTYPE_P2P}, | ||
105 | {NL80211_IFTYPE_MONITOR, WMI_NETTYPE_ADHOC}, /* FIXME */ | ||
106 | }; | ||
107 | uint i; | ||
108 | |||
109 | for (i = 0; i < ARRAY_SIZE(__nl2wmi); i++) { | ||
110 | if (__nl2wmi[i].nl == type) | ||
111 | return __nl2wmi[i].wmi; | ||
112 | } | ||
113 | |||
114 | return -EOPNOTSUPP; | ||
115 | } | ||
116 | |||
117 | static int wil_cfg80211_get_station(struct wiphy *wiphy, | ||
118 | struct net_device *ndev, | ||
119 | u8 *mac, struct station_info *sinfo) | ||
120 | { | ||
121 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
122 | int rc; | ||
123 | struct wmi_notify_req_cmd cmd = { | ||
124 | .cid = 0, | ||
125 | .interval_usec = 0, | ||
126 | }; | ||
127 | |||
128 | if (memcmp(mac, wil->dst_addr[0], ETH_ALEN)) | ||
129 | return -ENOENT; | ||
130 | |||
131 | /* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */ | ||
132 | rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd), | ||
133 | WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20); | ||
134 | if (rc) | ||
135 | return rc; | ||
136 | |||
137 | sinfo->generation = wil->sinfo_gen; | ||
138 | |||
139 | sinfo->filled |= STATION_INFO_TX_BITRATE; | ||
140 | sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; | ||
141 | sinfo->txrate.mcs = wil->stats.bf_mcs; | ||
142 | sinfo->filled |= STATION_INFO_RX_BITRATE; | ||
143 | sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; | ||
144 | sinfo->rxrate.mcs = wil->stats.last_mcs_rx; | ||
145 | |||
146 | if (test_bit(wil_status_fwconnected, &wil->status)) { | ||
147 | sinfo->filled |= STATION_INFO_SIGNAL; | ||
148 | sinfo->signal = 12; /* TODO: provide real value */ | ||
149 | } | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int wil_cfg80211_change_iface(struct wiphy *wiphy, | ||
155 | struct net_device *ndev, | ||
156 | enum nl80211_iftype type, u32 *flags, | ||
157 | struct vif_params *params) | ||
158 | { | ||
159 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
160 | struct wireless_dev *wdev = wil->wdev; | ||
161 | |||
162 | switch (type) { | ||
163 | case NL80211_IFTYPE_STATION: | ||
164 | case NL80211_IFTYPE_AP: | ||
165 | case NL80211_IFTYPE_P2P_CLIENT: | ||
166 | case NL80211_IFTYPE_P2P_GO: | ||
167 | break; | ||
168 | case NL80211_IFTYPE_MONITOR: | ||
169 | if (flags) | ||
170 | wil->monitor_flags = *flags; | ||
171 | else | ||
172 | wil->monitor_flags = 0; | ||
173 | |||
174 | break; | ||
175 | default: | ||
176 | return -EOPNOTSUPP; | ||
177 | } | ||
178 | |||
179 | wdev->iftype = type; | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static int wil_cfg80211_scan(struct wiphy *wiphy, | ||
185 | struct cfg80211_scan_request *request) | ||
186 | { | ||
187 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
188 | struct wireless_dev *wdev = wil->wdev; | ||
189 | struct { | ||
190 | struct wmi_start_scan_cmd cmd; | ||
191 | u16 chnl[4]; | ||
192 | } __packed cmd; | ||
193 | uint i, n; | ||
194 | |||
195 | if (wil->scan_request) { | ||
196 | wil_err(wil, "Already scanning\n"); | ||
197 | return -EAGAIN; | ||
198 | } | ||
199 | |||
200 | /* check we are client side */ | ||
201 | switch (wdev->iftype) { | ||
202 | case NL80211_IFTYPE_STATION: | ||
203 | case NL80211_IFTYPE_P2P_CLIENT: | ||
204 | break; | ||
205 | default: | ||
206 | return -EOPNOTSUPP; | ||
207 | |||
208 | } | ||
209 | |||
210 | /* FW don't support scan after connection attempt */ | ||
211 | if (test_bit(wil_status_dontscan, &wil->status)) { | ||
212 | wil_err(wil, "Scan after connect attempt not supported\n"); | ||
213 | return -EBUSY; | ||
214 | } | ||
215 | |||
216 | wil->scan_request = request; | ||
217 | |||
218 | memset(&cmd, 0, sizeof(cmd)); | ||
219 | cmd.cmd.num_channels = 0; | ||
220 | n = min(request->n_channels, 4U); | ||
221 | for (i = 0; i < n; i++) { | ||
222 | int ch = request->channels[i]->hw_value; | ||
223 | if (ch == 0) { | ||
224 | wil_err(wil, | ||
225 | "Scan requested for unknown frequency %dMhz\n", | ||
226 | request->channels[i]->center_freq); | ||
227 | continue; | ||
228 | } | ||
229 | /* 0-based channel indexes */ | ||
230 | cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1; | ||
231 | wil_dbg(wil, "Scan for ch %d : %d MHz\n", ch, | ||
232 | request->channels[i]->center_freq); | ||
233 | } | ||
234 | |||
235 | return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + | ||
236 | cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); | ||
237 | } | ||
238 | |||
239 | static int wil_cfg80211_connect(struct wiphy *wiphy, | ||
240 | struct net_device *ndev, | ||
241 | struct cfg80211_connect_params *sme) | ||
242 | { | ||
243 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
244 | struct cfg80211_bss *bss; | ||
245 | struct wmi_connect_cmd conn; | ||
246 | const u8 *ssid_eid; | ||
247 | const u8 *rsn_eid; | ||
248 | int ch; | ||
249 | int rc = 0; | ||
250 | |||
251 | bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, | ||
252 | sme->ssid, sme->ssid_len, | ||
253 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | ||
254 | if (!bss) { | ||
255 | wil_err(wil, "Unable to find BSS\n"); | ||
256 | return -ENOENT; | ||
257 | } | ||
258 | |||
259 | ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); | ||
260 | if (!ssid_eid) { | ||
261 | wil_err(wil, "No SSID\n"); | ||
262 | rc = -ENOENT; | ||
263 | goto out; | ||
264 | } | ||
265 | |||
266 | rsn_eid = sme->ie ? | ||
267 | cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) : | ||
268 | NULL; | ||
269 | if (rsn_eid) { | ||
270 | if (sme->ie_len > WMI_MAX_IE_LEN) { | ||
271 | rc = -ERANGE; | ||
272 | wil_err(wil, "IE too large (%td bytes)\n", | ||
273 | sme->ie_len); | ||
274 | goto out; | ||
275 | } | ||
276 | /* | ||
277 | * For secure assoc, send: | ||
278 | * (1) WMI_DELETE_CIPHER_KEY_CMD | ||
279 | * (2) WMI_SET_APPIE_CMD | ||
280 | */ | ||
281 | rc = wmi_del_cipher_key(wil, 0, bss->bssid); | ||
282 | if (rc) { | ||
283 | wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n"); | ||
284 | goto out; | ||
285 | } | ||
286 | /* WMI_SET_APPIE_CMD */ | ||
287 | rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie); | ||
288 | if (rc) { | ||
289 | wil_err(wil, "WMI_SET_APPIE_CMD failed\n"); | ||
290 | goto out; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | /* WMI_CONNECT_CMD */ | ||
295 | memset(&conn, 0, sizeof(conn)); | ||
296 | switch (bss->capability & 0x03) { | ||
297 | case WLAN_CAPABILITY_DMG_TYPE_AP: | ||
298 | conn.network_type = WMI_NETTYPE_INFRA; | ||
299 | break; | ||
300 | case WLAN_CAPABILITY_DMG_TYPE_PBSS: | ||
301 | conn.network_type = WMI_NETTYPE_P2P; | ||
302 | break; | ||
303 | default: | ||
304 | wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n", | ||
305 | bss->capability); | ||
306 | goto out; | ||
307 | } | ||
308 | if (rsn_eid) { | ||
309 | conn.dot11_auth_mode = WMI_AUTH11_SHARED; | ||
310 | conn.auth_mode = WMI_AUTH_WPA2_PSK; | ||
311 | conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP; | ||
312 | conn.pairwise_crypto_len = 16; | ||
313 | } else { | ||
314 | conn.dot11_auth_mode = WMI_AUTH11_OPEN; | ||
315 | conn.auth_mode = WMI_AUTH_NONE; | ||
316 | } | ||
317 | |||
318 | conn.ssid_len = min_t(u8, ssid_eid[1], 32); | ||
319 | memcpy(conn.ssid, ssid_eid+2, conn.ssid_len); | ||
320 | |||
321 | ch = bss->channel->hw_value; | ||
322 | if (ch == 0) { | ||
323 | wil_err(wil, "BSS at unknown frequency %dMhz\n", | ||
324 | bss->channel->center_freq); | ||
325 | rc = -EOPNOTSUPP; | ||
326 | goto out; | ||
327 | } | ||
328 | conn.channel = ch - 1; | ||
329 | |||
330 | memcpy(conn.bssid, bss->bssid, 6); | ||
331 | memcpy(conn.dst_mac, bss->bssid, 6); | ||
332 | /* | ||
333 | * FW don't support scan after connection attempt | ||
334 | */ | ||
335 | set_bit(wil_status_dontscan, &wil->status); | ||
336 | |||
337 | rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); | ||
338 | if (rc == 0) { | ||
339 | /* Connect can take lots of time */ | ||
340 | mod_timer(&wil->connect_timer, | ||
341 | jiffies + msecs_to_jiffies(2000)); | ||
342 | } | ||
343 | |||
344 | out: | ||
345 | cfg80211_put_bss(bss); | ||
346 | |||
347 | return rc; | ||
348 | } | ||
349 | |||
350 | static int wil_cfg80211_disconnect(struct wiphy *wiphy, | ||
351 | struct net_device *ndev, | ||
352 | u16 reason_code) | ||
353 | { | ||
354 | int rc; | ||
355 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
356 | |||
357 | rc = wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0); | ||
358 | |||
359 | return rc; | ||
360 | } | ||
361 | |||
362 | static int wil_cfg80211_set_channel(struct wiphy *wiphy, | ||
363 | struct cfg80211_chan_def *chandef) | ||
364 | { | ||
365 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
366 | struct wireless_dev *wdev = wil->wdev; | ||
367 | |||
368 | wdev->preset_chandef = *chandef; | ||
369 | |||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | static int wil_cfg80211_add_key(struct wiphy *wiphy, | ||
374 | struct net_device *ndev, | ||
375 | u8 key_index, bool pairwise, | ||
376 | const u8 *mac_addr, | ||
377 | struct key_params *params) | ||
378 | { | ||
379 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
380 | |||
381 | /* group key is not used */ | ||
382 | if (!pairwise) | ||
383 | return 0; | ||
384 | |||
385 | return wmi_add_cipher_key(wil, key_index, mac_addr, | ||
386 | params->key_len, params->key); | ||
387 | } | ||
388 | |||
389 | static int wil_cfg80211_del_key(struct wiphy *wiphy, | ||
390 | struct net_device *ndev, | ||
391 | u8 key_index, bool pairwise, | ||
392 | const u8 *mac_addr) | ||
393 | { | ||
394 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
395 | |||
396 | /* group key is not used */ | ||
397 | if (!pairwise) | ||
398 | return 0; | ||
399 | |||
400 | return wmi_del_cipher_key(wil, key_index, mac_addr); | ||
401 | } | ||
402 | |||
403 | /* Need to be present or wiphy_new() will WARN */ | ||
404 | static int wil_cfg80211_set_default_key(struct wiphy *wiphy, | ||
405 | struct net_device *ndev, | ||
406 | u8 key_index, bool unicast, | ||
407 | bool multicast) | ||
408 | { | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | static int wil_cfg80211_start_ap(struct wiphy *wiphy, | ||
413 | struct net_device *ndev, | ||
414 | struct cfg80211_ap_settings *info) | ||
415 | { | ||
416 | int rc = 0; | ||
417 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
418 | struct wireless_dev *wdev = ndev->ieee80211_ptr; | ||
419 | struct ieee80211_channel *channel = info->chandef.chan; | ||
420 | struct cfg80211_beacon_data *bcon = &info->beacon; | ||
421 | u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); | ||
422 | |||
423 | if (!channel) { | ||
424 | wil_err(wil, "AP: No channel???\n"); | ||
425 | return -EINVAL; | ||
426 | } | ||
427 | |||
428 | wil_dbg(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value, | ||
429 | channel->center_freq, info->privacy ? "secure" : "open"); | ||
430 | print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, | ||
431 | info->ssid, info->ssid_len); | ||
432 | |||
433 | rc = wil_reset(wil); | ||
434 | if (rc) | ||
435 | return rc; | ||
436 | |||
437 | rc = wmi_set_ssid(wil, info->ssid_len, info->ssid); | ||
438 | if (rc) | ||
439 | return rc; | ||
440 | |||
441 | rc = wmi_set_channel(wil, channel->hw_value); | ||
442 | if (rc) | ||
443 | return rc; | ||
444 | |||
445 | /* MAC address - pre-requisite for other commands */ | ||
446 | wmi_set_mac_address(wil, ndev->dev_addr); | ||
447 | |||
448 | /* IE's */ | ||
449 | /* bcon 'head IE's are not relevant for 60g band */ | ||
450 | wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, | ||
451 | bcon->beacon_ies); | ||
452 | wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len, | ||
453 | bcon->proberesp_ies); | ||
454 | wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, | ||
455 | bcon->assocresp_ies); | ||
456 | |||
457 | wil->secure_pcp = info->privacy; | ||
458 | |||
459 | rc = wmi_set_bcon(wil, info->beacon_interval, wmi_nettype); | ||
460 | if (rc) | ||
461 | return rc; | ||
462 | |||
463 | /* Rx VRING. After MAC and beacon */ | ||
464 | rc = wil_rx_init(wil); | ||
465 | |||
466 | netif_carrier_on(ndev); | ||
467 | |||
468 | return rc; | ||
469 | } | ||
470 | |||
471 | static int wil_cfg80211_stop_ap(struct wiphy *wiphy, | ||
472 | struct net_device *ndev) | ||
473 | { | ||
474 | int rc = 0; | ||
475 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
476 | struct wireless_dev *wdev = ndev->ieee80211_ptr; | ||
477 | u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); | ||
478 | |||
479 | /* To stop beaconing, set BI to 0 */ | ||
480 | rc = wmi_set_bcon(wil, 0, wmi_nettype); | ||
481 | |||
482 | return rc; | ||
483 | } | ||
484 | |||
485 | static struct cfg80211_ops wil_cfg80211_ops = { | ||
486 | .scan = wil_cfg80211_scan, | ||
487 | .connect = wil_cfg80211_connect, | ||
488 | .disconnect = wil_cfg80211_disconnect, | ||
489 | .change_virtual_intf = wil_cfg80211_change_iface, | ||
490 | .get_station = wil_cfg80211_get_station, | ||
491 | .set_monitor_channel = wil_cfg80211_set_channel, | ||
492 | .add_key = wil_cfg80211_add_key, | ||
493 | .del_key = wil_cfg80211_del_key, | ||
494 | .set_default_key = wil_cfg80211_set_default_key, | ||
495 | /* AP mode */ | ||
496 | .start_ap = wil_cfg80211_start_ap, | ||
497 | .stop_ap = wil_cfg80211_stop_ap, | ||
498 | }; | ||
499 | |||
500 | static void wil_wiphy_init(struct wiphy *wiphy) | ||
501 | { | ||
502 | /* TODO: set real value */ | ||
503 | wiphy->max_scan_ssids = 10; | ||
504 | wiphy->max_num_pmkids = 0 /* TODO: */; | ||
505 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
506 | BIT(NL80211_IFTYPE_AP) | | ||
507 | BIT(NL80211_IFTYPE_MONITOR); | ||
508 | /* TODO: enable P2P when integrated with supplicant: | ||
509 | * BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | ||
510 | */ | ||
511 | wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | | ||
512 | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; | ||
513 | dev_warn(wiphy_dev(wiphy), "%s : flags = 0x%08x\n", | ||
514 | __func__, wiphy->flags); | ||
515 | wiphy->probe_resp_offload = | ||
516 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | | ||
517 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | | ||
518 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; | ||
519 | |||
520 | wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz; | ||
521 | |||
522 | /* TODO: figure this out */ | ||
523 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | ||
524 | |||
525 | wiphy->cipher_suites = wil_cipher_suites; | ||
526 | wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites); | ||
527 | wiphy->mgmt_stypes = wil_mgmt_stypes; | ||
528 | } | ||
529 | |||
530 | struct wireless_dev *wil_cfg80211_init(struct device *dev) | ||
531 | { | ||
532 | int rc = 0; | ||
533 | struct wireless_dev *wdev; | ||
534 | |||
535 | wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | ||
536 | if (!wdev) | ||
537 | return ERR_PTR(-ENOMEM); | ||
538 | |||
539 | wdev->wiphy = wiphy_new(&wil_cfg80211_ops, | ||
540 | sizeof(struct wil6210_priv)); | ||
541 | if (!wdev->wiphy) { | ||
542 | rc = -ENOMEM; | ||
543 | goto out; | ||
544 | } | ||
545 | |||
546 | set_wiphy_dev(wdev->wiphy, dev); | ||
547 | wil_wiphy_init(wdev->wiphy); | ||
548 | |||
549 | rc = wiphy_register(wdev->wiphy); | ||
550 | if (rc < 0) | ||
551 | goto out_failed_reg; | ||
552 | |||
553 | return wdev; | ||
554 | |||
555 | out_failed_reg: | ||
556 | wiphy_free(wdev->wiphy); | ||
557 | out: | ||
558 | kfree(wdev); | ||
559 | |||
560 | return ERR_PTR(rc); | ||
561 | } | ||
562 | |||
563 | void wil_wdev_free(struct wil6210_priv *wil) | ||
564 | { | ||
565 | struct wireless_dev *wdev = wil_to_wdev(wil); | ||
566 | |||
567 | if (!wdev) | ||
568 | return; | ||
569 | |||
570 | wiphy_unregister(wdev->wiphy); | ||
571 | wiphy_free(wdev->wiphy); | ||
572 | kfree(wdev); | ||
573 | } | ||
diff --git a/drivers/net/wireless/ath/wil6210/dbg_hexdump.h b/drivers/net/wireless/ath/wil6210/dbg_hexdump.h new file mode 100644 index 000000000000..6a315ba5aa7d --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/dbg_hexdump.h | |||
@@ -0,0 +1,30 @@ | |||
1 | #ifndef WIL_DBG_HEXDUMP_H_ | ||
2 | #define WIL_DBG_HEXDUMP_H_ | ||
3 | |||
4 | #if defined(CONFIG_DYNAMIC_DEBUG) | ||
5 | #define wil_dynamic_hex_dump(prefix_str, prefix_type, rowsize, \ | ||
6 | groupsize, buf, len, ascii) \ | ||
7 | do { \ | ||
8 | DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, \ | ||
9 | __builtin_constant_p(prefix_str) ? prefix_str : "hexdump");\ | ||
10 | if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)) \ | ||
11 | print_hex_dump(KERN_DEBUG, prefix_str, \ | ||
12 | prefix_type, rowsize, groupsize, \ | ||
13 | buf, len, ascii); \ | ||
14 | } while (0) | ||
15 | |||
16 | #define wil_print_hex_dump_debug(prefix_str, prefix_type, rowsize, \ | ||
17 | groupsize, buf, len, ascii) \ | ||
18 | wil_dynamic_hex_dump(prefix_str, prefix_type, rowsize, \ | ||
19 | groupsize, buf, len, ascii) | ||
20 | |||
21 | #define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \ | ||
22 | wil_dynamic_hex_dump(prefix_str, prefix_type, 16, 1, buf, len, true) | ||
23 | #else /* defined(CONFIG_DYNAMIC_DEBUG) */ | ||
24 | #define wil_print_hex_dump_debug(prefix_str, prefix_type, rowsize, \ | ||
25 | groupsize, buf, len, ascii) \ | ||
26 | print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize, \ | ||
27 | groupsize, buf, len, ascii) | ||
28 | #endif /* defined(CONFIG_DYNAMIC_DEBUG) */ | ||
29 | |||
30 | #endif /* WIL_DBG_HEXDUMP_H_ */ | ||
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c new file mode 100644 index 000000000000..65fc9683bfd8 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/debugfs.c | |||
@@ -0,0 +1,603 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/debugfs.h> | ||
19 | #include <linux/seq_file.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include <linux/rtnetlink.h> | ||
22 | |||
23 | #include "wil6210.h" | ||
24 | #include "txrx.h" | ||
25 | |||
26 | /* Nasty hack. Better have per device instances */ | ||
27 | static u32 mem_addr; | ||
28 | static u32 dbg_txdesc_index; | ||
29 | |||
30 | static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, | ||
31 | const char *name, struct vring *vring) | ||
32 | { | ||
33 | void __iomem *x = wmi_addr(wil, vring->hwtail); | ||
34 | |||
35 | seq_printf(s, "VRING %s = {\n", name); | ||
36 | seq_printf(s, " pa = 0x%016llx\n", (unsigned long long)vring->pa); | ||
37 | seq_printf(s, " va = 0x%p\n", vring->va); | ||
38 | seq_printf(s, " size = %d\n", vring->size); | ||
39 | seq_printf(s, " swtail = %d\n", vring->swtail); | ||
40 | seq_printf(s, " swhead = %d\n", vring->swhead); | ||
41 | seq_printf(s, " hwtail = [0x%08x] -> ", vring->hwtail); | ||
42 | if (x) | ||
43 | seq_printf(s, "0x%08x\n", ioread32(x)); | ||
44 | else | ||
45 | seq_printf(s, "???\n"); | ||
46 | |||
47 | if (vring->va && (vring->size < 1025)) { | ||
48 | uint i; | ||
49 | for (i = 0; i < vring->size; i++) { | ||
50 | volatile struct vring_tx_desc *d = &vring->va[i].tx; | ||
51 | if ((i % 64) == 0 && (i != 0)) | ||
52 | seq_printf(s, "\n"); | ||
53 | seq_printf(s, "%s", (d->dma.status & BIT(0)) ? | ||
54 | "S" : (vring->ctx[i] ? "H" : "h")); | ||
55 | } | ||
56 | seq_printf(s, "\n"); | ||
57 | } | ||
58 | seq_printf(s, "}\n"); | ||
59 | } | ||
60 | |||
61 | static int wil_vring_debugfs_show(struct seq_file *s, void *data) | ||
62 | { | ||
63 | uint i; | ||
64 | struct wil6210_priv *wil = s->private; | ||
65 | |||
66 | wil_print_vring(s, wil, "rx", &wil->vring_rx); | ||
67 | |||
68 | for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { | ||
69 | struct vring *vring = &(wil->vring_tx[i]); | ||
70 | if (vring->va) { | ||
71 | char name[10]; | ||
72 | snprintf(name, sizeof(name), "tx_%2d", i); | ||
73 | wil_print_vring(s, wil, name, vring); | ||
74 | } | ||
75 | } | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static int wil_vring_seq_open(struct inode *inode, struct file *file) | ||
81 | { | ||
82 | return single_open(file, wil_vring_debugfs_show, inode->i_private); | ||
83 | } | ||
84 | |||
85 | static const struct file_operations fops_vring = { | ||
86 | .open = wil_vring_seq_open, | ||
87 | .release = single_release, | ||
88 | .read = seq_read, | ||
89 | .llseek = seq_lseek, | ||
90 | }; | ||
91 | |||
92 | static void wil_print_ring(struct seq_file *s, const char *prefix, | ||
93 | void __iomem *off) | ||
94 | { | ||
95 | struct wil6210_priv *wil = s->private; | ||
96 | struct wil6210_mbox_ring r; | ||
97 | int rsize; | ||
98 | uint i; | ||
99 | |||
100 | wil_memcpy_fromio_32(&r, off, sizeof(r)); | ||
101 | wil_mbox_ring_le2cpus(&r); | ||
102 | /* | ||
103 | * we just read memory block from NIC. This memory may be | ||
104 | * garbage. Check validity before using it. | ||
105 | */ | ||
106 | rsize = r.size / sizeof(struct wil6210_mbox_ring_desc); | ||
107 | |||
108 | seq_printf(s, "ring %s = {\n", prefix); | ||
109 | seq_printf(s, " base = 0x%08x\n", r.base); | ||
110 | seq_printf(s, " size = 0x%04x bytes -> %d entries\n", r.size, rsize); | ||
111 | seq_printf(s, " tail = 0x%08x\n", r.tail); | ||
112 | seq_printf(s, " head = 0x%08x\n", r.head); | ||
113 | seq_printf(s, " entry size = %d\n", r.entry_size); | ||
114 | |||
115 | if (r.size % sizeof(struct wil6210_mbox_ring_desc)) { | ||
116 | seq_printf(s, " ??? size is not multiple of %zd, garbage?\n", | ||
117 | sizeof(struct wil6210_mbox_ring_desc)); | ||
118 | goto out; | ||
119 | } | ||
120 | |||
121 | if (!wmi_addr(wil, r.base) || | ||
122 | !wmi_addr(wil, r.tail) || | ||
123 | !wmi_addr(wil, r.head)) { | ||
124 | seq_printf(s, " ??? pointers are garbage?\n"); | ||
125 | goto out; | ||
126 | } | ||
127 | |||
128 | for (i = 0; i < rsize; i++) { | ||
129 | struct wil6210_mbox_ring_desc d; | ||
130 | struct wil6210_mbox_hdr hdr; | ||
131 | size_t delta = i * sizeof(d); | ||
132 | void __iomem *x = wil->csr + HOSTADDR(r.base) + delta; | ||
133 | |||
134 | wil_memcpy_fromio_32(&d, x, sizeof(d)); | ||
135 | |||
136 | seq_printf(s, " [%2x] %s %s%s 0x%08x", i, | ||
137 | d.sync ? "F" : "E", | ||
138 | (r.tail - r.base == delta) ? "t" : " ", | ||
139 | (r.head - r.base == delta) ? "h" : " ", | ||
140 | le32_to_cpu(d.addr)); | ||
141 | if (0 == wmi_read_hdr(wil, d.addr, &hdr)) { | ||
142 | u16 len = le16_to_cpu(hdr.len); | ||
143 | seq_printf(s, " -> %04x %04x %04x %02x\n", | ||
144 | le16_to_cpu(hdr.seq), len, | ||
145 | le16_to_cpu(hdr.type), hdr.flags); | ||
146 | if (len <= MAX_MBOXITEM_SIZE) { | ||
147 | int n = 0; | ||
148 | unsigned char printbuf[16 * 3 + 2]; | ||
149 | unsigned char databuf[MAX_MBOXITEM_SIZE]; | ||
150 | void __iomem *src = wmi_buffer(wil, d.addr) + | ||
151 | sizeof(struct wil6210_mbox_hdr); | ||
152 | /* | ||
153 | * No need to check @src for validity - | ||
154 | * we already validated @d.addr while | ||
155 | * reading header | ||
156 | */ | ||
157 | wil_memcpy_fromio_32(databuf, src, len); | ||
158 | while (n < len) { | ||
159 | int l = min(len - n, 16); | ||
160 | hex_dump_to_buffer(databuf + n, l, | ||
161 | 16, 1, printbuf, | ||
162 | sizeof(printbuf), | ||
163 | false); | ||
164 | seq_printf(s, " : %s\n", printbuf); | ||
165 | n += l; | ||
166 | } | ||
167 | } | ||
168 | } else { | ||
169 | seq_printf(s, "\n"); | ||
170 | } | ||
171 | } | ||
172 | out: | ||
173 | seq_printf(s, "}\n"); | ||
174 | } | ||
175 | |||
176 | static int wil_mbox_debugfs_show(struct seq_file *s, void *data) | ||
177 | { | ||
178 | struct wil6210_priv *wil = s->private; | ||
179 | |||
180 | wil_print_ring(s, "tx", wil->csr + HOST_MBOX + | ||
181 | offsetof(struct wil6210_mbox_ctl, tx)); | ||
182 | wil_print_ring(s, "rx", wil->csr + HOST_MBOX + | ||
183 | offsetof(struct wil6210_mbox_ctl, rx)); | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static int wil_mbox_seq_open(struct inode *inode, struct file *file) | ||
189 | { | ||
190 | return single_open(file, wil_mbox_debugfs_show, inode->i_private); | ||
191 | } | ||
192 | |||
193 | static const struct file_operations fops_mbox = { | ||
194 | .open = wil_mbox_seq_open, | ||
195 | .release = single_release, | ||
196 | .read = seq_read, | ||
197 | .llseek = seq_lseek, | ||
198 | }; | ||
199 | |||
200 | static int wil_debugfs_iomem_x32_set(void *data, u64 val) | ||
201 | { | ||
202 | iowrite32(val, (void __iomem *)data); | ||
203 | wmb(); /* make sure write propagated to HW */ | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static int wil_debugfs_iomem_x32_get(void *data, u64 *val) | ||
209 | { | ||
210 | *val = ioread32((void __iomem *)data); | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get, | ||
216 | wil_debugfs_iomem_x32_set, "0x%08llx\n"); | ||
217 | |||
218 | static struct dentry *wil_debugfs_create_iomem_x32(const char *name, | ||
219 | mode_t mode, | ||
220 | struct dentry *parent, | ||
221 | void __iomem *value) | ||
222 | { | ||
223 | return debugfs_create_file(name, mode, parent, (void * __force)value, | ||
224 | &fops_iomem_x32); | ||
225 | } | ||
226 | |||
227 | static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil, | ||
228 | const char *name, | ||
229 | struct dentry *parent, u32 off) | ||
230 | { | ||
231 | struct dentry *d = debugfs_create_dir(name, parent); | ||
232 | |||
233 | if (IS_ERR_OR_NULL(d)) | ||
234 | return -ENODEV; | ||
235 | |||
236 | wil_debugfs_create_iomem_x32("ICC", S_IRUGO | S_IWUSR, d, | ||
237 | wil->csr + off); | ||
238 | wil_debugfs_create_iomem_x32("ICR", S_IRUGO | S_IWUSR, d, | ||
239 | wil->csr + off + 4); | ||
240 | wil_debugfs_create_iomem_x32("ICM", S_IRUGO | S_IWUSR, d, | ||
241 | wil->csr + off + 8); | ||
242 | wil_debugfs_create_iomem_x32("ICS", S_IWUSR, d, | ||
243 | wil->csr + off + 12); | ||
244 | wil_debugfs_create_iomem_x32("IMV", S_IRUGO | S_IWUSR, d, | ||
245 | wil->csr + off + 16); | ||
246 | wil_debugfs_create_iomem_x32("IMS", S_IWUSR, d, | ||
247 | wil->csr + off + 20); | ||
248 | wil_debugfs_create_iomem_x32("IMC", S_IWUSR, d, | ||
249 | wil->csr + off + 24); | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil, | ||
255 | struct dentry *parent) | ||
256 | { | ||
257 | struct dentry *d = debugfs_create_dir("PSEUDO_ISR", parent); | ||
258 | |||
259 | if (IS_ERR_OR_NULL(d)) | ||
260 | return -ENODEV; | ||
261 | |||
262 | wil_debugfs_create_iomem_x32("CAUSE", S_IRUGO, d, wil->csr + | ||
263 | HOSTADDR(RGF_DMA_PSEUDO_CAUSE)); | ||
264 | wil_debugfs_create_iomem_x32("MASK_SW", S_IRUGO, d, wil->csr + | ||
265 | HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); | ||
266 | wil_debugfs_create_iomem_x32("MASK_FW", S_IRUGO, d, wil->csr + | ||
267 | HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW)); | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil, | ||
273 | struct dentry *parent) | ||
274 | { | ||
275 | struct dentry *d = debugfs_create_dir("ITR_CNT", parent); | ||
276 | |||
277 | if (IS_ERR_OR_NULL(d)) | ||
278 | return -ENODEV; | ||
279 | |||
280 | wil_debugfs_create_iomem_x32("TRSH", S_IRUGO, d, wil->csr + | ||
281 | HOSTADDR(RGF_DMA_ITR_CNT_TRSH)); | ||
282 | wil_debugfs_create_iomem_x32("DATA", S_IRUGO, d, wil->csr + | ||
283 | HOSTADDR(RGF_DMA_ITR_CNT_DATA)); | ||
284 | wil_debugfs_create_iomem_x32("CTL", S_IRUGO, d, wil->csr + | ||
285 | HOSTADDR(RGF_DMA_ITR_CNT_CRL)); | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static int wil_memread_debugfs_show(struct seq_file *s, void *data) | ||
291 | { | ||
292 | struct wil6210_priv *wil = s->private; | ||
293 | void __iomem *a = wmi_buffer(wil, cpu_to_le32(mem_addr)); | ||
294 | |||
295 | if (a) | ||
296 | seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, ioread32(a)); | ||
297 | else | ||
298 | seq_printf(s, "[0x%08x] = INVALID\n", mem_addr); | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int wil_memread_seq_open(struct inode *inode, struct file *file) | ||
304 | { | ||
305 | return single_open(file, wil_memread_debugfs_show, inode->i_private); | ||
306 | } | ||
307 | |||
308 | static const struct file_operations fops_memread = { | ||
309 | .open = wil_memread_seq_open, | ||
310 | .release = single_release, | ||
311 | .read = seq_read, | ||
312 | .llseek = seq_lseek, | ||
313 | }; | ||
314 | |||
315 | static int wil_default_open(struct inode *inode, struct file *file) | ||
316 | { | ||
317 | if (inode->i_private) | ||
318 | file->private_data = inode->i_private; | ||
319 | |||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, | ||
324 | size_t count, loff_t *ppos) | ||
325 | { | ||
326 | enum { max_count = 4096 }; | ||
327 | struct debugfs_blob_wrapper *blob = file->private_data; | ||
328 | loff_t pos = *ppos; | ||
329 | size_t available = blob->size; | ||
330 | void *buf; | ||
331 | size_t ret; | ||
332 | |||
333 | if (pos < 0) | ||
334 | return -EINVAL; | ||
335 | |||
336 | if (pos >= available || !count) | ||
337 | return 0; | ||
338 | |||
339 | if (count > available - pos) | ||
340 | count = available - pos; | ||
341 | if (count > max_count) | ||
342 | count = max_count; | ||
343 | |||
344 | buf = kmalloc(count, GFP_KERNEL); | ||
345 | if (!buf) | ||
346 | return -ENOMEM; | ||
347 | |||
348 | wil_memcpy_fromio_32(buf, (const volatile void __iomem *)blob->data + | ||
349 | pos, count); | ||
350 | |||
351 | ret = copy_to_user(user_buf, buf, count); | ||
352 | kfree(buf); | ||
353 | if (ret == count) | ||
354 | return -EFAULT; | ||
355 | |||
356 | count -= ret; | ||
357 | *ppos = pos + count; | ||
358 | |||
359 | return count; | ||
360 | } | ||
361 | |||
362 | static const struct file_operations fops_ioblob = { | ||
363 | .read = wil_read_file_ioblob, | ||
364 | .open = wil_default_open, | ||
365 | .llseek = default_llseek, | ||
366 | }; | ||
367 | |||
368 | static | ||
369 | struct dentry *wil_debugfs_create_ioblob(const char *name, | ||
370 | mode_t mode, | ||
371 | struct dentry *parent, | ||
372 | struct debugfs_blob_wrapper *blob) | ||
373 | { | ||
374 | return debugfs_create_file(name, mode, parent, blob, &fops_ioblob); | ||
375 | } | ||
376 | /*---reset---*/ | ||
377 | static ssize_t wil_write_file_reset(struct file *file, const char __user *buf, | ||
378 | size_t len, loff_t *ppos) | ||
379 | { | ||
380 | struct wil6210_priv *wil = file->private_data; | ||
381 | struct net_device *ndev = wil_to_ndev(wil); | ||
382 | |||
383 | /** | ||
384 | * BUG: | ||
385 | * this code does NOT sync device state with the rest of system | ||
386 | * use with care, debug only!!! | ||
387 | */ | ||
388 | rtnl_lock(); | ||
389 | dev_close(ndev); | ||
390 | ndev->flags &= ~IFF_UP; | ||
391 | rtnl_unlock(); | ||
392 | wil_reset(wil); | ||
393 | |||
394 | return len; | ||
395 | } | ||
396 | |||
397 | static const struct file_operations fops_reset = { | ||
398 | .write = wil_write_file_reset, | ||
399 | .open = wil_default_open, | ||
400 | }; | ||
401 | /*---------Tx descriptor------------*/ | ||
402 | |||
403 | static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) | ||
404 | { | ||
405 | struct wil6210_priv *wil = s->private; | ||
406 | struct vring *vring = &(wil->vring_tx[0]); | ||
407 | |||
408 | if (!vring->va) { | ||
409 | seq_printf(s, "No Tx VRING\n"); | ||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | if (dbg_txdesc_index < vring->size) { | ||
414 | volatile struct vring_tx_desc *d = | ||
415 | &(vring->va[dbg_txdesc_index].tx); | ||
416 | volatile u32 *u = (volatile u32 *)d; | ||
417 | struct sk_buff *skb = vring->ctx[dbg_txdesc_index]; | ||
418 | |||
419 | seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index); | ||
420 | seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n", | ||
421 | u[0], u[1], u[2], u[3]); | ||
422 | seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n", | ||
423 | u[4], u[5], u[6], u[7]); | ||
424 | seq_printf(s, " SKB = %p\n", skb); | ||
425 | |||
426 | if (skb) { | ||
427 | unsigned char printbuf[16 * 3 + 2]; | ||
428 | int i = 0; | ||
429 | int len = skb_headlen(skb); | ||
430 | void *p = skb->data; | ||
431 | |||
432 | seq_printf(s, " len = %d\n", len); | ||
433 | |||
434 | while (i < len) { | ||
435 | int l = min(len - i, 16); | ||
436 | hex_dump_to_buffer(p + i, l, 16, 1, printbuf, | ||
437 | sizeof(printbuf), false); | ||
438 | seq_printf(s, " : %s\n", printbuf); | ||
439 | i += l; | ||
440 | } | ||
441 | } | ||
442 | seq_printf(s, "}\n"); | ||
443 | } else { | ||
444 | seq_printf(s, "TxDesc index (%d) >= size (%d)\n", | ||
445 | dbg_txdesc_index, vring->size); | ||
446 | } | ||
447 | |||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | static int wil_txdesc_seq_open(struct inode *inode, struct file *file) | ||
452 | { | ||
453 | return single_open(file, wil_txdesc_debugfs_show, inode->i_private); | ||
454 | } | ||
455 | |||
456 | static const struct file_operations fops_txdesc = { | ||
457 | .open = wil_txdesc_seq_open, | ||
458 | .release = single_release, | ||
459 | .read = seq_read, | ||
460 | .llseek = seq_lseek, | ||
461 | }; | ||
462 | |||
463 | /*---------beamforming------------*/ | ||
464 | static int wil_bf_debugfs_show(struct seq_file *s, void *data) | ||
465 | { | ||
466 | struct wil6210_priv *wil = s->private; | ||
467 | seq_printf(s, | ||
468 | "TSF : 0x%016llx\n" | ||
469 | "TxMCS : %d\n" | ||
470 | "Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n", | ||
471 | wil->stats.tsf, wil->stats.bf_mcs, | ||
472 | wil->stats.my_rx_sector, wil->stats.my_tx_sector, | ||
473 | wil->stats.peer_rx_sector, wil->stats.peer_tx_sector); | ||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | static int wil_bf_seq_open(struct inode *inode, struct file *file) | ||
478 | { | ||
479 | return single_open(file, wil_bf_debugfs_show, inode->i_private); | ||
480 | } | ||
481 | |||
482 | static const struct file_operations fops_bf = { | ||
483 | .open = wil_bf_seq_open, | ||
484 | .release = single_release, | ||
485 | .read = seq_read, | ||
486 | .llseek = seq_lseek, | ||
487 | }; | ||
488 | /*---------SSID------------*/ | ||
489 | static ssize_t wil_read_file_ssid(struct file *file, char __user *user_buf, | ||
490 | size_t count, loff_t *ppos) | ||
491 | { | ||
492 | struct wil6210_priv *wil = file->private_data; | ||
493 | struct wireless_dev *wdev = wil_to_wdev(wil); | ||
494 | |||
495 | return simple_read_from_buffer(user_buf, count, ppos, | ||
496 | wdev->ssid, wdev->ssid_len); | ||
497 | } | ||
498 | |||
499 | static ssize_t wil_write_file_ssid(struct file *file, const char __user *buf, | ||
500 | size_t count, loff_t *ppos) | ||
501 | { | ||
502 | struct wil6210_priv *wil = file->private_data; | ||
503 | struct wireless_dev *wdev = wil_to_wdev(wil); | ||
504 | struct net_device *ndev = wil_to_ndev(wil); | ||
505 | |||
506 | if (*ppos != 0) { | ||
507 | wil_err(wil, "Unable to set SSID substring from [%d]\n", | ||
508 | (int)*ppos); | ||
509 | return -EINVAL; | ||
510 | } | ||
511 | |||
512 | if (count > sizeof(wdev->ssid)) { | ||
513 | wil_err(wil, "SSID too long, len = %d\n", (int)count); | ||
514 | return -EINVAL; | ||
515 | } | ||
516 | if (netif_running(ndev)) { | ||
517 | wil_err(wil, "Unable to change SSID on running interface\n"); | ||
518 | return -EINVAL; | ||
519 | } | ||
520 | |||
521 | wdev->ssid_len = count; | ||
522 | return simple_write_to_buffer(wdev->ssid, wdev->ssid_len, ppos, | ||
523 | buf, count); | ||
524 | } | ||
525 | |||
526 | static const struct file_operations fops_ssid = { | ||
527 | .read = wil_read_file_ssid, | ||
528 | .write = wil_write_file_ssid, | ||
529 | .open = wil_default_open, | ||
530 | }; | ||
531 | |||
532 | /*----------------*/ | ||
533 | int wil6210_debugfs_init(struct wil6210_priv *wil) | ||
534 | { | ||
535 | struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME, | ||
536 | wil_to_wiphy(wil)->debugfsdir); | ||
537 | |||
538 | if (IS_ERR_OR_NULL(dbg)) | ||
539 | return -ENODEV; | ||
540 | |||
541 | debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox); | ||
542 | debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring); | ||
543 | debugfs_create_file("txdesc", S_IRUGO, dbg, wil, &fops_txdesc); | ||
544 | debugfs_create_u32("txdesc_index", S_IRUGO | S_IWUSR, dbg, | ||
545 | &dbg_txdesc_index); | ||
546 | debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf); | ||
547 | debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid); | ||
548 | debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg, | ||
549 | &wil->secure_pcp); | ||
550 | |||
551 | wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg, | ||
552 | HOSTADDR(RGF_USER_USER_ICR)); | ||
553 | wil6210_debugfs_create_ISR(wil, "DMA_EP_TX_ICR", dbg, | ||
554 | HOSTADDR(RGF_DMA_EP_TX_ICR)); | ||
555 | wil6210_debugfs_create_ISR(wil, "DMA_EP_RX_ICR", dbg, | ||
556 | HOSTADDR(RGF_DMA_EP_RX_ICR)); | ||
557 | wil6210_debugfs_create_ISR(wil, "DMA_EP_MISC_ICR", dbg, | ||
558 | HOSTADDR(RGF_DMA_EP_MISC_ICR)); | ||
559 | wil6210_debugfs_create_pseudo_ISR(wil, dbg); | ||
560 | wil6210_debugfs_create_ITR_CNT(wil, dbg); | ||
561 | |||
562 | debugfs_create_u32("mem_addr", S_IRUGO | S_IWUSR, dbg, &mem_addr); | ||
563 | debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread); | ||
564 | |||
565 | debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset); | ||
566 | |||
567 | wil->rgf_blob.data = (void * __force)wil->csr + 0; | ||
568 | wil->rgf_blob.size = 0xa000; | ||
569 | wil_debugfs_create_ioblob("blob_rgf", S_IRUGO, dbg, &wil->rgf_blob); | ||
570 | |||
571 | wil->fw_code_blob.data = (void * __force)wil->csr + 0x40000; | ||
572 | wil->fw_code_blob.size = 0x40000; | ||
573 | wil_debugfs_create_ioblob("blob_fw_code", S_IRUGO, dbg, | ||
574 | &wil->fw_code_blob); | ||
575 | |||
576 | wil->fw_data_blob.data = (void * __force)wil->csr + 0x80000; | ||
577 | wil->fw_data_blob.size = 0x8000; | ||
578 | wil_debugfs_create_ioblob("blob_fw_data", S_IRUGO, dbg, | ||
579 | &wil->fw_data_blob); | ||
580 | |||
581 | wil->fw_peri_blob.data = (void * __force)wil->csr + 0x88000; | ||
582 | wil->fw_peri_blob.size = 0x18000; | ||
583 | wil_debugfs_create_ioblob("blob_fw_peri", S_IRUGO, dbg, | ||
584 | &wil->fw_peri_blob); | ||
585 | |||
586 | wil->uc_code_blob.data = (void * __force)wil->csr + 0xa0000; | ||
587 | wil->uc_code_blob.size = 0x10000; | ||
588 | wil_debugfs_create_ioblob("blob_uc_code", S_IRUGO, dbg, | ||
589 | &wil->uc_code_blob); | ||
590 | |||
591 | wil->uc_data_blob.data = (void * __force)wil->csr + 0xb0000; | ||
592 | wil->uc_data_blob.size = 0x4000; | ||
593 | wil_debugfs_create_ioblob("blob_uc_data", S_IRUGO, dbg, | ||
594 | &wil->uc_data_blob); | ||
595 | |||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | void wil6210_debugfs_remove(struct wil6210_priv *wil) | ||
600 | { | ||
601 | debugfs_remove_recursive(wil->debug); | ||
602 | wil->debug = NULL; | ||
603 | } | ||
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c new file mode 100644 index 000000000000..38049da71049 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/interrupt.c | |||
@@ -0,0 +1,471 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/interrupt.h> | ||
18 | |||
19 | #include "wil6210.h" | ||
20 | |||
21 | /** | ||
22 | * Theory of operation: | ||
23 | * | ||
24 | * There is ISR pseudo-cause register, | ||
25 | * dma_rgf->DMA_RGF.PSEUDO_CAUSE.PSEUDO_CAUSE | ||
26 | * Its bits represents OR'ed bits from 3 real ISR registers: | ||
27 | * TX, RX, and MISC. | ||
28 | * | ||
29 | * Registers may be configured to either "write 1 to clear" or | ||
30 | * "clear on read" mode | ||
31 | * | ||
32 | * When handling interrupt, one have to mask/unmask interrupts for the | ||
33 | * real ISR registers, or hardware may malfunction. | ||
34 | * | ||
35 | */ | ||
36 | |||
37 | #define WIL6210_IRQ_DISABLE (0xFFFFFFFFUL) | ||
38 | #define WIL6210_IMC_RX BIT_DMA_EP_RX_ICR_RX_DONE | ||
39 | #define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \ | ||
40 | BIT_DMA_EP_TX_ICR_TX_DONE_N(0)) | ||
41 | #define WIL6210_IMC_MISC (ISR_MISC_FW_READY | ISR_MISC_MBOX_EVT) | ||
42 | |||
43 | #define WIL6210_IRQ_PSEUDO_MASK (u32)(~(BIT_DMA_PSEUDO_CAUSE_RX | \ | ||
44 | BIT_DMA_PSEUDO_CAUSE_TX | \ | ||
45 | BIT_DMA_PSEUDO_CAUSE_MISC)) | ||
46 | |||
47 | #if defined(CONFIG_WIL6210_ISR_COR) | ||
48 | /* configure to Clear-On-Read mode */ | ||
49 | #define WIL_ICR_ICC_VALUE (0xFFFFFFFFUL) | ||
50 | |||
51 | static inline void wil_icr_clear(u32 x, void __iomem *addr) | ||
52 | { | ||
53 | |||
54 | } | ||
55 | #else /* defined(CONFIG_WIL6210_ISR_COR) */ | ||
56 | /* configure to Write-1-to-Clear mode */ | ||
57 | #define WIL_ICR_ICC_VALUE (0UL) | ||
58 | |||
59 | static inline void wil_icr_clear(u32 x, void __iomem *addr) | ||
60 | { | ||
61 | iowrite32(x, addr); | ||
62 | } | ||
63 | #endif /* defined(CONFIG_WIL6210_ISR_COR) */ | ||
64 | |||
65 | static inline u32 wil_ioread32_and_clear(void __iomem *addr) | ||
66 | { | ||
67 | u32 x = ioread32(addr); | ||
68 | |||
69 | wil_icr_clear(x, addr); | ||
70 | |||
71 | return x; | ||
72 | } | ||
73 | |||
74 | static void wil6210_mask_irq_tx(struct wil6210_priv *wil) | ||
75 | { | ||
76 | iowrite32(WIL6210_IRQ_DISABLE, wil->csr + | ||
77 | HOSTADDR(RGF_DMA_EP_TX_ICR) + | ||
78 | offsetof(struct RGF_ICR, IMS)); | ||
79 | } | ||
80 | |||
81 | static void wil6210_mask_irq_rx(struct wil6210_priv *wil) | ||
82 | { | ||
83 | iowrite32(WIL6210_IRQ_DISABLE, wil->csr + | ||
84 | HOSTADDR(RGF_DMA_EP_RX_ICR) + | ||
85 | offsetof(struct RGF_ICR, IMS)); | ||
86 | } | ||
87 | |||
88 | static void wil6210_mask_irq_misc(struct wil6210_priv *wil) | ||
89 | { | ||
90 | iowrite32(WIL6210_IRQ_DISABLE, wil->csr + | ||
91 | HOSTADDR(RGF_DMA_EP_MISC_ICR) + | ||
92 | offsetof(struct RGF_ICR, IMS)); | ||
93 | } | ||
94 | |||
95 | static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil) | ||
96 | { | ||
97 | wil_dbg_IRQ(wil, "%s()\n", __func__); | ||
98 | |||
99 | iowrite32(WIL6210_IRQ_DISABLE, wil->csr + | ||
100 | HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); | ||
101 | |||
102 | clear_bit(wil_status_irqen, &wil->status); | ||
103 | } | ||
104 | |||
105 | static void wil6210_unmask_irq_tx(struct wil6210_priv *wil) | ||
106 | { | ||
107 | iowrite32(WIL6210_IMC_TX, wil->csr + | ||
108 | HOSTADDR(RGF_DMA_EP_TX_ICR) + | ||
109 | offsetof(struct RGF_ICR, IMC)); | ||
110 | } | ||
111 | |||
112 | static void wil6210_unmask_irq_rx(struct wil6210_priv *wil) | ||
113 | { | ||
114 | iowrite32(WIL6210_IMC_RX, wil->csr + | ||
115 | HOSTADDR(RGF_DMA_EP_RX_ICR) + | ||
116 | offsetof(struct RGF_ICR, IMC)); | ||
117 | } | ||
118 | |||
119 | static void wil6210_unmask_irq_misc(struct wil6210_priv *wil) | ||
120 | { | ||
121 | iowrite32(WIL6210_IMC_MISC, wil->csr + | ||
122 | HOSTADDR(RGF_DMA_EP_MISC_ICR) + | ||
123 | offsetof(struct RGF_ICR, IMC)); | ||
124 | } | ||
125 | |||
126 | static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) | ||
127 | { | ||
128 | wil_dbg_IRQ(wil, "%s()\n", __func__); | ||
129 | |||
130 | set_bit(wil_status_irqen, &wil->status); | ||
131 | |||
132 | iowrite32(WIL6210_IRQ_PSEUDO_MASK, wil->csr + | ||
133 | HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); | ||
134 | } | ||
135 | |||
136 | void wil6210_disable_irq(struct wil6210_priv *wil) | ||
137 | { | ||
138 | wil_dbg_IRQ(wil, "%s()\n", __func__); | ||
139 | |||
140 | wil6210_mask_irq_tx(wil); | ||
141 | wil6210_mask_irq_rx(wil); | ||
142 | wil6210_mask_irq_misc(wil); | ||
143 | wil6210_mask_irq_pseudo(wil); | ||
144 | } | ||
145 | |||
146 | void wil6210_enable_irq(struct wil6210_priv *wil) | ||
147 | { | ||
148 | wil_dbg_IRQ(wil, "%s()\n", __func__); | ||
149 | |||
150 | iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + | ||
151 | offsetof(struct RGF_ICR, ICC)); | ||
152 | iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + | ||
153 | offsetof(struct RGF_ICR, ICC)); | ||
154 | iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + | ||
155 | offsetof(struct RGF_ICR, ICC)); | ||
156 | |||
157 | wil6210_unmask_irq_pseudo(wil); | ||
158 | wil6210_unmask_irq_tx(wil); | ||
159 | wil6210_unmask_irq_rx(wil); | ||
160 | wil6210_unmask_irq_misc(wil); | ||
161 | } | ||
162 | |||
163 | static irqreturn_t wil6210_irq_rx(int irq, void *cookie) | ||
164 | { | ||
165 | struct wil6210_priv *wil = cookie; | ||
166 | u32 isr = wil_ioread32_and_clear(wil->csr + | ||
167 | HOSTADDR(RGF_DMA_EP_RX_ICR) + | ||
168 | offsetof(struct RGF_ICR, ICR)); | ||
169 | |||
170 | wil_dbg_IRQ(wil, "ISR RX 0x%08x\n", isr); | ||
171 | |||
172 | if (!isr) { | ||
173 | wil_err(wil, "spurious IRQ: RX\n"); | ||
174 | return IRQ_NONE; | ||
175 | } | ||
176 | |||
177 | wil6210_mask_irq_rx(wil); | ||
178 | |||
179 | if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) { | ||
180 | wil_dbg_IRQ(wil, "RX done\n"); | ||
181 | isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; | ||
182 | wil_rx_handle(wil); | ||
183 | } | ||
184 | |||
185 | if (isr) | ||
186 | wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr); | ||
187 | |||
188 | wil6210_unmask_irq_rx(wil); | ||
189 | |||
190 | return IRQ_HANDLED; | ||
191 | } | ||
192 | |||
193 | static irqreturn_t wil6210_irq_tx(int irq, void *cookie) | ||
194 | { | ||
195 | struct wil6210_priv *wil = cookie; | ||
196 | u32 isr = wil_ioread32_and_clear(wil->csr + | ||
197 | HOSTADDR(RGF_DMA_EP_TX_ICR) + | ||
198 | offsetof(struct RGF_ICR, ICR)); | ||
199 | |||
200 | wil_dbg_IRQ(wil, "ISR TX 0x%08x\n", isr); | ||
201 | |||
202 | if (!isr) { | ||
203 | wil_err(wil, "spurious IRQ: TX\n"); | ||
204 | return IRQ_NONE; | ||
205 | } | ||
206 | |||
207 | wil6210_mask_irq_tx(wil); | ||
208 | |||
209 | if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { | ||
210 | uint i; | ||
211 | wil_dbg_IRQ(wil, "TX done\n"); | ||
212 | isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; | ||
213 | for (i = 0; i < 24; i++) { | ||
214 | u32 mask = BIT_DMA_EP_TX_ICR_TX_DONE_N(i); | ||
215 | if (isr & mask) { | ||
216 | isr &= ~mask; | ||
217 | wil_dbg_IRQ(wil, "TX done(%i)\n", i); | ||
218 | wil_tx_complete(wil, i); | ||
219 | } | ||
220 | } | ||
221 | } | ||
222 | |||
223 | if (isr) | ||
224 | wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr); | ||
225 | |||
226 | wil6210_unmask_irq_tx(wil); | ||
227 | |||
228 | return IRQ_HANDLED; | ||
229 | } | ||
230 | |||
231 | static irqreturn_t wil6210_irq_misc(int irq, void *cookie) | ||
232 | { | ||
233 | struct wil6210_priv *wil = cookie; | ||
234 | u32 isr = wil_ioread32_and_clear(wil->csr + | ||
235 | HOSTADDR(RGF_DMA_EP_MISC_ICR) + | ||
236 | offsetof(struct RGF_ICR, ICR)); | ||
237 | |||
238 | wil_dbg_IRQ(wil, "ISR MISC 0x%08x\n", isr); | ||
239 | |||
240 | if (!isr) { | ||
241 | wil_err(wil, "spurious IRQ: MISC\n"); | ||
242 | return IRQ_NONE; | ||
243 | } | ||
244 | |||
245 | wil6210_mask_irq_misc(wil); | ||
246 | |||
247 | if (isr & ISR_MISC_FW_READY) { | ||
248 | wil_dbg_IRQ(wil, "IRQ: FW ready\n"); | ||
249 | /** | ||
250 | * Actual FW ready indicated by the | ||
251 | * WMI_FW_READY_EVENTID | ||
252 | */ | ||
253 | isr &= ~ISR_MISC_FW_READY; | ||
254 | } | ||
255 | |||
256 | wil->isr_misc = isr; | ||
257 | |||
258 | if (isr) { | ||
259 | return IRQ_WAKE_THREAD; | ||
260 | } else { | ||
261 | wil6210_unmask_irq_misc(wil); | ||
262 | return IRQ_HANDLED; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) | ||
267 | { | ||
268 | struct wil6210_priv *wil = cookie; | ||
269 | u32 isr = wil->isr_misc; | ||
270 | |||
271 | wil_dbg_IRQ(wil, "Thread ISR MISC 0x%08x\n", isr); | ||
272 | |||
273 | if (isr & ISR_MISC_MBOX_EVT) { | ||
274 | wil_dbg_IRQ(wil, "MBOX event\n"); | ||
275 | wmi_recv_cmd(wil); | ||
276 | isr &= ~ISR_MISC_MBOX_EVT; | ||
277 | } | ||
278 | |||
279 | if (isr) | ||
280 | wil_err(wil, "un-handled MISC ISR bits 0x%08x\n", isr); | ||
281 | |||
282 | wil->isr_misc = 0; | ||
283 | |||
284 | wil6210_unmask_irq_misc(wil); | ||
285 | |||
286 | return IRQ_HANDLED; | ||
287 | } | ||
288 | |||
289 | /** | ||
290 | * thread IRQ handler | ||
291 | */ | ||
292 | static irqreturn_t wil6210_thread_irq(int irq, void *cookie) | ||
293 | { | ||
294 | struct wil6210_priv *wil = cookie; | ||
295 | |||
296 | wil_dbg_IRQ(wil, "Thread IRQ\n"); | ||
297 | /* Discover real IRQ cause */ | ||
298 | if (wil->isr_misc) | ||
299 | wil6210_irq_misc_thread(irq, cookie); | ||
300 | |||
301 | wil6210_unmask_irq_pseudo(wil); | ||
302 | |||
303 | return IRQ_HANDLED; | ||
304 | } | ||
305 | |||
306 | /* DEBUG | ||
307 | * There is subtle bug in hardware that causes IRQ to raise when it should be | ||
308 | * masked. It is quite rare and hard to debug. | ||
309 | * | ||
310 | * Catch irq issue if it happens and print all I can. | ||
311 | */ | ||
312 | static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause) | ||
313 | { | ||
314 | if (!test_bit(wil_status_irqen, &wil->status)) { | ||
315 | u32 icm_rx = wil_ioread32_and_clear(wil->csr + | ||
316 | HOSTADDR(RGF_DMA_EP_RX_ICR) + | ||
317 | offsetof(struct RGF_ICR, ICM)); | ||
318 | u32 icr_rx = wil_ioread32_and_clear(wil->csr + | ||
319 | HOSTADDR(RGF_DMA_EP_RX_ICR) + | ||
320 | offsetof(struct RGF_ICR, ICR)); | ||
321 | u32 imv_rx = ioread32(wil->csr + | ||
322 | HOSTADDR(RGF_DMA_EP_RX_ICR) + | ||
323 | offsetof(struct RGF_ICR, IMV)); | ||
324 | u32 icm_tx = wil_ioread32_and_clear(wil->csr + | ||
325 | HOSTADDR(RGF_DMA_EP_TX_ICR) + | ||
326 | offsetof(struct RGF_ICR, ICM)); | ||
327 | u32 icr_tx = wil_ioread32_and_clear(wil->csr + | ||
328 | HOSTADDR(RGF_DMA_EP_TX_ICR) + | ||
329 | offsetof(struct RGF_ICR, ICR)); | ||
330 | u32 imv_tx = ioread32(wil->csr + | ||
331 | HOSTADDR(RGF_DMA_EP_TX_ICR) + | ||
332 | offsetof(struct RGF_ICR, IMV)); | ||
333 | u32 icm_misc = wil_ioread32_and_clear(wil->csr + | ||
334 | HOSTADDR(RGF_DMA_EP_MISC_ICR) + | ||
335 | offsetof(struct RGF_ICR, ICM)); | ||
336 | u32 icr_misc = wil_ioread32_and_clear(wil->csr + | ||
337 | HOSTADDR(RGF_DMA_EP_MISC_ICR) + | ||
338 | offsetof(struct RGF_ICR, ICR)); | ||
339 | u32 imv_misc = ioread32(wil->csr + | ||
340 | HOSTADDR(RGF_DMA_EP_MISC_ICR) + | ||
341 | offsetof(struct RGF_ICR, IMV)); | ||
342 | wil_err(wil, "IRQ when it should be masked: pseudo 0x%08x\n" | ||
343 | "Rx icm:icr:imv 0x%08x 0x%08x 0x%08x\n" | ||
344 | "Tx icm:icr:imv 0x%08x 0x%08x 0x%08x\n" | ||
345 | "Misc icm:icr:imv 0x%08x 0x%08x 0x%08x\n", | ||
346 | pseudo_cause, | ||
347 | icm_rx, icr_rx, imv_rx, | ||
348 | icm_tx, icr_tx, imv_tx, | ||
349 | icm_misc, icr_misc, imv_misc); | ||
350 | |||
351 | return -EINVAL; | ||
352 | } | ||
353 | |||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | static irqreturn_t wil6210_hardirq(int irq, void *cookie) | ||
358 | { | ||
359 | irqreturn_t rc = IRQ_HANDLED; | ||
360 | struct wil6210_priv *wil = cookie; | ||
361 | u32 pseudo_cause = ioread32(wil->csr + HOSTADDR(RGF_DMA_PSEUDO_CAUSE)); | ||
362 | |||
363 | /** | ||
364 | * pseudo_cause is Clear-On-Read, no need to ACK | ||
365 | */ | ||
366 | if ((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff)) | ||
367 | return IRQ_NONE; | ||
368 | |||
369 | /* FIXME: IRQ mask debug */ | ||
370 | if (wil6210_debug_irq_mask(wil, pseudo_cause)) | ||
371 | return IRQ_NONE; | ||
372 | |||
373 | wil6210_mask_irq_pseudo(wil); | ||
374 | |||
375 | /* Discover real IRQ cause | ||
376 | * There are 2 possible phases for every IRQ: | ||
377 | * - hard IRQ handler called right here | ||
378 | * - threaded handler called later | ||
379 | * | ||
380 | * Hard IRQ handler reads and clears ISR. | ||
381 | * | ||
382 | * If threaded handler requested, hard IRQ handler | ||
383 | * returns IRQ_WAKE_THREAD and saves ISR register value | ||
384 | * for the threaded handler use. | ||
385 | * | ||
386 | * voting for wake thread - need at least 1 vote | ||
387 | */ | ||
388 | if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_RX) && | ||
389 | (wil6210_irq_rx(irq, cookie) == IRQ_WAKE_THREAD)) | ||
390 | rc = IRQ_WAKE_THREAD; | ||
391 | |||
392 | if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_TX) && | ||
393 | (wil6210_irq_tx(irq, cookie) == IRQ_WAKE_THREAD)) | ||
394 | rc = IRQ_WAKE_THREAD; | ||
395 | |||
396 | if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_MISC) && | ||
397 | (wil6210_irq_misc(irq, cookie) == IRQ_WAKE_THREAD)) | ||
398 | rc = IRQ_WAKE_THREAD; | ||
399 | |||
400 | /* if thread is requested, it will unmask IRQ */ | ||
401 | if (rc != IRQ_WAKE_THREAD) | ||
402 | wil6210_unmask_irq_pseudo(wil); | ||
403 | |||
404 | wil_dbg_IRQ(wil, "Hard IRQ 0x%08x\n", pseudo_cause); | ||
405 | |||
406 | return rc; | ||
407 | } | ||
408 | |||
409 | static int wil6210_request_3msi(struct wil6210_priv *wil, int irq) | ||
410 | { | ||
411 | int rc; | ||
412 | /* | ||
413 | * IRQ's are in the following order: | ||
414 | * - Tx | ||
415 | * - Rx | ||
416 | * - Misc | ||
417 | */ | ||
418 | |||
419 | rc = request_irq(irq, wil6210_irq_tx, IRQF_SHARED, | ||
420 | WIL_NAME"_tx", wil); | ||
421 | if (rc) | ||
422 | return rc; | ||
423 | |||
424 | rc = request_irq(irq + 1, wil6210_irq_rx, IRQF_SHARED, | ||
425 | WIL_NAME"_rx", wil); | ||
426 | if (rc) | ||
427 | goto free0; | ||
428 | |||
429 | rc = request_threaded_irq(irq + 2, wil6210_irq_misc, | ||
430 | wil6210_irq_misc_thread, | ||
431 | IRQF_SHARED, WIL_NAME"_misc", wil); | ||
432 | if (rc) | ||
433 | goto free1; | ||
434 | |||
435 | return 0; | ||
436 | /* error branch */ | ||
437 | free1: | ||
438 | free_irq(irq + 1, wil); | ||
439 | free0: | ||
440 | free_irq(irq, wil); | ||
441 | |||
442 | return rc; | ||
443 | } | ||
444 | |||
445 | int wil6210_init_irq(struct wil6210_priv *wil, int irq) | ||
446 | { | ||
447 | int rc; | ||
448 | if (wil->n_msi == 3) | ||
449 | rc = wil6210_request_3msi(wil, irq); | ||
450 | else | ||
451 | rc = request_threaded_irq(irq, wil6210_hardirq, | ||
452 | wil6210_thread_irq, | ||
453 | wil->n_msi ? 0 : IRQF_SHARED, | ||
454 | WIL_NAME, wil); | ||
455 | if (rc) | ||
456 | return rc; | ||
457 | |||
458 | wil6210_enable_irq(wil); | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | void wil6210_fini_irq(struct wil6210_priv *wil, int irq) | ||
464 | { | ||
465 | wil6210_disable_irq(wil); | ||
466 | free_irq(irq, wil); | ||
467 | if (wil->n_msi == 3) { | ||
468 | free_irq(irq + 1, wil); | ||
469 | free_irq(irq + 2, wil); | ||
470 | } | ||
471 | } | ||
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c new file mode 100644 index 000000000000..95fcd361322b --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/main.c | |||
@@ -0,0 +1,407 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/netdevice.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/ieee80211.h> | ||
21 | #include <linux/wireless.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/moduleparam.h> | ||
24 | #include <linux/if_arp.h> | ||
25 | |||
26 | #include "wil6210.h" | ||
27 | |||
28 | /* | ||
29 | * Due to a hardware issue, | ||
30 | * one has to read/write to/from NIC in 32-bit chunks; | ||
31 | * regular memcpy_fromio and siblings will | ||
32 | * not work on 64-bit platform - it uses 64-bit transactions | ||
33 | * | ||
34 | * Force 32-bit transactions to enable NIC on 64-bit platforms | ||
35 | * | ||
36 | * To avoid byte swap on big endian host, __raw_{read|write}l | ||
37 | * should be used - {read|write}l would swap bytes to provide | ||
38 | * little endian on PCI value in host endianness. | ||
39 | */ | ||
40 | void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, | ||
41 | size_t count) | ||
42 | { | ||
43 | u32 *d = dst; | ||
44 | const volatile u32 __iomem *s = src; | ||
45 | |||
46 | /* size_t is unsigned, if (count%4 != 0) it will wrap */ | ||
47 | for (count += 4; count > 4; count -= 4) | ||
48 | *d++ = __raw_readl(s++); | ||
49 | } | ||
50 | |||
51 | void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, | ||
52 | size_t count) | ||
53 | { | ||
54 | volatile u32 __iomem *d = dst; | ||
55 | const u32 *s = src; | ||
56 | |||
57 | for (count += 4; count > 4; count -= 4) | ||
58 | __raw_writel(*s++, d++); | ||
59 | } | ||
60 | |||
61 | static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) | ||
62 | { | ||
63 | uint i; | ||
64 | struct net_device *ndev = wil_to_ndev(wil); | ||
65 | struct wireless_dev *wdev = wil->wdev; | ||
66 | |||
67 | wil_dbg(wil, "%s()\n", __func__); | ||
68 | |||
69 | wil_link_off(wil); | ||
70 | clear_bit(wil_status_fwconnected, &wil->status); | ||
71 | |||
72 | switch (wdev->sme_state) { | ||
73 | case CFG80211_SME_CONNECTED: | ||
74 | cfg80211_disconnected(ndev, WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
75 | NULL, 0, GFP_KERNEL); | ||
76 | break; | ||
77 | case CFG80211_SME_CONNECTING: | ||
78 | cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, | ||
79 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
80 | GFP_KERNEL); | ||
81 | break; | ||
82 | default: | ||
83 | ; | ||
84 | } | ||
85 | |||
86 | for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) | ||
87 | wil_vring_fini_tx(wil, i); | ||
88 | } | ||
89 | |||
90 | static void wil_disconnect_worker(struct work_struct *work) | ||
91 | { | ||
92 | struct wil6210_priv *wil = container_of(work, | ||
93 | struct wil6210_priv, disconnect_worker); | ||
94 | |||
95 | _wil6210_disconnect(wil, NULL); | ||
96 | } | ||
97 | |||
98 | static void wil_connect_timer_fn(ulong x) | ||
99 | { | ||
100 | struct wil6210_priv *wil = (void *)x; | ||
101 | |||
102 | wil_dbg(wil, "Connect timeout\n"); | ||
103 | |||
104 | /* reschedule to thread context - disconnect won't | ||
105 | * run from atomic context | ||
106 | */ | ||
107 | schedule_work(&wil->disconnect_worker); | ||
108 | } | ||
109 | |||
110 | int wil_priv_init(struct wil6210_priv *wil) | ||
111 | { | ||
112 | wil_dbg(wil, "%s()\n", __func__); | ||
113 | |||
114 | mutex_init(&wil->mutex); | ||
115 | mutex_init(&wil->wmi_mutex); | ||
116 | |||
117 | init_completion(&wil->wmi_ready); | ||
118 | |||
119 | wil->pending_connect_cid = -1; | ||
120 | setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil); | ||
121 | |||
122 | INIT_WORK(&wil->wmi_connect_worker, wmi_connect_worker); | ||
123 | INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker); | ||
124 | INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); | ||
125 | |||
126 | INIT_LIST_HEAD(&wil->pending_wmi_ev); | ||
127 | spin_lock_init(&wil->wmi_ev_lock); | ||
128 | |||
129 | wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi"); | ||
130 | if (!wil->wmi_wq) | ||
131 | return -EAGAIN; | ||
132 | |||
133 | wil->wmi_wq_conn = create_singlethread_workqueue(WIL_NAME"_connect"); | ||
134 | if (!wil->wmi_wq_conn) { | ||
135 | destroy_workqueue(wil->wmi_wq); | ||
136 | return -EAGAIN; | ||
137 | } | ||
138 | |||
139 | /* make shadow copy of registers that should not change on run time */ | ||
140 | wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX, | ||
141 | sizeof(struct wil6210_mbox_ctl)); | ||
142 | wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx); | ||
143 | wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | void wil6210_disconnect(struct wil6210_priv *wil, void *bssid) | ||
149 | { | ||
150 | del_timer_sync(&wil->connect_timer); | ||
151 | _wil6210_disconnect(wil, bssid); | ||
152 | } | ||
153 | |||
154 | void wil_priv_deinit(struct wil6210_priv *wil) | ||
155 | { | ||
156 | cancel_work_sync(&wil->disconnect_worker); | ||
157 | wil6210_disconnect(wil, NULL); | ||
158 | wmi_event_flush(wil); | ||
159 | destroy_workqueue(wil->wmi_wq_conn); | ||
160 | destroy_workqueue(wil->wmi_wq); | ||
161 | } | ||
162 | |||
163 | static void wil_target_reset(struct wil6210_priv *wil) | ||
164 | { | ||
165 | wil_dbg(wil, "Resetting...\n"); | ||
166 | |||
167 | /* register write */ | ||
168 | #define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a)) | ||
169 | /* register set = read, OR, write */ | ||
170 | #define S(a, v) iowrite32(ioread32(wil->csr + HOSTADDR(a)) | v, \ | ||
171 | wil->csr + HOSTADDR(a)) | ||
172 | |||
173 | /* hpal_perst_from_pad_src_n_mask */ | ||
174 | S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6)); | ||
175 | /* car_perst_rst_src_n_mask */ | ||
176 | S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7)); | ||
177 | |||
178 | W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */ | ||
179 | W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */ | ||
180 | |||
181 | msleep(100); | ||
182 | |||
183 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); | ||
184 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); | ||
185 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170); | ||
186 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00); | ||
187 | |||
188 | msleep(100); | ||
189 | |||
190 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); | ||
191 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); | ||
192 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); | ||
193 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); | ||
194 | |||
195 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); | ||
196 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); | ||
197 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); | ||
198 | |||
199 | msleep(2000); | ||
200 | |||
201 | W(RGF_USER_USER_CPU_0, BIT(0)); /* user_cpu_man_de_rst */ | ||
202 | |||
203 | msleep(2000); | ||
204 | |||
205 | wil_dbg(wil, "Reset completed\n"); | ||
206 | |||
207 | #undef W | ||
208 | #undef S | ||
209 | } | ||
210 | |||
211 | void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) | ||
212 | { | ||
213 | le32_to_cpus(&r->base); | ||
214 | le16_to_cpus(&r->entry_size); | ||
215 | le16_to_cpus(&r->size); | ||
216 | le32_to_cpus(&r->tail); | ||
217 | le32_to_cpus(&r->head); | ||
218 | } | ||
219 | |||
220 | static int wil_wait_for_fw_ready(struct wil6210_priv *wil) | ||
221 | { | ||
222 | ulong to = msecs_to_jiffies(1000); | ||
223 | ulong left = wait_for_completion_timeout(&wil->wmi_ready, to); | ||
224 | if (0 == left) { | ||
225 | wil_err(wil, "Firmware not ready\n"); | ||
226 | return -ETIME; | ||
227 | } else { | ||
228 | wil_dbg(wil, "FW ready after %d ms\n", | ||
229 | jiffies_to_msecs(to-left)); | ||
230 | } | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * We reset all the structures, and we reset the UMAC. | ||
236 | * After calling this routine, you're expected to reload | ||
237 | * the firmware. | ||
238 | */ | ||
239 | int wil_reset(struct wil6210_priv *wil) | ||
240 | { | ||
241 | int rc; | ||
242 | |||
243 | cancel_work_sync(&wil->disconnect_worker); | ||
244 | wil6210_disconnect(wil, NULL); | ||
245 | |||
246 | wmi_event_flush(wil); | ||
247 | |||
248 | flush_workqueue(wil->wmi_wq); | ||
249 | flush_workqueue(wil->wmi_wq_conn); | ||
250 | |||
251 | wil6210_disable_irq(wil); | ||
252 | wil->status = 0; | ||
253 | |||
254 | /* TODO: put MAC in reset */ | ||
255 | wil_target_reset(wil); | ||
256 | |||
257 | /* init after reset */ | ||
258 | wil->pending_connect_cid = -1; | ||
259 | INIT_COMPLETION(wil->wmi_ready); | ||
260 | |||
261 | /* make shadow copy of registers that should not change on run time */ | ||
262 | wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX, | ||
263 | sizeof(struct wil6210_mbox_ctl)); | ||
264 | wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx); | ||
265 | wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); | ||
266 | |||
267 | /* TODO: release MAC reset */ | ||
268 | wil6210_enable_irq(wil); | ||
269 | |||
270 | /* we just started MAC, wait for FW ready */ | ||
271 | rc = wil_wait_for_fw_ready(wil); | ||
272 | |||
273 | return rc; | ||
274 | } | ||
275 | |||
276 | |||
277 | void wil_link_on(struct wil6210_priv *wil) | ||
278 | { | ||
279 | struct net_device *ndev = wil_to_ndev(wil); | ||
280 | |||
281 | wil_dbg(wil, "%s()\n", __func__); | ||
282 | |||
283 | netif_carrier_on(ndev); | ||
284 | netif_tx_wake_all_queues(ndev); | ||
285 | } | ||
286 | |||
287 | void wil_link_off(struct wil6210_priv *wil) | ||
288 | { | ||
289 | struct net_device *ndev = wil_to_ndev(wil); | ||
290 | |||
291 | wil_dbg(wil, "%s()\n", __func__); | ||
292 | |||
293 | netif_tx_stop_all_queues(ndev); | ||
294 | netif_carrier_off(ndev); | ||
295 | } | ||
296 | |||
297 | static int __wil_up(struct wil6210_priv *wil) | ||
298 | { | ||
299 | struct net_device *ndev = wil_to_ndev(wil); | ||
300 | struct wireless_dev *wdev = wil->wdev; | ||
301 | struct ieee80211_channel *channel = wdev->preset_chandef.chan; | ||
302 | int rc; | ||
303 | int bi; | ||
304 | u16 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); | ||
305 | |||
306 | rc = wil_reset(wil); | ||
307 | if (rc) | ||
308 | return rc; | ||
309 | |||
310 | /* FIXME Firmware works now in PBSS mode(ToDS=0, FromDS=0) */ | ||
311 | wmi_nettype = wil_iftype_nl2wmi(NL80211_IFTYPE_ADHOC); | ||
312 | switch (wdev->iftype) { | ||
313 | case NL80211_IFTYPE_STATION: | ||
314 | wil_dbg(wil, "type: STATION\n"); | ||
315 | bi = 0; | ||
316 | ndev->type = ARPHRD_ETHER; | ||
317 | break; | ||
318 | case NL80211_IFTYPE_AP: | ||
319 | wil_dbg(wil, "type: AP\n"); | ||
320 | bi = 100; | ||
321 | ndev->type = ARPHRD_ETHER; | ||
322 | break; | ||
323 | case NL80211_IFTYPE_P2P_CLIENT: | ||
324 | wil_dbg(wil, "type: P2P_CLIENT\n"); | ||
325 | bi = 0; | ||
326 | ndev->type = ARPHRD_ETHER; | ||
327 | break; | ||
328 | case NL80211_IFTYPE_P2P_GO: | ||
329 | wil_dbg(wil, "type: P2P_GO\n"); | ||
330 | bi = 100; | ||
331 | ndev->type = ARPHRD_ETHER; | ||
332 | break; | ||
333 | case NL80211_IFTYPE_MONITOR: | ||
334 | wil_dbg(wil, "type: Monitor\n"); | ||
335 | bi = 0; | ||
336 | ndev->type = ARPHRD_IEEE80211_RADIOTAP; | ||
337 | /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */ | ||
338 | break; | ||
339 | default: | ||
340 | return -EOPNOTSUPP; | ||
341 | } | ||
342 | |||
343 | /* Apply profile in the following order: */ | ||
344 | /* SSID and channel for the AP */ | ||
345 | switch (wdev->iftype) { | ||
346 | case NL80211_IFTYPE_AP: | ||
347 | case NL80211_IFTYPE_P2P_GO: | ||
348 | if (wdev->ssid_len == 0) { | ||
349 | wil_err(wil, "SSID not set\n"); | ||
350 | return -EINVAL; | ||
351 | } | ||
352 | wmi_set_ssid(wil, wdev->ssid_len, wdev->ssid); | ||
353 | if (channel) | ||
354 | wmi_set_channel(wil, channel->hw_value); | ||
355 | break; | ||
356 | default: | ||
357 | ; | ||
358 | } | ||
359 | |||
360 | /* MAC address - pre-requisite for other commands */ | ||
361 | wmi_set_mac_address(wil, ndev->dev_addr); | ||
362 | |||
363 | /* Set up beaconing if required. */ | ||
364 | rc = wmi_set_bcon(wil, bi, wmi_nettype); | ||
365 | if (rc) | ||
366 | return rc; | ||
367 | |||
368 | /* Rx VRING. After MAC and beacon */ | ||
369 | wil_rx_init(wil); | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | int wil_up(struct wil6210_priv *wil) | ||
375 | { | ||
376 | int rc; | ||
377 | |||
378 | mutex_lock(&wil->mutex); | ||
379 | rc = __wil_up(wil); | ||
380 | mutex_unlock(&wil->mutex); | ||
381 | |||
382 | return rc; | ||
383 | } | ||
384 | |||
385 | static int __wil_down(struct wil6210_priv *wil) | ||
386 | { | ||
387 | if (wil->scan_request) { | ||
388 | cfg80211_scan_done(wil->scan_request, true); | ||
389 | wil->scan_request = NULL; | ||
390 | } | ||
391 | |||
392 | wil6210_disconnect(wil, NULL); | ||
393 | wil_rx_fini(wil); | ||
394 | |||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | int wil_down(struct wil6210_priv *wil) | ||
399 | { | ||
400 | int rc; | ||
401 | |||
402 | mutex_lock(&wil->mutex); | ||
403 | rc = __wil_down(wil); | ||
404 | mutex_unlock(&wil->mutex); | ||
405 | |||
406 | return rc; | ||
407 | } | ||
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c new file mode 100644 index 000000000000..3068b5cb53a7 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/netdev.c | |||
@@ -0,0 +1,157 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/netdevice.h> | ||
19 | #include <linux/etherdevice.h> | ||
20 | #include <linux/slab.h> | ||
21 | |||
22 | #include "wil6210.h" | ||
23 | |||
24 | static int wil_open(struct net_device *ndev) | ||
25 | { | ||
26 | struct wil6210_priv *wil = ndev_to_wil(ndev); | ||
27 | |||
28 | return wil_up(wil); | ||
29 | } | ||
30 | |||
31 | static int wil_stop(struct net_device *ndev) | ||
32 | { | ||
33 | struct wil6210_priv *wil = ndev_to_wil(ndev); | ||
34 | |||
35 | return wil_down(wil); | ||
36 | } | ||
37 | |||
38 | /* | ||
39 | * AC to queue mapping | ||
40 | * | ||
41 | * AC_VO -> queue 3 | ||
42 | * AC_VI -> queue 2 | ||
43 | * AC_BE -> queue 1 | ||
44 | * AC_BK -> queue 0 | ||
45 | */ | ||
46 | static u16 wil_select_queue(struct net_device *ndev, struct sk_buff *skb) | ||
47 | { | ||
48 | static const u16 wil_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; | ||
49 | struct wil6210_priv *wil = ndev_to_wil(ndev); | ||
50 | u16 rc; | ||
51 | |||
52 | skb->priority = cfg80211_classify8021d(skb); | ||
53 | |||
54 | rc = wil_1d_to_queue[skb->priority]; | ||
55 | |||
56 | wil_dbg_TXRX(wil, "%s() %d -> %d\n", __func__, (int)skb->priority, | ||
57 | (int)rc); | ||
58 | |||
59 | return rc; | ||
60 | } | ||
61 | |||
62 | static const struct net_device_ops wil_netdev_ops = { | ||
63 | .ndo_open = wil_open, | ||
64 | .ndo_stop = wil_stop, | ||
65 | .ndo_start_xmit = wil_start_xmit, | ||
66 | .ndo_select_queue = wil_select_queue, | ||
67 | .ndo_set_mac_address = eth_mac_addr, | ||
68 | .ndo_validate_addr = eth_validate_addr, | ||
69 | }; | ||
70 | |||
71 | void *wil_if_alloc(struct device *dev, void __iomem *csr) | ||
72 | { | ||
73 | struct net_device *ndev; | ||
74 | struct wireless_dev *wdev; | ||
75 | struct wil6210_priv *wil; | ||
76 | struct ieee80211_channel *ch; | ||
77 | int rc = 0; | ||
78 | |||
79 | wdev = wil_cfg80211_init(dev); | ||
80 | if (IS_ERR(wdev)) { | ||
81 | dev_err(dev, "wil_cfg80211_init failed\n"); | ||
82 | return wdev; | ||
83 | } | ||
84 | |||
85 | wil = wdev_to_wil(wdev); | ||
86 | wil->csr = csr; | ||
87 | wil->wdev = wdev; | ||
88 | |||
89 | rc = wil_priv_init(wil); | ||
90 | if (rc) { | ||
91 | dev_err(dev, "wil_priv_init failed\n"); | ||
92 | goto out_wdev; | ||
93 | } | ||
94 | |||
95 | wdev->iftype = NL80211_IFTYPE_STATION; /* TODO */ | ||
96 | /* default monitor channel */ | ||
97 | ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels; | ||
98 | cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT); | ||
99 | |||
100 | ndev = alloc_netdev_mqs(0, "wlan%d", ether_setup, WIL6210_TX_QUEUES, 1); | ||
101 | if (!ndev) { | ||
102 | dev_err(dev, "alloc_netdev_mqs failed\n"); | ||
103 | rc = -ENOMEM; | ||
104 | goto out_priv; | ||
105 | } | ||
106 | |||
107 | ndev->netdev_ops = &wil_netdev_ops; | ||
108 | ndev->ieee80211_ptr = wdev; | ||
109 | SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); | ||
110 | wdev->netdev = ndev; | ||
111 | |||
112 | wil_link_off(wil); | ||
113 | |||
114 | return wil; | ||
115 | |||
116 | out_priv: | ||
117 | wil_priv_deinit(wil); | ||
118 | |||
119 | out_wdev: | ||
120 | wil_wdev_free(wil); | ||
121 | |||
122 | return ERR_PTR(rc); | ||
123 | } | ||
124 | |||
125 | void wil_if_free(struct wil6210_priv *wil) | ||
126 | { | ||
127 | struct net_device *ndev = wil_to_ndev(wil); | ||
128 | if (!ndev) | ||
129 | return; | ||
130 | |||
131 | free_netdev(ndev); | ||
132 | wil_priv_deinit(wil); | ||
133 | wil_wdev_free(wil); | ||
134 | } | ||
135 | |||
136 | int wil_if_add(struct wil6210_priv *wil) | ||
137 | { | ||
138 | struct net_device *ndev = wil_to_ndev(wil); | ||
139 | int rc; | ||
140 | |||
141 | rc = register_netdev(ndev); | ||
142 | if (rc < 0) { | ||
143 | dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc); | ||
144 | return rc; | ||
145 | } | ||
146 | |||
147 | wil_link_off(wil); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | void wil_if_remove(struct wil6210_priv *wil) | ||
153 | { | ||
154 | struct net_device *ndev = wil_to_ndev(wil); | ||
155 | |||
156 | unregister_netdev(ndev); | ||
157 | } | ||
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c new file mode 100644 index 000000000000..0fc83edd6bad --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c | |||
@@ -0,0 +1,223 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/netdevice.h> | ||
21 | #include <linux/debugfs.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/moduleparam.h> | ||
24 | |||
25 | #include "wil6210.h" | ||
26 | |||
27 | static int use_msi = 1; | ||
28 | module_param(use_msi, int, S_IRUGO); | ||
29 | MODULE_PARM_DESC(use_msi, | ||
30 | " Use MSI interrupt: " | ||
31 | "0 - don't, 1 - (default) - single, or 3"); | ||
32 | |||
33 | /* Bus ops */ | ||
34 | static int wil_if_pcie_enable(struct wil6210_priv *wil) | ||
35 | { | ||
36 | struct pci_dev *pdev = wil->pdev; | ||
37 | int rc; | ||
38 | |||
39 | pci_set_master(pdev); | ||
40 | |||
41 | /* | ||
42 | * how many MSI interrupts to request? | ||
43 | */ | ||
44 | switch (use_msi) { | ||
45 | case 3: | ||
46 | case 1: | ||
47 | case 0: | ||
48 | break; | ||
49 | default: | ||
50 | wil_err(wil, "Invalid use_msi=%d, default to 1\n", | ||
51 | use_msi); | ||
52 | use_msi = 1; | ||
53 | } | ||
54 | wil->n_msi = use_msi; | ||
55 | if (wil->n_msi) { | ||
56 | wil_dbg(wil, "Setup %d MSI interrupts\n", use_msi); | ||
57 | rc = pci_enable_msi_block(pdev, wil->n_msi); | ||
58 | if (rc && (wil->n_msi == 3)) { | ||
59 | wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); | ||
60 | wil->n_msi = 1; | ||
61 | rc = pci_enable_msi_block(pdev, wil->n_msi); | ||
62 | } | ||
63 | if (rc) { | ||
64 | wil_err(wil, "pci_enable_msi failed, use INTx\n"); | ||
65 | wil->n_msi = 0; | ||
66 | } | ||
67 | } else { | ||
68 | wil_dbg(wil, "MSI interrupts disabled, use INTx\n"); | ||
69 | } | ||
70 | |||
71 | rc = wil6210_init_irq(wil, pdev->irq); | ||
72 | if (rc) | ||
73 | goto stop_master; | ||
74 | |||
75 | /* need reset here to obtain MAC */ | ||
76 | rc = wil_reset(wil); | ||
77 | if (rc) | ||
78 | goto release_irq; | ||
79 | |||
80 | return 0; | ||
81 | |||
82 | release_irq: | ||
83 | wil6210_fini_irq(wil, pdev->irq); | ||
84 | /* safe to call if no MSI */ | ||
85 | pci_disable_msi(pdev); | ||
86 | stop_master: | ||
87 | pci_clear_master(pdev); | ||
88 | return rc; | ||
89 | } | ||
90 | |||
91 | static int wil_if_pcie_disable(struct wil6210_priv *wil) | ||
92 | { | ||
93 | struct pci_dev *pdev = wil->pdev; | ||
94 | |||
95 | pci_clear_master(pdev); | ||
96 | /* disable and release IRQ */ | ||
97 | wil6210_fini_irq(wil, pdev->irq); | ||
98 | /* safe to call if no MSI */ | ||
99 | pci_disable_msi(pdev); | ||
100 | /* TODO: disable HW */ | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||
106 | { | ||
107 | struct wil6210_priv *wil; | ||
108 | struct device *dev = &pdev->dev; | ||
109 | void __iomem *csr; | ||
110 | int rc; | ||
111 | |||
112 | /* check HW */ | ||
113 | dev_info(&pdev->dev, WIL_NAME " device found [%04x:%04x] (rev %x)\n", | ||
114 | (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); | ||
115 | |||
116 | if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) { | ||
117 | dev_err(&pdev->dev, "Not " WIL_NAME "? " | ||
118 | "BAR0 size is %lu while expecting %lu\n", | ||
119 | (ulong)pci_resource_len(pdev, 0), WIL6210_MEM_SIZE); | ||
120 | return -ENODEV; | ||
121 | } | ||
122 | |||
123 | rc = pci_enable_device(pdev); | ||
124 | if (rc) { | ||
125 | dev_err(&pdev->dev, "pci_enable_device failed\n"); | ||
126 | return -ENODEV; | ||
127 | } | ||
128 | /* rollback to err_disable_pdev */ | ||
129 | |||
130 | rc = pci_request_region(pdev, 0, WIL_NAME); | ||
131 | if (rc) { | ||
132 | dev_err(&pdev->dev, "pci_request_region failed\n"); | ||
133 | goto err_disable_pdev; | ||
134 | } | ||
135 | /* rollback to err_release_reg */ | ||
136 | |||
137 | csr = pci_ioremap_bar(pdev, 0); | ||
138 | if (!csr) { | ||
139 | dev_err(&pdev->dev, "pci_ioremap_bar failed\n"); | ||
140 | rc = -ENODEV; | ||
141 | goto err_release_reg; | ||
142 | } | ||
143 | /* rollback to err_iounmap */ | ||
144 | dev_info(&pdev->dev, "CSR at %pR -> %p\n", &pdev->resource[0], csr); | ||
145 | |||
146 | wil = wil_if_alloc(dev, csr); | ||
147 | if (IS_ERR(wil)) { | ||
148 | rc = (int)PTR_ERR(wil); | ||
149 | dev_err(dev, "wil_if_alloc failed: %d\n", rc); | ||
150 | goto err_iounmap; | ||
151 | } | ||
152 | /* rollback to if_free */ | ||
153 | |||
154 | pci_set_drvdata(pdev, wil); | ||
155 | wil->pdev = pdev; | ||
156 | |||
157 | /* FW should raise IRQ when ready */ | ||
158 | rc = wil_if_pcie_enable(wil); | ||
159 | if (rc) { | ||
160 | wil_err(wil, "Enable device failed\n"); | ||
161 | goto if_free; | ||
162 | } | ||
163 | /* rollback to bus_disable */ | ||
164 | |||
165 | rc = wil_if_add(wil); | ||
166 | if (rc) { | ||
167 | wil_err(wil, "wil_if_add failed: %d\n", rc); | ||
168 | goto bus_disable; | ||
169 | } | ||
170 | |||
171 | wil6210_debugfs_init(wil); | ||
172 | |||
173 | /* check FW is alive */ | ||
174 | wmi_echo(wil); | ||
175 | |||
176 | return 0; | ||
177 | |||
178 | bus_disable: | ||
179 | wil_if_pcie_disable(wil); | ||
180 | if_free: | ||
181 | wil_if_free(wil); | ||
182 | err_iounmap: | ||
183 | pci_iounmap(pdev, csr); | ||
184 | err_release_reg: | ||
185 | pci_release_region(pdev, 0); | ||
186 | err_disable_pdev: | ||
187 | pci_disable_device(pdev); | ||
188 | |||
189 | return rc; | ||
190 | } | ||
191 | |||
192 | static void wil_pcie_remove(struct pci_dev *pdev) | ||
193 | { | ||
194 | struct wil6210_priv *wil = pci_get_drvdata(pdev); | ||
195 | |||
196 | wil6210_debugfs_remove(wil); | ||
197 | wil_if_pcie_disable(wil); | ||
198 | wil_if_remove(wil); | ||
199 | wil_if_free(wil); | ||
200 | pci_iounmap(pdev, wil->csr); | ||
201 | pci_release_region(pdev, 0); | ||
202 | pci_disable_device(pdev); | ||
203 | pci_set_drvdata(pdev, NULL); | ||
204 | } | ||
205 | |||
206 | static DEFINE_PCI_DEVICE_TABLE(wil6210_pcie_ids) = { | ||
207 | { PCI_DEVICE(0x1ae9, 0x0301) }, | ||
208 | { /* end: all zeroes */ }, | ||
209 | }; | ||
210 | MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); | ||
211 | |||
212 | static struct pci_driver wil6210_driver = { | ||
213 | .probe = wil_pcie_probe, | ||
214 | .remove = wil_pcie_remove, | ||
215 | .id_table = wil6210_pcie_ids, | ||
216 | .name = WIL_NAME, | ||
217 | }; | ||
218 | |||
219 | module_pci_driver(wil6210_driver); | ||
220 | |||
221 | MODULE_LICENSE("Dual BSD/GPL"); | ||
222 | MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>"); | ||
223 | MODULE_DESCRIPTION("Driver for 60g WiFi WIL6210 card"); | ||
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c new file mode 100644 index 000000000000..f29c294413cf --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/txrx.c | |||
@@ -0,0 +1,871 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/netdevice.h> | ||
19 | #include <linux/etherdevice.h> | ||
20 | #include <linux/hardirq.h> | ||
21 | #include <net/ieee80211_radiotap.h> | ||
22 | #include <linux/if_arp.h> | ||
23 | #include <linux/moduleparam.h> | ||
24 | |||
25 | #include "wil6210.h" | ||
26 | #include "wmi.h" | ||
27 | #include "txrx.h" | ||
28 | |||
29 | static bool rtap_include_phy_info; | ||
30 | module_param(rtap_include_phy_info, bool, S_IRUGO); | ||
31 | MODULE_PARM_DESC(rtap_include_phy_info, | ||
32 | " Include PHY info in the radiotap header, default - no"); | ||
33 | |||
34 | static inline int wil_vring_is_empty(struct vring *vring) | ||
35 | { | ||
36 | return vring->swhead == vring->swtail; | ||
37 | } | ||
38 | |||
39 | static inline u32 wil_vring_next_tail(struct vring *vring) | ||
40 | { | ||
41 | return (vring->swtail + 1) % vring->size; | ||
42 | } | ||
43 | |||
44 | static inline void wil_vring_advance_head(struct vring *vring, int n) | ||
45 | { | ||
46 | vring->swhead = (vring->swhead + n) % vring->size; | ||
47 | } | ||
48 | |||
49 | static inline int wil_vring_is_full(struct vring *vring) | ||
50 | { | ||
51 | return wil_vring_next_tail(vring) == vring->swhead; | ||
52 | } | ||
53 | /* | ||
54 | * Available space in Tx Vring | ||
55 | */ | ||
56 | static inline int wil_vring_avail_tx(struct vring *vring) | ||
57 | { | ||
58 | u32 swhead = vring->swhead; | ||
59 | u32 swtail = vring->swtail; | ||
60 | int used = (vring->size + swhead - swtail) % vring->size; | ||
61 | |||
62 | return vring->size - used - 1; | ||
63 | } | ||
64 | |||
65 | static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) | ||
66 | { | ||
67 | struct device *dev = wil_to_dev(wil); | ||
68 | size_t sz = vring->size * sizeof(vring->va[0]); | ||
69 | uint i; | ||
70 | |||
71 | BUILD_BUG_ON(sizeof(vring->va[0]) != 32); | ||
72 | |||
73 | vring->swhead = 0; | ||
74 | vring->swtail = 0; | ||
75 | vring->ctx = kzalloc(vring->size * sizeof(vring->ctx[0]), GFP_KERNEL); | ||
76 | if (!vring->ctx) { | ||
77 | wil_err(wil, "vring_alloc [%d] failed to alloc ctx mem\n", | ||
78 | vring->size); | ||
79 | vring->va = NULL; | ||
80 | return -ENOMEM; | ||
81 | } | ||
82 | /* | ||
83 | * vring->va should be aligned on its size rounded up to power of 2 | ||
84 | * This is granted by the dma_alloc_coherent | ||
85 | */ | ||
86 | vring->va = dma_alloc_coherent(dev, sz, &vring->pa, GFP_KERNEL); | ||
87 | if (!vring->va) { | ||
88 | wil_err(wil, "vring_alloc [%d] failed to alloc DMA mem\n", | ||
89 | vring->size); | ||
90 | kfree(vring->ctx); | ||
91 | vring->ctx = NULL; | ||
92 | return -ENOMEM; | ||
93 | } | ||
94 | /* initially, all descriptors are SW owned | ||
95 | * For Tx and Rx, ownership bit is at the same location, thus | ||
96 | * we can use any | ||
97 | */ | ||
98 | for (i = 0; i < vring->size; i++) { | ||
99 | volatile struct vring_tx_desc *d = &(vring->va[i].tx); | ||
100 | d->dma.status = TX_DMA_STATUS_DU; | ||
101 | } | ||
102 | |||
103 | wil_dbg(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size, | ||
104 | vring->va, (unsigned long long)vring->pa, vring->ctx); | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring, | ||
110 | int tx) | ||
111 | { | ||
112 | struct device *dev = wil_to_dev(wil); | ||
113 | size_t sz = vring->size * sizeof(vring->va[0]); | ||
114 | |||
115 | while (!wil_vring_is_empty(vring)) { | ||
116 | if (tx) { | ||
117 | volatile struct vring_tx_desc *d = | ||
118 | &vring->va[vring->swtail].tx; | ||
119 | dma_addr_t pa = d->dma.addr_low | | ||
120 | ((u64)d->dma.addr_high << 32); | ||
121 | struct sk_buff *skb = vring->ctx[vring->swtail]; | ||
122 | if (skb) { | ||
123 | dma_unmap_single(dev, pa, d->dma.length, | ||
124 | DMA_TO_DEVICE); | ||
125 | dev_kfree_skb_any(skb); | ||
126 | vring->ctx[vring->swtail] = NULL; | ||
127 | } else { | ||
128 | dma_unmap_page(dev, pa, d->dma.length, | ||
129 | DMA_TO_DEVICE); | ||
130 | } | ||
131 | vring->swtail = wil_vring_next_tail(vring); | ||
132 | } else { /* rx */ | ||
133 | volatile struct vring_rx_desc *d = | ||
134 | &vring->va[vring->swtail].rx; | ||
135 | dma_addr_t pa = d->dma.addr_low | | ||
136 | ((u64)d->dma.addr_high << 32); | ||
137 | struct sk_buff *skb = vring->ctx[vring->swhead]; | ||
138 | dma_unmap_single(dev, pa, d->dma.length, | ||
139 | DMA_FROM_DEVICE); | ||
140 | kfree_skb(skb); | ||
141 | wil_vring_advance_head(vring, 1); | ||
142 | } | ||
143 | } | ||
144 | dma_free_coherent(dev, sz, (void *)vring->va, vring->pa); | ||
145 | kfree(vring->ctx); | ||
146 | vring->pa = 0; | ||
147 | vring->va = NULL; | ||
148 | vring->ctx = NULL; | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * Allocate one skb for Rx VRING | ||
153 | * | ||
154 | * Safe to call from IRQ | ||
155 | */ | ||
156 | static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring, | ||
157 | u32 i, int headroom) | ||
158 | { | ||
159 | struct device *dev = wil_to_dev(wil); | ||
160 | unsigned int sz = RX_BUF_LEN; | ||
161 | volatile struct vring_rx_desc *d = &(vring->va[i].rx); | ||
162 | dma_addr_t pa; | ||
163 | |||
164 | /* TODO align */ | ||
165 | struct sk_buff *skb = dev_alloc_skb(sz + headroom); | ||
166 | if (unlikely(!skb)) | ||
167 | return -ENOMEM; | ||
168 | |||
169 | skb_reserve(skb, headroom); | ||
170 | skb_put(skb, sz); | ||
171 | |||
172 | pa = dma_map_single(dev, skb->data, skb->len, DMA_FROM_DEVICE); | ||
173 | if (unlikely(dma_mapping_error(dev, pa))) { | ||
174 | kfree_skb(skb); | ||
175 | return -ENOMEM; | ||
176 | } | ||
177 | |||
178 | d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT; | ||
179 | d->dma.addr_low = lower_32_bits(pa); | ||
180 | d->dma.addr_high = (u16)upper_32_bits(pa); | ||
181 | /* ip_length don't care */ | ||
182 | /* b11 don't care */ | ||
183 | /* error don't care */ | ||
184 | d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */ | ||
185 | d->dma.length = sz; | ||
186 | vring->ctx[i] = skb; | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | /** | ||
192 | * Adds radiotap header | ||
193 | * | ||
194 | * Any error indicated as "Bad FCS" | ||
195 | * | ||
196 | * Vendor data for 04:ce:14-1 (Wilocity-1) consists of: | ||
197 | * - Rx descriptor: 32 bytes | ||
198 | * - Phy info | ||
199 | */ | ||
200 | static void wil_rx_add_radiotap_header(struct wil6210_priv *wil, | ||
201 | struct sk_buff *skb, | ||
202 | volatile struct vring_rx_desc *d) | ||
203 | { | ||
204 | struct wireless_dev *wdev = wil->wdev; | ||
205 | struct wil6210_rtap { | ||
206 | struct ieee80211_radiotap_header rthdr; | ||
207 | /* fields should be in the order of bits in rthdr.it_present */ | ||
208 | /* flags */ | ||
209 | u8 flags; | ||
210 | /* channel */ | ||
211 | __le16 chnl_freq __aligned(2); | ||
212 | __le16 chnl_flags; | ||
213 | /* MCS */ | ||
214 | u8 mcs_present; | ||
215 | u8 mcs_flags; | ||
216 | u8 mcs_index; | ||
217 | } __packed; | ||
218 | struct wil6210_rtap_vendor { | ||
219 | struct wil6210_rtap rtap; | ||
220 | /* vendor */ | ||
221 | u8 vendor_oui[3] __aligned(2); | ||
222 | u8 vendor_ns; | ||
223 | __le16 vendor_skip; | ||
224 | u8 vendor_data[0]; | ||
225 | } __packed; | ||
226 | struct wil6210_rtap_vendor *rtap_vendor; | ||
227 | int rtap_len = sizeof(struct wil6210_rtap); | ||
228 | int phy_length = 0; /* phy info header size, bytes */ | ||
229 | static char phy_data[128]; | ||
230 | struct ieee80211_channel *ch = wdev->preset_chandef.chan; | ||
231 | |||
232 | if (rtap_include_phy_info) { | ||
233 | rtap_len = sizeof(*rtap_vendor) + sizeof(*d); | ||
234 | /* calculate additional length */ | ||
235 | if (d->dma.status & RX_DMA_STATUS_PHY_INFO) { | ||
236 | /** | ||
237 | * PHY info starts from 8-byte boundary | ||
238 | * there are 8-byte lines, last line may be partially | ||
239 | * written (HW bug), thus FW configures for last line | ||
240 | * to be excessive. Driver skips this last line. | ||
241 | */ | ||
242 | int len = min_t(int, 8 + sizeof(phy_data), | ||
243 | wil_rxdesc_phy_length(d)); | ||
244 | if (len > 8) { | ||
245 | void *p = skb_tail_pointer(skb); | ||
246 | void *pa = PTR_ALIGN(p, 8); | ||
247 | if (skb_tailroom(skb) >= len + (pa - p)) { | ||
248 | phy_length = len - 8; | ||
249 | memcpy(phy_data, pa, phy_length); | ||
250 | } | ||
251 | } | ||
252 | } | ||
253 | rtap_len += phy_length; | ||
254 | } | ||
255 | |||
256 | if (skb_headroom(skb) < rtap_len && | ||
257 | pskb_expand_head(skb, rtap_len, 0, GFP_ATOMIC)) { | ||
258 | wil_err(wil, "Unable to expand headrom to %d\n", rtap_len); | ||
259 | return; | ||
260 | } | ||
261 | |||
262 | rtap_vendor = (void *)skb_push(skb, rtap_len); | ||
263 | memset(rtap_vendor, 0, rtap_len); | ||
264 | |||
265 | rtap_vendor->rtap.rthdr.it_version = PKTHDR_RADIOTAP_VERSION; | ||
266 | rtap_vendor->rtap.rthdr.it_len = cpu_to_le16(rtap_len); | ||
267 | rtap_vendor->rtap.rthdr.it_present = cpu_to_le32( | ||
268 | (1 << IEEE80211_RADIOTAP_FLAGS) | | ||
269 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | ||
270 | (1 << IEEE80211_RADIOTAP_MCS)); | ||
271 | if (d->dma.status & RX_DMA_STATUS_ERROR) | ||
272 | rtap_vendor->rtap.flags |= IEEE80211_RADIOTAP_F_BADFCS; | ||
273 | |||
274 | rtap_vendor->rtap.chnl_freq = cpu_to_le16(ch ? ch->center_freq : 58320); | ||
275 | rtap_vendor->rtap.chnl_flags = cpu_to_le16(0); | ||
276 | |||
277 | rtap_vendor->rtap.mcs_present = IEEE80211_RADIOTAP_MCS_HAVE_MCS; | ||
278 | rtap_vendor->rtap.mcs_flags = 0; | ||
279 | rtap_vendor->rtap.mcs_index = wil_rxdesc_mcs(d); | ||
280 | |||
281 | if (rtap_include_phy_info) { | ||
282 | rtap_vendor->rtap.rthdr.it_present |= cpu_to_le32(1 << | ||
283 | IEEE80211_RADIOTAP_VENDOR_NAMESPACE); | ||
284 | /* OUI for Wilocity 04:ce:14 */ | ||
285 | rtap_vendor->vendor_oui[0] = 0x04; | ||
286 | rtap_vendor->vendor_oui[1] = 0xce; | ||
287 | rtap_vendor->vendor_oui[2] = 0x14; | ||
288 | rtap_vendor->vendor_ns = 1; | ||
289 | /* Rx descriptor + PHY data */ | ||
290 | rtap_vendor->vendor_skip = cpu_to_le16(sizeof(*d) + | ||
291 | phy_length); | ||
292 | memcpy(rtap_vendor->vendor_data, (void *)d, sizeof(*d)); | ||
293 | memcpy(rtap_vendor->vendor_data + sizeof(*d), phy_data, | ||
294 | phy_length); | ||
295 | } | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * Fast swap in place between 2 registers | ||
300 | */ | ||
301 | static void wil_swap_u16(u16 *a, u16 *b) | ||
302 | { | ||
303 | *a ^= *b; | ||
304 | *b ^= *a; | ||
305 | *a ^= *b; | ||
306 | } | ||
307 | |||
308 | static void wil_swap_ethaddr(void *data) | ||
309 | { | ||
310 | struct ethhdr *eth = data; | ||
311 | u16 *s = (u16 *)eth->h_source; | ||
312 | u16 *d = (u16 *)eth->h_dest; | ||
313 | |||
314 | wil_swap_u16(s++, d++); | ||
315 | wil_swap_u16(s++, d++); | ||
316 | wil_swap_u16(s, d); | ||
317 | } | ||
318 | |||
319 | /** | ||
320 | * reap 1 frame from @swhead | ||
321 | * | ||
322 | * Safe to call from IRQ | ||
323 | */ | ||
324 | static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, | ||
325 | struct vring *vring) | ||
326 | { | ||
327 | struct device *dev = wil_to_dev(wil); | ||
328 | struct net_device *ndev = wil_to_ndev(wil); | ||
329 | volatile struct vring_rx_desc *d; | ||
330 | struct sk_buff *skb; | ||
331 | dma_addr_t pa; | ||
332 | unsigned int sz = RX_BUF_LEN; | ||
333 | u8 ftype; | ||
334 | u8 ds_bits; | ||
335 | |||
336 | if (wil_vring_is_empty(vring)) | ||
337 | return NULL; | ||
338 | |||
339 | d = &(vring->va[vring->swhead].rx); | ||
340 | if (!(d->dma.status & RX_DMA_STATUS_DU)) { | ||
341 | /* it is not error, we just reached end of Rx done area */ | ||
342 | return NULL; | ||
343 | } | ||
344 | |||
345 | pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32); | ||
346 | skb = vring->ctx[vring->swhead]; | ||
347 | dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE); | ||
348 | skb_trim(skb, d->dma.length); | ||
349 | |||
350 | wil->stats.last_mcs_rx = wil_rxdesc_mcs(d); | ||
351 | |||
352 | /* use radiotap header only if required */ | ||
353 | if (ndev->type == ARPHRD_IEEE80211_RADIOTAP) | ||
354 | wil_rx_add_radiotap_header(wil, skb, d); | ||
355 | |||
356 | wil_dbg_TXRX(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length); | ||
357 | wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_NONE, 32, 4, | ||
358 | (const void *)d, sizeof(*d), false); | ||
359 | |||
360 | wil_vring_advance_head(vring, 1); | ||
361 | |||
362 | /* no extra checks if in sniffer mode */ | ||
363 | if (ndev->type != ARPHRD_ETHER) | ||
364 | return skb; | ||
365 | /* | ||
366 | * Non-data frames may be delivered through Rx DMA channel (ex: BAR) | ||
367 | * Driver should recognize it by frame type, that is found | ||
368 | * in Rx descriptor. If type is not data, it is 802.11 frame as is | ||
369 | */ | ||
370 | ftype = wil_rxdesc_ftype(d) << 2; | ||
371 | if (ftype != IEEE80211_FTYPE_DATA) { | ||
372 | wil_dbg_TXRX(wil, "Non-data frame ftype 0x%08x\n", ftype); | ||
373 | /* TODO: process it */ | ||
374 | kfree_skb(skb); | ||
375 | return NULL; | ||
376 | } | ||
377 | |||
378 | if (skb->len < ETH_HLEN) { | ||
379 | wil_err(wil, "Short frame, len = %d\n", skb->len); | ||
380 | /* TODO: process it (i.e. BAR) */ | ||
381 | kfree_skb(skb); | ||
382 | return NULL; | ||
383 | } | ||
384 | |||
385 | ds_bits = wil_rxdesc_ds_bits(d); | ||
386 | if (ds_bits == 1) { | ||
387 | /* | ||
388 | * HW bug - in ToDS mode, i.e. Rx on AP side, | ||
389 | * addresses get swapped | ||
390 | */ | ||
391 | wil_swap_ethaddr(skb->data); | ||
392 | } | ||
393 | |||
394 | return skb; | ||
395 | } | ||
396 | |||
397 | /** | ||
398 | * allocate and fill up to @count buffers in rx ring | ||
399 | * buffers posted at @swtail | ||
400 | */ | ||
401 | static int wil_rx_refill(struct wil6210_priv *wil, int count) | ||
402 | { | ||
403 | struct net_device *ndev = wil_to_ndev(wil); | ||
404 | struct vring *v = &wil->vring_rx; | ||
405 | u32 next_tail; | ||
406 | int rc = 0; | ||
407 | int headroom = ndev->type == ARPHRD_IEEE80211_RADIOTAP ? | ||
408 | WIL6210_RTAP_SIZE : 0; | ||
409 | |||
410 | for (; next_tail = wil_vring_next_tail(v), | ||
411 | (next_tail != v->swhead) && (count-- > 0); | ||
412 | v->swtail = next_tail) { | ||
413 | rc = wil_vring_alloc_skb(wil, v, v->swtail, headroom); | ||
414 | if (rc) { | ||
415 | wil_err(wil, "Error %d in wil_rx_refill[%d]\n", | ||
416 | rc, v->swtail); | ||
417 | break; | ||
418 | } | ||
419 | } | ||
420 | iowrite32(v->swtail, wil->csr + HOSTADDR(v->hwtail)); | ||
421 | |||
422 | return rc; | ||
423 | } | ||
424 | |||
425 | /* | ||
426 | * Pass Rx packet to the netif. Update statistics. | ||
427 | */ | ||
428 | static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) | ||
429 | { | ||
430 | int rc; | ||
431 | unsigned int len = skb->len; | ||
432 | |||
433 | if (in_interrupt()) | ||
434 | rc = netif_rx(skb); | ||
435 | else | ||
436 | rc = netif_rx_ni(skb); | ||
437 | |||
438 | if (likely(rc == NET_RX_SUCCESS)) { | ||
439 | ndev->stats.rx_packets++; | ||
440 | ndev->stats.rx_bytes += len; | ||
441 | |||
442 | } else { | ||
443 | ndev->stats.rx_dropped++; | ||
444 | } | ||
445 | } | ||
446 | |||
447 | /** | ||
448 | * Proceed all completed skb's from Rx VRING | ||
449 | * | ||
450 | * Safe to call from IRQ | ||
451 | */ | ||
452 | void wil_rx_handle(struct wil6210_priv *wil) | ||
453 | { | ||
454 | struct net_device *ndev = wil_to_ndev(wil); | ||
455 | struct vring *v = &wil->vring_rx; | ||
456 | struct sk_buff *skb; | ||
457 | |||
458 | if (!v->va) { | ||
459 | wil_err(wil, "Rx IRQ while Rx not yet initialized\n"); | ||
460 | return; | ||
461 | } | ||
462 | wil_dbg_TXRX(wil, "%s()\n", __func__); | ||
463 | while (NULL != (skb = wil_vring_reap_rx(wil, v))) { | ||
464 | wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_OFFSET, 16, 1, | ||
465 | skb->data, skb_headlen(skb), false); | ||
466 | |||
467 | skb_orphan(skb); | ||
468 | |||
469 | if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { | ||
470 | skb->dev = ndev; | ||
471 | skb_reset_mac_header(skb); | ||
472 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
473 | skb->pkt_type = PACKET_OTHERHOST; | ||
474 | skb->protocol = htons(ETH_P_802_2); | ||
475 | |||
476 | } else { | ||
477 | skb->protocol = eth_type_trans(skb, ndev); | ||
478 | } | ||
479 | |||
480 | wil_netif_rx_any(skb, ndev); | ||
481 | } | ||
482 | wil_rx_refill(wil, v->size); | ||
483 | } | ||
484 | |||
485 | int wil_rx_init(struct wil6210_priv *wil) | ||
486 | { | ||
487 | struct net_device *ndev = wil_to_ndev(wil); | ||
488 | struct wireless_dev *wdev = wil->wdev; | ||
489 | struct vring *vring = &wil->vring_rx; | ||
490 | int rc; | ||
491 | struct wmi_cfg_rx_chain_cmd cmd = { | ||
492 | .action = WMI_RX_CHAIN_ADD, | ||
493 | .rx_sw_ring = { | ||
494 | .max_mpdu_size = cpu_to_le16(RX_BUF_LEN), | ||
495 | }, | ||
496 | .mid = 0, /* TODO - what is it? */ | ||
497 | .decap_trans_type = WMI_DECAP_TYPE_802_3, | ||
498 | }; | ||
499 | struct { | ||
500 | struct wil6210_mbox_hdr_wmi wmi; | ||
501 | struct wmi_cfg_rx_chain_done_event evt; | ||
502 | } __packed evt; | ||
503 | |||
504 | vring->size = WIL6210_RX_RING_SIZE; | ||
505 | rc = wil_vring_alloc(wil, vring); | ||
506 | if (rc) | ||
507 | return rc; | ||
508 | |||
509 | cmd.rx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); | ||
510 | cmd.rx_sw_ring.ring_size = cpu_to_le16(vring->size); | ||
511 | if (wdev->iftype == NL80211_IFTYPE_MONITOR) { | ||
512 | struct ieee80211_channel *ch = wdev->preset_chandef.chan; | ||
513 | |||
514 | cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON); | ||
515 | if (ch) | ||
516 | cmd.sniffer_cfg.channel = ch->hw_value - 1; | ||
517 | cmd.sniffer_cfg.phy_info_mode = | ||
518 | cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP); | ||
519 | cmd.sniffer_cfg.phy_support = | ||
520 | cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL) | ||
521 | ? WMI_SNIFFER_CP : WMI_SNIFFER_DP); | ||
522 | } | ||
523 | /* typical time for secure PCP is 840ms */ | ||
524 | rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd), | ||
525 | WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000); | ||
526 | if (rc) | ||
527 | goto err_free; | ||
528 | |||
529 | vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr); | ||
530 | |||
531 | wil_dbg(wil, "Rx init: status %d tail 0x%08x\n", | ||
532 | le32_to_cpu(evt.evt.status), vring->hwtail); | ||
533 | |||
534 | rc = wil_rx_refill(wil, vring->size); | ||
535 | if (rc) | ||
536 | goto err_free; | ||
537 | |||
538 | return 0; | ||
539 | err_free: | ||
540 | wil_vring_free(wil, vring, 0); | ||
541 | |||
542 | return rc; | ||
543 | } | ||
544 | |||
545 | void wil_rx_fini(struct wil6210_priv *wil) | ||
546 | { | ||
547 | struct vring *vring = &wil->vring_rx; | ||
548 | |||
549 | if (vring->va) { | ||
550 | int rc; | ||
551 | struct wmi_cfg_rx_chain_cmd cmd = { | ||
552 | .action = cpu_to_le32(WMI_RX_CHAIN_DEL), | ||
553 | .rx_sw_ring = { | ||
554 | .max_mpdu_size = cpu_to_le16(RX_BUF_LEN), | ||
555 | }, | ||
556 | }; | ||
557 | struct { | ||
558 | struct wil6210_mbox_hdr_wmi wmi; | ||
559 | struct wmi_cfg_rx_chain_done_event cfg; | ||
560 | } __packed wmi_rx_cfg_reply; | ||
561 | |||
562 | rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd), | ||
563 | WMI_CFG_RX_CHAIN_DONE_EVENTID, | ||
564 | &wmi_rx_cfg_reply, sizeof(wmi_rx_cfg_reply), | ||
565 | 100); | ||
566 | wil_vring_free(wil, vring, 0); | ||
567 | } | ||
568 | } | ||
569 | |||
570 | int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, | ||
571 | int cid, int tid) | ||
572 | { | ||
573 | int rc; | ||
574 | struct wmi_vring_cfg_cmd cmd = { | ||
575 | .action = cpu_to_le32(WMI_VRING_CMD_ADD), | ||
576 | .vring_cfg = { | ||
577 | .tx_sw_ring = { | ||
578 | .max_mpdu_size = cpu_to_le16(TX_BUF_LEN), | ||
579 | }, | ||
580 | .ringid = id, | ||
581 | .cidxtid = (cid & 0xf) | ((tid & 0xf) << 4), | ||
582 | .encap_trans_type = WMI_VRING_ENC_TYPE_802_3, | ||
583 | .mac_ctrl = 0, | ||
584 | .to_resolution = 0, | ||
585 | .agg_max_wsize = 16, | ||
586 | .schd_params = { | ||
587 | .priority = cpu_to_le16(0), | ||
588 | .timeslot_us = cpu_to_le16(0xfff), | ||
589 | }, | ||
590 | }, | ||
591 | }; | ||
592 | struct { | ||
593 | struct wil6210_mbox_hdr_wmi wmi; | ||
594 | struct wmi_vring_cfg_done_event cmd; | ||
595 | } __packed reply; | ||
596 | struct vring *vring = &wil->vring_tx[id]; | ||
597 | |||
598 | if (vring->va) { | ||
599 | wil_err(wil, "Tx ring [%d] already allocated\n", id); | ||
600 | rc = -EINVAL; | ||
601 | goto out; | ||
602 | } | ||
603 | |||
604 | vring->size = size; | ||
605 | rc = wil_vring_alloc(wil, vring); | ||
606 | if (rc) | ||
607 | goto out; | ||
608 | |||
609 | cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); | ||
610 | cmd.vring_cfg.tx_sw_ring.ring_size = cpu_to_le16(vring->size); | ||
611 | |||
612 | rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd), | ||
613 | WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100); | ||
614 | if (rc) | ||
615 | goto out_free; | ||
616 | |||
617 | if (reply.cmd.status != WMI_VRING_CFG_SUCCESS) { | ||
618 | wil_err(wil, "Tx config failed, status 0x%02x\n", | ||
619 | reply.cmd.status); | ||
620 | goto out_free; | ||
621 | } | ||
622 | vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); | ||
623 | |||
624 | return 0; | ||
625 | out_free: | ||
626 | wil_vring_free(wil, vring, 1); | ||
627 | out: | ||
628 | |||
629 | return rc; | ||
630 | } | ||
631 | |||
632 | void wil_vring_fini_tx(struct wil6210_priv *wil, int id) | ||
633 | { | ||
634 | struct vring *vring = &wil->vring_tx[id]; | ||
635 | |||
636 | if (!vring->va) | ||
637 | return; | ||
638 | |||
639 | wil_vring_free(wil, vring, 1); | ||
640 | } | ||
641 | |||
642 | static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, | ||
643 | struct sk_buff *skb) | ||
644 | { | ||
645 | struct vring *v = &wil->vring_tx[0]; | ||
646 | |||
647 | if (v->va) | ||
648 | return v; | ||
649 | |||
650 | return NULL; | ||
651 | } | ||
652 | |||
653 | static int wil_tx_desc_map(volatile struct vring_tx_desc *d, | ||
654 | dma_addr_t pa, u32 len) | ||
655 | { | ||
656 | d->dma.addr_low = lower_32_bits(pa); | ||
657 | d->dma.addr_high = (u16)upper_32_bits(pa); | ||
658 | d->dma.ip_length = 0; | ||
659 | /* 0..6: mac_length; 7:ip_version 0-IP6 1-IP4*/ | ||
660 | d->dma.b11 = 0/*14 | BIT(7)*/; | ||
661 | d->dma.error = 0; | ||
662 | d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */ | ||
663 | d->dma.length = len; | ||
664 | d->dma.d0 = 0; | ||
665 | d->mac.d[0] = 0; | ||
666 | d->mac.d[1] = 0; | ||
667 | d->mac.d[2] = 0; | ||
668 | d->mac.ucode_cmd = 0; | ||
669 | /* use dst index 0 */ | ||
670 | d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS) | | ||
671 | (0 << MAC_CFG_DESC_TX_1_DST_INDEX_POS); | ||
672 | /* translation type: 0 - bypass; 1 - 802.3; 2 - native wifi */ | ||
673 | d->mac.d[2] = BIT(MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS) | | ||
674 | (1 << MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS); | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | ||
680 | struct sk_buff *skb) | ||
681 | { | ||
682 | struct device *dev = wil_to_dev(wil); | ||
683 | volatile struct vring_tx_desc *d; | ||
684 | u32 swhead = vring->swhead; | ||
685 | int avail = wil_vring_avail_tx(vring); | ||
686 | int nr_frags = skb_shinfo(skb)->nr_frags; | ||
687 | uint f; | ||
688 | int vring_index = vring - wil->vring_tx; | ||
689 | uint i = swhead; | ||
690 | dma_addr_t pa; | ||
691 | |||
692 | wil_dbg_TXRX(wil, "%s()\n", __func__); | ||
693 | |||
694 | if (avail < vring->size/8) | ||
695 | netif_tx_stop_all_queues(wil_to_ndev(wil)); | ||
696 | if (avail < 1 + nr_frags) { | ||
697 | wil_err(wil, "Tx ring full. No space for %d fragments\n", | ||
698 | 1 + nr_frags); | ||
699 | return -ENOMEM; | ||
700 | } | ||
701 | d = &(vring->va[i].tx); | ||
702 | |||
703 | /* FIXME FW can accept only unicast frames for the peer */ | ||
704 | memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN); | ||
705 | |||
706 | pa = dma_map_single(dev, skb->data, | ||
707 | skb_headlen(skb), DMA_TO_DEVICE); | ||
708 | |||
709 | wil_dbg_TXRX(wil, "Tx skb %d bytes %p -> %#08llx\n", skb_headlen(skb), | ||
710 | skb->data, (unsigned long long)pa); | ||
711 | wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_OFFSET, 16, 1, | ||
712 | skb->data, skb_headlen(skb), false); | ||
713 | |||
714 | if (unlikely(dma_mapping_error(dev, pa))) | ||
715 | return -EINVAL; | ||
716 | /* 1-st segment */ | ||
717 | wil_tx_desc_map(d, pa, skb_headlen(skb)); | ||
718 | d->mac.d[2] |= ((nr_frags + 1) << | ||
719 | MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS); | ||
720 | /* middle segments */ | ||
721 | for (f = 0; f < nr_frags; f++) { | ||
722 | const struct skb_frag_struct *frag = | ||
723 | &skb_shinfo(skb)->frags[f]; | ||
724 | int len = skb_frag_size(frag); | ||
725 | i = (swhead + f + 1) % vring->size; | ||
726 | d = &(vring->va[i].tx); | ||
727 | pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag), | ||
728 | DMA_TO_DEVICE); | ||
729 | if (unlikely(dma_mapping_error(dev, pa))) | ||
730 | goto dma_error; | ||
731 | wil_tx_desc_map(d, pa, len); | ||
732 | vring->ctx[i] = NULL; | ||
733 | } | ||
734 | /* for the last seg only */ | ||
735 | d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS); | ||
736 | d->dma.d0 |= BIT(9); /* BUG: undocumented bit */ | ||
737 | d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); | ||
738 | d->dma.d0 |= (vring_index << DMA_CFG_DESC_TX_0_QID_POS); | ||
739 | |||
740 | wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_NONE, 32, 4, | ||
741 | (const void *)d, sizeof(*d), false); | ||
742 | |||
743 | /* advance swhead */ | ||
744 | wil_vring_advance_head(vring, nr_frags + 1); | ||
745 | wil_dbg_TXRX(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); | ||
746 | iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); | ||
747 | /* hold reference to skb | ||
748 | * to prevent skb release before accounting | ||
749 | * in case of immediate "tx done" | ||
750 | */ | ||
751 | vring->ctx[i] = skb_get(skb); | ||
752 | |||
753 | return 0; | ||
754 | dma_error: | ||
755 | /* unmap what we have mapped */ | ||
756 | /* Note: increment @f to operate with positive index */ | ||
757 | for (f++; f > 0; f--) { | ||
758 | i = (swhead + f) % vring->size; | ||
759 | d = &(vring->va[i].tx); | ||
760 | d->dma.status = TX_DMA_STATUS_DU; | ||
761 | pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32); | ||
762 | if (vring->ctx[i]) | ||
763 | dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE); | ||
764 | else | ||
765 | dma_unmap_page(dev, pa, d->dma.length, DMA_TO_DEVICE); | ||
766 | } | ||
767 | |||
768 | return -EINVAL; | ||
769 | } | ||
770 | |||
771 | |||
772 | netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) | ||
773 | { | ||
774 | struct wil6210_priv *wil = ndev_to_wil(ndev); | ||
775 | struct vring *vring; | ||
776 | int rc; | ||
777 | |||
778 | wil_dbg_TXRX(wil, "%s()\n", __func__); | ||
779 | if (!test_bit(wil_status_fwready, &wil->status)) { | ||
780 | wil_err(wil, "FW not ready\n"); | ||
781 | goto drop; | ||
782 | } | ||
783 | if (!test_bit(wil_status_fwconnected, &wil->status)) { | ||
784 | wil_err(wil, "FW not connected\n"); | ||
785 | goto drop; | ||
786 | } | ||
787 | if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { | ||
788 | wil_err(wil, "Xmit in monitor mode not supported\n"); | ||
789 | goto drop; | ||
790 | } | ||
791 | if (skb->protocol == cpu_to_be16(ETH_P_PAE)) { | ||
792 | rc = wmi_tx_eapol(wil, skb); | ||
793 | } else { | ||
794 | /* find vring */ | ||
795 | vring = wil_find_tx_vring(wil, skb); | ||
796 | if (!vring) { | ||
797 | wil_err(wil, "No Tx VRING available\n"); | ||
798 | goto drop; | ||
799 | } | ||
800 | /* set up vring entry */ | ||
801 | rc = wil_tx_vring(wil, vring, skb); | ||
802 | } | ||
803 | switch (rc) { | ||
804 | case 0: | ||
805 | ndev->stats.tx_packets++; | ||
806 | ndev->stats.tx_bytes += skb->len; | ||
807 | dev_kfree_skb_any(skb); | ||
808 | return NETDEV_TX_OK; | ||
809 | case -ENOMEM: | ||
810 | return NETDEV_TX_BUSY; | ||
811 | default: | ||
812 | ; /* goto drop; */ | ||
813 | break; | ||
814 | } | ||
815 | drop: | ||
816 | netif_tx_stop_all_queues(ndev); | ||
817 | ndev->stats.tx_dropped++; | ||
818 | dev_kfree_skb_any(skb); | ||
819 | |||
820 | return NET_XMIT_DROP; | ||
821 | } | ||
822 | |||
823 | /** | ||
824 | * Clean up transmitted skb's from the Tx VRING | ||
825 | * | ||
826 | * Safe to call from IRQ | ||
827 | */ | ||
828 | void wil_tx_complete(struct wil6210_priv *wil, int ringid) | ||
829 | { | ||
830 | struct device *dev = wil_to_dev(wil); | ||
831 | struct vring *vring = &wil->vring_tx[ringid]; | ||
832 | |||
833 | if (!vring->va) { | ||
834 | wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid); | ||
835 | return; | ||
836 | } | ||
837 | |||
838 | wil_dbg_TXRX(wil, "%s(%d)\n", __func__, ringid); | ||
839 | |||
840 | while (!wil_vring_is_empty(vring)) { | ||
841 | volatile struct vring_tx_desc *d = &vring->va[vring->swtail].tx; | ||
842 | dma_addr_t pa; | ||
843 | struct sk_buff *skb; | ||
844 | if (!(d->dma.status & TX_DMA_STATUS_DU)) | ||
845 | break; | ||
846 | |||
847 | wil_dbg_TXRX(wil, | ||
848 | "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", | ||
849 | vring->swtail, d->dma.length, d->dma.status, | ||
850 | d->dma.error); | ||
851 | wil_hex_dump_TXRX("TxC ", DUMP_PREFIX_NONE, 32, 4, | ||
852 | (const void *)d, sizeof(*d), false); | ||
853 | |||
854 | pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32); | ||
855 | skb = vring->ctx[vring->swtail]; | ||
856 | if (skb) { | ||
857 | dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE); | ||
858 | dev_kfree_skb_any(skb); | ||
859 | vring->ctx[vring->swtail] = NULL; | ||
860 | } else { | ||
861 | dma_unmap_page(dev, pa, d->dma.length, DMA_TO_DEVICE); | ||
862 | } | ||
863 | d->dma.addr_low = 0; | ||
864 | d->dma.addr_high = 0; | ||
865 | d->dma.length = 0; | ||
866 | d->dma.status = TX_DMA_STATUS_DU; | ||
867 | vring->swtail = wil_vring_next_tail(vring); | ||
868 | } | ||
869 | if (wil_vring_avail_tx(vring) > vring->size/4) | ||
870 | netif_tx_wake_all_queues(wil_to_ndev(wil)); | ||
871 | } | ||
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h new file mode 100644 index 000000000000..45a61f597c5c --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/txrx.h | |||
@@ -0,0 +1,362 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #ifndef WIL6210_TXRX_H | ||
18 | #define WIL6210_TXRX_H | ||
19 | |||
20 | #define BUF_SW_OWNED (1) | ||
21 | #define BUF_HW_OWNED (0) | ||
22 | |||
23 | /* size of max. Rx packet */ | ||
24 | #define RX_BUF_LEN (2048) | ||
25 | #define TX_BUF_LEN (2048) | ||
26 | /* how many bytes to reserve for rtap header? */ | ||
27 | #define WIL6210_RTAP_SIZE (128) | ||
28 | |||
29 | /* Tx/Rx path */ | ||
30 | /* | ||
31 | * Tx descriptor - MAC part | ||
32 | * [dword 0] | ||
33 | * bit 0.. 9 : lifetime_expiry_value:10 | ||
34 | * bit 10 : interrup_en:1 | ||
35 | * bit 11 : status_en:1 | ||
36 | * bit 12..13 : txss_override:2 | ||
37 | * bit 14 : timestamp_insertion:1 | ||
38 | * bit 15 : duration_preserve:1 | ||
39 | * bit 16..21 : reserved0:6 | ||
40 | * bit 22..26 : mcs_index:5 | ||
41 | * bit 27 : mcs_en:1 | ||
42 | * bit 28..29 : reserved1:2 | ||
43 | * bit 30 : reserved2:1 | ||
44 | * bit 31 : sn_preserved:1 | ||
45 | * [dword 1] | ||
46 | * bit 0.. 3 : pkt_mode:4 | ||
47 | * bit 4 : pkt_mode_en:1 | ||
48 | * bit 5.. 7 : reserved0:3 | ||
49 | * bit 8..13 : reserved1:6 | ||
50 | * bit 14 : reserved2:1 | ||
51 | * bit 15 : ack_policy_en:1 | ||
52 | * bit 16..19 : dst_index:4 | ||
53 | * bit 20 : dst_index_en:1 | ||
54 | * bit 21..22 : ack_policy:2 | ||
55 | * bit 23 : lifetime_en:1 | ||
56 | * bit 24..30 : max_retry:7 | ||
57 | * bit 31 : max_retry_en:1 | ||
58 | * [dword 2] | ||
59 | * bit 0.. 7 : num_of_descriptors:8 | ||
60 | * bit 8..17 : reserved:10 | ||
61 | * bit 18..19 : l2_translation_type:2 | ||
62 | * bit 20 : snap_hdr_insertion_en:1 | ||
63 | * bit 21 : vlan_removal_en:1 | ||
64 | * bit 22..31 : reserved0:10 | ||
65 | * [dword 3] | ||
66 | * bit 0.. 31: ucode_cmd:32 | ||
67 | */ | ||
68 | struct vring_tx_mac { | ||
69 | u32 d[3]; | ||
70 | u32 ucode_cmd; | ||
71 | } __packed; | ||
72 | |||
73 | /* TX MAC Dword 0 */ | ||
74 | #define MAC_CFG_DESC_TX_0_LIFETIME_EXPIRY_VALUE_POS 0 | ||
75 | #define MAC_CFG_DESC_TX_0_LIFETIME_EXPIRY_VALUE_LEN 10 | ||
76 | #define MAC_CFG_DESC_TX_0_LIFETIME_EXPIRY_VALUE_MSK 0x3FF | ||
77 | |||
78 | #define MAC_CFG_DESC_TX_0_INTERRUP_EN_POS 10 | ||
79 | #define MAC_CFG_DESC_TX_0_INTERRUP_EN_LEN 1 | ||
80 | #define MAC_CFG_DESC_TX_0_INTERRUP_EN_MSK 0x400 | ||
81 | |||
82 | #define MAC_CFG_DESC_TX_0_STATUS_EN_POS 11 | ||
83 | #define MAC_CFG_DESC_TX_0_STATUS_EN_LEN 1 | ||
84 | #define MAC_CFG_DESC_TX_0_STATUS_EN_MSK 0x800 | ||
85 | |||
86 | #define MAC_CFG_DESC_TX_0_TXSS_OVERRIDE_POS 12 | ||
87 | #define MAC_CFG_DESC_TX_0_TXSS_OVERRIDE_LEN 2 | ||
88 | #define MAC_CFG_DESC_TX_0_TXSS_OVERRIDE_MSK 0x3000 | ||
89 | |||
90 | #define MAC_CFG_DESC_TX_0_TIMESTAMP_INSERTION_POS 14 | ||
91 | #define MAC_CFG_DESC_TX_0_TIMESTAMP_INSERTION_LEN 1 | ||
92 | #define MAC_CFG_DESC_TX_0_TIMESTAMP_INSERTION_MSK 0x4000 | ||
93 | |||
94 | #define MAC_CFG_DESC_TX_0_DURATION_PRESERVE_POS 15 | ||
95 | #define MAC_CFG_DESC_TX_0_DURATION_PRESERVE_LEN 1 | ||
96 | #define MAC_CFG_DESC_TX_0_DURATION_PRESERVE_MSK 0x8000 | ||
97 | |||
98 | #define MAC_CFG_DESC_TX_0_MCS_INDEX_POS 22 | ||
99 | #define MAC_CFG_DESC_TX_0_MCS_INDEX_LEN 5 | ||
100 | #define MAC_CFG_DESC_TX_0_MCS_INDEX_MSK 0x7C00000 | ||
101 | |||
102 | #define MAC_CFG_DESC_TX_0_MCS_EN_POS 27 | ||
103 | #define MAC_CFG_DESC_TX_0_MCS_EN_LEN 1 | ||
104 | #define MAC_CFG_DESC_TX_0_MCS_EN_MSK 0x8000000 | ||
105 | |||
106 | #define MAC_CFG_DESC_TX_0_SN_PRESERVED_POS 31 | ||
107 | #define MAC_CFG_DESC_TX_0_SN_PRESERVED_LEN 1 | ||
108 | #define MAC_CFG_DESC_TX_0_SN_PRESERVED_MSK 0x80000000 | ||
109 | |||
110 | /* TX MAC Dword 1 */ | ||
111 | #define MAC_CFG_DESC_TX_1_PKT_MODE_POS 0 | ||
112 | #define MAC_CFG_DESC_TX_1_PKT_MODE_LEN 4 | ||
113 | #define MAC_CFG_DESC_TX_1_PKT_MODE_MSK 0xF | ||
114 | |||
115 | #define MAC_CFG_DESC_TX_1_PKT_MODE_EN_POS 4 | ||
116 | #define MAC_CFG_DESC_TX_1_PKT_MODE_EN_LEN 1 | ||
117 | #define MAC_CFG_DESC_TX_1_PKT_MODE_EN_MSK 0x10 | ||
118 | |||
119 | #define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_POS 15 | ||
120 | #define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_LEN 1 | ||
121 | #define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_MSK 0x8000 | ||
122 | |||
123 | #define MAC_CFG_DESC_TX_1_DST_INDEX_POS 16 | ||
124 | #define MAC_CFG_DESC_TX_1_DST_INDEX_LEN 4 | ||
125 | #define MAC_CFG_DESC_TX_1_DST_INDEX_MSK 0xF0000 | ||
126 | |||
127 | #define MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS 20 | ||
128 | #define MAC_CFG_DESC_TX_1_DST_INDEX_EN_LEN 1 | ||
129 | #define MAC_CFG_DESC_TX_1_DST_INDEX_EN_MSK 0x100000 | ||
130 | |||
131 | #define MAC_CFG_DESC_TX_1_ACK_POLICY_POS 21 | ||
132 | #define MAC_CFG_DESC_TX_1_ACK_POLICY_LEN 2 | ||
133 | #define MAC_CFG_DESC_TX_1_ACK_POLICY_MSK 0x600000 | ||
134 | |||
135 | #define MAC_CFG_DESC_TX_1_LIFETIME_EN_POS 23 | ||
136 | #define MAC_CFG_DESC_TX_1_LIFETIME_EN_LEN 1 | ||
137 | #define MAC_CFG_DESC_TX_1_LIFETIME_EN_MSK 0x800000 | ||
138 | |||
139 | #define MAC_CFG_DESC_TX_1_MAX_RETRY_POS 24 | ||
140 | #define MAC_CFG_DESC_TX_1_MAX_RETRY_LEN 7 | ||
141 | #define MAC_CFG_DESC_TX_1_MAX_RETRY_MSK 0x7F000000 | ||
142 | |||
143 | #define MAC_CFG_DESC_TX_1_MAX_RETRY_EN_POS 31 | ||
144 | #define MAC_CFG_DESC_TX_1_MAX_RETRY_EN_LEN 1 | ||
145 | #define MAC_CFG_DESC_TX_1_MAX_RETRY_EN_MSK 0x80000000 | ||
146 | |||
147 | /* TX MAC Dword 2 */ | ||
148 | #define MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS 0 | ||
149 | #define MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_LEN 8 | ||
150 | #define MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_MSK 0xFF | ||
151 | |||
152 | #define MAC_CFG_DESC_TX_2_RESERVED_POS 8 | ||
153 | #define MAC_CFG_DESC_TX_2_RESERVED_LEN 10 | ||
154 | #define MAC_CFG_DESC_TX_2_RESERVED_MSK 0x3FF00 | ||
155 | |||
156 | #define MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS 18 | ||
157 | #define MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_LEN 2 | ||
158 | #define MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_MSK 0xC0000 | ||
159 | |||
160 | #define MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS 20 | ||
161 | #define MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_LEN 1 | ||
162 | #define MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_MSK 0x100000 | ||
163 | |||
164 | #define MAC_CFG_DESC_TX_2_VLAN_REMOVAL_EN_POS 21 | ||
165 | #define MAC_CFG_DESC_TX_2_VLAN_REMOVAL_EN_LEN 1 | ||
166 | #define MAC_CFG_DESC_TX_2_VLAN_REMOVAL_EN_MSK 0x200000 | ||
167 | |||
168 | /* TX MAC Dword 3 */ | ||
169 | #define MAC_CFG_DESC_TX_3_UCODE_CMD_POS 0 | ||
170 | #define MAC_CFG_DESC_TX_3_UCODE_CMD_LEN 32 | ||
171 | #define MAC_CFG_DESC_TX_3_UCODE_CMD_MSK 0xFFFFFFFF | ||
172 | |||
173 | /* TX DMA Dword 0 */ | ||
174 | #define DMA_CFG_DESC_TX_0_L4_LENGTH_POS 0 | ||
175 | #define DMA_CFG_DESC_TX_0_L4_LENGTH_LEN 8 | ||
176 | #define DMA_CFG_DESC_TX_0_L4_LENGTH_MSK 0xFF | ||
177 | |||
178 | #define DMA_CFG_DESC_TX_0_CMD_EOP_POS 8 | ||
179 | #define DMA_CFG_DESC_TX_0_CMD_EOP_LEN 1 | ||
180 | #define DMA_CFG_DESC_TX_0_CMD_EOP_MSK 0x100 | ||
181 | |||
182 | #define DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS 10 | ||
183 | #define DMA_CFG_DESC_TX_0_CMD_DMA_IT_LEN 1 | ||
184 | #define DMA_CFG_DESC_TX_0_CMD_DMA_IT_MSK 0x400 | ||
185 | |||
186 | #define DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_POS 11 | ||
187 | #define DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_LEN 2 | ||
188 | #define DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_MSK 0x1800 | ||
189 | |||
190 | #define DMA_CFG_DESC_TX_0_TCP_SEG_EN_POS 13 | ||
191 | #define DMA_CFG_DESC_TX_0_TCP_SEG_EN_LEN 1 | ||
192 | #define DMA_CFG_DESC_TX_0_TCP_SEG_EN_MSK 0x2000 | ||
193 | |||
194 | #define DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_POS 14 | ||
195 | #define DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_LEN 1 | ||
196 | #define DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_MSK 0x4000 | ||
197 | |||
198 | #define DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_POS 15 | ||
199 | #define DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_LEN 1 | ||
200 | #define DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_MSK 0x8000 | ||
201 | |||
202 | #define DMA_CFG_DESC_TX_0_QID_POS 16 | ||
203 | #define DMA_CFG_DESC_TX_0_QID_LEN 5 | ||
204 | #define DMA_CFG_DESC_TX_0_QID_MSK 0x1F0000 | ||
205 | |||
206 | #define DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_POS 21 | ||
207 | #define DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_LEN 1 | ||
208 | #define DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_MSK 0x200000 | ||
209 | |||
210 | #define DMA_CFG_DESC_TX_0_L4_TYPE_POS 30 | ||
211 | #define DMA_CFG_DESC_TX_0_L4_TYPE_LEN 2 | ||
212 | #define DMA_CFG_DESC_TX_0_L4_TYPE_MSK 0xC0000000 | ||
213 | |||
214 | |||
215 | #define TX_DMA_STATUS_DU BIT(0) | ||
216 | |||
217 | struct vring_tx_dma { | ||
218 | u32 d0; | ||
219 | u32 addr_low; | ||
220 | u16 addr_high; | ||
221 | u8 ip_length; | ||
222 | u8 b11; /* 0..6: mac_length; 7:ip_version */ | ||
223 | u8 error; /* 0..2: err; 3..7: reserved; */ | ||
224 | u8 status; /* 0: used; 1..7; reserved */ | ||
225 | u16 length; | ||
226 | } __packed; | ||
227 | |||
228 | /* | ||
229 | * Rx descriptor - MAC part | ||
230 | * [dword 0] | ||
231 | * bit 0.. 3 : tid:4 The QoS (b3-0) TID Field | ||
232 | * bit 4.. 6 : connection_id:3 :The Source index that was found during | ||
233 | * Parsing the TA. This field is used to define the source of the packet | ||
234 | * bit 7 : reserved:1 | ||
235 | * bit 8.. 9 : mac_id:2 : The MAC virtual Ring number (always zero) | ||
236 | * bit 10..11 : frame_type:2 : The FC Control (b3-2) - MPDU Type | ||
237 | * (management, data, control and extension) | ||
238 | * bit 12..15 : frame_subtype:4 : The FC Control (b7-4) - Frame Subtype | ||
239 | * bit 16..27 : seq_number:12 The received Sequence number field | ||
240 | * bit 28..31 : extended:4 extended subtype | ||
241 | * [dword 1] | ||
242 | * bit 0.. 3 : reserved | ||
243 | * bit 4.. 5 : key_id:2 | ||
244 | * bit 6 : decrypt_bypass:1 | ||
245 | * bit 7 : security:1 | ||
246 | * bit 8.. 9 : ds_bits:2 | ||
247 | * bit 10 : a_msdu_present:1 from qos header | ||
248 | * bit 11 : a_msdu_type:1 from qos header | ||
249 | * bit 12 : a_mpdu:1 part of AMPDU aggregation | ||
250 | * bit 13 : broadcast:1 | ||
251 | * bit 14 : mutlicast:1 | ||
252 | * bit 15 : reserved:1 | ||
253 | * bit 16..20 : rx_mac_qid:5 The Queue Identifier that the packet | ||
254 | * is received from | ||
255 | * bit 21..24 : mcs:4 | ||
256 | * bit 25..28 : mic_icr:4 | ||
257 | * bit 29..31 : reserved:3 | ||
258 | * [dword 2] | ||
259 | * bit 0.. 2 : time_slot:3 The timeslot that the MPDU is received | ||
260 | * bit 3 : fc_protocol_ver:1 The FC Control (b0) - Protocol Version | ||
261 | * bit 4 : fc_order:1 The FC Control (b15) -Order | ||
262 | * bit 5.. 7 : qos_ack_policy:3 The QoS (b6-5) ack policy Field | ||
263 | * bit 8 : esop:1 The QoS (b4) ESOP field | ||
264 | * bit 9 : qos_rdg_more_ppdu:1 The QoS (b9) RDG field | ||
265 | * bit 10..14 : qos_reserved:5 The QoS (b14-10) Reserved field | ||
266 | * bit 15 : qos_ac_constraint:1 | ||
267 | * bit 16..31 : pn_15_0:16 low 2 bytes of PN | ||
268 | * [dword 3] | ||
269 | * bit 0..31 : pn_47_16:32 high 4 bytes of PN | ||
270 | */ | ||
271 | struct vring_rx_mac { | ||
272 | u32 d0; | ||
273 | u32 d1; | ||
274 | u16 w4; | ||
275 | u16 pn_15_0; | ||
276 | u32 pn_47_16; | ||
277 | } __packed; | ||
278 | |||
279 | /* | ||
280 | * Rx descriptor - DMA part | ||
281 | * [dword 0] | ||
282 | * bit 0.. 7 : l4_length:8 layer 4 length | ||
283 | * bit 8.. 9 : reserved:2 | ||
284 | * bit 10 : cmd_dma_it:1 | ||
285 | * bit 11..15 : reserved:5 | ||
286 | * bit 16..29 : phy_info_length:14 | ||
287 | * bit 30..31 : l4_type:2 valid if the L4I bit is set in the status field | ||
288 | * [dword 1] | ||
289 | * bit 0..31 : addr_low:32 The payload buffer low address | ||
290 | * [dword 2] | ||
291 | * bit 0..15 : addr_high:16 The payload buffer high address | ||
292 | * bit 16..23 : ip_length:8 | ||
293 | * bit 24..30 : mac_length:7 | ||
294 | * bit 31 : ip_version:1 | ||
295 | * [dword 3] | ||
296 | * [byte 12] error | ||
297 | * [byte 13] status | ||
298 | * bit 0 : du:1 | ||
299 | * bit 1 : eop:1 | ||
300 | * bit 2 : error:1 | ||
301 | * bit 3 : mi:1 | ||
302 | * bit 4 : l3_identified:1 | ||
303 | * bit 5 : l4_identified:1 | ||
304 | * bit 6 : phy_info_included:1 | ||
305 | * bit 7 : reserved:1 | ||
306 | * [word 7] length | ||
307 | * | ||
308 | */ | ||
309 | |||
310 | #define RX_DMA_D0_CMD_DMA_IT BIT(10) | ||
311 | |||
312 | #define RX_DMA_STATUS_DU BIT(0) | ||
313 | #define RX_DMA_STATUS_ERROR BIT(2) | ||
314 | #define RX_DMA_STATUS_PHY_INFO BIT(6) | ||
315 | |||
316 | struct vring_rx_dma { | ||
317 | u32 d0; | ||
318 | u32 addr_low; | ||
319 | u16 addr_high; | ||
320 | u8 ip_length; | ||
321 | u8 b11; | ||
322 | u8 error; | ||
323 | u8 status; | ||
324 | u16 length; | ||
325 | } __packed; | ||
326 | |||
327 | struct vring_tx_desc { | ||
328 | struct vring_tx_mac mac; | ||
329 | struct vring_tx_dma dma; | ||
330 | } __packed; | ||
331 | |||
332 | struct vring_rx_desc { | ||
333 | struct vring_rx_mac mac; | ||
334 | struct vring_rx_dma dma; | ||
335 | } __packed; | ||
336 | |||
337 | union vring_desc { | ||
338 | struct vring_tx_desc tx; | ||
339 | struct vring_rx_desc rx; | ||
340 | } __packed; | ||
341 | |||
342 | static inline int wil_rxdesc_phy_length(volatile struct vring_rx_desc *d) | ||
343 | { | ||
344 | return WIL_GET_BITS(d->dma.d0, 16, 29); | ||
345 | } | ||
346 | |||
347 | static inline int wil_rxdesc_mcs(volatile struct vring_rx_desc *d) | ||
348 | { | ||
349 | return WIL_GET_BITS(d->mac.d1, 21, 24); | ||
350 | } | ||
351 | |||
352 | static inline int wil_rxdesc_ds_bits(volatile struct vring_rx_desc *d) | ||
353 | { | ||
354 | return WIL_GET_BITS(d->mac.d1, 8, 9); | ||
355 | } | ||
356 | |||
357 | static inline int wil_rxdesc_ftype(volatile struct vring_rx_desc *d) | ||
358 | { | ||
359 | return WIL_GET_BITS(d->mac.d0, 10, 11); | ||
360 | } | ||
361 | |||
362 | #endif /* WIL6210_TXRX_H */ | ||
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h new file mode 100644 index 000000000000..9bcfffa4006c --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/wil6210.h | |||
@@ -0,0 +1,363 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #ifndef __WIL6210_H__ | ||
18 | #define __WIL6210_H__ | ||
19 | |||
20 | #include <linux/netdevice.h> | ||
21 | #include <linux/wireless.h> | ||
22 | #include <net/cfg80211.h> | ||
23 | |||
24 | #include "dbg_hexdump.h" | ||
25 | |||
26 | #define WIL_NAME "wil6210" | ||
27 | |||
28 | /** | ||
29 | * extract bits [@b0:@b1] (inclusive) from the value @x | ||
30 | * it should be @b0 <= @b1, or result is incorrect | ||
31 | */ | ||
32 | static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) | ||
33 | { | ||
34 | return (x >> b0) & ((1 << (b1 - b0 + 1)) - 1); | ||
35 | } | ||
36 | |||
37 | #define WIL6210_MEM_SIZE (2*1024*1024UL) | ||
38 | |||
39 | #define WIL6210_TX_QUEUES (4) | ||
40 | |||
41 | #define WIL6210_RX_RING_SIZE (128) | ||
42 | #define WIL6210_TX_RING_SIZE (128) | ||
43 | #define WIL6210_MAX_TX_RINGS (24) | ||
44 | |||
45 | /* Hardware definitions begin */ | ||
46 | |||
47 | /* | ||
48 | * Mapping | ||
49 | * RGF File | Host addr | FW addr | ||
50 | * | | | ||
51 | * user_rgf | 0x000000 | 0x880000 | ||
52 | * dma_rgf | 0x001000 | 0x881000 | ||
53 | * pcie_rgf | 0x002000 | 0x882000 | ||
54 | * | | | ||
55 | */ | ||
56 | |||
57 | /* Where various structures placed in host address space */ | ||
58 | #define WIL6210_FW_HOST_OFF (0x880000UL) | ||
59 | |||
60 | #define HOSTADDR(fwaddr) (fwaddr - WIL6210_FW_HOST_OFF) | ||
61 | |||
62 | /* | ||
63 | * Interrupt control registers block | ||
64 | * | ||
65 | * each interrupt controlled by the same bit in all registers | ||
66 | */ | ||
67 | struct RGF_ICR { | ||
68 | u32 ICC; /* Cause Control, RW: 0 - W1C, 1 - COR */ | ||
69 | u32 ICR; /* Cause, W1C/COR depending on ICC */ | ||
70 | u32 ICM; /* Cause masked (ICR & ~IMV), W1C/COR depending on ICC */ | ||
71 | u32 ICS; /* Cause Set, WO */ | ||
72 | u32 IMV; /* Mask, RW+S/C */ | ||
73 | u32 IMS; /* Mask Set, write 1 to set */ | ||
74 | u32 IMC; /* Mask Clear, write 1 to clear */ | ||
75 | } __packed; | ||
76 | |||
77 | /* registers - FW addresses */ | ||
78 | #define RGF_USER_USER_SCRATCH_PAD (0x8802bc) | ||
79 | #define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */ | ||
80 | #define BIT_USER_USER_ICR_SW_INT_2 BIT(18) | ||
81 | #define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14) | ||
82 | #define RGF_USER_MAC_CPU_0 (0x8801fc) | ||
83 | #define RGF_USER_USER_CPU_0 (0x8801e0) | ||
84 | #define RGF_USER_CLKS_CTL_SW_RST_VEC_0 (0x880b04) | ||
85 | #define RGF_USER_CLKS_CTL_SW_RST_VEC_1 (0x880b08) | ||
86 | #define RGF_USER_CLKS_CTL_SW_RST_VEC_2 (0x880b0c) | ||
87 | #define RGF_USER_CLKS_CTL_SW_RST_VEC_3 (0x880b10) | ||
88 | |||
89 | #define RGF_DMA_PSEUDO_CAUSE (0x881c68) | ||
90 | #define RGF_DMA_PSEUDO_CAUSE_MASK_SW (0x881c6c) | ||
91 | #define RGF_DMA_PSEUDO_CAUSE_MASK_FW (0x881c70) | ||
92 | #define BIT_DMA_PSEUDO_CAUSE_RX BIT(0) | ||
93 | #define BIT_DMA_PSEUDO_CAUSE_TX BIT(1) | ||
94 | #define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2) | ||
95 | |||
96 | #define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */ | ||
97 | #define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0) | ||
98 | #define BIT_DMA_EP_TX_ICR_TX_DONE_N(n) BIT(n+1) /* n = [0..23] */ | ||
99 | #define RGF_DMA_EP_RX_ICR (0x881bd0) /* struct RGF_ICR */ | ||
100 | #define BIT_DMA_EP_RX_ICR_RX_DONE BIT(0) | ||
101 | #define RGF_DMA_EP_MISC_ICR (0x881bec) /* struct RGF_ICR */ | ||
102 | #define BIT_DMA_EP_MISC_ICR_RX_HTRSH BIT(0) | ||
103 | #define BIT_DMA_EP_MISC_ICR_TX_NO_ACT BIT(1) | ||
104 | #define BIT_DMA_EP_MISC_ICR_FW_INT0 BIT(28) | ||
105 | #define BIT_DMA_EP_MISC_ICR_FW_INT1 BIT(29) | ||
106 | |||
107 | /* Interrupt moderation control */ | ||
108 | #define RGF_DMA_ITR_CNT_TRSH (0x881c5c) | ||
109 | #define RGF_DMA_ITR_CNT_DATA (0x881c60) | ||
110 | #define RGF_DMA_ITR_CNT_CRL (0x881C64) | ||
111 | #define BIT_DMA_ITR_CNT_CRL_EN BIT(0) | ||
112 | #define BIT_DMA_ITR_CNT_CRL_EXT_TICK BIT(1) | ||
113 | #define BIT_DMA_ITR_CNT_CRL_FOREVER BIT(2) | ||
114 | #define BIT_DMA_ITR_CNT_CRL_CLR BIT(3) | ||
115 | #define BIT_DMA_ITR_CNT_CRL_REACH_TRSH BIT(4) | ||
116 | |||
117 | /* popular locations */ | ||
118 | #define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD) | ||
119 | #define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \ | ||
120 | offsetof(struct RGF_ICR, ICS)) | ||
121 | #define SW_INT_MBOX BIT_USER_USER_ICR_SW_INT_2 | ||
122 | |||
123 | /* ISR register bits */ | ||
124 | #define ISR_MISC_FW_READY BIT_DMA_EP_MISC_ICR_FW_INT0 | ||
125 | #define ISR_MISC_MBOX_EVT BIT_DMA_EP_MISC_ICR_FW_INT1 | ||
126 | |||
127 | /* Hardware definitions end */ | ||
128 | |||
129 | struct wil6210_mbox_ring { | ||
130 | u32 base; | ||
131 | u16 entry_size; /* max. size of mbox entry, incl. all headers */ | ||
132 | u16 size; | ||
133 | u32 tail; | ||
134 | u32 head; | ||
135 | } __packed; | ||
136 | |||
137 | struct wil6210_mbox_ring_desc { | ||
138 | __le32 sync; | ||
139 | __le32 addr; | ||
140 | } __packed; | ||
141 | |||
142 | /* at HOST_OFF_WIL6210_MBOX_CTL */ | ||
143 | struct wil6210_mbox_ctl { | ||
144 | struct wil6210_mbox_ring tx; | ||
145 | struct wil6210_mbox_ring rx; | ||
146 | } __packed; | ||
147 | |||
148 | struct wil6210_mbox_hdr { | ||
149 | __le16 seq; | ||
150 | __le16 len; /* payload, bytes after this header */ | ||
151 | __le16 type; | ||
152 | u8 flags; | ||
153 | u8 reserved; | ||
154 | } __packed; | ||
155 | |||
156 | #define WIL_MBOX_HDR_TYPE_WMI (0) | ||
157 | |||
158 | /* max. value for wil6210_mbox_hdr.len */ | ||
159 | #define MAX_MBOXITEM_SIZE (240) | ||
160 | |||
161 | struct wil6210_mbox_hdr_wmi { | ||
162 | u8 reserved0[2]; | ||
163 | __le16 id; | ||
164 | __le16 info1; /* bits [0..3] - device_id, rest - unused */ | ||
165 | u8 reserved1[2]; | ||
166 | } __packed; | ||
167 | |||
168 | struct pending_wmi_event { | ||
169 | struct list_head list; | ||
170 | struct { | ||
171 | struct wil6210_mbox_hdr hdr; | ||
172 | struct wil6210_mbox_hdr_wmi wmi; | ||
173 | u8 data[0]; | ||
174 | } __packed event; | ||
175 | }; | ||
176 | |||
177 | union vring_desc; | ||
178 | |||
179 | struct vring { | ||
180 | dma_addr_t pa; | ||
181 | volatile union vring_desc *va; /* vring_desc[size], WriteBack by DMA */ | ||
182 | u16 size; /* number of vring_desc elements */ | ||
183 | u32 swtail; | ||
184 | u32 swhead; | ||
185 | u32 hwtail; /* write here to inform hw */ | ||
186 | void **ctx; /* void *ctx[size] - software context */ | ||
187 | }; | ||
188 | |||
189 | enum { /* for wil6210_priv.status */ | ||
190 | wil_status_fwready = 0, | ||
191 | wil_status_fwconnected, | ||
192 | wil_status_dontscan, | ||
193 | wil_status_irqen, /* FIXME: interrupts enabled - for debug */ | ||
194 | }; | ||
195 | |||
196 | struct pci_dev; | ||
197 | |||
198 | struct wil6210_stats { | ||
199 | u64 tsf; | ||
200 | u32 snr; | ||
201 | u16 last_mcs_rx; | ||
202 | u16 bf_mcs; /* last BF, used for Tx */ | ||
203 | u16 my_rx_sector; | ||
204 | u16 my_tx_sector; | ||
205 | u16 peer_rx_sector; | ||
206 | u16 peer_tx_sector; | ||
207 | }; | ||
208 | |||
209 | struct wil6210_priv { | ||
210 | struct pci_dev *pdev; | ||
211 | int n_msi; | ||
212 | struct wireless_dev *wdev; | ||
213 | void __iomem *csr; | ||
214 | ulong status; | ||
215 | /* profile */ | ||
216 | u32 monitor_flags; | ||
217 | u32 secure_pcp; /* create secure PCP? */ | ||
218 | int sinfo_gen; | ||
219 | /* cached ISR registers */ | ||
220 | u32 isr_misc; | ||
221 | /* mailbox related */ | ||
222 | struct mutex wmi_mutex; | ||
223 | struct wil6210_mbox_ctl mbox_ctl; | ||
224 | struct completion wmi_ready; | ||
225 | u16 wmi_seq; | ||
226 | u16 reply_id; /**< wait for this WMI event */ | ||
227 | void *reply_buf; | ||
228 | u16 reply_size; | ||
229 | struct workqueue_struct *wmi_wq; /* for deferred calls */ | ||
230 | struct work_struct wmi_event_worker; | ||
231 | struct workqueue_struct *wmi_wq_conn; /* for connect worker */ | ||
232 | struct work_struct wmi_connect_worker; | ||
233 | struct work_struct disconnect_worker; | ||
234 | struct timer_list connect_timer; | ||
235 | int pending_connect_cid; | ||
236 | struct list_head pending_wmi_ev; | ||
237 | /* | ||
238 | * protect pending_wmi_ev | ||
239 | * - fill in IRQ from wil6210_irq_misc, | ||
240 | * - consumed in thread by wmi_event_worker | ||
241 | */ | ||
242 | spinlock_t wmi_ev_lock; | ||
243 | /* DMA related */ | ||
244 | struct vring vring_rx; | ||
245 | struct vring vring_tx[WIL6210_MAX_TX_RINGS]; | ||
246 | u8 dst_addr[WIL6210_MAX_TX_RINGS][ETH_ALEN]; | ||
247 | /* scan */ | ||
248 | struct cfg80211_scan_request *scan_request; | ||
249 | |||
250 | struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */ | ||
251 | /* statistics */ | ||
252 | struct wil6210_stats stats; | ||
253 | /* debugfs */ | ||
254 | struct dentry *debug; | ||
255 | struct debugfs_blob_wrapper fw_code_blob; | ||
256 | struct debugfs_blob_wrapper fw_data_blob; | ||
257 | struct debugfs_blob_wrapper fw_peri_blob; | ||
258 | struct debugfs_blob_wrapper uc_code_blob; | ||
259 | struct debugfs_blob_wrapper uc_data_blob; | ||
260 | struct debugfs_blob_wrapper rgf_blob; | ||
261 | }; | ||
262 | |||
263 | #define wil_to_wiphy(i) (i->wdev->wiphy) | ||
264 | #define wil_to_dev(i) (wiphy_dev(wil_to_wiphy(i))) | ||
265 | #define wiphy_to_wil(w) (struct wil6210_priv *)(wiphy_priv(w)) | ||
266 | #define wil_to_wdev(i) (i->wdev) | ||
267 | #define wdev_to_wil(w) (struct wil6210_priv *)(wdev_priv(w)) | ||
268 | #define wil_to_ndev(i) (wil_to_wdev(i)->netdev) | ||
269 | #define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr)) | ||
270 | |||
271 | #define wil_dbg(wil, fmt, arg...) netdev_dbg(wil_to_ndev(wil), fmt, ##arg) | ||
272 | #define wil_info(wil, fmt, arg...) netdev_info(wil_to_ndev(wil), fmt, ##arg) | ||
273 | #define wil_err(wil, fmt, arg...) netdev_err(wil_to_ndev(wil), fmt, ##arg) | ||
274 | |||
275 | #define wil_dbg_IRQ(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg) | ||
276 | #define wil_dbg_TXRX(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg) | ||
277 | #define wil_dbg_WMI(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg) | ||
278 | |||
279 | #define wil_hex_dump_TXRX(prefix_str, prefix_type, rowsize, \ | ||
280 | groupsize, buf, len, ascii) \ | ||
281 | wil_print_hex_dump_debug("DBG[TXRX]" prefix_str,\ | ||
282 | prefix_type, rowsize, \ | ||
283 | groupsize, buf, len, ascii) | ||
284 | |||
285 | #define wil_hex_dump_WMI(prefix_str, prefix_type, rowsize, \ | ||
286 | groupsize, buf, len, ascii) \ | ||
287 | wil_print_hex_dump_debug("DBG[ WMI]" prefix_str,\ | ||
288 | prefix_type, rowsize, \ | ||
289 | groupsize, buf, len, ascii) | ||
290 | |||
291 | void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, | ||
292 | size_t count); | ||
293 | void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, | ||
294 | size_t count); | ||
295 | |||
296 | void *wil_if_alloc(struct device *dev, void __iomem *csr); | ||
297 | void wil_if_free(struct wil6210_priv *wil); | ||
298 | int wil_if_add(struct wil6210_priv *wil); | ||
299 | void wil_if_remove(struct wil6210_priv *wil); | ||
300 | int wil_priv_init(struct wil6210_priv *wil); | ||
301 | void wil_priv_deinit(struct wil6210_priv *wil); | ||
302 | int wil_reset(struct wil6210_priv *wil); | ||
303 | void wil_link_on(struct wil6210_priv *wil); | ||
304 | void wil_link_off(struct wil6210_priv *wil); | ||
305 | int wil_up(struct wil6210_priv *wil); | ||
306 | int wil_down(struct wil6210_priv *wil); | ||
307 | void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); | ||
308 | |||
309 | void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); | ||
310 | void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); | ||
311 | int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr, | ||
312 | struct wil6210_mbox_hdr *hdr); | ||
313 | int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len); | ||
314 | void wmi_recv_cmd(struct wil6210_priv *wil); | ||
315 | int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, | ||
316 | u16 reply_id, void *reply, u8 reply_size, int to_msec); | ||
317 | void wmi_connect_worker(struct work_struct *work); | ||
318 | void wmi_event_worker(struct work_struct *work); | ||
319 | void wmi_event_flush(struct wil6210_priv *wil); | ||
320 | int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid); | ||
321 | int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid); | ||
322 | int wmi_set_channel(struct wil6210_priv *wil, int channel); | ||
323 | int wmi_get_channel(struct wil6210_priv *wil, int *channel); | ||
324 | int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb); | ||
325 | int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index, | ||
326 | const void *mac_addr); | ||
327 | int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index, | ||
328 | const void *mac_addr, int key_len, const void *key); | ||
329 | int wmi_echo(struct wil6210_priv *wil); | ||
330 | int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie); | ||
331 | |||
332 | int wil6210_init_irq(struct wil6210_priv *wil, int irq); | ||
333 | void wil6210_fini_irq(struct wil6210_priv *wil, int irq); | ||
334 | void wil6210_disable_irq(struct wil6210_priv *wil); | ||
335 | void wil6210_enable_irq(struct wil6210_priv *wil); | ||
336 | |||
337 | int wil6210_debugfs_init(struct wil6210_priv *wil); | ||
338 | void wil6210_debugfs_remove(struct wil6210_priv *wil); | ||
339 | |||
340 | struct wireless_dev *wil_cfg80211_init(struct device *dev); | ||
341 | void wil_wdev_free(struct wil6210_priv *wil); | ||
342 | |||
343 | int wmi_set_mac_address(struct wil6210_priv *wil, void *addr); | ||
344 | int wmi_set_bcon(struct wil6210_priv *wil, int bi, u8 wmi_nettype); | ||
345 | void wil6210_disconnect(struct wil6210_priv *wil, void *bssid); | ||
346 | |||
347 | int wil_rx_init(struct wil6210_priv *wil); | ||
348 | void wil_rx_fini(struct wil6210_priv *wil); | ||
349 | |||
350 | /* TX API */ | ||
351 | int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, | ||
352 | int cid, int tid); | ||
353 | void wil_vring_fini_tx(struct wil6210_priv *wil, int id); | ||
354 | |||
355 | netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev); | ||
356 | void wil_tx_complete(struct wil6210_priv *wil, int ringid); | ||
357 | |||
358 | /* RX API */ | ||
359 | void wil_rx_handle(struct wil6210_priv *wil); | ||
360 | |||
361 | int wil_iftype_nl2wmi(enum nl80211_iftype type); | ||
362 | |||
363 | #endif /* __WIL6210_H__ */ | ||
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c new file mode 100644 index 000000000000..12915f6e7617 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/wmi.c | |||
@@ -0,0 +1,975 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/pci.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/list.h> | ||
20 | #include <linux/etherdevice.h> | ||
21 | |||
22 | #include "wil6210.h" | ||
23 | #include "wmi.h" | ||
24 | |||
25 | /** | ||
26 | * WMI event receiving - theory of operations | ||
27 | * | ||
28 | * When firmware about to report WMI event, it fills memory area | ||
29 | * in the mailbox and raises misc. IRQ. Thread interrupt handler invoked for | ||
30 | * the misc IRQ, function @wmi_recv_cmd called by thread IRQ handler. | ||
31 | * | ||
32 | * @wmi_recv_cmd reads event, allocates memory chunk and attaches it to the | ||
33 | * event list @wil->pending_wmi_ev. Then, work queue @wil->wmi_wq wakes up | ||
34 | * and handles events within the @wmi_event_worker. Every event get detached | ||
35 | * from list, processed and deleted. | ||
36 | * | ||
37 | * Purpose for this mechanism is to release IRQ thread; otherwise, | ||
38 | * if WMI event handling involves another WMI command flow, this 2-nd flow | ||
39 | * won't be completed because of blocked IRQ thread. | ||
40 | */ | ||
41 | |||
42 | /** | ||
43 | * Addressing - theory of operations | ||
44 | * | ||
45 | * There are several buses present on the WIL6210 card. | ||
46 | * Same memory areas are visible at different address on | ||
47 | * the different busses. There are 3 main bus masters: | ||
48 | * - MAC CPU (ucode) | ||
49 | * - User CPU (firmware) | ||
50 | * - AHB (host) | ||
51 | * | ||
52 | * On the PCI bus, there is one BAR (BAR0) of 2Mb size, exposing | ||
53 | * AHB addresses starting from 0x880000 | ||
54 | * | ||
55 | * Internally, firmware uses addresses that allows faster access but | ||
56 | * are invisible from the host. To read from these addresses, alternative | ||
57 | * AHB address must be used. | ||
58 | * | ||
59 | * Memory mapping | ||
60 | * Linker address PCI/Host address | ||
61 | * 0x880000 .. 0xa80000 2Mb BAR0 | ||
62 | * 0x800000 .. 0x807000 0x900000 .. 0x907000 28k DCCM | ||
63 | * 0x840000 .. 0x857000 0x908000 .. 0x91f000 92k PERIPH | ||
64 | */ | ||
65 | |||
66 | /** | ||
67 | * @fw_mapping provides memory remapping table | ||
68 | */ | ||
69 | static const struct { | ||
70 | u32 from; /* linker address - from, inclusive */ | ||
71 | u32 to; /* linker address - to, exclusive */ | ||
72 | u32 host; /* PCI/Host address - BAR0 + 0x880000 */ | ||
73 | } fw_mapping[] = { | ||
74 | {0x000000, 0x040000, 0x8c0000}, /* FW code RAM 256k */ | ||
75 | {0x800000, 0x808000, 0x900000}, /* FW data RAM 32k */ | ||
76 | {0x840000, 0x860000, 0x908000}, /* peripheral data RAM 128k/96k used */ | ||
77 | {0x880000, 0x88a000, 0x880000}, /* various RGF */ | ||
78 | {0x8c0000, 0x932000, 0x8c0000}, /* trivial mapping for upper area */ | ||
79 | /* | ||
80 | * 920000..930000 ucode code RAM | ||
81 | * 930000..932000 ucode data RAM | ||
82 | */ | ||
83 | }; | ||
84 | |||
85 | /** | ||
86 | * return AHB address for given firmware/ucode internal (linker) address | ||
87 | * @x - internal address | ||
88 | * If address have no valid AHB mapping, return 0 | ||
89 | */ | ||
90 | static u32 wmi_addr_remap(u32 x) | ||
91 | { | ||
92 | uint i; | ||
93 | |||
94 | for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) { | ||
95 | if ((x >= fw_mapping[i].from) && (x < fw_mapping[i].to)) | ||
96 | return x + fw_mapping[i].host - fw_mapping[i].from; | ||
97 | } | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * Check address validity for WMI buffer; remap if needed | ||
104 | * @ptr - internal (linker) fw/ucode address | ||
105 | * | ||
106 | * Valid buffer should be DWORD aligned | ||
107 | * | ||
108 | * return address for accessing buffer from the host; | ||
109 | * if buffer is not valid, return NULL. | ||
110 | */ | ||
111 | void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_) | ||
112 | { | ||
113 | u32 off; | ||
114 | u32 ptr = le32_to_cpu(ptr_); | ||
115 | |||
116 | if (ptr % 4) | ||
117 | return NULL; | ||
118 | |||
119 | ptr = wmi_addr_remap(ptr); | ||
120 | if (ptr < WIL6210_FW_HOST_OFF) | ||
121 | return NULL; | ||
122 | |||
123 | off = HOSTADDR(ptr); | ||
124 | if (off > WIL6210_MEM_SIZE - 4) | ||
125 | return NULL; | ||
126 | |||
127 | return wil->csr + off; | ||
128 | } | ||
129 | |||
130 | /** | ||
131 | * Check address validity | ||
132 | */ | ||
133 | void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr) | ||
134 | { | ||
135 | u32 off; | ||
136 | |||
137 | if (ptr % 4) | ||
138 | return NULL; | ||
139 | |||
140 | if (ptr < WIL6210_FW_HOST_OFF) | ||
141 | return NULL; | ||
142 | |||
143 | off = HOSTADDR(ptr); | ||
144 | if (off > WIL6210_MEM_SIZE - 4) | ||
145 | return NULL; | ||
146 | |||
147 | return wil->csr + off; | ||
148 | } | ||
149 | |||
150 | int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr, | ||
151 | struct wil6210_mbox_hdr *hdr) | ||
152 | { | ||
153 | void __iomem *src = wmi_buffer(wil, ptr); | ||
154 | if (!src) | ||
155 | return -EINVAL; | ||
156 | |||
157 | wil_memcpy_fromio_32(hdr, src, sizeof(*hdr)); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) | ||
163 | { | ||
164 | struct { | ||
165 | struct wil6210_mbox_hdr hdr; | ||
166 | struct wil6210_mbox_hdr_wmi wmi; | ||
167 | } __packed cmd = { | ||
168 | .hdr = { | ||
169 | .type = WIL_MBOX_HDR_TYPE_WMI, | ||
170 | .flags = 0, | ||
171 | .len = cpu_to_le16(sizeof(cmd.wmi) + len), | ||
172 | }, | ||
173 | .wmi = { | ||
174 | .id = cpu_to_le16(cmdid), | ||
175 | .info1 = 0, | ||
176 | }, | ||
177 | }; | ||
178 | struct wil6210_mbox_ring *r = &wil->mbox_ctl.tx; | ||
179 | struct wil6210_mbox_ring_desc d_head; | ||
180 | u32 next_head; | ||
181 | void __iomem *dst; | ||
182 | void __iomem *head = wmi_addr(wil, r->head); | ||
183 | uint retry; | ||
184 | |||
185 | if (sizeof(cmd) + len > r->entry_size) { | ||
186 | wil_err(wil, "WMI size too large: %d bytes, max is %d\n", | ||
187 | (int)(sizeof(cmd) + len), r->entry_size); | ||
188 | return -ERANGE; | ||
189 | |||
190 | } | ||
191 | |||
192 | might_sleep(); | ||
193 | |||
194 | if (!test_bit(wil_status_fwready, &wil->status)) { | ||
195 | wil_err(wil, "FW not ready\n"); | ||
196 | return -EAGAIN; | ||
197 | } | ||
198 | |||
199 | if (!head) { | ||
200 | wil_err(wil, "WMI head is garbage: 0x%08x\n", r->head); | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | /* read Tx head till it is not busy */ | ||
204 | for (retry = 5; retry > 0; retry--) { | ||
205 | wil_memcpy_fromio_32(&d_head, head, sizeof(d_head)); | ||
206 | if (d_head.sync == 0) | ||
207 | break; | ||
208 | msleep(20); | ||
209 | } | ||
210 | if (d_head.sync != 0) { | ||
211 | wil_err(wil, "WMI head busy\n"); | ||
212 | return -EBUSY; | ||
213 | } | ||
214 | /* next head */ | ||
215 | next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size); | ||
216 | wil_dbg_WMI(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head); | ||
217 | /* wait till FW finish with previous command */ | ||
218 | for (retry = 5; retry > 0; retry--) { | ||
219 | r->tail = ioread32(wil->csr + HOST_MBOX + | ||
220 | offsetof(struct wil6210_mbox_ctl, tx.tail)); | ||
221 | if (next_head != r->tail) | ||
222 | break; | ||
223 | msleep(20); | ||
224 | } | ||
225 | if (next_head == r->tail) { | ||
226 | wil_err(wil, "WMI ring full\n"); | ||
227 | return -EBUSY; | ||
228 | } | ||
229 | dst = wmi_buffer(wil, d_head.addr); | ||
230 | if (!dst) { | ||
231 | wil_err(wil, "invalid WMI buffer: 0x%08x\n", | ||
232 | le32_to_cpu(d_head.addr)); | ||
233 | return -EINVAL; | ||
234 | } | ||
235 | cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq); | ||
236 | /* set command */ | ||
237 | wil_dbg_WMI(wil, "WMI command 0x%04x [%d]\n", cmdid, len); | ||
238 | wil_hex_dump_WMI("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd, | ||
239 | sizeof(cmd), true); | ||
240 | wil_hex_dump_WMI("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf, | ||
241 | len, true); | ||
242 | wil_memcpy_toio_32(dst, &cmd, sizeof(cmd)); | ||
243 | wil_memcpy_toio_32(dst + sizeof(cmd), buf, len); | ||
244 | /* mark entry as full */ | ||
245 | iowrite32(1, wil->csr + HOSTADDR(r->head) + | ||
246 | offsetof(struct wil6210_mbox_ring_desc, sync)); | ||
247 | /* advance next ptr */ | ||
248 | iowrite32(r->head = next_head, wil->csr + HOST_MBOX + | ||
249 | offsetof(struct wil6210_mbox_ctl, tx.head)); | ||
250 | |||
251 | /* interrupt to FW */ | ||
252 | iowrite32(SW_INT_MBOX, wil->csr + HOST_SW_INT); | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) | ||
258 | { | ||
259 | int rc; | ||
260 | |||
261 | mutex_lock(&wil->wmi_mutex); | ||
262 | rc = __wmi_send(wil, cmdid, buf, len); | ||
263 | mutex_unlock(&wil->wmi_mutex); | ||
264 | |||
265 | return rc; | ||
266 | } | ||
267 | |||
268 | /*=== Event handlers ===*/ | ||
269 | static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) | ||
270 | { | ||
271 | struct net_device *ndev = wil_to_ndev(wil); | ||
272 | struct wireless_dev *wdev = wil->wdev; | ||
273 | struct wmi_ready_event *evt = d; | ||
274 | u32 ver = le32_to_cpu(evt->sw_version); | ||
275 | |||
276 | wil_dbg_WMI(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac); | ||
277 | |||
278 | if (!is_valid_ether_addr(ndev->dev_addr)) { | ||
279 | memcpy(ndev->dev_addr, evt->mac, ETH_ALEN); | ||
280 | memcpy(ndev->perm_addr, evt->mac, ETH_ALEN); | ||
281 | } | ||
282 | snprintf(wdev->wiphy->fw_version, sizeof(wdev->wiphy->fw_version), | ||
283 | "%d", ver); | ||
284 | } | ||
285 | |||
286 | static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d, | ||
287 | int len) | ||
288 | { | ||
289 | wil_dbg_WMI(wil, "WMI: FW ready\n"); | ||
290 | |||
291 | set_bit(wil_status_fwready, &wil->status); | ||
292 | /* reuse wmi_ready for the firmware ready indication */ | ||
293 | complete(&wil->wmi_ready); | ||
294 | } | ||
295 | |||
296 | static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) | ||
297 | { | ||
298 | struct wmi_rx_mgmt_packet_event *data = d; | ||
299 | struct wiphy *wiphy = wil_to_wiphy(wil); | ||
300 | struct ieee80211_mgmt *rx_mgmt_frame = | ||
301 | (struct ieee80211_mgmt *)data->payload; | ||
302 | int ch_no = data->info.channel+1; | ||
303 | u32 freq = ieee80211_channel_to_frequency(ch_no, | ||
304 | IEEE80211_BAND_60GHZ); | ||
305 | struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq); | ||
306 | /* TODO convert LE to CPU */ | ||
307 | s32 signal = 0; /* TODO */ | ||
308 | __le16 fc = rx_mgmt_frame->frame_control; | ||
309 | u32 d_len = le32_to_cpu(data->info.len); | ||
310 | u16 d_status = le16_to_cpu(data->info.status); | ||
311 | |||
312 | wil_dbg_WMI(wil, "MGMT: channel %d MCS %d SNR %d\n", | ||
313 | data->info.channel, data->info.mcs, data->info.snr); | ||
314 | wil_dbg_WMI(wil, "status 0x%04x len %d stype %04x\n", d_status, d_len, | ||
315 | le16_to_cpu(data->info.stype)); | ||
316 | wil_dbg_WMI(wil, "qid %d mid %d cid %d\n", | ||
317 | data->info.qid, data->info.mid, data->info.cid); | ||
318 | |||
319 | if (!channel) { | ||
320 | wil_err(wil, "Frame on unsupported channel\n"); | ||
321 | return; | ||
322 | } | ||
323 | |||
324 | if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) { | ||
325 | struct cfg80211_bss *bss; | ||
326 | u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp); | ||
327 | u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info); | ||
328 | u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int); | ||
329 | const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable; | ||
330 | size_t ie_len = d_len - offsetof(struct ieee80211_mgmt, | ||
331 | u.beacon.variable); | ||
332 | wil_dbg_WMI(wil, "Capability info : 0x%04x\n", cap); | ||
333 | |||
334 | bss = cfg80211_inform_bss(wiphy, channel, rx_mgmt_frame->bssid, | ||
335 | tsf, cap, bi, ie_buf, ie_len, | ||
336 | signal, GFP_KERNEL); | ||
337 | if (bss) { | ||
338 | wil_dbg_WMI(wil, "Added BSS %pM\n", | ||
339 | rx_mgmt_frame->bssid); | ||
340 | cfg80211_put_bss(bss); | ||
341 | } else { | ||
342 | wil_err(wil, "cfg80211_inform_bss() failed\n"); | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | |||
347 | static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id, | ||
348 | void *d, int len) | ||
349 | { | ||
350 | if (wil->scan_request) { | ||
351 | struct wmi_scan_complete_event *data = d; | ||
352 | bool aborted = (data->status != 0); | ||
353 | |||
354 | wil_dbg_WMI(wil, "SCAN_COMPLETE(0x%08x)\n", data->status); | ||
355 | cfg80211_scan_done(wil->scan_request, aborted); | ||
356 | wil->scan_request = NULL; | ||
357 | } else { | ||
358 | wil_err(wil, "SCAN_COMPLETE while not scanning\n"); | ||
359 | } | ||
360 | } | ||
361 | |||
362 | static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) | ||
363 | { | ||
364 | struct net_device *ndev = wil_to_ndev(wil); | ||
365 | struct wireless_dev *wdev = wil->wdev; | ||
366 | struct wmi_connect_event *evt = d; | ||
367 | int ch; /* channel number */ | ||
368 | struct station_info sinfo; | ||
369 | u8 *assoc_req_ie, *assoc_resp_ie; | ||
370 | size_t assoc_req_ielen, assoc_resp_ielen; | ||
371 | /* capinfo(u16) + listen_interval(u16) + IEs */ | ||
372 | const size_t assoc_req_ie_offset = sizeof(u16) * 2; | ||
373 | /* capinfo(u16) + status_code(u16) + associd(u16) + IEs */ | ||
374 | const size_t assoc_resp_ie_offset = sizeof(u16) * 3; | ||
375 | |||
376 | if (len < sizeof(*evt)) { | ||
377 | wil_err(wil, "Connect event too short : %d bytes\n", len); | ||
378 | return; | ||
379 | } | ||
380 | if (len != sizeof(*evt) + evt->beacon_ie_len + evt->assoc_req_len + | ||
381 | evt->assoc_resp_len) { | ||
382 | wil_err(wil, | ||
383 | "Connect event corrupted : %d != %d + %d + %d + %d\n", | ||
384 | len, (int)sizeof(*evt), evt->beacon_ie_len, | ||
385 | evt->assoc_req_len, evt->assoc_resp_len); | ||
386 | return; | ||
387 | } | ||
388 | ch = evt->channel + 1; | ||
389 | wil_dbg_WMI(wil, "Connect %pM channel [%d] cid %d\n", | ||
390 | evt->bssid, ch, evt->cid); | ||
391 | wil_hex_dump_WMI("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1, | ||
392 | evt->assoc_info, len - sizeof(*evt), true); | ||
393 | |||
394 | /* figure out IE's */ | ||
395 | assoc_req_ie = &evt->assoc_info[evt->beacon_ie_len + | ||
396 | assoc_req_ie_offset]; | ||
397 | assoc_req_ielen = evt->assoc_req_len - assoc_req_ie_offset; | ||
398 | if (evt->assoc_req_len <= assoc_req_ie_offset) { | ||
399 | assoc_req_ie = NULL; | ||
400 | assoc_req_ielen = 0; | ||
401 | } | ||
402 | |||
403 | assoc_resp_ie = &evt->assoc_info[evt->beacon_ie_len + | ||
404 | evt->assoc_req_len + | ||
405 | assoc_resp_ie_offset]; | ||
406 | assoc_resp_ielen = evt->assoc_resp_len - assoc_resp_ie_offset; | ||
407 | if (evt->assoc_resp_len <= assoc_resp_ie_offset) { | ||
408 | assoc_resp_ie = NULL; | ||
409 | assoc_resp_ielen = 0; | ||
410 | } | ||
411 | |||
412 | if ((wdev->iftype == NL80211_IFTYPE_STATION) || | ||
413 | (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { | ||
414 | if (wdev->sme_state != CFG80211_SME_CONNECTING) { | ||
415 | wil_err(wil, "Not in connecting state\n"); | ||
416 | return; | ||
417 | } | ||
418 | del_timer_sync(&wil->connect_timer); | ||
419 | cfg80211_connect_result(ndev, evt->bssid, | ||
420 | assoc_req_ie, assoc_req_ielen, | ||
421 | assoc_resp_ie, assoc_resp_ielen, | ||
422 | WLAN_STATUS_SUCCESS, GFP_KERNEL); | ||
423 | |||
424 | } else if ((wdev->iftype == NL80211_IFTYPE_AP) || | ||
425 | (wdev->iftype == NL80211_IFTYPE_P2P_GO)) { | ||
426 | memset(&sinfo, 0, sizeof(sinfo)); | ||
427 | |||
428 | sinfo.generation = wil->sinfo_gen++; | ||
429 | |||
430 | if (assoc_req_ie) { | ||
431 | sinfo.assoc_req_ies = assoc_req_ie; | ||
432 | sinfo.assoc_req_ies_len = assoc_req_ielen; | ||
433 | sinfo.filled |= STATION_INFO_ASSOC_REQ_IES; | ||
434 | } | ||
435 | |||
436 | cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL); | ||
437 | } | ||
438 | set_bit(wil_status_fwconnected, &wil->status); | ||
439 | |||
440 | /* FIXME FW can transmit only ucast frames to peer */ | ||
441 | /* FIXME real ring_id instead of hard coded 0 */ | ||
442 | memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN); | ||
443 | |||
444 | wil->pending_connect_cid = evt->cid; | ||
445 | queue_work(wil->wmi_wq_conn, &wil->wmi_connect_worker); | ||
446 | } | ||
447 | |||
448 | static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, | ||
449 | void *d, int len) | ||
450 | { | ||
451 | struct wmi_disconnect_event *evt = d; | ||
452 | |||
453 | wil_dbg_WMI(wil, "Disconnect %pM reason %d proto %d wmi\n", | ||
454 | evt->bssid, | ||
455 | evt->protocol_reason_status, evt->disconnect_reason); | ||
456 | |||
457 | wil->sinfo_gen++; | ||
458 | |||
459 | wil6210_disconnect(wil, evt->bssid); | ||
460 | clear_bit(wil_status_dontscan, &wil->status); | ||
461 | } | ||
462 | |||
463 | static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) | ||
464 | { | ||
465 | struct wmi_notify_req_done_event *evt = d; | ||
466 | |||
467 | if (len < sizeof(*evt)) { | ||
468 | wil_err(wil, "Short NOTIFY event\n"); | ||
469 | return; | ||
470 | } | ||
471 | |||
472 | wil->stats.tsf = le64_to_cpu(evt->tsf); | ||
473 | wil->stats.snr = le32_to_cpu(evt->snr_val); | ||
474 | wil->stats.bf_mcs = le16_to_cpu(evt->bf_mcs); | ||
475 | wil->stats.my_rx_sector = le16_to_cpu(evt->my_rx_sector); | ||
476 | wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector); | ||
477 | wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector); | ||
478 | wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector); | ||
479 | wil_dbg_WMI(wil, "Link status, MCS %d TSF 0x%016llx\n" | ||
480 | "BF status 0x%08x SNR 0x%08x\n" | ||
481 | "Tx Tpt %d goodput %d Rx goodput %d\n" | ||
482 | "Sectors(rx:tx) my %d:%d peer %d:%d\n", | ||
483 | wil->stats.bf_mcs, wil->stats.tsf, evt->status, | ||
484 | wil->stats.snr, le32_to_cpu(evt->tx_tpt), | ||
485 | le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput), | ||
486 | wil->stats.my_rx_sector, wil->stats.my_tx_sector, | ||
487 | wil->stats.peer_rx_sector, wil->stats.peer_tx_sector); | ||
488 | } | ||
489 | |||
490 | /* | ||
491 | * Firmware reports EAPOL frame using WME event. | ||
492 | * Reconstruct Ethernet frame and deliver it via normal Rx | ||
493 | */ | ||
494 | static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, | ||
495 | void *d, int len) | ||
496 | { | ||
497 | struct net_device *ndev = wil_to_ndev(wil); | ||
498 | struct wmi_eapol_rx_event *evt = d; | ||
499 | u16 eapol_len = le16_to_cpu(evt->eapol_len); | ||
500 | int sz = eapol_len + ETH_HLEN; | ||
501 | struct sk_buff *skb; | ||
502 | struct ethhdr *eth; | ||
503 | |||
504 | wil_dbg_WMI(wil, "EAPOL len %d from %pM\n", eapol_len, | ||
505 | evt->src_mac); | ||
506 | |||
507 | if (eapol_len > 196) { /* TODO: revisit size limit */ | ||
508 | wil_err(wil, "EAPOL too large\n"); | ||
509 | return; | ||
510 | } | ||
511 | |||
512 | skb = alloc_skb(sz, GFP_KERNEL); | ||
513 | if (!skb) { | ||
514 | wil_err(wil, "Failed to allocate skb\n"); | ||
515 | return; | ||
516 | } | ||
517 | eth = (struct ethhdr *)skb_put(skb, ETH_HLEN); | ||
518 | memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN); | ||
519 | memcpy(eth->h_source, evt->src_mac, ETH_ALEN); | ||
520 | eth->h_proto = cpu_to_be16(ETH_P_PAE); | ||
521 | memcpy(skb_put(skb, eapol_len), evt->eapol, eapol_len); | ||
522 | skb->protocol = eth_type_trans(skb, ndev); | ||
523 | if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) { | ||
524 | ndev->stats.rx_packets++; | ||
525 | ndev->stats.rx_bytes += skb->len; | ||
526 | } else { | ||
527 | ndev->stats.rx_dropped++; | ||
528 | } | ||
529 | } | ||
530 | |||
531 | static const struct { | ||
532 | int eventid; | ||
533 | void (*handler)(struct wil6210_priv *wil, int eventid, | ||
534 | void *data, int data_len); | ||
535 | } wmi_evt_handlers[] = { | ||
536 | {WMI_READY_EVENTID, wmi_evt_ready}, | ||
537 | {WMI_FW_READY_EVENTID, wmi_evt_fw_ready}, | ||
538 | {WMI_RX_MGMT_PACKET_EVENTID, wmi_evt_rx_mgmt}, | ||
539 | {WMI_SCAN_COMPLETE_EVENTID, wmi_evt_scan_complete}, | ||
540 | {WMI_CONNECT_EVENTID, wmi_evt_connect}, | ||
541 | {WMI_DISCONNECT_EVENTID, wmi_evt_disconnect}, | ||
542 | {WMI_NOTIFY_REQ_DONE_EVENTID, wmi_evt_notify}, | ||
543 | {WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx}, | ||
544 | }; | ||
545 | |||
546 | /* | ||
547 | * Run in IRQ context | ||
548 | * Extract WMI command from mailbox. Queue it to the @wil->pending_wmi_ev | ||
549 | * that will be eventually handled by the @wmi_event_worker in the thread | ||
550 | * context of thread "wil6210_wmi" | ||
551 | */ | ||
552 | void wmi_recv_cmd(struct wil6210_priv *wil) | ||
553 | { | ||
554 | struct wil6210_mbox_ring_desc d_tail; | ||
555 | struct wil6210_mbox_hdr hdr; | ||
556 | struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx; | ||
557 | struct pending_wmi_event *evt; | ||
558 | u8 *cmd; | ||
559 | void __iomem *src; | ||
560 | ulong flags; | ||
561 | |||
562 | for (;;) { | ||
563 | u16 len; | ||
564 | |||
565 | r->head = ioread32(wil->csr + HOST_MBOX + | ||
566 | offsetof(struct wil6210_mbox_ctl, rx.head)); | ||
567 | if (r->tail == r->head) | ||
568 | return; | ||
569 | |||
570 | /* read cmd from tail */ | ||
571 | wil_memcpy_fromio_32(&d_tail, wil->csr + HOSTADDR(r->tail), | ||
572 | sizeof(struct wil6210_mbox_ring_desc)); | ||
573 | if (d_tail.sync == 0) { | ||
574 | wil_err(wil, "Mbox evt not owned by FW?\n"); | ||
575 | return; | ||
576 | } | ||
577 | |||
578 | if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) { | ||
579 | wil_err(wil, "Mbox evt at 0x%08x?\n", | ||
580 | le32_to_cpu(d_tail.addr)); | ||
581 | return; | ||
582 | } | ||
583 | |||
584 | len = le16_to_cpu(hdr.len); | ||
585 | src = wmi_buffer(wil, d_tail.addr) + | ||
586 | sizeof(struct wil6210_mbox_hdr); | ||
587 | evt = kmalloc(ALIGN(offsetof(struct pending_wmi_event, | ||
588 | event.wmi) + len, 4), | ||
589 | GFP_KERNEL); | ||
590 | if (!evt) { | ||
591 | wil_err(wil, "kmalloc for WMI event (%d) failed\n", | ||
592 | len); | ||
593 | return; | ||
594 | } | ||
595 | evt->event.hdr = hdr; | ||
596 | cmd = (void *)&evt->event.wmi; | ||
597 | wil_memcpy_fromio_32(cmd, src, len); | ||
598 | /* mark entry as empty */ | ||
599 | iowrite32(0, wil->csr + HOSTADDR(r->tail) + | ||
600 | offsetof(struct wil6210_mbox_ring_desc, sync)); | ||
601 | /* indicate */ | ||
602 | wil_dbg_WMI(wil, "Mbox evt %04x %04x %04x %02x\n", | ||
603 | le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type), | ||
604 | hdr.flags); | ||
605 | if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) && | ||
606 | (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { | ||
607 | wil_dbg_WMI(wil, "WMI event 0x%04x\n", | ||
608 | evt->event.wmi.id); | ||
609 | } | ||
610 | wil_hex_dump_WMI("evt ", DUMP_PREFIX_OFFSET, 16, 1, | ||
611 | &evt->event.hdr, sizeof(hdr) + len, true); | ||
612 | |||
613 | /* advance tail */ | ||
614 | r->tail = r->base + ((r->tail - r->base + | ||
615 | sizeof(struct wil6210_mbox_ring_desc)) % r->size); | ||
616 | iowrite32(r->tail, wil->csr + HOST_MBOX + | ||
617 | offsetof(struct wil6210_mbox_ctl, rx.tail)); | ||
618 | |||
619 | /* add to the pending list */ | ||
620 | spin_lock_irqsave(&wil->wmi_ev_lock, flags); | ||
621 | list_add_tail(&evt->list, &wil->pending_wmi_ev); | ||
622 | spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); | ||
623 | { | ||
624 | int q = queue_work(wil->wmi_wq, | ||
625 | &wil->wmi_event_worker); | ||
626 | wil_dbg_WMI(wil, "queue_work -> %d\n", q); | ||
627 | } | ||
628 | } | ||
629 | } | ||
630 | |||
631 | int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, | ||
632 | u16 reply_id, void *reply, u8 reply_size, int to_msec) | ||
633 | { | ||
634 | int rc; | ||
635 | int remain; | ||
636 | |||
637 | mutex_lock(&wil->wmi_mutex); | ||
638 | |||
639 | rc = __wmi_send(wil, cmdid, buf, len); | ||
640 | if (rc) | ||
641 | goto out; | ||
642 | |||
643 | wil->reply_id = reply_id; | ||
644 | wil->reply_buf = reply; | ||
645 | wil->reply_size = reply_size; | ||
646 | remain = wait_for_completion_timeout(&wil->wmi_ready, | ||
647 | msecs_to_jiffies(to_msec)); | ||
648 | if (0 == remain) { | ||
649 | wil_err(wil, "wmi_call(0x%04x->0x%04x) timeout %d msec\n", | ||
650 | cmdid, reply_id, to_msec); | ||
651 | rc = -ETIME; | ||
652 | } else { | ||
653 | wil_dbg_WMI(wil, | ||
654 | "wmi_call(0x%04x->0x%04x) completed in %d msec\n", | ||
655 | cmdid, reply_id, | ||
656 | to_msec - jiffies_to_msecs(remain)); | ||
657 | } | ||
658 | wil->reply_id = 0; | ||
659 | wil->reply_buf = NULL; | ||
660 | wil->reply_size = 0; | ||
661 | out: | ||
662 | mutex_unlock(&wil->wmi_mutex); | ||
663 | |||
664 | return rc; | ||
665 | } | ||
666 | |||
667 | int wmi_echo(struct wil6210_priv *wil) | ||
668 | { | ||
669 | struct wmi_echo_cmd cmd = { | ||
670 | .value = cpu_to_le32(0x12345678), | ||
671 | }; | ||
672 | |||
673 | return wmi_call(wil, WMI_ECHO_CMDID, &cmd, sizeof(cmd), | ||
674 | WMI_ECHO_RSP_EVENTID, NULL, 0, 20); | ||
675 | } | ||
676 | |||
677 | int wmi_set_mac_address(struct wil6210_priv *wil, void *addr) | ||
678 | { | ||
679 | struct wmi_set_mac_address_cmd cmd; | ||
680 | |||
681 | memcpy(cmd.mac, addr, ETH_ALEN); | ||
682 | |||
683 | wil_dbg_WMI(wil, "Set MAC %pM\n", addr); | ||
684 | |||
685 | return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd)); | ||
686 | } | ||
687 | |||
688 | int wmi_set_bcon(struct wil6210_priv *wil, int bi, u8 wmi_nettype) | ||
689 | { | ||
690 | struct wmi_bcon_ctrl_cmd cmd = { | ||
691 | .bcon_interval = cpu_to_le16(bi), | ||
692 | .network_type = wmi_nettype, | ||
693 | .disable_sec_offload = 1, | ||
694 | }; | ||
695 | |||
696 | if (!wil->secure_pcp) | ||
697 | cmd.disable_sec = 1; | ||
698 | |||
699 | return wmi_send(wil, WMI_BCON_CTRL_CMDID, &cmd, sizeof(cmd)); | ||
700 | } | ||
701 | |||
702 | int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid) | ||
703 | { | ||
704 | struct wmi_set_ssid_cmd cmd = { | ||
705 | .ssid_len = cpu_to_le32(ssid_len), | ||
706 | }; | ||
707 | |||
708 | if (ssid_len > sizeof(cmd.ssid)) | ||
709 | return -EINVAL; | ||
710 | |||
711 | memcpy(cmd.ssid, ssid, ssid_len); | ||
712 | |||
713 | return wmi_send(wil, WMI_SET_SSID_CMDID, &cmd, sizeof(cmd)); | ||
714 | } | ||
715 | |||
716 | int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid) | ||
717 | { | ||
718 | int rc; | ||
719 | struct { | ||
720 | struct wil6210_mbox_hdr_wmi wmi; | ||
721 | struct wmi_set_ssid_cmd cmd; | ||
722 | } __packed reply; | ||
723 | int len; /* reply.cmd.ssid_len in CPU order */ | ||
724 | |||
725 | rc = wmi_call(wil, WMI_GET_SSID_CMDID, NULL, 0, WMI_GET_SSID_EVENTID, | ||
726 | &reply, sizeof(reply), 20); | ||
727 | if (rc) | ||
728 | return rc; | ||
729 | |||
730 | len = le32_to_cpu(reply.cmd.ssid_len); | ||
731 | if (len > sizeof(reply.cmd.ssid)) | ||
732 | return -EINVAL; | ||
733 | |||
734 | *ssid_len = len; | ||
735 | memcpy(ssid, reply.cmd.ssid, len); | ||
736 | |||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | int wmi_set_channel(struct wil6210_priv *wil, int channel) | ||
741 | { | ||
742 | struct wmi_set_pcp_channel_cmd cmd = { | ||
743 | .channel = channel - 1, | ||
744 | }; | ||
745 | |||
746 | return wmi_send(wil, WMI_SET_PCP_CHANNEL_CMDID, &cmd, sizeof(cmd)); | ||
747 | } | ||
748 | |||
749 | int wmi_get_channel(struct wil6210_priv *wil, int *channel) | ||
750 | { | ||
751 | int rc; | ||
752 | struct { | ||
753 | struct wil6210_mbox_hdr_wmi wmi; | ||
754 | struct wmi_set_pcp_channel_cmd cmd; | ||
755 | } __packed reply; | ||
756 | |||
757 | rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, NULL, 0, | ||
758 | WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), 20); | ||
759 | if (rc) | ||
760 | return rc; | ||
761 | |||
762 | if (reply.cmd.channel > 3) | ||
763 | return -EINVAL; | ||
764 | |||
765 | *channel = reply.cmd.channel + 1; | ||
766 | |||
767 | return 0; | ||
768 | } | ||
769 | |||
770 | int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb) | ||
771 | { | ||
772 | struct wmi_eapol_tx_cmd *cmd; | ||
773 | struct ethhdr *eth; | ||
774 | u16 eapol_len = skb->len - ETH_HLEN; | ||
775 | void *eapol = skb->data + ETH_HLEN; | ||
776 | uint i; | ||
777 | int rc; | ||
778 | |||
779 | skb_set_mac_header(skb, 0); | ||
780 | eth = eth_hdr(skb); | ||
781 | wil_dbg_WMI(wil, "EAPOL %d bytes to %pM\n", eapol_len, eth->h_dest); | ||
782 | for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { | ||
783 | if (memcmp(wil->dst_addr[i], eth->h_dest, ETH_ALEN) == 0) | ||
784 | goto found_dest; | ||
785 | } | ||
786 | |||
787 | return -EINVAL; | ||
788 | |||
789 | found_dest: | ||
790 | /* find out eapol data & len */ | ||
791 | cmd = kzalloc(sizeof(*cmd) + eapol_len, GFP_KERNEL); | ||
792 | if (!cmd) | ||
793 | return -EINVAL; | ||
794 | |||
795 | memcpy(cmd->dst_mac, eth->h_dest, ETH_ALEN); | ||
796 | cmd->eapol_len = cpu_to_le16(eapol_len); | ||
797 | memcpy(cmd->eapol, eapol, eapol_len); | ||
798 | rc = wmi_send(wil, WMI_EAPOL_TX_CMDID, cmd, sizeof(*cmd) + eapol_len); | ||
799 | kfree(cmd); | ||
800 | |||
801 | return rc; | ||
802 | } | ||
803 | |||
804 | int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index, | ||
805 | const void *mac_addr) | ||
806 | { | ||
807 | struct wmi_delete_cipher_key_cmd cmd = { | ||
808 | .key_index = key_index, | ||
809 | }; | ||
810 | |||
811 | if (mac_addr) | ||
812 | memcpy(cmd.mac, mac_addr, WMI_MAC_LEN); | ||
813 | |||
814 | return wmi_send(wil, WMI_DELETE_CIPHER_KEY_CMDID, &cmd, sizeof(cmd)); | ||
815 | } | ||
816 | |||
817 | int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index, | ||
818 | const void *mac_addr, int key_len, const void *key) | ||
819 | { | ||
820 | struct wmi_add_cipher_key_cmd cmd = { | ||
821 | .key_index = key_index, | ||
822 | .key_usage = WMI_KEY_USE_PAIRWISE, | ||
823 | .key_len = key_len, | ||
824 | }; | ||
825 | |||
826 | if (!key || (key_len > sizeof(cmd.key))) | ||
827 | return -EINVAL; | ||
828 | |||
829 | memcpy(cmd.key, key, key_len); | ||
830 | if (mac_addr) | ||
831 | memcpy(cmd.mac, mac_addr, WMI_MAC_LEN); | ||
832 | |||
833 | return wmi_send(wil, WMI_ADD_CIPHER_KEY_CMDID, &cmd, sizeof(cmd)); | ||
834 | } | ||
835 | |||
836 | int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) | ||
837 | { | ||
838 | int rc; | ||
839 | u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len; | ||
840 | struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL); | ||
841 | if (!cmd) { | ||
842 | wil_err(wil, "kmalloc(%d) failed\n", len); | ||
843 | return -ENOMEM; | ||
844 | } | ||
845 | |||
846 | cmd->mgmt_frm_type = type; | ||
847 | /* BUG: FW API define ieLen as u8. Will fix FW */ | ||
848 | cmd->ie_len = cpu_to_le16(ie_len); | ||
849 | memcpy(cmd->ie_info, ie, ie_len); | ||
850 | rc = wmi_send(wil, WMI_SET_APPIE_CMDID, &cmd, len); | ||
851 | kfree(cmd); | ||
852 | |||
853 | return rc; | ||
854 | } | ||
855 | |||
856 | void wmi_event_flush(struct wil6210_priv *wil) | ||
857 | { | ||
858 | struct pending_wmi_event *evt, *t; | ||
859 | |||
860 | wil_dbg_WMI(wil, "%s()\n", __func__); | ||
861 | |||
862 | list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) { | ||
863 | list_del(&evt->list); | ||
864 | kfree(evt); | ||
865 | } | ||
866 | } | ||
867 | |||
868 | static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id, | ||
869 | void *d, int len) | ||
870 | { | ||
871 | uint i; | ||
872 | |||
873 | for (i = 0; i < ARRAY_SIZE(wmi_evt_handlers); i++) { | ||
874 | if (wmi_evt_handlers[i].eventid == id) { | ||
875 | wmi_evt_handlers[i].handler(wil, id, d, len); | ||
876 | return true; | ||
877 | } | ||
878 | } | ||
879 | |||
880 | return false; | ||
881 | } | ||
882 | |||
883 | static void wmi_event_handle(struct wil6210_priv *wil, | ||
884 | struct wil6210_mbox_hdr *hdr) | ||
885 | { | ||
886 | u16 len = le16_to_cpu(hdr->len); | ||
887 | |||
888 | if ((hdr->type == WIL_MBOX_HDR_TYPE_WMI) && | ||
889 | (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { | ||
890 | struct wil6210_mbox_hdr_wmi *wmi = (void *)(&hdr[1]); | ||
891 | void *evt_data = (void *)(&wmi[1]); | ||
892 | u16 id = le16_to_cpu(wmi->id); | ||
893 | /* check if someone waits for this event */ | ||
894 | if (wil->reply_id && wil->reply_id == id) { | ||
895 | if (wil->reply_buf) { | ||
896 | memcpy(wil->reply_buf, wmi, | ||
897 | min(len, wil->reply_size)); | ||
898 | } else { | ||
899 | wmi_evt_call_handler(wil, id, evt_data, | ||
900 | len - sizeof(*wmi)); | ||
901 | } | ||
902 | wil_dbg_WMI(wil, "Complete WMI 0x%04x\n", id); | ||
903 | complete(&wil->wmi_ready); | ||
904 | return; | ||
905 | } | ||
906 | /* unsolicited event */ | ||
907 | /* search for handler */ | ||
908 | if (!wmi_evt_call_handler(wil, id, evt_data, | ||
909 | len - sizeof(*wmi))) { | ||
910 | wil_err(wil, "Unhandled event 0x%04x\n", id); | ||
911 | } | ||
912 | } else { | ||
913 | wil_err(wil, "Unknown event type\n"); | ||
914 | print_hex_dump(KERN_ERR, "evt?? ", DUMP_PREFIX_OFFSET, 16, 1, | ||
915 | hdr, sizeof(*hdr) + len, true); | ||
916 | } | ||
917 | } | ||
918 | |||
919 | /* | ||
920 | * Retrieve next WMI event from the pending list | ||
921 | */ | ||
922 | static struct list_head *next_wmi_ev(struct wil6210_priv *wil) | ||
923 | { | ||
924 | ulong flags; | ||
925 | struct list_head *ret = NULL; | ||
926 | |||
927 | spin_lock_irqsave(&wil->wmi_ev_lock, flags); | ||
928 | |||
929 | if (!list_empty(&wil->pending_wmi_ev)) { | ||
930 | ret = wil->pending_wmi_ev.next; | ||
931 | list_del(ret); | ||
932 | } | ||
933 | |||
934 | spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); | ||
935 | |||
936 | return ret; | ||
937 | } | ||
938 | |||
939 | /* | ||
940 | * Handler for the WMI events | ||
941 | */ | ||
942 | void wmi_event_worker(struct work_struct *work) | ||
943 | { | ||
944 | struct wil6210_priv *wil = container_of(work, struct wil6210_priv, | ||
945 | wmi_event_worker); | ||
946 | struct pending_wmi_event *evt; | ||
947 | struct list_head *lh; | ||
948 | |||
949 | while ((lh = next_wmi_ev(wil)) != NULL) { | ||
950 | evt = list_entry(lh, struct pending_wmi_event, list); | ||
951 | wmi_event_handle(wil, &evt->event.hdr); | ||
952 | kfree(evt); | ||
953 | } | ||
954 | } | ||
955 | |||
956 | void wmi_connect_worker(struct work_struct *work) | ||
957 | { | ||
958 | int rc; | ||
959 | struct wil6210_priv *wil = container_of(work, struct wil6210_priv, | ||
960 | wmi_connect_worker); | ||
961 | |||
962 | if (wil->pending_connect_cid < 0) { | ||
963 | wil_err(wil, "No connection pending\n"); | ||
964 | return; | ||
965 | } | ||
966 | |||
967 | wil_dbg_WMI(wil, "Configure for connection CID %d\n", | ||
968 | wil->pending_connect_cid); | ||
969 | |||
970 | rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, | ||
971 | wil->pending_connect_cid, 0); | ||
972 | wil->pending_connect_cid = -1; | ||
973 | if (rc == 0) | ||
974 | wil_link_on(wil); | ||
975 | } | ||
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h new file mode 100644 index 000000000000..3bbf87572b07 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/wmi.h | |||
@@ -0,0 +1,1116 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * Copyright (c) 2006-2012 Wilocity . | ||
4 | * | ||
5 | * Permission to use, copy, modify, and/or distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * This file contains the definitions of the WMI protocol specified in the | ||
20 | * Wireless Module Interface (WMI) for the Wilocity | ||
21 | * MARLON 60 Gigabit wireless solution. | ||
22 | * It includes definitions of all the commands and events. | ||
23 | * Commands are messages from the host to the WM. | ||
24 | * Events are messages from the WM to the host. | ||
25 | */ | ||
26 | |||
27 | #ifndef __WILOCITY_WMI_H__ | ||
28 | #define __WILOCITY_WMI_H__ | ||
29 | |||
30 | /* General */ | ||
31 | |||
32 | #define WMI_MAC_LEN (6) | ||
33 | #define WMI_PROX_RANGE_NUM (3) | ||
34 | |||
35 | /* List of Commands */ | ||
36 | enum wmi_command_id { | ||
37 | WMI_CONNECT_CMDID = 0x0001, | ||
38 | WMI_DISCONNECT_CMDID = 0x0003, | ||
39 | WMI_START_SCAN_CMDID = 0x0007, | ||
40 | WMI_SET_BSS_FILTER_CMDID = 0x0009, | ||
41 | WMI_SET_PROBED_SSID_CMDID = 0x000a, | ||
42 | WMI_SET_LISTEN_INT_CMDID = 0x000b, | ||
43 | WMI_BCON_CTRL_CMDID = 0x000f, | ||
44 | WMI_ADD_CIPHER_KEY_CMDID = 0x0016, | ||
45 | WMI_DELETE_CIPHER_KEY_CMDID = 0x0017, | ||
46 | WMI_SET_APPIE_CMDID = 0x003f, | ||
47 | WMI_GET_APPIE_CMDID = 0x0040, | ||
48 | WMI_SET_WSC_STATUS_CMDID = 0x0041, | ||
49 | WMI_PXMT_RANGE_CFG_CMDID = 0x0042, | ||
50 | WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x0043, | ||
51 | WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300, | ||
52 | WMI_MEM_READ_CMDID = 0x0800, | ||
53 | WMI_MEM_WR_CMDID = 0x0801, | ||
54 | WMI_ECHO_CMDID = 0x0803, | ||
55 | WMI_DEEP_ECHO_CMDID = 0x0804, | ||
56 | WMI_CONFIG_MAC_CMDID = 0x0805, | ||
57 | WMI_CONFIG_PHY_DEBUG_CMDID = 0x0806, | ||
58 | WMI_ADD_STATION_CMDID = 0x0807, | ||
59 | WMI_ADD_DEBUG_TX_PCKT_CMDID = 0x0808, | ||
60 | WMI_PHY_GET_STATISTICS_CMDID = 0x0809, | ||
61 | WMI_FS_TUNE_CMDID = 0x080a, | ||
62 | WMI_CORR_MEASURE_CMDID = 0x080b, | ||
63 | WMI_TEMP_SENSE_CMDID = 0x080e, | ||
64 | WMI_DC_CALIB_CMDID = 0x080f, | ||
65 | WMI_SEND_TONE_CMDID = 0x0810, | ||
66 | WMI_IQ_TX_CALIB_CMDID = 0x0811, | ||
67 | WMI_IQ_RX_CALIB_CMDID = 0x0812, | ||
68 | WMI_SET_UCODE_IDLE_CMDID = 0x0813, | ||
69 | WMI_SET_WORK_MODE_CMDID = 0x0815, | ||
70 | WMI_LO_LEAKAGE_CALIB_CMDID = 0x0816, | ||
71 | WMI_MARLON_R_ACTIVATE_CMDID = 0x0817, | ||
72 | WMI_MARLON_R_READ_CMDID = 0x0818, | ||
73 | WMI_MARLON_R_WRITE_CMDID = 0x0819, | ||
74 | WMI_MARLON_R_TXRX_SEL_CMDID = 0x081a, | ||
75 | MAC_IO_STATIC_PARAMS_CMDID = 0x081b, | ||
76 | MAC_IO_DYNAMIC_PARAMS_CMDID = 0x081c, | ||
77 | WMI_SILENT_RSSI_CALIB_CMDID = 0x081d, | ||
78 | WMI_CFG_RX_CHAIN_CMDID = 0x0820, | ||
79 | WMI_VRING_CFG_CMDID = 0x0821, | ||
80 | WMI_RX_ON_CMDID = 0x0822, | ||
81 | WMI_VRING_BA_EN_CMDID = 0x0823, | ||
82 | WMI_VRING_BA_DIS_CMDID = 0x0824, | ||
83 | WMI_RCP_ADDBA_RESP_CMDID = 0x0825, | ||
84 | WMI_RCP_DELBA_CMDID = 0x0826, | ||
85 | WMI_SET_SSID_CMDID = 0x0827, | ||
86 | WMI_GET_SSID_CMDID = 0x0828, | ||
87 | WMI_SET_PCP_CHANNEL_CMDID = 0x0829, | ||
88 | WMI_GET_PCP_CHANNEL_CMDID = 0x082a, | ||
89 | WMI_SW_TX_REQ_CMDID = 0x082b, | ||
90 | WMI_RX_OFF_CMDID = 0x082c, | ||
91 | WMI_READ_MAC_RXQ_CMDID = 0x0830, | ||
92 | WMI_READ_MAC_TXQ_CMDID = 0x0831, | ||
93 | WMI_WRITE_MAC_RXQ_CMDID = 0x0832, | ||
94 | WMI_WRITE_MAC_TXQ_CMDID = 0x0833, | ||
95 | WMI_WRITE_MAC_XQ_FIELD_CMDID = 0x0834, | ||
96 | WMI_MLME_PUSH_CMDID = 0x0835, | ||
97 | WMI_BEAMFORMING_MGMT_CMDID = 0x0836, | ||
98 | WMI_BF_TXSS_MGMT_CMDID = 0x0837, | ||
99 | WMI_BF_SM_MGMT_CMDID = 0x0838, | ||
100 | WMI_BF_RXSS_MGMT_CMDID = 0x0839, | ||
101 | WMI_SET_SECTORS_CMDID = 0x0849, | ||
102 | WMI_MAINTAIN_PAUSE_CMDID = 0x0850, | ||
103 | WMI_MAINTAIN_RESUME_CMDID = 0x0851, | ||
104 | WMI_RS_MGMT_CMDID = 0x0852, | ||
105 | WMI_RF_MGMT_CMDID = 0x0853, | ||
106 | /* Performance monitoring commands */ | ||
107 | WMI_BF_CTRL_CMDID = 0x0862, | ||
108 | WMI_NOTIFY_REQ_CMDID = 0x0863, | ||
109 | WMI_GET_STATUS_CMDID = 0x0864, | ||
110 | WMI_UNIT_TEST_CMDID = 0x0900, | ||
111 | WMI_HICCUP_CMDID = 0x0901, | ||
112 | WMI_FLASH_READ_CMDID = 0x0902, | ||
113 | WMI_FLASH_WRITE_CMDID = 0x0903, | ||
114 | WMI_SECURITY_UNIT_TEST_CMDID = 0x0904, | ||
115 | |||
116 | WMI_SET_MAC_ADDRESS_CMDID = 0xf003, | ||
117 | WMI_ABORT_SCAN_CMDID = 0xf007, | ||
118 | WMI_SET_PMK_CMDID = 0xf028, | ||
119 | |||
120 | WMI_SET_PROMISCUOUS_MODE_CMDID = 0xf041, | ||
121 | WMI_GET_PMK_CMDID = 0xf048, | ||
122 | WMI_SET_PASSPHRASE_CMDID = 0xf049, | ||
123 | WMI_SEND_ASSOC_RES_CMDID = 0xf04a, | ||
124 | WMI_SET_ASSOC_REQ_RELAY_CMDID = 0xf04b, | ||
125 | WMI_EAPOL_TX_CMDID = 0xf04c, | ||
126 | WMI_MAC_ADDR_REQ_CMDID = 0xf04d, | ||
127 | WMI_FW_VER_CMDID = 0xf04e, | ||
128 | }; | ||
129 | |||
130 | /* | ||
131 | * Commands data structures | ||
132 | */ | ||
133 | |||
134 | /* | ||
135 | * Frame Types | ||
136 | */ | ||
137 | enum wmi_mgmt_frame_type { | ||
138 | WMI_FRAME_BEACON = 0, | ||
139 | WMI_FRAME_PROBE_REQ = 1, | ||
140 | WMI_FRAME_PROBE_RESP = 2, | ||
141 | WMI_FRAME_ASSOC_REQ = 3, | ||
142 | WMI_FRAME_ASSOC_RESP = 4, | ||
143 | WMI_NUM_MGMT_FRAME, | ||
144 | }; | ||
145 | |||
146 | /* | ||
147 | * WMI_CONNECT_CMDID | ||
148 | */ | ||
149 | enum wmi_network_type { | ||
150 | WMI_NETTYPE_INFRA = 0x01, | ||
151 | WMI_NETTYPE_ADHOC = 0x02, | ||
152 | WMI_NETTYPE_ADHOC_CREATOR = 0x04, | ||
153 | WMI_NETTYPE_AP = 0x10, | ||
154 | WMI_NETTYPE_P2P = 0x20, | ||
155 | WMI_NETTYPE_WBE = 0x40, /* PCIE over 60g */ | ||
156 | }; | ||
157 | |||
158 | enum wmi_dot11_auth_mode { | ||
159 | WMI_AUTH11_OPEN = 0x01, | ||
160 | WMI_AUTH11_SHARED = 0x02, | ||
161 | WMI_AUTH11_LEAP = 0x04, | ||
162 | WMI_AUTH11_WSC = 0x08, | ||
163 | }; | ||
164 | |||
165 | enum wmi_auth_mode { | ||
166 | WMI_AUTH_NONE = 0x01, | ||
167 | WMI_AUTH_WPA = 0x02, | ||
168 | WMI_AUTH_WPA2 = 0x04, | ||
169 | WMI_AUTH_WPA_PSK = 0x08, | ||
170 | WMI_AUTH_WPA2_PSK = 0x10, | ||
171 | WMI_AUTH_WPA_CCKM = 0x20, | ||
172 | WMI_AUTH_WPA2_CCKM = 0x40, | ||
173 | }; | ||
174 | |||
175 | enum wmi_crypto_type { | ||
176 | WMI_CRYPT_NONE = 0x01, | ||
177 | WMI_CRYPT_WEP = 0x02, | ||
178 | WMI_CRYPT_TKIP = 0x04, | ||
179 | WMI_CRYPT_AES = 0x08, | ||
180 | WMI_CRYPT_AES_GCMP = 0x20, | ||
181 | }; | ||
182 | |||
183 | |||
184 | enum wmi_connect_ctrl_flag_bits { | ||
185 | WMI_CONNECT_ASSOC_POLICY_USER = 0x0001, | ||
186 | WMI_CONNECT_SEND_REASSOC = 0x0002, | ||
187 | WMI_CONNECT_IGNORE_WPAx_GROUP_CIPHER = 0x0004, | ||
188 | WMI_CONNECT_PROFILE_MATCH_DONE = 0x0008, | ||
189 | WMI_CONNECT_IGNORE_AAC_BEACON = 0x0010, | ||
190 | WMI_CONNECT_CSA_FOLLOW_BSS = 0x0020, | ||
191 | WMI_CONNECT_DO_WPA_OFFLOAD = 0x0040, | ||
192 | WMI_CONNECT_DO_NOT_DEAUTH = 0x0080, | ||
193 | }; | ||
194 | |||
195 | #define WMI_MAX_SSID_LEN (32) | ||
196 | |||
197 | struct wmi_connect_cmd { | ||
198 | u8 network_type; | ||
199 | u8 dot11_auth_mode; | ||
200 | u8 auth_mode; | ||
201 | u8 pairwise_crypto_type; | ||
202 | u8 pairwise_crypto_len; | ||
203 | u8 group_crypto_type; | ||
204 | u8 group_crypto_len; | ||
205 | u8 ssid_len; | ||
206 | u8 ssid[WMI_MAX_SSID_LEN]; | ||
207 | u8 channel; | ||
208 | u8 reserved0; | ||
209 | u8 bssid[WMI_MAC_LEN]; | ||
210 | __le32 ctrl_flags; | ||
211 | u8 dst_mac[WMI_MAC_LEN]; | ||
212 | u8 reserved1[2]; | ||
213 | } __packed; | ||
214 | |||
215 | |||
216 | /* | ||
217 | * WMI_RECONNECT_CMDID | ||
218 | */ | ||
219 | struct wmi_reconnect_cmd { | ||
220 | u8 channel; /* hint */ | ||
221 | u8 reserved; | ||
222 | u8 bssid[WMI_MAC_LEN]; /* mandatory if set */ | ||
223 | } __packed; | ||
224 | |||
225 | |||
226 | /* | ||
227 | * WMI_SET_PMK_CMDID | ||
228 | */ | ||
229 | |||
230 | #define WMI_MIN_KEY_INDEX (0) | ||
231 | #define WMI_MAX_KEY_INDEX (3) | ||
232 | #define WMI_MAX_KEY_LEN (32) | ||
233 | #define WMI_PASSPHRASE_LEN (64) | ||
234 | #define WMI_PMK_LEN (32) | ||
235 | |||
236 | struct wmi_set_pmk_cmd { | ||
237 | u8 pmk[WMI_PMK_LEN]; | ||
238 | } __packed; | ||
239 | |||
240 | |||
241 | /* | ||
242 | * WMI_SET_PASSPHRASE_CMDID | ||
243 | */ | ||
244 | struct wmi_set_passphrase_cmd { | ||
245 | u8 ssid[WMI_MAX_SSID_LEN]; | ||
246 | u8 passphrase[WMI_PASSPHRASE_LEN]; | ||
247 | u8 ssid_len; | ||
248 | u8 passphrase_len; | ||
249 | } __packed; | ||
250 | |||
251 | /* | ||
252 | * WMI_ADD_CIPHER_KEY_CMDID | ||
253 | */ | ||
254 | enum wmi_key_usage { | ||
255 | WMI_KEY_USE_PAIRWISE = 0, | ||
256 | WMI_KEY_USE_GROUP = 1, | ||
257 | WMI_KEY_USE_TX = 2, /* default Tx Key - Static WEP only */ | ||
258 | }; | ||
259 | |||
260 | struct wmi_add_cipher_key_cmd { | ||
261 | u8 key_index; | ||
262 | u8 key_type; | ||
263 | u8 key_usage; /* enum wmi_key_usage */ | ||
264 | u8 key_len; | ||
265 | u8 key_rsc[8]; /* key replay sequence counter */ | ||
266 | u8 key[WMI_MAX_KEY_LEN]; | ||
267 | u8 key_op_ctrl; /* Additional Key Control information */ | ||
268 | u8 mac[WMI_MAC_LEN]; | ||
269 | } __packed; | ||
270 | |||
271 | /* | ||
272 | * WMI_DELETE_CIPHER_KEY_CMDID | ||
273 | */ | ||
274 | struct wmi_delete_cipher_key_cmd { | ||
275 | u8 key_index; | ||
276 | u8 mac[WMI_MAC_LEN]; | ||
277 | } __packed; | ||
278 | |||
279 | |||
280 | /* | ||
281 | * WMI_START_SCAN_CMDID | ||
282 | * | ||
283 | * Start L1 scan operation | ||
284 | * | ||
285 | * Returned events: | ||
286 | * - WMI_RX_MGMT_PACKET_EVENTID - for every probe resp. | ||
287 | * - WMI_SCAN_COMPLETE_EVENTID | ||
288 | */ | ||
289 | enum wmi_scan_type { | ||
290 | WMI_LONG_SCAN = 0, | ||
291 | WMI_SHORT_SCAN = 1, | ||
292 | }; | ||
293 | |||
294 | struct wmi_start_scan_cmd { | ||
295 | u8 reserved[8]; | ||
296 | __le32 home_dwell_time; /* Max duration in the home channel(ms) */ | ||
297 | __le32 force_scan_interval; /* Time interval between scans (ms)*/ | ||
298 | u8 scan_type; /* wmi_scan_type */ | ||
299 | u8 num_channels; /* how many channels follow */ | ||
300 | struct { | ||
301 | u8 channel; | ||
302 | u8 reserved; | ||
303 | } channel_list[0]; /* channels ID's */ | ||
304 | /* 0 - 58320 MHz */ | ||
305 | /* 1 - 60480 MHz */ | ||
306 | /* 2 - 62640 MHz */ | ||
307 | } __packed; | ||
308 | |||
309 | /* | ||
310 | * WMI_SET_PROBED_SSID_CMDID | ||
311 | */ | ||
312 | #define MAX_PROBED_SSID_INDEX (15) | ||
313 | |||
314 | enum wmi_ssid_flag { | ||
315 | WMI_SSID_FLAG_DISABLE = 0, /* disables entry */ | ||
316 | WMI_SSID_FLAG_SPECIFIC = 1, /* probes specified ssid */ | ||
317 | WMI_SSID_FLAG_ANY = 2, /* probes for any ssid */ | ||
318 | }; | ||
319 | |||
320 | struct wmi_probed_ssid_cmd { | ||
321 | u8 entry_index; /* 0 to MAX_PROBED_SSID_INDEX */ | ||
322 | u8 flag; /* enum wmi_ssid_flag */ | ||
323 | u8 ssid_len; | ||
324 | u8 ssid[WMI_MAX_SSID_LEN]; | ||
325 | } __packed; | ||
326 | |||
327 | /* | ||
328 | * WMI_SET_APPIE_CMDID | ||
329 | * Add Application specified IE to a management frame | ||
330 | */ | ||
331 | struct wmi_set_appie_cmd { | ||
332 | u8 mgmt_frm_type; /* enum wmi_mgmt_frame_type */ | ||
333 | u8 reserved; | ||
334 | __le16 ie_len; /* Length of the IE to be added to MGMT frame */ | ||
335 | u8 ie_info[0]; | ||
336 | } __packed; | ||
337 | |||
338 | #define WMI_MAX_IE_LEN (1024) | ||
339 | |||
340 | struct wmi_pxmt_range_cfg_cmd { | ||
341 | u8 dst_mac[WMI_MAC_LEN]; | ||
342 | __le16 range; | ||
343 | } __packed; | ||
344 | |||
345 | struct wmi_pxmt_snr2_range_cfg_cmd { | ||
346 | s8 snr2range_arr[WMI_PROX_RANGE_NUM-1]; | ||
347 | } __packed; | ||
348 | |||
349 | /* | ||
350 | * WMI_RF_MGMT_CMDID | ||
351 | */ | ||
352 | enum wmi_rf_mgmt_type { | ||
353 | WMI_RF_MGMT_W_DISABLE = 0, | ||
354 | WMI_RF_MGMT_W_ENABLE = 1, | ||
355 | WMI_RF_MGMT_GET_STATUS = 2, | ||
356 | }; | ||
357 | |||
358 | struct wmi_rf_mgmt_cmd { | ||
359 | __le32 rf_mgmt_type; | ||
360 | } __packed; | ||
361 | |||
362 | /* | ||
363 | * WMI_SET_SSID_CMDID | ||
364 | */ | ||
365 | struct wmi_set_ssid_cmd { | ||
366 | __le32 ssid_len; | ||
367 | u8 ssid[WMI_MAX_SSID_LEN]; | ||
368 | } __packed; | ||
369 | |||
370 | /* | ||
371 | * WMI_SET_PCP_CHANNEL_CMDID | ||
372 | */ | ||
373 | struct wmi_set_pcp_channel_cmd { | ||
374 | u8 channel; | ||
375 | u8 reserved[3]; | ||
376 | } __packed; | ||
377 | |||
378 | /* | ||
379 | * WMI_BCON_CTRL_CMDID | ||
380 | */ | ||
381 | struct wmi_bcon_ctrl_cmd { | ||
382 | __le16 bcon_interval; | ||
383 | __le16 frag_num; | ||
384 | __le64 ss_mask; | ||
385 | u8 network_type; | ||
386 | u8 reserved; | ||
387 | u8 disable_sec_offload; | ||
388 | u8 disable_sec; | ||
389 | } __packed; | ||
390 | |||
391 | /* | ||
392 | * WMI_SW_TX_REQ_CMDID | ||
393 | */ | ||
394 | struct wmi_sw_tx_req_cmd { | ||
395 | u8 dst_mac[WMI_MAC_LEN]; | ||
396 | __le16 len; | ||
397 | u8 payload[0]; | ||
398 | } __packed; | ||
399 | |||
400 | /* | ||
401 | * WMI_VRING_CFG_CMDID | ||
402 | */ | ||
403 | |||
404 | struct wmi_sw_ring_cfg { | ||
405 | __le64 ring_mem_base; | ||
406 | __le16 ring_size; | ||
407 | __le16 max_mpdu_size; | ||
408 | } __packed; | ||
409 | |||
410 | struct wmi_vring_cfg_schd { | ||
411 | __le16 priority; | ||
412 | __le16 timeslot_us; | ||
413 | } __packed; | ||
414 | |||
415 | enum wmi_vring_cfg_encap_trans_type { | ||
416 | WMI_VRING_ENC_TYPE_802_3 = 0, | ||
417 | WMI_VRING_ENC_TYPE_NATIVE_WIFI = 1, | ||
418 | }; | ||
419 | |||
420 | enum wmi_vring_cfg_ds_cfg { | ||
421 | WMI_VRING_DS_PBSS = 0, | ||
422 | WMI_VRING_DS_STATION = 1, | ||
423 | WMI_VRING_DS_AP = 2, | ||
424 | WMI_VRING_DS_ADDR4 = 3, | ||
425 | }; | ||
426 | |||
427 | enum wmi_vring_cfg_nwifi_ds_trans_type { | ||
428 | WMI_NWIFI_TX_TRANS_MODE_NO = 0, | ||
429 | WMI_NWIFI_TX_TRANS_MODE_AP2PBSS = 1, | ||
430 | WMI_NWIFI_TX_TRANS_MODE_STA2PBSS = 2, | ||
431 | }; | ||
432 | |||
433 | enum wmi_vring_cfg_schd_params_priority { | ||
434 | WMI_SCH_PRIO_REGULAR = 0, | ||
435 | WMI_SCH_PRIO_HIGH = 1, | ||
436 | }; | ||
437 | |||
438 | struct wmi_vring_cfg { | ||
439 | struct wmi_sw_ring_cfg tx_sw_ring; | ||
440 | u8 ringid; /* 0-23 vrings */ | ||
441 | |||
442 | #define CIDXTID_CID_POS (0) | ||
443 | #define CIDXTID_CID_LEN (4) | ||
444 | #define CIDXTID_CID_MSK (0xF) | ||
445 | #define CIDXTID_TID_POS (4) | ||
446 | #define CIDXTID_TID_LEN (4) | ||
447 | #define CIDXTID_TID_MSK (0xF0) | ||
448 | u8 cidxtid; | ||
449 | |||
450 | u8 encap_trans_type; | ||
451 | u8 ds_cfg; /* 802.3 DS cfg */ | ||
452 | u8 nwifi_ds_trans_type; | ||
453 | |||
454 | #define VRING_CFG_MAC_CTRL_LIFETIME_EN_POS (0) | ||
455 | #define VRING_CFG_MAC_CTRL_LIFETIME_EN_LEN (1) | ||
456 | #define VRING_CFG_MAC_CTRL_LIFETIME_EN_MSK (0x1) | ||
457 | #define VRING_CFG_MAC_CTRL_AGGR_EN_POS (1) | ||
458 | #define VRING_CFG_MAC_CTRL_AGGR_EN_LEN (1) | ||
459 | #define VRING_CFG_MAC_CTRL_AGGR_EN_MSK (0x2) | ||
460 | u8 mac_ctrl; | ||
461 | |||
462 | #define VRING_CFG_TO_RESOLUTION_VALUE_POS (0) | ||
463 | #define VRING_CFG_TO_RESOLUTION_VALUE_LEN (6) | ||
464 | #define VRING_CFG_TO_RESOLUTION_VALUE_MSK (0x3F) | ||
465 | u8 to_resolution; | ||
466 | u8 agg_max_wsize; | ||
467 | struct wmi_vring_cfg_schd schd_params; | ||
468 | } __packed; | ||
469 | |||
470 | enum wmi_vring_cfg_cmd_action { | ||
471 | WMI_VRING_CMD_ADD = 0, | ||
472 | WMI_VRING_CMD_MODIFY = 1, | ||
473 | WMI_VRING_CMD_DELETE = 2, | ||
474 | }; | ||
475 | |||
476 | struct wmi_vring_cfg_cmd { | ||
477 | __le32 action; | ||
478 | struct wmi_vring_cfg vring_cfg; | ||
479 | } __packed; | ||
480 | |||
481 | /* | ||
482 | * WMI_VRING_BA_EN_CMDID | ||
483 | */ | ||
484 | struct wmi_vring_ba_en_cmd { | ||
485 | u8 ringid; | ||
486 | u8 agg_max_wsize; | ||
487 | __le16 ba_timeout; | ||
488 | } __packed; | ||
489 | |||
490 | /* | ||
491 | * WMI_VRING_BA_DIS_CMDID | ||
492 | */ | ||
493 | struct wmi_vring_ba_dis_cmd { | ||
494 | u8 ringid; | ||
495 | u8 reserved; | ||
496 | __le16 reason; | ||
497 | } __packed; | ||
498 | |||
499 | /* | ||
500 | * WMI_NOTIFY_REQ_CMDID | ||
501 | */ | ||
502 | struct wmi_notify_req_cmd { | ||
503 | u8 cid; | ||
504 | u8 reserved[3]; | ||
505 | __le32 interval_usec; | ||
506 | } __packed; | ||
507 | |||
508 | /* | ||
509 | * WMI_CFG_RX_CHAIN_CMDID | ||
510 | */ | ||
511 | enum wmi_sniffer_cfg_mode { | ||
512 | WMI_SNIFFER_OFF = 0, | ||
513 | WMI_SNIFFER_ON = 1, | ||
514 | }; | ||
515 | |||
516 | enum wmi_sniffer_cfg_phy_info_mode { | ||
517 | WMI_SNIFFER_PHY_INFO_DISABLED = 0, | ||
518 | WMI_SNIFFER_PHY_INFO_ENABLED = 1, | ||
519 | }; | ||
520 | |||
521 | enum wmi_sniffer_cfg_phy_support { | ||
522 | WMI_SNIFFER_CP = 0, | ||
523 | WMI_SNIFFER_DP = 1, | ||
524 | WMI_SNIFFER_BOTH_PHYS = 2, | ||
525 | }; | ||
526 | |||
527 | struct wmi_sniffer_cfg { | ||
528 | __le32 mode; /* enum wmi_sniffer_cfg_mode */ | ||
529 | __le32 phy_info_mode; /* enum wmi_sniffer_cfg_phy_info_mode */ | ||
530 | __le32 phy_support; /* enum wmi_sniffer_cfg_phy_support */ | ||
531 | u8 channel; | ||
532 | u8 reserved[3]; | ||
533 | } __packed; | ||
534 | |||
535 | enum wmi_cfg_rx_chain_cmd_action { | ||
536 | WMI_RX_CHAIN_ADD = 0, | ||
537 | WMI_RX_CHAIN_DEL = 1, | ||
538 | }; | ||
539 | |||
540 | enum wmi_cfg_rx_chain_cmd_decap_trans_type { | ||
541 | WMI_DECAP_TYPE_802_3 = 0, | ||
542 | WMI_DECAP_TYPE_NATIVE_WIFI = 1, | ||
543 | }; | ||
544 | |||
545 | enum wmi_cfg_rx_chain_cmd_nwifi_ds_trans_type { | ||
546 | WMI_NWIFI_RX_TRANS_MODE_NO = 0, | ||
547 | WMI_NWIFI_RX_TRANS_MODE_PBSS2AP = 1, | ||
548 | WMI_NWIFI_RX_TRANS_MODE_PBSS2STA = 2, | ||
549 | }; | ||
550 | |||
551 | struct wmi_cfg_rx_chain_cmd { | ||
552 | __le32 action; | ||
553 | struct wmi_sw_ring_cfg rx_sw_ring; | ||
554 | u8 mid; | ||
555 | u8 decap_trans_type; | ||
556 | |||
557 | #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_POS (0) | ||
558 | #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_LEN (1) | ||
559 | #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_MSK (0x1) | ||
560 | u8 l2_802_3_offload_ctrl; | ||
561 | |||
562 | #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_POS (0) | ||
563 | #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_LEN (1) | ||
564 | #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_MSK (0x1) | ||
565 | #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_POS (1) | ||
566 | #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_LEN (1) | ||
567 | #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_MSK (0x2) | ||
568 | u8 l2_nwifi_offload_ctrl; | ||
569 | |||
570 | u8 vlan_id; | ||
571 | u8 nwifi_ds_trans_type; | ||
572 | |||
573 | #define L3_L4_CTRL_IPV4_CHECKSUM_EN_POS (0) | ||
574 | #define L3_L4_CTRL_IPV4_CHECKSUM_EN_LEN (1) | ||
575 | #define L3_L4_CTRL_IPV4_CHECKSUM_EN_MSK (0x1) | ||
576 | #define L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS (1) | ||
577 | #define L3_L4_CTRL_TCPIP_CHECKSUM_EN_LEN (1) | ||
578 | #define L3_L4_CTRL_TCPIP_CHECKSUM_EN_MSK (0x2) | ||
579 | u8 l3_l4_ctrl; | ||
580 | |||
581 | #define RING_CTRL_OVERRIDE_PREFETCH_THRSH_POS (0) | ||
582 | #define RING_CTRL_OVERRIDE_PREFETCH_THRSH_LEN (1) | ||
583 | #define RING_CTRL_OVERRIDE_PREFETCH_THRSH_MSK (0x1) | ||
584 | #define RING_CTRL_OVERRIDE_WB_THRSH_POS (1) | ||
585 | #define RING_CTRL_OVERRIDE_WB_THRSH_LEN (1) | ||
586 | #define RING_CTRL_OVERRIDE_WB_THRSH_MSK (0x2) | ||
587 | #define RING_CTRL_OVERRIDE_ITR_THRSH_POS (2) | ||
588 | #define RING_CTRL_OVERRIDE_ITR_THRSH_LEN (1) | ||
589 | #define RING_CTRL_OVERRIDE_ITR_THRSH_MSK (0x4) | ||
590 | #define RING_CTRL_OVERRIDE_HOST_THRSH_POS (3) | ||
591 | #define RING_CTRL_OVERRIDE_HOST_THRSH_LEN (1) | ||
592 | #define RING_CTRL_OVERRIDE_HOST_THRSH_MSK (0x8) | ||
593 | u8 ring_ctrl; | ||
594 | |||
595 | __le16 prefetch_thrsh; | ||
596 | __le16 wb_thrsh; | ||
597 | __le32 itr_value; | ||
598 | __le16 host_thrsh; | ||
599 | u8 reserved[2]; | ||
600 | struct wmi_sniffer_cfg sniffer_cfg; | ||
601 | } __packed; | ||
602 | |||
603 | /* | ||
604 | * WMI_RCP_ADDBA_RESP_CMDID | ||
605 | */ | ||
606 | struct wmi_rcp_addba_resp_cmd { | ||
607 | |||
608 | #define CIDXTID_CID_POS (0) | ||
609 | #define CIDXTID_CID_LEN (4) | ||
610 | #define CIDXTID_CID_MSK (0xF) | ||
611 | #define CIDXTID_TID_POS (4) | ||
612 | #define CIDXTID_TID_LEN (4) | ||
613 | #define CIDXTID_TID_MSK (0xF0) | ||
614 | u8 cidxtid; | ||
615 | |||
616 | u8 dialog_token; | ||
617 | __le16 status_code; | ||
618 | __le16 ba_param_set; /* ieee80211_ba_parameterset field to send */ | ||
619 | __le16 ba_timeout; | ||
620 | } __packed; | ||
621 | |||
622 | /* | ||
623 | * WMI_RCP_DELBA_CMDID | ||
624 | */ | ||
625 | struct wmi_rcp_delba_cmd { | ||
626 | |||
627 | #define CIDXTID_CID_POS (0) | ||
628 | #define CIDXTID_CID_LEN (4) | ||
629 | #define CIDXTID_CID_MSK (0xF) | ||
630 | #define CIDXTID_TID_POS (4) | ||
631 | #define CIDXTID_TID_LEN (4) | ||
632 | #define CIDXTID_TID_MSK (0xF0) | ||
633 | u8 cidxtid; | ||
634 | |||
635 | u8 reserved; | ||
636 | __le16 reason; | ||
637 | } __packed; | ||
638 | |||
639 | /* | ||
640 | * WMI_RCP_ADDBA_REQ_CMDID | ||
641 | */ | ||
642 | struct wmi_rcp_addba_req_cmd { | ||
643 | |||
644 | #define CIDXTID_CID_POS (0) | ||
645 | #define CIDXTID_CID_LEN (4) | ||
646 | #define CIDXTID_CID_MSK (0xF) | ||
647 | #define CIDXTID_TID_POS (4) | ||
648 | #define CIDXTID_TID_LEN (4) | ||
649 | #define CIDXTID_TID_MSK (0xF0) | ||
650 | u8 cidxtid; | ||
651 | |||
652 | u8 dialog_token; | ||
653 | /* ieee80211_ba_parameterset field as it received */ | ||
654 | __le16 ba_param_set; | ||
655 | __le16 ba_timeout; | ||
656 | /* ieee80211_ba_seqstrl field as it received */ | ||
657 | __le16 ba_seq_ctrl; | ||
658 | } __packed; | ||
659 | |||
660 | /* | ||
661 | * WMI_SET_MAC_ADDRESS_CMDID | ||
662 | */ | ||
663 | struct wmi_set_mac_address_cmd { | ||
664 | u8 mac[WMI_MAC_LEN]; | ||
665 | u8 reserved[2]; | ||
666 | } __packed; | ||
667 | |||
668 | |||
669 | /* | ||
670 | * WMI_EAPOL_TX_CMDID | ||
671 | */ | ||
672 | struct wmi_eapol_tx_cmd { | ||
673 | u8 dst_mac[WMI_MAC_LEN]; | ||
674 | __le16 eapol_len; | ||
675 | u8 eapol[0]; | ||
676 | } __packed; | ||
677 | |||
678 | /* | ||
679 | * WMI_ECHO_CMDID | ||
680 | * | ||
681 | * Check FW is alive | ||
682 | * | ||
683 | * WMI_DEEP_ECHO_CMDID | ||
684 | * | ||
685 | * Check FW and ucode are alive | ||
686 | * | ||
687 | * Returned event: WMI_ECHO_RSP_EVENTID | ||
688 | * same event for both commands | ||
689 | */ | ||
690 | struct wmi_echo_cmd { | ||
691 | __le32 value; | ||
692 | } __packed; | ||
693 | |||
694 | /* | ||
695 | * WMI Events | ||
696 | */ | ||
697 | |||
698 | /* | ||
699 | * List of Events (target to host) | ||
700 | */ | ||
701 | enum wmi_event_id { | ||
702 | WMI_IMM_RSP_EVENTID = 0x0000, | ||
703 | WMI_READY_EVENTID = 0x1001, | ||
704 | WMI_CONNECT_EVENTID = 0x1002, | ||
705 | WMI_DISCONNECT_EVENTID = 0x1003, | ||
706 | WMI_SCAN_COMPLETE_EVENTID = 0x100a, | ||
707 | WMI_REPORT_STATISTICS_EVENTID = 0x100b, | ||
708 | WMI_RD_MEM_RSP_EVENTID = 0x1800, | ||
709 | WMI_FW_READY_EVENTID = 0x1801, | ||
710 | WMI_EXIT_FAST_MEM_ACC_MODE_EVENTID = 0x0200, | ||
711 | WMI_ECHO_RSP_EVENTID = 0x1803, | ||
712 | WMI_CONFIG_MAC_DONE_EVENTID = 0x1805, | ||
713 | WMI_CONFIG_PHY_DEBUG_DONE_EVENTID = 0x1806, | ||
714 | WMI_ADD_STATION_DONE_EVENTID = 0x1807, | ||
715 | WMI_ADD_DEBUG_TX_PCKT_DONE_EVENTID = 0x1808, | ||
716 | WMI_PHY_GET_STATISTICS_EVENTID = 0x1809, | ||
717 | WMI_FS_TUNE_DONE_EVENTID = 0x180a, | ||
718 | WMI_CORR_MEASURE_DONE_EVENTID = 0x180b, | ||
719 | WMI_TEMP_SENSE_DONE_EVENTID = 0x180e, | ||
720 | WMI_DC_CALIB_DONE_EVENTID = 0x180f, | ||
721 | WMI_IQ_TX_CALIB_DONE_EVENTID = 0x1811, | ||
722 | WMI_IQ_RX_CALIB_DONE_EVENTID = 0x1812, | ||
723 | WMI_SET_WORK_MODE_DONE_EVENTID = 0x1815, | ||
724 | WMI_LO_LEAKAGE_CALIB_DONE_EVENTID = 0x1816, | ||
725 | WMI_MARLON_R_ACTIVATE_DONE_EVENTID = 0x1817, | ||
726 | WMI_MARLON_R_READ_DONE_EVENTID = 0x1818, | ||
727 | WMI_MARLON_R_WRITE_DONE_EVENTID = 0x1819, | ||
728 | WMI_MARLON_R_TXRX_SEL_DONE_EVENTID = 0x181a, | ||
729 | WMI_SILENT_RSSI_CALIB_DONE_EVENTID = 0x181d, | ||
730 | |||
731 | WMI_CFG_RX_CHAIN_DONE_EVENTID = 0x1820, | ||
732 | WMI_VRING_CFG_DONE_EVENTID = 0x1821, | ||
733 | WMI_RX_ON_DONE_EVENTID = 0x1822, | ||
734 | WMI_BA_STATUS_EVENTID = 0x1823, | ||
735 | WMI_RCP_ADDBA_REQ_EVENTID = 0x1824, | ||
736 | WMI_ADDBA_RESP_SENT_EVENTID = 0x1825, | ||
737 | WMI_DELBA_EVENTID = 0x1826, | ||
738 | WMI_GET_SSID_EVENTID = 0x1828, | ||
739 | WMI_GET_PCP_CHANNEL_EVENTID = 0x182a, | ||
740 | WMI_SW_TX_COMPLETE_EVENTID = 0x182b, | ||
741 | WMI_RX_OFF_DONE_EVENTID = 0x182c, | ||
742 | |||
743 | WMI_READ_MAC_RXQ_EVENTID = 0x1830, | ||
744 | WMI_READ_MAC_TXQ_EVENTID = 0x1831, | ||
745 | WMI_WRITE_MAC_RXQ_EVENTID = 0x1832, | ||
746 | WMI_WRITE_MAC_TXQ_EVENTID = 0x1833, | ||
747 | WMI_WRITE_MAC_XQ_FIELD_EVENTID = 0x1834, | ||
748 | |||
749 | WMI_BEAFORMING_MGMT_DONE_EVENTID = 0x1836, | ||
750 | WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837, | ||
751 | WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839, | ||
752 | WMI_RS_MGMT_DONE_EVENTID = 0x1852, | ||
753 | WMI_RF_MGMT_STATUS_EVENTID = 0x1853, | ||
754 | WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838, | ||
755 | WMI_RX_MGMT_PACKET_EVENTID = 0x1840, | ||
756 | |||
757 | /* Performance monitoring events */ | ||
758 | WMI_DATA_PORT_OPEN_EVENTID = 0x1860, | ||
759 | WMI_WBE_LINKDOWN_EVENTID = 0x1861, | ||
760 | |||
761 | WMI_BF_CTRL_DONE_EVENTID = 0x1862, | ||
762 | WMI_NOTIFY_REQ_DONE_EVENTID = 0x1863, | ||
763 | WMI_GET_STATUS_DONE_EVENTID = 0x1864, | ||
764 | |||
765 | WMI_UNIT_TEST_EVENTID = 0x1900, | ||
766 | WMI_FLASH_READ_DONE_EVENTID = 0x1902, | ||
767 | WMI_FLASH_WRITE_DONE_EVENTID = 0x1903, | ||
768 | |||
769 | WMI_SET_CHANNEL_EVENTID = 0x9000, | ||
770 | WMI_ASSOC_REQ_EVENTID = 0x9001, | ||
771 | WMI_EAPOL_RX_EVENTID = 0x9002, | ||
772 | WMI_MAC_ADDR_RESP_EVENTID = 0x9003, | ||
773 | WMI_FW_VER_EVENTID = 0x9004, | ||
774 | }; | ||
775 | |||
776 | /* | ||
777 | * Events data structures | ||
778 | */ | ||
779 | |||
780 | /* | ||
781 | * WMI_RF_MGMT_STATUS_EVENTID | ||
782 | */ | ||
783 | enum wmi_rf_status { | ||
784 | WMI_RF_ENABLED = 0, | ||
785 | WMI_RF_DISABLED_HW = 1, | ||
786 | WMI_RF_DISABLED_SW = 2, | ||
787 | WMI_RF_DISABLED_HW_SW = 3, | ||
788 | }; | ||
789 | |||
790 | struct wmi_rf_mgmt_status_event { | ||
791 | __le32 rf_status; | ||
792 | } __packed; | ||
793 | |||
794 | /* | ||
795 | * WMI_GET_STATUS_DONE_EVENTID | ||
796 | */ | ||
797 | struct wmi_get_status_done_event { | ||
798 | __le32 is_associated; | ||
799 | u8 cid; | ||
800 | u8 reserved0[3]; | ||
801 | u8 bssid[WMI_MAC_LEN]; | ||
802 | u8 channel; | ||
803 | u8 reserved1; | ||
804 | u8 network_type; | ||
805 | u8 reserved2[3]; | ||
806 | __le32 ssid_len; | ||
807 | u8 ssid[WMI_MAX_SSID_LEN]; | ||
808 | __le32 rf_status; | ||
809 | __le32 is_secured; | ||
810 | } __packed; | ||
811 | |||
812 | /* | ||
813 | * WMI_FW_VER_EVENTID | ||
814 | */ | ||
815 | struct wmi_fw_ver_event { | ||
816 | u8 major; | ||
817 | u8 minor; | ||
818 | __le16 subminor; | ||
819 | __le16 build; | ||
820 | } __packed; | ||
821 | |||
822 | /* | ||
823 | * WMI_MAC_ADDR_RESP_EVENTID | ||
824 | */ | ||
825 | struct wmi_mac_addr_resp_event { | ||
826 | u8 mac[WMI_MAC_LEN]; | ||
827 | u8 auth_mode; | ||
828 | u8 crypt_mode; | ||
829 | __le32 offload_mode; | ||
830 | } __packed; | ||
831 | |||
832 | /* | ||
833 | * WMI_EAPOL_RX_EVENTID | ||
834 | */ | ||
835 | struct wmi_eapol_rx_event { | ||
836 | u8 src_mac[WMI_MAC_LEN]; | ||
837 | __le16 eapol_len; | ||
838 | u8 eapol[0]; | ||
839 | } __packed; | ||
840 | |||
841 | /* | ||
842 | * WMI_READY_EVENTID | ||
843 | */ | ||
844 | enum wmi_phy_capability { | ||
845 | WMI_11A_CAPABILITY = 1, | ||
846 | WMI_11G_CAPABILITY = 2, | ||
847 | WMI_11AG_CAPABILITY = 3, | ||
848 | WMI_11NA_CAPABILITY = 4, | ||
849 | WMI_11NG_CAPABILITY = 5, | ||
850 | WMI_11NAG_CAPABILITY = 6, | ||
851 | WMI_11AD_CAPABILITY = 7, | ||
852 | WMI_11N_CAPABILITY_OFFSET = WMI_11NA_CAPABILITY - WMI_11A_CAPABILITY, | ||
853 | }; | ||
854 | |||
855 | struct wmi_ready_event { | ||
856 | __le32 sw_version; | ||
857 | __le32 abi_version; | ||
858 | u8 mac[WMI_MAC_LEN]; | ||
859 | u8 phy_capability; /* enum wmi_phy_capability */ | ||
860 | u8 reserved; | ||
861 | } __packed; | ||
862 | |||
863 | /* | ||
864 | * WMI_NOTIFY_REQ_DONE_EVENTID | ||
865 | */ | ||
866 | struct wmi_notify_req_done_event { | ||
867 | __le32 status; | ||
868 | __le64 tsf; | ||
869 | __le32 snr_val; | ||
870 | __le32 tx_tpt; | ||
871 | __le32 tx_goodput; | ||
872 | __le32 rx_goodput; | ||
873 | __le16 bf_mcs; | ||
874 | __le16 my_rx_sector; | ||
875 | __le16 my_tx_sector; | ||
876 | __le16 other_rx_sector; | ||
877 | __le16 other_tx_sector; | ||
878 | __le16 range; | ||
879 | } __packed; | ||
880 | |||
881 | /* | ||
882 | * WMI_CONNECT_EVENTID | ||
883 | */ | ||
884 | struct wmi_connect_event { | ||
885 | u8 channel; | ||
886 | u8 reserved0; | ||
887 | u8 bssid[WMI_MAC_LEN]; | ||
888 | __le16 listen_interval; | ||
889 | __le16 beacon_interval; | ||
890 | u8 network_type; | ||
891 | u8 reserved1[3]; | ||
892 | u8 beacon_ie_len; | ||
893 | u8 assoc_req_len; | ||
894 | u8 assoc_resp_len; | ||
895 | u8 cid; | ||
896 | u8 reserved2[3]; | ||
897 | u8 assoc_info[0]; | ||
898 | } __packed; | ||
899 | |||
900 | /* | ||
901 | * WMI_DISCONNECT_EVENTID | ||
902 | */ | ||
903 | enum wmi_disconnect_reason { | ||
904 | WMI_DIS_REASON_NO_NETWORK_AVAIL = 1, | ||
905 | WMI_DIS_REASON_LOST_LINK = 2, /* bmiss */ | ||
906 | WMI_DIS_REASON_DISCONNECT_CMD = 3, | ||
907 | WMI_DIS_REASON_BSS_DISCONNECTED = 4, | ||
908 | WMI_DIS_REASON_AUTH_FAILED = 5, | ||
909 | WMI_DIS_REASON_ASSOC_FAILED = 6, | ||
910 | WMI_DIS_REASON_NO_RESOURCES_AVAIL = 7, | ||
911 | WMI_DIS_REASON_CSERV_DISCONNECT = 8, | ||
912 | WMI_DIS_REASON_INVALID_PROFILE = 10, | ||
913 | WMI_DIS_REASON_DOT11H_CHANNEL_SWITCH = 11, | ||
914 | WMI_DIS_REASON_PROFILE_MISMATCH = 12, | ||
915 | WMI_DIS_REASON_CONNECTION_EVICTED = 13, | ||
916 | WMI_DIS_REASON_IBSS_MERGE = 14, | ||
917 | }; | ||
918 | |||
919 | struct wmi_disconnect_event { | ||
920 | __le16 protocol_reason_status; /* reason code, see 802.11 spec. */ | ||
921 | u8 bssid[WMI_MAC_LEN]; /* set if known */ | ||
922 | u8 disconnect_reason; /* see wmi_disconnect_reason_e */ | ||
923 | u8 assoc_resp_len; | ||
924 | u8 assoc_info[0]; | ||
925 | } __packed; | ||
926 | |||
927 | /* | ||
928 | * WMI_SCAN_COMPLETE_EVENTID | ||
929 | */ | ||
930 | struct wmi_scan_complete_event { | ||
931 | __le32 status; | ||
932 | } __packed; | ||
933 | |||
934 | /* | ||
935 | * WMI_BA_STATUS_EVENTID | ||
936 | */ | ||
937 | enum wmi_vring_ba_status { | ||
938 | WMI_BA_AGREED = 0, | ||
939 | WMI_BA_NON_AGREED = 1, | ||
940 | }; | ||
941 | |||
942 | struct wmi_vring_ba_status_event { | ||
943 | __le16 status; | ||
944 | u8 reserved[2]; | ||
945 | u8 ringid; | ||
946 | u8 agg_wsize; | ||
947 | __le16 ba_timeout; | ||
948 | } __packed; | ||
949 | |||
950 | /* | ||
951 | * WMI_DELBA_EVENTID | ||
952 | */ | ||
953 | struct wmi_delba_event { | ||
954 | |||
955 | #define CIDXTID_CID_POS (0) | ||
956 | #define CIDXTID_CID_LEN (4) | ||
957 | #define CIDXTID_CID_MSK (0xF) | ||
958 | #define CIDXTID_TID_POS (4) | ||
959 | #define CIDXTID_TID_LEN (4) | ||
960 | #define CIDXTID_TID_MSK (0xF0) | ||
961 | u8 cidxtid; | ||
962 | |||
963 | u8 from_initiator; | ||
964 | __le16 reason; | ||
965 | } __packed; | ||
966 | |||
967 | /* | ||
968 | * WMI_VRING_CFG_DONE_EVENTID | ||
969 | */ | ||
970 | enum wmi_vring_cfg_done_event_status { | ||
971 | WMI_VRING_CFG_SUCCESS = 0, | ||
972 | WMI_VRING_CFG_FAILURE = 1, | ||
973 | }; | ||
974 | |||
975 | struct wmi_vring_cfg_done_event { | ||
976 | u8 ringid; | ||
977 | u8 status; | ||
978 | u8 reserved[2]; | ||
979 | __le32 tx_vring_tail_ptr; | ||
980 | } __packed; | ||
981 | |||
982 | /* | ||
983 | * WMI_ADDBA_RESP_SENT_EVENTID | ||
984 | */ | ||
985 | enum wmi_rcp_addba_resp_sent_event_status { | ||
986 | WMI_ADDBA_SUCCESS = 0, | ||
987 | WMI_ADDBA_FAIL = 1, | ||
988 | }; | ||
989 | |||
990 | struct wmi_rcp_addba_resp_sent_event { | ||
991 | |||
992 | #define CIDXTID_CID_POS (0) | ||
993 | #define CIDXTID_CID_LEN (4) | ||
994 | #define CIDXTID_CID_MSK (0xF) | ||
995 | #define CIDXTID_TID_POS (4) | ||
996 | #define CIDXTID_TID_LEN (4) | ||
997 | #define CIDXTID_TID_MSK (0xF0) | ||
998 | u8 cidxtid; | ||
999 | |||
1000 | u8 reserved; | ||
1001 | __le16 status; | ||
1002 | } __packed; | ||
1003 | |||
1004 | /* | ||
1005 | * WMI_RCP_ADDBA_REQ_EVENTID | ||
1006 | */ | ||
1007 | struct wmi_rcp_addba_req_event { | ||
1008 | |||
1009 | #define CIDXTID_CID_POS (0) | ||
1010 | #define CIDXTID_CID_LEN (4) | ||
1011 | #define CIDXTID_CID_MSK (0xF) | ||
1012 | #define CIDXTID_TID_POS (4) | ||
1013 | #define CIDXTID_TID_LEN (4) | ||
1014 | #define CIDXTID_TID_MSK (0xF0) | ||
1015 | u8 cidxtid; | ||
1016 | |||
1017 | u8 dialog_token; | ||
1018 | __le16 ba_param_set; /* ieee80211_ba_parameterset as it received */ | ||
1019 | __le16 ba_timeout; | ||
1020 | __le16 ba_seq_ctrl; /* ieee80211_ba_seqstrl field as it received */ | ||
1021 | } __packed; | ||
1022 | |||
1023 | /* | ||
1024 | * WMI_CFG_RX_CHAIN_DONE_EVENTID | ||
1025 | */ | ||
1026 | enum wmi_cfg_rx_chain_done_event_status { | ||
1027 | WMI_CFG_RX_CHAIN_SUCCESS = 1, | ||
1028 | }; | ||
1029 | |||
1030 | struct wmi_cfg_rx_chain_done_event { | ||
1031 | __le32 rx_ring_tail_ptr; /* Rx V-Ring Tail pointer */ | ||
1032 | __le32 status; | ||
1033 | } __packed; | ||
1034 | |||
1035 | /* | ||
1036 | * WMI_WBE_LINKDOWN_EVENTID | ||
1037 | */ | ||
1038 | enum wmi_wbe_link_down_event_reason { | ||
1039 | WMI_WBE_REASON_USER_REQUEST = 0, | ||
1040 | WMI_WBE_REASON_RX_DISASSOC = 1, | ||
1041 | WMI_WBE_REASON_BAD_PHY_LINK = 2, | ||
1042 | }; | ||
1043 | |||
1044 | struct wmi_wbe_link_down_event { | ||
1045 | u8 cid; | ||
1046 | u8 reserved[3]; | ||
1047 | __le32 reason; | ||
1048 | } __packed; | ||
1049 | |||
1050 | /* | ||
1051 | * WMI_DATA_PORT_OPEN_EVENTID | ||
1052 | */ | ||
1053 | struct wmi_data_port_open_event { | ||
1054 | u8 cid; | ||
1055 | u8 reserved[3]; | ||
1056 | } __packed; | ||
1057 | |||
1058 | /* | ||
1059 | * WMI_GET_PCP_CHANNEL_EVENTID | ||
1060 | */ | ||
1061 | struct wmi_get_pcp_channel_event { | ||
1062 | u8 channel; | ||
1063 | u8 reserved[3]; | ||
1064 | } __packed; | ||
1065 | |||
1066 | /* | ||
1067 | * WMI_SW_TX_COMPLETE_EVENTID | ||
1068 | */ | ||
1069 | enum wmi_sw_tx_status { | ||
1070 | WMI_TX_SW_STATUS_SUCCESS = 0, | ||
1071 | WMI_TX_SW_STATUS_FAILED_NO_RESOURCES = 1, | ||
1072 | WMI_TX_SW_STATUS_FAILED_TX = 2, | ||
1073 | }; | ||
1074 | |||
1075 | struct wmi_sw_tx_complete_event { | ||
1076 | u8 status; /* enum wmi_sw_tx_status */ | ||
1077 | u8 reserved[3]; | ||
1078 | } __packed; | ||
1079 | |||
1080 | /* | ||
1081 | * WMI_GET_SSID_EVENTID | ||
1082 | */ | ||
1083 | struct wmi_get_ssid_event { | ||
1084 | __le32 ssid_len; | ||
1085 | u8 ssid[WMI_MAX_SSID_LEN]; | ||
1086 | } __packed; | ||
1087 | |||
1088 | /* | ||
1089 | * WMI_RX_MGMT_PACKET_EVENTID | ||
1090 | */ | ||
1091 | struct wmi_rx_mgmt_info { | ||
1092 | u8 mcs; | ||
1093 | s8 snr; | ||
1094 | __le16 range; | ||
1095 | __le16 stype; | ||
1096 | __le16 status; | ||
1097 | __le32 len; | ||
1098 | u8 qid; | ||
1099 | u8 mid; | ||
1100 | u8 cid; | ||
1101 | u8 channel; /* From Radio MNGR */ | ||
1102 | } __packed; | ||
1103 | |||
1104 | struct wmi_rx_mgmt_packet_event { | ||
1105 | struct wmi_rx_mgmt_info info; | ||
1106 | u8 payload[0]; | ||
1107 | } __packed; | ||
1108 | |||
1109 | /* | ||
1110 | * WMI_ECHO_RSP_EVENTID | ||
1111 | */ | ||
1112 | struct wmi_echo_event { | ||
1113 | __le32 echoed_value; | ||
1114 | } __packed; | ||
1115 | |||
1116 | #endif /* __WILOCITY_WMI_H__ */ | ||
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index b298e5d68be2..10e288d470e7 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/hw_random.h> | 7 | #include <linux/hw_random.h> |
8 | #include <linux/bcma/bcma.h> | 8 | #include <linux/bcma/bcma.h> |
9 | #include <linux/ssb/ssb.h> | 9 | #include <linux/ssb/ssb.h> |
10 | #include <linux/completion.h> | ||
10 | #include <net/mac80211.h> | 11 | #include <net/mac80211.h> |
11 | 12 | ||
12 | #include "debugfs.h" | 13 | #include "debugfs.h" |
@@ -722,6 +723,10 @@ enum b43_firmware_file_type { | |||
722 | struct b43_request_fw_context { | 723 | struct b43_request_fw_context { |
723 | /* The device we are requesting the fw for. */ | 724 | /* The device we are requesting the fw for. */ |
724 | struct b43_wldev *dev; | 725 | struct b43_wldev *dev; |
726 | /* a completion event structure needed if this call is asynchronous */ | ||
727 | struct completion fw_load_complete; | ||
728 | /* a pointer to the firmware object */ | ||
729 | const struct firmware *blob; | ||
725 | /* The type of firmware to request. */ | 730 | /* The type of firmware to request. */ |
726 | enum b43_firmware_file_type req_type; | 731 | enum b43_firmware_file_type req_type; |
727 | /* Error messages for each firmware type. */ | 732 | /* Error messages for each firmware type. */ |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 16ab280359bd..806e34c19281 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -2088,11 +2088,18 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error) | |||
2088 | b43warn(wl, text); | 2088 | b43warn(wl, text); |
2089 | } | 2089 | } |
2090 | 2090 | ||
2091 | static void b43_fw_cb(const struct firmware *firmware, void *context) | ||
2092 | { | ||
2093 | struct b43_request_fw_context *ctx = context; | ||
2094 | |||
2095 | ctx->blob = firmware; | ||
2096 | complete(&ctx->fw_load_complete); | ||
2097 | } | ||
2098 | |||
2091 | int b43_do_request_fw(struct b43_request_fw_context *ctx, | 2099 | int b43_do_request_fw(struct b43_request_fw_context *ctx, |
2092 | const char *name, | 2100 | const char *name, |
2093 | struct b43_firmware_file *fw) | 2101 | struct b43_firmware_file *fw, bool async) |
2094 | { | 2102 | { |
2095 | const struct firmware *blob; | ||
2096 | struct b43_fw_header *hdr; | 2103 | struct b43_fw_header *hdr; |
2097 | u32 size; | 2104 | u32 size; |
2098 | int err; | 2105 | int err; |
@@ -2131,11 +2138,31 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, | |||
2131 | B43_WARN_ON(1); | 2138 | B43_WARN_ON(1); |
2132 | return -ENOSYS; | 2139 | return -ENOSYS; |
2133 | } | 2140 | } |
2134 | err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev); | 2141 | if (async) { |
2142 | /* do this part asynchronously */ | ||
2143 | init_completion(&ctx->fw_load_complete); | ||
2144 | err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname, | ||
2145 | ctx->dev->dev->dev, GFP_KERNEL, | ||
2146 | ctx, b43_fw_cb); | ||
2147 | if (err < 0) { | ||
2148 | pr_err("Unable to load firmware\n"); | ||
2149 | return err; | ||
2150 | } | ||
2151 | /* stall here until fw ready */ | ||
2152 | wait_for_completion(&ctx->fw_load_complete); | ||
2153 | if (ctx->blob) | ||
2154 | goto fw_ready; | ||
2155 | /* On some ARM systems, the async request will fail, but the next sync | ||
2156 | * request works. For this reason, we dall through here | ||
2157 | */ | ||
2158 | } | ||
2159 | err = request_firmware(&ctx->blob, ctx->fwname, | ||
2160 | ctx->dev->dev->dev); | ||
2135 | if (err == -ENOENT) { | 2161 | if (err == -ENOENT) { |
2136 | snprintf(ctx->errors[ctx->req_type], | 2162 | snprintf(ctx->errors[ctx->req_type], |
2137 | sizeof(ctx->errors[ctx->req_type]), | 2163 | sizeof(ctx->errors[ctx->req_type]), |
2138 | "Firmware file \"%s\" not found\n", ctx->fwname); | 2164 | "Firmware file \"%s\" not found\n", |
2165 | ctx->fwname); | ||
2139 | return err; | 2166 | return err; |
2140 | } else if (err) { | 2167 | } else if (err) { |
2141 | snprintf(ctx->errors[ctx->req_type], | 2168 | snprintf(ctx->errors[ctx->req_type], |
@@ -2144,14 +2171,15 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, | |||
2144 | ctx->fwname, err); | 2171 | ctx->fwname, err); |
2145 | return err; | 2172 | return err; |
2146 | } | 2173 | } |
2147 | if (blob->size < sizeof(struct b43_fw_header)) | 2174 | fw_ready: |
2175 | if (ctx->blob->size < sizeof(struct b43_fw_header)) | ||
2148 | goto err_format; | 2176 | goto err_format; |
2149 | hdr = (struct b43_fw_header *)(blob->data); | 2177 | hdr = (struct b43_fw_header *)(ctx->blob->data); |
2150 | switch (hdr->type) { | 2178 | switch (hdr->type) { |
2151 | case B43_FW_TYPE_UCODE: | 2179 | case B43_FW_TYPE_UCODE: |
2152 | case B43_FW_TYPE_PCM: | 2180 | case B43_FW_TYPE_PCM: |
2153 | size = be32_to_cpu(hdr->size); | 2181 | size = be32_to_cpu(hdr->size); |
2154 | if (size != blob->size - sizeof(struct b43_fw_header)) | 2182 | if (size != ctx->blob->size - sizeof(struct b43_fw_header)) |
2155 | goto err_format; | 2183 | goto err_format; |
2156 | /* fallthrough */ | 2184 | /* fallthrough */ |
2157 | case B43_FW_TYPE_IV: | 2185 | case B43_FW_TYPE_IV: |
@@ -2162,7 +2190,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, | |||
2162 | goto err_format; | 2190 | goto err_format; |
2163 | } | 2191 | } |
2164 | 2192 | ||
2165 | fw->data = blob; | 2193 | fw->data = ctx->blob; |
2166 | fw->filename = name; | 2194 | fw->filename = name; |
2167 | fw->type = ctx->req_type; | 2195 | fw->type = ctx->req_type; |
2168 | 2196 | ||
@@ -2172,7 +2200,7 @@ err_format: | |||
2172 | snprintf(ctx->errors[ctx->req_type], | 2200 | snprintf(ctx->errors[ctx->req_type], |
2173 | sizeof(ctx->errors[ctx->req_type]), | 2201 | sizeof(ctx->errors[ctx->req_type]), |
2174 | "Firmware file \"%s\" format error.\n", ctx->fwname); | 2202 | "Firmware file \"%s\" format error.\n", ctx->fwname); |
2175 | release_firmware(blob); | 2203 | release_firmware(ctx->blob); |
2176 | 2204 | ||
2177 | return -EPROTO; | 2205 | return -EPROTO; |
2178 | } | 2206 | } |
@@ -2223,7 +2251,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) | |||
2223 | goto err_no_ucode; | 2251 | goto err_no_ucode; |
2224 | } | 2252 | } |
2225 | } | 2253 | } |
2226 | err = b43_do_request_fw(ctx, filename, &fw->ucode); | 2254 | err = b43_do_request_fw(ctx, filename, &fw->ucode, true); |
2227 | if (err) | 2255 | if (err) |
2228 | goto err_load; | 2256 | goto err_load; |
2229 | 2257 | ||
@@ -2235,7 +2263,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) | |||
2235 | else | 2263 | else |
2236 | goto err_no_pcm; | 2264 | goto err_no_pcm; |
2237 | fw->pcm_request_failed = false; | 2265 | fw->pcm_request_failed = false; |
2238 | err = b43_do_request_fw(ctx, filename, &fw->pcm); | 2266 | err = b43_do_request_fw(ctx, filename, &fw->pcm, false); |
2239 | if (err == -ENOENT) { | 2267 | if (err == -ENOENT) { |
2240 | /* We did not find a PCM file? Not fatal, but | 2268 | /* We did not find a PCM file? Not fatal, but |
2241 | * core rev <= 10 must do without hwcrypto then. */ | 2269 | * core rev <= 10 must do without hwcrypto then. */ |
@@ -2296,7 +2324,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) | |||
2296 | default: | 2324 | default: |
2297 | goto err_no_initvals; | 2325 | goto err_no_initvals; |
2298 | } | 2326 | } |
2299 | err = b43_do_request_fw(ctx, filename, &fw->initvals); | 2327 | err = b43_do_request_fw(ctx, filename, &fw->initvals, false); |
2300 | if (err) | 2328 | if (err) |
2301 | goto err_load; | 2329 | goto err_load; |
2302 | 2330 | ||
@@ -2355,7 +2383,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) | |||
2355 | default: | 2383 | default: |
2356 | goto err_no_initvals; | 2384 | goto err_no_initvals; |
2357 | } | 2385 | } |
2358 | err = b43_do_request_fw(ctx, filename, &fw->initvals_band); | 2386 | err = b43_do_request_fw(ctx, filename, &fw->initvals_band, false); |
2359 | if (err) | 2387 | if (err) |
2360 | goto err_load; | 2388 | goto err_load; |
2361 | 2389 | ||
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 8c684cd33529..abac25ee958d 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h | |||
@@ -137,9 +137,8 @@ void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on); | |||
137 | 137 | ||
138 | 138 | ||
139 | struct b43_request_fw_context; | 139 | struct b43_request_fw_context; |
140 | int b43_do_request_fw(struct b43_request_fw_context *ctx, | 140 | int b43_do_request_fw(struct b43_request_fw_context *ctx, const char *name, |
141 | const char *name, | 141 | struct b43_firmware_file *fw, bool async); |
142 | struct b43_firmware_file *fw); | ||
143 | void b43_do_release_fw(struct b43_firmware_file *fw); | 142 | void b43_do_release_fw(struct b43_firmware_file *fw); |
144 | 143 | ||
145 | #endif /* B43_MAIN_H_ */ | 144 | #endif /* B43_MAIN_H_ */ |
diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index d604b4036a76..3726cd6fcd75 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c | |||
@@ -3273,7 +3273,7 @@ il3945_store_measurement(struct device *d, struct device_attribute *attr, | |||
3273 | 3273 | ||
3274 | if (count) { | 3274 | if (count) { |
3275 | char *p = buffer; | 3275 | char *p = buffer; |
3276 | strncpy(buffer, buf, min(sizeof(buffer), count)); | 3276 | strlcpy(buffer, buf, sizeof(buffer)); |
3277 | channel = simple_strtoul(p, NULL, 0); | 3277 | channel = simple_strtoul(p, NULL, 0); |
3278 | if (channel) | 3278 | if (channel) |
3279 | params.channel = channel; | 3279 | params.channel = channel; |
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index da21328ca8ed..a790599fe2c2 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c | |||
@@ -1151,13 +1151,6 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | |||
1151 | next_reclaimed = ssn; | 1151 | next_reclaimed = ssn; |
1152 | } | 1152 | } |
1153 | 1153 | ||
1154 | if (tid != IWL_TID_NON_QOS) { | ||
1155 | priv->tid_data[sta_id][tid].next_reclaimed = | ||
1156 | next_reclaimed; | ||
1157 | IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n", | ||
1158 | next_reclaimed); | ||
1159 | } | ||
1160 | |||
1161 | iwl_trans_reclaim(priv->trans, txq_id, ssn, &skbs); | 1154 | iwl_trans_reclaim(priv->trans, txq_id, ssn, &skbs); |
1162 | 1155 | ||
1163 | iwlagn_check_ratid_empty(priv, sta_id, tid); | 1156 | iwlagn_check_ratid_empty(priv, sta_id, tid); |
@@ -1208,11 +1201,28 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | |||
1208 | if (!is_agg) | 1201 | if (!is_agg) |
1209 | iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1); | 1202 | iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1); |
1210 | 1203 | ||
1204 | /* | ||
1205 | * W/A for FW bug - the seq_ctl isn't updated when the | ||
1206 | * queues are flushed. Fetch it from the packet itself | ||
1207 | */ | ||
1208 | if (!is_agg && status == TX_STATUS_FAIL_FIFO_FLUSHED) { | ||
1209 | next_reclaimed = le16_to_cpu(hdr->seq_ctrl); | ||
1210 | next_reclaimed = | ||
1211 | SEQ_TO_SN(next_reclaimed + 0x10); | ||
1212 | } | ||
1213 | |||
1211 | is_offchannel_skb = | 1214 | is_offchannel_skb = |
1212 | (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN); | 1215 | (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN); |
1213 | freed++; | 1216 | freed++; |
1214 | } | 1217 | } |
1215 | 1218 | ||
1219 | if (tid != IWL_TID_NON_QOS) { | ||
1220 | priv->tid_data[sta_id][tid].next_reclaimed = | ||
1221 | next_reclaimed; | ||
1222 | IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n", | ||
1223 | next_reclaimed); | ||
1224 | } | ||
1225 | |||
1216 | WARN_ON(!is_agg && freed != 1); | 1226 | WARN_ON(!is_agg && freed != 1); |
1217 | 1227 | ||
1218 | /* | 1228 | /* |
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index dad4c4aad91f..8389cd38338b 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c | |||
@@ -1166,6 +1166,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) | |||
1166 | else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && | 1166 | else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && |
1167 | !trans_pcie->inta) | 1167 | !trans_pcie->inta) |
1168 | iwl_enable_interrupts(trans); | 1168 | iwl_enable_interrupts(trans); |
1169 | return IRQ_HANDLED; | ||
1169 | 1170 | ||
1170 | none: | 1171 | none: |
1171 | /* re-enable interrupts here since we don't have anything to service. */ | 1172 | /* re-enable interrupts here since we don't have anything to service. */ |
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index a875499f8945..efe525be27dd 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c | |||
@@ -1709,7 +1709,7 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv, | |||
1709 | NL80211_CHAN_NO_HT) | 1709 | NL80211_CHAN_NO_HT) |
1710 | config_bands |= BAND_GN; | 1710 | config_bands |= BAND_GN; |
1711 | } else { | 1711 | } else { |
1712 | if (cfg80211_get_chandef_type(¶ms->chandef) != | 1712 | if (cfg80211_get_chandef_type(¶ms->chandef) == |
1713 | NL80211_CHAN_NO_HT) | 1713 | NL80211_CHAN_NO_HT) |
1714 | config_bands = BAND_A; | 1714 | config_bands = BAND_A; |
1715 | else | 1715 | else |
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index cb682561c438..60e88b58039d 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c | |||
@@ -56,7 +56,6 @@ int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, | |||
56 | */ | 56 | */ |
57 | int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) | 57 | int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) |
58 | { | 58 | { |
59 | bool cancel_flag = false; | ||
60 | int status; | 59 | int status; |
61 | struct cmd_ctrl_node *cmd_queued; | 60 | struct cmd_ctrl_node *cmd_queued; |
62 | 61 | ||
@@ -70,14 +69,11 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) | |||
70 | atomic_inc(&adapter->cmd_pending); | 69 | atomic_inc(&adapter->cmd_pending); |
71 | 70 | ||
72 | /* Wait for completion */ | 71 | /* Wait for completion */ |
73 | wait_event_interruptible(adapter->cmd_wait_q.wait, | 72 | status = wait_event_interruptible(adapter->cmd_wait_q.wait, |
74 | *(cmd_queued->condition)); | 73 | *(cmd_queued->condition)); |
75 | if (!*(cmd_queued->condition)) | 74 | if (status) { |
76 | cancel_flag = true; | 75 | dev_err(adapter->dev, "cmd_wait_q terminated: %d\n", status); |
77 | 76 | return status; | |
78 | if (cancel_flag) { | ||
79 | mwifiex_cancel_pending_ioctl(adapter); | ||
80 | dev_dbg(adapter->dev, "cmd cancel\n"); | ||
81 | } | 77 | } |
82 | 78 | ||
83 | status = adapter->cmd_wait_q.status; | 79 | status = adapter->cmd_wait_q.status; |
@@ -496,8 +492,11 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) | |||
496 | return false; | 492 | return false; |
497 | } | 493 | } |
498 | 494 | ||
499 | wait_event_interruptible(adapter->hs_activate_wait_q, | 495 | if (wait_event_interruptible(adapter->hs_activate_wait_q, |
500 | adapter->hs_activate_wait_q_woken); | 496 | adapter->hs_activate_wait_q_woken)) { |
497 | dev_err(adapter->dev, "hs_activate_wait_q terminated\n"); | ||
498 | return false; | ||
499 | } | ||
501 | 500 | ||
502 | return true; | 501 | return true; |
503 | } | 502 | } |
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index f221b95b90b3..83564d36e801 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -4250,9 +4250,11 @@ static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw, | |||
4250 | p->amsdu_enabled = 0; | 4250 | p->amsdu_enabled = 0; |
4251 | 4251 | ||
4252 | rc = mwl8k_post_cmd(hw, &cmd->header); | 4252 | rc = mwl8k_post_cmd(hw, &cmd->header); |
4253 | if (!rc) | ||
4254 | rc = p->station_id; | ||
4253 | kfree(cmd); | 4255 | kfree(cmd); |
4254 | 4256 | ||
4255 | return rc ? rc : p->station_id; | 4257 | return rc; |
4256 | } | 4258 | } |
4257 | 4259 | ||
4258 | static int mwl8k_cmd_update_stadb_del(struct ieee80211_hw *hw, | 4260 | static int mwl8k_cmd_update_stadb_del(struct ieee80211_hw *hw, |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c index 1d5d3604e3e0..246e5352f2e1 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c | |||
@@ -692,7 +692,7 @@ u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw) | |||
692 | if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { | 692 | if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { |
693 | rtl92c_phy_sw_chnl_callback(hw); | 693 | rtl92c_phy_sw_chnl_callback(hw); |
694 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, | 694 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, |
695 | "sw_chnl_inprogress false schdule workitem\n"); | 695 | "sw_chnl_inprogress false schedule workitem\n"); |
696 | rtlphy->sw_chnl_inprogress = false; | 696 | rtlphy->sw_chnl_inprogress = false; |
697 | } else { | 697 | } else { |
698 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, | 698 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, |
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c index 39cc7938eedf..3d8536bb0d2b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c | |||
@@ -1106,7 +1106,7 @@ u8 rtl8723ae_phy_sw_chnl(struct ieee80211_hw *hw) | |||
1106 | if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { | 1106 | if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { |
1107 | rtl8723ae_phy_sw_chnl_callback(hw); | 1107 | rtl8723ae_phy_sw_chnl_callback(hw); |
1108 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, | 1108 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, |
1109 | "sw_chnl_inprogress false schdule workitem\n"); | 1109 | "sw_chnl_inprogress false schedule workitem\n"); |
1110 | rtlphy->sw_chnl_inprogress = false; | 1110 | rtlphy->sw_chnl_inprogress = false; |
1111 | } else { | 1111 | } else { |
1112 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, | 1112 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, |
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index bafd2bbcaf65..c18e5bf444fa 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c | |||
@@ -739,7 +739,7 @@ EXPORT_SYMBOL_GPL(pci_num_vf); | |||
739 | /** | 739 | /** |
740 | * pci_sriov_set_totalvfs -- reduce the TotalVFs available | 740 | * pci_sriov_set_totalvfs -- reduce the TotalVFs available |
741 | * @dev: the PCI PF device | 741 | * @dev: the PCI PF device |
742 | * numvfs: number that should be used for TotalVFs supported | 742 | * @numvfs: number that should be used for TotalVFs supported |
743 | * | 743 | * |
744 | * Should be called from PF driver's probe routine with | 744 | * Should be called from PF driver's probe routine with |
745 | * device's mutex held. | 745 | * device's mutex held. |
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 06f4eb7ab87e..afed7018a2b5 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c | |||
@@ -125,8 +125,11 @@ static const struct key_entry acer_wmi_keymap[] = { | |||
125 | {KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} }, | 125 | {KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} }, |
126 | {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */ | 126 | {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */ |
127 | {KE_IGNORE, 0x81, {KEY_SLEEP} }, | 127 | {KE_IGNORE, 0x81, {KEY_SLEEP} }, |
128 | {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad On/Off */ | 128 | {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad Toggle */ |
129 | {KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} }, | ||
130 | {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} }, | ||
129 | {KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} }, | 131 | {KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} }, |
132 | {KE_KEY, 0x85, {KEY_TOUCHPAD_TOGGLE} }, | ||
130 | {KE_END, 0} | 133 | {KE_END, 0} |
131 | }; | 134 | }; |
132 | 135 | ||
@@ -147,6 +150,7 @@ struct event_return_value { | |||
147 | #define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */ | 150 | #define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */ |
148 | #define ACER_WMID3_GDS_WIMAX (1<<7) /* WiMAX */ | 151 | #define ACER_WMID3_GDS_WIMAX (1<<7) /* WiMAX */ |
149 | #define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */ | 152 | #define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */ |
153 | #define ACER_WMID3_GDS_TOUCHPAD (1<<1) /* Touchpad */ | ||
150 | 154 | ||
151 | struct lm_input_params { | 155 | struct lm_input_params { |
152 | u8 function_num; /* Function Number */ | 156 | u8 function_num; /* Function Number */ |
@@ -875,7 +879,7 @@ WMI_execute_u32(u32 method_id, u32 in, u32 *out) | |||
875 | struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) }; | 879 | struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) }; |
876 | struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL }; | 880 | struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL }; |
877 | union acpi_object *obj; | 881 | union acpi_object *obj; |
878 | u32 tmp; | 882 | u32 tmp = 0; |
879 | acpi_status status; | 883 | acpi_status status; |
880 | 884 | ||
881 | status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result); | 885 | status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result); |
@@ -884,14 +888,14 @@ WMI_execute_u32(u32 method_id, u32 in, u32 *out) | |||
884 | return status; | 888 | return status; |
885 | 889 | ||
886 | obj = (union acpi_object *) result.pointer; | 890 | obj = (union acpi_object *) result.pointer; |
887 | if (obj && obj->type == ACPI_TYPE_BUFFER && | 891 | if (obj) { |
888 | (obj->buffer.length == sizeof(u32) || | 892 | if (obj->type == ACPI_TYPE_BUFFER && |
889 | obj->buffer.length == sizeof(u64))) { | 893 | (obj->buffer.length == sizeof(u32) || |
890 | tmp = *((u32 *) obj->buffer.pointer); | 894 | obj->buffer.length == sizeof(u64))) { |
891 | } else if (obj->type == ACPI_TYPE_INTEGER) { | 895 | tmp = *((u32 *) obj->buffer.pointer); |
892 | tmp = (u32) obj->integer.value; | 896 | } else if (obj->type == ACPI_TYPE_INTEGER) { |
893 | } else { | 897 | tmp = (u32) obj->integer.value; |
894 | tmp = 0; | 898 | } |
895 | } | 899 | } |
896 | 900 | ||
897 | if (out) | 901 | if (out) |
@@ -1193,12 +1197,14 @@ static acpi_status WMID_set_capabilities(void) | |||
1193 | return status; | 1197 | return status; |
1194 | 1198 | ||
1195 | obj = (union acpi_object *) out.pointer; | 1199 | obj = (union acpi_object *) out.pointer; |
1196 | if (obj && obj->type == ACPI_TYPE_BUFFER && | 1200 | if (obj) { |
1197 | (obj->buffer.length == sizeof(u32) || | 1201 | if (obj->type == ACPI_TYPE_BUFFER && |
1198 | obj->buffer.length == sizeof(u64))) { | 1202 | (obj->buffer.length == sizeof(u32) || |
1199 | devices = *((u32 *) obj->buffer.pointer); | 1203 | obj->buffer.length == sizeof(u64))) { |
1200 | } else if (obj->type == ACPI_TYPE_INTEGER) { | 1204 | devices = *((u32 *) obj->buffer.pointer); |
1201 | devices = (u32) obj->integer.value; | 1205 | } else if (obj->type == ACPI_TYPE_INTEGER) { |
1206 | devices = (u32) obj->integer.value; | ||
1207 | } | ||
1202 | } else { | 1208 | } else { |
1203 | kfree(out.pointer); | 1209 | kfree(out.pointer); |
1204 | return AE_ERROR; | 1210 | return AE_ERROR; |
@@ -1676,6 +1682,7 @@ static void acer_wmi_notify(u32 value, void *context) | |||
1676 | acpi_status status; | 1682 | acpi_status status; |
1677 | u16 device_state; | 1683 | u16 device_state; |
1678 | const struct key_entry *key; | 1684 | const struct key_entry *key; |
1685 | u32 scancode; | ||
1679 | 1686 | ||
1680 | status = wmi_get_event_data(value, &response); | 1687 | status = wmi_get_event_data(value, &response); |
1681 | if (status != AE_OK) { | 1688 | if (status != AE_OK) { |
@@ -1712,6 +1719,7 @@ static void acer_wmi_notify(u32 value, void *context) | |||
1712 | pr_warn("Unknown key number - 0x%x\n", | 1719 | pr_warn("Unknown key number - 0x%x\n", |
1713 | return_value.key_num); | 1720 | return_value.key_num); |
1714 | } else { | 1721 | } else { |
1722 | scancode = return_value.key_num; | ||
1715 | switch (key->keycode) { | 1723 | switch (key->keycode) { |
1716 | case KEY_WLAN: | 1724 | case KEY_WLAN: |
1717 | case KEY_BLUETOOTH: | 1725 | case KEY_BLUETOOTH: |
@@ -1725,9 +1733,11 @@ static void acer_wmi_notify(u32 value, void *context) | |||
1725 | rfkill_set_sw_state(bluetooth_rfkill, | 1733 | rfkill_set_sw_state(bluetooth_rfkill, |
1726 | !(device_state & ACER_WMID3_GDS_BLUETOOTH)); | 1734 | !(device_state & ACER_WMID3_GDS_BLUETOOTH)); |
1727 | break; | 1735 | break; |
1736 | case KEY_TOUCHPAD_TOGGLE: | ||
1737 | scancode = (device_state & ACER_WMID3_GDS_TOUCHPAD) ? | ||
1738 | KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF; | ||
1728 | } | 1739 | } |
1729 | sparse_keymap_report_entry(acer_wmi_input_dev, key, | 1740 | sparse_keymap_report_event(acer_wmi_input_dev, scancode, 1, true); |
1730 | 1, true); | ||
1731 | } | 1741 | } |
1732 | break; | 1742 | break; |
1733 | case WMID_ACCEL_EVENT: | 1743 | case WMID_ACCEL_EVENT: |
@@ -1946,12 +1956,14 @@ static u32 get_wmid_devices(void) | |||
1946 | return 0; | 1956 | return 0; |
1947 | 1957 | ||
1948 | obj = (union acpi_object *) out.pointer; | 1958 | obj = (union acpi_object *) out.pointer; |
1949 | if (obj && obj->type == ACPI_TYPE_BUFFER && | 1959 | if (obj) { |
1950 | (obj->buffer.length == sizeof(u32) || | 1960 | if (obj->type == ACPI_TYPE_BUFFER && |
1951 | obj->buffer.length == sizeof(u64))) { | 1961 | (obj->buffer.length == sizeof(u32) || |
1952 | devices = *((u32 *) obj->buffer.pointer); | 1962 | obj->buffer.length == sizeof(u64))) { |
1953 | } else if (obj->type == ACPI_TYPE_INTEGER) { | 1963 | devices = *((u32 *) obj->buffer.pointer); |
1954 | devices = (u32) obj->integer.value; | 1964 | } else if (obj->type == ACPI_TYPE_INTEGER) { |
1965 | devices = (u32) obj->integer.value; | ||
1966 | } | ||
1955 | } | 1967 | } |
1956 | 1968 | ||
1957 | kfree(out.pointer); | 1969 | kfree(out.pointer); |
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index ec1d3bc2dbe2..fcde4e528819 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c | |||
@@ -860,8 +860,10 @@ static ssize_t show_infos(struct device *dev, | |||
860 | /* | 860 | /* |
861 | * The HWRS method return informations about the hardware. | 861 | * The HWRS method return informations about the hardware. |
862 | * 0x80 bit is for WLAN, 0x100 for Bluetooth. | 862 | * 0x80 bit is for WLAN, 0x100 for Bluetooth. |
863 | * 0x40 for WWAN, 0x10 for WIMAX. | ||
863 | * The significance of others is yet to be found. | 864 | * The significance of others is yet to be found. |
864 | * If we don't find the method, we assume the device are present. | 865 | * We don't currently use this for device detection, and it |
866 | * takes several seconds to run on some systems. | ||
865 | */ | 867 | */ |
866 | rv = acpi_evaluate_integer(asus->handle, "HWRS", NULL, &temp); | 868 | rv = acpi_evaluate_integer(asus->handle, "HWRS", NULL, &temp); |
867 | if (!ACPI_FAILURE(rv)) | 869 | if (!ACPI_FAILURE(rv)) |
@@ -1682,7 +1684,7 @@ static int asus_laptop_get_info(struct asus_laptop *asus) | |||
1682 | { | 1684 | { |
1683 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 1685 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
1684 | union acpi_object *model = NULL; | 1686 | union acpi_object *model = NULL; |
1685 | unsigned long long bsts_result, hwrs_result; | 1687 | unsigned long long bsts_result; |
1686 | char *string = NULL; | 1688 | char *string = NULL; |
1687 | acpi_status status; | 1689 | acpi_status status; |
1688 | 1690 | ||
@@ -1741,20 +1743,9 @@ static int asus_laptop_get_info(struct asus_laptop *asus) | |||
1741 | return -ENOMEM; | 1743 | return -ENOMEM; |
1742 | } | 1744 | } |
1743 | 1745 | ||
1744 | if (*string) | 1746 | if (string) |
1745 | pr_notice(" %s model detected\n", string); | 1747 | pr_notice(" %s model detected\n", string); |
1746 | 1748 | ||
1747 | /* | ||
1748 | * The HWRS method return informations about the hardware. | ||
1749 | * 0x80 bit is for WLAN, 0x100 for Bluetooth, | ||
1750 | * 0x40 for WWAN, 0x10 for WIMAX. | ||
1751 | * The significance of others is yet to be found. | ||
1752 | */ | ||
1753 | status = | ||
1754 | acpi_evaluate_integer(asus->handle, "HWRS", NULL, &hwrs_result); | ||
1755 | if (!ACPI_FAILURE(status)) | ||
1756 | pr_notice(" HWRS returned %x", (int)hwrs_result); | ||
1757 | |||
1758 | if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL)) | 1749 | if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL)) |
1759 | asus->have_rsts = true; | 1750 | asus->have_rsts = true; |
1760 | 1751 | ||
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index dd90d15f5210..71623a2ff3e8 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c | |||
@@ -1523,6 +1523,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { | |||
1523 | }, | 1523 | }, |
1524 | .driver_data = &samsung_broken_acpi_video, | 1524 | .driver_data = &samsung_broken_acpi_video, |
1525 | }, | 1525 | }, |
1526 | { | ||
1527 | .callback = samsung_dmi_matched, | ||
1528 | .ident = "N250P", | ||
1529 | .matches = { | ||
1530 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), | ||
1531 | DMI_MATCH(DMI_PRODUCT_NAME, "N250P"), | ||
1532 | DMI_MATCH(DMI_BOARD_NAME, "N250P"), | ||
1533 | }, | ||
1534 | .driver_data = &samsung_broken_acpi_video, | ||
1535 | }, | ||
1526 | { }, | 1536 | { }, |
1527 | }; | 1537 | }; |
1528 | MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); | 1538 | MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); |
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index daaddec68def..b8ad71f7863f 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c | |||
@@ -786,28 +786,29 @@ static int sony_nc_int_call(acpi_handle handle, char *name, int *value, | |||
786 | static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value, | 786 | static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value, |
787 | void *buffer, size_t buflen) | 787 | void *buffer, size_t buflen) |
788 | { | 788 | { |
789 | int ret = 0; | ||
789 | size_t len = len; | 790 | size_t len = len; |
790 | union acpi_object *object = __call_snc_method(handle, name, value); | 791 | union acpi_object *object = __call_snc_method(handle, name, value); |
791 | 792 | ||
792 | if (!object) | 793 | if (!object) |
793 | return -EINVAL; | 794 | return -EINVAL; |
794 | 795 | ||
795 | if (object->type == ACPI_TYPE_BUFFER) | 796 | if (object->type == ACPI_TYPE_BUFFER) { |
796 | len = MIN(buflen, object->buffer.length); | 797 | len = MIN(buflen, object->buffer.length); |
798 | memcpy(buffer, object->buffer.pointer, len); | ||
797 | 799 | ||
798 | else if (object->type == ACPI_TYPE_INTEGER) | 800 | } else if (object->type == ACPI_TYPE_INTEGER) { |
799 | len = MIN(buflen, sizeof(object->integer.value)); | 801 | len = MIN(buflen, sizeof(object->integer.value)); |
802 | memcpy(buffer, &object->integer.value, len); | ||
800 | 803 | ||
801 | else { | 804 | } else { |
802 | pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n", | 805 | pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n", |
803 | ACPI_TYPE_BUFFER, object->type); | 806 | ACPI_TYPE_BUFFER, object->type); |
804 | kfree(object); | 807 | ret = -EINVAL; |
805 | return -EINVAL; | ||
806 | } | 808 | } |
807 | 809 | ||
808 | memcpy(buffer, object->buffer.pointer, len); | ||
809 | kfree(object); | 810 | kfree(object); |
810 | return 0; | 811 | return ret; |
811 | } | 812 | } |
812 | 813 | ||
813 | struct sony_nc_handles { | 814 | struct sony_nc_handles { |
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 0f65b246cc0c..278584302f2d 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c | |||
@@ -1885,9 +1885,15 @@ int regulator_can_change_voltage(struct regulator *regulator) | |||
1885 | struct regulator_dev *rdev = regulator->rdev; | 1885 | struct regulator_dev *rdev = regulator->rdev; |
1886 | 1886 | ||
1887 | if (rdev->constraints && | 1887 | if (rdev->constraints && |
1888 | rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE && | 1888 | (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { |
1889 | (rdev->desc->n_voltages - rdev->desc->linear_min_sel) > 1) | 1889 | if (rdev->desc->n_voltages - rdev->desc->linear_min_sel > 1) |
1890 | return 1; | 1890 | return 1; |
1891 | |||
1892 | if (rdev->desc->continuous_voltage_range && | ||
1893 | rdev->constraints->min_uV && rdev->constraints->max_uV && | ||
1894 | rdev->constraints->min_uV != rdev->constraints->max_uV) | ||
1895 | return 1; | ||
1896 | } | ||
1891 | 1897 | ||
1892 | return 0; | 1898 | return 0; |
1893 | } | 1899 | } |
@@ -3315,7 +3321,8 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) | |||
3315 | * @config: runtime configuration for regulator | 3321 | * @config: runtime configuration for regulator |
3316 | * | 3322 | * |
3317 | * Called by regulator drivers to register a regulator. | 3323 | * Called by regulator drivers to register a regulator. |
3318 | * Returns 0 on success. | 3324 | * Returns a valid pointer to struct regulator_dev on success |
3325 | * or an ERR_PTR() on error. | ||
3319 | */ | 3326 | */ |
3320 | struct regulator_dev * | 3327 | struct regulator_dev * |
3321 | regulator_register(const struct regulator_desc *regulator_desc, | 3328 | regulator_register(const struct regulator_desc *regulator_desc, |
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index df0eafb0dc7e..02be7fcae32f 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c | |||
@@ -71,26 +71,26 @@ struct voltage_map_desc { | |||
71 | int step; | 71 | int step; |
72 | }; | 72 | }; |
73 | 73 | ||
74 | /* Voltage maps in mV */ | 74 | /* Voltage maps in uV */ |
75 | static const struct voltage_map_desc ldo_voltage_map_desc = { | 75 | static const struct voltage_map_desc ldo_voltage_map_desc = { |
76 | .min = 800, .max = 3950, .step = 50, | 76 | .min = 800000, .max = 3950000, .step = 50000, |
77 | }; /* LDO1 ~ 18, 21 all */ | 77 | }; /* LDO1 ~ 18, 21 all */ |
78 | 78 | ||
79 | static const struct voltage_map_desc buck1245_voltage_map_desc = { | 79 | static const struct voltage_map_desc buck1245_voltage_map_desc = { |
80 | .min = 650, .max = 2225, .step = 25, | 80 | .min = 650000, .max = 2225000, .step = 25000, |
81 | }; /* Buck1, 2, 4, 5 */ | 81 | }; /* Buck1, 2, 4, 5 */ |
82 | 82 | ||
83 | static const struct voltage_map_desc buck37_voltage_map_desc = { | 83 | static const struct voltage_map_desc buck37_voltage_map_desc = { |
84 | .min = 750, .max = 3900, .step = 50, | 84 | .min = 750000, .max = 3900000, .step = 50000, |
85 | }; /* Buck3, 7 */ | 85 | }; /* Buck3, 7 */ |
86 | 86 | ||
87 | /* current map in mA */ | 87 | /* current map in uA */ |
88 | static const struct voltage_map_desc charger_current_map_desc = { | 88 | static const struct voltage_map_desc charger_current_map_desc = { |
89 | .min = 200, .max = 950, .step = 50, | 89 | .min = 200000, .max = 950000, .step = 50000, |
90 | }; | 90 | }; |
91 | 91 | ||
92 | static const struct voltage_map_desc topoff_current_map_desc = { | 92 | static const struct voltage_map_desc topoff_current_map_desc = { |
93 | .min = 50, .max = 200, .step = 10, | 93 | .min = 50000, .max = 200000, .step = 10000, |
94 | }; | 94 | }; |
95 | 95 | ||
96 | static const struct voltage_map_desc *reg_voltage_map[] = { | 96 | static const struct voltage_map_desc *reg_voltage_map[] = { |
@@ -194,7 +194,7 @@ static int max8997_list_voltage(struct regulator_dev *rdev, | |||
194 | if (val > desc->max) | 194 | if (val > desc->max) |
195 | return -EINVAL; | 195 | return -EINVAL; |
196 | 196 | ||
197 | return val * 1000; | 197 | return val; |
198 | } | 198 | } |
199 | 199 | ||
200 | static int max8997_get_enable_register(struct regulator_dev *rdev, | 200 | static int max8997_get_enable_register(struct regulator_dev *rdev, |
@@ -485,7 +485,6 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev, | |||
485 | { | 485 | { |
486 | struct max8997_data *max8997 = rdev_get_drvdata(rdev); | 486 | struct max8997_data *max8997 = rdev_get_drvdata(rdev); |
487 | struct i2c_client *i2c = max8997->iodev->i2c; | 487 | struct i2c_client *i2c = max8997->iodev->i2c; |
488 | int min_vol = min_uV / 1000, max_vol = max_uV / 1000; | ||
489 | const struct voltage_map_desc *desc; | 488 | const struct voltage_map_desc *desc; |
490 | int rid = rdev_get_id(rdev); | 489 | int rid = rdev_get_id(rdev); |
491 | int i, reg, shift, mask, ret; | 490 | int i, reg, shift, mask, ret; |
@@ -509,7 +508,7 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev, | |||
509 | 508 | ||
510 | desc = reg_voltage_map[rid]; | 509 | desc = reg_voltage_map[rid]; |
511 | 510 | ||
512 | i = max8997_get_voltage_proper_val(desc, min_vol, max_vol); | 511 | i = max8997_get_voltage_proper_val(desc, min_uV, max_uV); |
513 | if (i < 0) | 512 | if (i < 0) |
514 | return i; | 513 | return i; |
515 | 514 | ||
@@ -557,7 +556,7 @@ static int max8997_set_voltage_ldobuck_time_sel(struct regulator_dev *rdev, | |||
557 | case MAX8997_BUCK4: | 556 | case MAX8997_BUCK4: |
558 | case MAX8997_BUCK5: | 557 | case MAX8997_BUCK5: |
559 | return DIV_ROUND_UP(desc->step * (new_selector - old_selector), | 558 | return DIV_ROUND_UP(desc->step * (new_selector - old_selector), |
560 | max8997->ramp_delay); | 559 | max8997->ramp_delay * 1000); |
561 | } | 560 | } |
562 | 561 | ||
563 | return 0; | 562 | return 0; |
@@ -656,7 +655,6 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev, | |||
656 | const struct voltage_map_desc *desc; | 655 | const struct voltage_map_desc *desc; |
657 | int new_val, new_idx, damage, tmp_val, tmp_idx, tmp_dmg; | 656 | int new_val, new_idx, damage, tmp_val, tmp_idx, tmp_dmg; |
658 | bool gpio_dvs_mode = false; | 657 | bool gpio_dvs_mode = false; |
659 | int min_vol = min_uV / 1000, max_vol = max_uV / 1000; | ||
660 | 658 | ||
661 | if (rid < MAX8997_BUCK1 || rid > MAX8997_BUCK7) | 659 | if (rid < MAX8997_BUCK1 || rid > MAX8997_BUCK7) |
662 | return -EINVAL; | 660 | return -EINVAL; |
@@ -681,7 +679,7 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev, | |||
681 | selector); | 679 | selector); |
682 | 680 | ||
683 | desc = reg_voltage_map[rid]; | 681 | desc = reg_voltage_map[rid]; |
684 | new_val = max8997_get_voltage_proper_val(desc, min_vol, max_vol); | 682 | new_val = max8997_get_voltage_proper_val(desc, min_uV, max_uV); |
685 | if (new_val < 0) | 683 | if (new_val < 0) |
686 | return new_val; | 684 | return new_val; |
687 | 685 | ||
@@ -1123,8 +1121,8 @@ static int max8997_pmic_probe(struct platform_device *pdev) | |||
1123 | max8997->buck1_vol[i] = ret = | 1121 | max8997->buck1_vol[i] = ret = |
1124 | max8997_get_voltage_proper_val( | 1122 | max8997_get_voltage_proper_val( |
1125 | &buck1245_voltage_map_desc, | 1123 | &buck1245_voltage_map_desc, |
1126 | pdata->buck1_voltage[i] / 1000, | 1124 | pdata->buck1_voltage[i], |
1127 | pdata->buck1_voltage[i] / 1000 + | 1125 | pdata->buck1_voltage[i] + |
1128 | buck1245_voltage_map_desc.step); | 1126 | buck1245_voltage_map_desc.step); |
1129 | if (ret < 0) | 1127 | if (ret < 0) |
1130 | goto err_out; | 1128 | goto err_out; |
@@ -1132,8 +1130,8 @@ static int max8997_pmic_probe(struct platform_device *pdev) | |||
1132 | max8997->buck2_vol[i] = ret = | 1130 | max8997->buck2_vol[i] = ret = |
1133 | max8997_get_voltage_proper_val( | 1131 | max8997_get_voltage_proper_val( |
1134 | &buck1245_voltage_map_desc, | 1132 | &buck1245_voltage_map_desc, |
1135 | pdata->buck2_voltage[i] / 1000, | 1133 | pdata->buck2_voltage[i], |
1136 | pdata->buck2_voltage[i] / 1000 + | 1134 | pdata->buck2_voltage[i] + |
1137 | buck1245_voltage_map_desc.step); | 1135 | buck1245_voltage_map_desc.step); |
1138 | if (ret < 0) | 1136 | if (ret < 0) |
1139 | goto err_out; | 1137 | goto err_out; |
@@ -1141,8 +1139,8 @@ static int max8997_pmic_probe(struct platform_device *pdev) | |||
1141 | max8997->buck5_vol[i] = ret = | 1139 | max8997->buck5_vol[i] = ret = |
1142 | max8997_get_voltage_proper_val( | 1140 | max8997_get_voltage_proper_val( |
1143 | &buck1245_voltage_map_desc, | 1141 | &buck1245_voltage_map_desc, |
1144 | pdata->buck5_voltage[i] / 1000, | 1142 | pdata->buck5_voltage[i], |
1145 | pdata->buck5_voltage[i] / 1000 + | 1143 | pdata->buck5_voltage[i] + |
1146 | buck1245_voltage_map_desc.step); | 1144 | buck1245_voltage_map_desc.step); |
1147 | if (ret < 0) | 1145 | if (ret < 0) |
1148 | goto err_out; | 1146 | goto err_out; |
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index b821d08eb64a..1f0df4046b86 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c | |||
@@ -51,39 +51,39 @@ struct voltage_map_desc { | |||
51 | int step; | 51 | int step; |
52 | }; | 52 | }; |
53 | 53 | ||
54 | /* Voltage maps */ | 54 | /* Voltage maps in uV*/ |
55 | static const struct voltage_map_desc ldo23_voltage_map_desc = { | 55 | static const struct voltage_map_desc ldo23_voltage_map_desc = { |
56 | .min = 800, .step = 50, .max = 1300, | 56 | .min = 800000, .step = 50000, .max = 1300000, |
57 | }; | 57 | }; |
58 | static const struct voltage_map_desc ldo456711_voltage_map_desc = { | 58 | static const struct voltage_map_desc ldo456711_voltage_map_desc = { |
59 | .min = 1600, .step = 100, .max = 3600, | 59 | .min = 1600000, .step = 100000, .max = 3600000, |
60 | }; | 60 | }; |
61 | static const struct voltage_map_desc ldo8_voltage_map_desc = { | 61 | static const struct voltage_map_desc ldo8_voltage_map_desc = { |
62 | .min = 3000, .step = 100, .max = 3600, | 62 | .min = 3000000, .step = 100000, .max = 3600000, |
63 | }; | 63 | }; |
64 | static const struct voltage_map_desc ldo9_voltage_map_desc = { | 64 | static const struct voltage_map_desc ldo9_voltage_map_desc = { |
65 | .min = 2800, .step = 100, .max = 3100, | 65 | .min = 2800000, .step = 100000, .max = 3100000, |
66 | }; | 66 | }; |
67 | static const struct voltage_map_desc ldo10_voltage_map_desc = { | 67 | static const struct voltage_map_desc ldo10_voltage_map_desc = { |
68 | .min = 950, .step = 50, .max = 1300, | 68 | .min = 95000, .step = 50000, .max = 1300000, |
69 | }; | 69 | }; |
70 | static const struct voltage_map_desc ldo1213_voltage_map_desc = { | 70 | static const struct voltage_map_desc ldo1213_voltage_map_desc = { |
71 | .min = 800, .step = 100, .max = 3300, | 71 | .min = 800000, .step = 100000, .max = 3300000, |
72 | }; | 72 | }; |
73 | static const struct voltage_map_desc ldo1415_voltage_map_desc = { | 73 | static const struct voltage_map_desc ldo1415_voltage_map_desc = { |
74 | .min = 1200, .step = 100, .max = 3300, | 74 | .min = 1200000, .step = 100000, .max = 3300000, |
75 | }; | 75 | }; |
76 | static const struct voltage_map_desc ldo1617_voltage_map_desc = { | 76 | static const struct voltage_map_desc ldo1617_voltage_map_desc = { |
77 | .min = 1600, .step = 100, .max = 3600, | 77 | .min = 1600000, .step = 100000, .max = 3600000, |
78 | }; | 78 | }; |
79 | static const struct voltage_map_desc buck12_voltage_map_desc = { | 79 | static const struct voltage_map_desc buck12_voltage_map_desc = { |
80 | .min = 750, .step = 25, .max = 1525, | 80 | .min = 750000, .step = 25000, .max = 1525000, |
81 | }; | 81 | }; |
82 | static const struct voltage_map_desc buck3_voltage_map_desc = { | 82 | static const struct voltage_map_desc buck3_voltage_map_desc = { |
83 | .min = 1600, .step = 100, .max = 3600, | 83 | .min = 1600000, .step = 100000, .max = 3600000, |
84 | }; | 84 | }; |
85 | static const struct voltage_map_desc buck4_voltage_map_desc = { | 85 | static const struct voltage_map_desc buck4_voltage_map_desc = { |
86 | .min = 800, .step = 100, .max = 2300, | 86 | .min = 800000, .step = 100000, .max = 2300000, |
87 | }; | 87 | }; |
88 | 88 | ||
89 | static const struct voltage_map_desc *ldo_voltage_map[] = { | 89 | static const struct voltage_map_desc *ldo_voltage_map[] = { |
@@ -445,9 +445,9 @@ static int max8998_set_voltage_buck_time_sel(struct regulator_dev *rdev, | |||
445 | if (max8998->iodev->type == TYPE_MAX8998 && !(val & MAX8998_ENRAMP)) | 445 | if (max8998->iodev->type == TYPE_MAX8998 && !(val & MAX8998_ENRAMP)) |
446 | return 0; | 446 | return 0; |
447 | 447 | ||
448 | difference = (new_selector - old_selector) * desc->step; | 448 | difference = (new_selector - old_selector) * desc->step / 1000; |
449 | if (difference > 0) | 449 | if (difference > 0) |
450 | return difference / ((val & 0x0f) + 1); | 450 | return DIV_ROUND_UP(difference, (val & 0x0f) + 1); |
451 | 451 | ||
452 | return 0; | 452 | return 0; |
453 | } | 453 | } |
@@ -702,7 +702,7 @@ static int max8998_pmic_probe(struct platform_device *pdev) | |||
702 | i = 0; | 702 | i = 0; |
703 | while (buck12_voltage_map_desc.min + | 703 | while (buck12_voltage_map_desc.min + |
704 | buck12_voltage_map_desc.step*i | 704 | buck12_voltage_map_desc.step*i |
705 | < (pdata->buck1_voltage1 / 1000)) | 705 | < pdata->buck1_voltage1) |
706 | i++; | 706 | i++; |
707 | max8998->buck1_vol[0] = i; | 707 | max8998->buck1_vol[0] = i; |
708 | ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i); | 708 | ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i); |
@@ -713,7 +713,7 @@ static int max8998_pmic_probe(struct platform_device *pdev) | |||
713 | i = 0; | 713 | i = 0; |
714 | while (buck12_voltage_map_desc.min + | 714 | while (buck12_voltage_map_desc.min + |
715 | buck12_voltage_map_desc.step*i | 715 | buck12_voltage_map_desc.step*i |
716 | < (pdata->buck1_voltage2 / 1000)) | 716 | < pdata->buck1_voltage2) |
717 | i++; | 717 | i++; |
718 | 718 | ||
719 | max8998->buck1_vol[1] = i; | 719 | max8998->buck1_vol[1] = i; |
@@ -725,7 +725,7 @@ static int max8998_pmic_probe(struct platform_device *pdev) | |||
725 | i = 0; | 725 | i = 0; |
726 | while (buck12_voltage_map_desc.min + | 726 | while (buck12_voltage_map_desc.min + |
727 | buck12_voltage_map_desc.step*i | 727 | buck12_voltage_map_desc.step*i |
728 | < (pdata->buck1_voltage3 / 1000)) | 728 | < pdata->buck1_voltage3) |
729 | i++; | 729 | i++; |
730 | 730 | ||
731 | max8998->buck1_vol[2] = i; | 731 | max8998->buck1_vol[2] = i; |
@@ -737,7 +737,7 @@ static int max8998_pmic_probe(struct platform_device *pdev) | |||
737 | i = 0; | 737 | i = 0; |
738 | while (buck12_voltage_map_desc.min + | 738 | while (buck12_voltage_map_desc.min + |
739 | buck12_voltage_map_desc.step*i | 739 | buck12_voltage_map_desc.step*i |
740 | < (pdata->buck1_voltage4 / 1000)) | 740 | < pdata->buck1_voltage4) |
741 | i++; | 741 | i++; |
742 | 742 | ||
743 | max8998->buck1_vol[3] = i; | 743 | max8998->buck1_vol[3] = i; |
@@ -763,7 +763,7 @@ static int max8998_pmic_probe(struct platform_device *pdev) | |||
763 | i = 0; | 763 | i = 0; |
764 | while (buck12_voltage_map_desc.min + | 764 | while (buck12_voltage_map_desc.min + |
765 | buck12_voltage_map_desc.step*i | 765 | buck12_voltage_map_desc.step*i |
766 | < (pdata->buck2_voltage1 / 1000)) | 766 | < pdata->buck2_voltage1) |
767 | i++; | 767 | i++; |
768 | max8998->buck2_vol[0] = i; | 768 | max8998->buck2_vol[0] = i; |
769 | ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i); | 769 | ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i); |
@@ -774,7 +774,7 @@ static int max8998_pmic_probe(struct platform_device *pdev) | |||
774 | i = 0; | 774 | i = 0; |
775 | while (buck12_voltage_map_desc.min + | 775 | while (buck12_voltage_map_desc.min + |
776 | buck12_voltage_map_desc.step*i | 776 | buck12_voltage_map_desc.step*i |
777 | < (pdata->buck2_voltage2 / 1000)) | 777 | < pdata->buck2_voltage2) |
778 | i++; | 778 | i++; |
779 | max8998->buck2_vol[1] = i; | 779 | max8998->buck2_vol[1] = i; |
780 | ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i); | 780 | ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i); |
@@ -792,8 +792,8 @@ static int max8998_pmic_probe(struct platform_device *pdev) | |||
792 | int count = (desc->max - desc->min) / desc->step + 1; | 792 | int count = (desc->max - desc->min) / desc->step + 1; |
793 | 793 | ||
794 | regulators[index].n_voltages = count; | 794 | regulators[index].n_voltages = count; |
795 | regulators[index].min_uV = desc->min * 1000; | 795 | regulators[index].min_uV = desc->min; |
796 | regulators[index].uV_step = desc->step * 1000; | 796 | regulators[index].uV_step = desc->step; |
797 | } | 797 | } |
798 | 798 | ||
799 | config.dev = max8998->dev; | 799 | config.dev = max8998->dev; |
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index 9f991f2c525a..33b65c9ad5d5 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c | |||
@@ -214,7 +214,7 @@ static int s5m8767_reg_is_enabled(struct regulator_dev *rdev) | |||
214 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | 214 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); |
215 | int ret, reg; | 215 | int ret, reg; |
216 | int mask = 0xc0, enable_ctrl; | 216 | int mask = 0xc0, enable_ctrl; |
217 | u8 val; | 217 | unsigned int val; |
218 | 218 | ||
219 | ret = s5m8767_get_register(rdev, ®, &enable_ctrl); | 219 | ret = s5m8767_get_register(rdev, ®, &enable_ctrl); |
220 | if (ret == -EINVAL) | 220 | if (ret == -EINVAL) |
@@ -306,7 +306,7 @@ static int s5m8767_get_voltage_sel(struct regulator_dev *rdev) | |||
306 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | 306 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); |
307 | int reg, mask, ret; | 307 | int reg, mask, ret; |
308 | int reg_id = rdev_get_id(rdev); | 308 | int reg_id = rdev_get_id(rdev); |
309 | u8 val; | 309 | unsigned int val; |
310 | 310 | ||
311 | ret = s5m8767_get_voltage_register(rdev, ®); | 311 | ret = s5m8767_get_voltage_register(rdev, ®); |
312 | if (ret) | 312 | if (ret) |
diff --git a/drivers/rtc/rtc-da9055.c b/drivers/rtc/rtc-da9055.c index 96bafc5c3bf8..8f0dcfedb83c 100644 --- a/drivers/rtc/rtc-da9055.c +++ b/drivers/rtc/rtc-da9055.c | |||
@@ -227,7 +227,7 @@ static const struct rtc_class_ops da9055_rtc_ops = { | |||
227 | .alarm_irq_enable = da9055_rtc_alarm_irq_enable, | 227 | .alarm_irq_enable = da9055_rtc_alarm_irq_enable, |
228 | }; | 228 | }; |
229 | 229 | ||
230 | static int __init da9055_rtc_device_init(struct da9055 *da9055, | 230 | static int da9055_rtc_device_init(struct da9055 *da9055, |
231 | struct da9055_pdata *pdata) | 231 | struct da9055_pdata *pdata) |
232 | { | 232 | { |
233 | int ret; | 233 | int ret; |
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 9bd5da36f99e..704488d0f819 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c | |||
@@ -248,7 +248,7 @@ static void dasd_ext_handler(struct ext_code ext_code, | |||
248 | default: | 248 | default: |
249 | return; | 249 | return; |
250 | } | 250 | } |
251 | kstat_cpu(smp_processor_id()).irqs[EXTINT_DSD]++; | 251 | inc_irq_stat(IRQEXT_DSD); |
252 | if (!ip) { /* no intparm: unsolicited interrupt */ | 252 | if (!ip) { /* no intparm: unsolicited interrupt */ |
253 | DBF_EVENT(DBF_NOTICE, "%s", "caught unsolicited " | 253 | DBF_EVENT(DBF_NOTICE, "%s", "caught unsolicited " |
254 | "interrupt"); | 254 | "interrupt"); |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 806fe912d6e7..e37bc1620d14 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -4274,7 +4274,7 @@ static struct ccw_driver dasd_eckd_driver = { | |||
4274 | .thaw = dasd_generic_restore_device, | 4274 | .thaw = dasd_generic_restore_device, |
4275 | .restore = dasd_generic_restore_device, | 4275 | .restore = dasd_generic_restore_device, |
4276 | .uc_handler = dasd_generic_uc_handler, | 4276 | .uc_handler = dasd_generic_uc_handler, |
4277 | .int_class = IOINT_DAS, | 4277 | .int_class = IRQIO_DAS, |
4278 | }; | 4278 | }; |
4279 | 4279 | ||
4280 | /* | 4280 | /* |
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index eb748507c7fa..414698584344 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c | |||
@@ -78,7 +78,7 @@ static struct ccw_driver dasd_fba_driver = { | |||
78 | .freeze = dasd_generic_pm_freeze, | 78 | .freeze = dasd_generic_pm_freeze, |
79 | .thaw = dasd_generic_restore_device, | 79 | .thaw = dasd_generic_restore_device, |
80 | .restore = dasd_generic_restore_device, | 80 | .restore = dasd_generic_restore_device, |
81 | .int_class = IOINT_DAS, | 81 | .int_class = IRQIO_DAS, |
82 | }; | 82 | }; |
83 | 83 | ||
84 | static void | 84 | static void |
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 40084501c31b..33b7141a182f 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #define RAW3215_NR_CCWS 3 | 44 | #define RAW3215_NR_CCWS 3 |
45 | #define RAW3215_TIMEOUT HZ/10 /* time for delayed output */ | 45 | #define RAW3215_TIMEOUT HZ/10 /* time for delayed output */ |
46 | 46 | ||
47 | #define RAW3215_FIXED 1 /* 3215 console device is not be freed */ | ||
47 | #define RAW3215_WORKING 4 /* set if a request is being worked on */ | 48 | #define RAW3215_WORKING 4 /* set if a request is being worked on */ |
48 | #define RAW3215_THROTTLED 8 /* set if reading is disabled */ | 49 | #define RAW3215_THROTTLED 8 /* set if reading is disabled */ |
49 | #define RAW3215_STOPPED 16 /* set if writing is disabled */ | 50 | #define RAW3215_STOPPED 16 /* set if writing is disabled */ |
@@ -630,7 +631,8 @@ static void raw3215_shutdown(struct raw3215_info *raw) | |||
630 | DECLARE_WAITQUEUE(wait, current); | 631 | DECLARE_WAITQUEUE(wait, current); |
631 | unsigned long flags; | 632 | unsigned long flags; |
632 | 633 | ||
633 | if (!(raw->port.flags & ASYNC_INITIALIZED)) | 634 | if (!(raw->port.flags & ASYNC_INITIALIZED) || |
635 | (raw->flags & RAW3215_FIXED)) | ||
634 | return; | 636 | return; |
635 | /* Wait for outstanding requests, then free irq */ | 637 | /* Wait for outstanding requests, then free irq */ |
636 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); | 638 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); |
@@ -805,7 +807,7 @@ static struct ccw_driver raw3215_ccw_driver = { | |||
805 | .freeze = &raw3215_pm_stop, | 807 | .freeze = &raw3215_pm_stop, |
806 | .thaw = &raw3215_pm_start, | 808 | .thaw = &raw3215_pm_start, |
807 | .restore = &raw3215_pm_start, | 809 | .restore = &raw3215_pm_start, |
808 | .int_class = IOINT_C15, | 810 | .int_class = IRQIO_C15, |
809 | }; | 811 | }; |
810 | 812 | ||
811 | #ifdef CONFIG_TN3215_CONSOLE | 813 | #ifdef CONFIG_TN3215_CONSOLE |
@@ -927,6 +929,8 @@ static int __init con3215_init(void) | |||
927 | dev_set_drvdata(&cdev->dev, raw); | 929 | dev_set_drvdata(&cdev->dev, raw); |
928 | cdev->handler = raw3215_irq; | 930 | cdev->handler = raw3215_irq; |
929 | 931 | ||
932 | raw->flags |= RAW3215_FIXED; | ||
933 | |||
930 | /* Request the console irq */ | 934 | /* Request the console irq */ |
931 | if (raw3215_startup(raw) != 0) { | 935 | if (raw3215_startup(raw) != 0) { |
932 | raw3215_free_info(raw); | 936 | raw3215_free_info(raw); |
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index f3b8bb84faf2..9a6c140c5f07 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c | |||
@@ -1396,7 +1396,7 @@ static struct ccw_driver raw3270_ccw_driver = { | |||
1396 | .freeze = &raw3270_pm_stop, | 1396 | .freeze = &raw3270_pm_stop, |
1397 | .thaw = &raw3270_pm_start, | 1397 | .thaw = &raw3270_pm_start, |
1398 | .restore = &raw3270_pm_start, | 1398 | .restore = &raw3270_pm_start, |
1399 | .int_class = IOINT_C70, | 1399 | .int_class = IRQIO_C70, |
1400 | }; | 1400 | }; |
1401 | 1401 | ||
1402 | static int | 1402 | static int |
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 4fa21f7e2308..12c16a65dd25 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c | |||
@@ -400,7 +400,7 @@ static void sclp_interrupt_handler(struct ext_code ext_code, | |||
400 | u32 finished_sccb; | 400 | u32 finished_sccb; |
401 | u32 evbuf_pending; | 401 | u32 evbuf_pending; |
402 | 402 | ||
403 | kstat_cpu(smp_processor_id()).irqs[EXTINT_SCP]++; | 403 | inc_irq_stat(IRQEXT_SCP); |
404 | spin_lock(&sclp_lock); | 404 | spin_lock(&sclp_lock); |
405 | finished_sccb = param32 & 0xfffffff8; | 405 | finished_sccb = param32 & 0xfffffff8; |
406 | evbuf_pending = param32 & 0x3; | 406 | evbuf_pending = param32 & 0x3; |
@@ -813,7 +813,7 @@ static void sclp_check_handler(struct ext_code ext_code, | |||
813 | { | 813 | { |
814 | u32 finished_sccb; | 814 | u32 finished_sccb; |
815 | 815 | ||
816 | kstat_cpu(smp_processor_id()).irqs[EXTINT_SCP]++; | 816 | inc_irq_stat(IRQEXT_SCP); |
817 | finished_sccb = param32 & 0xfffffff8; | 817 | finished_sccb = param32 & 0xfffffff8; |
818 | /* Is this the interrupt we are waiting for? */ | 818 | /* Is this the interrupt we are waiting for? */ |
819 | if (finished_sccb == 0) | 819 | if (finished_sccb == 0) |
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 6ae929c024ae..9aa79702b370 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c | |||
@@ -1193,7 +1193,7 @@ static struct ccw_driver tape_34xx_driver = { | |||
1193 | .set_online = tape_34xx_online, | 1193 | .set_online = tape_34xx_online, |
1194 | .set_offline = tape_generic_offline, | 1194 | .set_offline = tape_generic_offline, |
1195 | .freeze = tape_generic_pm_suspend, | 1195 | .freeze = tape_generic_pm_suspend, |
1196 | .int_class = IOINT_TAP, | 1196 | .int_class = IRQIO_TAP, |
1197 | }; | 1197 | }; |
1198 | 1198 | ||
1199 | static int | 1199 | static int |
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 1b0eb49f739c..327cb19ad0b0 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c | |||
@@ -1656,7 +1656,7 @@ static struct ccw_driver tape_3590_driver = { | |||
1656 | .set_offline = tape_generic_offline, | 1656 | .set_offline = tape_generic_offline, |
1657 | .set_online = tape_3590_online, | 1657 | .set_online = tape_3590_online, |
1658 | .freeze = tape_generic_pm_suspend, | 1658 | .freeze = tape_generic_pm_suspend, |
1659 | .int_class = IOINT_TAP, | 1659 | .int_class = IRQIO_TAP, |
1660 | }; | 1660 | }; |
1661 | 1661 | ||
1662 | /* | 1662 | /* |
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index 73bef0bd394c..483f72ba030d 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c | |||
@@ -74,7 +74,7 @@ static struct ccw_driver ur_driver = { | |||
74 | .set_online = ur_set_online, | 74 | .set_online = ur_set_online, |
75 | .set_offline = ur_set_offline, | 75 | .set_offline = ur_set_offline, |
76 | .freeze = ur_pm_suspend, | 76 | .freeze = ur_pm_suspend, |
77 | .int_class = IOINT_VMR, | 77 | .int_class = IRQIO_VMR, |
78 | }; | 78 | }; |
79 | 79 | ||
80 | static DEFINE_MUTEX(vmur_mutex); | 80 | static DEFINE_MUTEX(vmur_mutex); |
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 68e80e2734a4..10729bbceced 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -283,7 +283,7 @@ struct chsc_sei_nt2_area { | |||
283 | u8 ccdf[PAGE_SIZE - 24 - 56]; /* content-code dependent field */ | 283 | u8 ccdf[PAGE_SIZE - 24 - 56]; /* content-code dependent field */ |
284 | } __packed; | 284 | } __packed; |
285 | 285 | ||
286 | #define CHSC_SEI_NT0 0ULL | 286 | #define CHSC_SEI_NT0 (1ULL << 63) |
287 | #define CHSC_SEI_NT2 (1ULL << 61) | 287 | #define CHSC_SEI_NT2 (1ULL << 61) |
288 | 288 | ||
289 | struct chsc_sei { | 289 | struct chsc_sei { |
@@ -291,7 +291,8 @@ struct chsc_sei { | |||
291 | u32 reserved1; | 291 | u32 reserved1; |
292 | u64 ntsm; /* notification type mask */ | 292 | u64 ntsm; /* notification type mask */ |
293 | struct chsc_header response; | 293 | struct chsc_header response; |
294 | u32 reserved2; | 294 | u32 :24; |
295 | u8 nt; | ||
295 | union { | 296 | union { |
296 | struct chsc_sei_nt0_area nt0_area; | 297 | struct chsc_sei_nt0_area nt0_area; |
297 | struct chsc_sei_nt2_area nt2_area; | 298 | struct chsc_sei_nt2_area nt2_area; |
@@ -496,17 +497,17 @@ static int __chsc_process_crw(struct chsc_sei *sei, u64 ntsm) | |||
496 | css_schedule_eval_all(); | 497 | css_schedule_eval_all(); |
497 | } | 498 | } |
498 | 499 | ||
499 | switch (sei->ntsm) { | 500 | switch (sei->nt) { |
500 | case CHSC_SEI_NT0: | 501 | case 0: |
501 | chsc_process_sei_nt0(&sei->u.nt0_area); | 502 | chsc_process_sei_nt0(&sei->u.nt0_area); |
502 | return 1; | 503 | break; |
503 | case CHSC_SEI_NT2: | 504 | case 2: |
504 | chsc_process_sei_nt2(&sei->u.nt2_area); | 505 | chsc_process_sei_nt2(&sei->u.nt2_area); |
505 | return 1; | 506 | break; |
506 | default: | 507 | default: |
507 | CIO_CRW_EVENT(2, "chsc: unhandled nt (nt=%08Lx)\n", | 508 | CIO_CRW_EVENT(2, "chsc: unhandled nt=%d\n", |
508 | sei->ntsm); | 509 | sei->nt); |
509 | return 0; | 510 | break; |
510 | } | 511 | } |
511 | } else { | 512 | } else { |
512 | CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n", | 513 | CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n", |
@@ -537,15 +538,7 @@ static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow) | |||
537 | sei = sei_page; | 538 | sei = sei_page; |
538 | 539 | ||
539 | CIO_TRACE_EVENT(2, "prcss"); | 540 | CIO_TRACE_EVENT(2, "prcss"); |
540 | 541 | __chsc_process_crw(sei, CHSC_SEI_NT0 | CHSC_SEI_NT2); | |
541 | /* | ||
542 | * The ntsm does not allow to select NT0 and NT2 together. We need to | ||
543 | * first check for NT2, than additionally for NT0... | ||
544 | */ | ||
545 | #ifdef CONFIG_PCI | ||
546 | if (!__chsc_process_crw(sei, CHSC_SEI_NT2)) | ||
547 | #endif | ||
548 | __chsc_process_crw(sei, CHSC_SEI_NT0); | ||
549 | } | 542 | } |
550 | 543 | ||
551 | void chsc_chp_online(struct chp_id chpid) | 544 | void chsc_chp_online(struct chp_id chpid) |
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 8f9a1a384496..facdf809113f 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c | |||
@@ -58,7 +58,7 @@ static void chsc_subchannel_irq(struct subchannel *sch) | |||
58 | 58 | ||
59 | CHSC_LOG(4, "irb"); | 59 | CHSC_LOG(4, "irb"); |
60 | CHSC_LOG_HEX(4, irb, sizeof(*irb)); | 60 | CHSC_LOG_HEX(4, irb, sizeof(*irb)); |
61 | kstat_cpu(smp_processor_id()).irqs[IOINT_CSC]++; | 61 | inc_irq_stat(IRQIO_CSC); |
62 | 62 | ||
63 | /* Copy irb to provided request and set done. */ | 63 | /* Copy irb to provided request and set done. */ |
64 | if (!request) { | 64 | if (!request) { |
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 8e927b9f285f..c8faf6230b0f 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -611,7 +611,7 @@ void __irq_entry do_IRQ(struct pt_regs *regs) | |||
611 | tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id; | 611 | tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id; |
612 | irb = (struct irb *)&S390_lowcore.irb; | 612 | irb = (struct irb *)&S390_lowcore.irb; |
613 | do { | 613 | do { |
614 | kstat_cpu(smp_processor_id()).irqs[IO_INTERRUPT]++; | 614 | kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL); |
615 | if (tpi_info->adapter_IO) { | 615 | if (tpi_info->adapter_IO) { |
616 | do_adapter_IO(tpi_info->isc); | 616 | do_adapter_IO(tpi_info->isc); |
617 | continue; | 617 | continue; |
@@ -619,7 +619,7 @@ void __irq_entry do_IRQ(struct pt_regs *regs) | |||
619 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; | 619 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; |
620 | if (!sch) { | 620 | if (!sch) { |
621 | /* Clear pending interrupt condition. */ | 621 | /* Clear pending interrupt condition. */ |
622 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | 622 | inc_irq_stat(IRQIO_CIO); |
623 | tsch(tpi_info->schid, irb); | 623 | tsch(tpi_info->schid, irb); |
624 | continue; | 624 | continue; |
625 | } | 625 | } |
@@ -633,9 +633,9 @@ void __irq_entry do_IRQ(struct pt_regs *regs) | |||
633 | if (sch->driver && sch->driver->irq) | 633 | if (sch->driver && sch->driver->irq) |
634 | sch->driver->irq(sch); | 634 | sch->driver->irq(sch); |
635 | else | 635 | else |
636 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | 636 | inc_irq_stat(IRQIO_CIO); |
637 | } else | 637 | } else |
638 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | 638 | inc_irq_stat(IRQIO_CIO); |
639 | spin_unlock(sch->lock); | 639 | spin_unlock(sch->lock); |
640 | /* | 640 | /* |
641 | * Are more interrupts pending? | 641 | * Are more interrupts pending? |
@@ -678,7 +678,7 @@ static void cio_tsch(struct subchannel *sch) | |||
678 | if (sch->driver && sch->driver->irq) | 678 | if (sch->driver && sch->driver->irq) |
679 | sch->driver->irq(sch); | 679 | sch->driver->irq(sch); |
680 | else | 680 | else |
681 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | 681 | inc_irq_stat(IRQIO_CIO); |
682 | if (!irq_context) { | 682 | if (!irq_context) { |
683 | irq_exit(); | 683 | irq_exit(); |
684 | _local_bh_enable(); | 684 | _local_bh_enable(); |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 6995cff44636..7cd5c6812ac7 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -758,7 +758,7 @@ static int io_subchannel_initialize_dev(struct subchannel *sch, | |||
758 | struct ccw_device *cdev) | 758 | struct ccw_device *cdev) |
759 | { | 759 | { |
760 | cdev->private->cdev = cdev; | 760 | cdev->private->cdev = cdev; |
761 | cdev->private->int_class = IOINT_CIO; | 761 | cdev->private->int_class = IRQIO_CIO; |
762 | atomic_set(&cdev->private->onoff, 0); | 762 | atomic_set(&cdev->private->onoff, 0); |
763 | cdev->dev.parent = &sch->dev; | 763 | cdev->dev.parent = &sch->dev; |
764 | cdev->dev.release = ccw_device_release; | 764 | cdev->dev.release = ccw_device_release; |
@@ -1023,7 +1023,7 @@ static void io_subchannel_irq(struct subchannel *sch) | |||
1023 | if (cdev) | 1023 | if (cdev) |
1024 | dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); | 1024 | dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); |
1025 | else | 1025 | else |
1026 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | 1026 | inc_irq_stat(IRQIO_CIO); |
1027 | } | 1027 | } |
1028 | 1028 | ||
1029 | void io_subchannel_init_config(struct subchannel *sch) | 1029 | void io_subchannel_init_config(struct subchannel *sch) |
@@ -1634,7 +1634,7 @@ ccw_device_probe_console(void) | |||
1634 | memset(&console_private, 0, sizeof(struct ccw_device_private)); | 1634 | memset(&console_private, 0, sizeof(struct ccw_device_private)); |
1635 | console_cdev.private = &console_private; | 1635 | console_cdev.private = &console_private; |
1636 | console_private.cdev = &console_cdev; | 1636 | console_private.cdev = &console_cdev; |
1637 | console_private.int_class = IOINT_CIO; | 1637 | console_private.int_class = IRQIO_CIO; |
1638 | ret = ccw_device_console_enable(&console_cdev, sch); | 1638 | ret = ccw_device_console_enable(&console_cdev, sch); |
1639 | if (ret) { | 1639 | if (ret) { |
1640 | cio_release_console(); | 1640 | cio_release_console(); |
@@ -1715,13 +1715,13 @@ ccw_device_probe (struct device *dev) | |||
1715 | if (cdrv->int_class != 0) | 1715 | if (cdrv->int_class != 0) |
1716 | cdev->private->int_class = cdrv->int_class; | 1716 | cdev->private->int_class = cdrv->int_class; |
1717 | else | 1717 | else |
1718 | cdev->private->int_class = IOINT_CIO; | 1718 | cdev->private->int_class = IRQIO_CIO; |
1719 | 1719 | ||
1720 | ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV; | 1720 | ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV; |
1721 | 1721 | ||
1722 | if (ret) { | 1722 | if (ret) { |
1723 | cdev->drv = NULL; | 1723 | cdev->drv = NULL; |
1724 | cdev->private->int_class = IOINT_CIO; | 1724 | cdev->private->int_class = IRQIO_CIO; |
1725 | return ret; | 1725 | return ret; |
1726 | } | 1726 | } |
1727 | 1727 | ||
@@ -1755,7 +1755,7 @@ ccw_device_remove (struct device *dev) | |||
1755 | } | 1755 | } |
1756 | ccw_device_set_timeout(cdev, 0); | 1756 | ccw_device_set_timeout(cdev, 0); |
1757 | cdev->drv = NULL; | 1757 | cdev->drv = NULL; |
1758 | cdev->private->int_class = IOINT_CIO; | 1758 | cdev->private->int_class = IRQIO_CIO; |
1759 | return 0; | 1759 | return 0; |
1760 | } | 1760 | } |
1761 | 1761 | ||
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 2e575cff9845..7d4ecb65db00 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h | |||
@@ -61,11 +61,10 @@ dev_fsm_event(struct ccw_device *cdev, enum dev_event dev_event) | |||
61 | 61 | ||
62 | if (dev_event == DEV_EVENT_INTERRUPT) { | 62 | if (dev_event == DEV_EVENT_INTERRUPT) { |
63 | if (state == DEV_STATE_ONLINE) | 63 | if (state == DEV_STATE_ONLINE) |
64 | kstat_cpu(smp_processor_id()). | 64 | inc_irq_stat(cdev->private->int_class); |
65 | irqs[cdev->private->int_class]++; | ||
66 | else if (state != DEV_STATE_CMFCHANGE && | 65 | else if (state != DEV_STATE_CMFCHANGE && |
67 | state != DEV_STATE_CMFUPDATE) | 66 | state != DEV_STATE_CMFUPDATE) |
68 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | 67 | inc_irq_stat(IRQIO_CIO); |
69 | } | 68 | } |
70 | dev_jumptable[state][dev_event](cdev, dev_event); | 69 | dev_jumptable[state][dev_event](cdev, dev_event); |
71 | } | 70 | } |
diff --git a/drivers/s390/cio/eadm_sch.c b/drivers/s390/cio/eadm_sch.c index 6c9673400464..d9eddcba7e88 100644 --- a/drivers/s390/cio/eadm_sch.c +++ b/drivers/s390/cio/eadm_sch.c | |||
@@ -139,7 +139,7 @@ static void eadm_subchannel_irq(struct subchannel *sch) | |||
139 | EADM_LOG(6, "irq"); | 139 | EADM_LOG(6, "irq"); |
140 | EADM_LOG_HEX(6, irb, sizeof(*irb)); | 140 | EADM_LOG_HEX(6, irb, sizeof(*irb)); |
141 | 141 | ||
142 | kstat_cpu(smp_processor_id()).irqs[IOINT_ADM]++; | 142 | inc_irq_stat(IRQIO_ADM); |
143 | 143 | ||
144 | if ((scsw->stctl & (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)) | 144 | if ((scsw->stctl & (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)) |
145 | && scsw->eswf == 1 && irb->esw.eadm.erw.r) | 145 | && scsw->eswf == 1 && irb->esw.eadm.erw.r) |
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index bdb394b066fc..bde5255200dc 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c | |||
@@ -182,7 +182,7 @@ static void tiqdio_thinint_handler(void *alsi, void *data) | |||
182 | struct qdio_q *q; | 182 | struct qdio_q *q; |
183 | 183 | ||
184 | last_ai_time = S390_lowcore.int_clock; | 184 | last_ai_time = S390_lowcore.int_clock; |
185 | kstat_cpu(smp_processor_id()).irqs[IOINT_QAI]++; | 185 | inc_irq_stat(IRQIO_QAI); |
186 | 186 | ||
187 | /* protect tiq_list entries, only changed in activate or shutdown */ | 187 | /* protect tiq_list entries, only changed in activate or shutdown */ |
188 | rcu_read_lock(); | 188 | rcu_read_lock(); |
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 7b865a7300e6..b8b340ac5332 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c | |||
@@ -1272,7 +1272,7 @@ out: | |||
1272 | 1272 | ||
1273 | static void ap_interrupt_handler(void *unused1, void *unused2) | 1273 | static void ap_interrupt_handler(void *unused1, void *unused2) |
1274 | { | 1274 | { |
1275 | kstat_cpu(smp_processor_id()).irqs[IOINT_APB]++; | 1275 | inc_irq_stat(IRQIO_APB); |
1276 | tasklet_schedule(&ap_tasklet); | 1276 | tasklet_schedule(&ap_tasklet); |
1277 | } | 1277 | } |
1278 | 1278 | ||
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 7dabef624da3..8491111aec12 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c | |||
@@ -392,7 +392,7 @@ static void kvm_extint_handler(struct ext_code ext_code, | |||
392 | 392 | ||
393 | if ((ext_code.subcode & 0xff00) != VIRTIO_SUBCODE_64) | 393 | if ((ext_code.subcode & 0xff00) != VIRTIO_SUBCODE_64) |
394 | return; | 394 | return; |
395 | kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++; | 395 | inc_irq_stat(IRQEXT_VRT); |
396 | 396 | ||
397 | /* The LSB might be overloaded, we have to mask it */ | 397 | /* The LSB might be overloaded, we have to mask it */ |
398 | vq = (struct virtqueue *)(param64 & ~1UL); | 398 | vq = (struct virtqueue *)(param64 & ~1UL); |
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 5c70a6599578..83bc9c5fa0c1 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c | |||
@@ -282,7 +282,7 @@ static struct ccw_driver claw_ccw_driver = { | |||
282 | .ids = claw_ids, | 282 | .ids = claw_ids, |
283 | .probe = ccwgroup_probe_ccwdev, | 283 | .probe = ccwgroup_probe_ccwdev, |
284 | .remove = ccwgroup_remove_ccwdev, | 284 | .remove = ccwgroup_remove_ccwdev, |
285 | .int_class = IOINT_CLW, | 285 | .int_class = IRQIO_CLW, |
286 | }; | 286 | }; |
287 | 287 | ||
288 | static ssize_t claw_driver_group_store(struct device_driver *ddrv, | 288 | static ssize_t claw_driver_group_store(struct device_driver *ddrv, |
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 817b68925ddd..676f12049a36 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c | |||
@@ -1755,7 +1755,7 @@ static struct ccw_driver ctcm_ccw_driver = { | |||
1755 | .ids = ctcm_ids, | 1755 | .ids = ctcm_ids, |
1756 | .probe = ccwgroup_probe_ccwdev, | 1756 | .probe = ccwgroup_probe_ccwdev, |
1757 | .remove = ccwgroup_remove_ccwdev, | 1757 | .remove = ccwgroup_remove_ccwdev, |
1758 | .int_class = IOINT_CTC, | 1758 | .int_class = IRQIO_CTC, |
1759 | }; | 1759 | }; |
1760 | 1760 | ||
1761 | static struct ccwgroup_driver ctcm_group_driver = { | 1761 | static struct ccwgroup_driver ctcm_group_driver = { |
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 2ca0f1dd7a00..c645dc9e98af 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c | |||
@@ -2384,7 +2384,7 @@ static struct ccw_driver lcs_ccw_driver = { | |||
2384 | .ids = lcs_ids, | 2384 | .ids = lcs_ids, |
2385 | .probe = ccwgroup_probe_ccwdev, | 2385 | .probe = ccwgroup_probe_ccwdev, |
2386 | .remove = ccwgroup_remove_ccwdev, | 2386 | .remove = ccwgroup_remove_ccwdev, |
2387 | .int_class = IOINT_LCS, | 2387 | .int_class = IRQIO_LCS, |
2388 | }; | 2388 | }; |
2389 | 2389 | ||
2390 | /** | 2390 | /** |
diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c index 5aedcdf4ac5c..1ebe67cd1833 100644 --- a/drivers/sh/clk/cpg.c +++ b/drivers/sh/clk/cpg.c | |||
@@ -126,6 +126,12 @@ static int sh_clk_div_set_rate(struct clk *clk, unsigned long rate) | |||
126 | 126 | ||
127 | static int sh_clk_div_enable(struct clk *clk) | 127 | static int sh_clk_div_enable(struct clk *clk) |
128 | { | 128 | { |
129 | if (clk->div_mask == SH_CLK_DIV6_MSK) { | ||
130 | int ret = sh_clk_div_set_rate(clk, clk->rate); | ||
131 | if (ret < 0) | ||
132 | return ret; | ||
133 | } | ||
134 | |||
129 | sh_clk_write(sh_clk_read(clk) & ~CPG_CKSTP_BIT, clk); | 135 | sh_clk_write(sh_clk_read(clk) & ~CPG_CKSTP_BIT, clk); |
130 | return 0; | 136 | return 0; |
131 | } | 137 | } |
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 7de2a10213bd..36eec320569c 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig | |||
@@ -444,6 +444,7 @@ config COMEDI_ADQ12B | |||
444 | 444 | ||
445 | config COMEDI_NI_AT_A2150 | 445 | config COMEDI_NI_AT_A2150 |
446 | tristate "NI AT-A2150 ISA card support" | 446 | tristate "NI AT-A2150 ISA card support" |
447 | select COMEDI_FC | ||
447 | depends on VIRT_TO_BUS | 448 | depends on VIRT_TO_BUS |
448 | ---help--- | 449 | ---help--- |
449 | Enable support for National Instruments AT-A2150 cards | 450 | Enable support for National Instruments AT-A2150 cards |
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index b7bba1790a20..9b038e4a7e71 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c | |||
@@ -1549,6 +1549,9 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, | |||
1549 | if (cmd == COMEDI_DEVCONFIG) { | 1549 | if (cmd == COMEDI_DEVCONFIG) { |
1550 | rc = do_devconfig_ioctl(dev, | 1550 | rc = do_devconfig_ioctl(dev, |
1551 | (struct comedi_devconfig __user *)arg); | 1551 | (struct comedi_devconfig __user *)arg); |
1552 | if (rc == 0) | ||
1553 | /* Evade comedi_auto_unconfig(). */ | ||
1554 | dev_file_info->hardware_device = NULL; | ||
1552 | goto done; | 1555 | goto done; |
1553 | } | 1556 | } |
1554 | 1557 | ||
diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index fb3d09323ba1..01de996239f1 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c | |||
@@ -345,7 +345,7 @@ static int waveform_ai_cancel(struct comedi_device *dev, | |||
345 | struct waveform_private *devpriv = dev->private; | 345 | struct waveform_private *devpriv = dev->private; |
346 | 346 | ||
347 | devpriv->timer_running = 0; | 347 | devpriv->timer_running = 0; |
348 | del_timer(&devpriv->timer); | 348 | del_timer_sync(&devpriv->timer); |
349 | return 0; | 349 | return 0; |
350 | } | 350 | } |
351 | 351 | ||
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c index aaac0b2cc9eb..fd1662b4175d 100644 --- a/drivers/staging/comedi/drivers/ni_pcimio.c +++ b/drivers/staging/comedi/drivers/ni_pcimio.c | |||
@@ -963,7 +963,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
963 | .ao_range_table = &range_ni_M_625x_ao, | 963 | .ao_range_table = &range_ni_M_625x_ao, |
964 | .reg_type = ni_reg_625x, | 964 | .reg_type = ni_reg_625x, |
965 | .ao_unipolar = 0, | 965 | .ao_unipolar = 0, |
966 | .ao_speed = 357, | 966 | .ao_speed = 350, |
967 | .num_p0_dio_channels = 8, | 967 | .num_p0_dio_channels = 8, |
968 | .caldac = {caldac_none}, | 968 | .caldac = {caldac_none}, |
969 | .has_8255 = 0, | 969 | .has_8255 = 0, |
@@ -982,7 +982,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
982 | .ao_range_table = &range_ni_M_625x_ao, | 982 | .ao_range_table = &range_ni_M_625x_ao, |
983 | .reg_type = ni_reg_625x, | 983 | .reg_type = ni_reg_625x, |
984 | .ao_unipolar = 0, | 984 | .ao_unipolar = 0, |
985 | .ao_speed = 357, | 985 | .ao_speed = 350, |
986 | .num_p0_dio_channels = 8, | 986 | .num_p0_dio_channels = 8, |
987 | .caldac = {caldac_none}, | 987 | .caldac = {caldac_none}, |
988 | .has_8255 = 0, | 988 | .has_8255 = 0, |
@@ -1001,7 +1001,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
1001 | .ao_range_table = &range_ni_M_625x_ao, | 1001 | .ao_range_table = &range_ni_M_625x_ao, |
1002 | .reg_type = ni_reg_625x, | 1002 | .reg_type = ni_reg_625x, |
1003 | .ao_unipolar = 0, | 1003 | .ao_unipolar = 0, |
1004 | .ao_speed = 357, | 1004 | .ao_speed = 350, |
1005 | .num_p0_dio_channels = 8, | 1005 | .num_p0_dio_channels = 8, |
1006 | .caldac = {caldac_none}, | 1006 | .caldac = {caldac_none}, |
1007 | .has_8255 = 0, | 1007 | .has_8255 = 0, |
@@ -1037,7 +1037,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
1037 | .ao_range_table = &range_ni_M_625x_ao, | 1037 | .ao_range_table = &range_ni_M_625x_ao, |
1038 | .reg_type = ni_reg_625x, | 1038 | .reg_type = ni_reg_625x, |
1039 | .ao_unipolar = 0, | 1039 | .ao_unipolar = 0, |
1040 | .ao_speed = 357, | 1040 | .ao_speed = 350, |
1041 | .num_p0_dio_channels = 32, | 1041 | .num_p0_dio_channels = 32, |
1042 | .caldac = {caldac_none}, | 1042 | .caldac = {caldac_none}, |
1043 | .has_8255 = 0, | 1043 | .has_8255 = 0, |
@@ -1056,7 +1056,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
1056 | .ao_range_table = &range_ni_M_625x_ao, | 1056 | .ao_range_table = &range_ni_M_625x_ao, |
1057 | .reg_type = ni_reg_625x, | 1057 | .reg_type = ni_reg_625x, |
1058 | .ao_unipolar = 0, | 1058 | .ao_unipolar = 0, |
1059 | .ao_speed = 357, | 1059 | .ao_speed = 350, |
1060 | .num_p0_dio_channels = 32, | 1060 | .num_p0_dio_channels = 32, |
1061 | .caldac = {caldac_none}, | 1061 | .caldac = {caldac_none}, |
1062 | .has_8255 = 0, | 1062 | .has_8255 = 0, |
@@ -1092,7 +1092,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
1092 | .ao_range_table = &range_ni_M_628x_ao, | 1092 | .ao_range_table = &range_ni_M_628x_ao, |
1093 | .reg_type = ni_reg_628x, | 1093 | .reg_type = ni_reg_628x, |
1094 | .ao_unipolar = 1, | 1094 | .ao_unipolar = 1, |
1095 | .ao_speed = 357, | 1095 | .ao_speed = 350, |
1096 | .num_p0_dio_channels = 8, | 1096 | .num_p0_dio_channels = 8, |
1097 | .caldac = {caldac_none}, | 1097 | .caldac = {caldac_none}, |
1098 | .has_8255 = 0, | 1098 | .has_8255 = 0, |
@@ -1111,7 +1111,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
1111 | .ao_range_table = &range_ni_M_628x_ao, | 1111 | .ao_range_table = &range_ni_M_628x_ao, |
1112 | .reg_type = ni_reg_628x, | 1112 | .reg_type = ni_reg_628x, |
1113 | .ao_unipolar = 1, | 1113 | .ao_unipolar = 1, |
1114 | .ao_speed = 357, | 1114 | .ao_speed = 350, |
1115 | .num_p0_dio_channels = 8, | 1115 | .num_p0_dio_channels = 8, |
1116 | .caldac = {caldac_none}, | 1116 | .caldac = {caldac_none}, |
1117 | .has_8255 = 0, | 1117 | .has_8255 = 0, |
@@ -1147,7 +1147,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
1147 | .ao_range_table = &range_ni_M_628x_ao, | 1147 | .ao_range_table = &range_ni_M_628x_ao, |
1148 | .reg_type = ni_reg_628x, | 1148 | .reg_type = ni_reg_628x, |
1149 | .ao_unipolar = 1, | 1149 | .ao_unipolar = 1, |
1150 | .ao_speed = 357, | 1150 | .ao_speed = 350, |
1151 | .num_p0_dio_channels = 32, | 1151 | .num_p0_dio_channels = 32, |
1152 | .caldac = {caldac_none}, | 1152 | .caldac = {caldac_none}, |
1153 | .has_8255 = 0, | 1153 | .has_8255 = 0, |
diff --git a/drivers/staging/fwserial/Kconfig b/drivers/staging/fwserial/Kconfig index 580406cb1808..b2f8331e4acf 100644 --- a/drivers/staging/fwserial/Kconfig +++ b/drivers/staging/fwserial/Kconfig | |||
@@ -3,7 +3,9 @@ config FIREWIRE_SERIAL | |||
3 | depends on FIREWIRE | 3 | depends on FIREWIRE |
4 | help | 4 | help |
5 | This enables TTY over IEEE 1394, providing high-speed serial | 5 | This enables TTY over IEEE 1394, providing high-speed serial |
6 | connectivity to cabled peers. | 6 | connectivity to cabled peers. This driver implements a |
7 | ad-hoc transport protocol and is currently limited to | ||
8 | Linux-to-Linux communication. | ||
7 | 9 | ||
8 | To compile this driver as a module, say M here: the module will | 10 | To compile this driver as a module, say M here: the module will |
9 | be called firewire-serial. | 11 | be called firewire-serial. |
diff --git a/drivers/staging/fwserial/TODO b/drivers/staging/fwserial/TODO index 726900548eae..8dae8fb25223 100644 --- a/drivers/staging/fwserial/TODO +++ b/drivers/staging/fwserial/TODO | |||
@@ -1,5 +1,5 @@ | |||
1 | TODOs | 1 | TODOs prior to this driver moving out of staging |
2 | ----- | 2 | ------------------------------------------------ |
3 | 1. Implement retries for RCODE_BUSY, RCODE_NO_ACK and RCODE_SEND_ERROR | 3 | 1. Implement retries for RCODE_BUSY, RCODE_NO_ACK and RCODE_SEND_ERROR |
4 | - I/O is handled asynchronously which presents some issues when error | 4 | - I/O is handled asynchronously which presents some issues when error |
5 | conditions occur. | 5 | conditions occur. |
@@ -11,17 +11,9 @@ TODOs | |||
11 | -- Issues with firewire stack -- | 11 | -- Issues with firewire stack -- |
12 | 1. This driver uses the same unregistered vendor id that the firewire core does | 12 | 1. This driver uses the same unregistered vendor id that the firewire core does |
13 | (0xd00d1e). Perhaps this could be exposed as a define in | 13 | (0xd00d1e). Perhaps this could be exposed as a define in |
14 | firewire-constants.h? | 14 | firewire.h? |
15 | 2. MAX_ASYNC_PAYLOAD needs to be publicly exposed by core/ohci | ||
16 | - otherwise how will this driver know the max size of address window to | ||
17 | open for one packet write? | ||
18 | 3. Maybe device_max_receive() and link_speed_to_max_payload() should be | 15 | 3. Maybe device_max_receive() and link_speed_to_max_payload() should be |
19 | taken up by the firewire core? | 16 | taken up by the firewire core? |
20 | 4. To avoid dropping rx data while still limiting the maximum buffering, | ||
21 | the size of the AR context must be known. How to expose this to drivers? | ||
22 | 5. Explore if bigger AR context will reduce RCODE_BUSY responses | ||
23 | (or auto-grow to certain max size -- but this would require major surgery | ||
24 | as the current AR is contiguously mapped) | ||
25 | 17 | ||
26 | -- Issues with TTY core -- | 18 | -- Issues with TTY core -- |
27 | 1. Hack for alternate device name scheme | 19 | 1. Hack for alternate device name scheme |
diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c index 61ee29083b26..d03a7f57e8d4 100644 --- a/drivers/staging/fwserial/fwserial.c +++ b/drivers/staging/fwserial/fwserial.c | |||
@@ -179,7 +179,7 @@ static void dump_profile(struct seq_file *m, struct stats *stats) | |||
179 | /* Returns the max receive packet size for the given card */ | 179 | /* Returns the max receive packet size for the given card */ |
180 | static inline int device_max_receive(struct fw_device *fw_device) | 180 | static inline int device_max_receive(struct fw_device *fw_device) |
181 | { | 181 | { |
182 | return 1 << (clamp_t(int, fw_device->max_rec, 8U, 13U) + 1); | 182 | return 1 << (clamp_t(int, fw_device->max_rec, 8U, 11U) + 1); |
183 | } | 183 | } |
184 | 184 | ||
185 | static void fwtty_log_tx_error(struct fwtty_port *port, int rcode) | 185 | static void fwtty_log_tx_error(struct fwtty_port *port, int rcode) |
diff --git a/drivers/staging/fwserial/fwserial.h b/drivers/staging/fwserial/fwserial.h index 8b572edf9563..caa1c1ea82d5 100644 --- a/drivers/staging/fwserial/fwserial.h +++ b/drivers/staging/fwserial/fwserial.h | |||
@@ -374,10 +374,10 @@ static inline void fwtty_bind_console(struct fwtty_port *port, | |||
374 | */ | 374 | */ |
375 | static inline int link_speed_to_max_payload(unsigned speed) | 375 | static inline int link_speed_to_max_payload(unsigned speed) |
376 | { | 376 | { |
377 | static const int max_async[] = { 307, 614, 1229, 2458, 4916, 9832, }; | 377 | static const int max_async[] = { 307, 614, 1229, 2458, }; |
378 | BUILD_BUG_ON(ARRAY_SIZE(max_async) - 1 != SCODE_3200); | 378 | BUILD_BUG_ON(ARRAY_SIZE(max_async) - 1 != SCODE_800); |
379 | 379 | ||
380 | speed = clamp(speed, (unsigned) SCODE_100, (unsigned) SCODE_3200); | 380 | speed = clamp(speed, (unsigned) SCODE_100, (unsigned) SCODE_800); |
381 | if (limit_bw) | 381 | if (limit_bw) |
382 | return max_async[speed]; | 382 | return max_async[speed]; |
383 | else | 383 | else |
diff --git a/drivers/staging/iio/gyro/Kconfig b/drivers/staging/iio/gyro/Kconfig index ea295b25308c..87979a0d03a9 100644 --- a/drivers/staging/iio/gyro/Kconfig +++ b/drivers/staging/iio/gyro/Kconfig | |||
@@ -27,8 +27,8 @@ config ADIS16130 | |||
27 | config ADIS16260 | 27 | config ADIS16260 |
28 | tristate "Analog Devices ADIS16260 Digital Gyroscope Sensor SPI driver" | 28 | tristate "Analog Devices ADIS16260 Digital Gyroscope Sensor SPI driver" |
29 | depends on SPI | 29 | depends on SPI |
30 | select IIO_TRIGGER if IIO_BUFFER | 30 | select IIO_ADIS_LIB |
31 | select IIO_SW_RING if IIO_BUFFER | 31 | select IIO_ADIS_LIB_BUFFER if IIO_BUFFER |
32 | help | 32 | help |
33 | Say yes here to build support for Analog Devices ADIS16260 ADIS16265 | 33 | Say yes here to build support for Analog Devices ADIS16260 ADIS16265 |
34 | ADIS16250 ADIS16255 and ADIS16251 programmable digital gyroscope sensors. | 34 | ADIS16250 ADIS16255 and ADIS16251 programmable digital gyroscope sensors. |
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c index ecf0f44bc70e..cec19f1cf56c 100644 --- a/drivers/staging/imx-drm/imx-drm-core.c +++ b/drivers/staging/imx-drm/imx-drm-core.c | |||
@@ -584,7 +584,6 @@ int imx_drm_add_encoder(struct drm_encoder *encoder, | |||
584 | 584 | ||
585 | ret = imx_drm_encoder_register(imx_drm_encoder); | 585 | ret = imx_drm_encoder_register(imx_drm_encoder); |
586 | if (ret) { | 586 | if (ret) { |
587 | kfree(imx_drm_encoder); | ||
588 | ret = -ENOMEM; | 587 | ret = -ENOMEM; |
589 | goto err_register; | 588 | goto err_register; |
590 | } | 589 | } |
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c index 677e665ca86d..f7059cddd7fd 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c | |||
@@ -1104,7 +1104,9 @@ static int ipu_probe(struct platform_device *pdev) | |||
1104 | if (ret) | 1104 | if (ret) |
1105 | goto out_failed_irq; | 1105 | goto out_failed_irq; |
1106 | 1106 | ||
1107 | ipu_reset(ipu); | 1107 | ret = ipu_reset(ipu); |
1108 | if (ret) | ||
1109 | goto out_failed_reset; | ||
1108 | 1110 | ||
1109 | /* Set MCU_T to divide MCU access window into 2 */ | 1111 | /* Set MCU_T to divide MCU access window into 2 */ |
1110 | ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18), | 1112 | ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18), |
@@ -1129,6 +1131,7 @@ failed_add_clients: | |||
1129 | ipu_submodules_exit(ipu); | 1131 | ipu_submodules_exit(ipu); |
1130 | failed_submodules_init: | 1132 | failed_submodules_init: |
1131 | ipu_irq_exit(ipu); | 1133 | ipu_irq_exit(ipu); |
1134 | out_failed_reset: | ||
1132 | out_failed_irq: | 1135 | out_failed_irq: |
1133 | clk_disable_unprepare(ipu->clk); | 1136 | clk_disable_unprepare(ipu->clk); |
1134 | failed_clk_get: | 1137 | failed_clk_get: |
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c index 1892006526b5..4b3a019409b5 100644 --- a/drivers/staging/imx-drm/ipuv3-crtc.c +++ b/drivers/staging/imx-drm/ipuv3-crtc.c | |||
@@ -452,7 +452,7 @@ static int ipu_get_resources(struct ipu_crtc *ipu_crtc, | |||
452 | int ret; | 452 | int ret; |
453 | 453 | ||
454 | ipu_crtc->ipu_ch = ipu_idmac_get(ipu, pdata->dma[0]); | 454 | ipu_crtc->ipu_ch = ipu_idmac_get(ipu, pdata->dma[0]); |
455 | if (IS_ERR_OR_NULL(ipu_crtc->ipu_ch)) { | 455 | if (IS_ERR(ipu_crtc->ipu_ch)) { |
456 | ret = PTR_ERR(ipu_crtc->ipu_ch); | 456 | ret = PTR_ERR(ipu_crtc->ipu_ch); |
457 | goto err_out; | 457 | goto err_out; |
458 | } | 458 | } |
@@ -472,7 +472,7 @@ static int ipu_get_resources(struct ipu_crtc *ipu_crtc, | |||
472 | if (pdata->dp >= 0) { | 472 | if (pdata->dp >= 0) { |
473 | ipu_crtc->dp = ipu_dp_get(ipu, pdata->dp); | 473 | ipu_crtc->dp = ipu_dp_get(ipu, pdata->dp); |
474 | if (IS_ERR(ipu_crtc->dp)) { | 474 | if (IS_ERR(ipu_crtc->dp)) { |
475 | ret = PTR_ERR(ipu_crtc->ipu_ch); | 475 | ret = PTR_ERR(ipu_crtc->dp); |
476 | goto err_out; | 476 | goto err_out; |
477 | } | 477 | } |
478 | } | 478 | } |
@@ -548,6 +548,8 @@ static int ipu_drm_probe(struct platform_device *pdev) | |||
548 | ipu_crtc->dev = &pdev->dev; | 548 | ipu_crtc->dev = &pdev->dev; |
549 | 549 | ||
550 | ret = ipu_crtc_init(ipu_crtc, pdata); | 550 | ret = ipu_crtc_init(ipu_crtc, pdata); |
551 | if (ret) | ||
552 | return ret; | ||
551 | 553 | ||
552 | platform_set_drvdata(pdev, ipu_crtc); | 554 | platform_set_drvdata(pdev, ipu_crtc); |
553 | 555 | ||
diff --git a/drivers/staging/omapdrm/Makefile b/drivers/staging/omapdrm/Makefile index 1ca0e0016de4..d85e058f2845 100644 --- a/drivers/staging/omapdrm/Makefile +++ b/drivers/staging/omapdrm/Makefile | |||
@@ -5,6 +5,7 @@ | |||
5 | 5 | ||
6 | ccflags-y := -Iinclude/drm -Werror | 6 | ccflags-y := -Iinclude/drm -Werror |
7 | omapdrm-y := omap_drv.o \ | 7 | omapdrm-y := omap_drv.o \ |
8 | omap_irq.o \ | ||
8 | omap_debugfs.o \ | 9 | omap_debugfs.o \ |
9 | omap_crtc.o \ | 10 | omap_crtc.o \ |
10 | omap_plane.o \ | 11 | omap_plane.o \ |
diff --git a/drivers/staging/omapdrm/TODO b/drivers/staging/omapdrm/TODO index 938c7888ca31..abeeb00aaa12 100644 --- a/drivers/staging/omapdrm/TODO +++ b/drivers/staging/omapdrm/TODO | |||
@@ -17,9 +17,6 @@ TODO | |||
17 | . Revisit GEM sync object infrastructure.. TTM has some framework for this | 17 | . Revisit GEM sync object infrastructure.. TTM has some framework for this |
18 | already. Possibly this could be refactored out and made more common? | 18 | already. Possibly this could be refactored out and made more common? |
19 | There should be some way to do this with less wheel-reinvention. | 19 | There should be some way to do this with less wheel-reinvention. |
20 | . Review DSS vs KMS mismatches. The omap_dss_device is sort of part encoder, | ||
21 | part connector. Which results in a bit of duct tape to fwd calls from | ||
22 | encoder to connector. Possibly this could be done a bit better. | ||
23 | . Solve PM sequencing on resume. DMM/TILER must be reloaded before any | 20 | . Solve PM sequencing on resume. DMM/TILER must be reloaded before any |
24 | access is made from any component in the system. Which means on suspend | 21 | access is made from any component in the system. Which means on suspend |
25 | CRTC's should be disabled, and on resume the LUT should be reprogrammed | 22 | CRTC's should be disabled, and on resume the LUT should be reprogrammed |
diff --git a/drivers/staging/omapdrm/omap_connector.c b/drivers/staging/omapdrm/omap_connector.c index 91edb3f96972..4cc9ee733c5f 100644 --- a/drivers/staging/omapdrm/omap_connector.c +++ b/drivers/staging/omapdrm/omap_connector.c | |||
@@ -31,9 +31,10 @@ | |||
31 | struct omap_connector { | 31 | struct omap_connector { |
32 | struct drm_connector base; | 32 | struct drm_connector base; |
33 | struct omap_dss_device *dssdev; | 33 | struct omap_dss_device *dssdev; |
34 | struct drm_encoder *encoder; | ||
34 | }; | 35 | }; |
35 | 36 | ||
36 | static inline void copy_timings_omap_to_drm(struct drm_display_mode *mode, | 37 | void copy_timings_omap_to_drm(struct drm_display_mode *mode, |
37 | struct omap_video_timings *timings) | 38 | struct omap_video_timings *timings) |
38 | { | 39 | { |
39 | mode->clock = timings->pixel_clock; | 40 | mode->clock = timings->pixel_clock; |
@@ -64,7 +65,7 @@ static inline void copy_timings_omap_to_drm(struct drm_display_mode *mode, | |||
64 | mode->flags |= DRM_MODE_FLAG_NVSYNC; | 65 | mode->flags |= DRM_MODE_FLAG_NVSYNC; |
65 | } | 66 | } |
66 | 67 | ||
67 | static inline void copy_timings_drm_to_omap(struct omap_video_timings *timings, | 68 | void copy_timings_drm_to_omap(struct omap_video_timings *timings, |
68 | struct drm_display_mode *mode) | 69 | struct drm_display_mode *mode) |
69 | { | 70 | { |
70 | timings->pixel_clock = mode->clock; | 71 | timings->pixel_clock = mode->clock; |
@@ -96,48 +97,7 @@ static inline void copy_timings_drm_to_omap(struct omap_video_timings *timings, | |||
96 | timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; | 97 | timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; |
97 | } | 98 | } |
98 | 99 | ||
99 | static void omap_connector_dpms(struct drm_connector *connector, int mode) | 100 | static enum drm_connector_status omap_connector_detect( |
100 | { | ||
101 | struct omap_connector *omap_connector = to_omap_connector(connector); | ||
102 | struct omap_dss_device *dssdev = omap_connector->dssdev; | ||
103 | int old_dpms; | ||
104 | |||
105 | DBG("%s: %d", dssdev->name, mode); | ||
106 | |||
107 | old_dpms = connector->dpms; | ||
108 | |||
109 | /* from off to on, do from crtc to connector */ | ||
110 | if (mode < old_dpms) | ||
111 | drm_helper_connector_dpms(connector, mode); | ||
112 | |||
113 | if (mode == DRM_MODE_DPMS_ON) { | ||
114 | /* store resume info for suspended displays */ | ||
115 | switch (dssdev->state) { | ||
116 | case OMAP_DSS_DISPLAY_SUSPENDED: | ||
117 | dssdev->activate_after_resume = true; | ||
118 | break; | ||
119 | case OMAP_DSS_DISPLAY_DISABLED: { | ||
120 | int ret = dssdev->driver->enable(dssdev); | ||
121 | if (ret) { | ||
122 | DBG("%s: failed to enable: %d", | ||
123 | dssdev->name, ret); | ||
124 | dssdev->driver->disable(dssdev); | ||
125 | } | ||
126 | break; | ||
127 | } | ||
128 | default: | ||
129 | break; | ||
130 | } | ||
131 | } else { | ||
132 | /* TODO */ | ||
133 | } | ||
134 | |||
135 | /* from on to off, do from connector to crtc */ | ||
136 | if (mode > old_dpms) | ||
137 | drm_helper_connector_dpms(connector, mode); | ||
138 | } | ||
139 | |||
140 | enum drm_connector_status omap_connector_detect( | ||
141 | struct drm_connector *connector, bool force) | 101 | struct drm_connector *connector, bool force) |
142 | { | 102 | { |
143 | struct omap_connector *omap_connector = to_omap_connector(connector); | 103 | struct omap_connector *omap_connector = to_omap_connector(connector); |
@@ -164,8 +124,6 @@ static void omap_connector_destroy(struct drm_connector *connector) | |||
164 | struct omap_connector *omap_connector = to_omap_connector(connector); | 124 | struct omap_connector *omap_connector = to_omap_connector(connector); |
165 | struct omap_dss_device *dssdev = omap_connector->dssdev; | 125 | struct omap_dss_device *dssdev = omap_connector->dssdev; |
166 | 126 | ||
167 | dssdev->driver->disable(dssdev); | ||
168 | |||
169 | DBG("%s", omap_connector->dssdev->name); | 127 | DBG("%s", omap_connector->dssdev->name); |
170 | drm_sysfs_connector_remove(connector); | 128 | drm_sysfs_connector_remove(connector); |
171 | drm_connector_cleanup(connector); | 129 | drm_connector_cleanup(connector); |
@@ -261,36 +219,12 @@ static int omap_connector_mode_valid(struct drm_connector *connector, | |||
261 | struct drm_encoder *omap_connector_attached_encoder( | 219 | struct drm_encoder *omap_connector_attached_encoder( |
262 | struct drm_connector *connector) | 220 | struct drm_connector *connector) |
263 | { | 221 | { |
264 | int i; | ||
265 | struct omap_connector *omap_connector = to_omap_connector(connector); | 222 | struct omap_connector *omap_connector = to_omap_connector(connector); |
266 | 223 | return omap_connector->encoder; | |
267 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { | ||
268 | struct drm_mode_object *obj; | ||
269 | |||
270 | if (connector->encoder_ids[i] == 0) | ||
271 | break; | ||
272 | |||
273 | obj = drm_mode_object_find(connector->dev, | ||
274 | connector->encoder_ids[i], | ||
275 | DRM_MODE_OBJECT_ENCODER); | ||
276 | |||
277 | if (obj) { | ||
278 | struct drm_encoder *encoder = obj_to_encoder(obj); | ||
279 | struct omap_overlay_manager *mgr = | ||
280 | omap_encoder_get_manager(encoder); | ||
281 | DBG("%s: found %s", omap_connector->dssdev->name, | ||
282 | mgr->name); | ||
283 | return encoder; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | DBG("%s: no encoder", omap_connector->dssdev->name); | ||
288 | |||
289 | return NULL; | ||
290 | } | 224 | } |
291 | 225 | ||
292 | static const struct drm_connector_funcs omap_connector_funcs = { | 226 | static const struct drm_connector_funcs omap_connector_funcs = { |
293 | .dpms = omap_connector_dpms, | 227 | .dpms = drm_helper_connector_dpms, |
294 | .detect = omap_connector_detect, | 228 | .detect = omap_connector_detect, |
295 | .fill_modes = drm_helper_probe_single_connector_modes, | 229 | .fill_modes = drm_helper_probe_single_connector_modes, |
296 | .destroy = omap_connector_destroy, | 230 | .destroy = omap_connector_destroy, |
@@ -302,34 +236,6 @@ static const struct drm_connector_helper_funcs omap_connector_helper_funcs = { | |||
302 | .best_encoder = omap_connector_attached_encoder, | 236 | .best_encoder = omap_connector_attached_encoder, |
303 | }; | 237 | }; |
304 | 238 | ||
305 | /* called from encoder when mode is set, to propagate settings to the dssdev */ | ||
306 | void omap_connector_mode_set(struct drm_connector *connector, | ||
307 | struct drm_display_mode *mode) | ||
308 | { | ||
309 | struct drm_device *dev = connector->dev; | ||
310 | struct omap_connector *omap_connector = to_omap_connector(connector); | ||
311 | struct omap_dss_device *dssdev = omap_connector->dssdev; | ||
312 | struct omap_dss_driver *dssdrv = dssdev->driver; | ||
313 | struct omap_video_timings timings = {0}; | ||
314 | |||
315 | copy_timings_drm_to_omap(&timings, mode); | ||
316 | |||
317 | DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | ||
318 | omap_connector->dssdev->name, | ||
319 | mode->base.id, mode->name, mode->vrefresh, mode->clock, | ||
320 | mode->hdisplay, mode->hsync_start, | ||
321 | mode->hsync_end, mode->htotal, | ||
322 | mode->vdisplay, mode->vsync_start, | ||
323 | mode->vsync_end, mode->vtotal, mode->type, mode->flags); | ||
324 | |||
325 | if (dssdrv->check_timings(dssdev, &timings)) { | ||
326 | dev_err(dev->dev, "could not set timings\n"); | ||
327 | return; | ||
328 | } | ||
329 | |||
330 | dssdrv->set_timings(dssdev, &timings); | ||
331 | } | ||
332 | |||
333 | /* flush an area of the framebuffer (in case of manual update display that | 239 | /* flush an area of the framebuffer (in case of manual update display that |
334 | * is not automatically flushed) | 240 | * is not automatically flushed) |
335 | */ | 241 | */ |
@@ -344,7 +250,8 @@ void omap_connector_flush(struct drm_connector *connector, | |||
344 | 250 | ||
345 | /* initialize connector */ | 251 | /* initialize connector */ |
346 | struct drm_connector *omap_connector_init(struct drm_device *dev, | 252 | struct drm_connector *omap_connector_init(struct drm_device *dev, |
347 | int connector_type, struct omap_dss_device *dssdev) | 253 | int connector_type, struct omap_dss_device *dssdev, |
254 | struct drm_encoder *encoder) | ||
348 | { | 255 | { |
349 | struct drm_connector *connector = NULL; | 256 | struct drm_connector *connector = NULL; |
350 | struct omap_connector *omap_connector; | 257 | struct omap_connector *omap_connector; |
@@ -360,6 +267,8 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, | |||
360 | } | 267 | } |
361 | 268 | ||
362 | omap_connector->dssdev = dssdev; | 269 | omap_connector->dssdev = dssdev; |
270 | omap_connector->encoder = encoder; | ||
271 | |||
363 | connector = &omap_connector->base; | 272 | connector = &omap_connector->base; |
364 | 273 | ||
365 | drm_connector_init(dev, connector, &omap_connector_funcs, | 274 | drm_connector_init(dev, connector, &omap_connector_funcs, |
diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c index d87bd84257bd..510942e67020 100644 --- a/drivers/staging/omapdrm/omap_crtc.c +++ b/drivers/staging/omapdrm/omap_crtc.c | |||
@@ -28,19 +28,131 @@ | |||
28 | struct omap_crtc { | 28 | struct omap_crtc { |
29 | struct drm_crtc base; | 29 | struct drm_crtc base; |
30 | struct drm_plane *plane; | 30 | struct drm_plane *plane; |
31 | |||
31 | const char *name; | 32 | const char *name; |
32 | int id; | 33 | int pipe; |
34 | enum omap_channel channel; | ||
35 | struct omap_overlay_manager_info info; | ||
36 | |||
37 | /* | ||
38 | * Temporary: eventually this will go away, but it is needed | ||
39 | * for now to keep the output's happy. (They only need | ||
40 | * mgr->id.) Eventually this will be replaced w/ something | ||
41 | * more common-panel-framework-y | ||
42 | */ | ||
43 | struct omap_overlay_manager mgr; | ||
44 | |||
45 | struct omap_video_timings timings; | ||
46 | bool enabled; | ||
47 | bool full_update; | ||
48 | |||
49 | struct omap_drm_apply apply; | ||
50 | |||
51 | struct omap_drm_irq apply_irq; | ||
52 | struct omap_drm_irq error_irq; | ||
53 | |||
54 | /* list of in-progress apply's: */ | ||
55 | struct list_head pending_applies; | ||
56 | |||
57 | /* list of queued apply's: */ | ||
58 | struct list_head queued_applies; | ||
59 | |||
60 | /* for handling queued and in-progress applies: */ | ||
61 | struct work_struct apply_work; | ||
33 | 62 | ||
34 | /* if there is a pending flip, these will be non-null: */ | 63 | /* if there is a pending flip, these will be non-null: */ |
35 | struct drm_pending_vblank_event *event; | 64 | struct drm_pending_vblank_event *event; |
36 | struct drm_framebuffer *old_fb; | 65 | struct drm_framebuffer *old_fb; |
66 | |||
67 | /* for handling page flips without caring about what | ||
68 | * the callback is called from. Possibly we should just | ||
69 | * make omap_gem always call the cb from the worker so | ||
70 | * we don't have to care about this.. | ||
71 | * | ||
72 | * XXX maybe fold into apply_work?? | ||
73 | */ | ||
74 | struct work_struct page_flip_work; | ||
75 | }; | ||
76 | |||
77 | /* | ||
78 | * Manager-ops, callbacks from output when they need to configure | ||
79 | * the upstream part of the video pipe. | ||
80 | * | ||
81 | * Most of these we can ignore until we add support for command-mode | ||
82 | * panels.. for video-mode the crtc-helpers already do an adequate | ||
83 | * job of sequencing the setup of the video pipe in the proper order | ||
84 | */ | ||
85 | |||
86 | /* we can probably ignore these until we support command-mode panels: */ | ||
87 | static void omap_crtc_start_update(struct omap_overlay_manager *mgr) | ||
88 | { | ||
89 | } | ||
90 | |||
91 | static int omap_crtc_enable(struct omap_overlay_manager *mgr) | ||
92 | { | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static void omap_crtc_disable(struct omap_overlay_manager *mgr) | ||
97 | { | ||
98 | } | ||
99 | |||
100 | static void omap_crtc_set_timings(struct omap_overlay_manager *mgr, | ||
101 | const struct omap_video_timings *timings) | ||
102 | { | ||
103 | struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr); | ||
104 | DBG("%s", omap_crtc->name); | ||
105 | omap_crtc->timings = *timings; | ||
106 | omap_crtc->full_update = true; | ||
107 | } | ||
108 | |||
109 | static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr, | ||
110 | const struct dss_lcd_mgr_config *config) | ||
111 | { | ||
112 | struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr); | ||
113 | DBG("%s", omap_crtc->name); | ||
114 | dispc_mgr_set_lcd_config(omap_crtc->channel, config); | ||
115 | } | ||
116 | |||
117 | static int omap_crtc_register_framedone_handler( | ||
118 | struct omap_overlay_manager *mgr, | ||
119 | void (*handler)(void *), void *data) | ||
120 | { | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static void omap_crtc_unregister_framedone_handler( | ||
125 | struct omap_overlay_manager *mgr, | ||
126 | void (*handler)(void *), void *data) | ||
127 | { | ||
128 | } | ||
129 | |||
130 | static const struct dss_mgr_ops mgr_ops = { | ||
131 | .start_update = omap_crtc_start_update, | ||
132 | .enable = omap_crtc_enable, | ||
133 | .disable = omap_crtc_disable, | ||
134 | .set_timings = omap_crtc_set_timings, | ||
135 | .set_lcd_config = omap_crtc_set_lcd_config, | ||
136 | .register_framedone_handler = omap_crtc_register_framedone_handler, | ||
137 | .unregister_framedone_handler = omap_crtc_unregister_framedone_handler, | ||
37 | }; | 138 | }; |
38 | 139 | ||
140 | /* | ||
141 | * CRTC funcs: | ||
142 | */ | ||
143 | |||
39 | static void omap_crtc_destroy(struct drm_crtc *crtc) | 144 | static void omap_crtc_destroy(struct drm_crtc *crtc) |
40 | { | 145 | { |
41 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 146 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
147 | |||
148 | DBG("%s", omap_crtc->name); | ||
149 | |||
150 | WARN_ON(omap_crtc->apply_irq.registered); | ||
151 | omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); | ||
152 | |||
42 | omap_crtc->plane->funcs->destroy(omap_crtc->plane); | 153 | omap_crtc->plane->funcs->destroy(omap_crtc->plane); |
43 | drm_crtc_cleanup(crtc); | 154 | drm_crtc_cleanup(crtc); |
155 | |||
44 | kfree(omap_crtc); | 156 | kfree(omap_crtc); |
45 | } | 157 | } |
46 | 158 | ||
@@ -48,14 +160,25 @@ static void omap_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
48 | { | 160 | { |
49 | struct omap_drm_private *priv = crtc->dev->dev_private; | 161 | struct omap_drm_private *priv = crtc->dev->dev_private; |
50 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 162 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
163 | bool enabled = (mode == DRM_MODE_DPMS_ON); | ||
51 | int i; | 164 | int i; |
52 | 165 | ||
53 | WARN_ON(omap_plane_dpms(omap_crtc->plane, mode)); | 166 | DBG("%s: %d", omap_crtc->name, mode); |
167 | |||
168 | if (enabled != omap_crtc->enabled) { | ||
169 | omap_crtc->enabled = enabled; | ||
170 | omap_crtc->full_update = true; | ||
171 | omap_crtc_apply(crtc, &omap_crtc->apply); | ||
54 | 172 | ||
55 | for (i = 0; i < priv->num_planes; i++) { | 173 | /* also enable our private plane: */ |
56 | struct drm_plane *plane = priv->planes[i]; | 174 | WARN_ON(omap_plane_dpms(omap_crtc->plane, mode)); |
57 | if (plane->crtc == crtc) | 175 | |
58 | WARN_ON(omap_plane_dpms(plane, mode)); | 176 | /* and any attached overlay planes: */ |
177 | for (i = 0; i < priv->num_planes; i++) { | ||
178 | struct drm_plane *plane = priv->planes[i]; | ||
179 | if (plane->crtc == crtc) | ||
180 | WARN_ON(omap_plane_dpms(plane, mode)); | ||
181 | } | ||
59 | } | 182 | } |
60 | } | 183 | } |
61 | 184 | ||
@@ -73,12 +196,26 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc, | |||
73 | struct drm_framebuffer *old_fb) | 196 | struct drm_framebuffer *old_fb) |
74 | { | 197 | { |
75 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 198 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
76 | struct drm_plane *plane = omap_crtc->plane; | ||
77 | 199 | ||
78 | return omap_plane_mode_set(plane, crtc, crtc->fb, | 200 | mode = adjusted_mode; |
201 | |||
202 | DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | ||
203 | omap_crtc->name, mode->base.id, mode->name, | ||
204 | mode->vrefresh, mode->clock, | ||
205 | mode->hdisplay, mode->hsync_start, | ||
206 | mode->hsync_end, mode->htotal, | ||
207 | mode->vdisplay, mode->vsync_start, | ||
208 | mode->vsync_end, mode->vtotal, | ||
209 | mode->type, mode->flags); | ||
210 | |||
211 | copy_timings_drm_to_omap(&omap_crtc->timings, mode); | ||
212 | omap_crtc->full_update = true; | ||
213 | |||
214 | return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb, | ||
79 | 0, 0, mode->hdisplay, mode->vdisplay, | 215 | 0, 0, mode->hdisplay, mode->vdisplay, |
80 | x << 16, y << 16, | 216 | x << 16, y << 16, |
81 | mode->hdisplay << 16, mode->vdisplay << 16); | 217 | mode->hdisplay << 16, mode->vdisplay << 16, |
218 | NULL, NULL); | ||
82 | } | 219 | } |
83 | 220 | ||
84 | static void omap_crtc_prepare(struct drm_crtc *crtc) | 221 | static void omap_crtc_prepare(struct drm_crtc *crtc) |
@@ -102,10 +239,11 @@ static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | |||
102 | struct drm_plane *plane = omap_crtc->plane; | 239 | struct drm_plane *plane = omap_crtc->plane; |
103 | struct drm_display_mode *mode = &crtc->mode; | 240 | struct drm_display_mode *mode = &crtc->mode; |
104 | 241 | ||
105 | return plane->funcs->update_plane(plane, crtc, crtc->fb, | 242 | return omap_plane_mode_set(plane, crtc, crtc->fb, |
106 | 0, 0, mode->hdisplay, mode->vdisplay, | 243 | 0, 0, mode->hdisplay, mode->vdisplay, |
107 | x << 16, y << 16, | 244 | x << 16, y << 16, |
108 | mode->hdisplay << 16, mode->vdisplay << 16); | 245 | mode->hdisplay << 16, mode->vdisplay << 16, |
246 | NULL, NULL); | ||
109 | } | 247 | } |
110 | 248 | ||
111 | static void omap_crtc_load_lut(struct drm_crtc *crtc) | 249 | static void omap_crtc_load_lut(struct drm_crtc *crtc) |
@@ -114,63 +252,54 @@ static void omap_crtc_load_lut(struct drm_crtc *crtc) | |||
114 | 252 | ||
115 | static void vblank_cb(void *arg) | 253 | static void vblank_cb(void *arg) |
116 | { | 254 | { |
117 | static uint32_t sequence; | ||
118 | struct drm_crtc *crtc = arg; | 255 | struct drm_crtc *crtc = arg; |
119 | struct drm_device *dev = crtc->dev; | 256 | struct drm_device *dev = crtc->dev; |
120 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 257 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
121 | struct drm_pending_vblank_event *event = omap_crtc->event; | ||
122 | unsigned long flags; | 258 | unsigned long flags; |
123 | struct timeval now; | ||
124 | 259 | ||
125 | WARN_ON(!event); | 260 | spin_lock_irqsave(&dev->event_lock, flags); |
261 | |||
262 | /* wakeup userspace */ | ||
263 | if (omap_crtc->event) | ||
264 | drm_send_vblank_event(dev, omap_crtc->pipe, omap_crtc->event); | ||
126 | 265 | ||
127 | omap_crtc->event = NULL; | 266 | omap_crtc->event = NULL; |
267 | omap_crtc->old_fb = NULL; | ||
128 | 268 | ||
129 | /* wakeup userspace */ | 269 | spin_unlock_irqrestore(&dev->event_lock, flags); |
130 | if (event) { | ||
131 | do_gettimeofday(&now); | ||
132 | |||
133 | spin_lock_irqsave(&dev->event_lock, flags); | ||
134 | /* TODO: we can't yet use the vblank time accounting, | ||
135 | * because omapdss lower layer is the one that knows | ||
136 | * the irq # and registers the handler, which more or | ||
137 | * less defeats how drm_irq works.. for now just fake | ||
138 | * the sequence number and use gettimeofday.. | ||
139 | * | ||
140 | event->event.sequence = drm_vblank_count_and_time( | ||
141 | dev, omap_crtc->id, &now); | ||
142 | */ | ||
143 | event->event.sequence = sequence++; | ||
144 | event->event.tv_sec = now.tv_sec; | ||
145 | event->event.tv_usec = now.tv_usec; | ||
146 | list_add_tail(&event->base.link, | ||
147 | &event->base.file_priv->event_list); | ||
148 | wake_up_interruptible(&event->base.file_priv->event_wait); | ||
149 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
150 | } | ||
151 | } | 270 | } |
152 | 271 | ||
153 | static void page_flip_cb(void *arg) | 272 | static void page_flip_worker(struct work_struct *work) |
154 | { | 273 | { |
155 | struct drm_crtc *crtc = arg; | 274 | struct omap_crtc *omap_crtc = |
156 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 275 | container_of(work, struct omap_crtc, page_flip_work); |
157 | struct drm_framebuffer *old_fb = omap_crtc->old_fb; | 276 | struct drm_crtc *crtc = &omap_crtc->base; |
277 | struct drm_device *dev = crtc->dev; | ||
278 | struct drm_display_mode *mode = &crtc->mode; | ||
158 | struct drm_gem_object *bo; | 279 | struct drm_gem_object *bo; |
159 | 280 | ||
160 | omap_crtc->old_fb = NULL; | 281 | drm_modeset_lock_all(dev); |
161 | 282 | omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb, | |
162 | omap_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb); | 283 | 0, 0, mode->hdisplay, mode->vdisplay, |
163 | 284 | crtc->x << 16, crtc->y << 16, | |
164 | /* really we'd like to setup the callback atomically w/ setting the | 285 | mode->hdisplay << 16, mode->vdisplay << 16, |
165 | * new scanout buffer to avoid getting stuck waiting an extra vblank | 286 | vblank_cb, crtc); |
166 | * cycle.. for now go for correctness and later figure out speed.. | 287 | drm_modeset_unlock_all(dev); |
167 | */ | ||
168 | omap_plane_on_endwin(omap_crtc->plane, vblank_cb, crtc); | ||
169 | 288 | ||
170 | bo = omap_framebuffer_bo(crtc->fb, 0); | 289 | bo = omap_framebuffer_bo(crtc->fb, 0); |
171 | drm_gem_object_unreference_unlocked(bo); | 290 | drm_gem_object_unreference_unlocked(bo); |
172 | } | 291 | } |
173 | 292 | ||
293 | static void page_flip_cb(void *arg) | ||
294 | { | ||
295 | struct drm_crtc *crtc = arg; | ||
296 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
297 | struct omap_drm_private *priv = crtc->dev->dev_private; | ||
298 | |||
299 | /* avoid assumptions about what ctxt we are called from: */ | ||
300 | queue_work(priv->wq, &omap_crtc->page_flip_work); | ||
301 | } | ||
302 | |||
174 | static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, | 303 | static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, |
175 | struct drm_framebuffer *fb, | 304 | struct drm_framebuffer *fb, |
176 | struct drm_pending_vblank_event *event) | 305 | struct drm_pending_vblank_event *event) |
@@ -179,14 +308,14 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, | |||
179 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 308 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
180 | struct drm_gem_object *bo; | 309 | struct drm_gem_object *bo; |
181 | 310 | ||
182 | DBG("%d -> %d", crtc->fb ? crtc->fb->base.id : -1, fb->base.id); | 311 | DBG("%d -> %d (event=%p)", crtc->fb ? crtc->fb->base.id : -1, |
312 | fb->base.id, event); | ||
183 | 313 | ||
184 | if (omap_crtc->event) { | 314 | if (omap_crtc->old_fb) { |
185 | dev_err(dev->dev, "already a pending flip\n"); | 315 | dev_err(dev->dev, "already a pending flip\n"); |
186 | return -EINVAL; | 316 | return -EINVAL; |
187 | } | 317 | } |
188 | 318 | ||
189 | omap_crtc->old_fb = crtc->fb; | ||
190 | omap_crtc->event = event; | 319 | omap_crtc->event = event; |
191 | crtc->fb = fb; | 320 | crtc->fb = fb; |
192 | 321 | ||
@@ -234,14 +363,244 @@ static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = { | |||
234 | .load_lut = omap_crtc_load_lut, | 363 | .load_lut = omap_crtc_load_lut, |
235 | }; | 364 | }; |
236 | 365 | ||
366 | const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc) | ||
367 | { | ||
368 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
369 | return &omap_crtc->timings; | ||
370 | } | ||
371 | |||
372 | enum omap_channel omap_crtc_channel(struct drm_crtc *crtc) | ||
373 | { | ||
374 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
375 | return omap_crtc->channel; | ||
376 | } | ||
377 | |||
378 | static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus) | ||
379 | { | ||
380 | struct omap_crtc *omap_crtc = | ||
381 | container_of(irq, struct omap_crtc, error_irq); | ||
382 | struct drm_crtc *crtc = &omap_crtc->base; | ||
383 | DRM_ERROR("%s: errors: %08x\n", omap_crtc->name, irqstatus); | ||
384 | /* avoid getting in a flood, unregister the irq until next vblank */ | ||
385 | omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); | ||
386 | } | ||
387 | |||
388 | static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus) | ||
389 | { | ||
390 | struct omap_crtc *omap_crtc = | ||
391 | container_of(irq, struct omap_crtc, apply_irq); | ||
392 | struct drm_crtc *crtc = &omap_crtc->base; | ||
393 | |||
394 | if (!omap_crtc->error_irq.registered) | ||
395 | omap_irq_register(crtc->dev, &omap_crtc->error_irq); | ||
396 | |||
397 | if (!dispc_mgr_go_busy(omap_crtc->channel)) { | ||
398 | struct omap_drm_private *priv = | ||
399 | crtc->dev->dev_private; | ||
400 | DBG("%s: apply done", omap_crtc->name); | ||
401 | omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq); | ||
402 | queue_work(priv->wq, &omap_crtc->apply_work); | ||
403 | } | ||
404 | } | ||
405 | |||
406 | static void apply_worker(struct work_struct *work) | ||
407 | { | ||
408 | struct omap_crtc *omap_crtc = | ||
409 | container_of(work, struct omap_crtc, apply_work); | ||
410 | struct drm_crtc *crtc = &omap_crtc->base; | ||
411 | struct drm_device *dev = crtc->dev; | ||
412 | struct omap_drm_apply *apply, *n; | ||
413 | bool need_apply; | ||
414 | |||
415 | /* | ||
416 | * Synchronize everything on mode_config.mutex, to keep | ||
417 | * the callbacks and list modification all serialized | ||
418 | * with respect to modesetting ioctls from userspace. | ||
419 | */ | ||
420 | drm_modeset_lock_all(dev); | ||
421 | dispc_runtime_get(); | ||
422 | |||
423 | /* | ||
424 | * If we are still pending a previous update, wait.. when the | ||
425 | * pending update completes, we get kicked again. | ||
426 | */ | ||
427 | if (omap_crtc->apply_irq.registered) | ||
428 | goto out; | ||
429 | |||
430 | /* finish up previous apply's: */ | ||
431 | list_for_each_entry_safe(apply, n, | ||
432 | &omap_crtc->pending_applies, pending_node) { | ||
433 | apply->post_apply(apply); | ||
434 | list_del(&apply->pending_node); | ||
435 | } | ||
436 | |||
437 | need_apply = !list_empty(&omap_crtc->queued_applies); | ||
438 | |||
439 | /* then handle the next round of of queued apply's: */ | ||
440 | list_for_each_entry_safe(apply, n, | ||
441 | &omap_crtc->queued_applies, queued_node) { | ||
442 | apply->pre_apply(apply); | ||
443 | list_del(&apply->queued_node); | ||
444 | apply->queued = false; | ||
445 | list_add_tail(&apply->pending_node, | ||
446 | &omap_crtc->pending_applies); | ||
447 | } | ||
448 | |||
449 | if (need_apply) { | ||
450 | enum omap_channel channel = omap_crtc->channel; | ||
451 | |||
452 | DBG("%s: GO", omap_crtc->name); | ||
453 | |||
454 | if (dispc_mgr_is_enabled(channel)) { | ||
455 | omap_irq_register(dev, &omap_crtc->apply_irq); | ||
456 | dispc_mgr_go(channel); | ||
457 | } else { | ||
458 | struct omap_drm_private *priv = dev->dev_private; | ||
459 | queue_work(priv->wq, &omap_crtc->apply_work); | ||
460 | } | ||
461 | } | ||
462 | |||
463 | out: | ||
464 | dispc_runtime_put(); | ||
465 | drm_modeset_unlock_all(dev); | ||
466 | } | ||
467 | |||
468 | int omap_crtc_apply(struct drm_crtc *crtc, | ||
469 | struct omap_drm_apply *apply) | ||
470 | { | ||
471 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
472 | struct drm_device *dev = crtc->dev; | ||
473 | |||
474 | WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); | ||
475 | |||
476 | /* no need to queue it again if it is already queued: */ | ||
477 | if (apply->queued) | ||
478 | return 0; | ||
479 | |||
480 | apply->queued = true; | ||
481 | list_add_tail(&apply->queued_node, &omap_crtc->queued_applies); | ||
482 | |||
483 | /* | ||
484 | * If there are no currently pending updates, then go ahead and | ||
485 | * kick the worker immediately, otherwise it will run again when | ||
486 | * the current update finishes. | ||
487 | */ | ||
488 | if (list_empty(&omap_crtc->pending_applies)) { | ||
489 | struct omap_drm_private *priv = crtc->dev->dev_private; | ||
490 | queue_work(priv->wq, &omap_crtc->apply_work); | ||
491 | } | ||
492 | |||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | /* called only from apply */ | ||
497 | static void set_enabled(struct drm_crtc *crtc, bool enable) | ||
498 | { | ||
499 | struct drm_device *dev = crtc->dev; | ||
500 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
501 | enum omap_channel channel = omap_crtc->channel; | ||
502 | struct omap_irq_wait *wait = NULL; | ||
503 | |||
504 | if (dispc_mgr_is_enabled(channel) == enable) | ||
505 | return; | ||
506 | |||
507 | /* ignore sync-lost irqs during enable/disable */ | ||
508 | omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); | ||
509 | |||
510 | if (dispc_mgr_get_framedone_irq(channel)) { | ||
511 | if (!enable) { | ||
512 | wait = omap_irq_wait_init(dev, | ||
513 | dispc_mgr_get_framedone_irq(channel), 1); | ||
514 | } | ||
515 | } else { | ||
516 | /* | ||
517 | * When we disable digit output, we need to wait until fields | ||
518 | * are done. Otherwise the DSS is still working, and turning | ||
519 | * off the clocks prevents DSS from going to OFF mode. And when | ||
520 | * enabling, we need to wait for the extra sync losts | ||
521 | */ | ||
522 | wait = omap_irq_wait_init(dev, | ||
523 | dispc_mgr_get_vsync_irq(channel), 2); | ||
524 | } | ||
525 | |||
526 | dispc_mgr_enable(channel, enable); | ||
527 | |||
528 | if (wait) { | ||
529 | int ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100)); | ||
530 | if (ret) { | ||
531 | dev_err(dev->dev, "%s: timeout waiting for %s\n", | ||
532 | omap_crtc->name, enable ? "enable" : "disable"); | ||
533 | } | ||
534 | } | ||
535 | |||
536 | omap_irq_register(crtc->dev, &omap_crtc->error_irq); | ||
537 | } | ||
538 | |||
539 | static void omap_crtc_pre_apply(struct omap_drm_apply *apply) | ||
540 | { | ||
541 | struct omap_crtc *omap_crtc = | ||
542 | container_of(apply, struct omap_crtc, apply); | ||
543 | struct drm_crtc *crtc = &omap_crtc->base; | ||
544 | struct drm_encoder *encoder = NULL; | ||
545 | |||
546 | DBG("%s: enabled=%d, full=%d", omap_crtc->name, | ||
547 | omap_crtc->enabled, omap_crtc->full_update); | ||
548 | |||
549 | if (omap_crtc->full_update) { | ||
550 | struct omap_drm_private *priv = crtc->dev->dev_private; | ||
551 | int i; | ||
552 | for (i = 0; i < priv->num_encoders; i++) { | ||
553 | if (priv->encoders[i]->crtc == crtc) { | ||
554 | encoder = priv->encoders[i]; | ||
555 | break; | ||
556 | } | ||
557 | } | ||
558 | } | ||
559 | |||
560 | if (!omap_crtc->enabled) { | ||
561 | set_enabled(&omap_crtc->base, false); | ||
562 | if (encoder) | ||
563 | omap_encoder_set_enabled(encoder, false); | ||
564 | } else { | ||
565 | if (encoder) { | ||
566 | omap_encoder_set_enabled(encoder, false); | ||
567 | omap_encoder_update(encoder, &omap_crtc->mgr, | ||
568 | &omap_crtc->timings); | ||
569 | omap_encoder_set_enabled(encoder, true); | ||
570 | omap_crtc->full_update = false; | ||
571 | } | ||
572 | |||
573 | dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info); | ||
574 | dispc_mgr_set_timings(omap_crtc->channel, | ||
575 | &omap_crtc->timings); | ||
576 | set_enabled(&omap_crtc->base, true); | ||
577 | } | ||
578 | |||
579 | omap_crtc->full_update = false; | ||
580 | } | ||
581 | |||
582 | static void omap_crtc_post_apply(struct omap_drm_apply *apply) | ||
583 | { | ||
584 | /* nothing needed for post-apply */ | ||
585 | } | ||
586 | |||
587 | static const char *channel_names[] = { | ||
588 | [OMAP_DSS_CHANNEL_LCD] = "lcd", | ||
589 | [OMAP_DSS_CHANNEL_DIGIT] = "tv", | ||
590 | [OMAP_DSS_CHANNEL_LCD2] = "lcd2", | ||
591 | }; | ||
592 | |||
237 | /* initialize crtc */ | 593 | /* initialize crtc */ |
238 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, | 594 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, |
239 | struct omap_overlay *ovl, int id) | 595 | struct drm_plane *plane, enum omap_channel channel, int id) |
240 | { | 596 | { |
241 | struct drm_crtc *crtc = NULL; | 597 | struct drm_crtc *crtc = NULL; |
242 | struct omap_crtc *omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL); | 598 | struct omap_crtc *omap_crtc; |
599 | struct omap_overlay_manager_info *info; | ||
600 | |||
601 | DBG("%s", channel_names[channel]); | ||
243 | 602 | ||
244 | DBG("%s", ovl->name); | 603 | omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL); |
245 | 604 | ||
246 | if (!omap_crtc) { | 605 | if (!omap_crtc) { |
247 | dev_err(dev->dev, "could not allocate CRTC\n"); | 606 | dev_err(dev->dev, "could not allocate CRTC\n"); |
@@ -250,10 +609,40 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, | |||
250 | 609 | ||
251 | crtc = &omap_crtc->base; | 610 | crtc = &omap_crtc->base; |
252 | 611 | ||
253 | omap_crtc->plane = omap_plane_init(dev, ovl, (1 << id), true); | 612 | INIT_WORK(&omap_crtc->page_flip_work, page_flip_worker); |
613 | INIT_WORK(&omap_crtc->apply_work, apply_worker); | ||
614 | |||
615 | INIT_LIST_HEAD(&omap_crtc->pending_applies); | ||
616 | INIT_LIST_HEAD(&omap_crtc->queued_applies); | ||
617 | |||
618 | omap_crtc->apply.pre_apply = omap_crtc_pre_apply; | ||
619 | omap_crtc->apply.post_apply = omap_crtc_post_apply; | ||
620 | |||
621 | omap_crtc->apply_irq.irqmask = pipe2vbl(id); | ||
622 | omap_crtc->apply_irq.irq = omap_crtc_apply_irq; | ||
623 | |||
624 | omap_crtc->error_irq.irqmask = | ||
625 | dispc_mgr_get_sync_lost_irq(channel); | ||
626 | omap_crtc->error_irq.irq = omap_crtc_error_irq; | ||
627 | omap_irq_register(dev, &omap_crtc->error_irq); | ||
628 | |||
629 | omap_crtc->channel = channel; | ||
630 | omap_crtc->plane = plane; | ||
254 | omap_crtc->plane->crtc = crtc; | 631 | omap_crtc->plane->crtc = crtc; |
255 | omap_crtc->name = ovl->name; | 632 | omap_crtc->name = channel_names[channel]; |
256 | omap_crtc->id = id; | 633 | omap_crtc->pipe = id; |
634 | |||
635 | /* temporary: */ | ||
636 | omap_crtc->mgr.id = channel; | ||
637 | |||
638 | dss_install_mgr_ops(&mgr_ops); | ||
639 | |||
640 | /* TODO: fix hard-coded setup.. add properties! */ | ||
641 | info = &omap_crtc->info; | ||
642 | info->default_color = 0x00000000; | ||
643 | info->trans_key = 0x00000000; | ||
644 | info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST; | ||
645 | info->trans_enabled = false; | ||
257 | 646 | ||
258 | drm_crtc_init(dev, crtc, &omap_crtc_funcs); | 647 | drm_crtc_init(dev, crtc, &omap_crtc_funcs); |
259 | drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); | 648 | drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); |
diff --git a/drivers/staging/omapdrm/omap_debugfs.c b/drivers/staging/omapdrm/omap_debugfs.c index 2f122e00b51d..e95540b3e2f6 100644 --- a/drivers/staging/omapdrm/omap_debugfs.c +++ b/drivers/staging/omapdrm/omap_debugfs.c | |||
@@ -72,6 +72,7 @@ static int fb_show(struct seq_file *m, void *arg) | |||
72 | seq_printf(m, "fbcon "); | 72 | seq_printf(m, "fbcon "); |
73 | omap_framebuffer_describe(priv->fbdev->fb, m); | 73 | omap_framebuffer_describe(priv->fbdev->fb, m); |
74 | 74 | ||
75 | mutex_lock(&dev->mode_config.fb_lock); | ||
75 | list_for_each_entry(fb, &dev->mode_config.fb_list, head) { | 76 | list_for_each_entry(fb, &dev->mode_config.fb_list, head) { |
76 | if (fb == priv->fbdev->fb) | 77 | if (fb == priv->fbdev->fb) |
77 | continue; | 78 | continue; |
@@ -79,6 +80,7 @@ static int fb_show(struct seq_file *m, void *arg) | |||
79 | seq_printf(m, "user "); | 80 | seq_printf(m, "user "); |
80 | omap_framebuffer_describe(fb, m); | 81 | omap_framebuffer_describe(fb, m); |
81 | } | 82 | } |
83 | mutex_unlock(&dev->mode_config.fb_lock); | ||
82 | 84 | ||
83 | mutex_unlock(&dev->struct_mutex); | 85 | mutex_unlock(&dev->struct_mutex); |
84 | mutex_unlock(&dev->mode_config.mutex); | 86 | mutex_unlock(&dev->mode_config.mutex); |
diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c index 84943e5ba1d6..dfdb4ba1e7c6 100644 --- a/drivers/staging/omapdrm/omap_drv.c +++ b/drivers/staging/omapdrm/omap_drv.c | |||
@@ -74,320 +74,99 @@ static int get_connector_type(struct omap_dss_device *dssdev) | |||
74 | } | 74 | } |
75 | } | 75 | } |
76 | 76 | ||
77 | #if 0 /* enable when dss2 supports hotplug */ | 77 | static int omap_modeset_init(struct drm_device *dev) |
78 | static int omap_drm_notifier(struct notifier_block *nb, | ||
79 | unsigned long evt, void *arg) | ||
80 | { | ||
81 | switch (evt) { | ||
82 | case OMAP_DSS_SIZE_CHANGE: | ||
83 | case OMAP_DSS_HOTPLUG_CONNECT: | ||
84 | case OMAP_DSS_HOTPLUG_DISCONNECT: { | ||
85 | struct drm_device *dev = drm_device; | ||
86 | DBG("hotplug event: evt=%d, dev=%p", evt, dev); | ||
87 | if (dev) | ||
88 | drm_sysfs_hotplug_event(dev); | ||
89 | |||
90 | return NOTIFY_OK; | ||
91 | } | ||
92 | default: /* don't care about other events for now */ | ||
93 | return NOTIFY_DONE; | ||
94 | } | ||
95 | } | ||
96 | #endif | ||
97 | |||
98 | static void dump_video_chains(void) | ||
99 | { | ||
100 | int i; | ||
101 | |||
102 | DBG("dumping video chains: "); | ||
103 | for (i = 0; i < omap_dss_get_num_overlays(); i++) { | ||
104 | struct omap_overlay *ovl = omap_dss_get_overlay(i); | ||
105 | struct omap_overlay_manager *mgr = ovl->manager; | ||
106 | struct omap_dss_device *dssdev = mgr ? | ||
107 | mgr->get_device(mgr) : NULL; | ||
108 | if (dssdev) { | ||
109 | DBG("%d: %s -> %s -> %s", i, ovl->name, mgr->name, | ||
110 | dssdev->name); | ||
111 | } else if (mgr) { | ||
112 | DBG("%d: %s -> %s", i, ovl->name, mgr->name); | ||
113 | } else { | ||
114 | DBG("%d: %s", i, ovl->name); | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | |||
119 | /* create encoders for each manager */ | ||
120 | static int create_encoder(struct drm_device *dev, | ||
121 | struct omap_overlay_manager *mgr) | ||
122 | { | ||
123 | struct omap_drm_private *priv = dev->dev_private; | ||
124 | struct drm_encoder *encoder = omap_encoder_init(dev, mgr); | ||
125 | |||
126 | if (!encoder) { | ||
127 | dev_err(dev->dev, "could not create encoder: %s\n", | ||
128 | mgr->name); | ||
129 | return -ENOMEM; | ||
130 | } | ||
131 | |||
132 | BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders)); | ||
133 | |||
134 | priv->encoders[priv->num_encoders++] = encoder; | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | /* create connectors for each display device */ | ||
140 | static int create_connector(struct drm_device *dev, | ||
141 | struct omap_dss_device *dssdev) | ||
142 | { | 78 | { |
143 | struct omap_drm_private *priv = dev->dev_private; | 79 | struct omap_drm_private *priv = dev->dev_private; |
144 | static struct notifier_block *notifier; | 80 | struct omap_dss_device *dssdev = NULL; |
145 | struct drm_connector *connector; | 81 | int num_ovls = dss_feat_get_num_ovls(); |
146 | int j; | 82 | int id; |
147 | |||
148 | if (!dssdev->driver) { | ||
149 | dev_warn(dev->dev, "%s has no driver.. skipping it\n", | ||
150 | dssdev->name); | ||
151 | return 0; | ||
152 | } | ||
153 | 83 | ||
154 | if (!(dssdev->driver->get_timings || | 84 | drm_mode_config_init(dev); |
155 | dssdev->driver->read_edid)) { | ||
156 | dev_warn(dev->dev, "%s driver does not support " | ||
157 | "get_timings or read_edid.. skipping it!\n", | ||
158 | dssdev->name); | ||
159 | return 0; | ||
160 | } | ||
161 | 85 | ||
162 | connector = omap_connector_init(dev, | 86 | omap_drm_irq_install(dev); |
163 | get_connector_type(dssdev), dssdev); | ||
164 | 87 | ||
165 | if (!connector) { | 88 | /* |
166 | dev_err(dev->dev, "could not create connector: %s\n", | 89 | * Create private planes and CRTCs for the last NUM_CRTCs overlay |
167 | dssdev->name); | 90 | * plus manager: |
168 | return -ENOMEM; | 91 | */ |
169 | } | 92 | for (id = 0; id < min(num_crtc, num_ovls); id++) { |
170 | 93 | struct drm_plane *plane; | |
171 | BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors)); | 94 | struct drm_crtc *crtc; |
172 | 95 | ||
173 | priv->connectors[priv->num_connectors++] = connector; | 96 | plane = omap_plane_init(dev, id, true); |
97 | crtc = omap_crtc_init(dev, plane, pipe2chan(id), id); | ||
174 | 98 | ||
175 | #if 0 /* enable when dss2 supports hotplug */ | 99 | BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); |
176 | notifier = kzalloc(sizeof(struct notifier_block), GFP_KERNEL); | 100 | priv->crtcs[id] = crtc; |
177 | notifier->notifier_call = omap_drm_notifier; | 101 | priv->num_crtcs++; |
178 | omap_dss_add_notify(dssdev, notifier); | ||
179 | #else | ||
180 | notifier = NULL; | ||
181 | #endif | ||
182 | 102 | ||
183 | for (j = 0; j < priv->num_encoders; j++) { | 103 | priv->planes[id] = plane; |
184 | struct omap_overlay_manager *mgr = | 104 | priv->num_planes++; |
185 | omap_encoder_get_manager(priv->encoders[j]); | ||
186 | if (mgr->get_device(mgr) == dssdev) { | ||
187 | drm_mode_connector_attach_encoder(connector, | ||
188 | priv->encoders[j]); | ||
189 | } | ||
190 | } | 105 | } |
191 | 106 | ||
192 | return 0; | 107 | /* |
193 | } | 108 | * Create normal planes for the remaining overlays: |
194 | |||
195 | /* create up to max_overlays CRTCs mapping to overlays.. by default, | ||
196 | * connect the overlays to different managers/encoders, giving priority | ||
197 | * to encoders connected to connectors with a detected connection | ||
198 | */ | ||
199 | static int create_crtc(struct drm_device *dev, struct omap_overlay *ovl, | ||
200 | int *j, unsigned int connected_connectors) | ||
201 | { | ||
202 | struct omap_drm_private *priv = dev->dev_private; | ||
203 | struct omap_overlay_manager *mgr = NULL; | ||
204 | struct drm_crtc *crtc; | ||
205 | |||
206 | /* find next best connector, ones with detected connection first | ||
207 | */ | 109 | */ |
208 | while (*j < priv->num_connectors && !mgr) { | 110 | for (; id < num_ovls; id++) { |
209 | if (connected_connectors & (1 << *j)) { | 111 | struct drm_plane *plane = omap_plane_init(dev, id, false); |
210 | struct drm_encoder *encoder = | ||
211 | omap_connector_attached_encoder( | ||
212 | priv->connectors[*j]); | ||
213 | if (encoder) | ||
214 | mgr = omap_encoder_get_manager(encoder); | ||
215 | 112 | ||
216 | } | 113 | BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); |
217 | (*j)++; | 114 | priv->planes[priv->num_planes++] = plane; |
218 | } | 115 | } |
219 | 116 | ||
220 | /* if we couldn't find another connected connector, lets start | 117 | for_each_dss_dev(dssdev) { |
221 | * looking at the unconnected connectors: | 118 | struct drm_connector *connector; |
222 | * | 119 | struct drm_encoder *encoder; |
223 | * note: it might not be immediately apparent, but thanks to | ||
224 | * the !mgr check in both this loop and the one above, the only | ||
225 | * way to enter this loop is with *j == priv->num_connectors, | ||
226 | * so idx can never go negative. | ||
227 | */ | ||
228 | while (*j < 2 * priv->num_connectors && !mgr) { | ||
229 | int idx = *j - priv->num_connectors; | ||
230 | if (!(connected_connectors & (1 << idx))) { | ||
231 | struct drm_encoder *encoder = | ||
232 | omap_connector_attached_encoder( | ||
233 | priv->connectors[idx]); | ||
234 | if (encoder) | ||
235 | mgr = omap_encoder_get_manager(encoder); | ||
236 | 120 | ||
121 | if (!dssdev->driver) { | ||
122 | dev_warn(dev->dev, "%s has no driver.. skipping it\n", | ||
123 | dssdev->name); | ||
124 | return 0; | ||
237 | } | 125 | } |
238 | (*j)++; | ||
239 | } | ||
240 | |||
241 | crtc = omap_crtc_init(dev, ovl, priv->num_crtcs); | ||
242 | |||
243 | if (!crtc) { | ||
244 | dev_err(dev->dev, "could not create CRTC: %s\n", | ||
245 | ovl->name); | ||
246 | return -ENOMEM; | ||
247 | } | ||
248 | 126 | ||
249 | BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); | 127 | if (!(dssdev->driver->get_timings || |
250 | 128 | dssdev->driver->read_edid)) { | |
251 | priv->crtcs[priv->num_crtcs++] = crtc; | 129 | dev_warn(dev->dev, "%s driver does not support " |
252 | 130 | "get_timings or read_edid.. skipping it!\n", | |
253 | return 0; | 131 | dssdev->name); |
254 | } | 132 | return 0; |
255 | |||
256 | static int create_plane(struct drm_device *dev, struct omap_overlay *ovl, | ||
257 | unsigned int possible_crtcs) | ||
258 | { | ||
259 | struct omap_drm_private *priv = dev->dev_private; | ||
260 | struct drm_plane *plane = | ||
261 | omap_plane_init(dev, ovl, possible_crtcs, false); | ||
262 | |||
263 | if (!plane) { | ||
264 | dev_err(dev->dev, "could not create plane: %s\n", | ||
265 | ovl->name); | ||
266 | return -ENOMEM; | ||
267 | } | ||
268 | |||
269 | BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); | ||
270 | |||
271 | priv->planes[priv->num_planes++] = plane; | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static int match_dev_name(struct omap_dss_device *dssdev, void *data) | ||
277 | { | ||
278 | return !strcmp(dssdev->name, data); | ||
279 | } | ||
280 | |||
281 | static unsigned int detect_connectors(struct drm_device *dev) | ||
282 | { | ||
283 | struct omap_drm_private *priv = dev->dev_private; | ||
284 | unsigned int connected_connectors = 0; | ||
285 | int i; | ||
286 | |||
287 | for (i = 0; i < priv->num_connectors; i++) { | ||
288 | struct drm_connector *connector = priv->connectors[i]; | ||
289 | if (omap_connector_detect(connector, true) == | ||
290 | connector_status_connected) { | ||
291 | connected_connectors |= (1 << i); | ||
292 | } | 133 | } |
293 | } | ||
294 | |||
295 | return connected_connectors; | ||
296 | } | ||
297 | 134 | ||
298 | static int omap_modeset_init(struct drm_device *dev) | 135 | encoder = omap_encoder_init(dev, dssdev); |
299 | { | ||
300 | const struct omap_drm_platform_data *pdata = dev->dev->platform_data; | ||
301 | struct omap_kms_platform_data *kms_pdata = NULL; | ||
302 | struct omap_drm_private *priv = dev->dev_private; | ||
303 | struct omap_dss_device *dssdev = NULL; | ||
304 | int i, j; | ||
305 | unsigned int connected_connectors = 0; | ||
306 | 136 | ||
307 | drm_mode_config_init(dev); | 137 | if (!encoder) { |
308 | 138 | dev_err(dev->dev, "could not create encoder: %s\n", | |
309 | if (pdata && pdata->kms_pdata) { | 139 | dssdev->name); |
310 | kms_pdata = pdata->kms_pdata; | 140 | return -ENOMEM; |
311 | |||
312 | /* if platform data is provided by the board file, use it to | ||
313 | * control which overlays, managers, and devices we own. | ||
314 | */ | ||
315 | for (i = 0; i < kms_pdata->mgr_cnt; i++) { | ||
316 | struct omap_overlay_manager *mgr = | ||
317 | omap_dss_get_overlay_manager( | ||
318 | kms_pdata->mgr_ids[i]); | ||
319 | create_encoder(dev, mgr); | ||
320 | } | ||
321 | |||
322 | for (i = 0; i < kms_pdata->dev_cnt; i++) { | ||
323 | struct omap_dss_device *dssdev = | ||
324 | omap_dss_find_device( | ||
325 | (void *)kms_pdata->dev_names[i], | ||
326 | match_dev_name); | ||
327 | if (!dssdev) { | ||
328 | dev_warn(dev->dev, "no such dssdev: %s\n", | ||
329 | kms_pdata->dev_names[i]); | ||
330 | continue; | ||
331 | } | ||
332 | create_connector(dev, dssdev); | ||
333 | } | 141 | } |
334 | 142 | ||
335 | connected_connectors = detect_connectors(dev); | 143 | connector = omap_connector_init(dev, |
144 | get_connector_type(dssdev), dssdev, encoder); | ||
336 | 145 | ||
337 | j = 0; | 146 | if (!connector) { |
338 | for (i = 0; i < kms_pdata->ovl_cnt; i++) { | 147 | dev_err(dev->dev, "could not create connector: %s\n", |
339 | struct omap_overlay *ovl = | 148 | dssdev->name); |
340 | omap_dss_get_overlay(kms_pdata->ovl_ids[i]); | 149 | return -ENOMEM; |
341 | create_crtc(dev, ovl, &j, connected_connectors); | ||
342 | } | 150 | } |
343 | 151 | ||
344 | for (i = 0; i < kms_pdata->pln_cnt; i++) { | 152 | BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders)); |
345 | struct omap_overlay *ovl = | 153 | BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors)); |
346 | omap_dss_get_overlay(kms_pdata->pln_ids[i]); | ||
347 | create_plane(dev, ovl, (1 << priv->num_crtcs) - 1); | ||
348 | } | ||
349 | } else { | ||
350 | /* otherwise just grab up to CONFIG_DRM_OMAP_NUM_CRTCS and try | ||
351 | * to make educated guesses about everything else | ||
352 | */ | ||
353 | int max_overlays = min(omap_dss_get_num_overlays(), num_crtc); | ||
354 | 154 | ||
355 | for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) | 155 | priv->encoders[priv->num_encoders++] = encoder; |
356 | create_encoder(dev, omap_dss_get_overlay_manager(i)); | 156 | priv->connectors[priv->num_connectors++] = connector; |
357 | |||
358 | for_each_dss_dev(dssdev) { | ||
359 | create_connector(dev, dssdev); | ||
360 | } | ||
361 | 157 | ||
362 | connected_connectors = detect_connectors(dev); | 158 | drm_mode_connector_attach_encoder(connector, encoder); |
363 | 159 | ||
364 | j = 0; | 160 | /* figure out which crtc's we can connect the encoder to: */ |
365 | for (i = 0; i < max_overlays; i++) { | 161 | encoder->possible_crtcs = 0; |
366 | create_crtc(dev, omap_dss_get_overlay(i), | 162 | for (id = 0; id < priv->num_crtcs; id++) { |
367 | &j, connected_connectors); | 163 | enum omap_dss_output_id supported_outputs = |
368 | } | 164 | dss_feat_get_supported_outputs(pipe2chan(id)); |
369 | 165 | if (supported_outputs & dssdev->output->id) | |
370 | /* use any remaining overlays as drm planes */ | 166 | encoder->possible_crtcs |= (1 << id); |
371 | for (; i < omap_dss_get_num_overlays(); i++) { | ||
372 | struct omap_overlay *ovl = omap_dss_get_overlay(i); | ||
373 | create_plane(dev, ovl, (1 << priv->num_crtcs) - 1); | ||
374 | } | 167 | } |
375 | } | 168 | } |
376 | 169 | ||
377 | /* for now keep the mapping of CRTCs and encoders static.. */ | ||
378 | for (i = 0; i < priv->num_encoders; i++) { | ||
379 | struct drm_encoder *encoder = priv->encoders[i]; | ||
380 | struct omap_overlay_manager *mgr = | ||
381 | omap_encoder_get_manager(encoder); | ||
382 | |||
383 | encoder->possible_crtcs = (1 << priv->num_crtcs) - 1; | ||
384 | |||
385 | DBG("%s: possible_crtcs=%08x", mgr->name, | ||
386 | encoder->possible_crtcs); | ||
387 | } | ||
388 | |||
389 | dump_video_chains(); | ||
390 | |||
391 | dev->mode_config.min_width = 32; | 170 | dev->mode_config.min_width = 32; |
392 | dev->mode_config.min_height = 32; | 171 | dev->mode_config.min_height = 32; |
393 | 172 | ||
@@ -450,7 +229,7 @@ static int ioctl_gem_new(struct drm_device *dev, void *data, | |||
450 | struct drm_file *file_priv) | 229 | struct drm_file *file_priv) |
451 | { | 230 | { |
452 | struct drm_omap_gem_new *args = data; | 231 | struct drm_omap_gem_new *args = data; |
453 | DBG("%p:%p: size=0x%08x, flags=%08x", dev, file_priv, | 232 | VERB("%p:%p: size=0x%08x, flags=%08x", dev, file_priv, |
454 | args->size.bytes, args->flags); | 233 | args->size.bytes, args->flags); |
455 | return omap_gem_new_handle(dev, file_priv, args->size, | 234 | return omap_gem_new_handle(dev, file_priv, args->size, |
456 | args->flags, &args->handle); | 235 | args->flags, &args->handle); |
@@ -510,7 +289,7 @@ static int ioctl_gem_info(struct drm_device *dev, void *data, | |||
510 | struct drm_gem_object *obj; | 289 | struct drm_gem_object *obj; |
511 | int ret = 0; | 290 | int ret = 0; |
512 | 291 | ||
513 | DBG("%p:%p: handle=%d", dev, file_priv, args->handle); | 292 | VERB("%p:%p: handle=%d", dev, file_priv, args->handle); |
514 | 293 | ||
515 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | 294 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); |
516 | if (!obj) | 295 | if (!obj) |
@@ -565,14 +344,6 @@ static int dev_load(struct drm_device *dev, unsigned long flags) | |||
565 | 344 | ||
566 | dev->dev_private = priv; | 345 | dev->dev_private = priv; |
567 | 346 | ||
568 | ret = omapdss_compat_init(); | ||
569 | if (ret) { | ||
570 | dev_err(dev->dev, "coult not init omapdss\n"); | ||
571 | dev->dev_private = NULL; | ||
572 | kfree(priv); | ||
573 | return ret; | ||
574 | } | ||
575 | |||
576 | priv->wq = alloc_ordered_workqueue("omapdrm", 0); | 347 | priv->wq = alloc_ordered_workqueue("omapdrm", 0); |
577 | 348 | ||
578 | INIT_LIST_HEAD(&priv->obj_list); | 349 | INIT_LIST_HEAD(&priv->obj_list); |
@@ -584,10 +355,13 @@ static int dev_load(struct drm_device *dev, unsigned long flags) | |||
584 | dev_err(dev->dev, "omap_modeset_init failed: ret=%d\n", ret); | 355 | dev_err(dev->dev, "omap_modeset_init failed: ret=%d\n", ret); |
585 | dev->dev_private = NULL; | 356 | dev->dev_private = NULL; |
586 | kfree(priv); | 357 | kfree(priv); |
587 | omapdss_compat_uninit(); | ||
588 | return ret; | 358 | return ret; |
589 | } | 359 | } |
590 | 360 | ||
361 | ret = drm_vblank_init(dev, priv->num_crtcs); | ||
362 | if (ret) | ||
363 | dev_warn(dev->dev, "could not init vblank\n"); | ||
364 | |||
591 | priv->fbdev = omap_fbdev_init(dev); | 365 | priv->fbdev = omap_fbdev_init(dev); |
592 | if (!priv->fbdev) { | 366 | if (!priv->fbdev) { |
593 | dev_warn(dev->dev, "omap_fbdev_init failed\n"); | 367 | dev_warn(dev->dev, "omap_fbdev_init failed\n"); |
@@ -596,10 +370,6 @@ static int dev_load(struct drm_device *dev, unsigned long flags) | |||
596 | 370 | ||
597 | drm_kms_helper_poll_init(dev); | 371 | drm_kms_helper_poll_init(dev); |
598 | 372 | ||
599 | ret = drm_vblank_init(dev, priv->num_crtcs); | ||
600 | if (ret) | ||
601 | dev_warn(dev->dev, "could not init vblank\n"); | ||
602 | |||
603 | return 0; | 373 | return 0; |
604 | } | 374 | } |
605 | 375 | ||
@@ -609,8 +379,9 @@ static int dev_unload(struct drm_device *dev) | |||
609 | 379 | ||
610 | DBG("unload: dev=%p", dev); | 380 | DBG("unload: dev=%p", dev); |
611 | 381 | ||
612 | drm_vblank_cleanup(dev); | ||
613 | drm_kms_helper_poll_fini(dev); | 382 | drm_kms_helper_poll_fini(dev); |
383 | drm_vblank_cleanup(dev); | ||
384 | omap_drm_irq_uninstall(dev); | ||
614 | 385 | ||
615 | omap_fbdev_free(dev); | 386 | omap_fbdev_free(dev); |
616 | omap_modeset_free(dev); | 387 | omap_modeset_free(dev); |
@@ -619,8 +390,6 @@ static int dev_unload(struct drm_device *dev) | |||
619 | flush_workqueue(priv->wq); | 390 | flush_workqueue(priv->wq); |
620 | destroy_workqueue(priv->wq); | 391 | destroy_workqueue(priv->wq); |
621 | 392 | ||
622 | omapdss_compat_uninit(); | ||
623 | |||
624 | kfree(dev->dev_private); | 393 | kfree(dev->dev_private); |
625 | dev->dev_private = NULL; | 394 | dev->dev_private = NULL; |
626 | 395 | ||
@@ -680,7 +449,9 @@ static void dev_lastclose(struct drm_device *dev) | |||
680 | } | 449 | } |
681 | } | 450 | } |
682 | 451 | ||
452 | drm_modeset_lock_all(dev); | ||
683 | ret = drm_fb_helper_restore_fbdev_mode(priv->fbdev); | 453 | ret = drm_fb_helper_restore_fbdev_mode(priv->fbdev); |
454 | drm_modeset_unlock_all(dev); | ||
684 | if (ret) | 455 | if (ret) |
685 | DBG("failed to restore crtc mode"); | 456 | DBG("failed to restore crtc mode"); |
686 | } | 457 | } |
@@ -695,60 +466,6 @@ static void dev_postclose(struct drm_device *dev, struct drm_file *file) | |||
695 | DBG("postclose: dev=%p, file=%p", dev, file); | 466 | DBG("postclose: dev=%p, file=%p", dev, file); |
696 | } | 467 | } |
697 | 468 | ||
698 | /** | ||
699 | * enable_vblank - enable vblank interrupt events | ||
700 | * @dev: DRM device | ||
701 | * @crtc: which irq to enable | ||
702 | * | ||
703 | * Enable vblank interrupts for @crtc. If the device doesn't have | ||
704 | * a hardware vblank counter, this routine should be a no-op, since | ||
705 | * interrupts will have to stay on to keep the count accurate. | ||
706 | * | ||
707 | * RETURNS | ||
708 | * Zero on success, appropriate errno if the given @crtc's vblank | ||
709 | * interrupt cannot be enabled. | ||
710 | */ | ||
711 | static int dev_enable_vblank(struct drm_device *dev, int crtc) | ||
712 | { | ||
713 | DBG("enable_vblank: dev=%p, crtc=%d", dev, crtc); | ||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | /** | ||
718 | * disable_vblank - disable vblank interrupt events | ||
719 | * @dev: DRM device | ||
720 | * @crtc: which irq to enable | ||
721 | * | ||
722 | * Disable vblank interrupts for @crtc. If the device doesn't have | ||
723 | * a hardware vblank counter, this routine should be a no-op, since | ||
724 | * interrupts will have to stay on to keep the count accurate. | ||
725 | */ | ||
726 | static void dev_disable_vblank(struct drm_device *dev, int crtc) | ||
727 | { | ||
728 | DBG("disable_vblank: dev=%p, crtc=%d", dev, crtc); | ||
729 | } | ||
730 | |||
731 | static irqreturn_t dev_irq_handler(DRM_IRQ_ARGS) | ||
732 | { | ||
733 | return IRQ_HANDLED; | ||
734 | } | ||
735 | |||
736 | static void dev_irq_preinstall(struct drm_device *dev) | ||
737 | { | ||
738 | DBG("irq_preinstall: dev=%p", dev); | ||
739 | } | ||
740 | |||
741 | static int dev_irq_postinstall(struct drm_device *dev) | ||
742 | { | ||
743 | DBG("irq_postinstall: dev=%p", dev); | ||
744 | return 0; | ||
745 | } | ||
746 | |||
747 | static void dev_irq_uninstall(struct drm_device *dev) | ||
748 | { | ||
749 | DBG("irq_uninstall: dev=%p", dev); | ||
750 | } | ||
751 | |||
752 | static const struct vm_operations_struct omap_gem_vm_ops = { | 469 | static const struct vm_operations_struct omap_gem_vm_ops = { |
753 | .fault = omap_gem_fault, | 470 | .fault = omap_gem_fault, |
754 | .open = drm_gem_vm_open, | 471 | .open = drm_gem_vm_open, |
@@ -778,12 +495,12 @@ static struct drm_driver omap_drm_driver = { | |||
778 | .preclose = dev_preclose, | 495 | .preclose = dev_preclose, |
779 | .postclose = dev_postclose, | 496 | .postclose = dev_postclose, |
780 | .get_vblank_counter = drm_vblank_count, | 497 | .get_vblank_counter = drm_vblank_count, |
781 | .enable_vblank = dev_enable_vblank, | 498 | .enable_vblank = omap_irq_enable_vblank, |
782 | .disable_vblank = dev_disable_vblank, | 499 | .disable_vblank = omap_irq_disable_vblank, |
783 | .irq_preinstall = dev_irq_preinstall, | 500 | .irq_preinstall = omap_irq_preinstall, |
784 | .irq_postinstall = dev_irq_postinstall, | 501 | .irq_postinstall = omap_irq_postinstall, |
785 | .irq_uninstall = dev_irq_uninstall, | 502 | .irq_uninstall = omap_irq_uninstall, |
786 | .irq_handler = dev_irq_handler, | 503 | .irq_handler = omap_irq_handler, |
787 | #ifdef CONFIG_DEBUG_FS | 504 | #ifdef CONFIG_DEBUG_FS |
788 | .debugfs_init = omap_debugfs_init, | 505 | .debugfs_init = omap_debugfs_init, |
789 | .debugfs_cleanup = omap_debugfs_cleanup, | 506 | .debugfs_cleanup = omap_debugfs_cleanup, |
diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h index 1d4aea53b75d..cd1f22b0b124 100644 --- a/drivers/staging/omapdrm/omap_drv.h +++ b/drivers/staging/omapdrm/omap_drv.h | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/platform_data/omap_drm.h> | 28 | #include <linux/platform_data/omap_drm.h> |
29 | #include "omap_drm.h" | 29 | #include "omap_drm.h" |
30 | 30 | ||
31 | |||
31 | #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) | 32 | #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) |
32 | #define VERB(fmt, ...) if (0) DRM_DEBUG(fmt, ##__VA_ARGS__) /* verbose debug */ | 33 | #define VERB(fmt, ...) if (0) DRM_DEBUG(fmt, ##__VA_ARGS__) /* verbose debug */ |
33 | 34 | ||
@@ -39,6 +40,51 @@ | |||
39 | */ | 40 | */ |
40 | #define MAX_MAPPERS 2 | 41 | #define MAX_MAPPERS 2 |
41 | 42 | ||
43 | /* parameters which describe (unrotated) coordinates of scanout within a fb: */ | ||
44 | struct omap_drm_window { | ||
45 | uint32_t rotation; | ||
46 | int32_t crtc_x, crtc_y; /* signed because can be offscreen */ | ||
47 | uint32_t crtc_w, crtc_h; | ||
48 | uint32_t src_x, src_y; | ||
49 | uint32_t src_w, src_h; | ||
50 | }; | ||
51 | |||
52 | /* Once GO bit is set, we can't make further updates to shadowed registers | ||
53 | * until the GO bit is cleared. So various parts in the kms code that need | ||
54 | * to update shadowed registers queue up a pair of callbacks, pre_apply | ||
55 | * which is called before setting GO bit, and post_apply that is called | ||
56 | * after GO bit is cleared. The crtc manages the queuing, and everyone | ||
57 | * else goes thru omap_crtc_apply() using these callbacks so that the | ||
58 | * code which has to deal w/ GO bit state is centralized. | ||
59 | */ | ||
60 | struct omap_drm_apply { | ||
61 | struct list_head pending_node, queued_node; | ||
62 | bool queued; | ||
63 | void (*pre_apply)(struct omap_drm_apply *apply); | ||
64 | void (*post_apply)(struct omap_drm_apply *apply); | ||
65 | }; | ||
66 | |||
67 | /* For transiently registering for different DSS irqs that various parts | ||
68 | * of the KMS code need during setup/configuration. We these are not | ||
69 | * necessarily the same as what drm_vblank_get/put() are requesting, and | ||
70 | * the hysteresis in drm_vblank_put() is not necessarily desirable for | ||
71 | * internal housekeeping related irq usage. | ||
72 | */ | ||
73 | struct omap_drm_irq { | ||
74 | struct list_head node; | ||
75 | uint32_t irqmask; | ||
76 | bool registered; | ||
77 | void (*irq)(struct omap_drm_irq *irq, uint32_t irqstatus); | ||
78 | }; | ||
79 | |||
80 | /* For KMS code that needs to wait for a certain # of IRQs: | ||
81 | */ | ||
82 | struct omap_irq_wait; | ||
83 | struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev, | ||
84 | uint32_t irqmask, int count); | ||
85 | int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, | ||
86 | unsigned long timeout); | ||
87 | |||
42 | struct omap_drm_private { | 88 | struct omap_drm_private { |
43 | uint32_t omaprev; | 89 | uint32_t omaprev; |
44 | 90 | ||
@@ -58,6 +104,7 @@ struct omap_drm_private { | |||
58 | 104 | ||
59 | struct workqueue_struct *wq; | 105 | struct workqueue_struct *wq; |
60 | 106 | ||
107 | /* list of GEM objects: */ | ||
61 | struct list_head obj_list; | 108 | struct list_head obj_list; |
62 | 109 | ||
63 | bool has_dmm; | 110 | bool has_dmm; |
@@ -65,6 +112,11 @@ struct omap_drm_private { | |||
65 | /* properties: */ | 112 | /* properties: */ |
66 | struct drm_property *rotation_prop; | 113 | struct drm_property *rotation_prop; |
67 | struct drm_property *zorder_prop; | 114 | struct drm_property *zorder_prop; |
115 | |||
116 | /* irq handling: */ | ||
117 | struct list_head irq_list; /* list of omap_drm_irq */ | ||
118 | uint32_t vblank_mask; /* irq bits set for userspace vblank */ | ||
119 | struct omap_drm_irq error_handler; | ||
68 | }; | 120 | }; |
69 | 121 | ||
70 | /* this should probably be in drm-core to standardize amongst drivers */ | 122 | /* this should probably be in drm-core to standardize amongst drivers */ |
@@ -75,15 +127,6 @@ struct omap_drm_private { | |||
75 | #define DRM_REFLECT_X 4 | 127 | #define DRM_REFLECT_X 4 |
76 | #define DRM_REFLECT_Y 5 | 128 | #define DRM_REFLECT_Y 5 |
77 | 129 | ||
78 | /* parameters which describe (unrotated) coordinates of scanout within a fb: */ | ||
79 | struct omap_drm_window { | ||
80 | uint32_t rotation; | ||
81 | int32_t crtc_x, crtc_y; /* signed because can be offscreen */ | ||
82 | uint32_t crtc_w, crtc_h; | ||
83 | uint32_t src_x, src_y; | ||
84 | uint32_t src_w, src_h; | ||
85 | }; | ||
86 | |||
87 | #ifdef CONFIG_DEBUG_FS | 130 | #ifdef CONFIG_DEBUG_FS |
88 | int omap_debugfs_init(struct drm_minor *minor); | 131 | int omap_debugfs_init(struct drm_minor *minor); |
89 | void omap_debugfs_cleanup(struct drm_minor *minor); | 132 | void omap_debugfs_cleanup(struct drm_minor *minor); |
@@ -92,23 +135,36 @@ void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m); | |||
92 | void omap_gem_describe_objects(struct list_head *list, struct seq_file *m); | 135 | void omap_gem_describe_objects(struct list_head *list, struct seq_file *m); |
93 | #endif | 136 | #endif |
94 | 137 | ||
138 | int omap_irq_enable_vblank(struct drm_device *dev, int crtc); | ||
139 | void omap_irq_disable_vblank(struct drm_device *dev, int crtc); | ||
140 | irqreturn_t omap_irq_handler(DRM_IRQ_ARGS); | ||
141 | void omap_irq_preinstall(struct drm_device *dev); | ||
142 | int omap_irq_postinstall(struct drm_device *dev); | ||
143 | void omap_irq_uninstall(struct drm_device *dev); | ||
144 | void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq); | ||
145 | void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq); | ||
146 | int omap_drm_irq_uninstall(struct drm_device *dev); | ||
147 | int omap_drm_irq_install(struct drm_device *dev); | ||
148 | |||
95 | struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev); | 149 | struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev); |
96 | void omap_fbdev_free(struct drm_device *dev); | 150 | void omap_fbdev_free(struct drm_device *dev); |
97 | 151 | ||
152 | const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc); | ||
153 | enum omap_channel omap_crtc_channel(struct drm_crtc *crtc); | ||
154 | int omap_crtc_apply(struct drm_crtc *crtc, | ||
155 | struct omap_drm_apply *apply); | ||
98 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, | 156 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, |
99 | struct omap_overlay *ovl, int id); | 157 | struct drm_plane *plane, enum omap_channel channel, int id); |
100 | 158 | ||
101 | struct drm_plane *omap_plane_init(struct drm_device *dev, | 159 | struct drm_plane *omap_plane_init(struct drm_device *dev, |
102 | struct omap_overlay *ovl, unsigned int possible_crtcs, | 160 | int plane_id, bool private_plane); |
103 | bool priv); | ||
104 | int omap_plane_dpms(struct drm_plane *plane, int mode); | 161 | int omap_plane_dpms(struct drm_plane *plane, int mode); |
105 | int omap_plane_mode_set(struct drm_plane *plane, | 162 | int omap_plane_mode_set(struct drm_plane *plane, |
106 | struct drm_crtc *crtc, struct drm_framebuffer *fb, | 163 | struct drm_crtc *crtc, struct drm_framebuffer *fb, |
107 | int crtc_x, int crtc_y, | 164 | int crtc_x, int crtc_y, |
108 | unsigned int crtc_w, unsigned int crtc_h, | 165 | unsigned int crtc_w, unsigned int crtc_h, |
109 | uint32_t src_x, uint32_t src_y, | 166 | uint32_t src_x, uint32_t src_y, |
110 | uint32_t src_w, uint32_t src_h); | 167 | uint32_t src_w, uint32_t src_h, |
111 | void omap_plane_on_endwin(struct drm_plane *plane, | ||
112 | void (*fxn)(void *), void *arg); | 168 | void (*fxn)(void *), void *arg); |
113 | void omap_plane_install_properties(struct drm_plane *plane, | 169 | void omap_plane_install_properties(struct drm_plane *plane, |
114 | struct drm_mode_object *obj); | 170 | struct drm_mode_object *obj); |
@@ -116,21 +172,25 @@ int omap_plane_set_property(struct drm_plane *plane, | |||
116 | struct drm_property *property, uint64_t val); | 172 | struct drm_property *property, uint64_t val); |
117 | 173 | ||
118 | struct drm_encoder *omap_encoder_init(struct drm_device *dev, | 174 | struct drm_encoder *omap_encoder_init(struct drm_device *dev, |
119 | struct omap_overlay_manager *mgr); | 175 | struct omap_dss_device *dssdev); |
120 | struct omap_overlay_manager *omap_encoder_get_manager( | 176 | int omap_encoder_set_enabled(struct drm_encoder *encoder, bool enabled); |
177 | int omap_encoder_update(struct drm_encoder *encoder, | ||
178 | struct omap_overlay_manager *mgr, | ||
179 | struct omap_video_timings *timings); | ||
180 | |||
181 | struct drm_connector *omap_connector_init(struct drm_device *dev, | ||
182 | int connector_type, struct omap_dss_device *dssdev, | ||
121 | struct drm_encoder *encoder); | 183 | struct drm_encoder *encoder); |
122 | struct drm_encoder *omap_connector_attached_encoder( | 184 | struct drm_encoder *omap_connector_attached_encoder( |
123 | struct drm_connector *connector); | 185 | struct drm_connector *connector); |
124 | enum drm_connector_status omap_connector_detect( | ||
125 | struct drm_connector *connector, bool force); | ||
126 | |||
127 | struct drm_connector *omap_connector_init(struct drm_device *dev, | ||
128 | int connector_type, struct omap_dss_device *dssdev); | ||
129 | void omap_connector_mode_set(struct drm_connector *connector, | ||
130 | struct drm_display_mode *mode); | ||
131 | void omap_connector_flush(struct drm_connector *connector, | 186 | void omap_connector_flush(struct drm_connector *connector, |
132 | int x, int y, int w, int h); | 187 | int x, int y, int w, int h); |
133 | 188 | ||
189 | void copy_timings_omap_to_drm(struct drm_display_mode *mode, | ||
190 | struct omap_video_timings *timings); | ||
191 | void copy_timings_drm_to_omap(struct omap_video_timings *timings, | ||
192 | struct drm_display_mode *mode); | ||
193 | |||
134 | uint32_t omap_framebuffer_get_formats(uint32_t *pixel_formats, | 194 | uint32_t omap_framebuffer_get_formats(uint32_t *pixel_formats, |
135 | uint32_t max_formats, enum omap_color_mode supported_modes); | 195 | uint32_t max_formats, enum omap_color_mode supported_modes); |
136 | struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, | 196 | struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, |
@@ -207,6 +267,40 @@ static inline int align_pitch(int pitch, int width, int bpp) | |||
207 | return ALIGN(pitch, 8 * bytespp); | 267 | return ALIGN(pitch, 8 * bytespp); |
208 | } | 268 | } |
209 | 269 | ||
270 | static inline enum omap_channel pipe2chan(int pipe) | ||
271 | { | ||
272 | int num_mgrs = dss_feat_get_num_mgrs(); | ||
273 | |||
274 | /* | ||
275 | * We usually don't want to create a CRTC for each manager, | ||
276 | * at least not until we have a way to expose private planes | ||
277 | * to userspace. Otherwise there would not be enough video | ||
278 | * pipes left for drm planes. The higher #'d managers tend | ||
279 | * to have more features so start in reverse order. | ||
280 | */ | ||
281 | return num_mgrs - pipe - 1; | ||
282 | } | ||
283 | |||
284 | /* map crtc to vblank mask */ | ||
285 | static inline uint32_t pipe2vbl(int crtc) | ||
286 | { | ||
287 | enum omap_channel channel = pipe2chan(crtc); | ||
288 | return dispc_mgr_get_vsync_irq(channel); | ||
289 | } | ||
290 | |||
291 | static inline int crtc2pipe(struct drm_device *dev, struct drm_crtc *crtc) | ||
292 | { | ||
293 | struct omap_drm_private *priv = dev->dev_private; | ||
294 | int i; | ||
295 | |||
296 | for (i = 0; i < ARRAY_SIZE(priv->crtcs); i++) | ||
297 | if (priv->crtcs[i] == crtc) | ||
298 | return i; | ||
299 | |||
300 | BUG(); /* bogus CRTC ptr */ | ||
301 | return -1; | ||
302 | } | ||
303 | |||
210 | /* should these be made into common util helpers? | 304 | /* should these be made into common util helpers? |
211 | */ | 305 | */ |
212 | 306 | ||
diff --git a/drivers/staging/omapdrm/omap_encoder.c b/drivers/staging/omapdrm/omap_encoder.c index 5341d5e3e317..e053160d2db3 100644 --- a/drivers/staging/omapdrm/omap_encoder.c +++ b/drivers/staging/omapdrm/omap_encoder.c | |||
@@ -22,37 +22,56 @@ | |||
22 | #include "drm_crtc.h" | 22 | #include "drm_crtc.h" |
23 | #include "drm_crtc_helper.h" | 23 | #include "drm_crtc_helper.h" |
24 | 24 | ||
25 | #include <linux/list.h> | ||
26 | |||
27 | |||
25 | /* | 28 | /* |
26 | * encoder funcs | 29 | * encoder funcs |
27 | */ | 30 | */ |
28 | 31 | ||
29 | #define to_omap_encoder(x) container_of(x, struct omap_encoder, base) | 32 | #define to_omap_encoder(x) container_of(x, struct omap_encoder, base) |
30 | 33 | ||
34 | /* The encoder and connector both map to same dssdev.. the encoder | ||
35 | * handles the 'active' parts, ie. anything the modifies the state | ||
36 | * of the hw, and the connector handles the 'read-only' parts, like | ||
37 | * detecting connection and reading edid. | ||
38 | */ | ||
31 | struct omap_encoder { | 39 | struct omap_encoder { |
32 | struct drm_encoder base; | 40 | struct drm_encoder base; |
33 | struct omap_overlay_manager *mgr; | 41 | struct omap_dss_device *dssdev; |
34 | }; | 42 | }; |
35 | 43 | ||
36 | static void omap_encoder_destroy(struct drm_encoder *encoder) | 44 | static void omap_encoder_destroy(struct drm_encoder *encoder) |
37 | { | 45 | { |
38 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | 46 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); |
39 | DBG("%s", omap_encoder->mgr->name); | ||
40 | drm_encoder_cleanup(encoder); | 47 | drm_encoder_cleanup(encoder); |
41 | kfree(omap_encoder); | 48 | kfree(omap_encoder); |
42 | } | 49 | } |
43 | 50 | ||
51 | static const struct drm_encoder_funcs omap_encoder_funcs = { | ||
52 | .destroy = omap_encoder_destroy, | ||
53 | }; | ||
54 | |||
55 | /* | ||
56 | * The CRTC drm_crtc_helper_set_mode() doesn't really give us the right | ||
57 | * order.. the easiest way to work around this for now is to make all | ||
58 | * the encoder-helper's no-op's and have the omap_crtc code take care | ||
59 | * of the sequencing and call us in the right points. | ||
60 | * | ||
61 | * Eventually to handle connecting CRTCs to different encoders properly, | ||
62 | * either the CRTC helpers need to change or we need to replace | ||
63 | * drm_crtc_helper_set_mode(), but lets wait until atomic-modeset for | ||
64 | * that. | ||
65 | */ | ||
66 | |||
44 | static void omap_encoder_dpms(struct drm_encoder *encoder, int mode) | 67 | static void omap_encoder_dpms(struct drm_encoder *encoder, int mode) |
45 | { | 68 | { |
46 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
47 | DBG("%s: %d", omap_encoder->mgr->name, mode); | ||
48 | } | 69 | } |
49 | 70 | ||
50 | static bool omap_encoder_mode_fixup(struct drm_encoder *encoder, | 71 | static bool omap_encoder_mode_fixup(struct drm_encoder *encoder, |
51 | const struct drm_display_mode *mode, | 72 | const struct drm_display_mode *mode, |
52 | struct drm_display_mode *adjusted_mode) | 73 | struct drm_display_mode *adjusted_mode) |
53 | { | 74 | { |
54 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
55 | DBG("%s", omap_encoder->mgr->name); | ||
56 | return true; | 75 | return true; |
57 | } | 76 | } |
58 | 77 | ||
@@ -60,47 +79,16 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder, | |||
60 | struct drm_display_mode *mode, | 79 | struct drm_display_mode *mode, |
61 | struct drm_display_mode *adjusted_mode) | 80 | struct drm_display_mode *adjusted_mode) |
62 | { | 81 | { |
63 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
64 | struct drm_device *dev = encoder->dev; | ||
65 | struct omap_drm_private *priv = dev->dev_private; | ||
66 | int i; | ||
67 | |||
68 | mode = adjusted_mode; | ||
69 | |||
70 | DBG("%s: set mode: %dx%d", omap_encoder->mgr->name, | ||
71 | mode->hdisplay, mode->vdisplay); | ||
72 | |||
73 | for (i = 0; i < priv->num_connectors; i++) { | ||
74 | struct drm_connector *connector = priv->connectors[i]; | ||
75 | if (connector->encoder == encoder) | ||
76 | omap_connector_mode_set(connector, mode); | ||
77 | |||
78 | } | ||
79 | } | 82 | } |
80 | 83 | ||
81 | static void omap_encoder_prepare(struct drm_encoder *encoder) | 84 | static void omap_encoder_prepare(struct drm_encoder *encoder) |
82 | { | 85 | { |
83 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
84 | struct drm_encoder_helper_funcs *encoder_funcs = | ||
85 | encoder->helper_private; | ||
86 | DBG("%s", omap_encoder->mgr->name); | ||
87 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); | ||
88 | } | 86 | } |
89 | 87 | ||
90 | static void omap_encoder_commit(struct drm_encoder *encoder) | 88 | static void omap_encoder_commit(struct drm_encoder *encoder) |
91 | { | 89 | { |
92 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
93 | struct drm_encoder_helper_funcs *encoder_funcs = | ||
94 | encoder->helper_private; | ||
95 | DBG("%s", omap_encoder->mgr->name); | ||
96 | omap_encoder->mgr->apply(omap_encoder->mgr); | ||
97 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); | ||
98 | } | 90 | } |
99 | 91 | ||
100 | static const struct drm_encoder_funcs omap_encoder_funcs = { | ||
101 | .destroy = omap_encoder_destroy, | ||
102 | }; | ||
103 | |||
104 | static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = { | 92 | static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = { |
105 | .dpms = omap_encoder_dpms, | 93 | .dpms = omap_encoder_dpms, |
106 | .mode_fixup = omap_encoder_mode_fixup, | 94 | .mode_fixup = omap_encoder_mode_fixup, |
@@ -109,23 +97,54 @@ static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = { | |||
109 | .commit = omap_encoder_commit, | 97 | .commit = omap_encoder_commit, |
110 | }; | 98 | }; |
111 | 99 | ||
112 | struct omap_overlay_manager *omap_encoder_get_manager( | 100 | /* |
113 | struct drm_encoder *encoder) | 101 | * Instead of relying on the helpers for modeset, the omap_crtc code |
102 | * calls these functions in the proper sequence. | ||
103 | */ | ||
104 | |||
105 | int omap_encoder_set_enabled(struct drm_encoder *encoder, bool enabled) | ||
114 | { | 106 | { |
115 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | 107 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); |
116 | return omap_encoder->mgr; | 108 | struct omap_dss_device *dssdev = omap_encoder->dssdev; |
109 | struct omap_dss_driver *dssdrv = dssdev->driver; | ||
110 | |||
111 | if (enabled) { | ||
112 | return dssdrv->enable(dssdev); | ||
113 | } else { | ||
114 | dssdrv->disable(dssdev); | ||
115 | return 0; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | int omap_encoder_update(struct drm_encoder *encoder, | ||
120 | struct omap_overlay_manager *mgr, | ||
121 | struct omap_video_timings *timings) | ||
122 | { | ||
123 | struct drm_device *dev = encoder->dev; | ||
124 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
125 | struct omap_dss_device *dssdev = omap_encoder->dssdev; | ||
126 | struct omap_dss_driver *dssdrv = dssdev->driver; | ||
127 | int ret; | ||
128 | |||
129 | dssdev->output->manager = mgr; | ||
130 | |||
131 | ret = dssdrv->check_timings(dssdev, timings); | ||
132 | if (ret) { | ||
133 | dev_err(dev->dev, "could not set timings: %d\n", ret); | ||
134 | return ret; | ||
135 | } | ||
136 | |||
137 | dssdrv->set_timings(dssdev, timings); | ||
138 | |||
139 | return 0; | ||
117 | } | 140 | } |
118 | 141 | ||
119 | /* initialize encoder */ | 142 | /* initialize encoder */ |
120 | struct drm_encoder *omap_encoder_init(struct drm_device *dev, | 143 | struct drm_encoder *omap_encoder_init(struct drm_device *dev, |
121 | struct omap_overlay_manager *mgr) | 144 | struct omap_dss_device *dssdev) |
122 | { | 145 | { |
123 | struct drm_encoder *encoder = NULL; | 146 | struct drm_encoder *encoder = NULL; |
124 | struct omap_encoder *omap_encoder; | 147 | struct omap_encoder *omap_encoder; |
125 | struct omap_overlay_manager_info info; | ||
126 | int ret; | ||
127 | |||
128 | DBG("%s", mgr->name); | ||
129 | 148 | ||
130 | omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL); | 149 | omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL); |
131 | if (!omap_encoder) { | 150 | if (!omap_encoder) { |
@@ -133,33 +152,14 @@ struct drm_encoder *omap_encoder_init(struct drm_device *dev, | |||
133 | goto fail; | 152 | goto fail; |
134 | } | 153 | } |
135 | 154 | ||
136 | omap_encoder->mgr = mgr; | 155 | omap_encoder->dssdev = dssdev; |
156 | |||
137 | encoder = &omap_encoder->base; | 157 | encoder = &omap_encoder->base; |
138 | 158 | ||
139 | drm_encoder_init(dev, encoder, &omap_encoder_funcs, | 159 | drm_encoder_init(dev, encoder, &omap_encoder_funcs, |
140 | DRM_MODE_ENCODER_TMDS); | 160 | DRM_MODE_ENCODER_TMDS); |
141 | drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs); | 161 | drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs); |
142 | 162 | ||
143 | mgr->get_manager_info(mgr, &info); | ||
144 | |||
145 | /* TODO: fix hard-coded setup.. */ | ||
146 | info.default_color = 0x00000000; | ||
147 | info.trans_key = 0x00000000; | ||
148 | info.trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST; | ||
149 | info.trans_enabled = false; | ||
150 | |||
151 | ret = mgr->set_manager_info(mgr, &info); | ||
152 | if (ret) { | ||
153 | dev_err(dev->dev, "could not set manager info\n"); | ||
154 | goto fail; | ||
155 | } | ||
156 | |||
157 | ret = mgr->apply(mgr); | ||
158 | if (ret) { | ||
159 | dev_err(dev->dev, "could not apply\n"); | ||
160 | goto fail; | ||
161 | } | ||
162 | |||
163 | return encoder; | 163 | return encoder; |
164 | 164 | ||
165 | fail: | 165 | fail: |
diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c index 09028e9c1093..bf6421f26c40 100644 --- a/drivers/staging/omapdrm/omap_fb.c +++ b/drivers/staging/omapdrm/omap_fb.c | |||
@@ -424,14 +424,6 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, | |||
424 | } | 424 | } |
425 | 425 | ||
426 | fb = &omap_fb->base; | 426 | fb = &omap_fb->base; |
427 | ret = drm_framebuffer_init(dev, fb, &omap_framebuffer_funcs); | ||
428 | if (ret) { | ||
429 | dev_err(dev->dev, "framebuffer init failed: %d\n", ret); | ||
430 | goto fail; | ||
431 | } | ||
432 | |||
433 | DBG("create: FB ID: %d (%p)", fb->base.id, fb); | ||
434 | |||
435 | omap_fb->format = format; | 427 | omap_fb->format = format; |
436 | 428 | ||
437 | for (i = 0; i < n; i++) { | 429 | for (i = 0; i < n; i++) { |
@@ -462,6 +454,14 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, | |||
462 | 454 | ||
463 | drm_helper_mode_fill_fb_struct(fb, mode_cmd); | 455 | drm_helper_mode_fill_fb_struct(fb, mode_cmd); |
464 | 456 | ||
457 | ret = drm_framebuffer_init(dev, fb, &omap_framebuffer_funcs); | ||
458 | if (ret) { | ||
459 | dev_err(dev->dev, "framebuffer init failed: %d\n", ret); | ||
460 | goto fail; | ||
461 | } | ||
462 | |||
463 | DBG("create: FB ID: %d (%p)", fb->base.id, fb); | ||
464 | |||
465 | return fb; | 465 | return fb; |
466 | 466 | ||
467 | fail: | 467 | fail: |
diff --git a/drivers/staging/omapdrm/omap_fbdev.c b/drivers/staging/omapdrm/omap_fbdev.c index 8a027bb77d97..2728e37e02be 100644 --- a/drivers/staging/omapdrm/omap_fbdev.c +++ b/drivers/staging/omapdrm/omap_fbdev.c | |||
@@ -275,8 +275,10 @@ fail: | |||
275 | if (ret) { | 275 | if (ret) { |
276 | if (fbi) | 276 | if (fbi) |
277 | framebuffer_release(fbi); | 277 | framebuffer_release(fbi); |
278 | if (fb) | 278 | if (fb) { |
279 | drm_framebuffer_unregister_private(fb); | ||
279 | drm_framebuffer_remove(fb); | 280 | drm_framebuffer_remove(fb); |
281 | } | ||
280 | } | 282 | } |
281 | 283 | ||
282 | return ret; | 284 | return ret; |
@@ -400,8 +402,10 @@ void omap_fbdev_free(struct drm_device *dev) | |||
400 | fbdev = to_omap_fbdev(priv->fbdev); | 402 | fbdev = to_omap_fbdev(priv->fbdev); |
401 | 403 | ||
402 | /* this will free the backing object */ | 404 | /* this will free the backing object */ |
403 | if (fbdev->fb) | 405 | if (fbdev->fb) { |
406 | drm_framebuffer_unregister_private(fbdev->fb); | ||
404 | drm_framebuffer_remove(fbdev->fb); | 407 | drm_framebuffer_remove(fbdev->fb); |
408 | } | ||
405 | 409 | ||
406 | kfree(fbdev); | 410 | kfree(fbdev); |
407 | 411 | ||
diff --git a/drivers/staging/omapdrm/omap_gem_dmabuf.c b/drivers/staging/omapdrm/omap_gem_dmabuf.c index ea3840038250..b6c5b5c6c8c5 100644 --- a/drivers/staging/omapdrm/omap_gem_dmabuf.c +++ b/drivers/staging/omapdrm/omap_gem_dmabuf.c | |||
@@ -194,7 +194,7 @@ struct dma_buf_ops omap_dmabuf_ops = { | |||
194 | struct dma_buf *omap_gem_prime_export(struct drm_device *dev, | 194 | struct dma_buf *omap_gem_prime_export(struct drm_device *dev, |
195 | struct drm_gem_object *obj, int flags) | 195 | struct drm_gem_object *obj, int flags) |
196 | { | 196 | { |
197 | return dma_buf_export(obj, &omap_dmabuf_ops, obj->size, 0600); | 197 | return dma_buf_export(obj, &omap_dmabuf_ops, obj->size, flags); |
198 | } | 198 | } |
199 | 199 | ||
200 | struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, | 200 | struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, |
diff --git a/drivers/staging/omapdrm/omap_irq.c b/drivers/staging/omapdrm/omap_irq.c new file mode 100644 index 000000000000..2629ba7be6c8 --- /dev/null +++ b/drivers/staging/omapdrm/omap_irq.c | |||
@@ -0,0 +1,322 @@ | |||
1 | /* | ||
2 | * drivers/staging/omapdrm/omap_irq.c | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments | ||
5 | * Author: Rob Clark <rob.clark@linaro.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include "omap_drv.h" | ||
21 | |||
22 | static DEFINE_SPINLOCK(list_lock); | ||
23 | |||
24 | static void omap_irq_error_handler(struct omap_drm_irq *irq, | ||
25 | uint32_t irqstatus) | ||
26 | { | ||
27 | DRM_ERROR("errors: %08x\n", irqstatus); | ||
28 | } | ||
29 | |||
30 | /* call with list_lock and dispc runtime held */ | ||
31 | static void omap_irq_update(struct drm_device *dev) | ||
32 | { | ||
33 | struct omap_drm_private *priv = dev->dev_private; | ||
34 | struct omap_drm_irq *irq; | ||
35 | uint32_t irqmask = priv->vblank_mask; | ||
36 | |||
37 | BUG_ON(!spin_is_locked(&list_lock)); | ||
38 | |||
39 | list_for_each_entry(irq, &priv->irq_list, node) | ||
40 | irqmask |= irq->irqmask; | ||
41 | |||
42 | DBG("irqmask=%08x", irqmask); | ||
43 | |||
44 | dispc_write_irqenable(irqmask); | ||
45 | dispc_read_irqenable(); /* flush posted write */ | ||
46 | } | ||
47 | |||
48 | void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq) | ||
49 | { | ||
50 | struct omap_drm_private *priv = dev->dev_private; | ||
51 | unsigned long flags; | ||
52 | |||
53 | dispc_runtime_get(); | ||
54 | spin_lock_irqsave(&list_lock, flags); | ||
55 | |||
56 | if (!WARN_ON(irq->registered)) { | ||
57 | irq->registered = true; | ||
58 | list_add(&irq->node, &priv->irq_list); | ||
59 | omap_irq_update(dev); | ||
60 | } | ||
61 | |||
62 | spin_unlock_irqrestore(&list_lock, flags); | ||
63 | dispc_runtime_put(); | ||
64 | } | ||
65 | |||
66 | void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq) | ||
67 | { | ||
68 | unsigned long flags; | ||
69 | |||
70 | dispc_runtime_get(); | ||
71 | spin_lock_irqsave(&list_lock, flags); | ||
72 | |||
73 | if (!WARN_ON(!irq->registered)) { | ||
74 | irq->registered = false; | ||
75 | list_del(&irq->node); | ||
76 | omap_irq_update(dev); | ||
77 | } | ||
78 | |||
79 | spin_unlock_irqrestore(&list_lock, flags); | ||
80 | dispc_runtime_put(); | ||
81 | } | ||
82 | |||
83 | struct omap_irq_wait { | ||
84 | struct omap_drm_irq irq; | ||
85 | int count; | ||
86 | }; | ||
87 | |||
88 | static DECLARE_WAIT_QUEUE_HEAD(wait_event); | ||
89 | |||
90 | static void wait_irq(struct omap_drm_irq *irq, uint32_t irqstatus) | ||
91 | { | ||
92 | struct omap_irq_wait *wait = | ||
93 | container_of(irq, struct omap_irq_wait, irq); | ||
94 | wait->count--; | ||
95 | wake_up_all(&wait_event); | ||
96 | } | ||
97 | |||
98 | struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev, | ||
99 | uint32_t irqmask, int count) | ||
100 | { | ||
101 | struct omap_irq_wait *wait = kzalloc(sizeof(*wait), GFP_KERNEL); | ||
102 | wait->irq.irq = wait_irq; | ||
103 | wait->irq.irqmask = irqmask; | ||
104 | wait->count = count; | ||
105 | omap_irq_register(dev, &wait->irq); | ||
106 | return wait; | ||
107 | } | ||
108 | |||
109 | int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, | ||
110 | unsigned long timeout) | ||
111 | { | ||
112 | int ret = wait_event_timeout(wait_event, (wait->count <= 0), timeout); | ||
113 | omap_irq_unregister(dev, &wait->irq); | ||
114 | kfree(wait); | ||
115 | if (ret == 0) | ||
116 | return -1; | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | /** | ||
121 | * enable_vblank - enable vblank interrupt events | ||
122 | * @dev: DRM device | ||
123 | * @crtc: which irq to enable | ||
124 | * | ||
125 | * Enable vblank interrupts for @crtc. If the device doesn't have | ||
126 | * a hardware vblank counter, this routine should be a no-op, since | ||
127 | * interrupts will have to stay on to keep the count accurate. | ||
128 | * | ||
129 | * RETURNS | ||
130 | * Zero on success, appropriate errno if the given @crtc's vblank | ||
131 | * interrupt cannot be enabled. | ||
132 | */ | ||
133 | int omap_irq_enable_vblank(struct drm_device *dev, int crtc) | ||
134 | { | ||
135 | struct omap_drm_private *priv = dev->dev_private; | ||
136 | unsigned long flags; | ||
137 | |||
138 | DBG("dev=%p, crtc=%d", dev, crtc); | ||
139 | |||
140 | dispc_runtime_get(); | ||
141 | spin_lock_irqsave(&list_lock, flags); | ||
142 | priv->vblank_mask |= pipe2vbl(crtc); | ||
143 | omap_irq_update(dev); | ||
144 | spin_unlock_irqrestore(&list_lock, flags); | ||
145 | dispc_runtime_put(); | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * disable_vblank - disable vblank interrupt events | ||
152 | * @dev: DRM device | ||
153 | * @crtc: which irq to enable | ||
154 | * | ||
155 | * Disable vblank interrupts for @crtc. If the device doesn't have | ||
156 | * a hardware vblank counter, this routine should be a no-op, since | ||
157 | * interrupts will have to stay on to keep the count accurate. | ||
158 | */ | ||
159 | void omap_irq_disable_vblank(struct drm_device *dev, int crtc) | ||
160 | { | ||
161 | struct omap_drm_private *priv = dev->dev_private; | ||
162 | unsigned long flags; | ||
163 | |||
164 | DBG("dev=%p, crtc=%d", dev, crtc); | ||
165 | |||
166 | dispc_runtime_get(); | ||
167 | spin_lock_irqsave(&list_lock, flags); | ||
168 | priv->vblank_mask &= ~pipe2vbl(crtc); | ||
169 | omap_irq_update(dev); | ||
170 | spin_unlock_irqrestore(&list_lock, flags); | ||
171 | dispc_runtime_put(); | ||
172 | } | ||
173 | |||
174 | irqreturn_t omap_irq_handler(DRM_IRQ_ARGS) | ||
175 | { | ||
176 | struct drm_device *dev = (struct drm_device *) arg; | ||
177 | struct omap_drm_private *priv = dev->dev_private; | ||
178 | struct omap_drm_irq *handler, *n; | ||
179 | unsigned long flags; | ||
180 | unsigned int id; | ||
181 | u32 irqstatus; | ||
182 | |||
183 | irqstatus = dispc_read_irqstatus(); | ||
184 | dispc_clear_irqstatus(irqstatus); | ||
185 | dispc_read_irqstatus(); /* flush posted write */ | ||
186 | |||
187 | VERB("irqs: %08x", irqstatus); | ||
188 | |||
189 | for (id = 0; id < priv->num_crtcs; id++) | ||
190 | if (irqstatus & pipe2vbl(id)) | ||
191 | drm_handle_vblank(dev, id); | ||
192 | |||
193 | spin_lock_irqsave(&list_lock, flags); | ||
194 | list_for_each_entry_safe(handler, n, &priv->irq_list, node) { | ||
195 | if (handler->irqmask & irqstatus) { | ||
196 | spin_unlock_irqrestore(&list_lock, flags); | ||
197 | handler->irq(handler, handler->irqmask & irqstatus); | ||
198 | spin_lock_irqsave(&list_lock, flags); | ||
199 | } | ||
200 | } | ||
201 | spin_unlock_irqrestore(&list_lock, flags); | ||
202 | |||
203 | return IRQ_HANDLED; | ||
204 | } | ||
205 | |||
206 | void omap_irq_preinstall(struct drm_device *dev) | ||
207 | { | ||
208 | DBG("dev=%p", dev); | ||
209 | dispc_runtime_get(); | ||
210 | dispc_clear_irqstatus(0xffffffff); | ||
211 | dispc_runtime_put(); | ||
212 | } | ||
213 | |||
214 | int omap_irq_postinstall(struct drm_device *dev) | ||
215 | { | ||
216 | struct omap_drm_private *priv = dev->dev_private; | ||
217 | struct omap_drm_irq *error_handler = &priv->error_handler; | ||
218 | |||
219 | DBG("dev=%p", dev); | ||
220 | |||
221 | INIT_LIST_HEAD(&priv->irq_list); | ||
222 | |||
223 | error_handler->irq = omap_irq_error_handler; | ||
224 | error_handler->irqmask = DISPC_IRQ_OCP_ERR; | ||
225 | |||
226 | /* for now ignore DISPC_IRQ_SYNC_LOST_DIGIT.. really I think | ||
227 | * we just need to ignore it while enabling tv-out | ||
228 | */ | ||
229 | error_handler->irqmask &= ~DISPC_IRQ_SYNC_LOST_DIGIT; | ||
230 | |||
231 | omap_irq_register(dev, error_handler); | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | void omap_irq_uninstall(struct drm_device *dev) | ||
237 | { | ||
238 | DBG("dev=%p", dev); | ||
239 | // TODO prolly need to call drm_irq_uninstall() somewhere too | ||
240 | } | ||
241 | |||
242 | /* | ||
243 | * We need a special version, instead of just using drm_irq_install(), | ||
244 | * because we need to register the irq via omapdss. Once omapdss and | ||
245 | * omapdrm are merged together we can assign the dispc hwmod data to | ||
246 | * ourselves and drop these and just use drm_irq_{install,uninstall}() | ||
247 | */ | ||
248 | |||
249 | int omap_drm_irq_install(struct drm_device *dev) | ||
250 | { | ||
251 | int ret; | ||
252 | |||
253 | mutex_lock(&dev->struct_mutex); | ||
254 | |||
255 | if (dev->irq_enabled) { | ||
256 | mutex_unlock(&dev->struct_mutex); | ||
257 | return -EBUSY; | ||
258 | } | ||
259 | dev->irq_enabled = 1; | ||
260 | mutex_unlock(&dev->struct_mutex); | ||
261 | |||
262 | /* Before installing handler */ | ||
263 | if (dev->driver->irq_preinstall) | ||
264 | dev->driver->irq_preinstall(dev); | ||
265 | |||
266 | ret = dispc_request_irq(dev->driver->irq_handler, dev); | ||
267 | |||
268 | if (ret < 0) { | ||
269 | mutex_lock(&dev->struct_mutex); | ||
270 | dev->irq_enabled = 0; | ||
271 | mutex_unlock(&dev->struct_mutex); | ||
272 | return ret; | ||
273 | } | ||
274 | |||
275 | /* After installing handler */ | ||
276 | if (dev->driver->irq_postinstall) | ||
277 | ret = dev->driver->irq_postinstall(dev); | ||
278 | |||
279 | if (ret < 0) { | ||
280 | mutex_lock(&dev->struct_mutex); | ||
281 | dev->irq_enabled = 0; | ||
282 | mutex_unlock(&dev->struct_mutex); | ||
283 | dispc_free_irq(dev); | ||
284 | } | ||
285 | |||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | int omap_drm_irq_uninstall(struct drm_device *dev) | ||
290 | { | ||
291 | unsigned long irqflags; | ||
292 | int irq_enabled, i; | ||
293 | |||
294 | mutex_lock(&dev->struct_mutex); | ||
295 | irq_enabled = dev->irq_enabled; | ||
296 | dev->irq_enabled = 0; | ||
297 | mutex_unlock(&dev->struct_mutex); | ||
298 | |||
299 | /* | ||
300 | * Wake up any waiters so they don't hang. | ||
301 | */ | ||
302 | if (dev->num_crtcs) { | ||
303 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
304 | for (i = 0; i < dev->num_crtcs; i++) { | ||
305 | DRM_WAKEUP(&dev->vbl_queue[i]); | ||
306 | dev->vblank_enabled[i] = 0; | ||
307 | dev->last_vblank[i] = | ||
308 | dev->driver->get_vblank_counter(dev, i); | ||
309 | } | ||
310 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
311 | } | ||
312 | |||
313 | if (!irq_enabled) | ||
314 | return -EINVAL; | ||
315 | |||
316 | if (dev->driver->irq_uninstall) | ||
317 | dev->driver->irq_uninstall(dev); | ||
318 | |||
319 | dispc_free_irq(dev); | ||
320 | |||
321 | return 0; | ||
322 | } | ||
diff --git a/drivers/staging/omapdrm/omap_plane.c b/drivers/staging/omapdrm/omap_plane.c index 2a8e5bab49c9..bb989d7f026d 100644 --- a/drivers/staging/omapdrm/omap_plane.c +++ b/drivers/staging/omapdrm/omap_plane.c | |||
@@ -41,12 +41,14 @@ struct callback { | |||
41 | 41 | ||
42 | struct omap_plane { | 42 | struct omap_plane { |
43 | struct drm_plane base; | 43 | struct drm_plane base; |
44 | struct omap_overlay *ovl; | 44 | int id; /* TODO rename omap_plane -> omap_plane_id in omapdss so I can use the enum */ |
45 | const char *name; | ||
45 | struct omap_overlay_info info; | 46 | struct omap_overlay_info info; |
47 | struct omap_drm_apply apply; | ||
46 | 48 | ||
47 | /* position/orientation of scanout within the fb: */ | 49 | /* position/orientation of scanout within the fb: */ |
48 | struct omap_drm_window win; | 50 | struct omap_drm_window win; |
49 | 51 | bool enabled; | |
50 | 52 | ||
51 | /* last fb that we pinned: */ | 53 | /* last fb that we pinned: */ |
52 | struct drm_framebuffer *pinned_fb; | 54 | struct drm_framebuffer *pinned_fb; |
@@ -54,189 +56,15 @@ struct omap_plane { | |||
54 | uint32_t nformats; | 56 | uint32_t nformats; |
55 | uint32_t formats[32]; | 57 | uint32_t formats[32]; |
56 | 58 | ||
57 | /* for synchronizing access to unpins fifo */ | 59 | struct omap_drm_irq error_irq; |
58 | struct mutex unpin_mutex; | ||
59 | 60 | ||
60 | /* set of bo's pending unpin until next END_WIN irq */ | 61 | /* set of bo's pending unpin until next post_apply() */ |
61 | DECLARE_KFIFO_PTR(unpin_fifo, struct drm_gem_object *); | 62 | DECLARE_KFIFO_PTR(unpin_fifo, struct drm_gem_object *); |
62 | int num_unpins, pending_num_unpins; | ||
63 | |||
64 | /* for deferred unpin when we need to wait for scanout complete irq */ | ||
65 | struct work_struct work; | ||
66 | |||
67 | /* callback on next endwin irq */ | ||
68 | struct callback endwin; | ||
69 | }; | ||
70 | 63 | ||
71 | /* map from ovl->id to the irq we are interested in for scanout-done */ | 64 | // XXX maybe get rid of this and handle vblank in crtc too? |
72 | static const uint32_t id2irq[] = { | 65 | struct callback apply_done_cb; |
73 | [OMAP_DSS_GFX] = DISPC_IRQ_GFX_END_WIN, | ||
74 | [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_END_WIN, | ||
75 | [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_END_WIN, | ||
76 | [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_END_WIN, | ||
77 | }; | 66 | }; |
78 | 67 | ||
79 | static void dispc_isr(void *arg, uint32_t mask) | ||
80 | { | ||
81 | struct drm_plane *plane = arg; | ||
82 | struct omap_plane *omap_plane = to_omap_plane(plane); | ||
83 | struct omap_drm_private *priv = plane->dev->dev_private; | ||
84 | |||
85 | omap_dispc_unregister_isr(dispc_isr, plane, | ||
86 | id2irq[omap_plane->ovl->id]); | ||
87 | |||
88 | queue_work(priv->wq, &omap_plane->work); | ||
89 | } | ||
90 | |||
91 | static void unpin_worker(struct work_struct *work) | ||
92 | { | ||
93 | struct omap_plane *omap_plane = | ||
94 | container_of(work, struct omap_plane, work); | ||
95 | struct callback endwin; | ||
96 | |||
97 | mutex_lock(&omap_plane->unpin_mutex); | ||
98 | DBG("unpinning %d of %d", omap_plane->num_unpins, | ||
99 | omap_plane->num_unpins + omap_plane->pending_num_unpins); | ||
100 | while (omap_plane->num_unpins > 0) { | ||
101 | struct drm_gem_object *bo = NULL; | ||
102 | int ret = kfifo_get(&omap_plane->unpin_fifo, &bo); | ||
103 | WARN_ON(!ret); | ||
104 | omap_gem_put_paddr(bo); | ||
105 | drm_gem_object_unreference_unlocked(bo); | ||
106 | omap_plane->num_unpins--; | ||
107 | } | ||
108 | endwin = omap_plane->endwin; | ||
109 | omap_plane->endwin.fxn = NULL; | ||
110 | mutex_unlock(&omap_plane->unpin_mutex); | ||
111 | |||
112 | if (endwin.fxn) | ||
113 | endwin.fxn(endwin.arg); | ||
114 | } | ||
115 | |||
116 | static void install_irq(struct drm_plane *plane) | ||
117 | { | ||
118 | struct omap_plane *omap_plane = to_omap_plane(plane); | ||
119 | struct omap_overlay *ovl = omap_plane->ovl; | ||
120 | int ret; | ||
121 | |||
122 | ret = omap_dispc_register_isr(dispc_isr, plane, id2irq[ovl->id]); | ||
123 | |||
124 | /* | ||
125 | * omapdss has upper limit on # of registered irq handlers, | ||
126 | * which we shouldn't hit.. but if we do the limit should | ||
127 | * be raised or bad things happen: | ||
128 | */ | ||
129 | WARN_ON(ret == -EBUSY); | ||
130 | } | ||
131 | |||
132 | /* push changes down to dss2 */ | ||
133 | static int commit(struct drm_plane *plane) | ||
134 | { | ||
135 | struct drm_device *dev = plane->dev; | ||
136 | struct omap_plane *omap_plane = to_omap_plane(plane); | ||
137 | struct omap_overlay *ovl = omap_plane->ovl; | ||
138 | struct omap_overlay_info *info = &omap_plane->info; | ||
139 | int ret; | ||
140 | |||
141 | DBG("%s", ovl->name); | ||
142 | DBG("%dx%d -> %dx%d (%d)", info->width, info->height, info->out_width, | ||
143 | info->out_height, info->screen_width); | ||
144 | DBG("%d,%d %08x %08x", info->pos_x, info->pos_y, | ||
145 | info->paddr, info->p_uv_addr); | ||
146 | |||
147 | /* NOTE: do we want to do this at all here, or just wait | ||
148 | * for dpms(ON) since other CRTC's may not have their mode | ||
149 | * set yet, so fb dimensions may still change.. | ||
150 | */ | ||
151 | ret = ovl->set_overlay_info(ovl, info); | ||
152 | if (ret) { | ||
153 | dev_err(dev->dev, "could not set overlay info\n"); | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | mutex_lock(&omap_plane->unpin_mutex); | ||
158 | omap_plane->num_unpins += omap_plane->pending_num_unpins; | ||
159 | omap_plane->pending_num_unpins = 0; | ||
160 | mutex_unlock(&omap_plane->unpin_mutex); | ||
161 | |||
162 | /* our encoder doesn't necessarily get a commit() after this, in | ||
163 | * particular in the dpms() and mode_set_base() cases, so force the | ||
164 | * manager to update: | ||
165 | * | ||
166 | * could this be in the encoder somehow? | ||
167 | */ | ||
168 | if (ovl->manager) { | ||
169 | ret = ovl->manager->apply(ovl->manager); | ||
170 | if (ret) { | ||
171 | dev_err(dev->dev, "could not apply settings\n"); | ||
172 | return ret; | ||
173 | } | ||
174 | |||
175 | /* | ||
176 | * NOTE: really this should be atomic w/ mgr->apply() but | ||
177 | * omapdss does not expose such an API | ||
178 | */ | ||
179 | if (omap_plane->num_unpins > 0) | ||
180 | install_irq(plane); | ||
181 | |||
182 | } else { | ||
183 | struct omap_drm_private *priv = dev->dev_private; | ||
184 | queue_work(priv->wq, &omap_plane->work); | ||
185 | } | ||
186 | |||
187 | |||
188 | if (ovl->is_enabled(ovl)) { | ||
189 | omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y, | ||
190 | info->out_width, info->out_height); | ||
191 | } | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | /* when CRTC that we are attached to has potentially changed, this checks | ||
197 | * if we are attached to proper manager, and if necessary updates. | ||
198 | */ | ||
199 | static void update_manager(struct drm_plane *plane) | ||
200 | { | ||
201 | struct omap_drm_private *priv = plane->dev->dev_private; | ||
202 | struct omap_plane *omap_plane = to_omap_plane(plane); | ||
203 | struct omap_overlay *ovl = omap_plane->ovl; | ||
204 | struct omap_overlay_manager *mgr = NULL; | ||
205 | int i; | ||
206 | |||
207 | if (plane->crtc) { | ||
208 | for (i = 0; i < priv->num_encoders; i++) { | ||
209 | struct drm_encoder *encoder = priv->encoders[i]; | ||
210 | if (encoder->crtc == plane->crtc) { | ||
211 | mgr = omap_encoder_get_manager(encoder); | ||
212 | break; | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | |||
217 | if (ovl->manager != mgr) { | ||
218 | bool enabled = ovl->is_enabled(ovl); | ||
219 | |||
220 | /* don't switch things around with enabled overlays: */ | ||
221 | if (enabled) | ||
222 | omap_plane_dpms(plane, DRM_MODE_DPMS_OFF); | ||
223 | |||
224 | if (ovl->manager) { | ||
225 | DBG("disconnecting %s from %s", ovl->name, | ||
226 | ovl->manager->name); | ||
227 | ovl->unset_manager(ovl); | ||
228 | } | ||
229 | |||
230 | if (mgr) { | ||
231 | DBG("connecting %s to %s", ovl->name, mgr->name); | ||
232 | ovl->set_manager(ovl, mgr); | ||
233 | } | ||
234 | |||
235 | if (enabled && mgr) | ||
236 | omap_plane_dpms(plane, DRM_MODE_DPMS_ON); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | static void unpin(void *arg, struct drm_gem_object *bo) | 68 | static void unpin(void *arg, struct drm_gem_object *bo) |
241 | { | 69 | { |
242 | struct drm_plane *plane = arg; | 70 | struct drm_plane *plane = arg; |
@@ -244,7 +72,6 @@ static void unpin(void *arg, struct drm_gem_object *bo) | |||
244 | 72 | ||
245 | if (kfifo_put(&omap_plane->unpin_fifo, | 73 | if (kfifo_put(&omap_plane->unpin_fifo, |
246 | (const struct drm_gem_object **)&bo)) { | 74 | (const struct drm_gem_object **)&bo)) { |
247 | omap_plane->pending_num_unpins++; | ||
248 | /* also hold a ref so it isn't free'd while pinned */ | 75 | /* also hold a ref so it isn't free'd while pinned */ |
249 | drm_gem_object_reference(bo); | 76 | drm_gem_object_reference(bo); |
250 | } else { | 77 | } else { |
@@ -264,13 +91,19 @@ static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb) | |||
264 | 91 | ||
265 | DBG("%p -> %p", pinned_fb, fb); | 92 | DBG("%p -> %p", pinned_fb, fb); |
266 | 93 | ||
267 | mutex_lock(&omap_plane->unpin_mutex); | 94 | if (fb) |
95 | drm_framebuffer_reference(fb); | ||
96 | |||
268 | ret = omap_framebuffer_replace(pinned_fb, fb, plane, unpin); | 97 | ret = omap_framebuffer_replace(pinned_fb, fb, plane, unpin); |
269 | mutex_unlock(&omap_plane->unpin_mutex); | 98 | |
99 | if (pinned_fb) | ||
100 | drm_framebuffer_unreference(pinned_fb); | ||
270 | 101 | ||
271 | if (ret) { | 102 | if (ret) { |
272 | dev_err(plane->dev->dev, "could not swap %p -> %p\n", | 103 | dev_err(plane->dev->dev, "could not swap %p -> %p\n", |
273 | omap_plane->pinned_fb, fb); | 104 | omap_plane->pinned_fb, fb); |
105 | if (fb) | ||
106 | drm_framebuffer_unreference(fb); | ||
274 | omap_plane->pinned_fb = NULL; | 107 | omap_plane->pinned_fb = NULL; |
275 | return ret; | 108 | return ret; |
276 | } | 109 | } |
@@ -281,31 +114,90 @@ static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb) | |||
281 | return 0; | 114 | return 0; |
282 | } | 115 | } |
283 | 116 | ||
284 | /* update parameters that are dependent on the framebuffer dimensions and | 117 | static void omap_plane_pre_apply(struct omap_drm_apply *apply) |
285 | * position within the fb that this plane scans out from. This is called | ||
286 | * when framebuffer or x,y base may have changed. | ||
287 | */ | ||
288 | static void update_scanout(struct drm_plane *plane) | ||
289 | { | 118 | { |
290 | struct omap_plane *omap_plane = to_omap_plane(plane); | 119 | struct omap_plane *omap_plane = |
291 | struct omap_overlay_info *info = &omap_plane->info; | 120 | container_of(apply, struct omap_plane, apply); |
292 | struct omap_drm_window *win = &omap_plane->win; | 121 | struct omap_drm_window *win = &omap_plane->win; |
122 | struct drm_plane *plane = &omap_plane->base; | ||
123 | struct drm_device *dev = plane->dev; | ||
124 | struct omap_overlay_info *info = &omap_plane->info; | ||
125 | struct drm_crtc *crtc = plane->crtc; | ||
126 | enum omap_channel channel; | ||
127 | bool enabled = omap_plane->enabled && crtc; | ||
128 | bool ilace, replication; | ||
293 | int ret; | 129 | int ret; |
294 | 130 | ||
295 | ret = update_pin(plane, plane->fb); | 131 | DBG("%s, enabled=%d", omap_plane->name, enabled); |
296 | if (ret) { | 132 | |
297 | dev_err(plane->dev->dev, | 133 | /* if fb has changed, pin new fb: */ |
298 | "could not pin fb: %d\n", ret); | 134 | update_pin(plane, enabled ? plane->fb : NULL); |
299 | omap_plane_dpms(plane, DRM_MODE_DPMS_OFF); | 135 | |
136 | if (!enabled) { | ||
137 | dispc_ovl_enable(omap_plane->id, false); | ||
300 | return; | 138 | return; |
301 | } | 139 | } |
302 | 140 | ||
141 | channel = omap_crtc_channel(crtc); | ||
142 | |||
143 | /* update scanout: */ | ||
303 | omap_framebuffer_update_scanout(plane->fb, win, info); | 144 | omap_framebuffer_update_scanout(plane->fb, win, info); |
304 | 145 | ||
305 | DBG("%s: %d,%d: %08x %08x (%d)", omap_plane->ovl->name, | 146 | DBG("%dx%d -> %dx%d (%d)", info->width, info->height, |
306 | win->src_x, win->src_y, | 147 | info->out_width, info->out_height, |
307 | (u32)info->paddr, (u32)info->p_uv_addr, | ||
308 | info->screen_width); | 148 | info->screen_width); |
149 | DBG("%d,%d %08x %08x", info->pos_x, info->pos_y, | ||
150 | info->paddr, info->p_uv_addr); | ||
151 | |||
152 | /* TODO: */ | ||
153 | ilace = false; | ||
154 | replication = false; | ||
155 | |||
156 | /* and finally, update omapdss: */ | ||
157 | ret = dispc_ovl_setup(omap_plane->id, info, | ||
158 | replication, omap_crtc_timings(crtc), false); | ||
159 | if (ret) { | ||
160 | dev_err(dev->dev, "dispc_ovl_setup failed: %d\n", ret); | ||
161 | return; | ||
162 | } | ||
163 | |||
164 | dispc_ovl_enable(omap_plane->id, true); | ||
165 | dispc_ovl_set_channel_out(omap_plane->id, channel); | ||
166 | } | ||
167 | |||
168 | static void omap_plane_post_apply(struct omap_drm_apply *apply) | ||
169 | { | ||
170 | struct omap_plane *omap_plane = | ||
171 | container_of(apply, struct omap_plane, apply); | ||
172 | struct drm_plane *plane = &omap_plane->base; | ||
173 | struct omap_overlay_info *info = &omap_plane->info; | ||
174 | struct drm_gem_object *bo = NULL; | ||
175 | struct callback cb; | ||
176 | |||
177 | cb = omap_plane->apply_done_cb; | ||
178 | omap_plane->apply_done_cb.fxn = NULL; | ||
179 | |||
180 | while (kfifo_get(&omap_plane->unpin_fifo, &bo)) { | ||
181 | omap_gem_put_paddr(bo); | ||
182 | drm_gem_object_unreference_unlocked(bo); | ||
183 | } | ||
184 | |||
185 | if (cb.fxn) | ||
186 | cb.fxn(cb.arg); | ||
187 | |||
188 | if (omap_plane->enabled) { | ||
189 | omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y, | ||
190 | info->out_width, info->out_height); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | static int apply(struct drm_plane *plane) | ||
195 | { | ||
196 | if (plane->crtc) { | ||
197 | struct omap_plane *omap_plane = to_omap_plane(plane); | ||
198 | return omap_crtc_apply(plane->crtc, &omap_plane->apply); | ||
199 | } | ||
200 | return 0; | ||
309 | } | 201 | } |
310 | 202 | ||
311 | int omap_plane_mode_set(struct drm_plane *plane, | 203 | int omap_plane_mode_set(struct drm_plane *plane, |
@@ -313,7 +205,8 @@ int omap_plane_mode_set(struct drm_plane *plane, | |||
313 | int crtc_x, int crtc_y, | 205 | int crtc_x, int crtc_y, |
314 | unsigned int crtc_w, unsigned int crtc_h, | 206 | unsigned int crtc_w, unsigned int crtc_h, |
315 | uint32_t src_x, uint32_t src_y, | 207 | uint32_t src_x, uint32_t src_y, |
316 | uint32_t src_w, uint32_t src_h) | 208 | uint32_t src_w, uint32_t src_h, |
209 | void (*fxn)(void *), void *arg) | ||
317 | { | 210 | { |
318 | struct omap_plane *omap_plane = to_omap_plane(plane); | 211 | struct omap_plane *omap_plane = to_omap_plane(plane); |
319 | struct omap_drm_window *win = &omap_plane->win; | 212 | struct omap_drm_window *win = &omap_plane->win; |
@@ -329,17 +222,20 @@ int omap_plane_mode_set(struct drm_plane *plane, | |||
329 | win->src_w = src_w >> 16; | 222 | win->src_w = src_w >> 16; |
330 | win->src_h = src_h >> 16; | 223 | win->src_h = src_h >> 16; |
331 | 224 | ||
332 | /* note: this is done after this fxn returns.. but if we need | 225 | if (fxn) { |
333 | * to do a commit/update_scanout, etc before this returns we | 226 | /* omap_crtc should ensure that a new page flip |
334 | * need the current value. | 227 | * isn't permitted while there is one pending: |
335 | */ | 228 | */ |
229 | BUG_ON(omap_plane->apply_done_cb.fxn); | ||
230 | |||
231 | omap_plane->apply_done_cb.fxn = fxn; | ||
232 | omap_plane->apply_done_cb.arg = arg; | ||
233 | } | ||
234 | |||
336 | plane->fb = fb; | 235 | plane->fb = fb; |
337 | plane->crtc = crtc; | 236 | plane->crtc = crtc; |
338 | 237 | ||
339 | update_scanout(plane); | 238 | return apply(plane); |
340 | update_manager(plane); | ||
341 | |||
342 | return 0; | ||
343 | } | 239 | } |
344 | 240 | ||
345 | static int omap_plane_update(struct drm_plane *plane, | 241 | static int omap_plane_update(struct drm_plane *plane, |
@@ -349,9 +245,12 @@ static int omap_plane_update(struct drm_plane *plane, | |||
349 | uint32_t src_x, uint32_t src_y, | 245 | uint32_t src_x, uint32_t src_y, |
350 | uint32_t src_w, uint32_t src_h) | 246 | uint32_t src_w, uint32_t src_h) |
351 | { | 247 | { |
352 | omap_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, | 248 | struct omap_plane *omap_plane = to_omap_plane(plane); |
353 | src_x, src_y, src_w, src_h); | 249 | omap_plane->enabled = true; |
354 | return omap_plane_dpms(plane, DRM_MODE_DPMS_ON); | 250 | return omap_plane_mode_set(plane, crtc, fb, |
251 | crtc_x, crtc_y, crtc_w, crtc_h, | ||
252 | src_x, src_y, src_w, src_h, | ||
253 | NULL, NULL); | ||
355 | } | 254 | } |
356 | 255 | ||
357 | static int omap_plane_disable(struct drm_plane *plane) | 256 | static int omap_plane_disable(struct drm_plane *plane) |
@@ -364,48 +263,32 @@ static int omap_plane_disable(struct drm_plane *plane) | |||
364 | static void omap_plane_destroy(struct drm_plane *plane) | 263 | static void omap_plane_destroy(struct drm_plane *plane) |
365 | { | 264 | { |
366 | struct omap_plane *omap_plane = to_omap_plane(plane); | 265 | struct omap_plane *omap_plane = to_omap_plane(plane); |
367 | DBG("%s", omap_plane->ovl->name); | 266 | |
267 | DBG("%s", omap_plane->name); | ||
268 | |||
269 | omap_irq_unregister(plane->dev, &omap_plane->error_irq); | ||
270 | |||
368 | omap_plane_disable(plane); | 271 | omap_plane_disable(plane); |
369 | drm_plane_cleanup(plane); | 272 | drm_plane_cleanup(plane); |
370 | WARN_ON(omap_plane->pending_num_unpins + omap_plane->num_unpins > 0); | 273 | |
274 | WARN_ON(!kfifo_is_empty(&omap_plane->unpin_fifo)); | ||
371 | kfifo_free(&omap_plane->unpin_fifo); | 275 | kfifo_free(&omap_plane->unpin_fifo); |
276 | |||
372 | kfree(omap_plane); | 277 | kfree(omap_plane); |
373 | } | 278 | } |
374 | 279 | ||
375 | int omap_plane_dpms(struct drm_plane *plane, int mode) | 280 | int omap_plane_dpms(struct drm_plane *plane, int mode) |
376 | { | 281 | { |
377 | struct omap_plane *omap_plane = to_omap_plane(plane); | 282 | struct omap_plane *omap_plane = to_omap_plane(plane); |
378 | struct omap_overlay *ovl = omap_plane->ovl; | 283 | bool enabled = (mode == DRM_MODE_DPMS_ON); |
379 | int r; | 284 | int ret = 0; |
380 | 285 | ||
381 | DBG("%s: %d", omap_plane->ovl->name, mode); | 286 | if (enabled != omap_plane->enabled) { |
382 | 287 | omap_plane->enabled = enabled; | |
383 | if (mode == DRM_MODE_DPMS_ON) { | 288 | ret = apply(plane); |
384 | update_scanout(plane); | ||
385 | r = commit(plane); | ||
386 | if (!r) | ||
387 | r = ovl->enable(ovl); | ||
388 | } else { | ||
389 | struct omap_drm_private *priv = plane->dev->dev_private; | ||
390 | r = ovl->disable(ovl); | ||
391 | update_pin(plane, NULL); | ||
392 | queue_work(priv->wq, &omap_plane->work); | ||
393 | } | 289 | } |
394 | 290 | ||
395 | return r; | 291 | return ret; |
396 | } | ||
397 | |||
398 | void omap_plane_on_endwin(struct drm_plane *plane, | ||
399 | void (*fxn)(void *), void *arg) | ||
400 | { | ||
401 | struct omap_plane *omap_plane = to_omap_plane(plane); | ||
402 | |||
403 | mutex_lock(&omap_plane->unpin_mutex); | ||
404 | omap_plane->endwin.fxn = fxn; | ||
405 | omap_plane->endwin.arg = arg; | ||
406 | mutex_unlock(&omap_plane->unpin_mutex); | ||
407 | |||
408 | install_irq(plane); | ||
409 | } | 292 | } |
410 | 293 | ||
411 | /* helper to install properties which are common to planes and crtcs */ | 294 | /* helper to install properties which are common to planes and crtcs */ |
@@ -454,25 +337,13 @@ int omap_plane_set_property(struct drm_plane *plane, | |||
454 | int ret = -EINVAL; | 337 | int ret = -EINVAL; |
455 | 338 | ||
456 | if (property == priv->rotation_prop) { | 339 | if (property == priv->rotation_prop) { |
457 | struct omap_overlay *ovl = omap_plane->ovl; | 340 | DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val); |
458 | |||
459 | DBG("%s: rotation: %02x", ovl->name, (uint32_t)val); | ||
460 | omap_plane->win.rotation = val; | 341 | omap_plane->win.rotation = val; |
461 | 342 | ret = apply(plane); | |
462 | if (ovl->is_enabled(ovl)) | ||
463 | ret = omap_plane_dpms(plane, DRM_MODE_DPMS_ON); | ||
464 | else | ||
465 | ret = 0; | ||
466 | } else if (property == priv->zorder_prop) { | 343 | } else if (property == priv->zorder_prop) { |
467 | struct omap_overlay *ovl = omap_plane->ovl; | 344 | DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val); |
468 | |||
469 | DBG("%s: zorder: %d", ovl->name, (uint32_t)val); | ||
470 | omap_plane->info.zorder = val; | 345 | omap_plane->info.zorder = val; |
471 | 346 | ret = apply(plane); | |
472 | if (ovl->is_enabled(ovl)) | ||
473 | ret = omap_plane_dpms(plane, DRM_MODE_DPMS_ON); | ||
474 | else | ||
475 | ret = 0; | ||
476 | } | 347 | } |
477 | 348 | ||
478 | return ret; | 349 | return ret; |
@@ -485,20 +356,38 @@ static const struct drm_plane_funcs omap_plane_funcs = { | |||
485 | .set_property = omap_plane_set_property, | 356 | .set_property = omap_plane_set_property, |
486 | }; | 357 | }; |
487 | 358 | ||
359 | static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus) | ||
360 | { | ||
361 | struct omap_plane *omap_plane = | ||
362 | container_of(irq, struct omap_plane, error_irq); | ||
363 | DRM_ERROR("%s: errors: %08x\n", omap_plane->name, irqstatus); | ||
364 | } | ||
365 | |||
366 | static const char *plane_names[] = { | ||
367 | [OMAP_DSS_GFX] = "gfx", | ||
368 | [OMAP_DSS_VIDEO1] = "vid1", | ||
369 | [OMAP_DSS_VIDEO2] = "vid2", | ||
370 | [OMAP_DSS_VIDEO3] = "vid3", | ||
371 | }; | ||
372 | |||
373 | static const uint32_t error_irqs[] = { | ||
374 | [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW, | ||
375 | [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW, | ||
376 | [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW, | ||
377 | [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW, | ||
378 | }; | ||
379 | |||
488 | /* initialize plane */ | 380 | /* initialize plane */ |
489 | struct drm_plane *omap_plane_init(struct drm_device *dev, | 381 | struct drm_plane *omap_plane_init(struct drm_device *dev, |
490 | struct omap_overlay *ovl, unsigned int possible_crtcs, | 382 | int id, bool private_plane) |
491 | bool priv) | ||
492 | { | 383 | { |
384 | struct omap_drm_private *priv = dev->dev_private; | ||
493 | struct drm_plane *plane = NULL; | 385 | struct drm_plane *plane = NULL; |
494 | struct omap_plane *omap_plane; | 386 | struct omap_plane *omap_plane; |
387 | struct omap_overlay_info *info; | ||
495 | int ret; | 388 | int ret; |
496 | 389 | ||
497 | DBG("%s: possible_crtcs=%08x, priv=%d", ovl->name, | 390 | DBG("%s: priv=%d", plane_names[id], private_plane); |
498 | possible_crtcs, priv); | ||
499 | |||
500 | /* friendly reminder to update table for future hw: */ | ||
501 | WARN_ON(ovl->id >= ARRAY_SIZE(id2irq)); | ||
502 | 391 | ||
503 | omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); | 392 | omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); |
504 | if (!omap_plane) { | 393 | if (!omap_plane) { |
@@ -506,47 +395,50 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, | |||
506 | goto fail; | 395 | goto fail; |
507 | } | 396 | } |
508 | 397 | ||
509 | mutex_init(&omap_plane->unpin_mutex); | ||
510 | |||
511 | ret = kfifo_alloc(&omap_plane->unpin_fifo, 16, GFP_KERNEL); | 398 | ret = kfifo_alloc(&omap_plane->unpin_fifo, 16, GFP_KERNEL); |
512 | if (ret) { | 399 | if (ret) { |
513 | dev_err(dev->dev, "could not allocate unpin FIFO\n"); | 400 | dev_err(dev->dev, "could not allocate unpin FIFO\n"); |
514 | goto fail; | 401 | goto fail; |
515 | } | 402 | } |
516 | 403 | ||
517 | INIT_WORK(&omap_plane->work, unpin_worker); | ||
518 | |||
519 | omap_plane->nformats = omap_framebuffer_get_formats( | 404 | omap_plane->nformats = omap_framebuffer_get_formats( |
520 | omap_plane->formats, ARRAY_SIZE(omap_plane->formats), | 405 | omap_plane->formats, ARRAY_SIZE(omap_plane->formats), |
521 | ovl->supported_modes); | 406 | dss_feat_get_supported_color_modes(id)); |
522 | omap_plane->ovl = ovl; | 407 | omap_plane->id = id; |
408 | omap_plane->name = plane_names[id]; | ||
409 | |||
523 | plane = &omap_plane->base; | 410 | plane = &omap_plane->base; |
524 | 411 | ||
525 | drm_plane_init(dev, plane, possible_crtcs, &omap_plane_funcs, | 412 | omap_plane->apply.pre_apply = omap_plane_pre_apply; |
526 | omap_plane->formats, omap_plane->nformats, priv); | 413 | omap_plane->apply.post_apply = omap_plane_post_apply; |
414 | |||
415 | omap_plane->error_irq.irqmask = error_irqs[id]; | ||
416 | omap_plane->error_irq.irq = omap_plane_error_irq; | ||
417 | omap_irq_register(dev, &omap_plane->error_irq); | ||
418 | |||
419 | drm_plane_init(dev, plane, (1 << priv->num_crtcs) - 1, &omap_plane_funcs, | ||
420 | omap_plane->formats, omap_plane->nformats, private_plane); | ||
527 | 421 | ||
528 | omap_plane_install_properties(plane, &plane->base); | 422 | omap_plane_install_properties(plane, &plane->base); |
529 | 423 | ||
530 | /* get our starting configuration, set defaults for parameters | 424 | /* get our starting configuration, set defaults for parameters |
531 | * we don't currently use, etc: | 425 | * we don't currently use, etc: |
532 | */ | 426 | */ |
533 | ovl->get_overlay_info(ovl, &omap_plane->info); | 427 | info = &omap_plane->info; |
534 | omap_plane->info.rotation_type = OMAP_DSS_ROT_DMA; | 428 | info->rotation_type = OMAP_DSS_ROT_DMA; |
535 | omap_plane->info.rotation = OMAP_DSS_ROT_0; | 429 | info->rotation = OMAP_DSS_ROT_0; |
536 | omap_plane->info.global_alpha = 0xff; | 430 | info->global_alpha = 0xff; |
537 | omap_plane->info.mirror = 0; | 431 | info->mirror = 0; |
538 | 432 | ||
539 | /* Set defaults depending on whether we are a CRTC or overlay | 433 | /* Set defaults depending on whether we are a CRTC or overlay |
540 | * layer. | 434 | * layer. |
541 | * TODO add ioctl to give userspace an API to change this.. this | 435 | * TODO add ioctl to give userspace an API to change this.. this |
542 | * will come in a subsequent patch. | 436 | * will come in a subsequent patch. |
543 | */ | 437 | */ |
544 | if (priv) | 438 | if (private_plane) |
545 | omap_plane->info.zorder = 0; | 439 | omap_plane->info.zorder = 0; |
546 | else | 440 | else |
547 | omap_plane->info.zorder = ovl->id; | 441 | omap_plane->info.zorder = id; |
548 | |||
549 | update_manager(plane); | ||
550 | 442 | ||
551 | return plane; | 443 | return plane; |
552 | 444 | ||
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c index ae38475854b5..d10d75e8a33f 100644 --- a/drivers/staging/rtl8187se/r8180_core.c +++ b/drivers/staging/rtl8187se/r8180_core.c | |||
@@ -937,7 +937,8 @@ short alloc_rx_desc_ring(struct net_device *dev, u16 bufsize, int count) | |||
937 | 937 | ||
938 | dma_tmp = pci_map_single(pdev, buf, bufsize * sizeof(u8), | 938 | dma_tmp = pci_map_single(pdev, buf, bufsize * sizeof(u8), |
939 | PCI_DMA_FROMDEVICE); | 939 | PCI_DMA_FROMDEVICE); |
940 | 940 | if (pci_dma_mapping_error(pdev, dma_tmp)) | |
941 | return -1; | ||
941 | if (-1 == buffer_add(&(priv->rxbuffer), buf, dma_tmp, | 942 | if (-1 == buffer_add(&(priv->rxbuffer), buf, dma_tmp, |
942 | &(priv->rxbufferhead))) { | 943 | &(priv->rxbufferhead))) { |
943 | DMESGE("Unable to allocate mem RX buf"); | 944 | DMESGE("Unable to allocate mem RX buf"); |
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 808aab6fa5ef..a9d78e9651c6 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | |||
@@ -1183,6 +1183,8 @@ void rtl8192_tx_fill_desc(struct net_device *dev, struct tx_desc *pdesc, | |||
1183 | pTxFwInfo->TxRate, | 1183 | pTxFwInfo->TxRate, |
1184 | cb_desc); | 1184 | cb_desc); |
1185 | 1185 | ||
1186 | if (pci_dma_mapping_error(priv->pdev, mapping)) | ||
1187 | RT_TRACE(COMP_ERR, "DMA Mapping error\n");; | ||
1186 | if (cb_desc->bAMPDUEnable) { | 1188 | if (cb_desc->bAMPDUEnable) { |
1187 | pTxFwInfo->AllowAggregation = 1; | 1189 | pTxFwInfo->AllowAggregation = 1; |
1188 | pTxFwInfo->RxMF = cb_desc->ampdu_factor; | 1190 | pTxFwInfo->RxMF = cb_desc->ampdu_factor; |
@@ -1280,6 +1282,8 @@ void rtl8192_tx_fill_cmd_desc(struct net_device *dev, | |||
1280 | dma_addr_t mapping = pci_map_single(priv->pdev, skb->data, skb->len, | 1282 | dma_addr_t mapping = pci_map_single(priv->pdev, skb->data, skb->len, |
1281 | PCI_DMA_TODEVICE); | 1283 | PCI_DMA_TODEVICE); |
1282 | 1284 | ||
1285 | if (pci_dma_mapping_error(priv->pdev, mapping)) | ||
1286 | RT_TRACE(COMP_ERR, "DMA Mapping error\n");; | ||
1283 | memset(entry, 0, 12); | 1287 | memset(entry, 0, 12); |
1284 | entry->LINIP = cb_desc->bLastIniPkt; | 1288 | entry->LINIP = cb_desc->bLastIniPkt; |
1285 | entry->FirstSeg = 1; | 1289 | entry->FirstSeg = 1; |
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 1a70f324552f..4ebf99b30975 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c | |||
@@ -2104,7 +2104,10 @@ static short rtl8192_alloc_rx_desc_ring(struct net_device *dev) | |||
2104 | skb_tail_pointer_rsl(skb), | 2104 | skb_tail_pointer_rsl(skb), |
2105 | priv->rxbuffersize, | 2105 | priv->rxbuffersize, |
2106 | PCI_DMA_FROMDEVICE); | 2106 | PCI_DMA_FROMDEVICE); |
2107 | 2107 | if (pci_dma_mapping_error(priv->pdev, *mapping)) { | |
2108 | dev_kfree_skb_any(skb); | ||
2109 | return -1; | ||
2110 | } | ||
2108 | entry->BufferAddress = cpu_to_le32(*mapping); | 2111 | entry->BufferAddress = cpu_to_le32(*mapping); |
2109 | 2112 | ||
2110 | entry->Length = priv->rxbuffersize; | 2113 | entry->Length = priv->rxbuffersize; |
@@ -2397,7 +2400,11 @@ static void rtl8192_rx_normal(struct net_device *dev) | |||
2397 | skb_tail_pointer_rsl(skb), | 2400 | skb_tail_pointer_rsl(skb), |
2398 | priv->rxbuffersize, | 2401 | priv->rxbuffersize, |
2399 | PCI_DMA_FROMDEVICE); | 2402 | PCI_DMA_FROMDEVICE); |
2400 | 2403 | if (pci_dma_mapping_error(priv->pdev, | |
2404 | *((dma_addr_t *)skb->cb))) { | ||
2405 | dev_kfree_skb_any(skb); | ||
2406 | return; | ||
2407 | } | ||
2401 | } | 2408 | } |
2402 | done: | 2409 | done: |
2403 | pdesc->BufferAddress = cpu_to_le32(*((dma_addr_t *)skb->cb)); | 2410 | pdesc->BufferAddress = cpu_to_le32(*((dma_addr_t *)skb->cb)); |
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c index 6b73843e580a..a96cd06d69dd 100644 --- a/drivers/staging/rtl8712/usb_intf.c +++ b/drivers/staging/rtl8712/usb_intf.c | |||
@@ -63,6 +63,8 @@ static struct usb_device_id rtl871x_usb_id_tbl[] = { | |||
63 | {USB_DEVICE(0x0B05, 0x1791)}, /* 11n mode disable */ | 63 | {USB_DEVICE(0x0B05, 0x1791)}, /* 11n mode disable */ |
64 | /* Belkin */ | 64 | /* Belkin */ |
65 | {USB_DEVICE(0x050D, 0x945A)}, | 65 | {USB_DEVICE(0x050D, 0x945A)}, |
66 | /* ISY IWL - Belkin clone */ | ||
67 | {USB_DEVICE(0x050D, 0x11F1)}, | ||
66 | /* Corega */ | 68 | /* Corega */ |
67 | {USB_DEVICE(0x07AA, 0x0047)}, | 69 | {USB_DEVICE(0x07AA, 0x0047)}, |
68 | /* D-Link */ | 70 | /* D-Link */ |
diff --git a/drivers/staging/sb105x/Kconfig b/drivers/staging/sb105x/Kconfig index ac87c5e38dee..1facad625554 100644 --- a/drivers/staging/sb105x/Kconfig +++ b/drivers/staging/sb105x/Kconfig | |||
@@ -2,6 +2,7 @@ config SB105X | |||
2 | tristate "SystemBase PCI Multiport UART" | 2 | tristate "SystemBase PCI Multiport UART" |
3 | select SERIAL_CORE | 3 | select SERIAL_CORE |
4 | depends on PCI | 4 | depends on PCI |
5 | depends on X86 | ||
5 | help | 6 | help |
6 | A driver for the SystemBase Multi-2/PCI serial card | 7 | A driver for the SystemBase Multi-2/PCI serial card |
7 | 8 | ||
diff --git a/drivers/staging/sb105x/sb_pci_mp.c b/drivers/staging/sb105x/sb_pci_mp.c index edb2a85b9d52..131afd0c460c 100644 --- a/drivers/staging/sb105x/sb_pci_mp.c +++ b/drivers/staging/sb105x/sb_pci_mp.c | |||
@@ -3054,6 +3054,7 @@ static int init_mp_dev(struct pci_dev *pcidev, mppcibrd_t brd) | |||
3054 | sbdev->nr_ports = ((portnum_hex/16)*10) + (portnum_hex % 16); | 3054 | sbdev->nr_ports = ((portnum_hex/16)*10) + (portnum_hex % 16); |
3055 | } | 3055 | } |
3056 | break; | 3056 | break; |
3057 | #ifdef CONFIG_PARPORT | ||
3057 | case PCI_DEVICE_ID_MP2S1P : | 3058 | case PCI_DEVICE_ID_MP2S1P : |
3058 | sbdev->nr_ports = 2; | 3059 | sbdev->nr_ports = 2; |
3059 | 3060 | ||
@@ -3073,6 +3074,7 @@ static int init_mp_dev(struct pci_dev *pcidev, mppcibrd_t brd) | |||
3073 | /* add PC compatible parallel port */ | 3074 | /* add PC compatible parallel port */ |
3074 | parport_pc_probe_port(pcidev->resource[2].start, pcidev->resource[3].start, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &pcidev->dev, 0); | 3075 | parport_pc_probe_port(pcidev->resource[2].start, pcidev->resource[3].start, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &pcidev->dev, 0); |
3075 | break; | 3076 | break; |
3077 | #endif | ||
3076 | } | 3078 | } |
3077 | 3079 | ||
3078 | ret = request_region(sbdev->uart_access_addr, (8*sbdev->nr_ports), sbdev->name); | 3080 | ret = request_region(sbdev->uart_access_addr, (8*sbdev->nr_ports), sbdev->name); |
diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c index df9533798095..7616f058a00b 100644 --- a/drivers/staging/speakup/synth.c +++ b/drivers/staging/speakup/synth.c | |||
@@ -342,7 +342,7 @@ int synth_init(char *synth_name) | |||
342 | 342 | ||
343 | mutex_lock(&spk_mutex); | 343 | mutex_lock(&spk_mutex); |
344 | /* First, check if we already have it loaded. */ | 344 | /* First, check if we already have it loaded. */ |
345 | for (i = 0; synths[i] != NULL && i < MAXSYNTHS; i++) | 345 | for (i = 0; i < MAXSYNTHS && synths[i] != NULL; i++) |
346 | if (strcmp(synths[i]->name, synth_name) == 0) | 346 | if (strcmp(synths[i]->name, synth_name) == 0) |
347 | synth = synths[i]; | 347 | synth = synths[i]; |
348 | 348 | ||
@@ -423,7 +423,7 @@ int synth_add(struct spk_synth *in_synth) | |||
423 | int i; | 423 | int i; |
424 | int status = 0; | 424 | int status = 0; |
425 | mutex_lock(&spk_mutex); | 425 | mutex_lock(&spk_mutex); |
426 | for (i = 0; synths[i] != NULL && i < MAXSYNTHS; i++) | 426 | for (i = 0; i < MAXSYNTHS && synths[i] != NULL; i++) |
427 | /* synth_remove() is responsible for rotating the array down */ | 427 | /* synth_remove() is responsible for rotating the array down */ |
428 | if (in_synth == synths[i]) { | 428 | if (in_synth == synths[i]) { |
429 | mutex_unlock(&spk_mutex); | 429 | mutex_unlock(&spk_mutex); |
diff --git a/drivers/staging/tidspbridge/core/_tiomap.h b/drivers/staging/tidspbridge/core/_tiomap.h index 543a127c7d4d..b783bfa59b1c 100644 --- a/drivers/staging/tidspbridge/core/_tiomap.h +++ b/drivers/staging/tidspbridge/core/_tiomap.h | |||
@@ -31,7 +31,7 @@ | |||
31 | * driver should read or write to PRM/CM registers directly; they | 31 | * driver should read or write to PRM/CM registers directly; they |
32 | * should rely on OMAP core code to do this. | 32 | * should rely on OMAP core code to do this. |
33 | */ | 33 | */ |
34 | #include <mach-omap2/cm2xxx_3xxx.h> | 34 | #include <mach-omap2/cm3xxx.h> |
35 | #include <mach-omap2/prm-regbits-34xx.h> | 35 | #include <mach-omap2/prm-regbits-34xx.h> |
36 | #include <mach-omap2/cm-regbits-34xx.h> | 36 | #include <mach-omap2/cm-regbits-34xx.h> |
37 | #include <dspbridge/devdefs.h> | 37 | #include <dspbridge/devdefs.h> |
diff --git a/drivers/staging/tidspbridge/core/dsp-clock.c b/drivers/staging/tidspbridge/core/dsp-clock.c index b647207928b1..2f084e181d39 100644 --- a/drivers/staging/tidspbridge/core/dsp-clock.c +++ b/drivers/staging/tidspbridge/core/dsp-clock.c | |||
@@ -121,9 +121,13 @@ void dsp_clk_exit(void) | |||
121 | for (i = 0; i < DM_TIMER_CLOCKS; i++) | 121 | for (i = 0; i < DM_TIMER_CLOCKS; i++) |
122 | omap_dm_timer_free(timer[i]); | 122 | omap_dm_timer_free(timer[i]); |
123 | 123 | ||
124 | clk_unprepare(iva2_clk); | ||
124 | clk_put(iva2_clk); | 125 | clk_put(iva2_clk); |
126 | clk_unprepare(ssi.sst_fck); | ||
125 | clk_put(ssi.sst_fck); | 127 | clk_put(ssi.sst_fck); |
128 | clk_unprepare(ssi.ssr_fck); | ||
126 | clk_put(ssi.ssr_fck); | 129 | clk_put(ssi.ssr_fck); |
130 | clk_unprepare(ssi.ick); | ||
127 | clk_put(ssi.ick); | 131 | clk_put(ssi.ick); |
128 | } | 132 | } |
129 | 133 | ||
@@ -145,14 +149,21 @@ void dsp_clk_init(void) | |||
145 | iva2_clk = clk_get(&dspbridge_device.dev, "iva2_ck"); | 149 | iva2_clk = clk_get(&dspbridge_device.dev, "iva2_ck"); |
146 | if (IS_ERR(iva2_clk)) | 150 | if (IS_ERR(iva2_clk)) |
147 | dev_err(bridge, "failed to get iva2 clock %p\n", iva2_clk); | 151 | dev_err(bridge, "failed to get iva2 clock %p\n", iva2_clk); |
152 | else | ||
153 | clk_prepare(iva2_clk); | ||
148 | 154 | ||
149 | ssi.sst_fck = clk_get(&dspbridge_device.dev, "ssi_sst_fck"); | 155 | ssi.sst_fck = clk_get(&dspbridge_device.dev, "ssi_sst_fck"); |
150 | ssi.ssr_fck = clk_get(&dspbridge_device.dev, "ssi_ssr_fck"); | 156 | ssi.ssr_fck = clk_get(&dspbridge_device.dev, "ssi_ssr_fck"); |
151 | ssi.ick = clk_get(&dspbridge_device.dev, "ssi_ick"); | 157 | ssi.ick = clk_get(&dspbridge_device.dev, "ssi_ick"); |
152 | 158 | ||
153 | if (IS_ERR(ssi.sst_fck) || IS_ERR(ssi.ssr_fck) || IS_ERR(ssi.ick)) | 159 | if (IS_ERR(ssi.sst_fck) || IS_ERR(ssi.ssr_fck) || IS_ERR(ssi.ick)) { |
154 | dev_err(bridge, "failed to get ssi: sst %p, ssr %p, ick %p\n", | 160 | dev_err(bridge, "failed to get ssi: sst %p, ssr %p, ick %p\n", |
155 | ssi.sst_fck, ssi.ssr_fck, ssi.ick); | 161 | ssi.sst_fck, ssi.ssr_fck, ssi.ick); |
162 | } else { | ||
163 | clk_prepare(ssi.sst_fck); | ||
164 | clk_prepare(ssi.ssr_fck); | ||
165 | clk_prepare(ssi.ick); | ||
166 | } | ||
156 | } | 167 | } |
157 | 168 | ||
158 | /** | 169 | /** |
diff --git a/drivers/staging/tidspbridge/core/wdt.c b/drivers/staging/tidspbridge/core/wdt.c index 1dce36fb828f..7ff0e6c98039 100644 --- a/drivers/staging/tidspbridge/core/wdt.c +++ b/drivers/staging/tidspbridge/core/wdt.c | |||
@@ -63,11 +63,15 @@ int dsp_wdt_init(void) | |||
63 | dsp_wdt.fclk = clk_get(NULL, "wdt3_fck"); | 63 | dsp_wdt.fclk = clk_get(NULL, "wdt3_fck"); |
64 | 64 | ||
65 | if (!IS_ERR(dsp_wdt.fclk)) { | 65 | if (!IS_ERR(dsp_wdt.fclk)) { |
66 | clk_prepare(dsp_wdt.fclk); | ||
67 | |||
66 | dsp_wdt.iclk = clk_get(NULL, "wdt3_ick"); | 68 | dsp_wdt.iclk = clk_get(NULL, "wdt3_ick"); |
67 | if (IS_ERR(dsp_wdt.iclk)) { | 69 | if (IS_ERR(dsp_wdt.iclk)) { |
68 | clk_put(dsp_wdt.fclk); | 70 | clk_put(dsp_wdt.fclk); |
69 | dsp_wdt.fclk = NULL; | 71 | dsp_wdt.fclk = NULL; |
70 | ret = -EFAULT; | 72 | ret = -EFAULT; |
73 | } else { | ||
74 | clk_prepare(dsp_wdt.iclk); | ||
71 | } | 75 | } |
72 | } else | 76 | } else |
73 | ret = -EFAULT; | 77 | ret = -EFAULT; |
@@ -95,10 +99,14 @@ void dsp_wdt_exit(void) | |||
95 | free_irq(INT_34XX_WDT3_IRQ, &dsp_wdt); | 99 | free_irq(INT_34XX_WDT3_IRQ, &dsp_wdt); |
96 | tasklet_kill(&dsp_wdt.wdt3_tasklet); | 100 | tasklet_kill(&dsp_wdt.wdt3_tasklet); |
97 | 101 | ||
98 | if (dsp_wdt.fclk) | 102 | if (dsp_wdt.fclk) { |
103 | clk_unprepare(dsp_wdt.fclk); | ||
99 | clk_put(dsp_wdt.fclk); | 104 | clk_put(dsp_wdt.fclk); |
100 | if (dsp_wdt.iclk) | 105 | } |
106 | if (dsp_wdt.iclk) { | ||
107 | clk_unprepare(dsp_wdt.iclk); | ||
101 | clk_put(dsp_wdt.iclk); | 108 | clk_put(dsp_wdt.iclk); |
109 | } | ||
102 | 110 | ||
103 | dsp_wdt.fclk = NULL; | 111 | dsp_wdt.fclk = NULL; |
104 | dsp_wdt.iclk = NULL; | 112 | dsp_wdt.iclk = NULL; |
diff --git a/drivers/staging/vme/devices/vme_pio2_core.c b/drivers/staging/vme/devices/vme_pio2_core.c index 0331178ca3b3..bf73ba26e88a 100644 --- a/drivers/staging/vme/devices/vme_pio2_core.c +++ b/drivers/staging/vme/devices/vme_pio2_core.c | |||
@@ -162,11 +162,9 @@ static struct vme_driver pio2_driver = { | |||
162 | 162 | ||
163 | static int __init pio2_init(void) | 163 | static int __init pio2_init(void) |
164 | { | 164 | { |
165 | int retval = 0; | ||
166 | |||
167 | if (bus_num == 0) { | 165 | if (bus_num == 0) { |
168 | pr_err("No cards, skipping registration\n"); | 166 | pr_err("No cards, skipping registration\n"); |
169 | goto err_nocard; | 167 | return -ENODEV; |
170 | } | 168 | } |
171 | 169 | ||
172 | if (bus_num > PIO2_CARDS_MAX) { | 170 | if (bus_num > PIO2_CARDS_MAX) { |
@@ -176,15 +174,7 @@ static int __init pio2_init(void) | |||
176 | } | 174 | } |
177 | 175 | ||
178 | /* Register the PIO2 driver */ | 176 | /* Register the PIO2 driver */ |
179 | retval = vme_register_driver(&pio2_driver, bus_num); | 177 | return vme_register_driver(&pio2_driver, bus_num); |
180 | if (retval != 0) | ||
181 | goto err_reg; | ||
182 | |||
183 | return retval; | ||
184 | |||
185 | err_reg: | ||
186 | err_nocard: | ||
187 | return retval; | ||
188 | } | 178 | } |
189 | 179 | ||
190 | static int pio2_match(struct vme_dev *vdev) | 180 | static int pio2_match(struct vme_dev *vdev) |
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c index 18c06a59c091..1d31eab19d16 100644 --- a/drivers/staging/wlan-ng/cfg80211.c +++ b/drivers/staging/wlan-ng/cfg80211.c | |||
@@ -638,8 +638,8 @@ int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev) | |||
638 | } | 638 | } |
639 | 639 | ||
640 | 640 | ||
641 | int prism2_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type, | 641 | int prism2_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, |
642 | int mbm) | 642 | enum nl80211_tx_power_setting type, int mbm) |
643 | { | 643 | { |
644 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); | 644 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); |
645 | wlandevice_t *wlandev = priv->wlandev; | 645 | wlandevice_t *wlandev = priv->wlandev; |
@@ -665,7 +665,8 @@ exit: | |||
665 | return err; | 665 | return err; |
666 | } | 666 | } |
667 | 667 | ||
668 | int prism2_get_tx_power(struct wiphy *wiphy, int *dbm) | 668 | int prism2_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, |
669 | int *dbm) | ||
669 | { | 670 | { |
670 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); | 671 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); |
671 | wlandevice_t *wlandev = priv->wlandev; | 672 | wlandevice_t *wlandev = priv->wlandev; |
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c index fb4a7c94aed3..f2a73bd739fb 100644 --- a/drivers/staging/zram/zram_drv.c +++ b/drivers/staging/zram/zram_drv.c | |||
@@ -265,7 +265,7 @@ out_cleanup: | |||
265 | static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, | 265 | static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, |
266 | int offset) | 266 | int offset) |
267 | { | 267 | { |
268 | int ret; | 268 | int ret = 0; |
269 | size_t clen; | 269 | size_t clen; |
270 | unsigned long handle; | 270 | unsigned long handle; |
271 | struct page *page; | 271 | struct page *page; |
@@ -286,10 +286,8 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, | |||
286 | goto out; | 286 | goto out; |
287 | } | 287 | } |
288 | ret = zram_decompress_page(zram, uncmem, index); | 288 | ret = zram_decompress_page(zram, uncmem, index); |
289 | if (ret) { | 289 | if (ret) |
290 | kfree(uncmem); | ||
291 | goto out; | 290 | goto out; |
292 | } | ||
293 | } | 291 | } |
294 | 292 | ||
295 | /* | 293 | /* |
@@ -302,16 +300,18 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, | |||
302 | 300 | ||
303 | user_mem = kmap_atomic(page); | 301 | user_mem = kmap_atomic(page); |
304 | 302 | ||
305 | if (is_partial_io(bvec)) | 303 | if (is_partial_io(bvec)) { |
306 | memcpy(uncmem + offset, user_mem + bvec->bv_offset, | 304 | memcpy(uncmem + offset, user_mem + bvec->bv_offset, |
307 | bvec->bv_len); | 305 | bvec->bv_len); |
308 | else | 306 | kunmap_atomic(user_mem); |
307 | user_mem = NULL; | ||
308 | } else { | ||
309 | uncmem = user_mem; | 309 | uncmem = user_mem; |
310 | } | ||
310 | 311 | ||
311 | if (page_zero_filled(uncmem)) { | 312 | if (page_zero_filled(uncmem)) { |
312 | kunmap_atomic(user_mem); | 313 | if (!is_partial_io(bvec)) |
313 | if (is_partial_io(bvec)) | 314 | kunmap_atomic(user_mem); |
314 | kfree(uncmem); | ||
315 | zram_stat_inc(&zram->stats.pages_zero); | 315 | zram_stat_inc(&zram->stats.pages_zero); |
316 | zram_set_flag(zram, index, ZRAM_ZERO); | 316 | zram_set_flag(zram, index, ZRAM_ZERO); |
317 | ret = 0; | 317 | ret = 0; |
@@ -321,9 +321,11 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, | |||
321 | ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen, | 321 | ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen, |
322 | zram->compress_workmem); | 322 | zram->compress_workmem); |
323 | 323 | ||
324 | kunmap_atomic(user_mem); | 324 | if (!is_partial_io(bvec)) { |
325 | if (is_partial_io(bvec)) | 325 | kunmap_atomic(user_mem); |
326 | kfree(uncmem); | 326 | user_mem = NULL; |
327 | uncmem = NULL; | ||
328 | } | ||
327 | 329 | ||
328 | if (unlikely(ret != LZO_E_OK)) { | 330 | if (unlikely(ret != LZO_E_OK)) { |
329 | pr_err("Compression failed! err=%d\n", ret); | 331 | pr_err("Compression failed! err=%d\n", ret); |
@@ -332,8 +334,10 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, | |||
332 | 334 | ||
333 | if (unlikely(clen > max_zpage_size)) { | 335 | if (unlikely(clen > max_zpage_size)) { |
334 | zram_stat_inc(&zram->stats.bad_compress); | 336 | zram_stat_inc(&zram->stats.bad_compress); |
335 | src = uncmem; | ||
336 | clen = PAGE_SIZE; | 337 | clen = PAGE_SIZE; |
338 | src = NULL; | ||
339 | if (is_partial_io(bvec)) | ||
340 | src = uncmem; | ||
337 | } | 341 | } |
338 | 342 | ||
339 | handle = zs_malloc(zram->mem_pool, clen); | 343 | handle = zs_malloc(zram->mem_pool, clen); |
@@ -345,7 +349,11 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, | |||
345 | } | 349 | } |
346 | cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_WO); | 350 | cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_WO); |
347 | 351 | ||
352 | if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) | ||
353 | src = kmap_atomic(page); | ||
348 | memcpy(cmem, src, clen); | 354 | memcpy(cmem, src, clen); |
355 | if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) | ||
356 | kunmap_atomic(src); | ||
349 | 357 | ||
350 | zs_unmap_object(zram->mem_pool, handle); | 358 | zs_unmap_object(zram->mem_pool, handle); |
351 | 359 | ||
@@ -358,9 +366,10 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, | |||
358 | if (clen <= PAGE_SIZE / 2) | 366 | if (clen <= PAGE_SIZE / 2) |
359 | zram_stat_inc(&zram->stats.good_compress); | 367 | zram_stat_inc(&zram->stats.good_compress); |
360 | 368 | ||
361 | return 0; | ||
362 | |||
363 | out: | 369 | out: |
370 | if (is_partial_io(bvec)) | ||
371 | kfree(uncmem); | ||
372 | |||
364 | if (ret) | 373 | if (ret) |
365 | zram_stat64_inc(zram, &zram->stats.failed_writes); | 374 | zram_stat64_inc(zram, &zram->stats.failed_writes); |
366 | return ret; | 375 | return ret; |
diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c index 9ac4c151eae4..ba6091bf93fc 100644 --- a/drivers/target/iscsi/iscsi_target_erl2.c +++ b/drivers/target/iscsi/iscsi_target_erl2.c | |||
@@ -372,7 +372,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn) | |||
372 | * made generic here. | 372 | * made generic here. |
373 | */ | 373 | */ |
374 | if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd && | 374 | if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd && |
375 | iscsi_sna_gte(cmd->stat_sn, conn->sess->exp_cmd_sn)) { | 375 | iscsi_sna_gte(cmd->cmd_sn, conn->sess->exp_cmd_sn)) { |
376 | list_del(&cmd->i_conn_node); | 376 | list_del(&cmd->i_conn_node); |
377 | spin_unlock_bh(&conn->cmd_lock); | 377 | spin_unlock_bh(&conn->cmd_lock); |
378 | iscsit_free_cmd(cmd); | 378 | iscsit_free_cmd(cmd); |
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 85140f7dde1e..7d4ec02e29a9 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c | |||
@@ -212,7 +212,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) | |||
212 | struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *l_tg_pt_gp_mem; | 212 | struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *l_tg_pt_gp_mem; |
213 | unsigned char *buf; | 213 | unsigned char *buf; |
214 | unsigned char *ptr; | 214 | unsigned char *ptr; |
215 | sense_reason_t rc; | 215 | sense_reason_t rc = TCM_NO_SENSE; |
216 | u32 len = 4; /* Skip over RESERVED area in header */ | 216 | u32 len = 4; /* Skip over RESERVED area in header */ |
217 | int alua_access_state, primary = 0; | 217 | int alua_access_state, primary = 0; |
218 | u16 tg_pt_id, rtpi; | 218 | u16 tg_pt_id, rtpi; |
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index e35dbf85841f..8e0290b38e43 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c | |||
@@ -2053,7 +2053,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, | |||
2053 | /* Used for APTPL metadata w/ UNREGISTER */ | 2053 | /* Used for APTPL metadata w/ UNREGISTER */ |
2054 | unsigned char *pr_aptpl_buf = NULL; | 2054 | unsigned char *pr_aptpl_buf = NULL; |
2055 | unsigned char isid_buf[PR_REG_ISID_LEN], *isid_ptr = NULL; | 2055 | unsigned char isid_buf[PR_REG_ISID_LEN], *isid_ptr = NULL; |
2056 | sense_reason_t ret; | 2056 | sense_reason_t ret = TCM_NO_SENSE; |
2057 | int pr_holder = 0, type; | 2057 | int pr_holder = 0, type; |
2058 | 2058 | ||
2059 | if (!se_sess || !se_lun) { | 2059 | if (!se_sess || !se_lun) { |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index c23c76ccef65..bd587b70661a 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -541,9 +541,6 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd) | |||
541 | 541 | ||
542 | void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) | 542 | void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) |
543 | { | 543 | { |
544 | if (!(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) | ||
545 | transport_lun_remove_cmd(cmd); | ||
546 | |||
547 | if (transport_cmd_check_stop_to_fabric(cmd)) | 544 | if (transport_cmd_check_stop_to_fabric(cmd)) |
548 | return; | 545 | return; |
549 | if (remove) | 546 | if (remove) |
@@ -1396,6 +1393,8 @@ static void target_complete_tmr_failure(struct work_struct *work) | |||
1396 | 1393 | ||
1397 | se_cmd->se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST; | 1394 | se_cmd->se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST; |
1398 | se_cmd->se_tfo->queue_tm_rsp(se_cmd); | 1395 | se_cmd->se_tfo->queue_tm_rsp(se_cmd); |
1396 | |||
1397 | transport_cmd_check_stop_to_fabric(se_cmd); | ||
1399 | } | 1398 | } |
1400 | 1399 | ||
1401 | /** | 1400 | /** |
@@ -1688,6 +1687,7 @@ void target_execute_cmd(struct se_cmd *cmd) | |||
1688 | } | 1687 | } |
1689 | 1688 | ||
1690 | cmd->t_state = TRANSPORT_PROCESSING; | 1689 | cmd->t_state = TRANSPORT_PROCESSING; |
1690 | cmd->transport_state |= CMD_T_ACTIVE; | ||
1691 | spin_unlock_irq(&cmd->t_state_lock); | 1691 | spin_unlock_irq(&cmd->t_state_lock); |
1692 | 1692 | ||
1693 | if (!target_handle_task_attr(cmd)) | 1693 | if (!target_handle_task_attr(cmd)) |
@@ -2597,6 +2597,16 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, | |||
2597 | * SENSE KEY values from include/scsi/scsi.h | 2597 | * SENSE KEY values from include/scsi/scsi.h |
2598 | */ | 2598 | */ |
2599 | switch (reason) { | 2599 | switch (reason) { |
2600 | case TCM_NO_SENSE: | ||
2601 | /* CURRENT ERROR */ | ||
2602 | buffer[0] = 0x70; | ||
2603 | buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; | ||
2604 | /* Not Ready */ | ||
2605 | buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY; | ||
2606 | /* NO ADDITIONAL SENSE INFORMATION */ | ||
2607 | buffer[SPC_ASC_KEY_OFFSET] = 0; | ||
2608 | buffer[SPC_ASCQ_KEY_OFFSET] = 0; | ||
2609 | break; | ||
2600 | case TCM_NON_EXISTENT_LUN: | 2610 | case TCM_NON_EXISTENT_LUN: |
2601 | /* CURRENT ERROR */ | 2611 | /* CURRENT ERROR */ |
2602 | buffer[0] = 0x70; | 2612 | buffer[0] = 0x70; |
@@ -2743,7 +2753,7 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, | |||
2743 | /* ILLEGAL REQUEST */ | 2753 | /* ILLEGAL REQUEST */ |
2744 | buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; | 2754 | buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; |
2745 | /* LOGICAL UNIT COMMUNICATION FAILURE */ | 2755 | /* LOGICAL UNIT COMMUNICATION FAILURE */ |
2746 | buffer[SPC_ASC_KEY_OFFSET] = 0x80; | 2756 | buffer[SPC_ASC_KEY_OFFSET] = 0x08; |
2747 | break; | 2757 | break; |
2748 | } | 2758 | } |
2749 | /* | 2759 | /* |
@@ -2804,6 +2814,8 @@ void transport_send_task_abort(struct se_cmd *cmd) | |||
2804 | } | 2814 | } |
2805 | cmd->scsi_status = SAM_STAT_TASK_ABORTED; | 2815 | cmd->scsi_status = SAM_STAT_TASK_ABORTED; |
2806 | 2816 | ||
2817 | transport_lun_remove_cmd(cmd); | ||
2818 | |||
2807 | pr_debug("Setting SAM_STAT_TASK_ABORTED status for CDB: 0x%02x," | 2819 | pr_debug("Setting SAM_STAT_TASK_ABORTED status for CDB: 0x%02x," |
2808 | " ITT: 0x%08x\n", cmd->t_task_cdb[0], | 2820 | " ITT: 0x%08x\n", cmd->t_task_cdb[0], |
2809 | cmd->se_tfo->get_task_tag(cmd)); | 2821 | cmd->se_tfo->get_task_tag(cmd)); |
diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index 12d6fa21e5e1..6659dd36e806 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c | |||
@@ -355,11 +355,11 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len, | |||
355 | 355 | ||
356 | tport = ft_tport_create(rdata->local_port); | 356 | tport = ft_tport_create(rdata->local_port); |
357 | if (!tport) | 357 | if (!tport) |
358 | return 0; /* not a target for this local port */ | 358 | goto not_target; /* not a target for this local port */ |
359 | 359 | ||
360 | acl = ft_acl_get(tport->tpg, rdata); | 360 | acl = ft_acl_get(tport->tpg, rdata); |
361 | if (!acl) | 361 | if (!acl) |
362 | return 0; | 362 | goto not_target; /* no target for this remote */ |
363 | 363 | ||
364 | if (!rspp) | 364 | if (!rspp) |
365 | goto fill; | 365 | goto fill; |
@@ -396,12 +396,18 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len, | |||
396 | 396 | ||
397 | /* | 397 | /* |
398 | * OR in our service parameters with other provider (initiator), if any. | 398 | * OR in our service parameters with other provider (initiator), if any. |
399 | * TBD XXX - indicate RETRY capability? | ||
400 | */ | 399 | */ |
401 | fill: | 400 | fill: |
402 | fcp_parm = ntohl(spp->spp_params); | 401 | fcp_parm = ntohl(spp->spp_params); |
402 | fcp_parm &= ~FCP_SPPF_RETRY; | ||
403 | spp->spp_params = htonl(fcp_parm | FCP_SPPF_TARG_FCN); | 403 | spp->spp_params = htonl(fcp_parm | FCP_SPPF_TARG_FCN); |
404 | return FC_SPP_RESP_ACK; | 404 | return FC_SPP_RESP_ACK; |
405 | |||
406 | not_target: | ||
407 | fcp_parm = ntohl(spp->spp_params); | ||
408 | fcp_parm &= ~FCP_SPPF_TARG_FCN; | ||
409 | spp->spp_params = htonl(fcp_parm); | ||
410 | return 0; | ||
405 | } | 411 | } |
406 | 412 | ||
407 | /** | 413 | /** |
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 4c90b510d016..640ae6c6d2d2 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig | |||
@@ -37,6 +37,7 @@ config USB_ARCH_HAS_EHCI | |||
37 | default y if ARCH_W90X900 | 37 | default y if ARCH_W90X900 |
38 | default y if ARCH_AT91 | 38 | default y if ARCH_AT91 |
39 | default y if ARCH_MXC | 39 | default y if ARCH_MXC |
40 | default y if ARCH_MXS | ||
40 | default y if ARCH_OMAP3 | 41 | default y if ARCH_OMAP3 |
41 | default y if ARCH_CNS3XXX | 42 | default y if ARCH_CNS3XXX |
42 | default y if ARCH_VT8500 | 43 | default y if ARCH_VT8500 |
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index caecad9213f5..8e9d31277c43 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c | |||
@@ -70,6 +70,9 @@ static int host_start(struct ci13xxx *ci) | |||
70 | else | 70 | else |
71 | ci->hcd = hcd; | 71 | ci->hcd = hcd; |
72 | 72 | ||
73 | if (ci->platdata->flags & CI13XXX_DISABLE_STREAMING) | ||
74 | hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); | ||
75 | |||
73 | return ret; | 76 | return ret; |
74 | } | 77 | } |
75 | 78 | ||
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 8d809a811e16..2d92cce260d7 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
@@ -1602,6 +1602,9 @@ static const struct usb_device_id acm_ids[] = { | |||
1602 | { USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */ | 1602 | { USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */ |
1603 | .driver_info = NO_UNION_NORMAL, | 1603 | .driver_info = NO_UNION_NORMAL, |
1604 | }, | 1604 | }, |
1605 | { USB_DEVICE(0x05f9, 0x4002), /* PSC Scanning, Magellan 800i */ | ||
1606 | .driver_info = NO_UNION_NORMAL, | ||
1607 | }, | ||
1605 | { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */ | 1608 | { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */ |
1606 | .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ | 1609 | .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ |
1607 | }, | 1610 | }, |
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index a815fd2cc5e7..957ed2c41482 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -877,6 +877,60 @@ static int hub_hub_status(struct usb_hub *hub, | |||
877 | return ret; | 877 | return ret; |
878 | } | 878 | } |
879 | 879 | ||
880 | static int hub_set_port_link_state(struct usb_hub *hub, int port1, | ||
881 | unsigned int link_status) | ||
882 | { | ||
883 | return set_port_feature(hub->hdev, | ||
884 | port1 | (link_status << 3), | ||
885 | USB_PORT_FEAT_LINK_STATE); | ||
886 | } | ||
887 | |||
888 | /* | ||
889 | * If USB 3.0 ports are placed into the Disabled state, they will no longer | ||
890 | * detect any device connects or disconnects. This is generally not what the | ||
891 | * USB core wants, since it expects a disabled port to produce a port status | ||
892 | * change event when a new device connects. | ||
893 | * | ||
894 | * Instead, set the link state to Disabled, wait for the link to settle into | ||
895 | * that state, clear any change bits, and then put the port into the RxDetect | ||
896 | * state. | ||
897 | */ | ||
898 | static int hub_usb3_port_disable(struct usb_hub *hub, int port1) | ||
899 | { | ||
900 | int ret; | ||
901 | int total_time; | ||
902 | u16 portchange, portstatus; | ||
903 | |||
904 | if (!hub_is_superspeed(hub->hdev)) | ||
905 | return -EINVAL; | ||
906 | |||
907 | ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED); | ||
908 | if (ret) { | ||
909 | dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", | ||
910 | port1, ret); | ||
911 | return ret; | ||
912 | } | ||
913 | |||
914 | /* Wait for the link to enter the disabled state. */ | ||
915 | for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) { | ||
916 | ret = hub_port_status(hub, port1, &portstatus, &portchange); | ||
917 | if (ret < 0) | ||
918 | return ret; | ||
919 | |||
920 | if ((portstatus & USB_PORT_STAT_LINK_STATE) == | ||
921 | USB_SS_PORT_LS_SS_DISABLED) | ||
922 | break; | ||
923 | if (total_time >= HUB_DEBOUNCE_TIMEOUT) | ||
924 | break; | ||
925 | msleep(HUB_DEBOUNCE_STEP); | ||
926 | } | ||
927 | if (total_time >= HUB_DEBOUNCE_TIMEOUT) | ||
928 | dev_warn(hub->intfdev, "Could not disable port %d after %d ms\n", | ||
929 | port1, total_time); | ||
930 | |||
931 | return hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_RX_DETECT); | ||
932 | } | ||
933 | |||
880 | static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) | 934 | static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) |
881 | { | 935 | { |
882 | struct usb_device *hdev = hub->hdev; | 936 | struct usb_device *hdev = hub->hdev; |
@@ -885,8 +939,13 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) | |||
885 | if (hub->ports[port1 - 1]->child && set_state) | 939 | if (hub->ports[port1 - 1]->child && set_state) |
886 | usb_set_device_state(hub->ports[port1 - 1]->child, | 940 | usb_set_device_state(hub->ports[port1 - 1]->child, |
887 | USB_STATE_NOTATTACHED); | 941 | USB_STATE_NOTATTACHED); |
888 | if (!hub->error && !hub_is_superspeed(hub->hdev)) | 942 | if (!hub->error) { |
889 | ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE); | 943 | if (hub_is_superspeed(hub->hdev)) |
944 | ret = hub_usb3_port_disable(hub, port1); | ||
945 | else | ||
946 | ret = clear_port_feature(hdev, port1, | ||
947 | USB_PORT_FEAT_ENABLE); | ||
948 | } | ||
890 | if (ret) | 949 | if (ret) |
891 | dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", | 950 | dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", |
892 | port1, ret); | 951 | port1, ret); |
@@ -2440,7 +2499,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub) | |||
2440 | #define HUB_SHORT_RESET_TIME 10 | 2499 | #define HUB_SHORT_RESET_TIME 10 |
2441 | #define HUB_BH_RESET_TIME 50 | 2500 | #define HUB_BH_RESET_TIME 50 |
2442 | #define HUB_LONG_RESET_TIME 200 | 2501 | #define HUB_LONG_RESET_TIME 200 |
2443 | #define HUB_RESET_TIMEOUT 500 | 2502 | #define HUB_RESET_TIMEOUT 800 |
2444 | 2503 | ||
2445 | static int hub_port_reset(struct usb_hub *hub, int port1, | 2504 | static int hub_port_reset(struct usb_hub *hub, int port1, |
2446 | struct usb_device *udev, unsigned int delay, bool warm); | 2505 | struct usb_device *udev, unsigned int delay, bool warm); |
@@ -2475,6 +2534,10 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, | |||
2475 | if (ret < 0) | 2534 | if (ret < 0) |
2476 | return ret; | 2535 | return ret; |
2477 | 2536 | ||
2537 | /* The port state is unknown until the reset completes. */ | ||
2538 | if ((portstatus & USB_PORT_STAT_RESET)) | ||
2539 | goto delay; | ||
2540 | |||
2478 | /* | 2541 | /* |
2479 | * Some buggy devices require a warm reset to be issued even | 2542 | * Some buggy devices require a warm reset to be issued even |
2480 | * when the port appears not to be connected. | 2543 | * when the port appears not to be connected. |
@@ -2520,11 +2583,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, | |||
2520 | if ((portchange & USB_PORT_STAT_C_CONNECTION)) | 2583 | if ((portchange & USB_PORT_STAT_C_CONNECTION)) |
2521 | return -ENOTCONN; | 2584 | return -ENOTCONN; |
2522 | 2585 | ||
2523 | /* if we`ve finished resetting, then break out of | 2586 | if ((portstatus & USB_PORT_STAT_ENABLE)) { |
2524 | * the loop | ||
2525 | */ | ||
2526 | if (!(portstatus & USB_PORT_STAT_RESET) && | ||
2527 | (portstatus & USB_PORT_STAT_ENABLE)) { | ||
2528 | if (hub_is_wusb(hub)) | 2587 | if (hub_is_wusb(hub)) |
2529 | udev->speed = USB_SPEED_WIRELESS; | 2588 | udev->speed = USB_SPEED_WIRELESS; |
2530 | else if (hub_is_superspeed(hub->hdev)) | 2589 | else if (hub_is_superspeed(hub->hdev)) |
@@ -2538,10 +2597,15 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, | |||
2538 | return 0; | 2597 | return 0; |
2539 | } | 2598 | } |
2540 | } else { | 2599 | } else { |
2541 | if (portchange & USB_PORT_STAT_C_BH_RESET) | 2600 | if (!(portstatus & USB_PORT_STAT_CONNECTION) || |
2542 | return 0; | 2601 | hub_port_warm_reset_required(hub, |
2602 | portstatus)) | ||
2603 | return -ENOTCONN; | ||
2604 | |||
2605 | return 0; | ||
2543 | } | 2606 | } |
2544 | 2607 | ||
2608 | delay: | ||
2545 | /* switch to the long delay after two short delay failures */ | 2609 | /* switch to the long delay after two short delay failures */ |
2546 | if (delay_time >= 2 * HUB_SHORT_RESET_TIME) | 2610 | if (delay_time >= 2 * HUB_SHORT_RESET_TIME) |
2547 | delay = HUB_LONG_RESET_TIME; | 2611 | delay = HUB_LONG_RESET_TIME; |
@@ -2565,14 +2629,11 @@ static void hub_port_finish_reset(struct usb_hub *hub, int port1, | |||
2565 | msleep(10 + 40); | 2629 | msleep(10 + 40); |
2566 | update_devnum(udev, 0); | 2630 | update_devnum(udev, 0); |
2567 | hcd = bus_to_hcd(udev->bus); | 2631 | hcd = bus_to_hcd(udev->bus); |
2568 | if (hcd->driver->reset_device) { | 2632 | /* The xHC may think the device is already reset, |
2569 | *status = hcd->driver->reset_device(hcd, udev); | 2633 | * so ignore the status. |
2570 | if (*status < 0) { | 2634 | */ |
2571 | dev_err(&udev->dev, "Cannot reset " | 2635 | if (hcd->driver->reset_device) |
2572 | "HCD device state\n"); | 2636 | hcd->driver->reset_device(hcd, udev); |
2573 | break; | ||
2574 | } | ||
2575 | } | ||
2576 | } | 2637 | } |
2577 | /* FALL THROUGH */ | 2638 | /* FALL THROUGH */ |
2578 | case -ENOTCONN: | 2639 | case -ENOTCONN: |
@@ -2580,16 +2641,16 @@ static void hub_port_finish_reset(struct usb_hub *hub, int port1, | |||
2580 | clear_port_feature(hub->hdev, | 2641 | clear_port_feature(hub->hdev, |
2581 | port1, USB_PORT_FEAT_C_RESET); | 2642 | port1, USB_PORT_FEAT_C_RESET); |
2582 | /* FIXME need disconnect() for NOTATTACHED device */ | 2643 | /* FIXME need disconnect() for NOTATTACHED device */ |
2583 | if (warm) { | 2644 | if (hub_is_superspeed(hub->hdev)) { |
2584 | clear_port_feature(hub->hdev, port1, | 2645 | clear_port_feature(hub->hdev, port1, |
2585 | USB_PORT_FEAT_C_BH_PORT_RESET); | 2646 | USB_PORT_FEAT_C_BH_PORT_RESET); |
2586 | clear_port_feature(hub->hdev, port1, | 2647 | clear_port_feature(hub->hdev, port1, |
2587 | USB_PORT_FEAT_C_PORT_LINK_STATE); | 2648 | USB_PORT_FEAT_C_PORT_LINK_STATE); |
2588 | } else { | 2649 | } |
2650 | if (!warm) | ||
2589 | usb_set_device_state(udev, *status | 2651 | usb_set_device_state(udev, *status |
2590 | ? USB_STATE_NOTATTACHED | 2652 | ? USB_STATE_NOTATTACHED |
2591 | : USB_STATE_DEFAULT); | 2653 | : USB_STATE_DEFAULT); |
2592 | } | ||
2593 | break; | 2654 | break; |
2594 | } | 2655 | } |
2595 | } | 2656 | } |
@@ -2939,7 +3000,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) | |||
2939 | static int finish_port_resume(struct usb_device *udev) | 3000 | static int finish_port_resume(struct usb_device *udev) |
2940 | { | 3001 | { |
2941 | int status = 0; | 3002 | int status = 0; |
2942 | u16 devstatus; | 3003 | u16 devstatus = 0; |
2943 | 3004 | ||
2944 | /* caller owns the udev device lock */ | 3005 | /* caller owns the udev device lock */ |
2945 | dev_dbg(&udev->dev, "%s\n", | 3006 | dev_dbg(&udev->dev, "%s\n", |
@@ -2984,7 +3045,13 @@ static int finish_port_resume(struct usb_device *udev) | |||
2984 | if (status) { | 3045 | if (status) { |
2985 | dev_dbg(&udev->dev, "gone after usb resume? status %d\n", | 3046 | dev_dbg(&udev->dev, "gone after usb resume? status %d\n", |
2986 | status); | 3047 | status); |
2987 | } else if (udev->actconfig) { | 3048 | /* |
3049 | * There are a few quirky devices which violate the standard | ||
3050 | * by claiming to have remote wakeup enabled after a reset, | ||
3051 | * which crash if the feature is cleared, hence check for | ||
3052 | * udev->reset_resume | ||
3053 | */ | ||
3054 | } else if (udev->actconfig && !udev->reset_resume) { | ||
2988 | le16_to_cpus(&devstatus); | 3055 | le16_to_cpus(&devstatus); |
2989 | if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { | 3056 | if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { |
2990 | status = usb_control_msg(udev, | 3057 | status = usb_control_msg(udev, |
@@ -4638,9 +4705,14 @@ static void hub_events(void) | |||
4638 | * SS.Inactive state. | 4705 | * SS.Inactive state. |
4639 | */ | 4706 | */ |
4640 | if (hub_port_warm_reset_required(hub, portstatus)) { | 4707 | if (hub_port_warm_reset_required(hub, portstatus)) { |
4708 | int status; | ||
4709 | |||
4641 | dev_dbg(hub_dev, "warm reset port %d\n", i); | 4710 | dev_dbg(hub_dev, "warm reset port %d\n", i); |
4642 | hub_port_reset(hub, i, NULL, | 4711 | status = hub_port_reset(hub, i, NULL, |
4643 | HUB_BH_RESET_TIME, true); | 4712 | HUB_BH_RESET_TIME, true); |
4713 | if (status < 0) | ||
4714 | hub_port_disable(hub, i, 1); | ||
4715 | connect_change = 0; | ||
4644 | } | 4716 | } |
4645 | 4717 | ||
4646 | if (connect_change) | 4718 | if (connect_change) |
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index fdefd9c7f7af..3113c1d71442 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c | |||
@@ -43,6 +43,9 @@ static const struct usb_device_id usb_quirk_list[] = { | |||
43 | /* Creative SB Audigy 2 NX */ | 43 | /* Creative SB Audigy 2 NX */ |
44 | { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, | 44 | { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, |
45 | 45 | ||
46 | /* Microsoft LifeCam-VX700 v2.0 */ | ||
47 | { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME }, | ||
48 | |||
46 | /* Logitech Quickcam Fusion */ | 49 | /* Logitech Quickcam Fusion */ |
47 | { USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME }, | 50 | { USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME }, |
48 | 51 | ||
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 92604b4f9712..5945aadaa1c9 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c | |||
@@ -56,7 +56,7 @@ | |||
56 | #define dump_register(nm) \ | 56 | #define dump_register(nm) \ |
57 | { \ | 57 | { \ |
58 | .name = __stringify(nm), \ | 58 | .name = __stringify(nm), \ |
59 | .offset = DWC3_ ##nm, \ | 59 | .offset = DWC3_ ##nm - DWC3_GLOBALS_REGS_START, \ |
60 | } | 60 | } |
61 | 61 | ||
62 | static const struct debugfs_reg32 dwc3_regs[] = { | 62 | static const struct debugfs_reg32 dwc3_regs[] = { |
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index fc0ec5e0d58e..d9f6b9372491 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c | |||
@@ -3231,7 +3231,7 @@ static int udc_pci_probe( | |||
3231 | } | 3231 | } |
3232 | 3232 | ||
3233 | if (!pdev->irq) { | 3233 | if (!pdev->irq) { |
3234 | dev_err(&dev->pdev->dev, "irq not set\n"); | 3234 | dev_err(&pdev->dev, "irq not set\n"); |
3235 | kfree(dev); | 3235 | kfree(dev); |
3236 | dev = NULL; | 3236 | dev = NULL; |
3237 | retval = -ENODEV; | 3237 | retval = -ENODEV; |
@@ -3250,7 +3250,7 @@ static int udc_pci_probe( | |||
3250 | dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR); | 3250 | dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR); |
3251 | 3251 | ||
3252 | if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) { | 3252 | if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) { |
3253 | dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq); | 3253 | dev_dbg(&pdev->dev, "request_irq(%d) fail\n", pdev->irq); |
3254 | kfree(dev); | 3254 | kfree(dev); |
3255 | dev = NULL; | 3255 | dev = NULL; |
3256 | retval = -EBUSY; | 3256 | retval = -EBUSY; |
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 95d584dbed13..8cf0c0f6fa1f 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c | |||
@@ -130,10 +130,7 @@ static const char ep0name[] = "ep0"; | |||
130 | static const char *const ep_name[] = { | 130 | static const char *const ep_name[] = { |
131 | ep0name, /* everyone has ep0 */ | 131 | ep0name, /* everyone has ep0 */ |
132 | 132 | ||
133 | /* act like a net2280: high speed, six configurable endpoints */ | 133 | /* act like a pxa250: fifteen fixed function endpoints */ |
134 | "ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f", | ||
135 | |||
136 | /* or like pxa250: fifteen fixed function endpoints */ | ||
137 | "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int", | 134 | "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int", |
138 | "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int", | 135 | "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int", |
139 | "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso", | 136 | "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso", |
@@ -141,6 +138,10 @@ static const char *const ep_name[] = { | |||
141 | 138 | ||
142 | /* or like sa1100: two fixed function endpoints */ | 139 | /* or like sa1100: two fixed function endpoints */ |
143 | "ep1out-bulk", "ep2in-bulk", | 140 | "ep1out-bulk", "ep2in-bulk", |
141 | |||
142 | /* and now some generic EPs so we have enough in multi config */ | ||
143 | "ep3out", "ep4in", "ep5out", "ep6out", "ep7in", "ep8out", "ep9in", | ||
144 | "ep10out", "ep11out", "ep12in", "ep13out", "ep14in", "ep15out", | ||
144 | }; | 145 | }; |
145 | #define DUMMY_ENDPOINTS ARRAY_SIZE(ep_name) | 146 | #define DUMMY_ENDPOINTS ARRAY_SIZE(ep_name) |
146 | 147 | ||
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 379aac7b82fc..6e8b1272ebce 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c | |||
@@ -1012,7 +1012,7 @@ static void udc_clock_enable(struct mv_udc *udc) | |||
1012 | unsigned int i; | 1012 | unsigned int i; |
1013 | 1013 | ||
1014 | for (i = 0; i < udc->clknum; i++) | 1014 | for (i = 0; i < udc->clknum; i++) |
1015 | clk_enable(udc->clk[i]); | 1015 | clk_prepare_enable(udc->clk[i]); |
1016 | } | 1016 | } |
1017 | 1017 | ||
1018 | static void udc_clock_disable(struct mv_udc *udc) | 1018 | static void udc_clock_disable(struct mv_udc *udc) |
@@ -1020,7 +1020,7 @@ static void udc_clock_disable(struct mv_udc *udc) | |||
1020 | unsigned int i; | 1020 | unsigned int i; |
1021 | 1021 | ||
1022 | for (i = 0; i < udc->clknum; i++) | 1022 | for (i = 0; i < udc->clknum; i++) |
1023 | clk_disable(udc->clk[i]); | 1023 | clk_disable_unprepare(udc->clk[i]); |
1024 | } | 1024 | } |
1025 | 1025 | ||
1026 | static void udc_stop(struct mv_udc *udc) | 1026 | static void udc_stop(struct mv_udc *udc) |
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 141971d9051e..439c3f972f8c 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c | |||
@@ -3477,12 +3477,11 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) | |||
3477 | /** | 3477 | /** |
3478 | * s3c_hsotg_release - release callback for hsotg device | 3478 | * s3c_hsotg_release - release callback for hsotg device |
3479 | * @dev: Device to for which release is called | 3479 | * @dev: Device to for which release is called |
3480 | * | ||
3481 | * Nothing to do as the resource is allocated using devm_ API. | ||
3480 | */ | 3482 | */ |
3481 | static void s3c_hsotg_release(struct device *dev) | 3483 | static void s3c_hsotg_release(struct device *dev) |
3482 | { | 3484 | { |
3483 | struct s3c_hsotg *hsotg = dev_get_drvdata(dev); | ||
3484 | |||
3485 | kfree(hsotg); | ||
3486 | } | 3485 | } |
3487 | 3486 | ||
3488 | /** | 3487 | /** |
diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index 4f7f76f00c74..7cacd6ae818e 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c | |||
@@ -1794,9 +1794,10 @@ static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg) | |||
1794 | tpg->tpg_nexus = NULL; | 1794 | tpg->tpg_nexus = NULL; |
1795 | 1795 | ||
1796 | kfree(tv_nexus); | 1796 | kfree(tv_nexus); |
1797 | ret = 0; | ||
1797 | out: | 1798 | out: |
1798 | mutex_unlock(&tpg->tpg_mutex); | 1799 | mutex_unlock(&tpg->tpg_mutex); |
1799 | return 0; | 1800 | return ret; |
1800 | } | 1801 | } |
1801 | 1802 | ||
1802 | static ssize_t tcm_usbg_tpg_store_nexus( | 1803 | static ssize_t tcm_usbg_tpg_store_nexus( |
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index d0f95482f40e..598dcc1212f0 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c | |||
@@ -887,7 +887,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) | |||
887 | pr_debug("gs_close: ttyGS%d (%p,%p) done!\n", | 887 | pr_debug("gs_close: ttyGS%d (%p,%p) done!\n", |
888 | port->port_num, tty, file); | 888 | port->port_num, tty, file); |
889 | 889 | ||
890 | wake_up_interruptible(&port->port.close_wait); | 890 | wake_up(&port->port.close_wait); |
891 | exit: | 891 | exit: |
892 | spin_unlock_irq(&port->port_lock); | 892 | spin_unlock_irq(&port->port_lock); |
893 | } | 893 | } |
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index fd9b5424b860..d81d2fcbff18 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c | |||
@@ -230,7 +230,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, | |||
230 | 230 | ||
231 | switch (phy_mode) { | 231 | switch (phy_mode) { |
232 | case FSL_USB2_PHY_ULPI: | 232 | case FSL_USB2_PHY_ULPI: |
233 | if (pdata->controller_ver) { | 233 | if (pdata->have_sysif_regs && pdata->controller_ver) { |
234 | /* controller version 1.6 or above */ | 234 | /* controller version 1.6 or above */ |
235 | setbits32(non_ehci + FSL_SOC_USB_CTRL, | 235 | setbits32(non_ehci + FSL_SOC_USB_CTRL, |
236 | ULPI_PHY_CLK_SEL); | 236 | ULPI_PHY_CLK_SEL); |
@@ -251,7 +251,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, | |||
251 | portsc |= PORT_PTS_PTW; | 251 | portsc |= PORT_PTS_PTW; |
252 | /* fall through */ | 252 | /* fall through */ |
253 | case FSL_USB2_PHY_UTMI: | 253 | case FSL_USB2_PHY_UTMI: |
254 | if (pdata->controller_ver) { | 254 | if (pdata->have_sysif_regs && pdata->controller_ver) { |
255 | /* controller version 1.6 or above */ | 255 | /* controller version 1.6 or above */ |
256 | setbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN); | 256 | setbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN); |
257 | mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to | 257 | mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to |
@@ -267,7 +267,8 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, | |||
267 | break; | 267 | break; |
268 | } | 268 | } |
269 | 269 | ||
270 | if (pdata->controller_ver && (phy_mode == FSL_USB2_PHY_ULPI)) { | 270 | if (pdata->have_sysif_regs && pdata->controller_ver && |
271 | (phy_mode == FSL_USB2_PHY_ULPI)) { | ||
271 | /* check PHY_CLK_VALID to get phy clk valid */ | 272 | /* check PHY_CLK_VALID to get phy clk valid */ |
272 | if (!spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) & | 273 | if (!spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) & |
273 | PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0)) { | 274 | PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0)) { |
@@ -278,7 +279,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, | |||
278 | 279 | ||
279 | ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); | 280 | ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); |
280 | 281 | ||
281 | if (phy_mode != FSL_USB2_PHY_ULPI) | 282 | if (phy_mode != FSL_USB2_PHY_ULPI && pdata->have_sysif_regs) |
282 | setbits32(non_ehci + FSL_SOC_USB_CTRL, USB_CTRL_USB_EN); | 283 | setbits32(non_ehci + FSL_SOC_USB_CTRL, USB_CTRL_USB_EN); |
283 | 284 | ||
284 | return 0; | 285 | return 0; |
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index f7bfc0b898b9..6c56297ea16b 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c | |||
@@ -43,7 +43,7 @@ static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv) | |||
43 | unsigned int i; | 43 | unsigned int i; |
44 | 44 | ||
45 | for (i = 0; i < ehci_mv->clknum; i++) | 45 | for (i = 0; i < ehci_mv->clknum; i++) |
46 | clk_enable(ehci_mv->clk[i]); | 46 | clk_prepare_enable(ehci_mv->clk[i]); |
47 | } | 47 | } |
48 | 48 | ||
49 | static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv) | 49 | static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv) |
@@ -51,7 +51,7 @@ static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv) | |||
51 | unsigned int i; | 51 | unsigned int i; |
52 | 52 | ||
53 | for (i = 0; i < ehci_mv->clknum; i++) | 53 | for (i = 0; i < ehci_mv->clknum; i++) |
54 | clk_disable(ehci_mv->clk[i]); | 54 | clk_disable_unprepare(ehci_mv->clk[i]); |
55 | } | 55 | } |
56 | 56 | ||
57 | static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv) | 57 | static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv) |
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index dabb20494826..170b9399e09f 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c | |||
@@ -200,6 +200,26 @@ static int ehci_pci_setup(struct usb_hcd *hcd) | |||
200 | break; | 200 | break; |
201 | } | 201 | } |
202 | 202 | ||
203 | /* optional debug port, normally in the first BAR */ | ||
204 | temp = pci_find_capability(pdev, PCI_CAP_ID_DBG); | ||
205 | if (temp) { | ||
206 | pci_read_config_dword(pdev, temp, &temp); | ||
207 | temp >>= 16; | ||
208 | if (((temp >> 13) & 7) == 1) { | ||
209 | u32 hcs_params = ehci_readl(ehci, | ||
210 | &ehci->caps->hcs_params); | ||
211 | |||
212 | temp &= 0x1fff; | ||
213 | ehci->debug = hcd->regs + temp; | ||
214 | temp = ehci_readl(ehci, &ehci->debug->control); | ||
215 | ehci_info(ehci, "debug port %d%s\n", | ||
216 | HCS_DEBUG_PORT(hcs_params), | ||
217 | (temp & DBGP_ENABLED) ? " IN USE" : ""); | ||
218 | if (!(temp & DBGP_ENABLED)) | ||
219 | ehci->debug = NULL; | ||
220 | } | ||
221 | } | ||
222 | |||
203 | retval = ehci_setup(hcd); | 223 | retval = ehci_setup(hcd); |
204 | if (retval) | 224 | if (retval) |
205 | return retval; | 225 | return retval; |
@@ -228,25 +248,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd) | |||
228 | break; | 248 | break; |
229 | } | 249 | } |
230 | 250 | ||
231 | /* optional debug port, normally in the first BAR */ | ||
232 | temp = pci_find_capability(pdev, 0x0a); | ||
233 | if (temp) { | ||
234 | pci_read_config_dword(pdev, temp, &temp); | ||
235 | temp >>= 16; | ||
236 | if ((temp & (3 << 13)) == (1 << 13)) { | ||
237 | temp &= 0x1fff; | ||
238 | ehci->debug = hcd->regs + temp; | ||
239 | temp = ehci_readl(ehci, &ehci->debug->control); | ||
240 | ehci_info(ehci, "debug port %d%s\n", | ||
241 | HCS_DEBUG_PORT(ehci->hcs_params), | ||
242 | (temp & DBGP_ENABLED) | ||
243 | ? " IN USE" | ||
244 | : ""); | ||
245 | if (!(temp & DBGP_ENABLED)) | ||
246 | ehci->debug = NULL; | ||
247 | } | ||
248 | } | ||
249 | |||
250 | /* at least the Genesys GL880S needs fixup here */ | 251 | /* at least the Genesys GL880S needs fixup here */ |
251 | temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params); | 252 | temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params); |
252 | temp &= 0x0f; | 253 | temp &= 0x0f; |
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 5105127c1d4b..11e0b79ff9d5 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c | |||
@@ -142,6 +142,9 @@ static int usb_get_ver_info(struct device_node *np) | |||
142 | return ver; | 142 | return ver; |
143 | } | 143 | } |
144 | 144 | ||
145 | if (of_device_is_compatible(np, "fsl,mpc5121-usb2-dr")) | ||
146 | return FSL_USB_VER_OLD; | ||
147 | |||
145 | if (of_device_is_compatible(np, "fsl-usb2-mph")) { | 148 | if (of_device_is_compatible(np, "fsl-usb2-mph")) { |
146 | if (of_device_is_compatible(np, "fsl-usb2-mph-v1.6")) | 149 | if (of_device_is_compatible(np, "fsl-usb2-mph-v1.6")) |
147 | ver = FSL_USB_VER_1_6; | 150 | ver = FSL_USB_VER_1_6; |
diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c index bd6a7447ccc9..f0ebe8e7c58b 100644 --- a/drivers/usb/host/imx21-hcd.c +++ b/drivers/usb/host/imx21-hcd.c | |||
@@ -58,6 +58,7 @@ | |||
58 | #include <linux/usb.h> | 58 | #include <linux/usb.h> |
59 | #include <linux/usb/hcd.h> | 59 | #include <linux/usb/hcd.h> |
60 | #include <linux/dma-mapping.h> | 60 | #include <linux/dma-mapping.h> |
61 | #include <linux/module.h> | ||
61 | 62 | ||
62 | #include "imx21-hcd.h" | 63 | #include "imx21-hcd.h" |
63 | 64 | ||
diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c index d370245a4ee2..5e3a6deb62b1 100644 --- a/drivers/usb/host/ohci-tmio.c +++ b/drivers/usb/host/ohci-tmio.c | |||
@@ -128,7 +128,8 @@ static void tmio_start_hc(struct platform_device *dev) | |||
128 | tmio_iowrite8(2, tmio->ccr + CCR_INTC); | 128 | tmio_iowrite8(2, tmio->ccr + CCR_INTC); |
129 | 129 | ||
130 | dev_info(&dev->dev, "revision %d @ 0x%08llx, irq %d\n", | 130 | dev_info(&dev->dev, "revision %d @ 0x%08llx, irq %d\n", |
131 | tmio_ioread8(tmio->ccr + CCR_REVID), hcd->rsrc_start, hcd->irq); | 131 | tmio_ioread8(tmio->ccr + CCR_REVID), |
132 | (u64) hcd->rsrc_start, hcd->irq); | ||
132 | } | 133 | } |
133 | 134 | ||
134 | static int ohci_tmio_start(struct usb_hcd *hcd) | 135 | static int ohci_tmio_start(struct usb_hcd *hcd) |
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index a686cf4905bb..68914429482f 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c | |||
@@ -761,12 +761,39 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
761 | break; | 761 | break; |
762 | case USB_PORT_FEAT_LINK_STATE: | 762 | case USB_PORT_FEAT_LINK_STATE: |
763 | temp = xhci_readl(xhci, port_array[wIndex]); | 763 | temp = xhci_readl(xhci, port_array[wIndex]); |
764 | |||
765 | /* Disable port */ | ||
766 | if (link_state == USB_SS_PORT_LS_SS_DISABLED) { | ||
767 | xhci_dbg(xhci, "Disable port %d\n", wIndex); | ||
768 | temp = xhci_port_state_to_neutral(temp); | ||
769 | /* | ||
770 | * Clear all change bits, so that we get a new | ||
771 | * connection event. | ||
772 | */ | ||
773 | temp |= PORT_CSC | PORT_PEC | PORT_WRC | | ||
774 | PORT_OCC | PORT_RC | PORT_PLC | | ||
775 | PORT_CEC; | ||
776 | xhci_writel(xhci, temp | PORT_PE, | ||
777 | port_array[wIndex]); | ||
778 | temp = xhci_readl(xhci, port_array[wIndex]); | ||
779 | break; | ||
780 | } | ||
781 | |||
782 | /* Put link in RxDetect (enable port) */ | ||
783 | if (link_state == USB_SS_PORT_LS_RX_DETECT) { | ||
784 | xhci_dbg(xhci, "Enable port %d\n", wIndex); | ||
785 | xhci_set_link_state(xhci, port_array, wIndex, | ||
786 | link_state); | ||
787 | temp = xhci_readl(xhci, port_array[wIndex]); | ||
788 | break; | ||
789 | } | ||
790 | |||
764 | /* Software should not attempt to set | 791 | /* Software should not attempt to set |
765 | * port link state above '5' (Rx.Detect) and the port | 792 | * port link state above '3' (U3) and the port |
766 | * must be enabled. | 793 | * must be enabled. |
767 | */ | 794 | */ |
768 | if ((temp & PORT_PE) == 0 || | 795 | if ((temp & PORT_PE) == 0 || |
769 | (link_state > USB_SS_PORT_LS_RX_DETECT)) { | 796 | (link_state > USB_SS_PORT_LS_U3)) { |
770 | xhci_warn(xhci, "Cannot set link state.\n"); | 797 | xhci_warn(xhci, "Cannot set link state.\n"); |
771 | goto error; | 798 | goto error; |
772 | } | 799 | } |
@@ -957,6 +984,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) | |||
957 | int max_ports; | 984 | int max_ports; |
958 | __le32 __iomem **port_array; | 985 | __le32 __iomem **port_array; |
959 | struct xhci_bus_state *bus_state; | 986 | struct xhci_bus_state *bus_state; |
987 | bool reset_change = false; | ||
960 | 988 | ||
961 | max_ports = xhci_get_ports(hcd, &port_array); | 989 | max_ports = xhci_get_ports(hcd, &port_array); |
962 | bus_state = &xhci->bus_state[hcd_index(hcd)]; | 990 | bus_state = &xhci->bus_state[hcd_index(hcd)]; |
@@ -988,6 +1016,12 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) | |||
988 | buf[(i + 1) / 8] |= 1 << (i + 1) % 8; | 1016 | buf[(i + 1) / 8] |= 1 << (i + 1) % 8; |
989 | status = 1; | 1017 | status = 1; |
990 | } | 1018 | } |
1019 | if ((temp & PORT_RC)) | ||
1020 | reset_change = true; | ||
1021 | } | ||
1022 | if (!status && !reset_change) { | ||
1023 | xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); | ||
1024 | clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); | ||
991 | } | 1025 | } |
992 | spin_unlock_irqrestore(&xhci->lock, flags); | 1026 | spin_unlock_irqrestore(&xhci->lock, flags); |
993 | return status ? retval : 0; | 1027 | return status ? retval : 0; |
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index fb51c7085ad0..35616ffbe3ae 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c | |||
@@ -1250,6 +1250,8 @@ static unsigned int xhci_microframes_to_exponent(struct usb_device *udev, | |||
1250 | static unsigned int xhci_parse_microframe_interval(struct usb_device *udev, | 1250 | static unsigned int xhci_parse_microframe_interval(struct usb_device *udev, |
1251 | struct usb_host_endpoint *ep) | 1251 | struct usb_host_endpoint *ep) |
1252 | { | 1252 | { |
1253 | if (ep->desc.bInterval == 0) | ||
1254 | return 0; | ||
1253 | return xhci_microframes_to_exponent(udev, ep, | 1255 | return xhci_microframes_to_exponent(udev, ep, |
1254 | ep->desc.bInterval, 0, 15); | 1256 | ep->desc.bInterval, 0, 15); |
1255 | } | 1257 | } |
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index cbb44b7b9d65..59fb5c677dbe 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c | |||
@@ -1725,6 +1725,15 @@ cleanup: | |||
1725 | if (bogus_port_status) | 1725 | if (bogus_port_status) |
1726 | return; | 1726 | return; |
1727 | 1727 | ||
1728 | /* | ||
1729 | * xHCI port-status-change events occur when the "or" of all the | ||
1730 | * status-change bits in the portsc register changes from 0 to 1. | ||
1731 | * New status changes won't cause an event if any other change | ||
1732 | * bits are still set. When an event occurs, switch over to | ||
1733 | * polling to avoid losing status changes. | ||
1734 | */ | ||
1735 | xhci_dbg(xhci, "%s: starting port polling.\n", __func__); | ||
1736 | set_bit(HCD_FLAG_POLL_RH, &hcd->flags); | ||
1728 | spin_unlock(&xhci->lock); | 1737 | spin_unlock(&xhci->lock); |
1729 | /* Pass this up to the core */ | 1738 | /* Pass this up to the core */ |
1730 | usb_hcd_poll_rh_status(hcd); | 1739 | usb_hcd_poll_rh_status(hcd); |
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 5c72c431bab1..f1f01a834ba7 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c | |||
@@ -884,6 +884,11 @@ int xhci_suspend(struct xhci_hcd *xhci) | |||
884 | xhci->shared_hcd->state != HC_STATE_SUSPENDED) | 884 | xhci->shared_hcd->state != HC_STATE_SUSPENDED) |
885 | return -EINVAL; | 885 | return -EINVAL; |
886 | 886 | ||
887 | /* Don't poll the roothubs on bus suspend. */ | ||
888 | xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); | ||
889 | clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); | ||
890 | del_timer_sync(&hcd->rh_timer); | ||
891 | |||
887 | spin_lock_irq(&xhci->lock); | 892 | spin_lock_irq(&xhci->lock); |
888 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | 893 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); |
889 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); | 894 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); |
@@ -1069,6 +1074,11 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) | |||
1069 | if (xhci->quirks & XHCI_COMP_MODE_QUIRK) | 1074 | if (xhci->quirks & XHCI_COMP_MODE_QUIRK) |
1070 | compliance_mode_recovery_timer_init(xhci); | 1075 | compliance_mode_recovery_timer_init(xhci); |
1071 | 1076 | ||
1077 | /* Re-enable port polling. */ | ||
1078 | xhci_dbg(xhci, "%s: starting port polling.\n", __func__); | ||
1079 | set_bit(HCD_FLAG_POLL_RH, &hcd->flags); | ||
1080 | usb_hcd_poll_rh_status(hcd); | ||
1081 | |||
1072 | return retval; | 1082 | return retval; |
1073 | } | 1083 | } |
1074 | #endif /* CONFIG_PM */ | 1084 | #endif /* CONFIG_PM */ |
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 7667b12f2ff5..268148de9714 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c | |||
@@ -2179,7 +2179,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf) | |||
2179 | if (dev->out_pipe == 0 || !param->length || param->sglen < 4) | 2179 | if (dev->out_pipe == 0 || !param->length || param->sglen < 4) |
2180 | break; | 2180 | break; |
2181 | retval = 0; | 2181 | retval = 0; |
2182 | dev_info(&intf->dev, "TEST 17: unlink from %d queues of " | 2182 | dev_info(&intf->dev, "TEST 24: unlink from %d queues of " |
2183 | "%d %d-byte writes\n", | 2183 | "%d %d-byte writes\n", |
2184 | param->iterations, param->sglen, param->length); | 2184 | param->iterations, param->sglen, param->length); |
2185 | for (i = param->iterations; retval == 0 && i > 0; --i) { | 2185 | for (i = param->iterations; retval == 0 && i > 0; --i) { |
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index f1c6c5470b92..fd3486745e64 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c | |||
@@ -2298,10 +2298,7 @@ static int __init musb_init(void) | |||
2298 | if (usb_disabled()) | 2298 | if (usb_disabled()) |
2299 | return 0; | 2299 | return 0; |
2300 | 2300 | ||
2301 | pr_info("%s: version " MUSB_VERSION ", " | 2301 | pr_info("%s: version " MUSB_VERSION ", ?dma?, otg (peripheral+host)\n", |
2302 | "?dma?" | ||
2303 | ", " | ||
2304 | "otg (peripheral+host)", | ||
2305 | musb_driver_name); | 2302 | musb_driver_name); |
2306 | return platform_driver_register(&musb_driver); | 2303 | return platform_driver_register(&musb_driver); |
2307 | } | 2304 | } |
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index e6f2ae8368bb..f7d764de6fda 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c | |||
@@ -134,6 +134,11 @@ static const resource_size_t dsps_control_module_phys[] = { | |||
134 | DSPS_AM33XX_CONTROL_MODULE_PHYS_1, | 134 | DSPS_AM33XX_CONTROL_MODULE_PHYS_1, |
135 | }; | 135 | }; |
136 | 136 | ||
137 | #define USBPHY_CM_PWRDN (1 << 0) | ||
138 | #define USBPHY_OTG_PWRDN (1 << 1) | ||
139 | #define USBPHY_OTGVDET_EN (1 << 19) | ||
140 | #define USBPHY_OTGSESSEND_EN (1 << 20) | ||
141 | |||
137 | /** | 142 | /** |
138 | * musb_dsps_phy_control - phy on/off | 143 | * musb_dsps_phy_control - phy on/off |
139 | * @glue: struct dsps_glue * | 144 | * @glue: struct dsps_glue * |
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index 6223062d5d1b..37962c99ff1e 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig | |||
@@ -110,7 +110,7 @@ config AB8500_USB | |||
110 | 110 | ||
111 | config FSL_USB2_OTG | 111 | config FSL_USB2_OTG |
112 | bool "Freescale USB OTG Transceiver Driver" | 112 | bool "Freescale USB OTG Transceiver Driver" |
113 | depends on USB_EHCI_FSL && USB_GADGET_FSL_USB2 && USB_SUSPEND | 113 | depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_SUSPEND |
114 | select USB_OTG | 114 | select USB_OTG |
115 | select USB_OTG_UTILS | 115 | select USB_OTG_UTILS |
116 | help | 116 | help |
diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/otg/mv_otg.c index 1dd57504186d..eace975991a8 100644 --- a/drivers/usb/otg/mv_otg.c +++ b/drivers/usb/otg/mv_otg.c | |||
@@ -240,7 +240,7 @@ static void otg_clock_enable(struct mv_otg *mvotg) | |||
240 | unsigned int i; | 240 | unsigned int i; |
241 | 241 | ||
242 | for (i = 0; i < mvotg->clknum; i++) | 242 | for (i = 0; i < mvotg->clknum; i++) |
243 | clk_enable(mvotg->clk[i]); | 243 | clk_prepare_enable(mvotg->clk[i]); |
244 | } | 244 | } |
245 | 245 | ||
246 | static void otg_clock_disable(struct mv_otg *mvotg) | 246 | static void otg_clock_disable(struct mv_otg *mvotg) |
@@ -248,7 +248,7 @@ static void otg_clock_disable(struct mv_otg *mvotg) | |||
248 | unsigned int i; | 248 | unsigned int i; |
249 | 249 | ||
250 | for (i = 0; i < mvotg->clknum; i++) | 250 | for (i = 0; i < mvotg->clknum; i++) |
251 | clk_disable(mvotg->clk[i]); | 251 | clk_disable_unprepare(mvotg->clk[i]); |
252 | } | 252 | } |
253 | 253 | ||
254 | static int mv_otg_enable_internal(struct mv_otg *mvotg) | 254 | static int mv_otg_enable_internal(struct mv_otg *mvotg) |
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index dd41f61893ef..f2985cd88021 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c | |||
@@ -545,15 +545,6 @@ static int usbhsg_pipe_disable(struct usbhsg_uep *uep) | |||
545 | return 0; | 545 | return 0; |
546 | } | 546 | } |
547 | 547 | ||
548 | static void usbhsg_uep_init(struct usbhsg_gpriv *gpriv) | ||
549 | { | ||
550 | int i; | ||
551 | struct usbhsg_uep *uep; | ||
552 | |||
553 | usbhsg_for_each_uep_with_dcp(uep, gpriv, i) | ||
554 | uep->pipe = NULL; | ||
555 | } | ||
556 | |||
557 | /* | 548 | /* |
558 | * | 549 | * |
559 | * usb_ep_ops | 550 | * usb_ep_ops |
@@ -610,7 +601,12 @@ static int usbhsg_ep_disable(struct usb_ep *ep) | |||
610 | { | 601 | { |
611 | struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); | 602 | struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); |
612 | 603 | ||
613 | return usbhsg_pipe_disable(uep); | 604 | usbhsg_pipe_disable(uep); |
605 | |||
606 | uep->pipe->mod_private = NULL; | ||
607 | uep->pipe = NULL; | ||
608 | |||
609 | return 0; | ||
614 | } | 610 | } |
615 | 611 | ||
616 | static struct usb_request *usbhsg_ep_alloc_request(struct usb_ep *ep, | 612 | static struct usb_request *usbhsg_ep_alloc_request(struct usb_ep *ep, |
@@ -761,9 +757,8 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) | |||
761 | usbhs_pipe_init(priv, | 757 | usbhs_pipe_init(priv, |
762 | usbhsg_dma_map_ctrl); | 758 | usbhsg_dma_map_ctrl); |
763 | usbhs_fifo_init(priv); | 759 | usbhs_fifo_init(priv); |
764 | usbhsg_uep_init(gpriv); | ||
765 | 760 | ||
766 | /* dcp init */ | 761 | /* dcp init instead of usbhsg_ep_enable() */ |
767 | dcp->pipe = usbhs_dcp_malloc(priv); | 762 | dcp->pipe = usbhs_dcp_malloc(priv); |
768 | dcp->pipe->mod_private = dcp; | 763 | dcp->pipe->mod_private = dcp; |
769 | usbhs_pipe_config_update(dcp->pipe, 0, 0, 64); | 764 | usbhs_pipe_config_update(dcp->pipe, 0, 0, 64); |
@@ -825,7 +820,7 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) | |||
825 | usbhs_sys_set_test_mode(priv, 0); | 820 | usbhs_sys_set_test_mode(priv, 0); |
826 | usbhs_sys_function_ctrl(priv, 0); | 821 | usbhs_sys_function_ctrl(priv, 0); |
827 | 822 | ||
828 | usbhsg_pipe_disable(dcp); | 823 | usbhsg_ep_disable(&dcp->ep); |
829 | 824 | ||
830 | dev_dbg(dev, "stop gadget\n"); | 825 | dev_dbg(dev, "stop gadget\n"); |
831 | 826 | ||
@@ -998,6 +993,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) | |||
998 | */ | 993 | */ |
999 | usbhsg_for_each_uep_with_dcp(uep, gpriv, i) { | 994 | usbhsg_for_each_uep_with_dcp(uep, gpriv, i) { |
1000 | uep->gpriv = gpriv; | 995 | uep->gpriv = gpriv; |
996 | uep->pipe = NULL; | ||
1001 | snprintf(uep->ep_name, EP_NAME_SIZE, "ep%d", i); | 997 | snprintf(uep->ep_name, EP_NAME_SIZE, "ep%d", i); |
1002 | 998 | ||
1003 | uep->ep.name = uep->ep_name; | 999 | uep->ep.name = uep->ep_name; |
diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 3d3cd6ca2689..b86815421c8d 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c | |||
@@ -661,9 +661,10 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) | |||
661 | status = -ESHUTDOWN; | 661 | status = -ESHUTDOWN; |
662 | 662 | ||
663 | urb->actual_length = pkt->actual; | 663 | urb->actual_length = pkt->actual; |
664 | usbhsh_ureq_free(hpriv, ureq); | ||
665 | 664 | ||
666 | usbhsh_endpoint_sequence_save(hpriv, urb, pkt); | 665 | usbhsh_endpoint_sequence_save(hpriv, urb, pkt); |
666 | usbhsh_ureq_free(hpriv, ureq); | ||
667 | |||
667 | usbhsh_pipe_detach(hpriv, usbhsh_ep_to_uep(urb->ep)); | 668 | usbhsh_pipe_detach(hpriv, usbhsh_ep_to_uep(urb->ep)); |
668 | 669 | ||
669 | usb_hcd_unlink_urb_from_ep(hcd, urb); | 670 | usb_hcd_unlink_urb_from_ep(hcd, urb); |
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 0a373b3ae96a..ba68835d06a6 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
@@ -875,6 +875,8 @@ static struct usb_device_id id_table_combined [] = { | |||
875 | { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID), | 875 | { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID), |
876 | .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, | 876 | .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, |
877 | { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) }, | 877 | { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) }, |
878 | /* Crucible Devices */ | ||
879 | { USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) }, | ||
878 | { }, /* Optional parameter entry */ | 880 | { }, /* Optional parameter entry */ |
879 | { } /* Terminating entry */ | 881 | { } /* Terminating entry */ |
880 | }; | 882 | }; |
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 049b6e715fa4..fa5d56038276 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h | |||
@@ -1259,3 +1259,9 @@ | |||
1259 | * ATI command output: Cinterion MC55i | 1259 | * ATI command output: Cinterion MC55i |
1260 | */ | 1260 | */ |
1261 | #define FTDI_CINTERION_MC55I_PID 0xA951 | 1261 | #define FTDI_CINTERION_MC55I_PID 0xA951 |
1262 | |||
1263 | /* | ||
1264 | * Product: Comet Caller ID decoder | ||
1265 | * Manufacturer: Crucible Technologies | ||
1266 | */ | ||
1267 | #define FTDI_CT_COMET_PID 0x8e08 | ||
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index e6f87b76c715..478adcfcdf26 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c | |||
@@ -288,6 +288,7 @@ static void option_instat_callback(struct urb *urb); | |||
288 | #define ALCATEL_VENDOR_ID 0x1bbb | 288 | #define ALCATEL_VENDOR_ID 0x1bbb |
289 | #define ALCATEL_PRODUCT_X060S_X200 0x0000 | 289 | #define ALCATEL_PRODUCT_X060S_X200 0x0000 |
290 | #define ALCATEL_PRODUCT_X220_X500D 0x0017 | 290 | #define ALCATEL_PRODUCT_X220_X500D 0x0017 |
291 | #define ALCATEL_PRODUCT_L100V 0x011e | ||
291 | 292 | ||
292 | #define PIRELLI_VENDOR_ID 0x1266 | 293 | #define PIRELLI_VENDOR_ID 0x1266 |
293 | #define PIRELLI_PRODUCT_C100_1 0x1002 | 294 | #define PIRELLI_PRODUCT_C100_1 0x1002 |
@@ -429,9 +430,12 @@ static void option_instat_callback(struct urb *urb); | |||
429 | #define MEDIATEK_VENDOR_ID 0x0e8d | 430 | #define MEDIATEK_VENDOR_ID 0x0e8d |
430 | #define MEDIATEK_PRODUCT_DC_1COM 0x00a0 | 431 | #define MEDIATEK_PRODUCT_DC_1COM 0x00a0 |
431 | #define MEDIATEK_PRODUCT_DC_4COM 0x00a5 | 432 | #define MEDIATEK_PRODUCT_DC_4COM 0x00a5 |
433 | #define MEDIATEK_PRODUCT_DC_4COM2 0x00a7 | ||
432 | #define MEDIATEK_PRODUCT_DC_5COM 0x00a4 | 434 | #define MEDIATEK_PRODUCT_DC_5COM 0x00a4 |
433 | #define MEDIATEK_PRODUCT_7208_1COM 0x7101 | 435 | #define MEDIATEK_PRODUCT_7208_1COM 0x7101 |
434 | #define MEDIATEK_PRODUCT_7208_2COM 0x7102 | 436 | #define MEDIATEK_PRODUCT_7208_2COM 0x7102 |
437 | #define MEDIATEK_PRODUCT_7103_2COM 0x7103 | ||
438 | #define MEDIATEK_PRODUCT_7106_2COM 0x7106 | ||
435 | #define MEDIATEK_PRODUCT_FP_1COM 0x0003 | 439 | #define MEDIATEK_PRODUCT_FP_1COM 0x0003 |
436 | #define MEDIATEK_PRODUCT_FP_2COM 0x0023 | 440 | #define MEDIATEK_PRODUCT_FP_2COM 0x0023 |
437 | #define MEDIATEK_PRODUCT_FPDC_1COM 0x0043 | 441 | #define MEDIATEK_PRODUCT_FPDC_1COM 0x0043 |
@@ -441,6 +445,10 @@ static void option_instat_callback(struct urb *urb); | |||
441 | #define CELLIENT_VENDOR_ID 0x2692 | 445 | #define CELLIENT_VENDOR_ID 0x2692 |
442 | #define CELLIENT_PRODUCT_MEN200 0x9005 | 446 | #define CELLIENT_PRODUCT_MEN200 0x9005 |
443 | 447 | ||
448 | /* Hyundai Petatel Inc. products */ | ||
449 | #define PETATEL_VENDOR_ID 0x1ff4 | ||
450 | #define PETATEL_PRODUCT_NP10T 0x600e | ||
451 | |||
444 | /* some devices interfaces need special handling due to a number of reasons */ | 452 | /* some devices interfaces need special handling due to a number of reasons */ |
445 | enum option_blacklist_reason { | 453 | enum option_blacklist_reason { |
446 | OPTION_BLACKLIST_NONE = 0, | 454 | OPTION_BLACKLIST_NONE = 0, |
@@ -923,7 +931,8 @@ static const struct usb_device_id option_ids[] = { | |||
923 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0257, 0xff, 0xff, 0xff), /* ZTE MF821 */ | 931 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0257, 0xff, 0xff, 0xff), /* ZTE MF821 */ |
924 | .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, | 932 | .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, |
925 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0265, 0xff, 0xff, 0xff) }, | 933 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0265, 0xff, 0xff, 0xff) }, |
926 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0284, 0xff, 0xff, 0xff) }, | 934 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0284, 0xff, 0xff, 0xff), /* ZTE MF880 */ |
935 | .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, | ||
927 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0317, 0xff, 0xff, 0xff) }, | 936 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0317, 0xff, 0xff, 0xff) }, |
928 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0326, 0xff, 0xff, 0xff), | 937 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0326, 0xff, 0xff, 0xff), |
929 | .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, | 938 | .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, |
@@ -1190,6 +1199,8 @@ static const struct usb_device_id option_ids[] = { | |||
1190 | .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist | 1199 | .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist |
1191 | }, | 1200 | }, |
1192 | { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D) }, | 1201 | { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D) }, |
1202 | { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L100V), | ||
1203 | .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, | ||
1193 | { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) }, | 1204 | { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) }, |
1194 | { USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) }, | 1205 | { USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) }, |
1195 | { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14), | 1206 | { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14), |
@@ -1294,7 +1305,12 @@ static const struct usb_device_id option_ids[] = { | |||
1294 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_2COM, 0x0a, 0x00, 0x00) }, | 1305 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_2COM, 0x0a, 0x00, 0x00) }, |
1295 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) }, | 1306 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) }, |
1296 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) }, | 1307 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) }, |
1308 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7103_2COM, 0xff, 0x00, 0x00) }, | ||
1309 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7106_2COM, 0x02, 0x02, 0x01) }, | ||
1310 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x02, 0x01) }, | ||
1311 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x00, 0x00) }, | ||
1297 | { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) }, | 1312 | { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) }, |
1313 | { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T) }, | ||
1298 | { } /* Terminating entry */ | 1314 | { } /* Terminating entry */ |
1299 | }; | 1315 | }; |
1300 | MODULE_DEVICE_TABLE(usb, option_ids); | 1316 | MODULE_DEVICE_TABLE(usb, option_ids); |
diff --git a/drivers/video/ssd1307fb.c b/drivers/video/ssd1307fb.c index 4d99dd7a6831..395cb6a8d8f3 100644 --- a/drivers/video/ssd1307fb.c +++ b/drivers/video/ssd1307fb.c | |||
@@ -145,8 +145,8 @@ static void ssd1307fb_update_display(struct ssd1307fb_par *par) | |||
145 | u32 page_length = SSD1307FB_WIDTH * i; | 145 | u32 page_length = SSD1307FB_WIDTH * i; |
146 | u32 index = page_length + (SSD1307FB_WIDTH * k + j) / 8; | 146 | u32 index = page_length + (SSD1307FB_WIDTH * k + j) / 8; |
147 | u8 byte = *(vmem + index); | 147 | u8 byte = *(vmem + index); |
148 | u8 bit = byte & (1 << (7 - (j % 8))); | 148 | u8 bit = byte & (1 << (j % 8)); |
149 | bit = bit >> (7 - (j % 8)); | 149 | bit = bit >> (j % 8); |
150 | buf |= bit << k; | 150 | buf |= bit << k; |
151 | } | 151 | } |
152 | ssd1307fb_write_data(par->client, buf); | 152 | ssd1307fb_write_data(par->client, buf); |
diff --git a/fs/buffer.c b/fs/buffer.c index c017a2dfb909..7a75c3e0fd58 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -2935,6 +2935,7 @@ static void guard_bh_eod(int rw, struct bio *bio, struct buffer_head *bh) | |||
2935 | void *kaddr = kmap_atomic(bh->b_page); | 2935 | void *kaddr = kmap_atomic(bh->b_page); |
2936 | memset(kaddr + bh_offset(bh) + bytes, 0, bh->b_size - bytes); | 2936 | memset(kaddr + bh_offset(bh) + bytes, 0, bh->b_size - bytes); |
2937 | kunmap_atomic(kaddr); | 2937 | kunmap_atomic(kaddr); |
2938 | flush_dcache_page(bh->b_page); | ||
2938 | } | 2939 | } |
2939 | } | 2940 | } |
2940 | 2941 | ||
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 153bb1e42e63..a5f12b7e228d 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
@@ -176,7 +176,7 @@ static int debugfs_parse_options(char *data, struct debugfs_mount_opts *opts) | |||
176 | opts->uid = uid; | 176 | opts->uid = uid; |
177 | break; | 177 | break; |
178 | case Opt_gid: | 178 | case Opt_gid: |
179 | if (match_octal(&args[0], &option)) | 179 | if (match_int(&args[0], &option)) |
180 | return -EINVAL; | 180 | return -EINVAL; |
181 | gid = make_kgid(current_user_ns(), option); | 181 | gid = make_kgid(current_user_ns(), option); |
182 | if (!gid_valid(gid)) | 182 | if (!gid_valid(gid)) |
@@ -434,8 +434,9 @@ static int count(struct user_arg_ptr argv, int max) | |||
434 | if (IS_ERR(p)) | 434 | if (IS_ERR(p)) |
435 | return -EFAULT; | 435 | return -EFAULT; |
436 | 436 | ||
437 | if (i++ >= max) | 437 | if (i >= max) |
438 | return -E2BIG; | 438 | return -E2BIG; |
439 | ++i; | ||
439 | 440 | ||
440 | if (fatal_signal_pending(current)) | 441 | if (fatal_signal_pending(current)) |
441 | return -ERESTARTNOHAND; | 442 | return -ERESTARTNOHAND; |
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index a2862339323b..81cc7eaff863 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c | |||
@@ -446,7 +446,8 @@ int __log_start_commit(journal_t *journal, tid_t target) | |||
446 | * currently running transaction (if it exists). Otherwise, | 446 | * currently running transaction (if it exists). Otherwise, |
447 | * the target tid must be an old one. | 447 | * the target tid must be an old one. |
448 | */ | 448 | */ |
449 | if (journal->j_running_transaction && | 449 | if (journal->j_commit_request != target && |
450 | journal->j_running_transaction && | ||
450 | journal->j_running_transaction->t_tid == target) { | 451 | journal->j_running_transaction->t_tid == target) { |
451 | /* | 452 | /* |
452 | * We want a new commit: OK, mark the request and wakeup the | 453 | * We want a new commit: OK, mark the request and wakeup the |
diff --git a/fs/seq_file.c b/fs/seq_file.c index 9d863fb501f9..f2bc3dfd0b88 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c | |||
@@ -296,7 +296,7 @@ EXPORT_SYMBOL(seq_read); | |||
296 | * seq_lseek - ->llseek() method for sequential files. | 296 | * seq_lseek - ->llseek() method for sequential files. |
297 | * @file: the file in question | 297 | * @file: the file in question |
298 | * @offset: new position | 298 | * @offset: new position |
299 | * @origin: 0 for absolute, 1 for relative position | 299 | * @whence: 0 for absolute, 1 for relative position |
300 | * | 300 | * |
301 | * Ready-made ->f_op->llseek() | 301 | * Ready-made ->f_op->llseek() |
302 | */ | 302 | */ |
diff --git a/fs/udf/super.c b/fs/udf/super.c index d44fb568abe1..e9be396a558d 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c | |||
@@ -307,7 +307,8 @@ static void udf_sb_free_partitions(struct super_block *sb) | |||
307 | { | 307 | { |
308 | struct udf_sb_info *sbi = UDF_SB(sb); | 308 | struct udf_sb_info *sbi = UDF_SB(sb); |
309 | int i; | 309 | int i; |
310 | 310 | if (sbi->s_partmaps == NULL) | |
311 | return; | ||
311 | for (i = 0; i < sbi->s_partitions; i++) | 312 | for (i = 0; i < sbi->s_partitions; i++) |
312 | udf_free_partition(&sbi->s_partmaps[i]); | 313 | udf_free_partition(&sbi->s_partmaps[i]); |
313 | kfree(sbi->s_partmaps); | 314 | kfree(sbi->s_partmaps); |
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index 26673a0b20e7..56d1614760cf 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c | |||
@@ -175,7 +175,7 @@ xfs_buf_get_maps( | |||
175 | bp->b_map_count = map_count; | 175 | bp->b_map_count = map_count; |
176 | 176 | ||
177 | if (map_count == 1) { | 177 | if (map_count == 1) { |
178 | bp->b_maps = &bp->b_map; | 178 | bp->b_maps = &bp->__b_map; |
179 | return 0; | 179 | return 0; |
180 | } | 180 | } |
181 | 181 | ||
@@ -193,7 +193,7 @@ static void | |||
193 | xfs_buf_free_maps( | 193 | xfs_buf_free_maps( |
194 | struct xfs_buf *bp) | 194 | struct xfs_buf *bp) |
195 | { | 195 | { |
196 | if (bp->b_maps != &bp->b_map) { | 196 | if (bp->b_maps != &bp->__b_map) { |
197 | kmem_free(bp->b_maps); | 197 | kmem_free(bp->b_maps); |
198 | bp->b_maps = NULL; | 198 | bp->b_maps = NULL; |
199 | } | 199 | } |
@@ -377,8 +377,8 @@ xfs_buf_allocate_memory( | |||
377 | } | 377 | } |
378 | 378 | ||
379 | use_alloc_page: | 379 | use_alloc_page: |
380 | start = BBTOB(bp->b_map.bm_bn) >> PAGE_SHIFT; | 380 | start = BBTOB(bp->b_maps[0].bm_bn) >> PAGE_SHIFT; |
381 | end = (BBTOB(bp->b_map.bm_bn + bp->b_length) + PAGE_SIZE - 1) | 381 | end = (BBTOB(bp->b_maps[0].bm_bn + bp->b_length) + PAGE_SIZE - 1) |
382 | >> PAGE_SHIFT; | 382 | >> PAGE_SHIFT; |
383 | page_count = end - start; | 383 | page_count = end - start; |
384 | error = _xfs_buf_get_pages(bp, page_count, flags); | 384 | error = _xfs_buf_get_pages(bp, page_count, flags); |
@@ -640,7 +640,7 @@ _xfs_buf_read( | |||
640 | xfs_buf_flags_t flags) | 640 | xfs_buf_flags_t flags) |
641 | { | 641 | { |
642 | ASSERT(!(flags & XBF_WRITE)); | 642 | ASSERT(!(flags & XBF_WRITE)); |
643 | ASSERT(bp->b_map.bm_bn != XFS_BUF_DADDR_NULL); | 643 | ASSERT(bp->b_maps[0].bm_bn != XFS_BUF_DADDR_NULL); |
644 | 644 | ||
645 | bp->b_flags &= ~(XBF_WRITE | XBF_ASYNC | XBF_READ_AHEAD); | 645 | bp->b_flags &= ~(XBF_WRITE | XBF_ASYNC | XBF_READ_AHEAD); |
646 | bp->b_flags |= flags & (XBF_READ | XBF_ASYNC | XBF_READ_AHEAD); | 646 | bp->b_flags |= flags & (XBF_READ | XBF_ASYNC | XBF_READ_AHEAD); |
@@ -1709,7 +1709,7 @@ xfs_buf_cmp( | |||
1709 | struct xfs_buf *bp = container_of(b, struct xfs_buf, b_list); | 1709 | struct xfs_buf *bp = container_of(b, struct xfs_buf, b_list); |
1710 | xfs_daddr_t diff; | 1710 | xfs_daddr_t diff; |
1711 | 1711 | ||
1712 | diff = ap->b_map.bm_bn - bp->b_map.bm_bn; | 1712 | diff = ap->b_maps[0].bm_bn - bp->b_maps[0].bm_bn; |
1713 | if (diff < 0) | 1713 | if (diff < 0) |
1714 | return -1; | 1714 | return -1; |
1715 | if (diff > 0) | 1715 | if (diff > 0) |
diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h index 23f5642480bb..433a12ed7b17 100644 --- a/fs/xfs/xfs_buf.h +++ b/fs/xfs/xfs_buf.h | |||
@@ -151,7 +151,7 @@ typedef struct xfs_buf { | |||
151 | struct page **b_pages; /* array of page pointers */ | 151 | struct page **b_pages; /* array of page pointers */ |
152 | struct page *b_page_array[XB_PAGES]; /* inline pages */ | 152 | struct page *b_page_array[XB_PAGES]; /* inline pages */ |
153 | struct xfs_buf_map *b_maps; /* compound buffer map */ | 153 | struct xfs_buf_map *b_maps; /* compound buffer map */ |
154 | struct xfs_buf_map b_map; /* inline compound buffer map */ | 154 | struct xfs_buf_map __b_map; /* inline compound buffer map */ |
155 | int b_map_count; | 155 | int b_map_count; |
156 | int b_io_length; /* IO size in BBs */ | 156 | int b_io_length; /* IO size in BBs */ |
157 | atomic_t b_pin_count; /* pin count */ | 157 | atomic_t b_pin_count; /* pin count */ |
@@ -330,8 +330,8 @@ void xfs_buf_stale(struct xfs_buf *bp); | |||
330 | * In future, uncached buffers will pass the block number directly to the io | 330 | * In future, uncached buffers will pass the block number directly to the io |
331 | * request function and hence these macros will go away at that point. | 331 | * request function and hence these macros will go away at that point. |
332 | */ | 332 | */ |
333 | #define XFS_BUF_ADDR(bp) ((bp)->b_map.bm_bn) | 333 | #define XFS_BUF_ADDR(bp) ((bp)->b_maps[0].bm_bn) |
334 | #define XFS_BUF_SET_ADDR(bp, bno) ((bp)->b_map.bm_bn = (xfs_daddr_t)(bno)) | 334 | #define XFS_BUF_SET_ADDR(bp, bno) ((bp)->b_maps[0].bm_bn = (xfs_daddr_t)(bno)) |
335 | 335 | ||
336 | static inline void xfs_buf_set_ref(struct xfs_buf *bp, int lru_ref) | 336 | static inline void xfs_buf_set_ref(struct xfs_buf *bp, int lru_ref) |
337 | { | 337 | { |
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index becf4a97efc6..77b09750e92c 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c | |||
@@ -71,7 +71,7 @@ xfs_buf_item_log_debug( | |||
71 | chunk_num = byte >> XFS_BLF_SHIFT; | 71 | chunk_num = byte >> XFS_BLF_SHIFT; |
72 | word_num = chunk_num >> BIT_TO_WORD_SHIFT; | 72 | word_num = chunk_num >> BIT_TO_WORD_SHIFT; |
73 | bit_num = chunk_num & (NBWORD - 1); | 73 | bit_num = chunk_num & (NBWORD - 1); |
74 | wordp = &(bip->bli_format.blf_data_map[word_num]); | 74 | wordp = &(bip->__bli_format.blf_data_map[word_num]); |
75 | bit_set = *wordp & (1 << bit_num); | 75 | bit_set = *wordp & (1 << bit_num); |
76 | ASSERT(bit_set); | 76 | ASSERT(bit_set); |
77 | byte++; | 77 | byte++; |
@@ -237,7 +237,7 @@ xfs_buf_item_size( | |||
237 | * cancel flag in it. | 237 | * cancel flag in it. |
238 | */ | 238 | */ |
239 | trace_xfs_buf_item_size_stale(bip); | 239 | trace_xfs_buf_item_size_stale(bip); |
240 | ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL); | 240 | ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL); |
241 | return bip->bli_format_count; | 241 | return bip->bli_format_count; |
242 | } | 242 | } |
243 | 243 | ||
@@ -278,7 +278,7 @@ xfs_buf_item_format_segment( | |||
278 | uint buffer_offset; | 278 | uint buffer_offset; |
279 | 279 | ||
280 | /* copy the flags across from the base format item */ | 280 | /* copy the flags across from the base format item */ |
281 | blfp->blf_flags = bip->bli_format.blf_flags; | 281 | blfp->blf_flags = bip->__bli_format.blf_flags; |
282 | 282 | ||
283 | /* | 283 | /* |
284 | * Base size is the actual size of the ondisk structure - it reflects | 284 | * Base size is the actual size of the ondisk structure - it reflects |
@@ -287,6 +287,17 @@ xfs_buf_item_format_segment( | |||
287 | */ | 287 | */ |
288 | base_size = offsetof(struct xfs_buf_log_format, blf_data_map) + | 288 | base_size = offsetof(struct xfs_buf_log_format, blf_data_map) + |
289 | (blfp->blf_map_size * sizeof(blfp->blf_data_map[0])); | 289 | (blfp->blf_map_size * sizeof(blfp->blf_data_map[0])); |
290 | |||
291 | nvecs = 0; | ||
292 | first_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size, 0); | ||
293 | if (!(bip->bli_flags & XFS_BLI_STALE) && first_bit == -1) { | ||
294 | /* | ||
295 | * If the map is not be dirty in the transaction, mark | ||
296 | * the size as zero and do not advance the vector pointer. | ||
297 | */ | ||
298 | goto out; | ||
299 | } | ||
300 | |||
290 | vecp->i_addr = blfp; | 301 | vecp->i_addr = blfp; |
291 | vecp->i_len = base_size; | 302 | vecp->i_len = base_size; |
292 | vecp->i_type = XLOG_REG_TYPE_BFORMAT; | 303 | vecp->i_type = XLOG_REG_TYPE_BFORMAT; |
@@ -301,15 +312,13 @@ xfs_buf_item_format_segment( | |||
301 | */ | 312 | */ |
302 | trace_xfs_buf_item_format_stale(bip); | 313 | trace_xfs_buf_item_format_stale(bip); |
303 | ASSERT(blfp->blf_flags & XFS_BLF_CANCEL); | 314 | ASSERT(blfp->blf_flags & XFS_BLF_CANCEL); |
304 | blfp->blf_size = nvecs; | 315 | goto out; |
305 | return vecp; | ||
306 | } | 316 | } |
307 | 317 | ||
308 | /* | 318 | /* |
309 | * Fill in an iovec for each set of contiguous chunks. | 319 | * Fill in an iovec for each set of contiguous chunks. |
310 | */ | 320 | */ |
311 | first_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size, 0); | 321 | |
312 | ASSERT(first_bit != -1); | ||
313 | last_bit = first_bit; | 322 | last_bit = first_bit; |
314 | nbits = 1; | 323 | nbits = 1; |
315 | for (;;) { | 324 | for (;;) { |
@@ -371,7 +380,8 @@ xfs_buf_item_format_segment( | |||
371 | nbits++; | 380 | nbits++; |
372 | } | 381 | } |
373 | } | 382 | } |
374 | bip->bli_format.blf_size = nvecs; | 383 | out: |
384 | blfp->blf_size = nvecs; | ||
375 | return vecp; | 385 | return vecp; |
376 | } | 386 | } |
377 | 387 | ||
@@ -405,7 +415,7 @@ xfs_buf_item_format( | |||
405 | if (bip->bli_flags & XFS_BLI_INODE_BUF) { | 415 | if (bip->bli_flags & XFS_BLI_INODE_BUF) { |
406 | if (!((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) && | 416 | if (!((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) && |
407 | xfs_log_item_in_current_chkpt(lip))) | 417 | xfs_log_item_in_current_chkpt(lip))) |
408 | bip->bli_format.blf_flags |= XFS_BLF_INODE_BUF; | 418 | bip->__bli_format.blf_flags |= XFS_BLF_INODE_BUF; |
409 | bip->bli_flags &= ~XFS_BLI_INODE_BUF; | 419 | bip->bli_flags &= ~XFS_BLI_INODE_BUF; |
410 | } | 420 | } |
411 | 421 | ||
@@ -485,7 +495,7 @@ xfs_buf_item_unpin( | |||
485 | ASSERT(bip->bli_flags & XFS_BLI_STALE); | 495 | ASSERT(bip->bli_flags & XFS_BLI_STALE); |
486 | ASSERT(xfs_buf_islocked(bp)); | 496 | ASSERT(xfs_buf_islocked(bp)); |
487 | ASSERT(XFS_BUF_ISSTALE(bp)); | 497 | ASSERT(XFS_BUF_ISSTALE(bp)); |
488 | ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL); | 498 | ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL); |
489 | 499 | ||
490 | trace_xfs_buf_item_unpin_stale(bip); | 500 | trace_xfs_buf_item_unpin_stale(bip); |
491 | 501 | ||
@@ -601,7 +611,7 @@ xfs_buf_item_unlock( | |||
601 | { | 611 | { |
602 | struct xfs_buf_log_item *bip = BUF_ITEM(lip); | 612 | struct xfs_buf_log_item *bip = BUF_ITEM(lip); |
603 | struct xfs_buf *bp = bip->bli_buf; | 613 | struct xfs_buf *bp = bip->bli_buf; |
604 | int aborted; | 614 | int aborted, clean, i; |
605 | uint hold; | 615 | uint hold; |
606 | 616 | ||
607 | /* Clear the buffer's association with this transaction. */ | 617 | /* Clear the buffer's association with this transaction. */ |
@@ -631,7 +641,7 @@ xfs_buf_item_unlock( | |||
631 | */ | 641 | */ |
632 | if (bip->bli_flags & XFS_BLI_STALE) { | 642 | if (bip->bli_flags & XFS_BLI_STALE) { |
633 | trace_xfs_buf_item_unlock_stale(bip); | 643 | trace_xfs_buf_item_unlock_stale(bip); |
634 | ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL); | 644 | ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL); |
635 | if (!aborted) { | 645 | if (!aborted) { |
636 | atomic_dec(&bip->bli_refcount); | 646 | atomic_dec(&bip->bli_refcount); |
637 | return; | 647 | return; |
@@ -644,8 +654,15 @@ xfs_buf_item_unlock( | |||
644 | * If the buf item isn't tracking any data, free it, otherwise drop the | 654 | * If the buf item isn't tracking any data, free it, otherwise drop the |
645 | * reference we hold to it. | 655 | * reference we hold to it. |
646 | */ | 656 | */ |
647 | if (xfs_bitmap_empty(bip->bli_format.blf_data_map, | 657 | clean = 1; |
648 | bip->bli_format.blf_map_size)) | 658 | for (i = 0; i < bip->bli_format_count; i++) { |
659 | if (!xfs_bitmap_empty(bip->bli_formats[i].blf_data_map, | ||
660 | bip->bli_formats[i].blf_map_size)) { | ||
661 | clean = 0; | ||
662 | break; | ||
663 | } | ||
664 | } | ||
665 | if (clean) | ||
649 | xfs_buf_item_relse(bp); | 666 | xfs_buf_item_relse(bp); |
650 | else | 667 | else |
651 | atomic_dec(&bip->bli_refcount); | 668 | atomic_dec(&bip->bli_refcount); |
@@ -716,7 +733,7 @@ xfs_buf_item_get_format( | |||
716 | bip->bli_format_count = count; | 733 | bip->bli_format_count = count; |
717 | 734 | ||
718 | if (count == 1) { | 735 | if (count == 1) { |
719 | bip->bli_formats = &bip->bli_format; | 736 | bip->bli_formats = &bip->__bli_format; |
720 | return 0; | 737 | return 0; |
721 | } | 738 | } |
722 | 739 | ||
@@ -731,7 +748,7 @@ STATIC void | |||
731 | xfs_buf_item_free_format( | 748 | xfs_buf_item_free_format( |
732 | struct xfs_buf_log_item *bip) | 749 | struct xfs_buf_log_item *bip) |
733 | { | 750 | { |
734 | if (bip->bli_formats != &bip->bli_format) { | 751 | if (bip->bli_formats != &bip->__bli_format) { |
735 | kmem_free(bip->bli_formats); | 752 | kmem_free(bip->bli_formats); |
736 | bip->bli_formats = NULL; | 753 | bip->bli_formats = NULL; |
737 | } | 754 | } |
diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h index 6850f49f4af3..16def435944a 100644 --- a/fs/xfs/xfs_buf_item.h +++ b/fs/xfs/xfs_buf_item.h | |||
@@ -104,7 +104,7 @@ typedef struct xfs_buf_log_item { | |||
104 | #endif | 104 | #endif |
105 | int bli_format_count; /* count of headers */ | 105 | int bli_format_count; /* count of headers */ |
106 | struct xfs_buf_log_format *bli_formats; /* array of in-log header ptrs */ | 106 | struct xfs_buf_log_format *bli_formats; /* array of in-log header ptrs */ |
107 | struct xfs_buf_log_format bli_format; /* embedded in-log header */ | 107 | struct xfs_buf_log_format __bli_format; /* embedded in-log header */ |
108 | } xfs_buf_log_item_t; | 108 | } xfs_buf_log_item_t; |
109 | 109 | ||
110 | void xfs_buf_item_init(struct xfs_buf *, struct xfs_mount *); | 110 | void xfs_buf_item_init(struct xfs_buf *, struct xfs_mount *); |
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c index 7536faaa61e7..12afe07a91d7 100644 --- a/fs/xfs/xfs_dir2_block.c +++ b/fs/xfs/xfs_dir2_block.c | |||
@@ -355,10 +355,12 @@ xfs_dir2_block_addname( | |||
355 | /* | 355 | /* |
356 | * If need to compact the leaf entries, do it now. | 356 | * If need to compact the leaf entries, do it now. |
357 | */ | 357 | */ |
358 | if (compact) | 358 | if (compact) { |
359 | xfs_dir2_block_compact(tp, bp, hdr, btp, blp, &needlog, | 359 | xfs_dir2_block_compact(tp, bp, hdr, btp, blp, &needlog, |
360 | &lfloghigh, &lfloglow); | 360 | &lfloghigh, &lfloglow); |
361 | else if (btp->stale) { | 361 | /* recalculate blp post-compaction */ |
362 | blp = xfs_dir2_block_leaf_p(btp); | ||
363 | } else if (btp->stale) { | ||
362 | /* | 364 | /* |
363 | * Set leaf logging boundaries to impossible state. | 365 | * Set leaf logging boundaries to impossible state. |
364 | * For the no-stale case they're set explicitly. | 366 | * For the no-stale case they're set explicitly. |
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c index 5f53e75409b8..8a59f8546552 100644 --- a/fs/xfs/xfs_qm_syscalls.c +++ b/fs/xfs/xfs_qm_syscalls.c | |||
@@ -784,11 +784,11 @@ xfs_qm_scall_getquota( | |||
784 | (XFS_IS_OQUOTA_ENFORCED(mp) && | 784 | (XFS_IS_OQUOTA_ENFORCED(mp) && |
785 | (dst->d_flags & (FS_PROJ_QUOTA | FS_GROUP_QUOTA)))) && | 785 | (dst->d_flags & (FS_PROJ_QUOTA | FS_GROUP_QUOTA)))) && |
786 | dst->d_id != 0) { | 786 | dst->d_id != 0) { |
787 | if (((int) dst->d_bcount > (int) dst->d_blk_softlimit) && | 787 | if ((dst->d_bcount > dst->d_blk_softlimit) && |
788 | (dst->d_blk_softlimit > 0)) { | 788 | (dst->d_blk_softlimit > 0)) { |
789 | ASSERT(dst->d_btimer != 0); | 789 | ASSERT(dst->d_btimer != 0); |
790 | } | 790 | } |
791 | if (((int) dst->d_icount > (int) dst->d_ino_softlimit) && | 791 | if ((dst->d_icount > dst->d_ino_softlimit) && |
792 | (dst->d_ino_softlimit > 0)) { | 792 | (dst->d_ino_softlimit > 0)) { |
793 | ASSERT(dst->d_itimer != 0); | 793 | ASSERT(dst->d_itimer != 0); |
794 | } | 794 | } |
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c index 4fc17d479d42..3edf5dbee001 100644 --- a/fs/xfs/xfs_trans_buf.c +++ b/fs/xfs/xfs_trans_buf.c | |||
@@ -93,7 +93,7 @@ _xfs_trans_bjoin( | |||
93 | xfs_buf_item_init(bp, tp->t_mountp); | 93 | xfs_buf_item_init(bp, tp->t_mountp); |
94 | bip = bp->b_fspriv; | 94 | bip = bp->b_fspriv; |
95 | ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); | 95 | ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); |
96 | ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_CANCEL)); | 96 | ASSERT(!(bip->__bli_format.blf_flags & XFS_BLF_CANCEL)); |
97 | ASSERT(!(bip->bli_flags & XFS_BLI_LOGGED)); | 97 | ASSERT(!(bip->bli_flags & XFS_BLI_LOGGED)); |
98 | if (reset_recur) | 98 | if (reset_recur) |
99 | bip->bli_recur = 0; | 99 | bip->bli_recur = 0; |
@@ -432,7 +432,7 @@ xfs_trans_brelse(xfs_trans_t *tp, | |||
432 | bip = bp->b_fspriv; | 432 | bip = bp->b_fspriv; |
433 | ASSERT(bip->bli_item.li_type == XFS_LI_BUF); | 433 | ASSERT(bip->bli_item.li_type == XFS_LI_BUF); |
434 | ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); | 434 | ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); |
435 | ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_CANCEL)); | 435 | ASSERT(!(bip->__bli_format.blf_flags & XFS_BLF_CANCEL)); |
436 | ASSERT(atomic_read(&bip->bli_refcount) > 0); | 436 | ASSERT(atomic_read(&bip->bli_refcount) > 0); |
437 | 437 | ||
438 | trace_xfs_trans_brelse(bip); | 438 | trace_xfs_trans_brelse(bip); |
@@ -519,7 +519,7 @@ xfs_trans_bhold(xfs_trans_t *tp, | |||
519 | ASSERT(bp->b_transp == tp); | 519 | ASSERT(bp->b_transp == tp); |
520 | ASSERT(bip != NULL); | 520 | ASSERT(bip != NULL); |
521 | ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); | 521 | ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); |
522 | ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_CANCEL)); | 522 | ASSERT(!(bip->__bli_format.blf_flags & XFS_BLF_CANCEL)); |
523 | ASSERT(atomic_read(&bip->bli_refcount) > 0); | 523 | ASSERT(atomic_read(&bip->bli_refcount) > 0); |
524 | 524 | ||
525 | bip->bli_flags |= XFS_BLI_HOLD; | 525 | bip->bli_flags |= XFS_BLI_HOLD; |
@@ -539,7 +539,7 @@ xfs_trans_bhold_release(xfs_trans_t *tp, | |||
539 | ASSERT(bp->b_transp == tp); | 539 | ASSERT(bp->b_transp == tp); |
540 | ASSERT(bip != NULL); | 540 | ASSERT(bip != NULL); |
541 | ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); | 541 | ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); |
542 | ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_CANCEL)); | 542 | ASSERT(!(bip->__bli_format.blf_flags & XFS_BLF_CANCEL)); |
543 | ASSERT(atomic_read(&bip->bli_refcount) > 0); | 543 | ASSERT(atomic_read(&bip->bli_refcount) > 0); |
544 | ASSERT(bip->bli_flags & XFS_BLI_HOLD); | 544 | ASSERT(bip->bli_flags & XFS_BLI_HOLD); |
545 | 545 | ||
@@ -598,7 +598,7 @@ xfs_trans_log_buf(xfs_trans_t *tp, | |||
598 | bip->bli_flags &= ~XFS_BLI_STALE; | 598 | bip->bli_flags &= ~XFS_BLI_STALE; |
599 | ASSERT(XFS_BUF_ISSTALE(bp)); | 599 | ASSERT(XFS_BUF_ISSTALE(bp)); |
600 | XFS_BUF_UNSTALE(bp); | 600 | XFS_BUF_UNSTALE(bp); |
601 | bip->bli_format.blf_flags &= ~XFS_BLF_CANCEL; | 601 | bip->__bli_format.blf_flags &= ~XFS_BLF_CANCEL; |
602 | } | 602 | } |
603 | 603 | ||
604 | tp->t_flags |= XFS_TRANS_DIRTY; | 604 | tp->t_flags |= XFS_TRANS_DIRTY; |
@@ -643,6 +643,7 @@ xfs_trans_binval( | |||
643 | xfs_buf_t *bp) | 643 | xfs_buf_t *bp) |
644 | { | 644 | { |
645 | xfs_buf_log_item_t *bip = bp->b_fspriv; | 645 | xfs_buf_log_item_t *bip = bp->b_fspriv; |
646 | int i; | ||
646 | 647 | ||
647 | ASSERT(bp->b_transp == tp); | 648 | ASSERT(bp->b_transp == tp); |
648 | ASSERT(bip != NULL); | 649 | ASSERT(bip != NULL); |
@@ -657,8 +658,8 @@ xfs_trans_binval( | |||
657 | */ | 658 | */ |
658 | ASSERT(XFS_BUF_ISSTALE(bp)); | 659 | ASSERT(XFS_BUF_ISSTALE(bp)); |
659 | ASSERT(!(bip->bli_flags & (XFS_BLI_LOGGED | XFS_BLI_DIRTY))); | 660 | ASSERT(!(bip->bli_flags & (XFS_BLI_LOGGED | XFS_BLI_DIRTY))); |
660 | ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_INODE_BUF)); | 661 | ASSERT(!(bip->__bli_format.blf_flags & XFS_BLF_INODE_BUF)); |
661 | ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL); | 662 | ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL); |
662 | ASSERT(bip->bli_item.li_desc->lid_flags & XFS_LID_DIRTY); | 663 | ASSERT(bip->bli_item.li_desc->lid_flags & XFS_LID_DIRTY); |
663 | ASSERT(tp->t_flags & XFS_TRANS_DIRTY); | 664 | ASSERT(tp->t_flags & XFS_TRANS_DIRTY); |
664 | return; | 665 | return; |
@@ -668,10 +669,12 @@ xfs_trans_binval( | |||
668 | 669 | ||
669 | bip->bli_flags |= XFS_BLI_STALE; | 670 | bip->bli_flags |= XFS_BLI_STALE; |
670 | bip->bli_flags &= ~(XFS_BLI_INODE_BUF | XFS_BLI_LOGGED | XFS_BLI_DIRTY); | 671 | bip->bli_flags &= ~(XFS_BLI_INODE_BUF | XFS_BLI_LOGGED | XFS_BLI_DIRTY); |
671 | bip->bli_format.blf_flags &= ~XFS_BLF_INODE_BUF; | 672 | bip->__bli_format.blf_flags &= ~XFS_BLF_INODE_BUF; |
672 | bip->bli_format.blf_flags |= XFS_BLF_CANCEL; | 673 | bip->__bli_format.blf_flags |= XFS_BLF_CANCEL; |
673 | memset((char *)(bip->bli_format.blf_data_map), 0, | 674 | for (i = 0; i < bip->bli_format_count; i++) { |
674 | (bip->bli_format.blf_map_size * sizeof(uint))); | 675 | memset(bip->bli_formats[i].blf_data_map, 0, |
676 | (bip->bli_formats[i].blf_map_size * sizeof(uint))); | ||
677 | } | ||
675 | bip->bli_item.li_desc->lid_flags |= XFS_LID_DIRTY; | 678 | bip->bli_item.li_desc->lid_flags |= XFS_LID_DIRTY; |
676 | tp->t_flags |= XFS_TRANS_DIRTY; | 679 | tp->t_flags |= XFS_TRANS_DIRTY; |
677 | } | 680 | } |
@@ -775,5 +778,5 @@ xfs_trans_dquot_buf( | |||
775 | type == XFS_BLF_GDQUOT_BUF); | 778 | type == XFS_BLF_GDQUOT_BUF); |
776 | ASSERT(atomic_read(&bip->bli_refcount) > 0); | 779 | ASSERT(atomic_read(&bip->bli_refcount) > 0); |
777 | 780 | ||
778 | bip->bli_format.blf_flags |= type; | 781 | bip->__bli_format.blf_flags |= type; |
779 | } | 782 | } |
diff --git a/include/drm/drmP.h b/include/drm/drmP.h index fad21c927a38..e74731c1a912 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h | |||
@@ -446,7 +446,15 @@ struct drm_file { | |||
446 | int is_master; /* this file private is a master for a minor */ | 446 | int is_master; /* this file private is a master for a minor */ |
447 | struct drm_master *master; /* master this node is currently associated with | 447 | struct drm_master *master; /* master this node is currently associated with |
448 | N.B. not always minor->master */ | 448 | N.B. not always minor->master */ |
449 | |||
450 | /** | ||
451 | * fbs - List of framebuffers associated with this file. | ||
452 | * | ||
453 | * Protected by fbs_lock. Note that the fbs list holds a reference on | ||
454 | * the fb object to prevent it from untimely disappearing. | ||
455 | */ | ||
449 | struct list_head fbs; | 456 | struct list_head fbs; |
457 | struct mutex fbs_lock; | ||
450 | 458 | ||
451 | wait_queue_head_t event_wait; | 459 | wait_queue_head_t event_wait; |
452 | struct list_head event_list; | 460 | struct list_head event_list; |
@@ -1276,6 +1284,11 @@ static inline int drm_device_is_unplugged(struct drm_device *dev) | |||
1276 | return ret; | 1284 | return ret; |
1277 | } | 1285 | } |
1278 | 1286 | ||
1287 | static inline bool drm_modeset_is_locked(struct drm_device *dev) | ||
1288 | { | ||
1289 | return mutex_is_locked(&dev->mode_config.mutex); | ||
1290 | } | ||
1291 | |||
1279 | /******************************************************************/ | 1292 | /******************************************************************/ |
1280 | /** \name Internal function definitions */ | 1293 | /** \name Internal function definitions */ |
1281 | /*@{*/ | 1294 | /*@{*/ |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 00d78b5161c0..66b2732f175a 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -254,6 +254,10 @@ struct drm_framebuffer { | |||
254 | * userspace perspective. | 254 | * userspace perspective. |
255 | */ | 255 | */ |
256 | struct kref refcount; | 256 | struct kref refcount; |
257 | /* | ||
258 | * Place on the dev->mode_config.fb_list, access protected by | ||
259 | * dev->mode_config.fb_lock. | ||
260 | */ | ||
257 | struct list_head head; | 261 | struct list_head head; |
258 | struct drm_mode_object base; | 262 | struct drm_mode_object base; |
259 | const struct drm_framebuffer_funcs *funcs; | 263 | const struct drm_framebuffer_funcs *funcs; |
@@ -390,6 +394,15 @@ struct drm_crtc { | |||
390 | struct drm_device *dev; | 394 | struct drm_device *dev; |
391 | struct list_head head; | 395 | struct list_head head; |
392 | 396 | ||
397 | /** | ||
398 | * crtc mutex | ||
399 | * | ||
400 | * This provides a read lock for the overall crtc state (mode, dpms | ||
401 | * state, ...) and a write lock for everything which can be update | ||
402 | * without a full modeset (fb, cursor data, ...) | ||
403 | */ | ||
404 | struct mutex mutex; | ||
405 | |||
393 | struct drm_mode_object base; | 406 | struct drm_mode_object base; |
394 | 407 | ||
395 | /* framebuffer the connector is currently bound to */ | 408 | /* framebuffer the connector is currently bound to */ |
@@ -771,8 +784,18 @@ struct drm_mode_config { | |||
771 | struct mutex idr_mutex; /* for IDR management */ | 784 | struct mutex idr_mutex; /* for IDR management */ |
772 | struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */ | 785 | struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */ |
773 | /* this is limited to one for now */ | 786 | /* this is limited to one for now */ |
787 | |||
788 | |||
789 | /** | ||
790 | * fb_lock - mutex to protect fb state | ||
791 | * | ||
792 | * Besides the global fb list his also protects the fbs list in the | ||
793 | * file_priv | ||
794 | */ | ||
795 | struct mutex fb_lock; | ||
774 | int num_fb; | 796 | int num_fb; |
775 | struct list_head fb_list; | 797 | struct list_head fb_list; |
798 | |||
776 | int num_connector; | 799 | int num_connector; |
777 | struct list_head connector_list; | 800 | struct list_head connector_list; |
778 | int num_encoder; | 801 | int num_encoder; |
@@ -842,6 +865,9 @@ struct drm_prop_enum_list { | |||
842 | char *name; | 865 | char *name; |
843 | }; | 866 | }; |
844 | 867 | ||
868 | extern void drm_modeset_lock_all(struct drm_device *dev); | ||
869 | extern void drm_modeset_unlock_all(struct drm_device *dev); | ||
870 | |||
845 | extern int drm_crtc_init(struct drm_device *dev, | 871 | extern int drm_crtc_init(struct drm_device *dev, |
846 | struct drm_crtc *crtc, | 872 | struct drm_crtc *crtc, |
847 | const struct drm_crtc_funcs *funcs); | 873 | const struct drm_crtc_funcs *funcs); |
@@ -932,10 +958,13 @@ extern void drm_framebuffer_set_object(struct drm_device *dev, | |||
932 | extern int drm_framebuffer_init(struct drm_device *dev, | 958 | extern int drm_framebuffer_init(struct drm_device *dev, |
933 | struct drm_framebuffer *fb, | 959 | struct drm_framebuffer *fb, |
934 | const struct drm_framebuffer_funcs *funcs); | 960 | const struct drm_framebuffer_funcs *funcs); |
961 | extern struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, | ||
962 | uint32_t id); | ||
935 | extern void drm_framebuffer_unreference(struct drm_framebuffer *fb); | 963 | extern void drm_framebuffer_unreference(struct drm_framebuffer *fb); |
936 | extern void drm_framebuffer_reference(struct drm_framebuffer *fb); | 964 | extern void drm_framebuffer_reference(struct drm_framebuffer *fb); |
937 | extern void drm_framebuffer_remove(struct drm_framebuffer *fb); | 965 | extern void drm_framebuffer_remove(struct drm_framebuffer *fb); |
938 | extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb); | 966 | extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb); |
967 | extern void drm_framebuffer_unregister_private(struct drm_framebuffer *fb); | ||
939 | extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); | 968 | extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); |
940 | extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); | 969 | extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); |
941 | extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY); | 970 | extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY); |
@@ -985,6 +1014,7 @@ extern int drm_mode_getcrtc(struct drm_device *dev, | |||
985 | void *data, struct drm_file *file_priv); | 1014 | void *data, struct drm_file *file_priv); |
986 | extern int drm_mode_getconnector(struct drm_device *dev, | 1015 | extern int drm_mode_getconnector(struct drm_device *dev, |
987 | void *data, struct drm_file *file_priv); | 1016 | void *data, struct drm_file *file_priv); |
1017 | extern int drm_mode_set_config_internal(struct drm_mode_set *set); | ||
988 | extern int drm_mode_setcrtc(struct drm_device *dev, | 1018 | extern int drm_mode_setcrtc(struct drm_device *dev, |
989 | void *data, struct drm_file *file_priv); | 1019 | void *data, struct drm_file *file_priv); |
990 | extern int drm_mode_getplane(struct drm_device *dev, | 1020 | extern int drm_mode_getplane(struct drm_device *dev, |
diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h index 9b991f91d81b..88591ef8fa24 100644 --- a/include/drm/drm_mm.h +++ b/include/drm/drm_mm.h | |||
@@ -70,7 +70,7 @@ struct drm_mm { | |||
70 | unsigned long scan_color; | 70 | unsigned long scan_color; |
71 | unsigned long scan_size; | 71 | unsigned long scan_size; |
72 | unsigned long scan_hit_start; | 72 | unsigned long scan_hit_start; |
73 | unsigned scan_hit_size; | 73 | unsigned long scan_hit_end; |
74 | unsigned scanned_blocks; | 74 | unsigned scanned_blocks; |
75 | unsigned long scan_start; | 75 | unsigned long scan_start; |
76 | unsigned long scan_end; | 76 | unsigned long scan_end; |
diff --git a/include/linux/audit.h b/include/linux/audit.h index bce729afbcf9..5a6d718adf34 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
@@ -24,6 +24,7 @@ | |||
24 | #define _LINUX_AUDIT_H_ | 24 | #define _LINUX_AUDIT_H_ |
25 | 25 | ||
26 | #include <linux/sched.h> | 26 | #include <linux/sched.h> |
27 | #include <linux/ptrace.h> | ||
27 | #include <uapi/linux/audit.h> | 28 | #include <uapi/linux/audit.h> |
28 | 29 | ||
29 | struct audit_sig_info { | 30 | struct audit_sig_info { |
@@ -157,7 +158,8 @@ void audit_core_dumps(long signr); | |||
157 | 158 | ||
158 | static inline void audit_seccomp(unsigned long syscall, long signr, int code) | 159 | static inline void audit_seccomp(unsigned long syscall, long signr, int code) |
159 | { | 160 | { |
160 | if (unlikely(!audit_dummy_context())) | 161 | /* Force a record to be reported if a signal was delivered. */ |
162 | if (signr || unlikely(!audit_dummy_context())) | ||
161 | __audit_seccomp(syscall, signr, code); | 163 | __audit_seccomp(syscall, signr, code); |
162 | } | 164 | } |
163 | 165 | ||
diff --git a/include/linux/compaction.h b/include/linux/compaction.h index 6ecb6dc2f303..cc7bddeaf553 100644 --- a/include/linux/compaction.h +++ b/include/linux/compaction.h | |||
@@ -22,7 +22,7 @@ extern int sysctl_extfrag_handler(struct ctl_table *table, int write, | |||
22 | extern int fragmentation_index(struct zone *zone, unsigned int order); | 22 | extern int fragmentation_index(struct zone *zone, unsigned int order); |
23 | extern unsigned long try_to_compact_pages(struct zonelist *zonelist, | 23 | extern unsigned long try_to_compact_pages(struct zonelist *zonelist, |
24 | int order, gfp_t gfp_mask, nodemask_t *mask, | 24 | int order, gfp_t gfp_mask, nodemask_t *mask, |
25 | bool sync, bool *contended, struct page **page); | 25 | bool sync, bool *contended); |
26 | extern int compact_pgdat(pg_data_t *pgdat, int order); | 26 | extern int compact_pgdat(pg_data_t *pgdat, int order); |
27 | extern void reset_isolation_suitable(pg_data_t *pgdat); | 27 | extern void reset_isolation_suitable(pg_data_t *pgdat); |
28 | extern unsigned long compaction_suitable(struct zone *zone, int order); | 28 | extern unsigned long compaction_suitable(struct zone *zone, int order); |
@@ -75,7 +75,7 @@ static inline bool compaction_restarting(struct zone *zone, int order) | |||
75 | #else | 75 | #else |
76 | static inline unsigned long try_to_compact_pages(struct zonelist *zonelist, | 76 | static inline unsigned long try_to_compact_pages(struct zonelist *zonelist, |
77 | int order, gfp_t gfp_mask, nodemask_t *nodemask, | 77 | int order, gfp_t gfp_mask, nodemask_t *nodemask, |
78 | bool sync, bool *contended, struct page **page) | 78 | bool sync, bool *contended) |
79 | { | 79 | { |
80 | return COMPACT_CONTINUE; | 80 | return COMPACT_CONTINUE; |
81 | } | 81 | } |
diff --git a/include/linux/cpu_rmap.h b/include/linux/cpu_rmap.h index ac3bbb5b9502..1739510d8994 100644 --- a/include/linux/cpu_rmap.h +++ b/include/linux/cpu_rmap.h | |||
@@ -13,9 +13,11 @@ | |||
13 | #include <linux/cpumask.h> | 13 | #include <linux/cpumask.h> |
14 | #include <linux/gfp.h> | 14 | #include <linux/gfp.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/kref.h> | ||
16 | 17 | ||
17 | /** | 18 | /** |
18 | * struct cpu_rmap - CPU affinity reverse-map | 19 | * struct cpu_rmap - CPU affinity reverse-map |
20 | * @refcount: kref for object | ||
19 | * @size: Number of objects to be reverse-mapped | 21 | * @size: Number of objects to be reverse-mapped |
20 | * @used: Number of objects added | 22 | * @used: Number of objects added |
21 | * @obj: Pointer to array of object pointers | 23 | * @obj: Pointer to array of object pointers |
@@ -23,6 +25,7 @@ | |||
23 | * based on affinity masks | 25 | * based on affinity masks |
24 | */ | 26 | */ |
25 | struct cpu_rmap { | 27 | struct cpu_rmap { |
28 | struct kref refcount; | ||
26 | u16 size, used; | 29 | u16 size, used; |
27 | void **obj; | 30 | void **obj; |
28 | struct { | 31 | struct { |
@@ -33,15 +36,7 @@ struct cpu_rmap { | |||
33 | #define CPU_RMAP_DIST_INF 0xffff | 36 | #define CPU_RMAP_DIST_INF 0xffff |
34 | 37 | ||
35 | extern struct cpu_rmap *alloc_cpu_rmap(unsigned int size, gfp_t flags); | 38 | extern struct cpu_rmap *alloc_cpu_rmap(unsigned int size, gfp_t flags); |
36 | 39 | extern int cpu_rmap_put(struct cpu_rmap *rmap); | |
37 | /** | ||
38 | * free_cpu_rmap - free CPU affinity reverse-map | ||
39 | * @rmap: Reverse-map allocated with alloc_cpu_rmap(), or %NULL | ||
40 | */ | ||
41 | static inline void free_cpu_rmap(struct cpu_rmap *rmap) | ||
42 | { | ||
43 | kfree(rmap); | ||
44 | } | ||
45 | 40 | ||
46 | extern int cpu_rmap_add(struct cpu_rmap *rmap, void *obj); | 41 | extern int cpu_rmap_add(struct cpu_rmap *rmap, void *obj); |
47 | extern int cpu_rmap_update(struct cpu_rmap *rmap, u16 index, | 42 | extern int cpu_rmap_update(struct cpu_rmap *rmap, u16 index, |
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 3711b34dc4f9..24cd1037b6d6 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h | |||
@@ -126,9 +126,9 @@ struct cpuidle_driver { | |||
126 | struct module *owner; | 126 | struct module *owner; |
127 | int refcnt; | 127 | int refcnt; |
128 | 128 | ||
129 | unsigned int power_specified:1; | ||
130 | /* set to 1 to use the core cpuidle time keeping (for all states). */ | 129 | /* set to 1 to use the core cpuidle time keeping (for all states). */ |
131 | unsigned int en_core_tk_irqen:1; | 130 | unsigned int en_core_tk_irqen:1; |
131 | /* states array must be ordered in decreasing power consumption */ | ||
132 | struct cpuidle_state states[CPUIDLE_STATE_MAX]; | 132 | struct cpuidle_state states[CPUIDLE_STATE_MAX]; |
133 | int state_count; | 133 | int state_count; |
134 | int safe_state_index; | 134 | int safe_state_index; |
diff --git a/include/linux/init.h b/include/linux/init.h index a799273714ac..10ed4f436458 100644 --- a/include/linux/init.h +++ b/include/linux/init.h | |||
@@ -93,14 +93,6 @@ | |||
93 | 93 | ||
94 | #define __exit __section(.exit.text) __exitused __cold notrace | 94 | #define __exit __section(.exit.text) __exitused __cold notrace |
95 | 95 | ||
96 | /* Used for HOTPLUG, but that is always enabled now, so just make them noops */ | ||
97 | #define __devinit | ||
98 | #define __devinitdata | ||
99 | #define __devinitconst | ||
100 | #define __devexit | ||
101 | #define __devexitdata | ||
102 | #define __devexitconst | ||
103 | |||
104 | /* Used for HOTPLUG_CPU */ | 96 | /* Used for HOTPLUG_CPU */ |
105 | #define __cpuinit __section(.cpuinit.text) __cold notrace | 97 | #define __cpuinit __section(.cpuinit.text) __cold notrace |
106 | #define __cpuinitdata __section(.cpuinit.data) | 98 | #define __cpuinitdata __section(.cpuinit.data) |
@@ -337,18 +329,6 @@ void __init parse_early_options(char *cmdline); | |||
337 | #define __INITRODATA_OR_MODULE __INITRODATA | 329 | #define __INITRODATA_OR_MODULE __INITRODATA |
338 | #endif /*CONFIG_MODULES*/ | 330 | #endif /*CONFIG_MODULES*/ |
339 | 331 | ||
340 | /* Functions marked as __devexit may be discarded at kernel link time, depending | ||
341 | on config options. Newer versions of binutils detect references from | ||
342 | retained sections to discarded sections and flag an error. Pointers to | ||
343 | __devexit functions must use __devexit_p(function_name), the wrapper will | ||
344 | insert either the function_name or NULL, depending on the config options. | ||
345 | */ | ||
346 | #if defined(MODULE) || defined(CONFIG_HOTPLUG) | ||
347 | #define __devexit_p(x) x | ||
348 | #else | ||
349 | #define __devexit_p(x) NULL | ||
350 | #endif | ||
351 | |||
352 | #ifdef MODULE | 332 | #ifdef MODULE |
353 | #define __exit_p(x) x | 333 | #define __exit_p(x) x |
354 | #else | 334 | #else |
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 5e4e6170f43a..5fa5afeeb759 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h | |||
@@ -268,11 +268,6 @@ struct irq_affinity_notify { | |||
268 | extern int | 268 | extern int |
269 | irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify); | 269 | irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify); |
270 | 270 | ||
271 | static inline void irq_run_affinity_notifiers(void) | ||
272 | { | ||
273 | flush_scheduled_work(); | ||
274 | } | ||
275 | |||
276 | #else /* CONFIG_SMP */ | 271 | #else /* CONFIG_SMP */ |
277 | 272 | ||
278 | static inline int irq_set_affinity(unsigned int irq, const struct cpumask *m) | 273 | static inline int irq_set_affinity(unsigned int irq, const struct cpumask *m) |
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 00e46376e28f..2bca44b0893c 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h | |||
@@ -524,14 +524,17 @@ static inline void print_irqtrace_events(struct task_struct *curr) | |||
524 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | 524 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
525 | # ifdef CONFIG_PROVE_LOCKING | 525 | # ifdef CONFIG_PROVE_LOCKING |
526 | # define rwsem_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, NULL, i) | 526 | # define rwsem_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, NULL, i) |
527 | # define rwsem_acquire_nest(l, s, t, n, i) lock_acquire(l, s, t, 0, 2, n, i) | ||
527 | # define rwsem_acquire_read(l, s, t, i) lock_acquire(l, s, t, 1, 2, NULL, i) | 528 | # define rwsem_acquire_read(l, s, t, i) lock_acquire(l, s, t, 1, 2, NULL, i) |
528 | # else | 529 | # else |
529 | # define rwsem_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, NULL, i) | 530 | # define rwsem_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, NULL, i) |
531 | # define rwsem_acquire_nest(l, s, t, n, i) lock_acquire(l, s, t, 0, 1, n, i) | ||
530 | # define rwsem_acquire_read(l, s, t, i) lock_acquire(l, s, t, 1, 1, NULL, i) | 532 | # define rwsem_acquire_read(l, s, t, i) lock_acquire(l, s, t, 1, 1, NULL, i) |
531 | # endif | 533 | # endif |
532 | # define rwsem_release(l, n, i) lock_release(l, n, i) | 534 | # define rwsem_release(l, n, i) lock_release(l, n, i) |
533 | #else | 535 | #else |
534 | # define rwsem_acquire(l, s, t, i) do { } while (0) | 536 | # define rwsem_acquire(l, s, t, i) do { } while (0) |
537 | # define rwsem_acquire_nest(l, s, t, n, i) do { } while (0) | ||
535 | # define rwsem_acquire_read(l, s, t, i) do { } while (0) | 538 | # define rwsem_acquire_read(l, s, t, i) do { } while (0) |
536 | # define rwsem_release(l, n, i) do { } while (0) | 539 | # define rwsem_release(l, n, i) do { } while (0) |
537 | #endif | 540 | #endif |
diff --git a/include/linux/mm.h b/include/linux/mm.h index 63204078f72b..66e2f7c61e5c 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -455,7 +455,6 @@ void put_pages_list(struct list_head *pages); | |||
455 | 455 | ||
456 | void split_page(struct page *page, unsigned int order); | 456 | void split_page(struct page *page, unsigned int order); |
457 | int split_free_page(struct page *page); | 457 | int split_free_page(struct page *page); |
458 | int capture_free_page(struct page *page, int alloc_order, int migratetype); | ||
459 | 458 | ||
460 | /* | 459 | /* |
461 | * Compound pages have a destructor function. Provide a | 460 | * Compound pages have a destructor function. Provide a |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c599e4782d45..9ef07d0868b6 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -60,6 +60,9 @@ struct wireless_dev; | |||
60 | #define SET_ETHTOOL_OPS(netdev,ops) \ | 60 | #define SET_ETHTOOL_OPS(netdev,ops) \ |
61 | ( (netdev)->ethtool_ops = (ops) ) | 61 | ( (netdev)->ethtool_ops = (ops) ) |
62 | 62 | ||
63 | extern void netdev_set_default_ethtool_ops(struct net_device *dev, | ||
64 | const struct ethtool_ops *ops); | ||
65 | |||
63 | /* hardware address assignment types */ | 66 | /* hardware address assignment types */ |
64 | #define NET_ADDR_PERM 0 /* address is permanent (default) */ | 67 | #define NET_ADDR_PERM 0 /* address is permanent (default) */ |
65 | #define NET_ADDR_RANDOM 1 /* address is generated randomly */ | 68 | #define NET_ADDR_RANDOM 1 /* address is generated randomly */ |
diff --git a/include/linux/rbtree_augmented.h b/include/linux/rbtree_augmented.h index 2ac60c9cf644..fea49b5da12a 100644 --- a/include/linux/rbtree_augmented.h +++ b/include/linux/rbtree_augmented.h | |||
@@ -123,9 +123,9 @@ __rb_change_child(struct rb_node *old, struct rb_node *new, | |||
123 | extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root, | 123 | extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root, |
124 | void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); | 124 | void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); |
125 | 125 | ||
126 | static __always_inline void | 126 | static __always_inline struct rb_node * |
127 | rb_erase_augmented(struct rb_node *node, struct rb_root *root, | 127 | __rb_erase_augmented(struct rb_node *node, struct rb_root *root, |
128 | const struct rb_augment_callbacks *augment) | 128 | const struct rb_augment_callbacks *augment) |
129 | { | 129 | { |
130 | struct rb_node *child = node->rb_right, *tmp = node->rb_left; | 130 | struct rb_node *child = node->rb_right, *tmp = node->rb_left; |
131 | struct rb_node *parent, *rebalance; | 131 | struct rb_node *parent, *rebalance; |
@@ -217,6 +217,14 @@ rb_erase_augmented(struct rb_node *node, struct rb_root *root, | |||
217 | } | 217 | } |
218 | 218 | ||
219 | augment->propagate(tmp, NULL); | 219 | augment->propagate(tmp, NULL); |
220 | return rebalance; | ||
221 | } | ||
222 | |||
223 | static __always_inline void | ||
224 | rb_erase_augmented(struct rb_node *node, struct rb_root *root, | ||
225 | const struct rb_augment_callbacks *augment) | ||
226 | { | ||
227 | struct rb_node *rebalance = __rb_erase_augmented(node, root, augment); | ||
220 | if (rebalance) | 228 | if (rebalance) |
221 | __rb_erase_color(rebalance, root, augment->rotate); | 229 | __rb_erase_color(rebalance, root, augment->rotate); |
222 | } | 230 | } |
diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h index 54bd7cd7ecbd..8da67d625e13 100644 --- a/include/linux/rwsem.h +++ b/include/linux/rwsem.h | |||
@@ -125,8 +125,17 @@ extern void downgrade_write(struct rw_semaphore *sem); | |||
125 | */ | 125 | */ |
126 | extern void down_read_nested(struct rw_semaphore *sem, int subclass); | 126 | extern void down_read_nested(struct rw_semaphore *sem, int subclass); |
127 | extern void down_write_nested(struct rw_semaphore *sem, int subclass); | 127 | extern void down_write_nested(struct rw_semaphore *sem, int subclass); |
128 | extern void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep_map *nest_lock); | ||
129 | |||
130 | # define down_write_nest_lock(sem, nest_lock) \ | ||
131 | do { \ | ||
132 | typecheck(struct lockdep_map *, &(nest_lock)->dep_map); \ | ||
133 | _down_write_nest_lock(sem, &(nest_lock)->dep_map); \ | ||
134 | } while (0); | ||
135 | |||
128 | #else | 136 | #else |
129 | # define down_read_nested(sem, subclass) down_read(sem) | 137 | # define down_read_nested(sem, subclass) down_read(sem) |
138 | # define down_write_nest_lock(sem, nest_lock) down_write(sem) | ||
130 | # define down_write_nested(sem, subclass) down_write(sem) | 139 | # define down_write_nested(sem, subclass) down_write(sem) |
131 | #endif | 140 | #endif |
132 | 141 | ||
diff --git a/include/linux/sched.h b/include/linux/sched.h index 206bb089c06b..6fc8f45de4e9 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1810,6 +1810,7 @@ extern void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, | |||
1810 | #define PF_MEMALLOC 0x00000800 /* Allocating memory */ | 1810 | #define PF_MEMALLOC 0x00000800 /* Allocating memory */ |
1811 | #define PF_NPROC_EXCEEDED 0x00001000 /* set_user noticed that RLIMIT_NPROC was exceeded */ | 1811 | #define PF_NPROC_EXCEEDED 0x00001000 /* set_user noticed that RLIMIT_NPROC was exceeded */ |
1812 | #define PF_USED_MATH 0x00002000 /* if unset the fpu must be initialized before use */ | 1812 | #define PF_USED_MATH 0x00002000 /* if unset the fpu must be initialized before use */ |
1813 | #define PF_USED_ASYNC 0x00004000 /* used async_schedule*(), used by module init */ | ||
1813 | #define PF_NOFREEZE 0x00008000 /* this thread should not be frozen */ | 1814 | #define PF_NOFREEZE 0x00008000 /* this thread should not be frozen */ |
1814 | #define PF_FROZEN 0x00010000 /* frozen for system suspend */ | 1815 | #define PF_FROZEN 0x00010000 /* frozen for system suspend */ |
1815 | #define PF_FSTRANS 0x00020000 /* inside a filesystem transaction */ | 1816 | #define PF_FSTRANS 0x00020000 /* inside a filesystem transaction */ |
diff --git a/include/sound/cs4271.h b/include/sound/cs4271.h index 6d9e15ed1dcf..dd8c48d14ed9 100644 --- a/include/sound/cs4271.h +++ b/include/sound/cs4271.h | |||
@@ -19,7 +19,7 @@ | |||
19 | 19 | ||
20 | struct cs4271_platform_data { | 20 | struct cs4271_platform_data { |
21 | int gpio_nreset; /* GPIO driving Reset pin, if any */ | 21 | int gpio_nreset; /* GPIO driving Reset pin, if any */ |
22 | int amutec_eq_bmutec:1; /* flag to enable AMUTEC=BMUTEC */ | 22 | bool amutec_eq_bmutec; /* flag to enable AMUTEC=BMUTEC */ |
23 | }; | 23 | }; |
24 | 24 | ||
25 | #endif /* __CS4271_H */ | 25 | #endif /* __CS4271_H */ |
diff --git a/include/sound/soc.h b/include/sound/soc.h index 769e27c774a3..bc56738cb109 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
@@ -58,8 +58,9 @@ | |||
58 | .info = snd_soc_info_volsw_range, .get = snd_soc_get_volsw_range, \ | 58 | .info = snd_soc_info_volsw_range, .get = snd_soc_get_volsw_range, \ |
59 | .put = snd_soc_put_volsw_range, \ | 59 | .put = snd_soc_put_volsw_range, \ |
60 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 60 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
61 | {.reg = xreg, .shift = xshift, .min = xmin,\ | 61 | {.reg = xreg, .rreg = xreg, .shift = xshift, \ |
62 | .max = xmax, .platform_max = xmax, .invert = xinvert} } | 62 | .rshift = xshift, .min = xmin, .max = xmax, \ |
63 | .platform_max = xmax, .invert = xinvert} } | ||
63 | #define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ | 64 | #define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ |
64 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 65 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
65 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | 66 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ |
@@ -88,8 +89,9 @@ | |||
88 | .info = snd_soc_info_volsw_range, \ | 89 | .info = snd_soc_info_volsw_range, \ |
89 | .get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \ | 90 | .get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \ |
90 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 91 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
91 | {.reg = xreg, .shift = xshift, .min = xmin,\ | 92 | {.reg = xreg, .rreg = xreg, .shift = xshift, \ |
92 | .max = xmax, .platform_max = xmax, .invert = xinvert} } | 93 | .rshift = xshift, .min = xmin, .max = xmax, \ |
94 | .platform_max = xmax, .invert = xinvert} } | ||
93 | #define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \ | 95 | #define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \ |
94 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | 96 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ |
95 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ | 97 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ |
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 7cae2360221e..663e34a5383f 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h | |||
@@ -174,6 +174,7 @@ typedef unsigned __bitwise__ sense_reason_t; | |||
174 | 174 | ||
175 | enum tcm_sense_reason_table { | 175 | enum tcm_sense_reason_table { |
176 | #define R(x) (__force sense_reason_t )(x) | 176 | #define R(x) (__force sense_reason_t )(x) |
177 | TCM_NO_SENSE = R(0x00), | ||
177 | TCM_NON_EXISTENT_LUN = R(0x01), | 178 | TCM_NON_EXISTENT_LUN = R(0x01), |
178 | TCM_UNSUPPORTED_SCSI_OPCODE = R(0x02), | 179 | TCM_UNSUPPORTED_SCSI_OPCODE = R(0x02), |
179 | TCM_INCORRECT_AMOUNT_OF_DATA = R(0x03), | 180 | TCM_INCORRECT_AMOUNT_OF_DATA = R(0x03), |
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index 76352ac45f24..9f096f1c0907 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h | |||
@@ -26,7 +26,6 @@ | |||
26 | 26 | ||
27 | #include <linux/types.h> | 27 | #include <linux/types.h> |
28 | #include <linux/elf-em.h> | 28 | #include <linux/elf-em.h> |
29 | #include <linux/ptrace.h> | ||
30 | 29 | ||
31 | /* The netlink messages for the audit system is divided into blocks: | 30 | /* The netlink messages for the audit system is divided into blocks: |
32 | * 1000 - 1099 are for commanding the audit system | 31 | * 1000 - 1099 are for commanding the audit system |
@@ -106,6 +105,7 @@ | |||
106 | #define AUDIT_MMAP 1323 /* Record showing descriptor and flags in mmap */ | 105 | #define AUDIT_MMAP 1323 /* Record showing descriptor and flags in mmap */ |
107 | #define AUDIT_NETFILTER_PKT 1324 /* Packets traversing netfilter chains */ | 106 | #define AUDIT_NETFILTER_PKT 1324 /* Packets traversing netfilter chains */ |
108 | #define AUDIT_NETFILTER_CFG 1325 /* Netfilter chain modifications */ | 107 | #define AUDIT_NETFILTER_CFG 1325 /* Netfilter chain modifications */ |
108 | #define AUDIT_SECCOMP 1326 /* Secure Computing event */ | ||
109 | 109 | ||
110 | #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ | 110 | #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ |
111 | #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ | 111 | #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ |
diff --git a/init/Kconfig b/init/Kconfig index 7d30240e5bfe..be8b7f55312d 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
@@ -1182,7 +1182,7 @@ config CC_OPTIMIZE_FOR_SIZE | |||
1182 | Enabling this option will pass "-Os" instead of "-O2" to gcc | 1182 | Enabling this option will pass "-Os" instead of "-O2" to gcc |
1183 | resulting in a smaller kernel. | 1183 | resulting in a smaller kernel. |
1184 | 1184 | ||
1185 | If unsure, say Y. | 1185 | If unsure, say N. |
1186 | 1186 | ||
1187 | config SYSCTL | 1187 | config SYSCTL |
1188 | bool | 1188 | bool |
diff --git a/kernel/async.c b/kernel/async.c index 9d3118384858..a1d585c351d6 100644 --- a/kernel/async.c +++ b/kernel/async.c | |||
@@ -196,6 +196,9 @@ static async_cookie_t __async_schedule(async_func_ptr *ptr, void *data, struct a | |||
196 | atomic_inc(&entry_count); | 196 | atomic_inc(&entry_count); |
197 | spin_unlock_irqrestore(&async_lock, flags); | 197 | spin_unlock_irqrestore(&async_lock, flags); |
198 | 198 | ||
199 | /* mark that this task has queued an async job, used by module init */ | ||
200 | current->flags |= PF_USED_ASYNC; | ||
201 | |||
199 | /* schedule for execution */ | 202 | /* schedule for execution */ |
200 | queue_work(system_unbound_wq, &entry->work); | 203 | queue_work(system_unbound_wq, &entry->work); |
201 | 204 | ||
diff --git a/kernel/audit.c b/kernel/audit.c index 40414e9143db..d596e5355f15 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
@@ -272,6 +272,8 @@ static int audit_log_config_change(char *function_name, int new, int old, | |||
272 | int rc = 0; | 272 | int rc = 0; |
273 | 273 | ||
274 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); | 274 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); |
275 | if (unlikely(!ab)) | ||
276 | return rc; | ||
275 | audit_log_format(ab, "%s=%d old=%d auid=%u ses=%u", function_name, new, | 277 | audit_log_format(ab, "%s=%d old=%d auid=%u ses=%u", function_name, new, |
276 | old, from_kuid(&init_user_ns, loginuid), sessionid); | 278 | old, from_kuid(&init_user_ns, loginuid), sessionid); |
277 | if (sid) { | 279 | if (sid) { |
@@ -619,6 +621,8 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type, | |||
619 | } | 621 | } |
620 | 622 | ||
621 | *ab = audit_log_start(NULL, GFP_KERNEL, msg_type); | 623 | *ab = audit_log_start(NULL, GFP_KERNEL, msg_type); |
624 | if (unlikely(!*ab)) | ||
625 | return rc; | ||
622 | audit_log_format(*ab, "pid=%d uid=%u auid=%u ses=%u", | 626 | audit_log_format(*ab, "pid=%d uid=%u auid=%u ses=%u", |
623 | task_tgid_vnr(current), | 627 | task_tgid_vnr(current), |
624 | from_kuid(&init_user_ns, current_uid()), | 628 | from_kuid(&init_user_ns, current_uid()), |
@@ -1097,6 +1101,23 @@ static inline void audit_get_stamp(struct audit_context *ctx, | |||
1097 | } | 1101 | } |
1098 | } | 1102 | } |
1099 | 1103 | ||
1104 | /* | ||
1105 | * Wait for auditd to drain the queue a little | ||
1106 | */ | ||
1107 | static void wait_for_auditd(unsigned long sleep_time) | ||
1108 | { | ||
1109 | DECLARE_WAITQUEUE(wait, current); | ||
1110 | set_current_state(TASK_INTERRUPTIBLE); | ||
1111 | add_wait_queue(&audit_backlog_wait, &wait); | ||
1112 | |||
1113 | if (audit_backlog_limit && | ||
1114 | skb_queue_len(&audit_skb_queue) > audit_backlog_limit) | ||
1115 | schedule_timeout(sleep_time); | ||
1116 | |||
1117 | __set_current_state(TASK_RUNNING); | ||
1118 | remove_wait_queue(&audit_backlog_wait, &wait); | ||
1119 | } | ||
1120 | |||
1100 | /* Obtain an audit buffer. This routine does locking to obtain the | 1121 | /* Obtain an audit buffer. This routine does locking to obtain the |
1101 | * audit buffer, but then no locking is required for calls to | 1122 | * audit buffer, but then no locking is required for calls to |
1102 | * audit_log_*format. If the tsk is a task that is currently in a | 1123 | * audit_log_*format. If the tsk is a task that is currently in a |
@@ -1142,20 +1163,13 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, | |||
1142 | 1163 | ||
1143 | while (audit_backlog_limit | 1164 | while (audit_backlog_limit |
1144 | && skb_queue_len(&audit_skb_queue) > audit_backlog_limit + reserve) { | 1165 | && skb_queue_len(&audit_skb_queue) > audit_backlog_limit + reserve) { |
1145 | if (gfp_mask & __GFP_WAIT && audit_backlog_wait_time | 1166 | if (gfp_mask & __GFP_WAIT && audit_backlog_wait_time) { |
1146 | && time_before(jiffies, timeout_start + audit_backlog_wait_time)) { | 1167 | unsigned long sleep_time; |
1147 | 1168 | ||
1148 | /* Wait for auditd to drain the queue a little */ | 1169 | sleep_time = timeout_start + audit_backlog_wait_time - |
1149 | DECLARE_WAITQUEUE(wait, current); | 1170 | jiffies; |
1150 | set_current_state(TASK_INTERRUPTIBLE); | 1171 | if ((long)sleep_time > 0) |
1151 | add_wait_queue(&audit_backlog_wait, &wait); | 1172 | wait_for_auditd(sleep_time); |
1152 | |||
1153 | if (audit_backlog_limit && | ||
1154 | skb_queue_len(&audit_skb_queue) > audit_backlog_limit) | ||
1155 | schedule_timeout(timeout_start + audit_backlog_wait_time - jiffies); | ||
1156 | |||
1157 | __set_current_state(TASK_RUNNING); | ||
1158 | remove_wait_queue(&audit_backlog_wait, &wait); | ||
1159 | continue; | 1173 | continue; |
1160 | } | 1174 | } |
1161 | if (audit_rate_check() && printk_ratelimit()) | 1175 | if (audit_rate_check() && printk_ratelimit()) |
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index e81175ef25f8..642a89c4f3d6 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c | |||
@@ -449,11 +449,26 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree) | |||
449 | return 0; | 449 | return 0; |
450 | } | 450 | } |
451 | 451 | ||
452 | static void audit_log_remove_rule(struct audit_krule *rule) | ||
453 | { | ||
454 | struct audit_buffer *ab; | ||
455 | |||
456 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); | ||
457 | if (unlikely(!ab)) | ||
458 | return; | ||
459 | audit_log_format(ab, "op="); | ||
460 | audit_log_string(ab, "remove rule"); | ||
461 | audit_log_format(ab, " dir="); | ||
462 | audit_log_untrustedstring(ab, rule->tree->pathname); | ||
463 | audit_log_key(ab, rule->filterkey); | ||
464 | audit_log_format(ab, " list=%d res=1", rule->listnr); | ||
465 | audit_log_end(ab); | ||
466 | } | ||
467 | |||
452 | static void kill_rules(struct audit_tree *tree) | 468 | static void kill_rules(struct audit_tree *tree) |
453 | { | 469 | { |
454 | struct audit_krule *rule, *next; | 470 | struct audit_krule *rule, *next; |
455 | struct audit_entry *entry; | 471 | struct audit_entry *entry; |
456 | struct audit_buffer *ab; | ||
457 | 472 | ||
458 | list_for_each_entry_safe(rule, next, &tree->rules, rlist) { | 473 | list_for_each_entry_safe(rule, next, &tree->rules, rlist) { |
459 | entry = container_of(rule, struct audit_entry, rule); | 474 | entry = container_of(rule, struct audit_entry, rule); |
@@ -461,14 +476,7 @@ static void kill_rules(struct audit_tree *tree) | |||
461 | list_del_init(&rule->rlist); | 476 | list_del_init(&rule->rlist); |
462 | if (rule->tree) { | 477 | if (rule->tree) { |
463 | /* not a half-baked one */ | 478 | /* not a half-baked one */ |
464 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); | 479 | audit_log_remove_rule(rule); |
465 | audit_log_format(ab, "op="); | ||
466 | audit_log_string(ab, "remove rule"); | ||
467 | audit_log_format(ab, " dir="); | ||
468 | audit_log_untrustedstring(ab, rule->tree->pathname); | ||
469 | audit_log_key(ab, rule->filterkey); | ||
470 | audit_log_format(ab, " list=%d res=1", rule->listnr); | ||
471 | audit_log_end(ab); | ||
472 | rule->tree = NULL; | 480 | rule->tree = NULL; |
473 | list_del_rcu(&entry->list); | 481 | list_del_rcu(&entry->list); |
474 | list_del(&entry->rule.list); | 482 | list_del(&entry->rule.list); |
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c index 4a599f699adc..22831c4d369c 100644 --- a/kernel/audit_watch.c +++ b/kernel/audit_watch.c | |||
@@ -240,6 +240,8 @@ static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watc | |||
240 | if (audit_enabled) { | 240 | if (audit_enabled) { |
241 | struct audit_buffer *ab; | 241 | struct audit_buffer *ab; |
242 | ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE); | 242 | ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE); |
243 | if (unlikely(!ab)) | ||
244 | return; | ||
243 | audit_log_format(ab, "auid=%u ses=%u op=", | 245 | audit_log_format(ab, "auid=%u ses=%u op=", |
244 | from_kuid(&init_user_ns, audit_get_loginuid(current)), | 246 | from_kuid(&init_user_ns, audit_get_loginuid(current)), |
245 | audit_get_sessionid(current)); | 247 | audit_get_sessionid(current)); |
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 7f19f23d38a3..f9fc54bbe06f 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c | |||
@@ -1144,7 +1144,6 @@ static void audit_log_rule_change(kuid_t loginuid, u32 sessionid, u32 sid, | |||
1144 | * audit_receive_filter - apply all rules to the specified message type | 1144 | * audit_receive_filter - apply all rules to the specified message type |
1145 | * @type: audit message type | 1145 | * @type: audit message type |
1146 | * @pid: target pid for netlink audit messages | 1146 | * @pid: target pid for netlink audit messages |
1147 | * @uid: target uid for netlink audit messages | ||
1148 | * @seq: netlink audit message sequence (serial) number | 1147 | * @seq: netlink audit message sequence (serial) number |
1149 | * @data: payload data | 1148 | * @data: payload data |
1150 | * @datasz: size of payload data | 1149 | * @datasz: size of payload data |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index e37e6a12c5e3..a371f857a0a9 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -1464,14 +1464,14 @@ static void show_special(struct audit_context *context, int *call_panic) | |||
1464 | audit_log_end(ab); | 1464 | audit_log_end(ab); |
1465 | ab = audit_log_start(context, GFP_KERNEL, | 1465 | ab = audit_log_start(context, GFP_KERNEL, |
1466 | AUDIT_IPC_SET_PERM); | 1466 | AUDIT_IPC_SET_PERM); |
1467 | if (unlikely(!ab)) | ||
1468 | return; | ||
1467 | audit_log_format(ab, | 1469 | audit_log_format(ab, |
1468 | "qbytes=%lx ouid=%u ogid=%u mode=%#ho", | 1470 | "qbytes=%lx ouid=%u ogid=%u mode=%#ho", |
1469 | context->ipc.qbytes, | 1471 | context->ipc.qbytes, |
1470 | context->ipc.perm_uid, | 1472 | context->ipc.perm_uid, |
1471 | context->ipc.perm_gid, | 1473 | context->ipc.perm_gid, |
1472 | context->ipc.perm_mode); | 1474 | context->ipc.perm_mode); |
1473 | if (!ab) | ||
1474 | return; | ||
1475 | } | 1475 | } |
1476 | break; } | 1476 | break; } |
1477 | case AUDIT_MQ_OPEN: { | 1477 | case AUDIT_MQ_OPEN: { |
@@ -2675,7 +2675,7 @@ void __audit_mmap_fd(int fd, int flags) | |||
2675 | context->type = AUDIT_MMAP; | 2675 | context->type = AUDIT_MMAP; |
2676 | } | 2676 | } |
2677 | 2677 | ||
2678 | static void audit_log_abend(struct audit_buffer *ab, char *reason, long signr) | 2678 | static void audit_log_task(struct audit_buffer *ab) |
2679 | { | 2679 | { |
2680 | kuid_t auid, uid; | 2680 | kuid_t auid, uid; |
2681 | kgid_t gid; | 2681 | kgid_t gid; |
@@ -2693,6 +2693,11 @@ static void audit_log_abend(struct audit_buffer *ab, char *reason, long signr) | |||
2693 | audit_log_task_context(ab); | 2693 | audit_log_task_context(ab); |
2694 | audit_log_format(ab, " pid=%d comm=", current->pid); | 2694 | audit_log_format(ab, " pid=%d comm=", current->pid); |
2695 | audit_log_untrustedstring(ab, current->comm); | 2695 | audit_log_untrustedstring(ab, current->comm); |
2696 | } | ||
2697 | |||
2698 | static void audit_log_abend(struct audit_buffer *ab, char *reason, long signr) | ||
2699 | { | ||
2700 | audit_log_task(ab); | ||
2696 | audit_log_format(ab, " reason="); | 2701 | audit_log_format(ab, " reason="); |
2697 | audit_log_string(ab, reason); | 2702 | audit_log_string(ab, reason); |
2698 | audit_log_format(ab, " sig=%ld", signr); | 2703 | audit_log_format(ab, " sig=%ld", signr); |
@@ -2715,6 +2720,8 @@ void audit_core_dumps(long signr) | |||
2715 | return; | 2720 | return; |
2716 | 2721 | ||
2717 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND); | 2722 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND); |
2723 | if (unlikely(!ab)) | ||
2724 | return; | ||
2718 | audit_log_abend(ab, "memory violation", signr); | 2725 | audit_log_abend(ab, "memory violation", signr); |
2719 | audit_log_end(ab); | 2726 | audit_log_end(ab); |
2720 | } | 2727 | } |
@@ -2723,8 +2730,11 @@ void __audit_seccomp(unsigned long syscall, long signr, int code) | |||
2723 | { | 2730 | { |
2724 | struct audit_buffer *ab; | 2731 | struct audit_buffer *ab; |
2725 | 2732 | ||
2726 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND); | 2733 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_SECCOMP); |
2727 | audit_log_abend(ab, "seccomp", signr); | 2734 | if (unlikely(!ab)) |
2735 | return; | ||
2736 | audit_log_task(ab); | ||
2737 | audit_log_format(ab, " sig=%ld", signr); | ||
2728 | audit_log_format(ab, " syscall=%ld", syscall); | 2738 | audit_log_format(ab, " syscall=%ld", syscall); |
2729 | audit_log_format(ab, " compat=%d", is_compat_task()); | 2739 | audit_log_format(ab, " compat=%d", is_compat_task()); |
2730 | audit_log_format(ab, " ip=0x%lx", KSTK_EIP(current)); | 2740 | audit_log_format(ab, " ip=0x%lx", KSTK_EIP(current)); |
diff --git a/kernel/module.c b/kernel/module.c index 250092c1d57d..b10b048367e1 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -3013,6 +3013,12 @@ static int do_init_module(struct module *mod) | |||
3013 | { | 3013 | { |
3014 | int ret = 0; | 3014 | int ret = 0; |
3015 | 3015 | ||
3016 | /* | ||
3017 | * We want to find out whether @mod uses async during init. Clear | ||
3018 | * PF_USED_ASYNC. async_schedule*() will set it. | ||
3019 | */ | ||
3020 | current->flags &= ~PF_USED_ASYNC; | ||
3021 | |||
3016 | blocking_notifier_call_chain(&module_notify_list, | 3022 | blocking_notifier_call_chain(&module_notify_list, |
3017 | MODULE_STATE_COMING, mod); | 3023 | MODULE_STATE_COMING, mod); |
3018 | 3024 | ||
@@ -3058,8 +3064,25 @@ static int do_init_module(struct module *mod) | |||
3058 | blocking_notifier_call_chain(&module_notify_list, | 3064 | blocking_notifier_call_chain(&module_notify_list, |
3059 | MODULE_STATE_LIVE, mod); | 3065 | MODULE_STATE_LIVE, mod); |
3060 | 3066 | ||
3061 | /* We need to finish all async code before the module init sequence is done */ | 3067 | /* |
3062 | async_synchronize_full(); | 3068 | * We need to finish all async code before the module init sequence |
3069 | * is done. This has potential to deadlock. For example, a newly | ||
3070 | * detected block device can trigger request_module() of the | ||
3071 | * default iosched from async probing task. Once userland helper | ||
3072 | * reaches here, async_synchronize_full() will wait on the async | ||
3073 | * task waiting on request_module() and deadlock. | ||
3074 | * | ||
3075 | * This deadlock is avoided by perfomring async_synchronize_full() | ||
3076 | * iff module init queued any async jobs. This isn't a full | ||
3077 | * solution as it will deadlock the same if module loading from | ||
3078 | * async jobs nests more than once; however, due to the various | ||
3079 | * constraints, this hack seems to be the best option for now. | ||
3080 | * Please refer to the following thread for details. | ||
3081 | * | ||
3082 | * http://thread.gmane.org/gmane.linux.kernel/1420814 | ||
3083 | */ | ||
3084 | if (current->flags & PF_USED_ASYNC) | ||
3085 | async_synchronize_full(); | ||
3063 | 3086 | ||
3064 | mutex_lock(&module_mutex); | 3087 | mutex_lock(&module_mutex); |
3065 | /* Drop initial reference. */ | 3088 | /* Drop initial reference. */ |
diff --git a/kernel/rwsem.c b/kernel/rwsem.c index 6850f53e02d8..b3c6c3fcd847 100644 --- a/kernel/rwsem.c +++ b/kernel/rwsem.c | |||
@@ -116,6 +116,16 @@ void down_read_nested(struct rw_semaphore *sem, int subclass) | |||
116 | 116 | ||
117 | EXPORT_SYMBOL(down_read_nested); | 117 | EXPORT_SYMBOL(down_read_nested); |
118 | 118 | ||
119 | void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep_map *nest) | ||
120 | { | ||
121 | might_sleep(); | ||
122 | rwsem_acquire_nest(&sem->dep_map, 0, 0, nest, _RET_IP_); | ||
123 | |||
124 | LOCK_CONTENDED(sem, __down_write_trylock, __down_write); | ||
125 | } | ||
126 | |||
127 | EXPORT_SYMBOL(_down_write_nest_lock); | ||
128 | |||
119 | void down_write_nested(struct rw_semaphore *sem, int subclass) | 129 | void down_write_nested(struct rw_semaphore *sem, int subclass) |
120 | { | 130 | { |
121 | might_sleep(); | 131 | might_sleep(); |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index e5125677efa0..3c13e46d7d24 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -2899,6 +2899,8 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf, | |||
2899 | if (copy_from_user(&buf, ubuf, cnt)) | 2899 | if (copy_from_user(&buf, ubuf, cnt)) |
2900 | return -EFAULT; | 2900 | return -EFAULT; |
2901 | 2901 | ||
2902 | buf[cnt] = 0; | ||
2903 | |||
2902 | trace_set_options(buf); | 2904 | trace_set_options(buf); |
2903 | 2905 | ||
2904 | *ppos += cnt; | 2906 | *ppos += cnt; |
@@ -3452,7 +3454,7 @@ static int tracing_wait_pipe(struct file *filp) | |||
3452 | return -EINTR; | 3454 | return -EINTR; |
3453 | 3455 | ||
3454 | /* | 3456 | /* |
3455 | * We block until we read something and tracing is enabled. | 3457 | * We block until we read something and tracing is disabled. |
3456 | * We still block if tracing is disabled, but we have never | 3458 | * We still block if tracing is disabled, but we have never |
3457 | * read anything. This allows a user to cat this file, and | 3459 | * read anything. This allows a user to cat this file, and |
3458 | * then enable tracing. But after we have read something, | 3460 | * then enable tracing. But after we have read something, |
@@ -3460,7 +3462,7 @@ static int tracing_wait_pipe(struct file *filp) | |||
3460 | * | 3462 | * |
3461 | * iter->pos will be 0 if we haven't read anything. | 3463 | * iter->pos will be 0 if we haven't read anything. |
3462 | */ | 3464 | */ |
3463 | if (tracing_is_enabled() && iter->pos) | 3465 | if (!tracing_is_enabled() && iter->pos) |
3464 | break; | 3466 | break; |
3465 | } | 3467 | } |
3466 | 3468 | ||
@@ -4815,10 +4817,17 @@ rb_simple_write(struct file *filp, const char __user *ubuf, | |||
4815 | return ret; | 4817 | return ret; |
4816 | 4818 | ||
4817 | if (buffer) { | 4819 | if (buffer) { |
4818 | if (val) | 4820 | mutex_lock(&trace_types_lock); |
4821 | if (val) { | ||
4819 | ring_buffer_record_on(buffer); | 4822 | ring_buffer_record_on(buffer); |
4820 | else | 4823 | if (current_trace->start) |
4824 | current_trace->start(tr); | ||
4825 | } else { | ||
4821 | ring_buffer_record_off(buffer); | 4826 | ring_buffer_record_off(buffer); |
4827 | if (current_trace->stop) | ||
4828 | current_trace->stop(tr); | ||
4829 | } | ||
4830 | mutex_unlock(&trace_types_lock); | ||
4822 | } | 4831 | } |
4823 | 4832 | ||
4824 | (*ppos)++; | 4833 | (*ppos)++; |
diff --git a/lib/cpu_rmap.c b/lib/cpu_rmap.c index 145dec5267c9..5fbed5caba6e 100644 --- a/lib/cpu_rmap.c +++ b/lib/cpu_rmap.c | |||
@@ -45,6 +45,7 @@ struct cpu_rmap *alloc_cpu_rmap(unsigned int size, gfp_t flags) | |||
45 | if (!rmap) | 45 | if (!rmap) |
46 | return NULL; | 46 | return NULL; |
47 | 47 | ||
48 | kref_init(&rmap->refcount); | ||
48 | rmap->obj = (void **)((char *)rmap + obj_offset); | 49 | rmap->obj = (void **)((char *)rmap + obj_offset); |
49 | 50 | ||
50 | /* Initially assign CPUs to objects on a rota, since we have | 51 | /* Initially assign CPUs to objects on a rota, since we have |
@@ -63,6 +64,35 @@ struct cpu_rmap *alloc_cpu_rmap(unsigned int size, gfp_t flags) | |||
63 | } | 64 | } |
64 | EXPORT_SYMBOL(alloc_cpu_rmap); | 65 | EXPORT_SYMBOL(alloc_cpu_rmap); |
65 | 66 | ||
67 | /** | ||
68 | * cpu_rmap_release - internal reclaiming helper called from kref_put | ||
69 | * @ref: kref to struct cpu_rmap | ||
70 | */ | ||
71 | static void cpu_rmap_release(struct kref *ref) | ||
72 | { | ||
73 | struct cpu_rmap *rmap = container_of(ref, struct cpu_rmap, refcount); | ||
74 | kfree(rmap); | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * cpu_rmap_get - internal helper to get new ref on a cpu_rmap | ||
79 | * @rmap: reverse-map allocated with alloc_cpu_rmap() | ||
80 | */ | ||
81 | static inline void cpu_rmap_get(struct cpu_rmap *rmap) | ||
82 | { | ||
83 | kref_get(&rmap->refcount); | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * cpu_rmap_put - release ref on a cpu_rmap | ||
88 | * @rmap: reverse-map allocated with alloc_cpu_rmap() | ||
89 | */ | ||
90 | int cpu_rmap_put(struct cpu_rmap *rmap) | ||
91 | { | ||
92 | return kref_put(&rmap->refcount, cpu_rmap_release); | ||
93 | } | ||
94 | EXPORT_SYMBOL(cpu_rmap_put); | ||
95 | |||
66 | /* Reevaluate nearest object for given CPU, comparing with the given | 96 | /* Reevaluate nearest object for given CPU, comparing with the given |
67 | * neighbours at the given distance. | 97 | * neighbours at the given distance. |
68 | */ | 98 | */ |
@@ -197,8 +227,7 @@ struct irq_glue { | |||
197 | * free_irq_cpu_rmap - free a CPU affinity reverse-map used for IRQs | 227 | * free_irq_cpu_rmap - free a CPU affinity reverse-map used for IRQs |
198 | * @rmap: Reverse-map allocated with alloc_irq_cpu_map(), or %NULL | 228 | * @rmap: Reverse-map allocated with alloc_irq_cpu_map(), or %NULL |
199 | * | 229 | * |
200 | * Must be called in process context, before freeing the IRQs, and | 230 | * Must be called in process context, before freeing the IRQs. |
201 | * without holding any locks required by global workqueue items. | ||
202 | */ | 231 | */ |
203 | void free_irq_cpu_rmap(struct cpu_rmap *rmap) | 232 | void free_irq_cpu_rmap(struct cpu_rmap *rmap) |
204 | { | 233 | { |
@@ -212,12 +241,18 @@ void free_irq_cpu_rmap(struct cpu_rmap *rmap) | |||
212 | glue = rmap->obj[index]; | 241 | glue = rmap->obj[index]; |
213 | irq_set_affinity_notifier(glue->notify.irq, NULL); | 242 | irq_set_affinity_notifier(glue->notify.irq, NULL); |
214 | } | 243 | } |
215 | irq_run_affinity_notifiers(); | ||
216 | 244 | ||
217 | kfree(rmap); | 245 | cpu_rmap_put(rmap); |
218 | } | 246 | } |
219 | EXPORT_SYMBOL(free_irq_cpu_rmap); | 247 | EXPORT_SYMBOL(free_irq_cpu_rmap); |
220 | 248 | ||
249 | /** | ||
250 | * irq_cpu_rmap_notify - callback for IRQ subsystem when IRQ affinity updated | ||
251 | * @notify: struct irq_affinity_notify passed by irq/manage.c | ||
252 | * @mask: cpu mask for new SMP affinity | ||
253 | * | ||
254 | * This is executed in workqueue context. | ||
255 | */ | ||
221 | static void | 256 | static void |
222 | irq_cpu_rmap_notify(struct irq_affinity_notify *notify, const cpumask_t *mask) | 257 | irq_cpu_rmap_notify(struct irq_affinity_notify *notify, const cpumask_t *mask) |
223 | { | 258 | { |
@@ -230,10 +265,16 @@ irq_cpu_rmap_notify(struct irq_affinity_notify *notify, const cpumask_t *mask) | |||
230 | pr_warning("irq_cpu_rmap_notify: update failed: %d\n", rc); | 265 | pr_warning("irq_cpu_rmap_notify: update failed: %d\n", rc); |
231 | } | 266 | } |
232 | 267 | ||
268 | /** | ||
269 | * irq_cpu_rmap_release - reclaiming callback for IRQ subsystem | ||
270 | * @ref: kref to struct irq_affinity_notify passed by irq/manage.c | ||
271 | */ | ||
233 | static void irq_cpu_rmap_release(struct kref *ref) | 272 | static void irq_cpu_rmap_release(struct kref *ref) |
234 | { | 273 | { |
235 | struct irq_glue *glue = | 274 | struct irq_glue *glue = |
236 | container_of(ref, struct irq_glue, notify.kref); | 275 | container_of(ref, struct irq_glue, notify.kref); |
276 | |||
277 | cpu_rmap_put(glue->rmap); | ||
237 | kfree(glue); | 278 | kfree(glue); |
238 | } | 279 | } |
239 | 280 | ||
@@ -258,10 +299,13 @@ int irq_cpu_rmap_add(struct cpu_rmap *rmap, int irq) | |||
258 | glue->notify.notify = irq_cpu_rmap_notify; | 299 | glue->notify.notify = irq_cpu_rmap_notify; |
259 | glue->notify.release = irq_cpu_rmap_release; | 300 | glue->notify.release = irq_cpu_rmap_release; |
260 | glue->rmap = rmap; | 301 | glue->rmap = rmap; |
302 | cpu_rmap_get(rmap); | ||
261 | glue->index = cpu_rmap_add(rmap, glue); | 303 | glue->index = cpu_rmap_add(rmap, glue); |
262 | rc = irq_set_affinity_notifier(irq, &glue->notify); | 304 | rc = irq_set_affinity_notifier(irq, &glue->notify); |
263 | if (rc) | 305 | if (rc) { |
306 | cpu_rmap_put(glue->rmap); | ||
264 | kfree(glue); | 307 | kfree(glue); |
308 | } | ||
265 | return rc; | 309 | return rc; |
266 | } | 310 | } |
267 | EXPORT_SYMBOL(irq_cpu_rmap_add); | 311 | EXPORT_SYMBOL(irq_cpu_rmap_add); |
diff --git a/lib/rbtree.c b/lib/rbtree.c index 4f56a11d67fa..c0e31fe2fabf 100644 --- a/lib/rbtree.c +++ b/lib/rbtree.c | |||
@@ -194,8 +194,12 @@ __rb_insert(struct rb_node *node, struct rb_root *root, | |||
194 | } | 194 | } |
195 | } | 195 | } |
196 | 196 | ||
197 | __always_inline void | 197 | /* |
198 | __rb_erase_color(struct rb_node *parent, struct rb_root *root, | 198 | * Inline version for rb_erase() use - we want to be able to inline |
199 | * and eliminate the dummy_rotate callback there | ||
200 | */ | ||
201 | static __always_inline void | ||
202 | ____rb_erase_color(struct rb_node *parent, struct rb_root *root, | ||
199 | void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) | 203 | void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) |
200 | { | 204 | { |
201 | struct rb_node *node = NULL, *sibling, *tmp1, *tmp2; | 205 | struct rb_node *node = NULL, *sibling, *tmp1, *tmp2; |
@@ -355,6 +359,13 @@ __rb_erase_color(struct rb_node *parent, struct rb_root *root, | |||
355 | } | 359 | } |
356 | } | 360 | } |
357 | } | 361 | } |
362 | |||
363 | /* Non-inline version for rb_erase_augmented() use */ | ||
364 | void __rb_erase_color(struct rb_node *parent, struct rb_root *root, | ||
365 | void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) | ||
366 | { | ||
367 | ____rb_erase_color(parent, root, augment_rotate); | ||
368 | } | ||
358 | EXPORT_SYMBOL(__rb_erase_color); | 369 | EXPORT_SYMBOL(__rb_erase_color); |
359 | 370 | ||
360 | /* | 371 | /* |
@@ -380,7 +391,10 @@ EXPORT_SYMBOL(rb_insert_color); | |||
380 | 391 | ||
381 | void rb_erase(struct rb_node *node, struct rb_root *root) | 392 | void rb_erase(struct rb_node *node, struct rb_root *root) |
382 | { | 393 | { |
383 | rb_erase_augmented(node, root, &dummy_callbacks); | 394 | struct rb_node *rebalance; |
395 | rebalance = __rb_erase_augmented(node, root, &dummy_callbacks); | ||
396 | if (rebalance) | ||
397 | ____rb_erase_color(rebalance, root, dummy_rotate); | ||
384 | } | 398 | } |
385 | EXPORT_SYMBOL(rb_erase); | 399 | EXPORT_SYMBOL(rb_erase); |
386 | 400 | ||
diff --git a/mm/bootmem.c b/mm/bootmem.c index 1324cd74faec..b93376c39b61 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c | |||
@@ -185,10 +185,23 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata) | |||
185 | 185 | ||
186 | while (start < end) { | 186 | while (start < end) { |
187 | unsigned long *map, idx, vec; | 187 | unsigned long *map, idx, vec; |
188 | unsigned shift; | ||
188 | 189 | ||
189 | map = bdata->node_bootmem_map; | 190 | map = bdata->node_bootmem_map; |
190 | idx = start - bdata->node_min_pfn; | 191 | idx = start - bdata->node_min_pfn; |
192 | shift = idx & (BITS_PER_LONG - 1); | ||
193 | /* | ||
194 | * vec holds at most BITS_PER_LONG map bits, | ||
195 | * bit 0 corresponds to start. | ||
196 | */ | ||
191 | vec = ~map[idx / BITS_PER_LONG]; | 197 | vec = ~map[idx / BITS_PER_LONG]; |
198 | |||
199 | if (shift) { | ||
200 | vec >>= shift; | ||
201 | if (end - start >= BITS_PER_LONG) | ||
202 | vec |= ~map[idx / BITS_PER_LONG + 1] << | ||
203 | (BITS_PER_LONG - shift); | ||
204 | } | ||
192 | /* | 205 | /* |
193 | * If we have a properly aligned and fully unreserved | 206 | * If we have a properly aligned and fully unreserved |
194 | * BITS_PER_LONG block of pages in front of us, free | 207 | * BITS_PER_LONG block of pages in front of us, free |
@@ -201,19 +214,18 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata) | |||
201 | count += BITS_PER_LONG; | 214 | count += BITS_PER_LONG; |
202 | start += BITS_PER_LONG; | 215 | start += BITS_PER_LONG; |
203 | } else { | 216 | } else { |
204 | unsigned long off = 0; | 217 | unsigned long cur = start; |
205 | 218 | ||
206 | vec >>= start & (BITS_PER_LONG - 1); | 219 | start = ALIGN(start + 1, BITS_PER_LONG); |
207 | while (vec) { | 220 | while (vec && cur != start) { |
208 | if (vec & 1) { | 221 | if (vec & 1) { |
209 | page = pfn_to_page(start + off); | 222 | page = pfn_to_page(cur); |
210 | __free_pages_bootmem(page, 0); | 223 | __free_pages_bootmem(page, 0); |
211 | count++; | 224 | count++; |
212 | } | 225 | } |
213 | vec >>= 1; | 226 | vec >>= 1; |
214 | off++; | 227 | ++cur; |
215 | } | 228 | } |
216 | start = ALIGN(start + 1, BITS_PER_LONG); | ||
217 | } | 229 | } |
218 | } | 230 | } |
219 | 231 | ||
diff --git a/mm/compaction.c b/mm/compaction.c index 6b807e466497..c62bd063d766 100644 --- a/mm/compaction.c +++ b/mm/compaction.c | |||
@@ -816,6 +816,7 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone, | |||
816 | static int compact_finished(struct zone *zone, | 816 | static int compact_finished(struct zone *zone, |
817 | struct compact_control *cc) | 817 | struct compact_control *cc) |
818 | { | 818 | { |
819 | unsigned int order; | ||
819 | unsigned long watermark; | 820 | unsigned long watermark; |
820 | 821 | ||
821 | if (fatal_signal_pending(current)) | 822 | if (fatal_signal_pending(current)) |
@@ -850,22 +851,16 @@ static int compact_finished(struct zone *zone, | |||
850 | return COMPACT_CONTINUE; | 851 | return COMPACT_CONTINUE; |
851 | 852 | ||
852 | /* Direct compactor: Is a suitable page free? */ | 853 | /* Direct compactor: Is a suitable page free? */ |
853 | if (cc->page) { | 854 | for (order = cc->order; order < MAX_ORDER; order++) { |
854 | /* Was a suitable page captured? */ | 855 | struct free_area *area = &zone->free_area[order]; |
855 | if (*cc->page) | 856 | |
857 | /* Job done if page is free of the right migratetype */ | ||
858 | if (!list_empty(&area->free_list[cc->migratetype])) | ||
859 | return COMPACT_PARTIAL; | ||
860 | |||
861 | /* Job done if allocation would set block type */ | ||
862 | if (cc->order >= pageblock_order && area->nr_free) | ||
856 | return COMPACT_PARTIAL; | 863 | return COMPACT_PARTIAL; |
857 | } else { | ||
858 | unsigned int order; | ||
859 | for (order = cc->order; order < MAX_ORDER; order++) { | ||
860 | struct free_area *area = &zone->free_area[cc->order]; | ||
861 | /* Job done if page is free of the right migratetype */ | ||
862 | if (!list_empty(&area->free_list[cc->migratetype])) | ||
863 | return COMPACT_PARTIAL; | ||
864 | |||
865 | /* Job done if allocation would set block type */ | ||
866 | if (cc->order >= pageblock_order && area->nr_free) | ||
867 | return COMPACT_PARTIAL; | ||
868 | } | ||
869 | } | 864 | } |
870 | 865 | ||
871 | return COMPACT_CONTINUE; | 866 | return COMPACT_CONTINUE; |
@@ -921,60 +916,6 @@ unsigned long compaction_suitable(struct zone *zone, int order) | |||
921 | return COMPACT_CONTINUE; | 916 | return COMPACT_CONTINUE; |
922 | } | 917 | } |
923 | 918 | ||
924 | static void compact_capture_page(struct compact_control *cc) | ||
925 | { | ||
926 | unsigned long flags; | ||
927 | int mtype, mtype_low, mtype_high; | ||
928 | |||
929 | if (!cc->page || *cc->page) | ||
930 | return; | ||
931 | |||
932 | /* | ||
933 | * For MIGRATE_MOVABLE allocations we capture a suitable page ASAP | ||
934 | * regardless of the migratetype of the freelist is is captured from. | ||
935 | * This is fine because the order for a high-order MIGRATE_MOVABLE | ||
936 | * allocation is typically at least a pageblock size and overall | ||
937 | * fragmentation is not impaired. Other allocation types must | ||
938 | * capture pages from their own migratelist because otherwise they | ||
939 | * could pollute other pageblocks like MIGRATE_MOVABLE with | ||
940 | * difficult to move pages and making fragmentation worse overall. | ||
941 | */ | ||
942 | if (cc->migratetype == MIGRATE_MOVABLE) { | ||
943 | mtype_low = 0; | ||
944 | mtype_high = MIGRATE_PCPTYPES; | ||
945 | } else { | ||
946 | mtype_low = cc->migratetype; | ||
947 | mtype_high = cc->migratetype + 1; | ||
948 | } | ||
949 | |||
950 | /* Speculatively examine the free lists without zone lock */ | ||
951 | for (mtype = mtype_low; mtype < mtype_high; mtype++) { | ||
952 | int order; | ||
953 | for (order = cc->order; order < MAX_ORDER; order++) { | ||
954 | struct page *page; | ||
955 | struct free_area *area; | ||
956 | area = &(cc->zone->free_area[order]); | ||
957 | if (list_empty(&area->free_list[mtype])) | ||
958 | continue; | ||
959 | |||
960 | /* Take the lock and attempt capture of the page */ | ||
961 | if (!compact_trylock_irqsave(&cc->zone->lock, &flags, cc)) | ||
962 | return; | ||
963 | if (!list_empty(&area->free_list[mtype])) { | ||
964 | page = list_entry(area->free_list[mtype].next, | ||
965 | struct page, lru); | ||
966 | if (capture_free_page(page, cc->order, mtype)) { | ||
967 | spin_unlock_irqrestore(&cc->zone->lock, | ||
968 | flags); | ||
969 | *cc->page = page; | ||
970 | return; | ||
971 | } | ||
972 | } | ||
973 | spin_unlock_irqrestore(&cc->zone->lock, flags); | ||
974 | } | ||
975 | } | ||
976 | } | ||
977 | |||
978 | static int compact_zone(struct zone *zone, struct compact_control *cc) | 919 | static int compact_zone(struct zone *zone, struct compact_control *cc) |
979 | { | 920 | { |
980 | int ret; | 921 | int ret; |
@@ -1054,9 +995,6 @@ static int compact_zone(struct zone *zone, struct compact_control *cc) | |||
1054 | goto out; | 995 | goto out; |
1055 | } | 996 | } |
1056 | } | 997 | } |
1057 | |||
1058 | /* Capture a page now if it is a suitable size */ | ||
1059 | compact_capture_page(cc); | ||
1060 | } | 998 | } |
1061 | 999 | ||
1062 | out: | 1000 | out: |
@@ -1069,8 +1007,7 @@ out: | |||
1069 | 1007 | ||
1070 | static unsigned long compact_zone_order(struct zone *zone, | 1008 | static unsigned long compact_zone_order(struct zone *zone, |
1071 | int order, gfp_t gfp_mask, | 1009 | int order, gfp_t gfp_mask, |
1072 | bool sync, bool *contended, | 1010 | bool sync, bool *contended) |
1073 | struct page **page) | ||
1074 | { | 1011 | { |
1075 | unsigned long ret; | 1012 | unsigned long ret; |
1076 | struct compact_control cc = { | 1013 | struct compact_control cc = { |
@@ -1080,7 +1017,6 @@ static unsigned long compact_zone_order(struct zone *zone, | |||
1080 | .migratetype = allocflags_to_migratetype(gfp_mask), | 1017 | .migratetype = allocflags_to_migratetype(gfp_mask), |
1081 | .zone = zone, | 1018 | .zone = zone, |
1082 | .sync = sync, | 1019 | .sync = sync, |
1083 | .page = page, | ||
1084 | }; | 1020 | }; |
1085 | INIT_LIST_HEAD(&cc.freepages); | 1021 | INIT_LIST_HEAD(&cc.freepages); |
1086 | INIT_LIST_HEAD(&cc.migratepages); | 1022 | INIT_LIST_HEAD(&cc.migratepages); |
@@ -1110,7 +1046,7 @@ int sysctl_extfrag_threshold = 500; | |||
1110 | */ | 1046 | */ |
1111 | unsigned long try_to_compact_pages(struct zonelist *zonelist, | 1047 | unsigned long try_to_compact_pages(struct zonelist *zonelist, |
1112 | int order, gfp_t gfp_mask, nodemask_t *nodemask, | 1048 | int order, gfp_t gfp_mask, nodemask_t *nodemask, |
1113 | bool sync, bool *contended, struct page **page) | 1049 | bool sync, bool *contended) |
1114 | { | 1050 | { |
1115 | enum zone_type high_zoneidx = gfp_zone(gfp_mask); | 1051 | enum zone_type high_zoneidx = gfp_zone(gfp_mask); |
1116 | int may_enter_fs = gfp_mask & __GFP_FS; | 1052 | int may_enter_fs = gfp_mask & __GFP_FS; |
@@ -1136,7 +1072,7 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist, | |||
1136 | int status; | 1072 | int status; |
1137 | 1073 | ||
1138 | status = compact_zone_order(zone, order, gfp_mask, sync, | 1074 | status = compact_zone_order(zone, order, gfp_mask, sync, |
1139 | contended, page); | 1075 | contended); |
1140 | rc = max(status, rc); | 1076 | rc = max(status, rc); |
1141 | 1077 | ||
1142 | /* If a normal allocation would succeed, stop compacting */ | 1078 | /* If a normal allocation would succeed, stop compacting */ |
@@ -1192,7 +1128,6 @@ int compact_pgdat(pg_data_t *pgdat, int order) | |||
1192 | struct compact_control cc = { | 1128 | struct compact_control cc = { |
1193 | .order = order, | 1129 | .order = order, |
1194 | .sync = false, | 1130 | .sync = false, |
1195 | .page = NULL, | ||
1196 | }; | 1131 | }; |
1197 | 1132 | ||
1198 | return __compact_pgdat(pgdat, &cc); | 1133 | return __compact_pgdat(pgdat, &cc); |
@@ -1203,14 +1138,13 @@ static int compact_node(int nid) | |||
1203 | struct compact_control cc = { | 1138 | struct compact_control cc = { |
1204 | .order = -1, | 1139 | .order = -1, |
1205 | .sync = true, | 1140 | .sync = true, |
1206 | .page = NULL, | ||
1207 | }; | 1141 | }; |
1208 | 1142 | ||
1209 | return __compact_pgdat(NODE_DATA(nid), &cc); | 1143 | return __compact_pgdat(NODE_DATA(nid), &cc); |
1210 | } | 1144 | } |
1211 | 1145 | ||
1212 | /* Compact all nodes in the system */ | 1146 | /* Compact all nodes in the system */ |
1213 | static int compact_nodes(void) | 1147 | static void compact_nodes(void) |
1214 | { | 1148 | { |
1215 | int nid; | 1149 | int nid; |
1216 | 1150 | ||
@@ -1219,8 +1153,6 @@ static int compact_nodes(void) | |||
1219 | 1153 | ||
1220 | for_each_online_node(nid) | 1154 | for_each_online_node(nid) |
1221 | compact_node(nid); | 1155 | compact_node(nid); |
1222 | |||
1223 | return COMPACT_COMPLETE; | ||
1224 | } | 1156 | } |
1225 | 1157 | ||
1226 | /* The written value is actually unused, all memory is compacted */ | 1158 | /* The written value is actually unused, all memory is compacted */ |
@@ -1231,7 +1163,7 @@ int sysctl_compaction_handler(struct ctl_table *table, int write, | |||
1231 | void __user *buffer, size_t *length, loff_t *ppos) | 1163 | void __user *buffer, size_t *length, loff_t *ppos) |
1232 | { | 1164 | { |
1233 | if (write) | 1165 | if (write) |
1234 | return compact_nodes(); | 1166 | compact_nodes(); |
1235 | 1167 | ||
1236 | return 0; | 1168 | return 0; |
1237 | } | 1169 | } |
diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 9e894edc7811..6001ee6347a9 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c | |||
@@ -1819,9 +1819,19 @@ int split_huge_page(struct page *page) | |||
1819 | 1819 | ||
1820 | BUG_ON(is_huge_zero_pfn(page_to_pfn(page))); | 1820 | BUG_ON(is_huge_zero_pfn(page_to_pfn(page))); |
1821 | BUG_ON(!PageAnon(page)); | 1821 | BUG_ON(!PageAnon(page)); |
1822 | anon_vma = page_lock_anon_vma_read(page); | 1822 | |
1823 | /* | ||
1824 | * The caller does not necessarily hold an mmap_sem that would prevent | ||
1825 | * the anon_vma disappearing so we first we take a reference to it | ||
1826 | * and then lock the anon_vma for write. This is similar to | ||
1827 | * page_lock_anon_vma_read except the write lock is taken to serialise | ||
1828 | * against parallel split or collapse operations. | ||
1829 | */ | ||
1830 | anon_vma = page_get_anon_vma(page); | ||
1823 | if (!anon_vma) | 1831 | if (!anon_vma) |
1824 | goto out; | 1832 | goto out; |
1833 | anon_vma_lock_write(anon_vma); | ||
1834 | |||
1825 | ret = 0; | 1835 | ret = 0; |
1826 | if (!PageCompound(page)) | 1836 | if (!PageCompound(page)) |
1827 | goto out_unlock; | 1837 | goto out_unlock; |
@@ -1832,7 +1842,8 @@ int split_huge_page(struct page *page) | |||
1832 | 1842 | ||
1833 | BUG_ON(PageCompound(page)); | 1843 | BUG_ON(PageCompound(page)); |
1834 | out_unlock: | 1844 | out_unlock: |
1835 | page_unlock_anon_vma_read(anon_vma); | 1845 | anon_vma_unlock(anon_vma); |
1846 | put_anon_vma(anon_vma); | ||
1836 | out: | 1847 | out: |
1837 | return ret; | 1848 | return ret; |
1838 | } | 1849 | } |
diff --git a/mm/internal.h b/mm/internal.h index d597f94cc205..9ba21100ebf3 100644 --- a/mm/internal.h +++ b/mm/internal.h | |||
@@ -135,7 +135,6 @@ struct compact_control { | |||
135 | int migratetype; /* MOVABLE, RECLAIMABLE etc */ | 135 | int migratetype; /* MOVABLE, RECLAIMABLE etc */ |
136 | struct zone *zone; | 136 | struct zone *zone; |
137 | bool contended; /* True if a lock was contended */ | 137 | bool contended; /* True if a lock was contended */ |
138 | struct page **page; /* Page captured of requested size */ | ||
139 | }; | 138 | }; |
140 | 139 | ||
141 | unsigned long | 140 | unsigned long |
diff --git a/mm/memblock.c b/mm/memblock.c index 625905523c2a..88adc8afb610 100644 --- a/mm/memblock.c +++ b/mm/memblock.c | |||
@@ -314,7 +314,8 @@ static void __init_memblock memblock_merge_regions(struct memblock_type *type) | |||
314 | } | 314 | } |
315 | 315 | ||
316 | this->size += next->size; | 316 | this->size += next->size; |
317 | memmove(next, next + 1, (type->cnt - (i + 1)) * sizeof(*next)); | 317 | /* move forward from next + 1, index of which is i + 2 */ |
318 | memmove(next, next + 1, (type->cnt - (i + 2)) * sizeof(*next)); | ||
318 | type->cnt--; | 319 | type->cnt--; |
319 | } | 320 | } |
320 | } | 321 | } |
diff --git a/mm/migrate.c b/mm/migrate.c index 3b676b0c5c3e..c38778610aa8 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -1679,9 +1679,21 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm, | |||
1679 | page_xchg_last_nid(new_page, page_last_nid(page)); | 1679 | page_xchg_last_nid(new_page, page_last_nid(page)); |
1680 | 1680 | ||
1681 | isolated = numamigrate_isolate_page(pgdat, page); | 1681 | isolated = numamigrate_isolate_page(pgdat, page); |
1682 | if (!isolated) { | 1682 | |
1683 | /* | ||
1684 | * Failing to isolate or a GUP pin prevents migration. The expected | ||
1685 | * page count is 2. 1 for anonymous pages without a mapping and 1 | ||
1686 | * for the callers pin. If the page was isolated, the page will | ||
1687 | * need to be put back on the LRU. | ||
1688 | */ | ||
1689 | if (!isolated || page_count(page) != 2) { | ||
1683 | count_vm_events(PGMIGRATE_FAIL, HPAGE_PMD_NR); | 1690 | count_vm_events(PGMIGRATE_FAIL, HPAGE_PMD_NR); |
1684 | put_page(new_page); | 1691 | put_page(new_page); |
1692 | if (isolated) { | ||
1693 | putback_lru_page(page); | ||
1694 | isolated = 0; | ||
1695 | goto out; | ||
1696 | } | ||
1685 | goto out_keep_locked; | 1697 | goto out_keep_locked; |
1686 | } | 1698 | } |
1687 | 1699 | ||
@@ -2886,7 +2886,7 @@ static void vm_lock_anon_vma(struct mm_struct *mm, struct anon_vma *anon_vma) | |||
2886 | * The LSB of head.next can't change from under us | 2886 | * The LSB of head.next can't change from under us |
2887 | * because we hold the mm_all_locks_mutex. | 2887 | * because we hold the mm_all_locks_mutex. |
2888 | */ | 2888 | */ |
2889 | down_write(&anon_vma->root->rwsem); | 2889 | down_write_nest_lock(&anon_vma->root->rwsem, &mm->mmap_sem); |
2890 | /* | 2890 | /* |
2891 | * We can safely modify head.next after taking the | 2891 | * We can safely modify head.next after taking the |
2892 | * anon_vma->root->rwsem. If some other vma in this mm shares | 2892 | * anon_vma->root->rwsem. If some other vma in this mm shares |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index bc6cc0e913bd..df2022ff0c8a 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -1384,14 +1384,8 @@ void split_page(struct page *page, unsigned int order) | |||
1384 | set_page_refcounted(page + i); | 1384 | set_page_refcounted(page + i); |
1385 | } | 1385 | } |
1386 | 1386 | ||
1387 | /* | 1387 | static int __isolate_free_page(struct page *page, unsigned int order) |
1388 | * Similar to the split_page family of functions except that the page | ||
1389 | * required at the given order and being isolated now to prevent races | ||
1390 | * with parallel allocators | ||
1391 | */ | ||
1392 | int capture_free_page(struct page *page, int alloc_order, int migratetype) | ||
1393 | { | 1388 | { |
1394 | unsigned int order; | ||
1395 | unsigned long watermark; | 1389 | unsigned long watermark; |
1396 | struct zone *zone; | 1390 | struct zone *zone; |
1397 | int mt; | 1391 | int mt; |
@@ -1399,7 +1393,6 @@ int capture_free_page(struct page *page, int alloc_order, int migratetype) | |||
1399 | BUG_ON(!PageBuddy(page)); | 1393 | BUG_ON(!PageBuddy(page)); |
1400 | 1394 | ||
1401 | zone = page_zone(page); | 1395 | zone = page_zone(page); |
1402 | order = page_order(page); | ||
1403 | mt = get_pageblock_migratetype(page); | 1396 | mt = get_pageblock_migratetype(page); |
1404 | 1397 | ||
1405 | if (mt != MIGRATE_ISOLATE) { | 1398 | if (mt != MIGRATE_ISOLATE) { |
@@ -1408,7 +1401,7 @@ int capture_free_page(struct page *page, int alloc_order, int migratetype) | |||
1408 | if (!zone_watermark_ok(zone, 0, watermark, 0, 0)) | 1401 | if (!zone_watermark_ok(zone, 0, watermark, 0, 0)) |
1409 | return 0; | 1402 | return 0; |
1410 | 1403 | ||
1411 | __mod_zone_freepage_state(zone, -(1UL << alloc_order), mt); | 1404 | __mod_zone_freepage_state(zone, -(1UL << order), mt); |
1412 | } | 1405 | } |
1413 | 1406 | ||
1414 | /* Remove page from free list */ | 1407 | /* Remove page from free list */ |
@@ -1416,11 +1409,7 @@ int capture_free_page(struct page *page, int alloc_order, int migratetype) | |||
1416 | zone->free_area[order].nr_free--; | 1409 | zone->free_area[order].nr_free--; |
1417 | rmv_page_order(page); | 1410 | rmv_page_order(page); |
1418 | 1411 | ||
1419 | if (alloc_order != order) | 1412 | /* Set the pageblock if the isolated page is at least a pageblock */ |
1420 | expand(zone, page, alloc_order, order, | ||
1421 | &zone->free_area[order], migratetype); | ||
1422 | |||
1423 | /* Set the pageblock if the captured page is at least a pageblock */ | ||
1424 | if (order >= pageblock_order - 1) { | 1413 | if (order >= pageblock_order - 1) { |
1425 | struct page *endpage = page + (1 << order) - 1; | 1414 | struct page *endpage = page + (1 << order) - 1; |
1426 | for (; page < endpage; page += pageblock_nr_pages) { | 1415 | for (; page < endpage; page += pageblock_nr_pages) { |
@@ -1431,7 +1420,7 @@ int capture_free_page(struct page *page, int alloc_order, int migratetype) | |||
1431 | } | 1420 | } |
1432 | } | 1421 | } |
1433 | 1422 | ||
1434 | return 1UL << alloc_order; | 1423 | return 1UL << order; |
1435 | } | 1424 | } |
1436 | 1425 | ||
1437 | /* | 1426 | /* |
@@ -1449,10 +1438,9 @@ int split_free_page(struct page *page) | |||
1449 | unsigned int order; | 1438 | unsigned int order; |
1450 | int nr_pages; | 1439 | int nr_pages; |
1451 | 1440 | ||
1452 | BUG_ON(!PageBuddy(page)); | ||
1453 | order = page_order(page); | 1441 | order = page_order(page); |
1454 | 1442 | ||
1455 | nr_pages = capture_free_page(page, order, 0); | 1443 | nr_pages = __isolate_free_page(page, order); |
1456 | if (!nr_pages) | 1444 | if (!nr_pages) |
1457 | return 0; | 1445 | return 0; |
1458 | 1446 | ||
@@ -2136,8 +2124,6 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order, | |||
2136 | bool *contended_compaction, bool *deferred_compaction, | 2124 | bool *contended_compaction, bool *deferred_compaction, |
2137 | unsigned long *did_some_progress) | 2125 | unsigned long *did_some_progress) |
2138 | { | 2126 | { |
2139 | struct page *page = NULL; | ||
2140 | |||
2141 | if (!order) | 2127 | if (!order) |
2142 | return NULL; | 2128 | return NULL; |
2143 | 2129 | ||
@@ -2149,16 +2135,12 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order, | |||
2149 | current->flags |= PF_MEMALLOC; | 2135 | current->flags |= PF_MEMALLOC; |
2150 | *did_some_progress = try_to_compact_pages(zonelist, order, gfp_mask, | 2136 | *did_some_progress = try_to_compact_pages(zonelist, order, gfp_mask, |
2151 | nodemask, sync_migration, | 2137 | nodemask, sync_migration, |
2152 | contended_compaction, &page); | 2138 | contended_compaction); |
2153 | current->flags &= ~PF_MEMALLOC; | 2139 | current->flags &= ~PF_MEMALLOC; |
2154 | 2140 | ||
2155 | /* If compaction captured a page, prep and use it */ | ||
2156 | if (page) { | ||
2157 | prep_new_page(page, order, gfp_mask); | ||
2158 | goto got_page; | ||
2159 | } | ||
2160 | |||
2161 | if (*did_some_progress != COMPACT_SKIPPED) { | 2141 | if (*did_some_progress != COMPACT_SKIPPED) { |
2142 | struct page *page; | ||
2143 | |||
2162 | /* Page migration frees to the PCP lists but we want merging */ | 2144 | /* Page migration frees to the PCP lists but we want merging */ |
2163 | drain_pages(get_cpu()); | 2145 | drain_pages(get_cpu()); |
2164 | put_cpu(); | 2146 | put_cpu(); |
@@ -2168,7 +2150,6 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order, | |||
2168 | alloc_flags & ~ALLOC_NO_WATERMARKS, | 2150 | alloc_flags & ~ALLOC_NO_WATERMARKS, |
2169 | preferred_zone, migratetype); | 2151 | preferred_zone, migratetype); |
2170 | if (page) { | 2152 | if (page) { |
2171 | got_page: | ||
2172 | preferred_zone->compact_blockskip_flush = false; | 2153 | preferred_zone->compact_blockskip_flush = false; |
2173 | preferred_zone->compact_considered = 0; | 2154 | preferred_zone->compact_considered = 0; |
2174 | preferred_zone->compact_defer_shift = 0; | 2155 | preferred_zone->compact_defer_shift = 0; |
@@ -5604,7 +5585,7 @@ static inline int pfn_to_bitidx(struct zone *zone, unsigned long pfn) | |||
5604 | pfn &= (PAGES_PER_SECTION-1); | 5585 | pfn &= (PAGES_PER_SECTION-1); |
5605 | return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS; | 5586 | return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS; |
5606 | #else | 5587 | #else |
5607 | pfn = pfn - zone->zone_start_pfn; | 5588 | pfn = pfn - round_down(zone->zone_start_pfn, pageblock_nr_pages); |
5608 | return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS; | 5589 | return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS; |
5609 | #endif /* CONFIG_SPARSEMEM */ | 5590 | #endif /* CONFIG_SPARSEMEM */ |
5610 | } | 5591 | } |
diff --git a/net/core/dev.c b/net/core/dev.c index 515473ee52cb..f64e439b4a00 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -6121,6 +6121,14 @@ struct netdev_queue *dev_ingress_queue_create(struct net_device *dev) | |||
6121 | 6121 | ||
6122 | static const struct ethtool_ops default_ethtool_ops; | 6122 | static const struct ethtool_ops default_ethtool_ops; |
6123 | 6123 | ||
6124 | void netdev_set_default_ethtool_ops(struct net_device *dev, | ||
6125 | const struct ethtool_ops *ops) | ||
6126 | { | ||
6127 | if (dev->ethtool_ops == &default_ethtool_ops) | ||
6128 | dev->ethtool_ops = ops; | ||
6129 | } | ||
6130 | EXPORT_SYMBOL_GPL(netdev_set_default_ethtool_ops); | ||
6131 | |||
6124 | /** | 6132 | /** |
6125 | * alloc_netdev_mqs - allocate network device | 6133 | * alloc_netdev_mqs - allocate network device |
6126 | * @sizeof_priv: size of private data to allocate space for | 6134 | * @sizeof_priv: size of private data to allocate space for |
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 3c9d20880283..d9c4f113d709 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
@@ -590,7 +590,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, | |||
590 | case IP_TTL: | 590 | case IP_TTL: |
591 | if (optlen < 1) | 591 | if (optlen < 1) |
592 | goto e_inval; | 592 | goto e_inval; |
593 | if (val != -1 && (val < 0 || val > 255)) | 593 | if (val != -1 && (val < 1 || val > 255)) |
594 | goto e_inval; | 594 | goto e_inval; |
595 | inet->uc_ttl = val; | 595 | inet->uc_ttl = val; |
596 | break; | 596 | break; |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 1ca253635f7a..2aa69c8ae60c 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -1428,12 +1428,12 @@ static void tcp_service_net_dma(struct sock *sk, bool wait) | |||
1428 | } | 1428 | } |
1429 | #endif | 1429 | #endif |
1430 | 1430 | ||
1431 | static inline struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off) | 1431 | static struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off) |
1432 | { | 1432 | { |
1433 | struct sk_buff *skb; | 1433 | struct sk_buff *skb; |
1434 | u32 offset; | 1434 | u32 offset; |
1435 | 1435 | ||
1436 | skb_queue_walk(&sk->sk_receive_queue, skb) { | 1436 | while ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) { |
1437 | offset = seq - TCP_SKB_CB(skb)->seq; | 1437 | offset = seq - TCP_SKB_CB(skb)->seq; |
1438 | if (tcp_hdr(skb)->syn) | 1438 | if (tcp_hdr(skb)->syn) |
1439 | offset--; | 1439 | offset--; |
@@ -1441,6 +1441,11 @@ static inline struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off) | |||
1441 | *off = offset; | 1441 | *off = offset; |
1442 | return skb; | 1442 | return skb; |
1443 | } | 1443 | } |
1444 | /* This looks weird, but this can happen if TCP collapsing | ||
1445 | * splitted a fat GRO packet, while we released socket lock | ||
1446 | * in skb_splice_bits() | ||
1447 | */ | ||
1448 | sk_eat_skb(sk, skb, false); | ||
1444 | } | 1449 | } |
1445 | return NULL; | 1450 | return NULL; |
1446 | } | 1451 | } |
@@ -1482,7 +1487,7 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, | |||
1482 | break; | 1487 | break; |
1483 | } | 1488 | } |
1484 | used = recv_actor(desc, skb, offset, len); | 1489 | used = recv_actor(desc, skb, offset, len); |
1485 | if (used < 0) { | 1490 | if (used <= 0) { |
1486 | if (!copied) | 1491 | if (!copied) |
1487 | copied = used; | 1492 | copied = used; |
1488 | break; | 1493 | break; |
@@ -1520,8 +1525,10 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, | |||
1520 | tcp_rcv_space_adjust(sk); | 1525 | tcp_rcv_space_adjust(sk); |
1521 | 1526 | ||
1522 | /* Clean up data we have read: This will do ACK frames. */ | 1527 | /* Clean up data we have read: This will do ACK frames. */ |
1523 | if (copied > 0) | 1528 | if (copied > 0) { |
1529 | tcp_recv_skb(sk, seq, &offset); | ||
1524 | tcp_cleanup_rbuf(sk, copied); | 1530 | tcp_cleanup_rbuf(sk, copied); |
1531 | } | ||
1525 | return copied; | 1532 | return copied; |
1526 | } | 1533 | } |
1527 | EXPORT_SYMBOL(tcp_read_sock); | 1534 | EXPORT_SYMBOL(tcp_read_sock); |
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index a28e4db8a952..18f97ca76b00 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -5543,7 +5543,7 @@ slow_path: | |||
5543 | if (len < (th->doff << 2) || tcp_checksum_complete_user(sk, skb)) | 5543 | if (len < (th->doff << 2) || tcp_checksum_complete_user(sk, skb)) |
5544 | goto csum_error; | 5544 | goto csum_error; |
5545 | 5545 | ||
5546 | if (!th->ack) | 5546 | if (!th->ack && !th->rst) |
5547 | goto discard; | 5547 | goto discard; |
5548 | 5548 | ||
5549 | /* | 5549 | /* |
@@ -5988,7 +5988,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, | |||
5988 | goto discard; | 5988 | goto discard; |
5989 | } | 5989 | } |
5990 | 5990 | ||
5991 | if (!th->ack) | 5991 | if (!th->ack && !th->rst) |
5992 | goto discard; | 5992 | goto discard; |
5993 | 5993 | ||
5994 | if (!tcp_validate_incoming(sk, skb, th, 0)) | 5994 | if (!tcp_validate_incoming(sk, skb, th, 0)) |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 408cac4ae00a..420e56326384 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -154,6 +154,11 @@ static void addrconf_type_change(struct net_device *dev, | |||
154 | unsigned long event); | 154 | unsigned long event); |
155 | static int addrconf_ifdown(struct net_device *dev, int how); | 155 | static int addrconf_ifdown(struct net_device *dev, int how); |
156 | 156 | ||
157 | static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, | ||
158 | int plen, | ||
159 | const struct net_device *dev, | ||
160 | u32 flags, u32 noflags); | ||
161 | |||
157 | static void addrconf_dad_start(struct inet6_ifaddr *ifp); | 162 | static void addrconf_dad_start(struct inet6_ifaddr *ifp); |
158 | static void addrconf_dad_timer(unsigned long data); | 163 | static void addrconf_dad_timer(unsigned long data); |
159 | static void addrconf_dad_completed(struct inet6_ifaddr *ifp); | 164 | static void addrconf_dad_completed(struct inet6_ifaddr *ifp); |
@@ -250,12 +255,6 @@ static inline bool addrconf_qdisc_ok(const struct net_device *dev) | |||
250 | return !qdisc_tx_is_noop(dev); | 255 | return !qdisc_tx_is_noop(dev); |
251 | } | 256 | } |
252 | 257 | ||
253 | /* Check if a route is valid prefix route */ | ||
254 | static inline int addrconf_is_prefix_route(const struct rt6_info *rt) | ||
255 | { | ||
256 | return (rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0; | ||
257 | } | ||
258 | |||
259 | static void addrconf_del_timer(struct inet6_ifaddr *ifp) | 258 | static void addrconf_del_timer(struct inet6_ifaddr *ifp) |
260 | { | 259 | { |
261 | if (del_timer(&ifp->timer)) | 260 | if (del_timer(&ifp->timer)) |
@@ -941,17 +940,15 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
941 | if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) { | 940 | if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) { |
942 | struct in6_addr prefix; | 941 | struct in6_addr prefix; |
943 | struct rt6_info *rt; | 942 | struct rt6_info *rt; |
944 | struct net *net = dev_net(ifp->idev->dev); | ||
945 | struct flowi6 fl6 = {}; | ||
946 | 943 | ||
947 | ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len); | 944 | ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len); |
948 | fl6.flowi6_oif = ifp->idev->dev->ifindex; | ||
949 | fl6.daddr = prefix; | ||
950 | rt = (struct rt6_info *)ip6_route_lookup(net, &fl6, | ||
951 | RT6_LOOKUP_F_IFACE); | ||
952 | 945 | ||
953 | if (rt != net->ipv6.ip6_null_entry && | 946 | rt = addrconf_get_prefix_route(&prefix, |
954 | addrconf_is_prefix_route(rt)) { | 947 | ifp->prefix_len, |
948 | ifp->idev->dev, | ||
949 | 0, RTF_GATEWAY | RTF_DEFAULT); | ||
950 | |||
951 | if (rt) { | ||
955 | if (onlink == 0) { | 952 | if (onlink == 0) { |
956 | ip6_del_rt(rt); | 953 | ip6_del_rt(rt); |
957 | rt = NULL; | 954 | rt = NULL; |
@@ -1877,7 +1874,7 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, | |||
1877 | continue; | 1874 | continue; |
1878 | if ((rt->rt6i_flags & flags) != flags) | 1875 | if ((rt->rt6i_flags & flags) != flags) |
1879 | continue; | 1876 | continue; |
1880 | if ((noflags != 0) && ((rt->rt6i_flags & flags) != 0)) | 1877 | if ((rt->rt6i_flags & noflags) != 0) |
1881 | continue; | 1878 | continue; |
1882 | dst_hold(&rt->dst); | 1879 | dst_hold(&rt->dst); |
1883 | break; | 1880 | break; |
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index 3ad1f9db5f8b..df082508362d 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c | |||
@@ -1806,7 +1806,7 @@ static void iucv_external_interrupt(struct ext_code ext_code, | |||
1806 | struct iucv_irq_data *p; | 1806 | struct iucv_irq_data *p; |
1807 | struct iucv_irq_list *work; | 1807 | struct iucv_irq_list *work; |
1808 | 1808 | ||
1809 | kstat_cpu(smp_processor_id()).irqs[EXTINT_IUC]++; | 1809 | inc_irq_stat(IRQEXT_IUC); |
1810 | p = iucv_irq_data[smp_processor_id()]; | 1810 | p = iucv_irq_data[smp_processor_id()]; |
1811 | if (p->ippathid >= iucv_max_pathid) { | 1811 | if (p->ippathid >= iucv_max_pathid) { |
1812 | WARN_ON(p->ippathid >= iucv_max_pathid); | 1812 | WARN_ON(p->ippathid >= iucv_max_pathid); |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5c61677487cf..47e0aca614b7 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1009,6 +1009,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1009 | if (old_probe_resp) | 1009 | if (old_probe_resp) |
1010 | kfree_rcu(old_probe_resp, rcu_head); | 1010 | kfree_rcu(old_probe_resp, rcu_head); |
1011 | 1011 | ||
1012 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
1013 | sta_info_flush(local, vlan); | ||
1012 | sta_info_flush(local, sdata); | 1014 | sta_info_flush(local, sdata); |
1013 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | 1015 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); |
1014 | 1016 | ||
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 53f03120db55..80e55527504b 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | #include <linux/nl80211.h> | 5 | #include <linux/nl80211.h> |
6 | #include <linux/export.h> | 6 | #include <linux/export.h> |
7 | #include <linux/rtnetlink.h> | ||
7 | #include <net/cfg80211.h> | 8 | #include <net/cfg80211.h> |
8 | #include "ieee80211_i.h" | 9 | #include "ieee80211_i.h" |
9 | #include "driver-ops.h" | 10 | #include "driver-ops.h" |
@@ -197,6 +198,15 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) | |||
197 | 198 | ||
198 | ctx = container_of(conf, struct ieee80211_chanctx, conf); | 199 | ctx = container_of(conf, struct ieee80211_chanctx, conf); |
199 | 200 | ||
201 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
202 | struct ieee80211_sub_if_data *vlan; | ||
203 | |||
204 | /* for the VLAN list */ | ||
205 | ASSERT_RTNL(); | ||
206 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
207 | rcu_assign_pointer(vlan->vif.chanctx_conf, NULL); | ||
208 | } | ||
209 | |||
200 | ieee80211_unassign_vif_chanctx(sdata, ctx); | 210 | ieee80211_unassign_vif_chanctx(sdata, ctx); |
201 | if (ctx->refcount == 0) | 211 | if (ctx->refcount == 0) |
202 | ieee80211_free_chanctx(local, ctx); | 212 | ieee80211_free_chanctx(local, ctx); |
@@ -316,6 +326,15 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
316 | goto out; | 326 | goto out; |
317 | } | 327 | } |
318 | 328 | ||
329 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
330 | struct ieee80211_sub_if_data *vlan; | ||
331 | |||
332 | /* for the VLAN list */ | ||
333 | ASSERT_RTNL(); | ||
334 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
335 | rcu_assign_pointer(vlan->vif.chanctx_conf, &ctx->conf); | ||
336 | } | ||
337 | |||
319 | ieee80211_recalc_smps_chanctx(local, ctx); | 338 | ieee80211_recalc_smps_chanctx(local, ctx); |
320 | out: | 339 | out: |
321 | mutex_unlock(&local->chanctx_mtx); | 340 | mutex_unlock(&local->chanctx_mtx); |
@@ -331,6 +350,25 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) | |||
331 | mutex_unlock(&sdata->local->chanctx_mtx); | 350 | mutex_unlock(&sdata->local->chanctx_mtx); |
332 | } | 351 | } |
333 | 352 | ||
353 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata) | ||
354 | { | ||
355 | struct ieee80211_local *local = sdata->local; | ||
356 | struct ieee80211_sub_if_data *ap; | ||
357 | struct ieee80211_chanctx_conf *conf; | ||
358 | |||
359 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->bss)) | ||
360 | return; | ||
361 | |||
362 | ap = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap); | ||
363 | |||
364 | mutex_lock(&local->chanctx_mtx); | ||
365 | |||
366 | conf = rcu_dereference_protected(ap->vif.chanctx_conf, | ||
367 | lockdep_is_held(&local->chanctx_mtx)); | ||
368 | rcu_assign_pointer(sdata->vif.chanctx_conf, conf); | ||
369 | mutex_unlock(&local->chanctx_mtx); | ||
370 | } | ||
371 | |||
334 | void ieee80211_iter_chan_contexts_atomic( | 372 | void ieee80211_iter_chan_contexts_atomic( |
335 | struct ieee80211_hw *hw, | 373 | struct ieee80211_hw *hw, |
336 | void (*iter)(struct ieee80211_hw *hw, | 374 | void (*iter)(struct ieee80211_hw *hw, |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 8881fc77fb13..6b7644e818d8 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -703,8 +703,8 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) | |||
703 | sdata_info(sdata, | 703 | sdata_info(sdata, |
704 | "No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n"); | 704 | "No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n"); |
705 | 705 | ||
706 | ieee80211_request_internal_scan(sdata, | 706 | ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len, |
707 | ifibss->ssid, ifibss->ssid_len, NULL); | 707 | NULL); |
708 | } | 708 | } |
709 | 709 | ||
710 | static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | 710 | static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) |
@@ -802,9 +802,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
802 | IEEE80211_SCAN_INTERVAL)) { | 802 | IEEE80211_SCAN_INTERVAL)) { |
803 | sdata_info(sdata, "Trigger new scan to find an IBSS to join\n"); | 803 | sdata_info(sdata, "Trigger new scan to find an IBSS to join\n"); |
804 | 804 | ||
805 | ieee80211_request_internal_scan(sdata, | 805 | ieee80211_request_ibss_scan(sdata, ifibss->ssid, |
806 | ifibss->ssid, ifibss->ssid_len, | 806 | ifibss->ssid_len, chan); |
807 | ifibss->fixed_channel ? ifibss->channel : NULL); | ||
808 | } else { | 807 | } else { |
809 | int interval = IEEE80211_SCAN_INTERVAL; | 808 | int interval = IEEE80211_SCAN_INTERVAL; |
810 | 809 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 42d0d0267730..8563b9a5cac3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -92,8 +92,6 @@ struct ieee80211_bss { | |||
92 | 92 | ||
93 | u32 device_ts; | 93 | u32 device_ts; |
94 | 94 | ||
95 | u8 dtim_period; | ||
96 | |||
97 | bool wmm_used; | 95 | bool wmm_used; |
98 | bool uapsd_supported; | 96 | bool uapsd_supported; |
99 | 97 | ||
@@ -140,7 +138,6 @@ enum ieee80211_bss_corrupt_data_flags { | |||
140 | 138 | ||
141 | /** | 139 | /** |
142 | * enum ieee80211_valid_data_flags - BSS valid data flags | 140 | * enum ieee80211_valid_data_flags - BSS valid data flags |
143 | * @IEEE80211_BSS_VALID_DTIM: DTIM data was gathered from non-corrupt IE | ||
144 | * @IEEE80211_BSS_VALID_WMM: WMM/UAPSD data was gathered from non-corrupt IE | 141 | * @IEEE80211_BSS_VALID_WMM: WMM/UAPSD data was gathered from non-corrupt IE |
145 | * @IEEE80211_BSS_VALID_RATES: Supported rates were gathered from non-corrupt IE | 142 | * @IEEE80211_BSS_VALID_RATES: Supported rates were gathered from non-corrupt IE |
146 | * @IEEE80211_BSS_VALID_ERP: ERP flag was gathered from non-corrupt IE | 143 | * @IEEE80211_BSS_VALID_ERP: ERP flag was gathered from non-corrupt IE |
@@ -151,7 +148,6 @@ enum ieee80211_bss_corrupt_data_flags { | |||
151 | * beacon/probe response. | 148 | * beacon/probe response. |
152 | */ | 149 | */ |
153 | enum ieee80211_bss_valid_data_flags { | 150 | enum ieee80211_bss_valid_data_flags { |
154 | IEEE80211_BSS_VALID_DTIM = BIT(0), | ||
155 | IEEE80211_BSS_VALID_WMM = BIT(1), | 151 | IEEE80211_BSS_VALID_WMM = BIT(1), |
156 | IEEE80211_BSS_VALID_RATES = BIT(2), | 152 | IEEE80211_BSS_VALID_RATES = BIT(2), |
157 | IEEE80211_BSS_VALID_ERP = BIT(3) | 153 | IEEE80211_BSS_VALID_ERP = BIT(3) |
@@ -440,6 +436,7 @@ struct ieee80211_if_managed { | |||
440 | unsigned long timers_running; /* used for quiesce/restart */ | 436 | unsigned long timers_running; /* used for quiesce/restart */ |
441 | bool powersave; /* powersave requested for this iface */ | 437 | bool powersave; /* powersave requested for this iface */ |
442 | bool broken_ap; /* AP is broken -- turn off powersave */ | 438 | bool broken_ap; /* AP is broken -- turn off powersave */ |
439 | u8 dtim_period; | ||
443 | enum ieee80211_smps_mode req_smps, /* requested smps mode */ | 440 | enum ieee80211_smps_mode req_smps, /* requested smps mode */ |
444 | driver_smps_mode; /* smps mode request */ | 441 | driver_smps_mode; /* smps mode request */ |
445 | 442 | ||
@@ -773,6 +770,10 @@ struct ieee80211_sub_if_data { | |||
773 | u32 mntr_flags; | 770 | u32 mntr_flags; |
774 | } u; | 771 | } u; |
775 | 772 | ||
773 | spinlock_t cleanup_stations_lock; | ||
774 | struct list_head cleanup_stations; | ||
775 | struct work_struct cleanup_stations_wk; | ||
776 | |||
776 | #ifdef CONFIG_MAC80211_DEBUGFS | 777 | #ifdef CONFIG_MAC80211_DEBUGFS |
777 | struct { | 778 | struct { |
778 | struct dentry *dir; | 779 | struct dentry *dir; |
@@ -1329,9 +1330,9 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1329 | 1330 | ||
1330 | /* scan/BSS handling */ | 1331 | /* scan/BSS handling */ |
1331 | void ieee80211_scan_work(struct work_struct *work); | 1332 | void ieee80211_scan_work(struct work_struct *work); |
1332 | int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, | 1333 | int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, |
1333 | const u8 *ssid, u8 ssid_len, | 1334 | const u8 *ssid, u8 ssid_len, |
1334 | struct ieee80211_channel *chan); | 1335 | struct ieee80211_channel *chan); |
1335 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | 1336 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, |
1336 | struct cfg80211_scan_request *req); | 1337 | struct cfg80211_scan_request *req); |
1337 | void ieee80211_scan_cancel(struct ieee80211_local *local); | 1338 | void ieee80211_scan_cancel(struct ieee80211_local *local); |
@@ -1628,6 +1629,7 @@ ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
1628 | const struct cfg80211_chan_def *chandef, | 1629 | const struct cfg80211_chan_def *chandef, |
1629 | enum ieee80211_chanctx_mode mode); | 1630 | enum ieee80211_chanctx_mode mode); |
1630 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); | 1631 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); |
1632 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); | ||
1631 | 1633 | ||
1632 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | 1634 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, |
1633 | struct ieee80211_chanctx *chanctx); | 1635 | struct ieee80211_chanctx *chanctx); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 09a80b55cf5a..8be854e86cd9 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -207,17 +207,8 @@ void ieee80211_recalc_idle(struct ieee80211_local *local) | |||
207 | 207 | ||
208 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | 208 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) |
209 | { | 209 | { |
210 | int meshhdrlen; | 210 | if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN) |
211 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
212 | |||
213 | meshhdrlen = (sdata->vif.type == NL80211_IFTYPE_MESH_POINT) ? 5 : 0; | ||
214 | |||
215 | /* FIX: what would be proper limits for MTU? | ||
216 | * This interface uses 802.3 frames. */ | ||
217 | if (new_mtu < 256 || | ||
218 | new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) { | ||
219 | return -EINVAL; | 211 | return -EINVAL; |
220 | } | ||
221 | 212 | ||
222 | dev->mtu = new_mtu; | 213 | dev->mtu = new_mtu; |
223 | return 0; | 214 | return 0; |
@@ -586,11 +577,13 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
586 | 577 | ||
587 | switch (sdata->vif.type) { | 578 | switch (sdata->vif.type) { |
588 | case NL80211_IFTYPE_AP_VLAN: | 579 | case NL80211_IFTYPE_AP_VLAN: |
589 | /* no need to tell driver, but set carrier */ | 580 | /* no need to tell driver, but set carrier and chanctx */ |
590 | if (rtnl_dereference(sdata->bss->beacon)) | 581 | if (rtnl_dereference(sdata->bss->beacon)) { |
582 | ieee80211_vif_vlan_copy_chanctx(sdata); | ||
591 | netif_carrier_on(dev); | 583 | netif_carrier_on(dev); |
592 | else | 584 | } else { |
593 | netif_carrier_off(dev); | 585 | netif_carrier_off(dev); |
586 | } | ||
594 | break; | 587 | break; |
595 | case NL80211_IFTYPE_MONITOR: | 588 | case NL80211_IFTYPE_MONITOR: |
596 | if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) { | 589 | if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) { |
@@ -839,6 +832,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
839 | switch (sdata->vif.type) { | 832 | switch (sdata->vif.type) { |
840 | case NL80211_IFTYPE_AP_VLAN: | 833 | case NL80211_IFTYPE_AP_VLAN: |
841 | list_del(&sdata->u.vlan.list); | 834 | list_del(&sdata->u.vlan.list); |
835 | rcu_assign_pointer(sdata->vif.chanctx_conf, NULL); | ||
842 | /* no need to tell driver */ | 836 | /* no need to tell driver */ |
843 | break; | 837 | break; |
844 | case NL80211_IFTYPE_MONITOR: | 838 | case NL80211_IFTYPE_MONITOR: |
@@ -865,20 +859,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
865 | cancel_work_sync(&sdata->work); | 859 | cancel_work_sync(&sdata->work); |
866 | /* | 860 | /* |
867 | * When we get here, the interface is marked down. | 861 | * When we get here, the interface is marked down. |
868 | * Call rcu_barrier() to wait both for the RX path | 862 | * Call synchronize_rcu() to wait for the RX path |
869 | * should it be using the interface and enqueuing | 863 | * should it be using the interface and enqueuing |
870 | * frames at this very time on another CPU, and | 864 | * frames at this very time on another CPU. |
871 | * for the sta free call_rcu callbacks. | ||
872 | */ | ||
873 | rcu_barrier(); | ||
874 | |||
875 | /* | ||
876 | * free_sta_rcu() enqueues a work for the actual | ||
877 | * sta cleanup, so we need to flush it while | ||
878 | * sdata is still valid. | ||
879 | */ | 865 | */ |
880 | flush_workqueue(local->workqueue); | 866 | synchronize_rcu(); |
881 | |||
882 | skb_queue_purge(&sdata->skb_queue); | 867 | skb_queue_purge(&sdata->skb_queue); |
883 | 868 | ||
884 | /* | 869 | /* |
@@ -1498,6 +1483,15 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | |||
1498 | mutex_unlock(&local->iflist_mtx); | 1483 | mutex_unlock(&local->iflist_mtx); |
1499 | } | 1484 | } |
1500 | 1485 | ||
1486 | static void ieee80211_cleanup_sdata_stas_wk(struct work_struct *wk) | ||
1487 | { | ||
1488 | struct ieee80211_sub_if_data *sdata; | ||
1489 | |||
1490 | sdata = container_of(wk, struct ieee80211_sub_if_data, cleanup_stations_wk); | ||
1491 | |||
1492 | ieee80211_cleanup_sdata_stas(sdata); | ||
1493 | } | ||
1494 | |||
1501 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, | 1495 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, |
1502 | struct wireless_dev **new_wdev, enum nl80211_iftype type, | 1496 | struct wireless_dev **new_wdev, enum nl80211_iftype type, |
1503 | struct vif_params *params) | 1497 | struct vif_params *params) |
@@ -1573,6 +1567,10 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1573 | 1567 | ||
1574 | INIT_LIST_HEAD(&sdata->key_list); | 1568 | INIT_LIST_HEAD(&sdata->key_list); |
1575 | 1569 | ||
1570 | spin_lock_init(&sdata->cleanup_stations_lock); | ||
1571 | INIT_LIST_HEAD(&sdata->cleanup_stations); | ||
1572 | INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk); | ||
1573 | |||
1576 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | 1574 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
1577 | struct ieee80211_supported_band *sband; | 1575 | struct ieee80211_supported_band *sband; |
1578 | sband = local->hw.wiphy->bands[i]; | 1576 | sband = local->hw.wiphy->bands[i]; |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 1bf03f9ff3ba..649ad513547f 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -163,7 +163,7 @@ int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) | |||
163 | return -ENOMEM; | 163 | return -ENOMEM; |
164 | sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1; | 164 | sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1; |
165 | for (i = 0; i < RMC_BUCKETS; i++) | 165 | for (i = 0; i < RMC_BUCKETS; i++) |
166 | INIT_LIST_HEAD(&sdata->u.mesh.rmc->bucket[i].list); | 166 | INIT_LIST_HEAD(&sdata->u.mesh.rmc->bucket[i]); |
167 | return 0; | 167 | return 0; |
168 | } | 168 | } |
169 | 169 | ||
@@ -177,7 +177,7 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata) | |||
177 | return; | 177 | return; |
178 | 178 | ||
179 | for (i = 0; i < RMC_BUCKETS; i++) | 179 | for (i = 0; i < RMC_BUCKETS; i++) |
180 | list_for_each_entry_safe(p, n, &rmc->bucket[i].list, list) { | 180 | list_for_each_entry_safe(p, n, &rmc->bucket[i], list) { |
181 | list_del(&p->list); | 181 | list_del(&p->list); |
182 | kmem_cache_free(rm_cache, p); | 182 | kmem_cache_free(rm_cache, p); |
183 | } | 183 | } |
@@ -210,7 +210,7 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr, | |||
210 | /* Don't care about endianness since only match matters */ | 210 | /* Don't care about endianness since only match matters */ |
211 | memcpy(&seqnum, &mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum)); | 211 | memcpy(&seqnum, &mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum)); |
212 | idx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask; | 212 | idx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask; |
213 | list_for_each_entry_safe(p, n, &rmc->bucket[idx].list, list) { | 213 | list_for_each_entry_safe(p, n, &rmc->bucket[idx], list) { |
214 | ++entries; | 214 | ++entries; |
215 | if (time_after(jiffies, p->exp_time) || | 215 | if (time_after(jiffies, p->exp_time) || |
216 | (entries == RMC_QUEUE_MAX_LEN)) { | 216 | (entries == RMC_QUEUE_MAX_LEN)) { |
@@ -229,7 +229,7 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr, | |||
229 | p->seqnum = seqnum; | 229 | p->seqnum = seqnum; |
230 | p->exp_time = jiffies + RMC_TIMEOUT; | 230 | p->exp_time = jiffies + RMC_TIMEOUT; |
231 | memcpy(p->sa, sa, ETH_ALEN); | 231 | memcpy(p->sa, sa, ETH_ALEN); |
232 | list_add(&p->list, &rmc->bucket[idx].list); | 232 | list_add(&p->list, &rmc->bucket[idx]); |
233 | return 0; | 233 | return 0; |
234 | } | 234 | } |
235 | 235 | ||
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 7c9215fb2ac8..84c28c6101cd 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -184,7 +184,7 @@ struct rmc_entry { | |||
184 | }; | 184 | }; |
185 | 185 | ||
186 | struct mesh_rmc { | 186 | struct mesh_rmc { |
187 | struct rmc_entry bucket[RMC_BUCKETS]; | 187 | struct list_head bucket[RMC_BUCKETS]; |
188 | u32 idx_mask; | 188 | u32 idx_mask; |
189 | }; | 189 | }; |
190 | 190 | ||
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7753a9ca98a6..a3552929a21d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1074,12 +1074,8 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
1074 | if (beaconint_us > latency) { | 1074 | if (beaconint_us > latency) { |
1075 | local->ps_sdata = NULL; | 1075 | local->ps_sdata = NULL; |
1076 | } else { | 1076 | } else { |
1077 | struct ieee80211_bss *bss; | ||
1078 | int maxslp = 1; | 1077 | int maxslp = 1; |
1079 | u8 dtimper; | 1078 | u8 dtimper = found->u.mgd.dtim_period; |
1080 | |||
1081 | bss = (void *)found->u.mgd.associated->priv; | ||
1082 | dtimper = bss->dtim_period; | ||
1083 | 1079 | ||
1084 | /* If the TIM IE is invalid, pretend the value is 1 */ | 1080 | /* If the TIM IE is invalid, pretend the value is 1 */ |
1085 | if (!dtimper) | 1081 | if (!dtimper) |
@@ -1410,10 +1406,17 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
1410 | 1406 | ||
1411 | ieee80211_led_assoc(local, 1); | 1407 | ieee80211_led_assoc(local, 1); |
1412 | 1408 | ||
1413 | if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) | 1409 | if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) { |
1414 | bss_conf->dtim_period = bss->dtim_period; | 1410 | /* |
1415 | else | 1411 | * If the AP is buggy we may get here with no DTIM period |
1412 | * known, so assume it's 1 which is the only safe assumption | ||
1413 | * in that case, although if the TIM IE is broken powersave | ||
1414 | * probably just won't work at all. | ||
1415 | */ | ||
1416 | bss_conf->dtim_period = sdata->u.mgd.dtim_period ?: 1; | ||
1417 | } else { | ||
1416 | bss_conf->dtim_period = 0; | 1418 | bss_conf->dtim_period = 0; |
1419 | } | ||
1417 | 1420 | ||
1418 | bss_conf->assoc = 1; | 1421 | bss_conf->assoc = 1; |
1419 | 1422 | ||
@@ -1562,6 +1565,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1562 | 1565 | ||
1563 | sdata->u.mgd.timers_running = 0; | 1566 | sdata->u.mgd.timers_running = 0; |
1564 | 1567 | ||
1568 | sdata->vif.bss_conf.dtim_period = 0; | ||
1569 | |||
1565 | ifmgd->flags = 0; | 1570 | ifmgd->flags = 0; |
1566 | ieee80211_vif_release_channel(sdata); | 1571 | ieee80211_vif_release_channel(sdata); |
1567 | } | 1572 | } |
@@ -2373,11 +2378,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
2373 | struct ieee80211_channel *channel; | 2378 | struct ieee80211_channel *channel; |
2374 | bool need_ps = false; | 2379 | bool need_ps = false; |
2375 | 2380 | ||
2376 | if (sdata->u.mgd.associated && | 2381 | if ((sdata->u.mgd.associated && |
2377 | ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) { | 2382 | ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) || |
2378 | bss = (void *)sdata->u.mgd.associated->priv; | 2383 | (sdata->u.mgd.assoc_data && |
2384 | ether_addr_equal(mgmt->bssid, | ||
2385 | sdata->u.mgd.assoc_data->bss->bssid))) { | ||
2379 | /* not previously set so we may need to recalc */ | 2386 | /* not previously set so we may need to recalc */ |
2380 | need_ps = !bss->dtim_period; | 2387 | need_ps = sdata->u.mgd.associated && !sdata->u.mgd.dtim_period; |
2388 | |||
2389 | if (elems->tim && !elems->parse_error) { | ||
2390 | struct ieee80211_tim_ie *tim_ie = elems->tim; | ||
2391 | sdata->u.mgd.dtim_period = tim_ie->dtim_period; | ||
2392 | } | ||
2381 | } | 2393 | } |
2382 | 2394 | ||
2383 | if (elems->ds_params && elems->ds_params_len == 1) | 2395 | if (elems->ds_params && elems->ds_params_len == 1) |
@@ -3896,20 +3908,41 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
3896 | /* kick off associate process */ | 3908 | /* kick off associate process */ |
3897 | 3909 | ||
3898 | ifmgd->assoc_data = assoc_data; | 3910 | ifmgd->assoc_data = assoc_data; |
3911 | ifmgd->dtim_period = 0; | ||
3899 | 3912 | ||
3900 | err = ieee80211_prep_connection(sdata, req->bss, true); | 3913 | err = ieee80211_prep_connection(sdata, req->bss, true); |
3901 | if (err) | 3914 | if (err) |
3902 | goto err_clear; | 3915 | goto err_clear; |
3903 | 3916 | ||
3904 | if (!bss->dtim_period && | 3917 | if (sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) { |
3905 | sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) { | 3918 | const struct cfg80211_bss_ies *beacon_ies; |
3906 | /* | 3919 | |
3907 | * Wait up to one beacon interval ... | 3920 | rcu_read_lock(); |
3908 | * should this be more if we miss one? | 3921 | beacon_ies = rcu_dereference(req->bss->beacon_ies); |
3909 | */ | 3922 | if (!beacon_ies) { |
3910 | sdata_info(sdata, "waiting for beacon from %pM\n", | 3923 | /* |
3911 | ifmgd->bssid); | 3924 | * Wait up to one beacon interval ... |
3912 | assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval); | 3925 | * should this be more if we miss one? |
3926 | */ | ||
3927 | sdata_info(sdata, "waiting for beacon from %pM\n", | ||
3928 | ifmgd->bssid); | ||
3929 | assoc_data->timeout = | ||
3930 | TU_TO_EXP_TIME(req->bss->beacon_interval); | ||
3931 | } else { | ||
3932 | const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM, | ||
3933 | beacon_ies->data, | ||
3934 | beacon_ies->len); | ||
3935 | if (tim_ie && tim_ie[1] >= | ||
3936 | sizeof(struct ieee80211_tim_ie)) { | ||
3937 | const struct ieee80211_tim_ie *tim; | ||
3938 | tim = (void *)(tim_ie + 2); | ||
3939 | ifmgd->dtim_period = tim->dtim_period; | ||
3940 | } | ||
3941 | assoc_data->have_beacon = true; | ||
3942 | assoc_data->sent_assoc = false; | ||
3943 | assoc_data->timeout = jiffies; | ||
3944 | } | ||
3945 | rcu_read_unlock(); | ||
3913 | } else { | 3946 | } else { |
3914 | assoc_data->have_beacon = true; | 3947 | assoc_data->have_beacon = true; |
3915 | assoc_data->sent_assoc = false; | 3948 | assoc_data->sent_assoc = false; |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 8ed83dcc149f..d59fc6818b1c 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -113,18 +113,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
113 | bss->valid_data |= IEEE80211_BSS_VALID_ERP; | 113 | bss->valid_data |= IEEE80211_BSS_VALID_ERP; |
114 | } | 114 | } |
115 | 115 | ||
116 | if (elems->tim && (!elems->parse_error || | ||
117 | !(bss->valid_data & IEEE80211_BSS_VALID_DTIM))) { | ||
118 | struct ieee80211_tim_ie *tim_ie = elems->tim; | ||
119 | bss->dtim_period = tim_ie->dtim_period; | ||
120 | if (!elems->parse_error) | ||
121 | bss->valid_data |= IEEE80211_BSS_VALID_DTIM; | ||
122 | } | ||
123 | |||
124 | /* If the beacon had no TIM IE, or it was invalid, use 1 */ | ||
125 | if (beacon && !bss->dtim_period) | ||
126 | bss->dtim_period = 1; | ||
127 | |||
128 | /* replace old supported rates if we get new values */ | 116 | /* replace old supported rates if we get new values */ |
129 | if (!elems->parse_error || | 117 | if (!elems->parse_error || |
130 | !(bss->valid_data & IEEE80211_BSS_VALID_RATES)) { | 118 | !(bss->valid_data & IEEE80211_BSS_VALID_RATES)) { |
@@ -832,9 +820,9 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | |||
832 | return res; | 820 | return res; |
833 | } | 821 | } |
834 | 822 | ||
835 | int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, | 823 | int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, |
836 | const u8 *ssid, u8 ssid_len, | 824 | const u8 *ssid, u8 ssid_len, |
837 | struct ieee80211_channel *chan) | 825 | struct ieee80211_channel *chan) |
838 | { | 826 | { |
839 | struct ieee80211_local *local = sdata->local; | 827 | struct ieee80211_local *local = sdata->local; |
840 | int ret = -EBUSY; | 828 | int ret = -EBUSY; |
@@ -848,22 +836,36 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, | |||
848 | 836 | ||
849 | /* fill internal scan request */ | 837 | /* fill internal scan request */ |
850 | if (!chan) { | 838 | if (!chan) { |
851 | int i, nchan = 0; | 839 | int i, max_n; |
840 | int n_ch = 0; | ||
852 | 841 | ||
853 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 842 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
854 | if (!local->hw.wiphy->bands[band]) | 843 | if (!local->hw.wiphy->bands[band]) |
855 | continue; | 844 | continue; |
856 | for (i = 0; | 845 | |
857 | i < local->hw.wiphy->bands[band]->n_channels; | 846 | max_n = local->hw.wiphy->bands[band]->n_channels; |
858 | i++) { | 847 | for (i = 0; i < max_n; i++) { |
859 | local->int_scan_req->channels[nchan] = | 848 | struct ieee80211_channel *tmp_ch = |
860 | &local->hw.wiphy->bands[band]->channels[i]; | 849 | &local->hw.wiphy->bands[band]->channels[i]; |
861 | nchan++; | 850 | |
851 | if (tmp_ch->flags & (IEEE80211_CHAN_NO_IBSS | | ||
852 | IEEE80211_CHAN_DISABLED)) | ||
853 | continue; | ||
854 | |||
855 | local->int_scan_req->channels[n_ch] = tmp_ch; | ||
856 | n_ch++; | ||
862 | } | 857 | } |
863 | } | 858 | } |
864 | 859 | ||
865 | local->int_scan_req->n_channels = nchan; | 860 | if (WARN_ON_ONCE(n_ch == 0)) |
861 | goto unlock; | ||
862 | |||
863 | local->int_scan_req->n_channels = n_ch; | ||
866 | } else { | 864 | } else { |
865 | if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IBSS | | ||
866 | IEEE80211_CHAN_DISABLED))) | ||
867 | goto unlock; | ||
868 | |||
867 | local->int_scan_req->channels[0] = chan; | 869 | local->int_scan_req->channels[0] = chan; |
868 | local->int_scan_req->n_channels = 1; | 870 | local->int_scan_req->n_channels = 1; |
869 | } | 871 | } |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f3e502502fee..ca9fde198188 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -91,9 +91,8 @@ static int sta_info_hash_del(struct ieee80211_local *local, | |||
91 | return -ENOENT; | 91 | return -ENOENT; |
92 | } | 92 | } |
93 | 93 | ||
94 | static void free_sta_work(struct work_struct *wk) | 94 | static void cleanup_single_sta(struct sta_info *sta) |
95 | { | 95 | { |
96 | struct sta_info *sta = container_of(wk, struct sta_info, free_sta_wk); | ||
97 | int ac, i; | 96 | int ac, i; |
98 | struct tid_ampdu_tx *tid_tx; | 97 | struct tid_ampdu_tx *tid_tx; |
99 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 98 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
@@ -153,11 +152,35 @@ static void free_sta_work(struct work_struct *wk) | |||
153 | sta_info_free(local, sta); | 152 | sta_info_free(local, sta); |
154 | } | 153 | } |
155 | 154 | ||
155 | void ieee80211_cleanup_sdata_stas(struct ieee80211_sub_if_data *sdata) | ||
156 | { | ||
157 | struct sta_info *sta; | ||
158 | |||
159 | spin_lock_bh(&sdata->cleanup_stations_lock); | ||
160 | while (!list_empty(&sdata->cleanup_stations)) { | ||
161 | sta = list_first_entry(&sdata->cleanup_stations, | ||
162 | struct sta_info, list); | ||
163 | list_del(&sta->list); | ||
164 | spin_unlock_bh(&sdata->cleanup_stations_lock); | ||
165 | |||
166 | cleanup_single_sta(sta); | ||
167 | |||
168 | spin_lock_bh(&sdata->cleanup_stations_lock); | ||
169 | } | ||
170 | |||
171 | spin_unlock_bh(&sdata->cleanup_stations_lock); | ||
172 | } | ||
173 | |||
156 | static void free_sta_rcu(struct rcu_head *h) | 174 | static void free_sta_rcu(struct rcu_head *h) |
157 | { | 175 | { |
158 | struct sta_info *sta = container_of(h, struct sta_info, rcu_head); | 176 | struct sta_info *sta = container_of(h, struct sta_info, rcu_head); |
177 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
159 | 178 | ||
160 | ieee80211_queue_work(&sta->local->hw, &sta->free_sta_wk); | 179 | spin_lock(&sdata->cleanup_stations_lock); |
180 | list_add_tail(&sta->list, &sdata->cleanup_stations); | ||
181 | spin_unlock(&sdata->cleanup_stations_lock); | ||
182 | |||
183 | ieee80211_queue_work(&sdata->local->hw, &sdata->cleanup_stations_wk); | ||
161 | } | 184 | } |
162 | 185 | ||
163 | /* protected by RCU */ | 186 | /* protected by RCU */ |
@@ -310,7 +333,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
310 | 333 | ||
311 | spin_lock_init(&sta->lock); | 334 | spin_lock_init(&sta->lock); |
312 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); | 335 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); |
313 | INIT_WORK(&sta->free_sta_wk, free_sta_work); | ||
314 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); | 336 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); |
315 | mutex_init(&sta->ampdu_mlme.mtx); | 337 | mutex_init(&sta->ampdu_mlme.mtx); |
316 | 338 | ||
@@ -862,7 +884,7 @@ void sta_info_init(struct ieee80211_local *local) | |||
862 | 884 | ||
863 | void sta_info_stop(struct ieee80211_local *local) | 885 | void sta_info_stop(struct ieee80211_local *local) |
864 | { | 886 | { |
865 | del_timer(&local->sta_cleanup); | 887 | del_timer_sync(&local->sta_cleanup); |
866 | sta_info_flush(local, NULL); | 888 | sta_info_flush(local, NULL); |
867 | } | 889 | } |
868 | 890 | ||
@@ -891,6 +913,20 @@ int sta_info_flush(struct ieee80211_local *local, | |||
891 | } | 913 | } |
892 | mutex_unlock(&local->sta_mtx); | 914 | mutex_unlock(&local->sta_mtx); |
893 | 915 | ||
916 | rcu_barrier(); | ||
917 | |||
918 | if (sdata) { | ||
919 | ieee80211_cleanup_sdata_stas(sdata); | ||
920 | cancel_work_sync(&sdata->cleanup_stations_wk); | ||
921 | } else { | ||
922 | mutex_lock(&local->iflist_mtx); | ||
923 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
924 | ieee80211_cleanup_sdata_stas(sdata); | ||
925 | cancel_work_sync(&sdata->cleanup_stations_wk); | ||
926 | } | ||
927 | mutex_unlock(&local->iflist_mtx); | ||
928 | } | ||
929 | |||
894 | return ret; | 930 | return ret; |
895 | } | 931 | } |
896 | 932 | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 1489bca9ea97..37c1889afd3a 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -299,7 +299,6 @@ struct sta_info { | |||
299 | spinlock_t lock; | 299 | spinlock_t lock; |
300 | 300 | ||
301 | struct work_struct drv_unblock_wk; | 301 | struct work_struct drv_unblock_wk; |
302 | struct work_struct free_sta_wk; | ||
303 | 302 | ||
304 | u16 listen_interval; | 303 | u16 listen_interval; |
305 | 304 | ||
@@ -563,4 +562,6 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta); | |||
563 | void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta); | 562 | void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta); |
564 | void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta); | 563 | void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta); |
565 | 564 | ||
565 | void ieee80211_cleanup_sdata_stas(struct ieee80211_sub_if_data *sdata); | ||
566 | |||
566 | #endif /* STA_INFO_H */ | 567 | #endif /* STA_INFO_H */ |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 1915ffe598e3..507b5e84fbdb 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -555,7 +555,7 @@ EXPORT_SYMBOL_GPL(rpc_clone_client); | |||
555 | * rpc_clone_client_set_auth - Clone an RPC client structure and set its auth | 555 | * rpc_clone_client_set_auth - Clone an RPC client structure and set its auth |
556 | * | 556 | * |
557 | * @clnt: RPC client whose parameters are copied | 557 | * @clnt: RPC client whose parameters are copied |
558 | * @auth: security flavor for new client | 558 | * @flavor: security flavor for new client |
559 | * | 559 | * |
560 | * Returns a fresh RPC client or an ERR_PTR. | 560 | * Returns a fresh RPC client or an ERR_PTR. |
561 | */ | 561 | */ |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index b4133bd13915..bfa31714581f 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -972,8 +972,7 @@ static void rpc_async_release(struct work_struct *work) | |||
972 | 972 | ||
973 | static void rpc_release_resources_task(struct rpc_task *task) | 973 | static void rpc_release_resources_task(struct rpc_task *task) |
974 | { | 974 | { |
975 | if (task->tk_rqstp) | 975 | xprt_release(task); |
976 | xprt_release(task); | ||
977 | if (task->tk_msg.rpc_cred) { | 976 | if (task->tk_msg.rpc_cred) { |
978 | put_rpccred(task->tk_msg.rpc_cred); | 977 | put_rpccred(task->tk_msg.rpc_cred); |
979 | task->tk_msg.rpc_cred = NULL; | 978 | task->tk_msg.rpc_cred = NULL; |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index bd462a532acf..33811db8788a 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -1136,10 +1136,18 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) | |||
1136 | void xprt_release(struct rpc_task *task) | 1136 | void xprt_release(struct rpc_task *task) |
1137 | { | 1137 | { |
1138 | struct rpc_xprt *xprt; | 1138 | struct rpc_xprt *xprt; |
1139 | struct rpc_rqst *req; | 1139 | struct rpc_rqst *req = task->tk_rqstp; |
1140 | 1140 | ||
1141 | if (!(req = task->tk_rqstp)) | 1141 | if (req == NULL) { |
1142 | if (task->tk_client) { | ||
1143 | rcu_read_lock(); | ||
1144 | xprt = rcu_dereference(task->tk_client->cl_xprt); | ||
1145 | if (xprt->snd_task == task) | ||
1146 | xprt_release_write(xprt, task); | ||
1147 | rcu_read_unlock(); | ||
1148 | } | ||
1142 | return; | 1149 | return; |
1150 | } | ||
1143 | 1151 | ||
1144 | xprt = req->rq_xprt; | 1152 | xprt = req->rq_xprt; |
1145 | if (task->tk_ops->rpc_count_stats != NULL) | 1153 | if (task->tk_ops->rpc_count_stats != NULL) |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 14d990400354..b677eab55b68 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -866,8 +866,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
866 | /* allow mac80211 to determine the timeout */ | 866 | /* allow mac80211 to determine the timeout */ |
867 | wdev->ps_timeout = -1; | 867 | wdev->ps_timeout = -1; |
868 | 868 | ||
869 | if (!dev->ethtool_ops) | 869 | netdev_set_default_ethtool_ops(dev, &cfg80211_ethtool_ops); |
870 | dev->ethtool_ops = &cfg80211_ethtool_ops; | ||
871 | 870 | ||
872 | if ((wdev->iftype == NL80211_IFTYPE_STATION || | 871 | if ((wdev->iftype == NL80211_IFTYPE_STATION || |
873 | wdev->iftype == NL80211_IFTYPE_P2P_CLIENT || | 872 | wdev->iftype == NL80211_IFTYPE_P2P_CLIENT || |
diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c index 6fc0ae90e5b1..fff7753e35c1 100644 --- a/sound/arm/pxa2xx-ac97-lib.c +++ b/sound/arm/pxa2xx-ac97-lib.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/io.h> | 20 | #include <linux/io.h> |
21 | #include <linux/gpio.h> | ||
21 | 22 | ||
22 | #include <sound/ac97_codec.h> | 23 | #include <sound/ac97_codec.h> |
23 | #include <sound/pxa2xx-lib.h> | 24 | #include <sound/pxa2xx-lib.h> |
@@ -148,6 +149,8 @@ static inline void pxa_ac97_warm_pxa27x(void) | |||
148 | 149 | ||
149 | static inline void pxa_ac97_cold_pxa27x(void) | 150 | static inline void pxa_ac97_cold_pxa27x(void) |
150 | { | 151 | { |
152 | unsigned int timeout; | ||
153 | |||
151 | GCR &= GCR_COLD_RST; /* clear everything but nCRST */ | 154 | GCR &= GCR_COLD_RST; /* clear everything but nCRST */ |
152 | GCR &= ~GCR_COLD_RST; /* then assert nCRST */ | 155 | GCR &= ~GCR_COLD_RST; /* then assert nCRST */ |
153 | 156 | ||
@@ -157,8 +160,10 @@ static inline void pxa_ac97_cold_pxa27x(void) | |||
157 | clk_enable(ac97conf_clk); | 160 | clk_enable(ac97conf_clk); |
158 | udelay(5); | 161 | udelay(5); |
159 | clk_disable(ac97conf_clk); | 162 | clk_disable(ac97conf_clk); |
160 | GCR = GCR_COLD_RST; | 163 | GCR = GCR_COLD_RST | GCR_WARM_RST; |
161 | udelay(50); | 164 | timeout = 100; /* wait for the codec-ready bit to be set */ |
165 | while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) | ||
166 | mdelay(1); | ||
162 | } | 167 | } |
163 | #endif | 168 | #endif |
164 | 169 | ||
@@ -340,8 +345,21 @@ int pxa2xx_ac97_hw_probe(struct platform_device *dev) | |||
340 | } | 345 | } |
341 | 346 | ||
342 | if (cpu_is_pxa27x()) { | 347 | if (cpu_is_pxa27x()) { |
343 | /* Use GPIO 113 as AC97 Reset on Bulverde */ | 348 | /* |
349 | * This gpio is needed for a work-around to a bug in the ac97 | ||
350 | * controller during warm reset. The direction and level is set | ||
351 | * here so that it is an output driven high when switching from | ||
352 | * AC97_nRESET alt function to generic gpio. | ||
353 | */ | ||
354 | ret = gpio_request_one(reset_gpio, GPIOF_OUT_INIT_HIGH, | ||
355 | "pxa27x ac97 reset"); | ||
356 | if (ret < 0) { | ||
357 | pr_err("%s: gpio_request_one() failed: %d\n", | ||
358 | __func__, ret); | ||
359 | goto err_conf; | ||
360 | } | ||
344 | pxa27x_assert_ac97reset(reset_gpio, 0); | 361 | pxa27x_assert_ac97reset(reset_gpio, 0); |
362 | |||
345 | ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK"); | 363 | ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK"); |
346 | if (IS_ERR(ac97conf_clk)) { | 364 | if (IS_ERR(ac97conf_clk)) { |
347 | ret = PTR_ERR(ac97conf_clk); | 365 | ret = PTR_ERR(ac97conf_clk); |
@@ -384,6 +402,8 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe); | |||
384 | 402 | ||
385 | void pxa2xx_ac97_hw_remove(struct platform_device *dev) | 403 | void pxa2xx_ac97_hw_remove(struct platform_device *dev) |
386 | { | 404 | { |
405 | if (cpu_is_pxa27x()) | ||
406 | gpio_free(reset_gpio); | ||
387 | GCR |= GCR_ACLINK_OFF; | 407 | GCR |= GCR_ACLINK_OFF; |
388 | free_irq(IRQ_AC97, NULL); | 408 | free_irq(IRQ_AC97, NULL); |
389 | if (ac97conf_clk) { | 409 | if (ac97conf_clk) { |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cca87277baf0..0b6aebacc56b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -573,9 +573,12 @@ enum { | |||
573 | #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ | 573 | #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ |
574 | 574 | ||
575 | /* quirks for Intel PCH */ | 575 | /* quirks for Intel PCH */ |
576 | #define AZX_DCAPS_INTEL_PCH \ | 576 | #define AZX_DCAPS_INTEL_PCH_NOPM \ |
577 | (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_BUFSIZE | \ | 577 | (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_BUFSIZE | \ |
578 | AZX_DCAPS_COUNT_LPIB_DELAY | AZX_DCAPS_PM_RUNTIME) | 578 | AZX_DCAPS_COUNT_LPIB_DELAY) |
579 | |||
580 | #define AZX_DCAPS_INTEL_PCH \ | ||
581 | (AZX_DCAPS_INTEL_PCH_NOPM | AZX_DCAPS_PM_RUNTIME) | ||
579 | 582 | ||
580 | /* quirks for ATI SB / AMD Hudson */ | 583 | /* quirks for ATI SB / AMD Hudson */ |
581 | #define AZX_DCAPS_PRESET_ATI_SB \ | 584 | #define AZX_DCAPS_PRESET_ATI_SB \ |
@@ -3586,13 +3589,13 @@ static void azx_remove(struct pci_dev *pci) | |||
3586 | static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { | 3589 | static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { |
3587 | /* CPT */ | 3590 | /* CPT */ |
3588 | { PCI_DEVICE(0x8086, 0x1c20), | 3591 | { PCI_DEVICE(0x8086, 0x1c20), |
3589 | .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, | 3592 | .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, |
3590 | /* PBG */ | 3593 | /* PBG */ |
3591 | { PCI_DEVICE(0x8086, 0x1d20), | 3594 | { PCI_DEVICE(0x8086, 0x1d20), |
3592 | .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, | 3595 | .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, |
3593 | /* Panther Point */ | 3596 | /* Panther Point */ |
3594 | { PCI_DEVICE(0x8086, 0x1e20), | 3597 | { PCI_DEVICE(0x8086, 0x1e20), |
3595 | .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, | 3598 | .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, |
3596 | /* Lynx Point */ | 3599 | /* Lynx Point */ |
3597 | { PCI_DEVICE(0x8086, 0x8c20), | 3600 | { PCI_DEVICE(0x8086, 0x8c20), |
3598 | .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, | 3601 | .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 60890bfecc19..dd798c3196ff 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -558,24 +558,12 @@ static int conexant_build_controls(struct hda_codec *codec) | |||
558 | return 0; | 558 | return 0; |
559 | } | 559 | } |
560 | 560 | ||
561 | #ifdef CONFIG_PM | ||
562 | static int conexant_suspend(struct hda_codec *codec) | ||
563 | { | ||
564 | snd_hda_shutup_pins(codec); | ||
565 | return 0; | ||
566 | } | ||
567 | #endif | ||
568 | |||
569 | static const struct hda_codec_ops conexant_patch_ops = { | 561 | static const struct hda_codec_ops conexant_patch_ops = { |
570 | .build_controls = conexant_build_controls, | 562 | .build_controls = conexant_build_controls, |
571 | .build_pcms = conexant_build_pcms, | 563 | .build_pcms = conexant_build_pcms, |
572 | .init = conexant_init, | 564 | .init = conexant_init, |
573 | .free = conexant_free, | 565 | .free = conexant_free, |
574 | .set_power_state = conexant_set_power, | 566 | .set_power_state = conexant_set_power, |
575 | #ifdef CONFIG_PM | ||
576 | .suspend = conexant_suspend, | ||
577 | #endif | ||
578 | .reboot_notify = snd_hda_shutup_pins, | ||
579 | }; | 567 | }; |
580 | 568 | ||
581 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | 569 | #ifdef CONFIG_SND_HDA_INPUT_BEEP |
@@ -4405,10 +4393,6 @@ static const struct hda_codec_ops cx_auto_patch_ops = { | |||
4405 | .init = cx_auto_init, | 4393 | .init = cx_auto_init, |
4406 | .free = conexant_free, | 4394 | .free = conexant_free, |
4407 | .unsol_event = snd_hda_jack_unsol_event, | 4395 | .unsol_event = snd_hda_jack_unsol_event, |
4408 | #ifdef CONFIG_PM | ||
4409 | .suspend = conexant_suspend, | ||
4410 | #endif | ||
4411 | .reboot_notify = snd_hda_shutup_pins, | ||
4412 | }; | 4396 | }; |
4413 | 4397 | ||
4414 | /* | 4398 | /* |
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index b6c21ea187ca..807a2aa1ff38 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
@@ -1502,7 +1502,7 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, | |||
1502 | ctl_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | 1502 | ctl_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); |
1503 | substream = snd_pcm_chmap_substream(info, ctl_idx); | 1503 | substream = snd_pcm_chmap_substream(info, ctl_idx); |
1504 | if (!substream || !substream->runtime) | 1504 | if (!substream || !substream->runtime) |
1505 | return -EBADFD; | 1505 | return 0; /* just for avoiding error from alsactl restore */ |
1506 | switch (substream->runtime->status->state) { | 1506 | switch (substream->runtime->status->state) { |
1507 | case SNDRV_PCM_STATE_OPEN: | 1507 | case SNDRV_PCM_STATE_OPEN: |
1508 | case SNDRV_PCM_STATE_SETUP: | 1508 | case SNDRV_PCM_STATE_SETUP: |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 71ae23dd7103..f5196277b6e9 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -5817,6 +5817,9 @@ enum { | |||
5817 | ALC269_TYPE_ALC269VB, | 5817 | ALC269_TYPE_ALC269VB, |
5818 | ALC269_TYPE_ALC269VC, | 5818 | ALC269_TYPE_ALC269VC, |
5819 | ALC269_TYPE_ALC269VD, | 5819 | ALC269_TYPE_ALC269VD, |
5820 | ALC269_TYPE_ALC280, | ||
5821 | ALC269_TYPE_ALC282, | ||
5822 | ALC269_TYPE_ALC284, | ||
5820 | }; | 5823 | }; |
5821 | 5824 | ||
5822 | /* | 5825 | /* |
@@ -5833,10 +5836,13 @@ static int alc269_parse_auto_config(struct hda_codec *codec) | |||
5833 | switch (spec->codec_variant) { | 5836 | switch (spec->codec_variant) { |
5834 | case ALC269_TYPE_ALC269VA: | 5837 | case ALC269_TYPE_ALC269VA: |
5835 | case ALC269_TYPE_ALC269VC: | 5838 | case ALC269_TYPE_ALC269VC: |
5839 | case ALC269_TYPE_ALC280: | ||
5840 | case ALC269_TYPE_ALC284: | ||
5836 | ssids = alc269va_ssids; | 5841 | ssids = alc269va_ssids; |
5837 | break; | 5842 | break; |
5838 | case ALC269_TYPE_ALC269VB: | 5843 | case ALC269_TYPE_ALC269VB: |
5839 | case ALC269_TYPE_ALC269VD: | 5844 | case ALC269_TYPE_ALC269VD: |
5845 | case ALC269_TYPE_ALC282: | ||
5840 | ssids = alc269_ssids; | 5846 | ssids = alc269_ssids; |
5841 | break; | 5847 | break; |
5842 | default: | 5848 | default: |
@@ -6400,7 +6406,8 @@ static int patch_alc269(struct hda_codec *codec) | |||
6400 | 6406 | ||
6401 | alc_auto_parse_customize_define(codec); | 6407 | alc_auto_parse_customize_define(codec); |
6402 | 6408 | ||
6403 | if (codec->vendor_id == 0x10ec0269) { | 6409 | switch (codec->vendor_id) { |
6410 | case 0x10ec0269: | ||
6404 | spec->codec_variant = ALC269_TYPE_ALC269VA; | 6411 | spec->codec_variant = ALC269_TYPE_ALC269VA; |
6405 | switch (alc_get_coef0(codec) & 0x00f0) { | 6412 | switch (alc_get_coef0(codec) & 0x00f0) { |
6406 | case 0x0010: | 6413 | case 0x0010: |
@@ -6425,6 +6432,20 @@ static int patch_alc269(struct hda_codec *codec) | |||
6425 | goto error; | 6432 | goto error; |
6426 | spec->init_hook = alc269_fill_coef; | 6433 | spec->init_hook = alc269_fill_coef; |
6427 | alc269_fill_coef(codec); | 6434 | alc269_fill_coef(codec); |
6435 | break; | ||
6436 | |||
6437 | case 0x10ec0280: | ||
6438 | case 0x10ec0290: | ||
6439 | spec->codec_variant = ALC269_TYPE_ALC280; | ||
6440 | break; | ||
6441 | case 0x10ec0282: | ||
6442 | case 0x10ec0283: | ||
6443 | spec->codec_variant = ALC269_TYPE_ALC282; | ||
6444 | break; | ||
6445 | case 0x10ec0284: | ||
6446 | case 0x10ec0292: | ||
6447 | spec->codec_variant = ALC269_TYPE_ALC284; | ||
6448 | break; | ||
6428 | } | 6449 | } |
6429 | 6450 | ||
6430 | /* automatic parse from the BIOS config */ | 6451 | /* automatic parse from the BIOS config */ |
@@ -7129,6 +7150,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { | |||
7129 | { .id = 0x10ec0280, .name = "ALC280", .patch = patch_alc269 }, | 7150 | { .id = 0x10ec0280, .name = "ALC280", .patch = patch_alc269 }, |
7130 | { .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 }, | 7151 | { .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 }, |
7131 | { .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 }, | 7152 | { .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 }, |
7153 | { .id = 0x10ec0284, .name = "ALC284", .patch = patch_alc269 }, | ||
7132 | { .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 }, | 7154 | { .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 }, |
7133 | { .id = 0x10ec0292, .name = "ALC292", .patch = patch_alc269 }, | 7155 | { .id = 0x10ec0292, .name = "ALC292", .patch = patch_alc269 }, |
7134 | { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", | 7156 | { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", |
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 6e02e064d7b4..223c3d9cc69e 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c | |||
@@ -441,6 +441,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); | |||
441 | */ | 441 | */ |
442 | /* status */ | 442 | /* status */ |
443 | #define HDSPM_AES32_wcLock 0x0200000 | 443 | #define HDSPM_AES32_wcLock 0x0200000 |
444 | #define HDSPM_AES32_wcSync 0x0100000 | ||
444 | #define HDSPM_AES32_wcFreq_bit 22 | 445 | #define HDSPM_AES32_wcFreq_bit 22 |
445 | /* (status >> HDSPM_AES32_wcFreq_bit) & 0xF gives WC frequency (cf function | 446 | /* (status >> HDSPM_AES32_wcFreq_bit) & 0xF gives WC frequency (cf function |
446 | HDSPM_bit2freq */ | 447 | HDSPM_bit2freq */ |
@@ -3467,10 +3468,12 @@ static int hdspm_wc_sync_check(struct hdspm *hdspm) | |||
3467 | switch (hdspm->io_type) { | 3468 | switch (hdspm->io_type) { |
3468 | case AES32: | 3469 | case AES32: |
3469 | status = hdspm_read(hdspm, HDSPM_statusRegister); | 3470 | status = hdspm_read(hdspm, HDSPM_statusRegister); |
3470 | if (status & HDSPM_wcSync) | 3471 | if (status & HDSPM_AES32_wcLock) { |
3471 | return 2; | 3472 | if (status & HDSPM_AES32_wcSync) |
3472 | else if (status & HDSPM_wcLock) | 3473 | return 2; |
3473 | return 1; | 3474 | else |
3475 | return 1; | ||
3476 | } | ||
3474 | return 0; | 3477 | return 0; |
3475 | break; | 3478 | break; |
3476 | 3479 | ||
@@ -4658,6 +4661,7 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, | |||
4658 | unsigned int status; | 4661 | unsigned int status; |
4659 | unsigned int status2; | 4662 | unsigned int status2; |
4660 | unsigned int timecode; | 4663 | unsigned int timecode; |
4664 | unsigned int wcLock, wcSync; | ||
4661 | int pref_syncref; | 4665 | int pref_syncref; |
4662 | char *autosync_ref; | 4666 | char *autosync_ref; |
4663 | int x; | 4667 | int x; |
@@ -4751,8 +4755,11 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, | |||
4751 | 4755 | ||
4752 | snd_iprintf(buffer, "--- Status:\n"); | 4756 | snd_iprintf(buffer, "--- Status:\n"); |
4753 | 4757 | ||
4758 | wcLock = status & HDSPM_AES32_wcLock; | ||
4759 | wcSync = wcLock && (status & HDSPM_AES32_wcSync); | ||
4760 | |||
4754 | snd_iprintf(buffer, "Word: %s Frequency: %d\n", | 4761 | snd_iprintf(buffer, "Word: %s Frequency: %d\n", |
4755 | (status & HDSPM_AES32_wcLock) ? "Sync " : "No Lock", | 4762 | (wcLock) ? (wcSync ? "Sync " : "Lock ") : "No Lock", |
4756 | HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF)); | 4763 | HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF)); |
4757 | 4764 | ||
4758 | for (x = 0; x < 8; x++) { | 4765 | for (x = 0; x < 8; x++) { |
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index adf397b9d0e6..1d8bb5917594 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c | |||
@@ -446,15 +446,9 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
446 | case SND_SOC_DAIFMT_DSP_A: | 446 | case SND_SOC_DAIFMT_DSP_A: |
447 | mode = 0; | 447 | mode = 0; |
448 | break; | 448 | break; |
449 | case SND_SOC_DAIFMT_DSP_B: | ||
450 | mode = 1; | ||
451 | break; | ||
452 | case SND_SOC_DAIFMT_I2S: | 449 | case SND_SOC_DAIFMT_I2S: |
453 | mode = 2; | 450 | mode = 2; |
454 | break; | 451 | break; |
455 | case SND_SOC_DAIFMT_LEFT_J: | ||
456 | mode = 3; | ||
457 | break; | ||
458 | default: | 452 | default: |
459 | arizona_aif_err(dai, "Unsupported DAI format %d\n", | 453 | arizona_aif_err(dai, "Unsupported DAI format %d\n", |
460 | fmt & SND_SOC_DAIFMT_FORMAT_MASK); | 454 | fmt & SND_SOC_DAIFMT_FORMAT_MASK); |
@@ -714,7 +708,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, | |||
714 | snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1, | 708 | snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1, |
715 | ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val); | 709 | ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val); |
716 | snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL, | 710 | snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL, |
717 | ARIZONA_AIF1_RATE_MASK, 8); | 711 | ARIZONA_AIF1_RATE_MASK, |
712 | 8 << ARIZONA_AIF1_RATE_SHIFT); | ||
718 | break; | 713 | break; |
719 | default: | 714 | default: |
720 | arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk); | 715 | arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk); |
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 41dae1ed3b71..4deebeb07177 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h | |||
@@ -34,15 +34,15 @@ | |||
34 | 34 | ||
35 | #define ARIZONA_FLL_SRC_MCLK1 0 | 35 | #define ARIZONA_FLL_SRC_MCLK1 0 |
36 | #define ARIZONA_FLL_SRC_MCLK2 1 | 36 | #define ARIZONA_FLL_SRC_MCLK2 1 |
37 | #define ARIZONA_FLL_SRC_SLIMCLK 2 | 37 | #define ARIZONA_FLL_SRC_SLIMCLK 3 |
38 | #define ARIZONA_FLL_SRC_FLL1 3 | 38 | #define ARIZONA_FLL_SRC_FLL1 4 |
39 | #define ARIZONA_FLL_SRC_FLL2 4 | 39 | #define ARIZONA_FLL_SRC_FLL2 5 |
40 | #define ARIZONA_FLL_SRC_AIF1BCLK 5 | 40 | #define ARIZONA_FLL_SRC_AIF1BCLK 8 |
41 | #define ARIZONA_FLL_SRC_AIF2BCLK 6 | 41 | #define ARIZONA_FLL_SRC_AIF2BCLK 9 |
42 | #define ARIZONA_FLL_SRC_AIF3BCLK 7 | 42 | #define ARIZONA_FLL_SRC_AIF3BCLK 10 |
43 | #define ARIZONA_FLL_SRC_AIF1LRCLK 8 | 43 | #define ARIZONA_FLL_SRC_AIF1LRCLK 12 |
44 | #define ARIZONA_FLL_SRC_AIF2LRCLK 9 | 44 | #define ARIZONA_FLL_SRC_AIF2LRCLK 13 |
45 | #define ARIZONA_FLL_SRC_AIF3LRCLK 10 | 45 | #define ARIZONA_FLL_SRC_AIF3LRCLK 14 |
46 | 46 | ||
47 | #define ARIZONA_MIXER_VOL_MASK 0x00FE | 47 | #define ARIZONA_MIXER_VOL_MASK 0x00FE |
48 | #define ARIZONA_MIXER_VOL_SHIFT 1 | 48 | #define ARIZONA_MIXER_VOL_SHIFT 1 |
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 4f1127935fdf..ac8742a1f25a 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c | |||
@@ -474,16 +474,16 @@ static int cs4271_probe(struct snd_soc_codec *codec) | |||
474 | struct cs4271_platform_data *cs4271plat = codec->dev->platform_data; | 474 | struct cs4271_platform_data *cs4271plat = codec->dev->platform_data; |
475 | int ret; | 475 | int ret; |
476 | int gpio_nreset = -EINVAL; | 476 | int gpio_nreset = -EINVAL; |
477 | int amutec_eq_bmutec = 0; | 477 | bool amutec_eq_bmutec = false; |
478 | 478 | ||
479 | #ifdef CONFIG_OF | 479 | #ifdef CONFIG_OF |
480 | if (of_match_device(cs4271_dt_ids, codec->dev)) { | 480 | if (of_match_device(cs4271_dt_ids, codec->dev)) { |
481 | gpio_nreset = of_get_named_gpio(codec->dev->of_node, | 481 | gpio_nreset = of_get_named_gpio(codec->dev->of_node, |
482 | "reset-gpio", 0); | 482 | "reset-gpio", 0); |
483 | 483 | ||
484 | if (!of_get_property(codec->dev->of_node, | 484 | if (of_get_property(codec->dev->of_node, |
485 | "cirrus,amutec-eq-bmutec", NULL)) | 485 | "cirrus,amutec-eq-bmutec", NULL)) |
486 | amutec_eq_bmutec = 1; | 486 | amutec_eq_bmutec = true; |
487 | } | 487 | } |
488 | #endif | 488 | #endif |
489 | 489 | ||
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 99bb1c69499e..9811a5478c87 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c | |||
@@ -737,7 +737,7 @@ static const struct cs42l52_clk_para clk_map_table[] = { | |||
737 | 737 | ||
738 | static int cs42l52_get_clk(int mclk, int rate) | 738 | static int cs42l52_get_clk(int mclk, int rate) |
739 | { | 739 | { |
740 | int i, ret = 0; | 740 | int i, ret = -EINVAL; |
741 | u_int mclk1, mclk2 = 0; | 741 | u_int mclk1, mclk2 = 0; |
742 | 742 | ||
743 | for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) { | 743 | for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) { |
@@ -749,8 +749,6 @@ static int cs42l52_get_clk(int mclk, int rate) | |||
749 | } | 749 | } |
750 | } | 750 | } |
751 | } | 751 | } |
752 | if (ret > ARRAY_SIZE(clk_map_table)) | ||
753 | return -EINVAL; | ||
754 | return ret; | 752 | return ret; |
755 | } | 753 | } |
756 | 754 | ||
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index d75257d40a49..e19490cfb3a8 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c | |||
@@ -111,9 +111,9 @@ static struct reg_default lm49453_reg_defs[] = { | |||
111 | { 101, 0x00 }, | 111 | { 101, 0x00 }, |
112 | { 102, 0x00 }, | 112 | { 102, 0x00 }, |
113 | { 103, 0x01 }, | 113 | { 103, 0x01 }, |
114 | { 105, 0x01 }, | 114 | { 104, 0x01 }, |
115 | { 106, 0x00 }, | 115 | { 105, 0x00 }, |
116 | { 107, 0x01 }, | 116 | { 106, 0x01 }, |
117 | { 107, 0x00 }, | 117 | { 107, 0x00 }, |
118 | { 108, 0x00 }, | 118 | { 108, 0x00 }, |
119 | { 109, 0x00 }, | 119 | { 109, 0x00 }, |
@@ -163,56 +163,25 @@ static struct reg_default lm49453_reg_defs[] = { | |||
163 | { 184, 0x00 }, | 163 | { 184, 0x00 }, |
164 | { 185, 0x00 }, | 164 | { 185, 0x00 }, |
165 | { 186, 0x00 }, | 165 | { 186, 0x00 }, |
166 | { 189, 0x00 }, | 166 | { 187, 0x00 }, |
167 | { 188, 0x00 }, | 167 | { 188, 0x00 }, |
168 | { 194, 0x00 }, | 168 | { 189, 0x00 }, |
169 | { 195, 0x00 }, | 169 | { 208, 0x06 }, |
170 | { 196, 0x00 }, | ||
171 | { 197, 0x00 }, | ||
172 | { 200, 0x00 }, | ||
173 | { 201, 0x00 }, | ||
174 | { 202, 0x00 }, | ||
175 | { 203, 0x00 }, | ||
176 | { 204, 0x00 }, | ||
177 | { 205, 0x00 }, | ||
178 | { 208, 0x00 }, | ||
179 | { 209, 0x00 }, | 170 | { 209, 0x00 }, |
180 | { 210, 0x00 }, | 171 | { 210, 0x08 }, |
181 | { 211, 0x00 }, | 172 | { 211, 0x54 }, |
182 | { 213, 0x00 }, | 173 | { 212, 0x14 }, |
183 | { 214, 0x00 }, | 174 | { 213, 0x0d }, |
184 | { 215, 0x00 }, | 175 | { 214, 0x0d }, |
185 | { 216, 0x00 }, | 176 | { 215, 0x14 }, |
186 | { 217, 0x00 }, | 177 | { 216, 0x60 }, |
187 | { 218, 0x00 }, | ||
188 | { 219, 0x00 }, | ||
189 | { 221, 0x00 }, | 178 | { 221, 0x00 }, |
190 | { 222, 0x00 }, | 179 | { 222, 0x00 }, |
180 | { 223, 0x00 }, | ||
191 | { 224, 0x00 }, | 181 | { 224, 0x00 }, |
192 | { 225, 0x00 }, | ||
193 | { 226, 0x00 }, | ||
194 | { 227, 0x00 }, | ||
195 | { 228, 0x00 }, | ||
196 | { 229, 0x00 }, | ||
197 | { 230, 0x13 }, | ||
198 | { 231, 0x00 }, | ||
199 | { 232, 0x80 }, | ||
200 | { 233, 0x0C }, | ||
201 | { 234, 0xDD }, | ||
202 | { 235, 0x00 }, | ||
203 | { 236, 0x04 }, | ||
204 | { 237, 0x00 }, | ||
205 | { 238, 0x00 }, | ||
206 | { 239, 0x00 }, | ||
207 | { 240, 0x00 }, | ||
208 | { 241, 0x00 }, | ||
209 | { 242, 0x00 }, | ||
210 | { 243, 0x00 }, | ||
211 | { 244, 0x00 }, | ||
212 | { 245, 0x00 }, | ||
213 | { 248, 0x00 }, | 182 | { 248, 0x00 }, |
214 | { 249, 0x00 }, | 183 | { 249, 0x00 }, |
215 | { 254, 0x00 }, | 184 | { 250, 0x00 }, |
216 | { 255, 0x00 }, | 185 | { 255, 0x00 }, |
217 | }; | 186 | }; |
218 | 187 | ||
@@ -525,36 +494,41 @@ SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_PORT2_TX2_REG, 7, 1, 0), | |||
525 | }; | 494 | }; |
526 | 495 | ||
527 | /* TLV Declarations */ | 496 | /* TLV Declarations */ |
528 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -7650, 150, 1); | 497 | static const DECLARE_TLV_DB_SCALE(adc_dac_tlv, -7650, 150, 1); |
529 | static const DECLARE_TLV_DB_SCALE(port_tlv, 0, 600, 0); | 498 | static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 200, 1); |
499 | static const DECLARE_TLV_DB_SCALE(port_tlv, -1800, 600, 0); | ||
500 | static const DECLARE_TLV_DB_SCALE(stn_tlv, -7200, 150, 0); | ||
530 | 501 | ||
531 | static const struct snd_kcontrol_new lm49453_sidetone_mixer_controls[] = { | 502 | static const struct snd_kcontrol_new lm49453_sidetone_mixer_controls[] = { |
532 | /* Sidetone supports mono only */ | 503 | /* Sidetone supports mono only */ |
533 | SOC_DAPM_SINGLE_TLV("Sidetone ADCL Volume", LM49453_P0_STN_VOL_ADCL_REG, | 504 | SOC_DAPM_SINGLE_TLV("Sidetone ADCL Volume", LM49453_P0_STN_VOL_ADCL_REG, |
534 | 0, 0x3F, 0, digital_tlv), | 505 | 0, 0x3F, 0, stn_tlv), |
535 | SOC_DAPM_SINGLE_TLV("Sidetone ADCR Volume", LM49453_P0_STN_VOL_ADCR_REG, | 506 | SOC_DAPM_SINGLE_TLV("Sidetone ADCR Volume", LM49453_P0_STN_VOL_ADCR_REG, |
536 | 0, 0x3F, 0, digital_tlv), | 507 | 0, 0x3F, 0, stn_tlv), |
537 | SOC_DAPM_SINGLE_TLV("Sidetone DMIC1L Volume", LM49453_P0_STN_VOL_DMIC1L_REG, | 508 | SOC_DAPM_SINGLE_TLV("Sidetone DMIC1L Volume", LM49453_P0_STN_VOL_DMIC1L_REG, |
538 | 0, 0x3F, 0, digital_tlv), | 509 | 0, 0x3F, 0, stn_tlv), |
539 | SOC_DAPM_SINGLE_TLV("Sidetone DMIC1R Volume", LM49453_P0_STN_VOL_DMIC1R_REG, | 510 | SOC_DAPM_SINGLE_TLV("Sidetone DMIC1R Volume", LM49453_P0_STN_VOL_DMIC1R_REG, |
540 | 0, 0x3F, 0, digital_tlv), | 511 | 0, 0x3F, 0, stn_tlv), |
541 | SOC_DAPM_SINGLE_TLV("Sidetone DMIC2L Volume", LM49453_P0_STN_VOL_DMIC2L_REG, | 512 | SOC_DAPM_SINGLE_TLV("Sidetone DMIC2L Volume", LM49453_P0_STN_VOL_DMIC2L_REG, |
542 | 0, 0x3F, 0, digital_tlv), | 513 | 0, 0x3F, 0, stn_tlv), |
543 | SOC_DAPM_SINGLE_TLV("Sidetone DMIC2R Volume", LM49453_P0_STN_VOL_DMIC2R_REG, | 514 | SOC_DAPM_SINGLE_TLV("Sidetone DMIC2R Volume", LM49453_P0_STN_VOL_DMIC2R_REG, |
544 | 0, 0x3F, 0, digital_tlv), | 515 | 0, 0x3F, 0, stn_tlv), |
545 | }; | 516 | }; |
546 | 517 | ||
547 | static const struct snd_kcontrol_new lm49453_snd_controls[] = { | 518 | static const struct snd_kcontrol_new lm49453_snd_controls[] = { |
548 | /* mic1 and mic2 supports mono only */ | 519 | /* mic1 and mic2 supports mono only */ |
549 | SOC_SINGLE_TLV("Mic1 Volume", LM49453_P0_ADC_LEVELL_REG, 0, 6, | 520 | SOC_SINGLE_TLV("Mic1 Volume", LM49453_P0_MICL_REG, 0, 15, 0, mic_tlv), |
550 | 0, digital_tlv), | 521 | SOC_SINGLE_TLV("Mic2 Volume", LM49453_P0_MICR_REG, 0, 15, 0, mic_tlv), |
551 | SOC_SINGLE_TLV("Mic2 Volume", LM49453_P0_ADC_LEVELR_REG, 0, 6, | 522 | |
552 | 0, digital_tlv), | 523 | SOC_SINGLE_TLV("ADCL Volume", LM49453_P0_ADC_LEVELL_REG, 0, 63, |
524 | 0, adc_dac_tlv), | ||
525 | SOC_SINGLE_TLV("ADCR Volume", LM49453_P0_ADC_LEVELR_REG, 0, 63, | ||
526 | 0, adc_dac_tlv), | ||
553 | 527 | ||
554 | SOC_DOUBLE_R_TLV("DMIC1 Volume", LM49453_P0_DMIC1_LEVELL_REG, | 528 | SOC_DOUBLE_R_TLV("DMIC1 Volume", LM49453_P0_DMIC1_LEVELL_REG, |
555 | LM49453_P0_DMIC1_LEVELR_REG, 0, 6, 0, digital_tlv), | 529 | LM49453_P0_DMIC1_LEVELR_REG, 0, 63, 0, adc_dac_tlv), |
556 | SOC_DOUBLE_R_TLV("DMIC2 Volume", LM49453_P0_DMIC2_LEVELL_REG, | 530 | SOC_DOUBLE_R_TLV("DMIC2 Volume", LM49453_P0_DMIC2_LEVELL_REG, |
557 | LM49453_P0_DMIC2_LEVELR_REG, 0, 6, 0, digital_tlv), | 531 | LM49453_P0_DMIC2_LEVELR_REG, 0, 63, 0, adc_dac_tlv), |
558 | 532 | ||
559 | SOC_DAPM_ENUM("Mic2Mode", lm49453_mic2mode_enum), | 533 | SOC_DAPM_ENUM("Mic2Mode", lm49453_mic2mode_enum), |
560 | SOC_DAPM_ENUM("DMIC12 SRC", lm49453_dmic12_cfg_enum), | 534 | SOC_DAPM_ENUM("DMIC12 SRC", lm49453_dmic12_cfg_enum), |
@@ -569,16 +543,16 @@ static const struct snd_kcontrol_new lm49453_snd_controls[] = { | |||
569 | 2, 1, 0), | 543 | 2, 1, 0), |
570 | 544 | ||
571 | SOC_DOUBLE_R_TLV("DAC HP Volume", LM49453_P0_DAC_HP_LEVELL_REG, | 545 | SOC_DOUBLE_R_TLV("DAC HP Volume", LM49453_P0_DAC_HP_LEVELL_REG, |
572 | LM49453_P0_DAC_HP_LEVELR_REG, 0, 6, 0, digital_tlv), | 546 | LM49453_P0_DAC_HP_LEVELR_REG, 0, 63, 0, adc_dac_tlv), |
573 | SOC_DOUBLE_R_TLV("DAC LO Volume", LM49453_P0_DAC_LO_LEVELL_REG, | 547 | SOC_DOUBLE_R_TLV("DAC LO Volume", LM49453_P0_DAC_LO_LEVELL_REG, |
574 | LM49453_P0_DAC_LO_LEVELR_REG, 0, 6, 0, digital_tlv), | 548 | LM49453_P0_DAC_LO_LEVELR_REG, 0, 63, 0, adc_dac_tlv), |
575 | SOC_DOUBLE_R_TLV("DAC LS Volume", LM49453_P0_DAC_LS_LEVELL_REG, | 549 | SOC_DOUBLE_R_TLV("DAC LS Volume", LM49453_P0_DAC_LS_LEVELL_REG, |
576 | LM49453_P0_DAC_LS_LEVELR_REG, 0, 6, 0, digital_tlv), | 550 | LM49453_P0_DAC_LS_LEVELR_REG, 0, 63, 0, adc_dac_tlv), |
577 | SOC_DOUBLE_R_TLV("DAC HA Volume", LM49453_P0_DAC_HA_LEVELL_REG, | 551 | SOC_DOUBLE_R_TLV("DAC HA Volume", LM49453_P0_DAC_HA_LEVELL_REG, |
578 | LM49453_P0_DAC_HA_LEVELR_REG, 0, 6, 0, digital_tlv), | 552 | LM49453_P0_DAC_HA_LEVELR_REG, 0, 63, 0, adc_dac_tlv), |
579 | 553 | ||
580 | SOC_SINGLE_TLV("EP Volume", LM49453_P0_DAC_LS_LEVELL_REG, | 554 | SOC_SINGLE_TLV("EP Volume", LM49453_P0_DAC_LS_LEVELL_REG, |
581 | 0, 6, 0, digital_tlv), | 555 | 0, 63, 0, adc_dac_tlv), |
582 | 556 | ||
583 | SOC_SINGLE_TLV("PORT1_1_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG, | 557 | SOC_SINGLE_TLV("PORT1_1_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG, |
584 | 0, 3, 0, port_tlv), | 558 | 0, 3, 0, port_tlv), |
@@ -1218,7 +1192,7 @@ static int lm49453_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | |||
1218 | } | 1192 | } |
1219 | 1193 | ||
1220 | snd_soc_update_bits(codec, LM49453_P0_AUDIO_PORT1_BASIC_REG, | 1194 | snd_soc_update_bits(codec, LM49453_P0_AUDIO_PORT1_BASIC_REG, |
1221 | LM49453_AUDIO_PORT1_BASIC_FMT_MASK|BIT(1)|BIT(5), | 1195 | LM49453_AUDIO_PORT1_BASIC_FMT_MASK|BIT(0)|BIT(5), |
1222 | (aif_val | mode | clk_phase)); | 1196 | (aif_val | mode | clk_phase)); |
1223 | 1197 | ||
1224 | snd_soc_write(codec, LM49453_P0_AUDIO_PORT1_RX_MSB_REG, clk_shift); | 1198 | snd_soc_write(codec, LM49453_P0_AUDIO_PORT1_RX_MSB_REG, clk_shift); |
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index cb1675cd8e1c..92bbfec9b107 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c | |||
@@ -401,7 +401,7 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { | |||
401 | 5, 1, 0), | 401 | 5, 1, 0), |
402 | 402 | ||
403 | SOC_SINGLE_TLV("Mic Volume", SGTL5000_CHIP_MIC_CTRL, | 403 | SOC_SINGLE_TLV("Mic Volume", SGTL5000_CHIP_MIC_CTRL, |
404 | 0, 4, 0, mic_gain_tlv), | 404 | 0, 3, 0, mic_gain_tlv), |
405 | }; | 405 | }; |
406 | 406 | ||
407 | /* mute the codec used by alsa core */ | 407 | /* mute the codec used by alsa core */ |
@@ -1344,7 +1344,7 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) | |||
1344 | SGTL5000_HP_ZCD_EN | | 1344 | SGTL5000_HP_ZCD_EN | |
1345 | SGTL5000_ADC_ZCD_EN); | 1345 | SGTL5000_ADC_ZCD_EN); |
1346 | 1346 | ||
1347 | snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 0); | 1347 | snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 2); |
1348 | 1348 | ||
1349 | /* | 1349 | /* |
1350 | * disable DAP | 1350 | * disable DAP |
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index ab355c4f0b2d..40c07be9b581 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c | |||
@@ -74,9 +74,10 @@ | |||
74 | SNDRV_PCM_FMTBIT_S32_LE) | 74 | SNDRV_PCM_FMTBIT_S32_LE) |
75 | #define S2PC_VALUE 0x98 | 75 | #define S2PC_VALUE 0x98 |
76 | #define CLOCK_OUT 0x60 | 76 | #define CLOCK_OUT 0x60 |
77 | #define LEFT_J_DATA_FORMAT 0x10 | 77 | #define DATA_FORMAT_MSK 0x0E |
78 | #define I2S_DATA_FORMAT 0x12 | 78 | #define LEFT_J_DATA_FORMAT 0x00 |
79 | #define RIGHT_J_DATA_FORMAT 0x14 | 79 | #define I2S_DATA_FORMAT 0x02 |
80 | #define RIGHT_J_DATA_FORMAT 0x04 | ||
80 | #define CODEC_MUTE_VAL 0x80 | 81 | #define CODEC_MUTE_VAL 0x80 |
81 | 82 | ||
82 | #define POWER_CNTLMSAK 0x40 | 83 | #define POWER_CNTLMSAK 0x40 |
@@ -289,7 +290,7 @@ static int sta529_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt) | |||
289 | return -EINVAL; | 290 | return -EINVAL; |
290 | } | 291 | } |
291 | 292 | ||
292 | snd_soc_update_bits(codec, STA529_S2PCFG0, 0x0D, mode); | 293 | snd_soc_update_bits(codec, STA529_S2PCFG0, DATA_FORMAT_MSK, mode); |
293 | 294 | ||
294 | return 0; | 295 | return 0; |
295 | } | 296 | } |
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 1cbe88f01d63..12bcae63a7f0 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c | |||
@@ -209,9 +209,9 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue) | |||
209 | 209 | ||
210 | ret = wm2000_read(i2c, WM2000_REG_SPEECH_CLARITY); | 210 | ret = wm2000_read(i2c, WM2000_REG_SPEECH_CLARITY); |
211 | if (wm2000->speech_clarity) | 211 | if (wm2000->speech_clarity) |
212 | ret &= ~WM2000_SPEECH_CLARITY; | ||
213 | else | ||
214 | ret |= WM2000_SPEECH_CLARITY; | 212 | ret |= WM2000_SPEECH_CLARITY; |
213 | else | ||
214 | ret &= ~WM2000_SPEECH_CLARITY; | ||
215 | wm2000_write(i2c, WM2000_REG_SPEECH_CLARITY, ret); | 215 | wm2000_write(i2c, WM2000_REG_SPEECH_CLARITY, ret); |
216 | 216 | ||
217 | wm2000_write(i2c, WM2000_REG_SYS_START0, 0x33); | 217 | wm2000_write(i2c, WM2000_REG_SYS_START0, 0x33); |
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index afcf31df77e0..e6cefe1ac677 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c | |||
@@ -1566,15 +1566,9 @@ static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
1566 | case SND_SOC_DAIFMT_DSP_A: | 1566 | case SND_SOC_DAIFMT_DSP_A: |
1567 | fmt_val = 0; | 1567 | fmt_val = 0; |
1568 | break; | 1568 | break; |
1569 | case SND_SOC_DAIFMT_DSP_B: | ||
1570 | fmt_val = 1; | ||
1571 | break; | ||
1572 | case SND_SOC_DAIFMT_I2S: | 1569 | case SND_SOC_DAIFMT_I2S: |
1573 | fmt_val = 2; | 1570 | fmt_val = 2; |
1574 | break; | 1571 | break; |
1575 | case SND_SOC_DAIFMT_LEFT_J: | ||
1576 | fmt_val = 3; | ||
1577 | break; | ||
1578 | default: | 1572 | default: |
1579 | dev_err(codec->dev, "Unsupported DAI format %d\n", | 1573 | dev_err(codec->dev, "Unsupported DAI format %d\n", |
1580 | fmt & SND_SOC_DAIFMT_FORMAT_MASK); | 1574 | fmt & SND_SOC_DAIFMT_FORMAT_MASK); |
@@ -1626,7 +1620,7 @@ static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
1626 | WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV, | 1620 | WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV, |
1627 | lrclk); | 1621 | lrclk); |
1628 | snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_5, | 1622 | snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_5, |
1629 | WM2200_AIF1_FMT_MASK << 1, fmt_val << 1); | 1623 | WM2200_AIF1_FMT_MASK, fmt_val); |
1630 | 1624 | ||
1631 | return 0; | 1625 | return 0; |
1632 | } | 1626 | } |
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 5a5f36936235..54397a508073 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c | |||
@@ -1279,15 +1279,9 @@ static int wm5100_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
1279 | case SND_SOC_DAIFMT_DSP_A: | 1279 | case SND_SOC_DAIFMT_DSP_A: |
1280 | mask = 0; | 1280 | mask = 0; |
1281 | break; | 1281 | break; |
1282 | case SND_SOC_DAIFMT_DSP_B: | ||
1283 | mask = 1; | ||
1284 | break; | ||
1285 | case SND_SOC_DAIFMT_I2S: | 1282 | case SND_SOC_DAIFMT_I2S: |
1286 | mask = 2; | 1283 | mask = 2; |
1287 | break; | 1284 | break; |
1288 | case SND_SOC_DAIFMT_LEFT_J: | ||
1289 | mask = 3; | ||
1290 | break; | ||
1291 | default: | 1285 | default: |
1292 | dev_err(codec->dev, "Unsupported DAI format %d\n", | 1286 | dev_err(codec->dev, "Unsupported DAI format %d\n", |
1293 | fmt & SND_SOC_DAIFMT_FORMAT_MASK); | 1287 | fmt & SND_SOC_DAIFMT_FORMAT_MASK); |
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 688ade080589..7a9048dad1cd 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c | |||
@@ -36,6 +36,9 @@ | |||
36 | struct wm5102_priv { | 36 | struct wm5102_priv { |
37 | struct arizona_priv core; | 37 | struct arizona_priv core; |
38 | struct arizona_fll fll[2]; | 38 | struct arizona_fll fll[2]; |
39 | |||
40 | unsigned int spk_ena:2; | ||
41 | unsigned int spk_ena_pending:1; | ||
39 | }; | 42 | }; |
40 | 43 | ||
41 | static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); | 44 | static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); |
@@ -787,6 +790,47 @@ ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE), | |||
787 | ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE), | 790 | ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE), |
788 | }; | 791 | }; |
789 | 792 | ||
793 | static int wm5102_spk_ev(struct snd_soc_dapm_widget *w, | ||
794 | struct snd_kcontrol *kcontrol, | ||
795 | int event) | ||
796 | { | ||
797 | struct snd_soc_codec *codec = w->codec; | ||
798 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | ||
799 | struct wm5102_priv *wm5102 = snd_soc_codec_get_drvdata(codec); | ||
800 | |||
801 | if (arizona->rev < 1) | ||
802 | return 0; | ||
803 | |||
804 | switch (event) { | ||
805 | case SND_SOC_DAPM_PRE_PMU: | ||
806 | if (!wm5102->spk_ena) { | ||
807 | snd_soc_write(codec, 0x4f5, 0x25a); | ||
808 | wm5102->spk_ena_pending = true; | ||
809 | } | ||
810 | break; | ||
811 | case SND_SOC_DAPM_POST_PMU: | ||
812 | if (wm5102->spk_ena_pending) { | ||
813 | msleep(75); | ||
814 | snd_soc_write(codec, 0x4f5, 0xda); | ||
815 | wm5102->spk_ena_pending = false; | ||
816 | wm5102->spk_ena++; | ||
817 | } | ||
818 | break; | ||
819 | case SND_SOC_DAPM_PRE_PMD: | ||
820 | wm5102->spk_ena--; | ||
821 | if (!wm5102->spk_ena) | ||
822 | snd_soc_write(codec, 0x4f5, 0x25a); | ||
823 | break; | ||
824 | case SND_SOC_DAPM_POST_PMD: | ||
825 | if (!wm5102->spk_ena) | ||
826 | snd_soc_write(codec, 0x4f5, 0x0da); | ||
827 | break; | ||
828 | } | ||
829 | |||
830 | return 0; | ||
831 | } | ||
832 | |||
833 | |||
790 | ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE); | 834 | ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE); |
791 | ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE); | 835 | ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE); |
792 | ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE); | 836 | ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE); |
@@ -1034,10 +1078,10 @@ SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1, | |||
1034 | ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | 1078 | ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, |
1035 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | 1079 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), |
1036 | SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1, | 1080 | SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1, |
1037 | ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | 1081 | ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev, |
1038 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | 1082 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), |
1039 | SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1, | 1083 | SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1, |
1040 | ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | 1084 | ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev, |
1041 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | 1085 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), |
1042 | SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1, | 1086 | SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1, |
1043 | ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | 1087 | ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, |
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index ffc89fab96fb..7b198c38f3ef 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
@@ -169,6 +169,7 @@ static int wm_adsp_load(struct wm_adsp *dsp) | |||
169 | const struct wm_adsp_region *mem; | 169 | const struct wm_adsp_region *mem; |
170 | const char *region_name; | 170 | const char *region_name; |
171 | char *file, *text; | 171 | char *file, *text; |
172 | void *buf; | ||
172 | unsigned int reg; | 173 | unsigned int reg; |
173 | int regions = 0; | 174 | int regions = 0; |
174 | int ret, offset, type, sizes; | 175 | int ret, offset, type, sizes; |
@@ -322,8 +323,18 @@ static int wm_adsp_load(struct wm_adsp *dsp) | |||
322 | } | 323 | } |
323 | 324 | ||
324 | if (reg) { | 325 | if (reg) { |
325 | ret = regmap_raw_write(regmap, reg, region->data, | 326 | buf = kmemdup(region->data, le32_to_cpu(region->len), |
327 | GFP_KERNEL); | ||
328 | if (!buf) { | ||
329 | adsp_err(dsp, "Out of memory\n"); | ||
330 | return -ENOMEM; | ||
331 | } | ||
332 | |||
333 | ret = regmap_raw_write(regmap, reg, buf, | ||
326 | le32_to_cpu(region->len)); | 334 | le32_to_cpu(region->len)); |
335 | |||
336 | kfree(buf); | ||
337 | |||
327 | if (ret != 0) { | 338 | if (ret != 0) { |
328 | adsp_err(dsp, | 339 | adsp_err(dsp, |
329 | "%s.%d: Failed to write %d bytes at %d in %s: %d\n", | 340 | "%s.%d: Failed to write %d bytes at %d in %s: %d\n", |
@@ -359,6 +370,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) | |||
359 | const char *region_name; | 370 | const char *region_name; |
360 | int ret, pos, blocks, type, offset, reg; | 371 | int ret, pos, blocks, type, offset, reg; |
361 | char *file; | 372 | char *file; |
373 | void *buf; | ||
362 | 374 | ||
363 | file = kzalloc(PAGE_SIZE, GFP_KERNEL); | 375 | file = kzalloc(PAGE_SIZE, GFP_KERNEL); |
364 | if (file == NULL) | 376 | if (file == NULL) |
@@ -426,6 +438,13 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) | |||
426 | } | 438 | } |
427 | 439 | ||
428 | if (reg) { | 440 | if (reg) { |
441 | buf = kmemdup(blk->data, le32_to_cpu(blk->len), | ||
442 | GFP_KERNEL); | ||
443 | if (!buf) { | ||
444 | adsp_err(dsp, "Out of memory\n"); | ||
445 | return -ENOMEM; | ||
446 | } | ||
447 | |||
429 | ret = regmap_raw_write(regmap, reg, blk->data, | 448 | ret = regmap_raw_write(regmap, reg, blk->data, |
430 | le32_to_cpu(blk->len)); | 449 | le32_to_cpu(blk->len)); |
431 | if (ret != 0) { | 450 | if (ret != 0) { |
@@ -433,6 +452,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) | |||
433 | "%s.%d: Failed to write to %x in %s\n", | 452 | "%s.%d: Failed to write to %x in %s\n", |
434 | file, blocks, reg, region_name); | 453 | file, blocks, reg, region_name); |
435 | } | 454 | } |
455 | |||
456 | kfree(buf); | ||
436 | } | 457 | } |
437 | 458 | ||
438 | pos += le32_to_cpu(blk->len) + sizeof(*blk); | 459 | pos += le32_to_cpu(blk->len) + sizeof(*blk); |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 91d592ff67b7..2370063b5824 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -1255,6 +1255,8 @@ static int soc_post_component_init(struct snd_soc_card *card, | |||
1255 | INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients); | 1255 | INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients); |
1256 | ret = device_add(rtd->dev); | 1256 | ret = device_add(rtd->dev); |
1257 | if (ret < 0) { | 1257 | if (ret < 0) { |
1258 | /* calling put_device() here to free the rtd->dev */ | ||
1259 | put_device(rtd->dev); | ||
1258 | dev_err(card->dev, | 1260 | dev_err(card->dev, |
1259 | "ASoC: failed to register runtime device: %d\n", ret); | 1261 | "ASoC: failed to register runtime device: %d\n", ret); |
1260 | return ret; | 1262 | return ret; |
@@ -1554,7 +1556,7 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) | |||
1554 | /* unregister the rtd device */ | 1556 | /* unregister the rtd device */ |
1555 | if (rtd->dev_registered) { | 1557 | if (rtd->dev_registered) { |
1556 | device_remove_file(rtd->dev, &dev_attr_codec_reg); | 1558 | device_remove_file(rtd->dev, &dev_attr_codec_reg); |
1557 | device_del(rtd->dev); | 1559 | device_unregister(rtd->dev); |
1558 | rtd->dev_registered = 0; | 1560 | rtd->dev_registered = 0; |
1559 | } | 1561 | } |
1560 | 1562 | ||
@@ -2917,7 +2919,7 @@ int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, | |||
2917 | platform_max = mc->platform_max; | 2919 | platform_max = mc->platform_max; |
2918 | 2920 | ||
2919 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 2921 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
2920 | uinfo->count = 1; | 2922 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; |
2921 | uinfo->value.integer.min = 0; | 2923 | uinfo->value.integer.min = 0; |
2922 | uinfo->value.integer.max = platform_max - min; | 2924 | uinfo->value.integer.max = platform_max - min; |
2923 | 2925 | ||
@@ -2941,12 +2943,14 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, | |||
2941 | (struct soc_mixer_control *)kcontrol->private_value; | 2943 | (struct soc_mixer_control *)kcontrol->private_value; |
2942 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2944 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2943 | unsigned int reg = mc->reg; | 2945 | unsigned int reg = mc->reg; |
2946 | unsigned int rreg = mc->rreg; | ||
2944 | unsigned int shift = mc->shift; | 2947 | unsigned int shift = mc->shift; |
2945 | int min = mc->min; | 2948 | int min = mc->min; |
2946 | int max = mc->max; | 2949 | int max = mc->max; |
2947 | unsigned int mask = (1 << fls(max)) - 1; | 2950 | unsigned int mask = (1 << fls(max)) - 1; |
2948 | unsigned int invert = mc->invert; | 2951 | unsigned int invert = mc->invert; |
2949 | unsigned int val, val_mask; | 2952 | unsigned int val, val_mask; |
2953 | int ret; | ||
2950 | 2954 | ||
2951 | val = ((ucontrol->value.integer.value[0] + min) & mask); | 2955 | val = ((ucontrol->value.integer.value[0] + min) & mask); |
2952 | if (invert) | 2956 | if (invert) |
@@ -2954,7 +2958,21 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, | |||
2954 | val_mask = mask << shift; | 2958 | val_mask = mask << shift; |
2955 | val = val << shift; | 2959 | val = val << shift; |
2956 | 2960 | ||
2957 | return snd_soc_update_bits_locked(codec, reg, val_mask, val); | 2961 | ret = snd_soc_update_bits_locked(codec, reg, val_mask, val); |
2962 | if (ret != 0) | ||
2963 | return ret; | ||
2964 | |||
2965 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2966 | val = ((ucontrol->value.integer.value[1] + min) & mask); | ||
2967 | if (invert) | ||
2968 | val = max - val; | ||
2969 | val_mask = mask << shift; | ||
2970 | val = val << shift; | ||
2971 | |||
2972 | ret = snd_soc_update_bits_locked(codec, rreg, val_mask, val); | ||
2973 | } | ||
2974 | |||
2975 | return ret; | ||
2958 | } | 2976 | } |
2959 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range); | 2977 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range); |
2960 | 2978 | ||
@@ -2974,6 +2992,7 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, | |||
2974 | (struct soc_mixer_control *)kcontrol->private_value; | 2992 | (struct soc_mixer_control *)kcontrol->private_value; |
2975 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2993 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2976 | unsigned int reg = mc->reg; | 2994 | unsigned int reg = mc->reg; |
2995 | unsigned int rreg = mc->rreg; | ||
2977 | unsigned int shift = mc->shift; | 2996 | unsigned int shift = mc->shift; |
2978 | int min = mc->min; | 2997 | int min = mc->min; |
2979 | int max = mc->max; | 2998 | int max = mc->max; |
@@ -2988,6 +3007,16 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, | |||
2988 | ucontrol->value.integer.value[0] = | 3007 | ucontrol->value.integer.value[0] = |
2989 | ucontrol->value.integer.value[0] - min; | 3008 | ucontrol->value.integer.value[0] - min; |
2990 | 3009 | ||
3010 | if (snd_soc_volsw_is_stereo(mc)) { | ||
3011 | ucontrol->value.integer.value[1] = | ||
3012 | (snd_soc_read(codec, rreg) >> shift) & mask; | ||
3013 | if (invert) | ||
3014 | ucontrol->value.integer.value[1] = | ||
3015 | max - ucontrol->value.integer.value[1]; | ||
3016 | ucontrol->value.integer.value[1] = | ||
3017 | ucontrol->value.integer.value[1] - min; | ||
3018 | } | ||
3019 | |||
2991 | return 0; | 3020 | return 0; |
2992 | } | 3021 | } |
2993 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range); | 3022 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range); |
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index d7711fce119b..cf191e6aebbe 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
@@ -1243,6 +1243,7 @@ static int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) | |||
1243 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && | 1243 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && |
1244 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && | 1244 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && |
1245 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && | 1245 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && |
1246 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) && | ||
1246 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) | 1247 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) |
1247 | continue; | 1248 | continue; |
1248 | 1249 | ||
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index e71fe55cebef..0e2ed3d05c45 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c | |||
@@ -179,6 +179,15 @@ static struct usbmix_name_map audigy2nx_map[] = { | |||
179 | { 0 } /* terminator */ | 179 | { 0 } /* terminator */ |
180 | }; | 180 | }; |
181 | 181 | ||
182 | static struct usbmix_selector_map c400_selectors[] = { | ||
183 | { | ||
184 | .id = 0x80, | ||
185 | .count = 2, | ||
186 | .names = (const char*[]) {"Internal", "SPDIF"} | ||
187 | }, | ||
188 | { 0 } /* terminator */ | ||
189 | }; | ||
190 | |||
182 | static struct usbmix_selector_map audigy2nx_selectors[] = { | 191 | static struct usbmix_selector_map audigy2nx_selectors[] = { |
183 | { | 192 | { |
184 | .id = 14, /* Capture Source */ | 193 | .id = 14, /* Capture Source */ |
@@ -367,6 +376,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { | |||
367 | .map = hercules_usb51_map, | 376 | .map = hercules_usb51_map, |
368 | }, | 377 | }, |
369 | { | 378 | { |
379 | .id = USB_ID(0x0763, 0x2030), | ||
380 | .selector_map = c400_selectors, | ||
381 | }, | ||
382 | { | ||
370 | .id = USB_ID(0x08bb, 0x2702), | 383 | .id = USB_ID(0x08bb, 0x2702), |
371 | .map = linex_map, | 384 | .map = linex_map, |
372 | .ignore_ctl_error = 1, | 385 | .ignore_ctl_error = 1, |
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 0422b1360af3..15520de1df56 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c | |||
@@ -1206,7 +1206,7 @@ static int snd_c400_create_mixer(struct usb_mixer_interface *mixer) | |||
1206 | * are valid they presents mono controls as L and R channels of | 1206 | * are valid they presents mono controls as L and R channels of |
1207 | * stereo. So we provide a good mixer here. | 1207 | * stereo. So we provide a good mixer here. |
1208 | */ | 1208 | */ |
1209 | struct std_mono_table ebox44_table[] = { | 1209 | static struct std_mono_table ebox44_table[] = { |
1210 | { | 1210 | { |
1211 | .unitid = 4, | 1211 | .unitid = 4, |
1212 | .control = 1, | 1212 | .control = 1, |
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index c6593101c049..d82e378d37cb 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
@@ -511,6 +511,16 @@ static int configure_sync_endpoint(struct snd_usb_substream *subs) | |||
511 | struct snd_usb_substream *sync_subs = | 511 | struct snd_usb_substream *sync_subs = |
512 | &subs->stream->substream[subs->direction ^ 1]; | 512 | &subs->stream->substream[subs->direction ^ 1]; |
513 | 513 | ||
514 | if (subs->sync_endpoint->type != SND_USB_ENDPOINT_TYPE_DATA || | ||
515 | !subs->stream) | ||
516 | return snd_usb_endpoint_set_params(subs->sync_endpoint, | ||
517 | subs->pcm_format, | ||
518 | subs->channels, | ||
519 | subs->period_bytes, | ||
520 | subs->cur_rate, | ||
521 | subs->cur_audiofmt, | ||
522 | NULL); | ||
523 | |||
514 | /* Try to find the best matching audioformat. */ | 524 | /* Try to find the best matching audioformat. */ |
515 | list_for_each_entry(fp, &sync_subs->fmt_list, list) { | 525 | list_for_each_entry(fp, &sync_subs->fmt_list, list) { |
516 | int score = match_endpoint_audioformats(fp, subs->cur_audiofmt, | 526 | int score = match_endpoint_audioformats(fp, subs->cur_audiofmt, |
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 78e845ec65da..64d25a7a4d59 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h | |||
@@ -2289,7 +2289,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
2289 | .rate_table = (unsigned int[]) { | 2289 | .rate_table = (unsigned int[]) { |
2290 | 44100, 48000, 88200, 96000 | 2290 | 44100, 48000, 88200, 96000 |
2291 | }, | 2291 | }, |
2292 | .clock = 0x81, | 2292 | .clock = 0x80, |
2293 | } | 2293 | } |
2294 | }, | 2294 | }, |
2295 | /* Capture */ | 2295 | /* Capture */ |
@@ -2315,7 +2315,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
2315 | .rate_table = (unsigned int[]) { | 2315 | .rate_table = (unsigned int[]) { |
2316 | 44100, 48000, 88200, 96000 | 2316 | 44100, 48000, 88200, 96000 |
2317 | }, | 2317 | }, |
2318 | .clock = 0x81, | 2318 | .clock = 0x80, |
2319 | } | 2319 | } |
2320 | }, | 2320 | }, |
2321 | /* MIDI */ | 2321 | /* MIDI */ |
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index acc12f004c23..2c971858d6b7 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c | |||
@@ -387,11 +387,13 @@ static int snd_usb_fasttrackpro_boot_quirk(struct usb_device *dev) | |||
387 | * rules | 387 | * rules |
388 | */ | 388 | */ |
389 | err = usb_driver_set_configuration(dev, 2); | 389 | err = usb_driver_set_configuration(dev, 2); |
390 | if (err < 0) { | 390 | if (err < 0) |
391 | snd_printdd("error usb_driver_set_configuration: %d\n", | 391 | snd_printdd("error usb_driver_set_configuration: %d\n", |
392 | err); | 392 | err); |
393 | return -ENODEV; | 393 | /* Always return an error, so that we stop creating a device |
394 | } | 394 | that will just be destroyed and recreated with a new |
395 | configuration */ | ||
396 | return -ENODEV; | ||
395 | } else | 397 | } else |
396 | snd_printk(KERN_INFO "usb-audio: Fast Track Pro config OK\n"); | 398 | snd_printk(KERN_INFO "usb-audio: Fast Track Pro config OK\n"); |
397 | 399 | ||
@@ -859,6 +861,17 @@ void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep) | |||
859 | if ((le16_to_cpu(ep->chip->dev->descriptor.idVendor) == 0x23ba) && | 861 | if ((le16_to_cpu(ep->chip->dev->descriptor.idVendor) == 0x23ba) && |
860 | ep->type == SND_USB_ENDPOINT_TYPE_SYNC) | 862 | ep->type == SND_USB_ENDPOINT_TYPE_SYNC) |
861 | ep->skip_packets = 4; | 863 | ep->skip_packets = 4; |
864 | |||
865 | /* | ||
866 | * M-Audio Fast Track C400 - when packets are not skipped, real world | ||
867 | * latency varies by approx. +/- 50 frames (at 96KHz) each time the | ||
868 | * stream is (re)started. When skipping packets 16 at endpoint start | ||
869 | * up, the real world latency is stable within +/- 1 frame (also | ||
870 | * across power cycles). | ||
871 | */ | ||
872 | if (ep->chip->usb_id == USB_ID(0x0763, 0x2030) && | ||
873 | ep->type == SND_USB_ENDPOINT_TYPE_DATA) | ||
874 | ep->skip_packets = 16; | ||
862 | } | 875 | } |
863 | 876 | ||
864 | void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, | 877 | void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, |